Skip to content

Commit

Permalink
WIP handling QSelf
Browse files Browse the repository at this point in the history
QSelf is the qualified self, used in expressions like
<Self as Foo>::Bar.  This commit only handles the most basic usage,
where Foo is the trait or struct being defined.
  • Loading branch information
asomers committed Jul 5, 2019
1 parent 116e5a2 commit 7aa4d9e
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 5 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Changed
### Fixed

- Fixed an issue with using associated types in generic parameter bounds
([116e5a2](https://github.com/asomers/mockall/commit/116e5a293254d6ae0348f73370bbf8623521a4c2))

- Fixed mocking methods with mutable arguments
([8058701](https://github.com/asomers/mockall/commit/8058701f7e195636fd1759f10187fa431b7aa61c))

Expand Down
61 changes: 56 additions & 5 deletions mockall_derive/src/automock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,6 @@ impl Attrs {
self.substitute_type(&mut binding.ty);
},
_ => {
dbg!(&arg);
compile_error(arg.span(),
"Mockall does not yet support this argument type in this position");
}
Expand Down Expand Up @@ -106,10 +105,28 @@ impl Attrs {
}
}
syn::Type::Path(path) => {
if let Some(ref _qself) = path.qself {
compile_error(path.span(), "QSelf is TODO");
}
if let Some(newty) = self.get_path(&path.path) {
if let Some(ref qself) = path.qself {
let qp = if let syn::Type::Path(p) = qself.ty.as_ref() {
&p.path
} else {
panic!("QSelf's type isn't a path?")
};
let qident = &qp.segments.first().unwrap().value().ident;
if qself.position != 1
|| qp.segments.len() != 1
|| path.path.segments.len() != 2
|| qident != "Self" {
compile_error(path.span(),
"QSelf is a work in progress");
}
let last_seg = path.path.segments.pop().unwrap();
let to_sub = &last_seg.value().ident;
let _ident = path.path.segments.pop().unwrap().value();
// TODO: check that the ident is the name of this type
let new_type = self.attrs.get(to_sub)
.expect("Unknown type substitution for QSelf");
*ty = new_type.clone();
} else if let Some(newty) = self.get_path(&path.path) {
*ty = newty;
} else {
for seg in path.path.segments.iter_mut() {
Expand Down Expand Up @@ -681,23 +698,31 @@ mod t {
let () = ();
}
}
::mockall::expectation! {
pub fn baz< >(&self) -> Box<SomeTrait<u32> > {
let () = ();
}
}
}
struct MockA_A {
foo: __mock_A_A::foo::Expectations ,
bar: __mock_A_A::bar::Expectations ,
baz: __mock_A_A::baz::Expectations ,
}
impl ::std::default::Default for MockA_A {
fn default() -> Self {
Self {
foo: __mock_A_A::foo::Expectations::default(),
bar: __mock_A_A::bar::Expectations::default(),
baz: __mock_A_A::baz::Expectations::default(),
}
}
}
impl MockA_A {
fn checkpoint(&mut self) {
{ self.foo.checkpoint(); }
{ self.bar.checkpoint(); }
{ self.baz.checkpoint(); }
}
}
impl MockA {
Expand All @@ -716,6 +741,9 @@ mod t {
fn bar(&self) -> Box<dyn SomeTrait<u32> > {
self.A_expectations.bar.call()
}
fn baz(&self) -> Box<dyn SomeTrait<u32> > {
self.A_expectations.baz.call()
}
}
impl MockA {
pub fn expect_foo(&mut self)
Expand All @@ -728,11 +756,17 @@ mod t {
{
self.A_expectations.bar.expect()
}
pub fn expect_baz(&mut self)
-> &mut __mock_A_A::baz::Expectation
{
self.A_expectations.baz.expect()
}
}"#, r#"
pub trait A {
type T: Clone + 'static;
fn foo(&self, x: Self::T) -> Self::T;
fn bar(&self) -> Box<dyn SomeTrait<Self::T>>;
fn baz(&self) -> Box<dyn SomeTrait<<Self as A>::T>>;
}"#);
}

Expand Down Expand Up @@ -1706,6 +1740,23 @@ mod t {
check("", &desired, &code);
}

fn check_substitute_type(attrs: TokenStream, input: TokenStream,
expected: TokenStream)
{
let _self: super::Attrs = syn::parse2(attrs).unwrap();
let mut in_ty: syn::Type = syn::parse2(input).unwrap();
let expect_ty: syn::Type = syn::parse2(expected).unwrap();
_self.substitute_type(&mut in_ty);
assert_eq!(in_ty, expect_ty);
}

#[test]
fn qself() {
check_substitute_type(quote!(type T = u32;),
quote!(<Self as Foo>::T),
quote!(u32));
}

#[test]
fn pub_trait() {
check("",
Expand Down

0 comments on commit 7aa4d9e

Please sign in to comment.