// run // Copyright 2026 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // Test that type assertions and type switches in generic functions // produce correct results when the compiler eliminates impossible // cases based on shape type analysis. package main import "fmt" func switchStringOrBytes[S string | []byte](x S) string { switch any(x).(type) { case string: return "string" case []byte: return "[]byte" } return "unknown" } func switchThree[S string | []byte | int](x S) string { switch any(x).(type) { case string: return "string" case []byte: return "[]byte" case int: return "int" } return "unknown" } type MyString string func switchNamed[S string | MyString](x S) string { switch any(x).(type) { case string: return "string" case MyString: return "MyString" } return "unknown" } func commaOkString[S string | []byte](x S) (string, bool) { v, ok := any(x).(string) return v, ok } func commaOkBytes[S string | []byte](x S) ([]byte, bool) { v, ok := any(x).([]byte) return v, ok } func commaOkChain[S string | []byte | int](x S) string { if _, ok := any(x).(string); ok { return "string" } if _, ok := any(x).([]byte); ok { return "[]byte" } if _, ok := any(x).(int); ok { return "int" } return "unknown" } // Intermediate variable tests. func commaOkViaVar[S string | []byte](x S) (string, bool) { iface := any(x) v, ok := iface.(string) return v, ok } func switchViaVar[S string | []byte](x S) string { iface := any(x) switch iface.(type) { case string: return "string" case []byte: return "[]byte" } return "unknown" } // When no switch case matches the shape, the default is taken. func switchFallsToDefault[S string | []byte | int](x S) string { switch any(x).(type) { case string: return "string" case []byte: return "[]byte" } return "other" } func main() { check("switchStringOrBytes string", switchStringOrBytes("hello"), "string") check("switchStringOrBytes []byte", switchStringOrBytes([]byte("hello")), "[]byte") check("switchThree string", switchThree("x"), "string") check("switchThree []byte", switchThree([]byte("x")), "[]byte") check("switchThree int", switchThree(42), "int") check("switchNamed string", switchNamed("hi"), "string") check("switchNamed MyString", switchNamed(MyString("hi")), "MyString") v1, ok1 := commaOkString("hello") check("commaOkString[string] val", v1, "hello") checkBool("commaOkString[string] ok", ok1, true) v2, ok2 := commaOkString([]byte("hello")) check("commaOkString[[]byte] val", v2, "") checkBool("commaOkString[[]byte] ok", ok2, false) v3, ok3 := commaOkBytes([]byte("world")) check("commaOkBytes[[]byte] val", string(v3), "world") checkBool("commaOkBytes[[]byte] ok", ok3, true) v4, ok4 := commaOkBytes("world") check("commaOkBytes[string] val", string(v4), "") checkBool("commaOkBytes[string] ok", ok4, false) check("commaOkChain string", commaOkChain("x"), "string") check("commaOkChain []byte", commaOkChain([]byte("x")), "[]byte") check("commaOkChain int", commaOkChain(42), "int") // Intermediate variable: comma-ok v5, ok5 := commaOkViaVar("hello") check("commaOkViaVar[string] val", v5, "hello") checkBool("commaOkViaVar[string] ok", ok5, true) v6, ok6 := commaOkViaVar([]byte("hello")) check("commaOkViaVar[[]byte] val", v6, "") checkBool("commaOkViaVar[[]byte] ok", ok6, false) // Intermediate variable: type switch check("switchViaVar string", switchViaVar("x"), "string") check("switchViaVar []byte", switchViaVar([]byte("x")), "[]byte") // All cases impossible: int instantiation hits default check("switchFallsToDefault string", switchFallsToDefault("x"), "string") check("switchFallsToDefault []byte", switchFallsToDefault([]byte("x")), "[]byte") check("switchFallsToDefault int", switchFallsToDefault(42), "other") } func check(name, got, want string) { if got != want { panic(fmt.Sprintf("%s: got %q, want %q", name, got, want)) } } func checkBool(name string, got, want bool) { if got != want { panic(fmt.Sprintf("%s: got %v, want %v", name, got, want)) } }