]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: reuse same node for global dictionaries
authorDan Scales <danscales@google.com>
Mon, 23 Aug 2021 22:45:10 +0000 (15:45 -0700)
committerDan Scales <danscales@google.com>
Tue, 24 Aug 2021 00:01:29 +0000 (00:01 +0000)
Change stencil.go:getDictionaryValue() and reflect.go:getDictionary() to
reuse any existing name node that has been created for the needed global
dictionary. Otherwise, these functions may set the Def on a specific
dictionary sym to two different name nodes, which means the first node
will not satisfy the invariant 'n.Sym().Def.(*ir.Name) == n' (which is
the assertion in this issue).

Fixes #47896

Change-Id: I1e7ae1efd077a83c7878b4342feb6d28d52476cc
Reviewed-on: https://go-review.googlesource.com/c/go/+/344609
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Trust: Dan Scales <danscales@google.com>

src/cmd/compile/internal/noder/stencil.go
src/cmd/compile/internal/reflectdata/reflect.go
test/typeparam/issue47896.go [new file with mode: 0644]

index 2d275d6a3b2c12b59c2bd3ef7f2c40438ec8d3a5..570dec999045467b39d42f5e9b1873a23cda038c 100644 (file)
@@ -1579,12 +1579,17 @@ func (g *irgen) finalizeSyms() {
 func (g *irgen) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node {
        sym := g.getDictionarySym(gf, targs, isMeth)
 
-       // Make a node referencing the dictionary symbol.
-       n := typecheck.NewName(sym)
-       n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
-       n.SetTypecheck(1)
-       n.Class = ir.PEXTERN
-       sym.Def = n
+       // Make (or reuse) a node referencing the dictionary symbol.
+       var n *ir.Name
+       if sym.Def != nil {
+               n = sym.Def.(*ir.Name)
+       } else {
+               n = typecheck.NewName(sym)
+               n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
+               n.SetTypecheck(1)
+               n.Class = ir.PEXTERN
+               sym.Def = n
+       }
 
        // Return the address of the dictionary.
        np := typecheck.NodAddr(n)
index 3ba8f52541edca7bc581522be9ef1f85e19e0b11..a95c76ff268f0c071ca7e208ab98ba1a31768afd 100644 (file)
@@ -2047,12 +2047,17 @@ func getDictionary(gf *types.Sym, targs []*types.Type) ir.Node {
                base.Fatalf("Dictionary should have already been generated: %s.%s", sym.Pkg.Path, sym.Name)
        }
 
-       // Make a node referencing the dictionary symbol.
-       n := typecheck.NewName(sym)
-       n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
-       n.SetTypecheck(1)
-       n.Class = ir.PEXTERN
-       sym.Def = n
+       // Make (or reuse) a node referencing the dictionary symbol.
+       var n *ir.Name
+       if sym.Def != nil {
+               n = sym.Def.(*ir.Name)
+       } else {
+               n = typecheck.NewName(sym)
+               n.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
+               n.SetTypecheck(1)
+               n.Class = ir.PEXTERN
+               sym.Def = n
+       }
 
        // Return the address of the dictionary.
        np := typecheck.NodAddr(n)
diff --git a/test/typeparam/issue47896.go b/test/typeparam/issue47896.go
new file mode 100644 (file)
index 0000000..1b2f265
--- /dev/null
@@ -0,0 +1,74 @@
+//  compile -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
+
+import (
+       "database/sql"
+)
+
+// Collection generic interface which things can be added to.
+type Collection[T any] interface {
+       Add(T)
+}
+
+// Slice generic slice implementation of a Collection
+type Slice[T any] []*T
+
+func (s *Slice[T]) Add(t *T) {
+       *s = append(*s, t)
+}
+
+type Scanner interface {
+       Scan(...interface{}) error
+}
+
+type Mapper[T any] func(s Scanner, t T) error
+
+type Repository[T any] struct {
+       db *sql.DB
+}
+
+func (r *Repository[T]) scan(rows *sql.Rows, m Mapper[*T], c Collection[*T]) error {
+       for rows.Next() {
+               t := new(T)
+               if err := m(rows, t); err != nil {
+                       return err
+               }
+               c.Add(t)
+       }
+       return rows.Err()
+}
+
+func (r *Repository[T]) query(query string, m Mapper[*T], c Collection[*T]) error {
+       rows, err := r.db.Query(query)
+       if err != nil {
+               return err
+       }
+       if err := r.scan(rows, m, c); err != nil {
+               rows.Close()
+               return err
+       }
+       return rows.Close()
+}
+
+type Actor struct {
+       ActorID   uint16
+       FirstName string
+       LastName  string
+}
+
+type ActorRepository struct {
+       r Repository[Actor]
+}
+
+func (ActorRepository) scan(s Scanner, a *Actor) error {
+       return s.Scan(&a.ActorID, &a.FirstName, &a.LastName)
+}
+
+func (r *ActorRepository) SelectAll(c Collection[*Actor]) error {
+       return r.r.query("SELECT `actor_id`, `first_name`, `last_name` FROM `actor` LIMIT 10", r.scan, c)
+}