mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
THIR patterns: Explicitly distinguish &pin from plain &/&mut
This commit is contained in:
@@ -807,12 +807,22 @@ pub enum PatKind<'tcx> {
|
||||
subpatterns: Vec<FieldPat<'tcx>>,
|
||||
},
|
||||
|
||||
/// `box P`, `&P`, `&mut P`, etc.
|
||||
/// Explicit or implicit `&P` or `&mut P`, for some subpattern `P`.
|
||||
///
|
||||
/// Implicit `&`/`&mut` patterns can be inserted by match-ergonomics.
|
||||
///
|
||||
/// With `feature(pin_ergonomics)`, this can also be `&pin const P` or
|
||||
/// `&pin mut P`, as indicated by the `pin` field.
|
||||
Deref {
|
||||
#[type_visitable(ignore)]
|
||||
pin: hir::Pinnedness,
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
},
|
||||
|
||||
/// Deref pattern, written `box P` for now.
|
||||
/// Explicit or implicit `deref!(..)` pattern, under `feature(deref_patterns)`.
|
||||
/// Represents a call to `Deref` or `DerefMut`, or a deref-move of `Box`.
|
||||
///
|
||||
/// `box P` patterns also lower to this, under `feature(box_patterns)`.
|
||||
DerefPattern {
|
||||
subpattern: Box<Pat<'tcx>>,
|
||||
/// Whether the pattern scrutinee needs to be borrowed in order to call `Deref::deref` or
|
||||
|
||||
@@ -268,7 +268,7 @@ pub(crate) fn for_each_immediate_subpat<'a, 'tcx>(
|
||||
| PatKind::Error(_) => {}
|
||||
|
||||
PatKind::Binding { subpattern: Some(subpattern), .. }
|
||||
| PatKind::Deref { subpattern }
|
||||
| PatKind::Deref { subpattern, .. }
|
||||
| PatKind::DerefPattern { subpattern, .. } => callback(subpattern),
|
||||
|
||||
PatKind::Variant { subpatterns, .. } | PatKind::Leaf { subpatterns } => {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use rustc_abi::FieldIdx;
|
||||
use rustc_middle::mir::*;
|
||||
use rustc_middle::span_bug;
|
||||
use rustc_middle::thir::*;
|
||||
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
|
||||
|
||||
@@ -314,23 +315,24 @@ pub(super) fn for_pattern(
|
||||
None
|
||||
}
|
||||
|
||||
// FIXME: Pin-patterns should probably have their own pattern kind,
|
||||
// instead of overloading `PatKind::Deref` via the pattern type.
|
||||
PatKind::Deref { ref subpattern }
|
||||
if let Some(ref_ty) = pattern.ty.pinned_ty()
|
||||
&& ref_ty.is_ref() =>
|
||||
{
|
||||
PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {
|
||||
let pinned_ref_ty = match pattern.ty.pinned_ty() {
|
||||
Some(p_ty) if p_ty.is_ref() => p_ty,
|
||||
_ => span_bug!(pattern.span, "bad type for pinned deref: {:?}", pattern.ty),
|
||||
};
|
||||
MatchPairTree::for_pattern(
|
||||
place_builder.field(FieldIdx::ZERO, ref_ty).deref(),
|
||||
// Project into the `Pin(_)` struct, then deref the inner `&` or `&mut`.
|
||||
place_builder.field(FieldIdx::ZERO, pinned_ref_ty).deref(),
|
||||
subpattern,
|
||||
cx,
|
||||
&mut subpairs,
|
||||
extra_data,
|
||||
);
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
PatKind::Deref { ref subpattern }
|
||||
PatKind::Deref { pin: Pinnedness::Not, ref subpattern }
|
||||
| PatKind::DerefPattern { ref subpattern, borrow: DerefPatBorrowMode::Box } => {
|
||||
MatchPairTree::for_pattern(
|
||||
place_builder.deref(),
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
use std::sync::Arc;
|
||||
|
||||
use itertools::{Itertools, Position};
|
||||
use rustc_abi::{FIRST_VARIANT, VariantIdx};
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};
|
||||
use rustc_data_structures::debug_assert_matches;
|
||||
use rustc_data_structures::fx::FxIndexMap;
|
||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||
@@ -909,7 +909,11 @@ fn visit_primary_bindings_special(
|
||||
| PatKind::Never
|
||||
| PatKind::Error(_) => {}
|
||||
|
||||
PatKind::Deref { ref subpattern } => {
|
||||
PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {
|
||||
// Project into the `Pin(_)` struct, then deref the inner `&` or `&mut`.
|
||||
visit_subpat(self, subpattern, &user_tys.leaf(FieldIdx::ZERO).deref(), f);
|
||||
}
|
||||
PatKind::Deref { pin: Pinnedness::Not, ref subpattern } => {
|
||||
visit_subpat(self, subpattern, &user_tys.deref(), f);
|
||||
}
|
||||
|
||||
|
||||
@@ -294,8 +294,12 @@ fn valtree_to_pat(&self, value: ty::Value<'tcx>) -> Box<Pat<'tcx>> {
|
||||
|| pointee_ty.is_slice()
|
||||
|| pointee_ty.is_sized(tcx, self.typing_env)
|
||||
{
|
||||
// References have the same valtree representation as their pointee.
|
||||
PatKind::Deref {
|
||||
// This node has type `ty::Ref`, so it's not a pin-deref.
|
||||
pin: hir::Pinnedness::Not,
|
||||
// Lower the valtree to a pattern as the pointee type.
|
||||
// This works because references have the same valtree
|
||||
// representation as their pointee.
|
||||
subpattern: self.valtree_to_pat(ty::Value { ty: *pointee_ty, valtree }),
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -132,12 +132,16 @@ fn lower_pattern(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tcx>> {
|
||||
debug!("{:?}: wrapping pattern with adjustment {:?}", thir_pat, adjust);
|
||||
let span = thir_pat.span;
|
||||
let kind = match adjust.kind {
|
||||
PatAdjust::BuiltinDeref => PatKind::Deref { subpattern: thir_pat },
|
||||
PatAdjust::BuiltinDeref => {
|
||||
PatKind::Deref { pin: hir::Pinnedness::Not, subpattern: thir_pat }
|
||||
}
|
||||
PatAdjust::OverloadedDeref => {
|
||||
let borrow = self.typeck_results.deref_pat_borrow_mode(adjust.source, pat);
|
||||
PatKind::DerefPattern { subpattern: thir_pat, borrow }
|
||||
}
|
||||
PatAdjust::PinDeref => PatKind::Deref { subpattern: thir_pat },
|
||||
PatAdjust::PinDeref => {
|
||||
PatKind::Deref { pin: hir::Pinnedness::Pinned, subpattern: thir_pat }
|
||||
}
|
||||
};
|
||||
Box::new(Pat { span, ty: adjust.source, kind, extra: None })
|
||||
});
|
||||
@@ -334,7 +338,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
|
||||
let borrow = self.typeck_results.deref_pat_borrow_mode(ty, subpattern);
|
||||
PatKind::DerefPattern { subpattern: self.lower_pattern(subpattern), borrow }
|
||||
}
|
||||
hir::PatKind::Ref(subpattern, _, _) => {
|
||||
hir::PatKind::Ref(subpattern, pin, _) => {
|
||||
// Track the default binding mode for the Rust 2024 migration suggestion.
|
||||
let opt_old_mode_span =
|
||||
self.rust_2024_migration.as_mut().and_then(|s| s.visit_explicit_deref());
|
||||
@@ -342,7 +346,7 @@ fn lower_pattern_unadjusted(&mut self, pat: &'tcx hir::Pat<'tcx>) -> Box<Pat<'tc
|
||||
if let Some(s) = &mut self.rust_2024_migration {
|
||||
s.leave_ref(opt_old_mode_span);
|
||||
}
|
||||
PatKind::Deref { subpattern }
|
||||
PatKind::Deref { pin, subpattern }
|
||||
}
|
||||
hir::PatKind::Box(subpattern) => PatKind::DerefPattern {
|
||||
subpattern: self.lower_pattern(subpattern),
|
||||
|
||||
@@ -774,8 +774,9 @@ fn print_pat_kind(&mut self, pat_kind: &PatKind<'tcx>, depth_lvl: usize) {
|
||||
print_indented!(self, "]", depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
}
|
||||
PatKind::Deref { subpattern } => {
|
||||
PatKind::Deref { pin, subpattern } => {
|
||||
print_indented!(self, "Deref { ", depth_lvl + 1);
|
||||
print_indented!(self, format_args!("pin: {pin:?}"), depth_lvl + 2);
|
||||
print_indented!(self, "subpattern:", depth_lvl + 2);
|
||||
self.print_pat(subpattern, depth_lvl + 2);
|
||||
print_indented!(self, "}", depth_lvl + 1);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
// tidy-alphabetical-start
|
||||
#![allow(unused_crate_dependencies)]
|
||||
#![cfg_attr(feature = "rustc", feature(if_let_guard))]
|
||||
// tidy-alphabetical-end
|
||||
|
||||
pub(crate) mod checks;
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
use rustc_abi::{FIRST_VARIANT, FieldIdx, Integer, VariantIdx};
|
||||
use rustc_arena::DroplessArena;
|
||||
use rustc_hir::HirId;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::{self as hir, HirId};
|
||||
use rustc_index::{Idx, IndexVec};
|
||||
use rustc_middle::middle::stability::EvalResult;
|
||||
use rustc_middle::thir::{self, Pat, PatKind, PatRange, PatRangeBoundary};
|
||||
@@ -468,12 +468,12 @@ pub fn lower_pat(&self, pat: &'p Pat<'tcx>) -> DeconstructedPat<'p, 'tcx> {
|
||||
fields = vec![];
|
||||
arity = 0;
|
||||
}
|
||||
PatKind::Deref { subpattern } => {
|
||||
PatKind::Deref { pin, subpattern } => {
|
||||
fields = vec![self.lower_pat(subpattern).at_index(0)];
|
||||
arity = 1;
|
||||
ctor = match ty.pinned_ref() {
|
||||
None if ty.is_ref() => Ref,
|
||||
Some((inner_ty, _)) => {
|
||||
ctor = match pin {
|
||||
hir::Pinnedness::Not if ty.is_ref() => Ref,
|
||||
hir::Pinnedness::Pinned if let Some((inner_ty, _)) = ty.pinned_ref() => {
|
||||
self.internal_state.has_lowered_deref_pat.set(true);
|
||||
DerefPattern(RevealedTy(inner_ty))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#![crate_type = "rlib"]
|
||||
#![feature(pin_ergonomics)]
|
||||
#![expect(incomplete_features)]
|
||||
//@ edition: 2024
|
||||
//@ check-pass
|
||||
|
||||
// Test that we don't ICE when projecting user-type-annotations through a `&pin` pattern.
|
||||
//
|
||||
// Historically, this could occur when the code handling those projections did not know
|
||||
// about `&pin` patterns, and incorrectly treated them as plain `&`/`&mut` patterns instead.
|
||||
|
||||
struct Data {
|
||||
x: u32
|
||||
}
|
||||
|
||||
pub fn project_user_type_through_pin() -> u32 {
|
||||
let &pin const Data { x }: &pin const Data = &pin const Data { x: 30 };
|
||||
x
|
||||
}
|
||||
@@ -10,6 +10,7 @@ Thir {
|
||||
span: $DIR/str-patterns.rs:11:9: 11:16 (#0),
|
||||
extra: None,
|
||||
kind: Deref {
|
||||
pin: Not,
|
||||
subpattern: Pat {
|
||||
ty: str,
|
||||
span: $DIR/str-patterns.rs:11:9: 11:16 (#0),
|
||||
@@ -50,6 +51,7 @@ Thir {
|
||||
},
|
||||
),
|
||||
kind: Deref {
|
||||
pin: Not,
|
||||
subpattern: Pat {
|
||||
ty: str,
|
||||
span: $DIR/str-patterns.rs:12:9: 12:17 (#0),
|
||||
|
||||
Reference in New Issue
Block a user