Skip to content

Commit 0399ba4

Browse files
committed
Parse weird negative impls
1 parent 15de586 commit 0399ba4

File tree

2 files changed

+101
-13
lines changed

2 files changed

+101
-13
lines changed

src/item.rs

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2380,20 +2380,35 @@ pub mod parsing {
23802380
input.parse::<Token![const]>()?;
23812381
}
23822382

2383-
let trait_ = (|| -> Option<_> {
2384-
let ahead = input.fork();
2385-
let polarity: Option<Token![!]> = ahead.parse().ok()?;
2386-
let mut path: Path = ahead.parse().ok()?;
2387-
if path.segments.last().unwrap().arguments.is_empty() && ahead.peek(token::Paren) {
2388-
let parenthesized = PathArguments::Parenthesized(ahead.parse().ok()?);
2389-
path.segments.last_mut().unwrap().arguments = parenthesized;
2383+
let begin = input.fork();
2384+
let polarity = if input.peek(Token![!]) && !input.peek2(token::Brace) {
2385+
Some(input.parse::<Token![!]>()?)
2386+
} else {
2387+
None
2388+
};
2389+
2390+
let first_ty: Type = input.parse()?;
2391+
let self_ty: Type;
2392+
let trait_;
2393+
2394+
let is_impl_for = input.peek(Token![for]);
2395+
if is_impl_for {
2396+
let for_token: Token![for] = input.parse()?;
2397+
if let Type::Path(TypePath { qself: None, path }) = first_ty {
2398+
trait_ = Some((polarity, path, for_token));
2399+
} else {
2400+
trait_ = None;
23902401
}
2391-
let for_token: Token![for] = ahead.parse().ok()?;
2392-
input.advance_to(&ahead);
2393-
Some((polarity, path, for_token))
2394-
})();
2402+
self_ty = input.parse()?;
2403+
} else {
2404+
trait_ = None;
2405+
self_ty = if polarity.is_none() {
2406+
first_ty
2407+
} else {
2408+
Type::Verbatim(verbatim::between(begin, input))
2409+
};
2410+
}
23952411

2396-
let self_ty: Type = input.parse()?;
23972412
generics.where_clause = input.parse()?;
23982413

23992414
let content;
@@ -2405,7 +2420,7 @@ pub mod parsing {
24052420
items.push(content.parse()?);
24062421
}
24072422

2408-
if is_const_impl {
2423+
if is_const_impl || is_impl_for && trait_.is_none() {
24092424
Ok(None)
24102425
} else {
24112426
Ok(Some(ItemImpl {

tests/test_item.rs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,76 @@ fn test_macro_variable_attr() {
4343
}
4444
"###);
4545
}
46+
47+
#[test]
48+
fn test_negative_impl() {
49+
// Rustc parses all of the following.
50+
51+
#[cfg(any())]
52+
impl ! {}
53+
let tokens = quote! {
54+
impl ! {}
55+
};
56+
snapshot!(tokens as Item, @r###"
57+
Item::Impl {
58+
generics: Generics,
59+
self_ty: Type::Never,
60+
}
61+
"###);
62+
63+
#[cfg(any())]
64+
impl !Trait {}
65+
let tokens = quote! {
66+
impl !Trait {}
67+
};
68+
snapshot!(tokens as Item, @r###"
69+
Item::Impl {
70+
generics: Generics,
71+
self_ty: Verbatim(`! Trait`),
72+
}
73+
"###);
74+
75+
#[cfg(any())]
76+
impl !Trait for T {}
77+
let tokens = quote! {
78+
impl !Trait for T {}
79+
};
80+
snapshot!(tokens as Item, @r###"
81+
Item::Impl {
82+
generics: Generics,
83+
trait_: Some((
84+
Some,
85+
Path {
86+
segments: [
87+
PathSegment {
88+
ident: "Trait",
89+
arguments: None,
90+
},
91+
],
92+
},
93+
)),
94+
self_ty: Type::Path {
95+
path: Path {
96+
segments: [
97+
PathSegment {
98+
ident: "T",
99+
arguments: None,
100+
},
101+
],
102+
},
103+
},
104+
}
105+
"###);
106+
107+
#[cfg(any())]
108+
impl !! {}
109+
let tokens = quote! {
110+
impl !! {}
111+
};
112+
snapshot!(tokens as Item, @r###"
113+
Item::Impl {
114+
generics: Generics,
115+
self_ty: Verbatim(`! !`),
116+
}
117+
"###);
118+
}

0 commit comments

Comments
 (0)