Skip to content

Commit 37dff90

Browse files
authored
Merge pull request dtolnay#936 from dtolnay/negative
Parse weird negative impls
2 parents 15de586 + 43a2eaa commit 37dff90

File tree

2 files changed

+103
-13
lines changed

2 files changed

+103
-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: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,3 +43,78 @@ 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+
#[rustfmt::skip]
65+
impl !Trait {}
66+
let tokens = quote! {
67+
impl !Trait {}
68+
};
69+
snapshot!(tokens as Item, @r###"
70+
Item::Impl {
71+
generics: Generics,
72+
self_ty: Verbatim(`! Trait`),
73+
}
74+
"###);
75+
76+
#[cfg(any())]
77+
impl !Trait for T {}
78+
let tokens = quote! {
79+
impl !Trait for T {}
80+
};
81+
snapshot!(tokens as Item, @r###"
82+
Item::Impl {
83+
generics: Generics,
84+
trait_: Some((
85+
Some,
86+
Path {
87+
segments: [
88+
PathSegment {
89+
ident: "Trait",
90+
arguments: None,
91+
},
92+
],
93+
},
94+
)),
95+
self_ty: Type::Path {
96+
path: Path {
97+
segments: [
98+
PathSegment {
99+
ident: "T",
100+
arguments: None,
101+
},
102+
],
103+
},
104+
},
105+
}
106+
"###);
107+
108+
#[cfg(any())]
109+
#[rustfmt::skip]
110+
impl !! {}
111+
let tokens = quote! {
112+
impl !! {}
113+
};
114+
snapshot!(tokens as Item, @r###"
115+
Item::Impl {
116+
generics: Generics,
117+
self_ty: Verbatim(`! !`),
118+
}
119+
"###);
120+
}

0 commit comments

Comments
 (0)