1use std::collections::VecDeque;
2use std::fmt::Write;
3use std::iter;
4use std::ops::ControlFlow;
5
6use rustc_data_structures::fx::FxHashSet;
7use rustc_errors::codes::*;
8use rustc_errors::{Applicability, Diag, MultiSpan, pluralize, struct_span_code_err};
9use rustc_hir as hir;
10use rustc_hir::def::{DefKind, Res};
11use rustc_middle::bug;
12use rustc_middle::queries::TaggedQueryKey;
13use rustc_middle::query::Cycle;
14use rustc_middle::ty::{self, Ty, TyCtxt};
15use rustc_span::def_id::{DefId, LocalDefId};
16use rustc_span::{DUMMY_SP, ErrorGuaranteed, Span};
17
18pub(crate) fn default(err: Diag<'_>) -> ! {
21 let guar = err.emit();
22 guar.raise_fatal()
23}
24
25pub(crate) fn fn_sig<'tcx>(
26 tcx: TyCtxt<'tcx>,
27 def_id: DefId,
28 _: Cycle<'tcx>,
29 err: Diag<'_>,
30) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> {
31 let guar = err.delay_as_bug();
32
33 let err = Ty::new_error(tcx, guar);
34
35 let arity = if let Some(node) = tcx.hir_get_if_local(def_id)
36 && let Some(sig) = node.fn_sig()
37 {
38 sig.decl.inputs.len()
39 } else {
40 tcx.dcx().abort_if_errors();
41 ::core::panicking::panic("internal error: entered unreachable code")unreachable!()
42 };
43
44 ty::EarlyBinder::bind(
45 tcx,
46 ty::Binder::dummy(tcx.mk_fn_sig_safe_rust_abi(std::iter::repeat_n(err, arity), err)),
47 )
48}
49
50pub(crate) fn check_representability<'tcx>(
51 tcx: TyCtxt<'tcx>,
52 _key: LocalDefId,
53 cycle: Cycle<'tcx>,
54 _err: Diag<'_>,
55) {
56 check_representability_inner(tcx, cycle);
57}
58
59pub(crate) fn check_representability_adt_ty<'tcx>(
60 tcx: TyCtxt<'tcx>,
61 _key: Ty<'tcx>,
62 cycle: Cycle<'tcx>,
63 _err: Diag<'_>,
64) {
65 check_representability_inner(tcx, cycle);
66}
67
68fn check_representability_inner<'tcx>(tcx: TyCtxt<'tcx>, cycle: Cycle<'tcx>) -> ! {
69 let mut item_and_field_ids = Vec::new();
70 let mut representable_ids = FxHashSet::default();
71 for frame in &cycle.frames {
72 if let TaggedQueryKey::check_representability(def_id) = frame.tagged_key
73 && tcx.def_kind(def_id) == DefKind::Field
74 {
75 let field_id: LocalDefId = def_id;
76 let parent_id = tcx.parent(field_id.to_def_id());
77 let item_id = match tcx.def_kind(parent_id) {
78 DefKind::Variant => tcx.parent(parent_id),
79 _ => parent_id,
80 };
81 item_and_field_ids.push((item_id.expect_local(), field_id));
82 }
83 }
84 for frame in &cycle.frames {
85 if let TaggedQueryKey::check_representability_adt_ty(key) = frame.tagged_key
86 && let Some(adt) = key.ty_adt_def()
87 && let Some(def_id) = adt.did().as_local()
88 && !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
89 {
90 representable_ids.insert(def_id);
91 }
92 }
93 let guar = recursive_type_error(tcx, item_and_field_ids, &representable_ids);
96 guar.raise_fatal()
97}
98
99pub(crate) fn variances_of<'tcx>(
100 tcx: TyCtxt<'tcx>,
101 def_id: DefId,
102 _cycle: Cycle<'tcx>,
103 err: Diag<'_>,
104) -> &'tcx [ty::Variance] {
105 let _guar = err.delay_as_bug();
106 let n = tcx.generics_of(def_id).count();
107 tcx.arena.alloc_from_iter(iter::repeat_n(ty::Bivariant, n))
108}
109
110fn search_for_cycle_permutation<Q, T>(
112 cycle: &[Q],
113 try_cycle: impl Fn(&mut VecDeque<&Q>) -> ControlFlow<T, ()>,
114 otherwise: impl FnOnce() -> T,
115) -> T {
116 let mut cycle: VecDeque<_> = cycle.iter().collect();
117 for _ in 0..cycle.len() {
118 match try_cycle(&mut cycle) {
119 ControlFlow::Continue(_) => {
120 cycle.rotate_left(1);
121 }
122 ControlFlow::Break(t) => return t,
123 }
124 }
125
126 otherwise()
127}
128
129pub(crate) fn layout_of<'tcx>(
130 tcx: TyCtxt<'tcx>,
131 _key: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
132 cycle: Cycle<'tcx>,
133 err: Diag<'_>,
134) -> Result<ty::layout::TyAndLayout<'tcx>, &'tcx ty::layout::LayoutError<'tcx>> {
135 let _guar = err.delay_as_bug();
136 let diag = search_for_cycle_permutation(
137 &cycle.frames,
138 |frames| {
139 if let TaggedQueryKey::layout_of(key) = frames[0].tagged_key
140 && let ty::Coroutine(def_id, _) = key.value.kind()
141 && let Some(def_id) = def_id.as_local()
142 && let def_kind = tcx.def_kind(def_id)
143 && #[allow(non_exhaustive_omitted_patterns)] match def_kind {
DefKind::Closure => true,
_ => false,
}matches!(def_kind, DefKind::Closure)
144 && let Some(coroutine_kind) = tcx.coroutine_kind(def_id)
145 {
146 let span = if coroutine_kind.is_fn_like() {
151 tcx.def_span(tcx.local_parent(def_id))
152 } else {
153 tcx.def_span(def_id)
154 };
155 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!(
156 tcx.sess.dcx(),
157 span,
158 E0733,
159 "recursion in {} {} requires boxing",
160 tcx.def_kind_descr_article(def_kind, def_id.to_def_id()),
161 tcx.def_kind_descr(def_kind, def_id.to_def_id()),
162 );
163 for (i, frame) in frames.iter().enumerate() {
164 let TaggedQueryKey::layout_of(frame_key) = frame.tagged_key else {
165 continue;
166 };
167 let &ty::Coroutine(frame_def_id, _) = frame_key.value.kind() else {
168 continue;
169 };
170 let Some(frame_coroutine_kind) = tcx.coroutine_kind(frame_def_id) else {
171 continue;
172 };
173 let frame_span =
174 frame.tagged_key.default_span(tcx, frames[(i + 1) % frames.len()].span);
175 if frame_span.is_dummy() {
176 continue;
177 }
178 if i == 0 {
179 diag.span_label(frame_span, "recursive call here");
180 } else {
181 let coroutine_span: Span = if frame_coroutine_kind.is_fn_like() {
182 tcx.def_span(tcx.parent(frame_def_id))
183 } else {
184 tcx.def_span(frame_def_id)
185 };
186 let mut multispan = MultiSpan::from_span(coroutine_span);
187 multispan.push_span_label(frame_span, "...leading to this recursive call");
188 diag.span_note(
189 multispan,
190 ::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)),
191 );
192 }
193 }
194 if #[allow(non_exhaustive_omitted_patterns)] match coroutine_kind {
hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _) => true,
_ => false,
}matches!(
197 coroutine_kind,
198 hir::CoroutineKind::Desugared(hir::CoroutineDesugaring::Async, _)
199 ) {
200 diag.note("a recursive `async fn` call must introduce indirection such as `Box::pin` to avoid an infinitely sized future");
201 }
202
203 ControlFlow::Break(diag)
204 } else {
205 ControlFlow::Continue(())
206 }
207 },
208 || create_cycle_error(tcx, &cycle, false),
209 );
210
211 diag.emit().raise_fatal()
212}
213
214fn recursive_type_error(
217 tcx: TyCtxt<'_>,
218 mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>,
219 representable_ids: &FxHashSet<LocalDefId>,
220) -> ErrorGuaranteed {
221 const ITEM_LIMIT: usize = 5;
222
223 let start_index = item_and_field_ids
225 .iter()
226 .enumerate()
227 .min_by_key(|&(_, &(id, _))| tcx.def_span(id))
228 .unwrap()
229 .0;
230 item_and_field_ids.rotate_left(start_index);
231
232 let cycle_len = item_and_field_ids.len();
233 let show_cycle_len = cycle_len.min(ITEM_LIMIT);
234
235 let mut err_span = MultiSpan::from_spans(
236 item_and_field_ids[..show_cycle_len]
237 .iter()
238 .map(|(id, _)| tcx.def_span(id.to_def_id()))
239 .collect(),
240 );
241 let mut suggestion = Vec::with_capacity(show_cycle_len * 2);
242 for i in 0..show_cycle_len {
243 let (_, field_id) = item_and_field_ids[i];
244 let (next_item_id, _) = item_and_field_ids[(i + 1) % cycle_len];
245 let hir::Node::Field(field) = tcx.hir_node_by_def_id(field_id) else {
247 ::rustc_middle::util::bug::bug_fmt(format_args!("expected field"))bug!("expected field")
248 };
249 let mut found = Vec::new();
250 find_item_ty_spans(tcx, field.ty, next_item_id, &mut found, representable_ids);
251
252 if found.is_empty() {
255 found.push(field.ty.span);
256 }
257
258 for span in found {
259 err_span.push_span_label(span, "recursive without indirection");
260 suggestion.push((span.shrink_to_lo(), "Box<".to_string()));
262 suggestion.push((span.shrink_to_hi(), ">".to_string()));
263 }
264 }
265 let items_list = {
266 let mut s = String::new();
267 for (i, &(item_id, _)) in item_and_field_ids.iter().enumerate() {
268 let path = tcx.def_path_str(item_id);
269 (&mut s).write_fmt(format_args!("`{0}`", path))write!(&mut s, "`{path}`").unwrap();
270 if i == (ITEM_LIMIT - 1) && cycle_len > ITEM_LIMIT {
271 (&mut s).write_fmt(format_args!(" and {0} more", cycle_len - 5))write!(&mut s, " and {} more", cycle_len - 5).unwrap();
272 break;
273 }
274 if cycle_len > 1 && i < cycle_len - 2 {
275 s.push_str(", ");
276 } else if cycle_len > 1 && i == cycle_len - 2 {
277 s.push_str(" and ")
278 }
279 }
280 s
281 };
282 {
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!(
283 tcx.dcx(),
284 err_span,
285 E0072,
286 "recursive type{} {} {} infinite size",
287 pluralize!(cycle_len),
288 items_list,
289 pluralize!("has", cycle_len),
290 )
291 .with_multipart_suggestion(
292 "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle",
293 suggestion,
294 Applicability::HasPlaceholders,
295 )
296 .emit()
297}
298
299fn find_item_ty_spans(
300 tcx: TyCtxt<'_>,
301 ty: &hir::Ty<'_>,
302 needle: LocalDefId,
303 spans: &mut Vec<Span>,
304 seen_representable: &FxHashSet<LocalDefId>,
305) {
306 match ty.kind {
307 hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
308 if let Res::Def(kind, def_id) = path.res
309 && #[allow(non_exhaustive_omitted_patterns)] match kind {
DefKind::Enum | DefKind::Struct | DefKind::Union => true,
_ => false,
}matches!(kind, DefKind::Enum | DefKind::Struct | DefKind::Union)
310 {
311 let check_params = def_id.as_local().is_none_or(|def_id| {
312 if def_id == needle {
313 spans.push(ty.span);
314 }
315 seen_representable.contains(&def_id)
316 });
317 if check_params && let Some(args) = path.segments.last().unwrap().args {
318 let params_in_repr = tcx.params_in_repr(def_id);
319 for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size())
321 {
322 if let hir::GenericArg::Type(ty) = arg
323 && params_in_repr.contains(i as u32)
324 {
325 find_item_ty_spans(
326 tcx,
327 ty.as_unambig_ty(),
328 needle,
329 spans,
330 seen_representable,
331 );
332 }
333 }
334 }
335 }
336 }
337 hir::TyKind::Array(ty, _) => find_item_ty_spans(tcx, ty, needle, spans, seen_representable),
338 hir::TyKind::Tup(tys) => {
339 tys.iter().for_each(|ty| find_item_ty_spans(tcx, ty, needle, spans, seen_representable))
340 }
341 _ => {}
342 }
343}
344
345#[inline(never)]
346#[cold]
347pub(crate) fn create_cycle_error<'tcx>(
348 tcx: TyCtxt<'tcx>,
349 Cycle { usage, frames }: &Cycle<'tcx>,
350 nested: bool,
351) -> Diag<'tcx> {
352 if !!frames.is_empty() {
::core::panicking::panic("assertion failed: !frames.is_empty()")
};assert!(!frames.is_empty());
353
354 let span = frames[0].tagged_key.catch_default_span(tcx, frames[1 % frames.len()].span);
355
356 let mut cycle_stack = Vec::new();
357
358 use crate::diagnostics::StackCount;
359 let stack_bottom = frames[0].tagged_key.catch_description(tcx);
360 let stack_count = if frames.len() == 1 {
361 StackCount::Single { stack_bottom: stack_bottom.clone() }
362 } else {
363 StackCount::Multiple { stack_bottom: stack_bottom.clone() }
364 };
365
366 let mut prev = span;
367 for i in 1..frames.len() {
368 let frame = &frames[i];
369 let span = frame.tagged_key.catch_default_span(tcx, frames[(i + 1) % frames.len()].span);
370 cycle_stack.push(crate::diagnostics::CycleStack {
371 span: if span == prev { DUMMY_SP } else { span },
372 desc: frame.tagged_key.catch_description(tcx),
373 });
374 prev = span;
375 }
376
377 let cycle_usage = usage.as_ref().map(|usage| {
378 let cycle_span = usage.tagged_key.catch_default_span(tcx, usage.span);
379 crate::diagnostics::CycleUsage {
380 span: if cycle_span != span { cycle_span } else { DUMMY_SP },
381 usage: usage.tagged_key.catch_description(tcx),
382 }
383 });
384
385 let is_all_def_kind = |def_kind| {
386 frames.iter().all(|frame| match frame.tagged_key {
389 TaggedQueryKey::type_of(def_id)
390 | TaggedQueryKey::explicit_implied_clauses_of(def_id)
391 if tcx.def_kind(def_id) == def_kind =>
392 {
393 true
394 }
395 _ => false,
396 })
397 };
398
399 let alias = if !nested {
400 if is_all_def_kind(DefKind::TyAlias) {
401 Some(crate::diagnostics::Alias::Ty)
402 } else if is_all_def_kind(DefKind::TraitAlias) {
403 Some(crate::diagnostics::Alias::Trait)
404 } else {
405 None
406 }
407 } else {
408 None
409 };
410
411 if nested {
412 tcx.sess.dcx().create_err(crate::diagnostics::NestedCycle {
413 span,
414 cycle_stack,
415 stack_bottom: crate::diagnostics::NestedCycleBottom { stack_bottom },
416 cycle_usage,
417 stack_count,
418 note_span: (),
419 })
420 } else {
421 tcx.sess.dcx().create_err(crate::diagnostics::Cycle {
422 span,
423 cycle_stack,
424 stack_bottom,
425 alias,
426 cycle_usage,
427 stack_count,
428 note_span: (),
429 })
430 }
431}