From 402dc2c0642a8f4cef7ca53eb7d30012dbe1b186 Mon Sep 17 00:00:00 2001 From: Dana Jansens Date: Fri, 21 Mar 2025 13:38:24 -0700 Subject: [PATCH] Add some test cases of specialization (#5165) - A test that should fail that looks to see we poison impls when we do a concrete lookup, so you can't define an impl specialization after we looked for it. This currently passes but should fail. - A test with a final specialization with a type constant written before a generic function using it. The generic function should be able to know the concrete type of the constant. This currently fails, and was discussed in open discussion here: https://docs.google.com/document/d/1Iut5f2TQBrtBNIduF4vJYOKfw7MbS8xH_J01_Q4e6Rk/edit?resourcekey=0-mc_vh5UzrzXfU4kO-3tOjA&tab=t.0#heading=h.swr8311y952x - A test with a specialization written after a generic function, which will be used symbolically so the type constant will not be known. This fails and should continue to, though the error diagnostic may change in time. - A test with a specialization written after a generic function, and which returns a value typed as the type constant from that specialization. The generic is called with types that should cause it to use that specialization in the specific, so the caller gets back the type expected. This currently fails but should pass. --------- Co-authored-by: josh11b <15258583+josh11b@users.noreply.github.com> --- .../lookup/min_prelude/specialization.carbon | 109 ++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon b/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon index a73e0646dd3d..f119011388e6 100644 --- a/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon +++ b/toolchain/check/testdata/impl/lookup/min_prelude/specialization.carbon @@ -305,3 +305,112 @@ impl C(()) as Z where .X = C(()) {} fn F() { let a: C(()).(Z.X) = {} as C(()); } + +// --- todo_fail_specialization_written_after_use_is_poisoned.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +class C {} + +impl forall [T:! type] T as Z(T) where .X = () {} + +fn F() { + let a: C.(Z(C).X) = (); +} + +// TODO: This impl changes the result of a previous lookup. The previous lookup +// should have created a poison value that this trips and thus generates a +// diagnostic. +impl C as Z(C) where .X = C {} + +// --- fail_todo_final_specialization_before_generic_use_of_type_constant.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +class C {} + +impl forall [T:! type, U:! type] T as Z(U) where .X = () {} + +// TODO: Make this `final`. +impl forall [T:! type] T as Z(C) where .X = C {} + +fn F[U:! type](T:! Z(C)) { + // TODO: The value of `.X` can be known to be `C` here when the impl `T as Z(C)` is + // final. + // CHECK:STDERR: fail_todo_final_specialization_before_generic_use_of_type_constant.carbon:[[@LINE+7]]:16: error: cannot implicitly convert value of type `C` to `T.(Z(C).X)` [ConversionFailure] + // CHECK:STDERR: let a: T.X = {} as C; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_todo_final_specialization_before_generic_use_of_type_constant.carbon:[[@LINE+4]]:16: note: type `C` does not implement interface `Core.ImplicitAs(T.(Z(C).X))` [MissingImplInMemberAccessNote] + // CHECK:STDERR: let a: T.X = {} as C; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + let a: T.X = {} as C; +} + +// --- fail_specialization_written_after_generic_use_of_type_constant.carbon +library "[[@TEST_NAME]]"; + +interface Z(T:! type) { + let X:! type; +} + +class C {} + +impl forall [T:! type, U:! type] T as Z(U) where .X = () {} + +fn F[U:! type](T:! Z(C)) { + // The value of `.X` is symbolic, it can't be assigned a value of type `C`. + // CHECK:STDERR: fail_specialization_written_after_generic_use_of_type_constant.carbon:[[@LINE+7]]:16: error: cannot implicitly convert value of type `C` to `T.(Z(C).X)` [ConversionFailure] + // CHECK:STDERR: let a: T.X = {} as C; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: fail_specialization_written_after_generic_use_of_type_constant.carbon:[[@LINE+4]]:16: note: type `C` does not implement interface `Core.ImplicitAs(T.(Z(C).X))` [MissingImplInMemberAccessNote] + // CHECK:STDERR: let a: T.X = {} as C; + // CHECK:STDERR: ^~~~~~~ + // CHECK:STDERR: + let a: T.X = {} as C; +} + +// TODO: Make this `final`. +impl forall [T:! type] T as Z(C) where .X = C {} + +// --- fail_specialization_written_after_generic_use.carbon +library "[[@TEST_NAME]]"; + +interface Z { + let V:! type; + fn F() -> V; +} + +interface Y {} +impl forall [T:! Y] T as Z where .V = () { + fn F() -> () { return (); } +} + +fn G(U:! Y) -> U.(Z.V) { + return U.(Z.F)(); +} + +class C { + impl as Y {} +} + +impl C as Z where .V = {} { + fn F() -> {} { return {}; } +} + +fn H() { + // CHECK:STDERR: fail_specialization_written_after_generic_use.carbon:[[@LINE+7]]:15: error: cannot implicitly convert value of type `()` to `{}` [ConversionFailure] + // CHECK:STDERR: let x: {} = G(C); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: fail_specialization_written_after_generic_use.carbon:[[@LINE+4]]:15: note: type `()` does not implement interface `Core.ImplicitAs({})` [MissingImplInMemberAccessNote] + // CHECK:STDERR: let x: {} = G(C); + // CHECK:STDERR: ^~~~ + // CHECK:STDERR: + let x: {} = G(C); +}