Add generated file
This PR adds generated files under pkg/client and vendor folder.
This commit is contained in:
562
vendor/golang.org/x/tools/go/ssa/interp/external.go
generated
vendored
Normal file
562
vendor/golang.org/x/tools/go/ssa/interp/external.go
generated
vendored
Normal 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`)
|
||||
}
|
35
vendor/golang.org/x/tools/go/ssa/interp/external_darwin.go
generated
vendored
Normal file
35
vendor/golang.org/x/tools/go/ssa/interp/external_darwin.go
generated
vendored
Normal 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)}
|
||||
}
|
256
vendor/golang.org/x/tools/go/ssa/interp/external_unix.go
generated
vendored
Normal file
256
vendor/golang.org/x/tools/go/ssa/interp/external_unix.go
generated
vendored
Normal 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
764
vendor/golang.org/x/tools/go/ssa/interp/interp.go
generated
vendored
Normal 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
317
vendor/golang.org/x/tools/go/ssa/interp/interp_test.go
generated
vendored
Normal 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
121
vendor/golang.org/x/tools/go/ssa/interp/map.go
generated
vendored
Normal 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
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
574
vendor/golang.org/x/tools/go/ssa/interp/reflect.go
generated
vendored
Normal 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"),
|
||||
}
|
||||
}
|
17
vendor/golang.org/x/tools/go/ssa/interp/testdata/a_test.go
generated
vendored
Normal file
17
vendor/golang.org/x/tools/go/ssa/interp/testdata/a_test.go
generated
vendored
Normal 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.
|
11
vendor/golang.org/x/tools/go/ssa/interp/testdata/b_test.go
generated
vendored
Normal file
11
vendor/golang.org/x/tools/go/ssa/interp/testdata/b_test.go
generated
vendored
Normal 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")
|
||||
}
|
144
vendor/golang.org/x/tools/go/ssa/interp/testdata/boundmeth.go
generated
vendored
Normal file
144
vendor/golang.org/x/tools/go/ssa/interp/testdata/boundmeth.go
generated
vendored
Normal 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()
|
||||
}
|
17
vendor/golang.org/x/tools/go/ssa/interp/testdata/c_test.go
generated
vendored
Normal file
17
vendor/golang.org/x/tools/go/ssa/interp/testdata/c_test.go
generated
vendored
Normal 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)
|
||||
}
|
52
vendor/golang.org/x/tools/go/ssa/interp/testdata/callstack.go
generated
vendored
Normal file
52
vendor/golang.org/x/tools/go/ssa/interp/testdata/callstack.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
184
vendor/golang.org/x/tools/go/ssa/interp/testdata/complit.go
generated
vendored
Normal file
184
vendor/golang.org/x/tools/go/ssa/interp/testdata/complit.go
generated
vendored
Normal 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() {
|
||||
}
|
534
vendor/golang.org/x/tools/go/ssa/interp/testdata/coverage.go
generated
vendored
Normal file
534
vendor/golang.org/x/tools/go/ssa/interp/testdata/coverage.go
generated
vendored
Normal 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")
|
||||
}
|
||||
}
|
53
vendor/golang.org/x/tools/go/ssa/interp/testdata/defer.go
generated
vendored
Normal file
53
vendor/golang.org/x/tools/go/ssa/interp/testdata/defer.go
generated
vendored
Normal 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() {
|
||||
}
|
114
vendor/golang.org/x/tools/go/ssa/interp/testdata/fieldprom.go
generated
vendored
Normal file
114
vendor/golang.org/x/tools/go/ssa/interp/testdata/fieldprom.go
generated
vendored
Normal 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)
|
||||
}
|
83
vendor/golang.org/x/tools/go/ssa/interp/testdata/ifaceconv.go
generated
vendored
Normal file
83
vendor/golang.org/x/tools/go/ssa/interp/testdata/ifaceconv.go
generated
vendored
Normal 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")
|
||||
}
|
||||
}
|
58
vendor/golang.org/x/tools/go/ssa/interp/testdata/ifaceprom.go
generated
vendored
Normal file
58
vendor/golang.org/x/tools/go/ssa/interp/testdata/ifaceprom.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
67
vendor/golang.org/x/tools/go/ssa/interp/testdata/initorder.go
generated
vendored
Normal file
67
vendor/golang.org/x/tools/go/ssa/interp/testdata/initorder.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
93
vendor/golang.org/x/tools/go/ssa/interp/testdata/methprom.go
generated
vendored
Normal file
93
vendor/golang.org/x/tools/go/ssa/interp/testdata/methprom.go
generated
vendored
Normal 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()
|
||||
}
|
75
vendor/golang.org/x/tools/go/ssa/interp/testdata/mrvchain.go
generated
vendored
Normal file
75
vendor/golang.org/x/tools/go/ssa/interp/testdata/mrvchain.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
55
vendor/golang.org/x/tools/go/ssa/interp/testdata/range.go
generated
vendored
Normal file
55
vendor/golang.org/x/tools/go/ssa/interp/testdata/range.go
generated
vendored
Normal 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() {
|
||||
}
|
34
vendor/golang.org/x/tools/go/ssa/interp/testdata/recover.go
generated
vendored
Normal file
34
vendor/golang.org/x/tools/go/ssa/interp/testdata/recover.go
generated
vendored
Normal 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))
|
||||
}
|
||||
}
|
11
vendor/golang.org/x/tools/go/ssa/interp/testdata/reflect.go
generated
vendored
Normal file
11
vendor/golang.org/x/tools/go/ssa/interp/testdata/reflect.go
generated
vendored
Normal 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)
|
||||
}
|
||||
}
|
58
vendor/golang.org/x/tools/go/ssa/interp/testdata/static.go
generated
vendored
Normal file
58
vendor/golang.org/x/tools/go/ssa/interp/testdata/static.go
generated
vendored
Normal 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
497
vendor/golang.org/x/tools/go/ssa/interp/value.go
generated
vendored
Normal 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]}
|
||||
}
|
Reference in New Issue
Block a user