Skip to content

Commit

Permalink
Merge #217
Browse files Browse the repository at this point in the history
217: Support overlapping lifetime names in HRTB r=taiki-e a=taiki-e



Co-authored-by: Taiki Endo <te316e89@gmail.com>
  • Loading branch information
bors[bot] and taiki-e authored May 8, 2020
2 parents fda7d74 + b467da8 commit 22d32e9
Show file tree
Hide file tree
Showing 20 changed files with 98 additions and 80 deletions.
16 changes: 9 additions & 7 deletions pin-project-internal/src/pin_project/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub(super) fn parse_derive(input: TokenStream) -> Result<TokenStream> {
// * https://github.com/taiki-e/pin-project/pull/70
#[doc(hidden)]
#[allow(non_upper_case_globals)]
#[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
const #dummy_const: () = {
#scoped_items
#unpin_impl
Expand Down Expand Up @@ -291,11 +292,11 @@ impl<'a> Context<'a> {

let ty_generics = generics.split_for_impl().1;
let self_ty = syn::parse_quote!(#ident #ty_generics);
let mut visitor = ReplaceReceiver::new(&self_ty);
let mut visitor = ReplaceReceiver(&self_ty);
visitor.visit_where_clause_mut(generics.make_where_clause());

let mut lifetime_name = String::from("'pin");
determine_lifetime_name(&mut lifetime_name, &generics.params);
determine_lifetime_name(&mut lifetime_name, generics);
let lifetime = Lifetime::new(&lifetime_name, Span::call_site());

let mut proj_generics = generics.clone();
Expand Down Expand Up @@ -377,16 +378,19 @@ impl<'a> Context<'a> {
#[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document.
#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
#[allow(dead_code)] // This lint warns unused fields/variants.
#[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
#vis struct #proj_ident #proj_generics #where_clause_fields
#[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document.
#[allow(dead_code)] // This lint warns unused fields/variants.
#[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
#vis struct #proj_ref_ident #proj_generics #where_clause_ref_fields
};
if self.replace.is_some() {
// Currently, using quote_spanned here does not seem to have any effect on the diagnostics.
proj_items.extend(quote! {
#[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document.
#[allow(dead_code)] // This lint warns unused fields/variants.
#[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
#vis struct #proj_own_ident #orig_generics #where_clause_own_fields
});
}
Expand Down Expand Up @@ -458,11 +462,13 @@ impl<'a> Context<'a> {
#[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document.
#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`.
#[allow(dead_code)] // This lint warns unused fields/variants.
#[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
#vis enum #proj_ident #proj_generics #where_clause {
#proj_variants
}
#[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document.
#[allow(dead_code)] // This lint warns unused fields/variants.
#[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
#vis enum #proj_ref_ident #proj_generics #where_clause {
#proj_ref_variants
}
Expand All @@ -472,6 +478,7 @@ impl<'a> Context<'a> {
proj_items.extend(quote! {
#[doc(hidden)] // TODO: If the user gave it a name, it should appear in the document.
#[allow(dead_code)] // This lint warns unused fields/variants.
#[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
#vis enum #proj_own_ident #orig_generics #orig_where_clause {
#proj_own_variants
}
Expand Down Expand Up @@ -715,7 +722,6 @@ impl<'a> Context<'a> {
let ty_generics = self.orig.generics.split_for_impl().1;

quote! {
#[allow(single_use_lifetimes)]
impl #impl_generics ::pin_project::__reexport::marker::Unpin for #orig_ident #ty_generics #where_clause {}
}
} else {
Expand Down Expand Up @@ -801,7 +807,6 @@ impl<'a> Context<'a> {
// For interoperability with `forbid(unsafe_code)`, `unsafe` token should be call-site span.
let unsafety = token::Unsafe::default();
quote_spanned! { pinned_drop =>
#[allow(single_use_lifetimes)]
impl #impl_generics ::pin_project::__reexport::ops::Drop for #ident #ty_generics #where_clause {
fn drop(&mut self) {
// Safety - we're in 'drop', so we know that 'self' will
Expand Down Expand Up @@ -844,7 +849,6 @@ impl<'a> Context<'a> {
trait #trait_ident {}
#[allow(clippy::drop_bounds)]
impl<T: ::pin_project::__reexport::ops::Drop> #trait_ident for T {}
#[allow(single_use_lifetimes)]
impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {}

// A dummy impl of `PinnedDrop`, to ensure that the user cannot implement it.
Expand All @@ -857,7 +861,6 @@ impl<'a> Context<'a> {
// impls, we emit one ourselves. If the user ends up writing a `PinnedDrop` impl,
// they'll get a "conflicting implementations of trait" error when coherence
// checks are run.
#[allow(single_use_lifetimes)]
impl #impl_generics ::pin_project::__private::PinnedDrop for #ident #ty_generics #where_clause {
unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {}
}
Expand Down Expand Up @@ -1000,7 +1003,6 @@ impl<'a> Context<'a> {
let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl();
let ident = self.orig.ident;
Ok(quote! {
#[allow(single_use_lifetimes)]
#[deny(safe_packed_borrows)]
fn __assert_not_repr_packed #impl_generics (val: &#ident #ty_generics) #where_clause {
#(#field_refs)*
Expand Down
6 changes: 3 additions & 3 deletions pin-project-internal/src/pinned_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,8 @@ fn expand_item(item: &mut ItemImpl) {
prepend_underscore_to_self(&mut ident.ident);
}
}
// This lint does not warn the receiver.
drop_inner.attrs.push(syn::parse_quote!(#[allow(clippy::needless_pass_by_value)]));
let mut visitor = ReplaceReceiver::new(&item.self_ty);

let mut visitor = ReplaceReceiver(&item.self_ty);
visitor.visit_signature_mut(&mut drop_inner.sig);
visitor.visit_block_mut(&mut drop_inner.block);

Expand All @@ -182,6 +181,7 @@ fn expand_item(item: &mut ItemImpl) {
}

method.block.stmts = syn::parse_quote! {
#[allow(clippy::needless_pass_by_value)] // This lint does not warn the receiver.
#drop_inner
__drop_inner(self);
};
Expand Down
4 changes: 2 additions & 2 deletions pin-project-internal/src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,11 @@ fn replace_item_impl(item: &mut ItemImpl, mutability: Mutability) {
replace_ident(ident, mutability);

let mut lifetime_name = String::from("'pin");
determine_lifetime_name(&mut lifetime_name, &item.generics.params);
determine_lifetime_name(&mut lifetime_name, &mut item.generics);
item.items
.iter_mut()
.filter_map(|i| if let ImplItem::Method(i) = i { Some(i) } else { None })
.for_each(|item| determine_lifetime_name(&mut lifetime_name, &item.sig.generics.params));
.for_each(|item| determine_lifetime_name(&mut lifetime_name, &mut item.sig.generics));
let lifetime = Lifetime::new(&lifetime_name, Span::call_site());

insert_lifetime(&mut item.generics, lifetime.clone());
Expand Down
46 changes: 20 additions & 26 deletions pin-project-internal/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,21 @@ pub(crate) fn proj_ident(ident: &Ident, mutability: Mutability) -> Ident {
}

/// Determines the lifetime names. Ensure it doesn't overlap with any existing lifetime names.
pub(crate) fn determine_lifetime_name(
lifetime_name: &mut String,
generics: &Punctuated<GenericParam, token::Comma>,
) {
let existing_lifetimes: Vec<String> = generics
.iter()
.filter_map(|param| {
if let GenericParam::Lifetime(LifetimeDef { lifetime, .. }) = param {
Some(lifetime.to_string())
} else {
None
}
})
.collect();
while existing_lifetimes.iter().any(|name| name.starts_with(&**lifetime_name)) {
pub(crate) fn determine_lifetime_name(lifetime_name: &mut String, generics: &mut Generics) {
struct CollectLifetimes(Vec<String>);

impl VisitMut for CollectLifetimes {
fn visit_lifetime_def_mut(&mut self, node: &mut LifetimeDef) {
self.0.push(node.lifetime.to_string())
}
}

debug_assert!(lifetime_name.starts_with('\''));

let mut lifetimes = CollectLifetimes(Vec::new());
lifetimes.visit_generics_mut(generics);

while lifetimes.0.iter().any(|name| name.starts_with(&**lifetime_name)) {
lifetime_name.push('_');
}
}
Expand Down Expand Up @@ -174,15 +174,9 @@ 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.30/src/receiver.rs

pub(crate) struct ReplaceReceiver<'a> {
self_ty: &'a Type,
}

impl<'a> ReplaceReceiver<'a> {
pub(crate) fn new(self_ty: &'a Type) -> Self {
Self { self_ty }
}
pub(crate) struct ReplaceReceiver<'a>(pub(crate) &'a Type);

impl ReplaceReceiver<'_> {
fn self_to_qself(&self, qself: &mut Option<QSelf>, path: &mut Path) {
if path.leading_colon.is_some() {
return;
Expand All @@ -200,7 +194,7 @@ impl<'a> ReplaceReceiver<'a> {

*qself = Some(QSelf {
lt_token: token::Lt::default(),
ty: Box::new(self.self_ty.clone()),
ty: Box::new(self.0.clone()),
position: 0,
as_token: None,
gt_token: token::Gt::default(),
Expand All @@ -225,7 +219,7 @@ impl<'a> ReplaceReceiver<'a> {
return;
}

if let Type::Path(self_ty) = &self.self_ty {
if let Type::Path(self_ty) = &self.0 {
let variant = mem::replace(path, self_ty.path.clone());
for segment in &mut path.segments {
if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments {
Expand All @@ -252,7 +246,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.clone();
*ty = self.0.clone();
} else {
self.visit_type_path_mut(node);
}
Expand Down
5 changes: 3 additions & 2 deletions tests/expand/tests/expand/default-enum.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ enum Enum<T, U> {
#[doc(hidden)]
#[allow(clippy::mut_mut)]
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
enum __EnumProjection<'pin, T, U>
where
Enum<T, U>: 'pin,
Expand All @@ -28,6 +29,7 @@ where
}
#[doc(hidden)]
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
enum __EnumProjectionRef<'pin, T, U>
where
Enum<T, U>: 'pin,
Expand All @@ -41,6 +43,7 @@ where
}
#[doc(hidden)]
#[allow(non_upper_case_globals)]
#[allow(single_use_lifetimes)]
const __SCOPE_Enum: () = {
impl<T, U> Enum<T, U> {
fn project<'pin>(
Expand Down Expand Up @@ -90,9 +93,7 @@ const __SCOPE_Enum: () = {
trait EnumMustNotImplDrop {}
#[allow(clippy::drop_bounds)]
impl<T: ::pin_project::__reexport::ops::Drop> EnumMustNotImplDrop for T {}
#[allow(single_use_lifetimes)]
impl<T, U> EnumMustNotImplDrop for Enum<T, U> {}
#[allow(single_use_lifetimes)]
impl<T, U> ::pin_project::__private::PinnedDrop for Enum<T, U> {
unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {}
}
Expand Down
6 changes: 3 additions & 3 deletions tests/expand/tests/expand/default-struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ struct Struct<T, U> {
#[doc(hidden)]
#[allow(clippy::mut_mut)]
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
struct __StructProjection<'pin, T, U>
where
Struct<T, U>: 'pin,
Expand All @@ -17,6 +18,7 @@ where
}
#[doc(hidden)]
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
struct __StructProjectionRef<'pin, T, U>
where
Struct<T, U>: 'pin,
Expand All @@ -26,6 +28,7 @@ where
}
#[doc(hidden)]
#[allow(non_upper_case_globals)]
#[allow(single_use_lifetimes)]
const __SCOPE_Struct: () = {
impl<T, U> Struct<T, U> {
fn project<'pin>(
Expand Down Expand Up @@ -62,13 +65,10 @@ const __SCOPE_Struct: () = {
trait StructMustNotImplDrop {}
#[allow(clippy::drop_bounds)]
impl<T: ::pin_project::__reexport::ops::Drop> StructMustNotImplDrop for T {}
#[allow(single_use_lifetimes)]
impl<T, U> StructMustNotImplDrop for Struct<T, U> {}
#[allow(single_use_lifetimes)]
impl<T, U> ::pin_project::__private::PinnedDrop for Struct<T, U> {
unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {}
}
#[allow(single_use_lifetimes)]
#[deny(safe_packed_borrows)]
fn __assert_not_repr_packed<T, U>(val: &Struct<T, U>) {
&val.pinned;
Expand Down
6 changes: 3 additions & 3 deletions tests/expand/tests/expand/default-tuple_struct.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ struct TupleStruct<T, U>(#[pin] T, U);
#[doc(hidden)]
#[allow(clippy::mut_mut)]
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
struct __TupleStructProjection<'pin, T, U>(
::pin_project::__reexport::pin::Pin<&'pin mut (T)>,
&'pin mut (U),
Expand All @@ -12,6 +13,7 @@ where
TupleStruct<T, U>: 'pin;
#[doc(hidden)]
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
struct __TupleStructProjectionRef<'pin, T, U>(
::pin_project::__reexport::pin::Pin<&'pin (T)>,
&'pin (U),
Expand All @@ -20,6 +22,7 @@ where
TupleStruct<T, U>: 'pin;
#[doc(hidden)]
#[allow(non_upper_case_globals)]
#[allow(single_use_lifetimes)]
const __SCOPE_TupleStruct: () = {
impl<T, U> TupleStruct<T, U> {
fn project<'pin>(
Expand Down Expand Up @@ -53,13 +56,10 @@ const __SCOPE_TupleStruct: () = {
trait TupleStructMustNotImplDrop {}
#[allow(clippy::drop_bounds)]
impl<T: ::pin_project::__reexport::ops::Drop> TupleStructMustNotImplDrop for T {}
#[allow(single_use_lifetimes)]
impl<T, U> TupleStructMustNotImplDrop for TupleStruct<T, U> {}
#[allow(single_use_lifetimes)]
impl<T, U> ::pin_project::__private::PinnedDrop for TupleStruct<T, U> {
unsafe fn drop(self: ::pin_project::__reexport::pin::Pin<&mut Self>) {}
}
#[allow(single_use_lifetimes)]
#[deny(safe_packed_borrows)]
fn __assert_not_repr_packed<T, U>(val: &TupleStruct<T, U>) {
&val.0;
Expand Down
4 changes: 3 additions & 1 deletion tests/expand/tests/expand/pinned_drop-enum.expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ enum Enum<T, U> {
#[doc(hidden)]
#[allow(clippy::mut_mut)]
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
enum __EnumProjection<'pin, T, U>
where
Enum<T, U>: 'pin,
Expand All @@ -29,6 +30,7 @@ where
}
#[doc(hidden)]
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
enum __EnumProjectionRef<'pin, T, U>
where
Enum<T, U>: 'pin,
Expand All @@ -42,6 +44,7 @@ where
}
#[doc(hidden)]
#[allow(non_upper_case_globals)]
#[allow(single_use_lifetimes)]
const __SCOPE_Enum: () = {
impl<T, U> Enum<T, U> {
fn project<'pin>(
Expand Down Expand Up @@ -88,7 +91,6 @@ const __SCOPE_Enum: () = {
__Enum<'pin, T, U>: ::pin_project::__reexport::marker::Unpin
{
}
#[allow(single_use_lifetimes)]
impl<T, U> ::pin_project::__reexport::ops::Drop for Enum<T, U> {
fn drop(&mut self) {
let pinned_self = unsafe { ::pin_project::__reexport::pin::Pin::new_unchecked(self) };
Expand Down
Loading

0 comments on commit 22d32e9

Please sign in to comment.