private Expression Spill( BoundSpillSequenceBuilder builder, Expression expression, bool isRef = false, bool sideEffectsOnly = false) { Debug.Assert(builder != null); while (true) { switch (expression.NodeType) { case NodeType.ListLiteralExpression: case NodeType.ArrayLiteralExpression: Debug.Assert(!isRef); Debug.Assert(!sideEffectsOnly); var arrayInitialization = (ListLiteralExpression)expression; var newInitializers = VisitExpressionList(ref builder, arrayInitialization.Items, forceSpill: true); arrayInitialization.Items = newInitializers; return(arrayInitialization); case NodeType.HashLiteralExpression: Debug.Assert(!isRef); Debug.Assert(!sideEffectsOnly); var hashInitialization = (HashLiteralExpression)expression; var newInitializerPairs = VisitExpressionPairList(ref builder, hashInitialization.Items, forceSpill: true); hashInitialization.Items = newInitializerPairs; return(hashInitialization); case SpillSequenceBuilder: var sequenceBuilder = (BoundSpillSequenceBuilder)expression; builder.Include(sequenceBuilder); expression = sequenceBuilder.Value; continue; case NodeType.SelfLiteralExpression: case NodeType.SuperLiteralExpression: if (isRef || !expression.ExpressionType.IsValueType) { return(expression); } goto default; case NodeType.ParameterDeclaration: if (isRef) { return(expression); } goto default; case NodeType.ReferenceExpression: var local = expression.Entity as InternalLocal; if (local != null) { if (local.Local["SynthesizedKind"] == AWAIT_SPILL_MARKER || isRef) { return(expression); } } goto default; case NodeType.MemberReferenceExpression: if (expression.Entity.EntityType == EntityType.Field) { var field = (IField)expression.Entity; if (field.IsInitOnly) { if (field.IsStatic) { return(expression); } if (!field.DeclaringType.IsValueType) { // save the receiver; can get the field later. var target = Spill(builder, ((MemberReferenceExpression)expression).Target, isRef && !field.Type.IsValueType, sideEffectsOnly); return(_F.CreateMemberReference(target, field)); } } } goto default; case NodeType.MethodInvocationExpression: var mie = (MethodInvocationExpression)expression; if (expression.Entity == BuiltinFunction.Eval) { builder.AddExpressions(mie.Arguments.Where(a => a != mie.Arguments.Last)); expression = mie.Arguments.Last; continue; } if (isRef) { Debug.Assert(mie.ExpressionType.IsPointer); CompilerContext.Current.Errors.Add(CompilerErrorFactory.UnsafeReturnInAsync(mie)); } goto default; case NodeType.BoolLiteralExpression: case NodeType.CharLiteralExpression: case NodeType.DoubleLiteralExpression: case NodeType.IntegerLiteralExpression: case NodeType.NullLiteralExpression: case NodeType.RELiteralExpression: case NodeType.StringLiteralExpression: case NodeType.TypeofExpression: return(expression); default: if (expression.ExpressionType == _tss.VoidType || sideEffectsOnly) { builder.AddStatement(new ExpressionStatement(expression)); return(null); } var replacement = _F.DeclareTempLocal(_currentMethod, expression.ExpressionType); var assignToTemp = _F.CreateAssignment( _F.CreateLocalReference(replacement), expression); builder.AddLocal(replacement); builder.AddStatement(new ExpressionStatement(assignToTemp)); return(_F.CreateLocalReference(replacement)); } } }