mirror of
https://github.com/yewstack/yew.git
synced 2025-12-08 21:26:25 +00:00
Fix some Hook edge cases (#2592)
* Fix a couple edge cases. * no implicit prelude.
This commit is contained in:
parent
58db53a026
commit
6fb547339f
@ -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.
|
||||
@ -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<()>>,
|
||||
}
|
||||
@ -26,6 +27,7 @@ impl CollectLifetimes {
|
||||
default_span,
|
||||
|
||||
impl_trait_lock: Arc::default(),
|
||||
type_trait_obj_lock: Arc::default(),
|
||||
impl_fn_lock: Arc::default(),
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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;
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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() {}
|
||||
@ -0,0 +1,8 @@
|
||||
#![no_implicit_prelude]
|
||||
|
||||
#[::yew::prelude::hook]
|
||||
fn use_str_ref(f: &::std::primitive::str) -> &::std::primitive::str {
|
||||
f
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
x
Reference in New Issue
Block a user