1use std::collections::VecDeque;
2use std::fmt::Write;
3use std::ops::ControlFlow;
4
5use rustc_data_structures::fx::FxHashSet;
6use rustc_errors::codes::*;
7use rustc_errors::{Applicability, MultiSpan, pluralize, struct_span_code_err};
8use rustc_hir as hir;
9use rustc_hir::def::{DefKind, Res};
10use rustc_query_system::query::{CycleError, report_cycle};
11use rustc_span::def_id::LocalDefId;
12use rustc_span::{ErrorGuaranteed, Span};
13
14use crate::dep_graph::dep_kinds;
15use crate::query::plumbing::CyclePlaceholder;
16use crate::ty::{self, Representability, Ty, TyCtxt};
17
18pub trait Value<'tcx>: Sized {
19 fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle_error: &CycleError, guar: ErrorGuaranteed)
20 -> Self;
21}
22
23impl<'tcx, T> Value<'tcx> for T {
24 default fn from_cycle_error(
25 tcx: TyCtxt<'tcx>,
26 cycle_error: &CycleError,
27 _guar: ErrorGuaranteed,
28 ) -> T {
29 tcx.sess.dcx().abort_if_errors();
30 crate::util::bug::bug_fmt(format_args!("<{0} as Value>::from_cycle_error called without errors: {1:#?}",
std::any::type_name::<T>(), cycle_error.cycle));bug!(
31 "<{} as Value>::from_cycle_error called without errors: {:#?}",
32 std::any::type_name::<T>(),
33 cycle_error.cycle,
34 );
35 }
36}
37
38impl<'tcx> Value<'tcx> for Ty<'_> {
39 fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
40 unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_error(tcx, guar)) }
43 }
44}
45
46impl<'tcx> Value<'tcx> for Result<ty::EarlyBinder<'_, Ty<'_>>, CyclePlaceholder> {
47 fn from_cycle_error(_tcx: TyCtxt<'tcx>, _: &CycleError, guar: ErrorGuaranteed) -> Self {
48 Err(CyclePlaceholder(guar))
49 }
50}
51
52impl<'tcx> Value<'tcx> for ty::SymbolName<'_> {
53 fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &CycleError, _guar: ErrorGuaranteed) -> Self {
54 unsafe {
57 std::mem::transmute::<ty::SymbolName<'tcx>, ty::SymbolName<'_>>(ty::SymbolName::new(
58 tcx, "<error>",
59 ))
60 }
61 }
62}
63
64impl<'tcx> Value<'tcx> for ty::Binder<'_, ty::FnSig<'_>> {
65 fn from_cycle_error(
66 tcx: TyCtxt<'tcx>,
67 cycle_error: &CycleError,
68 guar: ErrorGuaranteed,
69 ) -> Self {
70 let err = Ty::new_error(tcx, guar);
71
72 let arity = if let Some(info) = cycle_error.cycle.get(0)
73 && info.frame.dep_kind == dep_kinds::fn_sig
74 && let Some(def_id) = info.frame.def_id
75 && let Some(node) = tcx.hir_get_if_local(def_id)
76 && let Some(sig) = node.fn_sig()
77 {
78 sig.decl.inputs.len()
79 } else {
80 tcx.dcx().abort_if_errors();
81 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
82 };
83
84 let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig(
85 std::iter::repeat_n(err, arity),
86 err,
87 false,
88 rustc_hir::Safety::Safe,
89 rustc_abi::ExternAbi::Rust,
90 ));
91
92 unsafe { std::mem::transmute::<ty::PolyFnSig<'tcx>, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) }
95 }
96}
97
98impl<'tcx> Value<'tcx> for Representability {
99 fn from_cycle_error(
100 tcx: TyCtxt<'tcx>,
101 cycle_error: &CycleError,
102 _guar: ErrorGuaranteed,
103 ) -> Self {
104 let mut item_and_field_ids = Vec::new();
105 let mut representable_ids = FxHashSet::default();
106 for info in &cycle_error.cycle {
107 if info.frame.dep_kind == dep_kinds::representability
108 && let Some(field_id) = info.frame.def_id
109 && let Some(field_id) = field_id.as_local()
110 && let Some(DefKind::Field) = info.frame.info.def_kind
111 {
112 let parent_id = tcx.parent(field_id.to_def_id());
113 let item_id = match tcx.def_kind(parent_id) {
114 DefKind::Variant => tcx.parent(parent_id),
115 _ => parent_id,
116 };
117 item_and_field_ids.push((item_id.expect_local(), field_id));
118 }
119 }
120 for info in &cycle_error.cycle {
121 if info.frame.dep_kind == dep_kinds::representability_adt_ty
122 && let Some(def_id) = info.frame.def_id_for_ty_in_cycle
123 && let Some(def_id) = def_id.as_local()
124 && !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
125 {
126 representable_ids.insert(def_id);
127 }
128 }
129 let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids);
130 Representability::Infinite(guar)
131 }
132}
133
134impl<'tcx> Value<'tcx> for ty::EarlyBinder<'_, Ty<'_>> {
135 fn from_cycle_error(
136 tcx: TyCtxt<'tcx>,
137 cycle_error: &CycleError,
138 guar: ErrorGuaranteed,
139 ) -> Self {
140 ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle_error, guar))
141 }
142}
143
144impl<'tcx> Value<'tcx> for ty::EarlyBinder<'_, ty::Binder<'_, ty::FnSig<'_>>> {
145 fn from_cycle_error(
146 tcx: TyCtxt<'tcx>,
147 cycle_error: &CycleError,
148 guar: ErrorGuaranteed,
149 ) -> Self {
150 ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle_error, guar))
151 }
152}
153
154impl<'tcx> Value<'tcx> for &[ty::Variance] {
155 fn from_cycle_error(
156 tcx: TyCtxt<'tcx>,
157 cycle_error: &CycleError,
158 _guar: ErrorGuaranteed,
159 ) -> Self {
160 search_for_cycle_permutation(
161 &cycle_error.cycle,
162 |cycle| {
163 if let Some(info) = cycle.get(0)
164 && info.frame.dep_kind == dep_kinds::variances_of
165 && let Some(def_id) = info.frame.def_id
166 {
167 let n = tcx.generics_of(def_id).own_params.len();
168 ControlFlow::Break(::alloc::vec::from_elem(ty::Bivariant, n)vec![ty::Bivariant; n].leak())
169 } else {
170 ControlFlow::Continue(())
171 }
172 },
173 || {
174 crate::util::bug::span_bug_fmt(cycle_error.usage.as_ref().unwrap().0,
format_args!("only `variances_of` returns `&[ty::Variance]`"))span_bug!(
175 cycle_error.usage.as_ref().unwrap().0,
176 "only `variances_of` returns `&[ty::Variance]`"
177 )
178 },
179 )
180 }
181}
182
183fn search_for_cycle_permutation<Q, T>(
185 cycle: &[Q],
186 try_cycle: impl Fn(&mut VecDeque<&Q>) -> ControlFlow<T, ()>,
187 otherwise: impl FnOnce() -> T,
188) -> T {
189 let mut cycle: VecDeque<_> = cycle.iter().collect();
190 for _ in 0..cycle.len() {
191 match try_cycle(&mut cycle) {
192 ControlFlow::Continue(_) => {
193 cycle.rotate_left(1);
194 }
195 ControlFlow::Break(t) => return t,
196 }
197 }
198
199 otherwise()
200}
201
202impl<'tcx, T> Value<'tcx> for Result<T, &'_ ty::layout::LayoutError<'_>> {
203 fn from_cycle_error(
204 tcx: TyCtxt<'tcx>,
205 cycle_error: &CycleError,
206 _guar: ErrorGuaranteed,
207 ) -> Self {
208 let diag = search_for_cycle_permutation(
209 &cycle_error.cycle,
210 |cycle| {
211 if cycle[0].frame.dep_kind == dep_kinds::layout_of
212 && let Some(def_id) = cycle[0].frame.def_id_for_ty_in_cycle
213 && let Some(def_id) = def_id.as_local()
214 && let def_kind = tcx.def_kind(def_id)
215 && #[allow(non_exhaustive_omitted_patterns)] match def_kind {
DefKind::Closure => true,
_ => false,
}matches!(def_kind, DefKind::Closure)
216 && let Some(coroutine_kind) = tcx.coroutine_kind(def_id)
217 {
218 let span = if coroutine_kind.is_fn_like() {
223 tcx.def_span(tcx.local_parent(def_id))
224 } else {
225 tcx.def_span(def_id)
226 };
227 let mut diag = {
tcx.sess.dcx().struct_span_err(span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("recursion in {0} {1} 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())))
})).with_code(E0733)
}struct_span_code_err!(
228 tcx.sess.dcx(),
229 span,
230 E0733,
231 "recursion in {} {} requires boxing",
232 tcx.def_kind_descr_article(def_kind, def_id.to_def_id()),
233 tcx.def_kind_descr(def_kind, def_id.to_def_id()),
234 );
235 for (i, info) in cycle.iter().enumerate() {
236 if info.frame.dep_kind != dep_kinds::layout_of {
237 continue;
238 }
239 let Some(frame_def_id) = info.frame.def_id_for_ty_in_cycle else {
240 continue;
241 };
242 let Some(frame_coroutine_kind) = tcx.coroutine_kind(frame_def_id) else {
243 continue;
244 };
245 let frame_span =
246 info.frame.info.default_span(cycle[(i + 1) % cycle.len()].span);
247 if frame_span.is_dummy() {
248 continue;
249 }
250 if i == 0 {
251 diag.span_label(frame_span, "recursive call here");
252 } else {
253 let coroutine_span: Span = if frame_coroutine_kind.is_fn_like() {
254 tcx.def_span(tcx.parent(frame_def_id))
255 } else {
256 tcx.def_span(frame_def_id)
257 };
258 let mut multispan = MultiSpan::from_span(coroutine_span);
259 multispan
260 .push_span_label(frame_span, "...leading to this recursive call");
261 diag.span_note(
262 multispan,
263 ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("which leads to this {0}",
tcx.def_descr(frame_def_id)))
})format!("which leads to this {}", tcx.def_descr(frame_def_id)),
264 );
265 }
266 }
267 if #[allow(non_exhaustive_omitted_patterns)] match coroutine_kind {
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => true,
_ => false,
}matches!(
270 coroutine_kind,
271 hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
272 ) {
273 diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future");
274 }
275
276 ControlFlow::Break(diag)
277 } else {
278 ControlFlow::Continue(())
279 }
280 },
281 || report_cycle(tcx.sess, cycle_error),
282 );
283
284 let guar = diag.emit();
285
286 Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle(guar))))
290 }
291}
292
293fn recursive_type_error(
296 tcx: TyCtxt<'_>,
297 mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>,
298 representable_ids: &FxHashSet<LocalDefId>,
299) -> ErrorGuaranteed {
300 const ITEM_LIMIT: usize = 5;
301
302 let start_index = item_and_field_ids
304 .iter()
305 .enumerate()
306 .min_by_key(|&(_, &(id, _))| tcx.def_span(id))
307 .unwrap()
308 .0;
309 item_and_field_ids.rotate_left(start_index);
310
311 let cycle_len = item_and_field_ids.len();
312 let show_cycle_len = cycle_len.min(ITEM_LIMIT);
313
314 let mut err_span = MultiSpan::from_spans(
315 item_and_field_ids[..show_cycle_len]
316 .iter()
317 .map(|(id, _)| tcx.def_span(id.to_def_id()))
318 .collect(),
319 );
320 let mut suggestion = Vec::with_capacity(show_cycle_len * 2);
321 for i in 0..show_cycle_len {
322 let (_, field_id) = item_and_field_ids[i];
323 let (next_item_id, _) = item_and_field_ids[(i + 1) % cycle_len];
324 let hir::Node::Field(field) = tcx.hir_node_by_def_id(field_id) else {
326 crate::util::bug::bug_fmt(format_args!("expected field"))bug!("expected field")
327 };
328 let mut found = Vec::new();
329 find_item_ty_spans(tcx, field.ty, next_item_id, &mut found, representable_ids);
330
331 if found.is_empty() {
334 found.push(field.ty.span);
335 }
336
337 for span in found {
338 err_span.push_span_label(span, "recursive without indirection");
339 suggestion.push((span.shrink_to_lo(), "Box<".to_string()));
341 suggestion.push((span.shrink_to_hi(), ">".to_string()));
342 }
343 }
344 let items_list = {
345 let mut s = String::new();
346 for (i, &(item_id, _)) in item_and_field_ids.iter().enumerate() {
347 let path = tcx.def_path_str(item_id);
348 (&mut s).write_fmt(format_args!("`{0}`", path))write!(&mut s, "`{path}`").unwrap();
349 if i == (ITEM_LIMIT - 1) && cycle_len > ITEM_LIMIT {
350 (&mut s).write_fmt(format_args!(" and {0} more", cycle_len - 5))write!(&mut s, " and {} more", cycle_len - 5).unwrap();
351 break;
352 }
353 if cycle_len > 1 && i < cycle_len - 2 {
354 s.push_str(", ");
355 } else if cycle_len > 1 && i == cycle_len - 2 {
356 s.push_str(" and ")
357 }
358 }
359 s
360 };
361 {
tcx.dcx().struct_span_err(err_span,
::alloc::__export::must_use({
::alloc::fmt::format(format_args!("recursive type{0} {1} {2} infinite size",
if cycle_len == 1 { "" } else { "s" }, items_list,
if cycle_len == 1 { "has" } else { "have" }))
})).with_code(E0072)
}struct_span_code_err!(
362 tcx.dcx(),
363 err_span,
364 E0072,
365 "recursive type{} {} {} infinite size",
366 pluralize!(cycle_len),
367 items_list,
368 pluralize!("has", cycle_len),
369 )
370 .with_multipart_suggestion(
371 "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle",
372 suggestion,
373 Applicability::HasPlaceholders,
374 )
375 .emit()
376}
377
378fn find_item_ty_spans(
379 tcx: TyCtxt<'_>,
380 ty: &hir::Ty<'_>,
381 needle: LocalDefId,
382 spans: &mut Vec<Span>,
383 seen_representable: &FxHashSet<LocalDefId>,
384) {
385 match ty.kind {
386 hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
387 if let Res::Def(kind, def_id) = path.res
388 && #[allow(non_exhaustive_omitted_patterns)] match kind {
DefKind::Enum | DefKind::Struct | DefKind::Union => true,
_ => false,
}matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union)
389 {
390 let check_params = def_id.as_local().is_none_or(|def_id| {
391 if def_id == needle {
392 spans.push(ty.span);
393 }
394 seen_representable.contains(&def_id)
395 });
396 if check_params && let Some(args) = path.segments.last().unwrap().args {
397 let params_in_repr = tcx.params_in_repr(def_id);
398 for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size())
400 {
401 if let hir::GenericArg::Type(ty) = arg
402 && params_in_repr.contains(i as u32)
403 {
404 find_item_ty_spans(
405 tcx,
406 ty.as_unambig_ty(),
407 needle,
408 spans,
409 seen_representable,
410 );
411 }
412 }
413 }
414 }
415 }
416 hir::TyKind::Array(ty, _) => find_item_ty_spans(tcx, ty, needle, spans, seen_representable),
417 hir::TyKind::Tup(tys) => {
418 tys.iter().for_each(|ty| find_item_ty_spans(tcx, ty, needle, spans, seen_representable))
419 }
420 _ => {}
421 }
422}