mirror of
https://github.com/golang/go
synced 2024-11-22 23:50:03 -07: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:
parent
1bad3831a0
commit
fdded79e6e
@ -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))
|
||||
|
@ -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"})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user