Skip to content

Commit 8598c9f

Browse files
committed
Turn type inhabitedness into a query
1 parent b82f149 commit 8598c9f

File tree

4 files changed

+60
-27
lines changed

4 files changed

+60
-27
lines changed

compiler/rustc_middle/src/query/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,15 @@ rustc_queries! {
13081308
eval_always
13091309
desc { |tcx| "computing visibility of `{}`", tcx.def_path_str(def_id) }
13101310
}
1311+
1312+
/// Computes the set of modules from which this type is visibly uninhabited.
1313+
/// To check whether a type is uninhabited at all (not just from a given module), you could
1314+
/// check whether the forest is empty.
1315+
query type_uninhabited_from(
1316+
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
1317+
) -> Arc<ty::inhabitedness::DefIdForest> {
1318+
desc { "computing the inhabitedness of `{:?}`", key }
1319+
}
13111320
}
13121321

13131322
Other {

compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::mem;
1111
///
1212
/// This is used to represent a set of modules in which a type is visibly
1313
/// uninhabited.
14-
#[derive(Clone)]
14+
#[derive(Clone, HashStable)]
1515
pub struct DefIdForest {
1616
/// The minimal set of `DefId`s required to represent the whole set.
1717
/// If A and B are DefIds in the `DefIdForest`, and A is a descendant
@@ -72,6 +72,9 @@ impl<'tcx> DefIdForest {
7272
break;
7373
}
7474

75+
// `next_ret` and `old_ret` are empty here.
76+
// We keep the elements in `ret` that are also in `next_forest`. Those that aren't are
77+
// put back in `ret` via `old_ret`.
7578
for id in ret.root_ids.drain(..) {
7679
if next_forest.contains(tcx, id) {
7780
next_ret.push(id);
@@ -81,7 +84,13 @@ impl<'tcx> DefIdForest {
8184
}
8285
ret.root_ids.extend(old_ret.drain(..));
8386

87+
// We keep the elements in `next_forest` that are also in `ret`.
88+
// You'd think this is not needed because `next_ret` already contains `ret \inter
89+
// next_forest`. But those aren't just sets of things. If `ret = [a]`, `next_forest =
90+
// [b]` and `b` is a submodule of `a`, then `b` belongs in the intersection but we
91+
// didn't catch it in the loop above.
8492
next_ret.extend(next_forest.root_ids.into_iter().filter(|&id| ret.contains(tcx, id)));
93+
// `next_ret` now contains the intersection of the original `ret` and `next_forest`.
8594

8695
mem::swap(&mut next_ret, &mut ret.root_ids);
8796
next_ret.drain(..);

compiler/rustc_middle/src/ty/inhabitedness/mod.rs

+40-26
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use crate::ty::TyKind::*;
66
use crate::ty::{AdtDef, FieldDef, Ty, TyS, VariantDef};
77
use crate::ty::{AdtKind, Visibility};
88
use crate::ty::{DefId, SubstsRef};
9-
use rustc_data_structures::stack::ensure_sufficient_stack;
9+
10+
use std::sync::Arc;
1011

1112
mod def_id_forest;
1213

@@ -187,34 +188,47 @@ impl<'tcx> FieldDef {
187188

188189
impl<'tcx> TyS<'tcx> {
189190
/// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
190-
fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest {
191-
match *self.kind() {
192-
Adt(def, substs) => {
193-
ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env))
194-
}
191+
fn uninhabited_from(
192+
&'tcx self,
193+
tcx: TyCtxt<'tcx>,
194+
param_env: ty::ParamEnv<'tcx>,
195+
) -> DefIdForest {
196+
tcx.type_uninhabited_from(param_env.and(self)).as_ref().clone()
197+
}
198+
}
195199

196-
Never => DefIdForest::full(tcx),
200+
// Query provider for `type_uninhabited_from`.
201+
pub(crate) fn type_uninhabited_from<'tcx>(
202+
tcx: TyCtxt<'tcx>,
203+
key: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
204+
) -> Arc<DefIdForest> {
205+
let ty = key.value;
206+
let param_env = key.param_env;
207+
let forest = match *ty.kind() {
208+
Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
197209

198-
Tuple(ref tys) => DefIdForest::union(
199-
tcx,
200-
tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
201-
),
210+
Never => DefIdForest::full(tcx),
202211

203-
Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
204-
Some(0) | None => DefIdForest::empty(),
205-
// If the array is definitely non-empty, it's uninhabited if
206-
// the type of its elements is uninhabited.
207-
Some(1..) => ty.uninhabited_from(tcx, param_env),
208-
},
212+
Tuple(ref tys) => DefIdForest::union(
213+
tcx,
214+
tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
215+
),
209216

210-
// References to uninitialised memory are valid for any type, including
211-
// uninhabited types, in unsafe code, so we treat all references as
212-
// inhabited.
213-
// The precise semantics of inhabitedness with respect to references is currently
214-
// undecided.
215-
Ref(..) => DefIdForest::empty(),
217+
Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
218+
Some(0) | None => DefIdForest::empty(),
219+
// If the array is definitely non-empty, it's uninhabited if
220+
// the type of its elements is uninhabited.
221+
Some(1..) => ty.uninhabited_from(tcx, param_env),
222+
},
216223

217-
_ => DefIdForest::empty(),
218-
}
219-
}
224+
// References to uninitialised memory are valid for any type, including
225+
// uninhabited types, in unsafe code, so we treat all references as
226+
// inhabited.
227+
// The precise semantics of inhabitedness with respect to references is currently
228+
// undecided.
229+
Ref(..) => DefIdForest::empty(),
230+
231+
_ => DefIdForest::empty(),
232+
};
233+
Arc::new(forest)
220234
}

compiler/rustc_middle/src/ty/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -3146,6 +3146,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
31463146
*providers = ty::query::Providers {
31473147
trait_impls_of: trait_def::trait_impls_of_provider,
31483148
all_local_trait_impls: trait_def::all_local_trait_impls,
3149+
type_uninhabited_from: inhabitedness::type_uninhabited_from,
31493150
..*providers
31503151
};
31513152
}

0 commit comments

Comments
 (0)