├── .github ├── FUNDING.yml ├── dependabot.yaml └── workflows │ └── main.yml ├── clippy.toml ├── tests ├── remote_trait │ ├── Cargo.toml │ └── src │ │ └── lib.rs ├── ui_pass │ └── no_impls.rs ├── ui.rs ├── ui_fail │ ├── already_used.stderr │ ├── default_parameters.stderr │ ├── type_impl_trait.stderr │ ├── type_impl_trait.rs │ ├── conflicting_inherent_items.stderr │ ├── type_alias_overlap.rs │ ├── const_expr_overlap.rs │ ├── already_used.rs │ ├── unqualified_type_param.stderr │ ├── overlapping_2.stderr │ ├── type_alias_overlap.stderr │ ├── const_expr_overlap.stderr │ ├── overlapping.rs │ ├── unqualified_type_param.rs │ ├── conflicting_inherent_items.rs │ ├── overlapping_2.rs │ ├── default_parameters.rs │ ├── overlapping.stderr │ ├── missing_impl.rs │ ├── unsized.rs │ ├── missing_impl.stderr │ └── unsized.stderr ├── inherent_with_receiver.rs ├── fully_qualified_generic_param.rs ├── single_inherent_impl.rs ├── derivative_assoc_binding.rs ├── single_impl.rs ├── differing_inherent_items.rs ├── dispatch_on_self.rs ├── generic_arg_constraint.rs ├── non_overlapping_blanket_impls.rs ├── trait_with_const_param.rs ├── dispatch_on_different_parameters.rs ├── composite_where_clause.rs ├── nested_subgroups_2.rs ├── extra_param_bounds.rs ├── concrete_assoc_type.rs ├── trait_param_with_extra_bound.rs ├── non_superset.rs ├── dispatch_on_concrete_type.rs ├── dispatch_on_local_trait.rs ├── remote_trait.rs ├── multiple_associated_types.rs ├── supersets_1.rs ├── shared_helper.rs ├── basic.rs ├── dispatch_on_undefined_assoc_binding.rs ├── overlapping_idents.rs ├── extra_parameter.rs ├── trait_with_lifetime.rs ├── multiple_dispatch_traits.rs ├── dispatch_with_same_param.rs ├── generalized_signature.rs ├── unsafety.rs ├── supersets_2.rs ├── unsized_type.rs ├── elided_lifetime.rs ├── trait_object.rs ├── derivative_self_ty.rs ├── overlapping_common_group.rs ├── dispatch_on_assoc_type.rs ├── dispatch_on_generic.rs ├── gats.rs ├── multiple_blanket_impls.rs ├── disparate_trait_generics.rs ├── nested_subgroups.rs ├── inherent_nested_subgroups.rs ├── trait_with_assoc_type.rs ├── recursive_call.rs ├── dispatch_inherent_on_generic.rs ├── unconstrained_params.rs └── disjoint_inherent_impl.rs ├── .gitignore ├── Cargo.toml ├── src ├── generalize │ ├── token.rs │ ├── stmt.rs │ ├── item.rs │ ├── generics.rs │ └── pat.rs ├── disjoint.rs ├── helper_trait.rs ├── normalize.rs └── validate.rs ├── README.md └── CHANGELOG.md /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [mversic] 2 | patreon: mversic 3 | custom: paypal.me/marin101 4 | -------------------------------------------------------------------------------- /clippy.toml: -------------------------------------------------------------------------------- 1 | disallowed-types = ["std::collections::HashMap", "std::collections::HashSet"] 2 | -------------------------------------------------------------------------------- /tests/remote_trait/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "remote_trait" 3 | version = "0.1.0" 4 | edition = "2024" 5 | 6 | [dependencies] 7 | -------------------------------------------------------------------------------- /tests/ui_pass/no_impls.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | disjoint_impls! { 4 | pub trait Kita { 5 | const NAME: &'static str; 6 | } 7 | } 8 | 9 | fn main() {} 10 | -------------------------------------------------------------------------------- /tests/remote_trait/src/lib.rs: -------------------------------------------------------------------------------- 1 | /// Trait that has blanket impls defined in another crate. 2 | pub trait ForeignKita { 3 | fn kita() -> &'static str { 4 | "Default blanket" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /tests/ui.rs: -------------------------------------------------------------------------------- 1 | use trybuild::TestCases; 2 | 3 | #[test] 4 | fn ui() { 5 | let test_cases = TestCases::new(); 6 | test_cases.pass("tests/ui_pass/*.rs"); 7 | test_cases.compile_fail("tests/ui_fail/*.rs"); 8 | } 9 | -------------------------------------------------------------------------------- /tests/ui_fail/already_used.stderr: -------------------------------------------------------------------------------- 1 | error: `impl Trait` is not allowed in this position 2 | --> tests/ui_fail/already_used.rs:13:30 3 | | 4 | 13 | impl> Kita for T { 5 | | ^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/ui_fail/default_parameters.stderr: -------------------------------------------------------------------------------- 1 | error: Specify all trait arguments (including default) 2 | --> tests/ui_fail/default_parameters.rs:33:39 3 | | 4 | 33 | impl> Kita for T { 5 | | ^^^^ 6 | -------------------------------------------------------------------------------- /tests/ui_fail/type_impl_trait.stderr: -------------------------------------------------------------------------------- 1 | error: `impl Trait` is not allowed in this position 2 | --> tests/ui_fail/type_impl_trait.rs:12:30 3 | | 4 | 12 | impl> Kita for T { 5 | | ^^^^^^^^^^^^^ 6 | -------------------------------------------------------------------------------- /tests/ui_fail/type_impl_trait.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | disjoint_impls! { 8 | pub trait Kita { 9 | const NAME: &'static str; 10 | } 11 | 12 | impl> Kita for T { 13 | const NAME: &'static str = "Blanket A"; 14 | } 15 | } 16 | 17 | fn main() {} 18 | -------------------------------------------------------------------------------- /tests/ui_fail/conflicting_inherent_items.stderr: -------------------------------------------------------------------------------- 1 | error[E0592]: duplicate definitions with name `kita` 2 | --> tests/ui_fail/conflicting_inherent_items.rs:21:9 3 | | 4 | 21 | fn kita() -> &'static str { 5 | | ^^^^^^^^^^^^^^^^^^^^^^^^^ duplicate definitions for `kita` 6 | ... 7 | 26 | fn kita() -> String { 8 | | ------------------- other definition for `kita` 9 | -------------------------------------------------------------------------------- /tests/ui_fail/type_alias_overlap.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | type Alias = Vec; 4 | 5 | trait Dispatch { 6 | type Group; 7 | } 8 | 9 | impl Dispatch for u32 { 10 | type Group = Vec; 11 | } 12 | 13 | disjoint_impls! { 14 | trait Kita {} 15 | 16 | impl> Kita for T {} 17 | impl>> Kita for T {} 18 | } 19 | -------------------------------------------------------------------------------- /tests/ui_fail/const_expr_overlap.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | trait Dispatch { 4 | type Group; 5 | } 6 | 7 | struct FourArray; 8 | impl Dispatch for FourArray { 9 | type Group = [u8; 4]; 10 | } 11 | 12 | disjoint_impls! { 13 | trait Kita {} 14 | 15 | impl> Kita for T {} 16 | impl> Kita for T {} 17 | } 18 | -------------------------------------------------------------------------------- /tests/ui_fail/already_used.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | disjoint_impls! { 8 | pub trait Kita { 9 | type Kara; 10 | fn kita(a: T); 11 | } 12 | 13 | impl> Kita for T { 14 | type Kara = (); 15 | fn kita(a: T) {} 16 | } 17 | } 18 | 19 | fn main() {} 20 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "weekly" 8 | commit-message: 9 | prefix: chore 10 | include: scope 11 | 12 | - package-ecosystem: "cargo" 13 | directory: "/" 14 | schedule: 15 | interval: "daily" 16 | commit-message: 17 | prefix: chore 18 | include: scope 19 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Generated by Cargo 2 | # will have compiled files and executables 3 | debug/ 4 | target/ 5 | 6 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries 7 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html 8 | Cargo.lock 9 | 10 | # These are backup files generated by rustfmt 11 | **/*.rs.bk 12 | 13 | # MSVC Windows builds of rustc generate these, which store debugging information 14 | *.pdb 15 | -------------------------------------------------------------------------------- /tests/ui_fail/unqualified_type_param.stderr: -------------------------------------------------------------------------------- 1 | error: Ambiguous associated type. Qualify with a trait to disambiguate (e.g. < T as Trait > :: Group) 2 | --> tests/ui_fail/unqualified_type_param.rs:12:9 3 | | 4 | 12 | T::Group: Dispatch, 5 | | ^^^^^^^^ 6 | 7 | error: Ambiguous associated type. Qualify with a trait to disambiguate (e.g. < T as Trait > :: Group) 8 | --> tests/ui_fail/unqualified_type_param.rs:26:9 9 | | 10 | 26 | ::Group: Dispatch, 11 | | ^^^^^^^^^^ 12 | -------------------------------------------------------------------------------- /tests/ui_fail/overlapping_2.stderr: -------------------------------------------------------------------------------- 1 | error[E0119]: conflicting implementations of trait `Kita0` 2 | --> tests/ui_fail/overlapping_2.rs:21:5 3 | | 4 | 18 | impl + Dispatch2> Kita for T { 5 | | ------------------------------------------------------------------------------ first implementation here 6 | ... 7 | 21 | impl + Dispatch2> Kita for T { 8 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation 9 | -------------------------------------------------------------------------------- /tests/ui_fail/type_alias_overlap.stderr: -------------------------------------------------------------------------------- 1 | error[E0601]: `main` function not found in crate `$CRATE` 2 | --> tests/ui_fail/type_alias_overlap.rs:18:2 3 | | 4 | 18 | } 5 | | ^ consider adding a `main` function to `$DIR/tests/ui_fail/type_alias_overlap.rs` 6 | 7 | error[E0119]: conflicting implementations of trait `Kita0>` 8 | --> tests/ui_fail/type_alias_overlap.rs:17:5 9 | | 10 | 16 | impl> Kita for T {} 11 | | ------------------------------------------- first implementation here 12 | 17 | impl>> Kita for T {} 13 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation 14 | -------------------------------------------------------------------------------- /tests/ui_fail/const_expr_overlap.stderr: -------------------------------------------------------------------------------- 1 | error[E0601]: `main` function not found in crate `$CRATE` 2 | --> tests/ui_fail/const_expr_overlap.rs:17:2 3 | | 4 | 17 | } 5 | | ^ consider adding a `main` function to `$DIR/tests/ui_fail/const_expr_overlap.rs` 6 | 7 | error[E0119]: conflicting implementations of trait `Kita0<[u8; 4]>` 8 | --> tests/ui_fail/const_expr_overlap.rs:16:5 9 | | 10 | 15 | impl> Kita for T {} 11 | | ------------------------------------------------- first implementation here 12 | 16 | impl> Kita for T {} 13 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation 14 | -------------------------------------------------------------------------------- /tests/ui_fail/overlapping.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | pub enum GroupB {} 9 | pub enum GroupC {} 10 | 11 | disjoint_impls! { 12 | pub trait Kita { 13 | const NAME: &'static str; 14 | } 15 | 16 | impl> Kita for T { 17 | const NAME: &'static str = "Blanket A"; 18 | } 19 | impl> Kita for &T { 20 | const NAME: &'static str = "Blanket B"; 21 | } 22 | impl> Kita for &mut U { 23 | const NAME: &'static str = "Blanket C"; 24 | } 25 | } 26 | 27 | fn main() {} 28 | -------------------------------------------------------------------------------- /tests/ui_fail/unqualified_type_param.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch {} 4 | 5 | disjoint_impls! { 6 | pub trait Kita1 { 7 | const NAME: &'static str; 8 | } 9 | 10 | impl Kita1 for T 11 | where 12 | T::Group: Dispatch, 13 | { 14 | const NAME: &'static str = "Blanket A"; 15 | } 16 | } 17 | 18 | disjoint_impls! { 19 | pub trait Kita2 { 20 | const NAME: &'static str; 21 | } 22 | 23 | impl Kita2 for T 24 | where 25 | T: Dispatch, 26 | ::Group: Dispatch, 27 | { 28 | const NAME: &'static str = "Blanket A"; 29 | } 30 | } 31 | 32 | fn main() {} 33 | -------------------------------------------------------------------------------- /tests/ui_fail/conflicting_inherent_items.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | 12 | pub enum GroupB {} 13 | impl Dispatch for i32 { 14 | type Group = GroupB; 15 | } 16 | 17 | struct Wrapper(T); 18 | 19 | disjoint_impls! { 20 | impl> Wrapper { 21 | fn kita() -> &'static str { 22 | "Blanket A" 23 | } 24 | } 25 | impl> Wrapper { 26 | fn kita() -> String { 27 | "Blanket B".to_owned() 28 | } 29 | } 30 | } 31 | 32 | fn main() {} 33 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "disjoint_impls" 3 | version = "1.3.4" 4 | edition = "2024" 5 | license = "Apache-2.0" 6 | authors = ["Marin Veršić "] 7 | repository = "https://github.com/mversic/disjoint_impls" 8 | description = "Support for mutually disjoint impls" 9 | keywords = ["disjoint", "exclusive", "associated", "impl", "implementation"] 10 | 11 | [lib] 12 | proc-macro = true 13 | 14 | [dependencies] 15 | syn = {version = "2.0.105", features = ["full", "extra-traits", "visit", "visit-mut"]} 16 | proc-macro-error2 = "2.0.1" 17 | proc-macro2 = "1.0.97" 18 | itertools = "0.14.0" 19 | indexmap = "2.10.0" 20 | quote = "1.0.40" 21 | 22 | [dev-dependencies] 23 | remote_trait = { path = "tests/remote_trait" } 24 | trybuild = "1.0.110" 25 | -------------------------------------------------------------------------------- /tests/ui_fail/overlapping_2.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch1 { 4 | type Group; 5 | } 6 | pub trait Dispatch2 { 7 | type Group; 8 | } 9 | 10 | pub enum GroupA {} 11 | pub enum GroupB {} 12 | 13 | disjoint_impls! { 14 | pub trait Kita { 15 | const NAME: &'static str; 16 | } 17 | 18 | impl + Dispatch2> Kita for T { 19 | const NAME: &'static str = "Blanket AA"; 20 | } 21 | impl + Dispatch2> Kita for T { 22 | const NAME: &'static str = "Blanket AA"; 23 | } 24 | impl> Kita for T { 25 | const NAME: &'static str = "Blanket B*"; 26 | } 27 | } 28 | fn main() {} 29 | -------------------------------------------------------------------------------- /tests/inherent_with_receiver.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | trait Dispatch { 4 | type Group; 5 | } 6 | 7 | enum GroupA {} 8 | enum GroupB {} 9 | 10 | impl Dispatch for &str { 11 | type Group = GroupA; 12 | } 13 | 14 | impl Dispatch for i32 { 15 | type Group = GroupB; 16 | } 17 | 18 | struct Wrapper(T); 19 | 20 | disjoint_impls! { 21 | impl,> Wrapper { 22 | fn kita(&self) -> &'static str { 23 | "Blanket A" 24 | } 25 | } 26 | 27 | impl> Wrapper { 28 | fn kita(&self) -> &'static str { 29 | "Blanket B" 30 | } 31 | } 32 | } 33 | 34 | #[test] 35 | fn inherent_with_receiver() { 36 | assert_eq!("Blanket A", Wrapper("foo").kita()); 37 | assert_eq!("Blanket B", Wrapper(42).kita()); 38 | } 39 | -------------------------------------------------------------------------------- /tests/fully_qualified_generic_param.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | trait Dispatch { 4 | type Group; 5 | } 6 | 7 | enum GroupA {} 8 | enum GroupB {} 9 | 10 | impl Dispatch for u32 { 11 | type Group = GroupA; 12 | } 13 | 14 | impl Dispatch for i32 { 15 | type Group = GroupB; 16 | } 17 | 18 | disjoint_impls! { 19 | trait Kita { 20 | const NAME: &'static str; 21 | } 22 | 23 | impl> Kita<::Group> for T { 24 | const NAME: &'static str = "Blanket A"; 25 | } 26 | 27 | impl> Kita::Group>> for T { 28 | const NAME: &'static str = "Blanket B"; 29 | } 30 | } 31 | 32 | #[test] 33 | fn fully_qualified_generic_param() { 34 | assert_eq!("Blanket A", u32::NAME); 35 | assert_eq!("Blanket B", i32::NAME); 36 | } 37 | -------------------------------------------------------------------------------- /tests/ui_fail/default_parameters.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub trait Trait {} 8 | 9 | pub enum GroupA {} 10 | impl Dispatch for String { 11 | type Group = GroupA; 12 | } 13 | impl Dispatch for Vec { 14 | type Group = GroupA; 15 | } 16 | 17 | pub enum GroupB {} 18 | impl Dispatch for i32 { 19 | type Group = GroupB; 20 | } 21 | impl Dispatch for u32 { 22 | type Group = GroupB; 23 | } 24 | 25 | impl Trait for u32 {} 26 | impl Trait for [T; 1] {} 27 | 28 | disjoint_impls! { 29 | pub trait Kita { 30 | const NAME: &'static str; 31 | } 32 | 33 | impl> Kita for T { 34 | const NAME: &'static str = "Blanket A"; 35 | } 36 | impl> Kita<[T; 1]> for T { 37 | const NAME: &'static str = "Blanket B"; 38 | } 39 | } 40 | 41 | fn main() {} 42 | -------------------------------------------------------------------------------- /tests/single_inherent_impl.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub struct Wrapper<'a, T, const N: usize>(pub &'a T); 4 | 5 | disjoint_impls! { 6 | impl<'a, T, U> Wrapper<'a, (T, U), 12> { 7 | pub const NAME: &'static str = "Blanket"; 8 | 9 | fn kita(_a: T, _b: U) -> &'static str 10 | where 11 | T: 'a, 12 | U: 'a, 13 | { 14 | Self::NAME 15 | } 16 | } 17 | } 18 | 19 | /* 20 | const _: () = { 21 | impl<'a, T, U> Wrapper<'a, (T, U), 12> { 22 | pub const NAME: &'static str = "Blanket"; 23 | fn kita(_a: T, _b: U) -> &'static str 24 | where 25 | T: 'a, 26 | U: 'a, 27 | { 28 | Self::NAME 29 | } 30 | } 31 | }; 32 | */ 33 | 34 | #[test] 35 | fn single_inherent_impl() { 36 | assert_eq!("Blanket", >::kita(42, 420)); 37 | assert_eq!("Blanket", >::NAME); 38 | } 39 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "main" ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | static-analysis: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v6 19 | - uses: dtolnay/rust-toolchain@stable 20 | with: 21 | components: "rustfmt, clippy" 22 | - uses: Swatinem/rust-cache@v2 23 | 24 | - name: Rust Format + Check + Lint 25 | run: | 26 | cargo fmt --all --check 27 | cargo clippy --workspace --benches --tests --examples --quiet 28 | 29 | test: 30 | runs-on: ubuntu-latest 31 | needs: static-analysis 32 | 33 | steps: 34 | - uses: actions/checkout@v6 35 | - uses: dtolnay/rust-toolchain@stable 36 | - uses: Swatinem/rust-cache@v2 37 | 38 | - name: Run tests 39 | run: cargo test --workspace 40 | -------------------------------------------------------------------------------- /tests/ui_fail/overlapping.stderr: -------------------------------------------------------------------------------- 1 | error[E0119]: conflicting implementations of trait `Kita` for type `&_` 2 | --> tests/ui_fail/overlapping.rs:19:5 3 | | 4 | 16 | impl> Kita for T { 5 | | -------------------------------------------- first implementation here 6 | ... 7 | 19 | impl> Kita for &T { 8 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&_` 9 | | 10 | = note: downstream crates may implement trait `Dispatch` for type `&_` 11 | 12 | error[E0119]: conflicting implementations of trait `Kita` for type `&mut _` 13 | --> tests/ui_fail/overlapping.rs:22:5 14 | | 15 | 16 | impl> Kita for T { 16 | | -------------------------------------------- first implementation here 17 | ... 18 | 22 | impl> Kita for &mut U { 19 | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `&mut _` 20 | | 21 | = note: downstream crates may implement trait `Dispatch` for type `&mut _` 22 | -------------------------------------------------------------------------------- /src/generalize/token.rs: -------------------------------------------------------------------------------- 1 | use syn::Token; 2 | 3 | use super::*; 4 | 5 | impl Generalize for Token![&] { 6 | fn generalize( 7 | &self, 8 | _: &Self, 9 | _: &Params, 10 | _: &Params, 11 | _: &mut Generalizations<'_>, 12 | ) -> Option { 13 | Some(*self) 14 | } 15 | } 16 | 17 | impl Generalize for Token![if] { 18 | fn generalize( 19 | &self, 20 | _: &Self, 21 | _: &Params, 22 | _: &Params, 23 | _: &mut Generalizations<'_>, 24 | ) -> Option { 25 | Some(*self) 26 | } 27 | } 28 | 29 | impl Generalize for Token![else] { 30 | fn generalize( 31 | &self, 32 | _: &Self, 33 | _: &Params, 34 | _: &Params, 35 | _: &mut Generalizations<'_>, 36 | ) -> Option { 37 | Some(*self) 38 | } 39 | } 40 | 41 | impl Generalize for Token![@] { 42 | fn generalize( 43 | &self, 44 | _: &Self, 45 | _: &Params, 46 | _: &Params, 47 | _: &mut Generalizations<'_>, 48 | ) -> Option { 49 | Some(*self) 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/ui_fail/missing_impl.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch1 { 4 | type Group; 5 | } 6 | pub trait Dispatch2 { 7 | type Group; 8 | } 9 | 10 | pub enum GroupA {} 11 | pub enum GroupB {} 12 | 13 | impl Dispatch1 for String { 14 | type Group = GroupA; 15 | } 16 | impl Dispatch2 for String { 17 | type Group = GroupA; 18 | } 19 | impl Dispatch1 for Vec { 20 | type Group = GroupA; 21 | } 22 | impl Dispatch2 for Vec { 23 | type Group = GroupB; 24 | } 25 | 26 | impl Dispatch1 for i32 { 27 | type Group = GroupB; 28 | } 29 | impl Dispatch1 for u32 { 30 | type Group = GroupB; 31 | } 32 | 33 | disjoint_impls! { 34 | pub trait Kita { 35 | const NAME: &'static str; 36 | } 37 | 38 | impl + Dispatch2> Kita for T { 39 | const NAME: &'static str = "Blanket A"; 40 | } 41 | impl> Kita for T { 42 | const NAME: &'static str = "Blanket B"; 43 | } 44 | } 45 | 46 | fn main() { 47 | assert_eq!("Blanket A", String::NAME); 48 | assert_eq!("Blanket B", u32::NAME); 49 | assert_eq!("Blanket B", i32::NAME); 50 | 51 | let _ = as Kita>::NAME; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /tests/derivative_assoc_binding.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | struct LocalType(T); 4 | 5 | struct GroupA(T); 6 | struct GroupB(T); 7 | 8 | impl Kita for u32 { 9 | type Group = GroupA; 10 | 11 | const NAME: &'static str = "u32 impl"; 12 | } 13 | 14 | impl Kita for i32 { 15 | type Group = GroupB; 16 | const NAME: &'static str = "i32 impl"; 17 | } 18 | 19 | disjoint_impls! { 20 | trait Kita { 21 | type Group; 22 | 23 | const NAME: &'static str; 24 | } 25 | 26 | impl Kita for LocalType 27 | where 28 | T: Kita>, 29 | { 30 | type Group = (); 31 | 32 | const NAME: &'static str = "Blanket A"; 33 | } 34 | 35 | impl Kita for LocalType 36 | where 37 | T: Kita>, 38 | { 39 | type Group = (); 40 | 41 | const NAME: &'static str = "Blanket B"; 42 | } 43 | } 44 | 45 | #[test] 46 | fn derivative_assoc_binding() { 47 | assert_eq!("u32 impl", ::NAME); 48 | assert_eq!("i32 impl", ::NAME); 49 | 50 | assert_eq!("Blanket A", as Kita>::NAME); 51 | assert_eq!("Blanket B", as Kita>::NAME); 52 | } 53 | -------------------------------------------------------------------------------- /tests/single_impl.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | disjoint_impls! { 4 | pub trait Kita 5 | where 6 | T: Default, 7 | { 8 | type GenericAssociatedType; 9 | 10 | fn kita(_: Self::GenericAssociatedType) -> &'static str; 11 | } 12 | 13 | impl Kita for R 14 | where 15 | R: std::ops::Deref, 16 | { 17 | type GenericAssociatedType = GAT; 18 | 19 | fn kita(_: Self::GenericAssociatedType) -> &'static str { 20 | "Blanket" 21 | } 22 | } 23 | } 24 | 25 | /* 26 | pub trait Kita 27 | where 28 | T: Default, 29 | { 30 | type GenericAssociatedType; 31 | fn kita(_: Self::GenericAssociatedType) -> &'static str; 32 | } 33 | 34 | const _: () = { 35 | impl Kita for R 36 | where 37 | R: std::ops::Deref, 38 | { 39 | type GenericAssociatedType = GAT; 40 | fn kita(_: Self::GenericAssociatedType) -> &'static str { 41 | "Blanket" 42 | } 43 | } 44 | }; 45 | */ 46 | 47 | #[test] 48 | fn single_impl() { 49 | assert_eq!("Blanket", >::kita(12)); 50 | assert_eq!("Blanket", as Kita>::kita(12)); 51 | } 52 | -------------------------------------------------------------------------------- /tests/differing_inherent_items.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for Option { 9 | type Group = GroupA; 10 | } 11 | 12 | pub enum GroupB {} 13 | impl Dispatch for i32 { 14 | type Group = GroupB; 15 | } 16 | 17 | struct Wrapper(T); 18 | 19 | disjoint_impls! { 20 | impl Wrapper 21 | where 22 | Option: Dispatch, 23 | { 24 | fn kita() -> &'static str { 25 | "Blanket A" 26 | } 27 | } 28 | impl Wrapper 29 | where 30 | T: Dispatch, 31 | { 32 | fn kita() -> String { 33 | "Blanket B".to_owned() 34 | } 35 | } 36 | } 37 | 38 | /* 39 | const _: () = { 40 | impl Wrapper 41 | where 42 | Option: Dispatch, 43 | { 44 | fn kita() -> &'static str { 45 | "Blanket A" 46 | } 47 | } 48 | 49 | impl Wrapper 50 | where 51 | T: Dispatch, 52 | { 53 | fn kita() -> String { 54 | "Blanket B".to_owned() 55 | } 56 | } 57 | }; 58 | */ 59 | 60 | #[test] 61 | fn differing_inherent_items() { 62 | assert_eq!("Blanket A", Wrapper::::kita()); 63 | assert_eq!("Blanket B".to_owned(), Wrapper::::kita()); 64 | } 65 | -------------------------------------------------------------------------------- /tests/ui_fail/unsized.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group: ?Sized; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub struct GroupB; 16 | impl Dispatch for str { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for [u8] { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita { 25 | fn kita(&self) -> String; 26 | } 27 | 28 | impl, U: ?Sized, V> Kita for T { 29 | fn kita(&self) -> String { 30 | "Blanket A".to_owned() 31 | } 32 | } 33 | 34 | impl + ?Sized, U, V> Kita for T { 35 | fn kita(&self) -> String { 36 | "Blanket B".to_owned() 37 | } 38 | } 39 | } 40 | 41 | fn main() { 42 | assert_eq!("Blanket A", >::kita(&"")); 43 | assert_eq!("Blanket A", as Kita>::kita(&Vec::new())); 44 | assert_eq!("Blanket B", >::kita(&"")); 45 | assert_eq!("Blanket B", <[u8] as Kita>::kita(&[])); 46 | 47 | assert_eq!("Blanket A", >::kita(&String::new())); 48 | assert_eq!("Blanket A", as Kita>::kita(&Vec::new())); 49 | assert_eq!("Blanket B", >::kita(&"")); 50 | assert_eq!("Blanket B", <[u8] as Kita>::kita(&[])); 51 | } 52 | -------------------------------------------------------------------------------- /tests/dispatch_on_self.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | 12 | pub enum GroupB {} 13 | impl Dispatch for Option { 14 | type Group = GroupB; 15 | } 16 | 17 | disjoint_impls! { 18 | pub trait Kita { 19 | const NAME: &'static str; 20 | } 21 | 22 | impl Kita for T where Self: Dispatch { 23 | const NAME: &'static str = "Blanket A"; 24 | } 25 | impl> Kita for T { 26 | const NAME: &'static str = "Blanket B"; 27 | } 28 | } 29 | 30 | /* 31 | pub trait Kita { 32 | const NAME: &'static str; 33 | } 34 | 35 | const _: () = { 36 | pub trait Kita0<_TŠČ0: ?Sized> { 37 | const NAME: &'static str; 38 | } 39 | impl Kita0 for T 40 | where 41 | T: Dispatch, 42 | { 43 | const NAME: &'static str = "Blanket A"; 44 | } 45 | impl> Kita0 for T { 46 | const NAME: &'static str = "Blanket B"; 47 | } 48 | 49 | impl<_TŠČ0> Kita for _TŠČ0 50 | where 51 | _TŠČ0: Dispatch, 52 | Self: Kita0<<_TŠČ0 as Dispatch>::Group>, 53 | { 54 | const NAME: &'static str = ::Group>>::NAME; 55 | } 56 | }; 57 | */ 58 | 59 | #[test] 60 | fn dispatch_on_self() { 61 | assert_eq!("Blanket A", String::NAME); 62 | assert_eq!("Blanket B", Option::::NAME); 63 | } 64 | -------------------------------------------------------------------------------- /tests/generic_arg_constraint.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | trait Bound {} 4 | 5 | trait Dispatch { 6 | type Group: ?Sized; 7 | } 8 | 9 | impl Bound for str {} 10 | impl Dispatch for u32 { 11 | type Group = str; 12 | } 13 | impl Dispatch for i32 { 14 | type Group = u32; 15 | } 16 | 17 | disjoint_impls! { 18 | pub trait Kita { 19 | const NAME: &str; 20 | } 21 | 22 | // FIXME: ?Sized should be inferred. Rust doesn't allow it 23 | // here, but the disjoint_impls! macro rewrites the impl 24 | impl> Kita for Box { 25 | const NAME: &str = "Blanket A"; 26 | } 27 | impl> Kita for Box { 28 | const NAME: &str = "Blanket B"; 29 | } 30 | } 31 | 32 | /* 33 | pub trait Kita { 34 | const NAME: &str; 35 | } 36 | 37 | const _: () = { 38 | pub trait Kita0<_TŠČ0: ?Sized> { 39 | const NAME: &str; 40 | } 41 | impl, _TŠČ0: Bound + ?Sized> Kita0<_TŠČ0> 42 | for Box { 43 | const NAME: &str = "Blanket A"; 44 | } 45 | impl> Kita0 for Box { 46 | const NAME: &str = "Blanket B"; 47 | } 48 | 49 | impl<_TŠČ0> Kita for Box<_TŠČ0> 50 | where 51 | _TŠČ0: Dispatch, 52 | Self: Kita0<<_TŠČ0 as Dispatch>::Group>, 53 | { 54 | const NAME: &str = ::Group>>::NAME; 55 | } 56 | }; 57 | */ 58 | 59 | #[test] 60 | fn generic_arg_constraint() { 61 | assert_eq!( as Kita>::NAME, "Blanket A"); 62 | assert_eq!( as Kita>::NAME, "Blanket B"); 63 | } 64 | -------------------------------------------------------------------------------- /tests/ui_fail/missing_impl.stderr: -------------------------------------------------------------------------------- 1 | error[E0271]: type mismatch resolving ` as Dispatch2>::Group == GroupA` 2 | --> tests/ui_fail/missing_impl.rs:51:14 3 | | 4 | 51 | let _ = as Kita>::NAME; 5 | | ^^^^^^^^^^ type mismatch resolving ` as Dispatch2>::Group == GroupA` 6 | | 7 | note: expected this to be `GroupA` 8 | --> tests/ui_fail/missing_impl.rs:23:18 9 | | 10 | 23 | type Group = GroupB; 11 | | ^^^^^^ 12 | note: required for `Vec` to implement `Kita0` 13 | --> tests/ui_fail/missing_impl.rs:33:1 14 | | 15 | 33 | / disjoint_impls! { 16 | 34 | | pub trait Kita { 17 | 35 | | const NAME: &'static str; 18 | ... | 19 | 38 | | impl + Dispatch2> Kita for T { 20 | | | -------------- ^ 21 | | | | 22 | | | unsatisfied trait bound introduced here 23 | ... | 24 | 44 | | } 25 | | |_^ 26 | note: required for `Vec` to implement `Kita` 27 | --> tests/ui_fail/missing_impl.rs:33:1 28 | | 29 | 33 | / disjoint_impls! { 30 | 34 | | pub trait Kita { 31 | 35 | | const NAME: &'static str; 32 | ... | 33 | 38 | | impl + Dispatch2> Kita for T { 34 | | | ^^^^ 35 | ... | 36 | 44 | | } 37 | | |_^ 38 | = note: this error originates in the macro `disjoint_impls` (in Nightly builds, run with -Z macro-backtrace for more info) 39 | -------------------------------------------------------------------------------- /tests/non_overlapping_blanket_impls.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for u32 { 9 | type Group = GroupA; 10 | } 11 | 12 | pub enum GroupB {} 13 | impl Dispatch for i32 { 14 | type Group = GroupB; 15 | } 16 | 17 | disjoint_impls! { 18 | trait Kita { 19 | const NAME: &'static str; 20 | } 21 | 22 | impl Kita for (T,) { 23 | const NAME: &'static str = "Blanket 1"; 24 | } 25 | 26 | impl Kita for Option { 27 | const NAME: &'static str = "Concrete Option"; 28 | } 29 | 30 | impl<_0, _1> Kita for (_0, _1) 31 | where 32 | _0: Dispatch, 33 | { 34 | const NAME: &'static str = "Blanket A"; 35 | } 36 | impl<_0> Kita for (Vec<_0>, Vec<_0>) 37 | where 38 | _0: Dispatch, 39 | { 40 | const NAME: &'static str = "Blanket B"; 41 | } 42 | } 43 | 44 | /* 45 | trait Kita { 46 | const NAME: &'static str; 47 | } 48 | 49 | const _: () = { 50 | impl Kita for (T,) { 51 | const NAME: &'static str = "Blanket 1"; 52 | } 53 | 54 | impl Kita for Option { 55 | const NAME: &'static str = "Concrete Option"; 56 | } 57 | 58 | impl<_0, _1> Kita for (_0, _1) 59 | where 60 | _0: Dispatch, 61 | { 62 | const NAME: &'static str = "Blanket A"; 63 | } 64 | 65 | impl<_0> Kita for (Vec<_0>, Vec<_0>) 66 | where 67 | _0: Dispatch, 68 | { 69 | const NAME: &'static str = "Blanket B"; 70 | } 71 | }; 72 | */ 73 | 74 | #[test] 75 | fn non_overlapping_blanket_impls() { 76 | assert_eq!("Blanket 1", <(String,)>::NAME); 77 | assert_eq!("Concrete Option", Option::::NAME); 78 | 79 | assert_eq!(<(u32, Vec)>::NAME, "Blanket A"); 80 | assert_eq!(<(Vec, Vec)>::NAME, "Blanket B"); 81 | } 82 | -------------------------------------------------------------------------------- /tests/trait_with_const_param.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | trait Dispatch { 4 | type Group; 5 | } 6 | 7 | enum GroupA {} 8 | enum GroupB {} 9 | 10 | impl Dispatch<1> for [i32; 1] { 11 | type Group = GroupA; 12 | } 13 | impl Dispatch<2> for [i32; 2] { 14 | type Group = GroupB; 15 | } 16 | 17 | disjoint_impls! { 18 | trait Kita { 19 | const NAME: &'static str; 20 | } 21 | 22 | impl Kita for [i32; N] 23 | where 24 | [i32; N]: Dispatch, 25 | { 26 | const NAME: &'static str = "Blanket A"; 27 | } 28 | 29 | impl Kita for [i32; N] 30 | where 31 | [i32; N]: Dispatch, 32 | { 33 | const NAME: &'static str = "Blanket B"; 34 | } 35 | } 36 | 37 | /* 38 | trait Kita { 39 | const NAME: &'static str; 40 | } 41 | 42 | const _: () = { 43 | pub trait Kita0<_TŠČ1: ?Sized, const SIZE: usize> { 44 | const NAME: &'static str; 45 | } 46 | impl Kita0 for [i32; N] 47 | where 48 | [i32; N]: Dispatch, 49 | { 50 | const NAME: &'static str = "Blanket A"; 51 | } 52 | impl Kita0 for [i32; N] 53 | where 54 | [i32; N]: Dispatch, 55 | { 56 | const NAME: &'static str = "Blanket B"; 57 | } 58 | 59 | impl Kita<_CŠČ0> for [i32; _CŠČ0] 60 | where 61 | [i32; _CŠČ0]: Dispatch<_CŠČ0>, 62 | Self: Kita0<<[i32; _CŠČ0] as Dispatch<_CŠČ0>>::Group, _CŠČ0>, 63 | { 64 | const NAME: &'static str = >::Group, 66 | _CŠČ0, 67 | >>::NAME; 68 | } 69 | }; 70 | */ 71 | 72 | #[test] 73 | fn trait_with_const_param() { 74 | assert_eq!("Blanket A", <[i32; 1]>::NAME); 75 | assert_eq!("Blanket B", <[i32; 2]>::NAME); 76 | } 77 | -------------------------------------------------------------------------------- /tests/dispatch_on_different_parameters.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita { 25 | const NAME: &'static str; 26 | } 27 | 28 | impl Kita for T 29 | where 30 | U: Dispatch, 31 | { 32 | const NAME: &'static str = "Blanket A"; 33 | } 34 | impl> Kita for T { 35 | const NAME: &'static str = "Blanket B"; 36 | } 37 | } 38 | 39 | /* 40 | pub trait Kita { 41 | const NAME: &'static str; 42 | } 43 | 44 | const _: () = { 45 | pub trait Kita0<_TŠČ1: ?Sized, U> { 46 | const NAME: &'static str; 47 | } 48 | impl Kita0 for T 49 | where 50 | U: Dispatch, 51 | { 52 | const NAME: &'static str = "Blanket A"; 53 | } 54 | impl> Kita0 for T { 55 | const NAME: &'static str = "Blanket B"; 56 | } 57 | 58 | impl<_TŠČ0, _TŠČ1> Kita<_TŠČ0> for _TŠČ1 59 | where 60 | _TŠČ0: Dispatch, 61 | Self: Kita0<<_TŠČ0 as Dispatch>::Group, _TŠČ0>, 62 | { 63 | const NAME: &'static str = ::Group, 65 | _TŠČ0, 66 | >>::NAME; 67 | } 68 | }; 69 | */ 70 | 71 | #[test] 72 | fn dispatch_on_different_parameters() { 73 | assert_eq!("Blanket A", >::NAME); 74 | assert_eq!("Blanket B", as Kita>::NAME); 75 | assert_eq!("Blanket B", >::NAME); 76 | assert_eq!("Blanket B", >::NAME); 77 | } 78 | -------------------------------------------------------------------------------- /tests/composite_where_clause.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for Option { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Option> { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for Option { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for Option { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita { 25 | const NAME: &'static str; 26 | } 27 | 28 | impl Kita for T 29 | where 30 | Option: Dispatch, 31 | { 32 | const NAME: &'static str = "Blanket A"; 33 | } 34 | impl Kita for T 35 | where 36 | Option: Dispatch, 37 | { 38 | const NAME: &'static str = "Blanket B"; 39 | } 40 | } 41 | 42 | /* 43 | pub trait Kita { 44 | const NAME: &'static str; 45 | } 46 | 47 | const _: () = { 48 | pub trait Kita0<_TŠČ0: ?Sized> { 49 | const NAME: &'static str; 50 | } 51 | impl Kita0 for T 52 | where 53 | Option: Dispatch, 54 | { 55 | const NAME: &'static str = "Blanket A"; 56 | } 57 | impl Kita0 for T 58 | where 59 | Option: Dispatch, 60 | { 61 | const NAME: &'static str = "Blanket B"; 62 | } 63 | 64 | impl<_TŠČ0> Kita for _TŠČ0 65 | where 66 | Option<_TŠČ0>: Dispatch, 67 | Self: Kita0< as Dispatch>::Group>, 68 | { 69 | const NAME: &'static str = as Dispatch>::Group, 71 | >>::NAME; 72 | } 73 | }; 74 | */ 75 | 76 | #[test] 77 | fn composite_where_clause() { 78 | assert_eq!("Blanket A", ::NAME); 79 | assert_eq!("Blanket A", as Kita>::NAME); 80 | assert_eq!("Blanket B", ::NAME); 81 | assert_eq!("Blanket B", ::NAME); 82 | } 83 | -------------------------------------------------------------------------------- /tests/nested_subgroups_2.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | trait LocalTrait {} 4 | impl LocalTrait for i16 {} 5 | 6 | pub trait Dispatch1 { 7 | type Group; 8 | } 9 | pub trait Dispatch2 { 10 | type Group; 11 | } 12 | 13 | pub enum GroupA {} 14 | pub enum GroupB {} 15 | 16 | impl Dispatch1 for String { 17 | type Group = GroupA; 18 | } 19 | impl Dispatch2 for String { 20 | type Group = GroupA; 21 | } 22 | 23 | impl Dispatch1 for Vec { 24 | type Group = GroupA; 25 | } 26 | impl Dispatch2 for Vec { 27 | type Group = GroupB; 28 | } 29 | 30 | impl Dispatch1 for Vec { 31 | type Group = i16; 32 | } 33 | impl Dispatch2 for Vec { 34 | type Group = i16; 35 | } 36 | 37 | impl Dispatch1 for Vec { 38 | type Group = i16; 39 | } 40 | impl Dispatch2 for Vec { 41 | type Group = GroupB; 42 | } 43 | 44 | impl Dispatch1 for i32 { 45 | type Group = GroupB; 46 | } 47 | 48 | disjoint_impls! { 49 | pub trait Kita { 50 | const NAME: &'static str; 51 | } 52 | 53 | impl + Dispatch2> Kita for T { 54 | const NAME: &'static str = "Blanket AA"; 55 | } 56 | impl + Dispatch2> Kita for T { 57 | const NAME: &'static str = "Blanket AB"; 58 | } 59 | impl + Dispatch2, S: LocalTrait> Kita for T { 60 | const NAME: &'static str = "Blanket **"; 61 | } 62 | impl + Dispatch2> Kita for T { 63 | const NAME: &'static str = "Blanket *B"; 64 | } 65 | impl> Kita for T { 66 | const NAME: &'static str = "Blanket B*"; 67 | } 68 | } 69 | 70 | #[test] 71 | fn nested_subgroups_2() { 72 | assert_eq!("Blanket AA", String::NAME); 73 | assert_eq!("Blanket AB", Vec::::NAME); 74 | assert_eq!("Blanket **", Vec::::NAME); 75 | assert_eq!("Blanket *B", Vec::::NAME); 76 | assert_eq!("Blanket B*", i32::NAME); 77 | } 78 | -------------------------------------------------------------------------------- /tests/extra_param_bounds.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub trait A {} 8 | pub trait B {} 9 | 10 | pub enum GroupA {} 11 | impl A for String {} 12 | impl Dispatch for String { 13 | type Group = GroupA; 14 | } 15 | impl A for Vec {} 16 | impl Dispatch for Vec { 17 | type Group = GroupA; 18 | } 19 | 20 | pub enum GroupB {} 21 | impl B for i32 {} 22 | impl Dispatch for i32 { 23 | type Group = GroupB; 24 | } 25 | impl B for u32 {} 26 | impl Dispatch for u32 { 27 | type Group = GroupB; 28 | } 29 | 30 | disjoint_impls! { 31 | pub trait Kita { 32 | const NAME: &'static str; 33 | } 34 | 35 | impl + Dispatch + A> Kita for T { 36 | const NAME: &'static str = "Blanket A"; 37 | } 38 | impl> Kita for T 39 | where 40 | T: B + Dispatch, 41 | { 42 | const NAME: &'static str = "Blanket B"; 43 | } 44 | } 45 | 46 | /* 47 | pub trait Kita { 48 | const NAME: &'static str; 49 | } 50 | 51 | const _: () = { 52 | pub trait Kita0<_TŠČ1: ?Sized, U> { 53 | const NAME: &'static str; 54 | } 55 | impl + Dispatch + A> Kita0 for T { 56 | const NAME: &'static str = "Blanket A"; 57 | } 58 | impl> Kita0 for T 59 | where 60 | T: B + Dispatch, 61 | { 62 | const NAME: &'static str = "Blanket B"; 63 | } 64 | 65 | impl<_TŠČ0> Kita for _TŠČ0 66 | where 67 | _TŠČ0: Dispatch, 68 | Self: Kita0<<_TŠČ0 as Dispatch>::Group, u32>, 69 | { 70 | const NAME: &'static str = ::Group, 72 | u32, 73 | >>::NAME; 74 | } 75 | }; 76 | */ 77 | 78 | #[test] 79 | fn extra_param_bounds() { 80 | assert_eq!("Blanket A", String::NAME); 81 | assert_eq!("Blanket A", Vec::::NAME); 82 | assert_eq!("Blanket B", u32::NAME); 83 | assert_eq!("Blanket B", i32::NAME); 84 | } 85 | -------------------------------------------------------------------------------- /tests/concrete_assoc_type.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita { 25 | type Item; 26 | 27 | fn kita() -> Self::Item; 28 | } 29 | 30 | impl> Kita for T { 31 | type Item = u32; 32 | 33 | fn kita() -> u32 { 34 | 1 35 | } 36 | } 37 | impl + Default> Kita for U { 38 | type Item = U; 39 | 40 | fn kita() -> Self::Item { 41 | ::default() 42 | } 43 | } 44 | } 45 | 46 | /* 47 | pub trait Kita { 48 | type Item; 49 | 50 | fn kita() -> Self::Item; 51 | } 52 | 53 | const _: () = { 54 | pub trait Kita0<_TŠČ0: ?Sized> { 55 | type Item; 56 | 57 | fn kita() -> Self::Item; 58 | } 59 | impl> Kita0 for T { 60 | type Item = u32; 61 | 62 | fn kita() -> u32 { 63 | 1 64 | } 65 | } 66 | impl + Default> Kita0 for U { 67 | type Item = U; 68 | 69 | fn kita() -> Self::Item { 70 | ::default() 71 | } 72 | } 73 | 74 | impl<_TŠČ0> Kita for _TŠČ0 75 | where 76 | _TŠČ0: Dispatch, 77 | Self: Kita0<<_TŠČ0 as Dispatch>::Group>, 78 | { 79 | type Item = ::Group>>::Item; 80 | 81 | fn kita() -> Self::Item { 82 | ::Group>>::kita() 83 | } 84 | } 85 | }; 86 | */ 87 | 88 | #[test] 89 | fn concrete_assoc_type() { 90 | assert_eq!(1, String::kita()); 91 | assert_eq!(1, Vec::::kita()); 92 | assert_eq!(0, u32::kita()); 93 | assert_eq!(0, i32::kita()); 94 | } 95 | -------------------------------------------------------------------------------- /tests/trait_param_with_extra_bound.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | trait A {} 8 | 9 | pub enum GroupA {} 10 | impl A for u16 {} 11 | impl Dispatch for u16 { 12 | type Group = GroupA; 13 | } 14 | impl A for i16 {} 15 | impl Dispatch for i16 { 16 | type Group = GroupA; 17 | } 18 | 19 | pub enum GroupB {} 20 | impl Dispatch for i32 { 21 | type Group = GroupB; 22 | } 23 | impl Dispatch for u32 { 24 | type Group = GroupB; 25 | } 26 | 27 | disjoint_impls! { 28 | pub trait Kita = u32> { 29 | const NAME: &'static str; 30 | } 31 | 32 | impl + A, T> Kita for T 33 | where 34 | U: From, 35 | { 36 | const NAME: &'static str = "Blanket A"; 37 | } 38 | impl + From, T> Kita for T { 39 | const NAME: &'static str = "Blanket B"; 40 | } 41 | } 42 | 43 | /* 44 | pub trait Kita = u32> { 45 | const NAME: &'static str; 46 | } 47 | 48 | const _: () = { 49 | pub trait Kita0<_TŠČ1: ?Sized, U: From = u32> { 50 | const NAME: &'static str; 51 | } 52 | impl + A, T> Kita0 for T 53 | where 54 | U: From, 55 | { 56 | const NAME: &'static str = "Blanket A"; 57 | } 58 | impl + From, T> Kita0 for T { 59 | const NAME: &'static str = "Blanket B"; 60 | } 61 | 62 | impl<_TŠČ0, _TŠČ1> Kita<_TŠČ0> for _TŠČ1 63 | where 64 | _TŠČ0: From, 65 | _TŠČ0: From, 66 | _TŠČ0: Dispatch, 67 | Self: Kita0<<_TŠČ0 as Dispatch>::Group, _TŠČ0>, 68 | { 69 | const NAME: &'static str = ::Group, 71 | _TŠČ0, 72 | >>::NAME; 73 | } 74 | }; 75 | */ 76 | 77 | #[test] 78 | fn trait_param_with_extra_bound() { 79 | assert_eq!("Blanket A", >::NAME); 80 | assert_eq!("Blanket A", >::NAME); 81 | assert_eq!("Blanket B", >::NAME); 82 | assert_eq!("Blanket B", >::NAME); 83 | } 84 | -------------------------------------------------------------------------------- /tests/non_superset.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl<'a> Dispatch for &'a String { 9 | type Group = &'a GroupA; 10 | } 11 | impl<'a, T> Dispatch for &'a Vec { 12 | type Group = &'a GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for u32 { 17 | type Group = GroupA; 18 | } 19 | impl Dispatch for Vec { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | trait Kita { 25 | fn get_name() -> &'static str; 26 | } 27 | 28 | impl Kita for &(T, Vec) 29 | where 30 | T: Dispatch, 31 | { 32 | fn get_name() -> &'static str { 33 | "Blanket A" 34 | } 35 | } 36 | impl Kita for &(Vec, Vec) 37 | where 38 | Vec: Dispatch, 39 | { 40 | fn get_name() -> &'static str { 41 | "Blanket B" 42 | } 43 | } 44 | } 45 | 46 | /* 47 | trait Kita { 48 | fn get_name() -> &'static str; 49 | } 50 | 51 | const _: () = { 52 | pub trait Kita0<_TŠČ0: ?Sized> { 53 | fn get_name() -> &'static str; 54 | } 55 | impl<'_lšč0, T> Kita0 for &'_lšč0 (T, Vec) 56 | where 57 | T: Dispatch, 58 | { 59 | fn get_name() -> &'static str { 60 | "Blanket A" 61 | } 62 | } 63 | impl<'_lšč0, X> Kita0 for &'_lšč0 (Vec, Vec) 64 | where 65 | Vec: Dispatch, 66 | { 67 | fn get_name() -> &'static str { 68 | "Blanket B" 69 | } 70 | } 71 | 72 | impl<'_lšč0, _TŠČ0: '_lšč0, _TŠČ1: '_lšč0> Kita 73 | for &'_lšč0 (_TŠČ0, Vec<_TŠČ1>) 74 | where 75 | _TŠČ0: Dispatch, 76 | Self: Kita0<<_TŠČ0 as Dispatch>::Group>, 77 | { 78 | fn get_name() -> &'static str { 79 | ::Group>>::get_name() 80 | } 81 | } 82 | }; 83 | */ 84 | 85 | #[test] 86 | fn non_superset() { 87 | assert_eq!("Blanket A", <&(u32, Vec) as Kita>::get_name()); 88 | assert_eq!("Blanket B", <&(Vec, Vec) as Kita>::get_name()); 89 | } 90 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/mversic/disjoint_impls/blob/master/LICENSE) 2 | [![Crates.io](https://img.shields.io/crates/v/disjoint_impls.svg)](https://crates.io/crates/disjoint_impls) 3 | 4 | Crate will be maintained (at least) until [this idiom](https://github.com/rust-lang/rust/issues/20400) is allowed by the Rust compiler directly 5 | 6 | ## Description 7 | 8 | Enables writing non-overlapping (*disjoint*) impls distinguished by a set of associated types. 9 | 10 | Works for trait and inherent implementations alike (no special syntax). 11 | 12 | ### Trait implementations 13 | 14 | ```rs 15 | use disjoint_impls::disjoint_impls; 16 | 17 | pub trait Dispatch { 18 | type Group; 19 | } 20 | 21 | disjoint_impls! { 22 | pub trait Kita {} 23 | 24 | impl> Kita for T {} 25 | impl> Kita for T {} 26 | } 27 | ``` 28 | 29 | ### Inherent implementations 30 | 31 | ```rs 32 | use disjoint_impls::disjoint_impls; 33 | 34 | pub trait Dispatch { 35 | type Group; 36 | } 37 | 38 | struct Wrapper(T); 39 | 40 | disjoint_impls! { 41 | impl> Wrapper {} 42 | impl> Wrapper {} 43 | } 44 | ``` 45 | 46 | ### Foreign(remote) traits 47 | 48 | For traits defined outside the current crate (a.k.a. foreign or remote traits), duplicate 49 | the trait definition inside the macro and annotate it with `#[disjoint_impls(remote)]`. 50 | 51 | ```rs 52 | use disjoint_impls::disjoint_impls; 53 | // A foreign trait must be brought into scope so 54 | // the `disjoint_impls!` macro can refer to it. 55 | use remote_trait::ForeignKita; 56 | 57 | pub trait Dispatch { 58 | type Group; 59 | } 60 | 61 | // (orphan rule): You can define blanket impls only 62 | // for types that are defined in the current crate 63 | pub struct LocalType(T); 64 | 65 | disjoint_impls! { 66 | #[disjoint_impls(remote)] 67 | pub trait ForeignKita {} 68 | 69 | impl> ForeignKita for LocalType {} 70 | impl> ForeignKita for LocalType {} 71 | } 72 | ``` 73 | 74 | Other, much more complex examples, can be found in tests. 75 | -------------------------------------------------------------------------------- /tests/dispatch_on_concrete_type.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | impl Dispatch for u32 { 23 | type Group = GroupB; 24 | } 25 | 26 | disjoint_impls! { 27 | pub trait Kita { 28 | const NAME: &'static str; 29 | } 30 | 31 | impl, U> Kita for T 32 | where 33 | u32: Dispatch, 34 | { 35 | const NAME: &'static str = "Blanket A"; 36 | } 37 | impl, U> Kita for T 38 | where 39 | u32: Dispatch, 40 | { 41 | const NAME: &'static str = "Blanket B"; 42 | } 43 | } 44 | 45 | /* 46 | pub trait Kita { 47 | const NAME: &'static str; 48 | } 49 | 50 | const _: () = { 51 | pub trait Kita0<_TŠČ0: ?Sized, _TŠČ1: ?Sized> { 52 | const NAME: &'static str; 53 | } 54 | impl, U> Kita0 for T 55 | where 56 | u32: Dispatch, 57 | { 58 | const NAME: &'static str = "Blanket A"; 59 | } 60 | impl, U> Kita0 for T 61 | where 62 | u32: Dispatch, 63 | { 64 | const NAME: &'static str = "Blanket B"; 65 | } 66 | 67 | impl<_TŠČ0, _TŠČ1> Kita for _TŠČ0 68 | where 69 | u32: Dispatch, 70 | _TŠČ0: Dispatch<_TŠČ1>, 71 | Self: Kita0<_TŠČ1, <_TŠČ0 as Dispatch<_TŠČ1>>::Group>, 72 | { 73 | const NAME: &'static str = >::Group, 76 | >>::NAME; 77 | } 78 | }; 79 | */ 80 | 81 | fn main() { 82 | assert_eq!("Blanket A", ::NAME); 83 | assert_eq!("Blanket A", as Kita>::NAME); 84 | 85 | assert_eq!("Blanket B", ::NAME); 86 | assert_eq!("Blanket B", ::NAME); 87 | } 88 | -------------------------------------------------------------------------------- /tests/dispatch_on_local_trait.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait LocalTrait {} 4 | 5 | pub trait Dispatch { 6 | type Group; 7 | } 8 | 9 | pub enum LocalType {} 10 | impl Dispatch for String { 11 | type Group = LocalType; 12 | } 13 | impl Dispatch for Vec { 14 | type Group = u32; 15 | } 16 | 17 | impl Dispatch for u32 { 18 | type Group = i32; 19 | } 20 | 21 | impl LocalTrait for i32 {} 22 | 23 | // NOTE: Makes impls overlap 24 | //impl LocalTrait for u32 {} 25 | 26 | disjoint_impls! { 27 | pub trait Kita { 28 | const NAME: &str; 29 | 30 | type Kita; 31 | } 32 | 33 | impl> Kita for T { 34 | const NAME: &'static str = "Blanket A"; 35 | 36 | type Kita = u32; 37 | } 38 | impl> Kita for T { 39 | const NAME: &'static str = "Blanket B"; 40 | 41 | type Kita = u32; 42 | } 43 | impl, T: LocalTrait> Kita for U { 44 | const NAME: &'static str = "Blanket C"; 45 | 46 | type Kita = U::Group; 47 | } 48 | } 49 | 50 | /* 51 | pub trait Kita { 52 | const NAME: &str; 53 | type Kita; 54 | } 55 | 56 | const _: () = { 57 | pub trait Kita0<_TŠČ0: ?Sized> { 58 | const NAME: &str; 59 | type Kita; 60 | } 61 | impl> Kita0 for T { 62 | const NAME: &'static str = "Blanket A"; 63 | type Kita = u32; 64 | } 65 | impl> Kita0 for T { 66 | const NAME: &'static str = "Blanket B"; 67 | type Kita = u32; 68 | } 69 | impl, T: LocalTrait> Kita0 for U { 70 | const NAME: &'static str = "Blanket C"; 71 | type Kita = U::Group; 72 | } 73 | 74 | impl<_TŠČ0> Kita for _TŠČ0 75 | where 76 | _TŠČ0: Dispatch, 77 | Self: Kita0<<_TŠČ0 as Dispatch>::Group>, 78 | { 79 | const NAME: &str = ::Group>>::NAME; 80 | type Kita = ::Group>>::Kita; 81 | } 82 | }; 83 | */ 84 | 85 | #[test] 86 | fn dispatch_on_local_trait() { 87 | assert_eq!("Blanket A", String::NAME); 88 | assert_eq!("Blanket B", Vec::::NAME); 89 | assert_eq!("Blanket C", u32::NAME); 90 | } 91 | -------------------------------------------------------------------------------- /tests/remote_trait.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | use remote_trait::ForeignKita; 3 | 4 | pub trait Dispatch { 5 | type Group; 6 | } 7 | 8 | pub enum GroupA {} 9 | impl Dispatch for String { 10 | type Group = GroupA; 11 | } 12 | impl Dispatch for Vec { 13 | type Group = GroupA; 14 | } 15 | 16 | pub enum GroupB {} 17 | impl Dispatch for i32 { 18 | type Group = GroupB; 19 | } 20 | impl Dispatch for u32 { 21 | type Group = GroupB; 22 | } 23 | 24 | struct LocalType(T); 25 | 26 | disjoint_impls! { 27 | #[disjoint_impls(remote)] 28 | pub trait ForeignKita { 29 | fn kita() -> &'static str { 30 | "Default blanket" 31 | } 32 | } 33 | 34 | impl> ForeignKita for LocalType { 35 | fn kita() -> &'static str { 36 | "Blanket A" 37 | } 38 | } 39 | impl> ForeignKita for LocalType { 40 | fn kita() -> &'static str { 41 | "Blanket B" 42 | } 43 | } 44 | } 45 | 46 | /* 47 | const _: () = { 48 | pub trait ForeignKita0<_TŠČ1: ?Sized, U> { 49 | fn kita() -> &'static str { 50 | "Default blanket" 51 | } 52 | } 53 | impl> ForeignKita0 for LocalType { 54 | fn kita() -> &'static str { 55 | "Blanket A" 56 | } 57 | } 58 | impl> ForeignKita0 for LocalType { 59 | fn kita() -> &'static str { 60 | "Blanket B" 61 | } 62 | } 63 | 64 | impl<_TŠČ0, _TŠČ1> ForeignKita<_TŠČ0> for LocalType<_TŠČ1> 65 | where 66 | _TŠČ1: Dispatch, 67 | Self: ForeignKita0<<_TŠČ1 as Dispatch>::Group, _TŠČ0>, 68 | { 69 | fn kita() -> &'static str { 70 | ::Group, _TŠČ0>>::kita() 71 | } 72 | } 73 | }; 74 | */ 75 | 76 | #[test] 77 | fn remote_trait() { 78 | assert_eq!("Blanket A", as ForeignKita>::kita()); 79 | assert_eq!( 80 | "Blanket A", 81 | > as ForeignKita>::kita() 82 | ); 83 | assert_eq!("Blanket B", as ForeignKita>::kita()); 84 | assert_eq!("Blanket B", as ForeignKita>::kita()); 85 | } 86 | -------------------------------------------------------------------------------- /tests/multiple_associated_types.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group1; 5 | type Group2; 6 | } 7 | 8 | pub enum GroupA {} 9 | pub enum GroupB {} 10 | 11 | impl Dispatch for String { 12 | type Group1 = GroupA; 13 | type Group2 = GroupA; 14 | } 15 | impl Dispatch for Vec { 16 | type Group1 = GroupA; 17 | type Group2 = GroupB; 18 | } 19 | 20 | impl Dispatch for i32 { 21 | type Group1 = GroupB; 22 | type Group2 = GroupA; 23 | } 24 | impl Dispatch for u32 { 25 | type Group1 = GroupB; 26 | type Group2 = GroupB; 27 | } 28 | 29 | disjoint_impls! { 30 | pub trait Kita { 31 | const NAME: &'static str; 32 | } 33 | 34 | impl> Kita for T { 35 | const NAME: &'static str = "Blanket B*"; 36 | } 37 | impl> Kita for T { 38 | const NAME: &'static str = "Blanket AA"; 39 | } 40 | impl> Kita for T { 41 | const NAME: &'static str = "Blanket AB"; 42 | } 43 | } 44 | 45 | /* 46 | pub trait Kita { 47 | const NAME: &'static str; 48 | } 49 | 50 | const _: () = { 51 | pub trait Kita0<_TŠČ0: ?Sized, _TŠČ1: ?Sized> { 52 | const NAME: &'static str; 53 | } 54 | impl> Kita0::Group2> for T { 55 | const NAME: &'static str = "Blanket B*"; 56 | } 57 | impl> Kita0 for T { 58 | const NAME: &'static str = "Blanket AA"; 59 | } 60 | impl> Kita0 for T { 61 | const NAME: &'static str = "Blanket AB"; 62 | } 63 | 64 | impl<_TŠČ0> Kita for _TŠČ0 65 | where 66 | _TŠČ0: Dispatch, 67 | Self: Kita0<<_TŠČ0 as Dispatch>::Group1, <_TŠČ0 as Dispatch>::Group2>, 68 | { 69 | const NAME: &'static str = ::Group1, 71 | <_TŠČ0 as Dispatch>::Group2, 72 | >>::NAME; 73 | } 74 | }; 75 | */ 76 | 77 | #[test] 78 | fn multiple_associated_types() { 79 | assert_eq!("Blanket AA", String::NAME); 80 | assert_eq!("Blanket AB", Vec::::NAME); 81 | assert_eq!("Blanket B*", u32::NAME); 82 | assert_eq!("Blanket B*", i32::NAME); 83 | } 84 | -------------------------------------------------------------------------------- /tests/supersets_1.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group: ?Sized; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for Option { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Option { 12 | type Group = GroupA; 13 | } 14 | 15 | pub struct GroupB; 16 | impl Dispatch for Option> { 17 | type Group = GroupB; 18 | } 19 | 20 | disjoint_impls! { 21 | pub trait Kita { 22 | const NAME: &'static str; 23 | } 24 | 25 | impl Kita for T 26 | where 27 | Option: Dispatch, 28 | { 29 | const NAME: &'static str = "Blanket A"; 30 | } 31 | impl Kita for Vec 32 | where 33 | Option>: Dispatch, 34 | { 35 | const NAME: &'static str = "Blanket B"; 36 | } 37 | impl Kita for Option 38 | where 39 | Option: Dispatch, 40 | { 41 | const NAME: &'static str = "Blanket C"; 42 | } 43 | } 44 | 45 | /* 46 | pub trait Kita { 47 | const NAME: &'static str; 48 | } 49 | 50 | const _: () = { 51 | pub trait Kita0<_TŠČ0: ?Sized> { 52 | const NAME: &'static str; 53 | } 54 | impl Kita0 for T 55 | where 56 | Option: Dispatch, 57 | { 58 | const NAME: &'static str = "Blanket A"; 59 | } 60 | impl Kita0 for Vec 61 | where 62 | Option>: Dispatch, 63 | { 64 | const NAME: &'static str = "Blanket B"; 65 | } 66 | 67 | impl<_TŠČ0> Kita for _TŠČ0 68 | where 69 | Option<_TŠČ0>: Dispatch, 70 | Self: Kita0< as Dispatch>::Group>, 71 | { 72 | const NAME: &'static str = as Dispatch>::Group, 74 | >>::NAME; 75 | } 76 | 77 | impl Kita for Option 78 | where 79 | Option: Dispatch, 80 | { 81 | const NAME: &'static str = "Blanket C"; 82 | } 83 | }; 84 | */ 85 | 86 | #[test] 87 | fn supersets_1() { 88 | assert_eq!("Blanket A", String::NAME); 89 | assert_eq!("Blanket B", Vec::::NAME); 90 | assert_eq!("Blanket C", Option::::NAME); 91 | 92 | assert_eq!("Blanket A", u32::NAME); 93 | assert_eq!("Blanket B", Vec::::NAME); 94 | assert_eq!("Blanket C", Option::::NAME); 95 | } 96 | -------------------------------------------------------------------------------- /tests/shared_helper.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for [u32; 0] { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for u32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for [i32; 1] { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita: Dispatch { 25 | const NAME: &'static str; 26 | } 27 | 28 | impl> Kita for T { 29 | const NAME: &'static str = "Blanket A"; 30 | } 31 | impl Kita<*mut Self> for [R; N] 32 | where 33 | Self: Dispatch, 34 | { 35 | const NAME: &'static str = "Blanket A"; 36 | } 37 | impl Kita for R 38 | where 39 | Self: Dispatch, 40 | { 41 | const NAME: &'static str = "Blanket B"; 42 | } 43 | } 44 | 45 | /* 46 | pub trait Kita: Dispatch { 47 | const NAME: &'static str; 48 | } 49 | 50 | const _: () = { 51 | pub trait Kita0<_TŠČ1: ?Sized, U>: Dispatch { 52 | const NAME: &'static str; 53 | } 54 | impl> Kita0 for T { 55 | const NAME: &'static str = "Blanket A"; 56 | } 57 | impl Kita0 for [R; N] 58 | where 59 | [R; N]: Dispatch, 60 | { 61 | const NAME: &'static str = "Blanket A"; 62 | } 63 | impl Kita0 for R 64 | where 65 | R: Dispatch, 66 | { 67 | const NAME: &'static str = "Blanket B"; 68 | } 69 | 70 | impl<_TŠČ0, _TŠČ1> Kita<_TŠČ0> for _TŠČ1 71 | where 72 | Self: Dispatch, 73 | _TŠČ1: Dispatch, 74 | Self: Kita0<<_TŠČ1 as Dispatch>::Group, _TŠČ0>, 75 | { 76 | const NAME: &'static str = ::Group, 78 | _TŠČ0, 79 | >>::NAME; 80 | } 81 | }; 82 | */ 83 | 84 | #[test] 85 | fn shared_helper() { 86 | assert_eq!("Blanket A", String::NAME); 87 | assert_eq!("Blanket B", >::NAME); 88 | 89 | assert_eq!("Blanket A", <[u32; 0] as Kita<*mut [u32; 0]>>::NAME); 90 | assert_eq!("Blanket B", <[i32; 1] as Kita<*mut [i32; 1]>>::NAME); 91 | } 92 | -------------------------------------------------------------------------------- /tests/basic.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita { 25 | const NAME: &'static str; 26 | 27 | fn name() -> &'static str { 28 | "Default blanket" 29 | } 30 | } 31 | 32 | impl> Kita for T { 33 | const NAME: &'static str = "Blanket A"; 34 | } 35 | impl> Kita for U { 36 | const NAME: &'static str = "Blanket B"; 37 | 38 | fn name() -> &'static str { 39 | "Blanket B" 40 | } 41 | } 42 | } 43 | 44 | /* 45 | pub trait Kita { 46 | const NAME: &'static str; 47 | 48 | fn name() -> &'static str { 49 | "Default blanket" 50 | } 51 | } 52 | 53 | const _: () = { 54 | pub trait Kita0<_TŠČ0: ?Sized> { 55 | const NAME: &'static str; 56 | 57 | fn name() -> &'static str { 58 | "Default blanket" 59 | } 60 | } 61 | impl> Kita0 for T { 62 | const NAME: &'static str = "Blanket A"; 63 | } 64 | impl> Kita0 for U { 65 | const NAME: &'static str = "Blanket B"; 66 | 67 | fn name() -> &'static str { 68 | "Blanket B" 69 | } 70 | } 71 | 72 | impl<_TŠČ0> Kita for _TŠČ0 73 | where 74 | Self: Kita0<<_TŠČ0 as Dispatch>::Group>, 75 | _TŠČ0: Dispatch, 76 | { 77 | const NAME: &'static str = ::Group>>::NAME; 78 | 79 | fn name() -> &'static str { 80 | ::Group>>::name() 81 | } 82 | } 83 | }; 84 | */ 85 | 86 | #[test] 87 | fn basic() { 88 | assert_eq!("Blanket A", String::NAME); 89 | assert_eq!("Blanket A", Vec::::NAME); 90 | assert_eq!("Blanket B", u32::NAME); 91 | assert_eq!("Blanket B", i32::NAME); 92 | 93 | assert_eq!("Default blanket", String::name()); 94 | assert_eq!("Default blanket", Vec::::name()); 95 | assert_eq!("Blanket B", u32::name()); 96 | assert_eq!("Blanket B", i32::name()); 97 | } 98 | -------------------------------------------------------------------------------- /tests/dispatch_on_undefined_assoc_binding.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch1 { 4 | type Group; 5 | } 6 | pub trait Dispatch2 { 7 | type Group; 8 | } 9 | 10 | pub enum GroupA {} 11 | pub enum GroupB {} 12 | 13 | impl Dispatch1 for String { 14 | type Group = GroupA; 15 | } 16 | impl Dispatch2 for String { 17 | type Group = GroupA; 18 | } 19 | impl Dispatch1 for Vec { 20 | type Group = GroupA; 21 | } 22 | impl Dispatch2 for Vec { 23 | type Group = GroupB; 24 | } 25 | 26 | impl Dispatch1 for i32 { 27 | type Group = GroupB; 28 | } 29 | impl Dispatch2 for i32 { 30 | type Group = GroupB; 31 | } 32 | impl Dispatch1 for u32 { 33 | type Group = GroupB; 34 | } 35 | impl Dispatch2 for u32 { 36 | type Group = GroupB; 37 | } 38 | 39 | impl core::fmt::Display for GroupB { 40 | fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result { 41 | unimplemented!() 42 | } 43 | } 44 | 45 | disjoint_impls! { 46 | pub trait Kita { 47 | const NAME: &str; 48 | } 49 | 50 | impl + Dispatch2> Kita for T { 51 | const NAME: &str = "Blanket A"; 52 | } 53 | impl + Dispatch2> Kita for T { 54 | const NAME: &'static str = "Blanket B"; 55 | } 56 | } 57 | 58 | /* 59 | pub trait Kita { 60 | const NAME: &str; 61 | } 62 | 63 | const _: () = { 64 | pub trait Kita0<_TŠČ0: ?Sized, _TŠČ1: ?Sized> { 65 | const NAME: &str; 66 | } 67 | impl + Dispatch2> Kita0 68 | for T { 69 | const NAME: &str = "Blanket A"; 70 | } 71 | impl< 72 | T: Dispatch1 + Dispatch2, 73 | > Kita0<::Group, GroupB> for T { 74 | const NAME: &'static str = "Blanket B"; 75 | } 76 | 77 | impl<_TŠČ0> Kita for _TŠČ0 78 | where 79 | _TŠČ0: Dispatch2, 80 | _TŠČ0: Dispatch1, 81 | Self: Kita0<<_TŠČ0 as Dispatch2>::Group, <_TŠČ0 as Dispatch1>::Group>, 82 | { 83 | const NAME: &str = ::Group, 85 | <_TŠČ0 as Dispatch1>::Group, 86 | >>::NAME; 87 | } 88 | }; 89 | */ 90 | 91 | #[test] 92 | fn dispatch_on_undefined_assoc_binding() { 93 | assert_eq!("Blanket A", String::NAME); 94 | assert_eq!("Blanket B", u32::NAME); 95 | assert_eq!("Blanket B", i32::NAME); 96 | } 97 | -------------------------------------------------------------------------------- /tests/overlapping_idents.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait U 25 | where 26 | U: From, 27 | { 28 | type U: From; 29 | const U: &'static str; 30 | } 31 | 32 | impl> U for T 33 | where 34 | K: From, 35 | { 36 | type U = K; 37 | const U: &'static str = "Blanket A"; 38 | } 39 | impl> U for T 40 | where 41 | K: From, 42 | { 43 | type U = K; 44 | const U: &'static str = "Blanket B"; 45 | } 46 | } 47 | 48 | /* 49 | pub trait U 50 | where 51 | U: From, 52 | { 53 | type U: From; 54 | const U: &'static str; 55 | } 56 | 57 | const _: () = { 58 | pub trait U0<_TŠČ1: ?Sized, U> 59 | where 60 | U: From, 61 | { 62 | type U: From; 63 | const U: &'static str; 64 | } 65 | impl> U0 for T 66 | where 67 | K: From, 68 | { 69 | type U = K; 70 | const U: &'static str = "Blanket A"; 71 | } 72 | impl> U0 for T 73 | where 74 | K: From, 75 | { 76 | type U = K; 77 | const U: &'static str = "Blanket B"; 78 | } 79 | 80 | impl<_TŠČ0, _TŠČ1> U<_TŠČ0> for _TŠČ1 81 | where 82 | _TŠČ0: From, 83 | _TŠČ0: From, 84 | _TŠČ1: Dispatch, 85 | Self: U0<<_TŠČ1 as Dispatch>::Group, _TŠČ0>, 86 | { 87 | type U = ::Group, _TŠČ0>>::U; 88 | const U: &'static str = ::Group, _TŠČ0>>::U; 89 | } 90 | }; 91 | */ 92 | 93 | #[test] 94 | fn overlapping_idents() { 95 | assert_eq!("Blanket A", >::U); 96 | assert_eq!("Blanket A", as U>::U); 97 | assert_eq!("Blanket B", >::U); 98 | assert_eq!("Blanket B", >::U); 99 | } 100 | -------------------------------------------------------------------------------- /tests/extra_parameter.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita: Dispatch 25 | where 26 | U: From + From, 27 | { 28 | const NAME: &'static str; 29 | } 30 | 31 | impl> Kita for T 32 | where 33 | U: From + From, 34 | { 35 | const NAME: &'static str = "Blanket A"; 36 | } 37 | impl> Kita for T 38 | where 39 | U: From + From, 40 | { 41 | const NAME: &'static str = "Blanket B"; 42 | } 43 | } 44 | 45 | /* 46 | pub trait Kita: Dispatch 47 | where 48 | U: From + From, 49 | { 50 | const NAME: &'static str; 51 | } 52 | 53 | const _: () = { 54 | pub trait Kita0<_TŠČ1: ?Sized, U>: Dispatch 55 | where 56 | U: From + From, 57 | { 58 | const NAME: &'static str; 59 | } 60 | impl> Kita0 for T 61 | where 62 | U: From + From, 63 | { 64 | const NAME: &'static str = "Blanket A"; 65 | } 66 | impl> Kita0 for T 67 | where 68 | U: From + From, 69 | { 70 | const NAME: &'static str = "Blanket B"; 71 | } 72 | 73 | // TODO: Some of the bounds are repeated. Remove duplication 74 | 75 | impl<_TŠČ0, _TŠČ1> Kita<_TŠČ0> for _TŠČ1 76 | where 77 | _TŠČ0: From + From, 78 | Self: Dispatch, 79 | _TŠČ0: From, 80 | _TŠČ0: From, 81 | _TŠČ1: Dispatch, 82 | Self: Kita0<<_TŠČ1 as Dispatch>::Group, _TŠČ0>, 83 | { 84 | const NAME: &'static str = ::Group, 86 | _TŠČ0, 87 | >>::NAME; 88 | } 89 | }; 90 | */ 91 | 92 | #[test] 93 | fn extra_parameter() { 94 | assert_eq!("Blanket A", >::NAME); 95 | assert_eq!("Blanket A", as Kita>::NAME); 96 | assert_eq!("Blanket B", >::NAME); 97 | assert_eq!("Blanket B", >::NAME); 98 | } 99 | -------------------------------------------------------------------------------- /tests/trait_with_lifetime.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita<'a, 'b: 'a, U: 'b> 25 | where 26 | U: 'a, 27 | { 28 | fn get_name(&'b self) -> &'a str; 29 | } 30 | 31 | impl<'a, 'x: 'a, T: Dispatch> Kita<'a, 'x, u32> for T { 32 | fn get_name(&'x self) -> &'a str { 33 | "Blanket A" 34 | } 35 | } 36 | impl<'a, 'b: 'a, T: Dispatch> Kita<'a, 'b, u32> for T { 37 | fn get_name(&'b self) -> &'a str { 38 | "Blanket B" 39 | } 40 | } 41 | } 42 | 43 | /* 44 | pub trait Kita<'a, 'b: 'a, U: 'b> 45 | where 46 | U: 'a, 47 | { 48 | fn get_name(&'b self) -> &'a str; 49 | } 50 | 51 | const _: () = { 52 | pub trait Kita0<'a, 'b: 'a, _TŠČ3: ?Sized, U: 'b> 53 | where 54 | U: 'a, 55 | { 56 | fn get_name(&'b self) -> &'a str; 57 | } 58 | impl<'a, 'x: 'a, T: Dispatch> Kita0<'a, 'x, GroupA, u32> for T { 59 | fn get_name(&'x self) -> &'a str { 60 | "Blanket A" 61 | } 62 | } 63 | impl<'a, 'b: 'a, T: Dispatch> Kita0<'a, 'b, GroupB, u32> for T { 64 | fn get_name(&'b self) -> &'a str { 65 | "Blanket B" 66 | } 67 | } 68 | 69 | impl<'_lšč0, '_lšč1, _TŠČ0> Kita<'_lšč0, '_lšč1, u32> for _TŠČ0 70 | where 71 | u32: '_lšč0, 72 | '_lšč0:, 73 | '_lšč1: '_lšč0, 74 | u32: '_lšč1, 75 | _TŠČ0: Dispatch, 76 | Self: Kita0<'_lšč0, '_lšč1, <_TŠČ0 as Dispatch>::Group, u32>, 77 | { 78 | fn get_name(&'_lšč1 self) -> &'_lšč0 str { 79 | ::Group, 83 | u32, 84 | >>::get_name(self) 85 | } 86 | } 87 | }; 88 | */ 89 | 90 | #[test] 91 | fn trait_with_lifetime() { 92 | assert_eq!("Blanket A", >::get_name(&"".into())); 93 | assert_eq!("Blanket A", as Kita>::get_name(&vec![])); 94 | assert_eq!("Blanket B", >::get_name(&0)); 95 | assert_eq!("Blanket B", >::get_name(&0)); 96 | } 97 | -------------------------------------------------------------------------------- /tests/multiple_dispatch_traits.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch1 { 4 | type Group; 5 | } 6 | pub trait Dispatch2 { 7 | type Group; 8 | } 9 | 10 | pub enum GroupA {} 11 | pub enum GroupB {} 12 | 13 | impl Dispatch1 for String { 14 | type Group = GroupA; 15 | } 16 | impl Dispatch2 for String { 17 | type Group = GroupA; 18 | } 19 | impl Dispatch1 for Vec { 20 | type Group = GroupA; 21 | } 22 | impl Dispatch2 for Vec { 23 | type Group = GroupB; 24 | } 25 | 26 | impl Dispatch1 for i32 { 27 | type Group = GroupB; 28 | } 29 | impl Dispatch2 for i32 { 30 | type Group = GroupA; 31 | } 32 | impl Dispatch1 for u32 { 33 | type Group = GroupB; 34 | } 35 | impl Dispatch2 for u32 { 36 | type Group = GroupB; 37 | } 38 | 39 | disjoint_impls! { 40 | pub trait Kita { 41 | const NAME: &'static str; 42 | } 43 | 44 | impl + Dispatch2> Kita for T { 45 | const NAME: &'static str = "Blanket AA"; 46 | } 47 | impl + Dispatch2> Kita for T { 48 | const NAME: &'static str = "Blanket AB"; 49 | } 50 | impl + Dispatch2> Kita for T { 51 | const NAME: &'static str = "Blanket B*"; 52 | } 53 | } 54 | 55 | /* 56 | pub trait Kita { 57 | const NAME: &'static str; 58 | } 59 | 60 | const _: () = { 61 | pub trait Kita0<_TŠČ0: ?Sized, _TŠČ1: ?Sized> { 62 | const NAME: &'static str; 63 | } 64 | impl + Dispatch2> Kita0 65 | for T { 66 | const NAME: &'static str = "Blanket AA"; 67 | } 68 | impl + Dispatch2> Kita0 69 | for T { 70 | const NAME: &'static str = "Blanket AB"; 71 | } 72 | impl + Dispatch2> Kita0::Group> 73 | for T { 74 | const NAME: &'static str = "Blanket B*"; 75 | } 76 | 77 | impl<_TŠČ0> Kita for _TŠČ0 78 | where 79 | _TŠČ0: Dispatch1, 80 | _TŠČ0: Dispatch2, 81 | Self: Kita0<<_TŠČ0 as Dispatch1>::Group, <_TŠČ0 as Dispatch2>::Group>, 82 | { 83 | const NAME: &'static str = ::Group, 85 | <_TŠČ0 as Dispatch2>::Group, 86 | >>::NAME; 87 | } 88 | }; 89 | */ 90 | 91 | #[test] 92 | fn multiple_dispatch_traits() { 93 | assert_eq!("Blanket AA", String::NAME); 94 | assert_eq!("Blanket AB", Vec::::NAME); 95 | assert_eq!("Blanket B*", u32::NAME); 96 | assert_eq!("Blanket B*", i32::NAME); 97 | } 98 | -------------------------------------------------------------------------------- /tests/dispatch_with_same_param.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch<'a, T> { 4 | type Group; 5 | } 6 | 7 | trait Tr<'a> {} 8 | impl Tr<'_> for String {} 9 | impl Tr<'_> for Vec {} 10 | 11 | pub enum GroupA {} 12 | impl Dispatch<'_, ()> for String { 13 | type Group = GroupA; 14 | } 15 | impl Dispatch<'_, ()> for Vec { 16 | type Group = GroupA; 17 | } 18 | 19 | pub enum GroupB {} 20 | impl Dispatch<'_, ()> for i32 { 21 | type Group = GroupB; 22 | } 23 | impl Dispatch<'_, ()> for u32 { 24 | type Group = GroupB; 25 | } 26 | 27 | pub enum GroupC {} 28 | impl Dispatch<'_, ()> for Option { 29 | type Group = GroupC; 30 | } 31 | impl Dispatch<'_, ()> for (i32, u32) { 32 | type Group = GroupC; 33 | } 34 | 35 | disjoint_impls! { 36 | pub trait Kita { 37 | const NAME: &'static str; 38 | } 39 | 40 | impl<'a, T: Dispatch<'a, (), Group = GroupC>> Kita for &T { 41 | const NAME: &'static str = "Blanket C"; 42 | } 43 | impl<'a, T: Dispatch<'a, (), Group = GroupB>> Kita for &T { 44 | const NAME: &'static str = "Blanket B"; 45 | } 46 | impl<'b, 'k, T: Dispatch<'b, (), Group = GroupA>> Kita for &T 47 | where 48 | T: Tr<'k>, 49 | { 50 | const NAME: &'static str = "Blanket A"; 51 | } 52 | } 53 | 54 | /* 55 | pub trait Kita { 56 | const NAME: &'static str; 57 | } 58 | 59 | const _: () = { 60 | pub trait Kita0<_TŠČ0: ?Sized> { 61 | const NAME: &'static str; 62 | } 63 | impl<'a, '_lšč0, T: Dispatch<'a, (), Group = GroupC>> Kita0 64 | for &'_lšč0 T { 65 | const NAME: &'static str = "Blanket C"; 66 | } 67 | impl<'a, '_lšč0, T: Dispatch<'a, (), Group = GroupB>> Kita0 68 | for &'_lšč0 T { 69 | const NAME: &'static str = "Blanket B"; 70 | } 71 | impl<'b, 'k, '_lšč0, T: Dispatch<'b, (), Group = GroupA>> Kita0 72 | for &'_lšč0 T 73 | where 74 | T: Tr<'k>, 75 | { 76 | const NAME: &'static str = "Blanket A"; 77 | } 78 | 79 | impl<'_lšč0, '_lšč1, _TŠČ0: '_lšč0> Kita for &'_lšč0 _TŠČ0 80 | where 81 | _TŠČ0: Dispatch<'_lšč1, ()>, 82 | Self: Kita0<<_TŠČ0 as Dispatch<'_lšč1, ()>>::Group>, 83 | { 84 | const NAME: &'static str = >::Group, 86 | >>::NAME; 87 | } 88 | }; 89 | */ 90 | 91 | #[test] 92 | fn dispatch_with_same_param() { 93 | assert_eq!("Blanket A", <&String>::NAME); 94 | assert_eq!("Blanket A", <&Vec::>::NAME); 95 | assert_eq!("Blanket B", <&u32>::NAME); 96 | assert_eq!("Blanket B", <&i32>::NAME); 97 | assert_eq!("Blanket C", <&Option::>::NAME); 98 | assert_eq!("Blanket C", <&(i32, u32)>::NAME); 99 | } 100 | -------------------------------------------------------------------------------- /tests/generalized_signature.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | trait Dispatch { 4 | type Group; 5 | } 6 | 7 | impl Dispatch for String { 8 | type Group = bool; 9 | } 10 | impl Dispatch for u32 { 11 | type Group = u8; 12 | } 13 | 14 | disjoint_impls! { 15 | trait Kita { 16 | const NAME: &'static str; 17 | } 18 | 19 | impl Kita for B 20 | where 21 | B: Dispatch, 22 | U: Dispatch, 23 | { 24 | const NAME: &'static str = "Blanket A"; 25 | } 26 | impl Kita for U 27 | where 28 | B: Dispatch, 29 | U: Dispatch, 30 | { 31 | const NAME: &'static str = "Blanket B"; 32 | } 33 | impl Kita for B 34 | where 35 | B: Dispatch, 36 | U: Dispatch, 37 | { 38 | const NAME: &'static str = "Blanket C"; 39 | } 40 | } 41 | 42 | /* 43 | trait Kita { 44 | const NAME: &'static str; 45 | } 46 | 47 | const _: () = { 48 | pub trait Kita0<_TŠČ2: ?Sized, _TŠČ3: ?Sized, _TŠČ4: ?Sized, T, U> { 49 | const NAME: &'static str; 50 | } 51 | impl Kita0 for B 52 | where 53 | B: Dispatch, 54 | U: Dispatch, 55 | { 56 | const NAME: &'static str = "Blanket A"; 57 | } 58 | impl Kita0 for U 59 | where 60 | B: Dispatch, 61 | U: Dispatch, 62 | { 63 | const NAME: &'static str = "Blanket B"; 64 | } 65 | impl Kita0 for B 66 | where 67 | B: Dispatch, 68 | U: Dispatch, 69 | { 70 | const NAME: &'static str = "Blanket C"; 71 | } 72 | 73 | impl<_TŠČ0, _TŠČ1, _TŠČ2> Kita<_TŠČ0, _TŠČ1> for _TŠČ2 74 | where 75 | _TŠČ2: Dispatch, 76 | _TŠČ0: Dispatch, 77 | _TŠČ1: Dispatch, 78 | Self: Kita0< 79 | <_TŠČ2 as Dispatch>::Group, 80 | <_TŠČ0 as Dispatch>::Group, 81 | <_TŠČ1 as Dispatch>::Group, 82 | _TŠČ0, 83 | _TŠČ1, 84 | >, 85 | { 86 | const NAME: &'static str = ::Group, 88 | <_TŠČ0 as Dispatch>::Group, 89 | <_TŠČ1 as Dispatch>::Group, 90 | _TŠČ0, 91 | _TŠČ1, 92 | >>::NAME; 93 | } 94 | }; 95 | */ 96 | 97 | #[test] 98 | fn generalized_signature() { 99 | assert_eq!(>::NAME, "Blanket A"); 100 | assert_eq!(>::NAME, "Blanket B"); 101 | assert_eq!(>::NAME, "Blanket C"); 102 | } 103 | -------------------------------------------------------------------------------- /tests/unsafety.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | /// # Safety 25 | /// 26 | /// This trait is unsafe 27 | pub unsafe trait Kita: Dispatch { 28 | /// # Safety 29 | /// 30 | /// This function is unsafe 31 | unsafe fn kita() -> &'static str { 32 | "Default blanket" 33 | } 34 | } 35 | 36 | unsafe impl> Kita for T { 37 | unsafe fn kita() -> &'static str { 38 | "Blanket A" 39 | } 40 | } 41 | unsafe impl> Kita for T { 42 | unsafe fn kita() -> &'static str { 43 | "Blanket B" 44 | } 45 | } 46 | } 47 | 48 | /* 49 | /// # Safety 50 | /// 51 | /// This trait is unsafe 52 | pub unsafe trait Kita: Dispatch { 53 | /// # Safety 54 | /// 55 | /// This function is unsafe 56 | unsafe fn kita() -> &'static str { 57 | "Default blanket" 58 | } 59 | } 60 | 61 | const _: () = { 62 | /// # Safety 63 | /// 64 | /// This trait is unsafe 65 | pub unsafe trait Kita0<_TŠČ1: ?Sized, U>: Dispatch { 66 | /// # Safety 67 | /// 68 | /// This function is unsafe 69 | unsafe fn kita() -> &'static str { 70 | "Default blanket" 71 | } 72 | } 73 | unsafe impl> Kita0 for T { 74 | unsafe fn kita() -> &'static str { 75 | "Blanket A" 76 | } 77 | } 78 | unsafe impl> Kita0 for T { 79 | unsafe fn kita() -> &'static str { 80 | "Blanket B" 81 | } 82 | } 83 | 84 | unsafe impl<_TŠČ0, _TŠČ1> Kita<_TŠČ0> for _TŠČ1 85 | where 86 | Self: Dispatch, 87 | _TŠČ1: Dispatch, 88 | Self: Kita0<<_TŠČ1 as Dispatch>::Group, _TŠČ0>, 89 | { 90 | unsafe fn kita() -> &'static str { 91 | unsafe { ::Group, _TŠČ0>>::kita() } 92 | } 93 | } 94 | }; 95 | */ 96 | 97 | #[test] 98 | fn unsafety() { 99 | unsafe { 100 | assert_eq!("Blanket A", >::kita()); 101 | assert_eq!("Blanket A", as Kita>::kita()); 102 | assert_eq!("Blanket B", >::kita()); 103 | assert_eq!("Blanket B", >::kita()); 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /tests/supersets_2.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group: ?Sized; 5 | } 6 | 7 | pub enum GroupA {} 8 | pub enum GroupB {} 9 | pub enum GroupC {} 10 | pub enum GroupD {} 11 | impl Dispatch for (String, u32) { 12 | type Group = GroupA; 13 | } 14 | impl Dispatch for (Vec, u32) { 15 | type Group = GroupB; 16 | } 17 | impl Dispatch for (String, Vec) { 18 | type Group = GroupC; 19 | } 20 | impl Dispatch for (Vec, Vec) { 21 | type Group = GroupD; 22 | } 23 | 24 | disjoint_impls! { 25 | pub trait Kita { 26 | const NAME: &'static str; 27 | } 28 | 29 | impl Kita for (T, U) 30 | where 31 | (T, U): Dispatch, 32 | { 33 | const NAME: &'static str = "Blanket A"; 34 | } 35 | impl Kita for (Vec, U) 36 | where 37 | (Vec, U): Dispatch, 38 | { 39 | const NAME: &'static str = "Blanket B"; 40 | } 41 | impl Kita for (T, Vec) 42 | where 43 | (T, Vec): Dispatch, 44 | { 45 | const NAME: &'static str = "Blanket C"; 46 | } 47 | impl Kita for (Vec, Vec) 48 | where 49 | (Vec, Vec): Dispatch, 50 | { 51 | const NAME: &'static str = "Blanket D"; 52 | } 53 | } 54 | 55 | /* 56 | pub trait Kita { 57 | const NAME: &'static str; 58 | } 59 | 60 | const _: () = { 61 | pub trait Kita0<_TŠČ0: ?Sized> { 62 | const NAME: &'static str; 63 | } 64 | impl Kita0 for (T, U) 65 | where 66 | (T, U): Dispatch, 67 | { 68 | const NAME: &'static str = "Blanket A"; 69 | } 70 | impl Kita0 for (Vec, U) 71 | where 72 | (Vec, U): Dispatch, 73 | { 74 | const NAME: &'static str = "Blanket B"; 75 | } 76 | impl Kita0 for (T, Vec) 77 | where 78 | (T, Vec): Dispatch, 79 | { 80 | const NAME: &'static str = "Blanket C"; 81 | } 82 | impl Kita0 for (Vec, Vec) 83 | where 84 | (Vec, Vec): Dispatch, 85 | { 86 | const NAME: &'static str = "Blanket D"; 87 | } 88 | 89 | impl<_TŠČ0, _TŠČ1> Kita for (_TŠČ0, _TŠČ1) 90 | where 91 | (_TŠČ0, _TŠČ1): Dispatch, 92 | Self: Kita0<<(_TŠČ0, _TŠČ1) as Dispatch>::Group>, 93 | { 94 | const NAME: &'static str = ::Group, 96 | >>::NAME; 97 | } 98 | }; 99 | */ 100 | 101 | #[test] 102 | fn supersets_2() { 103 | assert_eq!("Blanket A", <(String, u32)>::NAME); 104 | assert_eq!("Blanket B", <(Vec, u32)>::NAME); 105 | assert_eq!("Blanket C", <(String, Vec)>::NAME); 106 | assert_eq!("Blanket D", <(Vec, Vec)>::NAME); 107 | } 108 | -------------------------------------------------------------------------------- /tests/unsized_type.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group: ?Sized; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub struct GroupB; 16 | impl Dispatch for str { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for [u8] { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita { 25 | fn kita(&self) -> String; 26 | } 27 | 28 | impl, U: ?Sized, V> Kita for T { 29 | fn kita(&self) -> String { 30 | "Blanket A".to_owned() 31 | } 32 | } 33 | 34 | impl + ?Sized, U, V> Kita for T { 35 | fn kita(&self) -> String { 36 | "Blanket B".to_owned() 37 | } 38 | } 39 | 40 | impl + ?Sized, U> Kita for T { 41 | fn kita(&self) -> String { 42 | "Blanket for str".to_owned() 43 | } 44 | } 45 | } 46 | 47 | /* 48 | pub trait Kita { 49 | fn kita(&self) -> String; 50 | } 51 | 52 | const _: () = { 53 | pub trait Kita0<_TŠČ2: ?Sized, T: ?Sized, U: ?Sized> { 54 | fn kita(&self) -> String; 55 | } 56 | impl, U: ?Sized, V> Kita0 for T { 57 | fn kita(&self) -> String { 58 | "Blanket A".to_owned() 59 | } 60 | } 61 | impl + ?Sized, U, V> Kita0 for T { 62 | fn kita(&self) -> String { 63 | "Blanket B".to_owned() 64 | } 65 | } 66 | 67 | // TODO: There are mpty bounds again here 68 | 69 | impl<_TŠČ0: ?Sized, _TŠČ1, _TŠČ2: ?Sized> Kita<_TŠČ0, _TŠČ1> for _TŠČ2 70 | where 71 | _TŠČ0:, 72 | _TŠČ1:, 73 | _TŠČ2: Dispatch, 74 | Self: Kita0<<_TŠČ2 as Dispatch>::Group, _TŠČ0, _TŠČ1>, 75 | { 76 | fn kita(&self) -> String { 77 | ::Group, _TŠČ0, _TŠČ1>>::kita(self) 78 | } 79 | } 80 | 81 | impl + ?Sized, U> Kita for T { 82 | fn kita(&self) -> String { 83 | "Blanket for str".to_owned() 84 | } 85 | } 86 | }; 87 | */ 88 | 89 | #[test] 90 | fn unsized_type() { 91 | assert_eq!( 92 | "Blanket A", 93 | >::kita(&String::new()) 94 | ); 95 | assert_eq!("Blanket A", as Kita>::kita(&Vec::new())); 96 | assert_eq!("Blanket B", >::kita("")); 97 | assert_eq!("Blanket B", <[u8] as Kita>::kita(&[])); 98 | 99 | assert_eq!("Blanket for str", >::kita("")); 100 | assert_eq!("Blanket for str", <[u8] as Kita>::kita(&[])); 101 | } 102 | -------------------------------------------------------------------------------- /tests/elided_lifetime.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl<'a> Dispatch for &'a String { 9 | type Group = &'a GroupA; 10 | } 11 | impl<'a, T> Dispatch for &'a Vec { 12 | type Group = &'a GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl<'a> Dispatch for &'a i32 { 17 | type Group = &'a GroupB; 18 | } 19 | impl<'a> Dispatch for &'a u32 { 20 | type Group = &'a GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita<'a, 'b, U> { 25 | fn get_name(&self) -> &str; 26 | } 27 | 28 | impl Kita<'_, '_, U> for &T 29 | where 30 | Self: Dispatch, 31 | { 32 | fn get_name(&self) -> &str { 33 | "Blanket A" 34 | } 35 | } 36 | impl<'a, 'b, 'c, T, U> Kita<'a, 'b, U> for &'c T 37 | where 38 | Self: Dispatch, 39 | { 40 | fn get_name(&self) -> &str { 41 | "Blanket B" 42 | } 43 | } 44 | } 45 | 46 | /* 47 | pub trait Kita<'a, 'b, U> { 48 | fn get_name(&self) -> &str; 49 | } 50 | 51 | const _: () = { 52 | pub trait Kita0<'a, 'b, _TŠČ3: ?Sized, U> { 53 | fn get_name(&self) -> &str; 54 | } 55 | impl< 56 | '_lšč0, 57 | '_lšč1, 58 | '_lšč2, 59 | '_lšč3, 60 | T, 61 | U, 62 | > Kita0<'_lšč0, '_lšč1, &'_lšč3 GroupA, U> for &'_lšč2 T 63 | where 64 | &'_lšč2 T: Dispatch, 65 | { 66 | fn get_name(&self) -> &str { 67 | "Blanket A" 68 | } 69 | } 70 | impl<'a, 'b, 'c, '_lšč0, T, U> Kita0<'a, 'b, &'_lšč0 GroupB, U> for &'c T 71 | where 72 | &'c T: Dispatch, 73 | { 74 | fn get_name(&self) -> &str { 75 | "Blanket B" 76 | } 77 | } 78 | 79 | // TODO: lifetime bounds are empty. Remove them 80 | 81 | impl< 82 | '_lšč0, 83 | '_lšč1, 84 | '_lšč2, 85 | '_lšč3, 86 | _TŠČ0, 87 | _TŠČ1: '_lšč2, 88 | > Kita<'_lšč0, '_lšč1, _TŠČ0> for &'_lšč2 _TŠČ1 89 | where 90 | '_lšč0:, 91 | '_lšč1:, 92 | &'_lšč2 _TŠČ1: Dispatch, 93 | Self: Kita0<'_lšč0, '_lšč1, <&'_lšč2 _TŠČ1 as Dispatch>::Group, _TŠČ0>, 94 | { 95 | fn get_name(&self) -> &str { 96 | ::Group, 100 | _TŠČ0, 101 | >>::get_name(self) 102 | } 103 | } 104 | }; 105 | */ 106 | 107 | #[test] 108 | fn elided_lifetime() { 109 | assert_eq!("Blanket A", <&String as Kita>::get_name(&&"".into())); 110 | assert_eq!("Blanket A", <&Vec:: as Kita>::get_name(&&vec![])); 111 | assert_eq!("Blanket B", <&u32 as Kita>::get_name(&&0)); 112 | assert_eq!("Blanket B", <&i32 as Kita>::get_name(&&0)); 113 | } 114 | -------------------------------------------------------------------------------- /tests/trait_object.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | pub trait Kara {} 24 | impl Dispatch for dyn Kara { 25 | type Group = GroupA; 26 | } 27 | 28 | disjoint_impls! { 29 | pub trait Kita { 30 | const NAME: &'static str; 31 | } 32 | 33 | impl> Kita for dyn Kara + Sync { 34 | const NAME: &'static str = "Blanket A"; 35 | } 36 | impl> Kita for dyn Kara + Sync { 37 | const NAME: &'static str = "Blanket B"; 38 | } 39 | impl> Kita for dyn Kara { 40 | const NAME: &'static str = "Blanket C"; 41 | } 42 | impl> Kita for dyn Kara { 43 | const NAME: &'static str = "Blanket D"; 44 | } 45 | } 46 | 47 | /* 48 | pub trait Kita { 49 | const NAME: &'static str; 50 | } 51 | 52 | const _: () = { 53 | pub trait Kita0<_TŠČ1: ?Sized, T> { 54 | const NAME: &'static str; 55 | } 56 | impl> Kita0 for dyn Kara + Sync { 57 | const NAME: &'static str = "Blanket A"; 58 | } 59 | impl> Kita0 for dyn Kara + Sync { 60 | const NAME: &'static str = "Blanket B"; 61 | } 62 | 63 | pub trait Kita1<_TŠČ1: ?Sized, T> { 64 | const NAME: &'static str; 65 | } 66 | impl> Kita1 for dyn Kara { 67 | const NAME: &'static str = "Blanket C"; 68 | } 69 | impl> Kita1 for dyn Kara { 70 | const NAME: &'static str = "Blanket D"; 71 | } 72 | 73 | impl<_TŠČ0> Kita<_TŠČ0> for dyn Kara + Sync 74 | where 75 | _TŠČ0: Dispatch, 76 | Self: Kita0<<_TŠČ0 as Dispatch>::Group, _TŠČ0>, 77 | { 78 | const NAME: &'static str = ::Group, 80 | _TŠČ0, 81 | >>::NAME; 82 | } 83 | impl<_TŠČ0> Kita<_TŠČ0> for dyn Kara 84 | where 85 | _TŠČ0: Dispatch, 86 | Self: Kita1<<_TŠČ0 as Dispatch>::Group, _TŠČ0>, 87 | { 88 | const NAME: &'static str = ::Group, 90 | _TŠČ0, 91 | >>::NAME; 92 | } 93 | }; 94 | */ 95 | 96 | fn main() { 97 | assert_eq!(>::NAME, "Blanket A"); 98 | assert_eq!(>::NAME, "Blanket B"); 99 | assert_eq!(>::NAME, "Blanket C"); 100 | assert_eq!(>::NAME, "Blanket D"); 101 | } 102 | -------------------------------------------------------------------------------- /tests/derivative_self_ty.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | pub enum GroupB {} 9 | 10 | impl Dispatch for String { 11 | type Group = GroupA; 12 | } 13 | impl Dispatch for Option { 14 | type Group = GroupA; 15 | } 16 | 17 | impl Dispatch for Vec { 18 | type Group = GroupB; 19 | } 20 | impl Dispatch for Option> { 21 | type Group = GroupA; 22 | } 23 | 24 | impl Dispatch for i32 { 25 | type Group = GroupA; 26 | } 27 | impl Dispatch for Option { 28 | type Group = GroupB; 29 | } 30 | 31 | impl Dispatch for u32 { 32 | type Group = GroupB; 33 | } 34 | impl Dispatch for Option { 35 | type Group = GroupB; 36 | } 37 | 38 | disjoint_impls! { 39 | pub trait Kita { 40 | const NAME: &'static str; 41 | } 42 | 43 | impl> Kita for Option 44 | where 45 | Self: Dispatch, 46 | { 47 | const NAME: &str = "Blanket AA"; 48 | } 49 | impl> Kita for Option 50 | where 51 | Option: Dispatch, 52 | { 53 | const NAME: &'static str = "Blanket BA"; 54 | } 55 | impl Kita for Option 56 | where 57 | Option: Dispatch, 58 | { 59 | const NAME: &'static str = "Blanket *B"; 60 | } 61 | } 62 | 63 | /* 64 | pub trait Kita { 65 | const NAME: &'static str; 66 | } 67 | 68 | const _: () = { 69 | pub trait Kita0<_TŠČ0: ?Sized, _TŠČ1: ?Sized> { 70 | const NAME: &'static str; 71 | } 72 | impl> Kita0 for Option 73 | where 74 | Option: Dispatch, 75 | { 76 | const NAME: &str = "Blanket AA"; 77 | } 78 | impl> Kita0 for Option 79 | where 80 | Option: Dispatch, 81 | { 82 | const NAME: &'static str = "Blanket BA"; 83 | } 84 | impl Kita0<::Group, GroupB> for Option 85 | where 86 | Option: Dispatch, 87 | { 88 | const NAME: &'static str = "Blanket *B"; 89 | } 90 | 91 | impl<_TŠČ0> Kita for Option<_TŠČ0> 92 | where 93 | _TŠČ0: Dispatch, 94 | Option<_TŠČ0>: Dispatch, 95 | Self: Kita0<<_TŠČ0 as Dispatch>::Group, as Dispatch>::Group>, 96 | { 97 | const NAME: &'static str = ::Group, 99 | as Dispatch>::Group, 100 | >>::NAME; 101 | } 102 | }; 103 | */ 104 | 105 | #[test] 106 | fn derivative_self_ty() { 107 | assert_eq!("Blanket AA", Option::::NAME); 108 | assert_eq!("Blanket BA", Option::>::NAME); 109 | assert_eq!("Blanket *B", Option::::NAME); 110 | assert_eq!("Blanket *B", Option::::NAME); 111 | } 112 | -------------------------------------------------------------------------------- /tests/overlapping_common_group.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub trait Dispatch2 { 8 | type Group; 9 | } 10 | 11 | pub enum GroupA {} 12 | impl Dispatch for String { 13 | type Group = GroupA; 14 | } 15 | impl Dispatch2 for String { 16 | type Group = GroupA; 17 | } 18 | impl Dispatch for Vec { 19 | type Group = GroupA; 20 | } 21 | impl Dispatch2 for Vec { 22 | type Group = GroupA; 23 | } 24 | 25 | pub enum GroupB {} 26 | impl Dispatch for i32 { 27 | type Group = GroupB; 28 | } 29 | impl Dispatch2 for i32 { 30 | type Group = GroupA; 31 | } 32 | impl Dispatch for u32 { 33 | type Group = GroupB; 34 | } 35 | impl Dispatch2 for u32 { 36 | type Group = GroupA; 37 | } 38 | impl Dispatch2 for (u32,) { 39 | type Group = GroupB; 40 | } 41 | 42 | disjoint_impls! { 43 | pub trait Kita { 44 | const NAME: &'static str; 45 | } 46 | 47 | impl> Kita for T 48 | where 49 | T: Dispatch2, 50 | { 51 | const NAME: &'static str = "Blanket A"; 52 | } 53 | impl> Kita for U 54 | where 55 | U: Dispatch2, 56 | { 57 | const NAME: &'static str = "Blanket B"; 58 | } 59 | impl Kita for (U,) 60 | where 61 | (U,): Dispatch2, 62 | { 63 | const NAME: &'static str = "Blanket C"; 64 | } 65 | } 66 | 67 | /* 68 | pub trait Kita { 69 | const NAME: &'static str; 70 | } 71 | 72 | const _: () = { 73 | pub trait Kita0<_TŠČ0: ?Sized> { 74 | const NAME: &'static str; 75 | } 76 | impl Kita0 for (U,) 77 | where 78 | (U,): Dispatch2, 79 | { 80 | const NAME: &'static str = "Blanket C"; 81 | } 82 | 83 | pub trait Kita00<_TŠČ0: ?Sized> { 84 | const NAME: &'static str; 85 | } 86 | impl> Kita00 for T 87 | where 88 | T: Dispatch2, 89 | { 90 | const NAME: &'static str = "Blanket A"; 91 | } 92 | impl> Kita00 for U 93 | where 94 | U: Dispatch2, 95 | { 96 | const NAME: &'static str = "Blanket B"; 97 | } 98 | 99 | impl<_TŠČ0> Kita0 for _TŠČ0 100 | where 101 | _TŠČ0: Dispatch, 102 | Self: Kita00<<_TŠČ0 as Dispatch>::Group>, 103 | { 104 | const NAME: &'static str = ::Group>>::NAME; 105 | } 106 | impl<_TŠČ0> Kita for _TŠČ0 107 | where 108 | _TŠČ0: Dispatch2, 109 | Self: Kita0<<_TŠČ0 as Dispatch2>::Group>, 110 | { 111 | const NAME: &'static str = ::Group>>::NAME; 112 | } 113 | }; 114 | */ 115 | 116 | #[test] 117 | fn overlapping_common_group() { 118 | assert_eq!("Blanket A", String::NAME); 119 | assert_eq!("Blanket A", Vec::::NAME); 120 | 121 | assert_eq!("Blanket B", i32::NAME); 122 | assert_eq!("Blanket B", u32::NAME); 123 | 124 | assert_eq!("Blanket C", <(u32,)>::NAME); 125 | } 126 | -------------------------------------------------------------------------------- /src/disjoint.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | pub fn generate( 4 | impl_group_idx: usize, 5 | mut impl_group: ImplGroup, 6 | ) -> impl Iterator { 7 | if impl_group.id.is_inherent() { 8 | for (impl_, args) in &mut impl_group.impls { 9 | traitize_inherent_impl(args, impl_, &impl_group.id.self_ty); 10 | } 11 | } 12 | 13 | let ty_params = impl_group 14 | .impls 15 | .iter() 16 | .map(|(impl_, _)| { 17 | impl_ 18 | .generics 19 | .type_params() 20 | .map(|param| param.ident.clone()) 21 | .collect::>() 22 | }) 23 | .collect::>(); 24 | 25 | let mut impl_assoc_bindings = impl_group 26 | .trait_bounds 27 | .0 28 | .values() 29 | .flat_map(|(orig_trait_bound, assoc_bindings)| { 30 | assoc_bindings.iter().map(|(assoc_ident, (_, payloads))| { 31 | payloads.iter().enumerate().map(|(i, payload)| { 32 | payload.as_ref().map_or_else( 33 | || assoc_binding_default(&orig_trait_bound[i], assoc_ident), 34 | |payload| { 35 | if let syn::Type::Path(syn::TypePath { path, .. }) = payload 36 | && let Some(ident) = path.get_ident() 37 | && ident.to_string().starts_with("_TŠČ") 38 | && !ty_params[i].contains(ident) 39 | { 40 | return assoc_binding_default(&orig_trait_bound[i], assoc_ident); 41 | } 42 | 43 | payload.clone() 44 | }, 45 | ) 46 | }) 47 | }) 48 | }) 49 | .collect::>(); 50 | 51 | impl_group.impls.iter_mut().for_each(|(impl_, _)| { 52 | let assoc_bindings = impl_assoc_bindings.iter_mut().map(|x| x.next().unwrap()); 53 | 54 | let trait_ = &mut impl_.trait_.as_mut().unwrap().1; 55 | let path = trait_.segments.last_mut().unwrap(); 56 | 57 | prepend_args(&mut path.arguments, &assoc_bindings.collect::>()); 58 | path.ident = helper_trait::gen_ident(&impl_group.id, impl_group_idx); 59 | }); 60 | 61 | impl_group.impls.into_iter().map(|(impl_, _)| impl_) 62 | } 63 | 64 | /// Modify impls into trait impls from inherent impls 65 | pub fn traitize_inherent_impl( 66 | generic_args: &[syn::GenericArgument], 67 | impl_: &mut syn::ItemImpl, 68 | self_ty: &syn::Type, 69 | ) { 70 | let syn::Type::Path(type_path) = &self_ty else { 71 | unreachable!() 72 | }; 73 | 74 | let ident = &type_path.path.segments.last().unwrap().ident; 75 | let trait_ = parse_quote! { #ident <#(#generic_args),*> }; 76 | 77 | impl_.items.iter_mut().for_each(|item| { 78 | let vis = match item { 79 | syn::ImplItem::Const(syn::ImplItemConst { vis, .. }) => vis, 80 | syn::ImplItem::Type(syn::ImplItemType { vis, .. }) => vis, 81 | syn::ImplItem::Fn(syn::ImplItemFn { vis, .. }) => vis, 82 | _ => return, 83 | }; 84 | 85 | *vis = syn::Visibility::Inherited; 86 | }); 87 | 88 | impl_.trait_ = Some((None, trait_, Default::default())); 89 | } 90 | -------------------------------------------------------------------------------- /tests/dispatch_on_assoc_type.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | pub enum GroupB {} 9 | pub enum GroupC {} 10 | pub enum GroupD {} 11 | 12 | impl Dispatch for String { 13 | type Group = i32; 14 | } 15 | impl Dispatch for Vec { 16 | type Group = u32; 17 | } 18 | impl Dispatch for &str { 19 | type Group = i16; 20 | } 21 | impl Dispatch for &[T] { 22 | type Group = u16; 23 | } 24 | 25 | impl Dispatch for i32 { 26 | type Group = GroupA; 27 | } 28 | impl Dispatch for u32 { 29 | type Group = GroupB; 30 | } 31 | 32 | impl Dispatch for i16 { 33 | type Group = GroupC; 34 | } 35 | impl Dispatch for u16 { 36 | type Group = GroupD; 37 | } 38 | 39 | disjoint_impls! { 40 | pub trait Kita { 41 | const NAME: &'static str; 42 | } 43 | 44 | impl Kita for T 45 | where 46 | T: Dispatch, 47 | ::Group: Dispatch, 48 | { 49 | const NAME: &'static str = "Blanket A"; 50 | } 51 | 52 | impl Kita for T 53 | where 54 | ::Group: Dispatch, 55 | { 56 | const NAME: &'static str = "Blanket B"; 57 | } 58 | 59 | impl Kita for T 60 | where 61 | ::Group: Dispatch, 62 | { 63 | const NAME: &'static str = "Blanket C"; 64 | } 65 | 66 | impl>> Kita for T { 67 | const NAME: &'static str = "Blanket D"; 68 | } 69 | } 70 | 71 | /* 72 | pub trait Kita { 73 | const NAME: &'static str; 74 | } 75 | 76 | const _: () = { 77 | pub trait Kita0<_TŠČ0: ?Sized, _TŠČ1: ?Sized> { 78 | const NAME: &'static str; 79 | } 80 | impl Kita0<::Group, GroupA> for T 81 | where 82 | T: Dispatch, 83 | ::Group: Dispatch, 84 | { 85 | const NAME: &'static str = "Blanket A"; 86 | } 87 | impl Kita0<::Group, GroupB> for T 88 | where 89 | ::Group: Dispatch, 90 | { 91 | const NAME: &'static str = "Blanket B"; 92 | } 93 | impl Kita0<::Group, GroupC> for T 94 | where 95 | ::Group: Dispatch, 96 | { 97 | const NAME: &'static str = "Blanket C"; 98 | } 99 | impl< 100 | T: Dispatch, 101 | _TŠČ0: Dispatch + ?Sized, 102 | > Kita0<_TŠČ0, GroupD> for T { 103 | const NAME: &'static str = "Blanket D"; 104 | } 105 | 106 | impl<_TŠČ0, _TŠČ1: ?Sized> Kita for _TŠČ0 107 | where 108 | _TŠČ0: Dispatch, 109 | _TŠČ1: Dispatch, 110 | Self: Kita0<_TŠČ1, <_TŠČ1 as Dispatch>::Group>, 111 | { 112 | const NAME: &'static str = ::Group, 115 | >>::NAME; 116 | } 117 | }; 118 | */ 119 | 120 | #[test] 121 | fn dispatch_on_assoc_type() { 122 | assert_eq!(String::NAME, "Blanket A"); 123 | assert_eq!(Vec::::NAME, "Blanket B"); 124 | assert_eq!(<&str>::NAME, "Blanket C"); 125 | assert_eq!(<&[i32]>::NAME, "Blanket D"); 126 | } 127 | -------------------------------------------------------------------------------- /tests/dispatch_on_generic.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | trait Tr { 8 | type A; 9 | } 10 | 11 | impl Tr for u8 { 12 | type A = u16; 13 | } 14 | impl Tr for i8 { 15 | type A = i16; 16 | } 17 | 18 | impl Dispatch for String { 19 | type Group = (u32, u32); 20 | } 21 | impl Dispatch for Vec { 22 | type Group = (u32, String); 23 | } 24 | 25 | impl Dispatch for i32 { 26 | type Group = [(String, String); 1]; 27 | } 28 | impl Dispatch for u32 { 29 | type Group = [(String, u32); 1]; 30 | } 31 | 32 | impl Dispatch for u8 { 33 | type Group = (i8,); 34 | } 35 | impl Dispatch for i8 { 36 | type Group = (u8,); 37 | } 38 | 39 | disjoint_impls! { 40 | pub trait Kita { 41 | fn kita(_a: U, _b: V) -> String { 42 | "Default Blanket".to_owned() 43 | } 44 | } 45 | 46 | impl, U, V> Kita<(U,), V> for T { 47 | fn kita(_a: (U,), _b: V) -> String { 48 | "Generic Blanket A".to_owned() 49 | } 50 | } 51 | impl, U: ToString, V> Kita<(V,), U> for T { 52 | fn kita(_a: (V,), b: U) -> String { 53 | b.to_string() 54 | } 55 | } 56 | 57 | impl, U: Tr, A> Kita for T {} 58 | } 59 | 60 | /* 61 | pub trait Kita { 62 | fn kita(_a: U, _b: V) -> String { 63 | "Default Blanket".to_owned() 64 | } 65 | } 66 | 67 | const _: () = { 68 | pub trait Kita0<_TŠČ2: ?Sized, U, V> { 69 | fn kita(_a: U, _b: V) -> String { 70 | "Default Blanket".to_owned() 71 | } 72 | } 73 | impl, U, V> Kita0<(U, V), (U,), V> for T { 74 | fn kita(_a: (U,), _b: V) -> String { 75 | "Generic Blanket A".to_owned() 76 | } 77 | } 78 | impl, U: ToString, V> Kita0<[(U, V); 1], (V,), U> 79 | for T { 80 | fn kita(_a: (V,), b: U) -> String { 81 | b.to_string() 82 | } 83 | } 84 | 85 | impl<_TŠČ0, _TŠČ1, _TŠČ2> Kita<(_TŠČ0,), _TŠČ1> for _TŠČ2 86 | where 87 | _TŠČ2: Dispatch, 88 | Self: Kita0<<_TŠČ2 as Dispatch>::Group, (_TŠČ0,), _TŠČ1>, 89 | { 90 | fn kita(_a: (_TŠČ0,), _b: _TŠČ1) -> String { 91 | ::Group, 93 | (_TŠČ0,), 94 | _TŠČ1, 95 | >>::kita(_a, _b) 96 | } 97 | } 98 | 99 | impl, U: Tr, A> Kita for T {} 100 | }; 101 | */ 102 | 103 | #[test] 104 | fn dispatch_on_generic() { 105 | let a_arg1 = 42; 106 | let a_arg2 = 420; 107 | 108 | let b_arg1 = "Generic Blanket B".to_owned(); 109 | let b_arg2 = "moja".to_owned(); 110 | let b_arg3 = "kita".to_owned(); 111 | 112 | assert_eq!("Generic Blanket A", String::kita((a_arg1,), a_arg2)); 113 | assert_eq!("Generic Blanket A", Vec::::kita((a_arg1,), b_arg2)); 114 | assert_eq!("Generic Blanket B", i32::kita((b_arg3,), b_arg1.clone())); 115 | assert_eq!("Generic Blanket B", u32::kita((a_arg2,), b_arg1)); 116 | 117 | assert_eq!("Default Blanket", u8::kita(a_arg2, 8_i8)); 118 | assert_eq!("Default Blanket", i8::kita(a_arg2, 8_u8)); 119 | } 120 | -------------------------------------------------------------------------------- /tests/gats.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for &i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for &u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita { 25 | type Item<'a> where Self: 'a; 26 | type Other<'a, K> where Self: 'a; 27 | 28 | fn kita<'a>(&'a mut self) -> Self::Item<'a>; 29 | 30 | fn pita<'a, K: 'a>() -> &'static str { 31 | "Default Blanket" 32 | } 33 | } 34 | 35 | impl> Kita for T { 36 | type Item<'a> = &'a u32 where Self: 'a; 37 | type Other<'a, K> = K where Self: 'a; 38 | 39 | fn kita<'a>(&'a mut self) -> &'a u32 { 40 | &1 41 | } 42 | } 43 | impl<'a, U> Kita for &'a U where Self: Dispatch { 44 | type Item<'u> = &'u U where Self: 'u; 45 | type Other<'u, K> = K where Self: 'u; 46 | 47 | fn kita<'u>(&'u mut self) -> Self::Item<'u> { 48 | self 49 | } 50 | } 51 | } 52 | 53 | /* 54 | pub trait Kita { 55 | type Item<'a> where Self: 'a; 56 | type Other<'a, K> where Self: 'a; 57 | 58 | fn kita<'a>(&'a mut self) -> Self::Item<'a>; 59 | fn pita<'a, K: 'a>() -> &'static str { 60 | "Default Blanket" 61 | } 62 | } 63 | 64 | const _: () = { 65 | pub trait Kita0<_TŠČ0: ?Sized> { 66 | type Item<'a> where Self: 'a; 67 | type Other<'a, K> where Self: 'a; 68 | 69 | fn kita<'a>(&'a mut self) -> Self::Item<'a>; 70 | fn pita<'a, K: 'a>() -> &'static str { 71 | "Default Blanket" 72 | } 73 | } 74 | impl> Kita0 for T { 75 | type Item<'a> = &'a u32 where Self: 'a; 76 | type Other<'a, K> = K where Self: 'a; 77 | 78 | fn kita<'a>(&'a mut self) -> &'a u32 { 79 | &1 80 | } 81 | } 82 | impl<'a, U> Kita0 for &'a U 83 | where 84 | &'a U: Dispatch, 85 | { 86 | type Item<'u> = &'u U where Self: 'u; 87 | type Other<'u, K> = K where Self: 'u; 88 | 89 | fn kita<'u>(&'u mut self) -> Self::Item<'u> { 90 | self 91 | } 92 | } 93 | 94 | impl<_TŠČ0> Kita for _TŠČ0 95 | where 96 | _TŠČ0: Dispatch, 97 | Self: Kita0<<_TŠČ0 as Dispatch>::Group>, 98 | { 99 | type Item<'a> = ::Group>>::Item<'a> 100 | where 101 | Self: 'a; 102 | type Other<'a, K> = ::Group>>::Other<'a, K> 103 | where 104 | Self: 'a; 105 | 106 | fn kita<'a>(&'a mut self) -> Self::Item<'a> { 107 | ::Group>>::kita(self) 108 | } 109 | fn pita<'a, K: 'a>() -> &'static str { 110 | ::Group>>::pita::() 111 | } 112 | } 113 | }; 114 | */ 115 | 116 | #[test] 117 | fn gats() { 118 | assert_eq!(&1, String::new().kita()); 119 | assert_eq!(&1, Vec::::new().kita()); 120 | assert_eq!(&12, (&12_u32).kita()); 121 | assert_eq!(&12, (&12_i32).kita()); 122 | } 123 | -------------------------------------------------------------------------------- /tests/multiple_blanket_impls.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for String { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Vec { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita { 25 | const NAME: &'static str; 26 | } 27 | 28 | impl> Kita for T { 29 | const NAME: &'static str = "Blanket A"; 30 | } 31 | impl> Kita for U { 32 | const NAME: &'static str = "Blanket B"; 33 | } 34 | 35 | impl, U: Dispatch> Kita for (T, U) { 36 | const NAME: &'static str = "Blanket AA"; 37 | } 38 | impl Kita for (U, T) 39 | where 40 | U: Dispatch, 41 | T: Dispatch, 42 | { 43 | const NAME: &'static str = "Blanket AB"; 44 | } 45 | impl, U: Dispatch> Kita for (T, U) { 46 | const NAME: &'static str = "Blanket B*"; 47 | } 48 | } 49 | 50 | /* 51 | pub trait Kita { 52 | const NAME: &'static str; 53 | } 54 | 55 | const _: () = { 56 | pub trait Kita0<_TŠČ0: ?Sized> { 57 | const NAME: &'static str; 58 | } 59 | impl> Kita0 for T { 60 | const NAME: &'static str = "Blanket A"; 61 | } 62 | impl> Kita0 for U { 63 | const NAME: &'static str = "Blanket B"; 64 | } 65 | 66 | pub trait Kita1<_TŠČ0: ?Sized, _TŠČ1: ?Sized> { 67 | const NAME: &'static str; 68 | } 69 | impl, U: Dispatch> Kita1 70 | for (T, U) { 71 | const NAME: &'static str = "Blanket AA"; 72 | } 73 | impl Kita1 for (U, T) 74 | where 75 | U: Dispatch, 76 | T: Dispatch, 77 | { 78 | const NAME: &'static str = "Blanket AB"; 79 | } 80 | impl, U: Dispatch> Kita1::Group> 81 | for (T, U) { 82 | const NAME: &'static str = "Blanket B*"; 83 | } 84 | 85 | impl<_TŠČ0> Kita for _TŠČ0 86 | where 87 | _TŠČ0: Dispatch, 88 | Self: Kita0<<_TŠČ0 as Dispatch>::Group>, 89 | { 90 | const NAME: &'static str = ::Group>>::NAME; 91 | } 92 | impl<_TŠČ0, _TŠČ1> Kita for (_TŠČ0, _TŠČ1) 93 | where 94 | _TŠČ0: Dispatch, 95 | _TŠČ1: Dispatch, 96 | Self: Kita1<<_TŠČ0 as Dispatch>::Group, <_TŠČ1 as Dispatch>::Group>, 97 | { 98 | const NAME: &'static str = ::Group, 100 | <_TŠČ1 as Dispatch>::Group, 101 | >>::NAME; 102 | } 103 | }; 104 | */ 105 | 106 | #[test] 107 | fn multiple_blanket_impls() { 108 | assert_eq!("Blanket A", String::NAME); 109 | assert_eq!("Blanket A", Vec::::NAME); 110 | assert_eq!("Blanket B", u32::NAME); 111 | assert_eq!("Blanket B", i32::NAME); 112 | 113 | assert_eq!("Blanket AA", <(String, String)>::NAME); 114 | assert_eq!("Blanket AB", <(String, u32)>::NAME); 115 | assert_eq!("Blanket B*", <(u32, i32)>::NAME); 116 | } 117 | -------------------------------------------------------------------------------- /tests/disparate_trait_generics.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for (u16, u32) { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for (i16, i32) { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for (i32, String) { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for (u32, String) { 20 | type Group = GroupB; 21 | } 22 | 23 | disjoint_impls! { 24 | pub trait Kita { 25 | const NAME: &'static str; 26 | } 27 | 28 | impl Kita<(U, C)> for T 29 | where 30 | (U, C): Dispatch, 31 | { 32 | const NAME: &'static str = "1st Blanket A"; 33 | } 34 | impl Kita<(U, C)> for T 35 | where 36 | (U, C): Dispatch, 37 | { 38 | const NAME: &'static str = "1st Blanket B"; 39 | } 40 | 41 | impl> Kita<(i32,)> for T { 42 | const NAME: &'static str = "2nd Blanket A"; 43 | } 44 | impl> Kita<(i32,)> for T { 45 | const NAME: &'static str = "2nd Blanket B"; 46 | } 47 | } 48 | 49 | /* 50 | pub trait Kita { 51 | const NAME: &'static str; 52 | } 53 | 54 | const _: () = { 55 | pub trait Kita0<_TŠČ1: ?Sized, U> { 56 | const NAME: &'static str; 57 | } 58 | impl Kita0 for T 59 | where 60 | (U, C): Dispatch, 61 | { 62 | const NAME: &'static str = "1st Blanket A"; 63 | } 64 | impl Kita0 for T 65 | where 66 | (U, C): Dispatch, 67 | { 68 | const NAME: &'static str = "1st Blanket B"; 69 | } 70 | 71 | pub trait Kita1<_TŠČ1: ?Sized, U> { 72 | const NAME: &'static str; 73 | } 74 | impl> Kita1 for T { 75 | const NAME: &'static str = "2nd Blanket A"; 76 | } 77 | impl> Kita1 for T { 78 | const NAME: &'static str = "2nd Blanket B"; 79 | } 80 | 81 | impl<_TŠČ0, _TŠČ1, _TŠČ2> Kita<(_TŠČ0, _TŠČ1)> for _TŠČ2 82 | where 83 | (_TŠČ0, _TŠČ1): Dispatch, 84 | Self: Kita0<<(_TŠČ0, _TŠČ1) as Dispatch>::Group, (_TŠČ0, _TŠČ1)>, 85 | { 86 | const NAME: &'static str = ::Group, 88 | (_TŠČ0, _TŠČ1), 89 | >>::NAME; 90 | } 91 | impl<_TŠČ0> Kita<(i32,)> for _TŠČ0 92 | where 93 | _TŠČ0: Dispatch, 94 | Self: Kita1<<_TŠČ0 as Dispatch>::Group, (i32,)>, 95 | { 96 | const NAME: &'static str = ::Group, 98 | (i32,), 99 | >>::NAME; 100 | } 101 | }; 102 | */ 103 | 104 | #[test] 105 | fn disparate_trait_generics() { 106 | assert_eq!("1st Blanket A", >::NAME); 107 | assert_eq!("1st Blanket A", >::NAME); 108 | assert_eq!("1st Blanket B", >::NAME); 109 | assert_eq!("1st Blanket B", as Kita<(u32, String)>>::NAME); 110 | 111 | assert_eq!("2nd Blanket A", <(u16, u32) as Kita<(i32,)>>::NAME); 112 | assert_eq!("2nd Blanket A", <(i16, i32) as Kita<(i32,)>>::NAME); 113 | assert_eq!("2nd Blanket B", <(i32, String) as Kita<(i32,)>>::NAME); 114 | assert_eq!("2nd Blanket B", <(u32, String) as Kita<(i32,)>>::NAME); 115 | } 116 | -------------------------------------------------------------------------------- /src/helper_trait.rs: -------------------------------------------------------------------------------- 1 | use crate::main_trait::is_remote; 2 | 3 | use super::*; 4 | 5 | /// Generate helper trait 6 | /// 7 | /// Helper trait contains all items of the main trait but is parametrized with 8 | /// type parameters corresponding to a minimal set of associated bindings 9 | /// that uniquely identify all of the disjoint impls within an impl group 10 | pub fn generate( 11 | main_trait: Option<&ItemTrait>, 12 | impl_group_idx: usize, 13 | impl_group: &ImplGroup, 14 | ) -> syn::ItemTrait { 15 | let assoc_binding_count = &impl_group.trait_bounds.generalized_idents().count(); 16 | 17 | let mut helper_trait = if let Some(helper_trait) = main_trait { 18 | helper_trait.clone() 19 | } else { 20 | let impl_items = gen_inherent_trait_items(impl_group.items.as_ref().unwrap()); 21 | 22 | let mut self_ty = impl_group.id.self_ty.clone(); 23 | if let syn::Type::Path(type_path) = &mut self_ty { 24 | type_path.path.segments.last_mut().unwrap().arguments = syn::PathArguments::None; 25 | } 26 | 27 | let impl_generics = &impl_group.params; 28 | 29 | parse_quote! { 30 | trait #self_ty <#impl_generics> { 31 | #(#impl_items)* 32 | } 33 | } 34 | }; 35 | 36 | helper_trait.attrs = core::mem::take(&mut helper_trait.attrs) 37 | .into_iter() 38 | .filter(|attr| !is_remote(attr)) 39 | .collect(); 40 | 41 | helper_trait.vis = syn::Visibility::Public(parse_quote!(pub)); 42 | helper_trait.ident = gen_ident(&impl_group.id, impl_group_idx); 43 | 44 | let start_idx = helper_trait.generics.params.len(); 45 | helper_trait.generics.params = combine_generic_args( 46 | (start_idx..start_idx + assoc_binding_count).map(|i| format_ident!("_TŠČ{i}")), 47 | &helper_trait.generics, 48 | ) 49 | .map(|arg| -> syn::GenericParam { parse_quote!(#arg) }) 50 | .collect(); 51 | 52 | helper_trait 53 | } 54 | 55 | fn combine_generic_args( 56 | assoc_param_bounds: impl IntoIterator, 57 | generics: &syn::Generics, 58 | ) -> impl Iterator { 59 | let mut generic_args: Vec<_> = assoc_param_bounds 60 | .into_iter() 61 | .map(|param| quote!(#param: ?Sized)) 62 | .collect(); 63 | 64 | let mut lifetimes = vec![]; 65 | for arg in &generics.params { 66 | if matches!(arg, syn::GenericParam::Lifetime(_)) { 67 | lifetimes.push(quote!(#arg)); 68 | } else { 69 | generic_args.push(quote!(#arg)); 70 | } 71 | } 72 | 73 | lifetimes.into_iter().chain(generic_args) 74 | } 75 | 76 | fn gen_inherent_trait_items(impl_items: &ImplItemsDesc) -> impl Iterator { 77 | let assoc_consts = impl_items 78 | .assoc_consts 79 | .iter() 80 | .map(|(ident, ty)| syn::TraitItem::Const(parse_quote! { const #ident: #ty; })); 81 | let assoc_types = impl_items 82 | .assoc_types 83 | .iter() 84 | .map(|ident| syn::TraitItem::Type(parse_quote! { const #ident; })); 85 | let fns = impl_items 86 | .fns 87 | .values() 88 | .map(|sig| syn::TraitItem::Fn(parse_quote! { #sig; })); 89 | 90 | assoc_consts.chain(assoc_types).chain(fns) 91 | } 92 | 93 | /// Generate ident of the helper trait 94 | pub fn gen_ident(group_id: &ImplGroupId, idx: usize) -> syn::Ident { 95 | let base = if let Some(trait_path) = &group_id.trait_ { 96 | trait_path.segments.last().map(|segment| &segment.ident) 97 | } else if let syn::Type::Path(ty) = &group_id.self_ty { 98 | ty.path.segments.last().map(|segment| &segment.ident) 99 | } else { 100 | unreachable!() 101 | } 102 | .unwrap(); 103 | 104 | format_ident!("{}{}", base, idx) 105 | } 106 | -------------------------------------------------------------------------------- /src/generalize/stmt.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl Generalize for syn::Stmt { 4 | fn generalize<'a>( 5 | &'a self, 6 | other: &'a Self, 7 | params1: &Params, 8 | params2: &Params, 9 | substitutions: &mut Generalizations<'a>, 10 | ) -> Option { 11 | use syn::Stmt::*; 12 | 13 | match (self, other) { 14 | (Local(x1), Local(x2)) => x1 15 | .generalize(x2, params1, params2, substitutions) 16 | .map(Local), 17 | (Item(_), _) | (_, Item(_)) => unimplemented!(), 18 | (Expr(x1, semi_token1), Expr(x2, semi_token2)) if semi_token1 == semi_token2 => x1 19 | .generalize(x2, params1, params2, substitutions) 20 | .map(|generalized| Expr(generalized, *semi_token1)), 21 | (Macro(x1), Macro(x2)) => x1 22 | .generalize(x2, params1, params2, substitutions) 23 | .map(Macro), 24 | _ => None, 25 | } 26 | } 27 | } 28 | 29 | impl Generalize for syn::Local { 30 | fn generalize<'a>( 31 | &'a self, 32 | other: &'a Self, 33 | params1: &Params, 34 | params2: &Params, 35 | substitutions: &mut Generalizations<'a>, 36 | ) -> Option { 37 | let attrs = self 38 | .attrs 39 | .generalize(&other.attrs, params1, params2, substitutions)?; 40 | let pat = self 41 | .pat 42 | .generalize(&other.pat, params1, params2, substitutions)?; 43 | let prev_expected_type = match (&self.pat, &other.pat) { 44 | (syn::Pat::Type(ty), _) | (_, syn::Pat::Type(ty)) => substitutions 45 | .curr_expr_expected_type 46 | .replace((*ty.ty).clone()), 47 | _ => None, 48 | }; 49 | let init = self 50 | .init 51 | .generalize(&other.init, params1, params2, substitutions)?; 52 | substitutions.curr_expr_expected_type = prev_expected_type; 53 | 54 | Some(Self { 55 | attrs, 56 | pat, 57 | init, 58 | ..self.clone() 59 | }) 60 | } 61 | } 62 | 63 | impl Generalize for syn::StmtMacro { 64 | fn generalize<'a>( 65 | &'a self, 66 | other: &'a Self, 67 | params1: &Params, 68 | params2: &Params, 69 | substitutions: &mut Generalizations<'a>, 70 | ) -> Option { 71 | if self.semi_token != other.semi_token { 72 | return None; 73 | } 74 | 75 | let attrs = self 76 | .attrs 77 | .generalize(&other.attrs, params1, params2, substitutions)?; 78 | let mac = self 79 | .mac 80 | .generalize(&other.mac, params1, params2, substitutions)?; 81 | 82 | Some(Self { 83 | attrs, 84 | mac, 85 | ..self.clone() 86 | }) 87 | } 88 | } 89 | 90 | impl Generalize for syn::LocalInit { 91 | fn generalize<'a>( 92 | &'a self, 93 | other: &'a Self, 94 | params1: &Params, 95 | params2: &Params, 96 | substitutions: &mut Generalizations<'a>, 97 | ) -> Option { 98 | let expr = self 99 | .expr 100 | .generalize(&other.expr, params1, params2, substitutions)?; 101 | let diverge = self 102 | .diverge 103 | .generalize(&other.diverge, params1, params2, substitutions)?; 104 | 105 | Some(Self { 106 | expr, 107 | diverge, 108 | ..self.clone() 109 | }) 110 | } 111 | } 112 | 113 | impl Generalize for syn::Block { 114 | fn generalize<'a>( 115 | &'a self, 116 | other: &'a Self, 117 | params1: &Params, 118 | params2: &Params, 119 | substitutions: &mut Generalizations<'a>, 120 | ) -> Option { 121 | let stmts = self 122 | .stmts 123 | .generalize(&other.stmts, params1, params2, substitutions)?; 124 | 125 | Some(Self { 126 | stmts, 127 | ..self.clone() 128 | }) 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /tests/nested_subgroups.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch1 { 4 | type Group; 5 | } 6 | pub trait Dispatch2 { 7 | type Group; 8 | } 9 | pub trait Dispatch3 { 10 | type Group; 11 | } 12 | 13 | pub enum GroupA {} 14 | pub enum GroupB {} 15 | 16 | impl Dispatch1 for String { 17 | type Group = GroupA; 18 | } 19 | impl Dispatch2 for String { 20 | type Group = GroupA; 21 | } 22 | impl Dispatch3 for String { 23 | type Group = GroupA; 24 | } 25 | 26 | impl Dispatch1 for Vec { 27 | type Group = GroupA; 28 | } 29 | impl Dispatch2 for Vec { 30 | type Group = GroupA; 31 | } 32 | impl Dispatch3 for Vec { 33 | type Group = GroupB; 34 | } 35 | 36 | impl Dispatch1 for Vec { 37 | type Group = GroupA; 38 | } 39 | impl Dispatch2 for Vec { 40 | type Group = GroupB; 41 | } 42 | impl Dispatch3 for Vec { 43 | type Group = GroupA; 44 | } 45 | 46 | impl Dispatch1 for i32 { 47 | type Group = GroupB; 48 | } 49 | 50 | disjoint_impls! { 51 | pub trait Kita { 52 | const NAME: &'static str; 53 | } 54 | 55 | impl + Dispatch2 + Dispatch3> Kita for T { 56 | const NAME: &'static str = "Blanket AAA"; 57 | } 58 | impl + Dispatch2 + Dispatch3> Kita for T { 59 | const NAME: &'static str = "Blanket AAB"; 60 | } 61 | impl + Dispatch2> Kita for T { 62 | const NAME: &'static str = "Blanket AB*"; 63 | } 64 | impl> Kita for T { 65 | const NAME: &'static str = "Blanket B**"; 66 | } 67 | } 68 | 69 | /* 70 | pub trait Kita { 71 | const NAME: &'static str; 72 | } 73 | 74 | const _: () = { 75 | pub trait Kita0<_TŠČ1: ?Sized, A> { 76 | const NAME: &'static str; 77 | } 78 | impl> Kita0 for T { 79 | const NAME: &'static str = "Blanket B**"; 80 | } 81 | 82 | pub trait Kita00<_TŠČ1: ?Sized, A> { 83 | const NAME: &'static str; 84 | } 85 | impl + Dispatch2> Kita00 86 | for T { 87 | const NAME: &'static str = "Blanket AB*"; 88 | } 89 | 90 | pub trait Kita000<_TŠČ1: ?Sized, A> { 91 | const NAME: &'static str; 92 | } 93 | impl< 94 | T: Dispatch1 + Dispatch2 95 | + Dispatch3, 96 | > Kita000 for T { 97 | const NAME: &'static str = "Blanket AAA"; 98 | } 99 | impl< 100 | T: Dispatch1 + Dispatch2 101 | + Dispatch3, 102 | > Kita000 for T { 103 | const NAME: &'static str = "Blanket AAB"; 104 | } 105 | 106 | impl<_TŠČ0> Kita00 for _TŠČ0 107 | where 108 | _TŠČ0: Dispatch3, 109 | Self: Kita000<<_TŠČ0 as Dispatch3>::Group, u32>, 110 | { 111 | const NAME: &'static str = ::Group, 113 | u32, 114 | >>::NAME; 115 | } 116 | impl<_TŠČ0> Kita0 for _TŠČ0 117 | where 118 | _TŠČ0: Dispatch2, 119 | Self: Kita00<<_TŠČ0 as Dispatch2>::Group, u32>, 120 | { 121 | const NAME: &'static str = ::Group, 123 | u32, 124 | >>::NAME; 125 | } 126 | impl<_TŠČ0> Kita for _TŠČ0 127 | where 128 | _TŠČ0: Dispatch1, 129 | Self: Kita0<<_TŠČ0 as Dispatch1>::Group, u32>, 130 | { 131 | const NAME: &'static str = ::Group, 133 | u32, 134 | >>::NAME; 135 | } 136 | }; 137 | */ 138 | 139 | #[test] 140 | fn nested_subgroups() { 141 | assert_eq!("Blanket AAA", String::NAME); 142 | assert_eq!("Blanket AAB", Vec::::NAME); 143 | assert_eq!("Blanket AB*", Vec::::NAME); 144 | assert_eq!("Blanket B**", i32::NAME); 145 | } 146 | -------------------------------------------------------------------------------- /tests/inherent_nested_subgroups.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch1 { 4 | type Group; 5 | } 6 | pub trait Dispatch2 { 7 | type Group; 8 | } 9 | pub trait Dispatch3 { 10 | type Group; 11 | } 12 | 13 | pub enum GroupA {} 14 | pub enum GroupB {} 15 | 16 | impl Dispatch1 for String { 17 | type Group = GroupA; 18 | } 19 | impl Dispatch2 for String { 20 | type Group = GroupA; 21 | } 22 | impl Dispatch3 for String { 23 | type Group = GroupA; 24 | } 25 | 26 | impl Dispatch1 for Vec { 27 | type Group = GroupA; 28 | } 29 | impl Dispatch2 for Vec { 30 | type Group = GroupA; 31 | } 32 | impl Dispatch3 for Vec { 33 | type Group = GroupB; 34 | } 35 | 36 | impl Dispatch1 for Vec { 37 | type Group = GroupA; 38 | } 39 | impl Dispatch2 for Vec { 40 | type Group = GroupB; 41 | } 42 | impl Dispatch3 for Vec { 43 | type Group = GroupA; 44 | } 45 | 46 | impl Dispatch1 for u32 { 47 | type Group = GroupA; 48 | } 49 | impl Dispatch2 for u32 { 50 | type Group = GroupB; 51 | } 52 | impl Dispatch3 for u32 { 53 | type Group = GroupB; 54 | } 55 | 56 | impl Dispatch1 for i32 { 57 | type Group = GroupB; 58 | } 59 | 60 | struct Wrapper(T); 61 | 62 | disjoint_impls! { 63 | impl + Dispatch2 + Dispatch3> Wrapper { 64 | const NAME: &'static str = "Blanket AAA"; 65 | } 66 | impl + Dispatch2 + Dispatch3> Wrapper { 67 | const NAME: &'static str = "Blanket AAB"; 68 | } 69 | impl + Dispatch2> Wrapper { 70 | const NAME: &'static str = "Blanket AB*"; 71 | } 72 | impl> Wrapper { 73 | const NAME: &'static str = "Blanket B**"; 74 | } 75 | } 76 | 77 | /* 78 | const _: () = { 79 | pub trait Wrapper0<_TŠČ2: ?Sized, _TŠČ0, _TŠČ1> { 80 | const NAME: &'static str; 81 | } 82 | impl> Wrapper0 for Wrapper { 83 | const NAME: &'static str = "Blanket B**"; 84 | } 85 | 86 | pub trait Wrapper00<_TŠČ2: ?Sized, _TŠČ0, _TŠČ1> { 87 | const NAME: &'static str; 88 | } 89 | impl< 90 | T: Dispatch1 + Dispatch2, 91 | > Wrapper00 for Wrapper { 92 | const NAME: &'static str = "Blanket AB*"; 93 | } 94 | 95 | pub trait Wrapper000<_TŠČ2: ?Sized, _TŠČ0, _TŠČ1> { 96 | const NAME: &'static str; 97 | } 98 | impl< 99 | T: Dispatch1 + Dispatch2 100 | + Dispatch3, 101 | > Wrapper000 for Wrapper { 102 | const NAME: &'static str = "Blanket AAA"; 103 | } 104 | impl< 105 | T: Dispatch1 + Dispatch2 106 | + Dispatch3, 107 | > Wrapper000 for Wrapper { 108 | const NAME: &'static str = "Blanket AAB"; 109 | } 110 | 111 | impl<_TŠČ0, _TŠČ1> Wrapper00 for Wrapper<_TŠČ0> 112 | where 113 | _TŠČ0: Dispatch3, 114 | Self: Wrapper000<_TŠČ1, _TŠČ0, _TŠČ1>, 115 | { 116 | const NAME: &'static str = >::NAME; 117 | } 118 | impl<_TŠČ0, _TŠČ1> Wrapper0 for Wrapper<_TŠČ0> 119 | where 120 | _TŠČ0: Dispatch2, 121 | Self: Wrapper00<_TŠČ1, _TŠČ0, _TŠČ1>, 122 | { 123 | const NAME: &'static str = >::NAME; 124 | } 125 | impl<_TŠČ0, _TŠČ1> Wrapper<_TŠČ0> 126 | where 127 | _TŠČ0: Dispatch1, 128 | Self: Wrapper0<_TŠČ1, _TŠČ0, _TŠČ1>, 129 | { 130 | const NAME: &'static str = >::NAME; 131 | } 132 | }; 133 | */ 134 | 135 | #[test] 136 | fn inherent_nested_subgroups() { 137 | assert_eq!("Blanket AAA", Wrapper::::NAME); 138 | assert_eq!("Blanket AAB", Wrapper::>::NAME); 139 | assert_eq!("Blanket AB*", Wrapper::>::NAME); 140 | assert_eq!("Blanket B**", Wrapper::::NAME); 141 | } 142 | -------------------------------------------------------------------------------- /src/generalize/item.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl Generalize for syn::Signature { 4 | fn generalize<'a>( 5 | &'a self, 6 | other: &'a Self, 7 | params1: &Params, 8 | params2: &Params, 9 | subs: &mut Generalizations<'a>, 10 | ) -> Option { 11 | if self.asyncness != other.asyncness 12 | || self.constness != other.constness 13 | || self.unsafety != other.unsafety 14 | || self.ident != other.ident 15 | { 16 | return None; 17 | } 18 | 19 | let abi = self.abi.generalize(&other.abi, params1, params2, subs)?; 20 | let generics = self 21 | .generics 22 | .generalize(&other.generics, params1, params2, subs)?; 23 | let inputs = self 24 | .inputs 25 | .generalize(&other.inputs, params1, params2, subs)?; 26 | let output = self 27 | .output 28 | .generalize(&other.output, params1, params2, subs)?; 29 | 30 | Some(syn::Signature { 31 | abi, 32 | generics, 33 | inputs, 34 | output, 35 | ..self.clone() 36 | }) 37 | } 38 | } 39 | 40 | impl Generalize for syn::ImplItemConst { 41 | fn generalize<'a>( 42 | &'a self, 43 | other: &'a Self, 44 | params1: &Params, 45 | params2: &Params, 46 | subs: &mut Generalizations<'a>, 47 | ) -> Option { 48 | if self.vis != other.vis || self.ident != other.ident { 49 | return None; 50 | } 51 | 52 | let attrs = self 53 | .attrs 54 | .generalize(&other.attrs, params1, params2, subs)?; 55 | let generics = self 56 | .generics 57 | .generalize(&other.generics, params1, params2, subs)?; 58 | let ty = self.ty.generalize(&other.ty, params1, params2, subs)?; 59 | let expr = self.expr.generalize(&other.expr, params1, params2, subs)?; 60 | 61 | Some(Self { 62 | attrs, 63 | generics, 64 | ty, 65 | expr, 66 | ..self.clone() 67 | }) 68 | } 69 | } 70 | 71 | impl Generalize for syn::ImplItemType { 72 | fn generalize<'a>( 73 | &'a self, 74 | other: &'a Self, 75 | params1: &Params, 76 | params2: &Params, 77 | subs: &mut Generalizations<'a>, 78 | ) -> Option { 79 | if self.vis != other.vis || self.ident != other.ident { 80 | return None; 81 | } 82 | 83 | let attrs = self 84 | .attrs 85 | .generalize(&other.attrs, params1, params2, subs)?; 86 | let generics = self 87 | .generics 88 | .generalize(&other.generics, params1, params2, subs)?; 89 | let ty = self.ty.generalize(&other.ty, params1, params2, subs)?; 90 | 91 | Some(Self { 92 | attrs, 93 | generics, 94 | ty, 95 | ..self.clone() 96 | }) 97 | } 98 | } 99 | 100 | impl Generalize for syn::FnArg { 101 | fn generalize<'a>( 102 | &'a self, 103 | other: &'a Self, 104 | params1: &Params, 105 | params2: &Params, 106 | subs: &mut Generalizations<'a>, 107 | ) -> Option { 108 | match (self, other) { 109 | (syn::FnArg::Receiver(x1), syn::FnArg::Receiver(x2)) => x1 110 | .generalize(x2, params1, params2, subs) 111 | .map(syn::FnArg::Receiver), 112 | (syn::FnArg::Typed(pat1), syn::FnArg::Typed(pat2)) => pat1 113 | .generalize(pat2, params1, params2, subs) 114 | .map(syn::FnArg::Typed), 115 | _ => None, 116 | } 117 | } 118 | } 119 | 120 | impl Generalize for syn::Receiver { 121 | fn generalize<'a>( 122 | &'a self, 123 | other: &'a Self, 124 | params1: &Params, 125 | params2: &Params, 126 | subs: &mut Generalizations<'a>, 127 | ) -> Option { 128 | if self.mutability != other.mutability || self.colon_token != other.colon_token { 129 | return None; 130 | } 131 | 132 | let attrs = self 133 | .attrs 134 | .generalize(&other.attrs, params1, params2, subs)?; 135 | let reference = self 136 | .reference 137 | .generalize(&other.reference, params1, params2, subs)?; 138 | let ty = self.ty.generalize(&other.ty, params1, params2, subs)?; 139 | 140 | Some(Self { 141 | attrs, 142 | reference, 143 | ty, 144 | ..self.clone() 145 | }) 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /tests/trait_with_assoc_type.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | trait A { 8 | type B; 9 | } 10 | 11 | pub enum GroupA {} 12 | impl Dispatch for (u16, u32) { 13 | type Group = GroupA; 14 | } 15 | impl Dispatch for (i16, i32) { 16 | type Group = GroupB; 17 | } 18 | 19 | pub enum GroupB {} 20 | impl Dispatch for (i32, String) { 21 | type Group = GroupB; 22 | } 23 | impl Dispatch for (u32, String) { 24 | type Group = GroupB; 25 | } 26 | 27 | impl A for (u16, u32) { 28 | type B = u32; 29 | } 30 | 31 | impl A for (i32, String) { 32 | type B = u32; 33 | } 34 | 35 | impl A for (i32,) { 36 | type B = u32; 37 | } 38 | 39 | impl A for (u32, T) { 40 | type B = i32; 41 | } 42 | 43 | disjoint_impls! { 44 | trait Kita, T = u32> 45 | where 46 | (T, U): A, 47 | { 48 | const NAME: &'static str; 49 | } 50 | 51 | impl Kita<(U, C), u32> for T 52 | where 53 | (U, C): Dispatch + A, 54 | (u32, (U, C)): A, 55 | { 56 | const NAME: &'static str = "1st Blanket A"; 57 | } 58 | impl Kita<(U, C), u32> for T 59 | where 60 | (U, C): Dispatch + A, 61 | (u32, (U, C)): A, 62 | { 63 | const NAME: &'static str = "1st Blanket B"; 64 | } 65 | 66 | impl> Kita<(i32,), u32> for T { 67 | const NAME: &'static str = "2nd Blanket A"; 68 | } 69 | impl> Kita<(i32,), u32> for T { 70 | const NAME: &'static str = "2nd Blanket B"; 71 | } 72 | } 73 | 74 | /* 75 | trait Kita, T = u32> 76 | where 77 | (T, U): A, 78 | { 79 | const NAME: &'static str; 80 | } 81 | 82 | const _: () = { 83 | pub trait Kita0< 84 | _TŠČ2: ?Sized, 85 | _TŠČ3: ?Sized, 86 | _TŠČ4: ?Sized, 87 | U: A, 88 | T = u32, 89 | > 90 | where 91 | (T, U): A, 92 | { 93 | const NAME: &'static str; 94 | } 95 | impl Kita0 for T 96 | where 97 | (U, C): Dispatch + A, 98 | (u32, (U, C)): A, 99 | { 100 | const NAME: &'static str = "1st Blanket A"; 101 | } 102 | impl Kita0 for T 103 | where 104 | (U, C): Dispatch + A, 105 | (u32, (U, C)): A, 106 | { 107 | const NAME: &'static str = "1st Blanket B"; 108 | } 109 | 110 | pub trait Kita1<_TŠČ2: ?Sized, U: A, T = u32> 111 | where 112 | (T, U): A, 113 | { 114 | const NAME: &'static str; 115 | } 116 | impl> Kita1 for T { 117 | const NAME: &'static str = "2nd Blanket A"; 118 | } 119 | impl> Kita1 for T { 120 | const NAME: &'static str = "2nd Blanket B"; 121 | } 122 | 123 | // TODO: Bounds are also duplicated here 124 | 125 | impl<_TŠČ0, _TŠČ1, _TŠČ2> Kita<(_TŠČ0, _TŠČ1), u32> for _TŠČ2 126 | where 127 | (u32, (_TŠČ0, _TŠČ1)): A, 128 | (_TŠČ0, _TŠČ1): A, 129 | (u32, (_TŠČ0, _TŠČ1)): A, 130 | (_TŠČ0, _TŠČ1): A, 131 | (_TŠČ0, _TŠČ1): Dispatch, 132 | Self: Kita0< 133 | <(u32, (_TŠČ0, _TŠČ1)) as A>::B, 134 | <(_TŠČ0, _TŠČ1) as A>::B, 135 | <(_TŠČ0, _TŠČ1) as Dispatch>::Group, 136 | (_TŠČ0, _TŠČ1), 137 | u32, 138 | >, 139 | { 140 | const NAME: &'static str = ::B, 142 | <(_TŠČ0, _TŠČ1) as A>::B, 143 | <(_TŠČ0, _TŠČ1) as Dispatch>::Group, 144 | (_TŠČ0, _TŠČ1), 145 | u32, 146 | >>::NAME; 147 | } 148 | impl<_TŠČ0> Kita<(i32,), u32> for _TŠČ0 149 | where 150 | (u32, (i32,)): A, 151 | (i32,): A, 152 | _TŠČ0: Dispatch, 153 | Self: Kita1<<_TŠČ0 as Dispatch>::Group, (i32,), u32>, 154 | { 155 | const NAME: &'static str = ::Group, 157 | (i32,), 158 | u32, 159 | >>::NAME; 160 | } 161 | }; 162 | */ 163 | 164 | #[test] 165 | fn trait_with_assoc_type() { 166 | assert_eq!("1st Blanket A", >::NAME); 167 | assert_eq!("1st Blanket B", >::NAME); 168 | assert_eq!("2nd Blanket A", <(u16, u32) as Kita<(i32,)>>::NAME); 169 | assert_eq!("2nd Blanket B", <(i16, i32) as Kita<(i32,)>>::NAME); 170 | } 171 | -------------------------------------------------------------------------------- /tests/recursive_call.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub enum GroupA {} 8 | impl Dispatch for Counted { 9 | type Group = GroupA; 10 | } 11 | impl Dispatch for Counted> { 12 | type Group = GroupA; 13 | } 14 | 15 | pub enum GroupB {} 16 | impl Dispatch for i32 { 17 | type Group = GroupB; 18 | } 19 | impl Dispatch for u32 { 20 | type Group = GroupB; 21 | } 22 | 23 | trait Counter { 24 | fn decrement(&mut self) -> u32; 25 | } 26 | 27 | struct Counted(u32, T); 28 | impl Counter for Counted { 29 | fn decrement(&mut self) -> u32 { 30 | self.0 = self.0.saturating_sub(1); 31 | self.0 32 | } 33 | } 34 | 35 | disjoint_impls! { 36 | pub trait Kita { 37 | type Item; 38 | 39 | fn kita(&mut self) -> Self::Item; 40 | } 41 | 42 | impl + Counter> Kita for T { 43 | type Item = u32; 44 | 45 | fn kita(&mut self) -> u32 { 46 | let _value = self.decrement(); 47 | let _value = Self::decrement(self); 48 | let value = T::decrement(self); 49 | 50 | if value == 0 { 51 | return 0; 52 | } 53 | 54 | // FIXME: Support this! 55 | //let _value = self.kita(); 56 | //let _value = Self::kita(self); 57 | //let value = T::kita(self); 58 | let _value = ::kita(self); 59 | let value = ::kita(self); 60 | 61 | value + 1 62 | } 63 | } 64 | impl + Default> Kita for U { 65 | type Item = U; 66 | 67 | fn kita(&mut self) -> Self::Item { 68 | ::default() 69 | } 70 | } 71 | 72 | impl> Kita for (T,) { 73 | type Item = u32; 74 | 75 | fn kita(&mut self) -> u32 { 76 | let a: Self::Item = ::kita(&mut 33); 77 | a 78 | } 79 | } 80 | impl + Default> Kita for (U,) { 81 | type Item = U; 82 | 83 | fn kita(&mut self) -> Self::Item { 84 | ::default() 85 | } 86 | } 87 | } 88 | 89 | /* 90 | pub trait Kita { 91 | type Item; 92 | fn kita(&mut self) -> Self::Item; 93 | } 94 | 95 | const _: () = { 96 | pub trait Kita0<_TŠČ0: ?Sized> { 97 | type Item; 98 | fn kita(&mut self) -> Self::Item; 99 | } 100 | impl + Counter> Kita0 for T { 101 | type Item = u32; 102 | fn kita(&mut self) -> u32 { 103 | let _value = self.decrement(); 104 | let _value = Self::decrement(self); 105 | let value = T::decrement(self); 106 | if value == 0 { 107 | return 0; 108 | } 109 | let _value = ::kita(self); 110 | let value = ::kita(self); 111 | value + 1 112 | } 113 | } 114 | impl + Default> Kita0 for U { 115 | type Item = U; 116 | fn kita(&mut self) -> Self::Item { 117 | ::default() 118 | } 119 | } 120 | 121 | pub trait Kita1<_TŠČ0: ?Sized> { 122 | type Item; 123 | fn kita(&mut self) -> Self::Item; 124 | } 125 | impl> Kita1 for (T,) { 126 | type Item = u32; 127 | fn kita(&mut self) -> u32 { 128 | let a: Self::Item = ::kita(&mut 33); 129 | a 130 | } 131 | } 132 | impl + Default> Kita1 for (U,) { 133 | type Item = U; 134 | fn kita(&mut self) -> Self::Item { 135 | ::default() 136 | } 137 | } 138 | 139 | impl<_TŠČ0> Kita for _TŠČ0 140 | where 141 | _TŠČ0: Dispatch, 142 | Self: Kita0<<_TŠČ0 as Dispatch>::Group>, 143 | { 144 | type Item = ::Group>>::Item; 145 | fn kita(&mut self) -> Self::Item { 146 | ::Group>>::kita(self) 147 | } 148 | } 149 | impl<_TŠČ0> Kita for (_TŠČ0,) 150 | where 151 | _TŠČ0: Dispatch, 152 | Self: Kita1<<_TŠČ0 as Dispatch>::Group>, 153 | { 154 | type Item = ::Group>>::Item; 155 | fn kita(&mut self) -> Self::Item { 156 | ::Group>>::kita(self) 157 | } 158 | } 159 | }; 160 | */ 161 | 162 | #[test] 163 | fn recursive_call() { 164 | assert_eq!(0, Counted::::kita(&mut Counted(2, "a".to_string()))); 165 | assert_eq!(1, Counted::>::kita(&mut Counted(12, vec![]))); 166 | assert_eq!(0, u32::kita(&mut 12)); 167 | assert_eq!(0, i32::kita(&mut 42)); 168 | } 169 | -------------------------------------------------------------------------------- /tests/dispatch_inherent_on_generic.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | trait A { 8 | type A; 9 | } 10 | 11 | impl A for u8 { 12 | type A = [u16; 1]; 13 | } 14 | impl A for i8 { 15 | type A = [i16; 2]; 16 | } 17 | 18 | impl Dispatch for String { 19 | type Group = (u32, u32); 20 | } 21 | impl Dispatch for Vec { 22 | type Group = (u32, String); 23 | } 24 | 25 | impl Dispatch for i32 { 26 | type Group = [(String, String); 1]; 27 | } 28 | impl Dispatch for u32 { 29 | type Group = [(String, u32); 1]; 30 | } 31 | 32 | impl Dispatch for u8 { 33 | type Group = (i8,); 34 | } 35 | impl Dispatch for i8 { 36 | type Group = (u8,); 37 | } 38 | 39 | struct Wrapper(T, U, V); 40 | 41 | disjoint_impls! { 42 | impl, U, V> Wrapper { 43 | fn kita(_a: (U,), _b: V) -> String { 44 | "Generic Blanket A".to_owned() 45 | } 46 | } 47 | impl, U: ToString, V> Wrapper { 48 | fn kita(_a: (V,), b: U) -> String { 49 | b.to_string() 50 | } 51 | } 52 | 53 | impl, U: A, Z: ToString> Wrapper { 54 | fn kara(_a: (U,), b: Z) -> String { 55 | b.to_string() 56 | } 57 | } 58 | impl, U: A, Z> Wrapper { 59 | fn kara(_a: (U,), _b: Z) -> String { 60 | "Generic Blanket B".to_owned() 61 | } 62 | } 63 | } 64 | 65 | /* 66 | const _: () = { 67 | pub trait Wrapper0<_TŠČ4: ?Sized, _TŠČ0, _TŠČ1, _TŠČ2, _TŠČ3> { 68 | fn kita(_a: (_TŠČ1,), _b: _TŠČ2) -> String; 69 | } 70 | impl, U, V> Wrapper0<(U, V), T, U, V, (U, V)> 71 | for Wrapper { 72 | fn kita(_a: (U,), _b: V) -> String { 73 | "Generic Blanket A".to_owned() 74 | } 75 | } 76 | impl< 77 | T: Dispatch, 78 | U: ToString, 79 | V, 80 | > Wrapper0<[(U, V); 1], T, V, U, [(U, V); 1]> for Wrapper { 81 | fn kita(_a: (V,), b: U) -> String { 82 | b.to_string() 83 | } 84 | } 85 | 86 | pub trait Wrapper1< 87 | _TŠČ4: ?Sized, 88 | _TŠČ5: ?Sized, 89 | _TŠČ0, 90 | _TŠČ1, 91 | _TŠČ2, 92 | const _CŠČ0: usize, 93 | > { 94 | fn kara(_a: (_TŠČ1,), b: _TŠČ2) -> String; 95 | } 96 | impl< 97 | T: Dispatch, 98 | U: A, 99 | Z: ToString, 100 | > Wrapper1<[Z; 1], (U,), T, U, Z, 1> for Wrapper { 101 | fn kara(_a: (U,), b: Z) -> String { 102 | b.to_string() 103 | } 104 | } 105 | impl< 106 | T: Dispatch, 107 | U: A, 108 | Z, 109 | > Wrapper1<[Z; 2], (U,), T, U, Z, 2> for Wrapper { 110 | fn kara(_a: (U,), _b: Z) -> String { 111 | "Generic Blanket B".to_owned() 112 | } 113 | } 114 | 115 | impl<_TŠČ0, _TŠČ1, _TŠČ2, _TŠČ3> Wrapper<_TŠČ0, (_TŠČ1,), _TŠČ2> 116 | where 117 | _TŠČ0: Dispatch, 118 | Self: Wrapper0<_TŠČ3, _TŠČ0, _TŠČ1, _TŠČ2, _TŠČ3>, 119 | { 120 | fn kita(_a: (_TŠČ1,), _b: _TŠČ2) -> String { 121 | >::kita(_a, _b) 122 | } 123 | } 124 | impl<_TŠČ0, _TŠČ1, _TŠČ2, const _CŠČ0: usize> Wrapper<_TŠČ0, u32, _TŠČ1> 125 | where 126 | _TŠČ1: A, 127 | _TŠČ0: Dispatch, 128 | Self: Wrapper1< 129 | [_TŠČ2; _CŠČ0], 130 | <_TŠČ0 as Dispatch>::Group, 131 | _TŠČ0, 132 | _TŠČ1, 133 | _TŠČ2, 134 | _CŠČ0, 135 | >, 136 | { 137 | fn kara(_a: (_TŠČ1,), b: _TŠČ2) -> String { 138 | ::Group, 141 | _TŠČ0, 142 | _TŠČ1, 143 | _TŠČ2, 144 | _CŠČ0, 145 | >>::kara(_a, b) 146 | } 147 | } 148 | }; 149 | */ 150 | 151 | #[test] 152 | fn dispatch_inherent_on_generic() { 153 | let a_arg1 = 42; 154 | let a_arg2 = 420; 155 | 156 | let b_arg2 = "moja".to_owned(); 157 | let b_arg3 = "kita".to_owned(); 158 | 159 | assert_eq!( 160 | "Generic Blanket A", 161 | Wrapper::::kita((a_arg1,), a_arg2) 162 | ); 163 | assert_eq!( 164 | "Generic Blanket A", 165 | Wrapper::, (u32,), String>::kita((a_arg1,), b_arg2) 166 | ); 167 | assert_eq!( 168 | "kita", 169 | Wrapper::::kita((a_arg1,), b_arg3) 170 | ); 171 | 172 | assert_eq!( 173 | "Generic Blanket B", 174 | Wrapper::::kara((42_i8,), 42_i16) 175 | ); 176 | assert_eq!("420", Wrapper::::kara((42_u8,), 420_u16)); 177 | } 178 | -------------------------------------------------------------------------------- /tests/ui_fail/unsized.stderr: -------------------------------------------------------------------------------- 1 | error[E0277]: the trait bound `str: Kita` is not satisfied 2 | --> tests/ui_fail/unsized.rs:42:30 3 | | 4 | 42 | assert_eq!("Blanket A", >::kita(&"")); 5 | | ^^^ the trait `Sized` is not implemented for `str` 6 | | 7 | note: required for `str` to implement `Kita0` 8 | --> tests/ui_fail/unsized.rs:28:53 9 | | 10 | 28 | impl, U: ?Sized, V> Kita for T { 11 | | _____________________________________________________^ 12 | 29 | | fn kita(&self) -> String { 13 | 30 | | "Blanket A".to_owned() 14 | ... | 15 | 34 | | impl + ?Sized, U, V> Kita for T { 16 | | | - ^ ^ 17 | | |________________________________________________|______________| 18 | | | 19 | | unsatisfied trait bound introduced here 20 | note: required for `str` to implement `Kita` 21 | --> tests/ui_fail/unsized.rs:23:1 22 | | 23 | 23 | / disjoint_impls! { 24 | 24 | | pub trait Kita { 25 | 25 | | fn kita(&self) -> String; 26 | ... | 27 | 28 | | impl, U: ?Sized, V> Kita for T { 28 | | | ^^^^^^^^^^ 29 | ... | 30 | 39 | | } 31 | | |_^ 32 | = note: this error originates in the macro `disjoint_impls` (in Nightly builds, run with -Z macro-backtrace for more info) 33 | 34 | error[E0277]: the size for values of type `str` cannot be known at compilation time 35 | --> tests/ui_fail/unsized.rs:43:30 36 | | 37 | 43 | assert_eq!("Blanket A", as Kita>::kita(&Vec::new())); 38 | | ^^^^^^^ doesn't have a size known at compile-time 39 | | 40 | = help: the trait `Sized` is not implemented for `str` 41 | note: required for `Vec` to implement `Kita` 42 | --> tests/ui_fail/unsized.rs:23:1 43 | | 44 | 23 | / disjoint_impls! { 45 | 24 | | pub trait Kita { 46 | 25 | | fn kita(&self) -> String; 47 | ... | 48 | 28 | | impl, U: ?Sized, V> Kita for T { 49 | | | ^^^^^^^^^^ 50 | ... | 51 | 39 | | } 52 | | |_^ 53 | = note: this error originates in the macro `disjoint_impls` (in Nightly builds, run with -Z macro-backtrace for more info) 54 | 55 | error[E0277]: the trait bound `str: Kita` is not satisfied 56 | --> tests/ui_fail/unsized.rs:44:30 57 | | 58 | 44 | assert_eq!("Blanket B", >::kita(&"")); 59 | | ^^^ the trait `Sized` is not implemented for `str` 60 | | 61 | note: required for `str` to implement `Kita` 62 | --> tests/ui_fail/unsized.rs:23:1 63 | | 64 | 23 | / disjoint_impls! { 65 | 24 | | pub trait Kita { 66 | 25 | | fn kita(&self) -> String; 67 | ... | 68 | 28 | | impl, U: ?Sized, V> Kita for T { 69 | | | ^^^^^^^^^^ 70 | ... | 71 | 39 | | } 72 | | |_^ 73 | = note: this error originates in the macro `disjoint_impls` (in Nightly builds, run with -Z macro-backtrace for more info) 74 | 75 | error[E0277]: the size for values of type `str` cannot be known at compilation time 76 | --> tests/ui_fail/unsized.rs:45:30 77 | | 78 | 45 | assert_eq!("Blanket B", <[u8] as Kita>::kita(&[])); 79 | | ^^^^ doesn't have a size known at compile-time 80 | | 81 | = help: the trait `Sized` is not implemented for `str` 82 | note: required for `[u8]` to implement `Kita0` 83 | --> tests/ui_fail/unsized.rs:28:53 84 | | 85 | 28 | impl, U: ?Sized, V> Kita for T { 86 | | _____________________________________________________^ 87 | 29 | | fn kita(&self) -> String { 88 | 30 | | "Blanket A".to_owned() 89 | ... | 90 | 34 | | impl + ?Sized, U, V> Kita for T { 91 | | | - ^ ^ 92 | | |________________________________________________|______________| 93 | | | 94 | | unsatisfied trait bound introduced here 95 | note: required for `[u8]` to implement `Kita` 96 | --> tests/ui_fail/unsized.rs:23:1 97 | | 98 | 23 | / disjoint_impls! { 99 | 24 | | pub trait Kita { 100 | 25 | | fn kita(&self) -> String; 101 | ... | 102 | 28 | | impl, U: ?Sized, V> Kita for T { 103 | | | ^^^^^^^^^^ 104 | ... | 105 | 39 | | } 106 | | |_^ 107 | = note: this error originates in the macro `disjoint_impls` (in Nightly builds, run with -Z macro-backtrace for more info) 108 | -------------------------------------------------------------------------------- /tests/unconstrained_params.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub trait Tr { 8 | type A; 9 | } 10 | 11 | pub enum GroupA {} 12 | impl Dispatch for String { 13 | type Group = GroupA; 14 | } 15 | impl Tr for String { 16 | type A = [(Self,); 1]; 17 | } 18 | impl Dispatch for (String,) { 19 | type Group = [GroupA; 1]; 20 | } 21 | 22 | impl Dispatch for Vec { 23 | type Group = GroupA; 24 | } 25 | impl Tr for Vec { 26 | type A = [(Self,); 1]; 27 | } 28 | impl Dispatch for (Vec,) { 29 | type Group = [u32; 2]; 30 | } 31 | 32 | pub enum GroupB {} 33 | impl Tr for i32 { 34 | type A = [i16; 2]; 35 | } 36 | impl Dispatch for i32 { 37 | type Group = GroupB; 38 | } 39 | impl Tr for u32 { 40 | type A = [i16; 2]; 41 | } 42 | impl Dispatch for u32 { 43 | type Group = GroupB; 44 | } 45 | impl Dispatch for i16 { 46 | type Group = GroupB; 47 | } 48 | 49 | disjoint_impls! { 50 | pub trait Kita { 51 | const NAME: &'static str; 52 | } 53 | 54 | impl, A: Dispatch, Z> Kita for T 55 | where 56 | Self: Tr, 57 | { 58 | const NAME: &'static str = "1st Blanket AA"; 59 | } 60 | impl + Tr, A: Dispatch, Z> Kita for T { 61 | const NAME: &'static str = "1st Blanket AB"; 62 | } 63 | impl + Tr, A: Dispatch> Kita for T { 64 | const NAME: &'static str = "1st Blanket B*"; 65 | } 66 | 67 | impl + Tr, A: Dispatch> Kita for [T; 1] { 68 | const NAME: &'static str = "2nd Blanket AA"; 69 | } 70 | impl + Tr, A: Dispatch> Kita for [T; 1] { 71 | const NAME: &'static str = "2nd Blanket AB"; 72 | } 73 | impl + Tr, A: Dispatch> Kita for [T; 1] { 74 | const NAME: &'static str = "2nd Blanket B*"; 75 | } 76 | } 77 | 78 | /* 79 | pub trait Kita { 80 | const NAME: &'static str; 81 | } 82 | #[allow(clippy::needless_lifetimes)] 83 | const _: () = { 84 | pub trait Kita0<_TŠČ0: ?Sized, _TŠČ1: ?Sized, _TŠČ2: ?Sized> { 85 | const NAME: &'static str; 86 | } 87 | impl< 88 | T: Dispatch, 89 | A: Dispatch, 90 | Z, 91 | > Kita0 for T 92 | where 93 | T: Tr, 94 | { 95 | const NAME: &'static str = "1st Blanket AA"; 96 | } 97 | impl< 98 | T: Dispatch + Tr, 99 | A: Dispatch, 100 | Z, 101 | > Kita0 for T { 102 | const NAME: &'static str = "1st Blanket AB"; 103 | } 104 | impl< 105 | T: Dispatch + Tr, 106 | A: Dispatch, 107 | > Kita0::Group> for T { 108 | const NAME: &'static str = "1st Blanket B*"; 109 | } 110 | 111 | pub trait Kita1<_TŠČ0: ?Sized, _TŠČ1: ?Sized, _TŠČ2: ?Sized> { 112 | const NAME: &'static str; 113 | } 114 | impl< 115 | T: Dispatch + Tr, 116 | A: Dispatch, 117 | > Kita1 for [T; 1] { 118 | const NAME: &'static str = "2nd Blanket AA"; 119 | } 120 | impl< 121 | T: Dispatch + Tr, 122 | A: Dispatch, 123 | > Kita1 for [T; 1] { 124 | const NAME: &'static str = "2nd Blanket AB"; 125 | } 126 | impl< 127 | T: Dispatch + Tr, 128 | A: Dispatch, 129 | > Kita1::Group> for [T; 1] { 130 | const NAME: &'static str = "2nd Blanket B*"; 131 | } 132 | 133 | impl<_TŠČ0, _TŠČ2, const _CŠČ0: usize> Kita for _TŠČ0 134 | where 135 | _TŠČ0: Dispatch, 136 | _TŠČ0: Tr, 137 | _TŠČ2: Dispatch, 138 | Self: Kita0< 139 | <_TŠČ0 as Dispatch>::Group, 140 | [_TŠČ2; _CŠČ0], 141 | <_TŠČ2 as Dispatch>::Group, 142 | >, 143 | { 144 | const NAME: &'static str = ::Group, 146 | [_TŠČ2; _CŠČ0], 147 | <_TŠČ2 as Dispatch>::Group, 148 | >>::NAME; 149 | } 150 | impl<_TŠČ0, _TŠČ2, const _CŠČ0: usize> Kita for [_TŠČ0; 1] 151 | where 152 | _TŠČ0: Dispatch, 153 | _TŠČ0: Tr, 154 | _TŠČ2: Dispatch, 155 | Self: Kita1< 156 | <_TŠČ0 as Dispatch>::Group, 157 | [_TŠČ2; _CŠČ0], 158 | <_TŠČ2 as Dispatch>::Group, 159 | >, 160 | { 161 | const NAME: &'static str = ::Group, 163 | [_TŠČ2; _CŠČ0], 164 | <_TŠČ2 as Dispatch>::Group, 165 | >>::NAME; 166 | } 167 | }; 168 | */ 169 | 170 | #[test] 171 | fn unconstrained_params() { 172 | assert_eq!("1st Blanket AA", String::NAME); 173 | assert_eq!("1st Blanket AB", Vec::::NAME); 174 | assert_eq!("1st Blanket B*", u32::NAME); 175 | assert_eq!("1st Blanket B*", i32::NAME); 176 | 177 | assert_eq!("2nd Blanket B*", <[u32; 1]>::NAME); 178 | assert_eq!("2nd Blanket B*", <[i32; 1]>::NAME); 179 | } 180 | -------------------------------------------------------------------------------- /tests/disjoint_inherent_impl.rs: -------------------------------------------------------------------------------- 1 | use disjoint_impls::disjoint_impls; 2 | 3 | pub trait Dispatch { 4 | type Group; 5 | } 6 | 7 | pub trait A {} 8 | pub trait B {} 9 | 10 | pub enum GroupA {} 11 | impl A for String {} 12 | impl Dispatch for String { 13 | type Group = GroupA; 14 | } 15 | impl A for Vec {} 16 | impl Dispatch for Vec { 17 | type Group = GroupA; 18 | } 19 | 20 | pub enum GroupB {} 21 | impl B for i32 {} 22 | impl Dispatch for i32 { 23 | type Group = GroupB; 24 | } 25 | impl B for u32 {} 26 | impl Dispatch for u32 { 27 | type Group = GroupB; 28 | } 29 | 30 | pub struct Wrapper<'a, T, const N: usize>(pub &'a T); 31 | 32 | disjoint_impls! { 33 | impl<'a, T: A, U> Wrapper<'a, (T, U), 12> 34 | where 35 | T: Dispatch + Dispatch, 36 | { 37 | pub const NAME: &'static str = "1st Blanket A"; 38 | 39 | fn kita(_a: T, _b: U) -> &'static str 40 | where 41 | T: 'a, 42 | U: 'a, 43 | { 44 | Self::NAME 45 | } 46 | } 47 | impl<'b, T, U> Wrapper<'b, (T, U), 12> 48 | where 49 | T: Dispatch + Dispatch + B, 50 | { 51 | pub const NAME: &'static str = "1st Blanket B"; 52 | 53 | fn kita(_a: T, _b: U) -> &'static str 54 | where 55 | T: 'b, 56 | U: 'b, 57 | { 58 | Self::NAME 59 | } 60 | } 61 | 62 | impl<'c, T: Dispatch + Dispatch> Wrapper<'c, T, 14> { 63 | pub const NAME: &'static str = "2nd Blanket A"; 64 | } 65 | impl<'c, T: Dispatch + Dispatch> Wrapper<'c, T, 14> { 66 | pub const NAME: &'static str = "2nd Blanket B"; 67 | } 68 | } 69 | 70 | /* 71 | const _: () = { 72 | pub trait Wrapper0<'_lšč0, _TŠČ4: ?Sized, _TŠČ0, _TŠČ1, _TŠČ2> { 73 | const NAME: &'static str; 74 | fn kita(_a: _TŠČ0, _b: _TŠČ1) -> &'static str 75 | where 76 | _TŠČ0: '_lšč0, 77 | _TŠČ1: '_lšč0; 78 | } 79 | impl<'a, T: A, U> Wrapper0<'a, GroupA, T, U, GroupA> for Wrapper<'a, (T, U), 12> 80 | where 81 | T: Dispatch + Dispatch, 82 | { 83 | const NAME: &'static str = "1st Blanket A"; 84 | fn kita(_a: T, _b: U) -> &'static str 85 | where 86 | T: 'a, 87 | U: 'a, 88 | { 89 | Self::NAME 90 | } 91 | } 92 | impl<'b, T, U> Wrapper0<'b, GroupB, T, U, GroupB> for Wrapper<'b, (T, U), 12> 93 | where 94 | T: Dispatch + Dispatch + B, 95 | { 96 | const NAME: &'static str = "1st Blanket B"; 97 | fn kita(_a: T, _b: U) -> &'static str 98 | where 99 | T: 'b, 100 | U: 'b, 101 | { 102 | Self::NAME 103 | } 104 | } 105 | 106 | pub trait Wrapper1<'_lšč0, _TŠČ3: ?Sized, _TŠČ0, _TŠČ1> { 107 | const NAME: &'static str; 108 | } 109 | impl< 110 | 'c, 111 | T: Dispatch + Dispatch, 112 | > Wrapper1<'c, GroupA, T, GroupA> for Wrapper<'c, T, 14> { 113 | const NAME: &'static str = "2nd Blanket A"; 114 | } 115 | impl< 116 | 'c, 117 | T: Dispatch + Dispatch, 118 | > Wrapper1<'c, GroupB, T, GroupB> for Wrapper<'c, T, 14> { 119 | const NAME: &'static str = "2nd Blanket B"; 120 | } 121 | 122 | impl<'_lšč0, _TŠČ0, _TŠČ1, _TŠČ2> Wrapper<'_lšč0, (_TŠČ0, _TŠČ1), 12> 123 | where 124 | _TŠČ0: Dispatch, 125 | Self: Wrapper0<'_lšč0, _TŠČ2, _TŠČ0, _TŠČ1, _TŠČ2>, 126 | { 127 | fn kita(_a: _TŠČ0, _b: _TŠČ1) -> &'static str 128 | where 129 | _TŠČ0: '_lšč0, 130 | _TŠČ1: '_lšč0, 131 | { 132 | >::kita(_a, _b) 139 | } 140 | const NAME: &'static str = >::NAME; 147 | } 148 | impl<'_lšč0, _TŠČ0, _TŠČ1> Wrapper<'_lšč0, _TŠČ0, 14> 149 | where 150 | _TŠČ0: Dispatch, 151 | Self: Wrapper1<'_lšč0, _TŠČ1, _TŠČ0, _TŠČ1>, 152 | { 153 | const NAME: &'static str = >::NAME; 159 | } 160 | }; 161 | */ 162 | 163 | #[test] 164 | fn disjoint_inherent_impl() { 165 | assert_eq!("1st Blanket A", >::NAME); 166 | assert_eq!("1st Blanket A", , u32), 12>>::NAME); 167 | assert_eq!("1st Blanket B", >::NAME); 168 | assert_eq!("1st Blanket B", >::NAME); 169 | 170 | assert_eq!("2nd Blanket A", >::NAME); 171 | assert_eq!("2nd Blanket A", , 14>>::NAME); 172 | assert_eq!("2nd Blanket B", >::NAME); 173 | assert_eq!("2nd Blanket B", >::NAME); 174 | 175 | assert_eq!( 176 | "1st Blanket A", 177 | >::kita(String::new(), 12) 178 | ); 179 | assert_eq!( 180 | "1st Blanket A", 181 | , u32), 12>>::kita(vec![], 12) 182 | ); 183 | assert_eq!("1st Blanket B", >::kita(12, 12)); 184 | assert_eq!("1st Blanket B", >::kita(12, 12)); 185 | } 186 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [1.3.4] - 2025-12-04 11 | ### Fixed 12 | - derivative generic types are not fundamental 13 | 14 | ## [1.3.3] - 2025-11-27 15 | ### Fixed 16 | - consider fully qualified generic params as generic params 17 | 18 | ## [1.3.2] - 2025-11-26 19 | ### Fixed 20 | - separate disjoint subgroups eagerly 21 | 22 | ## [1.3.1] - 2025-11-25 23 | ### Fixed 24 | - forbid non-qualified associated types 25 | 26 | ## [1.3.0] - 2025-11-24 27 | ### Added 28 | - support constraints in generic arguments 29 | - dispatch overlapping nested subgroups 30 | 31 | ### Fixed 32 | - use fundametal types to determine type disjointness 33 | - generalize elided lifetimes on function arguments 34 | 35 | ## [1.2.3] - 2025-11-05 36 | ### Fixed 37 | - dispatch on all possible trait combinations 38 | - separate disjoint impls eagerly 39 | 40 | ## [1.2.2] - 2025-11-04 41 | ### Fixed 42 | - generalize impl signatures, don't look for supersets 43 | 44 | ## [1.2.1] - 2025-10-17 45 | ### Added 46 | - support GATs 47 | 48 | ## [1.2.0] - 2025-10-13 49 | ### Fixed 50 | - require that at least one solution always exists even if overlapping 51 | - on intersection check if impl has generalization with the group 52 | 53 | ## [1.1.3] - 2025-10-07 54 | ### Fixed 55 | - silence `clippy::needless_lifetimes` lint 56 | 57 | ## [1.1.2] - 2025-10-07 58 | ### Changed 59 | - don't use unconstrained type parameters in associated bindings 60 | 61 | ## [1.1.1] - 2025-10-06 62 | ### Fixed 63 | - make all impls present in the output 64 | 65 | ## [1.1.0] - 2025-10-05 66 | 67 | ### Fixed 68 | - handle overlapping payloads when forming an impl group 69 | 70 | ### Changed 71 | - new impl resolution mechanism 72 | 73 | ### Removed 74 | - disallow unspecified default trait arguments 75 | 76 | ## [1.0.9] - 2025-09-09 77 | 78 | ### Added 79 | - support for foreign/remote traits 80 | - support for unsafe methods and traits 81 | 82 | ### Fixed 83 | - correctly name elided lifetimes 84 | 85 | ### Changed 86 | - move ambiguous associated param check to validation step 87 | 88 | ## [1.0.8] - 2025-08-30 89 | 90 | ### Added 91 | - handle elided lifetimes 92 | - enable dispatching on associated types 93 | 94 | ### Fixed 95 | - allow overlapping assoc bindings 96 | - compare item ids when checking for assoc bindings overlap 97 | 98 | ### Changed 99 | - simplify implementation for finding overlapping impls 100 | - simplify impl group id topsort implementation 101 | 102 | ## [1.0.7] - 2025-08-24 103 | 104 | ### Added 105 | - support dispatching on associated type 106 | 107 | ### Fixed 108 | - properly rename generic arguments in impl trait path 109 | 110 | ## [1.0.6] - 2025-08-24 111 | 112 | ### Fixed 113 | - properly define main trait generics 114 | - don't consider associated bounds on concrete types 115 | 116 | ### Changed 117 | - simplify tracking of associated binding groups 118 | - implementation of wrapper types (most notably of `TraitBound`) 119 | - rename assoc bound to assoc binding 120 | - optimize algorithm for finding impl groups 121 | 122 | ## [1.0.5] - 2025-08-12 123 | 124 | ### Added 125 | - Add support for associated type bounds 126 | 127 | ## [1.0.4] - 2025-08-11 128 | 129 | ### Added 130 | - Add compile tests 131 | - Implement support for params only constrained by other params 132 | 133 | ### Fixed 134 | - Properly resolve main trait bounded default params 135 | - Add param bounds for complex predicates to main trait impl 136 | - Properly index parameters 137 | 138 | ### Changed 139 | - Let single impls pass through without a helper trait 140 | 141 | ### Removed 142 | - Remove main trait assoc bounds from assoc bounds group for dispatch 143 | 144 | ## [1.0.3] - 2025-06-28 145 | 146 | ### Added 147 | - Support non-overlapping blanket impls 148 | 149 | ## [1.0.2] - 2025-06-25 150 | 151 | ### Fixed 152 | - Correctly serialize TraitBound to tokens 153 | 154 | ## [1.0.1] - 2025-06-25 155 | 156 | ### Fixed 157 | - Support single blanket impl 158 | 159 | ## [1.0.0] - 2025-03-24 160 | 161 | ### Added 162 | - Stabilized API 163 | 164 | 165 | ## [0.8.0] - 2024-09-18 166 | 167 | ### Added 168 | - Implement Substitute for every type in syn 169 | - Implement Superset for every type in syn 170 | - Add support for overlapping impl groups 171 | - Add support for dispatch on generic type 172 | - Add support for complex generic argument types 173 | 174 | ### Fixed 175 | - Add ?Sized bound on main trait params 176 | 177 | ### Changed 178 | - transition to using IndexMap instead of FxHashMap 179 | 180 | ## [0.7.1] - 2024-05-20 181 | 182 | ### Fixed 183 | - Add ?Sized bound to main trait type parameters 184 | 185 | ## [0.7.0] - 2024-01-23 186 | 187 | ### Added 188 | - Predictable ordering of generic arguments 189 | 190 | ### Fixed 191 | - Fix inherent impls parametrization 192 | - Fix for const parameters in inherent impls 193 | 194 | ### Changed 195 | - Only dispatch on assoc bounds that are present in all impls 196 | 197 | ## [0.6.0] - 2024-01-08 198 | 199 | ### Added 200 | - Support bounds for main trait parameters 201 | - Support const parameters in main trait 202 | - Support default generic types in main trait 203 | - Support multiple blanket impls on different trait generics 204 | - Support for resolution of parameters not bounded by trait or self type 205 | 206 | ### Fixed 207 | - Fix generation of main trait generics 208 | 209 | ### Changed 210 | - Keep original trait param identifiers 211 | 212 | ## [0.5.0] - 2023-11-23 213 | 214 | ### Added 215 | - Support multiple blanket impls on a different self type 216 | 217 | ## [0.4.0] - 2023-11-20 218 | 219 | ### Added 220 | - Add support for lifetimes in trait definition 221 | 222 | ## [0.3.0] - 2023-10-08 223 | 224 | ### Added 225 | - Add input validation 226 | - Add support for dispatch on unsized types 227 | 228 | ## [0.2.0] - 2023-09-24 229 | 230 | ### Added 231 | - Enable dispatch on where clause bounded type 232 | 233 | ### Changed 234 | - Don't require collection of type param identifiers to be ordered 235 | 236 | ## [0.1.0] - 2023-09-23 237 | -------------------------------------------------------------------------------- /src/normalize.rs: -------------------------------------------------------------------------------- 1 | //! Contains logic for normalizing impls 2 | 3 | use indexmap::IndexMap; 4 | use proc_macro2::Span; 5 | 6 | use quote::format_ident; 7 | use syn::{ 8 | Token, parse_quote, 9 | punctuated::Punctuated, 10 | visit_mut::{VisitMut, visit_trait_bound_mut}, 11 | }; 12 | 13 | struct ElidedLifetimeNamer { 14 | curr_elided_lifetime_idx: usize, 15 | } 16 | 17 | struct SelfReplacer<'a> { 18 | self_ty: &'a syn::Type, 19 | } 20 | 21 | struct ConstraintReplacer { 22 | curr_bounded_ty: Option, 23 | curr_trait_bound: Option, 24 | bounds: IndexMap< 25 | (syn::Type, syn::TraitBound, syn::Ident), 26 | Punctuated, 27 | >, 28 | } 29 | 30 | impl ConstraintReplacer { 31 | fn new() -> Self { 32 | Self { 33 | curr_bounded_ty: None, 34 | curr_trait_bound: None, 35 | bounds: IndexMap::new(), 36 | } 37 | } 38 | } 39 | 40 | impl VisitMut for ElidedLifetimeNamer { 41 | fn visit_lifetime_mut(&mut self, node: &mut syn::Lifetime) { 42 | if node.ident == "_" { 43 | let idx = self.curr_elided_lifetime_idx; 44 | node.ident = format_ident!("_lšč{idx}"); 45 | self.curr_elided_lifetime_idx += 1; 46 | } 47 | } 48 | fn visit_type_reference_mut(&mut self, node: &mut syn::TypeReference) { 49 | if node.lifetime.is_none() { 50 | node.lifetime = parse_quote!('_); 51 | } 52 | 53 | syn::visit_mut::visit_type_reference_mut(self, node); 54 | } 55 | } 56 | 57 | impl VisitMut for SelfReplacer<'_> { 58 | fn visit_type_mut(&mut self, node: &mut syn::Type) { 59 | if let syn::Type::Path(ty) = node { 60 | let first_seg = &ty.path.segments.first().unwrap(); 61 | 62 | if first_seg.ident == "Self" { 63 | *node = replace_path(&ty.path, self.self_ty); 64 | } 65 | } 66 | 67 | syn::visit_mut::visit_type_mut(self, node); 68 | } 69 | } 70 | 71 | impl VisitMut for ConstraintReplacer { 72 | fn visit_type_param_mut(&mut self, node: &mut syn::TypeParam) { 73 | let ident = &node.ident; 74 | 75 | self.curr_bounded_ty = Some(parse_quote!(#ident)); 76 | syn::visit_mut::visit_type_param_mut(self, node); 77 | 78 | self.curr_bounded_ty = None; 79 | } 80 | 81 | fn visit_predicate_type_mut(&mut self, node: &mut syn::PredicateType) { 82 | self.curr_bounded_ty = Some(node.bounded_ty.clone()); 83 | syn::visit_mut::visit_predicate_type_mut(self, node); 84 | 85 | self.curr_bounded_ty = None; 86 | } 87 | 88 | fn visit_trait_bound_mut(&mut self, node: &mut syn::TraitBound) { 89 | self.curr_trait_bound = Some(node.clone()); 90 | visit_trait_bound_mut(self, node); 91 | } 92 | 93 | fn visit_angle_bracketed_generic_arguments_mut( 94 | &mut self, 95 | node: &mut syn::AngleBracketedGenericArguments, 96 | ) { 97 | node.args.iter_mut().for_each(|arg| match arg { 98 | syn::GenericArgument::Constraint(constraint) => { 99 | let ty_idx = self.bounds.len(); 100 | 101 | let ident = constraint.ident.clone(); 102 | let generics = constraint.generics.clone(); 103 | 104 | let current_bounded_ty = self.curr_bounded_ty.take().unwrap(); 105 | let current_trait_bound = self.curr_trait_bound.take().unwrap(); 106 | 107 | let key = ( 108 | current_bounded_ty.clone(), 109 | current_trait_bound.clone(), 110 | ident.clone(), 111 | ); 112 | 113 | let ty = format_ident!("_TŠČ{}", ty_idx); 114 | let ty: syn::Type = parse_quote! { #ty }; 115 | self.curr_bounded_ty = Some(ty.clone()); 116 | 117 | self.bounds.entry(key.clone()).or_default(); 118 | for constraint_bound in &mut constraint.bounds { 119 | syn::visit_mut::visit_type_param_bound_mut(self, constraint_bound); 120 | } 121 | 122 | let bounds = constraint.bounds.clone(); 123 | *arg = syn::GenericArgument::AssocType(syn::AssocType { 124 | ident, 125 | generics, 126 | eq_token: parse_quote!(=), 127 | ty, 128 | }); 129 | 130 | self.curr_bounded_ty = Some(current_bounded_ty); 131 | self.curr_trait_bound = Some(current_trait_bound); 132 | 133 | self.bounds.insert(key, bounds); 134 | } 135 | _ => syn::visit_mut::visit_generic_argument_mut(self, arg), 136 | }); 137 | } 138 | } 139 | 140 | /// Normalizes an impl in the following ways: 141 | /// 142 | /// * Replace all occurrences of `Self` with concrete `self_ty` 143 | /// * Uniquely name all elided lifetimes as `_lšč{idx}` 144 | pub fn normalize(mut item_impl: syn::ItemImpl) -> syn::ItemImpl { 145 | let mut elided_lifetime_namer = ElidedLifetimeNamer { 146 | curr_elided_lifetime_idx: 0, 147 | }; 148 | if let Some((_, trait_, _)) = &mut item_impl.trait_ { 149 | elided_lifetime_namer.visit_path_mut(trait_); 150 | } 151 | elided_lifetime_namer.visit_type_mut(&mut item_impl.self_ty); 152 | elided_lifetime_namer.visit_generics_mut(&mut item_impl.generics); 153 | 154 | let mut self_replacer = SelfReplacer { 155 | self_ty: &item_impl.self_ty, 156 | }; 157 | if let Some((_, trait_, _)) = &mut item_impl.trait_ { 158 | self_replacer.visit_path_mut(trait_); 159 | } 160 | self_replacer.visit_generics_mut(&mut item_impl.generics); 161 | 162 | let mut constraint_replacer = ConstraintReplacer::new(); 163 | constraint_replacer.visit_item_impl_mut(&mut item_impl); 164 | 165 | item_impl.generics.params.extend( 166 | constraint_replacer 167 | .bounds 168 | .into_values() 169 | .enumerate() 170 | .map::(|(idx, bounds)| { 171 | let ty = format_ident!("_TŠČ{}", idx); 172 | parse_quote! { #ty: #bounds } 173 | }), 174 | ); 175 | 176 | item_impl 177 | .generics 178 | .params 179 | .extend( 180 | (0..elided_lifetime_namer.curr_elided_lifetime_idx).map(|idx| { 181 | syn::GenericParam::from(syn::LifetimeParam::new(syn::Lifetime::new( 182 | &format!("'_lšč{idx}"), 183 | Span::call_site(), 184 | ))) 185 | }), 186 | ); 187 | 188 | item_impl 189 | } 190 | 191 | pub fn replace_path(ty: &syn::Path, replacement: &syn::Type) -> syn::Type { 192 | let segments = ty.segments.iter().skip(1); 193 | 194 | if segments.len() > 0 { 195 | return parse_quote!(<#replacement> #(::#segments)*); 196 | } 197 | 198 | parse_quote!(#replacement) 199 | } 200 | 201 | #[cfg(test)] 202 | mod tests { 203 | use super::*; 204 | 205 | #[test] 206 | fn nested_assoc_constraints() { 207 | let item_impl: syn::ItemImpl = parse_quote! { 208 | impl>>> Kita for T {} 209 | }; 210 | let expected: syn::ItemImpl = parse_quote! { 211 | impl< 212 | T: Dispatch, 213 | _TŠČ0: Dispatch, 214 | _TŠČ1: Dispatch 215 | > Kita for T {} 216 | }; 217 | 218 | let res = normalize(item_impl); 219 | assert_eq!(expected, res); 220 | } 221 | } 222 | -------------------------------------------------------------------------------- /src/validate.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | struct Validator<'a>(IndexSet<&'a syn::Ident>); 4 | 5 | impl<'a> Validator<'a> { 6 | fn new(generics: &'a syn::Generics) -> Self { 7 | Self(generics.type_params().map(|param| ¶m.ident).collect()) 8 | } 9 | } 10 | 11 | impl Visit<'_> for Validator<'_> { 12 | fn visit_type_path(&mut self, node: &syn::TypePath) { 13 | let mut segments = node.path.segments.iter(); 14 | syn::visit::visit_type_path(self, node); 15 | 16 | let first = match &node.qself { 17 | None if node.path.segments.len() > 1 => { 18 | let first = &segments.next().unwrap().ident; 19 | 20 | if !self.0.contains(&first) { 21 | return; 22 | } 23 | 24 | parse_quote!(#first) 25 | } 26 | Some(syn::QSelf { ty, position, .. }) if *position == 0 => (*ty).clone(), 27 | _ => { 28 | return; 29 | } 30 | }; 31 | 32 | let abort_msg = format!( 33 | "Ambiguous associated type. Qualify with a trait to disambiguate (e.g. {})", 34 | quote::quote!(<#first as Trait>#(::#segments)*) 35 | ); 36 | 37 | abort!(node, abort_msg); 38 | } 39 | 40 | fn visit_type_impl_trait(&mut self, node: &syn::TypeImplTrait) { 41 | abort!(node, "`impl Trait` is not allowed in this position"); 42 | } 43 | 44 | fn visit_impl_item(&mut self, _: &syn::ImplItem) {} 45 | } 46 | 47 | pub fn validate_impl_syntax(item_impl: &ItemImpl) { 48 | Validator::new(&item_impl.generics).visit_item_impl(item_impl); 49 | } 50 | 51 | pub fn validate_trait_impls<'a, I: IntoIterator>( 52 | trait_: &ItemTrait, 53 | item_impls: I, 54 | ) where 55 | I::IntoIter: Clone, 56 | { 57 | let item_impls = item_impls.into_iter(); 58 | let nparams = trait_.generics.params.len(); 59 | 60 | for item_impl in item_impls.clone() { 61 | if let Some((_, trait_path, _)) = &item_impl.trait_ { 62 | let last_seg = trait_path.segments.last().unwrap(); 63 | 64 | match &last_seg.arguments { 65 | syn::PathArguments::AngleBracketed(bracketed) 66 | if bracketed.args.len() == nparams => {} 67 | syn::PathArguments::None if nparams == 0 => {} 68 | _ => abort!(last_seg, "Specify all trait arguments (including default)"), 69 | } 70 | 71 | if trait_.ident != last_seg.ident { 72 | abort!(last_seg.ident, "Doesn't match trait definition"); 73 | } 74 | } else { 75 | abort!(item_impl, "Expected trait impl, found inherent impl"); 76 | } 77 | 78 | match (trait_.unsafety, item_impl.unsafety) { 79 | (Some(_), Some(_)) | (None, None) => {} 80 | (Some(unsafety), None) => { 81 | abort!(unsafety, "Missing in one of the impls"); 82 | } 83 | (None, Some(unsafety)) => { 84 | abort!(unsafety, "Doesn't match trait definition"); 85 | } 86 | } 87 | } 88 | for impl_items in item_impls.map(|item_impl| &item_impl.items) { 89 | compare_trait_items(&trait_.items, impl_items); 90 | } 91 | } 92 | 93 | pub fn validate_inherent_impls<'a, I: IntoIterator>(item_impls: I) 94 | where 95 | I::IntoIter: Clone, 96 | { 97 | let item_impls = item_impls.into_iter(); 98 | 99 | for item_impl in item_impls.clone() { 100 | if let Some((_, item_impl_trait, _)) = &item_impl.trait_ { 101 | abort!(item_impl_trait, "Expected inherent impl but found trait"); 102 | } 103 | } 104 | 105 | let mut impl_items = item_impls.map(|item_impl| &item_impl.items); 106 | if let Some(first_items) = impl_items.next() { 107 | for second_items in impl_items { 108 | compare_inherent_items(first_items, second_items); 109 | } 110 | } 111 | } 112 | 113 | fn compare_trait_items(trait_items: &[syn::TraitItem], second: &[syn::ImplItem]) { 114 | let mut second_consts = IndexMap::new(); 115 | let mut second_types = IndexMap::new(); 116 | let mut second_fns = IndexMap::new(); 117 | 118 | second.iter().for_each(|item| match item { 119 | syn::ImplItem::Const(item) => { 120 | second_consts.insert(&item.ident, item); 121 | } 122 | syn::ImplItem::Type(item) => { 123 | second_types.insert(&item.ident, item); 124 | } 125 | syn::ImplItem::Fn(item) => { 126 | second_fns.insert(&item.sig.ident, item); 127 | } 128 | item => abort!(item, "Not supported"), 129 | }); 130 | 131 | for trait_item in trait_items { 132 | match trait_item { 133 | syn::TraitItem::Const(trait_item) => { 134 | if let Some(second_item) = second_consts.swap_remove(&trait_item.ident) { 135 | if trait_item.generics.params.len() != second_item.generics.params.len() { 136 | abort!(trait_item.generics, "Doesn't match trait definition"); 137 | } 138 | } else if trait_item.default.is_none() { 139 | abort!(trait_item, "Missing in one of the impls"); 140 | } 141 | } 142 | syn::TraitItem::Type(trait_item) => { 143 | if second_types.swap_remove(&trait_item.ident).is_none() 144 | && trait_item.default.is_none() 145 | { 146 | abort!(trait_item, "Missing in one of the impls"); 147 | } 148 | } 149 | syn::TraitItem::Fn(trait_item) => { 150 | if second_fns.swap_remove(&trait_item.sig.ident).is_none() 151 | && trait_item.default.is_none() 152 | { 153 | abort!(trait_item, "Missing in one of the impls"); 154 | } 155 | } 156 | item => abort!(item, "Not supported"), 157 | } 158 | } 159 | 160 | if let Some((second_item, _)) = second_consts.into_iter().next() { 161 | abort!(second_item, "Not found in trait definition"); 162 | } 163 | if let Some((second_item, _)) = second_types.into_iter().next() { 164 | abort!(second_item, "Not found in trait definition"); 165 | } 166 | if let Some((second_item, _)) = second_fns.into_iter().next() { 167 | abort!(second_item, "Not found in trait definition"); 168 | } 169 | } 170 | 171 | fn compare_inherent_items(first: &[syn::ImplItem], second: &[syn::ImplItem]) { 172 | let mut second_consts = IndexMap::new(); 173 | let mut second_types = IndexMap::new(); 174 | let mut second_fns = IndexMap::new(); 175 | 176 | second.iter().for_each(|item| match item { 177 | syn::ImplItem::Const(item) => { 178 | second_consts.insert(&item.ident, item); 179 | } 180 | syn::ImplItem::Type(item) => { 181 | second_types.insert(&item.ident, item); 182 | } 183 | syn::ImplItem::Fn(item) => { 184 | second_fns.insert(&item.sig.ident, item); 185 | } 186 | item => abort!(item, "Not supported"), 187 | }); 188 | 189 | for first_item in first { 190 | match first_item { 191 | syn::ImplItem::Const(first_item) => { 192 | if let Some(second_item) = second_consts.swap_remove(&first_item.ident) { 193 | if first_item.generics.params.len() != second_item.generics.params.len() { 194 | abort!(first_item.generics, "Generics don't match between impls"); 195 | } 196 | } else { 197 | abort!(first_item, "Not found in one of the impls"); 198 | } 199 | } 200 | syn::ImplItem::Type(first_item) => { 201 | if second_types.swap_remove(&first_item.ident).is_none() { 202 | abort!(first_item, "Not found in one of the impls"); 203 | } 204 | } 205 | syn::ImplItem::Fn(first_item) => { 206 | if second_fns.swap_remove(&first_item.sig.ident).is_none() { 207 | abort!(first_item, "Not found in one of the impls"); 208 | } 209 | } 210 | item => abort!(item, "Not supported"), 211 | } 212 | } 213 | 214 | if let Some((second_item, _)) = second_consts.into_iter().next() { 215 | abort!(second_item, "Not found in one of the impls"); 216 | } 217 | if let Some((second_item, _)) = second_types.into_iter().next() { 218 | abort!(second_item, "Not found in one of the impls"); 219 | } 220 | if let Some((second_item, _)) = second_fns.into_iter().next() { 221 | abort!(second_item, "Not found in one of the impls"); 222 | } 223 | } 224 | -------------------------------------------------------------------------------- /src/generalize/generics.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl Generalize for syn::LifetimeParam { 4 | fn generalize<'a>( 5 | &'a self, 6 | other: &'a Self, 7 | params1: &Params, 8 | params2: &Params, 9 | substitutions: &mut Generalizations<'a>, 10 | ) -> Option { 11 | let attrs = self 12 | .attrs 13 | .generalize(&other.attrs, params1, params2, substitutions)?; 14 | let lifetime = 15 | self.lifetime 16 | .generalize(&other.lifetime, params1, params2, substitutions)?; 17 | 18 | Some(Self { 19 | attrs, 20 | lifetime, 21 | ..self.clone() 22 | }) 23 | } 24 | } 25 | 26 | impl Generalize for syn::TypeParamBound { 27 | fn generalize<'a>( 28 | &'a self, 29 | other: &'a Self, 30 | params1: &Params, 31 | params2: &Params, 32 | substitutions: &mut Generalizations<'a>, 33 | ) -> Option { 34 | use syn::TypeParamBound::*; 35 | 36 | match (self, other) { 37 | (Trait(x1), Trait(x2)) => { 38 | let generalized = x1.generalize(x2, params1, params2, substitutions)?; 39 | Some(Trait(generalized)) 40 | } 41 | (Lifetime(x1), Lifetime(x2)) => { 42 | let generalized = x1.generalize(x2, params1, params2, substitutions)?; 43 | Some(Lifetime(generalized)) 44 | } 45 | (PreciseCapture(_), _) | (_, PreciseCapture(_)) => unreachable!(), 46 | _ => None, 47 | } 48 | } 49 | } 50 | 51 | impl Generalize for syn::TraitBound { 52 | fn generalize<'a>( 53 | &'a self, 54 | other: &'a Self, 55 | params1: &Params, 56 | params2: &Params, 57 | substitutions: &mut Generalizations<'a>, 58 | ) -> Option { 59 | if self.paren_token != other.paren_token || self.modifier != other.modifier { 60 | return None; 61 | } 62 | 63 | let lifetimes = 64 | self.lifetimes 65 | .generalize(&other.lifetimes, params1, params2, substitutions)?; 66 | let path = self 67 | .path 68 | .generalize(&other.path, params1, params2, substitutions)?; 69 | 70 | Some(Self { 71 | lifetimes, 72 | path, 73 | ..self.clone() 74 | }) 75 | } 76 | } 77 | 78 | impl Generalize for syn::BoundLifetimes { 79 | fn generalize<'a>( 80 | &'a self, 81 | other: &'a Self, 82 | params1: &Params, 83 | params2: &Params, 84 | substitutions: &mut Generalizations<'a>, 85 | ) -> Option { 86 | let lifetimes = 87 | self.lifetimes 88 | .generalize(&other.lifetimes, params1, params2, substitutions)?; 89 | 90 | Some(Self { 91 | lifetimes, 92 | ..self.clone() 93 | }) 94 | } 95 | } 96 | 97 | impl Generalize for syn::GenericParam { 98 | fn generalize<'a>( 99 | &'a self, 100 | other: &'a Self, 101 | params1: &Params, 102 | params2: &Params, 103 | substitutions: &mut Generalizations<'a>, 104 | ) -> Option { 105 | use syn::GenericParam::*; 106 | 107 | match (self, other) { 108 | (Lifetime(x1), Lifetime(x2)) => x1 109 | .generalize(x2, params1, params2, substitutions) 110 | .map(Lifetime), 111 | (Type(x1), Type(x2)) => x1.generalize(x2, params1, params2, substitutions).map(Type), 112 | (Const(x1), Const(x2)) => x1 113 | .generalize(x2, params1, params2, substitutions) 114 | .map(Const), 115 | _ => None, 116 | } 117 | } 118 | } 119 | 120 | impl Generalize for syn::TypeParam { 121 | fn generalize<'a>( 122 | &'a self, 123 | other: &'a Self, 124 | params1: &Params, 125 | params2: &Params, 126 | substitutions: &mut Generalizations<'a>, 127 | ) -> Option { 128 | let attrs = self 129 | .attrs 130 | .generalize(&other.attrs, params1, params2, substitutions)?; 131 | let bounds = self 132 | .bounds 133 | .generalize(&other.bounds, params1, params2, substitutions)?; 134 | 135 | let default = self 136 | .default 137 | .generalize(&other.default, params1, params2, substitutions)?; 138 | 139 | Some(Self { 140 | attrs, 141 | bounds, 142 | default, 143 | ..self.clone() 144 | }) 145 | } 146 | } 147 | 148 | impl Generalize for syn::ConstParam { 149 | fn generalize<'a>( 150 | &'a self, 151 | other: &'a Self, 152 | params1: &Params, 153 | params2: &Params, 154 | substitutions: &mut Generalizations<'a>, 155 | ) -> Option { 156 | let attrs = self 157 | .attrs 158 | .generalize(&other.attrs, params1, params2, substitutions)?; 159 | let ty = self 160 | .ty 161 | .generalize(&other.ty, params1, params2, substitutions)?; 162 | 163 | let default = self 164 | .default 165 | .generalize(&other.default, params1, params2, substitutions)?; 166 | 167 | Some(Self { 168 | attrs, 169 | ty, 170 | default, 171 | ..self.clone() 172 | }) 173 | } 174 | } 175 | 176 | impl Generalize for syn::WhereClause { 177 | fn generalize<'a>( 178 | &'a self, 179 | other: &'a Self, 180 | params1: &Params, 181 | params2: &Params, 182 | substitutions: &mut Generalizations<'a>, 183 | ) -> Option { 184 | let predicates = 185 | self.predicates 186 | .generalize(&other.predicates, params1, params2, substitutions)?; 187 | 188 | Some(Self { 189 | predicates, 190 | ..self.clone() 191 | }) 192 | } 193 | } 194 | 195 | impl Generalize for syn::WherePredicate { 196 | fn generalize<'a>( 197 | &'a self, 198 | other: &'a Self, 199 | params1: &Params, 200 | params2: &Params, 201 | substitutions: &mut Generalizations<'a>, 202 | ) -> Option { 203 | use syn::WherePredicate::*; 204 | 205 | match (self, other) { 206 | (Lifetime(x1), Lifetime(x2)) => x1 207 | .generalize(x2, params1, params2, substitutions) 208 | .map(Lifetime), 209 | (Type(x1), Type(x2)) => x1.generalize(x2, params1, params2, substitutions).map(Type), 210 | _ => None, 211 | } 212 | } 213 | } 214 | 215 | impl Generalize for syn::PredicateLifetime { 216 | fn generalize<'a>( 217 | &'a self, 218 | other: &'a Self, 219 | params1: &Params, 220 | params2: &Params, 221 | substitutions: &mut Generalizations<'a>, 222 | ) -> Option { 223 | let lifetime = 224 | self.lifetime 225 | .generalize(&other.lifetime, params1, params2, substitutions)?; 226 | let bounds = self 227 | .bounds 228 | .generalize(&other.bounds, params1, params2, substitutions)?; 229 | 230 | Some(Self { 231 | lifetime, 232 | bounds, 233 | ..self.clone() 234 | }) 235 | } 236 | } 237 | 238 | impl Generalize for syn::PredicateType { 239 | fn generalize<'a>( 240 | &'a self, 241 | other: &'a Self, 242 | params1: &Params, 243 | params2: &Params, 244 | substitutions: &mut Generalizations<'a>, 245 | ) -> Option { 246 | let lifetimes = 247 | self.lifetimes 248 | .generalize(&other.lifetimes, params1, params2, substitutions)?; 249 | let bounded_ty = 250 | self.bounded_ty 251 | .generalize(&other.bounded_ty, params1, params2, substitutions)?; 252 | let bounds = self 253 | .bounds 254 | .generalize(&other.bounds, params1, params2, substitutions)?; 255 | 256 | Some(Self { 257 | lifetimes, 258 | bounded_ty, 259 | bounds, 260 | ..self.clone() 261 | }) 262 | } 263 | } 264 | 265 | impl Generalize for syn::Generics { 266 | fn generalize<'a>( 267 | &'a self, 268 | other: &'a Self, 269 | params1: &Params, 270 | params2: &Params, 271 | substitutions: &mut Generalizations<'a>, 272 | ) -> Option { 273 | if self.lt_token.is_some() != other.lt_token.is_some() 274 | || self.gt_token.is_some() != other.gt_token.is_some() 275 | { 276 | return None; 277 | } 278 | 279 | let params = self 280 | .params 281 | .generalize(&other.params, params1, params2, substitutions)?; 282 | let where_clause = 283 | self.where_clause 284 | .generalize(&other.where_clause, params1, params2, substitutions)?; 285 | 286 | Some(Self { 287 | params, 288 | where_clause, 289 | ..self.clone() 290 | }) 291 | } 292 | } 293 | -------------------------------------------------------------------------------- /src/generalize/pat.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | 3 | impl Generalize for syn::Pat { 4 | fn generalize<'a>( 5 | &'a self, 6 | other: &'a Self, 7 | params1: &Params, 8 | params2: &Params, 9 | substitutions: &mut Generalizations<'a>, 10 | ) -> Option { 11 | use syn::Pat::*; 12 | 13 | match (self, other) { 14 | (Const(x1), Const(x2)) => x1 15 | .generalize(x2, params1, params2, substitutions) 16 | .map(Const), 17 | (Ident(x1), Ident(x2)) => x1 18 | .generalize(x2, params1, params2, substitutions) 19 | .map(Ident), 20 | (Lit(x1), Lit(x2)) => x1.generalize(x2, params1, params2, substitutions).map(Lit), 21 | (Macro(x1), Macro(x2)) => x1 22 | .generalize(x2, params1, params2, substitutions) 23 | .map(Macro), 24 | (Or(x1), Or(x2)) => x1.generalize(x2, params1, params2, substitutions).map(Or), 25 | (Paren(x1), Paren(x2)) => x1 26 | .generalize(x2, params1, params2, substitutions) 27 | .map(Paren), 28 | (Path(x1), Path(x2)) => x1.generalize(x2, params1, params2, substitutions).map(Path), 29 | (Range(x1), Range(x2)) => x1 30 | .generalize(x2, params1, params2, substitutions) 31 | .map(Range), 32 | (Reference(x1), Reference(x2)) => x1 33 | .generalize(x2, params1, params2, substitutions) 34 | .map(Reference), 35 | (Rest(x1), Rest(x2)) => x1.generalize(x2, params1, params2, substitutions).map(Rest), 36 | (Slice(x1), Slice(x2)) => x1 37 | .generalize(x2, params1, params2, substitutions) 38 | .map(Slice), 39 | (Struct(x1), Struct(x2)) => x1 40 | .generalize(x2, params1, params2, substitutions) 41 | .map(Struct), 42 | (Tuple(x1), Tuple(x2)) => x1 43 | .generalize(x2, params1, params2, substitutions) 44 | .map(Tuple), 45 | (TupleStruct(x1), TupleStruct(x2)) => x1 46 | .generalize(x2, params1, params2, substitutions) 47 | .map(TupleStruct), 48 | (Type(x1), Type(x2)) => x1.generalize(x2, params1, params2, substitutions).map(Type), 49 | (x1, Wild(_)) => x1.generalize(x1, params1, params1, substitutions), 50 | (Wild(_), x2) => x2.generalize(x2, params2, params2, substitutions), 51 | _ => None, 52 | } 53 | } 54 | } 55 | 56 | impl Generalize for syn::PatIdent { 57 | fn generalize<'a>( 58 | &'a self, 59 | other: &'a Self, 60 | params1: &Params, 61 | params2: &Params, 62 | substitutions: &mut Generalizations<'a>, 63 | ) -> Option { 64 | if self.by_ref != other.by_ref 65 | || self.mutability != other.mutability 66 | || self.ident != other.ident 67 | { 68 | return None; 69 | } 70 | let attrs = self 71 | .attrs 72 | .generalize(&other.attrs, params1, params2, substitutions)?; 73 | let subpat = self 74 | .subpat 75 | .generalize(&other.subpat, params1, params2, substitutions)?; 76 | 77 | Some(Self { 78 | attrs, 79 | subpat, 80 | ..self.clone() 81 | }) 82 | } 83 | } 84 | 85 | impl Generalize for syn::PatOr { 86 | fn generalize<'a>( 87 | &'a self, 88 | other: &'a Self, 89 | params1: &Params, 90 | params2: &Params, 91 | substitutions: &mut Generalizations<'a>, 92 | ) -> Option { 93 | let attrs = self 94 | .attrs 95 | .generalize(&other.attrs, params1, params2, substitutions)?; 96 | let cases = self 97 | .cases 98 | .generalize(&other.cases, params1, params2, substitutions)?; 99 | 100 | Some(Self { 101 | attrs, 102 | cases, 103 | ..self.clone() 104 | }) 105 | } 106 | } 107 | 108 | impl Generalize for syn::PatParen { 109 | fn generalize<'a>( 110 | &'a self, 111 | other: &'a Self, 112 | params1: &Params, 113 | params2: &Params, 114 | substitutions: &mut Generalizations<'a>, 115 | ) -> Option { 116 | let attrs = self 117 | .attrs 118 | .generalize(&other.attrs, params1, params2, substitutions)?; 119 | let pat = self 120 | .pat 121 | .generalize(&other.pat, params1, params2, substitutions)?; 122 | 123 | Some(Self { 124 | attrs, 125 | pat, 126 | ..self.clone() 127 | }) 128 | } 129 | } 130 | 131 | impl Generalize for syn::PatReference { 132 | fn generalize<'a>( 133 | &'a self, 134 | other: &'a Self, 135 | params1: &Params, 136 | params2: &Params, 137 | substitutions: &mut Generalizations<'a>, 138 | ) -> Option { 139 | if self.mutability != other.mutability { 140 | return None; 141 | } 142 | let attrs = self 143 | .attrs 144 | .generalize(&other.attrs, params1, params2, substitutions)?; 145 | let pat = self 146 | .pat 147 | .generalize(&other.pat, params1, params2, substitutions)?; 148 | 149 | Some(Self { 150 | attrs, 151 | pat, 152 | ..self.clone() 153 | }) 154 | } 155 | } 156 | 157 | impl Generalize for syn::PatRest { 158 | fn generalize<'a>( 159 | &'a self, 160 | other: &'a Self, 161 | params1: &Params, 162 | params2: &Params, 163 | substitutions: &mut Generalizations<'a>, 164 | ) -> Option { 165 | let attrs = self 166 | .attrs 167 | .generalize(&other.attrs, params1, params2, substitutions)?; 168 | Some(Self { 169 | attrs, 170 | ..self.clone() 171 | }) 172 | } 173 | } 174 | 175 | impl Generalize for syn::PatStruct { 176 | fn generalize( 177 | &self, 178 | _: &Self, 179 | _: &Params, 180 | _: &Params, 181 | _: &mut Generalizations<'_>, 182 | ) -> Option { 183 | unimplemented!() 184 | } 185 | } 186 | 187 | impl Generalize for syn::PatSlice { 188 | fn generalize<'a>( 189 | &'a self, 190 | other: &'a Self, 191 | params1: &Params, 192 | params2: &Params, 193 | substitutions: &mut Generalizations<'a>, 194 | ) -> Option { 195 | let attrs = self 196 | .attrs 197 | .generalize(&other.attrs, params1, params2, substitutions)?; 198 | let elems = self 199 | .elems 200 | .generalize(&other.elems, params1, params2, substitutions)?; 201 | 202 | Some(Self { 203 | attrs, 204 | elems, 205 | ..self.clone() 206 | }) 207 | } 208 | } 209 | 210 | impl Generalize for syn::PatTuple { 211 | fn generalize<'a>( 212 | &'a self, 213 | other: &'a Self, 214 | params1: &Params, 215 | params2: &Params, 216 | substitutions: &mut Generalizations<'a>, 217 | ) -> Option { 218 | let attrs = self 219 | .attrs 220 | .generalize(&other.attrs, params1, params2, substitutions)?; 221 | let elems = self 222 | .elems 223 | .generalize(&other.elems, params1, params2, substitutions)?; 224 | 225 | Some(Self { 226 | attrs, 227 | elems, 228 | ..self.clone() 229 | }) 230 | } 231 | } 232 | 233 | impl Generalize for syn::PatTupleStruct { 234 | fn generalize<'a>( 235 | &'a self, 236 | other: &'a Self, 237 | params1: &Params, 238 | params2: &Params, 239 | substitutions: &mut Generalizations<'a>, 240 | ) -> Option { 241 | let attrs = self 242 | .attrs 243 | .generalize(&other.attrs, params1, params2, substitutions)?; 244 | let path = self 245 | .path 246 | .generalize(&other.path, params1, params2, substitutions)?; 247 | let elems = self 248 | .elems 249 | .generalize(&other.elems, params1, params2, substitutions)?; 250 | 251 | Some(Self { 252 | attrs, 253 | path, 254 | elems, 255 | ..self.clone() 256 | }) 257 | } 258 | } 259 | 260 | impl Generalize for syn::PatType { 261 | fn generalize<'a>( 262 | &'a self, 263 | other: &'a Self, 264 | params1: &Params, 265 | params2: &Params, 266 | substitutions: &mut Generalizations<'a>, 267 | ) -> Option { 268 | let attrs = self 269 | .attrs 270 | .generalize(&other.attrs, params1, params2, substitutions)?; 271 | let ty = self 272 | .ty 273 | .generalize(&other.ty, params1, params2, substitutions)?; 274 | 275 | Some(Self { 276 | attrs, 277 | ty, 278 | ..self.clone() 279 | }) 280 | } 281 | } 282 | 283 | impl Generalize for syn::PatWild { 284 | fn generalize<'a>( 285 | &'a self, 286 | other: &'a Self, 287 | params1: &Params, 288 | params2: &Params, 289 | substitutions: &mut Generalizations<'a>, 290 | ) -> Option { 291 | let attrs = self 292 | .attrs 293 | .generalize(&other.attrs, params1, params2, substitutions)?; 294 | 295 | Some(Self { 296 | attrs, 297 | ..self.clone() 298 | }) 299 | } 300 | } 301 | --------------------------------------------------------------------------------