about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAriel Ben-Yehuda <ariel.byd@gmail.com>2016-04-16 15:16:36 +0300
committerAriel Ben-Yehuda <ariel.byd@gmail.com>2016-05-03 18:30:10 +0300
commit4bcabbd45a7b1a576465ff5e980d63fcd6cd34e0 (patch)
tree253a373c13cf5275d1c22d3b002b7f9649c32b6f
parent73f39a026a5a4e7ac37eb4f4840a9cf25ac5d0a5 (diff)
downloadrust-4bcabbd45a7b1a576465ff5e980d63fcd6cd34e0.tar.gz
rust-4bcabbd45a7b1a576465ff5e980d63fcd6cd34e0.zip
add comments and tests
-rw-r--r--src/librustc/ty/mod.rs38
-rw-r--r--src/test/compile-fail/issue-17431-2.rs1
-rw-r--r--src/test/compile-fail/issue-26548.rs3
-rw-r--r--src/test/compile-fail/range-1.rs1
-rw-r--r--src/test/compile-fail/sized-cycle-note.rs7
-rw-r--r--src/test/run-pass/issue-31299.rs36
6 files changed, 73 insertions, 13 deletions
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index b3ca120bd9f..d2b7354abb9 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -1721,6 +1721,17 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
 
     /// Returns a simpler type such that `Self: Sized` if and only
     /// if that type is Sized, or `TyErr` if this type is recursive.
+    ///
+    /// This is generally the `struct_tail` if this is a struct, or a
+    /// tuple of them if this is an enum.
+    ///
+    /// Oddly enough, checking that the sized-constraint is Sized is
+    /// actually more expressive than checking all members:
+    /// the Sized trait is inductive, so an associated type that references
+    /// Self would prevent its containing ADT from being Sized.
+    ///
+    /// Due to normalization being eager, this applies even if
+    /// the associated type is behind a pointer, e.g. issue #31299.
     pub fn sized_constraint(&self, tcx: &ty::TyCtxt<'tcx>) -> Ty<'tcx> {
         let dep_node = DepNode::SizedConstraint(self.did);
         match self.sized_constraint.get(dep_node) {
@@ -1749,6 +1760,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
             .collect();
 
         match tys.len() {
+            _ if tys.references_error() => tcx.types.err,
             0 => tcx.types.bool,
             1 => tys[0],
             _ => tcx.mk_tup(tys)
@@ -1768,7 +1780,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
                 tcx.types.bool
             }
 
-            TyStr | TyTrait(..) | TySlice(_) => {
+            TyStr | TyTrait(..) | TySlice(_) | TyError => {
                 // these are never sized - return the target type
                 ty
             }
@@ -1797,6 +1809,10 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
             }
 
             TyParam(..) => {
+                // perf hack: if there is a `T: Sized` bound, then
+                // we know that `T` is Sized and do not need to check
+                // it on the impl.
+
                 let sized_trait = match tcx.lang_items.sized_trait() {
                     Some(x) => x,
                     _ => return ty
@@ -1815,7 +1831,7 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
                 }
             }
 
-            TyInfer(..) | TyError => {
+            TyInfer(..) => {
                 bug!("unexpected type `{:?}` in sized_constraint_for_ty",
                      ty)
             }
@@ -1824,9 +1840,21 @@ impl<'tcx> AdtDefData<'tcx, 'tcx> {
         result
     }
 
-    /// Calculates the Sized-constraint. This replaces all always-Sized
-    /// types with bool. I could have made the TyIVar an Option, but that
-    /// would have been so much code.
+    /// 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>>)
     {
diff --git a/src/test/compile-fail/issue-17431-2.rs b/src/test/compile-fail/issue-17431-2.rs
index edbc8c82432..f39fb0e31c6 100644
--- a/src/test/compile-fail/issue-17431-2.rs
+++ b/src/test/compile-fail/issue-17431-2.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 struct Baz { q: Option<Foo> }
+//~^ ERROR recursive type `Baz` has infinite size
 
 struct Foo { q: Option<Baz> }
 //~^ ERROR recursive type `Foo` has infinite size
diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs
index 28080ae09e5..2919b0b3cac 100644
--- a/src/test/compile-fail/issue-26548.rs
+++ b/src/test/compile-fail/issue-26548.rs
@@ -8,10 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// error-pattern: overflow representing the type `S`
+
 trait Mirror { type It: ?Sized; }
 impl<T: ?Sized> Mirror for T { type It = Self; }
 struct S(Option<<S as Mirror>::It>);
-//~^ ERROR recursive type `S` has infinite size
 
 fn main() {
     let _s = S(None);
diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs
index 895d2450cfe..2a0773af73b 100644
--- a/src/test/compile-fail/range-1.rs
+++ b/src/test/compile-fail/range-1.rs
@@ -23,5 +23,4 @@ pub fn main() {
     let arr: &[_] = &[1, 2, 3];
     let range = *arr..;
     //~^ ERROR `[_]: std::marker::Sized` is not satisfied
-    //~| ERROR `[_]: std::marker::Sized` is not satisfied
 }
diff --git a/src/test/compile-fail/sized-cycle-note.rs b/src/test/compile-fail/sized-cycle-note.rs
index 3d7c4868e96..712b4ac22f0 100644
--- a/src/test/compile-fail/sized-cycle-note.rs
+++ b/src/test/compile-fail/sized-cycle-note.rs
@@ -17,14 +17,9 @@
 // 2. it should elaborate the steps that led to the cycle.
 
 struct Baz { q: Option<Foo> }
-
+//~^ ERROR recursive type `Baz` has infinite size
 struct Foo { q: Option<Baz> }
 //~^ ERROR recursive type `Foo` has infinite size
-//~| NOTE type `Foo` is embedded within `std::option::Option<Foo>`...
-//~| NOTE ...which in turn is embedded within `std::option::Option<Foo>`...
-//~| NOTE ...which in turn is embedded within `Baz`...
-//~| NOTE ...which in turn is embedded within `std::option::Option<Baz>`...
-//~| NOTE ...which in turn is embedded within `Foo`, completing the cycle.
 
 impl Foo { fn bar(&self) {} }
 
diff --git a/src/test/run-pass/issue-31299.rs b/src/test/run-pass/issue-31299.rs
new file mode 100644
index 00000000000..e49e13c458f
--- /dev/null
+++ b/src/test/run-pass/issue-31299.rs
@@ -0,0 +1,36 @@
+// Copyright 2012 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// Regression test for #31299. This was generating an overflow error
+// because of eager normalization:
+//
+// proving `M: Sized` requires
+// - proving `PtrBack<Vec<M>>: Sized` requis
+//   - 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.
+
+trait Front {
+    type Back;
+}
+
+impl<T> Front for Vec<T> {
+    type Back = Vec<T>;
+}
+
+struct PtrBack<T: Front>(Vec<T::Back>);
+
+struct M(PtrBack<Vec<M>>);
+
+fn main() {
+    std::mem::size_of::<M>();
+}