From e7aa37c20a52579bbe3894126a54d1f390b8b05c Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Sat, 17 Jul 2021 13:47:53 +0200 Subject: [PATCH] Support GATs for associated type arg parsing --- Cargo.lock | 4 +- crates/parser/src/grammar/paths.rs | 10 +- crates/parser/src/grammar/type_args.rs | 54 ++++++-- crates/syntax/src/ast/generated/nodes.rs | 51 +++---- .../ok/0138_associated_type_bounds.rast | 126 ++++++++++++------ .../inline/ok/0138_associated_type_bounds.rs | 2 +- 6 files changed, 165 insertions(+), 82 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3fa70bdb3..9ec7f977db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1758,9 +1758,9 @@ dependencies = [ [[package]] name = "ungrammar" -version = "1.14.1" +version = "1.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dbe67c0c0f5ded8e404578a9ab1009ffdb6ee219779329aefc0cb4fe7f44891" +checksum = "5334230a6ae9ca52bc811c968c0ae12f1750c0698ed52ea68dabab7ce5a80972" [[package]] name = "unicase" diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs index e633646c3b..c4e4f010ff 100644 --- a/crates/parser/src/grammar/paths.rs +++ b/crates/parser/src/grammar/paths.rs @@ -27,6 +27,10 @@ pub(super) fn expr_path(p: &mut Parser) { path(p, Mode::Expr) } +pub(crate) fn type_path_for_qualifier(p: &mut Parser, qual: CompletedMarker) { + path_for_qualifier(p, Mode::Type, qual) +} + #[derive(Clone, Copy, Eq, PartialEq)] enum Mode { Use, @@ -37,7 +41,11 @@ enum Mode { fn path(p: &mut Parser, mode: Mode) { let path = p.start(); path_segment(p, mode, true); - let mut qual = path.complete(p, PATH); + let qual = path.complete(p, PATH); + path_for_qualifier(p, mode, qual) +} + +fn path_for_qualifier(p: &mut Parser, mode: Mode, mut qual: CompletedMarker) { loop { let use_tree = matches!(p.nth(2), T![*] | T!['{']); if p.at(T![::]) && !use_tree { diff --git a/crates/parser/src/grammar/type_args.rs b/crates/parser/src/grammar/type_args.rs index ed2322e52c..175def8d5c 100644 --- a/crates/parser/src/grammar/type_args.rs +++ b/crates/parser/src/grammar/type_args.rs @@ -65,17 +65,51 @@ fn generic_arg(p: &mut Parser) { m.complete(p, LIFETIME_ARG); } // test associated_type_bounds - // fn print_all>(printables: T) {} - IDENT if p.nth(1) == T![:] && p.nth(2) != T![:] => { + // fn print_all = Item>>(printables: T) {} + IDENT if [T![<], T![=], T![:]].contains(&p.nth(1)) => { + let path_ty = p.start(); + let path = p.start(); + let path_seg = p.start(); name_ref(p); - type_params::bounds(p); - m.complete(p, ASSOC_TYPE_ARG); - } - IDENT if p.nth(1) == T![=] => { - name_ref(p); - p.bump_any(); - types::type_(p); - m.complete(p, ASSOC_TYPE_ARG); + if p.current() == T![<] { + opt_generic_arg_list(p, false); + } + match p.current() { + // NameRef<...> = + T![=] => { + p.bump_any(); + types::type_(p); + + path_seg.abandon(p); + path.abandon(p); + path_ty.abandon(p); + m.complete(p, ASSOC_TYPE_ARG); + } + T![:] if p.nth(1) == T![:] => { + // NameRef::, this is a path type + path_seg.complete(p, PATH_SEGMENT); + let qual = path.complete(p, PATH); + paths::type_path_for_qualifier(p, qual); + path_ty.complete(p, PATH_TYPE); + m.complete(p, TYPE_ARG); + } + // NameRef<...>: + T![:] => { + type_params::bounds(p); + + path_seg.abandon(p); + path.abandon(p); + path_ty.abandon(p); + m.complete(p, ASSOC_TYPE_ARG); + } + // NameRef, this is a single segment path type + _ => { + path_seg.complete(p, PATH_SEGMENT); + path.complete(p, PATH); + path_ty.complete(p, PATH_TYPE); + m.complete(p, TYPE_ARG); + } + } } T!['{'] => { expressions::block_expr(p); diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index b040bf61f4..287160a19f 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -107,6 +107,7 @@ pub struct AssocTypeArg { impl ast::TypeBoundsOwner for AssocTypeArg {} impl AssocTypeArg { pub fn name_ref(&self) -> Option { support::child(&self.syntax) } + pub fn generic_param_list(&self) -> Option { support::child(&self.syntax) } pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } pub fn ty(&self) -> Option { support::child(&self.syntax) } } @@ -125,6 +126,15 @@ impl ConstArg { pub fn expr(&self) -> Option { support::child(&self.syntax) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericParamList { + pub(crate) syntax: SyntaxNode, +} +impl GenericParamList { + pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } + pub fn generic_params(&self) -> AstChildren { support::children(&self.syntax) } + pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } +} +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct TypeBoundList { pub(crate) syntax: SyntaxNode, } @@ -454,15 +464,6 @@ impl Abi { pub fn extern_token(&self) -> Option { support::token(&self.syntax, T![extern]) } } #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct GenericParamList { - pub(crate) syntax: SyntaxNode, -} -impl GenericParamList { - pub fn l_angle_token(&self) -> Option { support::token(&self.syntax, T![<]) } - pub fn generic_params(&self) -> AstChildren { support::children(&self.syntax) } - pub fn r_angle_token(&self) -> Option { support::token(&self.syntax, T![>]) } -} -#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct WhereClause { pub(crate) syntax: SyntaxNode, } @@ -1584,6 +1585,17 @@ impl AstNode for ConstArg { } fn syntax(&self) -> &SyntaxNode { &self.syntax } } +impl AstNode for GenericParamList { + fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST } + fn cast(syntax: SyntaxNode) -> Option { + if Self::can_cast(syntax.kind()) { + Some(Self { syntax }) + } else { + None + } + } + fn syntax(&self) -> &SyntaxNode { &self.syntax } +} impl AstNode for TypeBoundList { fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST } fn cast(syntax: SyntaxNode) -> Option { @@ -1892,17 +1904,6 @@ impl AstNode for Abi { } fn syntax(&self) -> &SyntaxNode { &self.syntax } } -impl AstNode for GenericParamList { - fn can_cast(kind: SyntaxKind) -> bool { kind == GENERIC_PARAM_LIST } - fn cast(syntax: SyntaxNode) -> Option { - if Self::can_cast(syntax.kind()) { - Some(Self { syntax }) - } else { - None - } - } - fn syntax(&self) -> &SyntaxNode { &self.syntax } -} impl AstNode for WhereClause { fn can_cast(kind: SyntaxKind) -> bool { kind == WHERE_CLAUSE } fn cast(syntax: SyntaxNode) -> Option { @@ -3680,6 +3681,11 @@ impl std::fmt::Display for ConstArg { std::fmt::Display::fmt(self.syntax(), f) } } +impl std::fmt::Display for GenericParamList { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(self.syntax(), f) + } +} impl std::fmt::Display for TypeBoundList { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { std::fmt::Display::fmt(self.syntax(), f) @@ -3820,11 +3826,6 @@ impl std::fmt::Display for Abi { std::fmt::Display::fmt(self.syntax(), f) } } -impl std::fmt::Display for GenericParamList { - 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/test_data/parser/inline/ok/0138_associated_type_bounds.rast b/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast index 3870ec1353..605e4213f4 100644 --- a/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast +++ b/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rast @@ -1,55 +1,95 @@ -SOURCE_FILE@0..59 - FN@0..58 +SOURCE_FILE@0..94 + FN@0..93 FN_KW@0..2 "fn" WHITESPACE@2..3 " " NAME@3..12 IDENT@3..12 "print_all" - GENERIC_PARAM_LIST@12..40 + GENERIC_PARAM_LIST@12..75 L_ANGLE@12..13 "<" - TYPE_PARAM@13..39 + TYPE_PARAM@13..74 NAME@13..14 IDENT@13..14 "T" COLON@14..15 ":" WHITESPACE@15..16 " " - TYPE_BOUND_LIST@16..39 - TYPE_BOUND@16..39 - PATH_TYPE@16..39 - PATH@16..39 - PATH_SEGMENT@16..39 + TYPE_BOUND_LIST@16..74 + TYPE_BOUND@16..74 + PATH_TYPE@16..74 + PATH@16..74 + PATH_SEGMENT@16..74 NAME_REF@16..24 IDENT@16..24 "Iterator" - GENERIC_ARG_LIST@24..39 + GENERIC_ARG_LIST@24..74 L_ANGLE@24..25 "<" - ASSOC_TYPE_ARG@25..38 - NAME_REF@25..29 - IDENT@25..29 "Item" - COLON@29..30 ":" - WHITESPACE@30..31 " " - TYPE_BOUND_LIST@31..38 - TYPE_BOUND@31..38 - PATH_TYPE@31..38 - PATH@31..38 - PATH_SEGMENT@31..38 - NAME_REF@31..38 - IDENT@31..38 "Display" - R_ANGLE@38..39 ">" - R_ANGLE@39..40 ">" - PARAM_LIST@40..55 - L_PAREN@40..41 "(" - PARAM@41..54 - IDENT_PAT@41..51 - NAME@41..51 - IDENT@41..51 "printables" - COLON@51..52 ":" - WHITESPACE@52..53 " " - PATH_TYPE@53..54 - PATH@53..54 - PATH_SEGMENT@53..54 - NAME_REF@53..54 - IDENT@53..54 "T" - R_PAREN@54..55 ")" - WHITESPACE@55..56 " " - BLOCK_EXPR@56..58 - L_CURLY@56..57 "{" - R_CURLY@57..58 "}" - WHITESPACE@58..59 "\n" + TYPE_ARG@25..29 + PATH_TYPE@25..29 + PATH@25..29 + PATH_SEGMENT@25..29 + NAME_REF@25..29 + IDENT@25..29 "Item" + COMMA@29..30 "," + WHITESPACE@30..31 " " + TYPE_ARG@31..41 + PATH_TYPE@31..41 + PATH@31..41 + PATH@31..35 + PATH_SEGMENT@31..35 + NAME_REF@31..35 + IDENT@31..35 "Item" + COLON2@35..37 "::" + PATH_SEGMENT@37..41 + NAME_REF@37..41 + IDENT@37..41 "Item" + COMMA@41..42 "," + WHITESPACE@42..43 " " + ASSOC_TYPE_ARG@43..56 + NAME_REF@43..47 + IDENT@43..47 "Item" + COLON@47..48 ":" + WHITESPACE@48..49 " " + TYPE_BOUND_LIST@49..56 + TYPE_BOUND@49..56 + PATH_TYPE@49..56 + PATH@49..56 + PATH_SEGMENT@49..56 + NAME_REF@49..56 + IDENT@49..56 "Display" + COMMA@56..57 "," + WHITESPACE@57..58 " " + ASSOC_TYPE_ARG@58..73 + NAME_REF@58..62 + IDENT@58..62 "Item" + GENERIC_ARG_LIST@62..66 + L_ANGLE@62..63 "<" + LIFETIME_ARG@63..65 + LIFETIME@63..65 + LIFETIME_IDENT@63..65 "'a" + R_ANGLE@65..66 ">" + WHITESPACE@66..67 " " + EQ@67..68 "=" + WHITESPACE@68..69 " " + PATH_TYPE@69..73 + PATH@69..73 + PATH_SEGMENT@69..73 + NAME_REF@69..73 + IDENT@69..73 "Item" + R_ANGLE@73..74 ">" + R_ANGLE@74..75 ">" + PARAM_LIST@75..90 + L_PAREN@75..76 "(" + PARAM@76..89 + IDENT_PAT@76..86 + NAME@76..86 + IDENT@76..86 "printables" + COLON@86..87 ":" + WHITESPACE@87..88 " " + PATH_TYPE@88..89 + PATH@88..89 + PATH_SEGMENT@88..89 + NAME_REF@88..89 + IDENT@88..89 "T" + R_PAREN@89..90 ")" + WHITESPACE@90..91 " " + BLOCK_EXPR@91..93 + L_CURLY@91..92 "{" + R_CURLY@92..93 "}" + WHITESPACE@93..94 "\n" diff --git a/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs b/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs index eb21a657b9..d7a19dbb39 100644 --- a/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs +++ b/crates/syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs @@ -1 +1 @@ -fn print_all>(printables: T) {} +fn print_all = Item>>(printables: T) {}