about summary refs log tree commit diff
diff options
context:
space:
mode:
authortamasfe <me@tamasfe.dev>2023-04-01 15:26:03 +0200
committertamasfe <me@tamasfe.dev>2023-04-01 15:26:03 +0200
commit0b9c0c5088bc6d11455043a1e6c65b053f8acc43 (patch)
treeec9259abbf9e79d7a1f8daa78b8b1edb703bccaf
parentffb04ae32de66ca9d12646e5e559ec8ff318c8b1 (diff)
downloadrust-0b9c0c5088bc6d11455043a1e6c65b053f8acc43.tar.gz
rust-0b9c0c5088bc6d11455043a1e6c65b053f8acc43.zip
feat(syntax): RTN in bounds
Limited syntactic support for experimental return type notations.
https://github.com/rust-lang/rust/issues/109417
-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 407f38daad4..6c7e1c25d61 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(_) => {
+                // TODO: 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 919d9b91eba..55794954a82 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 cd87b304a2f..2af6e1b9867 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 00000000000..26d474f54f4
--- /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 00000000000..2a9ff270839
--- /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 1c15a606f95..08c8749e36c 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 0e84aca5c7d..6aa7efd8324 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 ccce71966ff..caef6a79539 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",