Skip to content

Commit 545134a

Browse files
Merge pull request #22022 from ChayimFriedman2/restrictions
feat: Support `impl` and `mut` restrictions
2 parents 0b3ff84 + 3fdd9a2 commit 545134a

23 files changed

Lines changed: 581 additions & 117 deletions

crates/ide-completion/src/context/analysis.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1592,7 +1592,7 @@ fn classify_name_ref<'db>(
15921592
kind_macro_call(it)?
15931593
},
15941594
ast::Meta(meta) => make_path_kind_attr(meta)?,
1595-
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
1595+
ast::VisibilityInner(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
15961596
ast::UseTree(_) => PathKind::Use,
15971597
// completing inside a qualifier
15981598
ast::Path(parent) => {
@@ -1621,7 +1621,7 @@ fn classify_name_ref<'db>(
16211621
kind_macro_call(it)?
16221622
},
16231623
ast::Meta(meta) => make_path_kind_attr(meta)?,
1624-
ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
1624+
ast::VisibilityInner(it) => PathKind::Vis { has_in_token: it.in_token().is_some() },
16251625
ast::UseTree(_) => PathKind::Use,
16261626
ast::RecordExpr(it) => make_path_kind_expr(it.into()),
16271627
_ => return None,

crates/parser/src/grammar.rs

Lines changed: 49 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -228,48 +228,61 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool {
228228

229229
let m = p.start();
230230
p.bump(T![pub]);
231-
if p.at(T!['(']) {
232-
match p.nth(1) {
233-
// test crate_visibility
234-
// pub(crate) struct S;
235-
// pub(self) struct S;
236-
// pub(super) struct S;
237-
238-
// test_err crate_visibility_empty_recover
239-
// pub() struct S;
240-
241-
// test pub_parens_typepath
242-
// struct B(pub (super::A));
243-
// struct B(pub (crate::A,));
244-
T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => {
245-
// If we are in a tuple struct, then the parens following `pub`
246-
// might be an tuple field, not part of the visibility. So in that
247-
// case we don't want to consume an identifier.
248-
249-
// test pub_tuple_field
250-
// struct MyStruct(pub (u32, u32));
251-
// struct MyStruct(pub (u32));
252-
// struct MyStruct(pub ());
253-
if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) {
254-
p.bump(T!['(']);
255-
paths::vis_path(p);
256-
p.expect(T![')']);
257-
}
258-
}
259-
// test crate_visibility_in
260-
// pub(in super::A) struct S;
261-
// pub(in crate) struct S;
262-
T![in] => {
231+
opt_visibility_inner(p, in_tuple_field);
232+
m.complete(p, VISIBILITY);
233+
true
234+
}
235+
236+
fn opt_visibility_inner(p: &mut Parser<'_>, in_tuple_field: bool) -> bool {
237+
if !p.at(T!['(']) {
238+
return false;
239+
}
240+
241+
match p.nth(1) {
242+
// test crate_visibility
243+
// pub(crate) struct S;
244+
// pub(self) struct S;
245+
// pub(super) struct S;
246+
247+
// test_err crate_visibility_empty_recover
248+
// pub() struct S;
249+
250+
// test pub_parens_typepath
251+
// struct B(pub (super::A));
252+
// struct B(pub (crate::A,));
253+
T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => {
254+
// If we are in a tuple struct, then the parens following `pub`
255+
// might be an tuple field, not part of the visibility. So in that
256+
// case we don't want to consume an identifier.
257+
258+
// test pub_tuple_field
259+
// struct MyStruct(pub (u32, u32));
260+
// struct MyStruct(pub (u32));
261+
// struct MyStruct(pub ());
262+
if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) {
263+
let m = p.start();
263264
p.bump(T!['(']);
264-
p.bump(T![in]);
265265
paths::vis_path(p);
266266
p.expect(T![')']);
267+
m.complete(p, VISIBILITY_INNER);
268+
return true;
267269
}
268-
_ => {}
269270
}
271+
// test crate_visibility_in
272+
// pub(in super::A) struct S;
273+
// pub(in crate) struct S;
274+
T![in] => {
275+
let m = p.start();
276+
p.bump(T!['(']);
277+
p.bump(T![in]);
278+
paths::vis_path(p);
279+
p.expect(T![')']);
280+
m.complete(p, VISIBILITY_INNER);
281+
return true;
282+
}
283+
_ => {}
270284
}
271-
m.complete(p, VISIBILITY);
272-
true
285+
false
273286
}
274287

275288
fn opt_rename(p: &mut Parser<'_>) {

crates/parser/src/grammar/items.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,25 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker, is_in_extern: bool) -> Res
167167
has_mods = true;
168168
}
169169

170+
if p.at(T![impl])
171+
&& p.nth(1) == T!['(']
172+
&& ((matches!(p.nth(2), T![crate] | T![super] | T![self]) && p.nth(3) == T![')'])
173+
|| p.nth(2) == T![in])
174+
{
175+
// test impl_restrictions
176+
// pub unsafe impl(crate) trait Foo {}
177+
// impl(in super::bar) trait Bar {}
178+
// impl () {}
179+
// impl (i32) {}
180+
let m = p.start();
181+
p.bump(T![impl]);
182+
if !opt_visibility_inner(p, false) {
183+
p.error("expected an impl restriction");
184+
}
185+
m.complete(p, IMPL_RESTRICTION);
186+
has_mods = true;
187+
}
188+
170189
// test default_item
171190
// default impl T for Foo {}
172191
if p.at_contextual_kw(T![default]) {

crates/parser/src/grammar/items/adt.rs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,30 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) {
133133
// struct S { #[attr] f: f32 }
134134
attributes::outer_attrs(p);
135135
opt_visibility(p, false);
136-
p.eat(T![unsafe]);
136+
137+
if p.at(T![mut]) && p.nth(1) == T!['('] {
138+
// test record_mut_restrictions_before
139+
// struct Foo { mut(super) unsafe i: i32 }
140+
let m = p.start();
141+
p.bump(T![mut]);
142+
if !opt_visibility_inner(p, false) {
143+
p.error("expected a mut restriction");
144+
}
145+
m.complete(p, MUT_RESTRICTION);
146+
}
147+
148+
// We accept mut restriction both after and before `unsafe`, as the order is undecided yet.
149+
if p.eat(T![unsafe]) && p.at(T![mut]) && p.nth(1) == T!['('] {
150+
// test record_mut_restrictions_after
151+
// struct Foo { unsafe mut(super) i: i32 }
152+
let m = p.start();
153+
p.bump(T![mut]);
154+
if !opt_visibility_inner(p, false) {
155+
p.error("expected a mut restriction");
156+
}
157+
m.complete(p, MUT_RESTRICTION);
158+
}
159+
137160
if p.at(IDENT) {
138161
name(p);
139162
p.expect(T![:]);
@@ -175,6 +198,18 @@ fn tuple_field_list(p: &mut Parser<'_>) {
175198
// struct S (#[attr] f32);
176199
attributes::outer_attrs(p);
177200
let has_vis = opt_visibility(p, true);
201+
202+
if p.at(T![mut]) && p.nth(1) == T!['('] {
203+
// test tuple_mut_restrictions
204+
// struct Foo(pub(crate) mut(super) i32);
205+
let m = p.start();
206+
p.bump(T![mut]);
207+
if !opt_visibility_inner(p, false) {
208+
p.error("expected a mut restriction");
209+
}
210+
m.complete(p, MUT_RESTRICTION);
211+
}
212+
178213
if !p.at_ts(types::TYPE_FIRST) {
179214
p.error("expected a type");
180215
if has_vis {

crates/parser/src/syntax_kind/generated.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ pub enum SyntaxKind {
218218
IDENT_PAT,
219219
IF_EXPR,
220220
IMPL,
221+
IMPL_RESTRICTION,
221222
IMPL_TRAIT_TYPE,
222223
INDEX_EXPR,
223224
INFER_TYPE,
@@ -247,6 +248,7 @@ pub enum SyntaxKind {
247248
MATCH_GUARD,
248249
METHOD_CALL_EXPR,
249250
MODULE,
251+
MUT_RESTRICTION,
250252
NAME,
251253
NAME_REF,
252254
NEVER_TYPE,
@@ -318,6 +320,7 @@ pub enum SyntaxKind {
318320
VARIANT,
319321
VARIANT_LIST,
320322
VISIBILITY,
323+
VISIBILITY_INNER,
321324
WHERE_CLAUSE,
322325
WHERE_PRED,
323326
WHILE_EXPR,
@@ -399,6 +402,7 @@ impl SyntaxKind {
399402
| IDENT_PAT
400403
| IF_EXPR
401404
| IMPL
405+
| IMPL_RESTRICTION
402406
| IMPL_TRAIT_TYPE
403407
| INDEX_EXPR
404408
| INFER_TYPE
@@ -428,6 +432,7 @@ impl SyntaxKind {
428432
| MATCH_GUARD
429433
| METHOD_CALL_EXPR
430434
| MODULE
435+
| MUT_RESTRICTION
431436
| NAME
432437
| NAME_REF
433438
| NEVER_TYPE
@@ -499,6 +504,7 @@ impl SyntaxKind {
499504
| VARIANT
500505
| VARIANT_LIST
501506
| VISIBILITY
507+
| VISIBILITY_INNER
502508
| WHERE_CLAUSE
503509
| WHERE_PRED
504510
| WHILE_EXPR

crates/parser/test_data/generated/runner.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,10 @@ mod ok {
348348
run_and_expect_no_errors("test_data/parser/inline/ok/impl_item_never_type.rs");
349349
}
350350
#[test]
351+
fn impl_restrictions() {
352+
run_and_expect_no_errors("test_data/parser/inline/ok/impl_restrictions.rs");
353+
}
354+
#[test]
351355
fn impl_trait_type() {
352356
run_and_expect_no_errors("test_data/parser/inline/ok/impl_trait_type.rs");
353357
}
@@ -556,6 +560,14 @@ mod ok {
556560
run_and_expect_no_errors("test_data/parser/inline/ok/record_literal_field_with_attr.rs");
557561
}
558562
#[test]
563+
fn record_mut_restrictions_after() {
564+
run_and_expect_no_errors("test_data/parser/inline/ok/record_mut_restrictions_after.rs");
565+
}
566+
#[test]
567+
fn record_mut_restrictions_before() {
568+
run_and_expect_no_errors("test_data/parser/inline/ok/record_mut_restrictions_before.rs");
569+
}
570+
#[test]
559571
fn record_pat_field() {
560572
run_and_expect_no_errors("test_data/parser/inline/ok/record_pat_field.rs");
561573
}
@@ -658,6 +670,10 @@ mod ok {
658670
run_and_expect_no_errors("test_data/parser/inline/ok/tuple_field_attrs.rs");
659671
}
660672
#[test]
673+
fn tuple_mut_restrictions() {
674+
run_and_expect_no_errors("test_data/parser/inline/ok/tuple_mut_restrictions.rs");
675+
}
676+
#[test]
661677
fn tuple_pat() { run_and_expect_no_errors("test_data/parser/inline/ok/tuple_pat.rs"); }
662678
#[test]
663679
fn tuple_pat_fields() {

crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ SOURCE_FILE
22
STRUCT
33
VISIBILITY
44
PUB_KW "pub"
5-
L_PAREN "("
6-
R_PAREN ")"
5+
VISIBILITY_INNER
6+
L_PAREN "("
7+
R_PAREN ")"
78
WHITESPACE " "
89
STRUCT_KW "struct"
910
WHITESPACE " "

crates/parser/test_data/parser/inline/ok/crate_visibility.rast

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@ SOURCE_FILE
22
STRUCT
33
VISIBILITY
44
PUB_KW "pub"
5-
L_PAREN "("
6-
PATH
7-
PATH_SEGMENT
8-
NAME_REF
9-
CRATE_KW "crate"
10-
R_PAREN ")"
5+
VISIBILITY_INNER
6+
L_PAREN "("
7+
PATH
8+
PATH_SEGMENT
9+
NAME_REF
10+
CRATE_KW "crate"
11+
R_PAREN ")"
1112
WHITESPACE " "
1213
STRUCT_KW "struct"
1314
WHITESPACE " "
@@ -18,12 +19,13 @@ SOURCE_FILE
1819
STRUCT
1920
VISIBILITY
2021
PUB_KW "pub"
21-
L_PAREN "("
22-
PATH
23-
PATH_SEGMENT
24-
NAME_REF
25-
SELF_KW "self"
26-
R_PAREN ")"
22+
VISIBILITY_INNER
23+
L_PAREN "("
24+
PATH
25+
PATH_SEGMENT
26+
NAME_REF
27+
SELF_KW "self"
28+
R_PAREN ")"
2729
WHITESPACE " "
2830
STRUCT_KW "struct"
2931
WHITESPACE " "
@@ -34,12 +36,13 @@ SOURCE_FILE
3436
STRUCT
3537
VISIBILITY
3638
PUB_KW "pub"
37-
L_PAREN "("
38-
PATH
39-
PATH_SEGMENT
40-
NAME_REF
41-
SUPER_KW "super"
42-
R_PAREN ")"
39+
VISIBILITY_INNER
40+
L_PAREN "("
41+
PATH
42+
PATH_SEGMENT
43+
NAME_REF
44+
SUPER_KW "super"
45+
R_PAREN ")"
4346
WHITESPACE " "
4447
STRUCT_KW "struct"
4548
WHITESPACE " "

0 commit comments

Comments
 (0)