Skip to content

Commit b3bc3e7

Browse files
authored
Merge pull request #340 from dtolnay/fallbackscan
Add infallible expr scanner fallback for scanning invalid code
2 parents 60bc0f2 + 0ab908a commit b3bc3e7

File tree

1 file changed

+35
-1
lines changed

1 file changed

+35
-1
lines changed

impl/src/fmt.rs

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
use crate::ast::Field;
22
use crate::attr::{Display, Trait};
33
use crate::scan_expr;
4-
use proc_macro2::TokenTree;
4+
use proc_macro2::{TokenStream, TokenTree};
55
use quote::{format_ident, quote, quote_spanned};
66
use std::collections::{BTreeSet as Set, HashMap as Map};
77
use syn::ext::IdentExt;
8+
use syn::parse::discouraged::Speculative;
89
use syn::parse::{ParseStream, Parser};
910
use syn::{Expr, Ident, Index, LitStr, Member, Result, Token};
1011

@@ -118,7 +119,25 @@ impl Display<'_> {
118119
}
119120
}
120121

122+
#[allow(clippy::unnecessary_wraps)]
121123
fn explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
124+
let ahead = input.fork();
125+
if let Ok(set) = try_explicit_named_args(&ahead) {
126+
input.advance_to(&ahead);
127+
return Ok(set);
128+
}
129+
130+
let ahead = input.fork();
131+
if let Ok(set) = fallback_explicit_named_args(&ahead) {
132+
input.advance_to(&ahead);
133+
return Ok(set);
134+
}
135+
136+
input.parse::<TokenStream>().unwrap();
137+
Ok(Set::new())
138+
}
139+
140+
fn try_explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
122141
let scan_expr = if is_syn_full() {
123142
|input: ParseStream| input.parse::<Expr>().map(drop)
124143
} else {
@@ -143,6 +162,21 @@ fn explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
143162
Ok(named_args)
144163
}
145164

165+
fn fallback_explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
166+
let mut named_args = Set::new();
167+
168+
while !input.is_empty() {
169+
if input.peek(Token![,]) && input.peek2(Ident::peek_any) && input.peek3(Token![=]) {
170+
input.parse::<Token![,]>()?;
171+
let ident = input.call(Ident::parse_any)?;
172+
input.parse::<Token![=]>()?;
173+
named_args.insert(ident);
174+
}
175+
}
176+
177+
Ok(named_args)
178+
}
179+
146180
fn is_syn_full() -> bool {
147181
// Expr::Block contains syn::Block which contains Vec<syn::Stmt>. In the
148182
// current version of Syn, syn::Stmt is exhaustive and could only plausibly

0 commit comments

Comments
 (0)