about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2018-09-05 15:52:01 -0400
committerNiko Matsakis <niko@alum.mit.edu>2018-09-10 08:28:31 -0400
commit16f4e8ac1d625c74e9711857afae4dac7fcf36e1 (patch)
treefc43641feb42182f8da3c9136f751ad326ef8f98
parent9c5e7941efcf78708f49eee10e954d62b436ea25 (diff)
downloadrust-16f4e8ac1d625c74e9711857afae4dac7fcf36e1.tar.gz
rust-16f4e8ac1d625c74e9711857afae4dac7fcf36e1.zip
generalize `AscribeUserType` to handle sub or super type
-rw-r--r--src/librustc/ich/impls_mir.rs3
-rw-r--r--src/librustc/mir/mod.rs17
-rw-r--r--src/librustc/mir/visit.rs7
-rw-r--r--src/librustc/ty/structural_impls.rs1
-rw-r--r--src/librustc_mir/borrow_check/nll/constraint_generation.rs1
-rw-r--r--src/librustc_mir/borrow_check/nll/renumber.rs1
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs80
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/relate_tys.rs43
-rw-r--r--src/librustc_mir/build/matches/mod.rs1
9 files changed, 62 insertions, 92 deletions
diff --git a/src/librustc/ich/impls_mir.rs b/src/librustc/ich/impls_mir.rs
index b0444848d61..120006b3201 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 8feb8f94946..3227888ec6a 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 a70ec8a5c57..723ba6332cc 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 955f2740b92..bd9dfc6b855 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 1ec3506feb4..7e8e1b32d4d 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 5de3247bad2..d77863d598f 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 682bce9266c..1d06a1335ce 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<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,
-            }
+            },
         }
     }
 
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 ef686cb1dd6..ab0c91aafd1 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 b5b0f5a2aa0..b5ed68009b5 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,
                     ),
                 },