Repository: rust
Issue: Trait object coercion has problems with contravariant structs and lifetime bounds
Labels: C-enhancement,A-lifetimes,T-compiler,A-coercions,A-variance,T-types,A-trait-objects

I would expect this code to compile:

``` rust
#![allow(dead_code)]
#![allow(unused_variables)]

struct Covariant<'a> { y: &'a i32 }
struct Contravariant<'a> { y: fn(&'a i32) }

trait HasLifetime<'a> : 'a {}
impl<'a, T> HasLifetime<'a> for T where T: 'a {}

fn check_lifetime_bound<'a, T: 'a>(x: &T) {}

fn check_contra_rightway<'a>(x: Contravariant<'a>) {
    let xref = &x;
    let xstatic: &Contravariant<'static> = &x;
    check_lifetime_bound::<'a>(&x);
    check_lifetime_bound::<'a>(xref);
    check_lifetime_bound::<'a>(xstatic);
    check_lifetime_bound::<'static>(&x);  // <-- this works, but...
    check_lifetime_bound::<'static>(xref);
    check_lifetime_bound::<'static>(xstatic);

    let a: &HasLifetime<'static> = &x;  // <-- this doesn't (BUG!)

    let a: &HasLifetime<'static> = xstatic;  // <-- nonetheless, this does work

    // NB: Substituting Any for HasLifetime<'static> produces identical
    // results.
}

fn check_co_wrongway<'a>(x: Covariant<'a>) {
    let xref = &x;
    // let xstatic: &Covariant<'static> = &x;  <-- correctly fails
    check_lifetime_bound::<'a>(&x);
    check_lifetime_bound::<'a>(xref);
    // check_lifetime_bound::<'static>(&x);  <-- correctly fails
    // check_lifetime_bound::<'static>(xref); <-- correctly fails

    let a: &HasLifetime<'a> = &x;
}

fn check_co_rightway<'a>(x: Covariant<'static>, _: &'a i32) {
    let xref = &x;
    let xa: &Covariant<'a> = &x;
    check_lifetime_bound::<'a>(&x);
    check_lifetime_bound::<'a>(xref);
    check_lifetime_bound::<'a>(xa);
    check_lifetime_bound::<'static>(&x);
    check_lifetime_bound::<'static>(xref);
    // check_lifetime_bound::<'static>(xa);  <-- this correctly fails
    let a: &HasLifetime<'a> = &x;
    let a: &HasLifetime<'a> = xref;
    let a: &HasLifetime<'a> = xa;

    // let bad: &HasLifetime<'static> = xa;  <-- correctly fails
}

fn main() {}
```

Using `rustc 1.11.0 (9b21dcd6a 2016-08-15)`, I get:

```
ref_life.rs:22:36: 22:38 error: the type `Contravariant<'a>` does not fulfill the required lifetime [E0477]
ref_life.rs:22     let a: &HasLifetime<'static> = &x;  // <-- this doesn't (BUG!)
                                                  ^~
ref_life.rs:22:36: 22:38 note: type must outlive the static lifetime
ref_life.rs:22:36: 22:38 error: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements [E0495]
ref_life.rs:22     let a: &HasLifetime<'static> = &x;  // <-- this doesn't (BUG!)
                                                  ^~
ref_life.rs:12:52: 28:2 note: first, the lifetime cannot outlive the lifetime 'a as defined on the block at 12:51...
ref_life.rs:12 fn check_contra_rightway<'a>(x: Contravariant<'a>) {
                                                                  ^
ref_life.rs:22:36: 22:38 note: ...so that the type `Contravariant<'a>` will meet its required lifetime bounds
ref_life.rs:22     let a: &HasLifetime<'static> = &x;  // <-- this doesn't (BUG!)
                                                  ^~
ref_life.rs:22:36: 22:38 note: but, the lifetime must be valid for the static lifetime...
ref_life.rs:22:36: 22:38 note: ...so that trait type parameters matches those specified on the impl (expected HasLifetime<'static>, found HasLifetime<'_>)
ref_life.rs:22     let a: &HasLifetime<'static> = &x;  // <-- this doesn't (BUG!)
                                                  ^~
error: aborting due to 2 previous errors
```

It seems that the rustc can match a covariant struct against a shorter lifetime bound when coercing to a trait object but that it can't match a contravariant struct against a longer timetime bound when coercing to a trait object, depite the fact that coercing directly works fine.