diff --git a/src/ty.rs b/src/ty.rs index 6e493e05b7..bbacd8487b 100644 --- a/src/ty.rs +++ b/src/ty.rs @@ -342,8 +342,17 @@ pub mod parsing { } fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result { - if input.peek(token::Group) && !input.peek2(Token![::]) && !input.peek2(Token![<]) { - return input.parse().map(Type::Group); + if input.peek(token::Group) { + let forked = input.fork(); + // Consume the group, and check for a `::` or `<` *after* it + // This ensure that we match `$ty`, and not `$ty` + // where `$ty` is `SomeType. + // We cannot use `peek2`, since it looks *inside* a `None`-delimited + // group + let _ = forked.parse().map(Type::Group); + if !forked.peek(Token![::]) && !forked.peek(Token![<]) { + return input.parse().map(Type::Group); + } } let begin = input.fork(); diff --git a/tests/test_ty.rs b/tests/test_ty.rs index 9cbdcd6b99..1523391222 100644 --- a/tests/test_ty.rs +++ b/tests/test_ty.rs @@ -51,3 +51,55 @@ fn test_macro_variable_type() { } "###); } + +#[test] +fn test_group_angle_brackets() { + // mimics the token stream corresponding to `$ty` + let tokens = TokenStream::from_iter(vec![ + TokenTree::Ident(Ident::new("Option", Span::call_site())), + TokenTree::Punct(Punct::new('<', Spacing::Alone)), + TokenTree::Group(Group::new(Delimiter::None, quote! { Vec })), + TokenTree::Punct(Punct::new('>', Spacing::Alone)), + ]); + + snapshot!(tokens as Type, @r###" + Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Option", + arguments: PathArguments::AngleBracketed { + args: [ + Type(Type::Group { + elem: Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "Vec", + arguments: PathArguments::AngleBracketed { + args: [ + Type(Type::Path { + path: Path { + segments: [ + PathSegment { + ident: "u8", + arguments: None, + }, + ], + }, + }), + ], + }, + }, + ], + }, + }, + }), + ], + }, + }, + ], + }, + } + "###); +}