-
Notifications
You must be signed in to change notification settings - Fork 13.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Disallow methods from traits that are not in scope #31908
Conversation
200383b
to
6dd4548
Compare
} | ||
impl T for () {} | ||
|
||
fn g<T>() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
to be fully consistent, we need to also update E0256
("import T
conflicts with type in this module"), because "use self::T;" will still work in the generic function g
, but not in h
.
6dd4548
to
bfa7fc4
Compare
Now that I see the impact, I have some concerns about both backwards compat, and that this might just not be the right rule. I hadn't fully considered that shadowing with any arbitrary type would rule out using the methods from a trait as well. For example, this change does not impact the iterator naming pattern, because we name the types Another example might be I've yet to come up with an actual problematic example, but at minimum a crater run seems worthwhile. cc @rust-lang/lang |
Crater run executing. |
Crater run result: https://gist.github.com/nikomatsakis/23a0ed555ecf83287c25 5 regressions. |
Ok, I believe these are our options:
|
☔ The latest upstream changes (presumably #31726) made this pull request unmergeable. Please resolve the merge conflicts. |
bfa7fc4
to
8774852
Compare
Having thought about this some more, I feel like this rule may in fact be the one that I find most intuitive. Admittedly, I argued the opposite in the past, but thinking about examples like this sort of changed my mind: fn foo<Default>(...) -> Default {
...
let x = SomeType::default();
...
} |
21ce5cb
to
d08b0c6
Compare
That example would still work since it uses UFCS, but your point stands. I updated this PR to use the compromise rule (i.e. allow traits from ancestor scopes). The only remaining regression is Thinking about this some more, I actually prefer this approach since I think we should consider the prelude not as something that gets imported into all* modules' scopes but instead as its own scope that is the parent of all modules' scopes. @nrc suggests this interpretation in his sets of scopes blog post. This interpretation would mean that we permanently treat the prelude like we currently treat all private imports; for example, we would never allow prelude-"imported" names to be used in a crate relative path or imported into another module. *except for |
I would not expect my example to work, even though it uses UFCS. The set of traits in scope for a UFCS call like
Hmm. I would find this a little surprising...
...but when you put it like that, it kind of makes sense. cc @rust-lang/lang, thoughts?
I think both @nrc and I would like to change "private imports" so that they behave precisely like all other items (e.g., |
ok, chatted briefly with @aturon on IRC, conclusion was that we should discuss again in the next @rust-lang/lang meeting :) |
Makes sense -- for some reason I thought the trait search only applied to non-UFCS methods.
As would @petrochenkov and I. I think the prelude should be treated differently from private imports (well, the prelude is already treated differently since it is shadowable by globs) in part because otherwise, mod foo {
pub type Result = ();
}
mod bar {
// use super::*; // uncommenting this line would import `Result` from `super`'s prelude ...
use foo::*;
fn f() -> Result { () } // ... making this an ambiguity error.
} It seems wrong for the prelude to be shadowable but for the names imported from another module's prelude to not be shadowable (and to shadow the original prelude). @petrochenkov also argues for treating the prelude differently in #31726. |
@jseyfried ok, I'm basically convinced that treating the prelude as a 'level above' in the scope makes sense. |
☔ The latest upstream changes (presumably #32141) made this pull request unmergeable. Please resolve the merge conflicts. |
d08b0c6
to
f7cb841
Compare
f7cb841
to
ed8a2e2
Compare
@nikomatsakis I amended this PR to treat the prelude as a level above in the scope hierarchy, i.e. to always allow prelude traits and only disallow shadowed glob-imported re-exports. |
After discussing in @rust-lang/lang, decided to adopt this approach where prelude is a scope above the other scopes. Thanks @jseyfried for your patience as always! |
@nikomatsakis no problem! This is ready to land pending your review (there's not much to review). After this lands, the rebase of #32167 will remove |
@bors r+ @jseyfried heh, when I looked at the code this morning, I was a bit surprised -- I expected a bit more. Anyway, going to work hard on getting to your other PRs now! |
📌 Commit ed8a2e2 has been approved by |
…akis Disallow methods from traits that are not in scope This PR only allows a trait method to be used if the trait is in scope (fixes #31379). This is a [breaking-change]. For example, the following would break: ```rust mod foo { pub trait T { fn f(&self) {} } impl T for () {} } mod bar { pub use foo::T; } fn main() { pub use bar::*; struct T; // This shadows the trait `T`, ().f() // making this an error. } ``` r? @nikomatsakis
This PR only allows a trait method to be used if the trait is in scope (fixes #31379).
This is a [breaking-change]. For example, the following would break:
r? @nikomatsakis