go/types: avoid closure allocations in mono check

This CL replaces monoEdge's "report" field with fields "pos" and
"typ", and pushes the logic for formatting them into the report
loop. This avoids needing to allocate a function closure for each
edge.

Also tweak a test case so the two type parameters involved in the
cycle aren't both "T" so they're easier to understand.

Change-Id: I9d392ad1d99a4c5e89da4613084e885149ebad07
Reviewed-on: https://go-review.googlesource.com/c/go/+/360815
Trust: Matthew Dempsky <mdempsky@google.com>
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2021-11-02 11:23:34 -07:00
parent 1011e26b9c
commit c45c32b1cd
2 changed files with 24 additions and 20 deletions

View file

@ -71,14 +71,11 @@ type monoVertex struct {
} }
type monoEdge struct { type monoEdge struct {
dst int dst, src int
src int
weight int weight int
// report emits an error describing why this edge exists. pos token.Pos
// typ Type
// TODO(mdempsky): Avoid requiring a function closure for each edge.
report func(check *Checker)
} }
func (check *Checker) monomorph() { func (check *Checker) monomorph() {
@ -139,12 +136,22 @@ func (check *Checker) reportInstanceLoop(v int) {
// TODO(mdempsky): Pivot stack so we report the cycle from the top? // TODO(mdempsky): Pivot stack so we report the cycle from the top?
obj := check.mono.vertices[v].obj obj0 := check.mono.vertices[v].obj
check.errorf(obj, _InvalidInstanceCycle, "instantiation cycle:") check.errorf(obj0, _InvalidInstanceCycle, "instantiation cycle:")
qf := RelativeTo(check.pkg)
for _, v := range stack { for _, v := range stack {
edge := check.mono.edges[check.mono.vertices[v].pre] edge := check.mono.edges[check.mono.vertices[v].pre]
edge.report(check) obj := check.mono.vertices[edge.dst].obj
switch obj.Type().(type) {
default:
panic("unexpected type")
case *Named:
check.errorf(atPos(edge.pos), _InvalidInstanceCycle, "\t%s implicitly parameterized by %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
case *TypeParam:
check.errorf(atPos(edge.pos), _InvalidInstanceCycle, "\t%s instantiated as %s", obj.Name(), TypeString(edge.typ, qf)) // secondary error, \t indented
}
} }
} }
@ -190,10 +197,7 @@ func (w *monoGraph) assign(pkg *Package, pos token.Pos, tpar *TypeParam, targ Ty
weight = 0 weight = 0
} }
w.addEdge(w.typeParamVertex(tpar), src, weight, func(check *Checker) { w.addEdge(w.typeParamVertex(tpar), src, weight, pos, targ)
qf := RelativeTo(check.pkg)
check.errorf(atPos(pos), _InvalidInstanceCycle, "\t%s instantiated as %s", tpar.Obj().Name(), TypeString(targ, qf)) // secondary error, \t indented
})
} }
// Recursively walk the type argument to find any defined types or // Recursively walk the type argument to find any defined types or
@ -283,9 +287,7 @@ func (w *monoGraph) localNamedVertex(pkg *Package, named *Named) int {
w.vertices = append(w.vertices, monoVertex{obj: obj}) w.vertices = append(w.vertices, monoVertex{obj: obj})
} }
w.addEdge(idx, w.typeParamVertex(tpar), 1, func(check *Checker) { w.addEdge(idx, w.typeParamVertex(tpar), 1, obj.Pos(), tpar)
check.errorf(obj, _InvalidInstanceCycle, "\t%s implicitly parameterized by %s", obj.Name(), elem.Name())
})
} }
} }
} }
@ -320,12 +322,14 @@ func (w *monoGraph) typeParamVertex(tpar *TypeParam) int {
return idx return idx
} }
func (w *monoGraph) addEdge(dst, src, weight int, report func(check *Checker)) { func (w *monoGraph) addEdge(dst, src, weight int, pos token.Pos, typ Type) {
// TODO(mdempsky): Deduplicate redundant edges? // TODO(mdempsky): Deduplicate redundant edges?
w.edges = append(w.edges, monoEdge{ w.edges = append(w.edges, monoEdge{
dst: dst, dst: dst,
src: src, src: src,
weight: weight, weight: weight,
report: report,
pos: pos,
typ: typ,
}) })
} }

View file

@ -84,7 +84,7 @@ var bads = []string{
"func F[T any]() { type U int; F[*U]() }", "func F[T any]() { type U int; F[*U]() }",
"type U[T any] int; func (U[T]) m() { var _ U[*T] }", "type U[T any] int; func (U[T]) m() { var _ U[*T] }",
"type U[T any] int; func (*U[T]) m() { var _ U[*T] }", "type U[T any] int; func (*U[T]) m() { var _ U[*T] }",
"type U[T any] [unsafe.Sizeof(F[*T])]byte; func F[T any]() { var _ U[T] }", "type U[T1 any] [unsafe.Sizeof(F[*T1])]byte; func F[T2 any]() { var _ U[T2] }",
"func F[A, B, C, D, E any]() { F[B, C, D, E, *A]() }", "func F[A, B, C, D, E any]() { F[B, C, D, E, *A]() }",
"type U[_ any] int; const X = unsafe.Sizeof(func() { type A[T any] U[A[*T]] })", "type U[_ any] int; const X = unsafe.Sizeof(func() { type A[T any] U[A[*T]] })",
"func F[T any]() { type A = *T; F[A]() }", "func F[T any]() { type A = *T; F[A]() }",