about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/mod.rs18
-rw-r--r--src/librustc/traits/error_reporting.rs106
-rw-r--r--src/librustc/ty/util.rs50
-rw-r--r--src/librustc_typeck/check/mod.rs8
-rw-r--r--src/test/compile-fail/issue-3008-1.rs13
-rw-r--r--src/test/compile-fail/issue-3779.rs6
-rw-r--r--src/test/ui/span/E0072.stderr3
-rw-r--r--src/test/ui/span/multiline-span-E0072.stderr1
-rw-r--r--src/test/ui/span/recursive-type-field.stderr39
9 files changed, 74 insertions, 170 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 2e5e3cb06fe..cb7f530b995 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 84122bf12a8..e846d74febf 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<DefId> {
-    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 87921c80502..e3ca52281de 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<Span>),
 }
 
 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<Ty<'tcx>>,
-                                               iter: It)
-                                               -> Representability
-        where It: Iterator<Item=Ty<'tcx>> {
-            iter.fold(Representability::Representable,
-                      |r, ty| cmp::max(r, is_type_structurally_recursive(tcx, sp, seen, ty)))
+        fn fold_repr<It: Iterator<Item=Representability>>(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<'tcx>>,
                                                     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 9185b6ec7b1..c07bd991b3e 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 d3c15763eb0..7ca6d9301a6 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 71e9325ab75..10f73dc0862 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<S>
+    //~^ NOTE recursive without indirection
 }
 
 fn main() {
diff --git a/src/test/ui/span/E0072.stderr b/src/test/ui/span/E0072.stderr
index 5204390ef9d..1f6dd6b1d16 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<ListNode>,
+   |     ---------------------- 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 9c6816e7363..a06cbd04deb 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<ListNode>,
+   | |     ---------------------- 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 d8219cbc220..b4d0b5a6a25 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<Bar<'a>>,
-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<Bar<'a>>,
-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<Bar<'a>>,
+   |     ------------------ 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