github.com/goplus/gogen@v1.16.0/builtin.go (about)

     1  /*
     2   Copyright 2021 The GoPlus Authors (goplus.org)
     3   Licensed under the Apache License, Version 2.0 (the "License");
     4   you may not use this file except in compliance with the License.
     5   You may obtain a copy of the License at
     6       http://www.apache.org/licenses/LICENSE-2.0
     7   Unless required by applicable law or agreed to in writing, software
     8   distributed under the License is distributed on an "AS IS" BASIS,
     9   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    10   See the License for the specific language governing permissions and
    11   limitations under the License.
    12  */
    13  
    14  package gogen
    15  
    16  import (
    17  	"fmt"
    18  	"go/ast"
    19  	"go/constant"
    20  	"go/token"
    21  	"go/types"
    22  	"log"
    23  	"runtime"
    24  	"strings"
    25  	"syscall"
    26  
    27  	"golang.org/x/tools/go/types/typeutil"
    28  )
    29  
    30  func newBuiltinDefault(pkg *Package, conf *Config) *types.Package {
    31  	builtin := types.NewPackage("", "")
    32  	InitBuiltin(pkg, builtin, conf)
    33  	return builtin
    34  }
    35  
    36  func InitBuiltin(pkg *Package, builtin *types.Package, conf *Config) {
    37  	initBuiltinOps(builtin, conf)
    38  	initBuiltinAssignOps(builtin)
    39  	initBuiltinFuncs(builtin)
    40  	initBuiltinTIs(pkg)
    41  	initUnsafeFuncs(pkg)
    42  }
    43  
    44  // ----------------------------------------------------------------------------
    45  
    46  type typeTParam struct {
    47  	name     string
    48  	contract Contract
    49  }
    50  
    51  type typeParam struct {
    52  	name string
    53  	tidx int
    54  }
    55  
    56  // initBuiltinOps initializes operators of the builtin package.
    57  func initBuiltinOps(builtin *types.Package, conf *Config) {
    58  	ops := [...]struct {
    59  		name    string
    60  		tparams []typeTParam
    61  		params  []typeParam
    62  		result  int
    63  	}{
    64  		{"Add", []typeTParam{{"T", addable}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
    65  		// func Gop_Add[T addable](a, b T) T
    66  
    67  		{"Sub", []typeTParam{{"T", number}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
    68  		// func Gop_Sub[T number](a, b T) T
    69  
    70  		{"Mul", []typeTParam{{"T", number}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
    71  		// func Gop_Mul[T number](a, b T) T
    72  
    73  		{"Quo", []typeTParam{{"T", number}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
    74  		// func Gop_Quo(a, b untyped_bigint) untyped_bigrat
    75  		// func Gop_Quo[T number](a, b T) T
    76  
    77  		{"Rem", []typeTParam{{"T", integer}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
    78  		// func Gop_Rem[T integer](a, b T) T
    79  
    80  		{"Or", []typeTParam{{"T", integer}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
    81  		// func Gop_Or[T integer](a, b T) T
    82  
    83  		{"Xor", []typeTParam{{"T", integer}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
    84  		// func Gop_Xor[T integer](a, b T) T
    85  
    86  		{"And", []typeTParam{{"T", integer}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
    87  		// func Gop_And[T integer](a, b T) T
    88  
    89  		{"AndNot", []typeTParam{{"T", integer}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
    90  		// func Gop_AndNot[T integer](a, b T) T
    91  
    92  		{"Lsh", []typeTParam{{"T", integer}, {"N", ninteger}}, []typeParam{{"a", 0}, {"n", 1}}, 0},
    93  		// func Gop_Lsh[T integer, N ninteger](a T, n N) T
    94  
    95  		{"Rsh", []typeTParam{{"T", integer}, {"N", ninteger}}, []typeParam{{"a", 0}, {"n", 1}}, 0},
    96  		// func Gop_Rsh[T integer, N ninteger](a T, n N) T
    97  
    98  		{"LT", []typeTParam{{"T", orderable}}, []typeParam{{"a", 0}, {"b", 0}}, -1},
    99  		// func Gop_LT[T orderable](a, b T) untyped_bool
   100  
   101  		{"LE", []typeTParam{{"T", orderable}}, []typeParam{{"a", 0}, {"b", 0}}, -1},
   102  		// func Gop_LE[T orderable](a, b T) untyped_bool
   103  
   104  		{"GT", []typeTParam{{"T", orderable}}, []typeParam{{"a", 0}, {"b", 0}}, -1},
   105  		// func Gop_GT[T orderable](a, b T) untyped_bool
   106  
   107  		{"GE", []typeTParam{{"T", orderable}}, []typeParam{{"a", 0}, {"b", 0}}, -1},
   108  		// func Gop_GE[T orderable](a, b T) untyped_bool
   109  
   110  		{"EQ", []typeTParam{{"T", comparable}}, []typeParam{{"a", 0}, {"b", 0}}, -1},
   111  		// func Gop_EQ[T comparable](a, b T) untyped_bool
   112  
   113  		{"NE", []typeTParam{{"T", comparable}}, []typeParam{{"a", 0}, {"b", 0}}, -1},
   114  		// func Gop_NE[T comparable](a, b T) untyped_bool
   115  
   116  		{"LAnd", []typeTParam{{"T", cbool}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
   117  		// func Gop_LAnd[T bool](a, b T) T
   118  
   119  		{"LOr", []typeTParam{{"T", cbool}}, []typeParam{{"a", 0}, {"b", 0}}, 0},
   120  		// func Gop_LOr[T bool](a, b T) T
   121  
   122  		{"Neg", []typeTParam{{"T", number}}, []typeParam{{"a", 0}}, 0},
   123  		// func Gop_Neg[T number](a T) T
   124  
   125  		{"Dup", []typeTParam{{"T", number}}, []typeParam{{"a", 0}}, 0},
   126  		// func Gop_Dup[T number](a T) T
   127  
   128  		{"Not", []typeTParam{{"T", integer}}, []typeParam{{"a", 0}}, 0},
   129  		// func Gop_Not[T integer](a T) T
   130  
   131  		{"LNot", []typeTParam{{"T", cbool}}, []typeParam{{"a", 0}}, 0},
   132  		// func Gop_LNot[T bool](a T) T
   133  	}
   134  	gbl := builtin.Scope()
   135  	for _, op := range ops {
   136  		tparams := newTParams(op.tparams)
   137  		n := len(op.params)
   138  		params := make([]*types.Var, n)
   139  		for i, param := range op.params {
   140  			params[i] = types.NewParam(token.NoPos, builtin, param.name, tparams[param.tidx])
   141  		}
   142  		var results *types.Tuple
   143  		if op.result != -2 {
   144  			var ret types.Type
   145  			if op.result < 0 {
   146  				ret = types.Typ[types.UntypedBool]
   147  			} else {
   148  				ret = tparams[op.result]
   149  			}
   150  			result := types.NewParam(token.NoPos, builtin, "", ret)
   151  			results = types.NewTuple(result)
   152  		}
   153  		tokFlag := nameToOps[op.name].Tok
   154  		if n == 1 {
   155  			tokFlag |= tokUnaryFlag
   156  		}
   157  		name := goxPrefix + op.name
   158  		tsig := NewTemplateSignature(tparams, nil, types.NewTuple(params...), results, false, tokFlag)
   159  		var tfn types.Object = NewTemplateFunc(token.NoPos, builtin, name, tsig)
   160  		if op.name == "Quo" { // func Gop_Quo(a, b untyped_bigint) untyped_bigrat
   161  			a := types.NewParam(token.NoPos, builtin, "a", conf.UntypedBigInt)
   162  			b := types.NewParam(token.NoPos, builtin, "b", conf.UntypedBigInt)
   163  			ret := types.NewParam(token.NoPos, builtin, "", conf.UntypedBigRat)
   164  			sig := NewTemplateSignature(nil, nil, types.NewTuple(a, b), types.NewTuple(ret), false, tokFlag)
   165  			quo := NewTemplateFunc(token.NoPos, builtin, name, sig)
   166  			tfn = NewOverloadFunc(token.NoPos, builtin, name, tfn, quo)
   167  		}
   168  		gbl.Insert(tfn)
   169  	}
   170  
   171  	// Inc++, Dec--, Recv<-, Addr& are special cases
   172  	gbl.Insert(NewInstruction(token.NoPos, builtin, goxPrefix+"Inc", incInstr{}))
   173  	gbl.Insert(NewInstruction(token.NoPos, builtin, goxPrefix+"Dec", decInstr{}))
   174  	gbl.Insert(NewInstruction(token.NoPos, builtin, goxPrefix+"Recv", recvInstr{}))
   175  	gbl.Insert(NewInstruction(token.NoPos, builtin, goxPrefix+"Addr", addrInstr{}))
   176  }
   177  
   178  func newTParams(params []typeTParam) []*TemplateParamType {
   179  	n := len(params)
   180  	tparams := make([]*TemplateParamType, n)
   181  	for i, tparam := range params {
   182  		tparams[i] = NewTemplateParamType(i, tparam.name, tparam.contract)
   183  	}
   184  	return tparams
   185  }
   186  
   187  // initBuiltinAssignOps initializes assign operators of the builtin package.
   188  func initBuiltinAssignOps(builtin *types.Package) {
   189  	ops := [...]struct {
   190  		name     string
   191  		t        Contract
   192  		ninteger bool
   193  	}{
   194  		{"AddAssign", addable, false},
   195  		// func Gop_AddAssign[T addable](a *T, b T)
   196  
   197  		{"SubAssign", number, false},
   198  		// func Gop_SubAssign[T number](a *T, b T)
   199  
   200  		{"MulAssign", number, false},
   201  		// func Gop_MulAssign[T number](a *T, b T)
   202  
   203  		{"QuoAssign", number, false},
   204  		// func Gop_QuoAssign[T number](a *T, b T)
   205  
   206  		{"RemAssign", integer, false},
   207  		// func Gop_RemAssign[T integer](a *T, b T)
   208  
   209  		{"OrAssign", integer, false},
   210  		// func Gop_OrAssign[T integer](a *T, b T)
   211  
   212  		{"XorAssign", integer, false},
   213  		// func Gop_XorAssign[T integer](a *T, b T)
   214  
   215  		{"AndAssign", integer, false},
   216  		// func Gop_Assign[T integer](a *T, b T)
   217  
   218  		{"AndNotAssign", integer, false},
   219  		// func Gop_AndNotAssign[T integer](a *T, b T)
   220  
   221  		{"LshAssign", integer, true},
   222  		// func Gop_LshAssign[T integer, N ninteger](a *T, n N)
   223  
   224  		{"RshAssign", integer, true},
   225  		// func Gop_RshAssign[T integer, N ninteger](a *T, n N)
   226  	}
   227  	gbl := builtin.Scope()
   228  	for _, op := range ops {
   229  		tparams := newOpTParams(op.t, op.ninteger)
   230  		params := make([]*types.Var, 2)
   231  		params[0] = types.NewParam(token.NoPos, builtin, "a", NewPointer(tparams[0]))
   232  		if op.ninteger {
   233  			params[1] = types.NewParam(token.NoPos, builtin, "n", tparams[1])
   234  		} else {
   235  			params[1] = types.NewParam(token.NoPos, builtin, "b", tparams[0])
   236  		}
   237  		name := goxPrefix + op.name
   238  		tsig := NewTemplateSignature(tparams, nil, types.NewTuple(params...), nil, false, 0)
   239  		tfn := NewTemplateFunc(token.NoPos, builtin, name, tsig)
   240  		gbl.Insert(tfn)
   241  	}
   242  }
   243  
   244  func newOpTParams(t Contract, utinteger bool) []*TemplateParamType {
   245  	tparams := make([]*TemplateParamType, 1, 2)
   246  	tparams[0] = NewTemplateParamType(0, "T", t)
   247  	if utinteger {
   248  		tparams = append(tparams, NewTemplateParamType(1, "N", ninteger))
   249  	}
   250  	return tparams
   251  }
   252  
   253  // ----------------------------------------------------------------------------
   254  
   255  type typeBParam struct {
   256  	name string
   257  	typ  types.BasicKind
   258  }
   259  
   260  type typeBFunc struct {
   261  	params []typeBParam
   262  	result types.BasicKind
   263  }
   264  
   265  type xType = interface{}
   266  type typeXParam struct {
   267  	name string
   268  	typ  xType // tidx | types.Type
   269  }
   270  
   271  const (
   272  	xtNone = iota << 16
   273  	xtEllipsis
   274  	xtSlice
   275  	xtMap
   276  	xtChanIn
   277  )
   278  
   279  // initBuiltinFuncs initializes builtin functions of the builtin package.
   280  func initBuiltinFuncs(builtin *types.Package) {
   281  	fns := [...]struct {
   282  		name    string
   283  		tparams []typeTParam
   284  		params  []typeXParam
   285  		result  xType
   286  	}{
   287  		{"copy", []typeTParam{{"Type", any}}, []typeXParam{{"dst", xtSlice}, {"src", xtSlice}}, types.Typ[types.Int]},
   288  		// func [Type any] copy(dst, src []Type) int
   289  
   290  		{"close", []typeTParam{{"Type", any}}, []typeXParam{{"c", xtChanIn}}, nil},
   291  		// func [Type any] close(c chan<- Type)
   292  
   293  		{"append", []typeTParam{{"Type", any}}, []typeXParam{{"slice", xtSlice}, {"elems", xtEllipsis}}, xtSlice},
   294  		// func [Type any] append(slice []Type, elems ...Type) []Type
   295  
   296  		{"delete", []typeTParam{{"Key", comparable}, {"Elem", any}}, []typeXParam{{"m", xtMap}, {"key", 0}}, nil},
   297  		// func [Key comparable, Elem any] delete(m map[Key]Elem, key Key)
   298  	}
   299  	gbl := builtin.Scope()
   300  	for _, fn := range fns {
   301  		tparams := newTParams(fn.tparams)
   302  		n := len(fn.params)
   303  		params := make([]*types.Var, n)
   304  		for i, param := range fn.params {
   305  			typ := newXParamType(tparams, param.typ)
   306  			params[i] = types.NewParam(token.NoPos, builtin, param.name, typ)
   307  		}
   308  		var ellipsis bool
   309  		if tidx, ok := fn.params[n-1].typ.(int); ok && (tidx&xtEllipsis) != 0 {
   310  			ellipsis = true
   311  		}
   312  		var results *types.Tuple
   313  		if fn.result != nil {
   314  			typ := newXParamType(tparams, fn.result)
   315  			results = types.NewTuple(types.NewParam(token.NoPos, builtin, "", typ))
   316  		}
   317  		tsig := NewTemplateSignature(tparams, nil, types.NewTuple(params...), results, ellipsis, tokFlagApproxType)
   318  		var tfn types.Object = NewTemplateFunc(token.NoPos, builtin, fn.name, tsig)
   319  		if fn.name == "append" { // append is a special case
   320  			appendString := NewInstruction(token.NoPos, builtin, "append", appendStringInstr{})
   321  			tfn = NewOverloadFunc(token.NoPos, builtin, "append", appendString, tfn)
   322  		} else if fn.name == "copy" {
   323  			// func [S string] copy(dst []byte, src S) int
   324  			tparams := newTParams([]typeTParam{{"S", tstring}})
   325  			dst := types.NewParam(token.NoPos, builtin, "dst", types.NewSlice(types.Typ[types.Byte]))
   326  			src := types.NewParam(token.NoPos, builtin, "src", tparams[0])
   327  			ret := types.NewParam(token.NoPos, builtin, "", types.Typ[types.Int])
   328  			tsig := NewTemplateSignature(tparams, nil, types.NewTuple(dst, src), types.NewTuple(ret), false)
   329  			copyString := NewTemplateFunc(token.NoPos, builtin, "copy", tsig)
   330  			tfn = NewOverloadFunc(token.NoPos, builtin, "copy", copyString, tfn)
   331  		}
   332  		gbl.Insert(tfn)
   333  	}
   334  	overloads := [...]struct {
   335  		name string
   336  		fns  [3]typeBFunc
   337  	}{
   338  		{"complex", [...]typeBFunc{
   339  			{[]typeBParam{{"r", types.UntypedFloat}, {"i", types.UntypedFloat}}, types.UntypedComplex},
   340  			{[]typeBParam{{"r", types.Float32}, {"i", types.Float32}}, types.Complex64},
   341  			{[]typeBParam{{"r", types.Float64}, {"i", types.Float64}}, types.Complex128},
   342  		}},
   343  		// func complex(r, i untyped_float) untyped_complex
   344  		// func complex(r, i float32) complex64
   345  		// func complex(r, i float64) complex128
   346  
   347  		{"real", [...]typeBFunc{
   348  			{[]typeBParam{{"c", types.UntypedComplex}}, types.UntypedFloat},
   349  			{[]typeBParam{{"c", types.Complex64}}, types.Float32},
   350  			{[]typeBParam{{"c", types.Complex128}}, types.Float64},
   351  		}},
   352  		// func real(c untyped_complex) untyped_float
   353  		// func real(c complex64) float32
   354  		// func real(c complex128) float64
   355  
   356  		{"imag", [...]typeBFunc{
   357  			{[]typeBParam{{"c", types.UntypedComplex}}, types.UntypedFloat},
   358  			{[]typeBParam{{"c", types.Complex64}}, types.Float32},
   359  			{[]typeBParam{{"c", types.Complex128}}, types.Float64},
   360  		}},
   361  		// func imag(c untyped_complex) untyped_float
   362  		// func imag(c complex64) float32
   363  		// func imag(c complex128) float64
   364  	}
   365  	for _, overload := range overloads {
   366  		fns := []types.Object{
   367  			newBFunc(builtin, overload.name, overload.fns[0]),
   368  			newBFunc(builtin, overload.name, overload.fns[1]),
   369  			newBFunc(builtin, overload.name, overload.fns[2]),
   370  		}
   371  		gbl.Insert(NewOverloadFunc(token.NoPos, builtin, overload.name, fns...))
   372  	}
   373  	// func panic(v interface{})
   374  	// func recover() interface{}
   375  	// func print(args ...interface{})
   376  	// func println(args ...interface{})
   377  	emptyIntfVar := types.NewVar(token.NoPos, builtin, "v", TyEmptyInterface)
   378  	emptyIntfTuple := types.NewTuple(emptyIntfVar)
   379  	emptyIntfSlice := types.NewSlice(TyEmptyInterface)
   380  	emptyIntfSliceVar := types.NewVar(token.NoPos, builtin, "args", emptyIntfSlice)
   381  	emptyIntfSliceTuple := types.NewTuple(emptyIntfSliceVar)
   382  	gbl.Insert(types.NewFunc(token.NoPos, builtin, "panic", types.NewSignatureType(nil, nil, nil, emptyIntfTuple, nil, false)))
   383  	gbl.Insert(types.NewFunc(token.NoPos, builtin, "recover", types.NewSignatureType(nil, nil, nil, nil, emptyIntfTuple, false)))
   384  	gbl.Insert(types.NewFunc(token.NoPos, builtin, "print", types.NewSignatureType(nil, nil, nil, emptyIntfSliceTuple, nil, true)))
   385  	gbl.Insert(types.NewFunc(token.NoPos, builtin, "println", types.NewSignatureType(nil, nil, nil, emptyIntfSliceTuple, nil, true)))
   386  
   387  	// new & make are special cases, they require to pass a type.
   388  	gbl.Insert(NewInstruction(token.NoPos, builtin, "new", newInstr{}))
   389  	gbl.Insert(NewInstruction(token.NoPos, builtin, "make", makeInstr{}))
   390  
   391  	// len & cap are special cases, because they may return a constant value.
   392  	gbl.Insert(NewInstruction(token.NoPos, builtin, "len", lenInstr{}))
   393  	gbl.Insert(NewInstruction(token.NoPos, builtin, "cap", capInstr{}))
   394  }
   395  
   396  func initUnsafeFuncs(pkg *Package) {
   397  	unsafe := types.NewPackage("unsafe", "unsafe")
   398  	gbl := unsafe.Scope()
   399  	// unsafe
   400  	gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Sizeof", unsafeSizeofInstr{}))
   401  	gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Alignof", unsafeAlignofInstr{}))
   402  	gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Offsetof", unsafeOffsetofInstr{}))
   403  	gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Add", unsafeAddInstr{}))
   404  	gbl.Insert(NewInstruction(token.NoPos, types.Unsafe, "Slice", unsafeSliceInstr{}))
   405  	pkg.unsafe_.Types = unsafe
   406  }
   407  
   408  func newBFunc(builtin *types.Package, name string, t typeBFunc) types.Object {
   409  	n := len(t.params)
   410  	vars := make([]*types.Var, n)
   411  	for i, param := range t.params {
   412  		vars[i] = types.NewParam(token.NoPos, builtin, param.name, types.Typ[param.typ])
   413  	}
   414  	result := types.NewParam(token.NoPos, builtin, "", types.Typ[t.result])
   415  	sig := types.NewSignatureType(nil, nil, nil, types.NewTuple(vars...), types.NewTuple(result), false)
   416  	return types.NewFunc(token.NoPos, builtin, name, sig)
   417  }
   418  
   419  func newXParamType(tparams []*TemplateParamType, x xType) types.Type {
   420  	if tidx, ok := x.(int); ok {
   421  		idx := tidx & 0xffff
   422  		switch tidx &^ 0xffff {
   423  		case xtNone:
   424  			return tparams[idx]
   425  		case xtEllipsis, xtSlice:
   426  			return NewSlice(tparams[idx])
   427  		case xtMap:
   428  			return NewMap(tparams[idx], tparams[idx+1])
   429  		case xtChanIn:
   430  			return NewChan(types.SendOnly, tparams[idx])
   431  		default:
   432  			panic("TODO: newXParamType - unexpected xType")
   433  		}
   434  	}
   435  	return x.(types.Type)
   436  }
   437  
   438  // ----------------------------------------------------------------------------
   439  
   440  type builtinFn struct {
   441  	fn   interface{}
   442  	narg int
   443  }
   444  
   445  var (
   446  	builtinFns = map[string]builtinFn{
   447  		"complex": {makeComplex, 2},
   448  		"real":    {constant.Real, 1},
   449  		"imag":    {constant.Imag, 1},
   450  	}
   451  )
   452  
   453  func builtinCall(fn *Element, args []*Element) constant.Value {
   454  	if fn, ok := fn.Val.(*ast.Ident); ok {
   455  		if bfn, ok := builtinFns[fn.Name]; ok {
   456  			a := args[0].CVal
   457  			switch bfn.narg {
   458  			case 1:
   459  				return bfn.fn.(func(a constant.Value) constant.Value)(a)
   460  			case 2:
   461  				b := args[1].CVal
   462  				return bfn.fn.(func(a, b constant.Value) constant.Value)(a, b)
   463  			}
   464  		}
   465  		panic("builtinCall: expect constant")
   466  	}
   467  	return nil
   468  }
   469  
   470  func makeComplex(re, im constant.Value) constant.Value {
   471  	return constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
   472  }
   473  
   474  type appendStringInstr struct {
   475  }
   476  
   477  // func append(slice []byte, val ..string) []byte
   478  func (p appendStringInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   479  	if len(args) == 2 && flags != 0 {
   480  		if t, ok := args[0].Type.(*types.Slice); ok {
   481  			if elem, ok := t.Elem().(*types.Basic); ok && elem.Kind() == types.Byte {
   482  				if v, ok := args[1].Type.(*types.Basic); ok {
   483  					if v.Kind() == types.String || v.Kind() == types.UntypedString {
   484  						return &Element{
   485  							Val: &ast.CallExpr{
   486  								Fun:      identAppend,
   487  								Args:     []ast.Expr{args[0].Val, args[1].Val},
   488  								Ellipsis: 1,
   489  							},
   490  							Type: t,
   491  						}, nil
   492  					}
   493  				}
   494  			}
   495  		}
   496  	}
   497  	return nil, syscall.EINVAL
   498  }
   499  
   500  type lenInstr struct {
   501  }
   502  
   503  type capInstr struct {
   504  }
   505  
   506  // func [Type lenable] len(v Type) int
   507  func (p lenInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   508  	if len(args) != 1 {
   509  		panic("TODO: len() should have one parameter")
   510  	}
   511  	var cval constant.Value
   512  	switch t := args[0].Type.(type) {
   513  	case *types.Basic:
   514  		switch t.Kind() {
   515  		case types.String, types.UntypedString:
   516  			if v := args[0].CVal; v != nil {
   517  				n := len(constant.StringVal(v))
   518  				cval = constant.MakeInt64(int64(n))
   519  			}
   520  		default:
   521  			panic("TODO: call len() to a basic type")
   522  		}
   523  	case *types.Array:
   524  		cval = constant.MakeInt64(t.Len())
   525  	case *types.Pointer:
   526  		if tt, ok := t.Elem().(*types.Array); ok {
   527  			cval = constant.MakeInt64(tt.Len())
   528  		} else {
   529  			panic("TODO: call len() to a pointer")
   530  		}
   531  	default:
   532  		if !lenable.Match(pkg, t) {
   533  			log.Panicln("TODO: can't call len() to", t)
   534  		}
   535  	}
   536  	ret = &Element{
   537  		Val:  &ast.CallExpr{Fun: identLen, Args: []ast.Expr{args[0].Val}},
   538  		Type: types.Typ[types.Int],
   539  		CVal: cval,
   540  	}
   541  	return
   542  }
   543  
   544  // func [Type capable] cap(v Type) int
   545  func (p capInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   546  	if len(args) != 1 {
   547  		panic("TODO: cap() should have one parameter")
   548  	}
   549  	var cval constant.Value
   550  	switch t := args[0].Type.(type) {
   551  	case *types.Array:
   552  		cval = constant.MakeInt64(t.Len())
   553  	case *types.Pointer:
   554  		if tt, ok := t.Elem().(*types.Array); ok {
   555  			cval = constant.MakeInt64(tt.Len())
   556  		} else {
   557  			panic("TODO: call cap() to a pointer")
   558  		}
   559  	default:
   560  		if !capable.Match(pkg, t) {
   561  			log.Panicln("TODO: can't call cap() to", t)
   562  		}
   563  	}
   564  	ret = &Element{
   565  		Val:  &ast.CallExpr{Fun: identCap, Args: []ast.Expr{args[0].Val}},
   566  		Type: types.Typ[types.Int],
   567  		CVal: cval,
   568  	}
   569  	return
   570  }
   571  
   572  type incInstr struct {
   573  }
   574  
   575  type decInstr struct {
   576  }
   577  
   578  // val++
   579  func (p incInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   580  	return callIncDec(pkg, args, token.INC)
   581  }
   582  
   583  // val--
   584  func (p decInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   585  	return callIncDec(pkg, args, token.DEC)
   586  }
   587  
   588  func callIncDec(pkg *Package, args []*Element, tok token.Token) (ret *Element, err error) {
   589  	if len(args) != 1 {
   590  		panic("TODO: please use val" + tok.String())
   591  	}
   592  	t, ok := args[0].Type.(*refType)
   593  	if !ok {
   594  		panic("TODO: not addressable")
   595  	}
   596  	cb := &pkg.cb
   597  	if !isNumeric(cb, t.typ) {
   598  		text, pos := cb.loadExpr(args[0].Src)
   599  		cb.panicCodeErrorf(pos, "invalid operation: %s%v (non-numeric type %v)", text, tok, t.typ)
   600  	}
   601  	cb.emitStmt(&ast.IncDecStmt{X: args[0].Val, Tok: tok})
   602  	return
   603  }
   604  
   605  func isNumeric(cb *CodeBuilder, typ types.Type) bool {
   606  	const (
   607  		numericFlags = types.IsInteger | types.IsFloat | types.IsComplex
   608  	)
   609  	if t, ok := typ.(*types.Named); ok {
   610  		typ = cb.getUnderlying(t)
   611  	}
   612  	if t, ok := typ.(*types.Basic); ok {
   613  		return (t.Info() & numericFlags) != 0
   614  	}
   615  	return false
   616  }
   617  
   618  type recvInstr struct {
   619  }
   620  
   621  // <-ch
   622  func (p recvInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   623  	if len(args) != 1 {
   624  		panic("TODO: please use <-ch")
   625  	}
   626  	t0 := args[0].Type
   627  retry:
   628  	switch t := t0.(type) {
   629  	case *types.Chan:
   630  		if t.Dir() != types.SendOnly {
   631  			typ := t.Elem()
   632  			if flags != 0 { // twoValue mode
   633  				typ = types.NewTuple(
   634  					pkg.NewParam(token.NoPos, "", typ),
   635  					pkg.NewParam(token.NoPos, "", types.Typ[types.Bool]))
   636  			}
   637  			ret = &Element{Val: &ast.UnaryExpr{Op: token.ARROW, X: args[0].Val}, Type: typ}
   638  			return
   639  		}
   640  		panic("TODO: <-ch is a send only chan")
   641  	case *types.Named:
   642  		t0 = pkg.cb.getUnderlying(t)
   643  		goto retry
   644  	}
   645  	panic("TODO: <-ch not a chan type")
   646  }
   647  
   648  type addrInstr struct {
   649  }
   650  
   651  // &variable
   652  func (p addrInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   653  	if len(args) != 1 {
   654  		panic("TODO: please use &variable to get its address")
   655  	}
   656  	// TODO: can't take addr(&) to a non-reference type
   657  	t, _ := DerefType(args[0].Type)
   658  	ret = &Element{Val: &ast.UnaryExpr{Op: token.AND, X: args[0].Val}, Type: types.NewPointer(t)}
   659  	return
   660  }
   661  
   662  type newInstr struct {
   663  }
   664  
   665  // func [] new(T any) *T
   666  func (p newInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   667  	if len(args) != 1 {
   668  		panic("TODO: use new(T) please")
   669  	}
   670  	ttyp, ok := args[0].Type.(*TypeType)
   671  	if !ok {
   672  		panic("TODO: new arg isn't a type")
   673  	}
   674  	typ := ttyp.Type()
   675  	ret = &Element{
   676  		Val: &ast.CallExpr{
   677  			Fun:  identNew,
   678  			Args: []ast.Expr{args[0].Val},
   679  		},
   680  		Type: types.NewPointer(typ),
   681  	}
   682  	return
   683  }
   684  
   685  type makeInstr struct {
   686  }
   687  
   688  // func [N ninteger] make(Type makable, size ...N) Type
   689  func (p makeInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   690  	n := len(args)
   691  	if n == 0 {
   692  		panic("TODO: make without args")
   693  	} else if n > 3 {
   694  		n, args = 3, args[:3]
   695  	}
   696  	ttyp, ok := args[0].Type.(*TypeType)
   697  	if !ok {
   698  		panic("TODO: make: first arg isn't a type")
   699  	}
   700  	typ := ttyp.Type()
   701  	if !makable.Match(pkg, typ) {
   702  		log.Panicln("TODO: can't make this type -", typ)
   703  	}
   704  	argsExpr := make([]ast.Expr, n)
   705  	for i, arg := range args {
   706  		argsExpr[i] = arg.Val
   707  	}
   708  	ret = &Element{
   709  		Val: &ast.CallExpr{
   710  			Fun:  identMake,
   711  			Args: argsExpr,
   712  		},
   713  		Type: typ,
   714  	}
   715  	return
   716  }
   717  
   718  func checkArgsCount(pkg *Package, fn string, n int, args int, src ast.Node) {
   719  	if args == n {
   720  		return
   721  	}
   722  	cb := &pkg.cb
   723  	text, pos := cb.loadExpr(src)
   724  	if pos != token.NoPos {
   725  		pos += token.Pos(len(fn))
   726  	}
   727  	if args < n {
   728  		cb.panicCodeErrorf(pos, "missing argument to function call: %v", text)
   729  	}
   730  	cb.panicCodeErrorf(pos, "too many arguments to function call: %v", text)
   731  }
   732  
   733  var (
   734  	std types.Sizes
   735  )
   736  
   737  func init() {
   738  	if runtime.Compiler == "gopherjs" {
   739  		std = &types.StdSizes{WordSize: 4, MaxAlign: 4}
   740  	} else {
   741  		std = types.SizesFor(runtime.Compiler, runtime.GOARCH)
   742  	}
   743  }
   744  
   745  func unsafeRef(name string) Ref {
   746  	return PkgRef{types.Unsafe}.Ref(name)
   747  }
   748  
   749  type unsafeSizeofInstr struct{}
   750  
   751  // func unsafe.Sizeof(x ArbitraryType) uintptr
   752  func (p unsafeSizeofInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   753  	checkArgsCount(pkg, "unsafe.Sizeof", 1, len(args), src)
   754  
   755  	typ := types.Default(realType(args[0].Type))
   756  	fn := toObjectExpr(pkg, unsafeRef("Sizeof"))
   757  	ret = &Element{
   758  		Val:  &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val}},
   759  		Type: types.Typ[types.Uintptr],
   760  		CVal: constant.MakeInt64(std.Sizeof(typ)),
   761  		Src:  src,
   762  	}
   763  	return
   764  }
   765  
   766  type unsafeAlignofInstr struct{}
   767  
   768  // func unsafe.Alignof(x ArbitraryType) uintptr
   769  func (p unsafeAlignofInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   770  	checkArgsCount(pkg, "unsafe.Alignof", 1, len(args), src)
   771  
   772  	typ := types.Default(realType(args[0].Type))
   773  	fn := toObjectExpr(pkg, unsafeRef("Alignof"))
   774  	ret = &Element{
   775  		Val:  &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val}},
   776  		Type: types.Typ[types.Uintptr],
   777  		CVal: constant.MakeInt64(std.Alignof(typ)),
   778  		Src:  src,
   779  	}
   780  	return
   781  }
   782  
   783  type unsafeOffsetofInstr struct{}
   784  
   785  // func unsafe.Offsetof(x ArbitraryType) uintptr
   786  func (p unsafeOffsetofInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   787  	checkArgsCount(pkg, "unsafe.Offsetof", 1, len(args), src)
   788  
   789  	var sel *ast.SelectorExpr
   790  	var ok bool
   791  	if sel, ok = args[0].Val.(*ast.SelectorExpr); !ok {
   792  		s, pos := pkg.cb.loadExpr(src)
   793  		if pos != token.NoPos {
   794  			pos += token.Pos(len("unsafe.Offsetof"))
   795  		}
   796  		pkg.cb.panicCodeErrorf(pos, "invalid expression %v", s)
   797  	}
   798  	if _, ok = args[0].Type.(*types.Signature); ok {
   799  		s, pos := pkg.cb.loadExpr(src)
   800  		if pos != token.NoPos {
   801  			pos += token.Pos(len("unsafe.Offsetof"))
   802  		}
   803  		pkg.cb.panicCodeErrorf(pos, "invalid expression %v: argument is a method value", s)
   804  	}
   805  	recv := denoteRecv(sel)
   806  	typ := getStruct(pkg, recv.Type)
   807  	_, index, _ := types.LookupFieldOrMethod(typ, false, pkg.Types, sel.Sel.Name)
   808  	offset, err := offsetof(pkg, typ, index, recv.Src, sel.Sel.Name)
   809  	if err != nil {
   810  		_, pos := pkg.cb.loadExpr(src)
   811  		if pos != token.NoPos {
   812  			pos += token.Pos(len("unsafe.Offsetof"))
   813  		}
   814  		pkg.cb.panicCodeErrorf(pos, "%v", err)
   815  	}
   816  	//var offset int64
   817  	fn := toObjectExpr(pkg, unsafeRef("Offsetof"))
   818  	ret = &Element{
   819  		Val:  &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val}},
   820  		Type: types.Typ[types.Uintptr],
   821  		CVal: constant.MakeInt64(offset),
   822  		Src:  src,
   823  	}
   824  	return
   825  }
   826  
   827  func getStruct(pkg *Package, typ types.Type) *types.Struct {
   828  retry:
   829  	switch t := typ.(type) {
   830  	case *types.Struct:
   831  		return t
   832  	case *types.Pointer:
   833  		typ = t.Elem()
   834  		goto retry
   835  	case *types.Named:
   836  		typ = pkg.cb.getUnderlying(t)
   837  		goto retry
   838  	}
   839  	return nil
   840  }
   841  
   842  func offsetsof(T *types.Struct) []int64 {
   843  	var fields []*types.Var
   844  	for i := 0; i < T.NumFields(); i++ {
   845  		fields = append(fields, T.Field(i))
   846  	}
   847  	return std.Offsetsof(fields)
   848  }
   849  
   850  // offsetof returns the offset of the field specified via
   851  // the index sequence relative to typ. All embedded fields
   852  // must be structs (rather than pointer to structs).
   853  func offsetof(pkg *Package, typ types.Type, index []int, recv ast.Node, sel string) (int64, error) {
   854  	var o int64
   855  	var typList []string
   856  	var indirectType int
   857  	for n, i := range index {
   858  		if n > 0 {
   859  			if t, ok := typ.(*types.Pointer); ok {
   860  				typ = t.Elem()
   861  				indirectType = n
   862  			}
   863  			if t, ok := typ.(*types.Named); ok {
   864  				typList = append(typList, t.Obj().Name())
   865  				typ = t.Underlying()
   866  			}
   867  		}
   868  		s := typ.(*types.Struct)
   869  		o += offsetsof(s)[i]
   870  		typ = s.Field(i).Type()
   871  	}
   872  	if indirectType > 0 {
   873  		s, _ := pkg.cb.loadExpr(recv)
   874  		return -1, fmt.Errorf("invalid expression unsafe.Offsetof(%v.%v.%v): selector implies indirection of embedded %v.%v",
   875  			s, strings.Join(typList, "."), sel,
   876  			s, strings.Join(typList[:indirectType], "."))
   877  	}
   878  	return o, nil
   879  }
   880  
   881  type unsafeAddInstr struct{}
   882  
   883  // func unsafe.Add(ptr Pointer, len IntegerType) Pointer
   884  func (p unsafeAddInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   885  	checkArgsCount(pkg, "unsafe.Add", 2, len(args), src)
   886  
   887  	if ts := args[0].Type.String(); ts != "unsafe.Pointer" {
   888  		s, _ := pkg.cb.loadExpr(args[0].Src)
   889  		pos := getSrcPos(src)
   890  		if pos != token.NoPos {
   891  			pos += token.Pos(len("unsafe.Add"))
   892  		}
   893  		pkg.cb.panicCodeErrorf(pos, "cannot use %v (type %v) as type unsafe.Pointer in argument to unsafe.Add", s, ts)
   894  	}
   895  	if t := args[1].Type; !ninteger.Match(pkg, t) {
   896  		s, _ := pkg.cb.loadExpr(args[1].Src)
   897  		pos := getSrcPos(src)
   898  		if pos != token.NoPos {
   899  			pos += token.Pos(len("unsafe.Add"))
   900  		}
   901  		pkg.cb.panicCodeErrorf(pos, "cannot use %v (type %v) as type int", s, t)
   902  	}
   903  	fn := toObjectExpr(pkg, unsafeRef("Sizeof")).(*ast.SelectorExpr)
   904  	fn.Sel.Name = "Add" // only in go v1.7+
   905  	ret = &Element{
   906  		Val:  &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val, args[1].Val}},
   907  		Type: types.Typ[types.UnsafePointer],
   908  	}
   909  	return
   910  }
   911  
   912  type unsafeSliceInstr struct{}
   913  
   914  // func unsafe.Slice(ptr *ArbitraryType, len IntegerType) []ArbitraryType
   915  func (p unsafeSliceInstr) Call(pkg *Package, args []*Element, flags InstrFlags, src ast.Node) (ret *Element, err error) {
   916  	checkArgsCount(pkg, "unsafe.Slice", 2, len(args), src)
   917  
   918  	t0, ok := args[0].Type.(*types.Pointer)
   919  	if !ok {
   920  		pos := getSrcPos(src)
   921  		if pos != token.NoPos {
   922  			pos += token.Pos(len("unsafe.Slice"))
   923  		}
   924  		pkg.cb.panicCodeErrorf(pos, "first argument to unsafe.Slice must be pointer; have %v", args[0].Type)
   925  	}
   926  	if t := args[1].Type; !ninteger.Match(pkg, t) {
   927  		pos := getSrcPos(src)
   928  		if pos != token.NoPos {
   929  			pos += token.Pos(len("unsafe.Slice"))
   930  		}
   931  		pkg.cb.panicCodeErrorf(pos, "non-integer len argument in unsafe.Slice - %v", t)
   932  	}
   933  	fn := toObjectExpr(pkg, unsafeRef("Sizeof")).(*ast.SelectorExpr)
   934  	fn.Sel.Name = "Slice" // only in go v1.7+
   935  	ret = &Element{
   936  		Val:  &ast.CallExpr{Fun: fn, Args: []ast.Expr{args[0].Val, args[1].Val}},
   937  		Type: types.NewSlice(t0.Elem()),
   938  	}
   939  	return
   940  }
   941  
   942  // ----------------------------------------------------------------------------
   943  
   944  type basicContract struct {
   945  	kinds uint64
   946  	desc  string
   947  }
   948  
   949  func (p *basicContract) Match(pkg *Package, typ types.Type) bool {
   950  retry:
   951  	switch t := typ.(type) {
   952  	case *types.Basic:
   953  		if (uint64(1)<<t.Kind())&p.kinds != 0 {
   954  			return true
   955  		}
   956  	case *types.Named:
   957  		typ = pkg.cb.getUnderlying(t)
   958  		goto retry
   959  	}
   960  	return false
   961  }
   962  
   963  func (p *basicContract) String() string {
   964  	return p.desc
   965  }
   966  
   967  const (
   968  	// int, int64, int32, int16, int8, uint, uintptr, uint64, uint32, uint16, uint8
   969  	kindsInteger = (1 << types.Int) | (1 << types.Int64) | (1 << types.Int32) | (1 << types.Int16) | (1 << types.Int8) |
   970  		(1 << types.Uint) | (1 << types.Uintptr) | (1 << types.Uint64) | (1 << types.Uint32) | (1 << types.Uint16) | (1 << types.Uint8) |
   971  		(1 << types.UntypedInt) | (1 << types.UntypedRune)
   972  
   973  	// float32, float64
   974  	kindsFloat = (1 << types.Float32) | (1 << types.Float64) | (1 << types.UntypedFloat)
   975  
   976  	// complex64, complex128
   977  	kindsComplex = (1 << types.Complex64) | (1 << types.Complex128) | (1 << types.UntypedComplex)
   978  
   979  	// string
   980  	kindsString = (1 << types.String) | (1 << types.UntypedString)
   981  
   982  	// bool
   983  	kindsBool = (1 << types.Bool) | (1 << types.UntypedBool)
   984  
   985  	// integer, float, complex
   986  	kindsNumber = kindsInteger | kindsFloat | kindsComplex
   987  
   988  	// number, string
   989  	kindsAddable = kindsNumber | kindsString
   990  
   991  	// integer, float, string
   992  	kindsOrderable = kindsInteger | kindsFloat | kindsString
   993  )
   994  
   995  // ----------------------------------------------------------------------------
   996  
   997  type comparableT struct {
   998  	// addable
   999  	// type bool, interface, pointer, array, chan, struct
  1000  	// NOTE: slice/map/func is very special, can only be compared to nil
  1001  }
  1002  
  1003  func (p comparableT) Match(pkg *Package, typ types.Type) bool {
  1004  retry:
  1005  	switch t := typ.(type) {
  1006  	case *types.Basic:
  1007  		return t.Kind() != types.UntypedNil // excluding nil
  1008  	case *types.Named:
  1009  		typ = pkg.cb.getUnderlying(t)
  1010  		goto retry
  1011  	case *types.Slice: // slice/map/func is very special
  1012  		return false
  1013  	case *types.Map:
  1014  		return false
  1015  	case *types.Signature:
  1016  		return false
  1017  	case *TemplateSignature:
  1018  		return false
  1019  	case *TemplateParamType:
  1020  		panic("TODO: unexpected - compare to template param type?")
  1021  	case *types.Tuple:
  1022  		panic("TODO: unexpected - compare to tuple type?")
  1023  	case *unboundType:
  1024  		panic("TODO: unexpected - compare to unboundType?")
  1025  	case *unboundFuncParam:
  1026  		panic("TODO: unexpected - compare to unboundFuncParam?")
  1027  	}
  1028  	return true
  1029  }
  1030  
  1031  func (p comparableT) String() string {
  1032  	return "comparable"
  1033  }
  1034  
  1035  // ----------------------------------------------------------------------------
  1036  
  1037  type anyT struct {
  1038  }
  1039  
  1040  func (p anyT) Match(pkg *Package, typ types.Type) bool {
  1041  	return true
  1042  }
  1043  
  1044  func (p anyT) String() string {
  1045  	return "any"
  1046  }
  1047  
  1048  // ----------------------------------------------------------------------------
  1049  
  1050  type capableT struct {
  1051  	// type slice, chan, array, array_pointer
  1052  }
  1053  
  1054  func (p capableT) Match(pkg *Package, typ types.Type) bool {
  1055  retry:
  1056  	switch t := typ.(type) {
  1057  	case *types.Slice:
  1058  		return true
  1059  	case *types.Chan:
  1060  		return true
  1061  	case *types.Array:
  1062  		return true
  1063  	case *types.Pointer:
  1064  		_, ok := t.Elem().(*types.Array) // array_pointer
  1065  		return ok
  1066  	case *types.Named:
  1067  		typ = pkg.cb.getUnderlying(t)
  1068  		goto retry
  1069  	}
  1070  	return false
  1071  }
  1072  
  1073  func (p capableT) String() string {
  1074  	return "capable"
  1075  }
  1076  
  1077  // ----------------------------------------------------------------------------
  1078  
  1079  type lenableT struct {
  1080  	// capable
  1081  	// type map, string
  1082  }
  1083  
  1084  func (p lenableT) Match(pkg *Package, typ types.Type) bool {
  1085  retry:
  1086  	switch t := typ.(type) {
  1087  	case *types.Basic:
  1088  		k := t.Kind()
  1089  		return k == types.String || k == types.UntypedString
  1090  	case *types.Map:
  1091  		return true
  1092  	case *types.Named:
  1093  		typ = pkg.cb.getUnderlying(t)
  1094  		goto retry
  1095  	}
  1096  	return capable.Match(pkg, typ)
  1097  }
  1098  
  1099  func (p lenableT) String() string {
  1100  	return "lenable"
  1101  }
  1102  
  1103  // ----------------------------------------------------------------------------
  1104  
  1105  type makableT struct {
  1106  	// type slice, chan, map
  1107  }
  1108  
  1109  func (p makableT) Match(pkg *Package, typ types.Type) bool {
  1110  retry:
  1111  	switch t := typ.(type) {
  1112  	case *types.Slice:
  1113  		return true
  1114  	case *types.Map:
  1115  		return true
  1116  	case *types.Chan:
  1117  		return true
  1118  	case *types.Named:
  1119  		typ = pkg.cb.getUnderlying(t)
  1120  		goto retry
  1121  	}
  1122  	return false
  1123  }
  1124  
  1125  func (p makableT) String() string {
  1126  	return "makable"
  1127  }
  1128  
  1129  // ----------------------------------------------------------------------------
  1130  
  1131  type addableT struct {
  1132  	// type basicContract{kindsAddable}, untyped_bigint, untyped_bigrat, untyped_bigfloat
  1133  }
  1134  
  1135  func (p addableT) Match(pkg *Package, typ types.Type) bool {
  1136  	switch t := typ.(type) {
  1137  	case *types.Named:
  1138  		switch t {
  1139  		case pkg.utBigInt, pkg.utBigRat, pkg.utBigFlt:
  1140  			return true
  1141  		default:
  1142  			// TODO: refactor
  1143  			cb := pkg.cb
  1144  			cb.stk.Push(elemNone)
  1145  			kind := cb.findMember(typ, "Gop_Add", "", MemberFlagVal, &Element{}, nil)
  1146  			if kind != 0 {
  1147  				cb.stk.PopN(1)
  1148  				if kind == MemberMethod {
  1149  					return true
  1150  				}
  1151  			}
  1152  		}
  1153  	}
  1154  	c := &basicContract{kinds: kindsAddable}
  1155  	return c.Match(pkg, typ)
  1156  }
  1157  
  1158  func (p addableT) String() string {
  1159  	return "addable"
  1160  }
  1161  
  1162  // ----------------------------------------------------------------------------
  1163  
  1164  type numberT struct {
  1165  	// type basicContract{kindsNumber}, untyped_bigint, untyped_bigrat, untyped_bigfloat
  1166  }
  1167  
  1168  func (p numberT) Match(pkg *Package, typ types.Type) bool {
  1169  	switch t := typ.(type) {
  1170  	case *types.Named:
  1171  		switch t {
  1172  		case pkg.utBigInt, pkg.utBigRat, pkg.utBigFlt:
  1173  			return true
  1174  		}
  1175  	}
  1176  	c := &basicContract{kinds: kindsNumber}
  1177  	return c.Match(pkg, typ)
  1178  }
  1179  
  1180  func (p numberT) String() string {
  1181  	return "number"
  1182  }
  1183  
  1184  // ----------------------------------------------------------------------------
  1185  
  1186  type orderableT struct {
  1187  	// type basicContract{kindsOrderable}, untyped_bigint, untyped_bigrat, untyped_bigfloat
  1188  }
  1189  
  1190  func (p orderableT) Match(pkg *Package, typ types.Type) bool {
  1191  	switch t := typ.(type) {
  1192  	case *types.Named:
  1193  		switch t {
  1194  		case pkg.utBigInt, pkg.utBigRat, pkg.utBigFlt:
  1195  			return true
  1196  		}
  1197  	}
  1198  	c := &basicContract{kinds: kindsOrderable}
  1199  	return c.Match(pkg, typ)
  1200  }
  1201  
  1202  func (p orderableT) String() string {
  1203  	return "orderable"
  1204  }
  1205  
  1206  // ----------------------------------------------------------------------------
  1207  
  1208  type integerT struct {
  1209  	// type basicContract{kindsNumber}, untyped_bigint
  1210  }
  1211  
  1212  func (p integerT) Match(pkg *Package, typ types.Type) bool {
  1213  	c := &basicContract{kinds: kindsNumber}
  1214  	if c.Match(pkg, typ) {
  1215  		return true
  1216  	}
  1217  	return typ == pkg.utBigInt
  1218  }
  1219  
  1220  func (p integerT) String() string {
  1221  	return "integer"
  1222  }
  1223  
  1224  // ----------------------------------------------------------------------------
  1225  
  1226  var (
  1227  	any        = anyT{}
  1228  	capable    = capableT{}
  1229  	lenable    = lenableT{}
  1230  	makable    = makableT{}
  1231  	cbool      = &basicContract{kindsBool, "bool"}
  1232  	ninteger   = &basicContract{kindsInteger, "ninteger"}
  1233  	tstring    = &basicContract{kindsString, "tstring"}
  1234  	orderable  = orderableT{}
  1235  	integer    = integerT{}
  1236  	number     = numberT{}
  1237  	addable    = addableT{}
  1238  	comparable = comparableT{}
  1239  )
  1240  
  1241  // ----------------------------------------------------------------------------
  1242  
  1243  type bmExargs = []interface{}
  1244  
  1245  type builtinMethod struct {
  1246  	name  string
  1247  	fn    types.Object
  1248  	eargs bmExargs
  1249  }
  1250  
  1251  func (p *builtinMethod) Results() *types.Tuple {
  1252  	return p.fn.Type().(*types.Signature).Results()
  1253  }
  1254  
  1255  func (p *builtinMethod) Params() *types.Tuple {
  1256  	params := p.fn.Type().(*types.Signature).Params()
  1257  	n := params.Len() - len(p.eargs) - 1
  1258  	if n <= 0 {
  1259  		return nil
  1260  	}
  1261  	ret := make([]*types.Var, n)
  1262  	for i := 0; i < n; i++ {
  1263  		ret[i] = params.At(i + 1)
  1264  	}
  1265  	return types.NewTuple(ret...)
  1266  }
  1267  
  1268  type mthdSignature interface {
  1269  	Results() *types.Tuple
  1270  	Params() *types.Tuple
  1271  }
  1272  
  1273  type builtinTI struct {
  1274  	typ     types.Type
  1275  	methods []*builtinMethod
  1276  }
  1277  
  1278  func (p *builtinTI) NumMethods() int {
  1279  	return len(p.methods)
  1280  }
  1281  
  1282  func (p *builtinTI) Method(i int) *builtinMethod {
  1283  	return p.methods[i]
  1284  }
  1285  
  1286  func (p *builtinTI) lookupByName(name string) mthdSignature {
  1287  	for i, n := 0, p.NumMethods(); i < n; i++ {
  1288  		method := p.Method(i)
  1289  		if method.name == name {
  1290  			return method
  1291  		}
  1292  	}
  1293  	return nil
  1294  }
  1295  
  1296  var (
  1297  	tyMap   types.Type = types.NewMap(types.Typ[types.Invalid], types.Typ[types.Invalid])
  1298  	tyChan  types.Type = types.NewChan(0, types.Typ[types.Invalid])
  1299  	tySlice types.Type = types.NewSlice(types.Typ[types.Invalid])
  1300  )
  1301  
  1302  func initBuiltinTIs(pkg *Package) {
  1303  	var (
  1304  		float64TI, intTI, int64TI, uint64TI *builtinTI
  1305  		ioxTI, stringTI, stringSliceTI      *builtinTI
  1306  	)
  1307  	btiMap := new(typeutil.Map)
  1308  	strconv := pkg.TryImport("strconv")
  1309  	strings := pkg.TryImport("strings")
  1310  	btoLen := types.Universe.Lookup("len")
  1311  	btoCap := types.Universe.Lookup("cap")
  1312  	{
  1313  		ioxPkg := pkg.conf.PkgPathIox
  1314  		if debugImportIox && ioxPkg == "" {
  1315  			ioxPkg = "github.com/goplus/gogen/internal/iox"
  1316  		}
  1317  		if ioxPkg != "" {
  1318  			if os := pkg.TryImport("os"); os.isValid() {
  1319  				if iox := pkg.TryImport(ioxPkg); iox.isValid() {
  1320  					ioxTI = &builtinTI{
  1321  						typ: os.Ref("File").Type(),
  1322  						methods: []*builtinMethod{
  1323  							{"Gop_Enum", iox.Ref("EnumLines"), nil},
  1324  						},
  1325  					}
  1326  				}
  1327  			}
  1328  		}
  1329  	}
  1330  	if strconv.isValid() {
  1331  		float64TI = &builtinTI{
  1332  			typ: types.Typ[types.Float64],
  1333  			methods: []*builtinMethod{
  1334  				{"String", strconv.Ref("FormatFloat"), bmExargs{'g', -1, 64}},
  1335  			},
  1336  		}
  1337  		intTI = &builtinTI{
  1338  			typ: types.Typ[types.Int],
  1339  			methods: []*builtinMethod{
  1340  				{"String", strconv.Ref("Itoa"), nil},
  1341  			},
  1342  		}
  1343  		int64TI = &builtinTI{
  1344  			typ: types.Typ[types.Int64],
  1345  			methods: []*builtinMethod{
  1346  				{"String", strconv.Ref("FormatInt"), bmExargs{10}},
  1347  			},
  1348  		}
  1349  		uint64TI = &builtinTI{
  1350  			typ: types.Typ[types.Uint64],
  1351  			methods: []*builtinMethod{
  1352  				{"String", strconv.Ref("FormatUint"), bmExargs{10}},
  1353  			},
  1354  		}
  1355  	}
  1356  	if strings.isValid() && strconv.isValid() {
  1357  		stringTI = &builtinTI{
  1358  			typ: types.Typ[types.String],
  1359  			methods: []*builtinMethod{
  1360  				{"Len", btoLen, nil},
  1361  				{"Count", strings.Ref("Count"), nil},
  1362  				{"Int", strconv.Ref("Atoi"), nil},
  1363  				{"Int64", strconv.Ref("ParseInt"), bmExargs{10, 64}},
  1364  				{"Uint64", strconv.Ref("ParseUint"), bmExargs{10, 64}},
  1365  				{"Float", strconv.Ref("ParseFloat"), bmExargs{64}},
  1366  				{"Index", strings.Ref("Index"), nil},
  1367  				{"IndexAny", strings.Ref("IndexAny"), nil},
  1368  				{"IndexByte", strings.Ref("IndexByte"), nil},
  1369  				{"IndexRune", strings.Ref("IndexRune"), nil},
  1370  				{"LastIndex", strings.Ref("LastIndex"), nil},
  1371  				{"LastIndexAny", strings.Ref("LastIndexAny"), nil},
  1372  				{"LastIndexByte", strings.Ref("LastIndexByte"), nil},
  1373  				{"Contains", strings.Ref("Contains"), nil},
  1374  				{"ContainsAny", strings.Ref("ContainsAny"), nil},
  1375  				{"ContainsRune", strings.Ref("ContainsRune"), nil},
  1376  				{"Compare", strings.Ref("Compare"), nil},
  1377  				{"EqualFold", strings.Ref("EqualFold"), nil},
  1378  				{"HasPrefix", strings.Ref("HasPrefix"), nil},
  1379  				{"HasSuffix", strings.Ref("HasSuffix"), nil},
  1380  				{"Quote", strconv.Ref("Quote"), nil},
  1381  				{"Unquote", strconv.Ref("Unquote"), nil},
  1382  				{"ToTitle", strings.Ref("ToTitle"), nil},
  1383  				{"ToUpper", strings.Ref("ToUpper"), nil},
  1384  				{"ToLower", strings.Ref("ToLower"), nil},
  1385  				{"Fields", strings.Ref("Fields"), nil},
  1386  				{"Repeat", strings.Ref("Repeat"), nil},
  1387  				{"Split", strings.Ref("Split"), nil},
  1388  				{"SplitAfter", strings.Ref("SplitAfter"), nil},
  1389  				{"SplitN", strings.Ref("SplitN"), nil},
  1390  				{"SplitAfterN", strings.Ref("SplitAfterN"), nil},
  1391  				{"Replace", strings.Ref("Replace"), nil},
  1392  				{"ReplaceAll", strings.Ref("ReplaceAll"), nil},
  1393  				{"Trim", strings.Ref("Trim"), nil},
  1394  				{"TrimSpace", strings.Ref("TrimSpace"), nil},
  1395  				{"TrimLeft", strings.Ref("TrimLeft"), nil},
  1396  				{"TrimRight", strings.Ref("TrimRight"), nil},
  1397  				{"TrimPrefix", strings.Ref("TrimPrefix"), nil},
  1398  				{"TrimSuffix", strings.Ref("TrimSuffix"), nil},
  1399  			},
  1400  		}
  1401  	}
  1402  	if strings.isValid() {
  1403  		stringSliceTI = &builtinTI{
  1404  			typ: types.NewSlice(types.Typ[types.String]),
  1405  			methods: []*builtinMethod{
  1406  				{"Len", btoLen, nil},
  1407  				{"Cap", btoCap, nil},
  1408  				{"Join", strings.Ref("Join"), nil},
  1409  			},
  1410  		}
  1411  	}
  1412  	tis := []*builtinTI{
  1413  		ioxTI,
  1414  		float64TI,
  1415  		intTI,
  1416  		int64TI,
  1417  		uint64TI,
  1418  		stringTI,
  1419  		stringSliceTI,
  1420  		{
  1421  			typ: tySlice,
  1422  			methods: []*builtinMethod{
  1423  				{"Len", btoLen, nil},
  1424  				{"Cap", btoCap, nil},
  1425  			},
  1426  		},
  1427  		{
  1428  			typ: tyMap,
  1429  			methods: []*builtinMethod{
  1430  				{"Len", btoLen, nil},
  1431  			},
  1432  		},
  1433  		{
  1434  			typ: tyChan,
  1435  			methods: []*builtinMethod{
  1436  				{"Len", btoLen, nil},
  1437  			},
  1438  		},
  1439  	}
  1440  	for _, ti := range tis {
  1441  		if ti != nil {
  1442  			btiMap.Set(ti.typ, ti)
  1443  		}
  1444  	}
  1445  	pkg.cb.btiMap = btiMap
  1446  }
  1447  
  1448  func (p *CodeBuilder) getBuiltinTI(typ types.Type) *builtinTI {
  1449  	switch t := typ.(type) {
  1450  	case *types.Basic:
  1451  		typ = types.Default(typ)
  1452  	case *types.Slice:
  1453  		if t.Elem() != types.Typ[types.String] {
  1454  			typ = tySlice
  1455  		}
  1456  	case *types.Map:
  1457  		typ = tyMap
  1458  	case *types.Chan:
  1459  		typ = tyChan
  1460  	}
  1461  	if bti := p.btiMap.At(typ); bti != nil {
  1462  		return bti.(*builtinTI)
  1463  	}
  1464  	return nil
  1465  }
  1466  
  1467  // ----------------------------------------------------------------------------