Skip to content

Commit

Permalink
We don't use tyerr anymore
Browse files Browse the repository at this point in the history
This however unearthed a bug, hence the FIXME and the workaround.
  • Loading branch information
Nadrieril committed May 17, 2020
1 parent 8f08b16 commit e5a2cd5
Show file tree
Hide file tree
Showing 3 changed files with 46 additions and 35 deletions.
37 changes: 3 additions & 34 deletions src/librustc_mir_build/hair/pattern/_match.rs
Expand Up @@ -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};
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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());

Expand Down
22 changes: 21 additions & 1 deletion src/librustc_mir_build/hair/pattern/check_match.rs
Expand Up @@ -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();
Expand Down
@@ -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() {}

0 comments on commit e5a2cd5

Please sign in to comment.