Detect cycles and specialize error reporting for Sized. It is important
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.
This commit is contained in:
parent
4bbe532737
commit
3046ac217f
@ -712,6 +712,43 @@ There's no easy fix for this, generally code will need to be refactored so that
|
||||
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:
|
||||
|
@ -182,7 +182,8 @@ fn report_on_unimplemented<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
|
||||
/// 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>)
|
||||
|
@ -11,10 +11,10 @@
|
||||
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::FulfillmentErrorCode;
|
||||
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>,
|
||||
|
@ -28,8 +28,10 @@ use syntax::ast;
|
||||
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;
|
||||
|
@ -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 =
|
||||
|
@ -711,7 +711,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
// 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 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||
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(_) => {
|
||||
|
@ -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 => (),
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)); }
|
||||
|
@ -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) {} }
|
||||
|
||||
|
@ -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) {} }
|
||||
|
||||
|
@ -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) {} }
|
||||
|
||||
|
@ -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) {} }
|
||||
|
||||
|
@ -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) {} }
|
||||
|
||||
|
@ -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) {} }
|
||||
|
||||
|
@ -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) {} }
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ impl<'a> Publisher<'a> for MyStruct<'a> {
|
||||
//~^^ 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
|
||||
|
@ -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);
|
||||
|
@ -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() {}
|
||||
|
@ -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() {
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
|
||||
enum foo { foo_(bar) }
|
||||
struct bar { x: bar }
|
||||
//~^ ERROR invalid recursive struct type
|
||||
//~^ ERROR E0072
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use std::marker;
|
||||
|
||||
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) {} }
|
||||
|
||||
|
@ -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>
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,5 @@ use std::cell::RefCell;
|
||||
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() { }
|
||||
|
@ -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>() {
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ use std::cell::RefCell;
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -19,5 +19,4 @@ fn assert<T: RecoverSafe + ?Sized>() {}
|
||||
|
||||
fn main() {
|
||||
assert::<Arc<RefCell<i32>>>(); //~ ERROR: is not implemented
|
||||
//~^ ERROR: is not implemented
|
||||
}
|
||||
|
@ -17,6 +17,5 @@ use std::cell::RefCell;
|
||||
fn assert<T: RecoverSafe + ?Sized>() {}
|
||||
|
||||
fn main() {
|
||||
assert::<&RefCell<i32>>(); //~ ERROR: is not implemented
|
||||
//~^ ERROR is not implemented
|
||||
assert::<&RefCell<i32>>(); //~ ERROR E0277
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ use std::cell::RefCell;
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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() {}
|
||||
|
31
src/test/compile-fail/sized-cycle-note.rs
Normal file
31
src/test/compile-fail/sized-cycle-note.rs
Normal file
@ -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() {}
|
@ -22,6 +22,6 @@ fn main() {
|
||||
x: 3
|
||||
};
|
||||
|
||||
let baz: Foo<usize> = panic!();
|
||||
let baz: Foo<usize> = loop { };
|
||||
//~^ ERROR not implemented
|
||||
}
|
||||
|
@ -21,5 +21,7 @@ fn main() {
|
||||
(box 10 as Box<bar>).dup();
|
||||
//~^ ERROR E0038
|
||||
//~| ERROR E0038
|
||||
//~| ERROR E0038
|
||||
//~| ERROR E0038
|
||||
//~| ERROR E0277
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user