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:
/// 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>
{
"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);
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>)
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;
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;
}
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) {
-> 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;
}
}
// 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;
}
}
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>,
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;
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 =
// 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
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(_) => {
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
// 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 => (),
```
"##,
-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
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
}
// 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)); }
// 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) {} }
// 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) {} }
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) {} }
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) {} }
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) {} }
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) {} }
// 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) {} }
// 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
}
//~^^ 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
// 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);
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() {}
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() {
}
enum foo { foo_(bar) }
struct bar { x: bar }
-//~^ ERROR invalid recursive struct type
+//~^ ERROR E0072
fn main() {
}
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) {} }
// 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>
}
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() { }
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>() {
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)]
let x = RefCell::new(0);
f(x);
//~^ ERROR `core::marker::Sync` is not implemented
- //~^^ ERROR `core::marker::Sync` is not implemented
}
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
}
fn main() {
assert::<Arc<RefCell<i32>>>(); //~ ERROR: is not implemented
- //~^ ERROR: is not implemented
}
fn assert<T: RecoverSafe + ?Sized>() {}
fn main() {
- assert::<&RefCell<i32>>(); //~ ERROR: is not implemented
- //~^ ERROR is not implemented
+ assert::<&RefCell<i32>>(); //~ ERROR E0277
}
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
}
}
fn make_bar_explicit<T:Bar>(t: &T) -> &Bar {
+ //~^ ERROR E0038
t as &Bar
}
// 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
}
// 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() {}
--- /dev/null
+// 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() {}
x: 3
};
- let baz: Foo<usize> = panic!();
+ let baz: Foo<usize> = loop { };
//~^ ERROR not implemented
}
(box 10 as Box<bar>).dup();
//~^ ERROR E0038
//~| ERROR E0038
+ //~| ERROR E0038
+ //~| ERROR E0038
//~| ERROR E0277
}
// 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
}