| // run -gcflags=-G=3 |
| |
| // 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) |
| } |