]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: resolve dictionaries/shape methods in markInlBody, if needed
authorDan Scales <danscales@google.com>
Tue, 11 Jan 2022 17:14:38 +0000 (09:14 -0800)
committerDan Scales <danscales@google.com>
Tue, 11 Jan 2022 21:51:51 +0000 (21:51 +0000)
Issue #50552 is due to a problem with my recent improvement in the
interaction between generics and inlining. In markInlBody(), we now mark
dictionaries and shape methods for export, so they will be available for
any package that inlines the current inlineable function. But we need to
make sure that the dictionary and method symbols have actually been
resolved into Nodes (looked up in the import data), if they are not
already defined, so we can then mark them for export.

Improved header comment on Resolve().

Fixes #50552

Change-Id: I89e52d39d3b9894591d2ad6eb3a8ed3bb5f1e0a0
Reviewed-on: https://go-review.googlesource.com/c/go/+/377714
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>

src/cmd/compile/internal/typecheck/crawler.go
src/cmd/compile/internal/typecheck/typecheck.go
test/run.go
test/typeparam/issue50552.dir/a.go [new file with mode: 0644]
test/typeparam/issue50552.dir/main.go [new file with mode: 0644]
test/typeparam/issue50552.go [new file with mode: 0644]

index cdb1c46509b93188448cdfc15ca59be76611d14d..87dc5165fd3f37950be51a51a487f88ad3854498 100644 (file)
@@ -8,6 +8,7 @@ import (
        "cmd/compile/internal/base"
        "cmd/compile/internal/ir"
        "cmd/compile/internal/types"
+       "cmd/internal/src"
 )
 
 // crawlExports crawls the type/object graph rooted at the given list of exported
@@ -241,11 +242,12 @@ func (p *crawler) markInlBody(n *ir.Name) {
                        if t.IsFullyInstantiated() && !t.HasShape() && !t.IsInterface() && t.Methods().Len() > 0 {
                                // For any fully-instantiated type, the relevant
                                // dictionaries and shape instantiations will have
-                               // already been created. Make sure that they are
-                               // exported, so that any other package that inlines
-                               // this function will have them available for import,
-                               // and so will not need another round of method and
-                               // dictionary instantiation after inlining.
+                               // already been created or are in the import data.
+                               // Make sure that they are exported, so that any
+                               // other package that inlines this function will have
+                               // them available for import, and so will not need
+                               // another round of method and dictionary
+                               // instantiation after inlining.
                                baseType := t.OrigSym().Def.(*ir.Name).Type()
                                shapes := make([]*types.Type, len(t.RParams()))
                                for i, t1 := range t.RParams() {
@@ -254,8 +256,16 @@ func (p *crawler) markInlBody(n *ir.Name) {
                                for j := range t.Methods().Slice() {
                                        baseNname := baseType.Methods().Slice()[j].Nname.(*ir.Name)
                                        dictsym := MakeDictSym(baseNname.Sym(), t.RParams(), true)
+                                       if dictsym.Def == nil {
+                                               in := Resolve(ir.NewIdent(src.NoXPos, dictsym))
+                                               dictsym = in.Sym()
+                                       }
                                        Export(dictsym.Def.(*ir.Name))
                                        methsym := MakeFuncInstSym(baseNname.Sym(), shapes, false, true)
+                                       if methsym.Def == nil {
+                                               in := Resolve(ir.NewIdent(src.NoXPos, methsym))
+                                               methsym = in.Sym()
+                                       }
                                        methNode := methsym.Def.(*ir.Name)
                                        Export(methNode)
                                        if HaveInlineBody(methNode.Func) {
index 42970f6a5e279fa4a133c2d56d946d7d3dbfe9b2..f6be298667eb5d3877ff4b452b618b3a08f947f0 100644 (file)
@@ -129,7 +129,11 @@ const (
 
 var typecheckdefstack []*ir.Name
 
-// Resolve ONONAME to definition, if any.
+// Resolve resolves an ONONAME node to a definition, if any. If n is not an ONONAME node,
+// Resolve returns n unchanged. If n is an ONONAME node and not in the same package,
+// then n.Sym() is resolved using import data. Otherwise, Resolve returns
+// n.Sym().Def. An ONONAME node can be created using ir.NewIdent(), so an imported
+// symbol can be resolved via Resolve(ir.NewIdent(src.NoXPos, sym)).
 func Resolve(n ir.Node) (res ir.Node) {
        if n == nil || n.Op() != ir.ONONAME {
                return n
index 278d5efce93345656ba89b4856420649a6c11a49..75073993b875236a7b31ab4ffcf390f0b26c443b 100644 (file)
@@ -2178,6 +2178,7 @@ var unifiedFailures = setOf(
        "typeparam/typeswitch2.go", // duplicate case failure due to stenciling
        "typeparam/typeswitch3.go", // duplicate case failure due to stenciling
        "typeparam/typeswitch4.go", // duplicate case failure due to stenciling
+       "typeparam/issue50552.go",  // gives missing method for instantiated type
 )
 
 func setOf(keys ...string) map[string]bool {
diff --git a/test/typeparam/issue50552.dir/a.go b/test/typeparam/issue50552.dir/a.go
new file mode 100644 (file)
index 0000000..89b9bcb
--- /dev/null
@@ -0,0 +1,16 @@
+package a
+
+type Builder[T any] struct{}
+
+func (r Builder[T]) New() T {
+       var v T
+       return v
+}
+
+func (r Builder[T]) New2() T {
+       return r.New()
+}
+
+func BuildInt() int {
+       return Builder[int]{}.New()
+}
diff --git a/test/typeparam/issue50552.dir/main.go b/test/typeparam/issue50552.dir/main.go
new file mode 100644 (file)
index 0000000..047c27e
--- /dev/null
@@ -0,0 +1,20 @@
+// 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.
+
+package main
+
+import (
+       "a"
+       "fmt"
+)
+
+func BuildInt() int {
+       return a.BuildInt()
+}
+
+func main() {
+       if got, want := BuildInt(), 0; got != want {
+               panic(fmt.Sprintf("got %d, want %d", got, want))
+       }
+}
diff --git a/test/typeparam/issue50552.go b/test/typeparam/issue50552.go
new file mode 100644 (file)
index 0000000..87b4ff4
--- /dev/null
@@ -0,0 +1,7 @@
+// compiledir -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 ignored