summaryrefslogtreecommitdiffstats
path: root/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-30 18:31:44 +0000
commitc23a457e72abe608715ac76f076f47dc42af07a5 (patch)
tree2772049aaf84b5c9d0ed12ec8d86812f7a7904b6 /compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
parentReleasing progress-linux version 1.73.0+dfsg1-1~progress7.99u1. (diff)
downloadrustc-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/pattern/const_to_pat.rs')
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs87
1 files changed, 56 insertions, 31 deletions
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
}
};