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 ```
This commit is contained in:
parent
96e2c34286
commit
ed6ad0952f
@ -1299,6 +1299,20 @@ 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 {
|
||||
|
@ -27,7 +27,7 @@ use errors::DiagnosticBuilder;
|
||||
use fmt_macros::{Parser, Piece, Position};
|
||||
use hir::{self, intravisit, Local, Pat, Body};
|
||||
use hir::intravisit::{Visitor, NestedVisitorMap};
|
||||
use hir::map::NodeExpr;
|
||||
use hir::map::{Node, NodeExpr};
|
||||
use hir::def_id::DefId;
|
||||
use infer::{self, InferCtxt};
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
@ -779,6 +779,18 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
pub fn recursive_type_with_infinite_size_error(self,
|
||||
type_def_id: DefId)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
@ -793,9 +805,119 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
err.help(&format!("insert indirection (e.g., a `Box`, `Rc`, or `&`) \
|
||||
at some point to make `{}` representable",
|
||||
self.item_path_str(type_def_id)));
|
||||
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn report_object_safety_error(self,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
|
28
src/test/ui/span/recursive-type-field.rs
Normal file
28
src/test/ui/span/recursive-type-field.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
struct Foo<'a> {
|
||||
bar: Bar<'a>,
|
||||
b: Rc<Bar<'a>>,
|
||||
}
|
||||
|
||||
struct Bar<'a> {
|
||||
y: (Foo<'a>, Foo<'a>),
|
||||
z: Option<Bar<'a>>,
|
||||
a: &'a Foo<'a>,
|
||||
c: &'a [Bar<'a>],
|
||||
d: [Bar<'a>; 1],
|
||||
e: Foo<'a>,
|
||||
x: Bar<'a>,
|
||||
}
|
||||
|
||||
fn main() {}
|
39
src/test/ui/span/recursive-type-field.stderr
Normal file
39
src/test/ui/span/recursive-type-field.stderr
Normal file
@ -0,0 +1,39 @@
|
||||
error[E0072]: recursive type `Foo` has infinite size
|
||||
--> $DIR/recursive-type-field.rs:13:1
|
||||
|
|
||||
13 | struct Foo<'a> {
|
||||
| _^ starting here...
|
||||
14 | | bar: Bar<'a>,
|
||||
| | ------------ recursive here
|
||||
15 | | b: Rc<Bar<'a>>,
|
||||
| | -------------- recursive here
|
||||
16 | | }
|
||||
| |_^ ...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
|
||||
--> $DIR/recursive-type-field.rs:18:1
|
||||
|
|
||||
18 | struct Bar<'a> {
|
||||
| _^ starting here...
|
||||
19 | | y: (Foo<'a>, Foo<'a>),
|
||||
| | --------------------- recursive here
|
||||
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
|
||||
24 | | e: Foo<'a>,
|
||||
| | ---------- recursive here
|
||||
25 | | x: Bar<'a>,
|
||||
| | ---------- recursive here
|
||||
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
|
Loading…
Reference in New Issue
Block a user