One of the stated benefits benefits of using the IIncrementalGenerator
over ISourceGenerator
is that different stages of the pipeline can recognize that the results of the current iteration is the same as a previous iteration and use cached results.
In order for this to work, presumably the type parameter of any IncrementalValueProvider
or IncrementalValuesProvider
would need to be value equatable, (as opposed to the default reference equatable) which is presumably why you see a lot of source generators implemented using record
This leads to the question, if the IncrementalValueProvider
equality function includes an ISymbol
representing the same semantic object, will they be considered equal for the purposes of the caching comparison during different iterations of the pipeline?
Would it be better to just forgo referencing an ISymbol
and just extract the data I need out of it (name, namespace, members, etc.)?
I have dug into the Equals functions of the Symbol implementations, and it is unclear, the base class Symbol.Equals()
does use reference comparison, but this appears to be overridden in most (possibly all) of the derived classes. and a spot check of these overrides appear that they are attempting to have a value equality, but again, there are a lot to check, and even if it does end up using the reference equality check, it is also possible that the symbol references are cached between runs and even a reference equals check will be true.
Would it be better to just forgo referencing an ISymbol
and just extract the data I need out of it (name, namespace, members, etc.)?
CodePudding user response:
Don't include symbols in the pipeline. Not only that they will compare unequal, but they also root compilations in memory and can lead to high memory usage.
The following small snippet shows how symbols compare unequal, even if they are resulting from the exact same syntax tree:
var trees = new[] { SyntaxFactory.ParseSyntaxTree("public class C { }") };
var comp1 = CSharpCompilation.Create(null, trees);
var s1 = comp1.GetTypeByMetadataName("C");
var comp2 = CSharpCompilation.Create(null, trees);
var s2 = comp2.GetTypeByMetadataName("C");
Console.WriteLine(s1.Equals(s2, SymbolEqualityComparer.Default));
But even if you provide your own equality comparer, rooting compilations is still an issue.