Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parse pinned local variable declarations #135631

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
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 @@ -790,7 +790,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(_)) => {
// Only mention the experimental `mut_ref` feature if if we're in edition 2024 and
// using other experimental matching features compatible with it.
if pat.span.at_least_rust_2024()
Expand All @@ -807,7 +807,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 @@ -816,11 +816,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 @@ -1043,7 +1043,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 @@ -963,7 +963,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 @@ -973,7 +973,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
Loading