Skip to content

Commit

Permalink
Merge pull request #945 from dtolnay/path
Browse files Browse the repository at this point in the history
Parse T<$ty>, $ty<T>, $ty::T
  • Loading branch information
dtolnay authored Dec 20, 2020
2 parents 1eabf0e + d5d2990 commit ae7d47f
Show file tree
Hide file tree
Showing 3 changed files with 218 additions and 12 deletions.
28 changes: 19 additions & 9 deletions src/path.rs
Original file line number Diff line number Diff line change
Expand Up @@ -499,22 +499,32 @@ pub mod parsing {
}
}

fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
Ok(Path {
pub(crate) fn parse_helper(input: ParseStream, expr_style: bool) -> Result<Self> {
let mut path = Path {
leading_colon: input.parse()?,
segments: {
let mut segments = Punctuated::new();
let value = PathSegment::parse_helper(input, expr_style)?;
segments.push_value(value);
while input.peek(Token![::]) {
let punct: Token![::] = input.parse()?;
segments.push_punct(punct);
let value = PathSegment::parse_helper(input, expr_style)?;
segments.push_value(value);
}
segments
},
})
};
Path::parse_rest(input, &mut path, expr_style)?;
Ok(path)
}

pub(crate) fn parse_rest(
input: ParseStream,
path: &mut Self,
expr_style: bool,
) -> Result<()> {
while input.peek(Token![::]) {
let punct: Token![::] = input.parse()?;
path.segments.push_punct(punct);
let value = PathSegment::parse_helper(input, expr_style)?;
path.segments.push_value(value);
}
Ok(())
}
}

Expand Down
36 changes: 33 additions & 3 deletions src/ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -342,11 +342,41 @@ pub mod parsing {
}

fn ambig_ty(input: ParseStream, allow_plus: bool) -> Result<Type> {
if input.peek(token::Group) && !input.peek2(Token![::]) && !input.peek2(Token![<]) {
return input.parse().map(Type::Group);
let begin = input.fork();

if input.peek(token::Group) {
let mut group: TypeGroup = input.parse()?;
if input.peek(Token![::]) && input.peek3(Ident::peek_any) {
if let Type::Path(mut ty) = *group.elem {
Path::parse_rest(input, &mut ty.path, false)?;
return Ok(Type::Path(ty));
} else {
return Ok(Type::Path(TypePath {
qself: Some(QSelf {
lt_token: Token![<](group.group_token.span),
position: 0,
as_token: None,
gt_token: Token![>](group.group_token.span),
ty: group.elem,
}),
path: Path::parse_helper(input, false)?,
}));
}
} else if input.peek(Token![<]) || input.peek(Token![::]) && input.peek3(Token![<]) {
if let Type::Path(mut ty) = *group.elem {
let arguments = &mut ty.path.segments.last_mut().unwrap().arguments;
if let PathArguments::None = arguments {
*arguments = PathArguments::AngleBracketed(input.parse()?);
Path::parse_rest(input, &mut ty.path, false)?;
return Ok(Type::Path(ty));
} else {
group.elem = Box::new(Type::Path(ty));
}
}
}
return Ok(Type::Group(group));
}

let begin = input.fork();
let mut lifetimes = None::<BoundLifetimes>;
let mut lookahead = input.lookahead1();
if lookahead.peek(Token![for]) {
Expand Down
166 changes: 166 additions & 0 deletions tests/test_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +50,170 @@ fn test_macro_variable_type() {
},
}
"###);

// mimics the token stream corresponding to `$ty::<T>`
let tokens = TokenStream::from_iter(vec![
TokenTree::Group(Group::new(Delimiter::None, quote! { ty })),
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Punct(Punct::new('<', Spacing::Alone)),
TokenTree::Ident(Ident::new("T", Span::call_site())),
TokenTree::Punct(Punct::new('>', Spacing::Alone)),
]);

snapshot!(tokens as Type, @r###"
Type::Path {
path: Path {
segments: [
PathSegment {
ident: "ty",
arguments: PathArguments::AngleBracketed {
colon2_token: Some,
args: [
Type(Type::Path {
path: Path {
segments: [
PathSegment {
ident: "T",
arguments: None,
},
],
},
}),
],
},
},
],
},
}
"###);
}

#[test]
fn test_group_angle_brackets() {
// mimics the token stream corresponding to `Option<$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<u8> })),
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,
},
],
},
}),
],
},
},
],
},
},
}),
],
},
},
],
},
}
"###);
}

#[test]
fn test_group_colons() {
// mimics the token stream corresponding to `$ty::Item`
let tokens = TokenStream::from_iter(vec![
TokenTree::Group(Group::new(Delimiter::None, quote! { Vec<u8> })),
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Ident(Ident::new("Item", Span::call_site())),
]);

snapshot!(tokens as Type, @r###"
Type::Path {
path: Path {
segments: [
PathSegment {
ident: "Vec",
arguments: PathArguments::AngleBracketed {
args: [
Type(Type::Path {
path: Path {
segments: [
PathSegment {
ident: "u8",
arguments: None,
},
],
},
}),
],
},
},
PathSegment {
ident: "Item",
arguments: None,
},
],
},
}
"###);

let tokens = TokenStream::from_iter(vec![
TokenTree::Group(Group::new(Delimiter::None, quote! { [T] })),
TokenTree::Punct(Punct::new(':', Spacing::Joint)),
TokenTree::Punct(Punct::new(':', Spacing::Alone)),
TokenTree::Ident(Ident::new("Element", Span::call_site())),
]);

snapshot!(tokens as Type, @r###"
Type::Path {
qself: Some(QSelf {
ty: Type::Slice {
elem: Type::Path {
path: Path {
segments: [
PathSegment {
ident: "T",
arguments: None,
},
],
},
},
},
position: 0,
}),
path: Path {
leading_colon: Some,
segments: [
PathSegment {
ident: "Element",
arguments: None,
},
],
},
}
"###);
}

0 comments on commit ae7d47f

Please sign in to comment.