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; }
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); }
/// <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)); }
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); }
/// <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); }
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); }