13
cl/_testdata/vargs/in.go
Normal file
13
cl/_testdata/vargs/in.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "github.com/goplus/llgo/internal/runtime/c"
|
||||||
|
|
||||||
|
func test(a ...any) {
|
||||||
|
for _, v := range a {
|
||||||
|
c.Printf(c.Str("%d\n"), v.(int))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
test(1, 2, 3)
|
||||||
|
}
|
||||||
89
cl/_testdata/vargs/out.ll
Normal file
89
cl/_testdata/vargs/out.ll
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
; ModuleID = 'main'
|
||||||
|
source_filename = "main"
|
||||||
|
|
||||||
|
%"github.com/goplus/llgo/internal/runtime.iface" = type { ptr, ptr }
|
||||||
|
%"github.com/goplus/llgo/internal/runtime.Slice" = type { ptr, i64, i64 }
|
||||||
|
|
||||||
|
@"main.init$guard" = global ptr null
|
||||||
|
@__llgo_argc = global ptr null
|
||||||
|
@__llgo_argv = global ptr null
|
||||||
|
@0 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1
|
||||||
|
|
||||||
|
define void @main.init() {
|
||||||
|
_llgo_0:
|
||||||
|
%0 = load i1, ptr @"main.init$guard", align 1
|
||||||
|
br i1 %0, label %_llgo_2, label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_0
|
||||||
|
store i1 true, ptr @"main.init$guard", align 1
|
||||||
|
br label %_llgo_2
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1, %_llgo_0
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main(i32 %0, ptr %1) {
|
||||||
|
_llgo_0:
|
||||||
|
store i32 %0, ptr @__llgo_argc, align 4
|
||||||
|
store ptr %1, ptr @__llgo_argv, align 8
|
||||||
|
call void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
|
call void @main.init()
|
||||||
|
%2 = call ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64 48)
|
||||||
|
%3 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i64 0
|
||||||
|
%4 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2)
|
||||||
|
%5 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %4, i64 1)
|
||||||
|
store %"github.com/goplus/llgo/internal/runtime.iface" %5, ptr %3, align 8
|
||||||
|
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i64 1
|
||||||
|
%7 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2)
|
||||||
|
%8 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %7, i64 2)
|
||||||
|
store %"github.com/goplus/llgo/internal/runtime.iface" %8, ptr %6, align 8
|
||||||
|
%9 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %2, i64 2
|
||||||
|
%10 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2)
|
||||||
|
%11 = call %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr %10, i64 3)
|
||||||
|
store %"github.com/goplus/llgo/internal/runtime.iface" %11, ptr %9, align 8
|
||||||
|
%12 = call %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr %2, i64 16, i64 3, i64 0, i64 3, i64 3)
|
||||||
|
call void @main.test(%"github.com/goplus/llgo/internal/runtime.Slice" %12)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @main.test(%"github.com/goplus/llgo/internal/runtime.Slice" %0) {
|
||||||
|
_llgo_0:
|
||||||
|
%1 = call i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice" %0)
|
||||||
|
br label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_1: ; preds = %_llgo_2, %_llgo_0
|
||||||
|
%2 = phi i64 [ -1, %_llgo_0 ], [ %3, %_llgo_2 ]
|
||||||
|
%3 = add i64 %2, 1
|
||||||
|
%4 = icmp slt i64 %3, %1
|
||||||
|
br i1 %4, label %_llgo_2, label %_llgo_3
|
||||||
|
|
||||||
|
_llgo_2: ; preds = %_llgo_1
|
||||||
|
%5 = call ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice" %0)
|
||||||
|
%6 = getelementptr inbounds %"github.com/goplus/llgo/internal/runtime.iface", ptr %5, i64 %3
|
||||||
|
%7 = load %"github.com/goplus/llgo/internal/runtime.iface", ptr %6, align 8
|
||||||
|
%8 = call ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64 2)
|
||||||
|
%9 = call i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface" %7, ptr %8)
|
||||||
|
%10 = call i32 (ptr, ...) @printf(ptr @0, i64 %9)
|
||||||
|
br label %_llgo_1
|
||||||
|
|
||||||
|
_llgo_3: ; preds = %_llgo_1
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
declare void @"github.com/goplus/llgo/internal/runtime.init"()
|
||||||
|
|
||||||
|
declare ptr @"github.com/goplus/llgo/internal/runtime.AllocZ"(i64)
|
||||||
|
|
||||||
|
declare ptr @"github.com/goplus/llgo/internal/runtime.Basic"(i64)
|
||||||
|
|
||||||
|
declare %"github.com/goplus/llgo/internal/runtime.iface" @"github.com/goplus/llgo/internal/runtime.MakeAnyInt"(ptr, i64)
|
||||||
|
|
||||||
|
declare %"github.com/goplus/llgo/internal/runtime.Slice" @"github.com/goplus/llgo/internal/runtime.NewSlice3"(ptr, i64, i64, i64, i64, i64)
|
||||||
|
|
||||||
|
declare i64 @"github.com/goplus/llgo/internal/runtime.SliceLen"(%"github.com/goplus/llgo/internal/runtime.Slice")
|
||||||
|
|
||||||
|
declare ptr @"github.com/goplus/llgo/internal/runtime.SliceData"(%"github.com/goplus/llgo/internal/runtime.Slice")
|
||||||
|
|
||||||
|
declare i64 @"github.com/goplus/llgo/internal/runtime.I2Int"(%"github.com/goplus/llgo/internal/runtime.iface", ptr)
|
||||||
|
|
||||||
|
declare i32 @printf(ptr, ...)
|
||||||
@@ -100,6 +100,16 @@ func TestErrAlloca(t *testing.T) {
|
|||||||
ctx.alloca(nil, nil)
|
ctx.alloca(nil, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestErrAllocaCStr(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r == nil {
|
||||||
|
t.Fatal("allocaCStr: no error?")
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
var ctx context
|
||||||
|
ctx.allocaCStr(nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
func TestCStrNoArgs(t *testing.T) {
|
func TestCStrNoArgs(t *testing.T) {
|
||||||
defer func() {
|
defer func() {
|
||||||
if r := recover(); r == nil {
|
if r := recover(); r == nil {
|
||||||
|
|||||||
@@ -62,12 +62,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func (p *context) funcKind(vfn ssa.Value) int {
|
func (p *context) funcKind(vfn ssa.Value) int {
|
||||||
if fn, ok := vfn.(*ssa.Function); ok && fn.Signature.Recv() == nil {
|
if fn, ok := vfn.(*ssa.Function); ok {
|
||||||
params := fn.Signature.Params()
|
params := fn.Signature.Params()
|
||||||
n := params.Len()
|
n := params.Len()
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
if fn.Name() == "init" && p.pkgNoInit(fn.Pkg.Pkg) {
|
if fn.Signature.Recv() == nil {
|
||||||
return fnIgnore
|
if fn.Name() == "init" && p.pkgNoInit(fn.Pkg.Pkg) {
|
||||||
|
return fnIgnore
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
last := params.At(n - 1)
|
last := params.At(n - 1)
|
||||||
@@ -356,9 +358,9 @@ func (p *context) isVArgs(vx ssa.Value) (ret []llssa.Expr, ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *context) checkVArgs(v *ssa.Alloc, t *types.Pointer) bool {
|
func (p *context) checkVArgs(v *ssa.Alloc, t *types.Pointer) bool {
|
||||||
if v.Comment == "varargs" { // this is a varargs allocation
|
if v.Comment == "varargs" { // this maybe a varargs allocation
|
||||||
if arr, ok := t.Elem().(*types.Array); ok {
|
if arr, ok := t.Elem().(*types.Array); ok {
|
||||||
if isAny(arr.Elem()) {
|
if isAny(arr.Elem()) && isVargs(p, v) {
|
||||||
p.vargs[v] = make([]llssa.Expr, arr.Len())
|
p.vargs[v] = make([]llssa.Expr, arr.Len())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -367,6 +369,20 @@ func (p *context) checkVArgs(v *ssa.Alloc, t *types.Pointer) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isVargs(ctx *context, v *ssa.Alloc) bool {
|
||||||
|
refs := *v.Referrers()
|
||||||
|
n := len(refs)
|
||||||
|
lastref := refs[n-1]
|
||||||
|
if i, ok := lastref.(*ssa.Slice); ok {
|
||||||
|
if refs = *i.Referrers(); len(refs) == 1 {
|
||||||
|
if call, ok := refs[0].(*ssa.Call); ok {
|
||||||
|
return ctx.funcKind(call.Call.Value) == fnHasVArg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
// func cstr(string) *int8
|
// func cstr(string) *int8
|
||||||
func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) {
|
||||||
if len(args) == 1 {
|
if len(args) == 1 {
|
||||||
@@ -468,42 +484,42 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
}
|
}
|
||||||
switch v := iv.(type) {
|
switch v := iv.(type) {
|
||||||
case *ssa.Call:
|
case *ssa.Call:
|
||||||
call := v.Call
|
cv := v.Call.Value
|
||||||
cv := call.Value
|
|
||||||
kind := p.funcKind(cv)
|
kind := p.funcKind(cv)
|
||||||
if kind == fnIgnore {
|
if kind == fnIgnore {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
args := v.Call.Args
|
||||||
if debugGoSSA {
|
if debugGoSSA {
|
||||||
log.Println(">>> Call", cv, call.Args)
|
log.Println(">>> Call", cv, args)
|
||||||
}
|
}
|
||||||
switch cv := cv.(type) {
|
switch cv := cv.(type) {
|
||||||
case *ssa.Builtin:
|
case *ssa.Builtin:
|
||||||
fn := cv.Name()
|
fn := cv.Name()
|
||||||
if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr
|
if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr
|
||||||
arg := call.Args[0]
|
arg := args[0]
|
||||||
ret = p.compileValue(b, arg)
|
ret = p.compileValue(b, arg)
|
||||||
// log.Println("wrapnilchk:", ret.TypeOf())
|
// log.Println("wrapnilchk:", ret.TypeOf())
|
||||||
} else {
|
} else {
|
||||||
args := p.compileValues(b, call.Args, kind)
|
args := p.compileValues(b, args, kind)
|
||||||
ret = b.BuiltinCall(fn, args...)
|
ret = b.BuiltinCall(fn, args...)
|
||||||
}
|
}
|
||||||
case *ssa.Function:
|
case *ssa.Function:
|
||||||
fn, ftype := p.compileFunction(cv)
|
fn, ftype := p.compileFunction(cv)
|
||||||
switch ftype {
|
switch ftype {
|
||||||
case goFunc, cFunc:
|
case goFunc, cFunc:
|
||||||
args := p.compileValues(b, call.Args, kind)
|
args := p.compileValues(b, args, kind)
|
||||||
ret = b.Call(fn.Expr, args...)
|
ret = b.Call(fn.Expr, args...)
|
||||||
case llgoCstr:
|
case llgoCstr:
|
||||||
ret = cstr(b, call.Args)
|
ret = cstr(b, args)
|
||||||
case llgoAdvance:
|
case llgoAdvance:
|
||||||
ret = p.advance(b, call.Args)
|
ret = p.advance(b, args)
|
||||||
case llgoIndex:
|
case llgoIndex:
|
||||||
ret = p.index(b, call.Args)
|
ret = p.index(b, args)
|
||||||
case llgoAlloca:
|
case llgoAlloca:
|
||||||
ret = p.alloca(b, call.Args)
|
ret = p.alloca(b, args)
|
||||||
case llgoAllocaCStr:
|
case llgoAllocaCStr:
|
||||||
ret = p.allocaCStr(b, call.Args)
|
ret = p.allocaCStr(b, args)
|
||||||
case llgoUnreachable: // func unreachable()
|
case llgoUnreachable: // func unreachable()
|
||||||
b.Unreachable()
|
b.Unreachable()
|
||||||
default:
|
default:
|
||||||
@@ -511,7 +527,7 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
fn := p.compileValue(b, cv)
|
fn := p.compileValue(b, cv)
|
||||||
args := p.compileValues(b, call.Args, kind)
|
args := p.compileValues(b, args, kind)
|
||||||
ret = b.Call(fn, args...)
|
ret = b.Call(fn, args...)
|
||||||
}
|
}
|
||||||
case *ssa.BinOp:
|
case *ssa.BinOp:
|
||||||
@@ -534,7 +550,7 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
ret = b.FieldAddr(x, v.Field)
|
ret = b.FieldAddr(x, v.Field)
|
||||||
case *ssa.Alloc:
|
case *ssa.Alloc:
|
||||||
t := v.Type().(*types.Pointer)
|
t := v.Type().(*types.Pointer)
|
||||||
if p.checkVArgs(v, t) { // varargs: this is a varargs allocation
|
if p.checkVArgs(v, t) { // varargs: this maybe a varargs allocation
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
elem := p.prog.Type(t.Elem(), llssa.InGo)
|
elem := p.prog.Type(t.Elem(), llssa.InGo)
|
||||||
@@ -580,12 +596,18 @@ func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue
|
|||||||
}
|
}
|
||||||
ret = b.Slice(x, low, high, max)
|
ret = b.Slice(x, low, high, max)
|
||||||
case *ssa.MakeInterface:
|
case *ssa.MakeInterface:
|
||||||
const (
|
if refs := *v.Referrers(); len(refs) == 1 {
|
||||||
delayExpr = true // varargs: don't need to convert an expr to any
|
if ref, ok := refs[0].(*ssa.Store); ok {
|
||||||
)
|
if va, ok := ref.Addr.(*ssa.IndexAddr); ok {
|
||||||
|
if _, ok = p.isVArgs(va.X); ok { // varargs: this is a varargs store
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
t := p.prog.Type(v.Type(), llssa.InGo)
|
t := p.prog.Type(v.Type(), llssa.InGo)
|
||||||
x := p.compileValue(b, v.X)
|
x := p.compileValue(b, v.X)
|
||||||
ret = b.MakeInterface(t, x, delayExpr)
|
ret = b.MakeInterface(t, x)
|
||||||
case *ssa.MakeSlice:
|
case *ssa.MakeSlice:
|
||||||
var nCap llssa.Expr
|
var nCap llssa.Expr
|
||||||
t := p.prog.Type(v.Type(), llssa.InGo)
|
t := p.prog.Type(v.Type(), llssa.InGo)
|
||||||
|
|||||||
57
ssa/expr.go
57
ssa/expr.go
@@ -44,8 +44,6 @@ func (v Expr) IsNil() bool {
|
|||||||
// Do evaluates the delay expression and returns the result.
|
// Do evaluates the delay expression and returns the result.
|
||||||
func (v Expr) Do(b Builder) Expr {
|
func (v Expr) Do(b Builder) Expr {
|
||||||
switch vt := v.Type; vt.kind {
|
switch vt := v.Type; vt.kind {
|
||||||
case vkDelayExpr:
|
|
||||||
return vt.raw.Type.(delayExprTy)()
|
|
||||||
case vkPhisExpr:
|
case vkPhisExpr:
|
||||||
e := vt.raw.Type.(*phisExprTy)
|
e := vt.raw.Type.(*phisExprTy)
|
||||||
return b.aggregateValue(e.Type, e.phis...)
|
return b.aggregateValue(e.Type, e.phis...)
|
||||||
@@ -55,23 +53,6 @@ func (v Expr) Do(b Builder) Expr {
|
|||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|
||||||
// DelayExpr returns a delay expression.
|
|
||||||
func DelayExpr(f func() Expr) Expr {
|
|
||||||
return Expr{Type: &aType{raw: rawType{delayExprTy(f)}, kind: vkDelayExpr}}
|
|
||||||
}
|
|
||||||
|
|
||||||
type delayExprTy func() Expr
|
|
||||||
|
|
||||||
func (p delayExprTy) Underlying() types.Type {
|
|
||||||
panic("don't call")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (p delayExprTy) String() string {
|
|
||||||
return "delayExpr"
|
|
||||||
}
|
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type phisExprTy struct {
|
type phisExprTy struct {
|
||||||
phis []llvm.Value
|
phis []llvm.Value
|
||||||
Type
|
Type
|
||||||
@@ -1059,35 +1040,27 @@ func castPtr(b llvm.Builder, x llvm.Value, t llvm.Type) llvm.Value {
|
|||||||
//
|
//
|
||||||
// t1 = make interface{} <- int (42:int)
|
// t1 = make interface{} <- int (42:int)
|
||||||
// t2 = make Stringer <- t0
|
// t2 = make Stringer <- t0
|
||||||
func (b Builder) MakeInterface(tinter Type, x Expr, mayDelay bool) (ret Expr) {
|
func (b Builder) MakeInterface(tinter Type, x Expr) (ret Expr) {
|
||||||
raw := tinter.raw.Type
|
raw := tinter.raw.Type
|
||||||
if debugInstr {
|
if debugInstr {
|
||||||
log.Printf("MakeInterface %v, %v\n", raw, x.impl)
|
log.Printf("MakeInterface %v, %v\n", raw, x.impl)
|
||||||
}
|
}
|
||||||
tiund := raw.Underlying().(*types.Interface)
|
prog := b.Prog
|
||||||
isAny := tiund.Empty()
|
pkg := b.Func.Pkg
|
||||||
fnDo := func() Expr {
|
switch tx := x.raw.Type.Underlying().(type) {
|
||||||
prog := b.Prog
|
case *types.Basic:
|
||||||
pkg := b.Func.Pkg
|
kind := tx.Kind()
|
||||||
switch tx := x.raw.Type.Underlying().(type) {
|
switch {
|
||||||
case *types.Basic:
|
case kind >= types.Int && kind <= types.Uintptr:
|
||||||
kind := tx.Kind()
|
t := b.InlineCall(pkg.rtFunc("Basic"), prog.Val(int(kind)))
|
||||||
switch {
|
tptr := prog.Uintptr()
|
||||||
case kind >= types.Int && kind <= types.Uintptr:
|
vptr := Expr{llvm.CreateIntCast(b.impl, x.impl, tptr.ll), tptr}
|
||||||
t := b.InlineCall(pkg.rtFunc("Basic"), prog.Val(int(kind)))
|
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter}
|
||||||
tptr := prog.Uintptr()
|
case kind == types.String:
|
||||||
vptr := Expr{llvm.CreateIntCast(b.impl, x.impl, tptr.ll), tptr}
|
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyString"), x).impl, tinter}
|
||||||
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyInt"), t, vptr).impl, tinter}
|
|
||||||
case kind == types.String:
|
|
||||||
return Expr{b.InlineCall(pkg.rtFunc("MakeAnyString"), x).impl, tinter}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
panic("todo")
|
|
||||||
}
|
}
|
||||||
if mayDelay && isAny {
|
panic("todo")
|
||||||
return DelayExpr(fnDo)
|
|
||||||
}
|
|
||||||
return fnDo()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// The TypeAssert instruction tests whether interface value X has type
|
// The TypeAssert instruction tests whether interface value X has type
|
||||||
|
|||||||
@@ -73,9 +73,7 @@ func TestCvtType(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestUserdefExpr(t *testing.T) {
|
func TestUserdefExpr(t *testing.T) {
|
||||||
a := delayExprTy(nil)
|
|
||||||
b := &phisExprTy{}
|
b := &phisExprTy{}
|
||||||
_ = a.String()
|
|
||||||
_ = b.String()
|
_ = b.String()
|
||||||
test := func(a types.Type) {
|
test := func(a types.Type) {
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -85,7 +83,6 @@ func TestUserdefExpr(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
a.Underlying()
|
a.Underlying()
|
||||||
}
|
}
|
||||||
test(a)
|
|
||||||
test(b)
|
test(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,7 @@ const (
|
|||||||
vkFuncPtr
|
vkFuncPtr
|
||||||
vkClosure
|
vkClosure
|
||||||
vkTuple
|
vkTuple
|
||||||
vkDelayExpr = -1
|
vkPhisExpr = -1
|
||||||
vkPhisExpr = -2
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
|
|||||||
Reference in New Issue
Block a user