Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions spec-trait-impl/crates/spec-trait-bin/src/examples/lifetimes2.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
use spec_trait_macro::{spec, when};

trait Bad1 {
fn bad1(&self);
}

impl<T> Bad1 for T {
fn bad1(&self) {
println!("generic");
}
}

#[when(T: 'static)]
impl<T> Bad1 for T {
fn bad1(&self) {
println!("'static");
}
}

pub fn run() {
println!("\n- Lifetimes 2 Examples:");

let static_str: &'static str = &"hello";
spec! { "hello".bad1(); &'static str }
spec! { "hello".bad1(); &'static str; &'static str: 'static }
spec! { "hello".bad1(); &str; &str: 'static }
spec! { static_str.bad1(); &'static str }
spec! { static_str.bad1(); &'static str; &'static str: 'static }
spec! { static_str.bad1(); &str; &str: 'static }
<&'static str as Bad1>::bad1(&static_str);
}
2 changes: 2 additions & 0 deletions spec-trait-impl/crates/spec-trait-bin/src/examples/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod all;
mod base;
mod higher;
mod lifetimes;
mod lifetimes2;
mod order;
mod repeating;
mod sself;
Expand All @@ -18,4 +19,5 @@ pub fn run() {
higher::run();
order::run();
all::run();
lifetimes2::run();
}
51 changes: 49 additions & 2 deletions spec-trait-impl/crates/spec-trait-utils/src/specialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use proc_macro2::Span;
use syn::punctuated::Punctuated;
use syn::visit::Visit;
use syn::visit_mut::VisitMut;
use syn::{GenericParam, Generics, Ident, LifetimeParam, Type, TypeParam};
use syn::{GenericParam, Generics, Ident, LifetimeParam, Type, TypeParam, TypeParamBound};

// TODO: infer lifetimes as well

Expand Down Expand Up @@ -213,7 +213,11 @@ pub fn apply_type_condition<T: Specializable>(

// add new generic types
for generic in new_generics {
add_generic_type(generics, &generic);
if is_direct_reference_to_generic(&new_type, &generic) {
add_generic_type_relaxed(generics, &generic);
} else {
add_generic_type(generics, &generic);
}
add_generic_type(other_generics, &generic);
// TODO: add generic to impl Trait types
}
Expand All @@ -234,6 +238,35 @@ pub fn apply_type_condition<T: Specializable>(
new_type
}

fn is_direct_reference_to_generic(ty: &Type, generic: &str) -> bool {
struct Finder<'a> {
generic: &'a str,
found: bool,
}

impl Visit<'_> for Finder<'_> {
fn visit_type_reference(&mut self, node: &syn::TypeReference) {
if let Type::Path(path) = node.elem.as_ref()
&& path.qself.is_none()
&& path.path.segments.len() == 1
&& path.path.segments[0].ident == self.generic
{
self.found = true;
return;
}

syn::visit::visit_type_reference(self, node);
}
}

let mut finder = Finder {
generic,
found: false,
};
finder.visit_type(ty);
finder.found
}

pub fn remove_generic(generics: &mut Generics, generic: &str) {
generics.params = generics.params
.clone()
Expand Down Expand Up @@ -279,6 +312,20 @@ pub fn add_generic_type(generics: &mut Generics, generic: &str) {
}))
}

pub fn add_generic_type_relaxed(generics: &mut Generics, generic: &str) {
let mut bounds = Punctuated::new();
bounds.push(TypeParamBound::Verbatim(quote::quote!(?Sized)));

generics.params.push(GenericParam::Type(TypeParam {
attrs: vec![],
ident: Ident::new(generic, Span::call_site()),
colon_token: None,
bounds,
eq_token: None,
default: None,
}))
}

pub fn add_generic_lifetime(generics: &mut Generics, generic: &str) {
generics.params.push(GenericParam::Lifetime(LifetimeParam {
attrs: vec![],
Expand Down
Loading