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.
5 // Binary package import.
6 // Based loosely on x/tools/go/importer.
12 "cmd/compile/internal/big"
17 // The overall structure of Import is symmetric to Export: For each
18 // export method in bexport.go there is a matching and symmetric method
19 // in bimport.go. Changing the export format requires making symmetric
20 // changes to bimport.go and bexport.go.
22 type importer struct {
24 buf []byte // reused for reading strings
26 // object lists, in order of deserialization
30 funcList []*Node // nil entry means already declared
33 // for delayed type verification
34 cmpList []struct{ pt, t *Type }
43 read int // bytes read
46 // Import populates importpkg from the serialized package data.
47 func Import(in *bufio.Reader) {
50 strList: []string{""}, // empty string is mapped to 0
53 // read low-level encoding format
54 switch format := p.rawByte(); format {
56 // compact format - nothing to do
60 Fatalf("importer: invalid encoding format in export data: got %q; want 'c' or 'd'", format)
63 p.trackAllTypes = p.rawByte() == 'a'
65 p.posInfoFormat = p.bool()
67 // --- generic export data ---
69 if v := p.string(); v != exportVersion {
70 Fatalf("importer: unknown export data version: %s", v)
73 // populate typList with predeclared "known" types
74 p.typList = append(p.typList, predeclared()...)
79 // defer some type-checking until all types are read in completely
80 // (parser.go:import_package)
99 if count := p.int(); count != objcount {
100 Fatalf("importer: got %d objects; want %d", objcount, count)
103 // --- compiler-specific export data ---
105 // read compiler-specific flags
106 importpkg.Safe = p.bool()
111 tag := p.tagOrIndex()
120 if count := p.int(); count != objcount {
121 Fatalf("importer: got %d objects; want %d", objcount, count)
124 // read inlineable functions bodies
125 if dclcontext != PEXTERN {
126 Fatalf("importer: unexpected context %d", dclcontext)
131 i := p.int() // index of function with inlineable body
136 // don't process the same function twice
138 Fatalf("importer: index not increasing: %d <= %d", i, i0)
143 Fatalf("importer: unexpected Funcdepth %d", Funcdepth)
146 // Note: In the original code, funchdr and funcbody are called for
147 // all functions (that were not yet imported). Now, we are calling
148 // them only for functions with inlineable bodies. funchdr does
149 // parameter renaming which doesn't matter if we don't have a body.
151 if f := p.funcList[i]; f != nil {
152 // function not yet imported - read body and set it
156 // Make sure empty body is not interpreted as
157 // no inlineable body (see also parser.fnbody)
158 // (not doing so can cause significant performance
159 // degradation due to unnecessary calls to empty
161 body = []*Node{Nod(OEMPTY, nil, nil)}
166 // function already imported - read body but discard declarations
167 dclcontext = PDISCARD // throw away any declarations
176 if count := p.int(); count != objcount {
177 Fatalf("importer: got %d functions; want %d", objcount, count)
180 if dclcontext != PEXTERN {
181 Fatalf("importer: unexpected context %d", dclcontext)
186 // --- end of export data ---
191 testdclstack() // debugging only
194 func (p *importer) verifyTypes() {
195 for _, pair := range p.cmpList {
198 if !Eqtype(pt.Orig, t) {
199 // TODO(gri) Is this a possible regular error (stale files)
200 // or can this only happen if export/import is flawed?
201 // (if the latter, change to Fatalf here)
202 Yyerror("inconsistent definition for type %v during import\n\t%v (in %q)\n\t%v (in %q)", pt.Sym, Tconv(pt, FmtLong), pt.Sym.Importdef.Path, Tconv(t, FmtLong), importpkg.Path)
207 func (p *importer) pkg() *Pkg {
208 // if the package was seen before, i is its index (>= 0)
214 // otherwise, i is the package tag (< 0)
216 Fatalf("importer: expected package tag, found tag = %d", i)
223 // we should never see an empty package name
225 Fatalf("importer: empty package name for path %q", path)
228 // we should never see a bad import path
229 if isbadimport(path) {
230 Fatalf("importer: bad package path %q for package %s", path, name)
233 // an empty path denotes the package we are currently importing;
234 // it must be the first package we see
235 if (path == "") != (len(p.pkgList) == 0) {
236 Fatalf("importer: package path %q for pkg index %d", path, len(p.pkgList))
245 } else if pkg.Name != name {
246 Fatalf("importer: conflicting package names %s and %s for path %q", pkg.Name, name, path)
248 p.pkgList = append(p.pkgList, pkg)
253 func idealType(typ *Type) *Type {
255 // canonicalize ideal types
261 func (p *importer) obj(tag int) {
265 sym := p.qualifiedName()
268 importconst(sym, idealType(typ), nodlit(val))
275 sym := p.qualifiedName()
281 sym := p.qualifiedName()
282 params := p.paramList()
283 result := p.paramList()
285 sig := functype(nil, params, result)
286 importsym(sym, ONAME)
287 if sym.Def != nil && sym.Def.Op == ONAME {
288 // function was imported before (via another import)
289 if !Eqtype(sig, sym.Def.Type) {
290 Fatalf("importer: inconsistent definition for func %v during import\n\t%v\n\t%v", sym, sym.Def.Type, sig)
292 p.funcList = append(p.funcList, nil)
296 n := newfuncname(sym)
299 p.funcList = append(p.funcList, n)
300 importlist = append(importlist, n)
303 fmt.Printf("import [%q] func %v \n", importpkg.Path, n)
304 if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
305 fmt.Printf("inl body: %v\n", n.Func.Inl)
310 Fatalf("importer: unexpected object (tag = %d)", tag)
314 func (p *importer) pos() {
315 if !p.posInfoFormat {
321 if delta := p.int(); delta != 0 {
324 } else if n := p.int(); n >= 0 {
326 file = p.prevFile[:n] + p.string()
332 // TODO(gri) register new position
335 func (p *importer) newtyp(etype EType) *Type {
338 p.typList = append(p.typList, t)
343 // This is like the function importtype but it delays the
344 // type identity check for types that have been seen already.
345 // importer.importtype and importtype and (export.go) need to
347 func (p *importer) importtype(pt, t *Type) {
348 // override declaration in unsafe.go for Pointer.
349 // there is no way in Go code to define unsafe.Pointer
350 // so we have to supply it.
351 if incannedimport != 0 && importpkg.Name == "unsafe" && pt.Nod.Sym.Name == "Pointer" {
352 t = Types[TUNSAFEPTR]
355 if pt.Etype == TFORW {
358 pt.Nod = n // unzero nod
359 pt.Sym.Importdef = importpkg
360 pt.Sym.Lastlineno = lineno
364 // pt.Orig and t must be identical. Since t may not be
365 // fully set up yet, collect the types and verify identity
367 p.cmpList = append(p.cmpList, struct{ pt, t *Type }{pt, t})
371 fmt.Printf("import type %v %v\n", pt, Tconv(t, FmtLong))
375 func (p *importer) typ() *Type {
376 // if the type was seen before, i is its index (>= 0)
382 // otherwise, i is the type tag (< 0)
386 // parser.go:hidden_importsym
388 tsym := p.qualifiedName()
390 // parser.go:hidden_pkgtype
392 p.typList = append(p.typList, t)
394 // read underlying type
395 // parser.go:hidden_type
398 // If we track all types, we cannot check equality of previously
399 // imported types until later. Use customized version of importtype.
405 // interfaces don't have associated methods
406 if t0.IsInterface() {
410 // set correct import context (since p.typ() may be called
411 // while importing the body of an inlined function)
412 savedContext := dclcontext
415 // read associated methods
416 for i := p.int(); i > 0; i-- {
417 // parser.go:hidden_fndcl
422 recv := p.paramList() // TODO(gri) do we need a full param list for the receiver?
423 params := p.paramList()
424 result := p.paramList()
426 n := methodname1(newname(sym), recv[0].Right)
427 n.Type = functype(recv[0], params, result)
429 addmethod(sym, n.Type, tsym.Pkg, false, false)
430 p.funcList = append(p.funcList, n)
431 importlist = append(importlist, n)
433 // (comment from parser.go)
434 // inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
435 // (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
436 // out by typecheck's lookdot as this $$.ttype. So by providing
437 // this back link here we avoid special casing there.
441 fmt.Printf("import [%q] meth %v \n", importpkg.Path, n)
442 if Debug['m'] > 2 && n.Func.Inl.Len() != 0 {
443 fmt.Printf("inl body: %v\n", n.Func.Inl)
448 dclcontext = savedContext
454 t.Extra = &ArrayType{Elem: elem, Bound: bound}
459 t.Extra = SliceType{Elem: elem}
462 t = p.newtyp(TDDDFIELD)
463 t.Extra = DDDFieldType{T: p.typ()}
466 t = p.newtyp(TSTRUCT)
467 tostruct0(t, p.fieldList())
471 t.Extra = PtrType{Elem: p.typ()}
475 params := p.paramList()
476 result := p.paramList()
477 functype0(t, nil, params, result)
482 Fatalf("importer: unexpected embedded interface")
484 tointerface0(t, p.methodList())
495 ct.Dir = ChanDir(p.int())
499 Fatalf("importer: unexpected type (tag = %d)", i)
503 Fatalf("importer: nil type (type tag = %d)", i)
509 func (p *importer) qualifiedName() *Sym {
512 return pkg.Lookup(name)
515 // parser.go:hidden_structdcl_list
516 func (p *importer) fieldList() (fields []*Node) {
517 if n := p.int(); n > 0 {
518 fields = make([]*Node, n)
519 for i := range fields {
520 fields[i] = p.field()
526 // parser.go:hidden_structdcl
527 func (p *importer) field() *Node {
535 n = Nod(ODCLFIELD, newname(sym), typenod(typ))
537 // anonymous field - typ must be T or *T and T must be a type name
539 if s == nil && typ.IsPtr() {
540 s = typ.Elem().Sym // deref
547 n.Right = typenod(typ)
549 n.SetVal(Val{U: note})
554 // parser.go:hidden_interfacedcl_list
555 func (p *importer) methodList() (methods []*Node) {
556 if n := p.int(); n > 0 {
557 methods = make([]*Node, n)
558 for i := range methods {
559 methods[i] = p.method()
565 // parser.go:hidden_interfacedcl
566 func (p *importer) method() *Node {
569 params := p.paramList()
570 result := p.paramList()
571 return Nod(ODCLFIELD, newname(sym), typenod(functype(fakethis(), params, result)))
574 // parser.go:sym,hidden_importsym
575 func (p *importer) fieldName() *Sym {
579 // During imports, unqualified non-exported identifiers are from builtinpkg
580 // (see parser.go:sym). The binary exporter only exports blank as a non-exported
581 // identifier without qualification.
583 } else if name == "?" || name != "" && !exportname(name) {
589 return pkg.Lookup(name)
592 // parser.go:ohidden_funarg_list
593 func (p *importer) paramList() []*Node {
598 // negative length indicates unnamed parameters
605 n := make([]*Node, i)
607 n[i] = p.param(named)
612 // parser.go:hidden_funarg
613 func (p *importer) param(named bool) *Node {
617 if typ.Etype == TDDDFIELD {
618 // TDDDFIELD indicates wrapped ... slice type
619 typ = typSlice(typ.DDDField())
623 n := Nod(ODCLFIELD, nil, typenod(typ))
629 Fatalf("importer: expected named parameter")
631 // TODO(gri) Supply function/method package rather than
632 // encoding the package for each parameter repeatedly.
637 n.Left = newname(pkg.Lookup(name))
640 // TODO(gri) This is compiler-specific (escape info).
641 // Move into compiler-specific section eventually?
642 n.SetVal(Val{U: p.string()})
647 func (p *importer) value(typ *Type) (x Val) {
648 switch tag := p.tagOrIndex(); tag {
657 u.SetInt64(p.int64())
658 u.Rune = typ == idealrune
664 if typ == idealint || typ.IsInteger() {
665 // uncommon case: large int encoded as float
683 Fatalf("importer: unknown constant (importing package with errors)")
689 Fatalf("importer: unexpected value tag %d", tag)
693 if typ.IsUntyped() && untype(x.Ctype()) != typ {
694 Fatalf("importer: value %v and type %v don't match", x, typ)
700 func (p *importer) float(x *Mpflt) {
708 mant := new(big.Int).SetBytes([]byte(p.string()))
710 m := x.Val.SetInt(mant)
711 m.SetMantExp(m, exp-mant.BitLen())
717 // ----------------------------------------------------------------------------
718 // Inlined function bodies
720 // Approach: Read nodes and use them to create/declare the same data structures
721 // as done originally by the (hidden) parser by closely following the parser's
722 // original code. In other words, "parsing" the import data (which happens to
723 // be encoded in binary rather textual form) is the best way at the moment to
724 // re-establish the syntax tree's invariants. At some future point we might be
725 // able to avoid this round-about way and create the rewritten nodes directly,
726 // possibly avoiding a lot of duplicate work (name resolution, type checking).
728 // Refined nodes (e.g., ODOTPTR as a refinement of OXDOT) are exported as their
729 // unrefined nodes (since this is what the importer uses). The respective case
730 // entries are unreachable in the importer.
732 func (p *importer) stmtList() []*Node {
739 // OBLOCK nodes may be created when importing ODCL nodes - unpack them
741 list = append(list, n.List.Slice()...)
743 list = append(list, n)
749 func (p *importer) exprList() []*Node {
756 list = append(list, n)
761 func (p *importer) elemList() []*Node {
763 list := make([]*Node, c)
764 for i := range list {
765 list[i] = Nod(OKEY, mkname(p.fieldSym()), p.expr())
770 func (p *importer) expr() *Node {
772 if n != nil && n.Op == OBLOCK {
773 Fatalf("unexpected block node: %v", n)
778 // TODO(gri) split into expr and stmt
779 func (p *importer) node() *Node {
780 switch op := p.op(); op {
783 // unreachable - unpacked by exporter
793 n := nodlit(p.value(typ))
794 if !typ.IsUntyped() {
795 conv := Nod(OCALL, typenod(typ), nil)
802 return mkname(p.sym())
804 // case OPACK, ONONAME:
805 // unreachable - should have been resolved by typechecking
809 return mkname(p.sym())
811 return typenod(p.typ())
813 // case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
814 // unreachable - should have been resolved by typechecking
821 if !p.bool() /* !implicit, i.e. '&' operator */ {
822 if n.Op == OCOMPLIT {
823 // Special case for &T{...}: turn into (*T){...}.
824 n.Right = Nod(OIND, n.Right, nil)
825 n.Right.Implicit = true
827 n = Nod(OADDR, n, nil)
833 n := Nod(OCOMPLIT, nil, typenod(p.typ()))
834 n.List.Set(p.elemList()) // special handling of field names
837 // case OARRAYLIT, OMAPLIT:
838 // unreachable - mapped to case OCOMPLIT below by exporter
841 n := Nod(OCOMPLIT, nil, typenod(p.typ()))
842 n.List.Set(p.exprList())
846 left, right := p.exprsOrNil()
847 return Nod(OKEY, left, right)
852 // case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
853 // unreachable - mapped to case OXDOT below by exporter
856 // see parser.new_dotname
857 return NodSym(OXDOT, p.expr(), p.fieldSym())
859 // case ODOTTYPE, ODOTTYPE2:
860 // unreachable - mapped to case ODOTTYPE below by exporter
863 n := Nod(ODOTTYPE, p.expr(), nil)
867 n.Right = typenod(p.typ())
871 // case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
872 // unreachable - mapped to cases below by exporter
875 return Nod(op, p.expr(), p.expr())
877 case OSLICE, OSLICE3:
878 n := Nod(op, p.expr(), nil)
879 low, high := p.exprsOrNil()
884 n.SetSliceBounds(low, high, max)
887 // case OCONV, OCONVIFACE, OCONVNOP, OARRAYBYTESTR, OARRAYRUNESTR, OSTRARRAYBYTE, OSTRARRAYRUNE, ORUNESTR:
888 // unreachable - mapped to OCONV case below by exporter
891 n := Nod(OCALL, typenod(p.typ()), nil)
892 n.List.Set(p.exprList())
895 case OCOPY, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
897 n.List.Set(p.exprList())
903 // case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
904 // unreachable - mapped to OCALL case below by exporter
907 n := Nod(OCALL, p.expr(), nil)
908 n.List.Set(p.exprList())
912 case OMAKEMAP, OMAKECHAN, OMAKESLICE:
913 n := builtinCall(OMAKE)
914 n.List.Append(typenod(p.typ()))
915 n.List.Append(p.exprList()...)
919 case OPLUS, OMINUS, OADDR, OCOM, OIND, ONOT, ORECV:
920 return Nod(op, p.expr(), nil)
922 // binary expressions
923 case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
924 OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
925 return Nod(op, p.expr(), p.expr())
930 for _, y := range list[1:] {
935 // case OCMPSTR, OCMPIFACE:
936 // unreachable - mapped to std comparison operators by exporter
939 // TODO(gri) these should not be exported in the first place
940 return Nod(OEMPTY, nil, nil)
942 // --------------------------------------------------------------------
949 lhs = dclname(p.sym())
951 // TODO(gri) avoid list created here!
952 return liststmt(variter([]*Node{lhs}, typenod(p.typ()), nil))
958 // unreachable - mapped to OAS case below by exporter
961 return Nod(OAS, p.expr(), p.expr())
964 n := Nod(OASOP, nil, nil)
965 n.Etype = EType(p.int())
968 n.Right = Nodintconst(1)
975 // case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
976 // unreachable - mapped to OAS2 case below by exporter
979 n := Nod(OAS2, nil, nil)
980 n.List.Set(p.exprList())
981 n.Rlist.Set(p.exprList())
985 n := Nod(ORETURN, nil, nil)
986 n.List.Set(p.exprList())
990 // unreachable - generated by compiler for trampolin routines (not exported)
993 return Nod(op, p.expr(), nil)
997 n := Nod(OIF, nil, nil)
998 n.Ninit.Set(p.stmtList())
1000 n.Nbody.Set(p.stmtList())
1001 n.Rlist.Set(p.stmtList())
1007 n := Nod(OFOR, nil, nil)
1008 n.Ninit.Set(p.stmtList())
1009 n.Left, n.Right = p.exprsOrNil()
1010 n.Nbody.Set(p.stmtList())
1016 n := Nod(ORANGE, nil, nil)
1017 n.List.Set(p.stmtList())
1019 n.Nbody.Set(p.stmtList())
1023 case OSELECT, OSWITCH:
1025 n := Nod(op, nil, nil)
1026 n.Ninit.Set(p.stmtList())
1027 n.Left, _ = p.exprsOrNil()
1028 n.List.Set(p.stmtList())
1032 // case OCASE, OXCASE:
1033 // unreachable - mapped to OXCASE case below by exporter
1037 n := Nod(OXCASE, nil, nil)
1038 n.List.Set(p.exprList())
1039 // TODO(gri) eventually we must declare variables for type switch
1040 // statements (type switch statements are not yet exported)
1041 n.Nbody.Set(p.stmtList())
1046 // unreachable - mapped to OXFALL case below by exporter
1048 case OBREAK, OCONTINUE, OGOTO, OXFALL:
1049 left, _ := p.exprsOrNil()
1050 return Nod(op, left, nil)
1053 // unreachable - not emitted by exporter
1056 n := Nod(OLABEL, p.expr(), nil)
1057 n.Left.Sym = dclstack // context, for goto restrictions
1064 Fatalf("cannot import %s (%d) node\n"+
1065 "==> please file an issue and assign to gri@\n", op, op)
1066 panic("unreachable") // satisfy compiler
1070 func builtinCall(op Op) *Node {
1071 return Nod(OCALL, mkname(builtinpkg.Lookup(goopnames[op])), nil)
1074 func (p *importer) exprsOrNil() (a, b *Node) {
1085 func (p *importer) fieldSym() *Sym {
1088 if !exportname(name) {
1091 return pkg.Lookup(name)
1094 func (p *importer) sym() *Sym {
1100 return pkg.Lookup(name)
1103 func (p *importer) bool() bool {
1107 func (p *importer) op() Op {
1111 // ----------------------------------------------------------------------------
1112 // Low-level decoders
1114 func (p *importer) tagOrIndex() int {
1119 return int(p.rawInt64())
1122 func (p *importer) int() int {
1124 if int64(int(x)) != x {
1125 Fatalf("importer: exported integer too large")
1130 func (p *importer) int64() int64 {
1138 func (p *importer) string() string {
1142 // if the string was seen before, i is its index (>= 0)
1143 // (the empty string is at index 0)
1148 // otherwise, i is the negative string length (< 0)
1149 if n := int(-i); n <= cap(p.buf) {
1152 p.buf = make([]byte, n)
1154 for i := range p.buf {
1155 p.buf[i] = p.rawByte()
1158 p.strList = append(p.strList, s)
1162 func (p *importer) marker(want byte) {
1163 if got := p.rawByte(); got != want {
1164 Fatalf("importer: incorrect marker: got %c; want %c (pos = %d)", got, want, p.read)
1168 if n := int(p.rawInt64()); n != pos {
1169 Fatalf("importer: incorrect position: got %d; want %d", n, pos)
1173 // rawInt64 should only be used by low-level decoders
1174 func (p *importer) rawInt64() int64 {
1175 i, err := binary.ReadVarint(p)
1177 Fatalf("importer: read error: %v", err)
1182 // needed for binary.ReadVarint in rawInt64
1183 func (p *importer) ReadByte() (byte, error) {
1184 return p.rawByte(), nil
1187 // rawByte is the bottleneck interface for reading from p.in.
1188 // It unescapes '|' 'S' to '$' and '|' '|' to '|'.
1189 // rawByte should only be used by low-level decoders.
1190 func (p *importer) rawByte() byte {
1191 c, err := p.in.ReadByte()
1194 Fatalf("importer: read error: %v", err)
1197 c, err = p.in.ReadByte()
1200 Fatalf("importer: read error: %v", err)
1208 Fatalf("importer: unexpected escape sequence in export data")