go.tools/ssa: fix crash in SSA builder when using GCImporter to satisfy imports (ssadump -build=G).

Packages were not being created for all types.Packages,
specifically, indirectly imported packages were missing.
(*Program).CreatePackages now iterates over the type-checker's
package map too.

Also: removed all concurrency from importer.  I think it was
incorrect (and hard to fix).

Also: change LoadInitialPackages so that all named packages
are loaded from source.  This happens regardless of whether
GCImporter is used to satisfy imports.

Details:
- importer.Config.SourceImports flag determines whether to
  load all packages from *.go source.
  (Before, this was indicated by Config.Build != nil.)
- importer.Config.Build field effectively defaults to
  &go/build.Default.  A zero importer.Config is now usable.
- importer.Importer.Config field is now exported.
- LoadPackage renamed to ImportPackage since the resulting
  packages may come from GCImporter (and be incomplete).
- doImport and ImportPackage fused.

Fixes golang/go#7028

R=gri, axwalk
CC=golang-codereviews
https://golang.org/cl/48770043
This commit is contained in:
Alan Donovan 2014-01-09 14:11:54 -05:00
parent df3357d07f
commit 3d82e7e94a
15 changed files with 129 additions and 193 deletions

View File

@ -73,7 +73,10 @@ func main() {
flag.Parse()
args := flag.Args()
impctx := importer.Config{Build: &build.Default}
impctx := importer.Config{
Build: &build.Default,
SourceImports: true,
}
// TODO(adonovan): make go/types choose its default Sizes from
// build.Default or a specified *build.Context.
var wordSize int64 = 8
@ -103,7 +106,7 @@ func main() {
case 'N':
mode |= ssa.NaiveForm
case 'G':
impctx.Build = nil
impctx.SourceImports = false
case 'L':
mode |= ssa.BuildSerially
default:
@ -147,8 +150,8 @@ func main() {
// The interpreter needs the runtime package.
if *runFlag {
if _, err := imp.LoadPackage("runtime"); err != nil {
log.Fatalf("LoadPackage(runtime) failed: %s", err)
if _, err := imp.ImportPackage("runtime"); err != nil {
log.Fatalf("ImportPackage(runtime) failed: %s", err)
}
}

View File

@ -50,7 +50,6 @@ import (
"go/token"
"os"
"strings"
"sync"
"code.google.com/p/go.tools/astutil"
"code.google.com/p/go.tools/go/exact"
@ -60,32 +59,28 @@ import (
// An Importer's exported methods are not thread-safe.
type Importer struct {
Fset *token.FileSet // position info for all files seen
config *Config // the client configuration, unmodified
importfn types.Importer // client's type import function
augment map[string]bool // packages to be augmented by TestFiles when imported
allPackagesMu sync.Mutex // guards 'allPackages' during internal concurrency
allPackages []*PackageInfo // all packages, including non-importable ones
importedMu sync.Mutex // guards 'imported'
imported map[string]*importInfo // all imported packages (incl. failures) by import path
Fset *token.FileSet // position info for all files seen
Config *Config // the client configuration, unmodified
importfn types.Importer // client's type import function
srcpkgs map[string]bool // for each package to load from source, whether to augment
allPackages []*PackageInfo // all packages, including non-importable ones
imported map[string]*importInfo // all imported packages (incl. failures) by import path
}
// importInfo holds internal information about each import path.
type importInfo struct {
path string // import path
info *PackageInfo // results of typechecking (including type errors)
err error // reason for failure to construct a package
ready chan struct{} // channel close is notification of ready state
path string // import path
info *PackageInfo // results of typechecking (including type errors)
err error // reason for failure to construct a package
}
// Config specifies the configuration for the importer.
// The zero value for Config is a ready-to-use default configuration.
type Config struct {
// TypeChecker contains options relating to the type checker.
//
// The supplied IgnoreFuncBodies is not used; the effective
// value comes from the TypeCheckFuncBodies func below.
//
// All callbacks must be thread-safe.
TypeChecker types.Config
// TypeCheckFuncBodies is a predicate over package import
@ -94,23 +89,35 @@ type Config struct {
// its function bodies; this can be used to quickly load
// dependencies from source. If nil, all func bodies are type
// checked.
//
// Must be thread-safe.
//
TypeCheckFuncBodies func(string) bool
// If Build is non-nil, it is used to satisfy imports.
// SourceImports determines whether to satisfy all imports by
// loading Go source code.
//
// If it is nil, binary object files produced by the gc
// compiler will be loaded instead of source code for all
// imported packages. Such files supply only the types of
// If false, the TypeChecker.Import mechanism will be used
// instead. Since that typically supplies only the types of
// package-level declarations and values of constants, but no
// code, so this mode will not yield a whole program. It is
// intended for analyses that perform intraprocedural analysis
// of a single package.
// code, it will not yield a whole program. It is intended
// for analyses that perform intraprocedural analysis of a
// single package.
//
// The importer's initial packages are always loaded from
// source, regardless of this flag's setting.
SourceImports bool
// If Build is non-nil, it is used to locate source packages.
// Otherwise &build.Default is used.
Build *build.Context
}
// build returns the effective build context.
func (c *Config) build() *build.Context {
if c.Build != nil {
return c.Build
}
return &build.Default
}
// New returns a new, empty Importer using configuration options
// specified by config.
//
@ -129,27 +136,27 @@ func New(config *Config) *Importer {
imp := &Importer{
Fset: token.NewFileSet(),
config: config,
Config: config,
importfn: importfn,
augment: make(map[string]bool),
srcpkgs: make(map[string]bool),
imported: make(map[string]*importInfo),
}
return imp
}
// AllPackages returns a new slice containing all packages loaded by
// importer imp.
// AllPackages returns a new slice containing all complete packages
// loaded by importer imp.
//
// This returns only packages that were loaded from source or directly
// imported from a source package. It does not include packages
// indirectly referenced by a binary package; they are found in
// config.TypeChecker.Packages.
// TODO(adonovan): rethink this API.
//
func (imp *Importer) AllPackages() []*PackageInfo {
return append([]*PackageInfo(nil), imp.allPackages...)
}
func (imp *Importer) addPackage(info *PackageInfo) {
imp.allPackagesMu.Lock()
imp.allPackages = append(imp.allPackages, info)
imp.allPackagesMu.Unlock()
}
// doImport imports the package denoted by path.
// It implements the types.Importer prototype.
//
@ -163,40 +170,7 @@ func (imp *Importer) addPackage(info *PackageInfo) {
// the types.Config.Error callback (the first of which is also saved
// in the package's PackageInfo).
//
// Idempotent and thread-safe.
//
//
// TODO(gri): The imports map (an alias for TypeChecker.Packages) must
// not be concurrently accessed. Today, the only (non-test) accesses
// of this map are in the client-supplied implementation of the
// importer function, i.e. the function below. But this is a fragile
// API because if go/types ever starts to access this map, it and its
// clients will have to agree to use the same mutex.
// Two better ideas:
//
// (1) require that the importer functions be stateful and have this
// map be part of that internal state.
// Pro: good encapsulation.
// Con: we can't have different importers collaborate, e.g.
// we can't use a source importer for some packages and
// GcImport for others since they'd each have a distinct map.
//
// (2) have there be a single map in go/types.Config, but expose
// lookup and update behind an interface and pass that interface
// to the importer implementations.
// Pro: sharing of the map among importers.
//
// This is idempotent but still doesn't address the issue of
// atomicity: when loading packages concurrently, we want to avoid
// the benign but suboptimal situation of two goroutines both
// importing "fmt", finding it not present, doing all the work, and
// double-updating the map.
// The interface to the map needs to express the idea that when a
// caller requests an import from the map and finds it not present,
// then it (and no other goroutine) becomes responsible for loading
// the package and updating the map; other goroutines should block
// until then. That's exactly what doImport0 below does; I think
// some of that logic should migrate into go/types.check.resolveFiles.
// Idempotent.
//
func (imp *Importer) doImport(imports map[string]*types.Package, path string) (*types.Package, error) {
// Package unsafe is handled specially, and has no PackageInfo.
@ -205,99 +179,67 @@ func (imp *Importer) doImport(imports map[string]*types.Package, path string) (*
return types.Unsafe, nil
}
info, err := imp.doImport0(imports, path)
info, err := imp.ImportPackage(path)
if err != nil {
return nil, err
}
if imports != nil {
// Update the package's imports map, whether success or failure.
//
// types.Package.Imports() is used by PackageInfo.Imports and
// thence by ssa.builder.
// TODO(gri): given that it doesn't specify whether it
// contains direct or transitive dependencies, it probably
// shouldn't be exposed. This package can make its own
// arrangements to implement PackageInfo.Imports().
importsMu.Lock()
imports[path] = info.Pkg
importsMu.Unlock()
}
// Update the type checker's package map on success.
imports[path] = info.Pkg
return info.Pkg, nil
}
var importsMu sync.Mutex // hack; see comment at doImport
// Like doImport, but returns a PackageInfo.
// ImportPackage imports the package whose import path is path, plus
// its necessary dependencies.
//
// Precondition: path != "unsafe".
func (imp *Importer) doImport0(imports map[string]*types.Package, path string) (*PackageInfo, error) {
imp.importedMu.Lock()
//
func (imp *Importer) ImportPackage(path string) (*PackageInfo, error) {
ii, ok := imp.imported[path]
if !ok {
ii = &importInfo{path: path, ready: make(chan struct{})}
ii = &importInfo{path: path}
imp.imported[path] = ii
}
imp.importedMu.Unlock()
if !ok {
// Find and create the actual package.
if imp.config.Build != nil {
imp.importSource(path, ii)
if augment, ok := imp.srcpkgs[ii.path]; ok || imp.Config.SourceImports {
which := "g" // load *.go files
if augment {
which = "gt" // augment package by in-package *_test.go files
}
imp.loadFromSource(ii, which)
} else {
imp.importBinary(imports, ii)
imp.loadFromBinary(ii)
}
if ii.info != nil {
ii.info.Importable = true
}
close(ii.ready) // enter ready state and wake up waiters
} else {
<-ii.ready // wait for ready condition
}
// Invariant: ii is ready.
return ii.info, ii.err
}
// importBinary implements package loading from the client-supplied
// loadFromBinary implements package loading from the client-supplied
// external source, e.g. object files from the gc compiler.
//
func (imp *Importer) importBinary(imports map[string]*types.Package, ii *importInfo) {
pkg, err := imp.importfn(imports, ii.path)
func (imp *Importer) loadFromBinary(ii *importInfo) {
pkg, err := imp.importfn(imp.Config.TypeChecker.Packages, ii.path)
if pkg != nil {
ii.info = &PackageInfo{Pkg: pkg}
imp.addPackage(ii.info)
imp.allPackages = append(imp.allPackages, ii.info)
} else {
ii.err = err
}
}
// importSource implements package loading by parsing Go source files
// located by go/build.
// loadFromSource implements package loading by parsing Go source files
// located by go/build. which indicates which files to include in the
// package.
//
func (imp *Importer) importSource(path string, ii *importInfo) {
which := "g" // load *.go files
if imp.augment[path] {
which = "gt" // augment package by in-package *_test.go files
}
if files, err := parsePackageFiles(imp.config.Build, imp.Fset, path, which); err == nil {
// Prefetch the imports asynchronously.
for path := range importsOf(path, files) {
go func(path string) { imp.doImport(nil, path) }(path)
}
func (imp *Importer) loadFromSource(ii *importInfo, which string) {
if files, err := parsePackageFiles(imp.Config.build(), imp.Fset, ii.path, which); err == nil {
// Type-check the package.
ii.info = imp.CreatePackage(path, files...)
// We needn't wait for the prefetching goroutines to
// finish. Each one either runs quickly and populates
// the imported map, in which case the type checker
// will wait for the map entry to become ready; or, it
// runs slowly, even after we return, but then becomes
// just another map waiter, in which case it won't
// mutate anything.
ii.info = imp.CreatePackage(ii.path, files...)
} else {
ii.err = err
}
@ -335,9 +277,9 @@ func (imp *Importer) CreatePackage(path string, files ...*ast.File) *PackageInfo
}
// Use a copy of the types.Config so we can vary IgnoreFuncBodies.
tc := imp.config.TypeChecker
tc := imp.Config.TypeChecker
tc.IgnoreFuncBodies = false
if f := imp.config.TypeCheckFuncBodies; f != nil {
if f := imp.Config.TypeCheckFuncBodies; f != nil {
tc.IgnoreFuncBodies = !f(path)
}
if tc.Error == nil {
@ -345,7 +287,7 @@ func (imp *Importer) CreatePackage(path string, files ...*ast.File) *PackageInfo
}
tc.Import = imp.doImport // doImport wraps the user's importfn, effectively
info.Pkg, info.Err = tc.Check(path, imp.Fset, files, &info.Info)
imp.addPackage(info)
imp.allPackages = append(imp.allPackages, info)
return info
}
@ -418,6 +360,7 @@ func (imp *Importer) LoadInitialPackages(args []string) ([]*PackageInfo, []strin
// Pass 1: parse the sets of files for each package.
var pkgs []*initialPkg
var seenAugmented bool
for len(args) > 0 {
arg := args[0]
args = args[1:]
@ -444,28 +387,24 @@ func (imp *Importer) LoadInitialPackages(args []string) ([]*PackageInfo, []strin
continue // ignore; has no PackageInfo
}
pkg := &initialPkg{
pkgs = append(pkgs, &initialPkg{
path: path,
importable: true,
}
pkgs = append(pkgs, pkg)
})
imp.srcpkgs[path] = false // unaugmented source package
if path != arg {
continue // had "notest:" prefix
}
if imp.config.Build == nil {
continue // can't locate *_test.go files
}
// TODO(adonovan): due to limitations of the current type
// checker design, we can augment at most one package.
if len(imp.augment) > 0 {
if seenAugmented {
continue // don't attempt a second
}
// Load the external test package.
xtestFiles, err := parsePackageFiles(imp.config.Build, imp.Fset, path, "x")
xtestFiles, err := parsePackageFiles(imp.Config.build(), imp.Fset, path, "x")
if err != nil {
return nil, nil, err
}
@ -479,24 +418,22 @@ func (imp *Importer) LoadInitialPackages(args []string) ([]*PackageInfo, []strin
// Mark the non-xtest package for augmentation with
// in-package *_test.go files when we import it below.
imp.augment[pkg.path] = true
imp.srcpkgs[path] = true
seenAugmented = true
}
}
// Pass 2: type-check each set of files to make a package.
var infos []*PackageInfo
imports := make(map[string]*types.Package) // keep importBinary happy
for _, pkg := range pkgs {
var info *PackageInfo
if pkg.importable {
// import package
var err error
info, err = imp.doImport0(imports, pkg.path)
info, err = imp.ImportPackage(pkg.path)
if err != nil {
return nil, nil, err // e.g. parse error (but not type error)
}
} else {
// create package
info = imp.CreatePackage(pkg.path, pkg.files...)
}
infos = append(infos, info)
@ -509,17 +446,9 @@ func (imp *Importer) LoadInitialPackages(args []string) ([]*PackageInfo, []strin
return infos, args, nil
}
// LoadPackage loads and type-checks the package whose import path is
// path, plus its necessary dependencies.
//
func (imp *Importer) LoadPackage(path string) (*PackageInfo, error) {
imports := make(map[string]*types.Package) // keep importBinary happy
return imp.doImport0(imports, path)
}
type initialPkg struct {
path string // the package's import path
importable bool // add package to import map false for main and xtests)
importable bool // add package to import map (false for main and xtests)
files []*ast.File // set of files (non-importable packages only)
}

View File

@ -6,18 +6,15 @@ package importer_test
import (
"fmt"
"go/build"
"testing"
"code.google.com/p/go.tools/importer"
)
func TestLoadInitialPackages(t *testing.T) {
ctxt := &importer.Config{Build: &build.Default}
// Failed load: bad first import path causes parsePackageFiles to fail.
args := []string{"nosuchpkg", "errors"}
if _, _, err := importer.New(ctxt).LoadInitialPackages(args); err == nil {
if _, _, err := importer.New(&importer.Config{}).LoadInitialPackages(args); err == nil {
t.Errorf("LoadInitialPackages(%q) succeeded, want failure", args)
} else {
// cannot find package: ok.
@ -25,7 +22,7 @@ func TestLoadInitialPackages(t *testing.T) {
// Failed load: bad second import path proceeds to doImport0, which fails.
args = []string{"errors", "nosuchpkg"}
if _, _, err := importer.New(ctxt).LoadInitialPackages(args); err == nil {
if _, _, err := importer.New(&importer.Config{}).LoadInitialPackages(args); err == nil {
t.Errorf("LoadInitialPackages(%q) succeeded, want failure", args)
} else {
// cannot find package: ok
@ -33,7 +30,7 @@ func TestLoadInitialPackages(t *testing.T) {
// Successful load.
args = []string{"fmt", "errors", "testdata/a.go,testdata/b.go", "--", "surplus"}
imp := importer.New(ctxt)
imp := importer.New(&importer.Config{})
infos, rest, err := imp.LoadInitialPackages(args)
if err != nil {
t.Errorf("LoadInitialPackages(%q) failed: %s", args, err)

View File

@ -82,7 +82,7 @@ func TestEnclosingFunction(t *testing.T) {
"900", "func@2.27"},
}
for _, test := range tests {
imp := importer.New(new(importer.Config)) // (NB: no go/build.Config)
imp := importer.New(&importer.Config{})
f, start, end := findInterval(t, imp.Fset, test.input, test.substr)
if f == nil {
continue

View File

@ -192,7 +192,7 @@ func (res *Result) Serial() *serial.Result {
// Clients that intend to perform multiple queries against the same
// analysis scope should use this pattern instead:
//
// imp := importer.New(&importer.Config{Build: buildContext})
// imp := importer.New(&importer.Config{Build: buildContext, SourceImports: true})
// o, err := oracle.New(imp, args, nil)
// if err != nil { ... }
// for ... {
@ -219,7 +219,7 @@ func Query(args []string, mode, pos string, ptalog io.Writer, buildContext *buil
return nil, fmt.Errorf("invalid mode type: %q", mode)
}
impcfg := importer.Config{Build: buildContext}
impcfg := importer.Config{Build: buildContext, SourceImports: true}
// For queries needing only a single typed package,
// reduce the analysis scope to that package.

View File

@ -6,7 +6,6 @@ package pointer_test
import (
"fmt"
"go/build"
"go/parser"
"sort"
@ -41,8 +40,7 @@ func main() {
}
`
// Construct an importer.
// Imports will be loaded as if by 'go build'.
imp := importer.New(&importer.Config{Build: &build.Default})
imp := importer.New(&importer.Config{SourceImports: true})
// Parse the input file.
file, err := parser.ParseFile(imp.Fset, "myprog.go", myprog, 0)

View File

@ -12,7 +12,6 @@ import (
"bytes"
"errors"
"fmt"
"go/build"
"go/parser"
"go/token"
"io/ioutil"
@ -152,7 +151,7 @@ func findProbe(prog *ssa.Program, probes map[*ssa.CallCommon]pointer.Pointer, e
}
func doOneInput(input, filename string) bool {
impctx := &importer.Config{Build: &build.Default}
impctx := &importer.Config{SourceImports: true}
imp := importer.New(impctx)
// Parsing.

View File

@ -810,9 +810,6 @@ func (b *builder) setCallFunc(fn *Function, e *ast.CallExpr, c *CallCommon) {
c.Method = obj
} else {
// "Call"-mode call.
// TODO(adonovan): fix: in -build=G
// mode, declaredFunc panics for
// cross-package calls.
c.Value = fn.Prog.declaredFunc(obj)
c.Args = append(c.Args, v)
}

View File

@ -40,7 +40,7 @@ func main() {
w.Write(nil) // interface invoke of external declared method
}
`
imp := importer.New(new(importer.Config)) // no go/build.Context; uses GC importer
imp := importer.New(&importer.Config{})
f, err := parser.ParseFile(imp.Fset, "<input>", test, 0)
if err != nil {
@ -58,10 +58,16 @@ func main() {
mainPkg := prog.Package(mainInfo.Pkg)
mainPkg.Build()
// Only the main package and its immediate dependencies are loaded.
deps := []string{"bytes", "io", "testing"}
// The main package, its direct and indirect dependencies are loaded.
deps := []string{
// directly imported dependencies:
"bytes", "io", "testing",
// indirect dependencies (partial list):
"errors", "fmt", "os", "runtime",
}
all := prog.AllPackages()
if len(all) != 1+len(deps) {
if len(all) <= len(deps) {
t.Errorf("unexpected set of loaded packages: %q", all)
}
for _, path := range deps {
@ -198,7 +204,7 @@ func TestTypesWithMethodSets(t *testing.T) {
},
}
for i, test := range tests {
imp := importer.New(new(importer.Config)) // no go/build.Context; uses GC importer
imp := importer.New(&importer.Config{})
f, err := parser.ParseFile(imp.Fset, "<input>", test.input, 0)
if err != nil {

View File

@ -250,6 +250,8 @@ func (prog *Program) CreatePackage(info *importer.PackageInfo) *Package {
//
func (prog *Program) CreatePackages(imp *importer.Importer) error {
var errpkgs []string
// Create source packages and directly imported packages.
for _, info := range imp.AllPackages() {
if info.Err != nil {
errpkgs = append(errpkgs, info.Pkg.Path())
@ -257,6 +259,15 @@ func (prog *Program) CreatePackages(imp *importer.Importer) error {
prog.CreatePackage(info)
}
}
// Create indirectly imported packages.
for _, obj := range imp.Config.TypeChecker.Packages {
prog.CreatePackage(&importer.PackageInfo{
Pkg: obj,
Importable: true,
})
}
if errpkgs != nil {
return fmt.Errorf("couldn't create these SSA packages due to type errors: %s",
strings.Join(errpkgs, ", "))

View File

@ -6,7 +6,6 @@ package ssa_test
import (
"fmt"
"go/build"
"go/parser"
"os"
@ -42,8 +41,8 @@ func main() {
fmt.Println(message)
}
`
// Construct an importer. Imports will be loaded as if by 'go build'.
imp := importer.New(&importer.Config{Build: &build.Default})
// Construct an importer.
imp := importer.New(&importer.Config{})
// Parse the input file.
file, err := parser.ParseFile(imp.Fset, "hello.go", hello, 0)

View File

@ -168,7 +168,7 @@ func run(t *testing.T, dir, input string, success successPredicate) bool {
inputs = append(inputs, dir+i)
}
imp := importer.New(&importer.Config{Build: &build.Default})
imp := importer.New(&importer.Config{SourceImports: true})
// TODO(adonovan): use LoadInitialPackages, then un-export ParseFiles.
// Then add the following packages' tests, which pass:
// "flag", "unicode", "unicode/utf8", "testing", "log", "path".
@ -194,8 +194,8 @@ func run(t *testing.T, dir, input string, success successPredicate) bool {
hint = fmt.Sprintf("To dump SSA representation, run:\n%% go build code.google.com/p/go.tools/cmd/ssadump && ./ssadump -build=CFP %s\n", input)
mainInfo := imp.CreatePackage(files[0].Name.Name, files...)
if _, err := imp.LoadPackage("runtime"); err != nil {
t.Errorf("LoadPackage(runtime) failed: %s", err)
if _, err := imp.ImportPackage("runtime"); err != nil {
t.Errorf("ImportPackage(runtime) failed: %s", err)
}
prog := ssa.NewProgram(imp.Fset, ssa.SanityCheckFunctions)
@ -321,7 +321,7 @@ func TestTestmainPackage(t *testing.T) {
// CreateTestMainPackage should return nil if there were no tests.
func TestNullTestmainPackage(t *testing.T) {
imp := importer.New(&importer.Config{Build: &build.Default})
imp := importer.New(&importer.Config{})
files, err := importer.ParseFiles(imp.Fset, ".", "testdata/b_test.go")
if err != nil {
t.Fatalf("ParseFiles failed: %s", err)

View File

@ -24,7 +24,7 @@ import (
)
func TestObjValueLookup(t *testing.T) {
imp := importer.New(new(importer.Config)) // (uses GCImporter)
imp := importer.New(&importer.Config{})
f, err := parser.ParseFile(imp.Fset, "testdata/objlookup.go", nil, parser.ParseComments)
if err != nil {
t.Error(err)
@ -186,7 +186,7 @@ func checkVarValue(t *testing.T, prog *ssa.Program, pkg *ssa.Package, ref []ast.
// Ensure that, in debug mode, we can determine the ssa.Value
// corresponding to every ast.Expr.
func TestValueForExpr(t *testing.T) {
imp := importer.New(new(importer.Config)) // (uses GCImporter)
imp := importer.New(&importer.Config{})
f, err := parser.ParseFile(imp.Fset, "testdata/valueforexpr.go", nil, parser.ParseComments)
if err != nil {
t.Error(err)

View File

@ -15,7 +15,7 @@ import (
)
func TestSwitches(t *testing.T) {
imp := importer.New(new(importer.Config)) // (uses GCImporter)
imp := importer.New(&importer.Config{})
f, err := parser.ParseFile(imp.Fset, "testdata/switches.go", nil, parser.ParseComments)
if err != nil {
t.Error(err)

View File

@ -10,7 +10,6 @@ package ssa_test
// Run test with GOMAXPROCS=8.
import (
"go/build"
"go/token"
"os"
"path/filepath"
@ -52,12 +51,10 @@ func allPackages() []string {
}
func TestStdlib(t *testing.T) {
impctx := importer.Config{Build: &build.Default}
// Load, parse and type-check the program.
t0 := time.Now()
imp := importer.New(&impctx)
imp := importer.New(&importer.Config{})
if _, _, err := imp.LoadInitialPackages(allPackages()); err != nil {
t.Errorf("LoadInitialPackages failed: %s", err)