aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cmd/compile/internal/noder/stencil.go17
-rw-r--r--src/cmd/compile/internal/reflectdata/reflect.go17
-rw-r--r--test/typeparam/issue47896.go74
3 files changed, 96 insertions, 12 deletions
diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go
index 2d275d6a3b..570dec9990 100644
--- a/src/cmd/compile/internal/noder/stencil.go
+++ b/src/cmd/compile/internal/noder/stencil.go
@@ -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)
diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go
index 3ba8f52541..a95c76ff26 100644
--- a/src/cmd/compile/internal/reflectdata/reflect.go
+++ b/src/cmd/compile/internal/reflectdata/reflect.go
@@ -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
index 0000000000..1b2f265cc1
--- /dev/null
+++ b/test/typeparam/issue47896.go
@@ -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)
+}