diff --git a/chalk-integration/src/lowering.rs b/chalk-integration/src/lowering.rs index 425534d535e..cc7b6afb83f 100644 --- a/chalk-integration/src/lowering.rs +++ b/chalk-integration/src/lowering.rs @@ -1143,6 +1143,7 @@ impl Lower for WellKnownTrait { WellKnownTrait::DiscriminantKind => rust_ir::WellKnownTrait::DiscriminantKind, WellKnownTrait::Generator => rust_ir::WellKnownTrait::Generator, WellKnownTrait::DispatchFromDyn => rust_ir::WellKnownTrait::DispatchFromDyn, + WellKnownTrait::Tuple => rust_ir::WellKnownTrait::Tuple, } } } diff --git a/chalk-parse/src/ast.rs b/chalk-parse/src/ast.rs index 3ed826479ad..5eab7bb4325 100644 --- a/chalk-parse/src/ast.rs +++ b/chalk-parse/src/ast.rs @@ -161,6 +161,7 @@ pub enum WellKnownTrait { DiscriminantKind, Generator, DispatchFromDyn, + Tuple, } #[derive(Clone, PartialEq, Eq, Debug)] diff --git a/chalk-parse/src/parser.lalrpop b/chalk-parse/src/parser.lalrpop index 0eaa460facd..39a825509b4 100644 --- a/chalk-parse/src/parser.lalrpop +++ b/chalk-parse/src/parser.lalrpop @@ -69,6 +69,7 @@ WellKnownTrait: WellKnownTrait = { "#" "[" "lang" "(" "discriminant_kind" ")" "]" => WellKnownTrait::DiscriminantKind, "#" "[" "lang" "(" "generator" ")" "]" => WellKnownTrait::Generator, "#" "[" "lang" "(" "dispatch_from_dyn" ")" "]" => WellKnownTrait::DispatchFromDyn, + "#" "[" "lang" "(" "tuple_trait" ")" "]" => WellKnownTrait::Tuple, }; AdtReprAttr: AdtReprAttr = { diff --git a/chalk-solve/src/clauses/builtin_traits.rs b/chalk-solve/src/clauses/builtin_traits.rs index 73fa4110171..b5a1c7d57dd 100644 --- a/chalk-solve/src/clauses/builtin_traits.rs +++ b/chalk-solve/src/clauses/builtin_traits.rs @@ -8,6 +8,7 @@ mod discriminant_kind; mod fn_family; mod generator; mod sized; +mod tuple; mod unsize; /// For well known traits we have special hard-coded impls, either as an @@ -50,6 +51,9 @@ pub fn add_builtin_program_clauses( WellKnownTrait::Generator => { generator::add_generator_program_clauses(db, builder, self_ty)?; } + WellKnownTrait::Tuple => { + tuple::add_tuple_program_clauses(db, builder, self_ty)?; + } // There are no builtin impls provided for the following traits: WellKnownTrait::Unpin | WellKnownTrait::Drop diff --git a/chalk-solve/src/clauses/builtin_traits/tuple.rs b/chalk-solve/src/clauses/builtin_traits/tuple.rs new file mode 100644 index 00000000000..a6244782759 --- /dev/null +++ b/chalk-solve/src/clauses/builtin_traits/tuple.rs @@ -0,0 +1,30 @@ +use crate::clauses::ClauseBuilder; +use crate::rust_ir::WellKnownTrait; +use crate::{Interner, RustIrDatabase, TraitRef}; +use chalk_ir::{Floundered, Substitution, Ty, TyKind}; + +/// Add implicit impl for the `Tuple` trait for all tuples +pub fn add_tuple_program_clauses( + db: &dyn RustIrDatabase, + builder: &mut ClauseBuilder<'_, I>, + self_ty: Ty, +) -> Result<(), Floundered> { + let interner = db.interner(); + + match self_ty.kind(interner) { + TyKind::Tuple(..) => { + let trait_id = db.well_known_trait_id(WellKnownTrait::Tuple).unwrap(); + + builder.push_fact(TraitRef { + trait_id, + substitution: Substitution::from1(interner, self_ty), + }); + + Ok(()) + } + + // Tuple trait is non-enumerable + TyKind::InferenceVar(..) | TyKind::BoundVar(_) | TyKind::Alias(..) => Err(Floundered), + _ => Ok(()), + } +} diff --git a/chalk-solve/src/display/items.rs b/chalk-solve/src/display/items.rs index 78ebbfac184..00387a07b34 100644 --- a/chalk-solve/src/display/items.rs +++ b/chalk-solve/src/display/items.rs @@ -205,6 +205,7 @@ impl RenderAsRust for TraitDatum { WellKnownTrait::DiscriminantKind => "discriminant_kind", WellKnownTrait::Generator => "generator", WellKnownTrait::DispatchFromDyn => "dispatch_from_dyn", + WellKnownTrait::Tuple => "tuple_trait", }; writeln!(f, "#[lang({})]", name)?; } diff --git a/chalk-solve/src/rust_ir.rs b/chalk-solve/src/rust_ir.rs index f68d6b97e3e..935a29032da 100644 --- a/chalk-solve/src/rust_ir.rs +++ b/chalk-solve/src/rust_ir.rs @@ -277,6 +277,7 @@ pub enum WellKnownTrait { DiscriminantKind, Generator, DispatchFromDyn, + Tuple, } chalk_ir::const_visit!(WellKnownTrait); diff --git a/chalk-solve/src/wf.rs b/chalk-solve/src/wf.rs index 84d9724171d..d552cdde7c2 100644 --- a/chalk-solve/src/wf.rs +++ b/chalk-solve/src/wf.rs @@ -435,7 +435,8 @@ where | WellKnownTrait::Unsize | WellKnownTrait::Sized | WellKnownTrait::DiscriminantKind - | WellKnownTrait::Generator => false, + | WellKnownTrait::Generator + | WellKnownTrait::Tuple => false, }; if is_legal { diff --git a/tests/test/tuples.rs b/tests/test/tuples.rs index 9f087a979e1..d295ba4b415 100644 --- a/tests/test/tuples.rs +++ b/tests/test/tuples.rs @@ -294,3 +294,55 @@ fn tuples_are_wf() { } } } + +#[test] +fn tuples_implement_tuple_trait() { + test! { + program { + #[lang(tuple_trait)] + trait Tuple { } + } + + goal { + (): Tuple + } yields { + expect![["Unique"]] + } + + goal { + (u8,): Tuple + } yields { + expect![["Unique"]] + } + + goal { + (i32, i32): Tuple + } yields { + expect![["Unique"]] + } + + goal { + ([u8],): Tuple + } yields { + expect![["Unique"]] + } + + goal { + forall { (T,): Tuple } + } yields { + expect![["Unique"]] + } + + goal { + i32: Tuple + } yields { + expect![["No possible solution"]] + } + + goal { + exists { T: Tuple } + } yields { + expect![["Ambiguous; no inference guidance"]] + } + } +}