]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix creation of named generic types (setting of t.nod)
authorDan Scales <danscales@google.com>
Wed, 10 Mar 2021 23:25:21 +0000 (15:25 -0800)
committerDan Scales <danscales@google.com>
Tue, 30 Mar 2021 04:48:27 +0000 (04:48 +0000)
The correct setting of t.nod is needed when exporting types. Make sure
we create instantiated named types correctly so t.nod is set.

New test file interfacearg.go that tests this (by instantiating a type
with an interface). Also has tests for various kinds of method
expressions.

Change-Id: Ia7fd9debd495336b73788af9e35d72331bb7d2b5
Reviewed-on: https://go-review.googlesource.com/c/go/+/305730
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Dan Scales <danscales@google.com>
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/noder/stencil.go
src/cmd/compile/internal/noder/types.go
src/cmd/compile/internal/types/type.go
test/typeparam/interfacearg.go [new file with mode: 0644]

index 8dcc9d811e2545270ecac75d252626bdde16d981..78e701eaf837e8fd5db8d215a1bca5a65c2ff504 100644 (file)
@@ -715,12 +715,10 @@ func (subst *subster) typ(t *types.Type) *types.Type {
                        return newsym.Def.Type()
                }
 
-               // In order to deal with recursive generic types, create a TFORW type
-               // initially and set its Def field, so it can be found if this type
-               // appears recursively within the type.
-               forw = types.New(types.TFORW)
-               forw.SetSym(newsym)
-               newsym.Def = ir.TypeNode(forw)
+               // In order to deal with recursive generic types, create a TFORW
+               // type initially and set the Def field of its sym, so it can be
+               // found if this type appears recursively within the type.
+               forw = newNamedTypeWithSym(t.Pos(), newsym)
                //println("Creating new type by sub", newsym.Name, forw.HasTParam())
                forw.SetRParams(neededTargs)
        }
@@ -894,3 +892,13 @@ func deref(t *types.Type) *types.Type {
        }
        return t
 }
+
+// newNamedTypeWithSym returns a TFORW type t with name specified by sym, such
+// that t.nod and sym.Def are set correctly.
+func newNamedTypeWithSym(pos src.XPos, sym *types.Sym) *types.Type {
+       name := ir.NewDeclNameAt(pos, ir.OTYPE, sym)
+       forw := types.NewNamed(name)
+       name.SetType(forw)
+       sym.Def = name
+       return forw
+}
index b196cb59453e772d160d759e5ca14344eeacd363..06c584714e1eb5c032183f4b2e1a3cf30cce69a8 100644 (file)
@@ -120,10 +120,8 @@ func (g *irgen) typ0(typ types2.Type) *types.Type {
                        // which may set HasTParam) before translating the
                        // underlying type itself, so we handle recursion
                        // correctly, including via method signatures.
-                       ntyp := types.New(types.TFORW)
+                       ntyp := newNamedTypeWithSym(g.pos(typ.Obj().Pos()), s)
                        g.typs[typ] = ntyp
-                       ntyp.SetSym(s)
-                       s.Def = ir.TypeNode(ntyp)
 
                        // If ntyp still has type params, then we must be
                        // referencing something like 'value[T2]', as when
index 7bf63764b86e614cfceb3c20f0f309fe8d27a133..31a99781d126e35a7bd9e517b4a2e5e17a13f05f 100644 (file)
@@ -160,8 +160,9 @@ type Type struct {
        methods    Fields
        allMethods Fields
 
-       nod        Object // canonical OTYPE node
-       underlying *Type  // original type (type literal or predefined type)
+       // canonical OTYPE node for a named type (should be an ir.Name node with same sym)
+       nod        Object
+       underlying *Type // original type (type literal or predefined type)
 
        // Cache of composite types, with this type being the element type.
        cache struct {
@@ -1642,7 +1643,7 @@ var (
        TypeResultMem = newResults([]*Type{TypeMem})
 )
 
-// NewNamed returns a new named type for the given type name.
+// NewNamed returns a new named type for the given type name. obj should be an ir.Name.
 func NewNamed(obj Object) *Type {
        t := New(TFORW)
        t.sym = obj.Sym()
@@ -1650,7 +1651,7 @@ func NewNamed(obj Object) *Type {
        return t
 }
 
-// Obj returns the type name for the named type t.
+// Obj returns the canonical type name node for a named type t, nil for an unnamed type.
 func (t *Type) Obj() Object {
        if t.sym != nil {
                return t.nod
diff --git a/test/typeparam/interfacearg.go b/test/typeparam/interfacearg.go
new file mode 100644 (file)
index 0000000..e2d85e3
--- /dev/null
@@ -0,0 +1,44 @@
+// run -gcflags=-G=3
+
+// 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.
+
+package main
+
+type I interface{}
+
+type _S[T any] struct {
+       *T
+}
+
+// F is a non-generic function, but has a type _S[I] which is instantiated from a
+// generic type. Test that _S[I] is successfully exported.
+func F() {
+       v := _S[I]{}
+       if v.T != nil {
+               panic(v)
+       }
+}
+
+// Testing the various combinations of method expressions.
+type S1 struct{}
+func (*S1) M() {}
+
+type S2 struct{}
+func (S2) M() {}
+
+func _F1[T interface{ M() }](t T) {
+       _ = T.M
+}
+
+func F2() {
+        _F1(&S1{})
+        _F1(S2{})
+        _F1(&S2{})
+}
+
+func main() {
+       F()
+       F2()
+}