Move logic to is_representable instead of climbing HIR
This commit is contained in:
parent
f7108e18cd
commit
a4fc925192
9 changed files with 74 additions and 170 deletions
|
|
@ -1739,24 +1739,6 @@ 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
|
||||
|
|
|
|||
|
|
@ -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::{Node, NodeExpr};
|
||||
use hir::map::NodeExpr;
|
||||
use hir::def_id::DefId;
|
||||
use infer::{self, InferCtxt};
|
||||
use infer::type_variable::TypeVariableOrigin;
|
||||
|
|
@ -778,53 +778,7 @@ impl<'a, 'gcx, 'tcx> InferCtxt<'a, 'gcx, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
}
|
||||
},
|
||||
_ => 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>
|
||||
|
|
@ -839,67 +793,9 @@ 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)));
|
||||
|
||||
// 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) {
|
||||
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::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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
pub fn report_object_safety_error(self,
|
||||
span: Span,
|
||||
trait_def_id: DefId,
|
||||
|
|
|
|||
|
|
@ -145,11 +145,11 @@ pub enum CopyImplementationError<'tcx> {
|
|||
///
|
||||
/// The ordering of the cases is significant. They are sorted so that cmp::max
|
||||
/// will keep the "more erroneous" of two values.
|
||||
#[derive(Copy, Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
|
||||
#[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
|
||||
pub enum Representability {
|
||||
Representable,
|
||||
ContainsRecursive,
|
||||
SelfRecursive,
|
||||
SelfRecursive(Vec<Span>),
|
||||
}
|
||||
|
||||
impl<'tcx> ParameterEnvironment<'tcx> {
|
||||
|
|
@ -1003,18 +1003,22 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
|||
|
||||
/// Check whether a type is representable. This means it cannot contain unboxed
|
||||
/// structural recursion. This check is needed for structs and enums.
|
||||
pub fn is_representable(&'tcx self, tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span)
|
||||
pub fn is_representable(&'tcx self,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
sp: Span)
|
||||
-> Representability {
|
||||
|
||||
// Iterate until something non-representable is found
|
||||
fn find_nonrepresentable<'a, 'tcx, It>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
sp: Span,
|
||||
seen: &mut Vec<Ty<'tcx>>,
|
||||
iter: It)
|
||||
-> Representability
|
||||
where It: Iterator<Item=Ty<'tcx>> {
|
||||
iter.fold(Representability::Representable,
|
||||
|r, ty| cmp::max(r, is_type_structurally_recursive(tcx, sp, seen, ty)))
|
||||
fn fold_repr<It: Iterator<Item=Representability>>(iter: It) -> Representability {
|
||||
iter.fold(Representability::Representable, |r1, r2| {
|
||||
match (r1, r2) {
|
||||
(Representability::SelfRecursive(v1),
|
||||
Representability::SelfRecursive(v2)) => {
|
||||
Representability::SelfRecursive(v1.iter().map(|s| *s).chain(v2).collect())
|
||||
}
|
||||
(r1, r2) => cmp::max(r1, r2)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn are_inner_types_recursive<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span,
|
||||
|
|
@ -1022,7 +1026,10 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
|||
-> Representability {
|
||||
match ty.sty {
|
||||
TyTuple(ref ts, _) => {
|
||||
find_nonrepresentable(tcx, sp, seen, ts.iter().cloned())
|
||||
// Find non representable
|
||||
fold_repr(ts.iter().map(|ty| {
|
||||
is_type_structurally_recursive(tcx, sp, seen, ty)
|
||||
}))
|
||||
}
|
||||
// Fixed-length vectors.
|
||||
// FIXME(#11924) Behavior undecided for zero-length vectors.
|
||||
|
|
@ -1030,10 +1037,17 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
|||
is_type_structurally_recursive(tcx, sp, seen, ty)
|
||||
}
|
||||
TyAdt(def, substs) => {
|
||||
find_nonrepresentable(tcx,
|
||||
sp,
|
||||
seen,
|
||||
def.all_fields().map(|f| f.ty(tcx, substs)))
|
||||
// Find non representable fields with their spans
|
||||
fold_repr(def.all_fields().map(|field| {
|
||||
let ty = field.ty(tcx, substs);
|
||||
let span = tcx.hir.span_if_local(field.did).unwrap_or(sp);
|
||||
match is_type_structurally_recursive(tcx, span, seen, ty) {
|
||||
Representability::SelfRecursive(_) => {
|
||||
Representability::SelfRecursive(vec![span])
|
||||
}
|
||||
x => x,
|
||||
}
|
||||
}))
|
||||
}
|
||||
TyClosure(..) => {
|
||||
// this check is run on type definitions, so we don't expect
|
||||
|
|
@ -1072,7 +1086,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
|||
sp: Span,
|
||||
seen: &mut Vec<Ty<'tcx>>,
|
||||
ty: Ty<'tcx>) -> Representability {
|
||||
debug!("is_type_structurally_recursive: {:?}", ty);
|
||||
debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
|
||||
|
||||
match ty.sty {
|
||||
TyAdt(def, _) => {
|
||||
|
|
@ -1093,7 +1107,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> {
|
|||
debug!("SelfRecursive: {:?} contains {:?}",
|
||||
seen_type,
|
||||
ty);
|
||||
return Representability::SelfRecursive;
|
||||
return Representability::SelfRecursive(vec![sp]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1378,8 +1378,12 @@ fn check_representable<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
// contain themselves. For case 2, there must be an inner type that will be
|
||||
// caught by case 1.
|
||||
match rty.is_representable(tcx, sp) {
|
||||
Representability::SelfRecursive => {
|
||||
tcx.recursive_type_with_infinite_size_error(item_def_id).emit();
|
||||
Representability::SelfRecursive(spans) => {
|
||||
let mut err = tcx.recursive_type_with_infinite_size_error(item_def_id);
|
||||
for span in spans {
|
||||
err.span_label(span, &"recursive without indirection");
|
||||
}
|
||||
err.emit();
|
||||
return false
|
||||
}
|
||||
Representability::Representable | Representability::ContainsRecursive => (),
|
||||
|
|
|
|||
|
|
@ -8,9 +8,16 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
enum foo { foo_(bar) }
|
||||
enum bar { bar_none, bar_some(bar) }
|
||||
//~^ ERROR recursive type `bar` has infinite size
|
||||
enum Foo {
|
||||
Foo_(Bar)
|
||||
}
|
||||
|
||||
enum Bar {
|
||||
//~^ ERROR recursive type `Bar` has infinite size
|
||||
//~| NOTE recursive type has infinite size
|
||||
BarNone,
|
||||
BarSome(Bar) //~ NOTE recursive without indirection
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,9 +8,11 @@
|
|||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
struct S { //~ ERROR E0072
|
||||
//~| NOTE recursive type has infinite size
|
||||
struct S {
|
||||
//~^ ERROR E0072
|
||||
//~| NOTE recursive type has infinite size
|
||||
element: Option<S>
|
||||
//~^ NOTE recursive without indirection
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,9 @@ error[E0072]: recursive type `ListNode` has infinite size
|
|||
|
|
||||
11 | struct ListNode {
|
||||
| ^^^^^^^^^^^^^^^ recursive type has infinite size
|
||||
12 | head: u8,
|
||||
13 | tail: Option<ListNode>,
|
||||
| ---------------------- recursive without indirection
|
||||
|
|
||||
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `ListNode` representable
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ error[E0072]: recursive type `ListNode` has infinite size
|
|||
14 | | {
|
||||
15 | | head: u8,
|
||||
16 | | tail: Option<ListNode>,
|
||||
| | ---------------------- recursive without indirection
|
||||
17 | | }
|
||||
| |_^ recursive type has infinite size
|
||||
|
|
||||
|
|
|
|||
|
|
@ -1,34 +1,29 @@
|
|||
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 without indirection
|
||||
15 | | b: Rc<Bar<'a>>,
|
||||
16 | | }
|
||||
| |_^ ...ending here: recursive type has infinite size
|
||||
13 | struct Foo<'a> {
|
||||
| ^^^^^^^^^^^^^^ recursive type has infinite size
|
||||
14 | bar: Bar<'a>,
|
||||
| ------------ recursive without indirection
|
||||
|
|
||||
= 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 without indirection
|
||||
20 | | z: Option<Bar<'a>>,
|
||||
21 | | a: &'a Foo<'a>,
|
||||
22 | | c: &'a [Bar<'a>],
|
||||
23 | | d: [Bar<'a>; 1],
|
||||
| | --------------- recursive without indirection
|
||||
24 | | e: Foo<'a>,
|
||||
| | ---------- recursive without indirection
|
||||
25 | | x: Bar<'a>,
|
||||
| | ---------- recursive without indirection
|
||||
26 | | }
|
||||
| |_^ ...ending here: recursive type has infinite size
|
||||
18 | struct Bar<'a> {
|
||||
| ^^^^^^^^^^^^^^ recursive type has infinite size
|
||||
19 | y: (Foo<'a>, Foo<'a>),
|
||||
| --------------------- recursive without indirection
|
||||
20 | z: Option<Bar<'a>>,
|
||||
| ------------------ recursive without indirection
|
||||
...
|
||||
23 | d: [Bar<'a>; 1],
|
||||
| --------------- recursive without indirection
|
||||
24 | e: Foo<'a>,
|
||||
| ---------- recursive without indirection
|
||||
25 | x: Bar<'a>,
|
||||
| ---------- recursive without indirection
|
||||
|
|
||||
= help: insert indirection (e.g., a `Box`, `Rc`, or `&`) at some point to make `Bar` representable
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue