-
Notifications
You must be signed in to change notification settings - Fork 13.3k
Trait methods can't be found by method resolution if the self
type involves projections
#121643
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
Comments
Of course, fixing this is also technically breaking (though unlikely problematic in practice, because who writes signatures like this?) because it not only causes compilation errors but also allows for fallbacks further down the line in method resolution candidates pub type Id<T> = <T as IdTrait>::T;
pub trait IdTrait {
type T: ?Sized;
}
impl<T: ?Sized> IdTrait for T {
type T = T;
}
#[derive(Copy, Clone)]
struct Foo;
impl Foo {
fn method_a(&self) {
println!("assoc method_a!");
}
fn method_b(&self) {
println!("assoc method_b!");
}
}
trait FooTrait {
fn method_a(self);
fn method_b(self: Id<Self>);
}
impl FooTrait for Foo {
fn method_a(self) {
println!("trait method_a!");
}
fn method_b(self) {
println!("trait method_b!");
}
}
pub fn main() {
let foo = Foo;
foo.method_a(); // trait method_a!
foo.method_b(); // assoc method_b!
}
|
@rustbot label +T-compiler, A-traits, A-typesystem, A-resolve, -needs-triage |
For anyone investigating this from the compiler side (i.e. I'm not gonna translate to normal people speech), this is because we're not normalizing the |
I gave it a try in normalizing
Alternatively, with
Both look very right to me. The hard part is to solve for the inference variable So @compiler-errors, would you mind dropping a hint at how this could be done? Thank you so much! |
Actually I have thought about it a bit more. I am not sure if unifying |
I think we can perform the normalization, but I don't think we can fulfill // We might override the blanket impl IdTrait if we have specialization in associated type
impl IdTrait for Baz {
type T = Foo;
}
// So then we need to use impl FooTrait for Baz. Should specialization allow this probe result, or no? cc @compiler-errors I have a tiny patch ready to just apply the normalization, but at this point I can't "solve" this issue entirely. |
@steffahn: I do not expect the code you shared to work as it is written.
@dingxiangfei2009: This code works in the new trait solver ( |
@compiler-errors With less compiler insight than you obviously, I was expecting it to work, because at some point the compiler (obviously) figured out that |
Also don’t forget that the code …somehow… did compile up to Rust |
No, the compiler does not typically "rewrite" things like this. We always start with an unnormalized signature and work forwards from there, which as I mentioned above, would result in ambiguity due the way that trait selection is implemented currently.
I see this instead as a shortcoming of the code that validates self types for method definitions. It currnetly uses a placeholder type (think of a skolem in haskell if you're familiar with that), which does allow projection to side-step the built-in ambiguity that we have when projecting the
Reminder that 1.21 was in 2017, and the type system has changed a lot since then. I wouldn't be surprised if whatever broke that code in 1.22 was a fundamental change that fixed normalization or something in the type system. |
…, r=<try> Use fulfillment in method probe, not evaluation This PR reworks method probing to use fulfillment instead of a `for`-loop of `evaluate_predicate` calls, and moves normalization from method candidate assembly into the `consider_probe`, where it's applied to *all* candidates. This last part coincidentally fixes rust-lang#121643 (comment). Regarding *why* this large rewrite is done: In general, it's an anti-pattern to do `for o in obligations { evaluate(o); }` because it's not compatible with the way that the new solver emits alias-relate obligations which constrain variables that may show up in other predicates. Putting this up for vibe-check mostly. Tests aren't yet blessed, and there are some nuances about whether it's worthwhile to restore regressed diagnostics. r? lcnr
…, r=<try> Use fulfillment in method probe, not evaluation This PR reworks method probing to use fulfillment instead of a `for`-loop of `evaluate_predicate` calls, and moves normalization from method candidate assembly into the `consider_probe`, where it's applied to *all* candidates. This last part coincidentally fixes rust-lang#121643 (comment). Regarding *why* this large rewrite is done: In general, it's an anti-pattern to do `for o in obligations { evaluate(o); }` because it's not compatible with the way that the new solver emits alias-relate obligations which constrain variables that may show up in other predicates. Putting this up for vibe-check mostly. Tests aren't yet blessed, and there are some nuances about whether it's worthwhile to restore regressed diagnostics. r? lcnr
…, r=<try> Use fulfillment in method probe, not evaluation This PR reworks method probing to use fulfillment instead of a `for`-loop of `evaluate_predicate` calls, and moves normalization from method candidate assembly into the `consider_probe`, where it's applied to *all* candidates. This last part coincidentally fixes rust-lang#121643 (comment). Regarding *why* this large rewrite is done: In general, it's an anti-pattern to do `for o in obligations { evaluate(o); }` because it's not compatible with the way that the new solver emits alias-relate obligations which constrain variables that may show up in other predicates. Putting this up for vibe-check mostly. Tests aren't yet blessed, and there are some nuances about whether it's worthwhile to restore regressed diagnostics. r? lcnr
Use fulfillment in method probe, not evaluation This PR reworks method probing to use fulfillment instead of a `for`-loop of `evaluate_predicate` calls, and moves normalization from method candidate assembly into the `consider_probe`, where it's applied to *all* candidates. This last part coincidentally fixes rust-lang/rust#121643 (comment). Regarding *why* this large rewrite is done: In general, it's an anti-pattern to do `for o in obligations { evaluate(o); }` because it's not compatible with the way that the new solver emits alias-relate obligations which constrain variables that may show up in other predicates. r? lcnr
I tried this code:
(playground)
I expected to see this happen: Code compiles successfully
Instead, this happened:
This is technically an old regression in
1.22
, the code compiled fine up to Rust1.21
.The text was updated successfully, but these errors were encountered: