Skip to content

Commit 16f4e8a

Browse files
committed
generalize AscribeUserType to handle sub or super type
1 parent 9c5e794 commit 16f4e8a

File tree

9 files changed

+62
-92
lines changed

9 files changed

+62
-92
lines changed

src/librustc/ich/impls_mir.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,9 @@ for mir::StatementKind<'gcx> {
255255
op.hash_stable(hcx, hasher);
256256
places.hash_stable(hcx, hasher);
257257
}
258-
mir::StatementKind::AscribeUserType(ref place, ref c_ty) => {
258+
mir::StatementKind::AscribeUserType(ref place, ref variance, ref c_ty) => {
259259
place.hash_stable(hcx, hasher);
260+
variance.hash_stable(hcx, hasher);
260261
c_ty.hash_stable(hcx, hasher);
261262
}
262263
mir::StatementKind::Nop => {}

src/librustc/mir/mod.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1641,9 +1641,14 @@ pub enum StatementKind<'tcx> {
16411641
///
16421642
/// let a: T = y;
16431643
///
1644-
/// Here we would insert a `AscribeUserType` that ensures that the
1645-
/// type `Y` of `y` is a subtype of `T` (`Y <: T`).
1646-
AscribeUserType(Place<'tcx>, CanonicalTy<'tcx>),
1644+
/// The effect of this annotation is to relate the type `T_y` of the place `y`
1645+
/// to the user-given type `T`. The effect depends on the specified variance:
1646+
///
1647+
/// - `Covariant` -- requires that `T_y <: T`
1648+
/// - `Contravariant` -- requires that `T_y :> T`
1649+
/// - `Invariant` -- requires that `T_y == T`
1650+
/// - `Bivariant` -- no effect
1651+
AscribeUserType(Place<'tcx>, ty::Variance, CanonicalTy<'tcx>),
16471652

16481653
/// No-op. Useful for deleting instructions without affecting statement indices.
16491654
Nop,
@@ -1720,8 +1725,8 @@ impl<'tcx> Debug for Statement<'tcx> {
17201725
ref outputs,
17211726
ref inputs,
17221727
} => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs),
1723-
AscribeUserType(ref place, ref c_ty) => {
1724-
write!(fmt, "AscribeUserType({:?}, {:?})", place, c_ty)
1728+
AscribeUserType(ref place, ref variance, ref c_ty) => {
1729+
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
17251730
}
17261731
Nop => write!(fmt, "nop"),
17271732
}
@@ -2644,7 +2649,7 @@ EnumTypeFoldableImpl! {
26442649
(StatementKind::InlineAsm) { asm, outputs, inputs },
26452650
(StatementKind::Validate)(a, b),
26462651
(StatementKind::EndRegion)(a),
2647-
(StatementKind::AscribeUserType)(a, b),
2652+
(StatementKind::AscribeUserType)(a, v, b),
26482653
(StatementKind::Nop),
26492654
}
26502655
}

src/librustc/mir/visit.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,10 @@ macro_rules! make_mir_visitor {
146146

147147
fn visit_ascribe_user_ty(&mut self,
148148
place: & $($mutability)* Place<'tcx>,
149+
variance: & $($mutability)* ty::Variance,
149150
c_ty: & $($mutability)* CanonicalTy<'tcx>,
150151
location: Location) {
151-
self.super_ascribe_user_ty(place, c_ty, location);
152+
self.super_ascribe_user_ty(place, variance, c_ty, location);
152153
}
153154

154155
fn visit_place(&mut self,
@@ -388,9 +389,10 @@ macro_rules! make_mir_visitor {
388389
}
389390
StatementKind::AscribeUserType(
390391
ref $($mutability)* place,
392+
ref $($mutability)* variance,
391393
ref $($mutability)* c_ty,
392394
) => {
393-
self.visit_ascribe_user_ty(place, c_ty, location);
395+
self.visit_ascribe_user_ty(place, variance, c_ty, location);
394396
}
395397
StatementKind::Nop => {}
396398
}
@@ -633,6 +635,7 @@ macro_rules! make_mir_visitor {
633635

634636
fn super_ascribe_user_ty(&mut self,
635637
place: & $($mutability)* Place<'tcx>,
638+
_variance: & $($mutability)* ty::Variance,
636639
c_ty: & $($mutability)* CanonicalTy<'tcx>,
637640
location: Location) {
638641
self.visit_place(place, PlaceContext::Validate, location);

src/librustc/ty/structural_impls.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! {
5757
::ty::ClosureKind,
5858
::ty::IntVarValue,
5959
::ty::ParamTy,
60+
::ty::Variance,
6061
::syntax_pos::Span,
6162
}
6263

src/librustc_mir/borrow_check/nll/constraint_generation.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
178178
fn visit_ascribe_user_ty(
179179
&mut self,
180180
_place: &Place<'tcx>,
181+
_variance: &ty::Variance,
181182
_c_ty: &CanonicalTy<'tcx>,
182183
_location: Location,
183184
) {

src/librustc_mir/borrow_check/nll/renumber.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
115115
fn visit_ascribe_user_ty(
116116
&mut self,
117117
_place: &mut Place<'tcx>,
118+
_variance: &mut ty::Variance,
118119
_c_ty: &mut CanonicalTy<'tcx>,
119120
_location: Location,
120121
) {

src/librustc_mir/borrow_check/nll/type_check/mod.rs

Lines changed: 34 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
1717
use borrow_check::nll::facts::AllFacts;
1818
use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
1919
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
20-
use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
20+
use borrow_check::nll::type_check::free_region_relations::{
21+
CreateResult, UniversalRegionRelations,
22+
};
2123
use borrow_check::nll::universal_regions::UniversalRegions;
2224
use borrow_check::nll::ToRegionVid;
2325
use dataflow::move_paths::MoveData;
@@ -246,10 +248,12 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
246248
self.sanitize_type(constant, constant.ty);
247249

248250
if let Some(user_ty) = constant.user_ty {
249-
if let Err(terr) =
250-
self.cx
251-
.eq_user_type_and_type(user_ty, constant.ty, location.boring())
252-
{
251+
if let Err(terr) = self.cx.relate_type_and_user_type(
252+
constant.ty,
253+
ty::Variance::Invariant,
254+
user_ty,
255+
location.boring(),
256+
) {
253257
span_mirbug!(
254258
self,
255259
constant,
@@ -850,30 +854,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
850854
)
851855
}
852856

853-
fn sub_type_and_user_type(
857+
fn relate_type_and_user_type(
854858
&mut self,
855859
a: Ty<'tcx>,
860+
v: ty::Variance,
856861
b: CanonicalTy<'tcx>,
857862
locations: Locations,
858863
) -> Fallible<()> {
859-
relate_tys::sub_type_and_user_type(
860-
self.infcx,
861-
a,
862-
b,
863-
locations,
864-
self.borrowck_context.as_mut().map(|x| &mut **x),
865-
)
866-
}
867-
868-
fn eq_user_type_and_type(
869-
&mut self,
870-
a: CanonicalTy<'tcx>,
871-
b: Ty<'tcx>,
872-
locations: Locations,
873-
) -> Fallible<()> {
874-
relate_tys::eq_user_type_and_type(
864+
relate_tys::relate_type_and_user_type(
875865
self.infcx,
876866
a,
867+
v,
877868
b,
878869
locations,
879870
self.borrowck_context.as_mut().map(|x| &mut **x),
@@ -894,8 +885,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
894885
// of lowering. Assignments to other sorts of places *are* interesting
895886
// though.
896887
let is_temp = if let Place::Local(l) = *place {
897-
l != RETURN_PLACE &&
898-
!mir.local_decls[l].is_user_variable.is_some()
888+
l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
899889
} else {
900890
false
901891
};
@@ -920,9 +910,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
920910
}
921911

922912
if let Some(user_ty) = self.rvalue_user_ty(rv) {
923-
if let Err(terr) = self.eq_user_type_and_type(
924-
user_ty,
913+
if let Err(terr) = self.relate_type_and_user_type(
925914
rv_ty,
915+
ty::Variance::Invariant,
916+
user_ty,
926917
location.boring(),
927918
) {
928919
span_mirbug!(
@@ -970,9 +961,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
970961
);
971962
};
972963
}
973-
StatementKind::AscribeUserType(ref place, c_ty) => {
964+
StatementKind::AscribeUserType(ref place, variance, c_ty) => {
974965
let place_ty = place.ty(mir, tcx).to_ty(tcx);
975-
if let Err(terr) = self.sub_type_and_user_type(place_ty, c_ty, Locations::All) {
966+
if let Err(terr) =
967+
self.relate_type_and_user_type(place_ty, variance, c_ty, Locations::All)
968+
{
976969
span_mirbug!(
977970
self,
978971
stmt,
@@ -1157,8 +1150,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
11571150
Some((ref dest, _target_block)) => {
11581151
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
11591152
let is_temp = if let Place::Local(l) = *dest {
1160-
l != RETURN_PLACE &&
1161-
!mir.local_decls[l].is_user_variable.is_some()
1153+
l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
11621154
} else {
11631155
false
11641156
};
@@ -1577,30 +1569,26 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
15771569
/// If this rvalue supports a user-given type annotation, then
15781570
/// extract and return it. This represents the final type of the
15791571
/// rvalue and will be unified with the inferred type.
1580-
fn rvalue_user_ty(
1581-
&self,
1582-
rvalue: &Rvalue<'tcx>,
1583-
) -> Option<CanonicalTy<'tcx>> {
1572+
fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<CanonicalTy<'tcx>> {
15841573
match rvalue {
1585-
Rvalue::Use(_) |
1586-
Rvalue::Repeat(..) |
1587-
Rvalue::Ref(..) |
1588-
Rvalue::Len(..) |
1589-
Rvalue::Cast(..) |
1590-
Rvalue::BinaryOp(..) |
1591-
Rvalue::CheckedBinaryOp(..) |
1592-
Rvalue::NullaryOp(..) |
1593-
Rvalue::UnaryOp(..) |
1594-
Rvalue::Discriminant(..) =>
1595-
None,
1574+
Rvalue::Use(_)
1575+
| Rvalue::Repeat(..)
1576+
| Rvalue::Ref(..)
1577+
| Rvalue::Len(..)
1578+
| Rvalue::Cast(..)
1579+
| Rvalue::BinaryOp(..)
1580+
| Rvalue::CheckedBinaryOp(..)
1581+
| Rvalue::NullaryOp(..)
1582+
| Rvalue::UnaryOp(..)
1583+
| Rvalue::Discriminant(..) => None,
15961584

15971585
Rvalue::Aggregate(aggregate, _) => match **aggregate {
15981586
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
15991587
AggregateKind::Array(_) => None,
16001588
AggregateKind::Tuple => None,
16011589
AggregateKind::Closure(_, _) => None,
16021590
AggregateKind::Generator(_, _, _) => None,
1603-
}
1591+
},
16041592
}
16051593
}
16061594

src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs

Lines changed: 6 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ pub(super) fn eq_types<'tcx>(
6363
/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
6464
/// a user-given type (which means it may have canonical variables
6565
/// encoding things like `_`).
66-
pub(super) fn sub_type_and_user_type<'tcx>(
66+
pub(super) fn relate_type_and_user_type<'tcx>(
6767
infcx: &InferCtxt<'_, '_, 'tcx>,
6868
a: Ty<'tcx>,
69+
v: ty::Variance,
6970
b: CanonicalTy<'tcx>,
7071
locations: Locations,
7172
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
@@ -79,53 +80,21 @@ pub(super) fn sub_type_and_user_type<'tcx>(
7980
value: b_value,
8081
} = b;
8182

82-
// (*) The `TypeRelating` code assumes that the "canonical variables"
83-
// appear in the "a" side, so start with `Contravariant` ambient
83+
// The `TypeRelating` code assumes that the "canonical variables"
84+
// appear in the "a" side, so flip `Contravariant` ambient
8485
// variance to get the right relationship.
86+
let v1 = ty::Contravariant.xform(v);
8587

8688
TypeRelating::new(
8789
infcx,
88-
ty::Variance::Contravariant, // (*)
90+
v1,
8991
locations,
9092
borrowck_context,
9193
b_variables,
9294
).relate(&b_value, &a)?;
9395
Ok(())
9496
}
9597

96-
/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
97-
/// a user-given type (which means it may have canonical variables
98-
/// encoding things like `_`).
99-
pub(super) fn eq_user_type_and_type<'tcx>(
100-
infcx: &InferCtxt<'_, '_, 'tcx>,
101-
a: CanonicalTy<'tcx>,
102-
b: Ty<'tcx>,
103-
locations: Locations,
104-
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
105-
) -> Fallible<()> {
106-
debug!(
107-
"eq_user_type_and_type(a={:?}, b={:?}, locations={:?})",
108-
a, b, locations
109-
);
110-
let Canonical {
111-
variables: a_variables,
112-
value: a_value,
113-
} = a;
114-
115-
// (*) The `TypeRelating` code assumes that the "canonical variables"
116-
// appear in the "a" side, so start with `Contravariant` ambient
117-
// variance to get the right relationship.
118-
119-
TypeRelating::new(
120-
infcx,
121-
ty::Variance::Invariant, // (*)
122-
locations,
123-
borrowck_context,
124-
a_variables,
125-
).relate(&a_value, &b)?;
126-
Ok(())
127-
}
128-
12998
struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
13099
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,
131100

src/librustc_mir/build/matches/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,6 +1188,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
11881188
source_info,
11891189
kind: StatementKind::AscribeUserType(
11901190
ascription.source.clone(),
1191+
ty::Variance::Covariant,
11911192
ascription.user_ty,
11921193
),
11931194
},

0 commit comments

Comments
 (0)