From ea095d3175482e2cf7f608787dfaf766b4b3d80d Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 4 Aug 2020 13:10:51 -0400 Subject: [PATCH 1/7] Add copy program clauses for all types --- .../src/clauses/builtin_traits/copy.rs | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/chalk-solve/src/clauses/builtin_traits/copy.rs b/chalk-solve/src/clauses/builtin_traits/copy.rs index 81df1ac2fb2..badd48595ed 100644 --- a/chalk-solve/src/clauses/builtin_traits/copy.rs +++ b/chalk-solve/src/clauses/builtin_traits/copy.rs @@ -1,7 +1,7 @@ use crate::clauses::builtin_traits::needs_impl_for_tys; use crate::clauses::ClauseBuilder; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::{ApplicationTy, Substitution, TyData, TypeName}; +use chalk_ir::{ApplicationTy, Mutability, Substitution, TyData, TyKind, TypeName}; use std::iter; fn push_tuple_copy_conditions( @@ -58,11 +58,27 @@ pub fn add_copy_program_clauses( let upvars = upvars.substitute(db.interner(), &closure_fn_substitution); needs_impl_for_tys(db, builder, trait_ref, Some(upvars).into_iter()); } - _ => {} + + TypeName::Ref(Mutability::Not) + | TypeName::Raw(_) + | TypeName::Scalar(_) + | TypeName::Never => builder.push_fact(trait_ref.clone()), + + TypeName::Ref(Mutability::Mut) + | TypeName::Adt(_) + | TypeName::AssociatedType(_) + | TypeName::Slice + | TypeName::OpaqueType(_) + | TypeName::Str + | TypeName::Error => {} }, TyData::Function(_) => builder.push_fact(trait_ref.clone()), + TyData::InferenceVar(_, kind) => match kind { + TyKind::Integer | TyKind::Float => builder.push_fact(trait_ref.clone()), + TyKind::General => {} + }, // TODO(areredify) // when #368 lands, extend this to handle everything accordingly - _ => {} + TyData::Alias(_) | TyData::Dyn(_) | TyData::BoundVar(_) | TyData::Placeholder(_) => {} }; } From 039d0baa53c3f1aa2f1f8d1afe2cf7d057cb795a Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 4 Aug 2020 13:18:07 -0400 Subject: [PATCH 2/7] Reorganize well-known traits tests --- tests/test/builtin_impls.rs | 5 - tests/test/builtin_impls/clone.rs | 64 ------ tests/test/builtin_impls/copy.rs | 67 ------- tests/test/builtin_impls/fn_family.rs | 201 ------------------- tests/test/builtin_impls/sized.rs | 125 ------------ tests/test/fn_def.rs | 59 ++++++ tests/test/functions.rs | 238 ++++++++++++++++++++--- tests/test/mod.rs | 2 +- tests/test/scalars.rs | 26 +++ tests/test/tuples.rs | 203 +++++++++++++++++++ tests/test/{builtin_impls => }/unsize.rs | 0 11 files changed, 501 insertions(+), 489 deletions(-) delete mode 100644 tests/test/builtin_impls.rs delete mode 100644 tests/test/builtin_impls/clone.rs delete mode 100644 tests/test/builtin_impls/copy.rs delete mode 100644 tests/test/builtin_impls/fn_family.rs delete mode 100644 tests/test/builtin_impls/sized.rs rename tests/test/{builtin_impls => }/unsize.rs (100%) diff --git a/tests/test/builtin_impls.rs b/tests/test/builtin_impls.rs deleted file mode 100644 index f3884946dee..00000000000 --- a/tests/test/builtin_impls.rs +++ /dev/null @@ -1,5 +0,0 @@ -mod clone; -mod copy; -mod fn_family; -mod sized; -mod unsize; diff --git a/tests/test/builtin_impls/clone.rs b/tests/test/builtin_impls/clone.rs deleted file mode 100644 index 1ab37f581f3..00000000000 --- a/tests/test/builtin_impls/clone.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::test::*; - -#[test] -fn tuples_are_clone() { - test! { - program { - #[non_enumerable] // see above - #[lang(clone)] - trait Clone { } - - struct S {} - - impl Clone for u8 {} - } - - goal { - ([u8],): Clone - } yields { - "No possible solution" - } - - goal { - (u8, [u8]): Clone - } yields { - "No possible solution" - } - - goal { - ([u8], u8): Clone - } yields { - "No possible solution" - } - - goal { - (): Clone - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - (u8,): Clone - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - (u8, u8): Clone - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - exists { (T, u8): Clone } - } yields { - "Ambiguous" - } - - goal { - forall { if (T: Clone) { (T, u8): Clone } } - } yields { - "Unique; substitution [], lifetime constraints []" - } - } -} diff --git a/tests/test/builtin_impls/copy.rs b/tests/test/builtin_impls/copy.rs deleted file mode 100644 index 542b29beef2..00000000000 --- a/tests/test/builtin_impls/copy.rs +++ /dev/null @@ -1,67 +0,0 @@ -use crate::test::*; - -#[test] -fn tuples_are_copy() { - test! { - program { - // FIXME: If we don't declare Copy non-enumerable, `exists { T: - // Copy }` gives wrong results, because it doesn't consider the - // built-in impls. - #[non_enumerable] - #[lang(copy)] - trait Copy { } - - struct S {} - - impl Copy for u8 {} - } - - goal { - ([u8],): Copy - } yields { - "No possible solution" - } - - goal { - (u8, [u8]): Copy - } yields { - "No possible solution" - } - - goal { - ([u8], u8): Copy - } yields { - "No possible solution" - } - - goal { - (): Copy - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - (u8,): Copy - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - (u8, u8): Copy - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - exists { (T, u8): Copy } - } yields { - "Ambiguous" - } - - goal { - forall { if (T: Copy) { (T, u8): Copy } } - } yields { - "Unique; substitution [], lifetime constraints []" - } - } -} diff --git a/tests/test/builtin_impls/fn_family.rs b/tests/test/builtin_impls/fn_family.rs deleted file mode 100644 index 82b78edcac7..00000000000 --- a/tests/test/builtin_impls/fn_family.rs +++ /dev/null @@ -1,201 +0,0 @@ -use crate::test::*; - -#[test] -fn function_implement_fn_traits() { - test! { - program { - #[lang(fn_once)] - trait FnOnce { - type Output; - } - - #[lang(fn_mut)] - trait FnMut where Self: FnOnce { } - - #[lang(fn)] - trait Fn where Self: FnMut { } - - struct Ty { } - - trait Clone { } - opaque type MyOpaque: Clone = Ty; - - } - - // Simple test: make sure a fully monomorphic type implements FnOnce - goal { - fn(u8): FnOnce<(u8,)> - } yields { - "Unique; substitution [], lifetime constraints []" - } - - // Same as above, but for FnMut - goal { - fn(u8): FnMut<(u8,)> - } yields { - "Unique; substitution [], lifetime constraints []" - } - - // Same as above, but for Fn - goal { - fn(u8): Fn<(u8,)> - } yields { - "Unique; substitution [], lifetime constraints []" - } - - // Make sure unsafe function pointers don't implement FnOnce - goal { - unsafe fn(u8): FnOnce<(u8,)> - } yields { - "No possible solution" - } - // Same as above but for FnMut - goal { - unsafe fn(u8): FnMut<(u8,)> - } yields { - "No possible solution" - } - // Same as above but for Fn - goal { - unsafe fn(u8): Fn<(u8,)> - } yields { - "No possible solution" - } - - // Function pointres implicity return `()` when no return - // type is specified - make sure that normalization understands - // this - goal { - Normalize(>::Output -> ()) - } yields { - "Unique; substitution [], lifetime constraints []" - } - - // Tests normalizing when an explicit return type is used - goal { - Normalize( bool as FnOnce<(u8,)>>::Output -> bool) - } yields { - "Unique; substitution [], lifetime constraints []" - } - - // Tests that we fail to normalize when there's a mismatch with - // fully monomorphic types. - goal { - Normalize( bool as FnOnce<(u8,)>>::Output -> u8) - } yields { - "No possible solution" - } - - // Ensures that we don't find a solution when doing so would - // require us to conclude that two different universally quantified - // types (T and V) are equal. - goal { - forall { - Normalize( T as FnOnce<(u8, V)>>::Output -> V) - } - } yields { - "No possible solution" - } - - // Tests that we can normalize a generic function pointer type - goal { - forall { - exists { - Normalize( T as FnOnce<(u8, V)>>::Output -> U) - } - } - } yields { - "Unique; substitution [?0 := !1_0], lifetime constraints []" - } - - // Tests that we properly tuple function arguments when constrcting - // the `FnOnce` impl - goal { - fn(u8, u32): FnOnce<(u8,u32)> - } yields { - "Unique; substitution [], lifetime constraints []" - } - - // Tests that we don't find a solution when fully monomorphic - // types are mismatched - goal { - fn(i32): FnOnce<(bool,)> - } yields { - "No possible solution" - } - - // Tests function pointer types that use the function's binder - // Universally quantified lifetimes that differ only in their - // name ('a vs 'b) should be considered equivalent here - goal { - forall<'a> { - for<'b> fn(&'b u8): FnOnce<(&'a u8,)> - } - } yields { - "Unique; substitution [], lifetime constraints []" - } - - // Tests that a 'stricter' function (requires lifetimes to be the same) - // can implement `FnOnce` for a 'less strict' signature (dose not require - // lifetimes to be the same), provided that the lifetimes are *actually* - // the same. - goal { - forall<'a, 'b> { - for<'c> fn(&'c u8, &'c i32): FnOnce<(&'a u8, &'b i32)> - } - } yields { - "Unique; substitution [], lifetime constraints [InEnvironment { environment: Env([]), goal: '!1_0: '!1_1 }, InEnvironment { environment: Env([]), goal: '!1_1: '!1_0 }]" - } - - // Tests the opposite case as the previous test: a 'less strict' function - // (does not require lifetimes to be the same) can implement `FnOnce` for - // a 'stricter' signature (requires lifetimes to be the same) without - // any additional requirements - goal { - forall<'a> { - for<'b, 'c> fn(&'b u8, &'c i32): FnOnce<(&'a u8, &'a i32)> - } - } yields { - "Unique; substitution [], lifetime constraints []" - } - - // Similiar to the above test, but for types instead of lifetimes: - // a 'stricter' function (requires types to be the same) can never - // implement `FnOnce` for a 'less strict' signature (does not require - // types to be the same) - goal { - forall { - fn(T, T): FnOnce<(T, U)> - } - } yields { - "No possible solution" - } - - // Tests the opposite case as a previous test: a 'less strict' - // function can never implement 'FnOnce' for a 'more strict' signature - // (does not require types to bthe same) - goal { - forall { - fn(T, U): FnOnce<(T, T)> - } - } yields { - "No possible solution" - } - - // Tests that we flounder for inference variables - goal { - exists { - T: FnOnce<()> - } - } yields_first[SolverChoice::slg(3, None)] { - "Floundered" - } - - // Tests that we flounder for alias type (opaque) - goal { - MyOpaque: FnOnce<()> - } yields_first[SolverChoice::slg(3, None)] { - "Floundered" - } - } -} diff --git a/tests/test/builtin_impls/sized.rs b/tests/test/builtin_impls/sized.rs deleted file mode 100644 index 4132e2689d5..00000000000 --- a/tests/test/builtin_impls/sized.rs +++ /dev/null @@ -1,125 +0,0 @@ -use crate::test::*; - -#[test] -fn tuples_are_sized() { - test! { - program { - #[lang(sized)] - trait Sized { } - - trait Foo {} - } - - goal { - ([u8],): Sized - } yields { - "No possible solution" - } - - goal { - (u8, [u8]): Sized - } yields { - "No possible solution" - } - - // It should not be well-formed because for tuples, only - // the last element is allowed not to be Sized. - goal { - ([u8], u8): Sized - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - (): Sized - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - (u8,): Sized - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - (u8, u8): Sized - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - exists { (T, u8): Sized } - } yields { - "Unique; for { substitution [?0 := ^0.0], lifetime constraints [] }" - } - - goal { - forall { (T, u8): Sized } - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - forall { (u8, T): Sized } - } yields { - "No possible solution" - } - - goal { - forall { if (T: Sized) { (u8, T): Sized } } - } yields { - "Unique; substitution [], lifetime constraints []" - } - } -} - -#[test] -fn functions_are_sized() { - test! { - program { - #[lang(sized)] - trait Sized { } - - trait Copy {} - } - - goal { - fn(()): Sized - } yields { - "Unique; substitution [], lifetime constraints []" - } - - goal { - fn([u8]): Sized - } yields { - "Unique; substitution [], lifetime constraints []" - } - } -} - -#[test] -fn scalars_are_sized() { - test! { - program { - #[lang(sized)] trait Sized { } - } - - goal { i8: Sized } yields { "Unique" } - goal { i16: Sized } yields { "Unique" } - goal { i32: Sized } yields { "Unique" } - goal { i64: Sized } yields { "Unique" } - goal { i128: Sized } yields { "Unique" } - goal { isize: Sized } yields { "Unique" } - goal { u8: Sized } yields { "Unique" } - goal { u16: Sized } yields { "Unique" } - goal { u32: Sized } yields { "Unique" } - goal { u64: Sized } yields { "Unique" } - goal { u128: Sized } yields { "Unique" } - goal { usize: Sized } yields { "Unique" } - goal { f32: Sized } yields { "Unique" } - goal { f64: Sized } yields { "Unique" } - goal { bool: Sized } yields { "Unique" } - goal { char: Sized } yields { "Unique" } - } -} diff --git a/tests/test/fn_def.rs b/tests/test/fn_def.rs index ec95d7dae99..a96738d1bc4 100644 --- a/tests/test/fn_def.rs +++ b/tests/test/fn_def.rs @@ -166,3 +166,62 @@ fn generic_fn_implements_fn_traits() { } } } + +#[test] +fn fn_defs() { + test! { + program { + trait Foo { } + + struct Bar { } + + struct Xyzzy { } + impl Foo for Xyzzy { } + + fn baz(quux: T) -> T + where T: Foo; + + fn garply(thud: i32) -> i32; + } + + goal { + WellFormed(baz) + } yields { + "No possible solution" + } + + goal { + WellFormed(baz) + } yields { + "Unique" + } + + goal { + WellFormed(garply) + } yields { + "Unique" + } + + } +} + +#[test] +fn fn_def_implied_bounds_from_env() { + test! { + program { + trait Foo { } + + struct Bar { } + impl Foo for Bar { } + + fn baz() where T: Foo; + } + goal { + if (FromEnv(baz)) { + Bar: Foo + } + } yields { + "Unique" + } + } +} diff --git a/tests/test/functions.rs b/tests/test/functions.rs index 48a4efa8ae5..802b069845e 100644 --- a/tests/test/functions.rs +++ b/tests/test/functions.rs @@ -1,60 +1,246 @@ use super::*; #[test] -fn fn_defs() { +fn functions_are_sized() { test! { program { - trait Foo { } - - struct Bar { } - - struct Xyzzy { } - impl Foo for Xyzzy { } - - fn baz(quux: T) -> T - where T: Foo; - - fn garply(thud: i32) -> i32; + #[lang(sized)] + trait Sized { } } goal { - WellFormed(baz) + fn(()): Sized } yields { - "No possible solution" + "Unique; substitution [], lifetime constraints []" } goal { - WellFormed(baz) + fn([u8]): Sized } yields { - "Unique" + "Unique; substitution [], lifetime constraints []" + } + } +} + +fn functions_are_copy() { + test! { + program { + #[lang(copy)] + trait Copy { } } goal { - WellFormed(garply) + fn(()): Copy } yields { - "Unique" + "Unique; substitution [], lifetime constraints []" } + goal { + fn([u8]): Copy + } yields { + "Unique; substitution [], lifetime constraints []" + } } } +use crate::test::*; + #[test] -fn fn_def_implied_bounds_from_env() { +fn function_implement_fn_traits() { test! { program { - trait Foo { } + #[lang(fn_once)] + trait FnOnce { + type Output; + } + + #[lang(fn_mut)] + trait FnMut where Self: FnOnce { } + + #[lang(fn)] + trait Fn where Self: FnMut { } + + struct Ty { } + + trait Clone { } + opaque type MyOpaque: Clone = Ty; + + } + + // Simple test: make sure a fully monomorphic type implements FnOnce + goal { + fn(u8): FnOnce<(u8,)> + } yields { + "Unique; substitution [], lifetime constraints []" + } + + // Same as above, but for FnMut + goal { + fn(u8): FnMut<(u8,)> + } yields { + "Unique; substitution [], lifetime constraints []" + } - struct Bar { } - impl Foo for Bar { } + // Same as above, but for Fn + goal { + fn(u8): Fn<(u8,)> + } yields { + "Unique; substitution [], lifetime constraints []" + } - fn baz() where T: Foo; + // Make sure unsafe function pointers don't implement FnOnce + goal { + unsafe fn(u8): FnOnce<(u8,)> + } yields { + "No possible solution" } + // Same as above but for FnMut goal { - if (FromEnv(baz)) { - Bar: Foo + unsafe fn(u8): FnMut<(u8,)> + } yields { + "No possible solution" + } + // Same as above but for Fn + goal { + unsafe fn(u8): Fn<(u8,)> + } yields { + "No possible solution" + } + + // Function pointres implicity return `()` when no return + // type is specified - make sure that normalization understands + // this + goal { + Normalize(>::Output -> ()) + } yields { + "Unique; substitution [], lifetime constraints []" + } + + // Tests normalizing when an explicit return type is used + goal { + Normalize( bool as FnOnce<(u8,)>>::Output -> bool) + } yields { + "Unique; substitution [], lifetime constraints []" + } + + // Tests that we fail to normalize when there's a mismatch with + // fully monomorphic types. + goal { + Normalize( bool as FnOnce<(u8,)>>::Output -> u8) + } yields { + "No possible solution" + } + + // Ensures that we don't find a solution when doing so would + // require us to conclude that two different universally quantified + // types (T and V) are equal. + goal { + forall { + Normalize( T as FnOnce<(u8, V)>>::Output -> V) + } + } yields { + "No possible solution" + } + + // Tests that we can normalize a generic function pointer type + goal { + forall { + exists { + Normalize( T as FnOnce<(u8, V)>>::Output -> U) + } } } yields { - "Unique" + "Unique; substitution [?0 := !1_0], lifetime constraints []" + } + + // Tests that we properly tuple function arguments when constrcting + // the `FnOnce` impl + goal { + fn(u8, u32): FnOnce<(u8,u32)> + } yields { + "Unique; substitution [], lifetime constraints []" + } + + // Tests that we don't find a solution when fully monomorphic + // types are mismatched + goal { + fn(i32): FnOnce<(bool,)> + } yields { + "No possible solution" + } + + // Tests function pointer types that use the function's binder + // Universally quantified lifetimes that differ only in their + // name ('a vs 'b) should be considered equivalent here + goal { + forall<'a> { + for<'b> fn(&'b u8): FnOnce<(&'a u8,)> + } + } yields { + "Unique; substitution [], lifetime constraints []" + } + + // Tests that a 'stricter' function (requires lifetimes to be the same) + // can implement `FnOnce` for a 'less strict' signature (dose not require + // lifetimes to be the same), provided that the lifetimes are *actually* + // the same. + goal { + forall<'a, 'b> { + for<'c> fn(&'c u8, &'c i32): FnOnce<(&'a u8, &'b i32)> + } + } yields { + "Unique; substitution [], lifetime constraints [InEnvironment { environment: Env([]), goal: '!1_0: '!1_1 }, InEnvironment { environment: Env([]), goal: '!1_1: '!1_0 }]" + } + + // Tests the opposite case as the previous test: a 'less strict' function + // (does not require lifetimes to be the same) can implement `FnOnce` for + // a 'stricter' signature (requires lifetimes to be the same) without + // any additional requirements + goal { + forall<'a> { + for<'b, 'c> fn(&'b u8, &'c i32): FnOnce<(&'a u8, &'a i32)> + } + } yields { + "Unique; substitution [], lifetime constraints []" + } + + // Similiar to the above test, but for types instead of lifetimes: + // a 'stricter' function (requires types to be the same) can never + // implement `FnOnce` for a 'less strict' signature (does not require + // types to be the same) + goal { + forall { + fn(T, T): FnOnce<(T, U)> + } + } yields { + "No possible solution" + } + + // Tests the opposite case as a previous test: a 'less strict' + // function can never implement 'FnOnce' for a 'more strict' signature + // (does not require types to bthe same) + goal { + forall { + fn(T, U): FnOnce<(T, T)> + } + } yields { + "No possible solution" + } + + // Tests that we flounder for inference variables + goal { + exists { + T: FnOnce<()> + } + } yields_first[SolverChoice::slg(3, None)] { + "Floundered" + } + + // Tests that we flounder for alias type (opaque) + goal { + MyOpaque: FnOnce<()> + } yields_first[SolverChoice::slg(3, None)] { + "Floundered" } } } diff --git a/tests/test/mod.rs b/tests/test/mod.rs index 5bdb2789da4..13ee775fb9c 100644 --- a/tests/test/mod.rs +++ b/tests/test/mod.rs @@ -317,7 +317,6 @@ fn solve_goal(program_text: &str, goals: Vec<(&str, SolverChoice, TestGoal)>) { mod arrays; mod auto_traits; -mod builtin_impls; mod closures; mod coherence_goals; mod coinduction; @@ -340,4 +339,5 @@ mod slices; mod string; mod tuples; mod unify; +mod unsize; mod wf_goals; diff --git a/tests/test/scalars.rs b/tests/test/scalars.rs index d612e135f64..210516ad855 100644 --- a/tests/test/scalars.rs +++ b/tests/test/scalars.rs @@ -136,3 +136,29 @@ fn scalars_are_well_formed() { goal { WellFormed(char) } yields { "Unique" } } } + +#[test] +fn scalars_are_sized() { + test! { + program { + #[lang(sized)] trait Sized { } + } + + goal { i8: Sized } yields { "Unique" } + goal { i16: Sized } yields { "Unique" } + goal { i32: Sized } yields { "Unique" } + goal { i64: Sized } yields { "Unique" } + goal { i128: Sized } yields { "Unique" } + goal { isize: Sized } yields { "Unique" } + goal { u8: Sized } yields { "Unique" } + goal { u16: Sized } yields { "Unique" } + goal { u32: Sized } yields { "Unique" } + goal { u64: Sized } yields { "Unique" } + goal { u128: Sized } yields { "Unique" } + goal { usize: Sized } yields { "Unique" } + goal { f32: Sized } yields { "Unique" } + goal { f64: Sized } yields { "Unique" } + goal { bool: Sized } yields { "Unique" } + goal { char: Sized } yields { "Unique" } + } +} diff --git a/tests/test/tuples.rs b/tests/test/tuples.rs index 5542f8ae2d3..ba12428ec03 100644 --- a/tests/test/tuples.rs +++ b/tests/test/tuples.rs @@ -34,3 +34,206 @@ fn tuple_trait_impl() { } } } + +#[test] +fn tuples_are_copy() { + test! { + program { + // FIXME: If we don't declare Copy non-enumerable, `exists { T: + // Copy }` gives wrong results, because it doesn't consider the + // built-in impls. + #[non_enumerable] + #[lang(copy)] + trait Copy { } + + struct S {} + + impl Copy for u8 {} + } + + goal { + ([u8],): Copy + } yields { + "No possible solution" + } + + goal { + (u8, [u8]): Copy + } yields { + "No possible solution" + } + + goal { + ([u8], u8): Copy + } yields { + "No possible solution" + } + + goal { + (): Copy + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + (u8,): Copy + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + (u8, u8): Copy + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + exists { (T, u8): Copy } + } yields { + "Ambiguous" + } + + goal { + forall { if (T: Copy) { (T, u8): Copy } } + } yields { + "Unique; substitution [], lifetime constraints []" + } + } +} + +#[test] +fn tuples_are_sized() { + test! { + program { + #[lang(sized)] + trait Sized { } + + trait Foo {} + } + + goal { + ([u8],): Sized + } yields { + "No possible solution" + } + + goal { + (u8, [u8]): Sized + } yields { + "No possible solution" + } + + // It should not be well-formed because for tuples, only + // the last element is allowed not to be Sized. + goal { + ([u8], u8): Sized + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + (): Sized + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + (u8,): Sized + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + (u8, u8): Sized + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + exists { (T, u8): Sized } + } yields { + "Unique; for { substitution [?0 := ^0.0], lifetime constraints [] }" + } + + goal { + forall { (T, u8): Sized } + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + forall { (u8, T): Sized } + } yields { + "No possible solution" + } + + goal { + forall { if (T: Sized) { (u8, T): Sized } } + } yields { + "Unique; substitution [], lifetime constraints []" + } + } +} + +#[test] +fn tuples_are_clone() { + test! { + program { + #[non_enumerable] // see above + #[lang(clone)] + trait Clone { } + + struct S {} + + impl Clone for u8 {} + } + + goal { + ([u8],): Clone + } yields { + "No possible solution" + } + + goal { + (u8, [u8]): Clone + } yields { + "No possible solution" + } + + goal { + ([u8], u8): Clone + } yields { + "No possible solution" + } + + goal { + (): Clone + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + (u8,): Clone + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + (u8, u8): Clone + } yields { + "Unique; substitution [], lifetime constraints []" + } + + goal { + exists { (T, u8): Clone } + } yields { + "Ambiguous" + } + + goal { + forall { if (T: Clone) { (T, u8): Clone } } + } yields { + "Unique; substitution [], lifetime constraints []" + } + } +} diff --git a/tests/test/builtin_impls/unsize.rs b/tests/test/unsize.rs similarity index 100% rename from tests/test/builtin_impls/unsize.rs rename to tests/test/unsize.rs From 5c6856d2be77fb0f13590835e93b1a9b49a2ffdb Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 4 Aug 2020 13:26:02 -0400 Subject: [PATCH 3/7] Add sized program clauses for all types --- .../src/clauses/builtin_traits/sized.rs | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/chalk-solve/src/clauses/builtin_traits/sized.rs b/chalk-solve/src/clauses/builtin_traits/sized.rs index 90fd6b56255..7c1eb81002d 100644 --- a/chalk-solve/src/clauses/builtin_traits/sized.rs +++ b/chalk-solve/src/clauses/builtin_traits/sized.rs @@ -4,7 +4,7 @@ use crate::clauses::builtin_traits::needs_impl_for_tys; use crate::clauses::ClauseBuilder; use crate::rust_ir::AdtKind; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::{AdtId, ApplicationTy, Substitution, TyData, TypeName}; +use chalk_ir::{AdtId, ApplicationTy, Substitution, TyData, TyKind, TypeName}; fn push_adt_sized_conditions( db: &dyn RustIrDatabase, @@ -70,6 +70,8 @@ pub fn add_sized_program_clauses( trait_ref: &TraitRef, ty: &TyData, ) { + // TODO(areredify) + // when #368 lands, extend this to handle everything accordingly match ty { TyData::Apply(ApplicationTy { name, substitution }) => match name { TypeName::Adt(adt_id) => { @@ -85,11 +87,22 @@ pub fn add_sized_program_clauses( | TypeName::Scalar(_) | TypeName::Raw(_) | TypeName::Ref(_) => builder.push_fact(trait_ref.clone()), - _ => {} + + TypeName::AssociatedType(_) + | TypeName::Slice + | TypeName::OpaqueType(_) + | TypeName::Str + | TypeName::Error => {} }, - TyData::Function(_) => builder.push_fact(trait_ref.clone()), - // TODO(areredify) - // when #368 lands, extend this to handle everything accordingly - _ => {} + + TyData::Function(_) + | TyData::InferenceVar(_, TyKind::Float) + | TyData::InferenceVar(_, TyKind::Integer) => builder.push_fact(trait_ref.clone()), + + TyData::InferenceVar(_, TyKind::General) + | TyData::Placeholder(_) + | TyData::Dyn(_) + | TyData::Alias(_) + | TyData::BoundVar(_) => {} } } From 76a61e6eafd4a897a7f470c2bf6265922da88989 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 4 Aug 2020 14:13:38 -0400 Subject: [PATCH 4/7] Handle builtin program clauses for bound vars --- chalk-solve/src/clauses.rs | 2 +- chalk-solve/src/clauses/builtin_traits.rs | 15 ++++++++---- .../src/clauses/builtin_traits/clone.rs | 7 +++--- .../src/clauses/builtin_traits/copy.rs | 23 +++++++++++++++++-- .../src/clauses/builtin_traits/sized.rs | 18 ++++++++++++--- 5 files changed, 51 insertions(+), 14 deletions(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index e2f6387d5d2..56dd43a20cc 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -313,7 +313,7 @@ fn program_clauses_that_could_match( } if let Some(well_known) = trait_datum.well_known { - builtin_traits::add_builtin_program_clauses(db, builder, well_known, trait_ref)?; + builtin_traits::add_builtin_program_clauses(db, builder, well_known, trait_ref, binders)?; } } DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => match &alias_eq.alias { diff --git a/chalk-solve/src/clauses/builtin_traits.rs b/chalk-solve/src/clauses/builtin_traits.rs index ff1ed83cffb..d21a4b602b6 100644 --- a/chalk-solve/src/clauses/builtin_traits.rs +++ b/chalk-solve/src/clauses/builtin_traits.rs @@ -1,5 +1,5 @@ use super::{builder::ClauseBuilder, generalize}; -use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait}; +use crate::{CanonicalVarKinds, Interner, RustIrDatabase, TraitRef, WellKnownTrait}; use chalk_ir::{Floundered, Substitution, Ty}; mod clone; @@ -15,6 +15,7 @@ pub fn add_builtin_program_clauses( builder: &mut ClauseBuilder<'_, I>, well_known: WellKnownTrait, trait_ref: &TraitRef, + binders: &CanonicalVarKinds, ) -> Result<(), Floundered> { // If `trait_ref` contains bound vars, we want to universally quantify them. // `Generalize` collects them for us. @@ -25,9 +26,15 @@ pub fn add_builtin_program_clauses( let ty = self_ty.data(db.interner()); match well_known { - WellKnownTrait::Sized => sized::add_sized_program_clauses(db, builder, &trait_ref, ty), - WellKnownTrait::Copy => copy::add_copy_program_clauses(db, builder, &trait_ref, ty), - WellKnownTrait::Clone => clone::add_clone_program_clauses(db, builder, &trait_ref, ty), + WellKnownTrait::Sized => { + sized::add_sized_program_clauses(db, builder, &trait_ref, ty, binders) + } + WellKnownTrait::Copy => { + copy::add_copy_program_clauses(db, builder, &trait_ref, ty, binders) + } + WellKnownTrait::Clone => { + clone::add_clone_program_clauses(db, builder, &trait_ref, ty, binders) + } WellKnownTrait::FnOnce | WellKnownTrait::FnMut | WellKnownTrait::Fn => { fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)? } diff --git a/chalk-solve/src/clauses/builtin_traits/clone.rs b/chalk-solve/src/clauses/builtin_traits/clone.rs index 7fb62fbd0a1..69943be85db 100644 --- a/chalk-solve/src/clauses/builtin_traits/clone.rs +++ b/chalk-solve/src/clauses/builtin_traits/clone.rs @@ -1,6 +1,6 @@ use crate::clauses::ClauseBuilder; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::TyData; +use chalk_ir::{CanonicalVarKinds, TyData}; use super::copy::add_copy_program_clauses; @@ -9,9 +9,8 @@ pub fn add_clone_program_clauses( builder: &mut ClauseBuilder<'_, I>, trait_ref: &TraitRef, ty: &TyData, + binders: &CanonicalVarKinds, ) { - let _interner = db.interner(); - // Implement Clone for types that automaticly implement Copy - add_copy_program_clauses(db, builder, trait_ref, ty); + add_copy_program_clauses(db, builder, trait_ref, ty, binders); } diff --git a/chalk-solve/src/clauses/builtin_traits/copy.rs b/chalk-solve/src/clauses/builtin_traits/copy.rs index badd48595ed..695ca207744 100644 --- a/chalk-solve/src/clauses/builtin_traits/copy.rs +++ b/chalk-solve/src/clauses/builtin_traits/copy.rs @@ -1,8 +1,12 @@ use crate::clauses::builtin_traits::needs_impl_for_tys; use crate::clauses::ClauseBuilder; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::{ApplicationTy, Mutability, Substitution, TyData, TyKind, TypeName}; +use chalk_ir::{ + ApplicationTy, CanonicalVarKinds, Mutability, Substitution, TyData, TyKind, TypeName, + VariableKind, +}; use std::iter; +use tracing::instrument; fn push_tuple_copy_conditions( db: &dyn RustIrDatabase, @@ -29,11 +33,13 @@ fn push_tuple_copy_conditions( ); } +#[instrument(skip(db, builder))] pub fn add_copy_program_clauses( db: &dyn RustIrDatabase, builder: &mut ClauseBuilder<'_, I>, trait_ref: &TraitRef, ty: &TyData, + binders: &CanonicalVarKinds, ) { match ty { TyData::Apply(ApplicationTy { name, substitution }) => match name { @@ -72,13 +78,26 @@ pub fn add_copy_program_clauses( | TypeName::Str | TypeName::Error => {} }, + TyData::Function(_) => builder.push_fact(trait_ref.clone()), + TyData::InferenceVar(_, kind) => match kind { TyKind::Integer | TyKind::Float => builder.push_fact(trait_ref.clone()), TyKind::General => {} }, + + TyData::BoundVar(bound_var) => { + let var_kind = &binders.at(db.interner(), bound_var.index).kind; + match var_kind { + VariableKind::Ty(TyKind::Integer) | VariableKind::Ty(TyKind::Float) => { + builder.push_fact(trait_ref.clone()) + } + VariableKind::Ty(_) | VariableKind::Const(_) | VariableKind::Lifetime => {} + } + } + // TODO(areredify) // when #368 lands, extend this to handle everything accordingly - TyData::Alias(_) | TyData::Dyn(_) | TyData::BoundVar(_) | TyData::Placeholder(_) => {} + TyData::Alias(_) | TyData::Dyn(_) | TyData::Placeholder(_) => {} }; } diff --git a/chalk-solve/src/clauses/builtin_traits/sized.rs b/chalk-solve/src/clauses/builtin_traits/sized.rs index 7c1eb81002d..da2ade50a96 100644 --- a/chalk-solve/src/clauses/builtin_traits/sized.rs +++ b/chalk-solve/src/clauses/builtin_traits/sized.rs @@ -4,7 +4,9 @@ use crate::clauses::builtin_traits::needs_impl_for_tys; use crate::clauses::ClauseBuilder; use crate::rust_ir::AdtKind; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::{AdtId, ApplicationTy, Substitution, TyData, TyKind, TypeName}; +use chalk_ir::{ + AdtId, ApplicationTy, CanonicalVarKinds, Substitution, TyData, TyKind, TypeName, VariableKind, +}; fn push_adt_sized_conditions( db: &dyn RustIrDatabase, @@ -69,6 +71,7 @@ pub fn add_sized_program_clauses( builder: &mut ClauseBuilder<'_, I>, trait_ref: &TraitRef, ty: &TyData, + binders: &CanonicalVarKinds, ) { // TODO(areredify) // when #368 lands, extend this to handle everything accordingly @@ -99,10 +102,19 @@ pub fn add_sized_program_clauses( | TyData::InferenceVar(_, TyKind::Float) | TyData::InferenceVar(_, TyKind::Integer) => builder.push_fact(trait_ref.clone()), + TyData::BoundVar(bound_var) => { + let var_kind = &binders.at(db.interner(), bound_var.index).kind; + match var_kind { + VariableKind::Ty(TyKind::Integer) | VariableKind::Ty(TyKind::Float) => { + builder.push_fact(trait_ref.clone()) + } + VariableKind::Ty(_) | VariableKind::Const(_) | VariableKind::Lifetime => {} + } + } + TyData::InferenceVar(_, TyKind::General) | TyData::Placeholder(_) | TyData::Dyn(_) - | TyData::Alias(_) - | TyData::BoundVar(_) => {} + | TyData::Alias(_) => {} } } From 38e9e8a55c3e8aa8b660f655a84639aab8eb2f41 Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 4 Aug 2020 14:26:15 -0400 Subject: [PATCH 5/7] Add more test for builtin traits --- tests/test/numerics.rs | 36 +++++++++++++++++++++++++++++++ tests/test/refs.rs | 48 ++++++++++++++++++++++++++++++++++++++++++ tests/test/scalars.rs | 44 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 128 insertions(+) diff --git a/tests/test/numerics.rs b/tests/test/numerics.rs index c2e16c7e638..d349294a5dc 100644 --- a/tests/test/numerics.rs +++ b/tests/test/numerics.rs @@ -189,3 +189,39 @@ fn integers_are_not_floats() { } } } + +#[test] +fn integers_are_copy() { + test! { + program { + #[lang(copy)] + trait Copy { } + } + + goal { + exists { + I: Copy + } + } yields { + "Unique" + } + } +} + +#[test] +fn integers_are_sized() { + test! { + program { + #[lang(sized)] + trait Sized { } + } + + goal { + exists { + I: Sized + } + } yields { + "Unique" + } + } +} diff --git a/tests/test/refs.rs b/tests/test/refs.rs index d6439ce5dff..88c3335af19 100644 --- a/tests/test/refs.rs +++ b/tests/test/refs.rs @@ -29,6 +29,30 @@ fn immut_refs_are_sized() { } } +#[test] +fn immut_refs_are_copy_clone() { + test! { + program { + #[lang(copy)] + trait Copy { } + + #[lang(clone)] + trait Clone { } + } + + goal { + forall<'a, T> { &'a T: Copy } + } yields { + "Unique; substitution [], lifetime constraints []" + } + goal { + forall<'a, T> { &'a T: Clone } + } yields { + "Unique; substitution [], lifetime constraints []" + } + } +} + #[test] fn mut_refs_are_well_formed() { test! { @@ -57,3 +81,27 @@ fn mut_refs_are_sized() { } } } + +#[test] +fn mut_refs_are_not_copy_clone() { + test! { + program { + #[lang(copy)] + trait Copy { } + + #[lang(clone)] + trait Clone { } + } + + goal { + forall<'a, T> { &'a mut T: Copy } + } yields { + "No possible solution" + } + goal { + forall<'a, T> { &'a mut T: Clone } + } yields { + "No possible solution" + } + } +} diff --git a/tests/test/scalars.rs b/tests/test/scalars.rs index 210516ad855..c4cf5cf4844 100644 --- a/tests/test/scalars.rs +++ b/tests/test/scalars.rs @@ -162,3 +162,47 @@ fn scalars_are_sized() { goal { char: Sized } yields { "Unique" } } } + +#[test] +fn scalars_are_copy_clone() { + test! { + program { + #[lang(copy)] trait Copy { } + #[lang(clone)] trait Clone { } + } + + goal { i8: Copy } yields { "Unique" } + goal { i16: Copy } yields { "Unique" } + goal { i32: Copy } yields { "Unique" } + goal { i64: Copy } yields { "Unique" } + goal { i128: Copy } yields { "Unique" } + goal { isize: Copy } yields { "Unique" } + goal { u8: Copy } yields { "Unique" } + goal { u16: Copy } yields { "Unique" } + goal { u32: Copy } yields { "Unique" } + goal { u64: Copy } yields { "Unique" } + goal { u128: Copy } yields { "Unique" } + goal { usize: Copy } yields { "Unique" } + goal { f32: Copy } yields { "Unique" } + goal { f64: Copy } yields { "Unique" } + goal { bool: Copy } yields { "Unique" } + goal { char: Copy } yields { "Unique" } + + goal { i8: Clone } yields { "Unique" } + goal { i16: Clone } yields { "Unique" } + goal { i32: Clone } yields { "Unique" } + goal { i64: Clone } yields { "Unique" } + goal { i128: Clone } yields { "Unique" } + goal { isize: Clone } yields { "Unique" } + goal { u8: Clone } yields { "Unique" } + goal { u16: Clone } yields { "Unique" } + goal { u32: Clone } yields { "Unique" } + goal { u64: Clone } yields { "Unique" } + goal { u128: Clone } yields { "Unique" } + goal { usize: Clone } yields { "Unique" } + goal { f32: Clone } yields { "Unique" } + goal { f64: Clone } yields { "Unique" } + goal { bool: Clone } yields { "Unique" } + goal { char: Clone } yields { "Unique" } + } +} From e8a3401c81c775f01e020df8644553cfed2abacf Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 4 Aug 2020 14:35:16 -0400 Subject: [PATCH 6/7] Format --- chalk-solve/src/clauses.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/chalk-solve/src/clauses.rs b/chalk-solve/src/clauses.rs index 56dd43a20cc..db54807664e 100644 --- a/chalk-solve/src/clauses.rs +++ b/chalk-solve/src/clauses.rs @@ -313,7 +313,9 @@ fn program_clauses_that_could_match( } if let Some(well_known) = trait_datum.well_known { - builtin_traits::add_builtin_program_clauses(db, builder, well_known, trait_ref, binders)?; + builtin_traits::add_builtin_program_clauses( + db, builder, well_known, trait_ref, binders, + )?; } } DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => match &alias_eq.alias { From 974762b55135981a5948e1fdbc88f8999515613d Mon Sep 17 00:00:00 2001 From: Nathan Whitaker Date: Tue, 4 Aug 2020 15:17:24 -0400 Subject: [PATCH 7/7] Address comments --- .../src/clauses/builtin_traits/copy.rs | 15 +++--- .../src/clauses/builtin_traits/sized.rs | 2 - tests/test/functions.rs | 2 - tests/test/refs.rs | 48 ------------------- tests/test/scalars.rs | 44 ----------------- 5 files changed, 6 insertions(+), 105 deletions(-) diff --git a/chalk-solve/src/clauses/builtin_traits/copy.rs b/chalk-solve/src/clauses/builtin_traits/copy.rs index 695ca207744..5fd9c1a17ac 100644 --- a/chalk-solve/src/clauses/builtin_traits/copy.rs +++ b/chalk-solve/src/clauses/builtin_traits/copy.rs @@ -2,8 +2,7 @@ use crate::clauses::builtin_traits::needs_impl_for_tys; use crate::clauses::ClauseBuilder; use crate::{Interner, RustIrDatabase, TraitRef}; use chalk_ir::{ - ApplicationTy, CanonicalVarKinds, Mutability, Substitution, TyData, TyKind, TypeName, - VariableKind, + ApplicationTy, CanonicalVarKinds, Substitution, TyData, TyKind, TypeName, VariableKind, }; use std::iter; use tracing::instrument; @@ -65,17 +64,17 @@ pub fn add_copy_program_clauses( needs_impl_for_tys(db, builder, trait_ref, Some(upvars).into_iter()); } - TypeName::Ref(Mutability::Not) + // these impls are in libcore + TypeName::Ref(_) | TypeName::Raw(_) | TypeName::Scalar(_) - | TypeName::Never => builder.push_fact(trait_ref.clone()), + | TypeName::Never + | TypeName::Str => {} - TypeName::Ref(Mutability::Mut) - | TypeName::Adt(_) + TypeName::Adt(_) | TypeName::AssociatedType(_) | TypeName::Slice | TypeName::OpaqueType(_) - | TypeName::Str | TypeName::Error => {} }, @@ -96,8 +95,6 @@ pub fn add_copy_program_clauses( } } - // TODO(areredify) - // when #368 lands, extend this to handle everything accordingly TyData::Alias(_) | TyData::Dyn(_) | TyData::Placeholder(_) => {} }; } diff --git a/chalk-solve/src/clauses/builtin_traits/sized.rs b/chalk-solve/src/clauses/builtin_traits/sized.rs index da2ade50a96..786c705a29c 100644 --- a/chalk-solve/src/clauses/builtin_traits/sized.rs +++ b/chalk-solve/src/clauses/builtin_traits/sized.rs @@ -73,8 +73,6 @@ pub fn add_sized_program_clauses( ty: &TyData, binders: &CanonicalVarKinds, ) { - // TODO(areredify) - // when #368 lands, extend this to handle everything accordingly match ty { TyData::Apply(ApplicationTy { name, substitution }) => match name { TypeName::Adt(adt_id) => { diff --git a/tests/test/functions.rs b/tests/test/functions.rs index 802b069845e..df82529b187 100644 --- a/tests/test/functions.rs +++ b/tests/test/functions.rs @@ -43,8 +43,6 @@ fn functions_are_copy() { } } -use crate::test::*; - #[test] fn function_implement_fn_traits() { test! { diff --git a/tests/test/refs.rs b/tests/test/refs.rs index 88c3335af19..d6439ce5dff 100644 --- a/tests/test/refs.rs +++ b/tests/test/refs.rs @@ -29,30 +29,6 @@ fn immut_refs_are_sized() { } } -#[test] -fn immut_refs_are_copy_clone() { - test! { - program { - #[lang(copy)] - trait Copy { } - - #[lang(clone)] - trait Clone { } - } - - goal { - forall<'a, T> { &'a T: Copy } - } yields { - "Unique; substitution [], lifetime constraints []" - } - goal { - forall<'a, T> { &'a T: Clone } - } yields { - "Unique; substitution [], lifetime constraints []" - } - } -} - #[test] fn mut_refs_are_well_formed() { test! { @@ -81,27 +57,3 @@ fn mut_refs_are_sized() { } } } - -#[test] -fn mut_refs_are_not_copy_clone() { - test! { - program { - #[lang(copy)] - trait Copy { } - - #[lang(clone)] - trait Clone { } - } - - goal { - forall<'a, T> { &'a mut T: Copy } - } yields { - "No possible solution" - } - goal { - forall<'a, T> { &'a mut T: Clone } - } yields { - "No possible solution" - } - } -} diff --git a/tests/test/scalars.rs b/tests/test/scalars.rs index c4cf5cf4844..210516ad855 100644 --- a/tests/test/scalars.rs +++ b/tests/test/scalars.rs @@ -162,47 +162,3 @@ fn scalars_are_sized() { goal { char: Sized } yields { "Unique" } } } - -#[test] -fn scalars_are_copy_clone() { - test! { - program { - #[lang(copy)] trait Copy { } - #[lang(clone)] trait Clone { } - } - - goal { i8: Copy } yields { "Unique" } - goal { i16: Copy } yields { "Unique" } - goal { i32: Copy } yields { "Unique" } - goal { i64: Copy } yields { "Unique" } - goal { i128: Copy } yields { "Unique" } - goal { isize: Copy } yields { "Unique" } - goal { u8: Copy } yields { "Unique" } - goal { u16: Copy } yields { "Unique" } - goal { u32: Copy } yields { "Unique" } - goal { u64: Copy } yields { "Unique" } - goal { u128: Copy } yields { "Unique" } - goal { usize: Copy } yields { "Unique" } - goal { f32: Copy } yields { "Unique" } - goal { f64: Copy } yields { "Unique" } - goal { bool: Copy } yields { "Unique" } - goal { char: Copy } yields { "Unique" } - - goal { i8: Clone } yields { "Unique" } - goal { i16: Clone } yields { "Unique" } - goal { i32: Clone } yields { "Unique" } - goal { i64: Clone } yields { "Unique" } - goal { i128: Clone } yields { "Unique" } - goal { isize: Clone } yields { "Unique" } - goal { u8: Clone } yields { "Unique" } - goal { u16: Clone } yields { "Unique" } - goal { u32: Clone } yields { "Unique" } - goal { u64: Clone } yields { "Unique" } - goal { u128: Clone } yields { "Unique" } - goal { usize: Clone } yields { "Unique" } - goal { f32: Clone } yields { "Unique" } - goal { f64: Clone } yields { "Unique" } - goal { bool: Clone } yields { "Unique" } - goal { char: Clone } yields { "Unique" } - } -}