/// <summary>
        /// If the condition has a constant value, then just use the selected branch.
        /// e.g. "true ? x : y" becomes "x".
        /// </summary>
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            // just a fact, not a requirement (VisitExpression would have rewritten otherwise)
            Debug.Assert(node.ConstantValue == null);

            var rewrittenCondition   = VisitExpression(node.Condition);
            var rewrittenConsequence = VisitExpression(node.Consequence);
            var rewrittenAlternative = VisitExpression(node.Alternative);

            if (rewrittenCondition.ConstantValue == null)
            {
                return(node.Update(
                           node.IsRef,
                           rewrittenCondition,
                           rewrittenConsequence,
                           rewrittenAlternative,
                           node.ConstantValueOpt,
                           node.NaturalTypeOpt,
                           node.WasTargetTyped,
                           node.Type
                           ));
            }

            return(RewriteConditionalOperator(
                       node.Syntax,
                       rewrittenCondition,
                       rewrittenConsequence,
                       rewrittenAlternative,
                       node.ConstantValueOpt,
                       node.Type,
                       node.IsRef
                       ));
        }
Пример #2
0
        private BoundExpression VisitConditionalOperator(BoundConditionalOperator node)
        {
            var condition   = Visit(node.Condition);
            var consequence = VisitExactType(node.Consequence);
            var alternative = VisitExactType(node.Alternative);

            return(ExprFactory("Condition", condition, consequence, alternative));
        }
Пример #3
0
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            BoundSpillSequenceBuilder conditionBuilder = null;
            var condition = VisitExpression(ref conditionBuilder, node.Condition);

            BoundSpillSequenceBuilder consequenceBuilder = null;
            var consequence = VisitExpression(ref consequenceBuilder, node.Consequence);

            BoundSpillSequenceBuilder alternativeBuilder = null;
            var alternative = VisitExpression(ref alternativeBuilder, node.Alternative);

            if (consequenceBuilder == null && alternativeBuilder == null)
            {
                return(UpdateExpression(conditionBuilder, node.Update(condition, consequence, alternative, node.ConstantValueOpt, node.Type)));
            }

            if (conditionBuilder == null)
            {
                conditionBuilder = new BoundSpillSequenceBuilder();
            }
            if (consequenceBuilder == null)
            {
                consequenceBuilder = new BoundSpillSequenceBuilder();
            }
            if (alternativeBuilder == null)
            {
                alternativeBuilder = new BoundSpillSequenceBuilder();
            }

            if (node.Type.SpecialType == SpecialType.System_Void)
            {
                conditionBuilder.AddStatement(
                    _F.If(condition,
                          UpdateStatement(consequenceBuilder, _F.ExpressionStatement(consequence), substituteTemps: false),
                          UpdateStatement(alternativeBuilder, _F.ExpressionStatement(alternative), substituteTemps: false)));

                return(conditionBuilder.Update(_F.Default(node.Type)));
            }
            else
            {
                Debug.Assert(_F.Syntax.IsKind(SyntaxKind.AwaitExpression));
                var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.AwaitSpill, syntax: _F.Syntax);

                conditionBuilder.AddLocal(tmp, _F.Diagnostics);
                conditionBuilder.AddStatement(
                    _F.If(condition,
                          UpdateStatement(consequenceBuilder, _F.Assignment(_F.Local(tmp), consequence), substituteTemps: false),
                          UpdateStatement(alternativeBuilder, _F.Assignment(_F.Local(tmp), alternative), substituteTemps: false)));

                return(conditionBuilder.Update(_F.Local(tmp)));
            }
        }
Пример #4
0
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            BoundSpillSequenceBuilder conditionBuilder = null;
            var condition = VisitExpression(ref conditionBuilder, node.Condition);

            BoundSpillSequenceBuilder consequenceBuilder = null;
            var consequence = VisitExpression(ref consequenceBuilder, node.Consequence);

            BoundSpillSequenceBuilder alternativeBuilder = null;
            var alternative = VisitExpression(ref alternativeBuilder, node.Alternative);

            if (consequenceBuilder == null && alternativeBuilder == null)
            {
                return(UpdateExpression(conditionBuilder, node.Update(node.IsRef, condition, consequence, alternative, node.ConstantValueOpt, node.Type)));
            }

            if (conditionBuilder == null)
            {
                conditionBuilder = new BoundSpillSequenceBuilder();
            }
            if (consequenceBuilder == null)
            {
                consequenceBuilder = new BoundSpillSequenceBuilder();
            }
            if (alternativeBuilder == null)
            {
                alternativeBuilder = new BoundSpillSequenceBuilder();
            }

            if (node.Type.IsVoidType())
            {
                conditionBuilder.AddStatement(
                    _F.If(condition,
                          UpdateStatement(consequenceBuilder, _F.ExpressionStatement(consequence)),
                          UpdateStatement(alternativeBuilder, _F.ExpressionStatement(alternative))));

                return(conditionBuilder.Update(_F.Default(node.Type)));
            }
            else
            {
                var tmp = _F.SynthesizedLocal(node.Type, kind: SynthesizedLocalKind.Spill, syntax: _F.Syntax);

                conditionBuilder.AddLocal(tmp);
                conditionBuilder.AddStatement(
                    _F.If(condition,
                          UpdateStatement(consequenceBuilder, _F.Assignment(_F.Local(tmp), consequence)),
                          UpdateStatement(alternativeBuilder, _F.Assignment(_F.Local(tmp), alternative))));

                return(conditionBuilder.Update(_F.Local(tmp)));
            }
        }
        /// <summary>
        /// If the condition has a constant value, then just use the selected branch.
        /// e.g. "true ? x : y" becomes "x".
        /// </summary>
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            // just a fact, not a requirement (VisitExpression would have rewritten otherwise)
            Debug.Assert(node.ConstantValue == null);

            var rewrittenCondition = VisitExpression(node.Condition);
            var rewrittenConsequence = VisitExpression(node.Consequence);
            var rewrittenAlternative = VisitExpression(node.Alternative);

            if (rewrittenCondition.ConstantValue == null)
            {
                return node.Update(rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.ConstantValueOpt, node.Type);
            }

            return RewriteConditionalOperator(
                node.Syntax,
                rewrittenCondition,
                rewrittenConsequence,
                rewrittenAlternative,
                node.ConstantValueOpt,
                node.Type);
        }
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            BoundExpression condition   = (BoundExpression)this.Visit(node.Condition);
            BoundExpression consequence = (BoundExpression)this.Visit(node.Consequence);
            BoundExpression alternative = (BoundExpression)this.Visit(node.Alternative);
            TypeSymbol      type        = this.VisitType(node.Type);

            if (!RequiresSpill(condition, consequence, alternative))
            {
                return(node.Update(condition, consequence, alternative, node.ConstantValueOpt, type));
            }

            var spillBuilder = new SpillBuilder();

            LocalSymbol resultLocal = F.SynthesizedLocal(type, null);

            spillBuilder.Locals.Add(resultLocal);

            BoundExpression newCondition;

            if (condition.Kind == BoundKind.SpillSequence)
            {
                var spill = (BoundSpillSequence)condition;
                spillBuilder.AddSpill(spill);
                newCondition = spill.Value;
            }
            else
            {
                newCondition = condition;
            }

            spillBuilder.Statements.Add(
                F.If(
                    condition: newCondition,
                    thenClause: CrushExpression(consequence, resultLocal),
                    elseClause: CrushExpression(alternative, resultLocal)));

            return(spillBuilder.BuildSequenceAndFree(F, F.Local(resultLocal)));
        }
Пример #7
0
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            BoundSpillSequence2 ss1 = null;
            var condition           = VisitExpression(ref ss1, node.Condition);

            BoundSpillSequence2 ss2 = null;
            var consequence         = VisitExpression(ref ss2, node.Consequence);

            BoundSpillSequence2 ss3 = null;
            var alternative         = VisitExpression(ref ss3, node.Alternative);

            if (ss2 == null && ss3 == null)
            {
                return(UpdateExpression(ss1, node.Update(condition, consequence, alternative, node.ConstantValueOpt, node.Type)));
            }

            var tmp = F.SynthesizedLocal(node.Type);

            if (ss1 == null)
            {
                ss1 = new BoundSpillSequence2();
            }
            if (ss2 == null)
            {
                ss2 = new BoundSpillSequence2();
            }
            if (ss3 == null)
            {
                ss3 = new BoundSpillSequence2();
            }

            ss1.Add(tmp);
            ss1.Add(
                F.If(condition,
                     UpdateStatement(ss2, F.Assignment(F.Local(tmp), consequence)),
                     UpdateStatement(ss3, F.Assignment(F.Local(tmp), alternative))));
            return(ss1.Update(F.Local(tmp)));
        }
Пример #8
0
        private BoundExpression OptimizeLiftedUnaryOperator(
            UnaryOperatorKind operatorKind,
            SyntaxNode syntax,
            MethodSymbol method,
            BoundExpression loweredOperand,
            TypeSymbol type)
        {
            if (NullableNeverHasValue(loweredOperand))
            {
                return(new BoundDefaultOperator(syntax, null, type));
            }

            // Second, another simple optimization. If we know that the operand is never null
            // then we can obtain the non-null value and skip generating the temporary. That is,
            // "~(new int?(M()))" is the same as "new int?(~M())".

            BoundExpression neverNull = NullableAlwaysHasValue(loweredOperand);

            if (neverNull != null)
            {
                return(GetLiftedUnaryOperatorConsequence(operatorKind, syntax, method, type, neverNull));
            }

            var conditionalLeft = loweredOperand as BoundLoweredConditionalAccess;

            // NOTE: we could in theory handle side-effecting loweredRight here too
            //       by including it as a part of whenNull, but there is a concern
            //       that it can lead to code duplication
            var optimize = conditionalLeft != null &&
                           (conditionalLeft.WhenNullOpt == null || conditionalLeft.WhenNullOpt.IsDefaultValue());

            if (optimize)
            {
                var result = LowerLiftedUnaryOperator(operatorKind, syntax, method, conditionalLeft.WhenNotNull, type);

                return(conditionalLeft.Update(
                           conditionalLeft.Receiver,
                           conditionalLeft.HasValueMethodOpt,
                           whenNotNull: result,
                           whenNullOpt: null,
                           id: conditionalLeft.Id,
                           type: result.Type
                           ));
            }

            // This optimization is analogous to DistributeLiftedConversionIntoLiftedOperand.

            // Suppose we have a lifted unary conversion whose operand is itself a lifted operation.
            // That is, we have something like:
            //
            // int? r = - (M() + N());
            //
            // where M() and N() return nullable ints. We would simply codegen this as first
            // creating the nullable int result of M() + N(), then checking it for nullity,
            // and then doing the unary minus. That is:
            //
            // int? m = M();
            // int? n = N();
            // int? t = m.HasValue && n.HasValue ? new int?(m.Value + n.Value) : new int?();
            // int? r = t.HasValue ? new int?(-t.Value) : new int?();
            //
            // However, we also observe that we can distribute the unary minus into both branches of
            // the conditional:
            //
            // int? m = M();
            // int? n = N();
            // int? r = m.HasValue && n.HasValue ? - (new int?(m.Value + n.Value))) : - new int?();
            //
            // And we already optimize those! So we could reduce this to:
            //
            // int? m = M();
            // int? n = N();
            // int? r = m.HasValue && n.HasValue ? new int?(- (m.Value + n.Value)) : new int?());
            //
            // which avoids entirely the creation of the unnecessary nullable int and the unnecessary
            // extra null check.

            if (loweredOperand.Kind == BoundKind.Sequence)
            {
                BoundSequence seq = (BoundSequence)loweredOperand;
                if (seq.Value.Kind == BoundKind.ConditionalOperator)
                {
                    BoundConditionalOperator conditional = (BoundConditionalOperator)seq.Value;
                    Debug.Assert(seq.Type == conditional.Type);
                    Debug.Assert(conditional.Type == conditional.Consequence.Type);
                    Debug.Assert(conditional.Type == conditional.Alternative.Type);

                    if (NullableAlwaysHasValue(conditional.Consequence) != null && NullableNeverHasValue(conditional.Alternative))
                    {
                        return(new BoundSequence(
                                   syntax,
                                   seq.Locals,
                                   seq.SideEffects,
                                   RewriteConditionalOperator(
                                       syntax,
                                       conditional.Condition,
                                       MakeUnaryOperator(operatorKind, syntax, method, conditional.Consequence, type),
                                       MakeUnaryOperator(operatorKind, syntax, method, conditional.Alternative, type),
                                       ConstantValue.NotAvailable,
                                       type),
                                   type));
                    }
                }
            }

            return(null);
        }
 private BoundExpression VisitConditionalOperator(BoundConditionalOperator node)
 {
     var condition = Visit(node.Condition);
     var consequence = VisitExactType(node.Consequence);
     var alternative = VisitExactType(node.Alternative);
     return ExprFactory("Condition", condition, consequence, alternative);
 }
Пример #10
0
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            BoundSpillSequence2 ss1 = null;
            var condition = VisitExpression(ref ss1, node.Condition);

            BoundSpillSequence2 ss2 = null;
            var consequence = VisitExpression(ref ss2, node.Consequence);

            BoundSpillSequence2 ss3 = null;
            var alternative = VisitExpression(ref ss3, node.Alternative);

            if (ss2 == null && ss3 == null)
            {
                return UpdateExpression(ss1, node.Update(condition, consequence, alternative, node.ConstantValueOpt, node.Type));
            }

            var tmp = F.SynthesizedLocal(node.Type);
            if (ss1 == null) ss1 = new BoundSpillSequence2();
            if (ss2 == null) ss2 = new BoundSpillSequence2();
            if (ss3 == null) ss3 = new BoundSpillSequence2();

            ss1.Add(tmp);
            ss1.Add(
                F.If(condition,
                    UpdateStatement(ss2, F.Assignment(F.Local(tmp), consequence)),
                    UpdateStatement(ss3, F.Assignment(F.Local(tmp), alternative))));
            return ss1.Update(F.Local(tmp));
        }
        public override BoundNode VisitConditionalOperator(BoundConditionalOperator node)
        {
            BoundExpression condition = (BoundExpression)this.Visit(node.Condition);
            BoundExpression consequence = (BoundExpression)this.Visit(node.Consequence);
            BoundExpression alternative = (BoundExpression)this.Visit(node.Alternative);
            TypeSymbol type = this.VisitType(node.Type);

            if (!RequiresSpill(condition, consequence, alternative))
            {
                return node.Update(condition, consequence, alternative, node.ConstantValueOpt, type);
            }

            var spillBuilder = new SpillBuilder();

            LocalSymbol resultLocal = F.SynthesizedLocal(type, null);
            spillBuilder.Locals.Add(resultLocal);

            BoundExpression newCondition;
            if (condition.Kind == BoundKind.SpillSequence)
            {
                var spill = (BoundSpillSequence)condition;
                spillBuilder.AddSpill(spill);
                newCondition = spill.Value;
            }
            else
            {
                newCondition = condition;
            }

            spillBuilder.Statements.Add(
                F.If(
                    condition: newCondition,
                    thenClause: CrushExpression(consequence, resultLocal),
                    elseClause: CrushExpression(alternative, resultLocal)));

            return spillBuilder.BuildSequenceAndFree(F, F.Local(resultLocal));

        }