Skip to content

Commit

Permalink
Auto merge of #14746 - lowr:patch/associated-return-types, r=Veykril
Browse files Browse the repository at this point in the history
Parse associated return type bounds

This PR implements parser support for associated return type bounds: `T: Foo<bar(): Send>`. This PR does not implement associated return types (`T::bar(): Send`) because it's not implemented even in rustc, and also removes `(..)`-style return type notation because it has been removed in rust-lang/rust#110203 (effectively reverting #14465).

I don't plan to proactively follow this unstable feature unless an RFC is accepted and my main motivation here is to remove no-longer-valid syntax `(..)` from our parser, nevertheless adding minimal parser support so anyone interested (as can be seen in #14465) can experiment it without rust-analyzer's syntax errors.
  • Loading branch information
bors committed May 15, 2023
2 parents e5c7228 + fa2340a commit bc03418
Show file tree
Hide file tree
Showing 14 changed files with 363 additions and 106 deletions.
7 changes: 4 additions & 3 deletions crates/hir-def/src/path/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,10 @@ pub(super) fn lower_generic_args(
args.push(GenericArg::Type(type_ref));
}
ast::GenericArg::AssocTypeArg(assoc_type_arg) => {
if assoc_type_arg.param_list().is_some() {
// We currently ignore associated return type bounds.
continue;
}
if let Some(name_ref) = assoc_type_arg.name_ref() {
let name = name_ref.as_name();
let args = assoc_type_arg
Expand Down Expand Up @@ -216,9 +220,6 @@ 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.
}
}
}

Expand Down
41 changes: 23 additions & 18 deletions crates/parser/src/grammar/generic_args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,29 @@ fn generic_arg(p: &mut Parser<'_>) -> bool {
}
}
}
IDENT if p.nth(1) == T!['('] && p.nth_at(2, T![..]) => return_type_arg(p),
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>>() {}
generic_params::bounds(p);
m.complete(p, ASSOC_TYPE_ARG);
} else {
// test bare_dyn_types_with_paren_as_generic_args
// type A = S<Fn(i32)>;
// type A = S<Fn(i32) + Send>;
// type B = S<Fn(i32) -> i32>;
// type C = S<Fn(i32) -> i32 + Send>;
opt_ret_type(p);
let m = m.complete(p, PATH_SEGMENT).precede(p).complete(p, PATH);
let m = paths::type_path_for_qualifier(p, m);
let m = m.precede(p).complete(p, PATH_TYPE);
let m = types::opt_type_bounds_as_dyn_trait_type(p, m);
m.precede(p).complete(p, TYPE_ARG);
}
}
_ if p.at_ts(types::TYPE_FIRST) => type_arg(p),
_ => return false,
}
Expand Down Expand Up @@ -140,20 +162,3 @@ 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);
}
1 change: 1 addition & 0 deletions crates/parser/src/grammar/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) {
Mode::Type => {
// test typepathfn_with_coloncolon
// type F = Start::(Middle) -> (Middle)::End;
// type GenericArg = S<Start(Middle)::End>;
if p.at(T![::]) && p.nth_at(2, T!['(']) {
p.bump(T![::]);
}
Expand Down
9 changes: 6 additions & 3 deletions crates/parser/src/grammar/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -337,13 +337,16 @@ pub(super) fn path_type_(p: &mut Parser<'_>, allow_bounds: bool) {

/// This turns a parsed PATH_TYPE or FOR_TYPE optionally into a DYN_TRAIT_TYPE
/// with a TYPE_BOUND_LIST
fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser<'_>, type_marker: CompletedMarker) {
pub(super) fn opt_type_bounds_as_dyn_trait_type(
p: &mut Parser<'_>,
type_marker: CompletedMarker,
) -> CompletedMarker {
assert!(matches!(
type_marker.kind(),
SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_TYPE
));
if !p.at(T![+]) {
return;
return type_marker;
}

// First create a TYPE_BOUND from the completed PATH_TYPE
Expand All @@ -360,5 +363,5 @@ fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser<'_>, type_marker: CompletedM
let m = generic_params::bounds_without_colon_m(p, m);

// Finally precede everything with DYN_TRAIT_TYPE
m.precede(p).complete(p, DYN_TRAIT_TYPE);
m.precede(p).complete(p, DYN_TRAIT_TYPE)
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,41 @@ SOURCE_FILE
IDENT "End"
SEMICOLON ";"
WHITESPACE "\n"
TYPE_ALIAS
TYPE_KW "type"
WHITESPACE " "
NAME
IDENT "GenericArg"
WHITESPACE " "
EQ "="
WHITESPACE " "
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "S"
GENERIC_ARG_LIST
L_ANGLE "<"
TYPE_ARG
PATH_TYPE
PATH
PATH
PATH_SEGMENT
NAME_REF
IDENT "Start"
PARAM_LIST
L_PAREN "("
PARAM
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Middle"
R_PAREN ")"
COLON2 "::"
PATH_SEGMENT
NAME_REF
IDENT "End"
R_ANGLE ">"
SEMICOLON ";"
WHITESPACE "\n"
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
type F = Start::(Middle) -> (Middle)::End;
type GenericArg = S<Start(Middle)::End>;
33 changes: 0 additions & 33 deletions crates/parser/test_data/parser/inline/ok/0206_return_type_arg.rast

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
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 "Foo"
GENERIC_ARG_LIST
L_ANGLE "<"
ASSOC_TYPE_ARG
NAME_REF
IDENT "foo"
PARAM_LIST
L_PAREN "("
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Send"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "bar"
PARAM_LIST
L_PAREN "("
PARAM
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
R_PAREN ")"
COLON ":"
WHITESPACE " "
TYPE_BOUND_LIST
TYPE_BOUND
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "Send"
COMMA ","
WHITESPACE " "
ASSOC_TYPE_ARG
NAME_REF
IDENT "baz"
PARAM_LIST
L_PAREN "("
PARAM
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
COMMA ","
WHITESPACE " "
PARAM
PATH_TYPE
PATH
PATH_SEGMENT
NAME_REF
IDENT "i32"
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"
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
fn foo<T: Foo<foo(): Send, bar(i32): Send, baz(i32, i32): Send>>() {}
Loading

0 comments on commit bc03418

Please sign in to comment.