未验证 提交 73015314 编写于 作者: C Chris Sienkiewicz 提交者: GitHub

Invert the binding order of InitializerExpressions and CreationExpressions (#30805)

* Invert the order of binding for InitializerExpressions and CreationExpressions:
- Push intializer binding into the respective creation expression bindings so that initializer binding takes place *after* the creation, ensuring any referenced out vars have already been inferred, preventing infinite loops
- Add tests to show behavior
上级 7933187a
......@@ -3703,36 +3703,29 @@ protected BoundExpression BindObjectCreationExpression(ObjectCreationExpressionS
{
var typeWithAnnotations = BindType(node.Type, diagnostics);
var type = typeWithAnnotations.TypeSymbol;
var originalType = type;
if (typeWithAnnotations.IsAnnotated && !type.IsNullableType())
{
diagnostics.Add(ErrorCode.ERR_AnnotationDisallowedInObjectCreation, node.Location, type);
}
BoundObjectInitializerExpressionBase boundInitializerOpt = node.Initializer == null ?
null :
BindInitializerExpression(
syntax: node.Initializer,
type: type,
typeSyntax: node.Type,
diagnostics: diagnostics);
switch (type.TypeKind)
{
case TypeKind.Struct:
case TypeKind.Class:
case TypeKind.Enum:
case TypeKind.Error:
return BindClassCreationExpression(node, (NamedTypeSymbol)type, GetName(node.Type), boundInitializerOpt, diagnostics);
return BindClassCreationExpression(node, (NamedTypeSymbol)type, GetName(node.Type), diagnostics, originalType);
case TypeKind.Delegate:
return BindDelegateCreationExpression(node, (NamedTypeSymbol)type, diagnostics);
case TypeKind.Interface:
return BindInterfaceCreationExpression(node, (NamedTypeSymbol)type, boundInitializerOpt, diagnostics);
return BindInterfaceCreationExpression(node, (NamedTypeSymbol)type, diagnostics);
case TypeKind.TypeParameter:
return BindTypeParameterCreationExpression(node, (TypeParameterSymbol)type, boundInitializerOpt, diagnostics);
return BindTypeParameterCreationExpression(node, (TypeParameterSymbol)type, diagnostics);
case TypeKind.Submission:
// script class is synthesized and should not be used as a type of a new expression:
......@@ -3930,7 +3923,7 @@ private BoundExpression BindDelegateCreationExpression(ObjectCreationExpressionS
}
}
private BoundExpression BindClassCreationExpression(ObjectCreationExpressionSyntax node, NamedTypeSymbol type, string typeName, BoundObjectInitializerExpressionBase boundInitializerOpt, DiagnosticBag diagnostics)
private BoundExpression BindClassCreationExpression(ObjectCreationExpressionSyntax node, NamedTypeSymbol type, string typeName, DiagnosticBag diagnostics, TypeSymbol initializerType = null)
{
// Get the bound arguments and the argument names.
AnalyzedArguments analyzedArguments = AnalyzedArguments.GetInstance();
......@@ -3944,15 +3937,15 @@ private BoundExpression BindClassCreationExpression(ObjectCreationExpressionSynt
if (type.IsStatic)
{
diagnostics.Add(ErrorCode.ERR_InstantiatingStaticClass, node.Location, type);
return MakeBadExpressionForObjectCreation(node, type, boundInitializerOpt, analyzedArguments);
return MakeBadExpressionForObjectCreation(node, type, analyzedArguments, diagnostics);
}
else if (node.Type.Kind() == SyntaxKind.TupleType)
{
diagnostics.Add(ErrorCode.ERR_NewWithTupleTypeSyntax, node.Type.GetLocation());
return MakeBadExpressionForObjectCreation(node, type, boundInitializerOpt, analyzedArguments);
return MakeBadExpressionForObjectCreation(node, type, analyzedArguments, diagnostics);
}
return BindClassCreationExpression(node, typeName, node.Type, type, analyzedArguments, diagnostics, boundInitializerOpt);
return BindClassCreationExpression(node, typeName, node.Type, type, analyzedArguments, diagnostics, node.Initializer, initializerType);
}
finally
{
......@@ -3960,13 +3953,17 @@ private BoundExpression BindClassCreationExpression(ObjectCreationExpressionSynt
}
}
private BoundExpression MakeBadExpressionForObjectCreation(ObjectCreationExpressionSyntax node, TypeSymbol type, BoundExpression boundInitializerOpt, AnalyzedArguments analyzedArguments)
private BoundExpression MakeBadExpressionForObjectCreation(ObjectCreationExpressionSyntax node, TypeSymbol type, AnalyzedArguments analyzedArguments, DiagnosticBag diagnostics)
{
var children = ArrayBuilder<BoundExpression>.GetInstance();
children.AddRange(BuildArgumentsForErrorRecovery(analyzedArguments));
if (boundInitializerOpt != null)
if (node.Initializer != null)
{
children.Add(boundInitializerOpt);
var boundInitializer = BindInitializerExpression(syntax: node.Initializer,
type: type,
typeSyntax: node.Type,
diagnostics: diagnostics);
children.Add(boundInitializer);
}
return new BoundBadExpression(node, LookupResultKind.NotCreatable, ImmutableArray.Create<Symbol>(type), children.ToImmutableAndFree(), type);
......@@ -4711,7 +4708,8 @@ private bool IsConstructorAccessible(MethodSymbol constructor, ref HashSet<Diagn
NamedTypeSymbol type,
AnalyzedArguments analyzedArguments,
DiagnosticBag diagnostics,
BoundObjectInitializerExpressionBase boundInitializerOpt = null)
InitializerExpressionSyntax initializerSyntaxOpt = null,
TypeSymbol initializerTypeOpt = null)
{
BoundExpression result = null;
......@@ -4724,6 +4722,7 @@ private bool IsConstructorAccessible(MethodSymbol constructor, ref HashSet<Diagn
}
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
BoundObjectInitializerExpressionBase boundInitializerOpt = null;
// If we have a dynamic argument then do overload resolution to see if there are one or more
// applicable candidates. If there are, then this is a dynamic object creation; we'll work out
......@@ -4744,6 +4743,7 @@ private bool IsConstructorAccessible(MethodSymbol constructor, ref HashSet<Diagn
hasErrors &= ReportBadDynamicArguments(node, argArray, refKindsArray, diagnostics, queryClause: null);
boundInitializerOpt = makeBoundInitializerOpt();
result = new BoundDynamicObjectCreationExpression(
node,
typeName,
......@@ -4795,7 +4795,7 @@ private bool IsConstructorAccessible(MethodSymbol constructor, ref HashSet<Diagn
ReportDiagnosticsIfObsolete(diagnostics, method, node, hasBaseReceiver: false);
// NOTE: Use-site diagnostics were reported during overload resolution.
ConstantValue constantValueOpt = (boundInitializerOpt == null && method.IsDefaultValueTypeConstructor()) ?
ConstantValue constantValueOpt = (initializerSyntaxOpt == null && method.IsDefaultValueTypeConstructor()) ?
FoldParameterlessValueTypeConstructor(type) :
null;
......@@ -4816,6 +4816,7 @@ private bool IsConstructorAccessible(MethodSymbol constructor, ref HashSet<Diagn
diagnostics);
}
boundInitializerOpt = makeBoundInitializerOpt();
result = new BoundObjectCreationExpression(
node,
method,
......@@ -4864,15 +4865,27 @@ private bool IsConstructorAccessible(MethodSymbol constructor, ref HashSet<Diagn
var childNodes = ArrayBuilder<BoundExpression>.GetInstance();
childNodes.AddRange(BuildArgumentsForErrorRecovery(analyzedArguments, candidateConstructors));
if (boundInitializerOpt != null)
if (initializerSyntaxOpt != null)
{
childNodes.Add(boundInitializerOpt);
childNodes.Add(boundInitializerOpt ?? makeBoundInitializerOpt());
}
return new BoundBadExpression(node, resultKind, symbols.ToImmutableAndFree(), childNodes.ToImmutableAndFree(), type);
BoundObjectInitializerExpressionBase makeBoundInitializerOpt()
{
if (initializerSyntaxOpt != null)
{
return BindInitializerExpression(syntax: initializerSyntaxOpt,
type: initializerTypeOpt ?? type,
typeSyntax: typeNode,
diagnostics: diagnostics);
}
return null;
}
}
private BoundExpression BindInterfaceCreationExpression(ObjectCreationExpressionSyntax node, NamedTypeSymbol type, BoundObjectInitializerExpressionBase boundInitializerOpt, DiagnosticBag diagnostics)
private BoundExpression BindInterfaceCreationExpression(ObjectCreationExpressionSyntax node, NamedTypeSymbol type, DiagnosticBag diagnostics)
{
Debug.Assert((object)type != null);
......@@ -4889,7 +4902,7 @@ private BoundExpression BindInterfaceCreationExpression(ObjectCreationExpression
NamedTypeSymbol coClassType = type.ComImportCoClass;
if ((object)coClassType != null)
{
return BindComImportCoClassCreationExpression(node, type, coClassType, boundInitializerOpt, diagnostics);
return BindComImportCoClassCreationExpression(node, type, coClassType, diagnostics);
}
}
......@@ -4909,7 +4922,7 @@ private BoundExpression BindBadInterfaceCreationExpression(ObjectCreationExpress
return result;
}
private BoundExpression BindComImportCoClassCreationExpression(ObjectCreationExpressionSyntax node, NamedTypeSymbol interfaceType, NamedTypeSymbol coClassType, BoundObjectInitializerExpressionBase boundInitializerOpt, DiagnosticBag diagnostics)
private BoundExpression BindComImportCoClassCreationExpression(ObjectCreationExpressionSyntax node, NamedTypeSymbol interfaceType, NamedTypeSymbol coClassType, DiagnosticBag diagnostics)
{
Debug.Assert((object)interfaceType != null);
Debug.Assert(interfaceType.IsInterfaceType());
......@@ -4944,10 +4957,10 @@ private BoundExpression BindComImportCoClassCreationExpression(ObjectCreationExp
// NoPIA support
if (interfaceType.ContainingAssembly.IsLinked)
{
return BindNoPiaObjectCreationExpression(node, interfaceType, coClassType, boundInitializerOpt, diagnostics);
return BindNoPiaObjectCreationExpression(node, interfaceType, coClassType, diagnostics);
}
var classCreation = BindClassCreationExpression(node, coClassType, coClassType.Name, boundInitializerOpt, diagnostics);
var classCreation = BindClassCreationExpression(node, coClassType, coClassType.Name, diagnostics, interfaceType);
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
Conversion conversion = this.Conversions.ClassifyConversionFromExpression(classCreation, interfaceType, ref useSiteDiagnostics, forCast: true);
diagnostics.Add(node, useSiteDiagnostics);
......@@ -4985,7 +4998,6 @@ private BoundExpression BindComImportCoClassCreationExpression(ObjectCreationExp
ObjectCreationExpressionSyntax node,
NamedTypeSymbol interfaceType,
NamedTypeSymbol coClassType,
BoundObjectInitializerExpressionBase boundInitializerOpt,
DiagnosticBag diagnostics)
{
string guidString;
......@@ -4996,6 +5008,12 @@ private BoundExpression BindComImportCoClassCreationExpression(ObjectCreationExp
guidString = System.Guid.Empty.ToString("D");
}
var boundInitializerOpt = node.Initializer == null ? null :
BindInitializerExpression(syntax: node.Initializer,
type: interfaceType,
typeSyntax: node.Type,
diagnostics: diagnostics);
var creation = new BoundNoPiaObjectCreationExpression(node, guidString, boundInitializerOpt, interfaceType);
// Get the bound arguments and the argument names, it is an error if any are present.
......@@ -5020,7 +5038,7 @@ private BoundExpression BindComImportCoClassCreationExpression(ObjectCreationExp
return creation;
}
private BoundExpression BindTypeParameterCreationExpression(ObjectCreationExpressionSyntax node, TypeParameterSymbol typeParameter, BoundObjectInitializerExpressionBase boundInitializerOpt, DiagnosticBag diagnostics)
private BoundExpression BindTypeParameterCreationExpression(ObjectCreationExpressionSyntax node, TypeParameterSymbol typeParameter, DiagnosticBag diagnostics)
{
AnalyzedArguments analyzedArguments = AnalyzedArguments.GetInstance();
BindArgumentsAndNames(node.ArgumentList, diagnostics, analyzedArguments);
......@@ -5039,10 +5057,17 @@ private BoundExpression BindTypeParameterCreationExpression(ObjectCreationExpres
}
else
{
var boundInitializerOpt = node.Initializer == null ?
null :
BindInitializerExpression(
syntax: node.Initializer,
type: typeParameter,
typeSyntax: node.Type,
diagnostics: diagnostics);
return new BoundNewT(node, boundInitializerOpt, typeParameter);
}
return MakeBadExpressionForObjectCreation(node, typeParameter, boundInitializerOpt, analyzedArguments);
return MakeBadExpressionForObjectCreation(node, typeParameter, analyzedArguments, diagnostics);
}
finally
{
......
......@@ -34493,6 +34493,53 @@ public class C
");
Assert.Null(model.GetOperation(node3).Parent);
}
[Fact]
public void OutVarInConstructorUsedInObjectInitializer()
{
var source =
@"
public class C
{
public int Number { get; set; }
public C(out int n)
{
n = 1;
}
public static void Main()
{
C c = new C(out var i) { Number = i };
System.Console.WriteLine(c.Number);
}
}
";
CompileAndVerify(source, expectedOutput: @"1");
}
[Fact]
public void OutVarInConstructorUsedInCollectionInitializer()
{
var source =
@"
public class C : System.Collections.Generic.List<int>
{
public C(out int n)
{
n = 1;
}
public static void Main()
{
C c = new C(out var i) { i, i, i };
System.Console.WriteLine(c[0]);
}
}
";
CompileAndVerify(source, expectedOutput: @"1");
}
}
internal static class OutVarTestsExtensions
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册