Type inference problem with lifetimes and assoiated types
I am trying to get some lifetime polymorphism but I unable to do so because of some bugs (#24424, #23958). This time it seems that the type inference is not working.
use std::ops::Range;
pub trait Iter {
type Type: Iterator;
}
pub trait T {
fn f<'a>(&'a self) -> <&'a Self as Iter>::Type where &'a Self: Iter;
}
pub struct S;
impl<'a> Iter for &'a S {
type Type = Range<usize>;
}
impl T for S {
fn f<'a>(&'a self) -> <&'a Self as Iter>::Type where &'a Self: Iter {
0usize..10
}
}
fn main() {}
gives
<anon>:19:9: 19:19 error: mismatched types:
expected `<&'a S as Iter>::Type`,
found `core::ops::Range<usize>`
(expected associated type,
found struct `core::ops::Range`) [E0308]
<anon>:19 0usize..10
^~~~~~~~~~
<anon>:19:9: 19:19 help: see the detailed explanation for E0308
error: aborting due to previous error
playpen: application terminated with error code 101
Slightly simplified testcase:
use std::ops::Range; pub trait Iter { type Type: Iterator; } pub struct S; impl<'a> Iter for &'a S { type Type = Range<usize>; } impl S { fn f<'a>(&'a self) -> Range<usize> where &'a S: Iter { let x: <&'static S as Iter>::Type = 0usize..10; x } } fn main() {}Basically, the compiler is getting confused by the where clause: it sees the bound on the implementation, and "resolves" the associated type based on that, rather than actually trying to look up the type. The problem is that the bound is trivial: depending on it actually reduces the amount of information available, rather than increasing it.
Related to #27987, I think; CC @arielb1.
eefriedman at 2015-08-27 19:28:59
This is one of the tentacles of #21974 - the only relation to #27987 is that we would have ignored the poisonous where-clause if its lifetime was
'static. The issue can be fixed by just not specifying the where-clause:use std::ops::Range; pub trait Iter { type Type: Iterator; } pub trait T { fn f<'a>(&'a self) -> <&'a Self as Iter>::Type where &'a Self: Iter; } pub struct S; impl<'a> Iter for &'a S { type Type = Range<usize>; } impl T for S { fn f<'a>(&'a self) -> <&'a Self as Iter>::Type // need some (holding) bound on 'a to make it early-bound where &'a (): Sized { 0usize..10 } } fn main() {}Ariel Ben-Yehuda at 2015-08-27 21:10:39
Is there an existing bug report about the
where &'a (): Sizedthing?eefriedman at 2015-08-27 21:43:23
@eefriedman
It's not a bug, just a less-than-optimally-documented feature (early-bound vs. late-bound regions). See my comment at enum Region and the links referenced therein. Its the same reason you can't write
fn foo<'a>(){} fn main() { foo::<'static>() //~ ERROR too many lifetime parameters provided }Ariel Ben-Yehuda at 2015-08-29 20:14:39
Ah, right... we need to decide somehow whether the lifetime is part of the function type.
eefriedman at 2015-08-29 20:46:11
Current error:
rustc 1.15.1 (021bd294c 2017-02-08) error[E0308]: mismatched types --> <anon>:19:9 | 19 | 0usize..10 | ---------- | | | expected associated type, found struct `std::ops::Range` | in this macro invocation | = note: expected type `<&'a S as Iter>::Type` = note: found type `std::ops::Range<usize>` error: aborting due to previous errorBrian Anderson at 2017-03-09 17:37:43
Triage: no change as of Rust 1.41:
error[E0308]: mismatched types --> src/main.rs:19:9 | 18 | fn f<'a>(&'a self) -> <&'a Self as Iter>::Type where &'a Self: Iter { | ------------------------ expected `<&'a S as Iter>::Type` because of return type 19 | 0usize..10 | ^^^^^^^^^^ expected associated type, found struct `std::ops::Range` | = note: expected associated type `<&'a S as Iter>::Type` found struct `std::ops::Range<usize>` = note: consider constraining the associated type `<&'a S as Iter>::Type` to `std::ops::Range<usize>` or calling a method that returns `<&'a S as Iter>::Type` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.htmlbstrie at 2020-02-20 14:36:23