summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/thir
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_mir_build/src/thir')
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs16
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs58
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs87
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs18
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs64
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs49
6 files changed, 165 insertions, 127 deletions
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 6c1f7d7a6..16a85d427 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -647,21 +647,15 @@ impl<'tcx> Cx<'tcx> {
out_expr: out_expr.map(|expr| self.mirror_expr(expr)),
},
hir::InlineAsmOperand::Const { ref anon_const } => {
- let value = mir::ConstantKind::from_anon_const(
- tcx,
- anon_const.def_id,
- self.param_env,
- );
+ let value =
+ mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env);
let span = tcx.def_span(anon_const.def_id);
InlineAsmOperand::Const { value, span }
}
hir::InlineAsmOperand::SymFn { ref anon_const } => {
- let value = mir::ConstantKind::from_anon_const(
- tcx,
- anon_const.def_id,
- self.param_env,
- );
+ let value =
+ mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env);
let span = tcx.def_span(anon_const.def_id);
InlineAsmOperand::SymFn { value, span }
@@ -950,7 +944,7 @@ impl<'tcx> Cx<'tcx> {
let kind = if self.tcx.is_thread_local_static(id) {
ExprKind::ThreadLocalRef(id)
} else {
- let alloc_id = self.tcx.create_static_alloc(id);
+ let alloc_id = self.tcx.reserve_and_set_static_alloc(id);
ExprKind::StaticRef { alloc_id, ty, def_id: id }
};
ExprKind::Deref {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 383e80851..d440ca319 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -7,6 +7,7 @@ use crate::errors::*;
use rustc_arena::TypedArena;
use rustc_ast::Mutability;
+use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, MultiSpan,
@@ -660,6 +661,17 @@ fn report_arm_reachability<'p, 'tcx>(
}
}
+fn collect_non_exhaustive_tys<'p, 'tcx>(
+ pat: &DeconstructedPat<'p, 'tcx>,
+ non_exhaustive_tys: &mut FxHashSet<Ty<'tcx>>,
+) {
+ if matches!(pat.ctor(), Constructor::NonExhaustive) {
+ non_exhaustive_tys.insert(pat.ty());
+ }
+ pat.iter_fields()
+ .for_each(|field_pat| collect_non_exhaustive_tys(field_pat, non_exhaustive_tys))
+}
+
/// Report that a match is not exhaustive.
fn non_exhaustive_match<'p, 'tcx>(
cx: &MatchCheckCtxt<'p, 'tcx>,
@@ -708,31 +720,33 @@ fn non_exhaustive_match<'p, 'tcx>(
};
};
- let is_variant_list_non_exhaustive = matches!(scrut_ty.kind(),
- ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local());
-
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
- err.note(format!(
- "the matched value is of type `{}`{}",
- scrut_ty,
- if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" }
- ));
- if (scrut_ty == cx.tcx.types.usize || scrut_ty == cx.tcx.types.isize)
- && !is_empty_match
- && witnesses.len() == 1
- && matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
- {
- err.note(format!(
- "`{scrut_ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
- exhaustively",
- ));
- if cx.tcx.sess.is_nightly_build() {
- err.help(format!(
- "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
- enable precise `{scrut_ty}` matching",
- ));
+ err.note(format!("the matched value is of type `{}`", scrut_ty));
+
+ if !is_empty_match && witnesses.len() == 1 {
+ let mut non_exhaustive_tys = FxHashSet::default();
+ collect_non_exhaustive_tys(&witnesses[0], &mut non_exhaustive_tys);
+
+ for ty in non_exhaustive_tys {
+ if ty.is_ptr_sized_integral() {
+ err.note(format!(
+ "`{ty}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
+ exhaustively",
+ ));
+ if cx.tcx.sess.is_nightly_build() {
+ err.help(format!(
+ "add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
+ enable precise `{ty}` matching",
+ ));
+ }
+ } else if ty == cx.tcx.types.str_ {
+ err.note("`&str` cannot be matched exhaustively, so a wildcard `_` is necessary");
+ } else if cx.is_foreign_non_exhaustive_enum(ty) {
+ err.note(format!("`{ty}` is marked as non-exhaustive, so a wildcard `_` is necessary to match exhaustively"));
+ }
}
}
+
if let ty::Ref(_, sub_ty, _) = scrut_ty.kind() {
if !sub_ty.is_inhabited_from(cx.tcx, cx.module, cx.param_env) {
err.note("references are always considered inhabited");
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 1376344cf..ae4424660 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -16,18 +16,20 @@ use std::cell::Cell;
use super::PatCtxt;
use crate::errors::{
- FloatPattern, IndirectStructuralMatch, InvalidPattern, NontrivialStructuralMatch,
- PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
+ FloatPattern, IndirectStructuralMatch, InvalidPattern, NonPartialEqMatch,
+ NontrivialStructuralMatch, PointerPattern, TypeNotStructural, UnionPattern, UnsizedPattern,
};
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
/// Converts an evaluated constant to a pattern (if possible).
/// This means aggregate values (like structs and enums) are converted
/// to a pattern that matches the value (as if you'd compared via structural equality).
+ ///
+ /// `cv` must be a valtree or a `mir::ConstValue`.
#[instrument(level = "debug", skip(self), ret)]
pub(super) fn const_to_pat(
&self,
- cv: mir::ConstantKind<'tcx>,
+ cv: mir::Const<'tcx>,
id: hir::HirId,
span: Span,
check_body_for_struct_match_violation: Option<DefId>,
@@ -64,12 +66,10 @@ struct ConstToPat<'tcx> {
}
/// This error type signals that we encountered a non-struct-eq situation.
-/// We bubble this up in order to get back to the reference destructuring and make that emit
-/// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq`
-/// on such patterns (since that function takes a reference) and not have to jump through any
-/// hoops to get a reference to the value.
+/// We will fall back to calling `PartialEq::eq` on such patterns,
+/// and exhaustiveness checking will consider them as matching nothing.
#[derive(Debug)]
-struct FallbackToConstRef;
+struct FallbackToOpaqueConst;
impl<'tcx> ConstToPat<'tcx> {
fn new(
@@ -104,7 +104,7 @@ impl<'tcx> ConstToPat<'tcx> {
fn to_pat(
&mut self,
- cv: mir::ConstantKind<'tcx>,
+ cv: mir::Const<'tcx>,
check_body_for_struct_match_violation: Option<DefId>,
) -> Box<Pat<'tcx>> {
trace!(self.treat_byte_string_as_slice);
@@ -124,7 +124,7 @@ impl<'tcx> ConstToPat<'tcx> {
debug!(?check_body_for_struct_match_violation, ?mir_structural_match_violation);
let inlined_const_as_pat = match cv {
- mir::ConstantKind::Ty(c) => match c.kind() {
+ mir::Const::Ty(c) => match c.kind() {
ty::ConstKind::Param(_)
| ty::ConstKind::Infer(_)
| ty::ConstKind::Bound(_, _)
@@ -136,7 +136,7 @@ impl<'tcx> ConstToPat<'tcx> {
}
ty::ConstKind::Value(valtree) => self
.recur(valtree, cv.ty(), mir_structural_match_violation.unwrap_or(false))
- .unwrap_or_else(|_| {
+ .unwrap_or_else(|_: FallbackToOpaqueConst| {
Box::new(Pat {
span: self.span,
ty: cv.ty(),
@@ -144,10 +144,10 @@ impl<'tcx> ConstToPat<'tcx> {
})
}),
},
- mir::ConstantKind::Unevaluated(_, _) => {
+ mir::Const::Unevaluated(_, _) => {
span_bug!(self.span, "unevaluated const in `to_pat`: {cv:?}")
}
- mir::ConstantKind::Val(_, _) => Box::new(Pat {
+ mir::Const::Val(_, _) => Box::new(Pat {
span: self.span,
ty: cv.ty(),
kind: PatKind::Constant { value: cv },
@@ -155,8 +155,9 @@ impl<'tcx> ConstToPat<'tcx> {
};
if !self.saw_const_match_error.get() {
- // If we were able to successfully convert the const to some pat,
- // double-check that all types in the const implement `Structural`.
+ // If we were able to successfully convert the const to some pat (possibly with some
+ // lints, but no errors), double-check that all types in the const implement
+ // `Structural` and `PartialEq`.
let structural =
traits::search_for_structural_match_violation(self.span, self.tcx(), cv.ty());
@@ -178,7 +179,7 @@ impl<'tcx> ConstToPat<'tcx> {
}
if let Some(non_sm_ty) = structural {
- if !self.type_may_have_partial_eq_impl(cv.ty()) {
+ if !self.type_has_partial_eq_impl(cv.ty()) {
if let ty::Adt(def, ..) = non_sm_ty.kind() {
if def.is_union() {
let err = UnionPattern { span: self.span };
@@ -192,8 +193,10 @@ impl<'tcx> ConstToPat<'tcx> {
} else {
let err = InvalidPattern { span: self.span, non_sm_ty };
self.tcx().sess.emit_err(err);
- return Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Wild });
}
+ // All branches above emitted an error. Don't print any more lints.
+ // The pattern we return is irrelevant since we errored.
+ return Box::new(Pat { span: self.span, ty: cv.ty(), kind: PatKind::Wild });
} else if !self.saw_const_match_lint.get() {
if let Some(mir_structural_match_violation) = mir_structural_match_violation {
match non_sm_ty.kind() {
@@ -238,13 +241,24 @@ impl<'tcx> ConstToPat<'tcx> {
_ => {}
}
}
+
+ // Always check for `PartialEq`, even if we emitted other lints. (But not if there were
+ // any errors.) This ensures it shows up in cargo's future-compat reports as well.
+ if !self.type_has_partial_eq_impl(cv.ty()) {
+ self.tcx().emit_spanned_lint(
+ lint::builtin::CONST_PATTERNS_WITHOUT_PARTIAL_EQ,
+ self.id,
+ self.span,
+ NonPartialEqMatch { non_peq_ty: cv.ty() },
+ );
+ }
}
inlined_const_as_pat
}
#[instrument(level = "trace", skip(self), ret)]
- fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
+ fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
// double-check there even *is* a semantic `PartialEq` to dispatch to.
//
// (If there isn't, then we can safely issue a hard
@@ -259,14 +273,19 @@ impl<'tcx> ConstToPat<'tcx> {
ty::TraitRef::new(self.tcx(), partial_eq_trait_id, [ty, ty]),
);
- // FIXME: should this call a `predicate_must_hold` variant instead?
- self.infcx.predicate_may_hold(&partial_eq_obligation)
+ // This *could* accept a type that isn't actually `PartialEq`, because region bounds get
+ // ignored. However that should be pretty much impossible since consts that do not depend on
+ // generics can only mention the `'static` lifetime, and how would one have a type that's
+ // `PartialEq` for some lifetime but *not* for `'static`? If this ever becomes a problem
+ // we'll need to leave some sort of trace of this requirement in the MIR so that borrowck
+ // can ensure that the type really implements `PartialEq`.
+ self.infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation)
}
fn field_pats(
&self,
vals: impl Iterator<Item = (ValTree<'tcx>, Ty<'tcx>)>,
- ) -> Result<Vec<FieldPat<'tcx>>, FallbackToConstRef> {
+ ) -> Result<Vec<FieldPat<'tcx>>, FallbackToOpaqueConst> {
vals.enumerate()
.map(|(idx, (val, ty))| {
let field = FieldIdx::new(idx);
@@ -284,7 +303,7 @@ impl<'tcx> ConstToPat<'tcx> {
cv: ValTree<'tcx>,
ty: Ty<'tcx>,
mir_structural_match_violation: bool,
- ) -> Result<Box<Pat<'tcx>>, FallbackToConstRef> {
+ ) -> Result<Box<Pat<'tcx>>, FallbackToOpaqueConst> {
let id = self.id;
let span = self.span;
let tcx = self.tcx();
@@ -299,7 +318,7 @@ impl<'tcx> ConstToPat<'tcx> {
span,
FloatPattern,
);
- return Err(FallbackToConstRef);
+ return Err(FallbackToOpaqueConst);
}
// If the type is not structurally comparable, just emit the constant directly,
// causing the pattern match code to treat it opaquely.
@@ -323,11 +342,12 @@ impl<'tcx> ConstToPat<'tcx> {
// Since we are behind a reference, we can just bubble the error up so we get a
// constant at reference type, making it easy to let the fallback call
// `PartialEq::eq` on it.
- return Err(FallbackToConstRef);
+ return Err(FallbackToOpaqueConst);
}
ty::FnDef(..) => {
self.saw_const_match_error.set(true);
tcx.sess.emit_err(InvalidPattern { span, non_sm_ty: ty });
+ // We errored, so the pattern we generate is irrelevant.
PatKind::Wild
}
ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
@@ -335,6 +355,7 @@ impl<'tcx> ConstToPat<'tcx> {
self.saw_const_match_error.set(true);
let err = TypeNotStructural { span, non_sm_ty: ty };
tcx.sess.emit_err(err);
+ // We errored, so the pattern we generate is irrelevant.
PatKind::Wild
}
ty::Adt(adt_def, args) if adt_def.is_enum() => {
@@ -385,9 +406,9 @@ impl<'tcx> ConstToPat<'tcx> {
ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() {
// `&str` is represented as a valtree, let's keep using this
// optimization for now.
- ty::Str => PatKind::Constant {
- value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
- },
+ ty::Str => {
+ PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
+ }
// Backwards compatibility hack: support references to non-structural types,
// but hard error if we aren't behind a double reference. We could just use
// the fallback code path below, but that would allow *more* of this fishy
@@ -404,13 +425,15 @@ impl<'tcx> ConstToPat<'tcx> {
IndirectStructuralMatch { non_sm_ty: *pointee_ty },
);
}
- return Err(FallbackToConstRef);
+ return Err(FallbackToOpaqueConst);
} else {
if !self.saw_const_match_error.get() {
self.saw_const_match_error.set(true);
let err = TypeNotStructural { span, non_sm_ty: *pointee_ty };
tcx.sess.emit_err(err);
}
+ tcx.sess.delay_span_bug(span, "`saw_const_match_error` set but no error?");
+ // We errored, so the pattern we generate is irrelevant.
PatKind::Wild
}
}
@@ -423,6 +446,7 @@ impl<'tcx> ConstToPat<'tcx> {
tcx.sess.emit_err(err);
// FIXME: introduce PatKind::Error to silence follow up diagnostics due to unreachable patterns.
+ // We errored, so the pattern we generate is irrelevant.
PatKind::Wild
} else {
let old = self.behind_reference.replace(true);
@@ -445,14 +469,15 @@ impl<'tcx> ConstToPat<'tcx> {
}
}
},
- ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => PatKind::Constant {
- value: mir::ConstantKind::Ty(ty::Const::new_value(tcx, cv, ty)),
- },
+ ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) => {
+ PatKind::Constant { value: mir::Const::Ty(ty::Const::new_value(tcx, cv, ty)) }
+ }
ty::FnPtr(..) | ty::RawPtr(..) => unreachable!(),
_ => {
self.saw_const_match_error.set(true);
let err = InvalidPattern { span, non_sm_ty: ty };
tcx.sess.emit_err(err);
+ // We errored, so the pattern we generate is irrelevant.
PatKind::Wild
}
};
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index bee1c4e46..b79beb1c5 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -137,16 +137,16 @@ impl IntRange {
fn from_constant<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- value: mir::ConstantKind<'tcx>,
+ value: mir::Const<'tcx>,
) -> Option<IntRange> {
let ty = value.ty();
let (target_size, bias) = Self::integral_size_and_signed_bias(tcx, ty)?;
let val = match value {
- mir::ConstantKind::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
+ mir::Const::Ty(c) if let ty::ConstKind::Value(valtree) = c.kind() => {
valtree.unwrap_leaf().to_bits(target_size).ok()
},
// This is a more general form of the previous case.
- _ => value.try_eval_bits(tcx, param_env, ty),
+ _ => value.try_eval_bits(tcx, param_env),
}?;
let val = val ^ bias;
@@ -225,8 +225,8 @@ impl IntRange {
let (lo, hi) = (lo ^ bias, hi ^ bias);
let env = ty::ParamEnv::empty().and(ty);
- let lo_const = mir::ConstantKind::from_bits(tcx, lo, env);
- let hi_const = mir::ConstantKind::from_bits(tcx, hi, env);
+ let lo_const = mir::Const::from_bits(tcx, lo, env);
+ let hi_const = mir::Const::from_bits(tcx, hi, env);
let kind = if lo == hi {
PatKind::Constant { value: lo_const }
@@ -619,9 +619,9 @@ pub(super) enum Constructor<'tcx> {
/// Ranges of integer literal values (`2`, `2..=5` or `2..5`).
IntRange(IntRange),
/// Ranges of floating-point literal values (`2.0..=5.2`).
- FloatRange(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>, RangeEnd),
+ FloatRange(mir::Const<'tcx>, mir::Const<'tcx>, RangeEnd),
/// String literals. Strings are not quite the same as `&[u8]` so we treat them separately.
- Str(mir::ConstantKind<'tcx>),
+ Str(mir::Const<'tcx>),
/// Array and slice patterns.
Slice(Slice),
/// Constants that must not be matched structurally. They are treated as black
@@ -1379,8 +1379,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> {
let ty = lo.ty();
ctor = if let Some(int_range) = IntRange::from_range(
cx.tcx,
- lo.eval_bits(cx.tcx, cx.param_env, lo.ty()),
- hi.eval_bits(cx.tcx, cx.param_env, hi.ty()),
+ lo.eval_bits(cx.tcx, cx.param_env),
+ hi.eval_bits(cx.tcx, cx.param_env),
ty,
&end,
) {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index c08fe54c3..fe47a1cd7 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -18,9 +18,9 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::RangeEnd;
use rustc_index::Idx;
use rustc_middle::mir::interpret::{
- ConstValue, ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
+ ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar,
};
-use rustc_middle::mir::{self, ConstantKind, UserTypeProjection};
+use rustc_middle::mir::{self, Const, UserTypeProjection};
use rustc_middle::mir::{BorrowKind, Mutability};
use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange};
use rustc_middle::ty::CanonicalUserTypeAnnotation;
@@ -100,8 +100,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern_range(
&mut self,
ty: Ty<'tcx>,
- lo: mir::ConstantKind<'tcx>,
- hi: mir::ConstantKind<'tcx>,
+ lo: mir::Const<'tcx>,
+ hi: mir::Const<'tcx>,
end: RangeEnd,
span: Span,
lo_expr: Option<&hir::Expr<'tcx>>,
@@ -131,7 +131,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
{
- if lo.eval_bits(self.tcx, self.param_env, ty) != val {
+ if lo.eval_bits(self.tcx, self.param_env) != val {
lower_overflow = true;
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
}
@@ -139,7 +139,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
{
- if hi.eval_bits(self.tcx, self.param_env, ty) != val {
+ if hi.eval_bits(self.tcx, self.param_env) != val {
higher_overflow = true;
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
}
@@ -162,7 +162,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = lo_expr
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
{
- if lo.eval_bits(self.tcx, self.param_env, ty) != val {
+ if lo.eval_bits(self.tcx, self.param_env) != val {
lower_overflow = true;
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
}
@@ -170,7 +170,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
if let Some(hir::Expr { kind: hir::ExprKind::Lit(lit), .. }) = hi_expr
&& let rustc_ast::ast::LitKind::Int(val, _) = lit.node
{
- if hi.eval_bits(self.tcx, self.param_env, ty) != val {
+ if hi.eval_bits(self.tcx, self.param_env) != val {
higher_overflow = true;
self.tcx.sess.emit_err(LiteralOutOfRange { span: lit.span, ty, max: max() });
}
@@ -191,18 +191,18 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
ty: Ty<'tcx>,
lo: Option<&PatKind<'tcx>>,
hi: Option<&PatKind<'tcx>>,
- ) -> Option<(mir::ConstantKind<'tcx>, mir::ConstantKind<'tcx>)> {
+ ) -> Option<(mir::Const<'tcx>, mir::Const<'tcx>)> {
match (lo, hi) {
(Some(PatKind::Constant { value: lo }), Some(PatKind::Constant { value: hi })) => {
Some((*lo, *hi))
}
(Some(PatKind::Constant { value: lo }), None) => {
let hi = ty.numeric_max_val(self.tcx)?;
- Some((*lo, mir::ConstantKind::from_const(hi, self.tcx)))
+ Some((*lo, mir::Const::from_ty_const(hi, self.tcx)))
}
(None, Some(PatKind::Constant { value: hi })) => {
let lo = ty.numeric_min_val(self.tcx)?;
- Some((mir::ConstantKind::from_const(lo, self.tcx), *hi))
+ Some((mir::Const::from_ty_const(lo, self.tcx), *hi))
}
_ => None,
}
@@ -439,7 +439,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
DefKind::Struct
| DefKind::Ctor(CtorOf::Struct, ..)
| DefKind::Union
- | DefKind::TyAlias { .. }
+ | DefKind::TyAlias
| DefKind::AssocTy,
_,
)
@@ -525,8 +525,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
.tcx
.const_eval_global_id_for_typeck(param_env_reveal_all, cid, Some(span))
.map(|val| match val {
- Some(valtree) => mir::ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
- None => mir::ConstantKind::Val(
+ Some(valtree) => mir::Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
+ None => mir::Const::Val(
self.tcx
.const_eval_global_id(param_env_reveal_all, cid, Some(span))
.expect("const_eval_global_id_for_typeck should have already failed"),
@@ -555,8 +555,8 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
subpattern: pattern,
ascription: Ascription {
annotation,
- /// Note that use `Contravariant` here. See the
- /// `variance` field documentation for details.
+ // Note that use `Contravariant` here. See the
+ // `variance` field documentation for details.
variance: ty::Variance::Contravariant,
},
},
@@ -566,7 +566,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
pattern
}
}
- Err(ErrorHandled::TooGeneric) => {
+ Err(ErrorHandled::TooGeneric(_)) => {
// While `Reported | Linted` cases will have diagnostics emitted already
// it is not true for TooGeneric case, so we need to give user more information.
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
@@ -608,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
};
if let Some(lit_input) = lit_input {
match tcx.at(expr.span).lit_to_const(lit_input) {
- Ok(c) => return self.const_to_pat(ConstantKind::Ty(c), id, span, None).kind,
+ Ok(c) => return self.const_to_pat(Const::Ty(c), id, span, None).kind,
// If an error occurred, ignore that it's a literal
// and leave reporting the error up to const eval of
// the unevaluated constant below.
@@ -626,11 +626,13 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), args: args };
// First try using a valtree in order to destructure the constant into a pattern.
+ // FIXME: replace "try to do a thing, then fall back to another thing"
+ // but something more principled, like a trait query checking whether this can be turned into a valtree.
if let Ok(Some(valtree)) =
self.tcx.const_eval_resolve_for_typeck(self.param_env, ct, Some(span))
{
self.const_to_pat(
- ConstantKind::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
+ Const::Ty(ty::Const::new_value(self.tcx, valtree, ty)),
id,
span,
None,
@@ -638,14 +640,14 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
.kind
} else {
// If that fails, convert it to an opaque constant pattern.
- match tcx.const_eval_resolve(self.param_env, uneval, None) {
- Ok(val) => self.const_to_pat(mir::ConstantKind::Val(val, ty), id, span, None).kind,
- Err(ErrorHandled::TooGeneric) => {
+ match tcx.const_eval_resolve(self.param_env, uneval, Some(span)) {
+ Ok(val) => self.const_to_pat(mir::Const::Val(val, ty), id, span, None).kind,
+ Err(ErrorHandled::TooGeneric(_)) => {
// If we land here it means the const can't be evaluated because it's `TooGeneric`.
self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span });
PatKind::Wild
}
- Err(ErrorHandled::Reported(_)) => PatKind::Wild,
+ Err(ErrorHandled::Reported(..)) => PatKind::Wild,
}
}
}
@@ -676,7 +678,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg };
match self.tcx.at(expr.span).lit_to_const(lit_input) {
Ok(constant) => {
- self.const_to_pat(ConstantKind::Ty(constant), expr.hir_id, lit.span, None).kind
+ self.const_to_pat(Const::Ty(constant), expr.hir_id, lit.span, None).kind
}
Err(LitToConstError::Reported(_)) => PatKind::Wild,
Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"),
@@ -836,8 +838,8 @@ impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> {
#[instrument(skip(tcx), level = "debug")]
pub(crate) fn compare_const_vals<'tcx>(
tcx: TyCtxt<'tcx>,
- a: mir::ConstantKind<'tcx>,
- b: mir::ConstantKind<'tcx>,
+ a: mir::Const<'tcx>,
+ b: mir::Const<'tcx>,
param_env: ty::ParamEnv<'tcx>,
) -> Option<Ordering> {
assert_eq!(a.ty(), b.ty());
@@ -853,18 +855,18 @@ pub(crate) fn compare_const_vals<'tcx>(
ty::Float(_) | ty::Int(_) => {} // require special handling, see below
_ => match (a, b) {
(
- mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(a)), _a_ty),
- mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(b)), _b_ty),
+ mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(a)), _a_ty),
+ mir::Const::Val(mir::ConstValue::Scalar(Scalar::Int(b)), _b_ty),
) => return Some(a.cmp(&b)),
- (mir::ConstantKind::Ty(a), mir::ConstantKind::Ty(b)) => {
+ (mir::Const::Ty(a), mir::Const::Ty(b)) => {
return Some(a.kind().cmp(&b.kind()));
}
_ => {}
},
}
- let a = a.eval_bits(tcx, param_env, ty);
- let b = b.eval_bits(tcx, param_env, ty);
+ let a = a.eval_bits(tcx, param_env);
+ let b = b.eval_bits(tcx, param_env);
use rustc_apfloat::Float;
match *ty.kind() {
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 08cfe98bb..21031e8ba 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -618,10 +618,15 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
let new_witnesses = if let Constructor::Missing { .. } = ctor {
// We got the special `Missing` constructor, so each of the missing constructors
// gives a new pattern that is not caught by the match. We list those patterns.
- let new_patterns = if pcx.is_non_exhaustive {
- // Here we don't want the user to try to list all variants, we want them to add
- // a wildcard, so we only suggest that.
- vec![DeconstructedPat::wildcard(pcx.ty, pcx.span)]
+ if pcx.is_non_exhaustive {
+ witnesses
+ .into_iter()
+ // Here we don't want the user to try to list all variants, we want them to add
+ // a wildcard, so we only suggest that.
+ .map(|witness| {
+ witness.apply_constructor(pcx, &Constructor::NonExhaustive)
+ })
+ .collect()
} else {
let mut split_wildcard = SplitWildcard::new(pcx);
split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor));
@@ -633,7 +638,7 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
// constructor, that matches everything that can be built with
// it. For example, if `ctor` is a `Constructor::Variant` for
// `Option::Some`, we get the pattern `Some(_)`.
- let mut new: Vec<DeconstructedPat<'_, '_>> = split_wildcard
+ let mut new_patterns: Vec<DeconstructedPat<'_, '_>> = split_wildcard
.iter_missing(pcx)
.filter_map(|missing_ctor| {
// Check if this variant is marked `doc(hidden)`
@@ -648,27 +653,25 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> {
.collect();
if hide_variant_show_wild {
- new.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
+ new_patterns.push(DeconstructedPat::wildcard(pcx.ty, pcx.span));
}
- new
- };
-
- witnesses
- .into_iter()
- .flat_map(|witness| {
- new_patterns.iter().map(move |pat| {
- Witness(
- witness
- .0
- .iter()
- .chain(once(pat))
- .map(DeconstructedPat::clone_and_forget_reachability)
- .collect(),
- )
+ witnesses
+ .into_iter()
+ .flat_map(|witness| {
+ new_patterns.iter().map(move |pat| {
+ Witness(
+ witness
+ .0
+ .iter()
+ .chain(once(pat))
+ .map(DeconstructedPat::clone_and_forget_reachability)
+ .collect(),
+ )
+ })
})
- })
- .collect()
+ .collect()
+ }
} else {
witnesses
.into_iter()