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
|
// actually this is somewhat "disjoint" from the code below
|
||||||
// that aims to account for `ref x`.
|
// that aims to account for `ref x`.
|
||||||
if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) {
|
if let Some(vec) = self.cx.typeck_results().pat_adjustments().get(pat.hir_id) {
|
||||||
if let Some(first_ty) = vec.first() {
|
if let Some(first_adjust) = vec.first() {
|
||||||
debug!("pat_ty(pat={:?}) found adjusted ty `{:?}`", pat, first_ty);
|
debug!("pat_ty(pat={:?}) found adjustment `{:?}`", pat, first_adjust);
|
||||||
return Ok(*first_ty);
|
return Ok(first_adjust.source);
|
||||||
}
|
}
|
||||||
} else if let PatKind::Ref(subpat, _) = pat.kind
|
} else if let PatKind::Ref(subpat, _) = pat.kind
|
||||||
&& self.cx.typeck_results().skipped_ref_pats().contains(pat.hir_id)
|
&& 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 rustc_trait_selection::traits::{ObligationCause, ObligationCauseCode};
|
||||||
use tracing::{debug, instrument, trace};
|
use tracing::{debug, instrument, trace};
|
||||||
use ty::VariantDef;
|
use ty::VariantDef;
|
||||||
|
use ty::adjustment::{PatAdjust, PatAdjustment};
|
||||||
|
|
||||||
use super::report_unexpected_variant_res;
|
use super::report_unexpected_variant_res;
|
||||||
use crate::expectation::Expectation;
|
use crate::expectation::Expectation;
|
||||||
|
@ -415,7 +416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||||
.pat_adjustments_mut()
|
.pat_adjustments_mut()
|
||||||
.entry(pat.hir_id)
|
.entry(pat.hir_id)
|
||||||
.or_default()
|
.or_default()
|
||||||
.push(expected);
|
.push(PatAdjustment { kind: PatAdjust::BuiltinDeref, source: expected });
|
||||||
|
|
||||||
let mut binding_mode = ByRef::Yes(match pat_info.binding_mode {
|
let mut binding_mode = ByRef::Yes(match pat_info.binding_mode {
|
||||||
// If default binding mode is by value, make it `ref` or `ref mut`
|
// 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.
|
/// Records the index of the field being coerced.
|
||||||
Struct(FieldIdx),
|
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 {
|
impl fmt::Debug for ty::BoundRegionKind {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
|
@ -90,7 +90,7 @@ pub struct TypeckResults<'tcx> {
|
||||||
///
|
///
|
||||||
/// See:
|
/// See:
|
||||||
/// <https://github.com/rust-lang/rfcs/blob/master/text/2005-match-ergonomics.md#definitions>
|
/// <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
|
/// Set of reference patterns that match against a match-ergonomics inserted reference
|
||||||
/// (as opposed to against a reference in the scrutinee type).
|
/// (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 }
|
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 }
|
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 }
|
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_hir::{BindingMode, ByRef, HirId, Mutability};
|
||||||
use rustc_lint as lint;
|
use rustc_lint as lint;
|
||||||
use rustc_middle::span_bug;
|
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 rustc_span::{Ident, Span};
|
||||||
|
|
||||||
use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg};
|
use crate::errors::{Rust2024IncompatiblePat, Rust2024IncompatiblePatSugg};
|
||||||
|
@ -93,10 +93,10 @@ impl<'a> PatMigration<'a> {
|
||||||
pub(super) fn visit_implicit_derefs<'tcx>(
|
pub(super) fn visit_implicit_derefs<'tcx>(
|
||||||
&mut self,
|
&mut self,
|
||||||
pat_span: Span,
|
pat_span: Span,
|
||||||
adjustments: &[Ty<'tcx>],
|
adjustments: &[ty::adjustment::PatAdjustment<'tcx>],
|
||||||
) -> Option<(Span, Mutability)> {
|
) -> Option<(Span, Mutability)> {
|
||||||
let implicit_deref_mutbls = adjustments.iter().map(|ref_ty| {
|
let implicit_deref_mutbls = adjustments.iter().map(|adjust| {
|
||||||
let &ty::Ref(_, _, mutbl) = ref_ty.kind() else {
|
let &ty::Ref(_, _, mutbl) = adjust.source.kind() else {
|
||||||
span_bug!(pat_span, "pattern implicitly dereferences a non-ref type");
|
span_bug!(pat_span, "pattern implicitly dereferences a non-ref type");
|
||||||
};
|
};
|
||||||
mutbl
|
mutbl
|
||||||
|
|
|
@ -18,6 +18,7 @@ use rustc_middle::mir::interpret::LitToConstInput;
|
||||||
use rustc_middle::thir::{
|
use rustc_middle::thir::{
|
||||||
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
|
Ascription, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary,
|
||||||
};
|
};
|
||||||
|
use rustc_middle::ty::adjustment::PatAdjustment;
|
||||||
use rustc_middle::ty::layout::IntegerExt;
|
use rustc_middle::ty::layout::IntegerExt;
|
||||||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode};
|
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypingMode};
|
||||||
use rustc_middle::{bug, span_bug};
|
use rustc_middle::{bug, span_bug};
|
||||||
|
@ -63,7 +64,7 @@ pub(super) fn pat_from_hir<'a, 'tcx>(
|
||||||
|
|
||||||
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
|
||||||
fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'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);
|
self.typeck_results.pat_adjustments().get(pat.hir_id).map_or(&[], |v| &**v);
|
||||||
|
|
||||||
// Track the default binding mode for the Rust 2024 migration suggestion.
|
// 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),
|
_ => self.lower_pattern_unadjusted(pat),
|
||||||
};
|
};
|
||||||
|
|
||||||
let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, ref_ty| {
|
let adjusted_pat = adjustments.iter().rev().fold(unadjusted_pat, |thir_pat, adjust| {
|
||||||
debug!("{:?}: wrapping pattern with type {:?}", thir_pat, ref_ty);
|
debug!("{:?}: wrapping pattern with type {:?}", thir_pat, adjust);
|
||||||
Box::new(Pat {
|
Box::new(Pat {
|
||||||
span: thir_pat.span,
|
span: thir_pat.span,
|
||||||
ty: *ref_ty,
|
ty: adjust.source,
|
||||||
kind: PatKind::Deref { subpattern: thir_pat },
|
kind: PatKind::Deref { subpattern: thir_pat },
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
|
@ -179,7 +179,7 @@ fn find_first_mismatch(cx: &LateContext<'_>, pat: &Pat<'_>) -> Option<(Span, Mut
|
||||||
};
|
};
|
||||||
if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) {
|
if let Some(adjustments) = cx.typeck_results().pat_adjustments().get(adjust_pat.hir_id) {
|
||||||
if let [first, ..] = **adjustments {
|
if let [first, ..] = **adjustments {
|
||||||
if let ty::Ref(.., mutability) = *first.kind() {
|
if let ty::Ref(.., mutability) = *first.source.kind() {
|
||||||
let level = if p.hir_id == pat.hir_id {
|
let level = if p.hir_id == pat.hir_id {
|
||||||
Level::Top
|
Level::Top
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue