Change:
<ins> error[E0308]: mismatched types --> $DIR/trait-associated-constant.rs:31:5 | 31 |     const AC: Option<&'c str> = None; |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `std::option::Option<&'b str>` found type `std::option::Option<&'c str>` note: the lifetime 'c as defined on the impl at 30:1... --> $DIR/trait-associated-constant.rs:30:1 | 30 | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 30:1 --> $DIR/trait-associated-constant.rs:30:1 | 30 | impl<'a: 'b, 'b, 'c> Anything<'a, 'b> for FailStruct1 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/trait-associated-constant.rs:38:5 | 38 |     const AC: Option<&'a str> = None; |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | = note: expected type `std::option::Option<&'b str>` found type `std::option::Option<&'a str>` note: the lifetime 'a as defined on the impl at 37:1... --> $DIR/trait-associated-constant.rs:37:1 | 37 | impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...does not necessarily outlive the lifetime 'b as defined on the impl at 37:1 --> $DIR/trait-associated-constant.rs:37:1 | 37 | impl<'a: 'b, 'b> Anything<'a, 'b> for FailStruct2 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors </ins>

Discussion:
is probably the same issue.
Not a dup of
or rather, with the fix applied, I get another ICE =)
That new ICE seems similar to :)
Hmm, yes, but it's definitely not an issue with
This probably has something to do with the fact that consts use the identity substitutions when computing universal regions substitutions: since those are always going to be generating regions: I have yet to track down the code that should be resolving those early bounds and why it isn't doing so.
Hmm, you are in the right area of the code. But I think the problem runs just a touch deeper. Actually the comments here are not that great. I should do a pass to improve them. But let me try to first explain what's happening a bit and then how to fix it. The role of the enum (which should perhaps be renamed?) is to kind of capture the "external signature" for a given piece of MIR, and ideally in a way that identifies all of the "degrees of freedom" that the code has (and just those degrees of freedom). Based just on the defining-type, we should be able to identify the following information: The universally bound regions (i.e., lifetime parameters), both early and (where relevant) late bound The types of all the MIR inputs (expressed in terms of these universally bound regions) The types of the MIR output (expressed in terms of these universally bound regions) This is perhaps easiest to explain with a function item. Assume that we are working with the MIR for this function : In that case, the defining type will be the variant: You can see that it is actually sort of minimal: just a def-id and a substs array. In this case, the substs array will consist of three things, first a lifetime variable (representing ) and then two types (, as it happens): (This array gets created in ; this will basically replace the formal lifetime parameter of (represented as an ) with a fresh variable .) Given the array, we can easily compute the set of region variables representing universally bound regions in a function signature -- it's just the region variables appearing in the substs array. That's what we use to build the map in . Note that this substs array does not, for example, include the types of the arguments etc. That's because those types can be reconstructed using queries.

For example, the function includes this code, which extracts the function signature (using the query) and then basically substitutes (the call has that effect) from the formal lifetime parameters: Part of the reason it is done this way is that then the types of both arguments ( and ) will reference the same lifetime (). If, when creating the defining type, we had on something that contained the types of those arguments separately, then they would have been rewritten to use two different lifetime variables. This would have been too many "degrees of freedom". For constants, our defining-type variant is currently the type of the constant: This is actually wrong, and is roughly the equivalent of storing the types of the arguments directly in the . The fault arises from in -- it was written with functions and closures in mind. It fetches the "type" associated with the def-id and rewrites all the regions in it. This is ok for functions and closures because the type of a function or closure is already a kind of indirection; e.g., a is . We probably want to change that variant to something more like Fn: then we want to do is to refactor somewhat. I would expect it to look more like the following. This is the same as the existing code, just rearranged so that it only executes for : meanwhile, for and , we'll do something slightly different. We don't want to start by fetching , because that gets the type associated with the static. Instead, we'll do: Then we can change the other bits of code to match. For example: becomes When we wish to compute the "return type" of the closure, then we can do the query: becomes: I think that ought to work. cc