Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ExpressionLambda Rewriter Failure when assigning to lambda parameter to self #3826

Closed
SLaks opened this issue Jul 3, 2015 · 9 comments · Fixed by #5448
Closed

ExpressionLambda Rewriter Failure when assigning to lambda parameter to self #3826

SLaks opened this issue Jul 3, 2015 · 9 comments · Fixed by #5448

Comments

@SLaks
Copy link
Contributor

SLaks commented Jul 3, 2015

Source:

Expression<Func<int, int>> x = y => y = y;

VS says: "csc2.exe" exited with code -2146232797.

The compiler throws

Unexpected value 'AssignmentOperator' of type 'Microsoft.CodeAnalysis.CSharp.BoundKind'

Stack trace:

>   Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.ExpressionLambdaRewriter.VisitInternal(Microsoft.CodeAnalysis.CSharp.BoundExpression node)  Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.ExpressionLambdaRewriter.Visit(Microsoft.CodeAnalysis.CSharp.BoundExpression node)  Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.ExpressionLambdaRewriter.TranslateLambdaBody(Microsoft.CodeAnalysis.CSharp.BoundBlock block)    Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.ExpressionLambdaRewriter.VisitLambdaInternal(Microsoft.CodeAnalysis.CSharp.BoundLambda node)    Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.ExpressionLambdaRewriter.RewriteLambda(Microsoft.CodeAnalysis.CSharp.BoundLambda node, Microsoft.CodeAnalysis.CSharp.TypeCompilationState compilationState, Microsoft.CodeAnalysis.CSharp.Symbols.TypeMap typeMap, Microsoft.CodeAnalysis.CSharp.BinderFlags binderFlags, Microsoft.CodeAnalysis.DiagnosticBag diagnostics) Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.LambdaRewriter.RewriteLambdaConversion(Microsoft.CodeAnalysis.CSharp.BoundLambda node)  Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.LambdaRewriter.VisitConversion(Microsoft.CodeAnalysis.CSharp.BoundConversion conversion)    Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.BoundConversion.Accept(Microsoft.CodeAnalysis.CSharp.BoundTreeVisitor visitor)  Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.BoundTreeRewriter.VisitAssignmentOperator(Microsoft.CodeAnalysis.CSharp.BoundAssignmentOperator node)   Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.Symbols.MethodToClassRewriter.VisitAssignmentOperator(Microsoft.CodeAnalysis.CSharp.BoundAssignmentOperator node)   Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.BoundAssignmentOperator.Accept(Microsoft.CodeAnalysis.CSharp.BoundTreeVisitor visitor)  Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.BoundTreeRewriter.VisitExpressionStatement(Microsoft.CodeAnalysis.CSharp.BoundExpressionStatement node) Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.BoundExpressionStatement.Accept(Microsoft.CodeAnalysis.CSharp.BoundTreeVisitor visitor) Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.BoundTreeRewriter.VisitSequencePointWithSpan(Microsoft.CodeAnalysis.CSharp.BoundSequencePointWithSpan node) Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.BoundSequencePointWithSpan.Accept(Microsoft.CodeAnalysis.CSharp.BoundTreeVisitor visitor)   Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.LambdaRewriter.RewriteBlock(Microsoft.CodeAnalysis.CSharp.BoundBlock node, Microsoft.CodeAnalysis.ArrayBuilder<Microsoft.CodeAnalysis.CSharp.BoundExpression> prologue, Microsoft.CodeAnalysis.ArrayBuilder<Microsoft.CodeAnalysis.CSharp.Symbols.LocalSymbol> newLocals)   Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.LambdaRewriter.VisitBlock(Microsoft.CodeAnalysis.CSharp.BoundBlock node)    Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.BoundBlock.Accept(Microsoft.CodeAnalysis.CSharp.BoundTreeVisitor visitor)   Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.LambdaRewriter.Rewrite(Microsoft.CodeAnalysis.CSharp.BoundStatement loweredBody, Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol thisType, Microsoft.CodeAnalysis.CSharp.Symbols.ParameterSymbol thisParameter, Microsoft.CodeAnalysis.CSharp.Symbols.MethodSymbol method, int methodOrdinal, Microsoft.CodeAnalysis.ArrayBuilder<Microsoft.CodeAnalysis.CodeGen.LambdaDebugInfo> lambdaDebugInfoBuilder, Microsoft.CodeAnalysis.ArrayBuilder<Microsoft.CodeAnalysis.CodeGen.ClosureDebugInfo> closureDebugInfoBuilder, Microsoft.CodeAnalysis.CodeGen.VariableSlotAllocator slotAllocatorOpt, Microsoft.CodeAnalysis.CSharp.TypeCompilationState compilationState, Microsoft.CodeAnalysis.DiagnosticBag diagnostics, bool assignLocals)  Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.MethodCompiler.LowerBodyOrInitializer(Microsoft.CodeAnalysis.CSharp.Symbols.MethodSymbol method, int methodOrdinal, Microsoft.CodeAnalysis.CSharp.BoundStatement body, Microsoft.CodeAnalysis.CSharp.SynthesizedSubmissionFields previousSubmissionFields, Microsoft.CodeAnalysis.CSharp.TypeCompilationState compilationState, Microsoft.CodeAnalysis.DiagnosticBag diagnostics, ref Microsoft.CodeAnalysis.CodeGen.VariableSlotAllocator lazyVariableSlotAllocator, Microsoft.CodeAnalysis.ArrayBuilder<Microsoft.CodeAnalysis.CodeGen.LambdaDebugInfo> lambdaDebugInfoBuilder, Microsoft.CodeAnalysis.ArrayBuilder<Microsoft.CodeAnalysis.CodeGen.ClosureDebugInfo> closureDebugInfoBuilder, out Microsoft.CodeAnalysis.CSharp.StateMachineTypeSymbol stateMachineTypeOpt)   Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.MethodCompiler.CompileMethod(Microsoft.CodeAnalysis.CSharp.Symbols.MethodSymbol methodSymbol, int methodOrdinal, ref Microsoft.CodeAnalysis.CSharp.Binder.ProcessedFieldInitializers processedInitializers, Microsoft.CodeAnalysis.CSharp.SynthesizedSubmissionFields previousSubmissionFields, Microsoft.CodeAnalysis.CSharp.TypeCompilationState compilationState)    Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.MethodCompiler.CompileNamedType(Microsoft.CodeAnalysis.CSharp.Symbols.NamedTypeSymbol symbol)   Unknown
    Microsoft.CodeAnalysis.CSharp.dll!Microsoft.CodeAnalysis.CSharp.MethodCompiler.CompileNamedTypeAsTask.AnonymousMethod__0()  Unknown
@SLaks
Copy link
Contributor Author

SLaks commented Jul 3, 2015

The legacy compiler raises CS0832 An expression tree may not contain an assignment operator.

Feature request: Can you please remove that error?

@SLaks SLaks changed the title ExpressionLambda Rewriter Failure when assigning to lambda parameter ExpressionLambda Rewriter Failure when assigning to lambda parameter to self Jul 3, 2015
@SLaks
Copy link
Contributor Author

SLaks commented Jul 3, 2015

Assigning to anything other than the parameter itself works.
http://source.roslyn.io/#Roslyn.Compilers.CSharp.Semantic.UnitTests/Semantics/SemanticErrorTests.cs,11458

@SLaks
Copy link
Contributor Author

SLaks commented Jul 3, 2015

The bug is caused by http://source.roslyn.io/#Microsoft.CodeAnalysis.CSharp/Lowering/DiagnosticsPass_ExpressionTrees.cs,126, which suppresses the CS0832 in favor of CS1717 (why?)

@leppie
Copy link
Contributor

leppie commented Jul 3, 2015

@SLaks: Why is assignment forbidden?

@SLaks
Copy link
Contributor Author

SLaks commented Jul 3, 2015

https://msdn.microsoft.com/en-us/library/bb384223

An expression tree does not preserve variable state or have any concept of a storage location.

On the other hand, it seems to be perfectly possible:

var param = Expression.Parameter(typeof(int));
var f = Expression.Lambda<Func<int, int>>(
    Expression.Assign(param, param),
    param
);

This works fine.

@leppie
Copy link
Contributor

leppie commented Jul 3, 2015

@SLaks: Seems like an unnecessary limitation or justification. Like your example, an expression is just access to syntax at the runtime. Even if C# allowed compile-time manipulation, I cant see it being a problem.

@SLaks
Copy link
Contributor Author

SLaks commented Jul 3, 2015

True.

Allowing this (including assignments to fields in closure classes) would probably also be useful for more sophisticated expression-based runtime configuration systems.

@leppie
Copy link
Contributor

leppie commented Jul 3, 2015

@SLaks: Mind you, it is probably bad style, in Scheme you would rather do this:

(let ((foo blah))
  (let ((foo (bar foo)))
    ...)

instead of

(let ((foo blah))
  (set! foo (bar foo))
  ...)

Either way, it gets compiled into the same thing (based on SSA). But on a semantic/scope level it is different (not to ... though).

You could probably do the same with some LINQ and/or nested lambdas in C#.

BTW: Nice catch :D I like to break things too!

@gafter gafter added this to the 1.1 milestone Aug 13, 2015
@gafter
Copy link
Member

gafter commented Aug 13, 2015

Expression trees do not currently support mutation operations or statements, even though underlying trees for most of them are defined. We are definitely interested in expanding the set of supported operations in the future.

@gafter gafter added Bug and removed Bug labels Aug 25, 2015
@jaredpar jaredpar self-assigned this Sep 25, 2015
jaredpar added a commit to jaredpar/roslyn that referenced this issue Sep 25, 2015
All assignments in an expression tree should be an error.  Self
assignment was being flagged as only a warning which lead to later
errors in code generation.  Changed the behavior to warn and error for
self assignment (matches native compiler behavior).

close dotnet#3826
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants