Add generated file

This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
xing-yang
2018-07-12 10:55:15 -07:00
parent 36b1de0341
commit e213d1890d
17729 changed files with 5090889 additions and 0 deletions

562
vendor/golang.org/x/tools/go/ssa/interp/external.go generated vendored Normal file
View File

@@ -0,0 +1,562 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package interp
// Emulated functions that we cannot interpret because they are
// external or because they use "unsafe" or "reflect" operations.
import (
"go/types"
"math"
"os"
"runtime"
"strings"
"sync/atomic"
"time"
"unsafe"
"golang.org/x/tools/go/ssa"
)
type externalFn func(fr *frame, args []value) value
// TODO(adonovan): fix: reflect.Value abstracts an lvalue or an
// rvalue; Set() causes mutations that can be observed via aliases.
// We have not captured that correctly here.
// Key strings are from Function.String().
var externals = make(map[string]externalFn)
func init() {
// That little dot ۰ is an Arabic zero numeral (U+06F0), categories [Nd].
for k, v := range map[string]externalFn{
"(*sync.Pool).Get": ext۰sync۰Pool۰Get,
"(*sync.Pool).Put": ext۰nop,
"(reflect.Value).Bool": ext۰reflect۰Value۰Bool,
"(reflect.Value).CanAddr": ext۰reflect۰Value۰CanAddr,
"(reflect.Value).CanInterface": ext۰reflect۰Value۰CanInterface,
"(reflect.Value).Elem": ext۰reflect۰Value۰Elem,
"(reflect.Value).Field": ext۰reflect۰Value۰Field,
"(reflect.Value).Float": ext۰reflect۰Value۰Float,
"(reflect.Value).Index": ext۰reflect۰Value۰Index,
"(reflect.Value).Int": ext۰reflect۰Value۰Int,
"(reflect.Value).Interface": ext۰reflect۰Value۰Interface,
"(reflect.Value).IsNil": ext۰reflect۰Value۰IsNil,
"(reflect.Value).IsValid": ext۰reflect۰Value۰IsValid,
"(reflect.Value).Kind": ext۰reflect۰Value۰Kind,
"(reflect.Value).Len": ext۰reflect۰Value۰Len,
"(reflect.Value).MapIndex": ext۰reflect۰Value۰MapIndex,
"(reflect.Value).MapKeys": ext۰reflect۰Value۰MapKeys,
"(reflect.Value).NumField": ext۰reflect۰Value۰NumField,
"(reflect.Value).NumMethod": ext۰reflect۰Value۰NumMethod,
"(reflect.Value).Pointer": ext۰reflect۰Value۰Pointer,
"(reflect.Value).Set": ext۰reflect۰Value۰Set,
"(reflect.Value).String": ext۰reflect۰Value۰String,
"(reflect.Value).Type": ext۰reflect۰Value۰Type,
"(reflect.Value).Uint": ext۰reflect۰Value۰Uint,
"(reflect.error).Error": ext۰reflect۰error۰Error,
"(reflect.rtype).Bits": ext۰reflect۰rtype۰Bits,
"(reflect.rtype).Elem": ext۰reflect۰rtype۰Elem,
"(reflect.rtype).Field": ext۰reflect۰rtype۰Field,
"(reflect.rtype).In": ext۰reflect۰rtype۰In,
"(reflect.rtype).Kind": ext۰reflect۰rtype۰Kind,
"(reflect.rtype).NumField": ext۰reflect۰rtype۰NumField,
"(reflect.rtype).NumIn": ext۰reflect۰rtype۰NumIn,
"(reflect.rtype).NumMethod": ext۰reflect۰rtype۰NumMethod,
"(reflect.rtype).NumOut": ext۰reflect۰rtype۰NumOut,
"(reflect.rtype).Out": ext۰reflect۰rtype۰Out,
"(reflect.rtype).Size": ext۰reflect۰rtype۰Size,
"(reflect.rtype).String": ext۰reflect۰rtype۰String,
"bytes.init": ext۰nop, // avoid asm dependency
"bytes.Equal": ext۰bytes۰Equal,
"bytes.IndexByte": ext۰bytes۰IndexByte,
"hash/crc32.haveSSE42": ext۰crc32۰haveSSE42,
"internal/cpu.cpuid": ext۰cpu۰cpuid,
"internal/syscall/unix.syscall_fcntl": ext۰syscall۰unix۰syscall_fcntl,
"math.Abs": ext۰math۰Abs,
"math.Exp": ext۰math۰Exp,
"math.Float32bits": ext۰math۰Float32bits,
"math.Float32frombits": ext۰math۰Float32frombits,
"math.Float64bits": ext۰math۰Float64bits,
"math.Float64frombits": ext۰math۰Float64frombits,
"math.Ldexp": ext۰math۰Ldexp,
"math.Log": ext۰math۰Log,
"math.Min": ext۰math۰Min,
"math.hasSSE4": ext۰math۰hasSSE4,
"math.hasVectorFacility": ext۰math۰hasVectorFacility,
"os.runtime_args": ext۰os۰runtime_args,
"os.runtime_beforeExit": ext۰nop,
"os/signal.init": ext۰nop,
"reflect.New": ext۰reflect۰New,
"reflect.SliceOf": ext۰reflect۰SliceOf,
"reflect.TypeOf": ext۰reflect۰TypeOf,
"reflect.ValueOf": ext۰reflect۰ValueOf,
"reflect.Zero": ext۰reflect۰Zero,
"reflect.init": ext۰reflect۰Init,
"reflect.valueInterface": ext۰reflect۰valueInterface,
"runtime.Breakpoint": ext۰runtime۰Breakpoint,
"runtime.Caller": ext۰runtime۰Caller,
"runtime.Callers": ext۰runtime۰Callers,
"runtime.FuncForPC": ext۰runtime۰FuncForPC,
"runtime.GC": ext۰runtime۰GC,
"runtime.GOMAXPROCS": ext۰runtime۰GOMAXPROCS,
"runtime.Goexit": ext۰runtime۰Goexit,
"runtime.Gosched": ext۰runtime۰Gosched,
"runtime.init": ext۰nop,
"runtime.KeepAlive": ext۰nop,
"runtime.NumCPU": ext۰runtime۰NumCPU,
"runtime.NumGoroutine": ext۰runtime۰NumGoroutine,
"runtime.ReadMemStats": ext۰runtime۰ReadMemStats,
"runtime.SetFinalizer": ext۰nop, // ignore
"(*runtime.Func).Entry": ext۰runtime۰Func۰Entry,
"(*runtime.Func).FileLine": ext۰runtime۰Func۰FileLine,
"(*runtime.Func).Name": ext۰runtime۰Func۰Name,
"runtime.environ": ext۰runtime۰environ,
"runtime.getgoroot": ext۰runtime۰getgoroot,
"strings.init": ext۰nop, // avoid asm dependency
"strings.Count": ext۰strings۰Count,
"strings.Index": ext۰strings۰Index,
"strings.IndexByte": ext۰strings۰IndexByte,
"sync.runtime_Semacquire": ext۰nop, // unimplementable
"sync.runtime_Semrelease": ext۰nop, // unimplementable
"sync.runtime_Syncsemcheck": ext۰nop, // unimplementable
"sync.runtime_notifyListCheck": ext۰nop,
"sync.runtime_registerPoolCleanup": ext۰nop,
"sync/atomic.AddInt32": ext۰atomic۰AddInt32,
"sync/atomic.AddUint32": ext۰atomic۰AddUint32,
"sync/atomic.CompareAndSwapInt32": ext۰atomic۰CompareAndSwapInt32,
"sync/atomic.CompareAndSwapUint32": ext۰atomic۰CompareAndSwapUint32,
"sync/atomic.LoadInt32": ext۰atomic۰LoadInt32,
"sync/atomic.LoadUint32": ext۰atomic۰LoadUint32,
"sync/atomic.StoreInt32": ext۰atomic۰StoreInt32,
"sync/atomic.StoreUint32": ext۰atomic۰StoreUint32,
"sync/atomic.AddInt64": ext۰atomic۰AddInt64,
"sync/atomic.AddUint64": ext۰atomic۰AddUint64,
"sync/atomic.CompareAndSwapInt64": ext۰atomic۰CompareAndSwapInt64,
"sync/atomic.CompareAndSwapUint64": ext۰atomic۰CompareAndSwapUint64,
"sync/atomic.LoadInt64": ext۰atomic۰LoadInt64,
"sync/atomic.LoadUint64": ext۰atomic۰LoadUint64,
"sync/atomic.StoreInt64": ext۰atomic۰StoreInt64,
"sync/atomic.StoreUint64": ext۰atomic۰StoreUint64,
"(*sync/atomic.Value).Load": ext۰atomic۰ValueLoad,
"(*sync/atomic.Value).Store": ext۰atomic۰ValueStore,
"testing.MainStart": ext۰testing۰MainStart,
"time.Sleep": ext۰time۰Sleep,
"time.now": ext۰time۰now,
} {
externals[k] = v
}
}
// wrapError returns an interpreted 'error' interface value for err.
func wrapError(err error) value {
if err == nil {
return iface{}
}
return iface{t: errorType, v: err.Error()}
}
func ext۰nop(fr *frame, args []value) value { return nil }
func ext۰sync۰Pool۰Get(fr *frame, args []value) value {
Pool := fr.i.prog.ImportedPackage("sync").Type("Pool").Object()
_, newIndex, _ := types.LookupFieldOrMethod(Pool.Type(), false, Pool.Pkg(), "New")
if New := (*args[0].(*value)).(structure)[newIndex[0]]; New != nil {
return call(fr.i, fr, 0, New, nil)
}
return nil
}
func ext۰bytes۰Equal(fr *frame, args []value) value {
// func Equal(a, b []byte) bool
a := args[0].([]value)
b := args[1].([]value)
if len(a) != len(b) {
return false
}
for i := range a {
if a[i] != b[i] {
return false
}
}
return true
}
func ext۰bytes۰IndexByte(fr *frame, args []value) value {
// func IndexByte(s []byte, c byte) int
s := args[0].([]value)
c := args[1].(byte)
for i, b := range s {
if b.(byte) == c {
return i
}
}
return -1
}
func ext۰crc32۰haveSSE42(fr *frame, args []value) value {
return false
}
func ext۰math۰Float64frombits(fr *frame, args []value) value {
return math.Float64frombits(args[0].(uint64))
}
func ext۰math۰Float64bits(fr *frame, args []value) value {
return math.Float64bits(args[0].(float64))
}
func ext۰math۰Float32frombits(fr *frame, args []value) value {
return math.Float32frombits(args[0].(uint32))
}
func ext۰math۰Abs(fr *frame, args []value) value {
return math.Abs(args[0].(float64))
}
func ext۰math۰Exp(fr *frame, args []value) value {
return math.Exp(args[0].(float64))
}
func ext۰math۰Float32bits(fr *frame, args []value) value {
return math.Float32bits(args[0].(float32))
}
func ext۰math۰Min(fr *frame, args []value) value {
return math.Min(args[0].(float64), args[1].(float64))
}
func ext۰math۰hasSSE4(fr *frame, args []value) value {
return false
}
func ext۰math۰hasVectorFacility(fr *frame, args []value) value {
return false
}
func ext۰math۰Ldexp(fr *frame, args []value) value {
return math.Ldexp(args[0].(float64), args[1].(int))
}
func ext۰math۰Log(fr *frame, args []value) value {
return math.Log(args[0].(float64))
}
func ext۰os۰runtime_args(fr *frame, args []value) value {
return fr.i.osArgs
}
func ext۰runtime۰Breakpoint(fr *frame, args []value) value {
runtime.Breakpoint()
return nil
}
func ext۰runtime۰Caller(fr *frame, args []value) value {
// func Caller(skip int) (pc uintptr, file string, line int, ok bool)
skip := 1 + args[0].(int)
for i := 0; i < skip; i++ {
if fr != nil {
fr = fr.caller
}
}
var pc uintptr
var file string
var line int
var ok bool
if fr != nil {
fn := fr.fn
// TODO(adonovan): use pc/posn of current instruction, not start of fn.
// (Required to interpret the log package's tests.)
pc = uintptr(unsafe.Pointer(fn))
posn := fn.Prog.Fset.Position(fn.Pos())
file = posn.Filename
line = posn.Line
ok = true
}
return tuple{pc, file, line, ok}
}
func ext۰runtime۰Callers(fr *frame, args []value) value {
// Callers(skip int, pc []uintptr) int
skip := args[0].(int)
pc := args[1].([]value)
for i := 0; i < skip; i++ {
if fr != nil {
fr = fr.caller
}
}
i := 0
for fr != nil && i < len(pc) {
pc[i] = uintptr(unsafe.Pointer(fr.fn))
i++
fr = fr.caller
}
return i
}
func ext۰runtime۰FuncForPC(fr *frame, args []value) value {
// FuncForPC(pc uintptr) *Func
pc := args[0].(uintptr)
var fn *ssa.Function
if pc != 0 {
fn = (*ssa.Function)(unsafe.Pointer(pc)) // indeed unsafe!
}
var Func value
Func = structure{fn} // a runtime.Func
return &Func
}
func ext۰runtime۰environ(fr *frame, args []value) value {
// This function also implements syscall.runtime_envs.
return environ
}
func ext۰runtime۰getgoroot(fr *frame, args []value) value {
return os.Getenv("GOROOT")
}
func ext۰strings۰Count(fr *frame, args []value) value {
// Call compiled version to avoid asm dependency.
return strings.Count(args[0].(string), args[1].(string))
}
func ext۰strings۰IndexByte(fr *frame, args []value) value {
// Call compiled version to avoid asm dependency.
return strings.IndexByte(args[0].(string), args[1].(byte))
}
func ext۰strings۰Index(fr *frame, args []value) value {
// Call compiled version to avoid asm dependency.
return strings.Index(args[0].(string), args[1].(string))
}
func ext۰runtime۰GOMAXPROCS(fr *frame, args []value) value {
// Ignore args[0]; don't let the interpreted program
// set the interpreter's GOMAXPROCS!
return runtime.GOMAXPROCS(0)
}
func ext۰runtime۰Goexit(fr *frame, args []value) value {
// TODO(adonovan): don't kill the interpreter's main goroutine.
runtime.Goexit()
return nil
}
func ext۰runtime۰GC(fr *frame, args []value) value {
runtime.GC()
return nil
}
func ext۰runtime۰Gosched(fr *frame, args []value) value {
runtime.Gosched()
return nil
}
func ext۰runtime۰NumCPU(fr *frame, args []value) value {
return runtime.NumCPU()
}
func ext۰runtime۰NumGoroutine(fr *frame, args []value) value {
return int(atomic.LoadInt32(&fr.i.goroutines))
}
func ext۰runtime۰ReadMemStats(fr *frame, args []value) value {
// TODO(adonovan): populate args[0].(Struct)
return nil
}
func ext۰atomic۰LoadUint32(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
return (*args[0].(*value)).(uint32)
}
func ext۰atomic۰StoreUint32(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
*args[0].(*value) = args[1].(uint32)
return nil
}
func ext۰atomic۰LoadInt32(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
return (*args[0].(*value)).(int32)
}
func ext۰atomic۰StoreInt32(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
*args[0].(*value) = args[1].(int32)
return nil
}
func ext۰atomic۰CompareAndSwapInt32(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
p := args[0].(*value)
if (*p).(int32) == args[1].(int32) {
*p = args[2].(int32)
return true
}
return false
}
func ext۰atomic۰CompareAndSwapUint32(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
p := args[0].(*value)
if (*p).(uint32) == args[1].(uint32) {
*p = args[2].(uint32)
return true
}
return false
}
func ext۰atomic۰AddInt32(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
p := args[0].(*value)
newv := (*p).(int32) + args[1].(int32)
*p = newv
return newv
}
func ext۰atomic۰AddUint32(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
p := args[0].(*value)
newv := (*p).(uint32) + args[1].(uint32)
*p = newv
return newv
}
func ext۰atomic۰LoadUint64(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
return (*args[0].(*value)).(uint64)
}
func ext۰atomic۰StoreUint64(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
*args[0].(*value) = args[1].(uint64)
return nil
}
func ext۰atomic۰LoadInt64(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
return (*args[0].(*value)).(int64)
}
func ext۰atomic۰StoreInt64(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
*args[0].(*value) = args[1].(int64)
return nil
}
func ext۰atomic۰CompareAndSwapInt64(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
p := args[0].(*value)
if (*p).(int64) == args[1].(int64) {
*p = args[2].(int64)
return true
}
return false
}
func ext۰atomic۰CompareAndSwapUint64(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
p := args[0].(*value)
if (*p).(uint64) == args[1].(uint64) {
*p = args[2].(uint64)
return true
}
return false
}
func ext۰atomic۰AddInt64(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
p := args[0].(*value)
newv := (*p).(int64) + args[1].(int64)
*p = newv
return newv
}
func ext۰atomic۰AddUint64(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
p := args[0].(*value)
newv := (*p).(uint64) + args[1].(uint64)
*p = newv
return newv
}
func ext۰atomic۰ValueLoad(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
// Receiver is *struct{v interface{}}.
return (*args[0].(*value)).(structure)[0]
}
func ext۰atomic۰ValueStore(fr *frame, args []value) value {
// TODO(adonovan): fix: not atomic!
// Receiver is *struct{v interface{}}.
(*args[0].(*value)).(structure)[0] = args[1]
return nil
}
func ext۰cpu۰cpuid(fr *frame, args []value) value {
return tuple{uint32(0), uint32(0), uint32(0), uint32(0)}
}
func ext۰syscall۰unix۰syscall_fcntl(fr *frame, args []value) value {
return tuple{int(0), wrapError(nil)}
}
// Pretend: type runtime.Func struct { entry *ssa.Function }
func ext۰runtime۰Func۰FileLine(fr *frame, args []value) value {
// func (*runtime.Func) FileLine(uintptr) (string, int)
f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
pc := args[1].(uintptr)
_ = pc
if f != nil {
// TODO(adonovan): use position of current instruction, not fn.
posn := f.Prog.Fset.Position(f.Pos())
return tuple{posn.Filename, posn.Line}
}
return tuple{"", 0}
}
func ext۰runtime۰Func۰Name(fr *frame, args []value) value {
// func (*runtime.Func) Name() string
f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
if f != nil {
return f.String()
}
return ""
}
func ext۰runtime۰Func۰Entry(fr *frame, args []value) value {
// func (*runtime.Func) Entry() uintptr
f, _ := (*args[0].(*value)).(structure)[0].(*ssa.Function)
return uintptr(unsafe.Pointer(f))
}
func ext۰time۰now(fr *frame, args []value) value {
nano := time.Now().UnixNano()
return tuple{int64(nano / 1e9), int32(nano % 1e9), int64(0)}
}
func ext۰time۰Sleep(fr *frame, args []value) value {
time.Sleep(time.Duration(args[0].(int64)))
return nil
}
func valueToBytes(v value) []byte {
in := v.([]value)
b := make([]byte, len(in))
for i := range in {
b[i] = in[i].(byte)
}
return b
}
func ext۰testing۰MainStart(fr *frame, args []value) value {
// We no longer support interpretation of the "testing" package
// because it changes too often and uses low-level features that
// are a pain to emulate.
panic(`interpretation of the "testing" package is no longer supported`)
}

View File

@@ -0,0 +1,35 @@
// Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin
package interp
import "syscall"
func init() {
externals["syscall.Sysctl"] = ext۰syscall۰Sysctl
fillStat = func(st *syscall.Stat_t, stat structure) {
stat[0] = st.Dev
stat[1] = st.Mode
stat[2] = st.Nlink
stat[3] = st.Ino
stat[4] = st.Uid
stat[5] = st.Gid
stat[6] = st.Rdev
// TODO(adonovan): fix: copy Timespecs.
// stat[8] = st.Atim
// stat[9] = st.Mtim
// stat[10] = st.Ctim
stat[12] = st.Size
stat[13] = st.Blocks
stat[14] = st.Blksize
}
}
func ext۰syscall۰Sysctl(fr *frame, args []value) value {
r, err := syscall.Sysctl(args[0].(string))
return tuple{r, wrapError(err)}
}

View File

@@ -0,0 +1,256 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build darwin linux
package interp
import "syscall"
func init() {
for k, v := range map[string]externalFn{
"os.Pipe": ext۰os۰Pipe,
"syscall.Close": ext۰syscall۰Close,
"syscall.Exit": ext۰syscall۰Exit,
"syscall.Fchown": ext۰syscall۰Fchown,
"syscall.Fstat": ext۰syscall۰Fstat,
"syscall.Ftruncate": ext۰syscall۰Ftruncate,
"syscall.Getpid": ext۰syscall۰Getpid,
"syscall.Getwd": ext۰syscall۰Getwd,
"syscall.Kill": ext۰syscall۰Kill,
"syscall.Link": ext۰syscall۰Link,
"syscall.Lstat": ext۰syscall۰Lstat,
"syscall.Mkdir": ext۰syscall۰Mkdir,
"syscall.Open": ext۰syscall۰Open,
"syscall.ParseDirent": ext۰syscall۰ParseDirent,
"syscall.RawSyscall": ext۰syscall۰RawSyscall,
"syscall.Read": ext۰syscall۰Read,
"syscall.ReadDirent": ext۰syscall۰ReadDirent,
"syscall.Readlink": ext۰syscall۰Readlink,
"syscall.Rmdir": ext۰syscall۰Rmdir,
"syscall.Seek": ext۰syscall۰Seek,
"syscall.Stat": ext۰syscall۰Stat,
"syscall.Symlink": ext۰syscall۰Symlink,
"syscall.Write": ext۰syscall۰Write,
"syscall.Unlink": ext۰syscall۰Unlink,
"syscall۰UtimesNano": ext۰syscall۰UtimesNano,
"syscall.setenv_c": ext۰nop,
"syscall.unsetenv_c": ext۰nop,
"syscall.runtime_envs": ext۰runtime۰environ,
} {
externals[k] = v
}
syswrite = syscall.Write
}
func ext۰os۰Pipe(fr *frame, args []value) value {
// func os.Pipe() (r *File, w *File, err error)
// The portable POSIX pipe(2) call is good enough for our needs.
var p [2]int
if err := syscall.Pipe(p[:]); err != nil {
// TODO(adonovan): fix: return an *os.SyscallError.
return tuple{nil, nil, wrapError(err)}
}
NewFile := fr.i.prog.ImportedPackage("os").Func("NewFile")
r := call(fr.i, fr, 0, NewFile, []value{uintptr(p[0]), "|0"})
w := call(fr.i, fr, 0, NewFile, []value{uintptr(p[1]), "|1"})
return tuple{r, w, wrapError(nil)}
}
// overridden on darwin
var fillStat = func(st *syscall.Stat_t, stat structure) {
stat[0] = st.Dev
stat[1] = st.Ino
stat[2] = st.Nlink
stat[3] = st.Mode
stat[4] = st.Uid
stat[5] = st.Gid
stat[7] = st.Rdev
stat[8] = st.Size
stat[9] = st.Blksize
stat[10] = st.Blocks
// TODO(adonovan): fix: copy Timespecs.
// stat[11] = st.Atim
// stat[12] = st.Mtim
// stat[13] = st.Ctim
}
func ext۰syscall۰Close(fr *frame, args []value) value {
// func Close(fd int) (err error)
return wrapError(syscall.Close(args[0].(int)))
}
func ext۰syscall۰Exit(fr *frame, args []value) value {
panic(exitPanic(args[0].(int)))
}
func ext۰syscall۰Fchown(fr *frame, args []value) value {
fd := args[0].(int)
uid := args[1].(int)
gid := args[2].(int)
return wrapError(syscall.Fchown(fd, uid, gid))
}
func ext۰syscall۰Fstat(fr *frame, args []value) value {
// func Fstat(fd int, stat *Stat_t) (err error)
fd := args[0].(int)
stat := (*args[1].(*value)).(structure)
var st syscall.Stat_t
err := syscall.Fstat(fd, &st)
fillStat(&st, stat)
return wrapError(err)
}
func ext۰syscall۰Ftruncate(fr *frame, args []value) value {
fd := args[0].(int)
length := args[1].(int64)
return wrapError(syscall.Ftruncate(fd, length))
}
func ext۰syscall۰Getpid(fr *frame, args []value) value {
return syscall.Getpid()
}
func ext۰syscall۰Getwd(fr *frame, args []value) value {
s, err := syscall.Getwd()
return tuple{s, wrapError(err)}
}
func ext۰syscall۰Kill(fr *frame, args []value) value {
// func Kill(pid int, sig Signal) (err error)
return wrapError(syscall.Kill(args[0].(int), syscall.Signal(args[1].(int))))
}
func ext۰syscall۰Link(fr *frame, args []value) value {
path := args[0].(string)
link := args[1].(string)
return wrapError(syscall.Link(path, link))
}
func ext۰syscall۰Lstat(fr *frame, args []value) value {
// func Lstat(name string, stat *Stat_t) (err error)
name := args[0].(string)
stat := (*args[1].(*value)).(structure)
var st syscall.Stat_t
err := syscall.Lstat(name, &st)
fillStat(&st, stat)
return wrapError(err)
}
func ext۰syscall۰Mkdir(fr *frame, args []value) value {
path := args[0].(string)
mode := args[1].(uint32)
return wrapError(syscall.Mkdir(path, mode))
}
func ext۰syscall۰Open(fr *frame, args []value) value {
// func Open(path string, mode int, perm uint32) (fd int, err error) {
path := args[0].(string)
mode := args[1].(int)
perm := args[2].(uint32)
fd, err := syscall.Open(path, mode, perm)
return tuple{fd, wrapError(err)}
}
func ext۰syscall۰ParseDirent(fr *frame, args []value) value {
// func ParseDirent(buf []byte, max int, names []string) (consumed int, count int, newnames []string)
max := args[1].(int)
var names []string
for _, iname := range args[2].([]value) {
names = append(names, iname.(string))
}
consumed, count, newnames := syscall.ParseDirent(valueToBytes(args[0]), max, names)
var inewnames []value
for _, newname := range newnames {
inewnames = append(inewnames, newname)
}
return tuple{consumed, count, inewnames}
}
func ext۰syscall۰RawSyscall(fr *frame, args []value) value {
return tuple{uintptr(0), uintptr(0), uintptr(syscall.ENOSYS)}
}
func ext۰syscall۰Read(fr *frame, args []value) value {
// func Read(fd int, p []byte) (n int, err error)
fd := args[0].(int)
p := args[1].([]value)
b := make([]byte, len(p))
n, err := syscall.Read(fd, b)
for i := 0; i < n; i++ {
p[i] = b[i]
}
return tuple{n, wrapError(err)}
}
func ext۰syscall۰ReadDirent(fr *frame, args []value) value {
// func ReadDirent(fd int, buf []byte) (n int, err error)
fd := args[0].(int)
p := args[1].([]value)
b := make([]byte, len(p))
n, err := syscall.ReadDirent(fd, b)
for i := 0; i < n; i++ {
p[i] = b[i]
}
return tuple{n, wrapError(err)}
}
func ext۰syscall۰Readlink(fr *frame, args []value) value {
path := args[0].(string)
buf := valueToBytes(args[1])
n, err := syscall.Readlink(path, buf)
return tuple{n, wrapError(err)}
}
func ext۰syscall۰Rmdir(fr *frame, args []value) value {
return wrapError(syscall.Rmdir(args[0].(string)))
}
func ext۰syscall۰Seek(fr *frame, args []value) value {
fd := args[0].(int)
offset := args[1].(int64)
whence := args[2].(int)
new, err := syscall.Seek(fd, offset, whence)
return tuple{new, wrapError(err)}
}
func ext۰syscall۰Stat(fr *frame, args []value) value {
// func Stat(name string, stat *Stat_t) (err error)
name := args[0].(string)
stat := (*args[1].(*value)).(structure)
var st syscall.Stat_t
err := syscall.Stat(name, &st)
fillStat(&st, stat)
return wrapError(err)
}
func ext۰syscall۰Symlink(fr *frame, args []value) value {
path := args[0].(string)
link := args[1].(string)
return wrapError(syscall.Symlink(path, link))
}
func ext۰syscall۰Unlink(fr *frame, args []value) value {
return wrapError(syscall.Unlink(args[0].(string)))
}
func ext۰syscall۰UtimesNano(fr *frame, args []value) value {
path := args[0].(string)
var ts [2]syscall.Timespec
err := syscall.UtimesNano(path, ts[:])
// TODO(adonovan): copy the Timespecs into args[1]
return wrapError(err)
}
func ext۰syscall۰Write(fr *frame, args []value) value {
// func Write(fd int, p []byte) (n int, err error)
n, err := write(args[0].(int), valueToBytes(args[1]))
return tuple{n, wrapError(err)}
}

764
vendor/golang.org/x/tools/go/ssa/interp/interp.go generated vendored Normal file
View File

@@ -0,0 +1,764 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package ssa/interp defines an interpreter for the SSA
// representation of Go programs.
//
// This interpreter is provided as an adjunct for testing the SSA
// construction algorithm. Its purpose is to provide a minimal
// metacircular implementation of the dynamic semantics of each SSA
// instruction. It is not, and will never be, a production-quality Go
// interpreter.
//
// The following is a partial list of Go features that are currently
// unsupported or incomplete in the interpreter.
//
// * Unsafe operations, including all uses of unsafe.Pointer, are
// impossible to support given the "boxed" value representation we
// have chosen.
//
// * The reflect package is only partially implemented.
//
// * The "testing" package is no longer supported because it
// depends on low-level details that change too often.
//
// * "sync/atomic" operations are not atomic due to the "boxed" value
// representation: it is not possible to read, modify and write an
// interface value atomically. As a consequence, Mutexes are currently
// broken.
//
// * recover is only partially implemented. Also, the interpreter
// makes no attempt to distinguish target panics from interpreter
// crashes.
//
// * map iteration is asymptotically inefficient.
//
// * the sizes of the int, uint and uintptr types in the target
// program are assumed to be the same as those of the interpreter
// itself.
//
// * all values occupy space, even those of types defined by the spec
// to have zero size, e.g. struct{}. This can cause asymptotic
// performance degradation.
//
// * os.Exit is implemented using panic, causing deferred functions to
// run.
package interp // import "golang.org/x/tools/go/ssa/interp"
import (
"fmt"
"go/token"
"go/types"
"os"
"reflect"
"runtime"
"sync/atomic"
"golang.org/x/tools/go/ssa"
)
type continuation int
const (
kNext continuation = iota
kReturn
kJump
)
// Mode is a bitmask of options affecting the interpreter.
type Mode uint
const (
DisableRecover Mode = 1 << iota // Disable recover() in target programs; show interpreter crash instead.
EnableTracing // Print a trace of all instructions as they are interpreted.
)
type methodSet map[string]*ssa.Function
// State shared between all interpreted goroutines.
type interpreter struct {
osArgs []value // the value of os.Args
prog *ssa.Program // the SSA program
globals map[ssa.Value]*value // addresses of global variables (immutable)
mode Mode // interpreter options
reflectPackage *ssa.Package // the fake reflect package
errorMethods methodSet // the method set of reflect.error, which implements the error interface.
rtypeMethods methodSet // the method set of rtype, which implements the reflect.Type interface.
runtimeErrorString types.Type // the runtime.errorString type
sizes types.Sizes // the effective type-sizing function
goroutines int32 // atomically updated
}
type deferred struct {
fn value
args []value
instr *ssa.Defer
tail *deferred
}
type frame struct {
i *interpreter
caller *frame
fn *ssa.Function
block, prevBlock *ssa.BasicBlock
env map[ssa.Value]value // dynamic values of SSA variables
locals []value
defers *deferred
result value
panicking bool
panic interface{}
}
func (fr *frame) get(key ssa.Value) value {
switch key := key.(type) {
case nil:
// Hack; simplifies handling of optional attributes
// such as ssa.Slice.{Low,High}.
return nil
case *ssa.Function, *ssa.Builtin:
return key
case *ssa.Const:
return constValue(key)
case *ssa.Global:
if r, ok := fr.i.globals[key]; ok {
return r
}
}
if r, ok := fr.env[key]; ok {
return r
}
panic(fmt.Sprintf("get: no value for %T: %v", key, key.Name()))
}
// runDefer runs a deferred call d.
// It always returns normally, but may set or clear fr.panic.
//
func (fr *frame) runDefer(d *deferred) {
if fr.i.mode&EnableTracing != 0 {
fmt.Fprintf(os.Stderr, "%s: invoking deferred function call\n",
fr.i.prog.Fset.Position(d.instr.Pos()))
}
var ok bool
defer func() {
if !ok {
// Deferred call created a new state of panic.
fr.panicking = true
fr.panic = recover()
}
}()
call(fr.i, fr, d.instr.Pos(), d.fn, d.args)
ok = true
}
// runDefers executes fr's deferred function calls in LIFO order.
//
// On entry, fr.panicking indicates a state of panic; if
// true, fr.panic contains the panic value.
//
// On completion, if a deferred call started a panic, or if no
// deferred call recovered from a previous state of panic, then
// runDefers itself panics after the last deferred call has run.
//
// If there was no initial state of panic, or it was recovered from,
// runDefers returns normally.
//
func (fr *frame) runDefers() {
for d := fr.defers; d != nil; d = d.tail {
fr.runDefer(d)
}
fr.defers = nil
if fr.panicking {
panic(fr.panic) // new panic, or still panicking
}
}
// lookupMethod returns the method set for type typ, which may be one
// of the interpreter's fake types.
func lookupMethod(i *interpreter, typ types.Type, meth *types.Func) *ssa.Function {
switch typ {
case rtypeType:
return i.rtypeMethods[meth.Id()]
case errorType:
return i.errorMethods[meth.Id()]
}
return i.prog.LookupMethod(typ, meth.Pkg(), meth.Name())
}
// visitInstr interprets a single ssa.Instruction within the activation
// record frame. It returns a continuation value indicating where to
// read the next instruction from.
func visitInstr(fr *frame, instr ssa.Instruction) continuation {
switch instr := instr.(type) {
case *ssa.DebugRef:
// no-op
case *ssa.UnOp:
fr.env[instr] = unop(instr, fr.get(instr.X))
case *ssa.BinOp:
fr.env[instr] = binop(instr.Op, instr.X.Type(), fr.get(instr.X), fr.get(instr.Y))
case *ssa.Call:
fn, args := prepareCall(fr, &instr.Call)
fr.env[instr] = call(fr.i, fr, instr.Pos(), fn, args)
case *ssa.ChangeInterface:
fr.env[instr] = fr.get(instr.X)
case *ssa.ChangeType:
fr.env[instr] = fr.get(instr.X) // (can't fail)
case *ssa.Convert:
fr.env[instr] = conv(instr.Type(), instr.X.Type(), fr.get(instr.X))
case *ssa.MakeInterface:
fr.env[instr] = iface{t: instr.X.Type(), v: fr.get(instr.X)}
case *ssa.Extract:
fr.env[instr] = fr.get(instr.Tuple).(tuple)[instr.Index]
case *ssa.Slice:
fr.env[instr] = slice(fr.get(instr.X), fr.get(instr.Low), fr.get(instr.High), fr.get(instr.Max))
case *ssa.Return:
switch len(instr.Results) {
case 0:
case 1:
fr.result = fr.get(instr.Results[0])
default:
var res []value
for _, r := range instr.Results {
res = append(res, fr.get(r))
}
fr.result = tuple(res)
}
fr.block = nil
return kReturn
case *ssa.RunDefers:
fr.runDefers()
case *ssa.Panic:
panic(targetPanic{fr.get(instr.X)})
case *ssa.Send:
fr.get(instr.Chan).(chan value) <- fr.get(instr.X)
case *ssa.Store:
store(deref(instr.Addr.Type()), fr.get(instr.Addr).(*value), fr.get(instr.Val))
case *ssa.If:
succ := 1
if fr.get(instr.Cond).(bool) {
succ = 0
}
fr.prevBlock, fr.block = fr.block, fr.block.Succs[succ]
return kJump
case *ssa.Jump:
fr.prevBlock, fr.block = fr.block, fr.block.Succs[0]
return kJump
case *ssa.Defer:
fn, args := prepareCall(fr, &instr.Call)
fr.defers = &deferred{
fn: fn,
args: args,
instr: instr,
tail: fr.defers,
}
case *ssa.Go:
fn, args := prepareCall(fr, &instr.Call)
atomic.AddInt32(&fr.i.goroutines, 1)
go func() {
call(fr.i, nil, instr.Pos(), fn, args)
atomic.AddInt32(&fr.i.goroutines, -1)
}()
case *ssa.MakeChan:
fr.env[instr] = make(chan value, asInt(fr.get(instr.Size)))
case *ssa.Alloc:
var addr *value
if instr.Heap {
// new
addr = new(value)
fr.env[instr] = addr
} else {
// local
addr = fr.env[instr].(*value)
}
*addr = zero(deref(instr.Type()))
case *ssa.MakeSlice:
slice := make([]value, asInt(fr.get(instr.Cap)))
tElt := instr.Type().Underlying().(*types.Slice).Elem()
for i := range slice {
slice[i] = zero(tElt)
}
fr.env[instr] = slice[:asInt(fr.get(instr.Len))]
case *ssa.MakeMap:
reserve := 0
if instr.Reserve != nil {
reserve = asInt(fr.get(instr.Reserve))
}
fr.env[instr] = makeMap(instr.Type().Underlying().(*types.Map).Key(), reserve)
case *ssa.Range:
fr.env[instr] = rangeIter(fr.get(instr.X), instr.X.Type())
case *ssa.Next:
fr.env[instr] = fr.get(instr.Iter).(iter).next()
case *ssa.FieldAddr:
fr.env[instr] = &(*fr.get(instr.X).(*value)).(structure)[instr.Field]
case *ssa.Field:
fr.env[instr] = fr.get(instr.X).(structure)[instr.Field]
case *ssa.IndexAddr:
x := fr.get(instr.X)
idx := fr.get(instr.Index)
switch x := x.(type) {
case []value:
fr.env[instr] = &x[asInt(idx)]
case *value: // *array
fr.env[instr] = &(*x).(array)[asInt(idx)]
default:
panic(fmt.Sprintf("unexpected x type in IndexAddr: %T", x))
}
case *ssa.Index:
fr.env[instr] = fr.get(instr.X).(array)[asInt(fr.get(instr.Index))]
case *ssa.Lookup:
fr.env[instr] = lookup(instr, fr.get(instr.X), fr.get(instr.Index))
case *ssa.MapUpdate:
m := fr.get(instr.Map)
key := fr.get(instr.Key)
v := fr.get(instr.Value)
switch m := m.(type) {
case map[value]value:
m[key] = v
case *hashmap:
m.insert(key.(hashable), v)
default:
panic(fmt.Sprintf("illegal map type: %T", m))
}
case *ssa.TypeAssert:
fr.env[instr] = typeAssert(fr.i, instr, fr.get(instr.X).(iface))
case *ssa.MakeClosure:
var bindings []value
for _, binding := range instr.Bindings {
bindings = append(bindings, fr.get(binding))
}
fr.env[instr] = &closure{instr.Fn.(*ssa.Function), bindings}
case *ssa.Phi:
for i, pred := range instr.Block().Preds {
if fr.prevBlock == pred {
fr.env[instr] = fr.get(instr.Edges[i])
break
}
}
case *ssa.Select:
var cases []reflect.SelectCase
if !instr.Blocking {
cases = append(cases, reflect.SelectCase{
Dir: reflect.SelectDefault,
})
}
for _, state := range instr.States {
var dir reflect.SelectDir
if state.Dir == types.RecvOnly {
dir = reflect.SelectRecv
} else {
dir = reflect.SelectSend
}
var send reflect.Value
if state.Send != nil {
send = reflect.ValueOf(fr.get(state.Send))
}
cases = append(cases, reflect.SelectCase{
Dir: dir,
Chan: reflect.ValueOf(fr.get(state.Chan)),
Send: send,
})
}
chosen, recv, recvOk := reflect.Select(cases)
if !instr.Blocking {
chosen-- // default case should have index -1.
}
r := tuple{chosen, recvOk}
for i, st := range instr.States {
if st.Dir == types.RecvOnly {
var v value
if i == chosen && recvOk {
// No need to copy since send makes an unaliased copy.
v = recv.Interface().(value)
} else {
v = zero(st.Chan.Type().Underlying().(*types.Chan).Elem())
}
r = append(r, v)
}
}
fr.env[instr] = r
default:
panic(fmt.Sprintf("unexpected instruction: %T", instr))
}
// if val, ok := instr.(ssa.Value); ok {
// fmt.Println(toString(fr.env[val])) // debugging
// }
return kNext
}
// prepareCall determines the function value and argument values for a
// function call in a Call, Go or Defer instruction, performing
// interface method lookup if needed.
//
func prepareCall(fr *frame, call *ssa.CallCommon) (fn value, args []value) {
v := fr.get(call.Value)
if call.Method == nil {
// Function call.
fn = v
} else {
// Interface method invocation.
recv := v.(iface)
if recv.t == nil {
panic("method invoked on nil interface")
}
if f := lookupMethod(fr.i, recv.t, call.Method); f == nil {
// Unreachable in well-typed programs.
panic(fmt.Sprintf("method set for dynamic type %v does not contain %s", recv.t, call.Method))
} else {
fn = f
}
args = append(args, recv.v)
}
for _, arg := range call.Args {
args = append(args, fr.get(arg))
}
return
}
// call interprets a call to a function (function, builtin or closure)
// fn with arguments args, returning its result.
// callpos is the position of the callsite.
//
func call(i *interpreter, caller *frame, callpos token.Pos, fn value, args []value) value {
switch fn := fn.(type) {
case *ssa.Function:
if fn == nil {
panic("call of nil function") // nil of func type
}
return callSSA(i, caller, callpos, fn, args, nil)
case *closure:
return callSSA(i, caller, callpos, fn.Fn, args, fn.Env)
case *ssa.Builtin:
return callBuiltin(caller, callpos, fn, args)
}
panic(fmt.Sprintf("cannot call %T", fn))
}
func loc(fset *token.FileSet, pos token.Pos) string {
if pos == token.NoPos {
return ""
}
return " at " + fset.Position(pos).String()
}
// callSSA interprets a call to function fn with arguments args,
// and lexical environment env, returning its result.
// callpos is the position of the callsite.
//
func callSSA(i *interpreter, caller *frame, callpos token.Pos, fn *ssa.Function, args []value, env []value) value {
if i.mode&EnableTracing != 0 {
fset := fn.Prog.Fset
// TODO(adonovan): fix: loc() lies for external functions.
fmt.Fprintf(os.Stderr, "Entering %s%s.\n", fn, loc(fset, fn.Pos()))
suffix := ""
if caller != nil {
suffix = ", resuming " + caller.fn.String() + loc(fset, callpos)
}
defer fmt.Fprintf(os.Stderr, "Leaving %s%s.\n", fn, suffix)
}
fr := &frame{
i: i,
caller: caller, // for panic/recover
fn: fn,
}
if fn.Parent() == nil {
name := fn.String()
if ext := externals[name]; ext != nil {
if i.mode&EnableTracing != 0 {
fmt.Fprintln(os.Stderr, "\t(external)")
}
return ext(fr, args)
}
if fn.Blocks == nil {
panic("no code for function: " + name)
}
}
fr.env = make(map[ssa.Value]value)
fr.block = fn.Blocks[0]
fr.locals = make([]value, len(fn.Locals))
for i, l := range fn.Locals {
fr.locals[i] = zero(deref(l.Type()))
fr.env[l] = &fr.locals[i]
}
for i, p := range fn.Params {
fr.env[p] = args[i]
}
for i, fv := range fn.FreeVars {
fr.env[fv] = env[i]
}
for fr.block != nil {
runFrame(fr)
}
// Destroy the locals to avoid accidental use after return.
for i := range fn.Locals {
fr.locals[i] = bad{}
}
return fr.result
}
// runFrame executes SSA instructions starting at fr.block and
// continuing until a return, a panic, or a recovered panic.
//
// After a panic, runFrame panics.
//
// After a normal return, fr.result contains the result of the call
// and fr.block is nil.
//
// A recovered panic in a function without named return parameters
// (NRPs) becomes a normal return of the zero value of the function's
// result type.
//
// After a recovered panic in a function with NRPs, fr.result is
// undefined and fr.block contains the block at which to resume
// control.
//
func runFrame(fr *frame) {
defer func() {
if fr.block == nil {
return // normal return
}
if fr.i.mode&DisableRecover != 0 {
return // let interpreter crash
}
fr.panicking = true
fr.panic = recover()
if fr.i.mode&EnableTracing != 0 {
fmt.Fprintf(os.Stderr, "Panicking: %T %v.\n", fr.panic, fr.panic)
}
fr.runDefers()
fr.block = fr.fn.Recover
}()
for {
if fr.i.mode&EnableTracing != 0 {
fmt.Fprintf(os.Stderr, ".%s:\n", fr.block)
}
block:
for _, instr := range fr.block.Instrs {
if fr.i.mode&EnableTracing != 0 {
if v, ok := instr.(ssa.Value); ok {
fmt.Fprintln(os.Stderr, "\t", v.Name(), "=", instr)
} else {
fmt.Fprintln(os.Stderr, "\t", instr)
}
}
switch visitInstr(fr, instr) {
case kReturn:
return
case kNext:
// no-op
case kJump:
break block
}
}
}
}
// doRecover implements the recover() built-in.
func doRecover(caller *frame) value {
// recover() must be exactly one level beneath the deferred
// function (two levels beneath the panicking function) to
// have any effect. Thus we ignore both "defer recover()" and
// "defer f() -> g() -> recover()".
if caller.i.mode&DisableRecover == 0 &&
caller != nil && !caller.panicking &&
caller.caller != nil && caller.caller.panicking {
caller.caller.panicking = false
p := caller.caller.panic
caller.caller.panic = nil
// TODO(adonovan): support runtime.Goexit.
switch p := p.(type) {
case targetPanic:
// The target program explicitly called panic().
return p.v
case runtime.Error:
// The interpreter encountered a runtime error.
return iface{caller.i.runtimeErrorString, p.Error()}
case string:
// The interpreter explicitly called panic().
return iface{caller.i.runtimeErrorString, p}
default:
panic(fmt.Sprintf("unexpected panic type %T in target call to recover()", p))
}
}
return iface{}
}
// setGlobal sets the value of a system-initialized global variable.
func setGlobal(i *interpreter, pkg *ssa.Package, name string, v value) {
if g, ok := i.globals[pkg.Var(name)]; ok {
*g = v
return
}
panic("no global variable: " + pkg.Pkg.Path() + "." + name)
}
var environ []value
func init() {
for _, s := range os.Environ() {
environ = append(environ, s)
}
environ = append(environ, "GOSSAINTERP=1")
environ = append(environ, "GOARCH="+runtime.GOARCH)
}
// deleteBodies delete the bodies of all standalone functions except the
// specified ones. A missing intrinsic leads to a clear runtime error.
func deleteBodies(pkg *ssa.Package, except ...string) {
keep := make(map[string]bool)
for _, e := range except {
keep[e] = true
}
for _, mem := range pkg.Members {
if fn, ok := mem.(*ssa.Function); ok && !keep[fn.Name()] {
fn.Blocks = nil
}
}
}
// Interpret interprets the Go program whose main package is mainpkg.
// mode specifies various interpreter options. filename and args are
// the initial values of os.Args for the target program. sizes is the
// effective type-sizing function for this program.
//
// Interpret returns the exit code of the program: 2 for panic (like
// gc does), or the argument to os.Exit for normal termination.
//
// The SSA program must include the "runtime" package.
//
func Interpret(mainpkg *ssa.Package, mode Mode, sizes types.Sizes, filename string, args []string) (exitCode int) {
if syswrite == nil {
fmt.Fprintln(os.Stderr, "Interpret: unsupported platform.")
return 1
}
i := &interpreter{
prog: mainpkg.Prog,
globals: make(map[ssa.Value]*value),
mode: mode,
sizes: sizes,
goroutines: 1,
}
runtimePkg := i.prog.ImportedPackage("runtime")
if runtimePkg == nil {
panic("ssa.Program doesn't include runtime package")
}
i.runtimeErrorString = runtimePkg.Type("errorString").Object().Type()
initReflect(i)
i.osArgs = append(i.osArgs, filename)
for _, arg := range args {
i.osArgs = append(i.osArgs, arg)
}
for _, pkg := range i.prog.AllPackages() {
// Initialize global storage.
for _, m := range pkg.Members {
switch v := m.(type) {
case *ssa.Global:
cell := zero(deref(v.Type()))
i.globals[v] = &cell
}
}
// Ad-hoc initialization for magic system variables.
switch pkg.Pkg.Path() {
case "syscall":
setGlobal(i, pkg, "envs", environ)
case "reflect":
deleteBodies(pkg, "DeepEqual", "deepValueEqual")
case "runtime":
sz := sizes.Sizeof(pkg.Pkg.Scope().Lookup("MemStats").Type())
setGlobal(i, pkg, "sizeof_C_MStats", uintptr(sz))
deleteBodies(pkg, "GOROOT", "gogetenv")
}
}
// Top-level error handler.
exitCode = 2
defer func() {
if exitCode != 2 || i.mode&DisableRecover != 0 {
return
}
switch p := recover().(type) {
case exitPanic:
exitCode = int(p)
return
case targetPanic:
fmt.Fprintln(os.Stderr, "panic:", toString(p.v))
case runtime.Error:
fmt.Fprintln(os.Stderr, "panic:", p.Error())
case string:
fmt.Fprintln(os.Stderr, "panic:", p)
default:
fmt.Fprintf(os.Stderr, "panic: unexpected type: %T: %v\n", p, p)
}
// TODO(adonovan): dump panicking interpreter goroutine?
// buf := make([]byte, 0x10000)
// runtime.Stack(buf, false)
// fmt.Fprintln(os.Stderr, string(buf))
// (Or dump panicking target goroutine?)
}()
// Run!
call(i, nil, token.NoPos, mainpkg.Func("init"), nil)
if mainFn := mainpkg.Func("main"); mainFn != nil {
call(i, nil, token.NoPos, mainFn, nil)
exitCode = 0
} else {
fmt.Fprintln(os.Stderr, "No main function.")
exitCode = 1
}
return
}
// deref returns a pointer's element type; otherwise it returns typ.
// TODO(adonovan): Import from ssa?
func deref(typ types.Type) types.Type {
if p, ok := typ.Underlying().(*types.Pointer); ok {
return p.Elem()
}
return typ
}

317
vendor/golang.org/x/tools/go/ssa/interp/interp_test.go generated vendored Normal file
View File

@@ -0,0 +1,317 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build linux darwin
package interp_test
import (
"bytes"
"fmt"
"go/build"
"go/types"
"os"
"path/filepath"
"runtime"
"strings"
"testing"
"time"
"golang.org/x/tools/go/loader"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/ssa/interp"
"golang.org/x/tools/go/ssa/ssautil"
)
// Each line contains a space-separated list of $GOROOT/test/
// filenames comprising the main package of a program.
// They are ordered quickest-first, roughly.
//
// TODO(adonovan): integrate into the $GOROOT/test driver scripts,
// golden file checking, etc.
var gorootTestTests = []string{
"235.go",
"alias1.go",
"chancap.go",
"func5.go",
"func6.go",
"func7.go",
"func8.go",
"helloworld.go",
"varinit.go",
"escape3.go",
"initcomma.go",
"cmp.go",
"compos.go",
"turing.go",
"indirect.go",
"complit.go",
"for.go",
"struct0.go",
"intcvt.go",
"printbig.go",
"deferprint.go",
"escape.go",
"range.go",
"const4.go",
"float_lit.go",
"bigalg.go",
"decl.go",
"if.go",
"named.go",
"bigmap.go",
"func.go",
"reorder2.go",
"closure.go",
"gc.go",
"simassign.go",
"iota.go",
"nilptr2.go",
"goprint.go", // doesn't actually assert anything (cmpout)
"utf.go",
"method.go",
"char_lit.go",
"env.go",
"int_lit.go",
"string_lit.go",
"defer.go",
"typeswitch.go",
"stringrange.go",
"reorder.go",
"method3.go",
"literal.go",
"nul1.go", // doesn't actually assert anything (errorcheckoutput)
"zerodivide.go",
"convert.go",
"convT2X.go",
"switch.go",
"initialize.go",
"ddd.go",
"blank.go", // partly disabled
"map.go",
"closedchan.go",
"divide.go",
"rename.go",
"const3.go",
"nil.go",
"recover.go", // reflection parts disabled
"recover1.go",
"recover2.go",
"recover3.go",
"typeswitch1.go",
"floatcmp.go",
"crlf.go", // doesn't actually assert anything (runoutput)
// Slow tests follow.
"bom.go", // ~1.7s
"gc1.go", // ~1.7s
"cmplxdivide.go cmplxdivide1.go", // ~2.4s
// Working, but not worth enabling:
// "append.go", // works, but slow (15s).
// "gc2.go", // works, but slow, and cheats on the memory check.
// "sigchld.go", // works, but only on POSIX.
// "peano.go", // works only up to n=9, and slow even then.
// "stack.go", // works, but too slow (~30s) by default.
// "solitaire.go", // works, but too slow (~30s).
// "const.go", // works but for but one bug: constant folder doesn't consider representations.
// "init1.go", // too slow (80s) and not that interesting. Cheats on ReadMemStats check too.
// "rotate.go rotate0.go", // emits source for a test
// "rotate.go rotate1.go", // emits source for a test
// "rotate.go rotate2.go", // emits source for a test
// "rotate.go rotate3.go", // emits source for a test
// "64bit.go", // emits source for a test
// "run.go", // test driver, not a test.
// Broken. TODO(adonovan): fix.
// copy.go // very slow; but with N=4 quickly crashes, slice index out of range.
// nilptr.go // interp: V > uintptr not implemented. Slow test, lots of mem
// args.go // works, but requires specific os.Args from the driver.
// index.go // a template, not a real test.
// mallocfin.go // SetFinalizer not implemented.
// TODO(adonovan): add tests from $GOROOT/test/* subtrees:
// bench chan bugs fixedbugs interface ken.
}
// These are files in go.tools/go/ssa/interp/testdata/.
var testdataTests = []string{
"boundmeth.go",
"complit.go",
"coverage.go",
"defer.go",
"fieldprom.go",
"ifaceconv.go",
"ifaceprom.go",
"initorder.go",
"methprom.go",
"mrvchain.go",
"range.go",
"recover.go",
"reflect.go",
"static.go",
"callstack.go",
}
type successPredicate func(exitcode int, output string) error
func run(t *testing.T, dir, input string, success successPredicate) bool {
if runtime.GOOS == "darwin" {
t.Skip("skipping on darwin until golang.org/issue/23166 is fixed")
}
fmt.Printf("Input: %s\n", input)
start := time.Now()
var inputs []string
for _, i := range strings.Split(input, " ") {
if strings.HasSuffix(i, ".go") {
i = dir + i
}
inputs = append(inputs, i)
}
var conf loader.Config
if _, err := conf.FromArgs(inputs, true); err != nil {
t.Errorf("FromArgs(%s) failed: %s", inputs, err)
return false
}
conf.Import("runtime")
// Print a helpful hint if we don't make it to the end.
var hint string
defer func() {
if hint != "" {
fmt.Println("FAIL")
fmt.Println(hint)
} else {
fmt.Println("PASS")
}
interp.CapturedOutput = nil
}()
hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build golang.org/x/tools/cmd/ssadump && ./ssadump -test -build=CFP %s\n", input)
iprog, err := conf.Load()
if err != nil {
t.Errorf("conf.Load(%s) failed: %s", inputs, err)
return false
}
prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
prog.Build()
// Find first main or test package among the initial packages.
var mainPkg *ssa.Package
for _, info := range iprog.InitialPackages() {
if info.Pkg.Path() == "runtime" {
continue // not an initial package
}
p := prog.Package(info.Pkg)
if p.Pkg.Name() == "main" && p.Func("main") != nil {
mainPkg = p
break
}
mainPkg = prog.CreateTestMainPackage(p)
if mainPkg != nil {
break
}
}
if mainPkg == nil {
t.Fatalf("no main or test packages among initial packages: %s", inputs)
}
var out bytes.Buffer
interp.CapturedOutput = &out
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, &types.StdSizes{WordSize: 8, MaxAlign: 8}, inputs[0], []string{})
// The definition of success varies with each file.
if err := success(exitCode, out.String()); err != nil {
t.Errorf("interp.Interpret(%s) failed: %s", inputs, err)
return false
}
hint = "" // call off the hounds
if false {
fmt.Println(input, time.Since(start)) // test profiling
}
return true
}
const slash = string(os.PathSeparator)
func printFailures(failures []string) {
if failures != nil {
fmt.Println("The following tests failed:")
for _, f := range failures {
fmt.Printf("\t%s\n", f)
}
}
}
func success(exitcode int, output string) error {
if exitcode != 0 {
return fmt.Errorf("exit code was %d", exitcode)
}
if strings.Contains(output, "BUG") {
return fmt.Errorf("exited zero but output contained 'BUG'")
}
return nil
}
// TestTestdataFiles runs the interpreter on testdata/*.go.
func TestTestdataFiles(t *testing.T) {
var failures []string
start := time.Now()
for _, input := range testdataTests {
if testing.Short() && time.Since(start) > 30*time.Second {
printFailures(failures)
t.Skipf("timeout - aborting test")
}
if !run(t, "testdata"+slash, input, success) {
failures = append(failures, input)
}
}
printFailures(failures)
}
// TestGorootTest runs the interpreter on $GOROOT/test/*.go.
func TestGorootTest(t *testing.T) {
if testing.Short() {
t.Skip() // too slow (~30s)
}
var failures []string
for _, input := range gorootTestTests {
if !run(t, filepath.Join(build.Default.GOROOT, "test")+slash, input, success) {
failures = append(failures, input)
}
}
printFailures(failures)
}
// CreateTestMainPackage should return nil if there were no tests.
func TestNullTestmainPackage(t *testing.T) {
var conf loader.Config
conf.CreateFromFilenames("", "testdata/b_test.go")
iprog, err := conf.Load()
if err != nil {
t.Fatalf("CreatePackages failed: %s", err)
}
prog := ssautil.CreateProgram(iprog, ssa.SanityCheckFunctions)
mainPkg := prog.Package(iprog.Created[0].Pkg)
if mainPkg.Func("main") != nil {
t.Fatalf("unexpected main function")
}
if prog.CreateTestMainPackage(mainPkg) != nil {
t.Fatalf("CreateTestMainPackage returned non-nil")
}
}

121
vendor/golang.org/x/tools/go/ssa/interp/map.go generated vendored Normal file
View File

@@ -0,0 +1,121 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package interp
// Custom hashtable atop map.
// For use when the key's equivalence relation is not consistent with ==.
// The Go specification doesn't address the atomicity of map operations.
// The FAQ states that an implementation is permitted to crash on
// concurrent map access.
import (
"go/types"
)
type hashable interface {
hash(t types.Type) int
eq(t types.Type, x interface{}) bool
}
type entry struct {
key hashable
value value
next *entry
}
// A hashtable atop the built-in map. Since each bucket contains
// exactly one hash value, there's no need to perform hash-equality
// tests when walking the linked list. Rehashing is done by the
// underlying map.
type hashmap struct {
keyType types.Type
table map[int]*entry
length int // number of entries in map
}
// makeMap returns an empty initialized map of key type kt,
// preallocating space for reserve elements.
func makeMap(kt types.Type, reserve int) value {
if usesBuiltinMap(kt) {
return make(map[value]value, reserve)
}
return &hashmap{keyType: kt, table: make(map[int]*entry, reserve)}
}
// delete removes the association for key k, if any.
func (m *hashmap) delete(k hashable) {
if m != nil {
hash := k.hash(m.keyType)
head := m.table[hash]
if head != nil {
if k.eq(m.keyType, head.key) {
m.table[hash] = head.next
m.length--
return
}
prev := head
for e := head.next; e != nil; e = e.next {
if k.eq(m.keyType, e.key) {
prev.next = e.next
m.length--
return
}
prev = e
}
}
}
}
// lookup returns the value associated with key k, if present, or
// value(nil) otherwise.
func (m *hashmap) lookup(k hashable) value {
if m != nil {
hash := k.hash(m.keyType)
for e := m.table[hash]; e != nil; e = e.next {
if k.eq(m.keyType, e.key) {
return e.value
}
}
}
return nil
}
// insert updates the map to associate key k with value v. If there
// was already an association for an eq() (though not necessarily ==)
// k, the previous key remains in the map and its associated value is
// updated.
func (m *hashmap) insert(k hashable, v value) {
hash := k.hash(m.keyType)
head := m.table[hash]
for e := head; e != nil; e = e.next {
if k.eq(m.keyType, e.key) {
e.value = v
return
}
}
m.table[hash] = &entry{
key: k,
value: v,
next: head,
}
m.length++
}
// len returns the number of key/value associations in the map.
func (m *hashmap) len() int {
if m != nil {
return m.length
}
return 0
}
// entries returns a rangeable map of entries.
func (m *hashmap) entries() map[int]*entry {
if m != nil {
return m.table
}
return nil
}

1396
vendor/golang.org/x/tools/go/ssa/interp/ops.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

574
vendor/golang.org/x/tools/go/ssa/interp/reflect.go generated vendored Normal file
View File

@@ -0,0 +1,574 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package interp
// Emulated "reflect" package.
//
// We completely replace the built-in "reflect" package.
// The only thing clients can depend upon are that reflect.Type is an
// interface and reflect.Value is an (opaque) struct.
import (
"fmt"
"go/token"
"go/types"
"reflect"
"unsafe"
"golang.org/x/tools/go/ssa"
)
type opaqueType struct {
types.Type
name string
}
func (t *opaqueType) String() string { return t.name }
// A bogus "reflect" type-checker package. Shared across interpreters.
var reflectTypesPackage = types.NewPackage("reflect", "reflect")
// rtype is the concrete type the interpreter uses to implement the
// reflect.Type interface.
//
// type rtype <opaque>
var rtypeType = makeNamedType("rtype", &opaqueType{nil, "rtype"})
// error is an (interpreted) named type whose underlying type is string.
// The interpreter uses it for all implementations of the built-in error
// interface that it creates.
// We put it in the "reflect" package for expedience.
//
// type error string
var errorType = makeNamedType("error", &opaqueType{nil, "error"})
func makeNamedType(name string, underlying types.Type) *types.Named {
obj := types.NewTypeName(token.NoPos, reflectTypesPackage, name, nil)
return types.NewNamed(obj, underlying, nil)
}
func makeReflectValue(t types.Type, v value) value {
return structure{rtype{t}, v}
}
// Given a reflect.Value, returns its rtype.
func rV2T(v value) rtype {
return v.(structure)[0].(rtype)
}
// Given a reflect.Value, returns the underlying interpreter value.
func rV2V(v value) value {
return v.(structure)[1]
}
// makeReflectType boxes up an rtype in a reflect.Type interface.
func makeReflectType(rt rtype) value {
return iface{rtypeType, rt}
}
func ext۰reflect۰Init(fr *frame, args []value) value {
// Signature: func()
return nil
}
func ext۰reflect۰rtype۰Bits(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) int
rt := args[0].(rtype).t
basic, ok := rt.Underlying().(*types.Basic)
if !ok {
panic(fmt.Sprintf("reflect.Type.Bits(%T): non-basic type", rt))
}
return int(fr.i.sizes.Sizeof(basic)) * 8
}
func ext۰reflect۰rtype۰Elem(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) reflect.Type
return makeReflectType(rtype{args[0].(rtype).t.Underlying().(interface {
Elem() types.Type
}).Elem()})
}
func ext۰reflect۰rtype۰Field(fr *frame, args []value) value {
// Signature: func (t reflect.rtype, i int) reflect.StructField
st := args[0].(rtype).t.Underlying().(*types.Struct)
i := args[1].(int)
f := st.Field(i)
return structure{
f.Name(),
f.Pkg().Path(),
makeReflectType(rtype{f.Type()}),
st.Tag(i),
0, // TODO(adonovan): offset
[]value{}, // TODO(adonovan): indices
f.Anonymous(),
}
}
func ext۰reflect۰rtype۰In(fr *frame, args []value) value {
// Signature: func (t reflect.rtype, i int) int
i := args[1].(int)
return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Params().At(i).Type()})
}
func ext۰reflect۰rtype۰Kind(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) uint
return uint(reflectKind(args[0].(rtype).t))
}
func ext۰reflect۰rtype۰NumField(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) int
return args[0].(rtype).t.Underlying().(*types.Struct).NumFields()
}
func ext۰reflect۰rtype۰NumIn(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) int
return args[0].(rtype).t.(*types.Signature).Params().Len()
}
func ext۰reflect۰rtype۰NumMethod(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) int
return fr.i.prog.MethodSets.MethodSet(args[0].(rtype).t).Len()
}
func ext۰reflect۰rtype۰NumOut(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) int
return args[0].(rtype).t.(*types.Signature).Results().Len()
}
func ext۰reflect۰rtype۰Out(fr *frame, args []value) value {
// Signature: func (t reflect.rtype, i int) int
i := args[1].(int)
return makeReflectType(rtype{args[0].(rtype).t.(*types.Signature).Results().At(i).Type()})
}
func ext۰reflect۰rtype۰Size(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) uintptr
return uintptr(fr.i.sizes.Sizeof(args[0].(rtype).t))
}
func ext۰reflect۰rtype۰String(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) string
return args[0].(rtype).t.String()
}
func ext۰reflect۰New(fr *frame, args []value) value {
// Signature: func (t reflect.Type) reflect.Value
t := args[0].(iface).v.(rtype).t
alloc := zero(t)
return makeReflectValue(types.NewPointer(t), &alloc)
}
func ext۰reflect۰SliceOf(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) Type
return makeReflectType(rtype{types.NewSlice(args[0].(iface).v.(rtype).t)})
}
func ext۰reflect۰TypeOf(fr *frame, args []value) value {
// Signature: func (t reflect.rtype) Type
return makeReflectType(rtype{args[0].(iface).t})
}
func ext۰reflect۰ValueOf(fr *frame, args []value) value {
// Signature: func (interface{}) reflect.Value
itf := args[0].(iface)
return makeReflectValue(itf.t, itf.v)
}
func ext۰reflect۰Zero(fr *frame, args []value) value {
// Signature: func (t reflect.Type) reflect.Value
t := args[0].(iface).v.(rtype).t
return makeReflectValue(t, zero(t))
}
func reflectKind(t types.Type) reflect.Kind {
switch t := t.(type) {
case *types.Named:
return reflectKind(t.Underlying())
case *types.Basic:
switch t.Kind() {
case types.Bool:
return reflect.Bool
case types.Int:
return reflect.Int
case types.Int8:
return reflect.Int8
case types.Int16:
return reflect.Int16
case types.Int32:
return reflect.Int32
case types.Int64:
return reflect.Int64
case types.Uint:
return reflect.Uint
case types.Uint8:
return reflect.Uint8
case types.Uint16:
return reflect.Uint16
case types.Uint32:
return reflect.Uint32
case types.Uint64:
return reflect.Uint64
case types.Uintptr:
return reflect.Uintptr
case types.Float32:
return reflect.Float32
case types.Float64:
return reflect.Float64
case types.Complex64:
return reflect.Complex64
case types.Complex128:
return reflect.Complex128
case types.String:
return reflect.String
case types.UnsafePointer:
return reflect.UnsafePointer
}
case *types.Array:
return reflect.Array
case *types.Chan:
return reflect.Chan
case *types.Signature:
return reflect.Func
case *types.Interface:
return reflect.Interface
case *types.Map:
return reflect.Map
case *types.Pointer:
return reflect.Ptr
case *types.Slice:
return reflect.Slice
case *types.Struct:
return reflect.Struct
}
panic(fmt.Sprint("unexpected type: ", t))
}
func ext۰reflect۰Value۰Kind(fr *frame, args []value) value {
// Signature: func (reflect.Value) uint
return uint(reflectKind(rV2T(args[0]).t))
}
func ext۰reflect۰Value۰String(fr *frame, args []value) value {
// Signature: func (reflect.Value) string
return toString(rV2V(args[0]))
}
func ext۰reflect۰Value۰Type(fr *frame, args []value) value {
// Signature: func (reflect.Value) reflect.Type
return makeReflectType(rV2T(args[0]))
}
func ext۰reflect۰Value۰Uint(fr *frame, args []value) value {
// Signature: func (reflect.Value) uint64
switch v := rV2V(args[0]).(type) {
case uint:
return uint64(v)
case uint8:
return uint64(v)
case uint16:
return uint64(v)
case uint32:
return uint64(v)
case uint64:
return uint64(v)
case uintptr:
return uint64(v)
}
panic("reflect.Value.Uint")
}
func ext۰reflect۰Value۰Len(fr *frame, args []value) value {
// Signature: func (reflect.Value) int
switch v := rV2V(args[0]).(type) {
case string:
return len(v)
case array:
return len(v)
case chan value:
return cap(v)
case []value:
return len(v)
case *hashmap:
return v.len()
case map[value]value:
return len(v)
default:
panic(fmt.Sprintf("reflect.(Value).Len(%v)", v))
}
}
func ext۰reflect۰Value۰MapIndex(fr *frame, args []value) value {
// Signature: func (reflect.Value) Value
tValue := rV2T(args[0]).t.Underlying().(*types.Map).Key()
k := rV2V(args[1])
switch m := rV2V(args[0]).(type) {
case map[value]value:
if v, ok := m[k]; ok {
return makeReflectValue(tValue, v)
}
case *hashmap:
if v := m.lookup(k.(hashable)); v != nil {
return makeReflectValue(tValue, v)
}
default:
panic(fmt.Sprintf("(reflect.Value).MapIndex(%T, %T)", m, k))
}
return makeReflectValue(nil, nil)
}
func ext۰reflect۰Value۰MapKeys(fr *frame, args []value) value {
// Signature: func (reflect.Value) []Value
var keys []value
tKey := rV2T(args[0]).t.Underlying().(*types.Map).Key()
switch v := rV2V(args[0]).(type) {
case map[value]value:
for k := range v {
keys = append(keys, makeReflectValue(tKey, k))
}
case *hashmap:
for _, e := range v.entries() {
for ; e != nil; e = e.next {
keys = append(keys, makeReflectValue(tKey, e.key))
}
}
default:
panic(fmt.Sprintf("(reflect.Value).MapKeys(%T)", v))
}
return keys
}
func ext۰reflect۰Value۰NumField(fr *frame, args []value) value {
// Signature: func (reflect.Value) int
return len(rV2V(args[0]).(structure))
}
func ext۰reflect۰Value۰NumMethod(fr *frame, args []value) value {
// Signature: func (reflect.Value) int
return fr.i.prog.MethodSets.MethodSet(rV2T(args[0]).t).Len()
}
func ext۰reflect۰Value۰Pointer(fr *frame, args []value) value {
// Signature: func (v reflect.Value) uintptr
switch v := rV2V(args[0]).(type) {
case *value:
return uintptr(unsafe.Pointer(v))
case chan value:
return reflect.ValueOf(v).Pointer()
case []value:
return reflect.ValueOf(v).Pointer()
case *hashmap:
return reflect.ValueOf(v.entries()).Pointer()
case map[value]value:
return reflect.ValueOf(v).Pointer()
case *ssa.Function:
return uintptr(unsafe.Pointer(v))
case *closure:
return uintptr(unsafe.Pointer(v))
default:
panic(fmt.Sprintf("reflect.(Value).Pointer(%T)", v))
}
}
func ext۰reflect۰Value۰Index(fr *frame, args []value) value {
// Signature: func (v reflect.Value, i int) Value
i := args[1].(int)
t := rV2T(args[0]).t.Underlying()
switch v := rV2V(args[0]).(type) {
case array:
return makeReflectValue(t.(*types.Array).Elem(), v[i])
case []value:
return makeReflectValue(t.(*types.Slice).Elem(), v[i])
default:
panic(fmt.Sprintf("reflect.(Value).Index(%T)", v))
}
}
func ext۰reflect۰Value۰Bool(fr *frame, args []value) value {
// Signature: func (reflect.Value) bool
return rV2V(args[0]).(bool)
}
func ext۰reflect۰Value۰CanAddr(fr *frame, args []value) value {
// Signature: func (v reflect.Value) bool
// Always false for our representation.
return false
}
func ext۰reflect۰Value۰CanInterface(fr *frame, args []value) value {
// Signature: func (v reflect.Value) bool
// Always true for our representation.
return true
}
func ext۰reflect۰Value۰Elem(fr *frame, args []value) value {
// Signature: func (v reflect.Value) reflect.Value
switch x := rV2V(args[0]).(type) {
case iface:
return makeReflectValue(x.t, x.v)
case *value:
return makeReflectValue(rV2T(args[0]).t.Underlying().(*types.Pointer).Elem(), *x)
default:
panic(fmt.Sprintf("reflect.(Value).Elem(%T)", x))
}
}
func ext۰reflect۰Value۰Field(fr *frame, args []value) value {
// Signature: func (v reflect.Value, i int) reflect.Value
v := args[0]
i := args[1].(int)
return makeReflectValue(rV2T(v).t.Underlying().(*types.Struct).Field(i).Type(), rV2V(v).(structure)[i])
}
func ext۰reflect۰Value۰Float(fr *frame, args []value) value {
// Signature: func (reflect.Value) float64
switch v := rV2V(args[0]).(type) {
case float32:
return float64(v)
case float64:
return float64(v)
}
panic("reflect.Value.Float")
}
func ext۰reflect۰Value۰Interface(fr *frame, args []value) value {
// Signature: func (v reflect.Value) interface{}
return ext۰reflect۰valueInterface(fr, args)
}
func ext۰reflect۰Value۰Int(fr *frame, args []value) value {
// Signature: func (reflect.Value) int64
switch x := rV2V(args[0]).(type) {
case int:
return int64(x)
case int8:
return int64(x)
case int16:
return int64(x)
case int32:
return int64(x)
case int64:
return x
default:
panic(fmt.Sprintf("reflect.(Value).Int(%T)", x))
}
}
func ext۰reflect۰Value۰IsNil(fr *frame, args []value) value {
// Signature: func (reflect.Value) bool
switch x := rV2V(args[0]).(type) {
case *value:
return x == nil
case chan value:
return x == nil
case map[value]value:
return x == nil
case *hashmap:
return x == nil
case iface:
return x.t == nil
case []value:
return x == nil
case *ssa.Function:
return x == nil
case *ssa.Builtin:
return x == nil
case *closure:
return x == nil
default:
panic(fmt.Sprintf("reflect.(Value).IsNil(%T)", x))
}
}
func ext۰reflect۰Value۰IsValid(fr *frame, args []value) value {
// Signature: func (reflect.Value) bool
return rV2V(args[0]) != nil
}
func ext۰reflect۰Value۰Set(fr *frame, args []value) value {
// TODO(adonovan): implement.
return nil
}
func ext۰reflect۰valueInterface(fr *frame, args []value) value {
// Signature: func (v reflect.Value, safe bool) interface{}
v := args[0].(structure)
return iface{rV2T(v).t, rV2V(v)}
}
func ext۰reflect۰error۰Error(fr *frame, args []value) value {
return args[0]
}
// newMethod creates a new method of the specified name, package and receiver type.
func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function {
// TODO(adonovan): fix: hack: currently the only part of Signature
// that is needed is the "pointerness" of Recv.Type, and for
// now, we'll set it to always be false since we're only
// concerned with rtype. Encapsulate this better.
sig := types.NewSignature(types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false)
fn := pkg.Prog.NewFunction(name, sig, "fake reflect method")
fn.Pkg = pkg
return fn
}
func initReflect(i *interpreter) {
i.reflectPackage = &ssa.Package{
Prog: i.prog,
Pkg: reflectTypesPackage,
Members: make(map[string]ssa.Member),
}
// Clobber the type-checker's notion of reflect.Value's
// underlying type so that it more closely matches the fake one
// (at least in the number of fields---we lie about the type of
// the rtype field).
//
// We must ensure that calls to (ssa.Value).Type() return the
// fake type so that correct "shape" is used when allocating
// variables, making zero values, loading, and storing.
//
// TODO(adonovan): obviously this is a hack. We need a cleaner
// way to fake the reflect package (almost---DeepEqual is fine).
// One approach would be not to even load its source code, but
// provide fake source files. This would guarantee that no bad
// information leaks into other packages.
if r := i.prog.ImportedPackage("reflect"); r != nil {
rV := r.Pkg.Scope().Lookup("Value").Type().(*types.Named)
// delete bodies of the old methods
mset := i.prog.MethodSets.MethodSet(rV)
for j := 0; j < mset.Len(); j++ {
i.prog.MethodValue(mset.At(j)).Blocks = nil
}
tEface := types.NewInterface(nil, nil).Complete()
rV.SetUnderlying(types.NewStruct([]*types.Var{
types.NewField(token.NoPos, r.Pkg, "t", tEface, false), // a lie
types.NewField(token.NoPos, r.Pkg, "v", tEface, false),
}, nil))
}
i.rtypeMethods = methodSet{
"Bits": newMethod(i.reflectPackage, rtypeType, "Bits"),
"Elem": newMethod(i.reflectPackage, rtypeType, "Elem"),
"Field": newMethod(i.reflectPackage, rtypeType, "Field"),
"In": newMethod(i.reflectPackage, rtypeType, "In"),
"Kind": newMethod(i.reflectPackage, rtypeType, "Kind"),
"NumField": newMethod(i.reflectPackage, rtypeType, "NumField"),
"NumIn": newMethod(i.reflectPackage, rtypeType, "NumIn"),
"NumMethod": newMethod(i.reflectPackage, rtypeType, "NumMethod"),
"NumOut": newMethod(i.reflectPackage, rtypeType, "NumOut"),
"Out": newMethod(i.reflectPackage, rtypeType, "Out"),
"Size": newMethod(i.reflectPackage, rtypeType, "Size"),
"String": newMethod(i.reflectPackage, rtypeType, "String"),
}
i.errorMethods = methodSet{
"Error": newMethod(i.reflectPackage, errorType, "Error"),
}
}

View File

@@ -0,0 +1,17 @@
package a
import "testing"
func TestFoo(t *testing.T) {
t.Error("foo")
}
func TestBar(t *testing.T) {
t.Error("bar")
}
func BenchmarkWiz(b *testing.B) {
b.Error("wiz")
}
// Don't test Examples since that testing package needs pipe(2) for that.

View File

@@ -0,0 +1,11 @@
package b
import "testing"
func NotATest(t *testing.T) {
t.Error("foo")
}
func NotABenchmark(b *testing.B) {
b.Error("wiz")
}

View File

@@ -0,0 +1,144 @@
// Tests of bound method closures.
package main
import "fmt"
func assert(b bool) {
if !b {
panic("oops")
}
}
type I int
func (i I) add(x int) int {
return int(i) + x
}
func valueReceiver() {
var three I = 3
assert(three.add(5) == 8)
var add3 func(int) int = three.add
assert(add3(5) == 8)
}
type S struct{ x int }
func (s *S) incr() {
s.x++
}
func (s *S) get() int {
return s.x
}
func pointerReceiver() {
ps := new(S)
incr := ps.incr
get := ps.get
assert(get() == 0)
incr()
incr()
incr()
assert(get() == 3)
}
func addressibleValuePointerReceiver() {
var s S
incr := s.incr
get := s.get
assert(get() == 0)
incr()
incr()
incr()
assert(get() == 3)
}
type S2 struct {
S
}
func promotedReceiver() {
var s2 S2
incr := s2.incr
get := s2.get
assert(get() == 0)
incr()
incr()
incr()
assert(get() == 3)
}
func anonStruct() {
var s struct{ S }
incr := s.incr
get := s.get
assert(get() == 0)
incr()
incr()
incr()
assert(get() == 3)
}
func typeCheck() {
var i interface{}
i = (*S).incr
_ = i.(func(*S)) // type assertion: receiver type prepended to params
var s S
i = s.incr
_ = i.(func()) // type assertion: receiver type disappears
}
type errString string
func (err errString) Error() string {
return string(err)
}
// Regression test for a builder crash.
func regress1(x error) func() string {
return x.Error
}
// Regression test for b/7269:
// taking the value of an interface method performs a nil check.
func nilInterfaceMethodValue() {
err := fmt.Errorf("ok")
f := err.Error
if got := f(); got != "ok" {
panic(got)
}
err = nil
if got := f(); got != "ok" {
panic(got)
}
defer func() {
r := fmt.Sprint(recover())
// runtime panic string varies across toolchains
if r != "runtime error: interface conversion: interface is nil, not error" &&
r != "runtime error: invalid memory address or nil pointer dereference" {
panic("want runtime panic from nil interface method value, got " + r)
}
}()
f = err.Error // runtime panic: err is nil
panic("unreachable")
}
func main() {
valueReceiver()
pointerReceiver()
addressibleValuePointerReceiver()
promotedReceiver()
anonStruct()
typeCheck()
if e := regress1(errString("hi"))(); e != "hi" {
panic(e)
}
nilInterfaceMethodValue()
}

View File

@@ -0,0 +1,17 @@
package c_test
import (
"os"
"testing"
)
func TestC(t *testing.T) {
println("TestC")
}
func TestMain(m *testing.M) {
println("TestMain start")
code := m.Run()
println("TestMain end")
os.Exit(code)
}

View File

@@ -0,0 +1,52 @@
package main
import (
"fmt"
"path"
"runtime"
"strings"
)
var stack string
func f() {
pc := make([]uintptr, 6)
pc = pc[:runtime.Callers(1, pc)]
for _, f := range pc {
Func := runtime.FuncForPC(f)
name := Func.Name()
if strings.Contains(name, "$") || strings.Contains(name, ".func") {
name = "func" // anon funcs vary across toolchains
}
file, line := Func.FileLine(0)
stack += fmt.Sprintf("%s at %s:%d\n", name, path.Base(file), line)
}
}
func g() { f() }
func h() { g() }
func i() { func() { h() }() }
// Hack: the 'func' and the call to Caller are on the same line,
// to paper over differences between toolchains.
// (The interpreter's location info isn't yet complete.)
func runtimeCaller0() (uintptr, string, int, bool) { return runtime.Caller(0) }
func main() {
i()
if stack != `main.f at callstack.go:12
main.g at callstack.go:26
main.h at callstack.go:27
func at callstack.go:28
main.i at callstack.go:28
main.main at callstack.go:35
` {
panic("unexpected stack: " + stack)
}
pc, file, line, _ := runtimeCaller0()
got := fmt.Sprintf("%s @ %s:%d", runtime.FuncForPC(pc).Name(), path.Base(file), line)
if got != "main.runtimeCaller0 @ callstack.go:33" {
panic("runtime.Caller: " + got)
}
}

View File

@@ -0,0 +1,184 @@
package main
// Tests of composite literals.
import "fmt"
// Map literals.
func init() {
type M map[int]int
m1 := []*M{{1: 1}, &M{2: 2}}
want := "map[1:1] map[2:2]"
if got := fmt.Sprint(*m1[0], *m1[1]); got != want {
panic(got)
}
m2 := []M{{1: 1}, M{2: 2}}
if got := fmt.Sprint(m2[0], m2[1]); got != want {
panic(got)
}
}
// Nonliteral keys in composite literal.
func init() {
const zero int = 1
var v = []int{1 + zero: 42}
if x := fmt.Sprint(v); x != "[0 0 42]" {
panic(x)
}
}
// Test for in-place initialization.
func init() {
// struct
type S struct {
a, b int
}
s := S{1, 2}
s = S{b: 3}
if s.a != 0 {
panic("s.a != 0")
}
if s.b != 3 {
panic("s.b != 3")
}
s = S{}
if s.a != 0 {
panic("s.a != 0")
}
if s.b != 0 {
panic("s.b != 0")
}
// array
type A [4]int
a := A{2, 4, 6, 8}
a = A{1: 6, 2: 4}
if a[0] != 0 {
panic("a[0] != 0")
}
if a[1] != 6 {
panic("a[1] != 6")
}
if a[2] != 4 {
panic("a[2] != 4")
}
if a[3] != 0 {
panic("a[3] != 0")
}
a = A{}
if a[0] != 0 {
panic("a[0] != 0")
}
if a[1] != 0 {
panic("a[1] != 0")
}
if a[2] != 0 {
panic("a[2] != 0")
}
if a[3] != 0 {
panic("a[3] != 0")
}
}
// Regression test for https://github.com/golang/go/issues/10127:
// composite literal clobbers destination before reading from it.
func init() {
// map
{
type M map[string]int
m := M{"x": 1, "y": 2}
m = M{"x": m["y"], "y": m["x"]}
if m["x"] != 2 || m["y"] != 1 {
panic(fmt.Sprint(m))
}
n := M{"x": 3}
m, n = M{"x": n["x"]}, M{"x": m["x"]} // parallel assignment
if got := fmt.Sprint(m["x"], n["x"]); got != "3 2" {
panic(got)
}
}
// struct
{
type T struct{ x, y, z int }
t := T{x: 1, y: 2, z: 3}
t = T{x: t.y, y: t.z, z: t.x} // all fields
if got := fmt.Sprint(t); got != "{2 3 1}" {
panic(got)
}
t = T{x: t.y, y: t.z + 3} // not all fields
if got := fmt.Sprint(t); got != "{3 4 0}" {
panic(got)
}
u := T{x: 5, y: 6, z: 7}
t, u = T{x: u.x}, T{x: t.x} // parallel assignment
if got := fmt.Sprint(t, u); got != "{5 0 0} {3 0 0}" {
panic(got)
}
}
// array
{
a := [3]int{0: 1, 1: 2, 2: 3}
a = [3]int{0: a[1], 1: a[2], 2: a[0]} // all elements
if got := fmt.Sprint(a); got != "[2 3 1]" {
panic(got)
}
a = [3]int{0: a[1], 1: a[2] + 3} // not all elements
if got := fmt.Sprint(a); got != "[3 4 0]" {
panic(got)
}
b := [3]int{0: 5, 1: 6, 2: 7}
a, b = [3]int{0: b[0]}, [3]int{0: a[0]} // parallel assignment
if got := fmt.Sprint(a, b); got != "[5 0 0] [3 0 0]" {
panic(got)
}
}
// slice
{
s := []int{0: 1, 1: 2, 2: 3}
s = []int{0: s[1], 1: s[2], 2: s[0]} // all elements
if got := fmt.Sprint(s); got != "[2 3 1]" {
panic(got)
}
s = []int{0: s[1], 1: s[2] + 3} // not all elements
if got := fmt.Sprint(s); got != "[3 4]" {
panic(got)
}
t := []int{0: 5, 1: 6, 2: 7}
s, t = []int{0: t[0]}, []int{0: s[0]} // parallel assignment
if got := fmt.Sprint(s, t); got != "[5] [3]" {
panic(got)
}
}
}
// Regression test for https://github.com/golang/go/issues/13341:
// within a map literal, if a key expression is a composite literal,
// Go 1.5 allows its type to be omitted. An & operation may be implied.
func init() {
type S struct{ x int }
// same as map[*S]bool{&S{x: 1}: true}
m := map[*S]bool{{x: 1}: true}
for s := range m {
if s.x != 1 {
panic(s) // wrong key
}
return
}
panic("map is empty")
}
func main() {
}

View File

@@ -0,0 +1,534 @@
// This interpreter test is designed to run very quickly yet provide
// some coverage of a broad selection of constructs.
//
// Validate this file with 'go run' after editing.
// TODO(adonovan): break this into small files organized by theme.
package main
import (
"fmt"
"reflect"
)
func init() {
// Call of variadic function with (implicit) empty slice.
if x := fmt.Sprint(); x != "" {
panic(x)
}
}
type empty interface{}
type I interface {
f() int
}
type T struct{ z int }
func (t T) f() int { return t.z }
func use(interface{}) {}
var counter = 2
// Test initialization, including init blocks containing 'return'.
// Assertion is in main.
func init() {
counter *= 3
return
counter *= 3
}
func init() {
counter *= 5
return
counter *= 5
}
// Recursion.
func fib(x int) int {
if x < 2 {
return x
}
return fib(x-1) + fib(x-2)
}
func fibgen(ch chan int) {
for x := 0; x < 10; x++ {
ch <- fib(x)
}
close(ch)
}
// Goroutines and channels.
func init() {
ch := make(chan int)
go fibgen(ch)
var fibs []int
for v := range ch {
fibs = append(fibs, v)
if len(fibs) == 10 {
break
}
}
if x := fmt.Sprint(fibs); x != "[0 1 1 2 3 5 8 13 21 34]" {
panic(x)
}
}
// Test of aliasing.
func init() {
type S struct {
a, b string
}
s1 := []string{"foo", "bar"}
s2 := s1 // creates an alias
s2[0] = "wiz"
if x := fmt.Sprint(s1, s2); x != "[wiz bar] [wiz bar]" {
panic(x)
}
pa1 := &[2]string{"foo", "bar"}
pa2 := pa1 // creates an alias
pa2[0] = "wiz"
if x := fmt.Sprint(*pa1, *pa2); x != "[wiz bar] [wiz bar]" {
panic(x)
}
a1 := [2]string{"foo", "bar"}
a2 := a1 // creates a copy
a2[0] = "wiz"
if x := fmt.Sprint(a1, a2); x != "[foo bar] [wiz bar]" {
panic(x)
}
t1 := S{"foo", "bar"}
t2 := t1 // copy
t2.a = "wiz"
if x := fmt.Sprint(t1, t2); x != "{foo bar} {wiz bar}" {
panic(x)
}
}
func main() {
print() // legal
if counter != 2*3*5 {
panic(counter)
}
// Test builtins (e.g. complex) preserve named argument types.
type N complex128
var n N
n = complex(1.0, 2.0)
if n != complex(1.0, 2.0) {
panic(n)
}
if x := reflect.TypeOf(n).String(); x != "main.N" {
panic(x)
}
if real(n) != 1.0 || imag(n) != 2.0 {
panic(n)
}
// Channel + select.
ch := make(chan int, 1)
select {
case ch <- 1:
// ok
default:
panic("couldn't send")
}
if <-ch != 1 {
panic("couldn't receive")
}
// A "receive" select-case that doesn't declare its vars. (regression test)
anint := 0
ok := false
select {
case anint, ok = <-ch:
case anint = <-ch:
default:
}
_ = anint
_ = ok
// Anon structs with methods.
anon := struct{ T }{T: T{z: 1}}
if x := anon.f(); x != 1 {
panic(x)
}
var i I = anon
if x := i.f(); x != 1 {
panic(x)
}
// NB. precise output of reflect.Type.String is undefined.
if x := reflect.TypeOf(i).String(); x != "struct { main.T }" && x != "struct{main.T}" {
panic(x)
}
// fmt.
const message = "Hello, World!"
if fmt.Sprintf("%s, %s!", "Hello", "World") != message {
panic("oops")
}
// Type assertion.
type S struct {
f int
}
var e empty = S{f: 42}
switch v := e.(type) {
case S:
if v.f != 42 {
panic(v.f)
}
default:
panic(reflect.TypeOf(v))
}
if i, ok := e.(I); ok {
panic(i)
}
// Switch.
var x int
switch x {
case 1:
panic(x)
fallthrough
case 2, 3:
panic(x)
default:
// ok
}
// empty switch
switch {
}
// empty switch
switch {
default:
}
// empty switch
switch {
default:
fallthrough
case false:
}
// string -> []rune conversion.
use([]rune("foo"))
// Calls of form x.f().
type S2 struct {
f func() int
}
S2{f: func() int { return 1 }}.f() // field is a func value
T{}.f() // method call
i.f() // interface method invocation
(interface {
f() int
}(T{})).f() // anon interface method invocation
// Map lookup.
if v, ok := map[string]string{}["foo5"]; v != "" || ok {
panic("oops")
}
// Regression test: implicit address-taken struct literal
// inside literal map element.
_ = map[int]*struct{}{0: {}}
}
type mybool bool
func (mybool) f() {}
func init() {
type mybool bool
var b mybool
var i interface{} = b || b // result preserves types of operands
_ = i.(mybool)
i = false && b // result preserves type of "typed" operand
_ = i.(mybool)
i = b || true // result preserves type of "typed" operand
_ = i.(mybool)
}
func init() {
var x, y int
var b mybool = x == y // x==y is an untyped bool
b.f()
}
// Simple closures.
func init() {
b := 3
f := func(a int) int {
return a + b
}
b++
if x := f(1); x != 5 { // 1+4 == 5
panic(x)
}
b++
if x := f(2); x != 7 { // 2+5 == 7
panic(x)
}
if b := f(1) < 16 || f(2) < 17; !b {
panic("oops")
}
}
// Shifts.
func init() {
var i int64 = 1
var u uint64 = 1 << 32
if x := i << uint32(u); x != 1 {
panic(x)
}
if x := i << uint64(u); x != 0 {
panic(x)
}
}
// Implicit conversion of delete() key operand.
func init() {
type I interface{}
m := make(map[I]bool)
m[1] = true
m[I(2)] = true
if len(m) != 2 {
panic(m)
}
delete(m, I(1))
delete(m, 2)
if len(m) != 0 {
panic(m)
}
}
// An I->I conversion always succeeds.
func init() {
var x I
if I(x) != I(nil) {
panic("I->I conversion failed")
}
}
// An I->I type-assert fails iff the value is nil.
func init() {
defer func() {
r := fmt.Sprint(recover())
// Exact error varies by toolchain.
if r != "runtime error: interface conversion: interface is nil, not main.I" &&
r != "interface conversion: interface is nil, not main.I" {
panic("I->I type assertion succeeded for nil value")
}
}()
var x I
_ = x.(I)
}
//////////////////////////////////////////////////////////////////////
// Variadic bridge methods and interface thunks.
type VT int
var vcount = 0
func (VT) f(x int, y ...string) {
vcount++
if x != 1 {
panic(x)
}
if len(y) != 2 || y[0] != "foo" || y[1] != "bar" {
panic(y)
}
}
type VS struct {
VT
}
type VI interface {
f(x int, y ...string)
}
func init() {
foobar := []string{"foo", "bar"}
var s VS
s.f(1, "foo", "bar")
s.f(1, foobar...)
if vcount != 2 {
panic("s.f not called twice")
}
fn := VI.f
fn(s, 1, "foo", "bar")
fn(s, 1, foobar...)
if vcount != 4 {
panic("I.f not called twice")
}
}
// Multiple labels on same statement.
func multipleLabels() {
var trace []int
i := 0
one:
two:
for ; i < 3; i++ {
trace = append(trace, i)
switch i {
case 0:
continue two
case 1:
i++
goto one
case 2:
break two
}
}
if x := fmt.Sprint(trace); x != "[0 1 2]" {
panic(x)
}
}
func init() {
multipleLabels()
}
func init() {
// Struct equivalence ignores blank fields.
type s struct{ x, _, z int }
s1 := s{x: 1, z: 3}
s2 := s{x: 1, z: 3}
if s1 != s2 {
panic("not equal")
}
}
func init() {
// A slice var can be compared to const []T nil.
var i interface{} = []string{"foo"}
var j interface{} = []string(nil)
if i.([]string) == nil {
panic("expected i non-nil")
}
if j.([]string) != nil {
panic("expected j nil")
}
// But two slices cannot be compared, even if one is nil.
defer func() {
r := fmt.Sprint(recover())
if r != "runtime error: comparing uncomparable type []string" {
panic("want panic from slice comparison, got " + r)
}
}()
_ = i == j // interface comparison recurses on types
}
func init() {
// Regression test for SSA renaming bug.
var ints []int
for range "foo" {
var x int
x++
ints = append(ints, x)
}
if fmt.Sprint(ints) != "[1 1 1]" {
panic(ints)
}
}
// Regression test for issue 6949:
// []byte("foo") is not a constant since it allocates memory.
func init() {
var r string
for i, b := range "ABC" {
x := []byte("abc")
x[i] = byte(b)
r += string(x)
}
if r != "AbcaBcabC" {
panic(r)
}
}
// Test of 3-operand x[lo:hi:max] slice.
func init() {
s := []int{0, 1, 2, 3}
lenCapLoHi := func(x []int) [4]int { return [4]int{len(x), cap(x), x[0], x[len(x)-1]} }
if got := lenCapLoHi(s[1:3]); got != [4]int{2, 3, 1, 2} {
panic(got)
}
if got := lenCapLoHi(s[1:3:3]); got != [4]int{2, 2, 1, 2} {
panic(got)
}
max := 3
if "a"[0] == 'a' {
max = 2 // max is non-constant, even in SSA form
}
if got := lenCapLoHi(s[1:2:max]); got != [4]int{1, 1, 1, 1} {
panic(got)
}
}
var one = 1 // not a constant
// Test makeslice.
func init() {
check := func(s []string, wantLen, wantCap int) {
if len(s) != wantLen {
panic(len(s))
}
if cap(s) != wantCap {
panic(cap(s))
}
}
// SSA form:
check(make([]string, 10), 10, 10) // new([10]string)[:10]
check(make([]string, one), 1, 1) // make([]string, one, one)
check(make([]string, 0, 10), 0, 10) // new([10]string)[:0]
check(make([]string, 0, one), 0, 1) // make([]string, 0, one)
check(make([]string, one, 10), 1, 10) // new([10]string)[:one]
check(make([]string, one, one), 1, 1) // make([]string, one, one)
}
// Test that a nice error is issued by indirection wrappers.
func init() {
var ptr *T
var i I = ptr
defer func() {
r := fmt.Sprint(recover())
// Exact error varies by toolchain:
if r != "runtime error: value method (main.T).f called using nil *main.T pointer" &&
r != "value method main.T.f called using nil *T pointer" {
panic("want panic from call with nil receiver, got " + r)
}
}()
i.f()
panic("unreachable")
}
// Regression test for a subtle bug in which copying values would causes
// subcomponents of aggregate variables to change address, breaking
// aliases.
func init() {
type T struct{ f int }
var x T
p := &x.f
x = T{}
*p = 1
if x.f != 1 {
panic("lost store")
}
if p != &x.f {
panic("unstable address")
}
}

View File

@@ -0,0 +1,53 @@
package main
// Tests of defer. (Deferred recover() belongs is recover.go.)
import "fmt"
func deferMutatesResults(noArgReturn bool) (a, b int) {
defer func() {
if a != 1 || b != 2 {
panic(fmt.Sprint(a, b))
}
a, b = 3, 4
}()
if noArgReturn {
a, b = 1, 2
return
}
return 1, 2
}
func init() {
a, b := deferMutatesResults(true)
if a != 3 || b != 4 {
panic(fmt.Sprint(a, b))
}
a, b = deferMutatesResults(false)
if a != 3 || b != 4 {
panic(fmt.Sprint(a, b))
}
}
// We concatenate init blocks to make a single function, but we must
// run defers at the end of each block, not the combined function.
var deferCount = 0
func init() {
deferCount = 1
defer func() {
deferCount++
}()
// defer runs HERE
}
func init() {
// Strictly speaking the spec says deferCount may be 0 or 2
// since the relative order of init blocks is unspecified.
if deferCount != 2 {
panic(deferCount) // defer call has not run!
}
}
func main() {
}

View File

@@ -0,0 +1,114 @@
package main
// Tests of field promotion logic.
type A struct {
x int
y *int
}
type B struct {
p int
q *int
}
type C struct {
A
*B
}
type D struct {
a int
C
}
func assert(cond bool) {
if !cond {
panic("failed")
}
}
func f1(c C) {
assert(c.x == c.A.x)
assert(c.y == c.A.y)
assert(&c.x == &c.A.x)
assert(&c.y == &c.A.y)
assert(c.p == c.B.p)
assert(c.q == c.B.q)
assert(&c.p == &c.B.p)
assert(&c.q == &c.B.q)
c.x = 1
*c.y = 1
c.p = 1
*c.q = 1
}
func f2(c *C) {
assert(c.x == c.A.x)
assert(c.y == c.A.y)
assert(&c.x == &c.A.x)
assert(&c.y == &c.A.y)
assert(c.p == c.B.p)
assert(c.q == c.B.q)
assert(&c.p == &c.B.p)
assert(&c.q == &c.B.q)
c.x = 1
*c.y = 1
c.p = 1
*c.q = 1
}
func f3(d D) {
assert(d.x == d.C.A.x)
assert(d.y == d.C.A.y)
assert(&d.x == &d.C.A.x)
assert(&d.y == &d.C.A.y)
assert(d.p == d.C.B.p)
assert(d.q == d.C.B.q)
assert(&d.p == &d.C.B.p)
assert(&d.q == &d.C.B.q)
d.x = 1
*d.y = 1
d.p = 1
*d.q = 1
}
func f4(d *D) {
assert(d.x == d.C.A.x)
assert(d.y == d.C.A.y)
assert(&d.x == &d.C.A.x)
assert(&d.y == &d.C.A.y)
assert(d.p == d.C.B.p)
assert(d.q == d.C.B.q)
assert(&d.p == &d.C.B.p)
assert(&d.q == &d.C.B.q)
d.x = 1
*d.y = 1
d.p = 1
*d.q = 1
}
func main() {
y := 123
c := C{
A{x: 42, y: &y},
&B{p: 42, q: &y},
}
assert(&c.x == &c.A.x)
f1(c)
f2(&c)
d := D{C: c}
f3(d)
f4(&d)
}

View File

@@ -0,0 +1,83 @@
package main
// Tests of interface conversions and type assertions.
type I0 interface {
}
type I1 interface {
f()
}
type I2 interface {
f()
g()
}
type C0 struct{}
type C1 struct{}
func (C1) f() {}
type C2 struct{}
func (C2) f() {}
func (C2) g() {}
func main() {
var i0 I0
var i1 I1
var i2 I2
// Nil always causes a type assertion to fail, even to the
// same type.
if _, ok := i0.(I0); ok {
panic("nil i0.(I0) succeeded")
}
if _, ok := i1.(I1); ok {
panic("nil i1.(I1) succeeded")
}
if _, ok := i2.(I2); ok {
panic("nil i2.(I2) succeeded")
}
// Conversions can't fail, even with nil.
_ = I0(i0)
_ = I0(i1)
_ = I1(i1)
_ = I0(i2)
_ = I1(i2)
_ = I2(i2)
// Non-nil type assertions pass or fail based on the concrete type.
i1 = C1{}
if _, ok := i1.(I0); !ok {
panic("C1 i1.(I0) failed")
}
if _, ok := i1.(I1); !ok {
panic("C1 i1.(I1) failed")
}
if _, ok := i1.(I2); ok {
panic("C1 i1.(I2) succeeded")
}
i1 = C2{}
if _, ok := i1.(I0); !ok {
panic("C2 i1.(I0) failed")
}
if _, ok := i1.(I1); !ok {
panic("C2 i1.(I1) failed")
}
if _, ok := i1.(I2); !ok {
panic("C2 i1.(I2) failed")
}
// Conversions can't fail.
i1 = C1{}
if I0(i1) == nil {
panic("C1 I0(i1) was nil")
}
if I1(i1) == nil {
panic("C1 I1(i1) was nil")
}
}

View File

@@ -0,0 +1,58 @@
package main
// Test of promotion of methods of an interface embedded within a
// struct. In particular, this test exercises that the correct
// method is called.
type I interface {
one() int
two() string
}
type S struct {
I
}
type impl struct{}
func (impl) one() int {
return 1
}
func (impl) two() string {
return "two"
}
func main() {
var s S
s.I = impl{}
if one := s.I.one(); one != 1 {
panic(one)
}
if one := s.one(); one != 1 {
panic(one)
}
closOne := s.I.one
if one := closOne(); one != 1 {
panic(one)
}
closOne = s.one
if one := closOne(); one != 1 {
panic(one)
}
if two := s.I.two(); two != "two" {
panic(two)
}
if two := s.two(); two != "two" {
panic(two)
}
closTwo := s.I.two
if two := closTwo(); two != "two" {
panic(two)
}
closTwo = s.two
if two := closTwo(); two != "two" {
panic(two)
}
}

View File

@@ -0,0 +1,67 @@
package main
import "fmt"
// Test of initialization order of package-level vars.
var counter int
func next() int {
c := counter
counter++
return c
}
func next2() (x int, y int) {
x = next()
y = next()
return
}
func makeOrder() int {
_, _, _, _ = f, b, d, e
return 0
}
func main() {
// Initialization constraints:
// - {f,b,c/d,e} < order (ref graph traversal)
// - order < {a} (lexical order)
// - b < c/d < e < f (lexical order)
// Solution: a b c/d e f
abcdef := [6]int{a, b, c, d, e, f}
if abcdef != [6]int{0, 1, 2, 3, 4, 5} {
panic(abcdef)
}
}
var order = makeOrder()
var a, b = next(), next()
var c, d = next2()
var e, f = next(), next()
// ------------------------------------------------------------------------
var order2 []string
func create(x int, name string) int {
order2 = append(order2, name)
return x
}
var C = create(B+1, "C")
var A, B = create(1, "A"), create(2, "B")
// Initialization order of package-level value specs.
func init() {
x := fmt.Sprint(order2)
// Result varies by toolchain. This is a spec bug.
if x != "[B C A]" && // gc
x != "[A B C]" { // go/types
panic(x)
}
if C != 3 {
panic(c)
}
}

View File

@@ -0,0 +1,93 @@
package main
// Tests of method promotion logic.
type A struct{ magic int }
func (a A) x() {
if a.magic != 1 {
panic(a.magic)
}
}
func (a *A) y() *A {
return a
}
type B struct{ magic int }
func (b B) p() {
if b.magic != 2 {
panic(b.magic)
}
}
func (b *B) q() {
if b != theC.B {
panic("oops")
}
}
type I interface {
f()
}
type impl struct{ magic int }
func (i impl) f() {
if i.magic != 3 {
panic("oops")
}
}
type C struct {
A
*B
I
}
func assert(cond bool) {
if !cond {
panic("failed")
}
}
var theC = C{
A: A{1},
B: &B{2},
I: impl{3},
}
func addr() *C {
return &theC
}
func value() C {
return theC
}
func main() {
// address
addr().x()
if addr().y() != &theC.A {
panic("oops")
}
addr().p()
addr().q()
addr().f()
// addressable value
var c C = value()
c.x()
if c.y() != &c.A {
panic("oops")
}
c.p()
c.q()
c.f()
// non-addressable value
value().x()
// value().y() // not in method set
value().p()
value().q()
value().f()
}

View File

@@ -0,0 +1,75 @@
// Tests of call chaining f(g()) when g has multiple return values (MRVs).
// See https://code.google.com/p/go/issues/detail?id=4573.
package main
func assert(actual, expected int) {
if actual != expected {
panic(actual)
}
}
func g() (int, int) {
return 5, 7
}
func g2() (float64, float64) {
return 5, 7
}
func f1v(x int, v ...int) {
assert(x, 5)
assert(v[0], 7)
}
func f2(x, y int) {
assert(x, 5)
assert(y, 7)
}
func f2v(x, y int, v ...int) {
assert(x, 5)
assert(y, 7)
assert(len(v), 0)
}
func complexArgs() (float64, float64) {
return 5, 7
}
func appendArgs() ([]string, string) {
return []string{"foo"}, "bar"
}
func h() (i interface{}, ok bool) {
m := map[int]string{1: "hi"}
i, ok = m[1] // string->interface{} conversion within multi-valued expression
return
}
func h2() (i interface{}, ok bool) {
ch := make(chan string, 1)
ch <- "hi"
i, ok = <-ch // string->interface{} conversion within multi-valued expression
return
}
func main() {
f1v(g())
f2(g())
f2v(g())
if c := complex(complexArgs()); c != 5+7i {
panic(c)
}
if s := append(appendArgs()); len(s) != 2 || s[0] != "foo" || s[1] != "bar" {
panic(s)
}
i, ok := h()
if !ok || i.(string) != "hi" {
panic(i)
}
i, ok = h2()
if !ok || i.(string) != "hi" {
panic(i)
}
}

View File

@@ -0,0 +1,55 @@
package main
// Tests of range loops.
import "fmt"
// Range over string.
func init() {
if x := len("Hello, 世界"); x != 13 { // bytes
panic(x)
}
var indices []int
var runes []rune
for i, r := range "Hello, 世界" {
runes = append(runes, r)
indices = append(indices, i)
}
if x := fmt.Sprint(runes); x != "[72 101 108 108 111 44 32 19990 30028]" {
panic(x)
}
if x := fmt.Sprint(indices); x != "[0 1 2 3 4 5 6 7 10]" {
panic(x)
}
s := ""
for _, r := range runes {
s = fmt.Sprintf("%s%c", s, r)
}
if s != "Hello, 世界" {
panic(s)
}
var x int
for range "Hello, 世界" {
x++
}
if x != len(indices) {
panic(x)
}
}
// Regression test for range of pointer to named array type.
func init() {
type intarr [3]int
ia := intarr{1, 2, 3}
var count int
for _, x := range &ia {
count += x
}
if count != 6 {
panic(count)
}
}
func main() {
}

View File

@@ -0,0 +1,34 @@
package main
// Tests of panic/recover.
import "fmt"
func fortyTwo() (r int) {
r = 42
// The next two statements simulate a 'return' statement.
defer func() { recover() }()
panic(nil)
}
func zero() int {
defer func() { recover() }()
panic(1)
}
func zeroEmpty() (int, string) {
defer func() { recover() }()
panic(1)
}
func main() {
if r := fortyTwo(); r != 42 {
panic(r)
}
if r := zero(); r != 0 {
panic(r)
}
if r, s := zeroEmpty(); r != 0 || s != "" {
panic(fmt.Sprint(r, s))
}
}

View File

@@ -0,0 +1,11 @@
package main
import "reflect"
func main() {
// Regression test for issue 9462.
got := reflect.SliceOf(reflect.TypeOf(byte(0))).String()
if got != "[]uint8" && got != "[]byte" { // result varies by toolchain
println("BUG: " + got)
}
}

View File

@@ -0,0 +1,58 @@
package main
// Static tests of SSA builder (via the sanity checker).
// Dynamic semantics are not exercised.
func init() {
// Regression test for issue 6806.
ch := make(chan int)
select {
case n, _ := <-ch:
_ = n
default:
// The default case disables the simplification of
// select to a simple receive statement.
}
// value,ok-form receive where TypeOf(ok) is a named boolean.
type mybool bool
var x int
var y mybool
select {
case x, y = <-ch:
default:
// The default case disables the simplification of
// select to a simple receive statement.
}
_ = x
_ = y
}
var a int
// Regression test for issue 7840 (covered by SSA sanity checker).
func bug7840() bool {
// This creates a single-predecessor block with a φ-node.
return false && a == 0 && a == 0
}
// A blocking select (sans "default:") cannot fall through.
// Regression test for issue 7022.
func bug7022() int {
var c1, c2 chan int
select {
case <-c1:
return 123
case <-c2:
return 456
}
}
// Parens should not prevent intrinsic treatment of built-ins.
// (Regression test for a crash.)
func init() {
_ = (new)(int)
_ = (make)([]int, 0)
}
func main() {}

497
vendor/golang.org/x/tools/go/ssa/interp/value.go generated vendored Normal file
View File

@@ -0,0 +1,497 @@
// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package interp
// Values
//
// All interpreter values are "boxed" in the empty interface, value.
// The range of possible dynamic types within value are:
//
// - bool
// - numbers (all built-in int/float/complex types are distinguished)
// - string
// - map[value]value --- maps for which usesBuiltinMap(keyType)
// *hashmap --- maps for which !usesBuiltinMap(keyType)
// - chan value
// - []value --- slices
// - iface --- interfaces.
// - structure --- structs. Fields are ordered and accessed by numeric indices.
// - array --- arrays.
// - *value --- pointers. Careful: *value is a distinct type from *array etc.
// - *ssa.Function \
// *ssa.Builtin } --- functions. A nil 'func' is always of type *ssa.Function.
// *closure /
// - tuple --- as returned by Return, Next, "value,ok" modes, etc.
// - iter --- iterators from 'range' over map or string.
// - bad --- a poison pill for locals that have gone out of scope.
// - rtype -- the interpreter's concrete implementation of reflect.Type
//
// Note that nil is not on this list.
//
// Pay close attention to whether or not the dynamic type is a pointer.
// The compiler cannot help you since value is an empty interface.
import (
"bytes"
"fmt"
"go/types"
"io"
"reflect"
"strings"
"sync"
"unsafe"
"golang.org/x/tools/go/ssa"
"golang.org/x/tools/go/types/typeutil"
)
type value interface{}
type tuple []value
type array []value
type iface struct {
t types.Type // never an "untyped" type
v value
}
type structure []value
// For map, array, *array, slice, string or channel.
type iter interface {
// next returns a Tuple (key, value, ok).
// key and value are unaliased, e.g. copies of the sequence element.
next() tuple
}
type closure struct {
Fn *ssa.Function
Env []value
}
type bad struct{}
type rtype struct {
t types.Type
}
// Hash functions and equivalence relation:
// hashString computes the FNV hash of s.
func hashString(s string) int {
var h uint32
for i := 0; i < len(s); i++ {
h ^= uint32(s[i])
h *= 16777619
}
return int(h)
}
var (
mu sync.Mutex
hasher = typeutil.MakeHasher()
)
// hashType returns a hash for t such that
// types.Identical(x, y) => hashType(x) == hashType(y).
func hashType(t types.Type) int {
mu.Lock()
h := int(hasher.Hash(t))
mu.Unlock()
return h
}
// usesBuiltinMap returns true if the built-in hash function and
// equivalence relation for type t are consistent with those of the
// interpreter's representation of type t. Such types are: all basic
// types (bool, numbers, string), pointers and channels.
//
// usesBuiltinMap returns false for types that require a custom map
// implementation: interfaces, arrays and structs.
//
// Panic ensues if t is an invalid map key type: function, map or slice.
func usesBuiltinMap(t types.Type) bool {
switch t := t.(type) {
case *types.Basic, *types.Chan, *types.Pointer:
return true
case *types.Named:
return usesBuiltinMap(t.Underlying())
case *types.Interface, *types.Array, *types.Struct:
return false
}
panic(fmt.Sprintf("invalid map key type: %T", t))
}
func (x array) eq(t types.Type, _y interface{}) bool {
y := _y.(array)
tElt := t.Underlying().(*types.Array).Elem()
for i, xi := range x {
if !equals(tElt, xi, y[i]) {
return false
}
}
return true
}
func (x array) hash(t types.Type) int {
h := 0
tElt := t.Underlying().(*types.Array).Elem()
for _, xi := range x {
h += hash(tElt, xi)
}
return h
}
func (x structure) eq(t types.Type, _y interface{}) bool {
y := _y.(structure)
tStruct := t.Underlying().(*types.Struct)
for i, n := 0, tStruct.NumFields(); i < n; i++ {
if f := tStruct.Field(i); !f.Anonymous() {
if !equals(f.Type(), x[i], y[i]) {
return false
}
}
}
return true
}
func (x structure) hash(t types.Type) int {
tStruct := t.Underlying().(*types.Struct)
h := 0
for i, n := 0, tStruct.NumFields(); i < n; i++ {
if f := tStruct.Field(i); !f.Anonymous() {
h += hash(f.Type(), x[i])
}
}
return h
}
// nil-tolerant variant of types.Identical.
func sameType(x, y types.Type) bool {
if x == nil {
return y == nil
}
return y != nil && types.Identical(x, y)
}
func (x iface) eq(t types.Type, _y interface{}) bool {
y := _y.(iface)
return sameType(x.t, y.t) && (x.t == nil || equals(x.t, x.v, y.v))
}
func (x iface) hash(_ types.Type) int {
return hashType(x.t)*8581 + hash(x.t, x.v)
}
func (x rtype) hash(_ types.Type) int {
return hashType(x.t)
}
func (x rtype) eq(_ types.Type, y interface{}) bool {
return types.Identical(x.t, y.(rtype).t)
}
// equals returns true iff x and y are equal according to Go's
// linguistic equivalence relation for type t.
// In a well-typed program, the dynamic types of x and y are
// guaranteed equal.
func equals(t types.Type, x, y value) bool {
switch x := x.(type) {
case bool:
return x == y.(bool)
case int:
return x == y.(int)
case int8:
return x == y.(int8)
case int16:
return x == y.(int16)
case int32:
return x == y.(int32)
case int64:
return x == y.(int64)
case uint:
return x == y.(uint)
case uint8:
return x == y.(uint8)
case uint16:
return x == y.(uint16)
case uint32:
return x == y.(uint32)
case uint64:
return x == y.(uint64)
case uintptr:
return x == y.(uintptr)
case float32:
return x == y.(float32)
case float64:
return x == y.(float64)
case complex64:
return x == y.(complex64)
case complex128:
return x == y.(complex128)
case string:
return x == y.(string)
case *value:
return x == y.(*value)
case chan value:
return x == y.(chan value)
case structure:
return x.eq(t, y)
case array:
return x.eq(t, y)
case iface:
return x.eq(t, y)
case rtype:
return x.eq(t, y)
}
// Since map, func and slice don't support comparison, this
// case is only reachable if one of x or y is literally nil
// (handled in eqnil) or via interface{} values.
panic(fmt.Sprintf("comparing uncomparable type %s", t))
}
// Returns an integer hash of x such that equals(x, y) => hash(x) == hash(y).
func hash(t types.Type, x value) int {
switch x := x.(type) {
case bool:
if x {
return 1
}
return 0
case int:
return x
case int8:
return int(x)
case int16:
return int(x)
case int32:
return int(x)
case int64:
return int(x)
case uint:
return int(x)
case uint8:
return int(x)
case uint16:
return int(x)
case uint32:
return int(x)
case uint64:
return int(x)
case uintptr:
return int(x)
case float32:
return int(x)
case float64:
return int(x)
case complex64:
return int(real(x))
case complex128:
return int(real(x))
case string:
return hashString(x)
case *value:
return int(uintptr(unsafe.Pointer(x)))
case chan value:
return int(uintptr(reflect.ValueOf(x).Pointer()))
case structure:
return x.hash(t)
case array:
return x.hash(t)
case iface:
return x.hash(t)
case rtype:
return x.hash(t)
}
panic(fmt.Sprintf("%T is unhashable", x))
}
// reflect.Value struct values don't have a fixed shape, since the
// payload can be a scalar or an aggregate depending on the instance.
// So store (and load) can't simply use recursion over the shape of the
// rhs value, or the lhs, to copy the value; we need the static type
// information. (We can't make reflect.Value a new basic data type
// because its "structness" is exposed to Go programs.)
// load returns the value of type T in *addr.
func load(T types.Type, addr *value) value {
switch T := T.Underlying().(type) {
case *types.Struct:
v := (*addr).(structure)
a := make(structure, len(v))
for i := range a {
a[i] = load(T.Field(i).Type(), &v[i])
}
return a
case *types.Array:
v := (*addr).(array)
a := make(array, len(v))
for i := range a {
a[i] = load(T.Elem(), &v[i])
}
return a
default:
return *addr
}
}
// store stores value v of type T into *addr.
func store(T types.Type, addr *value, v value) {
switch T := T.Underlying().(type) {
case *types.Struct:
lhs := (*addr).(structure)
rhs := v.(structure)
for i := range lhs {
store(T.Field(i).Type(), &lhs[i], rhs[i])
}
case *types.Array:
lhs := (*addr).(array)
rhs := v.(array)
for i := range lhs {
store(T.Elem(), &lhs[i], rhs[i])
}
default:
*addr = v
}
}
// Prints in the style of built-in println.
// (More or less; in gc println is actually a compiler intrinsic and
// can distinguish println(1) from println(interface{}(1)).)
func writeValue(buf *bytes.Buffer, v value) {
switch v := v.(type) {
case nil, bool, int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr, float32, float64, complex64, complex128, string:
fmt.Fprintf(buf, "%v", v)
case map[value]value:
buf.WriteString("map[")
sep := ""
for k, e := range v {
buf.WriteString(sep)
sep = " "
writeValue(buf, k)
buf.WriteString(":")
writeValue(buf, e)
}
buf.WriteString("]")
case *hashmap:
buf.WriteString("map[")
sep := " "
for _, e := range v.entries() {
for e != nil {
buf.WriteString(sep)
sep = " "
writeValue(buf, e.key)
buf.WriteString(":")
writeValue(buf, e.value)
e = e.next
}
}
buf.WriteString("]")
case chan value:
fmt.Fprintf(buf, "%v", v) // (an address)
case *value:
if v == nil {
buf.WriteString("<nil>")
} else {
fmt.Fprintf(buf, "%p", v)
}
case iface:
fmt.Fprintf(buf, "(%s, ", v.t)
writeValue(buf, v.v)
buf.WriteString(")")
case structure:
buf.WriteString("{")
for i, e := range v {
if i > 0 {
buf.WriteString(" ")
}
writeValue(buf, e)
}
buf.WriteString("}")
case array:
buf.WriteString("[")
for i, e := range v {
if i > 0 {
buf.WriteString(" ")
}
writeValue(buf, e)
}
buf.WriteString("]")
case []value:
buf.WriteString("[")
for i, e := range v {
if i > 0 {
buf.WriteString(" ")
}
writeValue(buf, e)
}
buf.WriteString("]")
case *ssa.Function, *ssa.Builtin, *closure:
fmt.Fprintf(buf, "%p", v) // (an address)
case rtype:
buf.WriteString(v.t.String())
case tuple:
// Unreachable in well-formed Go programs
buf.WriteString("(")
for i, e := range v {
if i > 0 {
buf.WriteString(", ")
}
writeValue(buf, e)
}
buf.WriteString(")")
default:
fmt.Fprintf(buf, "<%T>", v)
}
}
// Implements printing of Go values in the style of built-in println.
func toString(v value) string {
var b bytes.Buffer
writeValue(&b, v)
return b.String()
}
// ------------------------------------------------------------------------
// Iterators
type stringIter struct {
*strings.Reader
i int
}
func (it *stringIter) next() tuple {
okv := make(tuple, 3)
ch, n, err := it.ReadRune()
ok := err != io.EOF
okv[0] = ok
if ok {
okv[1] = it.i
okv[2] = ch
}
it.i += n
return okv
}
type mapIter chan [2]value
func (it mapIter) next() tuple {
kv, ok := <-it
return tuple{ok, kv[0], kv[1]}
}