/// <summary> /// Rewrite an assignment operator. /// /// Possible cases: /// (1) Neither the lvalue nor rvalue contain an await expression. /// (2) Only the lvalue contains an await expression. /// (3) The rvalue contains an await expression, and the lvalue is one of: /// (a) an await-containing expression, /// (b) an array access, /// (c) a field access, or /// (d) a local /// /// </summary> public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { BoundExpression leftNode = (BoundExpression)this.Visit(node.Left); BoundExpression rightNode = (BoundExpression)this.Visit(node.Right); TypeSymbol type = this.VisitType(node.Type); if (!RequiresSpill(leftNode, rightNode)) { // Case (1) - no await expression: return node.Update(leftNode, rightNode, node.RefKind, type); } if (!RequiresSpill(rightNode)) { // Case (2) - only lvalue contains await // Spill(l_sideEffects, lvalue) = rvalue // is rewritten as: // Spill(l_sideEffects, lvalue = rvalue) var spill = (BoundSpillSequence) leftNode; var newAssignment = node.Update(spill.Value, rightNode, node.RefKind, type); return RewriteSpillSequence(spill, newAssignment); } // Case (3) - return SpillAssignmentOperator(node, leftNode, (BoundSpillSequence) rightNode); }
private BoundNode SpillAssignmentOperator(BoundAssignmentOperator node, BoundExpression left, BoundSpillSequence right) { var spillBuilder = new SpillBuilder(); var spilledLeftNode = SpillLValue(left, spillBuilder); var innerSpill = node.Update(spilledLeftNode, right.Value, node.RefKind, node.Type); spillBuilder.AddSpill(right); return spillBuilder.BuildSequenceAndFree(F, innerSpill); }
private BoundNode SpillAssignmentOperator(BoundAssignmentOperator node, BoundExpression left, BoundSpillSequence right) { var spillBuilder = new SpillBuilder(); var spilledLeftNode = SpillLValue(left, spillBuilder); var innerSpill = node.Update(spilledLeftNode, right.Value, node.RefKind, node.Type); spillBuilder.AddSpill(right); return(spillBuilder.BuildSequenceAndFree(F, innerSpill)); }
private bool CheckForAssignmentToSelf(BoundAssignmentOperator node) { if (!node.HasAnyErrors && IsSameLocalOrField(node.Left, node.Right)) { Error(ErrorCode.WRN_AssignmentToSelf, node); return(true); } return(false); }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { if (!CheckForAssignmentToSelf(node) && _inExpressionLambda && node.Left.Kind != BoundKind.ObjectInitializerMember && node.Left.Kind != BoundKind.DynamicObjectInitializerMember) { Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node); } return(base.VisitAssignmentOperator(node)); }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { if (node.Left.Kind == BoundKind.Local && node.RefKind != RefKind.None) { var localSymbol = ((BoundLocal)node.Left).LocalSymbol; Debug.Assert(localSymbol.RefKind != RefKind.None); refLocalInitializers.Add(localSymbol, node.Right); } return(base.VisitAssignmentOperator(node)); }
private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssignmentOperator node) { Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.Spill); Debug.Assert(local.SyntaxOpt != null); Debug.Assert(this.OriginalMethod.IsAsync); var right = (BoundExpression)Visit(node.Right); var sideEffects = ArrayBuilder <BoundExpression> .GetInstance(); bool needsSacrificialEvaluation = false; var hoistedFields = ArrayBuilder <StateMachineFieldSymbol> .GetInstance(); SyntaxNode awaitSyntaxOpt; int syntaxOffset; if (F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug) { awaitSyntaxOpt = local.GetDeclaratorSyntax(); Debug.Assert(awaitSyntaxOpt.IsKind(SyntaxKind.AwaitExpression) || awaitSyntaxOpt.IsKind(SyntaxKind.SwitchExpression)); syntaxOffset = OriginalMethod.CalculateLocalSyntaxOffset(LambdaUtilities.GetDeclaratorPosition(awaitSyntaxOpt), awaitSyntaxOpt.SyntaxTree); } else { // These are only used to calculate debug id for ref-spilled variables, // no need to do so in release build. awaitSyntaxOpt = null; syntaxOffset = -1; } var replacement = HoistExpression(right, awaitSyntaxOpt, syntaxOffset, local.RefKind, sideEffects, hoistedFields, ref needsSacrificialEvaluation); proxies.Add(local, new CapturedToExpressionSymbolReplacement(replacement, hoistedFields.ToImmutableAndFree(), isReusable: true)); if (needsSacrificialEvaluation) { var type = TypeMap.SubstituteType(local.Type).Type; var sacrificialTemp = F.SynthesizedLocal(type, refKind: RefKind.Ref); Debug.Assert(TypeSymbol.Equals(type, replacement.Type, TypeCompareKind.ConsiderEverything2)); return(F.Sequence(ImmutableArray.Create(sacrificialTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificialTemp), replacement, isRef: true))); } if (sideEffects.Count == 0) { sideEffects.Free(); return(null); } var last = sideEffects.Last(); sideEffects.RemoveLast(); return(F.Sequence(ImmutableArray <LocalSymbol> .Empty, sideEffects.ToImmutableAndFree(), last)); }
/// <summary> /// Figures out how to assign from sourceType into receivingVariable and bundles the information (leaving holes for the actual source and receiver) into an AssignmentInfo. /// </summary> private BoundDeconstructionAssignmentStep MakeDeconstructionAssignmentStep( BoundExpression receivingVariable, TypeSymbol sourceType, BoundDeconstructValuePlaceholder inputPlaceholder, CSharpSyntaxNode node, DiagnosticBag diagnostics) { var outputPlaceholder = new BoundDeconstructValuePlaceholder(receivingVariable.Syntax, receivingVariable.Type) { WasCompilerGenerated = true }; // each assignment has a placeholder for a receiver and another for the source BoundAssignmentOperator op = BindAssignment(receivingVariable.Syntax, outputPlaceholder, inputPlaceholder, diagnostics); return(new BoundDeconstructionAssignmentStep(node, op, inputPlaceholder, outputPlaceholder)); }
private void InitVariableProxy(CSharpSyntaxNode syntax, Symbol symbol, LocalSymbol framePointer, ArrayBuilder <BoundExpression> prologue) { CapturedSymbolReplacement proxy; if (proxies.TryGetValue(symbol, out proxy)) { BoundExpression value; switch (symbol.Kind) { case SymbolKind.Parameter: { var parameter = (ParameterSymbol)symbol; ParameterSymbol parameterToUse; if (!parameterMap.TryGetValue(parameter, out parameterToUse)) { parameterToUse = parameter; } value = new BoundParameter(syntax, parameterToUse); } break; case SymbolKind.Local: if (!this.assignLocals) { return; } else { var local = (LocalSymbol)symbol; LocalSymbol localToUse; if (!localMap.TryGetValue(local, out localToUse)) { localToUse = local; } value = new BoundLocal(syntax, localToUse, null, localToUse.Type); } break; default: throw ExceptionUtilities.UnexpectedValue(symbol.Kind); } var left = proxy.Replacement(syntax, frameType1 => new BoundLocal(syntax, framePointer, null, framePointer.Type)); var assignToProxy = new BoundAssignmentOperator(syntax, left, value, value.Type); prologue.Add(assignToProxy); } }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { base.VisitAssignmentOperator(node); var rvalue = MakeValueHolder(node.Right); switch (node.Left.Kind) { case BoundKind.Local: { var left = (BoundLocal)node.Left; this.State.variables[left.LocalSymbol] = rvalue.value; } break; case BoundKind.DeclarationExpression: { var left = (BoundDeclarationExpression)node.Left; this.State.variables[left.LocalSymbol] = rvalue.value; } break; case BoundKind.Parameter: { var left = (BoundParameter)node.Left; this.State.variables[left.ParameterSymbol] = rvalue.value; } break; case BoundKind.FieldAccess: case BoundKind.PropertyAccess: { foreach (var e in rvalue.value.creations) { this.State.possiblyUndisposedCreations.Remove(e); } } break; default: break; } return(rvalue); }
/// <summary> /// Takes an expression and returns the bound local expression "temp" /// and the bound assignment expression "temp = expr". /// </summary> public BoundLocal StoreToTemp(BoundExpression argument, out BoundAssignmentOperator store, RefKind refKind = RefKind.None, TempKind tempKind = TempKind.None) { MethodSymbol containingMethod = this.CurrentMethod; var syntax = argument.Syntax; var type = argument.Type; var local = new BoundLocal( syntax, new SynthesizedLocal(containingMethod, type, syntax: (tempKind == TempKind.None) ? null : syntax, refKind: refKind, tempKind: tempKind), null, type); store = new BoundAssignmentOperator( syntax, local, argument, refKind, type); return(local); }
/// <summary> /// Takes an expression and returns the bound local expression "temp" /// and the bound assignment expression "temp = expr". /// </summary> /// <param name="argument"></param> /// <param name="refKind"></param> /// <param name="containingMethod"></param> /// <returns></returns> public static Pair<BoundAssignmentOperator, BoundLocal> StoreToTemp(BoundExpression argument, RefKind refKind, MethodSymbol containingMethod) { var syntax = argument.Syntax; var type = argument.Type; var local = new BoundLocal( syntax, // TODO: the following temp local symbol should have its ContainingSymbol set. new TempLocalSymbol(type, refKind, containingMethod), null, type); var store = new BoundAssignmentOperator( syntax, local, argument, refKind, type); return Pair.Make(store, local); }
/// <summary> /// Takes an expression and returns the bound local expression "temp" /// and the bound assignment expression "temp = expr". /// </summary> /// <param name="argument"></param> /// <param name="refKind"></param> /// <param name="containingMethod"></param> /// <returns></returns> public static Pair <BoundAssignmentOperator, BoundLocal> StoreToTemp(BoundExpression argument, RefKind refKind, MethodSymbol containingMethod) { var syntax = argument.Syntax; var type = argument.Type; var local = new BoundLocal( syntax, // TODO: the following temp local symbol should have its ContainingSymbol set. new TempLocalSymbol(type, refKind, containingMethod), null, type); var store = new BoundAssignmentOperator( syntax, local, argument, refKind, type); return(Pair.Make(store, local)); }
/// <summary> /// Takes an expression and returns the bound local expression "temp" /// and the bound assignment expression "temp = expr". /// </summary> public BoundLocal StoreToTemp(BoundExpression argument, out BoundAssignmentOperator store, RefKind refKind = RefKind.None, SynthesizedLocalKind kind = SynthesizedLocalKind.LoweringTemp) { MethodSymbol containingMethod = this.CurrentMethod; var syntax = argument.Syntax; var type = argument.Type; var local = new BoundLocal( syntax, new SynthesizedLocal(containingMethod, type, kind, syntax: kind.IsLongLived() ? syntax : null, refKind: refKind), null, type); store = new BoundAssignmentOperator( syntax, local, argument, refKind, type); return(local); }
private static BoundExpressionStatement ClearGlobal(CSharpCompilation compilation, SyntaxNode node, FieldSymbol field) { var lhs = new BoundFieldAccess(node, null, field, null) { WasCompilerGenerated = true }; var rhs = new BoundDefaultExpression(node, field.Type) { WasCompilerGenerated = true }; var op = new BoundAssignmentOperator(node, lhs, rhs, field.Type) { WasCompilerGenerated = true }; var stmt = new BoundExpressionStatement(node, op) { WasCompilerGenerated = true }; return(stmt); }
private static BoundExpressionStatement vulcanruntimeStateAssign(SyntaxNode syntax, FieldSymbol field, bool value) { var bfa = new BoundFieldAccess(syntax, null, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true }; var lit = new BoundLiteral(syntax, ConstantValue.Create(value), field.Type) { WasCompilerGenerated = true }; var ass = new BoundAssignmentOperator(syntax, bfa, lit, isRef: false, lit.Type) { WasCompilerGenerated = true }; var stmt = new BoundExpressionStatement(syntax, ass) { WasCompilerGenerated = true }; return(stmt); }
private void InitParameterProxy(CSharpSyntaxNode syntax, Symbol p, LocalSymbol framePointer, ArrayBuilder <BoundExpression> prologue) { CapturedSymbolReplacement proxy; if (proxies.TryGetValue(p, out proxy)) { BoundExpression assignToProxy; var left = proxy.Replacement(syntax, frameType1 => new BoundLocal(syntax, framePointer, null, framePointer.Type)); var parameter = p as ParameterSymbol; if ((object)parameter != null) { ParameterSymbol parameterToUse; if (!parameterMap.TryGetValue(parameter, out parameterToUse)) { parameterToUse = parameter; } assignToProxy = new BoundAssignmentOperator(syntax, left, new BoundParameter(syntax, parameterToUse), parameter.Type); } else { var local = (LocalSymbol)p; // catch parameter Debug.Assert(local.DeclarationKind == LocalDeclarationKind.Catch); LocalSymbol localToUse; if (!localMap.TryGetValue(local, out localToUse)) { localToUse = local; } assignToProxy = new BoundAssignmentOperator(syntax, left, new BoundLocal(syntax, localToUse, null, localToUse.Type), localToUse.Type); } prologue.Add(assignToProxy); } }
/// <summary> /// Returns true if the initializer is a field initializer which should be optimized out /// </summary> private static bool ShouldOptimizeOutInitializer(BoundStatement initializer) { BoundStatement statement = initializer; if (initializer.Kind == BoundKind.SequencePointWithSpan) { statement = ((BoundSequencePointWithSpan)initializer).StatementOpt; } else if (initializer.Kind == BoundKind.SequencePoint) { statement = ((BoundSequencePoint)initializer).StatementOpt; } if (statement == null || statement.Kind != BoundKind.ExpressionStatement) { return(false); } BoundAssignmentOperator assignment = ((BoundExpressionStatement)statement).Expression as BoundAssignmentOperator; if (assignment == null) { return(false); } Debug.Assert(assignment.Left.Kind == BoundKind.FieldAccess); var lhsField = ((BoundFieldAccess)assignment.Left).FieldSymbol; if (!lhsField.IsStatic && lhsField.ContainingType.IsStructType()) { return(false); } BoundExpression rhs = assignment.Right; return(rhs.IsDefaultValue()); }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { // Assume value of expression is used. return(VisitAssignmentOperator(node, used: true)); }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { BoundSpillSequenceBuilder builder = null; var right = VisitExpression(ref builder, node.Right); BoundExpression left = node.Left; if (builder == null) { left = VisitExpression(ref builder, left); } else { // if the right-hand-side has await, spill the left var leftBuilder = new BoundSpillSequenceBuilder(); switch (left.Kind) { case BoundKind.Local: case BoundKind.Parameter: // locals and parameters are directly assignable, LHS is not on the stack so nothing to spill break; case BoundKind.FieldAccess: var field = (BoundFieldAccess)left; // static fields are directly assignable, LHS is not on the stack, nothing to spill if (field.FieldSymbol.IsStatic) { break; } // instance fields are directly assignable, but receiver is pushed, so need to spill that. var receiver = VisitExpression(ref leftBuilder, field.ReceiverOpt); receiver = Spill(builder, receiver, field.FieldSymbol.ContainingType.IsValueType ? RefKind.Ref : RefKind.None); left = field.Update(receiver, field.FieldSymbol, field.ConstantValueOpt, field.ResultKind, field.Type); break; case BoundKind.ArrayAccess: var arrayAccess = (BoundArrayAccess)left; // array and indices are pushed on stack so need to spill that var expression = VisitExpression(ref leftBuilder, arrayAccess.Expression); expression = Spill(builder, expression, RefKind.None); var indices = this.VisitExpressionList(ref builder, arrayAccess.Indices, forceSpill: true); left = arrayAccess.Update(expression, indices, arrayAccess.Type); break; default: // must be something indirectly assignable, just visit and spill as an ordinary Ref (not a RefReadOnly!!) // // NOTE: in some cases this will result in spiller producing an error. // For example if the LHS is a ref-returning method like // // obj.RefReturning(a, b, c) = await Something(); // // the spiller would eventually have to spill the evaluation result of "refReturning" call as an ordinary Ref, // which it can't. left = Spill(leftBuilder, VisitExpression(ref leftBuilder, left), RefKind.Ref); break; } leftBuilder.Include(builder); builder = leftBuilder; } return(UpdateExpression(builder, node.Update(left, right, node.IsRef, node.Type))); }
private BoundExpression HoistRefInitialization(LocalSymbol local, BoundAssignmentOperator node) { var right = (BoundExpression)Visit(node.Right); var sideEffects = ArrayBuilder<BoundExpression>.GetInstance(); bool needsSacrificialEvaluation = false; var replacement = HoistExpression(local, right, true, sideEffects, ref needsSacrificialEvaluation); proxies.Add(local, new CapturedToExpressionSymbolReplacement(replacement)); if (needsSacrificialEvaluation) { var type = TypeMap.SubstituteType(local.Type); var sacrificalTemp = F.SynthesizedLocal(type, refKind: RefKind.Ref); Debug.Assert(type == replacement.Type); return F.Sequence(ImmutableArray.Create(sacrificalTemp), sideEffects.ToImmutableAndFree(), F.AssignmentExpression(F.Local(sacrificalTemp), replacement, refKind: RefKind.Ref)); } else if (sideEffects.Count == 0) { sideEffects.Free(); return null; } else { var last = sideEffects.Last(); sideEffects.RemoveLast(); return F.Sequence(ImmutableArray<LocalSymbol>.Empty, sideEffects.ToImmutableAndFree(), last); } }
public override BoundNode?VisitAssignmentOperator(BoundAssignmentOperator node) { _mightAssignSomething = true; return(null); }
/// <summary> /// If we have a WinRT type event, we need to encapsulate the adder call /// (which returns an EventRegistrationToken) with a call to /// WindowsRuntimeMarshal.AddEventHandler or RemoveEventHandler, but these /// require us to create a new Func representing the adder and another /// Action representing the Remover. /// /// The rewritten call looks something like: /// /// WindowsRuntimeMarshal.AddEventHandler<EventHandler> /// (new Func<EventHandler, EventRegistrationToken>(@object.add), /// new Action<EventRegistrationToken>(@object.remove), handler); /// /// Where @object is a compiler-generated local temp if needed. /// </summary> /// <remarks> /// TODO: use or delete isDynamic. /// </remarks> private BoundExpression RewriteWindowsRuntimeEventAssignmentOperator(SyntaxNode syntax, EventSymbol eventSymbol, EventAssignmentKind kind, bool isDynamic, BoundExpression rewrittenReceiverOpt, BoundExpression rewrittenArgument) { BoundAssignmentOperator tempAssignment = null; BoundLocal boundTemp = null; if (!eventSymbol.IsStatic && CanChangeValueBetweenReads(rewrittenReceiverOpt)) { boundTemp = _factory.StoreToTemp(rewrittenReceiverOpt, out tempAssignment); } NamedTypeSymbol tokenType = _factory.WellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_EventRegistrationToken); NamedTypeSymbol marshalType = _factory.WellKnownType(WellKnownType.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal); NamedTypeSymbol actionType = _factory.WellKnownType(WellKnownType.System_Action_T).Construct(tokenType); TypeSymbol eventType = eventSymbol.Type; BoundExpression delegateCreationArgument = boundTemp ?? rewrittenReceiverOpt ?? _factory.Type(eventType); BoundDelegateCreationExpression removeDelegate = new BoundDelegateCreationExpression( syntax: syntax, argument: delegateCreationArgument, methodOpt: eventSymbol.RemoveMethod, isExtensionMethod: false, type: actionType); BoundExpression clearCall = null; if (kind == EventAssignmentKind.Assignment) { MethodSymbol clearMethod; if (TryGetWellKnownTypeMember(syntax, WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal__RemoveAllEventHandlers, out clearMethod)) { clearCall = MakeCall( syntax: syntax, rewrittenReceiver: null, method: clearMethod, rewrittenArguments: ImmutableArray.Create <BoundExpression>(removeDelegate), type: clearMethod.ReturnType); } else { clearCall = new BoundBadExpression(syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, ImmutableArray.Create <BoundExpression>(removeDelegate), ErrorTypeSymbol.UnknownResultType); } } ImmutableArray <BoundExpression> marshalArguments; WellKnownMember helper; if (kind == EventAssignmentKind.Subtraction) { helper = WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal__RemoveEventHandler_T; marshalArguments = ImmutableArray.Create <BoundExpression>(removeDelegate, rewrittenArgument); } else { NamedTypeSymbol func2Type = _factory.WellKnownType(WellKnownType.System_Func_T2).Construct(eventType, tokenType); BoundDelegateCreationExpression addDelegate = new BoundDelegateCreationExpression( syntax: syntax, argument: delegateCreationArgument, methodOpt: eventSymbol.AddMethod, isExtensionMethod: false, type: func2Type); helper = WellKnownMember.System_Runtime_InteropServices_WindowsRuntime_WindowsRuntimeMarshal__AddEventHandler_T; marshalArguments = ImmutableArray.Create <BoundExpression>(addDelegate, removeDelegate, rewrittenArgument); } BoundExpression marshalCall; MethodSymbol marshalMethod; if (TryGetWellKnownTypeMember(syntax, helper, out marshalMethod)) { marshalMethod = marshalMethod.Construct(eventType); marshalCall = MakeCall( syntax: syntax, rewrittenReceiver: null, method: marshalMethod, rewrittenArguments: marshalArguments, type: marshalMethod.ReturnType); } else { marshalCall = new BoundBadExpression(syntax, LookupResultKind.NotInvocable, ImmutableArray <Symbol> .Empty, marshalArguments, ErrorTypeSymbol.UnknownResultType); } // In this case, we don't need a sequence. if (boundTemp == null && clearCall == null) { return(marshalCall); } ImmutableArray <LocalSymbol> tempSymbols = boundTemp == null ? ImmutableArray <LocalSymbol> .Empty : ImmutableArray.Create <LocalSymbol>(boundTemp.LocalSymbol); ArrayBuilder <BoundExpression> sideEffects = ArrayBuilder <BoundExpression> .GetInstance(2); //max size if (clearCall != null) { sideEffects.Add(clearCall); } if (tempAssignment != null) { sideEffects.Add(tempAssignment); } Debug.Assert(sideEffects.Any(), "Otherwise, we shouldn't be building a sequence"); return(new BoundSequence(syntax, tempSymbols, sideEffects.ToImmutableAndFree(), marshalCall, marshalCall.Type)); }
/// <summary> /// Takes an expression and returns the bound local expression "temp" /// and the bound assignment expression "temp = expr". /// </summary> public BoundLocal StoreToTemp(BoundExpression argument, out BoundAssignmentOperator store, RefKind refKind = RefKind.None, TempKind tempKind = TempKind.None) { MethodSymbol containingMethod = this.CurrentMethod; var syntax = argument.Syntax; var type = argument.Type; var local = new BoundLocal( syntax, new SynthesizedLocal(containingMethod, type, syntax: (tempKind == TempKind.None) ? null : syntax, refKind: refKind, tempKind: tempKind), null, type); store = new BoundAssignmentOperator( syntax, local, argument, refKind, type); return local; }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { if (node.Left.Kind != BoundKind.Local) { return base.VisitAssignmentOperator(node); } var leftLocal = ((BoundLocal)node.Left).LocalSymbol; if (!NeedsProxy(leftLocal)) { return base.VisitAssignmentOperator(node); } if (proxies.ContainsKey(leftLocal)) { Debug.Assert(node.RefKind == RefKind.None); return base.VisitAssignmentOperator(node); } // TODO (move to AsyncMethodToStateMachineRewriter, this is not applicable to iterators) // User-declared variables are preassigned their proxies, and by-value synthesized variables // are assigned proxies at the beginning of their scope by the enclosing construct. // Here we handle ref temps. Ref synthesized variables are the target of a ref assignment operator before // being used in any other way. Debug.Assert(leftLocal.SynthesizedKind == SynthesizedLocalKind.AwaitSpill); Debug.Assert(node.RefKind != RefKind.None); // We have an assignment to a variable that has not yet been assigned a proxy. // So we assign the proxy before translating the assignment. return HoistRefInitialization((SynthesizedLocal)leftLocal, node); }
private BoundExpression HoistRefInitialization(SynthesizedLocal local, BoundAssignmentOperator node) { Debug.Assert(local.SynthesizedKind == SynthesizedLocalKind.AwaitSpill); Debug.Assert(local.SyntaxOpt != null); Debug.Assert(this.OriginalMethod.IsAsync); var right = (BoundExpression)Visit(node.Right); var sideEffects = ArrayBuilder<BoundExpression>.GetInstance(); bool needsSacrificialEvaluation = false; var hoistedFields = ArrayBuilder<StateMachineFieldSymbol>.GetInstance(); AwaitExpressionSyntax awaitSyntaxOpt; int syntaxOffset; if (F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug) { awaitSyntaxOpt = (AwaitExpressionSyntax)local.GetDeclaratorSyntax(); syntaxOffset = this.OriginalMethod.CalculateLocalSyntaxOffset(awaitSyntaxOpt.SpanStart, awaitSyntaxOpt.SyntaxTree); } else { // These are only used to calculate debug id for ref-spilled variables, // no need to do so in release build. awaitSyntaxOpt = null; syntaxOffset = -1; } var replacement = HoistExpression(right, awaitSyntaxOpt, syntaxOffset, true, sideEffects, hoistedFields, ref needsSacrificialEvaluation); proxies.Add(local, new CapturedToExpressionSymbolReplacement(replacement, hoistedFields.ToImmutableAndFree(), isReusable: true)); if (needsSacrificialEvaluation) { 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)); } if (sideEffects.Count == 0) { sideEffects.Free(); return null; } var last = sideEffects.Last(); sideEffects.RemoveLast(); return F.Sequence(ImmutableArray<LocalSymbol>.Empty, sideEffects.ToImmutableAndFree(), last); }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { if (node.Left.Kind != BoundKind.Local) { return base.VisitAssignmentOperator(node); } var left = (BoundLocal)node.Left; var local = left.LocalSymbol; if (!IsCaptured(local)) { return base.VisitAssignmentOperator(node); } if (proxies.ContainsKey(local)) { Debug.Assert(node.RefKind == RefKind.None); return base.VisitAssignmentOperator(node); } // user-declared variables are preassigned their proxies, and value temps // are assigned proxies at the beginning of their scope by the enclosing construct. // Here we handle ref temps. Ref temps are the target of a ref assignment operator before // being used in any other way. Debug.Assert( local.SynthesizedLocalKind == SynthesizedLocalKind.AwaitSpilledTemp || local.SynthesizedLocalKind != SynthesizedLocalKind.LambdaDisplayClass); Debug.Assert(node.RefKind != RefKind.None); // we have an assignment to a variable that has not yet been assigned a proxy. // So we assign the proxy before translating the assignment. return HoistRefInitialization(local, node); }
// Rewrite object initializer member assignment and add it to the result. // new SomeType { Member = 0 }; // ~~~~~~~~~~ private void AddObjectInitializer( ref ArrayBuilder<BoundExpression> dynamicSiteInitializers, ref ArrayBuilder<LocalSymbol> temps, ArrayBuilder<BoundExpression> result, BoundExpression rewrittenReceiver, BoundAssignmentOperator assignment) { Debug.Assert(rewrittenReceiver != null); Debug.Assert(!_inExpressionLambda); // Update the receiver for the field/property access as we might have introduced a temp for the initializer rewrite. BoundExpression rewrittenLeft = null; // Do not lower pointer access yet, we'll do it later. if (assignment.Left.Kind != BoundKind.PointerElementAccess) { rewrittenLeft = VisitExpression(assignment.Left); } BoundKind rhsKind = assignment.Right.Kind; bool isRhsNestedInitializer = rhsKind == BoundKind.ObjectInitializerExpression || rhsKind == BoundKind.CollectionInitializerExpression; BoundExpression rewrittenAccess; switch ((rewrittenLeft ?? assignment.Left).Kind) { case BoundKind.ObjectInitializerMember: { var memberInit = (BoundObjectInitializerMember)rewrittenLeft; if (!memberInit.Arguments.IsDefaultOrEmpty) { var args = EvaluateSideEffectingArgumentsToTemps(memberInit.Arguments, result, ref temps); memberInit = memberInit.Update( memberInit.MemberSymbol, args, memberInit.ArgumentNamesOpt, memberInit.ArgumentRefKindsOpt, memberInit.Expanded, memberInit.ArgsToParamsOpt, memberInit.ResultKind, memberInit.Type); } if (memberInit.MemberSymbol == null && memberInit.Type.IsDynamic()) { if (dynamicSiteInitializers == null) { dynamicSiteInitializers = ArrayBuilder<BoundExpression>.GetInstance(); } if (!isRhsNestedInitializer) { var rewrittenRight = VisitExpression(assignment.Right); var setMember = _dynamicFactory.MakeDynamicSetIndex( rewrittenReceiver, memberInit.Arguments, memberInit.ArgumentNamesOpt, memberInit.ArgumentRefKindsOpt, rewrittenRight); dynamicSiteInitializers.Add(setMember.SiteInitialization); result.Add(setMember.SiteInvocation); return; } var getMember = _dynamicFactory.MakeDynamicGetIndex( rewrittenReceiver, memberInit.Arguments, memberInit.ArgumentNamesOpt, memberInit.ArgumentRefKindsOpt); dynamicSiteInitializers.Add(getMember.SiteInitialization); rewrittenAccess = getMember.SiteInvocation; } else { rewrittenAccess = MakeObjectInitializerMemberAccess(rewrittenReceiver, memberInit, isRhsNestedInitializer); if (!isRhsNestedInitializer) { // Rewrite simple assignment to field/property. var rewrittenRight = VisitExpression(assignment.Right); result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, RefKind.None, assignment.Type, used: false)); return; } } break; } case BoundKind.DynamicObjectInitializerMember: { if (dynamicSiteInitializers == null) { dynamicSiteInitializers = ArrayBuilder<BoundExpression>.GetInstance(); } var initializerMember = (BoundDynamicObjectInitializerMember)rewrittenLeft; if (!isRhsNestedInitializer) { var rewrittenRight = VisitExpression(assignment.Right); var setMember = _dynamicFactory.MakeDynamicSetMember(rewrittenReceiver, initializerMember.MemberName, rewrittenRight); dynamicSiteInitializers.Add(setMember.SiteInitialization); result.Add(setMember.SiteInvocation); return; } var getMember = _dynamicFactory.MakeDynamicGetMember(rewrittenReceiver, initializerMember.MemberName, resultIndexed: false); dynamicSiteInitializers.Add(getMember.SiteInitialization); rewrittenAccess = getMember.SiteInvocation; break; } case BoundKind.ArrayAccess: { var arrayAccess = (BoundArrayAccess)rewrittenLeft; var indices = EvaluateSideEffectingArgumentsToTemps(arrayAccess.Indices, result, ref temps); rewrittenAccess = arrayAccess.Update(rewrittenReceiver, indices, arrayAccess.Type); if (!isRhsNestedInitializer) { // Rewrite simple assignment to field/property. var rewrittenRight = VisitExpression(assignment.Right); result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, RefKind.None, assignment.Type, used: false)); return; } break; } case BoundKind.PointerElementAccess: { // Remember we haven't lowered this node yet. var pointerAccess = (BoundPointerElementAccess)assignment.Left; var rewrittenIndex = VisitExpression(pointerAccess.Index); if (CanChangeValueBetweenReads(rewrittenIndex)) { BoundAssignmentOperator store; var temp = _factory.StoreToTemp(rewrittenIndex, out store); rewrittenIndex = temp; if (temps == null) { temps = ArrayBuilder<LocalSymbol>.GetInstance(); } temps.Add(temp.LocalSymbol); result.Add(store); } rewrittenAccess = RewritePointerElementAccess(pointerAccess, rewrittenReceiver, rewrittenIndex); if (!isRhsNestedInitializer) { // Rewrite as simple assignment. var rewrittenRight = VisitExpression(assignment.Right); result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, RefKind.None, assignment.Type, used: false)); return; } break; } default: throw ExceptionUtilities.UnexpectedValue((rewrittenLeft ?? assignment.Left).Kind); } AddObjectOrCollectionInitializers(ref dynamicSiteInitializers, ref temps, result, rewrittenAccess, assignment.Right); }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { CheckForAssignmentToSelf(node); if (_inExpressionLambda && node.Left.Kind != BoundKind.ObjectInitializerMember && node.Left.Kind != BoundKind.DynamicObjectInitializerMember) { Error(ErrorCode.ERR_ExpressionTreeContainsAssignment, node); } return base.VisitAssignmentOperator(node); }
private bool CheckForAssignmentToSelf(BoundAssignmentOperator node) { if (!node.HasAnyErrors && IsSameLocalOrField(node.Left, node.Right)) { Error(ErrorCode.WRN_AssignmentToSelf, node); return true; } return false; }
/// <summary> /// Generates a submission initialization part of a Script type constructor that represents an interactive submission. /// </summary> /// <remarks> /// The constructor takes a parameter of type Roslyn.Scripting.Session - the session reference. /// It adds the object being constructed into the session by calling Microsoft.CSharp.RuntimeHelpers.SessionHelpers.SetSubmission, /// and retrieves strongly typed references on all previous submission script classes whose members are referenced by this submission. /// The references are stored to fields of the submission (<paramref name="synthesizedFields"/>). /// </remarks> private static ImmutableArray <BoundStatement> MakeSubmissionInitialization(CSharpSyntaxNode syntax, MethodSymbol submissionConstructor, SynthesizedSubmissionFields synthesizedFields, CSharpCompilation compilation) { Debug.Assert(submissionConstructor.ParameterCount == 2); BoundStatement[] result = new BoundStatement[1 + synthesizedFields.Count]; var sessionReference = new BoundParameter(syntax, submissionConstructor.Parameters[0]) { WasCompilerGenerated = true }; var submissionGetter = (MethodSymbol)compilation.GetWellKnownTypeMember( WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__GetSubmission ); var submissionAdder = (MethodSymbol)compilation.GetWellKnownTypeMember( WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__SetSubmission ); // TODO: report missing adder/getter Debug.Assert((object)submissionAdder != null && (object)submissionGetter != null); var intType = compilation.GetSpecialType(SpecialType.System_Int32); var thisReference = new BoundThisReference(syntax, submissionConstructor.ContainingType) { WasCompilerGenerated = true }; int i = 0; // hostObject = (THostObject)SessionHelpers.SetSubmission(<session>, <slot index>, this); var slotIndex = compilation.GetSubmissionSlotIndex(); Debug.Assert(slotIndex >= 0); BoundExpression setSubmission = BoundCall.Synthesized(syntax, null, submissionAdder, sessionReference, new BoundLiteral(syntax, ConstantValue.Create(slotIndex), intType) { WasCompilerGenerated = true }, thisReference ); var hostObjectField = synthesizedFields.GetHostObjectField(); if ((object)hostObjectField != null) { setSubmission = new BoundAssignmentOperator(syntax, new BoundFieldAccess(syntax, thisReference, hostObjectField, ConstantValue.NotAvailable) { WasCompilerGenerated = true }, BoundConversion.Synthesized(syntax, setSubmission, Conversion.ExplicitReference, false, true, ConstantValue.NotAvailable, hostObjectField.Type ), hostObjectField.Type ) { WasCompilerGenerated = true }; } result[i++] = new BoundExpressionStatement(syntax, setSubmission) { WasCompilerGenerated = true }; foreach (var field in synthesizedFields.FieldSymbols) { var targetScriptClass = (ImplicitNamedTypeSymbol)field.Type; var targetSubmissionId = targetScriptClass.DeclaringCompilation.GetSubmissionSlotIndex(); Debug.Assert(targetSubmissionId >= 0); // this.<field> = (<FieldType>)SessionHelpers.GetSubmission(<session>, <i>); result[i++] = new BoundExpressionStatement(syntax, new BoundAssignmentOperator(syntax, new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true }, BoundConversion.Synthesized(syntax, BoundCall.Synthesized(syntax, null, submissionGetter, sessionReference, new BoundLiteral(syntax, ConstantValue.Create(targetSubmissionId), intType) { WasCompilerGenerated = true }), Conversion.ExplicitReference, false, true, ConstantValue.NotAvailable, targetScriptClass ), targetScriptClass ) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; } Debug.Assert(i == result.Length); return(result.AsImmutableOrNull()); }
// Rewrite object initializer member assignment and add it to the result. // new SomeType { Member = 0 }; // ~~~~~~~~~~ private void AddObjectInitializer(ref ArrayBuilder<BoundExpression> dynamicSiteInitializers, ArrayBuilder<BoundExpression> result, BoundExpression rewrittenReceiver, BoundAssignmentOperator assignment) { Debug.Assert(rewrittenReceiver != null); Debug.Assert(!inExpressionLambda); // Update the receiver for the field/property access as we might have introduced a temp for the initializer rewrite. BoundExpression rewrittenLeft = VisitExpression(assignment.Left); BoundKind rhsKind = assignment.Right.Kind; bool isRhsNestedInitializer = rhsKind == BoundKind.ObjectInitializerExpression || rhsKind == BoundKind.CollectionInitializerExpression; BoundExpression rewrittenAccess; if (rewrittenLeft.Kind == BoundKind.ObjectInitializerMember) { var memberInit = (BoundObjectInitializerMember)rewrittenLeft; if (memberInit.MemberSymbol == null && memberInit.Type.IsDynamic()) { if (dynamicSiteInitializers == null) { dynamicSiteInitializers = ArrayBuilder<BoundExpression>.GetInstance(); } if (!isRhsNestedInitializer) { var rewrittenRight = VisitExpression(assignment.Right); var setMember = dynamicFactory.MakeDynamicSetIndex( rewrittenReceiver, memberInit.Arguments, default(ImmutableArray<string>), default(ImmutableArray<RefKind>), rewrittenRight); dynamicSiteInitializers.Add(setMember.SiteInitialization); result.Add(setMember.SiteInvocation); return; } var getMember = dynamicFactory.MakeDynamicGetIndex( rewrittenReceiver, memberInit.Arguments, default(ImmutableArray<string>), default(ImmutableArray<RefKind>)); dynamicSiteInitializers.Add(getMember.SiteInitialization); rewrittenAccess = getMember.SiteInvocation; } else { rewrittenAccess = MakeObjectInitializerMemberAccess(rewrittenReceiver, memberInit, isRhsNestedInitializer); if (!isRhsNestedInitializer) { // Rewrite simple assignment to field/property. var rewrittenRight = VisitExpression(assignment.Right); result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, assignment.Type, used: false)); return; } } } else { if (dynamicSiteInitializers == null) { dynamicSiteInitializers = ArrayBuilder<BoundExpression>.GetInstance(); } Debug.Assert(rewrittenLeft.Kind == BoundKind.DynamicObjectInitializerMember); var initializerMember = (BoundDynamicObjectInitializerMember)rewrittenLeft; if (!isRhsNestedInitializer) { var rewrittenRight = VisitExpression(assignment.Right); var setMember = dynamicFactory.MakeDynamicSetMember(rewrittenReceiver, initializerMember.MemberName, rewrittenRight); dynamicSiteInitializers.Add(setMember.SiteInitialization); result.Add(setMember.SiteInvocation); return; } var getMember = dynamicFactory.MakeDynamicGetMember(rewrittenReceiver, initializerMember.MemberName, resultIndexed: false); dynamicSiteInitializers.Add(getMember.SiteInitialization); rewrittenAccess = getMember.SiteInvocation; } AddObjectOrCollectionInitializers(ref dynamicSiteInitializers, result, rewrittenAccess, assignment.Right); }
private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bool used) { var loweredRight = VisitExpression(node.Right); BoundExpression left = node.Left; BoundExpression loweredLeft; switch (left.Kind) { case BoundKind.PropertyAccess: loweredLeft = VisitPropertyAccess((BoundPropertyAccess)left, isLeftOfAssignment: true); break; case BoundKind.IndexerAccess: loweredLeft = VisitIndexerAccess((BoundIndexerAccess)left, isLeftOfAssignment: true); break; case BoundKind.EventAccess: { BoundEventAccess eventAccess = (BoundEventAccess)left; if (eventAccess.EventSymbol.IsWindowsRuntimeEvent) { Debug.Assert(!node.IsRef); return(VisitWindowsRuntimeEventFieldAssignmentOperator(node.Syntax, eventAccess, loweredRight)); } goto default; } case BoundKind.DynamicMemberAccess: { // dyn.m = expr var memberAccess = (BoundDynamicMemberAccess)left; var loweredReceiver = VisitExpression(memberAccess.Receiver); #if XSHARP if (_compilation.Options.LateBindingOrFox(node.Syntax) && !loweredReceiver.HasDynamicType()) { var expr = MakeVODynamicSetMember(loweredReceiver, memberAccess.Name, loweredRight); if (expr != null) { return(expr); } } #endif return(_dynamicFactory.MakeDynamicSetMember(loweredReceiver, memberAccess.Name, loweredRight).ToExpression()); } case BoundKind.DynamicIndexerAccess: { // dyn[args] = expr var indexerAccess = (BoundDynamicIndexerAccess)left; Debug.Assert(indexerAccess.ReceiverOpt != null); var loweredReceiver = VisitExpression(indexerAccess.ReceiverOpt); var loweredArguments = VisitList(indexerAccess.Arguments); return(MakeDynamicSetIndex( indexerAccess, loweredReceiver, loweredArguments, indexerAccess.ArgumentNamesOpt, indexerAccess.ArgumentRefKindsOpt, loweredRight)); } default: loweredLeft = VisitExpression(left); break; } return(MakeStaticAssignmentOperator(node.Syntax, loweredLeft, loweredRight, node.IsRef, node.Type, used)); }
// Rewrite object initializer member assignment and add it to the result. // new SomeType { Member = 0 }; // ~~~~~~~~~~ private void AddObjectInitializer( ref ArrayBuilder <BoundExpression> dynamicSiteInitializers, ref ArrayBuilder <LocalSymbol> temps, ArrayBuilder <BoundExpression> result, BoundExpression rewrittenReceiver, BoundAssignmentOperator assignment) { Debug.Assert(rewrittenReceiver != null); Debug.Assert(!_inExpressionLambda); // Update the receiver for the field/property access as we might have introduced a temp for the initializer rewrite. BoundExpression rewrittenLeft = null; // Do not lower pointer access yet, we'll do it later. if (assignment.Left.Kind != BoundKind.PointerElementAccess) { rewrittenLeft = VisitExpression(assignment.Left); } BoundKind rhsKind = assignment.Right.Kind; bool isRhsNestedInitializer = rhsKind == BoundKind.ObjectInitializerExpression || rhsKind == BoundKind.CollectionInitializerExpression; BoundExpression rewrittenAccess; switch ((rewrittenLeft ?? assignment.Left).Kind) { case BoundKind.ObjectInitializerMember: { var memberInit = (BoundObjectInitializerMember)rewrittenLeft; if (!memberInit.Arguments.IsDefaultOrEmpty) { var args = EvaluateSideEffectingArgumentsToTemps(memberInit.Arguments, result, ref temps); memberInit = memberInit.Update( memberInit.MemberSymbol, args, memberInit.ArgumentNamesOpt, memberInit.ArgumentRefKindsOpt, memberInit.Expanded, memberInit.ArgsToParamsOpt, memberInit.ResultKind, memberInit.ReceiverType, memberInit.BinderOpt, memberInit.Type); } if (memberInit.MemberSymbol == null && memberInit.Type.IsDynamic()) { if (dynamicSiteInitializers == null) { dynamicSiteInitializers = ArrayBuilder <BoundExpression> .GetInstance(); } if (!isRhsNestedInitializer) { var rewrittenRight = VisitExpression(assignment.Right); var setMember = _dynamicFactory.MakeDynamicSetIndex( rewrittenReceiver, memberInit.Arguments, memberInit.ArgumentNamesOpt, memberInit.ArgumentRefKindsOpt, rewrittenRight); dynamicSiteInitializers.Add(setMember.SiteInitialization); result.Add(setMember.SiteInvocation); return; } var getMember = _dynamicFactory.MakeDynamicGetIndex( rewrittenReceiver, memberInit.Arguments, memberInit.ArgumentNamesOpt, memberInit.ArgumentRefKindsOpt); dynamicSiteInitializers.Add(getMember.SiteInitialization); rewrittenAccess = getMember.SiteInvocation; } else { rewrittenAccess = MakeObjectInitializerMemberAccess(rewrittenReceiver, memberInit, isRhsNestedInitializer); if (!isRhsNestedInitializer) { // Rewrite simple assignment to field/property. var rewrittenRight = VisitExpression(assignment.Right); result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, false, assignment.Type, used: false)); return; } } break; } case BoundKind.DynamicObjectInitializerMember: { if (dynamicSiteInitializers == null) { dynamicSiteInitializers = ArrayBuilder <BoundExpression> .GetInstance(); } var initializerMember = (BoundDynamicObjectInitializerMember)rewrittenLeft; if (!isRhsNestedInitializer) { var rewrittenRight = VisitExpression(assignment.Right); var setMember = _dynamicFactory.MakeDynamicSetMember(rewrittenReceiver, initializerMember.MemberName, rewrittenRight); dynamicSiteInitializers.Add(setMember.SiteInitialization); result.Add(setMember.SiteInvocation); return; } var getMember = _dynamicFactory.MakeDynamicGetMember(rewrittenReceiver, initializerMember.MemberName, resultIndexed: false); dynamicSiteInitializers.Add(getMember.SiteInitialization); rewrittenAccess = getMember.SiteInvocation; break; } case BoundKind.ArrayAccess: { var arrayAccess = (BoundArrayAccess)rewrittenLeft; var indices = EvaluateSideEffectingArgumentsToTemps(arrayAccess.Indices, result, ref temps); rewrittenAccess = arrayAccess.Update(rewrittenReceiver, indices, arrayAccess.Type); if (!isRhsNestedInitializer) { // Rewrite simple assignment to field/property. var rewrittenRight = VisitExpression(assignment.Right); result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, false, assignment.Type, used: false)); return; } break; } case BoundKind.PointerElementAccess: { // Remember we haven't lowered this node yet. var pointerAccess = (BoundPointerElementAccess)assignment.Left; var rewrittenIndex = VisitExpression(pointerAccess.Index); if (CanChangeValueBetweenReads(rewrittenIndex)) { BoundAssignmentOperator store; var temp = _factory.StoreToTemp(rewrittenIndex, out store); rewrittenIndex = temp; if (temps == null) { temps = ArrayBuilder <LocalSymbol> .GetInstance(); } temps.Add(temp.LocalSymbol); result.Add(store); } rewrittenAccess = RewritePointerElementAccess(pointerAccess, rewrittenReceiver, rewrittenIndex); if (!isRhsNestedInitializer) { // Rewrite as simple assignment. var rewrittenRight = VisitExpression(assignment.Right); result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, false, assignment.Type, used: false)); return; } break; } default: throw ExceptionUtilities.UnexpectedValue((rewrittenLeft ?? assignment.Left).Kind); } AddObjectOrCollectionInitializers(ref dynamicSiteInitializers, ref temps, result, rewrittenAccess, assignment.Right); }
/// <summary> /// Takes an expression and returns the bound local expression "temp" /// and the bound assignment expression "temp = expr". /// </summary> public BoundLocal StoreToTemp(BoundExpression argument, out BoundAssignmentOperator store, RefKind refKind = RefKind.None, SynthesizedLocalKind kind = SynthesizedLocalKind.LoweringTemp) { MethodSymbol containingMethod = this.CurrentMethod; var syntax = argument.Syntax; var type = argument.Type; var local = new BoundLocal( syntax, new SynthesizedLocal(containingMethod, type, kind, syntax: kind.IsLongLived() ? syntax : null, refKind: refKind), null, type); store = new BoundAssignmentOperator( syntax, local, argument, refKind, type); return local; }
/// <summary> /// Generates a submission initialization part of a Script type constructor that represents an interactive submission. /// </summary> /// <remarks> /// The constructor takes a parameter of type Roslyn.Scripting.Session - the session reference. /// It adds the object being constructed into the session by calling Microsoft.CSharp.RuntimeHelpers.SessionHelpers.SetSubmission, /// and retrieves strongly typed references on all previous submission script classes whose members are referenced by this submission. /// The references are stored to fields of the submission (<paramref name="synthesizedFields"/>). /// </remarks> private static ImmutableArray<BoundStatement> MakeSubmissionInitialization(CSharpSyntaxNode syntax, MethodSymbol submissionConstructor, SynthesizedSubmissionFields synthesizedFields, CSharpCompilation compilation) { Debug.Assert(submissionConstructor.ParameterCount == 2); BoundStatement[] result = new BoundStatement[1 + synthesizedFields.Count]; var sessionReference = new BoundParameter(syntax, submissionConstructor.Parameters[0]) { WasCompilerGenerated = true }; var submissionGetter = (MethodSymbol)compilation.GetWellKnownTypeMember( WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__GetSubmission ); var submissionAdder = (MethodSymbol)compilation.GetWellKnownTypeMember( WellKnownMember.Microsoft_CSharp_RuntimeHelpers_SessionHelpers__SetSubmission ); // TODO: report missing adder/getter Debug.Assert((object)submissionAdder != null && (object)submissionGetter != null); var intType = compilation.GetSpecialType(SpecialType.System_Int32); var thisReference = new BoundThisReference(syntax, submissionConstructor.ContainingType) { WasCompilerGenerated = true }; int i = 0; // hostObject = (THostObject)SessionHelpers.SetSubmission(<session>, <slot index>, this); var slotIndex = compilation.GetSubmissionSlotIndex(); Debug.Assert(slotIndex >= 0); BoundExpression setSubmission = BoundCall.Synthesized(syntax, null, submissionAdder, sessionReference, new BoundLiteral(syntax, ConstantValue.Create(slotIndex), intType) { WasCompilerGenerated = true }, thisReference ); var hostObjectField = synthesizedFields.GetHostObjectField(); if ((object)hostObjectField != null) { setSubmission = new BoundAssignmentOperator(syntax, new BoundFieldAccess(syntax, thisReference, hostObjectField, ConstantValue.NotAvailable) { WasCompilerGenerated = true }, BoundConversion.Synthesized(syntax, setSubmission, Conversion.ExplicitReference, false, true, ConstantValue.NotAvailable, hostObjectField.Type ), hostObjectField.Type ) { WasCompilerGenerated = true }; } result[i++] = new BoundExpressionStatement(syntax, setSubmission) { WasCompilerGenerated = true }; foreach (var field in synthesizedFields.FieldSymbols) { var targetScriptClass = (ImplicitNamedTypeSymbol)field.Type; var targetSubmissionId = targetScriptClass.DeclaringCompilation.GetSubmissionSlotIndex(); Debug.Assert(targetSubmissionId >= 0); // this.<field> = (<FieldType>)SessionHelpers.GetSubmission(<session>, <i>); result[i++] = new BoundExpressionStatement(syntax, new BoundAssignmentOperator(syntax, new BoundFieldAccess(syntax, thisReference, field, ConstantValue.NotAvailable) { WasCompilerGenerated = true }, BoundConversion.Synthesized(syntax, BoundCall.Synthesized(syntax, null, submissionGetter, sessionReference, new BoundLiteral(syntax, ConstantValue.Create(targetSubmissionId), intType) { WasCompilerGenerated = true }), Conversion.ExplicitReference, false, true, ConstantValue.NotAvailable, targetScriptClass ), targetScriptClass ) { WasCompilerGenerated = true }) { WasCompilerGenerated = true }; } Debug.Assert(i == result.Length); return result.AsImmutableOrNull(); }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { if (node.Left.Kind != BoundKind.Local) return (BoundExpression)base.VisitAssignmentOperator(node); var left = (BoundLocal)node.Left; var local = left.LocalSymbol; if (!variablesCaptured.Contains(local)) return (BoundExpression)base.VisitAssignmentOperator(node); if (proxies.ContainsKey(local)) { Debug.Assert(node.RefKind == RefKind.None); return (BoundExpression)base.VisitAssignmentOperator(node); } // user-declared variables are preassigned their proxies, and value temps // are assigned proxies at the beginning of their scope by the enclosing construct. // Here we handle ref temps. Ref temps are the target of a ref assignment operator before // being used in any other way. Debug.Assert(local.DeclarationKind == LocalDeclarationKind.CompilerGenerated); Debug.Assert(node.RefKind != RefKind.None); // we have an assignment to a variable that has not yet been assigned a proxy. // So we assign the proxy before translating the assignment. return HoistRefInitialization(local, node); }
/// <summary> /// Takes an expression and returns the bound local expression "temp" /// and the bound assignment expression "temp = expr". /// </summary> public BoundLocal StoreToTemp( BoundExpression argument, out BoundAssignmentOperator store, RefKind refKind = RefKind.None, SynthesizedLocalKind kind = SynthesizedLocalKind.LoweringTemp, CSharpSyntaxNode syntaxOpt = null #if DEBUG , [CallerLineNumber]int callerLineNumber = 0 , [CallerFilePath]string callerFilePath = null #endif ) { MethodSymbol containingMethod = this.CurrentMethod; var syntax = argument.Syntax; var type = argument.Type; var local = new BoundLocal( syntax, new SynthesizedLocal( containingMethod, type, kind, #if DEBUG createdAtLineNumber: callerLineNumber, createdAtFilePath: callerFilePath, #endif syntaxOpt: syntaxOpt ?? (kind.IsLongLived() ? syntax : null), isPinned: false, refKind: refKind), null, type); store = new BoundAssignmentOperator( syntax, local, argument, refKind, type); return local; }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { BoundSpillSequence2 ss = null; var right = VisitExpression(ref ss, node.Right); BoundExpression left; if (ss == null || node.Left.Kind == BoundKind.Local) { left = VisitExpression(ref ss, node.Left); } else { // if the right-hand-side has await, spill the left var ss2 = new BoundSpillSequence2(); left = VisitExpression(ref ss2, node.Left); if (left.Kind != BoundKind.Local) left = Spill(ss2, left, RefKind.Ref); ss2.IncludeSequence(ss); ss = ss2; } return UpdateExpression(ss, node.Update(left, right, node.RefKind, node.Type)); }
public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node) { if (node.Left.Kind == BoundKind.Local && node.RefKind != RefKind.None) { var localSymbol = ((BoundLocal)node.Left).LocalSymbol; Debug.Assert(localSymbol.RefKind != RefKind.None); refLocalInitializers.Add(localSymbol, node.Right); } return base.VisitAssignmentOperator(node); }
private BoundExpression MakePropertyAssignment( CSharpSyntaxNode syntax, BoundExpression rewrittenReceiver, PropertySymbol property, ImmutableArray <BoundExpression> rewrittenArguments, ImmutableArray <RefKind> argumentRefKindsOpt, bool expanded, ImmutableArray <int> argsToParamsOpt, BoundExpression rewrittenRight, TypeSymbol type, bool used) { // Rewrite property assignment into call to setter. var setMethod = property.GetOwnOrInheritedSetMethod(); if ((object)setMethod == null) { Debug.Assert((property as SourcePropertySymbol)?.IsAutoProperty == true, "only autoproperties can be assignable without having setters"); var backingField = (property as SourcePropertySymbol).BackingField; return(factory.AssignmentExpression( factory.Field(rewrittenReceiver, backingField), rewrittenRight)); } // We have already lowered each argument, but we may need some additional rewriting for the arguments, // such as generating a params array, re-ordering arguments based on argsToParamsOpt map, inserting arguments for optional parameters, etc. ImmutableArray <LocalSymbol> argTemps; rewrittenArguments = MakeArguments(syntax, rewrittenArguments, property, setMethod, expanded, argsToParamsOpt, ref argumentRefKindsOpt, out argTemps, enableCallerInfo: ThreeState.True); if (used) { // Save expression value to a temporary before calling the // setter, and restore the temporary after the setter, so the // assignment can be used as an embedded expression. TypeSymbol exprType = rewrittenRight.Type; LocalSymbol rhsTemp = factory.SynthesizedLocal(exprType); BoundExpression boundRhs = new BoundLocal(syntax, rhsTemp, null, exprType); BoundExpression rhsAssignment = new BoundAssignmentOperator( syntax, boundRhs, rewrittenRight, exprType); BoundExpression setterCall = BoundCall.Synthesized( syntax, rewrittenReceiver, setMethod, AppendToPossibleNull(rewrittenArguments, rhsAssignment)); return(new BoundSequence( syntax, AppendToPossibleNull(argTemps, rhsTemp), ImmutableArray.Create(setterCall), boundRhs, type)); } else { BoundCall setterCall = BoundCall.Synthesized( syntax, rewrittenReceiver, setMethod, AppendToPossibleNull(rewrittenArguments, rewrittenRight)); if (argTemps.IsDefaultOrEmpty) { return(setterCall); } else { return(new BoundSequence( syntax, argTemps, ImmutableArray <BoundExpression> .Empty, setterCall, setMethod.ReturnType)); } } }
// Rewrite object initializer member assignment and add it to the result. // new SomeType { Member = 0 }; // ~~~~~~~~~~ private void AddObjectInitializer(ref ArrayBuilder <BoundExpression> dynamicSiteInitializers, ArrayBuilder <BoundExpression> result, BoundExpression rewrittenReceiver, BoundAssignmentOperator assignment) { Debug.Assert(rewrittenReceiver != null); Debug.Assert(!inExpressionLambda); // Update the receiver for the field/property access as we might have introduced a temp for the initializer rewrite. BoundExpression rewrittenLeft = VisitExpression(assignment.Left); BoundKind rhsKind = assignment.Right.Kind; bool isRhsNestedInitializer = rhsKind == BoundKind.ObjectInitializerExpression || rhsKind == BoundKind.CollectionInitializerExpression; BoundExpression rewrittenAccess; if (rewrittenLeft.Kind == BoundKind.ObjectInitializerMember) { rewrittenAccess = MakeObjectInitializerMemberAccess(rewrittenReceiver, (BoundObjectInitializerMember)rewrittenLeft, isRhsNestedInitializer); if (!isRhsNestedInitializer) { // Rewrite simple assignment to field/property. var rewrittenRight = VisitExpression(assignment.Right); result.Add(MakeStaticAssignmentOperator(assignment.Syntax, rewrittenAccess, rewrittenRight, assignment.Type, used: false)); return; } } else { if (dynamicSiteInitializers == null) { dynamicSiteInitializers = ArrayBuilder <BoundExpression> .GetInstance(); } Debug.Assert(rewrittenLeft.Kind == BoundKind.DynamicObjectInitializerMember); var initializerMember = (BoundDynamicObjectInitializerMember)rewrittenLeft; if (!isRhsNestedInitializer) { var rewrittenRight = VisitExpression(assignment.Right); var setMember = dynamicFactory.MakeDynamicSetMember(rewrittenReceiver, initializerMember.MemberName, rewrittenRight); dynamicSiteInitializers.Add(setMember.SiteInitialization); result.Add(setMember.SiteInvocation); return; } var getMember = dynamicFactory.MakeDynamicGetMember(rewrittenReceiver, initializerMember.MemberName, resultIndexed: false); dynamicSiteInitializers.Add(getMember.SiteInitialization); rewrittenAccess = getMember.SiteInvocation; } AddObjectOrCollectionInitializers(ref dynamicSiteInitializers, result, rewrittenAccess, assignment.Right); }
private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bool used) { var loweredRight = VisitExpression(node.Right); BoundExpression left = node.Left; BoundExpression loweredLeft; switch (left.Kind) { case BoundKind.PropertyAccess: loweredLeft = VisitPropertyAccess((BoundPropertyAccess)left, isLeftOfAssignment: true); break; case BoundKind.IndexerAccess: loweredLeft = VisitIndexerAccess((BoundIndexerAccess)left, isLeftOfAssignment: true); break; case BoundKind.ImplicitIndexerAccess: loweredLeft = VisitImplicitIndexerAccess( (BoundImplicitIndexerAccess)left, isLeftOfAssignment: true); break; case BoundKind.EventAccess: { BoundEventAccess eventAccess = (BoundEventAccess)left; if (eventAccess.EventSymbol.IsWindowsRuntimeEvent) { Debug.Assert(!node.IsRef); return(VisitWindowsRuntimeEventFieldAssignmentOperator(node.Syntax, eventAccess, loweredRight)); } goto default; } case BoundKind.DynamicMemberAccess: { // dyn.m = expr var memberAccess = (BoundDynamicMemberAccess)left; var loweredReceiver = VisitExpression(memberAccess.Receiver); return(_dynamicFactory.MakeDynamicSetMember(loweredReceiver, memberAccess.Name, loweredRight).ToExpression()); } case BoundKind.DynamicIndexerAccess: { // dyn[args] = expr var indexerAccess = (BoundDynamicIndexerAccess)left; var loweredReceiver = VisitExpression(indexerAccess.Receiver); // Dynamic can't have created handler conversions because we don't know target types. AssertNoImplicitInterpolatedStringHandlerConversions(indexerAccess.Arguments); var loweredArguments = VisitList(indexerAccess.Arguments); return(MakeDynamicSetIndex( indexerAccess, loweredReceiver, loweredArguments, indexerAccess.ArgumentNamesOpt, indexerAccess.ArgumentRefKindsOpt, loweredRight)); } default: loweredLeft = VisitExpression(left); break; } return(MakeStaticAssignmentOperator(node.Syntax, loweredLeft, loweredRight, node.IsRef, node.Type, used)); }
/// <summary> /// Introduce a frame around the translation of the given node. /// </summary> /// <param name="node">The node whose translation should be translated to contain a frame</param> /// <param name="frame">The frame for the translated node</param> /// <param name="F">A function that computes the translation of the node. It receives lists of added statements and added symbols</param> /// <returns>The translated statement, as returned from F</returns> private T IntroduceFrame <T>(BoundNode node, LambdaFrame frame, Func <ArrayBuilder <BoundExpression>, ArrayBuilder <LocalSymbol>, T> F) { NamedTypeSymbol frameType = frame.ConstructIfGeneric(StaticCast <TypeSymbol> .From(currentTypeParameters)); LocalSymbol framePointer = new LambdaFrameLocalSymbol(this.topLevelMethod, frameType, CompilationState); CSharpSyntaxNode syntax = node.Syntax; // assign new frame to the frame variable CompilationState.AddSynthesizedMethod(frame.Constructor, FlowAnalysisPass.AppendImplicitReturn(MethodCompiler.BindMethodBody(frame.Constructor, CompilationState, null), frame.Constructor)); var prologue = ArrayBuilder <BoundExpression> .GetInstance(); MethodSymbol constructor = frame.Constructor.AsMember(frameType); Debug.Assert(frameType == constructor.ContainingType); var newFrame = new BoundObjectCreationExpression( syntax: syntax, constructor: constructor); prologue.Add(new BoundAssignmentOperator(syntax, new BoundLocal(syntax, framePointer, null, frameType), newFrame, frameType)); CapturedSymbolReplacement oldInnermostFrameProxy = null; if ((object)innermostFramePointer != null) { proxies.TryGetValue(innermostFramePointer, out oldInnermostFrameProxy); if (analysis.needsParentFrame.Contains(node)) { var capturedFrame = new LambdaCapturedVariable(frame, innermostFramePointer); FieldSymbol frameParent = capturedFrame.AsMember(frameType); BoundExpression left = new BoundFieldAccess(syntax, new BoundLocal(syntax, framePointer, null, frameType), frameParent, null); BoundExpression right = FrameOfType(syntax, frameParent.Type as NamedTypeSymbol); BoundExpression assignment = new BoundAssignmentOperator(syntax, left, right, left.Type); if (this.currentMethod.MethodKind == MethodKind.Constructor && capturedFrame.Type == this.currentMethod.ContainingType && !this.seenBaseCall) { // Containing method is a constructor // Initialization statement for the "this" proxy must be inserted // after the constructor initializer statement block // This insertion will be done by the delegate F Debug.Assert(thisProxyInitDeferred == null); thisProxyInitDeferred = assignment; } else { prologue.Add(assignment); } if (CompilationState.Emitting) { CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(frame, capturedFrame); } proxies[innermostFramePointer] = new CapturedToFrameSymbolReplacement(capturedFrame); } } // Capture any parameters of this block. This would typically occur // at the top level of a method or lambda with captured parameters. // TODO: speed up the following by computing it in analysis. foreach (var v in analysis.variablesCaptured) { BoundNode varNode; if (!analysis.variableBlock.TryGetValue(v, out varNode) || varNode != node || analysis.declaredInsideExpressionLambda.Contains(v)) { continue; } InitVariableProxy(syntax, v, framePointer, prologue); } Symbol oldInnermostFramePointer = innermostFramePointer; innermostFramePointer = framePointer; var addedLocals = ArrayBuilder <LocalSymbol> .GetInstance(); addedLocals.Add(framePointer); framePointers.Add(frame, framePointer); var result = F(prologue, addedLocals); framePointers.Remove(frame); innermostFramePointer = oldInnermostFramePointer; if ((object)innermostFramePointer != null) { if (oldInnermostFrameProxy != null) { proxies[innermostFramePointer] = oldInnermostFrameProxy; } else { proxies.Remove(innermostFramePointer); } } return(result); }