pattern lowering, yeet TypingEnv::from_param_env

This commit is contained in:
lcnr 2024-11-19 17:05:23 +01:00
parent decf37bd16
commit 07a5272476
3 changed files with 38 additions and 63 deletions

View File

@ -123,7 +123,7 @@ impl<'tcx> Cx<'tcx> {
#[instrument(level = "debug", skip(self))]
fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
pat_from_hir(self.tcx, self.param_env, self.typeck_results(), p)
pat_from_hir(self.tcx, self.typing_env(), self.typeck_results(), p)
}
fn closure_env_param(&self, owner_def: LocalDefId, expr_id: HirId) -> Option<Param<'tcx>> {

View File

@ -2,11 +2,11 @@ use rustc_abi::{FieldIdx, VariantIdx};
use rustc_apfloat::Float;
use rustc_hir as hir;
use rustc_index::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::Obligation;
use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::{FieldPat, Pat, PatKind};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, TypingMode, ValTree};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt, ValTree};
use rustc_middle::{mir, span_bug};
use rustc_span::Span;
use rustc_trait_selection::traits::ObligationCause;
@ -35,10 +35,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
id: hir::HirId,
span: Span,
) -> Box<Pat<'tcx>> {
// FIXME(#132279): We likely want to be able to reveal the hidden types
// of opaques defined in this function here.
let infcx = self.tcx.infer_ctxt().build(TypingMode::non_body_analysis());
let mut convert = ConstToPat::new(self, id, span, infcx);
let mut convert = ConstToPat::new(self, id, span);
match c.kind() {
ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
@ -49,27 +46,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
}
struct ConstToPat<'tcx> {
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
span: Span,
// inference context used for checking `T: Structural` bounds.
infcx: InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
treat_byte_string_as_slice: bool,
}
impl<'tcx> ConstToPat<'tcx> {
fn new(
pat_ctxt: &PatCtxt<'_, 'tcx>,
id: hir::HirId,
span: Span,
infcx: InferCtxt<'tcx>,
) -> Self {
fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span) -> Self {
trace!(?pat_ctxt.typeck_results.hir_owner);
ConstToPat {
tcx: pat_ctxt.tcx,
typing_env: pat_ctxt.typing_env,
span,
infcx,
param_env: pat_ctxt.param_env,
treat_byte_string_as_slice: pat_ctxt
.typeck_results
.treat_byte_string_as_slice
@ -77,16 +67,8 @@ impl<'tcx> ConstToPat<'tcx> {
}
}
fn tcx(&self) -> TyCtxt<'tcx> {
self.infcx.tcx
}
fn typing_env(&self) -> ty::TypingEnv<'tcx> {
self.infcx.typing_env(self.param_env)
}
fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool {
ty.is_structural_eq_shallow(self.infcx.tcx)
ty.is_structural_eq_shallow(self.tcx)
}
fn unevaluated_to_pat(
@ -105,22 +87,21 @@ impl<'tcx> ConstToPat<'tcx> {
// FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
// instead of having this logic here
let typing_env =
self.tcx().erase_regions(self.typing_env()).with_reveal_all_normalized(self.tcx());
let uv = self.tcx().erase_regions(uv);
self.tcx.erase_regions(self.typing_env).with_reveal_all_normalized(self.tcx);
let uv = self.tcx.erase_regions(uv);
// try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const.
let valtree = match self.infcx.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span)
{
let valtree = match self.tcx.const_eval_resolve_for_typeck(typing_env, uv, self.span) {
Ok(Ok(c)) => c,
Err(ErrorHandled::Reported(_, _)) => {
// Let's tell the use where this failing const occurs.
let e = self.tcx().dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
let e = self.tcx.dcx().emit_err(CouldNotEvalConstPattern { span: self.span });
return pat_from_kind(PatKind::Error(e));
}
Err(ErrorHandled::TooGeneric(_)) => {
let e = self
.tcx()
.tcx
.dcx()
.emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
return pat_from_kind(PatKind::Error(e));
@ -130,13 +111,13 @@ impl<'tcx> ConstToPat<'tcx> {
let e = match bad_ty.kind() {
ty::Adt(def, ..) => {
assert!(def.is_union());
self.tcx().dcx().emit_err(UnionPattern { span: self.span })
self.tcx.dcx().emit_err(UnionPattern { span: self.span })
}
ty::FnPtr(..) | ty::RawPtr(..) => {
self.tcx().dcx().emit_err(PointerPattern { span: self.span })
self.tcx.dcx().emit_err(PointerPattern { span: self.span })
}
_ => self
.tcx()
.tcx
.dcx()
.emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }),
};
@ -151,7 +132,7 @@ impl<'tcx> ConstToPat<'tcx> {
// Always check for `PartialEq` if we had no other errors yet.
if !self.type_has_partial_eq_impl(ty) {
let err = TypeNotPartialEq { span: self.span, non_peq_ty: ty };
let e = self.tcx().dcx().emit_err(err);
let e = self.tcx.dcx().emit_err(err);
return pat_from_kind(PatKind::Error(e));
}
}
@ -161,18 +142,19 @@ impl<'tcx> ConstToPat<'tcx> {
#[instrument(level = "trace", skip(self), ret)]
fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool {
let tcx = self.tcx();
let (infcx, param_env) = self.tcx.infer_ctxt().build_with_typing_env(self.typing_env);
// double-check there even *is* a semantic `PartialEq` to dispatch to.
//
// (If there isn't, then we can safely issue a hard
// error, because that's never worked, due to compiler
// using `PartialEq::eq` in this scenario in the past.)
let partial_eq_trait_id = tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span));
let partial_eq_trait_id =
self.tcx.require_lang_item(hir::LangItem::PartialEq, Some(self.span));
let partial_eq_obligation = Obligation::new(
tcx,
self.tcx,
ObligationCause::dummy(),
self.param_env,
ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]),
param_env,
ty::TraitRef::new(self.tcx, partial_eq_trait_id, [ty, ty]),
);
// This *could* accept a type that isn't actually `PartialEq`, because region bounds get
@ -181,7 +163,7 @@ impl<'tcx> ConstToPat<'tcx> {
// `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)
infcx.predicate_must_hold_modulo_regions(&partial_eq_obligation)
}
fn field_pats(
@ -192,7 +174,7 @@ impl<'tcx> ConstToPat<'tcx> {
.map(|(idx, (val, ty))| {
let field = FieldIdx::new(idx);
// Patterns can only use monomorphic types.
let ty = self.tcx().normalize_erasing_regions(self.typing_env(), ty);
let ty = self.tcx.normalize_erasing_regions(self.typing_env, ty);
FieldPat { field, pattern: self.valtree_to_pat(val, ty) }
})
.collect()
@ -202,12 +184,12 @@ impl<'tcx> ConstToPat<'tcx> {
#[instrument(skip(self), level = "debug")]
fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
let span = self.span;
let tcx = self.tcx();
let tcx = self.tcx;
let kind = match ty.kind() {
ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => {
// Extremely important check for all ADTs! Make sure they opted-in to be used in
// patterns.
debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty,);
debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, ty);
let err = TypeNotStructural { span, non_sm_ty: ty };
let e = tcx.dcx().emit_err(err);
// We errored. Signal that in the pattern, so that follow up errors can be silenced.
@ -225,7 +207,7 @@ impl<'tcx> ConstToPat<'tcx> {
adt_def.variants()[variant_index]
.fields
.iter()
.map(|field| field.ty(self.tcx(), args)),
.map(|field| field.ty(self.tcx, args)),
),
),
}
@ -233,14 +215,9 @@ impl<'tcx> ConstToPat<'tcx> {
ty::Adt(def, args) => {
assert!(!def.is_union()); // Valtree construction would never succeed for unions.
PatKind::Leaf {
subpatterns: self.field_pats(
cv.unwrap_branch().iter().copied().zip(
def.non_enum_variant()
.fields
.iter()
.map(|field| field.ty(self.tcx(), args)),
),
),
subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(
def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx, args)),
)),
}
}
ty::Tuple(fields) => PatKind::Leaf {
@ -274,9 +251,7 @@ impl<'tcx> ConstToPat<'tcx> {
// convert the dereferenced constant to a pattern that is the sub-pattern of the
// deref pattern.
_ => {
if !pointee_ty.is_sized(tcx, self.infcx.typing_env(self.param_env))
&& !pointee_ty.is_slice()
{
if !pointee_ty.is_sized(tcx, self.typing_env) && !pointee_ty.is_slice() {
let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
let e = tcx.dcx().emit_err(err);
// We errored. Signal that in the pattern, so that follow up errors can be silenced.

View File

@ -30,7 +30,7 @@ use crate::thir::util::UserAnnotatedTyHelpers;
struct PatCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
/// Used by the Rust 2024 migration lint.
@ -39,13 +39,13 @@ struct PatCtxt<'a, 'tcx> {
pub(super) fn pat_from_hir<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>,
pat: &'tcx hir::Pat<'tcx>,
) -> Box<Pat<'tcx>> {
let mut pcx = PatCtxt {
tcx,
param_env,
typing_env,
typeck_results,
rust_2024_migration_suggestion: typeck_results
.rust_2024_migration_desugared_pats()
@ -242,7 +242,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity);
let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity);
let cmp = lo.compare_with(hi, ty, self.tcx, ty::TypingEnv::from_param_env(self.param_env));
let cmp = lo.compare_with(hi, ty, self.tcx, self.typing_env);
let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty }));
match (end, cmp) {
// `x..y` where `x < y`.