Skip to content

Commit

Permalink
Use syn's real expression parser if it has full syntax support
Browse files Browse the repository at this point in the history
  • Loading branch information
dtolnay committed Nov 3, 2024
1 parent 144b3b6 commit dabb96f
Showing 1 changed file with 27 additions and 3 deletions.
30 changes: 27 additions & 3 deletions impl/src/fmt.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use crate::ast::Field;
use crate::attr::{Display, Trait};
use crate::scan_expr::scan_expr;
use crate::scan_expr;
use proc_macro2::TokenTree;
use quote::{format_ident, quote_spanned};
use quote::{format_ident, quote, quote_spanned};
use std::collections::{BTreeSet as Set, HashMap as Map};
use syn::ext::IdentExt;
use syn::parse::{ParseStream, Parser};
use syn::{Ident, Index, LitStr, Member, Result, Token};
use syn::{Expr, Ident, Index, LitStr, Member, Result, Token};

impl Display<'_> {
// Transform `"error {var}"` to `"error {}", var`.
Expand Down Expand Up @@ -119,6 +119,12 @@ impl Display<'_> {
}

fn explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
let scan_expr = if is_syn_full() {
|input: ParseStream| input.parse::<Expr>().map(drop)
} else {
scan_expr::scan_expr
};

let mut named_args = Set::new();

while !input.is_empty() {
Expand All @@ -137,6 +143,24 @@ fn explicit_named_args(input: ParseStream) -> Result<Set<Ident>> {
Ok(named_args)
}

fn is_syn_full() -> bool {
// Expr::Block contains syn::Block which contains Vec<syn::Stmt>. In the
// current version of Syn, syn::Stmt is exhaustive and could only plausibly
// represent `trait Trait {}` in Stmt::Item which contains syn::Item. Most
// of the point of syn's non-"full" mode is to avoid compiling Item and the
// entire expansive syntax tree it comprises. So the following expression
// being parsed to Expr::Block is a reliable indication that "full" is
// enabled.
let test = quote!({
trait Trait {}
});
match syn::parse2(test) {
Ok(Expr::Verbatim(_)) | Err(_) => false,
Ok(Expr::Block(_)) => true,
Ok(_) => unreachable!(),
}
}

fn take_int(read: &mut &str) -> String {
let mut int = String::new();
for (i, ch) in read.char_indices() {
Expand Down

0 comments on commit dabb96f

Please sign in to comment.