diff --git a/crates/hir-def/src/path/lower.rs b/crates/hir-def/src/path/lower.rs index 7e4b7ac34b..26d2706175 100644 --- a/crates/hir-def/src/path/lower.rs +++ b/crates/hir-def/src/path/lower.rs @@ -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 diff --git a/crates/parser/src/grammar/generic_args.rs b/crates/parser/src/grammar/generic_args.rs index e583a4de71..b7d72b8d33 100644 --- a/crates/parser/src/grammar/generic_args.rs +++ b/crates/parser/src/grammar/generic_args.rs @@ -76,6 +76,29 @@ fn generic_arg(p: &mut Parser<'_>) -> bool { } } } + 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>() {} + generic_params::bounds(p); + m.complete(p, ASSOC_TYPE_ARG); + } else { + // test bare_dyn_types_with_paren_as_generic_args + // type A = S; + // type A = S; + // type B = S i32>; + // type C = S 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, } diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs index 26490aa97e..01b8f9e918 100644 --- a/crates/parser/src/grammar/paths.rs +++ b/crates/parser/src/grammar/paths.rs @@ -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; if p.at(T![::]) && p.nth_at(2, T!['(']) { p.bump(T![::]); } diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs index 26dac87956..93ef483502 100644 --- a/crates/parser/src/grammar/types.rs +++ b/crates/parser/src/grammar/types.rs @@ -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 @@ -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) } diff --git a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast index b47a5a5c14..67277d0639 100644 --- a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast +++ b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rast @@ -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" diff --git a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs index 8efd93a7ff..8c54f6704b 100644 --- a/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs +++ b/crates/parser/test_data/parser/inline/ok/0202_typepathfn_with_coloncolon.rs @@ -1 +1,2 @@ type F = Start::(Middle) -> (Middle)::End; +type GenericArg = S; diff --git a/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rast b/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rast new file mode 100644 index 0000000000..2fa52068c9 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rast @@ -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" diff --git a/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs b/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs new file mode 100644 index 0000000000..42029ac592 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0208_associated_return_type_bounds.rs @@ -0,0 +1 @@ +fn foo>() {} diff --git a/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rast b/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rast new file mode 100644 index 0000000000..d5f97bad89 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rast @@ -0,0 +1,175 @@ +SOURCE_FILE + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "A" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "A" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + DYN_TRAIT_TYPE + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Send" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "B" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_ANGLE ">" + SEMICOLON ";" + WHITESPACE "\n" + TYPE_ALIAS + TYPE_KW "type" + WHITESPACE " " + NAME + IDENT "C" + WHITESPACE " " + EQ "=" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "S" + GENERIC_ARG_LIST + L_ANGLE "<" + TYPE_ARG + DYN_TRAIT_TYPE + TYPE_BOUND_LIST + TYPE_BOUND + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "Fn" + PARAM_LIST + L_PAREN "(" + PARAM + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + R_PAREN ")" + WHITESPACE " " + RET_TYPE + THIN_ARROW "->" + WHITESPACE " " + PATH_TYPE + PATH + PATH_SEGMENT + NAME_REF + IDENT "i32" + WHITESPACE " " + PLUS "+" + WHITESPACE " " + 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/0209_bare_dyn_types_with_paren_as_generic_args.rs b/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rs new file mode 100644 index 0000000000..800002b1b8 --- /dev/null +++ b/crates/parser/test_data/parser/inline/ok/0209_bare_dyn_types_with_paren_as_generic_args.rs @@ -0,0 +1,4 @@ +type A = S; +type A = S; +type B = S i32>; +type C = S i32 + Send>; diff --git a/crates/syntax/rust.ungram b/crates/syntax/rust.ungram index 1c15a606f9..4c9027dec6 100644 --- a/crates/syntax/rust.ungram +++ b/crates/syntax/rust.ungram @@ -51,7 +51,9 @@ TypeArg = Type AssocTypeArg = - NameRef GenericArgList? (':' TypeBoundList | ('=' Type | ConstArg)) + NameRef + (GenericArgList | ParamList RetType?)? + (':' TypeBoundList | ('=' Type | ConstArg)) LifetimeArg = Lifetime @@ -581,7 +583,7 @@ ImplTraitType = 'impl' TypeBoundList DynTraitType = - 'dyn' TypeBoundList + 'dyn'? TypeBoundList TypeBoundList = bounds:(TypeBound ('+' TypeBound)* '+'?) diff --git a/crates/syntax/src/ast/generated/nodes.rs b/crates/syntax/src/ast/generated/nodes.rs index 0e84aca5c7..61f6a04c98 100644 --- a/crates/syntax/src/ast/generated/nodes.rs +++ b/crates/syntax/src/ast/generated/nodes.rs @@ -121,6 +121,8 @@ impl ast::HasTypeBounds for AssocTypeArg {} impl AssocTypeArg { pub fn name_ref(&self) -> Option { support::child(&self.syntax) } pub fn generic_arg_list(&self) -> Option { support::child(&self.syntax) } + pub fn param_list(&self) -> Option { support::child(&self.syntax) } + pub fn ret_type(&self) -> Option { support::child(&self.syntax) } pub fn eq_token(&self) -> Option { support::token(&self.syntax, T![=]) } pub fn ty(&self) -> Option { support::child(&self.syntax) } pub fn const_arg(&self) -> Option { support::child(&self.syntax) }