Unnamed repository; edit this file 'description' to name the repository.
-rw-r--r--crates/hir-def/src/path/lower.rs3
-rw-r--r--crates/parser/src/grammar/generic_args.rs18
-rw-r--r--crates/parser/src/syntax_kind/generated.rs1
-rw-r--r--crates/parser/test_data/parser/inline/ok/0206_return_type_arg.rast33
-rw-r--r--crates/parser/test_data/parser/inline/ok/0206_return_type_arg.rs1
-rw-r--r--crates/syntax/rust.ungram4
-rw-r--r--crates/syntax/src/ast/generated/nodes.rs44
-rw-r--r--crates/syntax/src/tests/ast_src.rs1
8 files changed, 103 insertions, 2 deletions
diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs
index 407f38daad..c35f915b00 100644
--- a/crates/hir-def/src/path/lower.rs
+++ b/crates/hir-def/src/path/lower.rs
@@ -218,6 +218,9 @@ pub(super) fn lower_generic_args(
let arg = ConstRefOrPath::from_expr_opt(arg.expr());
args.push(GenericArg::Const(arg))
}
+ ast::GenericArg::ReturnTypeArg(_) => {
+ // FIXME: return type notation is experimental, we don't do anything with it yet.
+ }
}
}
diff --git a/crates/parser/src/grammar/generic_args.rs b/crates/parser/src/grammar/generic_args.rs
index 919d9b91eb..55794954a8 100644
--- a/crates/parser/src/grammar/generic_args.rs
+++ b/crates/parser/src/grammar/generic_args.rs
@@ -76,6 +76,7 @@ fn generic_arg(p: &mut Parser<'_>) -> bool {
}
}
}
+ IDENT if p.nth(1) == T!['('] && p.nth_at(2, T![..]) => return_type_arg(p),
_ if p.at_ts(types::TYPE_FIRST) => type_arg(p),
_ => return false,
}
@@ -139,3 +140,20 @@ fn type_arg(p: &mut Parser<'_>) {
types::type_(p);
m.complete(p, TYPE_ARG);
}
+
+// test return_type_arg
+// type T = S<foo(..): Send>;
+pub(super) fn return_type_arg(p: &mut Parser<'_>) {
+ let m = p.start();
+ p.expect(IDENT);
+ p.expect(T!['(']);
+ p.expect(T![..]);
+ p.expect(T![')']);
+ if !p.at(T![:]) {
+ p.error("expected :");
+ m.abandon(p);
+ return;
+ }
+ generic_params::bounds(p);
+ m.complete(p, RETURN_TYPE_ARG);
+}
diff --git a/crates/parser/src/syntax_kind/generated.rs b/crates/parser/src/syntax_kind/generated.rs
index cd87b304a2..2af6e1b986 100644
--- a/crates/parser/src/syntax_kind/generated.rs
+++ b/crates/parser/src/syntax_kind/generated.rs
@@ -245,6 +245,7 @@ pub enum SyntaxKind {
GENERIC_PARAM,
LIFETIME_PARAM,
TYPE_PARAM,
+ RETURN_TYPE_ARG,
CONST_PARAM,
GENERIC_ARG_LIST,
LIFETIME,
diff --git a/crates/parser/test_data/parser/inline/ok/0206_return_type_arg.rast b/crates/parser/test_data/parser/inline/ok/0206_return_type_arg.rast
new file mode 100644
index 0000000000..26d474f54f
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0206_return_type_arg.rast
@@ -0,0 +1,33 @@
+SOURCE_FILE
+ TYPE_ALIAS
+ TYPE_KW "type"
+ WHITESPACE " "
+ NAME
+ IDENT "T"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ GENERIC_ARG_LIST
+ L_ANGLE "<"
+ RETURN_TYPE_ARG
+ IDENT "foo"
+ L_PAREN "("
+ DOT2 ".."
+ R_PAREN ")"
+ COLON ":"
+ WHITESPACE " "
+ TYPE_BOUND_LIST
+ TYPE_BOUND
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "Send"
+ R_ANGLE ">"
+ SEMICOLON ";"
+ WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0206_return_type_arg.rs b/crates/parser/test_data/parser/inline/ok/0206_return_type_arg.rs
new file mode 100644
index 0000000000..2a9ff27083
--- /dev/null
+++ b/crates/parser/test_data/parser/inline/ok/0206_return_type_arg.rs
@@ -0,0 +1 @@
+type T = S<foo(..): Send>;
diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram
index 1c15a606f9..08c8749e36 100644
--- a/crates/syntax/rust.ungram
+++ b/crates/syntax/rust.ungram
@@ -46,6 +46,7 @@ GenericArg =
| AssocTypeArg
| LifetimeArg
| ConstArg
+| ReturnTypeArg
TypeArg =
Type
@@ -59,6 +60,9 @@ LifetimeArg =
ConstArg =
Expr
+ReturnTypeArg =
+ NameRef '(' '..' ')' ':' TypeBoundList
+
MacroCall =
Attr* Path '!' TokenTree ';'?
diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs
index 0e84aca5c7..6aa7efd832 100644
--- a/crates/syntax/src/ast/generated/nodes.rs
+++ b/crates/syntax/src/ast/generated/nodes.rs
@@ -143,6 +143,18 @@ impl ConstArg {
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
+pub struct ReturnTypeArg {
+ pub(crate) syntax: SyntaxNode,
+}
+impl ast::HasTypeBounds for ReturnTypeArg {}
+impl ReturnTypeArg {
+ pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
+ pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
+ pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
+ pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct TypeBoundList {
pub(crate) syntax: SyntaxNode,
}
@@ -1516,6 +1528,7 @@ pub enum GenericArg {
AssocTypeArg(AssocTypeArg),
LifetimeArg(LifetimeArg),
ConstArg(ConstArg),
+ ReturnTypeArg(ReturnTypeArg),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1865,6 +1878,17 @@ impl AstNode for ConstArg {
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
+impl AstNode for ReturnTypeArg {
+ fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_TYPE_ARG }
+ fn cast(syntax: SyntaxNode) -> Option<Self> {
+ 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<Self> {
@@ -3219,9 +3243,12 @@ impl From<LifetimeArg> for GenericArg {
impl From<ConstArg> for GenericArg {
fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) }
}
+impl From<ReturnTypeArg> for GenericArg {
+ fn from(node: ReturnTypeArg) -> GenericArg { GenericArg::ReturnTypeArg(node) }
+}
impl AstNode for GenericArg {
fn can_cast(kind: SyntaxKind) -> bool {
- matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG)
+ matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG | RETURN_TYPE_ARG)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
let res = match syntax.kind() {
@@ -3229,6 +3256,7 @@ impl AstNode for GenericArg {
ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }),
LIFETIME_ARG => GenericArg::LifetimeArg(LifetimeArg { syntax }),
CONST_ARG => GenericArg::ConstArg(ConstArg { syntax }),
+ RETURN_TYPE_ARG => GenericArg::ReturnTypeArg(ReturnTypeArg { syntax }),
_ => return None,
};
Some(res)
@@ -3239,6 +3267,7 @@ impl AstNode for GenericArg {
GenericArg::AssocTypeArg(it) => &it.syntax,
GenericArg::LifetimeArg(it) => &it.syntax,
GenericArg::ConstArg(it) => &it.syntax,
+ GenericArg::ReturnTypeArg(it) => &it.syntax,
}
}
}
@@ -4170,7 +4199,13 @@ impl AstNode for AnyHasTypeBounds {
fn can_cast(kind: SyntaxKind) -> bool {
matches!(
kind,
- ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED
+ ASSOC_TYPE_ARG
+ | RETURN_TYPE_ARG
+ | TRAIT
+ | TYPE_ALIAS
+ | LIFETIME_PARAM
+ | TYPE_PARAM
+ | WHERE_PRED
)
}
fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4333,6 +4368,11 @@ impl std::fmt::Display for ConstArg {
std::fmt::Display::fmt(self.syntax(), f)
}
}
+impl std::fmt::Display for ReturnTypeArg {
+ 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)
diff --git a/crates/syntax/src/tests/ast_src.rs b/crates/syntax/src/tests/ast_src.rs
index ccce71966f..caef6a7953 100644
--- a/crates/syntax/src/tests/ast_src.rs
+++ b/crates/syntax/src/tests/ast_src.rs
@@ -199,6 +199,7 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
"GENERIC_PARAM",
"LIFETIME_PARAM",
"TYPE_PARAM",
+ "RETURN_TYPE_ARG",
"CONST_PARAM",
"GENERIC_ARG_LIST",
"LIFETIME",