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

Nested associated type projection is overly conservative #38078

Open
aturon opened this issue Nov 29, 2016 · 27 comments
Open

Nested associated type projection is overly conservative #38078

aturon opened this issue Nov 29, 2016 · 27 comments
Labels
A-trait-system Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@aturon
Copy link
Member

aturon commented Nov 29, 2016

The following setup

trait OneTrait {
    type Ty: AnotherTrait;
    fn project() -> Self::Ty::Out;
}

trait AnotherTrait {
    type Out;
}

produces the error

rustc 1.13.0 (2c6933acc 2016-11-07)
error[E0223]: ambiguous associated type
 --> <anon>:3:17
  |
3 |     fn bar() -> Self::Bar::Out;
  |                 ^^^^^^^^^^^^^^ ambiguous associated type
  |
  = note: specify the type using the syntax `<<Self as Foo>::Bar as Trait>::Out`

It would be great for the less explicit projection to work here.

cc @nikomatsakis

@aturon aturon added the A-trait-system Area: Trait system label Nov 29, 2016
@aturon
Copy link
Member Author

aturon commented Nov 29, 2016

Note that the issue title may be overly specific; I haven't deeply investigated the cases where this kind of projection fails.

@alexcrichton
Copy link
Member

In my experience at least A::B::C never works, although maybe bugs have been fixed that enables that recnetly?

@petrochenkov
Copy link
Contributor

FWIW, <<Self as Foo>::Bar as Trait>::Out can be shortened to <Self::Ty as AnotherTrait>::Out.
A::B for associated types currently works only if A is a type parameter (including Self) that is known to have a trait with associated type B as a bound.

@malbarbo
Copy link
Contributor

Possible duplicates: #31372 and #35711

@nikomatsakis
Copy link
Contributor

In terms of the compiler's implementation, this isn't really about projection. It's not actually getting that far. Rather, it fails when lowering the AST into types, which is the point where we have to pick a trait. @eddyb has been doing a lot of heroic work refactoring the type-end to remove that limitation, which is fairly tricky -- the problem is that to do it properly, one must reason about the where-clauses that are in scope and do trait selection, but to know what where-clauses are in scope, one must lower them, and that is what we are trying to do. To resolve this, @eddyb has been refactoring the compiler to cope with partially lowered sets of where-clauses, basically.

@neuronsguy
Copy link

So, is @eddyb's fix for this being developed openly somewhere it's possible to track progress (or help?) This issue is causing me some frustration, so I'd love to know what I could do to help resolve it.

@nikomatsakis
Copy link
Contributor

I think he wound up taking another approach. I'm not sure what's the shortest path here just now.

@eddyb
Copy link
Member

eddyb commented Mar 16, 2017

Perhaps keying the type_param_predicates requests on a type instead of just type parameters specifically, and treating failure to convert some types in bounds as an ambiguity, may work.

@gnzlbg
Copy link
Contributor

gnzlbg commented Oct 25, 2017

This is a huge paper cut for me: I have a lot of code of the form <<<<F as E>::E as D>::D as C>::C as B>::B as A>::A> and it is completely unreadable to write methods on traits while having to skim through that.

There are two cases where this cuts me:

  • when I know that there isn't an ambiguity yet I have to disambiguate
  • when I doubt if there is an ambiguity and might not want one, in which case I need to go through the whole trait hierarchy looking for it because... even though the error says "ambiguous" it doesn't bother telling me where the ambiguities are...

Having to disambiguate is the smaller paper cut. It would already be infinitely helpful if the error message would tell me if there is an actual ambiguity and where, or if it would tell me that there isn't an ambiguity.

@gnzlbg
Copy link
Contributor

gnzlbg commented Oct 25, 2017

Maybe the problem is that what I understand by ambiguous (e.g. that two associated types are named equal) and what the compiler understands by ambiguous are different things.

@zesterer
Copy link
Contributor

I've tried using syntax, that one would expect to work just fine, and have wound up with this issue. It's quite clear to any human that there exist no ambiguities in this code, yet the compiler unnecessarily requires extra (and ugly) syntax to accept the code. This is extremely inconvenient.

@alexlitty
Copy link

I'm not sure if chiming in and saying "me too" at this point is more annoying than helpful, but me too :)

I think this one's hard on novice Rustaceans because we're interpreting the situation as human error, as if we've unintentionally made the situation ambiguous and there's something we can do to correct it.

@tiby312
Copy link

tiby312 commented May 5, 2018

I would also love this. I've been "shortening" it like this, but this way there is an extra associated type that structs have to implement for no reason:

trait OneTrait {
    type Ty: AnotherTrait<Out=Self::Oy>;
    type Oy;
    fn project() -> Self::Oy;
}

trait AnotherTrait {
    type Out;
}

@purpleposeidon
Copy link

At the very least, the error message should be improved; it gives bad advice:
[Playground]

@ZacLiveEarth
Copy link

Is this issue one that someone could take on as a first issue for fixing the compiler or is this still in the area of experts? It seemed like something quite hard a while ago, but maybe progress has been made? If this is something easier than it used to be, could someone point me to the area of code that would need to be fixed?

@eddyb
Copy link
Member

eddyb commented May 13, 2019

Sadly, not enough progress has been made for this to be readily doable yet.

@AlterionX
Copy link

Has there been any progress on this front? Was just curious if there was/will be/is planned to have an update of some sort.

daniel5151 added a commit to daniel5151/gdbstub that referenced this issue Jun 24, 2020
Ah ha! No more leaking GDB internals to users*!

*Assuming the user is using an architecture listed already implemented
under the `arch` module, they don't have to dig through the GDB source
for some obscure XML files.

The unfortunate side-effect of this change is the really digusting type
syntax which `Target` has to use. `<Self::Arch as Arch>::Usize` is
really gnarly :sad:

If rust-lang/rust#38078 ever gets fixed,
the type could be re-written as `Self::Arch::Usize`, which is a _lot_
cleaner.
@jplatte
Copy link
Contributor

jplatte commented Aug 10, 2020

Will chalk resolve this?

@Shelim
Copy link

Shelim commented Aug 10, 2020

Still happens with Rust 1.45.2

Following code:

pub struct MyStruct {
    rng : rand::Rng::SmallRng
}

Outputs:

 error[E0223]: ambiguous associated type
    --> src\algorithm\m_struct.rs:11:11
       |
    11 |     rng : rand::Rng::SmallRng,
       |           ^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn rand::Rng + 'static) as Trait>::SmallRng`

Is there any workaround?

@nikomatsakis
Copy link
Contributor

chalk will not resolve this without more work, though we did have some experimental ideas for how to resolve it.

@Yuri6037
Copy link

This also is a problem with non-nested types:

trait T
{
    type M : Sized;
}

struct S
{
    some_var: u32
}

impl T for S
{
    type M = u32;
}

fn main()
{
    let v: S::M = 0;
}

Output:

error[E0223]: ambiguous associated type
  --> src/main.rs:18:12
   |
18 |     let v: S::M = 0;
   |            ^^^^ help: use fully-qualified syntax: `<S as Trait>::M`

error: aborting due to previous error

@crlf0710
Copy link
Member

I'm not super convinced. I think it's reasonable to ask rustc_resolve to give an initial "associated item or variant" lookup or something.
If it's resolved without ambiguity, an error should not be emitted to the user.

This kind of resolution is easy victim to upstream associated item changes. However for ergonomics it might be worth it?

@duaneking
Copy link

At least give me an error that tells me what to do? Because the current output is insanely bad for developer productivity; It should be telling me what options it thinks it has and why its considered ambiguous.

@VladasZ
Copy link

VladasZ commented Apr 7, 2022

Any progress on this?

@iximeow
Copy link
Contributor

iximeow commented Aug 9, 2023

i've been dancing around this issue in some form or another for a few years and i only just realized that another workaround for this is writing a type alias to at least hide the process of walking rustc through the type relationships:

pub trait ATrait {
    type B: BTrait;
}

pub trait BTrait {
    type C: CTrait;
}

pub trait CTrait {}

// this works! i can go simplify several crates now. yay.
pub type AToC<A> = <<A as ATrait>::B as BTrait>::C;

pub fn project<A: ATrait>() -> AToC<A> {
    panic!("C");
}

this is similar to tiby312's comment a few years ago but i hadn't fully considered that the type alias could be freestanding and organized elsewhere as appropriate.

@thijsc
Copy link

thijsc commented Dec 1, 2024

Just chiming in that it would be really nice if this was possible. I came up with a nice refactor that turned out to be not practical because it's not ergonomic to use a type nested in the trait in a trait implementation. It would be really nice if this was possible.

@zesterer
Copy link
Contributor

zesterer commented Dec 1, 2024

Am I right in thinking that this is caused by rustc not having a notion of 'trait variables' (akin to type variables) within its solver? I've added support for trait variables to my own lang and it seems to be pretty reliably capable of arbitrary associated type projection like this.

tgross35 added a commit to tgross35/rust-libm that referenced this issue Dec 22, 2024
The ambiguous associated types error sometimes fires in cases where it
shouldn't be ambiguous ([1]), which can make things clunky when working
with chained associated types (e.g. `Op::FTy::Int::*` does not work).
Add helper types that we can use instead of the full syntax.

There aren't too many cases in-crate now but this is relevant for some
open PRs.

[1]: rust-lang/rust#38078
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-trait-system Area: Trait system C-bug Category: This is a bug. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests