Skip to content

Commit ae698f8

Browse files
committed
Add sugar for &pin (const|mut) types
1 parent 7caad69 commit ae698f8

File tree

23 files changed

+283
-62
lines changed

23 files changed

+283
-62
lines changed

Diff for: compiler/rustc_ast/src/ast.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use std::{cmp, fmt, mem};
2323

2424
pub use GenericArgs::*;
2525
pub use UnsafeSource::*;
26-
pub use rustc_ast_ir::{Movability, Mutability};
26+
pub use rustc_ast_ir::{Movability, Mutability, Pinnedness};
2727
use rustc_data_structures::packed::Pu128;
2828
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
2929
use rustc_data_structures::stack::ensure_sufficient_stack;
@@ -2161,6 +2161,10 @@ pub enum TyKind {
21612161
Ptr(MutTy),
21622162
/// A reference (`&'a T` or `&'a mut T`).
21632163
Ref(Option<Lifetime>, MutTy),
2164+
/// A pinned reference (`&'a pin const T` or `&'a pin mut T`).
2165+
///
2166+
/// Desugars into `Pin<&'a T>` or `Pin<&'a mut T>`.
2167+
PinnedRef(Option<Lifetime>, MutTy),
21642168
/// A bare function (e.g., `fn(usize) -> bool`).
21652169
BareFn(P<BareFnTy>),
21662170
/// The never type (`!`).
@@ -2509,7 +2513,10 @@ impl Param {
25092513
if ident.name == kw::SelfLower {
25102514
return match self.ty.kind {
25112515
TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
2512-
TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
2516+
TyKind::Ref(lt, MutTy { ref ty, mutbl })
2517+
| TyKind::PinnedRef(lt, MutTy { ref ty, mutbl })
2518+
if ty.kind.is_implicit_self() =>
2519+
{
25132520
Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
25142521
}
25152522
_ => Some(respan(

Diff for: compiler/rustc_ast/src/mut_visit.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -485,7 +485,7 @@ pub fn walk_ty<T: MutVisitor>(vis: &mut T, ty: &mut P<Ty>) {
485485
}
486486
TyKind::Slice(ty) => vis.visit_ty(ty),
487487
TyKind::Ptr(mt) => vis.visit_mt(mt),
488-
TyKind::Ref(lt, mt) => {
488+
TyKind::Ref(lt, mt) | TyKind::PinnedRef(lt, mt) => {
489489
visit_opt(lt, |lt| vis.visit_lifetime(lt));
490490
vis.visit_mt(mt);
491491
}

Diff for: compiler/rustc_ast/src/util/classify.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,9 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> {
247247
break (mac.args.delim == Delimiter::Brace).then_some(mac);
248248
}
249249

250-
ast::TyKind::Ptr(mut_ty) | ast::TyKind::Ref(_, mut_ty) => {
250+
ast::TyKind::Ptr(mut_ty)
251+
| ast::TyKind::Ref(_, mut_ty)
252+
| ast::TyKind::PinnedRef(_, mut_ty) => {
251253
ty = &mut_ty.ty;
252254
}
253255

Diff for: compiler/rustc_ast/src/visit.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -499,7 +499,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result {
499499
match kind {
500500
TyKind::Slice(ty) | TyKind::Paren(ty) => try_visit!(visitor.visit_ty(ty)),
501501
TyKind::Ptr(MutTy { ty, mutbl: _ }) => try_visit!(visitor.visit_ty(ty)),
502-
TyKind::Ref(opt_lifetime, MutTy { ty, mutbl: _ }) => {
502+
TyKind::Ref(opt_lifetime, MutTy { ty, mutbl: _ })
503+
| TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl: _ }) => {
503504
visit_opt!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref);
504505
try_visit!(visitor.visit_ty(ty));
505506
}

Diff for: compiler/rustc_ast_ir/src/lib.rs

+7
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,10 @@ impl Mutability {
7979
matches!(self, Self::Not)
8080
}
8181
}
82+
83+
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)]
84+
#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))]
85+
pub enum Pinnedness {
86+
Not,
87+
Pinned,
88+
}

Diff for: compiler/rustc_ast_lowering/src/expr.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -640,7 +640,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
640640
self.lower_span(span),
641641
Some(self.allow_gen_future.clone()),
642642
);
643-
let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span);
643+
let resume_ty =
644+
self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None);
644645
let input_ty = hir::Ty {
645646
hir_id: self.next_id(),
646647
kind: hir::TyKind::Path(resume_ty),
@@ -2065,7 +2066,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
20652066
lang_item: hir::LangItem,
20662067
name: Symbol,
20672068
) -> hir::Expr<'hir> {
2068-
let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span));
2069+
let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span), None);
20692070
let path = hir::ExprKind::Path(hir::QPath::TypeRelative(
20702071
self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))),
20712072
self.arena.alloc(hir::PathSegment::new(

Diff for: compiler/rustc_ast_lowering/src/lib.rs

+43-8
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey};
5555
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
5656
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE, LocalDefId, LocalDefIdMap};
5757
use rustc_hir::{
58-
self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName,
59-
TraitCandidate,
58+
self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, MissingLifetimeKind,
59+
ParamName, TraitCandidate,
6060
};
6161
use rustc_index::{Idx, IndexSlice, IndexVec};
6262
use rustc_macros::extension;
@@ -765,8 +765,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
765765
res
766766
}
767767

768-
fn make_lang_item_qpath(&mut self, lang_item: hir::LangItem, span: Span) -> hir::QPath<'hir> {
769-
hir::QPath::Resolved(None, self.make_lang_item_path(lang_item, span, None))
768+
fn make_lang_item_qpath(
769+
&mut self,
770+
lang_item: hir::LangItem,
771+
span: Span,
772+
args: Option<&'hir hir::GenericArgs<'hir>>,
773+
) -> hir::QPath<'hir> {
774+
hir::QPath::Resolved(None, self.make_lang_item_path(lang_item, span, args))
770775
}
771776

772777
fn make_lang_item_path(
@@ -1317,6 +1322,32 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
13171322
let lifetime = self.lower_lifetime(&region);
13181323
hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx))
13191324
}
1325+
TyKind::PinnedRef(region, mt) => {
1326+
let region = region.unwrap_or_else(|| {
1327+
let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) =
1328+
self.resolver.get_lifetime_res(t.id)
1329+
{
1330+
debug_assert_eq!(start.plus(1), end);
1331+
start
1332+
} else {
1333+
self.next_node_id()
1334+
};
1335+
let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi();
1336+
Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id }
1337+
});
1338+
let lifetime = self.lower_lifetime(&region);
1339+
let kind = hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx));
1340+
let span = self.lower_span(t.span);
1341+
let arg = hir::Ty { kind, span, hir_id: self.next_id() };
1342+
let args = self.arena.alloc(hir::GenericArgs {
1343+
args: self.arena.alloc([hir::GenericArg::Type(self.arena.alloc(arg))]),
1344+
constraints: &[],
1345+
parenthesized: hir::GenericArgsParentheses::No,
1346+
span_ext: span,
1347+
});
1348+
let path = self.make_lang_item_qpath(LangItem::Pin, span, Some(args));
1349+
hir::TyKind::Path(path)
1350+
}
13201351
TyKind::BareFn(f) => {
13211352
let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params);
13221353
hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy {
@@ -1882,10 +1913,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
18821913
// Given we are only considering `ImplicitSelf` types, we needn't consider
18831914
// the case where we have a mutable pattern to a reference as that would
18841915
// no longer be an `ImplicitSelf`.
1885-
TyKind::Ref(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl {
1886-
hir::Mutability::Not => hir::ImplicitSelfKind::RefImm,
1887-
hir::Mutability::Mut => hir::ImplicitSelfKind::RefMut,
1888-
},
1916+
TyKind::Ref(_, mt) | TyKind::PinnedRef(_, mt)
1917+
if mt.ty.kind.is_implicit_self() =>
1918+
{
1919+
match mt.mutbl {
1920+
hir::Mutability::Not => hir::ImplicitSelfKind::RefImm,
1921+
hir::Mutability::Mut => hir::ImplicitSelfKind::RefMut,
1922+
}
1923+
}
18891924
_ => hir::ImplicitSelfKind::None,
18901925
}
18911926
}),

Diff for: compiler/rustc_ast_lowering/src/lifetime_collector.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> {
9595
visit::walk_ty(self, t);
9696
self.current_binders.pop();
9797
}
98-
TyKind::Ref(None, _) => {
98+
TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => {
9999
self.record_elided_anchor(t.id, t.span);
100100
visit::walk_ty(self, t);
101101
}

Diff for: compiler/rustc_ast_passes/src/feature_gate.rs

+1
Original file line numberDiff line numberDiff line change
@@ -547,6 +547,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) {
547547
gate_all!(mut_ref, "mutable by-reference bindings are experimental");
548548
gate_all!(global_registration, "global registration is experimental");
549549
gate_all!(return_type_notation, "return type notation is experimental");
550+
gate_all!(pin_ergonomics, "pinned reference syntax is experimental");
550551

551552
if !visitor.features.never_patterns {
552553
if let Some(spans) = spans.get(&sym::never_patterns) {

Diff for: compiler/rustc_ast_pretty/src/pprust/state.rs

+6
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,12 @@ impl<'a> State<'a> {
11631163
self.print_opt_lifetime(lifetime);
11641164
self.print_mt(mt, false);
11651165
}
1166+
ast::TyKind::PinnedRef(lifetime, mt) => {
1167+
self.word("&");
1168+
self.print_opt_lifetime(lifetime);
1169+
self.word("pin ");
1170+
self.print_mt(mt, true);
1171+
}
11661172
ast::TyKind::Never => {
11671173
self.word("!");
11681174
}

Diff for: compiler/rustc_hir/src/hir.rs

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
use std::fmt;
22

3-
use rustc_ast as ast;
43
use rustc_ast::util::parser::ExprPrecedence;
54
use rustc_ast::{
6-
Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitKind,
7-
TraitObjectSyntax, UintTy,
5+
self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label,
6+
LitKind, TraitObjectSyntax, UintTy,
87
};
98
pub use rustc_ast::{
109
BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability,

Diff for: compiler/rustc_parse/src/parser/ty.rs

+34-5
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@ use rustc_ast::ptr::P;
22
use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token, TokenKind};
33
use rustc_ast::util::case::Case;
44
use rustc_ast::{
5-
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, DUMMY_NODE_ID, FnRetTy,
6-
GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability,
7-
PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind,
5+
self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound, GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, Pinnedness, PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID
86
};
97
use rustc_errors::{Applicability, PResult};
108
use rustc_span::symbol::{Ident, kw, sym};
@@ -529,7 +527,10 @@ impl<'a> Parser<'a> {
529527
fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> {
530528
let and_span = self.prev_token.span;
531529
let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime());
532-
let mut mutbl = self.parse_mutability();
530+
let (pinned, mut mutbl) = match self.parse_pin_and_mut() {
531+
Some(pin_mut) => pin_mut,
532+
None => (Pinnedness::Not, self.parse_mutability()),
533+
};
533534
if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() {
534535
// A lifetime is invalid here: it would be part of a bare trait bound, which requires
535536
// it to be followed by a plus, but we disallow plus in the pointee type.
@@ -565,7 +566,35 @@ impl<'a> Parser<'a> {
565566
self.bump_with((dyn_tok, dyn_tok_sp));
566567
}
567568
let ty = self.parse_ty_no_plus()?;
568-
Ok(TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }))
569+
Ok(match pinned {
570+
Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }),
571+
Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }),
572+
})
573+
}
574+
575+
/// Parses `pin` and `mut` annotations on references.
576+
///
577+
/// It must be either `pin const` or `pin mut`.
578+
pub(crate) fn parse_pin_and_mut(&mut self) -> Option<(Pinnedness, Mutability)> {
579+
if self.token.is_ident_named(sym::pin) {
580+
let result = self.look_ahead(1, |token| {
581+
if token.is_keyword(kw::Const) {
582+
Some((Pinnedness::Pinned, Mutability::Not))
583+
} else if token.is_keyword(kw::Mut) {
584+
Some((Pinnedness::Pinned, Mutability::Mut))
585+
} else {
586+
None
587+
}
588+
});
589+
if result.is_some() {
590+
self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
591+
self.bump();
592+
self.bump();
593+
}
594+
result
595+
} else {
596+
None
597+
}
569598
}
570599

571600
// Parses the `typeof(EXPR)`.

Diff for: compiler/rustc_passes/src/hir_stats.rs

+27-23
Original file line numberDiff line numberDiff line change
@@ -574,29 +574,33 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
574574
}
575575

576576
fn visit_ty(&mut self, t: &'v ast::Ty) {
577-
record_variants!((self, t, t.kind, Id::None, ast, Ty, TyKind), [
578-
Slice,
579-
Array,
580-
Ptr,
581-
Ref,
582-
BareFn,
583-
Never,
584-
Tup,
585-
AnonStruct,
586-
AnonUnion,
587-
Path,
588-
Pat,
589-
TraitObject,
590-
ImplTrait,
591-
Paren,
592-
Typeof,
593-
Infer,
594-
ImplicitSelf,
595-
MacCall,
596-
CVarArgs,
597-
Dummy,
598-
Err
599-
]);
577+
record_variants!(
578+
(self, t, t.kind, Id::None, ast, Ty, TyKind),
579+
[
580+
Slice,
581+
Array,
582+
Ptr,
583+
Ref,
584+
PinnedRef,
585+
BareFn,
586+
Never,
587+
Tup,
588+
AnonStruct,
589+
AnonUnion,
590+
Path,
591+
Pat,
592+
TraitObject,
593+
ImplTrait,
594+
Paren,
595+
Typeof,
596+
Infer,
597+
ImplicitSelf,
598+
MacCall,
599+
CVarArgs,
600+
Dummy,
601+
Err
602+
]
603+
);
600604

601605
ast_visit::walk_ty(self, t)
602606
}

Diff for: compiler/rustc_resolve/src/late.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r
779779
let prev = self.diag_metadata.current_trait_object;
780780
let prev_ty = self.diag_metadata.current_type_path;
781781
match &ty.kind {
782-
TyKind::Ref(None, _) => {
782+
TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => {
783783
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
784784
// NodeId `ty.id`.
785785
// This span will be used in case of elision failure.
@@ -2326,7 +2326,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
23262326
impl<'ra> Visitor<'ra> for FindReferenceVisitor<'_, '_, '_> {
23272327
fn visit_ty(&mut self, ty: &'ra Ty) {
23282328
trace!("FindReferenceVisitor considering ty={:?}", ty);
2329-
if let TyKind::Ref(lt, _) = ty.kind {
2329+
if let TyKind::Ref(lt, _) | TyKind::PinnedRef(lt, _) = ty.kind {
23302330
// See if anything inside the &thing contains Self
23312331
let mut visitor =
23322332
SelfVisitor { r: self.r, impl_self: self.impl_self, self_found: false };

Diff for: compiler/rustc_resolve/src/late/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3482,7 +3482,7 @@ struct LifetimeFinder<'ast> {
34823482

34833483
impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> {
34843484
fn visit_ty(&mut self, t: &'ast Ty) {
3485-
if let TyKind::Ref(_, mut_ty) = &t.kind {
3485+
if let TyKind::Ref(_, mut_ty) | TyKind::PinnedRef(_, mut_ty) = &t.kind {
34863486
self.seen.push(t);
34873487
if t.span.lo() == self.lifetime.lo() {
34883488
self.found = Some(&mut_ty.ty);

Diff for: src/tools/clippy/clippy_utils/src/ast_utils.rs

+3
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,9 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool {
753753
(Ref(ll, l), Ref(rl, r)) => {
754754
both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
755755
},
756+
(PinnedRef(ll, l), PinnedRef(rl, r)) => {
757+
both(ll.as_ref(), rl.as_ref(), |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty)
758+
},
756759
(BareFn(l), BareFn(r)) => {
757760
l.safety == r.safety
758761
&& eq_ext(&l.ext, &r.ext)

Diff for: src/tools/rustfmt/src/types.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -827,7 +827,8 @@ impl Rewrite for ast::Ty {
827827

828828
rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
829829
}
830-
ast::TyKind::Ref(ref lifetime, ref mt) => {
830+
ast::TyKind::Ref(ref lifetime, _pinned, ref mt) => {
831+
// FIXME: format pinnedness
831832
let mut_str = format_mutability(mt.mutbl);
832833
let mut_len = mut_str.len();
833834
let mut result = String::with_capacity(128);
@@ -1262,7 +1263,7 @@ pub(crate) fn can_be_overflowed_type(
12621263
) -> bool {
12631264
match ty.kind {
12641265
ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
1265-
ast::TyKind::Ref(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
1266+
ast::TyKind::Ref(_, _, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
12661267
can_be_overflowed_type(context, &*mutty.ty, len)
12671268
}
12681269
_ => false,

0 commit comments

Comments
 (0)