]>
Commit | Line | Data |
---|---|---|
9fa01778 XL |
1 | //! Miscellaneous type-system utilities that are too small to deserve their own modules. |
2 | ||
48663c56 XL |
3 | use crate::hir; |
4 | use crate::hir::def::DefKind; | |
9fa01778 XL |
5 | use crate::hir::def_id::DefId; |
6 | use crate::hir::map::DefPathData; | |
532ac7d7 | 7 | use crate::mir::interpret::{sign_extend, truncate}; |
9fa01778 XL |
8 | use crate::ich::NodeIdHashingMode; |
9 | use crate::traits::{self, ObligationCause}; | |
532ac7d7 XL |
10 | use crate::ty::{self, DefIdTree, Ty, TyCtxt, GenericParamDefKind, TypeFoldable}; |
11 | use crate::ty::subst::{Subst, InternalSubsts, SubstsRef, UnpackedKind}; | |
9fa01778 XL |
12 | use crate::ty::query::TyCtxtAt; |
13 | use crate::ty::TyKind::*; | |
14 | use crate::ty::layout::{Integer, IntegerExt}; | |
532ac7d7 | 15 | use crate::mir::interpret::ConstValue; |
9fa01778 XL |
16 | use crate::util::common::ErrorReported; |
17 | use crate::middle::lang_items; | |
54a0048b | 18 | |
94b46f34 | 19 | use rustc_data_structures::stable_hasher::{StableHasher, HashStable}; |
0731742a | 20 | use rustc_data_structures::fx::{FxHashMap, FxHashSet}; |
532ac7d7 | 21 | use rustc_macros::HashStable; |
0531ce1d | 22 | use std::{cmp, fmt}; |
83c7162d | 23 | use syntax::ast; |
a7813a04 | 24 | use syntax::attr::{self, SignedInt, UnsignedInt}; |
48663c56 | 25 | use syntax::symbol::sym; |
8bb4bdeb | 26 | use syntax_pos::{Span, DUMMY_SP}; |
e9174d1e | 27 | |
0531ce1d XL |
28 | #[derive(Copy, Clone, Debug)] |
29 | pub struct Discr<'tcx> { | |
9fa01778 | 30 | /// Bit representation of the discriminant (e.g., `-128i8` is `0xFF_u128`). |
0531ce1d XL |
31 | pub val: u128, |
32 | pub ty: Ty<'tcx> | |
33 | } | |
8bb4bdeb | 34 | |
0531ce1d | 35 | impl<'tcx> fmt::Display for Discr<'tcx> { |
0bf4aa26 | 36 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
0531ce1d | 37 | match self.ty.sty { |
b7449926 | 38 | ty::Int(ity) => { |
532ac7d7 XL |
39 | let size = ty::tls::with(|tcx| { |
40 | Integer::from_attr(&tcx, SignedInt(ity)).size() | |
0531ce1d | 41 | }); |
532ac7d7 | 42 | let x = self.val; |
0531ce1d | 43 | // sign extend the raw representation to be an i128 |
532ac7d7 | 44 | let x = sign_extend(x, size) as i128; |
0531ce1d XL |
45 | write!(fmt, "{}", x) |
46 | }, | |
47 | _ => write!(fmt, "{}", self.val), | |
48 | } | |
49 | } | |
cc61c64b | 50 | } |
8bb4bdeb | 51 | |
0531ce1d | 52 | impl<'tcx> Discr<'tcx> { |
9fa01778 | 53 | /// Adds `1` to the value and wraps around if the maximum for the type is reached. |
dc9dc135 | 54 | pub fn wrap_incr(self, tcx: TyCtxt<'tcx>) -> Self { |
0531ce1d XL |
55 | self.checked_add(tcx, 1).0 |
56 | } | |
dc9dc135 | 57 | pub fn checked_add(self, tcx: TyCtxt<'tcx>, n: u128) -> (Self, bool) { |
0531ce1d | 58 | let (int, signed) = match self.ty.sty { |
a1dfa0c6 XL |
59 | Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true), |
60 | Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false), | |
0531ce1d XL |
61 | _ => bug!("non integer discriminant"), |
62 | }; | |
8bb4bdeb | 63 | |
532ac7d7 | 64 | let size = int.size(); |
0531ce1d | 65 | let bit_size = int.size().bits(); |
94b46f34 | 66 | let shift = 128 - bit_size; |
0531ce1d XL |
67 | if signed { |
68 | let sext = |u| { | |
532ac7d7 | 69 | sign_extend(u, size) as i128 |
0531ce1d XL |
70 | }; |
71 | let min = sext(1_u128 << (bit_size - 1)); | |
94b46f34 | 72 | let max = i128::max_value() >> shift; |
0531ce1d XL |
73 | let val = sext(self.val); |
74 | assert!(n < (i128::max_value() as u128)); | |
75 | let n = n as i128; | |
76 | let oflo = val > max - n; | |
77 | let val = if oflo { | |
78 | min + (n - (max - val) - 1) | |
79 | } else { | |
80 | val + n | |
81 | }; | |
82 | // zero the upper bits | |
83 | let val = val as u128; | |
532ac7d7 | 84 | let val = truncate(val, size); |
0531ce1d XL |
85 | (Self { |
86 | val: val as u128, | |
87 | ty: self.ty, | |
88 | }, oflo) | |
89 | } else { | |
94b46f34 | 90 | let max = u128::max_value() >> shift; |
0531ce1d XL |
91 | let val = self.val; |
92 | let oflo = val > max - n; | |
93 | let val = if oflo { | |
94 | n - (max - val) - 1 | |
95 | } else { | |
96 | val + n | |
97 | }; | |
98 | (Self { | |
99 | val: val, | |
100 | ty: self.ty, | |
101 | }, oflo) | |
8bb4bdeb XL |
102 | } |
103 | } | |
e9174d1e SL |
104 | } |
105 | ||
0531ce1d | 106 | pub trait IntTypeExt { |
dc9dc135 XL |
107 | fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>; |
108 | fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option<Discr<'tcx>>; | |
109 | fn initial_discriminant<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Discr<'tcx>; | |
0531ce1d XL |
110 | } |
111 | ||
e9174d1e | 112 | impl IntTypeExt for attr::IntType { |
dc9dc135 | 113 | fn to_ty<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { |
e9174d1e | 114 | match *self { |
0bf4aa26 XL |
115 | SignedInt(ast::IntTy::I8) => tcx.types.i8, |
116 | SignedInt(ast::IntTy::I16) => tcx.types.i16, | |
117 | SignedInt(ast::IntTy::I32) => tcx.types.i32, | |
118 | SignedInt(ast::IntTy::I64) => tcx.types.i64, | |
32a655c1 | 119 | SignedInt(ast::IntTy::I128) => tcx.types.i128, |
0bf4aa26 | 120 | SignedInt(ast::IntTy::Isize) => tcx.types.isize, |
a7813a04 XL |
121 | UnsignedInt(ast::UintTy::U8) => tcx.types.u8, |
122 | UnsignedInt(ast::UintTy::U16) => tcx.types.u16, | |
123 | UnsignedInt(ast::UintTy::U32) => tcx.types.u32, | |
124 | UnsignedInt(ast::UintTy::U64) => tcx.types.u64, | |
0bf4aa26 | 125 | UnsignedInt(ast::UintTy::U128) => tcx.types.u128, |
2c00a5a8 | 126 | UnsignedInt(ast::UintTy::Usize) => tcx.types.usize, |
e9174d1e SL |
127 | } |
128 | } | |
129 | ||
dc9dc135 | 130 | fn initial_discriminant<'tcx>(&self, tcx: TyCtxt<'tcx>) -> Discr<'tcx> { |
0531ce1d XL |
131 | Discr { |
132 | val: 0, | |
133 | ty: self.to_ty(tcx) | |
e9174d1e SL |
134 | } |
135 | } | |
136 | ||
dc9dc135 | 137 | fn disr_incr<'tcx>(&self, tcx: TyCtxt<'tcx>, val: Option<Discr<'tcx>>) -> Option<Discr<'tcx>> { |
a7813a04 | 138 | if let Some(val) = val { |
0531ce1d XL |
139 | assert_eq!(self.to_ty(tcx), val.ty); |
140 | let (new, oflo) = val.checked_add(tcx, 1); | |
141 | if oflo { | |
142 | None | |
143 | } else { | |
144 | Some(new) | |
145 | } | |
a7813a04 XL |
146 | } else { |
147 | Some(self.initial_discriminant(tcx)) | |
148 | } | |
e9174d1e SL |
149 | } |
150 | } | |
151 | ||
152 | ||
94b46f34 | 153 | #[derive(Clone)] |
32a655c1 | 154 | pub enum CopyImplementationError<'tcx> { |
94b46f34 | 155 | InfrigingFields(Vec<&'tcx ty::FieldDef>), |
e9174d1e | 156 | NotAnAdt, |
cc61c64b | 157 | HasDestructor, |
e9174d1e SL |
158 | } |
159 | ||
160 | /// Describes whether a type is representable. For types that are not | |
161 | /// representable, 'SelfRecursive' and 'ContainsRecursive' are used to | |
162 | /// distinguish between types that are recursive with themselves and types that | |
163 | /// contain a different recursive type. These cases can therefore be treated | |
164 | /// differently when reporting errors. | |
165 | /// | |
166 | /// The ordering of the cases is significant. They are sorted so that cmp::max | |
167 | /// will keep the "more erroneous" of two values. | |
7cac9316 | 168 | #[derive(Clone, PartialOrd, Ord, Eq, PartialEq, Debug)] |
e9174d1e SL |
169 | pub enum Representability { |
170 | Representable, | |
171 | ContainsRecursive, | |
7cac9316 | 172 | SelfRecursive(Vec<Span>), |
e9174d1e SL |
173 | } |
174 | ||
7cac9316 | 175 | impl<'tcx> ty::ParamEnv<'tcx> { |
dc9dc135 XL |
176 | pub fn can_type_implement_copy( |
177 | self, | |
178 | tcx: TyCtxt<'tcx>, | |
179 | self_type: Ty<'tcx>, | |
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 | ||
dc9dc135 | 227 | impl<'tcx> TyCtxt<'tcx> { |
cc61c64b XL |
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 | ||
dc9dc135 | 248 | impl<'tcx> TyCtxt<'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 | 278 | if let Some((&last_ty, _)) = tys.split_last() { |
48663c56 | 279 | ty = last_ty.expect_ty(); |
7cac9316 XL |
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() { | |
48663c56 XL |
317 | a = a_last.expect_ty(); |
318 | b = b_tys.last().unwrap().expect_ty(); | |
041b39d2 XL |
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>`). |
48663c56 | 447 | if self.has_attr(dtor, sym::unsafe_destructor_blind_to_params) { |
cc61c64b XL |
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 | } | |
532ac7d7 XL |
497 | UnpackedKind::Const(&ty::Const { |
498 | val: ConstValue::Param(ref pc), | |
499 | .. | |
500 | }) => { | |
501 | !impl_generics.const_param(pc, self).pure_wrt_drop | |
502 | } | |
503 | UnpackedKind::Lifetime(_) | | |
504 | UnpackedKind::Type(_) | | |
505 | UnpackedKind::Const(_) => { | |
506 | // Not a type, const or region param: this should be reported | |
0531ce1d XL |
507 | // as an error. |
508 | false | |
509 | } | |
cc61c64b | 510 | } |
0bf4aa26 XL |
511 | }) |
512 | .map(|(&item_param, _)| item_param) | |
513 | .collect(); | |
cc61c64b XL |
514 | debug!("destructor_constraint({:?}) = {:?}", def.did, result); |
515 | result | |
b039eaaf | 516 | } |
9e0c209e | 517 | |
9fa01778 XL |
518 | /// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note |
519 | /// that closures have a `DefId`, but the closure *expression* also | |
8faf50e0 XL |
520 | /// has a `HirId` that is located within the context where the |
521 | /// closure appears (and, sadly, a corresponding `NodeId`, since | |
522 | /// those are not yet phased out). The parent of the closure's | |
9fa01778 | 523 | /// `DefId` will also be the context where it appears. |
abe05a73 XL |
524 | pub fn is_closure(self, def_id: DefId) -> bool { |
525 | self.def_key(def_id).disambiguated_data.data == DefPathData::ClosureExpr | |
526 | } | |
527 | ||
9fa01778 | 528 | /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). |
8faf50e0 | 529 | pub fn is_trait(self, def_id: DefId) -> bool { |
48663c56 | 530 | self.def_kind(def_id) == Some(DefKind::Trait) |
8faf50e0 XL |
531 | } |
532 | ||
9fa01778 XL |
533 | /// Returns `true` if `def_id` refers to a trait alias (i.e., `trait Foo = ...;`), |
534 | /// and `false` otherwise. | |
535 | pub fn is_trait_alias(self, def_id: DefId) -> bool { | |
48663c56 | 536 | self.def_kind(def_id) == Some(DefKind::TraitAlias) |
9fa01778 XL |
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. | |
532ac7d7 XL |
541 | pub fn is_constructor(self, def_id: DefId) -> bool { |
542 | self.def_key(def_id).disambiguated_data.data == DefPathData::Ctor | |
8faf50e0 XL |
543 | } |
544 | ||
dc9dc135 | 545 | /// Given the def-ID of a fn or closure, returns the def-ID of |
ff7c6d11 | 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) { |
532ac7d7 | 555 | def_id = self.parent(def_id).unwrap_or_else(|| { |
476ff2be SL |
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 | ||
532ac7d7 | 589 | /// Given the `DefId` of some item that has no type or const parameters, make |
cc61c64b | 590 | /// a suitable "empty substs" for it. |
532ac7d7 XL |
591 | pub fn empty_substs_for_def_id(self, item_def_id: DefId) -> SubstsRef<'tcx> { |
592 | InternalSubsts::for_item(self, item_def_id, |param, _| { | |
94b46f34 | 593 | match param.kind { |
48663c56 | 594 | GenericParamDefKind::Lifetime => self.lifetimes.re_erased.into(), |
532ac7d7 | 595 | GenericParamDefKind::Type { .. } => { |
94b46f34 XL |
596 | bug!("empty_substs_for_def_id: {:?} has type parameters", item_def_id) |
597 | } | |
532ac7d7 XL |
598 | GenericParamDefKind::Const { .. } => { |
599 | bug!("empty_substs_for_def_id: {:?} has const parameters", item_def_id) | |
600 | } | |
94b46f34 | 601 | } |
cc61c64b XL |
602 | }) |
603 | } | |
7cac9316 | 604 | |
48663c56 XL |
605 | /// Returns `true` if the node pointed to by `def_id` is a `static` item. |
606 | pub fn is_static(&self, def_id: DefId) -> bool { | |
607 | self.static_mutability(def_id).is_some() | |
608 | } | |
609 | ||
610 | /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item. | |
611 | pub fn is_mutable_static(&self, def_id: DefId) -> bool { | |
612 | self.static_mutability(def_id) == Some(hir::MutMutable) | |
abe05a73 | 613 | } |
0731742a XL |
614 | |
615 | /// Expands the given impl trait type, stopping if the type is recursive. | |
616 | pub fn try_expand_impl_trait_type( | |
617 | self, | |
618 | def_id: DefId, | |
532ac7d7 | 619 | substs: SubstsRef<'tcx>, |
0731742a XL |
620 | ) -> Result<Ty<'tcx>, Ty<'tcx>> { |
621 | use crate::ty::fold::TypeFolder; | |
622 | ||
dc9dc135 | 623 | struct OpaqueTypeExpander<'tcx> { |
0731742a XL |
624 | // Contains the DefIds of the opaque types that are currently being |
625 | // expanded. When we expand an opaque type we insert the DefId of | |
626 | // that type, and when we finish expanding that type we remove the | |
627 | // its DefId. | |
628 | seen_opaque_tys: FxHashSet<DefId>, | |
629 | primary_def_id: DefId, | |
630 | found_recursion: bool, | |
dc9dc135 | 631 | tcx: TyCtxt<'tcx>, |
0731742a XL |
632 | } |
633 | ||
dc9dc135 | 634 | impl<'tcx> OpaqueTypeExpander<'tcx> { |
0731742a XL |
635 | fn expand_opaque_ty( |
636 | &mut self, | |
637 | def_id: DefId, | |
532ac7d7 | 638 | substs: SubstsRef<'tcx>, |
0731742a XL |
639 | ) -> Option<Ty<'tcx>> { |
640 | if self.found_recursion { | |
641 | None | |
642 | } else if self.seen_opaque_tys.insert(def_id) { | |
643 | let generic_ty = self.tcx.type_of(def_id); | |
644 | let concrete_ty = generic_ty.subst(self.tcx, substs); | |
645 | let expanded_ty = self.fold_ty(concrete_ty); | |
646 | self.seen_opaque_tys.remove(&def_id); | |
647 | Some(expanded_ty) | |
648 | } else { | |
649 | // If another opaque type that we contain is recursive, then it | |
650 | // will report the error, so we don't have to. | |
651 | self.found_recursion = def_id == self.primary_def_id; | |
652 | None | |
653 | } | |
654 | } | |
655 | } | |
656 | ||
dc9dc135 XL |
657 | impl<'tcx> TypeFolder<'tcx> for OpaqueTypeExpander<'tcx> { |
658 | fn tcx(&self) -> TyCtxt<'tcx> { | |
0731742a XL |
659 | self.tcx |
660 | } | |
661 | ||
662 | fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { | |
663 | if let ty::Opaque(def_id, substs) = t.sty { | |
664 | self.expand_opaque_ty(def_id, substs).unwrap_or(t) | |
665 | } else { | |
666 | t.super_fold_with(self) | |
667 | } | |
668 | } | |
669 | } | |
670 | ||
671 | let mut visitor = OpaqueTypeExpander { | |
672 | seen_opaque_tys: FxHashSet::default(), | |
673 | primary_def_id: def_id, | |
674 | found_recursion: false, | |
675 | tcx: self, | |
676 | }; | |
677 | let expanded_type = visitor.expand_opaque_ty(def_id, substs).unwrap(); | |
678 | if visitor.found_recursion { | |
679 | Err(expanded_type) | |
680 | } else { | |
681 | Ok(expanded_type) | |
682 | } | |
683 | } | |
9e0c209e SL |
684 | } |
685 | ||
dc9dc135 | 686 | impl<'tcx> ty::TyS<'tcx> { |
0731742a XL |
687 | /// Checks whether values of this type `T` are *moved* or *copied* |
688 | /// when referenced -- this amounts to a check for whether `T: | |
689 | /// Copy`, but note that we **don't** consider lifetimes when | |
690 | /// doing this check. This means that we may generate MIR which | |
691 | /// does copies even when the type actually doesn't satisfy the | |
692 | /// full requirements for the `Copy` trait (cc #29149) -- this | |
693 | /// winds up being reported as an error during NLL borrow check. | |
dc9dc135 XL |
694 | pub fn is_copy_modulo_regions( |
695 | &'tcx self, | |
696 | tcx: TyCtxt<'tcx>, | |
697 | param_env: ty::ParamEnv<'tcx>, | |
698 | span: Span, | |
699 | ) -> bool { | |
0731742a | 700 | tcx.at(span).is_copy_raw(param_env.and(self)) |
e9174d1e SL |
701 | } |
702 | ||
0731742a XL |
703 | /// Checks whether values of this type `T` have a size known at |
704 | /// compile time (i.e., whether `T: Sized`). Lifetimes are ignored | |
705 | /// for the purposes of this check, so it can be an | |
706 | /// over-approximation in generic contexts, where one can have | |
707 | /// strange rules like `<T as Foo<'static>>::Bar: Sized` that | |
708 | /// actually carry lifetime requirements. | |
dc9dc135 | 709 | pub fn is_sized(&'tcx self, tcx_at: TyCtxtAt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { |
0531ce1d | 710 | tcx_at.is_sized_raw(param_env.and(self)) |
e9174d1e SL |
711 | } |
712 | ||
0731742a XL |
713 | /// Checks whether values of this type `T` implement the `Freeze` |
714 | /// trait -- frozen types are those that do not contain a | |
9fa01778 | 715 | /// `UnsafeCell` anywhere. This is a language concept used to |
0731742a XL |
716 | /// distinguish "true immutability", which is relevant to |
717 | /// optimization as well as the rules around static values. Note | |
718 | /// that the `Freeze` trait is not exposed to end users and is | |
719 | /// effectively an implementation detail. | |
dc9dc135 XL |
720 | pub fn is_freeze( |
721 | &'tcx self, | |
722 | tcx: TyCtxt<'tcx>, | |
723 | param_env: ty::ParamEnv<'tcx>, | |
724 | span: Span, | |
725 | ) -> bool { | |
7cac9316 | 726 | tcx.at(span).is_freeze_raw(param_env.and(self)) |
cc61c64b XL |
727 | } |
728 | ||
729 | /// If `ty.needs_drop(...)` returns `true`, then `ty` is definitely | |
730 | /// non-copy and *might* have a destructor attached; if it returns | |
0731742a | 731 | /// `false`, then `ty` definitely has no destructor (i.e., no drop glue). |
cc61c64b XL |
732 | /// |
733 | /// (Note that this implies that if `ty` has a destructor attached, | |
734 | /// then `needs_drop` will definitely return `true` for `ty`.) | |
735 | #[inline] | |
dc9dc135 | 736 | pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool { |
9fa01778 | 737 | tcx.needs_drop_raw(param_env.and(self)).0 |
cc61c64b XL |
738 | } |
739 | ||
0731742a XL |
740 | pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { |
741 | match (&a.sty, &b.sty) { | |
742 | (&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => { | |
743 | if did_a != did_b { | |
744 | return false; | |
745 | } | |
746 | ||
747 | substs_a.types().zip(substs_b.types()).all(|(a, b)| Self::same_type(a, b)) | |
748 | } | |
749 | _ => a == b, | |
750 | } | |
751 | } | |
752 | ||
e9174d1e SL |
753 | /// Check whether a type is representable. This means it cannot contain unboxed |
754 | /// structural recursion. This check is needed for structs and enums. | |
dc9dc135 | 755 | pub fn is_representable(&'tcx self, tcx: TyCtxt<'tcx>, sp: Span) -> Representability { |
e9174d1e | 756 | // Iterate until something non-representable is found |
7cac9316 XL |
757 | fn fold_repr<It: Iterator<Item=Representability>>(iter: It) -> Representability { |
758 | iter.fold(Representability::Representable, |r1, r2| { | |
759 | match (r1, r2) { | |
760 | (Representability::SelfRecursive(v1), | |
761 | Representability::SelfRecursive(v2)) => { | |
0bf4aa26 | 762 | Representability::SelfRecursive(v1.into_iter().chain(v2).collect()) |
7cac9316 XL |
763 | } |
764 | (r1, r2) => cmp::max(r1, r2) | |
765 | } | |
766 | }) | |
e9174d1e SL |
767 | } |
768 | ||
dc9dc135 XL |
769 | fn are_inner_types_recursive<'tcx>( |
770 | tcx: TyCtxt<'tcx>, | |
771 | sp: Span, | |
041b39d2 XL |
772 | seen: &mut Vec<Ty<'tcx>>, |
773 | representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>, | |
dc9dc135 XL |
774 | ty: Ty<'tcx>, |
775 | ) -> Representability { | |
e9174d1e | 776 | match ty.sty { |
b7449926 | 777 | Tuple(ref ts) => { |
7cac9316 XL |
778 | // Find non representable |
779 | fold_repr(ts.iter().map(|ty| { | |
48663c56 XL |
780 | is_type_structurally_recursive( |
781 | tcx, | |
782 | sp, | |
783 | seen, | |
784 | representable_cache, | |
785 | ty.expect_ty(), | |
786 | ) | |
7cac9316 | 787 | })) |
e9174d1e SL |
788 | } |
789 | // Fixed-length vectors. | |
790 | // FIXME(#11924) Behavior undecided for zero-length vectors. | |
b7449926 | 791 | Array(ty, _) => { |
041b39d2 | 792 | is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty) |
e9174d1e | 793 | } |
b7449926 | 794 | Adt(def, substs) => { |
7cac9316 XL |
795 | // Find non representable fields with their spans |
796 | fold_repr(def.all_fields().map(|field| { | |
797 | let ty = field.ty(tcx, substs); | |
0731742a | 798 | let span = tcx.hir().span_if_local(field.did).unwrap_or(sp); |
041b39d2 XL |
799 | match is_type_structurally_recursive(tcx, span, seen, |
800 | representable_cache, ty) | |
801 | { | |
7cac9316 XL |
802 | Representability::SelfRecursive(_) => { |
803 | Representability::SelfRecursive(vec![span]) | |
804 | } | |
805 | x => x, | |
806 | } | |
807 | })) | |
e9174d1e | 808 | } |
b7449926 | 809 | Closure(..) => { |
e9174d1e SL |
810 | // this check is run on type definitions, so we don't expect |
811 | // to see closure types | |
54a0048b | 812 | bug!("requires check invoked on inapplicable type: {:?}", ty) |
e9174d1e SL |
813 | } |
814 | _ => Representability::Representable, | |
815 | } | |
816 | } | |
817 | ||
476ff2be | 818 | fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool { |
e9174d1e | 819 | match ty.sty { |
b7449926 | 820 | Adt(ty_def, _) => { |
e9174d1e SL |
821 | ty_def == def |
822 | } | |
823 | _ => false | |
824 | } | |
825 | } | |
826 | ||
e9174d1e SL |
827 | // Does the type `ty` directly (without indirection through a pointer) |
828 | // contain any types on stack `seen`? | |
dc9dc135 XL |
829 | fn is_type_structurally_recursive<'tcx>( |
830 | tcx: TyCtxt<'tcx>, | |
041b39d2 XL |
831 | sp: Span, |
832 | seen: &mut Vec<Ty<'tcx>>, | |
833 | representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>, | |
dc9dc135 XL |
834 | ty: Ty<'tcx>, |
835 | ) -> Representability { | |
7cac9316 | 836 | debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp); |
041b39d2 XL |
837 | if let Some(representability) = representable_cache.get(ty) { |
838 | debug!("is_type_structurally_recursive: {:?} {:?} - (cached) {:?}", | |
839 | ty, sp, representability); | |
840 | return representability.clone(); | |
841 | } | |
842 | ||
843 | let representability = is_type_structurally_recursive_inner( | |
844 | tcx, sp, seen, representable_cache, ty); | |
845 | ||
846 | representable_cache.insert(ty, representability.clone()); | |
847 | representability | |
848 | } | |
e9174d1e | 849 | |
dc9dc135 XL |
850 | fn is_type_structurally_recursive_inner<'tcx>( |
851 | tcx: TyCtxt<'tcx>, | |
041b39d2 XL |
852 | sp: Span, |
853 | seen: &mut Vec<Ty<'tcx>>, | |
854 | representable_cache: &mut FxHashMap<Ty<'tcx>, Representability>, | |
dc9dc135 XL |
855 | ty: Ty<'tcx>, |
856 | ) -> Representability { | |
e9174d1e | 857 | match ty.sty { |
b7449926 | 858 | Adt(def, _) => { |
e9174d1e SL |
859 | { |
860 | // Iterate through stack of previously seen types. | |
861 | let mut iter = seen.iter(); | |
862 | ||
863 | // The first item in `seen` is the type we are actually curious about. | |
864 | // We want to return SelfRecursive if this type contains itself. | |
865 | // It is important that we DON'T take generic parameters into account | |
866 | // for this check, so that Bar<T> in this example counts as SelfRecursive: | |
867 | // | |
868 | // struct Foo; | |
869 | // struct Bar<T> { x: Bar<Foo> } | |
870 | ||
3157f602 XL |
871 | if let Some(&seen_type) = iter.next() { |
872 | if same_struct_or_enum(seen_type, def) { | |
873 | debug!("SelfRecursive: {:?} contains {:?}", | |
874 | seen_type, | |
875 | ty); | |
7cac9316 | 876 | return Representability::SelfRecursive(vec![sp]); |
e9174d1e | 877 | } |
e9174d1e SL |
878 | } |
879 | ||
880 | // We also need to know whether the first item contains other types | |
881 | // that are structurally recursive. If we don't catch this case, we | |
882 | // will recurse infinitely for some inputs. | |
883 | // | |
884 | // It is important that we DO take generic parameters into account | |
885 | // here, so that code like this is considered SelfRecursive, not | |
886 | // ContainsRecursive: | |
887 | // | |
888 | // struct Foo { Option<Option<Foo>> } | |
889 | ||
890 | for &seen_type in iter { | |
0731742a | 891 | if ty::TyS::same_type(ty, seen_type) { |
e9174d1e SL |
892 | debug!("ContainsRecursive: {:?} contains {:?}", |
893 | seen_type, | |
894 | ty); | |
895 | return Representability::ContainsRecursive; | |
896 | } | |
897 | } | |
898 | } | |
899 | ||
900 | // For structs and enums, track all previously seen types by pushing them | |
901 | // onto the 'seen' stack. | |
902 | seen.push(ty); | |
041b39d2 | 903 | let out = are_inner_types_recursive(tcx, sp, seen, representable_cache, ty); |
e9174d1e SL |
904 | seen.pop(); |
905 | out | |
906 | } | |
907 | _ => { | |
908 | // No need to push in other cases. | |
041b39d2 | 909 | are_inner_types_recursive(tcx, sp, seen, representable_cache, ty) |
e9174d1e SL |
910 | } |
911 | } | |
912 | } | |
913 | ||
914 | debug!("is_type_representable: {:?}", self); | |
915 | ||
916 | // To avoid a stack overflow when checking an enum variant or struct that | |
917 | // contains a different, structurally recursive type, maintain a stack | |
918 | // of seen types and check recursion for each of them (issues #3008, #3779). | |
0bf4aa26 XL |
919 | let mut seen: Vec<Ty<'_>> = Vec::new(); |
920 | let mut representable_cache = FxHashMap::default(); | |
041b39d2 XL |
921 | let r = is_type_structurally_recursive( |
922 | tcx, sp, &mut seen, &mut representable_cache, self); | |
e9174d1e SL |
923 | debug!("is_type_representable: {:?} is {:?}", self, r); |
924 | r | |
925 | } | |
926 | } | |
7cac9316 | 927 | |
dc9dc135 | 928 | fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { |
7cac9316 XL |
929 | let (param_env, ty) = query.into_parts(); |
930 | let trait_def_id = tcx.require_lang_item(lang_items::CopyTraitLangItem); | |
041b39d2 | 931 | tcx.infer_ctxt() |
0731742a XL |
932 | .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( |
933 | &infcx, | |
934 | param_env, | |
935 | ty, | |
936 | trait_def_id, | |
937 | DUMMY_SP, | |
938 | )) | |
7cac9316 XL |
939 | } |
940 | ||
dc9dc135 | 941 | fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { |
7cac9316 XL |
942 | let (param_env, ty) = query.into_parts(); |
943 | let trait_def_id = tcx.require_lang_item(lang_items::SizedTraitLangItem); | |
041b39d2 | 944 | tcx.infer_ctxt() |
0731742a XL |
945 | .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( |
946 | &infcx, | |
947 | param_env, | |
948 | ty, | |
949 | trait_def_id, | |
950 | DUMMY_SP, | |
951 | )) | |
7cac9316 XL |
952 | } |
953 | ||
dc9dc135 | 954 | fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool { |
7cac9316 XL |
955 | let (param_env, ty) = query.into_parts(); |
956 | let trait_def_id = tcx.require_lang_item(lang_items::FreezeTraitLangItem); | |
041b39d2 | 957 | tcx.infer_ctxt() |
0731742a XL |
958 | .enter(|infcx| traits::type_known_to_meet_bound_modulo_regions( |
959 | &infcx, | |
960 | param_env, | |
961 | ty, | |
962 | trait_def_id, | |
963 | DUMMY_SP, | |
964 | )) | |
7cac9316 XL |
965 | } |
966 | ||
532ac7d7 | 967 | #[derive(Clone, HashStable)] |
9fa01778 XL |
968 | pub struct NeedsDrop(pub bool); |
969 | ||
dc9dc135 | 970 | fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop { |
7cac9316 XL |
971 | let (param_env, ty) = query.into_parts(); |
972 | ||
973 | let needs_drop = |ty: Ty<'tcx>| -> bool { | |
9fa01778 | 974 | tcx.needs_drop_raw(param_env.and(ty)).0 |
7cac9316 XL |
975 | }; |
976 | ||
977 | assert!(!ty.needs_infer()); | |
978 | ||
9fa01778 | 979 | NeedsDrop(match ty.sty { |
7cac9316 | 980 | // Fast-path for primitive types |
b7449926 XL |
981 | ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) | |
982 | ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never | | |
983 | ty::FnDef(..) | ty::FnPtr(_) | ty::Char | ty::GeneratorWitness(..) | | |
984 | ty::RawPtr(_) | ty::Ref(..) | ty::Str => false, | |
7cac9316 | 985 | |
abe05a73 | 986 | // Foreign types can never have destructors |
b7449926 | 987 | ty::Foreign(..) => false, |
abe05a73 | 988 | |
8faf50e0 | 989 | // `ManuallyDrop` doesn't have a destructor regardless of field types. |
b7449926 | 990 | ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false, |
8faf50e0 | 991 | |
0731742a | 992 | // Issue #22536: We first query `is_copy_modulo_regions`. It sees a |
7cac9316 XL |
993 | // normalized version of the type, and therefore will definitely |
994 | // know whether the type implements Copy (and thus needs no | |
995 | // cleanup/drop/zeroing) ... | |
0731742a | 996 | _ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false, |
7cac9316 XL |
997 | |
998 | // ... (issue #22536 continued) but as an optimization, still use | |
999 | // prior logic of asking for the structural "may drop". | |
1000 | ||
1001 | // FIXME(#22815): Note that this is a conservative heuristic; | |
1002 | // it may report that the type "may drop" when actual type does | |
1003 | // not actually have a destructor associated with it. But since | |
1004 | // the type absolutely did not have the `Copy` bound attached | |
1005 | // (see above), it is sound to treat it as having a destructor. | |
1006 | ||
1007 | // User destructors are the only way to have concrete drop types. | |
b7449926 | 1008 | ty::Adt(def, _) if def.has_dtor(tcx) => true, |
7cac9316 XL |
1009 | |
1010 | // Can refer to a type which may drop. | |
1011 | // FIXME(eddyb) check this against a ParamEnv. | |
a1dfa0c6 XL |
1012 | ty::Dynamic(..) | ty::Projection(..) | ty::Param(_) | ty::Bound(..) | |
1013 | ty::Placeholder(..) | ty::Opaque(..) | ty::Infer(_) | ty::Error => true, | |
7cac9316 | 1014 | |
0bf4aa26 XL |
1015 | ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"), |
1016 | ||
7cac9316 | 1017 | // Structural recursion. |
b7449926 | 1018 | ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty), |
7cac9316 | 1019 | |
b7449926 | 1020 | ty::Closure(def_id, ref substs) => substs.upvar_tys(def_id, tcx).any(needs_drop), |
7cac9316 | 1021 | |
ea8adc8c XL |
1022 | // Pessimistically assume that all generators will require destructors |
1023 | // as we don't know if a destructor is a noop or not until after the MIR | |
1024 | // state transformation pass | |
b7449926 | 1025 | ty::Generator(..) => true, |
ea8adc8c | 1026 | |
48663c56 | 1027 | ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).any(needs_drop), |
7cac9316 | 1028 | |
8faf50e0 XL |
1029 | // unions don't have destructors because of the child types, |
1030 | // only if they manually implement `Drop` (handled above). | |
b7449926 | 1031 | ty::Adt(def, _) if def.is_union() => false, |
7cac9316 | 1032 | |
b7449926 | 1033 | ty::Adt(def, substs) => |
7cac9316 XL |
1034 | def.variants.iter().any( |
1035 | |variant| variant.fields.iter().any( | |
1036 | |field| needs_drop(field.ty(tcx, substs)))), | |
9fa01778 | 1037 | }) |
7cac9316 XL |
1038 | } |
1039 | ||
abe05a73 XL |
1040 | pub enum ExplicitSelf<'tcx> { |
1041 | ByValue, | |
1042 | ByReference(ty::Region<'tcx>, hir::Mutability), | |
ff7c6d11 | 1043 | ByRawPointer(hir::Mutability), |
abe05a73 XL |
1044 | ByBox, |
1045 | Other | |
1046 | } | |
1047 | ||
1048 | impl<'tcx> ExplicitSelf<'tcx> { | |
1049 | /// Categorizes an explicit self declaration like `self: SomeType` | |
1050 | /// into either `self`, `&self`, `&mut self`, `Box<self>`, or | |
1051 | /// `Other`. | |
1052 | /// This is mainly used to require the arbitrary_self_types feature | |
1053 | /// in the case of `Other`, to improve error messages in the common cases, | |
1054 | /// and to make `Other` non-object-safe. | |
1055 | /// | |
1056 | /// Examples: | |
1057 | /// | |
1058 | /// ``` | |
1059 | /// impl<'a> Foo for &'a T { | |
1060 | /// // Legal declarations: | |
1061 | /// fn method1(self: &&'a T); // ExplicitSelf::ByReference | |
1062 | /// fn method2(self: &'a T); // ExplicitSelf::ByValue | |
1063 | /// fn method3(self: Box<&'a T>); // ExplicitSelf::ByBox | |
1064 | /// fn method4(self: Rc<&'a T>); // ExplicitSelf::Other | |
1065 | /// | |
1066 | /// // Invalid cases will be caught by `check_method_receiver`: | |
1067 | /// fn method_err1(self: &'a mut T); // ExplicitSelf::Other | |
1068 | /// fn method_err2(self: &'static T) // ExplicitSelf::ByValue | |
1069 | /// fn method_err3(self: &&T) // ExplicitSelf::ByReference | |
1070 | /// } | |
1071 | /// ``` | |
1072 | /// | |
1073 | pub fn determine<P>( | |
1074 | self_arg_ty: Ty<'tcx>, | |
1075 | is_self_ty: P | |
1076 | ) -> ExplicitSelf<'tcx> | |
1077 | where | |
1078 | P: Fn(Ty<'tcx>) -> bool | |
1079 | { | |
1080 | use self::ExplicitSelf::*; | |
1081 | ||
1082 | match self_arg_ty.sty { | |
1083 | _ if is_self_ty(self_arg_ty) => ByValue, | |
b7449926 | 1084 | ty::Ref(region, ty, mutbl) if is_self_ty(ty) => { |
abe05a73 XL |
1085 | ByReference(region, mutbl) |
1086 | } | |
b7449926 | 1087 | ty::RawPtr(ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => { |
ff7c6d11 XL |
1088 | ByRawPointer(mutbl) |
1089 | } | |
b7449926 | 1090 | ty::Adt(def, _) if def.is_box() && is_self_ty(self_arg_ty.boxed_ty()) => { |
ff7c6d11 XL |
1091 | ByBox |
1092 | } | |
abe05a73 XL |
1093 | _ => Other |
1094 | } | |
1095 | } | |
1096 | } | |
1097 | ||
0bf4aa26 | 1098 | pub fn provide(providers: &mut ty::query::Providers<'_>) { |
94b46f34 | 1099 | *providers = ty::query::Providers { |
7cac9316 XL |
1100 | is_copy_raw, |
1101 | is_sized_raw, | |
1102 | is_freeze_raw, | |
1103 | needs_drop_raw, | |
7cac9316 XL |
1104 | ..*providers |
1105 | }; | |
1106 | } |