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
6 changes: 3 additions & 3 deletions spec-trait-impl/crates/spec-trait-bin/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -244,10 +244,10 @@ impl<T, U> Foo<U> for T {
}
}

#[when(all(not(T = i32), not(T = ZST)))]
#[when(all(not(T = i32), not(T = ZST), not(U = i32)))]
impl<T, U> Foo<U> for T {
fn foo(&self, _x: U) {
println!("Foo impl T where T is not i32 or ZST");
println!("Foo impl T where T is not i32 or ZST and U is not i32");
}
}

Expand Down Expand Up @@ -326,7 +326,7 @@ fn main() {
spec! { x.foo(1u8); Vec<i32>; [u8]; u8 = MyType } // -> "Foo impl T where T is Vec<_> and U is MyType"
spec! { 1i32.foo("str"); i32; [&str] } // -> "Foo impl T where U is &str"
spec! { zst.foo("str"); ZST; [&str] } // -> "Foo impl T where U is &str"
spec! { 1u8.foo(1u8); u8; [u8] } // -> "Foo impl T where T is not i32 or ZST"
spec! { 1u8.foo(1u8); u8; [u8] } // -> "Foo impl T where T is not i32 or ZST and U is not i32"
println!();

// T - Foo4
Expand Down
95 changes: 51 additions & 44 deletions spec-trait-impl/crates/spec-trait-utils/src/impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ use crate::parsing::{
parse_generics,
};
use crate::specialize::{
Specializable, add_generic_lifetime, add_generic_type, apply_type_condition,
get_assignable_conditions, get_used_generics, remove_generic,
Specializable, TypeReplacer, add_generic_lifetime, add_generic_type, apply_type_condition,
get_assignable_conditions, get_used_generics, handle_generics, remove_generic,
};
use crate::types::{replace_type, type_contains, type_contains_lifetime};
use proc_macro2::TokenStream;
Expand Down Expand Up @@ -130,58 +130,65 @@ impl ImplBody {
let mut new_impl = self.clone();
let mut specialized = new_impl.clone();

// set specialized trait name
specialized.trait_name = specialized.get_spec_trait_name();

// apply condition
if let Some(condition) = &self.condition {
specialized.apply_condition(condition);
}

// set missing generics
let mut trait_generics = str_to_generics(&specialized.trait_generics);
let curr_generics_types = get_generics_types::<HashSet<_>>(&specialized.trait_generics);
let curr_generics_lifetimes =
get_generics_lifetimes::<HashSet<_>>(&specialized.trait_generics);
for generic in get_generics_types::<Vec<_>>(&specialized.impl_generics) {
if !curr_generics_types.contains(&generic) {
add_generic_type(&mut trait_generics, &generic);
// fix generics
specialized.add_missing_generics();
specialized.remove_unused_generics();

// set specialized trait name
specialized.trait_name = specialized.get_spec_trait_name();
let mut replacer = TypeReplacer {
generic: self.trait_name.clone(),
type_: str_to_type_name(&specialized.trait_name),
};
specialized.handle_items_replace(&mut replacer);

// TODO: fix generics for impl Trait types

// set specialized trait
new_impl.specialized = Some(Box::new(specialized));
new_impl
}

/// add missing generics from impl to trait
fn add_missing_generics(&mut self) {
let mut trait_generics = str_to_generics(&self.trait_generics);
let curr_generics_types = get_generics_types::<HashSet<_>>(&self.trait_generics);
let curr_generics_lifetimes = get_generics_lifetimes::<HashSet<_>>(&self.trait_generics);
handle_generics(&self.impl_generics, |generic| {
if generic.starts_with("'") && !curr_generics_lifetimes.contains(generic) {
add_generic_lifetime(&mut trait_generics, generic);
}
}
for generic in get_generics_lifetimes::<Vec<_>>(&specialized.impl_generics) {
if !curr_generics_lifetimes.contains(&generic) {
add_generic_lifetime(&mut trait_generics, &generic);
if !generic.starts_with("'") && !curr_generics_types.contains(generic) {
add_generic_type(&mut trait_generics, generic);
}
}
specialized.trait_generics = to_string(&trait_generics);

// clean unused generics
let used_generics =
get_used_generics(&specialized, &str_to_generics(&specialized.impl_generics));

let mut impl_generics = str_to_generics(&specialized.impl_generics);
let mut trait_generics = str_to_generics(&specialized.trait_generics);
for generic in get_generics_lifetimes::<Vec<_>>(&specialized.impl_generics) {
if !used_generics.contains(&generic) {
remove_generic(&mut trait_generics, &generic);
if !type_contains_lifetime(&str_to_type_name(&specialized.type_name), &generic) {
remove_generic(&mut impl_generics, &generic);
});
self.trait_generics = to_string(&trait_generics);
}

/// remove unused generics from impl and trait
fn remove_unused_generics(&mut self) {
let used_generics = get_used_generics(self, &str_to_generics(&self.impl_generics));
let mut impl_generics = str_to_generics(&self.impl_generics);
let mut trait_generics = str_to_generics(&self.trait_generics);
handle_generics(&self.impl_generics, |generic| {
if !used_generics.contains(generic) {
remove_generic(&mut trait_generics, generic);
let ty = str_to_type_name(&self.type_name);
if !generic.starts_with("'") && !type_contains(&ty, generic) {
remove_generic(&mut impl_generics, generic);
}
}
}
for generic in get_generics_types::<Vec<_>>(&specialized.impl_generics) {
if !used_generics.contains(&generic) {
remove_generic(&mut trait_generics, &generic);
if !type_contains(&str_to_type_name(&specialized.type_name), &generic) {
remove_generic(&mut impl_generics, &generic);
if generic.starts_with("'") && !type_contains_lifetime(&ty, generic) {
remove_generic(&mut impl_generics, generic);
}
}
}
specialized.impl_generics = to_string(&impl_generics);
specialized.trait_generics = to_string(&trait_generics);

new_impl.specialized = Some(Box::new(specialized));
new_impl
});
self.impl_generics = to_string(&impl_generics);
self.trait_generics = to_string(&trait_generics);
}

/// apply a condition to the impl body, modifying its generics and items
Expand Down
1 change: 1 addition & 0 deletions spec-trait-impl/crates/spec-trait-utils/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ pub mod impls;
pub mod parsing;
mod specialize;
pub mod traits;
mod type_visitor;
pub mod types;
14 changes: 13 additions & 1 deletion spec-trait-impl/crates/spec-trait-utils/src/specialize.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::collections::HashSet;

use crate::conditions::WhenCondition;
use crate::conversions::{str_to_lifetime, str_to_type_name};
use crate::conversions::{str_to_generics, str_to_lifetime, str_to_type_name};
use crate::types::{
Aliases, replace_infers, replace_type, type_assignable, type_contains, type_contains_lifetime,
};
Expand Down Expand Up @@ -101,11 +101,13 @@ pub fn apply_type_condition<T: Specializable>(
for generic in new_generics {
add_generic_type(generics, &generic);
add_generic_type(other_generics, &generic);
// TODO: add generic to impl Trait types
}

// remove generic type
remove_generic(generics, &item_generic);
remove_generic(other_generics, impl_generic);
// TODO: remove generic from impl Trait types

// replace generic type with type in the items
let mut replacer = TypeReplacer {
Expand Down Expand Up @@ -209,6 +211,16 @@ pub fn get_used_generics<T: Specializable>(target: &T, generics: &Generics) -> H
visitor.used_generics
}

pub fn handle_generics<F: FnMut(&str)>(generics_str: &str, mut generics_fn: F) {
let generics = str_to_generics(generics_str);
for g in collect_generics_lifetimes::<Vec<_>>(&generics) {
generics_fn(&g);
}
for g in collect_generics_types::<Vec<_>>(&generics) {
generics_fn(&g);
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
88 changes: 46 additions & 42 deletions spec-trait-impl/crates/spec-trait-utils/src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use crate::parsing::{
};
use crate::specialize::{
Specializable, TypeReplacer, add_generic_lifetime, add_generic_type, apply_type_condition,
get_assignable_conditions, get_used_generics, remove_generic,
get_assignable_conditions, get_used_generics, handle_generics, remove_generic,
};
use crate::types::get_unique_generic_name;
use proc_macro2::TokenStream;
Expand Down Expand Up @@ -110,65 +110,69 @@ impl TraitBody {
let mut new_trait = self.clone();
let mut specialized = new_trait.clone();

// set specialized trait name
specialized.name = impl_body.specialized.as_ref().unwrap().trait_name.clone();

// replace generics with unique generic name
specialized.replace_generics_names();

// set missing generic lifetimes
let mut generics = str_to_generics(&specialized.generics);
let impl_generics = &impl_body.specialized.as_ref().unwrap().trait_generics;
let specialized_impl_generics = str_to_generics(impl_generics);
for generic in get_generics_lifetimes::<Vec<_>>(impl_generics) {
if specialized
.get_corresponding_generic(&specialized_impl_generics, &generic)
.is_none()
{
add_generic_lifetime(&mut generics, &generic);
}
}
specialized.generics = to_string(&generics);
// add missing generics from impl
specialized.add_missing_generics(impl_body);

// apply condition
if let Some(condition) = &impl_body.condition {
let mut impl_generics = str_to_generics(&impl_body.trait_generics);
specialized.apply_condition(&mut impl_generics, condition);
}

// set missing generic types
let mut generics = str_to_generics(&specialized.generics);
// fix generics
specialized.add_missing_generics(impl_body);
specialized.remove_unused_generics();

// set specialized trait name
specialized.name = impl_body.specialized.as_ref().unwrap().trait_name.clone();
let mut replacer = TypeReplacer {
generic: self.name.clone(),
type_: str_to_type_name(&specialized.name),
};
specialized.handle_items_replace(&mut replacer);

// TODO: fix generics for impl Trait types

// set specialized trait
new_trait.specialized = Some(Box::new(specialized));
new_trait
}

/// add missing generics from impl to trait
fn add_missing_generics(&mut self, impl_body: &ImplBody) {
let mut generics = str_to_generics(&self.generics);
let impl_generics = &impl_body.specialized.as_ref().unwrap().trait_generics;
let specialized_impl_generics = str_to_generics(impl_generics);
for generic in get_generics_types::<Vec<_>>(impl_generics) {
if specialized
.get_corresponding_generic(&specialized_impl_generics, &generic)
handle_generics(impl_generics, |generic| {
if self
.get_corresponding_generic(&specialized_impl_generics, generic)
.is_none()
{
add_generic_type(&mut generics, &generic);
if generic.starts_with("'") {
add_generic_lifetime(&mut generics, generic);
} else {
add_generic_type(&mut generics, generic);
}
}
}
specialized.generics = to_string(&generics);
});
self.generics = to_string(&generics);
self.generics = to_string(&generics);
}

/// remove unused generics from trait
fn remove_unused_generics(&mut self) {
// clean unused generics
let used_generics =
get_used_generics(&specialized, &str_to_generics(&specialized.generics));

let mut generics = str_to_generics(&specialized.generics);
for generic in get_generics_lifetimes::<Vec<_>>(&specialized.generics) {
if !used_generics.contains(&generic) {
remove_generic(&mut generics, &generic);
}
}
for generic in get_generics_types::<Vec<_>>(&specialized.generics) {
if !used_generics.contains(&generic) {
remove_generic(&mut generics, &generic);
let used_generics = get_used_generics(self, &str_to_generics(&self.generics));
let mut generics = str_to_generics(&self.generics);
handle_generics(&self.generics, |generic| {
if !used_generics.contains(generic) {
remove_generic(&mut generics, generic);
}
}
specialized.generics = to_string(&generics);

new_trait.specialized = Some(Box::new(specialized));
new_trait
});
self.generics = to_string(&generics);
}

/// apply a condition to the trait body, modifying its generics and items
Expand Down
Loading