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
This commit is contained in:
parent
ed6ad0952f
commit
f7108e18cd
6 changed files with 112 additions and 126 deletions
|
|
@ -1299,20 +1299,6 @@ 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 {
|
||||
|
|
@ -1753,6 +1739,24 @@ impl Item_ {
|
|||
ItemDefaultImpl(..) => "item",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fields(&self) -> &[StructField] {
|
||||
match *self {
|
||||
ItemStruct(ref vd, _) => {
|
||||
return vd.fields();
|
||||
}
|
||||
ItemEnum(EnumDef { ref variants }, _) => {
|
||||
for variant in variants {
|
||||
let fields = variant.node.data.fields();
|
||||
if fields.len() > 0 {
|
||||
return fields;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
&[]
|
||||
}
|
||||
}
|
||||
|
||||
/// A reference from an trait to one of its associated items. This
|
||||
|
|
|
|||
|
|
@ -778,19 +778,53 @@ 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");
|
||||
/// Get the `DefId` for a given struct or enum `Ty`.
|
||||
fn ty_def_id(ty: &hir::Ty) -> Option<DefId> {
|
||||
match ty.node {
|
||||
hir::TyPath(hir::QPath::Resolved(_, ref path)) => {
|
||||
match path.def {
|
||||
hir::def::Def::Struct(did) | hir::def::Def::Enum(did) => {
|
||||
Some(did)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
||||
/// Add a span label to `err` pointing at `sp` if the field represented by `node_id` points
|
||||
/// recursively at the type `ty` without indirection.
|
||||
fn annotate_recursive_field_ty(&self,
|
||||
node_id: ast::NodeId,
|
||||
ty: &hir::Ty,
|
||||
sp: Span,
|
||||
err: &mut DiagnosticBuilder<'tcx>) -> bool {
|
||||
if let Some(did) = ty_def_id(ty) {
|
||||
return self.annotate_recursive_field_id(node_id, did, sp, err);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Add a span label to `err` pointing at `sp` if the field represented by `node_id` points
|
||||
/// recursively at the type represented by `did` without indirection.
|
||||
fn annotate_recursive_field_id(&self,
|
||||
node_id:
|
||||
ast::NodeId,
|
||||
did: DefId,
|
||||
sp: Span,
|
||||
err: &mut DiagnosticBuilder<'tcx>) -> bool
|
||||
{
|
||||
if let Some(Node::NodeItem(item)) = self.hir.get_if_local(did) {
|
||||
if self.is_node_id_referenced_in_item(item, node_id) {
|
||||
err.span_label(sp, &"recursive without indirection");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn recursive_type_with_infinite_size_error(self,
|
||||
type_def_id: DefId)
|
||||
-> DiagnosticBuilder<'tcx>
|
||||
|
|
@ -806,114 +840,62 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||
at some point to make `{}` representable",
|
||||
self.item_path_str(type_def_id)));
|
||||
|
||||
// Look at the type for the the recursive type's fields and label those that are causing it
|
||||
// to be of infinite size.
|
||||
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");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
for field in self_item.node.fields() {
|
||||
match field.ty.node {
|
||||
hir::TyPath(ref qpath) => {
|
||||
// Foo
|
||||
if let &hir::QPath::Resolved(_, ref path) = qpath {
|
||||
match path.def {
|
||||
hir::def::Def::Struct(did) |
|
||||
hir::def::Def::Enum(did) => {
|
||||
self.annotate_recursive_field_id(self_item.id,
|
||||
did,
|
||||
field.span,
|
||||
&mut err);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
hir::TyArray(ref ty, _) => {
|
||||
// [Foo]
|
||||
self.annotate_recursive_field_ty(self_item.id, &ty, field.span, &mut err);
|
||||
}
|
||||
hir::TyTup(ref tys) => {
|
||||
// (Foo, Bar)
|
||||
for ty in tys {
|
||||
if self.annotate_recursive_field_ty(self_item.id,
|
||||
&ty,
|
||||
field.span,
|
||||
&mut err) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
err
|
||||
}
|
||||
|
||||
/// Given `item`, determine wether the node identified by `node_id` is referenced without any
|
||||
/// indirection in any of `item`'s fields.
|
||||
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;
|
||||
}
|
||||
}
|
||||
for field in item.node.fields() {
|
||||
if let Some(Node::NodeItem(ref item)) = ty_def_id(&field.ty).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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ enum foo { foo_(bar) }
|
|||
struct bar { x: bar }
|
||||
//~^ ERROR E0072
|
||||
//~| NOTE recursive type has infinite size
|
||||
//~| NOTE recursive without indirection
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,8 @@
|
|||
enum Expr { //~ ERROR E0072
|
||||
//~| NOTE recursive type has infinite size
|
||||
Plus(Expr, Expr),
|
||||
//~^ NOTE recursive without indirection
|
||||
//~| NOTE recursive without indirection
|
||||
Literal(i64),
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
struct t1 { //~ ERROR E0072
|
||||
//~| NOTE recursive type has infinite size
|
||||
foo: isize,
|
||||
foolish: t1
|
||||
foolish: t1 //~ NOTE recursive without indirection
|
||||
}
|
||||
|
||||
fn main() { }
|
||||
|
|
|
|||
|
|
@ -4,9 +4,8 @@ error[E0072]: recursive type `Foo` has infinite size
|
|||
13 | struct Foo<'a> {
|
||||
| _^ starting here...
|
||||
14 | | bar: Bar<'a>,
|
||||
| | ------------ recursive here
|
||||
| | ------------ recursive without indirection
|
||||
15 | | b: Rc<Bar<'a>>,
|
||||
| | -------------- recursive here
|
||||
16 | | }
|
||||
| |_^ ...ending here: recursive type has infinite size
|
||||
|
|
||||
|
|
@ -18,22 +17,20 @@ error[E0072]: recursive type `Bar` has infinite size
|
|||
18 | struct Bar<'a> {
|
||||
| _^ starting here...
|
||||
19 | | y: (Foo<'a>, Foo<'a>),
|
||||
| | --------------------- recursive here
|
||||
| | --------------------- recursive without indirection
|
||||
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
|
||||
| | --------------- recursive without indirection
|
||||
24 | | e: Foo<'a>,
|
||||
| | ---------- recursive here
|
||||
| | ---------- recursive without indirection
|
||||
25 | | x: Bar<'a>,
|
||||
| | ---------- recursive here
|
||||
| | ---------- recursive without indirection
|
||||
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…
Add table
Add a link
Reference in a new issue