2023-09-15 13:39:11 +00:00
|
|
|
use crate::dep_graph::dep_kinds;
|
2023-08-27 22:02:54 +00:00
|
|
|
use crate::query::plumbing::CyclePlaceholder;
|
2022-08-15 19:11:11 +00:00
|
|
|
use rustc_data_structures::fx::FxHashSet;
|
Stop using `String` for error codes.
Error codes are integers, but `String` is used everywhere to represent
them. Gross!
This commit introduces `ErrCode`, an integral newtype for error codes,
replacing `String`. It also introduces a constant for every error code,
e.g. `E0123`, and removes the `error_code!` macro. The constants are
imported wherever used with `use rustc_errors::codes::*`.
With the old code, we have three different ways to specify an error code
at a use point:
```
error_code!(E0123) // macro call
struct_span_code_err!(dcx, span, E0123, "msg"); // bare ident arg to macro call
\#[diag(name, code = "E0123")] // string
struct Diag;
```
With the new code, they all use the `E0123` constant.
```
E0123 // constant
struct_span_code_err!(dcx, span, E0123, "msg"); // constant
\#[diag(name, code = E0123)] // constant
struct Diag;
```
The commit also changes the structure of the error code definitions:
- `rustc_error_codes` now just defines a higher-order macro listing the
used error codes and nothing else.
- Because that's now the only thing in the `rustc_error_codes` crate, I
moved it into the `lib.rs` file and removed the `error_codes.rs` file.
- `rustc_errors` uses that macro to define everything, e.g. the error
code constants and the `DIAGNOSTIC_TABLES`. This is in its new
`codes.rs` file.
2024-01-13 23:57:07 +00:00
|
|
|
use rustc_errors::{codes::*, pluralize, struct_span_code_err, Applicability, MultiSpan};
|
2022-08-15 19:11:11 +00:00
|
|
|
use rustc_hir as hir;
|
2023-02-17 16:19:13 +00:00
|
|
|
use rustc_hir::def::{DefKind, Res};
|
2022-08-15 19:11:11 +00:00
|
|
|
use rustc_middle::ty::Representability;
|
2023-02-22 15:51:17 +00:00
|
|
|
use rustc_middle::ty::{self, Ty, TyCtxt};
|
2023-11-08 06:56:06 +00:00
|
|
|
use rustc_query_system::query::{report_cycle, CycleError};
|
2022-09-02 01:43:12 +00:00
|
|
|
use rustc_query_system::Value;
|
2022-08-15 19:11:11 +00:00
|
|
|
use rustc_span::def_id::LocalDefId;
|
2023-08-27 21:32:55 +00:00
|
|
|
use rustc_span::{ErrorGuaranteed, Span};
|
2022-08-15 19:11:11 +00:00
|
|
|
|
2023-11-24 15:05:11 +00:00
|
|
|
use std::collections::VecDeque;
|
2022-08-15 19:11:11 +00:00
|
|
|
use std::fmt::Write;
|
2024-01-08 14:31:25 +00:00
|
|
|
use std::ops::ControlFlow;
|
2017-09-18 09:40:13 +00:00
|
|
|
|
2023-09-15 13:39:11 +00:00
|
|
|
impl<'tcx> Value<TyCtxt<'tcx>> for Ty<'_> {
|
2023-11-08 05:56:32 +00:00
|
|
|
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
|
2020-06-01 17:58:18 +00:00
|
|
|
// SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
|
|
|
|
// FIXME: Represent the above fact in the trait system somehow.
|
2023-08-27 21:32:55 +00:00
|
|
|
unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) }
|
2017-09-18 09:40:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-27 00:03:47 +00:00
|
|
|
impl<'tcx> Value<TyCtxt<'tcx>> for Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
|
2023-11-08 05:56:32 +00:00
|
|
|
fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
|
2023-08-27 22:02:54 +00:00
|
|
|
Err(CyclePlaceholder(guar))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-15 13:39:11 +00:00
|
|
|
impl<'tcx> Value<TyCtxt<'tcx>> for ty::SymbolName<'_> {
|
2023-11-08 05:56:32 +00:00
|
|
|
fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, _guar: ErrorGuaranteed) -> Self {
|
2020-07-10 05:45:05 +00:00
|
|
|
// SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
|
|
|
|
// FIXME: Represent the above fact in the trait system somehow.
|
|
|
|
unsafe {
|
|
|
|
std::mem::transmute::<ty::SymbolName<'tcx>, ty::SymbolName<'_>>(ty::SymbolName::new(
|
2022-09-02 01:43:12 +00:00
|
|
|
tcx, "<error>",
|
2020-07-10 05:45:05 +00:00
|
|
|
))
|
|
|
|
}
|
2017-09-18 09:40:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-09-15 13:39:11 +00:00
|
|
|
impl<'tcx> Value<TyCtxt<'tcx>> for ty::Binder<'_, ty::FnSig<'_>> {
|
2023-11-08 05:56:32 +00:00
|
|
|
fn from_cycle_error(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
cycle_error: &CycleError,
|
|
|
|
guar: ErrorGuaranteed,
|
|
|
|
) -> Self {
|
2023-08-27 21:32:55 +00:00
|
|
|
let err = Ty::new_error(tcx, guar);
|
2022-12-02 04:01:59 +00:00
|
|
|
|
2023-11-08 05:56:32 +00:00
|
|
|
let arity = if let Some(frame) = cycle_error.cycle.get(0)
|
2023-09-15 13:39:11 +00:00
|
|
|
&& frame.query.dep_kind == dep_kinds::fn_sig
|
2022-12-02 04:01:59 +00:00
|
|
|
&& let Some(def_id) = frame.query.def_id
|
|
|
|
&& let Some(node) = tcx.hir().get_if_local(def_id)
|
|
|
|
&& let Some(sig) = node.fn_sig()
|
|
|
|
{
|
|
|
|
sig.decl.inputs.len() + sig.decl.implicit_self.has_implicit_self() as usize
|
|
|
|
} else {
|
2023-12-21 05:26:09 +00:00
|
|
|
tcx.dcx().abort_if_errors();
|
2022-12-02 04:01:59 +00:00
|
|
|
unreachable!()
|
|
|
|
};
|
|
|
|
|
2022-08-10 20:53:06 +00:00
|
|
|
let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig(
|
2022-12-02 04:01:59 +00:00
|
|
|
std::iter::repeat(err).take(arity),
|
2022-08-10 20:53:06 +00:00
|
|
|
err,
|
|
|
|
false,
|
2024-05-17 17:17:48 +00:00
|
|
|
rustc_hir::Safety::Safe,
|
2022-08-10 20:53:06 +00:00
|
|
|
rustc_target::spec::abi::Abi::Rust,
|
|
|
|
));
|
|
|
|
|
|
|
|
// SAFETY: This is never called when `Self` is not `ty::Binder<'tcx, ty::FnSig<'tcx>>`.
|
|
|
|
// FIXME: Represent the above fact in the trait system somehow.
|
|
|
|
unsafe { std::mem::transmute::<ty::PolyFnSig<'tcx>, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) }
|
|
|
|
}
|
|
|
|
}
|
2022-08-15 19:11:11 +00:00
|
|
|
|
2023-09-15 13:39:11 +00:00
|
|
|
impl<'tcx> Value<TyCtxt<'tcx>> for Representability {
|
2023-11-08 05:56:32 +00:00
|
|
|
fn from_cycle_error(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
cycle_error: &CycleError,
|
|
|
|
_guar: ErrorGuaranteed,
|
|
|
|
) -> Self {
|
2022-08-15 19:11:11 +00:00
|
|
|
let mut item_and_field_ids = Vec::new();
|
|
|
|
let mut representable_ids = FxHashSet::default();
|
2023-11-08 05:56:32 +00:00
|
|
|
for info in &cycle_error.cycle {
|
2023-09-15 13:39:11 +00:00
|
|
|
if info.query.dep_kind == dep_kinds::representability
|
2022-08-15 19:11:11 +00:00
|
|
|
&& let Some(field_id) = info.query.def_id
|
|
|
|
&& let Some(field_id) = field_id.as_local()
|
|
|
|
&& let Some(DefKind::Field) = info.query.def_kind
|
|
|
|
{
|
|
|
|
let parent_id = tcx.parent(field_id.to_def_id());
|
|
|
|
let item_id = match tcx.def_kind(parent_id) {
|
|
|
|
DefKind::Variant => tcx.parent(parent_id),
|
|
|
|
_ => parent_id,
|
|
|
|
};
|
|
|
|
item_and_field_ids.push((item_id.expect_local(), field_id));
|
|
|
|
}
|
|
|
|
}
|
2023-11-08 05:56:32 +00:00
|
|
|
for info in &cycle_error.cycle {
|
2023-09-15 13:39:11 +00:00
|
|
|
if info.query.dep_kind == dep_kinds::representability_adt_ty
|
2023-11-08 06:56:06 +00:00
|
|
|
&& let Some(def_id) = info.query.ty_def_id
|
2022-08-15 19:11:11 +00:00
|
|
|
&& let Some(def_id) = def_id.as_local()
|
|
|
|
&& !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
|
|
|
|
{
|
|
|
|
representable_ids.insert(def_id);
|
|
|
|
}
|
|
|
|
}
|
2024-03-13 17:52:25 +00:00
|
|
|
let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids);
|
|
|
|
Representability::Infinite(guar)
|
2022-08-15 19:11:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-27 00:03:47 +00:00
|
|
|
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<'_, Ty<'_>> {
|
2023-11-08 05:56:32 +00:00
|
|
|
fn from_cycle_error(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
cycle_error: &CycleError,
|
|
|
|
guar: ErrorGuaranteed,
|
|
|
|
) -> Self {
|
|
|
|
ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle_error, guar))
|
2023-01-10 18:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-27 00:03:47 +00:00
|
|
|
impl<'tcx> Value<TyCtxt<'tcx>> for ty::EarlyBinder<'_, ty::Binder<'_, ty::FnSig<'_>>> {
|
2023-11-08 05:56:32 +00:00
|
|
|
fn from_cycle_error(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
cycle_error: &CycleError,
|
|
|
|
guar: ErrorGuaranteed,
|
|
|
|
) -> Self {
|
|
|
|
ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle_error, guar))
|
2023-01-10 18:53:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-02-23 11:45:44 +00:00
|
|
|
impl<'tcx> Value<TyCtxt<'tcx>> for &[ty::Variance] {
|
|
|
|
fn from_cycle_error(
|
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
cycle_error: &CycleError,
|
|
|
|
_guar: ErrorGuaranteed,
|
|
|
|
) -> Self {
|
|
|
|
if let Some(frame) = cycle_error.cycle.get(0)
|
|
|
|
&& frame.query.dep_kind == dep_kinds::variances_of
|
|
|
|
&& let Some(def_id) = frame.query.def_id
|
|
|
|
{
|
2024-05-10 00:56:44 +00:00
|
|
|
let n = tcx.generics_of(def_id).own_params.len();
|
2024-06-12 19:36:35 +00:00
|
|
|
vec![ty::Bivariant; n].leak()
|
2024-02-23 11:45:44 +00:00
|
|
|
} else {
|
|
|
|
span_bug!(
|
|
|
|
cycle_error.usage.as_ref().unwrap().0,
|
|
|
|
"only `variances_of` returns `&[ty::Variance]`"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-08 14:31:25 +00:00
|
|
|
// Take a cycle of `Q` and try `try_cycle` on every permutation, falling back to `otherwise`.
|
|
|
|
fn search_for_cycle_permutation<Q, T>(
|
|
|
|
cycle: &[Q],
|
|
|
|
try_cycle: impl Fn(&mut VecDeque<&Q>) -> ControlFlow<T, ()>,
|
|
|
|
otherwise: impl FnOnce() -> T,
|
|
|
|
) -> T {
|
|
|
|
let mut cycle: VecDeque<_> = cycle.iter().collect();
|
|
|
|
for _ in 0..cycle.len() {
|
|
|
|
match try_cycle(&mut cycle) {
|
|
|
|
ControlFlow::Continue(_) => {
|
|
|
|
cycle.rotate_left(1);
|
|
|
|
}
|
|
|
|
ControlFlow::Break(t) => return t,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
otherwise()
|
|
|
|
}
|
|
|
|
|
2023-09-15 13:39:11 +00:00
|
|
|
impl<'tcx, T> Value<TyCtxt<'tcx>> for Result<T, &'_ ty::layout::LayoutError<'_>> {
|
2023-11-08 05:56:32 +00:00
|
|
|
fn from_cycle_error(
|
2023-11-08 06:56:06 +00:00
|
|
|
tcx: TyCtxt<'tcx>,
|
|
|
|
cycle_error: &CycleError,
|
|
|
|
_guar: ErrorGuaranteed,
|
2023-11-08 05:56:32 +00:00
|
|
|
) -> Self {
|
2024-01-08 14:31:25 +00:00
|
|
|
let diag = search_for_cycle_permutation(
|
|
|
|
&cycle_error.cycle,
|
|
|
|
|cycle| {
|
2023-11-24 15:05:11 +00:00
|
|
|
if cycle[0].query.dep_kind == dep_kinds::layout_of
|
|
|
|
&& let Some(def_id) = cycle[0].query.ty_def_id
|
|
|
|
&& let Some(def_id) = def_id.as_local()
|
|
|
|
&& let def_kind = tcx.def_kind(def_id)
|
|
|
|
&& matches!(def_kind, DefKind::Closure)
|
|
|
|
&& let Some(coroutine_kind) = tcx.coroutine_kind(def_id)
|
|
|
|
{
|
|
|
|
// FIXME: `def_span` for an fn-like coroutine will point to the fn's body
|
|
|
|
// due to interactions between the desugaring into a closure expr and the
|
|
|
|
// def_span code. I'm not motivated to fix it, because I tried and it was
|
|
|
|
// not working, so just hack around it by grabbing the parent fn's span.
|
|
|
|
let span = if coroutine_kind.is_fn_like() {
|
|
|
|
tcx.def_span(tcx.local_parent(def_id))
|
2023-11-08 07:19:01 +00:00
|
|
|
} else {
|
2023-11-24 15:05:11 +00:00
|
|
|
tcx.def_span(def_id)
|
2023-11-08 07:19:01 +00:00
|
|
|
};
|
2024-01-03 22:08:36 +00:00
|
|
|
let mut diag = struct_span_code_err!(
|
2023-11-24 15:05:11 +00:00
|
|
|
tcx.sess.dcx(),
|
|
|
|
span,
|
|
|
|
E0733,
|
|
|
|
"recursion in {} {} requires boxing",
|
|
|
|
tcx.def_kind_descr_article(def_kind, def_id.to_def_id()),
|
|
|
|
tcx.def_kind_descr(def_kind, def_id.to_def_id()),
|
2023-11-08 07:19:01 +00:00
|
|
|
);
|
2023-11-24 15:05:11 +00:00
|
|
|
for (i, frame) in cycle.iter().enumerate() {
|
|
|
|
if frame.query.dep_kind != dep_kinds::layout_of {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
let Some(frame_def_id) = frame.query.ty_def_id else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
let Some(frame_coroutine_kind) = tcx.coroutine_kind(frame_def_id) else {
|
|
|
|
continue;
|
|
|
|
};
|
|
|
|
let frame_span =
|
|
|
|
frame.query.default_span(cycle[(i + 1) % cycle.len()].span);
|
|
|
|
if frame_span.is_dummy() {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if i == 0 {
|
|
|
|
diag.span_label(frame_span, "recursive call here");
|
|
|
|
} else {
|
|
|
|
let coroutine_span: Span = if frame_coroutine_kind.is_fn_like() {
|
|
|
|
tcx.def_span(tcx.parent(frame_def_id))
|
|
|
|
} else {
|
|
|
|
tcx.def_span(frame_def_id)
|
|
|
|
};
|
|
|
|
let mut multispan = MultiSpan::from_span(coroutine_span);
|
|
|
|
multispan
|
|
|
|
.push_span_label(frame_span, "...leading to this recursive call");
|
|
|
|
diag.span_note(
|
|
|
|
multispan,
|
|
|
|
format!("which leads to this {}", tcx.def_descr(frame_def_id)),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// FIXME: We could report a structured suggestion if we had
|
|
|
|
// enough info here... Maybe we can use a hacky HIR walker.
|
|
|
|
if matches!(
|
|
|
|
coroutine_kind,
|
|
|
|
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
|
|
|
|
) {
|
|
|
|
diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future");
|
|
|
|
}
|
2024-01-08 14:31:25 +00:00
|
|
|
|
|
|
|
ControlFlow::Break(diag)
|
2023-11-24 15:05:11 +00:00
|
|
|
} else {
|
2024-01-08 14:31:25 +00:00
|
|
|
ControlFlow::Continue(())
|
2023-11-08 07:19:01 +00:00
|
|
|
}
|
2024-01-08 14:31:25 +00:00
|
|
|
},
|
|
|
|
|| report_cycle(tcx.sess, cycle_error),
|
|
|
|
);
|
|
|
|
|
|
|
|
let guar = diag.emit();
|
2023-11-08 06:56:06 +00:00
|
|
|
|
2023-04-30 21:05:27 +00:00
|
|
|
// tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
|
|
|
|
// min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
|
|
|
|
// tcx.arena.alloc is pretty much equal to leaking).
|
2023-11-08 05:13:35 +00:00
|
|
|
Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle(guar))))
|
2023-05-02 16:14:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-15 19:11:11 +00:00
|
|
|
// item_and_field_ids should form a cycle where each field contains the
|
|
|
|
// type in the next element in the list
|
|
|
|
pub fn recursive_type_error(
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>,
|
|
|
|
representable_ids: &FxHashSet<LocalDefId>,
|
2024-03-13 17:52:25 +00:00
|
|
|
) -> ErrorGuaranteed {
|
2022-08-15 19:11:11 +00:00
|
|
|
const ITEM_LIMIT: usize = 5;
|
|
|
|
|
|
|
|
// Rotate the cycle so that the item with the lowest span is first
|
|
|
|
let start_index = item_and_field_ids
|
|
|
|
.iter()
|
|
|
|
.enumerate()
|
|
|
|
.min_by_key(|&(_, &(id, _))| tcx.def_span(id))
|
|
|
|
.unwrap()
|
|
|
|
.0;
|
|
|
|
item_and_field_ids.rotate_left(start_index);
|
|
|
|
|
|
|
|
let cycle_len = item_and_field_ids.len();
|
|
|
|
let show_cycle_len = cycle_len.min(ITEM_LIMIT);
|
|
|
|
|
|
|
|
let mut err_span = MultiSpan::from_spans(
|
|
|
|
item_and_field_ids[..show_cycle_len]
|
|
|
|
.iter()
|
|
|
|
.map(|(id, _)| tcx.def_span(id.to_def_id()))
|
|
|
|
.collect(),
|
|
|
|
);
|
|
|
|
let mut suggestion = Vec::with_capacity(show_cycle_len * 2);
|
|
|
|
for i in 0..show_cycle_len {
|
|
|
|
let (_, field_id) = item_and_field_ids[i];
|
|
|
|
let (next_item_id, _) = item_and_field_ids[(i + 1) % cycle_len];
|
|
|
|
// Find the span(s) that contain the next item in the cycle
|
2023-12-01 13:28:34 +00:00
|
|
|
let hir::Node::Field(field) = tcx.hir_node_by_def_id(field_id) else {
|
|
|
|
bug!("expected field")
|
|
|
|
};
|
2022-08-15 19:11:11 +00:00
|
|
|
let mut found = Vec::new();
|
|
|
|
find_item_ty_spans(tcx, field.ty, next_item_id, &mut found, representable_ids);
|
|
|
|
|
|
|
|
// Couldn't find the type. Maybe it's behind a type alias?
|
|
|
|
// In any case, we'll just suggest boxing the whole field.
|
|
|
|
if found.is_empty() {
|
|
|
|
found.push(field.ty.span);
|
|
|
|
}
|
|
|
|
|
|
|
|
for span in found {
|
|
|
|
err_span.push_span_label(span, "recursive without indirection");
|
|
|
|
// FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
|
|
|
|
suggestion.push((span.shrink_to_lo(), "Box<".to_string()));
|
|
|
|
suggestion.push((span.shrink_to_hi(), ">".to_string()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let items_list = {
|
|
|
|
let mut s = String::new();
|
2023-02-16 09:25:11 +00:00
|
|
|
for (i, &(item_id, _)) in item_and_field_ids.iter().enumerate() {
|
|
|
|
let path = tcx.def_path_str(item_id);
|
2022-08-15 19:11:11 +00:00
|
|
|
write!(&mut s, "`{path}`").unwrap();
|
|
|
|
if i == (ITEM_LIMIT - 1) && cycle_len > ITEM_LIMIT {
|
|
|
|
write!(&mut s, " and {} more", cycle_len - 5).unwrap();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if cycle_len > 1 && i < cycle_len - 2 {
|
|
|
|
s.push_str(", ");
|
|
|
|
} else if cycle_len > 1 && i == cycle_len - 2 {
|
|
|
|
s.push_str(" and ")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
s
|
|
|
|
};
|
2024-01-03 22:08:36 +00:00
|
|
|
struct_span_code_err!(
|
2023-12-18 11:21:37 +00:00
|
|
|
tcx.dcx(),
|
2022-08-15 19:11:11 +00:00
|
|
|
err_span,
|
|
|
|
E0072,
|
|
|
|
"recursive type{} {} {} infinite size",
|
|
|
|
pluralize!(cycle_len),
|
|
|
|
items_list,
|
|
|
|
pluralize!("has", cycle_len),
|
2024-01-03 06:03:10 +00:00
|
|
|
)
|
2024-01-08 22:08:49 +00:00
|
|
|
.with_multipart_suggestion(
|
2022-08-15 19:11:11 +00:00
|
|
|
"insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle",
|
|
|
|
suggestion,
|
|
|
|
Applicability::HasPlaceholders,
|
2024-01-03 06:03:10 +00:00
|
|
|
)
|
2024-03-13 17:52:25 +00:00
|
|
|
.emit()
|
2022-08-15 19:11:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
fn find_item_ty_spans(
|
|
|
|
tcx: TyCtxt<'_>,
|
|
|
|
ty: &hir::Ty<'_>,
|
|
|
|
needle: LocalDefId,
|
|
|
|
spans: &mut Vec<Span>,
|
|
|
|
seen_representable: &FxHashSet<LocalDefId>,
|
|
|
|
) {
|
|
|
|
match ty.kind {
|
|
|
|
hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
|
2023-02-17 16:19:13 +00:00
|
|
|
if let Res::Def(kind, def_id) = path.res
|
2023-09-26 02:15:32 +00:00
|
|
|
&& !matches!(kind, DefKind::TyAlias)
|
|
|
|
{
|
2022-08-15 19:11:11 +00:00
|
|
|
let check_params = def_id.as_local().map_or(true, |def_id| {
|
|
|
|
if def_id == needle {
|
|
|
|
spans.push(ty.span);
|
|
|
|
}
|
|
|
|
seen_representable.contains(&def_id)
|
|
|
|
});
|
|
|
|
if check_params && let Some(args) = path.segments.last().unwrap().args {
|
|
|
|
let params_in_repr = tcx.params_in_repr(def_id);
|
2022-11-09 16:05:38 +00:00
|
|
|
// the domain size check is needed because the HIR may not be well-formed at this point
|
|
|
|
for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size())
|
|
|
|
{
|
2022-08-15 19:11:11 +00:00
|
|
|
if let hir::GenericArg::Type(ty) = arg
|
|
|
|
&& params_in_repr.contains(i as u32)
|
|
|
|
{
|
|
|
|
find_item_ty_spans(tcx, ty, needle, spans, seen_representable);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
hir::TyKind::Array(ty, _) => find_item_ty_spans(tcx, ty, needle, spans, seen_representable),
|
|
|
|
hir::TyKind::Tup(tys) => {
|
|
|
|
tys.iter().for_each(|ty| find_item_ty_spans(tcx, ty, needle, spans, seen_representable))
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|