1
0
mirror of https://github.com/golang/go synced 2024-09-23 17:20:13 -06:00

cmd/compile: fix handling of partially inferred type arguments

In the case of partially inferred type arguments, we need to use the
IndexExpr as the key in g.info.Inferred[] rather than the CallExpr.

Added an extra fromStrings1 call in the settable.go test that tests
partially inferred type arguments. This new call uses a new concrete
type SettableString as well.

I also added another implementation fromStrings3 (derived from a go2go
tests) that typechecks but intentionally causes a panic.

Change-Id: I74d35c5a741f72f37160a96fbec939451157f392
Reviewed-on: https://go-review.googlesource.com/c/go/+/300309
Run-TryBot: Dan Scales <danscales@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Trust: Dan Scales <danscales@google.com>
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Dan Scales 2021-03-09 18:24:51 -08:00
parent 1bad3831a0
commit fdded79e6e
2 changed files with 61 additions and 6 deletions

View File

@ -96,7 +96,17 @@ func (g *irgen) expr0(typ types2.Type, expr syntax.Expr) ir.Node {
case *syntax.CallExpr:
fun := g.expr(expr.Fun)
if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.Targs) > 0 {
// The key for the Inferred map is usually the expr.
key := syntax.Expr(expr)
if _, ok := expr.Fun.(*syntax.IndexExpr); ok {
// If the Fun is an IndexExpr, then this may be a
// partial type inference case. In this case, we look up
// the IndexExpr in the Inferred map.
// TODO(gri): should types2 always record the callExpr as the key?
key = syntax.Expr(expr.Fun)
}
if inferred, ok := g.info.Inferred[key]; ok && len(inferred.Targs) > 0 {
targs := make([]ir.Node, len(inferred.Targs))
for i, targ := range inferred.Targs {
targs[i] = ir.TypeNode(g.typ(targ))

View File

@ -11,11 +11,14 @@ import (
"strconv"
)
// Various implementations of fromStrings().
type _Setter[B any] interface {
Set(string)
type *B
}
// Takes two type parameters where PT = *T
func fromStrings1[T any, PT _Setter[T]](s []string) []T {
result := make([]T, len(s))
for i, v := range s {
@ -28,6 +31,7 @@ func fromStrings1[T any, PT _Setter[T]](s []string) []T {
return result
}
// Takes one type parameter and a set function
func fromStrings2[T any](s []string, set func(*T, string)) []T {
results := make([]T, len(s))
for i, v := range s {
@ -36,24 +40,65 @@ func fromStrings2[T any](s []string, set func(*T, string)) []T {
return results
}
type Settable int
type _Setter2 interface {
Set(string)
}
func (p *Settable) Set(s string) {
// Takes only one type parameter, but causes a panic (see below)
func fromStrings3[T _Setter2](s []string) []T {
results := make([]T, len(s))
for i, v := range s {
// Panics if T is a pointer type because receiver is T(nil).
results[i].Set(v)
}
return results
}
// Two concrete types with the appropriate Set method.
type SettableInt int
func (p *SettableInt) Set(s string) {
i, err := strconv.Atoi(s)
if err != nil {
panic(err)
}
*p = Settable(i)
*p = SettableInt(i)
}
type SettableString struct {
s string
}
func (x *SettableString) Set(s string) {
x.s = s
}
func main() {
s := fromStrings1[Settable, *Settable]([]string{"1"})
s := fromStrings1[SettableInt, *SettableInt]([]string{"1"})
if len(s) != 1 || s[0] != 1 {
panic(fmt.Sprintf("got %v, want %v", s, []int{1}))
}
s = fromStrings2([]string{"1"}, func(p *Settable, s string) { p.Set(s) })
// Test out constraint type inference, which should determine that the second
// type param is *SettableString.
ps := fromStrings1[SettableString]([]string{"x", "y"})
if len(ps) != 2 || ps[0] != (SettableString{"x"}) || ps[1] != (SettableString{"y"}) {
panic(s)
}
s = fromStrings2([]string{"1"}, func(p *SettableInt, s string) { p.Set(s) })
if len(s) != 1 || s[0] != 1 {
panic(fmt.Sprintf("got %v, want %v", s, []int{1}))
}
defer func() {
if recover() == nil {
panic("did not panic as expected")
}
}()
// This should type check but should panic at run time,
// because it will make a slice of *SettableInt and then call
// Set on a nil value.
fromStrings3[*SettableInt]([]string{"1"})
}