case *syntax.CallExpr:
fun := g.expr(expr.Fun)
- // 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 {
+ // The key for the Inferred map is the CallExpr (if inferring
+ // types required the function arguments) or the IndexExpr below
+ // (if types could be inferred without the function arguments).
+ if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.Targs) > 0 {
+ // This is the case where inferring types required the
+ // types of the function arguments.
targs := make([]ir.Node, len(inferred.Targs))
for i, targ := range inferred.Targs {
targs[i] = ir.TypeNode(g.typ(targ))
case *syntax.IndexExpr:
var targs []ir.Node
- if _, ok := expr.Index.(*syntax.ListExpr); ok {
+
+ if inferred, ok := g.info.Inferred[expr]; ok && len(inferred.Targs) > 0 {
+ // This is the partial type inference case where the types
+ // can be inferred from other type arguments without using
+ // the types of the function arguments.
+ targs = make([]ir.Node, len(inferred.Targs))
+ for i, targ := range inferred.Targs {
+ targs[i] = ir.TypeNode(g.typ(targ))
+ }
+ } else if _, ok := expr.Index.(*syntax.ListExpr); ok {
targs = g.exprList(expr.Index)
} else {
index := g.expr(expr.Index)
// This is generic function instantiation with a single type
targs = []ir.Node{index}
}
- // This is a generic function instantiation (e.g. min[int])
+ // This is a generic function instantiation (e.g. min[int]).
+ // Generic type instantiation is handled in the type
+ // section of expr() above (using g.typ).
x := g.expr(expr.X)
if x.Op() != ir.ONAME || x.Type().Kind() != types.TFUNC {
panic("Incorrect argument for generic func instantiation")
}
- // This could also be an OTYPEINST once we can handle those examples.
n := ir.NewInstExpr(pos, ir.OFUNCINST, x, targs)
typed(g.typ(typ), n)
return n
func _[V any, T interface { type map[string]V }](p T) V {
return p["test"]
}
+
+
+// Testing partial and full type inference, including the case where the types can
+// be inferred without needing the types of the function arguments.
+
+func f0[A any, B interface{type C}, C interface{type D}, D interface{type A}](a A, b B, c C, d D)
+func _() {
+ f := f0[string]
+ f("a", "b", "c", "d")
+ f0("a", "b", "c", "d")
+}
+
+func f1[A any, B interface{type A}](a A, b B)
+func _() {
+ f := f1[int]
+ f(int(0), int(0))
+ f1(int(0), int(0))
+ f(0, 0)
+ f1(0, 0)
+}
+
+func f2[A any, B interface{type []A}](a A, b B)
+func _() {
+ f := f2[byte]
+ f(byte(0), []byte{})
+ f2(byte(0), []byte{})
+ f(0, []byte{})
+ // f2(0, []byte{}) - this one doesn't work
+}
+
+func f3[A any, B interface{type C}, C interface{type *A}](a A, b B, c C)
+func _() {
+ f := f3[int]
+ var x int
+ f(x, &x, &x)
+ f3(x, &x, &x)
+}
+
+func f4[A any, B interface{type []C}, C interface{type *A}](a A, b B, c C)
+func _() {
+ f := f4[int]
+ var x int
+ f(x, []*int{}, &x)
+ f4(x, []*int{}, &x)
+}
+
+func f5[A interface{type struct{b B; c C}}, B any, C interface{type *B}](x B) A
+func _() {
+ x := f5(1.2)
+ var _ float64 = x.b
+ var _ float64 = *x.c
+}
+
+func f6[A any, B interface{type struct{f []A}}](B) A
+func _() {
+ x := f6(struct{f []string}{})
+ var _ string = x
+}