Skip to content

Commit

Permalink
parse pinned local variable declarations
Browse files Browse the repository at this point in the history
  • Loading branch information
frank-king committed Jan 20, 2025
1 parent 73c0ae6 commit 87de2da
Show file tree
Hide file tree
Showing 48 changed files with 389 additions and 84 deletions.
33 changes: 23 additions & 10 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -718,18 +718,22 @@ impl ByRef {
/// Used for both the explicit binding annotations given in the HIR for a binding
/// and the final binding mode that we infer after type inference/match ergonomics.
/// `.0` is the by-reference mode (`ref`, `ref mut`, or by value),
/// `.1` is the mutability of the binding.
/// `.1` is the pinnedness of the binding,
/// `.2` is the mutability of the binding.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[derive(Encodable, Decodable, HashStable_Generic)]
pub struct BindingMode(pub ByRef, pub Mutability);
pub struct BindingMode(pub ByRef, pub Pinnedness, pub Mutability);

impl BindingMode {
pub const NONE: Self = Self(ByRef::No, Mutability::Not);
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Not);
pub const MUT: Self = Self(ByRef::No, Mutability::Mut);
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Not);
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Mutability::Mut);
pub const MUT_REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Mutability::Mut);
pub const NONE: Self = Self(ByRef::No, Pinnedness::Not, Mutability::Not);
pub const REF: Self = Self(ByRef::Yes(Mutability::Not), Pinnedness::Not, Mutability::Not);
pub const MUT: Self = Self(ByRef::No, Pinnedness::Not, Mutability::Mut);
pub const REF_MUT: Self = Self(ByRef::Yes(Mutability::Mut), Pinnedness::Not, Mutability::Not);
pub const MUT_REF: Self = Self(ByRef::Yes(Mutability::Not), Pinnedness::Not, Mutability::Mut);
pub const MUT_REF_MUT: Self =
Self(ByRef::Yes(Mutability::Mut), Pinnedness::Not, Mutability::Mut);
pub const PIN_CONST: Self = Self(ByRef::No, Pinnedness::Pinned, Mutability::Not);
pub const PIN_MUT: Self = Self(ByRef::No, Pinnedness::Pinned, Mutability::Mut);

pub fn prefix_str(self) -> &'static str {
match self {
Expand All @@ -739,6 +743,9 @@ impl BindingMode {
Self::REF_MUT => "ref mut ",
Self::MUT_REF => "mut ref ",
Self::MUT_REF_MUT => "mut ref mut ",
Self::PIN_CONST => "pin const ",
Self::PIN_MUT => "pin mut ",
Self(_, Pinnedness::Pinned, _) => panic!("unsupported pinned binding mode"),
}
}
}
Expand Down Expand Up @@ -2551,7 +2558,9 @@ pub type ExplicitSelf = Spanned<SelfKind>;
impl Param {
/// Attempts to cast parameter to `ExplicitSelf`.
pub fn to_self(&self) -> Option<ExplicitSelf> {
if let PatKind::Ident(BindingMode(ByRef::No, mutbl), ident, _) = self.pat.kind {
if let PatKind::Ident(BindingMode(ByRef::No, Pinnedness::Not, mutbl), ident, _) =
self.pat.kind
{
if ident.name == kw::SelfLower {
return match self.ty.kind {
TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
Expand Down Expand Up @@ -2606,7 +2615,11 @@ impl Param {
attrs,
pat: P(Pat {
id: DUMMY_NODE_ID,
kind: PatKind::Ident(BindingMode(ByRef::No, mutbl), eself_ident, None),
kind: PatKind::Ident(
BindingMode(ByRef::No, Pinnedness::Not, mutbl),
eself_ident,
None,
),
span,
tokens: None,
}),
Expand Down
9 changes: 9 additions & 0 deletions compiler/rustc_ast_ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,12 @@ pub enum Pinnedness {
Not,
Pinned,
}

impl Pinnedness {
pub fn is_pin(self) -> bool {
matches!(self, Self::Pinned)
}
pub fn is_not(self) -> bool {
matches!(self, Self::Not)
}
}
4 changes: 3 additions & 1 deletion compiler/rustc_ast_lowering/src/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
// Check if this is a binding pattern, if so, we can optimize and avoid adding a
// `let <pat> = __argN;` statement. In this case, we do not rename the parameter.
let (ident, is_simple_parameter) = match parameter.pat.kind {
hir::PatKind::Binding(hir::BindingMode(ByRef::No, _), _, ident, _) => (ident, true),
hir::PatKind::Binding(hir::BindingMode(ByRef::No, _, _), _, ident, _) => {
(ident, true)
}
// For `ref mut` or wildcard arguments, we can't reuse the binding, but
// we can keep the same name for the parameter.
// This lets rustdoc render it correctly in documentation.
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_ast_lowering/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1607,7 +1607,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
implicit_self: decl.inputs.get(0).map_or(hir::ImplicitSelfKind::None, |arg| {
let is_mutable_pat = matches!(
arg.pat.kind,
PatKind::Ident(hir::BindingMode(_, Mutability::Mut), ..)
PatKind::Ident(hir::BindingMode(_, _, Mutability::Mut), ..)
);

match &arg.ty.kind {
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_ast_pretty/src/pprust/state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1594,7 +1594,10 @@ impl<'a> State<'a> {
match &pat.kind {
PatKind::Wild => self.word("_"),
PatKind::Never => self.word("!"),
PatKind::Ident(BindingMode(by_ref, mutbl), ident, sub) => {
PatKind::Ident(BindingMode(by_ref, pin, mutbl), ident, sub) => {
if pin.is_pin() {
self.word_nbsp("pin");
}
if mutbl.is_mut() {
self.word_nbsp("mut");
}
Expand Down
10 changes: 5 additions & 5 deletions compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
{
match *decl.local_info() {
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
binding_mode: BindingMode(ByRef::No, Mutability::Not),
binding_mode: BindingMode(ByRef::No, _, Mutability::Not),
opt_ty_info: Some(sp),
opt_match_place: _,
pat_span: _,
Expand Down Expand Up @@ -732,7 +732,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
debug!("local_decl: {:?}", local_decl);
let pat_span = match *local_decl.local_info() {
LocalInfo::User(BindingForm::Var(mir::VarBindingForm {
binding_mode: BindingMode(ByRef::No, Mutability::Not),
binding_mode: BindingMode(ByRef::No, _, Mutability::Not),
opt_ty_info: _,
opt_match_place: _,
pat_span,
Expand Down Expand Up @@ -1147,7 +1147,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}

LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
binding_mode: BindingMode(ByRef::No, _),
binding_mode: BindingMode(ByRef::No, _, _),
opt_ty_info,
..
})) => {
Expand Down Expand Up @@ -1225,7 +1225,7 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> {
}

LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
binding_mode: BindingMode(ByRef::Yes(_), _),
binding_mode: BindingMode(ByRef::Yes(_), _, _),
..
})) => {
let pattern_span: Span = local_decl.source_info.span;
Expand Down Expand Up @@ -1440,7 +1440,7 @@ fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symb
match *local_decl.local_info() {
// Check if mutably borrowing a mutable reference.
LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
binding_mode: BindingMode(ByRef::No, Mutability::Not),
binding_mode: BindingMode(ByRef::No, _, Mutability::Not),
..
})) => matches!(local_decl.ty.kind(), ty::Ref(_, _, hir::Mutability::Mut)),
LocalInfo::User(mir::BindingForm::ImplicitSelf(kind)) => {
Expand Down
8 changes: 6 additions & 2 deletions compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ pub(crate) use SubstructureFields::*;
use rustc_ast::ptr::P;
use rustc_ast::{
self as ast, AnonConst, BindingMode, ByRef, EnumDef, Expr, GenericArg, GenericParamKind,
Generics, Mutability, PatKind, VariantData,
Generics, Mutability, PatKind, Pinnedness, VariantData,
};
use rustc_attr_parsing as attr;
use rustc_expand::base::{Annotatable, ExtCtxt};
Expand Down Expand Up @@ -1477,7 +1477,11 @@ impl<'a> TraitDef<'a> {
struct_field.ident,
cx.pat(
path.span,
PatKind::Ident(BindingMode(by_ref, Mutability::Not), path, None),
PatKind::Ident(
BindingMode(by_ref, Pinnedness::Not, Mutability::Not),
path,
None,
),
),
)
});
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_hir/src/pat_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl hir::Pat<'_> {

pub fn simple_ident(&self) -> Option<Ident> {
match self.kind {
PatKind::Binding(BindingMode(ByRef::No, _), _, ident, None) => Some(ident),
PatKind::Binding(BindingMode(ByRef::No, _, _), _, ident, None) => Some(ident),
_ => None,
}
}
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_hir_analysis/src/check/region.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,7 +681,7 @@ fn resolve_local<'tcx>(
// & expression, and its lifetime would be extended to the end of the block (due
// to a different rule, not the below code).
match pat.kind {
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _), ..) => true,
PatKind::Binding(hir::BindingMode(hir::ByRef::Yes(_), _, _), ..) => true,

PatKind::Struct(_, field_pats, _) => field_pats.iter().any(|fp| is_binding_pat(fp.pat)),

Expand All @@ -700,7 +700,7 @@ fn resolve_local<'tcx>(
}

PatKind::Ref(_, _)
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), ..)
| PatKind::Binding(hir::BindingMode(hir::ByRef::No, _, _), ..)
| PatKind::Wild
| PatKind::Never
| PatKind::Path(_)
Expand Down
5 changes: 4 additions & 1 deletion compiler/rustc_hir_pretty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1871,7 +1871,10 @@ impl<'a> State<'a> {
match pat.kind {
PatKind::Wild => self.word("_"),
PatKind::Never => self.word("!"),
PatKind::Binding(BindingMode(by_ref, mutbl), _, ident, sub) => {
PatKind::Binding(BindingMode(by_ref, pin, mutbl), _, ident, sub) => {
if pin.is_pin() {
self.word_nbsp("pin");
}
if mutbl.is_mut() {
self.word_nbsp("mut");
}
Expand Down
12 changes: 6 additions & 6 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// Determine the binding mode...
let bm = match user_bind_annot {
BindingMode(ByRef::No, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
BindingMode(ByRef::No, pin, Mutability::Mut) if matches!(def_br, ByRef::Yes(_)) => {
if pat.span.at_least_rust_2024()
&& (self.tcx.features().ref_pat_eat_one_layer_2024()
|| self.tcx.features().ref_pat_eat_one_layer_2024_structural())
Expand All @@ -745,7 +745,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.emit();
}

BindingMode(def_br, Mutability::Mut)
BindingMode(def_br, pin, Mutability::Mut)
} else {
// `mut` resets the binding mode on edition <= 2021
self.add_rust_2024_migration_desugared_pat(
Expand All @@ -754,11 +754,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ident.span,
"requires binding by-value, but the implicit default is by-reference",
);
BindingMode(ByRef::No, Mutability::Mut)
BindingMode(ByRef::No, pin, Mutability::Mut)
}
}
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
BindingMode(ByRef::Yes(_), _) => {
BindingMode(ByRef::No, pin, mutbl) => BindingMode(def_br, pin, mutbl),
BindingMode(ByRef::Yes(_), _, _) => {
if matches!(def_br, ByRef::Yes(_)) {
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
self.add_rust_2024_migration_desugared_pat(
Expand Down Expand Up @@ -981,7 +981,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let PatKind::Ref(the_ref, _) = i.kind
&& let PatKind::Binding(mt, _, ident, _) = the_ref.kind
{
let BindingMode(_, mtblty) = mt;
let BindingMode(_, _, mtblty) = mt;
err.span_suggestion_verbose(
i.span,
format!("consider removing `&{mutability}` from the pattern"),
Expand Down
5 changes: 3 additions & 2 deletions compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
else {
bug!();
};
let hir::PatKind::Binding(hir::BindingMode(hir::ByRef::No, _), _, _, _) = pat.kind
let hir::PatKind::Binding(hir::BindingMode(hir::ByRef::No, _, _), _, _, _) =
pat.kind
else {
// Complex pattern, skip the non-upvar local.
continue;
Expand Down Expand Up @@ -1799,7 +1800,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

let bm = *typeck_results.pat_binding_modes().get(var_hir_id).expect("missing binding mode");

let mut is_mutbl = bm.1;
let mut is_mutbl = bm.2;

for pointer_ty in place.deref_tys() {
match self.structurally_resolve_type(self.tcx.hir().span(var_hir_id), pointer_ty).kind()
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1122,7 +1122,7 @@ impl<'tcx> LocalDecl<'tcx> {
self.local_info(),
LocalInfo::User(
BindingForm::Var(VarBindingForm {
binding_mode: BindingMode(ByRef::No, _),
binding_mode: BindingMode(ByRef::No, _, _),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
Expand All @@ -1139,7 +1139,7 @@ impl<'tcx> LocalDecl<'tcx> {
self.local_info(),
LocalInfo::User(
BindingForm::Var(VarBindingForm {
binding_mode: BindingMode(ByRef::No, _),
binding_mode: BindingMode(ByRef::No, _, _),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/thir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -629,7 +629,7 @@ impl<'tcx> Pat<'tcx> {
pub fn simple_ident(&self) -> Option<Symbol> {
match self.kind {
PatKind::Binding {
name, mode: BindingMode(ByRef::No, _), subpattern: None, ..
name, mode: BindingMode(ByRef::No, _, _), subpattern: None, ..
} => Some(name),
_ => None,
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/typeck_results.rs
Original file line number Diff line number Diff line change
Expand Up @@ -456,7 +456,7 @@ impl<'tcx> TypeckResults<'tcx> {
let mut has_ref_mut = false;
pat.walk(|pat| {
if let hir::PatKind::Binding(_, id, _, _) = pat.kind
&& let Some(BindingMode(ByRef::Yes(Mutability::Mut), _)) =
&& let Some(BindingMode(ByRef::Yes(Mutability::Mut), _, _)) =
self.pat_binding_modes().get(id)
{
has_ref_mut = true;
Expand Down
8 changes: 5 additions & 3 deletions compiler/rustc_mir_build/src/builder/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -583,7 +583,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
) -> BlockAnd<()> {
match irrefutable_pat.kind {
// Optimize the case of `let x = ...` to write directly into `x`
PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => {
PatKind::Binding {
mode: BindingMode(ByRef::No, _, _), var, subpattern: None, ..
} => {
let place = self.storage_live_binding(
block,
var,
Expand All @@ -608,7 +610,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
box Pat {
kind:
PatKind::Binding {
mode: BindingMode(ByRef::No, _),
mode: BindingMode(ByRef::No, _, _),
var,
subpattern: None,
..
Expand Down Expand Up @@ -2758,7 +2760,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let tcx = self.tcx;
let debug_source_info = SourceInfo { span: source_info.span, scope: visibility_scope };
let local = LocalDecl {
mutability: mode.1,
mutability: mode.2,
ty: var_ty,
user_ty: if user_ty.is_empty() { None } else { Some(Box::new(user_ty)) },
source_info,
Expand Down
4 changes: 2 additions & 2 deletions compiler/rustc_mir_build/src/builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
// Don't introduce extra copies for simple bindings
PatKind::Binding {
var,
mode: BindingMode(ByRef::No, mutability),
mode: BindingMode(ByRef::No, pin, mutability),
subpattern: None,
..
} => {
Expand All @@ -978,7 +978,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
if let Some(kind) = param.self_kind {
LocalInfo::User(BindingForm::ImplicitSelf(kind))
} else {
let binding_mode = BindingMode(ByRef::No, mutability);
let binding_mode = BindingMode(ByRef::No, pin, mutability);
LocalInfo::User(BindingForm::Var(VarBindingForm {
binding_mode,
opt_ty_info: param.ty_span,
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/check_unsafety.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
}
visit::walk_pat(self, pat);
}
PatKind::Binding { mode: BindingMode(ByRef::Yes(rm), _), ty, .. } => {
PatKind::Binding { mode: BindingMode(ByRef::Yes(rm), _, _), ty, .. } => {
if self.inside_adt {
let ty::Ref(_, ty, _) = ty.kind() else {
span_bug!(
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_mir_build/src/thir/pattern/check_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -876,7 +876,7 @@ fn check_for_bindings_named_same_as_variants(
) {
if let PatKind::Binding {
name,
mode: BindingMode(ByRef::No, Mutability::Not),
mode: BindingMode(ByRef::No, _, Mutability::Not),
subpattern: None,
ty,
..
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_parse/messages.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,8 @@ parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable
parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
parse_note_pin_pattern_usage = `pin mut` or `pin const` may be followed by `variable` and `variable @ pattern`
parse_nul_in_c_str = null characters in C string literals are not supported
parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
Expand Down Expand Up @@ -698,6 +700,11 @@ parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@`
.label_binding = binding on the right, should be on the left
.suggestion = switch the order
parse_pin_on_nested_ident_pattern = `pin {$mutbl}` must be attached to each individual binding
.suggestion = add `pin {$mutbl}` to each binding
parse_pin_on_non_ident_pattern = `pin {$mutbl}` must be followed by a named binding
.suggestion = remove the `pin {$mutbl}` prefix
parse_question_mark_in_type = invalid `?` in type
.label = `?` is only allowed on expressions, not types
.suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type
Expand Down
Loading

0 comments on commit 87de2da

Please sign in to comment.