Skip to content

Commit

Permalink
Merge #248
Browse files Browse the repository at this point in the history
248: Use TypePath in ReplaceReceiver r=taiki-e a=taiki-e



Co-authored-by: Taiki Endo <[email protected]>
  • Loading branch information
bors[bot] and taiki-e authored Jun 7, 2020
2 parents 11bf791 + c654ac3 commit 2334cce
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 37 deletions.
51 changes: 34 additions & 17 deletions pin-project-internal/src/pinned_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,29 @@ use crate::utils::{parse_as_empty, prepend_underscore_to_self, ReplaceReceiver,

pub(crate) fn attribute(args: &TokenStream, mut input: ItemImpl) -> TokenStream {
if let Err(e) = parse_as_empty(args).and_then(|()| parse(&mut input)) {
let self_ty = &input.self_ty;
let (impl_generics, _, where_clause) = input.generics.split_for_impl();

let mut tokens = e.to_compile_error();
// A dummy impl of `PinnedDrop`.
// In many cases, `#[pinned_drop] impl` is declared after `#[pin_project]`.
// Therefore, if `pinned_drop` compile fails, you will also get an error
// about `PinnedDrop` not being implemented.
// This can be prevented to some extent by generating a dummy
// `PinnedDrop` implementation.
// We already know that we will get a compile error, so this won't
// accidentally compile successfully.
tokens.extend(quote! {
impl #impl_generics ::pin_project::__private::PinnedDrop for #self_ty #where_clause {
unsafe fn drop(self: ::pin_project::__private::Pin<&mut Self>) {}
}
});
if let Type::Path(self_ty) = &*input.self_ty {
let (impl_generics, _, where_clause) = input.generics.split_for_impl();

// A dummy impl of `PinnedDrop`.
// In many cases, `#[pinned_drop] impl` is declared after `#[pin_project]`.
// Therefore, if `pinned_drop` compile fails, you will also get an error
// about `PinnedDrop` not being implemented.
// This can be prevented to some extent by generating a dummy
// `PinnedDrop` implementation.
// We already know that we will get a compile error, so this won't
// accidentally compile successfully.
//
// However, if `input.self_ty` is not Type::Path, there is a high possibility that
// the type does not exist, so do not generate a dummy impl.
tokens.extend(quote! {
impl #impl_generics ::pin_project::__private::PinnedDrop for #self_ty
#where_clause
{
unsafe fn drop(self: ::pin_project::__private::Pin<&mut Self>) {}
}
});
}
tokens
} else {
input.into_token_stream()
Expand Down Expand Up @@ -116,6 +122,16 @@ fn parse(item: &mut ItemImpl) -> Result<()> {
return Err(error!(item, "not all trait items implemented, missing: `drop`"));
}

match &*item.self_ty {
Type::Path(_) => {}
ty => {
return Err(error!(
ty,
"implementing the trait `PinnedDrop` on this type is unsupported"
));
}
}

item.items
.iter()
.enumerate()
Expand Down Expand Up @@ -171,7 +187,8 @@ fn expand_item(item: &mut ItemImpl) {
prepend_underscore_to_self(&mut ident.ident);
}
}
let mut visitor = ReplaceReceiver(&item.self_ty);
let self_ty = if let Type::Path(ty) = &*item.self_ty { ty } else { unreachable!() };
let mut visitor = ReplaceReceiver(self_ty);
visitor.visit_signature_mut(&mut drop_inner.sig);
visitor.visit_block_mut(&mut drop_inner.block);

Expand Down
34 changes: 14 additions & 20 deletions pin-project-internal/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,10 +205,10 @@ impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> {
// Replace `self`/`Self` with `__self`/`self_ty`.
// Based on https://github.com/dtolnay/async-trait/blob/0.1.33/src/receiver.rs

pub(crate) struct ReplaceReceiver<'a>(pub(crate) &'a Type);
pub(crate) struct ReplaceReceiver<'a>(pub(crate) &'a TypePath);

impl ReplaceReceiver<'_> {
fn self_ty(&self, span: Span) -> Type {
fn self_ty(&self, span: Span) -> TypePath {
respan(self.0, span)
}

Expand All @@ -229,7 +229,7 @@ impl ReplaceReceiver<'_> {

*qself = Some(QSelf {
lt_token: token::Lt::default(),
ty: Box::new(self.self_ty(first.ident.span())),
ty: Box::new(self.self_ty(first.ident.span()).into()),
position: 0,
as_token: None,
gt_token: token::Gt::default(),
Expand All @@ -251,24 +251,18 @@ impl ReplaceReceiver<'_> {
return;
}

if let Type::Path(self_ty) = self.self_ty(first.ident.span()) {
let variant = mem::replace(path, self_ty.path);
for segment in &mut path.segments {
if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
bracketed.colon2_token = Some(token::Colon2::default());
}
let self_ty = self.self_ty(first.ident.span());
let variant = mem::replace(path, self_ty.path);
for segment in &mut path.segments {
if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() {
bracketed.colon2_token = Some(token::Colon2::default());
}
}
if variant.segments.len() > 1 {
path.segments.push_punct(token::Colon2::default());
path.segments.extend(variant.segments.into_pairs().skip(1));
}
} else {
let span = path.segments[0].ident.span();
let msg = "Self type of this impl is unsupported in expression position";
let error = Error::new(span, msg).to_compile_error();
*path = parse_quote!(::pin_project::__private::PhantomData::<#error>);
}
if variant.segments.len() > 1 {
path.segments.push_punct(token::Colon2::default());
path.segments.extend(variant.segments.into_pairs().skip(1));
}
}

Expand Down Expand Up @@ -324,7 +318,7 @@ impl VisitMut for ReplaceReceiver<'_> {
fn visit_type_mut(&mut self, ty: &mut Type) {
if let Type::Path(node) = ty {
if node.qself.is_none() && node.path.is_ident("Self") {
*ty = self.self_ty(node.path.segments[0].ident.span());
*ty = self.self_ty(node.path.segments[0].ident.span()).into();
} else {
self.visit_type_path_mut(node);
}
Expand Down
22 changes: 22 additions & 0 deletions tests/ui/pinned_drop/invalid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,4 +204,26 @@ mod method {
}
}

mod self_ty {
use pin_project::pinned_drop;

#[pinned_drop]
impl PinnedDrop for () {
//~^ ERROR implementing the trait `PinnedDrop` on this type is unsupported
fn drop(self: Pin<&mut Self>) {}
}

#[pinned_drop]
impl PinnedDrop for &mut A {
//~^ ERROR implementing the trait `PinnedDrop` on this type is unsupported
fn drop(self: Pin<&mut Self>) {}
}

#[pinned_drop]
impl PinnedDrop for [A] {
//~^ ERROR implementing the trait `PinnedDrop` on this type is unsupported
fn drop(self: Pin<&mut Self>) {}
}
}

fn main() {}
18 changes: 18 additions & 0 deletions tests/ui/pinned_drop/invalid.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -123,3 +123,21 @@ error: method `pinned_drop` is not a member of trait `PinnedDrop
|
203 | fn pinned_drop(&mut self) {} //~ ERROR method `pinned_drop` is not a member of trait `PinnedDrop
| ^^^^^^^^^^^

error: implementing the trait `PinnedDrop` on this type is unsupported
--> $DIR/invalid.rs:211:25
|
211 | impl PinnedDrop for () {
| ^^

error: implementing the trait `PinnedDrop` on this type is unsupported
--> $DIR/invalid.rs:217:25
|
217 | impl PinnedDrop for &mut A {
| ^^^^^^

error: implementing the trait `PinnedDrop` on this type is unsupported
--> $DIR/invalid.rs:223:25
|
223 | impl PinnedDrop for [A] {
| ^^^

0 comments on commit 2334cce

Please sign in to comment.