Skip to content

Commit

Permalink
interp: improve internal handling of functions
Browse files Browse the repository at this point in the history
Up to now functions could be stored as node values in frame (as for interpreter defined functions) or function values, directly callable by the Go runtime. We now always store functions in the later form, making the processing of functions, anonymous closures and methods simpler and more robust. All functions, once compiled are always directly callable, with no further wrapping necessary.

Fixes #1459.
  • Loading branch information
mvertes authored Oct 19, 2022
1 parent 6b8c94e commit e003140
Show file tree
Hide file tree
Showing 10 changed files with 196 additions and 189 deletions.
41 changes: 41 additions & 0 deletions _test/cli8.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package main

import (
"net/http"
"net/http/httptest"
)

type T struct {
name string
next http.Handler
}

func (t *T) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
println("in T.ServeHTTP")
if t.next != nil {
t.next.ServeHTTP(rw, req)
}
}

func New(name string, next http.Handler) (http.Handler, error) { return &T{name, next}, nil }

func main() {
next := func(rw http.ResponseWriter, req *http.Request) {
println("in next")
}

t, err := New("test", http.HandlerFunc(next))
if err != nil {
panic(err)
}

recorder := httptest.NewRecorder()
req := httptest.NewRequest(http.MethodGet, "/", nil)
t.ServeHTTP(recorder, req)
println(recorder.Result().Status)
}

// Output:
// in T.ServeHTTP
// in next
// 200 OK
18 changes: 18 additions & 0 deletions _test/convert3.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package main

import (
"fmt"
"net/http"
)

func main() {
next := func(rw http.ResponseWriter, req *http.Request) {
rw.Header().Set("Cache-Control", "max-age=20")
rw.WriteHeader(http.StatusOK)
}
f := http.HandlerFunc(next)
fmt.Printf("%T\n", f.ServeHTTP)
}

// Output:
// func(http.ResponseWriter, *http.Request)
22 changes: 22 additions & 0 deletions _test/issue-1459.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package main

import "fmt"

type funclistItem func()

type funclist struct {
list []funclistItem
}

func main() {
funcs := funclist{}

funcs.list = append(funcs.list, func() { fmt.Println("first") })

for _, f := range funcs.list {
f()
}
}

// Output:
// first
2 changes: 1 addition & 1 deletion _test/struct49.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func main() {
}
s.ts["test"] = append(s.ts["test"], &T{s: s})

t , ok:= s.getT("test")
t, ok := s.getT("test")
println(t != nil, ok)
}

Expand Down
1 change: 1 addition & 0 deletions generate.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package yaegi provides a Go interpreter.
package yaegi

//go:generate go generate github.com/traefik/yaegi/internal/cmd/extract
Expand Down
1 change: 1 addition & 0 deletions internal/unsafe2/unsafe.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package unsafe2 provides helpers to generate recursive struct types.
package unsafe2

import (
Expand Down
7 changes: 1 addition & 6 deletions interp/cfg.go
Original file line number Diff line number Diff line change
Expand Up @@ -1707,12 +1707,7 @@ func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string
}
if c.typ.cat == nilT {
// nil: Set node value to zero of return type
if typ.cat == funcT {
// Wrap the typed nil value in a node, as per other interpreter functions
c.rval = reflect.ValueOf(&node{kind: basicLit, rval: reflect.New(typ.TypeOf()).Elem()})
} else {
c.rval = reflect.New(typ.TypeOf()).Elem()
}
c.rval = reflect.New(typ.TypeOf()).Elem()
}
}

Expand Down
Loading

0 comments on commit e003140

Please sign in to comment.