// makeLen returns the len builtin specialized to type func(T)int. func makeLen(T types.Type) *Builtin { lenParams := types.NewTuple(anonVar(T)) return &Builtin{ name: "len", sig: types.NewSignature(nil, nil, lenParams, lenResults, false), } }
// newMethod creates a new method of the specified name, package and receiver type. func newMethod(pkg *ssa.Package, recvType types.Type, name string) *ssa.Function { // TODO(adonovan): fix: hack: currently the only part of Signature // that is needed is the "pointerness" of Recv.Type, and for // now, we'll set it to always be false since we're only // concerned with rtype. Encapsulate this better. sig := types.NewSignature(nil, types.NewVar(token.NoPos, nil, "recv", recvType), nil, nil, false) fn := pkg.Prog.NewFunction(name, sig, "fake reflect method") fn.Pkg = pkg return fn }
// Signature = Parameters [ Result ] . // Result = Type | Parameters . // func (p *parser) parseSignature(recv *types.Var) *types.Signature { params, isVariadic := p.parseParameters() // optional result type var results []*types.Var if p.tok == '(' { var variadic bool results, variadic = p.parseParameters() if variadic { p.error("... not permitted on result type") } } return types.NewSignature(nil, recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic) }
func changeRecv(s *types.Signature, recv *types.Var) *types.Signature { return types.NewSignature(nil, recv, s.Params(), s.Results(), s.Variadic()) }
// makeWrapper returns a synthetic method that delegates to the // declared method denoted by meth.Obj(), first performing any // necessary pointer indirections or field selections implied by meth. // // The resulting method's receiver type is meth.Recv(). // // This function is versatile but quite subtle! Consider the // following axes of variation when making changes: // - optional receiver indirection // - optional implicit field selections // - meth.Obj() may denote a concrete or an interface method // - the result may be a thunk or a wrapper. // // EXCLUSIVE_LOCKS_REQUIRED(prog.methodsMu) // func makeWrapper(prog *Program, meth *types.Selection) *Function { obj := meth.Obj().(*types.Func) // the declared function sig := meth.Type().(*types.Signature) // type of this wrapper var recv *types.Var // wrapper's receiver or thunk's params[0] name := obj.Name() var description string var start int // first regular param if meth.Kind() == types.MethodExpr { name += "$thunk" description = "thunk" recv = sig.Params().At(0) start = 1 } else { description = "wrapper" recv = sig.Recv() } description = fmt.Sprintf("%s for %s", description, meth.Obj()) if prog.mode&LogSource != 0 { defer logStack("make %s to (%s)", description, recv.Type())() } fn := &Function{ name: name, method: meth, object: obj, Signature: sig, Synthetic: description, Prog: prog, pos: obj.Pos(), } fn.startBody() fn.addSpilledParam(recv) createParams(fn, start) indices := meth.Index() var v Value = fn.Locals[0] // spilled receiver if isPointer(meth.Recv()) { v = emitLoad(fn, v) // For simple indirection wrappers, perform an informative nil-check: // "value method (T).f called using nil *T pointer" if len(indices) == 1 && !isPointer(recvType(obj)) { var c Call c.Call.Value = &Builtin{ name: "ssa:wrapnilchk", sig: types.NewSignature(nil, nil, types.NewTuple(anonVar(meth.Recv()), anonVar(tString), anonVar(tString)), types.NewTuple(anonVar(meth.Recv())), false), } c.Call.Args = []Value{ v, stringConst(deref(meth.Recv()).String()), stringConst(meth.Obj().Name()), } c.setType(v.Type()) v = fn.emit(&c) } } // Invariant: v is a pointer, either // value of *A receiver param, or // address of A spilled receiver. // We use pointer arithmetic (FieldAddr possibly followed by // Load) in preference to value extraction (Field possibly // preceded by Load). v = emitImplicitSelections(fn, v, indices[:len(indices)-1]) // Invariant: v is a pointer, either // value of implicit *C field, or // address of implicit C field. var c Call if r := recvType(obj); !isInterface(r) { // concrete method if !isPointer(r) { v = emitLoad(fn, v) } c.Call.Value = prog.declaredFunc(obj) c.Call.Args = append(c.Call.Args, v) } else { c.Call.Method = obj c.Call.Value = emitLoad(fn, v) } for _, arg := range fn.Params[1:] { c.Call.Args = append(c.Call.Args, arg) } emitTailCall(fn, &c) fn.finishBody() return fn }