Browse Source

Parenthesize a ref-conditional assignment target

Assigning through a ref-conditional, (cond ? ref a : ref b) = value, was
emitted without the parentheses, so it re-parsed as
cond ? ref a : (ref b = value) and failed to compile (CS8156 / CS0201).
The target was only parenthesized above assignment precedence, but a
conditional binds tighter than assignment, so the check let it through.

Require the assignment target to have precedence above the conditional
operator. Ordinary lvalues (locals, fields, indexers) are primary
expressions and are unaffected; the postfix ++ form already parenthesized
correctly via unary precedence. Covers plain and compound assignments alike.

Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/4086/head
Siegfried Pammer 4 weeks ago
parent
commit
5be91a1238
  1. 7
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs
  2. 6
      ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs

7
ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs

@ -343,6 +343,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -343,6 +343,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
RefReassignment(ref reference.GetHashCode() == 4 ? ref reference : ref s);
}
public static void ConditionalRefAssignment(bool c, ref int a, ref int b)
{
(c ? ref a : ref b) = 3;
(c ? ref a : ref b) += 10;
(c ? ref b : ref a)++;
}
public static void Main(string[] args)
{
DoubleNumber(ref args.Length == 1 ? ref numbers[0] : ref DefaultInt);

6
ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs

@ -475,8 +475,10 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor @@ -475,8 +475,10 @@ namespace ICSharpCode.Decompiler.CSharp.OutputVisitor
{
Parenthesize(assignmentExpression);
}
// assignment is right-associative
ParenthesizeIfRequired(assignmentExpression.Left, PrecedenceLevel.Assignment + 1);
// assignment is right-associative. A ref-conditional target (cond ? ref a : ref b)
// has conditional precedence and would otherwise re-parse as cond ? ref a : (ref b = value),
// so the target needs precedence above ?: to keep its parentheses.
ParenthesizeIfRequired(assignmentExpression.Left, PrecedenceLevel.Conditional + 1);
HandleAssignmentRHS(assignmentExpression.Right);
base.VisitAssignmentExpression(assignmentExpression);
}

Loading…
Cancel
Save