]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: unique LinkString for renamed, embedded fields
authorMatthew Dempsky <mdempsky@google.com>
Thu, 16 Dec 2021 20:55:15 +0000 (12:55 -0800)
committerMatthew Dempsky <mdempsky@google.com>
Mon, 10 Jan 2022 17:54:35 +0000 (17:54 +0000)
Using type aliases, it's possible to create structs with embedded
fields that have no corresponding type literal notation. However, we
still need to generate a unique name for these types to use for linker
symbols. This CL introduces a new "struct{ Name = Type }" syntax for
use in LinkString formatting to represent these types.

Fixes #50190.

Change-Id: I025ceb09a86e00b7583d3b9885d612f5d6cb44fe
Reviewed-on: https://go-review.googlesource.com/c/go/+/372914
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
Trust: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Dan Scales <danscales@google.com>
Trust: Dan Scales <danscales@google.com>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/cmd/compile/internal/types/fmt.go
test/fixedbugs/issue50190.go [new file with mode: 0644]

index 3198a1f53c8674c6234d6d2fcaa1eb402718a36f..13994834241652c292e9518be134c2c8a5df6e2e 100644 (file)
@@ -631,6 +631,7 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
        }
 
        var name string
+       nameSep := " "
        if verb != 'S' {
                s := f.Sym
 
@@ -639,9 +640,41 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
                        s = OrigSym(s)
                }
 
-               if s != nil && f.Embedded == 0 {
+               if s != nil {
                        if funarg != FunargNone {
                                name = fmt.Sprint(f.Nname)
+                       } else if f.Embedded != 0 {
+                               // Using type aliases and embedded fields, it's possible to
+                               // construct types that can't be directly represented as a
+                               // type literal. For example, given "type Int = int" (#50190),
+                               // it would be incorrect to format "struct{ Int }" as either
+                               // "struct{ int }" or "struct{ Int int }", because those each
+                               // represent other, distinct types.
+                               //
+                               // So for the purpose of LinkString (i.e., fmtTypeID), we use
+                               // the non-standard syntax "struct{ Int = int }" to represent
+                               // embedded fields that have been renamed through the use of
+                               // type aliases.
+                               if mode == fmtTypeID {
+                                       // Compute styp, the symbol that would normally be used as
+                                       // the field name when embedding f.Type.
+                                       // TODO(mdempsky): Check for other occurences of this logic
+                                       // and deduplicate.
+                                       typ := f.Type
+                                       if typ.Sym() == nil && typ.IsPtr() {
+                                               typ = typ.Elem()
+                                       }
+                                       styp := typ.Sym()
+                                       if styp != nil && IsExported(styp.Name) {
+                                               styp = LocalPkg.Lookup(styp.Name)
+                                       }
+
+                                       // If embedded field was renamed, use syntax extension.
+                                       if s != styp {
+                                               name = sconv(s, 0, mode)
+                                               nameSep = " = "
+                                       }
+                               }
                        } else if verb == 'L' {
                                name = s.Name
                                if name == ".F" {
@@ -658,7 +691,7 @@ func fldconv(b *bytes.Buffer, f *Field, verb rune, mode fmtMode, visited map[*Ty
 
        if name != "" {
                b.WriteString(name)
-               b.WriteString(" ")
+               b.WriteString(nameSep)
        }
 
        if f.IsDDD() {
diff --git a/test/fixedbugs/issue50190.go b/test/fixedbugs/issue50190.go
new file mode 100644 (file)
index 0000000..01ff6ea
--- /dev/null
@@ -0,0 +1,21 @@
+// run
+
+// 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 int float32
+
+type Int = int
+
+type A = struct{ int }
+type B = struct{ Int }
+
+func main() {
+       var x, y interface{} = A{}, B{}
+       if x == y {
+               panic("FAIL")
+       }
+}