Skip to content

Commit e106feb

Browse files
committed
Eagerly parse variant-level borrow attribute instead of deferring entire Meta
1 parent 696f6f5 commit e106feb

File tree

1 file changed

+57
-15
lines changed

1 file changed

+57
-15
lines changed

serde_derive/src/internals/attr.rs

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,12 @@ pub struct Variant {
797797
other: bool,
798798
serialize_with: Option<syn::ExprPath>,
799799
deserialize_with: Option<syn::ExprPath>,
800-
borrow: Option<syn::Meta>,
800+
borrow: Option<BorrowAttribute>,
801+
}
802+
803+
struct BorrowAttribute {
804+
path: syn::Path,
805+
lifetimes: Option<BTreeSet<syn::Lifetime>>,
801806
}
802807

803808
impl Variant {
@@ -950,10 +955,35 @@ impl Variant {
950955
}
951956
}
952957

953-
// Defer `#[serde(borrow)]` and `#[serde(borrow = "'a + 'b")]`
954-
Meta(m) if m.path() == BORROW => match &variant.fields {
958+
// Parse `#[serde(borrow)]`
959+
Meta(Path(word)) if word == BORROW => match &variant.fields {
960+
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
961+
borrow.set(
962+
word,
963+
BorrowAttribute {
964+
path: word.clone(),
965+
lifetimes: None,
966+
},
967+
);
968+
}
969+
_ => {
970+
let msg = "#[serde(borrow)] may only be used on newtype variants";
971+
cx.error_spanned_by(variant, msg);
972+
}
973+
},
974+
975+
// Parse `#[serde(borrow = "'a + 'b")]`
976+
Meta(NameValue(m)) if m.path == BORROW => match &variant.fields {
955977
syn::Fields::Unnamed(fields) if fields.unnamed.len() == 1 => {
956-
borrow.set(m.path(), m.clone());
978+
if let Ok(lifetimes) = parse_lit_into_lifetimes(cx, BORROW, &m.lit) {
979+
borrow.set(
980+
&m.path,
981+
BorrowAttribute {
982+
path: m.path.clone(),
983+
lifetimes: Some(lifetimes),
984+
},
985+
);
986+
}
957987
}
958988
_ => {
959989
let msg = "#[serde(borrow)] may only be used on newtype variants";
@@ -1110,17 +1140,29 @@ impl Field {
11101140
None => index.to_string(),
11111141
};
11121142

1113-
let variant_borrow = attrs
1114-
.and_then(|variant| variant.borrow.as_ref())
1115-
.map(|borrow| Meta(borrow.clone()));
1116-
1117-
for meta_item in variant_borrow.into_iter().chain(
1118-
field
1119-
.attrs
1120-
.iter()
1121-
.flat_map(|attr| get_serde_meta_items(cx, attr))
1122-
.flatten(),
1123-
) {
1143+
if let Some(borrow_attribute) = attrs.and_then(|variant| variant.borrow.as_ref()) {
1144+
if let Ok(borrowable) = borrowable_lifetimes(cx, &ident, field) {
1145+
if let Some(lifetimes) = &borrow_attribute.lifetimes {
1146+
for lifetime in lifetimes {
1147+
if !borrowable.contains(lifetime) {
1148+
let msg =
1149+
format!("field `{}` does not have lifetime {}", ident, lifetime);
1150+
cx.error_spanned_by(field, msg);
1151+
}
1152+
}
1153+
borrowed_lifetimes.set(&borrow_attribute.path, lifetimes.clone());
1154+
} else {
1155+
borrowed_lifetimes.set(&borrow_attribute.path, borrowable);
1156+
}
1157+
}
1158+
}
1159+
1160+
for meta_item in field
1161+
.attrs
1162+
.iter()
1163+
.flat_map(|attr| get_serde_meta_items(cx, attr))
1164+
.flatten()
1165+
{
11241166
match &meta_item {
11251167
// Parse `#[serde(rename = "foo")]`
11261168
Meta(NameValue(m)) if m.path == RENAME => {

0 commit comments

Comments
 (0)