-
Notifications
You must be signed in to change notification settings - Fork 13k
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
ICE: librustc/traits/codegen/mod.rs:68: Encountered error OutputTypeParameterMismatch
#53420
Comments
trait Lt<'a> {
type T;
}
impl<'a> Lt<'a> for () {
type T = ();
}
fn main() {
let _:fn(<() as Lt<'_>>::T) = |()| {};
} |
The error message actually tells us the reason:
So the unification between Interestingly, the following works: fn main() {
let _: fn(_) = |_:<Id<()> as Lt<'_>>::T| {};
} but creates another ICE when try to call the function: trait Lt<'a> {
type T;
}
struct Id<T>(T);
impl<'a,T> Lt<'a> for Id<T> {
type T = T;
}
fn main() {
let f: fn(_) = |_:<Id<()> as Lt<'_>>::T| {};
f(())
} where the error message again contains:
So, my guess is that somehow this unification passed. However, some work was missing to actually substitute it before generating MIR, and the MIR checker then fails because it didn't follow the same logic to justify the unification. |
The following is working, but the MIR shows a potential reason that seems causes the issue. trait Lt<'a> {
type T;
}
struct Id<T>(T);
impl<'a,T> Lt<'a> for Id<T> {
type T = T;
}
fn main() {
let _v: <Id<()> as Lt<'_>>::T = ();
let _f: fn(_) = |_:<Id<()> as Lt<'_>>::T| {};
//ICE: broken MIR in DefId
//_f(_v)
} In generated MIR, it contains the following:
I think this should be subsituted and change to
Interestingly, the variable
Further investigate shows that if we remove the lifetime the problem is resolved. So it seems that the erasure of lifetime wasn't done properly and left behind things that can be substituted? Issues maybe releated: |
Manually desugaring //Working
let _:&FnOnce<(<() as Lt<'_>>::T,),Output=()> = &|_|{};
//Not working
let _:&FnOnce(<() as Lt<'_>>::T) = &|_|{}; Suggests the problem is in desugaring More example: let f:&FnOnce(_)= &|_:<() as Lt<'_>>::T|{}; compiled into MIR (which is WRONG):
let f:&mut FnMut<(<() as Lt<'_>>::T,),Output=()> = &mut |_|{}; compiled into MIR (CORRECT)
|
A more scary ICE: panic with messages that is irrelevant to the code (nightly only with fn main() {
let v:<() as Lt<'_>>::T = ();
let f:&mut FnMut<(_,),Output=()> = &mut |_:<() as Lt<'_>>::T|{};
f(v);
} Error mesage:
I run a local compiler that was compiled from source code, and modifyed the src\librustc_codegen_llvm\back\link.rs file, so function So if I am right, the thread that do MIRI verification was running simultaneously with the LLVM codegen and linker. But MIRI thread issued an error at an unfortunate time point so it crashes the profiler thread. Compare to the HRTB broken MIR issue, I think this is more serious and so I am going to create another issue. |
I need answer of the following question: When should So I suppose the fix would be in the monorphization. After monorphization the substitution should be done but it didn't, which causes problems in codegen. |
Found the following code in "/src/librustc/traits/select.rs": /// In the case of closure types and fn pointers,
/// we currently treat the input type parameters on the trait as
/// outputs. This means that when we have a match we have only
/// considered the self type, so we have to go back and make sure
/// to relate the argument types too. This is kind of wrong, but
/// since we control the full set of impls, also not that wrong,
/// and it DOES yield better error messages (since we don't report
/// errors as if there is no applicable impl, but rather report
/// errors are about mismatched argument types.
///
/// Here is an example. Imagine we have a closure expression
/// and we desugared it so that the type of the expression is
/// `Closure`, and `Closure` expects an int as argument. Then it
/// is "as if" the compiler generated this impl:
///
/// impl Fn(int) for Closure { ... }
///
/// Now imagine our obligation is `Fn(usize) for Closure`. So far
/// we have matched the self-type `Closure`. At this point we'll
/// compare the `int` to `usize` and generate an error.
///
/// Note that this checking occurs *after* the impl has selected,
/// because these output type parameters should not affect the
/// selection of the impl. Therefore, if there is a mismatch, we
/// report an error to the user.
fn confirm_poly_trait_refs(&mut self,
obligation_cause: ObligationCause<'tcx>,
obligation_param_env: ty::ParamEnv<'tcx>,
obligation_trait_ref: ty::PolyTraitRef<'tcx>,
expected_trait_ref: ty::PolyTraitRef<'tcx>)
-> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>>
{
let obligation_trait_ref = obligation_trait_ref.clone();
self.infcx
.at(&obligation_cause, obligation_param_env)
.sup(obligation_trait_ref, expected_trait_ref)
.map(|InferOk { obligations, .. }| obligations)
.map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
} seems like the following assumsion
didn't hold in this case so the error is reported. So the conclusion: in "/src/librustc/traits/select.rs", pub fn select(...
let candidate = match self.candidate_from_obligation(&stack) {...
...
match self.confirm_candidate(obligation, candidate) {...
...
} the call One obvious solution is to ensure we substitute associate types after |
Or, is the following (/src/librustc/traits/select.rs) fn confirm_fn_pointer_candidate(&mut self, obligation: &TraitObligation<'tcx>)
-> Result<VtableFnPointerData<'tcx, PredicateObligation<'tcx>>, SelectionError<'tcx>>
{
debug!("confirm_fn_pointer_candidate({:?})",
obligation);
// ok to skip binder; it is reintroduced below
let self_ty = self.infcx.shallow_resolve(*obligation.self_ty().skip_binder());
let sig = self_ty.fn_sig(self.tcx());
let trait_ref =
self.tcx().closure_trait_ref_and_return_type(obligation.predicate.def_id(),
self_ty,
sig,
util::TupleArgumentsFlag::Yes)
.map_bound(|(trait_ref, _)| trait_ref);
let Normalized { value: trait_ref, obligations } =
project::normalize_with_depth(self,
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
&trait_ref);
self.confirm_poly_trait_refs(obligation.cause.clone(),
obligation.param_env,
obligation.predicate.to_poly_trait_ref(),
trait_ref)?;
Ok(VtableFnPointerData { fn_ty: self_ty, nested: obligations })
} correct? I mean the following assumsion:
given the fact that we have trouble to unify |
I see you have been working on #18993 (HRTB). This issue seems to be in the concept "late bound regions" you introduced: Can you please look into this and tell me when it is supposed to be bound? (I can see the difficulty here: there is a lifetime but was never specified and no clue was given to infer it, making it hard to assume anything on it) |
A slightly adjusted from the minimal reproducable trait Lt<'a> {
type T;
}
impl<'a> Lt<'a> for () {
type T = ();
}
fn main() {
let _:fn(()) = |_:<() as Lt<'_>>::T| {};
} gives a normal, but still confusing error message:
This is consistent in both stable and nightly(2015 or 2018). trait Lt<'a> {
type T;
}
impl<'a> Lt<'a> for () {
type T = ();
}
fn test<'a>() {
let _:fn(<() as Lt<'a>>::T) = |()| {};
}
fn main() {
test();
} is working, but will trigger this ICE if remove the |
assigning self for preliminary investigation |
Since this is an ICE and is not using any unstable features (and in fact, reproduces on the stable channel), I have tagged it as P-high for now. That means we'll be visiting it regularly during the weekly compiler team meeting. |
Also: Thank you @earthengine for your patience as well as your copious notes from your own investigations. My current hypothesis is that normalization is supposed to be doing the substitution mapping |
Discussed at T-compiler meeting. Seems to be duplicate of issue #29997. Closing as duplicate. |
(duplicate of #62529, which is where I will try to track future instances of this field of ICE.) |
I was attempt to apply the trick of this blog post to improve my named closures crate. But I run into this ICE, which is unfortunately in stable.
https://play.rust-lang.org/?gist=22299e701c9bdb472a5fc8fe303b7fa1&version=stable&mode=debug&edition=2015
This is freshly occur so I didn't simplify the code.
The text was updated successfully, but these errors were encountered: