diff --git a/pin-project-internal/src/pin_project/derive.rs b/pin-project-internal/src/pin_project/derive.rs index 090090a0..aabbf0ec 100644 --- a/pin-project-internal/src/pin_project/derive.rs +++ b/pin-project-internal/src/pin_project/derive.rs @@ -1,11 +1,8 @@ -use std::mem; - use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, quote_spanned}; use syn::{ parse::{Parse, ParseBuffer, ParseStream}, - punctuated::Punctuated, - visit_mut::{self, VisitMut}, + visit_mut::VisitMut, *, }; @@ -224,7 +221,7 @@ impl Context { { let ty_generics = generics.split_for_impl().1; let self_ty = syn::parse_quote!(#ident #ty_generics); - let mut visitor = ReplaceSelf::new(&self_ty); + let mut visitor = ReplaceReceiver::new(&self_ty); visitor.visit_where_clause_mut(generics.make_where_clause()); } @@ -799,66 +796,3 @@ impl Context { }) } } - -// Replace `Self` with `self_ty`. -// Based on https://github.com/dtolnay/async-trait/blob/1.0.15/src/receiver.rs - -struct ReplaceSelf<'a> { - self_ty: &'a Type, -} - -impl<'a> ReplaceSelf<'a> { - fn new(self_ty: &'a Type) -> Self { - Self { self_ty } - } - - fn self_to_qself(&mut self, qself: &mut Option, path: &mut Path) { - if path.leading_colon.is_some() { - return; - } - - let first = &path.segments[0]; - if first.ident != "Self" || !first.arguments.is_empty() { - return; - } - - match path.segments.pairs().next().unwrap().punct() { - Some(colon) => path.leading_colon = Some(**colon), - None => return, - } - - *qself = Some(QSelf { - lt_token: token::Lt::default(), - ty: Box::new(self.self_ty.clone()), - position: 0, - as_token: None, - gt_token: token::Gt::default(), - }); - - let segments = mem::replace(&mut path.segments, Punctuated::new()); - path.segments = segments.into_pairs().skip(1).collect(); - } -} - -impl VisitMut for ReplaceSelf<'_> { - // `Self` -> `Receiver` - 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(); - } else { - self.visit_type_path_mut(node); - } - } else { - visit_mut::visit_type_mut(self, ty); - } - } - - // `Self::Assoc` -> `::Assoc` - fn visit_type_path_mut(&mut self, ty: &mut TypePath) { - if ty.qself.is_none() { - self.self_to_qself(&mut ty.qself, &mut ty.path); - } - visit_mut::visit_type_path_mut(self, ty); - } -} diff --git a/pin-project-internal/src/pinned_drop.rs b/pin-project-internal/src/pinned_drop.rs index 39c5bed5..11cc37dc 100644 --- a/pin-project-internal/src/pinned_drop.rs +++ b/pin-project-internal/src/pinned_drop.rs @@ -1,15 +1,10 @@ -use std::mem; - -use proc_macro2::{Group, Span, TokenStream, TokenTree}; +use proc_macro2::{Span, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; -use syn::{ - punctuated::Punctuated, - spanned::Spanned, - visit_mut::{self, VisitMut}, - *, -}; +use syn::{spanned::Spanned, visit_mut::VisitMut, *}; -use crate::utils::{parse_as_empty, CURRENT_PRIVATE_MODULE}; +use crate::utils::{ + parse_as_empty, prepend_underscore_to_self, ReplaceReceiver, CURRENT_PRIVATE_MODULE, +}; pub(crate) fn attribute(args: &TokenStream, mut input: ItemImpl) -> TokenStream { if let Err(e) = parse_as_empty(args).and_then(|()| parse(&mut input)) { @@ -202,121 +197,3 @@ fn expand_item(item: &mut ItemImpl) { __drop_inner(self); }}; } - -// Replace `self` and `Self` with `__self` and `self_ty`. -// Based on https://github.com/dtolnay/async-trait/blob/1.0.15/src/receiver.rs - -struct ReplaceReceiver<'a> { - self_ty: &'a Type, -} - -impl<'a> ReplaceReceiver<'a> { - fn new(self_ty: &'a Type) -> Self { - Self { self_ty } - } - - fn self_to_qself(&mut self, qself: &mut Option, path: &mut Path) { - if path.leading_colon.is_some() { - return; - } - - let first = &path.segments[0]; - if first.ident != "Self" || !first.arguments.is_empty() { - return; - } - - match path.segments.pairs().next().unwrap().punct() { - Some(colon) => path.leading_colon = Some(**colon), - None => return, - } - - *qself = Some(QSelf { - lt_token: token::Lt::default(), - ty: Box::new(self.self_ty.clone()), - position: 0, - as_token: None, - gt_token: token::Gt::default(), - }); - - let segments = mem::replace(&mut path.segments, Punctuated::new()); - path.segments = segments.into_pairs().skip(1).collect(); - } -} - -impl VisitMut for ReplaceReceiver<'_> { - // `Self` -> `Receiver` - 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(); - } else { - self.visit_type_path_mut(node); - } - } else { - visit_mut::visit_type_mut(self, ty); - } - } - - // `Self::Assoc` -> `::Assoc` - fn visit_type_path_mut(&mut self, ty: &mut TypePath) { - if ty.qself.is_none() { - self.self_to_qself(&mut ty.qself, &mut ty.path); - } - visit_mut::visit_type_path_mut(self, ty); - } - - // `Self::method` -> `::method` - fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) { - if expr.qself.is_none() { - prepend_underscore_to_self(&mut expr.path.segments[0].ident); - self.self_to_qself(&mut expr.qself, &mut expr.path); - } - visit_mut::visit_expr_path_mut(self, expr); - } - - fn visit_macro_mut(&mut self, node: &mut Macro) { - // We can't tell in general whether `self` inside a macro invocation - // refers to the self in the argument list or a different self - // introduced within the macro. Heuristic: if the macro input contains - // `fn`, then `self` is more likely to refer to something other than the - // outer function's self argument. - if !contains_fn(node.tokens.clone()) { - node.tokens = fold_token_stream(node.tokens.clone()); - } - } - - fn visit_item_mut(&mut self, _: &mut Item) { - // Do not recurse into nested items. - } -} - -fn contains_fn(tokens: TokenStream) -> bool { - tokens.into_iter().any(|tt| match tt { - TokenTree::Ident(ident) => ident == "fn", - TokenTree::Group(group) => contains_fn(group.stream()), - _ => false, - }) -} - -fn fold_token_stream(tokens: TokenStream) -> TokenStream { - tokens - .into_iter() - .map(|tt| match tt { - TokenTree::Ident(mut ident) => { - prepend_underscore_to_self(&mut ident); - TokenTree::Ident(ident) - } - TokenTree::Group(group) => { - let content = fold_token_stream(group.stream()); - TokenTree::Group(Group::new(group.delimiter(), content)) - } - other => other, - }) - .collect() -} - -fn prepend_underscore_to_self(ident: &mut Ident) { - if ident == "self" { - *ident = Ident::new("__self", ident.span()); - } -} diff --git a/pin-project-internal/src/utils.rs b/pin-project-internal/src/utils.rs index 24d5fd90..aca2c9f3 100644 --- a/pin-project-internal/src/utils.rs +++ b/pin-project-internal/src/utils.rs @@ -1,9 +1,12 @@ -use proc_macro2::TokenStream; +use std::mem; + +use proc_macro2::{Group, TokenStream, TokenTree}; use quote::{format_ident, quote_spanned}; use syn::{ parse::{ParseBuffer, ParseStream}, punctuated::Punctuated, token::{self, Comma}, + visit_mut::{self, VisitMut}, *, }; @@ -155,3 +158,151 @@ impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> { Ok(content) } } + +// Replace `self`/`Self` with `__self`/`self_ty`. +// Based on https://github.com/dtolnay/async-trait/blob/0.1.22/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 } + } + + fn self_to_qself(&mut self, qself: &mut Option, path: &mut Path) { + if path.leading_colon.is_some() { + return; + } + + let first = &path.segments[0]; + if first.ident != "Self" || !first.arguments.is_empty() { + return; + } + + if path.segments.len() == 1 { + self.self_to_expr_path(path); + return; + } + + *qself = Some(QSelf { + lt_token: token::Lt::default(), + ty: Box::new(self.self_ty.clone()), + position: 0, + as_token: None, + gt_token: token::Gt::default(), + }); + + match path.segments.pairs().next().unwrap().punct() { + Some(&&colon) => path.leading_colon = Some(colon), + None => return, + } + + let segments = mem::replace(&mut path.segments, Punctuated::new()); + path.segments = segments.into_pairs().skip(1).collect(); + } + + fn self_to_expr_path(&self, path: &mut Path) { + if let Type::Path(self_ty) = &self.self_ty { + *path = self_ty.path.clone(); + 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(Default::default()); + } + } + } + } 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!(::core::marker::PhantomData::<#error>); + } + } +} + +impl VisitMut for ReplaceReceiver<'_> { + // `Self` -> `Receiver` + 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(); + } else { + self.visit_type_path_mut(node); + } + } else { + visit_mut::visit_type_mut(self, ty); + } + } + + // `Self::Assoc` -> `::Assoc` + fn visit_type_path_mut(&mut self, ty: &mut TypePath) { + if ty.qself.is_none() { + self.self_to_qself(&mut ty.qself, &mut ty.path); + } + visit_mut::visit_type_path_mut(self, ty); + } + + // `Self::method` -> `::method` + fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) { + if expr.qself.is_none() { + prepend_underscore_to_self(&mut expr.path.segments[0].ident); + self.self_to_qself(&mut expr.qself, &mut expr.path); + } + visit_mut::visit_expr_path_mut(self, expr); + } + + fn visit_expr_struct_mut(&mut self, expr: &mut ExprStruct) { + if expr.path.is_ident("Self") { + self.self_to_expr_path(&mut expr.path); + } + visit_mut::visit_expr_struct_mut(self, expr); + } + + fn visit_macro_mut(&mut self, node: &mut Macro) { + // We can't tell in general whether `self` inside a macro invocation + // refers to the self in the argument list or a different self + // introduced within the macro. Heuristic: if the macro input contains + // `fn`, then `self` is more likely to refer to something other than the + // outer function's self argument. + if !contains_fn(node.tokens.clone()) { + node.tokens = fold_token_stream(node.tokens.clone()); + } + } + + fn visit_item_mut(&mut self, _: &mut Item) { + // Do not recurse into nested items. + } +} + +fn contains_fn(tokens: TokenStream) -> bool { + tokens.into_iter().any(|tt| match tt { + TokenTree::Ident(ident) => ident == "fn", + TokenTree::Group(group) => contains_fn(group.stream()), + _ => false, + }) +} + +fn fold_token_stream(tokens: TokenStream) -> TokenStream { + tokens + .into_iter() + .map(|tt| match tt { + TokenTree::Ident(mut ident) => { + prepend_underscore_to_self(&mut ident); + TokenTree::Ident(ident) + } + TokenTree::Group(group) => { + let content = fold_token_stream(group.stream()); + TokenTree::Group(Group::new(group.delimiter(), content)) + } + other => other, + }) + .collect() +} + +pub(crate) fn prepend_underscore_to_self(ident: &mut Ident) { + if ident == "self" { + *ident = Ident::new("__self", ident.span()); + } +} diff --git a/tests/pinned_drop.rs b/tests/pinned_drop.rs index fbafb2dc..9130c4ab 100644 --- a/tests/pinned_drop.rs +++ b/tests/pinned_drop.rs @@ -27,7 +27,7 @@ fn safe_project() { } #[test] -fn test_mut_argument() { +fn mut_self_argument() { #[pin_project(PinnedDrop)] struct Struct { data: usize, @@ -42,7 +42,7 @@ fn test_mut_argument() { } #[test] -fn test_self_in_vec() { +fn self_in_vec() { #[pin_project(PinnedDrop)] struct Struct { data: usize, @@ -57,7 +57,7 @@ fn test_self_in_vec() { } #[test] -fn test_self_in_macro_containing_fn() { +fn self_in_macro_containing_fn() { #[pin_project(PinnedDrop)] pub struct Struct { data: usize, @@ -83,7 +83,7 @@ fn test_self_in_macro_containing_fn() { } #[test] -fn test_call_self() { +fn self_call() { #[pin_project(PinnedDrop)] pub struct Struct { data: usize, @@ -112,8 +112,65 @@ fn test_call_self() { } } +// See also `ui/pinned_drop/self.rs`. #[test] -fn test_self_match() { +fn self_expr() { + #[pin_project(PinnedDrop)] + pub struct Struct { + x: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(mut self: Pin<&mut Self>) { + let _: Self = Self { x: 0 }; + } + } + + #[pin_project(PinnedDrop)] + pub struct TupleStruct(usize); + + #[pinned_drop] + impl PinnedDrop for TupleStruct { + fn drop(mut self: Pin<&mut Self>) { + let _: Self = Self(0); + } + } + + #[pin_project(PinnedDrop)] + pub enum Enum { + StructVariant { x: usize }, + TupleVariant(usize), + } + + #[pinned_drop] + impl PinnedDrop for Enum { + fn drop(mut self: Pin<&mut Self>) { + // let _: Self = Self::StructVariant { x: 0 }; //~ ERROR can't use generic parameters from outer function [E0401] + let _: Self = Self::TupleVariant(0); + } + } +} + +// See also `ui/pinned_drop/self.rs`. +#[test] +fn self_pat() { + #[pin_project(PinnedDrop)] + pub struct Struct { + x: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(mut self: Pin<&mut Self>) { + // match *self { + // Self { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] + // } + // if let Self { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] + // let Self { x: _ } = *self; //~ ERROR can't use generic parameters from outer function [E0401] + } + } + #[pin_project(PinnedDrop)] pub struct TupleStruct(usize); @@ -125,7 +182,25 @@ fn test_self_match() { Self(_) => {} } if let Self(_) = *self {} - let _: Self = Self(0); + let Self(_) = *self; + } + } + + #[pin_project(PinnedDrop)] + pub enum Enum { + StructVariant { x: usize }, + TupleVariant(usize), + } + + #[pinned_drop] + impl PinnedDrop for Enum { + fn drop(mut self: Pin<&mut Self>) { + // match *self { + // Self::StructVariant { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] + // Self::TupleVariant(_) => {} //~ ERROR can't use generic parameters from outer function [E0401] + // } + // if let Self::StructVariant { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] + // if let Self::TupleVariant(_) = *self {} //~ ERROR can't use generic parameters from outer function [E0401] } } } diff --git a/tests/ui/pinned_drop/ref-self.rs b/tests/ui/pinned_drop/ref-self.rs index 06970cfd..79ae05cd 100644 --- a/tests/ui/pinned_drop/ref-self.rs +++ b/tests/ui/pinned_drop/ref-self.rs @@ -1,10 +1,12 @@ +// `ref (mut) self` are rejected by rustc. + use std::pin::Pin; -pub struct Foo { +pub struct Struct { field: u8, } -impl Foo { +impl Struct { fn method_ref(ref self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` fn method_ref_mut(ref mut self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` } diff --git a/tests/ui/pinned_drop/ref-self.stderr b/tests/ui/pinned_drop/ref-self.stderr index b832bdd3..3ab48981 100644 --- a/tests/ui/pinned_drop/ref-self.stderr +++ b/tests/ui/pinned_drop/ref-self.stderr @@ -1,11 +1,11 @@ error: expected identifier, found keyword `self` - --> $DIR/ref-self.rs:8:23 - | -8 | fn method_ref(ref self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` - | ^^^^ expected identifier, found keyword + --> $DIR/ref-self.rs:10:23 + | +10 | fn method_ref(ref self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` + | ^^^^ expected identifier, found keyword error: expected identifier, found keyword `self` - --> $DIR/ref-self.rs:9:31 - | -9 | fn method_ref_mut(ref mut self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` - | ^^^^ expected identifier, found keyword + --> $DIR/ref-self.rs:11:31 + | +11 | fn method_ref_mut(ref mut self: Pin<&mut Self>) {} //~ ERROR expected identifier, found keyword `self` + | ^^^^ expected identifier, found keyword diff --git a/tests/ui/pinned_drop/self-match.rs b/tests/ui/pinned_drop/self-match.rs deleted file mode 100644 index 6b1e769a..00000000 --- a/tests/ui/pinned_drop/self-match.rs +++ /dev/null @@ -1,54 +0,0 @@ -use pin_project::{pin_project, pinned_drop}; -use std::pin::Pin; - -#[pin_project(PinnedDrop)] -pub struct Struct { - x: usize, -} - -#[pinned_drop] -impl PinnedDrop for Struct { - fn drop(mut self: Pin<&mut Self>) { - match *self { - Self { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] - } - if let Self { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] - let _: Self = Self { x: 0 }; //~ ERROR can't use generic parameters from outer function [E0401] - } -} - -#[pin_project(PinnedDrop)] -pub struct TupleStruct(usize); - -#[pinned_drop] -impl PinnedDrop for TupleStruct { - fn drop(mut self: Pin<&mut Self>) { - match *self { - Self(_) => {} - } - if let Self(_) = *self {} - let _: Self = Self(0); - } -} - -#[pin_project(PinnedDrop)] -pub enum Enum { - StructVariant { x: usize }, - TupleVariant(usize), -} - -#[pinned_drop] -impl PinnedDrop for Enum { - fn drop(mut self: Pin<&mut Self>) { - match *self { - Self::StructVariant { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] - Self::TupleVariant(_) => {} //~ ERROR can't use generic parameters from outer function [E0401] - } - if let Self::StructVariant { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] - if let Self::TupleVariant(_) = *self {} //~ ERROR can't use generic parameters from outer function [E0401] - let _: Self = Self::StructVariant { x: 0 }; //~ ERROR can't use generic parameters from outer function [E0401] - let _: Self = Self::TupleVariant(0); - } -} - -fn main() {} \ No newline at end of file diff --git a/tests/ui/pinned_drop/self-match.stderr b/tests/ui/pinned_drop/self-match.stderr deleted file mode 100644 index 9a98ff3c..00000000 --- a/tests/ui/pinned_drop/self-match.stderr +++ /dev/null @@ -1,95 +0,0 @@ -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-match.rs:13:13 - | -10 | impl PinnedDrop for Struct { - | ---- `Self` type implicitly declared here, by this `impl` -... -13 | Self { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] - | ^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-match.rs:15:16 - | -10 | impl PinnedDrop for Struct { - | ---- `Self` type implicitly declared here, by this `impl` -... -15 | if let Self { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] - | ^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-match.rs:16:23 - | -10 | impl PinnedDrop for Struct { - | ---- `Self` type implicitly declared here, by this `impl` -... -16 | let _: Self = Self { x: 0 }; //~ ERROR can't use generic parameters from outer function [E0401] - | ^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-match.rs:44:13 - | -41 | impl PinnedDrop for Enum { - | ---- `Self` type implicitly declared here, by this `impl` -... -44 | Self::StructVariant { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] - | ^^^^^^^^^^^^^^^^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-match.rs:45:13 - | -41 | impl PinnedDrop for Enum { - | ---- `Self` type implicitly declared here, by this `impl` -... -45 | Self::TupleVariant(_) => {} //~ ERROR can't use generic parameters from outer function [E0401] - | ^^^^^^^^^^^^^^^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-match.rs:47:16 - | -41 | impl PinnedDrop for Enum { - | ---- `Self` type implicitly declared here, by this `impl` -... -47 | if let Self::StructVariant { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] - | ^^^^^^^^^^^^^^^^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-match.rs:48:16 - | -41 | impl PinnedDrop for Enum { - | ---- `Self` type implicitly declared here, by this `impl` -... -48 | if let Self::TupleVariant(_) = *self {} //~ ERROR can't use generic parameters from outer function [E0401] - | ^^^^^^^^^^^^^^^^^^ - | | - | use of generic parameter from outer function - | use a type here instead - -error[E0401]: can't use generic parameters from outer function - --> $DIR/self-match.rs:49:23 - | -41 | impl PinnedDrop for Enum { - | ---- `Self` type implicitly declared here, by this `impl` -... -49 | let _: Self = Self::StructVariant { x: 0 }; //~ ERROR can't use generic parameters from outer function [E0401] - | ^^^^^^^^^^^^^^^^^^^ - | | - | use of generic parameter from outer function - | use a type here instead diff --git a/tests/ui/pinned_drop/self.rs b/tests/ui/pinned_drop/self.rs new file mode 100644 index 00000000..6d552a71 --- /dev/null +++ b/tests/ui/pinned_drop/self.rs @@ -0,0 +1,93 @@ +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +fn self_expr() { + #[pin_project(PinnedDrop)] + pub struct Struct { + x: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(mut self: Pin<&mut Self>) { + let _: Self = Self { x: 0 }; + } + } + + #[pin_project(PinnedDrop)] + pub struct TupleStruct(usize); + + #[pinned_drop] + impl PinnedDrop for TupleStruct { + fn drop(mut self: Pin<&mut Self>) { + let _: Self = Self(0); + } + } + + #[pin_project(PinnedDrop)] + pub enum Enum { + StructVariant { x: usize }, + TupleVariant(usize), + } + + #[pinned_drop] + impl PinnedDrop for Enum { + fn drop(mut self: Pin<&mut Self>) { + let _: Self = Self::StructVariant { x: 0 }; //~ ERROR can't use generic parameters from outer function [E0401] + let _: Self = Self::TupleVariant(0); + } + } +} + +fn self_pat() { + #[pin_project(PinnedDrop)] + pub struct Struct { + x: usize, + } + + #[pinned_drop] + impl PinnedDrop for Struct { + fn drop(mut self: Pin<&mut Self>) { + match *self { + Self { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] + } + if let Self { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] + let Self { x: _ } = *self; //~ ERROR can't use generic parameters from outer function [E0401] + } + } + + #[pin_project(PinnedDrop)] + pub struct TupleStruct(usize); + + #[pinned_drop] + impl PinnedDrop for TupleStruct { + #[allow(irrefutable_let_patterns)] + fn drop(mut self: Pin<&mut Self>) { + match *self { + Self(_) => {} + } + if let Self(_) = *self {} + let Self(_) = *self; + } + } + + #[pin_project(PinnedDrop)] + pub enum Enum { + StructVariant { x: usize }, + TupleVariant(usize), + } + + #[pinned_drop] + impl PinnedDrop for Enum { + fn drop(mut self: Pin<&mut Self>) { + match *self { + Self::StructVariant { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] + Self::TupleVariant(_) => {} //~ ERROR can't use generic parameters from outer function [E0401] + } + if let Self::StructVariant { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] + if let Self::TupleVariant(_) = *self {} //~ ERROR can't use generic parameters from outer function [E0401] + } + } +} + +fn main() {} diff --git a/tests/ui/pinned_drop/self.stderr b/tests/ui/pinned_drop/self.stderr new file mode 100644 index 00000000..54c7b676 --- /dev/null +++ b/tests/ui/pinned_drop/self.stderr @@ -0,0 +1,95 @@ +error[E0401]: can't use generic parameters from outer function + --> $DIR/self.rs:36:27 + | +34 | impl PinnedDrop for Enum { + | ---- `Self` type implicitly declared here, by this `impl` +35 | fn drop(mut self: Pin<&mut Self>) { +36 | let _: Self = Self::StructVariant { x: 0 }; //~ ERROR can't use generic parameters from outer function [E0401] + | ^^^^^^^^^^^^^^^^^^^ + | | + | use of generic parameter from outer function + | use a type here instead + +error[E0401]: can't use generic parameters from outer function + --> $DIR/self.rs:52:17 + | +49 | impl PinnedDrop for Struct { + | ---- `Self` type implicitly declared here, by this `impl` +... +52 | Self { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] + | ^^^^ + | | + | use of generic parameter from outer function + | use a type here instead + +error[E0401]: can't use generic parameters from outer function + --> $DIR/self.rs:54:20 + | +49 | impl PinnedDrop for Struct { + | ---- `Self` type implicitly declared here, by this `impl` +... +54 | if let Self { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] + | ^^^^ + | | + | use of generic parameter from outer function + | use a type here instead + +error[E0401]: can't use generic parameters from outer function + --> $DIR/self.rs:55:17 + | +49 | impl PinnedDrop for Struct { + | ---- `Self` type implicitly declared here, by this `impl` +... +55 | let Self { x: _ } = *self; //~ ERROR can't use generic parameters from outer function [E0401] + | ^^^^ + | | + | use of generic parameter from outer function + | use a type here instead + +error[E0401]: can't use generic parameters from outer function + --> $DIR/self.rs:84:17 + | +81 | impl PinnedDrop for Enum { + | ---- `Self` type implicitly declared here, by this `impl` +... +84 | Self::StructVariant { x: _ } => {} //~ ERROR can't use generic parameters from outer function [E0401] + | ^^^^^^^^^^^^^^^^^^^ + | | + | use of generic parameter from outer function + | use a type here instead + +error[E0401]: can't use generic parameters from outer function + --> $DIR/self.rs:85:17 + | +81 | impl PinnedDrop for Enum { + | ---- `Self` type implicitly declared here, by this `impl` +... +85 | Self::TupleVariant(_) => {} //~ ERROR can't use generic parameters from outer function [E0401] + | ^^^^^^^^^^^^^^^^^^ + | | + | use of generic parameter from outer function + | use a type here instead + +error[E0401]: can't use generic parameters from outer function + --> $DIR/self.rs:87:20 + | +81 | impl PinnedDrop for Enum { + | ---- `Self` type implicitly declared here, by this `impl` +... +87 | if let Self::StructVariant { x: _ } = *self {} //~ ERROR can't use generic parameters from outer function [E0401] + | ^^^^^^^^^^^^^^^^^^^ + | | + | use of generic parameter from outer function + | use a type here instead + +error[E0401]: can't use generic parameters from outer function + --> $DIR/self.rs:88:20 + | +81 | impl PinnedDrop for Enum { + | ---- `Self` type implicitly declared here, by this `impl` +... +88 | if let Self::TupleVariant(_) = *self {} //~ ERROR can't use generic parameters from outer function [E0401] + | ^^^^^^^^^^^^^^^^^^ + | | + | use of generic parameter from outer function + | use a type here instead