Skip to content

Commit f41a7a3

Browse files
rubysclaude
andcommitted
test(rust): the errors/ac_base pair is not the pair kotlin and swift had
Same two file names, same symptom in the CI matrix, different problem underneath — worth writing down before someone ports the kotlin fix and finds it does nothing. kotlin and swift transpile `active_record/errors.rb` and only needed `X < StandardError` rendered as a relation check. rust doesn't transpile the file at all: `RecordNotFound` is an `errors_ext::FrameworkError` const, so `RecordNotFound.new("…").message` has no type to reach. Wiring the runtime entry was tried and measured; the note now records what came out — the parent is dropped so there's no `message` field and no Display/Error, `super(message)` hits an `ExprNode::Super` arm rust2's expr emit doesn't have, optional params are dropped so the bare `RecordNotFound.new()` the test calls has no constructor, and the `raise(KIND, payload)` consts at ~11 sites in `active_record_base.rs` collide with real structs of the same names. That last one is a design call about how rust represents a raise, not a wiring fix. ac_base is likewise a rust2 test-emit shape rather than a typing gap: rust2 is the only per-target test emit that doesn't seed `test_extras` from `app.rbs_signatures`, so the parent-signature adoption that greened kotlin and swift never reaches it; the test class lowers to free `#[test]` fns, so `@controller` from `setup` emits as `self.controller` in a function with no `self` (all 54 E0424s, one cause); and the same Instance→Class rewrite strips `&self` off the hoisted `TestController`, whose base state rust would have to compose rather than inherit. Refs #34. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 083b870 commit f41a7a3

1 file changed

Lines changed: 53 additions & 9 deletions

File tree

tests/framework_tests_rust.rs

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,11 @@ fn inflector_test_passes_under_rust() {
167167
// These five run (`cargo test --test framework_tests_rust -- --ignored`)
168168
// and fail to COMPILE the emitted crate — they are a worklist, not a
169169
// mystery. Kept in the file so the intent is recorded and the next fix
170-
// has something to run against; CI is scoped to the green subset, the
171-
// same convention framework-tests-kotlin / -swift use. Drop names from
172-
// the CI filter as these close. Tracked in #34 §1.
170+
// has something to run against; CI is scoped to the green subset. (That
171+
// convention used to be shared with framework-tests-kotlin / -swift;
172+
// both now run unfiltered — see below for why rust's two look like
173+
// theirs and aren't.) Drop names from the CI filter as these close.
174+
// Tracked in #34 §1.
173175
//
174176
// json_builder — the rust `JsonBuilder` surface is typed for APP call
175177
// sites, not the framework contract: `encode_value` takes
@@ -186,13 +188,55 @@ fn inflector_test_passes_under_rust() {
186188
// `id` accessor its own AR-shaped body implies, and String/Option
187189
// mismatches remain (`unwrap_or_default` on a `String`).
188190
//
189-
// errors — `RecordNotFound` / `StandardError` as class-reflection
190-
// values. THE SAME FAMILY kotlin and swift defer; whoever closes it
191-
// for one should check all three in the same pass.
191+
// errors — NOT the same shape kotlin and swift had, despite the
192+
// shared symptom. Those two transpile `active_record/errors.rb`
193+
// and only needed `X < StandardError` rendered as a relation
194+
// check; rust does not transpile the file at all (see the note in
195+
// `runtime_loader::RUST_RUNTIME`), so `RecordNotFound` is an
196+
// `errors_ext::FrameworkError` enum CONST, not a type, and the
197+
// test's `RecordNotFound.new("…").message` has nothing to reach.
198+
// Wiring the runtime entry was tried and measured; what comes out
199+
// needs four things rust2 doesn't do yet:
200+
// * `class X < StandardError` → an error struct. The parent is
201+
// dropped, so the emit is a fieldless `struct RecordNotFound`
202+
// with no `message` field and no Display / std::error::Error.
203+
// * `super(message)` inside `initialize` → `/* TODO rust2:
204+
// ExprNode::Discriminant(22) */`. rust2's expr emit has no
205+
// `Super` arm at all (only the `decide/` walkers know it).
206+
// * optional params. rust2 drops Ruby defaults and makes every
207+
// param required, so `RecordNotFound.new()` — which the test
208+
// calls, and which is the whole point of the default-message
209+
// contract — has no constructor to hit.
210+
// * a decision about `errors_ext`. Its `RecordNotFound` /
211+
// `RecordInvalid` consts are what `raise(KIND, payload)`
212+
// passes at the ~11 raise sites in the transpiled
213+
// `active_record_base.rs`; real structs of the same names
214+
// either shadow them or duplicate them. That is a design call
215+
// about how rust represents a raise, not a wiring fix.
216+
// The class-relation `<` still needs an answer too, and rust has
217+
// no runtime type system to ask — unlike swift's metatype `is` and
218+
// kotlin's `isAssignableFrom`, rust's honest rendering is a
219+
// compile-time fold from the emitter's own class table.
192220
//
193-
// ac_base — the inline `TestController` body, dominated by 54
194-
// "expected value, found module `self`". Also a kotlin/swift
195-
// sibling.
221+
// ac_base — a rust2 test-emit shape, not a typing gap. Three
222+
// findings, measured against the current tree:
223+
// * rust2's `test_extras` is the only per-target test emit that
224+
// does NOT seed itself from `app.rbs_signatures` (kotlin,
225+
// swift and csharp all do). So the framework `.rbs` never
226+
// reaches the test lowering, and the inline `TestController <
227+
// ActionController::Base` misses the parent-signature adoption
228+
// that greened kotlin and swift — `process_action` still emits
229+
// `(action_name: serde_json::Value) -> serde_json::Value`.
230+
// * the test class lowers to free `#[test]` fns (instance
231+
// methods are rewritten to class methods for `emit_module`),
232+
// so `@controller` set in `setup` emits as `self.controller`
233+
// in a function that has no `self` — 54 E0424s, all one cause.
234+
// Hoisting the setup ivars to a local per test fn is the fix.
235+
// * the same Instance→Class rewrite reaches the hoisted inner
236+
// class, so `TestController`'s methods lose `&self` and its
237+
// body's `render(...)` / `index()` become free-function calls
238+
// that resolve to nothing. rust has no inheritance, so the
239+
// stand-in also needs its base's state by composition.
196240

197241
#[test]
198242
#[ignore]

0 commit comments

Comments
 (0)