aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/noder/stencil.go20
-rw-r--r--src/cmd/compile/internal/noder/types.go4
-rw-r--r--src/cmd/compile/internal/types/type.go9
-rw-r--r--test/typeparam/interfacearg.go44
4 files changed, 64 insertions, 13 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 8dcc9d811e..78e701eaf8 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -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
+}
diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go
index b196cb5945..06c584714e 100644
--- a/src/cmd/compile/internal/noder/types.go
+++ b/src/cmd/compile/internal/noder/types.go
@@ -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
diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go
index 7bf63764b8..31a99781d1 100644
--- a/src/cmd/compile/internal/types/type.go
+++ b/src/cmd/compile/internal/types/type.go
@@ -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
index 0000000000..e2d85e3647
--- /dev/null
+++ b/test/typeparam/interfacearg.go
@@ -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()
+}