Skip to content

Commit 978f134

Browse files
committed
[spr] initial version
Created using spr 1.3.6-beta.1
2 parents 092c10c + 137601a commit 978f134

18 files changed

+300
-43
lines changed

daft-derive/src/internals/imp.rs

+30-34
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,50 @@
11
use super::error_store::{ErrorSink, ErrorStore};
22
use proc_macro2::{Span, TokenStream};
3-
use quote::{quote, ToTokens};
3+
use quote::{quote, quote_spanned, ToTokens};
44
use syn::{
5-
parse_quote, parse_str, visit::Visit, Attribute, Data, DataStruct,
6-
DeriveInput, Expr, Field, Fields, GenericParam, Generics, Index, Lifetime,
7-
LifetimeParam, Path, Token, WhereClause, WherePredicate,
5+
parse_quote, parse_quote_spanned, parse_str, spanned::Spanned,
6+
visit::Visit, Attribute, Data, DataStruct, DeriveInput, Expr, Field,
7+
Fields, GenericParam, Generics, Index, Lifetime, LifetimeParam, Path,
8+
Token, WhereClause, WherePredicate,
89
};
910

10-
pub fn derive_diffable(input: syn::DeriveInput) -> TokenStream {
11+
pub struct DeriveDiffableOutput {
12+
pub out: Option<TokenStream>,
13+
pub errors: Vec<syn::Error>,
14+
}
15+
16+
impl ToTokens for DeriveDiffableOutput {
17+
fn to_tokens(&self, tokens: &mut TokenStream) {
18+
tokens.extend(self.out.clone());
19+
tokens.extend(self.errors.iter().map(|error| error.to_compile_error()));
20+
}
21+
}
22+
23+
pub fn derive_diffable(input: syn::DeriveInput) -> DeriveDiffableOutput {
1124
let mut error_store = ErrorStore::new();
1225

1326
match &input.data {
1427
Data::Enum(_) => {
1528
// Implement all Enums as `Leaf`s
1629
let out = make_leaf(&input, AttrPosition::Enum, error_store.sink());
17-
// Errors might have occurred while parsing attributes.
18-
let errors = error_store
19-
.into_inner()
20-
.into_iter()
21-
.map(|error| error.into_compile_error());
22-
quote! {
23-
#out
24-
#(#errors)*
30+
DeriveDiffableOutput {
31+
out: Some(out),
32+
errors: error_store.into_inner(),
2533
}
2634
}
2735
Data::Struct(s) => {
2836
// This might be None if there are errors.
2937
let out = make_struct_impl(&input, s, error_store.sink());
30-
let errors = error_store
31-
.into_inner()
32-
.into_iter()
33-
.map(|error| error.into_compile_error());
34-
quote! {
35-
#out
36-
#(#errors)*
37-
}
38+
DeriveDiffableOutput { out, errors: error_store.into_inner() }
3839
}
3940

4041
Data::Union(_) => {
4142
// Implement all unions as `Leaf`s
4243
let out =
4344
make_leaf(&input, AttrPosition::Union, error_store.sink());
44-
// Errors might have occurred while parsing attributes.
45-
let errors = error_store
46-
.into_inner()
47-
.into_iter()
48-
.map(|error| error.into_compile_error());
49-
quote! {
50-
#out
51-
#(#errors)*
45+
DeriveDiffableOutput {
46+
out: Some(out),
47+
errors: error_store.into_inner(),
5248
}
5349
}
5450
}
@@ -568,11 +564,11 @@ impl DiffFields {
568564
let mut f = f.clone();
569565

570566
f.ty = if config.mode == FieldMode::Leaf {
571-
parse_quote! {
567+
parse_quote_spanned! {f.span()=>
572568
#daft_crate::Leaf<&#lt #ty>
573569
}
574570
} else {
575-
parse_quote! {
571+
parse_quote_spanned! {f.span()=>
576572
<#ty as #daft_crate::Diffable>::Diff<#lt>
577573
}
578574
};
@@ -596,7 +592,7 @@ impl DiffFields {
596592
trait_bound: &syn::TraitBound,
597593
) -> WhereClause {
598594
let predicates = self.types().map(|ty| -> WherePredicate {
599-
parse_quote! {
595+
parse_quote_spanned! {ty.span()=>
600596
#ty: #trait_bound
601597
}
602598
});
@@ -632,14 +628,14 @@ fn generate_field_diffs(
632628
}
633629
};
634630
if config.mode == FieldMode::Leaf {
635-
quote! {
631+
quote_spanned! {f.span()=>
636632
#field_name: #daft_crate::Leaf {
637633
before: &self.#field_name,
638634
after: &other.#field_name
639635
}
640636
}
641637
} else {
642-
quote! {
638+
quote_spanned! {f.span()=>
643639
#field_name: #daft_crate::Diffable::diff(
644640
&self.#field_name,
645641
&other.#field_name

daft-derive/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#![doc(html_root_url = "https://docs.rs/daft-derive/0.1.1")]
77
mod internals;
88

9+
use quote::ToTokens;
910
use syn::parse_macro_input;
1011

1112
// NOTE: We do not define documentation here -- only in daft while re-exporting
@@ -16,5 +17,5 @@ pub fn derive_diffable(
1617
input: proc_macro::TokenStream,
1718
) -> proc_macro::TokenStream {
1819
let input = parse_macro_input!(input as syn::DeriveInput);
19-
internals::derive_diffable(input).into()
20+
internals::derive_diffable(input).into_token_stream().into()
2021
}

daft-derive/tests/fixtures/README.md

+12-3
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,15 @@ These fixtures ensure that:
99

1010
Each file in `valid` is automatically picked up by the snapshot and UI tests.
1111

12-
Currently, `snapshot_test.rs` only tests the first struct or enum in the file.
13-
The test can be extended to test multiple macro invocations per file if
14-
necessary.
12+
`snapshot_test.rs` tests all macro invocations annotated with `#[derive(Diffable)]`.
13+
14+
## Invalid fixtures
15+
16+
These fixtures ensure that:
17+
18+
* the macro's success output, if any, is stable, via `snapshot_test.rs`.
19+
* the macro's output fails with a good error message, via `ui_test.rs`.
20+
21+
Each file in `invalid` is automatically picked up by the snapshot and UI tests.
22+
23+
Like with valid fixtures, `snapshot_test.rs` tests all macro invocations annotated with `#[derive(Diffable)]`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
impl ::daft::Diffable for MyEnum {
2+
type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft;
3+
fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> {
4+
::daft::Leaf {
5+
before: self,
6+
after: other,
7+
}
8+
}
9+
}
10+
impl ::daft::Diffable for MyEnum2 {
11+
type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft;
12+
fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> {
13+
::daft::Leaf {
14+
before: self,
15+
after: other,
16+
}
17+
}
18+
}

daft-derive/tests/fixtures/invalid/output/field-attribute-with-value.output.rs

Whitespace-only changes.

daft-derive/tests/fixtures/invalid/output/field-leaf-and-ignore.output.rs

Whitespace-only changes.

daft-derive/tests/fixtures/invalid/output/field-specified-multiple-times.output.rs

Whitespace-only changes.

daft-derive/tests/fixtures/invalid/output/field-unknown-attribute.output.rs

Whitespace-only changes.

daft-derive/tests/fixtures/invalid/output/struct-attribute-with-value.output.rs

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
struct MyStructDiff<'__daft> {
2+
a: <i32 as ::daft::Diffable>::Diff<'__daft>,
3+
b: <NonDiffable as ::daft::Diffable>::Diff<'__daft>,
4+
}
5+
impl<'__daft> ::std::fmt::Debug for MyStructDiff<'__daft>
6+
where
7+
<i32 as ::daft::Diffable>::Diff<'__daft>: ::std::fmt::Debug,
8+
<NonDiffable as ::daft::Diffable>::Diff<'__daft>: ::std::fmt::Debug,
9+
{
10+
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
11+
f.debug_struct(stringify!(MyStructDiff))
12+
.field(stringify!(a), &self.a)
13+
.field(stringify!(b), &self.b)
14+
.finish()
15+
}
16+
}
17+
impl<'__daft> ::std::cmp::PartialEq for MyStructDiff<'__daft>
18+
where
19+
<i32 as ::daft::Diffable>::Diff<'__daft>: ::std::cmp::PartialEq,
20+
<NonDiffable as ::daft::Diffable>::Diff<'__daft>: ::std::cmp::PartialEq,
21+
{
22+
fn eq(&self, other: &Self) -> bool {
23+
self.a == other.a && self.b == other.b
24+
}
25+
}
26+
impl<'__daft> ::std::cmp::Eq for MyStructDiff<'__daft>
27+
where
28+
<i32 as ::daft::Diffable>::Diff<'__daft>: ::std::cmp::Eq,
29+
<NonDiffable as ::daft::Diffable>::Diff<'__daft>: ::std::cmp::Eq,
30+
{}
31+
impl ::daft::Diffable for MyStruct {
32+
type Diff<'__daft> = MyStructDiff<'__daft> where Self: '__daft;
33+
fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> MyStructDiff<'__daft> {
34+
Self::Diff {
35+
a: ::daft::Diffable::diff(&self.a, &other.a),
36+
b: ::daft::Diffable::diff(&self.b, &other.b),
37+
}
38+
}
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
impl ::daft::Diffable for MyStruct {
2+
type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft;
3+
fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> {
4+
::daft::Leaf {
5+
before: self,
6+
after: other,
7+
}
8+
}
9+
}

daft-derive/tests/fixtures/invalid/output/struct-specified-multiple-times.output.rs

Whitespace-only changes.

daft-derive/tests/fixtures/invalid/output/struct-unknown-attribute.output.rs

Whitespace-only changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
impl ::daft::Diffable for MyUnion {
2+
type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft;
3+
fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> {
4+
::daft::Leaf {
5+
before: self,
6+
after: other,
7+
}
8+
}
9+
}
10+
impl ::daft::Diffable for MyUnion2 {
11+
type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft;
12+
fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> {
13+
::daft::Leaf {
14+
before: self,
15+
after: other,
16+
}
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
use daft::Diffable;
2+
3+
struct NonDiffable {}
4+
5+
#[derive(Diffable)]
6+
struct MyStruct {
7+
a: i32,
8+
b: NonDiffable,
9+
}
10+
11+
fn main() {
12+
// MyStruct should still exist, even though the Diffable impl has errors.
13+
let _ = MyStruct { a: 0, b: NonDiffable {} };
14+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
error[E0277]: the trait bound `NonDiffable: Diffable` is not satisfied
2+
--> tests/fixtures/invalid/struct-field-not-diffable.rs:8:5
3+
|
4+
8 | b: NonDiffable,
5+
| ^ the trait `Diffable` is not implemented for `NonDiffable`
6+
|
7+
= help: the following other types implement trait `Diffable`:
8+
&'a T
9+
()
10+
(A, B)
11+
(A, B, C)
12+
(A, B, C, D)
13+
(A, B, C, D, E)
14+
(A, B, C, D, E, F)
15+
(A, B, C, D, E, F, G)
16+
and $N others
17+
18+
error[E0277]: the trait bound `NonDiffable: Diffable` is not satisfied
19+
--> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10
20+
|
21+
5 | #[derive(Diffable)]
22+
| ^^^^^^^^ the trait `Diffable` is not implemented for `NonDiffable`
23+
|
24+
= help: the following other types implement trait `Diffable`:
25+
&'a T
26+
()
27+
(A, B)
28+
(A, B, C)
29+
(A, B, C, D)
30+
(A, B, C, D, E)
31+
(A, B, C, D, E, F)
32+
(A, B, C, D, E, F, G)
33+
and $N others
34+
= note: this error originates in the derive macro `Diffable` (in Nightly builds, run with -Z macro-backtrace for more info)
35+
36+
error[E0277]: the trait bound `NonDiffable: Diffable` is not satisfied in `MyStructDiff<'__daft>`
37+
--> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10
38+
|
39+
5 | #[derive(Diffable)]
40+
| ^^^^^^^^ within `MyStructDiff<'__daft>`, the trait `Diffable` is not implemented for `NonDiffable`
41+
|
42+
= help: the following other types implement trait `Diffable`:
43+
&'a T
44+
()
45+
(A, B)
46+
(A, B, C)
47+
(A, B, C, D)
48+
(A, B, C, D, E)
49+
(A, B, C, D, E, F)
50+
(A, B, C, D, E, F, G)
51+
and $N others
52+
note: required because it appears within the type `MyStructDiff<'__daft>`
53+
--> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10
54+
|
55+
5 | #[derive(Diffable)]
56+
| ^^^^^^^^
57+
note: required by a bound in `daft::Diffable::Diff`
58+
--> $WORKSPACE/daft/src/diffable.rs
59+
|
60+
| / type Diff<'daft>
61+
| | where
62+
| | Self: 'daft;
63+
| |____________________^ required by this bound in `Diffable::Diff`
64+
= note: this error originates in the derive macro `Diffable` (in Nightly builds, run with -Z macro-backtrace for more info)
65+
66+
error[E0277]: the trait bound `NonDiffable: Diffable` is not satisfied in `MyStructDiff<'__daft>`
67+
--> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10
68+
|
69+
5 | #[derive(Diffable)]
70+
| ^^^^^^^^ within `MyStructDiff<'__daft>`, the trait `Diffable` is not implemented for `NonDiffable`
71+
|
72+
= help: the following other types implement trait `Diffable`:
73+
&'a T
74+
()
75+
(A, B)
76+
(A, B, C)
77+
(A, B, C, D)
78+
(A, B, C, D, E)
79+
(A, B, C, D, E, F)
80+
(A, B, C, D, E, F, G)
81+
and $N others
82+
note: required because it appears within the type `MyStructDiff<'__daft>`
83+
--> tests/fixtures/invalid/struct-field-not-diffable.rs:5:10
84+
|
85+
5 | #[derive(Diffable)]
86+
| ^^^^^^^^
87+
= note: the return type of a function must have a statically known size
88+
= note: this error originates in the derive macro `Diffable` (in Nightly builds, run with -Z macro-backtrace for more info)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
impl ::daft::Diffable for Inner {
2+
type Diff<'__daft> = ::daft::Leaf<&'__daft Self> where Self: '__daft;
3+
fn diff<'__daft>(&'__daft self, other: &'__daft Self) -> Self::Diff<'__daft> {
4+
::daft::Leaf {
5+
before: self,
6+
after: other,
7+
}
8+
}
9+
}

0 commit comments

Comments
 (0)