未验证 提交 bb0207f6 编写于 作者: A Andy Gocke 提交者: GitHub

Change AssignmentOperator to use IsRef instead of RefKind (#23415)

Assignments can be ref or regular, but there's no such thing as a
"ref-readonly" assignment or "out" assignment, only left-hand sides that
can be ref-kind. Changing to IsRef prevents bugs around looking for the
RefKind of the assignment instead of looking for the RefKind of the LHS.
上级 647e5814
......@@ -405,7 +405,7 @@ internal bool CheckValueKind(SyntaxNode node, BoundExpression expr, BindValueKin
var conditional = (BoundConditionalOperator)expr;
// byref conditional defers to its operands
if (conditional.IsByRef &&
if (conditional.IsRef &&
(CheckValueKind(conditional.Consequence.Syntax, conditional.Consequence, valueKind, checkingReceiver: false, diagnostics: diagnostics) &
CheckValueKind(conditional.Alternative.Syntax, conditional.Alternative, valueKind, checkingReceiver: false, diagnostics: diagnostics)))
{
......@@ -1659,7 +1659,7 @@ internal static uint GetRefEscape(BoundExpression expr, uint scopeOfTheContainin
case BoundKind.ConditionalOperator:
var conditional = (BoundConditionalOperator)expr;
if (conditional.IsByRef)
if (conditional.IsRef)
{
// ref conditional defers to its operands
return Math.Max(GetRefEscape(conditional.Consequence, scopeOfTheContainingExpression),
......@@ -1847,7 +1847,7 @@ internal static bool CheckRefEscape(SyntaxNode node, BoundExpression expr, uint
case BoundKind.ConditionalOperator:
var conditional = (BoundConditionalOperator)expr;
if (conditional.IsByRef)
if (conditional.IsRef)
{
return CheckRefEscape(conditional.Consequence.Syntax, conditional.Consequence, escapeFrom, escapeTo, checkingReceiver: false, diagnostics: diagnostics) &&
CheckRefEscape(conditional.Alternative.Syntax, conditional.Alternative, escapeFrom, escapeTo, checkingReceiver: false, diagnostics: diagnostics);
......@@ -2036,7 +2036,7 @@ internal static uint GetValEscape(BoundExpression expr, uint scopeOfTheContainin
var consEscape = GetValEscape(conditional.Consequence, scopeOfTheContainingExpression);
if (conditional.IsByRef)
if (conditional.IsRef)
{
// ref conditional defers to one operand.
// the other one is the same or we will be reporting errors anyways.
......@@ -2320,7 +2320,7 @@ internal static bool CheckValEscape(SyntaxNode node, BoundExpression expr, uint
var consValid = CheckValEscape(conditional.Consequence.Syntax, conditional.Consequence, escapeFrom, escapeTo, checkingReceiver: false, diagnostics: diagnostics);
if (!consValid || conditional.IsByRef)
if (!consValid || conditional.IsRef)
{
// ref conditional defers to one operand.
// the other one is the same or we will be reporting errors anyways.
......
......@@ -5,11 +5,38 @@
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
internal static partial class BoundExpressionExtensions
{
/// <summary>
/// Returns the RefKind if the expression represents a symbol
/// that has a RefKind. This method is ILLEGAL to call for
/// other expressions.
/// </summary>
public static RefKind GetRefKind(this BoundExpression node)
{
switch (node.Kind)
{
case BoundKind.Local:
return ((BoundLocal)node).LocalSymbol.RefKind;
case BoundKind.Parameter:
return ((BoundParameter)node).ParameterSymbol.RefKind;
case BoundKind.Call:
return ((BoundCall)node).Method.RefKind;
case BoundKind.PropertyAccess:
return ((BoundPropertyAccess)node).PropertySymbol.RefKind;
default:
throw ExceptionUtilities.UnexpectedValue(node.Kind);
}
}
public static bool IsLiteralNull(this BoundExpression node)
{
return node.Kind == BoundKind.Literal && node.ConstantValue.Discriminator == ConstantValueTypeDiscriminator.Null;
......
......@@ -356,7 +356,7 @@
<Node Name="BoundAssignmentOperator" Base="BoundExpression">
<Field Name="Left" Type="BoundExpression"/>
<Field Name="Right" Type="BoundExpression" Null="NotApplicable"/>
<!-- This is almost always RefKind.None.
<!-- This is almost always false.
In C# most assignments to a variable are simply writes to the
logical variable. For example, when you say
......@@ -379,7 +379,7 @@
through addr. We therefore need to disambiguate what kind of assignment
we are doing based on something other than the refness of the left hand side.
-->
<Field Name="RefKind" Type="RefKind" Null="NotApplicable"/>
<Field Name="IsRef" Type="bool" Null="NotApplicable"/>
</Node>
<Node Name="BoundDeconstructionAssignmentOperator" Base="BoundExpression">
......@@ -400,7 +400,7 @@
<Node Name="BoundConditionalOperator" Base="BoundExpression">
<!-- Non-null type is required for this node kind -->
<Field Name="Type" Type="TypeSymbol" Override="true" Null="disallow"/>
<Field Name="IsByRef" Type="bool"/>
<Field Name="IsRef" Type="bool"/>
<Field Name="Condition" Type="BoundExpression"/>
<Field Name="Consequence" Type="BoundExpression"/>
<Field Name="Alternative" Type="BoundExpression"/>
......
......@@ -455,8 +455,8 @@ public BoundNamespaceExpression Update(NamespaceSymbol namespaceSymbol)
internal sealed partial class BoundAssignmentOperator
{
public BoundAssignmentOperator(SyntaxNode syntax, BoundExpression left, BoundExpression right,
TypeSymbol type, RefKind refKind = RefKind.None, bool hasErrors = false)
: this(syntax, left, right, refKind, type, hasErrors)
TypeSymbol type, bool isRef = false, bool hasErrors = false)
: this(syntax, left, right, isRef, type, hasErrors)
{
}
}
......
......@@ -139,12 +139,12 @@ private LocalDefinition EmitAddress(BoundExpression expression, AddressKind addr
case BoundKind.AssignmentOperator:
var assignment = (BoundAssignmentOperator)expression;
if (assignment.RefKind == RefKind.None)
if (!assignment.IsRef)
{
goto default;
}
throw ExceptionUtilities.UnexpectedValue(assignment.RefKind);
throw ExceptionUtilities.UnexpectedValue(assignment.IsRef);
case BoundKind.ThrowExpression:
// emit value or address is the same here.
......@@ -411,7 +411,7 @@ private bool HasHome(BoundExpression expression, AddressKind addressKind)
return HasHome(((BoundSequence)expression).Value, addressKind);
case BoundKind.AssignmentOperator:
return ((BoundAssignmentOperator)expression).RefKind != RefKind.None;
return ((BoundAssignmentOperator)expression).IsRef;
case BoundKind.ComplexConditionalReceiver:
Debug.Assert(HasHome(((BoundComplexConditionalReceiver)expression).ValueTypeReceiver, addressKind));
......@@ -427,7 +427,7 @@ private bool HasHome(BoundExpression expression, AddressKind addressKind)
var ternary = (BoundConditionalOperator)expression;
// only ref ternary may be referenced as a variable
if (!ternary.IsByRef)
if (!ternary.IsRef)
{
return false;
}
......
......@@ -1922,7 +1922,7 @@ private void EmitAssignmentExpression(BoundAssignmentOperator assignmentOperator
{
if (TryEmitAssignmentInPlace(assignmentOperator, useKind != UseKind.Unused))
{
Debug.Assert(assignmentOperator.RefKind == RefKind.None);
Debug.Assert(!assignmentOperator.IsRef);
return;
}
......@@ -2211,7 +2211,7 @@ private bool EmitAssignmentPreamble(BoundAssignmentOperator assignmentOperator)
// and then do an indirect store. In that case we need to have the
// contents of addr on the stack.
if (left.LocalSymbol.RefKind != RefKind.None && assignmentOperator.RefKind == RefKind.None)
if (left.LocalSymbol.RefKind != RefKind.None && !assignmentOperator.IsRef)
{
if (!IsStackLocal(left.LocalSymbol))
{
......@@ -2274,7 +2274,7 @@ private bool EmitAssignmentPreamble(BoundAssignmentOperator assignmentOperator)
case BoundKind.ConditionalOperator:
{
var left = (BoundConditionalOperator)assignmentTarget;
Debug.Assert(left.IsByRef);
Debug.Assert(left.IsRef);
var temp = EmitAddress(left, AddressKind.Writeable);
Debug.Assert(temp == null, "taking ref of this should not create a temp");
......@@ -2301,7 +2301,7 @@ private bool EmitAssignmentPreamble(BoundAssignmentOperator assignmentOperator)
// Since sequence is used as a variable, we will keep the locals for the extent of the containing expression
DefineAndRecordLocals(sequence);
EmitSideEffects(sequence);
lhsUsesStack = EmitAssignmentPreamble(assignmentOperator.Update(sequence.Value, assignmentOperator.Right, assignmentOperator.RefKind, assignmentOperator.Type));
lhsUsesStack = EmitAssignmentPreamble(assignmentOperator.Update(sequence.Value, assignmentOperator.Right, assignmentOperator.IsRef, assignmentOperator.Type));
CloseScopeAndKeepLocals(sequence);
}
break;
......@@ -2342,7 +2342,7 @@ private bool EmitAssignmentPreamble(BoundAssignmentOperator assignmentOperator)
private void EmitAssignmentValue(BoundAssignmentOperator assignmentOperator)
{
if (assignmentOperator.RefKind == RefKind.None)
if (!assignmentOperator.IsRef)
{
EmitExpression(assignmentOperator.Right, used: true);
}
......@@ -2412,7 +2412,7 @@ private LocalDefinition EmitAssignmentDuplication(BoundAssignmentOperator assign
// is created here. And also that either its value or its indirected value is read out
// after the store, in EmitAssignmentPostfix, below.
Debug.Assert(assignmentOperator.RefKind == RefKind.None);
Debug.Assert(!assignmentOperator.IsRef);
temp = AllocateTemp(assignmentOperator.Left.Type, assignmentOperator.Left.Syntax);
_builder.EmitLocalStore(temp);
......@@ -2439,7 +2439,7 @@ private void EmitStore(BoundAssignmentOperator assignment)
// See the comments in EmitAssignmentExpression above for details.
BoundLocal local = (BoundLocal)expression;
if (local.LocalSymbol.RefKind != RefKind.None && assignment.RefKind == RefKind.None)
if (local.LocalSymbol.RefKind != RefKind.None && !assignment.IsRef)
{
EmitIndirectStore(local.LocalSymbol.Type, local.Syntax);
}
......@@ -2477,7 +2477,7 @@ private void EmitStore(BoundAssignmentOperator assignment)
break;
case BoundKind.ConditionalOperator:
Debug.Assert(((BoundConditionalOperator)expression).IsByRef);
Debug.Assert(((BoundConditionalOperator)expression).IsRef);
EmitIndirectStore(expression.Type, expression.Syntax);
break;
......@@ -2490,7 +2490,7 @@ private void EmitStore(BoundAssignmentOperator assignment)
case BoundKind.Sequence:
{
var sequence = (BoundSequence)expression;
EmitStore(assignment.Update(sequence.Value, assignment.Right, assignment.RefKind, assignment.Type));
EmitStore(assignment.Update(sequence.Value, assignment.Right, assignment.IsRef, assignment.Type));
}
break;
......@@ -2522,7 +2522,7 @@ private void EmitAssignmentPostfix(BoundAssignmentOperator assignment, LocalDefi
FreeTemp(temp);
}
if (useKind == UseKind.UsedAsValue && assignment.RefKind != RefKind.None)
if (useKind == UseKind.UsedAsValue && assignment.IsRef)
{
EmitLoadIndirect(assignment.Type, assignment.Syntax);
}
......
......@@ -870,7 +870,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
// into ==> {se1, se2, se3, val = something}
BoundExpression rewritten = sequence.Update(sequence.Locals,
sequence.SideEffects,
node.Update(sequence.Value, node.Right, node.RefKind, node.Type),
node.Update(sequence.Value, node.Right, node.IsRef, node.Type),
sequence.Type);
rewritten = (BoundExpression)Visit(rewritten);
......@@ -895,8 +895,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
Debug.Assert(_context != ExprContext.AssignmentTarget, "assignment expression cannot be a target of another assignment");
ExprContext rhsContext;
if (node.RefKind != RefKind.None ||
_context == ExprContext.Address)
if (node.IsRef || _context == ExprContext.Address)
{
// we need the address of rhs one way or another so we cannot have it on the stack.
rhsContext = ExprContext.Address;
......@@ -960,7 +959,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
assignmentLocal = null;
}
return node.Update(left, right, node.RefKind, node.Type);
return node.Update(left, right, node.IsRef, node.Type);
}
// indirect assignment is assignment to a value referenced indirectly
......@@ -971,9 +970,8 @@ private static bool IsIndirectAssignment(BoundAssignmentOperator node)
{
var lhs = node.Left;
Debug.Assert(node.RefKind == RefKind.None || lhs is BoundLocal local &&
(local.LocalSymbol.RefKind == node.RefKind ||
local.LocalSymbol.RefKind == RefKind.RefReadOnly),
Debug.Assert(!node.IsRef || lhs is BoundLocal local &&
local.LocalSymbol.RefKind != RefKind.None,
"only ref locals can be a target of a ref assignment");
switch (lhs.Kind)
......@@ -985,8 +983,7 @@ private static bool IsIndirectAssignment(BoundAssignmentOperator node)
case BoundKind.Parameter:
if (((BoundParameter)lhs).ParameterSymbol.RefKind != RefKind.None)
{
bool isIndirect = node.RefKind == RefKind.None;
return isIndirect;
return !node.IsRef;
}
return false;
......@@ -994,8 +991,7 @@ private static bool IsIndirectAssignment(BoundAssignmentOperator node)
case BoundKind.Local:
if (((BoundLocal)lhs).LocalSymbol.RefKind != RefKind.None)
{
bool isIndirect = node.RefKind == RefKind.None;
return isIndirect;
return !node.IsRef;
}
return false;
......@@ -1005,15 +1001,15 @@ private static bool IsIndirectAssignment(BoundAssignmentOperator node)
return true;
case BoundKind.ConditionalOperator:
Debug.Assert(((BoundConditionalOperator)lhs).IsByRef, "only ref ternaries are assignable");
Debug.Assert(((BoundConditionalOperator)lhs).IsRef, "only ref ternaries are assignable");
return true;
case BoundKind.AssignmentOperator:
Debug.Assert(((BoundAssignmentOperator)lhs).RefKind == RefKind.Ref, "only ref assignments are assignable");
Debug.Assert(((BoundAssignmentOperator)lhs).IsRef, "only ref assignments are assignable");
return true;
case BoundKind.Sequence:
Debug.Assert(!IsIndirectAssignment(node.Update(((BoundSequence)node.Left).Value, node.Right, node.RefKind, node.Type)),
Debug.Assert(!IsIndirectAssignment(node.Update(((BoundSequence)node.Left).Value, node.Right, node.IsRef, node.Type)),
"indirect assignment to a sequence is unexpected");
return false;
......@@ -1251,7 +1247,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
var cookie = GetStackStateCookie(); // implicit goto here
var context = node.IsByRef ? ExprContext.Address : ExprContext.Value;
var context = node.IsRef ? ExprContext.Address : ExprContext.Value;
SetStackDepth(origStack); // consequence is evaluated with original stack
BoundExpression consequence = this.VisitExpression(node.Consequence, context);
......@@ -1263,7 +1259,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
EnsureStackState(cookie); // implicit label here
return node.Update(node.IsByRef, condition, consequence, alternative, node.ConstantValueOpt, node.Type);
return node.Update(node.IsRef, condition, consequence, alternative, node.ConstantValueOpt, node.Type);
}
public override BoundNode VisitBinaryOperator(BoundBinaryOperator node)
......@@ -1989,7 +1985,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
// indirect local store is not special. (operands still could be rewritten)
// NOTE: if Lhs is a stack local, it will be handled as a read and possibly duped.
var isIndirectLocalStore = left.LocalSymbol.RefKind != RefKind.None && node.RefKind == RefKind.None;
var isIndirectLocalStore = left.LocalSymbol.RefKind != RefKind.None && !node.IsRef;
if (isIndirectLocalStore)
{
return base.VisitAssignmentOperator(node);
......@@ -2023,7 +2019,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
{
// assigned local used later - keep assignment.
// codegen will keep value on stack when sees assignment "stackLocal = expr"
return node.Update(left, right, node.RefKind, node.Type);
return node.Update(left, right, node.IsRef, node.Type);
}
}
......
......@@ -102,7 +102,7 @@ internal static class MethodBodySynthesizer
objectType)
{ WasCompilerGenerated = true },
thisReference,
RefKind.None,
false,
thisReference.Type)
{ WasCompilerGenerated = true })
{ WasCompilerGenerated = true });
......
......@@ -1156,9 +1156,9 @@ private Symbol UseNonFieldSymbolUnsafely(BoundExpression expression)
return null;
}
protected void Assign(BoundNode node, BoundExpression value, RefKind refKind = RefKind.None, bool read = true)
protected void Assign(BoundNode node, BoundExpression value, bool isRef = false, bool read = true)
{
AssignImpl(node, value, written: true, refKind: refKind, read: read);
AssignImpl(node, value, written: true, isRef: isRef, read: read);
}
/// <summary>
......@@ -1167,9 +1167,9 @@ protected void Assign(BoundNode node, BoundExpression value, RefKind refKind = R
/// <param name="node">Node being assigned to.</param>
/// <param name="value">The value being assigned.</param>
/// <param name="written">True if target location is considered written to.</param>
/// <param name="refKind">Target kind (by-ref or not).</param>
/// <param name="isRef">Ref assignment or value assignment.</param>
/// <param name="read">True if target location is considered read from.</param>
protected virtual void AssignImpl(BoundNode node, BoundExpression value, RefKind refKind, bool written, bool read)
protected virtual void AssignImpl(BoundNode node, BoundExpression value, bool isRef, bool written, bool read)
{
switch (node.Kind)
{
......@@ -1203,7 +1203,7 @@ protected virtual void AssignImpl(BoundNode node, BoundExpression value, RefKind
case BoundKind.Local:
{
var local = (BoundLocal)node;
if (local.LocalSymbol.RefKind != refKind)
if (local.LocalSymbol.RefKind != RefKind.None && !isRef)
{
// Writing through the (reference) value of a reference local
// requires us to read the reference itself.
......@@ -1232,7 +1232,7 @@ protected virtual void AssignImpl(BoundNode node, BoundExpression value, RefKind
}
case BoundKind.RangeVariable:
AssignImpl(((BoundRangeVariable)node).Value, value, refKind, written, read);
AssignImpl(((BoundRangeVariable)node).Value, value, isRef, written, read);
break;
case BoundKind.BadExpression:
......@@ -1241,13 +1241,13 @@ protected virtual void AssignImpl(BoundNode node, BoundExpression value, RefKind
var bad = (BoundBadExpression)node;
if (!bad.ChildBoundNodes.IsDefault && bad.ChildBoundNodes.Length == 1)
{
AssignImpl(bad.ChildBoundNodes[0], value, refKind, written, read);
AssignImpl(bad.ChildBoundNodes[0], value, isRef, written, read);
}
break;
}
case BoundKind.TupleLiteral:
((BoundTupleExpression)node).VisitAllElements((x, self) => self.Assign(x, value: null, refKind: refKind), this);
((BoundTupleExpression)node).VisitAllElements((x, self) => self.Assign(x, value: null, isRef: isRef), this);
break;
default:
......@@ -1476,7 +1476,7 @@ private void AssignPatternVariables(BoundPattern pattern)
case BoundKind.DeclarationPattern:
{
var pat = (BoundDeclarationPattern)pattern;
Assign(pat, null, RefKind.None, false);
Assign(pat, value: null, isRef: false, read: false);
break;
}
case BoundKind.WildcardPattern:
......@@ -1854,7 +1854,7 @@ public override BoundNode VisitParameter(BoundParameter node)
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
{
base.VisitAssignmentOperator(node);
Assign(node.Left, node.Right, refKind: node.RefKind);
Assign(node.Left, node.Right, isRef: node.IsRef);
return null;
}
......
......@@ -183,7 +183,7 @@ private Symbol GetNodeSymbol(BoundNode node)
}
#endif
protected override void AssignImpl(BoundNode node, BoundExpression value, RefKind refKind, bool written, bool read)
protected override void AssignImpl(BoundNode node, BoundExpression value, bool isRef, bool written, bool read)
{
if (IsInside)
{
......@@ -209,7 +209,7 @@ protected override void AssignImpl(BoundNode node, BoundExpression value, RefKin
}
}
base.AssignImpl(node, value, refKind, written, read);
base.AssignImpl(node, value, isRef, written, read);
}
private bool FlowsOut(ParameterSymbol param)
......
......@@ -1672,9 +1672,9 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
VisitRvalue(node.Right);
// byref assignment is also a potential write
if (node.RefKind != RefKind.None)
if (node.IsRef)
{
WriteArgument(node.Right, node.RefKind, method: null);
WriteArgument(node.Right, node.Left.GetRefKind(), method: null);
}
return null;
......@@ -2337,7 +2337,7 @@ public override BoundNode VisitContinueStatement(BoundContinueStatement node)
public sealed override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
{
var isByRef = node.IsByRef;
var isByRef = node.IsRef;
VisitCondition(node.Condition);
var consequenceState = this.StateWhenTrue;
......
......@@ -172,7 +172,7 @@ private void NoteReceiverReadOrWritten(BoundFieldAccess expr, HashSet<Symbol> re
}
}
protected override void AssignImpl(BoundNode node, BoundExpression value, RefKind refKind, bool written, bool read)
protected override void AssignImpl(BoundNode node, BoundExpression value, bool isRef, bool written, bool read)
{
switch (node.Kind)
{
......@@ -182,7 +182,7 @@ protected override void AssignImpl(BoundNode node, BoundExpression value, RefKin
case BoundKind.QueryClause:
{
base.AssignImpl(node, value, refKind, written, read);
base.AssignImpl(node, value, isRef, written, read);
var symbol = ((BoundQueryClause)node).DefinedSymbol;
if ((object)symbol != null)
{
......@@ -193,7 +193,7 @@ protected override void AssignImpl(BoundNode node, BoundExpression value, RefKin
case BoundKind.FieldAccess:
{
base.AssignImpl(node, value, refKind, written, read);
base.AssignImpl(node, value, isRef, written, read);
var fieldAccess = node as BoundFieldAccess;
if (!IsInside && node.Syntax != null && node.Syntax.Span.Contains(RegionSpan))
{
......@@ -203,7 +203,7 @@ protected override void AssignImpl(BoundNode node, BoundExpression value, RefKin
break;
default:
base.AssignImpl(node, value, refKind, written, read);
base.AssignImpl(node, value, isRef, written, read);
break;
}
}
......
......@@ -1125,7 +1125,7 @@ public BoundCompoundAssignmentOperator Update(BinaryOperatorSignature @operator,
internal sealed partial class BoundAssignmentOperator : BoundExpression
{
public BoundAssignmentOperator(SyntaxNode syntax, BoundExpression left, BoundExpression right, RefKind refKind, TypeSymbol type, bool hasErrors = false)
public BoundAssignmentOperator(SyntaxNode syntax, BoundExpression left, BoundExpression right, bool isRef, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.AssignmentOperator, syntax, type, hasErrors || left.HasErrors() || right.HasErrors())
{
......@@ -1133,7 +1133,7 @@ public BoundAssignmentOperator(SyntaxNode syntax, BoundExpression left, BoundExp
this.Left = left;
this.Right = right;
this.RefKind = refKind;
this.IsRef = isRef;
}
......@@ -1141,18 +1141,18 @@ public BoundAssignmentOperator(SyntaxNode syntax, BoundExpression left, BoundExp
public BoundExpression Right { get; }
public RefKind RefKind { get; }
public bool IsRef { get; }
public override BoundNode Accept(BoundTreeVisitor visitor)
{
return visitor.VisitAssignmentOperator(this);
}
public BoundAssignmentOperator Update(BoundExpression left, BoundExpression right, RefKind refKind, TypeSymbol type)
public BoundAssignmentOperator Update(BoundExpression left, BoundExpression right, bool isRef, TypeSymbol type)
{
if (left != this.Left || right != this.Right || refKind != this.RefKind || type != this.Type)
if (left != this.Left || right != this.Right || isRef != this.IsRef || type != this.Type)
{
var result = new BoundAssignmentOperator(this.Syntax, left, right, refKind, type, this.HasErrors);
var result = new BoundAssignmentOperator(this.Syntax, left, right, isRef, type, this.HasErrors);
result.WasCompilerGenerated = this.WasCompilerGenerated;
return result;
}
......@@ -1239,7 +1239,7 @@ public BoundNullCoalescingOperator Update(BoundExpression leftOperand, BoundExpr
internal sealed partial class BoundConditionalOperator : BoundExpression
{
public BoundConditionalOperator(SyntaxNode syntax, bool isByRef, BoundExpression condition, BoundExpression consequence, BoundExpression alternative, ConstantValue constantValueOpt, TypeSymbol type, bool hasErrors = false)
public BoundConditionalOperator(SyntaxNode syntax, bool isRef, BoundExpression condition, BoundExpression consequence, BoundExpression alternative, ConstantValue constantValueOpt, TypeSymbol type, bool hasErrors = false)
: base(BoundKind.ConditionalOperator, syntax, type, hasErrors || condition.HasErrors() || consequence.HasErrors() || alternative.HasErrors())
{
......@@ -1248,7 +1248,7 @@ public BoundConditionalOperator(SyntaxNode syntax, bool isByRef, BoundExpression
Debug.Assert(alternative != null, "Field 'alternative' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
Debug.Assert(type != null, "Field 'type' cannot be null (use Null=\"allow\" in BoundNodes.xml to remove this check)");
this.IsByRef = isByRef;
this.IsRef = isRef;
this.Condition = condition;
this.Consequence = consequence;
this.Alternative = alternative;
......@@ -1256,7 +1256,7 @@ public BoundConditionalOperator(SyntaxNode syntax, bool isByRef, BoundExpression
}
public bool IsByRef { get; }
public bool IsRef { get; }
public BoundExpression Condition { get; }
......@@ -1271,11 +1271,11 @@ public override BoundNode Accept(BoundTreeVisitor visitor)
return visitor.VisitConditionalOperator(this);
}
public BoundConditionalOperator Update(bool isByRef, BoundExpression condition, BoundExpression consequence, BoundExpression alternative, ConstantValue constantValueOpt, TypeSymbol type)
public BoundConditionalOperator Update(bool isRef, BoundExpression condition, BoundExpression consequence, BoundExpression alternative, ConstantValue constantValueOpt, TypeSymbol type)
{
if (isByRef != this.IsByRef || condition != this.Condition || consequence != this.Consequence || alternative != this.Alternative || constantValueOpt != this.ConstantValueOpt || type != this.Type)
if (isRef != this.IsRef || condition != this.Condition || consequence != this.Consequence || alternative != this.Alternative || constantValueOpt != this.ConstantValueOpt || type != this.Type)
{
var result = new BoundConditionalOperator(this.Syntax, isByRef, condition, consequence, alternative, constantValueOpt, type, this.HasErrors);
var result = new BoundConditionalOperator(this.Syntax, isRef, condition, consequence, alternative, constantValueOpt, type, this.HasErrors);
result.WasCompilerGenerated = this.WasCompilerGenerated;
return result;
}
......@@ -8586,7 +8586,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
BoundExpression left = (BoundExpression)this.Visit(node.Left);
BoundExpression right = (BoundExpression)this.Visit(node.Right);
TypeSymbol type = this.VisitType(node.Type);
return node.Update(left, right, node.RefKind, type);
return node.Update(left, right, node.IsRef, type);
}
public override BoundNode VisitDeconstructionAssignmentOperator(BoundDeconstructionAssignmentOperator node)
{
......@@ -8608,7 +8608,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
BoundExpression consequence = (BoundExpression)this.Visit(node.Consequence);
BoundExpression alternative = (BoundExpression)this.Visit(node.Alternative);
TypeSymbol type = this.VisitType(node.Type);
return node.Update(node.IsByRef, condition, consequence, alternative, node.ConstantValueOpt, type);
return node.Update(node.IsRef, condition, consequence, alternative, node.ConstantValueOpt, type);
}
public override BoundNode VisitArrayAccess(BoundArrayAccess node)
{
......@@ -9585,7 +9585,7 @@ public override TreeDumperNode VisitAssignmentOperator(BoundAssignmentOperator n
{
new TreeDumperNode("left", null, new TreeDumperNode[] { Visit(node.Left, null) }),
new TreeDumperNode("right", null, new TreeDumperNode[] { Visit(node.Right, null) }),
new TreeDumperNode("refKind", node.RefKind, null),
new TreeDumperNode("isRef", node.IsRef, null),
new TreeDumperNode("type", node.Type, null)
}
);
......@@ -9616,7 +9616,7 @@ public override TreeDumperNode VisitConditionalOperator(BoundConditionalOperator
{
return new TreeDumperNode("conditionalOperator", null, new TreeDumperNode[]
{
new TreeDumperNode("isByRef", node.IsByRef, null),
new TreeDumperNode("isRef", node.IsRef, null),
new TreeDumperNode("condition", null, new TreeDumperNode[] { Visit(node.Condition, null) }),
new TreeDumperNode("consequence", null, new TreeDumperNode[] { Visit(node.Consequence, null) }),
new TreeDumperNode("alternative", null, new TreeDumperNode[] { Visit(node.Alternative, null) }),
......
......@@ -404,7 +404,7 @@ private BoundStatement UpdateStatement(BoundSpillSequenceBuilder builder, BoundS
// The "strict" ones do not permit implicit copying, so the same situation should result in an error.
if (refKind != RefKind.None && refKind != RefKind.RefReadOnly)
{
Debug.Assert(conditional.IsByRef);
Debug.Assert(conditional.IsRef);
_F.Diagnostics.Add(ErrorCode.ERR_RefConditionalAndAwait, _F.Syntax.Location);
}
refKind = RefKind.None;
......@@ -740,7 +740,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
builder = leftBuilder;
}
return UpdateExpression(builder, node.Update(left, right, node.RefKind, node.Type));
return UpdateExpression(builder, node.Update(left, right, node.IsRef, node.Type));
}
public override BoundNode VisitBadExpression(BoundBadExpression node)
......@@ -838,7 +838,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
if (consequenceBuilder == null && alternativeBuilder == null)
{
return UpdateExpression(conditionBuilder, node.Update(node.IsByRef, condition, consequence, alternative, node.ConstantValueOpt, node.Type));
return UpdateExpression(conditionBuilder, node.Update(node.IsRef, condition, consequence, alternative, node.ConstantValueOpt, node.Type));
}
if (conditionBuilder == null) conditionBuilder = new BoundSpillSequenceBuilder();
......
......@@ -577,7 +577,7 @@ internal static bool WouldBeAssignableIfUsedAsMethodReceiver(BoundExpression rec
return true;
case BoundKind.ConditionalOperator:
return ((BoundConditionalOperator)receiver).IsByRef;
return ((BoundConditionalOperator)receiver).IsRef;
case BoundKind.Call:
return ((BoundCall)receiver).Method.RefKind == RefKind.Ref;
......
......@@ -37,7 +37,7 @@ private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bo
BoundEventAccess eventAccess = (BoundEventAccess)left;
if (eventAccess.EventSymbol.IsWindowsRuntimeEvent)
{
Debug.Assert(node.RefKind == RefKind.None);
Debug.Assert(!node.IsRef);
return VisitWindowsRuntimeEventFieldAssignmentOperator(node.Syntax, eventAccess, loweredRight);
}
goto default;
......@@ -72,7 +72,7 @@ private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bo
break;
}
return MakeStaticAssignmentOperator(node.Syntax, loweredLeft, loweredRight, node.RefKind, node.Type, used);
return MakeStaticAssignmentOperator(node.Syntax, loweredLeft, loweredRight, node.IsRef, node.Type, used);
}
/// <summary>
......@@ -125,7 +125,7 @@ private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bo
throw ExceptionUtilities.Unreachable;
default:
return MakeStaticAssignmentOperator(syntax, rewrittenLeft, rewrittenRight, RefKind.None, type, used);
return MakeStaticAssignmentOperator(syntax, rewrittenLeft, rewrittenRight, isRef: false, type: type, used: used);
}
}
......@@ -156,7 +156,13 @@ private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bo
/// Generates a lowered form of the assignment operator for the given left and right sub-expressions.
/// Left and right sub-expressions must be in lowered form.
/// </summary>
private BoundExpression MakeStaticAssignmentOperator(SyntaxNode syntax, BoundExpression rewrittenLeft, BoundExpression rewrittenRight, RefKind refKind, TypeSymbol type, bool used)
private BoundExpression MakeStaticAssignmentOperator(
SyntaxNode syntax,
BoundExpression rewrittenLeft,
BoundExpression rewrittenRight,
bool isRef,
TypeSymbol type,
bool used)
{
switch (rewrittenLeft.Kind)
{
......@@ -166,7 +172,7 @@ private BoundExpression MakeStaticAssignmentOperator(SyntaxNode syntax, BoundExp
case BoundKind.PropertyAccess:
{
Debug.Assert(refKind == RefKind.None);
Debug.Assert(!isRef);
BoundPropertyAccess propertyAccess = (BoundPropertyAccess)rewrittenLeft;
BoundExpression rewrittenReceiver = propertyAccess.ReceiverOpt;
PropertySymbol property = propertyAccess.PropertySymbol;
......@@ -186,7 +192,7 @@ private BoundExpression MakeStaticAssignmentOperator(SyntaxNode syntax, BoundExp
case BoundKind.IndexerAccess:
{
Debug.Assert(refKind == RefKind.None);
Debug.Assert(!isRef);
BoundIndexerAccess indexerAccess = (BoundIndexerAccess)rewrittenLeft;
BoundExpression rewrittenReceiver = indexerAccess.ReceiverOpt;
ImmutableArray<BoundExpression> rewrittenArguments = indexerAccess.Arguments;
......@@ -207,13 +213,13 @@ private BoundExpression MakeStaticAssignmentOperator(SyntaxNode syntax, BoundExp
case BoundKind.Local:
{
Debug.Assert(refKind == RefKind.None || ((BoundLocal)rewrittenLeft).LocalSymbol.RefKind != RefKind.None);
Debug.Assert(!isRef || ((BoundLocal)rewrittenLeft).LocalSymbol.RefKind != RefKind.None);
return new BoundAssignmentOperator(
syntax,
rewrittenLeft,
rewrittenRight,
type,
refKind: refKind);
isRef: isRef);
}
case BoundKind.DiscardExpression:
......@@ -223,7 +229,7 @@ private BoundExpression MakeStaticAssignmentOperator(SyntaxNode syntax, BoundExp
default:
{
Debug.Assert(refKind == RefKind.None);
Debug.Assert(!isRef);
return new BoundAssignmentOperator(
syntax,
rewrittenLeft,
......
......@@ -551,11 +551,11 @@ private BoundExpression TransformCompoundAssignmentLHS(BoundExpression originalL
break;
case BoundKind.ConditionalOperator:
Debug.Assert(((BoundConditionalOperator)originalLHS).IsByRef);
Debug.Assert(((BoundConditionalOperator)originalLHS).IsRef);
break;
case BoundKind.AssignmentOperator:
Debug.Assert(((BoundAssignmentOperator)originalLHS).RefKind != RefKind.None);
Debug.Assert(((BoundAssignmentOperator)originalLHS).IsRef);
break;
case BoundKind.PointerElementAccess:
......
......@@ -24,7 +24,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
if (rewrittenCondition.ConstantValue == null)
{
return node.Update(node.IsByRef, rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.ConstantValueOpt, node.Type);
return node.Update(node.IsRef, rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.ConstantValueOpt, node.Type);
}
return RewriteConditionalOperator(
......@@ -34,7 +34,7 @@ public override BoundNode VisitConditionalOperator(BoundConditionalOperator node
rewrittenAlternative,
node.ConstantValueOpt,
node.Type,
node.IsByRef);
node.IsRef);
}
private static BoundExpression RewriteConditionalOperator(
......
......@@ -47,7 +47,7 @@ public override BoundNode VisitFixedStatement(BoundFixedStatement node)
_factory.Syntax,
_factory.Default(new PointerTypeSymbol(pinnedTemp.Type)),
pinnedTemp.Type),
refKind: RefKind.Ref);
isRef: true);
}
}
......@@ -265,7 +265,7 @@ public override BoundNode VisitFixedLocalCollectionInitializer(BoundFixedLocalCo
Debug.Assert(!localSymbol.IsPinned);
// pinnedTemp = ref v;
BoundStatement pinnedTempInit = factory.Assignment(factory.Local(pinnedTemp), initializerExpr, refKind: RefKind.Ref);
BoundStatement pinnedTempInit = factory.Assignment(factory.Local(pinnedTemp), initializerExpr, isRef: true);
// &pinnedTemp;
var addr = new BoundAddressOfOperator(
......
......@@ -62,7 +62,7 @@ private BoundStatement RewriteLocalDeclaration(BoundLocalDeclaration originalOpt
),
rewrittenInitializer,
localSymbol.Type,
localSymbol.RefKind),
localSymbol.IsRef),
hasErrors);
return InstrumentLocalDeclarationIfNecessary(originalOpt, localSymbol, rewrittenLocalDeclaration);
......
......@@ -282,7 +282,7 @@ private BoundExpression MakeCollectionInitializer(BoundExpression rewrittenRecei
{
// Rewrite simple assignment to field/property.
var rewrittenRight = VisitExpression(assignment.Right);
result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, RefKind.None, assignment.Type, used: false));
result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, false, assignment.Type, used: false));
return;
}
}
......@@ -323,7 +323,7 @@ private BoundExpression MakeCollectionInitializer(BoundExpression rewrittenRecei
{
// Rewrite simple assignment to field/property.
var rewrittenRight = VisitExpression(assignment.Right);
result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, RefKind.None, assignment.Type, used: false));
result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, false, assignment.Type, used: false));
return;
}
......@@ -356,7 +356,7 @@ private BoundExpression MakeCollectionInitializer(BoundExpression rewrittenRecei
{
// Rewrite as simple assignment.
var rewrittenRight = VisitExpression(assignment.Right);
result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, RefKind.None, assignment.Type, used: false));
result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, false, assignment.Type, used: false));
return;
}
......
......@@ -422,7 +422,7 @@ private void LowerConstantValueDecision(DecisionTree.ByValue byValue)
Debug.Assert(loweredLeft.Type.Equals(loweredRight.Type, TypeCompareKind.AllIgnoreOptions));
addBindings.Add(_factory.ExpressionStatement(
_localRewriter.MakeStaticAssignmentOperator(
_factory.Syntax, loweredLeft, loweredRight, RefKind.None, loweredLeft.Type, false)));
_factory.Syntax, loweredLeft, loweredRight, isRef: false, type: loweredLeft.Type, used: false)));
}
}
}
......
......@@ -385,7 +385,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
BoundExpression originalRight = node.Right;
if (leftLocal.LocalSymbol.RefKind != RefKind.None &&
node.RefKind != RefKind.None &&
node.IsRef &&
NeedsProxy(leftLocal.LocalSymbol))
{
Debug.Assert(!proxies.ContainsKey(leftLocal.LocalSymbol));
......@@ -422,8 +422,8 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
BoundAssignmentOperator tempAssignment;
BoundLocal tempLocal = factory.StoreToTemp(rewrittenRight, out tempAssignment);
Debug.Assert(node.RefKind == RefKind.None);
BoundAssignmentOperator rewrittenAssignment = node.Update(rewrittenLeft, tempLocal, node.RefKind, rewrittenType);
Debug.Assert(!node.IsRef);
BoundAssignmentOperator rewrittenAssignment = node.Update(rewrittenLeft, tempLocal, node.IsRef, rewrittenType);
return new BoundSequence(
node.Syntax,
......@@ -433,7 +433,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
rewrittenType);
}
return node.Update(rewrittenLeft, rewrittenRight, node.RefKind, rewrittenType);
return node.Update(rewrittenLeft, rewrittenRight, node.IsRef, rewrittenType);
}
public override BoundNode VisitFieldInfo(BoundFieldInfo node)
......
......@@ -497,7 +497,7 @@ private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssi
var type = TypeMap.SubstituteType(local.Type).Type;
var sacrificialTemp = F.SynthesizedLocal(type, refKind: RefKind.Ref);
Debug.Assert(type == replacement.Type);
return F.Sequence(ImmutableArray.Create(sacrificialTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificialTemp), replacement, refKind: RefKind.Ref));
return F.Sequence(ImmutableArray.Create(sacrificialTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificialTemp), replacement, isRef: true));
}
if (sideEffects.Count == 0)
......@@ -581,7 +581,7 @@ private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssi
var conditional = (BoundConditionalOperator)expr;
if (isRef)
{
Debug.Assert(conditional.IsByRef);
Debug.Assert(conditional.IsRef);
F.Diagnostics.Add(ErrorCode.ERR_RefConditionalAndAwait, F.Syntax.Location);
isRef = false; // Switch to ByVal to avoid asserting later in the pipeline
}
......@@ -755,7 +755,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
if (proxies.ContainsKey(leftLocal))
{
Debug.Assert(node.RefKind == RefKind.None);
Debug.Assert(!node.IsRef);
return base.VisitAssignmentOperator(node);
}
......@@ -767,7 +767,7 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
// being used in any other way.
Debug.Assert(leftLocal.SynthesizedKind == SynthesizedLocalKind.AwaitSpill);
Debug.Assert(node.RefKind != RefKind.None);
Debug.Assert(node.IsRef);
// We have an assignment to a variable that has not yet been assigned a proxy.
// So we assign the proxy before translating the assignment.
......
......@@ -363,9 +363,9 @@ public PropertySymbol SpecialProperty(SpecialMember sm)
return (PropertySymbol)SpecialMember(sm);
}
public BoundExpressionStatement Assignment(BoundExpression left, BoundExpression right, RefKind refKind = RefKind.None)
public BoundExpressionStatement Assignment(BoundExpression left, BoundExpression right, bool isRef = false)
{
return ExpressionStatement(AssignmentExpression(left, right, refKind));
return ExpressionStatement(AssignmentExpression(left, right, isRef));
}
public BoundExpressionStatement ExpressionStatement(BoundExpression expr)
......@@ -373,12 +373,12 @@ public BoundExpressionStatement ExpressionStatement(BoundExpression expr)
return new BoundExpressionStatement(Syntax, expr) { WasCompilerGenerated = true };
}
public BoundAssignmentOperator AssignmentExpression(BoundExpression left, BoundExpression right, RefKind refKind = RefKind.None)
public BoundAssignmentOperator AssignmentExpression(BoundExpression left, BoundExpression right, bool isRef = false)
{
Debug.Assert(left.Type.Equals(right.Type, TypeCompareKind.AllIgnoreOptions) ||
right.Type.IsErrorType() || left.Type.IsErrorType());
return new BoundAssignmentOperator(Syntax, left, right, left.Type, refKind: refKind) { WasCompilerGenerated = true };
return new BoundAssignmentOperator(Syntax, left, right, left.Type, isRef: isRef) { WasCompilerGenerated = true };
}
public BoundBlock Block()
......@@ -1299,7 +1299,7 @@ internal static BoundExpression NullOrDefault(TypeSymbol typeSymbol, SyntaxNode
syntax,
local,
argument,
refKind,
refKind != RefKind.None,
type);
return local;
......
......@@ -1005,7 +1005,7 @@ private ISimpleAssignmentOperation CreateBoundAssignmentOperatorOperation(BoundA
Debug.Assert(!IsMemberInitializer(boundAssignmentOperator));
Lazy<IOperation> target = new Lazy<IOperation>(() => Create(boundAssignmentOperator.Left));
bool isRef = boundAssignmentOperator.RefKind != RefKind.None;
bool isRef = boundAssignmentOperator.IsRef;
Lazy<IOperation> value = new Lazy<IOperation>(() => Create(boundAssignmentOperator.Right));
SyntaxNode syntax = boundAssignmentOperator.Syntax;
ITypeSymbol type = boundAssignmentOperator.Type;
......@@ -1117,7 +1117,7 @@ private IConditionalOperation CreateBoundConditionalOperatorOperation(BoundCondi
Lazy<IOperation> condition = new Lazy<IOperation>(() => Create(boundConditionalOperator.Condition));
Lazy<IOperation> whenTrue = new Lazy<IOperation>(() => Create(boundConditionalOperator.Consequence));
Lazy<IOperation> whenFalse = new Lazy<IOperation>(() => Create(boundConditionalOperator.Alternative));
bool isRef = boundConditionalOperator.IsByRef;
bool isRef = boundConditionalOperator.IsRef;
SyntaxNode syntax = boundConditionalOperator.Syntax;
ITypeSymbol type = boundConditionalOperator.Type;
Optional<object> constantValue = ConvertToOptional(boundConditionalOperator.ConstantValue);
......
......@@ -75,7 +75,7 @@ internal sealed class LocalDeclarationRewriter
syntax,
new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type),
initializer,
RefKind.None,
false,
local.Type);
statements.Add(new BoundExpressionStatement(syntax, assignment));
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册