Skip to content

Commit a4fc925

Browse files
committed
Move logic to is_representable instead of climbing HIR
1 parent f7108e1 commit a4fc925

File tree

9 files changed

+74
-170
lines changed

9 files changed

+74
-170
lines changed

src/librustc/hir/mod.rs

-18
Original file line numberDiff line numberDiff line change
@@ -1739,24 +1739,6 @@ impl Item_ {
17391739
ItemDefaultImpl(..) => "item",
17401740
}
17411741
}
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-
}
17601742
}
17611743

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

src/librustc/traits/error_reporting.rs

+1-105
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::{Node, NodeExpr};
30+
use hir::map::NodeExpr;
3131
use hir::def_id::DefId;
3232
use infer::{self, InferCtxt};
3333
use infer::type_variable::TypeVariableOrigin;
@@ -778,53 +778,7 @@ 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-
796781
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
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;
823-
}
824-
}
825-
false
826-
}
827-
828782
pub fn recursive_type_with_infinite_size_error(self,
829783
type_def_id: DefId)
830784
-> DiagnosticBuilder<'tcx>
@@ -839,67 +793,9 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
839793
err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
840794
at some point to make `{}` representable",
841795
self.item_path_str(type_def_id)));
842-
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.
845-
if let Some(Node::NodeItem(self_item)) = self.hir.get_if_local(type_def_id) {
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);
858-
}
859-
_ => (),
860-
}
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;
875-
}
876-
}
877-
}
878-
_ => (),
879-
}
880-
}
881-
}
882796
err
883797
}
884798

885-
/// Given `item`, determine wether the node identified by `node_id` is referenced without any
886-
/// indirection in any of `item`'s fields.
887-
fn is_node_id_referenced_in_item(&self, item: &hir::Item, node_id: ast::NodeId) -> bool {
888-
if item.id == node_id {
889-
return true;
890-
}
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;
897-
}
898-
}
899-
}
900-
false
901-
}
902-
903799
pub fn report_object_safety_error(self,
904800
span: Span,
905801
trait_def_id: DefId,

src/librustc/ty/util.rs

+32-18
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,11 @@ pub enum CopyImplementationError<'tcx> {
145145
///
146146
/// The ordering of the cases is significant. They are sorted so that cmp::max
147147
/// will keep the "more erroneous" of two values.
148-
#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
148+
#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
149149
pub enum Representability {
150150
Representable,
151151
ContainsRecursive,
152-
SelfRecursive,
152+
SelfRecursive(Vec<Span>),
153153
}
154154

155155
impl<'tcx> ParameterEnvironment<'tcx> {
@@ -1003,37 +1003,51 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
10031003

10041004
/// Check whether a type is representable. This means it cannot contain unboxed
10051005
/// structural recursion. This check is needed for structs and enums.
1006-
pub fn is_representable(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span)
1006+
pub fn is_representable(&'tcx self,
1007+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
1008+
sp: Span)
10071009
-> Representability {
10081010

10091011
// Iterate until something non-representable is found
1010-
fn find_nonrepresentable<'a, 'tcx, It>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
1011-
sp: Span,
1012-
seen: &mut Vec<Ty<'tcx>>,
1013-
iter: It)
1014-
-> Representability
1015-
where It: Iterator<Item=Ty<'tcx>> {
1016-
iter.fold(Representability::Representable,
1017-
|r, ty| cmp::max(r, is_type_structurally_recursive(tcx, sp, seen, ty)))
1012+
fn fold_repr<It: Iterator<Item=Representability>>(iter: It) -> Representability {
1013+
iter.fold(Representability::Representable, |r1, r2| {
1014+
match (r1, r2) {
1015+
(Representability::SelfRecursive(v1),
1016+
Representability::SelfRecursive(v2)) => {
1017+
Representability::SelfRecursive(v1.iter().map(|s| *s).chain(v2).collect())
1018+
}
1019+
(r1, r2) => cmp::max(r1, r2)
1020+
}
1021+
})
10181022
}
10191023

10201024
fn are_inner_types_recursive<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span,
10211025
seen: &mut Vec<Ty<'tcx>>, ty: Ty<'tcx>)
10221026
-> Representability {
10231027
match ty.sty {
10241028
TyTuple(ref ts, _) => {
1025-
find_nonrepresentable(tcx, sp, seen, ts.iter().cloned())
1029+
// Find non representable
1030+
fold_repr(ts.iter().map(|ty| {
1031+
is_type_structurally_recursive(tcx, sp, seen, ty)
1032+
}))
10261033
}
10271034
// Fixed-length vectors.
10281035
// FIXME(#11924) Behavior undecided for zero-length vectors.
10291036
TyArray(ty, _) => {
10301037
is_type_structurally_recursive(tcx, sp, seen, ty)
10311038
}
10321039
TyAdt(def, substs) => {
1033-
find_nonrepresentable(tcx,
1034-
sp,
1035-
seen,
1036-
def.all_fields().map(|f| f.ty(tcx, substs)))
1040+
// Find non representable fields with their spans
1041+
fold_repr(def.all_fields().map(|field| {
1042+
let ty = field.ty(tcx, substs);
1043+
let span = tcx.hir.span_if_local(field.did).unwrap_or(sp);
1044+
match is_type_structurally_recursive(tcx, span, seen, ty) {
1045+
Representability::SelfRecursive(_) => {
1046+
Representability::SelfRecursive(vec![span])
1047+
}
1048+
x => x,
1049+
}
1050+
}))
10371051
}
10381052
TyClosure(..) => {
10391053
// this check is run on type definitions, so we don't expect
@@ -1072,7 +1086,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
10721086
sp: Span,
10731087
seen: &mut Vec<Ty<'tcx>>,
10741088
ty: Ty<'tcx>) -> Representability {
1075-
debug!("is_type_structurally_recursive: {:?}", ty);
1089+
debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
10761090

10771091
match ty.sty {
10781092
TyAdt(def, _) => {
@@ -1093,7 +1107,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
10931107
debug!("SelfRecursive: {:?} contains {:?}",
10941108
seen_type,
10951109
ty);
1096-
return Representability::SelfRecursive;
1110+
return Representability::SelfRecursive(vec![sp]);
10971111
}
10981112
}
10991113

src/librustc_typeck/check/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1378,8 +1378,12 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13781378
// contain themselves. For case 2, there must be an inner type that will be
13791379
// caught by case 1.
13801380
match rty.is_representable(tcx, sp) {
1381-
Representability::SelfRecursive => {
1382-
tcx.recursive_type_with_infinite_size_error(item_def_id).emit();
1381+
Representability::SelfRecursive(spans) => {
1382+
let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id);
1383+
for span in spans {
1384+
err.span_label(span, &"recursive without indirection");
1385+
}
1386+
err.emit();
13831387
return false
13841388
}
13851389
Representability::Representable | Representability::ContainsRecursive => (),

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

+10-3
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,16 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
enum foo { foo_(bar) }
12-
enum bar { bar_none, bar_some(bar) }
13-
//~^ ERROR recursive type `bar` has infinite size
11+
enum Foo {
12+
Foo_(Bar)
13+
}
14+
15+
enum Bar {
16+
//~^ ERROR recursive type `Bar` has infinite size
17+
//~| NOTE recursive type has infinite size
18+
BarNone,
19+
BarSome(Bar) //~ NOTE recursive without indirection
20+
}
1421

1522
fn main() {
1623
}

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
struct S { //~ ERROR E0072
12-
//~| NOTE recursive type has infinite size
11+
struct S {
12+
//~^ ERROR E0072
13+
//~| NOTE recursive type has infinite size
1314
element: Option<S>
15+
//~^ NOTE recursive without indirection
1416
}
1517

1618
fn main() {

src/test/ui/span/E0072.stderr

+3
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@ error[E0072]: recursive type `ListNode` has infinite size
33
|
44
11 | struct ListNode {
55
| ^^^^^^^^^^^^^^^ recursive type has infinite size
6+
12 | head: u8,
7+
13 | tail: Option<ListNode>,
8+
| ---------------------- recursive without indirection
69
|
710
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable
811

src/test/ui/span/multiline-span-E0072.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ error[E0072]: recursive type `ListNode` has infinite size
66
14 | | {
77
15 | | head: u8,
88
16 | | tail: Option<ListNode>,
9+
| | ---------------------- recursive without indirection
910
17 | | }
1011
| |_^ recursive type has infinite size
1112
|

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

+17-22
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,29 @@
11
error[E0072]: recursive type `Foo` has infinite size
22
--> $DIR/recursive-type-field.rs:13:1
33
|
4-
13 | struct Foo<'a> {
5-
| _^ starting here...
6-
14 | | bar: Bar<'a>,
7-
| | ------------ recursive without indirection
8-
15 | | b: Rc<Bar<'a>>,
9-
16 | | }
10-
| |_^ ...ending here: recursive type has infinite size
4+
13 | struct Foo<'a> {
5+
| ^^^^^^^^^^^^^^ recursive type has infinite size
6+
14 | bar: Bar<'a>,
7+
| ------------ recursive without indirection
118
|
129
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
1310

1411
error[E0072]: recursive type `Bar` has infinite size
1512
--> $DIR/recursive-type-field.rs:18:1
1613
|
17-
18 | struct Bar<'a> {
18-
| _^ starting here...
19-
19 | | y: (Foo<'a>, Foo<'a>),
20-
| | --------------------- recursive without indirection
21-
20 | | z: Option<Bar<'a>>,
22-
21 | | a: &'a Foo<'a>,
23-
22 | | c: &'a [Bar<'a>],
24-
23 | | d: [Bar<'a>; 1],
25-
| | --------------- recursive without indirection
26-
24 | | e: Foo<'a>,
27-
| | ---------- recursive without indirection
28-
25 | | x: Bar<'a>,
29-
| | ---------- recursive without indirection
30-
26 | | }
31-
| |_^ ...ending here: recursive type has infinite size
14+
18 | struct Bar<'a> {
15+
| ^^^^^^^^^^^^^^ recursive type has infinite size
16+
19 | y: (Foo<'a>, Foo<'a>),
17+
| --------------------- recursive without indirection
18+
20 | z: Option<Bar<'a>>,
19+
| ------------------ recursive without indirection
20+
...
21+
23 | d: [Bar<'a>; 1],
22+
| --------------- recursive without indirection
23+
24 | e: Foo<'a>,
24+
| ---------- recursive without indirection
25+
25 | x: Bar<'a>,
26+
| ---------- recursive without indirection
3227
|
3328
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
3429

0 commit comments

Comments
 (0)