mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: reuse same node for global dictionaries
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>
This commit is contained in:
parent
be1a693477
commit
8eeb1bff1d
3 changed files with 96 additions and 12 deletions
|
|
@ -1579,12 +1579,17 @@ func (g *irgen) finalizeSyms() {
|
||||||
func (g *irgen) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node {
|
func (g *irgen) getDictionaryValue(gf *ir.Name, targs []*types.Type, isMeth bool) ir.Node {
|
||||||
sym := g.getDictionarySym(gf, targs, isMeth)
|
sym := g.getDictionarySym(gf, targs, isMeth)
|
||||||
|
|
||||||
// Make a node referencing the dictionary symbol.
|
// Make (or reuse) a node referencing the dictionary symbol.
|
||||||
n := typecheck.NewName(sym)
|
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.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
n.Class = ir.PEXTERN
|
n.Class = ir.PEXTERN
|
||||||
sym.Def = n
|
sym.Def = n
|
||||||
|
}
|
||||||
|
|
||||||
// Return the address of the dictionary.
|
// Return the address of the dictionary.
|
||||||
np := typecheck.NodAddr(n)
|
np := typecheck.NodAddr(n)
|
||||||
|
|
|
||||||
|
|
@ -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)
|
base.Fatalf("Dictionary should have already been generated: %s.%s", sym.Pkg.Path, sym.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make a node referencing the dictionary symbol.
|
// Make (or reuse) a node referencing the dictionary symbol.
|
||||||
n := typecheck.NewName(sym)
|
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.SetType(types.Types[types.TUINTPTR]) // should probably be [...]uintptr, but doesn't really matter
|
||||||
n.SetTypecheck(1)
|
n.SetTypecheck(1)
|
||||||
n.Class = ir.PEXTERN
|
n.Class = ir.PEXTERN
|
||||||
sym.Def = n
|
sym.Def = n
|
||||||
|
}
|
||||||
|
|
||||||
// Return the address of the dictionary.
|
// Return the address of the dictionary.
|
||||||
np := typecheck.NodAddr(n)
|
np := typecheck.NodAddr(n)
|
||||||
|
|
|
||||||
74
test/typeparam/issue47896.go
Normal file
74
test/typeparam/issue47896.go
Normal file
|
|
@ -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)
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue