// run // Copyright 2021 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. // This test case stress tests a number of subtle cases involving // nested type-parameterized declarations. At a high-level, it // declares a generic function that contains a generic type // declaration: // // func F[A intish]() { // type T[B intish] struct{} // // // store reflect.Type tuple (A, B, F[A].T[B]) in tests // } // // It then instantiates this function with a variety of type arguments // for A and B. Particularly tricky things like shadowed types. // // From this data it tests two things: // // 1. Given tuples (A, B, F[A].T[B]) and (A', B', F[A'].T[B']), // F[A].T[B] should be identical to F[A'].T[B'] iff (A, B) is // identical to (A', B'). // // 2. A few of the instantiations are constructed to be identical, and // it tests that exactly these pairs are duplicated (by golden // output comparison to nested.out). // // In both cases, we're effectively using the compiler's existing // runtime.Type handling (which is well tested) of type identity of A // and B as a way to help bootstrap testing and validate its new // runtime.Type handling of F[A].T[B]. // // This isn't perfect, but it smoked out a handful of issues in // gotypes2 and unified IR. package main import ( "fmt" "reflect" ) type test struct { TArgs [2]reflect.Type Instance reflect.Type } var tests []test type intish interface{ ~int } type Int int type GlobalInt = Int // allow access to global Int, even when shadowed func F[A intish]() { add := func(B, T interface{}) { tests = append(tests, test{ TArgs: [2]reflect.Type{ reflect.TypeOf(A(0)), reflect.TypeOf(B), }, Instance: reflect.TypeOf(T), }) } type Int int type T[B intish] struct{} add(int(0), T[int]{}) add(Int(0), T[Int]{}) add(GlobalInt(0), T[GlobalInt]{}) add(A(0), T[A]{}) // NOTE: intentionally dups with int and GlobalInt type U[_ any] int type V U[int] type W V add(U[int](0), T[U[int]]{}) add(U[Int](0), T[U[Int]]{}) add(U[GlobalInt](0), T[U[GlobalInt]]{}) add(U[A](0), T[U[A]]{}) // NOTE: intentionally dups with U[int] and U[GlobalInt] add(V(0), T[V]{}) add(W(0), T[W]{}) } func main() { type Int int F[int]() F[Int]() F[GlobalInt]() type U[_ any] int type V U[int] type W V F[U[int]]() F[U[Int]]() F[U[GlobalInt]]() F[V]() F[W]() type X[A any] U[X[A]] F[X[int]]() F[X[Int]]() F[X[GlobalInt]]() for j, tj := range tests { for i, ti := range tests[:j+1] { if (ti.TArgs == tj.TArgs) != (ti.Instance == tj.Instance) { fmt.Printf("FAIL: %d,%d: %s, but %s\n", i, j, eq(ti.TArgs, tj.TArgs), eq(ti.Instance, tj.Instance)) } // The test is constructed so we should see a few identical types. // See "NOTE" comments above. if i != j && ti.Instance == tj.Instance { fmt.Printf("%d,%d: %v\n", i, j, ti.Instance) } } } } func eq(a, b interface{}) string { op := "==" if a != b { op = "!=" } return fmt.Sprintf("%v %s %v", a, op, b) }