Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/thir/visit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 } => {
Expand Down
18 changes: 10 additions & 8 deletions compiler/rustc_mir_build/src/builder/matches/match_pair.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::sync::Arc;

use rustc_abi::FieldIdx;
use rustc_middle::mir::*;
use rustc_middle::span_bug;
use rustc_middle::thir::*;
use rustc_middle::ty::{self, Ty, TypeVisitableExt};

Expand Down Expand Up @@ -314,23 +315,24 @@ impl<'tcx> MatchPairTree<'tcx> {
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(),
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_mir_build/src/builder/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use std::mem;
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;
Expand Down Expand Up @@ -909,7 +909,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| 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);
}

Expand Down
6 changes: 5 additions & 1 deletion compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,12 @@ impl<'tcx> ConstToPat<'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 {
Expand Down
12 changes: 8 additions & 4 deletions compiler/rustc_mir_build/src/thir/pattern/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,12 +132,16 @@ impl<'tcx> PatCtxt<'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 })
});
Expand Down Expand Up @@ -334,15 +338,15 @@ impl<'tcx> PatCtxt<'tcx> {
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());
let subpattern = self.lower_pattern(subpattern);
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),
Expand Down
3 changes: 2 additions & 1 deletion compiler/rustc_mir_build/src/thir/print.rs
Original file line number Diff line number Diff line change
Expand Up @@ -774,8 +774,9 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
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);
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_pattern_analysis/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_pattern_analysis/src/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use std::iter::once;

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};
Expand Down Expand Up @@ -468,12 +468,12 @@ impl<'p, 'tcx: 'p> RustcPatCtxt<'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))
}
Expand Down
19 changes: 19 additions & 0 deletions tests/ui/pin-ergonomics/user-type-projection.rs
Original file line number Diff line number Diff line change
@@ -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
}
2 changes: 2 additions & 0 deletions tests/ui/thir-print/str-patterns.stdout
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down Expand Up @@ -50,6 +51,7 @@ Thir {
},
),
kind: Deref {
pin: Not,
subpattern: Pat {
ty: str,
span: $DIR/str-patterns.rs:12:9: 12:17 (#0),
Expand Down
Loading