rustc_middle/ty/inhabitedness/
mod.rs1#![cfg_attr(bootstrap, doc = "#![feature(never_type)]")]
9use std::assert_matches;
47
48use rustc_data_structures::fx::FxHashSet;
49use rustc_hir::def::DefKind;
50use rustc_span::bug;
51use rustc_span::def_id::LocalModId;
52use rustc_type_ir::TyKind::*;
53use tracing::instrument;
54
55use crate::query::Providers;
56use crate::ty::consts::ConstExt;
57use crate::ty::{
58 self, AdtDef, DefId, Ty, TyCtxt, TypeVisitableExt, TypingEnv, VariantDef, Visibility,
59};
60
61pub mod inhabited_predicate;
62
63pub use inhabited_predicate::InhabitedPredicate;
64
65pub(crate) fn provide(providers: &mut Providers) {
66 *providers = Providers {
67 inhabited_predicate_for_def,
68 inhabited_predicate_type,
69 is_opsem_inhabited_raw,
70 ..*providers
71 };
72}
73
74fn inhabited_predicate_for_def(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
77 match tcx.def_kind(def_id) {
78 DefKind::Enum => {
79 if let Some(def_id) = def_id.as_local() {
80 tcx.ensure_ok().check_representability(def_id);
81 }
82 let adt = tcx.adt_def(def_id);
83 InhabitedPredicate::any(tcx, adt.variants().iter().map(|v| v.inhabited_predicate(tcx)))
84 }
85 DefKind::Struct => {
86 if let Some(def_id) = def_id.as_local() {
87 tcx.ensure_ok().check_representability(def_id);
88 }
89 let adt = tcx.adt_def(def_id);
90 variant_inhabited_predicate(tcx, adt, adt.non_enum_variant())
91 }
92 DefKind::Variant => {
93 let adt = tcx.adt_def(tcx.parent(def_id));
94 let variant = adt.variant_with_id(def_id);
95 variant_inhabited_predicate(tcx, adt, variant)
96 }
97 def_kind => ::rustc_span::macros::bug_impl(None,
format_args!("unexpected DefKind: {0:?}", def_kind), Location::caller())bug!("unexpected DefKind: {def_kind:?}"),
98 }
99}
100
101impl VariantDef {
102 pub fn inhabited_predicate<'tcx>(&self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
103 if self.fields.is_empty() {
104 return InhabitedPredicate::True;
105 }
106 tcx.inhabited_predicate_for_def(self.def_id)
107 }
108}
109
110fn variant_inhabited_predicate<'tcx>(
111 tcx: TyCtxt<'tcx>,
112 adt: AdtDef<'tcx>,
113 variant: &VariantDef,
114) -> InhabitedPredicate<'tcx> {
115 InhabitedPredicate::all(
116 tcx,
117 variant.fields.iter().map(|field| {
118 let pred = tcx
119 .type_of(field.did)
120 .instantiate_identity()
121 .skip_norm_wip()
122 .inhabited_predicate(tcx);
123 if adt.is_enum() {
124 return pred;
125 }
126 match field.vis {
127 Visibility::Public => pred,
128 Visibility::Restricted(from) => InhabitedPredicate::NotInModule(from).or(tcx, pred),
129 }
130 }),
131 )
132}
133
134impl<'tcx> Ty<'tcx> {
135 {}
let __tracing_attr_span;
let __tracing_attr_guard;
if ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() || { false }
{
__tracing_attr_span =
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("inhabited_predicate",
"rustc_middle::ty::inhabitedness", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_middle/src/ty/inhabitedness/mod.rs"),
::tracing_core::__macro_support::Option::Some(135u32),
::tracing_core::__macro_support::Option::Some("rustc_middle::ty::inhabitedness"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("self")
}> =
::tracing::__macro_support::FieldName::new("self");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::SPAN)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let mut interest = ::tracing::subscriber::Interest::never();
if ::tracing::Level::DEBUG <=
::tracing::level_filters::STATIC_MAX_LEVEL &&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{ interest = __CALLSITE.interest(); !interest.is_never() }
&&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest) {
let meta = __CALLSITE.metadata();
::tracing::Span::new(meta,
&{
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
meta.fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&self)
as &dyn ::tracing::field::Value))])
})
} else {
let span =
::tracing::__macro_support::__disabled_span(__CALLSITE.metadata());
{};
span
}
};
__tracing_attr_guard = __tracing_attr_span.enter();
}
#[allow(clippy :: redundant_closure_call)]
let x =
(move ||
{
#[allow(unknown_lints, unreachable_code, clippy ::
diverging_sub_expression, clippy :: empty_loop, clippy ::
let_unit_value, clippy :: let_with_type_underscore, clippy
:: needless_return, clippy :: unreachable)]
if false {
let __tracing_attr_fake_return: InhabitedPredicate<'tcx> =
loop {};
return __tracing_attr_fake_return;
}
{
if true {
if !!self.has_infer() {
::core::panicking::panic("assertion failed: !self.has_infer()")
};
};
match self.kind() {
Adt(adt, _) if adt.is_union() => InhabitedPredicate::True,
Adt(adt, _) if
adt.variant_list_has_applicable_non_exhaustive() => {
InhabitedPredicate::True
}
Never => InhabitedPredicate::False,
Param(_) |
Alias(_, ty::AliasTy {
kind: ty::Inherent { .. } | ty::Projection { .. } |
ty::Free { .. }, .. }) =>
InhabitedPredicate::GenericType(self),
&Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, args,
.. }) => {
match def_id.as_local() {
None => InhabitedPredicate::True,
Some(local_def_id) => {
let key = ty::OpaqueTypeKey { def_id: local_def_id, args };
InhabitedPredicate::OpaqueType(key)
}
}
}
Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
Adt(..) | Array(..) | Tuple(_) =>
tcx.inhabited_predicate_type(self),
_ => InhabitedPredicate::True,
}
}
})();
{
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event /rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_middle/src/ty/inhabitedness/mod.rs:135",
"rustc_middle::ty::inhabitedness", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("/rustc-dev/5ceaf6608eb354c2f5bbb3b8d974caa367dac81c/compiler/rustc_middle/src/ty/inhabitedness/mod.rs"),
::tracing_core::__macro_support::Option::Some(135u32),
::tracing_core::__macro_support::Option::Some("rustc_middle::ty::inhabitedness"),
::tracing_core::field::FieldSet::new(&[{
const NAME:
::tracing::__macro_support::FieldName<{
::tracing::__macro_support::FieldName::len("return")
}> =
::tracing::__macro_support::FieldName::new("return");
NAME.as_str()
}], ::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&::tracing::field::debug(&x)
as &dyn ::tracing::field::Value))])
});
} else { ; }
};
x;#[instrument(level = "debug", skip(tcx), ret)]
136 pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx> {
137 debug_assert!(!self.has_infer());
138 match self.kind() {
139 Adt(adt, _) if adt.is_union() => InhabitedPredicate::True,
141 Adt(adt, _) if adt.variant_list_has_applicable_non_exhaustive() => {
143 InhabitedPredicate::True
144 }
145 Never => InhabitedPredicate::False,
146 Param(_)
148 | Alias(
149 _,
150 ty::AliasTy {
151 kind: ty::Inherent { .. } | ty::Projection { .. } | ty::Free { .. },
152 ..
153 },
154 ) => InhabitedPredicate::GenericType(self),
155 &Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => {
156 match def_id.as_local() {
157 None => InhabitedPredicate::True,
159 Some(local_def_id) => {
161 let key = ty::OpaqueTypeKey { def_id: local_def_id, args };
162 InhabitedPredicate::OpaqueType(key)
163 }
164 }
165 }
166 Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
167 Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
169 _ => InhabitedPredicate::True,
171 }
172 }
173
174 #[cfg_attr(bootstrap, doc = "#![feature(never_type)]")]
179 pub fn is_inhabited_from(
215 self,
216 tcx: TyCtxt<'tcx>,
217 module: LocalModId,
218 typing_env: ty::TypingEnv<'tcx>,
219 ) -> bool {
220 self.inhabited_predicate(tcx).apply(tcx, typing_env, module)
221 }
222
223 pub fn is_privately_uninhabited(
228 self,
229 tcx: TyCtxt<'tcx>,
230 typing_env: ty::TypingEnv<'tcx>,
231 ) -> bool {
232 !self.inhabited_predicate(tcx).apply_ignore_module(tcx, typing_env)
233 }
234
235 pub fn is_opsem_inhabited(self, tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>) -> bool {
244 OpsemInhabitedCtx { tcx, typing_env, seen: None, stop_at_ref: false }.is_inhabited_ty(self)
246 }
247}
248
249fn inhabited_predicate_type<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> InhabitedPredicate<'tcx> {
251 match *ty.kind() {
252 Adt(adt, args) => tcx.inhabited_predicate_for_def(adt.did()).instantiate(tcx, args),
253
254 Tuple(tys) => {
255 InhabitedPredicate::all(tcx, tys.iter().map(|ty| ty.inhabited_predicate(tcx)))
256 }
257
258 Array(ty, len) => match len.try_to_target_usize(tcx) {
261 Some(0) => InhabitedPredicate::True,
262 Some(1..) => ty.inhabited_predicate(tcx),
263 None => ty.inhabited_predicate(tcx).or(tcx, InhabitedPredicate::ConstIsZero(len)),
264 },
265
266 _ => ::rustc_span::macros::bug_impl(None,
format_args!("unexpected TyKind, use `Ty::inhabited_predicate`"),
Location::caller())bug!("unexpected TyKind, use `Ty::inhabited_predicate`"),
267 }
268}
269
270struct OpsemInhabitedCtx<'tcx> {
273 tcx: TyCtxt<'tcx>,
274 typing_env: TypingEnv<'tcx>,
275 seen: Option<FxHashSet<DefId>>,
279 stop_at_ref: bool,
282}
283
284impl<'tcx> OpsemInhabitedCtx<'tcx> {
285 fn is_inhabited_ty(&mut self, ty: Ty<'tcx>) -> bool {
287 let tcx = self.tcx;
288 match *ty.kind() {
289 ty::Int(_)
291 | ty::Uint(_)
292 | ty::Float(_)
293 | ty::Bool
294 | ty::Char
295 | ty::Str
296 | ty::Foreign(..)
297 | ty::RawPtr(..)
298 | ty::FnPtr(..)
299 | ty::FnDef(..) => true,
300 ty::Dynamic(..) => true, ty::Slice(..) => true, ty::Never => false,
303
304 ty::Ref(_, pointee, _) => {
306 if self.stop_at_ref {
307 return true;
311 }
312 self.is_inhabited_ty(pointee)
313 }
314 ty::Tuple(tys) => tys.iter().all(|ty| self.is_inhabited_ty(ty)),
315 ty::Array(elem, len) => {
316 len.try_to_target_usize(tcx).unwrap() == 0 || self.is_inhabited_ty(elem)
317 }
318 ty::Pat(inner, _pat) => self.is_inhabited_ty(inner),
319 ty::Closure(_def, args) => {
320 let args = args.as_closure();
321 args.upvar_tys().iter().all(|ty| self.is_inhabited_ty(ty))
322 }
323 ty::Coroutine(_def, args) => {
324 let args = args.as_coroutine();
325 args.upvar_tys().iter().all(|ty| self.is_inhabited_ty(ty))
326 }
327 ty::CoroutineClosure(_def, args) => {
328 let args = args.as_coroutine_closure();
329 args.upvar_tys().iter().all(|ty| self.is_inhabited_ty(ty))
330 }
331 ty::UnsafeBinder(base) => {
332 let base = tcx.instantiate_bound_regions_with_erased((*base).into());
333 self.is_inhabited_ty(base)
334 }
335 ty::Adt(..) => self.is_inhabited_adt_ty(ty),
336
337 ty::Error(_error_guaranteed) => {
338 true
340 }
341
342 ty::Infer(..)
343 | ty::Placeholder(..)
344 | ty::Bound(..)
345 | ty::Param(..)
346 | ty::Alias(..)
347 | ty::CoroutineWitness(..) => {
348 ::rustc_span::macros::bug_impl(None,
format_args!("non-normalized type in `is_opsem_uninhabited`: `{0}`", ty),
Location::caller())bug!("non-normalized type in `is_opsem_uninhabited`: `{ty}`")
349 }
350 }
351 }
352
353 fn is_inhabited_adt_ty(&mut self, ty: Ty<'tcx>) -> bool {
354 let ty::Adt(adt_def, adt_args) = *ty.kind() else {
355 ::core::panicking::panic("internal error: entered unreachable code");unreachable! {}
356 };
357 let Self { tcx, typing_env, .. } = *self;
358
359 if adt_def.is_union() {
360 return true;
362 }
363
364 let Some(seen) = self.seen.as_mut() else {
365 return tcx.is_opsem_inhabited_raw(typing_env.as_query_input(ty));
367 };
368
369 let new_adt = seen.insert(adt_def.did());
370 let stop_at_ref_prev = self.stop_at_ref;
375 self.stop_at_ref |= !new_adt;
376
377 let inhabited = adt_def.variants().iter().any(|variant| {
379 variant.fields.iter().all(|field| {
380 let ty = field.ty(tcx, adt_args);
381 let ty = tcx.normalize_erasing_regions(typing_env, ty);
382 self.is_inhabited_ty(ty)
383 })
384 });
385
386 self.stop_at_ref = stop_at_ref_prev;
387 if new_adt {
389 self.seen.as_mut().unwrap().remove(&adt_def.did());
390 }
391
392 inhabited
393 }
394}
395
396fn is_opsem_inhabited_raw<'tcx>(
397 tcx: TyCtxt<'tcx>,
398 env: ty::PseudoCanonicalInput<'tcx, Ty<'tcx>>,
399) -> bool {
400 let (ty, typing_env) = (env.value, env.typing_env);
401 {
match ty.kind() {
ty::Adt(..) => {}
ref left_val => {
::core::panicking::assert_matches_failed(left_val, "ty::Adt(..)",
::core::option::Option::Some(format_args!("the query should only be invoked by `Ty::is_opsem_inhabited`")));
}
}
};assert_matches!(
402 ty.kind(),
403 ty::Adt(..),
404 "the query should only be invoked by `Ty::is_opsem_inhabited`"
405 );
406
407 OpsemInhabitedCtx { tcx, typing_env, seen: Some(FxHashSet::default()), stop_at_ref: false }
408 .is_inhabited_adt_ty(ty)
409}