Example #1
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));
        }
Example #2
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.SpecialType == SpecialType.System_Void)
            {
                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(node.IsRef, rewrittenCondition, rewrittenConsequence, rewrittenAlternative, node.ConstantValueOpt, node.Type));
            }

            return(RewriteConditionalOperator(
                       node.Syntax,
                       rewrittenCondition,
                       rewrittenConsequence,
                       rewrittenAlternative,
                       node.ConstantValueOpt,
                       node.Type,
                       node.IsRef));
        }
Example #4
0
        private BoundExpression OptimizeLiftedUnaryOperator(
            UnaryOperatorKind operatorKind,
            SyntaxNode syntax,
            MethodSymbol method,
            BoundExpression loweredOperand,
            TypeSymbol type)
        {
            if (NullableNeverHasValue(loweredOperand))
            {
                return(new BoundDefaultExpression(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(TypeSymbol.Equals(seq.Type, conditional.Type, TypeCompareKind.ConsiderEverything2));
                    Debug.Assert(TypeSymbol.Equals(conditional.Type, conditional.Consequence.Type, TypeCompareKind.ConsiderEverything2));
                    Debug.Assert(TypeSymbol.Equals(conditional.Type, conditional.Alternative.Type, TypeCompareKind.ConsiderEverything2));

                    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,
                                       isRef: false),
                                   type));
                    }
                }
            }

            return(null);
        }