loader: improve error messages for failed imports

Add location information (whenever possible) to failed imports. This
helps in debugging where an incorrect import came from.

For example, show the following error message:

    /home/ayke/src/github.com/tinygo-org/tinygo/src/machine/machine.go:5:8: cannot find package "foobar" in any of:
        /usr/local/go/src/foobar (from $GOROOT)
        /home/ayke/src/foobar (from $GOPATH)

Instead of the following:

    error: cannot find package "foobar" in any of:
        /usr/local/go/src/foobar (from $GOROOT)
        /home/ayke/src/foobar (from $GOPATH)
Этот коммит содержится в:
Ayke van Laethem 2019-12-31 17:44:34 +01:00 коммит произвёл Ron Evans
родитель b424056721
коммит 69c1d802e1
2 изменённых файлов: 20 добавлений и 5 удалений

Просмотреть файл

@ -251,13 +251,17 @@ func (c *Compiler) Compile(mainPath string) []error {
return []error{err} return []error{err}
} }
} else { } else {
_, err = lprogram.Import(mainPath, wd) _, err = lprogram.Import(mainPath, wd, token.Position{
Filename: "build command-line-arguments",
})
if err != nil { if err != nil {
return []error{err} return []error{err}
} }
} }
_, err = lprogram.Import("runtime", "") _, err = lprogram.Import("runtime", "", token.Position{
Filename: "build default import",
})
if err != nil { if err != nil {
return []error{err} return []error{err}
} }

Просмотреть файл

@ -6,6 +6,7 @@ import (
"go/ast" "go/ast"
"go/build" "go/build"
"go/parser" "go/parser"
"go/scanner"
"go/token" "go/token"
"go/types" "go/types"
"os" "os"
@ -46,7 +47,7 @@ type Package struct {
// Import loads the given package relative to srcDir (for the vendor directory). // Import loads the given package relative to srcDir (for the vendor directory).
// It only loads the current package without recursion. // It only loads the current package without recursion.
func (p *Program) Import(path, srcDir string) (*Package, error) { func (p *Program) Import(path, srcDir string, pos token.Position) (*Package, error) {
if p.Packages == nil { if p.Packages == nil {
p.Packages = make(map[string]*Package) p.Packages = make(map[string]*Package)
} }
@ -59,7 +60,10 @@ func (p *Program) Import(path, srcDir string) (*Package, error) {
} }
buildPkg, err := ctx.Import(path, srcDir, build.ImportComment) buildPkg, err := ctx.Import(path, srcDir, build.ImportComment)
if err != nil { if err != nil {
return nil, err return nil, scanner.Error{
Pos: pos,
Msg: err.Error(), // TODO: define a new error type that will wrap the inner error
}
} }
if existingPkg, ok := p.Packages[buildPkg.ImportPath]; ok { if existingPkg, ok := p.Packages[buildPkg.ImportPath]; ok {
// Already imported, or at least started the import. // Already imported, or at least started the import.
@ -467,7 +471,14 @@ func (p *Package) importRecursively(includeTests bool) error {
if _, ok := p.Imports[to]; ok { if _, ok := p.Imports[to]; ok {
continue continue
} }
importedPkg, err := p.Program.Import(to, p.Package.Dir) // Find error location.
var pos token.Position
if len(p.Package.ImportPos[to]) > 0 {
pos = p.Package.ImportPos[to][0]
} else {
pos = token.Position{Filename: p.Package.ImportPath}
}
importedPkg, err := p.Program.Import(to, p.Package.Dir, pos)
if err != nil { if err != nil {
if err, ok := err.(*ImportCycleError); ok { if err, ok := err.(*ImportCycleError); ok {
err.Packages = append([]string{p.ImportPath}, err.Packages...) err.Packages = append([]string{p.ImportPath}, err.Packages...)