Auto merge of #100720 - camsteffen:representable, r=cjgillot
Rewrite representability * Improve placement of `Box` in the suggestion * Multiple items in a cycle emit 1 error instead of an error for each item in the cycle * Introduce `representability` query to avoid traversing an item every time it is used. * Also introduce `params_in_repr` query to avoid traversing generic items every time it is used.
This commit is contained in:
commit
bba9785dd7
61 changed files with 537 additions and 744 deletions
|
@ -2751,82 +2751,6 @@ impl<'v> Visitor<'v> for FindTypeParam {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn recursive_type_with_infinite_size_error<'tcx>(
|
||||
tcx: TyCtxt<'tcx>,
|
||||
type_def_id: DefId,
|
||||
spans: Vec<(Span, Option<hir::HirId>)>,
|
||||
) {
|
||||
assert!(type_def_id.is_local());
|
||||
let span = tcx.def_span(type_def_id);
|
||||
let path = tcx.def_path_str(type_def_id);
|
||||
let mut err =
|
||||
struct_span_err!(tcx.sess, span, E0072, "recursive type `{}` has infinite size", path);
|
||||
err.span_label(span, "recursive type has infinite size");
|
||||
for &(span, _) in &spans {
|
||||
err.span_label(span, "recursive without indirection");
|
||||
}
|
||||
let msg = format!(
|
||||
"insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `{}` representable",
|
||||
path,
|
||||
);
|
||||
if spans.len() <= 4 {
|
||||
// FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
|
||||
err.multipart_suggestion(
|
||||
&msg,
|
||||
spans
|
||||
.into_iter()
|
||||
.flat_map(|(span, field_id)| {
|
||||
if let Some(generic_span) = get_option_generic_from_field_id(tcx, field_id) {
|
||||
// If we match an `Option` and can grab the span of the Option's generic, then
|
||||
// suggest boxing the generic arg for a non-null niche optimization.
|
||||
vec![
|
||||
(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(),
|
||||
Applicability::HasPlaceholders,
|
||||
);
|
||||
} else {
|
||||
err.help(&msg);
|
||||
}
|
||||
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.last()?.args?.args.get(0)?;
|
||||
|
||||
// Take the span out of the type, if it's a type
|
||||
if let hir::GenericArg::Type(generic_ty) = generic_arg { Some(generic_ty.span) } else { None }
|
||||
}
|
||||
|
||||
/// Summarizes information
|
||||
#[derive(Clone)]
|
||||
pub enum ArgKind {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue