public BoundElementAccessExpression(VariableSymbol variable, BoundExpression?index) :
     base(variable, BoundNodeKind.ElementAccessExpression)
 {
     Index = index;
 }
        /// <summary>
        /// Generates a lowered form of the assignment operator for the given left and right sub-expressions.
        /// Left and right sub-expressions must be in lowered form.
        /// </summary>
        private BoundExpression MakeStaticAssignmentOperator(
            SyntaxNode syntax,
            BoundExpression rewrittenLeft,
            BoundExpression rewrittenRight,
            bool isRef,
            TypeSymbol type,
            bool used)
        {
            switch (rewrittenLeft.Kind)
            {
            case BoundKind.DynamicIndexerAccess:
            case BoundKind.DynamicMemberAccess:
                throw ExceptionUtilities.UnexpectedValue(rewrittenLeft.Kind);

            case BoundKind.PropertyAccess:
            {
                Debug.Assert(!isRef);
                BoundPropertyAccess propertyAccess    = (BoundPropertyAccess)rewrittenLeft;
                BoundExpression?    rewrittenReceiver = propertyAccess.ReceiverOpt;
                PropertySymbol      property          = propertyAccess.PropertySymbol;
                Debug.Assert(!property.IsIndexer);
                return(MakePropertyAssignment(
                           syntax,
                           rewrittenReceiver,
                           property,
                           ImmutableArray <BoundExpression> .Empty,
                           default(ImmutableArray <RefKind>),
                           false,
                           default(ImmutableArray <int>),
                           rewrittenRight,
                           type,
                           used));
            }

            case BoundKind.IndexerAccess:
            {
                Debug.Assert(!isRef);
                BoundIndexerAccess indexerAccess           = (BoundIndexerAccess)rewrittenLeft;
                BoundExpression?   rewrittenReceiver       = indexerAccess.ReceiverOpt;
                ImmutableArray <BoundExpression> arguments = indexerAccess.Arguments;
                PropertySymbol indexer = indexerAccess.Indexer;
                Debug.Assert(indexer.IsIndexer || indexer.IsIndexedProperty);
                return(MakePropertyAssignment(
                           syntax,
                           rewrittenReceiver,
                           indexer,
                           arguments,
                           indexerAccess.ArgumentRefKindsOpt,
                           indexerAccess.Expanded,
                           indexerAccess.ArgsToParamsOpt,
                           rewrittenRight,
                           type,
                           used));
            }

            case BoundKind.Local:
            {
                Debug.Assert(!isRef || ((BoundLocal)rewrittenLeft).LocalSymbol.RefKind != RefKind.None);
                return(new BoundAssignmentOperator(
                           syntax,
                           rewrittenLeft,
                           rewrittenRight,
                           type,
                           isRef: isRef));
            }

            case BoundKind.Parameter:
            {
                Debug.Assert(!isRef || rewrittenLeft.GetRefKind() != RefKind.None);
                return(new BoundAssignmentOperator(
                           syntax,
                           rewrittenLeft,
                           rewrittenRight,
                           isRef,
                           type));
            }

            case BoundKind.DiscardExpression:
            {
                return(rewrittenRight);
            }

            case BoundKind.Sequence:
                // An Index or Range pattern-based indexer, or an interpolated string handler conversion
                // that uses an indexer argument, produces a sequence with a nested
                // BoundIndexerAccess. We need to lower the final expression and produce an
                // update sequence
                var sequence = (BoundSequence)rewrittenLeft;
                if (sequence.Value.Kind == BoundKind.IndexerAccess)
                {
                    return(sequence.Update(
                               sequence.Locals,
                               sequence.SideEffects,
                               MakeStaticAssignmentOperator(
                                   syntax,
                                   sequence.Value,
                                   rewrittenRight,
                                   isRef,
                                   type,
                                   used),
                               type));
                }
                goto default;

            default:
            {
                Debug.Assert(!isRef);
                return(new BoundAssignmentOperator(
                           syntax,
                           rewrittenLeft,
                           rewrittenRight,
                           type));
            }
            }
        }
        private BoundExpression MakePropertyAssignment(
            SyntaxNode syntax,
            BoundExpression?rewrittenReceiver,
            PropertySymbol property,
            ImmutableArray <BoundExpression> rewrittenArguments,
            ImmutableArray <RefKind> argumentRefKindsOpt,
            bool expanded,
            ImmutableArray <int> argsToParamsOpt,
            BoundExpression rewrittenRight,
            TypeSymbol type,
            bool used)
        {
            // Rewrite property assignment into call to setter.
            var setMethod = property.GetOwnOrInheritedSetMethod();

            if ((object)setMethod == null)
            {
                var sourceProperty = (SourcePropertySymbol)property;
                Debug.Assert(sourceProperty.IsAutoProperty == true,
                             "only autoproperties can be assignable without having setters");

                var backingField = sourceProperty.BackingField;
                return(_factory.AssignmentExpression(
                           _factory.Field(rewrittenReceiver, backingField),
                           rewrittenRight));
            }

            // 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> argTemps;

            rewrittenArguments = MakeArguments(
                syntax,
                rewrittenArguments,
                property,
                setMethod,
                expanded,
                argsToParamsOpt,
                ref argumentRefKindsOpt,
                out argTemps,
                invokedAsExtensionMethod: false,
                enableCallerInfo: ThreeState.True);

            if (used)
            {
                // Save expression value to a temporary before calling the
                // setter, and restore the temporary after the setter, so the
                // assignment can be used as an embedded expression.
                TypeSymbol?exprType = rewrittenRight.Type;
                Debug.Assert(exprType is object);

                LocalSymbol rhsTemp = _factory.SynthesizedLocal(exprType);

                BoundExpression boundRhs = new BoundLocal(syntax, rhsTemp, null, exprType);

                BoundExpression rhsAssignment = new BoundAssignmentOperator(
                    syntax,
                    boundRhs,
                    rewrittenRight,
                    exprType);

                BoundExpression setterCall = BoundCall.Synthesized(
                    syntax,
                    rewrittenReceiver,
                    setMethod,
                    AppendToPossibleNull(rewrittenArguments, rhsAssignment));

                return(new BoundSequence(
                           syntax,
                           AppendToPossibleNull(argTemps, rhsTemp),
                           ImmutableArray.Create(setterCall),
                           boundRhs,
                           type));
            }
            else
            {
                BoundCall setterCall = BoundCall.Synthesized(
                    syntax,
                    rewrittenReceiver,
                    setMethod,
                    AppendToPossibleNull(rewrittenArguments, rewrittenRight));

                if (argTemps.IsDefaultOrEmpty)
                {
                    return(setterCall);
                }
                else
                {
                    return(new BoundSequence(
                               syntax,
                               argTemps,
                               ImmutableArray <BoundExpression> .Empty,
                               setterCall,
                               setMethod.ReturnType));
                }
            }
        }
示例#4
0
 public BoundReturnStatement(SyntaxNode syntax, BoundExpression?expression)
     : base(syntax)
 {
     Expression = expression;
 }
示例#5
0
        public override BoundNode VisitFieldAccess(BoundFieldAccess node)
        {
            BoundExpression?rewrittenReceiver = VisitExpression(node.ReceiverOpt);

            return(MakeFieldAccess(node.Syntax, rewrittenReceiver, node.FieldSymbol, node.ConstantValue, node.ResultKind, node.Type, node));
        }
示例#6
0
 protected abstract bool TryGetReceiverAndMember(BoundExpression expr, out BoundExpression?receiver, [NotNullWhen(true)] out Symbol?member);
 private static bool BaseReferenceInReceiverWasRewritten([NotNullWhen(true)] BoundExpression?originalReceiver, [NotNullWhen(true)] BoundExpression?rewrittenReceiver)
 {
     return(originalReceiver is { Kind: BoundKind.BaseReference } &&
示例#8
0
 public static BoundCall Synthesized(SyntaxNode syntax, BoundExpression?receiverOpt, MethodSymbol method)
 {
     return(Synthesized(syntax, receiverOpt, method, ImmutableArray <BoundExpression> .Empty));
 }
示例#9
0
 internal DeconstructionVariable(BoundExpression variable, SyntaxNode syntax)
 {
     Single          = variable;
     NestedVariables = null;
     Syntax          = (CSharpSyntaxNode)syntax;
 }
示例#10
0
 internal DeconstructionVariable(ArrayBuilder <DeconstructionVariable> variables, SyntaxNode syntax)
 {
     Single          = null;
     NestedVariables = variables;
     Syntax          = (CSharpSyntaxNode)syntax;
 }
示例#11
0
        internal BoundExpression BindQuery(QueryExpressionSyntax node, BindingDiagnosticBag diagnostics)
        {
            var fromClause          = node.FromClause;
            var boundFromExpression = BindLeftOfPotentialColorColorMemberAccess(fromClause.Expression, diagnostics);

            // If the from expression is of the type dynamic we can't infer the types for any lambdas that occur in the query.
            // Only if there are none we could bind the query but we report an error regardless since such queries are not useful.
            if (boundFromExpression.HasDynamicType())
            {
                diagnostics.Add(ErrorCode.ERR_BadDynamicQuery, fromClause.Expression.Location);
                boundFromExpression = BadExpression(fromClause.Expression, boundFromExpression);
            }
            else
            {
                boundFromExpression = BindToNaturalType(boundFromExpression, diagnostics);
            }

            QueryTranslationState state = new QueryTranslationState();

            state.fromExpression = MakeMemberAccessValue(boundFromExpression, diagnostics);

            var x = state.rangeVariable = state.AddRangeVariable(this, fromClause.Identifier, diagnostics);

            for (int i = node.Body.Clauses.Count - 1; i >= 0; i--)
            {
                state.clauses.Push(node.Body.Clauses[i]);
            }

            state.selectOrGroup = node.Body.SelectOrGroup;

            // A from clause that explicitly specifies a range variable type
            //     from T x in e
            // is translated into
            //     from x in ( e ) . Cast < T > ( )
            BoundExpression?cast = null;

            if (fromClause.Type != null)
            {
                var typeRestriction = BindTypeArgument(fromClause.Type, diagnostics);
                cast = MakeQueryInvocation(fromClause, state.fromExpression, "Cast", fromClause.Type, typeRestriction, diagnostics);
                state.fromExpression = cast;
            }

            state.fromExpression = MakeQueryClause(fromClause, state.fromExpression, x, castInvocation: cast);
            BoundExpression result = BindQueryInternal1(state, diagnostics);

            for (QueryContinuationSyntax?continuation = node.Body.Continuation; continuation != null; continuation = continuation.Body.Continuation)
            {
                // A query expression with a continuation
                //     from ... into x ...
                // is translated into
                //     from x in ( from ... ) ...
                state.Clear();
                state.fromExpression = result;
                x = state.rangeVariable = state.AddRangeVariable(this, continuation.Identifier, diagnostics);
                Debug.Assert(state.clauses.IsEmpty());
                var clauses = continuation.Body.Clauses;
                for (int i = clauses.Count - 1; i >= 0; i--)
                {
                    state.clauses.Push(clauses[i]);
                }

                state.selectOrGroup = continuation.Body.SelectOrGroup;
                result = BindQueryInternal1(state, diagnostics);
                result = MakeQueryClause(continuation.Body, result, x);
                result = MakeQueryClause(continuation, result, x);
            }

            state.Free();
            return(MakeQueryClause(node, result));
        }
示例#12
0
        private BoundExpression FinalTranslation(QueryTranslationState state, BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(state.clauses.IsEmpty());
            switch (state.selectOrGroup.Kind())
            {
            case SyntaxKind.SelectClause:
            {
                // A query expression of the form
                //     from x in e select v
                // is translated into
                //     ( e ) . Select ( x => v )
                var selectClause = (SelectClauseSyntax)state.selectOrGroup;
                var x            = state.rangeVariable;
                var e            = state.fromExpression;
                var v            = selectClause.Expression;
                var lambda       = MakeQueryUnboundLambda(state.RangeVariableMap(), x, v, diagnostics.AccumulatesDependencies);
                var result       = MakeQueryInvocation(state.selectOrGroup, e, "Select", lambda, diagnostics);
                return(MakeQueryClause(selectClause, result, queryInvocation: result));
            }

            case SyntaxKind.GroupClause:
            {
                // A query expression of the form
                //     from x in e group v by k
                // is translated into
                //     ( e ) . GroupBy ( x => k , x => v )
                // except when v is the identifier x, the translation is
                //     ( e ) . GroupBy ( x => k )
                var       groupClause = (GroupClauseSyntax)state.selectOrGroup;
                var       x           = state.rangeVariable;
                var       e           = state.fromExpression;
                var       v           = groupClause.GroupExpression;
                var       k           = groupClause.ByExpression;
                var       vId         = v as IdentifierNameSyntax;
                BoundCall result;
                var       lambdaLeft = MakeQueryUnboundLambda(state.RangeVariableMap(), x, k, diagnostics.AccumulatesDependencies);

                // this is the unoptimized form (when v is not the identifier x)
                var             d           = BindingDiagnosticBag.GetInstance(diagnostics);
                BoundExpression lambdaRight = MakeQueryUnboundLambda(state.RangeVariableMap(), x, v, diagnostics.AccumulatesDependencies);
                result = MakeQueryInvocation(state.selectOrGroup, e, "GroupBy", ImmutableArray.Create(lambdaLeft, lambdaRight), d);
                // k and v appear reversed in the invocation, so we reorder their evaluation
                result = ReverseLastTwoParameterOrder(result);

                BoundExpression?unoptimizedForm = null;
                if (vId != null && vId.Identifier.ValueText == x.Name)
                {
                    // The optimized form.  We store the unoptimized form for analysis
                    unoptimizedForm = result;
                    result          = MakeQueryInvocation(state.selectOrGroup, e, "GroupBy", lambdaLeft, diagnostics);
                    if (unoptimizedForm.HasAnyErrors && !result.HasAnyErrors)
                    {
                        unoptimizedForm = null;
                    }
                }
                else
                {
                    diagnostics.AddRange(d);
                }

                d.Free();
                return(MakeQueryClause(groupClause, result, queryInvocation: result, unoptimizedForm: unoptimizedForm));
            }

            default:
            {
                // there should have been a syntax error if we get here.
                Debug.Assert(state.fromExpression.Type is { });
                return(new BoundBadExpression(
                           state.selectOrGroup, LookupResultKind.OverloadResolutionFailure, ImmutableArray <Symbol?> .Empty,
                           ImmutableArray.Create(state.fromExpression), state.fromExpression.Type));
            }
示例#13
0
 public BoundReturnStatement(BoundExpression?expression)
 {
     Expression = expression;
 }
示例#14
0
        private BoundExpression BindInterpolatedString(
            InterpolatedStringExpressionSyntax node,
            BindingDiagnosticBag diagnostics
            )
        {
            var builder = ArrayBuilder <BoundExpression> .GetInstance();

            var           stringType       = GetSpecialType(SpecialType.System_String, diagnostics, node);
            ConstantValue?resultConstant   = null;
            bool          isResultConstant = true;

            if (node.Contents.Count == 0)
            {
                resultConstant = ConstantValue.Create(string.Empty);
            }
            else
            {
                var objectType = GetSpecialType(SpecialType.System_Object, diagnostics, node);
                var intType    = GetSpecialType(SpecialType.System_Int32, diagnostics, node);
                foreach (var content in node.Contents)
                {
                    switch (content.Kind())
                    {
                    case SyntaxKind.Interpolation:
                    {
                        var interpolation = (InterpolationSyntax)content;
                        var value         = BindValue(
                            interpolation.Expression,
                            diagnostics,
                            BindValueKind.RValue
                            );
                        if (value.Type is null)
                        {
                            value = GenerateConversionForAssignment(
                                objectType,
                                value,
                                diagnostics
                                );
                        }
                        else
                        {
                            value = BindToNaturalType(value, diagnostics);
                            _     = GenerateConversionForAssignment(objectType, value, diagnostics);
                        }

                        // We need to ensure the argument is not a lambda, method group, etc. It isn't nice to wait until lowering,
                        // when we perform overload resolution, to report a problem. So we do that check by calling
                        // GenerateConversionForAssignment with objectType. However we want to preserve the original expression's
                        // natural type so that overload resolution may select a specialized implementation of string.Format,
                        // so we discard the result of that call and only preserve its diagnostics.
                        BoundExpression?alignment = null;
                        BoundLiteral?   format    = null;
                        if (interpolation.AlignmentClause != null)
                        {
                            alignment = GenerateConversionForAssignment(
                                intType,
                                BindValue(
                                    interpolation.AlignmentClause.Value,
                                    diagnostics,
                                    Binder.BindValueKind.RValue
                                    ),
                                diagnostics
                                );
                            var alignmentConstant = alignment.ConstantValue;
                            if (alignmentConstant != null && !alignmentConstant.IsBad)
                            {
                                const int magnitudeLimit = 32767;
                                // check that the magnitude of the alignment is "in range".
                                int alignmentValue = alignmentConstant.Int32Value;
                                //  We do the arithmetic using negative numbers because the largest negative int has no corresponding positive (absolute) value.
                                alignmentValue =
                                    (alignmentValue > 0) ? -alignmentValue : alignmentValue;
                                if (alignmentValue < -magnitudeLimit)
                                {
                                    diagnostics.Add(
                                        ErrorCode.WRN_AlignmentMagnitude,
                                        alignment.Syntax.Location,
                                        alignmentConstant.Int32Value,
                                        magnitudeLimit
                                        );
                                }
                            }
                            else if (!alignment.HasErrors)
                            {
                                diagnostics.Add(
                                    ErrorCode.ERR_ConstantExpected,
                                    interpolation.AlignmentClause.Value.Location
                                    );
                            }
                        }

                        if (interpolation.FormatClause != null)
                        {
                            var  text = interpolation.FormatClause.FormatStringToken.ValueText;
                            char lastChar;
                            bool hasErrors = false;
                            if (text.Length == 0)
                            {
                                diagnostics.Add(
                                    ErrorCode.ERR_EmptyFormatSpecifier,
                                    interpolation.FormatClause.Location
                                    );
                                hasErrors = true;
                            }
                            else if (
                                SyntaxFacts.IsWhitespace(lastChar = text[text.Length - 1]) ||
                                SyntaxFacts.IsNewLine(lastChar)
                                )
                            {
                                diagnostics.Add(
                                    ErrorCode.ERR_TrailingWhitespaceInFormatSpecifier,
                                    interpolation.FormatClause.Location
                                    );
                                hasErrors = true;
                            }

                            format = new BoundLiteral(
                                interpolation.FormatClause,
                                ConstantValue.Create(text),
                                stringType,
                                hasErrors
                                );
                        }

                        builder.Add(
                            new BoundStringInsert(interpolation, value, alignment, format, null)
                            );
                        if (
                            !isResultConstant ||
                            value.ConstantValue == null ||
                            !(interpolation is { FormatClause: null, AlignmentClause: null }) ||
                            !(value.ConstantValue is { IsString: true, IsBad: false })
示例#15
0
        private bool GetGetAwaiterMethod(BoundExpression expression, SyntaxNode node, DiagnosticBag diagnostics, [NotNullWhen(true)] out BoundExpression?getAwaiterCall)
        {
            RoslynDebug.Assert(expression.Type is object);
            if (expression.Type.IsVoidType())
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaitArgVoidCall, node);
                getAwaiterCall = null;
                return(false);
            }

            getAwaiterCall = MakeInvocationExpression(node, expression, WellKnownMemberNames.GetAwaiter, ImmutableArray <BoundExpression> .Empty, diagnostics);
            if (getAwaiterCall.HasAnyErrors) // && !expression.HasAnyErrors?
            {
                getAwaiterCall = null;
                return(false);
            }

            if (getAwaiterCall.Kind != BoundKind.Call)
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaitArg, node, expression.Type);
                getAwaiterCall = null;
                return(false);
            }

            var getAwaiterMethod = ((BoundCall)getAwaiterCall).Method;

            if (getAwaiterMethod is ErrorMethodSymbol ||
                HasOptionalOrVariableParameters(getAwaiterMethod) || // We might have been able to resolve a GetAwaiter overload with optional parameters, so check for that here
                getAwaiterMethod.ReturnsVoid)                        // If GetAwaiter returns void, don't bother checking that it returns an Awaiter.
            {
                Error(diagnostics, ErrorCode.ERR_BadAwaitArg, node, expression.Type);
                getAwaiterCall = null;
                return(false);
            }

            return(true);
        }
示例#16
0
 public BoundCall Update(BoundExpression?receiverOpt, MethodSymbol method, ImmutableArray <BoundExpression> arguments)
 {
     return(this.Update(receiverOpt, method, arguments, ArgumentNamesOpt, ArgumentRefKindsOpt, IsDelegateCall, Expanded, InvokedAsExtensionMethod, ArgsToParamsOpt, ResultKind, OriginalMethodsOpt, BinderOpt, Type));
 }
示例#17
0
        internal BoundAwaitableInfo BindAwaitInfo(BoundAwaitableValuePlaceholder placeholder, SyntaxNode node, DiagnosticBag diagnostics, ref bool hasErrors, BoundExpression?expressionOpt = null)
        {
            bool hasGetAwaitableErrors = !GetAwaitableExpressionInfo(
                expressionOpt ?? placeholder,
                placeholder,
                out bool isDynamic,
                out BoundExpression? getAwaiter,
                out PropertySymbol? isCompleted,
                out MethodSymbol? getResult,
                getAwaiterGetResultCall: out _,
                node,
                diagnostics);

            hasErrors |= hasGetAwaitableErrors;

            return(new BoundAwaitableInfo(node, placeholder, isDynamic: isDynamic, getAwaiter, isCompleted, getResult, hasErrors: hasGetAwaitableErrors)
            {
                WasCompilerGenerated = true
            });
        }
示例#18
0
 public static BoundCall Synthesized(SyntaxNode syntax, BoundExpression?receiverOpt, MethodSymbol method, BoundExpression arg0, BoundExpression arg1)
 {
     return(Synthesized(syntax, receiverOpt, method, ImmutableArray.Create(arg0, arg1)));
 }
示例#19
0
        private bool GetAwaitableExpressionInfo(
            BoundExpression expression,
            BoundExpression getAwaiterArgument,
            out bool isDynamic,
            out BoundExpression?getAwaiter,
            out PropertySymbol?isCompleted,
            out MethodSymbol?getResult,
            out BoundExpression?getAwaiterGetResultCall,
            SyntaxNode node,
            BindingDiagnosticBag diagnostics
            )
        {
            Debug.Assert(
                TypeSymbol.Equals(
                    expression.Type,
                    getAwaiterArgument.Type,
                    TypeCompareKind.ConsiderEverything
                    )
                );

            isDynamic               = false;
            getAwaiter              = null;
            isCompleted             = null;
            getResult               = null;
            getAwaiterGetResultCall = null;

            if (!ValidateAwaitedExpression(expression, node, diagnostics))
            {
                return(false);
            }

            if (expression.HasDynamicType())
            {
                isDynamic = true;
                return(true);
            }

            if (!GetGetAwaiterMethod(getAwaiterArgument, node, diagnostics, out getAwaiter))
            {
                return(false);
            }

            TypeSymbol awaiterType = getAwaiter.Type !;

            return(GetIsCompletedProperty(
                       awaiterType,
                       node,
                       expression.Type !,
                       diagnostics,
                       out isCompleted
                       ) &&
                   AwaiterImplementsINotifyCompletion(awaiterType, node, diagnostics) &&
                   GetGetResultMethod(
                       getAwaiter,
                       node,
                       expression.Type !,
                       diagnostics,
                       out getResult,
                       out getAwaiterGetResultCall
                       ));
        }
示例#20
0
 // Rewrite collection initializer add method calls:
 // 2) new List<int> { 1 };
 //                    ~
 private void AddCollectionInitializers(ref ArrayBuilder <BoundExpression>?dynamicSiteInitializers, ArrayBuilder <BoundExpression> result, BoundExpression?rewrittenReceiver, ImmutableArray <BoundExpression> initializers)
 {
     Debug.Assert(rewrittenReceiver is { } || _inExpressionLambda);
示例#21
0
        /// <summary>
        /// Finds the GetResult method of an Awaiter type.
        /// </summary>
        /// <remarks>
        /// Spec 7.7.7.1:
        /// An Awaiter A has an accessible instance method GetResult with no parameters and no type parameters.
        /// </remarks>
        private bool GetGetResultMethod(
            BoundExpression awaiterExpression,
            SyntaxNode node,
            TypeSymbol awaitedExpressionType,
            BindingDiagnosticBag diagnostics,
            out MethodSymbol?getResultMethod,
            [NotNullWhen(true)] out BoundExpression?getAwaiterGetResultCall
            )
        {
            var awaiterType = awaiterExpression.Type;

            getAwaiterGetResultCall = MakeInvocationExpression(
                node,
                awaiterExpression,
                WellKnownMemberNames.GetResult,
                ImmutableArray <BoundExpression> .Empty,
                diagnostics
                );
            if (getAwaiterGetResultCall.HasAnyErrors)
            {
                getResultMethod         = null;
                getAwaiterGetResultCall = null;
                return(false);
            }

            RoslynDebug.Assert(awaiterType is object);
            if (getAwaiterGetResultCall.Kind != BoundKind.Call)
            {
                Error(
                    diagnostics,
                    ErrorCode.ERR_NoSuchMember,
                    node,
                    awaiterType,
                    WellKnownMemberNames.GetResult
                    );
                getResultMethod         = null;
                getAwaiterGetResultCall = null;
                return(false);
            }

            getResultMethod = ((BoundCall)getAwaiterGetResultCall).Method;
            if (getResultMethod.IsExtensionMethod)
            {
                Error(
                    diagnostics,
                    ErrorCode.ERR_NoSuchMember,
                    node,
                    awaiterType,
                    WellKnownMemberNames.GetResult
                    );
                getResultMethod         = null;
                getAwaiterGetResultCall = null;
                return(false);
            }

            if (HasOptionalOrVariableParameters(getResultMethod) || getResultMethod.IsConditional)
            {
                Error(
                    diagnostics,
                    ErrorCode.ERR_BadAwaiterPattern,
                    node,
                    awaiterType,
                    awaitedExpressionType
                    );
                getResultMethod         = null;
                getAwaiterGetResultCall = null;
                return(false);
            }

            // The lack of a GetResult method will be reported by ValidateGetResult().
            return(true);
        }
        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, etc.
            // NOTE: This is done later by MakeArguments, for now we just lower each argument.
            BoundExpression?receiverDiscard = null;

            ImmutableArray <RefKind>         argumentRefKindsOpt = node.ArgumentRefKindsOpt;
            ImmutableArray <BoundExpression> rewrittenArguments  = VisitArguments(
                node.Arguments,
                node.Constructor,
                node.ArgsToParamsOpt,
                argumentRefKindsOpt,
                ref receiverDiscard,
                out ArrayBuilder <LocalSymbol>?tempsBuilder);

            // 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, etc.
            rewrittenArguments = MakeArguments(
                node.Syntax,
                rewrittenArguments,
                node.Constructor,
                node.Expanded,
                node.ArgsToParamsOpt,
                ref argumentRefKindsOpt,
                ref tempsBuilder);

            BoundExpression rewrittenObjectCreation;
            var             temps = tempsBuilder.ToImmutableAndFree();

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

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

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

                return(rewrittenObjectCreation);
            }

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

            // replace "new S()" with a default struct ctor with "default(S)"
            if (node.Constructor.IsDefaultValueTypeConstructor(requireZeroInit: true))
            {
                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(TypeSymbol.Equals(rewrittenObjectCreation.Type, ((NamedTypeSymbol)node.Type).ComImportCoClass, TypeCompareKind.ConsiderEverything2));
                rewrittenObjectCreation = MakeConversionNode(rewrittenObjectCreation, node.Type, false, false);
            }

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

            return(MakeExpressionWithInitializer(node.Syntax, rewrittenObjectCreation, node.InitializerExpressionOpt, node.Type));
        }
        private BoundStatement?RewriteLocalDeclaration(BoundLocalDeclaration?originalOpt, SyntaxNode syntax, LocalSymbol localSymbol, BoundExpression?rewrittenInitializer, bool hasErrors = false)
        {
            // A declaration of a local variable without an initializer has no associated IL.
            // Simply remove the declaration from the bound tree. The local symbol will
            // remain in the bound block, so codegen will make a stack frame location for it.
            if (rewrittenInitializer == null)
            {
                return(null);
            }

            // A declaration of a local constant also does nothing, even though there is
            // an assignment. The value will be emitted directly where it is used. The
            // local symbol remains in the bound block, but codegen will skip making a
            // stack frame location for it. (We still need a symbol for it to stay
            // around because we'll be generating debug info for it.)
            if (localSymbol.IsConst)
            {
                if (!localSymbol.Type.IsReferenceType && localSymbol.ConstantValue == null)
                {
                    // This can occur in error scenarios (e.g. bad imported metadata)
                    hasErrors = true;
                }
                else
                {
                    return(null);
                }
            }

            // lowered local declaration node is associated with declaration (not whole statement)
            // this is done to make sure that debugger stepping is same as before
            var localDeclaration = syntax as LocalDeclarationStatementSyntax;

            if (localDeclaration != null)
            {
                syntax = localDeclaration.Declaration.Variables[0];
            }

            BoundStatement rewrittenLocalDeclaration = new BoundExpressionStatement(
                syntax,
                new BoundAssignmentOperator(
                    syntax,
                    new BoundLocal(
                        syntax,
                        localSymbol,
                        null,
                        localSymbol.Type
                        ),
                    rewrittenInitializer,
                    localSymbol.Type,
                    localSymbol.IsRef),
                hasErrors);

            return(InstrumentLocalDeclarationIfNecessary(originalOpt, localSymbol, rewrittenLocalDeclaration));
        }