]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_middle/src/values.rs
New upstream version 1.73.0+dfsg1
[rustc.git] / compiler / rustc_middle / src / values.rs
CommitLineData
9c376795 1use crate::dep_graph::DepKind;
2b03887a
FG
2use rustc_data_structures::fx::FxHashSet;
3use rustc_errors::{pluralize, struct_span_err, Applicability, MultiSpan};
4use rustc_hir as hir;
9ffffee4 5use rustc_hir::def::{DefKind, Res};
2b03887a 6use rustc_middle::ty::Representability;
353b0b11 7use rustc_middle::ty::{self, Ty, TyCtxt};
2b03887a 8use rustc_query_system::query::QueryInfo;
f2b60f7d 9use rustc_query_system::Value;
2b03887a
FG
10use rustc_span::def_id::LocalDefId;
11use rustc_span::Span;
12
13use std::fmt::Write;
f2b60f7d 14
9c376795
FG
15impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Ty<'_> {
16 fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self {
f2b60f7d
FG
17 // SAFETY: This is never called when `Self` is not `Ty<'tcx>`.
18 // FIXME: Represent the above fact in the trait system somehow.
fe692bf9 19 unsafe { std::mem::transmute::<Ty<'tcx>, Ty<'_>>(Ty::new_misc_error(tcx)) }
f2b60f7d
FG
20 }
21}
22
9c376795
FG
23impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::SymbolName<'_> {
24 fn from_cycle_error(tcx: TyCtxt<'tcx>, _: &[QueryInfo<DepKind>]) -> Self {
f2b60f7d
FG
25 // SAFETY: This is never called when `Self` is not `SymbolName<'tcx>`.
26 // FIXME: Represent the above fact in the trait system somehow.
27 unsafe {
28 std::mem::transmute::<ty::SymbolName<'tcx>, ty::SymbolName<'_>>(ty::SymbolName::new(
29 tcx, "<error>",
30 ))
31 }
32 }
33}
34
9c376795
FG
35impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::Binder<'_, ty::FnSig<'_>> {
36 fn from_cycle_error(tcx: TyCtxt<'tcx>, stack: &[QueryInfo<DepKind>]) -> Self {
fe692bf9 37 let err = Ty::new_misc_error(tcx);
487cf647
FG
38
39 let arity = if let Some(frame) = stack.get(0)
9c376795 40 && frame.query.dep_kind == DepKind::fn_sig
487cf647
FG
41 && let Some(def_id) = frame.query.def_id
42 && let Some(node) = tcx.hir().get_if_local(def_id)
43 && let Some(sig) = node.fn_sig()
44 {
45 sig.decl.inputs.len() + sig.decl.implicit_self.has_implicit_self() as usize
46 } else {
47 tcx.sess.abort_if_errors();
48 unreachable!()
49 };
50
f2b60f7d 51 let fn_sig = ty::Binder::dummy(tcx.mk_fn_sig(
487cf647 52 std::iter::repeat(err).take(arity),
f2b60f7d
FG
53 err,
54 false,
55 rustc_hir::Unsafety::Normal,
56 rustc_target::spec::abi::Abi::Rust,
57 ));
58
59 // SAFETY: This is never called when `Self` is not `ty::Binder<'tcx, ty::FnSig<'tcx>>`.
60 // FIXME: Represent the above fact in the trait system somehow.
61 unsafe { std::mem::transmute::<ty::PolyFnSig<'tcx>, ty::Binder<'_, ty::FnSig<'_>>>(fn_sig) }
62 }
63}
2b03887a 64
9c376795
FG
65impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for Representability {
66 fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
2b03887a
FG
67 let mut item_and_field_ids = Vec::new();
68 let mut representable_ids = FxHashSet::default();
69 for info in cycle {
9c376795 70 if info.query.dep_kind == DepKind::representability
2b03887a
FG
71 && let Some(field_id) = info.query.def_id
72 && let Some(field_id) = field_id.as_local()
73 && let Some(DefKind::Field) = info.query.def_kind
74 {
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 info in cycle {
9c376795 84 if info.query.dep_kind == DepKind::representability_adt_ty
2b03887a
FG
85 && let Some(def_id) = info.query.ty_adt_id
86 && let Some(def_id) = def_id.as_local()
87 && !item_and_field_ids.iter().any(|&(id, _)| id == def_id)
88 {
89 representable_ids.insert(def_id);
90 }
91 }
92 recursive_type_error(tcx, item_and_field_ids, &representable_ids);
93 Representability::Infinite
94 }
95}
96
9c376795
FG
97impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<Ty<'_>> {
98 fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
fe692bf9 99 ty::EarlyBinder::bind(Ty::from_cycle_error(tcx, cycle))
9c376795
FG
100 }
101}
102
103impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::FnSig<'_>>> {
104 fn from_cycle_error(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> Self {
fe692bf9 105 ty::EarlyBinder::bind(ty::Binder::from_cycle_error(tcx, cycle))
9c376795
FG
106 }
107}
108
fe692bf9 109impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, &'_ ty::layout::LayoutError<'_>> {
49aad941 110 fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self {
fe692bf9
FG
111 // tcx.arena.alloc cannot be used because we are not allowed to use &'tcx LayoutError under
112 // min_specialization. Since this is an error path anyways, leaking doesn't matter (and really,
113 // tcx.arena.alloc is pretty much equal to leaking).
114 Err(Box::leak(Box::new(ty::layout::LayoutError::Cycle)))
49aad941
FG
115 }
116}
117
2b03887a
FG
118// item_and_field_ids should form a cycle where each field contains the
119// type in the next element in the list
120pub fn recursive_type_error(
121 tcx: TyCtxt<'_>,
122 mut item_and_field_ids: Vec<(LocalDefId, LocalDefId)>,
123 representable_ids: &FxHashSet<LocalDefId>,
124) {
125 const ITEM_LIMIT: usize = 5;
126
127 // Rotate the cycle so that the item with the lowest span is first
128 let start_index = item_and_field_ids
129 .iter()
130 .enumerate()
131 .min_by_key(|&(_, &(id, _))| tcx.def_span(id))
132 .unwrap()
133 .0;
134 item_and_field_ids.rotate_left(start_index);
135
136 let cycle_len = item_and_field_ids.len();
137 let show_cycle_len = cycle_len.min(ITEM_LIMIT);
138
139 let mut err_span = MultiSpan::from_spans(
140 item_and_field_ids[..show_cycle_len]
141 .iter()
142 .map(|(id, _)| tcx.def_span(id.to_def_id()))
143 .collect(),
144 );
145 let mut suggestion = Vec::with_capacity(show_cycle_len * 2);
146 for i in 0..show_cycle_len {
147 let (_, field_id) = item_and_field_ids[i];
148 let (next_item_id, _) = item_and_field_ids[(i + 1) % cycle_len];
149 // Find the span(s) that contain the next item in the cycle
150 let hir_id = tcx.hir().local_def_id_to_hir_id(field_id);
151 let hir::Node::Field(field) = tcx.hir().get(hir_id) else { bug!("expected field") };
152 let mut found = Vec::new();
153 find_item_ty_spans(tcx, field.ty, next_item_id, &mut found, representable_ids);
154
155 // Couldn't find the type. Maybe it's behind a type alias?
156 // In any case, we'll just suggest boxing the whole field.
157 if found.is_empty() {
158 found.push(field.ty.span);
159 }
160
161 for span in found {
162 err_span.push_span_label(span, "recursive without indirection");
163 // FIXME(compiler-errors): This suggestion might be erroneous if Box is shadowed
164 suggestion.push((span.shrink_to_lo(), "Box<".to_string()));
165 suggestion.push((span.shrink_to_hi(), ">".to_string()));
166 }
167 }
168 let items_list = {
169 let mut s = String::new();
49aad941
FG
170 for (i, &(item_id, _)) in item_and_field_ids.iter().enumerate() {
171 let path = tcx.def_path_str(item_id);
2b03887a
FG
172 write!(&mut s, "`{path}`").unwrap();
173 if i == (ITEM_LIMIT - 1) && cycle_len > ITEM_LIMIT {
174 write!(&mut s, " and {} more", cycle_len - 5).unwrap();
175 break;
176 }
177 if cycle_len > 1 && i < cycle_len - 2 {
178 s.push_str(", ");
179 } else if cycle_len > 1 && i == cycle_len - 2 {
180 s.push_str(" and ")
181 }
182 }
183 s
184 };
185 let mut err = struct_span_err!(
186 tcx.sess,
187 err_span,
188 E0072,
189 "recursive type{} {} {} infinite size",
190 pluralize!(cycle_len),
191 items_list,
192 pluralize!("has", cycle_len),
193 );
194 err.multipart_suggestion(
195 "insert some indirection (e.g., a `Box`, `Rc`, or `&`) to break the cycle",
196 suggestion,
197 Applicability::HasPlaceholders,
198 );
199 err.emit();
200}
201
202fn find_item_ty_spans(
203 tcx: TyCtxt<'_>,
204 ty: &hir::Ty<'_>,
205 needle: LocalDefId,
206 spans: &mut Vec<Span>,
207 seen_representable: &FxHashSet<LocalDefId>,
208) {
209 match ty.kind {
210 hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
9ffffee4 211 if let Res::Def(kind, def_id) = path.res
add651ee 212 && !matches!(kind, DefKind::TyAlias { .. }) {
2b03887a
FG
213 let check_params = def_id.as_local().map_or(true, |def_id| {
214 if def_id == needle {
215 spans.push(ty.span);
216 }
217 seen_representable.contains(&def_id)
218 });
219 if check_params && let Some(args) = path.segments.last().unwrap().args {
220 let params_in_repr = tcx.params_in_repr(def_id);
487cf647
FG
221 // the domain size check is needed because the HIR may not be well-formed at this point
222 for (i, arg) in args.args.iter().enumerate().take(params_in_repr.domain_size()) {
2b03887a
FG
223 if let hir::GenericArg::Type(ty) = arg && params_in_repr.contains(i as u32) {
224 find_item_ty_spans(tcx, ty, needle, spans, seen_representable);
225 }
226 }
227 }
228 }
229 }
230 hir::TyKind::Array(ty, _) => find_item_ty_spans(tcx, ty, needle, spans, seen_representable),
231 hir::TyKind::Tup(tys) => {
232 tys.iter().for_each(|ty| find_item_ty_spans(tcx, ty, needle, spans, seen_representable))
233 }
234 _ => {}
235 }
236}