func hasError(sig *types.Signature) bool { res := sig.Results() if res == nil || res.Len() <= 0 { return false } nerr := 0 for i := 0; i < res.Len(); i++ { ret := res.At(i) if isErrorType(ret.Type()) { nerr++ } } switch { case nerr == 0: return false case nerr == 1: return true default: panic(fmt.Errorf( "gopy: invalid number of comma-errors (%d)", nerr, )) } return false }
// FuncHasQuery returns the offset of the string parameter named "query", or // none if no such parameter exists. func FuncHasQuery(s *types.Signature) (offset int, ok bool) { params := s.Params() for i := 0; i < params.Len(); i++ { v := params.At(i) if v.Name() == "query" && v.Type() == stringType { return i, true } } return 0, false }
// formatIndex returns the index of the format string parameter within // a signature. If it cannot find any format string parameter, it // returns -1. func formatIndex(sig *types.Signature) int { if sig == nil { return -1 } idx := -1 for i := 0; i < sig.Params().Len(); i++ { p := sig.Params().At(i) if typ, ok := p.Type().(*types.Basic); ok && typ.Kind() == types.String { idx = i } } return idx }
// writeSignature writes to buf the signature sig in declaration syntax. func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *types.Signature, params []*Parameter) { buf.WriteString("func ") if recv := sig.Recv(); recv != nil { buf.WriteString("(") if n := params[0].Name(); n != "" { buf.WriteString(n) buf.WriteString(" ") } types.WriteType(buf, params[0].Type(), types.RelativeTo(from)) buf.WriteString(") ") } buf.WriteString(name) types.WriteSignature(buf, sig, types.RelativeTo(from)) }
func (p *exporter) signature(sig *types.Signature) { // We need the receiver information (T vs *T) // for methods associated with named types. // We do not record interface receiver types in the // export data because 1) the importer can derive them // from the interface type and 2) they create cycles // in the type graph. if recv := sig.Recv(); recv != nil { if _, ok := recv.Type().Underlying().(*types.Interface); !ok { // 1-element tuple p.int(1) p.param(recv) } else { // 0-element tuple p.int(0) } } else { // 0-element tuple p.int(0) } p.tuple(sig.Params()) p.tuple(sig.Results()) if sig.Variadic() { p.int(1) } else { p.int(0) } }
func isImplementable(sig *types.Signature) bool { params := sig.Params() for i := 0; i < params.Len(); i++ { if !isExported(params.At(i).Type()) { return false } } res := sig.Results() for i := 0; i < res.Len(); i++ { if !isExported(res.At(i).Type()) { return false } } return true }
func (c *funcContext) translateCall(e *ast.CallExpr, sig *types.Signature, fun *expression) *expression { args := c.translateArgs(sig, e.Args, e.Ellipsis.IsValid(), false) if c.Blocking[e] { resumeCase := c.caseCounter c.caseCounter++ returnVar := "$r" if sig.Results().Len() != 0 { returnVar = c.newVariable("_r") } c.Printf("%[1]s = %[2]s(%[3]s); /* */ $s = %[4]d; case %[4]d: if($c) { $c = false; %[1]s = %[1]s.$blk(); } if (%[1]s && %[1]s.$blk !== undefined) { break s; }", returnVar, fun, strings.Join(args, ", "), resumeCase) if sig.Results().Len() != 0 { return c.formatExpr("%s", returnVar) } return c.formatExpr("") } return c.formatExpr("%s(%s)", fun, strings.Join(args, ", ")) }
func (c *funcContext) translateArgs(sig *types.Signature, argExprs []ast.Expr, ellipsis, clone bool) []string { if len(argExprs) == 1 { if tuple, isTuple := c.p.TypeOf(argExprs[0]).(*types.Tuple); isTuple { tupleVar := c.newVariable("_tuple") c.Printf("%s = %s;", tupleVar, c.translateExpr(argExprs[0])) argExprs = make([]ast.Expr, tuple.Len()) for i := range argExprs { argExprs[i] = c.newIdent(c.formatExpr("%s[%d]", tupleVar, i).String(), tuple.At(i).Type()) } } } paramsLen := sig.Params().Len() var varargType *types.Slice if sig.Variadic() && !ellipsis { varargType = sig.Params().At(paramsLen - 1).Type().(*types.Slice) } preserveOrder := false for i := 1; i < len(argExprs); i++ { preserveOrder = preserveOrder || c.Blocking[argExprs[i]] } args := make([]string, len(argExprs)) for i, argExpr := range argExprs { var argType types.Type switch { case varargType != nil && i >= paramsLen-1: argType = varargType.Elem() default: argType = sig.Params().At(i).Type() } var arg string switch { case clone: arg = c.translateImplicitConversionWithCloning(argExpr, argType).String() default: arg = c.translateImplicitConversion(argExpr, argType).String() } if preserveOrder && c.p.Types[argExpr].Value == nil { argVar := c.newVariable("_arg") c.Printf("%s = %s;", argVar, arg) arg = argVar } args[i] = arg } if varargType != nil { return append(args[:paramsLen-1], fmt.Sprintf("new %s([%s])", c.typeName(varargType), strings.Join(args[paramsLen-1:], ", "))) } return args }
func newFuncFrom(p *Package, parent string, obj types.Object, sig *types.Signature) (Func, error) { haserr := false res := sig.Results() var ret types.Type switch res.Len() { case 2: if !isErrorType(res.At(1).Type()) { return Func{}, fmt.Errorf( "bind: second result value must be of type error: %s", obj, ) } haserr = true ret = res.At(0).Type() case 1: if isErrorType(res.At(0).Type()) { haserr = true ret = nil } else { ret = res.At(0).Type() } case 0: ret = nil default: return Func{}, fmt.Errorf("bind: too many results to return: %v", obj) } id := obj.Pkg().Name() + "_" + obj.Name() if parent != "" { id = obj.Pkg().Name() + "_" + parent + "_" + obj.Name() } return Func{ pkg: p, sig: newSignatureFrom(p, sig), typ: obj.Type(), name: obj.Name(), id: id, doc: p.getDoc(parent, obj), ret: ret, err: haserr, }, nil }
func newSignatureFrom(pkg *Package, sig *types.Signature) *Signature { var recv *Var if sig.Recv() != nil { recv = newVarFrom(pkg, sig.Recv()) } return &Signature{ ret: newVarsFrom(pkg, sig.Results()), args: newVarsFrom(pkg, sig.Params()), recv: recv, } }
func (c *converter) convertSignature(v *gotypes.Signature) *types.Signature { if v == nil { return nil } if v, ok := c.converted[v]; ok { return v.(*types.Signature) } ret := types.NewSignature( c.convertParamVar(v.Recv()), c.convertTuple(v.Params(), c.convertParamVar), c.convertTuple(v.Results(), c.convertParamVar), v.Variadic(), ) c.converted[v] = ret return ret }
func (w *Walker) writeSignature(buf *bytes.Buffer, sig *types.Signature) { w.writeParams(buf, sig.Params(), sig.Variadic()) switch res := sig.Results(); res.Len() { case 0: // nothing to do case 1: buf.WriteByte(' ') w.writeType(buf, res.At(0).Type()) default: buf.WriteByte(' ') w.writeParams(buf, res, false) } }
// sigParamsCompatible determines if the parameter parts of two signatures of functions are compatible. // They are compatible if: // - The number of parameters equal and the types of parameters are compatible for each of them. // - The latter parameters have exactly one extra parameter which is a variadic parameter. func sigParamsCompatible(s1, s2 *types.Signature) bool { extra := tuplesCompatibleExtra(s1.Params(), s2.Params(), cmpLower) switch { case extra == nil: // s2 params is incompatible with s1 params return false case len(extra) == 0: // s2 params is compatible with s1 params return true case len(extra) == 1: // s2 params is compatible with s1 params with an extra variadic arg if s1.Variadic() == false && s2.Variadic() == true { return true } } return false }
func sigResultsCompatible(s1, s2 *types.Signature) bool { if s1.Results().Len() == 0 { return true } extra := tuplesCompatibleExtra(s1.Results(), s2.Results(), cmpUpper) switch { case extra == nil: return false case len(extra) == 0: return true } return false }
func (p *printer) writeSignatureInternal(this *types.Package, sig *types.Signature, visited []types.Type) { p.writeTuple(this, sig.Params(), sig.Variadic(), visited) res := sig.Results() n := res.Len() if n == 0 { // no result return } p.print(" ") if n == 1 && res.At(0).Name() == "" { // single unnamed result p.writeTypeInternal(this, res.At(0).Type(), visited) return } // multiple or named result(s) p.writeTuple(this, res, false, visited) }
func changeRecv(s *types.Signature, recv *types.Var) *types.Signature { return types.NewSignature(recv, s.Params(), s.Results(), s.Variadic()) }
func (c *funcContext) translateBuiltin(name string, sig *types.Signature, args []ast.Expr, ellipsis bool) *expression { switch name { case "new": t := sig.Results().At(0).Type().(*types.Pointer) if c.p.Pkg.Path() == "syscall" && types.Identical(t.Elem().Underlying(), types.Typ[types.Uintptr]) { return c.formatExpr("new Uint8Array(8)") } switch t.Elem().Underlying().(type) { case *types.Struct, *types.Array: return c.formatExpr("%e", c.zeroValue(t.Elem())) default: return c.formatExpr("$newDataPointer(%e, %s)", c.zeroValue(t.Elem()), c.typeName(t)) } case "make": switch argType := c.p.TypeOf(args[0]).Underlying().(type) { case *types.Slice: t := c.typeName(c.p.TypeOf(args[0])) if len(args) == 3 { return c.formatExpr("$makeSlice(%s, %f, %f)", t, args[1], args[2]) } return c.formatExpr("$makeSlice(%s, %f)", t, args[1]) case *types.Map: if len(args) == 2 && c.p.Types[args[1]].Value == nil { return c.formatExpr(`((%1f < 0 || %1f > 2147483647) ? $throwRuntimeError("makemap: size out of range") : {})`, args[1]) } return c.formatExpr("{}") case *types.Chan: length := "0" if len(args) == 2 { length = c.formatExpr("%f", args[1]).String() } return c.formatExpr("new $Chan(%s, %s)", c.typeName(c.p.TypeOf(args[0]).Underlying().(*types.Chan).Elem()), length) default: panic(fmt.Sprintf("Unhandled make type: %T\n", argType)) } case "len": switch argType := c.p.TypeOf(args[0]).Underlying().(type) { case *types.Basic: return c.formatExpr("%e.length", args[0]) case *types.Slice: return c.formatExpr("%e.$length", args[0]) case *types.Pointer: return c.formatExpr("(%e, %d)", args[0], argType.Elem().(*types.Array).Len()) case *types.Map: return c.formatExpr("$keys(%e).length", args[0]) case *types.Chan: return c.formatExpr("%e.$buffer.length", args[0]) // length of array is constant default: panic(fmt.Sprintf("Unhandled len type: %T\n", argType)) } case "cap": switch argType := c.p.TypeOf(args[0]).Underlying().(type) { case *types.Slice, *types.Chan: return c.formatExpr("%e.$capacity", args[0]) case *types.Pointer: return c.formatExpr("(%e, %d)", args[0], argType.Elem().(*types.Array).Len()) // capacity of array is constant default: panic(fmt.Sprintf("Unhandled cap type: %T\n", argType)) } case "panic": return c.formatExpr("$panic(%s)", c.translateImplicitConversion(args[0], types.NewInterface(nil, nil))) case "append": if ellipsis || len(args) == 1 { argStr := c.translateArgs(sig, args, ellipsis, false) return c.formatExpr("$appendSlice(%s, %s)", argStr[0], argStr[1]) } sliceType := sig.Results().At(0).Type().Underlying().(*types.Slice) return c.formatExpr("$append(%e, %s)", args[0], strings.Join(c.translateExprSlice(args[1:], sliceType.Elem()), ", ")) case "delete": keyType := c.p.TypeOf(args[0]).Underlying().(*types.Map).Key() return c.formatExpr(`delete %e[%s.keyFor(%s)]`, args[0], c.typeName(keyType), c.translateImplicitConversion(args[1], keyType)) case "copy": if basic, isBasic := c.p.TypeOf(args[1]).Underlying().(*types.Basic); isBasic && isString(basic) { return c.formatExpr("$copyString(%e, %e)", args[0], args[1]) } return c.formatExpr("$copySlice(%e, %e)", args[0], args[1]) case "print", "println": return c.formatExpr("console.log(%s)", strings.Join(c.translateExprSlice(args, nil), ", ")) case "complex": argStr := c.translateArgs(sig, args, ellipsis, false) return c.formatExpr("new %s(%s, %s)", c.typeName(sig.Results().At(0).Type()), argStr[0], argStr[1]) case "real": return c.formatExpr("%e.$real", args[0]) case "imag": return c.formatExpr("%e.$imag", args[0]) case "recover": return c.formatExpr("$recover()") case "close": return c.formatExpr(`$close(%e)`, args[0]) default: panic(fmt.Sprintf("Unhandled builtin: %s\n", name)) } }
func (f *Finder) call(sig *types.Signature, args []ast.Expr) { if len(args) == 0 { return } // Ellipsis call? e.g. f(x, y, z...) if _, ok := args[len(args)-1].(*ast.Ellipsis); ok { for i, arg := range args { // The final arg is a slice, and so is the final param. f.assign(sig.Params().At(i).Type(), f.expr(arg)) } return } var argtypes []types.Type // Gather the effective actual parameter types. if tuple, ok := f.info.Types[args[0]].Type.(*types.Tuple); ok { // f(g()) call where g has multiple results? f.expr(args[0]) // unpack the tuple for i := 0; i < tuple.Len(); i++ { argtypes = append(argtypes, tuple.At(i).Type()) } } else { for _, arg := range args { argtypes = append(argtypes, f.expr(arg)) } } // Assign the actuals to the formals. if !sig.Variadic() { for i, argtype := range argtypes { f.assign(sig.Params().At(i).Type(), argtype) } } else { // The first n-1 parameters are assigned normally. nnormals := sig.Params().Len() - 1 for i, argtype := range argtypes[:nnormals] { f.assign(sig.Params().At(i).Type(), argtype) } // Remaining args are assigned to elements of varargs slice. tElem := sig.Params().At(nnormals).Type().(*types.Slice).Elem() for i := nnormals; i < len(argtypes); i++ { f.assign(tElem, argtypes[i]) } } }
func (b *Builder) convertSignature(u types.Universe, t *tc.Signature) *types.Signature { signature := &types.Signature{} for i := 0; i < t.Params().Len(); i++ { signature.Parameters = append(signature.Parameters, b.walkType(u, nil, t.Params().At(i).Type())) } for i := 0; i < t.Results().Len(); i++ { signature.Results = append(signature.Results, b.walkType(u, nil, t.Results().At(i).Type())) } if r := t.Recv(); r != nil { signature.Receiver = b.walkType(u, nil, r.Type()) } signature.Variadic = t.Variadic() return signature }
// lostCancelPath finds a path through the CFG, from stmt (which defines // the 'cancel' variable v) to a return statement, that doesn't "use" v. // If it finds one, it returns the return statement (which may be synthetic). // sig is the function's type, if known. func lostCancelPath(f *File, g *cfg.CFG, v *types.Var, stmt ast.Node, sig *types.Signature) *ast.ReturnStmt { vIsNamedResult := sig != nil && tupleContains(sig.Results(), v) // uses reports whether stmts contain a "use" of variable v. uses := func(f *File, v *types.Var, stmts []ast.Node) bool { found := false for _, stmt := range stmts { ast.Inspect(stmt, func(n ast.Node) bool { switch n := n.(type) { case *ast.Ident: if f.pkg.uses[n] == v { found = true } case *ast.ReturnStmt: // A naked return statement counts as a use // of the named result variables. if n.Results == nil && vIsNamedResult { found = true } } return !found }) } return found } // blockUses computes "uses" for each block, caching the result. memo := make(map[*cfg.Block]bool) blockUses := func(f *File, v *types.Var, b *cfg.Block) bool { res, ok := memo[b] if !ok { res = uses(f, v, b.Nodes) memo[b] = res } return res } // Find the var's defining block in the CFG, // plus the rest of the statements of that block. var defblock *cfg.Block var rest []ast.Node outer: for _, b := range g.Blocks { for i, n := range b.Nodes { if n == stmt { defblock = b rest = b.Nodes[i+1:] break outer } } } if defblock == nil { panic("internal error: can't find defining block for cancel var") } // Is v "used" in the remainder of its defining block? if uses(f, v, rest) { return nil } // Does the defining block return without using v? if ret := defblock.Return(); ret != nil { return ret } // Search the CFG depth-first for a path, from defblock to a // return block, in which v is never "used". seen := make(map[*cfg.Block]bool) var search func(blocks []*cfg.Block) *ast.ReturnStmt search = func(blocks []*cfg.Block) *ast.ReturnStmt { for _, b := range blocks { if !seen[b] { seen[b] = true // Prune the search if the block uses v. if blockUses(f, v, b) { continue } // Found path to return statement? if ret := b.Return(); ret != nil { if debugLostCancel { fmt.Printf("found path to return in block %s\n", b) } return ret // found } // Recur if ret := search(b.Succs); ret != nil { if debugLostCancel { fmt.Printf(" from block %s\n", b) } return ret } } } return nil } return search(defblock.Succs) }