diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs index 2e5e3cb06fe5..cb7f530b9952 100644 --- a/src/librustc/hir/mod.rs +++ b/src/librustc/hir/mod.rs @@ -1739,24 +1739,6 @@ impl Item_ { ItemDefaultImpl(..) => "item", } } - - pub fn fields(&self) -> &[StructField] { - match *self { - ItemStruct(ref vd, _) => { - return vd.fields(); - } - ItemEnum(EnumDef { ref variants }, _) => { - for variant in variants { - let fields = variant.node.data.fields(); - if fields.len() > 0 { - return fields; - } - } - } - _ => (), - } - &[] - } } /// A reference from an trait to one of its associated items. This diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs index 84122bf12a8f..e846d74febfb 100644 --- a/src/librustc/traits/error_reporting.rs +++ b/src/librustc/traits/error_reporting.rs @@ -27,7 +27,7 @@ use errors::DiagnosticBuilder; use fmt_macros::{Parser, Piece, Position}; use hir::{self, intravisit, Local, Pat, Body}; use hir::intravisit::{Visitor, NestedVisitorMap}; -use hir::map::{Node, NodeExpr}; +use hir::map::NodeExpr; use hir::def_id::DefId; use infer::{self, InferCtxt}; use infer::type_variable::TypeVariableOrigin; @@ -778,53 +778,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> { } } -/// Get the `DefId` for a given struct or enum `Ty`. -fn ty_def_id(ty: &hir::Ty) -> Option { - match ty.node { - hir::TyPath(hir::QPath::Resolved(_, ref path)) => { - match path.def { - hir::def::Def::Struct(did) | hir::def::Def::Enum(did) => { - Some(did) - } - _ => None, - } - }, - _ => None, - } -} - impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { - /// Add a span label to `err` pointing at `sp` if the field represented by `node_id` points - /// recursively at the type `ty` without indirection. - fn annotate_recursive_field_ty(&self, - node_id: ast::NodeId, - ty: &hir::Ty, - sp: Span, - err: &mut DiagnosticBuilder<'tcx>) -> bool { - if let Some(did) = ty_def_id(ty) { - return self.annotate_recursive_field_id(node_id, did, sp, err); - } - false - } - - /// Add a span label to `err` pointing at `sp` if the field represented by `node_id` points - /// recursively at the type represented by `did` without indirection. - fn annotate_recursive_field_id(&self, - node_id: - ast::NodeId, - did: DefId, - sp: Span, - err: &mut DiagnosticBuilder<'tcx>) -> bool - { - if let Some(Node::NodeItem(item)) = self.hir.get_if_local(did) { - if self.is_node_id_referenced_in_item(item, node_id) { - err.span_label(sp, &"recursive without indirection"); - return true; - } - } - false - } - pub fn recursive_type_with_infinite_size_error(self, type_def_id: DefId) -> DiagnosticBuilder<'tcx> @@ -839,67 +793,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \ at some point to make `{}` representable", self.item_path_str(type_def_id))); - - // Look at the type for the the recursive type's fields and label those that are causing it - // to be of infinite size. - if let Some(Node::NodeItem(self_item)) = self.hir.get_if_local(type_def_id) { - for field in self_item.node.fields() { - match field.ty.node { - hir::TyPath(ref qpath) => { - // Foo - if let &hir::QPath::Resolved(_, ref path) = qpath { - match path.def { - hir::def::Def::Struct(did) | - hir::def::Def::Enum(did) => { - self.annotate_recursive_field_id(self_item.id, - did, - field.span, - &mut err); - } - _ => (), - } - } - } - hir::TyArray(ref ty, _) => { - // [Foo] - self.annotate_recursive_field_ty(self_item.id, &ty, field.span, &mut err); - } - hir::TyTup(ref tys) => { - // (Foo, Bar) - for ty in tys { - if self.annotate_recursive_field_ty(self_item.id, - &ty, - field.span, - &mut err) { - break; - } - } - } - _ => (), - } - } - } err } - /// Given `item`, determine wether the node identified by `node_id` is referenced without any - /// indirection in any of `item`'s fields. - fn is_node_id_referenced_in_item(&self, item: &hir::Item, node_id: ast::NodeId) -> bool { - if item.id == node_id { - return true; - } - for field in item.node.fields() { - if let Some(Node::NodeItem(ref item)) = ty_def_id(&field.ty).and_then(|id| { - self.hir.get_if_local(id) - }) { - if self.is_node_id_referenced_in_item(item, node_id) { - return true; - } - } - } - false - } - pub fn report_object_safety_error(self, span: Span, trait_def_id: DefId, diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index 87921c80502e..e3ca52281de6 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -145,11 +145,11 @@ pub enum CopyImplementationError<'tcx> { /// /// The ordering of the cases is significant. They are sorted so that cmp::max /// will keep the "more erroneous" of two values. -#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] +#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] pub enum Representability { Representable, ContainsRecursive, - SelfRecursive, + SelfRecursive(Vec), } impl<'tcx> ParameterEnvironment<'tcx> { @@ -1003,18 +1003,22 @@ impl<'a, 'tcx> ty::TyS<'tcx> { /// Check whether a type is representable. This means it cannot contain unboxed /// structural recursion. This check is needed for structs and enums. - pub fn is_representable(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span) + pub fn is_representable(&'tcx self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + sp: Span) -> Representability { // Iterate until something non-representable is found - fn find_nonrepresentable<'a, 'tcx, It>(tcx: TyCtxt<'a, 'tcx, 'tcx>, - sp: Span, - seen: &mut Vec>, - iter: It) - -> Representability - where It: Iterator> { - iter.fold(Representability::Representable, - |r, ty| cmp::max(r, is_type_structurally_recursive(tcx, sp, seen, ty))) + fn fold_repr>(iter: It) -> Representability { + iter.fold(Representability::Representable, |r1, r2| { + match (r1, r2) { + (Representability::SelfRecursive(v1), + Representability::SelfRecursive(v2)) => { + Representability::SelfRecursive(v1.iter().map(|s| *s).chain(v2).collect()) + } + (r1, r2) => cmp::max(r1, r2) + } + }) } fn are_inner_types_recursive<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, @@ -1022,7 +1026,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> { -> Representability { match ty.sty { TyTuple(ref ts, _) => { - find_nonrepresentable(tcx, sp, seen, ts.iter().cloned()) + // Find non representable + fold_repr(ts.iter().map(|ty| { + is_type_structurally_recursive(tcx, sp, seen, ty) + })) } // Fixed-length vectors. // FIXME(#11924) Behavior undecided for zero-length vectors. @@ -1030,10 +1037,17 @@ impl<'a, 'tcx> ty::TyS<'tcx> { is_type_structurally_recursive(tcx, sp, seen, ty) } TyAdt(def, substs) => { - find_nonrepresentable(tcx, - sp, - seen, - def.all_fields().map(|f| f.ty(tcx, substs))) + // Find non representable fields with their spans + fold_repr(def.all_fields().map(|field| { + let ty = field.ty(tcx, substs); + let span = tcx.hir.span_if_local(field.did).unwrap_or(sp); + match is_type_structurally_recursive(tcx, span, seen, ty) { + Representability::SelfRecursive(_) => { + Representability::SelfRecursive(vec![span]) + } + x => x, + } + })) } TyClosure(..) => { // this check is run on type definitions, so we don't expect @@ -1072,7 +1086,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { sp: Span, seen: &mut Vec>, ty: Ty<'tcx>) -> Representability { - debug!("is_type_structurally_recursive: {:?}", ty); + debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp); match ty.sty { TyAdt(def, _) => { @@ -1093,7 +1107,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { debug!("SelfRecursive: {:?} contains {:?}", seen_type, ty); - return Representability::SelfRecursive; + return Representability::SelfRecursive(vec![sp]); } } diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 9185b6ec7b1d..c07bd991b3e7 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -1378,8 +1378,12 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, // contain themselves. For case 2, there must be an inner type that will be // caught by case 1. match rty.is_representable(tcx, sp) { - Representability::SelfRecursive => { - tcx.recursive_type_with_infinite_size_error(item_def_id).emit(); + Representability::SelfRecursive(spans) => { + let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id); + for span in spans { + err.span_label(span, &"recursive without indirection"); + } + err.emit(); return false } Representability::Representable | Representability::ContainsRecursive => (), diff --git a/src/test/compile-fail/issue-3008-1.rs b/src/test/compile-fail/issue-3008-1.rs index d3c15763eb00..7ca6d9301a68 100644 --- a/src/test/compile-fail/issue-3008-1.rs +++ b/src/test/compile-fail/issue-3008-1.rs @@ -8,9 +8,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -enum foo { foo_(bar) } -enum bar { bar_none, bar_some(bar) } -//~^ ERROR recursive type `bar` has infinite size +enum Foo { + Foo_(Bar) +} + +enum Bar { + //~^ ERROR recursive type `Bar` has infinite size + //~| NOTE recursive type has infinite size + BarNone, + BarSome(Bar) //~ NOTE recursive without indirection +} fn main() { } diff --git a/src/test/compile-fail/issue-3779.rs b/src/test/compile-fail/issue-3779.rs index 71e9325ab75d..10f73dc08628 100644 --- a/src/test/compile-fail/issue-3779.rs +++ b/src/test/compile-fail/issue-3779.rs @@ -8,9 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -struct S { //~ ERROR E0072 - //~| NOTE recursive type has infinite size +struct S { + //~^ ERROR E0072 + //~| NOTE recursive type has infinite size element: Option + //~^ NOTE recursive without indirection } fn main() { diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr index 5204390ef9d2..1f6dd6b1d165 100644 --- a/src/test/ui/span/E0072.stderr +++ b/src/test/ui/span/E0072.stderr @@ -3,6 +3,9 @@ error[E0072]: recursive type `ListNode` has infinite size | 11 | struct ListNode { | ^^^^^^^^^^^^^^^ recursive type has infinite size +12 | head: u8, +13 | tail: Option, + | ---------------------- recursive without indirection | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable diff --git a/src/test/ui/span/multiline-span-E0072.stderr b/src/test/ui/span/multiline-span-E0072.stderr index 9c6816e73631..a06cbd04deb4 100644 --- a/src/test/ui/span/multiline-span-E0072.stderr +++ b/src/test/ui/span/multiline-span-E0072.stderr @@ -6,6 +6,7 @@ error[E0072]: recursive type `ListNode` has infinite size 14 | | { 15 | | head: u8, 16 | | tail: Option, + | | ---------------------- recursive without indirection 17 | | } | |_^ recursive type has infinite size | diff --git a/src/test/ui/span/recursive-type-field.stderr b/src/test/ui/span/recursive-type-field.stderr index d8219cbc2209..b4d0b5a6a25d 100644 --- a/src/test/ui/span/recursive-type-field.stderr +++ b/src/test/ui/span/recursive-type-field.stderr @@ -1,34 +1,29 @@ error[E0072]: recursive type `Foo` has infinite size --> $DIR/recursive-type-field.rs:13:1 | -13 | struct Foo<'a> { - | _^ starting here... -14 | | bar: Bar<'a>, - | | ------------ recursive without indirection -15 | | b: Rc>, -16 | | } - | |_^ ...ending here: recursive type has infinite size +13 | struct Foo<'a> { + | ^^^^^^^^^^^^^^ recursive type has infinite size +14 | bar: Bar<'a>, + | ------------ recursive without indirection | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable error[E0072]: recursive type `Bar` has infinite size --> $DIR/recursive-type-field.rs:18:1 | -18 | struct Bar<'a> { - | _^ starting here... -19 | | y: (Foo<'a>, Foo<'a>), - | | --------------------- recursive without indirection -20 | | z: Option>, -21 | | a: &'a Foo<'a>, -22 | | c: &'a [Bar<'a>], -23 | | d: [Bar<'a>; 1], - | | --------------- recursive without indirection -24 | | e: Foo<'a>, - | | ---------- recursive without indirection -25 | | x: Bar<'a>, - | | ---------- recursive without indirection -26 | | } - | |_^ ...ending here: recursive type has infinite size +18 | struct Bar<'a> { + | ^^^^^^^^^^^^^^ recursive type has infinite size +19 | y: (Foo<'a>, Foo<'a>), + | --------------------- recursive without indirection +20 | z: Option>, + | ------------------ recursive without indirection +... +23 | d: [Bar<'a>; 1], + | --------------- recursive without indirection +24 | e: Foo<'a>, + | ---------- recursive without indirection +25 | x: Bar<'a>, + | ---------- recursive without indirection | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable