about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-11-10 09:38:10 +0000
committerbors <bors@rust-lang.org>2018-11-10 09:38:10 +0000
commit4cd3294a1d0c5b34020ac35cf7cc00044f7c3b19 (patch)
tree564530c64dc26c9e033d79e216e7dc62a08719ab
parent0366ccafa6f1740acc9c26797e08d7691d835393 (diff)
parent1bbaa553416b67fd2de472829f465ca0b24186a2 (diff)
Auto merge of #55637 - pnkfelix:issue-55552-dont-attempt-to-ascribe-projections-out-of-a-ty-var, r=nikomatsakis
Do not attempt to ascribe projections out of a ty var

If we encounter `_` ascribed to structural pattern like `(a, b)`, just skip relate_types.

Fix #55552
-rw-r--r--src/librustc/mir/tcx.rs19
-rw-r--r--src/librustc_mir/borrow_check/nll/type_check/mod.rs35
-rw-r--r--src/librustc_traits/type_op.rs30
-rw-r--r--src/test/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs31
4 files changed, 93 insertions, 22 deletions
diff --git a/src/librustc/mir/tcx.rs b/src/librustc/mir/tcx.rs
index 4b53235eab4..f773f46b6f5 100644
--- a/src/librustc/mir/tcx.rs
+++ b/src/librustc/mir/tcx.rs
@@ -80,7 +80,8 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
                          elem: &PlaceElem<'tcx>)
                          -> PlaceTy<'tcx>
     {
-        self.projection_ty_core(tcx, elem, |_, _, ty| ty)
+        self.projection_ty_core(tcx, elem, |_, _, ty| -> Result<Ty<'tcx>, ()> { Ok(ty) })
+            .unwrap()
     }
 
     /// `place_ty.projection_ty_core(tcx, elem, |...| { ... })`
@@ -88,11 +89,12 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
     /// `Ty` or downcast variant corresponding to that projection.
     /// The `handle_field` callback must map a `Field` to its `Ty`,
     /// (which should be trivial when `T` = `Ty`).
-    pub fn projection_ty_core<V, T>(self,
-                                    tcx: TyCtxt<'a, 'gcx, 'tcx>,
-                                    elem: &ProjectionElem<'tcx, V, T>,
-                                    mut handle_field: impl FnMut(&Self, &Field, &T) -> Ty<'tcx>)
-                                    -> PlaceTy<'tcx>
+    pub fn projection_ty_core<V, T, E>(
+        self,
+        tcx: TyCtxt<'a, 'gcx, 'tcx>,
+        elem: &ProjectionElem<'tcx, V, T>,
+        mut handle_field: impl FnMut(&Self, &Field, &T) -> Result<Ty<'tcx>, E>)
+        -> Result<PlaceTy<'tcx>, E>
     where
         V: ::std::fmt::Debug, T: ::std::fmt::Debug
     {
@@ -142,10 +144,11 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
                         bug!("cannot downcast non-ADT type: `{:?}`", self)
                     }
                 },
-            ProjectionElem::Field(ref f, ref fty) => PlaceTy::Ty { ty: handle_field(&self, f, fty) }
+            ProjectionElem::Field(ref f, ref fty) =>
+                PlaceTy::Ty { ty: handle_field(&self, f, fty)? },
         };
         debug!("projection_ty self: {:?} elem: {:?} yields: {:?}", self, elem, answer);
-        answer
+        Ok(answer)
     }
 }
 
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 734ddbc3ab9..a057f2f45c0 100644
--- a/src/librustc_mir/borrow_check/nll/type_check/mod.rs
+++ b/src/librustc_mir/borrow_check/nll/type_check/mod.rs
@@ -1021,20 +1021,39 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
                 let v1 = ty::Contravariant.xform(v);
 
                 let tcx = self.infcx.tcx;
-                let mut projected_ty = PlaceTy::from_ty(ty);
+                let ty = self.normalize(ty, locations);
+
+                // We need to follow any provided projetions into the type.
+                //
+                // if we hit a ty var as we descend, then just skip the
+                // attempt to relate the mir local with any type.
+                #[derive(Debug)] struct HitTyVar;
+                let mut curr_projected_ty: Result<PlaceTy, HitTyVar>;
+
+                curr_projected_ty = Ok(PlaceTy::from_ty(ty));
                 for proj in &user_ty.projs {
-                    projected_ty = projected_ty.projection_ty_core(
+                    let projected_ty = if let Ok(projected_ty) = curr_projected_ty {
+                        projected_ty
+                    } else {
+                        break;
+                    };
+                    curr_projected_ty = projected_ty.projection_ty_core(
                         tcx, proj, |this, field, &()| {
-                            let ty = this.field_ty(tcx, field);
-                            self.normalize(ty, locations)
+                            if this.to_ty(tcx).is_ty_var() {
+                                Err(HitTyVar)
+                            } else {
+                                let ty = this.field_ty(tcx, field);
+                                Ok(self.normalize(ty, locations))
+                            }
                         });
                 }
                 debug!("user_ty base: {:?} freshened: {:?} projs: {:?} yields: {:?}",
-                       user_ty.base, ty, user_ty.projs, projected_ty);
+                       user_ty.base, ty, user_ty.projs, curr_projected_ty);
 
-                let ty = projected_ty.to_ty(tcx);
-
-                self.relate_types(ty, v1, a, locations, category)?;
+                if let Ok(projected_ty) = curr_projected_ty {
+                    let ty = projected_ty.to_ty(tcx);
+                    self.relate_types(ty, v1, a, locations, category)?;
+                }
             }
             UserTypeAnnotation::TypeOf(def_id, canonical_substs) => {
                 let (
diff --git a/src/librustc_traits/type_op.rs b/src/librustc_traits/type_op.rs
index 2ed02a4cdab..e635bc9efc4 100644
--- a/src/librustc_traits/type_op.rs
+++ b/src/librustc_traits/type_op.rs
@@ -151,17 +151,35 @@ impl AscribeUserTypeCx<'me, 'gcx, 'tcx> {
         debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
         let ty = self.normalize(ty);
 
-        let mut projected_ty = PlaceTy::from_ty(ty);
+        // We need to follow any provided projetions into the type.
+        //
+        // if we hit a ty var as we descend, then just skip the
+        // attempt to relate the mir local with any type.
+
+        struct HitTyVar;
+        let mut curr_projected_ty: Result<PlaceTy, HitTyVar>;
+        curr_projected_ty = Ok(PlaceTy::from_ty(ty));
         for proj in projs {
-            projected_ty = projected_ty.projection_ty_core(
+            let projected_ty = if let Ok(projected_ty) = curr_projected_ty {
+                projected_ty
+            } else {
+                break;
+            };
+            curr_projected_ty = projected_ty.projection_ty_core(
                 tcx, proj, |this, field, &()| {
-                    let ty = this.field_ty(tcx, field);
-                    self.normalize(ty)
+                    if this.to_ty(tcx).is_ty_var() {
+                        Err(HitTyVar)
+                    } else {
+                        let ty = this.field_ty(tcx, field);
+                        Ok(self.normalize(ty))
+                    }
                 });
         }
-        let ty = projected_ty.to_ty(tcx);
 
-        self.relate(mir_ty, variance, ty)?;
+        if let Ok(projected_ty) = curr_projected_ty {
+            let ty = projected_ty.to_ty(tcx);
+            self.relate(mir_ty, variance, ty)?;
+        }
 
         if let Some(UserSelfTy {
             impl_def_id,
diff --git a/src/test/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs b/src/test/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs
new file mode 100644
index 00000000000..6d91fd3508a
--- /dev/null
+++ b/src/test/ui/borrowck/issue-55552-ascribe-wildcard-to-structured-pattern.rs
@@ -0,0 +1,31 @@
+// compile-pass
+
+// rust-lang/rust#55552: The strategy pnkfelix landed in PR #55274
+// (for ensuring that NLL respects user-provided lifetime annotations)
+// did not handle the case where the ascribed type has some expliit
+// wildcards (`_`) mixed in, and it caused an internal compiler error
+// (ICE).
+//
+// This test is just checking that we do not ICE when such things
+// occur.
+
+struct X;
+struct Y;
+struct Z;
+
+struct Pair { x: X, y: Y }
+
+pub fn join<A, B, RA, RB>(oper_a: A, oper_b: B) -> (RA, RB)
+where A: FnOnce() -> RA + Send,
+      B: FnOnce() -> RB + Send,
+      RA: Send,
+      RB: Send
+{
+    (oper_a(), oper_b())
+}
+
+fn main() {
+    let ((_x, _y), _z): (_, Z) = join(|| (X, Y), || Z);
+
+    let (Pair { x: _x, y: _y }, Z): (_, Z) = join(|| Pair { x: X, y: Y }, || Z);
+}