Skip to content

Commit f7108e1

Browse files
committed
Only point at the fields that cause infinite size
* clean up code * point only fields that cause the type to be of infinite size * fix unittests
1 parent ed6ad09 commit f7108e1

File tree

6 files changed

+109
-123
lines changed

6 files changed

+109
-123
lines changed

src/librustc/hir/mod.rs

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,20 +1299,6 @@ 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-
13161302
/// Not represented directly in the AST, referred to by name through a ty_path.
13171303
#[derive(Clone, PartialEq, Eq, RustcEncodable, RustcDecodable, Hash, Debug, Copy)]
13181304
pub enum PrimTy {
@@ -1753,6 +1739,24 @@ impl Item_ {
17531739
ItemDefaultImpl(..) => "item",
17541740
}
17551741
}
1742+
1743+
pub fn fields(&self) -> &[StructField] {
1744+
match *self {
1745+
ItemStruct(ref vd, _) => {
1746+
return vd.fields();
1747+
}
1748+
ItemEnum(EnumDef { ref variants }, _) => {
1749+
for variant in variants {
1750+
let fields = variant.node.data.fields();
1751+
if fields.len() > 0 {
1752+
return fields;
1753+
}
1754+
}
1755+
}
1756+
_ => (),
1757+
}
1758+
&[]
1759+
}
17561760
}
17571761

17581762
/// A reference from an trait to one of its associated items. This

src/librustc/traits/error_reporting.rs

Lines changed: 81 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -778,19 +778,53 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
778778
}
779779
}
780780

781+
/// Get the `DefId` for a given struct or enum `Ty`.
782+
fn ty_def_id(ty: &hir::Ty) -> Option<DefId> {
783+
match ty.node {
784+
hir::TyPath(hir::QPath::Resolved(_, ref path)) => {
785+
match path.def {
786+
hir::def::Def::Struct(did) | hir::def::Def::Enum(did) => {
787+
Some(did)
788+
}
789+
_ => None,
790+
}
791+
},
792+
_ => None,
793+
}
794+
}
795+
781796
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");
797+
/// Add a span label to `err` pointing at `sp` if the field represented by `node_id` points
798+
/// recursively at the type `ty` without indirection.
799+
fn annotate_recursive_field_ty(&self,
800+
node_id: ast::NodeId,
801+
ty: &hir::Ty,
802+
sp: Span,
803+
err: &mut DiagnosticBuilder<'tcx>) -> bool {
804+
if let Some(did) = ty_def_id(ty) {
805+
return self.annotate_recursive_field_id(node_id, did, sp, err);
806+
}
807+
false
808+
}
809+
810+
/// Add a span label to `err` pointing at `sp` if the field represented by `node_id` points
811+
/// recursively at the type represented by `did` without indirection.
812+
fn annotate_recursive_field_id(&self,
813+
node_id:
814+
ast::NodeId,
815+
did: DefId,
816+
sp: Span,
817+
err: &mut DiagnosticBuilder<'tcx>) -> bool
818+
{
819+
if let Some(Node::NodeItem(item)) = self.hir.get_if_local(did) {
820+
if self.is_node_id_referenced_in_item(item, node_id) {
821+
err.span_label(sp, &"recursive without indirection");
822+
return true;
788823
}
789-
true
790-
} else {
791-
false
792824
}
825+
false
793826
}
827+
794828
pub fn recursive_type_with_infinite_size_error(self,
795829
type_def_id: DefId)
796830
-> DiagnosticBuilder<'tcx>
@@ -806,114 +840,62 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
806840
at some point to make `{}` representable",
807841
self.item_path_str(type_def_id)));
808842

843+
// Look at the type for the the recursive type's fields and label those that are causing it
844+
// to be of infinite size.
809845
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+
for field in self_item.node.fields() {
847+
match field.ty.node {
848+
hir::TyPath(ref qpath) => {
849+
// Foo
850+
if let &hir::QPath::Resolved(_, ref path) = qpath {
851+
match path.def {
852+
hir::def::Def::Struct(did) |
853+
hir::def::Def::Enum(did) => {
854+
self.annotate_recursive_field_id(self_item.id,
855+
did,
856+
field.span,
857+
&mut err);
846858
}
859+
_ => (),
847860
}
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-
}
861+
}
862+
}
863+
hir::TyArray(ref ty, _) => {
864+
// [Foo]
865+
self.annotate_recursive_field_ty(self_item.id, &ty, field.span, &mut err);
866+
}
867+
hir::TyTup(ref tys) => {
868+
// (Foo, Bar)
869+
for ty in tys {
870+
if self.annotate_recursive_field_ty(self_item.id,
871+
&ty,
872+
field.span,
873+
&mut err) {
874+
break;
867875
}
868-
_ => (),
869876
}
870877
}
878+
_ => (),
871879
}
872-
_ => (),
873880
}
874881
}
875882
err
876883
}
877884

885+
/// Given `item`, determine wether the node identified by `node_id` is referenced without any
886+
/// indirection in any of `item`'s fields.
878887
fn is_node_id_referenced_in_item(&self, item: &hir::Item, node_id: ast::NodeId) -> bool {
879888
if item.id == node_id {
880889
return true;
881890
}
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-
}
891+
for field in item.node.fields() {
892+
if let Some(Node::NodeItem(ref item)) = ty_def_id(&field.ty).and_then(|id| {
893+
self.hir.get_if_local(id)
894+
}) {
895+
if self.is_node_id_referenced_in_item(item, node_id) {
896+
return true;
914897
}
915898
}
916-
_ => (),
917899
}
918900
false
919901
}

src/test/compile-fail/issue-3008-2.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ enum foo { foo_(bar) }
1212
struct bar { x: bar }
1313
//~^ ERROR E0072
1414
//~| NOTE recursive type has infinite size
15+
//~| NOTE recursive without indirection
1516

1617
fn main() {
1718
}

src/test/compile-fail/issue-32326.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
enum Expr { //~ ERROR E0072
1616
//~| NOTE recursive type has infinite size
1717
Plus(Expr, Expr),
18+
//~^ NOTE recursive without indirection
19+
//~| NOTE recursive without indirection
1820
Literal(i64),
1921
}
2022

src/test/compile-fail/type-recursive.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
struct t1 { //~ ERROR E0072
1212
//~| NOTE recursive type has infinite size
1313
foo: isize,
14-
foolish: t1
14+
foolish: t1 //~ NOTE recursive without indirection
1515
}
1616

1717
fn main() { }

src/test/ui/span/recursive-type-field.stderr

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,8 @@ error[E0072]: recursive type `Foo` has infinite size
44
13 | struct Foo<'a> {
55
| _^ starting here...
66
14 | | bar: Bar<'a>,
7-
| | ------------ recursive here
7+
| | ------------ recursive without indirection
88
15 | | b: Rc<Bar<'a>>,
9-
| | -------------- recursive here
109
16 | | }
1110
| |_^ ...ending here: recursive type has infinite size
1211
|
@@ -18,22 +17,20 @@ error[E0072]: recursive type `Bar` has infinite size
1817
18 | struct Bar<'a> {
1918
| _^ starting here...
2019
19 | | y: (Foo<'a>, Foo<'a>),
21-
| | --------------------- recursive here
20+
| | --------------------- recursive without indirection
2221
20 | | z: Option<Bar<'a>>,
23-
| | ------------------ recursive here
2422
21 | | a: &'a Foo<'a>,
25-
| | -------------- recursive here
2623
22 | | c: &'a [Bar<'a>],
27-
| | ---------------- recursive here
2824
23 | | d: [Bar<'a>; 1],
29-
| | --------------- recursive here
25+
| | --------------- recursive without indirection
3026
24 | | e: Foo<'a>,
31-
| | ---------- recursive here
27+
| | ---------- recursive without indirection
3228
25 | | x: Bar<'a>,
33-
| | ---------- recursive here
29+
| | ---------- recursive without indirection
3430
26 | | }
3531
| |_^ ...ending here: recursive type has infinite size
3632
|
3733
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
3834

3935
error: aborting due to 2 previous errors
36+

0 commit comments

Comments
 (0)