Skip to content

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

Open
matt-edmondson wants to merge 2 commits into
mainfrom
claude/project-thread-kddtpg-170
Open

matt-edmondson wants to merge 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

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