|
| 1 | +// run -gcflags=all="-d=unified -G" |
| 2 | + |
| 3 | +// Copyright 2021 The Go Authors. All rights reserved. |
| 4 | +// Use of this source code is governed by a BSD-style |
| 5 | +// license that can be found in the LICENSE file. |
| 6 | + |
| 7 | +// This test case stress tests a number of subtle cases involving |
| 8 | +// nested type-parameterized declarations. At a high-level, it |
| 9 | +// declares a generic function that contains a generic type |
| 10 | +// declaration: |
| 11 | +// |
| 12 | +// func F[A intish]() { |
| 13 | +// type T[B intish] struct{} |
| 14 | +// |
| 15 | +// // store reflect.Type tuple (A, B, F[A].T[B]) in tests |
| 16 | +// } |
| 17 | +// |
| 18 | +// It then instantiates this function with a variety of type arguments |
| 19 | +// for A and B. Particularly tricky things like shadowed types. |
| 20 | +// |
| 21 | +// From this data it tests two things: |
| 22 | +// |
| 23 | +// 1. Given tuples (A, B, F[A].T[B]) and (A', B', F[A'].T[B']), |
| 24 | +// F[A].T[B] should be identical to F[A'].T[B'] iff (A, B) is |
| 25 | +// identical to (A', B'). |
| 26 | +// |
| 27 | +// 2. A few of the instantiations are constructed to be identical, and |
| 28 | +// it tests that exactly these pairs are duplicated (by golden |
| 29 | +// output comparison to nested.out). |
| 30 | +// |
| 31 | +// In both cases, we're effectively using the compiler's existing |
| 32 | +// runtime.Type handling (which is well tested) of type identity of A |
| 33 | +// and B as a way to help bootstrap testing and validate its new |
| 34 | +// runtime.Type handling of F[A].T[B]. |
| 35 | +// |
| 36 | +// This isn't perfect, but it smoked out a handful of issues in |
| 37 | +// gotypes2 and unified IR. |
| 38 | + |
| 39 | +package main |
| 40 | + |
| 41 | +import ( |
| 42 | + "fmt" |
| 43 | + "reflect" |
| 44 | +) |
| 45 | + |
| 46 | +type test struct { |
| 47 | + TArgs [2]reflect.Type |
| 48 | + Instance reflect.Type |
| 49 | +} |
| 50 | + |
| 51 | +var tests []test |
| 52 | + |
| 53 | +type intish interface{ ~int } |
| 54 | + |
| 55 | +type Int int |
| 56 | +type GlobalInt = Int // allow access to global Int, even when shadowed |
| 57 | + |
| 58 | +func F[A intish]() { |
| 59 | + add := func(B, T interface{}) { |
| 60 | + tests = append(tests, test{ |
| 61 | + TArgs: [2]reflect.Type{ |
| 62 | + reflect.TypeOf(A(0)), |
| 63 | + reflect.TypeOf(B), |
| 64 | + }, |
| 65 | + Instance: reflect.TypeOf(T), |
| 66 | + }) |
| 67 | + } |
| 68 | + |
| 69 | + type Int int |
| 70 | + |
| 71 | + type T[B intish] struct{} |
| 72 | + |
| 73 | + add(int(0), T[int]{}) |
| 74 | + add(Int(0), T[Int]{}) |
| 75 | + add(GlobalInt(0), T[GlobalInt]{}) |
| 76 | + add(A(0), T[A]{}) // NOTE: intentionally dups with int and GlobalInt |
| 77 | + |
| 78 | + type U[_ any] int |
| 79 | + type V U[int] |
| 80 | + type W V |
| 81 | + |
| 82 | + add(U[int](0), T[U[int]]{}) |
| 83 | + add(U[Int](0), T[U[Int]]{}) |
| 84 | + add(U[GlobalInt](0), T[U[GlobalInt]]{}) |
| 85 | + add(U[A](0), T[U[A]]{}) // NOTE: intentionally dups with U[int] and U[GlobalInt] |
| 86 | + add(V(0), T[V]{}) |
| 87 | + add(W(0), T[W]{}) |
| 88 | +} |
| 89 | + |
| 90 | +func main() { |
| 91 | + type Int int |
| 92 | + |
| 93 | + F[int]() |
| 94 | + F[Int]() |
| 95 | + F[GlobalInt]() |
| 96 | + |
| 97 | + type U[_ any] int |
| 98 | + type V U[int] |
| 99 | + type W V |
| 100 | + |
| 101 | + F[U[int]]() |
| 102 | + F[U[Int]]() |
| 103 | + F[U[GlobalInt]]() |
| 104 | + F[V]() |
| 105 | + F[W]() |
| 106 | + |
| 107 | + type X[A any] U[X[A]] |
| 108 | + |
| 109 | + F[X[int]]() |
| 110 | + F[X[Int]]() |
| 111 | + F[X[GlobalInt]]() |
| 112 | + |
| 113 | + for j, tj := range tests { |
| 114 | + for i, ti := range tests[:j+1] { |
| 115 | + if (ti.TArgs == tj.TArgs) != (ti.Instance == tj.Instance) { |
| 116 | + fmt.Printf("FAIL: %d,%d: %s, but %s\n", i, j, eq(ti.TArgs, tj.TArgs), eq(ti.Instance, tj.Instance)) |
| 117 | + } |
| 118 | + |
| 119 | + // The test is constructed so we should see a few identical types. |
| 120 | + // See "NOTE" comments above. |
| 121 | + if i != j && ti.Instance == tj.Instance { |
| 122 | + fmt.Printf("%d,%d: %v\n", i, j, ti.Instance) |
| 123 | + } |
| 124 | + } |
| 125 | + } |
| 126 | +} |
| 127 | + |
| 128 | +func eq(a, b interface{}) string { |
| 129 | + op := "==" |
| 130 | + if a != b { |
| 131 | + op = "!=" |
| 132 | + } |
| 133 | + return fmt.Sprintf("%v %s %v", a, op, b) |
| 134 | +} |
0 commit comments