Skip to content

Commit

Permalink
Fix build failures
Browse files Browse the repository at this point in the history
  • Loading branch information
TedDriggs committed Jan 30, 2024
1 parent 1b3017d commit a962baf
Show file tree
Hide file tree
Showing 11 changed files with 77 additions and 89 deletions.
8 changes: 4 additions & 4 deletions derive_builder/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -645,13 +645,13 @@
//! #[derive(Debug, PartialEq, Default, Builder, Clone)]
//! #[builder(derive(Debug, PartialEq))]
//! struct Lorem {
//! #[builder(setter(into), field(type = "u32"))]
//! #[builder(setter(into), field(ty = "u32"))]
//! ipsum: u32,
//!
//! #[builder(field(type = "String", build = "()"))]
//! #[builder(field(ty = "String", build = "()"))]
//! dolor: (),
//!
//! #[builder(field(type = "&'static str", build = "self.amet.parse()?"))]
//! #[builder(field(ty = "&'static str", build = "self.amet.parse()?"))]
//! amet: u32,
//! }
//!
Expand All @@ -670,7 +670,7 @@
//! # }
//! ```
//!
//! The builder field type (`type =`) must implement `Default`.
//! The builder field type (`ty =`) must implement `Default`.
//!
//! The argument to `build` must be a literal string containing Rust code for the contents of a block, which must evaluate to the type of the target field.
//! It may refer to the builder struct as `self`, use `?`, etc.
Expand Down
4 changes: 2 additions & 2 deletions derive_builder/tests/builder_field_custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ use std::num::ParseIntError;

#[derive(Debug, PartialEq, Default, Builder, Clone)]
pub struct Lorem {
#[builder(field(type = "Option<usize>", build = "self.ipsum.unwrap_or(42) + 1"))]
#[builder(field(ty = "Option<usize>", build = "self.ipsum.unwrap_or(42) + 1"))]
ipsum: usize,

#[builder(setter(into), field(type = "String", build = "self.dolor.parse()?"))]
#[builder(setter(into), field(ty = "String", build = "self.dolor.parse()?"))]
dolor: u32,
}

Expand Down
4 changes: 2 additions & 2 deletions derive_builder/tests/compile-fail/builder_field_custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ pub struct Lorem {
ipsum: usize,

// `default` is incompatible with `field.type`, even without `field.build`
#[builder(default = "2", field(type = "usize"))]
#[builder(default = "2", field(ty = "usize"))]
sit: usize,

// Both errors can occur on the same field
#[builder(default = "3", field(type = "usize", build = "self.ipsum + 42"))]
#[builder(default = "3", field(ty = "usize", build = "self.ipsum + 42"))]
amet: usize,
}

Expand Down
10 changes: 5 additions & 5 deletions derive_builder/tests/compile-fail/builder_field_custom.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ error: #[builder(default)] and #[builder(field(build="..."))] cannot be used tog
8 | default = "1",
| ^^^

error: #[builder(default)] and #[builder(field(type="..."))] cannot be used together
error: #[builder(default)] and #[builder(field(ty="..."))] cannot be used together
--> tests/compile-fail/builder_field_custom.rs:14:25
|
14 | #[builder(default = "2", field(type = "usize"))]
14 | #[builder(default = "2", field(ty = "usize"))]
| ^^^

error: #[builder(default)] and #[builder(field(build="..."))] cannot be used together
--> tests/compile-fail/builder_field_custom.rs:18:25
|
18 | #[builder(default = "3", field(type = "usize", build = "self.ipsum + 42"))]
18 | #[builder(default = "3", field(ty = "usize", build = "self.ipsum + 42"))]
| ^^^

error: #[builder(default)] and #[builder(field(type="..."))] cannot be used together
error: #[builder(default)] and #[builder(field(ty="..."))] cannot be used together
--> tests/compile-fail/builder_field_custom.rs:18:25
|
18 | #[builder(default = "3", field(type = "usize", build = "self.ipsum + 42"))]
18 | #[builder(default = "3", field(ty = "usize", build = "self.ipsum + 42"))]
| ^^^
16 changes: 9 additions & 7 deletions derive_builder_core/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
[package]
name = "derive_builder_core"
version = "0.13.0"
authors = ["Colin Kiegel <[email protected]>",
"Pascal Hertleif <[email protected]>",
"Jan-Erik Rediger <[email protected]>",
"Ted Driggs <[email protected]>"]
authors = [
"Colin Kiegel <[email protected]>",
"Pascal Hertleif <[email protected]>",
"Jan-Erik Rediger <[email protected]>",
"Ted Driggs <[email protected]>",
]

description = "Internal helper library for the derive_builder crate."
repository = "https://github.com/colin-kiegel/rust-derive-builder"
Expand All @@ -19,10 +21,10 @@ clippy = []
lib_has_std = []

[dependencies]
darling = "0.14.0"
darling = "0.20.4"
proc-macro2 = "1.0.37"
quote = "1.0.18"
syn = { version = "1.0.91", features = ["full", "extra-traits"] }
quote = "1.0.35"
syn = { version = "2.0.15", features = ["full", "extra-traits"] }

[dev-dependencies]
pretty_assertions = "1.2.1"
10 changes: 7 additions & 3 deletions derive_builder_core/src/block.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::convert::TryFrom;

use proc_macro2::TokenStream;
use proc_macro2::{Span, TokenStream};
use quote::ToTokens;
use syn::{self, spanned::Spanned, Block, LitStr};

Expand All @@ -16,6 +16,10 @@ impl BlockContents {
pub fn is_empty(&self) -> bool {
self.0.stmts.is_empty()
}

pub fn span(&self) -> Span {
self.0.span()
}
}

impl ToTokens for BlockContents {
Expand All @@ -39,7 +43,7 @@ impl From<syn::Expr> for BlockContents {
fn from(v: syn::Expr) -> Self {
Self(Block {
brace_token: syn::token::Brace(v.span()),
stmts: vec![syn::Stmt::Expr(v)],
stmts: vec![syn::Stmt::Expr(v, None)],
})
}
}
Expand Down Expand Up @@ -71,7 +75,7 @@ mod test {
}

#[test]
#[should_panic(expected = r#"lex error"#)]
#[should_panic(expected = r#"cannot parse"#)]
fn block_invalid_token_trees() {
parse("let x = 2; { x+1").unwrap();
}
Expand Down
2 changes: 1 addition & 1 deletion derive_builder_core/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -858,7 +858,7 @@ mod tests {

add_simple_foo_builder(&mut result);

result.append_all(quote!(compile_error! { #ALLOC_NOT_ENABLED_ERROR }));
result.append_all(quote!(::core::compile_error! { #ALLOC_NOT_ENABLED_ERROR }));

result
}
Expand Down
16 changes: 7 additions & 9 deletions derive_builder_core/src/default_expression.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,13 @@ impl DefaultExpression {
}
}

pub fn span(&self) -> Span {
match self {
DefaultExpression::Explicit(block) => block.span(),
DefaultExpression::Trait => Span::call_site(),
}
}

#[cfg(test)]
pub fn explicit<I: Into<BlockContents>>(content: I) -> Self {
DefaultExpression::Explicit(content.into())
Expand All @@ -39,15 +46,6 @@ impl darling::FromMeta for DefaultExpression {
}
}

impl syn::spanned::Spanned for DefaultExpression {
fn span(&self) -> Span {
match self {
DefaultExpression::Explicit(block) => block.span(),
DefaultExpression::Trait => Span::call_site(),
}
}
}

/// Wrapper for `DefaultExpression`
struct DefaultExpressionWithCrateRoot<'a> {
crate_root: &'a syn::Path,
Expand Down
80 changes: 31 additions & 49 deletions derive_builder_core/src/macro_options/darling_opts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ use crate::BuildMethod;

use darling::util::{Flag, PathList, SpannedValue};
use darling::{self, Error, FromMeta};
use proc_macro2::{Span, TokenStream};
use syn::parse::{ParseStream, Parser};
use proc_macro2::Span;
use syn::Meta;
use syn::{self, spanned::Spanned, Attribute, Generics, Ident, Path};

Expand Down Expand Up @@ -61,8 +60,10 @@ fn no_visibility_conflict<T: Visibility>(v: &T) -> darling::Result<()> {
}
} else if declares_public && declares_private {
Err(
Error::custom(r#"`public` and `private` cannot be used together"#)
.with_span(v.public()),
Error::custom(r#"`public` and `private` cannot be used together"#).with_span(
// TODO fix this
&Span::call_site(),
),
)
} else {
Ok(())
Expand Down Expand Up @@ -103,7 +104,7 @@ impl FromMeta for BuildFnError {
match item {
Meta::Path(_) => Err(Error::unsupported_format("word").with_span(item)),
Meta::List(_) => BuildFnErrorGenerated::from_meta(item).map(Self::Generated),
Meta::NameValue(i) => Path::from_value(&i.lit).map(Self::Existing),
Meta::NameValue(i) => Path::from_expr(&i.value).map(Self::Existing),
}
}
}
Expand All @@ -112,7 +113,7 @@ impl FromMeta for BuildFnError {
/// There is no inheritance for these settings from struct-level to field-level,
/// so we don't bother using `Option` for values in this struct.
#[derive(Debug, Clone, FromMeta)]
#[darling(default, and_then = "Self::validation_needs_error")]
#[darling(default, and_then = Self::validation_needs_error)]
pub struct BuildFn {
skip: bool,
name: Ident,
Expand Down Expand Up @@ -155,7 +156,7 @@ impl BuildFn {
Error::custom(
"Cannot set `error(validation_error = false)` when using `validate`",
)
.with_span(&e.validation_error),
.with_span(&e.validation_error.span()),
)
}
}
Expand Down Expand Up @@ -226,7 +227,7 @@ pub struct FieldLevelFieldMeta {
private: Flag,
vis: Option<syn::Visibility>,
/// Custom builder field type
#[darling(rename = "type")]
#[darling(rename = "ty")]
builder_type: Option<syn::Type>,
/// Custom builder field method, for making target struct field value
build: Option<BlockContents>,
Expand Down Expand Up @@ -270,14 +271,10 @@ impl StructLevelSetter {
/// * `each(name = "...")`, which allows setting additional options on the `each` setter
fn parse_each(meta: &Meta) -> darling::Result<Option<Each>> {
if let Meta::NameValue(mnv) = meta {
if let syn::Lit::Str(v) = &mnv.lit {
v.parse::<Ident>()
.map(Each::from)
.map(Some)
.map_err(|_| darling::Error::unknown_value(&v.value()).with_span(v))
} else {
Err(darling::Error::unexpected_lit_type(&mnv.lit))
}
Ident::from_meta(meta)
.map(Each::from)
.map(Some)
.map_err(|e| e.with_span(&mnv.value))
} else {
Each::from_meta(meta).map(Some)
}
Expand All @@ -294,7 +291,7 @@ pub struct FieldLevelSetter {
strip_option: Option<bool>,
skip: Option<bool>,
custom: Option<bool>,
#[darling(with = "parse_each")]
#[darling(with = parse_each)]
each: Option<Each>,
}

Expand Down Expand Up @@ -425,19 +422,19 @@ impl Field {
darling::Error::custom(
r#"#[builder(default)] and #[builder(field(build="..."))] cannot be used together"#,
)
.with_span(field_default),
.with_span(&field_default.span()),
);
}

// `field.type` being set means `default` will not be used, since we don't know how
// `field.ty` being set means `default` will not be used, since we don't know how
// to check a custom field type for the absence of a value and therefore we'll never
// know that we should use the `default` value.
if self.field.builder_type.is_some() {
errors.push(
darling::Error::custom(
r#"#[builder(default)] and #[builder(field(type="..."))] cannot be used together"#,
r#"#[builder(default)] and #[builder(field(ty="..."))] cannot be used together"#,
)
.with_span(field_default)
.with_span(&field_default.span())
)
}
};
Expand Down Expand Up @@ -482,7 +479,7 @@ fn distribute_and_unnest_attrs(
for attr in input.drain(..) {
let destination = outputs
.iter_mut()
.find(|(ptattr, _)| attr.path.is_ident(ptattr));
.find(|(ptattr, _)| attr.path().is_ident(ptattr));

if let Some((_, destination)) = destination {
match unnest_from_one_attribute(attr) {
Expand All @@ -509,7 +506,7 @@ fn unnest_from_one_attribute(attr: syn::Attribute) -> darling::Result<Attribute>
syn::AttrStyle::Inner(bang) => {
return Err(darling::Error::unsupported_format(&format!(
"{} must be an outer attribute",
attr.path
attr.path()
.get_ident()
.map(Ident::to_string)
.unwrap_or_else(|| "Attribute".to_string())
Expand All @@ -518,34 +515,19 @@ fn unnest_from_one_attribute(attr: syn::Attribute) -> darling::Result<Attribute>
}
};

#[derive(Debug)]
struct ContainedAttribute(syn::Attribute);
impl syn::parse::Parse for ContainedAttribute {
fn parse(input: ParseStream) -> syn::Result<Self> {
// Strip parentheses, and save the span of the parenthesis token
let content;
let paren_token = parenthesized!(content in input);
let wrap_span = paren_token.span;

// Wrap up in #[ ] instead.
let pound = Token![#](wrap_span); // We can't write a literal # inside quote
let content: TokenStream = content.parse()?;
let content = quote_spanned!(wrap_span=> #pound [ #content ]);

let parser = syn::Attribute::parse_outer;
let mut attrs = parser.parse2(content)?.into_iter();
// TryFrom for Array not available in Rust 1.40
// We think this error can never actually happen, since `#[...]` ought to make just one Attribute
let attr = match (attrs.next(), attrs.next()) {
(Some(attr), None) => attr,
_ => return Err(input.error("expected exactly one attribute")),
};
Ok(Self(attr))
let original_span = attr.span();

let pound = attr.pound_token;
let meta = attr.meta;

match meta {
Meta::Path(_) => Err(Error::unsupported_format("word").with_span(&meta)),
Meta::NameValue(_) => Err(Error::unsupported_format("name-value").with_span(&meta)),
Meta::List(list) => {
let inner = list.tokens;
Ok(parse_quote_spanned!(original_span=> #pound [ #inner ]))
}
}

let ContainedAttribute(attr) = syn::parse2(attr.tokens)?;
Ok(attr)
}

impl Visibility for Field {
Expand Down
4 changes: 2 additions & 2 deletions derive_builder_core/src/setter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ fn wrap_expression_in_some(crate_root: &syn::Path, bare_value: impl ToTokens) ->
// We cannot handle those arbitrary names.
fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> {
use syn::punctuated::Pair;
use syn::token::Colon2;
use syn::token::PathSep;
use syn::{GenericArgument, Path, PathArguments, PathSegment};

fn extract_type_path(ty: &syn::Type) -> Option<&Path> {
Expand All @@ -255,7 +255,7 @@ fn extract_type_from_option(ty: &syn::Type) -> Option<&syn::Type> {

// TODO store (with lazy static) precomputed parsing of Option when support of rust 1.18 will be removed (incompatible with lazy_static)
// TODO maybe optimization, reverse the order of segments
fn extract_option_segment(path: &Path) -> Option<Pair<&PathSegment, &Colon2>> {
fn extract_option_segment(path: &Path) -> Option<Pair<&PathSegment, &PathSep>> {
let idents_of_path = path.segments.iter().fold(String::new(), |mut acc, v| {
acc.push_str(&v.ident.to_string());
acc.push('|');
Expand Down
Loading

0 comments on commit a962baf

Please sign in to comment.