Skip to content

Commit

Permalink
cmd/compile: restore test/nested.go test cases
Browse files Browse the repository at this point in the history
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 golang#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 golang#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>
  • Loading branch information
mdempsky committed Aug 23, 2022
1 parent c94633d commit 72a76ca
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 38 deletions.
40 changes: 23 additions & 17 deletions src/cmd/compile/internal/noder/writer.go
Original file line number Diff line number Diff line change
Expand Up @@ -432,8 +432,9 @@ func (pw *pkgWriter) pkgIdx(pkg *types2.Package) pkgbits.Index {
// @@@ Types

var (
anyTypeName = types2.Universe.Lookup("any").(*types2.TypeName)
runeTypeName = types2.Universe.Lookup("rune").(*types2.TypeName)
anyTypeName = types2.Universe.Lookup("any").(*types2.TypeName)
comparableTypeName = types2.Universe.Lookup("comparable").(*types2.TypeName)
runeTypeName = types2.Universe.Lookup("rune").(*types2.TypeName)
)

// typ writes a use of the given type into the bitstream.
Expand Down Expand Up @@ -485,7 +486,7 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
w.Len(int(kind))

default:
// Handle "byte" and "rune" as references to their TypeName.
// Handle "byte" and "rune" as references to their TypeNames.
obj := types2.Universe.Lookup(typ.Name())
assert(obj.Type() == typ)

Expand Down Expand Up @@ -543,6 +544,7 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo {
w.structType(typ)

case *types2.Interface:
// Handle "any" as reference to its TypeName.
if typ == anyTypeName.Type() {
w.Code(pkgbits.TypeNamed)
w.obj(anyTypeName, nil)
Expand Down Expand Up @@ -590,6 +592,23 @@ func (w *writer) unionType(typ *types2.Union) {
}

func (w *writer) interfaceType(typ *types2.Interface) {
// If typ has no embedded types but it's not a basic interface, then
// the natural description we write out below will fail to
// reconstruct it.
if typ.NumEmbeddeds() == 0 && !typ.IsMethodSet() {
// Currently, this can only happen for the underlying Interface of
// "comparable", which is needed to handle type declarations like
// "type C comparable".
assert(typ == comparableTypeName.Type().(*types2.Named).Underlying())

// Export as "interface{ comparable }".
w.Len(0) // NumExplicitMethods
w.Len(1) // NumEmbeddeds
w.Bool(false) // IsImplicit
w.typ(comparableTypeName.Type()) // EmbeddedType(0)
return
}

w.Len(typ.NumExplicitMethods())
w.Len(typ.NumEmbeddeds())

Expand Down Expand Up @@ -775,9 +794,6 @@ func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj {
return pkgbits.ObjFunc

case *types2.TypeName:
decl, ok := w.p.typDecls[obj]
assert(ok)

if obj.IsAlias() {
w.pos(obj)
w.typ(obj.Type())
Expand All @@ -790,7 +806,7 @@ func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj {
w.pos(obj)
w.typeParamNames(named.TypeParams())
wext.typeExt(obj)
w.typExpr(decl.Type)
w.typ(named.Underlying())

w.Len(named.NumMethods())
for i := 0; i < named.NumMethods(); i++ {
Expand All @@ -807,16 +823,6 @@ func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj {
}
}

// typExpr writes the type represented by the given expression.
//
// TODO(mdempsky): Document how this differs from exprType.
func (w *writer) typExpr(expr syntax.Expr) {
tv, ok := w.p.info.Types[expr]
assert(ok)
assert(tv.IsType())
w.typ(tv.Type)
}

// objDict writes the dictionary needed for reading the given object.
func (w *writer) objDict(obj types2.Object, dict *writerDict) {
// TODO(mdempsky): Split objDict into multiple entries? reader.go
Expand Down
26 changes: 5 additions & 21 deletions test/typeparam/nested.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,27 +104,11 @@ func main() {
F[V]()
F[W]()

// TODO(go.dev/issue/54512): Restore these tests. They currently
// cause problems for shaping with unified IR.
//
// For example, instantiating X[int] requires instantiating shape
// type X[shapify(int)] == X[go.shape.int]. In turn, this requires
// instantiating U[shapify(X[go.shape.int])]. But we're still in the
// process of constructing X[go.shape.int], so we don't yet know its
// underlying type.
//
// Notably, this is a consequence of unified IR writing out type
// declarations with a reference to the full RHS expression (i.e.,
// U[X[A]]) rather than its underlying type (i.e., int), which is
// necessary to support //go:notinheap. Once go.dev/issue/46731 is
// implemented and unified IR is updated, I expect this will just
// work.
//
// type X[A any] U[X[A]]
//
// F[X[int]]()
// F[X[Int]]()
// F[X[GlobalInt]]()
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] {
Expand Down

0 comments on commit 72a76ca

Please sign in to comment.