Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign upICE: OutputTypeParameterMismatch in failing to resolve associated type as tuple. #33364
Comments
rphmeier
added a commit
to rphmeier/Snorkium
that referenced
this issue
May 3, 2016
Aatch
added
the
regression-from-stable-to-beta
label
May 3, 2016
This comment has been minimized.
This comment has been minimized.
|
Removing the higher-ranked lifetimes appears to make it work. Interestingly, the MIR typecheck seems to be picking up the error indirectly, as the warnings disappear once that is fixed. This is still a bug, but changing the impl<'a, T: Foo<'a>> Wrap<T> {
fn consume<F>(f: F) where F: Fn(<T as Foo<'a>>::Item) {
self.foo.consume(f);
}
}works. I assume the reason is that there's no link between the lifetime in the bound on The error in the case where your destructing in the parameter list is correct, though not very helpful. |
This comment has been minimized.
This comment has been minimized.
|
Could you elaborate on why you believe the error message to be correct? It is my understanding that you can destructure tuples in a function or closure's argument list. This function is accepting a tuple as the argument but is not allowing destructuring within the argument list. |
This comment has been minimized.
This comment has been minimized.
|
@rphmeier ah, I was focussed on the error and missed the fact that the first case works on stable. It's not about whether or not you can or can't destructure in an argument list (you can). The error is about a type-mismatch. The use of higher-ranked lifetimes here isn't correct, and causes the types not match. Why the let-destructuring works on stable is beyond me though. |
nrc
added
the
T-compiler
label
May 5, 2016
This comment has been minimized.
This comment has been minimized.
|
triage: P-high |
rust-highfive
added
the
P-high
label
May 5, 2016
pnkfelix
self-assigned this
May 19, 2016
This comment has been minimized.
This comment has been minimized.
|
This may have been obvious to others, but just to confirm: reproducing the issue described does not require using a 3-tuple. A 1-tuple However, the behavior changes in a subtle manner if you try to go all the way to removing the tuple entirely (e.g. |
This comment has been minimized.
This comment has been minimized.
|
Nominating; I currently agree with @Aatch's analysis that the original code should (probably) have been rejected by the compiler, but I am not clear on what the appropriate course of action is to take this time. Namely, we are currently in a situation where we are both emitting a warning from mir typecheck, and then subsequently erroring during
So my question is: Should we either:
|
pnkfelix
added
the
I-nominated
label
May 25, 2016
This comment has been minimized.
This comment has been minimized.
|
Here is a gist of a somewhat reduced version of the issue: notably, it is set up so that you can pass I said earlier that the original code probably should have been rejected, but the more I look at this, the more uncertain I become about that claim. (To me it comes down to a question of whether the |
This comment has been minimized.
This comment has been minimized.
|
Thanks for looking into this @pnkfelix -- I'm not particularly knowledgeable about the intricacies of HRTBs, but my intuition when I was writing this code went as like this: |
This comment has been minimized.
This comment has been minimized.
|
So I looked into this. My feeling is that the underlying problem here is that we do not attempt to normalize under a higher-ranked binder -- this is why (e.g.) stable fails to understand the argument type. This is definitely a pre-existing issue (and there are a number of open issues related to it), but I'm not sure why we started to ICE when we did not before. |
This comment has been minimized.
This comment has been minimized.
|
Did more digging. The story is a bit more complex, but I think more readily fixed. It turns out that, in the main typeck pass, we do indeed fail to normalize the type of the parameter in the closure. But, because references to local variables go through the same procedure that computes the types for references to items, we put those same types through the same instantiation procedure, which applies substitutions and then does normalization. In this case, there are no substitutions to apply, but we still do it. And this causes us to normalize the type of the argument on each reference to So TL;DR I think we can get this example (at least) working by normalizing the argument types before we store them in the liberated-fn-sig map, or else by normalized the argument types when building MIR. I sort of lean towards the former, just because it's a bit easier to do since there is already a fulfillment context handing around and so forth to handle errors (and it seems more efficient to boot, since we can stop renormalizing on each reference). |
This comment has been minimized.
This comment has been minimized.
|
Another reason to normalize the entire fn signature is that I think it will fix this example, which illustrates that the return type is not normalized, though the argument types are: use std::marker::PhantomData;
trait Foo<'a> {
type Item;
fn consume<F>(self, f: F) where F: Fn(Self::Item);
}
struct Consume<A>(PhantomData<A>);
impl<'a, A:'a> Foo<'a> for Consume<A> {
type Item = &'a A;
fn consume<F>(self, _f: F) where F: Fn(Self::Item) -> Self::Item {
if blackbox() {
_f(any());
}
}
}
#[derive(Clone)]
struct Wrap<T> { foo: T }
impl<T: for <'a> Foo<'a>> Wrap<T> {
fn consume<F>(self, f: F) where F: for <'b> Fn(<T as Foo<'b>>::Item) -> <T as Foo<'b>>::Item {
self.foo.consume(f);
}
}
fn main() {
// This does not (but is only noticed if you call the closure).
let _wrap = Wrap { foo: Consume(PhantomData::<u32>,) };
_wrap.consume(|xxxxx| xxxxx);
}
pub static mut FLAG: bool = false;
fn blackbox() -> bool { unsafe { FLAG } }
fn any<T>() -> T { loop { } } |
nikomatsakis
removed
the
I-nominated
label
May 26, 2016
This comment has been minimized.
This comment has been minimized.
|
OK so it appears I was half right. After fixing the problem I mentioned, the warnings about MIR typeck failures go away, but the ICE remains. Also, the variation I posted still doesn't type check. =) I am now looking in more detail at the ICE from trans. |
This comment has been minimized.
This comment has been minimized.
|
Note that at this point the current stable (1.9) exhibits the warning and the ICE on the original code posted in the description. (The gist I posted earlier sidesteps the ICE on the current stable, but still ICE's on the current beta.) |
This comment has been minimized.
This comment has been minimized.
|
I have a PR blocked by an ICE that appeared after updating to stable 1.9, and after spending the day attempting to find a workaround it's beginning to look suspiciously similar to this one. Some similarities:
There are more details along with the backtrace and an example at my original issue here #34027. I'm happy to close it in favour of tracking this issue if you think they fall under the same umbrella. |
This comment has been minimized.
This comment has been minimized.
|
So I did some further digging. The current error is definitely the kind of problem I had hope for lazy normalization to fix -- the immediate cause of the ICE is that we wind up solving an obligation where we will be able to normalize, but only once we have "opened" the binder, and once we do that, we are in the inference code and hence we can't normalize (yet!). I'm not sure though why this is only occurring now. |
This comment has been minimized.
This comment has been minimized.
|
My branch btw is issue-33364 (which does solve the MIR warning). |
This comment has been minimized.
This comment has been minimized.
|
I ended up working around the ICE I was running into, see here for details. |
This comment has been minimized.
This comment has been minimized.
|
I tried commenting out the trans collector, but still encountered the same ICE (which is what I expected). This does though suggest the problem is not "specific" to MIR in any particular way (also what I expected). I don't really know how this ever avoided an ICE, tbh, but it really does feel like we should fix via the lazy normalization series of patches, though that's a bit longer term (not sure just how long; @soltanmm has been making some very steady progress and things are getting close). |
This comment has been minimized.
This comment has been minimized.
|
I did enough bisection to determine that the problem was exposed during PR #32080. However, many of the individual commits of that PR unfortunately do not build, so the end bisect state looks like this: commit 9723a3b builds and does not expose the problem, commit da66431 builds and does expose it, and
I haven't traced through the different behaves on the two nearest points in the commit series that expose the problem. I might try to do that next, in the hopes of learning why we were avoiding an ICE here previously. (But I also suspect that I should reassign this bug to @nikomatsakis ) |
This comment has been minimized.
This comment has been minimized.
|
One possible strategy might be to optimize how trans works so that it only fulfills obligations that it HAS to fulfill to resolve in order to solve type variables. This might sidestep the ICE for now because it may never feel the need to resolve this particular obligation. I have to double-check this assertion though, it may not be true. In any case it wouldn't be a fix (that would be lazy norm, I think), but then again my feeling is this code only ever worked through happenstance in any case. |
This comment has been minimized.
This comment has been minimized.
|
@rust-lang/compiler Can someone be assigned to this P-high bug? |
brson
added
the
A-resolve
label
Jun 23, 2016
This comment has been minimized.
This comment has been minimized.
|
Triage: still blocked on #34573, which is actively being pursued. |
arielb1
added
A-traits
and removed
A-mir
A-resolve
labels
Jul 21, 2016
This comment has been minimized.
This comment has been minimized.
|
reassigning bug to @nikomatsakis |
pnkfelix
assigned
nikomatsakis
and unassigned
pnkfelix
Jul 21, 2016
This comment has been minimized.
This comment has been minimized.
|
triage: P-medium |
rust-highfive
added
P-medium
and removed
P-high
labels
Jul 21, 2016
nikomatsakis
referenced this issue
Jul 21, 2016
Closed
Encountered error `Unimplemented` selecting `Binder(<[closure ...] as Fn()>)` during trans #34349
brson
added
the
I-ICE
label
Sep 13, 2016
nikomatsakis
added
the
E-hard
label
Sep 13, 2016
brson
added
I-needs-decision
and removed
E-hard
labels
Sep 13, 2016
This comment has been minimized.
This comment has been minimized.
|
OK so -- just an update. I tried a few alternatives here as a possible alternative to @pnkfelix's PR #34573. In particular, I tried:
|
This comment has been minimized.
This comment has been minimized.
|
@pnkfelix Can you clarify why this is P-medium instead of P-high? |
This comment has been minimized.
This comment has been minimized.
|
Because it is probably not going to be fixed before lazy normalization. |
This comment has been minimized.
This comment has been minimized.
|
@arielb1 thanks! |
This comment has been minimized.
This comment has been minimized.
|
Removing I-needs-decision flag; we definitely decided to not land #34573. The plan instead is to implement lazy normalization, which should fix this (or at least make it feasible to fix in a principled way...) |
pnkfelix
removed
the
I-needs-decision
label
Apr 6, 2017
Mark-Simulacrum
added
the
C-bug
label
Jul 22, 2017
jturner314
referenced this issue
May 19, 2018
Open
ICE with higher-rank trait bounds and associated type #50886
This comment has been minimized.
This comment has been minimized.
|
Triage: OP's code still errors with
you also don't need to uncomment the last line to break it. |
This comment has been minimized.
This comment has been minimized.
|
@nikomatsakis is #52812 a duplicate of this? |
eddyb
referenced this issue
Nov 3, 2018
Open
ATC-like for<'a> Fn(<X as Trait<'a>>::Type) does not consistently normalize (and can ICE). #52812
This comment has been minimized.
This comment has been minimized.
|
This issue itself might be a duplicate of #29997. |
rphmeier commentedMay 3, 2016
I honestly don't really know how to describe this one.
On stable the uncommented version works as expected, although it yields an ICE on both Beta and Nightly.
On all three release channels, the commented portion of the code fails to resolve
<(PhantomData<A>, PhantomData<B>, PhantomData<C>) as Foo<'a>>::Itemas(&'a A, &'a B, &'a C), although they are the same type.The expected behavior is that I should be able to call wrap.consume() and match on the argument as a tuple. Note that without the indirection through "Wrap", this works as expected. In my program, the wrapper does more work which cannot be stripped away.
playground: http://is.gd/EYtNFj