Description
struct Foo<T>(T); // `T` is covariant.
fn foo<'b>(x: Foo<for<'a> fn(&'a ())>) {
let Foo(y): Foo<fn(&'b ())> = x;
}
fn main() {}
should compile but errors with
error[E0308]: mismatched types
--> src/main.rs:4:13
|
4 | let Foo(y): Foo<fn(&'b ())> = x;
| ^ one type is more general than the other
|
= note: expected fn pointer `for<'a> fn(&'a ())`
found fn pointer `fn(&())`
looking at the mir of foo
it becomes clear why that happens:
fn foo(_1: Foo<for<'a> fn(&'a ())>) -> () {
debug x => _1; // in scope 0 at src/main.rs:3:12: 3:13
let mut _0: (); // return place in scope 0 at src/main.rs:3:40: 3:40
let _2: fn(&()) as UserTypeProjection { base: UserType(0), projs: [Field(field[0], ())] }; // in scope 0 at src/main.rs:4:13: 4:14
scope 1 {
debug y => _2; // in scope 1 at src/main.rs:4:13: 4:14
}
bb0: {
AscribeUserType(_1, +, UserTypeProjection { base: UserType(1), projs: [] }); // scope 0 at src/main.rs:4:17: 4:32
StorageLive(_2); // scope 0 at src/main.rs:4:13: 4:14
_2 = (_1.0: fn(&())); // scope 0 at src/main.rs:4:13: 4:14
_0 = const (); // scope 0 at src/main.rs:3:40: 5:2
StorageDead(_2); // scope 0 at src/main.rs:5:1: 5:2
return; // scope 0 at src/main.rs:5:2: 5:2
}
}
notice that in _2 = (_1.0: fn(&()));
the type of _1.0
is actually for<'a> fn(&'a ())
.
Possible ways to fix this are:
- correctly deal with subtyping when sanitizing field projections, note that they cannot just always be covariant.
- change the type of the field to be the actual one during mir building, so that subtyping actually happens at the assignment
always lazily recompute the type of the field instead of storing it in the mir
Metadata
Metadata
Assignees
Labels
Area: Variance (https://doc.rust-lang.org/nomicon/subtyping.html)Category: This is a bug.Call for participation: Hard difficulty. Experience needed to fix: A lot.Call for participation: This issue has a mentor. Use #t-compiler/help on Zulip for discussion.Relevant to the types team, which will review and decide on the PR/issue.