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:
parent
0fe8f3454d
commit
f35eae780b
8 changed files with 50 additions and 16 deletions
|
@ -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)
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 },
|
||||
})
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue