未验证 提交 dbf4b235 编写于 作者: A AlekseyTs 提交者: GitHub

IOperation - expose declared locals for field/property/parameter initializers. (#25023)

上级 d946a48a
......@@ -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)
......
......@@ -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;
}
}
}
......@@ -33,12 +33,8 @@
<AbstractNode Name="BoundInitializer" Base="BoundNode"/>
<Node Name="BoundFieldInitializer" Base="BoundInitializer">
<Field Name="Field" Type="FieldSymbol"/>
<Field Name="InitialValue" Type="BoundExpression"/>
</Node>
<AbstractNode Name="BoundEqualsValue" Base="BoundNode">
<AbstractNode Name="BoundEqualsValue" Base="BoundInitializer">
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<!-- Expression representing the value. -->
<Field Name="Value" Type="BoundExpression"/>
</AbstractNode>
......
......@@ -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)
......
......@@ -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))
......
......@@ -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);
......
......@@ -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<LocalSymbol> 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<LocalSymbol> 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<LocalSymbol> 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<LocalSymbol> 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<LocalSymbol> 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<LocalSymbol> 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<LocalSymbol> 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<LocalSymbol> 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<A,R>
{
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) })
}
);
......
......@@ -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<BoundExpression>.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:
......
......@@ -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:
......
......@@ -1254,7 +1254,7 @@ private IFieldInitializerOperation CreateBoundFieldEqualsValueOperation(BoundFie
ITypeSymbol type = null;
Optional<object> constantValue = default(Optional<object>);
bool isImplicit = boundFieldEqualsValue.WasCompilerGenerated;
return new LazyFieldInitializer(initializedFields, value, kind, _semanticModel, syntax, type, constantValue, isImplicit);
return new LazyFieldInitializer(boundFieldEqualsValue.Locals.As<ILocalSymbol>(), 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<object> constantValue = default(Optional<object>);
bool isImplicit = boundPropertyEqualsValue.WasCompilerGenerated;
return new LazyPropertyInitializer(initializedProperties, value, kind, _semanticModel, syntax, type, constantValue, isImplicit);
return new LazyPropertyInitializer(boundPropertyEqualsValue.Locals.As<ILocalSymbol>(), initializedProperties, value, kind, _semanticModel, syntax, type, constantValue, isImplicit);
}
private IParameterInitializerOperation CreateBoundParameterEqualsValueOperation(BoundParameterEqualsValue boundParameterEqualsValue)
......@@ -1278,7 +1278,7 @@ private IParameterInitializerOperation CreateBoundParameterEqualsValueOperation(
ITypeSymbol type = null;
Optional<object> constantValue = default(Optional<object>);
bool isImplicit = boundParameterEqualsValue.WasCompilerGenerated;
return new LazyParameterInitializer(parameter, value, kind, _semanticModel, syntax, type, constantValue, isImplicit);
return new LazyParameterInitializer(boundParameterEqualsValue.Locals.As<ILocalSymbol>(), parameter, value, kind, _semanticModel, syntax, type, constantValue, isImplicit);
}
private IBlockOperation CreateBoundBlockOperation(BoundBlock boundBlock)
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
......
......@@ -267,12 +267,12 @@ private static void CheckBoundInitializers(IEnumerable<ExpectedInitializer> 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;
......
......@@ -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<EqualsValueClauseSyntax>().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<EqualsValueClauseSyntax>().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>(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<EqualsValueClauseSyntax>().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<EqualsValueClauseSyntax>().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]
......@@ -1733,6 +1733,8 @@ public override void Accept(OperationVisitor visitor)
{
return visitor.VisitVariableInitializer(this, argument);
}
ImmutableArray<ILocalSymbol> ISymbolInitializerOperation.Locals => ImmutableArray<ILocalSymbol>.Empty;
}
/// <summary>
......@@ -1768,11 +1770,15 @@ internal sealed partial class LazyVariableInitializer : BaseVariableInitializer,
/// </summary>
internal abstract partial class BaseFieldInitializer : SymbolInitializer, IFieldInitializerOperation
{
public BaseFieldInitializer(ImmutableArray<IFieldSymbol> initializedFields, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
public BaseFieldInitializer(ImmutableArray<ILocalSymbol> locals, ImmutableArray<IFieldSymbol> initializedFields, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(kind, semanticModel, syntax, type, constantValue, isImplicit)
{
Locals = locals;
InitializedFields = initializedFields;
}
public ImmutableArray<ILocalSymbol> Locals { get; }
/// <summary>
/// Initialized fields. There can be multiple fields for Visual Basic fields declared with As New.
/// </summary>
......@@ -1803,8 +1809,8 @@ public override void Accept(OperationVisitor visitor)
/// </summary>
internal sealed partial class FieldInitializer : BaseFieldInitializer, IFieldInitializerOperation
{
public FieldInitializer(ImmutableArray<IFieldSymbol> initializedFields, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(initializedFields, kind, semanticModel, syntax, type, constantValue, isImplicit)
public FieldInitializer(ImmutableArray<ILocalSymbol> locals, ImmutableArray<IFieldSymbol> initializedFields, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> 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<IOperation> _lazyValue;
public LazyFieldInitializer(ImmutableArray<IFieldSymbol> initializedFields, Lazy<IOperation> value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(initializedFields, kind, semanticModel, syntax, type, constantValue, isImplicit)
public LazyFieldInitializer(ImmutableArray<ILocalSymbol> locals, ImmutableArray<IFieldSymbol> initializedFields, Lazy<IOperation> value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> 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)
/// </summary>
internal abstract partial class BaseParameterInitializer : SymbolInitializer, IParameterInitializerOperation
{
public BaseParameterInitializer(IParameterSymbol parameter, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
public BaseParameterInitializer(ImmutableArray<ILocalSymbol> locals, IParameterSymbol parameter, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(kind, semanticModel, syntax, type, constantValue, isImplicit)
{
Locals = locals;
Parameter = parameter;
}
public ImmutableArray<ILocalSymbol> Locals { get; }
/// <summary>
/// Initialized parameter.
/// </summary>
......@@ -3797,8 +3807,8 @@ public override void Accept(OperationVisitor visitor)
/// </summary>
internal sealed partial class ParameterInitializer : BaseParameterInitializer, IParameterInitializerOperation
{
public ParameterInitializer(IParameterSymbol parameter, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(parameter, kind, semanticModel, syntax, type, constantValue, isImplicit)
public ParameterInitializer(ImmutableArray<ILocalSymbol> locals, IParameterSymbol parameter, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> 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<IOperation> _lazyValue;
public LazyParameterInitializer(IParameterSymbol parameter, Lazy<IOperation> value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(parameter, kind, semanticModel, syntax, type, constantValue, isImplicit)
public LazyParameterInitializer(ImmutableArray<ILocalSymbol> locals, IParameterSymbol parameter, Lazy<IOperation> value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> 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<IOperation> pointer, Seman
/// </summary>
internal abstract partial class BasePropertyInitializer : SymbolInitializer, IPropertyInitializerOperation
{
public BasePropertyInitializer(ImmutableArray<IPropertySymbol> initializedProperties, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
public BasePropertyInitializer(ImmutableArray<ILocalSymbol> locals, ImmutableArray<IPropertySymbol> initializedProperties, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(kind, semanticModel, syntax, type, constantValue, isImplicit)
{
Locals = locals;
InitializedProperties = initializedProperties;
}
public ImmutableArray<ILocalSymbol> Locals { get; }
/// <summary>
/// Initialized properties. There can be multiple properties for Visual Basic 'WithEvents' declaration with AsNew clause.
/// </summary>
......@@ -4050,8 +4064,8 @@ public override void Accept(OperationVisitor visitor)
/// </summary>
internal sealed partial class PropertyInitializer : BasePropertyInitializer, IPropertyInitializerOperation
{
public PropertyInitializer(ImmutableArray<IPropertySymbol> initializedProperties, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(initializedProperties, kind, semanticModel, syntax, type, constantValue, isImplicit)
public PropertyInitializer(ImmutableArray<ILocalSymbol> locals, ImmutableArray<IPropertySymbol> initializedProperties, IOperation value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> 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<IOperation> _lazyValue;
public LazyPropertyInitializer(ImmutableArray<IPropertySymbol> initializedProperties, Lazy<IOperation> value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(initializedProperties, kind, semanticModel, syntax, type, constantValue, isImplicit)
public LazyPropertyInitializer(ImmutableArray<ILocalSymbol> locals, ImmutableArray<IPropertySymbol> initializedProperties, Lazy<IOperation> value, OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> 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<IOperation> value, Lazy<ImmutableArray<ISwitchCa
/// <summary>
/// Represents an initializer for a field, property, or parameter.
/// </summary>
internal abstract partial class SymbolInitializer : Operation, ISymbolInitializerOperation
internal abstract partial class SymbolInitializer : Operation
{
protected SymbolInitializer(OperationKind kind, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(kind, semanticModel, syntax, type, constantValue, isImplicit)
......
// 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
{
/// <summary>
......@@ -16,6 +18,11 @@ namespace Microsoft.CodeAnalysis.Operations
/// </remarks>
public interface ISymbolInitializerOperation : IOperation
{
/// <summary>
/// Local declared in and scoped to the <see cref="Value"/>.
/// </summary>
ImmutableArray<ILocalSymbol> Locals { get; }
/// <summary>
/// Underlying initializer value.
/// </summary>
......
......@@ -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)
......
......@@ -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.ILocalSymbol>
Microsoft.CodeAnalysis.Operations.ITupleOperation.NaturalType.get -> Microsoft.CodeAnalysis.ITypeSymbol
abstract Microsoft.CodeAnalysis.DataFlowAnalysis.CapturedInside.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.ISymbol>
abstract Microsoft.CodeAnalysis.DataFlowAnalysis.CapturedOutside.get -> System.Collections.Immutable.ImmutableArray<Microsoft.CodeAnalysis.ISymbol>
......
......@@ -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
......
......@@ -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);
}
......
......@@ -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);
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册