Skip to content

Commit

Permalink
Ensure PhantomData type bounds are ignored.
Browse files Browse the repository at this point in the history
Added tests to catch these cases as well.

Issue mcarton#25
  • Loading branch information
azriel91 committed Oct 19, 2018
1 parent 05f6341 commit 723429a
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 6 deletions.
24 changes: 18 additions & 6 deletions src/bound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -112,12 +112,10 @@ where
}
impl<'ast> visit::Visit<'ast> for FindTyParams {
fn visit_path(&mut self, path: &'ast syn::Path) {
if let Some(syn::punctuated::Pair::Punctuated(seg, _)) = path.segments.last() {
if seg.ident == "PhantomData" {
// Hardcoded exception, because `PhantomData<T>` implements
// most traits whether or not `T` implements it.
return;
}
if is_phantom_data(path) {
// Hardcoded exception, because `PhantomData<T>` implements
// most traits whether or not `T` implements it.
return;
}
if path.leading_colon.is_none() && path.segments.len() == 1 {
let id = path.segments[0].ident.clone();
Expand All @@ -138,6 +136,13 @@ where
.body
.all_fields()
.into_iter()
.filter(|field| {
if let syn::Type::Path(syn::TypePath { ref path, .. }) = field.ty {
!is_phantom_data(path)
} else {
true
}
})
.filter(|field| filter(&field.attrs))
.map(|field| &field.ty);

Expand All @@ -164,3 +169,10 @@ where
}
cloned
}

fn is_phantom_data(path: &syn::Path) -> bool {
match path.segments.last() {
Some(syn::punctuated::Pair::End(seg)) if seg.ident == "PhantomData" => true,
_ => false,
}
}
26 changes: 26 additions & 0 deletions tests/derive-clone-generics.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#[macro_use]
extern crate derivative;

use std::marker::PhantomData;

struct NoClone;

#[derive(Derivative)]
#[derivative(Clone, PartialEq)]
struct PhantomField<T> {
foo: PhantomData<T>,
}

#[derive(Derivative)]
#[derivative(Clone, PartialEq)]
struct PhantomTuple<T> {
foo: PhantomData<(T,)>,
}

#[test]
fn main() {
let phantom_field = PhantomField::<NoClone> { foo: Default::default() };
let phantom_tuple = PhantomTuple::<NoClone> { foo: Default::default() };
assert!(phantom_field == phantom_field.clone());
assert!(phantom_tuple == phantom_tuple.clone());
}
16 changes: 16 additions & 0 deletions tests/derive-debug-generics.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#[macro_use]
extern crate derivative;

use std::marker::PhantomData;

#[derive(Derivative)]
#[derivative(Debug)]
struct Foo<T, U> {
Expand Down Expand Up @@ -58,6 +60,18 @@ impl<T: std::fmt::Debug> ToDebug for T {
}
}

#[derive(Derivative)]
#[derivative(Debug)]
struct PhantomField<T> {
foo: PhantomData<T>,
}

#[derive(Derivative)]
#[derivative(Debug)]
struct PhantomTuple<T> {
foo: PhantomData<(T,)>,
}

#[test]
fn main() {
assert_eq!(Foo { foo: 42, bar: NoDebug }.to_show(), "Foo { foo: 42 }".to_string());
Expand All @@ -69,4 +83,6 @@ fn main() {
assert_eq!(F(NoDebug).to_show(), "F".to_string());
assert_eq!(G(42, NoDebug).to_show(), "G(42)".to_string());
assert_eq!(J(NoDebug).to_show(), "J".to_string());
assert_eq!(&format!("{:?}", PhantomField::<NoDebug> { foo: Default::default() }), "PhantomField { foo: PhantomData }");
assert_eq!(&format!("{:?}", PhantomTuple::<NoDebug> { foo: Default::default() }), "PhantomTuple { foo: PhantomData }");
}

0 comments on commit 723429a

Please sign in to comment.