Skip to content
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

Field-backed properties: support partial properties with auto-implemented accessors and with initializers #74959

Merged
merged 29 commits into from
Sep 10, 2024

Conversation

cston
Copy link
Member

@cston cston commented Aug 30, 2024

See proposal.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Aug 30, 2024
@cston cston force-pushed the partial-props branch 4 times, most recently from b0f42f7 to 45cb105 Compare September 2, 2024 21:33
@cston cston force-pushed the partial-props branch 2 times, most recently from 22ba653 to ae4b17a Compare September 4, 2024 03:53
@cston cston force-pushed the partial-props branch 2 times, most recently from a8eeabf to 28c7686 Compare September 5, 2024 03:19
@cston cston marked this pull request as ready for review September 5, 2024 05:16
@cston cston requested a review from a team as a code owner September 5, 2024 05:16
@cston cston marked this pull request as draft September 5, 2024 16:04
@RikkiGibson
Copy link
Contributor

Test failure log
[xUnit.net 00:01:15.29]     Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.SourceGeneration.GeneratorDriverFuzzTests.Fuzz_Generate [FAIL]
  Failed Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.SourceGeneration.GeneratorDriverFuzzTests.Fuzz_Generate [2 s]
  Error Message:
   Assert.Equal() Failure
Expected: ImmutableArray<SyntaxTree> []
Actual:   ImmutableArray<SyntaxTree> System.Collections.Immutable.ImmutableArray`1[Microsoft.CodeAnalysis.SyntaxTree]
  Stack Trace:
     at Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.SourceGeneration.GeneratorDriverFuzzTests.Fuzz_Iteration(Int32 iteration, Random random) in /_/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverFuzzTests.cs:line 332
   at Microsoft.CodeAnalysis.CSharp.Semantic.UnitTests.SourceGeneration.GeneratorDriverFuzzTests.Fuzz_Generate() in /_/src/Compilers/CSharp/Test/Semantic/SourceGeneration/GeneratorDriverFuzzTests.cs:line 258
  Standard Output Messages:
     [Fact]
     public void Fuzz_782()
     {
         var source = "";
         var comp = CreateCompilation(source);
         var hintNameProvider = new HintNameProvider(4);
         var generator = new IncrementalGeneratorWrapper(new PipelineCallbackGenerator(registerPipeline));
 
         // original input
         var originalInputs = new[]
         {
             new InMemoryAdditionalText("0", "a"),
             new InMemoryAdditionalText("1", "c"),
         };
 
         // from scratch on original
         GeneratorDriver driver1 = CSharpGeneratorDriver.Create(new[] { generator }, originalInputs);
         driver1.RunGenerators(comp);
 
         // make edits to original input
         var editedInputs = ImmutableArray.Create(new AdditionalText[]
         {
             new InMemoryAdditionalText("2", "a"),
             new InMemoryAdditionalText("3", "b"),
             new InMemoryAdditionalText("1", "b"),
         });
 
         // incremental update from edited input
         driver1 = driver1.ReplaceAdditionalTexts(editedInputs);
         hintNameProvider.Reset(4);
         driver1 = driver1.RunGenerators(comp);
         var result1 = driver1.GetRunResult();
 
         // from scratch on edited
         GeneratorDriver driver2 = CSharpGeneratorDriver.Create(new[] { generator }, editedInputs);
         hintNameProvider.Reset(4);
         driver2 = driver2.RunGenerators(comp);
         var result2 = driver2.GetRunResult();
 
         Assert.Equal(result2.GeneratedTrees, result1.GeneratedTrees, SyntaxTreeComparer.Instance);
         Assert.Equal(result2.Diagnostics, result1.Diagnostics, CommonDiagnosticComparer.Instance);
 
         void registerPipeline(IncrementalGeneratorInitializationContext context)
         {
             var provider = context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Select((additionalText, _) => (AdditionalText)new InMemoryAdditionalText(additionalText.Path, additionalText.GetText()!.ToString() switch
                 {
                     "a" => "b",
                     var other => other
                 }))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Select((additionalText, _) => (AdditionalText)new InMemoryAdditionalText(additionalText.Path, additionalText.GetText()!.ToString() switch
                 {
                     "a" => "b",
                     var other => other
                 }))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Select((additionalText, _) => (AdditionalText)new InMemoryAdditionalText(additionalText.Path, additionalText.GetText()!.ToString() switch
                 {
                     "a" => "b",
                     var other => other
                 }))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Select((additionalText, _) => (AdditionalText)new InMemoryAdditionalText(additionalText.Path, additionalText.GetText()!.ToString() switch
                 {
                     "a" => "b",
                     var other => other
                 }))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Select((additionalText, _) => (AdditionalText)new InMemoryAdditionalText(additionalText.Path, additionalText.GetText()!.ToString() switch
                 {
                     "a" => "b",
                     var other => other
                 }))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Select((additionalText, _) => (AdditionalText)new InMemoryAdditionalText(additionalText.Path, additionalText.GetText()!.ToString() switch
                 {
                     "a" => "b",
                     var other => other
                 }))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Select((additionalText, _) => (AdditionalText)new InMemoryAdditionalText(additionalText.Path, additionalText.GetText()!.ToString() switch
                 {
                     "a" => "b",
                     var other => other
                 }))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Combine(context.AdditionalTextsProvider
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (true, true),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .SelectMany((additionalText, _) => new (bool TransformAs, bool TransformCs)[] {
                     (false, true),
                     (true, true),
                     (false, false),
                 }.Select(logic => (AdditionalText)new InMemoryAdditionalText(hintNameProvider.GetNextHintName(), additionalText.GetText()!.ToString() switch
                 {
                     "a" when logic.TransformAs => "b",
                     "c" when logic.TransformCs => "d",
                     var other => other
                 })))
                 .Select((additionalText, _) => (AdditionalText)new InMemoryAdditionalText(additionalText.Path, additionalText.GetText()!.ToString() switch
                 {
                     "a" => "b",
                     var other => other
                 }))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
                 .Collect()
                 )
                 .Select((pair, _)
                     => (AdditionalText)new InMemoryAdditionalText(
                         pair.Left.Path,
                         string.Join("", pair.Right.Select(text => text.GetText()!.ToString()))))
             ;
             context.RegisterSourceOutput(provider, (context, text) =>
             {
                 context.AddSource(text.Path, text.GetText()!.ToString());
             });
         }
     }

There is no way that a fuzzer I added like a year ago is now finding a real (but likely transient) problem..right?

@RikkiGibson RikkiGibson self-assigned this Sep 6, 2024
// When calling through the SemanticModel, partial members are not
// necessarily merged when the containing type includes a primary
// constructor - see https://github.com/dotnet/roslyn/issues/75002.
else if (_containingType.PrimaryConstructor is { })
Copy link
Contributor

@RikkiGibson RikkiGibson Sep 6, 2024

Choose a reason for hiding this comment

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

This feels like too direct of a workaround for a bug. Basically, it's not clear that this is the only case where we would be accessing this information before containing type members are complete.

I think if this API must work while the symbol is in this state, then it would make sense to:

  • Debug.Assert(_containingType.PrimaryConstructor is { }), so that we detect any test scenarios which tell us more cases where this is occurring.
  • Always return the same value when !_containingType.AreMembersComplete, regardless of whether _containingType.PrimaryConstructor is { }. Whether the right thing is for it to always be DeclaredAutoPropertyInfo or _lazyMergedAutoPropertyInfo!, I am not sure. It is essentially an internal error recovery scenario, for a case where the symbols are in an invalid state.

I was also wondering, did you consider using a similar pattern as we use for BoundAttributesSource/GetAttributeDeclarations? Basically make the definition part the source of truth for properties like BackingField, UsesFieldKeyword etc., digging into the implementation part symbol to obtain bits of information when the APIs are first accessed. #Resolved

@cston
Copy link
Member Author

cston commented Sep 9, 2024

@333fred, @RikkiGibson, @dotnet/roslyn-compiler, please review.

@cston cston requested a review from a team September 9, 2024 20:40
Comment on lines 685 to 687
// The property should only be used after members in the containing
// type are complete, and partial members have been merged.
return backingField;
Copy link
Contributor

@RikkiGibson RikkiGibson Sep 10, 2024

Choose a reason for hiding this comment

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

I think we should also assert that we are in one of the scenarios which is known to have this problem (containing type has primary constructor). #Resolved

Copy link
Member Author

@cston cston Sep 10, 2024

Choose a reason for hiding this comment

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

I don't think we can assert here since this is a property that might be invoked in the debugger, before containing members are complete.

Copy link
Member

Choose a reason for hiding this comment

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

Could we assert !Debugger.IsAttached?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers New Feature - Field Keyword untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants