// 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) }
// 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), } }
// emitTypeTest emits to f a type test value,ok := x.(t) and returns // a (value, ok) tuple. x.Type() must be an interface. // func emitTypeTest(f *Function, x Value, t types.Type, pos token.Pos) Value { a := &TypeAssert{ X: x, AssertedType: t, CommaOk: true, } a.setPos(pos) a.setType(types.NewTuple( newVar("value", t), varOk, )) return f.emit(a) }
// 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, sel *types.Selection) *Function { obj := sel.Obj().(*types.Func) // the declared function sig := sel.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 sel.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, sel.Obj()) if prog.mode&LogSource != 0 { defer logStack("make %s to (%s)", description, recv.Type())() } fn := &Function{ name: name, method: sel, object: obj, Signature: sig, Synthetic: description, Prog: prog, pos: obj.Pos(), } fn.startBody() fn.addSpilledParam(recv) createParams(fn, start) indices := sel.Index() var v Value = fn.Locals[0] // spilled receiver if isPointer(sel.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(sel.Recv()), anonVar(tString), anonVar(tString)), types.NewTuple(anonVar(sel.Recv())), false), } c.Call.Args = []Value{ v, stringConst(deref(sel.Recv()).String()), stringConst(sel.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 }
// CreateTestMainPackage creates and returns a synthetic "main" // package that runs all the tests of the supplied packages, similar // to the one that would be created by the 'go test' tool. // // It returns nil if the program contains no tests. // func (prog *Program) CreateTestMainPackage(pkgs ...*Package) *Package { pkgs, tests, benchmarks, examples := FindTests(pkgs) if len(pkgs) == 0 { return nil } testmain := &Package{ Prog: prog, Members: make(map[string]Member), values: make(map[types.Object]Value), Object: types.NewPackage("test$main", "main"), } // Build package's init function. init := &Function{ name: "init", Signature: new(types.Signature), Synthetic: "package initializer", Pkg: testmain, Prog: prog, } init.startBody() if testMainStartBodyHook != nil { testMainStartBodyHook(init) } // Initialize packages to test. var pkgpaths []string for _, pkg := range pkgs { var v Call v.Call.Value = pkg.init v.setType(types.NewTuple()) init.emit(&v) pkgpaths = append(pkgpaths, pkg.Object.Path()) } sort.Strings(pkgpaths) init.emit(new(Return)) init.finishBody() testmain.init = init testmain.Object.MarkComplete() testmain.Members[init.name] = init // For debugging convenience, define an unexported const // that enumerates the packages. packagesConst := types.NewConst(token.NoPos, testmain.Object, "packages", tString, exact.MakeString(strings.Join(pkgpaths, " "))) memberFromObject(testmain, packagesConst, nil) // Create main *types.Func and *ssa.Function mainFunc := types.NewFunc(token.NoPos, testmain.Object, "main", new(types.Signature)) memberFromObject(testmain, mainFunc, nil) main := testmain.Func("main") main.Synthetic = "test main function" main.startBody() if testMainStartBodyHook != nil { testMainStartBodyHook(main) } if testingPkg := prog.ImportedPackage("testing"); testingPkg != nil { testingMain := testingPkg.Func("Main") testingMainParams := testingMain.Signature.Params() // The generated code is as if compiled from this: // // func main() { // match := func(_, _ string) (bool, error) { return true, nil } // tests := []testing.InternalTest{{"TestFoo", TestFoo}, ...} // benchmarks := []testing.InternalBenchmark{...} // examples := []testing.InternalExample{...} // testing.Main(match, tests, benchmarks, examples) // } matcher := &Function{ name: "matcher", Signature: testingMainParams.At(0).Type().(*types.Signature), Synthetic: "test matcher predicate", parent: main, Pkg: testmain, Prog: prog, } main.AnonFuncs = append(main.AnonFuncs, matcher) matcher.startBody() matcher.emit(&Return{Results: []Value{vTrue, nilConst(types.Universe.Lookup("error").Type())}}) matcher.finishBody() // Emit call: testing.Main(matcher, tests, benchmarks, examples). var c Call c.Call.Value = testingMain c.Call.Args = []Value{ matcher, testMainSlice(main, tests, testingMainParams.At(1).Type()), testMainSlice(main, benchmarks, testingMainParams.At(2).Type()), testMainSlice(main, examples, testingMainParams.At(3).Type()), } emitTailCall(main, &c) } else { // The program does not import "testing", but FindTests // returned non-nil, which must mean there were Examples // but no Tests or Benchmarks. // We'll simply call them from testmain.main; this will // ensure they don't panic, but will not check any // "Output:" comments. for _, eg := range examples { var c Call c.Call.Value = eg c.setType(types.NewTuple()) main.emit(&c) } main.emit(&Return{}) main.currentBlock = nil } main.finishBody() testmain.Members["main"] = main if prog.mode&PrintPackages != 0 { printMu.Lock() testmain.WriteTo(os.Stdout) printMu.Unlock() } if prog.mode&SanityCheckFunctions != 0 { sanityCheckPackage(testmain) } prog.packages[testmain.Object] = testmain return testmain }
func logStack(format string, args ...interface{}) func() { msg := fmt.Sprintf(format, args...) io.WriteString(os.Stderr, msg) io.WriteString(os.Stderr, "\n") return func() { io.WriteString(os.Stderr, msg) io.WriteString(os.Stderr, " end\n") } } // newVar creates a 'var' for use in a types.Tuple. func newVar(name string, typ types.Type) *types.Var { return types.NewParam(token.NoPos, nil, name, typ) } // anonVar creates an anonymous 'var' for use in a types.Tuple. func anonVar(typ types.Type) *types.Var { return newVar("", typ) } var lenResults = types.NewTuple(anonVar(tInt)) // 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), } }