]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ty_utils/src/representability.rs
Rollup merge of #93208 - kellerkindt:wrapping_int_assign_impl, r=m-ou-se
[rust.git] / compiler / rustc_ty_utils / src / representability.rs
1 //! Check whether a type is representable.
2 use rustc_data_structures::stable_map::FxHashMap;
3 use rustc_hir as hir;
4 use rustc_middle::ty::{self, Ty, TyCtxt};
5 use rustc_span::Span;
6 use std::cmp;
7
8 /// Describes whether a type is representable. For types that are not
9 /// representable, 'SelfRecursive' and 'ContainsRecursive' are used to
10 /// distinguish between types that are recursive with themselves and types that
11 /// contain a different recursive type. These cases can therefore be treated
12 /// differently when reporting errors.
13 ///
14 /// The ordering of the cases is significant. They are sorted so that cmp::max
15 /// will keep the "more erroneous" of two values.
16 #[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)]
17 pub enum Representability {
18     Representable,
19     ContainsRecursive,
20     SelfRecursive(Vec<Span>),
21 }
22
23 /// Check whether a type is representable. This means it cannot contain unboxed
24 /// structural recursion. This check is needed for structs and enums.
25 pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> Representability {
26     debug!("is_type_representable: {:?}", ty);
27     // To avoid a stack overflow when checking an enum variant or struct that
28     // contains a different, structurally recursive type, maintain a stack of
29     // seen types and check recursion for each of them (issues #3008, #3779,
30     // #74224, #84611). `shadow_seen` contains the full stack and `seen` only
31     // the one for the current type (e.g. if we have structs A and B, B contains
32     // a field of type A, and we're currently looking at B, then `seen` will be
33     // cleared when recursing to check A, but `shadow_seen` won't, so that we
34     // can catch cases of mutual recursion where A also contains B).
35     let mut seen: Vec<Ty<'_>> = Vec::new();
36     let mut shadow_seen: Vec<&'tcx ty::AdtDef> = Vec::new();
37     let mut representable_cache = FxHashMap::default();
38     let mut force_result = false;
39     let r = is_type_structurally_recursive(
40         tcx,
41         sp,
42         &mut seen,
43         &mut shadow_seen,
44         &mut representable_cache,
45         ty,
46         &mut force_result,
47     );
48     debug!("is_type_representable: {:?} is {:?}", ty, r);
49     r
50 }
51
52 // Iterate until something non-representable is found
53 fn fold_repr<It: Iterator<Item = Representability>>(iter: It) -> Representability {
54     iter.fold(Representability::Representable, |r1, r2| match (r1, r2) {
55         (Representability::SelfRecursive(v1), Representability::SelfRecursive(v2)) => {
56             Representability::SelfRecursive(v1.into_iter().chain(v2).collect())
57         }
58         (r1, r2) => cmp::max(r1, r2),
59     })
60 }
61
62 fn are_inner_types_recursive<'tcx>(
63     tcx: TyCtxt<'tcx>,
64     sp: Span,
65     seen: &mut Vec<Ty<'tcx>>,
66     shadow_seen: &mut Vec<&'tcx ty::AdtDef>,
67     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
68     ty: Ty<'tcx>,
69     force_result: &mut bool,
70 ) -> Representability {
71     debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen);
72     match ty.kind() {
73         ty::Tuple(..) => {
74             // Find non representable
75             fold_repr(ty.tuple_fields().map(|ty| {
76                 is_type_structurally_recursive(
77                     tcx,
78                     sp,
79                     seen,
80                     shadow_seen,
81                     representable_cache,
82                     ty,
83                     force_result,
84                 )
85             }))
86         }
87         // Fixed-length vectors.
88         // FIXME(#11924) Behavior undecided for zero-length vectors.
89         ty::Array(ty, _) => is_type_structurally_recursive(
90             tcx,
91             sp,
92             seen,
93             shadow_seen,
94             representable_cache,
95             ty,
96             force_result,
97         ),
98         ty::Adt(def, substs) => {
99             // Find non representable fields with their spans
100             fold_repr(def.all_fields().map(|field| {
101                 let ty = field.ty(tcx, substs);
102                 let span = match field.did.as_local().and_then(|id| tcx.hir().find_by_def_id(id)) {
103                     Some(hir::Node::Field(field)) => field.ty.span,
104                     _ => sp,
105                 };
106
107                 let mut result = None;
108
109                 // First, we check whether the field type per se is representable.
110                 // This catches cases as in #74224 and #84611. There is a special
111                 // case related to mutual recursion, though; consider this example:
112                 //
113                 //   struct A<T> {
114                 //       z: T,
115                 //       x: B<T>,
116                 //   }
117                 //
118                 //   struct B<T> {
119                 //       y: A<T>
120                 //   }
121                 //
122                 // Here, without the following special case, both A and B are
123                 // ContainsRecursive, which is a problem because we only report
124                 // errors for SelfRecursive. We fix this by detecting this special
125                 // case (shadow_seen.first() is the type we are originally
126                 // interested in, and if we ever encounter the same AdtDef again,
127                 // we know that it must be SelfRecursive) and "forcibly" returning
128                 // SelfRecursive (by setting force_result, which tells the calling
129                 // invocations of are_inner_types_representable to forward the
130                 // result without adjusting).
131                 if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) {
132                     *force_result = true;
133                     result = Some(Representability::SelfRecursive(vec![span]));
134                 }
135
136                 if result == None {
137                     result = Some(Representability::Representable);
138
139                     // Now, we check whether the field types per se are representable, e.g.
140                     // for struct Foo { x: Option<Foo> }, we first check whether Option<_>
141                     // by itself is representable (which it is), and the nesting of Foo
142                     // will be detected later. This is necessary for #74224 and #84611.
143
144                     // If we have encountered an ADT definition that we have not seen
145                     // before (no need to check them twice), recurse to see whether that
146                     // definition is SelfRecursive. If so, we must be ContainsRecursive.
147                     if shadow_seen.len() > 1
148                         && !shadow_seen
149                             .iter()
150                             .take(shadow_seen.len() - 1)
151                             .any(|seen_def| seen_def == def)
152                     {
153                         let adt_def_id = def.did;
154                         let raw_adt_ty = tcx.type_of(adt_def_id);
155                         debug!("are_inner_types_recursive: checking nested type: {:?}", raw_adt_ty);
156
157                         // Check independently whether the ADT is SelfRecursive. If so,
158                         // we must be ContainsRecursive (except for the special case
159                         // mentioned above).
160                         let mut nested_seen: Vec<Ty<'_>> = vec![];
161                         result = Some(
162                             match is_type_structurally_recursive(
163                                 tcx,
164                                 span,
165                                 &mut nested_seen,
166                                 shadow_seen,
167                                 representable_cache,
168                                 raw_adt_ty,
169                                 force_result,
170                             ) {
171                                 Representability::SelfRecursive(_) => {
172                                     if *force_result {
173                                         Representability::SelfRecursive(vec![span])
174                                     } else {
175                                         Representability::ContainsRecursive
176                                     }
177                                 }
178                                 x => x,
179                             },
180                         );
181                     }
182
183                     // We only enter the following block if the type looks representable
184                     // so far. This is necessary for cases such as this one (#74224):
185                     //
186                     //   struct A<T> {
187                     //       x: T,
188                     //       y: A<A<T>>,
189                     //   }
190                     //
191                     //   struct B {
192                     //       z: A<usize>
193                     //   }
194                     //
195                     // When checking B, we recurse into A and check field y of type
196                     // A<A<usize>>. We haven't seen this exact type before, so we recurse
197                     // into A<A<usize>>, which contains, A<A<A<usize>>>, and so forth,
198                     // ad infinitum. We can prevent this from happening by first checking
199                     // A separately (the code above) and only checking for nested Bs if
200                     // A actually looks representable (which it wouldn't in this example).
201                     if result == Some(Representability::Representable) {
202                         // Now, even if the type is representable (e.g. Option<_>),
203                         // it might still contribute to a recursive type, e.g.:
204                         //   struct Foo { x: Option<Option<Foo>> }
205                         // These cases are handled by passing the full `seen`
206                         // stack to is_type_structurally_recursive (instead of the
207                         // empty `nested_seen` above):
208                         result = Some(
209                             match is_type_structurally_recursive(
210                                 tcx,
211                                 span,
212                                 seen,
213                                 shadow_seen,
214                                 representable_cache,
215                                 ty,
216                                 force_result,
217                             ) {
218                                 Representability::SelfRecursive(_) => {
219                                     Representability::SelfRecursive(vec![span])
220                                 }
221                                 x => x,
222                             },
223                         );
224                     }
225                 }
226
227                 result.unwrap()
228             }))
229         }
230         ty::Closure(..) => {
231             // this check is run on type definitions, so we don't expect
232             // to see closure types
233             bug!("requires check invoked on inapplicable type: {:?}", ty)
234         }
235         _ => Representability::Representable,
236     }
237 }
238
239 fn same_adt<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool {
240     match *ty.kind() {
241         ty::Adt(ty_def, _) => ty_def == def,
242         _ => false,
243     }
244 }
245
246 // Does the type `ty` directly (without indirection through a pointer)
247 // contain any types on stack `seen`?
248 fn is_type_structurally_recursive<'tcx>(
249     tcx: TyCtxt<'tcx>,
250     sp: Span,
251     seen: &mut Vec<Ty<'tcx>>,
252     shadow_seen: &mut Vec<&'tcx ty::AdtDef>,
253     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
254     ty: Ty<'tcx>,
255     force_result: &mut bool,
256 ) -> Representability {
257     debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp);
258     if let Some(representability) = representable_cache.get(ty) {
259         debug!(
260             "is_type_structurally_recursive: {:?} {:?} - (cached) {:?}",
261             ty, sp, representability
262         );
263         return representability.clone();
264     }
265
266     let representability = is_type_structurally_recursive_inner(
267         tcx,
268         sp,
269         seen,
270         shadow_seen,
271         representable_cache,
272         ty,
273         force_result,
274     );
275
276     representable_cache.insert(ty, representability.clone());
277     representability
278 }
279
280 fn is_type_structurally_recursive_inner<'tcx>(
281     tcx: TyCtxt<'tcx>,
282     sp: Span,
283     seen: &mut Vec<Ty<'tcx>>,
284     shadow_seen: &mut Vec<&'tcx ty::AdtDef>,
285     representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>,
286     ty: Ty<'tcx>,
287     force_result: &mut bool,
288 ) -> Representability {
289     match ty.kind() {
290         ty::Adt(def, _) => {
291             {
292                 debug!("is_type_structurally_recursive_inner: adt: {:?}, seen: {:?}", ty, seen);
293
294                 // Iterate through stack of previously seen types.
295                 let mut iter = seen.iter();
296
297                 // The first item in `seen` is the type we are actually curious about.
298                 // We want to return SelfRecursive if this type contains itself.
299                 // It is important that we DON'T take generic parameters into account
300                 // for this check, so that Bar<T> in this example counts as SelfRecursive:
301                 //
302                 // struct Foo;
303                 // struct Bar<T> { x: Bar<Foo> }
304
305                 if let Some(&seen_adt) = iter.next() {
306                     if same_adt(seen_adt, *def) {
307                         debug!("SelfRecursive: {:?} contains {:?}", seen_adt, ty);
308                         return Representability::SelfRecursive(vec![sp]);
309                     }
310                 }
311
312                 // We also need to know whether the first item contains other types
313                 // that are structurally recursive. If we don't catch this case, we
314                 // will recurse infinitely for some inputs.
315                 //
316                 // It is important that we DO take generic parameters into account
317                 // here, because nesting e.g. Options is allowed (as long as the
318                 // definition of Option doesn't itself include an Option field, which
319                 // would be a case of SelfRecursive above). The following, too, counts
320                 // as SelfRecursive:
321                 //
322                 // struct Foo { Option<Option<Foo>> }
323
324                 for &seen_adt in iter {
325                     if ty == seen_adt {
326                         debug!("ContainsRecursive: {:?} contains {:?}", seen_adt, ty);
327                         return Representability::ContainsRecursive;
328                     }
329                 }
330             }
331
332             // For structs and enums, track all previously seen types by pushing them
333             // onto the 'seen' stack.
334             seen.push(ty);
335             shadow_seen.push(def);
336             let out = are_inner_types_recursive(
337                 tcx,
338                 sp,
339                 seen,
340                 shadow_seen,
341                 representable_cache,
342                 ty,
343                 force_result,
344             );
345             shadow_seen.pop();
346             seen.pop();
347             out
348         }
349         _ => {
350             // No need to push in other cases.
351             are_inner_types_recursive(
352                 tcx,
353                 sp,
354                 seen,
355                 shadow_seen,
356                 representable_cache,
357                 ty,
358                 force_result,
359             )
360         }
361     }
362 }