nandi/rustnimpublic Fork
⑂ 24296c3
Commits
⬇ Clone ▾
git clone https://git.rickub.com/nandi/rustnim.git
git clone ssh://git@rickub.com/nandi/rustnim.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

Download ZIP

Resolve a qualified path by the module its segments name

`::enumflags2::_internal::next_bit` resolved when enumflags2 was one of two
input files and not when it was one of 357, which is the kind of difference
that means the resolution was working by accident. It searched only the
current module, the `use` map, and the root -- so it found the function only
when the *calling* file happened to be the right place to look.

Now every segment of the path is a candidate module, which is what the path is
actually saying, and after those a global fallback: if exactly one module has
a function by that name, it is that one. Two would be a guess, so that is
refused rather than picked from.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
nandithebull committed 2026-09-19T10:06:10-07:00 Browse files
24296c3 parent: 47de6c6
modified src/lower.rs +19 -5
@@ -1504,15 +1504,29 @@ impl Lowerer {
15041504 }
15051505 }
15061506 let imported = self.use_map.get(&last).cloned();
1507- for m in [Some(self.cur_mod.clone()), imported, Some(String::new())]
1508- .into_iter()
1509- .flatten()
1510- {
1507+ // Any segment of the path may name the module the function is in.
1508+ // `::enumflags2::_internal::next_bit` is in `enumflags2` when that
1509+ // crate arrives as one expanded file, and in `_internal` when the
1510+ // inline module is what carries the name.
1511+ let mut cands: Vec<String> = vec![self.cur_mod.clone()];
1512+ cands.extend(imported);
1513+ cands.push(String::new());
1514+ cands.extend(segs.iter().rev().skip(1).cloned());
1515+ for m in cands {
15111516 if self.fns.contains_key(&(m.clone(), last.clone())) {
15121517 return Some((m, last));
15131518 }
15141519 }
1515- None
1520+ // Nothing named the module. A path that names a crate rustnim was
1521+ // given as a whole file resolves here: if exactly one module has a
1522+ // function by this name, it is that one. Two would be a guess, so
1523+ // that is refused rather than picked from.
1524+ let mut hits = self.fns.keys().filter(|(_, n)| n == &last);
1525+ let first = hits.next()?;
1526+ if hits.next().is_some() {
1527+ return None;
1528+ }
1529+ Some(first.clone())
15161530 }
15171531
15181532 /// The Nim `proc` head for a Rust signature, used both for the forward
@@ -1504,15 +1504,29 @@ impl Lowerer {
1504 }1504 }
1505 }1505 }
1506 let imported = self.use_map.get(&last).cloned();1506 let imported = self.use_map.get(&last).cloned();
1507- for m in [Some(self.cur_mod.clone()), imported, Some(String::new())]1507+ // Any segment of the path may name the module the function is in.
1508- .into_iter()1508+ // `::enumflags2::_internal::next_bit` is in `enumflags2` when that
1509- .flatten()1509+ // crate arrives as one expanded file, and in `_internal` when the
1510- {1510+ // inline module is what carries the name.
1511+ let mut cands: Vec<String> = vec![self.cur_mod.clone()];
1512+ cands.extend(imported);
1513+ cands.push(String::new());
1514+ cands.extend(segs.iter().rev().skip(1).cloned());
1515+ for m in cands {
1511 if self.fns.contains_key(&(m.clone(), last.clone())) {1516 if self.fns.contains_key(&(m.clone(), last.clone())) {
1512 return Some((m, last));1517 return Some((m, last));
1513 }1518 }
1514 }1519 }
1515- None1520+ // Nothing named the module. A path that names a crate rustnim was
1521+ // given as a whole file resolves here: if exactly one module has a
1522+ // function by this name, it is that one. Two would be a guess, so
1523+ // that is refused rather than picked from.
1524+ let mut hits = self.fns.keys().filter(|(_, n)| n == &last);
1525+ let first = hits.next()?;
1526+ if hits.next().is_some() {
1527+ return None;
1528+ }
1529+ Some(first.clone())
1516 }1530 }
1517 1531
1518 /// The Nim `proc` head for a Rust signature, used both for the forward1532 /// The Nim `proc` head for a Rust signature, used both for the forward