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>
24296c3 parent: 47de6c6 modified
src/lower.rs +19 -5 | @@ -1504,15 +1504,29 @@ impl Lowerer { | ||
| 1504 | 1504 | } |
| 1505 | 1505 | } |
| 1506 | 1506 | 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 { | |
| 1511 | 1516 | if self.fns.contains_key(&(m.clone(), last.clone())) { |
| 1512 | 1517 | return Some((m, last)); |
| 1513 | 1518 | } |
| 1514 | 1519 | } |
| 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()) | |
| 1516 | 1530 | } |
| 1517 | 1531 | |
| 1518 | 1532 | /// 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 | - 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()) | ||
| 1516 | } | 1530 | } |
| 1517 | 1531 | ||
| 1518 | /// The Nim `proc` head for a Rust signature, used both for the forward | 1532 | /// The Nim `proc` head for a Rust signature, used both for the forward |