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))] #[instrument(level = "debug", skip(self))]
fn pattern_from_hir(&mut self, p: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> { 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>> { 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_apfloat::Float;
use rustc_hir as hir; use rustc_hir as hir;
use rustc_index::Idx; use rustc_index::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::Obligation; use rustc_infer::traits::Obligation;
use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::mir::interpret::ErrorHandled;
use rustc_middle::thir::{FieldPat, Pat, PatKind}; 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_middle::{mir, span_bug};
use rustc_span::Span; use rustc_span::Span;
use rustc_trait_selection::traits::ObligationCause; use rustc_trait_selection::traits::ObligationCause;
@ -35,10 +35,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
id: hir::HirId, id: hir::HirId,
span: Span, span: Span,
) -> Box<Pat<'tcx>> { ) -> Box<Pat<'tcx>> {
// FIXME(#132279): We likely want to be able to reveal the hidden types let mut convert = ConstToPat::new(self, id, span);
// 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);
match c.kind() { match c.kind() {
ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty), ty::ConstKind::Unevaluated(uv) => convert.unevaluated_to_pat(uv, ty),
@ -49,27 +46,20 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
} }
struct ConstToPat<'tcx> { struct ConstToPat<'tcx> {
tcx: TyCtxt<'tcx>,
typing_env: ty::TypingEnv<'tcx>,
span: Span, span: Span,
// inference context used for checking `T: Structural` bounds.
infcx: InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
treat_byte_string_as_slice: bool, treat_byte_string_as_slice: bool,
} }
impl<'tcx> ConstToPat<'tcx> { impl<'tcx> ConstToPat<'tcx> {
fn new( fn new(pat_ctxt: &PatCtxt<'_, 'tcx>, id: hir::HirId, span: Span) -> Self {
pat_ctxt: &PatCtxt<'_, 'tcx>,
id: hir::HirId,
span: Span,
infcx: InferCtxt<'tcx>,
) -> Self {
trace!(?pat_ctxt.typeck_results.hir_owner); trace!(?pat_ctxt.typeck_results.hir_owner);
ConstToPat { ConstToPat {
tcx: pat_ctxt.tcx,
typing_env: pat_ctxt.typing_env,
span, span,
infcx,
param_env: pat_ctxt.param_env,
treat_byte_string_as_slice: pat_ctxt treat_byte_string_as_slice: pat_ctxt
.typeck_results .typeck_results
.treat_byte_string_as_slice .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 { 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( 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` // FIXME: `const_eval_resolve_for_typeck` should probably just set the env to `Reveal::All`
// instead of having this logic here // instead of having this logic here
let typing_env = let typing_env =
self.tcx().erase_regions(self.typing_env()).with_reveal_all_normalized(self.tcx()); self.tcx.erase_regions(self.typing_env).with_reveal_all_normalized(self.tcx);
let uv = self.tcx().erase_regions(uv); let uv = self.tcx.erase_regions(uv);
// try to resolve e.g. associated constants to their definition on an impl, and then // try to resolve e.g. associated constants to their definition on an impl, and then
// evaluate the const. // 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, Ok(Ok(c)) => c,
Err(ErrorHandled::Reported(_, _)) => { Err(ErrorHandled::Reported(_, _)) => {
// Let's tell the use where this failing const occurs. // 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)); return pat_from_kind(PatKind::Error(e));
} }
Err(ErrorHandled::TooGeneric(_)) => { Err(ErrorHandled::TooGeneric(_)) => {
let e = self let e = self
.tcx() .tcx
.dcx() .dcx()
.emit_err(ConstPatternDependsOnGenericParameter { span: self.span }); .emit_err(ConstPatternDependsOnGenericParameter { span: self.span });
return pat_from_kind(PatKind::Error(e)); return pat_from_kind(PatKind::Error(e));
@ -130,13 +111,13 @@ impl<'tcx> ConstToPat<'tcx> {
let e = match bad_ty.kind() { let e = match bad_ty.kind() {
ty::Adt(def, ..) => { ty::Adt(def, ..) => {
assert!(def.is_union()); 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(..) => { ty::FnPtr(..) | ty::RawPtr(..) => {
self.tcx().dcx().emit_err(PointerPattern { span: self.span }) self.tcx.dcx().emit_err(PointerPattern { span: self.span })
} }
_ => self _ => self
.tcx() .tcx
.dcx() .dcx()
.emit_err(InvalidPattern { span: self.span, non_sm_ty: bad_ty }), .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. // Always check for `PartialEq` if we had no other errors yet.
if !self.type_has_partial_eq_impl(ty) { if !self.type_has_partial_eq_impl(ty) {
let err = TypeNotPartialEq { span: self.span, non_peq_ty: 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)); return pat_from_kind(PatKind::Error(e));
} }
} }
@ -161,18 +142,19 @@ impl<'tcx> ConstToPat<'tcx> {
#[instrument(level = "trace", skip(self), ret)] #[instrument(level = "trace", skip(self), ret)]
fn type_has_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { 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. // double-check there even *is* a semantic `PartialEq` to dispatch to.
// //
// (If there isn't, then we can safely issue a hard // (If there isn't, then we can safely issue a hard
// error, because that's never worked, due to compiler // error, because that's never worked, due to compiler
// using `PartialEq::eq` in this scenario in the past.) // 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( let partial_eq_obligation = Obligation::new(
tcx, self.tcx,
ObligationCause::dummy(), ObligationCause::dummy(),
self.param_env, param_env,
ty::TraitRef::new(tcx, partial_eq_trait_id, [ty, ty]), 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 // 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 // `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 // 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`. // 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( fn field_pats(
@ -192,7 +174,7 @@ impl<'tcx> ConstToPat<'tcx> {
.map(|(idx, (val, ty))| { .map(|(idx, (val, ty))| {
let field = FieldIdx::new(idx); let field = FieldIdx::new(idx);
// Patterns can only use monomorphic types. // 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) } FieldPat { field, pattern: self.valtree_to_pat(val, ty) }
}) })
.collect() .collect()
@ -202,12 +184,12 @@ impl<'tcx> ConstToPat<'tcx> {
#[instrument(skip(self), level = "debug")] #[instrument(skip(self), level = "debug")]
fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> { fn valtree_to_pat(&self, cv: ValTree<'tcx>, ty: Ty<'tcx>) -> Box<Pat<'tcx>> {
let span = self.span; let span = self.span;
let tcx = self.tcx(); let tcx = self.tcx;
let kind = match ty.kind() { let kind = match ty.kind() {
ty::Adt(adt_def, _) if !self.type_marked_structural(ty) => { 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 // Extremely important check for all ADTs! Make sure they opted-in to be used in
// patterns. // 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 err = TypeNotStructural { span, non_sm_ty: ty };
let e = tcx.dcx().emit_err(err); let e = tcx.dcx().emit_err(err);
// We errored. Signal that in the pattern, so that follow up errors can be silenced. // 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] adt_def.variants()[variant_index]
.fields .fields
.iter() .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) => { ty::Adt(def, args) => {
assert!(!def.is_union()); // Valtree construction would never succeed for unions. assert!(!def.is_union()); // Valtree construction would never succeed for unions.
PatKind::Leaf { PatKind::Leaf {
subpatterns: self.field_pats( subpatterns: self.field_pats(cv.unwrap_branch().iter().copied().zip(
cv.unwrap_branch().iter().copied().zip( def.non_enum_variant().fields.iter().map(|field| field.ty(self.tcx, args)),
def.non_enum_variant() )),
.fields
.iter()
.map(|field| field.ty(self.tcx(), args)),
),
),
} }
} }
ty::Tuple(fields) => PatKind::Leaf { 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 // convert the dereferenced constant to a pattern that is the sub-pattern of the
// deref pattern. // deref pattern.
_ => { _ => {
if !pointee_ty.is_sized(tcx, self.infcx.typing_env(self.param_env)) if !pointee_ty.is_sized(tcx, self.typing_env) && !pointee_ty.is_slice() {
&& !pointee_ty.is_slice()
{
let err = UnsizedPattern { span, non_sm_ty: *pointee_ty }; let err = UnsizedPattern { span, non_sm_ty: *pointee_ty };
let e = tcx.dcx().emit_err(err); let e = tcx.dcx().emit_err(err);
// We errored. Signal that in the pattern, so that follow up errors can be silenced. // 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> { struct PatCtxt<'a, 'tcx> {
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, typing_env: ty::TypingEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>,
/// Used by the Rust 2024 migration lint. /// Used by the Rust 2024 migration lint.
@ -39,13 +39,13 @@ struct PatCtxt<'a, 'tcx> {
pub(super) fn pat_from_hir<'a, 'tcx>( pub(super) fn pat_from_hir<'a, 'tcx>(
tcx: TyCtxt<'tcx>, tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>, typing_env: ty::TypingEnv<'tcx>,
typeck_results: &'a ty::TypeckResults<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>,
pat: &'tcx hir::Pat<'tcx>, pat: &'tcx hir::Pat<'tcx>,
) -> Box<Pat<'tcx>> { ) -> Box<Pat<'tcx>> {
let mut pcx = PatCtxt { let mut pcx = PatCtxt {
tcx, tcx,
param_env, typing_env,
typeck_results, typeck_results,
rust_2024_migration_suggestion: typeck_results rust_2024_migration_suggestion: typeck_results
.rust_2024_migration_desugared_pats() .rust_2024_migration_desugared_pats()
@ -242,7 +242,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity); let lo = lo.unwrap_or(PatRangeBoundary::NegInfinity);
let hi = hi.unwrap_or(PatRangeBoundary::PosInfinity); 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 })); let mut kind = PatKind::Range(Box::new(PatRange { lo, hi, end, ty }));
match (end, cmp) { match (end, cmp) {
// `x..y` where `x < y`. // `x..y` where `x < y`.