That ambiguity between module local or crate item can be avoided by writing use self::modname::*
or use crate::modname::*
instead to disambiguate. But yes, all item name resolution needs to remain fully unambiguous after all macro expansion is complete.
There could (and would need to) be similar rules for implicit module mounting — e.g. consider all unresolved use
to be module mounting after all macros that can be resolved without implicit mod
have been expanded — but while it should be fully feasible to do so, the question is whether it's worth making name resolution even more complicated.
It still could be. Default binding modes (also known as match ergonomics) are another feature which serves to make the simple common case simpler at the expense of making in this case type inference for the bindings more complicated.
But there are two still common cases where implicit module mounting can be problematic:
- Module visibility. Still requiring
pub use modname
for any module paths that aren't okay with being mod local means a majority of modules will just replacepub mod
withpub use
and no other differences. Learning how to manage multiple source files once seems better than learning once for file splitting and again later for module organization[1]. - Modules that don't export any items to be
use
d. If requiring a module always meant ause
it'd be more obviously desirable to makeuse
the way to load the module, butimpl
s don't need to beuse
d and can be in any module. So a module that doesn't export any items to outside the module still needs to be mounted despite ause
of the module being "unused" except for the side effect ofmod
loading.
Then there's some bonus questions: does use super::modname
work to mount a sibling module, or does implicit mod
only work for self::modname
paths (after resolution)? What about qualified paths not part of a use tree? If only specifically a use self::
works, I suspect "missing use
" issues to come up in similar volume to "missing mod
" today.
The error I've actually seen more often — writing mod m
to access a sibling module instead of use super::m
— isn't even addressed by implicit mod
. (And might even make it worse. Thinking mod m
looks for ./m.rs
or ./m/mod.rs
is easy, but this is only true in mod.rs
or the crate root file; the search path is actually based on module path[2] instead.)
I can imagine this leading to someone writing
pub mod foo { pub use bar::*; }
due to decoupling the concept of "module" from "file" and learninguse file::*
as the way to splitmain.rs
into multiple files. ↩︎Rooted from the closest parent module with an explicit
#[path]
specified. Pre-2018,mod
was only allowed in crate root,mod.rs
, or#[path]
modules, which made this less divergence harder to discover. ↩︎