Operator precedence made the condition read
(setting && Add) || Subtract, so 'x -= 1' was converted to 'x--' even
with IntroduceIncrementAndDecrement disabled. Only observable with the
non-default setting, which no fixture configuration exercises, so no
test accompanies the fix.
Assisted-by: Claude:claude-fable-5:Claude Code
Reviving the 2020 test-cases-fp-types fixtures (compound assignment on
float, double and decimal) exposed an asymmetry: post-increment and
post-decrement on float/double round-tripped as x++/x--, but the pre
forms came back as x += 1f because the increment detection in
PrettifyAssignments only accepted integer constants. C# defines ++/--
on floating-point types as adding or subtracting exactly 1, so the
conversion is exact for a constant 1 operand. Decimal already works
through the op_Increment/op_Decrement path.
Assisted-by: Claude:claude-fable-5:Claude Code
Record AST transform groups and mutation steps through the C# pipeline, replay selected steps with the stepper, and carry modified-node ranges through output so the Debug Steps pane can highlight the selected mutation without replacing its full step tree.
Assisted-by: CodeAlta:gpt-5.5:CodeAlta
With every optional slot nullable, the null-object pattern is dead. Generated
non-nullable getters return the backing field directly, which surfaced a last
tier of slots the decompiler legitimately leaves empty (omitted range operands,
an implicitly-typed array creation, unnamed parameters, an unbound generic
argument, and others) and flips them to nullable too. The machinery is then
removed entirely: the per-node null classes, the .Null statics and
VisitNullNode, AstNode.IsNull, the role null object, and Identifier.Null.
AcceptVisitor becomes unconditionally generated, and consumers move from
.IsNull to is null and from unconditional visits to ?.AcceptVisitor.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Optional single-child slots return T? with a real null instead of a role
null-object, taking the C# grammar as the oracle for which slots are optional.
The generator emits the property type as T? and matches it with MatchOptional,
and consumers move from .IsNull to is null / ?.. This covers the optional
statement, member, try-catch, creation-initializer and pattern slots and the
optional NameSlot tokens. A few slots the grammar marks required but the
decompiler legitimately leaves empty (the implicit-element-access target, an
implicitly-typed lambda parameter's type) are flipped to nullable as well.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Turn on #nullable enable across the AST transform pipeline, ahead of
annotating the slot properties themselves. TransformContext now exposes the
nullable CurrentMember/CurrentTypeDefinition/CurrentModule contract already
declared by ITypeResolveContext, and the generated pattern-to-node conversion
returns a non-null node so patterns can be used in collection initializers
without warnings. No IL changes.
Assisted-by: Claude:claude-opus-4-8:Claude Code