golang.org/x/tools@v0.21.1-0.20240520172518-788d39e776b1/internal/gcimporter/iexport.go (about) 1 // Copyright 2019 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. 4 5 // Indexed binary package export. 6 // This file was derived from $GOROOT/src/cmd/compile/internal/gc/iexport.go; 7 // see that file for specification of the format. 8 9 package gcimporter 10 11 import ( 12 "bytes" 13 "encoding/binary" 14 "fmt" 15 "go/constant" 16 "go/token" 17 "go/types" 18 "io" 19 "math/big" 20 "reflect" 21 "sort" 22 "strconv" 23 "strings" 24 25 "golang.org/x/tools/go/types/objectpath" 26 "golang.org/x/tools/internal/aliases" 27 "golang.org/x/tools/internal/tokeninternal" 28 ) 29 30 // IExportShallow encodes "shallow" export data for the specified package. 31 // 32 // No promises are made about the encoding other than that it can be decoded by 33 // the same version of IIExportShallow. If you plan to save export data in the 34 // file system, be sure to include a cryptographic digest of the executable in 35 // the key to avoid version skew. 36 // 37 // If the provided reportf func is non-nil, it will be used for reporting bugs 38 // encountered during export. 39 // TODO(rfindley): remove reportf when we are confident enough in the new 40 // objectpath encoding. 41 func IExportShallow(fset *token.FileSet, pkg *types.Package, reportf ReportFunc) ([]byte, error) { 42 // In principle this operation can only fail if out.Write fails, 43 // but that's impossible for bytes.Buffer---and as a matter of 44 // fact iexportCommon doesn't even check for I/O errors. 45 // TODO(adonovan): handle I/O errors properly. 46 // TODO(adonovan): use byte slices throughout, avoiding copying. 47 const bundle, shallow = false, true 48 var out bytes.Buffer 49 err := iexportCommon(&out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}) 50 return out.Bytes(), err 51 } 52 53 // IImportShallow decodes "shallow" types.Package data encoded by 54 // IExportShallow in the same executable. This function cannot import data from 55 // cmd/compile or gcexportdata.Write. 56 // 57 // The importer calls getPackages to obtain package symbols for all 58 // packages mentioned in the export data, including the one being 59 // decoded. 60 // 61 // If the provided reportf func is non-nil, it will be used for reporting bugs 62 // encountered during import. 63 // TODO(rfindley): remove reportf when we are confident enough in the new 64 // objectpath encoding. 65 func IImportShallow(fset *token.FileSet, getPackages GetPackagesFunc, data []byte, path string, reportf ReportFunc) (*types.Package, error) { 66 const bundle = false 67 const shallow = true 68 pkgs, err := iimportCommon(fset, getPackages, data, bundle, path, shallow, reportf) 69 if err != nil { 70 return nil, err 71 } 72 return pkgs[0], nil 73 } 74 75 // ReportFunc is the type of a function used to report formatted bugs. 76 type ReportFunc = func(string, ...interface{}) 77 78 // Current bundled export format version. Increase with each format change. 79 // 0: initial implementation 80 const bundleVersion = 0 81 82 // IExportData writes indexed export data for pkg to out. 83 // 84 // If no file set is provided, position info will be missing. 85 // The package path of the top-level package will not be recorded, 86 // so that calls to IImportData can override with a provided package path. 87 func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error { 88 const bundle, shallow = false, false 89 return iexportCommon(out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}) 90 } 91 92 // IExportBundle writes an indexed export bundle for pkgs to out. 93 func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error { 94 const bundle, shallow = true, false 95 return iexportCommon(out, fset, bundle, shallow, iexportVersion, pkgs) 96 } 97 98 func iexportCommon(out io.Writer, fset *token.FileSet, bundle, shallow bool, version int, pkgs []*types.Package) (err error) { 99 if !debug { 100 defer func() { 101 if e := recover(); e != nil { 102 if ierr, ok := e.(internalError); ok { 103 err = ierr 104 return 105 } 106 // Not an internal error; panic again. 107 panic(e) 108 } 109 }() 110 } 111 112 p := iexporter{ 113 fset: fset, 114 version: version, 115 shallow: shallow, 116 allPkgs: map[*types.Package]bool{}, 117 stringIndex: map[string]uint64{}, 118 declIndex: map[types.Object]uint64{}, 119 tparamNames: map[types.Object]string{}, 120 typIndex: map[types.Type]uint64{}, 121 } 122 if !bundle { 123 p.localpkg = pkgs[0] 124 } 125 126 for i, pt := range predeclared() { 127 p.typIndex[pt] = uint64(i) 128 } 129 if len(p.typIndex) > predeclReserved { 130 panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved)) 131 } 132 133 // Initialize work queue with exported declarations. 134 for _, pkg := range pkgs { 135 scope := pkg.Scope() 136 for _, name := range scope.Names() { 137 if token.IsExported(name) { 138 p.pushDecl(scope.Lookup(name)) 139 } 140 } 141 142 if bundle { 143 // Ensure pkg and its imports are included in the index. 144 p.allPkgs[pkg] = true 145 for _, imp := range pkg.Imports() { 146 p.allPkgs[imp] = true 147 } 148 } 149 } 150 151 // Loop until no more work. 152 for !p.declTodo.empty() { 153 p.doDecl(p.declTodo.popHead()) 154 } 155 156 // Produce index of offset of each file record in files. 157 var files intWriter 158 var fileOffset []uint64 // fileOffset[i] is offset in files of file encoded as i 159 if p.shallow { 160 fileOffset = make([]uint64, len(p.fileInfos)) 161 for i, info := range p.fileInfos { 162 fileOffset[i] = uint64(files.Len()) 163 p.encodeFile(&files, info.file, info.needed) 164 } 165 } 166 167 // Append indices to data0 section. 168 dataLen := uint64(p.data0.Len()) 169 w := p.newWriter() 170 w.writeIndex(p.declIndex) 171 172 if bundle { 173 w.uint64(uint64(len(pkgs))) 174 for _, pkg := range pkgs { 175 w.pkg(pkg) 176 imps := pkg.Imports() 177 w.uint64(uint64(len(imps))) 178 for _, imp := range imps { 179 w.pkg(imp) 180 } 181 } 182 } 183 w.flush() 184 185 // Assemble header. 186 var hdr intWriter 187 if bundle { 188 hdr.uint64(bundleVersion) 189 } 190 hdr.uint64(uint64(p.version)) 191 hdr.uint64(uint64(p.strings.Len())) 192 if p.shallow { 193 hdr.uint64(uint64(files.Len())) 194 hdr.uint64(uint64(len(fileOffset))) 195 for _, offset := range fileOffset { 196 hdr.uint64(offset) 197 } 198 } 199 hdr.uint64(dataLen) 200 201 // Flush output. 202 io.Copy(out, &hdr) 203 io.Copy(out, &p.strings) 204 if p.shallow { 205 io.Copy(out, &files) 206 } 207 io.Copy(out, &p.data0) 208 209 return nil 210 } 211 212 // encodeFile writes to w a representation of the file sufficient to 213 // faithfully restore position information about all needed offsets. 214 // Mutates the needed array. 215 func (p *iexporter) encodeFile(w *intWriter, file *token.File, needed []uint64) { 216 _ = needed[0] // precondition: needed is non-empty 217 218 w.uint64(p.stringOff(file.Name())) 219 220 size := uint64(file.Size()) 221 w.uint64(size) 222 223 // Sort the set of needed offsets. Duplicates are harmless. 224 sort.Slice(needed, func(i, j int) bool { return needed[i] < needed[j] }) 225 226 lines := tokeninternal.GetLines(file) // byte offset of each line start 227 w.uint64(uint64(len(lines))) 228 229 // Rather than record the entire array of line start offsets, 230 // we save only a sparse list of (index, offset) pairs for 231 // the start of each line that contains a needed position. 232 var sparse [][2]int // (index, offset) pairs 233 outer: 234 for i, lineStart := range lines { 235 lineEnd := size 236 if i < len(lines)-1 { 237 lineEnd = uint64(lines[i+1]) 238 } 239 // Does this line contains a needed offset? 240 if needed[0] < lineEnd { 241 sparse = append(sparse, [2]int{i, lineStart}) 242 for needed[0] < lineEnd { 243 needed = needed[1:] 244 if len(needed) == 0 { 245 break outer 246 } 247 } 248 } 249 } 250 251 // Delta-encode the columns. 252 w.uint64(uint64(len(sparse))) 253 var prev [2]int 254 for _, pair := range sparse { 255 w.uint64(uint64(pair[0] - prev[0])) 256 w.uint64(uint64(pair[1] - prev[1])) 257 prev = pair 258 } 259 } 260 261 // writeIndex writes out an object index. mainIndex indicates whether 262 // we're writing out the main index, which is also read by 263 // non-compiler tools and includes a complete package description 264 // (i.e., name and height). 265 func (w *exportWriter) writeIndex(index map[types.Object]uint64) { 266 type pkgObj struct { 267 obj types.Object 268 name string // qualified name; differs from obj.Name for type params 269 } 270 // Build a map from packages to objects from that package. 271 pkgObjs := map[*types.Package][]pkgObj{} 272 273 // For the main index, make sure to include every package that 274 // we reference, even if we're not exporting (or reexporting) 275 // any symbols from it. 276 if w.p.localpkg != nil { 277 pkgObjs[w.p.localpkg] = nil 278 } 279 for pkg := range w.p.allPkgs { 280 pkgObjs[pkg] = nil 281 } 282 283 for obj := range index { 284 name := w.p.exportName(obj) 285 pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name}) 286 } 287 288 var pkgs []*types.Package 289 for pkg, objs := range pkgObjs { 290 pkgs = append(pkgs, pkg) 291 292 sort.Slice(objs, func(i, j int) bool { 293 return objs[i].name < objs[j].name 294 }) 295 } 296 297 sort.Slice(pkgs, func(i, j int) bool { 298 return w.exportPath(pkgs[i]) < w.exportPath(pkgs[j]) 299 }) 300 301 w.uint64(uint64(len(pkgs))) 302 for _, pkg := range pkgs { 303 w.string(w.exportPath(pkg)) 304 w.string(pkg.Name()) 305 w.uint64(uint64(0)) // package height is not needed for go/types 306 307 objs := pkgObjs[pkg] 308 w.uint64(uint64(len(objs))) 309 for _, obj := range objs { 310 w.string(obj.name) 311 w.uint64(index[obj.obj]) 312 } 313 } 314 } 315 316 // exportName returns the 'exported' name of an object. It differs from 317 // obj.Name() only for type parameters (see tparamExportName for details). 318 func (p *iexporter) exportName(obj types.Object) (res string) { 319 if name := p.tparamNames[obj]; name != "" { 320 return name 321 } 322 return obj.Name() 323 } 324 325 type iexporter struct { 326 fset *token.FileSet 327 out *bytes.Buffer 328 version int 329 330 shallow bool // don't put types from other packages in the index 331 objEncoder *objectpath.Encoder // encodes objects from other packages in shallow mode; lazily allocated 332 localpkg *types.Package // (nil in bundle mode) 333 334 // allPkgs tracks all packages that have been referenced by 335 // the export data, so we can ensure to include them in the 336 // main index. 337 allPkgs map[*types.Package]bool 338 339 declTodo objQueue 340 341 strings intWriter 342 stringIndex map[string]uint64 343 344 // In shallow mode, object positions are encoded as (file, offset). 345 // Each file is recorded as a line-number table. 346 // Only the lines of needed positions are saved faithfully. 347 fileInfo map[*token.File]uint64 // value is index in fileInfos 348 fileInfos []*filePositions 349 350 data0 intWriter 351 declIndex map[types.Object]uint64 352 tparamNames map[types.Object]string // typeparam->exported name 353 typIndex map[types.Type]uint64 354 355 indent int // for tracing support 356 } 357 358 type filePositions struct { 359 file *token.File 360 needed []uint64 // unordered list of needed file offsets 361 } 362 363 func (p *iexporter) trace(format string, args ...interface{}) { 364 if !trace { 365 // Call sites should also be guarded, but having this check here allows 366 // easily enabling/disabling debug trace statements. 367 return 368 } 369 fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...) 370 } 371 372 // objectpathEncoder returns the lazily allocated objectpath.Encoder to use 373 // when encoding objects in other packages during shallow export. 374 // 375 // Using a shared Encoder amortizes some of cost of objectpath search. 376 func (p *iexporter) objectpathEncoder() *objectpath.Encoder { 377 if p.objEncoder == nil { 378 p.objEncoder = new(objectpath.Encoder) 379 } 380 return p.objEncoder 381 } 382 383 // stringOff returns the offset of s within the string section. 384 // If not already present, it's added to the end. 385 func (p *iexporter) stringOff(s string) uint64 { 386 off, ok := p.stringIndex[s] 387 if !ok { 388 off = uint64(p.strings.Len()) 389 p.stringIndex[s] = off 390 391 p.strings.uint64(uint64(len(s))) 392 p.strings.WriteString(s) 393 } 394 return off 395 } 396 397 // fileIndexAndOffset returns the index of the token.File and the byte offset of pos within it. 398 func (p *iexporter) fileIndexAndOffset(file *token.File, pos token.Pos) (uint64, uint64) { 399 index, ok := p.fileInfo[file] 400 if !ok { 401 index = uint64(len(p.fileInfo)) 402 p.fileInfos = append(p.fileInfos, &filePositions{file: file}) 403 if p.fileInfo == nil { 404 p.fileInfo = make(map[*token.File]uint64) 405 } 406 p.fileInfo[file] = index 407 } 408 // Record each needed offset. 409 info := p.fileInfos[index] 410 offset := uint64(file.Offset(pos)) 411 info.needed = append(info.needed, offset) 412 413 return index, offset 414 } 415 416 // pushDecl adds n to the declaration work queue, if not already present. 417 func (p *iexporter) pushDecl(obj types.Object) { 418 // Package unsafe is known to the compiler and predeclared. 419 // Caller should not ask us to do export it. 420 if obj.Pkg() == types.Unsafe { 421 panic("cannot export package unsafe") 422 } 423 424 // Shallow export data: don't index decls from other packages. 425 if p.shallow && obj.Pkg() != p.localpkg { 426 return 427 } 428 429 if _, ok := p.declIndex[obj]; ok { 430 return 431 } 432 433 p.declIndex[obj] = ^uint64(0) // mark obj present in work queue 434 p.declTodo.pushTail(obj) 435 } 436 437 // exportWriter handles writing out individual data section chunks. 438 type exportWriter struct { 439 p *iexporter 440 441 data intWriter 442 prevFile string 443 prevLine int64 444 prevColumn int64 445 } 446 447 func (w *exportWriter) exportPath(pkg *types.Package) string { 448 if pkg == w.p.localpkg { 449 return "" 450 } 451 return pkg.Path() 452 } 453 454 func (p *iexporter) doDecl(obj types.Object) { 455 if trace { 456 p.trace("exporting decl %v (%T)", obj, obj) 457 p.indent++ 458 defer func() { 459 p.indent-- 460 p.trace("=> %s", obj) 461 }() 462 } 463 w := p.newWriter() 464 465 switch obj := obj.(type) { 466 case *types.Var: 467 w.tag(varTag) 468 w.pos(obj.Pos()) 469 w.typ(obj.Type(), obj.Pkg()) 470 471 case *types.Func: 472 sig, _ := obj.Type().(*types.Signature) 473 if sig.Recv() != nil { 474 // We shouldn't see methods in the package scope, 475 // but the type checker may repair "func () F() {}" 476 // to "func (Invalid) F()" and then treat it like "func F()", 477 // so allow that. See golang/go#57729. 478 if sig.Recv().Type() != types.Typ[types.Invalid] { 479 panic(internalErrorf("unexpected method: %v", sig)) 480 } 481 } 482 483 // Function. 484 if sig.TypeParams().Len() == 0 { 485 w.tag(funcTag) 486 } else { 487 w.tag(genericFuncTag) 488 } 489 w.pos(obj.Pos()) 490 // The tparam list of the function type is the declaration of the type 491 // params. So, write out the type params right now. Then those type params 492 // will be referenced via their type offset (via typOff) in all other 493 // places in the signature and function where they are used. 494 // 495 // While importing the type parameters, tparamList computes and records 496 // their export name, so that it can be later used when writing the index. 497 if tparams := sig.TypeParams(); tparams.Len() > 0 { 498 w.tparamList(obj.Name(), tparams, obj.Pkg()) 499 } 500 w.signature(sig) 501 502 case *types.Const: 503 w.tag(constTag) 504 w.pos(obj.Pos()) 505 w.value(obj.Type(), obj.Val()) 506 507 case *types.TypeName: 508 t := obj.Type() 509 510 if tparam, ok := aliases.Unalias(t).(*types.TypeParam); ok { 511 w.tag(typeParamTag) 512 w.pos(obj.Pos()) 513 constraint := tparam.Constraint() 514 if p.version >= iexportVersionGo1_18 { 515 implicit := false 516 if iface, _ := aliases.Unalias(constraint).(*types.Interface); iface != nil { 517 implicit = iface.IsImplicit() 518 } 519 w.bool(implicit) 520 } 521 w.typ(constraint, obj.Pkg()) 522 break 523 } 524 525 if obj.IsAlias() { 526 w.tag(aliasTag) 527 w.pos(obj.Pos()) 528 if alias, ok := t.(*aliases.Alias); ok { 529 // Preserve materialized aliases, 530 // even of non-exported types. 531 t = aliases.Rhs(alias) 532 } 533 w.typ(t, obj.Pkg()) 534 break 535 } 536 537 // Defined type. 538 named, ok := t.(*types.Named) 539 if !ok { 540 panic(internalErrorf("%s is not a defined type", t)) 541 } 542 543 if named.TypeParams().Len() == 0 { 544 w.tag(typeTag) 545 } else { 546 w.tag(genericTypeTag) 547 } 548 w.pos(obj.Pos()) 549 550 if named.TypeParams().Len() > 0 { 551 // While importing the type parameters, tparamList computes and records 552 // their export name, so that it can be later used when writing the index. 553 w.tparamList(obj.Name(), named.TypeParams(), obj.Pkg()) 554 } 555 556 underlying := named.Underlying() 557 w.typ(underlying, obj.Pkg()) 558 559 if types.IsInterface(t) { 560 break 561 } 562 563 n := named.NumMethods() 564 w.uint64(uint64(n)) 565 for i := 0; i < n; i++ { 566 m := named.Method(i) 567 w.pos(m.Pos()) 568 w.string(m.Name()) 569 sig, _ := m.Type().(*types.Signature) 570 571 // Receiver type parameters are type arguments of the receiver type, so 572 // their name must be qualified before exporting recv. 573 if rparams := sig.RecvTypeParams(); rparams.Len() > 0 { 574 prefix := obj.Name() + "." + m.Name() 575 for i := 0; i < rparams.Len(); i++ { 576 rparam := rparams.At(i) 577 name := tparamExportName(prefix, rparam) 578 w.p.tparamNames[rparam.Obj()] = name 579 } 580 } 581 w.param(sig.Recv()) 582 w.signature(sig) 583 } 584 585 default: 586 panic(internalErrorf("unexpected object: %v", obj)) 587 } 588 589 p.declIndex[obj] = w.flush() 590 } 591 592 func (w *exportWriter) tag(tag byte) { 593 w.data.WriteByte(tag) 594 } 595 596 func (w *exportWriter) pos(pos token.Pos) { 597 if w.p.shallow { 598 w.posV2(pos) 599 } else if w.p.version >= iexportVersionPosCol { 600 w.posV1(pos) 601 } else { 602 w.posV0(pos) 603 } 604 } 605 606 // posV2 encoding (used only in shallow mode) records positions as 607 // (file, offset), where file is the index in the token.File table 608 // (which records the file name and newline offsets) and offset is a 609 // byte offset. It effectively ignores //line directives. 610 func (w *exportWriter) posV2(pos token.Pos) { 611 if pos == token.NoPos { 612 w.uint64(0) 613 return 614 } 615 file := w.p.fset.File(pos) // fset must be non-nil 616 index, offset := w.p.fileIndexAndOffset(file, pos) 617 w.uint64(1 + index) 618 w.uint64(offset) 619 } 620 621 func (w *exportWriter) posV1(pos token.Pos) { 622 if w.p.fset == nil { 623 w.int64(0) 624 return 625 } 626 627 p := w.p.fset.Position(pos) 628 file := p.Filename 629 line := int64(p.Line) 630 column := int64(p.Column) 631 632 deltaColumn := (column - w.prevColumn) << 1 633 deltaLine := (line - w.prevLine) << 1 634 635 if file != w.prevFile { 636 deltaLine |= 1 637 } 638 if deltaLine != 0 { 639 deltaColumn |= 1 640 } 641 642 w.int64(deltaColumn) 643 if deltaColumn&1 != 0 { 644 w.int64(deltaLine) 645 if deltaLine&1 != 0 { 646 w.string(file) 647 } 648 } 649 650 w.prevFile = file 651 w.prevLine = line 652 w.prevColumn = column 653 } 654 655 func (w *exportWriter) posV0(pos token.Pos) { 656 if w.p.fset == nil { 657 w.int64(0) 658 return 659 } 660 661 p := w.p.fset.Position(pos) 662 file := p.Filename 663 line := int64(p.Line) 664 665 // When file is the same as the last position (common case), 666 // we can save a few bytes by delta encoding just the line 667 // number. 668 // 669 // Note: Because data objects may be read out of order (or not 670 // at all), we can only apply delta encoding within a single 671 // object. This is handled implicitly by tracking prevFile and 672 // prevLine as fields of exportWriter. 673 674 if file == w.prevFile { 675 delta := line - w.prevLine 676 w.int64(delta) 677 if delta == deltaNewFile { 678 w.int64(-1) 679 } 680 } else { 681 w.int64(deltaNewFile) 682 w.int64(line) // line >= 0 683 w.string(file) 684 w.prevFile = file 685 } 686 w.prevLine = line 687 } 688 689 func (w *exportWriter) pkg(pkg *types.Package) { 690 // Ensure any referenced packages are declared in the main index. 691 w.p.allPkgs[pkg] = true 692 693 w.string(w.exportPath(pkg)) 694 } 695 696 func (w *exportWriter) qualifiedType(obj *types.TypeName) { 697 name := w.p.exportName(obj) 698 699 // Ensure any referenced declarations are written out too. 700 w.p.pushDecl(obj) 701 w.string(name) 702 w.pkg(obj.Pkg()) 703 } 704 705 // TODO(rfindley): what does 'pkg' even mean here? It would be better to pass 706 // it in explicitly into signatures and structs that may use it for 707 // constructing fields. 708 func (w *exportWriter) typ(t types.Type, pkg *types.Package) { 709 w.data.uint64(w.p.typOff(t, pkg)) 710 } 711 712 func (p *iexporter) newWriter() *exportWriter { 713 return &exportWriter{p: p} 714 } 715 716 func (w *exportWriter) flush() uint64 { 717 off := uint64(w.p.data0.Len()) 718 io.Copy(&w.p.data0, &w.data) 719 return off 720 } 721 722 func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 { 723 off, ok := p.typIndex[t] 724 if !ok { 725 w := p.newWriter() 726 w.doTyp(t, pkg) 727 off = predeclReserved + w.flush() 728 p.typIndex[t] = off 729 } 730 return off 731 } 732 733 func (w *exportWriter) startType(k itag) { 734 w.data.uint64(uint64(k)) 735 } 736 737 func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) { 738 if trace { 739 w.p.trace("exporting type %s (%T)", t, t) 740 w.p.indent++ 741 defer func() { 742 w.p.indent-- 743 w.p.trace("=> %s", t) 744 }() 745 } 746 switch t := t.(type) { 747 case *aliases.Alias: 748 // TODO(adonovan): support parameterized aliases, following *types.Named. 749 w.startType(aliasType) 750 w.qualifiedType(t.Obj()) 751 752 case *types.Named: 753 if targs := t.TypeArgs(); targs.Len() > 0 { 754 w.startType(instanceType) 755 // TODO(rfindley): investigate if this position is correct, and if it 756 // matters. 757 w.pos(t.Obj().Pos()) 758 w.typeList(targs, pkg) 759 w.typ(t.Origin(), pkg) 760 return 761 } 762 w.startType(definedType) 763 w.qualifiedType(t.Obj()) 764 765 case *types.TypeParam: 766 w.startType(typeParamType) 767 w.qualifiedType(t.Obj()) 768 769 case *types.Pointer: 770 w.startType(pointerType) 771 w.typ(t.Elem(), pkg) 772 773 case *types.Slice: 774 w.startType(sliceType) 775 w.typ(t.Elem(), pkg) 776 777 case *types.Array: 778 w.startType(arrayType) 779 w.uint64(uint64(t.Len())) 780 w.typ(t.Elem(), pkg) 781 782 case *types.Chan: 783 w.startType(chanType) 784 // 1 RecvOnly; 2 SendOnly; 3 SendRecv 785 var dir uint64 786 switch t.Dir() { 787 case types.RecvOnly: 788 dir = 1 789 case types.SendOnly: 790 dir = 2 791 case types.SendRecv: 792 dir = 3 793 } 794 w.uint64(dir) 795 w.typ(t.Elem(), pkg) 796 797 case *types.Map: 798 w.startType(mapType) 799 w.typ(t.Key(), pkg) 800 w.typ(t.Elem(), pkg) 801 802 case *types.Signature: 803 w.startType(signatureType) 804 w.pkg(pkg) 805 w.signature(t) 806 807 case *types.Struct: 808 w.startType(structType) 809 n := t.NumFields() 810 // Even for struct{} we must emit some qualifying package, because that's 811 // what the compiler does, and thus that's what the importer expects. 812 fieldPkg := pkg 813 if n > 0 { 814 fieldPkg = t.Field(0).Pkg() 815 } 816 if fieldPkg == nil { 817 // TODO(rfindley): improve this very hacky logic. 818 // 819 // The importer expects a package to be set for all struct types, even 820 // those with no fields. A better encoding might be to set NumFields 821 // before pkg. setPkg panics with a nil package, which may be possible 822 // to reach with invalid packages (and perhaps valid packages, too?), so 823 // (arbitrarily) set the localpkg if available. 824 // 825 // Alternatively, we may be able to simply guarantee that pkg != nil, by 826 // reconsidering the encoding of constant values. 827 if w.p.shallow { 828 fieldPkg = w.p.localpkg 829 } else { 830 panic(internalErrorf("no package to set for empty struct")) 831 } 832 } 833 w.pkg(fieldPkg) 834 w.uint64(uint64(n)) 835 836 for i := 0; i < n; i++ { 837 f := t.Field(i) 838 if w.p.shallow { 839 w.objectPath(f) 840 } 841 w.pos(f.Pos()) 842 w.string(f.Name()) // unexported fields implicitly qualified by prior setPkg 843 w.typ(f.Type(), fieldPkg) 844 w.bool(f.Anonymous()) 845 w.string(t.Tag(i)) // note (or tag) 846 } 847 848 case *types.Interface: 849 w.startType(interfaceType) 850 w.pkg(pkg) 851 852 n := t.NumEmbeddeds() 853 w.uint64(uint64(n)) 854 for i := 0; i < n; i++ { 855 ft := t.EmbeddedType(i) 856 tPkg := pkg 857 if named, _ := aliases.Unalias(ft).(*types.Named); named != nil { 858 w.pos(named.Obj().Pos()) 859 } else { 860 w.pos(token.NoPos) 861 } 862 w.typ(ft, tPkg) 863 } 864 865 // See comment for struct fields. In shallow mode we change the encoding 866 // for interface methods that are promoted from other packages. 867 868 n = t.NumExplicitMethods() 869 w.uint64(uint64(n)) 870 for i := 0; i < n; i++ { 871 m := t.ExplicitMethod(i) 872 if w.p.shallow { 873 w.objectPath(m) 874 } 875 w.pos(m.Pos()) 876 w.string(m.Name()) 877 sig, _ := m.Type().(*types.Signature) 878 w.signature(sig) 879 } 880 881 case *types.Union: 882 w.startType(unionType) 883 nt := t.Len() 884 w.uint64(uint64(nt)) 885 for i := 0; i < nt; i++ { 886 term := t.Term(i) 887 w.bool(term.Tilde()) 888 w.typ(term.Type(), pkg) 889 } 890 891 default: 892 panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t))) 893 } 894 } 895 896 // objectPath writes the package and objectPath to use to look up obj in a 897 // different package, when encoding in "shallow" mode. 898 // 899 // When doing a shallow import, the importer creates only the local package, 900 // and requests package symbols for dependencies from the client. 901 // However, certain types defined in the local package may hold objects defined 902 // (perhaps deeply) within another package. 903 // 904 // For example, consider the following: 905 // 906 // package a 907 // func F() chan * map[string] struct { X int } 908 // 909 // package b 910 // import "a" 911 // var B = a.F() 912 // 913 // In this example, the type of b.B holds fields defined in package a. 914 // In order to have the correct canonical objects for the field defined in the 915 // type of B, they are encoded as objectPaths and later looked up in the 916 // importer. The same problem applies to interface methods. 917 func (w *exportWriter) objectPath(obj types.Object) { 918 if obj.Pkg() == nil || obj.Pkg() == w.p.localpkg { 919 // obj.Pkg() may be nil for the builtin error.Error. 920 // In this case, or if obj is declared in the local package, no need to 921 // encode. 922 w.string("") 923 return 924 } 925 objectPath, err := w.p.objectpathEncoder().For(obj) 926 if err != nil { 927 // Fall back to the empty string, which will cause the importer to create a 928 // new object, which matches earlier behavior. Creating a new object is 929 // sufficient for many purposes (such as type checking), but causes certain 930 // references algorithms to fail (golang/go#60819). However, we didn't 931 // notice this problem during months of gopls@v0.12.0 testing. 932 // 933 // TODO(golang/go#61674): this workaround is insufficient, as in the case 934 // where the field forwarded from an instantiated type that may not appear 935 // in the export data of the original package: 936 // 937 // // package a 938 // type A[P any] struct{ F P } 939 // 940 // // package b 941 // type B a.A[int] 942 // 943 // We need to update references algorithms not to depend on this 944 // de-duplication, at which point we may want to simply remove the 945 // workaround here. 946 w.string("") 947 return 948 } 949 w.string(string(objectPath)) 950 w.pkg(obj.Pkg()) 951 } 952 953 func (w *exportWriter) signature(sig *types.Signature) { 954 w.paramList(sig.Params()) 955 w.paramList(sig.Results()) 956 if sig.Params().Len() > 0 { 957 w.bool(sig.Variadic()) 958 } 959 } 960 961 func (w *exportWriter) typeList(ts *types.TypeList, pkg *types.Package) { 962 w.uint64(uint64(ts.Len())) 963 for i := 0; i < ts.Len(); i++ { 964 w.typ(ts.At(i), pkg) 965 } 966 } 967 968 func (w *exportWriter) tparamList(prefix string, list *types.TypeParamList, pkg *types.Package) { 969 ll := uint64(list.Len()) 970 w.uint64(ll) 971 for i := 0; i < list.Len(); i++ { 972 tparam := list.At(i) 973 // Set the type parameter exportName before exporting its type. 974 exportName := tparamExportName(prefix, tparam) 975 w.p.tparamNames[tparam.Obj()] = exportName 976 w.typ(list.At(i), pkg) 977 } 978 } 979 980 const blankMarker = "$" 981 982 // tparamExportName returns the 'exported' name of a type parameter, which 983 // differs from its actual object name: it is prefixed with a qualifier, and 984 // blank type parameter names are disambiguated by their index in the type 985 // parameter list. 986 func tparamExportName(prefix string, tparam *types.TypeParam) string { 987 assert(prefix != "") 988 name := tparam.Obj().Name() 989 if name == "_" { 990 name = blankMarker + strconv.Itoa(tparam.Index()) 991 } 992 return prefix + "." + name 993 } 994 995 // tparamName returns the real name of a type parameter, after stripping its 996 // qualifying prefix and reverting blank-name encoding. See tparamExportName 997 // for details. 998 func tparamName(exportName string) string { 999 // Remove the "path" from the type param name that makes it unique. 1000 ix := strings.LastIndex(exportName, ".") 1001 if ix < 0 { 1002 errorf("malformed type parameter export name %s: missing prefix", exportName) 1003 } 1004 name := exportName[ix+1:] 1005 if strings.HasPrefix(name, blankMarker) { 1006 return "_" 1007 } 1008 return name 1009 } 1010 1011 func (w *exportWriter) paramList(tup *types.Tuple) { 1012 n := tup.Len() 1013 w.uint64(uint64(n)) 1014 for i := 0; i < n; i++ { 1015 w.param(tup.At(i)) 1016 } 1017 } 1018 1019 func (w *exportWriter) param(obj types.Object) { 1020 w.pos(obj.Pos()) 1021 w.localIdent(obj) 1022 w.typ(obj.Type(), obj.Pkg()) 1023 } 1024 1025 func (w *exportWriter) value(typ types.Type, v constant.Value) { 1026 w.typ(typ, nil) 1027 if w.p.version >= iexportVersionGo1_18 { 1028 w.int64(int64(v.Kind())) 1029 } 1030 1031 if v.Kind() == constant.Unknown { 1032 // golang/go#60605: treat unknown constant values as if they have invalid type 1033 // 1034 // This loses some fidelity over the package type-checked from source, but that 1035 // is acceptable. 1036 // 1037 // TODO(rfindley): we should switch on the recorded constant kind rather 1038 // than the constant type 1039 return 1040 } 1041 1042 switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType { 1043 case types.IsBoolean: 1044 w.bool(constant.BoolVal(v)) 1045 case types.IsInteger: 1046 var i big.Int 1047 if i64, exact := constant.Int64Val(v); exact { 1048 i.SetInt64(i64) 1049 } else if ui64, exact := constant.Uint64Val(v); exact { 1050 i.SetUint64(ui64) 1051 } else { 1052 i.SetString(v.ExactString(), 10) 1053 } 1054 w.mpint(&i, typ) 1055 case types.IsFloat: 1056 f := constantToFloat(v) 1057 w.mpfloat(f, typ) 1058 case types.IsComplex: 1059 w.mpfloat(constantToFloat(constant.Real(v)), typ) 1060 w.mpfloat(constantToFloat(constant.Imag(v)), typ) 1061 case types.IsString: 1062 w.string(constant.StringVal(v)) 1063 default: 1064 if b.Kind() == types.Invalid { 1065 // package contains type errors 1066 break 1067 } 1068 panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying())) 1069 } 1070 } 1071 1072 // constantToFloat converts a constant.Value with kind constant.Float to a 1073 // big.Float. 1074 func constantToFloat(x constant.Value) *big.Float { 1075 x = constant.ToFloat(x) 1076 // Use the same floating-point precision (512) as cmd/compile 1077 // (see Mpprec in cmd/compile/internal/gc/mpfloat.go). 1078 const mpprec = 512 1079 var f big.Float 1080 f.SetPrec(mpprec) 1081 if v, exact := constant.Float64Val(x); exact { 1082 // float64 1083 f.SetFloat64(v) 1084 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int { 1085 // TODO(gri): add big.Rat accessor to constant.Value. 1086 n := valueToRat(num) 1087 d := valueToRat(denom) 1088 f.SetRat(n.Quo(n, d)) 1089 } else { 1090 // Value too large to represent as a fraction => inaccessible. 1091 // TODO(gri): add big.Float accessor to constant.Value. 1092 _, ok := f.SetString(x.ExactString()) 1093 assert(ok) 1094 } 1095 return &f 1096 } 1097 1098 func valueToRat(x constant.Value) *big.Rat { 1099 // Convert little-endian to big-endian. 1100 // I can't believe this is necessary. 1101 bytes := constant.Bytes(x) 1102 for i := 0; i < len(bytes)/2; i++ { 1103 bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i] 1104 } 1105 return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes)) 1106 } 1107 1108 // mpint exports a multi-precision integer. 1109 // 1110 // For unsigned types, small values are written out as a single 1111 // byte. Larger values are written out as a length-prefixed big-endian 1112 // byte string, where the length prefix is encoded as its complement. 1113 // For example, bytes 0, 1, and 2 directly represent the integer 1114 // values 0, 1, and 2; while bytes 255, 254, and 253 indicate a 1-, 1115 // 2-, and 3-byte big-endian string follow. 1116 // 1117 // Encoding for signed types use the same general approach as for 1118 // unsigned types, except small values use zig-zag encoding and the 1119 // bottom bit of length prefix byte for large values is reserved as a 1120 // sign bit. 1121 // 1122 // The exact boundary between small and large encodings varies 1123 // according to the maximum number of bytes needed to encode a value 1124 // of type typ. As a special case, 8-bit types are always encoded as a 1125 // single byte. 1126 // 1127 // TODO(mdempsky): Is this level of complexity really worthwhile? 1128 func (w *exportWriter) mpint(x *big.Int, typ types.Type) { 1129 basic, ok := typ.Underlying().(*types.Basic) 1130 if !ok { 1131 panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying())) 1132 } 1133 1134 signed, maxBytes := intSize(basic) 1135 1136 negative := x.Sign() < 0 1137 if !signed && negative { 1138 panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x)) 1139 } 1140 1141 b := x.Bytes() 1142 if len(b) > 0 && b[0] == 0 { 1143 panic(internalErrorf("leading zeros")) 1144 } 1145 if uint(len(b)) > maxBytes { 1146 panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x)) 1147 } 1148 1149 maxSmall := 256 - maxBytes 1150 if signed { 1151 maxSmall = 256 - 2*maxBytes 1152 } 1153 if maxBytes == 1 { 1154 maxSmall = 256 1155 } 1156 1157 // Check if x can use small value encoding. 1158 if len(b) <= 1 { 1159 var ux uint 1160 if len(b) == 1 { 1161 ux = uint(b[0]) 1162 } 1163 if signed { 1164 ux <<= 1 1165 if negative { 1166 ux-- 1167 } 1168 } 1169 if ux < maxSmall { 1170 w.data.WriteByte(byte(ux)) 1171 return 1172 } 1173 } 1174 1175 n := 256 - uint(len(b)) 1176 if signed { 1177 n = 256 - 2*uint(len(b)) 1178 if negative { 1179 n |= 1 1180 } 1181 } 1182 if n < maxSmall || n >= 256 { 1183 panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n)) 1184 } 1185 1186 w.data.WriteByte(byte(n)) 1187 w.data.Write(b) 1188 } 1189 1190 // mpfloat exports a multi-precision floating point number. 1191 // 1192 // The number's value is decomposed into mantissa × 2**exponent, where 1193 // mantissa is an integer. The value is written out as mantissa (as a 1194 // multi-precision integer) and then the exponent, except exponent is 1195 // omitted if mantissa is zero. 1196 func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) { 1197 if f.IsInf() { 1198 panic("infinite constant") 1199 } 1200 1201 // Break into f = mant × 2**exp, with 0.5 <= mant < 1. 1202 var mant big.Float 1203 exp := int64(f.MantExp(&mant)) 1204 1205 // Scale so that mant is an integer. 1206 prec := mant.MinPrec() 1207 mant.SetMantExp(&mant, int(prec)) 1208 exp -= int64(prec) 1209 1210 manti, acc := mant.Int(nil) 1211 if acc != big.Exact { 1212 panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc)) 1213 } 1214 w.mpint(manti, typ) 1215 if manti.Sign() != 0 { 1216 w.int64(exp) 1217 } 1218 } 1219 1220 func (w *exportWriter) bool(b bool) bool { 1221 var x uint64 1222 if b { 1223 x = 1 1224 } 1225 w.uint64(x) 1226 return b 1227 } 1228 1229 func (w *exportWriter) int64(x int64) { w.data.int64(x) } 1230 func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) } 1231 func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) } 1232 1233 func (w *exportWriter) localIdent(obj types.Object) { 1234 // Anonymous parameters. 1235 if obj == nil { 1236 w.string("") 1237 return 1238 } 1239 1240 name := obj.Name() 1241 if name == "_" { 1242 w.string("_") 1243 return 1244 } 1245 1246 w.string(name) 1247 } 1248 1249 type intWriter struct { 1250 bytes.Buffer 1251 } 1252 1253 func (w *intWriter) int64(x int64) { 1254 var buf [binary.MaxVarintLen64]byte 1255 n := binary.PutVarint(buf[:], x) 1256 w.Write(buf[:n]) 1257 } 1258 1259 func (w *intWriter) uint64(x uint64) { 1260 var buf [binary.MaxVarintLen64]byte 1261 n := binary.PutUvarint(buf[:], x) 1262 w.Write(buf[:n]) 1263 } 1264 1265 func assert(cond bool) { 1266 if !cond { 1267 panic("internal error: assertion failed") 1268 } 1269 } 1270 1271 // The below is copied from go/src/cmd/compile/internal/gc/syntax.go. 1272 1273 // objQueue is a FIFO queue of types.Object. The zero value of objQueue is 1274 // a ready-to-use empty queue. 1275 type objQueue struct { 1276 ring []types.Object 1277 head, tail int 1278 } 1279 1280 // empty returns true if q contains no Nodes. 1281 func (q *objQueue) empty() bool { 1282 return q.head == q.tail 1283 } 1284 1285 // pushTail appends n to the tail of the queue. 1286 func (q *objQueue) pushTail(obj types.Object) { 1287 if len(q.ring) == 0 { 1288 q.ring = make([]types.Object, 16) 1289 } else if q.head+len(q.ring) == q.tail { 1290 // Grow the ring. 1291 nring := make([]types.Object, len(q.ring)*2) 1292 // Copy the old elements. 1293 part := q.ring[q.head%len(q.ring):] 1294 if q.tail-q.head <= len(part) { 1295 part = part[:q.tail-q.head] 1296 copy(nring, part) 1297 } else { 1298 pos := copy(nring, part) 1299 copy(nring[pos:], q.ring[:q.tail%len(q.ring)]) 1300 } 1301 q.ring, q.head, q.tail = nring, 0, q.tail-q.head 1302 } 1303 1304 q.ring[q.tail%len(q.ring)] = obj 1305 q.tail++ 1306 } 1307 1308 // popHead pops a node from the head of the queue. It panics if q is empty. 1309 func (q *objQueue) popHead() types.Object { 1310 if q.empty() { 1311 panic("dequeue empty") 1312 } 1313 obj := q.ring[q.head%len(q.ring)] 1314 q.head++ 1315 return obj 1316 } 1317 1318 // internalError represents an error generated inside this package. 1319 type internalError string 1320 1321 func (e internalError) Error() string { return "gcimporter: " + string(e) } 1322 1323 // TODO(adonovan): make this call panic, so that it's symmetric with errorf. 1324 // Otherwise it's easy to forget to do anything with the error. 1325 // 1326 // TODO(adonovan): also, consider switching the names "errorf" and 1327 // "internalErrorf" as the former is used for bugs, whose cause is 1328 // internal inconsistency, whereas the latter is used for ordinary 1329 // situations like bad input, whose cause is external. 1330 func internalErrorf(format string, args ...interface{}) error { 1331 return internalError(fmt.Sprintf(format, args...)) 1332 }