github.com/goplus/gop@v1.2.6/cl/expr.go (about)

     1  /*
     2   * Copyright (c) 2021 The GoPlus Authors (goplus.org). All rights reserved.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cl
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  	goast "go/ast"
    23  	gotoken "go/token"
    24  	"go/types"
    25  	"log"
    26  	"math/big"
    27  	"strconv"
    28  	"strings"
    29  	"syscall"
    30  
    31  	"github.com/goplus/gogen"
    32  	"github.com/goplus/gogen/cpackages"
    33  	"github.com/goplus/gop/ast"
    34  	"github.com/goplus/gop/printer"
    35  	"github.com/goplus/gop/token"
    36  )
    37  
    38  /*-----------------------------------------------------------------------------
    39  
    40  Name context:
    41  - varVal               (ident)
    42  - varRef = expr        (identLHS)
    43  - pkgRef.member        (selectorExpr)
    44  - pkgRef.member = expr (selectorExprLHS)
    45  - pkgRef.fn(args)      (callExpr)
    46  - fn(args)             (callExpr)
    47  - spx.fn(args)         (callExpr)
    48  - this.member          (classMember)
    49  - this.method(args)    (classMember)
    50  
    51  Name lookup:
    52  - local variables
    53  - $recv members (only in class files)
    54  - package globals (variables, constants, types, imported packages etc.)
    55  - $spx package exports (only in class files)
    56  - $universe package exports (including builtins)
    57  
    58  // ---------------------------------------------------------------------------*/
    59  
    60  const (
    61  	clIdentCanAutoCall = 1 << iota // allow auto property
    62  	clIdentAllowBuiltin
    63  	clIdentLHS
    64  	clIdentSelectorExpr // this ident is X (not Sel) of ast.SelectorExpr
    65  	clIdentGoto
    66  	clCallWithTwoValue
    67  	clCommandWithoutArgs // this expr is a command without args (eg. ls)
    68  	clCommandIdent       // this expr is a command and an ident (eg. mkdir "abc")
    69  	clIdentInStringLitEx // this expr is an ident in a string extended literal (eg. ${PATH})
    70  )
    71  
    72  const (
    73  	objNormal = iota
    74  	objPkgRef
    75  	objCPkgRef
    76  	objGopExecOrEnv
    77  
    78  	objGopEnv  = objGopExecOrEnv
    79  	objGopExec = objGopExecOrEnv
    80  )
    81  
    82  func compileIdent(ctx *blockCtx, ident *ast.Ident, flags int) (pkg gogen.PkgRef, kind int) {
    83  	fvalue := (flags&clIdentSelectorExpr) != 0 || (flags&clIdentLHS) == 0
    84  	cb := ctx.cb
    85  	name := ident.Name
    86  	if name == "_" {
    87  		if fvalue {
    88  			panic(ctx.newCodeError(ident.Pos(), "cannot use _ as value"))
    89  		}
    90  		cb.VarRef(nil)
    91  		return
    92  	}
    93  
    94  	var recv *types.Var
    95  	var oldo types.Object
    96  	scope := ctx.pkg.Types.Scope()
    97  	at, o := cb.Scope().LookupParent(name, token.NoPos)
    98  	if o != nil {
    99  		if at != scope && at != types.Universe { // local object
   100  			goto find
   101  		}
   102  	}
   103  
   104  	if ctx.isClass { // in a Go+ class file
   105  		if recv = classRecv(cb); recv != nil {
   106  			cb.Val(recv)
   107  			chkFlag := flags
   108  			if chkFlag&clIdentSelectorExpr != 0 { // TODO: remove this condition
   109  				chkFlag = clIdentCanAutoCall
   110  			}
   111  			if compileMember(ctx, ident, name, chkFlag) == nil { // class member object
   112  				return
   113  			}
   114  			cb.InternalStack().PopN(1)
   115  		}
   116  	}
   117  
   118  	// global object
   119  	if ctx.loadSymbol(name) {
   120  		o, at = scope.Lookup(name), scope
   121  	}
   122  	if o != nil && at != types.Universe {
   123  		goto find
   124  	}
   125  
   126  	// pkgRef object
   127  	if (flags & clIdentSelectorExpr) != 0 {
   128  		if name == "C" && len(ctx.clookups) > 0 {
   129  			kind = objCPkgRef
   130  			return
   131  		}
   132  		if pi, ok := ctx.findImport(name); ok {
   133  			if rec := ctx.recorder(); rec != nil {
   134  				rec.Use(ident, pi.pkgName)
   135  			}
   136  			return pi.PkgRef, objPkgRef
   137  		}
   138  	}
   139  
   140  	// function alias
   141  	if compileFuncAlias(ctx, scope, ident, flags) {
   142  		return
   143  	}
   144  
   145  	// object from import . "xxx"
   146  	if compilePkgRef(ctx, gogen.PkgRef{}, ident, flags, objPkgRef) {
   147  		return
   148  	}
   149  
   150  	// universe object
   151  	if obj := ctx.pkg.Builtin().TryRef(name); obj != nil {
   152  		if (flags&clIdentAllowBuiltin) == 0 && isBuiltin(o) && !strings.HasPrefix(o.Name(), "print") {
   153  			panic(ctx.newCodeErrorf(ident.Pos(), "use of builtin %s not in function call", name))
   154  		}
   155  		oldo, o = o, obj
   156  	} else if o == nil {
   157  		// for support Gop_Exec, see TestSpxGopExec
   158  		if (clCommandIdent&flags) != 0 && recv != nil && gopMember(cb, recv, "Gop_Exec", ident) == nil {
   159  			kind = objGopExec
   160  			return
   161  		}
   162  		// for support Gop_Env, see TestSpxGopEnv
   163  		if (clIdentInStringLitEx&flags) != 0 && recv != nil && gopMember(cb, recv, "Gop_Env", ident) == nil {
   164  			kind = objGopEnv
   165  			return
   166  		}
   167  		if (clIdentGoto & flags) != 0 {
   168  			l := ident.Obj.Data.(*ast.Ident)
   169  			panic(ctx.newCodeErrorf(l.Pos(), "label %v is not defined", l.Name))
   170  		}
   171  		panic(ctx.newCodeErrorf(ident.Pos(), "undefined: %s", name))
   172  	}
   173  
   174  find:
   175  	if fvalue {
   176  		cb.Val(o, ident)
   177  	} else {
   178  		cb.VarRef(o, ident)
   179  	}
   180  	if rec := ctx.recorder(); rec != nil {
   181  		e := cb.Get(-1)
   182  		if oldo != nil && gogen.IsTypeEx(e.Type) { // for builtin object
   183  			rec.recordIdent(ident, oldo)
   184  			return
   185  		}
   186  		rec.recordIdent(ident, o)
   187  	}
   188  	return
   189  }
   190  
   191  /*
   192  func compileMatrixLit(ctx *blockCtx, v *ast.MatrixLit) {
   193  	cb := ctx.cb
   194  	ncol := -1
   195  	for _, elts := range v.Elts {
   196  		switch n := len(elts); n {
   197  		case 1:
   198  			elt := elts[0]
   199  			if e, ok := elt.(*ast.Ellipsis); ok {
   200  				compileExpr(ctx, e.Elt)
   201  				panic("TODO") // TODO(xsw): matrixLit with ellipsis
   202  			}
   203  			fallthrough
   204  		default:
   205  			if ncol < 0 {
   206  				ncol = n
   207  			} else if ncol != n {
   208  				ctx.handleErrorf(elts[0].Pos(), "inconsistent matrix column count: got %v, want %v", n, ncol)
   209  			}
   210  			for _, elt := range elts {
   211  				compileExpr(ctx, elt)
   212  			}
   213  			cb.SliceLitEx(...)
   214  		}
   215  	}
   216  }
   217  */
   218  
   219  func compileEnvExpr(ctx *blockCtx, v *ast.EnvExpr) {
   220  	cb := ctx.cb
   221  	if ctx.isClass { // in a Go+ class file
   222  		if recv := classRecv(cb); recv != nil {
   223  			if gopMember(cb, recv, "Gop_Env", v) == nil {
   224  				name := v.Name
   225  				cb.Val(name.Name, name).CallWith(1, 0, v)
   226  				return
   227  			}
   228  		}
   229  	}
   230  	invalidVal(cb)
   231  	ctx.handleErrorf(v.Pos(), "operator $%v undefined", v.Name)
   232  }
   233  
   234  func classRecv(cb *gogen.CodeBuilder) *types.Var {
   235  	if fn := cb.Func(); fn != nil {
   236  		sig := fn.Ancestor().Type().(*types.Signature)
   237  		return sig.Recv()
   238  	}
   239  	return nil
   240  }
   241  
   242  func gopMember(cb *gogen.CodeBuilder, recv *types.Var, op string, src ...ast.Node) error {
   243  	_, e := cb.Val(recv).Member(op, gogen.MemberFlagVal, src...)
   244  	return e
   245  }
   246  
   247  func isBuiltin(o types.Object) bool {
   248  	if _, ok := o.(*types.Builtin); ok {
   249  		return ok
   250  	}
   251  	return false
   252  }
   253  
   254  func compileMember(ctx *blockCtx, v ast.Node, name string, flags int) error {
   255  	var mflag gogen.MemberFlag
   256  	switch {
   257  	case (flags & clIdentLHS) != 0:
   258  		mflag = gogen.MemberFlagRef
   259  	case (flags & clIdentCanAutoCall) != 0:
   260  		mflag = gogen.MemberFlagAutoProperty
   261  	default:
   262  		mflag = gogen.MemberFlagMethodAlias
   263  	}
   264  	_, err := ctx.cb.Member(name, mflag, v)
   265  	return err
   266  }
   267  
   268  func compileExprLHS(ctx *blockCtx, expr ast.Expr) {
   269  	switch v := expr.(type) {
   270  	case *ast.Ident:
   271  		compileIdent(ctx, v, clIdentLHS)
   272  	case *ast.IndexExpr:
   273  		compileIndexExprLHS(ctx, v)
   274  	case *ast.SelectorExpr:
   275  		compileSelectorExprLHS(ctx, v)
   276  	case *ast.StarExpr:
   277  		compileStarExprLHS(ctx, v)
   278  	default:
   279  		panic(ctx.newCodeErrorf(v.Pos(), "compileExprLHS failed: unknown - %T", expr))
   280  	}
   281  	if rec := ctx.recorder(); rec != nil {
   282  		rec.recordExpr(ctx, expr, true)
   283  	}
   284  }
   285  
   286  func twoValue(inFlags []int) bool {
   287  	return inFlags != nil && (inFlags[0]&clCallWithTwoValue) != 0
   288  }
   289  
   290  func identOrSelectorFlags(inFlags []int) (flags int, cmdNoArgs bool) {
   291  	if inFlags == nil {
   292  		return clIdentCanAutoCall, false
   293  	}
   294  	flags = inFlags[0]
   295  	if cmdNoArgs = (flags & clCommandWithoutArgs) != 0; cmdNoArgs {
   296  		flags &^= clCommandWithoutArgs
   297  	} else {
   298  		flags |= clIdentCanAutoCall
   299  	}
   300  	return
   301  }
   302  
   303  func callCmdNoArgs(ctx *blockCtx, src ast.Node, panicErr bool) (err error) {
   304  	if gogen.IsFunc(ctx.cb.InternalStack().Get(-1).Type) {
   305  		if err = ctx.cb.CallWithEx(0, 0, src); err != nil {
   306  			if panicErr {
   307  				panic(err)
   308  			}
   309  		}
   310  	}
   311  	return
   312  }
   313  
   314  func compileExpr(ctx *blockCtx, expr ast.Expr, inFlags ...int) {
   315  	switch v := expr.(type) {
   316  	case *ast.Ident:
   317  		flags, cmdNoArgs := identOrSelectorFlags(inFlags)
   318  		if cmdNoArgs {
   319  			flags |= clCommandIdent // for support Gop_Exec, see TestSpxGopExec
   320  		}
   321  		_, kind := compileIdent(ctx, v, flags)
   322  		if cmdNoArgs || kind == objGopExecOrEnv {
   323  			cb := ctx.cb
   324  			if kind == objGopExecOrEnv {
   325  				cb.Val(v.Name, v)
   326  			} else {
   327  				err := callCmdNoArgs(ctx, expr, false)
   328  				if err == nil {
   329  					return
   330  				}
   331  				if !(ctx.isClass && tryGopExec(cb, v)) {
   332  					panic(err)
   333  				}
   334  			}
   335  			cb.CallWith(1, 0, v)
   336  		}
   337  	case *ast.BasicLit:
   338  		compileBasicLit(ctx, v)
   339  	case *ast.CallExpr:
   340  		flags := 0
   341  		if inFlags != nil {
   342  			flags = inFlags[0]
   343  		}
   344  		compileCallExpr(ctx, v, flags)
   345  	case *ast.SelectorExpr:
   346  		flags, cmdNoArgs := identOrSelectorFlags(inFlags)
   347  		compileSelectorExpr(ctx, v, flags)
   348  		if cmdNoArgs {
   349  			callCmdNoArgs(ctx, expr, true)
   350  			return
   351  		}
   352  	case *ast.BinaryExpr:
   353  		compileBinaryExpr(ctx, v)
   354  	case *ast.UnaryExpr:
   355  		compileUnaryExpr(ctx, v, twoValue(inFlags))
   356  	case *ast.FuncLit:
   357  		compileFuncLit(ctx, v)
   358  	case *ast.CompositeLit:
   359  		compileCompositeLit(ctx, v, nil, false)
   360  	case *ast.SliceLit:
   361  		compileSliceLit(ctx, v, nil)
   362  	case *ast.RangeExpr:
   363  		compileRangeExpr(ctx, v)
   364  	case *ast.IndexExpr:
   365  		compileIndexExpr(ctx, v, twoValue(inFlags))
   366  	case *ast.IndexListExpr:
   367  		compileIndexListExpr(ctx, v, twoValue(inFlags))
   368  	case *ast.SliceExpr:
   369  		compileSliceExpr(ctx, v)
   370  	case *ast.StarExpr:
   371  		compileStarExpr(ctx, v)
   372  	case *ast.ArrayType:
   373  		ctx.cb.Typ(toArrayType(ctx, v), v)
   374  	case *ast.MapType:
   375  		ctx.cb.Typ(toMapType(ctx, v), v)
   376  	case *ast.StructType:
   377  		ctx.cb.Typ(toStructType(ctx, v), v)
   378  	case *ast.ChanType:
   379  		ctx.cb.Typ(toChanType(ctx, v), v)
   380  	case *ast.InterfaceType:
   381  		ctx.cb.Typ(toInterfaceType(ctx, v), v)
   382  	case *ast.ComprehensionExpr:
   383  		compileComprehensionExpr(ctx, v, twoValue(inFlags))
   384  	case *ast.TypeAssertExpr:
   385  		compileTypeAssertExpr(ctx, v, twoValue(inFlags))
   386  	case *ast.ParenExpr:
   387  		compileExpr(ctx, v.X, inFlags...)
   388  	case *ast.ErrWrapExpr:
   389  		compileErrWrapExpr(ctx, v, 0)
   390  	case *ast.FuncType:
   391  		ctx.cb.Typ(toFuncType(ctx, v, nil, nil), v)
   392  	case *ast.EnvExpr:
   393  		compileEnvExpr(ctx, v)
   394  	/* case *ast.MatrixLit:
   395  	compileMatrixLit(ctx, v) */
   396  	default:
   397  		panic(ctx.newCodeErrorf(v.Pos(), "compileExpr failed: unknown - %T", v))
   398  	}
   399  	if rec := ctx.recorder(); rec != nil {
   400  		rec.recordExpr(ctx, expr, false)
   401  	}
   402  }
   403  
   404  func compileExprOrNone(ctx *blockCtx, expr ast.Expr) {
   405  	if expr != nil {
   406  		compileExpr(ctx, expr)
   407  	} else {
   408  		ctx.cb.None()
   409  	}
   410  }
   411  
   412  func compileUnaryExpr(ctx *blockCtx, v *ast.UnaryExpr, twoValue bool) {
   413  	compileExpr(ctx, v.X)
   414  	ctx.cb.UnaryOp(gotoken.Token(v.Op), twoValue, v)
   415  }
   416  
   417  func compileBinaryExpr(ctx *blockCtx, v *ast.BinaryExpr) {
   418  	compileExpr(ctx, v.X)
   419  	compileExpr(ctx, v.Y)
   420  	ctx.cb.BinaryOp(gotoken.Token(v.Op), v)
   421  }
   422  
   423  func compileIndexExprLHS(ctx *blockCtx, v *ast.IndexExpr) {
   424  	compileExpr(ctx, v.X)
   425  	compileExpr(ctx, v.Index)
   426  	ctx.cb.IndexRef(1, v)
   427  }
   428  
   429  func compileStarExprLHS(ctx *blockCtx, v *ast.StarExpr) { // *x = ...
   430  	compileExpr(ctx, v.X)
   431  	ctx.cb.ElemRef()
   432  }
   433  
   434  func compileStarExpr(ctx *blockCtx, v *ast.StarExpr) { // ... = *x
   435  	compileExpr(ctx, v.X)
   436  	ctx.cb.Star()
   437  }
   438  
   439  func compileTypeAssertExpr(ctx *blockCtx, v *ast.TypeAssertExpr, twoValue bool) {
   440  	compileExpr(ctx, v.X)
   441  	if v.Type == nil {
   442  		panic("TODO: x.(type) is only used in type switch")
   443  	}
   444  	typ := toType(ctx, v.Type)
   445  	ctx.cb.TypeAssert(typ, twoValue, v)
   446  }
   447  
   448  func compileIndexExpr(ctx *blockCtx, v *ast.IndexExpr, twoValue bool) { // x[i]
   449  	compileExpr(ctx, v.X)
   450  	compileExpr(ctx, v.Index)
   451  	ctx.cb.Index(1, twoValue, v)
   452  }
   453  
   454  func compileIndexListExpr(ctx *blockCtx, v *ast.IndexListExpr, twoValue bool) { // fn[t1,t2]
   455  	compileExpr(ctx, v.X)
   456  	n := len(v.Indices)
   457  	for i := 0; i < n; i++ {
   458  		compileExpr(ctx, v.Indices[i])
   459  	}
   460  	ctx.cb.Index(n, twoValue, v)
   461  }
   462  
   463  func compileSliceExpr(ctx *blockCtx, v *ast.SliceExpr) { // x[i:j:k]
   464  	compileExpr(ctx, v.X)
   465  	compileExprOrNone(ctx, v.Low)
   466  	compileExprOrNone(ctx, v.High)
   467  	if v.Slice3 {
   468  		compileExprOrNone(ctx, v.Max)
   469  	}
   470  	ctx.cb.Slice(v.Slice3, v)
   471  }
   472  
   473  func compileSelectorExprLHS(ctx *blockCtx, v *ast.SelectorExpr) {
   474  	switch x := v.X.(type) {
   475  	case *ast.Ident:
   476  		if at, kind := compileIdent(ctx, x, clIdentLHS|clIdentSelectorExpr); kind != objNormal {
   477  			ctx.cb.VarRef(at.Ref(v.Sel.Name))
   478  			return
   479  		}
   480  	default:
   481  		compileExpr(ctx, v.X)
   482  	}
   483  	ctx.cb.MemberRef(v.Sel.Name, v)
   484  }
   485  
   486  func compileSelectorExpr(ctx *blockCtx, v *ast.SelectorExpr, flags int) {
   487  	switch x := v.X.(type) {
   488  	case *ast.Ident:
   489  		if at, kind := compileIdent(ctx, x, flags|clIdentCanAutoCall|clIdentSelectorExpr); kind != objNormal {
   490  			if compilePkgRef(ctx, at, v.Sel, flags, kind) {
   491  				return
   492  			}
   493  			if token.IsExported(v.Sel.Name) {
   494  				panic(ctx.newCodeErrorf(x.Pos(), "undefined: %s.%s", x.Name, v.Sel.Name))
   495  			}
   496  			panic(ctx.newCodeErrorf(x.Pos(), "cannot refer to unexported name %s.%s", x.Name, v.Sel.Name))
   497  		}
   498  	default:
   499  		compileExpr(ctx, v.X)
   500  	}
   501  	if err := compileMember(ctx, v, v.Sel.Name, flags); err != nil {
   502  		panic(err)
   503  	}
   504  }
   505  
   506  func compileFuncAlias(ctx *blockCtx, scope *types.Scope, x *ast.Ident, flags int) bool {
   507  	name := x.Name
   508  	if c := name[0]; c >= 'a' && c <= 'z' {
   509  		name = string(rune(c)+('A'-'a')) + name[1:]
   510  		o := scope.Lookup(name)
   511  		if o == nil && ctx.loadSymbol(name) {
   512  			o = scope.Lookup(name)
   513  		}
   514  		if o != nil {
   515  			return identVal(ctx, x, flags, o, true)
   516  		}
   517  	}
   518  	return false
   519  }
   520  
   521  func pkgRef(at gogen.PkgRef, name string) (o types.Object, alias bool) {
   522  	if c := name[0]; c >= 'a' && c <= 'z' {
   523  		name = string(rune(c)+('A'-'a')) + name[1:]
   524  		if v := at.TryRef(name); v != nil && gogen.IsFunc(v.Type()) {
   525  			return v, true
   526  		}
   527  		return
   528  	}
   529  	return at.TryRef(name), false
   530  }
   531  
   532  // allow pkg.Types to be nil
   533  func lookupPkgRef(ctx *blockCtx, pkg gogen.PkgRef, x *ast.Ident, pkgKind int) (o types.Object, alias bool) {
   534  	if pkg.Types != nil {
   535  		return pkgRef(pkg, x.Name)
   536  	}
   537  	if pkgKind == objPkgRef {
   538  		for _, at := range ctx.lookups {
   539  			if o2, alias2 := pkgRef(at, x.Name); o2 != nil {
   540  				if o != nil {
   541  					panic(ctx.newCodeErrorf(
   542  						x.Pos(), "confliction: %s declared both in \"%s\" and \"%s\"",
   543  						x.Name, at.Types.Path(), pkg.Types.Path()))
   544  				}
   545  				pkg, o, alias = at, o2, alias2
   546  			}
   547  		}
   548  	} else {
   549  		var cpkg cpackages.PkgRef
   550  		for _, at := range ctx.clookups {
   551  			if o2 := at.Lookup(x.Name); o2 != nil {
   552  				if o != nil {
   553  					panic(ctx.newCodeErrorf(
   554  						x.Pos(), "confliction: %s declared both in \"%s\" and \"%s\"",
   555  						x.Name, at.Pkg().Types.Path(), cpkg.Pkg().Types.Path()))
   556  				}
   557  				cpkg, o = at, o2
   558  			}
   559  		}
   560  	}
   561  	return
   562  }
   563  
   564  // allow at.Types to be nil
   565  func compilePkgRef(ctx *blockCtx, at gogen.PkgRef, x *ast.Ident, flags, pkgKind int) bool {
   566  	if v, alias := lookupPkgRef(ctx, at, x, pkgKind); v != nil {
   567  		if (flags & clIdentLHS) != 0 {
   568  			if rec := ctx.recorder(); rec != nil {
   569  				rec.Use(x, v)
   570  			}
   571  			ctx.cb.VarRef(v, x)
   572  			return true
   573  		}
   574  		return identVal(ctx, x, flags, v, alias)
   575  	}
   576  	return false
   577  }
   578  
   579  func identVal(ctx *blockCtx, x *ast.Ident, flags int, v types.Object, alias bool) bool {
   580  	autocall := false
   581  	if alias {
   582  		if autocall = (flags & clIdentCanAutoCall) != 0; autocall {
   583  			if !gogen.HasAutoProperty(v.Type()) {
   584  				return false
   585  			}
   586  		}
   587  	}
   588  	if rec := ctx.recorder(); rec != nil {
   589  		rec.Use(x, v)
   590  	}
   591  	cb := ctx.cb.Val(v, x)
   592  	if autocall {
   593  		cb.CallWith(0, 0, x)
   594  	}
   595  	return true
   596  }
   597  
   598  type fnType struct {
   599  	next      *fnType
   600  	params    *types.Tuple
   601  	sig       *types.Signature
   602  	base      int
   603  	size      int
   604  	variadic  bool
   605  	typetype  bool
   606  	typeparam bool
   607  }
   608  
   609  func (p *fnType) arg(i int, ellipsis bool) types.Type {
   610  	if i+p.base < p.size {
   611  		return p.params.At(i + p.base).Type()
   612  	}
   613  	if p.variadic {
   614  		t := p.params.At(p.size).Type()
   615  		if ellipsis {
   616  			return t
   617  		}
   618  		return t.(*types.Slice).Elem()
   619  	}
   620  	return nil
   621  }
   622  
   623  func (p *fnType) init(base int, t *types.Signature) {
   624  	p.base = base
   625  	p.sig = t
   626  	p.params, p.variadic, p.typeparam = t.Params(), t.Variadic(), t.TypeParams() != nil
   627  	p.size = p.params.Len()
   628  	if p.variadic {
   629  		p.size--
   630  	}
   631  }
   632  
   633  func (p *fnType) initTypeType(t *gogen.TypeType) {
   634  	param := types.NewParam(0, nil, "", t.Type())
   635  	p.params, p.typetype = types.NewTuple(param), true
   636  	p.size = 1
   637  }
   638  
   639  func (p *fnType) load(fnt types.Type) {
   640  	switch v := fnt.(type) {
   641  	case *gogen.TypeType:
   642  		p.initTypeType(v)
   643  	case *types.Signature:
   644  		typ, objs := gogen.CheckSigFuncExObjects(v)
   645  		switch typ.(type) {
   646  		case *gogen.TyOverloadFunc, *gogen.TyOverloadMethod:
   647  			p.initFuncs(0, objs)
   648  			return
   649  		case *gogen.TyTemplateRecvMethod:
   650  			p.initFuncs(1, objs)
   651  			return
   652  		}
   653  		p.init(0, v)
   654  	}
   655  }
   656  
   657  func (p *fnType) initFuncs(base int, funcs []types.Object) {
   658  	for i, obj := range funcs {
   659  		if sig, ok := obj.Type().(*types.Signature); ok {
   660  			if i == 0 {
   661  				p.init(base, sig)
   662  			} else {
   663  				fn := &fnType{}
   664  				fn.init(base, sig)
   665  				p.next = fn
   666  				p = p.next
   667  			}
   668  		}
   669  	}
   670  }
   671  
   672  func compileCallExpr(ctx *blockCtx, v *ast.CallExpr, inFlags int) {
   673  	var ifn *ast.Ident
   674  	switch fn := v.Fun.(type) {
   675  	case *ast.Ident:
   676  		if v.IsCommand() { // for support Gop_Exec, see TestSpxGopExec
   677  			inFlags |= clCommandIdent
   678  		}
   679  		if _, kind := compileIdent(ctx, fn, clIdentAllowBuiltin|inFlags); kind == objGopExec {
   680  			args := make([]ast.Expr, 1, len(v.Args)+1)
   681  			args[0] = toBasicLit(fn)
   682  			args = append(args, v.Args...)
   683  			v = &ast.CallExpr{Fun: fn, Args: args, Ellipsis: v.Ellipsis, NoParenEnd: v.NoParenEnd}
   684  		} else {
   685  			ifn = fn
   686  		}
   687  	case *ast.SelectorExpr:
   688  		compileSelectorExpr(ctx, fn, 0)
   689  	case *ast.ErrWrapExpr:
   690  		if v.IsCommand() {
   691  			callExpr := *v
   692  			callExpr.Fun = fn.X
   693  			ewExpr := *fn
   694  			ewExpr.X = &callExpr
   695  			compileErrWrapExpr(ctx, &ewExpr, inFlags)
   696  			return
   697  		}
   698  		compileErrWrapExpr(ctx, fn, 0)
   699  	default:
   700  		compileExpr(ctx, fn)
   701  	}
   702  	var err error
   703  	var stk = ctx.cb.InternalStack()
   704  	var base = stk.Len()
   705  	var flags gogen.InstrFlags
   706  	var ellipsis = v.Ellipsis != gotoken.NoPos
   707  	if ellipsis {
   708  		flags = gogen.InstrFlagEllipsis
   709  	}
   710  	if (inFlags & clCallWithTwoValue) != 0 {
   711  		flags |= gogen.InstrFlagTwoValue
   712  	}
   713  	pfn := stk.Get(-1)
   714  	fnt := pfn.Type
   715  	fn := &fnType{}
   716  	fn.load(fnt)
   717  	for fn != nil {
   718  		if err = compileCallArgs(ctx, pfn, fn, v, ellipsis, flags); err == nil {
   719  			if rec := ctx.recorder(); rec != nil {
   720  				rec.recordCallExpr(ctx, v, fnt)
   721  			}
   722  			return
   723  		}
   724  		stk.SetLen(base)
   725  		fn = fn.next
   726  	}
   727  	if ifn != nil && builtinOrGopExec(ctx, ifn, v, flags) == nil {
   728  		return
   729  	}
   730  	panic(err)
   731  }
   732  
   733  func toBasicLit(fn *ast.Ident) *ast.BasicLit {
   734  	return &ast.BasicLit{ValuePos: fn.NamePos, Kind: token.STRING, Value: strconv.Quote(fn.Name)}
   735  }
   736  
   737  // maybe builtin new/delete: see TestSpxNewObj, TestMayBuiltinDelete
   738  // maybe Gop_Exec: see TestSpxGopExec
   739  func builtinOrGopExec(ctx *blockCtx, ifn *ast.Ident, v *ast.CallExpr, flags gogen.InstrFlags) error {
   740  	cb := ctx.cb
   741  	switch name := ifn.Name; name {
   742  	case "new", "delete":
   743  		cb.InternalStack().PopN(1)
   744  		cb.Val(ctx.pkg.Builtin().Ref(name), ifn)
   745  		return fnCall(ctx, v, flags, 0)
   746  	default:
   747  		// for support Gop_Exec, see TestSpxGopExec
   748  		if v.IsCommand() && ctx.isClass && tryGopExec(cb, ifn) {
   749  			return fnCall(ctx, v, flags, 1)
   750  		}
   751  	}
   752  	return syscall.ENOENT
   753  }
   754  
   755  func tryGopExec(cb *gogen.CodeBuilder, ifn *ast.Ident) bool {
   756  	if recv := classRecv(cb); recv != nil {
   757  		cb.InternalStack().PopN(1)
   758  		if gopMember(cb, recv, "Gop_Exec", ifn) == nil {
   759  			cb.Val(ifn.Name, ifn)
   760  			return true
   761  		}
   762  	}
   763  	return false
   764  }
   765  
   766  func fnCall(ctx *blockCtx, v *ast.CallExpr, flags gogen.InstrFlags, extra int) error {
   767  	for _, arg := range v.Args {
   768  		compileExpr(ctx, arg)
   769  	}
   770  	return ctx.cb.CallWithEx(len(v.Args)+extra, flags, v)
   771  }
   772  
   773  func compileCallArgs(ctx *blockCtx, pfn *gogen.Element, fn *fnType, v *ast.CallExpr, ellipsis bool, flags gogen.InstrFlags) (err error) {
   774  	var needInferFunc bool
   775  	for i, arg := range v.Args {
   776  		switch expr := arg.(type) {
   777  		case *ast.LambdaExpr:
   778  			if fn.typeparam {
   779  				needInferFunc = true
   780  				compileIdent(ctx, ast.NewIdent("nil"), 0)
   781  				continue
   782  			}
   783  			sig, e := checkLambdaFuncType(ctx, expr, fn.arg(i, ellipsis), clLambaArgument, v.Fun)
   784  			if e != nil {
   785  				return e
   786  			}
   787  			if err = compileLambdaExpr(ctx, expr, sig); err != nil {
   788  				return
   789  			}
   790  		case *ast.LambdaExpr2:
   791  			if fn.typeparam {
   792  				needInferFunc = true
   793  				compileIdent(ctx, ast.NewIdent("nil"), 0)
   794  				continue
   795  			}
   796  			sig, e := checkLambdaFuncType(ctx, expr, fn.arg(i, ellipsis), clLambaArgument, v.Fun)
   797  			if e != nil {
   798  				return e
   799  			}
   800  			if err = compileLambdaExpr2(ctx, expr, sig); err != nil {
   801  				return
   802  			}
   803  		case *ast.CompositeLit:
   804  			if err = compileCompositeLitEx(ctx, expr, fn.arg(i, ellipsis), true); err != nil {
   805  				return
   806  			}
   807  		case *ast.SliceLit:
   808  			t := fn.arg(i, ellipsis)
   809  			switch t.(type) {
   810  			case *types.Slice:
   811  			case *types.Named:
   812  				if _, ok := getUnderlying(ctx, t).(*types.Slice); !ok {
   813  					t = nil
   814  				}
   815  			default:
   816  				t = nil
   817  			}
   818  			typetype := fn.typetype && t != nil
   819  			if typetype {
   820  				ctx.cb.InternalStack().PopN(1)
   821  			}
   822  			if err = compileSliceLit(ctx, expr, t, true); err != nil {
   823  				return
   824  			}
   825  			if typetype {
   826  				return
   827  			}
   828  		default:
   829  			compileExpr(ctx, arg)
   830  		}
   831  	}
   832  	if needInferFunc {
   833  		typ, err := gogen.InferFunc(ctx.pkg, pfn, fn.sig, nil, ctx.cb.InternalStack().GetArgs(len(v.Args)), flags)
   834  		if err != nil {
   835  			return err
   836  		}
   837  		next := &fnType{}
   838  		next.init(fn.base, typ.(*types.Signature))
   839  		next.next = fn.next
   840  		fn.next = next
   841  		return errCallNext
   842  	}
   843  	return ctx.cb.CallWithEx(len(v.Args), flags, v)
   844  }
   845  
   846  var (
   847  	errCallNext = errors.New("call next")
   848  )
   849  
   850  type clLambaFlag string
   851  
   852  const (
   853  	clLambaAssign   clLambaFlag = "assignment"
   854  	clLambaField    clLambaFlag = "field value"
   855  	clLambaArgument clLambaFlag = "argument"
   856  )
   857  
   858  // check lambda func type
   859  func checkLambdaFuncType(ctx *blockCtx, lambda ast.Expr, ftyp types.Type, flag clLambaFlag, toNode ast.Node) (*types.Signature, error) {
   860  	typ := ftyp
   861  retry:
   862  	switch t := typ.(type) {
   863  	case *types.Signature:
   864  		if l, ok := lambda.(*ast.LambdaExpr); ok {
   865  			if len(l.Rhs) != t.Results().Len() {
   866  				break
   867  			}
   868  		}
   869  		return t, nil
   870  	case *types.Named:
   871  		typ = t.Underlying()
   872  		goto retry
   873  	}
   874  	src := ctx.LoadExpr(toNode)
   875  	return nil, ctx.newCodeErrorf(lambda.Pos(), "cannot use lambda literal as type %v in %v to %v", ftyp, flag, src)
   876  }
   877  
   878  func compileLambda(ctx *blockCtx, lambda ast.Expr, sig *types.Signature) {
   879  	switch expr := lambda.(type) {
   880  	case *ast.LambdaExpr:
   881  		if err := compileLambdaExpr(ctx, expr, sig); err != nil {
   882  			panic(err)
   883  		}
   884  	case *ast.LambdaExpr2:
   885  		if err := compileLambdaExpr2(ctx, expr, sig); err != nil {
   886  			panic(err)
   887  		}
   888  	}
   889  }
   890  
   891  func makeLambdaParams(ctx *blockCtx, pos token.Pos, lhs []*ast.Ident, in *types.Tuple) (*types.Tuple, error) {
   892  	pkg := ctx.pkg
   893  	n := len(lhs)
   894  	if nin := in.Len(); n != nin {
   895  		fewOrMany := "few"
   896  		if n > nin {
   897  			fewOrMany = "many"
   898  		}
   899  		has := make([]string, n)
   900  		for i, v := range lhs {
   901  			has[i] = v.Name
   902  		}
   903  		return nil, ctx.newCodeErrorf(
   904  			pos, "too %s arguments in lambda expression\n\thave (%s)\n\twant %v", fewOrMany, strings.Join(has, ", "), in)
   905  	}
   906  	if n == 0 {
   907  		return nil, nil
   908  	}
   909  	params := make([]*types.Var, n)
   910  	for i, name := range lhs {
   911  		param := pkg.NewParam(name.Pos(), name.Name, in.At(i).Type())
   912  		params[i] = param
   913  		if rec := ctx.recorder(); rec != nil {
   914  			rec.Def(name, param)
   915  		}
   916  	}
   917  	return types.NewTuple(params...), nil
   918  }
   919  
   920  func makeLambdaResults(pkg *gogen.Package, out *types.Tuple) *types.Tuple {
   921  	nout := out.Len()
   922  	if nout == 0 {
   923  		return nil
   924  	}
   925  	results := make([]*types.Var, nout)
   926  	for i := 0; i < nout; i++ {
   927  		results[i] = pkg.NewParam(token.NoPos, "", out.At(i).Type())
   928  	}
   929  	return types.NewTuple(results...)
   930  }
   931  
   932  func compileLambdaExpr(ctx *blockCtx, v *ast.LambdaExpr, sig *types.Signature) error {
   933  	pkg := ctx.pkg
   934  	params, err := makeLambdaParams(ctx, v.Pos(), v.Lhs, sig.Params())
   935  	if err != nil {
   936  		return err
   937  	}
   938  	results := makeLambdaResults(pkg, sig.Results())
   939  	ctx.cb.NewClosure(params, results, false).BodyStart(pkg)
   940  	if len(v.Lhs) > 0 {
   941  		defNames(ctx, v.Lhs, ctx.cb.Scope())
   942  	}
   943  	for _, v := range v.Rhs {
   944  		compileExpr(ctx, v)
   945  	}
   946  	if rec := ctx.recorder(); rec != nil {
   947  		rec.Scope(v, ctx.cb.Scope())
   948  	}
   949  	ctx.cb.Return(len(v.Rhs)).End(v)
   950  	return nil
   951  }
   952  
   953  func compileLambdaExpr2(ctx *blockCtx, v *ast.LambdaExpr2, sig *types.Signature) error {
   954  	pkg := ctx.pkg
   955  	params, err := makeLambdaParams(ctx, v.Pos(), v.Lhs, sig.Params())
   956  	if err != nil {
   957  		return err
   958  	}
   959  	results := makeLambdaResults(pkg, sig.Results())
   960  	comments, once := ctx.cb.BackupComments()
   961  	fn := ctx.cb.NewClosure(params, results, false)
   962  	cb := fn.BodyStart(ctx.pkg, v.Body)
   963  	if len(v.Lhs) > 0 {
   964  		defNames(ctx, v.Lhs, cb.Scope())
   965  	}
   966  	compileStmts(ctx, v.Body.List)
   967  	if rec := ctx.recorder(); rec != nil {
   968  		rec.Scope(v, ctx.cb.Scope())
   969  	}
   970  	cb.End(v)
   971  	ctx.cb.SetComments(comments, once)
   972  	return nil
   973  }
   974  
   975  func compileFuncLit(ctx *blockCtx, v *ast.FuncLit) {
   976  	cb := ctx.cb
   977  	comments, once := cb.BackupComments()
   978  	sig := toFuncType(ctx, v.Type, nil, nil)
   979  	if rec := ctx.recorder(); rec != nil {
   980  		rec.recordFuncLit(v, sig)
   981  	}
   982  	fn := cb.NewClosureWith(sig)
   983  	if body := v.Body; body != nil {
   984  		loadFuncBody(ctx, fn, body, nil, v)
   985  		cb.SetComments(comments, once)
   986  	}
   987  }
   988  
   989  func compileBasicLit(ctx *blockCtx, v *ast.BasicLit) {
   990  	cb := ctx.cb
   991  	switch v.Kind {
   992  	case token.RAT:
   993  		val := v.Value
   994  		bi, _ := new(big.Int).SetString(val[:len(val)-1], 10) // remove r suffix
   995  		cb.UntypedBigInt(bi, v)
   996  	case token.CSTRING:
   997  		s, err := strconv.Unquote(v.Value)
   998  		if err != nil {
   999  			log.Panicln("compileBasicLit:", err)
  1000  		}
  1001  		n := len(s)
  1002  		tyInt8 := types.Typ[types.Int8]
  1003  		typ := types.NewArray(tyInt8, int64(n+1))
  1004  		cb.Typ(types.NewPointer(tyInt8)).Typ(types.Typ[types.UnsafePointer])
  1005  		for i := 0; i < n; i++ {
  1006  			cb.Val(rune(s[i]))
  1007  		}
  1008  		cb.Val(rune(0)).ArrayLit(typ, n+1).UnaryOp(gotoken.AND).Call(1).Call(1)
  1009  	default:
  1010  		if v.Extra == nil {
  1011  			basicLit(cb, v)
  1012  			return
  1013  		}
  1014  		compileStringLitEx(ctx, cb, v)
  1015  	}
  1016  }
  1017  
  1018  func invalidVal(cb *gogen.CodeBuilder) {
  1019  	cb.Val(&gogen.Element{Type: types.Typ[types.Invalid]})
  1020  }
  1021  
  1022  func basicLit(cb *gogen.CodeBuilder, v *ast.BasicLit) {
  1023  	cb.Val(&goast.BasicLit{Kind: gotoken.Token(v.Kind), Value: v.Value}, v)
  1024  }
  1025  
  1026  const (
  1027  	stringutilPkgPath = "github.com/qiniu/x/stringutil"
  1028  )
  1029  
  1030  func compileStringLitEx(ctx *blockCtx, cb *gogen.CodeBuilder, lit *ast.BasicLit) {
  1031  	pos := lit.ValuePos + 1
  1032  	quote := lit.Value[:1]
  1033  	parts := lit.Extra.Parts
  1034  	n := len(parts)
  1035  	if n != 1 {
  1036  		cb.Val(ctx.pkg.Import(stringutilPkgPath).Ref("Concat"))
  1037  	}
  1038  	for _, part := range parts {
  1039  		switch v := part.(type) {
  1040  		case string: // normal string literal or end with "$$"
  1041  			next := pos + token.Pos(len(v))
  1042  			if strings.HasSuffix(v, "$$") {
  1043  				v = v[:len(v)-1]
  1044  			}
  1045  			basicLit(cb, &ast.BasicLit{ValuePos: pos - 1, Value: quote + v + quote, Kind: token.STRING})
  1046  			pos = next
  1047  		case ast.Expr:
  1048  			flags := 0
  1049  			if _, ok := v.(*ast.Ident); ok {
  1050  				flags = clIdentInStringLitEx
  1051  			}
  1052  			compileExpr(ctx, v, flags)
  1053  			t := cb.Get(-1).Type
  1054  			if t.Underlying() != types.Typ[types.String] {
  1055  				if _, err := cb.Member("string", gogen.MemberFlagAutoProperty); err != nil {
  1056  					if e, ok := err.(*gogen.CodeError); ok {
  1057  						err = ctx.newCodeErrorf(v.Pos(), "%s.string%s", ctx.LoadExpr(v), e.Msg)
  1058  					}
  1059  					ctx.handleErr(err)
  1060  				}
  1061  			}
  1062  			pos = v.End()
  1063  		default:
  1064  			panic("compileStringLitEx TODO: unexpected part")
  1065  		}
  1066  	}
  1067  	if n != 1 {
  1068  		cb.CallWith(n, 0, lit)
  1069  	}
  1070  }
  1071  
  1072  const (
  1073  	compositeLitVal    = 0
  1074  	compositeLitKeyVal = 1
  1075  )
  1076  
  1077  func checkCompositeLitElts(elts []ast.Expr) (kind int) {
  1078  	for _, elt := range elts {
  1079  		if _, ok := elt.(*ast.KeyValueExpr); ok {
  1080  			return compositeLitKeyVal
  1081  		}
  1082  	}
  1083  	return compositeLitVal
  1084  }
  1085  
  1086  func compileCompositeLitElts(ctx *blockCtx, elts []ast.Expr, kind int, expected *kvType) {
  1087  	for _, elt := range elts {
  1088  		if kv, ok := elt.(*ast.KeyValueExpr); ok {
  1089  			if key, ok := kv.Key.(*ast.CompositeLit); ok && key.Type == nil {
  1090  				compileCompositeLit(ctx, key, expected.Key(), false)
  1091  			} else {
  1092  				compileExpr(ctx, kv.Key)
  1093  			}
  1094  			if val, ok := kv.Value.(*ast.CompositeLit); ok && val.Type == nil {
  1095  				compileCompositeLit(ctx, val, expected.Elem(), false)
  1096  			} else {
  1097  				compileExpr(ctx, kv.Value)
  1098  			}
  1099  		} else {
  1100  			if kind == compositeLitKeyVal {
  1101  				ctx.cb.None()
  1102  			}
  1103  			if val, ok := elt.(*ast.CompositeLit); ok && val.Type == nil {
  1104  				compileCompositeLit(ctx, val, expected.Elem(), false)
  1105  			} else {
  1106  				compileExpr(ctx, elt)
  1107  			}
  1108  		}
  1109  	}
  1110  }
  1111  
  1112  func compileStructLitInKeyVal(ctx *blockCtx, elts []ast.Expr, t *types.Struct, typ types.Type, src *ast.CompositeLit) error {
  1113  	for _, elt := range elts {
  1114  		kv := elt.(*ast.KeyValueExpr)
  1115  		name := kv.Key.(*ast.Ident)
  1116  		idx := lookupField(t, name.Name)
  1117  		if idx >= 0 {
  1118  			ctx.cb.Val(idx)
  1119  		} else {
  1120  			src := ctx.LoadExpr(name)
  1121  			return ctx.newCodeErrorf(name.Pos(), "%s undefined (type %v has no field or method %s)", src, typ, name.Name)
  1122  		}
  1123  		if rec := ctx.recorder(); rec != nil {
  1124  			rec.Use(name, t.Field(idx))
  1125  		}
  1126  		switch expr := kv.Value.(type) {
  1127  		case *ast.LambdaExpr, *ast.LambdaExpr2:
  1128  			sig, err := checkLambdaFuncType(ctx, expr, t.Field(idx).Type(), clLambaField, kv.Key)
  1129  			if err != nil {
  1130  				return err
  1131  			}
  1132  			compileLambda(ctx, expr, sig)
  1133  		default:
  1134  			compileExpr(ctx, kv.Value)
  1135  		}
  1136  	}
  1137  	ctx.cb.StructLit(typ, len(elts)<<1, true, src)
  1138  	return nil
  1139  }
  1140  
  1141  func lookupField(t *types.Struct, name string) int {
  1142  	for i, n := 0, t.NumFields(); i < n; i++ {
  1143  		if fld := t.Field(i); fld.Name() == name {
  1144  			return i
  1145  		}
  1146  	}
  1147  	return -1
  1148  }
  1149  
  1150  type kvType struct {
  1151  	underlying types.Type
  1152  	key, val   types.Type
  1153  	cached     bool
  1154  }
  1155  
  1156  func (p *kvType) required() *kvType {
  1157  	if !p.cached {
  1158  		p.cached = true
  1159  		switch t := p.underlying.(type) {
  1160  		case *types.Slice:
  1161  			p.key, p.val = types.Typ[types.Int], t.Elem()
  1162  		case *types.Array:
  1163  			p.key, p.val = types.Typ[types.Int], t.Elem()
  1164  		case *types.Map:
  1165  			p.key, p.val = t.Key(), t.Elem()
  1166  		}
  1167  	}
  1168  	return p
  1169  }
  1170  
  1171  func (p *kvType) Key() types.Type {
  1172  	return p.required().key
  1173  }
  1174  
  1175  func (p *kvType) Elem() types.Type {
  1176  	return p.required().val
  1177  }
  1178  
  1179  func getUnderlying(ctx *blockCtx, typ types.Type) types.Type {
  1180  	u := typ.Underlying()
  1181  	if u == nil {
  1182  		if t, ok := typ.(*types.Named); ok {
  1183  			ctx.loadNamed(ctx.pkg, t)
  1184  			u = t.Underlying()
  1185  		}
  1186  	}
  1187  	return u
  1188  }
  1189  
  1190  func compileCompositeLit(ctx *blockCtx, v *ast.CompositeLit, expected types.Type, mapOrStructOnly bool) {
  1191  	if err := compileCompositeLitEx(ctx, v, expected, mapOrStructOnly); err != nil {
  1192  		panic(err)
  1193  	}
  1194  }
  1195  
  1196  // mapOrStructOnly means only map/struct can omit type
  1197  func compileCompositeLitEx(ctx *blockCtx, v *ast.CompositeLit, expected types.Type, mapOrStructOnly bool) error {
  1198  	var hasPtr bool
  1199  	var typ, underlying types.Type
  1200  	var kind = checkCompositeLitElts(v.Elts)
  1201  	if v.Type != nil {
  1202  		typ = toType(ctx, v.Type)
  1203  		underlying = getUnderlying(ctx, typ)
  1204  	} else if expected != nil {
  1205  		if t, ok := expected.(*types.Pointer); ok {
  1206  			telem := t.Elem()
  1207  			tu := getUnderlying(ctx, telem)
  1208  			if _, ok := tu.(*types.Struct); ok { // struct pointer
  1209  				typ, underlying, hasPtr = telem, tu, true
  1210  			}
  1211  		} else if tu := getUnderlying(ctx, expected); !mapOrStructOnly || isMapOrStruct(tu) {
  1212  			typ, underlying = expected, tu
  1213  		}
  1214  	}
  1215  	if t, ok := underlying.(*types.Struct); ok && kind == compositeLitKeyVal {
  1216  		if err := compileStructLitInKeyVal(ctx, v.Elts, t, typ, v); err != nil {
  1217  			return err
  1218  		}
  1219  	} else {
  1220  		compileCompositeLitElts(ctx, v.Elts, kind, &kvType{underlying: underlying})
  1221  		n := len(v.Elts)
  1222  		if isMap(underlying) {
  1223  			if kind == compositeLitVal && n > 0 {
  1224  				return ctx.newCodeError(v.Pos(), "missing key in map literal")
  1225  			}
  1226  			if err := ctx.cb.MapLitEx(typ, n<<1, v); err != nil {
  1227  				return err
  1228  			}
  1229  		} else {
  1230  			switch underlying.(type) {
  1231  			case *types.Slice:
  1232  				ctx.cb.SliceLitEx(typ, n<<kind, kind == compositeLitKeyVal, v)
  1233  			case *types.Array:
  1234  				ctx.cb.ArrayLitEx(typ, n<<kind, kind == compositeLitKeyVal, v)
  1235  			case *types.Struct:
  1236  				ctx.cb.StructLit(typ, n, false, v) // key-val mode handled by compileStructLitInKeyVal
  1237  			default:
  1238  				return ctx.newCodeErrorf(v.Pos(), "invalid composite literal type %v", typ)
  1239  			}
  1240  		}
  1241  	}
  1242  	if hasPtr {
  1243  		ctx.cb.UnaryOp(gotoken.AND)
  1244  		typ = expected
  1245  	}
  1246  	if rec := ctx.recorder(); rec != nil {
  1247  		rec.recordCompositeLit(v, typ)
  1248  	}
  1249  	return nil
  1250  }
  1251  
  1252  func isMap(tu types.Type) bool {
  1253  	if tu == nil { // map can omit type
  1254  		return true
  1255  	}
  1256  	_, ok := tu.(*types.Map)
  1257  	return ok
  1258  }
  1259  
  1260  func isMapOrStruct(tu types.Type) bool {
  1261  	switch tu.(type) {
  1262  	case *types.Struct:
  1263  		return true
  1264  	case *types.Map:
  1265  		return true
  1266  	}
  1267  	return false
  1268  }
  1269  
  1270  func compileSliceLit(ctx *blockCtx, v *ast.SliceLit, typ types.Type, noPanic ...bool) (err error) {
  1271  	if noPanic != nil {
  1272  		defer func() {
  1273  			if e := recover(); e != nil { // TODO: don't use defer to capture error
  1274  				err = ctx.recoverErr(e, v)
  1275  			}
  1276  		}()
  1277  	}
  1278  	n := len(v.Elts)
  1279  	for _, elt := range v.Elts {
  1280  		compileExpr(ctx, elt)
  1281  	}
  1282  	if sliceHasTypeParam(ctx, typ) {
  1283  		ctx.cb.SliceLitEx(nil, n, false, v)
  1284  	} else {
  1285  		ctx.cb.SliceLitEx(typ, n, false, v)
  1286  	}
  1287  	return
  1288  }
  1289  
  1290  func compileRangeExpr(ctx *blockCtx, v *ast.RangeExpr) {
  1291  	pkg, cb := ctx.pkg, ctx.cb
  1292  	cb.Val(pkg.Builtin().Ref("newRange"))
  1293  	if v.First == nil {
  1294  		ctx.cb.Val(0, v)
  1295  	} else {
  1296  		compileExpr(ctx, v.First)
  1297  	}
  1298  	compileExpr(ctx, v.Last)
  1299  	if v.Expr3 == nil {
  1300  		ctx.cb.Val(1, v)
  1301  	} else {
  1302  		compileExpr(ctx, v.Expr3)
  1303  	}
  1304  	cb.Call(3)
  1305  }
  1306  
  1307  const (
  1308  	comprehensionInvalid = iota
  1309  	comprehensionList
  1310  	comprehensionMap
  1311  	comprehensionSelect
  1312  )
  1313  
  1314  func comprehensionKind(v *ast.ComprehensionExpr) int {
  1315  	switch v.Tok {
  1316  	case token.LBRACK: // [
  1317  		return comprehensionList
  1318  	case token.LBRACE: // {
  1319  		if _, ok := v.Elt.(*ast.KeyValueExpr); ok {
  1320  			return comprehensionMap
  1321  		}
  1322  		return comprehensionSelect
  1323  	}
  1324  	panic("TODO: invalid comprehensionExpr")
  1325  }
  1326  
  1327  // [expr for k, v <- container, cond]
  1328  // {for k, v <- container, cond}
  1329  // {expr for k, v <- container, cond}
  1330  // {kexpr: vexpr for k, v <- container, cond}
  1331  func compileComprehensionExpr(ctx *blockCtx, v *ast.ComprehensionExpr, twoValue bool) {
  1332  	kind := comprehensionKind(v)
  1333  	pkg, cb := ctx.pkg, ctx.cb
  1334  	var results *types.Tuple
  1335  	var ret *gogen.Param
  1336  	if v.Elt == nil {
  1337  		boolean := pkg.NewParam(token.NoPos, "_gop_ok", types.Typ[types.Bool])
  1338  		results = types.NewTuple(boolean)
  1339  	} else {
  1340  		ret = pkg.NewAutoParam("_gop_ret")
  1341  		if kind == comprehensionSelect && twoValue {
  1342  			boolean := pkg.NewParam(token.NoPos, "_gop_ok", types.Typ[types.Bool])
  1343  			results = types.NewTuple(ret, boolean)
  1344  		} else {
  1345  			results = types.NewTuple(ret)
  1346  		}
  1347  	}
  1348  	cb.NewClosure(nil, results, false).BodyStart(pkg)
  1349  	if kind == comprehensionMap {
  1350  		cb.VarRef(ret).ZeroLit(ret.Type()).Assign(1)
  1351  	}
  1352  	end := 0
  1353  	for i := len(v.Fors) - 1; i >= 0; i-- {
  1354  		names := make([]string, 0, 2)
  1355  		defineNames := make([]*ast.Ident, 0, 2)
  1356  		forStmt := v.Fors[i]
  1357  		if forStmt.Key != nil {
  1358  			names = append(names, forStmt.Key.Name)
  1359  			defineNames = append(defineNames, forStmt.Key)
  1360  		} else {
  1361  			names = append(names, "_")
  1362  		}
  1363  		names = append(names, forStmt.Value.Name)
  1364  		defineNames = append(defineNames, forStmt.Value)
  1365  		cb.ForRange(names...)
  1366  		compileExpr(ctx, forStmt.X)
  1367  		cb.RangeAssignThen(forStmt.TokPos)
  1368  		defNames(ctx, defineNames, cb.Scope())
  1369  		if rec := ctx.recorder(); rec != nil {
  1370  			rec.Scope(forStmt, cb.Scope())
  1371  		}
  1372  		if forStmt.Cond != nil {
  1373  			cb.If()
  1374  			if forStmt.Init != nil {
  1375  				compileStmt(ctx, forStmt.Init)
  1376  			}
  1377  			compileExpr(ctx, forStmt.Cond)
  1378  			cb.Then()
  1379  			end++
  1380  		}
  1381  		end++
  1382  	}
  1383  	switch kind {
  1384  	case comprehensionList:
  1385  		// _gop_ret = append(_gop_ret, elt)
  1386  		cb.VarRef(ret)
  1387  		cb.Val(pkg.Builtin().Ref("append"))
  1388  		cb.Val(ret)
  1389  		compileExpr(ctx, v.Elt)
  1390  		cb.Call(2).Assign(1)
  1391  	case comprehensionMap:
  1392  		// _gop_ret[key] = val
  1393  		cb.Val(ret)
  1394  		kv := v.Elt.(*ast.KeyValueExpr)
  1395  		compileExpr(ctx, kv.Key)
  1396  		cb.IndexRef(1)
  1397  		compileExpr(ctx, kv.Value)
  1398  		cb.Assign(1)
  1399  	default:
  1400  		if v.Elt == nil {
  1401  			// return true
  1402  			cb.Val(true)
  1403  			cb.Return(1)
  1404  		} else {
  1405  			// return elt, true
  1406  			compileExpr(ctx, v.Elt)
  1407  			n := 1
  1408  			if twoValue {
  1409  				cb.Val(true)
  1410  				n++
  1411  			}
  1412  			cb.Return(n)
  1413  		}
  1414  	}
  1415  	for i := 0; i < end; i++ {
  1416  		cb.End()
  1417  	}
  1418  	cb.Return(0).End().Call(0)
  1419  }
  1420  
  1421  const (
  1422  	errorPkgPath = "github.com/qiniu/x/errors"
  1423  )
  1424  
  1425  var (
  1426  	tyError = types.Universe.Lookup("error").Type()
  1427  )
  1428  
  1429  func compileErrWrapExpr(ctx *blockCtx, v *ast.ErrWrapExpr, inFlags int) {
  1430  	pkg, cb := ctx.pkg, ctx.cb
  1431  	useClosure := v.Tok == token.NOT || v.Default != nil
  1432  	if !useClosure && (cb.Scope().Parent() == types.Universe) {
  1433  		panic("TODO: can't use expr? in global")
  1434  	}
  1435  
  1436  	compileExpr(ctx, v.X, inFlags)
  1437  	x := cb.InternalStack().Pop()
  1438  	n := 0
  1439  	results, ok := x.Type.(*types.Tuple)
  1440  	if ok {
  1441  		n = results.Len() - 1
  1442  	}
  1443  
  1444  	var ret []*types.Var
  1445  	if n > 0 {
  1446  		i, retName := 0, "_gop_ret"
  1447  		ret = make([]*gogen.Param, n)
  1448  		for {
  1449  			ret[i] = pkg.NewAutoParam(retName)
  1450  			i++
  1451  			if i >= n {
  1452  				break
  1453  			}
  1454  			retName = "_gop_ret" + strconv.Itoa(i+1)
  1455  		}
  1456  	}
  1457  	sig := types.NewSignatureType(nil, nil, nil, nil, types.NewTuple(ret...), false)
  1458  	if useClosure {
  1459  		cb.NewClosureWith(sig).BodyStart(pkg)
  1460  	} else {
  1461  		cb.CallInlineClosureStart(sig, 0, false)
  1462  	}
  1463  
  1464  	cb.NewVar(tyError, "_gop_err")
  1465  	err := cb.Scope().Lookup("_gop_err")
  1466  
  1467  	for _, retVar := range ret {
  1468  		cb.VarRef(retVar)
  1469  	}
  1470  	cb.VarRef(err)
  1471  	cb.InternalStack().Push(x)
  1472  	cb.Assign(n+1, 1)
  1473  
  1474  	cb.If().Val(err).CompareNil(gotoken.NEQ).Then()
  1475  	if v.Default == nil {
  1476  		pos := pkg.Fset.Position(v.Pos())
  1477  		currentFunc := ctx.cb.Func().Ancestor()
  1478  		const newFrameArgs = 5
  1479  
  1480  		currentFuncName := currentFunc.Name()
  1481  		if currentFuncName == "" {
  1482  			currentFuncName = "main"
  1483  		}
  1484  
  1485  		currentFuncName = strings.Join([]string{currentFunc.Pkg().Name(), currentFuncName}, ".")
  1486  
  1487  		cb.
  1488  			VarRef(err).
  1489  			Val(pkg.Import(errorPkgPath).Ref("NewFrame")).
  1490  			Val(err).
  1491  			Val(sprintAst(pkg.Fset, v.X)).
  1492  			Val(relFile(ctx.relBaseDir, pos.Filename)).
  1493  			Val(pos.Line).
  1494  			Val(currentFuncName).
  1495  			Call(newFrameArgs).
  1496  			Assign(1)
  1497  	}
  1498  
  1499  	if v.Tok == token.NOT { // expr!
  1500  		cb.Val(pkg.Builtin().Ref("panic")).Val(err).Call(1).EndStmt()
  1501  	} else if v.Default == nil { // expr?
  1502  		cb.Val(err).ReturnErr(true)
  1503  	} else { // expr?:val
  1504  		compileExpr(ctx, v.Default)
  1505  		cb.Return(1)
  1506  	}
  1507  	cb.End().Return(0).End()
  1508  	if useClosure {
  1509  		cb.Call(0)
  1510  	}
  1511  }
  1512  
  1513  func sprintAst(fset *token.FileSet, x ast.Node) string {
  1514  	var buf bytes.Buffer
  1515  	err := printer.Fprint(&buf, fset, x)
  1516  	if err != nil {
  1517  		panic("Unexpected error: " + err.Error())
  1518  	}
  1519  
  1520  	return buf.String()
  1521  }
  1522  
  1523  // -----------------------------------------------------------------------------