diff --git a/loader/errors.go b/loader/errors.go index b8e4860a..c25652ee 100644 --- a/loader/errors.go +++ b/loader/errors.go @@ -1,5 +1,10 @@ package loader +import ( + "go/token" + "strings" +) + // Errors contains a list of parser errors or a list of typechecker errors for // the given package. type Errors struct { @@ -15,13 +20,20 @@ func (e Errors) Error() string { // packages is a list from the root package to the leaf package that imports one // of the packages in the list. type ImportCycleError struct { - Packages []string + Packages []string + ImportPositions []token.Position } func (e *ImportCycleError) Error() string { - msg := "import cycle: " + e.Packages[0] - for _, path := range e.Packages[1:] { - msg += " → " + path + var msg strings.Builder + msg.WriteString("import cycle:\n\t") + msg.WriteString(strings.Join(e.Packages, "\n\t")) + msg.WriteString("\n at ") + for i, pos := range e.ImportPositions { + if i > 0 { + msg.WriteString(", ") + } + msg.WriteString(pos.String()) } - return msg + return msg.String() } diff --git a/loader/loader.go b/loader/loader.go index 7c888757..54fbfea9 100644 --- a/loader/loader.go +++ b/loader/loader.go @@ -166,7 +166,9 @@ func (p *Program) Parse() error { err := pkg.importRecursively() if err != nil { if err, ok := err.(*ImportCycleError); ok { - err.Packages = append([]string{pkg.ImportPath}, err.Packages...) + if pkg.ImportPath != err.Packages[0] { + err.Packages = append([]string{pkg.ImportPath}, err.Packages...) + } } return err } @@ -339,10 +341,13 @@ func (p *Package) importRecursively() error { return err } if importedPkg.Importing { - return &ImportCycleError{[]string{p.ImportPath, importedPkg.ImportPath}} + return &ImportCycleError{[]string{p.ImportPath, importedPkg.ImportPath}, p.ImportPos[to]} } err = importedPkg.importRecursively() if err != nil { + if err, ok := err.(*ImportCycleError); ok { + err.Packages = append([]string{p.ImportPath}, err.Packages...) + } return err } p.Imports[to] = importedPkg