You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Method resolution should obey usual shadowing rules for glob imports & prelude #51497
Today item import take precedence over glob imports which take precedence over prelude imports. This works for traits:
mod a {pubtraitX{fnx(&self){println!("a");}}implXfor(){}}mod b {pubtraitX{fnx(&self){println!("b");}}implXfor(){}}use a::X;use b::*;fnmain(){().x();// Works and prints "a", b/c b is shadowed}
However, this logic does not work for trait methods. If we rename b::X to b::Y, the code fails to compile:
mod a {pubtraitX{fnx(&self){println!("a");}}implXfor(){}}mod b {pubtraitY{fnx(&self){println!("b");}}implYfor(){}}use a::X;use b::*;fnmain(){().x();// error: multiple `x` found}
Hm, not sure that #31908 is exactly what I am thinking about. That PR tweaks the logic of shadowing the trait itself, but not the methods.
That is, I imagine the rule like "if both Foo::x and Bar::x are applicable methods, but Foo trait is brought in scope via a glob/prelude import and Bar is imported/defined explicitly, do not report error and resolve ambiguity in favor of Bar".
I think I ran into a problem that is related to this during a workshop yesterday.
Here's a minimal reproduction of the problem:
mod submodule {pubtraitMyThing{fnfoo(){}}pubstructA{}implMyThingforA{}}use submodule::*;typeMyThing = A;fnmain(){MyThing::foo();}
I'm using a submodule here, but in the workshop this was coming from an external crate and the problem was much less obvious because there were many other items being imported.
The problem was that both the participant and I expected that since we were using a glob import, the trait MyThing would already be imported, but the error message was recommending that we import it:
error[E0599]: no function or associated item named `foo` found for type `submodule::A` in the current scope
--> src/main.rs:16:14
|
6 | pub struct A {}
| ------------ function or associated item `foo` not found for this
...
16 | MyThing::foo();
| ---------^^^
| |
| function or associated item not found in `submodule::A`
|
= help: items from traits can only be used if the trait is in scope
help: the following trait is implemented but not in scope, perhaps add a `use` for it:
|
11 | use crate::submodule::MyThing;
|
Usually, when you redefine a type in Rust, it's an error, but for glob imports the shadowing can lead to these kinds of errors that aren't really obvious given the semantics that many of us expect.
I think for my particular case it might be better to adjust the error message to deal with this edge case rather than adjust the trait resolution behaviour at all.
@petrochenkov Can we try doing this again, or at least having the information propagated to the type-checker?
I don't know why I never thought of this (nor recall seeing this issue), but it seems like a great solution for putting more traits in the prelude (with as _) and not worry about introducing ambiguity to users.
or at least having the information propagated to the type-checker?
Resolver builds sets of trait in scope for every method location and when it adds a trait into the set it knows how it was introduced - with a glob, or with a single import or definition, or with prelude.
So it certainly can pass it further to type checker for use.
Note that traits don't shadow each other in the "trait in scope" set, but rather form a union
mod m {pubtraitTrait1{fnfoo(){}}pubtraitTrait2{fnbar(){}}implTrait1foru8{}implTrait2foru8{}}use m::Trait1asTrait;fnmain(){use m::Trait2asTrait;
u8::bar();// OK
u8::foo();// OK too, despite Trait2 "shadowing" Trait1}
so if the priority for method resolution is based on "glob"-ness, then the results could be slightly inconsistent with usual resolution
mod m {pubtraitTrait1{fnfoo(){}}implTrait1foru8{}}mod n {pubtraitTrait2{fnfoo(){}}implTrait2foru8{}}use m::Trait1;fnmain(){use n::*;
u8::foo();// Now: ERROR multiple applicable items in scope// Proposed: OK, Trait1::foo is selected despite Trait2 being// "closer in scopes" and "shadowing" Trait1.}
The T-lang team discussed this in their weekly meeting today.
Our basic reaction was that the change proposed here would at least require some investigation to determine what all the implications are.
From our understanding of the discussion here, it appears to be an open question whether or not this change would solely cause strictly more code to be accepted (and not change the behavior of programs that are accepted today).
We think that a PR that implements the change being described (since that sounds relatively simple?) would be a great first step in such an investigation, since that would be something we could get crater results on.
Note as well that a successful crater run is a necessary condition, but it is not a sufficient condition on its own to justify the change.
Some T-lang members want to ensure we also consider the overall effect on the semantics of method resolution as well.
Will this also fix the bug with glob imports shadowing public imports? - i.e.:
mod a {mod b {pubfnsomething(){}}pubuse b::*;use b::something;// overrides "pub use b::something"fnother(){something()}}fnmain(){// error: "function something is private"!
a::something();}
I ran into this problem a few days ago and could explain why the function was private, even though I re-exported it via pub use. This is a problem because now I need to check every time if I have a use and a pub use statement referencing the same module, which is tedious. Not sure if this is the right place to ask this, but it seemed related.
@fschutt seems unrelated to this issue, which is specifically for method resolution. Your example seems to be expected behavior: non-glob imports shadow (are stronger than) glob ones.
Activity
petrochenkov commentedon Jun 11, 2018
There was an attempt to do it in #31908 and apparently there was breakage.
petrochenkov commentedon Jun 11, 2018
We can probably redo that experiment again, look how many crates break, maybe make the change edition-specific.
matklad commentedon Jun 11, 2018
Hm, not sure that #31908 is exactly what I am thinking about. That PR tweaks the logic of shadowing the trait itself, but not the methods.
That is, I imagine the rule like "if both Foo::x and Bar::x are applicable methods, but Foo trait is brought in scope via a glob/prelude import and Bar is imported/defined explicitly, do not report error and resolve ambiguity in favor of Bar".
sunjay commentedon Mar 30, 2019
I think I ran into a problem that is related to this during a workshop yesterday.
Here's a minimal reproduction of the problem:
I'm using a submodule here, but in the workshop this was coming from an external crate and the problem was much less obvious because there were many other items being imported.
The problem was that both the participant and I expected that since we were using a glob import, the trait
MyThingwould already be imported, but the error message was recommending that we import it:Usually, when you redefine a type in Rust, it's an error, but for glob imports the shadowing can lead to these kinds of errors that aren't really obvious given the semantics that many of us expect.
I think for my particular case it might be better to adjust the error message to deal with this edge case rather than adjust the trait resolution behaviour at all.
eddyb commentedon Mar 30, 2019
@petrochenkov Can we try doing this again, or at least having the information propagated to the type-checker?
I don't know why I never thought of this (nor recall seeing this issue), but it seems like a great solution for putting more traits in the prelude (with
as _) and not worry about introducing ambiguity to users.cc @rust-lang/libs
petrochenkov commentedon Mar 30, 2019
@eddyb
Resolver builds sets of trait in scope for every method location and when it adds a trait into the set it knows how it was introduced - with a glob, or with a single import or definition, or with prelude.
So it certainly can pass it further to type checker for use.
petrochenkov commentedon Mar 30, 2019
Note that traits don't shadow each other in the "trait in scope" set, but rather form a union
so if the priority for method resolution is based on "glob"-ness, then the results could be slightly inconsistent with usual resolution
eddyb commentedon Mar 30, 2019
I would expect them to shadow eachother when the method name clashes, i.e. completely disregarding the trait name.
Centril commentedon Apr 4, 2019
T-Lang did not have sufficient time to discuss this; leaving for next week.
pnkfelix commentedon Apr 18, 2019
The T-lang team discussed this in their weekly meeting today.
Our basic reaction was that the change proposed here would at least require some investigation to determine what all the implications are.
We think that a PR that implements the change being described (since that sounds relatively simple?) would be a great first step in such an investigation, since that would be something we could get crater results on.
fschutt commentedon Apr 19, 2019
Will this also fix the bug with glob imports shadowing public imports? - i.e.:
playground
I ran into this problem a few days ago and could explain why the function was private, even though I re-exported it via pub use. This is a problem because now I need to check every time if I have a
useand apub usestatement referencing the same module, which is tedious. Not sure if this is the right place to ask this, but it seemed related.matklad commentedon Apr 19, 2019
@fschutt seems unrelated to this issue, which is specifically for method resolution. Your example seems to be expected behavior: non-glob imports shadow (are stronger than) glob ones.