Fiddle ParamEnv through to a place that used to use ParamEnv::empty in a buggy manner

This commit is contained in:
Oliver Scherer 2020-03-16 18:51:55 +01:00
parent 59f4ba9504
commit 7894509b00
5 changed files with 64 additions and 24 deletions

View File

@ -90,30 +90,46 @@ impl<'tcx> TyCtxt<'tcx> {
/// ```
/// This code should only compile in modules where the uninhabitedness of Foo is
/// visible.
pub fn is_ty_uninhabited_from(self, module: DefId, ty: Ty<'tcx>) -> bool {
pub fn is_ty_uninhabited_from(
self,
module: DefId,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
// To check whether this type is uninhabited at all (not just from the
// given node), you could check whether the forest is empty.
// ```
// forest.is_empty()
// ```
ty.uninhabited_from(self).contains(self, module)
ty.uninhabited_from(self, param_env).contains(self, module)
}
pub fn is_ty_uninhabited_from_any_module(self, ty: Ty<'tcx>) -> bool {
!ty.uninhabited_from(self).is_empty()
pub fn is_ty_uninhabited_from_any_module(
self,
ty: Ty<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
!ty.uninhabited_from(self, param_env).is_empty()
}
}
impl<'tcx> AdtDef {
/// Calculates the forest of `DefId`s from which this ADT is visibly uninhabited.
fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, substs: SubstsRef<'tcx>) -> DefIdForest {
fn uninhabited_from(
&self,
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> DefIdForest {
// Non-exhaustive ADTs from other crates are always considered inhabited.
if self.is_variant_list_non_exhaustive() && !self.did.is_local() {
DefIdForest::empty()
} else {
DefIdForest::intersection(
tcx,
self.variants.iter().map(|v| v.uninhabited_from(tcx, substs, self.adt_kind())),
self.variants
.iter()
.map(|v| v.uninhabited_from(tcx, substs, self.adt_kind(), param_env)),
)
}
}
@ -126,6 +142,7 @@ impl<'tcx> VariantDef {
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
adt_kind: AdtKind,
param_env: ty::ParamEnv<'tcx>,
) -> DefIdForest {
let is_enum = match adt_kind {
// For now, `union`s are never considered uninhabited.
@ -140,7 +157,7 @@ impl<'tcx> VariantDef {
} else {
DefIdForest::union(
tcx,
self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum)),
self.fields.iter().map(|f| f.uninhabited_from(tcx, substs, is_enum, param_env)),
)
}
}
@ -153,8 +170,9 @@ impl<'tcx> FieldDef {
tcx: TyCtxt<'tcx>,
substs: SubstsRef<'tcx>,
is_enum: bool,
param_env: ty::ParamEnv<'tcx>,
) -> DefIdForest {
let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx);
let data_uninhabitedness = move || self.ty(tcx, substs).uninhabited_from(tcx, param_env);
// FIXME(canndrew): Currently enum fields are (incorrectly) stored with
// `Visibility::Invisible` so we need to override `self.vis` if we're
// dealing with an enum.
@ -176,20 +194,21 @@ impl<'tcx> FieldDef {
impl<'tcx> TyS<'tcx> {
/// Calculates the forest of `DefId`s from which this type is visibly uninhabited.
fn uninhabited_from(&self, tcx: TyCtxt<'tcx>) -> DefIdForest {
fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest {
match self.kind {
Adt(def, substs) => def.uninhabited_from(tcx, substs),
Adt(def, substs) => def.uninhabited_from(tcx, substs, param_env),
Never => DefIdForest::full(tcx),
Tuple(ref tys) => {
DefIdForest::union(tcx, tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx)))
}
Tuple(ref tys) => DefIdForest::union(
tcx,
tys.iter().map(|ty| ty.expect_ty().uninhabited_from(tcx, param_env)),
),
Array(ty, len) => match len.try_eval_usize(tcx, ty::ParamEnv::empty()) {
Array(ty, len) => match len.try_eval_usize(tcx, param_env) {
// If the array is definitely non-empty, it's uninhabited if
// the type of its elements is uninhabited.
Some(n) if n != 0 => ty.uninhabited_from(tcx),
Some(n) if n != 0 => ty.uninhabited_from(tcx, param_env),
_ => DefIdForest::empty(),
},

View File

@ -124,7 +124,12 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnusedResults {
descr_post: &str,
plural_len: usize,
) -> bool {
if ty.is_unit() || cx.tcx.is_ty_uninhabited_from(cx.tcx.parent_module(expr.hir_id), ty)
if ty.is_unit()
|| cx.tcx.is_ty_uninhabited_from(
cx.tcx.parent_module(expr.hir_id),
ty,
cx.param_env,
)
{
return true;
}

View File

@ -209,7 +209,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
i == variant_index || {
self.hir.tcx().features().exhaustive_patterns
&& !v
.uninhabited_from(self.hir.tcx(), substs, adt_def.adt_kind())
.uninhabited_from(
self.hir.tcx(),
substs,
adt_def.adt_kind(),
self.hir.param_env,
)
.is_empty()
}
}) && (adt_def.did.is_local()

View File

@ -598,7 +598,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
if self.tcx.features().exhaustive_patterns {
self.tcx.is_ty_uninhabited_from(self.module, ty)
self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env)
} else {
false
}
@ -1267,7 +1267,7 @@ fn all_constructors<'a, 'tcx>(
def.variants
.iter()
.filter(|v| {
!v.uninhabited_from(cx.tcx, substs, def.adt_kind())
!v.uninhabited_from(cx.tcx, substs, def.adt_kind(), cx.param_env)
.contains(cx.tcx, cx.module)
})
.map(|v| Variant(v.def_id))

View File

@ -398,7 +398,7 @@ fn visit_fn<'tcx>(
intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id);
// compute liveness
let mut lsets = Liveness::new(&mut fn_maps, body_id);
let mut lsets = Liveness::new(&mut fn_maps, def_id);
let entry_ln = lsets.compute(&body.value);
// check for various error conditions
@ -658,6 +658,7 @@ const ACC_USE: u32 = 4;
struct Liveness<'a, 'tcx> {
ir: &'a mut IrMaps<'tcx>,
tables: &'a ty::TypeckTables<'tcx>,
param_env: ty::ParamEnv<'tcx>,
s: Specials,
successors: Vec<LiveNode>,
rwu_table: RWUTable,
@ -670,7 +671,7 @@ struct Liveness<'a, 'tcx> {
}
impl<'a, 'tcx> Liveness<'a, 'tcx> {
fn new(ir: &'a mut IrMaps<'tcx>, body: hir::BodyId) -> Liveness<'a, 'tcx> {
fn new(ir: &'a mut IrMaps<'tcx>, def_id: DefId) -> Liveness<'a, 'tcx> {
// Special nodes and variables:
// - exit_ln represents the end of the fn, either by return or panic
// - implicit_ret_var is a pseudo-variable that represents
@ -681,7 +682,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
clean_exit_var: ir.add_variable(CleanExit),
};
let tables = ir.tcx.body_tables(body);
let tables = ir.tcx.typeck_tables_of(def_id);
let param_env = ir.tcx.param_env(def_id);
let num_live_nodes = ir.num_live_nodes;
let num_vars = ir.num_vars;
@ -689,6 +691,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
Liveness {
ir,
tables,
param_env,
s: specials,
successors: vec![invalid_node(); num_live_nodes],
rwu_table: RWUTable::new(num_live_nodes * num_vars),
@ -1126,7 +1129,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprKind::Call(ref f, ref args) => {
let m = self.ir.tcx.parent_module(expr.hir_id);
let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) {
let succ = if self.ir.tcx.is_ty_uninhabited_from(
m,
self.tables.expr_ty(expr),
self.param_env,
) {
self.s.exit_ln
} else {
succ
@ -1137,7 +1144,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
hir::ExprKind::MethodCall(.., ref args) => {
let m = self.ir.tcx.parent_module(expr.hir_id);
let succ = if self.ir.tcx.is_ty_uninhabited_from(m, self.tables.expr_ty(expr)) {
let succ = if self.ir.tcx.is_ty_uninhabited_from(
m,
self.tables.expr_ty(expr),
self.param_env,
) {
self.s.exit_ln
} else {
succ