Skip to content

Commit 545a81e

Browse files
committed
Parse impl restrictions
1 parent dbe4acb commit 545a81e

7 files changed

Lines changed: 105 additions & 53 deletions

File tree

src/cli/diagnostics.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ fn convert(error: Error, cx: RenderCx<'_>) -> Diag {
9797
Diag::new("string literal guard too large").highlight(span)
9898
}
9999
Error::ReservedMultiHash(span) => Diag::new("reserved multi-hash").highlight(span),
100+
Error::ImplRestrictedTraitAlias => Diag::new("trait aliases cannot be impl-restricted"),
100101
Error::InvalidEscapeSequence(span) => Diag::new("invalid escape sequence").highlight(span),
101102
Error::EmptyCharLit(span) => Diag::new("empty char literal").highlight(span),
102103
Error::MultiScalarCharLit(span) => Diag::new("multi-scalar char literal").highlight(span),

src/lib/ast/item.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,7 +259,7 @@ pub(crate) struct StructItem<'src> {
259259

260260
#[derive(Debug)]
261261
pub(crate) struct TraitItem<'src> {
262-
pub(crate) modifiers: TraitItemModifiers,
262+
pub(crate) modifiers: TraitItemModifiers<'src>,
263263
pub(crate) binder: Ident<'src>,
264264
pub(crate) generics: Generics<'src>,
265265
pub(crate) bounds: Vec<Bound<'src>>,
@@ -275,10 +275,11 @@ pub(crate) struct TraitAliasItem<'src> {
275275
}
276276

277277
#[derive(Default, Debug)]
278-
pub(crate) struct TraitItemModifiers {
278+
pub(crate) struct TraitItemModifiers<'src> {
279279
pub(crate) constness: Constness,
280280
pub(crate) safety: Safety,
281281
pub(crate) autoness: Autoness,
282+
pub(crate) impl_restriction: Option<Path<'src, NoGenericArgs>>,
282283
}
283284

284285
#[derive(Default, Debug)]

src/lib/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pub enum Error {
4848
FrontmatterOpeningTooLarge(Span),
4949
GenericArgsOnFieldExpr(Span),
5050
HigherRankedBinderOnInvalidBound(Span),
51+
ImplRestrictedTraitAlias,
5152
InvalidAbiStr(Span),
5253
InvalidAssocItemKind(Span),
5354
InvalidDigit(Span),

src/lib/fmter/item.rs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -526,13 +526,18 @@ impl Fmt for (ast::TraitItem<'_>, Vec<ast::Attr<'_, ast::attr::Inner>>) {
526526
}
527527
}
528528

529-
impl Fmt for TrailingSpace<ast::TraitItemModifiers> {
529+
impl Fmt for TrailingSpace<ast::TraitItemModifiers<'_>> {
530530
fn fmt(self, cx: &mut Cx<'_>) {
531-
let Self(ast::TraitItemModifiers { constness, safety, autoness }) = self;
531+
let Self(ast::TraitItemModifiers { constness, safety, autoness, impl_restriction }) = self;
532532

533533
constness.trailing_space().fmt(cx);
534534
safety.trailing_space().fmt(cx);
535535
autoness.trailing_space().fmt(cx);
536+
if let Some(path) = impl_restriction {
537+
fmt!(cx, "impl");
538+
Restriction(path).fmt(cx);
539+
fmt!(cx, " ");
540+
}
536541
}
537542
}
538543

@@ -683,21 +688,34 @@ impl Fmt for TrailingSpace<ast::Visibility<'_>> {
683688
match vis {
684689
ast::Visibility::Inherited => {}
685690
ast::Visibility::Restricted(path) => {
686-
fmt!(cx, "pub(");
687-
if let [ast::PathSeg { ident: ast::Ident!("crate" | "super" | "self"), args: () }] =
688-
&*path.segs
689-
{
690-
} else {
691-
fmt!(cx, "in ");
692-
}
693-
path.fmt(cx);
694-
fmt!(cx, ") ");
691+
fmt!(cx, "pub");
692+
Restriction(path).fmt(cx);
693+
fmt!(cx, " ");
695694
}
696695
ast::Visibility::Public => fmt!(cx, "pub "),
697696
}
698697
}
699698
}
700699

700+
struct Restriction<'src>(ast::Path<'src, ast::NoGenericArgs>);
701+
702+
impl Fmt for Restriction<'_> {
703+
fn fmt(self, cx: &mut Cx<'_>) {
704+
let Self(path) = self;
705+
706+
fmt!(cx, "(");
707+
if let [seg] = path.segs.as_slice()
708+
&& let name @ ("crate" | "super" | "self") = seg.ident.name
709+
{
710+
name.fmt(cx);
711+
} else {
712+
fmt!(cx, "in ");
713+
path.fmt(cx);
714+
}
715+
fmt!(cx, ")");
716+
}
717+
}
718+
701719
impl Fmt for TrailingSpace<ast::Constness> {
702720
fn fmt(self, cx: &mut Cx<'_>) {
703721
let Self(constness) = self;

src/lib/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#![feature(mut_ref)]
1414
#![feature(negative_impls)]
1515
#![feature(never_type)]
16+
#![feature(try_blocks)]
1617
#![feature(type_changing_struct_update)]
1718
// Lints
1819
#![expect(incomplete_features, reason = "deref_patterns")]

src/lib/parser.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,7 @@ mod test;
2020
mod ty;
2121
mod weak;
2222

23-
type Result<T, E = BufferedError> = std::result::Result<T, E>;
24-
25-
#[derive(Debug)]
26-
struct BufferedError(());
23+
type Result<T, E = ()> = std::result::Result<T, E>;
2724

2825
#[expect(clippy::missing_errors_doc)] // FIXME: TODO
2926
#[expect(clippy::result_unit_err)] // handled via an out-parameter
@@ -37,7 +34,7 @@ pub fn parse<'src>(
3734
let shebang = file.shebang.map(|shebang| this.source(shebang));
3835
let frontmatter = file.frontmatter.map(|frontmatter| this.source(frontmatter));
3936

40-
this.parse_file(shebang, frontmatter).map_err(drop)
37+
this.parse_file(shebang, frontmatter)
4138
}
4239

4340
struct Parser<'t, 'e, 'src> {
@@ -170,7 +167,7 @@ impl<'t, 'e, 'src> Parser<'t, 'e, 'src> {
170167

171168
fn fatal<T>(&mut self, error: Error) -> Result<T> {
172169
self.error(error);
173-
Err(BufferedError(()))
170+
Err(())
174171
}
175172

176173
// FIXME: Overload the ret ty to allow for `-> Option<Span>`
@@ -237,14 +234,14 @@ impl<'t, 'e, 'src> Parser<'t, 'e, 'src> {
237234
Parser { errors, ..*self }
238235
}
239236

240-
// FIXME: Improve impl
241237
fn probe<T>(
242238
&mut self,
243239
parse: impl FnOnce(&mut Parser<'_, '_, 'src>) -> Option<T>,
244240
) -> Option<T> {
245241
let mut errors = ErrorBuffer::Hold(Vec::new());
246242
let mut this = self.snapshot(&mut errors);
247243
parse(&mut this).inspect(|_| {
244+
let Self { tokens: _, errors: _, token: _, index: _, source: _, edition: _ };
248245
self.tokens = this.tokens;
249246
self.token = this.token;
250247
self.index = this.index;

src/lib/parser/item.rs

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::{
1010
error::{Buffer as ErrorBuffer, Error},
1111
span::Span,
1212
};
13+
use std::mem;
1314

1415
impl<'src> Parser<'_, '_, 'src> {
1516
/// Parse a sequence of items.
@@ -156,11 +157,11 @@ impl<'src> Parser<'_, '_, 'src> {
156157

157158
let start = self.token.span;
158159

159-
let qualifiers: Vec<_> =
160+
let mut qualifiers: Vec<_> =
160161
self.parse_item_qualifiers().map(|(qualifier, _)| qualifier).collect();
161162

162163
// FIXME: Provide more targeted diagnostics if the qualifiers don't make sense.
163-
match qualifiers.as_slice() {
164+
match qualifiers.as_mut_slice() {
164165
[] => {}
165166
[Qualifier::Type] => return self.fin_parse_ty_alias_item(defaultness),
166167
// FEATURE: `const_block_items` <https://github.com/rust-lang/rust/issues/149226>
@@ -201,7 +202,7 @@ impl<'src> Parser<'_, '_, 'src> {
201202

202203
return self.fin_parse_static_item(safety);
203204
}
204-
&[mut ref qualifiers @ .., Qualifier::Fn] => {
205+
&mut [mut ref mut qualifiers @ .., Qualifier::Fn] => {
205206
let mut modifiers = ast::FnItemModifiers { defaultness, .. };
206207

207208
(modifiers.constness, qualifiers) = Qualifier::strip_const(qualifiers);
@@ -222,7 +223,7 @@ impl<'src> Parser<'_, '_, 'src> {
222223

223224
return self.fin_parse_fn_item(modifiers, cx, attrs);
224225
}
225-
&[mut ref qualifiers @ .., Qualifier::Trait] => {
226+
&mut [mut ref mut qualifiers @ .., Qualifier::Trait] => {
226227
let mut modifiers = ast::TraitItemModifiers::default();
227228

228229
// FEATURE: `const_trait_impl` <https://github.com/rust-lang/rust/issues/143874>
@@ -233,6 +234,13 @@ impl<'src> Parser<'_, '_, 'src> {
233234
[Qualifier::Auto, qualifiers @ ..] => (ast::Autoness::Auto, qualifiers),
234235
_ => (ast::Autoness::Not, qualifiers),
235236
};
237+
(modifiers.impl_restriction, qualifiers) = match qualifiers {
238+
[Qualifier::ImplRestriction(path), qualifiers @ ..] => {
239+
let Ok(path) = path else { return Err(()) };
240+
(Some(mem::replace(path, ast::Path { segs: Vec::new() })), qualifiers)
241+
}
242+
_ => (None, qualifiers),
243+
};
236244
if !qualifiers.is_empty() {
237245
self.error(Error::InvalidItemPrefix(start.until(self.token.span)));
238246
}
@@ -327,6 +335,13 @@ impl<'src> Parser<'_, '_, 'src> {
327335
},
328336
TokenKind::Impl => {
329337
self.advance();
338+
339+
// FEATURE: `impl_restriction` <https://github.com/rust-lang/rust/issues/105077>
340+
if let Some(path) = self.parse_restriction(Some(TokenKind::Trait)) {
341+
yield (Qualifier::ImplRestriction(Box::new(path)), self.token.kind);
342+
continue;
343+
}
344+
330345
yield (Qualifier::Impl, self.token.kind);
331346
// Once we encounter `impl`, don't attempt to look for more item qualifiers.
332347
// That's because the grammar following an impl item's `impl` is very complex &
@@ -807,7 +822,7 @@ impl<'src> Parser<'_, '_, 'src> {
807822
/// <!-- FIXME: Add an EBNF section back in -->
808823
fn fin_parse_trait_item(
809824
&mut self,
810-
modifiers: ast::TraitItemModifiers,
825+
modifiers: ast::TraitItemModifiers<'src>,
811826
attrs: &mut Vec<ast::Attr<'src>>,
812827
) -> Result<ast::ItemKind<'src>> {
813828
let binder = self.parse_common_ident()?;
@@ -836,7 +851,7 @@ impl<'src> Parser<'_, '_, 'src> {
836851
/// Finish parsing a trait alias item.
837852
fn fin_parse_trait_alias_item(
838853
&mut self,
839-
modifiers: ast::TraitItemModifiers,
854+
modifiers: ast::TraitItemModifiers<'src>,
840855
binder: ast::Ident<'src>,
841856
params: Vec<ast::GenericParam<'src>>,
842857
) -> Result<ast::ItemKind<'src>> {
@@ -845,7 +860,7 @@ impl<'src> Parser<'_, '_, 'src> {
845860

846861
self.parse(TokenKind::Semicolon)?;
847862

848-
let ast::TraitItemModifiers { constness, safety, autoness } = modifiers;
863+
let ast::TraitItemModifiers { constness, safety, autoness, impl_restriction } = modifiers;
849864

850865
match safety {
851866
ast::Safety::Inherited => {}
@@ -857,6 +872,10 @@ impl<'src> Parser<'_, '_, 'src> {
857872
ast::Autoness::Not => {}
858873
}
859874

875+
if impl_restriction.is_some() {
876+
self.error(Error::ImplRestrictedTraitAlias);
877+
}
878+
860879
Ok(ast::ItemKind::TraitAlias(Box::new(ast::TraitAliasItem {
861880
constness,
862881
binder,
@@ -1025,43 +1044,57 @@ impl<'src> Parser<'_, '_, 'src> {
10251044
return Ok(ast::Visibility::Inherited);
10261045
}
10271046

1028-
enum VisKeyword {
1047+
if let Some(path) = self.parse_restriction(None) {
1048+
return Ok(ast::Visibility::Restricted(path?));
1049+
}
1050+
1051+
Ok(ast::Visibility::Public)
1052+
}
1053+
1054+
fn begins_visibility(&self) -> bool {
1055+
// To kept in sync with `Self::parse_visibility`.
1056+
1057+
self.token.kind == TokenKind::Pub
1058+
}
1059+
1060+
fn parse_restriction(
1061+
&mut self,
1062+
disambiguator: Option<TokenKind>,
1063+
) -> Option<Result<ast::Path<'src, ast::NoGenericArgs>>> {
1064+
enum Herald {
10291065
In,
10301066
CrateSuperSelf(Span),
10311067
}
10321068

1033-
// FIXME: Only do this lookahead dance for tuple struct fields. This way, we can
1034-
// can give better errors on invalid vis restrictions in the common cases.
10351069
if self.token.kind == TokenKind::OpenRoundBracket
10361070
&& let token = self.peek(1)
1037-
&& let Some(keyword) = match token.kind {
1071+
&& let Some(herald) = match token.kind {
10381072
TokenKind::Crate | TokenKind::Super | TokenKind::SelfLower
1039-
if let TokenKind::CloseRoundBracket = self.peek(2).kind =>
1073+
if let TokenKind::CloseRoundBracket = self.peek(2).kind
1074+
&& disambiguator.is_none_or(|t| self.peek(3).kind == t) =>
10401075
{
1041-
Some(VisKeyword::CrateSuperSelf(token.span))
1076+
Some(Herald::CrateSuperSelf(token.span))
10421077
}
1043-
TokenKind::In => Some(VisKeyword::In),
1078+
TokenKind::In => Some(Herald::In),
10441079
_ => None,
10451080
}
10461081
{
1047-
self.advance();
1048-
self.advance();
1082+
self.advance(); // parenthesis
1083+
self.advance(); // herald
10491084

1050-
let path = match keyword {
1051-
VisKeyword::In => self.parse_path(PathMode::Normal)?,
1052-
VisKeyword::CrateSuperSelf(span) => ast::Path::ident(self.ident(span)),
1085+
let path = try {
1086+
let path = match herald {
1087+
Herald::In => self.parse_path(PathMode::Normal)?,
1088+
Herald::CrateSuperSelf(span) => ast::Path::ident(self.ident(span)),
1089+
};
1090+
self.parse(TokenKind::CloseRoundBracket)?;
1091+
path
10531092
};
1054-
self.parse(TokenKind::CloseRoundBracket)?;
1055-
return Ok(ast::Visibility::Restricted(path));
1056-
}
10571093

1058-
Ok(ast::Visibility::Public)
1059-
}
1060-
1061-
fn begins_visibility(&self) -> bool {
1062-
// To kept in sync with `Self::parse_visibility`.
1094+
return Some(path);
1095+
}
10631096

1064-
self.token.kind == TokenKind::Pub
1097+
None
10651098
}
10661099
}
10671100

@@ -1121,7 +1154,6 @@ pub(super) enum ItemCx {
11211154
Trait,
11221155
}
11231156

1124-
#[derive(Clone, Copy)]
11251157
enum Qualifier<'src> {
11261158
Async,
11271159
Auto,
@@ -1130,6 +1162,7 @@ enum Qualifier<'src> {
11301162
Fn,
11311163
Gen,
11321164
Impl,
1165+
ImplRestriction(Box<Result<ast::Path<'src, ast::NoGenericArgs>>>),
11331166
Mod,
11341167
Reuse,
11351168
Safe,
@@ -1140,29 +1173,29 @@ enum Qualifier<'src> {
11401173
}
11411174

11421175
impl<'src> Qualifier<'src> {
1143-
fn strip_const(qualifiers: &[Self]) -> (ast::Constness, &[Self]) {
1176+
fn strip_const(qualifiers: &mut [Self]) -> (ast::Constness, &mut [Self]) {
11441177
match qualifiers {
11451178
[Self::Const, qualifiers @ ..] => (ast::Constness::Const, qualifiers),
11461179
_ => (ast::Constness::Not, qualifiers),
11471180
}
11481181
}
11491182

1150-
fn strip_unsafe(qualifiers: &[Self]) -> (ast::Safety, &[Self]) {
1183+
fn strip_unsafe(qualifiers: &mut [Self]) -> (ast::Safety, &mut [Self]) {
11511184
match qualifiers {
11521185
[Self::Unsafe, qualifiers @ ..] => (ast::Safety::Unsafe, qualifiers),
11531186
_ => (ast::Safety::Inherited, qualifiers),
11541187
}
11551188
}
11561189

1157-
fn strip_safety(qualifiers: &[Self]) -> (ast::Safety<()>, &[Self]) {
1190+
fn strip_safety(qualifiers: &mut [Self]) -> (ast::Safety<()>, &mut [Self]) {
11581191
match qualifiers {
11591192
[Self::Unsafe, qualifiers @ ..] => (ast::Safety::Unsafe, qualifiers),
11601193
[Self::Safe, qualifiers @ ..] => (ast::Safety::Safe(()), qualifiers),
11611194
_ => (ast::Safety::Inherited, qualifiers),
11621195
}
11631196
}
11641197

1165-
fn strip_extern(qualifiers: &[Self]) -> (ast::Externness<'src>, &[Self]) {
1198+
fn strip_extern(qualifiers: &mut [Self]) -> (ast::Externness<'src>, &mut [Self]) {
11661199
match qualifiers {
11671200
[Self::Extern(abi), qualifiers @ ..] => (ast::Externness::Extern(*abi), qualifiers),
11681201
_ => (ast::Externness::Not, qualifiers),

0 commit comments

Comments
 (0)