Let's hunt this ICE down together!


#1

and

are two related bugs I reported 2 weeks ago. I have did some research on those and feel like this is not an easy issue.

The following:

trait Lt<'a> {
    type T;
}
impl<'a> Lt<'a> for () {
    type T = ();
}

fn main() {
    let _:<() as Lt<'_>>::T = ();
    let _:fn(<() as Lt<'_>>::T) = |()| {};
}

will ICE in stable. I run rustc -Zdump-dir=main command, and here is “EraseRegions.before.mir”

fn main() -> (){
    let mut _0: ();                      // return place
    let mut _1: ();
    let mut _2: for<'r> fn(<() as Lt<'r>>::T);
    let mut _3: [closure@src/test/run-pass/issue-53420.rs:22:35: 22:42];

    bb0: {                              
        StorageLive(_1);                 // bb0[0]: scope 0 at src/test/run-pass/issue-53420.rs:21:31: 21:33
        _1 = ();                         // bb0[1]: scope 0 at src/test/run-pass/issue-53420.rs:21:31: 21:33
        StorageDead(_1);                 // bb0[2]: scope 0 at src/test/run-pass/issue-53420.rs:21:33: 21:34
        StorageLive(_2);                 // bb0[3]: scope 0 at src/test/run-pass/issue-53420.rs:22:35: 22:42
        StorageLive(_3);                 // bb0[4]: scope 0 at src/test/run-pass/issue-53420.rs:22:35: 22:42
        _3 = [closure@src/test/run-pass/issue-53420.rs:22:35: 22:42]; // bb0[5]: scope 0 at src/test/run-pass/issue-53420.rs:22:35: 22:42
                                         // closure
                                         // + def_id: DefId(0/1:11 ~ issue_53420[317d]::main[0]::{{closure}}[0])
                                         // + substs: ClosureSubsts {
                                         //     substs: [
                                         //         i8,
                                         //         for<'r> extern "rust-call" fn((<() as Lt<'r>>::T,))
                                         //     ]
                                         // }
        _2 = move _3 as for<'r> fn(<() as Lt<'r>>::T) (ClosureFnPointer); // bb0[6]: scope 0 at src/test/run-pass/issue-53420.rs:22:35: 22:42
        StorageDead(_3);                 // bb0[7]: scope 0 at src/test/run-pass/issue-53420.rs:22:41: 22:42
        StorageDead(_2);                 // bb0[8]: scope 0 at src/test/run-pass/issue-53420.rs:22:42: 22:43
        _0 = ();                         // bb0[9]: scope 0 at src/test/run-pass/issue-53420.rs:20:11: 23:2
        return;                          // bb0[10]: scope 0 at src/test/run-pass/issue-53420.rs:23:2: 23:2
    }
}

then “EraseRegions.after.mir” have no change. This is a concern, because after erase regions, we should not have lifetimes any more! but the code above still have it. This is WRONG.

I will continue hunting down the bug, and appreciate any help on giving me some hints on what to look at, and what to expect.


Late bound lifetimes (HRTB related)
#2

When look at src/librustc/ty/erase_regions.rs I realise that

for<'r> fn(<() as Lt<'r>>::T)

is a “late bound region”, and will not be subsitited at this stage. This is unlike <() as Lt<'_>>::T, which will be substituted to () in earlier stage.

The problem is then, as we never really have a lifetime parameter here, later when it try to unify for<'r> fn(<() as Lt<'r>>::T) with () it fails. Maybe this is where it should be fixed? This implies we should look at

/src/librustc/traits/select.rs

pub fn select(...
     let candidate = match self.candidate_from_obligation(&stack) {...
     ...
     match self.confirm_candidate(obligation, candidate) {...
     ...
}

where self.candidate_from_obligation success but self.confirm_candidate fails, and issued the ICE. So, confirm_candidate should success even for<'r> fn(<() as Lt<'r>>::T) and () didn’t match literaly, I think.