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