Skip to content

Fix #3860: Avoid 'out var' if the variable recurs in the argument list#3864

Open
siegfriedpammer wants to merge 2 commits into
masterfrom
fix-3860-outvar-explicit-type
Open

Fix #3860: Avoid 'out var' if the variable recurs in the argument list#3864
siegfriedpammer wants to merge 2 commits into
masterfrom
fix-3860-outvar-explicit-type

Conversation

@siegfriedpammer

Copy link
Copy Markdown
Member

Fixes #3860.

When the same local is passed as multiple out arguments of one call, DeclareVariables turned the first use into an implicitly-typed declaration, producing f(out var x, out x), which fails to recompile with CS8196: referencing an implicitly-typed out variable in another argument of the declaring call is not permitted, because its type is only inferred once overload resolution of that call has completed. The explicitly-typed form f(out int x, out x) is valid C#, so the transform now falls back to the explicit type when the variable is referenced again within the declaring call (resolving identifiers through collision-merged variables).

New Pretty fixture methods in OutVariables.cs reproduce the issue (previously decompiled as out var a, out a in all compiler configurations); full Pretty/Ugly/ILPretty/VBPretty runs pass.

This PR was authored by an AI agent on behalf of @siegfriedpammer.

🤖 Generated with Claude Code

Passing the same local as multiple out arguments of one call made
DeclareVariables turn the first use into an implicitly-typed declaration,
producing 'f(out var x, out x)'. Referencing an implicitly-typed out
variable in another argument of the declaring call is rejected by the
compiler (CS8196), because its type is only inferred once overload
resolution of that call has completed. The explicitly-typed form
'f(out int x, out x)' is valid, so fall back to the explicit type in
that case.

Assisted-by: Claude:claude-fable-5:Claude Code
@siegfriedpammer siegfriedpammer force-pushed the fix-3860-outvar-explicit-type branch from a7088b2 to 7ccb8f4 Compare July 5, 2026 19:07
@dgrunwald

Copy link
Copy Markdown
Member

Do we also need to worry about nested cases? Foo(out var x, Bar(out x))

CS8196 also fires when the second reference sits inside a nested call
in another argument of the declaring call, e.g.
OutAndValue(out var a, UseAndReturn(out a)). The existing check already
covers this because it walks all descendants of the sibling arguments;
this fixture pins that behavior.

Assisted-by: Claude:claude-fable-5:Claude Code
@siegfriedpammer siegfriedpammer force-pushed the fix-3860-outvar-explicit-type branch from 1104b22 to 62c8d3b Compare July 6, 2026 20:52
@siegfriedpammer

Copy link
Copy Markdown
Member Author

I added a test case, seems Claude implemented support for it "by accident"... the weird first-child-next-sibling loop traverses all descendants of the individual arguments... I was thinking about changing the loop to actually use InvocationExpression.Arguments instead... what do you think?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Decompiled out variables fail to recompile when the same local is passed as multiple out arguments

2 participants