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>
This commit is contained in:
Dana Jansens
2025-03-21 20:38:24 +00:00
committed by GitHub
co-authored by josh11b
parent 868efb7c86
commit 402dc2c064
@@ -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);
}