1 | // Copyright 2015 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 | // This file is a copy of $GOROOT/src/go/internal/gcimporter/bimport.go. |
6 | |
7 | package gcimporter |
8 | |
9 | import ( |
10 | "encoding/binary" |
11 | "fmt" |
12 | "go/constant" |
13 | "go/token" |
14 | "go/types" |
15 | "sort" |
16 | "strconv" |
17 | "strings" |
18 | "sync" |
19 | "unicode" |
20 | "unicode/utf8" |
21 | ) |
22 | |
23 | type importer struct { |
24 | imports map[string]*types.Package |
25 | data []byte |
26 | importpath string |
27 | buf []byte // for reading strings |
28 | version int // export format version |
29 | |
30 | // object lists |
31 | strList []string // in order of appearance |
32 | pathList []string // in order of appearance |
33 | pkgList []*types.Package // in order of appearance |
34 | typList []types.Type // in order of appearance |
35 | interfaceList []*types.Interface // for delayed completion only |
36 | trackAllTypes bool |
37 | |
38 | // position encoding |
39 | posInfoFormat bool |
40 | prevFile string |
41 | prevLine int |
42 | fake fakeFileSet |
43 | |
44 | // debugging support |
45 | debugFormat bool |
46 | read int // bytes read |
47 | } |
48 | |
49 | // BImportData imports a package from the serialized package data |
50 | // and returns the number of bytes consumed and a reference to the package. |
51 | // If the export data version is not recognized or the format is otherwise |
52 | // compromised, an error is returned. |
53 | func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) { |
54 | // catch panics and return them as errors |
55 | const currentVersion = 6 |
56 | version := -1 // unknown version |
57 | defer func() { |
58 | if e := recover(); e != nil { |
59 | // Return a (possibly nil or incomplete) package unchanged (see #16088). |
60 | if version > currentVersion { |
61 | err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e) |
62 | } else { |
63 | err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e) |
64 | } |
65 | } |
66 | }() |
67 | |
68 | p := importer{ |
69 | imports: imports, |
70 | data: data, |
71 | importpath: path, |
72 | version: version, |
73 | strList: []string{""}, // empty string is mapped to 0 |
74 | pathList: []string{""}, // empty string is mapped to 0 |
75 | fake: fakeFileSet{ |
76 | fset: fset, |
77 | files: make(map[string]*fileInfo), |
78 | }, |
79 | } |
80 | defer p.fake.setLines() // set lines for files in fset |
81 | |
82 | // read version info |
83 | var versionstr string |
84 | if b := p.rawByte(); b == 'c' || b == 'd' { |
85 | // Go1.7 encoding; first byte encodes low-level |
86 | // encoding format (compact vs debug). |
87 | // For backward-compatibility only (avoid problems with |
88 | // old installed packages). Newly compiled packages use |
89 | // the extensible format string. |
90 | // TODO(gri) Remove this support eventually; after Go1.8. |
91 | if b == 'd' { |
92 | p.debugFormat = true |
93 | } |
94 | p.trackAllTypes = p.rawByte() == 'a' |
95 | p.posInfoFormat = p.int() != 0 |
96 | versionstr = p.string() |
97 | if versionstr == "v1" { |
98 | version = 0 |
99 | } |
100 | } else { |
101 | // Go1.8 extensible encoding |
102 | // read version string and extract version number (ignore anything after the version number) |
103 | versionstr = p.rawStringln(b) |
104 | if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" { |
105 | if v, err := strconv.Atoi(s[1]); err == nil && v > 0 { |
106 | version = v |
107 | } |
108 | } |
109 | } |
110 | p.version = version |
111 | |
112 | // read version specific flags - extend as necessary |
113 | switch p.version { |
114 | // case currentVersion: |
115 | // ... |
116 | // fallthrough |
117 | case currentVersion, 5, 4, 3, 2, 1: |
118 | p.debugFormat = p.rawStringln(p.rawByte()) == "debug" |
119 | p.trackAllTypes = p.int() != 0 |
120 | p.posInfoFormat = p.int() != 0 |
121 | case 0: |
122 | // Go1.7 encoding format - nothing to do here |
123 | default: |
124 | errorf("unknown bexport format version %d (%q)", p.version, versionstr) |
125 | } |
126 | |
127 | // --- generic export data --- |
128 | |
129 | // populate typList with predeclared "known" types |
130 | p.typList = append(p.typList, predeclared()...) |
131 | |
132 | // read package data |
133 | pkg = p.pkg() |
134 | |
135 | // read objects of phase 1 only (see cmd/compile/internal/gc/bexport.go) |
136 | objcount := 0 |
137 | for { |
138 | tag := p.tagOrIndex() |
139 | if tag == endTag { |
140 | break |
141 | } |
142 | p.obj(tag) |
143 | objcount++ |
144 | } |
145 | |
146 | // self-verification |
147 | if count := p.int(); count != objcount { |
148 | errorf("got %d objects; want %d", objcount, count) |
149 | } |
150 | |
151 | // ignore compiler-specific import data |
152 | |
153 | // complete interfaces |
154 | // TODO(gri) re-investigate if we still need to do this in a delayed fashion |
155 | for _, typ := range p.interfaceList { |
156 | typ.Complete() |
157 | } |
158 | |
159 | // record all referenced packages as imports |
160 | list := append(([]*types.Package)(nil), p.pkgList[1:]...) |
161 | sort.Sort(byPath(list)) |
162 | pkg.SetImports(list) |
163 | |
164 | // package was imported completely and without errors |
165 | pkg.MarkComplete() |
166 | |
167 | return p.read, pkg, nil |
168 | } |
169 | |
170 | func errorf(format string, args ...interface{}) { |
171 | panic(fmt.Sprintf(format, args...)) |
172 | } |
173 | |
174 | func (p *importer) pkg() *types.Package { |
175 | // if the package was seen before, i is its index (>= 0) |
176 | i := p.tagOrIndex() |
177 | if i >= 0 { |
178 | return p.pkgList[i] |
179 | } |
180 | |
181 | // otherwise, i is the package tag (< 0) |
182 | if i != packageTag { |
183 | errorf("unexpected package tag %d version %d", i, p.version) |
184 | } |
185 | |
186 | // read package data |
187 | name := p.string() |
188 | var path string |
189 | if p.version >= 5 { |
190 | path = p.path() |
191 | } else { |
192 | path = p.string() |
193 | } |
194 | if p.version >= 6 { |
195 | p.int() // package height; unused by go/types |
196 | } |
197 | |
198 | // we should never see an empty package name |
199 | if name == "" { |
200 | errorf("empty package name in import") |
201 | } |
202 | |
203 | // an empty path denotes the package we are currently importing; |
204 | // it must be the first package we see |
205 | if (path == "") != (len(p.pkgList) == 0) { |
206 | errorf("package path %q for pkg index %d", path, len(p.pkgList)) |
207 | } |
208 | |
209 | // if the package was imported before, use that one; otherwise create a new one |
210 | if path == "" { |
211 | path = p.importpath |
212 | } |
213 | pkg := p.imports[path] |
214 | if pkg == nil { |
215 | pkg = types.NewPackage(path, name) |
216 | p.imports[path] = pkg |
217 | } else if pkg.Name() != name { |
218 | errorf("conflicting names %s and %s for package %q", pkg.Name(), name, path) |
219 | } |
220 | p.pkgList = append(p.pkgList, pkg) |
221 | |
222 | return pkg |
223 | } |
224 | |
225 | // objTag returns the tag value for each object kind. |
226 | func objTag(obj types.Object) int { |
227 | switch obj.(type) { |
228 | case *types.Const: |
229 | return constTag |
230 | case *types.TypeName: |
231 | return typeTag |
232 | case *types.Var: |
233 | return varTag |
234 | case *types.Func: |
235 | return funcTag |
236 | default: |
237 | errorf("unexpected object: %v (%T)", obj, obj) // panics |
238 | panic("unreachable") |
239 | } |
240 | } |
241 | |
242 | func sameObj(a, b types.Object) bool { |
243 | // Because unnamed types are not canonicalized, we cannot simply compare types for |
244 | // (pointer) identity. |
245 | // Ideally we'd check equality of constant values as well, but this is good enough. |
246 | return objTag(a) == objTag(b) && types.Identical(a.Type(), b.Type()) |
247 | } |
248 | |
249 | func (p *importer) declare(obj types.Object) { |
250 | pkg := obj.Pkg() |
251 | if alt := pkg.Scope().Insert(obj); alt != nil { |
252 | // This can only trigger if we import a (non-type) object a second time. |
253 | // Excluding type aliases, this cannot happen because 1) we only import a package |
254 | // once; and b) we ignore compiler-specific export data which may contain |
255 | // functions whose inlined function bodies refer to other functions that |
256 | // were already imported. |
257 | // However, type aliases require reexporting the original type, so we need |
258 | // to allow it (see also the comment in cmd/compile/internal/gc/bimport.go, |
259 | // method importer.obj, switch case importing functions). |
260 | // TODO(gri) review/update this comment once the gc compiler handles type aliases. |
261 | if !sameObj(obj, alt) { |
262 | errorf("inconsistent import:\n\t%v\npreviously imported as:\n\t%v\n", obj, alt) |
263 | } |
264 | } |
265 | } |
266 | |
267 | func (p *importer) obj(tag int) { |
268 | switch tag { |
269 | case constTag: |
270 | pos := p.pos() |
271 | pkg, name := p.qualifiedName() |
272 | typ := p.typ(nil, nil) |
273 | val := p.value() |
274 | p.declare(types.NewConst(pos, pkg, name, typ, val)) |
275 | |
276 | case aliasTag: |
277 | // TODO(gri) verify type alias hookup is correct |
278 | pos := p.pos() |
279 | pkg, name := p.qualifiedName() |
280 | typ := p.typ(nil, nil) |
281 | p.declare(types.NewTypeName(pos, pkg, name, typ)) |
282 | |
283 | case typeTag: |
284 | p.typ(nil, nil) |
285 | |
286 | case varTag: |
287 | pos := p.pos() |
288 | pkg, name := p.qualifiedName() |
289 | typ := p.typ(nil, nil) |
290 | p.declare(types.NewVar(pos, pkg, name, typ)) |
291 | |
292 | case funcTag: |
293 | pos := p.pos() |
294 | pkg, name := p.qualifiedName() |
295 | params, isddd := p.paramList() |
296 | result, _ := p.paramList() |
297 | sig := types.NewSignature(nil, params, result, isddd) |
298 | p.declare(types.NewFunc(pos, pkg, name, sig)) |
299 | |
300 | default: |
301 | errorf("unexpected object tag %d", tag) |
302 | } |
303 | } |
304 | |
305 | const deltaNewFile = -64 // see cmd/compile/internal/gc/bexport.go |
306 | |
307 | func (p *importer) pos() token.Pos { |
308 | if !p.posInfoFormat { |
309 | return token.NoPos |
310 | } |
311 | |
312 | file := p.prevFile |
313 | line := p.prevLine |
314 | delta := p.int() |
315 | line += delta |
316 | if p.version >= 5 { |
317 | if delta == deltaNewFile { |
318 | if n := p.int(); n >= 0 { |
319 | // file changed |
320 | file = p.path() |
321 | line = n |
322 | } |
323 | } |
324 | } else { |
325 | if delta == 0 { |
326 | if n := p.int(); n >= 0 { |
327 | // file changed |
328 | file = p.prevFile[:n] + p.string() |
329 | line = p.int() |
330 | } |
331 | } |
332 | } |
333 | p.prevFile = file |
334 | p.prevLine = line |
335 | |
336 | return p.fake.pos(file, line, 0) |
337 | } |
338 | |
339 | // Synthesize a token.Pos |
340 | type fakeFileSet struct { |
341 | fset *token.FileSet |
342 | files map[string]*fileInfo |
343 | } |
344 | |
345 | type fileInfo struct { |
346 | file *token.File |
347 | lastline int |
348 | } |
349 | |
350 | const maxlines = 64 * 1024 |
351 | |
352 | func (s *fakeFileSet) pos(file string, line, column int) token.Pos { |
353 | // TODO(mdempsky): Make use of column. |
354 | |
355 | // Since we don't know the set of needed file positions, we reserve maxlines |
356 | // positions per file. We delay calling token.File.SetLines until all |
357 | // positions have been calculated (by way of fakeFileSet.setLines), so that |
358 | // we can avoid setting unnecessary lines. See also golang/go#46586. |
359 | f := s.files[file] |
360 | if f == nil { |
361 | f = &fileInfo{file: s.fset.AddFile(file, -1, maxlines)} |
362 | s.files[file] = f |
363 | } |
364 | if line > maxlines { |
365 | line = 1 |
366 | } |
367 | if line > f.lastline { |
368 | f.lastline = line |
369 | } |
370 | |
371 | // Return a fake position assuming that f.file consists only of newlines. |
372 | return token.Pos(f.file.Base() + line - 1) |
373 | } |
374 | |
375 | func (s *fakeFileSet) setLines() { |
376 | fakeLinesOnce.Do(func() { |
377 | fakeLines = make([]int, maxlines) |
378 | for i := range fakeLines { |
379 | fakeLines[i] = i |
380 | } |
381 | }) |
382 | for _, f := range s.files { |
383 | f.file.SetLines(fakeLines[:f.lastline]) |
384 | } |
385 | } |
386 | |
387 | var ( |
388 | fakeLines []int |
389 | fakeLinesOnce sync.Once |
390 | ) |
391 | |
392 | func (p *importer) qualifiedName() (pkg *types.Package, name string) { |
393 | name = p.string() |
394 | pkg = p.pkg() |
395 | return |
396 | } |
397 | |
398 | func (p *importer) record(t types.Type) { |
399 | p.typList = append(p.typList, t) |
400 | } |
401 | |
402 | // A dddSlice is a types.Type representing ...T parameters. |
403 | // It only appears for parameter types and does not escape |
404 | // the importer. |
405 | type dddSlice struct { |
406 | elem types.Type |
407 | } |
408 | |
409 | func (t *dddSlice) Underlying() types.Type { return t } |
410 | func (t *dddSlice) String() string { return "..." + t.elem.String() } |
411 | |
412 | // parent is the package which declared the type; parent == nil means |
413 | // the package currently imported. The parent package is needed for |
414 | // exported struct fields and interface methods which don't contain |
415 | // explicit package information in the export data. |
416 | // |
417 | // A non-nil tname is used as the "owner" of the result type; i.e., |
418 | // the result type is the underlying type of tname. tname is used |
419 | // to give interface methods a named receiver type where possible. |
420 | func (p *importer) typ(parent *types.Package, tname *types.Named) types.Type { |
421 | // if the type was seen before, i is its index (>= 0) |
422 | i := p.tagOrIndex() |
423 | if i >= 0 { |
424 | return p.typList[i] |
425 | } |
426 | |
427 | // otherwise, i is the type tag (< 0) |
428 | switch i { |
429 | case namedTag: |
430 | // read type object |
431 | pos := p.pos() |
432 | parent, name := p.qualifiedName() |
433 | scope := parent.Scope() |
434 | obj := scope.Lookup(name) |
435 | |
436 | // if the object doesn't exist yet, create and insert it |
437 | if obj == nil { |
438 | obj = types.NewTypeName(pos, parent, name, nil) |
439 | scope.Insert(obj) |
440 | } |
441 | |
442 | if _, ok := obj.(*types.TypeName); !ok { |
443 | errorf("pkg = %s, name = %s => %s", parent, name, obj) |
444 | } |
445 | |
446 | // associate new named type with obj if it doesn't exist yet |
447 | t0 := types.NewNamed(obj.(*types.TypeName), nil, nil) |
448 | |
449 | // but record the existing type, if any |
450 | tname := obj.Type().(*types.Named) // tname is either t0 or the existing type |
451 | p.record(tname) |
452 | |
453 | // read underlying type |
454 | t0.SetUnderlying(p.typ(parent, t0)) |
455 | |
456 | // interfaces don't have associated methods |
457 | if types.IsInterface(t0) { |
458 | return tname |
459 | } |
460 | |
461 | // read associated methods |
462 | for i := p.int(); i > 0; i-- { |
463 | // TODO(gri) replace this with something closer to fieldName |
464 | pos := p.pos() |
465 | name := p.string() |
466 | if !exported(name) { |
467 | p.pkg() |
468 | } |
469 | |
470 | recv, _ := p.paramList() // TODO(gri) do we need a full param list for the receiver? |
471 | params, isddd := p.paramList() |
472 | result, _ := p.paramList() |
473 | p.int() // go:nointerface pragma - discarded |
474 | |
475 | sig := types.NewSignature(recv.At(0), params, result, isddd) |
476 | t0.AddMethod(types.NewFunc(pos, parent, name, sig)) |
477 | } |
478 | |
479 | return tname |
480 | |
481 | case arrayTag: |
482 | t := new(types.Array) |
483 | if p.trackAllTypes { |
484 | p.record(t) |
485 | } |
486 | |
487 | n := p.int64() |
488 | *t = *types.NewArray(p.typ(parent, nil), n) |
489 | return t |
490 | |
491 | case sliceTag: |
492 | t := new(types.Slice) |
493 | if p.trackAllTypes { |
494 | p.record(t) |
495 | } |
496 | |
497 | *t = *types.NewSlice(p.typ(parent, nil)) |
498 | return t |
499 | |
500 | case dddTag: |
501 | t := new(dddSlice) |
502 | if p.trackAllTypes { |
503 | p.record(t) |
504 | } |
505 | |
506 | t.elem = p.typ(parent, nil) |
507 | return t |
508 | |
509 | case structTag: |
510 | t := new(types.Struct) |
511 | if p.trackAllTypes { |
512 | p.record(t) |
513 | } |
514 | |
515 | *t = *types.NewStruct(p.fieldList(parent)) |
516 | return t |
517 | |
518 | case pointerTag: |
519 | t := new(types.Pointer) |
520 | if p.trackAllTypes { |
521 | p.record(t) |
522 | } |
523 | |
524 | *t = *types.NewPointer(p.typ(parent, nil)) |
525 | return t |
526 | |
527 | case signatureTag: |
528 | t := new(types.Signature) |
529 | if p.trackAllTypes { |
530 | p.record(t) |
531 | } |
532 | |
533 | params, isddd := p.paramList() |
534 | result, _ := p.paramList() |
535 | *t = *types.NewSignature(nil, params, result, isddd) |
536 | return t |
537 | |
538 | case interfaceTag: |
539 | // Create a dummy entry in the type list. This is safe because we |
540 | // cannot expect the interface type to appear in a cycle, as any |
541 | // such cycle must contain a named type which would have been |
542 | // first defined earlier. |
543 | // TODO(gri) Is this still true now that we have type aliases? |
544 | // See issue #23225. |
545 | n := len(p.typList) |
546 | if p.trackAllTypes { |
547 | p.record(nil) |
548 | } |
549 | |
550 | var embeddeds []types.Type |
551 | for n := p.int(); n > 0; n-- { |
552 | p.pos() |
553 | embeddeds = append(embeddeds, p.typ(parent, nil)) |
554 | } |
555 | |
556 | t := newInterface(p.methodList(parent, tname), embeddeds) |
557 | p.interfaceList = append(p.interfaceList, t) |
558 | if p.trackAllTypes { |
559 | p.typList[n] = t |
560 | } |
561 | return t |
562 | |
563 | case mapTag: |
564 | t := new(types.Map) |
565 | if p.trackAllTypes { |
566 | p.record(t) |
567 | } |
568 | |
569 | key := p.typ(parent, nil) |
570 | val := p.typ(parent, nil) |
571 | *t = *types.NewMap(key, val) |
572 | return t |
573 | |
574 | case chanTag: |
575 | t := new(types.Chan) |
576 | if p.trackAllTypes { |
577 | p.record(t) |
578 | } |
579 | |
580 | dir := chanDir(p.int()) |
581 | val := p.typ(parent, nil) |
582 | *t = *types.NewChan(dir, val) |
583 | return t |
584 | |
585 | default: |
586 | errorf("unexpected type tag %d", i) // panics |
587 | panic("unreachable") |
588 | } |
589 | } |
590 | |
591 | func chanDir(d int) types.ChanDir { |
592 | // tag values must match the constants in cmd/compile/internal/gc/go.go |
593 | switch d { |
594 | case 1 /* Crecv */ : |
595 | return types.RecvOnly |
596 | case 2 /* Csend */ : |
597 | return types.SendOnly |
598 | case 3 /* Cboth */ : |
599 | return types.SendRecv |
600 | default: |
601 | errorf("unexpected channel dir %d", d) |
602 | return 0 |
603 | } |
604 | } |
605 | |
606 | func (p *importer) fieldList(parent *types.Package) (fields []*types.Var, tags []string) { |
607 | if n := p.int(); n > 0 { |
608 | fields = make([]*types.Var, n) |
609 | tags = make([]string, n) |
610 | for i := range fields { |
611 | fields[i], tags[i] = p.field(parent) |
612 | } |
613 | } |
614 | return |
615 | } |
616 | |
617 | func (p *importer) field(parent *types.Package) (*types.Var, string) { |
618 | pos := p.pos() |
619 | pkg, name, alias := p.fieldName(parent) |
620 | typ := p.typ(parent, nil) |
621 | tag := p.string() |
622 | |
623 | anonymous := false |
624 | if name == "" { |
625 | // anonymous field - typ must be T or *T and T must be a type name |
626 | switch typ := deref(typ).(type) { |
627 | case *types.Basic: // basic types are named types |
628 | pkg = nil // // objects defined in Universe scope have no package |
629 | name = typ.Name() |
630 | case *types.Named: |
631 | name = typ.Obj().Name() |
632 | default: |
633 | errorf("named base type expected") |
634 | } |
635 | anonymous = true |
636 | } else if alias { |
637 | // anonymous field: we have an explicit name because it's an alias |
638 | anonymous = true |
639 | } |
640 | |
641 | return types.NewField(pos, pkg, name, typ, anonymous), tag |
642 | } |
643 | |
644 | func (p *importer) methodList(parent *types.Package, baseType *types.Named) (methods []*types.Func) { |
645 | if n := p.int(); n > 0 { |
646 | methods = make([]*types.Func, n) |
647 | for i := range methods { |
648 | methods[i] = p.method(parent, baseType) |
649 | } |
650 | } |
651 | return |
652 | } |
653 | |
654 | func (p *importer) method(parent *types.Package, baseType *types.Named) *types.Func { |
655 | pos := p.pos() |
656 | pkg, name, _ := p.fieldName(parent) |
657 | // If we don't have a baseType, use a nil receiver. |
658 | // A receiver using the actual interface type (which |
659 | // we don't know yet) will be filled in when we call |
660 | // types.Interface.Complete. |
661 | var recv *types.Var |
662 | if baseType != nil { |
663 | recv = types.NewVar(token.NoPos, parent, "", baseType) |
664 | } |
665 | params, isddd := p.paramList() |
666 | result, _ := p.paramList() |
667 | sig := types.NewSignature(recv, params, result, isddd) |
668 | return types.NewFunc(pos, pkg, name, sig) |
669 | } |
670 | |
671 | func (p *importer) fieldName(parent *types.Package) (pkg *types.Package, name string, alias bool) { |
672 | name = p.string() |
673 | pkg = parent |
674 | if pkg == nil { |
675 | // use the imported package instead |
676 | pkg = p.pkgList[0] |
677 | } |
678 | if p.version == 0 && name == "_" { |
679 | // version 0 didn't export a package for _ fields |
680 | return |
681 | } |
682 | switch name { |
683 | case "": |
684 | // 1) field name matches base type name and is exported: nothing to do |
685 | case "?": |
686 | // 2) field name matches base type name and is not exported: need package |
687 | name = "" |
688 | pkg = p.pkg() |
689 | case "@": |
690 | // 3) field name doesn't match type name (alias) |
691 | name = p.string() |
692 | alias = true |
693 | fallthrough |
694 | default: |
695 | if !exported(name) { |
696 | pkg = p.pkg() |
697 | } |
698 | } |
699 | return |
700 | } |
701 | |
702 | func (p *importer) paramList() (*types.Tuple, bool) { |
703 | n := p.int() |
704 | if n == 0 { |
705 | return nil, false |
706 | } |
707 | // negative length indicates unnamed parameters |
708 | named := true |
709 | if n < 0 { |
710 | n = -n |
711 | named = false |
712 | } |
713 | // n > 0 |
714 | params := make([]*types.Var, n) |
715 | isddd := false |
716 | for i := range params { |
717 | params[i], isddd = p.param(named) |
718 | } |
719 | return types.NewTuple(params...), isddd |
720 | } |
721 | |
722 | func (p *importer) param(named bool) (*types.Var, bool) { |
723 | t := p.typ(nil, nil) |
724 | td, isddd := t.(*dddSlice) |
725 | if isddd { |
726 | t = types.NewSlice(td.elem) |
727 | } |
728 | |
729 | var pkg *types.Package |
730 | var name string |
731 | if named { |
732 | name = p.string() |
733 | if name == "" { |
734 | errorf("expected named parameter") |
735 | } |
736 | if name != "_" { |
737 | pkg = p.pkg() |
738 | } |
739 | if i := strings.Index(name, "·"); i > 0 { |
740 | name = name[:i] // cut off gc-specific parameter numbering |
741 | } |
742 | } |
743 | |
744 | // read and discard compiler-specific info |
745 | p.string() |
746 | |
747 | return types.NewVar(token.NoPos, pkg, name, t), isddd |
748 | } |
749 | |
750 | func exported(name string) bool { |
751 | ch, _ := utf8.DecodeRuneInString(name) |
752 | return unicode.IsUpper(ch) |
753 | } |
754 | |
755 | func (p *importer) value() constant.Value { |
756 | switch tag := p.tagOrIndex(); tag { |
757 | case falseTag: |
758 | return constant.MakeBool(false) |
759 | case trueTag: |
760 | return constant.MakeBool(true) |
761 | case int64Tag: |
762 | return constant.MakeInt64(p.int64()) |
763 | case floatTag: |
764 | return p.float() |
765 | case complexTag: |
766 | re := p.float() |
767 | im := p.float() |
768 | return constant.BinaryOp(re, token.ADD, constant.MakeImag(im)) |
769 | case stringTag: |
770 | return constant.MakeString(p.string()) |
771 | case unknownTag: |
772 | return constant.MakeUnknown() |
773 | default: |
774 | errorf("unexpected value tag %d", tag) // panics |
775 | panic("unreachable") |
776 | } |
777 | } |
778 | |
779 | func (p *importer) float() constant.Value { |
780 | sign := p.int() |
781 | if sign == 0 { |
782 | return constant.MakeInt64(0) |
783 | } |
784 | |
785 | exp := p.int() |
786 | mant := []byte(p.string()) // big endian |
787 | |
788 | // remove leading 0's if any |
789 | for len(mant) > 0 && mant[0] == 0 { |
790 | mant = mant[1:] |
791 | } |
792 | |
793 | // convert to little endian |
794 | // TODO(gri) go/constant should have a more direct conversion function |
795 | // (e.g., once it supports a big.Float based implementation) |
796 | for i, j := 0, len(mant)-1; i < j; i, j = i+1, j-1 { |
797 | mant[i], mant[j] = mant[j], mant[i] |
798 | } |
799 | |
800 | // adjust exponent (constant.MakeFromBytes creates an integer value, |
801 | // but mant represents the mantissa bits such that 0.5 <= mant < 1.0) |
802 | exp -= len(mant) << 3 |
803 | if len(mant) > 0 { |
804 | for msd := mant[len(mant)-1]; msd&0x80 == 0; msd <<= 1 { |
805 | exp++ |
806 | } |
807 | } |
808 | |
809 | x := constant.MakeFromBytes(mant) |
810 | switch { |
811 | case exp < 0: |
812 | d := constant.Shift(constant.MakeInt64(1), token.SHL, uint(-exp)) |
813 | x = constant.BinaryOp(x, token.QUO, d) |
814 | case exp > 0: |
815 | x = constant.Shift(x, token.SHL, uint(exp)) |
816 | } |
817 | |
818 | if sign < 0 { |
819 | x = constant.UnaryOp(token.SUB, x, 0) |
820 | } |
821 | return x |
822 | } |
823 | |
824 | // ---------------------------------------------------------------------------- |
825 | // Low-level decoders |
826 | |
827 | func (p *importer) tagOrIndex() int { |
828 | if p.debugFormat { |
829 | p.marker('t') |
830 | } |
831 | |
832 | return int(p.rawInt64()) |
833 | } |
834 | |
835 | func (p *importer) int() int { |
836 | x := p.int64() |
837 | if int64(int(x)) != x { |
838 | errorf("exported integer too large") |
839 | } |
840 | return int(x) |
841 | } |
842 | |
843 | func (p *importer) int64() int64 { |
844 | if p.debugFormat { |
845 | p.marker('i') |
846 | } |
847 | |
848 | return p.rawInt64() |
849 | } |
850 | |
851 | func (p *importer) path() string { |
852 | if p.debugFormat { |
853 | p.marker('p') |
854 | } |
855 | // if the path was seen before, i is its index (>= 0) |
856 | // (the empty string is at index 0) |
857 | i := p.rawInt64() |
858 | if i >= 0 { |
859 | return p.pathList[i] |
860 | } |
861 | // otherwise, i is the negative path length (< 0) |
862 | a := make([]string, -i) |
863 | for n := range a { |
864 | a[n] = p.string() |
865 | } |
866 | s := strings.Join(a, "/") |
867 | p.pathList = append(p.pathList, s) |
868 | return s |
869 | } |
870 | |
871 | func (p *importer) string() string { |
872 | if p.debugFormat { |
873 | p.marker('s') |
874 | } |
875 | // if the string was seen before, i is its index (>= 0) |
876 | // (the empty string is at index 0) |
877 | i := p.rawInt64() |
878 | if i >= 0 { |
879 | return p.strList[i] |
880 | } |
881 | // otherwise, i is the negative string length (< 0) |
882 | if n := int(-i); n <= cap(p.buf) { |
883 | p.buf = p.buf[:n] |
884 | } else { |
885 | p.buf = make([]byte, n) |
886 | } |
887 | for i := range p.buf { |
888 | p.buf[i] = p.rawByte() |
889 | } |
890 | s := string(p.buf) |
891 | p.strList = append(p.strList, s) |
892 | return s |
893 | } |
894 | |
895 | func (p *importer) marker(want byte) { |
896 | if got := p.rawByte(); got != want { |
897 | errorf("incorrect marker: got %c; want %c (pos = %d)", got, want, p.read) |
898 | } |
899 | |
900 | pos := p.read |
901 | if n := int(p.rawInt64()); n != pos { |
902 | errorf("incorrect position: got %d; want %d", n, pos) |
903 | } |
904 | } |
905 | |
906 | // rawInt64 should only be used by low-level decoders. |
907 | func (p *importer) rawInt64() int64 { |
908 | i, err := binary.ReadVarint(p) |
909 | if err != nil { |
910 | errorf("read error: %v", err) |
911 | } |
912 | return i |
913 | } |
914 | |
915 | // rawStringln should only be used to read the initial version string. |
916 | func (p *importer) rawStringln(b byte) string { |
917 | p.buf = p.buf[:0] |
918 | for b != '\n' { |
919 | p.buf = append(p.buf, b) |
920 | b = p.rawByte() |
921 | } |
922 | return string(p.buf) |
923 | } |
924 | |
925 | // needed for binary.ReadVarint in rawInt64 |
926 | func (p *importer) ReadByte() (byte, error) { |
927 | return p.rawByte(), nil |
928 | } |
929 | |
930 | // byte is the bottleneck interface for reading p.data. |
931 | // It unescapes '|' 'S' to '$' and '|' '|' to '|'. |
932 | // rawByte should only be used by low-level decoders. |
933 | func (p *importer) rawByte() byte { |
934 | b := p.data[0] |
935 | r := 1 |
936 | if b == '|' { |
937 | b = p.data[1] |
938 | r = 2 |
939 | switch b { |
940 | case 'S': |
941 | b = '$' |
942 | case '|': |
943 | // nothing to do |
944 | default: |
945 | errorf("unexpected escape sequence in export data") |
946 | } |
947 | } |
948 | p.data = p.data[r:] |
949 | p.read += r |
950 | return b |
951 | |
952 | } |
953 | |
954 | // ---------------------------------------------------------------------------- |
955 | // Export format |
956 | |
957 | // Tags. Must be < 0. |
958 | const ( |
959 | // Objects |
960 | packageTag = -(iota + 1) |
961 | constTag |
962 | typeTag |
963 | varTag |
964 | funcTag |
965 | endTag |
966 | |
967 | // Types |
968 | namedTag |
969 | arrayTag |
970 | sliceTag |
971 | dddTag |
972 | structTag |
973 | pointerTag |
974 | signatureTag |
975 | interfaceTag |
976 | mapTag |
977 | chanTag |
978 | |
979 | // Values |
980 | falseTag |
981 | trueTag |
982 | int64Tag |
983 | floatTag |
984 | fractionTag // not used by gc |
985 | complexTag |
986 | stringTag |
987 | nilTag // only used by gc (appears in exported inlined function bodies) |
988 | unknownTag // not used by gc (only appears in packages with errors) |
989 | |
990 | // Type aliases |
991 | aliasTag |
992 | ) |
993 | |
994 | var predeclOnce sync.Once |
995 | var predecl []types.Type // initialized lazily |
996 | |
997 | func predeclared() []types.Type { |
998 | predeclOnce.Do(func() { |
999 | // initialize lazily to be sure that all |
1000 | // elements have been initialized before |
1001 | predecl = []types.Type{ // basic types |
1002 | types.Typ[types.Bool], |
1003 | types.Typ[types.Int], |
1004 | types.Typ[types.Int8], |
1005 | types.Typ[types.Int16], |
1006 | types.Typ[types.Int32], |
1007 | types.Typ[types.Int64], |
1008 | types.Typ[types.Uint], |
1009 | types.Typ[types.Uint8], |
1010 | types.Typ[types.Uint16], |
1011 | types.Typ[types.Uint32], |
1012 | types.Typ[types.Uint64], |
1013 | types.Typ[types.Uintptr], |
1014 | types.Typ[types.Float32], |
1015 | types.Typ[types.Float64], |
1016 | types.Typ[types.Complex64], |
1017 | types.Typ[types.Complex128], |
1018 | types.Typ[types.String], |
1019 | |
1020 | // basic type aliases |
1021 | types.Universe.Lookup("byte").Type(), |
1022 | types.Universe.Lookup("rune").Type(), |
1023 | |
1024 | // error |
1025 | types.Universe.Lookup("error").Type(), |
1026 | |
1027 | // untyped types |
1028 | types.Typ[types.UntypedBool], |
1029 | types.Typ[types.UntypedInt], |
1030 | types.Typ[types.UntypedRune], |
1031 | types.Typ[types.UntypedFloat], |
1032 | types.Typ[types.UntypedComplex], |
1033 | types.Typ[types.UntypedString], |
1034 | types.Typ[types.UntypedNil], |
1035 | |
1036 | // package unsafe |
1037 | types.Typ[types.UnsafePointer], |
1038 | |
1039 | // invalid type |
1040 | types.Typ[types.Invalid], // only appears in packages with errors |
1041 | |
1042 | // used internally by gc; never used by this package or in .a files |
1043 | anyType{}, |
1044 | } |
1045 | predecl = append(predecl, additionalPredeclared()...) |
1046 | }) |
1047 | return predecl |
1048 | } |
1049 | |
1050 | type anyType struct{} |
1051 | |
1052 | func (t anyType) Underlying() types.Type { return t } |
1053 | func (t anyType) String() string { return "any" } |
1054 |
Members