Make uninhabitedness checking more intelligent
This commit is contained in:
parent
62b359094f
commit
88afbf2d99
@ -415,7 +415,7 @@ impl<'a, 'tcx> CFGBuilder<'a, 'tcx> {
|
|||||||
args: I) -> CFGIndex {
|
args: I) -> CFGIndex {
|
||||||
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
let func_or_rcvr_exit = self.expr(func_or_rcvr, pred);
|
||||||
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
|
let ret = self.straightline(call_expr, func_or_rcvr_exit, args);
|
||||||
if self.tables.expr_ty(call_expr).conservative_is_uninhabited() {
|
if self.tables.expr_ty(call_expr).conservative_is_uninhabited(self.tcx) {
|
||||||
self.add_unreachable_node()
|
self.add_unreachable_node()
|
||||||
} else {
|
} else {
|
||||||
ret
|
ret
|
||||||
|
@ -1197,7 +1197,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::Call(ref f, ref args) => {
|
hir::ExprKind::Call(ref f, ref args) => {
|
||||||
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() {
|
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited(self.ir.tcx) {
|
||||||
self.s.exit_ln
|
self.s.exit_ln
|
||||||
} else {
|
} else {
|
||||||
succ
|
succ
|
||||||
@ -1207,7 +1207,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hir::ExprKind::MethodCall(.., ref args) => {
|
hir::ExprKind::MethodCall(.., ref args) => {
|
||||||
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited() {
|
let succ = if self.tables.expr_ty(expr).conservative_is_uninhabited(self.ir.tcx) {
|
||||||
self.s.exit_ln
|
self.s.exit_ln
|
||||||
} else {
|
} else {
|
||||||
succ
|
succ
|
||||||
|
@ -1543,14 +1543,40 @@ impl<'a, 'gcx, 'tcx> TyS<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn conservative_is_uninhabited(&self) -> bool {
|
pub fn conservative_is_uninhabited(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> bool {
|
||||||
// Checks whether a type is definitely uninhabited. This is
|
// Checks whether a type is definitely uninhabited. This is
|
||||||
// conservative: for some types that are uninhabited we return `false`,
|
// conservative: for some types that are uninhabited we return `false`,
|
||||||
// but we only return `true` for types that are definitely uninhabited.
|
// but we only return `true` for types that are definitely uninhabited.
|
||||||
match self.sty {
|
match self.sty {
|
||||||
ty::Never => true,
|
ty::Never => true,
|
||||||
ty::Adt(def, _) => def.variants.is_empty(),
|
ty::Adt(def, _) => {
|
||||||
_ => false
|
// Any ADT is uninhabited if:
|
||||||
|
// (a) It has no variants (i.e. an empty `enum`);
|
||||||
|
// (b) Each of its variants (a single one in the case of a `struct`) has at least
|
||||||
|
// one uninhabited field.
|
||||||
|
def.variants.iter().all(|var| {
|
||||||
|
var.fields.iter().any(|field| {
|
||||||
|
tcx.type_of(field.did).conservative_is_uninhabited(tcx)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ty::Tuple(tys) => tys.iter().any(|ty| ty.conservative_is_uninhabited(tcx)),
|
||||||
|
ty::Array(ty, len) => {
|
||||||
|
match len.val.try_to_scalar() {
|
||||||
|
// If the array is definitely non-empty, it's uninhabited if
|
||||||
|
// the type of its elements is uninhabited.
|
||||||
|
Some(n) if !n.is_null() => ty.conservative_is_uninhabited(tcx),
|
||||||
|
_ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::Ref(..) => {
|
||||||
|
// Though references to uninhabited types are trivially uninhabited
|
||||||
|
// theoretically, null references are permitted in unsafe code (as
|
||||||
|
// long as the value is not dereferenced), so we treat all references
|
||||||
|
// as inhabited.
|
||||||
|
false
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1546,7 +1546,7 @@ impl<'a, 'gcx, 'tcx> TypeChecker<'a, 'gcx, 'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
if !sig.output().conservative_is_uninhabited() {
|
if !sig.output().conservative_is_uninhabited(self.tcx()) {
|
||||||
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
span_mirbug!(self, term, "call to converging function {:?} w/o dest", sig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -331,7 +331,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
|
|||||||
func: fun,
|
func: fun,
|
||||||
args,
|
args,
|
||||||
cleanup: Some(cleanup),
|
cleanup: Some(cleanup),
|
||||||
destination: if expr.ty.conservative_is_uninhabited() {
|
destination: if expr.ty.conservative_is_uninhabited(this.hir.tcx()) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Some((destination.clone(), success))
|
Some((destination.clone(), success))
|
||||||
|
@ -230,7 +230,7 @@ impl<'a, 'tcx> MatchVisitor<'a, 'tcx> {
|
|||||||
let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
|
let scrutinee_is_uninhabited = if self.tcx.features().exhaustive_patterns {
|
||||||
self.tcx.is_ty_uninhabited_from(module, pat_ty)
|
self.tcx.is_ty_uninhabited_from(module, pat_ty)
|
||||||
} else {
|
} else {
|
||||||
pat_ty.conservative_is_uninhabited()
|
pat_ty.conservative_is_uninhabited(self.tcx)
|
||||||
};
|
};
|
||||||
if !scrutinee_is_uninhabited {
|
if !scrutinee_is_uninhabited {
|
||||||
// We know the type is inhabited, so this must be wrong
|
// We know the type is inhabited, so this must be wrong
|
||||||
|
Loading…
x
Reference in New Issue
Block a user