about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/librustc/hir/mod.rs32
-rw-r--r--src/librustc/traits/error_reporting.rs180
-rw-r--r--src/test/compile-fail/issue-3008-2.rs1
-rw-r--r--src/test/compile-fail/issue-32326.rs2
-rw-r--r--src/test/compile-fail/type-recursive.rs2
-rw-r--r--src/test/ui/span/recursive-type-field.stderr15
6 files changed, 109 insertions, 123 deletions
diff --git a/src/librustc/hir/mod.rs b/src/librustc/hir/mod.rs
index 333b64b08d7..2e5e3cb06fe 100644
--- a/src/librustc/hir/mod.rs
+++ b/src/librustc/hir/mod.rs
@@ -1299,20 +1299,6 @@ impl fmt::Debug for Ty {
     }
 }
 
-impl Ty {
-    pub fn ty_def_id(&self) -> Option<DefId> {
-        match self.node {
-            TyPath(QPath::Resolved(_, ref path)) => {
-                match path.def {
-                    Def::Struct(did) | Def::Enum(did) => Some(did),
-                    _ => None,
-                }
-            },
-            _ => None,
-        }
-    }
-}
-
 /// Not represented directly in the AST, referred to by name through a ty_path.
 #[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
 pub enum PrimTy {
@@ -1753,6 +1739,24 @@ 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 c462a56e562..84122bf12a8 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -778,19 +778,53 @@ 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> {
-    fn foo(&self, id: ast::NodeId, ty: &hir::Ty, sp: Span, err: &mut DiagnosticBuilder<'tcx>) -> bool {
-        if let Some(Node::NodeItem(item)) = ty.ty_def_id().and_then(|id| {
-            self.hir.get_if_local(id)
-        }) {
-            if self.is_node_id_referenced_in_item(item, id) {
-                err.span_label(sp, &"recursive here");
+    /// 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;
             }
-            true
-        } else {
-            false
         }
+        false
     }
+
     pub fn recursive_type_with_infinite_size_error(self,
                                                    type_def_id: DefId)
                                                    -> DiagnosticBuilder<'tcx>
@@ -806,114 +840,62 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
                            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) {
-            match self_item.node {
-                hir::ItemStruct(hir::VariantData::Struct(ref fields, _), _) |
-                hir::ItemStruct(hir::VariantData::Tuple(ref fields, _), _) => {
-                    for field in fields {
-                        match field.ty.node {
-                            hir::TyPath(ref qpath) => {
-                                // Foo | Option<Foo>
-                                if let &hir::QPath::Resolved(_, ref path) = qpath {
-                                    for segment in path.segments.iter() {
-                                        if let hir::AngleBracketedParameters(
-                                            hir::AngleBracketedParameterData {
-                                                ref types, ..
-                                            }) = segment.parameters
-                                        {
-                                            for ty in types {
-                                                if self.foo(self_item.id, &ty, field.span,
-                                                            &mut err) {
-                                                    break;
-                                                }
-                                            }
-                                        }
-
-                                    }
-                                    match path.def {
-                                        hir::def::Def::Struct(did) | hir::def::Def::Enum(did) => {
-                                            let local = self.hir.get_if_local(did);
-                                            if let Some(Node::NodeItem(item)) = local {
-                                                if self.is_node_id_referenced_in_item(item,
-                                                                                      self_item.id)
-                                                {
-                                                    err.span_label(field.span, &"recursive here");
-                                                }
-                                            }
-                                        }
-                                        _ => (),
-                                    }
+            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::TySlice(ref ty) |
-                            hir::TyArray(ref ty, _) |
-                            hir::TyPtr(hir::MutTy { ref ty, .. }) |
-                            hir::TyRptr(_, hir::MutTy { ref ty, .. }) => {
-                                // &[Foo] | [Foo] | &'a [Foo]
-                                if let hir::TySlice(ref ty) = ty.node {
-                                    // &'a [Foo]
-                                    let _ = self.foo(self_item.id, &ty, field.span, &mut err);
-                                } else {
-                                    let _ = self.foo(self_item.id, &ty, field.span, &mut err);
-                                }
-                            }
-                            hir::TyTup(ref tys) => {
-                                // (Foo, Bar)
-                                for ty in tys {
-                                    if self.foo(self_item.id, &ty, field.span, &mut err) {
-                                        break;
-                                    }
-                                }
+                        }
+                    }
+                    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;
         }
-        match item.node {
-            hir::ItemStruct(hir::VariantData::Struct(ref fields, _), _) |
-            hir::ItemStruct(hir::VariantData::Tuple(ref fields, _), _) => {
-                for field in fields {
-                    if let Some(Node::NodeItem(ref item)) = field.ty.ty_def_id().and_then(|id| {
-                        self.hir.get_if_local(id)
-                    }) {
-                        if self.is_node_id_referenced_in_item(item, node_id) {
-                            return true;
-                        }
-                    }
-                }
-            }
-            hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
-                for variant in variants {
-                    match variant.node.data {
-                        hir::VariantData::Struct(ref fields, _) |
-                        hir::VariantData::Tuple(ref fields, _) => {
-                            for field in fields {
-                                if let Some(Node::NodeItem(ref item)) = field.ty
-                                    .ty_def_id().and_then(|id| {
-                                        self.hir.get_if_local(id)
-                                    })
-                                {
-                                    if self.is_node_id_referenced_in_item(item, 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
     }
diff --git a/src/test/compile-fail/issue-3008-2.rs b/src/test/compile-fail/issue-3008-2.rs
index 3bc8413cbca..061d1facda0 100644
--- a/src/test/compile-fail/issue-3008-2.rs
+++ b/src/test/compile-fail/issue-3008-2.rs
@@ -12,6 +12,7 @@ enum foo { foo_(bar) }
 struct bar { x: bar }
 //~^ ERROR E0072
 //~| NOTE recursive type has infinite size
+//~| NOTE recursive without indirection
 
 fn main() {
 }
diff --git a/src/test/compile-fail/issue-32326.rs b/src/test/compile-fail/issue-32326.rs
index afffe2a2c8d..70a7cd8b970 100644
--- a/src/test/compile-fail/issue-32326.rs
+++ b/src/test/compile-fail/issue-32326.rs
@@ -15,6 +15,8 @@
 enum Expr { //~ ERROR E0072
             //~| NOTE recursive type has infinite size
     Plus(Expr, Expr),
+    //~^ NOTE recursive without indirection
+    //~| NOTE recursive without indirection
     Literal(i64),
 }
 
diff --git a/src/test/compile-fail/type-recursive.rs b/src/test/compile-fail/type-recursive.rs
index 7b56c6c15eb..5dd76ce32c7 100644
--- a/src/test/compile-fail/type-recursive.rs
+++ b/src/test/compile-fail/type-recursive.rs
@@ -11,7 +11,7 @@
 struct t1 { //~ ERROR E0072
             //~| NOTE recursive type has infinite size
     foo: isize,
-    foolish: t1
+    foolish: t1  //~ NOTE recursive without indirection
 }
 
 fn main() { }
diff --git a/src/test/ui/span/recursive-type-field.stderr b/src/test/ui/span/recursive-type-field.stderr
index 69d88f3a277..d8219cbc220 100644
--- a/src/test/ui/span/recursive-type-field.stderr
+++ b/src/test/ui/span/recursive-type-field.stderr
@@ -4,9 +4,8 @@ error[E0072]: recursive type `Foo` has infinite size
 13 |   struct Foo<'a> {
    |  _^ starting here...
 14 | |     bar: Bar<'a>,
-   | |     ------------ recursive here
+   | |     ------------ recursive without indirection
 15 | |     b: Rc<Bar<'a>>,
-   | |     -------------- recursive here
 16 | | }
    | |_^ ...ending here: recursive type has infinite size
    |
@@ -18,22 +17,20 @@ error[E0072]: recursive type `Bar` has infinite size
 18 |   struct Bar<'a> {
    |  _^ starting here...
 19 | |     y: (Foo<'a>, Foo<'a>),
-   | |     --------------------- recursive here
+   | |     --------------------- recursive without indirection
 20 | |     z: Option<Bar<'a>>,
-   | |     ------------------ recursive here
 21 | |     a: &'a Foo<'a>,
-   | |     -------------- recursive here
 22 | |     c: &'a [Bar<'a>],
-   | |     ---------------- recursive here
 23 | |     d: [Bar<'a>; 1],
-   | |     --------------- recursive here
+   | |     --------------- recursive without indirection
 24 | |     e: Foo<'a>,
-   | |     ---------- recursive here
+   | |     ---------- recursive without indirection
 25 | |     x: Bar<'a>,
-   | |     ---------- recursive here
+   | |     ---------- recursive without indirection
 26 | | }
    | |_^ ...ending here: recursive type has infinite size
    |
    = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
 
 error: aborting due to 2 previous errors
+