generalize AscribeUserType to handle sub or super type

This commit is contained in:
Niko Matsakis 2018-09-05 15:52:01 -04:00
parent 9c5e7941ef
commit 16f4e8ac1d
9 changed files with 62 additions and 92 deletions

View file

@ -255,8 +255,9 @@ for mir::StatementKind<'gcx> {
op.hash_stable(hcx, hasher);
places.hash_stable(hcx, hasher);
}
mir::StatementKind::AscribeUserType(ref place, ref c_ty) => {
mir::StatementKind::AscribeUserType(ref place, ref variance, ref c_ty) => {
place.hash_stable(hcx, hasher);
variance.hash_stable(hcx, hasher);
c_ty.hash_stable(hcx, hasher);
}
mir::StatementKind::Nop => {}

View file

@ -1641,9 +1641,14 @@ pub enum StatementKind<'tcx> {
///
/// let a: T = y;
///
/// Here we would insert a `AscribeUserType` that ensures that the
/// type `Y` of `y` is a subtype of `T` (`Y <: T`).
AscribeUserType(Place<'tcx>, CanonicalTy<'tcx>),
/// The effect of this annotation is to relate the type `T_y` of the place `y`
/// to the user-given type `T`. The effect depends on the specified variance:
///
/// - `Covariant` -- requires that `T_y <: T`
/// - `Contravariant` -- requires that `T_y :> T`
/// - `Invariant` -- requires that `T_y == T`
/// - `Bivariant` -- no effect
AscribeUserType(Place<'tcx>, ty::Variance, CanonicalTy<'tcx>),
/// No-op. Useful for deleting instructions without affecting statement indices.
Nop,
@ -1720,8 +1725,8 @@ impl<'tcx> Debug for Statement<'tcx> {
ref outputs,
ref inputs,
} => write!(fmt, "asm!({:?} : {:?} : {:?})", asm, outputs, inputs),
AscribeUserType(ref place, ref c_ty) => {
write!(fmt, "AscribeUserType({:?}, {:?})", place, c_ty)
AscribeUserType(ref place, ref variance, ref c_ty) => {
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
}
Nop => write!(fmt, "nop"),
}
@ -2644,7 +2649,7 @@ EnumTypeFoldableImpl! {
(StatementKind::InlineAsm) { asm, outputs, inputs },
(StatementKind::Validate)(a, b),
(StatementKind::EndRegion)(a),
(StatementKind::AscribeUserType)(a, b),
(StatementKind::AscribeUserType)(a, v, b),
(StatementKind::Nop),
}
}

View file

@ -146,9 +146,10 @@ macro_rules! make_mir_visitor {
fn visit_ascribe_user_ty(&mut self,
place: & $($mutability)* Place<'tcx>,
variance: & $($mutability)* ty::Variance,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
location: Location) {
self.super_ascribe_user_ty(place, c_ty, location);
self.super_ascribe_user_ty(place, variance, c_ty, location);
}
fn visit_place(&mut self,
@ -388,9 +389,10 @@ macro_rules! make_mir_visitor {
}
StatementKind::AscribeUserType(
ref $($mutability)* place,
ref $($mutability)* variance,
ref $($mutability)* c_ty,
) => {
self.visit_ascribe_user_ty(place, c_ty, location);
self.visit_ascribe_user_ty(place, variance, c_ty, location);
}
StatementKind::Nop => {}
}
@ -633,6 +635,7 @@ macro_rules! make_mir_visitor {
fn super_ascribe_user_ty(&mut self,
place: & $($mutability)* Place<'tcx>,
_variance: & $($mutability)* ty::Variance,
c_ty: & $($mutability)* CanonicalTy<'tcx>,
location: Location) {
self.visit_place(place, PlaceContext::Validate, location);

View file

@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! {
::ty::ClosureKind,
::ty::IntVarValue,
::ty::ParamTy,
::ty::Variance,
::syntax_pos::Span,
}

View file

@ -178,6 +178,7 @@ impl<'cg, 'cx, 'gcx, 'tcx> Visitor<'tcx> for ConstraintGeneration<'cg, 'cx, 'gcx
fn visit_ascribe_user_ty(
&mut self,
_place: &Place<'tcx>,
_variance: &ty::Variance,
_c_ty: &CanonicalTy<'tcx>,
_location: Location,
) {

View file

@ -115,6 +115,7 @@ impl<'a, 'gcx, 'tcx> MutVisitor<'tcx> for NLLVisitor<'a, 'gcx, 'tcx> {
fn visit_ascribe_user_ty(
&mut self,
_place: &mut Place<'tcx>,
_variance: &mut ty::Variance,
_c_ty: &mut CanonicalTy<'tcx>,
_location: Location,
) {

View file

@ -17,7 +17,9 @@ use borrow_check::nll::constraints::{ConstraintSet, OutlivesConstraint};
use borrow_check::nll::facts::AllFacts;
use borrow_check::nll::region_infer::values::{LivenessValues, RegionValueElements};
use borrow_check::nll::region_infer::{ClosureRegionRequirementsExt, TypeTest};
use borrow_check::nll::type_check::free_region_relations::{CreateResult, UniversalRegionRelations};
use borrow_check::nll::type_check::free_region_relations::{
CreateResult, UniversalRegionRelations,
};
use borrow_check::nll::universal_regions::UniversalRegions;
use borrow_check::nll::ToRegionVid;
use dataflow::move_paths::MoveData;
@ -246,10 +248,12 @@ impl<'a, 'b, 'gcx, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'gcx, 'tcx> {
self.sanitize_type(constant, constant.ty);
if let Some(user_ty) = constant.user_ty {
if let Err(terr) =
self.cx
.eq_user_type_and_type(user_ty, constant.ty, location.boring())
{
if let Err(terr) = self.cx.relate_type_and_user_type(
constant.ty,
ty::Variance::Invariant,
user_ty,
location.boring(),
) {
span_mirbug!(
self,
constant,
@ -850,30 +854,17 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
)
}
fn sub_type_and_user_type(
fn relate_type_and_user_type(
&mut self,
a: Ty<'tcx>,
v: ty::Variance,
b: CanonicalTy<'tcx>,
locations: Locations,
) -> Fallible<()> {
relate_tys::sub_type_and_user_type(
self.infcx,
a,
b,
locations,
self.borrowck_context.as_mut().map(|x| &mut **x),
)
}
fn eq_user_type_and_type(
&mut self,
a: CanonicalTy<'tcx>,
b: Ty<'tcx>,
locations: Locations,
) -> Fallible<()> {
relate_tys::eq_user_type_and_type(
relate_tys::relate_type_and_user_type(
self.infcx,
a,
v,
b,
locations,
self.borrowck_context.as_mut().map(|x| &mut **x),
@ -894,8 +885,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
// of lowering. Assignments to other sorts of places *are* interesting
// though.
let is_temp = if let Place::Local(l) = *place {
l != RETURN_PLACE &&
!mir.local_decls[l].is_user_variable.is_some()
l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
} else {
false
};
@ -920,9 +910,10 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
}
if let Some(user_ty) = self.rvalue_user_ty(rv) {
if let Err(terr) = self.eq_user_type_and_type(
user_ty,
if let Err(terr) = self.relate_type_and_user_type(
rv_ty,
ty::Variance::Invariant,
user_ty,
location.boring(),
) {
span_mirbug!(
@ -970,9 +961,11 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
);
};
}
StatementKind::AscribeUserType(ref place, c_ty) => {
StatementKind::AscribeUserType(ref place, variance, c_ty) => {
let place_ty = place.ty(mir, tcx).to_ty(tcx);
if let Err(terr) = self.sub_type_and_user_type(place_ty, c_ty, Locations::All) {
if let Err(terr) =
self.relate_type_and_user_type(place_ty, variance, c_ty, Locations::All)
{
span_mirbug!(
self,
stmt,
@ -1157,8 +1150,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
Some((ref dest, _target_block)) => {
let dest_ty = dest.ty(mir, tcx).to_ty(tcx);
let is_temp = if let Place::Local(l) = *dest {
l != RETURN_PLACE &&
!mir.local_decls[l].is_user_variable.is_some()
l != RETURN_PLACE && !mir.local_decls[l].is_user_variable.is_some()
} else {
false
};
@ -1577,22 +1569,18 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
/// If this rvalue supports a user-given type annotation, then
/// extract and return it. This represents the final type of the
/// rvalue and will be unified with the inferred type.
fn rvalue_user_ty(
&self,
rvalue: &Rvalue<'tcx>,
) -> Option<CanonicalTy<'tcx>> {
fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option<CanonicalTy<'tcx>> {
match rvalue {
Rvalue::Use(_) |
Rvalue::Repeat(..) |
Rvalue::Ref(..) |
Rvalue::Len(..) |
Rvalue::Cast(..) |
Rvalue::BinaryOp(..) |
Rvalue::CheckedBinaryOp(..) |
Rvalue::NullaryOp(..) |
Rvalue::UnaryOp(..) |
Rvalue::Discriminant(..) =>
None,
Rvalue::Use(_)
| Rvalue::Repeat(..)
| Rvalue::Ref(..)
| Rvalue::Len(..)
| Rvalue::Cast(..)
| Rvalue::BinaryOp(..)
| Rvalue::CheckedBinaryOp(..)
| Rvalue::NullaryOp(..)
| Rvalue::UnaryOp(..)
| Rvalue::Discriminant(..) => None,
Rvalue::Aggregate(aggregate, _) => match **aggregate {
AggregateKind::Adt(_, _, _, user_ty, _) => user_ty,
@ -1600,7 +1588,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
AggregateKind::Tuple => None,
AggregateKind::Closure(_, _) => None,
AggregateKind::Generator(_, _, _) => None,
}
},
}
}

View file

@ -63,9 +63,10 @@ pub(super) fn eq_types<'tcx>(
/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
/// a user-given type (which means it may have canonical variables
/// encoding things like `_`).
pub(super) fn sub_type_and_user_type<'tcx>(
pub(super) fn relate_type_and_user_type<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: Ty<'tcx>,
v: ty::Variance,
b: CanonicalTy<'tcx>,
locations: Locations,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
@ -79,13 +80,14 @@ pub(super) fn sub_type_and_user_type<'tcx>(
value: b_value,
} = b;
// (*) The `TypeRelating` code assumes that the "canonical variables"
// appear in the "a" side, so start with `Contravariant` ambient
// The `TypeRelating` code assumes that the "canonical variables"
// appear in the "a" side, so flip `Contravariant` ambient
// variance to get the right relationship.
let v1 = ty::Contravariant.xform(v);
TypeRelating::new(
infcx,
ty::Variance::Contravariant, // (*)
v1,
locations,
borrowck_context,
b_variables,
@ -93,39 +95,6 @@ pub(super) fn sub_type_and_user_type<'tcx>(
Ok(())
}
/// Adds sufficient constraints to ensure that `a <: b`, where `b` is
/// a user-given type (which means it may have canonical variables
/// encoding things like `_`).
pub(super) fn eq_user_type_and_type<'tcx>(
infcx: &InferCtxt<'_, '_, 'tcx>,
a: CanonicalTy<'tcx>,
b: Ty<'tcx>,
locations: Locations,
borrowck_context: Option<&mut BorrowCheckContext<'_, 'tcx>>,
) -> Fallible<()> {
debug!(
"eq_user_type_and_type(a={:?}, b={:?}, locations={:?})",
a, b, locations
);
let Canonical {
variables: a_variables,
value: a_value,
} = a;
// (*) The `TypeRelating` code assumes that the "canonical variables"
// appear in the "a" side, so start with `Contravariant` ambient
// variance to get the right relationship.
TypeRelating::new(
infcx,
ty::Variance::Invariant, // (*)
locations,
borrowck_context,
a_variables,
).relate(&a_value, &b)?;
Ok(())
}
struct TypeRelating<'cx, 'bccx: 'cx, 'gcx: 'tcx, 'tcx: 'bccx> {
infcx: &'cx InferCtxt<'cx, 'gcx, 'tcx>,

View file

@ -1188,6 +1188,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
source_info,
kind: StatementKind::AscribeUserType(
ascription.source.clone(),
ty::Variance::Covariant,
ascription.user_ty,
),
},