diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
commit | dc0db358abe19481e475e10c32149b53370f1a1c (patch) | |
tree | ab8ce99c4b255ce46f99ef402c27916055b899ee /compiler/rustc_mir_build/src/thir/pattern/mod.rs | |
parent | Releasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip |
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler/rustc_mir_build/src/thir/pattern/mod.rs')
-rw-r--r-- | compiler/rustc_mir_build/src/thir/pattern/mod.rs | 127 |
1 files changed, 91 insertions, 36 deletions
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index 1cf2f7ec0..600995927 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -18,14 +18,15 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::RangeEnd; use rustc_index::Idx; use rustc_middle::mir::interpret::{ - ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar, + ConstValue, ErrorHandled, GlobalId, LitToConstError, LitToConstInput, Scalar, }; -use rustc_middle::mir::{self, UserTypeProjection}; +use rustc_middle::mir::{self, ConstantKind, UserTypeProjection}; use rustc_middle::mir::{BorrowKind, Mutability}; use rustc_middle::thir::{Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange}; use rustc_middle::ty::subst::{GenericArg, SubstsRef}; use rustc_middle::ty::CanonicalUserTypeAnnotation; -use rustc_middle::ty::{self, AdtDef, ConstKind, Region, Ty, TyCtxt, UserType}; +use rustc_middle::ty::TypeVisitableExt; +use rustc_middle::ty::{self, AdtDef, Region, Ty, TyCtxt, UserType}; use rustc_span::{Span, Symbol}; use rustc_target::abi::FieldIdx; @@ -286,7 +287,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { ty::BindByValue(mutbl) => (mutbl, BindingMode::ByValue), ty::BindByReference(hir::Mutability::Mut) => ( Mutability::Not, - BindingMode::ByRef(BorrowKind::Mut { allow_two_phase_borrow: false }), + BindingMode::ByRef(BorrowKind::Mut { kind: mir::MutBorrowKind::Default }), ), ty::BindByReference(hir::Mutability::Not) => { (Mutability::Not, BindingMode::ByRef(BorrowKind::Shared)) @@ -518,16 +519,24 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } }; - // `mir_const_qualif` must be called with the `DefId` of the item where the const is - // defined, not where it is declared. The difference is significant for associated - // constants. - let mir_structural_match_violation = self.tcx.mir_const_qualif(instance.def_id()).custom_eq; - debug!("mir_structural_match_violation({:?}) -> {}", qpath, mir_structural_match_violation); - - match self.tcx.const_eval_instance(param_env_reveal_all, instance, Some(span)) { - Ok(literal) => { - let const_ = mir::ConstantKind::Val(literal, ty); - let pattern = self.const_to_pat(const_, id, span, mir_structural_match_violation); + let cid = GlobalId { instance, promoted: None }; + // Prefer valtrees over opaque constants. + let const_value = self + .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( + self.tcx + .const_eval_global_id(param_env_reveal_all, cid, Some(span)) + .expect("const_eval_global_id_for_typeck should have already failed"), + ty, + ), + }); + + match const_value { + Ok(const_) => { + let pattern = self.const_to_pat(const_, id, span, Some(instance.def_id())); if !is_associated_const { return pattern; @@ -573,31 +582,72 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { /// Converts inline const patterns. fn lower_inline_const( &mut self, - anon_const: &'tcx hir::AnonConst, + block: &'tcx hir::ConstBlock, id: hir::HirId, span: Span, ) -> PatKind<'tcx> { - let value = mir::ConstantKind::from_inline_const(self.tcx, anon_const.def_id); - - // Evaluate early like we do in `lower_path`. - let value = value.eval(self.tcx, self.param_env); - - match value { - mir::ConstantKind::Ty(c) => match c.kind() { - ConstKind::Param(_) => { - self.tcx.sess.emit_err(ConstParamInPattern { span }); - return PatKind::Wild; + let tcx = self.tcx; + let def_id = block.def_id; + let body_id = block.body; + let expr = &tcx.hir().body(body_id).value; + let ty = tcx.typeck(def_id).node_type(block.hir_id); + + // Special case inline consts that are just literals. This is solely + // a performance optimization, as we could also just go through the regular + // const eval path below. + // FIXME: investigate the performance impact of removing this. + let lit_input = match expr.kind { + hir::ExprKind::Lit(ref lit) => Some(LitToConstInput { lit: &lit.node, ty, neg: false }), + hir::ExprKind::Unary(hir::UnOp::Neg, ref expr) => match expr.kind { + hir::ExprKind::Lit(ref lit) => { + Some(LitToConstInput { lit: &lit.node, ty, neg: true }) } - ConstKind::Error(_) => { - return PatKind::Wild; - } - _ => bug!("Expected ConstKind::Param"), + _ => None, }, - mir::ConstantKind::Val(_, _) => self.const_to_pat(value, id, span, false).kind, - mir::ConstantKind::Unevaluated(..) => { - // If we land here it means the const can't be evaluated because it's `TooGeneric`. - self.tcx.sess.emit_err(ConstPatternDependsOnGenericParameter { span }); - return PatKind::Wild; + _ => None, + }; + 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, + // If an error occurred, ignore that it's a literal + // and leave reporting the error up to const eval of + // the unevaluated constant below. + Err(_) => {} + } + } + + let typeck_root_def_id = tcx.typeck_root_def_id(def_id.to_def_id()); + let parent_substs = + tcx.erase_regions(ty::InternalSubsts::identity_for_item(tcx, typeck_root_def_id)); + let substs = + ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty }) + .substs; + + let uneval = mir::UnevaluatedConst { def: def_id.to_def_id(), substs, promoted: None }; + debug_assert!(!substs.has_free_regions()); + + let ct = ty::UnevaluatedConst { def: def_id.to_def_id(), substs: substs }; + // First try using a valtree in order to destructure the constant into a pattern. + 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)), + id, + span, + None, + ) + .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) => { + // 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, } } } @@ -626,8 +676,10 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let lit_input = LitToConstInput { lit: &lit.node, ty: self.typeck_results.expr_ty(expr), neg }; - match self.tcx.at(expr.span).lit_to_mir_constant(lit_input) { - Ok(constant) => self.const_to_pat(constant, expr.hir_id, lit.span, false).kind, + 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 + } Err(LitToConstError::Reported(_)) => PatKind::Wild, Err(LitToConstError::TypeError) => bug!("lower_lit: had type error"), } @@ -806,6 +858,9 @@ pub(crate) fn compare_const_vals<'tcx>( mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(a)), _a_ty), mir::ConstantKind::Val(ConstValue::Scalar(Scalar::Int(b)), _b_ty), ) => return Some(a.cmp(&b)), + (mir::ConstantKind::Ty(a), mir::ConstantKind::Ty(b)) => { + return Some(a.kind().cmp(&b.kind())); + } _ => {} }, } |