diff options
Diffstat (limited to 'third_party/rust/pin-project-internal')
11 files changed, 2558 insertions, 0 deletions
diff --git a/third_party/rust/pin-project-internal/.cargo-checksum.json b/third_party/rust/pin-project-internal/.cargo-checksum.json new file mode 100644 index 0000000000..a115ec6566 --- /dev/null +++ b/third_party/rust/pin-project-internal/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"3fe6c53bc8cb8dfee1091ff799a743024b78bbf7ded986396ccb8a139bc7f02b","LICENSE-APACHE":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","src/lib.rs":"fe9fdaa1dcf2e9ade6ae1c34e20195223c8f63d19c0ba2d0189e07207d4f1a30","src/pin_project/attribute.rs":"5b441bab16d19215d660790b46eab18b402d36edb951ba7f8284772bf2a470bd","src/pin_project/derive.rs":"f244d4bed929350fdfcc96513fce17a4ab2146e1f7974ae1255d72a9b72ffd33","src/pin_project/mod.rs":"4c5f5215d1737a6e4797d7f5eb1f7f6008505b06cfc304a66758bd96e6252c0c","src/pinned_drop.rs":"4519a66e9804143578faf60ed8239811d92cc6b2af817736439a9bc772d48780","src/project.rs":"e6ce9acaaad85d9945c24ec4507e6373aa61dfab50717453666733fa8161c099","src/utils.rs":"340a79dd4b02b5ea97c747ef5c56d5a8cedfaeff4a259fe5140c83803b2ed115"},"package":"8988430ce790d8682672117bc06dda364c0be32d3abd738234f19f3240bad99a"}
\ No newline at end of file diff --git a/third_party/rust/pin-project-internal/Cargo.toml b/third_party/rust/pin-project-internal/Cargo.toml new file mode 100644 index 0000000000..f9d79ef0e9 --- /dev/null +++ b/third_party/rust/pin-project-internal/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "pin-project-internal" +version = "0.4.9" +authors = ["Taiki Endo <te316e89@gmail.com>"] +description = "An internal crate to support pin_project - do not use directly\n" +homepage = "https://github.com/taiki-e/pin-project" +documentation = "https://docs.rs/pin-project-internal" +keywords = ["pin", "macros", "attribute"] +categories = ["no-std", "rust-patterns"] +license = "Apache-2.0 OR MIT" +repository = "https://github.com/taiki-e/pin-project" + +[lib] +proc-macro = true +[dependencies.proc-macro2] +version = "1.0" + +[dependencies.quote] +version = "1.0" + +[dependencies.syn] +version = "1.0" +features = ["full", "visit-mut"] diff --git a/third_party/rust/pin-project-internal/LICENSE-APACHE b/third_party/rust/pin-project-internal/LICENSE-APACHE new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/third_party/rust/pin-project-internal/LICENSE-APACHE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/third_party/rust/pin-project-internal/LICENSE-MIT b/third_party/rust/pin-project-internal/LICENSE-MIT new file mode 100644 index 0000000000..31aa79387f --- /dev/null +++ b/third_party/rust/pin-project-internal/LICENSE-MIT @@ -0,0 +1,23 @@ +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/third_party/rust/pin-project-internal/src/lib.rs b/third_party/rust/pin-project-internal/src/lib.rs new file mode 100644 index 0000000000..ba7abbb3d4 --- /dev/null +++ b/third_party/rust/pin-project-internal/src/lib.rs @@ -0,0 +1,552 @@ +//! An internal crate to support pin_project - **do not use directly** + +#![recursion_limit = "256"] +#![doc(html_root_url = "https://docs.rs/pin-project-internal/0.4.9")] +#![doc(test( + no_crate_inject, + attr(deny(warnings, rust_2018_idioms, single_use_lifetimes), allow(dead_code)) +))] +#![warn(unsafe_code)] +#![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)] +#![warn(clippy::all)] +// mem::take requires Rust 1.40 +#![allow(clippy::mem_replace_with_default)] +#![allow(clippy::needless_doctest_main)] +// While this crate supports stable Rust, it currently requires +// nightly Rust in order for rustdoc to correctly document auto-generated +// `Unpin` impls. This does not affect the runtime functionality of this crate, +// nor does it affect the safety of the api provided by this crate. +// +// This is disabled by default and can be enabled using +// `--cfg pin_project_show_unpin_struct` in RUSTFLAGS. +// +// Refs: +// * https://github.com/taiki-e/pin-project/pull/53#issuecomment-525906867 +// * https://github.com/taiki-e/pin-project/pull/70 +// * https://github.com/rust-lang/rust/issues/63281 +#![cfg_attr(pin_project_show_unpin_struct, feature(proc_macro_def_site))] + +// older compilers require explicit `extern crate`. +#[allow(unused_extern_crates)] +extern crate proc_macro; + +#[macro_use] +mod utils; + +mod pin_project; +mod pinned_drop; +mod project; + +use proc_macro::TokenStream; + +use utils::{Immutable, Mutable}; + +/// An attribute that creates a projection struct covering all the fields. +/// +/// This attribute creates a projection struct according to the following rules: +/// +/// - For the field that uses `#[pin]` attribute, makes the pinned reference to +/// the field. +/// - For the other fields, makes the unpinned reference to the field. +/// +/// The following methods are implemented on the original `#[pin_project]` type: +/// +/// ``` +/// # #[rustversion::since(1.36)] +/// # fn dox() { +/// # use std::pin::Pin; +/// # type Projection<'a> = &'a (); +/// # type ProjectionRef<'a> = &'a (); +/// # trait Dox { +/// fn project(self: Pin<&mut Self>) -> Projection<'_>; +/// fn project_ref(self: Pin<&Self>) -> ProjectionRef<'_>; +/// # } +/// # } +/// ``` +/// +/// The visibility of the projected type and projection method is based on the +/// original type. However, if the visibility of the original type is `pub`, +/// the visibility of the projected type and the projection method is `pub(crate)`. +/// +/// If you want to call the `project` method multiple times or later use the +/// original Pin type, it needs to use [`.as_mut()`][`Pin::as_mut`] to avoid +/// consuming the `Pin`. +/// +/// ## Safety +/// +/// This attribute is completely safe. In the absence of other `unsafe` code *that you write*, +/// it is impossible to cause undefined behavior with this attribute. +/// +/// This is accomplished by enforcing the four requirements for pin projection +/// stated in [the Rust documentation](https://doc.rust-lang.org/nightly/std/pin/index.html#projections-and-structural-pinning): +/// +/// 1. The struct must only be Unpin if all the structural fields are Unpin. +/// +/// To enforce this, this attribute will automatically generate an `Unpin` implementation +/// for you, which will require that all structurally pinned fields be `Unpin` +/// If you wish to provide an manual `Unpin` impl, you can do so via the +/// `UnsafeUnpin` argument. +/// +/// 2. The destructor of the struct must not move structural fields out of its argument. +/// +/// To enforce this, this attribute will generate code like this: +/// +/// ```rust +/// struct MyStruct {} +/// trait MyStructMustNotImplDrop {} +/// impl<T: Drop> MyStructMustNotImplDrop for T {} +/// impl MyStructMustNotImplDrop for MyStruct {} +/// ``` +/// +/// If you attempt to provide an Drop impl, the blanket impl will +/// then apply to your type, causing a compile-time error due to +/// the conflict with the second impl. +/// +/// If you wish to provide a custom `Drop` impl, you can annotate a function +/// with `#[pinned_drop]`. This function takes a pinned version of your struct - +/// that is, `Pin<&mut MyStruct>` where `MyStruct` is the type of your struct. +/// +/// You can call `project()` on this type as usual, along with any other +/// methods you have defined. Because your code is never provided with +/// a `&mut MyStruct`, it is impossible to move out of pin-projectable +/// fields in safe code in your destructor. +/// +/// 3. You must make sure that you uphold the Drop guarantee: once your struct is pinned, +/// the memory that contains the content is not overwritten or deallocated without calling the content's destructors. +/// +/// Safe code doesn't need to worry about this - the only wait to violate this requirement +/// is to manually deallocate memory (which is `unsafe`), or to overwrite a field with something else. +/// Because your custom destructor takes `Pin<&mut MyStruct`, it's impossible to obtain +/// a mutable reference to a pin-projected field in safe code. +/// +/// 4. You must not offer any other operations that could lead to data being moved out of the structural fields when your type is pinned. +/// +/// As with requirement 3, it is impossible for safe code to violate this. This crate ensures that safe code can never +/// obtain a mutable reference to `#[pin]` fields, which prevents you from ever moving out of them in safe code. +/// +/// Pin projections are also incompatible with `#[repr(packed)]` structs. Attempting to use this attribute +/// on a `#[repr(packed)]` struct results in a compile-time error. +/// +/// +/// ## Examples +/// +/// Using `#[pin_project]` will automatically create the appropriate +/// conditional [`Unpin`] implementation: +/// +/// ```rust +/// use pin_project::pin_project; +/// use std::pin::Pin; +/// +/// #[pin_project] +/// struct Foo<T, U> { +/// #[pin] +/// future: T, +/// field: U, +/// } +/// +/// impl<T, U> Foo<T, U> { +/// fn baz(self: Pin<&mut Self>) { +/// let this = self.project(); +/// let _: Pin<&mut T> = this.future; // Pinned reference to the field +/// let _: &mut U = this.field; // Normal reference to the field +/// } +/// } +/// ``` +/// +/// Note that borrowing the field where `#[pin]` attribute is used multiple +/// times requires using [`.as_mut()`][`Pin::as_mut`] to avoid +/// consuming the `Pin`. +/// +/// If you want to implement [`Unpin`] manually, you must use the `UnsafeUnpin` +/// argument to `#[pin_project]`. +/// +/// ```rust +/// use pin_project::{pin_project, UnsafeUnpin}; +/// use std::pin::Pin; +/// +/// #[pin_project(UnsafeUnpin)] +/// struct Foo<T, U> { +/// #[pin] +/// future: T, +/// field: U, +/// } +/// +/// impl<T, U> Foo<T, U> { +/// fn baz(self: Pin<&mut Self>) { +/// let this = self.project(); +/// let _: Pin<&mut T> = this.future; // Pinned reference to the field +/// let _: &mut U = this.field; // Normal reference to the field +/// } +/// } +/// +/// unsafe impl<T: Unpin, U> UnsafeUnpin for Foo<T, U> {} // Conditional Unpin impl +/// ``` +/// +/// Note the usage of the unsafe [`UnsafeUnpin`] trait, instead of the usual +/// [`Unpin`] trait. [`UnsafeUnpin`] behaves exactly like [`Unpin`], except that is +/// unsafe to implement. This unsafety comes from the fact that pin projections +/// are being used. If you implement [`UnsafeUnpin`], you must ensure that it is +/// only implemented when all pin-projected fields implement [`Unpin`]. +/// +/// See [`UnsafeUnpin`] trait for more details. +/// +/// ### `#[pinned_drop]` +/// +/// In order to correctly implement pin projections, a type's `Drop` impl must +/// not move out of any structurally pinned fields. Unfortunately, [`Drop::drop`] +/// takes `&mut Self`, not `Pin<&mut Self>`. +/// +/// To ensure that this requirement is upheld, the `#[pin_project]` attribute will +/// provide a [`Drop`] impl for you. This `Drop` impl will delegate to an impl +/// block annotated with `#[pinned_drop]` if you use the `PinnedDrop` argument +/// to `#[pin_project]`. This impl block acts just like a normal [`Drop`] impl, +/// except for the following two: +/// +/// * `drop` method takes `Pin<&mut Self>` +/// * Name of the trait is `PinnedDrop`. +/// +/// `#[pin_project]` implements the actual [`Drop`] trait via `PinnedDrop` you +/// implemented. To drop a type that implements `PinnedDrop`, use the [`drop`] +/// function just like dropping a type that directly implements [`Drop`]. +/// +/// In particular, it will never be called more than once, just like [`Drop::drop`]. +/// +/// For example: +/// +/// ```rust +/// use pin_project::{pin_project, pinned_drop}; +/// use std::{fmt::Debug, pin::Pin}; +/// +/// #[pin_project(PinnedDrop)] +/// pub struct Foo<T: Debug, U: Debug> { +/// #[pin] +/// pinned_field: T, +/// unpin_field: U, +/// } +/// +/// #[pinned_drop] +/// impl<T: Debug, U: Debug> PinnedDrop for Foo<T, U> { +/// fn drop(self: Pin<&mut Self>) { +/// println!("Dropping pinned field: {:?}", self.pinned_field); +/// println!("Dropping unpin field: {:?}", self.unpin_field); +/// } +/// } +/// +/// fn main() { +/// let _x = Foo { pinned_field: true, unpin_field: 40 }; +/// } +/// ``` +/// +/// See also [`pinned_drop`] attribute. +/// +/// ## Supported Items +/// +/// The current pin-project supports the following types of items. +/// +/// ### Structs (structs with named fields): +/// +/// ```rust +/// use pin_project::pin_project; +/// use std::pin::Pin; +/// +/// #[pin_project] +/// struct Foo<T, U> { +/// #[pin] +/// future: T, +/// field: U, +/// } +/// +/// impl<T, U> Foo<T, U> { +/// fn baz(self: Pin<&mut Self>) { +/// let this = self.project(); +/// let _: Pin<&mut T> = this.future; +/// let _: &mut U = this.field; +/// } +/// } +/// ``` +/// +/// ### Tuple structs (structs with unnamed fields): +/// +/// ```rust +/// use pin_project::pin_project; +/// use std::pin::Pin; +/// +/// #[pin_project] +/// struct Foo<T, U>(#[pin] T, U); +/// +/// impl<T, U> Foo<T, U> { +/// fn baz(self: Pin<&mut Self>) { +/// let this = self.project(); +/// let _: Pin<&mut T> = this.0; +/// let _: &mut U = this.1; +/// } +/// } +/// ``` +/// +/// Structs without fields (unit-like struct and zero fields struct) are not +/// supported. +/// +/// ### Enums +/// +/// `pin_project` also supports enums, but to use it, you need to use with the +/// [`project`] attribute. +/// +/// The attribute at the expression position is not stable, so you need to use +/// a dummy `#[project]` attribute for the function. +/// +/// ```rust +/// use pin_project::{pin_project, project}; +/// use std::pin::Pin; +/// +/// #[pin_project] +/// enum Foo<A, B, C> { +/// Tuple(#[pin] A, B), +/// Struct { field: C }, +/// Unit, +/// } +/// +/// impl<A, B, C> Foo<A, B, C> { +/// #[project] // Nightly does not need a dummy attribute to the function. +/// fn baz(self: Pin<&mut Self>) { +/// #[project] +/// match self.project() { +/// Foo::Tuple(x, y) => { +/// let _: Pin<&mut A> = x; +/// let _: &mut B = y; +/// } +/// Foo::Struct { field } => { +/// let _: &mut C = field; +/// } +/// Foo::Unit => {} +/// } +/// } +/// } +/// ``` +/// +/// Enums without variants (zero-variant enums) are not supported. +/// +/// See also [`project`] and [`project_ref`] attributes. +/// +/// [`Pin::as_mut`]: core::pin::Pin::as_mut +/// [`Pin::set`]: core::pin::Pin::set +/// [`drop`]: Drop::drop +/// [`UnsafeUnpin`]: https://docs.rs/pin-project/0.4/pin_project/trait.UnsafeUnpin.html +/// [`project`]: ./attr.project.html +/// [`project_ref`]: ./attr.project_ref.html +/// [`pinned_drop`]: ./attr.pinned_drop.html +#[proc_macro_attribute] +pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream { + pin_project::attribute(&args.into(), input.into()).into() +} + +/// An attribute for annotating an impl block that implements [`Drop`]. +/// +/// This attribute is only needed when you wish to provide a [`Drop`] +/// impl for your type. The impl block annotated with `#[pinned_drop]` acts just +/// like a normal [`Drop`] impl, except for the fact that `drop` method takes +/// `Pin<&mut Self>`. In particular, it will never be called more than once, +/// just like [`Drop::drop`]. +/// +/// ## Example +/// +/// ```rust +/// use pin_project::{pin_project, pinned_drop}; +/// use std::pin::Pin; +/// +/// #[pin_project(PinnedDrop)] +/// struct Foo { +/// #[pin] +/// field: u8, +/// } +/// +/// #[pinned_drop] +/// impl PinnedDrop for Foo { +/// fn drop(self: Pin<&mut Self>) { +/// println!("Dropping: {}", self.field); +/// } +/// } +/// +/// fn main() { +/// let _x = Foo { field: 50 }; +/// } +/// ``` +/// +/// See ["pinned-drop" section of `pin_project` attribute][pinned-drop] for more details. +/// +/// [pinned-drop]: ./attr.pin_project.html#pinned_drop +#[proc_macro_attribute] +pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input); + pinned_drop::attribute(&args.into(), input).into() +} + +/// An attribute to provide way to refer to the projected type returned by +/// `project` method. +/// +/// The following syntaxes are supported. +/// +/// ## `impl` blocks +/// +/// All methods (and associated functions) in `#[project] impl` block become +/// methods of the projected type. If you want to implement methods on the +/// original type, you need to create another (non-`#[project]`) `impl` block. +/// +/// To call a method implemented in `#[project] impl` block, you need to first +/// get the projected-type with `let this = self.project();`. +/// +/// ### Examples +/// +/// ```rust +/// use pin_project::{pin_project, project}; +/// use std::pin::Pin; +/// +/// #[pin_project] +/// struct Foo<T, U> { +/// #[pin] +/// future: T, +/// field: U, +/// } +/// +/// // impl for the original type +/// impl<T, U> Foo<T, U> { +/// fn bar(self: Pin<&mut Self>) { +/// self.project().baz() +/// } +/// } +/// +/// // impl for the projected type +/// #[project] +/// impl<T, U> Foo<T, U> { +/// fn baz(self) { +/// let Self { future, field } = self; +/// +/// let _: Pin<&mut T> = future; +/// let _: &mut U = field; +/// } +/// } +/// ``` +/// +/// ## `let` bindings +/// +/// *The attribute at the expression position is not stable, so you need to use +/// a dummy `#[project]` attribute for the function.* +/// +/// ### Examples +/// +/// ```rust +/// use pin_project::{pin_project, project}; +/// use std::pin::Pin; +/// +/// #[pin_project] +/// struct Foo<T, U> { +/// #[pin] +/// future: T, +/// field: U, +/// } +/// +/// impl<T, U> Foo<T, U> { +/// #[project] // Nightly does not need a dummy attribute to the function. +/// fn baz(self: Pin<&mut Self>) { +/// #[project] +/// let Foo { future, field } = self.project(); +/// +/// let _: Pin<&mut T> = future; +/// let _: &mut U = field; +/// } +/// } +/// ``` +/// +/// ## `match` expressions +/// +/// *The attribute at the expression position is not stable, so you need to use +/// a dummy `#[project]` attribute for the function.* +/// +/// ### Examples +/// +/// ```rust +/// use pin_project::{pin_project, project}; +/// use std::pin::Pin; +/// +/// #[pin_project] +/// enum Foo<A, B, C> { +/// Tuple(#[pin] A, B), +/// Struct { field: C }, +/// Unit, +/// } +/// +/// impl<A, B, C> Foo<A, B, C> { +/// #[project] // Nightly does not need a dummy attribute to the function. +/// fn baz(self: Pin<&mut Self>) { +/// #[project] +/// match self.project() { +/// Foo::Tuple(x, y) => { +/// let _: Pin<&mut A> = x; +/// let _: &mut B = y; +/// } +/// Foo::Struct { field } => { +/// let _: &mut C = field; +/// } +/// Foo::Unit => {} +/// } +/// } +/// } +/// ``` +/// +/// ## `use` statements +/// +/// ### Examples +/// +/// ```rust +/// # mod dox { +/// use pin_project::pin_project; +/// +/// #[pin_project] +/// struct Foo<A> { +/// #[pin] +/// field: A, +/// } +/// +/// mod bar { +/// use super::Foo; +/// use pin_project::project; +/// use std::pin::Pin; +/// +/// #[project] +/// use super::Foo; +/// +/// #[project] +/// fn baz<A>(foo: Pin<&mut Foo<A>>) { +/// #[project] +/// let Foo { field } = foo.project(); +/// let _: Pin<&mut A> = field; +/// } +/// } +/// # } +/// ``` +#[proc_macro_attribute] +pub fn project(args: TokenStream, input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input); + project::attribute(&args.into(), input, Mutable).into() +} + +/// An attribute to provide way to refer to the projected type returned by +/// `project_ref` method. +/// +/// This is the same as [`project`] attribute except it refers to the projected +/// type returned by `project_ref` method. +/// +/// See [`project`] attribute for more details. +/// +/// [`project`]: ./attr.project.html +#[proc_macro_attribute] +pub fn project_ref(args: TokenStream, input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input); + project::attribute(&args.into(), input, Immutable).into() +} + +/// An internal helper macro. +#[doc(hidden)] +#[proc_macro_derive(__PinProjectInternalDerive, attributes(pin))] +pub fn __pin_project_internal_derive(input: TokenStream) -> TokenStream { + pin_project::derive(input.into()).into() +} diff --git a/third_party/rust/pin-project-internal/src/pin_project/attribute.rs b/third_party/rust/pin-project-internal/src/pin_project/attribute.rs new file mode 100644 index 0000000000..7a0996e720 --- /dev/null +++ b/third_party/rust/pin-project-internal/src/pin_project/attribute.rs @@ -0,0 +1,71 @@ +use proc_macro2::{Span, TokenStream}; +use quote::quote; +use syn::{ + parse::{Parse, ParseStream}, + *, +}; + +use crate::utils::{SliceExt, CURRENT_PRIVATE_MODULE}; + +use super::PIN; + +// To generate the correct `Unpin` implementation and the projection methods, +// we need to collect the types of the pinned fields. +// However, since proc-macro-attribute is applied before `#[cfg]` and `#[cfg_attr]` on fields, +// we cannot be collecting field types properly at this timing. +// So instead of generating the `Unpin` implementation and the projection methods here, +// delegate their processing to proc-macro-derive. +// +// At this stage, only attributes are parsed and the following attributes are +// added to the attributes of the item. +// * `#[derive(InternalDerive)]` - An internal helper macro that does the above processing. +// * `#[pin(#private(#args))]` - Pass the argument of `#[pin_project]` to proc-macro-derive (`InternalDerive`). + +pub(super) fn parse_attribute(args: &TokenStream, input: TokenStream) -> Result<TokenStream> { + let Input { mut attrs, body } = syn::parse2(input)?; + + let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); + attrs.push(syn::parse_quote! { + #[derive(::pin_project::#private::__PinProjectInternalDerive)] + }); + // Use `#private` to prevent users from trying to control `InternalDerive` manually. + // `#private` does not guarantee compatibility between patch versions, + // so it should be sufficient for this purpose in most cases. + attrs.push(syn::parse_quote! { + #[pin(#private(#args))] + }); + + Ok(quote! { + #(#attrs)* + #body + }) +} + +#[allow(dead_code)] // https://github.com/rust-lang/rust/issues/56750 +struct Input { + attrs: Vec<Attribute>, + body: TokenStream, +} + +impl Parse for Input { + fn parse(input: ParseStream<'_>) -> Result<Self> { + let attrs = input.call(Attribute::parse_outer)?; + + let ahead = input.fork(); + let _vis: Visibility = ahead.parse()?; + if !ahead.peek(Token![struct]) && !ahead.peek(Token![enum]) { + // If we check this only on proc-macro-derive, it may generate unhelpful error messages. + // So it is preferable to be able to detect it here. + Err(error!( + input.parse::<TokenStream>()?, + "#[pin_project] attribute may only be used on structs or enums" + )) + } else if let Some(attr) = attrs.find(PIN) { + Err(error!(attr, "#[pin] attribute may only be used on fields of structs or variants")) + } else if let Some(attr) = attrs.find("pin_project") { + Err(error!(attr, "only one #[pin_project] attribute is allowed")) + } else { + Ok(Self { attrs, body: input.parse()? }) + } + } +} diff --git a/third_party/rust/pin-project-internal/src/pin_project/derive.rs b/third_party/rust/pin-project-internal/src/pin_project/derive.rs new file mode 100644 index 0000000000..30318f0483 --- /dev/null +++ b/third_party/rust/pin-project-internal/src/pin_project/derive.rs @@ -0,0 +1,834 @@ +use proc_macro2::{Span, TokenStream}; +use quote::{format_ident, quote, quote_spanned}; +use syn::{ + parse::{Parse, ParseBuffer, ParseStream}, + visit_mut::VisitMut, + *, +}; + +use crate::utils::*; + +use super::PIN; + +pub(super) fn parse_derive(input: TokenStream) -> Result<TokenStream> { + match syn::parse2(input)? { + Item::Struct(ItemStruct { attrs, vis, ident, generics, fields, .. }) => { + validate_struct(&ident, &fields)?; + let mut cx = Context::new(attrs, vis, ident, generics)?; + + let packed_check = cx.ensure_not_packed(&fields)?; + let mut proj_items = cx.parse_struct(&fields)?; + proj_items.extend(packed_check); + proj_items.extend(cx.make_unpin_impl()); + proj_items.extend(cx.make_drop_impl()); + Ok(proj_items) + } + Item::Enum(ItemEnum { attrs, vis, ident, generics, brace_token, variants, .. }) => { + validate_enum(brace_token, &variants)?; + let mut cx = Context::new(attrs, vis, ident, generics)?; + + // We don't need to check for '#[repr(packed)]', + // since it does not apply to enums. + let mut proj_items = cx.parse_enum(&variants)?; + proj_items.extend(cx.make_unpin_impl()); + proj_items.extend(cx.make_drop_impl()); + Ok(proj_items) + } + item => Err(error!(item, "#[pin_project] attribute may only be used on structs or enums")), + } +} + +fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> { + match fields { + Fields::Named(FieldsNamed { named: f, .. }) + | Fields::Unnamed(FieldsUnnamed { unnamed: f, .. }) + if f.is_empty() => + { + Err(error!( + fields, + "#[pin_project] attribute may not be used on structs with zero fields" + )) + } + Fields::Unit => { + Err(error!(ident, "#[pin_project] attribute may not be used on structs with units")) + } + _ => Ok(()), + } +} + +fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> { + if variants.is_empty() { + return Err(syn::Error::new( + brace_token.span, + "#[pin_project] attribute may not be used on enums without variants", + )); + } + let has_field = variants.iter().try_fold(false, |has_field, v| { + if let Some((_, e)) = &v.discriminant { + Err(error!(e, "#[pin_project] attribute may not be used on enums with discriminants")) + } else if let Some(attr) = v.attrs.find(PIN) { + Err(error!(attr, "#[pin] attribute may only be used on fields of structs or variants")) + } else if let Fields::Unit = v.fields { + Ok(has_field) + } else { + Ok(true) + } + })?; + if has_field { + Ok(()) + } else { + Err(error!( + variants, + "#[pin_project] attribute may not be used on enums that have no field" + )) + } +} + +#[derive(Default)] +struct Args { + pinned_drop: Option<Span>, + unsafe_unpin: Option<Span>, +} + +const DUPLICATE_PIN: &str = "duplicate #[pin] attribute"; + +impl Args { + fn get(attrs: &[Attribute]) -> Result<Self> { + let mut prev: Option<(&Attribute, Result<Args>)> = None; + + for attr in attrs { + if attr.path.is_ident(PIN) { + if let Some((prev_attr, prev_res)) = &prev { + // As the `#[pin]` attribute generated by `#[pin_project]` + // has the same span as `#[pin_project]`, it is possible + // that a useless error message will be generated. + let res = syn::parse2::<Self>(attr.tokens.clone()); + let span = match (&prev_res, res) { + (Ok(_), Ok(_)) => unreachable!(), + (_, Ok(_)) => prev_attr, + (Ok(_), _) => attr, + (Err(prev_err), Err(_)) => { + if prev_err.to_string() == DUPLICATE_PIN { + attr + } else { + prev_attr + } + } + }; + return Err(error!(span, DUPLICATE_PIN)); + } + prev = Some((attr, syn::parse2::<Self>(attr.tokens.clone()))); + } + } + + // This `unwrap` only fails if another macro removes `#[pin]`. + prev.unwrap().1 + } +} + +impl Parse for Args { + fn parse(input: ParseStream<'_>) -> Result<Self> { + fn parse_input(input: ParseStream<'_>) -> Result<ParseBuffer<'_>> { + // Extracts `#args` from `(#private(#args))`. + if let Ok(content) = input.parenthesized() { + if let Ok(private) = content.parse::<Ident>() { + if private == CURRENT_PRIVATE_MODULE { + if let Ok(args) = content.parenthesized() { + return Ok(args); + } + } + } + } + + // If this fails, it means that there is a `#[pin]` attribute + // inserted by something other than #[pin_project] attribute. + Err(error!(TokenStream::new(), DUPLICATE_PIN)) + } + + let input = parse_input(input)?; + let mut args = Self::default(); + while !input.is_empty() { + let ident = input.parse::<Ident>()?; + match &*ident.to_string() { + "PinnedDrop" => { + if args.pinned_drop.is_some() { + return Err(error!(ident, "duplicate `PinnedDrop` argument")); + } + args.pinned_drop = Some(ident.span()); + } + "UnsafeUnpin" => { + if args.unsafe_unpin.is_some() { + return Err(error!(ident, "duplicate `UnsafeUnpin` argument")); + } + args.unsafe_unpin = Some(ident.span()); + } + _ => return Err(error!(ident, "unexpected argument: {}", ident)), + } + + if !input.is_empty() { + let _: token::Comma = input.parse()?; + } + } + + Ok(args) + } +} + +struct OriginalType { + /// Attributes of the original type. + attrs: Vec<Attribute>, + /// Visibility of the original type. + vis: Visibility, + /// Name of the original type. + ident: Ident, + /// Generics of the original type. + generics: Generics, +} + +struct ProjectedType { + /// Visibility of the projected type. + vis: Visibility, + /// Name of the projected type returned by `project` method. + mut_ident: Ident, + /// Name of the projected type returned by `project_ref` method. + ref_ident: Ident, + /// Lifetime on the generated projected type. + lifetime: Lifetime, + /// Generics of the projected type. + generics: Generics, + /// `where` clause of the projected type. This has an additional + /// bound generated by `insert_lifetime_and_bound` + where_clause: WhereClause, +} + +struct Context { + orig: OriginalType, + proj: ProjectedType, + /// Types of the pinned fields. + pinned_fields: Vec<Type>, + /// `PinnedDrop` attribute. + pinned_drop: Option<Span>, + /// `UnsafeUnpin` attribute. + unsafe_unpin: Option<Span>, +} + +impl Context { + fn new( + attrs: Vec<Attribute>, + vis: Visibility, + ident: Ident, + mut generics: Generics, + ) -> Result<Self> { + let Args { pinned_drop, unsafe_unpin } = Args::get(&attrs)?; + + { + let ty_generics = generics.split_for_impl().1; + let self_ty = syn::parse_quote!(#ident #ty_generics); + let mut visitor = ReplaceReceiver::new(&self_ty); + visitor.visit_where_clause_mut(generics.make_where_clause()); + } + + let mut lifetime_name = String::from(DEFAULT_LIFETIME_NAME); + determine_lifetime_name(&mut lifetime_name, &generics.params); + let lifetime = Lifetime::new(&lifetime_name, Span::call_site()); + + let mut proj_generics = generics.clone(); + let ty_generics = generics.split_for_impl().1; + let ty_generics_as_generics = syn::parse_quote!(#ty_generics); + let pred = insert_lifetime_and_bound( + &mut proj_generics, + lifetime.clone(), + &ty_generics_as_generics, + ident.clone(), + ); + let mut where_clause = generics.clone().make_where_clause().clone(); + where_clause.predicates.push(pred); + + Ok(Self { + proj: ProjectedType { + vis: determine_visibility(&vis), + mut_ident: proj_ident(&ident, Mutable), + ref_ident: proj_ident(&ident, Immutable), + lifetime, + generics: proj_generics, + where_clause, + }, + orig: OriginalType { attrs, vis, ident, generics }, + pinned_drop, + unsafe_unpin, + pinned_fields: Vec::new(), + }) + } + + fn parse_struct(&mut self, fields: &Fields) -> Result<TokenStream> { + let (proj_pat, proj_init, proj_fields, proj_ref_fields) = match fields { + Fields::Named(fields) => self.visit_named(fields)?, + Fields::Unnamed(fields) => self.visit_unnamed(fields)?, + Fields::Unit => unreachable!(), + }; + + let orig_ident = &self.orig.ident; + let proj_ident = &self.proj.mut_ident; + let proj_ref_ident = &self.proj.ref_ident; + let vis = &self.proj.vis; + let proj_generics = &self.proj.generics; + let where_clause = &self.proj.where_clause; + + // For tuple structs, we need to generate `(T1, T2) where Foo: Bar` + // For non-tuple structs, we need to generate `where Foo: Bar { field1: T }` + let (where_clause_fields, where_clause_ref_fields) = match fields { + Fields::Named(_) => { + (quote!(#where_clause #proj_fields), quote!(#where_clause #proj_ref_fields)) + } + Fields::Unnamed(_) => { + (quote!(#proj_fields #where_clause;), quote!(#proj_ref_fields #where_clause;)) + } + Fields::Unit => unreachable!(), + }; + + let mut proj_items = quote! { + #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. + #[allow(dead_code)] // This lint warns unused fields/variants. + #vis struct #proj_ident #proj_generics #where_clause_fields + #[allow(dead_code)] // This lint warns unused fields/variants. + #vis struct #proj_ref_ident #proj_generics #where_clause_ref_fields + }; + + let proj_body = quote! { + let #orig_ident #proj_pat = self.get_unchecked_mut(); + #proj_ident #proj_init + }; + let proj_ref_body = quote! { + let #orig_ident #proj_pat = self.get_ref(); + #proj_ref_ident #proj_init + }; + + proj_items.extend(self.make_proj_impl(&proj_body, &proj_ref_body)); + + Ok(proj_items) + } + + fn parse_enum(&mut self, variants: &Variants) -> Result<TokenStream> { + let (proj_variants, proj_ref_variants, proj_arms, proj_ref_arms) = + self.visit_variants(variants)?; + + let proj_ident = &self.proj.mut_ident; + let proj_ref_ident = &self.proj.ref_ident; + let vis = &self.proj.vis; + let proj_generics = &self.proj.generics; + let where_clause = &self.proj.where_clause; + + let mut proj_items = quote! { + #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. + #[allow(dead_code)] // This lint warns unused fields/variants. + #vis enum #proj_ident #proj_generics #where_clause { + #proj_variants + } + #[allow(dead_code)] // This lint warns unused fields/variants. + #vis enum #proj_ref_ident #proj_generics #where_clause { + #proj_ref_variants + } + }; + + let proj_body = quote! { + match self.get_unchecked_mut() { + #proj_arms + } + }; + let proj_ref_body = quote! { + match self.get_ref() { + #proj_ref_arms + } + }; + + proj_items.extend(self.make_proj_impl(&proj_body, &proj_ref_body)); + + Ok(proj_items) + } + + fn visit_variants( + &mut self, + variants: &Variants, + ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> { + let mut proj_variants = TokenStream::new(); + let mut proj_ref_variants = TokenStream::new(); + let mut proj_arms = TokenStream::new(); + let mut proj_ref_arms = TokenStream::new(); + for Variant { ident, fields, .. } in variants { + let (proj_pat, proj_body, proj_fields, proj_ref_fields) = match fields { + Fields::Named(fields) => self.visit_named(fields)?, + Fields::Unnamed(fields) => self.visit_unnamed(fields)?, + Fields::Unit => { + (TokenStream::new(), TokenStream::new(), TokenStream::new(), TokenStream::new()) + } + }; + + let orig_ident = &self.orig.ident; + let proj_ident = &self.proj.mut_ident; + let proj_ref_ident = &self.proj.ref_ident; + proj_variants.extend(quote! { + #ident #proj_fields, + }); + proj_ref_variants.extend(quote! { + #ident #proj_ref_fields, + }); + proj_arms.extend(quote! { + #orig_ident::#ident #proj_pat => { + #proj_ident::#ident #proj_body + } + }); + proj_ref_arms.extend(quote! { + #orig_ident::#ident #proj_pat => { + #proj_ref_ident::#ident #proj_body + } + }); + } + + Ok((proj_variants, proj_ref_variants, proj_arms, proj_ref_arms)) + } + + fn visit_named( + &mut self, + FieldsNamed { named: fields, .. }: &FieldsNamed, + ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> { + let mut proj_pat = Vec::with_capacity(fields.len()); + let mut proj_body = Vec::with_capacity(fields.len()); + let mut proj_fields = Vec::with_capacity(fields.len()); + let mut proj_ref_fields = Vec::with_capacity(fields.len()); + for Field { attrs, vis, ident, ty, .. } in fields { + if attrs.find_exact(PIN)?.is_some() { + self.pinned_fields.push(ty.clone()); + + let lifetime = &self.proj.lifetime; + proj_fields.push(quote! { + #vis #ident: ::core::pin::Pin<&#lifetime mut (#ty)> + }); + proj_ref_fields.push(quote! { + #vis #ident: ::core::pin::Pin<&#lifetime (#ty)> + }); + proj_body.push(quote! { + #ident: ::core::pin::Pin::new_unchecked(#ident) + }); + } else { + let lifetime = &self.proj.lifetime; + proj_fields.push(quote! { + #vis #ident: &#lifetime mut (#ty) + }); + proj_ref_fields.push(quote! { + #vis #ident: &#lifetime (#ty) + }); + proj_body.push(quote! { + #ident + }); + } + proj_pat.push(ident); + } + + let proj_pat = quote!({ #(#proj_pat),* }); + let proj_body = quote!({ #(#proj_body),* }); + let proj_fields = quote!({ #(#proj_fields),* }); + let proj_ref_fields = quote!({ #(#proj_ref_fields),* }); + + Ok((proj_pat, proj_body, proj_fields, proj_ref_fields)) + } + + fn visit_unnamed( + &mut self, + FieldsUnnamed { unnamed: fields, .. }: &FieldsUnnamed, + ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> { + let mut proj_pat = Vec::with_capacity(fields.len()); + let mut proj_body = Vec::with_capacity(fields.len()); + let mut proj_fields = Vec::with_capacity(fields.len()); + let mut proj_ref_fields = Vec::with_capacity(fields.len()); + for (i, Field { attrs, vis, ty, .. }) in fields.iter().enumerate() { + let id = format_ident!("_{}", i); + if attrs.find_exact(PIN)?.is_some() { + self.pinned_fields.push(ty.clone()); + + let lifetime = &self.proj.lifetime; + proj_fields.push(quote! { + #vis ::core::pin::Pin<&#lifetime mut (#ty)> + }); + proj_ref_fields.push(quote! { + #vis ::core::pin::Pin<&#lifetime (#ty)> + }); + proj_body.push(quote! { + ::core::pin::Pin::new_unchecked(#id) + }); + } else { + let lifetime = &self.proj.lifetime; + proj_fields.push(quote! { + #vis &#lifetime mut (#ty) + }); + proj_ref_fields.push(quote! { + #vis &#lifetime (#ty) + }); + proj_body.push(quote! { + #id + }); + } + proj_pat.push(id); + } + + let proj_pat = quote!((#(#proj_pat),*)); + let proj_body = quote!((#(#proj_body),*)); + let (proj_fields, proj_ref_fields) = + (quote!((#(#proj_fields),*)), quote!((#(#proj_ref_fields),*))); + + Ok((proj_pat, proj_body, proj_fields, proj_ref_fields)) + } + + /// Creates conditional `Unpin` implementation for original type. + fn make_unpin_impl(&mut self) -> TokenStream { + if let Some(unsafe_unpin) = self.unsafe_unpin { + let mut proj_generics = self.proj.generics.clone(); + let orig_ident = &self.orig.ident; + let lifetime = &self.proj.lifetime; + + let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); + proj_generics.make_where_clause().predicates.push( + // Make the error message highlight `UnsafeUnpin` argument. + syn::parse2(quote_spanned! { unsafe_unpin => + ::pin_project::#private::Wrapper<#lifetime, Self>: ::pin_project::UnsafeUnpin + }) + .unwrap(), + ); + + let (impl_generics, _, where_clause) = proj_generics.split_for_impl(); + let ty_generics = self.orig.generics.split_for_impl().1; + + quote! { + #[allow(single_use_lifetimes)] + impl #impl_generics ::core::marker::Unpin for #orig_ident #ty_generics #where_clause {} + } + } else { + let mut full_where_clause = self.orig.generics.where_clause.as_ref().cloned().unwrap(); + let orig_ident = &self.orig.ident; + + let make_span = || { + #[cfg(pin_project_show_unpin_struct)] + { + proc_macro::Span::def_site().into() + } + #[cfg(not(pin_project_show_unpin_struct))] + { + Span::call_site() + } + }; + + let struct_ident = format_ident!("__{}", orig_ident, span = make_span()); + + // Generate a field in our new struct for every + // pinned field in the original type. + let fields: Vec<_> = self + .pinned_fields + .iter() + .enumerate() + .map(|(i, ty)| { + let field_ident = format_ident!("__field{}", i); + quote! { + #field_ident: #ty + } + }) + .collect(); + + // We could try to determine the subset of type parameters + // and lifetimes that are actually used by the pinned fields + // (as opposed to those only used by unpinned fields). + // However, this would be tricky and error-prone, since + // it's possible for users to create types that would alias + // with generic parameters (e.g. 'struct T'). + // + // Instead, we generate a use of every single type parameter + // and lifetime used in the original struct. For type parameters, + // we generate code like this: + // + // ```rust + // struct AlwaysUnpin<T: ?Sized>(PhantomData<T>) {} + // impl<T: ?Sized> Unpin for AlwaysUnpin<T> {} + // + // ... + // _field: AlwaysUnpin<(A, B, C)> + // ``` + // + // This ensures that any unused type parameters + // don't end up with Unpin bounds. + let lifetime_fields: Vec<_> = self + .orig + .generics + .lifetimes() + .enumerate() + .map(|(i, LifetimeDef { lifetime, .. })| { + let field_ident = format_ident!("__lifetime{}", i); + quote! { + #field_ident: &#lifetime () + } + }) + .collect(); + + let scope_ident = format_ident!("__unpin_scope_{}", orig_ident); + + let vis = &self.orig.vis; + let lifetime = &self.proj.lifetime; + let type_params: Vec<_> = self.orig.generics.type_params().map(|t| &t.ident).collect(); + let proj_generics = &self.proj.generics; + let (impl_generics, proj_ty_generics, _) = proj_generics.split_for_impl(); + let (_, ty_generics, where_clause) = self.orig.generics.split_for_impl(); + + full_where_clause.predicates.push(syn::parse_quote! { + #struct_ident #proj_ty_generics: ::core::marker::Unpin + }); + + let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); + let inner_data = quote! { + // This needs to have the same visibility as the original type, + // due to the limitations of the 'public in private' error. + // + // Out goal is to implement the public trait Unpin for + // a potentially public user type. Because of this, rust + // requires that any types mentioned in the where clause of + // our Unpin impl also be public. This means that our generated + // 'UnpinStruct' type must also be public. However, we take + // steps to ensure that the user can never actually reference + // this 'public' type. These steps are described below. + // + // See also https://github.com/taiki-e/pin-project/pull/53. + #vis struct #struct_ident #proj_generics #where_clause { + __pin_project_use_generics: ::pin_project::#private::AlwaysUnpin<#lifetime, (#(#type_params),*)>, + + #(#fields,)* + #(#lifetime_fields,)* + } + + impl #impl_generics ::core::marker::Unpin for #orig_ident #ty_generics #full_where_clause {} + }; + + if cfg!(pin_project_show_unpin_struct) { + // On nightly, we use def-site hygiene to make it impossible + // for user code to refer to any of the types we define. + // This allows us to omit wrapping the generated types + // in an fn() scope, allowing rustdoc to properly document + // them. + inner_data + } else { + // When we're not on nightly, we need to create an enclosing fn() scope + // for all of our generated items. This makes it impossible for + // user code to refer to any of our generated types, but has + // the advantage of preventing Rustdoc from displaying + // docs for any of our types. In particular, users cannot see + // the automatically generated Unpin impl for the 'UnpinStruct$Name' types. + quote! { + #[allow(non_snake_case)] + fn #scope_ident() { + #inner_data + } + } + } + } + } + + /// Creates `Drop` implementation for original type. + fn make_drop_impl(&self) -> TokenStream { + let ident = &self.orig.ident; + let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl(); + + let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); + if let Some(pinned_drop) = self.pinned_drop { + // Make the error message highlight `PinnedDrop` argument. + // See https://github.com/taiki-e/pin-project/issues/16#issuecomment-513586812 + // for why this is only for the span of function calls, not the entire `impl` block. + let call_drop = quote_spanned! { pinned_drop => + ::pin_project::#private::PinnedDrop::drop(pinned_self) + }; + + quote! { + #[allow(single_use_lifetimes)] + impl #impl_generics ::core::ops::Drop for #ident #ty_generics #where_clause { + fn drop(&mut self) { + // Safety - we're in 'drop', so we know that 'self' will + // never move again. + let pinned_self = unsafe { ::core::pin::Pin::new_unchecked(self) }; + // We call `pinned_drop` only once. Since `PinnedDrop::drop` + // is an unsafe function and a private API, it is never called again in safe + // code *unless the user uses a maliciously crafted macro*. + unsafe { + #call_drop; + } + } + } + } + } else { + // If the user does not provide a pinned_drop impl, + // we need to ensure that they don't provide a `Drop` impl of their + // own. + // Based on https://github.com/upsuper/assert-impl/blob/f503255b292ab0ba8d085b657f4065403cfa46eb/src/lib.rs#L80-L87 + // + // We create a new identifier for each struct, so that the traits + // for different types do not conflict with each other. + // + // Another approach would be to provide an empty Drop impl, + // which would conflict with a user-provided Drop impl. + // However, this would trigger the compiler's special handling + // of Drop types (e.g. fields cannot be moved out of a Drop type). + // This approach prevents the creation of needless Drop impls, + // giving users more flexibility. + let trait_ident = format_ident!("{}MustNotImplDrop", ident); + + quote! { + // There are two possible cases: + // 1. The user type does not implement Drop. In this case, + // the first blanked impl will not apply to it. This code + // will compile, as there is only one impl of MustNotImplDrop for the user type + // 2. The user type does impl Drop. This will make the blanket impl applicable, + // which will then conflict with the explicit MustNotImplDrop impl below. + // This will result in a compilation error, which is exactly what we want. + trait #trait_ident {} + #[allow(clippy::drop_bounds)] + impl<T: ::core::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. + // Since the user did not pass `PinnedDrop` to `#[pin_project]`, any `PinnedDrop` + // impl will not actually be called. Unfortunately, we can't detect this situation + // directly from either the `#[pin_project]` or `#[pinned_drop]` attributes, since + // we don't know what other attirbutes/impl may exist. + // + // To ensure that users don't accidentally write a non-functional `PinnedDrop` + // 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: ::core::pin::Pin<&mut Self>) {} + } + } + } + } + + /// Creates an implementation of the projection method. + fn make_proj_impl(&self, proj_body: &TokenStream, proj_ref_body: &TokenStream) -> TokenStream { + let vis = &self.proj.vis; + let lifetime = &self.proj.lifetime; + let orig_ident = &self.orig.ident; + let proj_ident = &self.proj.mut_ident; + let proj_ref_ident = &self.proj.ref_ident; + + let proj_ty_generics = self.proj.generics.split_for_impl().1; + let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl(); + + quote! { + impl #impl_generics #orig_ident #ty_generics #where_clause { + #vis fn project<#lifetime>( + self: ::core::pin::Pin<&#lifetime mut Self>, + ) -> #proj_ident #proj_ty_generics { + unsafe { + #proj_body + } + } + #vis fn project_ref<#lifetime>( + self: ::core::pin::Pin<&#lifetime Self>, + ) -> #proj_ref_ident #proj_ty_generics { + unsafe { + #proj_ref_body + } + } + } + } + } + + fn ensure_not_packed(&self, fields: &Fields) -> Result<TokenStream> { + for meta in self.orig.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) { + if let Meta::List(l) = meta { + if l.path.is_ident("repr") { + for repr in l.nested.iter() { + match repr { + NestedMeta::Meta(Meta::Path(path)) + | NestedMeta::Meta(Meta::List(MetaList { path, .. })) + if path.is_ident("packed") => + { + return Err(error!( + repr, + "#[pin_project] attribute may not be used on #[repr(packed)] types" + )); + } + _ => {} + } + } + } + } + } + + // As proc-macro-derive can't rewrite the structure definition, + // it's probably no longer necessary, but it keeps it for now. + + // Workaround for https://github.com/taiki-e/pin-project/issues/32 + // Through the tricky use of proc macros, it's possible to bypass + // the above check for the 'repr' attribute. + // To ensure that it's impossible to use pin projections on a #[repr(packed)] + // struct, we generate code like this: + // + // #[deny(safe_packed_borrows)] + // fn enforce_not_packed_for_MyStruct(val: &MyStruct) { + // let _field1 = &val.field1; + // let _field2 = &val.field2; + // ... + // let _fieldn = &val.fieldn; + // } + // + // Taking a reference to a packed field is unsafe, and applying + // #[deny(safe_packed_borrows)] makes sure that doing this without + // an 'unsafe' block (which we deliberately do not generate) + // is a hard error. + // + // If the struct ends up having #[repr(packed)] applied somehow, + // this will generate an (unfriendly) error message. Under all reasonable + // circumstances, we'll detect the #[repr(packed)] attribute, and generate + // a much nicer error above. + // + // There is one exception: If the type of a struct field has an alignment of 1 + // (e.g. u8), it is always safe to take a reference to it, even if the struct + // is #[repr(packed)]. If the struct is composed entirely of types of alignment 1, + // our generated method will not trigger an error if the struct is #[repr(packed)] + // + // Fortunately, this should have no observable consequence - #[repr(packed)] + // is essentially a no-op on such a type. Nevertheless, we include a test + // to ensure that the compiler doesn't ever try to copy the fields on + // such a struct when trying to drop it - which is reason we prevent + // #[repr(packed)] in the first place. + // + // See also https://github.com/taiki-e/pin-project/pull/34. + let mut field_refs = vec![]; + match fields { + Fields::Named(FieldsNamed { named, .. }) => { + for Field { ident, .. } in named { + field_refs.push(quote! { + &val.#ident; + }); + } + } + Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => { + for (index, _) in unnamed.iter().enumerate() { + let index = Index::from(index); + field_refs.push(quote! { + &val.#index; + }); + } + } + Fields::Unit => {} + } + + let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl(); + + let struct_name = &self.orig.ident; + let method_name = format_ident!("__pin_project_assert_not_repr_packed_{}", self.orig.ident); + Ok(quote! { + #[allow(single_use_lifetimes)] + #[allow(non_snake_case)] + #[deny(safe_packed_borrows)] + fn #method_name #impl_generics (val: &#struct_name #ty_generics) #where_clause { + #(#field_refs)* + } + }) + } +} diff --git a/third_party/rust/pin-project-internal/src/pin_project/mod.rs b/third_party/rust/pin-project-internal/src/pin_project/mod.rs new file mode 100644 index 0000000000..e8d83aacf7 --- /dev/null +++ b/third_party/rust/pin-project-internal/src/pin_project/mod.rs @@ -0,0 +1,15 @@ +use proc_macro2::TokenStream; + +mod attribute; +mod derive; + +/// The annotation for pinned type. +const PIN: &str = "pin"; + +pub(crate) fn attribute(args: &TokenStream, input: TokenStream) -> TokenStream { + attribute::parse_attribute(args, input).unwrap_or_else(|e| e.to_compile_error()) +} + +pub(crate) fn derive(input: TokenStream) -> TokenStream { + derive::parse_derive(input).unwrap_or_else(|e| e.to_compile_error()) +} diff --git a/third_party/rust/pin-project-internal/src/pinned_drop.rs b/third_party/rust/pin-project-internal/src/pinned_drop.rs new file mode 100644 index 0000000000..11cc37dc50 --- /dev/null +++ b/third_party/rust/pin-project-internal/src/pinned_drop.rs @@ -0,0 +1,199 @@ +use proc_macro2::{Span, TokenStream}; +use quote::{quote, quote_spanned, ToTokens}; +use syn::{spanned::Spanned, visit_mut::VisitMut, *}; + +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)) { + let self_ty = &input.self_ty; + let (impl_generics, _, where_clause) = input.generics.split_for_impl(); + + let mut tokens = e.to_compile_error(); + let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); + // Generate a dummy `PinnedDrop` implementation. + // 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: ::core::pin::Pin<&mut Self>) {} + } + }); + tokens + } else { + input.into_token_stream() + } +} + +fn parse_method(method: &ImplItemMethod) -> Result<()> { + fn get_ty_path(ty: &Type) -> Option<&Path> { + if let Type::Path(TypePath { qself: None, path }) = ty { Some(path) } else { None } + } + + const INVALID_ARGUMENT: &str = "method `drop` must take an argument `self: Pin<&mut Self>`"; + + if method.sig.ident != "drop" { + return Err(error!( + method.sig.ident, + "method `{}` is not a member of trait `PinnedDrop", method.sig.ident, + )); + } + + if let ReturnType::Type(_, ty) = &method.sig.output { + match &**ty { + Type::Tuple(TypeTuple { elems, .. }) if elems.is_empty() => {} + _ => return Err(error!(ty, "method `drop` must return the unit type")), + } + } + + if method.sig.inputs.len() != 1 { + if method.sig.inputs.is_empty() { + return Err(syn::Error::new(method.sig.paren_token.span, INVALID_ARGUMENT)); + } else { + return Err(error!(&method.sig.inputs, INVALID_ARGUMENT)); + } + } + + if let FnArg::Typed(PatType { pat, ty, .. }) = &method.sig.inputs[0] { + // !by_ref (mutability) ident !subpat: path + if let (Pat::Ident(PatIdent { by_ref: None, ident, subpat: None, .. }), Some(path)) = + (&**pat, get_ty_path(ty)) + { + let ty = &path.segments.last().unwrap(); + if let PathArguments::AngleBracketed(args) = &ty.arguments { + // (mut) self: (path::)Pin<args> + if ident == "self" && args.args.len() == 1 && ty.ident == "Pin" { + // &mut <elem> + if let GenericArgument::Type(Type::Reference(TypeReference { + mutability: Some(_), + elem, + .. + })) = &args.args[0] + { + if get_ty_path(elem).map_or(false, |path| path.is_ident("Self")) { + if method.sig.unsafety.is_some() { + return Err(error!( + method.sig.unsafety, + "implementing the method `drop` is not unsafe" + )); + } + return Ok(()); + } + } + } + } + } + } + + Err(error!(method.sig.inputs[0], INVALID_ARGUMENT)) +} + +fn parse(item: &mut ItemImpl) -> Result<()> { + if let Some((_, path, _)) = &mut item.trait_ { + if path.is_ident("PinnedDrop") { + let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); + *path = syn::parse2(quote_spanned! { path.span() => + ::pin_project::#private::PinnedDrop + }) + .unwrap(); + } else { + return Err(error!( + path, + "#[pinned_drop] may only be used on implementation for the `PinnedDrop` trait" + )); + } + } else { + return Err(error!( + item.self_ty, + "#[pinned_drop] may only be used on implementation for the `PinnedDrop` trait" + )); + } + + if item.unsafety.is_some() { + return Err(error!(item.unsafety, "implementing the trait `PinnedDrop` is not unsafe")); + } + if item.items.is_empty() { + return Err(error!(item, "not all trait items implemented, missing: `drop`")); + } + + for (i, item) in item.items.iter().enumerate() { + match item { + ImplItem::Const(item) => { + return Err(error!( + item, + "const `{}` is not a member of trait `PinnedDrop`", item.ident + )); + } + ImplItem::Type(item) => { + return Err(error!( + item, + "type `{}` is not a member of trait `PinnedDrop`", item.ident + )); + } + ImplItem::Method(method) => { + parse_method(method)?; + if i != 0 { + return Err(error!(method, "duplicate definitions with name `drop`")); + } + } + _ => parse_as_empty(&item.to_token_stream())?, + } + } + + expand_item(item); + + Ok(()) +} + +// from: +// +// fn drop(self: Pin<&mut Self>) { +// // something +// } +// +// into: +// +// unsafe fn drop(self: Pin<&mut Self>) { +// fn __drop_inner<T>(__self: Pin<&mut Foo<'_, T>>) { +// // something +// } +// __drop_inner(self); +// } +// +fn expand_item(item: &mut ItemImpl) { + let method = + if let ImplItem::Method(method) = &mut item.items[0] { method } else { unreachable!() }; + let mut drop_inner = method.clone(); + + // `fn drop(mut self: Pin<&mut Self>)` -> `fn __drop_inner<T>(mut __self: Pin<&mut Receiver>)` + drop_inner.sig.ident = Ident::new("__drop_inner", drop_inner.sig.ident.span()); + drop_inner.sig.generics = item.generics.clone(); + if let FnArg::Typed(arg) = &mut drop_inner.sig.inputs[0] { + if let Pat::Ident(ident) = &mut *arg.pat { + prepend_underscore_to_self(&mut ident.ident); + } + } + let mut visitor = ReplaceReceiver::new(&item.self_ty); + visitor.visit_signature_mut(&mut drop_inner.sig); + visitor.visit_block_mut(&mut drop_inner.block); + + // `fn drop(mut self: Pin<&mut Self>)` -> `unsafe fn drop(self: Pin<&mut Self>)` + method.sig.unsafety = Some(token::Unsafe::default()); + if let FnArg::Typed(arg) = &mut method.sig.inputs[0] { + if let Pat::Ident(ident) = &mut *arg.pat { + ident.mutability = None; + } + } + + method.block = syn::parse_quote! {{ + #drop_inner + __drop_inner(self); + }}; +} diff --git a/third_party/rust/pin-project-internal/src/project.rs b/third_party/rust/pin-project-internal/src/project.rs new file mode 100644 index 0000000000..92627d435b --- /dev/null +++ b/third_party/rust/pin-project-internal/src/project.rs @@ -0,0 +1,286 @@ +use proc_macro2::{Span, TokenStream}; +use quote::ToTokens; +use syn::{ + visit_mut::{self, VisitMut}, + *, +}; + +use crate::utils::*; + +pub(crate) fn attribute(args: &TokenStream, input: Stmt, mutability: Mutability) -> TokenStream { + parse_as_empty(args) + .and_then(|()| parse(input, mutability)) + .unwrap_or_else(|e| e.to_compile_error()) +} + +fn replace_stmt(stmt: &mut Stmt, mutability: Mutability) -> Result<()> { + match stmt { + Stmt::Expr(Expr::Match(expr)) | Stmt::Semi(Expr::Match(expr), _) => { + Context::new(mutability).replace_expr_match(expr); + } + Stmt::Expr(Expr::If(expr_if)) => { + let mut expr_if = expr_if; + while let Expr::Let(ref mut expr) = &mut *expr_if.cond { + Context::new(mutability).replace_expr_let(expr); + if let Some((_, ref mut expr)) = expr_if.else_branch { + if let Expr::If(new_expr_if) = &mut **expr { + expr_if = new_expr_if; + continue; + } + } + break; + } + } + Stmt::Local(local) => Context::new(mutability).replace_local(local)?, + _ => {} + } + Ok(()) +} + +fn parse(mut stmt: Stmt, mutability: Mutability) -> Result<TokenStream> { + replace_stmt(&mut stmt, mutability)?; + match &mut stmt { + Stmt::Item(Item::Fn(item)) => replace_item_fn(item, mutability)?, + Stmt::Item(Item::Impl(item)) => replace_item_impl(item, mutability), + Stmt::Item(Item::Use(item)) => replace_item_use(item, mutability)?, + _ => {} + } + + Ok(stmt.into_token_stream()) +} + +struct Context { + register: Option<(Ident, usize)>, + replaced: bool, + mutability: Mutability, +} + +impl Context { + fn new(mutability: Mutability) -> Self { + Self { register: None, replaced: false, mutability } + } + + fn update(&mut self, ident: &Ident, len: usize) { + if self.register.is_none() { + self.register = Some((ident.clone(), len)); + } + } + + fn compare_paths(&self, ident: &Ident, len: usize) -> bool { + match &self.register { + Some((i, l)) => *l == len && ident == i, + None => false, + } + } + + fn replace_local(&mut self, local: &mut Local) -> Result<()> { + if let Some(Expr::Match(expr)) = local.init.as_mut().map(|(_, expr)| &mut **expr) { + self.replace_expr_match(expr); + } + + if self.replaced { + if is_replaceable(&local.pat, false) { + return Err(error!( + local.pat, + "Both initializer expression and pattern are replaceable, \ + you need to split the initializer expression into separate let bindings \ + to avoid ambiguity" + )); + } + } else { + self.replace_pat(&mut local.pat, false); + } + + Ok(()) + } + + fn replace_expr_let(&mut self, expr: &mut ExprLet) { + self.replace_pat(&mut expr.pat, true) + } + + fn replace_expr_match(&mut self, expr: &mut ExprMatch) { + expr.arms.iter_mut().for_each(|Arm { pat, .. }| self.replace_pat(pat, true)) + } + + fn replace_pat(&mut self, pat: &mut Pat, allow_pat_path: bool) { + match pat { + Pat::Ident(PatIdent { subpat: Some((_, pat)), .. }) + | Pat::Reference(PatReference { pat, .. }) + | Pat::Box(PatBox { pat, .. }) + | Pat::Type(PatType { pat, .. }) => self.replace_pat(pat, allow_pat_path), + + Pat::Or(PatOr { cases, .. }) => { + cases.iter_mut().for_each(|pat| self.replace_pat(pat, allow_pat_path)) + } + + Pat::Struct(PatStruct { path, .. }) | Pat::TupleStruct(PatTupleStruct { path, .. }) => { + self.replace_path(path) + } + Pat::Path(PatPath { qself: None, path, .. }) if allow_pat_path => { + self.replace_path(path) + } + _ => {} + } + } + + fn replace_path(&mut self, path: &mut Path) { + let len = match path.segments.len() { + // 1: struct + // 2: enum + len @ 1 | len @ 2 => len, + // other path + _ => return, + }; + + if self.register.is_none() || self.compare_paths(&path.segments[0].ident, len) { + self.update(&path.segments[0].ident, len); + self.replaced = true; + replace_ident(&mut path.segments[0].ident, self.mutability); + } + } +} + +fn is_replaceable(pat: &Pat, allow_pat_path: bool) -> bool { + match pat { + Pat::Ident(PatIdent { subpat: Some((_, pat)), .. }) + | Pat::Reference(PatReference { pat, .. }) + | Pat::Box(PatBox { pat, .. }) + | Pat::Type(PatType { pat, .. }) => is_replaceable(pat, allow_pat_path), + + Pat::Or(PatOr { cases, .. }) => cases.iter().any(|pat| is_replaceable(pat, allow_pat_path)), + + Pat::Struct(_) | Pat::TupleStruct(_) => true, + Pat::Path(PatPath { qself: None, .. }) => allow_pat_path, + _ => false, + } +} + +fn replace_item_impl(item: &mut ItemImpl, mutability: Mutability) { + let PathSegment { ident, arguments } = match &mut *item.self_ty { + Type::Path(TypePath { qself: None, path }) => path.segments.last_mut().unwrap(), + _ => return, + }; + + replace_ident(ident, mutability); + + let mut lifetime_name = String::from(DEFAULT_LIFETIME_NAME); + determine_lifetime_name(&mut lifetime_name, &item.generics.params); + 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)); + let lifetime = Lifetime::new(&lifetime_name, Span::call_site()); + + insert_lifetime(&mut item.generics, lifetime.clone()); + + match arguments { + PathArguments::None => { + *arguments = PathArguments::AngleBracketed(syn::parse_quote!(<#lifetime>)); + } + PathArguments::AngleBracketed(args) => { + args.args.insert(0, syn::parse_quote!(#lifetime)); + } + PathArguments::Parenthesized(_) => unreachable!(), + } +} + +fn replace_item_fn(item: &mut ItemFn, mutability: Mutability) -> Result<()> { + let mut visitor = FnVisitor { res: Ok(()), mutability }; + visitor.visit_block_mut(&mut item.block); + visitor.res +} + +fn replace_item_use(item: &mut ItemUse, mutability: Mutability) -> Result<()> { + let mut visitor = UseTreeVisitor { res: Ok(()), mutability }; + visitor.visit_item_use_mut(item); + visitor.res +} + +fn replace_ident(ident: &mut Ident, mutability: Mutability) { + *ident = proj_ident(ident, mutability); +} + +// ================================================================================================= +// visitors + +struct FnVisitor { + res: Result<()>, + mutability: Mutability, +} + +impl FnVisitor { + /// Returns the attribute name. + fn name(&self) -> &str { + if self.mutability == Mutable { "project" } else { "project_ref" } + } + + fn visit_stmt(&mut self, node: &mut Stmt) -> Result<()> { + let attr = match node { + Stmt::Expr(Expr::Match(expr)) | Stmt::Semi(Expr::Match(expr), _) => { + expr.attrs.find_remove(self.name())? + } + Stmt::Local(local) => local.attrs.find_remove(self.name())?, + Stmt::Expr(Expr::If(expr_if)) => { + if let Expr::Let(_) = &*expr_if.cond { + expr_if.attrs.find_remove(self.name())? + } else { + None + } + } + _ => return Ok(()), + }; + if let Some(attr) = attr { + parse_as_empty(&attr.tokens)?; + replace_stmt(node, self.mutability)?; + } + Ok(()) + } +} + +impl VisitMut for FnVisitor { + fn visit_stmt_mut(&mut self, node: &mut Stmt) { + if self.res.is_err() { + return; + } + + visit_mut::visit_stmt_mut(self, node); + + if let Err(e) = self.visit_stmt(node) { + self.res = Err(e) + } + } + + fn visit_item_mut(&mut self, _: &mut Item) { + // Do not recurse into nested items. + } +} + +struct UseTreeVisitor { + res: Result<()>, + mutability: Mutability, +} + +impl VisitMut for UseTreeVisitor { + fn visit_use_tree_mut(&mut self, node: &mut UseTree) { + if self.res.is_err() { + return; + } + + match node { + // Desugar `use tree::<name>` into `tree::__<name>Projection`. + UseTree::Name(name) => replace_ident(&mut name.ident, self.mutability), + UseTree::Glob(glob) => { + self.res = + Err(error!(glob, "#[project] attribute may not be used on glob imports")); + } + UseTree::Rename(rename) => { + // TODO: Consider allowing the projected type to be renamed by `#[project] use Foo as Bar`. + self.res = + Err(error!(rename, "#[project] attribute may not be used on renamed imports")); + } + node @ UseTree::Path(_) | node @ UseTree::Group(_) => { + visit_mut::visit_use_tree_mut(self, node) + } + } + } +} diff --git a/third_party/rust/pin-project-internal/src/utils.rs b/third_party/rust/pin-project-internal/src/utils.rs new file mode 100644 index 0000000000..1890afcf36 --- /dev/null +++ b/third_party/rust/pin-project-internal/src/utils.rs @@ -0,0 +1,339 @@ +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}, + *, +}; + +pub(crate) const DEFAULT_LIFETIME_NAME: &str = "'pin"; +pub(crate) const CURRENT_PRIVATE_MODULE: &str = "__private"; + +pub(crate) type Variants = Punctuated<Variant, token::Comma>; + +pub(crate) use Mutability::{Immutable, Mutable}; + +macro_rules! error { + ($span:expr, $msg:expr) => { + syn::Error::new_spanned(&$span, $msg) + }; + ($span:expr, $($tt:tt)*) => { + error!($span, format!($($tt)*)) + }; +} + +#[derive(Clone, Copy, Eq, PartialEq)] +pub(crate) enum Mutability { + Mutable, + Immutable, +} + +/// Creates the ident of projected type from the ident of the original type. +pub(crate) fn proj_ident(ident: &Ident, mutability: Mutability) -> Ident { + if mutability == Mutable { + format_ident!("__{}Projection", ident) + } else { + format_ident!("__{}ProjectionRef", 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, 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)) { + lifetime_name.push('_'); + } +} + +/// Like `insert_lifetime`, but also generates a bound of the form +/// `OriginalType<A, B>: 'lifetime`. Used when generating the definition +/// of a projection type +pub(crate) fn insert_lifetime_and_bound( + generics: &mut Generics, + lifetime: Lifetime, + orig_generics: &Generics, + orig_ident: Ident, +) -> WherePredicate { + insert_lifetime(generics, lifetime.clone()); + + let orig_type: syn::Type = syn::parse_quote!(#orig_ident #orig_generics); + let mut punct = Punctuated::new(); + punct.push(TypeParamBound::Lifetime(lifetime)); + + WherePredicate::Type(PredicateType { + lifetimes: None, + bounded_ty: orig_type, + colon_token: syn::token::Colon::default(), + bounds: punct, + }) +} + +/// Inserts a `lifetime` at position `0` of `generics.params`. +pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) { + if generics.lt_token.is_none() { + generics.lt_token = Some(token::Lt::default()) + } + if generics.gt_token.is_none() { + generics.gt_token = Some(token::Gt::default()) + } + + generics.params.insert( + 0, + GenericParam::Lifetime(LifetimeDef { + attrs: Vec::new(), + lifetime, + colon_token: None, + bounds: Punctuated::new(), + }), + ); +} + +/// Determines the visibility of the projected type and projection method. +pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility { + if let Visibility::Public(token) = vis { + syn::parse2(quote_spanned! { token.pub_token.span => + pub(crate) + }) + .unwrap() + } else { + vis.clone() + } +} + +/// Check if `tokens` is an empty `TokenStream`. +/// This is almost equivalent to `syn::parse2::<Nothing>()`, +/// but produces a better error message and does not require ownership of `tokens`. +pub(crate) fn parse_as_empty(tokens: &TokenStream) -> Result<()> { + if tokens.is_empty() { Ok(()) } else { Err(error!(tokens, "unexpected token: {}", tokens)) } +} + +// ================================================================================================= +// extension traits + +pub(crate) trait SliceExt { + fn position_exact(&self, ident: &str) -> Result<Option<usize>>; + fn find(&self, ident: &str) -> Option<&Attribute>; + fn find_exact(&self, ident: &str) -> Result<Option<&Attribute>>; +} + +pub(crate) trait VecExt { + fn find_remove(&mut self, ident: &str) -> Result<Option<Attribute>>; +} + +impl SliceExt for [Attribute] { + fn position_exact(&self, ident: &str) -> Result<Option<usize>> { + self.iter() + .try_fold((0, None), |(i, mut prev), attr| { + if attr.path.is_ident(ident) { + if prev.is_some() { + return Err(error!(attr, "duplicate #[{}] attribute", ident)); + } + parse_as_empty(&attr.tokens)?; + prev = Some(i); + } + Ok((i + 1, prev)) + }) + .map(|(_, pos)| pos) + } + + fn find(&self, ident: &str) -> Option<&Attribute> { + self.iter().position(|attr| attr.path.is_ident(ident)).and_then(|i| self.get(i)) + } + + fn find_exact(&self, ident: &str) -> Result<Option<&Attribute>> { + self.position_exact(ident).map(|pos| pos.and_then(|i| self.get(i))) + } +} + +impl VecExt for Vec<Attribute> { + fn find_remove(&mut self, ident: &str) -> Result<Option<Attribute>> { + self.position_exact(ident).map(|pos| pos.map(|i| self.remove(i))) + } +} + +pub(crate) trait ParseBufferExt<'a> { + fn parenthesized(self) -> Result<ParseBuffer<'a>>; +} + +impl<'a> ParseBufferExt<'a> for ParseStream<'a> { + fn parenthesized(self) -> Result<ParseBuffer<'a>> { + let content; + let _: token::Paren = syn::parenthesized!(content in self); + Ok(content) + } +} + +impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> { + fn parenthesized(self) -> Result<ParseBuffer<'a>> { + let content; + let _: token::Paren = syn::parenthesized!(content in self); + Ok(content) + } +} + +// ================================================================================================= +// visitors + +// 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<QSelf>, 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(token::Colon2::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` -> `<Receiver>::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` -> `<Receiver>::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()); + } +} |