only require sub type relation on field projection types

This commit is contained in:
b-naber 2023-01-31 17:45:30 +01:00
parent 00cf19a75a
commit 6e1d228285
8 changed files with 151 additions and 4 deletions

View file

@ -534,7 +534,7 @@ fn sanitize_place(
return PlaceTy::from_ty(self.tcx().ty_error());
}
}
place_ty = self.sanitize_projection(place_ty, elem, place, location);
place_ty = self.sanitize_projection(place_ty, elem, place, location, context);
}
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
@ -630,12 +630,14 @@ fn sanitize_promoted(&mut self, promoted_body: &'b Body<'tcx>, location: Locatio
}
}
#[instrument(skip(self), level = "debug")]
fn sanitize_projection(
&mut self,
base: PlaceTy<'tcx>,
pi: PlaceElem<'tcx>,
place: &Place<'tcx>,
location: Location,
context: PlaceContext,
) -> PlaceTy<'tcx> {
debug!("sanitize_projection: {:?} {:?} {:?}", base, pi, place);
let tcx = self.tcx();
@ -713,8 +715,11 @@ fn sanitize_projection(
match self.field_ty(place, base, field, location) {
Ok(ty) => {
let ty = self.cx.normalize(ty, location);
if let Err(terr) = self.cx.eq_types(
debug!(?fty, ?ty);
if let Err(terr) = self.cx.relate_types(
ty,
self.get_ambient_variance(context),
fty,
location.to_locations(),
ConstraintCategory::Boring,
@ -743,9 +748,10 @@ fn sanitize_projection(
let ty = self.sanitize_type(place, ty);
let ty = self.cx.normalize(ty, location);
self.cx
.eq_types(
base.ty,
.relate_types(
ty,
self.get_ambient_variance(context),
base.ty,
location.to_locations(),
ConstraintCategory::TypeAnnotation,
)
@ -760,6 +766,13 @@ fn error(&mut self) -> Ty<'tcx> {
self.tcx().ty_error()
}
fn get_ambient_variance(&self, context: PlaceContext) -> ty::Variance {
match context {
PlaceContext::MutatingUse(_) => ty::Invariant,
PlaceContext::NonMutatingUse(_) | PlaceContext::NonUse(_) => ty::Covariant,
}
}
fn field_ty(
&mut self,
parent: &dyn fmt::Debug,

View file

@ -0,0 +1,24 @@
// build-pass
struct Inv<'a>(&'a mut &'a ());
enum Foo<T> {
Bar,
Var(T),
}
type Supertype = Foo<for<'a> fn(Inv<'a>, Inv<'a>)>;
fn foo(x: Foo<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>) {
match x {
Supertype::Bar => {}
Supertype::Var(x) => {}
}
}
fn foo_nested(x: Foo<Foo<for<'a, 'b> fn(Inv<'a>, Inv<'b>)>>) {
match x {
Foo::Bar => {}
Foo::Var(Supertype::Bar) => {}
Foo::Var(Supertype::Var(x)) => {}
}
}
fn main() {}

View file

@ -0,0 +1,19 @@
use std::sync::Mutex;
static GLOBAL: Mutex<&'static str> = Mutex::new("global str");
struct Foo<T>(T); // `T` is covariant.
fn foo() {
let mut x: Foo<for<'a> fn(&'a str)> = Foo(|_| ());
let Foo(ref mut y): Foo<fn(&'static str)> = x;
//~^ ERROR mismatched types
*y = |s| *GLOBAL.lock().unwrap() = s;
let string = String::from("i am shortlived");
(x.0)(&string);
}
fn main() {
foo();
println!("{}", GLOBAL.lock().unwrap());
}

View file

@ -0,0 +1,12 @@
error[E0308]: mismatched types
--> $DIR/field-projection-mutating-context.rs:9:13
|
LL | let Foo(ref mut y): Foo<fn(&'static str)> = x;
| ^^^^^^^^^ one type is more general than the other
|
= note: expected fn pointer `for<'a> fn(&'a str)`
found fn pointer `fn(&str)`
error: aborting due to previous error
For more information about this error, try `rustc --explain E0308`.

View file

@ -0,0 +1,17 @@
use std::sync::Mutex;
static GLOBAL: Mutex<&'static str> = Mutex::new("global str");
struct Foo<T>(T); // `T` is covariant.
fn foo<'a>(mut x: Foo<fn(&'a str)>, string: &'a str) {
let Foo(ref mut y): Foo<fn(&'static str)> = x;
//~^ ERROR lifetime may not live long enough
*y = |s| *GLOBAL.lock().unwrap() = s;
(x.0)(&string);
}
fn main() {
foo(Foo(|_| ()), &String::from("i am shortlived"));
println!("{}", GLOBAL.lock().unwrap());
}

View file

@ -0,0 +1,10 @@
error: lifetime may not live long enough
--> $DIR/field-projection-mutating-context2.rs:8:25
|
LL | fn foo<'a>(mut x: Foo<fn(&'a str)>, string: &'a str) {
| -- lifetime `'a` defined here
LL | let Foo(ref mut y): Foo<fn(&'static str)> = x;
| ^^^^^^^^^^^^^^^^^^^^^ type annotation requires that `'a` must outlive `'static`
error: aborting due to previous error

View file

@ -0,0 +1,15 @@
// build-pass
enum Foo<T> {
Var(T),
} // `T` is covariant.
fn foo<'b>(x: Foo<for<'a> fn(&'a ())>) {
let Foo::Var(x): Foo<fn(&'b ())> = x;
}
fn foo_nested<'b>(x: Foo<Foo<for<'a> fn(&'a ())>>) {
let Foo::Var(Foo::Var(x)): Foo<Foo<fn(&'b ())>> = x;
}
fn main() {}

View file

@ -0,0 +1,37 @@
// build-pass
struct Foo<T>(T); // `T` is covariant.
struct Bar<T> {
x: T,
} // `T` is covariant.
fn bar<'b>(x: Bar<for<'a> fn(&'a ())>) {
let Bar { x }: Bar<fn(&'b ())> = x;
}
fn bar_nested<'b>(x: Bar<Bar<for<'a> fn(&'a ())>>) {
let Bar { x: Bar { x } }: Bar<Bar<fn(&'b ())>> = x;
}
fn bar_foo_nested<'b>(x: Bar<Foo<for<'a> fn(&'a ())>>) {
let Bar { x: Foo ( x ) }: Bar<Foo<fn(&'b ())>> = x;
}
fn foo<'b>(x: Foo<for<'a> fn(&'a ())>) {
let Foo(y): Foo<fn(&'b ())> = x;
}
fn foo_nested<'b>(x: Foo<Foo<for<'a> fn(&'a ())>>) {
let Foo(Foo(y)): Foo<Foo<fn(&'b ())>> = x;
}
fn tuple<'b>(x: (u32, for<'a> fn(&'a ()))) {
let (_, y): (u32, fn(&'b ())) = x;
}
fn tuple_nested<'b>(x: (u32, (u32, for<'a> fn(&'a ())))) {
let (_, (_, y)): (u32, (u32, fn(&'b ()))) = x;
}
fn main() {}