1
Fork 0

store the kind of pattern adjustments in pat_adjustments

This allows us to better distinguish builtin and overloaded implicit
dereferences.
This commit is contained in:
dianne 2025-03-14 18:56:15 -07:00
parent 0fe8f3454d
commit f35eae780b
8 changed files with 50 additions and 16 deletions

View file

@ -1227,9 +1227,9 @@ impl<'tcx, Cx: TypeInformationCtxt<'tcx>, D: Delegate<'tcx>> ExprUseVisitor<'tcx
// actually this is somewhat "disjoint" from the code below
// that aims to account for `ref x`.
if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) {
if let Some(first_ty) = vec.first() {
debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
return Ok(*first_ty);
if let Some(first_adjust) = vec.first() {
debug!("pat_ty(pat={:?}) found adjustment `{:?}`", pat, first_adjust);
return Ok(first_adjust.source);
}
} else if let PatKind::Ref(subpat, _) = pat.kind
&& self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)

View file

@ -29,6 +29,7 @@ use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
use tracing::{debug, instrument, trace};
use ty::VariantDef;
use ty::adjustment::{PatAdjust, PatAdjustment};
use super::report_unexpected_variant_res;
use crate::expectation::Expectation;
@ -415,7 +416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.pat_adjustments_mut()
.entry(pat.hir_id)
.or_default()
.push(expected);
.push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
let mut binding_mode = ByRef::Yes(match pat_info.binding_mode {
// If default binding mode is by value, make it `ref` or `ref mut`

View file

@ -214,3 +214,25 @@ pub enum CustomCoerceUnsized {
/// Records the index of the field being coerced.
Struct(FieldIdx),
}
/// Represents an implicit coercion applied to the scrutinee of a match before testing a pattern
/// against it. Currently, this is used only for implicit dereferences.
#[derive(Clone, Copy, TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)]
pub struct PatAdjustment<'tcx> {
pub kind: PatAdjust,
/// The type of the scrutinee before the adjustment is applied, or the "adjusted type" of the
/// pattern.
pub source: Ty<'tcx>,
}
/// Represents implicit coercions of patterns' types, rather than values' types.
#[derive(Clone, Copy, PartialEq, Debug, TyEncodable, TyDecodable, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
pub enum PatAdjust {
/// An implicit dereference before matching, such as when matching the pattern `0` against a
/// scrutinee of type `&u8` or `&mut u8`.
BuiltinDeref,
/// An implicit call to `Deref(Mut)::deref(_mut)` before matching, such as when matching the
/// pattern `[..]` against a scrutinee of type `Vec<T>`.
OverloadedDeref,
}

View file

@ -61,6 +61,12 @@ impl<'tcx> fmt::Debug for ty::adjustment::Adjustment<'tcx> {
}
}
impl<'tcx> fmt::Debug for ty::adjustment::PatAdjustment<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} -> {:?}", self.source, self.kind)
}
}
impl fmt::Debug for ty::BoundRegionKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {

View file

@ -90,7 +90,7 @@ pub struct TypeckResults<'tcx> {
///
/// See:
/// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
pat_adjustments: ItemLocalMap<Vec<Ty<'tcx>>>,
pat_adjustments: ItemLocalMap<Vec<ty::adjustment::PatAdjustment<'tcx>>>,
/// Set of reference patterns that match against a match-ergonomics inserted reference
/// (as opposed to against a reference in the scrutinee type).
@ -403,11 +403,15 @@ impl<'tcx> TypeckResults<'tcx> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_binding_modes }
}
pub fn pat_adjustments(&self) -> LocalTableInContext<'_, Vec<Ty<'tcx>>> {
pub fn pat_adjustments(
&self,
) -> LocalTableInContext<'_, Vec<ty::adjustment::PatAdjustment<'tcx>>> {
LocalTableInContext { hir_owner: self.hir_owner, data: &self.pat_adjustments }
}
pub fn pat_adjustments_mut(&mut self) -> LocalTableInContextMut<'_, Vec<Ty<'tcx>>> {
pub fn pat_adjustments_mut(
&mut self,
) -> LocalTableInContextMut<'_, Vec<ty::adjustment::PatAdjustment<'tcx>>> {
LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.pat_adjustments }
}

View file

@ -5,7 +5,7 @@ use rustc_errors::MultiSpan;
use rustc_hir::{BindingMode, ByRef, HirId, Mutability};
use rustc_lint as lint;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, Ty, TyCtxt};
use rustc_middle::ty::{self, Rust2024IncompatiblePatInfo, TyCtxt};
use rustc_span::{Ident, Span};
use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg};
@ -93,10 +93,10 @@ impl<'a> PatMigration<'a> {
pub(super) fn visit_implicit_derefs<'tcx>(
&mut self,
pat_span: Span,
adjustments: &[Ty<'tcx>],
adjustments: &[ty::adjustment::PatAdjustment<'tcx>],
) -> Option<(Span, Mutability)> {
let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| {
let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
let implicit_deref_mutbls = adjustments.iter().map(|adjust| {
let &ty::Ref(_, _, mutbl) = adjust.source.kind() else {
span_bug!(pat_span, "pattern implicitly dereferences a non-ref type");
};
mutbl

View file

@ -18,6 +18,7 @@ use rustc_middle::mir::interpret::LitToConstInput;
use rustc_middle::thir::{
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
};
use rustc_middle::ty::adjustment::PatAdjustment;
use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode};
use rustc_middle::{bug, span_bug};
@ -63,7 +64,7 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
let adjustments: &[Ty<'tcx>] =
let adjustments: &[PatAdjustment<'tcx>] =
self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
// Track the default binding mode for the Rust 2024 migration suggestion.
@ -102,11 +103,11 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
_ => self.lower_pattern_unadjusted(pat),
};
let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, adjust| {
debug!("{:?}: wrapping pattern with type {:?}", thir_pat, adjust);
Box::new(Pat {
span: thir_pat.span,
ty: *ref_ty,
ty: adjust.source,
kind: PatKind::Deref { subpattern: thir_pat },
})
});