2018-04-01 01:55:55 -07:00
|
|
|
// Copyright 2018 The Go Authors. All rights reserved.
|
|
|
|
|
// Use of this source code is governed by a BSD-style
|
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
|
|
// Indexed package import.
|
|
|
|
|
// See iexport.go for the export data format.
|
|
|
|
|
|
|
|
|
|
package gc
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"cmd/compile/internal/types"
|
|
|
|
|
"cmd/internal/bio"
|
|
|
|
|
"cmd/internal/src"
|
|
|
|
|
"encoding/binary"
|
|
|
|
|
"fmt"
|
|
|
|
|
"math/big"
|
|
|
|
|
"os"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// An iimporterAndOffset identifies an importer and an offset within
|
|
|
|
|
// its data section.
|
|
|
|
|
type iimporterAndOffset struct {
|
|
|
|
|
p *iimporter
|
|
|
|
|
off uint64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var (
|
|
|
|
|
// declImporter maps from imported identifiers to an importer
|
|
|
|
|
// and offset where that identifier's declaration can be read.
|
|
|
|
|
declImporter = map[*types.Sym]iimporterAndOffset{}
|
|
|
|
|
|
|
|
|
|
// inlineImporter is like declImporter, but for inline bodies
|
|
|
|
|
// for function and method symbols.
|
|
|
|
|
inlineImporter = map[*types.Sym]iimporterAndOffset{}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
func expandDecl(n *Node) {
|
|
|
|
|
if n.Op != ONONAME {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := importReaderFor(n, declImporter)
|
|
|
|
|
if r == nil {
|
|
|
|
|
// Can happen if user tries to reference an undeclared name.
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r.doDecl(n)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func expandInline(fn *Node) {
|
|
|
|
|
if fn.Func.Inl.Body != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r := importReaderFor(fn, inlineImporter)
|
|
|
|
|
if r == nil {
|
|
|
|
|
Fatalf("missing import reader for %v", fn)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
r.doInline(fn)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func importReaderFor(n *Node, importers map[*types.Sym]iimporterAndOffset) *importReader {
|
|
|
|
|
x, ok := importers[n.Sym]
|
|
|
|
|
if !ok {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return x.p.newReader(x.off, n.Sym.Pkg)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type intReader struct {
|
|
|
|
|
*bio.Reader
|
|
|
|
|
pkg *types.Pkg
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *intReader) int64() int64 {
|
|
|
|
|
i, err := binary.ReadVarint(r.Reader)
|
|
|
|
|
if err != nil {
|
|
|
|
|
yyerror("import %q: read error: %v", r.pkg.Path, err)
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *intReader) uint64() uint64 {
|
|
|
|
|
i, err := binary.ReadUvarint(r.Reader)
|
|
|
|
|
if err != nil {
|
|
|
|
|
yyerror("import %q: read error: %v", r.pkg.Path, err)
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
return i
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func iimport(pkg *types.Pkg, in *bio.Reader) {
|
|
|
|
|
ir := &intReader{in, pkg}
|
|
|
|
|
|
|
|
|
|
version := ir.uint64()
|
|
|
|
|
if version != iexportVersion {
|
|
|
|
|
yyerror("import %q: unknown export format version %d", pkg.Path, version)
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sLen := ir.uint64()
|
|
|
|
|
dLen := ir.uint64()
|
|
|
|
|
|
|
|
|
|
// Map string (and data) section into memory as a single large
|
|
|
|
|
// string. This reduces heap fragmentation and allows
|
|
|
|
|
// returning individual substrings very efficiently.
|
|
|
|
|
data, err := mapFile(in.File(), in.Offset(), int64(sLen+dLen))
|
|
|
|
|
if err != nil {
|
|
|
|
|
yyerror("import %q: mapping input: %v", pkg.Path, err)
|
|
|
|
|
errorexit()
|
|
|
|
|
}
|
|
|
|
|
stringData := data[:sLen]
|
|
|
|
|
declData := data[sLen:]
|
|
|
|
|
|
2019-05-08 18:46:04 -04:00
|
|
|
in.MustSeek(int64(sLen+dLen), os.SEEK_CUR)
|
2018-04-01 01:55:55 -07:00
|
|
|
|
|
|
|
|
p := &iimporter{
|
|
|
|
|
ipkg: pkg,
|
|
|
|
|
|
|
|
|
|
pkgCache: map[uint64]*types.Pkg{},
|
|
|
|
|
posBaseCache: map[uint64]*src.PosBase{},
|
|
|
|
|
typCache: map[uint64]*types.Type{},
|
|
|
|
|
|
|
|
|
|
stringData: stringData,
|
|
|
|
|
declData: declData,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for i, pt := range predeclared() {
|
|
|
|
|
p.typCache[uint64(i)] = pt
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Declaration index.
|
|
|
|
|
for nPkgs := ir.uint64(); nPkgs > 0; nPkgs-- {
|
|
|
|
|
pkg := p.pkgAt(ir.uint64())
|
|
|
|
|
pkgName := p.stringAt(ir.uint64())
|
|
|
|
|
pkgHeight := int(ir.uint64())
|
|
|
|
|
if pkg.Name == "" {
|
|
|
|
|
pkg.Name = pkgName
|
|
|
|
|
pkg.Height = pkgHeight
|
|
|
|
|
numImport[pkgName]++
|
|
|
|
|
|
|
|
|
|
// TODO(mdempsky): This belongs somewhere else.
|
|
|
|
|
pkg.Lookup("_").Def = asTypesNode(nblank)
|
|
|
|
|
} else {
|
|
|
|
|
if pkg.Name != pkgName {
|
|
|
|
|
Fatalf("conflicting package names %v and %v for path %q", pkg.Name, pkgName, pkg.Path)
|
|
|
|
|
}
|
|
|
|
|
if pkg.Height != pkgHeight {
|
|
|
|
|
Fatalf("conflicting package heights %v and %v for path %q", pkg.Height, pkgHeight, pkg.Path)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for nSyms := ir.uint64(); nSyms > 0; nSyms-- {
|
|
|
|
|
s := pkg.Lookup(p.stringAt(ir.uint64()))
|
|
|
|
|
off := ir.uint64()
|
|
|
|
|
|
|
|
|
|
if _, ok := declImporter[s]; ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
declImporter[s] = iimporterAndOffset{p, off}
|
|
|
|
|
|
|
|
|
|
// Create stub declaration. If used, this will
|
|
|
|
|
// be overwritten by expandDecl.
|
|
|
|
|
if s.Def != nil {
|
|
|
|
|
Fatalf("unexpected definition for %v: %v", s, asNode(s.Def))
|
|
|
|
|
}
|
|
|
|
|
s.Def = asTypesNode(npos(src.NoXPos, dclname(s)))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Inline body index.
|
|
|
|
|
for nPkgs := ir.uint64(); nPkgs > 0; nPkgs-- {
|
|
|
|
|
pkg := p.pkgAt(ir.uint64())
|
|
|
|
|
|
|
|
|
|
for nSyms := ir.uint64(); nSyms > 0; nSyms-- {
|
|
|
|
|
s := pkg.Lookup(p.stringAt(ir.uint64()))
|
|
|
|
|
off := ir.uint64()
|
|
|
|
|
|
|
|
|
|
if _, ok := inlineImporter[s]; ok {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
inlineImporter[s] = iimporterAndOffset{p, off}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type iimporter struct {
|
|
|
|
|
ipkg *types.Pkg
|
|
|
|
|
|
|
|
|
|
pkgCache map[uint64]*types.Pkg
|
|
|
|
|
posBaseCache map[uint64]*src.PosBase
|
|
|
|
|
typCache map[uint64]*types.Type
|
|
|
|
|
|
|
|
|
|
stringData string
|
|
|
|
|
declData string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *iimporter) stringAt(off uint64) string {
|
|
|
|
|
var x [binary.MaxVarintLen64]byte
|
|
|
|
|
n := copy(x[:], p.stringData[off:])
|
|
|
|
|
|
|
|
|
|
slen, n := binary.Uvarint(x[:n])
|
|
|
|
|
if n <= 0 {
|
|
|
|
|
Fatalf("varint failed")
|
|
|
|
|
}
|
|
|
|
|
spos := off + uint64(n)
|
|
|
|
|
return p.stringData[spos : spos+slen]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *iimporter) posBaseAt(off uint64) *src.PosBase {
|
|
|
|
|
if posBase, ok := p.posBaseCache[off]; ok {
|
|
|
|
|
return posBase
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file := p.stringAt(off)
|
|
|
|
|
posBase := src.NewFileBase(file, file)
|
|
|
|
|
p.posBaseCache[off] = posBase
|
|
|
|
|
return posBase
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *iimporter) pkgAt(off uint64) *types.Pkg {
|
|
|
|
|
if pkg, ok := p.pkgCache[off]; ok {
|
|
|
|
|
return pkg
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pkg := p.ipkg
|
|
|
|
|
if pkgPath := p.stringAt(off); pkgPath != "" {
|
|
|
|
|
pkg = types.NewPkg(pkgPath, "")
|
|
|
|
|
}
|
|
|
|
|
p.pkgCache[off] = pkg
|
|
|
|
|
return pkg
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// An importReader keeps state for reading an individual imported
|
|
|
|
|
// object (declaration or inline body).
|
|
|
|
|
type importReader struct {
|
|
|
|
|
strings.Reader
|
|
|
|
|
p *iimporter
|
|
|
|
|
|
|
|
|
|
currPkg *types.Pkg
|
|
|
|
|
prevBase *src.PosBase
|
|
|
|
|
prevLine int64
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *iimporter) newReader(off uint64, pkg *types.Pkg) *importReader {
|
|
|
|
|
r := &importReader{
|
|
|
|
|
p: p,
|
|
|
|
|
currPkg: pkg,
|
|
|
|
|
}
|
|
|
|
|
// (*strings.Reader).Reset wasn't added until Go 1.7, and we
|
|
|
|
|
// need to build with Go 1.4.
|
|
|
|
|
r.Reader = *strings.NewReader(p.declData[off:])
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) string() string { return r.p.stringAt(r.uint64()) }
|
|
|
|
|
func (r *importReader) posBase() *src.PosBase { return r.p.posBaseAt(r.uint64()) }
|
|
|
|
|
func (r *importReader) pkg() *types.Pkg { return r.p.pkgAt(r.uint64()) }
|
|
|
|
|
|
|
|
|
|
func (r *importReader) setPkg() {
|
|
|
|
|
r.currPkg = r.pkg()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) doDecl(n *Node) {
|
|
|
|
|
if n.Op != ONONAME {
|
|
|
|
|
Fatalf("doDecl: unexpected Op for %v: %v", n.Sym, n.Op)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tag := r.byte()
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
|
|
|
|
|
switch tag {
|
|
|
|
|
case 'A':
|
|
|
|
|
typ := r.typ()
|
|
|
|
|
|
|
|
|
|
importalias(r.p.ipkg, pos, n.Sym, typ)
|
|
|
|
|
|
|
|
|
|
case 'C':
|
|
|
|
|
typ, val := r.value()
|
|
|
|
|
|
|
|
|
|
importconst(r.p.ipkg, pos, n.Sym, typ, val)
|
|
|
|
|
|
|
|
|
|
case 'F':
|
|
|
|
|
typ := r.signature(nil)
|
|
|
|
|
|
|
|
|
|
importfunc(r.p.ipkg, pos, n.Sym, typ)
|
|
|
|
|
r.funcExt(n)
|
|
|
|
|
|
|
|
|
|
case 'T':
|
|
|
|
|
// Types can be recursive. We need to setup a stub
|
|
|
|
|
// declaration before recursing.
|
|
|
|
|
t := importtype(r.p.ipkg, pos, n.Sym)
|
|
|
|
|
|
2018-07-06 12:14:22 -07:00
|
|
|
// We also need to defer width calculations until
|
|
|
|
|
// after the underlying type has been assigned.
|
2019-08-30 14:54:21 -07:00
|
|
|
defercheckwidth()
|
2018-04-01 01:55:55 -07:00
|
|
|
underlying := r.typ()
|
2019-08-30 15:59:16 -07:00
|
|
|
setUnderlying(t, underlying)
|
2019-08-30 14:54:21 -07:00
|
|
|
resumecheckwidth()
|
2018-04-01 01:55:55 -07:00
|
|
|
|
|
|
|
|
if underlying.IsInterface() {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ms := make([]*types.Field, r.uint64())
|
|
|
|
|
for i := range ms {
|
|
|
|
|
mpos := r.pos()
|
|
|
|
|
msym := r.ident()
|
|
|
|
|
recv := r.param()
|
|
|
|
|
mtyp := r.signature(recv)
|
|
|
|
|
|
|
|
|
|
f := types.NewField()
|
|
|
|
|
f.Pos = mpos
|
|
|
|
|
f.Sym = msym
|
|
|
|
|
f.Type = mtyp
|
|
|
|
|
ms[i] = f
|
|
|
|
|
|
|
|
|
|
m := newfuncnamel(mpos, methodSym(recv.Type, msym))
|
|
|
|
|
m.Type = mtyp
|
|
|
|
|
m.SetClass(PFUNC)
|
2018-11-01 12:20:28 -04:00
|
|
|
// methodSym already marked m.Sym as a function.
|
2018-04-01 01:55:55 -07:00
|
|
|
|
|
|
|
|
// (comment from parser.go)
|
|
|
|
|
// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
|
|
|
|
|
// (dotmeth's type).Nname.Inl, and dotmeth's type has been pulled
|
|
|
|
|
// out by typecheck's lookdot as this $$.ttype. So by providing
|
|
|
|
|
// this back link here we avoid special casing there.
|
|
|
|
|
mtyp.SetNname(asTypesNode(m))
|
|
|
|
|
}
|
|
|
|
|
t.Methods().Set(ms)
|
|
|
|
|
|
|
|
|
|
for _, m := range ms {
|
|
|
|
|
r.methExt(m)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
case 'V':
|
|
|
|
|
typ := r.typ()
|
|
|
|
|
|
|
|
|
|
importvar(r.p.ipkg, pos, n.Sym, typ)
|
|
|
|
|
r.varExt(n)
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Fatalf("unexpected tag: %v", tag)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importReader) value() (typ *types.Type, v Val) {
|
|
|
|
|
typ = p.typ()
|
|
|
|
|
|
|
|
|
|
switch constTypeOf(typ) {
|
|
|
|
|
case CTNIL:
|
|
|
|
|
v.U = &NilVal{}
|
|
|
|
|
case CTBOOL:
|
|
|
|
|
v.U = p.bool()
|
|
|
|
|
case CTSTR:
|
|
|
|
|
v.U = p.string()
|
|
|
|
|
case CTINT:
|
|
|
|
|
x := new(Mpint)
|
|
|
|
|
x.Rune = typ == types.Idealrune
|
|
|
|
|
p.mpint(&x.Val, typ)
|
|
|
|
|
v.U = x
|
|
|
|
|
case CTFLT:
|
|
|
|
|
x := newMpflt()
|
|
|
|
|
p.float(x, typ)
|
|
|
|
|
v.U = x
|
|
|
|
|
case CTCPLX:
|
|
|
|
|
x := newMpcmplx()
|
|
|
|
|
p.float(&x.Real, typ)
|
|
|
|
|
p.float(&x.Imag, typ)
|
|
|
|
|
v.U = x
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importReader) mpint(x *big.Int, typ *types.Type) {
|
|
|
|
|
signed, maxBytes := intSize(typ)
|
|
|
|
|
|
|
|
|
|
maxSmall := 256 - maxBytes
|
|
|
|
|
if signed {
|
|
|
|
|
maxSmall = 256 - 2*maxBytes
|
|
|
|
|
}
|
|
|
|
|
if maxBytes == 1 {
|
|
|
|
|
maxSmall = 256
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
n, _ := p.ReadByte()
|
|
|
|
|
if uint(n) < maxSmall {
|
|
|
|
|
v := int64(n)
|
|
|
|
|
if signed {
|
|
|
|
|
v >>= 1
|
|
|
|
|
if n&1 != 0 {
|
|
|
|
|
v = ^v
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
x.SetInt64(v)
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
v := -n
|
|
|
|
|
if signed {
|
|
|
|
|
v = -(n &^ 1) >> 1
|
|
|
|
|
}
|
|
|
|
|
if v < 1 || uint(v) > maxBytes {
|
|
|
|
|
Fatalf("weird decoding: %v, %v => %v", n, signed, v)
|
|
|
|
|
}
|
|
|
|
|
b := make([]byte, v)
|
|
|
|
|
p.Read(b)
|
|
|
|
|
x.SetBytes(b)
|
|
|
|
|
if signed && n&1 != 0 {
|
|
|
|
|
x.Neg(x)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *importReader) float(x *Mpflt, typ *types.Type) {
|
|
|
|
|
var mant big.Int
|
|
|
|
|
p.mpint(&mant, typ)
|
|
|
|
|
m := x.Val.SetInt(&mant)
|
|
|
|
|
if m.Sign() == 0 {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
m.SetMantExp(m, int(p.int64()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) ident() *types.Sym {
|
|
|
|
|
name := r.string()
|
|
|
|
|
if name == "" {
|
|
|
|
|
return nil
|
|
|
|
|
}
|
|
|
|
|
pkg := r.currPkg
|
|
|
|
|
if types.IsExported(name) {
|
|
|
|
|
pkg = localpkg
|
|
|
|
|
}
|
|
|
|
|
return pkg.Lookup(name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) qualifiedIdent() *types.Sym {
|
|
|
|
|
name := r.string()
|
|
|
|
|
pkg := r.pkg()
|
|
|
|
|
return pkg.Lookup(name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) pos() src.XPos {
|
|
|
|
|
delta := r.int64()
|
|
|
|
|
if delta != deltaNewFile {
|
|
|
|
|
r.prevLine += delta
|
|
|
|
|
} else if l := r.int64(); l == -1 {
|
|
|
|
|
r.prevLine += deltaNewFile
|
|
|
|
|
} else {
|
|
|
|
|
r.prevBase = r.posBase()
|
|
|
|
|
r.prevLine = l
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (r.prevBase == nil || r.prevBase.AbsFilename() == "") && r.prevLine == 0 {
|
|
|
|
|
// TODO(mdempsky): Remove once we reliably write
|
|
|
|
|
// position information for all nodes.
|
|
|
|
|
return src.NoXPos
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if r.prevBase == nil {
|
|
|
|
|
Fatalf("missing posbase")
|
|
|
|
|
}
|
|
|
|
|
pos := src.MakePos(r.prevBase, uint(r.prevLine), 0)
|
|
|
|
|
return Ctxt.PosTable.XPos(pos)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) typ() *types.Type {
|
|
|
|
|
return r.p.typAt(r.uint64())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (p *iimporter) typAt(off uint64) *types.Type {
|
|
|
|
|
t, ok := p.typCache[off]
|
|
|
|
|
if !ok {
|
|
|
|
|
if off < predeclReserved {
|
|
|
|
|
Fatalf("predeclared type missing from cache: %d", off)
|
|
|
|
|
}
|
|
|
|
|
t = p.newReader(off-predeclReserved, nil).typ1()
|
|
|
|
|
p.typCache[off] = t
|
|
|
|
|
}
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) typ1() *types.Type {
|
|
|
|
|
switch k := r.kind(); k {
|
|
|
|
|
default:
|
|
|
|
|
Fatalf("unexpected kind tag in %q: %v", r.p.ipkg.Path, k)
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
|
|
case definedType:
|
|
|
|
|
// We might be called from within doInline, in which
|
|
|
|
|
// case Sym.Def can point to declared parameters
|
|
|
|
|
// instead of the top-level types. Also, we don't
|
|
|
|
|
// support inlining functions with local defined
|
|
|
|
|
// types. Therefore, this must be a package-scope
|
|
|
|
|
// type.
|
|
|
|
|
n := asNode(r.qualifiedIdent().PkgDef())
|
|
|
|
|
if n.Op == ONONAME {
|
|
|
|
|
expandDecl(n)
|
|
|
|
|
}
|
|
|
|
|
if n.Op != OTYPE {
|
|
|
|
|
Fatalf("expected OTYPE, got %v: %v, %v", n.Op, n.Sym, n)
|
|
|
|
|
}
|
|
|
|
|
return n.Type
|
|
|
|
|
case pointerType:
|
|
|
|
|
return types.NewPtr(r.typ())
|
|
|
|
|
case sliceType:
|
|
|
|
|
return types.NewSlice(r.typ())
|
|
|
|
|
case arrayType:
|
|
|
|
|
n := r.uint64()
|
|
|
|
|
return types.NewArray(r.typ(), int64(n))
|
|
|
|
|
case chanType:
|
|
|
|
|
dir := types.ChanDir(r.uint64())
|
|
|
|
|
return types.NewChan(r.typ(), dir)
|
|
|
|
|
case mapType:
|
|
|
|
|
return types.NewMap(r.typ(), r.typ())
|
|
|
|
|
|
|
|
|
|
case signatureType:
|
|
|
|
|
r.setPkg()
|
|
|
|
|
return r.signature(nil)
|
|
|
|
|
|
|
|
|
|
case structType:
|
|
|
|
|
r.setPkg()
|
|
|
|
|
|
|
|
|
|
fs := make([]*types.Field, r.uint64())
|
|
|
|
|
for i := range fs {
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
sym := r.ident()
|
|
|
|
|
typ := r.typ()
|
|
|
|
|
emb := r.bool()
|
|
|
|
|
note := r.string()
|
|
|
|
|
|
|
|
|
|
f := types.NewField()
|
|
|
|
|
f.Pos = pos
|
|
|
|
|
f.Sym = sym
|
|
|
|
|
f.Type = typ
|
|
|
|
|
if emb {
|
|
|
|
|
f.Embedded = 1
|
|
|
|
|
}
|
|
|
|
|
f.Note = note
|
|
|
|
|
fs[i] = f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t := types.New(TSTRUCT)
|
|
|
|
|
t.SetPkg(r.currPkg)
|
|
|
|
|
t.SetFields(fs)
|
|
|
|
|
return t
|
|
|
|
|
|
|
|
|
|
case interfaceType:
|
|
|
|
|
r.setPkg()
|
|
|
|
|
|
|
|
|
|
embeddeds := make([]*types.Field, r.uint64())
|
|
|
|
|
for i := range embeddeds {
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
typ := r.typ()
|
|
|
|
|
|
|
|
|
|
f := types.NewField()
|
|
|
|
|
f.Pos = pos
|
|
|
|
|
f.Type = typ
|
|
|
|
|
embeddeds[i] = f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
methods := make([]*types.Field, r.uint64())
|
|
|
|
|
for i := range methods {
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
sym := r.ident()
|
|
|
|
|
typ := r.signature(fakeRecvField())
|
|
|
|
|
|
|
|
|
|
f := types.NewField()
|
|
|
|
|
f.Pos = pos
|
|
|
|
|
f.Sym = sym
|
|
|
|
|
f.Type = typ
|
|
|
|
|
methods[i] = f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
t := types.New(TINTER)
|
|
|
|
|
t.SetPkg(r.currPkg)
|
|
|
|
|
t.SetInterface(append(embeddeds, methods...))
|
2018-07-06 12:14:22 -07:00
|
|
|
|
|
|
|
|
// Ensure we expand the interface in the frontend (#25055).
|
|
|
|
|
checkwidth(t)
|
|
|
|
|
|
2018-04-01 01:55:55 -07:00
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) kind() itag {
|
|
|
|
|
return itag(r.uint64())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) signature(recv *types.Field) *types.Type {
|
|
|
|
|
params := r.paramList()
|
|
|
|
|
results := r.paramList()
|
|
|
|
|
if n := len(params); n > 0 {
|
2018-11-18 08:34:38 -08:00
|
|
|
params[n-1].SetIsDDD(r.bool())
|
2018-04-01 01:55:55 -07:00
|
|
|
}
|
|
|
|
|
t := functypefield(recv, params, results)
|
|
|
|
|
t.SetPkg(r.currPkg)
|
|
|
|
|
return t
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) paramList() []*types.Field {
|
|
|
|
|
fs := make([]*types.Field, r.uint64())
|
|
|
|
|
for i := range fs {
|
|
|
|
|
fs[i] = r.param()
|
|
|
|
|
}
|
|
|
|
|
return fs
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) param() *types.Field {
|
|
|
|
|
f := types.NewField()
|
|
|
|
|
f.Pos = r.pos()
|
|
|
|
|
f.Sym = r.ident()
|
|
|
|
|
f.Type = r.typ()
|
|
|
|
|
return f
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) bool() bool {
|
|
|
|
|
return r.uint64() != 0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) int64() int64 {
|
|
|
|
|
n, err := binary.ReadVarint(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
Fatalf("readVarint: %v", err)
|
|
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) uint64() uint64 {
|
|
|
|
|
n, err := binary.ReadUvarint(r)
|
|
|
|
|
if err != nil {
|
|
|
|
|
Fatalf("readVarint: %v", err)
|
|
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) byte() byte {
|
|
|
|
|
x, err := r.ReadByte()
|
|
|
|
|
if err != nil {
|
|
|
|
|
Fatalf("declReader.ReadByte: %v", err)
|
|
|
|
|
}
|
|
|
|
|
return x
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compiler-specific extensions.
|
|
|
|
|
|
|
|
|
|
func (r *importReader) varExt(n *Node) {
|
|
|
|
|
r.linkname(n.Sym)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) funcExt(n *Node) {
|
|
|
|
|
r.linkname(n.Sym)
|
|
|
|
|
|
|
|
|
|
// Escape analysis.
|
|
|
|
|
for _, fs := range types.RecvsParams {
|
|
|
|
|
for _, f := range fs(n.Type).FieldSlice() {
|
|
|
|
|
f.Note = r.string()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Inline body.
|
|
|
|
|
if u := r.uint64(); u > 0 {
|
|
|
|
|
n.Func.Inl = &Inline{
|
|
|
|
|
Cost: int32(u - 1),
|
|
|
|
|
}
|
2018-07-26 12:46:50 +03:00
|
|
|
n.Func.Endlineno = r.pos()
|
2018-04-01 01:55:55 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) methExt(m *types.Field) {
|
|
|
|
|
if r.bool() {
|
|
|
|
|
m.SetNointerface(true)
|
|
|
|
|
}
|
|
|
|
|
r.funcExt(asNode(m.Type.Nname()))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) linkname(s *types.Sym) {
|
|
|
|
|
s.Linkname = r.string()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) doInline(n *Node) {
|
|
|
|
|
if len(n.Func.Inl.Body) != 0 {
|
|
|
|
|
Fatalf("%v already has inline body", n)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
funchdr(n)
|
|
|
|
|
body := r.stmtList()
|
|
|
|
|
funcbody()
|
|
|
|
|
if body == nil {
|
|
|
|
|
//
|
|
|
|
|
// Make sure empty body is not interpreted as
|
|
|
|
|
// no inlineable body (see also parser.fnbody)
|
|
|
|
|
// (not doing so can cause significant performance
|
|
|
|
|
// degradation due to unnecessary calls to empty
|
|
|
|
|
// functions).
|
|
|
|
|
body = []*Node{}
|
|
|
|
|
}
|
|
|
|
|
n.Func.Inl.Body = body
|
|
|
|
|
|
|
|
|
|
importlist = append(importlist, n)
|
|
|
|
|
|
|
|
|
|
if Debug['E'] > 0 && Debug['m'] > 2 {
|
|
|
|
|
if Debug['m'] > 3 {
|
|
|
|
|
fmt.Printf("inl body for %v %#v: %+v\n", n, n.Type, asNodes(n.Func.Inl.Body))
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Printf("inl body for %v %#v: %v\n", n, n.Type, asNodes(n.Func.Inl.Body))
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
|
// Inlined function bodies
|
|
|
|
|
|
|
|
|
|
// Approach: Read nodes and use them to create/declare the same data structures
|
|
|
|
|
// as done originally by the (hidden) parser by closely following the parser's
|
|
|
|
|
// original code. In other words, "parsing" the import data (which happens to
|
|
|
|
|
// be encoded in binary rather textual form) is the best way at the moment to
|
|
|
|
|
// re-establish the syntax tree's invariants. At some future point we might be
|
|
|
|
|
// able to avoid this round-about way and create the rewritten nodes directly,
|
|
|
|
|
// possibly avoiding a lot of duplicate work (name resolution, type checking).
|
|
|
|
|
//
|
|
|
|
|
// Refined nodes (e.g., ODOTPTR as a refinement of OXDOT) are exported as their
|
|
|
|
|
// unrefined nodes (since this is what the importer uses). The respective case
|
|
|
|
|
// entries are unreachable in the importer.
|
|
|
|
|
|
|
|
|
|
func (r *importReader) stmtList() []*Node {
|
|
|
|
|
var list []*Node
|
|
|
|
|
for {
|
|
|
|
|
n := r.node()
|
|
|
|
|
if n == nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
// OBLOCK nodes may be created when importing ODCL nodes - unpack them
|
|
|
|
|
if n.Op == OBLOCK {
|
|
|
|
|
list = append(list, n.List.Slice()...)
|
|
|
|
|
} else {
|
|
|
|
|
list = append(list, n)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
return list
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) exprList() []*Node {
|
|
|
|
|
var list []*Node
|
|
|
|
|
for {
|
|
|
|
|
n := r.expr()
|
|
|
|
|
if n == nil {
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
list = append(list, n)
|
|
|
|
|
}
|
|
|
|
|
return list
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) expr() *Node {
|
|
|
|
|
n := r.node()
|
|
|
|
|
if n != nil && n.Op == OBLOCK {
|
|
|
|
|
Fatalf("unexpected block node: %v", n)
|
|
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO(gri) split into expr and stmt
|
|
|
|
|
func (r *importReader) node() *Node {
|
|
|
|
|
switch op := r.op(); op {
|
|
|
|
|
// expressions
|
|
|
|
|
// case OPAREN:
|
|
|
|
|
// unreachable - unpacked by exporter
|
|
|
|
|
|
|
|
|
|
// case ODDDARG:
|
|
|
|
|
// unimplemented
|
|
|
|
|
|
|
|
|
|
case OLITERAL:
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
typ, val := r.value()
|
|
|
|
|
|
|
|
|
|
n := npos(pos, nodlit(val))
|
|
|
|
|
n.Type = typ
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case ONONAME:
|
|
|
|
|
return mkname(r.qualifiedIdent())
|
|
|
|
|
|
|
|
|
|
case ONAME:
|
|
|
|
|
return mkname(r.ident())
|
|
|
|
|
|
|
|
|
|
// case OPACK, ONONAME:
|
|
|
|
|
// unreachable - should have been resolved by typechecking
|
|
|
|
|
|
|
|
|
|
case OTYPE:
|
|
|
|
|
return typenod(r.typ())
|
|
|
|
|
|
|
|
|
|
// case OTARRAY, OTMAP, OTCHAN, OTSTRUCT, OTINTER, OTFUNC:
|
|
|
|
|
// unreachable - should have been resolved by typechecking
|
|
|
|
|
|
|
|
|
|
// case OCLOSURE:
|
|
|
|
|
// unimplemented
|
|
|
|
|
|
|
|
|
|
case OPTRLIT:
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
n := npos(pos, r.expr())
|
|
|
|
|
if !r.bool() /* !implicit, i.e. '&' operator */ {
|
|
|
|
|
if n.Op == OCOMPLIT {
|
|
|
|
|
// Special case for &T{...}: turn into (*T){...}.
|
2018-11-18 08:34:38 -08:00
|
|
|
n.Right = nodl(pos, ODEREF, n.Right, nil)
|
2018-04-01 01:55:55 -07:00
|
|
|
n.Right.SetImplicit(true)
|
|
|
|
|
} else {
|
|
|
|
|
n = nodl(pos, OADDR, n, nil)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case OSTRUCTLIT:
|
|
|
|
|
// TODO(mdempsky): Export position information for OSTRUCTKEY nodes.
|
|
|
|
|
savedlineno := lineno
|
|
|
|
|
lineno = r.pos()
|
|
|
|
|
n := nodl(lineno, OCOMPLIT, nil, typenod(r.typ()))
|
|
|
|
|
n.List.Set(r.elemList()) // special handling of field names
|
|
|
|
|
lineno = savedlineno
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case OARRAYLIT, OSLICELIT, OMAPLIT:
|
|
|
|
|
// unreachable - mapped to case OCOMPLIT below by exporter
|
|
|
|
|
|
|
|
|
|
case OCOMPLIT:
|
|
|
|
|
n := nodl(r.pos(), OCOMPLIT, nil, typenod(r.typ()))
|
|
|
|
|
n.List.Set(r.exprList())
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case OKEY:
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
left, right := r.exprsOrNil()
|
|
|
|
|
return nodl(pos, OKEY, left, right)
|
|
|
|
|
|
|
|
|
|
// case OSTRUCTKEY:
|
|
|
|
|
// unreachable - handled in case OSTRUCTLIT by elemList
|
|
|
|
|
|
|
|
|
|
// case OCALLPART:
|
|
|
|
|
// unimplemented
|
|
|
|
|
|
|
|
|
|
// case OXDOT, ODOT, ODOTPTR, ODOTINTER, ODOTMETH:
|
|
|
|
|
// unreachable - mapped to case OXDOT below by exporter
|
|
|
|
|
|
|
|
|
|
case OXDOT:
|
|
|
|
|
// see parser.new_dotname
|
|
|
|
|
return npos(r.pos(), nodSym(OXDOT, r.expr(), r.ident()))
|
|
|
|
|
|
|
|
|
|
// case ODOTTYPE, ODOTTYPE2:
|
|
|
|
|
// unreachable - mapped to case ODOTTYPE below by exporter
|
|
|
|
|
|
|
|
|
|
case ODOTTYPE:
|
|
|
|
|
n := nodl(r.pos(), ODOTTYPE, r.expr(), nil)
|
|
|
|
|
n.Type = r.typ()
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case OINDEX, OINDEXMAP, OSLICE, OSLICESTR, OSLICEARR, OSLICE3, OSLICE3ARR:
|
|
|
|
|
// unreachable - mapped to cases below by exporter
|
|
|
|
|
|
|
|
|
|
case OINDEX:
|
|
|
|
|
return nodl(r.pos(), op, r.expr(), r.expr())
|
|
|
|
|
|
|
|
|
|
case OSLICE, OSLICE3:
|
|
|
|
|
n := nodl(r.pos(), op, r.expr(), nil)
|
|
|
|
|
low, high := r.exprsOrNil()
|
|
|
|
|
var max *Node
|
|
|
|
|
if n.Op.IsSlice3() {
|
|
|
|
|
max = r.expr()
|
|
|
|
|
}
|
|
|
|
|
n.SetSliceBounds(low, high, max)
|
|
|
|
|
return n
|
|
|
|
|
|
2018-11-18 08:34:38 -08:00
|
|
|
// case OCONV, OCONVIFACE, OCONVNOP, OBYTES2STR, ORUNES2STR, OSTR2BYTES, OSTR2RUNES, ORUNESTR:
|
2018-04-01 01:55:55 -07:00
|
|
|
// unreachable - mapped to OCONV case below by exporter
|
|
|
|
|
|
|
|
|
|
case OCONV:
|
|
|
|
|
n := nodl(r.pos(), OCONV, r.expr(), nil)
|
|
|
|
|
n.Type = r.typ()
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case OCOPY, OCOMPLEX, OREAL, OIMAG, OAPPEND, OCAP, OCLOSE, ODELETE, OLEN, OMAKE, ONEW, OPANIC, ORECOVER, OPRINT, OPRINTN:
|
|
|
|
|
n := npos(r.pos(), builtinCall(op))
|
|
|
|
|
n.List.Set(r.exprList())
|
|
|
|
|
if op == OAPPEND {
|
2018-11-18 08:34:38 -08:00
|
|
|
n.SetIsDDD(r.bool())
|
2018-04-01 01:55:55 -07:00
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case OCALL, OCALLFUNC, OCALLMETH, OCALLINTER, OGETG:
|
|
|
|
|
// unreachable - mapped to OCALL case below by exporter
|
|
|
|
|
|
|
|
|
|
case OCALL:
|
cmd/compile: rewrite f(g()) for multi-value g() during typecheck
This is a re-attempt at CL 153841, which caused two regressions:
1. crypto/ecdsa failed to build with -gcflags=-l=4. This was because
when "t1, t2, ... := g(); f(t1, t2, ...)" was exported, we were losing
the first assignment from the call's Ninit field.
2. net/http/pprof failed to run with -gcflags=-N. This is due to a
conflict with CL 159717: as of that CL, package-scope initialization
statements are executed within the "init.ializer" function, rather
than the "init" function, and the generated temp variables need to be
moved accordingly too.
[Rest of description is as before.]
This CL moves order.go's copyRet logic for rewriting f(g()) into t1,
t2, ... := g(); f(t1, t2, ...) earlier into typecheck. This allows the
rest of the compiler to stop worrying about multi-value functions
appearing outside of OAS2FUNC nodes.
This changes compiler behavior in a few observable ways:
1. Typechecking error messages for builtin functions now use general
case error messages rather than unnecessarily differing ones.
2. Because f(g()) is rewritten before inlining, saved inline bodies
now see the rewritten form too. This could be addressed, but doesn't
seem worthwhile.
3. Most notably, this simplifies escape analysis and fixes a memory
corruption issue in esc.go. See #29197 for details.
Fixes #15992.
Fixes #29197.
Change-Id: I930b10f7e27af68a0944d6c9bfc8707c3fab27a4
Reviewed-on: https://go-review.googlesource.com/c/go/+/166983
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
2018-12-12 11:15:37 -08:00
|
|
|
n := nodl(r.pos(), OCALL, nil, nil)
|
|
|
|
|
n.Ninit.Set(r.stmtList())
|
|
|
|
|
n.Left = r.expr()
|
2018-04-01 01:55:55 -07:00
|
|
|
n.List.Set(r.exprList())
|
2018-11-18 08:34:38 -08:00
|
|
|
n.SetIsDDD(r.bool())
|
2018-04-01 01:55:55 -07:00
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case OMAKEMAP, OMAKECHAN, OMAKESLICE:
|
|
|
|
|
n := npos(r.pos(), builtinCall(OMAKE))
|
|
|
|
|
n.List.Append(typenod(r.typ()))
|
|
|
|
|
n.List.Append(r.exprList()...)
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// unary expressions
|
2018-11-18 08:34:38 -08:00
|
|
|
case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
|
2018-04-01 01:55:55 -07:00
|
|
|
return nodl(r.pos(), op, r.expr(), nil)
|
|
|
|
|
|
|
|
|
|
// binary expressions
|
|
|
|
|
case OADD, OAND, OANDAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE, OLT,
|
|
|
|
|
OLSH, OMOD, OMUL, ONE, OOR, OOROR, ORSH, OSEND, OSUB, OXOR:
|
|
|
|
|
return nodl(r.pos(), op, r.expr(), r.expr())
|
|
|
|
|
|
|
|
|
|
case OADDSTR:
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
list := r.exprList()
|
|
|
|
|
x := npos(pos, list[0])
|
|
|
|
|
for _, y := range list[1:] {
|
|
|
|
|
x = nodl(pos, OADD, x, y)
|
|
|
|
|
}
|
|
|
|
|
return x
|
|
|
|
|
|
|
|
|
|
// --------------------------------------------------------------------
|
|
|
|
|
// statements
|
|
|
|
|
case ODCL:
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
lhs := npos(pos, dclname(r.ident()))
|
|
|
|
|
typ := typenod(r.typ())
|
|
|
|
|
return npos(pos, liststmt(variter([]*Node{lhs}, typ, nil))) // TODO(gri) avoid list creation
|
|
|
|
|
|
|
|
|
|
// case ODCLFIELD:
|
|
|
|
|
// unimplemented
|
|
|
|
|
|
|
|
|
|
// case OAS, OASWB:
|
|
|
|
|
// unreachable - mapped to OAS case below by exporter
|
|
|
|
|
|
|
|
|
|
case OAS:
|
|
|
|
|
return nodl(r.pos(), OAS, r.expr(), r.expr())
|
|
|
|
|
|
|
|
|
|
case OASOP:
|
|
|
|
|
n := nodl(r.pos(), OASOP, nil, nil)
|
|
|
|
|
n.SetSubOp(r.op())
|
|
|
|
|
n.Left = r.expr()
|
|
|
|
|
if !r.bool() {
|
|
|
|
|
n.Right = nodintconst(1)
|
|
|
|
|
n.SetImplicit(true)
|
|
|
|
|
} else {
|
|
|
|
|
n.Right = r.expr()
|
|
|
|
|
}
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case OAS2DOTTYPE, OAS2FUNC, OAS2MAPR, OAS2RECV:
|
|
|
|
|
// unreachable - mapped to OAS2 case below by exporter
|
|
|
|
|
|
|
|
|
|
case OAS2:
|
|
|
|
|
n := nodl(r.pos(), OAS2, nil, nil)
|
|
|
|
|
n.List.Set(r.exprList())
|
|
|
|
|
n.Rlist.Set(r.exprList())
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case ORETURN:
|
|
|
|
|
n := nodl(r.pos(), ORETURN, nil, nil)
|
|
|
|
|
n.List.Set(r.exprList())
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case ORETJMP:
|
|
|
|
|
// unreachable - generated by compiler for trampolin routines (not exported)
|
|
|
|
|
|
2018-11-18 08:34:38 -08:00
|
|
|
case OGO, ODEFER:
|
2018-04-01 01:55:55 -07:00
|
|
|
return nodl(r.pos(), op, r.expr(), nil)
|
|
|
|
|
|
|
|
|
|
case OIF:
|
|
|
|
|
n := nodl(r.pos(), OIF, nil, nil)
|
|
|
|
|
n.Ninit.Set(r.stmtList())
|
|
|
|
|
n.Left = r.expr()
|
|
|
|
|
n.Nbody.Set(r.stmtList())
|
|
|
|
|
n.Rlist.Set(r.stmtList())
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case OFOR:
|
|
|
|
|
n := nodl(r.pos(), OFOR, nil, nil)
|
|
|
|
|
n.Ninit.Set(r.stmtList())
|
|
|
|
|
n.Left, n.Right = r.exprsOrNil()
|
|
|
|
|
n.Nbody.Set(r.stmtList())
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case ORANGE:
|
|
|
|
|
n := nodl(r.pos(), ORANGE, nil, nil)
|
|
|
|
|
n.List.Set(r.stmtList())
|
|
|
|
|
n.Right = r.expr()
|
|
|
|
|
n.Nbody.Set(r.stmtList())
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case OSELECT, OSWITCH:
|
|
|
|
|
n := nodl(r.pos(), op, nil, nil)
|
|
|
|
|
n.Ninit.Set(r.stmtList())
|
|
|
|
|
n.Left, _ = r.exprsOrNil()
|
|
|
|
|
n.List.Set(r.stmtList())
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case OCASE, OXCASE:
|
|
|
|
|
// unreachable - mapped to OXCASE case below by exporter
|
|
|
|
|
|
|
|
|
|
case OXCASE:
|
|
|
|
|
n := nodl(r.pos(), OXCASE, nil, nil)
|
|
|
|
|
n.List.Set(r.exprList())
|
|
|
|
|
// TODO(gri) eventually we must declare variables for type switch
|
|
|
|
|
// statements (type switch statements are not yet exported)
|
|
|
|
|
n.Nbody.Set(r.stmtList())
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
// case OFALL:
|
|
|
|
|
// unreachable - mapped to OXFALL case below by exporter
|
|
|
|
|
|
|
|
|
|
case OFALL:
|
|
|
|
|
n := nodl(r.pos(), OFALL, nil, nil)
|
|
|
|
|
return n
|
|
|
|
|
|
|
|
|
|
case OBREAK, OCONTINUE:
|
|
|
|
|
pos := r.pos()
|
|
|
|
|
left, _ := r.exprsOrNil()
|
|
|
|
|
if left != nil {
|
|
|
|
|
left = newname(left.Sym)
|
|
|
|
|
}
|
|
|
|
|
return nodl(pos, op, left, nil)
|
|
|
|
|
|
|
|
|
|
// case OEMPTY:
|
|
|
|
|
// unreachable - not emitted by exporter
|
|
|
|
|
|
|
|
|
|
case OGOTO, OLABEL:
|
2018-10-26 20:10:23 -07:00
|
|
|
n := nodl(r.pos(), op, nil, nil)
|
|
|
|
|
n.Sym = lookup(r.string())
|
|
|
|
|
return n
|
2018-04-01 01:55:55 -07:00
|
|
|
|
|
|
|
|
case OEND:
|
|
|
|
|
return nil
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
Fatalf("cannot import %v (%d) node\n"+
|
2018-12-17 14:42:29 -08:00
|
|
|
"\t==> please file an issue and assign to gri@", op, int(op))
|
2018-04-01 01:55:55 -07:00
|
|
|
panic("unreachable") // satisfy compiler
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) op() Op {
|
|
|
|
|
return Op(r.uint64())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) elemList() []*Node {
|
|
|
|
|
c := r.uint64()
|
|
|
|
|
list := make([]*Node, c)
|
|
|
|
|
for i := range list {
|
|
|
|
|
s := r.ident()
|
|
|
|
|
list[i] = nodSym(OSTRUCTKEY, r.expr(), s)
|
|
|
|
|
}
|
|
|
|
|
return list
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r *importReader) exprsOrNil() (a, b *Node) {
|
|
|
|
|
ab := r.uint64()
|
|
|
|
|
if ab&1 != 0 {
|
|
|
|
|
a = r.expr()
|
|
|
|
|
}
|
|
|
|
|
if ab&2 != 0 {
|
2018-06-18 14:38:45 -07:00
|
|
|
b = r.node()
|
2018-04-01 01:55:55 -07:00
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|