Skip to content

Commit 1ebac28

Browse files
committed
Auto merge of #14465 - tamasfe:feat/rtn-syntax, r=Veykril
Limited syntax support for return type notations (RTN) Experimental RTN bound support was recently merged into rustc (rust-lang/rust#109417), the goal of this PR is to allow experimentation without syntax errors everywhere. The parsing implemented currently aligns with the state of the tracking issue, it only supports the form `T<foo(..): Bounds>`. The parser always checks for the presence of `..` to disambiguate from `Fn*()` types, this is not ideal but I didn't want to spend too much time as it is an experimental feature.
2 parents 1ce25f1 + 25910bc commit 1ebac28

File tree

8 files changed

+103
-2
lines changed

8 files changed

+103
-2
lines changed

crates/hir-def/src/path/lower.rs

+3
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,9 @@ pub(super) fn lower_generic_args(
218218
let arg = ConstRefOrPath::from_expr_opt(arg.expr());
219219
args.push(GenericArg::Const(arg))
220220
}
221+
ast::GenericArg::ReturnTypeArg(_) => {
222+
// FIXME: return type notation is experimental, we don't do anything with it yet.
223+
}
221224
}
222225
}
223226

crates/parser/src/grammar/generic_args.rs

+18
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ fn generic_arg(p: &mut Parser<'_>) -> bool {
7676
}
7777
}
7878
}
79+
IDENT if p.nth(1) == T!['('] && p.nth_at(2, T![..]) => return_type_arg(p),
7980
_ if p.at_ts(types::TYPE_FIRST) => type_arg(p),
8081
_ => return false,
8182
}
@@ -139,3 +140,20 @@ fn type_arg(p: &mut Parser<'_>) {
139140
types::type_(p);
140141
m.complete(p, TYPE_ARG);
141142
}
143+
144+
// test return_type_arg
145+
// type T = S<foo(..): Send>;
146+
pub(super) fn return_type_arg(p: &mut Parser<'_>) {
147+
let m = p.start();
148+
p.expect(IDENT);
149+
p.expect(T!['(']);
150+
p.expect(T![..]);
151+
p.expect(T![')']);
152+
if !p.at(T![:]) {
153+
p.error("expected :");
154+
m.abandon(p);
155+
return;
156+
}
157+
generic_params::bounds(p);
158+
m.complete(p, RETURN_TYPE_ARG);
159+
}

crates/parser/src/syntax_kind/generated.rs

+1
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@ pub enum SyntaxKind {
245245
GENERIC_PARAM,
246246
LIFETIME_PARAM,
247247
TYPE_PARAM,
248+
RETURN_TYPE_ARG,
248249
CONST_PARAM,
249250
GENERIC_ARG_LIST,
250251
LIFETIME,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
SOURCE_FILE
2+
TYPE_ALIAS
3+
TYPE_KW "type"
4+
WHITESPACE " "
5+
NAME
6+
IDENT "T"
7+
WHITESPACE " "
8+
EQ "="
9+
WHITESPACE " "
10+
PATH_TYPE
11+
PATH
12+
PATH_SEGMENT
13+
NAME_REF
14+
IDENT "S"
15+
GENERIC_ARG_LIST
16+
L_ANGLE "<"
17+
RETURN_TYPE_ARG
18+
IDENT "foo"
19+
L_PAREN "("
20+
DOT2 ".."
21+
R_PAREN ")"
22+
COLON ":"
23+
WHITESPACE " "
24+
TYPE_BOUND_LIST
25+
TYPE_BOUND
26+
PATH_TYPE
27+
PATH
28+
PATH_SEGMENT
29+
NAME_REF
30+
IDENT "Send"
31+
R_ANGLE ">"
32+
SEMICOLON ";"
33+
WHITESPACE "\n"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
type T = S<foo(..): Send>;

crates/syntax/rust.ungram

+4
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ GenericArg =
4646
| AssocTypeArg
4747
| LifetimeArg
4848
| ConstArg
49+
| ReturnTypeArg
4950

5051
TypeArg =
5152
Type
@@ -59,6 +60,9 @@ LifetimeArg =
5960
ConstArg =
6061
Expr
6162

63+
ReturnTypeArg =
64+
NameRef '(' '..' ')' ':' TypeBoundList
65+
6266
MacroCall =
6367
Attr* Path '!' TokenTree ';'?
6468

crates/syntax/src/ast/generated/nodes.rs

+42-2
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,18 @@ impl ConstArg {
142142
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
143143
}
144144

145+
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
146+
pub struct ReturnTypeArg {
147+
pub(crate) syntax: SyntaxNode,
148+
}
149+
impl ast::HasTypeBounds for ReturnTypeArg {}
150+
impl ReturnTypeArg {
151+
pub fn name_ref(&self) -> Option<NameRef> { support::child(&self.syntax) }
152+
pub fn l_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T!['(']) }
153+
pub fn dotdot_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![..]) }
154+
pub fn r_paren_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![')']) }
155+
}
156+
145157
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
146158
pub struct TypeBoundList {
147159
pub(crate) syntax: SyntaxNode,
@@ -1516,6 +1528,7 @@ pub enum GenericArg {
15161528
AssocTypeArg(AssocTypeArg),
15171529
LifetimeArg(LifetimeArg),
15181530
ConstArg(ConstArg),
1531+
ReturnTypeArg(ReturnTypeArg),
15191532
}
15201533

15211534
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -1865,6 +1878,17 @@ impl AstNode for ConstArg {
18651878
}
18661879
fn syntax(&self) -> &SyntaxNode { &self.syntax }
18671880
}
1881+
impl AstNode for ReturnTypeArg {
1882+
fn can_cast(kind: SyntaxKind) -> bool { kind == RETURN_TYPE_ARG }
1883+
fn cast(syntax: SyntaxNode) -> Option<Self> {
1884+
if Self::can_cast(syntax.kind()) {
1885+
Some(Self { syntax })
1886+
} else {
1887+
None
1888+
}
1889+
}
1890+
fn syntax(&self) -> &SyntaxNode { &self.syntax }
1891+
}
18681892
impl AstNode for TypeBoundList {
18691893
fn can_cast(kind: SyntaxKind) -> bool { kind == TYPE_BOUND_LIST }
18701894
fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -3219,16 +3243,20 @@ impl From<LifetimeArg> for GenericArg {
32193243
impl From<ConstArg> for GenericArg {
32203244
fn from(node: ConstArg) -> GenericArg { GenericArg::ConstArg(node) }
32213245
}
3246+
impl From<ReturnTypeArg> for GenericArg {
3247+
fn from(node: ReturnTypeArg) -> GenericArg { GenericArg::ReturnTypeArg(node) }
3248+
}
32223249
impl AstNode for GenericArg {
32233250
fn can_cast(kind: SyntaxKind) -> bool {
3224-
matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG)
3251+
matches!(kind, TYPE_ARG | ASSOC_TYPE_ARG | LIFETIME_ARG | CONST_ARG | RETURN_TYPE_ARG)
32253252
}
32263253
fn cast(syntax: SyntaxNode) -> Option<Self> {
32273254
let res = match syntax.kind() {
32283255
TYPE_ARG => GenericArg::TypeArg(TypeArg { syntax }),
32293256
ASSOC_TYPE_ARG => GenericArg::AssocTypeArg(AssocTypeArg { syntax }),
32303257
LIFETIME_ARG => GenericArg::LifetimeArg(LifetimeArg { syntax }),
32313258
CONST_ARG => GenericArg::ConstArg(ConstArg { syntax }),
3259+
RETURN_TYPE_ARG => GenericArg::ReturnTypeArg(ReturnTypeArg { syntax }),
32323260
_ => return None,
32333261
};
32343262
Some(res)
@@ -3239,6 +3267,7 @@ impl AstNode for GenericArg {
32393267
GenericArg::AssocTypeArg(it) => &it.syntax,
32403268
GenericArg::LifetimeArg(it) => &it.syntax,
32413269
GenericArg::ConstArg(it) => &it.syntax,
3270+
GenericArg::ReturnTypeArg(it) => &it.syntax,
32423271
}
32433272
}
32443273
}
@@ -4170,7 +4199,13 @@ impl AstNode for AnyHasTypeBounds {
41704199
fn can_cast(kind: SyntaxKind) -> bool {
41714200
matches!(
41724201
kind,
4173-
ASSOC_TYPE_ARG | TRAIT | TYPE_ALIAS | LIFETIME_PARAM | TYPE_PARAM | WHERE_PRED
4202+
ASSOC_TYPE_ARG
4203+
| RETURN_TYPE_ARG
4204+
| TRAIT
4205+
| TYPE_ALIAS
4206+
| LIFETIME_PARAM
4207+
| TYPE_PARAM
4208+
| WHERE_PRED
41744209
)
41754210
}
41764211
fn cast(syntax: SyntaxNode) -> Option<Self> {
@@ -4333,6 +4368,11 @@ impl std::fmt::Display for ConstArg {
43334368
std::fmt::Display::fmt(self.syntax(), f)
43344369
}
43354370
}
4371+
impl std::fmt::Display for ReturnTypeArg {
4372+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
4373+
std::fmt::Display::fmt(self.syntax(), f)
4374+
}
4375+
}
43364376
impl std::fmt::Display for TypeBoundList {
43374377
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43384378
std::fmt::Display::fmt(self.syntax(), f)

crates/syntax/src/tests/ast_src.rs

+1
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ pub(crate) const KINDS_SRC: KindsSrc<'_> = KindsSrc {
199199
"GENERIC_PARAM",
200200
"LIFETIME_PARAM",
201201
"TYPE_PARAM",
202+
"RETURN_TYPE_ARG",
202203
"CONST_PARAM",
203204
"GENERIC_ARG_LIST",
204205
"LIFETIME",

0 commit comments

Comments
 (0)