Skip to content

Don't treat SyntaxProvider transform step inputs as cached. #58935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 20, 2022

Conversation

jkoritzinsky
Copy link
Member

@jkoritzinsky jkoritzinsky commented Jan 19, 2022

This fixes a case where we had a bad step state transition where we went from all "Cached" inputs to a "Modified" output, which is disallowed (this is how I found this bug) by never treating the input as "Cached" (which is also valid as one of the inputs is the SemanticModel, which we don't cache between runs).

This is blocking DllImportGenerator from adopting the Incremental Step Tracking API for our testing.

Copy link
Member

@chsienki chsienki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This actually breaks correctness. It's not possible to use the cached semantic results: we know that the syntax hasn't changed (which is why we do it two phase) but even with a cached syntax tree the things it refers too (for instance a class in another tree) can changed between runs, meaning we always have to run the transform step, even when the syntax tree hasn't changed.

@jkoritzinsky
Copy link
Member Author

That's because the SemanticModel is also provided as an input... Makes sense. I'll go back to the drawing board on this one.

@jkoritzinsky jkoritzinsky changed the title Enable using cached results of the transform function for a SyntaxProvider when the SyntaxNode entry is cached. Don't treat SyntaxProvider transform step inputs as cached. Jan 20, 2022
@jkoritzinsky
Copy link
Member Author

@chsienki I've taken an alternative approach here that shouldn't impact correctness and will accurately reflect the fact that we don't cache the SemanticModel between generator runs. Can you take another look?

@jkoritzinsky jkoritzinsky requested a review from chsienki January 20, 2022 00:36
Copy link
Member

@chsienki chsienki left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. Thanks!

@jkoritzinsky jkoritzinsky merged commit d305677 into dotnet:main Jan 20, 2022
@ghost ghost added this to the Next milestone Jan 20, 2022
@jkoritzinsky jkoritzinsky deleted the syntax-input-node-cached-tree branch January 20, 2022 21:49
@chsienki
Copy link
Member

chsienki commented Jan 20, 2022

@jkoritzinsky Just a heads up, we usually require two sign offs to merge into main.

@cston Could you do a review + retroactive sign off?

@jkoritzinsky
Copy link
Member Author

Sorry! I figured that if auto-merge was available that the requirements to merge had been met.

@@ -101,7 +101,11 @@ public void VisitTree(Lazy<SyntaxNode> root, EntryState state, SemanticModel? mo
var value = new GeneratorSyntaxContext(node, model);
var transformed = _owner._transformFunc(value, cancellationToken);

if (state == EntryState.Added || !_transformTable.TryModifyEntry(transformed, _owner._comparer, stopwatch.Elapsed, noInputStepsStepInfo, state))
// The SemanticModel we provide to GeneratorSyntaxContext is never guaranteed to be the same between runs,
// so we never consider the input to the transform as cached.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should the caller of VisitTree() be responsible for passing the correct EntryState in state instead? (Why is the incoming state ever set to Cached if that value is ignored?)

Copy link
Member Author

@jkoritzinsky jkoritzinsky Jan 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The passed-in EntryState value can be cached for the "filter" step as it represents the "what is the state of the syntax tree represented by root".

The GeneratorSyntaxContext basically functions as a Combine node of a SyntaxNode and the Compilation, but since we already handle the "Compilation is cached" situation previously, we don't need to handle it here in the same way. We can assume that if we get here, that the Compilation changed, so we need to make the "input state" for the transform Modified as one of the inputs (the semantic model/compilation) has changed.

context.RegisterSourceOutput(source, (spc, fieldName) =>
{
spc.AddSource(fieldName, "");
});
});

GeneratorDriver driver = CSharpGeneratorDriver.Create(new[] { new IncrementalGeneratorWrapper(testGenerator) }, parseOptions: parseOptions, driverOptions: new GeneratorDriverOptions(IncrementalGeneratorOutputKind.None, trackIncrementalGeneratorSteps: true));
// Don't enable incremental tracking here as incremental tracking disables the "unchanged compilation implies unchanged syntax trees" optimization.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

incremental tracking disables the "unchanged compilation implies unchanged syntax trees" optimization

Do we need to support this optimization with incremental tracking? (Is this the TODO in DriverStateTable.Builder.GetSyntaxInputTable()?) If so, is there an issue logged to track that?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need to support this optimization with incremental tracking as incremental tracking is meant to be a test-only feature, but it would be a "nice to have" feature if the implementation of it becomes simpler in a future refactoring.

This is the TODO in GetSyntaxInputTable(). There currently isn't an issue logged for it as it's not a required feature.

Copy link
Contributor

@cston cston left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@RikkiGibson RikkiGibson modified the milestones: Next, 17.2.P1 Feb 4, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants