1
0
mirror of https://github.com/golang/go synced 2024-09-28 23:24:33 -06:00
go/test/typeparam/nested.go
Matthew Dempsky 72a76ca1f9 cmd/compile: restore test/nested.go test cases
When handling a type declaration like:

```
type B A
```

unified IR has been writing out that B's underlying type is A, rather
than the underlying type of A.

This is a bit awkward to implement and adds complexity to importers,
who need to handle resolving the underlying type themselves. But it
was necessary to handle when A was declared like:

```
//go:notinheap
type A int
```

Because we expected A's not-in-heap'ness to be conferred to B, which
required knowing that A was on the path from B to its actual
underlying type int.

However, since #46731 was accepted, we no longer need to support this
case. Instead we can write out B's actual underlying type.

One stumbling point though is the existing code for exporting
interfaces doesn't work for the underlying type of `comparable`, which
is now needed to implement `type C comparable`. As a bit of a hack, we
we instead export its underlying type as `interface{ comparable }`.

Fixes #54512.

Change-Id: I0fb892068d656f1e87bb8ef97da27756051126d5
Reviewed-on: https://go-review.googlesource.com/c/go/+/424854
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
2022-08-23 18:13:38 +00:00

135 lines
3.0 KiB
Go

// 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)
}