From 5be91a1238d10cbcc41f6baa43807e892b5da2db Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 22 Aug 2026 17:45:45 +0200 Subject: [PATCH] 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 --- .../TestCases/Pretty/RefLocalsAndReturns.cs | 7 +++++++ .../CSharp/OutputVisitor/InsertParenthesesVisitor.cs | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs index 8428b684c..9c8f34130 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/RefLocalsAndReturns.cs @@ -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); diff --git a/ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs b/ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs index 01148bc5f..86dce99f4 100644 --- a/ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs +++ b/ICSharpCode.Decompiler/CSharp/OutputVisitor/InsertParenthesesVisitor.cs @@ -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); }