Change to Ty::is_inhabited_from

This commit is contained in:
Cameron Steffen 2022-10-23 17:32:17 -05:00
parent a6d96f9fd7
commit 34cbe72780
9 changed files with 73 additions and 81 deletions

View File

@ -217,7 +217,7 @@ fn handle_uninhabited_return(&mut self, expr: &Expr<'tcx>) {
let ty = self.tcx.erase_regions(ty); let ty = self.tcx.erase_regions(ty);
let m = self.tcx.parent_module(expr.hir_id).to_def_id(); let m = self.tcx.parent_module(expr.hir_id).to_def_id();
let param_env = self.tcx.param_env(m.expect_local()); let param_env = self.tcx.param_env(m.expect_local());
if self.tcx.is_ty_uninhabited_from(m, ty, param_env) { if !ty.is_inhabited_from(self.tcx, m, param_env) {
// This function will not return. We model this fact as an infinite loop. // This function will not return. We model this fact as an infinite loop.
self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1); self.drop_ranges.add_control_edge(self.expr_index + 1, self.expr_index + 1);
} }

View File

@ -542,10 +542,10 @@ fn check_must_not_suspend_ty<'tcx>(
data: SuspendCheckData<'_, 'tcx>, data: SuspendCheckData<'_, 'tcx>,
) -> bool { ) -> bool {
if ty.is_unit() if ty.is_unit()
// FIXME: should this check `is_ty_uninhabited_from`. This query is not available in this stage // FIXME: should this check `Ty::is_inhabited_from`. This query is not available in this stage
// of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in // of typeck (before ReVar and RePlaceholder are removed), but may remove noise, like in
// `must_use` // `must_use`
// || fcx.tcx.is_ty_uninhabited_from(fcx.tcx.parent_module(hir_id).to_def_id(), ty, fcx.param_env) // || !ty.is_inhabited_from(fcx.tcx, fcx.tcx.parent_module(hir_id).to_def_id(), fcx.param_env)
{ {
return false; return false;
} }

View File

@ -201,9 +201,9 @@ fn check_must_use_ty<'tcx>(
plural_len: usize, plural_len: usize,
) -> bool { ) -> bool {
if ty.is_unit() if ty.is_unit()
|| cx.tcx.is_ty_uninhabited_from( || !ty.is_inhabited_from(
cx.tcx,
cx.tcx.parent_module(expr.hir_id).to_def_id(), cx.tcx.parent_module(expr.hir_id).to_def_id(),
ty,
cx.param_env, cx.param_env,
) )
{ {

View File

@ -57,57 +57,6 @@ pub(crate) fn provide(providers: &mut ty::query::Providers) {
ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers }; ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers };
} }
impl<'tcx> TyCtxt<'tcx> {
/// Checks whether a type is visibly uninhabited from a particular module.
///
/// # Example
/// ```
/// #![feature(never_type)]
/// # fn main() {}
/// enum Void {}
/// mod a {
/// pub mod b {
/// pub struct SecretlyUninhabited {
/// _priv: !,
/// }
/// }
/// }
///
/// mod c {
/// use super::Void;
/// pub struct AlsoSecretlyUninhabited {
/// _priv: Void,
/// }
/// mod d {
/// }
/// }
///
/// struct Foo {
/// x: a::b::SecretlyUninhabited,
/// y: c::AlsoSecretlyUninhabited,
/// }
/// ```
/// In this code, the type `Foo` will only be visibly uninhabited inside the
/// modules b, c and d. This effects pattern-matching on `Foo` or types that
/// contain `Foo`.
///
/// # Example
/// ```ignore (illustrative)
/// let foo_result: Result<T, Foo> = ... ;
/// let Ok(t) = foo_result;
/// ```
/// 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>,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
!ty.inhabited_predicate(self).apply(self, param_env, module)
}
}
/// Returns an `InhabitedPredicate` that is generic over type parameters and /// Returns an `InhabitedPredicate` that is generic over type parameters and
/// requires calling [`InhabitedPredicate::subst`] /// requires calling [`InhabitedPredicate::subst`]
fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> { fn inhabited_predicate_adt(tcx: TyCtxt<'_>, def_id: DefId) -> InhabitedPredicate<'_> {
@ -171,6 +120,55 @@ pub fn inhabited_predicate(self, tcx: TyCtxt<'tcx>) -> InhabitedPredicate<'tcx>
_ => InhabitedPredicate::True, _ => InhabitedPredicate::True,
} }
} }
/// Checks whether a type is visibly uninhabited from a particular module.
///
/// # Example
/// ```
/// #![feature(never_type)]
/// # fn main() {}
/// enum Void {}
/// mod a {
/// pub mod b {
/// pub struct SecretlyUninhabited {
/// _priv: !,
/// }
/// }
/// }
///
/// mod c {
/// use super::Void;
/// pub struct AlsoSecretlyUninhabited {
/// _priv: Void,
/// }
/// mod d {
/// }
/// }
///
/// struct Foo {
/// x: a::b::SecretlyUninhabited,
/// y: c::AlsoSecretlyUninhabited,
/// }
/// ```
/// In this code, the type `Foo` will only be visibly uninhabited inside the
/// modules b, c and d. This effects pattern-matching on `Foo` or types that
/// contain `Foo`.
///
/// # Example
/// ```ignore (illustrative)
/// let foo_result: Result<T, Foo> = ... ;
/// let Ok(t) = foo_result;
/// ```
/// This code should only compile in modules where the uninhabitedness of Foo is
/// visible.
pub fn is_inhabited_from(
self,
tcx: TyCtxt<'tcx>,
module: DefId,
param_env: ty::ParamEnv<'tcx>,
) -> bool {
self.inhabited_predicate(tcx).apply(tcx, param_env, module)
}
} }
/// N.B. this query should only be called through `Ty::inhabited_predicate` /// N.B. this query should only be called through `Ty::inhabited_predicate`

View File

@ -271,15 +271,10 @@ pub(crate) fn expr_into_dest(
// MIR checks and ultimately whether code is accepted or not. We can only // MIR checks and ultimately whether code is accepted or not. We can only
// omit the return edge if a return type is visibly uninhabited to a module // omit the return edge if a return type is visibly uninhabited to a module
// that makes the call. // that makes the call.
target: if this.tcx.is_ty_uninhabited_from( target: expr
this.parent_module, .ty
expr.ty, .is_inhabited_from(this.tcx, this.parent_module, this.param_env)
this.param_env, .then_some(success),
) {
None
} else {
Some(success)
},
from_hir_call, from_hir_call,
fn_span, fn_span,
}, },

View File

@ -818,7 +818,7 @@ fn non_exhaustive_match<'p, 'tcx>(
} }
} }
if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() { if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
if cx.tcx.is_ty_uninhabited_from(cx.module, *sub_ty, cx.param_env) { if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) {
err.note("references are always considered inhabited"); err.note("references are always considered inhabited");
} }
} }

View File

@ -324,7 +324,7 @@ pub(crate) struct MatchCheckCtxt<'p, 'tcx> {
impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> {
pub(super) fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool { pub(super) fn is_uninhabited(&self, ty: Ty<'tcx>) -> bool {
if self.tcx.features().exhaustive_patterns { if self.tcx.features().exhaustive_patterns {
self.tcx.is_ty_uninhabited_from(self.module, ty, self.param_env) !ty.is_inhabited_from(self.tcx, self.module, self.param_env)
} else { } else {
false false
} }

View File

@ -1284,7 +1284,9 @@ fn propagate_through_loop(
fn check_is_ty_uninhabited(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode { fn check_is_ty_uninhabited(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNode {
let ty = self.typeck_results.expr_ty(expr); let ty = self.typeck_results.expr_ty(expr);
let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id(); let m = self.ir.tcx.parent_module(expr.hir_id).to_def_id();
if self.ir.tcx.is_ty_uninhabited_from(m, ty, self.param_env) { if ty.is_inhabited_from(self.ir.tcx, m, self.param_env) {
return succ;
}
match self.ir.lnks[succ] { match self.ir.lnks[succ] {
LiveNodeKind::ExprNode(succ_span, succ_id) => { LiveNodeKind::ExprNode(succ_span, succ_id) => {
self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "expression"); self.warn_about_unreachable(expr.span, ty, succ_span, succ_id, "expression");
@ -1295,9 +1297,6 @@ fn check_is_ty_uninhabited(&mut self, expr: &Expr<'_>, succ: LiveNode) -> LiveNo
_ => {} _ => {}
}; };
self.exit_ln self.exit_ln
} else {
succ
}
} }
fn warn_about_unreachable( fn warn_about_unreachable(

View File

@ -2,7 +2,7 @@
// aux-build:empty.rs // aux-build:empty.rs
// //
// This tests plays with matching and uninhabited types. This also serves as a test for the // This tests plays with matching and uninhabited types. This also serves as a test for the
// `tcx.is_ty_uninhabited_from()` function. // `Ty::is_inhabited_from` function.
#![feature(never_type)] #![feature(never_type)]
#![feature(never_type_fallback)] #![feature(never_type_fallback)]
#![feature(exhaustive_patterns)] #![feature(exhaustive_patterns)]