Skip to content

Pass a call's receiver the way C, C++ and Rust can reach it [patch] - #328

Merged
matt-edmondson merged 2 commits into
mainfrom
claude/project-thread-kddtpg-170
Oct 22, 2026
Merged

matt-edmondson merged 2 commits into
mainfrom
claude/project-thread-kddtpg-170

Conversation

@matt-edmondson

Copy link
Copy Markdown
Contributor

Requested by Matt · project thread

Before: a method call on a const T& or const T* parameter generated Vec_length(&other) in C, which passes a pointer to a pointer. A chain such as v.twice().length() generated Vec_length(&Vec_twice(&v)), and no C compiler accepts the address of a call's result. C++ wrote other.length() on a pointer, and Rust wrote other.length() on a *const Vec. None of those compile.

After: C passes a pointer or reference receiver as it is (Vec2_length(other)). It wraps a call's result in a one-element array compound literal, Vec2_length((Vec2[]){ Vec2_twice(&v) }), which is an lvalue and decays to the pointer the function takes. C++ writes other->length(), and Rust writes unsafe { (*other).length() }.

How: the receiver's indirection comes from the static-type scope in StandardLanguageGenerator. C and C++ already pushed that scope. Rust now pushes it for function bodies and registers its locals. C also looks up a call's return type by the mangled name it gives a member function (Vec2_twice), because the shared lookup only knows the declared name. The base generator gains SpellMemberAccess, which C++ overrides to write ->. A receiver whose type is unknown is written as before.

The C, C++ and Rust compile tests each gain one case. It covers a call on a reference parameter, a call on a pointer parameter, and a chained call, all built from the shared ReceiverExemplar fixture. Each case compiles the output with warnings as errors, runs the driver, and checks the exit code. All 3 fail without the fix. The full suite passes: 1386 tests, 0 failures.

This doesn't cover a call on a type (static methods, #300) or on self (#141).

Fixes #170


Generated by Claude Code

C passed the address of a receiver that was already a pointer or
reference, and took the address of a call's result, so no method chain
compiled. C now passes a pointer as it is and puts a call's result in a
one-element array compound literal. C++ reaches through a pointer with
->, and Rust dereferences a raw pointer inside unsafe. Rust now scopes
the static types of a function's parameters and locals to know which.

Fixes #170

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tZnrna9oooMZHDaLyXumk
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018tZnrna9oooMZHDaLyXumk
@sonarqubecloud

Copy link
Copy Markdown

@matt-edmondson
matt-edmondson merged commit 09c15d3 into main Oct 22, 2026
16 checks passed
@matt-edmondson
matt-edmondson deleted the claude/project-thread-kddtpg-170 branch October 22, 2026 13:21
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.

Calling a method through a pointer or reference, or on another call's result, generates C, C++ and Rust that doesn't compile

2 participants