We don't use tyerr anymore
This however unearthed a bug, hence the FIXME and the workaround.
This commit is contained in:
parent
8f08b16c03
commit
e5a2cd526a
3 changed files with 46 additions and 35 deletions
|
|
@ -242,7 +242,7 @@ use rustc_hir::{HirId, RangeEnd};
|
|||
use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
|
||||
use rustc_middle::mir::Field;
|
||||
use rustc_middle::ty::layout::IntegerExt;
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeFoldable};
|
||||
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
|
||||
use rustc_session::lint;
|
||||
use rustc_span::{Span, DUMMY_SP};
|
||||
use rustc_target::abi::{Integer, Size, VariantIdx};
|
||||
|
|
@ -1739,11 +1739,7 @@ impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
|
|||
/// to a set of such vectors `m` - this is defined as there being a set of
|
||||
/// inputs that will match `v` but not any of the sets in `m`.
|
||||
///
|
||||
/// All the patterns at each column of the `matrix ++ v` matrix must
|
||||
/// have the same type, except that wildcard (PatKind::Wild) patterns
|
||||
/// with type `TyErr` are also allowed, even if the "type of the column"
|
||||
/// is not `TyErr`. That is used to represent private fields, as using their
|
||||
/// real type would assert that they are inhabited.
|
||||
/// All the patterns at each column of the `matrix ++ v` matrix must have the same type.
|
||||
///
|
||||
/// This is used both for reachability checking (if a pattern isn't useful in
|
||||
/// relation to preceding patterns, it is not reachable) and exhaustiveness
|
||||
|
|
@ -1807,34 +1803,7 @@ crate fn is_useful<'p, 'tcx>(
|
|||
return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
|
||||
}
|
||||
|
||||
let (ty, span) = matrix
|
||||
.heads()
|
||||
.map(|r| (r.ty, r.span))
|
||||
.find(|(ty, _)| !ty.references_error())
|
||||
.unwrap_or((v.head().ty, v.head().span));
|
||||
let pcx = PatCtxt {
|
||||
// TyErr is used to represent the type of wildcard patterns matching
|
||||
// against inaccessible (private) fields of structs, so that we won't
|
||||
// be able to observe whether the types of the struct's fields are
|
||||
// inhabited.
|
||||
//
|
||||
// If the field is truly inaccessible, then all the patterns
|
||||
// matching against it must be wildcard patterns, so its type
|
||||
// does not matter.
|
||||
//
|
||||
// However, if we are matching against non-wildcard patterns, we
|
||||
// need to know the real type of the field so we can specialize
|
||||
// against it. This primarily occurs through constants - they
|
||||
// can include contents for fields that are inaccessible at the
|
||||
// location of the match. In that case, the field's type is
|
||||
// inhabited - by the constant - so we can just use it.
|
||||
//
|
||||
// FIXME: this might lead to "unstable" behavior with macro hygiene
|
||||
// introducing uninhabited patterns for inaccessible fields. We
|
||||
// need to figure out how to model that.
|
||||
ty,
|
||||
span,
|
||||
};
|
||||
let pcx = PatCtxt { ty: v.head().ty, span: v.head().span };
|
||||
|
||||
debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
|
||||
|
||||
|
|
|
|||
|
|
@ -186,8 +186,28 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
|
|||
// Fourth, check for unreachable arms.
|
||||
let matrix = check_arms(&mut cx, &inlined_arms, source);
|
||||
|
||||
// Fifth, check if the match is exhaustive.
|
||||
// FIXME: getting the type using `node_type` means that if `f` has output type `!`, we
|
||||
// get `scrut_ty = !` instead of `bool` in the following:
|
||||
// ```
|
||||
// fn from(never: !) -> usize {
|
||||
// match never {
|
||||
// true => 1,
|
||||
// false => 0,
|
||||
// }
|
||||
// }
|
||||
// ```
|
||||
// If we use `expr_ty_adjusted` instead, then the following breaks, because we get
|
||||
// `scrut_ty = ()` instead of `!`.
|
||||
// ```
|
||||
// fn from(never: !) -> usize {
|
||||
// match never {}
|
||||
// }
|
||||
// ```
|
||||
// As a workaround, we retrieve the type from the match arms when possible.
|
||||
let scrut_ty = self.tables.node_type(scrut.hir_id);
|
||||
let scrut_ty = inlined_arms.iter().map(|(p, _, _)| p.ty).next().unwrap_or(scrut_ty);
|
||||
|
||||
// Fifth, check if the match is exhaustive.
|
||||
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
|
||||
// since an empty matrix can occur when there are arms, if those arms all have guards.
|
||||
let is_empty_match = inlined_arms.is_empty();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
// check-pass
|
||||
|
||||
// In PR 71930, it was discovered that the code to retrieve the inferred type of a match scrutinee
|
||||
// was incorrect.
|
||||
|
||||
fn f() -> ! {
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn g() -> usize {
|
||||
match f() { // Should infer type `bool`
|
||||
false => 0,
|
||||
true => 1,
|
||||
}
|
||||
}
|
||||
|
||||
fn h() -> usize {
|
||||
match f() { // Should infer type `!`
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Add table
Add a link
Reference in a new issue