Rollup merge of #107339 - aliemjay:covariant, r=lcnr
internally change regions to be covariant Surprisingly, we consider the reference type `&'a T` to be contravaraint in its lifetime parameter. This is confusing and conflicts with the documentation we have in the reference, rustnomicon, and rustc-dev-guide. This also arguably not the correct use of terminology since we can use `&'static u8` in a place where `&' a u8` is expected, this implies that `&'static u8 <: &' a u8` and consequently `'static <: ' a`, hence covariance. Because of this, when relating two types, we used to switch the argument positions in a confusing way: `Subtype(&'a u8 <: &'b u8) => Subtype('b <: 'a) => Outlives('a: 'b) => RegionSubRegion('b <= 'a)` The reason for the current behavior is probably that we wanted `Subtype('b <: 'a)` and `RegionSubRegion('b <= 'a)` to be equivalent, but I don' t think this is a good reason since these relations are sufficiently different in that the first is a relation in the subtyping lattice and is intrinsic to the type-systems, while the the second relation is an implementation detail of regionck. This PR changes this behavior to use covariance, so.. `Subtype(&'a u8 <: &'b u8) => Subtype('a <: 'b) => Outlives('a: 'b) => RegionSubRegion('b <= 'a) ` Resolves #103676 r? `@lcnr`
This commit is contained in:
commit
a5caa989c9
@ -225,8 +225,7 @@ fn add_constraints_from_ty(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::Ref(region, ty, mutbl) => {
|
ty::Ref(region, ty, mutbl) => {
|
||||||
let contra = self.contravariant(variance);
|
self.add_constraints_from_region(current, region, variance);
|
||||||
self.add_constraints_from_region(current, region, contra);
|
|
||||||
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
|
self.add_constraints_from_mt(current, &ty::TypeAndMut { ty, mutbl }, variance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,9 +257,8 @@ fn add_constraints_from_ty(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::Dynamic(data, r, _) => {
|
ty::Dynamic(data, r, _) => {
|
||||||
// The type `Foo<T+'a>` is contravariant w/r/t `'a`:
|
// The type `dyn Trait<T> +'a` is covariant w/r/t `'a`:
|
||||||
let contra = self.contravariant(variance);
|
self.add_constraints_from_region(current, r, variance);
|
||||||
self.add_constraints_from_region(current, r, contra);
|
|
||||||
|
|
||||||
if let Some(poly_trait_ref) = data.principal() {
|
if let Some(poly_trait_ref) = data.principal() {
|
||||||
self.add_constraints_from_invariant_substs(
|
self.add_constraints_from_invariant_substs(
|
||||||
|
@ -79,7 +79,8 @@ fn regions(
|
|||||||
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
|
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
|
||||||
|
|
||||||
let origin = Subtype(Box::new(self.fields.trace.clone()));
|
let origin = Subtype(Box::new(self.fields.trace.clone()));
|
||||||
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
|
// GLB(&'static u8, &'a u8) == &RegionLUB('static, 'a) u8 == &'static u8
|
||||||
|
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
|
||||||
self.tcx(),
|
self.tcx(),
|
||||||
origin,
|
origin,
|
||||||
a,
|
a,
|
||||||
|
@ -79,7 +79,8 @@ fn regions(
|
|||||||
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
|
debug!("{}.regions({:?}, {:?})", self.tag(), a, b);
|
||||||
|
|
||||||
let origin = Subtype(Box::new(self.fields.trace.clone()));
|
let origin = Subtype(Box::new(self.fields.trace.clone()));
|
||||||
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().lub_regions(
|
// LUB(&'static u8, &'a u8) == &RegionGLB('static, 'a) u8 == &'a u8
|
||||||
|
Ok(self.fields.infcx.inner.borrow_mut().unwrap_region_constraints().glb_regions(
|
||||||
self.tcx(),
|
self.tcx(),
|
||||||
origin,
|
origin,
|
||||||
a,
|
a,
|
||||||
|
@ -663,13 +663,13 @@ fn regions(
|
|||||||
debug!(?v_b);
|
debug!(?v_b);
|
||||||
|
|
||||||
if self.ambient_covariance() {
|
if self.ambient_covariance() {
|
||||||
// Covariance: a <= b. Hence, `b: a`.
|
// Covariant: &'a u8 <: &'b u8. Hence, `'a: 'b`.
|
||||||
self.push_outlives(v_b, v_a, self.ambient_variance_info);
|
self.push_outlives(v_a, v_b, self.ambient_variance_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.ambient_contravariance() {
|
if self.ambient_contravariance() {
|
||||||
// Contravariant: b <= a. Hence, `a: b`.
|
// Contravariant: &'b u8 <: &'a u8. Hence, `'b: 'a`.
|
||||||
self.push_outlives(v_a, v_b, self.ambient_variance_info);
|
self.push_outlives(v_b, v_a, self.ambient_variance_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(a)
|
Ok(a)
|
||||||
|
@ -191,12 +191,13 @@ fn regions(
|
|||||||
// from the "cause" field, we could perhaps give more tailored
|
// from the "cause" field, we could perhaps give more tailored
|
||||||
// error messages.
|
// error messages.
|
||||||
let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
|
let origin = SubregionOrigin::Subtype(Box::new(self.fields.trace.clone()));
|
||||||
|
// Subtype(&'a u8, &'b u8) => Outlives('a: 'b) => SubRegion('b, 'a)
|
||||||
self.fields
|
self.fields
|
||||||
.infcx
|
.infcx
|
||||||
.inner
|
.inner
|
||||||
.borrow_mut()
|
.borrow_mut()
|
||||||
.unwrap_region_constraints()
|
.unwrap_region_constraints()
|
||||||
.make_subregion(origin, a, b);
|
.make_subregion(origin, b, a);
|
||||||
|
|
||||||
Ok(a)
|
Ok(a)
|
||||||
}
|
}
|
||||||
|
@ -443,12 +443,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||||||
if a_repr == b_repr =>
|
if a_repr == b_repr =>
|
||||||
{
|
{
|
||||||
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
|
let region_bound = relation.with_cause(Cause::ExistentialRegionBound, |relation| {
|
||||||
relation.relate_with_variance(
|
relation.relate(a_region, b_region)
|
||||||
ty::Contravariant,
|
|
||||||
ty::VarianceDiagInfo::default(),
|
|
||||||
a_region,
|
|
||||||
b_region,
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr))
|
Ok(tcx.mk_dynamic(relation.relate(a_obj, b_obj)?, region_bound, a_repr))
|
||||||
}
|
}
|
||||||
@ -497,12 +492,7 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
(&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
|
(&ty::Ref(a_r, a_ty, a_mutbl), &ty::Ref(b_r, b_ty, b_mutbl)) => {
|
||||||
let r = relation.relate_with_variance(
|
let r = relation.relate(a_r, b_r)?;
|
||||||
ty::Contravariant,
|
|
||||||
ty::VarianceDiagInfo::default(),
|
|
||||||
a_r,
|
|
||||||
b_r,
|
|
||||||
)?;
|
|
||||||
let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
|
let a_mt = ty::TypeAndMut { ty: a_ty, mutbl: a_mutbl };
|
||||||
let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
|
let b_mt = ty::TypeAndMut { ty: b_ty, mutbl: b_mutbl };
|
||||||
let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
|
let mt = relate_type_and_mut(relation, a_mt, b_mt, a)?;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Foo<'a, T> { //~ ERROR [-, o]
|
struct Foo<'a, T> { //~ ERROR [+, o]
|
||||||
t: &'a mut T,
|
t: &'a mut T,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
error: [-, o]
|
error: [+, o]
|
||||||
--> $DIR/E0208.rs:4:1
|
--> $DIR/E0208.rs:4:1
|
||||||
|
|
|
|
||||||
LL | struct Foo<'a, T> {
|
LL | struct Foo<'a, T> {
|
||||||
|
@ -10,7 +10,7 @@ fn method(&'a self) { }
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Foo<'a, T : Trait<'a>> { //~ ERROR [-, +]
|
struct Foo<'a, T : Trait<'a>> { //~ ERROR [+, +]
|
||||||
field: (T, &'a ())
|
field: (T, &'a ())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
error: [-, +]
|
error: [+, +]
|
||||||
--> $DIR/variance-associated-types.rs:13:1
|
--> $DIR/variance-associated-types.rs:13:1
|
||||||
|
|
|
|
||||||
LL | struct Foo<'a, T : Trait<'a>> {
|
LL | struct Foo<'a, T : Trait<'a>> {
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
// Regions that just appear in normal spots are contravariant:
|
// Regions that just appear in normal spots are contravariant:
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
|
struct Test2<'a, 'b, 'c> { //~ ERROR [+, +, +]
|
||||||
x: &'a isize,
|
x: &'a isize,
|
||||||
y: &'b [isize],
|
y: &'b [isize],
|
||||||
c: &'c str
|
c: &'c str
|
||||||
@ -15,7 +15,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR [-, -, -]
|
|||||||
// Those same annotations in function arguments become covariant:
|
// Those same annotations in function arguments become covariant:
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
|
struct Test3<'a, 'b, 'c> { //~ ERROR [-, -, -]
|
||||||
x: extern "Rust" fn(&'a isize),
|
x: extern "Rust" fn(&'a isize),
|
||||||
y: extern "Rust" fn(&'b [isize]),
|
y: extern "Rust" fn(&'b [isize]),
|
||||||
c: extern "Rust" fn(&'c str),
|
c: extern "Rust" fn(&'c str),
|
||||||
@ -24,7 +24,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR [+, +, +]
|
|||||||
// Mutability induces invariance:
|
// Mutability induces invariance:
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
|
struct Test4<'a, 'b:'a> { //~ ERROR [+, o]
|
||||||
x: &'a mut &'b isize,
|
x: &'a mut &'b isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,7 +32,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR [-, o]
|
|||||||
// contravariant context:
|
// contravariant context:
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
|
struct Test5<'a, 'b:'a> { //~ ERROR [-, o]
|
||||||
x: extern "Rust" fn(&'a mut &'b isize),
|
x: extern "Rust" fn(&'a mut &'b isize),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ struct Test5<'a, 'b:'a> { //~ ERROR [+, o]
|
|||||||
// argument list occurs in an invariant context.
|
// argument list occurs in an invariant context.
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Test6<'a, 'b:'a> { //~ ERROR [-, o]
|
struct Test6<'a, 'b:'a> { //~ ERROR [+, o]
|
||||||
x: &'a mut extern "Rust" fn(&'b isize),
|
x: &'a mut extern "Rust" fn(&'b isize),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,7 +56,7 @@ struct Test7<'a> { //~ ERROR [*]
|
|||||||
// Try enums too.
|
// Try enums too.
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
enum Test8<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
|
enum Test8<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
|
||||||
Test8A(extern "Rust" fn(&'a isize)),
|
Test8A(extern "Rust" fn(&'a isize)),
|
||||||
Test8B(&'b [isize]),
|
Test8B(&'b [isize]),
|
||||||
Test8C(&'b mut &'c str),
|
Test8C(&'b mut &'c str),
|
||||||
|
@ -1,28 +1,28 @@
|
|||||||
error: [-, -, -]
|
error: [+, +, +]
|
||||||
--> $DIR/variance-regions-direct.rs:9:1
|
--> $DIR/variance-regions-direct.rs:9:1
|
||||||
|
|
|
|
||||||
LL | struct Test2<'a, 'b, 'c> {
|
LL | struct Test2<'a, 'b, 'c> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [+, +, +]
|
error: [-, -, -]
|
||||||
--> $DIR/variance-regions-direct.rs:18:1
|
--> $DIR/variance-regions-direct.rs:18:1
|
||||||
|
|
|
|
||||||
LL | struct Test3<'a, 'b, 'c> {
|
LL | struct Test3<'a, 'b, 'c> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [-, o]
|
error: [+, o]
|
||||||
--> $DIR/variance-regions-direct.rs:27:1
|
--> $DIR/variance-regions-direct.rs:27:1
|
||||||
|
|
|
|
||||||
LL | struct Test4<'a, 'b:'a> {
|
LL | struct Test4<'a, 'b:'a> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [+, o]
|
error: [-, o]
|
||||||
--> $DIR/variance-regions-direct.rs:35:1
|
--> $DIR/variance-regions-direct.rs:35:1
|
||||||
|
|
|
|
||||||
LL | struct Test5<'a, 'b:'a> {
|
LL | struct Test5<'a, 'b:'a> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [-, o]
|
error: [+, o]
|
||||||
--> $DIR/variance-regions-direct.rs:45:1
|
--> $DIR/variance-regions-direct.rs:45:1
|
||||||
|
|
|
|
||||||
LL | struct Test6<'a, 'b:'a> {
|
LL | struct Test6<'a, 'b:'a> {
|
||||||
@ -34,7 +34,7 @@ error: [*]
|
|||||||
LL | struct Test7<'a> {
|
LL | struct Test7<'a> {
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [+, -, o]
|
error: [-, +, o]
|
||||||
--> $DIR/variance-regions-direct.rs:59:1
|
--> $DIR/variance-regions-direct.rs:59:1
|
||||||
|
|
|
|
||||||
LL | enum Test8<'a, 'b, 'c:'b> {
|
LL | enum Test8<'a, 'b, 'c:'b> {
|
||||||
|
@ -5,14 +5,14 @@
|
|||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [+, -, o, *]
|
enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR [-, +, o, *]
|
||||||
Test8A(extern "Rust" fn(&'a isize)),
|
Test8A(extern "Rust" fn(&'a isize)),
|
||||||
Test8B(&'b [isize]),
|
Test8B(&'b [isize]),
|
||||||
Test8C(&'b mut &'c str),
|
Test8C(&'b mut &'c str),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, -, +]
|
struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR [*, o, +, -]
|
||||||
f: Base<'z, 'y, 'x, 'w>
|
f: Base<'z, 'y, 'x, 'w>
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,12 +22,12 @@ struct Derived2<'a, 'b:'a, 'c> { //~ ERROR [o, o, *]
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
|
#[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here)
|
||||||
struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, -, *]
|
struct Derived3<'a:'b, 'b, 'c> { //~ ERROR [o, +, *]
|
||||||
f: Base<'a, 'b, 'a, 'c>
|
f: Base<'a, 'b, 'a, 'c>
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
|
#[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here)
|
||||||
struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [+, -, o]
|
struct Derived4<'a, 'b, 'c:'b> { //~ ERROR [-, +, o]
|
||||||
f: Base<'a, 'b, 'c, 'a>
|
f: Base<'a, 'b, 'c, 'a>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
error: [+, -, o, *]
|
error: [-, +, o, *]
|
||||||
--> $DIR/variance-regions-indirect.rs:8:1
|
--> $DIR/variance-regions-indirect.rs:8:1
|
||||||
|
|
|
|
||||||
LL | enum Base<'a, 'b, 'c:'b, 'd> {
|
LL | enum Base<'a, 'b, 'c:'b, 'd> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [*, o, -, +]
|
error: [*, o, +, -]
|
||||||
--> $DIR/variance-regions-indirect.rs:15:1
|
--> $DIR/variance-regions-indirect.rs:15:1
|
||||||
|
|
|
|
||||||
LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
|
LL | struct Derived1<'w, 'x:'y, 'y, 'z> {
|
||||||
@ -16,13 +16,13 @@ error: [o, o, *]
|
|||||||
LL | struct Derived2<'a, 'b:'a, 'c> {
|
LL | struct Derived2<'a, 'b:'a, 'c> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [o, -, *]
|
error: [o, +, *]
|
||||||
--> $DIR/variance-regions-indirect.rs:25:1
|
--> $DIR/variance-regions-indirect.rs:25:1
|
||||||
|
|
|
|
||||||
LL | struct Derived3<'a:'b, 'b, 'c> {
|
LL | struct Derived3<'a:'b, 'b, 'c> {
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: [+, -, o]
|
error: [-, +, o]
|
||||||
--> $DIR/variance-regions-indirect.rs:30:1
|
--> $DIR/variance-regions-indirect.rs:30:1
|
||||||
|
|
|
|
||||||
LL | struct Derived4<'a, 'b, 'c:'b> {
|
LL | struct Derived4<'a, 'b, 'c:'b> {
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
trait T { fn foo(&self); }
|
trait T { fn foo(&self); }
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct TOption<'a> { //~ ERROR [-]
|
struct TOption<'a> { //~ ERROR [+]
|
||||||
v: Option<Box<dyn T + 'a>>,
|
v: Option<Box<dyn T + 'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
error: [-]
|
error: [+]
|
||||||
--> $DIR/variance-trait-object-bound.rs:14:1
|
--> $DIR/variance-trait-object-bound.rs:14:1
|
||||||
|
|
|
|
||||||
LL | struct TOption<'a> {
|
LL | struct TOption<'a> {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
// not considered bivariant.
|
// not considered bivariant.
|
||||||
|
|
||||||
#[rustc_variance]
|
#[rustc_variance]
|
||||||
struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [-, o, o]
|
struct InvariantMut<'a,A:'a,B:'a> { //~ ERROR [+, o, o]
|
||||||
t: &'a mut (A,B)
|
t: &'a mut (A,B)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
error: [-, o, o]
|
error: [+, o, o]
|
||||||
--> $DIR/variance-types.rs:10:1
|
--> $DIR/variance-types.rs:10:1
|
||||||
|
|
|
|
||||||
LL | struct InvariantMut<'a,A:'a,B:'a> {
|
LL | struct InvariantMut<'a,A:'a,B:'a> {
|
||||||
|
Loading…
Reference in New Issue
Block a user