Skip to content

Commit a478e46

Browse files
committed
Auto merge of #40857 - estebank:recursive, r=arielb1
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 { | ^^^^^^^^^^ recursive type has infinite size 2 | bar: Bar, | -------- recursive here | = 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 { | ^^^^^^^^^^ recursive type has infinite size 6 | foo: Foo, | -------- recursive here | = help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable ```
2 parents ced823e + a4fc925 commit a478e46

11 files changed

+119
-26
lines changed

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> {
@@ -1006,37 +1006,51 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
10061006

10071007
/// Check whether a type is representable. This means it cannot contain unboxed
10081008
/// structural recursion. This check is needed for structs and enums.
1009-
pub fn is_representable(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span)
1009+
pub fn is_representable(&'tcx self,
1010+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
1011+
sp: Span)
10101012
-> Representability {
10111013

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

10231027
fn are_inner_types_recursive<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span,
10241028
seen: &mut Vec<Ty<'tcx>>, ty: Ty<'tcx>)
10251029
-> Representability {
10261030
match ty.sty {
10271031
TyTuple(ref ts, _) => {
1028-
find_nonrepresentable(tcx, sp, seen, ts.iter().cloned())
1032+
// Find non representable
1033+
fold_repr(ts.iter().map(|ty| {
1034+
is_type_structurally_recursive(tcx, sp, seen, ty)
1035+
}))
10291036
}
10301037
// Fixed-length vectors.
10311038
// FIXME(#11924) Behavior undecided for zero-length vectors.
10321039
TyArray(ty, _) => {
10331040
is_type_structurally_recursive(tcx, sp, seen, ty)
10341041
}
10351042
TyAdt(def, substs) => {
1036-
find_nonrepresentable(tcx,
1037-
sp,
1038-
seen,
1039-
def.all_fields().map(|f| f.ty(tcx, substs)))
1043+
// Find non representable fields with their spans
1044+
fold_repr(def.all_fields().map(|field| {
1045+
let ty = field.ty(tcx, substs);
1046+
let span = tcx.hir.span_if_local(field.did).unwrap_or(sp);
1047+
match is_type_structurally_recursive(tcx, span, seen, ty) {
1048+
Representability::SelfRecursive(_) => {
1049+
Representability::SelfRecursive(vec![span])
1050+
}
1051+
x => x,
1052+
}
1053+
}))
10401054
}
10411055
TyClosure(..) => {
10421056
// this check is run on type definitions, so we don't expect
@@ -1075,7 +1089,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
10751089
sp: Span,
10761090
seen: &mut Vec<Ty<'tcx>>,
10771091
ty: Ty<'tcx>) -> Representability {
1078-
debug!("is_type_structurally_recursive: {:?}", ty);
1092+
debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
10791093

10801094
match ty.sty {
10811095
TyAdt(def, _) => {
@@ -1096,7 +1110,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
10961110
debug!("SelfRecursive: {:?} contains {:?}",
10971111
seen_type,
10981112
ty);
1099-
return Representability::SelfRecursive;
1113+
return Representability::SelfRecursive(vec![sp]);
11001114
}
11011115
}
11021116

src/librustc_typeck/check/mod.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -1374,8 +1374,12 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
13741374
// contain themselves. For case 2, there must be an inner type that will be
13751375
// caught by case 1.
13761376
match rty.is_representable(tcx, sp) {
1377-
Representability::SelfRecursive => {
1378-
tcx.recursive_type_with_infinite_size_error(item_def_id).emit();
1377+
Representability::SelfRecursive(spans) => {
1378+
let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id);
1379+
for span in spans {
1380+
err.span_label(span, &"recursive without indirection");
1381+
}
1382+
err.emit();
13791383
return false
13801384
}
13811385
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-3008-2.rs

+1
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

+2
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/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/compile-fail/type-recursive.rs

+1-1
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/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
|
+28
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() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
error[E0072]: recursive type `Foo` has infinite size
2+
--> $DIR/recursive-type-field.rs:13:1
3+
|
4+
13 | struct Foo<'a> {
5+
| ^^^^^^^^^^^^^^ recursive type has infinite size
6+
14 | bar: Bar<'a>,
7+
| ------------ recursive without indirection
8+
|
9+
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Foo` representable
10+
11+
error[E0072]: recursive type `Bar` has infinite size
12+
--> $DIR/recursive-type-field.rs:18:1
13+
|
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
27+
|
28+
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
29+
30+
error: aborting due to 2 previous errors
31+

0 commit comments

Comments
 (0)