Skip to content
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

Bringing a trait alias into scope doesn't allow calling methods from its component traits #56485

Closed
Nemo157 opened this issue Dec 3, 2018 · 11 comments · Fixed by #59166
Closed
Labels
A-resolve Area: Name resolution A-traits Area: Trait system I-needs-decision Issue: In need of a decision. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@Nemo157
Copy link
Member

Nemo157 commented Dec 3, 2018

#![feature(trait_alias)]

mod some_module {
    pub trait Foo {
        fn foo(&self);
    }
    
    pub struct Qux;
    
    impl Foo for Qux {
        fn foo(&self) {}
    }
    
    pub trait Bar = Foo;
}

use some_module::{Bar, Qux};

fn use_baz(object: Qux) {
    // Should this work because Bar is in scope?
    object.foo();
}

(playground) currently produces an error:

error[E0599]: no method named `foo` found for type `some_module::Qux` in the current scope
  --> src/lib.rs:21:12
   |
8  |     pub struct Qux;
   |     --------------- method `foo` not found for this
...
21 |     object.foo();
   |            ^^^
   |
   = 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:
   |
17 | use some_module::Foo;
   |

cc #41517

@Centril Centril added I-needs-decision Issue: In need of a decision. T-lang Relevant to the language team, which will review and decide on the PR/issue. A-resolve Area: Name resolution A-traits Area: Trait system labels Dec 3, 2018
@alexreg
Copy link
Contributor

alexreg commented Dec 3, 2018

Thanks for opening this. @Centril, what does your intuition say about this?

@Centril
Copy link
Contributor

Centril commented Dec 4, 2018

@alexreg The thing I'm currently thinking about is what makes sense when you extend it beyond this simple example; in particular, if we say: trait Foo = TraitA + TraitB; and then we use path::to::Foo;, does that then bring into scope both TraitA and TraitBs methods? what if there is a conflict in naming?

In other words, consider:

#![feature(trait_alias)]

mod alpha {
    pub trait A { fn foo(); }
    pub trait B { fn foo(); }
    pub trait C = A + B;
}

use alpha::C;

(this incidentally causes an ICE)

@alexreg
Copy link
Contributor

alexreg commented Feb 1, 2019

@nikomatsakis Thoughts on how feasible it would be to make this work, given the current state of the import system (about which I know little)?

@seanmonstar
Copy link
Contributor

If I were to import an alias, I'd likely often do so to call the methods off the trait as well as to set bounds. It'd be surprising if it didn't. If there is a name conflict, we can differentiate the way we do already: using UFCS with the specific trait, instead of the alias.

Is this the last thing needed to decide on for stabilization? The tracking issue makes it look that :D

@alexreg
Copy link
Contributor

alexreg commented Mar 8, 2019

@seanmonstar That's the last "feature" that really needs to be implemented, yeah. I'd be glad to help fix it, but I'd need some advice from someone who understand the import system, really. I've not touched that before.

@seanmonstar
Copy link
Contributor

I was playing around with this, trying to discover where the error happens, when I found that this doesn't happen if you make the function generic on the trait.

fn generic<T: Bar>(object: T) {
    // works!
    object.foo();
}

fn concrete_to_generic(object: Qux) {
    // works!
    generic(object);
}

As for if the trait alias contains multiple traits with the same name, the method conflict is already as expected: "multiple applicable items in scope", and qualifying with some_module::Fooz::foo(&object) works.

@alexreg
Copy link
Contributor

alexreg commented Mar 13, 2019

I'm not sure what you mean. Could you post a complete example on the playground?

@seanmonstar
Copy link
Contributor

Seems like nightly on the playground is timing out for me, but works locally: https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=92e4a4878c40c2a7a6af7a04f9cfd9ed

@alexreg
Copy link
Contributor

alexreg commented Mar 13, 2019

Ah right, I see. That makes sense because the type system resolves the type alias then, and not name resolution.

Nightly on the playground has been broken for a while now...

@petrochenkov
Copy link
Contributor

@seanmonstar
Candidates from bounds on a type parameters are treated like inherent and are found even if the trait is not in scope (the relevant code is in fn assemble_inherent_candidates_from_param).

@Centril
The example seems equivalent to

#![feature(trait_alias)]

mod alpha {
    pub trait A { fn foo() {} }
    pub trait B { fn foo() {} }
    // pub trait C = A + B;
    
    impl A for u8 {}
    impl B for u8 {}
}

// use alpha::C;
use alpha::*;

fn main() {
    u8::foo(); // ERROR multiple applicable items in scope
}

, the ambiguity error is already reported during resolution of a specific method in this case.

@petrochenkov
Copy link
Contributor

One interesting effect is that the traits become in scope in the module that defines (rather than imports) the alias.

#![feature(trait_alias)]

mod m {
    pub trait A { fn foo() {} }
    pub trait B { fn bar() {} }
    
    impl A for u8 {}
    impl B for u8 {}
}

trait C = m::A + m::B;

fn main() {
    u8::foo(); // OK
}

Centril added a commit to Centril/rust that referenced this issue Apr 1, 2019
…lexreg

resolve: collect trait aliases along with traits

It seems trait aliases weren't being collected as `TraitCandidates` in resolve, this should change that. (I can't compile the full compiler locally, so relying on CI...)

Fixes rust-lang#56485

r? @alexreg
Centril added a commit to Centril/rust that referenced this issue Apr 2, 2019
…lexreg

resolve: collect trait aliases along with traits

It seems trait aliases weren't being collected as `TraitCandidates` in resolve, this should change that. (I can't compile the full compiler locally, so relying on CI...)

Fixes rust-lang#56485

r? @alexreg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-resolve Area: Name resolution A-traits Area: Trait system I-needs-decision Issue: In need of a decision. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants