-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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
HRTB bounds not resolving correctly (take 2) #89196
Comments
Interestingly, if you change this to I think the problem here is we're unable to resolve what Theoretically, we can choose any |
I don't think we can make this code compile as-is. We need to pick a trait impl, and we can only do that if we know |
Ah, so specifying the type as |
Yeah, that should work. |
I think we've tripped up against "diagnostics are terrible when you're relying on the inference of |
Okay, so the suggest fix gets me further, but: Snippet: trait MiniDataProvider<M>
where
M: MiniDataMarker
{
fn mini_load_payload(&self) -> MiniDataPayload<M>;
}
impl<M> MiniDataProvider<M> for MiniStructProvider<M>
where
M: MiniDataMarker,
for<'a> <M::Yokeable as MiniYokeable<'a>>::Output: Clone,
{ ... }
let provider = MiniStructProvider { ... };
let payload: MiniDataPayload<SimpleStruct> = provider.mini_load_payload(); The compiler should figure out based on the type of However, it does work if I fully specify the trait: // Works!
let payload = MiniDataProvider::<SimpleStruct>::mini_load_payload(&provider); But, I cannot expect all the call sites to migrate to the fully-qualified trait function syntax. So, this is still a bug. |
@sffc That seems somewhat expected: There could potentially be multiple impls of |
There is exactly one |
That's not how inference sees this, though; it sees a complicated impl that it can't resolve without already knowing the concrete trait being dealt with. To be clear, there are two issues here:
Neither is an actual typesystem bug as originally reported. |
I agree with everything you said. To be clear, the bug in the inference engine really is a problem, as it blocks us (and others) from removing the "Wrap" workaround for #85636 as suggested in #85636 (comment) (see unicode-org/icu4x#1090). I would like this ticket to focus on the inference bug. |
Note the error message:
So, the compiler knows that the impl exists, and it wants to use it, but it can't because it thinks there are unsatisfied trait bounds. |
Yeah the diagnostics are definitely wrong here (we should perhaps file separate bugs for them -- both the one in the initial issue and the one in your updated code), but from talking to @eddyb it seems unlikely that the inference here can be improved any time soon, it's coming from a pretty important assumption in the inference engine. What's actually happening here is that the compiler is bailing on inference because it's not sure that it's solvable and is tripping a heuristic used to avoid infinite recursion in the inference engine. The wrapper hack works because this heuristic applies to cases where |
Filed a diagnostic issue: #89418 |
I think the reduction is not complete. What you want is this: let payload: MiniDataPayload<SimpleStruct> = MiniDataProvider::<_>::mini_load_payload(&provider); Basically the method call version tries this and fails it. If you actually call the method, but ask for the types to be inferred, you get more information:
This is why the wrapper hack works, it avoids hitting the " If the bound on the <M::Yokeable as MiniYokeable<'static>>::Output: Clone (check out on playground) So I believe what happens is:
What's interesting is that this can fail early even if For method calls, I can understand why (since But for
Somehow, this fails (presumably after inference is complete). Do we not try hard enough to resolve inference variables that came from replacing a not-yet-resolved projection, before giving up? |
Reconstructed the scenario I was guessing at (then further reduced it, because it turns out trait Trait<'a> {
type Out;
}
impl<'a, T> Trait<'a> for T {
type Out = T;
}
fn weird_bound<X>() -> X
where
for<'a> X: Trait<'a>,
for<'a> <X as Trait<'a>>::Out: Copy
{ todo!() }
fn main() {
let _: () = weird_bound();
} @jackh726 ^^ hopefully this is more useful. Zero method calls, just failing to propagate If I had to guess, it's failing to check if an inference variable was resolved before giving up somewhere. |
Yeah, I think this is falling into a class of bugs that I've been running into a lot recently. Basically, the general idea is that when we make a method call, we assign new inference vars as generics. We then add the required obligations, and try to normalize them. At this point, normalization fails because we have an inference variable as a Self type. And we also have late-bound vars in the projection, so we can't return a new inference var + obligation. This basically causes us to topple. The only thing that might work here as an "easy" solution is to try to delay normalization the required obligations until after we've done the expected type checking part (which means we'll have more into about the inference var, supposedly). Other than that, I think we're just back at the limit of what we can handle with late-bound vars in projections. And this might just have to wait until lazy norm. |
I have an example where even if you specify an explicit type, it does not resolve correctly: (play) Codestruct E<A, B> {
a: A,
b: B,
}
struct S;
impl S {
fn e<A, B>(&self, a: A, b: B)
where Self: R<E<A, B>>
{}
}
trait R<A> {}
impl<A> R<A> for S where A: Tr {}
trait Tr {}
trait HasItem {
type Item;
}
impl<T: IntoIterator> HasItem for T {
type Item = T::Item;
}
impl<T> HasItem for [T] {
type Item = T;
}
impl<A, B> Tr for E<A, B>
where
A: AsRef<[u8]>,
B: HasItem,
<B as HasItem>::Item: AsRef<[u8]>,
for<'a> &'a B: IntoIterator<Item = &'a <B as HasItem>::Item>,
for<'a> <&'a B as IntoIterator>::IntoIter: Clone,
{
}
const ST: &str = "";
const V: Vec<u8> = Vec::new();
fn main() {
let arr: [Vec<u8>; 1] = [V];
S.e(ST, arr);
} Failure:
|
More errors of this kind: #90638 |
Current output:
|
…imulacrum Add a few known-bug tests The labels of these tests should be changed from `S-bug-has-mcve` to `S-bug-has-test` once this is merged. cc: rust-lang#101518 rust-lang#99492 rust-lang#90950 rust-lang#89196 rust-lang#104034 rust-lang#101350 rust-lang#103705 rust-lang#103899 I couldn't reproduce the failures in rust-lang#101962 and rust-lang#100772 (so either these have started passing, or I didn't repro properly), so leaving those out for now. rust-lang#102065 was a bit more complicated, since it uses `rustc_private` and I didn't want to mess with that.
This is similar to the resolved issue #85636 , but details a newer iteration of that problem that has not yet been fixed.
Code example
(playpen)
This fails to compile on beta/nightly (stable does not have #85499 so we cannot expect this to compile) with:
The trait is implemented here:
for<'a> <SimpleStruct as MiniYokeable>::Output
is justSimpleStruct
, which implements Clone.cc @jackh726 @sffc
The text was updated successfully, but these errors were encountered: