Esempio n. 1
0
func (c *compiler) evalCallArgs(ftype *types.Signature, args []ast.Expr) []Value {
	var argValues []Value
	if len(args) == 0 {
		return argValues
	}
	arg0 := args[0]
	if _, ok := c.types.expr[arg0].Type.(*types.Tuple); ok {
		// f(g(...)), where g is multi-value return
		argValues = c.destructureExpr(args[0])
	} else {
		argValues = make([]Value, len(args))
		for i, x := range args {
			var paramtyp types.Type
			params := ftype.Params()
			if ftype.IsVariadic() && i >= int(params.Len()-1) {
				paramtyp = params.At(int(params.Len() - 1)).Type()
			} else {
				paramtyp = params.At(i).Type()
			}
			c.convertUntyped(x, paramtyp)
			argValues[i] = c.VisitExpr(x)
		}
	}
	return argValues
}
Esempio n. 2
0
File: decl.go Progetto: qioixiy/llgo
func (c *compiler) makeFunc(ident *ast.Ident, ftyp *types.Signature) *LLVMValue {
	fname := ident.String()
	if ftyp.Recv() == nil && fname == "init" {
		// Make "init" functions anonymous.
		fname = ""
	} else {
		var pkgname string
		if recv := ftyp.Recv(); recv != nil {
			var recvname string
			switch recvtyp := recv.Type().(type) {
			case *types.Pointer:
				if named, ok := recvtyp.Elem().(*types.Named); ok {
					obj := named.Obj()
					recvname = "*" + obj.Name()
					pkgname = obj.Pkg().Path()
				}
			case *types.Named:
				named := recvtyp
				obj := named.Obj()
				recvname = obj.Name()
				pkgname = obj.Pkg().Path()
			}

			if recvname != "" {
				fname = fmt.Sprintf("%s.%s", recvname, fname)
			} else {
				// If the receiver is an unnamed struct, we're
				// synthesising a method for an unnamed struct
				// type. There's no meaningful name to give the
				// function, so leave it up to LLVM.
				fname = ""
			}
		} else {
			obj := c.typeinfo.Objects[ident]
			pkgname = obj.Pkg().Path()
		}
		if fname != "" {
			fname = pkgname + "." + fname
		}
	}

	// gcimporter may produce multiple AST objects for the same function.
	llvmftyp := c.types.ToLLVM(ftyp)
	var fn llvm.Value
	if fname != "" {
		fn = c.module.Module.NamedFunction(fname)
	}
	if fn.IsNil() {
		llvmfptrtyp := llvmftyp.StructElementTypes()[0].ElementType()
		fn = llvm.AddFunction(c.module.Module, fname, llvmfptrtyp)
	}
	fn = llvm.ConstInsertValue(llvm.ConstNull(llvmftyp), fn, []uint32{0})
	return c.NewValue(fn, ftyp)
}
Esempio n. 3
0
// writeSignature writes to buf the signature sig in declaration syntax.
func writeSignature(buf *bytes.Buffer, pkg *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(" ")
		}
		buf.WriteString(relType(params[0].Type(), pkg))
		buf.WriteString(") ")
	}
	buf.WriteString(name)
	types.WriteSignature(buf, pkg, sig)
}
Esempio n. 4
0
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)
	}
}
Esempio n. 5
0
func (tm *TypeMap) funcRuntimeType(f *types.Signature) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(f, reflect.Func)
	funcType := llvm.ConstNull(tm.runtimeFuncType)
	funcType = llvm.ConstInsertValue(funcType, rtype, []uint32{0})
	// dotdotdot
	if f.IsVariadic() {
		variadic := llvm.ConstInt(llvm.Int1Type(), 1, false)
		funcType = llvm.ConstInsertValue(funcType, variadic, []uint32{1})
	}
	// TODO in
	//funcType = llvm.ConstInsertValue(funcType, tm.ToRuntime(p.Elt()), []uint32{2})
	// TODO out
	//funcType = llvm.ConstInsertValue(funcType, tm.ToRuntime(p.Elt()), []uint32{3})
	return tm.makeRuntimeTypeGlobal(funcType)
}
Esempio n. 6
0
// changeRecv returns sig with Recv prepended to Params().
func changeRecv(sig *types.Signature) *types.Signature {
	params := sig.Params()
	n := params.Len()
	p2 := make([]*types.Var, n+1)
	p2[0] = sig.Recv()
	for i := 0; i < n; i++ {
		p2[i+1] = params.At(i)
	}
	return types.NewSignature(nil, nil, types.NewTuple(p2...), sig.Results(), sig.IsVariadic())
}
Esempio n. 7
0
func (c *compiler) evalCallArgs(ftype *types.Signature, args []ast.Expr, dotdotdot bool) []Value {
	var argValues []Value
	if len(args) == 0 {
		return argValues
	}

	var argtypes []types.Type
	if t, ok := c.typeinfo.Types[args[0]].(*types.Tuple); ok {
		argtypes = make([]types.Type, t.Len())
	} else {
		argtypes = make([]types.Type, len(args))
	}

	params := ftype.Params()
	for i := range argtypes {
		if ftype.IsVariadic() && i >= int(params.Len()-1) {
			argtypes[i] = params.At(int(params.Len() - 1)).Type()
			argtypes[i] = argtypes[i].(*types.Slice).Elem()
		} else {
			argtypes[i] = params.At(i).Type()
		}
	}

	if len(argtypes) > len(args) {
		// f(g(...)), where g is multi-value return
		argValues = c.destructureExpr(args[0])
	} else {
		argValues = make([]Value, len(args))
		for i, x := range args {
			c.convertUntyped(x, argtypes[i])
			argValues[i] = c.VisitExpr(x)
		}
	}

	for i, v := range argValues {
		if !dotdotdot || i < int(params.Len()-1) {
			argValues[i] = v.Convert(argtypes[i])
		}
	}
	return argValues
}
Esempio n. 8
0
func (cdd *CDD) signature(sig *types.Signature, recv bool, pnames int) (res results, params string) {
	params = "("
	res = cdd.results(sig.Results())
	if r := sig.Recv(); r != nil && recv {
		typ, dim, acds := cdd.TypeStr(r.Type())
		res.acds = append(res.acds, acds...)
		var pname string
		switch pnames {
		case numNames:
			pname = "_0"
		case orgNames:
			pname = cdd.NameStr(r, true)
		}
		if pname == "" {
			params += typ + dimFuncPtr("", dim)
		} else {
			params += typ + " " + dimFuncPtr(pname, dim)
		}
		if sig.Params() != nil {
			params += ", "
		}
	}
	if p := sig.Params(); p != nil {
		for i, n := 0, p.Len(); i < n; i++ {
			if i != 0 {
				params += ", "
			}
			v := p.At(i)
			typ, dim, acds := cdd.TypeStr(v.Type())
			res.acds = append(res.acds, acds...)
			var pname string
			switch pnames {
			case numNames:
				pname = "_" + strconv.Itoa(i+1)
			case orgNames:
				pname = cdd.NameStr(v, true)
				if pname == "_$" {
					pname = "unused" + cdd.gtc.uniqueId()
				}
			}
			if pname == "" {
				params += typ + dimFuncPtr("", dim)
			} else {
				params += typ + " " + dimFuncPtr(pname, dim)
			}
		}
	}
	params += ")"
	return
}
Esempio n. 9
0
func (c *funcContext) translateArgs(sig *types.Signature, args []ast.Expr, ellipsis bool) []string {
	params := make([]string, sig.Params().Len())
	for i := range params {
		if sig.Variadic() && i == len(params)-1 && !ellipsis {
			varargType := sig.Params().At(i).Type().(*types.Slice)
			varargs := make([]string, len(args)-i)
			for j, arg := range args[i:] {
				varargs[j] = c.translateImplicitConversionWithCloning(arg, varargType.Elem()).String()
			}
			params[i] = fmt.Sprintf("new %s([%s])", c.typeName(varargType), strings.Join(varargs, ", "))
			break
		}
		argType := sig.Params().At(i).Type()
		params[i] = c.translateImplicitConversionWithCloning(args[i], argType).String()
	}
	return params
}
Esempio n. 10
0
func (c *PkgContext) translateArgs(sig *types.Signature, args []ast.Expr, ellipsis bool) string {
	params := make([]string, sig.Params().Len())
	for i := range params {
		if sig.IsVariadic() && i == len(params)-1 && !ellipsis {
			varargType := sig.Params().At(i).Type().(*types.Slice)
			varargs := make([]string, len(args)-i)
			for j, arg := range args[i:] {
				varargs[j] = c.translateExprToType(arg, varargType.Elem())
			}
			params[i] = fmt.Sprintf("new %s(%s)", c.typeName(varargType), createListComposite(varargType.Elem(), varargs))
			break
		}
		argType := sig.Params().At(i).Type()
		params[i] = c.translateExprToType(args[i], argType)
	}
	return strings.Join(params, ", ")
}
Esempio n. 11
0
func (w *Walker) writeSignature(buf *bytes.Buffer, sig *types.Signature) {
	w.writeParams(buf, sig.Params(), sig.IsVariadic())
	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)
	}
}
Esempio n. 12
0
// writeSignature writes to w the signature sig in declaration syntax.
// Derived from types.Signature.String().
//
func writeSignature(w io.Writer, name string, sig *types.Signature, params []*Parameter) {
	io.WriteString(w, "func ")
	if recv := sig.Recv(); recv != nil {
		io.WriteString(w, "(")
		if n := params[0].Name(); n != "" {
			io.WriteString(w, n)
			io.WriteString(w, " ")
		}
		io.WriteString(w, params[0].Type().String())
		io.WriteString(w, ") ")
		params = params[1:]
	}
	io.WriteString(w, name)
	io.WriteString(w, "(")
	for i, v := range params {
		if i > 0 {
			io.WriteString(w, ", ")
		}
		io.WriteString(w, v.Name())
		io.WriteString(w, " ")
		if sig.IsVariadic() && i == len(params)-1 {
			io.WriteString(w, "...")
			io.WriteString(w, v.Type().Underlying().(*types.Slice).Elem().String())
		} else {
			io.WriteString(w, v.Type().String())
		}
	}
	io.WriteString(w, ")")
	if n := sig.Results().Len(); n > 0 {
		io.WriteString(w, " ")
		r := sig.Results()
		if n == 1 && r.At(0).Name() == "" {
			io.WriteString(w, r.At(0).Type().String())
		} else {
			io.WriteString(w, r.String())
		}
	}
}
Esempio n. 13
0
func (p *exporter) signature(sig *types.Signature) {
	// TODO(gri) We only need to record the receiver type
	//           for interface methods if we flatten them
	//           out. If we track embedded types instead,
	//           the information is already present.
	// We do need the receiver information (T vs *T)
	// for methods associated with named types.
	if recv := sig.Recv(); recv != nil {
		// 1-element tuple
		p.int(1)
		p.param(recv)
	} 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)
	}
}
Esempio n. 14
0
func (v funcTypeVisitor) Visit(node ast.Node) ast.Visitor {
	var sig *types.Signature
	var noderecv *ast.FieldList
	var astfunc *ast.FuncType

	switch node := node.(type) {
	case *ast.FuncDecl:
		sig = v.objects[node.Name].Type().(*types.Signature)
		astfunc = node.Type
		noderecv = node.Recv
	case *ast.FuncLit:
		sig = v.exprtypes[node].Type.(*types.Signature)
		astfunc = node.Type
	default:
		return v
	}

	// go/types creates a separate types.Var for
	// internal and external usage. We need to
	// associate them at the object data level.
	paramIdents := fieldlistIdents(astfunc.Params)
	resultIdents := fieldlistIdents(astfunc.Results)
	if recv := sig.Recv(); recv != nil {
		id := fieldlistIdents(noderecv)[0]
		if obj, ok := v.objects[id]; ok {
			v.objectdata[recv] = v.objectdata[obj]
		}
	}
	for i, id := range paramIdents {
		if obj, ok := v.objects[id]; ok {
			v.objectdata[sig.Params().At(i)] = v.objectdata[obj]
		}
	}
	for i, id := range resultIdents {
		if obj, ok := v.objects[id]; ok {
			v.objectdata[sig.Results().At(i)] = v.objectdata[obj]
		}
	}
	return v
}
Esempio n. 15
0
func (tm *TypeMap) funcRuntimeType(f *types.Signature) (global, ptr llvm.Value) {
	rtype := tm.makeRtype(f, reflect.Func)
	funcType := llvm.ConstNull(tm.runtime.funcType.llvm)
	global, ptr = tm.makeRuntimeTypeGlobal(funcType, typeString(f))
	tm.types.Set(f, runtimeTypeInfo{global, ptr})
	funcType = llvm.ConstInsertValue(funcType, rtype, []uint32{0})
	// dotdotdot
	if f.Variadic() {
		variadic := llvm.ConstInt(llvm.Int1Type(), 1, false)
		funcType = llvm.ConstInsertValue(funcType, variadic, []uint32{1})
	}
	// in
	intypes := tm.rtypeSlice(f.Params())
	funcType = llvm.ConstInsertValue(funcType, intypes, []uint32{2})
	// out
	outtypes := tm.rtypeSlice(f.Results())
	funcType = llvm.ConstInsertValue(funcType, outtypes, []uint32{3})
	global.SetInitializer(funcType)
	return global, ptr
}
Esempio n. 16
0
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)
}
Esempio n. 17
0
func (ts *TypeStringer) writeSignature(buf *bytes.Buffer, sig *types.Signature, unique bool) {
	if recv := sig.Recv(); recv != nil {
		if _, ok := recv.Type().Underlying().(*types.Interface); !ok {
			ts.writeType(buf, recv.Type(), unique)
			buf.WriteByte(' ')
		}
	}

	ts.writeParams(buf, sig.Params(), sig.IsVariadic(), unique)
	if sig.Results().Len() == 0 {
		// no result
		return
	}

	buf.WriteByte(' ')
	if sig.Results().Len() == 1 {
		// single unnamed result
		ts.writeType(buf, sig.Results().At(0).Type(), unique)
		return
	}

	// multiple or named result(s)
	ts.writeParams(buf, sig.Results(), false, unique)
}
Esempio n. 18
0
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])
		}
	}
}
Esempio n. 19
0
func (ts *TypeStringer) writeSignature(buf *bytes.Buffer, sig *types.Signature) {
	if recv := sig.Recv(); recv != nil {
		ts.writeType(buf, recv.Type())
		buf.WriteByte(' ')
	}

	ts.writeParams(buf, sig.Params(), sig.IsVariadic())
	if sig.Results().Len() == 0 {
		// no result
		return
	}

	buf.WriteByte(' ')
	if sig.Results().Len() == 1 {
		// single unnamed result
		ts.writeType(buf, sig.Results().At(0).Type())
		return
	}

	// multiple or named result(s)
	ts.writeParams(buf, sig.Results(), false)
}
Esempio n. 20
0
func (tm *LLVMTypeMap) funcLLVMType(tstr string, f *types.Signature) llvm.Type {
	typ, ok := tm.types[tstr]
	if !ok {
		// If there's a receiver change the receiver to an
		// additional (first) parameter, and take the value of
		// the resulting signature instead.
		var param_types []llvm.Type
		if recv := f.Recv(); recv != nil {
			params := f.Params()
			paramvars := make([]*types.Var, int(params.Len()+1))
			paramvars[0] = recv
			for i := 0; i < int(params.Len()); i++ {
				paramvars[i+1] = params.At(i)
			}
			params = types.NewTuple(paramvars...)
			f := types.NewSignature(nil, params, f.Results(), f.IsVariadic())
			return tm.ToLLVM(f)
		}

		typ = llvm.GlobalContext().StructCreateNamed("")
		tm.types[tstr] = typ

		params := f.Params()
		nparams := int(params.Len())
		for i := 0; i < nparams; i++ {
			typ := params.At(i).Type()
			if f.IsVariadic() && i == nparams-1 {
				typ = types.NewSlice(typ)
			}
			llvmtyp := tm.ToLLVM(typ)
			param_types = append(param_types, llvmtyp)
		}

		var return_type llvm.Type
		results := f.Results()
		switch nresults := int(results.Len()); nresults {
		case 0:
			return_type = llvm.VoidType()
		case 1:
			return_type = tm.ToLLVM(results.At(0).Type())
		default:
			elements := make([]llvm.Type, nresults)
			for i := range elements {
				result := results.At(i)
				elements[i] = tm.ToLLVM(result.Type())
			}
			return_type = llvm.StructType(elements, false)
		}

		fntyp := llvm.FunctionType(return_type, param_types, false)
		fnptrtyp := llvm.PointerType(fntyp, 0)
		i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
		elements := []llvm.Type{fnptrtyp, i8ptr} // func, closure
		typ.StructSetBody(elements, false)
	}
	return typ
}
Esempio n. 21
0
func (tm *llvmTypeMap) funcLLVMType(f *types.Signature, name string) llvm.Type {
	// If there's a receiver change the receiver to an
	// additional (first) parameter, and take the value of
	// the resulting signature instead.
	if recv := f.Recv(); recv != nil {
		params := f.Params()
		paramvars := make([]*types.Var, int(params.Len()+1))
		paramvars[0] = recv
		for i := 0; i < int(params.Len()); i++ {
			paramvars[i+1] = params.At(i)
		}
		params = types.NewTuple(paramvars...)
		f := types.NewSignature(nil, nil, params, f.Results(), f.Variadic())
		return tm.toLLVM(f, name)
	}

	if typ, ok := tm.types.At(f).(llvm.Type); ok {
		return typ
	}
	typ := llvm.GlobalContext().StructCreateNamed(name)
	tm.types.Set(f, typ)

	params := f.Params()
	param_types := make([]llvm.Type, params.Len())
	for i := range param_types {
		llvmtyp := tm.ToLLVM(params.At(i).Type())
		param_types[i] = llvmtyp
	}

	var return_type llvm.Type
	results := f.Results()
	switch nresults := int(results.Len()); nresults {
	case 0:
		return_type = llvm.VoidType()
	case 1:
		return_type = tm.ToLLVM(results.At(0).Type())
	default:
		elements := make([]llvm.Type, nresults)
		for i := range elements {
			result := results.At(i)
			elements[i] = tm.ToLLVM(result.Type())
		}
		return_type = llvm.StructType(elements, false)
	}

	fntyp := llvm.FunctionType(return_type, param_types, false)
	fnptrtyp := llvm.PointerType(fntyp, 0)
	i8ptr := llvm.PointerType(llvm.Int8Type(), 0)
	elements := []llvm.Type{fnptrtyp, i8ptr} // func, closure
	typ.StructSetBody(elements, false)
	return typ
}
Esempio n. 22
0
File: types.go Progetto: minux/llgo
func (m *TypeMap) descriptorSignature(t *types.Signature, name string) TypeDebugDescriptor {
	// If there's a receiver change the receiver to an
	// additional (first) parameter, and take the value of
	// the resulting signature instead.
	if recv := t.Recv(); recv != nil {
		params := t.Params()
		paramvars := make([]*types.Var, int(params.Len()+1))
		paramvars[0] = recv
		for i := 0; i < int(params.Len()); i++ {
			paramvars[i+1] = params.At(i)
		}
		params = types.NewTuple(paramvars...)
		t := types.NewSignature(nil, nil, params, t.Results(), t.Variadic())
		return m.typeDebugDescriptor(t, name)
	}
	if dt, ok := m.m.At(t).(TypeDebugDescriptor); ok {
		return dt
	}

	var returnType DebugDescriptor
	var paramTypes []DebugDescriptor
	if results := t.Results(); results.Len() == 1 {
		returnType = m.TypeDebugDescriptor(results.At(0).Type())
	} else if results != nil {
		fields := make([]DebugDescriptor, results.Len())
		for i := range fields {
			fields[i] = m.TypeDebugDescriptor(results.At(i).Type())
		}
		returnType = NewStructCompositeType(fields)
	}
	if params := t.Params(); params != nil && params.Len() > 0 {
		paramTypes = make([]DebugDescriptor, params.Len())
		for i := range paramTypes {
			paramTypes[i] = m.TypeDebugDescriptor(params.At(i).Type())
		}
	}
	ct := NewStructCompositeType([]DebugDescriptor{
		NewSubroutineCompositeType(returnType, paramTypes),
		m.TypeDebugDescriptor(types.NewPointer(types.Typ[types.Uint8])),
	})
	ct.Name = name
	m.m.Set(t, ct)
	return ct
}
Esempio n. 23
0
func changeRecv(s *types.Signature, recv *types.Var) *types.Signature {
	return types.NewSignature(nil, recv, s.Params(), s.Results(), s.Variadic())
}
Esempio n. 24
0
func (c *PkgContext) translateFunctionBody(stmts []ast.Stmt, sig *types.Signature) {
	c.funcVarNames = nil

	body := c.CatchOutput(func() {
		var resultNames []ast.Expr
		if sig != nil && sig.Results().Len() != 0 && sig.Results().At(0).Name() != "" {
			resultNames = make([]ast.Expr, sig.Results().Len())
			for i := 0; i < sig.Results().Len(); i++ {
				result := sig.Results().At(i)
				name := result.Name()
				if result.Name() == "_" {
					name = "result"
				}
				id := ast.NewIdent(name)
				c.info.Types[id] = result.Type()
				c.info.Objects[id] = result
				c.Printf("%s = %s;", c.translateExpr(id), c.zeroValue(result.Type()))
				resultNames[i] = id
			}
		}

		if sig != nil {
			s := c.functionSig
			defer func() { c.functionSig = s }()
			c.functionSig = sig
		}
		r := c.resultNames
		defer func() { c.resultNames = r }()
		c.resultNames = resultNames
		p := c.postLoopStmt
		defer func() { c.postLoopStmt = p }()
		c.postLoopStmt = make(map[string]ast.Stmt)

		v := HasDeferVisitor{}
		ast.Walk(&v, &ast.BlockStmt{List: stmts})
		switch v.hasDefer {
		case true:
			c.Printf("var Go$deferred = [];")
			c.Printf("try {")
			c.Indent(func() {
				c.translateStmtList(stmts)
			})
			c.Printf("} catch(Go$err) {")
			c.Indent(func() {
				c.Printf("if (Go$err.constructor !== Go$Panic) { Go$err = Go$wrapJavaScriptError(Go$err); }")
				c.Printf("Go$errorStack.push({ frame: Go$getStackDepth(), error: Go$err });")
				if sig != nil && sig.Results().Len() != 0 && resultNames == nil {
					zeros := make([]string, sig.Results().Len())
					for i := range zeros {
						zeros[i] = c.zeroValue(sig.Results().At(i).Type())
					}
					c.Printf("return %s;", strings.Join(zeros, ", "))
				}
			})
			c.Printf("} finally {")
			c.Indent(func() {
				c.Printf("Go$callDeferred(Go$deferred);")
				if resultNames != nil {
					c.translateStmt(&ast.ReturnStmt{}, "")
				}
			})
			c.Printf("}")
		case false:
			c.translateStmtList(stmts)
		}
	})

	if len(c.funcVarNames) != 0 {
		c.Printf("var %s;", strings.Join(c.funcVarNames, ", "))
	}
	c.Write(body)
}