]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | //! Miscellaneous type-system utilities that are too small to deserve their own modules. |
2 | ||
3 | use crate::hir::def::Def; | |
4 | use crate::hir::def_id::DefId; | |
5 | use crate::hir::map::DefPathData; | |
6 | use crate::hir::{self, Node}; | |
7 | use crate::ich::NodeIdHashingMode; | |
8 | use crate::traits::{self, ObligationCause}; | |
9 | use crate::ty::{self, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; | |
10 | use crate::ty::subst::{Subst, Substs, UnpackedKind}; | |
11 | use crate::ty::query::TyCtxtAt; | |
12 | use crate::ty::TyKind::*; | |
13 | use crate::ty::layout::{Integer, IntegerExt}; | |
14 | use crate::util::common::ErrorReported; | |
15 | use crate::middle::lang_items; | |
54a0048b | 16 | |
94b46f34 | 17 | use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; |
0731742a | 18 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
0531ce1d | 19 | use std::{cmp, fmt}; |
83c7162d | 20 | use syntax::ast; |
a7813a04 | 21 | use syntax::attr::{self, SignedInt, UnsignedInt}; |
8bb4bdeb | 22 | use syntax_pos::{Span, DUMMY_SP}; |
e9174d1e | 23 | |
0531ce1d XL |
24 | #[derive(Copy, Clone, Debug)] |
25 | pub struct Discr<'tcx> { | |
9fa01778 | 26 | /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`). |
0531ce1d XL |
27 | pub val: u128, |
28 | pub ty: Ty<'tcx> | |
29 | } | |
8bb4bdeb | 30 | |
0531ce1d | 31 | impl<'tcx> fmt::Display for Discr<'tcx> { |
0bf4aa26 | 32 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
0531ce1d | 33 | match self.ty.sty { |
b7449926 | 34 | ty::Int(ity) => { |
0531ce1d | 35 | let bits = ty::tls::with(|tcx| { |
a1dfa0c6 | 36 | Integer::from_attr(&tcx, SignedInt(ity)).size().bits() |
0531ce1d XL |
37 | }); |
38 | let x = self.val as i128; | |
39 | // sign extend the raw representation to be an i128 | |
40 | let x = (x << (128 - bits)) >> (128 - bits); | |
41 | write!(fmt, "{}", x) | |
42 | }, | |
43 | _ => write!(fmt, "{}", self.val), | |
44 | } | |
45 | } | |
cc61c64b | 46 | } |
8bb4bdeb | 47 | |
0531ce1d | 48 | impl<'tcx> Discr<'tcx> { |
9fa01778 | 49 | /// Adds `1` to the value and wraps around if the maximum for the type is reached. |
0531ce1d XL |
50 | pub fn wrap_incr<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Self { |
51 | self.checked_add(tcx, 1).0 | |
52 | } | |
53 | pub fn checked_add<'a, 'gcx>(self, tcx: TyCtxt<'a, 'gcx, 'tcx>, n: u128) -> (Self, bool) { | |
54 | let (int, signed) = match self.ty.sty { | |
a1dfa0c6 XL |
55 | Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true), |
56 | Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false), | |
0531ce1d XL |
57 | _ => bug!("non integer discriminant"), |
58 | }; | |
8bb4bdeb | 59 | |
0531ce1d | 60 | let bit_size = int.size().bits(); |
94b46f34 | 61 | let shift = 128 - bit_size; |
0531ce1d XL |
62 | if signed { |
63 | let sext = |u| { | |
64 | let i = u as i128; | |
94b46f34 | 65 | (i << shift) >> shift |
0531ce1d XL |
66 | }; |
67 | let min = sext(1_u128 << (bit_size - 1)); | |
94b46f34 | 68 | let max = i128::max_value() >> shift; |
0531ce1d XL |
69 | let val = sext(self.val); |
70 | assert!(n < (i128::max_value() as u128)); | |
71 | let n = n as i128; | |
72 | let oflo = val > max - n; | |
73 | let val = if oflo { | |
74 | min + (n - (max - val) - 1) | |
75 | } else { | |
76 | val + n | |
77 | }; | |
78 | // zero the upper bits | |
79 | let val = val as u128; | |
94b46f34 | 80 | let val = (val << shift) >> shift; |
0531ce1d XL |
81 | (Self { |
82 | val: val as u128, | |
83 | ty: self.ty, | |
84 | }, oflo) | |
85 | } else { | |
94b46f34 | 86 | let max = u128::max_value() >> shift; |
0531ce1d XL |
87 | let val = self.val; |
88 | let oflo = val > max - n; | |
89 | let val = if oflo { | |
90 | n - (max - val) - 1 | |
91 | } else { | |
92 | val + n | |
93 | }; | |
94 | (Self { | |
95 | val: val, | |
96 | ty: self.ty, | |
97 | }, oflo) | |
8bb4bdeb XL |
98 | } |
99 | } | |
e9174d1e SL |
100 | } |
101 | ||
0531ce1d XL |
102 | pub trait IntTypeExt { |
103 | fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx>; | |
104 | fn disr_incr<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, val: Option<Discr<'tcx>>) | |
105 | -> Option<Discr<'tcx>>; | |
106 | fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx>; | |
107 | } | |
108 | ||
e9174d1e | 109 | impl IntTypeExt for attr::IntType { |
8bb4bdeb | 110 | fn to_ty<'a, 'gcx, 'tcx>(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> { |
e9174d1e | 111 | match *self { |
0bf4aa26 XL |
112 | SignedInt(ast::IntTy::I8) => tcx.types.i8, |
113 | SignedInt(ast::IntTy::I16) => tcx.types.i16, | |
114 | SignedInt(ast::IntTy::I32) => tcx.types.i32, | |
115 | SignedInt(ast::IntTy::I64) => tcx.types.i64, | |
32a655c1 | 116 | SignedInt(ast::IntTy::I128) => tcx.types.i128, |
0bf4aa26 | 117 | SignedInt(ast::IntTy::Isize) => tcx.types.isize, |
a7813a04 XL |
118 | UnsignedInt(ast::UintTy::U8) => tcx.types.u8, |
119 | UnsignedInt(ast::UintTy::U16) => tcx.types.u16, | |
120 | UnsignedInt(ast::UintTy::U32) => tcx.types.u32, | |
121 | UnsignedInt(ast::UintTy::U64) => tcx.types.u64, | |
0bf4aa26 | 122 | UnsignedInt(ast::UintTy::U128) => tcx.types.u128, |
2c00a5a8 | 123 | UnsignedInt(ast::UintTy::Usize) => tcx.types.usize, |
e9174d1e SL |
124 | } |
125 | } | |
126 | ||
0531ce1d XL |
127 | fn initial_discriminant<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> Discr<'tcx> { |
128 | Discr { | |
129 | val: 0, | |
130 | ty: self.to_ty(tcx) | |
e9174d1e SL |
131 | } |
132 | } | |
133 | ||
0531ce1d XL |
134 | fn disr_incr<'a, 'tcx>( |
135 | &self, | |
136 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
137 | val: Option<Discr<'tcx>>, | |
138 | ) -> Option<Discr<'tcx>> { | |
a7813a04 | 139 | if let Some(val) = val { |
0531ce1d XL |
140 | assert_eq!(self.to_ty(tcx), val.ty); |
141 | let (new, oflo) = val.checked_add(tcx, 1); | |
142 | if oflo { | |
143 | None | |
144 | } else { | |
145 | Some(new) | |
146 | } | |
a7813a04 XL |
147 | } else { |
148 | Some(self.initial_discriminant(tcx)) | |
149 | } | |
e9174d1e SL |
150 | } |
151 | } | |
152 | ||
153 | ||
94b46f34 | 154 | #[derive(Clone)] |
32a655c1 | 155 | pub enum CopyImplementationError<'tcx> { |
94b46f34 | 156 | InfrigingFields(Vec<&'tcx ty::FieldDef>), |
e9174d1e | 157 | NotAnAdt, |
cc61c64b | 158 | HasDestructor, |
e9174d1e SL |
159 | } |
160 | ||
161 | /// Describes whether a type is representable. For types that are not | |
162 | /// representable, 'SelfRecursive' and 'ContainsRecursive' are used to | |
163 | /// distinguish between types that are recursive with themselves and types that | |
164 | /// contain a different recursive type. These cases can therefore be treated | |
165 | /// differently when reporting errors. | |
166 | /// | |
167 | /// The ordering of the cases is significant. They are sorted so that cmp::max | |
168 | /// will keep the "more erroneous" of two values. | |
7cac9316 | 169 | #[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] |
e9174d1e SL |
170 | pub enum Representability { |
171 | Representable, | |
172 | ContainsRecursive, | |
7cac9316 | 173 | SelfRecursive(Vec<Span>), |
e9174d1e SL |
174 | } |
175 | ||
7cac9316 | 176 | impl<'tcx> ty::ParamEnv<'tcx> { |
7cac9316 XL |
177 | pub fn can_type_implement_copy<'a>(self, |
178 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
94b46f34 | 179 | self_type: Ty<'tcx>) |
7cac9316 | 180 | -> Result<(), CopyImplementationError<'tcx>> { |
e9174d1e | 181 | // FIXME: (@jroesch) float this code up |
041b39d2 | 182 | tcx.infer_ctxt().enter(|infcx| { |
32a655c1 | 183 | let (adt, substs) = match self_type.sty { |
83c7162d XL |
184 | // These types used to have a builtin impl. |
185 | // Now libcore provides that impl. | |
b7449926 XL |
186 | ty::Uint(_) | ty::Int(_) | ty::Bool | ty::Float(_) | |
187 | ty::Char | ty::RawPtr(..) | ty::Never | | |
188 | ty::Ref(_, _, hir::MutImmutable) => return Ok(()), | |
83c7162d | 189 | |
b7449926 | 190 | ty::Adt(adt, substs) => (adt, substs), |
83c7162d | 191 | |
cc61c64b | 192 | _ => return Err(CopyImplementationError::NotAnAdt), |
a7813a04 | 193 | }; |
e9174d1e | 194 | |
94b46f34 | 195 | let mut infringing = Vec::new(); |
32a655c1 SL |
196 | for variant in &adt.variants { |
197 | for field in &variant.fields { | |
94b46f34 XL |
198 | let ty = field.ty(tcx, substs); |
199 | if ty.references_error() { | |
200 | continue; | |
32a655c1 | 201 | } |
0bf4aa26 | 202 | let span = tcx.def_span(field.did); |
94b46f34 XL |
203 | let cause = ObligationCause { span, ..ObligationCause::dummy() }; |
204 | let ctx = traits::FulfillmentContext::new(); | |
205 | match traits::fully_normalize(&infcx, ctx, cause, self, &ty) { | |
0731742a | 206 | Ok(ty) => if !infcx.type_is_copy_modulo_regions(self, ty, span) { |
94b46f34 XL |
207 | infringing.push(field); |
208 | } | |
209 | Err(errors) => { | |
210 | infcx.report_fulfillment_errors(&errors, None, false); | |
211 | } | |
212 | }; | |
32a655c1 SL |
213 | } |
214 | } | |
94b46f34 XL |
215 | if !infringing.is_empty() { |
216 | return Err(CopyImplementationError::InfrigingFields(infringing)); | |
217 | } | |
8bb4bdeb | 218 | if adt.has_dtor(tcx) { |
a7813a04 XL |
219 | return Err(CopyImplementationError::HasDestructor); |
220 | } | |
e9174d1e | 221 | |
a7813a04 XL |
222 | Ok(()) |
223 | }) | |
e9174d1e SL |
224 | } |
225 | } | |
226 | ||
cc61c64b XL |
227 | impl<'a, 'tcx> TyCtxt<'a, 'tcx, 'tcx> { |
228 | /// Creates a hash of the type `Ty` which will be the same no matter what crate | |
229 | /// context it's calculated within. This is used by the `type_id` intrinsic. | |
230 | pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 { | |
231 | let mut hasher = StableHasher::new(); | |
ea8adc8c | 232 | let mut hcx = self.create_stable_hashing_context(); |
cc61c64b | 233 | |
3b2f2976 XL |
234 | // We want the type_id be independent of the types free regions, so we |
235 | // erase them. The erase_regions() call will also anonymize bound | |
236 | // regions, which is desirable too. | |
237 | let ty = self.erase_regions(&ty); | |
238 | ||
cc61c64b XL |
239 | hcx.while_hashing_spans(false, |hcx| { |
240 | hcx.with_node_id_hashing_mode(NodeIdHashingMode::HashDefPath, |hcx| { | |
241 | ty.hash_stable(hcx, &mut hasher); | |
242 | }); | |
243 | }); | |
244 | hasher.finish() | |
245 | } | |
246 | } | |
247 | ||
a7813a04 | 248 | impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> { |
5bcae85e | 249 | pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { |
0bf4aa26 XL |
250 | if let ty::Adt(def, substs) = ty.sty { |
251 | for field in def.all_fields() { | |
252 | let field_ty = field.ty(self, substs); | |
253 | if let Error = field_ty.sty { | |
254 | return true; | |
5bcae85e SL |
255 | } |
256 | } | |
5bcae85e SL |
257 | } |
258 | false | |
259 | } | |
260 | ||
e9174d1e SL |
261 | /// Returns the deeply last field of nested structures, or the same type, |
262 | /// if not a structure at all. Corresponds to the only possible unsized | |
263 | /// field, and its type can be used to determine unsizing strategy. | |
a7813a04 | 264 | pub fn struct_tail(self, mut ty: Ty<'tcx>) -> Ty<'tcx> { |
7cac9316 XL |
265 | loop { |
266 | match ty.sty { | |
b7449926 | 267 | ty::Adt(def, substs) => { |
7cac9316 XL |
268 | if !def.is_struct() { |
269 | break; | |
270 | } | |
2c00a5a8 | 271 | match def.non_enum_variant().fields.last() { |
7cac9316 XL |
272 | Some(f) => ty = f.ty(self, substs), |
273 | None => break, | |
274 | } | |
275 | } | |
276 | ||
b7449926 | 277 | ty::Tuple(tys) => { |
7cac9316 XL |
278 | if let Some((&last_ty, _)) = tys.split_last() { |
279 | ty = last_ty; | |
280 | } else { | |
281 | break; | |
282 | } | |
283 | } | |
284 | ||
285 | _ => { | |
286 | break; | |
287 | } | |
e9174d1e SL |
288 | } |
289 | } | |
290 | ty | |
291 | } | |
292 | ||
293 | /// Same as applying struct_tail on `source` and `target`, but only | |
294 | /// keeps going as long as the two types are instances of the same | |
295 | /// structure definitions. | |
a1dfa0c6 | 296 | /// For `(Foo<Foo<T>>, Foo<dyn Trait>)`, the result will be `(Foo<T>, Trait)`, |
e9174d1e | 297 | /// whereas struct_tail produces `T`, and `Trait`, respectively. |
a7813a04 | 298 | pub fn struct_lockstep_tails(self, |
e9174d1e SL |
299 | source: Ty<'tcx>, |
300 | target: Ty<'tcx>) | |
301 | -> (Ty<'tcx>, Ty<'tcx>) { | |
302 | let (mut a, mut b) = (source, target); | |
041b39d2 XL |
303 | loop { |
304 | match (&a.sty, &b.sty) { | |
b7449926 | 305 | (&Adt(a_def, a_substs), &Adt(b_def, b_substs)) |
041b39d2 | 306 | if a_def == b_def && a_def.is_struct() => { |
2c00a5a8 | 307 | if let Some(f) = a_def.non_enum_variant().fields.last() { |
041b39d2 XL |
308 | a = f.ty(self, a_substs); |
309 | b = f.ty(self, b_substs); | |
310 | } else { | |
311 | break; | |
312 | } | |
313 | }, | |
b7449926 | 314 | (&Tuple(a_tys), &Tuple(b_tys)) |
041b39d2 XL |
315 | if a_tys.len() == b_tys.len() => { |
316 | if let Some(a_last) = a_tys.last() { | |
317 | a = a_last; | |
318 | b = b_tys.last().unwrap(); | |
319 | } else { | |
320 | break; | |
321 | } | |
322 | }, | |
cc61c64b | 323 | _ => break, |
e9174d1e SL |
324 | } |
325 | } | |
326 | (a, b) | |
327 | } | |
328 | ||
e9174d1e SL |
329 | /// Given a set of predicates that apply to an object type, returns |
330 | /// the region bounds that the (erased) `Self` type must | |
331 | /// outlive. Precisely *because* the `Self` type is erased, the | |
332 | /// parameter `erased_self_ty` must be supplied to indicate what type | |
333 | /// has been used to represent `Self` in the predicates | |
334 | /// themselves. This should really be a unique type; `FreshTy(0)` is a | |
335 | /// popular choice. | |
336 | /// | |
0731742a | 337 | /// N.B., in some cases, particularly around higher-ranked bounds, |
e9174d1e SL |
338 | /// this function returns a kind of conservative approximation. |
339 | /// That is, all regions returned by this function are definitely | |
340 | /// required, but there may be other region bounds that are not | |
341 | /// returned, as well as requirements like `for<'a> T: 'a`. | |
342 | /// | |
343 | /// Requires that trait definitions have been processed so that we can | |
344 | /// elaborate predicates and walk supertraits. | |
9fa01778 XL |
345 | // |
346 | // FIXME: callers may only have a `&[Predicate]`, not a `Vec`, so that's | |
347 | // what this code should accept. | |
a7813a04 | 348 | pub fn required_region_bounds(self, |
e9174d1e SL |
349 | erased_self_ty: Ty<'tcx>, |
350 | predicates: Vec<ty::Predicate<'tcx>>) | |
7cac9316 | 351 | -> Vec<ty::Region<'tcx>> { |
e9174d1e SL |
352 | debug!("required_region_bounds(erased_self_ty={:?}, predicates={:?})", |
353 | erased_self_ty, | |
354 | predicates); | |
355 | ||
a1dfa0c6 | 356 | assert!(!erased_self_ty.has_escaping_bound_vars()); |
e9174d1e SL |
357 | |
358 | traits::elaborate_predicates(self, predicates) | |
359 | .filter_map(|predicate| { | |
360 | match predicate { | |
361 | ty::Predicate::Projection(..) | | |
362 | ty::Predicate::Trait(..) | | |
cc61c64b | 363 | ty::Predicate::Subtype(..) | |
e9174d1e SL |
364 | ty::Predicate::WellFormed(..) | |
365 | ty::Predicate::ObjectSafe(..) | | |
a7813a04 | 366 | ty::Predicate::ClosureKind(..) | |
ea8adc8c XL |
367 | ty::Predicate::RegionOutlives(..) | |
368 | ty::Predicate::ConstEvaluatable(..) => { | |
e9174d1e SL |
369 | None |
370 | } | |
83c7162d | 371 | ty::Predicate::TypeOutlives(predicate) => { |
e9174d1e SL |
372 | // Search for a bound of the form `erased_self_ty |
373 | // : 'a`, but be wary of something like `for<'a> | |
374 | // erased_self_ty : 'a` (we interpret a | |
375 | // higher-ranked bound like that as 'static, | |
376 | // though at present the code in `fulfill.rs` | |
377 | // considers such bounds to be unsatisfiable, so | |
378 | // it's kind of a moot point since you could never | |
379 | // construct such an object, but this seems | |
380 | // correct even if that code changes). | |
83c7162d | 381 | let ty::OutlivesPredicate(ref t, ref r) = predicate.skip_binder(); |
a1dfa0c6 | 382 | if t == &erased_self_ty && !r.has_escaping_bound_vars() { |
83c7162d | 383 | Some(*r) |
e9174d1e SL |
384 | } else { |
385 | None | |
386 | } | |
387 | } | |
388 | } | |
389 | }) | |
390 | .collect() | |
391 | } | |
392 | ||
8bb4bdeb XL |
393 | /// Calculate the destructor of a given type. |
394 | pub fn calculate_dtor( | |
395 | self, | |
396 | adt_did: DefId, | |
0531ce1d | 397 | validate: &mut dyn FnMut(Self, DefId) -> Result<(), ErrorReported> |
8bb4bdeb | 398 | ) -> Option<ty::Destructor> { |
ea8adc8c | 399 | let drop_trait = if let Some(def_id) = self.lang_items().drop_trait() { |
8bb4bdeb XL |
400 | def_id |
401 | } else { | |
402 | return None; | |
403 | }; | |
404 | ||
9fa01778 | 405 | self.ensure().coherent_trait(drop_trait); |
8bb4bdeb XL |
406 | |
407 | let mut dtor_did = None; | |
7cac9316 | 408 | let ty = self.type_of(adt_did); |
041b39d2 | 409 | self.for_each_relevant_impl(drop_trait, ty, |impl_did| { |
8bb4bdeb | 410 | if let Some(item) = self.associated_items(impl_did).next() { |
0bf4aa26 | 411 | if validate(self, impl_did).is_ok() { |
8bb4bdeb XL |
412 | dtor_did = Some(item.def_id); |
413 | } | |
414 | } | |
415 | }); | |
416 | ||
ff7c6d11 | 417 | Some(ty::Destructor { did: dtor_did? }) |
cc61c64b XL |
418 | } |
419 | ||
9fa01778 | 420 | /// Returns the set of types that are required to be alive in |
cc61c64b XL |
421 | /// order to run the destructor of `def` (see RFCs 769 and |
422 | /// 1238). | |
423 | /// | |
424 | /// Note that this returns only the constraints for the | |
425 | /// destructor of `def` itself. For the destructors of the | |
426 | /// contents, you need `adt_dtorck_constraint`. | |
427 | pub fn destructor_constraints(self, def: &'tcx ty::AdtDef) | |
428 | -> Vec<ty::subst::Kind<'tcx>> | |
429 | { | |
430 | let dtor = match def.destructor(self) { | |
431 | None => { | |
432 | debug!("destructor_constraints({:?}) - no dtor", def.did); | |
433 | return vec![] | |
434 | } | |
435 | Some(dtor) => dtor.did | |
e9174d1e | 436 | }; |
b039eaaf SL |
437 | |
438 | // RFC 1238: if the destructor method is tagged with the | |
439 | // attribute `unsafe_destructor_blind_to_params`, then the | |
440 | // compiler is being instructed to *assume* that the | |
441 | // destructor will not access borrowed data, | |
442 | // even if such data is otherwise reachable. | |
e9174d1e | 443 | // |
0731742a | 444 | // Such access can be in plain sight (e.g., dereferencing |
b039eaaf | 445 | // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden |
0731742a | 446 | // (e.g., calling `foo.0.clone()` of `Foo<T:Clone>`). |
cc61c64b XL |
447 | if self.has_attr(dtor, "unsafe_destructor_blind_to_params") { |
448 | debug!("destructor_constraint({:?}) - blind", def.did); | |
449 | return vec![]; | |
450 | } | |
451 | ||
452 | let impl_def_id = self.associated_item(dtor).container.id(); | |
7cac9316 | 453 | let impl_generics = self.generics_of(impl_def_id); |
cc61c64b XL |
454 | |
455 | // We have a destructor - all the parameters that are not | |
456 | // pure_wrt_drop (i.e, don't have a #[may_dangle] attribute) | |
457 | // must be live. | |
458 | ||
459 | // We need to return the list of parameters from the ADTs | |
460 | // generics/substs that correspond to impure parameters on the | |
461 | // impl's generics. This is a bit ugly, but conceptually simple: | |
462 | // | |
463 | // Suppose our ADT looks like the following | |
464 | // | |
465 | // struct S<X, Y, Z>(X, Y, Z); | |
466 | // | |
467 | // and the impl is | |
468 | // | |
469 | // impl<#[may_dangle] P0, P1, P2> Drop for S<P1, P2, P0> | |
470 | // | |
471 | // We want to return the parameters (X, Y). For that, we match | |
472 | // up the item-substs <X, Y, Z> with the substs on the impl ADT, | |
473 | // <P1, P2, P0>, and then look up which of the impl substs refer to | |
474 | // parameters marked as pure. | |
475 | ||
7cac9316 | 476 | let impl_substs = match self.type_of(impl_def_id).sty { |
b7449926 | 477 | ty::Adt(def_, substs) if def_ == def => substs, |
cc61c64b XL |
478 | _ => bug!() |
479 | }; | |
480 | ||
7cac9316 | 481 | let item_substs = match self.type_of(def.did).sty { |
b7449926 | 482 | ty::Adt(def_, substs) if def_ == def => substs, |
cc61c64b XL |
483 | _ => bug!() |
484 | }; | |
485 | ||
486 | let result = item_substs.iter().zip(impl_substs.iter()) | |
487 | .filter(|&(_, &k)| { | |
0531ce1d XL |
488 | match k.unpack() { |
489 | UnpackedKind::Lifetime(&ty::RegionKind::ReEarlyBound(ref ebr)) => { | |
490 | !impl_generics.region_param(ebr, self).pure_wrt_drop | |
491 | } | |
492 | UnpackedKind::Type(&ty::TyS { | |
b7449926 | 493 | sty: ty::Param(ref pt), .. |
0531ce1d XL |
494 | }) => { |
495 | !impl_generics.type_param(pt, self).pure_wrt_drop | |
496 | } | |
497 | UnpackedKind::Lifetime(_) | UnpackedKind::Type(_) => { | |
498 | // not a type or region param - this should be reported | |
499 | // as an error. | |
500 | false | |
501 | } | |
cc61c64b | 502 | } |
0bf4aa26 XL |
503 | }) |
504 | .map(|(&item_param, _)| item_param) | |
505 | .collect(); | |
cc61c64b XL |
506 | debug!("destructor_constraint({:?}) = {:?}", def.did, result); |
507 | result | |
b039eaaf | 508 | } |
9e0c209e | 509 | |
9fa01778 XL |
510 | /// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note |
511 | /// that closures have a `DefId`, but the closure *expression* also | |
8faf50e0 XL |
512 | /// has a `HirId` that is located within the context where the |
513 | /// closure appears (and, sadly, a corresponding `NodeId`, since | |
514 | /// those are not yet phased out). The parent of the closure's | |
9fa01778 | 515 | /// `DefId` will also be the context where it appears. |
abe05a73 XL |
516 | pub fn is_closure(self, def_id: DefId) -> bool { |
517 | self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr | |
518 | } | |
519 | ||
9fa01778 | 520 | /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). |
8faf50e0 XL |
521 | pub fn is_trait(self, def_id: DefId) -> bool { |
522 | if let DefPathData::Trait(_) = self.def_key(def_id).disambiguated_data.data { | |
523 | true | |
524 | } else { | |
525 | false | |
526 | } | |
527 | } | |
528 | ||
9fa01778 XL |
529 | /// Returns `true` if `def_id` refers to a trait alias (i.e., `trait Foo = ...;`), |
530 | /// and `false` otherwise. | |
531 | pub fn is_trait_alias(self, def_id: DefId) -> bool { | |
532 | if let DefPathData::TraitAlias(_) = self.def_key(def_id).disambiguated_data.data { | |
533 | true | |
534 | } else { | |
535 | false | |
536 | } | |
537 | } | |
538 | ||
539 | /// Returns `true` if this `DefId` refers to the implicit constructor for | |
540 | /// a tuple struct like `struct Foo(u32)`, and `false` otherwise. | |
8faf50e0 XL |
541 | pub fn is_struct_constructor(self, def_id: DefId) -> bool { |
542 | self.def_key(def_id).disambiguated_data.data == DefPathData::StructCtor | |
543 | } | |
544 | ||
ff7c6d11 XL |
545 | /// Given the `DefId` of a fn or closure, returns the `DefId` of |
546 | /// the innermost fn item that the closure is contained within. | |
9fa01778 | 547 | /// This is a significant `DefId` because, when we do |
ff7c6d11 | 548 | /// type-checking, we type-check this fn item and all of its |
9fa01778 | 549 | /// (transitive) closures together. Therefore, when we fetch the |
ff7c6d11 XL |
550 | /// `typeck_tables_of` the closure, for example, we really wind up |
551 | /// fetching the `typeck_tables_of` the enclosing fn item. | |
cc61c64b | 552 | pub fn closure_base_def_id(self, def_id: DefId) -> DefId { |
476ff2be | 553 | let mut def_id = def_id; |
abe05a73 | 554 | while self.is_closure(def_id) { |
476ff2be SL |
555 | def_id = self.parent_def_id(def_id).unwrap_or_else(|| { |
556 | bug!("closure {:?} has no parent", def_id); | |
557 | }); | |
558 | } | |
559 | def_id | |
9e0c209e | 560 | } |
cc61c64b | 561 | |
9fa01778 | 562 | /// Given the `DefId` and substs a closure, creates the type of |
ff7c6d11 XL |
563 | /// `self` argument that the closure expects. For example, for a |
564 | /// `Fn` closure, this would return a reference type `&T` where | |
9fa01778 | 565 | /// `T = closure_ty`. |
ff7c6d11 XL |
566 | /// |
567 | /// Returns `None` if this closure's kind has not yet been inferred. | |
568 | /// This should only be possible during type checking. | |
569 | /// | |
570 | /// Note that the return value is a late-bound region and hence | |
571 | /// wrapped in a binder. | |
572 | pub fn closure_env_ty(self, | |
573 | closure_def_id: DefId, | |
574 | closure_substs: ty::ClosureSubsts<'tcx>) | |
575 | -> Option<ty::Binder<Ty<'tcx>>> | |
576 | { | |
577 | let closure_ty = self.mk_closure(closure_def_id, closure_substs); | |
94b46f34 | 578 | let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv); |
ff7c6d11 XL |
579 | let closure_kind_ty = closure_substs.closure_kind_ty(closure_def_id, self); |
580 | let closure_kind = closure_kind_ty.to_opt_closure_kind()?; | |
581 | let env_ty = match closure_kind { | |
582 | ty::ClosureKind::Fn => self.mk_imm_ref(self.mk_region(env_region), closure_ty), | |
583 | ty::ClosureKind::FnMut => self.mk_mut_ref(self.mk_region(env_region), closure_ty), | |
584 | ty::ClosureKind::FnOnce => closure_ty, | |
585 | }; | |
83c7162d | 586 | Some(ty::Binder::bind(env_ty)) |
ff7c6d11 XL |
587 | } |
588 | ||
9fa01778 | 589 | /// Given the `DefId` of some item that has no type parameters, make |
cc61c64b | 590 | /// a suitable "empty substs" for it. |
94b46f34 XL |
591 | pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> &'tcx Substs<'tcx> { |
592 | Substs::for_item(self, item_def_id, |param, _| { | |
593 | match param.kind { | |
594 | GenericParamDefKind::Lifetime => self.types.re_erased.into(), | |
595 | GenericParamDefKind::Type {..} => { | |
596 | bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) | |
597 | } | |
598 | } | |
cc61c64b XL |
599 | }) |
600 | } | |
7cac9316 | 601 | |
9fa01778 | 602 | /// Returns `true` if the node pointed to by `def_id` is a static item, and its mutability. |
0531ce1d | 603 | pub fn is_static(&self, def_id: DefId) -> Option<hir::Mutability> { |
0731742a | 604 | if let Some(node) = self.hir().get_if_local(def_id) { |
abe05a73 | 605 | match node { |
b7449926 | 606 | Node::Item(&hir::Item { |
8faf50e0 | 607 | node: hir::ItemKind::Static(_, mutbl, _), .. |
0531ce1d | 608 | }) => Some(mutbl), |
b7449926 | 609 | Node::ForeignItem(&hir::ForeignItem { |
8faf50e0 | 610 | node: hir::ForeignItemKind::Static(_, is_mutbl), .. |
0531ce1d XL |
611 | }) => |
612 | Some(if is_mutbl { | |
613 | hir::Mutability::MutMutable | |
614 | } else { | |
615 | hir::Mutability::MutImmutable | |
616 | }), | |
617 | _ => None | |
abe05a73 XL |
618 | } |
619 | } else { | |
620 | match self.describe_def(def_id) { | |
0531ce1d XL |
621 | Some(Def::Static(_, is_mutbl)) => |
622 | Some(if is_mutbl { | |
623 | hir::Mutability::MutMutable | |
624 | } else { | |
625 | hir::Mutability::MutImmutable | |
626 | }), | |
627 | _ => None | |
abe05a73 XL |
628 | } |
629 | } | |
630 | } | |
0731742a XL |
631 | |
632 | /// Expands the given impl trait type, stopping if the type is recursive. | |
633 | pub fn try_expand_impl_trait_type( | |
634 | self, | |
635 | def_id: DefId, | |
636 | substs: &'tcx Substs<'tcx>, | |
637 | ) -> Result<Ty<'tcx>, Ty<'tcx>> { | |
638 | use crate::ty::fold::TypeFolder; | |
639 | ||
640 | struct OpaqueTypeExpander<'a, 'gcx, 'tcx> { | |
641 | // Contains the DefIds of the opaque types that are currently being | |
642 | // expanded. When we expand an opaque type we insert the DefId of | |
643 | // that type, and when we finish expanding that type we remove the | |
644 | // its DefId. | |
645 | seen_opaque_tys: FxHashSet<DefId>, | |
646 | primary_def_id: DefId, | |
647 | found_recursion: bool, | |
648 | tcx: TyCtxt<'a, 'gcx, 'tcx>, | |
649 | } | |
650 | ||
651 | impl<'a, 'gcx, 'tcx> OpaqueTypeExpander<'a, 'gcx, 'tcx> { | |
652 | fn expand_opaque_ty( | |
653 | &mut self, | |
654 | def_id: DefId, | |
655 | substs: &'tcx Substs<'tcx>, | |
656 | ) -> Option<Ty<'tcx>> { | |
657 | if self.found_recursion { | |
658 | None | |
659 | } else if self.seen_opaque_tys.insert(def_id) { | |
660 | let generic_ty = self.tcx.type_of(def_id); | |
661 | let concrete_ty = generic_ty.subst(self.tcx, substs); | |
662 | let expanded_ty = self.fold_ty(concrete_ty); | |
663 | self.seen_opaque_tys.remove(&def_id); | |
664 | Some(expanded_ty) | |
665 | } else { | |
666 | // If another opaque type that we contain is recursive, then it | |
667 | // will report the error, so we don't have to. | |
668 | self.found_recursion = def_id == self.primary_def_id; | |
669 | None | |
670 | } | |
671 | } | |
672 | } | |
673 | ||
674 | impl<'a, 'gcx, 'tcx> TypeFolder<'gcx, 'tcx> for OpaqueTypeExpander<'a, 'gcx, 'tcx> { | |
675 | fn tcx(&self) -> TyCtxt<'_, 'gcx, 'tcx> { | |
676 | self.tcx | |
677 | } | |
678 | ||
679 | fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { | |
680 | if let ty::Opaque(def_id, substs) = t.sty { | |
681 | self.expand_opaque_ty(def_id, substs).unwrap_or(t) | |
682 | } else { | |
683 | t.super_fold_with(self) | |
684 | } | |
685 | } | |
686 | } | |
687 | ||
688 | let mut visitor = OpaqueTypeExpander { | |
689 | seen_opaque_tys: FxHashSet::default(), | |
690 | primary_def_id: def_id, | |
691 | found_recursion: false, | |
692 | tcx: self, | |
693 | }; | |
694 | let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); | |
695 | if visitor.found_recursion { | |
696 | Err(expanded_type) | |
697 | } else { | |
698 | Ok(expanded_type) | |
699 | } | |
700 | } | |
9e0c209e SL |
701 | } |
702 | ||
a7813a04 | 703 | impl<'a, 'tcx> ty::TyS<'tcx> { |
0731742a XL |
704 | /// Checks whether values of this type `T` are *moved* or *copied* |
705 | /// when referenced -- this amounts to a check for whether `T: | |
706 | /// Copy`, but note that we **don't** consider lifetimes when | |
707 | /// doing this check. This means that we may generate MIR which | |
708 | /// does copies even when the type actually doesn't satisfy the | |
709 | /// full requirements for the `Copy` trait (cc #29149) -- this | |
710 | /// winds up being reported as an error during NLL borrow check. | |
711 | pub fn is_copy_modulo_regions(&'tcx self, | |
712 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
713 | param_env: ty::ParamEnv<'tcx>, | |
714 | span: Span) | |
715 | -> bool { | |
716 | tcx.at(span).is_copy_raw(param_env.and(self)) | |
e9174d1e SL |
717 | } |
718 | ||
0731742a XL |
719 | /// Checks whether values of this type `T` have a size known at |
720 | /// compile time (i.e., whether `T: Sized`). Lifetimes are ignored | |
721 | /// for the purposes of this check, so it can be an | |
722 | /// over-approximation in generic contexts, where one can have | |
723 | /// strange rules like `<T as Foo<'static>>::Bar: Sized` that | |
724 | /// actually carry lifetime requirements. | |
7cac9316 | 725 | pub fn is_sized(&'tcx self, |
0531ce1d XL |
726 | tcx_at: TyCtxtAt<'a, 'tcx, 'tcx>, |
727 | param_env: ty::ParamEnv<'tcx>)-> bool | |
e9174d1e | 728 | { |
0531ce1d | 729 | tcx_at.is_sized_raw(param_env.and(self)) |
e9174d1e SL |
730 | } |
731 | ||
0731742a XL |
732 | /// Checks whether values of this type `T` implement the `Freeze` |
733 | /// trait -- frozen types are those that do not contain a | |
9fa01778 | 734 | /// `UnsafeCell` anywhere. This is a language concept used to |
0731742a XL |
735 | /// distinguish "true immutability", which is relevant to |
736 | /// optimization as well as the rules around static values. Note | |
737 | /// that the `Freeze` trait is not exposed to end users and is | |
738 | /// effectively an implementation detail. | |
7cac9316 XL |
739 | pub fn is_freeze(&'tcx self, |
740 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
741 | param_env: ty::ParamEnv<'tcx>, | |
742 | span: Span)-> bool | |
cc61c64b | 743 | { |
7cac9316 | 744 | tcx.at(span).is_freeze_raw(param_env.and(self)) |
cc61c64b XL |
745 | } |
746 | ||
747 | /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely | |
748 | /// non-copy and *might* have a destructor attached; if it returns | |
0731742a | 749 | /// `false`, then `ty` definitely has no destructor (i.e., no drop glue). |
cc61c64b XL |
750 | /// |
751 | /// (Note that this implies that if `ty` has a destructor attached, | |
752 | /// then `needs_drop` will definitely return `true` for `ty`.) | |
753 | #[inline] | |
7cac9316 XL |
754 | pub fn needs_drop(&'tcx self, |
755 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
756 | param_env: ty::ParamEnv<'tcx>) | |
757 | -> bool { | |
9fa01778 | 758 | tcx.needs_drop_raw(param_env.and(self)).0 |
cc61c64b XL |
759 | } |
760 | ||
0731742a XL |
761 | pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { |
762 | match (&a.sty, &b.sty) { | |
763 | (&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => { | |
764 | if did_a != did_b { | |
765 | return false; | |
766 | } | |
767 | ||
768 | substs_a.types().zip(substs_b.types()).all(|(a, b)| Self::same_type(a, b)) | |
769 | } | |
770 | _ => a == b, | |
771 | } | |
772 | } | |
773 | ||
e9174d1e SL |
774 | /// Check whether a type is representable. This means it cannot contain unboxed |
775 | /// structural recursion. This check is needed for structs and enums. | |
7cac9316 XL |
776 | pub fn is_representable(&'tcx self, |
777 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
778 | sp: Span) | |
0bf4aa26 XL |
779 | -> Representability |
780 | { | |
e9174d1e | 781 | // Iterate until something non-representable is found |
7cac9316 XL |
782 | fn fold_repr<It: Iterator<Item=Representability>>(iter: It) -> Representability { |
783 | iter.fold(Representability::Representable, |r1, r2| { | |
784 | match (r1, r2) { | |
785 | (Representability::SelfRecursive(v1), | |
786 | Representability::SelfRecursive(v2)) => { | |
0bf4aa26 | 787 | Representability::SelfRecursive(v1.into_iter().chain(v2).collect()) |
7cac9316 XL |
788 | } |
789 | (r1, r2) => cmp::max(r1, r2) | |
790 | } | |
791 | }) | |
e9174d1e SL |
792 | } |
793 | ||
041b39d2 XL |
794 | fn are_inner_types_recursive<'a, 'tcx>( |
795 | tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, | |
796 | seen: &mut Vec<Ty<'tcx>>, | |
797 | representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>, | |
798 | ty: Ty<'tcx>) | |
799 | -> Representability | |
800 | { | |
e9174d1e | 801 | match ty.sty { |
b7449926 | 802 | Tuple(ref ts) => { |
7cac9316 XL |
803 | // Find non representable |
804 | fold_repr(ts.iter().map(|ty| { | |
041b39d2 | 805 | is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty) |
7cac9316 | 806 | })) |
e9174d1e SL |
807 | } |
808 | // Fixed-length vectors. | |
809 | // FIXME(#11924) Behavior undecided for zero-length vectors. | |
b7449926 | 810 | Array(ty, _) => { |
041b39d2 | 811 | is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty) |
e9174d1e | 812 | } |
b7449926 | 813 | Adt(def, substs) => { |
7cac9316 XL |
814 | // Find non representable fields with their spans |
815 | fold_repr(def.all_fields().map(|field| { | |
816 | let ty = field.ty(tcx, substs); | |
0731742a | 817 | let span = tcx.hir().span_if_local(field.did).unwrap_or(sp); |
041b39d2 XL |
818 | match is_type_structurally_recursive(tcx, span, seen, |
819 | representable_cache, ty) | |
820 | { | |
7cac9316 XL |
821 | Representability::SelfRecursive(_) => { |
822 | Representability::SelfRecursive(vec![span]) | |
823 | } | |
824 | x => x, | |
825 | } | |
826 | })) | |
e9174d1e | 827 | } |
b7449926 | 828 | Closure(..) => { |
e9174d1e SL |
829 | // this check is run on type definitions, so we don't expect |
830 | // to see closure types | |
54a0048b | 831 | bug!("requires check invoked on inapplicable type: {:?}", ty) |
e9174d1e SL |
832 | } |
833 | _ => Representability::Representable, | |
834 | } | |
835 | } | |
836 | ||
476ff2be | 837 | fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool { |
e9174d1e | 838 | match ty.sty { |
b7449926 | 839 | Adt(ty_def, _) => { |
e9174d1e SL |
840 | ty_def == def |
841 | } | |
842 | _ => false | |
843 | } | |
844 | } | |
845 | ||
e9174d1e SL |
846 | // Does the type `ty` directly (without indirection through a pointer) |
847 | // contain any types on stack `seen`? | |
041b39d2 XL |
848 | fn is_type_structurally_recursive<'a, 'tcx>( |
849 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
850 | sp: Span, | |
851 | seen: &mut Vec<Ty<'tcx>>, | |
852 | representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>, | |
853 | ty: Ty<'tcx>) -> Representability | |
854 | { | |
7cac9316 | 855 | debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp); |
041b39d2 XL |
856 | if let Some(representability) = representable_cache.get(ty) { |
857 | debug!("is_type_structurally_recursive: {:?} {:?} - (cached) {:?}", | |
858 | ty, sp, representability); | |
859 | return representability.clone(); | |
860 | } | |
861 | ||
862 | let representability = is_type_structurally_recursive_inner( | |
863 | tcx, sp, seen, representable_cache, ty); | |
864 | ||
865 | representable_cache.insert(ty, representability.clone()); | |
866 | representability | |
867 | } | |
e9174d1e | 868 | |
041b39d2 XL |
869 | fn is_type_structurally_recursive_inner<'a, 'tcx>( |
870 | tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
871 | sp: Span, | |
872 | seen: &mut Vec<Ty<'tcx>>, | |
873 | representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>, | |
874 | ty: Ty<'tcx>) -> Representability | |
875 | { | |
e9174d1e | 876 | match ty.sty { |
b7449926 | 877 | Adt(def, _) => { |
e9174d1e SL |
878 | { |
879 | // Iterate through stack of previously seen types. | |
880 | let mut iter = seen.iter(); | |
881 | ||
882 | // The first item in `seen` is the type we are actually curious about. | |
883 | // We want to return SelfRecursive if this type contains itself. | |
884 | // It is important that we DON'T take generic parameters into account | |
885 | // for this check, so that Bar<T> in this example counts as SelfRecursive: | |
886 | // | |
887 | // struct Foo; | |
888 | // struct Bar<T> { x: Bar<Foo> } | |
889 | ||
3157f602 XL |
890 | if let Some(&seen_type) = iter.next() { |
891 | if same_struct_or_enum(seen_type, def) { | |
892 | debug!("SelfRecursive: {:?} contains {:?}", | |
893 | seen_type, | |
894 | ty); | |
7cac9316 | 895 | return Representability::SelfRecursive(vec![sp]); |
e9174d1e | 896 | } |
e9174d1e SL |
897 | } |
898 | ||
899 | // We also need to know whether the first item contains other types | |
900 | // that are structurally recursive. If we don't catch this case, we | |
901 | // will recurse infinitely for some inputs. | |
902 | // | |
903 | // It is important that we DO take generic parameters into account | |
904 | // here, so that code like this is considered SelfRecursive, not | |
905 | // ContainsRecursive: | |
906 | // | |
907 | // struct Foo { Option<Option<Foo>> } | |
908 | ||
909 | for &seen_type in iter { | |
0731742a | 910 | if ty::TyS::same_type(ty, seen_type) { |
e9174d1e SL |
911 | debug!("ContainsRecursive: {:?} contains {:?}", |
912 | seen_type, | |
913 | ty); | |
914 | return Representability::ContainsRecursive; | |
915 | } | |
916 | } | |
917 | } | |
918 | ||
919 | // For structs and enums, track all previously seen types by pushing them | |
920 | // onto the 'seen' stack. | |
921 | seen.push(ty); | |
041b39d2 | 922 | let out = are_inner_types_recursive(tcx, sp, seen, representable_cache, ty); |
e9174d1e SL |
923 | seen.pop(); |
924 | out | |
925 | } | |
926 | _ => { | |
927 | // No need to push in other cases. | |
041b39d2 | 928 | are_inner_types_recursive(tcx, sp, seen, representable_cache, ty) |
e9174d1e SL |
929 | } |
930 | } | |
931 | } | |
932 | ||
933 | debug!("is_type_representable: {:?}", self); | |
934 | ||
935 | // To avoid a stack overflow when checking an enum variant or struct that | |
936 | // contains a different, structurally recursive type, maintain a stack | |
937 | // of seen types and check recursion for each of them (issues #3008, #3779). | |
0bf4aa26 XL |
938 | let mut seen: Vec<Ty<'_>> = Vec::new(); |
939 | let mut representable_cache = FxHashMap::default(); | |
041b39d2 XL |
940 | let r = is_type_structurally_recursive( |
941 | tcx, sp, &mut seen, &mut representable_cache, self); | |
e9174d1e SL |
942 | debug!("is_type_representable: {:?} is {:?}", self, r); |
943 | r | |
944 | } | |
945 | } | |
7cac9316 XL |
946 | |
947 | fn is_copy_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
948 | query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) | |
949 | -> bool | |
950 | { | |
951 | let (param_env, ty) = query.into_parts(); | |
952 | let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem); | |
041b39d2 | 953 | tcx.infer_ctxt() |
0731742a XL |
954 | .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( |
955 | &infcx, | |
956 | param_env, | |
957 | ty, | |
958 | trait_def_id, | |
959 | DUMMY_SP, | |
960 | )) | |
7cac9316 XL |
961 | } |
962 | ||
963 | fn is_sized_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
964 | query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) | |
965 | -> bool | |
966 | { | |
967 | let (param_env, ty) = query.into_parts(); | |
968 | let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem); | |
041b39d2 | 969 | tcx.infer_ctxt() |
0731742a XL |
970 | .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( |
971 | &infcx, | |
972 | param_env, | |
973 | ty, | |
974 | trait_def_id, | |
975 | DUMMY_SP, | |
976 | )) | |
7cac9316 XL |
977 | } |
978 | ||
979 | fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, | |
980 | query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) | |
981 | -> bool | |
982 | { | |
983 | let (param_env, ty) = query.into_parts(); | |
984 | let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem); | |
041b39d2 | 985 | tcx.infer_ctxt() |
0731742a XL |
986 | .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( |
987 | &infcx, | |
988 | param_env, | |
989 | ty, | |
990 | trait_def_id, | |
991 | DUMMY_SP, | |
992 | )) | |
7cac9316 XL |
993 | } |
994 | ||
9fa01778 XL |
995 | #[derive(Clone)] |
996 | pub struct NeedsDrop(pub bool); | |
997 | ||
7cac9316 XL |
998 | fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, |
999 | query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) | |
9fa01778 | 1000 | -> NeedsDrop |
7cac9316 XL |
1001 | { |
1002 | let (param_env, ty) = query.into_parts(); | |
1003 | ||
1004 | let needs_drop = |ty: Ty<'tcx>| -> bool { | |
9fa01778 | 1005 | tcx.needs_drop_raw(param_env.and(ty)).0 |
7cac9316 XL |
1006 | }; |
1007 | ||
1008 | assert!(!ty.needs_infer()); | |
1009 | ||
9fa01778 | 1010 | NeedsDrop(match ty.sty { |
7cac9316 | 1011 | // Fast-path for primitive types |
b7449926 XL |
1012 | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) | |
1013 | ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never | | |
1014 | ty::FnDef(..) | ty::FnPtr(_) | ty::Char | ty::GeneratorWitness(..) | | |
1015 | ty::RawPtr(_) | ty::Ref(..) | ty::Str => false, | |
7cac9316 | 1016 | |
abe05a73 | 1017 | // Foreign types can never have destructors |
b7449926 | 1018 | ty::Foreign(..) => false, |
abe05a73 | 1019 | |
8faf50e0 | 1020 | // `ManuallyDrop` doesn't have a destructor regardless of field types. |
b7449926 | 1021 | ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false, |
8faf50e0 | 1022 | |
0731742a | 1023 | // Issue #22536: We first query `is_copy_modulo_regions`. It sees a |
7cac9316 XL |
1024 | // normalized version of the type, and therefore will definitely |
1025 | // know whether the type implements Copy (and thus needs no | |
1026 | // cleanup/drop/zeroing) ... | |
0731742a | 1027 | _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false, |
7cac9316 XL |
1028 | |
1029 | // ... (issue #22536 continued) but as an optimization, still use | |
1030 | // prior logic of asking for the structural "may drop". | |
1031 | ||
1032 | // FIXME(#22815): Note that this is a conservative heuristic; | |
1033 | // it may report that the type "may drop" when actual type does | |
1034 | // not actually have a destructor associated with it. But since | |
1035 | // the type absolutely did not have the `Copy` bound attached | |
1036 | // (see above), it is sound to treat it as having a destructor. | |
1037 | ||
1038 | // User destructors are the only way to have concrete drop types. | |
b7449926 | 1039 | ty::Adt(def, _) if def.has_dtor(tcx) => true, |
7cac9316 XL |
1040 | |
1041 | // Can refer to a type which may drop. | |
1042 | // FIXME(eddyb) check this against a ParamEnv. | |
a1dfa0c6 XL |
1043 | ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) | ty::Bound(..) | |
1044 | ty::Placeholder(..) | ty::Opaque(..) | ty::Infer(_) | ty::Error => true, | |
7cac9316 | 1045 | |
0bf4aa26 XL |
1046 | ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), |
1047 | ||
7cac9316 | 1048 | // Structural recursion. |
b7449926 | 1049 | ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty), |
7cac9316 | 1050 | |
b7449926 | 1051 | ty::Closure(def_id, ref substs) => substs.upvar_tys(def_id, tcx).any(needs_drop), |
7cac9316 | 1052 | |
ea8adc8c XL |
1053 | // Pessimistically assume that all generators will require destructors |
1054 | // as we don't know if a destructor is a noop or not until after the MIR | |
1055 | // state transformation pass | |
b7449926 | 1056 | ty::Generator(..) => true, |
ea8adc8c | 1057 | |
b7449926 | 1058 | ty::Tuple(ref tys) => tys.iter().cloned().any(needs_drop), |
7cac9316 | 1059 | |
8faf50e0 XL |
1060 | // unions don't have destructors because of the child types, |
1061 | // only if they manually implement `Drop` (handled above). | |
b7449926 | 1062 | ty::Adt(def, _) if def.is_union() => false, |
7cac9316 | 1063 | |
b7449926 | 1064 | ty::Adt(def, substs) => |
7cac9316 XL |
1065 | def.variants.iter().any( |
1066 | |variant| variant.fields.iter().any( | |
1067 | |field| needs_drop(field.ty(tcx, substs)))), | |
9fa01778 | 1068 | }) |
7cac9316 XL |
1069 | } |
1070 | ||
abe05a73 XL |
1071 | pub enum ExplicitSelf<'tcx> { |
1072 | ByValue, | |
1073 | ByReference(ty::Region<'tcx>, hir::Mutability), | |
ff7c6d11 | 1074 | ByRawPointer(hir::Mutability), |
abe05a73 XL |
1075 | ByBox, |
1076 | Other | |
1077 | } | |
1078 | ||
1079 | impl<'tcx> ExplicitSelf<'tcx> { | |
1080 | /// Categorizes an explicit self declaration like `self: SomeType` | |
1081 | /// into either `self`, `&self`, `&mut self`, `Box<self>`, or | |
1082 | /// `Other`. | |
1083 | /// This is mainly used to require the arbitrary_self_types feature | |
1084 | /// in the case of `Other`, to improve error messages in the common cases, | |
1085 | /// and to make `Other` non-object-safe. | |
1086 | /// | |
1087 | /// Examples: | |
1088 | /// | |
1089 | /// ``` | |
1090 | /// impl<'a> Foo for &'a T { | |
1091 | /// // Legal declarations: | |
1092 | /// fn method1(self: &&'a T); // ExplicitSelf::ByReference | |
1093 | /// fn method2(self: &'a T); // ExplicitSelf::ByValue | |
1094 | /// fn method3(self: Box<&'a T>); // ExplicitSelf::ByBox | |
1095 | /// fn method4(self: Rc<&'a T>); // ExplicitSelf::Other | |
1096 | /// | |
1097 | /// // Invalid cases will be caught by `check_method_receiver`: | |
1098 | /// fn method_err1(self: &'a mut T); // ExplicitSelf::Other | |
1099 | /// fn method_err2(self: &'static T) // ExplicitSelf::ByValue | |
1100 | /// fn method_err3(self: &&T) // ExplicitSelf::ByReference | |
1101 | /// } | |
1102 | /// ``` | |
1103 | /// | |
1104 | pub fn determine<P>( | |
1105 | self_arg_ty: Ty<'tcx>, | |
1106 | is_self_ty: P | |
1107 | ) -> ExplicitSelf<'tcx> | |
1108 | where | |
1109 | P: Fn(Ty<'tcx>) -> bool | |
1110 | { | |
1111 | use self::ExplicitSelf::*; | |
1112 | ||
1113 | match self_arg_ty.sty { | |
1114 | _ if is_self_ty(self_arg_ty) => ByValue, | |
b7449926 | 1115 | ty::Ref(region, ty, mutbl) if is_self_ty(ty) => { |
abe05a73 XL |
1116 | ByReference(region, mutbl) |
1117 | } | |
b7449926 | 1118 | ty::RawPtr(ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => { |
ff7c6d11 XL |
1119 | ByRawPointer(mutbl) |
1120 | } | |
b7449926 | 1121 | ty::Adt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => { |
ff7c6d11 XL |
1122 | ByBox |
1123 | } | |
abe05a73 XL |
1124 | _ => Other |
1125 | } | |
1126 | } | |
1127 | } | |
1128 | ||
0bf4aa26 | 1129 | pub fn provide(providers: &mut ty::query::Providers<'_>) { |
94b46f34 | 1130 | *providers = ty::query::Providers { |
7cac9316 XL |
1131 | is_copy_raw, |
1132 | is_sized_raw, | |
1133 | is_freeze_raw, | |
1134 | needs_drop_raw, | |
7cac9316 XL |
1135 | ..*providers |
1136 | }; | |
1137 | } |