diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs index a20aa39f78dc997f0c524c07e717410345d45e46..1a4e0b1daa30ef0a03cbf1414dc8568e1da3f3b4 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Expressions.cs @@ -236,35 +236,43 @@ internal BoundExpression BindValueAllowArgList(ExpressionSyntax node, Diagnostic return CheckValue(result, valueKind, diagnostics); } - internal BoundExpression BindVariableOrAutoPropInitializer( + internal BoundFieldEqualsValue BindFieldInitializer( + FieldSymbol field, EqualsValueClauseSyntax initializerOpt, - RefKind refKind, - TypeSymbol varType, DiagnosticBag diagnostics) { + Debug.Assert((object)this.ContainingMemberOrLambda == field); + if (initializerOpt == null) { return null; } - SymbolKind containingMemberOrLambdaKind = this.ContainingMemberOrLambda.Kind; - Debug.Assert(containingMemberOrLambdaKind == SymbolKind.Field || containingMemberOrLambdaKind == SymbolKind.Method); - bool isMemberInitializer = containingMemberOrLambdaKind == SymbolKind.Field; - Binder initializerBinder = isMemberInitializer ? this.GetBinder(initializerOpt) : this; - + Binder initializerBinder = this.GetBinder(initializerOpt); Debug.Assert(initializerBinder != null); - BindValueKind valueKind; - ExpressionSyntax value; - IsInitializerRefKindValid(initializerOpt, initializerOpt, refKind, diagnostics, out valueKind, out value); - var initializer = initializerBinder.BindPossibleArrayInitializer(value, varType, valueKind, diagnostics); - initializer = initializerBinder.GenerateConversionForAssignment(varType, initializer, diagnostics); + BoundExpression result = initializerBinder.BindVariableOrAutoPropInitializerValue(initializerOpt, RefKind.None, + field.GetFieldType(initializerBinder.FieldsBeingBound), diagnostics); - if (isMemberInitializer) + return new BoundFieldEqualsValue(initializerOpt, field, initializerBinder.GetDeclaredLocalsForScope(initializerOpt), result); + } + + internal BoundExpression BindVariableOrAutoPropInitializerValue( + EqualsValueClauseSyntax initializerOpt, + RefKind refKind, + TypeSymbol varType, + DiagnosticBag diagnostics) + { + if (initializerOpt == null) { - initializer = initializerBinder.WrapWithVariablesIfAny(initializerOpt, initializer); + return null; } + BindValueKind valueKind; + ExpressionSyntax value; + IsInitializerRefKindValid(initializerOpt, initializerOpt, refKind, diagnostics, out valueKind, out value); + BoundExpression initializer = BindPossibleArrayInitializer(value, varType, valueKind, diagnostics); + initializer = GenerateConversionForAssignment(varType, initializer, diagnostics); return initializer; } @@ -278,9 +286,9 @@ internal BoundExpression BindValueAllowArgList(ExpressionSyntax node, Diagnostic binder); } - internal BoundExpression BindParameterDefaultValue( + internal BoundParameterEqualsValue BindParameterDefaultValue( EqualsValueClauseSyntax defaultValueSyntax, - TypeSymbol parameterType, + ParameterSymbol parameter, DiagnosticBag diagnostics, out BoundExpression valueBeforeConversion) { @@ -295,10 +303,11 @@ internal BoundExpression BindValueAllowArgList(ExpressionSyntax node, Diagnostic // Always generate the conversion, even if the expression is not convertible to the given type. // We want the erroneous conversion in the tree. - return defaultValueBinder.WrapWithVariablesIfAny(defaultValueSyntax, defaultValueBinder.GenerateConversionForAssignment(parameterType, valueBeforeConversion, diagnostics, isDefaultParameter: true)); + return new BoundParameterEqualsValue(defaultValueSyntax, parameter, defaultValueBinder.GetDeclaredLocalsForScope(defaultValueSyntax), + defaultValueBinder.GenerateConversionForAssignment(parameter.Type, valueBeforeConversion, diagnostics, isDefaultParameter: true)); } - internal BoundExpression BindEnumConstantInitializer( + internal BoundFieldEqualsValue BindEnumConstantInitializer( SourceEnumConstantSymbol symbol, EqualsValueClauseSyntax equalsValueSyntax, DiagnosticBag diagnostics) @@ -308,7 +317,7 @@ internal BoundExpression BindValueAllowArgList(ExpressionSyntax node, Diagnostic var initializer = initializerBinder.BindValue(equalsValueSyntax.Value, diagnostics, BindValueKind.RValue); initializer = initializerBinder.GenerateConversionForAssignment(symbol.ContainingType.EnumUnderlyingType, initializer, diagnostics); - return initializerBinder.WrapWithVariablesIfAny(equalsValueSyntax, initializer); + return new BoundFieldEqualsValue(equalsValueSyntax, symbol, initializerBinder.GetDeclaredLocalsForScope(equalsValueSyntax), initializer); } public BoundExpression BindExpression(ExpressionSyntax node, DiagnosticBag diagnostics) diff --git a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs index 73b583d0d795495e4f591b8c827f350da36ab16c..6919314e1a887af6ca777827498c44f02d334677 100644 --- a/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs +++ b/src/Compilers/CSharp/Portable/Binder/Binder_Initializers.cs @@ -110,7 +110,7 @@ internal struct ProcessedFieldInitializers parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.FieldInitializer, fieldSymbol); - BoundFieldInitializer boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics); + BoundFieldEqualsValue boundInitializer = BindFieldInitializer(parentBinder, fieldSymbol, initializerNode, diagnostics); boundInitializers.Add(boundInitializer); } } @@ -246,7 +246,7 @@ internal struct ProcessedFieldInitializers return new BoundGlobalStatementInitializer(statementNode, statement); } - private static BoundFieldInitializer BindFieldInitializer(Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax equalsValueClauseNode, + private static BoundFieldEqualsValue BindFieldInitializer(Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax equalsValueClauseNode, DiagnosticBag diagnostics) { Debug.Assert(!fieldSymbol.IsMetadataConstant); @@ -269,17 +269,14 @@ internal struct ProcessedFieldInitializers } binder = new ExecutableCodeBinder(equalsValueClauseNode, fieldSymbol, new LocalScopeBinder(binder)); - var boundInitValue = binder.BindVariableOrAutoPropInitializer(equalsValueClauseNode, RefKind.None, fieldSymbol.GetFieldType(fieldsBeingBound), initializerDiagnostics); + BoundFieldEqualsValue boundInitValue = binder.BindFieldInitializer(fieldSymbol, equalsValueClauseNode, initializerDiagnostics); if (isImplicitlyTypedField) { initializerDiagnostics.Free(); } - return new BoundFieldInitializer( - equalsValueClauseNode.Value, //we want the attached sequence point to indicate the value node - fieldSymbol, - boundInitValue); + return boundInitValue; } } } diff --git a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml index 4e1fe41bd8b6ce96687ae4ea8b566c9e936e990e..164e2585593f5349a16946bb743d393a65e8e711 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml +++ b/src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml @@ -33,12 +33,8 @@ - - - - - - + + diff --git a/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs b/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs index 28ade0abe694227fad3c79fcad76fa20ab9043e3..e19182e7945317d6dabdb5eaf7ab5f42a869f2f5 100644 --- a/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs +++ b/src/Compilers/CSharp/Portable/Compilation/InitializerSemanticModel.cs @@ -157,54 +157,36 @@ private BoundEqualsValue BindEqualsValue(Binder binder, EqualsValueClauseSyntax { var field = (FieldSymbol)this.MemberSymbol; var enumField = field as SourceEnumConstantSymbol; - BoundExpression result; if ((object)enumField != null) { - result = binder.BindEnumConstantInitializer(enumField, equalsValue, diagnostics); + return binder.BindEnumConstantInitializer(enumField, equalsValue, diagnostics); } else { - result = binder.BindVariableOrAutoPropInitializer(equalsValue, RefKind.None, field.GetFieldType(binder.FieldsBeingBound), diagnostics); + return binder.BindFieldInitializer(field, equalsValue, diagnostics); } - if (result != null) - { - return new BoundFieldEqualsValue(equalsValue, field, result); - } - break; } case SymbolKind.Property: { - var property = (PropertySymbol)this.MemberSymbol; - BoundExpression result = binder.BindVariableOrAutoPropInitializer(equalsValue, RefKind.None, property.Type, diagnostics); - if (result != null) - { - return new BoundPropertyEqualsValue(equalsValue, property, result); - } - break; + var property = (SourcePropertySymbol)this.MemberSymbol; + BoundFieldEqualsValue result = binder.BindFieldInitializer(property.BackingField, equalsValue, diagnostics); + return new BoundPropertyEqualsValue(result.Syntax, property, result.Locals, result.Value); } case SymbolKind.Parameter: { - BoundExpression unusedValueBeforeConversion; // not needed. var parameter = (ParameterSymbol)this.MemberSymbol; - BoundExpression result = binder.BindParameterDefaultValue( + return binder.BindParameterDefaultValue( equalsValue, - parameter.Type, + parameter, diagnostics, - out unusedValueBeforeConversion); - if (result != null) - { - return new BoundParameterEqualsValue(equalsValue, parameter, result); - } - break; + out _); } default: throw ExceptionUtilities.UnexpectedValue(this.MemberSymbol.Kind); } - - return null; } private bool IsBindableInitializer(CSharpSyntaxNode node) diff --git a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs index 066889d35dddb1989811f165c268aaacab9df6b1..bc35982a12cb6328670eca39846fa06fe06a2ec0 100644 --- a/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs +++ b/src/Compilers/CSharp/Portable/Compiler/MethodCompiler.cs @@ -565,7 +565,7 @@ private void CompileNamedType(NamedTypeSymbol containingType) if (_moduleBeingBuiltOpt != null && !hasStaticConstructor && !processedStaticInitializers.BoundInitializers.IsDefaultOrEmpty) { Debug.Assert(processedStaticInitializers.BoundInitializers.All((init) => - (init.Kind == BoundKind.FieldInitializer) && !((BoundFieldInitializer)init).Field.IsMetadataConstant)); + (init.Kind == BoundKind.FieldEqualsValue) && !((BoundFieldEqualsValue)init).Field.IsMetadataConstant)); MethodSymbol method = new SynthesizedStaticConstructor(sourceTypeSymbol); if (PassesFilter(_filterOpt, method)) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs index 58cf04f4b7830aa5a00af816cedec64bc3f5b324..8f5a6468620f1127d008089779bf8e0f11acc57e 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/PreciseAbstractFlowPass.cs @@ -1169,12 +1169,6 @@ public override BoundNode VisitScope(BoundScope node) return null; } - public override BoundNode VisitFieldInitializer(BoundFieldInitializer node) - { - Visit(node.InitialValue); - return null; - } - public override BoundNode VisitExpressionStatement(BoundExpressionStatement node) { VisitRvalue(node.Expression); diff --git a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs index 22510a5fc1e6436607dd7c0fc11fabb6b70d67c1..acf1504cef6c4b3b3ff3c639ff85eeb884b32a1d 100644 --- a/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs +++ b/src/Compilers/CSharp/Portable/Generated/BoundNodes.xml.Generated.cs @@ -20,7 +20,6 @@ namespace Microsoft.CodeAnalysis.CSharp { internal enum BoundKind: byte { - FieldInitializer, FieldEqualsValue, PropertyEqualsValue, ParameterEqualsValue, @@ -197,63 +196,33 @@ protected BoundInitializer(BoundKind kind, SyntaxNode syntax) } - internal sealed partial class BoundFieldInitializer : BoundInitializer + internal abstract partial class BoundEqualsValue : BoundInitializer { - public BoundFieldInitializer(SyntaxNode syntax, FieldSymbol field, BoundExpression initialValue, bool hasErrors = false) - : base(BoundKind.FieldInitializer, syntax, hasErrors || initialValue.HasErrors()) - { - - Debug.Assert(field != null, "Field 'field' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); - Debug.Assert(initialValue != null, "Field 'initialValue' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); - - this.Field = field; - this.InitialValue = initialValue; - } - - - public FieldSymbol Field { get; } - - public BoundExpression InitialValue { get; } - - public override BoundNode Accept(BoundTreeVisitor visitor) - { - return visitor.VisitFieldInitializer(this); - } - - public BoundFieldInitializer Update(FieldSymbol field, BoundExpression initialValue) - { - if (field != this.Field || initialValue != this.InitialValue) - { - var result = new BoundFieldInitializer(this.Syntax, field, initialValue, this.HasErrors); - result.WasCompilerGenerated = this.WasCompilerGenerated; - return result; - } - return this; - } - } - - internal abstract partial class BoundEqualsValue : BoundNode - { - protected BoundEqualsValue(BoundKind kind, SyntaxNode syntax, BoundExpression value, bool hasErrors = false) + protected BoundEqualsValue(BoundKind kind, SyntaxNode syntax, ImmutableArray locals, BoundExpression value, bool hasErrors = false) : base(kind, syntax, hasErrors) { + Debug.Assert(!locals.IsDefault, "Field 'locals' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); Debug.Assert(value != null, "Field 'value' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); + this.Locals = locals; this.Value = value; } + public ImmutableArray Locals { get; } + public BoundExpression Value { get; } } internal sealed partial class BoundFieldEqualsValue : BoundEqualsValue { - public BoundFieldEqualsValue(SyntaxNode syntax, FieldSymbol field, BoundExpression value, bool hasErrors = false) - : base(BoundKind.FieldEqualsValue, syntax, value, hasErrors || value.HasErrors()) + public BoundFieldEqualsValue(SyntaxNode syntax, FieldSymbol field, ImmutableArray locals, BoundExpression value, bool hasErrors = false) + : base(BoundKind.FieldEqualsValue, syntax, locals, value, hasErrors || value.HasErrors()) { Debug.Assert(field != null, "Field 'field' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); + Debug.Assert(!locals.IsDefault, "Field 'locals' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); Debug.Assert(value != null, "Field 'value' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); this.Field = field; @@ -267,11 +236,11 @@ public override BoundNode Accept(BoundTreeVisitor visitor) return visitor.VisitFieldEqualsValue(this); } - public BoundFieldEqualsValue Update(FieldSymbol field, BoundExpression value) + public BoundFieldEqualsValue Update(FieldSymbol field, ImmutableArray locals, BoundExpression value) { - if (field != this.Field || value != this.Value) + if (field != this.Field || locals != this.Locals || value != this.Value) { - var result = new BoundFieldEqualsValue(this.Syntax, field, value, this.HasErrors); + var result = new BoundFieldEqualsValue(this.Syntax, field, locals, value, this.HasErrors); result.WasCompilerGenerated = this.WasCompilerGenerated; return result; } @@ -281,11 +250,12 @@ public BoundFieldEqualsValue Update(FieldSymbol field, BoundExpression value) internal sealed partial class BoundPropertyEqualsValue : BoundEqualsValue { - public BoundPropertyEqualsValue(SyntaxNode syntax, PropertySymbol property, BoundExpression value, bool hasErrors = false) - : base(BoundKind.PropertyEqualsValue, syntax, value, hasErrors || value.HasErrors()) + public BoundPropertyEqualsValue(SyntaxNode syntax, PropertySymbol property, ImmutableArray locals, BoundExpression value, bool hasErrors = false) + : base(BoundKind.PropertyEqualsValue, syntax, locals, value, hasErrors || value.HasErrors()) { Debug.Assert(property != null, "Field 'property' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); + Debug.Assert(!locals.IsDefault, "Field 'locals' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); Debug.Assert(value != null, "Field 'value' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); this.Property = property; @@ -299,11 +269,11 @@ public override BoundNode Accept(BoundTreeVisitor visitor) return visitor.VisitPropertyEqualsValue(this); } - public BoundPropertyEqualsValue Update(PropertySymbol property, BoundExpression value) + public BoundPropertyEqualsValue Update(PropertySymbol property, ImmutableArray locals, BoundExpression value) { - if (property != this.Property || value != this.Value) + if (property != this.Property || locals != this.Locals || value != this.Value) { - var result = new BoundPropertyEqualsValue(this.Syntax, property, value, this.HasErrors); + var result = new BoundPropertyEqualsValue(this.Syntax, property, locals, value, this.HasErrors); result.WasCompilerGenerated = this.WasCompilerGenerated; return result; } @@ -313,11 +283,12 @@ public BoundPropertyEqualsValue Update(PropertySymbol property, BoundExpression internal sealed partial class BoundParameterEqualsValue : BoundEqualsValue { - public BoundParameterEqualsValue(SyntaxNode syntax, ParameterSymbol parameter, BoundExpression value, bool hasErrors = false) - : base(BoundKind.ParameterEqualsValue, syntax, value, hasErrors || value.HasErrors()) + public BoundParameterEqualsValue(SyntaxNode syntax, ParameterSymbol parameter, ImmutableArray locals, BoundExpression value, bool hasErrors = false) + : base(BoundKind.ParameterEqualsValue, syntax, locals, value, hasErrors || value.HasErrors()) { Debug.Assert(parameter != null, "Field 'parameter' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); + Debug.Assert(!locals.IsDefault, "Field 'locals' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); Debug.Assert(value != null, "Field 'value' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)"); this.Parameter = parameter; @@ -331,11 +302,11 @@ public override BoundNode Accept(BoundTreeVisitor visitor) return visitor.VisitParameterEqualsValue(this); } - public BoundParameterEqualsValue Update(ParameterSymbol parameter, BoundExpression value) + public BoundParameterEqualsValue Update(ParameterSymbol parameter, ImmutableArray locals, BoundExpression value) { - if (parameter != this.Parameter || value != this.Value) + if (parameter != this.Parameter || locals != this.Locals || value != this.Value) { - var result = new BoundParameterEqualsValue(this.Syntax, parameter, value, this.HasErrors); + var result = new BoundParameterEqualsValue(this.Syntax, parameter, locals, value, this.HasErrors); result.WasCompilerGenerated = this.WasCompilerGenerated; return result; } @@ -6232,8 +6203,6 @@ internal R VisitInternal(BoundNode node, A arg) { switch (node.Kind) { - case BoundKind.FieldInitializer: - return VisitFieldInitializer(node as BoundFieldInitializer, arg); case BoundKind.FieldEqualsValue: return VisitFieldEqualsValue(node as BoundFieldEqualsValue, arg); case BoundKind.PropertyEqualsValue: @@ -6544,10 +6513,6 @@ internal R VisitInternal(BoundNode node, A arg) internal abstract partial class BoundTreeVisitor { - public virtual R VisitFieldInitializer(BoundFieldInitializer node, A arg) - { - return this.DefaultVisit(node, arg); - } public virtual R VisitFieldEqualsValue(BoundFieldEqualsValue node, A arg) { return this.DefaultVisit(node, arg); @@ -7156,10 +7121,6 @@ public virtual R VisitConstructorMethodBody(BoundConstructorMethodBody node, A a internal abstract partial class BoundTreeVisitor { - public virtual BoundNode VisitFieldInitializer(BoundFieldInitializer node) - { - return this.DefaultVisit(node); - } public virtual BoundNode VisitFieldEqualsValue(BoundFieldEqualsValue node) { return this.DefaultVisit(node); @@ -7768,11 +7729,6 @@ public virtual BoundNode VisitConstructorMethodBody(BoundConstructorMethodBody n internal abstract partial class BoundTreeWalker: BoundTreeVisitor { - public override BoundNode VisitFieldInitializer(BoundFieldInitializer node) - { - this.Visit(node.InitialValue); - return null; - } public override BoundNode VisitFieldEqualsValue(BoundFieldEqualsValue node) { this.Visit(node.Value); @@ -8558,25 +8514,20 @@ public override BoundNode VisitConstructorMethodBody(BoundConstructorMethodBody internal abstract partial class BoundTreeRewriter : BoundTreeVisitor { - public override BoundNode VisitFieldInitializer(BoundFieldInitializer node) - { - BoundExpression initialValue = (BoundExpression)this.Visit(node.InitialValue); - return node.Update(node.Field, initialValue); - } public override BoundNode VisitFieldEqualsValue(BoundFieldEqualsValue node) { BoundExpression value = (BoundExpression)this.Visit(node.Value); - return node.Update(node.Field, value); + return node.Update(node.Field, node.Locals, value); } public override BoundNode VisitPropertyEqualsValue(BoundPropertyEqualsValue node) { BoundExpression value = (BoundExpression)this.Visit(node.Value); - return node.Update(node.Property, value); + return node.Update(node.Property, node.Locals, value); } public override BoundNode VisitParameterEqualsValue(BoundParameterEqualsValue node) { BoundExpression value = (BoundExpression)this.Visit(node.Value); - return node.Update(node.Parameter, value); + return node.Update(node.Parameter, node.Locals, value); } public override BoundNode VisitGlobalStatementInitializer(BoundGlobalStatementInitializer node) { @@ -9463,20 +9414,12 @@ public static TreeDumperNode MakeTree(BoundNode node) { return (new BoundTreeDumperNodeProducer()).Visit(node, null); } - public override TreeDumperNode VisitFieldInitializer(BoundFieldInitializer node, object arg) - { - return new TreeDumperNode("fieldInitializer", null, new TreeDumperNode[] - { - new TreeDumperNode("field", node.Field, null), - new TreeDumperNode("initialValue", null, new TreeDumperNode[] { Visit(node.InitialValue, null) }) - } - ); - } public override TreeDumperNode VisitFieldEqualsValue(BoundFieldEqualsValue node, object arg) { return new TreeDumperNode("fieldEqualsValue", null, new TreeDumperNode[] { new TreeDumperNode("field", node.Field, null), + new TreeDumperNode("locals", node.Locals, null), new TreeDumperNode("value", null, new TreeDumperNode[] { Visit(node.Value, null) }) } ); @@ -9486,6 +9429,7 @@ public override TreeDumperNode VisitPropertyEqualsValue(BoundPropertyEqualsValue return new TreeDumperNode("propertyEqualsValue", null, new TreeDumperNode[] { new TreeDumperNode("property", node.Property, null), + new TreeDumperNode("locals", node.Locals, null), new TreeDumperNode("value", null, new TreeDumperNode[] { Visit(node.Value, null) }) } ); @@ -9495,6 +9439,7 @@ public override TreeDumperNode VisitParameterEqualsValue(BoundParameterEqualsVal return new TreeDumperNode("parameterEqualsValue", null, new TreeDumperNode[] { new TreeDumperNode("parameter", node.Parameter, null), + new TreeDumperNode("locals", node.Locals, null), new TreeDumperNode("value", null, new TreeDumperNode[] { Visit(node.Value, null) }) } ); diff --git a/src/Compilers/CSharp/Portable/Lowering/InitializerRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/InitializerRewriter.cs index 6f4640d218a4382371cac64b6259e8f08e1fcc70..4c7c9374da3461f617ae9ca6aab9f54c68ce3ce8 100644 --- a/src/Compilers/CSharp/Portable/Lowering/InitializerRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/InitializerRewriter.cs @@ -82,9 +82,10 @@ internal static BoundExpression GetTrailingScriptExpression(BoundStatement state null; } - private static BoundStatement RewriteFieldInitializer(BoundFieldInitializer fieldInit) + private static BoundStatement RewriteFieldInitializer(BoundFieldEqualsValue fieldInit) { - var syntax = fieldInit.Syntax; + SyntaxNode syntax = fieldInit.Syntax; + syntax = (syntax as EqualsValueClauseSyntax)?.Value ?? syntax; //we want the attached sequence point to indicate the value node var boundReceiver = fieldInit.Field.IsStatic ? null : new BoundThisReference(syntax, fieldInit.Field.ContainingType); @@ -95,7 +96,10 @@ private static BoundStatement RewriteFieldInitializer(BoundFieldInitializer fiel boundReceiver, fieldInit.Field, constantValueOpt: null), - fieldInit.InitialValue, + fieldInit.Locals.IsEmpty ? + fieldInit.Value : + new BoundSequence(fieldInit.Syntax, fieldInit.Locals, ImmutableArray.Empty, fieldInit.Value, fieldInit.Value.Type) + { WasCompilerGenerated = true }, fieldInit.Field.Type) { WasCompilerGenerated = true }) { WasCompilerGenerated = fieldInit.WasCompilerGenerated }; @@ -108,8 +112,8 @@ private static BoundStatement RewriteInitializersAsStatements(BoundInitializer i { switch (initializer.Kind) { - case BoundKind.FieldInitializer: - return RewriteFieldInitializer((BoundFieldInitializer)initializer); + case BoundKind.FieldEqualsValue: + return RewriteFieldInitializer((BoundFieldEqualsValue)initializer); case BoundKind.GlobalStatementInitializer: return ((BoundGlobalStatementInitializer)initializer).Statement; default: diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.Analysis.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.Analysis.cs index 216cca9ee6d9eaec7cbbf2fd93308e35657bc8d4..57b2704c05a6b831529e69ddb4cdefbd3a05a01f 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.Analysis.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.Analysis.cs @@ -111,7 +111,7 @@ private static BoundNode FindNodeToAnalyze(BoundNode node) case BoundKind.Block: case BoundKind.StatementList: - case BoundKind.FieldInitializer: + case BoundKind.FieldEqualsValue: return node; case BoundKind.GlobalStatementInitializer: diff --git a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs index 2a7fdec617bfa63b442e204785862ed7138e2cd1..be5e507d9668894d7e2dd730a28979972feff52f 100644 --- a/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs +++ b/src/Compilers/CSharp/Portable/Operations/CSharpOperationFactory.cs @@ -1254,7 +1254,7 @@ private IFieldInitializerOperation CreateBoundFieldEqualsValueOperation(BoundFie ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundFieldEqualsValue.WasCompilerGenerated; - return new LazyFieldInitializer(initializedFields, value, kind, _semanticModel, syntax, type, constantValue, isImplicit); + return new LazyFieldInitializer(boundFieldEqualsValue.Locals.As(), initializedFields, value, kind, _semanticModel, syntax, type, constantValue, isImplicit); } private IPropertyInitializerOperation CreateBoundPropertyEqualsValueOperation(BoundPropertyEqualsValue boundPropertyEqualsValue) @@ -1266,7 +1266,7 @@ private IPropertyInitializerOperation CreateBoundPropertyEqualsValueOperation(Bo ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundPropertyEqualsValue.WasCompilerGenerated; - return new LazyPropertyInitializer(initializedProperties, value, kind, _semanticModel, syntax, type, constantValue, isImplicit); + return new LazyPropertyInitializer(boundPropertyEqualsValue.Locals.As(), initializedProperties, value, kind, _semanticModel, syntax, type, constantValue, isImplicit); } private IParameterInitializerOperation CreateBoundParameterEqualsValueOperation(BoundParameterEqualsValue boundParameterEqualsValue) @@ -1278,7 +1278,7 @@ private IParameterInitializerOperation CreateBoundParameterEqualsValueOperation( ITypeSymbol type = null; Optional constantValue = default(Optional); bool isImplicit = boundParameterEqualsValue.WasCompilerGenerated; - return new LazyParameterInitializer(parameter, value, kind, _semanticModel, syntax, type, constantValue, isImplicit); + return new LazyParameterInitializer(boundParameterEqualsValue.Locals.As(), parameter, value, kind, _semanticModel, syntax, type, constantValue, isImplicit); } private IBlockOperation CreateBoundBlockOperation(BoundBlock boundBlock) diff --git a/src/Compilers/CSharp/Portable/Symbols/ConstantValueUtils.cs b/src/Compilers/CSharp/Portable/Symbols/ConstantValueUtils.cs index e52e90d14f89364870ec213a45eb0e997e0cdb2b..627c2c7d09cdf98094464e8d50b0be5243585cff 100644 --- a/src/Compilers/CSharp/Portable/Symbols/ConstantValueUtils.cs +++ b/src/Compilers/CSharp/Portable/Symbols/ConstantValueUtils.cs @@ -36,16 +36,16 @@ internal static class ConstantValueUtils binder = new EarlyWellKnownAttributeBinder(binder); } var inProgressBinder = new ConstantFieldsInProgressBinder(new ConstantFieldsInProgress(symbol, dependencies), binder); - var boundValue = BindFieldOrEnumInitializer(inProgressBinder, symbol, equalsValueNode, diagnostics); + BoundFieldEqualsValue boundValue = BindFieldOrEnumInitializer(inProgressBinder, symbol, equalsValueNode, diagnostics); var initValueNodeLocation = equalsValueNode.Value.Location; - var value = GetAndValidateConstantValue(boundValue, symbol, symbol.Type, initValueNodeLocation, diagnostics); + var value = GetAndValidateConstantValue(boundValue.Value, symbol, symbol.Type, initValueNodeLocation, diagnostics); Debug.Assert(value != null); return value; } - private static BoundExpression BindFieldOrEnumInitializer( + private static BoundFieldEqualsValue BindFieldOrEnumInitializer( Binder binder, FieldSymbol fieldSymbol, EqualsValueClauseSyntax initializer, @@ -54,7 +54,7 @@ internal static class ConstantValueUtils var enumConstant = fieldSymbol as SourceEnumConstantSymbol; Binder collisionDetector = new LocalScopeBinder(binder); collisionDetector = new ExecutableCodeBinder(initializer, fieldSymbol, collisionDetector); - BoundExpression result; + BoundFieldEqualsValue result; if ((object)enumConstant != null) { @@ -62,7 +62,7 @@ internal static class ConstantValueUtils } else { - result = collisionDetector.BindVariableOrAutoPropInitializer(initializer, RefKind.None, fieldSymbol.Type, diagnostics); + result = collisionDetector.BindFieldInitializer(fieldSymbol, initializer, diagnostics); } return result; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs index 7608653e1348dcd8f8a7bff3023fed838ab46148..d14431b5411433999599c2c7a6fa221020f469a6 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceComplexParameterSymbol.cs @@ -186,7 +186,7 @@ protected ConstantValue MakeDefaultExpression(DiagnosticBag diagnostics, Binder Debug.Assert(binderForDefault.ContainingMemberOrLambda == ContainingSymbol); BoundExpression valueBeforeConversion; - var convertedExpression = binderForDefault.BindParameterDefaultValue(defaultSyntax, parameterType, diagnostics, out valueBeforeConversion); + BoundExpression convertedExpression = binderForDefault.BindParameterDefaultValue(defaultSyntax, this, diagnostics, out valueBeforeConversion).Value; if (valueBeforeConversion.HasErrors) { return ConstantValue.Bad; diff --git a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs index 8cb1c5c3f393416ad7280416a4e48cc33fe80c23..4922eb0fb91fa150b8769c1e3f57d0fca18cb929 100644 --- a/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs +++ b/src/Compilers/CSharp/Portable/Symbols/Source/SourceLocalSymbol.cs @@ -545,7 +545,7 @@ private void MakeConstantTuple(LocalSymbol inProgress, BoundExpression boundInit if (boundInitValue == null) { var inProgressBinder = new LocalInProgressBinder(this, this._initializerBinder); - boundInitValue = inProgressBinder.BindVariableOrAutoPropInitializer(_initializer, this.RefKind, type, diagnostics); + boundInitValue = inProgressBinder.BindVariableOrAutoPropInitializerValue(_initializer, this.RefKind, type, diagnostics); } value = ConstantValueUtils.GetAndValidateConstantValue(boundInitValue, this, type, initValueNodeLocation, diagnostics); diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/FieldInitializerBindingTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/FieldInitializerBindingTests.cs index 0d4164746694ec7cb86ec42e0a56b540a3096eb0..a2b64c5e06341010cf23b8d4f1b65787bd79413d 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/FieldInitializerBindingTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/FieldInitializerBindingTests.cs @@ -267,12 +267,12 @@ private static void CheckBoundInitializers(IEnumerable expe foreach (var expectedInitializer in expectedInitializers) { var boundInit = boundInitializers[i++]; - Assert.Equal(BoundKind.FieldInitializer, boundInit.Kind); + Assert.Equal(BoundKind.FieldEqualsValue, boundInit.Kind); - var boundFieldInit = (BoundFieldInitializer)boundInit; + var boundFieldInit = (BoundFieldEqualsValue)boundInit; - var initValueSyntax = boundFieldInit.InitialValue.Syntax; - Assert.Same(initValueSyntax, boundInit.Syntax); + var initValueSyntax = boundFieldInit.Value.Syntax; + Assert.Same(initValueSyntax.Parent, boundInit.Syntax); Assert.Equal(expectedInitializer.InitialValue, initValueSyntax.ToFullString()); var initValueLineNumber = syntaxTree.GetLineSpan(initValueSyntax.Span).StartLinePosition.Line; diff --git a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs index 5ac40d23869ab7cfa08bdf977620116af1a5600a..3692643f22189011299864fbc759ad13af1e278a 100644 --- a/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs +++ b/src/Compilers/CSharp/Test/Semantic/Semantics/OutVarTests.cs @@ -5047,6 +5047,7 @@ static bool TakeOutParam(object y, out int x) VerifyModelForOutVar(model, x9Decl); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void Scope_FieldInitializers_02() { @@ -5136,6 +5137,36 @@ public static bool TakeOutParam(object y, out int x) Assert.Equal(2, x7Ref.Length); VerifyModelForOutVar(model, x7Decl, x7Ref[0]); VerifyNotInScope(model, x7Ref[1]); + + var node = tree.GetRoot().DescendantNodes().OfType().First(); + + compilation.VerifyOperationTree(node, expectedOperationTree: +@" +IFieldInitializerOperation (Field: X.Test3) (OperationKind.FieldInitializer, Type: null, IsInvalid) (Syntax: '= TakeOutPa ... 3) ? x3 : 0') + Locals: Local_1: System.Int32 x3 + IConditionalOperation (OperationKind.Conditional, Type: System.Int32, IsInvalid) (Syntax: 'TakeOutPara ... 3) ? x3 : 0') + Condition: + IInvocationOperation (System.Boolean Test.TakeOutParam(System.Object y, out System.Int32 x)) (OperationKind.Invocation, Type: System.Boolean, IsInvalid) (Syntax: 'TakeOutPara ... out int x3)') + Instance Receiver: + null + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: y) (OperationKind.Argument, Type: null, IsInvalid) (Syntax: '3') + IConversionOperation (TryCast: False, Unchecked) (OperationKind.Conversion, Type: System.Object, IsInvalid, IsImplicit) (Syntax: '3') + Conversion: CommonConversion (Exists: True, IsIdentity: False, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Operand: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3, IsInvalid) (Syntax: '3') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null, IsInvalid) (Syntax: 'out int x3') + IDeclarationExpressionOperation (OperationKind.DeclarationExpression, Type: System.Int32, IsInvalid) (Syntax: 'int x3') + ILocalReferenceOperation: x3 (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'x3') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + WhenTrue: + ILocalReferenceOperation: x3 (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'x3') + WhenFalse: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsInvalid) (Syntax: '0') +"); } [Fact] @@ -5236,6 +5267,7 @@ static bool TakeOutParam(object y, out int x) VerifyNotInScope(model, x7Ref[2]); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void FieldInitializers_01() { @@ -5272,6 +5304,39 @@ static bool TakeOutParam(int y, out int x) // static bool Test1 = TakeOutParam(1, out int x1) && Dummy(x1); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "int x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(9, 45) ); + + var tree = compilation.SyntaxTrees.Single(); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + + compilation.VerifyOperationTree(node, expectedOperationTree: +@" +IFieldInitializerOperation (Field: System.Boolean X.Test1) (OperationKind.FieldInitializer, Type: null) (Syntax: '= TakeOutPa ... & Dummy(x1)') + Locals: Local_1: System.Int32 x1 + IBinaryOperation (BinaryOperatorKind.And) (OperationKind.BinaryOperator, Type: System.Boolean) (Syntax: 'TakeOutPara ... & Dummy(x1)') + Left: + IInvocationOperation (System.Boolean X.TakeOutParam(System.Int32 y, out System.Int32 x)) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'TakeOutPara ... out int x1)') + Instance Receiver: + null + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: y) (OperationKind.Argument, Type: null) (Syntax: '1') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: 'out int x1') + IDeclarationExpressionOperation (OperationKind.DeclarationExpression, Type: System.Int32) (Syntax: 'int x1') + ILocalReferenceOperation: x1 (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInvocationOperation (System.Boolean X.Dummy(System.Int32 x)) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'Dummy(x1)') + Instance Receiver: + null + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: 'x1') + ILocalReferenceOperation: x1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) +"); } [Fact] @@ -10390,6 +10455,7 @@ static bool TakeOutParam(T y, out T x) VerifyModelForOutVar(model, x1Decl[1], x1Ref[1]); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void Scope_ParameterDefault_01() { @@ -10496,6 +10562,35 @@ static bool TakeOutParam(int y, out int x) VerifyModelForOutVar(model, x7Decl, x7Ref[0]); VerifyNotInScope(model, x7Ref[1]); VerifyNotInScope(model, x7Ref[2]); + + var node = tree.GetRoot().DescendantNodes().OfType().First(); + + compilation.VerifyOperationTree(node, expectedOperationTree: +@" +IParameterInitializerOperation (Parameter: [System.Boolean p = default(System.Boolean)]) (OperationKind.ParameterInitializer, Type: null, IsInvalid) (Syntax: '= TakeOutPa ... ) && x3 > 0') + Locals: Local_1: System.Int32 x3 + IBinaryOperation (BinaryOperatorKind.And) (OperationKind.BinaryOperator, Type: System.Boolean, IsInvalid) (Syntax: 'TakeOutPara ... ) && x3 > 0') + Left: + IInvocationOperation (System.Boolean X.TakeOutParam(System.Int32 y, out System.Int32 x)) (OperationKind.Invocation, Type: System.Boolean, IsInvalid) (Syntax: 'TakeOutPara ... out int x3)') + Instance Receiver: + null + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: y) (OperationKind.Argument, Type: null, IsInvalid) (Syntax: '3') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 3, IsInvalid) (Syntax: '3') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null, IsInvalid) (Syntax: 'out int x3') + IDeclarationExpressionOperation (OperationKind.DeclarationExpression, Type: System.Int32, IsInvalid) (Syntax: 'int x3') + ILocalReferenceOperation: x3 (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'x3') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IBinaryOperation (BinaryOperatorKind.GreaterThan) (OperationKind.BinaryOperator, Type: System.Boolean, IsInvalid) (Syntax: 'x3 > 0') + Left: + ILocalReferenceOperation: x3 (OperationKind.LocalReference, Type: System.Int32, IsInvalid) (Syntax: 'x3') + Right: + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 0, IsInvalid) (Syntax: '0') +"); } [Fact] @@ -10688,6 +10783,7 @@ static bool TakeOutParam(int y, out int x) VerifyNotInScope(model, x7Ref[2]); } + [CompilerTrait(CompilerFeature.IOperation)] [Fact] public void PropertyInitializers_01() { @@ -10724,6 +10820,38 @@ static bool TakeOutParam(int y, out int x) // static bool Test1 {get;} = TakeOutParam(1, out int x1) && Dummy(x1); Diagnostic(ErrorCode.ERR_FeatureNotAvailableInVersion7_2, "int x1").WithArguments("declaration of expression variables in member initializers and queries", "7.3").WithLocation(9, 52) ); + var tree = compilation.SyntaxTrees.Single(); + var node = tree.GetRoot().DescendantNodes().OfType().Single(); + + compilation.VerifyOperationTree(node, expectedOperationTree: +@" +IPropertyInitializerOperation (Property: System.Boolean X.Test1 { get; }) (OperationKind.PropertyInitializer, Type: null) (Syntax: '= TakeOutPa ... & Dummy(x1)') + Locals: Local_1: System.Int32 x1 + IBinaryOperation (BinaryOperatorKind.And) (OperationKind.BinaryOperator, Type: System.Boolean) (Syntax: 'TakeOutPara ... & Dummy(x1)') + Left: + IInvocationOperation (System.Boolean X.TakeOutParam(System.Int32 y, out System.Int32 x)) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'TakeOutPara ... out int x1)') + Instance Receiver: + null + Arguments(2): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: y) (OperationKind.Argument, Type: null) (Syntax: '1') + ILiteralOperation (OperationKind.Literal, Type: System.Int32, Constant: 1) (Syntax: '1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: 'out int x1') + IDeclarationExpressionOperation (OperationKind.DeclarationExpression, Type: System.Int32) (Syntax: 'int x1') + ILocalReferenceOperation: x1 (IsDeclaration: True) (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + Right: + IInvocationOperation (System.Boolean X.Dummy(System.Int32 x)) (OperationKind.Invocation, Type: System.Boolean) (Syntax: 'Dummy(x1)') + Instance Receiver: + null + Arguments(1): + IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: x) (OperationKind.Argument, Type: null) (Syntax: 'x1') + ILocalReferenceOperation: x1 (OperationKind.LocalReference, Type: System.Int32) (Syntax: 'x1') + InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) + OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null) +"); } [Fact] diff --git a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs index 67aa1e610c72e304c681ad9f178ff560bc81eb33..3766cd22e116f5651809a9c47ec72d10c60e1074 100644 --- a/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs +++ b/src/Compilers/Core/Portable/Generated/Operations.xml.Generated.cs @@ -1733,6 +1733,8 @@ public override void Accept(OperationVisitor visitor) { return visitor.VisitVariableInitializer(this, argument); } + + ImmutableArray ISymbolInitializerOperation.Locals => ImmutableArray.Empty; } /// @@ -1768,11 +1770,15 @@ internal sealed partial class LazyVariableInitializer : BaseVariableInitializer, /// internal abstract partial class BaseFieldInitializer : SymbolInitializer, IFieldInitializerOperation { - public BaseFieldInitializer(ImmutableArray initializedFields, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + public BaseFieldInitializer(ImmutableArray locals, ImmutableArray initializedFields, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : base(kind, semanticModel, syntax, type, constantValue, isImplicit) { + Locals = locals; InitializedFields = initializedFields; } + + public ImmutableArray Locals { get; } + /// /// Initialized fields. There can be multiple fields for Visual Basic fields declared with As New. /// @@ -1803,8 +1809,8 @@ public override void Accept(OperationVisitor visitor) /// internal sealed partial class FieldInitializer : BaseFieldInitializer, IFieldInitializerOperation { - public FieldInitializer(ImmutableArray initializedFields, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : - base(initializedFields, kind, semanticModel, syntax, type, constantValue, isImplicit) + public FieldInitializer(ImmutableArray locals, ImmutableArray initializedFields, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + base(locals, initializedFields, kind, semanticModel, syntax, type, constantValue, isImplicit) { ValueImpl = value; } @@ -1818,8 +1824,8 @@ internal sealed partial class LazyFieldInitializer : BaseFieldInitializer, IFiel { private readonly Lazy _lazyValue; - public LazyFieldInitializer(ImmutableArray initializedFields, Lazy value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : - base(initializedFields, kind, semanticModel, syntax, type, constantValue, isImplicit) + public LazyFieldInitializer(ImmutableArray locals, ImmutableArray initializedFields, Lazy value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + base(locals, initializedFields, kind, semanticModel, syntax, type, constantValue, isImplicit) { _lazyValue = value ?? throw new System.ArgumentNullException(nameof(value)); } @@ -3762,11 +3768,15 @@ public override void Accept(OperationVisitor visitor) /// internal abstract partial class BaseParameterInitializer : SymbolInitializer, IParameterInitializerOperation { - public BaseParameterInitializer(IParameterSymbol parameter, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + public BaseParameterInitializer(ImmutableArray locals, IParameterSymbol parameter, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : base(kind, semanticModel, syntax, type, constantValue, isImplicit) { + Locals = locals; Parameter = parameter; } + + public ImmutableArray Locals { get; } + /// /// Initialized parameter. /// @@ -3797,8 +3807,8 @@ public override void Accept(OperationVisitor visitor) /// internal sealed partial class ParameterInitializer : BaseParameterInitializer, IParameterInitializerOperation { - public ParameterInitializer(IParameterSymbol parameter, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : - base(parameter, kind, semanticModel, syntax, type, constantValue, isImplicit) + public ParameterInitializer(ImmutableArray locals, IParameterSymbol parameter, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + base(locals, parameter, kind, semanticModel, syntax, type, constantValue, isImplicit) { ValueImpl = value; } @@ -3812,8 +3822,8 @@ internal sealed partial class LazyParameterInitializer : BaseParameterInitialize { private readonly Lazy _lazyValue; - public LazyParameterInitializer(IParameterSymbol parameter, Lazy value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : - base(parameter, kind, semanticModel, syntax, type, constantValue, isImplicit) + public LazyParameterInitializer(ImmutableArray locals, IParameterSymbol parameter, Lazy value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + base(locals, parameter, kind, semanticModel, syntax, type, constantValue, isImplicit) { _lazyValue = value ?? throw new System.ArgumentNullException(nameof(value)); } @@ -4015,11 +4025,15 @@ public LazyPointerIndirectionReferenceExpression(Lazy pointer, Seman /// internal abstract partial class BasePropertyInitializer : SymbolInitializer, IPropertyInitializerOperation { - public BasePropertyInitializer(ImmutableArray initializedProperties, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + public BasePropertyInitializer(ImmutableArray locals, ImmutableArray initializedProperties, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : base(kind, semanticModel, syntax, type, constantValue, isImplicit) { + Locals = locals; InitializedProperties = initializedProperties; } + + public ImmutableArray Locals { get; } + /// /// Initialized properties. There can be multiple properties for Visual Basic 'WithEvents' declaration with AsNew clause. /// @@ -4050,8 +4064,8 @@ public override void Accept(OperationVisitor visitor) /// internal sealed partial class PropertyInitializer : BasePropertyInitializer, IPropertyInitializerOperation { - public PropertyInitializer(ImmutableArray initializedProperties, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : - base(initializedProperties, kind, semanticModel, syntax, type, constantValue, isImplicit) + public PropertyInitializer(ImmutableArray locals, ImmutableArray initializedProperties, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + base(locals, initializedProperties, kind, semanticModel, syntax, type, constantValue, isImplicit) { ValueImpl = value; } @@ -4065,8 +4079,8 @@ internal sealed partial class LazyPropertyInitializer : BasePropertyInitializer, { private readonly Lazy _lazyValue; - public LazyPropertyInitializer(ImmutableArray initializedProperties, Lazy value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : - base(initializedProperties, kind, semanticModel, syntax, type, constantValue, isImplicit) + public LazyPropertyInitializer(ImmutableArray locals, ImmutableArray initializedProperties, Lazy value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : + base(locals, initializedProperties, kind, semanticModel, syntax, type, constantValue, isImplicit) { _lazyValue = value ?? throw new System.ArgumentNullException(nameof(value)); } @@ -4713,7 +4727,7 @@ public LazySwitchStatement(Lazy value, Lazy /// Represents an initializer for a field, property, or parameter. /// - internal abstract partial class SymbolInitializer : Operation, ISymbolInitializerOperation + internal abstract partial class SymbolInitializer : Operation { protected SymbolInitializer(OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional constantValue, bool isImplicit) : base(kind, semanticModel, syntax, type, constantValue, isImplicit) diff --git a/src/Compilers/Core/Portable/Operations/ISymbolInitializerOperation.cs b/src/Compilers/Core/Portable/Operations/ISymbolInitializerOperation.cs index a793c5ce702c054e09bc6e96d02d62d5448a7294..236238edc7fb857d13e8918f4422738e39b4c8ee 100644 --- a/src/Compilers/Core/Portable/Operations/ISymbolInitializerOperation.cs +++ b/src/Compilers/Core/Portable/Operations/ISymbolInitializerOperation.cs @@ -1,5 +1,7 @@ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. +using System.Collections.Immutable; + namespace Microsoft.CodeAnalysis.Operations { /// @@ -16,6 +18,11 @@ namespace Microsoft.CodeAnalysis.Operations /// public interface ISymbolInitializerOperation : IOperation { + /// + /// Local declared in and scoped to the . + /// + ImmutableArray Locals { get; } + /// /// Underlying initializer value. /// diff --git a/src/Compilers/Core/Portable/Operations/OperationCloner.cs b/src/Compilers/Core/Portable/Operations/OperationCloner.cs index 5fb7f925e649d71a791197d073870782875ffddf..ec4a0891718a8a3e0b8e47e881c19d24f67b6ccc 100644 --- a/src/Compilers/Core/Portable/Operations/OperationCloner.cs +++ b/src/Compilers/Core/Portable/Operations/OperationCloner.cs @@ -342,7 +342,7 @@ public override IOperation VisitCollectionElementInitializer(ICollectionElementI public override IOperation VisitFieldInitializer(IFieldInitializerOperation operation, object argument) { - return new FieldInitializer(operation.InitializedFields, Visit(operation.Value), operation.Kind, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); + return new FieldInitializer(operation.Locals, operation.InitializedFields, Visit(operation.Value), operation.Kind, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); } public override IOperation VisitVariableInitializer(IVariableInitializerOperation operation, object argument) @@ -352,12 +352,12 @@ public override IOperation VisitVariableInitializer(IVariableInitializerOperatio public override IOperation VisitPropertyInitializer(IPropertyInitializerOperation operation, object argument) { - return new PropertyInitializer(operation.InitializedProperties, Visit(operation.Value), operation.Kind, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); + return new PropertyInitializer(operation.Locals, operation.InitializedProperties, Visit(operation.Value), operation.Kind, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); } public override IOperation VisitParameterInitializer(IParameterInitializerOperation operation, object argument) { - return new ParameterInitializer(operation.Parameter, Visit(operation.Value), operation.Kind, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); + return new ParameterInitializer(operation.Locals, operation.Parameter, Visit(operation.Value), operation.Kind, ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit); } public override IOperation VisitArrayCreation(IArrayCreationOperation operation, object argument) diff --git a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt index ecd343f89bfde9c2e0c45b058b795db5c295caeb..0b7e44fc52773ed78b7110acc182599d5f043f20 100644 --- a/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt +++ b/src/Compilers/Core/Portable/PublicAPI.Unshipped.txt @@ -5,6 +5,7 @@ Microsoft.CodeAnalysis.MetadataImportOptions Microsoft.CodeAnalysis.MetadataImportOptions.All = 2 -> Microsoft.CodeAnalysis.MetadataImportOptions Microsoft.CodeAnalysis.MetadataImportOptions.Internal = 1 -> Microsoft.CodeAnalysis.MetadataImportOptions Microsoft.CodeAnalysis.MetadataImportOptions.Public = 0 -> Microsoft.CodeAnalysis.MetadataImportOptions +Microsoft.CodeAnalysis.Operations.ISymbolInitializerOperation.Locals.get -> System.Collections.Immutable.ImmutableArray Microsoft.CodeAnalysis.Operations.ITupleOperation.NaturalType.get -> Microsoft.CodeAnalysis.ITypeSymbol abstract Microsoft.CodeAnalysis.DataFlowAnalysis.CapturedInside.get -> System.Collections.Immutable.ImmutableArray abstract Microsoft.CodeAnalysis.DataFlowAnalysis.CapturedOutside.get -> System.Collections.Immutable.ImmutableArray diff --git a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb index fd18940202a5f5783d39e944a3d8ef66de8cc64e..41293cff3300224344f70377f1d01c5eef5c4f32 100644 --- a/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb +++ b/src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory.vb @@ -853,7 +853,7 @@ Namespace Microsoft.CodeAnalysis.Operations Dim type As ITypeSymbol = Nothing Dim constantValue As [Optional](Of Object) = New [Optional](Of Object)() Dim isImplicit As Boolean = boundFieldInitializer.WasCompilerGenerated - Return New LazyFieldInitializer(initializedFields, value, kind, _semanticModel, syntax, type, constantValue, isImplicit) + Return New LazyFieldInitializer(ImmutableArray(Of ILocalSymbol).Empty, initializedFields, value, kind, _semanticModel, syntax, type, constantValue, isImplicit) End Function Private Function CreateBoundPropertyInitializerOperation(boundPropertyInitializer As BoundPropertyInitializer) As IPropertyInitializerOperation @@ -864,7 +864,7 @@ Namespace Microsoft.CodeAnalysis.Operations Dim type As ITypeSymbol = Nothing Dim constantValue As [Optional](Of Object) = New [Optional](Of Object)() Dim isImplicit As Boolean = boundPropertyInitializer.WasCompilerGenerated - Return New LazyPropertyInitializer(initializedProperties, value, kind, _semanticModel, syntax, type, constantValue, isImplicit) + Return New LazyPropertyInitializer(ImmutableArray(Of ILocalSymbol).Empty, initializedProperties, value, kind, _semanticModel, syntax, type, constantValue, isImplicit) End Function Private Function CreateBoundParameterEqualsValueOperation(boundParameterEqualsValue As BoundParameterEqualsValue) As IParameterInitializerOperation @@ -875,7 +875,7 @@ Namespace Microsoft.CodeAnalysis.Operations Dim type As ITypeSymbol = Nothing Dim constantValue As [Optional](Of Object) = New [Optional](Of Object)() Dim isImplicit As Boolean = boundParameterEqualsValue.WasCompilerGenerated - Return New LazyParameterInitializer(parameter, value, kind, _semanticModel, syntax, type, constantValue, isImplicit) + Return New LazyParameterInitializer(ImmutableArray(Of ILocalSymbol).Empty, parameter, value, kind, _semanticModel, syntax, type, constantValue, isImplicit) End Function Private Function CreateBoundRValuePlaceholderOperation(boundRValuePlaceholder As BoundRValuePlaceholder) As IOperation diff --git a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs index e450bde8b0646a3c576979420e4750f5d3b9db6e..86c2542ddcabe6a7a91c92e6fb47d86acdf2f39a 100644 --- a/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs +++ b/src/Test/Utilities/Portable/Compilation/OperationTreeVerifier.cs @@ -1198,6 +1198,7 @@ public override void VisitFieldInitializer(IFieldInitializerOperation operation) Unindent(); } + LogLocals(operation.Locals); base.VisitFieldInitializer(operation); } @@ -1205,7 +1206,7 @@ public override void VisitVariableInitializer(IVariableInitializerOperation oper { LogString(nameof(IVariableInitializerOperation)); LogCommonPropertiesAndNewLine(operation); - + Assert.Empty(operation.Locals); base.VisitVariableInitializer(operation); } @@ -1239,7 +1240,8 @@ public override void VisitPropertyInitializer(IPropertyInitializerOperation oper Unindent(); } - + + LogLocals(operation.Locals); base.VisitPropertyInitializer(operation); } @@ -1250,6 +1252,7 @@ public override void VisitParameterInitializer(IParameterInitializerOperation op LogString(")"); LogCommonPropertiesAndNewLine(operation); + LogLocals(operation.Locals); base.VisitParameterInitializer(operation); } diff --git a/src/Test/Utilities/Portable/Compilation/TestOperationVisitor.cs b/src/Test/Utilities/Portable/Compilation/TestOperationVisitor.cs index 831e41218084bf0448498800e129690971c4d60a..360008ea402ce1cd02684f87cc7742c3270fc097 100644 --- a/src/Test/Utilities/Portable/Compilation/TestOperationVisitor.cs +++ b/src/Test/Utilities/Portable/Compilation/TestOperationVisitor.cs @@ -831,6 +831,11 @@ public override void VisitCollectionElementInitializer(ICollectionElementInitial private void VisitSymbolInitializer(ISymbolInitializerOperation operation) { + foreach (var local in operation.Locals) + { + Assert.NotNull(local); + } + Assert.Same(operation.Value, operation.Children.Single()); } @@ -847,6 +852,7 @@ public override void VisitFieldInitializer(IFieldInitializerOperation operation) public override void VisitVariableInitializer(IVariableInitializerOperation operation) { Assert.Equal(OperationKind.VariableInitializer, operation.Kind); + Assert.Empty(operation.Locals); VisitSymbolInitializer(operation); }