Skip to content

Commit ba7633d

Browse files
olwangclaude
andcommitted
rsscript: read-of-qualified-call parse fix; remove resolved tracking docs
`read module.fn(args)` in argument position misparsed: `read` bound to the module path's first segment as a receiver call, dropping the effect (RS0202). A module-receiver receiver call always carries an explicit effect (bare module calls parse as Callee::Qualified), so module_isolation now converts it to the qualified free call and re-applies the effect to the whole call — `read m.fn()` == `read (m.fn())` == `read flat()`. Verified at parity; receiver-call shorthand on real value receivers is unaffected. This was the last open request. All docs/requests/*.md and docs/tinygrad-port-todo.md are now resolved, so they're removed (history retains their write-ups). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 23b9484 commit ba7633d

8 files changed

Lines changed: 63 additions & 444 deletions

File tree

crates/rsscript/src/syntax/module_isolation.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,44 @@ impl Resolver {
606606
*name = mangled;
607607
}
608608
}
609-
Expr::Call { callee, args, .. } => {
609+
Expr::Call { callee, args, span } => {
610+
// `<effect> module.fn(args)` parses as a receiver call, but when the
611+
// receiver names a module it is a module-qualified free call. The
612+
// effect was written for the *call*, not the module, so convert it
613+
// and re-apply the effect to the whole call: `read m.fn()` becomes
614+
// `read (m__fn())`, identical to `read flat()` and `read (m.fn())`.
615+
// A receiver call always carries an explicit effect (bare module
616+
// calls parse as `Callee::Qualified`, handled below), so this never
617+
// affects value-position calls.
618+
if let Callee::ReceiverCall {
619+
receiver,
620+
method,
621+
effect,
622+
} = callee
623+
&& let Some(prefix) = module_path_of_receiver(receiver, scope)
624+
&& self
625+
.module_defs
626+
.get(&prefix)
627+
.is_some_and(|names| names.contains(method))
628+
{
629+
let effect = *effect;
630+
let mangled = format!("{prefix}{MODULE_SEP}{method}");
631+
for arg in args.iter_mut() {
632+
self.rewrite_expr(&mut arg.value, file, scope);
633+
}
634+
let call_args = std::mem::take(args);
635+
let span = span.clone();
636+
*expr = Expr::Effect {
637+
effect,
638+
value: Box::new(Expr::Call {
639+
callee: Callee::Name(mangled),
640+
args: call_args,
641+
span: span.clone(),
642+
}),
643+
span,
644+
};
645+
return;
646+
}
610647
self.rewrite_callee(callee, file, scope);
611648
for arg in args {
612649
self.rewrite_expr(&mut arg.value, file, scope);

crates/rsscript/tests/checker_frontend/misc.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,31 @@ fn qualified_variant_in_match_pattern_checks_clean() {
6464
);
6565
}
6666

67+
#[test]
68+
fn read_qualified_module_call_parses_as_read_of_call() {
69+
// `read m.fn(args)` in argument position is read-of-the-call, not a receiver
70+
// call on the module — identical to `read flat()` / `read (m.fn())`.
71+
let diagnostics = analyze_sources_with_interfaces(
72+
&[
73+
("m.rss", "module m\n\nfn order_names() -> fresh String { return \"x\" }\n"),
74+
(
75+
"app.rss",
76+
concat!(
77+
"module app\n\n",
78+
"fn sink(v: read String) -> Unit { return Unit }\n\n",
79+
"fn use_it() -> Unit { return sink(v: read m.order_names()) }\n",
80+
),
81+
),
82+
],
83+
&[],
84+
);
85+
assert_eq!(
86+
diagnostics,
87+
Vec::new(),
88+
"`read m.fn()` should resolve as read-of-call: {diagnostics:?}"
89+
);
90+
}
91+
6792
#[test]
6893
fn glob_import_brings_module_symbols_into_scope() {
6994
// `use ops.*` imports the module's type, const, and functions; bare variants

docs/requests/freshness-direct-call-return.md

Lines changed: 0 additions & 71 deletions
This file was deleted.

docs/requests/module-glob-import.md

Lines changed: 0 additions & 79 deletions
This file was deleted.

docs/requests/module-qualified-variant-pattern.md

Lines changed: 0 additions & 89 deletions
This file was deleted.

0 commit comments

Comments
 (0)