Improve error message to distinguish tuple struct vs tuple variant

This commit is contained in:
David Tolnay 2024-11-04 20:10:27 -05:00
parent 93690a35d6
commit 7e43dec573
No known key found for this signature in database
GPG key ID: F9BA143B95FF6D82
2 changed files with 49 additions and 5 deletions

View file

@ -2,6 +2,7 @@ use crate::attr::{self, Attrs};
use crate::generics::ParamsInScope;
use crate::unraw::{IdentUnraw, MemberUnraw};
use proc_macro2::Span;
use std::fmt::{self, Display};
use syn::{
Data, DataEnum, DataStruct, DeriveInput, Error, Fields, Generics, Ident, Index, Result, Type,
};
@ -40,6 +41,16 @@ pub struct Field<'a> {
pub contains_generic: bool,
}
#[derive(Copy, Clone)]
pub enum ContainerKind {
Struct,
TupleStruct,
UnitStruct,
StructVariant,
TupleVariant,
UnitVariant,
}
impl<'a> Input<'a> {
pub fn from_syn(node: &'a DeriveInput) -> Result<Self> {
match &node.data {
@ -60,7 +71,8 @@ impl<'a> Struct<'a> {
let span = attrs.span().unwrap_or_else(Span::call_site);
let fields = Field::multiple_from_syn(&data.fields, &scope, span)?;
if let Some(display) = &mut attrs.display {
display.expand_shorthand(&fields)?;
let container = ContainerKind::from_struct(data);
display.expand_shorthand(&fields, container)?;
}
Ok(Struct {
attrs,
@ -85,7 +97,8 @@ impl<'a> Enum<'a> {
display.clone_from(&attrs.display);
}
if let Some(display) = &mut variant.attrs.display {
display.expand_shorthand(&variant.fields)?;
let container = ContainerKind::from_variant(node);
display.expand_shorthand(&variant.fields, container)?;
} else if variant.attrs.transparent.is_none() {
variant.attrs.transparent = attrs.transparent;
}
@ -149,6 +162,37 @@ impl<'a> Field<'a> {
}
}
impl ContainerKind {
fn from_struct(node: &DataStruct) -> Self {
match node.fields {
Fields::Named(_) => ContainerKind::Struct,
Fields::Unnamed(_) => ContainerKind::TupleStruct,
Fields::Unit => ContainerKind::UnitStruct,
}
}
fn from_variant(node: &syn::Variant) -> Self {
match node.fields {
Fields::Named(_) => ContainerKind::StructVariant,
Fields::Unnamed(_) => ContainerKind::TupleVariant,
Fields::Unit => ContainerKind::UnitVariant,
}
}
}
impl Display for ContainerKind {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str(match self {
ContainerKind::Struct => "struct",
ContainerKind::TupleStruct => "tuple struct",
ContainerKind::UnitStruct => "unit struct",
ContainerKind::StructVariant => "struct variant",
ContainerKind::TupleVariant => "tuple variant",
ContainerKind::UnitVariant => "unit variant",
})
}
}
impl Attrs<'_> {
pub fn span(&self) -> Option<Span> {
if let Some(display) = &self.display {

View file

@ -1,4 +1,4 @@
use crate::ast::Field;
use crate::ast::{ContainerKind, Field};
use crate::attr::{Display, Trait};
use crate::scan_expr::scan_expr;
use crate::unraw::{IdentUnraw, MemberUnraw};
@ -13,7 +13,7 @@ use syn::{Expr, Ident, Index, LitStr, Token};
impl Display<'_> {
// Transform `"error {var}"` to `"error {}", var`.
pub fn expand_shorthand(&mut self, fields: &[Field]) -> Result<()> {
pub fn expand_shorthand(&mut self, fields: &[Field], container: ContainerKind) -> Result<()> {
let raw_args = self.args.clone();
let FmtArguments {
named: mut named_args,
@ -62,7 +62,7 @@ impl Display<'_> {
let int = take_int(&mut read);
if !extra_positional_arguments_allowed {
if let Some(first_unnamed) = &first_unnamed {
let msg = "ambiguous reference to positional arguments by number in a tuple struct; change this to a named argument";
let msg = format!("ambiguous reference to positional arguments by number in a {container}; change this to a named argument");
return Err(Error::new_spanned(first_unnamed, msg));
}
}