- 
                Notifications
    You must be signed in to change notification settings 
- Fork 13.9k
Description
I stumbled upon this issue by accident, as I noticed that using a symbol that has been imported in multiple glob statements does not result in an error:
mod foo {
    pub fn p() { println("foo"); }
}
mod bar {
    pub fn p() { println("bar"); }
}
mod baz {
   use foo::*;
   use bar::*;
   #[main]
   fn my_main() {
       p();
   }
}A simple oversight, I thought, and dove into resolve to fix the bug. Then I noticed that not even single imports are checked for conflicts:
mod foo {
    pub fn p() { println("foo"); }
}
mod bar {
    pub fn p() { println("bar"); }
}
mod baz {
   use foo::p;
   use bar::p;
   #[main]
   fn my_main() {
       p();
   }
}I assumed that the reason for this was that currently both glob and single imports are flattened into a hashmap per module and tried to introduce a 2-level import scheme that allows duplicates only in glob imports but not in single imports.
And then I noticed that it's possible to export glob imports from a crate, making that scheme impossible. Even worse: this makes the global API of a crate dependent on the vigilance of the developer to not export multiple symbols with the same name, as a simple rearranging of use statements in the source code could break existing users of the crate.
So, there are four possible ways to go about this problem:
- 
Don't change anything. I.e. don't check for duplicate imported symbols, neither single imports nor glob imports. (Maybe add a lint, but that would probably have to be turned of in many cases, e.g. libstdis full of duplicate glob imports).
- 
Disallow duplicate imports, even when glob importing. This is IMO not workable. 
- 
Disallow exporting glob imports from crates, making the aforementioned 2-level duplicate checking possible (i.e. disallow duplicate single imports, disallow used duplicate glob imports, allow unused duplicate glob imports). 
- 
A variant on 3): allow exporting glob imports, implement the 2-level scheme for imports that are not visible from outside the crate, but disallow any duplicate imports otherwise. 
- 
or 4) would be my preferred solution, but would incur a lot of work, both in implementing the scheme and restructuring existing code. 1) is the most realistic solution, but I personally don't really like it, as Rust is all about safety after all. 
Fun example at the end:
mod foo {
    pub fn p() { println("foo"); }
}
mod bar {
    pub fn p() { println("bar"); }
}
mod baz {
   use bar::p;
   use foo::*;
   #[main]
   fn my_main() {
       p();
   }
}Here, the use foo::*; is marked as being unused, even though when running the program, foo::foo() is actually the implementation of foo() that is used.