diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs index b0444848d619..120006b32016 100644 --- a/src/librustc/ich/impls_mir.rs +++ b/src/librustc/ich/impls_mir.rs @@ -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 => {} diff --git a/src/librustc/mir/mod.rs b/src/librustc/mir/mod.rs index 8feb8f949469..3227888ec6ab 100644 --- a/src/librustc/mir/mod.rs +++ b/src/librustc/mir/mod.rs @@ -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), } } diff --git a/src/librustc/mir/visit.rs b/src/librustc/mir/visit.rs index a70ec8a5c571..723ba6332cce 100644 --- a/src/librustc/mir/visit.rs +++ b/src/librustc/mir/visit.rs @@ -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); diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs index 955f2740b929..bd9dfc6b8551 100644 --- a/src/librustc/ty/structural_impls.rs +++ b/src/librustc/ty/structural_impls.rs @@ -57,6 +57,7 @@ CloneTypeFoldableAndLiftImpls! { ::ty::ClosureKind, ::ty::IntVarValue, ::ty::ParamTy, + ::ty::Variance, ::syntax_pos::Span, } diff --git a/src/librustc_mir/borrow_check/nll/constraint_generation.rs b/src/librustc_mir/borrow_check/nll/constraint_generation.rs index 1ec3506feb41..7e8e1b32d4d9 100644 --- a/src/librustc_mir/borrow_check/nll/constraint_generation.rs +++ b/src/librustc_mir/borrow_check/nll/constraint_generation.rs @@ -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, ) { diff --git a/src/librustc_mir/borrow_check/nll/renumber.rs b/src/librustc_mir/borrow_check/nll/renumber.rs index 5de3247bad29..d77863d598f6 100644 --- a/src/librustc_mir/borrow_check/nll/renumber.rs +++ b/src/librustc_mir/borrow_check/nll/renumber.rs @@ -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, ) { diff --git a/src/librustc_mir/borrow_check/nll/type_check/mod.rs b/src/librustc_mir/borrow_check/nll/type_check/mod.rs index 682bce9266c6..1d06a1335cec 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs @@ -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> { + fn rvalue_user_ty(&self, rvalue: &Rvalue<'tcx>) -> Option> { 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, - } + }, } } diff --git a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs index ef686cb1dd6f..ab0c91aafd16 100644 --- a/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs +++ b/src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs @@ -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>, diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index b5b0f5a2aa03..b5ed68009b5f 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -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, ), },