本文整理汇总了C#中BoundAssignmentOperator类的典型用法代码示例。如果您正苦于以下问题:C# BoundAssignmentOperator类的具体用法?C# BoundAssignmentOperator怎么用?C# BoundAssignmentOperator使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。
BoundAssignmentOperator类属于命名空间,在下文中一共展示了BoundAssignmentOperator类的15个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C#代码示例。
示例1: RewriteLocalDeclaration
private static void RewriteLocalDeclaration(
CSharpCompilation compilation,
EENamedTypeSymbol container,
HashSet<LocalSymbol> declaredLocals,
ArrayBuilder<BoundStatement> statements,
BoundLocalDeclaration node)
{
Debug.Assert(node.ArgumentsOpt.IsDefault);
var local = node.LocalSymbol;
var syntax = node.Syntax;
declaredLocals.Add(local);
var typeType = compilation.GetWellKnownType(WellKnownType.System_Type);
var stringType = compilation.GetSpecialType(SpecialType.System_String);
// CreateVariable(Type type, string name)
var method = PlaceholderLocalSymbol.GetIntrinsicMethod(compilation, ExpressionCompilerConstants.CreateVariableMethodName);
var type = new BoundTypeOfOperator(syntax, new BoundTypeExpression(syntax, aliasOpt: null, type: local.Type), null, typeType);
var name = new BoundLiteral(syntax, ConstantValue.Create(local.Name), stringType);
var call = BoundCall.Synthesized(
syntax,
receiverOpt: null,
method: method,
arguments: ImmutableArray.Create<BoundExpression>(type, name));
statements.Add(new BoundExpressionStatement(syntax, call));
var initializer = node.InitializerOpt;
if (initializer != null)
{
// Generate assignment to local. The assignment will
// be rewritten in PlaceholderLocalRewriter.
var assignment = new BoundAssignmentOperator(
syntax,
new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type),
initializer,
RefKind.None,
local.Type);
statements.Add(new BoundExpressionStatement(syntax, assignment));
}
}
示例2: RewriteLocalDeclaration
private static void RewriteLocalDeclaration(
ArrayBuilder<BoundStatement> statements,
BoundLocalDeclaration node)
{
Debug.Assert(node.ArgumentsOpt.IsDefault);
var initializer = node.InitializerOpt;
if (initializer != null)
{
var local = node.LocalSymbol;
var syntax = node.Syntax;
// Generate assignment to local. The assignment will
// be rewritten in PlaceholderLocalRewriter.
var assignment = new BoundAssignmentOperator(
syntax,
new BoundLocal(syntax, local, constantValueOpt: null, type: local.Type),
initializer,
RefKind.None,
local.Type);
statements.Add(new BoundExpressionStatement(syntax, assignment));
}
}
示例3: EmitAssignmentPreamble
private bool EmitAssignmentPreamble(BoundAssignmentOperator assignmentOperator)
{
var assignmentTarget = assignmentOperator.Left;
bool lhsUsesStack = false;
switch (assignmentTarget.Kind)
{
case BoundKind.RefValueOperator:
EmitRefValueAddress((BoundRefValueOperator)assignmentTarget);
break;
case BoundKind.FieldAccess:
{
var left = (BoundFieldAccess)assignmentTarget;
if (!left.FieldSymbol.IsStatic)
{
var temp = EmitReceiverRef(left.ReceiverOpt);
Debug.Assert(temp == null, "temp is unexpected when assigning to a field");
lhsUsesStack = true;
}
}
break;
case BoundKind.Parameter:
{
var left = (BoundParameter)assignmentTarget;
if (left.ParameterSymbol.RefKind != RefKind.None)
{
_builder.EmitLoadArgumentOpcode(ParameterSlot(left));
lhsUsesStack = true;
}
}
break;
case BoundKind.Local:
{
var left = (BoundLocal)assignmentTarget;
// Again, consider our earlier case:
//
// ref int addr = ref N().s;
// int sum = addr + 10;
// addr = sum;
//
// There are three different ways we could be assigning to a local.
//
// In the first case, we want to simply call N(), take the address
// of s, and then store that address in addr.
//
// In the second case again we simply want to compute the sum and
// store the result in sum.
//
// In the third case however we want to first load the contents of
// addr -- the address of field s -- then put the sum on the stack,
// 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 (!IsStackLocal(left.LocalSymbol))
{
LocalDefinition localDefinition = GetLocal(left);
_builder.EmitLocalLoad(localDefinition);
}
else
{
// this is a case of indirect assignment to a stack temp.
// currently byref temp can only be a stack local in scenarios where
// there is only one assignment and it is the last one.
// I do not yet know how to support cases where we assign more than once.
// That where Dup of LHS would be needed, but as a general scenario
// it is not always possible to handle. Fortunately all the cases where we
// indirectly assign to a byref temp come from rewriter and all
// they all are write-once cases.
//
// For now analyzer asserts that indirect writes are final reads of
// a ref local. And we never need a dup here.
// builder.EmitOpCode(ILOpCode.Dup);
}
lhsUsesStack = true;
}
}
break;
case BoundKind.ArrayAccess:
{
var left = (BoundArrayAccess)assignmentTarget;
EmitExpression(left.Expression, used: true);
EmitArrayIndices(left.Indices);
lhsUsesStack = true;
}
break;
case BoundKind.ThisReference:
{
var left = (BoundThisReference)assignmentTarget;
var temp = EmitAddress(left, AddressKind.Writeable);
//.........这里部分代码省略.........
示例4: TryEmitAssignmentInPlace
// sometimes it is possible and advantageous to get an address of the lHS and
// perform assignment as an in-place initialization via initobj or constructor invocation.
//
// 1) initobj
// is used when assigning default value to T that is not a verifier reference.
//
// 2) in-place ctor call
// is used when assigning a freshly created struct. "x = new S(arg)" can be
// replaced by x.S(arg) as long as partial assignment cannot be observed -
// i.e. target must not be on the heap and we should not be in a try block.
private bool TryEmitAssignmentInPlace(BoundAssignmentOperator assignmentOperator, bool used)
{
var left = assignmentOperator.Left;
// if result is used, and lives on heap, we must keep RHS value on the stack.
// otherwise we can try conjuring up the RHS value directly where it belongs.
if (used && !TargetIsNotOnHeap(left))
{
return false;
}
if (!SafeToGetWriteableReference(left))
{
// cannot take a ref
return false;
}
var right = assignmentOperator.Right;
var rightType = right.Type;
// in-place is not advantageous for reference types or constants
if (!rightType.IsTypeParameter())
{
if (rightType.IsReferenceType || (right.ConstantValue != null && rightType.SpecialType != SpecialType.System_Decimal))
{
return false;
}
}
if (right.IsDefaultValue())
{
InPlaceInit(left, used);
return true;
}
if (right.Kind == BoundKind.ObjectCreationExpression)
{
// It is desirable to do in-place ctor call if possible.
// we could do newobj/stloc, but in-place call
// produces same or better code in current JITs
if (PartialCtorResultCannotEscape(left))
{
var objCreation = (BoundObjectCreationExpression)right;
InPlaceCtorCall(left, objCreation, used);
return true;
}
}
return false;
}
示例5: EmitAssignmentExpression
private void EmitAssignmentExpression(BoundAssignmentOperator assignmentOperator, UseKind useKind)
{
if (TryEmitAssignmentInPlace(assignmentOperator, useKind != UseKind.Unused))
{
Debug.Assert(assignmentOperator.RefKind == RefKind.None);
return;
}
// Assignment expression codegen has the following parts:
//
// * PreRHS: We need to emit instructions before the load of the right hand side if:
// - If the left hand side is a ref local or ref formal parameter and the right hand
// side is a value then we must put the ref on the stack early so that we can store
// indirectly into it.
// - If the left hand side is an array slot then we must evaluate the array and indices
// before we evaluate the right hand side. We ensure that the array and indices are
// on the stack when the store is executed.
// - Similarly, if the left hand side is a non-static field then its receiver must be
// evaluated before the right hand side.
//
// * RHS: There are three possible ways to do an assignment with respect to "refness",
// and all are found in the lowering of:
//
// N().s += 10;
//
// That expression is realized as
//
// ref int addr = ref N().s; // Assign a ref on the right hand side to the left hand side.
// int sum = addr + 10; // No refs at all; assign directly to sum.
// addr = sum; // Assigns indirectly through the address.
//
// - If we are in the first case then assignmentOperator.RefKind is Ref and the left hand side is a
// ref local temporary. We simply assign the ref on the RHS to the storage on the LHS with no indirection.
//
// - If we are in the second case then nothing is ref; we have a value on one side an a local on the other.
// Again, there is no indirection.
//
// - If we are in the third case then we have a ref on the left and a value on the right. We must compute the
// value of the right hand side and then store it into the left hand side.
//
// * Duplication: The result of an assignment operation is the value that was assigned. It is possible that
// later codegen is expecting this value to be on the stack when we're done here. This is controlled by
// the "used" formal parameter. There are two possible cases:
// - If the preamble put stuff on the stack for the usage of the store, then we must not put an extra copy
// of the right hand side value on the stack; that will be between the value and the stuff needed to
// do the storage. In that case we put the right hand side value in a temporary and restore it later.
// - Otherwise we can just do a dup instruction; there's nothing before the dup on the stack that we'll need.
//
// * Storage: Either direct or indirect, depending. See the RHS section above for details.
//
// * Post-storage: If we stashed away the duplicated value in the temporary, we need to restore it back to the stack.
bool lhsUsesStack = EmitAssignmentPreamble(assignmentOperator);
EmitAssignmentValue(assignmentOperator);
LocalDefinition temp = EmitAssignmentDuplication(assignmentOperator, useKind, lhsUsesStack);
EmitStore(assignmentOperator);
EmitAssignmentPostfix(assignmentOperator, temp, useKind);
}
示例6: IsIndirectOrInstanceFieldAssignment
private static bool IsIndirectOrInstanceFieldAssignment(BoundAssignmentOperator node)
{
var lhs = node.Left;
if (lhs.Kind == BoundKind.FieldAccess)
{
return !((BoundFieldAccess)lhs).FieldSymbol.IsStatic;
}
return IsIndirectAssignment(node);
}
示例7: IsIndirectAssignment
// indirect assignment is assignment to a value referenced indirectly
// it may only happen if
// 1) lhs is a reference (must be a parameter or a local)
// 2) it is not a ref/out assignment where the reference itself would be assigned
private static bool IsIndirectAssignment(BoundAssignmentOperator node)
{
var lhs = node.Left;
switch (lhs.Kind)
{
case BoundKind.ThisReference:
Debug.Assert(lhs.Type.IsValueType && node.RefKind == RefKind.None);
return true;
case BoundKind.Parameter:
if (((BoundParameter)lhs).ParameterSymbol.RefKind != RefKind.None)
{
bool isIndirect = node.RefKind == RefKind.None;
Debug.Assert(isIndirect, "direct assignment to a ref/out parameter is highly suspicious");
return isIndirect;
}
break;
case BoundKind.Local:
if (((BoundLocal)lhs).LocalSymbol.RefKind != RefKind.None)
{
bool isIndirect = node.RefKind == RefKind.None;
return isIndirect;
}
break;
}
Debug.Assert(node.RefKind == RefKind.None, "this is not something that can be assigned indirectly");
return false;
}
示例8: VisitAssignmentOperator
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
{
// Assume value of expression is used.
return VisitAssignmentOperator(node, used: true);
}
示例9: EmitStore
private void EmitStore(BoundAssignmentOperator assignment)
{
BoundExpression expression = assignment.Left;
switch (expression.Kind)
{
case BoundKind.FieldAccess:
EmitFieldStore((BoundFieldAccess)expression);
break;
case BoundKind.Local:
// If we are doing a 'normal' local assignment like 'int t = 10;', or
// if we are initializing a temporary like 'ref int t = ref M().s;' then
// we just emit a local store. If we are doing an assignment through
// a ref local temporary then we assume that the instruction to load
// the address is already on the stack, and we must indirect through it.
// See the comments in EmitAssignmentExpression above for details.
BoundLocal local = (BoundLocal)expression;
if (local.LocalSymbol.RefKind != RefKind.None && assignment.RefKind == RefKind.None)
{
EmitIndirectStore(local.LocalSymbol.Type, local.Syntax);
}
else
{
if (IsStackLocal(local.LocalSymbol))
{
// assign to stack var == leave original value on stack
break;
}
else
{
_builder.EmitLocalStore(GetLocal(local));
}
}
break;
case BoundKind.ArrayAccess:
var array = ((BoundArrayAccess)expression).Expression;
var arrayType = (ArrayTypeSymbol)array.Type;
EmitArrayElementStore(arrayType, expression.Syntax);
break;
case BoundKind.ThisReference:
EmitThisStore((BoundThisReference)expression);
break;
case BoundKind.Parameter:
EmitParameterStore((BoundParameter)expression);
break;
case BoundKind.Dup:
Debug.Assert(((BoundDup)expression).RefKind != RefKind.None);
EmitIndirectStore(expression.Type, expression.Syntax);
break;
case BoundKind.RefValueOperator:
case BoundKind.PointerIndirectionOperator:
case BoundKind.PseudoVariable:
EmitIndirectStore(expression.Type, expression.Syntax);
break;
case BoundKind.Sequence:
{
var sequence = (BoundSequence)expression;
EmitStore(assignment.Update(sequence.Value, assignment.Right, assignment.RefKind, assignment.Type));
var notReleased = DigForValueLocal(sequence);
if (notReleased != null)
{
FreeLocal(notReleased);
}
}
break;
case BoundKind.Call:
Debug.Assert(((BoundCall)expression).Method.RefKind != RefKind.None);
EmitIndirectStore(expression.Type, expression.Syntax);
break;
case BoundKind.ModuleVersionId:
EmitModuleVersionIdStore((BoundModuleVersionId)expression);
break;
case BoundKind.InstrumentationPayloadRoot:
EmitInstrumentationPayloadRootStore((BoundInstrumentationPayloadRoot)expression);
break;
case BoundKind.PreviousSubmissionReference:
// Script references are lowered to a this reference and a field access.
default:
throw ExceptionUtilities.UnexpectedValue(expression.Kind);
}
}
示例10: VisitAssignmentOperator
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
{
BoundExpression originalLeft = node.Left;
if (originalLeft.Kind != BoundKind.Local)
{
return base.VisitAssignmentOperator(node);
}
var leftLocal = (BoundLocal)originalLeft;
BoundExpression originalRight = node.Right;
if (leftLocal.LocalSymbol.RefKind != RefKind.None &&
node.RefKind != RefKind.None &&
NeedsProxy(leftLocal.LocalSymbol))
{
Debug.Assert(!proxies.ContainsKey(leftLocal.LocalSymbol));
Debug.Assert(!IsStackAlloc(originalRight));
//spilling ref local variables
throw ExceptionUtilities.Unreachable;
}
if (NeedsProxy(leftLocal.LocalSymbol) && !proxies.ContainsKey(leftLocal.LocalSymbol))
{
Debug.Assert(leftLocal.LocalSymbol.DeclarationKind == LocalDeclarationKind.None);
// spilling temp variables
throw ExceptionUtilities.Unreachable;
}
BoundExpression rewrittenLeft = (BoundExpression)this.Visit(leftLocal);
BoundExpression rewrittenRight = (BoundExpression)this.Visit(originalRight);
TypeSymbol rewrittenType = VisitType(node.Type);
// Check if we're assigning the result of stackalloc to a hoisted local.
// If we are, we need to store the result in a temp local and then assign
// the value of the local to the field corresponding to the hoisted local.
// If the receiver of the field is on the stack when the stackalloc happens,
// popping it will free the memory (?) or otherwise cause verification issues.
// DevDiv Bugs 59454
if (rewrittenLeft.Kind != BoundKind.Local && IsStackAlloc(originalRight))
{
// From ILGENREC::genAssign:
// DevDiv Bugs 59454: Handle hoisted local initialized with a stackalloc
// NOTE: Need to check for cast of stackalloc on RHS.
// If LHS isLocal, then genAddr is a noop so regular case works fine.
SyntheticBoundNodeFactory factory = new SyntheticBoundNodeFactory(this.CurrentMethod, rewrittenLeft.Syntax, this.CompilationState, this.Diagnostics);
BoundAssignmentOperator tempAssignment;
BoundLocal tempLocal = factory.StoreToTemp(rewrittenRight, out tempAssignment);
Debug.Assert(node.RefKind == RefKind.None);
BoundAssignmentOperator rewrittenAssignment = node.Update(rewrittenLeft, tempLocal, node.RefKind, rewrittenType);
return new BoundSequence(
node.Syntax,
ImmutableArray.Create<LocalSymbol>(tempLocal.LocalSymbol),
ImmutableArray.Create<BoundExpression>(tempAssignment),
rewrittenAssignment,
rewrittenType);
}
return node.Update(rewrittenLeft, rewrittenRight, node.RefKind, rewrittenType);
}
示例11: VisitAssignmentOperator
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)
{
return this.SetMayHaveSideEffects();
}
示例12: IsIndirectAssignment
// indirect assignment is assignment to a value referenced indirectly
// it may only happen if
// 1) lhs is a reference (must be a parameter or a local)
// 2) it is not a ref/out assignment where the reference itself would be assigned
private static bool IsIndirectAssignment(BoundAssignmentOperator node)
{
var lhs = node.Left;
Debug.Assert(node.RefKind == RefKind.None || (lhs as BoundLocal)?.LocalSymbol.RefKind == RefKind.Ref,
"only ref locals can be a target of a ref assignment");
switch (lhs.Kind)
{
case BoundKind.ThisReference:
Debug.Assert(lhs.Type.IsValueType, "'this' is assignable only in structs");
return true;
case BoundKind.Parameter:
if (((BoundParameter)lhs).ParameterSymbol.RefKind != RefKind.None)
{
bool isIndirect = node.RefKind == RefKind.None;
return isIndirect;
}
return false;
case BoundKind.Local:
if (((BoundLocal)lhs).LocalSymbol.RefKind != RefKind.None)
{
bool isIndirect = node.RefKind == RefKind.None;
return isIndirect;
}
return false;
case BoundKind.Call:
Debug.Assert(((BoundCall)lhs).Method.RefKind == RefKind.Ref, "only ref returning methods are assignable");
return true;
case BoundKind.AssignmentOperator:
Debug.Assert(((BoundAssignmentOperator)lhs).RefKind == RefKind.Ref, "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)),
"indirect assignment to a sequence is unexpected");
return false;
case BoundKind.RefValueOperator:
case BoundKind.PointerIndirectionOperator:
case BoundKind.PseudoVariable:
return true;
case BoundKind.ModuleVersionId:
case BoundKind.InstrumentationPayloadRoot:
// these are just stores into special static fields
goto case BoundKind.FieldAccess;
case BoundKind.FieldAccess:
case BoundKind.ArrayAccess:
// always symbolic stores
return false;
default:
throw ExceptionUtilities.UnexpectedValue(lhs.Kind);
}
}
示例13: EmitAssignmentValue
private void EmitAssignmentValue(BoundAssignmentOperator assignmentOperator)
{
if (assignmentOperator.RefKind == RefKind.None)
{
EmitExpression(assignmentOperator.Right, used: true);
}
else
{
// LEAKING A TEMP IS OK HERE
// Once a reference is assigned to a byref local, there is no easy way to figure when
// reference is no longer in use.
// Therefore if we had to create a temp while producing a reference, we do not know when
// the temp slot can be reused so we must leak it.
var temp = EmitAddress(assignmentOperator.Right, AddressKind.Writeable);
}
}
示例14: VisitCompoundAssignmentOperator
//.........这里部分代码省略.........
// UNDONE:
// UNDONE: For now, we'll punt on both problems, as indexers are not implemented yet anyway.
// UNDONE: We'll just generate one temporary for each argument. This will work, but in the
// UNDONE: subsequent rewritings will generate more unnecessary temporaries.
var transformedArguments = ArrayBuilder<BoundExpression>.GetInstance();
foreach (var argument in indexer.Arguments)
{
var rewrittenArgument = (BoundExpression)Visit(argument);
var argumentTemp = TempHelpers.StoreToTemp(rewrittenArgument, RefKind.None, containingSymbol);
transformedArguments.Add(argumentTemp.Item2);
stores.Add(argumentTemp.Item1);
temps.Add(argumentTemp.Item2.LocalSymbol);
}
transformedLHS = new BoundIndexerAccess(indexer.Syntax, indexer.SyntaxTree, transformedArguments.ToReadOnlyAndFree(), transformedReceiver,
indexer.IndexerSymbol, indexer.Type);
}
else if (node.Left.Kind == BoundKind.Local || node.Left.Kind == BoundKind.Parameter)
{
// No temporaries are needed. Just generate local = local + value
transformedLHS = node.Left;
}
else if (node.Left.Kind == BoundKind.FieldAccess)
{
// * If the field is static then no temporaries are needed.
// * If the field is not static and the receiver is of reference type then generate t = r; t.f = t.f + value
// * If the field is not static and the receiver is a variable of value type then we'll fall into the
// general variable case below.
var fieldAccess = (BoundFieldAccess)node.Left;
if (fieldAccess.ReceiverOpt == null)
{
transformedLHS = fieldAccess;
}
else if (!fieldAccess.ReceiverOpt.Type.IsValueType)
{
var rewrittenReceiver = (BoundExpression)Visit(fieldAccess.ReceiverOpt);
var receiverTemp = TempHelpers.StoreToTemp(rewrittenReceiver, RefKind.None, containingSymbol);
stores.Add(receiverTemp.Item1);
temps.Add(receiverTemp.Item2.LocalSymbol);
transformedLHS = new BoundFieldAccess(fieldAccess.Syntax, fieldAccess.SyntaxTree, receiverTemp.Item2, fieldAccess.FieldSymbol, null);
}
}
if (transformedLHS == null)
{
// We made no transformation above. Either we have array[index] += value or
// structVariable.field += value; either way we have a potentially complicated variable-
// producing expression on the left. Generate
// ref temp = ref variable; temp = temp + value
var rewrittenVariable = (BoundExpression)Visit(node.Left);
var variableTemp = TempHelpers.StoreToTemp(rewrittenVariable, RefKind.Ref, containingSymbol);
stores.Add(variableTemp.Item1);
temps.Add(variableTemp.Item2.LocalSymbol);
transformedLHS = variableTemp.Item2;
}
// OK, we now have the temporary declarations, the temporary stores, and the transformed left hand side.
// We need to generate
//
// xlhs = (FINAL)((LEFT)xlhs op rhs)
//
// And then wrap it up with the generated temporaries.
//
// (The right hand side has already been converted to the type expected by the operator.)
BoundExpression opLHS = BoundConversion.SynthesizedConversion(transformedLHS, node.LeftConversion, node.Operator.LeftType);
Debug.Assert(node.Right.Type == node.Operator.RightType);
BoundExpression op = new BoundBinaryOperator(null, null, node.Operator.Kind, opLHS, node.Right, null, node.Operator.ReturnType);
BoundExpression opFinal = BoundConversion.SynthesizedConversion(op, node.FinalConversion, node.Left.Type);
BoundExpression assignment = new BoundAssignmentOperator(null, null, transformedLHS, opFinal, node.Left.Type);
// OK, at this point we have:
//
// * temps evaluating and storing portions of the LHS that must be evaluated only once.
// * the "transformed" left hand side, rebuilt to use temps where necessary
// * the assignment "xlhs = (FINAL)((LEFT)xlhs op (RIGHT)rhs)"
//
// Notice that we have recursively rewritten the bound nodes that are things stored in
// the temps, but we might have more rewriting to do on the assignment. There are three
// conversions in there that might be lowered to method calls, an operator that might
// be lowered to delegate combine, string concat, and so on, and don't forget, we
// haven't lowered the right hand side at all! Let's rewrite all these things at once.
BoundExpression rewrittenAssignment = (BoundExpression)Visit(assignment);
BoundExpression result = (temps.Count == 0) ?
rewrittenAssignment :
new BoundSequence(null,
null,
temps.ToReadOnly(),
stores.ToReadOnly(),
rewrittenAssignment,
rewrittenAssignment.Type);
temps.Free();
stores.Free();
return result;
}
示例15: EmitAssignmentValue
private void EmitAssignmentValue(BoundAssignmentOperator assignmentOperator)
{
if (assignmentOperator.RefKind == RefKind.None)
{
EmitExpression(assignmentOperator.Right, used: true);
}
else
{
// LEAKING A TEMP IS OK HERE
// generally taking a ref for the purpose of ref assignment should not be done on homeless values
// however, there are very rare cases when we need to get a ref off a copy in synthetic code and we have to leak those.
// fortunately these are very short-lived temps that should not cause value sharing.
var temp = EmitAddress(assignmentOperator.Right, AddressKind.Writeable);
#if DEBUG
Debug.Assert(temp == null || ((SynthesizedLocal)assignmentOperator.Left.ExpressionSymbol).SynthesizedKind == SynthesizedLocalKind.LoweringTemp);
#endif
}
}