Skip to content

Commit ed6ad09

Browse files
committed
Point at fields that make the type recursive
On recursive types of infinite size, point at all the fields that make the type recursive. ```rust struct Foo { bar: Bar, } struct Bar { foo: Foo, } ``` outputs ``` error[E0072]: recursive type `Foo` has infinite size --> file.rs:1:1 1 | struct Foo { | _^ starting here... 2 | | bar: Bar, | | -------- recursive here 3 | | } | |_^ ...ending here: recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable error[E0072]: recursive type `Bar` has infinite size --> file.rs:5:1 | 5 | struct Bar { | _^ starting here... 6 | | foo: Foo, | | -------- recursive here 7 | | } | |_^ ...ending here: recursive type has infinite size | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable ```
1 parent 96e2c34 commit ed6ad09

File tree

4 files changed

+204
-1
lines changed

4 files changed

+204
-1
lines changed

src/librustc/hir/mod.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,20 @@ impl fmt::Debug for Ty {
12991299
}
13001300
}
13011301

1302+
impl Ty {
1303+
pub fn ty_def_id(&self) -> Option<DefId> {
1304+
match self.node {
1305+
TyPath(QPath::Resolved(_, ref path)) => {
1306+
match path.def {
1307+
Def::Struct(did) | Def::Enum(did) => Some(did),
1308+
_ => None,
1309+
}
1310+
},
1311+
_ => None,
1312+
}
1313+
}
1314+
}
1315+
13021316
/// Not represented directly in the AST, referred to by name through a ty_path.
13031317
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
13041318
pub enum PrimTy {

src/librustc/traits/error_reporting.rs

Lines changed: 123 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use errors::DiagnosticBuilder;
2727
use fmt_macros::{Parser, Piece, Position};
2828
use hir::{self, intravisit, Local, Pat, Body};
2929
use hir::intravisit::{Visitor, NestedVisitorMap};
30-
use hir::map::NodeExpr;
30+
use hir::map::{Node, NodeExpr};
3131
use hir::def_id::DefId;
3232
use infer::{self, InferCtxt};
3333
use infer::type_variable::TypeVariableOrigin;
@@ -779,6 +779,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
779779
}
780780

781781
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
782+
fn foo(&self, id: ast::NodeId, ty: &hir::Ty, sp: Span, err: &mut DiagnosticBuilder<'tcx>) -> bool {
783+
if let Some(Node::NodeItem(item)) = ty.ty_def_id().and_then(|id| {
784+
self.hir.get_if_local(id)
785+
}) {
786+
if self.is_node_id_referenced_in_item(item, id) {
787+
err.span_label(sp, &"recursive here");
788+
}
789+
true
790+
} else {
791+
false
792+
}
793+
}
782794
pub fn recursive_type_with_infinite_size_error(self,
783795
type_def_id: DefId)
784796
-> DiagnosticBuilder<'tcx>
@@ -793,9 +805,119 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
793805
err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
794806
at some point to make `{}` representable",
795807
self.item_path_str(type_def_id)));
808+
809+
if let Some(Node::NodeItem(self_item)) = self.hir.get_if_local(type_def_id) {
810+
match self_item.node {
811+
hir::ItemStruct(hir::VariantData::Struct(ref fields, _), _) |
812+
hir::ItemStruct(hir::VariantData::Tuple(ref fields, _), _) => {
813+
for field in fields {
814+
match field.ty.node {
815+
hir::TyPath(ref qpath) => {
816+
// Foo | Option<Foo>
817+
if let &hir::QPath::Resolved(_, ref path) = qpath {
818+
for segment in path.segments.iter() {
819+
if let hir::AngleBracketedParameters(
820+
hir::AngleBracketedParameterData {
821+
ref types, ..
822+
}) = segment.parameters
823+
{
824+
for ty in types {
825+
if self.foo(self_item.id, &ty, field.span,
826+
&mut err) {
827+
break;
828+
}
829+
}
830+
}
831+
832+
}
833+
match path.def {
834+
hir::def::Def::Struct(did) | hir::def::Def::Enum(did) => {
835+
let local = self.hir.get_if_local(did);
836+
if let Some(Node::NodeItem(item)) = local {
837+
if self.is_node_id_referenced_in_item(item,
838+
self_item.id)
839+
{
840+
err.span_label(field.span, &"recursive here");
841+
}
842+
}
843+
}
844+
_ => (),
845+
}
846+
}
847+
}
848+
hir::TySlice(ref ty) |
849+
hir::TyArray(ref ty, _) |
850+
hir::TyPtr(hir::MutTy { ref ty, .. }) |
851+
hir::TyRptr(_, hir::MutTy { ref ty, .. }) => {
852+
// &[Foo] | [Foo] | &'a [Foo]
853+
if let hir::TySlice(ref ty) = ty.node {
854+
// &'a [Foo]
855+
let _ = self.foo(self_item.id, &ty, field.span, &mut err);
856+
} else {
857+
let _ = self.foo(self_item.id, &ty, field.span, &mut err);
858+
}
859+
}
860+
hir::TyTup(ref tys) => {
861+
// (Foo, Bar)
862+
for ty in tys {
863+
if self.foo(self_item.id, &ty, field.span, &mut err) {
864+
break;
865+
}
866+
}
867+
}
868+
_ => (),
869+
}
870+
}
871+
}
872+
_ => (),
873+
}
874+
}
796875
err
797876
}
798877

878+
fn is_node_id_referenced_in_item(&self, item: &hir::Item, node_id: ast::NodeId) -> bool {
879+
if item.id == node_id {
880+
return true;
881+
}
882+
match item.node {
883+
hir::ItemStruct(hir::VariantData::Struct(ref fields, _), _) |
884+
hir::ItemStruct(hir::VariantData::Tuple(ref fields, _), _) => {
885+
for field in fields {
886+
if let Some(Node::NodeItem(ref item)) = field.ty.ty_def_id().and_then(|id| {
887+
self.hir.get_if_local(id)
888+
}) {
889+
if self.is_node_id_referenced_in_item(item, node_id) {
890+
return true;
891+
}
892+
}
893+
}
894+
}
895+
hir::ItemEnum(hir::EnumDef { ref variants }, _) => {
896+
for variant in variants {
897+
match variant.node.data {
898+
hir::VariantData::Struct(ref fields, _) |
899+
hir::VariantData::Tuple(ref fields, _) => {
900+
for field in fields {
901+
if let Some(Node::NodeItem(ref item)) = field.ty
902+
.ty_def_id().and_then(|id| {
903+
self.hir.get_if_local(id)
904+
})
905+
{
906+
if self.is_node_id_referenced_in_item(item, node_id) {
907+
return true;
908+
}
909+
}
910+
}
911+
}
912+
_ => (),
913+
}
914+
}
915+
}
916+
_ => (),
917+
}
918+
false
919+
}
920+
799921
pub fn report_object_safety_error(self,
800922
span: Span,
801923
trait_def_id: DefId,
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
use std::rc::Rc;
12+
13+
struct Foo<'a> {
14+
bar: Bar<'a>,
15+
b: Rc<Bar<'a>>,
16+
}
17+
18+
struct Bar<'a> {
19+
y: (Foo<'a>, Foo<'a>),
20+
z: Option<Bar<'a>>,
21+
a: &'a Foo<'a>,
22+
c: &'a [Bar<'a>],
23+
d: [Bar<'a>; 1],
24+
e: Foo<'a>,
25+
x: Bar<'a>,
26+
}
27+
28+
fn main() {}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
error[E0072]: recursive type `Foo` has infinite size
2+
--> $DIR/recursive-type-field.rs:13:1
3+
|
4+
13 | struct Foo<'a> {
5+
| _^ starting here...
6+
14 | | bar: Bar<'a>,
7+
| | ------------ recursive here
8+
15 | | b: Rc<Bar<'a>>,
9+
| | -------------- recursive here
10+
16 | | }
11+
| |_^ ...ending here: recursive type has infinite size
12+
|
13+
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
14+
15+
error[E0072]: recursive type `Bar` has infinite size
16+
--> $DIR/recursive-type-field.rs:18:1
17+
|
18+
18 | struct Bar<'a> {
19+
| _^ starting here...
20+
19 | | y: (Foo<'a>, Foo<'a>),
21+
| | --------------------- recursive here
22+
20 | | z: Option<Bar<'a>>,
23+
| | ------------------ recursive here
24+
21 | | a: &'a Foo<'a>,
25+
| | -------------- recursive here
26+
22 | | c: &'a [Bar<'a>],
27+
| | ---------------- recursive here
28+
23 | | d: [Bar<'a>; 1],
29+
| | --------------- recursive here
30+
24 | | e: Foo<'a>,
31+
| | ---------- recursive here
32+
25 | | x: Bar<'a>,
33+
| | ---------- recursive here
34+
26 | | }
35+
| |_^ ...ending here: recursive type has infinite size
36+
|
37+
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
38+
39+
error: aborting due to 2 previous errors

0 commit comments

Comments
 (0)