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 2 commits 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 @@ -720,18 +720,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 @@ -741,6 +745,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 @@ -2604,7 +2611,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 @@ -2659,7 +2668,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 @@ -93,3 +93,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 @@ -1283,7 +1283,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 @@ -1628,7 +1628,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 @@ -1620,7 +1620,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 @@ -305,7 +305,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 @@ -1144,7 +1144,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 @@ -1223,7 +1223,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 @@ -1438,7 +1438,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 @@ -1470,7 +1470,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/hir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use rustc_ast::{
};
pub use rustc_ast::{
BinOp, BinOpKind, BindingMode, BorrowKind, BoundConstness, BoundPolarity, ByRef, CaptureBy,
ImplPolarity, IsAuto, Movability, Mutability, UnOp, UnsafeBinderCastKind,
ImplPolarity, IsAuto, Movability, Mutability, Pinnedness, UnOp, UnsafeBinderCastKind,
};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;
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::Expr(_)
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 @@ -1914,7 +1914,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
20 changes: 11 additions & 9 deletions compiler/rustc_hir_typeck/src/pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::{
self as hir, BindingMode, ByRef, ExprKind, HirId, LangItem, Mutability, Pat, PatExpr,
PatExprKind, PatKind, expr_needs_parens,
PatExprKind, PatKind, Pinnedness, expr_needs_parens,
};
use rustc_infer::infer;
use rustc_middle::traits::PatternOriginExpr;
Expand Down Expand Up @@ -824,7 +824,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {

// Determine the binding mode...
let bm = match user_bind_annot {
BindingMode(ByRef::No, Mutability::Mut) if let ByRef::Yes(def_br_mutbl) = def_br => {
BindingMode(ByRef::No, pin, Mutability::Mut)
if let ByRef::Yes(def_br_mutbl) = def_br =>
{
// 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 @@ -841,7 +843,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 @@ -850,11 +852,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
't', // last char of `mut`
def_br_mutbl,
);
BindingMode(ByRef::No, Mutability::Mut)
BindingMode(ByRef::No, pin, Mutability::Mut)
}
}
BindingMode(ByRef::No, mutbl) => BindingMode(def_br, mutbl),
BindingMode(ByRef::Yes(user_br_mutbl), _) => {
BindingMode(ByRef::No, pin, mutbl) => BindingMode(def_br, pin, mutbl),
BindingMode(ByRef::Yes(user_br_mutbl), _, _) => {
if let ByRef::Yes(def_br_mutbl) = def_br {
// `ref`/`ref mut` overrides the binding mode on edition <= 2021
self.add_rust_2024_migration_desugared_pat(
Expand Down Expand Up @@ -1079,7 +1081,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 Expand Up @@ -2872,8 +2874,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If the user-provided binding modifier doesn't match the default binding mode, we'll
// need to suggest reference patterns, which can affect other bindings.
// For simplicity, we opt to suggest making the pattern fully explicit.
info.suggest_eliding_modes &=
user_bind_annot == BindingMode(ByRef::Yes(def_br_mutbl), Mutability::Not);
info.suggest_eliding_modes &= user_bind_annot
== BindingMode(ByRef::Yes(def_br_mutbl), Pinnedness::Not, Mutability::Not);
"binding modifier"
} else {
info.bad_ref_pats = true;
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 @@ -1802,7 +1803,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
6 changes: 4 additions & 2 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::def_id::{CRATE_DEF_ID, DefId};
use rustc_hir::{
self as hir, BindingMode, ByRef, CoroutineDesugaring, CoroutineKind, HirId, ImplicitSelfKind,
Pinnedness,
};
use rustc_index::bit_set::DenseBitSet;
use rustc_index::{Idx, IndexSlice, IndexVec};
Expand Down Expand Up @@ -1094,7 +1095,8 @@ impl<'tcx> LocalDecl<'tcx> {
self.local_info(),
LocalInfo::User(
BindingForm::Var(VarBindingForm {
binding_mode: BindingMode(ByRef::No, _),
// FIXME(pin_ergonomics): `pin const` can also be made mutable, but needs special handling.
binding_mode: BindingMode(ByRef::No, Pinnedness::Not, _),
opt_ty_info: _,
opt_match_place: _,
pat_span: _,
Expand All @@ -1111,7 +1113,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 @@ -633,7 +633,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 @@ -454,7 +454,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 @@ -594,7 +594,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 @@ -618,7 +620,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
ref subpattern,
ascription: thir::Ascription { ref annotation, variance: _ },
} if let PatKind::Binding {
mode: BindingMode(ByRef::No, _),
mode: BindingMode(ByRef::No, _, _),
var,
subpattern: None,
..
Expand Down Expand Up @@ -2772,7 +2774,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 @@ -953,7 +953,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 @@ -963,7 +963,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
Loading
Loading