Specialize suggestion for Option<T>
This commit is contained in:
parent
df20355fa9
commit
de04c05dea
14 changed files with 231 additions and 63 deletions
|
@ -2285,10 +2285,10 @@ impl<'v> Visitor<'v> for FindTypeParam {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn recursive_type_with_infinite_size_error(
|
pub fn recursive_type_with_infinite_size_error<'tcx>(
|
||||||
tcx: TyCtxt<'_>,
|
tcx: TyCtxt<'tcx>,
|
||||||
type_def_id: DefId,
|
type_def_id: DefId,
|
||||||
spans: Vec<Span>,
|
spans: Vec<(Span, Option<hir::HirId>)>,
|
||||||
) {
|
) {
|
||||||
assert!(type_def_id.is_local());
|
assert!(type_def_id.is_local());
|
||||||
let span = tcx.hir().span_if_local(type_def_id).unwrap();
|
let span = tcx.hir().span_if_local(type_def_id).unwrap();
|
||||||
|
@ -2297,7 +2297,7 @@ pub fn recursive_type_with_infinite_size_error(
|
||||||
let mut err =
|
let mut err =
|
||||||
struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
|
struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
|
||||||
err.span_label(span, "recursive type has infinite size");
|
err.span_label(span, "recursive type has infinite size");
|
||||||
for &span in &spans {
|
for &(span, _) in &spans {
|
||||||
err.span_label(span, "recursive without indirection");
|
err.span_label(span, "recursive without indirection");
|
||||||
}
|
}
|
||||||
let msg = format!(
|
let msg = format!(
|
||||||
|
@ -2305,16 +2305,25 @@ pub fn recursive_type_with_infinite_size_error(
|
||||||
path,
|
path,
|
||||||
);
|
);
|
||||||
if spans.len() <= 4 {
|
if spans.len() <= 4 {
|
||||||
|
// FIXME: This suggestion might be erroneous if Option or Box are shadowed
|
||||||
err.multipart_suggestion(
|
err.multipart_suggestion(
|
||||||
&msg,
|
&msg,
|
||||||
spans
|
spans
|
||||||
.iter()
|
.into_iter()
|
||||||
.flat_map(|&span| {
|
.flat_map(|(span, field_id)| {
|
||||||
[
|
if let Some(generic_span) = get_option_generic_from_field_id(tcx, field_id) {
|
||||||
(span.shrink_to_lo(), "Box<".to_string()),
|
// If we match an `Option` and can grab the span of the Option's generic, then
|
||||||
(span.shrink_to_hi(), ">".to_string()),
|
// suggest boxing the generic arg for a non-null niche optimization.
|
||||||
]
|
vec![
|
||||||
.into_iter()
|
(generic_span.shrink_to_lo(), "Box<".to_string()),
|
||||||
|
(generic_span.shrink_to_hi(), ">".to_string()),
|
||||||
|
]
|
||||||
|
} else {
|
||||||
|
vec![
|
||||||
|
(span.shrink_to_lo(), "Box<".to_string()),
|
||||||
|
(span.shrink_to_hi(), ">".to_string()),
|
||||||
|
]
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
Applicability::HasPlaceholders,
|
Applicability::HasPlaceholders,
|
||||||
|
@ -2325,6 +2334,38 @@ pub fn recursive_type_with_infinite_size_error(
|
||||||
err.emit();
|
err.emit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extract the span for the generic type `T` of `Option<T>` in a field definition
|
||||||
|
fn get_option_generic_from_field_id(tcx: TyCtxt<'_>, field_id: Option<hir::HirId>) -> Option<Span> {
|
||||||
|
let node = tcx.hir().find(field_id?);
|
||||||
|
|
||||||
|
// Expect a field from our field_id
|
||||||
|
let Some(hir::Node::Field(field_def)) = node
|
||||||
|
else { bug!("Expected HirId corresponding to FieldDef, found: {:?}", node) };
|
||||||
|
|
||||||
|
// Match a type that is a simple QPath with no Self
|
||||||
|
let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = &field_def.ty.kind
|
||||||
|
else { return None };
|
||||||
|
|
||||||
|
// Check if the path we're checking resolves to Option
|
||||||
|
let hir::def::Res::Def(_, did) = path.res
|
||||||
|
else { return None };
|
||||||
|
|
||||||
|
// Bail if this path doesn't describe `::core::option::Option`
|
||||||
|
if !tcx.is_diagnostic_item(sym::Option, did) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match a single generic arg in the 0th path segment
|
||||||
|
let generic_arg = path.segments.get(0)?.args?.args.get(0);
|
||||||
|
|
||||||
|
// Take the span out of the type, if it's a type
|
||||||
|
if let Some(hir::GenericArg::Type(generic_ty)) = generic_arg {
|
||||||
|
Some(generic_ty.span)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Summarizes information
|
/// Summarizes information
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum ArgKind {
|
pub enum ArgKind {
|
||||||
|
|
|
@ -17,12 +17,20 @@ use std::cmp;
|
||||||
pub enum Representability {
|
pub enum Representability {
|
||||||
Representable,
|
Representable,
|
||||||
ContainsRecursive,
|
ContainsRecursive,
|
||||||
SelfRecursive(Vec<Span>),
|
/// Return a list of types that are included in themselves:
|
||||||
|
/// the spans where they are self-included, and (if found)
|
||||||
|
/// the HirId of the FieldDef that defines the self-inclusion.
|
||||||
|
SelfRecursive(Vec<(Span, Option<hir::HirId>)>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check whether a type is representable. This means it cannot contain unboxed
|
/// Check whether a type is representable. This means it cannot contain unboxed
|
||||||
/// structural recursion. This check is needed for structs and enums.
|
/// structural recursion. This check is needed for structs and enums.
|
||||||
pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> Representability {
|
pub fn ty_is_representable<'tcx>(
|
||||||
|
tcx: TyCtxt<'tcx>,
|
||||||
|
ty: Ty<'tcx>,
|
||||||
|
sp: Span,
|
||||||
|
field_id: Option<hir::HirId>,
|
||||||
|
) -> Representability {
|
||||||
debug!("is_type_representable: {:?}", ty);
|
debug!("is_type_representable: {:?}", ty);
|
||||||
// To avoid a stack overflow when checking an enum variant or struct that
|
// To avoid a stack overflow when checking an enum variant or struct that
|
||||||
// contains a different, structurally recursive type, maintain a stack of
|
// contains a different, structurally recursive type, maintain a stack of
|
||||||
|
@ -38,11 +46,12 @@ pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> R
|
||||||
let mut force_result = false;
|
let mut force_result = false;
|
||||||
let r = is_type_structurally_recursive(
|
let r = is_type_structurally_recursive(
|
||||||
tcx,
|
tcx,
|
||||||
sp,
|
|
||||||
&mut seen,
|
&mut seen,
|
||||||
&mut shadow_seen,
|
&mut shadow_seen,
|
||||||
&mut representable_cache,
|
&mut representable_cache,
|
||||||
ty,
|
ty,
|
||||||
|
sp,
|
||||||
|
field_id,
|
||||||
&mut force_result,
|
&mut force_result,
|
||||||
);
|
);
|
||||||
debug!("is_type_representable: {:?} is {:?}", ty, r);
|
debug!("is_type_representable: {:?} is {:?}", ty, r);
|
||||||
|
@ -61,11 +70,12 @@ fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representabilit
|
||||||
|
|
||||||
fn are_inner_types_recursive<'tcx>(
|
fn are_inner_types_recursive<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
sp: Span,
|
|
||||||
seen: &mut Vec<Ty<'tcx>>,
|
seen: &mut Vec<Ty<'tcx>>,
|
||||||
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
|
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
|
||||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
sp: Span,
|
||||||
|
field_id: Option<hir::HirId>,
|
||||||
force_result: &mut bool,
|
force_result: &mut bool,
|
||||||
) -> Representability {
|
) -> Representability {
|
||||||
debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen);
|
debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen);
|
||||||
|
@ -75,11 +85,12 @@ fn are_inner_types_recursive<'tcx>(
|
||||||
fold_repr(fields.iter().map(|ty| {
|
fold_repr(fields.iter().map(|ty| {
|
||||||
is_type_structurally_recursive(
|
is_type_structurally_recursive(
|
||||||
tcx,
|
tcx,
|
||||||
sp,
|
|
||||||
seen,
|
seen,
|
||||||
shadow_seen,
|
shadow_seen,
|
||||||
representable_cache,
|
representable_cache,
|
||||||
ty,
|
ty,
|
||||||
|
sp,
|
||||||
|
field_id,
|
||||||
force_result,
|
force_result,
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
|
@ -88,20 +99,26 @@ fn are_inner_types_recursive<'tcx>(
|
||||||
// FIXME(#11924) Behavior undecided for zero-length vectors.
|
// FIXME(#11924) Behavior undecided for zero-length vectors.
|
||||||
ty::Array(ty, _) => is_type_structurally_recursive(
|
ty::Array(ty, _) => is_type_structurally_recursive(
|
||||||
tcx,
|
tcx,
|
||||||
sp,
|
|
||||||
seen,
|
seen,
|
||||||
shadow_seen,
|
shadow_seen,
|
||||||
representable_cache,
|
representable_cache,
|
||||||
*ty,
|
*ty,
|
||||||
|
sp,
|
||||||
|
field_id,
|
||||||
force_result,
|
force_result,
|
||||||
),
|
),
|
||||||
ty::Adt(def, substs) => {
|
ty::Adt(def, substs) => {
|
||||||
// Find non representable fields with their spans
|
// Find non representable fields with their spans
|
||||||
fold_repr(def.all_fields().map(|field| {
|
fold_repr(def.all_fields().map(|field| {
|
||||||
let ty = field.ty(tcx, substs);
|
let ty = field.ty(tcx, substs);
|
||||||
let span = match field.did.as_local().and_then(|id| tcx.hir().find_by_def_id(id)) {
|
let (sp, field_id) = match field
|
||||||
Some(hir::Node::Field(field)) => field.ty.span,
|
.did
|
||||||
_ => sp,
|
.as_local()
|
||||||
|
.map(|id| tcx.hir().local_def_id_to_hir_id(id))
|
||||||
|
.and_then(|id| tcx.hir().find(id))
|
||||||
|
{
|
||||||
|
Some(hir::Node::Field(field)) => (field.ty.span, Some(field.hir_id)),
|
||||||
|
_ => (sp, field_id),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut result = None;
|
let mut result = None;
|
||||||
|
@ -130,7 +147,7 @@ fn are_inner_types_recursive<'tcx>(
|
||||||
// result without adjusting).
|
// result without adjusting).
|
||||||
if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) {
|
if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) {
|
||||||
*force_result = true;
|
*force_result = true;
|
||||||
result = Some(Representability::SelfRecursive(vec![span]));
|
result = Some(Representability::SelfRecursive(vec![(sp, field_id)]));
|
||||||
}
|
}
|
||||||
|
|
||||||
if result == None {
|
if result == None {
|
||||||
|
@ -161,16 +178,17 @@ fn are_inner_types_recursive<'tcx>(
|
||||||
result = Some(
|
result = Some(
|
||||||
match is_type_structurally_recursive(
|
match is_type_structurally_recursive(
|
||||||
tcx,
|
tcx,
|
||||||
span,
|
|
||||||
&mut nested_seen,
|
&mut nested_seen,
|
||||||
shadow_seen,
|
shadow_seen,
|
||||||
representable_cache,
|
representable_cache,
|
||||||
raw_adt_ty,
|
raw_adt_ty,
|
||||||
|
sp,
|
||||||
|
field_id,
|
||||||
force_result,
|
force_result,
|
||||||
) {
|
) {
|
||||||
Representability::SelfRecursive(_) => {
|
Representability::SelfRecursive(_) => {
|
||||||
if *force_result {
|
if *force_result {
|
||||||
Representability::SelfRecursive(vec![span])
|
Representability::SelfRecursive(vec![(sp, field_id)])
|
||||||
} else {
|
} else {
|
||||||
Representability::ContainsRecursive
|
Representability::ContainsRecursive
|
||||||
}
|
}
|
||||||
|
@ -208,15 +226,16 @@ fn are_inner_types_recursive<'tcx>(
|
||||||
result = Some(
|
result = Some(
|
||||||
match is_type_structurally_recursive(
|
match is_type_structurally_recursive(
|
||||||
tcx,
|
tcx,
|
||||||
span,
|
|
||||||
seen,
|
seen,
|
||||||
shadow_seen,
|
shadow_seen,
|
||||||
representable_cache,
|
representable_cache,
|
||||||
ty,
|
ty,
|
||||||
|
sp,
|
||||||
|
field_id,
|
||||||
force_result,
|
force_result,
|
||||||
) {
|
) {
|
||||||
Representability::SelfRecursive(_) => {
|
Representability::SelfRecursive(_) => {
|
||||||
Representability::SelfRecursive(vec![span])
|
Representability::SelfRecursive(vec![(sp, field_id)])
|
||||||
}
|
}
|
||||||
x => x,
|
x => x,
|
||||||
},
|
},
|
||||||
|
@ -247,29 +266,31 @@ fn same_adt<'tcx>(ty: Ty<'tcx>, def: ty::AdtDef<'tcx>) -> bool {
|
||||||
// contain any types on stack `seen`?
|
// contain any types on stack `seen`?
|
||||||
fn is_type_structurally_recursive<'tcx>(
|
fn is_type_structurally_recursive<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
sp: Span,
|
|
||||||
seen: &mut Vec<Ty<'tcx>>,
|
seen: &mut Vec<Ty<'tcx>>,
|
||||||
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
|
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
|
||||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
sp: Span,
|
||||||
|
field_id: Option<hir::HirId>,
|
||||||
force_result: &mut bool,
|
force_result: &mut bool,
|
||||||
) -> Representability {
|
) -> Representability {
|
||||||
debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
|
debug!("is_type_structurally_recursive: {:?} {:?} {:?}", ty, sp, field_id);
|
||||||
if let Some(representability) = representable_cache.get(&ty) {
|
if let Some(representability) = representable_cache.get(&ty) {
|
||||||
debug!(
|
debug!(
|
||||||
"is_type_structurally_recursive: {:?} {:?} - (cached) {:?}",
|
"is_type_structurally_recursive: {:?} {:?} {:?} - (cached) {:?}",
|
||||||
ty, sp, representability
|
ty, sp, field_id, representability
|
||||||
);
|
);
|
||||||
return representability.clone();
|
return representability.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
let representability = is_type_structurally_recursive_inner(
|
let representability = is_type_structurally_recursive_inner(
|
||||||
tcx,
|
tcx,
|
||||||
sp,
|
|
||||||
seen,
|
seen,
|
||||||
shadow_seen,
|
shadow_seen,
|
||||||
representable_cache,
|
representable_cache,
|
||||||
ty,
|
ty,
|
||||||
|
sp,
|
||||||
|
field_id,
|
||||||
force_result,
|
force_result,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -279,11 +300,12 @@ fn is_type_structurally_recursive<'tcx>(
|
||||||
|
|
||||||
fn is_type_structurally_recursive_inner<'tcx>(
|
fn is_type_structurally_recursive_inner<'tcx>(
|
||||||
tcx: TyCtxt<'tcx>,
|
tcx: TyCtxt<'tcx>,
|
||||||
sp: Span,
|
|
||||||
seen: &mut Vec<Ty<'tcx>>,
|
seen: &mut Vec<Ty<'tcx>>,
|
||||||
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
|
shadow_seen: &mut Vec<ty::AdtDef<'tcx>>,
|
||||||
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
|
||||||
ty: Ty<'tcx>,
|
ty: Ty<'tcx>,
|
||||||
|
sp: Span,
|
||||||
|
field_id: Option<hir::HirId>,
|
||||||
force_result: &mut bool,
|
force_result: &mut bool,
|
||||||
) -> Representability {
|
) -> Representability {
|
||||||
match ty.kind() {
|
match ty.kind() {
|
||||||
|
@ -305,7 +327,7 @@ fn is_type_structurally_recursive_inner<'tcx>(
|
||||||
if let Some(&seen_adt) = iter.next() {
|
if let Some(&seen_adt) = iter.next() {
|
||||||
if same_adt(seen_adt, *def) {
|
if same_adt(seen_adt, *def) {
|
||||||
debug!("SelfRecursive: {:?} contains {:?}", seen_adt, ty);
|
debug!("SelfRecursive: {:?} contains {:?}", seen_adt, ty);
|
||||||
return Representability::SelfRecursive(vec![sp]);
|
return Representability::SelfRecursive(vec![(sp, field_id)]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,11 +357,12 @@ fn is_type_structurally_recursive_inner<'tcx>(
|
||||||
shadow_seen.push(*def);
|
shadow_seen.push(*def);
|
||||||
let out = are_inner_types_recursive(
|
let out = are_inner_types_recursive(
|
||||||
tcx,
|
tcx,
|
||||||
sp,
|
|
||||||
seen,
|
seen,
|
||||||
shadow_seen,
|
shadow_seen,
|
||||||
representable_cache,
|
representable_cache,
|
||||||
ty,
|
ty,
|
||||||
|
sp,
|
||||||
|
field_id,
|
||||||
force_result,
|
force_result,
|
||||||
);
|
);
|
||||||
shadow_seen.pop();
|
shadow_seen.pop();
|
||||||
|
@ -350,11 +373,12 @@ fn is_type_structurally_recursive_inner<'tcx>(
|
||||||
// No need to push in other cases.
|
// No need to push in other cases.
|
||||||
are_inner_types_recursive(
|
are_inner_types_recursive(
|
||||||
tcx,
|
tcx,
|
||||||
sp,
|
|
||||||
seen,
|
seen,
|
||||||
shadow_seen,
|
shadow_seen,
|
||||||
representable_cache,
|
representable_cache,
|
||||||
ty,
|
ty,
|
||||||
|
sp,
|
||||||
|
field_id,
|
||||||
force_result,
|
force_result,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1045,7 +1045,7 @@ pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalD
|
||||||
// recursive type. It is only necessary to throw an error on those that
|
// recursive type. It is only necessary to throw an error on those that
|
||||||
// contain themselves. For case 2, there must be an inner type that will be
|
// contain themselves. For case 2, there must be an inner type that will be
|
||||||
// caught by case 1.
|
// caught by case 1.
|
||||||
match representability::ty_is_representable(tcx, rty, sp) {
|
match representability::ty_is_representable(tcx, rty, sp, None) {
|
||||||
Representability::SelfRecursive(spans) => {
|
Representability::SelfRecursive(spans) => {
|
||||||
recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
|
recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans);
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -8,8 +8,8 @@ LL | struct Foo { foo: Option<Option<Foo>> }
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
||||||
|
|
|
|
||||||
LL | struct Foo { foo: Box<Option<Option<Foo>>> }
|
LL | struct Foo { foo: Option<Box<Option<Foo>>> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ LL | struct Baz { q: Option<Foo> }
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
|
||||||
|
|
|
|
||||||
LL | struct Baz { q: Box<Option<Foo>> }
|
LL | struct Baz { q: Option<Box<Foo>> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error[E0072]: recursive type `Foo` has infinite size
|
error[E0072]: recursive type `Foo` has infinite size
|
||||||
--> $DIR/issue-17431-2.rs:4:1
|
--> $DIR/issue-17431-2.rs:4:1
|
||||||
|
@ -21,8 +21,8 @@ LL | struct Foo { q: Option<Baz> }
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
||||||
|
|
|
|
||||||
LL | struct Foo { q: Box<Option<Baz>> }
|
LL | struct Foo { q: Option<Box<Baz>> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ LL | struct Foo<T> { foo: Option<Option<Foo<T>>>, marker: marker::PhantomData<T>
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
||||||
|
|
|
|
||||||
LL | struct Foo<T> { foo: Box<Option<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
|
LL | struct Foo<T> { foo: Option<Box<Option<Foo<T>>>>, marker: marker::PhantomData<T> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ LL | enum Foo { Voo(Option<Option<Foo>>) }
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
||||||
|
|
|
|
||||||
LL | enum Foo { Voo(Box<Option<Option<Foo>>>) }
|
LL | enum Foo { Voo(Option<Box<Option<Foo>>>) }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ LL | element: Option<S>
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `S` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `S` representable
|
||||||
|
|
|
|
||||||
LL | element: Box<Option<S>>
|
LL | element: Option<Box<S>>
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ LL | struct Baz { q: Option<Foo> }
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Baz` representable
|
||||||
|
|
|
|
||||||
LL | struct Baz { q: Box<Option<Foo>> }
|
LL | struct Baz { q: Option<Box<Foo>> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error[E0072]: recursive type `Foo` has infinite size
|
error[E0072]: recursive type `Foo` has infinite size
|
||||||
--> $DIR/sized-cycle-note.rs:11:1
|
--> $DIR/sized-cycle-note.rs:11:1
|
||||||
|
@ -21,8 +21,8 @@ LL | struct Foo { q: Option<Baz> }
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable
|
||||||
|
|
|
|
||||||
LL | struct Foo { q: Box<Option<Baz>> }
|
LL | struct Foo { q: Option<Box<Baz>> }
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
|
@ -9,8 +9,8 @@ LL | tail: Option<ListNode>,
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
|
||||||
|
|
|
|
||||||
LL | tail: Box<Option<ListNode>>,
|
LL | tail: Option<Box<ListNode>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -12,8 +12,8 @@ LL | | }
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `ListNode` representable
|
||||||
|
|
|
|
||||||
LL | tail: Box<Option<ListNode>>,
|
LL | tail: Option<Box<ListNode>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error: aborting due to previous error
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,8 @@ LL | y: Option<Option<D<T>>>,
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `C` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `C` representable
|
||||||
|
|
|
|
||||||
LL | y: Box<Option<Option<D<T>>>>,
|
LL | y: Option<Box<Option<D<T>>>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error[E0072]: recursive type `D` has infinite size
|
error[E0072]: recursive type `D` has infinite size
|
||||||
--> $DIR/mutual-struct-recursion.rs:18:1
|
--> $DIR/mutual-struct-recursion.rs:18:1
|
||||||
|
@ -51,8 +51,8 @@ LL | z: Option<Option<C<T>>>,
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `D` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `D` representable
|
||||||
|
|
|
|
||||||
LL | z: Box<Option<Option<C<T>>>>,
|
LL | z: Option<Box<Option<C<T>>>>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to 4 previous errors
|
error: aborting due to 4 previous errors
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,30 @@
|
||||||
struct T1 { //~ ERROR E0072
|
struct T1 { //~ ERROR E0072
|
||||||
foo: isize,
|
foo: isize,
|
||||||
foolish: T1
|
foolish: T1,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct T2 { //~ ERROR E0072
|
||||||
|
inner: Option<T2>,
|
||||||
|
}
|
||||||
|
|
||||||
|
type OptionT3 = Option<T3>;
|
||||||
|
|
||||||
|
struct T3 { //~ ERROR E0072
|
||||||
|
inner: OptionT3,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct T4(Option<T4>); //~ ERROR E0072
|
||||||
|
|
||||||
|
enum T5 { //~ ERROR E0072
|
||||||
|
Variant(Option<T5>),
|
||||||
|
}
|
||||||
|
|
||||||
|
enum T6 { //~ ERROR E0072
|
||||||
|
Variant{ field: Option<T6> },
|
||||||
|
}
|
||||||
|
|
||||||
|
struct T7 { //~ ERROR E0072
|
||||||
|
foo: std::cell::Cell<Option<T7>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() { }
|
fn main() { }
|
||||||
|
|
|
@ -4,14 +4,93 @@ error[E0072]: recursive type `T1` has infinite size
|
||||||
LL | struct T1 {
|
LL | struct T1 {
|
||||||
| ^^^^^^^^^ recursive type has infinite size
|
| ^^^^^^^^^ recursive type has infinite size
|
||||||
LL | foo: isize,
|
LL | foo: isize,
|
||||||
LL | foolish: T1
|
LL | foolish: T1,
|
||||||
| -- recursive without indirection
|
| -- recursive without indirection
|
||||||
|
|
|
|
||||||
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T1` representable
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T1` representable
|
||||||
|
|
|
|
||||||
LL | foolish: Box<T1>
|
LL | foolish: Box<T1>,
|
||||||
| ++++ +
|
| ++++ +
|
||||||
|
|
||||||
error: aborting due to previous error
|
error[E0072]: recursive type `T2` has infinite size
|
||||||
|
--> $DIR/type-recursive.rs:6:1
|
||||||
|
|
|
||||||
|
LL | struct T2 {
|
||||||
|
| ^^^^^^^^^ recursive type has infinite size
|
||||||
|
LL | inner: Option<T2>,
|
||||||
|
| ---------- recursive without indirection
|
||||||
|
|
|
||||||
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T2` representable
|
||||||
|
|
|
||||||
|
LL | inner: Option<Box<T2>>,
|
||||||
|
| ++++ +
|
||||||
|
|
||||||
|
error[E0072]: recursive type `T3` has infinite size
|
||||||
|
--> $DIR/type-recursive.rs:12:1
|
||||||
|
|
|
||||||
|
LL | struct T3 {
|
||||||
|
| ^^^^^^^^^ recursive type has infinite size
|
||||||
|
LL | inner: OptionT3,
|
||||||
|
| -------- recursive without indirection
|
||||||
|
|
|
||||||
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T3` representable
|
||||||
|
|
|
||||||
|
LL | inner: Box<OptionT3>,
|
||||||
|
| ++++ +
|
||||||
|
|
||||||
|
error[E0072]: recursive type `T4` has infinite size
|
||||||
|
--> $DIR/type-recursive.rs:16:1
|
||||||
|
|
|
||||||
|
LL | struct T4(Option<T4>);
|
||||||
|
| ^^^^^^^^^^----------^^
|
||||||
|
| | |
|
||||||
|
| | recursive without indirection
|
||||||
|
| recursive type has infinite size
|
||||||
|
|
|
||||||
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T4` representable
|
||||||
|
|
|
||||||
|
LL | struct T4(Option<Box<T4>>);
|
||||||
|
| ++++ +
|
||||||
|
|
||||||
|
error[E0072]: recursive type `T5` has infinite size
|
||||||
|
--> $DIR/type-recursive.rs:18:1
|
||||||
|
|
|
||||||
|
LL | enum T5 {
|
||||||
|
| ^^^^^^^ recursive type has infinite size
|
||||||
|
LL | Variant(Option<T5>),
|
||||||
|
| ---------- recursive without indirection
|
||||||
|
|
|
||||||
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T5` representable
|
||||||
|
|
|
||||||
|
LL | Variant(Option<Box<T5>>),
|
||||||
|
| ++++ +
|
||||||
|
|
||||||
|
error[E0072]: recursive type `T6` has infinite size
|
||||||
|
--> $DIR/type-recursive.rs:22:1
|
||||||
|
|
|
||||||
|
LL | enum T6 {
|
||||||
|
| ^^^^^^^ recursive type has infinite size
|
||||||
|
LL | Variant{ field: Option<T6> },
|
||||||
|
| ---------- recursive without indirection
|
||||||
|
|
|
||||||
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T6` representable
|
||||||
|
|
|
||||||
|
LL | Variant{ field: Option<Box<T6>> },
|
||||||
|
| ++++ +
|
||||||
|
|
||||||
|
error[E0072]: recursive type `T7` has infinite size
|
||||||
|
--> $DIR/type-recursive.rs:26:1
|
||||||
|
|
|
||||||
|
LL | struct T7 {
|
||||||
|
| ^^^^^^^^^ recursive type has infinite size
|
||||||
|
LL | foo: std::cell::Cell<Option<T7>>,
|
||||||
|
| --------------------------- recursive without indirection
|
||||||
|
|
|
||||||
|
help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `T7` representable
|
||||||
|
|
|
||||||
|
LL | foo: Box<std::cell::Cell<Option<T7>>>,
|
||||||
|
| ++++ +
|
||||||
|
|
||||||
|
error: aborting due to 7 previous errors
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0072`.
|
For more information about this error, try `rustc --explain E0072`.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue