]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_ty_utils/src/ty.rs
Auto merge of #86911 - bjorn3:crate_info_refactor, r=petrochenkov
[rust.git] / compiler / rustc_ty_utils / src / ty.rs
1 use rustc_data_structures::fx::FxIndexSet;
2 use rustc_hir as hir;
3 use rustc_hir::def_id::{DefId, LocalDefId};
4 use rustc_middle::hir::map as hir_map;
5 use rustc_middle::ty::subst::Subst;
6 use rustc_middle::ty::{
7     self, Binder, Predicate, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness,
8 };
9 use rustc_span::Span;
10 use rustc_trait_selection::traits;
11
12 fn sized_constraint_for_ty<'tcx>(
13     tcx: TyCtxt<'tcx>,
14     adtdef: &ty::AdtDef,
15     ty: Ty<'tcx>,
16 ) -> Vec<Ty<'tcx>> {
17     use ty::TyKind::*;
18
19     let result = match ty.kind() {
20         Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..)
21         | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![],
22
23         Str | Dynamic(..) | Slice(_) | Foreign(..) | Error(_) | GeneratorWitness(..) => {
24             // these are never sized - return the target type
25             vec![ty]
26         }
27
28         Tuple(ref tys) => match tys.last() {
29             None => vec![],
30             Some(ty) => sized_constraint_for_ty(tcx, adtdef, ty.expect_ty()),
31         },
32
33         Adt(adt, substs) => {
34             // recursive case
35             let adt_tys = adt.sized_constraint(tcx);
36             debug!("sized_constraint_for_ty({:?}) intermediate = {:?}", ty, adt_tys);
37             adt_tys
38                 .iter()
39                 .map(|ty| ty.subst(tcx, substs))
40                 .flat_map(|ty| sized_constraint_for_ty(tcx, adtdef, ty))
41                 .collect()
42         }
43
44         Projection(..) | Opaque(..) => {
45             // must calculate explicitly.
46             // FIXME: consider special-casing always-Sized projections
47             vec![ty]
48         }
49
50         Param(..) => {
51             // perf hack: if there is a `T: Sized` bound, then
52             // we know that `T` is Sized and do not need to check
53             // it on the impl.
54
55             let sized_trait = match tcx.lang_items().sized_trait() {
56                 Some(x) => x,
57                 _ => return vec![ty],
58             };
59             let sized_predicate = ty::Binder::dummy(ty::TraitRef {
60                 def_id: sized_trait,
61                 substs: tcx.mk_substs_trait(ty, &[]),
62             })
63             .without_const()
64             .to_predicate(tcx);
65             let predicates = tcx.predicates_of(adtdef.did).predicates;
66             if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] }
67         }
68
69         Placeholder(..) | Bound(..) | Infer(..) => {
70             bug!("unexpected type `{:?}` in sized_constraint_for_ty", ty)
71         }
72     };
73     debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
74     result
75 }
76
77 fn associated_item_from_trait_item_ref(
78     tcx: TyCtxt<'_>,
79     parent_def_id: LocalDefId,
80     trait_item_ref: &hir::TraitItemRef,
81 ) -> ty::AssocItem {
82     let def_id = trait_item_ref.id.def_id;
83     let (kind, has_self) = match trait_item_ref.kind {
84         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
85         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
86         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
87     };
88
89     ty::AssocItem {
90         ident: trait_item_ref.ident,
91         kind,
92         vis: tcx.visibility(def_id),
93         defaultness: trait_item_ref.defaultness,
94         def_id: def_id.to_def_id(),
95         container: ty::TraitContainer(parent_def_id.to_def_id()),
96         fn_has_self_parameter: has_self,
97     }
98 }
99
100 fn associated_item_from_impl_item_ref(
101     tcx: TyCtxt<'_>,
102     parent_def_id: LocalDefId,
103     impl_item_ref: &hir::ImplItemRef<'_>,
104 ) -> ty::AssocItem {
105     let def_id = impl_item_ref.id.def_id;
106     let (kind, has_self) = match impl_item_ref.kind {
107         hir::AssocItemKind::Const => (ty::AssocKind::Const, false),
108         hir::AssocItemKind::Fn { has_self } => (ty::AssocKind::Fn, has_self),
109         hir::AssocItemKind::Type => (ty::AssocKind::Type, false),
110     };
111
112     ty::AssocItem {
113         ident: impl_item_ref.ident,
114         kind,
115         vis: tcx.visibility(def_id),
116         defaultness: impl_item_ref.defaultness,
117         def_id: def_id.to_def_id(),
118         container: ty::ImplContainer(parent_def_id.to_def_id()),
119         fn_has_self_parameter: has_self,
120     }
121 }
122
123 fn associated_item(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItem {
124     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
125     let parent_id = tcx.hir().get_parent_item(id);
126     let parent_def_id = tcx.hir().local_def_id(parent_id);
127     let parent_item = tcx.hir().expect_item(parent_id);
128     match parent_item.kind {
129         hir::ItemKind::Impl(ref impl_) => {
130             if let Some(impl_item_ref) =
131                 impl_.items.iter().find(|i| i.id.def_id.to_def_id() == def_id)
132             {
133                 let assoc_item =
134                     associated_item_from_impl_item_ref(tcx, parent_def_id, impl_item_ref);
135                 debug_assert_eq!(assoc_item.def_id, def_id);
136                 return assoc_item;
137             }
138         }
139
140         hir::ItemKind::Trait(.., ref trait_item_refs) => {
141             if let Some(trait_item_ref) =
142                 trait_item_refs.iter().find(|i| i.id.def_id.to_def_id() == def_id)
143             {
144                 let assoc_item =
145                     associated_item_from_trait_item_ref(tcx, parent_def_id, trait_item_ref);
146                 debug_assert_eq!(assoc_item.def_id, def_id);
147                 return assoc_item;
148             }
149         }
150
151         _ => {}
152     }
153
154     span_bug!(
155         parent_item.span,
156         "unexpected parent of trait or impl item or item not found: {:?}",
157         parent_item.kind
158     )
159 }
160
161 fn impl_defaultness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::Defaultness {
162     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
163     let item = tcx.hir().expect_item(hir_id);
164     if let hir::ItemKind::Impl(impl_) = &item.kind {
165         impl_.defaultness
166     } else {
167         bug!("`impl_defaultness` called on {:?}", item);
168     }
169 }
170
171 /// Calculates the `Sized` constraint.
172 ///
173 /// In fact, there are only a few options for the types in the constraint:
174 ///     - an obviously-unsized type
175 ///     - a type parameter or projection whose Sizedness can't be known
176 ///     - a tuple of type parameters or projections, if there are multiple
177 ///       such.
178 ///     - a Error, if a type contained itself. The representability
179 ///       check should catch this case.
180 fn adt_sized_constraint(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AdtSizedConstraint<'_> {
181     let def = tcx.adt_def(def_id);
182
183     let result = tcx.mk_type_list(
184         def.variants
185             .iter()
186             .flat_map(|v| v.fields.last())
187             .flat_map(|f| sized_constraint_for_ty(tcx, def, tcx.type_of(f.did))),
188     );
189
190     debug!("adt_sized_constraint: {:?} => {:?}", def, result);
191
192     ty::AdtSizedConstraint(result)
193 }
194
195 fn associated_item_def_ids(tcx: TyCtxt<'_>, def_id: DefId) -> &[DefId] {
196     let id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
197     let item = tcx.hir().expect_item(id);
198     match item.kind {
199         hir::ItemKind::Trait(.., ref trait_item_refs) => tcx.arena.alloc_from_iter(
200             trait_item_refs.iter().map(|trait_item_ref| trait_item_ref.id.def_id.to_def_id()),
201         ),
202         hir::ItemKind::Impl(ref impl_) => tcx.arena.alloc_from_iter(
203             impl_.items.iter().map(|impl_item_ref| impl_item_ref.id.def_id.to_def_id()),
204         ),
205         hir::ItemKind::TraitAlias(..) => &[],
206         _ => span_bug!(item.span, "associated_item_def_ids: not impl or trait"),
207     }
208 }
209
210 fn associated_items(tcx: TyCtxt<'_>, def_id: DefId) -> ty::AssocItems<'_> {
211     let items = tcx.associated_item_def_ids(def_id).iter().map(|did| tcx.associated_item(*did));
212     ty::AssocItems::new(items)
213 }
214
215 fn def_ident_span(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Span> {
216     tcx.hir().get_if_local(def_id).and_then(|node| node.ident()).map(|ident| ident.span)
217 }
218
219 /// If the given `DefId` describes an item belonging to a trait,
220 /// returns the `DefId` of the trait that the trait item belongs to;
221 /// otherwise, returns `None`.
222 fn trait_of_item(tcx: TyCtxt<'_>, def_id: DefId) -> Option<DefId> {
223     tcx.opt_associated_item(def_id).and_then(|associated_item| match associated_item.container {
224         ty::TraitContainer(def_id) => Some(def_id),
225         ty::ImplContainer(_) => None,
226     })
227 }
228
229 /// See `ParamEnv` struct definition for details.
230 fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
231     // The param_env of an impl Trait type is its defining function's param_env
232     if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
233         return param_env(tcx, parent);
234     }
235     // Compute the bounds on Self and the type parameters.
236
237     let ty::InstantiatedPredicates { mut predicates, .. } =
238         tcx.predicates_of(def_id).instantiate_identity(tcx);
239
240     // Finally, we have to normalize the bounds in the environment, in
241     // case they contain any associated type projections. This process
242     // can yield errors if the put in illegal associated types, like
243     // `<i32 as Foo>::Bar` where `i32` does not implement `Foo`. We
244     // report these errors right here; this doesn't actually feel
245     // right to me, because constructing the environment feels like a
246     // kind of a "idempotent" action, but I'm not sure where would be
247     // a better place. In practice, we construct environments for
248     // every fn once during type checking, and we'll abort if there
249     // are any errors at that point, so after type checking you can be
250     // sure that this will succeed without errors anyway.
251
252     if tcx.sess.opts.debugging_opts.chalk {
253         let environment = well_formed_types_in_env(tcx, def_id);
254         predicates.extend(environment);
255     }
256
257     let unnormalized_env =
258         ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing);
259
260     let body_id = def_id
261         .as_local()
262         .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id))
263         .map_or(hir::CRATE_HIR_ID, |id| {
264             tcx.hir().maybe_body_owned_by(id).map_or(id, |body| body.hir_id)
265         });
266     let cause = traits::ObligationCause::misc(tcx.def_span(def_id), body_id);
267     traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause)
268 }
269
270 /// Elaborate the environment.
271 ///
272 /// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s
273 /// that are assumed to be well-formed (because they come from the environment).
274 ///
275 /// Used only in chalk mode.
276 fn well_formed_types_in_env<'tcx>(
277     tcx: TyCtxt<'tcx>,
278     def_id: DefId,
279 ) -> &'tcx ty::List<Predicate<'tcx>> {
280     use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind};
281     use rustc_middle::ty::subst::GenericArgKind;
282
283     debug!("environment(def_id = {:?})", def_id);
284
285     // The environment of an impl Trait type is its defining function's environment.
286     if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) {
287         return well_formed_types_in_env(tcx, parent);
288     }
289
290     // Compute the bounds on `Self` and the type parameters.
291     let ty::InstantiatedPredicates { predicates, .. } =
292         tcx.predicates_of(def_id).instantiate_identity(tcx);
293
294     let clauses = predicates.into_iter();
295
296     if !def_id.is_local() {
297         return ty::List::empty();
298     }
299     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
300     let node = tcx.hir().get(hir_id);
301
302     enum NodeKind {
303         TraitImpl,
304         InherentImpl,
305         Fn,
306         Other,
307     }
308
309     let node_kind = match node {
310         Node::TraitItem(item) => match item.kind {
311             TraitItemKind::Fn(..) => NodeKind::Fn,
312             _ => NodeKind::Other,
313         },
314
315         Node::ImplItem(item) => match item.kind {
316             ImplItemKind::Fn(..) => NodeKind::Fn,
317             _ => NodeKind::Other,
318         },
319
320         Node::Item(item) => match item.kind {
321             ItemKind::Impl(hir::Impl { of_trait: Some(_), .. }) => NodeKind::TraitImpl,
322             ItemKind::Impl(hir::Impl { of_trait: None, .. }) => NodeKind::InherentImpl,
323             ItemKind::Fn(..) => NodeKind::Fn,
324             _ => NodeKind::Other,
325         },
326
327         Node::ForeignItem(item) => match item.kind {
328             ForeignItemKind::Fn(..) => NodeKind::Fn,
329             _ => NodeKind::Other,
330         },
331
332         // FIXME: closures?
333         _ => NodeKind::Other,
334     };
335
336     // FIXME(eddyb) isn't the unordered nature of this a hazard?
337     let mut inputs = FxIndexSet::default();
338
339     match node_kind {
340         // In a trait impl, we assume that the header trait ref and all its
341         // constituents are well-formed.
342         NodeKind::TraitImpl => {
343             let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl");
344
345             // FIXME(chalk): this has problems because of late-bound regions
346             //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk()));
347             inputs.extend(trait_ref.substs.iter());
348         }
349
350         // In an inherent impl, we assume that the receiver type and all its
351         // constituents are well-formed.
352         NodeKind::InherentImpl => {
353             let self_ty = tcx.type_of(def_id);
354             inputs.extend(self_ty.walk());
355         }
356
357         // In an fn, we assume that the arguments and all their constituents are
358         // well-formed.
359         NodeKind::Fn => {
360             let fn_sig = tcx.fn_sig(def_id);
361             let fn_sig = tcx.liberate_late_bound_regions(def_id, fn_sig);
362
363             inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk()));
364         }
365
366         NodeKind::Other => (),
367     }
368     let input_clauses = inputs.into_iter().filter_map(|arg| {
369         match arg.unpack() {
370             GenericArgKind::Type(ty) => {
371                 let binder = Binder::dummy(PredicateKind::TypeWellFormedFromEnv(ty));
372                 Some(tcx.mk_predicate(binder))
373             }
374
375             // FIXME(eddyb) no WF conditions from lifetimes?
376             GenericArgKind::Lifetime(_) => None,
377
378             // FIXME(eddyb) support const generics in Chalk
379             GenericArgKind::Const(_) => None,
380         }
381     });
382
383     tcx.mk_predicates(clauses.chain(input_clauses))
384 }
385
386 fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> {
387     tcx.param_env(def_id).with_reveal_all_normalized(tcx)
388 }
389
390 fn instance_def_size_estimate<'tcx>(
391     tcx: TyCtxt<'tcx>,
392     instance_def: ty::InstanceDef<'tcx>,
393 ) -> usize {
394     use ty::InstanceDef;
395
396     match instance_def {
397         InstanceDef::Item(..) | InstanceDef::DropGlue(..) => {
398             let mir = tcx.instance_mir(instance_def);
399             mir.basic_blocks().iter().map(|bb| bb.statements.len() + 1).sum()
400         }
401         // Estimate the size of other compiler-generated shims to be 1.
402         _ => 1,
403     }
404 }
405
406 /// If `def_id` is an issue 33140 hack impl, returns its self type; otherwise, returns `None`.
407 ///
408 /// See [`ty::ImplOverlapKind::Issue33140`] for more details.
409 fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option<Ty<'_>> {
410     debug!("issue33140_self_ty({:?})", def_id);
411
412     let trait_ref = tcx
413         .impl_trait_ref(def_id)
414         .unwrap_or_else(|| bug!("issue33140_self_ty called on inherent impl {:?}", def_id));
415
416     debug!("issue33140_self_ty({:?}), trait-ref={:?}", def_id, trait_ref);
417
418     let is_marker_like = tcx.impl_polarity(def_id) == ty::ImplPolarity::Positive
419         && tcx.associated_item_def_ids(trait_ref.def_id).is_empty();
420
421     // Check whether these impls would be ok for a marker trait.
422     if !is_marker_like {
423         debug!("issue33140_self_ty - not marker-like!");
424         return None;
425     }
426
427     // impl must be `impl Trait for dyn Marker1 + Marker2 + ...`
428     if trait_ref.substs.len() != 1 {
429         debug!("issue33140_self_ty - impl has substs!");
430         return None;
431     }
432
433     let predicates = tcx.predicates_of(def_id);
434     if predicates.parent.is_some() || !predicates.predicates.is_empty() {
435         debug!("issue33140_self_ty - impl has predicates {:?}!", predicates);
436         return None;
437     }
438
439     let self_ty = trait_ref.self_ty();
440     let self_ty_matches = match self_ty.kind() {
441         ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(),
442         _ => false,
443     };
444
445     if self_ty_matches {
446         debug!("issue33140_self_ty - MATCHES!");
447         Some(self_ty)
448     } else {
449         debug!("issue33140_self_ty - non-matching self type");
450         None
451     }
452 }
453
454 /// Check if a function is async.
455 fn asyncness(tcx: TyCtxt<'_>, def_id: DefId) -> hir::IsAsync {
456     let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local());
457
458     let node = tcx.hir().get(hir_id);
459
460     let fn_like = hir_map::blocks::FnLikeNode::from_node(node).unwrap_or_else(|| {
461         bug!("asyncness: expected fn-like node but got `{:?}`", def_id);
462     });
463
464     fn_like.asyncness()
465 }
466
467 /// Don't call this directly: use ``tcx.conservative_is_privately_uninhabited`` instead.
468 #[instrument(level = "debug", skip(tcx))]
469 pub fn conservative_is_privately_uninhabited_raw<'tcx>(
470     tcx: TyCtxt<'tcx>,
471     param_env_and: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
472 ) -> bool {
473     let (param_env, ty) = param_env_and.into_parts();
474     match ty.kind() {
475         ty::Never => {
476             debug!("ty::Never =>");
477             true
478         }
479         ty::Adt(def, _) if def.is_union() => {
480             debug!("ty::Adt(def, _) if def.is_union() =>");
481             // For now, `union`s are never considered uninhabited.
482             false
483         }
484         ty::Adt(def, substs) => {
485             debug!("ty::Adt(def, _) if def.is_not_union() =>");
486             // Any ADT is uninhabited if either:
487             // (a) It has no variants (i.e. an empty `enum`);
488             // (b) Each of its variants (a single one in the case of a `struct`) has at least
489             //     one uninhabited field.
490             def.variants.iter().all(|var| {
491                 var.fields.iter().any(|field| {
492                     let ty = tcx.type_of(field.did).subst(tcx, substs);
493                     tcx.conservative_is_privately_uninhabited(param_env.and(ty))
494                 })
495             })
496         }
497         ty::Tuple(..) => {
498             debug!("ty::Tuple(..) =>");
499             ty.tuple_fields().any(|ty| tcx.conservative_is_privately_uninhabited(param_env.and(ty)))
500         }
501         ty::Array(ty, len) => {
502             debug!("ty::Array(ty, len) =>");
503             match len.try_eval_usize(tcx, param_env) {
504                 Some(0) | None => false,
505                 // If the array is definitely non-empty, it's uninhabited if
506                 // the type of its elements is uninhabited.
507                 Some(1..) => tcx.conservative_is_privately_uninhabited(param_env.and(ty)),
508             }
509         }
510         ty::Ref(..) => {
511             debug!("ty::Ref(..) =>");
512             // References to uninitialised memory is valid for any type, including
513             // uninhabited types, in unsafe code, so we treat all references as
514             // inhabited.
515             false
516         }
517         _ => {
518             debug!("_ =>");
519             false
520         }
521     }
522 }
523
524 pub fn provide(providers: &mut ty::query::Providers) {
525     *providers = ty::query::Providers {
526         asyncness,
527         associated_item,
528         associated_item_def_ids,
529         associated_items,
530         adt_sized_constraint,
531         def_ident_span,
532         param_env,
533         param_env_reveal_all_normalized,
534         trait_of_item,
535         instance_def_size_estimate,
536         issue33140_self_ty,
537         impl_defaultness,
538         conservative_is_privately_uninhabited: conservative_is_privately_uninhabited_raw,
539         ..*providers
540     };
541 }