internal void Parse(BoundConditionalOperator boundConditionalOperator)
 {
     base.Parse(boundConditionalOperator);
     this.Condition   = Deserialize(boundConditionalOperator.Condition) as Expression;
     this.Consequence = Deserialize(boundConditionalOperator.Consequence) as Expression;
     this.Alternative = Deserialize(boundConditionalOperator.Alternative) as Expression;
 }
Exemple #2
0
        private void EmitConditionalOperatorAddress(
            BoundConditionalOperator expr,
            AddressKind addressKind
            )
        {
            Debug.Assert(
                expr.ConstantValue == null,
                "Constant value should have been emitted directly"
                );

            object consequenceLabel = new object();
            object doneLabel        = new object();

            EmitCondBranch(expr.Condition, ref consequenceLabel, sense: true);
            AddExpressionTemp(EmitAddress(expr.Alternative, addressKind));

            _builder.EmitBranch(ILOpCode.Br, doneLabel);

            // If we get to consequenceLabel, we should not have Alternative on stack, adjust for that.
            _builder.AdjustStack(-1);

            _builder.MarkLabel(consequenceLabel);
            AddExpressionTemp(EmitAddress(expr.Consequence, addressKind));

            _builder.MarkLabel(doneLabel);
        }
Exemple #3
0
        /// <summary>
        /// If the condition has a constant value, then just use the selected branch.
        /// e.g. "true ? x : y" becomes "x".
        ///
        /// In some special cases, it is also necessary to make implicit reference conversions
        /// explicit to satisfy CLR verification rules.  See IsUpdateRequiredForExplicitConversion.
        /// </summary>
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            if (node.ConstantValue == null && !node.HasErrors)
            {
                ConstantValue conditionConstantValue = node.Condition.ConstantValue;
                if (conditionConstantValue == ConstantValue.True)
                {
                    return(Visit(node.Consequence));
                }
                else if (conditionConstantValue == ConstantValue.False)
                {
                    return(Visit(node.Alternative));
                }
                else if (conditionConstantValue == null || !conditionConstantValue.IsBad)
                {
                    TypeSymbol      exprType    = node.Type;
                    BoundExpression consequence = node.Consequence;
                    BoundExpression alternative = node.Alternative;

                    if (IsUpdateRequiredForExplicitConversion(exprType, ref consequence, ref alternative))
                    {
                        return(node.Update(
                                   node.Condition,
                                   consequence,
                                   alternative,
                                   node.ConstantValueOpt,
                                   exprType));
                    }
                }
            }
            return(base.VisitConditionalOperator(node));
        }
Exemple #4
0
        public override object VisitConditionalOperator(BoundConditionalOperator node, object arg)
        {
            VisitCondition(node.Condition);
            var consequenceState = new FlowAnalysisLocalState(this.state.Reachable, this.state.AssignedWhenTrue);
            var alternativeState = new FlowAnalysisLocalState(this.state.Reachable, this.state.AssignedWhenFalse);

            this.state = consequenceState;
            Visit(node.Consequence);
            consequenceState = this.state;

            this.state = alternativeState;
            Visit(node.Alternative);
            alternativeState = this.state;

            if (IsConstantTrue(node.Condition))
            {
                this.state = consequenceState;
                // it may be a boolean state at this point.
            }
            else if (IsConstantFalse(node.Condition))
            {
                this.state = alternativeState;
                // it may be a boolean state at this point.
            }
            else
            {
                // is may not be a boolean state at this point (5.3.3.28)
                this.state = consequenceState;
                this.state.Join(alternativeState);
            }
            return(null);
        }
Exemple #5
0
        /// <summary>
        /// Emit code for a conditional (aka ternary) operator.
        /// </summary>
        /// <remarks>
        /// (b ? x : y) becomes
        ///     push b
        ///     if pop then goto CONSEQUENCE
        ///     push y
        ///     goto DONE
        ///   CONSEQUENCE:
        ///     push x
        ///   DONE:
        /// </remarks>
        private void EmitConditionalOperator(BoundConditionalOperator expr, bool used)
        {
            Debug.Assert(expr.ConstantValue == null, "Constant value should have been emitted directly");

            object consequenceLabel = new object();
            object doneLabel = new object();

            EmitCondBranch(expr.Condition, ref consequenceLabel, sense: true);
            EmitExpression(expr.Alternative, used);

            //
            // III.1.8.1.3 Merging stack states
            // . . . 
            // Let T be the type from the slot on the newly computed state and S
            // be the type from the corresponding slot on the previously stored state. The merged type, U, shall
            // be computed as follows (recall that S := T is the compatibility function defined
            // in §III.1.8.1.2.2):
            // 1. if S := T then U=S
            // 2. Otherwise, if T := S then U=T
            // 3. Otherwise, if S and T are both object types, then let V be the closest common supertype of S and T then U=V.
            // 4. Otherwise, the merge shall fail.
            //
            // When the target merge type is an interface that one or more classes implement, we emit static casts
            // from any class to the target interface.
            // You may think that it's possible to elide one of the static casts and have the CLR recognize
            // that merging a class and interface should succeed if the class implements the interface. Unfortunately,
            // it seems that either PEVerify or the runtime/JIT verifier will complain at you if you try to remove
            // either of the casts.
            //
            var mergeTypeOfAlternative = StackMergeType(expr.Alternative);
            if (used)
            {
                if (IsVarianceCast(expr.Type, mergeTypeOfAlternative))
                {
                    EmitStaticCast(expr.Type, expr.Syntax);
                    mergeTypeOfAlternative = expr.Type;
                }
                else if (expr.Type.IsInterfaceType() && expr.Type != mergeTypeOfAlternative)
                {
                    EmitStaticCast(expr.Type, expr.Syntax);
                }
            }

            _builder.EmitBranch(ILOpCode.Br, doneLabel);
            if (used)
            {
                // If we get to consequenceLabel, we should not have Alternative on stack, adjust for that.
                _builder.AdjustStack(-1);
            }

            _builder.MarkLabel(consequenceLabel);
            EmitExpression(expr.Consequence, used);

            if (used)
            {
                var mergeTypeOfConsequence = StackMergeType(expr.Consequence);
                if (IsVarianceCast(expr.Type, mergeTypeOfConsequence))
                {
                    EmitStaticCast(expr.Type, expr.Syntax);
                    mergeTypeOfConsequence = expr.Type;
                }
                else if (expr.Type.IsInterfaceType() && expr.Type != mergeTypeOfConsequence)
                {
                    EmitStaticCast(expr.Type, expr.Syntax);
                }
            }

            _builder.MarkLabel(doneLabel);
        }
Exemple #6
0
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            var origStack = StackDepth();
            BoundExpression condition = (BoundExpression)this.Visit(node.Condition);

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

            SetStackDepth(origStack);  // consequence is evaluated with original stack
            BoundExpression consequence = (BoundExpression)this.Visit(node.Consequence);

            EnsureStackState(cookie);   // implicit label here

            SetStackDepth(origStack);  // alternative is evaluated with original stack
            BoundExpression alternative = (BoundExpression)this.Visit(node.Alternative);

            EnsureStackState(cookie);   // implicit label here

            return node.Update(condition, consequence, alternative, node.ConstantValueOpt, node.Type);
        }
        /// <summary>
        /// If the condition has a constant value, then just use the selected branch.
        /// e.g. "true ? x : y" becomes "x".
        /// 
        /// In some special cases, it is also necessary to make implicit reference conversions
        /// explicit to satisfy CLR verification rules.  See IsUpdateRequiredForExplicitConversion.
        /// </summary>
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            if (node.ConstantValue == null && !node.HasErrors)
            {
                ConstantValue conditionConstantValue = node.Condition.ConstantValue;
                if (conditionConstantValue == ConstantValue.True)
                {
                    return Visit(node.Consequence);
                }
                else if (conditionConstantValue == ConstantValue.False)
                {
                    return Visit(node.Alternative);
                }
                else if (conditionConstantValue == null || !conditionConstantValue.IsBad)
                {
                    TypeSymbol exprType = node.Type;
                    BoundExpression consequence = node.Consequence;
                    BoundExpression alternative = node.Alternative;

                    if (IsUpdateRequiredForExplicitConversion(exprType, ref consequence, ref alternative))
                    {
                        return node.Update(
                            node.Condition,
                            consequence,
                            alternative,
                            node.ConstantValueOpt,
                            exprType);
                    }
                }
            }
            return base.VisitConditionalOperator(node);
        }