generalize AscribeUserType to handle sub or super type
This commit is contained in:
parent
9c5e7941ef
commit
16f4e8ac1d
9 changed files with 62 additions and 92 deletions
|
|
@ -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 => {}
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! {
|
|||
::ty::ClosureKind,
|
||||
::ty::IntVarValue,
|
||||
::ty::ParamTy,
|
||||
::ty::Variance,
|
||||
::syntax_pos::Span,
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
),
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue