Skip to content

Commit

Permalink
Fix some Hook edge cases (#2592)
Browse files Browse the repository at this point in the history
* Fix a couple edge cases.

* no implicit prelude.
  • Loading branch information
futursolo committed Apr 15, 2022
1 parent 58db53a commit 6fb5473
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 9 deletions.
18 changes: 16 additions & 2 deletions packages/yew-macro/src/hook/lifetime.rs
Expand Up @@ -3,7 +3,7 @@ use std::sync::{Arc, Mutex};
use syn::visit_mut::{self, VisitMut};
use syn::{
GenericArgument, Lifetime, ParenthesizedGenericArguments, Receiver, TypeBareFn, TypeImplTrait,
TypeParamBound, TypeReference,
TypeParamBound, TypeReference, TypeTraitObject,
};

// borrowed from the awesome async-trait crate.
Expand All @@ -13,6 +13,7 @@ pub struct CollectLifetimes {
pub name: &'static str,
pub default_span: Span,

pub type_trait_obj_lock: Arc<Mutex<()>>,
pub impl_trait_lock: Arc<Mutex<()>>,
pub impl_fn_lock: Arc<Mutex<()>>,
}
Expand All @@ -26,6 +27,7 @@ impl CollectLifetimes {
default_span,

impl_trait_lock: Arc::default(),
type_trait_obj_lock: Arc::default(),
impl_fn_lock: Arc::default(),
}
}
Expand All @@ -34,6 +36,10 @@ impl CollectLifetimes {
self.impl_trait_lock.try_lock().is_err()
}

fn is_type_trait_obj(&self) -> bool {
self.type_trait_obj_lock.try_lock().is_err()
}

fn is_impl_fn(&self) -> bool {
self.impl_fn_lock.try_lock().is_err()
}
Expand Down Expand Up @@ -102,12 +108,20 @@ impl VisitMut for CollectLifetimes {
visit_mut::visit_type_impl_trait_mut(self, impl_trait);
}

fn visit_type_trait_object_mut(&mut self, type_trait_obj: &mut TypeTraitObject) {
let type_trait_obj_lock = self.type_trait_obj_lock.clone();
let _locked = type_trait_obj_lock.try_lock();

visit_mut::visit_type_trait_object_mut(self, type_trait_obj);
}

fn visit_parenthesized_generic_arguments_mut(
&mut self,
generic_args: &mut ParenthesizedGenericArguments,
) {
let impl_fn_lock = self.impl_fn_lock.clone();
let _maybe_locked = self.is_impl_trait().then(|| impl_fn_lock.try_lock());
let _maybe_locked =
(self.is_impl_trait() || self.is_type_trait_obj()).then(|| impl_fn_lock.try_lock());

visit_mut::visit_parenthesized_generic_arguments_mut(self, generic_args);
}
Expand Down
9 changes: 8 additions & 1 deletion packages/yew-macro/src/hook/mod.rs
Expand Up @@ -4,6 +4,7 @@ use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::{
parse_file, parse_quote, visit_mut, Attribute, Ident, ItemFn, LitStr, ReturnType, Signature,
Type,
};

mod body;
Expand Down Expand Up @@ -131,19 +132,25 @@ pub fn hook_impl(hook: HookFn) -> syn::Result<TokenStream> {
let inner_fn = quote! { fn #inner_fn_ident #generics (#ctx_ident: &mut ::yew::functional::HookContext, #inputs) #inner_fn_rt #where_clause #block };

let inner_type_impl = if hook_sig.needs_boxing {
let with_output = !matches!(hook_sig.output_type, Type::ImplTrait(_),);
let inner_fn_rt = with_output.then(|| &inner_fn_rt);
let output_type = with_output.then(|| &output_type);

let hook_lifetime = &hook_sig.hook_lifetime;
let hook_lifetime_plus = quote! { #hook_lifetime + };

let boxed_inner_ident = Ident::new("boxed_inner", Span::mixed_site());
let boxed_fn_type = quote! { ::std::boxed::Box<dyn #hook_lifetime_plus ::std::ops::FnOnce(&mut ::yew::functional::HookContext) #inner_fn_rt> };

let as_boxed_fn = with_output.then(|| quote! { as #boxed_fn_type });

// We need boxing implementation for `impl Trait` arguments.
quote! {
let #boxed_inner_ident = ::std::boxed::Box::new(
move |#ctx_ident: &mut ::yew::functional::HookContext| #inner_fn_rt {
#inner_fn_ident (#ctx_ident, #(#input_args,)*)
}
) as #boxed_fn_type;
) #as_boxed_fn;

::yew::functional::BoxedHook::<#hook_lifetime, #output_type>::new(#boxed_inner_ident)
}
Expand Down
30 changes: 24 additions & 6 deletions packages/yew-macro/src/hook/signature.rs
Expand Up @@ -51,12 +51,30 @@ impl HookSignature {
parse_quote! { -> impl #bound ::yew::functional::Hook<Output = ()> },
parse_quote! { () },
),
ReturnType::Type(arrow, ref return_type) => (
parse_quote_spanned! {
return_type.span() => #arrow impl #bound ::yew::functional::Hook<Output = #return_type>
},
*return_type.clone(),
),
ReturnType::Type(arrow, ref return_type) => {
if let Type::Reference(ref m) = &**return_type {
if m.lifetime.is_none() {
let mut return_type_ref = m.clone();
return_type_ref.lifetime = parse_quote!('hook);

let return_type_ref = Type::Reference(return_type_ref);

return (
parse_quote_spanned! {
return_type.span() => #arrow impl #bound ::yew::functional::Hook<Output = #return_type_ref>
},
return_type_ref,
);
}
}

(
parse_quote_spanned! {
return_type.span() => #arrow impl #bound ::yew::functional::Hook<Output = #return_type>
},
*return_type.clone(),
)
}
}
}

Expand Down
@@ -0,0 +1,8 @@
#![no_implicit_prelude]

#[::yew::prelude::hook]
fn use_boxed_fn(_f: ::std::boxed::Box<dyn::std::ops::Fn(&str) -> &str>) {
::std::todo!()
}

fn main() {}
@@ -0,0 +1,8 @@
#![no_implicit_prelude]

#[::yew::prelude::hook]
fn use_deref_as_u32() -> impl ::std::ops::Deref<Target = ::std::primitive::u32> {
::std::rc::Rc::new(0)
}

fn main() {}
8 changes: 8 additions & 0 deletions packages/yew-macro/tests/hook_attr/hook-return-ref-pass.rs
@@ -0,0 +1,8 @@
#![no_implicit_prelude]

#[::yew::prelude::hook]
fn use_str_ref(f: &::std::primitive::str) -> &::std::primitive::str {
f
}

fn main() {}

1 comment on commit 6fb5473

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yew master branch benchmarks (Lower is better)

Benchmark suite Current: 6fb5473 Previous: 58db53a Ratio
yew-struct-keyed 01_run1k 161.505 162.3635 0.99
yew-struct-keyed 02_replace1k 186.3345 187.0155 1.00
yew-struct-keyed 03_update10th1k_x16 344.2385 329.96500000000003 1.04
yew-struct-keyed 04_select1k 64.89349999999999 53.821 1.21
yew-struct-keyed 05_swap1k 81.49350000000001 77.1215 1.06
yew-struct-keyed 06_remove-one-1k 25.77 25.424999999999997 1.01
yew-struct-keyed 07_create10k 2828.4880000000003 2912.3915 0.97
yew-struct-keyed 08_create1k-after1k_x2 400.5415 409.2745 0.98
yew-struct-keyed 09_clear1k_x8 174.517 186.4505 0.94
yew-struct-keyed 21_ready-memory 1.457233428955078 1.457233428955078 1
yew-struct-keyed 22_run-memory 1.6948280334472656 1.6556472778320312 1.02
yew-struct-keyed 23_update5-memory 1.7004127502441406 1.6958503723144531 1.00
yew-struct-keyed 24_run5-memory 1.705596923828125 1.944721221923828 0.88
yew-struct-keyed 25_run-clear-memory 1.328125 1.3280715942382812 1.00
yew-struct-keyed 31_startup-ci 1734.6999999999998 1839.414 0.94
yew-struct-keyed 32_startup-bt 26.54 31.728 0.84
yew-struct-keyed 33_startup-mainthreadcost 206.772 218.8160000000001 0.94
yew-struct-keyed 34_startup-totalbytes 328.7392578125 328.7392578125 1

This comment was automatically generated by workflow using github-action-benchmark.

Please sign in to comment.