func (p *importer) obj(tag int) { switch tag { case constTag: pos := p.pos() pkg, name := p.qualifiedName() typ := p.typ(nil) val := p.value() p.declare(types.NewConst(pos, pkg, name, typ, val)) case typeTag: _ = p.typ(nil) case varTag: pos := p.pos() pkg, name := p.qualifiedName() typ := p.typ(nil) p.declare(types.NewVar(pos, pkg, name, typ)) case funcTag: pos := p.pos() pkg, name := p.qualifiedName() params, isddd := p.paramList() result, _ := p.paramList() sig := types.NewSignature(nil, params, result, isddd) p.declare(types.NewFunc(pos, pkg, name, sig)) default: panic(fmt.Sprintf("unexpected object tag %d", tag)) } }
func (p *importer) method(parent *types.Package) *types.Func { pos := p.pos() pkg, name := p.fieldName(parent) params, isddd := p.paramList() result, _ := p.paramList() sig := types.NewSignature(nil, params, result, isddd) return types.NewFunc(pos, pkg, name, sig) }
// Func = Name FunctionType . func (p *parser) parseFunc(pkg *types.Package) *types.Func { name := p.parseName() if strings.ContainsRune(name, '$') { // This is a Type$equal or Type$hash function, which we don't want to parse, // except for the types. p.discardDirectiveWhileParsingTypes(pkg) return nil } return types.NewFunc(token.NoPos, pkg, name, p.parseFunctionType(pkg)) }
func ParseFuncDecl(fnDecl *gst.FuncDecl) (*types.Func, bool) { var fn *types.Func var pkg *types.Package pkg = nil name := fnDecl.Name var sig *types.Signature sig = types.NewSignature(nil, nil, nil, false) var pos token.Pos fn = types.NewFunc(pos, pkg, name, sig) return fn, true }
// InterfaceType = "interface" "{" [ MethodList ] "}" . // MethodList = Method { ";" Method } . // Method = Name Signature . // // The methods of embedded interfaces are always "inlined" // by the compiler and thus embedded interfaces are never // visible in the export data. // func (p *parser) parseInterfaceType(parent *types.Package) types.Type { var methods []*types.Func p.expectKeyword("interface") p.expect('{') for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ { if i > 0 { p.expect(';') } pkg, name := p.parseName(parent, true) sig := p.parseSignature(nil) methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig)) } p.expect('}') // Complete requires the type's embedded interfaces to be fully defined, // but we do not define any return types.NewInterface(methods, nil).Complete() }
func (p *importer) obj(tag int) { switch tag { case constTag: pos := p.pos() pkg, name := p.qualifiedName() typ := p.typ(nil) val := p.value() p.declare(types.NewConst(pos, pkg, name, typ, val)) case typeTag: p.typ(nil) case varTag: pos := p.pos() pkg, name := p.qualifiedName() typ := p.typ(nil) p.declare(types.NewVar(pos, pkg, name, typ)) case funcTag: pos := p.pos() pkg, name := p.qualifiedName() params, isddd := p.paramList() result, _ := p.paramList() sig := types.NewSignature(nil, params, result, isddd) p.declare(types.NewFunc(pos, pkg, name, sig)) case aliasTag: pos := p.pos() name := p.string() var orig types.Object if pkg, name := p.qualifiedName(); pkg != nil { orig = pkg.Scope().Lookup(name) } // Alias-related code. Keep for now. _ = pos _ = name _ = orig // p.declare(types.NewAlias(pos, p.pkgList[0], name, orig)) default: errorf("unexpected object tag %d", tag) } }
// MethodDecl = "func" Receiver Name Func . // Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" . // func (p *parser) parseMethodDecl() { // "func" already consumed p.expect('(') recv, _ := p.parseParameter() // receiver p.expect(')') // determine receiver base type object base := deref(recv.Type()).(*types.Named) // parse method name, signature, and possibly inlined body _, name := p.parseName(nil, false) sig := p.parseFunc(recv) // methods always belong to the same package as the base type object pkg := base.Obj().Pkg() // add method to type unless type was imported before // and method exists already // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small. base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig)) }
func (p *importer) obj(pkg *types.Package) { var obj types.Object switch tag := p.int(); tag { case constTag: obj = types.NewConst(token.NoPos, pkg, p.string(), p.typ(), p.value()) case typeTag: // type object is added to scope via respective named type _ = p.typ().(*types.Named) return case varTag: obj = types.NewVar(token.NoPos, pkg, p.string(), p.typ()) case funcTag: obj = types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature)) default: panic(fmt.Sprintf("unexpected object tag %d", tag)) } if alt := pkg.Scope().Insert(obj); alt != nil { panic(fmt.Sprintf("%s already declared", alt.Name())) } }
// NamedType = TypeName Type { Method } . // Method = "func" "(" Param ")" Name ParamList ResultList ";" . func (p *parser) parseNamedType(n int) types.Type { obj := p.parseTypeName() pkg := obj.Pkg() typ := obj.Type() p.typeMap[n] = typ nt, ok := typ.(*types.Named) if !ok { // This can happen for unsafe.Pointer, which is a TypeName holding a Basic type. pt := p.parseType(pkg) if pt != typ { p.error("unexpected underlying type for non-named TypeName") } return typ } underlying := p.parseType(pkg) if nt.Underlying() == nil { nt.SetUnderlying(underlying.Underlying()) } for p.tok == scanner.Ident { // collect associated methods p.expectKeyword("func") p.expect('(') receiver, _ := p.parseParam(pkg) p.expect(')') name := p.parseName() params, isVariadic := p.parseParamList(pkg) results := p.parseResultList(pkg) p.expect(';') sig := types.NewSignature(receiver, params, results, isVariadic) nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig)) } return nt }
// BImportData imports a package from the serialized package data // and returns the number of bytes consumed and a reference to the package. // If data is obviously malformed, an error is returned but in // general it is not recommended to call BImportData on untrusted data. func BImportData(imports map[string]*types.Package, data []byte, path string) (int, *types.Package, error) { p := importer{ imports: imports, data: data, } p.buf = p.bufarray[:] // read low-level encoding format switch format := p.byte(); format { case 'c': // compact format - nothing to do case 'd': p.debugFormat = true default: return p.read, nil, fmt.Errorf("invalid encoding format in export data: got %q; want 'c' or 'd'", format) } // --- generic export data --- if v := p.string(); v != "v0" { return p.read, nil, fmt.Errorf("unknown version: %s", v) } // populate typList with predeclared "known" types p.typList = append(p.typList, predeclared...) // read package data // TODO(gri) clean this up i := p.tagOrIndex() if i != packageTag { panic(fmt.Sprintf("package tag expected, got %d", i)) } name := p.string() if s := p.string(); s != "" { panic(fmt.Sprintf("empty path expected, got %s", s)) } pkg := p.imports[path] if pkg == nil { pkg = types.NewPackage(path, name) p.imports[path] = pkg } p.pkgList = append(p.pkgList, pkg) if debug && p.pkgList[0] != pkg { panic("imported packaged not found in pkgList[0]") } // read compiler-specific flags p.string() // discard // read consts for i := p.int(); i > 0; i-- { name := p.string() typ := p.typ(nil) val := p.value() p.declare(types.NewConst(token.NoPos, pkg, name, typ, val)) } // read vars for i := p.int(); i > 0; i-- { name := p.string() typ := p.typ(nil) p.declare(types.NewVar(token.NoPos, pkg, name, typ)) } // read funcs for i := p.int(); i > 0; i-- { name := p.string() sig := p.typ(nil).(*types.Signature) p.int() // read and discard index of inlined function body p.declare(types.NewFunc(token.NoPos, pkg, name, sig)) } // read types for i := p.int(); i > 0; i-- { // name is parsed as part of named type and the // type object is added to scope via respective // named type _ = p.typ(nil).(*types.Named) } // ignore compiler-specific import data // complete interfaces for _, typ := range p.typList { if it, ok := typ.(*types.Interface); ok { it.Complete() } } // record all referenced packages as imports list := append(([]*types.Package)(nil), p.pkgList[1:]...) sort.Sort(byPath(list)) pkg.SetImports(list) // package was imported completely and without errors pkg.MarkComplete() return p.read, pkg, nil }
// parent is the package which declared the type; parent == nil means // the package currently imported. The parent package is needed for // exported struct fields and interface methods which don't contain // explicit package information in the export data. func (p *importer) typ(parent *types.Package) types.Type { // if the type was seen before, i is its index (>= 0) i := p.tagOrIndex() if i >= 0 { return p.typList[i] } // otherwise, i is the type tag (< 0) switch i { case namedTag: // read type object name := p.string() parent = p.pkg() scope := parent.Scope() obj := scope.Lookup(name) // if the object doesn't exist yet, create and insert it if obj == nil { obj = types.NewTypeName(token.NoPos, parent, name, nil) scope.Insert(obj) } if _, ok := obj.(*types.TypeName); !ok { panic(fmt.Sprintf("pkg = %s, name = %s => %s", parent, name, obj)) } // associate new named type with obj if it doesn't exist yet t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) // but record the existing type, if any t := obj.Type().(*types.Named) p.record(t) // read underlying type t0.SetUnderlying(p.typ(parent)) // interfaces don't have associated methods if _, ok := t0.Underlying().(*types.Interface); ok { return t } // read associated methods for i := p.int(); i > 0; i-- { name := p.string() recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver? params, isddd := p.paramList() result, _ := p.paramList() p.int() // read and discard index of inlined function body sig := types.NewSignature(recv.At(0), params, result, isddd) t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig)) } return t case arrayTag: t := new(types.Array) p.record(t) n := p.int64() *t = *types.NewArray(p.typ(parent), n) return t case sliceTag: t := new(types.Slice) p.record(t) *t = *types.NewSlice(p.typ(parent)) return t case dddTag: t := new(dddSlice) p.record(t) t.elem = p.typ(parent) return t case structTag: t := new(types.Struct) p.record(t) n := p.int() fields := make([]*types.Var, n) tags := make([]string, n) for i := range fields { fields[i] = p.field(parent) tags[i] = p.string() } *t = *types.NewStruct(fields, tags) return t case pointerTag: t := new(types.Pointer) p.record(t) *t = *types.NewPointer(p.typ(parent)) return t case signatureTag: t := new(types.Signature) p.record(t) params, isddd := p.paramList() result, _ := p.paramList() *t = *types.NewSignature(nil, params, result, isddd) return t case interfaceTag: // Create a dummy entry in the type list. This is safe because we // cannot expect the interface type to appear in a cycle, as any // such cycle must contain a named type which would have been // first defined earlier. n := len(p.typList) p.record(nil) // no embedded interfaces with gc compiler if p.int() != 0 { panic("unexpected embedded interface") } // read methods methods := make([]*types.Func, p.int()) for i := range methods { pkg, name := p.fieldName(parent) params, isddd := p.paramList() result, _ := p.paramList() sig := types.NewSignature(nil, params, result, isddd) methods[i] = types.NewFunc(token.NoPos, pkg, name, sig) } t := types.NewInterface(methods, nil) p.typList[n] = t return t case mapTag: t := new(types.Map) p.record(t) key := p.typ(parent) val := p.typ(parent) *t = *types.NewMap(key, val) return t case chanTag: t := new(types.Chan) p.record(t) var dir types.ChanDir // tag values must match the constants in cmd/compile/internal/gc/go.go switch d := p.int(); d { case 1 /* Crecv */ : dir = types.RecvOnly case 2 /* Csend */ : dir = types.SendOnly case 3 /* Cboth */ : dir = types.SendRecv default: panic(fmt.Sprintf("unexpected channel dir %d", d)) } val := p.typ(parent) *t = *types.NewChan(dir, val) return t default: panic(fmt.Sprintf("unexpected type tag %d", i)) } }
// FuncDecl = "func" ExportedName Func . // func (p *parser) parseFuncDecl() { // "func" already consumed pkg, name := p.parseExportedName() typ := p.parseFunc(nil) pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ)) }
// parent is the package which declared the type; parent == nil means // the package currently imported. The parent package is needed for // exported struct fields and interface methods which don't contain // explicit package information in the export data. func (p *importer) typ(parent *types.Package) types.Type { // if the type was seen before, i is its index (>= 0) i := p.tagOrIndex() if i >= 0 { return p.typList[i] } // otherwise, i is the type tag (< 0) switch i { case namedTag: // read type object pos := p.pos() parent, name := p.qualifiedName() scope := parent.Scope() obj := scope.Lookup(name) // if the object doesn't exist yet, create and insert it if obj == nil { obj = types.NewTypeName(pos, parent, name, nil) scope.Insert(obj) } if _, ok := obj.(*types.TypeName); !ok { errorf("pkg = %s, name = %s => %s", parent, name, obj) } // associate new named type with obj if it doesn't exist yet t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) // but record the existing type, if any t := obj.Type().(*types.Named) p.record(t) // read underlying type t0.SetUnderlying(p.typ(parent)) // interfaces don't have associated methods if types.IsInterface(t0) { return t } // read associated methods for i := p.int(); i > 0; i-- { // TODO(gri) replace this with something closer to fieldName pos := p.pos() name := p.string() if !exported(name) { p.pkg() } recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver? params, isddd := p.paramList() result, _ := p.paramList() p.int() // go:nointerface pragma - discarded sig := types.NewSignature(recv.At(0), params, result, isddd) t0.AddMethod(types.NewFunc(pos, parent, name, sig)) } return t case arrayTag: t := new(types.Array) if p.trackAllTypes { p.record(t) } n := p.int64() *t = *types.NewArray(p.typ(parent), n) return t case sliceTag: t := new(types.Slice) if p.trackAllTypes { p.record(t) } *t = *types.NewSlice(p.typ(parent)) return t case dddTag: t := new(dddSlice) if p.trackAllTypes { p.record(t) } t.elem = p.typ(parent) return t case structTag: t := new(types.Struct) if p.trackAllTypes { p.record(t) } *t = *types.NewStruct(p.fieldList(parent)) return t case pointerTag: t := new(types.Pointer) if p.trackAllTypes { p.record(t) } *t = *types.NewPointer(p.typ(parent)) return t case signatureTag: t := new(types.Signature) if p.trackAllTypes { p.record(t) } params, isddd := p.paramList() result, _ := p.paramList() *t = *types.NewSignature(nil, params, result, isddd) return t case interfaceTag: // Create a dummy entry in the type list. This is safe because we // cannot expect the interface type to appear in a cycle, as any // such cycle must contain a named type which would have been // first defined earlier. n := len(p.typList) if p.trackAllTypes { p.record(nil) } // no embedded interfaces with gc compiler if p.int() != 0 { errorf("unexpected embedded interface") } t := types.NewInterface(p.methodList(parent), nil) if p.trackAllTypes { p.typList[n] = t } return t case mapTag: t := new(types.Map) if p.trackAllTypes { p.record(t) } key := p.typ(parent) val := p.typ(parent) *t = *types.NewMap(key, val) return t case chanTag: t := new(types.Chan) if p.trackAllTypes { p.record(t) } var dir types.ChanDir // tag values must match the constants in cmd/compile/internal/gc/go.go switch d := p.int(); d { case 1 /* Crecv */ : dir = types.RecvOnly case 2 /* Csend */ : dir = types.SendOnly case 3 /* Cboth */ : dir = types.SendRecv default: errorf("unexpected channel dir %d", d) } val := p.typ(parent) *t = *types.NewChan(dir, val) return t default: errorf("unexpected type tag %d", i) // panics panic("unreachable") } }
func (p *importer) typ() types.Type { // if the type was seen before, i is its index (>= 0) i := p.int() if i >= 0 { return p.typList[i] } // otherwise, i is the type tag (< 0) switch i { case arrayTag: t := new(types.Array) p.record(t) n := p.int64() *t = *types.NewArray(p.typ(), n) return t case sliceTag: t := new(types.Slice) p.record(t) *t = *types.NewSlice(p.typ()) return t case structTag: t := new(types.Struct) p.record(t) n := p.int() fields := make([]*types.Var, n) tags := make([]string, n) for i := range fields { fields[i] = p.field() tags[i] = p.string() } *t = *types.NewStruct(fields, tags) return t case pointerTag: t := new(types.Pointer) p.record(t) *t = *types.NewPointer(p.typ()) return t case signatureTag: t := new(types.Signature) p.record(t) *t = *p.signature() return t case interfaceTag: // Create a dummy entry in the type list. This is safe because we // cannot expect the interface type to appear in a cycle, as any // such cycle must contain a named type which would have been // first defined earlier. n := len(p.typList) p.record(nil) // read embedded interfaces embeddeds := make([]*types.Named, p.int()) for i := range embeddeds { embeddeds[i] = p.typ().(*types.Named) } // read methods methods := make([]*types.Func, p.int()) for i := range methods { pkg, name := p.qualifiedName() methods[i] = types.NewFunc(token.NoPos, pkg, name, p.typ().(*types.Signature)) } t := types.NewInterface(methods, embeddeds) p.typList[n] = t return t case mapTag: t := new(types.Map) p.record(t) *t = *types.NewMap(p.typ(), p.typ()) return t case chanTag: t := new(types.Chan) p.record(t) *t = *types.NewChan(types.ChanDir(p.int()), p.typ()) return t case namedTag: // read type object name := p.string() pkg := p.pkg() scope := pkg.Scope() obj := scope.Lookup(name) // if the object doesn't exist yet, create and insert it if obj == nil { obj = types.NewTypeName(token.NoPos, pkg, name, nil) scope.Insert(obj) } // associate new named type with obj if it doesn't exist yet t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) // but record the existing type, if any t := obj.Type().(*types.Named) p.record(t) // read underlying type t0.SetUnderlying(p.typ()) // read associated methods for i, n := 0, p.int(); i < n; i++ { t0.AddMethod(types.NewFunc(token.NoPos, pkg, p.string(), p.typ().(*types.Signature))) } return t default: panic(fmt.Sprintf("unexpected type tag %d", i)) } }
// 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), Pkg: 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.Pkg.Path()) } sort.Strings(pkgpaths) init.emit(new(Return)) init.finishBody() testmain.init = init testmain.Pkg.MarkComplete() testmain.Members[init.name] = init // For debugging convenience, define an unexported const // that enumerates the packages. packagesConst := types.NewConst(token.NoPos, testmain.Pkg, "packages", tString, exact.MakeString(strings.Join(pkgpaths, " "))) memberFromObject(testmain, packagesConst, nil) // Create main *types.Func and *ssa.Function mainFunc := types.NewFunc(token.NoPos, testmain.Pkg, "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.Pkg] = testmain return testmain }
// CreateTestMainPackage creates and returns a synthetic "testmain" // package for the specified package if it defines tests, benchmarks or // executable examples, or nil otherwise. The new package is named // "main" and provides a function named "main" that runs the tests, // similar to the one that would be created by the 'go test' tool. // // Subsequent calls to prog.AllPackages include the new package. // The package pkg must belong to the program prog. func (prog *Program) CreateTestMainPackage(pkg *Package) *Package { if pkg.Prog != prog { log.Fatal("Package does not belong to Program") } tests, benchmarks, examples, testMainFunc := FindTests(pkg) if testMainFunc == nil && tests == nil && benchmarks == nil && examples == nil { return nil } testmain := &Package{ Prog: prog, Members: make(map[string]Member), values: make(map[types.Object]Value), Pkg: types.NewPackage(pkg.Pkg.Path()+"$testmain", "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 package under test. var v Call v.Call.Value = pkg.init v.setType(types.NewTuple()) init.emit(&v) init.emit(new(Return)) init.finishBody() testmain.init = init testmain.Pkg.MarkComplete() testmain.Members[init.name] = init // Create main *types.Func and *Function mainFunc := types.NewFunc(token.NoPos, testmain.Pkg, "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{...} // if TestMain is defined { // m := testing.MainStart(match, tests, benchmarks, examples) // return TestMain(m) // } else { // return 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() var c Call 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()), } if testMainFunc != nil { // Emit: m := testing.MainStart(matcher, tests, benchmarks, examples). // (Main and MainStart have the same parameters.) mainStart := testingPkg.Func("MainStart") c.Call.Value = mainStart c.setType(mainStart.Signature.Results().At(0).Type()) // *testing.M m := main.emit(&c) // Emit: return TestMain(m) var c2 Call c2.Call.Value = testMainFunc c2.Call.Args = []Value{m} emitTailCall(main, &c2) } else { // Emit: return testing.Main(matcher, tests, benchmarks, examples) c.Call.Value = testingMain emitTailCall(main, &c) } } else { // The program does not import "testing", but FindTests // returned non-nil, which must mean there were Examples // but no Test, Benchmark, or TestMain functions. // We'll simply call them from testmain.main; this will // ensure they don't panic, but will not check any // "Output:" comments. // (We should not execute an Example that has no // "Output:" comment, but it's impossible to tell here.) 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.Pkg] = testmain return testmain }