aboutsummaryrefslogtreecommitdiff
path: root/go/ssa/interp
diff options
context:
space:
mode:
Diffstat (limited to 'go/ssa/interp')
-rw-r--r--go/ssa/interp/interp.go10
-rw-r--r--go/ssa/interp/interp_test.go72
-rw-r--r--go/ssa/interp/testdata/src/encoding/encoding.go15
-rw-r--r--go/ssa/interp/testdata/src/log/log.go8
4 files changed, 102 insertions, 3 deletions
diff --git a/go/ssa/interp/interp.go b/go/ssa/interp/interp.go
index 0f6a21f92..2b21aad70 100644
--- a/go/ssa/interp/interp.go
+++ b/go/ssa/interp/interp.go
@@ -51,6 +51,7 @@ import (
"os"
"reflect"
"runtime"
+ "strings"
"sync/atomic"
"golang.org/x/tools/go/ssa"
@@ -505,7 +506,11 @@ func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function,
return ext(fr, args)
}
if fn.Blocks == nil {
- panic("no code for function: " + name)
+ var reason string // empty by default
+ if strings.HasPrefix(fn.Synthetic, "instantiation") {
+ reason = " (interp requires ssa.BuilderMode to include InstantiateGenerics on generics)"
+ }
+ panic("no code for function: " + name + reason)
}
}
fr.env = make(map[ssa.Value]value)
@@ -637,6 +642,9 @@ func setGlobal(i *interpreter, pkg *ssa.Package, name string, v value) {
// gc does), or the argument to os.Exit for normal termination.
//
// The SSA program must include the "runtime" package.
+//
+// Type parameterized functions must have been built with
+// InstantiateGenerics in the ssa.BuilderMode to be interpreted.
func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) {
i := &interpreter{
prog: mainpkg.Prog,
diff --git a/go/ssa/interp/interp_test.go b/go/ssa/interp/interp_test.go
index 91ecb9793..4da3ffe0b 100644
--- a/go/ssa/interp/interp_test.go
+++ b/go/ssa/interp/interp_test.go
@@ -31,6 +31,7 @@ import (
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/interp"
"golang.org/x/tools/go/ssa/ssautil"
+ "golang.org/x/tools/internal/typeparams"
)
// Each line contains a space-separated list of $GOROOT/test/
@@ -182,7 +183,9 @@ func run(t *testing.T, input string) bool {
return false
}
- prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
+ bmode := ssa.InstantiateGenerics | ssa.SanityCheckFunctions
+ // bmode |= ssa.PrintFunctions // enable for debugging
+ prog := ssautil.CreateProgram(iprog, bmode)
prog.Build()
mainPkg := prog.Package(iprog.Created[0].Pkg)
@@ -194,7 +197,10 @@ func run(t *testing.T, input string) bool {
sizes := types.SizesFor("gc", ctx.GOARCH)
hint = fmt.Sprintf("To trace execution, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -build=C -test -run --interp=T %s\n", input)
- exitCode := interp.Interpret(mainPkg, 0, sizes, input, []string{})
+ var imode interp.Mode // default mode
+ // imode |= interp.DisableRecover // enable for debugging
+ // imode |= interp.EnableTracing // enable for debugging
+ exitCode := interp.Interpret(mainPkg, imode, sizes, input, []string{})
if exitCode != 0 {
t.Fatalf("interpreting %s: exit code was %d", input, exitCode)
}
@@ -248,3 +254,65 @@ func TestGorootTest(t *testing.T) {
}
printFailures(failures)
}
+
+// TestTypeparamTest runs the interpreter on runnable examples
+// in $GOROOT/test/typeparam/*.go.
+
+func TestTypeparamTest(t *testing.T) {
+ if !typeparams.Enabled {
+ return
+ }
+
+ // Skip known failures for the given reason.
+ // TODO(taking): Address these.
+ skip := map[string]string{
+ "chans.go": "interp tests do not support runtime.SetFinalizer",
+ "issue23536.go": "unknown reason",
+ "issue376214.go": "unknown issue with variadic cast on bytes",
+ "issue48042.go": "interp tests do not handle reflect.Value.SetInt",
+ "issue47716.go": "interp tests do not handle unsafe.Sizeof",
+ "issue50419.go": "interp tests do not handle dispatch to String() correctly",
+ "issue51733.go": "interp does not handle unsafe casts",
+ "ordered.go": "math.NaN() comparisons not being handled correctly",
+ "orderedmap.go": "interp tests do not support runtime.SetFinalizer",
+ "stringer.go": "unknown reason",
+ "issue48317.go": "interp tests do not support encoding/json",
+ "issue48318.go": "interp tests do not support encoding/json",
+ }
+ // Collect all of the .go files in dir that are runnable.
+ dir := filepath.Join(build.Default.GOROOT, "test", "typeparam")
+ list, err := os.ReadDir(dir)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var inputs []string
+ for _, entry := range list {
+ if entry.IsDir() || !strings.HasSuffix(entry.Name(), ".go") {
+ continue // Consider standalone go files.
+ }
+ if reason := skip[entry.Name()]; reason != "" {
+ t.Logf("skipping %q due to %s.", entry.Name(), reason)
+ continue
+ }
+ input := filepath.Join(dir, entry.Name())
+ src, err := os.ReadFile(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ // Only build test files that can be compiled, or compiled and run.
+ if bytes.HasPrefix(src, []byte("// run")) && !bytes.HasPrefix(src, []byte("// rundir")) {
+ inputs = append(inputs, input)
+ } else {
+ t.Logf("Not a `// run` file: %s", entry.Name())
+ }
+ }
+
+ var failures []string
+ for _, input := range inputs {
+ t.Log("running", input)
+ if !run(t, input) {
+ failures = append(failures, input)
+ }
+ }
+ printFailures(failures)
+}
diff --git a/go/ssa/interp/testdata/src/encoding/encoding.go b/go/ssa/interp/testdata/src/encoding/encoding.go
new file mode 100644
index 000000000..73e9de494
--- /dev/null
+++ b/go/ssa/interp/testdata/src/encoding/encoding.go
@@ -0,0 +1,15 @@
+package encoding
+
+type BinaryMarshaler interface {
+ MarshalBinary() (data []byte, err error)
+}
+type BinaryUnmarshaler interface {
+ UnmarshalBinary(data []byte) error
+}
+
+type TextMarshaler interface {
+ MarshalText() (text []byte, err error)
+}
+type TextUnmarshaler interface {
+ UnmarshalText(text []byte) error
+}
diff --git a/go/ssa/interp/testdata/src/log/log.go b/go/ssa/interp/testdata/src/log/log.go
index 8897c1d21..9a57e8c1c 100644
--- a/go/ssa/interp/testdata/src/log/log.go
+++ b/go/ssa/interp/testdata/src/log/log.go
@@ -8,8 +8,16 @@ import (
func Println(v ...interface{}) {
fmt.Println(v...)
}
+func Printf(format string, v ...interface{}) {
+ fmt.Printf(format, v...)
+}
func Fatalln(v ...interface{}) {
Println(v...)
os.Exit(1)
}
+
+func Fatalf(format string, v ...interface{}) {
+ Printf(format, v...)
+ os.Exit(1)
+}