mirror of
				https://github.com/golang/go.git
				synced 2025-10-31 00:30:57 +00:00 
			
		
		
		
	
		
			
	
	
		
			135 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
		
		
			
		
	
	
			135 lines
		
	
	
	
		
			3 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
|   | // run -gcflags=all="-d=unified -G" | ||
|  | 
 | ||
|  | // 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) | ||
|  | } |