Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 5 additions & 22 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -1015,28 +1015,8 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
n.typ = valueTOf(t.rtype.Elem())
}
case funcT:
// A function indexed by a type means an instantiated generic function.
c1 := n.child[1]
if !c1.isType(sc) {
n.typ = t
return
}
g, found, err := genAST(sc, t.node.anc, []*itype{c1.typ})
if err != nil {
return
}
if !found {
if _, err = interp.cfg(g, t.node.anc.scope, importPath, pkgName); err != nil {
return
}
// Generate closures for function body.
if err = genRun(g.child[3]); err != nil {
return
}
}
// Replace generic func node by instantiated one.
n.anc.child[childPos(n)] = g
n.typ = g.typ
// A function indexed by a type. Leave this to the callExpr,
// since we may need partial type inference.
return
case genericT:
name := t.id() + "[" + n.child[1].typ.id() + "]"
Expand Down Expand Up @@ -1179,6 +1159,9 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
}
wireChild(n)
switch c0 := n.child[0]; {
case c0.kind == indexExpr && c0.typ == nil:
c0.gen = nop
fallthrough
case c0.kind == indexListExpr:
// Instantiate a generic function then call it.
fun := c0.child[0].sym.node
Expand Down
33 changes: 33 additions & 0 deletions interp/interp_eval_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,39 @@ func TestEvalFunctionCallWithFunctionParam(t *testing.T) {
}
}

func TestEvalFunctionPartialInference(t *testing.T) {
i := interp.New(interp.Options{})
eval(t, i, `
func indexExpr[T, U any](v U) U { return v }

func indexListExpr[T, U, V any](v V) V { return v }
`)

t.Run("one explicit param", func(t *testing.T) {
v := eval(t, i, "noindexExpr[string](12)")
iv, ok := v.Interface().(int)
if !ok {
t.Fatalf("unexpected return type: got %T, want int", v)
}
want := 12
if iv != want {
t.Fatalf("unexpected value: got %v, want %v", i, want)
}
})

t.Run("multiple explicit params", func(t *testing.T) {
v := eval(t, i, "noindexListExpr[string, string](12)")
iv, ok := v.Interface().(int)
if !ok {
t.Fatalf("unexpected return type: got %T, want int", v)
}
want := 12
if iv != want {
t.Fatalf("unexpected value: got %v, want %v", i, want)
}
})
}

func TestEvalCall(t *testing.T) {
i := interp.New(interp.Options{})
runTests(t, i, []testCase{
Expand Down