Repository navigation
Ambiguity errors in 2018 uniform import paths are not technically necessary #56414
Description
Activity
- addedA-resolveArea: Name/path resolution done by `rustc_resolve` specificallyArea: Name/path resolution done by `rustc_resolve` specificallyT-langRelevant to the language teamRelevant to the language team
on Dec 1, 2018 👍 for "remove ambiguity warnings for any case except local name versus extern crate".
- addedC-tracking-issueCategory: An issue tracking the progress of sth. like the implementation of an RFCCategory: An issue tracking the progress of sth. like the implementation of an RFC
on Jan 24, 2019 If I understand your proposal correctly, then I believe that the following example (albeit perhaps contrived) would render quite paradoxical:
pub mod a { // outer decl pub mod a {} // inner decl } pub mod b { use super::*; // outer use pub fn f() { // inner use use a::*; } }
How does the name
ain the inner use statement resolve? If the top level module declaration is in scope (by the outer use statement), then the inner module declaration should also be available by means of the inner use statement. By lifting the ambiguity restriction, this declaration should shadow the outer declaration from being in scope.In short: the outer declaration is only in scope, if it is not in scope. Or something like that :)
This is "Rustell's paradox", and the restriction that you describe seems to ensure that it is only barely dodged in the Rust name semantics.FWIW, I am not a Rust programmer, so forgive me if I misunderstood the semantics or your proposal. I am interested in name binding semantics however and I figured the above example was worth keeping in mind.
@ajrouvoet
The "name vs any other name during import resolution" error is not the last line of defense against paradoxes like this :)This example will likely cause the "glob import vs any other name from outer scope during import/macro resolution" error if the "name vs any other name during import resolution" restriction is removed.
I can check today, the fix for this issue is a one-line change in the compiler (this
ifbranch https://github.com/rust-lang/rust/blob/master/src/librustc_resolve/macros.rs#L782 needs to be removed).Thanks for having a look; I'm very curious about this.
I can see how the type-checker may guard against this specific scenarios. At the same time I wonder if one could still give a declarative semantics of name resolution in Rust for the result. It may be unwanted that name resolution can only be explained in the end in terms of what the implemented algorithm can/cannot resolve. This seems important for reasoning about the language, for explaining rust to programmers, but also for tools that strive for conformance with the reference rust compiler.
I wonder if one could still give a declarative semantics of name resolution in Rust for the result.
It should certainly be possible to compact the specification of import resolution behavior into something shorter than its implementation in the compiler.
AFAIK, there were some plans to build an isolated name resolution model outside of the compiler, but I'm not aware of any concrete results following from those plans.The general idea behind the ambiguity errors in particular is that we report an error if some name in inner scope can "materialize" later (due to import dependencies, or macro expansion) than the same name in outer scope.
#53778 (comment) describes how this general idea applies to macros.
With globs the situation is simpler - a name can "materialize" from a glob arbitrarily late, so a name from a glob in inner scope can never coincide with any name in outer scopes.#![feature(decl_macro)] mod m { pub macro a() {} } macro a() {} // Outer scope fn main() { use m::*; // Inner scope a!(); // error[E0659]: `a` is ambiguous (glob import vs any other name from outer scope during import/macro resolution) }
There's a similar issue when an item being imported has the same name as the path being used.
mod users { pub struct table; pub mod dsl { pub use super::table as users; } } fn main() { use users::dsl::*; }
Outputs:
error[E0659]: `users` is ambiguous (name vs any other name during import resolution) --> src/main.rs:9:9 | 9 | use users::dsl::*; | ^^^^^ ambiguous name | note: `users` could refer to the struct imported here --> src/main.rs:9:9 | 9 | use users::dsl::*; | ^^^^^^^^^^^^^ note: `users` could also refer to the module defined here --> src/main.rs:1:1 | 1 | / mod users { 2 | | pub struct table; 3 | | pub mod dsl { 4 | | pub use super::table as users; 5 | | } 6 | | } | |_^An import should never be ambiguous with itself.
- addedS-tracking-needs-summaryStatus: It's hard to tell what's been done and what hasn't! Someone should do some investigation.Status: It's hard to tell what's been done and what hasn't! Someone should do some investigation.
on Jun 8, 2022 We discussed this in today's @rust-lang/lang meeting. We think that this could potentially be removed at this point, given that we've long-since settled on a specific module-system model, but we'd like to confirm which cases still produce errors (in order to confirm that those errors aren't actually catching anything of value), and whether further changes have reduced the set of things that produce errors.
Another way of putting this:
- Is the check sufficiently annoying to users that we should remove it?
- Another take: does it provide so little utility that we should remove it because it is more trouble to continue supporting it?
I implemented this change in #112086.
- added a commit that references this issue
on Jun 30, 2024 - added a commit that references this issue
on Jul 25, 2024 - added a commit that references this issue
on Dec 11, 2024
Right now import resolution on 2018 edition fails with an ambiguity error if multiple candidates are found:
This is different from non-import paths in which resolutions from closer scopes are preferred without errors.
This restriction is technically unnecessary and exists because some people were uncomfortable with disambiguation happening in import paths specifically (see previous threads, ... many of them, #55618 being the latest one).
This restriction can be lifted fully or partially if it causes too much trouble in practice with ambiguity errors, or with addition of new names to libraries being backward-incompatible due to new ambiguities.
(By "partially" I mean e.g. "disambiguation is okay, unless one of the candidates is an extern crate" or something like that.)