diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:44 +0000 |
commit | c23a457e72abe608715ac76f076f47dc42af07a5 (patch) | |
tree | 2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_mir_build/src/thir | |
parent | Releasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-c23a457e72abe608715ac76f076f47dc42af07a5.tar.xz rustc-c23a457e72abe608715ac76f076f47dc42af07a5.zip |
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_build/src/thir')
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() |