Beispiel #1
0
        public override BoundNode VisitObjectCreationExpression(BoundObjectCreationExpression node)
        {
            Debug.Assert(node != null);

            // Rewrite the arguments.
            // NOTE: We may need additional argument rewriting such as generating a params array,
            //       re-ordering arguments based on argsToParamsOpt map, inserting arguments for optional parameters, etc.
            // NOTE: This is done later by MakeArguments, for now we just lower each argument.
            var rewrittenArguments = VisitList(node.Arguments);

            // We have already lowered each argument, but we may need some additional rewriting for the arguments,
            // such as generating a params array, re-ordering arguments based on argsToParamsOpt map, inserting arguments for optional parameters, etc.
            ImmutableArray <LocalSymbol> temps;
            ImmutableArray <RefKind>     argumentRefKindsOpt = node.ArgumentRefKindsOpt;

            rewrittenArguments = MakeArguments(node.Syntax, rewrittenArguments, node.Constructor, node.Constructor, node.Expanded, node.ArgsToParamsOpt, ref argumentRefKindsOpt, out temps);

            BoundExpression rewrittenObjectCreation;

            if (_inExpressionLambda)
            {
                if (!temps.IsDefaultOrEmpty)
                {
                    throw ExceptionUtilities.UnexpectedValue(temps.Length);
                }

                rewrittenObjectCreation = node.UpdateArgumentsAndInitializer(rewrittenArguments, MakeObjectCreationInitializerForExpressionTree(node.InitializerExpressionOpt), changeTypeOpt: node.Constructor.ContainingType);

                if (node.Type.IsInterfaceType())
                {
                    Debug.Assert(rewrittenObjectCreation.Type == ((NamedTypeSymbol)node.Type).ComImportCoClass);
                    rewrittenObjectCreation = MakeConversionNode(rewrittenObjectCreation, node.Type, false, false);
                }

                return(rewrittenObjectCreation);
            }

            rewrittenObjectCreation = node.UpdateArgumentsAndInitializer(rewrittenArguments, newInitializerExpression: null, changeTypeOpt: node.Constructor.ContainingType);

            // replace "new S()" with a default struct ctor with "default(S)"
            if (node.Constructor.IsDefaultValueTypeConstructor())
            {
                rewrittenObjectCreation = new BoundDefaultExpression(rewrittenObjectCreation.Syntax, rewrittenObjectCreation.Type);
            }

            if (!temps.IsDefaultOrEmpty)
            {
                rewrittenObjectCreation = new BoundSequence(
                    node.Syntax,
                    temps,
                    ImmutableArray <BoundExpression> .Empty,
                    rewrittenObjectCreation,
                    node.Type);
            }

            if (node.Type.IsInterfaceType())
            {
                Debug.Assert(rewrittenObjectCreation.Type == ((NamedTypeSymbol)node.Type).ComImportCoClass);
                rewrittenObjectCreation = MakeConversionNode(rewrittenObjectCreation, node.Type, false, false);
            }

            if (node.InitializerExpressionOpt == null || node.InitializerExpressionOpt.HasErrors)
            {
                return(rewrittenObjectCreation);
            }

            return(MakeObjectCreationWithInitializer(node.Syntax, rewrittenObjectCreation, node.InitializerExpressionOpt, node.Type));
        }
        private BoundExpression LowerLiftedUnaryOperator(
            UnaryOperatorKind kind,
            SyntaxNode syntax,
            MethodSymbol method,
            BoundExpression loweredOperand,
            TypeSymbol type)
        {
            // First, an optimization. If we know that the operand is always null then
            // we can simply lower to the alternative.

            BoundExpression optimized = OptimizeLiftedUnaryOperator(kind, syntax, method, loweredOperand, type);

            if (optimized != null)
            {
                return(optimized);
            }

            // We do not know whether the operand is null or non-null, so we generate:
            //
            // S? temp = operand;
            // R? r = temp.HasValue ?
            //        new R?(OP(temp.GetValueOrDefault())) :
            //        default(R?);

            BoundAssignmentOperator tempAssignment;
            BoundLocal   boundTemp         = _factory.StoreToTemp(loweredOperand, out tempAssignment);
            MethodSymbol getValueOrDefault = UnsafeGetNullableMethod(syntax, boundTemp.Type, SpecialMember.System_Nullable_T_GetValueOrDefault);

            // temp.HasValue
            BoundExpression condition = MakeNullableHasValue(syntax, boundTemp);

            // temp.GetValueOrDefault()
            BoundExpression call_GetValueOrDefault = BoundCall.Synthesized(syntax, boundTemp, getValueOrDefault);

            // new R?(temp.GetValueOrDefault())
            BoundExpression consequence = GetLiftedUnaryOperatorConsequence(kind, syntax, method, type, call_GetValueOrDefault);

            // default(R?)
            BoundExpression alternative = new BoundDefaultExpression(syntax, type);

            // temp.HasValue ?
            //          new R?(OP(temp.GetValueOrDefault())) :
            //          default(R?);
            BoundExpression conditionalExpression = RewriteConditionalOperator(
                syntax: syntax,
                rewrittenCondition: condition,
                rewrittenConsequence: consequence,
                rewrittenAlternative: alternative,
                constantValueOpt: null,
                rewrittenType: type,
                isRef: false);

            // temp = operand;
            // temp.HasValue ?
            //          new R?(OP(temp.GetValueOrDefault())) :
            //          default(R?);
            return(new BoundSequence(
                       syntax: syntax,
                       locals: ImmutableArray.Create <LocalSymbol>(boundTemp.LocalSymbol),
                       sideEffects: ImmutableArray.Create <BoundExpression>(tempAssignment),
                       value: conditionalExpression,
                       type: type));
        }
        private BoundExpression MakeUserDefinedIncrementOperator(BoundIncrementOperator node, BoundExpression rewrittenValueToIncrement)
        {
            Debug.Assert((object)node.MethodOpt != null);
            Debug.Assert(node.MethodOpt.ParameterCount == 1);

            bool isLifted = node.OperatorKind.IsLifted();
            bool @checked = node.OperatorKind.IsChecked();

            BoundExpression rewrittenArgument = rewrittenValueToIncrement;
            SyntaxNode      syntax            = node.Syntax;

            TypeSymbol type = node.MethodOpt.GetParameterType(0);

            if (isLifted)
            {
                type = _compilation.GetSpecialType(SpecialType.System_Nullable_T).Construct(type);
                Debug.Assert(TypeSymbol.Equals(node.MethodOpt.GetParameterType(0), node.MethodOpt.ReturnType, TypeCompareKind.ConsiderEverything2));
            }

            if (!node.OperandConversion.IsIdentity)
            {
                rewrittenArgument = MakeConversionNode(
                    syntax: syntax,
                    rewrittenOperand: rewrittenValueToIncrement,
                    conversion: node.OperandConversion,
                    rewrittenType: type,
                    @checked: @checked);
            }

            if (!isLifted)
            {
                return(BoundCall.Synthesized(syntax, null, node.MethodOpt, rewrittenArgument));
            }

            // S? temp = operand;
            // S? r = temp.HasValue ?
            //        new S?(op_Increment(temp.GetValueOrDefault())) :
            //        default(S?);

            // Unlike the other unary operators, we do not attempt to optimize nullable user-defined
            // increment or decrement. The operand is a variable (or property), and so we do not know if
            // it is always null/never null.

            BoundAssignmentOperator tempAssignment;
            BoundLocal boundTemp = _factory.StoreToTemp(rewrittenArgument, out tempAssignment);

            MethodSymbol getValueOrDefault = UnsafeGetNullableMethod(syntax, type, SpecialMember.System_Nullable_T_GetValueOrDefault);
            MethodSymbol ctor = UnsafeGetNullableMethod(syntax, type, SpecialMember.System_Nullable_T__ctor);

            // temp.HasValue
            BoundExpression condition = MakeNullableHasValue(node.Syntax, boundTemp);

            // temp.GetValueOrDefault()
            BoundExpression call_GetValueOrDefault = BoundCall.Synthesized(syntax, boundTemp, getValueOrDefault);

            // op_Increment(temp.GetValueOrDefault())
            BoundExpression userDefinedCall = BoundCall.Synthesized(syntax, null, node.MethodOpt, call_GetValueOrDefault);

            // new S?(op_Increment(temp.GetValueOrDefault()))
            BoundExpression consequence = new BoundObjectCreationExpression(syntax, ctor, null, userDefinedCall);

            // default(S?)
            BoundExpression alternative = new BoundDefaultExpression(syntax, type);

            // temp.HasValue ?
            //          new S?(op_Increment(temp.GetValueOrDefault())) :
            //          default(S?);
            BoundExpression conditionalExpression = RewriteConditionalOperator(
                syntax: syntax,
                rewrittenCondition: condition,
                rewrittenConsequence: consequence,
                rewrittenAlternative: alternative,
                constantValueOpt: null,
                rewrittenType: type,
                isRef: false);

            // temp = operand;
            // temp.HasValue ?
            //          new S?(op_Increment(temp.GetValueOrDefault())) :
            //          default(S?);
            return(new BoundSequence(
                       syntax: syntax,
                       locals: ImmutableArray.Create <LocalSymbol>(boundTemp.LocalSymbol),
                       sideEffects: ImmutableArray.Create <BoundExpression>(tempAssignment),
                       value: conditionalExpression,
                       type: type));
        }
Beispiel #4
0
        private BoundExpression LiftRangeExpression(BoundRangeExpression node, ImmutableArray <BoundExpression> operands)
        {
            Debug.Assert(node.Type.IsNullableType());
            Debug.Assert(operands.Any(operand => operand.Type.IsNullableType()));
            Debug.Assert(operands.Length == 1 || operands.Length == 2);

            ArrayBuilder <BoundExpression> sideeffects = ArrayBuilder <BoundExpression> .GetInstance();

            ArrayBuilder <LocalSymbol> locals = ArrayBuilder <LocalSymbol> .GetInstance();

            ArrayBuilder <BoundExpression> arguments = ArrayBuilder <BoundExpression> .GetInstance();

            // left.HasValue && right.HasValue
            BoundExpression condition = null;

            foreach (var operand in operands)
            {
                BoundExpression tempOperand = CaptureExpressionInTempIfNeeded(operand, sideeffects, locals);

                if (tempOperand.Type.IsNullableType())
                {
                    BoundExpression operandHasValue = MakeOptimizedHasValue(tempOperand.Syntax, tempOperand);

                    if (condition is null)
                    {
                        condition = operandHasValue;
                    }
                    else
                    {
                        TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);
                        condition = MakeBinaryOperator(node.Syntax, BinaryOperatorKind.BoolAnd, condition, operandHasValue, boolType, method: null);
                    }

                    arguments.Add(MakeOptimizedGetValueOrDefault(tempOperand.Syntax, tempOperand));
                }
                else
                {
                    arguments.Add(tempOperand);
                }
            }

            Debug.Assert(condition != null);

            // method(left.GetValueOrDefault(), right.GetValueOrDefault())
            BoundExpression rangeCall = MakeCall(
                node.Syntax,
                rewrittenReceiver: null,
                node.MethodOpt,
                arguments.ToImmutableArray(),
                node.MethodOpt.ReturnType.TypeSymbol);

            if (!TryGetNullableMethod(node.Syntax, node.Type, SpecialMember.System_Nullable_T__ctor, out MethodSymbol nullableCtor))
            {
                return(BadExpression(node.Syntax, node.Type, node));
            }

            // new Nullable(method(left.GetValueOrDefault(), right.GetValueOrDefault()))
            BoundExpression consequence = new BoundObjectCreationExpression(node.Syntax, nullableCtor, binderOpt: null, rangeCall);

            // default
            BoundExpression alternative = new BoundDefaultExpression(node.Syntax, constantValueOpt: null, node.Type);

            // left.HasValue && right.HasValue ? new Nullable(method(left.GetValueOrDefault(), right.GetValueOrDefault())) : default
            BoundExpression conditionalExpression = RewriteConditionalOperator(
                syntax: node.Syntax,
                rewrittenCondition: condition,
                rewrittenConsequence: consequence,
                rewrittenAlternative: alternative,
                constantValueOpt: null,
                rewrittenType: node.Type,
                isRef: false);

            return(new BoundSequence(
                       syntax: node.Syntax,
                       locals: locals.ToImmutableAndFree(),
                       sideEffects: sideeffects.ToImmutableAndFree(),
                       value: conditionalExpression,
                       type: node.Type));
        }
Beispiel #5
0
        public static BoundBlock Rewrite(
            MethodSymbol method,
            BoundBlock block,
            DiagnosticBag diagnostics,
            bool hasTrailingExpression,
            bool originalBodyNested)
        {
#if DEBUG
            // We should only see a trailingExpression if we're in a Script initializer.
            Debug.Assert(!hasTrailingExpression || method.IsScriptInitializer);
            var initialDiagnosticCount = diagnostics.ToReadOnly().Length;
#endif
            var compilation = method.DeclaringCompilation;

            if (method.ReturnsVoid || method.IsIterator || method.IsAsyncEffectivelyReturningTask(compilation))
            {
                // we don't analyze synthesized void methods.
                if ((method.IsImplicitlyDeclared && !method.IsScriptInitializer && !(method.ContainingType.IsStructType() && method.IsParameterlessConstructor() && !method.IsDefaultValueTypeConstructor())) ||
                    Analyze(compilation, method, block, diagnostics))
                {
                    block = AppendImplicitReturn(block, method, originalBodyNested);
                }
            }
            else if (Analyze(compilation, method, block, diagnostics))
            {
                // If the method is a lambda expression being converted to a non-void delegate type
                // and the end point is reachable then suppress the error here; a special error
                // will be reported by the lambda binder.
                Debug.Assert(method.MethodKind != MethodKind.AnonymousFunction);

                // Add implicit "return default(T)" if this is a submission that does not have a trailing expression.
                var submissionResultType = (method as SynthesizedInteractiveInitializerMethod)?.ResultType;
                if (!hasTrailingExpression && ((object)submissionResultType != null))
                {
                    Debug.Assert(!submissionResultType.IsVoidType());

                    var trailingExpression = new BoundDefaultExpression(method.GetNonNullSyntaxNode(), submissionResultType);
                    var newStatements      = block.Statements.Add(new BoundReturnStatement(trailingExpression.Syntax, RefKind.None, trailingExpression));
                    block = new BoundBlock(block.Syntax, ImmutableArray <LocalSymbol> .Empty, newStatements)
                    {
                        WasCompilerGenerated = true
                    };
#if DEBUG
                    // It should not be necessary to repeat analysis after adding this node, because adding a trailing
                    // return in cases where one was missing should never produce different Diagnostics.
                    IEnumerable <Diagnostic> getErrorsOnly(IEnumerable <Diagnostic> diags) => diags.Where(d => d.Severity == DiagnosticSeverity.Error);

                    var flowAnalysisDiagnostics = DiagnosticBag.GetInstance();
                    Debug.Assert(!Analyze(compilation, method, block, flowAnalysisDiagnostics));
                    // Ignore warnings since flow analysis reports nullability mismatches.
                    Debug.Assert(getErrorsOnly(flowAnalysisDiagnostics.ToReadOnly()).SequenceEqual(getErrorsOnly(diagnostics.ToReadOnly().Skip(initialDiagnosticCount))));
                    flowAnalysisDiagnostics.Free();
#endif
                }
                // If there's more than one location, then the method is partial and we
                // have already reported a non-void partial method error.
                else if (method.Locations.Length == 1)
                {
                    diagnostics.Add(ErrorCode.ERR_ReturnExpected, method.Locations[0], method);
                }
            }

            return(block);
        }
Beispiel #6
0
        public override BoundNode VisitRangeExpression(BoundRangeExpression node)
        {
            Debug.Assert(node != null && node.MethodOpt != null);

            bool needLifting     = false;
            var  operandsBuilder = new ArrayBuilder <BoundExpression>();

            var left = node.LeftOperand;

            if (left != null)
            {
                operandsBuilder.Add(tryOptimizeOperand(left));
            }

            var right = node.RightOperand;

            if (right != null)
            {
                operandsBuilder.Add(tryOptimizeOperand(right));
            }

            ImmutableArray <BoundExpression> operands = operandsBuilder.ToImmutable();

            if (needLifting)
            {
                return(LiftRangeExpression(node, operands));
            }
            else
            {
                BoundExpression rangeCreation = MakeCall(
                    node.Syntax,
                    rewrittenReceiver: null,
                    node.MethodOpt,
                    operands,
                    node.MethodOpt.ReturnType.TypeSymbol);

                if (node.Type.IsNullableType())
                {
                    if (!TryGetNullableMethod(node.Syntax, node.Type, SpecialMember.System_Nullable_T__ctor, out MethodSymbol nullableCtor))
                    {
                        return(BadExpression(node.Syntax, node.Type, node));
                    }

                    return(new BoundObjectCreationExpression(node.Syntax, nullableCtor, binderOpt: null, rangeCreation));
                }

                return(rangeCreation);
            }

            BoundExpression tryOptimizeOperand(BoundExpression operand)
            {
                Debug.Assert(operand != null);
                operand = VisitExpression(operand);

                if (NullableNeverHasValue(operand))
                {
                    operand = new BoundDefaultExpression(operand.Syntax, operand.Type.GetNullableUnderlyingType());
                }
                else
                {
                    operand = NullableAlwaysHasValue(operand) ?? operand;

                    if (operand.Type.IsNullableType())
                    {
                        needLifting = true;
                    }
                }

                return(operand);
            }
        }
        private BoundExpression LiftRangeExpression(BoundRangeExpression node, BoundExpression left, BoundExpression right)
        {
            Debug.Assert(node.Type.IsNullableType());
            Debug.Assert(left?.Type.IsNullableType() == true || right?.Type.IsNullableType() == true);
            Debug.Assert(!(left is null && right is null));

            var sideeffects = ArrayBuilder <BoundExpression> .GetInstance();

            var locals = ArrayBuilder <LocalSymbol> .GetInstance();

            // makeRange(left.GetValueOrDefault(), right.GetValueOrDefault())
            BoundExpression condition = null;

            left  = getIndexFromPossibleNullable(left);
            right = getIndexFromPossibleNullable(right);
            var rangeExpr = MakeRangeExpression(node.MethodOpt, left, right);

            Debug.Assert(condition != null);

            if (!TryGetNullableMethod(node.Syntax, node.Type, SpecialMember.System_Nullable_T__ctor, out MethodSymbol nullableCtor))
            {
                return(BadExpression(node.Syntax, node.Type, node));
            }

            // new Nullable(makeRange(left.GetValueOrDefault(), right.GetValueOrDefault()))
            BoundExpression consequence = new BoundObjectCreationExpression(node.Syntax, nullableCtor, binderOpt: null, rangeExpr);

            // default
            BoundExpression alternative = new BoundDefaultExpression(node.Syntax, constantValueOpt: null, node.Type);

            // left.HasValue && right.HasValue
            //     ? new Nullable(makeRange(left.GetValueOrDefault(), right.GetValueOrDefault()))
            //     : default
            BoundExpression conditionalExpression = RewriteConditionalOperator(
                syntax: node.Syntax,
                rewrittenCondition: condition,
                rewrittenConsequence: consequence,
                rewrittenAlternative: alternative,
                constantValueOpt: null,
                rewrittenType: node.Type,
                isRef: false);

            return(new BoundSequence(
                       syntax: node.Syntax,
                       locals: locals.ToImmutableAndFree(),
                       sideEffects: sideeffects.ToImmutableAndFree(),
                       value: conditionalExpression,
                       type: node.Type));

            BoundExpression getIndexFromPossibleNullable(BoundExpression arg)
            {
                if (arg is null)
                {
                    return(null);
                }

                BoundExpression tempOperand = CaptureExpressionInTempIfNeeded(arg, sideeffects, locals);

                if (tempOperand.Type.IsNullableType())
                {
                    BoundExpression operandHasValue = MakeOptimizedHasValue(tempOperand.Syntax, tempOperand);

                    if (condition is null)
                    {
                        condition = operandHasValue;
                    }
                    else
                    {
                        TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);
                        condition = MakeBinaryOperator(node.Syntax, BinaryOperatorKind.BoolAnd, condition, operandHasValue, boolType, method: null);
                    }

                    return(MakeOptimizedGetValueOrDefault(tempOperand.Syntax, tempOperand));
                }
                else
                {
                    return(tempOperand);
                }
            }
        }
        public override BoundNode VisitRangeExpression(BoundRangeExpression node)
        {
            Debug.Assert(node != null && node.MethodOpt != null);

            bool needLifting = false;
            var  F           = _factory;

            var left = node.LeftOperandOpt;

            if (left != null)
            {
                left = tryOptimizeOperand(left);
            }

            var right = node.RightOperandOpt;

            if (right != null)
            {
                right = tryOptimizeOperand(right);
            }

            if (needLifting)
            {
                return(LiftRangeExpression(node, left, right));
            }
            else
            {
                BoundExpression rangeCreation = MakeRangeExpression(node.MethodOpt, left, right);

                if (node.Type.IsNullableType())
                {
                    if (!TryGetNullableMethod(node.Syntax, node.Type, SpecialMember.System_Nullable_T__ctor, out MethodSymbol nullableCtor))
                    {
                        return(BadExpression(node.Syntax, node.Type, node));
                    }

                    return(new BoundObjectCreationExpression(node.Syntax, nullableCtor, binderOpt: null, rangeCreation));
                }

                return(rangeCreation);
            }

            BoundExpression tryOptimizeOperand(BoundExpression operand)
            {
                Debug.Assert(operand != null);
                operand = VisitExpression(operand);

                if (NullableNeverHasValue(operand))
                {
                    operand = new BoundDefaultExpression(operand.Syntax, operand.Type.GetNullableUnderlyingType());
                }
                else
                {
                    operand = NullableAlwaysHasValue(operand) ?? operand;

                    if (operand.Type.IsNullableType())
                    {
                        needLifting = true;
                    }
                }

                return(operand);
            }
        }
Beispiel #9
0
        public override BoundNode VisitRangeExpression(BoundRangeExpression node)
        {
            Debug.Assert(node != null && node.MethodOpt != null);

            bool needLifting = false;
            var  F           = _factory;

            var left = node.LeftOperand;

            if (left != null)
            {
                left = tryOptimizeOperand(left);
            }
            else
            {
                left = newIndexZero(fromEnd: false);
            }

            var right = node.RightOperand;

            if (right != null)
            {
                right = tryOptimizeOperand(right);
            }
            else
            {
                right = newIndexZero(fromEnd: true);
            }

            var operands = ImmutableArray.Create(left, right);

            if (needLifting)
            {
                return(LiftRangeExpression(node, operands));
            }
            else
            {
                BoundExpression rangeCreation = new BoundObjectCreationExpression(
                    node.Syntax,
                    node.MethodOpt,
                    binderOpt: null,
                    operands);

                if (node.Type.IsNullableType())
                {
                    if (!TryGetNullableMethod(node.Syntax, node.Type, SpecialMember.System_Nullable_T__ctor, out MethodSymbol nullableCtor))
                    {
                        return(BadExpression(node.Syntax, node.Type, node));
                    }

                    return(new BoundObjectCreationExpression(node.Syntax, nullableCtor, binderOpt: null, rangeCreation));
                }

                return(rangeCreation);
            }

            BoundExpression newIndexZero(bool fromEnd) =>
            // new Index(0, fromEnd: fromEnd)
            F.New(
                WellKnownMember.System_Index__ctor,
                ImmutableArray.Create <BoundExpression>(F.Literal(0), F.Literal(fromEnd)));

            BoundExpression tryOptimizeOperand(BoundExpression operand)
            {
                Debug.Assert(operand != null);
                operand = VisitExpression(operand);

                if (NullableNeverHasValue(operand))
                {
                    operand = new BoundDefaultExpression(operand.Syntax, operand.Type.GetNullableUnderlyingType());
                }
                else
                {
                    operand = NullableAlwaysHasValue(operand) ?? operand;

                    if (operand.Type.IsNullableType())
                    {
                        needLifting = true;
                    }
                }

                return(operand);
            }
        }
Beispiel #10
0
        public override BoundNode VisitFromEndIndexExpression(BoundFromEndIndexExpression node)
        {
            Debug.Assert(node.MethodOpt != null);

            NamedTypeSymbol booleanType = _compilation.GetSpecialType(SpecialType.System_Boolean);
            BoundExpression fromEnd     = MakeLiteral(node.Syntax, ConstantValue.Create(true), booleanType);

            BoundExpression operand = VisitExpression(node.Operand);

            if (NullableNeverHasValue(operand))
            {
                operand = new BoundDefaultExpression(operand.Syntax, operand.Type.GetNullableUnderlyingType());
            }

            operand = NullableAlwaysHasValue(operand) ?? operand;

            if (!node.Type.IsNullableType())
            {
                return(new BoundObjectCreationExpression(node.Syntax, node.MethodOpt, binderOpt: null, operand, fromEnd));
            }

            ArrayBuilder <BoundExpression> sideeffects = ArrayBuilder <BoundExpression> .GetInstance();

            ArrayBuilder <LocalSymbol> locals = ArrayBuilder <LocalSymbol> .GetInstance();

            // operand.HasValue
            operand = CaptureExpressionInTempIfNeeded(operand, sideeffects, locals);
            BoundExpression condition = MakeOptimizedHasValue(operand.Syntax, operand);

            // new Index(operand, fromEnd: true)
            BoundExpression boundOperandGetValueOrDefault = MakeOptimizedGetValueOrDefault(operand.Syntax, operand);
            BoundExpression indexCreation = new BoundObjectCreationExpression(node.Syntax, node.MethodOpt, binderOpt: null, boundOperandGetValueOrDefault, fromEnd);

            if (!TryGetNullableMethod(node.Syntax, node.Type, SpecialMember.System_Nullable_T__ctor, out MethodSymbol nullableCtor))
            {
                return(BadExpression(node.Syntax, node.Type, operand));
            }

            // new Nullable(new Index(operand, fromEnd: true))
            BoundExpression consequence = new BoundObjectCreationExpression(node.Syntax, nullableCtor, binderOpt: null, indexCreation);

            // default
            BoundExpression alternative = new BoundDefaultExpression(node.Syntax, node.Type);

            // operand.HasValue ? new Nullable(new Index(operand, fromEnd: true)) : default
            BoundExpression conditionalExpression = RewriteConditionalOperator(
                syntax: node.Syntax,
                rewrittenCondition: condition,
                rewrittenConsequence: consequence,
                rewrittenAlternative: alternative,
                constantValueOpt: null,
                rewrittenType: node.Type,
                isRef: false);

            return(new BoundSequence(
                       syntax: node.Syntax,
                       locals: locals.ToImmutableAndFree(),
                       sideEffects: sideeffects.ToImmutableAndFree(),
                       value: conditionalExpression,
                       type: node.Type));
        }