Skip to content

Commit 5b64381

Browse files
committed
cmd/compile: fix naming of types inside instantiations
Issues 47713 and 47877 were both due to problems with the names used for instantiated functions/methods, which must be in sync with the names used by types2. - Switched to using NameString() for writing out type arguments in instantiation names. This ensures that we are always adding the package to type names even for the local package. Previously, we were explicitly adding the package name for local packages, but that doesn't handle the case when the local type is embedded inside a pointer or slice type. By switching to NameString(), we fix #47713. - types1 and types2 write out 'interface {' differently (vs. 'interface{') and we were already handling that. But we needed to add similar code to handle 'struct {' vs 'struct{'. This fixes issue #47877. While fixing these bugs, I also moved some duplicated code (which include some of the changes above) into a common function addTargs(). I also moved InstType() name to subr.go, and renamed: MakeInstName -> MakeFuncInstSym and MakeDictName -> MakeDictSym. Also removed a couple of ".inst..inst." prefix checks which are irrelvant now, since we don't add ".inst." anymore to function instantiations. Fixes #47713 Fixes #47877 Fixes #47922 Change-Id: I19e9a073451f3ababd8ec31b6608cd79ba8cba36 Reviewed-on: https://go-review.googlesource.com/c/go/+/344613 Trust: Dan Scales <[email protected]> Reviewed-by: Keith Randall <[email protected]>
1 parent 4a9f0ce commit 5b64381

File tree

7 files changed

+115
-61
lines changed

7 files changed

+115
-61
lines changed

src/cmd/compile/internal/noder/stencil.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -590,7 +590,7 @@ func (g *irgen) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth
590590
shapes = s1
591591
}
592592

593-
sym := typecheck.MakeInstName(nameNode.Sym(), shapes, isMeth)
593+
sym := typecheck.MakeFuncInstSym(nameNode.Sym(), shapes, isMeth)
594594
info := g.instInfoMap[sym]
595595
if info == nil {
596596
// If instantiation doesn't exist yet, create it and add
@@ -1372,7 +1372,7 @@ func (g *irgen) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool)
13721372
}
13731373

13741374
// Get a symbol representing the dictionary.
1375-
sym := typecheck.MakeDictName(gf.Sym(), targs, isMeth)
1375+
sym := typecheck.MakeDictSym(gf.Sym(), targs, isMeth)
13761376

13771377
// Initialize the dictionary, if we haven't yet already.
13781378
lsym := sym.Linksym()

src/cmd/compile/internal/reflectdata/reflect.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1897,10 +1897,6 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
18971897
} else {
18981898
targs = rcvr.RParams()
18991899
}
1900-
if strings.HasPrefix(ir.MethodSym(orig, method.Sym).Name, ".inst.") {
1901-
fmt.Printf("%s\n", ir.MethodSym(orig, method.Sym).Name)
1902-
panic("multiple .inst.")
1903-
}
19041900
// The wrapper for an auto-generated pointer/non-pointer
19051901
// receiver method should share the same dictionary as the
19061902
// corresponding original (user-written) method.
@@ -1929,7 +1925,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy
19291925
}
19301926
targs = targs2
19311927

1932-
sym := typecheck.MakeInstName(ir.MethodSym(methodrcvr, method.Sym), targs, true)
1928+
sym := typecheck.MakeFuncInstSym(ir.MethodSym(methodrcvr, method.Sym), targs, true)
19331929
if sym.Def == nil {
19341930
// Currently we make sure that we have all the instantiations
19351931
// we need by generating them all in ../noder/stencil.go:instantiateMethods
@@ -2040,7 +2036,7 @@ func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node {
20402036
}
20412037
}
20422038

2043-
sym := typecheck.MakeDictName(gf, targs, true)
2039+
sym := typecheck.MakeDictSym(gf, targs, true)
20442040

20452041
// Initialize the dictionary, if we haven't yet already.
20462042
if lsym := sym.Linksym(); len(lsym.P) == 0 {

src/cmd/compile/internal/typecheck/iimport.go

Lines changed: 1 addition & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
package typecheck
99

1010
import (
11-
"bytes"
1211
"encoding/binary"
1312
"fmt"
1413
"go/constant"
@@ -1751,32 +1750,6 @@ func builtinCall(pos src.XPos, op ir.Op) *ir.CallExpr {
17511750
return ir.NewCallExpr(pos, ir.OCALL, ir.NewIdent(base.Pos, types.BuiltinPkg.Lookup(ir.OpNames[op])), nil)
17521751
}
17531752

1754-
// InstTypeName creates a name for an instantiated type, based on the name of the
1755-
// generic type and the type args.
1756-
func InstTypeName(name string, targs []*types.Type) string {
1757-
b := bytes.NewBufferString(name)
1758-
b.WriteByte('[')
1759-
for i, targ := range targs {
1760-
if i > 0 {
1761-
b.WriteByte(',')
1762-
}
1763-
// WriteString() does not include the package name for the local
1764-
// package, but we want it to make sure type arguments (including
1765-
// type params) are uniquely specified.
1766-
if targ.Sym() != nil && targ.Sym().Pkg == types.LocalPkg {
1767-
b.WriteString(targ.Sym().Pkg.Name)
1768-
b.WriteByte('.')
1769-
}
1770-
// types1 uses "interface {" and types2 uses "interface{" - convert
1771-
// to consistent types2 format.
1772-
tstring := targ.String()
1773-
tstring = strings.Replace(tstring, "interface {", "interface{", -1)
1774-
b.WriteString(tstring)
1775-
}
1776-
b.WriteByte(']')
1777-
return b.String()
1778-
}
1779-
17801753
// NewIncompleteNamedType returns a TFORW type t with name specified by sym, such
17811754
// that t.nod and sym.Def are set correctly.
17821755
func NewIncompleteNamedType(pos src.XPos, sym *types.Sym) *types.Type {
@@ -1879,7 +1852,7 @@ func substInstType(t *types.Type, baseType *types.Type, targs []*types.Type) {
18791852
}
18801853
t2 := msubst.Typ(f.Type)
18811854
oldsym := f.Nname.Sym()
1882-
newsym := MakeInstName(oldsym, targs, true)
1855+
newsym := MakeFuncInstSym(oldsym, targs, true)
18831856
var nname *ir.Name
18841857
if newsym.Def != nil {
18851858
nname = newsym.Def.(*ir.Name)

src/cmd/compile/internal/typecheck/subr.go

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,35 @@ func TypesOf(x []ir.Node) []*types.Type {
900900
return r
901901
}
902902

903+
// addTargs writes out the targs to buffer b as a comma-separated list enclosed by
904+
// brackets.
905+
func addTargs(b *bytes.Buffer, targs []*types.Type) {
906+
b.WriteByte('[')
907+
for i, targ := range targs {
908+
if i > 0 {
909+
b.WriteByte(',')
910+
}
911+
// Use NameString(), which includes the package name for the local
912+
// package, to make sure that type arguments (including type params),
913+
// are uniquely specified.
914+
tstring := targ.NameString()
915+
// types1 uses "interface {" and types2 uses "interface{" - convert
916+
// to consistent types2 format. Same for "struct {"
917+
tstring = strings.Replace(tstring, "interface {", "interface{", -1)
918+
tstring = strings.Replace(tstring, "struct {", "struct{", -1)
919+
b.WriteString(tstring)
920+
}
921+
b.WriteString("]")
922+
}
923+
924+
// InstTypeName creates a name for an instantiated type, based on the name of the
925+
// generic type and the type args.
926+
func InstTypeName(name string, targs []*types.Type) string {
927+
b := bytes.NewBufferString(name)
928+
addTargs(b, targs)
929+
return b.String()
930+
}
931+
903932
// makeInstName1 returns the name of the generic function instantiated with the
904933
// given types, which can have type params or shapes, or be concrete types. name is
905934
// the name of the generic function or method.
@@ -912,36 +941,16 @@ func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string {
912941
} else {
913942
b.WriteString(name)
914943
}
915-
b.WriteString("[")
916-
for i, targ := range targs {
917-
if i > 0 {
918-
b.WriteString(",")
919-
}
920-
// WriteString() does not include the package name for the local
921-
// package, but we want it for uniqueness.
922-
if targ.Sym() != nil && targ.Sym().Pkg == types.LocalPkg {
923-
b.WriteString(targ.Sym().Pkg.Name)
924-
b.WriteByte('.')
925-
}
926-
// types1 uses "interface {" and types2 uses "interface{" - convert
927-
// to consistent types2 format.
928-
tstring := targ.String()
929-
tstring = strings.Replace(tstring, "interface {", "interface{", -1)
930-
b.WriteString(tstring)
931-
}
932-
b.WriteString("]")
944+
addTargs(b, targs)
933945
if i >= 0 {
934946
i2 := strings.LastIndex(name[i:], "]")
935947
assert(i2 >= 0)
936948
b.WriteString(name[i+i2+1:])
937949
}
938-
if strings.HasPrefix(b.String(), ".inst..inst.") {
939-
panic(fmt.Sprintf("multiple .inst. prefix in %s", b.String()))
940-
}
941950
return b.String()
942951
}
943952

944-
// MakeInstName makes the unique name for a stenciled generic function or method,
953+
// MakeFuncInstSym makes the unique sym for a stenciled generic function or method,
945954
// based on the name of the function fnsym and the targs. It replaces any
946955
// existing bracket type list in the name. MakeInstName asserts that fnsym has
947956
// brackets in its name if and only if hasBrackets is true.
@@ -953,11 +962,11 @@ func makeInstName1(name string, targs []*types.Type, hasBrackets bool) string {
953962
//
954963
// The standard naming is something like: 'genFn[int,bool]' for functions and
955964
// '(*genType[int,bool]).methodName' for methods
956-
func MakeInstName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
965+
func MakeFuncInstSym(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
957966
return gf.Pkg.Lookup(makeInstName1(gf.Name, targs, hasBrackets))
958967
}
959968

960-
func MakeDictName(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
969+
func MakeDictSym(gf *types.Sym, targs []*types.Type, hasBrackets bool) *types.Sym {
961970
for _, targ := range targs {
962971
if targ.HasTParam() {
963972
fmt.Printf("FUNCTION %s\n", gf.Name)
@@ -1222,7 +1231,7 @@ func (ts *Tsubster) Typ(t *types.Type) *types.Type {
12221231
for i, f := range t.Methods().Slice() {
12231232
t2 := ts.Typ(f.Type)
12241233
oldsym := f.Nname.Sym()
1225-
newsym := MakeInstName(oldsym, ts.Targs, true)
1234+
newsym := MakeFuncInstSym(oldsym, ts.Targs, true)
12261235
var nname *ir.Name
12271236
if newsym.Def != nil {
12281237
nname = newsym.Def.(*ir.Name)

test/typeparam/issue47713.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// run -gcflags=-G=3
2+
3+
// Copyright 2021 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
import (
10+
"encoding"
11+
"fmt"
12+
)
13+
14+
type Seralizable interface {
15+
encoding.BinaryMarshaler
16+
encoding.BinaryUnmarshaler
17+
}
18+
19+
type SerDeString string
20+
21+
func (s *SerDeString) UnmarshalBinary(in []byte) error {
22+
*s = SerDeString(in)
23+
return nil
24+
}
25+
26+
func (s SerDeString) MarshalBinary() ([]byte, error) {
27+
return []byte(s), nil
28+
}
29+
30+
31+
type GenericSerializable[T Seralizable] struct {
32+
Key string
33+
Value T
34+
}
35+
36+
func (g GenericSerializable[T]) Send() {
37+
out, err := g.Value.MarshalBinary()
38+
if err != nil {
39+
panic("bad")
40+
}
41+
var newval SerDeString
42+
newval.UnmarshalBinary(out)
43+
fmt.Printf("Sent %s\n", newval)
44+
}
45+
46+
func main() {
47+
val := SerDeString("asdf")
48+
x := GenericSerializable[*SerDeString]{
49+
Value: &val,
50+
}
51+
x.Send()
52+
}

test/typeparam/issue47713.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Sent asdf

test/typeparam/issue47877.go

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// run -gcflags=-G=3
2+
3+
// Copyright 2021 The Go Authors. All rights reserved.
4+
// Use of this source code is governed by a BSD-style
5+
// license that can be found in the LICENSE file.
6+
7+
package main
8+
9+
type Map[K comparable, V any] struct {
10+
m map[K]V
11+
}
12+
13+
func NewMap[K comparable, V any]() Map[K, V] {
14+
return Map[K, V]{m: map[K]V{}}
15+
}
16+
17+
func (m Map[K, V]) Get(key K) V {
18+
return m.m[key]
19+
}
20+
21+
func main() {
22+
_ = NewMap[int, struct{}]()
23+
}

0 commit comments

Comments
 (0)