diff options
-rw-r--r-- | src/cmd/compile/internal/noder/stencil.go | 20 | ||||
-rw-r--r-- | src/cmd/compile/internal/noder/types.go | 4 | ||||
-rw-r--r-- | src/cmd/compile/internal/types/type.go | 9 | ||||
-rw-r--r-- | test/typeparam/interfacearg.go | 44 |
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() +} |