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 (https://github.com/rust-lang/rust/issues/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.
This commit is contained in:
commit
1ebac28f0d
8 changed files with 103 additions and 2 deletions
|
|
@ -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.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -245,6 +245,7 @@ pub enum SyntaxKind {
|
|||
GENERIC_PARAM,
|
||||
LIFETIME_PARAM,
|
||||
TYPE_PARAM,
|
||||
RETURN_TYPE_ARG,
|
||||
CONST_PARAM,
|
||||
GENERIC_ARG_LIST,
|
||||
LIFETIME,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
@ -0,0 +1 @@
|
|||
type T = S<foo(..): Send>;
|
||||
|
|
@ -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 ';'?
|
||||
|
||||
|
|
|
|||
|
|
@ -142,6 +142,18 @@ impl ConstArg {
|
|||
pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
|
||||
}
|
||||
|
||||
#[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)
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue