about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-04-22 16:38:17 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2016-05-03 18:30:10 +0300
commit05f1a057b6e59fd07b4af7a9a2f0101d67faba88 (patch)
tree89b72843e31fc98ae1670741e197dfc29ed37cf0
parent6fc19ada6b2c6373b28e70a1dffda68dba96f9a1 (diff)
downloadrust-05f1a057b6e59fd07b4af7a9a2f0101d67faba88.tar.gz
rust-05f1a057b6e59fd07b4af7a9a2f0101d67faba88.zip
address review comments
-rw-r--r--src/librustc/ty/mod.rs156
-rw-r--r--src/test/run-pass/issue-31299.rs9
2 files changed, 83 insertions, 82 deletions
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index b4156fde6a3..a61e8603dbb 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1750,28 +1750,69 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
 }
 
 impl<'tcx> AdtDefData<'tcx, 'tcx> {
-    fn sized_constraint_for_tys<TYS>(
-        &'tcx self,
-        tcx: &ty::TyCtxt<'tcx>,
-        stack: &mut Vec<AdtDefMaster<'tcx>>,
-        tys: TYS
-    ) -> Ty<'tcx>
-        where TYS: IntoIterator<Item=Ty<'tcx>>
+    /// Calculates the Sized-constraint.
+    ///
+    /// As the Sized-constraint of enums can be a *set* of types,
+    /// the Sized-constraint may need to be a set also. Because introducing
+    /// a new type of IVar is currently a complex affair, the Sized-constraint
+    /// may be a tuple.
+    ///
+    /// In fact, there are only a few options for the constraint:
+    ///     - `bool`, if the type is always Sized
+    ///     - an obviously-unsized type
+    ///     - a type parameter or projection whose Sizedness can't be known
+    ///     - a tuple of type parameters or projections, if there are multiple
+    ///       such.
+    ///     - a TyError, if a type contained itself. The representability
+    ///       check should catch this case.
+    fn calculate_sized_constraint_inner(&'tcx self, tcx: &ty::TyCtxt<'tcx>,
+                                        stack: &mut Vec<AdtDefMaster<'tcx>>)
     {
-        let tys : Vec<_> = tys.into_iter()
-            .map(|ty| self.sized_constraint_for_ty(tcx, stack, ty))
-            .flat_map(|ty| match ty.sty {
-                ty::TyTuple(ref tys) => tys.last().cloned(),
-                _ => Some(ty)
-            })
-            .filter(|ty| *ty != tcx.types.bool)
-            .collect();
-
-        match tys.len() {
+
+        let dep_node = DepNode::SizedConstraint(self.did);
+
+        if self.sized_constraint.get(dep_node).is_some() {
+            return;
+        }
+
+        if stack.contains(&self) {
+            debug!("calculate_sized_constraint: {:?} is recursive", self);
+            // This should be reported as an error by `check_representable`.
+            //
+            // Consider the type as Sized in the meanwhile to avoid
+            // further errors.
+            self.sized_constraint.fulfill(dep_node, tcx.types.err);
+            return;
+        }
+
+        stack.push(self);
+
+        let tys : Vec<_> =
+            self.variants.iter().flat_map(|v| {
+                v.fields.last()
+            }).flat_map(|f| {
+                self.sized_constraint_for_ty(tcx, stack, f.unsubst_ty())
+            }).collect();
+
+        let self_ = stack.pop().unwrap();
+        assert_eq!(self_, self);
+
+        let ty = match tys.len() {
             _ if tys.references_error() => tcx.types.err,
             0 => tcx.types.bool,
             1 => tys[0],
             _ => tcx.mk_tup(tys)
+        };
+
+        match self.sized_constraint.get(dep_node) {
+            Some(old_ty) => {
+                debug!("calculate_sized_constraint: {:?} recurred", self);
+                assert_eq!(old_ty, tcx.types.err)
+            }
+            None => {
+                debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
+                self.sized_constraint.fulfill(dep_node, ty)
+            }
         }
     }
 
@@ -1780,22 +1821,23 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
         tcx: &ty::TyCtxt<'tcx>,
         stack: &mut Vec<AdtDefMaster<'tcx>>,
         ty: Ty<'tcx>
-    ) -> Ty<'tcx> {
+    ) -> Vec<Ty<'tcx>> {
         let result = match ty.sty {
             TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
             TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
             TyArray(..) | TyClosure(..) => {
-                // these are always sized - return a primitive
-                tcx.types.bool
+                vec![]
             }
 
             TyStr | TyTrait(..) | TySlice(_) | TyError => {
                 // these are never sized - return the target type
-                ty
+                vec![ty]
             }
 
             TyTuple(ref tys) => {
-                self.sized_constraint_for_tys(tcx, stack, tys.iter().cloned())
+                tys.last().into_iter().flat_map(|ty| {
+                    self.sized_constraint_for_ty(tcx, stack, ty)
+                }).collect()
             }
 
             TyEnum(adt, substs) | TyStruct(adt, substs) => {
@@ -1808,13 +1850,19 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
                     .subst(tcx, substs);
                 debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
                        ty, adt_ty);
-                self.sized_constraint_for_ty(tcx, stack, adt_ty)
+                if let ty::TyTuple(ref tys) = adt_ty.sty {
+                    tys.iter().flat_map(|ty| {
+                        self.sized_constraint_for_ty(tcx, stack, ty)
+                    }).collect()
+                } else {
+                    self.sized_constraint_for_ty(tcx, stack, adt_ty)
+                }
             }
 
             TyProjection(..) => {
                 // must calculate explicitly.
                 // FIXME: consider special-casing always-Sized projections
-                ty
+                vec![ty]
             }
 
             TyParam(..) => {
@@ -1824,7 +1872,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
 
                 let sized_trait = match tcx.lang_items.sized_trait() {
                     Some(x) => x,
-                    _ => return ty
+                    _ => return vec![ty]
                 };
                 let sized_predicate = Binder(TraitRef {
                     def_id: sized_trait,
@@ -1834,9 +1882,9 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
                 }).to_predicate();
                 let predicates = tcx.lookup_predicates(self.did).predicates;
                 if predicates.into_iter().any(|p| p == sized_predicate) {
-                    tcx.types.bool
+                    vec![]
                 } else {
-                    ty
+                    vec![ty]
                 }
             }
 
@@ -1848,60 +1896,6 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
         debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
         result
     }
-
-    /// Calculates the Sized-constraint.
-    ///
-    /// As the Sized-constraint of enums can be a *set* of types,
-    /// the Sized-constraint may need to be a set also. Because introducing
-    /// a new type of IVar is currently a complex affair, the Sized-constraint
-    /// may be a tuple.
-    ///
-    /// In fact, there are only a few options for the constraint:
-    ///     - `bool`, if the type is always Sized
-    ///     - an obviously-unsized type
-    ///     - a type parameter or projection whose Sizedness can't be known
-    ///     - a tuple of type parameters or projections, if there are multiple
-    ///       such.
-    ///     - a TyError, if a type contained itself. The representability
-    ///       check should catch this case.
-    fn calculate_sized_constraint_inner(&'tcx self, tcx: &ty::TyCtxt<'tcx>,
-                                        stack: &mut Vec<AdtDefMaster<'tcx>>)
-    {
-
-        let dep_node = DepNode::SizedConstraint(self.did);
-
-        if self.sized_constraint.get(dep_node).is_some() {
-            return;
-        }
-
-        if stack.contains(&self) {
-            debug!("calculate_sized_constraint: {:?} is recursive", self);
-            self.sized_constraint.fulfill(dep_node, tcx.types.err);
-            return;
-        }
-
-        stack.push(self);
-        let ty = self.sized_constraint_for_tys(
-            tcx, stack,
-            self.variants.iter().flat_map(|v| {
-                v.fields.last()
-            }).map(|f| f.unsubst_ty())
-        );
-
-        let self_ = stack.pop().unwrap();
-        assert_eq!(self_, self);
-
-        match self.sized_constraint.get(dep_node) {
-            Some(old_ty) => {
-                debug!("calculate_sized_constraint: {:?} recurred", self);
-                assert_eq!(old_ty, tcx.types.err)
-            }
-            None => {
-                debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
-                self.sized_constraint.fulfill(dep_node, ty)
-            }
-        }
-    }
 }
 
 impl<'tcx, 'container> VariantDefData<'tcx, 'container> {
diff --git a/src/test/run-pass/issue-31299.rs b/src/test/run-pass/issue-31299.rs
index e49e13c458f..6c04e66068e 100644
--- a/src/test/run-pass/issue-31299.rs
+++ b/src/test/run-pass/issue-31299.rs
@@ -12,12 +12,19 @@
 // because of eager normalization:
 //
 // proving `M: Sized` requires
-// - proving `PtrBack<Vec<M>>: Sized` requis
+// - proving `PtrBack<Vec<M>>: Sized` requires
 //   - normalizing `Vec<<Vec<M> as Front>::Back>>: Sized` requires
 //     - proving `Vec<M>: Front` requires
 //       - `M: Sized` <-- cycle!
 //
 // If we skip the normalization step, though, everything goes fine.
+//
+// This could be fixed by implementing lazy normalization everywhere.
+//
+// However, we want this to work before then. For that, when checking
+// whether a type is Sized we only check that the tails are Sized. As
+// PtrBack does not have a tail, we don't need to normalize anything
+// and this compiles
 
 trait Front {
     type Back;