Bug 1836420 - Upgrade extend to 1.2.0. r=emilio,supply-chain-reviewers

Differential Revision: https://phabricator.services.mozilla.com/D179757
This commit is contained in:
Mike Hommey 2023-06-05 22:49:52 +00:00
parent 8ba840c3b8
commit 1991d34ad4
11 changed files with 183 additions and 141 deletions

7
Cargo.lock generated
View File

@ -1525,14 +1525,13 @@ dependencies = [
[[package]] [[package]]
name = "extend" name = "extend"
version = "1.1.2" version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c5216e387a76eebaaf11f6d871ec8a4aae0b25f05456ee21f228e024b1b3610" checksum = "311a6d2f1f9d60bff73d2c78a0af97ed27f79672f15c238192a5bbb64db56d00"
dependencies = [ dependencies = [
"proc-macro-error",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.107", "syn 2.0.18",
] ]
[[package]] [[package]]

View File

@ -1154,6 +1154,11 @@ criteria = "safe-to-deploy"
version = "1.1.2" version = "1.1.2"
notes = "Inspected the crate and noted that the impl block comes directly from the proc-macro input. If no new code can be added by this crate, I don't think there can be any issues." notes = "Inspected the crate and noted that the impl block comes directly from the proc-macro input. If no new code can be added by this crate, I don't think there can be any issues."
[[audits.extend]]
who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy"
delta = "1.1.2 -> 1.2.0"
[[audits.fallible_collections]] [[audits.fallible_collections]]
who = "Mike Hommey <mh+mozilla@glandium.org>" who = "Mike Hommey <mh+mozilla@glandium.org>"
criteria = "safe-to-deploy" criteria = "safe-to-deploy"

View File

@ -1 +1 @@
{"files":{"CHANGELOG.md":"910cd2057d356b18cd4f21791bc23956734a83b0f58701ec0d0d03405f5c21df","Cargo.toml":"928b8b97607b3589b85a6d4d00fb1cf64b78bee6354c303d8f49fbfa2ca5bdae","LICENSE":"db0efd0bb80126f32214f478434536d07d86a30658fb209d8b543b7261492a2b","README.md":"0872b2b15ec22732a09b121a31cdd8f8cfc80566f671566e4a7fb6b52a742a2e","deny.toml":"60448e9313f1883a7adf30713fcca789c454e77228105926024ce3abe9293100","rustfmt.toml":"9bbb759b3914c49c8060bcdeeb7786f4aec083d30bcfe236bbd48d8388d06103","src/lib.rs":"85bd23c064c78dcd141cb2fecca6fff2ee7e1dfb4cf19b74ab97ef30d51f6f03","tests/compile_fail/double_vis.rs":"524e8bc996f5a45de3d15f0c741d4f3414004e9c636c52de0f011785cc535109","tests/compile_fail/double_vis.stderr":"3748e67e6f41bd5624946ad7cdc4e2b30a9d0b5e76bc27c19ecc9d62da733978","tests/compile_fail/supertraits_are_actually_included.rs":"c03980316c4e71ceb7e80ab7011f00b6f1f8f89906670e9823267a4118f72853","tests/compile_fail/supertraits_are_actually_included.stderr":"835e79bb1bceb48e9db5f0a410c57af51c856e17917ef72f65e3ae2af79d97ec","tests/compile_pass/associated_constants.rs":"f3e56405650ddd31c33e932846553e88fe7181585e0f09a7414d50d521b0f103","tests/compile_pass/async_trait.rs":"9138801d67dbe20ed87fdb3f48bb968f0bfa11fe2d27414d5ea5ea7a6e44bb35","tests/compile_pass/changing_extension_trait_name.rs":"046e7a66151ce05c3515b4bea36be72f83b98f3bdb06fa6f065ad6fc373e19f2","tests/compile_pass/complex_trait_name.rs":"5a8c3588c26df07973739fbb85619d0de480cc8c992611dfc2dbcb9ab3c6e2b6","tests/compile_pass/double_ext_on_same_type.rs":"0e4d16fe9059f0325e4ad1337d53738876633b0533f9a2d4e9714ddada96eb4d","tests/compile_pass/extension_on_complex_types.rs":"88bdf979e1f399d7f9824165730b33884bc9c46347d246f8cc12e0e2039642a1","tests/compile_pass/generics.rs":"367f089e8010d1c98ccc975b03acb6cf03810793e1198105f75c006eafd52bb8","tests/compile_pass/hello_world.rs":"1961cfa634143974f0d64b26f817ac3148375faa5cf5864d63f0127d3af8099e","tests/compile_pass/issue_2.rs":"a14d5e2179b74ff71c5357e8a4f1a9ac228a711196edd40c12719565c8dfaa21","tests/compile_pass/more_than_one_extension.rs":"1d7486e4e9e4095d7e7f42aac878d836f021c49fbe26c31cb13fe6a0415a8558","tests/compile_pass/multiple_config.rs":"dc3b06e4fafbb7236b5bc49f9a5e9693241c07118da8886dd0752b895ff27425","tests/compile_pass/multiple_generic_params.rs":"2ac052ea7b818b6d45ee8070cf6ec18953419473f711375cafbe7283244b5743","tests/compile_pass/pub_impl.rs":"8dfcba21fbbc45efcf85b66fca2d187022569e72d4b10b57047eddda67a1725b","tests/compile_pass/ref_and_ref_mut.rs":"d1086a23809cbd8f87487677073238c3657a8a98fafc63a688eb9d622bf2eb11","tests/compile_pass/sized.rs":"baceaaabcf368b3c72e6d27fea72aadde11d97d9d153c35df5e2d89fb3da4e3e","tests/compile_pass/super_trait.rs":"07448e1fe2b9018125ccaabf7db1e2a244788519bb42117f8e437e48358eb2f0","tests/compile_pass/visibility_config.rs":"64846014a63327661fb250cdb726cce532ed82b1cea5cb83308526bcba22b4be"},"package":"5c5216e387a76eebaaf11f6d871ec8a4aae0b25f05456ee21f228e024b1b3610"} {"files":{"CHANGELOG.md":"7f91119554e4587936d7e431dae1b7b77c677230809615ad81e931477e7b7013","Cargo.toml":"fa01cfc6e053fa0072da1ad9e413a147a4f2cfee53a529de57a7c44ce858ad13","LICENSE":"db0efd0bb80126f32214f478434536d07d86a30658fb209d8b543b7261492a2b","README.md":"0872b2b15ec22732a09b121a31cdd8f8cfc80566f671566e4a7fb6b52a742a2e","deny.toml":"5896a0134be617fcfbde7680ae65f0d8bbb14e7250588f27d8bff347f7bd59d3","src/lib.rs":"6128d331b2ee8fb6261548387b691c633b515a3d6dec1533cac69035676c11ef","tests/compile_fail/double_vis.rs":"524e8bc996f5a45de3d15f0c741d4f3414004e9c636c52de0f011785cc535109","tests/compile_fail/double_vis.stderr":"3748e67e6f41bd5624946ad7cdc4e2b30a9d0b5e76bc27c19ecc9d62da733978","tests/compile_fail/supertraits_are_actually_included.rs":"c03980316c4e71ceb7e80ab7011f00b6f1f8f89906670e9823267a4118f72853","tests/compile_fail/supertraits_are_actually_included.stderr":"d88d744cd810a58b3f7a4495ecb020604ddc1badfb765a7b13bd38ba1ba0f243","tests/compile_pass/associated_constants.rs":"f3e56405650ddd31c33e932846553e88fe7181585e0f09a7414d50d521b0f103","tests/compile_pass/async_trait.rs":"9138801d67dbe20ed87fdb3f48bb968f0bfa11fe2d27414d5ea5ea7a6e44bb35","tests/compile_pass/changing_extension_trait_name.rs":"046e7a66151ce05c3515b4bea36be72f83b98f3bdb06fa6f065ad6fc373e19f2","tests/compile_pass/complex_trait_name.rs":"5a8c3588c26df07973739fbb85619d0de480cc8c992611dfc2dbcb9ab3c6e2b6","tests/compile_pass/destructure.rs":"274b1c97ecce02fd3412a4da3f194e48dc1339a7714ebf3748b0d9ff16ce93be","tests/compile_pass/double_ext_on_same_type.rs":"0e4d16fe9059f0325e4ad1337d53738876633b0533f9a2d4e9714ddada96eb4d","tests/compile_pass/extension_on_complex_types.rs":"8dd484df9e6a4c8a20b9f14b8d33aeecb8fce6a9e1be2e68b8dc7f312e860562","tests/compile_pass/generics.rs":"367f089e8010d1c98ccc975b03acb6cf03810793e1198105f75c006eafd52bb8","tests/compile_pass/hello_world.rs":"1961cfa634143974f0d64b26f817ac3148375faa5cf5864d63f0127d3af8099e","tests/compile_pass/issue_2.rs":"a14d5e2179b74ff71c5357e8a4f1a9ac228a711196edd40c12719565c8dfaa21","tests/compile_pass/more_than_one_extension.rs":"1d7486e4e9e4095d7e7f42aac878d836f021c49fbe26c31cb13fe6a0415a8558","tests/compile_pass/multiple_config.rs":"dc3b06e4fafbb7236b5bc49f9a5e9693241c07118da8886dd0752b895ff27425","tests/compile_pass/multiple_generic_params.rs":"2ac052ea7b818b6d45ee8070cf6ec18953419473f711375cafbe7283244b5743","tests/compile_pass/pub_impl.rs":"8dfcba21fbbc45efcf85b66fca2d187022569e72d4b10b57047eddda67a1725b","tests/compile_pass/ref_and_ref_mut.rs":"d1086a23809cbd8f87487677073238c3657a8a98fafc63a688eb9d622bf2eb11","tests/compile_pass/sized.rs":"baceaaabcf368b3c72e6d27fea72aadde11d97d9d153c35df5e2d89fb3da4e3e","tests/compile_pass/super_trait.rs":"07448e1fe2b9018125ccaabf7db1e2a244788519bb42117f8e437e48358eb2f0","tests/compile_pass/visibility_config.rs":"64846014a63327661fb250cdb726cce532ed82b1cea5cb83308526bcba22b4be"},"package":"311a6d2f1f9d60bff73d2c78a0af97ed27f79672f15c238192a5bbb64db56d00"}

View File

@ -6,11 +6,19 @@ for Rust libraries in [RFC #1105](https://github.com/rust-lang/rfcs/blob/master/
## Unreleased ## Unreleased
None. - None.
### Breaking changes ### Breaking changes
None. - None.
## 1.2.0 - 2023-03-18
- Support destructuring function arguments
## 1.1.3 - 2023-03-18
- Update to syn 2.0
## 1.1.2 - 2021-09-02 ## 1.1.2 - 2021-09-02

View File

@ -3,32 +3,30 @@
# When uploading crates to the registry Cargo will automatically # When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility # "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies # with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies # to registry (e.g., crates.io) dependencies.
# #
# If you believe there's an error in this file please file an # If you are reading this file be aware that the original Cargo.toml
# issue against the rust-lang/cargo repository. If you're # will likely look very different (and much more reasonable).
# editing this file be aware that the upstream Cargo.toml # See Cargo.toml.orig for the original contents.
# will likely look very different (and much more reasonable)
[package] [package]
edition = "2018" edition = "2018"
name = "extend" name = "extend"
version = "1.1.2" version = "1.2.0"
authors = ["David Pedersen <david.pdrsn@gmail.com>"] authors = ["David Pedersen <david.pdrsn@gmail.com>"]
description = "Create extensions for types you don't own with extension traits but without the boilerplate." description = "Create extensions for types you don't own with extension traits but without the boilerplate."
homepage = "https://github.com/davidpdrsn/extend" homepage = "https://github.com/davidpdrsn/extend"
documentation = "https://docs.rs/extend"
readme = "README.md" readme = "README.md"
keywords = ["extension", "trait"] keywords = [
"extension",
"trait",
]
categories = ["rust-patterns"] categories = ["rust-patterns"]
license = "MIT" license = "MIT"
repository = "https://github.com/davidpdrsn/extend.git" repository = "https://github.com/davidpdrsn/extend"
[lib] [lib]
path = "src/lib.rs"
proc-macro = true proc-macro = true
[dependencies.proc-macro-error]
version = "1"
[dependencies.proc-macro2] [dependencies.proc-macro2]
version = "1" version = "1"
@ -37,12 +35,15 @@ version = "1"
version = "1" version = "1"
[dependencies.syn] [dependencies.syn]
version = "1" version = "2"
features = ["full", "extra-traits", "visit"] features = [
"full",
"extra-traits",
"visit",
]
[dev-dependencies.async-trait] [dev-dependencies.async-trait]
version = "0.1.40" version = "0.1.40"
[dev-dependencies.trybuild] [dev-dependencies.trybuild]
version = "1.0.17" version = "1.0.17"
[badges.maintenance]
status = "passively-maintained"

View File

@ -1,47 +1,23 @@
targets = []
[advisories] [advisories]
db-path = "~/.cargo/advisory-db"
db-urls = ["https://github.com/rustsec/advisory-db"]
vulnerability = "deny" vulnerability = "deny"
unmaintained = "warn" unmaintained = "warn"
yanked = "warn"
notice = "warn" notice = "warn"
ignore = [] ignore = []
[licenses] [licenses]
unlicensed = "deny" unlicensed = "warn"
allow = [ allow = []
"MIT",
"Apache-2.0",
]
deny = [] deny = []
copyleft = "warn" copyleft = "warn"
allow-osi-fsf-free = "neither" allow-osi-fsf-free = "either"
default = "deny"
confidence-threshold = 0.8 confidence-threshold = 0.8
exceptions = []
[licenses.private]
ignore = false
registries = []
[bans] [bans]
multiple-versions = "deny" multiple-versions = "deny"
wildcards = "allow"
highlight = "all" highlight = "all"
allow = []
deny = []
skip = []
skip-tree = [] skip-tree = []
[sources] [sources]
unknown-registry = "warn" unknown-registry = "warn"
unknown-git = "warn" unknown-git = "warn"
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
allow-git = [] allow-git = []
[sources.allow-org]
github = []
gitlab = []
bitbucket = []

View File

@ -1 +0,0 @@
merge_imports = true

View File

@ -13,12 +13,10 @@
//! } //! }
//! } //! }
//! //!
//! fn main() { //! assert_eq!(
//! assert_eq!( //! vec![1, 2, 3],
//! vec![1, 2, 3], //! vec![2, 3, 1].sorted(),
//! vec![2, 3, 1].sorted(), //! );
//! );
//! }
//! ``` //! ```
//! //!
//! # How does it work? //! # How does it work?
@ -150,28 +148,21 @@
//! //!
//! [extension traits]: https://dev.to/matsimitsu/extending-existing-functionality-in-rust-with-traits-in-rust-3622 //! [extension traits]: https://dev.to/matsimitsu/extending-existing-functionality-in-rust-with-traits-in-rust-3622
#![doc(html_root_url = "https://docs.rs/extend/1.1.2")]
#![allow(clippy::let_and_return)] #![allow(clippy::let_and_return)]
#![deny( #![deny(unused_variables, dead_code, unused_must_use, unused_imports)]
unused_variables,
mutable_borrow_reservation_conflict,
dead_code,
unused_must_use,
unused_imports
)]
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use proc_macro_error::*;
use quote::{format_ident, quote, ToTokens}; use quote::{format_ident, quote, ToTokens};
use std::convert::{TryFrom, TryInto};
use syn::{ use syn::{
parse::{self, Parse, ParseStream}, parse::{self, Parse, ParseStream},
parse_macro_input, parse_quote, parse_macro_input, parse_quote,
punctuated::Punctuated, punctuated::Punctuated,
spanned::Spanned, spanned::Spanned,
token::{Add, Semi}, token::{Plus, Semi},
Ident, ImplItem, ItemImpl, Token, TraitItemConst, TraitItemMethod, Type, TypeArray, TypeBareFn, Ident, ImplItem, ItemImpl, Result, Token, TraitItemConst, TraitItemFn, Type, TypeArray,
TypeGroup, TypeNever, TypeParamBound, TypeParen, TypePath, TypePtr, TypeReference, TypeSlice, TypeBareFn, TypeGroup, TypeNever, TypeParamBound, TypeParen, TypePath, TypePtr, TypeReference,
TypeTraitObject, TypeTuple, Visibility, TypeSlice, TypeTraitObject, TypeTuple, Visibility,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -201,7 +192,6 @@ impl Parse for Input {
/// See crate docs for more info. /// See crate docs for more info.
#[proc_macro_attribute] #[proc_macro_attribute]
#[proc_macro_error]
#[allow(clippy::unneeded_field_pattern)] #[allow(clippy::unneeded_field_pattern)]
pub fn ext( pub fn ext(
attr: proc_macro::TokenStream, attr: proc_macro::TokenStream,
@ -209,7 +199,10 @@ pub fn ext(
) -> proc_macro::TokenStream { ) -> proc_macro::TokenStream {
let item = parse_macro_input!(item as Input); let item = parse_macro_input!(item as Input);
let config = parse_macro_input!(attr as Config); let config = parse_macro_input!(attr as Config);
go(item, config) match go(item, config) {
Ok(tokens) => tokens,
Err(err) => err.into_compile_error().into(),
}
} }
/// Like [`ext`](macro@crate::ext) but always add `Sized` as a supertrait. /// Like [`ext`](macro@crate::ext) but always add `Sized` as a supertrait.
@ -228,7 +221,6 @@ pub fn ext(
/// } /// }
/// ``` /// ```
#[proc_macro_attribute] #[proc_macro_attribute]
#[proc_macro_error]
#[allow(clippy::unneeded_field_pattern)] #[allow(clippy::unneeded_field_pattern)]
pub fn ext_sized( pub fn ext_sized(
attr: proc_macro::TokenStream, attr: proc_macro::TokenStream,
@ -243,16 +235,19 @@ pub fn ext_sized(
Some(parse_quote!(Sized)) Some(parse_quote!(Sized))
}; };
go(item, config) match go(item, config) {
Ok(tokens) => tokens,
Err(err) => err.into_compile_error().into(),
}
} }
fn go(item: Input, mut config: Config) -> proc_macro::TokenStream { fn go(item: Input, mut config: Config) -> Result<proc_macro::TokenStream> {
if let Some(vis) = item.vis { if let Some(vis) = item.vis {
if config.visibility != Visibility::Inherited { if config.visibility != Visibility::Inherited {
abort!( return Err(syn::Error::new(
config.visibility.span(), config.visibility.span(),
"Cannot set visibility on `#[ext]` and `impl` block" "Cannot set visibility on `#[ext]` and `impl` block",
); ));
} }
config.visibility = vis; config.visibility = vis;
@ -272,19 +267,24 @@ fn go(item: Input, mut config: Config) -> proc_macro::TokenStream {
} = item.item_impl; } = item.item_impl;
if let Some((_, path, _)) = trait_ { if let Some((_, path, _)) = trait_ {
abort!(path.span(), "Trait impls cannot be used for #[ext]"); return Err(syn::Error::new(
path.span(),
"Trait impls cannot be used for #[ext]",
));
} }
let self_ty = parse_self_ty(&self_ty); let self_ty = parse_self_ty(&self_ty)?;
let ext_trait_name = config let ext_trait_name = if let Some(ext_trait_name) = config.ext_trait_name {
.ext_trait_name ext_trait_name
.unwrap_or_else(|| ext_trait_name(&self_ty)); } else {
ext_trait_name(&self_ty)?
};
let MethodsAndConsts { let MethodsAndConsts {
trait_methods, trait_methods,
trait_consts, trait_consts,
} = extract_allowed_items(&items); } = extract_allowed_items(&items)?;
let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
@ -299,7 +299,7 @@ fn go(item: Input, mut config: Config) -> proc_macro::TokenStream {
let supertraits_quoted = if all_supertraits.is_empty() { let supertraits_quoted = if all_supertraits.is_empty() {
quote! {} quote! {}
} else { } else {
let supertraits_quoted = punctuated_from_iter::<_, _, Add>(all_supertraits); let supertraits_quoted = punctuated_from_iter::<_, _, Plus>(all_supertraits);
quote! { : #supertraits_quoted } quote! { : #supertraits_quoted }
}; };
@ -330,7 +330,7 @@ fn go(item: Input, mut config: Config) -> proc_macro::TokenStream {
}) })
.into(); .into();
code Ok(code)
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -349,8 +349,8 @@ enum ExtType<'a> {
} }
#[allow(clippy::wildcard_in_or_patterns)] #[allow(clippy::wildcard_in_or_patterns)]
fn parse_self_ty(self_ty: &Type) -> ExtType { fn parse_self_ty(self_ty: &Type) -> Result<ExtType> {
match self_ty { let ty = match self_ty {
Type::Array(inner) => ExtType::Array(inner), Type::Array(inner) => ExtType::Array(inner),
Type::Group(inner) => ExtType::Group(inner), Type::Group(inner) => ExtType::Group(inner),
Type::Never(inner) => ExtType::Never(inner), Type::Never(inner) => ExtType::Never(inner),
@ -363,15 +363,20 @@ fn parse_self_ty(self_ty: &Type) -> ExtType {
Type::BareFn(inner) => ExtType::BareFn(inner), Type::BareFn(inner) => ExtType::BareFn(inner),
Type::TraitObject(inner) => ExtType::TraitObject(inner), Type::TraitObject(inner) => ExtType::TraitObject(inner),
Type::ImplTrait(_) | Type::Infer(_) | Type::Macro(_) | Type::Verbatim(_) | _ => abort!( Type::ImplTrait(_) | Type::Infer(_) | Type::Macro(_) | Type::Verbatim(_) | _ => {
self_ty.span(), return Err(syn::Error::new(
"#[ext] is not supported for this kind of type" self_ty.span(),
), "#[ext] is not supported for this kind of type",
} ))
}
};
Ok(ty)
} }
impl<'a> From<&'a Type> for ExtType<'a> { impl<'a> TryFrom<&'a Type> for ExtType<'a> {
fn from(inner: &'a Type) -> ExtType<'a> { type Error = syn::Error;
fn try_from(inner: &'a Type) -> Result<ExtType<'a>> {
parse_self_ty(inner) parse_self_ty(inner)
} }
} }
@ -394,60 +399,60 @@ impl<'a> ToTokens for ExtType<'a> {
} }
} }
fn ext_trait_name(self_ty: &ExtType) -> Ident { fn ext_trait_name(self_ty: &ExtType) -> Result<Ident> {
fn inner_self_ty(self_ty: &ExtType) -> Ident { fn inner_self_ty(self_ty: &ExtType) -> Result<Ident> {
match self_ty { match self_ty {
ExtType::Path(inner) => find_and_combine_idents(inner), ExtType::Path(inner) => find_and_combine_idents(inner),
ExtType::Reference(inner) => { ExtType::Reference(inner) => {
let name = inner_self_ty(&(&*inner.elem).into()); let name = inner_self_ty(&(&*inner.elem).try_into()?)?;
if inner.mutability.is_some() { if inner.mutability.is_some() {
format_ident!("RefMut{}", name) Ok(format_ident!("RefMut{}", name))
} else { } else {
format_ident!("Ref{}", name) Ok(format_ident!("Ref{}", name))
} }
} }
ExtType::Array(inner) => { ExtType::Array(inner) => {
let name = inner_self_ty(&(&*inner.elem).into()); let name = inner_self_ty(&(&*inner.elem).try_into()?)?;
format_ident!("ListOf{}", name) Ok(format_ident!("ListOf{}", name))
} }
ExtType::Group(inner) => { ExtType::Group(inner) => {
let name = inner_self_ty(&(&*inner.elem).into()); let name = inner_self_ty(&(&*inner.elem).try_into()?)?;
format_ident!("Group{}", name) Ok(format_ident!("Group{}", name))
} }
ExtType::Paren(inner) => { ExtType::Paren(inner) => {
let name = inner_self_ty(&(&*inner.elem).into()); let name = inner_self_ty(&(&*inner.elem).try_into()?)?;
format_ident!("Paren{}", name) Ok(format_ident!("Paren{}", name))
} }
ExtType::Ptr(inner) => { ExtType::Ptr(inner) => {
let name = inner_self_ty(&(&*inner.elem).into()); let name = inner_self_ty(&(&*inner.elem).try_into()?)?;
format_ident!("PointerTo{}", name) Ok(format_ident!("PointerTo{}", name))
} }
ExtType::Slice(inner) => { ExtType::Slice(inner) => {
let name = inner_self_ty(&(&*inner.elem).into()); let name = inner_self_ty(&(&*inner.elem).try_into()?)?;
format_ident!("SliceOf{}", name) Ok(format_ident!("SliceOf{}", name))
} }
ExtType::Tuple(inner) => { ExtType::Tuple(inner) => {
let mut name = format_ident!("TupleOf"); let mut name = format_ident!("TupleOf");
for elem in &inner.elems { for elem in &inner.elems {
name = format_ident!("{}{}", name, inner_self_ty(&elem.into())); name = format_ident!("{}{}", name, inner_self_ty(&elem.try_into()?)?);
} }
name Ok(name)
} }
ExtType::Never(_) => format_ident!("Never"), ExtType::Never(_) => Ok(format_ident!("Never")),
ExtType::BareFn(inner) => { ExtType::BareFn(inner) => {
let mut name = format_ident!("BareFn"); let mut name = format_ident!("BareFn");
for input in inner.inputs.iter() { for input in inner.inputs.iter() {
name = format_ident!("{}{}", name, inner_self_ty(&(&input.ty).into())); name = format_ident!("{}{}", name, inner_self_ty(&(&input.ty).try_into()?)?);
} }
match &inner.output { match &inner.output {
syn::ReturnType::Default => { syn::ReturnType::Default => {
name = format_ident!("{}Unit", name); name = format_ident!("{}Unit", name);
} }
syn::ReturnType::Type(_, ty) => { syn::ReturnType::Type(_, ty) => {
name = format_ident!("{}{}", name, inner_self_ty(&(&**ty).into())); name = format_ident!("{}{}", name, inner_self_ty(&(&**ty).try_into()?)?);
} }
} }
name Ok(name)
} }
ExtType::TraitObject(inner) => { ExtType::TraitObject(inner) => {
let mut name = format_ident!("TraitObject"); let mut name = format_ident!("TraitObject");
@ -461,17 +466,20 @@ fn ext_trait_name(self_ty: &ExtType) -> Ident {
TypeParamBound::Lifetime(lifetime) => { TypeParamBound::Lifetime(lifetime) => {
name = format_ident!("{}{}", name, lifetime.ident); name = format_ident!("{}{}", name, lifetime.ident);
} }
other => {
return Err(syn::Error::new(other.span(), "unsupported bound"));
}
} }
} }
name Ok(name)
} }
} }
} }
format_ident!("{}Ext", inner_self_ty(self_ty)) Ok(format_ident!("{}Ext", inner_self_ty(self_ty)?))
} }
fn find_and_combine_idents(type_path: &TypePath) -> Ident { fn find_and_combine_idents(type_path: &TypePath) -> Result<Ident> {
use syn::visit::{self, Visit}; use syn::visit::{self, Visit};
struct IdentVisitor<'a>(Vec<&'a Ident>); struct IdentVisitor<'a>(Vec<&'a Ident>);
@ -487,7 +495,7 @@ fn find_and_combine_idents(type_path: &TypePath) -> Ident {
let idents = visitor.0; let idents = visitor.0;
if idents.is_empty() { if idents.is_empty() {
abort!(type_path.span(), "Empty type path") Err(syn::Error::new(type_path.span(), "Empty type path"))
} else { } else {
let start = &idents[0].span(); let start = &idents[0].span();
let combined_span = idents let combined_span = idents
@ -497,29 +505,49 @@ fn find_and_combine_idents(type_path: &TypePath) -> Ident {
let combined_name = idents.iter().map(|i| i.to_string()).collect::<String>(); let combined_name = idents.iter().map(|i| i.to_string()).collect::<String>();
Ident::new(&combined_name, combined_span) Ok(Ident::new(&combined_name, combined_span))
} }
} }
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct MethodsAndConsts { struct MethodsAndConsts {
trait_methods: Vec<TraitItemMethod>, trait_methods: Vec<TraitItemFn>,
trait_consts: Vec<TraitItemConst>, trait_consts: Vec<TraitItemConst>,
} }
#[allow(clippy::wildcard_in_or_patterns)] #[allow(clippy::wildcard_in_or_patterns)]
fn extract_allowed_items(items: &[ImplItem]) -> MethodsAndConsts { fn extract_allowed_items(items: &[ImplItem]) -> Result<MethodsAndConsts> {
let mut acc = MethodsAndConsts::default(); let mut acc = MethodsAndConsts::default();
for item in items { for item in items {
match item { match item {
ImplItem::Method(method) => acc.trait_methods.push(TraitItemMethod { ImplItem::Fn(method) => acc.trait_methods.push(TraitItemFn {
attrs: method.attrs.clone(), attrs: method.attrs.clone(),
sig: method.sig.clone(), sig: {
let mut sig = method.sig.clone();
sig.inputs = sig
.inputs
.into_iter()
.map(|fn_arg| match fn_arg {
syn::FnArg::Receiver(recv) => syn::FnArg::Receiver(recv),
syn::FnArg::Typed(mut pat_type) => {
pat_type.pat = Box::new(match *pat_type.pat {
syn::Pat::Ident(pat_ident) => syn::Pat::Ident(pat_ident),
_ => {
parse_quote!(_)
}
});
syn::FnArg::Typed(pat_type)
}
})
.collect();
sig
},
default: None, default: None,
semi_token: Some(Semi::default()), semi_token: Some(Semi::default()),
}), }),
ImplItem::Const(const_) => acc.trait_consts.push(TraitItemConst { ImplItem::Const(const_) => acc.trait_consts.push(TraitItemConst {
attrs: const_.attrs.clone(), attrs: const_.attrs.clone(),
generics: const_.generics.clone(),
const_token: Default::default(), const_token: Default::default(),
ident: const_.ident.clone(), ident: const_.ident.clone(),
colon_token: Default::default(), colon_token: Default::default(),
@ -527,22 +555,31 @@ fn extract_allowed_items(items: &[ImplItem]) -> MethodsAndConsts {
default: None, default: None,
semi_token: Default::default(), semi_token: Default::default(),
}), }),
ImplItem::Type(_) => abort!( ImplItem::Type(_) => {
item.span(), return Err(syn::Error::new(
"Associated types are not allowed in #[ext] impls" item.span(),
), "Associated types are not allowed in #[ext] impls",
ImplItem::Macro(_) => abort!(item.span(), "Macros are not allowed in #[ext] impls"), ))
ImplItem::Verbatim(_) | _ => abort!(item.span(), "Not allowed in #[ext] impls"), }
ImplItem::Macro(_) => {
return Err(syn::Error::new(
item.span(),
"Macros are not allowed in #[ext] impls",
))
}
ImplItem::Verbatim(_) | _ => {
return Err(syn::Error::new(item.span(), "Not allowed in #[ext] impls"))
}
} }
} }
acc Ok(acc)
} }
#[derive(Debug)] #[derive(Debug)]
struct Config { struct Config {
ext_trait_name: Option<Ident>, ext_trait_name: Option<Ident>,
visibility: Visibility, visibility: Visibility,
supertraits: Option<Punctuated<TypeParamBound, Add>>, supertraits: Option<Punctuated<TypeParamBound, Plus>>,
} }
impl Parse for Config { impl Parse for Config {
@ -565,9 +602,9 @@ impl Parse for Config {
} }
"supertraits" => { "supertraits" => {
config.supertraits = config.supertraits =
Some(Punctuated::<TypeParamBound, Add>::parse_terminated(input)?); Some(Punctuated::<TypeParamBound, Plus>::parse_terminated(input)?);
} }
_ => abort!(ident.span(), "Unknown configuration name"), _ => return Err(syn::Error::new(ident.span(), "Unknown configuration name")),
} }
input.parse::<Token![,]>().ok(); input.parse::<Token![,]>().ok();

View File

@ -1,10 +1,13 @@
error[E0277]: the trait bound `String: MyTrait` is not satisfied error[E0277]: the trait bound `String: MyTrait` is not satisfied
--> $DIR/supertraits_are_actually_included.rs:6:6 --> tests/compile_fail/supertraits_are_actually_included.rs:6:6
|
6 | impl String {
| ^^^^^^ the trait `MyTrait` is not implemented for `String`
|
note: required by a bound in `StringExt`
--> tests/compile_fail/supertraits_are_actually_included.rs:5:21
| |
5 | #[ext(supertraits = MyTrait)] 5 | #[ext(supertraits = MyTrait)]
| ------- required by this bound in `StringExt` | ^^^^^^^ required by this bound in `StringExt`
6 | impl String { 6 | impl String {
| ^^^^^^ | ------ required by a bound in this
| |
| the trait `MyTrait` is not implemented for `String`
| required by a bound in this

View File

@ -0,0 +1,12 @@
#![allow(warnings)]
use extend::ext;
#[ext]
impl i32 {
fn foo(self, (a, b): (i32, i32)) {}
fn bar(self, [a, b]: [i32; 2]) {}
}
fn main() {}

View File

@ -1,3 +1,5 @@
#![allow(warnings)]
use extend::ext; use extend::ext;
#[ext] #[ext]