示例#1
0
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            BoundSpillSequenceBuilder builder = null;
            var             right             = VisitExpression(ref builder, node.RightOperand);
            BoundExpression left;

            if (builder == null)
            {
                left = VisitExpression(ref builder, node.LeftOperand);
            }
            else
            {
                var leftBuilder = new BoundSpillSequenceBuilder();
                left = VisitExpression(ref leftBuilder, node.LeftOperand);
                left = Spill(leftBuilder, left);

                var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.Spill, syntax: _F.Syntax);
                leftBuilder.AddLocal(tmp);
                leftBuilder.AddStatement(_F.Assignment(_F.Local(tmp), left));
                leftBuilder.AddStatement(_F.If(
                                             _F.ObjectEqual(_F.Local(tmp), _F.Null(left.Type)),
                                             UpdateStatement(builder, _F.Assignment(_F.Local(tmp), right))));

                return(UpdateExpression(leftBuilder, _F.Local(tmp)));
            }

            return(UpdateExpression(builder, node.Update(left, right, node.LeftConversion, node.OperatorResultKind, node.Type)));
        }
示例#2
0
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            BoundSpillSequenceBuilder builder = null;
            var             right             = VisitExpression(ref builder, node.RightOperand);
            BoundExpression left;

            if (builder == null)
            {
                left = VisitExpression(ref builder, node.LeftOperand);
            }
            else
            {
                var leftBuilder = new BoundSpillSequenceBuilder();
                left = VisitExpression(ref leftBuilder, node.LeftOperand);
                left = Spill(leftBuilder, left);

                leftBuilder.AddStatement(_F.If(
                                             _F.ObjectEqual(left, _F.Null(left.Type)),
                                             UpdateStatement(builder, _F.Assignment(left, right), substituteTemps: false)));

                return(UpdateExpression(leftBuilder, left));
            }

            return(UpdateExpression(builder, node.Update(left, right, node.LeftConversion, node.Type)));
        }
示例#3
0
 internal void Parse(BoundNullCoalescingOperator boundNullCoalescingOperator)
 {
     base.Parse(boundNullCoalescingOperator);
     this.LeftOperand    = Deserialize(boundNullCoalescingOperator.LeftOperand) as Expression;
     this.RightOperand   = Deserialize(boundNullCoalescingOperator.RightOperand) as Expression;
     this.ConversionKind = boundNullCoalescingOperator.LeftConversion.Kind;
 }
示例#4
0
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            BoundSpillSequence2 ss = null;
            var             right  = VisitExpression(ref ss, node.RightOperand);
            BoundExpression left;

            if (ss == null)
            {
                left = VisitExpression(ref ss, node.LeftOperand);
            }
            else
            {
                var ssLeft = new BoundSpillSequence2();
                left = VisitExpression(ref ssLeft, node.LeftOperand);
                left = Spill(ssLeft, left);

                ssLeft.Add(F.If(
                               F.ObjectEqual(left, F.Null(left.Type)),
                               UpdateStatement(ss, F.Assignment(left, right))
                               ));
                return(UpdateExpression(ssLeft, left));
            }

            return(UpdateExpression(ss, node.Update(left, right, node.LeftConversion, node.Type)));
        }
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            BoundExpression rewrittenLeft       = (BoundExpression)Visit(node.LeftOperand);
            BoundExpression rewrittenRight      = (BoundExpression)Visit(node.RightOperand);
            TypeSymbol      rewrittenResultType = VisitType(node.Type);

            return(MakeNullCoalescingOperator(node.Syntax, rewrittenLeft, rewrittenRight, node.LeftConversion, node.OperatorResultKind, rewrittenResultType));
        }
示例#6
0
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            if (_inExpressionLambda && (node.LeftOperand.IsLiteralNull() || node.LeftOperand.IsLiteralDefault()))
            {
                Error(ErrorCode.ERR_ExpressionTreeContainsBadCoalesce, node.LeftOperand);
            }

            return(base.VisitNullCoalescingOperator(node));
        }
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            if (_inExpressionLambda && node.LeftOperand.ConstantValue != null && node.LeftOperand.ConstantValue.IsNull)
            {
                Error(ErrorCode.ERR_ExpressionTreeContainsBadCoalesce, node.LeftOperand);
            }

            return(base.VisitNullCoalescingOperator(node));
        }
示例#8
0
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            // TestExpression ?? ElseExpression
            if (node.ConstantValue == null && !node.HasErrors)
            {
                var           testExpression = node.TestExpression;
                ConstantValue testExpressionConstantValue = testExpression.ConstantValue;
                if (testExpressionConstantValue != null)
                {
                    // testExpression is a known compile time constant
                    if (testExpressionConstantValue == ConstantValue.Null)
                    {
                        // testExpression is always null
                        return(Visit(node.ElseExpression));
                    }
                    // testExpression is always non null constant
                    return(Visit(node.LeftConversion ?? node.TestExpression));
                }
                else
                {
                    TypeSymbol      exprType       = node.Type;
                    BoundExpression elseExpression = node.ElseExpression;
                    BoundExpression leftConversion = node.LeftConversion; //it's a BoundConversion, but we're passing by ref

                    // There are two ways that a conversion of the test expression can be represented:
                    //   1) If it was cast in source, then node.TestExpression could be a BoundConversion, or
                    //   2) If the compiler generated a conversion to reconcile the types, then node.LeftConversion could be non-null.
                    if (leftConversion == null)
                    {
                        if (IsUpdateRequiredForExplicitConversion(exprType, ref testExpression, ref elseExpression))
                        {
                            return(node.Update(
                                       testExpression,
                                       elseExpression,
                                       leftConversion: null,
                                       constantValueOpt: null,
                                       type: exprType));
                        }
                    }
                    else if (IsUpdateRequiredForExplicitConversion(exprType, ref leftConversion, ref elseExpression))
                    {
                        return(node.Update(
                                   (BoundExpression)Visit(testExpression),
                                   elseExpression,
                                   (BoundConversion)leftConversion,
                                   constantValueOpt: null,
                                   type: exprType));
                    }
                }
            }
            return(base.VisitNullCoalescingOperator(node));
        }
        private BoundExpression VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            var left  = Visit(node.LeftOperand);
            var right = Visit(node.RightOperand);

            if (node.LeftConversion.IsUserDefined)
            {
                TypeSymbol lambdaParamType = node.LeftOperand.Type.StrippedType();
                return(ExprFactory("Coalesce", left, right, MakeConversionLambda(node.LeftConversion, lambdaParamType, node.Type)));
            }
            else
            {
                return(ExprFactory("Coalesce", left, right));
            }
        }
示例#10
0
        private BoundNode FuseNodes(BoundConditionalAccess conditionalAccess, BoundNullCoalescingOperator node)
        {
            var type = node.RightOperand.Type;

            conditionalAccess = conditionalAccess.Update(conditionalAccess.Receiver, conditionalAccess.AccessExpression, type);

            var whenNull = (BoundExpression)Visit(node.RightOperand);

            if (whenNull.IsDefaultValue() && whenNull.Type.SpecialType != SpecialType.System_Decimal)
            {
                whenNull = null;
            }

            return(RewriteConditionalAccess(conditionalAccess, used: true, rewrittenWhenNull: whenNull));
        }
示例#11
0
 public override object VisitNullCoalescingOperator(BoundNullCoalescingOperator node, object arg)
 {
     VisitExpression(node.Left);
     if (IsConstantNull(node.Left))
     {
         VisitExpression(node.Right);
     }
     else
     {
         var savedState = this.state.Clone();
         VisitExpression(node.Right);
         this.state = savedState;
     }
     return(null);
 }
示例#12
0
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            // check for common pattern   a?.b ?? c  where b is a value type
            // in such cases the result of the expression is either b or c
            // we can skip nullable wrapping/unwrapping

            BoundConditionalAccess conditionalAccess;

            if (TryGetOptimizableNullableConditionalAccess(node.LeftOperand, out conditionalAccess))
            {
                return(FuseNodes(conditionalAccess, node));
            }

            BoundExpression rewrittenLeft       = (BoundExpression)Visit(node.LeftOperand);
            BoundExpression rewrittenRight      = (BoundExpression)Visit(node.RightOperand);
            TypeSymbol      rewrittenResultType = VisitType(node.Type);

            return(MakeNullCoalescingOperator(node.Syntax, rewrittenLeft, rewrittenRight, node.LeftConversion, rewrittenResultType));
        }
示例#13
0
        /// <summary>
        /// Emit code for a null-coalescing operator.
        /// </summary>
        /// <remarks>
        /// x ?? y becomes
        ///   push x
        ///   dup x
        ///   if pop != null goto LEFT_NOT_NULL
        ///     pop 
        ///     push y
        ///   LEFT_NOT_NULL:
        /// </remarks>
        private void EmitNullCoalescingOperator(BoundNullCoalescingOperator expr, bool used)
        {
            Debug.Assert(expr.LeftConversion.IsIdentity, "coalesce with nontrivial left conversions are lowered into ternary.");
            Debug.Assert(expr.Type.IsReferenceType);

            EmitExpression(expr.LeftOperand, used: true);

            // See the notes about verification type merges in EmitConditionalOperator
            var mergeTypeOfLeftValue = StackMergeType(expr.LeftOperand);
            if (used)
            {
                if (IsVarianceCast(expr.Type, mergeTypeOfLeftValue))
                {
                    EmitStaticCast(expr.Type, expr.Syntax);
                    mergeTypeOfLeftValue = expr.Type;
                }
                else if (expr.Type.IsInterfaceType() && expr.Type != mergeTypeOfLeftValue)
                {
                    EmitStaticCast(expr.Type, expr.Syntax);
                }

                _builder.EmitOpCode(ILOpCode.Dup);
            }

            if (expr.Type.IsTypeParameter())
            {
                EmitBox(expr.Type, expr.LeftOperand.Syntax);
            }

            object ifLeftNotNullLabel = new object();
            _builder.EmitBranch(ILOpCode.Brtrue, ifLeftNotNullLabel);

            if (used)
            {
                _builder.EmitOpCode(ILOpCode.Pop);
            }

            EmitExpression(expr.RightOperand, used);
            if (used)
            {
                var mergeTypeOfRightValue = StackMergeType(expr.RightOperand);
                if (IsVarianceCast(expr.Type, mergeTypeOfRightValue))
                {
                    EmitStaticCast(expr.Type, expr.Syntax);
                    mergeTypeOfRightValue = expr.Type;
                }
            }

            _builder.MarkLabel(ifLeftNotNullLabel);
        }
示例#14
0
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            var origStack = StackDepth();
            BoundExpression left = (BoundExpression)this.Visit(node.LeftOperand);

            var cookie = GetStackStateCookie();     // implicit branch here

            // right is evaluated with original stack 
            // (this is not entirely true, codegen may keep left on the stack as an ephemeral temp, but that is irrelevant here)
            SetStackDepth(origStack);
            BoundExpression right = (BoundExpression)this.Visit(node.RightOperand);

            EnsureStackState(cookie);   // implicit label here

            return node.Update(left, right, node.LeftConversion, node.Type);
        }
        public override BoundNode VisitNullCoalescingOperator(BoundNullCoalescingOperator node)
        {
            // TestExpression ?? ElseExpression
            if (node.ConstantValue == null && !node.HasErrors)
            {
                var testExpression = node.TestExpression;
                ConstantValue testExpressionConstantValue = testExpression.ConstantValue;
                if (testExpressionConstantValue != null)
                {
                    // testExpression is a known compile time constant
                    if (testExpressionConstantValue == ConstantValue.Null)
                    {
                        // testExpression is always null
                        return Visit(node.ElseExpression);
                    }
                    // testExpression is always non null constant
                    return Visit(node.LeftConversion ?? node.TestExpression);
                }
                else
                {
                    TypeSymbol exprType = node.Type;
                    BoundExpression elseExpression = node.ElseExpression;
                    BoundExpression leftConversion = node.LeftConversion; //it's a BoundConversion, but we're passing by ref

                    // There are two ways that a conversion of the test expression can be represented:
                    //   1) If it was cast in source, then node.TestExpression could be a BoundConversion, or
                    //   2) If the compiler generated a conversion to reconcile the types, then node.LeftConversion could be non-null.
                    if (leftConversion == null)
                    {
                        if (IsUpdateRequiredForExplicitConversion(exprType, ref testExpression, ref elseExpression))
                        {
                            return node.Update(
                                testExpression,
                                elseExpression,
                                leftConversion: null,
                                constantValueOpt: null,
                                type: exprType);
                        }
                    }
                    else if (IsUpdateRequiredForExplicitConversion(exprType, ref leftConversion, ref elseExpression))
                    {
                        return node.Update(
                            (BoundExpression)Visit(testExpression),
                            elseExpression,
                            (BoundConversion)leftConversion,
                            constantValueOpt: null,
                            type: exprType);
                    }
                }
            }
            return base.VisitNullCoalescingOperator(node);
        }
示例#16
0
        private static BoundStatement RewriteFieldInitializer(BoundFieldEqualsValue fieldInit)
        {
            var syntax = fieldInit.Syntax;

            syntax = (syntax as EqualsValueClauseSyntax)?.Value ?? syntax; //we want the attached sequence point to indicate the value node
            var boundReceiver = fieldInit.Field.IsStatic ? null :
                                new BoundThisReference(syntax, fieldInit.Field.ContainingType);

#if XSHARP
            var initValue = fieldInit.Value;
            // a generated initial value for VO NULL_STRING initialization
            // should not overwrite a value set in a child class
            // not that we recommend that <g>
            bool wasGenerated = fieldInit.WasCompilerGenerated;
            if (!wasGenerated)
            {
                var xNode = initValue.Syntax as LiteralExpressionSyntax;
                if (xNode != null && xNode.XGenerated)
                {
                    wasGenerated = true;
                }
            }
            if (wasGenerated && fieldInit.Field.Type.IsStringType() &&
                boundReceiver != null &&
                fieldInit.Field.DeclaringCompilation.Options.HasOption(CompilerOption.NullStrings, boundReceiver.Syntax))
            {
                var fldaccess = new BoundFieldAccess(syntax,
                                                     boundReceiver,
                                                     fieldInit.Field,
                                                     constantValueOpt: null)
                {
                    WasCompilerGenerated = true
                };
                initValue = new BoundNullCoalescingOperator(syntax,
                                                            fldaccess,
                                                            initValue,
                                                            Conversion.Identity,
                                                            fieldInit.Field.Type)
                {
                    WasCompilerGenerated = true
                };
            }
            BoundStatement boundStatement =
                new BoundExpressionStatement(syntax,
                                             new BoundAssignmentOperator(syntax,
                                                                         new BoundFieldAccess(syntax,
                                                                                              boundReceiver,
                                                                                              fieldInit.Field,
                                                                                              constantValueOpt: null),
                                                                         initValue,
                                                                         fieldInit.Field.Type)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = fieldInit.WasCompilerGenerated
            };
#else
            BoundStatement boundStatement =
                new BoundExpressionStatement(syntax,
                                             new BoundAssignmentOperator(syntax,
                                                                         new BoundFieldAccess(syntax,
                                                                                              boundReceiver,
                                                                                              fieldInit.Field,
                                                                                              constantValueOpt: null),
                                                                         fieldInit.Value,
                                                                         fieldInit.Field.Type)
            {
                WasCompilerGenerated = true
            })
            {
                WasCompilerGenerated = !fieldInit.Locals.IsEmpty || fieldInit.WasCompilerGenerated
            };
#endif
            if (!fieldInit.Locals.IsEmpty)
            {
                boundStatement = new BoundBlock(syntax, fieldInit.Locals, ImmutableArray.Create(boundStatement))
                {
                    WasCompilerGenerated = fieldInit.WasCompilerGenerated
                };
            }

            Debug.Assert(LocalRewriter.IsFieldOrPropertyInitializer(boundStatement));
            return(boundStatement);
        }