Source file test/typeparam/nested.go

     1  // run
     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  }
   135  

View as plain text