Skip to content

Give C# operators the operand the AST leaves implicit [patch] - #230

Merged
matt-edmondson merged 1 commit into
mainfrom
fix/126-csharp-operator-implicit-operand
Oct 14, 2026
Merged

matt-edmondson merged 1 commit into
mainfrom
fix/126-csharp-operator-implicit-operand

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Fixes #126

What changed

In the AST, operators are members, like C++'s Money operator+(Money rhs): the instance is the implicit left-hand operand. C# operators are static and take every operand explicitly. CSharpGenerator wrote the AST's parameters as they were, which caused three problems:

  • a binary + with one parameter compiled as unary +, so every a + b call site failed;
  • a unary operator or conversion with no parameters failed with CS1019;
  • a read-only operator on a struct came out as static readonly, which fails with CS0106. The guard added in Write C# member modifiers only where C# allows them [patch] #225 only checked IsStatic, and an operator is static without the declaration saying so.

Now any operator or conversion that belongs to a type takes that type as a leading self parameter (TakesImplicitOperand). self is the name the C lowering already gives its receiver, so a body that reads self.x means the same thing in both targets. Operators are no longer written readonly.

public static Point operator +(Point self, Point rhs)
public static Point operator -(Point self)
public static implicit operator double(Point self)

Tests

  • New CSharpGeneratedSourceCompilesTests.Operators_Compile. It builds CompiledExemplar.Point() with Plus(), Negate() and ToDouble("self.x"), then runs dotnet build on it with a driver that uses a + b, -a and the implicit conversion. If the generator change is reverted, the test fails (CS1534, plus the readonly CS0106 errors).
  • Full suite: 1281 passed, 0 failed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LJsBos8vaJcor3uRqngfwE


Generated by Claude Code

The AST's operators are members, as in C++ and Rust: operator+(rhs) is
binary and the instance is its left-hand operand. C# operators are static
and take every operand explicitly, so the generator wrote a binary
operator as a unary one, and a unary operator or conversion with no
parameters at all (CS1019). An operator or conversion that belongs to a
type now takes that type as a leading `self` parameter, the name the C
lowering already uses, so bodies reading self.x mean the same thing.

An operator is also never written readonly any more: it is static in C#
whether or not the declaration says so, and a read-only operator on a
struct failed with CS0106.

Adds a compile test covering CompiledExemplar.Plus, Negate and ToDouble
on Point, with a driver that uses a + b, -a and the conversion.

Fixes #126

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LJsBos8vaJcor3uRqngfwE
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 6436bd0 into main Oct 14, 2026
16 checks passed
@matt-edmondson
matt-edmondson deleted the fix/126-csharp-operator-implicit-operand branch October 14, 2026 09:04
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.

C#: member operators lose their implicit operand, so binary + silently becomes unary + and unary/conversion operators fail with CS1019

2 participants