Unnamed repository; edit this file 'description' to name the repository.
Support `impl` and `mut` restrictions
I chose the order of mut restrictions to be `unsafe mut(...)` for unsafe fields, but it's undecided yet.
23 files changed, 581 insertions, 117 deletions
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 2a293313f2..60f5dabefc 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -1592,7 +1592,7 @@ fn classify_name_ref<'db>( kind_macro_call(it)? }, ast::Meta(meta) => make_path_kind_attr(meta)?, - ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() }, + ast::VisibilityInner(it) => PathKind::Vis { has_in_token: it.in_token().is_some() }, ast::UseTree(_) => PathKind::Use, // completing inside a qualifier ast::Path(parent) => { @@ -1621,7 +1621,7 @@ fn classify_name_ref<'db>( kind_macro_call(it)? }, ast::Meta(meta) => make_path_kind_attr(meta)?, - ast::Visibility(it) => PathKind::Vis { has_in_token: it.in_token().is_some() }, + ast::VisibilityInner(it) => PathKind::Vis { has_in_token: it.in_token().is_some() }, ast::UseTree(_) => PathKind::Use, ast::RecordExpr(it) => make_path_kind_expr(it.into()), _ => return None, diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs index 1ff8a56b58..e8a9ddde69 100644 --- a/crates/parser/src/grammar.rs +++ b/crates/parser/src/grammar.rs @@ -228,48 +228,61 @@ fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { let m = p.start(); p.bump(T![pub]); - if p.at(T!['(']) { - match p.nth(1) { - // test crate_visibility - // pub(crate) struct S; - // pub(self) struct S; - // pub(super) struct S; - - // test_err crate_visibility_empty_recover - // pub() struct S; - - // test pub_parens_typepath - // struct B(pub (super::A)); - // struct B(pub (crate::A,)); - T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => { - // If we are in a tuple struct, then the parens following `pub` - // might be an tuple field, not part of the visibility. So in that - // case we don't want to consume an identifier. - - // test pub_tuple_field - // struct MyStruct(pub (u32, u32)); - // struct MyStruct(pub (u32)); - // struct MyStruct(pub ()); - if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) { - p.bump(T!['(']); - paths::vis_path(p); - p.expect(T![')']); - } - } - // test crate_visibility_in - // pub(in super::A) struct S; - // pub(in crate) struct S; - T![in] => { + opt_visibility_inner(p, in_tuple_field); + m.complete(p, VISIBILITY); + true +} + +fn opt_visibility_inner(p: &mut Parser<'_>, in_tuple_field: bool) -> bool { + if !p.at(T!['(']) { + return false; + } + + match p.nth(1) { + // test crate_visibility + // pub(crate) struct S; + // pub(self) struct S; + // pub(super) struct S; + + // test_err crate_visibility_empty_recover + // pub() struct S; + + // test pub_parens_typepath + // struct B(pub (super::A)); + // struct B(pub (crate::A,)); + T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => { + // If we are in a tuple struct, then the parens following `pub` + // might be an tuple field, not part of the visibility. So in that + // case we don't want to consume an identifier. + + // test pub_tuple_field + // struct MyStruct(pub (u32, u32)); + // struct MyStruct(pub (u32)); + // struct MyStruct(pub ()); + if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) { + let m = p.start(); p.bump(T!['(']); - p.bump(T![in]); paths::vis_path(p); p.expect(T![')']); + m.complete(p, VISIBILITY_INNER); + return true; } - _ => {} } + // test crate_visibility_in + // pub(in super::A) struct S; + // pub(in crate) struct S; + T![in] => { + let m = p.start(); + p.bump(T!['(']); + p.bump(T![in]); + paths::vis_path(p); + p.expect(T![')']); + m.complete(p, VISIBILITY_INNER); + return true; + } + _ => {} } - m.complete(p, VISIBILITY); - true + false } fn opt_rename(p: &mut Parser<'_>) { diff --git a/crates/parser/src/grammar/items.rs b/crates/parser/src/grammar/items.rs index c0acdde2a7..6c46fac290 100644 --- a/crates/parser/src/grammar/items.rs +++ b/crates/parser/src/grammar/items.rs @@ -167,6 +167,25 @@ pub(super) fn opt_item(p: &mut Parser<'_>, m: Marker, is_in_extern: bool) -> Res has_mods = true; } + if p.at(T![impl]) + && p.nth(1) == T!['('] + && ((matches!(p.nth(2), T![crate] | T![super] | T![self]) && p.nth(3) == T![')']) + || p.nth(2) == T![in]) + { + // test impl_restrictions + // pub unsafe impl(crate) trait Foo {} + // impl(in super::bar) trait Bar {} + // impl () {} + // impl (i32) {} + let m = p.start(); + p.bump(T![impl]); + if !opt_visibility_inner(p, false) { + p.error("expected an impl restriction"); + } + m.complete(p, IMPL_RESTRICTION); + has_mods = true; + } + // test default_item // default impl T for Foo {} if p.at_contextual_kw(T![default]) { diff --git a/crates/parser/src/grammar/items/adt.rs b/crates/parser/src/grammar/items/adt.rs index cfba4c3a77..a030190ad3 100644 --- a/crates/parser/src/grammar/items/adt.rs +++ b/crates/parser/src/grammar/items/adt.rs @@ -133,7 +133,30 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) { // struct S { #[attr] f: f32 } attributes::outer_attrs(p); opt_visibility(p, false); - p.eat(T![unsafe]); + + if p.at(T![mut]) && p.nth(1) == T!['('] { + // test record_mut_restrictions_before + // struct Foo { mut(super) unsafe i: i32 } + let m = p.start(); + p.bump(T![mut]); + if !opt_visibility_inner(p, false) { + p.error("expected a mut restriction"); + } + m.complete(p, MUT_RESTRICTION); + } + + // We accept mut restriction both after and before `unsafe`, as the order is undecided yet. + if p.eat(T![unsafe]) && p.at(T![mut]) && p.nth(1) == T!['('] { + // test record_mut_restrictions_after + // struct Foo { unsafe mut(super) i: i32 } + let m = p.start(); + p.bump(T![mut]); + if !opt_visibility_inner(p, false) { + p.error("expected a mut restriction"); + } + m.complete(p, MUT_RESTRICTION); + } + if p.at(IDENT) { name(p); p.expect(T![:]); @@ -175,6 +198,18 @@ fn tuple_field_list(p: &mut Parser<'_>) { // struct S (#[attr] f32); attributes::outer_attrs(p); let has_vis = opt_visibility(p, true); + + if p.at(T![mut]) && p.nth(1) == T!['('] { + // test tuple_mut_restrictions + // struct Foo(pub(crate) mut(super) i32); + let m = p.start(); + p.bump(T![mut]); + if !opt_visibility_inner(p, false) { + p.error("expected a mut restriction"); + } + m.complete(p, MUT_RESTRICTION); + } + if !p.at_ts(types::TYPE_FIRST) { p.error("expected a type"); if has_vis { diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs index 9cd48f2aa4..59fa3ee773 100644 --- a/crates/parser/src/syntax_kind/generated.rs +++ b/crates/parser/src/syntax_kind/generated.rs @@ -218,6 +218,7 @@ pub enum SyntaxKind { IDENT_PAT, IF_EXPR, IMPL, + IMPL_RESTRICTION, IMPL_TRAIT_TYPE, INDEX_EXPR, INFER_TYPE, @@ -247,6 +248,7 @@ pub enum SyntaxKind { MATCH_GUARD, METHOD_CALL_EXPR, MODULE, + MUT_RESTRICTION, NAME, NAME_REF, NEVER_TYPE, @@ -318,6 +320,7 @@ pub enum SyntaxKind { VARIANT, VARIANT_LIST, VISIBILITY, + VISIBILITY_INNER, WHERE_CLAUSE, WHERE_PRED, WHILE_EXPR, @@ -399,6 +402,7 @@ impl SyntaxKind { | IDENT_PAT | IF_EXPR | IMPL + | IMPL_RESTRICTION | IMPL_TRAIT_TYPE | INDEX_EXPR | INFER_TYPE @@ -428,6 +432,7 @@ impl SyntaxKind { | MATCH_GUARD | METHOD_CALL_EXPR | MODULE + | MUT_RESTRICTION | NAME | NAME_REF | NEVER_TYPE @@ -499,6 +504,7 @@ impl SyntaxKind { | VARIANT | VARIANT_LIST | VISIBILITY + | VISIBILITY_INNER | WHERE_CLAUSE | WHERE_PRED | WHILE_EXPR diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs index 71978390df..10b1f85d39 100644 --- a/crates/parser/test_data/generated/runner.rs +++ b/crates/parser/test_data/generated/runner.rs @@ -348,6 +348,10 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/impl_item_never_type.rs"); } #[test] + fn impl_restrictions() { + run_and_expect_no_errors("test_data/parser/inline/ok/impl_restrictions.rs"); + } + #[test] fn impl_trait_type() { run_and_expect_no_errors("test_data/parser/inline/ok/impl_trait_type.rs"); } @@ -556,6 +560,14 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/record_literal_field_with_attr.rs"); } #[test] + fn record_mut_restrictions_after() { + run_and_expect_no_errors("test_data/parser/inline/ok/record_mut_restrictions_after.rs"); + } + #[test] + fn record_mut_restrictions_before() { + run_and_expect_no_errors("test_data/parser/inline/ok/record_mut_restrictions_before.rs"); + } + #[test] fn record_pat_field() { run_and_expect_no_errors("test_data/parser/inline/ok/record_pat_field.rs"); } @@ -658,6 +670,10 @@ mod ok { run_and_expect_no_errors("test_data/parser/inline/ok/tuple_field_attrs.rs"); } #[test] + fn tuple_mut_restrictions() { + run_and_expect_no_errors("test_data/parser/inline/ok/tuple_mut_restrictions.rs"); + } + #[test] fn tuple_pat() { run_and_expect_no_errors("test_data/parser/inline/ok/tuple_pat.rs"); } #[test] fn tuple_pat_fields() { diff --git a/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast b/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast index 172bc099b5..37116ca895 100644 --- a/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast +++ b/crates/parser/test_data/parser/inline/err/crate_visibility_empty_recover.rast @@ -2,8 +2,9 @@ SOURCE_FILE STRUCT VISIBILITY PUB_KW "pub" - L_PAREN "(" - R_PAREN ")" + VISIBILITY_INNER + L_PAREN "(" + R_PAREN ")" WHITESPACE " " STRUCT_KW "struct" WHITESPACE " " diff --git a/crates/parser/test_data/parser/inline/ok/crate_visibility.rast b/crates/parser/test_data/parser/inline/ok/crate_visibility.rast index 8738292a9f..c946f19321 100644 --- a/crates/parser/test_data/parser/inline/ok/crate_visibility.rast +++ b/crates/parser/test_data/parser/inline/ok/crate_visibility.rast @@ -2,12 +2,13 @@ SOURCE_FILE STRUCT VISIBILITY PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - R_PAREN ")" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + CRATE_KW "crate" + R_PAREN ")" WHITESPACE " " STRUCT_KW "struct" WHITESPACE " " @@ -18,12 +19,13 @@ SOURCE_FILE STRUCT VISIBILITY PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - SELF_KW "self" - R_PAREN ")" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + SELF_KW "self" + R_PAREN ")" WHITESPACE " " STRUCT_KW "struct" WHITESPACE " " @@ -34,12 +36,13 @@ SOURCE_FILE STRUCT VISIBILITY PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - R_PAREN ")" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + SUPER_KW "super" + R_PAREN ")" WHITESPACE " " STRUCT_KW "struct" WHITESPACE " " diff --git a/crates/parser/test_data/parser/inline/ok/crate_visibility_in.rast b/crates/parser/test_data/parser/inline/ok/crate_visibility_in.rast index ac45c56956..1a551ea221 100644 --- a/crates/parser/test_data/parser/inline/ok/crate_visibility_in.rast +++ b/crates/parser/test_data/parser/inline/ok/crate_visibility_in.rast @@ -2,19 +2,20 @@ SOURCE_FILE STRUCT VISIBILITY PUB_KW "pub" - L_PAREN "(" - IN_KW "in" - WHITESPACE " " - PATH + VISIBILITY_INNER + L_PAREN "(" + IN_KW "in" + WHITESPACE " " PATH + PATH + PATH_SEGMENT + NAME_REF + SUPER_KW "super" + COLON2 "::" PATH_SEGMENT NAME_REF - SUPER_KW "super" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "A" - R_PAREN ")" + IDENT "A" + R_PAREN ")" WHITESPACE " " STRUCT_KW "struct" WHITESPACE " " @@ -25,14 +26,15 @@ SOURCE_FILE STRUCT VISIBILITY PUB_KW "pub" - L_PAREN "(" - IN_KW "in" - WHITESPACE " " - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - R_PAREN ")" + VISIBILITY_INNER + L_PAREN "(" + IN_KW "in" + WHITESPACE " " + PATH + PATH_SEGMENT + NAME_REF + CRATE_KW "crate" + R_PAREN ")" WHITESPACE " " STRUCT_KW "struct" WHITESPACE " " diff --git a/crates/parser/test_data/parser/inline/ok/impl_restrictions.rast b/crates/parser/test_data/parser/inline/ok/impl_restrictions.rast new file mode 100644 index 0000000000..5f2680cbaa --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/impl_restrictions.rast @@ -0,0 +1,80 @@ +SOURCE_FILE + TRAIT + VISIBILITY + PUB_KW "pub" + WHITESPACE " " + UNSAFE_KW "unsafe" + WHITESPACE " " + IMPL_RESTRICTION + IMPL_KW "impl" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + CRATE_KW "crate" + R_PAREN ")" + WHITESPACE " " + TRAIT_KW "trait" + WHITESPACE " " + NAME + IDENT "Foo" + WHITESPACE " " + ASSOC_ITEM_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" + TRAIT + IMPL_RESTRICTION + IMPL_KW "impl" + VISIBILITY_INNER + L_PAREN "(" + IN_KW "in" + WHITESPACE " " + PATH + PATH + PATH_SEGMENT + NAME_REF + SUPER_KW "super" + COLON2 "::" + PATH_SEGMENT + NAME_REF + IDENT "bar" + R_PAREN ")" + WHITESPACE " " + TRAIT_KW "trait" + WHITESPACE " " + NAME + IDENT "Bar" + WHITESPACE " " + ASSOC_ITEM_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" + IMPL + IMPL_KW "impl" + WHITESPACE " " + TUPLE_TYPE + L_PAREN "(" + R_PAREN ")" + WHITESPACE " " + ASSOC_ITEM_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" + IMPL + IMPL_KW "impl" + WHITESPACE " " + PAREN_TYPE + L_PAREN "(" + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + ASSOC_ITEM_LIST + L_CURLY "{" + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/impl_restrictions.rs b/crates/parser/test_data/parser/inline/ok/impl_restrictions.rs new file mode 100644 index 0000000000..0a46b158af --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/impl_restrictions.rs @@ -0,0 +1,4 @@ +pub unsafe impl(crate) trait Foo {} +impl(in super::bar) trait Bar {} +impl () {} +impl (i32) {} diff --git a/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_after.rast b/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_after.rast new file mode 100644 index 0000000000..ebe3c81468 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_after.rast @@ -0,0 +1,35 @@ +SOURCE_FILE + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "Foo" + WHITESPACE " " + RECORD_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_FIELD + UNSAFE_KW "unsafe" + WHITESPACE " " + MUT_RESTRICTION + MUT_KW "mut" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + SUPER_KW "super" + R_PAREN ")" + WHITESPACE " " + NAME + IDENT "i" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_after.rs b/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_after.rs new file mode 100644 index 0000000000..bf37f60f85 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_after.rs @@ -0,0 +1 @@ +struct Foo { unsafe mut(super) i: i32 } diff --git a/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_before.rast b/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_before.rast new file mode 100644 index 0000000000..7f76e737f7 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_before.rast @@ -0,0 +1,35 @@ +SOURCE_FILE + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "Foo" + WHITESPACE " " + RECORD_FIELD_LIST + L_CURLY "{" + WHITESPACE " " + RECORD_FIELD + MUT_RESTRICTION + MUT_KW "mut" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + SUPER_KW "super" + R_PAREN ")" + WHITESPACE " " + UNSAFE_KW "unsafe" + WHITESPACE " " + NAME + IDENT "i" + COLON ":" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + WHITESPACE " " + R_CURLY "}" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_before.rs b/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_before.rs new file mode 100644 index 0000000000..9bbb80f205 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/record_mut_restrictions_before.rs @@ -0,0 +1 @@ +struct Foo { mut(super) unsafe i: i32 } diff --git a/crates/parser/test_data/parser/inline/ok/tuple_mut_restrictions.rast b/crates/parser/test_data/parser/inline/ok/tuple_mut_restrictions.rast new file mode 100644 index 0000000000..944133ff85 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/tuple_mut_restrictions.rast @@ -0,0 +1,37 @@ +SOURCE_FILE + STRUCT + STRUCT_KW "struct" + WHITESPACE " " + NAME + IDENT "Foo" + TUPLE_FIELD_LIST + L_PAREN "(" + TUPLE_FIELD + VISIBILITY + PUB_KW "pub" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + CRATE_KW "crate" + R_PAREN ")" + WHITESPACE " " + MUT_RESTRICTION + MUT_KW "mut" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + SUPER_KW "super" + R_PAREN ")" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + SEMICOLON ";" + WHITESPACE "\n" diff --git a/crates/parser/test_data/parser/inline/ok/tuple_mut_restrictions.rs b/crates/parser/test_data/parser/inline/ok/tuple_mut_restrictions.rs new file mode 100644 index 0000000000..42653b0043 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/tuple_mut_restrictions.rs @@ -0,0 +1 @@ +struct Foo(pub(crate) mut(super) i32); diff --git a/crates/parser/test_data/parser/ok/0012_visibility.rast b/crates/parser/test_data/parser/ok/0012_visibility.rast index 3d9322947b..348498daa9 100644 --- a/crates/parser/test_data/parser/ok/0012_visibility.rast +++ b/crates/parser/test_data/parser/ok/0012_visibility.rast @@ -52,12 +52,13 @@ SOURCE_FILE FN VISIBILITY PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - CRATE_KW "crate" - R_PAREN ")" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + CRATE_KW "crate" + R_PAREN ")" WHITESPACE " " FN_KW "fn" WHITESPACE " " @@ -75,12 +76,13 @@ SOURCE_FILE FN VISIBILITY PUB_KW "pub" - L_PAREN "(" - PATH - PATH_SEGMENT - NAME_REF - SUPER_KW "super" - R_PAREN ")" + VISIBILITY_INNER + L_PAREN "(" + PATH + PATH_SEGMENT + NAME_REF + SUPER_KW "super" + R_PAREN ")" WHITESPACE " " FN_KW "fn" WHITESPACE " " @@ -98,24 +100,25 @@ SOURCE_FILE FN VISIBILITY PUB_KW "pub" - L_PAREN "(" - IN_KW "in" - WHITESPACE " " - PATH + VISIBILITY_INNER + L_PAREN "(" + IN_KW "in" + WHITESPACE " " PATH PATH + PATH + PATH_SEGMENT + NAME_REF + IDENT "foo" + COLON2 "::" PATH_SEGMENT NAME_REF - IDENT "foo" + IDENT "bar" COLON2 "::" PATH_SEGMENT NAME_REF - IDENT "bar" - COLON2 "::" - PATH_SEGMENT - NAME_REF - IDENT "baz" - R_PAREN ")" + IDENT "baz" + R_PAREN ")" WHITESPACE " " FN_KW "fn" WHITESPACE " " diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 324b2bbd58..caf92aca87 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -277,6 +277,7 @@ RecordFieldList = RecordField = Attr* Visibility? 'unsafe'? + MutRestriction? Name ':' Type ('=' default_val:ConstArg)? TupleFieldList = @@ -284,12 +285,16 @@ TupleFieldList = TupleField = Attr* Visibility? + MutRestriction? Type FieldList = RecordFieldList | TupleFieldList +MutRestriction = + 'mut' VisibilityInner + Enum = Attr* Visibility? 'enum' Name GenericParamList? WhereClause? @@ -336,10 +341,14 @@ Static = Trait = Attr* Visibility? 'unsafe'? 'auto'? + ImplRestriction? 'trait' Name GenericParamList? (((':' TypeBoundList?)? WhereClause? AssocItemList) | ('=' TypeBoundList? WhereClause? ';')) +ImplRestriction = + 'impl' VisibilityInner + AssocItemList = '{' Attr* AssocItem* '}' @@ -368,8 +377,10 @@ ExternItem = | TypeAlias Visibility = - 'pub' ('(' 'in'? Path ')')? + 'pub' VisibilityInner? +VisibilityInner = + '(' 'in'? Path ')' //****************************// // Statements and Expressions // diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index cd7f6a018a..69fd703c03 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -808,6 +808,15 @@ impl Impl { #[inline] pub fn unsafe_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![unsafe]) } } +pub struct ImplRestriction { + pub(crate) syntax: SyntaxNode, +} +impl ImplRestriction { + #[inline] + pub fn visibility_inner(&self) -> Option<VisibilityInner> { support::child(&self.syntax) } + #[inline] + pub fn impl_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![impl]) } +} pub struct ImplTraitType { pub(crate) syntax: SyntaxNode, } @@ -1114,6 +1123,15 @@ impl Module { #[inline] pub fn mod_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mod]) } } +pub struct MutRestriction { + pub(crate) syntax: SyntaxNode, +} +impl MutRestriction { + #[inline] + pub fn visibility_inner(&self) -> Option<VisibilityInner> { support::child(&self.syntax) } + #[inline] + pub fn mut_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![mut]) } +} pub struct Name { pub(crate) syntax: SyntaxNode, } @@ -1400,6 +1418,8 @@ impl RecordField { #[inline] pub fn default_val(&self) -> Option<ConstArg> { support::child(&self.syntax) } #[inline] + pub fn mut_restriction(&self) -> Option<MutRestriction> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } #[inline] pub fn colon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![:]) } @@ -1690,6 +1710,8 @@ impl Trait { #[inline] pub fn assoc_item_list(&self) -> Option<AssocItemList> { support::child(&self.syntax) } #[inline] + pub fn impl_restriction(&self) -> Option<ImplRestriction> { support::child(&self.syntax) } + #[inline] pub fn semicolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![;]) } #[inline] pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) } @@ -1743,6 +1765,8 @@ impl ast::HasDocComments for TupleField {} impl ast::HasVisibility for TupleField {} impl TupleField { #[inline] + pub fn mut_restriction(&self) -> Option<MutRestriction> { support::child(&self.syntax) } + #[inline] pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) } } pub struct TupleFieldList { @@ -2001,6 +2025,15 @@ pub struct Visibility { } impl Visibility { #[inline] + pub fn visibility_inner(&self) -> Option<VisibilityInner> { support::child(&self.syntax) } + #[inline] + pub fn pub_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![pub]) } +} +pub struct VisibilityInner { + pub(crate) syntax: SyntaxNode, +} +impl VisibilityInner { + #[inline] pub fn path(&self) -> Option<Path> { support::child(&self.syntax) } #[inline] pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) } @@ -2008,8 +2041,6 @@ impl Visibility { pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) } #[inline] pub fn in_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![in]) } - #[inline] - pub fn pub_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![pub]) } } pub struct WhereClause { pub(crate) syntax: SyntaxNode, @@ -4192,6 +4223,38 @@ impl fmt::Debug for Impl { f.debug_struct("Impl").field("syntax", &self.syntax).finish() } } +impl AstNode for ImplRestriction { + #[inline] + fn kind() -> SyntaxKind + where + Self: Sized, + { + IMPL_RESTRICTION + } + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == IMPL_RESTRICTION } + #[inline] + fn cast(syntax: SyntaxNode) -> Option<Self> { + if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl hash::Hash for ImplRestriction { + fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); } +} +impl Eq for ImplRestriction {} +impl PartialEq for ImplRestriction { + fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax } +} +impl Clone for ImplRestriction { + fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } } +} +impl fmt::Debug for ImplRestriction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("ImplRestriction").field("syntax", &self.syntax).finish() + } +} impl AstNode for ImplTraitType { #[inline] fn kind() -> SyntaxKind @@ -5120,6 +5183,38 @@ impl fmt::Debug for Module { f.debug_struct("Module").field("syntax", &self.syntax).finish() } } +impl AstNode for MutRestriction { + #[inline] + fn kind() -> SyntaxKind + where + Self: Sized, + { + MUT_RESTRICTION + } + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == MUT_RESTRICTION } + #[inline] + fn cast(syntax: SyntaxNode) -> Option<Self> { + if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl hash::Hash for MutRestriction { + fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); } +} +impl Eq for MutRestriction {} +impl PartialEq for MutRestriction { + fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax } +} +impl Clone for MutRestriction { + fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } } +} +impl fmt::Debug for MutRestriction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("MutRestriction").field("syntax", &self.syntax).finish() + } +} impl AstNode for Name { #[inline] fn kind() -> SyntaxKind @@ -7392,6 +7487,38 @@ impl fmt::Debug for Visibility { f.debug_struct("Visibility").field("syntax", &self.syntax).finish() } } +impl AstNode for VisibilityInner { + #[inline] + fn kind() -> SyntaxKind + where + Self: Sized, + { + VISIBILITY_INNER + } + #[inline] + fn can_cast(kind: SyntaxKind) -> bool { kind == VISIBILITY_INNER } + #[inline] + fn cast(syntax: SyntaxNode) -> Option<Self> { + if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None } + } + #[inline] + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} +impl hash::Hash for VisibilityInner { + fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); } +} +impl Eq for VisibilityInner {} +impl PartialEq for VisibilityInner { + fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax } +} +impl Clone for VisibilityInner { + fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } } +} +impl fmt::Debug for VisibilityInner { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("VisibilityInner").field("syntax", &self.syntax).finish() + } +} impl AstNode for WhereClause { #[inline] fn kind() -> SyntaxKind @@ -10092,6 +10219,11 @@ impl std::fmt::Display for Impl { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for ImplRestriction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for ImplTraitType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -10237,6 +10369,11 @@ impl std::fmt::Display for Module { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for MutRestriction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for Name { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -10592,6 +10729,11 @@ impl std::fmt::Display for Visibility { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for VisibilityInner { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for WhereClause { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs index 03118d01dc..751f8d7e1c 100644 --- a/crates/syntax/src/ast/node_ext.rs +++ b/crates/syntax/src/ast/node_ext.rs @@ -948,6 +948,15 @@ pub enum VisibilityKind { impl ast::Visibility { pub fn kind(&self) -> VisibilityKind { + match self.visibility_inner() { + Some(inner) => inner.kind(), + None => VisibilityKind::Pub, + } + } +} + +impl ast::VisibilityInner { + pub fn kind(&self) -> VisibilityKind { match self.path() { Some(path) => { if let Some(segment) = diff --git a/crates/syntax/src/validation.rs b/crates/syntax/src/validation.rs index 485140be8f..4622590656 100644 --- a/crates/syntax/src/validation.rs +++ b/crates/syntax/src/validation.rs @@ -240,8 +240,16 @@ fn validate_numeric_name(name_ref: Option<ast::NameRef>, errors: &mut Vec<Syntax } fn validate_visibility(vis: ast::Visibility, errors: &mut Vec<SyntaxError>) { - let path_without_in_token = vis.in_token().is_none() - && vis.path().and_then(|p| p.as_single_name_ref()).and_then(|n| n.ident_token()).is_some(); + let path_without_in_token = if let Some(inner) = vis.visibility_inner() { + inner.in_token().is_none() + && inner + .path() + .and_then(|p| p.as_single_name_ref()) + .and_then(|n| n.ident_token()) + .is_some() + } else { + false + }; if path_without_in_token { errors.push(SyntaxError::new("incorrect visibility restriction", vis.syntax.text_range())); } diff --git a/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rast b/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rast index 90c258cd1a..2d6d4b2681 100644 --- a/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rast +++ b/crates/syntax/test_data/parser/validation/0037_visibility_in_traits.rast @@ -51,12 +51,13 @@ [email protected] [email protected] "pub" - [email protected] "(" - [email protected] "crate" - [email protected] ")" + [email protected] "(" + [email protected] "crate" + [email protected] ")" [email protected] "type" @@ -73,12 +74,13 @@ [email protected] [email protected] "pub" - [email protected] "(" - [email protected] "crate" - [email protected] ")" + [email protected] "(" + [email protected] "crate" + [email protected] ")" [email protected] "const" |