Skip to content

Commit fdfb3e3

Browse files
committed
Record anonymous type dependencies during initial binding
Fixes #73558
1 parent 7b48e08 commit fdfb3e3

File tree

16 files changed

+216
-15
lines changed

16 files changed

+216
-15
lines changed

src/Compilers/CSharp/Portable/Binder/Binder_AnonymousTypes.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ private BoundExpression BindAnonymousObjectCreation(AnonymousObjectCreationExpre
104104
// Create anonymous type
105105
AnonymousTypeManager manager = this.Compilation.AnonymousTypeManager;
106106
AnonymousTypeDescriptor descriptor = new AnonymousTypeDescriptor(fields.AsImmutableOrNull(), node.NewKeyword.GetLocation());
107-
NamedTypeSymbol anonymousType = manager.ConstructAnonymousTypeSymbol(descriptor);
107+
NamedTypeSymbol anonymousType = manager.ConstructAnonymousTypeSymbol(descriptor, diagnostics);
108108

109109
// declarators - bound nodes created for providing semantic info
110110
// on anonymous type fields having explicitly specified name

src/Compilers/CSharp/Portable/Binder/Binder_Query.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -822,7 +822,7 @@ private BoundExpression MakePair(CSharpSyntaxNode node, string field1Name, Bound
822822
);
823823

824824
AnonymousTypeManager manager = this.Compilation.AnonymousTypeManager;
825-
NamedTypeSymbol anonymousType = manager.ConstructAnonymousTypeSymbol(typeDescriptor);
825+
NamedTypeSymbol anonymousType = manager.ConstructAnonymousTypeSymbol(typeDescriptor, diagnostics);
826826
return MakeConstruction(node, anonymousType, ImmutableArray.Create(field1Value, field2Value), diagnostics);
827827

828828
AnonymousTypeField createField(string fieldName, BoundExpression fieldValue) =>

src/Compilers/CSharp/Portable/Compilation/CSharpCompilation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4335,7 +4335,7 @@ protected override INamedTypeSymbol CommonCreateAnonymousTypeSymbol(
43354335

43364336
var descriptor = new AnonymousTypeDescriptor(fields.ToImmutableAndFree(), Location.None);
43374337

4338-
return this.AnonymousTypeManager.ConstructAnonymousTypeSymbol(descriptor).GetPublicSymbol();
4338+
return this.AnonymousTypeManager.ConstructAnonymousTypeSymbol(descriptor, BindingDiagnosticBag.Discarded).GetPublicSymbol();
43394339
}
43404340

43414341
protected override IMethodSymbol CommonCreateBuiltinOperator(

src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.SymbolCollection.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,9 @@ public bool ReportMissingOrErroneousSymbols(BindingDiagnosticBag diagnostics)
5050

5151
public bool ReportMissingOrErroneousSymbolsForDelegates(BindingDiagnosticBag diagnostics)
5252
{
53+
// If we start reporting errors for non-Special types or members here,
54+
// we need to call this method from ConstructAnonymousDelegateSymbol to callect dependencies.
55+
5356
bool hasErrors = false;
5457

5558
ReportErrorOnSymbol(System_Object, diagnostics, ref hasErrors);

src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.Templates.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,9 @@ void assignIndexedNames(IReadOnlyList<AnonymousTypeOrDelegateTemplateSymbol> tem
500500
SealTemplates();
501501
}
502502

503+
// If we change conditions under which ReportMissingOrErroneousSymbols is called here,
504+
// we also need to adjust conditions under which ReportMissingOrErroneousSymbols is called to
505+
// collect dependencies. Quite possibly call it in more places.
503506
if (anonymousTypes.Count > 0 && !ReportMissingOrErroneousSymbols(diagnostics))
504507
{
505508
// Process all the templates

src/Compilers/CSharp/Portable/Symbols/AnonymousTypes/AnonymousTypeManager.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,13 +28,24 @@ internal AnonymousTypeManager(CSharpCompilation compilation)
2828
/// <summary>
2929
/// Given anonymous type descriptor provided constructs an anonymous type symbol.
3030
/// </summary>
31-
public NamedTypeSymbol ConstructAnonymousTypeSymbol(AnonymousTypeDescriptor typeDescr)
31+
public NamedTypeSymbol ConstructAnonymousTypeSymbol(AnonymousTypeDescriptor typeDescr, BindingDiagnosticBag diagnostics)
3232
{
33+
if (diagnostics.AccumulatesDependencies)
34+
{
35+
var depencies = BindingDiagnosticBag.GetInstance(withDependencies: true, withDiagnostics: false);
36+
ReportMissingOrErroneousSymbols(depencies);
37+
diagnostics.AddRange(depencies);
38+
depencies.Free();
39+
}
40+
3341
return new AnonymousTypePublicSymbol(this, typeDescr);
3442
}
3543

3644
public NamedTypeSymbol ConstructAnonymousDelegateSymbol(AnonymousTypeDescriptor typeDescr)
3745
{
46+
// ReportMissingOrErroneousSymbols is not reporting anything for delegate types and
47+
// ReportMissingOrErroneousSymbolsForDelegates reports only Special types.
48+
// Therefore, we have no additional dependencies to report here.
3849
return new AnonymousDelegatePublicSymbol(this, typeDescr);
3950
}
4051

@@ -71,7 +82,7 @@ public static NamedTypeSymbol ConstructAnonymousTypeSymbol(NamedTypeSymbol type,
7182
Debug.Assert(type.IsAnonymousType);
7283

7384
var anonymous = (AnonymousTypePublicSymbol)type;
74-
return anonymous.Manager.ConstructAnonymousTypeSymbol(anonymous.TypeDescriptor.WithNewFieldsTypes(newFieldTypes));
85+
return anonymous.Manager.ConstructAnonymousTypeSymbol(anonymous.TypeDescriptor.WithNewFieldsTypes(newFieldTypes), BindingDiagnosticBag.Discarded);
7586
}
7687
}
7788
}

src/Compilers/CSharp/Test/Emit3/RefStructInterfacesTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21450,7 +21450,7 @@ static void Test<T>(T x)
2145021450
);
2145121451
}
2145221452

21453-
[ConditionalFact(typeof(NoUsedAssembliesValidation))] // https://github.com/dotnet/roslyn/issues/73558: Follow up on used assemblies validation failure. Could be an artifact of https://github.com/dotnet/roslyn/issues/72945.
21453+
[Fact]
2145421454
[WorkItem("https://github.com/dotnet/roslyn/issues/72945")]
2145521455
[WorkItem("https://github.com/dotnet/roslyn/issues/73558")]
2145621456
public void AnonymousTypeMember_02()

src/Compilers/CSharp/Test/Symbol/Compilation/UsedAssembliesTests.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6025,5 +6025,79 @@ static void Main()
60256025

60266026
CompileWithUsedAssemblyReferences(source4, comp1Ref);
60276027
}
6028+
6029+
[Fact]
6030+
[WorkItem("https://github.com/dotnet/roslyn/issues/73558")]
6031+
public void AnonymousTypes_01()
6032+
{
6033+
var source =
6034+
@"
6035+
class Program
6036+
{
6037+
static void Main()
6038+
{
6039+
var anon = new { X = 1, Y = 2 };
6040+
}
6041+
}
6042+
";
6043+
var comp1 = CreateCompilation(source, targetFramework: TargetFramework.Net100);
6044+
var used = comp1.GetUsedAssemblyReferences();
6045+
AssertEx.Equal("System.Collections", comp1.GetWellKnownType(WellKnownType.System_Collections_Generic_EqualityComparer_T).ContainingAssembly.Name);
6046+
6047+
CompileAndVerify(comp1, verify: Verification.FailsPEVerify).VerifyDiagnostics();
6048+
6049+
var comp2 = comp1.RemoveAllReferences().AddReferences(used);
6050+
CompileAndVerify(comp2, verify: Verification.FailsPEVerify).VerifyDiagnostics();
6051+
}
6052+
6053+
[Fact]
6054+
[WorkItem("https://github.com/dotnet/roslyn/issues/73558")]
6055+
public void AnonymousTypes_02()
6056+
{
6057+
var source =
6058+
@"
6059+
class Program
6060+
{
6061+
static void Main()
6062+
{
6063+
var anon = (int x, int y) => {};
6064+
}
6065+
}
6066+
";
6067+
var comp1 = CreateCompilation(source, targetFramework: TargetFramework.Net100);
6068+
var used = comp1.GetUsedAssemblyReferences();
6069+
6070+
CompileAndVerify(comp1, verify: Verification.FailsPEVerify).VerifyDiagnostics();
6071+
6072+
var comp2 = comp1.RemoveAllReferences().AddReferences(used);
6073+
CompileAndVerify(comp2, verify: Verification.FailsPEVerify).VerifyDiagnostics();
6074+
}
6075+
6076+
[Fact]
6077+
[WorkItem("https://github.com/dotnet/roslyn/issues/73558")]
6078+
public void AnonymousTypes_03()
6079+
{
6080+
var source =
6081+
@"
6082+
class Program
6083+
{
6084+
static void Main()
6085+
{
6086+
var anon1 = new { X = 1, Y = 2 };
6087+
var anon2 = new { U = 1, V = 2 };
6088+
}
6089+
}
6090+
";
6091+
var comp1 = CreateCompilation(source, targetFramework: TargetFramework.Net100);
6092+
comp1.MakeTypeMissing(WellKnownType.System_Collections_Generic_EqualityComparer_T);
6093+
comp1.VerifyEmitDiagnostics(
6094+
// error CS0656: Missing compiler required member 'System.Collections.Generic.EqualityComparer`1.Equals'
6095+
Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.Collections.Generic.EqualityComparer`1", "Equals").WithLocation(1, 1),
6096+
// error CS0656: Missing compiler required member 'System.Collections.Generic.EqualityComparer`1.GetHashCode'
6097+
Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.Collections.Generic.EqualityComparer`1", "GetHashCode").WithLocation(1, 1),
6098+
// error CS0656: Missing compiler required member 'System.Collections.Generic.EqualityComparer`1.get_Default'
6099+
Diagnostic(ErrorCode.ERR_MissingPredefinedMember).WithArguments("System.Collections.Generic.EqualityComparer`1", "get_Default").WithLocation(1, 1)
6100+
);
6101+
}
60286102
}
60296103
}

src/Compilers/VisualBasic/Portable/Binding/Binder_AnonymousTypes.vb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
3434
End If
3535
Next
3636

37-
Return CreateAnonymousObjectCreationExpression(node, typeDescr, initExpressions)
37+
Return CreateAnonymousObjectCreationExpression(node, typeDescr, initExpressions, diagnostics)
3838
End Function
3939

4040
Private Function CreateAnonymousObjectCreationExpression(node As VisualBasicSyntaxNode,
4141
typeDescr As AnonymousTypeDescriptor,
4242
initExpressions As ImmutableArray(Of BoundExpression),
43+
diagnostics As BindingDiagnosticBag,
4344
Optional hasErrors As Boolean = False) As BoundExpression
4445
' Get or create an anonymous type
4546
Dim anonymousType As AnonymousTypeManager.AnonymousTypePublicSymbol =
46-
Me.Compilation.AnonymousTypeManager.ConstructAnonymousTypeSymbol(typeDescr)
47+
Me.Compilation.AnonymousTypeManager.ConstructAnonymousTypeSymbol(typeDescr, diagnostics)
4748

4849
' get constructor
4950
Dim constructor As MethodSymbol = anonymousType.InstanceConstructors.First()
@@ -280,7 +281,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
280281
Me._fields.AsImmutableOrNull(),
281282
typeLocationToken.GetLocation(),
282283
False),
283-
boundInitializers.AsImmutableOrNull())
284+
boundInitializers.AsImmutableOrNull(),
285+
diagnostics)
284286

285287
Me._freeze = True
286288

src/Compilers/VisualBasic/Portable/BoundTree/GroupTypeInferenceLambda.vb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
1212

1313
Partial Friend Class GroupTypeInferenceLambda
1414

15-
Public Function InferLambdaReturnType(delegateParams As ImmutableArray(Of ParameterSymbol)) As TypeSymbol
15+
Public Function InferLambdaReturnType(delegateParams As ImmutableArray(Of ParameterSymbol), diagnostics As BindingDiagnosticBag) As TypeSymbol
1616
' Return type of the lambda must be an Anonymous Type corresponding to the following initializer:
1717
' New With {key .$VB$ItAnonymous = <delegates's second parameter> }
1818
If delegateParams.Length <> 2 Then
@@ -25,7 +25,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
2525
Syntax.QueryClauseKeywordOrRangeVariableIdentifier.GetLocation(),
2626
True)),
2727
Syntax.QueryClauseKeywordOrRangeVariableIdentifier.GetLocation(),
28-
True))
28+
True),
29+
diagnostics)
2930
End If
3031
End Function
3132

0 commit comments

Comments
 (0)