]> git.lizzy.rs Git - rust.git/commitdiff
Detect cycles and specialize error reporting for Sized. It is important
authorNiko Matsakis <niko@alum.mit.edu>
Sat, 9 Jan 2016 02:41:37 +0000 (21:41 -0500)
committerNiko Matsakis <niko@alum.mit.edu>
Sat, 16 Jan 2016 10:22:32 +0000 (05:22 -0500)
to get the `Sized` error usable, since that hits new users
frequently. Further work is needed for the error reporting for non-Sized
cycle cases; those currently just fallback to the old path. Also adjust tests.

40 files changed:
src/librustc/diagnostics.rs
src/librustc/middle/traits/error_reporting.rs
src/librustc/middle/traits/fulfill.rs
src/librustc/middle/traits/mod.rs
src/librustc/middle/traits/project.rs
src/librustc/middle/traits/select.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/diagnostics.rs
src/test/compile-fail/bad-sized.rs
src/test/compile-fail/infinite-tag-type-recursion.rs
src/test/compile-fail/issue-17431-1.rs
src/test/compile-fail/issue-17431-2.rs
src/test/compile-fail/issue-17431-3.rs
src/test/compile-fail/issue-17431-4.rs
src/test/compile-fail/issue-17431-5.rs
src/test/compile-fail/issue-17431-6.rs
src/test/compile-fail/issue-17431-7.rs
src/test/compile-fail/issue-20261.rs
src/test/compile-fail/issue-20831-debruijn.rs
src/test/compile-fail/issue-26548.rs
src/test/compile-fail/issue-2718-a.rs
src/test/compile-fail/issue-3008-1.rs
src/test/compile-fail/issue-3008-2.rs
src/test/compile-fail/issue-3008-3.rs
src/test/compile-fail/issue-3779.rs
src/test/compile-fail/issue-7364.rs
src/test/compile-fail/kindck-impl-type-params.rs
src/test/compile-fail/lint-ctypes.rs
src/test/compile-fail/mut-not-freeze.rs
src/test/compile-fail/not-panic-safe-2.rs
src/test/compile-fail/not-panic-safe-3.rs
src/test/compile-fail/not-panic-safe-4.rs
src/test/compile-fail/not-panic-safe-6.rs
src/test/compile-fail/object-safety-generics.rs
src/test/compile-fail/range-1.rs
src/test/compile-fail/recursive-enum.rs
src/test/compile-fail/sized-cycle-note.rs [new file with mode: 0644]
src/test/compile-fail/trait-bounds-on-structs-and-enums-locals.rs
src/test/compile-fail/trait-test-2.rs
src/test/compile-fail/type-recursive.rs

index 3aabe4b4931307d10bf6e12b3967a6066ae56d5a..2a2936e73631638e4158378ffaeecdc689449324 100644 (file)
@@ -712,6 +712,43 @@ trait Super<A> {
 you no longer need to derive from `Super<Self>`.
 "####,
 
+E0072: r##"
+When defining a recursive struct or enum, any use of the type being defined
+from inside the definition must occur behind a pointer (like `Box` or `&`).
+This is because structs and enums must have a well-defined size, and without
+the pointer the size of the type would need to be unbounded.
+
+Consider the following erroneous definition of a type for a list of bytes:
+
+```
+// error, invalid recursive struct type
+struct ListNode {
+    head: u8,
+    tail: Option<ListNode>,
+}
+```
+
+This type cannot have a well-defined size, because it needs to be arbitrarily
+large (since we would be able to nest `ListNode`s to any depth). Specifically,
+
+```plain
+size of `ListNode` = 1 byte for `head`
+                   + 1 byte for the discriminant of the `Option`
+                   + size of `ListNode`
+```
+
+One way to fix this is by wrapping `ListNode` in a `Box`, like so:
+
+```
+struct ListNode {
+    head: u8,
+    tail: Option<Box<ListNode>>,
+}
+```
+
+This works because `Box` is a pointer, so its size is well-known.
+"##,
+
 E0109: r##"
 You tried to give a type parameter to a type which doesn't need it. Erroneous
 code example:
index 883c5e7bb40eb2713f37ea37fb5afc5d3761e9fe..ef97c4c8a12a901a4650473c23bdd57280d4e7a8 100644 (file)
@@ -182,7 +182,8 @@ trait definition for {} must have a value, \
 /// if the program type checks or not -- and they are unusual
 /// occurrences in any case.
 pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
-                                          obligation: &Obligation<'tcx, T>)
+                                          obligation: &Obligation<'tcx, T>,
+                                          suggest_increasing_limit: bool)
                                           -> !
     where T: fmt::Display + TypeFoldable<'tcx>
 {
@@ -192,7 +193,9 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
                                    "overflow evaluating the requirement `{}`",
                                    predicate);
 
-    suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span);
+    if suggest_increasing_limit {
+        suggest_new_overflow_limit(infcx.tcx, &mut err, obligation.cause.span);
+    }
 
     note_obligation_cause(infcx, &mut err, obligation);
 
@@ -201,6 +204,141 @@ pub fn report_overflow_error<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
     unreachable!();
 }
 
+/// Reports that a cycle was detected which led to overflow and halts
+/// compilation. This is equivalent to `report_overflow_error` except
+/// that we can give a more helpful error message (and, in particular,
+/// we do not suggest increasing the overflow limit, which is not
+/// going to help).
+pub fn report_overflow_error_cycle<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                             cycle: &Vec<PredicateObligation<'tcx>>)
+                                             -> !
+{
+    assert!(cycle.len() > 1);
+
+    debug!("report_overflow_error_cycle(cycle length = {})", cycle.len());
+
+    let cycle = infcx.resolve_type_vars_if_possible(cycle);
+
+    debug!("report_overflow_error_cycle: cycle={:?}", cycle);
+
+    assert_eq!(&cycle[0].predicate, &cycle.last().unwrap().predicate);
+
+    try_report_overflow_error_type_of_infinite_size(infcx, &cycle);
+    report_overflow_error(infcx, &cycle[0], false);
+}
+
+/// If a cycle results from evaluated whether something is Sized, that
+/// is a particular special case that always results from a struct or
+/// enum definition that lacks indirection (e.g., `struct Foo { x: Foo
+/// }`). We wish to report a targeted error for this case.
+pub fn try_report_overflow_error_type_of_infinite_size<'a, 'tcx>(
+    infcx: &InferCtxt<'a, 'tcx>,
+    cycle: &[PredicateObligation<'tcx>])
+{
+    let sized_trait = match infcx.tcx.lang_items.sized_trait() {
+        Some(v) => v,
+        None => return,
+    };
+    let top_is_sized = {
+        match cycle[0].predicate {
+            ty::Predicate::Trait(ref data) => data.def_id() == sized_trait,
+            _ => false,
+        }
+    };
+    if !top_is_sized {
+        return;
+    }
+
+    // The only way to have a type of infinite size is to have,
+    // somewhere, a struct/enum type involved. Identify all such types
+    // and report the cycle to the user.
+
+    let struct_enum_tys: Vec<_> =
+        cycle.iter()
+             .flat_map(|obligation| match obligation.predicate {
+                 ty::Predicate::Trait(ref data) => {
+                     assert_eq!(data.def_id(), sized_trait);
+                     let self_ty = data.skip_binder().trait_ref.self_ty(); // (*)
+                     // (*) ok to skip binder because this is just
+                     // error reporting and regions don't really
+                     // matter
+                     match self_ty.sty {
+                         ty::TyEnum(..) | ty::TyStruct(..) => Some(self_ty),
+                         _ => None,
+                     }
+                 }
+                 _ => {
+                     infcx.tcx.sess.span_bug(obligation.cause.span,
+                                             &format!("Sized cycle involving non-trait-ref: {:?}",
+                                                      obligation.predicate));
+                 }
+             })
+             .collect();
+
+    assert!(!struct_enum_tys.is_empty());
+
+    // This is a bit tricky. We want to pick a "main type" in the
+    // listing that is local to the current crate, so we can give a
+    // good span to the user. But it might not be the first one in our
+    // cycle list. So find the first one that is local and then
+    // rotate.
+    let (main_index, main_def_id) =
+        struct_enum_tys.iter()
+                       .enumerate()
+                       .filter_map(|(index, ty)| match ty.sty {
+                           ty::TyEnum(adt_def, _) | ty::TyStruct(adt_def, _) if adt_def.did.is_local() =>
+                               Some((index, adt_def.did)),
+                           _ =>
+                               None,
+                       })
+                       .next()
+                       .unwrap(); // should always be SOME local type involved!
+
+    // Rotate so that the "main" type is at index 0.
+    let struct_enum_tys: Vec<_> =
+        struct_enum_tys.iter()
+                       .cloned()
+                       .skip(main_index)
+                       .chain(struct_enum_tys.iter().cloned().take(main_index))
+                       .collect();
+
+    let tcx = infcx.tcx;
+    let mut err = recursive_type_with_infinite_size_error(tcx, main_def_id);
+    let len = struct_enum_tys.len();
+    if len > 2 {
+        let span = tcx.map.span_if_local(main_def_id).unwrap();
+        err.fileline_note(span,
+                          &format!("type `{}` is embedded within `{}`...",
+                                   struct_enum_tys[0],
+                                   struct_enum_tys[1]));
+        for &next_ty in &struct_enum_tys[1..len-1] {
+            err.fileline_note(span,
+                              &format!("...which in turn is embedded within `{}`...", next_ty));
+        }
+        err.fileline_note(span,
+                          &format!("...which in turn is embedded within `{}`, \
+                                    completing the cycle.",
+                                   struct_enum_tys[len-1]));
+    }
+    err.emit();
+    infcx.tcx.sess.abort_if_errors();
+    unreachable!();
+}
+
+pub fn recursive_type_with_infinite_size_error<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                                     type_def_id: DefId)
+                                                     -> DiagnosticBuilder<'tcx>
+{
+    assert!(type_def_id.is_local());
+    let span = tcx.map.span_if_local(type_def_id).unwrap();
+    let mut err = struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size",
+                                   tcx.item_path_str(type_def_id));
+    err.fileline_help(span, &format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
+                                      at some point to make `{}` representable",
+                                     tcx.item_path_str(type_def_id)));
+    err
+}
+
 pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                         obligation: &PredicateObligation<'tcx>,
                                         error: &SelectionError<'tcx>)
index 0e1c9c3843bf763444f9a4e3241eb1367681378a..2fdf93e6e35dea903d0da0d50639d1d22f551382 100644 (file)
 use middle::infer::InferCtxt;
 use middle::ty::{self, Ty, TypeFoldable};
 use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error};
-
+use std::iter;
 use syntax::ast;
 use util::common::ErrorReported;
-use util::nodemap::{FnvHashSet, NodeMap};
+use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
 
 use super::CodeAmbiguity;
 use super::CodeProjectionError;
@@ -25,6 +25,7 @@
 use super::ObligationCause;
 use super::PredicateObligation;
 use super::project;
+use super::report_overflow_error_cycle;
 use super::select::SelectionContext;
 use super::Unimplemented;
 use super::util::predicate_for_builtin_bound;
@@ -357,6 +358,17 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
     }
 
     let obligation = &pending_obligation.obligation;
+
+    // If we exceed the recursion limit, take a moment to look for a
+    // cycle so we can give a better error report from here, where we
+    // have more context.
+    let recursion_limit = selcx.tcx().sess.recursion_limit.get();
+    if obligation.recursion_depth >= recursion_limit {
+        if let Some(cycle) = scan_for_cycle(obligation, &backtrace) {
+            report_overflow_error_cycle(selcx.infcx(), &cycle);
+        }
+    }
+
     match obligation.predicate {
         ty::Predicate::Trait(ref data) => {
             if coinductive_match(selcx, obligation, data, &backtrace) {
@@ -488,11 +500,15 @@ fn coinductive_match<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                               -> bool
 {
     if selcx.tcx().trait_has_default_impl(top_data.def_id()) {
+        debug!("coinductive_match: top_data={:?}", top_data);
         for bt_obligation in backtrace.clone() {
+            debug!("coinductive_match: bt_obligation={:?}", bt_obligation);
+
             // *Everything* in the backtrace must be a defaulted trait.
             match bt_obligation.obligation.predicate {
                 ty::Predicate::Trait(ref data) => {
                     if !selcx.tcx().trait_has_default_impl(data.def_id()) {
+                        debug!("coinductive_match: trait does not have default impl");
                         break;
                     }
                 }
@@ -501,7 +517,7 @@ fn coinductive_match<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
 
             // And we must find a recursive match.
             if bt_obligation.obligation.predicate == top_obligation.predicate {
-                debug!("process_predicate: found a match in the backtrace");
+                debug!("coinductive_match: found a match in the backtrace");
                 return true;
             }
         }
@@ -510,6 +526,27 @@ fn coinductive_match<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
     false
 }
 
+fn scan_for_cycle<'a,'tcx>(top_obligation: &PredicateObligation<'tcx>,
+                           backtrace: &Backtrace<PendingPredicateObligation<'tcx>>)
+                           -> Option<Vec<PredicateObligation<'tcx>>>
+{
+    let mut map = FnvHashMap();
+    let all_obligations =
+        || iter::once(top_obligation)
+               .chain(backtrace.clone()
+                               .map(|p| &p.obligation));
+    for (index, bt_obligation) in all_obligations().enumerate() {
+        if let Some(&start) = map.get(&bt_obligation.predicate) {
+            // Found a cycle starting at position `start` and running
+            // until the current position (`index`).
+            return Some(all_obligations().skip(start).take(index - start + 1).cloned().collect());
+        } else {
+            map.insert(bt_obligation.predicate.clone(), index);
+        }
+    }
+    None
+}
+
 fn register_region_obligation<'tcx>(t_a: Ty<'tcx>,
                                     r_b: ty::Region,
                                     cause: ObligationCause<'tcx>,
index 4a92a8a9d580e8077234d7e31fea7455fe533250..8fecffcea9fe446269f7b927bea4bbb32c41070e 100644 (file)
 use syntax::codemap::{Span, DUMMY_SP};
 
 pub use self::error_reporting::TraitErrorKey;
+pub use self::error_reporting::recursive_type_with_infinite_size_error;
 pub use self::error_reporting::report_fulfillment_errors;
 pub use self::error_reporting::report_overflow_error;
+pub use self::error_reporting::report_overflow_error_cycle;
 pub use self::error_reporting::report_selection_error;
 pub use self::error_reporting::report_object_safety_error;
 pub use self::coherence::orphan_check;
index e9d7b330d07acc17f15bbc29f093e63dd3812872..c363425db85b09e68dcad9ab8d8a76c40dde9758 100644 (file)
@@ -479,7 +479,7 @@ fn project_type<'cx,'tcx>(
     let recursion_limit = selcx.tcx().sess.recursion_limit.get();
     if obligation.recursion_depth >= recursion_limit {
         debug!("project: overflow!");
-        report_overflow_error(selcx.infcx(), &obligation);
+        report_overflow_error(selcx.infcx(), &obligation, true);
     }
 
     let obligation_trait_ref =
index f6d0da904a40f0bd15b197c854a0777da08aeaff..75992b6849b017193adc53aacfe73e92c4b684fa 100644 (file)
@@ -711,7 +711,7 @@ fn candidate_from_obligation<'o>(&mut self,
         // not update) the cache.
         let recursion_limit = self.infcx.tcx.sess.recursion_limit.get();
         if stack.obligation.recursion_depth >= recursion_limit {
-            report_overflow_error(self.infcx(), &stack.obligation);
+            report_overflow_error(self.infcx(), &stack.obligation, true);
         }
 
         // Check the cache. Note that we skolemize the trait-ref
@@ -2124,6 +2124,9 @@ fn vtable_builtin_data(&mut self,
                            nested: ty::Binder<Vec<Ty<'tcx>>>)
                            -> VtableBuiltinData<PredicateObligation<'tcx>>
     {
+        debug!("vtable_builtin_data(obligation={:?}, bound={:?}, nested={:?})",
+               obligation, bound, nested);
+
         let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) {
             Ok(def_id) => def_id,
             Err(_) => {
index e9184a12d722d8cf09290bfedeab2887d9886110..eafa1e4304d41207881d631565474202615a067c 100644 (file)
@@ -4132,7 +4132,7 @@ fn check_const_with_ty<'a, 'tcx>(fcx: &FnCtxt<'a, 'tcx>,
 pub fn check_representable(tcx: &ty::ctxt,
                            sp: Span,
                            item_id: ast::NodeId,
-                           designation: &str) -> bool {
+                           _designation: &str) -> bool {
     let rty = tcx.node_id_to_type(item_id);
 
     // Check that it is possible to represent this type. This call identifies
@@ -4142,9 +4142,7 @@ pub fn check_representable(tcx: &ty::ctxt,
     // caught by case 1.
     match rty.is_representable(tcx, sp) {
         Representability::SelfRecursive => {
-            struct_span_err!(tcx.sess, sp, E0072, "invalid recursive {} type", designation)
-                .fileline_help(sp, "wrap the inner value in a box to make it representable")
-                .emit();
+            traits::recursive_type_with_infinite_size_error(tcx, tcx.map.local_def_id(item_id)).emit();
             return false
         }
         Representability::Representable | Representability::ContainsRecursive => (),
index 5f2582a548bacc6199f057d655aa4a97a9c5de41..55a1021f0fb9418ca3357292b586d25ec4b27881 100644 (file)
@@ -869,43 +869,6 @@ fn main() {
 ```
 "##,
 
-E0072: r##"
-When defining a recursive struct or enum, any use of the type being defined
-from inside the definition must occur behind a pointer (like `Box` or `&`).
-This is because structs and enums must have a well-defined size, and without
-the pointer the size of the type would need to be unbounded.
-
-Consider the following erroneous definition of a type for a list of bytes:
-
-```
-// error, invalid recursive struct type
-struct ListNode {
-    head: u8,
-    tail: Option<ListNode>,
-}
-```
-
-This type cannot have a well-defined size, because it needs to be arbitrarily
-large (since we would be able to nest `ListNode`s to any depth). Specifically,
-
-```plain
-size of `ListNode` = 1 byte for `head`
-                   + 1 byte for the discriminant of the `Option`
-                   + size of `ListNode`
-```
-
-One way to fix this is by wrapping `ListNode` in a `Box`, like so:
-
-```
-struct ListNode {
-    head: u8,
-    tail: Option<Box<ListNode>>,
-}
-```
-
-This works because `Box` is a pointer, so its size is well-known.
-"##,
-
 E0073: r##"
 You cannot define a struct (or enum) `Foo` that requires an instance of `Foo`
 in order to make a new `Foo` value. This is because there would be no way a
index 8c13ff70515313a63ed79e9a1371d8563fe12fbe..bfe9d7403399d10cf1dbc705c3de3c5d8ceba898 100644 (file)
@@ -13,5 +13,6 @@ trait Trait {}
 pub fn main() {
     let x: Vec<Trait + Sized> = Vec::new();
     //~^ ERROR the trait `core::marker::Sized` is not implemented
-    //~^^ ERROR the trait `core::marker::Sized` is not implemented
+    //~| ERROR the trait `core::marker::Sized` is not implemented
+    //~| ERROR the trait `core::marker::Sized` is not implemented
 }
index 7dbf75feda054df0431062e7da43ee49ff609017..c9a7f731aea08a0f2f6ce427977d2751d9f18ab3 100644 (file)
@@ -8,9 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-
-// error-pattern: invalid recursive enum type
-
 enum mlist { cons(isize, mlist), nil, }
+//~^ ERROR recursive type `mlist` has infinite size
 
 fn main() { let a = mlist::cons(10, mlist::cons(11, mlist::nil)); }
index bd3f2835058700942b137a968c78ea7d1945cce0..260cc366fae08a1cca39a36b4654568e904479c8 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 struct Foo { foo: Option<Option<Foo>> }
-//~^ ERROR invalid recursive struct type
+//~^ ERROR recursive type `Foo` has infinite size
 
 impl Foo { fn bar(&self) {} }
 
index 4e1c0d6571d168567fddf88b66746bef322ddd63..edbc8c82432e0331b38cdae55603dfbddeff877b 100644 (file)
@@ -9,10 +9,9 @@
 // except according to those terms.
 
 struct Baz { q: Option<Foo> }
-//~^ ERROR invalid recursive struct type
 
 struct Foo { q: Option<Baz> }
-//~^ ERROR invalid recursive struct type
+//~^ ERROR recursive type `Foo` has infinite size
 
 impl Foo { fn bar(&self) {} }
 
index 07c5f106456d121f781b3e7f540966ca286cb281..9ba085591f08bb3f8dd877d1f02e6294e19800d5 100644 (file)
@@ -11,7 +11,7 @@
 use std::sync::Mutex;
 
 struct Foo { foo: Mutex<Option<Foo>> }
-//~^ ERROR invalid recursive struct type
+//~^ ERROR recursive type `Foo` has infinite size
 
 impl Foo { fn bar(&self) {} }
 
index 74952d9ca2b38f39ab5c4afed213e080fc647106..665c3cf8fe6391cbe2d92f789b1c305bcf7193ae 100644 (file)
@@ -11,7 +11,7 @@
 use std::marker;
 
 struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T> }
-//~^ ERROR invalid recursive struct type
+//~^ ERROR recursive type `Foo` has infinite size
 
 impl<T> Foo<T> { fn bar(&self) {} }
 
index 157b5ed434e9f23dad91c26f3959228bdbea3bc4..85ed4d5d634dbf09bbe419c7f534d8f7800b0952 100644 (file)
@@ -11,8 +11,9 @@
 use std::marker;
 
 struct Foo { foo: Bar<Foo> }
+
 struct Bar<T> { x: Bar<Foo> , marker: marker::PhantomData<T> }
-//~^ ERROR invalid recursive struct type
+//~^ ERROR recursive type `Bar` has infinite size
 
 impl Foo { fn foo(&self) {} }
 
index b2037378d3787532c7065ac5673c021b8e4ee4d4..4c1e82c3d6ae48b533e25100ef24e681fd66f3bd 100644 (file)
@@ -11,7 +11,7 @@
 use std::sync::Mutex;
 
 enum Foo { X(Mutex<Option<Foo>>) }
-//~^ ERROR invalid recursive enum type
+//~^ ERROR recursive type `Foo` has infinite size
 
 impl Foo { fn bar(self) {} }
 
index 9ad81e030aaf0eab8fe16065481a0fb36cb3f7b7..71b85da29fc717cd4f588f73a462624763a69515 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 enum Foo { Voo(Option<Option<Foo>>) }
-//~^ ERROR invalid recursive enum type
+//~^ ERROR recursive type `Foo` has infinite size
 
 impl Foo { fn bar(&self) {} }
 
index 42fd856ad8784ee54766dd517208a7c8b2512362..09044b5b5055ddad3fb8a855d52719033e399842 100644 (file)
@@ -9,7 +9,7 @@
 // except according to those terms.
 
 fn main() {
-    for (ref i,) in [].iter() { //~ ERROR: type mismatch resolving
+    for (ref i,) in [].iter() { //~ ERROR mismatched types
         i.clone();
         //~^ ERROR: the type of this value must be known in this context
     }
index 3f96a9c342283d0678db124b5d7bfe0e4ca200bc..48ea344c7c24caa3a45f11fcdc6447ed5c9fcb91 100644 (file)
@@ -40,6 +40,7 @@ fn subscribe(&mut self, t : Box<Subscriber<Input=<Self as Publisher>::Output> +
         //~^^ ERROR cannot infer
         //~|  ERROR cannot infer
         //~|  ERROR cannot infer
+        //~|  ERROR cannot infer
         //
         // The fact that `Publisher` is using an implicit lifetime is
         // what was causing the debruijn accounting to be off, so
index 8b02e8e7046ce94a16f9f37ebc949d407e19ff71..28080ae09e51bb87d82a608986c753e81a78fd24 100644 (file)
@@ -8,11 +8,10 @@
 // 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; }
-impl<T> Mirror for T { type It = Self; }
+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);
index 37daf76c0b953c8534ab59b784a8971227e1c016..6de28cbbf357ca3c109f04e0d80be7dc658b01c4 100644 (file)
@@ -16,7 +16,7 @@ mod pingpong {
     use send_packet;
     pub type ping = send_packet<pong>;
     pub struct pong(send_packet<ping>);
-    //~^ ERROR invalid recursive struct type
+    //~^ ERROR recursive type `pingpong::pong` has infinite size
 }
 
 fn main() {}
index eb6842083263594a8561127d689079d957419cb6..d3c15763eb00e57ca85b1877706bfca6f95f1af3 100644 (file)
@@ -10,7 +10,7 @@
 
 enum foo { foo_(bar) }
 enum bar { bar_none, bar_some(bar) }
-//~^ ERROR invalid recursive enum type
+//~^ ERROR recursive type `bar` has infinite size
 
 fn main() {
 }
index f934e0771c2ab39c998829b7cc50be27e20a3087..e6cc29634a1e8ebaf696f54192e82775336323a2 100644 (file)
@@ -12,7 +12,7 @@
 
 enum foo { foo_(bar) }
 struct bar { x: bar }
-//~^ ERROR invalid recursive struct type
+//~^ ERROR E0072
 
 fn main() {
 }
index f8756b83f23a642d52e82394a32a5ec5acac48f3..66bfab003e9cf2640c10ec0b99c0c63870d3b963 100644 (file)
@@ -12,7 +12,7 @@
 
 enum E1 { V1(E2<E1>), }
 enum E2<T> { V2(E2<E1>, marker::PhantomData<T>), }
-//~^ ERROR invalid recursive enum type
+//~^ ERROR recursive type `E2` has infinite size
 
 impl E1 { fn foo(&self) {} }
 
index 66d8fb40cd120c94adf1eb04944d2ebb58175542..d96b1a1cbe35b1cd4f08bf56fa391ea88b25f733 100644 (file)
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-struct S {
-    //~^ ERROR invalid recursive struct type
+struct S { //~ ERROR E0072
     element: Option<S>
 }
 
index 7d0a9007829926e1ea4bb198ffcfd4ef5d0ffa1e..87b7b73d57dbd41b18b560199588bb21b0339b64 100644 (file)
@@ -17,6 +17,5 @@
 static boxed: Box<RefCell<isize>> = box RefCell::new(0);
 //~^ ERROR allocations are not allowed in statics
 //~| ERROR the trait `core::marker::Sync` is not implemented for the type
-//~| ERROR the trait `core::marker::Sync` is not implemented for the type
 
 fn main() { }
index 3474a73b31fdcab834dc557911b1eab3eb09f15a..aec40c1a73a806f488acac21c3077c4da8d7c803 100644 (file)
@@ -27,14 +27,12 @@ fn f<T>(val: T) {
     let t: S<T> = S(marker::PhantomData);
     let a = &t as &Gettable<T>;
     //~^ ERROR the trait `core::marker::Send` is not implemented
-    //~^^ ERROR the trait `core::marker::Copy` is not implemented
 }
 
 fn g<T>(val: T) {
     let t: S<T> = S(marker::PhantomData);
     let a: &Gettable<T> = &t;
     //~^ ERROR the trait `core::marker::Send` is not implemented
-    //~^^ ERROR the trait `core::marker::Copy` is not implemented
 }
 
 fn foo<'a>() {
index 5c49098d870536efef5c1c25450429455963577c..731c1edbfc00b7fdf0f70f0b9c1f1cc26b9bbe57 100644 (file)
@@ -13,8 +13,8 @@
 
 extern crate libc;
 
-trait Mirror { type It; }
-impl<T> Mirror for T { type It = Self; }
+trait Mirror { type It: ?Sized; }
+impl<T: ?Sized> Mirror for T { type It = Self; }
 #[repr(C)]
 pub struct StructWithProjection(*mut <StructWithProjection as Mirror>::It);
 #[repr(C)]
index 2269c58c97de34cdfdbb556ea54cbb7c88446500..db19132b2c454738a19133d13e563fed724d4ba8 100644 (file)
@@ -16,5 +16,4 @@ fn main() {
     let x = RefCell::new(0);
     f(x);
     //~^ ERROR `core::marker::Sync` is not implemented
-    //~^^ ERROR `core::marker::Sync` is not implemented
 }
index 47a65505d8a3de0a6f342ab696e7763a91dcf9ac..922d70b8013dc73f1ae93ef69365ca54e8e81307 100644 (file)
@@ -18,7 +18,6 @@
 fn assert<T: RecoverSafe + ?Sized>() {}
 
 fn main() {
-    assert::<Rc<RefCell<i32>>>(); //~ ERROR: is not implemented
-    //~^ ERROR: is not implemented
+    assert::<Rc<RefCell<i32>>>(); //~ ERROR E0277
 }
 
index a0c7865eeb01c041cf86929ffb9295c96a4c7992..50a69543f7d04fbfaa77a0d4cea3ef2d46f6457e 100644 (file)
@@ -19,5 +19,4 @@ fn assert<T: RecoverSafe + ?Sized>() {}
 
 fn main() {
     assert::<Arc<RefCell<i32>>>(); //~ ERROR: is not implemented
-    //~^ ERROR: is not implemented
 }
index 9e716131525c968e65e8ede0d577f6b0ea6810b8..c50e4b9d87e063cd295e971d841d66b5be2914da 100644 (file)
@@ -17,6 +17,5 @@
 fn assert<T: RecoverSafe + ?Sized>() {}
 
 fn main() {
-    assert::<&RefCell<i32>>(); //~ ERROR: is not implemented
-    //~^ ERROR is not implemented
+    assert::<&RefCell<i32>>(); //~ ERROR E0277
 }
index 90c730d37589b2c2a8e736c1713bdc2e910f87d2..0fc912dc95fab8eeeb43b991b875643610404c65 100644 (file)
@@ -17,7 +17,6 @@
 fn assert<T: RecoverSafe + ?Sized>() {}
 
 fn main() {
-    assert::<*mut RefCell<i32>>(); //~ ERROR: is not implemented
-    //~^ ERROR is not implemented
+    assert::<*mut RefCell<i32>>(); //~ ERROR E0277
 }
 
index 341736f7ab5ee8c938539b8f48dc2282ac46861b..8e3161ef884be5b83410291364cc2678c9b8ddf0 100644 (file)
@@ -28,6 +28,7 @@ fn make_bar<T:Bar>(t: &T) -> &Bar {
 }
 
 fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
+    //~^ ERROR E0038
     t as &Bar
 }
 
index 826e4283ef82748fb400c0b2208ed75f67e5c9a8..b839902c6832ab16eeeaa9c77ef57513348d8966 100644 (file)
@@ -17,12 +17,11 @@ pub fn main() {
 
     // Bool => does not implement iterator.
     for i in false..true {}
-    //~^ ERROR the trait
-    //~^^ ERROR the trait
-    //~^^^ ERROR the trait
+    //~^ ERROR E0277
 
     // Unsized type.
     let arr: &[_] = &[1, 2, 3];
     let range = *arr..;
     //~^ ERROR the trait `core::marker::Sized` is not implemented
+    //~| ERROR the trait `core::marker::Sized` is not implemented
 }
index 33dcbdf74d2269fa63740a14d6229ae5fb7fbab6..555755cdb96eadfbb7dd664a0cbfeba20865e7af 100644 (file)
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern: invalid recursive enum type
-
 enum list<T> { cons(T, list<T>), nil }
+//~^ ERROR recursive type `list` has infinite size
 
 fn main() {}
diff --git a/src/test/compile-fail/sized-cycle-note.rs b/src/test/compile-fail/sized-cycle-note.rs
new file mode 100644 (file)
index 0000000..bb1ab2e
--- /dev/null
@@ -0,0 +1,31 @@
+// Copyright 2014 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.
+
+// Test the error message resulting from a cycle in solving `Foo:
+// Sized`. The specifics of the message will of course but the main
+// thing we want to preserve is that:
+//
+// 1. the message should appear attached to one of the structs
+//    defined in this file;
+// 2. it should elaborate the steps that led to the cycle.
+
+struct Baz { q: Option<Foo> }
+
+struct Foo { q: Option<Baz> }
+//~^ ERROR recursive type `Foo` has infinite size
+//~| type `Foo` is embedded within `core::option::Option<Foo>`...
+//~| ...which in turn is embedded within `core::option::Option<Foo>`...
+//~| ...which in turn is embedded within `Baz`...
+//~| ...which in turn is embedded within `core::option::Option<Baz>`...
+//~| ...which in turn is embedded within `Foo`, completing the cycle.
+
+impl Foo { fn bar(&self) {} }
+
+fn main() {}
index d39b7e15edc34e9d2f7e2b20839c9258ee62882f..520691fbecc481b34985c4bb65c40cd6074609a1 100644 (file)
@@ -22,6 +22,6 @@ fn main() {
         x: 3
     };
 
-    let baz: Foo<usize> = panic!();
+    let baz: Foo<usize> = loop { };
     //~^ ERROR not implemented
 }
index 2d4df77f960452a126928ce40ee05fb108324012..0cfcf6bb3f907084617231fcb3b29e923453eee5 100644 (file)
@@ -21,5 +21,7 @@ fn main() {
     (box 10 as Box<bar>).dup();
     //~^ ERROR E0038
     //~| ERROR E0038
+    //~| ERROR E0038
+    //~| ERROR E0038
     //~| ERROR E0277
 }
index 3b08d900733c5e219ac4e3d038d25bd19b032270..4bb739800df368821aacde032015d05231cc3ea8 100644 (file)
@@ -8,8 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-// error-pattern:invalid recursive struct type
-struct t1 {
+struct t1 { //~ ERROR E0072
     foo: isize,
     foolish: t1
 }