1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
5 // This file is a modified copy of $GOROOT/src/go/internal/gcimporter/gcimporter.go,
6 // but it also contains the original source-based importer code for Go1.6.
7 // Once we stop supporting 1.6, we can remove that code.
9 // Package gcimporter provides various functions for reading
10 // gc-generated object files that can be used to implement the
11 // Importer interface defined by the Go 1.5 standard library package.
12 package gcimporter // import "golang.org/x/tools/go/internal/gcimporter"
32 // debugging/development support
35 var pkgExts = [...]string{".a", ".o"}
37 // FindPkg returns the filename and unique package id for an import
38 // path based on package information provided by build.Import (using
39 // the build.Default build.Context). A relative srcDir is interpreted
40 // relative to the current working directory.
41 // If no file was found, an empty filename is returned.
43 func FindPkg(path, srcDir string) (filename, id string) {
51 // "x" -> "$GOPATH/pkg/$GOOS_$GOARCH/x.ext", "x"
52 // Don't require the source files to be present.
53 if abs, err := filepath.Abs(srcDir); err == nil { // see issue 14282
56 bp, _ := build.Import(path, srcDir, build.FindOnly|build.AllowBinary)
58 id = path // make sure we have an id to print in error message
61 noext = strings.TrimSuffix(bp.PkgObj, ".a")
64 case build.IsLocalImport(path):
65 // "./x" -> "/this/directory/x.ext", "/this/directory/x"
66 noext = filepath.Join(srcDir, path)
69 case filepath.IsAbs(path):
70 // for completeness only - go/build.Import
71 // does not support absolute imports
72 // "/x" -> "/x.ext", "/x"
77 if false { // for debugging
79 fmt.Printf("%s -> %s\n", path, id)
84 for _, ext := range pkgExts {
85 filename = noext + ext
86 if f, err := os.Stat(filename); err == nil && !f.IsDir() {
91 filename = "" // not found
95 // ImportData imports a package by reading the gc-generated export data,
96 // adds the corresponding package object to the packages map indexed by id,
97 // and returns the object.
99 // The packages map must contains all packages already imported. The data
100 // reader position must be the beginning of the export data section. The
101 // filename is only used in error messages.
103 // If packages[id] contains the completely imported package, that package
104 // can be used directly, and there is no need to call this function (but
105 // there is also no harm but for extra time used).
107 func ImportData(packages map[string]*types.Package, filename, id string, data io.Reader) (pkg *types.Package, err error) {
108 // support for parser error handling
110 switch r := recover().(type) {
116 panic(r) // internal error
121 p.init(filename, id, data, packages)
122 pkg = p.parseExport()
127 // Import imports a gc-generated package given its import path and srcDir, adds
128 // the corresponding package object to the packages map, and returns the object.
129 // The packages map must contain all packages already imported.
131 func Import(packages map[string]*types.Package, path, srcDir string, lookup func(path string) (io.ReadCloser, error)) (pkg *types.Package, err error) {
133 var filename, id string
135 // With custom lookup specified, assume that caller has
136 // converted path to a canonical import path for use in the map.
137 if path == "unsafe" {
138 return types.Unsafe, nil
142 // No need to re-import if the package was imported completely before.
143 if pkg = packages[id]; pkg != nil && pkg.Complete() {
146 f, err := lookup(path)
152 filename, id = FindPkg(path, srcDir)
154 if path == "unsafe" {
155 return types.Unsafe, nil
157 return nil, fmt.Errorf("can't find import: %q", id)
160 // no need to re-import if the package was imported completely before
161 if pkg = packages[id]; pkg != nil && pkg.Complete() {
166 f, err := os.Open(filename)
172 // add file name to error
173 err = fmt.Errorf("%s: %v", filename, err)
181 buf := bufio.NewReader(rc)
182 if hdr, err = FindExportData(buf); err != nil {
188 // Work-around if we don't have a filename; happens only if lookup != nil.
189 // Either way, the filename is only needed for importer error messages, so
194 return ImportData(packages, filename, id, buf)
198 data, err = ioutil.ReadAll(buf)
203 // TODO(gri): allow clients of go/importer to provide a FileSet.
204 // Or, define a new standard go/types/gcexportdata package.
205 fset := token.NewFileSet()
207 // The indexed export format starts with an 'i'; the older
208 // binary export format starts with a 'c', 'd', or 'v'
209 // (from "version"). Select appropriate importer.
210 if len(data) > 0 && data[0] == 'i' {
211 _, pkg, err = IImportData(fset, packages, data[1:], id)
213 _, pkg, err = BImportData(fset, packages, data, id)
217 err = fmt.Errorf("unknown export data header: %q", hdr)
223 // ----------------------------------------------------------------------------
226 // TODO(gri) Imported objects don't have position information.
227 // Ideally use the debug table line info; alternatively
228 // create some fake position (or the position of the
229 // import). That way error messages referring to imported
230 // objects can print meaningful information.
232 // parser parses the exports inside a gc compiler-produced
233 // object/archive file and populates its scope with the results.
235 scanner scanner.Scanner
236 tok rune // current token
237 lit string // literal string; only valid for Ident, Int, String tokens
238 id string // package id of imported package
239 sharedPkgs map[string]*types.Package // package id -> package object (across importer)
240 localPkgs map[string]*types.Package // package id -> package object (just this package)
243 func (p *parser) init(filename, id string, src io.Reader, packages map[string]*types.Package) {
245 p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
246 p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | scanner.ScanChars | scanner.ScanStrings | scanner.ScanComments | scanner.SkipComments
247 p.scanner.Whitespace = 1<<'\t' | 1<<' '
248 p.scanner.Filename = filename // for good error messages
251 p.sharedPkgs = packages
253 // check consistency of packages map
254 for _, pkg := range packages {
255 if pkg.Name() == "" {
256 fmt.Printf("no package name for %s\n", pkg.Path())
262 func (p *parser) next() {
263 p.tok = p.scanner.Scan()
265 case scanner.Ident, scanner.Int, scanner.Char, scanner.String, '·':
266 p.lit = p.scanner.TokenText()
271 fmt.Printf("%s: %q -> %q\n", scanner.TokenString(p.tok), p.scanner.TokenText(), p.lit)
275 func declTypeName(pkg *types.Package, name string) *types.TypeName {
277 if obj := scope.Lookup(name); obj != nil {
278 return obj.(*types.TypeName)
280 obj := types.NewTypeName(token.NoPos, pkg, name, nil)
281 // a named type may be referred to before the underlying type
282 // is known - set it up
283 types.NewNamed(obj, nil, nil)
288 // ----------------------------------------------------------------------------
291 // Internal errors are boxed as importErrors.
292 type importError struct {
297 func (e importError) Error() string {
298 return fmt.Sprintf("import error %s (byte offset = %d): %s", e.pos, e.pos.Offset, e.err)
301 func (p *parser) error(err interface{}) {
302 if s, ok := err.(string); ok {
305 // panic with a runtime.Error if err is not an error
306 panic(importError{p.scanner.Pos(), err.(error)})
309 func (p *parser) errorf(format string, args ...interface{}) {
310 p.error(fmt.Sprintf(format, args...))
313 func (p *parser) expect(tok rune) string {
316 p.errorf("expected %s, got %s (%s)", scanner.TokenString(tok), scanner.TokenString(p.tok), lit)
322 func (p *parser) expectSpecial(tok string) {
323 sep := 'x' // not white space
325 for i < len(tok) && p.tok == rune(tok[i]) && sep > ' ' {
326 sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
331 p.errorf("expected %q, got %q", tok, tok[0:i])
335 func (p *parser) expectKeyword(keyword string) {
336 lit := p.expect(scanner.Ident)
338 p.errorf("expected keyword %s, got %q", keyword, lit)
342 // ----------------------------------------------------------------------------
343 // Qualified and unqualified names
345 // PackageId = string_lit .
347 func (p *parser) parsePackageId() string {
348 id, err := strconv.Unquote(p.expect(scanner.String))
352 // id == "" stands for the imported package id
353 // (only known at time of package installation)
360 // PackageName = ident .
362 func (p *parser) parsePackageName() string {
363 return p.expect(scanner.Ident)
366 // dotIdentifier = ( ident | '·' ) { ident | int | '·' } .
367 func (p *parser) parseDotIdent() string {
369 if p.tok != scanner.Int {
370 sep := 'x' // not white space
371 for (p.tok == scanner.Ident || p.tok == scanner.Int || p.tok == '·') && sep > ' ' {
373 sep = p.scanner.Peek() // if sep <= ' ', there is white space before the next token
378 p.expect(scanner.Ident) // use expect() for error handling
383 // QualifiedName = "@" PackageId "." ( "?" | dotIdentifier ) .
385 func (p *parser) parseQualifiedName() (id, name string) {
387 id = p.parsePackageId()
389 // Per rev f280b8a485fd (10/2/2013), qualified names may be used for anonymous fields.
393 name = p.parseDotIdent()
398 // getPkg returns the package for a given id. If the package is
399 // not found, create the package and add it to the p.localPkgs
400 // and p.sharedPkgs maps. name is the (expected) name of the
401 // package. If name == "", the package name is expected to be
402 // set later via an import clause in the export data.
404 // id identifies a package, usually by a canonical package path like
405 // "encoding/json" but possibly by a non-canonical import path like
408 func (p *parser) getPkg(id, name string) *types.Package {
409 // package unsafe is not in the packages maps - handle explicitly
414 pkg := p.localPkgs[id]
416 // first import of id from this package
417 pkg = p.sharedPkgs[id]
419 // first import of id by this importer;
420 // add (possibly unnamed) pkg to shared packages
421 pkg = types.NewPackage(id, name)
422 p.sharedPkgs[id] = pkg
424 // add (possibly unnamed) pkg to local packages
425 if p.localPkgs == nil {
426 p.localPkgs = make(map[string]*types.Package)
428 p.localPkgs[id] = pkg
429 } else if name != "" {
430 // package exists already and we have an expected package name;
431 // make sure names match or set package name if necessary
432 if pname := pkg.Name(); pname == "" {
434 } else if pname != name {
435 p.errorf("%s package name mismatch: %s (given) vs %s (expected)", id, pname, name)
441 // parseExportedName is like parseQualifiedName, but
442 // the package id is resolved to an imported *types.Package.
444 func (p *parser) parseExportedName() (pkg *types.Package, name string) {
445 id, name := p.parseQualifiedName()
446 pkg = p.getPkg(id, "")
450 // ----------------------------------------------------------------------------
453 // BasicType = identifier .
455 func (p *parser) parseBasicType() types.Type {
456 id := p.expect(scanner.Ident)
457 obj := types.Universe.Lookup(id)
458 if obj, ok := obj.(*types.TypeName); ok {
461 p.errorf("not a basic type: %s", id)
465 // ArrayType = "[" int_lit "]" Type .
467 func (p *parser) parseArrayType(parent *types.Package) types.Type {
468 // "[" already consumed and lookahead known not to be "]"
469 lit := p.expect(scanner.Int)
471 elem := p.parseType(parent)
472 n, err := strconv.ParseInt(lit, 10, 64)
476 return types.NewArray(elem, n)
479 // MapType = "map" "[" Type "]" Type .
481 func (p *parser) parseMapType(parent *types.Package) types.Type {
482 p.expectKeyword("map")
484 key := p.parseType(parent)
486 elem := p.parseType(parent)
487 return types.NewMap(key, elem)
490 // Name = identifier | "?" | QualifiedName .
492 // For unqualified and anonymous names, the returned package is the parent
493 // package unless parent == nil, in which case the returned package is the
494 // package being imported. (The parent package is not nil if the the name
495 // is an unqualified struct field or interface method name belonging to a
496 // type declared in another package.)
498 // For qualified names, the returned package is nil (and not created if
499 // it doesn't exist yet) unless materializePkg is set (which creates an
500 // unnamed package with valid package path). In the latter case, a
501 // subsequent import clause is expected to provide a name for the package.
503 func (p *parser) parseName(parent *types.Package, materializePkg bool) (pkg *types.Package, name string) {
506 pkg = p.sharedPkgs[p.id]
516 // exported name prefixed with package path
519 id, name = p.parseQualifiedName()
521 pkg = p.getPkg(id, "")
524 p.error("name expected")
529 func deref(typ types.Type) types.Type {
530 if p, _ := typ.(*types.Pointer); p != nil {
536 // Field = Name Type [ string_lit ] .
538 func (p *parser) parseField(parent *types.Package) (*types.Var, string) {
539 pkg, name := p.parseName(parent, true)
542 // Blank fields should be package-qualified because they
543 // are unexported identifiers, but gc does not qualify them.
544 // Assuming that the ident belongs to the current package
545 // causes types to change during re-exporting, leading
546 // to spurious "can't assign A to B" errors from go/types.
547 // As a workaround, pretend all blank fields belong
548 // to the same unique dummy package.
549 const blankpkg = "<_>"
550 pkg = p.getPkg(blankpkg, blankpkg)
553 typ := p.parseType(parent)
556 // anonymous field - typ must be T or *T and T must be a type name
557 switch typ := deref(typ).(type) {
558 case *types.Basic: // basic types are named types
559 pkg = nil // objects defined in Universe scope have no package
562 name = typ.Obj().Name()
564 p.errorf("anonymous field expected")
569 if p.tok == scanner.String {
570 s := p.expect(scanner.String)
572 tag, err = strconv.Unquote(s)
574 p.errorf("invalid struct tag %s: %s", s, err)
577 return types.NewField(token.NoPos, pkg, name, typ, anonymous), tag
580 // StructType = "struct" "{" [ FieldList ] "}" .
581 // FieldList = Field { ";" Field } .
583 func (p *parser) parseStructType(parent *types.Package) types.Type {
584 var fields []*types.Var
587 p.expectKeyword("struct")
589 for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
593 fld, tag := p.parseField(parent)
594 if tag != "" && tags == nil {
595 tags = make([]string, i)
598 tags = append(tags, tag)
600 fields = append(fields, fld)
604 return types.NewStruct(fields, tags)
607 // Parameter = ( identifier | "?" ) [ "..." ] Type [ string_lit ] .
609 func (p *parser) parseParameter() (par *types.Var, isVariadic bool) {
610 _, name := p.parseName(nil, false)
611 // remove gc-specific parameter numbering
612 if i := strings.Index(name, "·"); i >= 0 {
616 p.expectSpecial("...")
619 typ := p.parseType(nil)
621 typ = types.NewSlice(typ)
623 // ignore argument tag (e.g. "noescape")
624 if p.tok == scanner.String {
627 // TODO(gri) should we provide a package?
628 par = types.NewVar(token.NoPos, nil, name, typ)
632 // Parameters = "(" [ ParameterList ] ")" .
633 // ParameterList = { Parameter "," } Parameter .
635 func (p *parser) parseParameters() (list []*types.Var, isVariadic bool) {
637 for p.tok != ')' && p.tok != scanner.EOF {
641 par, variadic := p.parseParameter()
642 list = append(list, par)
645 p.error("... not on final argument")
655 // Signature = Parameters [ Result ] .
656 // Result = Type | Parameters .
658 func (p *parser) parseSignature(recv *types.Var) *types.Signature {
659 params, isVariadic := p.parseParameters()
661 // optional result type
662 var results []*types.Var
665 results, variadic = p.parseParameters()
667 p.error("... not permitted on result type")
671 return types.NewSignature(recv, types.NewTuple(params...), types.NewTuple(results...), isVariadic)
674 // InterfaceType = "interface" "{" [ MethodList ] "}" .
675 // MethodList = Method { ";" Method } .
676 // Method = Name Signature .
678 // The methods of embedded interfaces are always "inlined"
679 // by the compiler and thus embedded interfaces are never
680 // visible in the export data.
682 func (p *parser) parseInterfaceType(parent *types.Package) types.Type {
683 var methods []*types.Func
685 p.expectKeyword("interface")
687 for i := 0; p.tok != '}' && p.tok != scanner.EOF; i++ {
691 pkg, name := p.parseName(parent, true)
692 sig := p.parseSignature(nil)
693 methods = append(methods, types.NewFunc(token.NoPos, pkg, name, sig))
697 // Complete requires the type's embedded interfaces to be fully defined,
698 // but we do not define any
699 return types.NewInterface(methods, nil).Complete()
702 // ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
704 func (p *parser) parseChanType(parent *types.Package) types.Type {
705 dir := types.SendRecv
706 if p.tok == scanner.Ident {
707 p.expectKeyword("chan")
709 p.expectSpecial("<-")
713 p.expectSpecial("<-")
714 p.expectKeyword("chan")
717 elem := p.parseType(parent)
718 return types.NewChan(dir, elem)
722 // BasicType | TypeName | ArrayType | SliceType | StructType |
723 // PointerType | FuncType | InterfaceType | MapType | ChanType |
726 // BasicType = ident .
727 // TypeName = ExportedName .
728 // SliceType = "[" "]" Type .
729 // PointerType = "*" Type .
730 // FuncType = "func" Signature .
732 func (p *parser) parseType(parent *types.Package) types.Type {
737 return p.parseBasicType()
739 return p.parseStructType(parent)
743 return p.parseSignature(nil)
745 return p.parseInterfaceType(parent)
747 return p.parseMapType(parent)
749 return p.parseChanType(parent)
753 pkg, name := p.parseExportedName()
754 return declTypeName(pkg, name).Type()
756 p.next() // look ahead
760 return types.NewSlice(p.parseType(parent))
762 return p.parseArrayType(parent)
766 return types.NewPointer(p.parseType(parent))
768 return p.parseChanType(parent)
772 typ := p.parseType(parent)
776 p.errorf("expected type, got %s (%q)", scanner.TokenString(p.tok), p.lit)
780 // ----------------------------------------------------------------------------
783 // ImportDecl = "import" PackageName PackageId .
785 func (p *parser) parseImportDecl() {
786 p.expectKeyword("import")
787 name := p.parsePackageName()
788 p.getPkg(p.parsePackageId(), name)
791 // int_lit = [ "+" | "-" ] { "0" ... "9" } .
793 func (p *parser) parseInt() string {
802 return s + p.expect(scanner.Int)
805 // number = int_lit [ "p" int_lit ] .
807 func (p *parser) parseNumber() (typ *types.Basic, val constant.Value) {
809 mant := constant.MakeFromLiteral(p.parseInt(), token.INT, 0)
811 panic("invalid mantissa")
817 exp, err := strconv.ParseInt(p.parseInt(), 10, 0)
822 denom := constant.MakeInt64(1)
823 denom = constant.Shift(denom, token.SHL, uint(-exp))
824 typ = types.Typ[types.UntypedFloat]
825 val = constant.BinaryOp(mant, token.QUO, denom)
829 mant = constant.Shift(mant, token.SHL, uint(exp))
831 typ = types.Typ[types.UntypedFloat]
836 typ = types.Typ[types.UntypedInt]
841 // ConstDecl = "const" ExportedName [ Type ] "=" Literal .
842 // Literal = bool_lit | int_lit | float_lit | complex_lit | rune_lit | string_lit .
843 // bool_lit = "true" | "false" .
844 // complex_lit = "(" float_lit "+" float_lit "i" ")" .
845 // rune_lit = "(" int_lit "+" int_lit ")" .
846 // string_lit = `"` { unicode_char } `"` .
848 func (p *parser) parseConstDecl() {
849 p.expectKeyword("const")
850 pkg, name := p.parseExportedName()
854 // constant types are never structured - no need for parent type
855 typ0 = p.parseType(nil)
860 var val constant.Value
864 if p.lit != "true" && p.lit != "false" {
865 p.error("expected true or false")
867 typ = types.Typ[types.UntypedBool]
868 val = constant.MakeBool(p.lit == "true")
871 case '-', scanner.Int:
873 typ, val = p.parseNumber()
876 // complex_lit or rune_lit
878 if p.tok == scanner.Char {
881 typ = types.Typ[types.UntypedRune]
882 _, val = p.parseNumber()
886 _, re := p.parseNumber()
888 _, im := p.parseNumber()
891 typ = types.Typ[types.UntypedComplex]
892 val = constant.BinaryOp(re, token.ADD, constant.MakeImag(im))
896 typ = types.Typ[types.UntypedRune]
897 val = constant.MakeFromLiteral(p.lit, token.CHAR, 0)
902 typ = types.Typ[types.UntypedString]
903 val = constant.MakeFromLiteral(p.lit, token.STRING, 0)
907 p.errorf("expected literal got %s", scanner.TokenString(p.tok))
914 pkg.Scope().Insert(types.NewConst(token.NoPos, pkg, name, typ0, val))
917 // TypeDecl = "type" ExportedName Type .
919 func (p *parser) parseTypeDecl() {
920 p.expectKeyword("type")
921 pkg, name := p.parseExportedName()
922 obj := declTypeName(pkg, name)
924 // The type object may have been imported before and thus already
925 // have a type associated with it. We still need to parse the type
926 // structure, but throw it away if the object already has a type.
927 // This ensures that all imports refer to the same type object for
928 // a given type declaration.
929 typ := p.parseType(pkg)
931 if name := obj.Type().(*types.Named); name.Underlying() == nil {
932 name.SetUnderlying(typ)
936 // VarDecl = "var" ExportedName Type .
938 func (p *parser) parseVarDecl() {
939 p.expectKeyword("var")
940 pkg, name := p.parseExportedName()
941 typ := p.parseType(pkg)
942 pkg.Scope().Insert(types.NewVar(token.NoPos, pkg, name, typ))
945 // Func = Signature [ Body ] .
946 // Body = "{" ... "}" .
948 func (p *parser) parseFunc(recv *types.Var) *types.Signature {
949 sig := p.parseSignature(recv)
952 for i := 1; i > 0; p.next() {
964 // MethodDecl = "func" Receiver Name Func .
965 // Receiver = "(" ( identifier | "?" ) [ "*" ] ExportedName ")" .
967 func (p *parser) parseMethodDecl() {
968 // "func" already consumed
970 recv, _ := p.parseParameter() // receiver
973 // determine receiver base type object
974 base := deref(recv.Type()).(*types.Named)
976 // parse method name, signature, and possibly inlined body
977 _, name := p.parseName(nil, false)
978 sig := p.parseFunc(recv)
980 // methods always belong to the same package as the base type object
981 pkg := base.Obj().Pkg()
983 // add method to type unless type was imported before
984 // and method exists already
985 // TODO(gri) This leads to a quadratic algorithm - ok for now because method counts are small.
986 base.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
989 // FuncDecl = "func" ExportedName Func .
991 func (p *parser) parseFuncDecl() {
992 // "func" already consumed
993 pkg, name := p.parseExportedName()
994 typ := p.parseFunc(nil)
995 pkg.Scope().Insert(types.NewFunc(token.NoPos, pkg, name, typ))
998 // Decl = [ ImportDecl | ConstDecl | TypeDecl | VarDecl | FuncDecl | MethodDecl ] "\n" .
1000 func (p *parser) parseDecl() {
1001 if p.tok == scanner.Ident {
1012 p.next() // look ahead
1023 // ----------------------------------------------------------------------------
1026 // Export = "PackageClause { Decl } "$$" .
1027 // PackageClause = "package" PackageName [ "safe" ] "\n" .
1029 func (p *parser) parseExport() *types.Package {
1030 p.expectKeyword("package")
1031 name := p.parsePackageName()
1032 if p.tok == scanner.Ident && p.lit == "safe" {
1033 // package was compiled with -u option - ignore
1038 pkg := p.getPkg(p.id, name)
1040 for p.tok != '$' && p.tok != scanner.EOF {
1044 if ch := p.scanner.Peek(); p.tok != '$' || ch != '$' {
1045 // don't call next()/expect() since reading past the
1046 // export data may cause scanner errors (e.g. NUL chars)
1047 p.errorf("expected '$$', got %s %c", scanner.TokenString(p.tok), ch)
1050 if n := p.scanner.ErrorCount; n != 0 {
1051 p.errorf("expected no scanner errors, got %d", n)
1054 // Record all locally referenced packages as imports.
1055 var imports []*types.Package
1056 for id, pkg2 := range p.localPkgs {
1057 if pkg2.Name() == "" {
1058 p.errorf("%s package has no name", id)
1061 continue // avoid self-edge
1063 imports = append(imports, pkg2)
1065 sort.Sort(byPath(imports))
1066 pkg.SetImports(imports)
1068 // package was imported completely and without errors
1074 type byPath []*types.Package
1076 func (a byPath) Len() int { return len(a) }
1077 func (a byPath) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
1078 func (a byPath) Less(i, j int) bool { return a[i].Path() < a[j].Path() }