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)); } } }
public BoundReturnStatement(SyntaxNode syntax, BoundExpression?expression) : base(syntax) { Expression = expression; }
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)); }
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 } &&
public static BoundCall Synthesized(SyntaxNode syntax, BoundExpression?receiverOpt, MethodSymbol method) { return(Synthesized(syntax, receiverOpt, method, ImmutableArray <BoundExpression> .Empty)); }
internal DeconstructionVariable(BoundExpression variable, SyntaxNode syntax) { Single = variable; NestedVariables = null; Syntax = (CSharpSyntaxNode)syntax; }
internal DeconstructionVariable(ArrayBuilder <DeconstructionVariable> variables, SyntaxNode syntax) { Single = null; NestedVariables = variables; Syntax = (CSharpSyntaxNode)syntax; }
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)); }
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)); }
public BoundReturnStatement(BoundExpression?expression) { Expression = expression; }
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 })
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); }
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)); }
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 }); }
public static BoundCall Synthesized(SyntaxNode syntax, BoundExpression?receiverOpt, MethodSymbol method, BoundExpression arg0, BoundExpression arg1) { return(Synthesized(syntax, receiverOpt, method, ImmutableArray.Create(arg0, arg1))); }
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 )); }
// 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);
/// <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)); }