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