Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/parser/src/grammar/generic_args.rs13
-rw-r--r--crates/parser/src/grammar/generic_params.rs3
-rw-r--r--crates/parser/src/grammar/paths.rs21
-rw-r--r--crates/parser/src/syntax_kind/generated.rs1
-rw-r--r--crates/parser/test_data/generated/runner.rs14
-rw-r--r--crates/parser/test_data/parser/inline/ok/associated_return_type_bounds.rs1
-rw-r--r--crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast49
-rw-r--r--crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs1
-rw-r--r--crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast50
-rw-r--r--crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs4
-rw-r--r--crates/syntax/rust.ungram6
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs36
12 files changed, 183 insertions, 16 deletions
diff --git a/crates/parser/src/grammar/generic_args.rs b/crates/parser/src/grammar/generic_args.rs
index 249be2a333..c62c8a9d3f 100644
--- a/crates/parser/src/grammar/generic_args.rs
+++ b/crates/parser/src/grammar/generic_args.rs
@@ -102,13 +102,18 @@ fn generic_arg(p: &mut Parser<'_>) -> bool {
IDENT if p.nth_at(1, T!['(']) => {
let m = p.start();
name_ref(p);
- params::param_list_fn_trait(p);
- if p.at(T![:]) && !p.at(T![::]) {
- // test associated_return_type_bounds
- // fn foo<T: Foo<foo(): Send, bar(i32): Send, baz(i32, i32): Send>>() {}
+ if p.nth_at(1, T![..]) {
+ let rtn = p.start();
+ p.bump(T!['(']);
+ p.bump(T![..]);
+ p.expect(T![')']);
+ rtn.complete(p, RETURN_TYPE_SYNTAX);
+ // test return_type_syntax_assoc_type_bound
+ // fn foo<T: Trait<method(..): Send>>() {}
generic_params::bounds(p);
m.complete(p, ASSOC_TYPE_ARG);
} else {
+ params::param_list_fn_trait(p);
// test bare_dyn_types_with_paren_as_generic_args
// type A = S<Fn(i32)>;
// type A = S<Fn(i32) + Send>;
diff --git a/crates/parser/src/grammar/generic_params.rs b/crates/parser/src/grammar/generic_params.rs
index cf80a535ac..e0fa753fa7 100644
--- a/crates/parser/src/grammar/generic_params.rs
+++ b/crates/parser/src/grammar/generic_params.rs
@@ -119,8 +119,7 @@ fn lifetime_bounds(p: &mut Parser<'_>) {
// test type_param_bounds
// struct S<T: 'a + ?Sized + (Copy) + ~const Drop>;
pub(super) fn bounds(p: &mut Parser<'_>) {
- assert!(p.at(T![:]));
- p.bump(T![:]);
+ p.expect(T![:]);
bounds_without_colon(p);
}
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
index 01b8f9e918..09db921803 100644
--- a/crates/parser/src/grammar/paths.rs
+++ b/crates/parser/src/grammar/paths.rs
@@ -140,11 +140,24 @@ fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) {
if p.at(T![::]) && p.nth_at(2, T!['(']) {
p.bump(T![::]);
}
- // test path_fn_trait_args
- // type F = Box<Fn(i32) -> ()>;
if p.at(T!['(']) {
- params::param_list_fn_trait(p);
- opt_ret_type(p);
+ if p.nth_at(1, T![..]) {
+ // test return_type_syntax_in_path
+ // fn foo<T>()
+ // where
+ // T::method(..): Send,
+ // {}
+ let rtn = p.start();
+ p.bump(T!['(']);
+ p.bump(T![..]);
+ p.expect(T![')']);
+ rtn.complete(p, RETURN_TYPE_SYNTAX);
+ } else {
+ // test path_fn_trait_args
+ // type F = Box<Fn(i32) -> ()>;
+ params::param_list_fn_trait(p);
+ opt_ret_type(p);
+ }
} else {
generic_args::opt_generic_arg_list(p, false);
}
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index eaacd88e3e..00f212487a 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -253,6 +253,7 @@ pub enum SyntaxKind {
RENAME,
REST_PAT,
RETURN_EXPR,
+ RETURN_TYPE_SYNTAX,
RET_TYPE,
SELF_PARAM,
SLICE_PAT,
diff --git a/crates/parser/test_data/generated/runner.rs b/crates/parser/test_data/generated/runner.rs
index 1907f03b44..9ce5a2ae74 100644
--- a/crates/parser/test_data/generated/runner.rs
+++ b/crates/parser/test_data/generated/runner.rs
@@ -37,10 +37,6 @@ mod ok {
#[test]
fn assoc_type_eq() { run_and_expect_no_errors("test_data/parser/inline/ok/assoc_type_eq.rs"); }
#[test]
- fn associated_return_type_bounds() {
- run_and_expect_no_errors("test_data/parser/inline/ok/associated_return_type_bounds.rs");
- }
- #[test]
fn associated_type_bounds() {
run_and_expect_no_errors("test_data/parser/inline/ok/associated_type_bounds.rs");
}
@@ -519,6 +515,16 @@ mod ok {
#[test]
fn return_expr() { run_and_expect_no_errors("test_data/parser/inline/ok/return_expr.rs"); }
#[test]
+ fn return_type_syntax_assoc_type_bound() {
+ run_and_expect_no_errors(
+ "test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs",
+ );
+ }
+ #[test]
+ fn return_type_syntax_in_path() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/return_type_syntax_in_path.rs");
+ }
+ #[test]
fn self_param() { run_and_expect_no_errors("test_data/parser/inline/ok/self_param.rs"); }
#[test]
fn self_param_outer_attr() {
diff --git a/crates/parser/test_data/parser/inline/ok/associated_return_type_bounds.rs b/crates/parser/test_data/parser/inline/ok/associated_return_type_bounds.rs
deleted file mode 100644
index 42029ac592..0000000000
--- a/crates/parser/test_data/parser/inline/ok/associated_return_type_bounds.rs
+++ /dev/null
@@ -1 +0,0 @@
-fn foo<T: Foo<foo(): Send, bar(i32): Send, baz(i32, i32): Send>>() {}
diff --git a/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast b/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast
new file mode 100644
index 0000000000..30e0e73bbd
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rast
@@ -0,0 +1,49 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Trait"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ ASSOC_TYPE_ARG
+ NAME_REF
+ IDENT "method"
+ RETURN_TYPE_SYNTAX
+ L_PAREN "("
+ DOT2 ".."
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ R_ANGLE ">"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs b/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs
new file mode 100644
index 0000000000..8a4cf4c3a0
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/return_type_syntax_assoc_type_bound.rs
@@ -0,0 +1 @@
+fn foo<T: Trait<method(..): Send>>() {}
diff --git a/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast b/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast
new file mode 100644
index 0000000000..501dccd79d
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rast
@@ -0,0 +1,50 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ GENERIC_PARAM_LIST
+ L_ANGLE "<"
+ TYPE_PARAM
+ NAME
+ IDENT "T"
+ R_ANGLE ">"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE "\n"
+ WHERE_CLAUSE
+ WHERE_KW "where"
+ WHITESPACE "\n "
+ WHERE_PRED
+ PATH_TYPE
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "T"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "method"
+ RETURN_TYPE_SYNTAX
+ L_PAREN "("
+ DOT2 ".."
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ COMMA ","
+ WHITESPACE "\n"
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs b/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs
new file mode 100644
index 0000000000..a9b63fb01c
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/return_type_syntax_in_path.rs
@@ -0,0 +1,4 @@
+fn foo<T>()
+where
+ T::method(..): Send,
+{}
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 069be2df3a..ba7d8bacfb 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -38,8 +38,12 @@ PathSegment =
'::'? NameRef
| NameRef GenericArgList?
| NameRef ParamList RetType?
+| NameRef ReturnTypeSyntax
| '<' Type ('as' PathType)? '>'
+ReturnTypeSyntax =
+ '(' '..' ')'
+
//*************************//
// Generics //
@@ -59,7 +63,7 @@ TypeArg =
AssocTypeArg =
NameRef
- (GenericArgList | ParamList RetType?)?
+ (GenericArgList | ParamList RetType? | ReturnTypeSyntax)?
(':' TypeBoundList | ('=' Type | ConstArg))
LifetimeArg =
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 01886d119d..bd8092d7f0 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -114,6 +114,8 @@ impl AssocTypeArg {
#[inline]
pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
#[inline]
+ pub fn return_type_syntax(&self) -> Option<ReturnTypeSyntax> { support::child(&self.syntax) }
+ #[inline]
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
#[inline]
pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
@@ -1221,6 +1223,8 @@ impl PathSegment {
#[inline]
pub fn ret_type(&self) -> Option<RetType> { support::child(&self.syntax) }
#[inline]
+ pub fn return_type_syntax(&self) -> Option<ReturnTypeSyntax> { support::child(&self.syntax) }
+ #[inline]
pub fn ty(&self) -> Option<Type> { support::child(&self.syntax) }
#[inline]
pub fn coloncolon_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![::]) }
@@ -1486,6 +1490,19 @@ impl ReturnExpr {
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ReturnTypeSyntax {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ReturnTypeSyntax {
+ #[inline]
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+ #[inline]
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+ #[inline]
+ pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SelfParam {
pub(crate) syntax: SyntaxNode,
}
@@ -3697,6 +3714,20 @@ impl AstNode for ReturnExpr {
#[inline]
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
+impl AstNode for ReturnTypeSyntax {
+ #[inline]
+ fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_TYPE_SYNTAX }
+ #[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 AstNode for SelfParam {
#[inline]
fn can_cast(kind: SyntaxKind) -> bool { kind == SELF_PARAM }
@@ -6609,6 +6640,11 @@ impl std::fmt::Display for ReturnExpr {
std::fmt::Display::fmt(self.syntax(), f)
}
}
+impl std::fmt::Display for ReturnTypeSyntax {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ std::fmt::Display::fmt(self.syntax(), f)
+ }
+}
impl std::fmt::Display for SelfParam {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(self.syntax(), f)