Skip to content

Commit e5a2cd5

Browse files
committed
We don't use tyerr anymore
This however unearthed a bug, hence the FIXME and the workaround.
1 parent 8f08b16 commit e5a2cd5

File tree

3 files changed

+46
-35
lines changed

3 files changed

+46
-35
lines changed

src/librustc_mir_build/hair/pattern/_match.rs

+3-34
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ use rustc_hir::{HirId, RangeEnd};
242242
use rustc_middle::mir::interpret::{truncate, AllocId, ConstValue, Pointer, Scalar};
243243
use rustc_middle::mir::Field;
244244
use rustc_middle::ty::layout::IntegerExt;
245-
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeFoldable};
245+
use rustc_middle::ty::{self, Const, Ty, TyCtxt};
246246
use rustc_session::lint;
247247
use rustc_span::{Span, DUMMY_SP};
248248
use rustc_target::abi::{Integer, Size, VariantIdx};
@@ -1739,11 +1739,7 @@ impl<'tcx> fmt::Debug for MissingConstructors<'tcx> {
17391739
/// to a set of such vectors `m` - this is defined as there being a set of
17401740
/// inputs that will match `v` but not any of the sets in `m`.
17411741
///
1742-
/// All the patterns at each column of the `matrix ++ v` matrix must
1743-
/// have the same type, except that wildcard (PatKind::Wild) patterns
1744-
/// with type `TyErr` are also allowed, even if the "type of the column"
1745-
/// is not `TyErr`. That is used to represent private fields, as using their
1746-
/// real type would assert that they are inhabited.
1742+
/// All the patterns at each column of the `matrix ++ v` matrix must have the same type.
17471743
///
17481744
/// This is used both for reachability checking (if a pattern isn't useful in
17491745
/// relation to preceding patterns, it is not reachable) and exhaustiveness
@@ -1807,34 +1803,7 @@ crate fn is_useful<'p, 'tcx>(
18071803
return if any_is_useful { Useful(unreachable_pats) } else { NotUseful };
18081804
}
18091805

1810-
let (ty, span) = matrix
1811-
.heads()
1812-
.map(|r| (r.ty, r.span))
1813-
.find(|(ty, _)| !ty.references_error())
1814-
.unwrap_or((v.head().ty, v.head().span));
1815-
let pcx = PatCtxt {
1816-
// TyErr is used to represent the type of wildcard patterns matching
1817-
// against inaccessible (private) fields of structs, so that we won't
1818-
// be able to observe whether the types of the struct's fields are
1819-
// inhabited.
1820-
//
1821-
// If the field is truly inaccessible, then all the patterns
1822-
// matching against it must be wildcard patterns, so its type
1823-
// does not matter.
1824-
//
1825-
// However, if we are matching against non-wildcard patterns, we
1826-
// need to know the real type of the field so we can specialize
1827-
// against it. This primarily occurs through constants - they
1828-
// can include contents for fields that are inaccessible at the
1829-
// location of the match. In that case, the field's type is
1830-
// inhabited - by the constant - so we can just use it.
1831-
//
1832-
// FIXME: this might lead to "unstable" behavior with macro hygiene
1833-
// introducing uninhabited patterns for inaccessible fields. We
1834-
// need to figure out how to model that.
1835-
ty,
1836-
span,
1837-
};
1806+
let pcx = PatCtxt { ty: v.head().ty, span: v.head().span };
18381807

18391808
debug!("is_useful_expand_first_col: pcx={:#?}, expanding {:#?}", pcx, v.head());
18401809

src/librustc_mir_build/hair/pattern/check_match.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,28 @@ impl<'tcx> MatchVisitor<'_, 'tcx> {
186186
// Fourth, check for unreachable arms.
187187
let matrix = check_arms(&mut cx, &inlined_arms, source);
188188

189-
// Fifth, check if the match is exhaustive.
189+
// FIXME: getting the type using `node_type` means that if `f` has output type `!`, we
190+
// get `scrut_ty = !` instead of `bool` in the following:
191+
// ```
192+
// fn from(never: !) -> usize {
193+
// match never {
194+
// true => 1,
195+
// false => 0,
196+
// }
197+
// }
198+
// ```
199+
// If we use `expr_ty_adjusted` instead, then the following breaks, because we get
200+
// `scrut_ty = ()` instead of `!`.
201+
// ```
202+
// fn from(never: !) -> usize {
203+
// match never {}
204+
// }
205+
// ```
206+
// As a workaround, we retrieve the type from the match arms when possible.
190207
let scrut_ty = self.tables.node_type(scrut.hir_id);
208+
let scrut_ty = inlined_arms.iter().map(|(p, _, _)| p.ty).next().unwrap_or(scrut_ty);
209+
210+
// Fifth, check if the match is exhaustive.
191211
// Note: An empty match isn't the same as an empty matrix for diagnostics purposes,
192212
// since an empty matrix can occur when there are arms, if those arms all have guards.
193213
let is_empty_match = inlined_arms.is_empty();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// check-pass
2+
3+
// In PR 71930, it was discovered that the code to retrieve the inferred type of a match scrutinee
4+
// was incorrect.
5+
6+
fn f() -> ! {
7+
panic!()
8+
}
9+
10+
fn g() -> usize {
11+
match f() { // Should infer type `bool`
12+
false => 0,
13+
true => 1,
14+
}
15+
}
16+
17+
fn h() -> usize {
18+
match f() { // Should infer type `!`
19+
}
20+
}
21+
22+
fn main() {}

0 commit comments

Comments
 (0)