1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227 package gcimporter
228
229 import (
230 "bytes"
231 "encoding/binary"
232 "fmt"
233 "go/constant"
234 "go/token"
235 "go/types"
236 "io"
237 "math/big"
238 "reflect"
239 "slices"
240 "sort"
241 "strconv"
242 "strings"
243
244 "golang.org/x/tools/go/types/objectpath"
245 )
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278 func IExportShallow(fset *token.FileSet, pkg *types.Package, reportf ReportFunc) ([]byte, error) {
279
280
281
282
283
284 const bundle, shallow = false, true
285 var out bytes.Buffer
286 err := iexportCommon(&out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}, reportf)
287 return out.Bytes(), err
288 }
289
290
291
292
293
294
295
296
297
298
299
300
301
302 func IImportShallow(fset *token.FileSet, getPackages GetPackagesFunc, data []byte, path string, reportf ReportFunc) (*types.Package, error) {
303 const bundle = false
304 const shallow = true
305 pkgs, err := iimportCommon(fset, getPackages, data, bundle, path, shallow, reportf)
306 if err != nil {
307 return nil, err
308 }
309 return pkgs[0], nil
310 }
311
312
313 type ReportFunc = func(string, ...any)
314
315
316
317 const bundleVersion = 0
318
319
320
321
322
323
324 func IExportData(out io.Writer, fset *token.FileSet, pkg *types.Package) error {
325 const bundle, shallow = false, false
326 return iexportCommon(out, fset, bundle, shallow, iexportVersion, []*types.Package{pkg}, nil)
327 }
328
329
330 func IExportBundle(out io.Writer, fset *token.FileSet, pkgs []*types.Package) error {
331 const bundle, shallow = true, false
332 return iexportCommon(out, fset, bundle, shallow, iexportVersion, pkgs, nil)
333 }
334
335 func iexportCommon(out io.Writer, fset *token.FileSet, bundle, shallow bool, version int, pkgs []*types.Package, reportf ReportFunc) (err error) {
336 if !debug {
337 defer func() {
338 if e := recover(); e != nil {
339
340 if reportf != nil {
341 reportf("panic in exporter")
342 }
343 if ierr, ok := e.(internalError); ok {
344
345
346
347 err = ierr
348 return
349 }
350
351 panic(e)
352 }
353 }()
354 }
355
356 p := iexporter{
357 fset: fset,
358 version: version,
359 shallow: shallow,
360 allPkgs: map[*types.Package]bool{},
361 stringIndex: map[string]uint64{},
362 declIndex: map[types.Object]uint64{},
363 tparamNames: map[types.Object]string{},
364 typIndex: map[types.Type]uint64{},
365 }
366 if !bundle {
367 p.localpkg = pkgs[0]
368 }
369
370 for i, pt := range predeclared() {
371 p.typIndex[pt] = uint64(i)
372 }
373 if len(p.typIndex) > predeclReserved {
374 panic(internalErrorf("too many predeclared types: %d > %d", len(p.typIndex), predeclReserved))
375 }
376
377
378 for _, pkg := range pkgs {
379 scope := pkg.Scope()
380 for _, name := range scope.Names() {
381 if token.IsExported(name) {
382 p.pushDecl(scope.Lookup(name))
383 }
384 }
385
386 if bundle {
387
388 p.allPkgs[pkg] = true
389 for _, imp := range pkg.Imports() {
390 p.allPkgs[imp] = true
391 }
392 }
393 }
394
395
396 for !p.declTodo.empty() {
397 p.doDecl(p.declTodo.popHead())
398 }
399
400
401 var files intWriter
402 var fileOffset []uint64
403 if p.shallow {
404 fileOffset = make([]uint64, len(p.fileInfos))
405 for i, info := range p.fileInfos {
406 fileOffset[i] = uint64(files.Len())
407 p.encodeFile(&files, info.file, info.needed)
408 }
409 }
410
411
412 dataLen := uint64(p.data0.Len())
413 w := p.newWriter()
414 w.writeIndex(p.declIndex)
415
416 if bundle {
417 w.uint64(uint64(len(pkgs)))
418 for _, pkg := range pkgs {
419 w.pkg(pkg)
420 imps := pkg.Imports()
421 w.uint64(uint64(len(imps)))
422 for _, imp := range imps {
423 w.pkg(imp)
424 }
425 }
426 }
427 w.flush()
428
429
430 var hdr intWriter
431 if bundle {
432 hdr.uint64(bundleVersion)
433 }
434 hdr.uint64(uint64(p.version))
435 hdr.uint64(uint64(p.strings.Len()))
436 if p.shallow {
437 hdr.uint64(uint64(files.Len()))
438 hdr.uint64(uint64(len(fileOffset)))
439 for _, offset := range fileOffset {
440 hdr.uint64(offset)
441 }
442 }
443 hdr.uint64(dataLen)
444
445
446 io.Copy(out, &hdr)
447 io.Copy(out, &p.strings)
448 if p.shallow {
449 io.Copy(out, &files)
450 }
451 io.Copy(out, &p.data0)
452
453 return nil
454 }
455
456
457
458
459 func (p *iexporter) encodeFile(w *intWriter, file *token.File, needed []uint64) {
460 _ = needed[0]
461
462 w.uint64(p.stringOff(file.Name()))
463
464 size := uint64(file.Size())
465 w.uint64(size)
466
467
468 slices.Sort(needed)
469
470 lines := file.Lines()
471 w.uint64(uint64(len(lines)))
472
473
474
475
476 var sparse [][2]int
477 outer:
478 for i, lineStart := range lines {
479 lineEnd := size
480 if i < len(lines)-1 {
481 lineEnd = uint64(lines[i+1])
482 }
483
484 if needed[0] < lineEnd {
485 sparse = append(sparse, [2]int{i, lineStart})
486 for needed[0] < lineEnd {
487 needed = needed[1:]
488 if len(needed) == 0 {
489 break outer
490 }
491 }
492 }
493 }
494
495
496 w.uint64(uint64(len(sparse)))
497 var prev [2]int
498 for _, pair := range sparse {
499 w.uint64(uint64(pair[0] - prev[0]))
500 w.uint64(uint64(pair[1] - prev[1]))
501 prev = pair
502 }
503 }
504
505
506
507
508
509 func (w *exportWriter) writeIndex(index map[types.Object]uint64) {
510 type pkgObj struct {
511 obj types.Object
512 name string
513 }
514
515 pkgObjs := map[*types.Package][]pkgObj{}
516
517
518
519
520 if w.p.localpkg != nil {
521 pkgObjs[w.p.localpkg] = nil
522 }
523 for pkg := range w.p.allPkgs {
524 pkgObjs[pkg] = nil
525 }
526
527 for obj := range index {
528 name := w.p.exportName(obj)
529 pkgObjs[obj.Pkg()] = append(pkgObjs[obj.Pkg()], pkgObj{obj, name})
530 }
531
532 var pkgs []*types.Package
533 for pkg, objs := range pkgObjs {
534 pkgs = append(pkgs, pkg)
535
536 sort.Slice(objs, func(i, j int) bool {
537 return objs[i].name < objs[j].name
538 })
539 }
540
541 sort.Slice(pkgs, func(i, j int) bool {
542 return w.exportPath(pkgs[i]) < w.exportPath(pkgs[j])
543 })
544
545 w.uint64(uint64(len(pkgs)))
546 for _, pkg := range pkgs {
547 w.string(w.exportPath(pkg))
548 w.string(pkg.Name())
549 w.uint64(uint64(0))
550
551 objs := pkgObjs[pkg]
552 w.uint64(uint64(len(objs)))
553 for _, obj := range objs {
554 w.string(obj.name)
555 w.uint64(index[obj.obj])
556 }
557 }
558 }
559
560
561
562 func (p *iexporter) exportName(obj types.Object) (res string) {
563 if name := p.tparamNames[obj]; name != "" {
564 return name
565 }
566 return obj.Name()
567 }
568
569 type iexporter struct {
570 fset *token.FileSet
571 version int
572
573 shallow bool
574 objEncoder *objectpath.Encoder
575 localpkg *types.Package
576
577
578
579
580 allPkgs map[*types.Package]bool
581
582 declTodo objQueue
583
584 strings intWriter
585 stringIndex map[string]uint64
586
587
588
589
590 fileInfo map[*token.File]uint64
591 fileInfos []*filePositions
592
593 data0 intWriter
594 declIndex map[types.Object]uint64
595 tparamNames map[types.Object]string
596 typIndex map[types.Type]uint64
597
598 indent int
599 }
600
601 type filePositions struct {
602 file *token.File
603 needed []uint64
604 }
605
606 func (p *iexporter) trace(format string, args ...any) {
607 if !trace {
608
609
610 return
611 }
612 fmt.Printf(strings.Repeat("..", p.indent)+format+"\n", args...)
613 }
614
615
616
617
618
619 func (p *iexporter) objectpathEncoder() *objectpath.Encoder {
620 if p.objEncoder == nil {
621 p.objEncoder = new(objectpath.Encoder)
622 }
623 return p.objEncoder
624 }
625
626
627
628 func (p *iexporter) stringOff(s string) uint64 {
629 off, ok := p.stringIndex[s]
630 if !ok {
631 off = uint64(p.strings.Len())
632 p.stringIndex[s] = off
633
634 p.strings.uint64(uint64(len(s)))
635 p.strings.WriteString(s)
636 }
637 return off
638 }
639
640
641 func (p *iexporter) fileIndexAndOffset(file *token.File, pos token.Pos) (uint64, uint64) {
642 index, ok := p.fileInfo[file]
643 if !ok {
644 index = uint64(len(p.fileInfo))
645 p.fileInfos = append(p.fileInfos, &filePositions{file: file})
646 if p.fileInfo == nil {
647 p.fileInfo = make(map[*token.File]uint64)
648 }
649 p.fileInfo[file] = index
650 }
651
652 info := p.fileInfos[index]
653 offset := uint64(file.Offset(pos))
654 info.needed = append(info.needed, offset)
655
656 return index, offset
657 }
658
659
660 func (p *iexporter) pushDecl(obj types.Object) {
661
662
663 if obj.Pkg() == types.Unsafe {
664 panic("cannot export package unsafe")
665 }
666
667
668 if p.shallow && obj.Pkg() != p.localpkg {
669 return
670 }
671
672 if _, ok := p.declIndex[obj]; ok {
673 return
674 }
675
676 p.declIndex[obj] = ^uint64(0)
677 p.declTodo.pushTail(obj)
678 }
679
680
681 type exportWriter struct {
682 p *iexporter
683
684 data intWriter
685 prevFile string
686 prevLine int64
687 prevColumn int64
688 }
689
690 func (w *exportWriter) exportPath(pkg *types.Package) string {
691 if pkg == w.p.localpkg {
692 return ""
693 }
694 return pkg.Path()
695 }
696
697 func (p *iexporter) doDecl(obj types.Object) {
698 if trace {
699 p.trace("exporting decl %v (%T)", obj, obj)
700 p.indent++
701 defer func() {
702 p.indent--
703 p.trace("=> %s", obj)
704 }()
705 }
706 w := p.newWriter()
707
708 switch obj := obj.(type) {
709 case *types.Var:
710 w.tag(varTag)
711 w.pos(obj.Pos())
712 w.typ(obj.Type(), obj.Pkg())
713
714 case *types.Func:
715 sig, _ := obj.Type().(*types.Signature)
716 if sig.Recv() != nil {
717
718
719
720
721 if sig.Recv().Type() != types.Typ[types.Invalid] {
722 panic(internalErrorf("unexpected method: %v", sig))
723 }
724 }
725
726
727 if sig.TypeParams().Len() == 0 {
728 w.tag(funcTag)
729 } else {
730 w.tag(genericFuncTag)
731 }
732 w.pos(obj.Pos())
733
734
735
736
737
738
739
740 if tparams := sig.TypeParams(); tparams.Len() > 0 {
741 w.tparamList(obj.Name(), tparams, obj.Pkg())
742 }
743 w.signature(sig)
744
745 case *types.Const:
746 w.tag(constTag)
747 w.pos(obj.Pos())
748 w.value(obj.Type(), obj.Val())
749
750 case *types.TypeName:
751 t := obj.Type()
752
753 if tparam, ok := types.Unalias(t).(*types.TypeParam); ok {
754 w.tag(typeParamTag)
755 w.pos(obj.Pos())
756 constraint := tparam.Constraint()
757 if p.version >= iexportVersionGo1_18 {
758 implicit := false
759 if iface, _ := types.Unalias(constraint).(*types.Interface); iface != nil {
760 implicit = iface.IsImplicit()
761 }
762 w.bool(implicit)
763 }
764 w.typ(constraint, obj.Pkg())
765 break
766 }
767
768 if obj.IsAlias() {
769 alias, materialized := t.(*types.Alias)
770
771 var tparams *types.TypeParamList
772 if materialized {
773 tparams = alias.TypeParams()
774 }
775 if tparams.Len() == 0 {
776 w.tag(aliasTag)
777 } else {
778 w.tag(genericAliasTag)
779 }
780 w.pos(obj.Pos())
781 if tparams.Len() > 0 {
782 w.tparamList(obj.Name(), tparams, obj.Pkg())
783 }
784 if materialized {
785
786
787 t = alias.Rhs()
788 }
789 w.typ(t, obj.Pkg())
790 break
791 }
792
793
794 named, ok := t.(*types.Named)
795 if !ok {
796 panic(internalErrorf("%s is not a defined type", t))
797 }
798
799 if named.TypeParams().Len() == 0 {
800 w.tag(typeTag)
801 } else {
802 w.tag(genericTypeTag)
803 }
804 w.pos(obj.Pos())
805
806 if named.TypeParams().Len() > 0 {
807
808
809 w.tparamList(obj.Name(), named.TypeParams(), obj.Pkg())
810 }
811
812 underlying := named.Underlying()
813 w.typ(underlying, obj.Pkg())
814
815 if types.IsInterface(t) {
816 break
817 }
818
819 n := named.NumMethods()
820 w.uint64(uint64(n))
821 for i := range n {
822 m := named.Method(i)
823 w.pos(m.Pos())
824 w.string(m.Name())
825 sig, _ := m.Type().(*types.Signature)
826 if w.p.version >= iexportVersionGenericMethods && w.bool(sig.TypeParams().Len() > 0) {
827 w.tparamList(obj.Name()+"."+m.Name(), sig.TypeParams(), obj.Pkg())
828 }
829
830
831
832 if rparams := sig.RecvTypeParams(); rparams.Len() > 0 {
833 prefix := obj.Name() + "." + m.Name()
834 for rparam := range rparams.TypeParams() {
835 name := tparamExportName(prefix, rparam)
836 w.p.tparamNames[rparam.Obj()] = name
837 }
838 }
839 w.param(sig.Recv())
840 w.signature(sig)
841 }
842
843 default:
844 panic(internalErrorf("unexpected object: %v", obj))
845 }
846
847 p.declIndex[obj] = w.flush()
848 }
849
850 func (w *exportWriter) tag(tag byte) {
851 w.data.WriteByte(tag)
852 }
853
854 func (w *exportWriter) pos(pos token.Pos) {
855 if w.p.shallow {
856 w.posV2(pos)
857 } else if w.p.version >= iexportVersionPosCol {
858 w.posV1(pos)
859 } else {
860 w.posV0(pos)
861 }
862 }
863
864
865
866
867
868 func (w *exportWriter) posV2(pos token.Pos) {
869 if pos == token.NoPos {
870 w.uint64(0)
871 return
872 }
873 file := w.p.fset.File(pos)
874 index, offset := w.p.fileIndexAndOffset(file, pos)
875 w.uint64(1 + index)
876 w.uint64(offset)
877 }
878
879 func (w *exportWriter) posV1(pos token.Pos) {
880 if w.p.fset == nil {
881 w.int64(0)
882 return
883 }
884
885 p := w.p.fset.Position(pos)
886 file := p.Filename
887 line := int64(p.Line)
888 column := int64(p.Column)
889
890 deltaColumn := (column - w.prevColumn) << 1
891 deltaLine := (line - w.prevLine) << 1
892
893 if file != w.prevFile {
894 deltaLine |= 1
895 }
896 if deltaLine != 0 {
897 deltaColumn |= 1
898 }
899
900 w.int64(deltaColumn)
901 if deltaColumn&1 != 0 {
902 w.int64(deltaLine)
903 if deltaLine&1 != 0 {
904 w.string(file)
905 }
906 }
907
908 w.prevFile = file
909 w.prevLine = line
910 w.prevColumn = column
911 }
912
913 func (w *exportWriter) posV0(pos token.Pos) {
914 if w.p.fset == nil {
915 w.int64(0)
916 return
917 }
918
919 p := w.p.fset.Position(pos)
920 file := p.Filename
921 line := int64(p.Line)
922
923
924
925
926
927
928
929
930
931
932 if file == w.prevFile {
933 delta := line - w.prevLine
934 w.int64(delta)
935 if delta == deltaNewFile {
936 w.int64(-1)
937 }
938 } else {
939 w.int64(deltaNewFile)
940 w.int64(line)
941 w.string(file)
942 w.prevFile = file
943 }
944 w.prevLine = line
945 }
946
947 func (w *exportWriter) pkg(pkg *types.Package) {
948 if pkg == nil {
949
950
951
952
953 panic("nil package")
954 }
955
956 w.p.allPkgs[pkg] = true
957
958 w.string(w.exportPath(pkg))
959 }
960
961 func (w *exportWriter) qualifiedType(obj *types.TypeName) {
962 name := w.p.exportName(obj)
963
964
965 w.p.pushDecl(obj)
966 w.string(name)
967 w.pkg(obj.Pkg())
968 }
969
970
971
972
973
974
975 func (w *exportWriter) typ(t types.Type, pkg *types.Package) {
976 w.data.uint64(w.p.typOff(t, pkg))
977 }
978
979 func (p *iexporter) newWriter() *exportWriter {
980 return &exportWriter{p: p}
981 }
982
983 func (w *exportWriter) flush() uint64 {
984 off := uint64(w.p.data0.Len())
985 io.Copy(&w.p.data0, &w.data)
986 return off
987 }
988
989 func (p *iexporter) typOff(t types.Type, pkg *types.Package) uint64 {
990 off, ok := p.typIndex[t]
991 if !ok {
992 w := p.newWriter()
993 w.doTyp(t, pkg)
994 off = predeclReserved + w.flush()
995 p.typIndex[t] = off
996 }
997 return off
998 }
999
1000 func (w *exportWriter) startType(k itag) {
1001 w.data.uint64(uint64(k))
1002 }
1003
1004
1005 func (w *exportWriter) doTyp(t types.Type, pkg *types.Package) {
1006 if trace {
1007 w.p.trace("exporting type %s (%T)", t, t)
1008 w.p.indent++
1009 defer func() {
1010 w.p.indent--
1011 w.p.trace("=> %s", t)
1012 }()
1013 }
1014 switch t := t.(type) {
1015 case *types.Alias:
1016 if targs := t.TypeArgs(); targs.Len() > 0 {
1017 w.startType(instanceType)
1018 w.pos(t.Obj().Pos())
1019 w.typeList(targs, pkg)
1020 w.typ(t.Origin(), pkg)
1021 return
1022 }
1023 w.startType(aliasType)
1024 w.qualifiedType(t.Obj())
1025
1026 case *types.Named:
1027 if targs := t.TypeArgs(); targs.Len() > 0 {
1028 w.startType(instanceType)
1029
1030
1031 w.pos(t.Obj().Pos())
1032 w.typeList(targs, pkg)
1033 w.typ(t.Origin(), pkg)
1034 return
1035 }
1036 w.startType(definedType)
1037 w.qualifiedType(t.Obj())
1038
1039 case *types.TypeParam:
1040 w.startType(typeParamType)
1041 w.qualifiedType(t.Obj())
1042
1043 case *types.Pointer:
1044 w.startType(pointerType)
1045 w.typ(t.Elem(), pkg)
1046
1047 case *types.Slice:
1048 w.startType(sliceType)
1049 w.typ(t.Elem(), pkg)
1050
1051 case *types.Array:
1052 w.startType(arrayType)
1053 w.uint64(uint64(t.Len()))
1054 w.typ(t.Elem(), pkg)
1055
1056 case *types.Chan:
1057 w.startType(chanType)
1058
1059 var dir uint64
1060 switch t.Dir() {
1061 case types.RecvOnly:
1062 dir = 1
1063 case types.SendOnly:
1064 dir = 2
1065 case types.SendRecv:
1066 dir = 3
1067 }
1068 w.uint64(dir)
1069 w.typ(t.Elem(), pkg)
1070
1071 case *types.Map:
1072 w.startType(mapType)
1073 w.typ(t.Key(), pkg)
1074 w.typ(t.Elem(), pkg)
1075
1076 case *types.Signature:
1077 w.startType(signatureType)
1078 w.pkg(pkg)
1079 w.signature(t)
1080
1081 case *types.Struct:
1082 w.startType(structType)
1083 n := t.NumFields()
1084
1085
1086 fieldPkg := pkg
1087 if n > 0 {
1088 fieldPkg = t.Field(0).Pkg()
1089 }
1090 if fieldPkg == nil {
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101 if w.p.shallow {
1102 fieldPkg = w.p.localpkg
1103 } else {
1104 panic(internalErrorf("no package to set for empty struct"))
1105 }
1106 }
1107 w.pkg(fieldPkg)
1108 w.uint64(uint64(n))
1109
1110 for i := range n {
1111 f := t.Field(i)
1112 if w.p.shallow {
1113 w.objectPath(f)
1114 }
1115 w.pos(f.Pos())
1116 w.string(f.Name())
1117 w.typ(f.Type(), fieldPkg)
1118 w.bool(f.Anonymous())
1119 w.string(t.Tag(i))
1120 }
1121
1122 case *types.Interface:
1123 w.startType(interfaceType)
1124 w.pkg(pkg)
1125
1126 n := t.NumEmbeddeds()
1127 w.uint64(uint64(n))
1128 for i := 0; i < n; i++ {
1129 ft := t.EmbeddedType(i)
1130 if named, _ := types.Unalias(ft).(*types.Named); named != nil {
1131 w.pos(named.Obj().Pos())
1132 } else {
1133
1134 w.pos(token.NoPos)
1135 }
1136 w.typ(ft, pkg)
1137 }
1138
1139
1140
1141
1142 n = t.NumExplicitMethods()
1143 w.uint64(uint64(n))
1144 for i := 0; i < n; i++ {
1145 m := t.ExplicitMethod(i)
1146 if w.p.shallow {
1147 w.objectPath(m)
1148 }
1149 w.pos(m.Pos())
1150 w.string(m.Name())
1151 sig, _ := m.Type().(*types.Signature)
1152 w.signature(sig)
1153 }
1154
1155 case *types.Union:
1156 w.startType(unionType)
1157 nt := t.Len()
1158 w.uint64(uint64(nt))
1159 for i := range nt {
1160 term := t.Term(i)
1161 w.bool(term.Tilde())
1162 w.typ(term.Type(), pkg)
1163 }
1164
1165 default:
1166 panic(internalErrorf("unexpected type: %v, %v", t, reflect.TypeOf(t)))
1167 }
1168 }
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191 func (w *exportWriter) objectPath(obj types.Object) {
1192 if obj.Pkg() == nil || obj.Pkg() == w.p.localpkg {
1193
1194
1195
1196 w.string("")
1197 return
1198 }
1199 objectPath, err := w.p.objectpathEncoder().For(obj)
1200 if err != nil {
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220 w.string("")
1221 return
1222 }
1223 w.string(string(objectPath))
1224 w.pkg(obj.Pkg())
1225 }
1226
1227 func (w *exportWriter) signature(sig *types.Signature) {
1228 w.paramList(sig.Params())
1229 w.paramList(sig.Results())
1230 if sig.Params().Len() > 0 {
1231 w.bool(sig.Variadic())
1232 }
1233 }
1234
1235 func (w *exportWriter) typeList(ts *types.TypeList, pkg *types.Package) {
1236 w.uint64(uint64(ts.Len()))
1237 for t := range ts.Types() {
1238 w.typ(t, pkg)
1239 }
1240 }
1241
1242 func (w *exportWriter) tparamList(prefix string, list *types.TypeParamList, pkg *types.Package) {
1243 ll := uint64(list.Len())
1244 w.uint64(ll)
1245 for tparam := range list.TypeParams() {
1246
1247 exportName := tparamExportName(prefix, tparam)
1248 w.p.tparamNames[tparam.Obj()] = exportName
1249 w.typ(tparam, pkg)
1250 }
1251 }
1252
1253 const blankMarker = "$"
1254
1255
1256
1257
1258
1259 func tparamExportName(prefix string, tparam *types.TypeParam) string {
1260 assert(prefix != "")
1261 name := tparam.Obj().Name()
1262 if name == "_" {
1263 name = blankMarker + strconv.Itoa(tparam.Index())
1264 }
1265 return prefix + "." + name
1266 }
1267
1268
1269
1270
1271 func tparamName(exportName string) string {
1272
1273 ix := strings.LastIndex(exportName, ".")
1274 if ix < 0 {
1275 errorf("malformed type parameter export name %s: missing prefix", exportName)
1276 }
1277 name := exportName[ix+1:]
1278 if strings.HasPrefix(name, blankMarker) {
1279 return "_"
1280 }
1281 return name
1282 }
1283
1284 func (w *exportWriter) paramList(tup *types.Tuple) {
1285 n := tup.Len()
1286 w.uint64(uint64(n))
1287 for i := range n {
1288 w.param(tup.At(i))
1289 }
1290 }
1291
1292 func (w *exportWriter) param(obj types.Object) {
1293 w.pos(obj.Pos())
1294 w.localIdent(obj)
1295 w.typ(obj.Type(), obj.Pkg())
1296 }
1297
1298 func (w *exportWriter) value(typ types.Type, v constant.Value) {
1299 w.typ(typ, nil)
1300 if w.p.version >= iexportVersionGo1_18 {
1301 w.int64(int64(v.Kind()))
1302 }
1303
1304 if v.Kind() == constant.Unknown {
1305
1306
1307
1308
1309
1310
1311
1312 return
1313 }
1314
1315 switch b := typ.Underlying().(*types.Basic); b.Info() & types.IsConstType {
1316 case types.IsBoolean:
1317 w.bool(constant.BoolVal(v))
1318 case types.IsInteger:
1319 var i big.Int
1320 if i64, exact := constant.Int64Val(v); exact {
1321 i.SetInt64(i64)
1322 } else if ui64, exact := constant.Uint64Val(v); exact {
1323 i.SetUint64(ui64)
1324 } else {
1325 i.SetString(v.ExactString(), 10)
1326 }
1327 w.mpint(&i, typ)
1328 case types.IsFloat:
1329 f := constantToFloat(v)
1330 w.mpfloat(f, typ)
1331 case types.IsComplex:
1332 w.mpfloat(constantToFloat(constant.Real(v)), typ)
1333 w.mpfloat(constantToFloat(constant.Imag(v)), typ)
1334 case types.IsString:
1335 w.string(constant.StringVal(v))
1336 default:
1337 if b.Kind() == types.Invalid {
1338
1339 break
1340 }
1341 panic(internalErrorf("unexpected type %v (%v)", typ, typ.Underlying()))
1342 }
1343 }
1344
1345
1346
1347 func constantToFloat(x constant.Value) *big.Float {
1348 x = constant.ToFloat(x)
1349
1350
1351 const mpprec = 512
1352 var f big.Float
1353 f.SetPrec(mpprec)
1354 if v, exact := constant.Float64Val(x); exact {
1355
1356 f.SetFloat64(v)
1357 } else if num, denom := constant.Num(x), constant.Denom(x); num.Kind() == constant.Int {
1358
1359 n := valueToRat(num)
1360 d := valueToRat(denom)
1361 f.SetRat(n.Quo(n, d))
1362 } else {
1363
1364
1365 _, ok := f.SetString(x.ExactString())
1366 assert(ok)
1367 }
1368 return &f
1369 }
1370
1371 func valueToRat(x constant.Value) *big.Rat {
1372
1373
1374 bytes := constant.Bytes(x)
1375 for i := 0; i < len(bytes)/2; i++ {
1376 bytes[i], bytes[len(bytes)-1-i] = bytes[len(bytes)-1-i], bytes[i]
1377 }
1378 return new(big.Rat).SetInt(new(big.Int).SetBytes(bytes))
1379 }
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401 func (w *exportWriter) mpint(x *big.Int, typ types.Type) {
1402 basic, ok := typ.Underlying().(*types.Basic)
1403 if !ok {
1404 panic(internalErrorf("unexpected type %v (%T)", typ.Underlying(), typ.Underlying()))
1405 }
1406
1407 signed, maxBytes := intSize(basic)
1408
1409 negative := x.Sign() < 0
1410 if !signed && negative {
1411 panic(internalErrorf("negative unsigned integer; type %v, value %v", typ, x))
1412 }
1413
1414 b := x.Bytes()
1415 if len(b) > 0 && b[0] == 0 {
1416 panic(internalErrorf("leading zeros"))
1417 }
1418 if uint(len(b)) > maxBytes {
1419 panic(internalErrorf("bad mpint length: %d > %d (type %v, value %v)", len(b), maxBytes, typ, x))
1420 }
1421
1422 maxSmall := 256 - maxBytes
1423 if signed {
1424 maxSmall = 256 - 2*maxBytes
1425 }
1426 if maxBytes == 1 {
1427 maxSmall = 256
1428 }
1429
1430
1431 if len(b) <= 1 {
1432 var ux uint
1433 if len(b) == 1 {
1434 ux = uint(b[0])
1435 }
1436 if signed {
1437 ux <<= 1
1438 if negative {
1439 ux--
1440 }
1441 }
1442 if ux < maxSmall {
1443 w.data.WriteByte(byte(ux))
1444 return
1445 }
1446 }
1447
1448 n := 256 - uint(len(b))
1449 if signed {
1450 n = 256 - 2*uint(len(b))
1451 if negative {
1452 n |= 1
1453 }
1454 }
1455 if n < maxSmall || n >= 256 {
1456 panic(internalErrorf("encoding mistake: %d, %v, %v => %d", len(b), signed, negative, n))
1457 }
1458
1459 w.data.WriteByte(byte(n))
1460 w.data.Write(b)
1461 }
1462
1463
1464
1465
1466
1467
1468
1469 func (w *exportWriter) mpfloat(f *big.Float, typ types.Type) {
1470 if f.IsInf() {
1471 panic("infinite constant")
1472 }
1473
1474
1475 var mant big.Float
1476 exp := int64(f.MantExp(&mant))
1477
1478
1479 prec := mant.MinPrec()
1480 mant.SetMantExp(&mant, int(prec))
1481 exp -= int64(prec)
1482
1483 manti, acc := mant.Int(nil)
1484 if acc != big.Exact {
1485 panic(internalErrorf("mantissa scaling failed for %f (%s)", f, acc))
1486 }
1487 w.mpint(manti, typ)
1488 if manti.Sign() != 0 {
1489 w.int64(exp)
1490 }
1491 }
1492
1493 func (w *exportWriter) bool(b bool) bool {
1494 var x uint64
1495 if b {
1496 x = 1
1497 }
1498 w.uint64(x)
1499 return b
1500 }
1501
1502 func (w *exportWriter) int64(x int64) { w.data.int64(x) }
1503 func (w *exportWriter) uint64(x uint64) { w.data.uint64(x) }
1504 func (w *exportWriter) string(s string) { w.uint64(w.p.stringOff(s)) }
1505
1506 func (w *exportWriter) localIdent(obj types.Object) {
1507
1508 if obj == nil {
1509 w.string("")
1510 return
1511 }
1512
1513 name := obj.Name()
1514 if name == "_" {
1515 w.string("_")
1516 return
1517 }
1518
1519 w.string(name)
1520 }
1521
1522 type intWriter struct {
1523 bytes.Buffer
1524 }
1525
1526 func (w *intWriter) int64(x int64) {
1527 var buf [binary.MaxVarintLen64]byte
1528 n := binary.PutVarint(buf[:], x)
1529 w.Write(buf[:n])
1530 }
1531
1532 func (w *intWriter) uint64(x uint64) {
1533 var buf [binary.MaxVarintLen64]byte
1534 n := binary.PutUvarint(buf[:], x)
1535 w.Write(buf[:n])
1536 }
1537
1538 func assert(cond bool) {
1539 if !cond {
1540 panic("internal error: assertion failed")
1541 }
1542 }
1543
1544
1545
1546
1547
1548 type objQueue struct {
1549 ring []types.Object
1550 head, tail int
1551 }
1552
1553
1554 func (q *objQueue) empty() bool {
1555 return q.head == q.tail
1556 }
1557
1558
1559 func (q *objQueue) pushTail(obj types.Object) {
1560 if len(q.ring) == 0 {
1561 q.ring = make([]types.Object, 16)
1562 } else if q.head+len(q.ring) == q.tail {
1563
1564 nring := make([]types.Object, len(q.ring)*2)
1565
1566 part := q.ring[q.head%len(q.ring):]
1567 if q.tail-q.head <= len(part) {
1568 part = part[:q.tail-q.head]
1569 copy(nring, part)
1570 } else {
1571 pos := copy(nring, part)
1572 copy(nring[pos:], q.ring[:q.tail%len(q.ring)])
1573 }
1574 q.ring, q.head, q.tail = nring, 0, q.tail-q.head
1575 }
1576
1577 q.ring[q.tail%len(q.ring)] = obj
1578 q.tail++
1579 }
1580
1581
1582 func (q *objQueue) popHead() types.Object {
1583 if q.empty() {
1584 panic("dequeue empty")
1585 }
1586 obj := q.ring[q.head%len(q.ring)]
1587 q.head++
1588 return obj
1589 }
1590
1591
1592 type internalError string
1593
1594 func (e internalError) Error() string { return "gcimporter: " + string(e) }
1595
1596
1597
1598
1599
1600
1601
1602
1603 func internalErrorf(format string, args ...any) error {
1604 return internalError(fmt.Sprintf(format, args...))
1605 }
1606
View as plain text