예제 #1
0
        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));
                }
            }
        }