]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: fix reflect naming of local generic types
authorMatthew Dempsky <mdempsky@google.com>
Thu, 18 Aug 2022 22:16:23 +0000 (15:16 -0700)
committerMatthew Dempsky <mdempsky@google.com>
Tue, 23 Aug 2022 18:13:48 +0000 (18:13 +0000)
To disambiguate local types, we append a "·N" suffix to their name and
then trim it off again when producing their runtime type descriptors.

However, if a local type is generic, then we were further appending
the type arguments after this suffix, and the code in types/fmt.go
responsible for trimming didn't know to handle this.

We could extend the types/fmt.go code to look for the "·N" suffix
elsewhere in the type name, but this is risky because it could
legitimately (albeit unlikely) appear in struct field tags.

Instead, the most robust solution is to just change the mangling logic
to keep the "·N" suffix at the end, where types/fmt.go can easily and
reliably trim it.

Note: the "·N" suffix is still visible within the type arguments
list (e.g., the "·3" suffixes in nested.out), because we currently use
the link strings in the type arguments list.

Fixes #54456.

Change-Id: Ie9beaf7e5330982f539bff57b8d48868a3674a37
Reviewed-on: https://go-review.googlesource.com/c/go/+/424901
TryBot-Result: Gopher Robot <gobot@golang.org>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Than McIntosh <thanm@google.com>
src/cmd/compile/internal/noder/reader.go
src/cmd/compile/internal/noder/writer.go
src/cmd/compile/internal/types/fmt.go
test/run.go
test/typeparam/issue54456.go [new file with mode: 0644]
test/typeparam/nested.out

index 1acc8c7fb6eb1f04228ad9f35ff088eebba18713..5f770166dbc1ad2ad65e164a3320820566b46d24 100644 (file)
@@ -777,8 +777,13 @@ func (dict *readerDict) mangle(sym *types.Sym) *types.Sym {
                return sym
        }
 
+       // If sym is a locally defined generic type, we need the suffix to
+       // stay at the end after mangling so that types/fmt.go can strip it
+       // out again when writing the type's runtime descriptor (#54456).
+       base, suffix := types.SplitVargenSuffix(sym.Name)
+
        var buf strings.Builder
-       buf.WriteString(sym.Name)
+       buf.WriteString(base)
        buf.WriteByte('[')
        for i, targ := range dict.targs {
                if i > 0 {
@@ -791,6 +796,7 @@ func (dict *readerDict) mangle(sym *types.Sym) *types.Sym {
                buf.WriteString(targ.LinkString())
        }
        buf.WriteByte(']')
+       buf.WriteString(suffix)
        return sym.Pkg.Lookup(buf.String())
 }
 
index d9cd1cbd323415b7a13f4b217b4541ac1e5213ba..c2c3567220a1569528ccc32cdb4a5877b00577d7 100644 (file)
@@ -933,8 +933,11 @@ func (w *writer) qualifiedIdent(obj types2.Object) {
                decl, ok := w.p.typDecls[obj.(*types2.TypeName)]
                assert(ok)
                if decl.gen != 0 {
-                       // TODO(mdempsky): Find a better solution than embedding middle
-                       // dot in the symbol name; this is terrible.
+                       // For local defined types, we embed a scope-disambiguation
+                       // number directly into their name. types.SplitVargenSuffix then
+                       // knows to look for this.
+                       //
+                       // TODO(mdempsky): Find a better solution; this is terrible.
                        name = fmt.Sprintf("%s·%v", name, decl.gen)
                }
        }
index c1138643b72e669a21b16a2cfc829b5e8977aadd..c6e99d26c265d7668b1fa6603d5ff3fc2b66b91c 100644 (file)
@@ -340,13 +340,9 @@ func tconv2(b *bytes.Buffer, t *Type, verb rune, mode fmtMode, visited map[*Type
                // non-fmtTypeID modes.
                sym := t.Sym()
                if mode != fmtTypeID {
-                       i := len(sym.Name)
-                       for i > 0 && sym.Name[i-1] >= '0' && sym.Name[i-1] <= '9' {
-                               i--
-                       }
-                       const dot = "·"
-                       if i >= len(dot) && sym.Name[i-len(dot):i] == dot {
-                               sym = &Sym{Pkg: sym.Pkg, Name: sym.Name[:i-len(dot)]}
+                       base, _ := SplitVargenSuffix(sym.Name)
+                       if len(base) < len(sym.Name) {
+                               sym = &Sym{Pkg: sym.Pkg, Name: base}
                        }
                }
                sconv2(b, sym, verb, mode)
@@ -704,6 +700,21 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
        }
 }
 
+// SplitVargenSuffix returns name split into a base string and a ·N
+// suffix, if any.
+func SplitVargenSuffix(name string) (base, suffix string) {
+       i := len(name)
+       for i > 0 && name[i-1] >= '0' && name[i-1] <= '9' {
+               i--
+       }
+       const dot = "·"
+       if i >= len(dot) && name[i-len(dot):i] == dot {
+               i -= len(dot)
+               return name[:i], name[i:]
+       }
+       return name, ""
+}
+
 // Val
 
 func FmtConst(v constant.Value, sharp bool) string {
index 21f0f7d634cec6df073585a62b3ab1b0a6d084b4..58d09b6b59f0db5779e7aff72486cceee04cc552 100644 (file)
@@ -1990,6 +1990,7 @@ var go118Failures = setOf(
        "fixedbugs/issue54343.go",  // 1.18 compiler assigns receiver parameter to global variable
        "typeparam/nested.go",      // 1.18 compiler doesn't support function-local types with generics
        "typeparam/issue51521.go",  // 1.18 compiler produces bad panic message and link error
+       "typeparam/issue54456.go",  // 1.18 compiler fails to distinguish local generic types
        "typeparam/issue54497.go",  // 1.18 compiler is more conservative about inlining due to repeated issues
        "typeparam/mdempsky/16.go", // 1.18 compiler uses interface shape type in failed type assertions
        "typeparam/mdempsky/17.go", // 1.18 compiler mishandles implicit conversions from range loops
diff --git a/test/typeparam/issue54456.go b/test/typeparam/issue54456.go
new file mode 100644 (file)
index 0000000..8342163
--- /dev/null
@@ -0,0 +1,37 @@
+// run
+
+// Copyright 2022 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.
+
+// The Go 1.18 frontend failed to disambiguate instantiations of
+// different, locally defined generic types with the same name.
+//
+// The unified frontend also exposed the scope-disambiguation mangling
+// to end users in reflect data.
+
+package main
+
+import (
+       "reflect"
+)
+
+func one() any { type T[_ any] int; return T[int](0) }
+func two() any { type T[_ any] int; return T[int](0) }
+
+func main() {
+       p, q := one(), two()
+
+       // p and q have different dynamic types; this comparison should
+       // evaluate false.
+       if p == q {
+               panic("bad type identity")
+       }
+
+       for _, x := range []any{p, q} {
+               // The names here should not contain "·1" or "·2".
+               if name := reflect.TypeOf(x).String(); name != "main.T[int]" {
+                       panic(name)
+               }
+       }
+}
index 37cb762e32baacdb79c6bcb980f081664b8a7560..0836d9b0dc06421c8927a92edbc7de0772e462b1 100644 (file)
@@ -1,4 +1,4 @@
-0,3: main.T·2[int;int]
-4,7: main.T·2[int;main.U·3[int;int]]
-22,23: main.T·2[main.Int;main.Int]
-26,27: main.T·2[main.Int;main.U·3[main.Int;main.Int]]
+0,3: main.T[int;int]
+4,7: main.T[int;main.U[int;int]·3]
+22,23: main.T[main.Int;main.Int]
+26,27: main.T[main.Int;main.U[main.Int;main.Int]·3]