Skip to content

Compound Assignment when ref temps are required crashes the compiler #36443

@333fred

Description

@333fred
using System;
using System.Threading.Tasks;
struct S
{
    int? i;

    static async Task Main()
    {    

        S s = default;
        Console.WriteLine(s.i += await GetInt());
    }

    static Task<int?> GetInt() => Task.FromResult((int?)1);
}

This code crashes the compiler with the following stack:

Details
Message: 
    System.InvalidOperationException : Unexpected value 'Local' of type 'Microsoft.CodeAnalysis.CSharp.BoundKind'
    
  Stack Trace: 
    at ThrowingTraceListener.Fail(String message, String detailMessage) in ThrowingTraceListener.cs line: 24
    at TraceListener.Fail(String message)
    at TraceInternal.Fail(String message)
    at Debug.Assert(Boolean condition, String message)
    at ExceptionUtilities.UnexpectedValue(Object o) in ExceptionUtilities.cs line: 18
    at MethodToStateMachineRewriter.HoistExpression(BoundExpression expr, AwaitExpressionSyntax awaitSyntaxOpt, Int32 syntaxOffset, RefKind refKind, ArrayBuilder`1 sideEffects, ArrayBuilder`1 hoistedFields, Boolean& needsSacrificialEvaluation) in MethodToStateMachineRewriter.cs line: 606
    at MethodToStateMachineRewriter.HoistExpression(BoundExpression expr, AwaitExpressionSyntax awaitSyntaxOpt, Int32 syntaxOffset, RefKind refKind, ArrayBuilder`1 sideEffects, ArrayBuilder`1 hoistedFields, Boolean& needsSacrificialEvaluation) in MethodToStateMachineRewriter.cs line: 549
    at MethodToStateMachineRewriter.HoistRefInitialization(SynthesizedLocal local, BoundAssignmentOperator node) in MethodToStateMachineRewriter.cs line: 484
    at MethodToStateMachineRewriter.VisitAssignmentOperator(BoundAssignmentOperator node) in MethodToStateMachineRewriter.cs line: 779
    at BoundAssignmentOperator.Accept(BoundTreeVisitor visitor) in BoundNodes.xml.Generated.cs line: 1507
    at BoundTreeVisitor.Visit(BoundNode node) in BoundTreeVisitors.cs line: 145
    at BoundTreeRewriterWithStackGuard.VisitExpressionWithoutStackGuard(BoundExpression node) in BoundTreeRewriter.cs line: 97
    at BoundTreeVisitor.VisitExpressionWithStackGuard(BoundExpression node) in BoundTreeVisitors.cs line: 223
    at BoundTreeVisitor.VisitExpressionWithStackGuard(Int32& recursionDepth, BoundExpression node) in BoundTreeVisitors.cs line: 204
    at BoundTreeRewriterWithStackGuard.Visit(BoundNode node) in BoundTreeRewriter.cs line: 84
    at MethodToStateMachineRewriter.Visit(BoundNode node) in MethodToStateMachineRewriter.cs line: 658
    at AsyncMethodToStateMachineRewriter.VisitExpressionStatement(BoundExpressionStatement node) in AsyncMethodToStateMachineRewriter.cs line: 272
    at BoundExpressionStatement.Accept(BoundTreeVisitor visitor) in BoundNodes.xml.Generated.cs line: 3023
    at BoundTreeVisitor.Visit(BoundNode node) in BoundTreeVisitors.cs line: 145
    at BoundTreeRewriterWithStackGuard.Visit(BoundNode node) in BoundTreeRewriter.cs line: 87
    at MethodToStateMachineRewriter.Visit(BoundNode node) in MethodToStateMachineRewriter.cs line: 658
    at BoundTreeRewriter.DoVisitList[T](ImmutableArray`1 list) in BoundTreeRewriter.cs line: 37
    at BoundTreeRewriter.VisitList[T](ImmutableArray`1 list) in BoundTreeRewriter.cs line: 26
    at MethodToClassRewriter.VisitBlock(BoundBlock node) in MethodToClassRewriter.cs line: 139
    at MethodToStateMachineRewriter.<>n__0(BoundBlock node)
    at <>c__DisplayClass42_0.<VisitBlock>b__0() in MethodToStateMachineRewriter.cs line: 665
    at MethodToStateMachineRewriter.PossibleIteratorScope(ImmutableArray`1 locals, Func`1 wrapped) in MethodToStateMachineRewriter.cs line: 301
    at MethodToStateMachineRewriter.VisitBlock(BoundBlock node) in MethodToStateMachineRewriter.cs line: 665
    at BoundBlock.Accept(BoundTreeVisitor visitor) in BoundNodes.xml.Generated.cs line: 2673
    at BoundTreeVisitor.Visit(BoundNode node) in BoundTreeVisitors.cs line: 145
    at BoundTreeRewriterWithStackGuard.Visit(BoundNode node) in BoundTreeRewriter.cs line: 87
    at MethodToStateMachineRewriter.Visit(BoundNode node) in MethodToStateMachineRewriter.cs line: 658
    at BoundTreeRewriter.VisitSequencePoint(BoundSequencePoint node) in BoundNodes.xml.Generated.cs line: 9546
    at BoundSequencePoint.Accept(BoundTreeVisitor visitor) in BoundNodes.xml.Generated.cs line: 2614
    at BoundTreeVisitor.Visit(BoundNode node) in BoundTreeVisitors.cs line: 145
    at BoundTreeRewriterWithStackGuard.Visit(BoundNode node) in BoundTreeRewriter.cs line: 87
    at MethodToStateMachineRewriter.Visit(BoundNode node) in MethodToStateMachineRewriter.cs line: 658
    at BoundTreeRewriter.DoVisitList[T](ImmutableArray`1 list) in BoundTreeRewriter.cs line: 37
    at BoundTreeRewriter.VisitList[T](ImmutableArray`1 list) in BoundTreeRewriter.cs line: 26
    at MethodToClassRewriter.VisitBlock(BoundBlock node) in MethodToClassRewriter.cs line: 139
    at MethodToStateMachineRewriter.<>n__0(BoundBlock node)
    at <>c__DisplayClass42_0.<VisitBlock>b__0() in MethodToStateMachineRewriter.cs line: 665
    at MethodToStateMachineRewriter.PossibleIteratorScope(ImmutableArray`1 locals, Func`1 wrapped) in MethodToStateMachineRewriter.cs line: 301
    at MethodToStateMachineRewriter.VisitBlock(BoundBlock node) in MethodToStateMachineRewriter.cs line: 665
    at BoundBlock.Accept(BoundTreeVisitor visitor) in BoundNodes.xml.Generated.cs line: 2673
    at BoundTreeVisitor.Visit(BoundNode node) in BoundTreeVisitors.cs line: 145
    at BoundTreeRewriterWithStackGuard.Visit(BoundNode node) in BoundTreeRewriter.cs line: 87
    at MethodToStateMachineRewriter.Visit(BoundNode node) in MethodToStateMachineRewriter.cs line: 658
    at AsyncMethodToStateMachineRewriter.VisitBody(BoundStatement body) in AsyncMethodToStateMachineRewriter.cs line: 255
    at AsyncMethodToStateMachineRewriter.GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod) in AsyncMethodToStateMachineRewriter.cs line: 121
    at AsyncRewriter.GenerateMoveNext(SynthesizedImplementationMethod moveNextMethod) in AsyncRewriter.cs line: 269
    at AsyncRewriter.GenerateMethodImplementations() in AsyncRewriter.cs line: 140
    at StateMachineRewriter.Rewrite() in StateMachineRewriter.cs line: 114
    at AsyncRewriter.Rewrite(BoundStatement bodyWithAwaitLifted, MethodSymbol method, Int32 methodOrdinal, VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, DiagnosticBag diagnostics, AsyncStateMachine& stateMachineType) in AsyncRewriter.cs line: 81
    at MethodCompiler.LowerBodyOrInitializer(MethodSymbol method, Int32 methodOrdinal, BoundStatement body, SynthesizedSubmissionFields previousSubmissionFields, TypeCompilationState compilationState, Boolean instrumentForDynamicAnalysis, DebugDocumentProvider debugDocumentProvider, ImmutableArray`1& dynamicAnalysisSpans, DiagnosticBag diagnostics, VariableSlotAllocator& lazyVariableSlotAllocator, ArrayBuilder`1 lambdaDebugInfoBuilder, ArrayBuilder`1 closureDebugInfoBuilder, StateMachineTypeSymbol& stateMachineTypeOpt) in MethodCompiler.cs line: 1346
    at MethodCompiler.CompileMethod(MethodSymbol methodSymbol, Int32 methodOrdinal, ProcessedFieldInitializers& processedInitializers, SynthesizedSubmissionFields previousSubmissionFields, TypeCompilationState compilationState) in MethodCompiler.cs line: 1099
    at MethodCompiler.CompileNamedType(NamedTypeSymbol containingType) in MethodCompiler.cs line: 507
    at <>c__DisplayClass22_0.<CompileNamedTypeAsTask>b__0() in MethodCompiler.cs line: 397
    at <>c__DisplayClass5_0.<WithCurrentUICulture>b__0() in UICultureUtilities.cs line: 136
    at Task.InnerInvoke()
    at Task.Execute()
    at --- End of stack trace from previous location where exception was thrown ---

The issue here is that TransformCompoundAssignmentLHS can return a ref local for the following case:

// Case 5: otherwise, it must be structVariable.field += value or array[index] += value. Either way
// we have a variable on the left. Transform it into:
// ref temp = ref variable
// temp = temp + value

The fix is likely to simply issue an understandable error here, instead of throwing an UnreachableCode exception. FYI @jcouv @agocke.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions