fix(lower): bare-call resolver binds same-name flat authors per source [0102c]
Third of four fix-0102 sub-steps — the behaviour fix for NORMAL call sites.
Adds THE bare-name resolver `resolveBareCallee(name, caller_file)` over
fix-0102a's `module_fns` + `flat_import_graph` and routes the primary call
path through it:
- own-author wins: a file's bare call to a name IT authors binds its OWN
author, not the first-wins merge winner. (When the winner already is the
caller's own — every single-author and first-importer case — the resolver
returns `.none` so the existing path binds it byte-for-byte.)
- a bare call to a name two or more FLAT imports both provide is `.ambiguous`
and rejected with a loud diagnostic ("declared by multiple imported
modules — qualify the call"); a namespaced author never collides.
- a single flat-reachable author that differs from the winner binds that
author; otherwise `.none`.
The resolved shadow author lowers into its OWN FuncId via fix-0102b's
identity-addressable `lowerFunctionBodyInto` (shared `bareAuthorFuncId`
helper, also used by `lowerRetainedSameNameAuthors`). Only plain free
functions route — generic / comptime / foreign / builtin authors and any
scope-mangled / UFCS-aliased / locally-shadowed name fall straight to the
existing dispatch, so single-author / local / std / qualified resolution is
unchanged (full example suite stays green, including bundle.sx and the
comptime format/pack examples).
Examples 0722 (flat file per-source bind), 0723 (flat vs namespaced, no false
ambiguity), 0724 (ambiguous → diagnostic), 0725 (flat directory per-source
bind), 0727 (user namespace literally named __m0). Each fails on
wt-fix-0102-base (first-wins mis-bind / no diagnostic) and passes here. The
fix-0102b unit test now calls a per-module wrapper (main can't bare-call the
2-author name) and asserts the resolver's three variants directly.
Gate: zig build, zig build test (400/400), bash tests/run_examples.sh
(462 passed) all green.
This commit is contained in:
18
examples/0722-modules-flat-same-name-own.sx
Normal file
18
examples/0722-modules-flat-same-name-own.sx
Normal file
@@ -0,0 +1,18 @@
|
||||
// fix-0102c (issue 0102): two flat FILE imports each author a same-name free
|
||||
// function `greet`. The first-wins import merge keeps exactly one `greet` in
|
||||
// the merged scope, but each module's OWN code must bind its OWN author when it
|
||||
// calls `greet` bare. `from_a` (in a.sx) returns 1; `from_b` (in b.sx) returns
|
||||
// 2 — per-source binding, resolved by identity, not first-wins.
|
||||
#import "modules/std.sx";
|
||||
#import "0722-modules-flat-same-name-own/a.sx";
|
||||
#import "0722-modules-flat-same-name-own/b.sx";
|
||||
|
||||
report :: (label: string, ok: bool) {
|
||||
if ok { print("{}: ok\n", label); } else { print("{}: FAIL\n", label); }
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
report("from_a binds a.greet", from_a() == 1);
|
||||
report("from_b binds b.greet", from_b() == 2);
|
||||
0
|
||||
}
|
||||
5
examples/0722-modules-flat-same-name-own/a.sx
Normal file
5
examples/0722-modules-flat-same-name-own/a.sx
Normal file
@@ -0,0 +1,5 @@
|
||||
// a.sx authors `greet`. Its own `from_a` calls `greet` bare — under fix-0102c
|
||||
// that binds a.sx's OWN author (own-author wins), even though b.sx also
|
||||
// authors `greet` and the first-wins merge keeps only one in the merged scope.
|
||||
greet :: () -> s64 { return 1; }
|
||||
from_a :: () -> s64 { return greet(); }
|
||||
4
examples/0722-modules-flat-same-name-own/b.sx
Normal file
4
examples/0722-modules-flat-same-name-own/b.sx
Normal file
@@ -0,0 +1,4 @@
|
||||
// b.sx authors its OWN `greet`. `from_b`'s bare `greet` must bind b.sx's
|
||||
// author (2), not the first-wins winner from a.sx.
|
||||
greet :: () -> s64 { return 2; }
|
||||
from_b :: () -> s64 { return greet(); }
|
||||
17
examples/0723-modules-flat-vs-namespaced.sx
Normal file
17
examples/0723-modules-flat-vs-namespaced.sx
Normal file
@@ -0,0 +1,17 @@
|
||||
// fix-0102c (issue 0102): one FLAT and one NAMESPACED author of `value`. The
|
||||
// bare call `value()` binds the FLAT author (10); the namespaced author is
|
||||
// reached only through `nm.value()` (20). A namespaced author must NOT make the
|
||||
// bare call ambiguous — only flat authors collide.
|
||||
#import "modules/std.sx";
|
||||
#import "0723-modules-flat-vs-namespaced/flat.sx";
|
||||
nm :: #import "0723-modules-flat-vs-namespaced/named.sx";
|
||||
|
||||
report :: (label: string, ok: bool) {
|
||||
if ok { print("{}: ok\n", label); } else { print("{}: FAIL\n", label); }
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
report("bare binds flat", value() == 10);
|
||||
report("nm.value binds named", nm.value() == 20);
|
||||
0
|
||||
}
|
||||
3
examples/0723-modules-flat-vs-namespaced/flat.sx
Normal file
3
examples/0723-modules-flat-vs-namespaced/flat.sx
Normal file
@@ -0,0 +1,3 @@
|
||||
// Flat-imported author of `value`. A bare `value()` in the consumer binds THIS
|
||||
// one — the only bare (flat) author of the name.
|
||||
value :: () -> s64 { return 10; }
|
||||
4
examples/0723-modules-flat-vs-namespaced/named.sx
Normal file
4
examples/0723-modules-flat-vs-namespaced/named.sx
Normal file
@@ -0,0 +1,4 @@
|
||||
// Namespaced-imported author of `value`. Reachable only as `nm.value`; it never
|
||||
// enters the flat merge, so it neither shadows the flat author nor makes the
|
||||
// bare call ambiguous.
|
||||
value :: () -> s64 { return 20; }
|
||||
12
examples/0724-modules-flat-same-name-ambiguous.sx
Normal file
12
examples/0724-modules-flat-same-name-ambiguous.sx
Normal file
@@ -0,0 +1,12 @@
|
||||
// fix-0102c (issue 0102): a genuinely-ambiguous bare call. `main` flat-imports
|
||||
// two modules that each author `dup` and neither is `main`'s own — a bare
|
||||
// `dup()` can't pick one, so the compiler rejects it with a loud diagnostic
|
||||
// instead of silently first-wins-binding one. Qualify the call to disambiguate.
|
||||
#import "modules/std.sx";
|
||||
#import "0724-modules-flat-same-name-ambiguous/a.sx";
|
||||
#import "0724-modules-flat-same-name-ambiguous/b.sx";
|
||||
|
||||
main :: () -> s32 {
|
||||
print("{}\n", dup());
|
||||
0
|
||||
}
|
||||
3
examples/0724-modules-flat-same-name-ambiguous/a.sx
Normal file
3
examples/0724-modules-flat-same-name-ambiguous/a.sx
Normal file
@@ -0,0 +1,3 @@
|
||||
// One of two flat authors of `dup`. A consumer that flat-imports BOTH and calls
|
||||
// `dup` bare cannot pick between them.
|
||||
dup :: () -> s64 { return 1; }
|
||||
2
examples/0724-modules-flat-same-name-ambiguous/b.sx
Normal file
2
examples/0724-modules-flat-same-name-ambiguous/b.sx
Normal file
@@ -0,0 +1,2 @@
|
||||
// The second flat author of `dup`.
|
||||
dup :: () -> s64 { return 2; }
|
||||
17
examples/0725-modules-flat-dir-same-name.sx
Normal file
17
examples/0725-modules-flat-dir-same-name.sx
Normal file
@@ -0,0 +1,17 @@
|
||||
// fix-0102c (issue 0102): two flat DIRECTORY imports each author a same-name
|
||||
// `tag`. A directory flat-import exposes the directory's authored functions, so
|
||||
// `caller1`/`caller2` are visible here, and each binds its OWN directory's `tag`
|
||||
// when it calls bare — per-source binding across directory imports (100 / 200).
|
||||
#import "modules/std.sx";
|
||||
#import "0725-modules-flat-dir-same-name/d1";
|
||||
#import "0725-modules-flat-dir-same-name/d2";
|
||||
|
||||
report :: (label: string, ok: bool) {
|
||||
if ok { print("{}: ok\n", label); } else { print("{}: FAIL\n", label); }
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
report("caller1 binds d1.tag", caller1() == 100);
|
||||
report("caller2 binds d2.tag", caller2() == 200);
|
||||
0
|
||||
}
|
||||
3
examples/0725-modules-flat-dir-same-name/d1/one.sx
Normal file
3
examples/0725-modules-flat-dir-same-name/d1/one.sx
Normal file
@@ -0,0 +1,3 @@
|
||||
// d1's author of `tag`. `caller1` (also in d1) binds d1's own `tag` (100).
|
||||
tag :: () -> s64 { return 100; }
|
||||
caller1 :: () -> s64 { return tag(); }
|
||||
4
examples/0725-modules-flat-dir-same-name/d2/two.sx
Normal file
4
examples/0725-modules-flat-dir-same-name/d2/two.sx
Normal file
@@ -0,0 +1,4 @@
|
||||
// d2's author of `tag`. `caller2` (also in d2) binds d2's own `tag` (200),
|
||||
// even though d1's `tag` is the first-wins merge winner.
|
||||
tag :: () -> s64 { return 200; }
|
||||
caller2 :: () -> s64 { return tag(); }
|
||||
20
examples/0727-modules-user-ns-m0.sx
Normal file
20
examples/0727-modules-user-ns-m0.sx
Normal file
@@ -0,0 +1,20 @@
|
||||
// fix-0102c (issue 0102): a user namespace alias literally named `__m0`
|
||||
// coexists with flat same-name imports. fix-0102 resolves same-name authors by
|
||||
// FnDecl IDENTITY — there are no synthetic `__m0`-style names to collide with —
|
||||
// so a user namespace spelled `__m0` is just an ordinary namespace: `call_a`
|
||||
// binds a.ping (1), `call_b` binds b.ping (2), and `__m0.ping` reaches m.ping (99).
|
||||
#import "modules/std.sx";
|
||||
#import "0727-modules-user-ns-m0/a.sx";
|
||||
#import "0727-modules-user-ns-m0/b.sx";
|
||||
__m0 :: #import "0727-modules-user-ns-m0/m.sx";
|
||||
|
||||
report :: (label: string, ok: bool) {
|
||||
if ok { print("{}: ok\n", label); } else { print("{}: FAIL\n", label); }
|
||||
}
|
||||
|
||||
main :: () -> s32 {
|
||||
report("call_a binds a.ping", call_a() == 1);
|
||||
report("call_b binds b.ping", call_b() == 2);
|
||||
report("__m0.ping binds m.ping", __m0.ping() == 99);
|
||||
0
|
||||
}
|
||||
3
examples/0727-modules-user-ns-m0/a.sx
Normal file
3
examples/0727-modules-user-ns-m0/a.sx
Normal file
@@ -0,0 +1,3 @@
|
||||
// Flat author of `ping`; `call_a` binds a.sx's own `ping` (1).
|
||||
ping :: () -> s64 { return 1; }
|
||||
call_a :: () -> s64 { return ping(); }
|
||||
3
examples/0727-modules-user-ns-m0/b.sx
Normal file
3
examples/0727-modules-user-ns-m0/b.sx
Normal file
@@ -0,0 +1,3 @@
|
||||
// Second flat author of `ping`; `call_b` binds b.sx's own `ping` (2).
|
||||
ping :: () -> s64 { return 2; }
|
||||
call_b :: () -> s64 { return ping(); }
|
||||
3
examples/0727-modules-user-ns-m0/m.sx
Normal file
3
examples/0727-modules-user-ns-m0/m.sx
Normal file
@@ -0,0 +1,3 @@
|
||||
// Imported under a user namespace literally named `__m0`. Reached as
|
||||
// `__m0.ping` (99); coexists with the flat `ping` collision.
|
||||
ping :: () -> s64 { return 99; }
|
||||
1
examples/expected/0722-modules-flat-same-name-own.exit
Normal file
1
examples/expected/0722-modules-flat-same-name-own.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/expected/0722-modules-flat-same-name-own.stderr
Normal file
1
examples/expected/0722-modules-flat-same-name-own.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
2
examples/expected/0722-modules-flat-same-name-own.stdout
Normal file
2
examples/expected/0722-modules-flat-same-name-own.stdout
Normal file
@@ -0,0 +1,2 @@
|
||||
from_a binds a.greet: ok
|
||||
from_b binds b.greet: ok
|
||||
1
examples/expected/0723-modules-flat-vs-namespaced.exit
Normal file
1
examples/expected/0723-modules-flat-vs-namespaced.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/expected/0723-modules-flat-vs-namespaced.stderr
Normal file
1
examples/expected/0723-modules-flat-vs-namespaced.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
2
examples/expected/0723-modules-flat-vs-namespaced.stdout
Normal file
2
examples/expected/0723-modules-flat-vs-namespaced.stdout
Normal file
@@ -0,0 +1,2 @@
|
||||
bare binds flat: ok
|
||||
nm.value binds named: ok
|
||||
@@ -0,0 +1 @@
|
||||
1
|
||||
@@ -0,0 +1,5 @@
|
||||
error: 'dup' is ambiguous; declared by multiple imported modules — qualify the call
|
||||
--> examples/0724-modules-flat-same-name-ambiguous.sx:10:19
|
||||
|
|
||||
10 | print("{}\n", dup());
|
||||
| ^^^
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
1
examples/expected/0725-modules-flat-dir-same-name.exit
Normal file
1
examples/expected/0725-modules-flat-dir-same-name.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/expected/0725-modules-flat-dir-same-name.stderr
Normal file
1
examples/expected/0725-modules-flat-dir-same-name.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
2
examples/expected/0725-modules-flat-dir-same-name.stdout
Normal file
2
examples/expected/0725-modules-flat-dir-same-name.stdout
Normal file
@@ -0,0 +1,2 @@
|
||||
caller1 binds d1.tag: ok
|
||||
caller2 binds d2.tag: ok
|
||||
1
examples/expected/0727-modules-user-ns-m0.exit
Normal file
1
examples/expected/0727-modules-user-ns-m0.exit
Normal file
@@ -0,0 +1 @@
|
||||
0
|
||||
1
examples/expected/0727-modules-user-ns-m0.stderr
Normal file
1
examples/expected/0727-modules-user-ns-m0.stderr
Normal file
@@ -0,0 +1 @@
|
||||
|
||||
3
examples/expected/0727-modules-user-ns-m0.stdout
Normal file
3
examples/expected/0727-modules-user-ns-m0.stdout
Normal file
@@ -0,0 +1,3 @@
|
||||
call_a binds a.ping: ok
|
||||
call_b binds b.ping: ok
|
||||
__m0.ping binds m.ping: ok
|
||||
Reference in New Issue
Block a user