| | |
| | |
| | |
| |
|
| | package noder |
| |
|
| | import ( |
| | "encoding/hex" |
| | "fmt" |
| | "go/constant" |
| | "internal/buildcfg" |
| | "internal/pkgbits" |
| | "path/filepath" |
| | "strings" |
| |
|
| | "cmd/compile/internal/base" |
| | "cmd/compile/internal/dwarfgen" |
| | "cmd/compile/internal/inline" |
| | "cmd/compile/internal/inline/interleaved" |
| | "cmd/compile/internal/ir" |
| | "cmd/compile/internal/objw" |
| | "cmd/compile/internal/reflectdata" |
| | "cmd/compile/internal/staticinit" |
| | "cmd/compile/internal/typecheck" |
| | "cmd/compile/internal/types" |
| | "cmd/internal/hash" |
| | "cmd/internal/obj" |
| | "cmd/internal/objabi" |
| | "cmd/internal/src" |
| | ) |
| |
|
| | |
| | |
| |
|
| | |
| | type pkgReader struct { |
| | pkgbits.PkgDecoder |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | posBases []*src.PosBase |
| | pkgs []*types.Pkg |
| | typs []*types.Type |
| |
|
| | |
| | |
| | |
| | newindex []index |
| | } |
| |
|
| | func newPkgReader(pr pkgbits.PkgDecoder) *pkgReader { |
| | return &pkgReader{ |
| | PkgDecoder: pr, |
| |
|
| | posBases: make([]*src.PosBase, pr.NumElems(pkgbits.SectionPosBase)), |
| | pkgs: make([]*types.Pkg, pr.NumElems(pkgbits.SectionPkg)), |
| | typs: make([]*types.Type, pr.NumElems(pkgbits.SectionType)), |
| |
|
| | newindex: make([]index, pr.TotalElems()), |
| | } |
| | } |
| |
|
| | |
| | |
| | type pkgReaderIndex struct { |
| | pr *pkgReader |
| | idx index |
| | dict *readerDict |
| | methodSym *types.Sym |
| |
|
| | synthetic func(pos src.XPos, r *reader) |
| | } |
| |
|
| | func (pri pkgReaderIndex) asReader(k pkgbits.SectionKind, marker pkgbits.SyncMarker) *reader { |
| | if pri.synthetic != nil { |
| | return &reader{synthetic: pri.synthetic} |
| | } |
| |
|
| | r := pri.pr.newReader(k, pri.idx, marker) |
| | r.dict = pri.dict |
| | r.methodSym = pri.methodSym |
| | return r |
| | } |
| |
|
| | func (pr *pkgReader) newReader(k pkgbits.SectionKind, idx index, marker pkgbits.SyncMarker) *reader { |
| | return &reader{ |
| | Decoder: pr.NewDecoder(k, idx, marker), |
| | p: pr, |
| | } |
| | } |
| |
|
| | |
| | type reader struct { |
| | pkgbits.Decoder |
| |
|
| | p *pkgReader |
| |
|
| | dict *readerDict |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | curfn *ir.Func |
| | locals []*ir.Name |
| | closureVars []*ir.Name |
| |
|
| | |
| | |
| | |
| | |
| | |
| | funarghack bool |
| |
|
| | |
| | |
| | methodSym *types.Sym |
| |
|
| | |
| | dictParam *ir.Name |
| |
|
| | |
| | |
| | |
| | synthetic func(pos src.XPos, r *reader) |
| |
|
| | |
| | |
| | scopeVars []int |
| | marker dwarfgen.ScopeMarker |
| | lastCloseScopePos src.XPos |
| |
|
| | |
| |
|
| | |
| | |
| | inlCaller *ir.Func |
| | inlCall *ir.CallExpr |
| | inlFunc *ir.Func |
| | inlTreeIndex int |
| | inlPosBases map[*src.PosBase]*src.PosBase |
| |
|
| | |
| | |
| | suppressInlPos int |
| |
|
| | delayResults bool |
| |
|
| | |
| | retlabel *types.Sym |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type readerDict struct { |
| | shaped bool |
| |
|
| | |
| | |
| | |
| | baseSym *types.Sym |
| |
|
| | |
| | |
| | shapedObj *ir.Name |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | targs []*types.Type |
| |
|
| | |
| | |
| | implicits int |
| |
|
| | derived []derivedInfo |
| | derivedTypes []*types.Type |
| |
|
| | |
| | typeParamMethodExprs []readerMethodExprInfo |
| | subdicts []objInfo |
| | rtypes []typeInfo |
| | itabs []itabInfo |
| | } |
| |
|
| | type readerMethodExprInfo struct { |
| | typeParamIdx int |
| | method *types.Sym |
| | } |
| |
|
| | func setType(n ir.Node, typ *types.Type) { |
| | n.SetType(typ) |
| | n.SetTypecheck(1) |
| | } |
| |
|
| | func setValue(name *ir.Name, val constant.Value) { |
| | name.SetVal(val) |
| | name.Defn = nil |
| | } |
| |
|
| | |
| |
|
| | |
| | func (r *reader) pos() src.XPos { |
| | return base.Ctxt.PosTable.XPos(r.pos0()) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) origPos() (origPos, inlPos src.XPos) { |
| | r.suppressInlPos++ |
| | origPos = r.pos() |
| | r.suppressInlPos-- |
| | inlPos = r.inlPos(origPos) |
| | return |
| | } |
| |
|
| | func (r *reader) pos0() src.Pos { |
| | r.Sync(pkgbits.SyncPos) |
| | if !r.Bool() { |
| | return src.NoPos |
| | } |
| |
|
| | posBase := r.posBase() |
| | line := r.Uint() |
| | col := r.Uint() |
| | return src.MakePos(posBase, line, col) |
| | } |
| |
|
| | |
| | func (r *reader) posBase() *src.PosBase { |
| | return r.inlPosBase(r.p.posBaseIdx(r.Reloc(pkgbits.SectionPosBase))) |
| | } |
| |
|
| | |
| | |
| | func (pr *pkgReader) posBaseIdx(idx index) *src.PosBase { |
| | if b := pr.posBases[idx]; b != nil { |
| | return b |
| | } |
| |
|
| | r := pr.newReader(pkgbits.SectionPosBase, idx, pkgbits.SyncPosBase) |
| | var b *src.PosBase |
| |
|
| | absFilename := r.String() |
| | filename := absFilename |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | const dollarGOROOT = "$GOROOT" |
| | if buildcfg.GOROOT != "" && strings.HasPrefix(filename, dollarGOROOT) { |
| | filename = filepath.FromSlash(buildcfg.GOROOT + filename[len(dollarGOROOT):]) |
| | } |
| |
|
| | if r.Bool() { |
| | b = src.NewFileBase(filename, absFilename) |
| | } else { |
| | pos := r.pos0() |
| | line := r.Uint() |
| | col := r.Uint() |
| | b = src.NewLinePragmaBase(pos, filename, absFilename, line, col) |
| | } |
| |
|
| | pr.posBases[idx] = b |
| | return b |
| | } |
| |
|
| | |
| | |
| | |
| | func (r *reader) inlPosBase(oldBase *src.PosBase) *src.PosBase { |
| | if index := oldBase.InliningIndex(); index >= 0 { |
| | base.Fatalf("oldBase %v already has inlining index %v", oldBase, index) |
| | } |
| |
|
| | if r.inlCall == nil || r.suppressInlPos != 0 { |
| | return oldBase |
| | } |
| |
|
| | if newBase, ok := r.inlPosBases[oldBase]; ok { |
| | return newBase |
| | } |
| |
|
| | newBase := src.NewInliningBase(oldBase, r.inlTreeIndex) |
| | r.inlPosBases[oldBase] = newBase |
| | return newBase |
| | } |
| |
|
| | |
| | |
| | |
| | func (r *reader) inlPos(xpos src.XPos) src.XPos { |
| | pos := base.Ctxt.PosTable.Pos(xpos) |
| | pos.SetBase(r.inlPosBase(pos.Base())) |
| | return base.Ctxt.PosTable.XPos(pos) |
| | } |
| |
|
| | |
| |
|
| | |
| | func (r *reader) pkg() *types.Pkg { |
| | r.Sync(pkgbits.SyncPkg) |
| | return r.p.pkgIdx(r.Reloc(pkgbits.SectionPkg)) |
| | } |
| |
|
| | |
| | |
| | func (pr *pkgReader) pkgIdx(idx index) *types.Pkg { |
| | if pkg := pr.pkgs[idx]; pkg != nil { |
| | return pkg |
| | } |
| |
|
| | pkg := pr.newReader(pkgbits.SectionPkg, idx, pkgbits.SyncPkgDef).doPkg() |
| | pr.pkgs[idx] = pkg |
| | return pkg |
| | } |
| |
|
| | |
| | func (r *reader) doPkg() *types.Pkg { |
| | path := r.String() |
| | switch path { |
| | case "": |
| | path = r.p.PkgPath() |
| | case "builtin": |
| | return types.BuiltinPkg |
| | case "unsafe": |
| | return types.UnsafePkg |
| | } |
| |
|
| | name := r.String() |
| |
|
| | pkg := types.NewPkg(path, "") |
| |
|
| | if pkg.Name == "" { |
| | pkg.Name = name |
| | } else { |
| | base.Assertf(pkg.Name == name, "package %q has name %q, but want %q", pkg.Path, pkg.Name, name) |
| | } |
| |
|
| | return pkg |
| | } |
| |
|
| | |
| |
|
| | func (r *reader) typ() *types.Type { |
| | return r.typWrapped(true) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) typWrapped(wrapped bool) *types.Type { |
| | return r.p.typIdx(r.typInfo(), r.dict, wrapped) |
| | } |
| |
|
| | func (r *reader) typInfo() typeInfo { |
| | r.Sync(pkgbits.SyncType) |
| | if r.Bool() { |
| | return typeInfo{idx: index(r.Len()), derived: true} |
| | } |
| | return typeInfo{idx: r.Reloc(pkgbits.SectionType), derived: false} |
| | } |
| |
|
| | |
| | |
| | func (pr *pkgReader) typListIdx(infos []typeInfo, dict *readerDict) []*types.Type { |
| | typs := make([]*types.Type, len(infos)) |
| | for i, info := range infos { |
| | typs[i] = pr.typIdx(info, dict, true) |
| | } |
| | return typs |
| | } |
| |
|
| | |
| | |
| | |
| | func (pr *pkgReader) typIdx(info typeInfo, dict *readerDict, wrapped bool) *types.Type { |
| | idx := info.idx |
| | var where **types.Type |
| | if info.derived { |
| | where = &dict.derivedTypes[idx] |
| | idx = dict.derived[idx].idx |
| | } else { |
| | where = &pr.typs[idx] |
| | } |
| |
|
| | if typ := *where; typ != nil { |
| | return typ |
| | } |
| |
|
| | r := pr.newReader(pkgbits.SectionType, idx, pkgbits.SyncTypeIdx) |
| | r.dict = dict |
| |
|
| | typ := r.doTyp() |
| | if typ == nil { |
| | base.Fatalf("doTyp returned nil for info=%v", info) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | if prev := *where; prev != nil { |
| | return prev |
| | } |
| |
|
| | if wrapped { |
| | |
| | |
| | *where = typ |
| |
|
| | r.needWrapper(typ) |
| | } |
| |
|
| | if !typ.IsUntyped() { |
| | types.CheckSize(typ) |
| | } |
| |
|
| | return typ |
| | } |
| |
|
| | func (r *reader) doTyp() *types.Type { |
| | switch tag := pkgbits.CodeType(r.Code(pkgbits.SyncType)); tag { |
| | default: |
| | panic(fmt.Sprintf("unexpected type: %v", tag)) |
| |
|
| | case pkgbits.TypeBasic: |
| | return *basics[r.Len()] |
| |
|
| | case pkgbits.TypeNamed: |
| | obj := r.obj() |
| | assert(obj.Op() == ir.OTYPE) |
| | return obj.Type() |
| |
|
| | case pkgbits.TypeTypeParam: |
| | return r.dict.targs[r.Len()] |
| |
|
| | case pkgbits.TypeArray: |
| | len := int64(r.Uint64()) |
| | return types.NewArray(r.typ(), len) |
| | case pkgbits.TypeChan: |
| | dir := dirs[r.Len()] |
| | return types.NewChan(r.typ(), dir) |
| | case pkgbits.TypeMap: |
| | return types.NewMap(r.typ(), r.typ()) |
| | case pkgbits.TypePointer: |
| | return types.NewPtr(r.typ()) |
| | case pkgbits.TypeSignature: |
| | return r.signature(nil) |
| | case pkgbits.TypeSlice: |
| | return types.NewSlice(r.typ()) |
| | case pkgbits.TypeStruct: |
| | return r.structType() |
| | case pkgbits.TypeInterface: |
| | return r.interfaceType() |
| | case pkgbits.TypeUnion: |
| | return r.unionType() |
| | } |
| | } |
| |
|
| | func (r *reader) unionType() *types.Type { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | if false { |
| | pure := false |
| | for i, n := 0, r.Len(); i < n; i++ { |
| | _ = r.Bool() |
| | term := r.typ() |
| | if term.IsEmptyInterface() { |
| | pure = true |
| | } |
| | } |
| | if !pure { |
| | base.Fatalf("impure type set used in value type") |
| | } |
| | } |
| |
|
| | return types.Types[types.TINTER] |
| | } |
| |
|
| | func (r *reader) interfaceType() *types.Type { |
| | nmethods, nembeddeds := r.Len(), r.Len() |
| | implicit := nmethods == 0 && nembeddeds == 1 && r.Bool() |
| | assert(!implicit) |
| |
|
| | fields := make([]*types.Field, nmethods+nembeddeds) |
| | methods, embeddeds := fields[:nmethods], fields[nmethods:] |
| |
|
| | for i := range methods { |
| | methods[i] = types.NewField(r.pos(), r.selector(), r.signature(types.FakeRecv())) |
| | } |
| | for i := range embeddeds { |
| | embeddeds[i] = types.NewField(src.NoXPos, nil, r.typ()) |
| | } |
| |
|
| | if len(fields) == 0 { |
| | return types.Types[types.TINTER] |
| | } |
| | return types.NewInterface(fields) |
| | } |
| |
|
| | func (r *reader) structType() *types.Type { |
| | fields := make([]*types.Field, r.Len()) |
| | for i := range fields { |
| | field := types.NewField(r.pos(), r.selector(), r.typ()) |
| | field.Note = r.String() |
| | if r.Bool() { |
| | field.Embedded = 1 |
| | } |
| | fields[i] = field |
| | } |
| | return types.NewStruct(fields) |
| | } |
| |
|
| | func (r *reader) signature(recv *types.Field) *types.Type { |
| | r.Sync(pkgbits.SyncSignature) |
| |
|
| | params := r.params() |
| | results := r.params() |
| | if r.Bool() { |
| | params[len(params)-1].SetIsDDD(true) |
| | } |
| |
|
| | return types.NewSignature(recv, params, results) |
| | } |
| |
|
| | func (r *reader) params() []*types.Field { |
| | r.Sync(pkgbits.SyncParams) |
| | params := make([]*types.Field, r.Len()) |
| | for i := range params { |
| | params[i] = r.param() |
| | } |
| | return params |
| | } |
| |
|
| | func (r *reader) param() *types.Field { |
| | r.Sync(pkgbits.SyncParam) |
| | return types.NewField(r.pos(), r.localIdent(), r.typ()) |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | var objReader = map[*types.Sym]pkgReaderIndex{} |
| |
|
| | |
| | func (r *reader) obj() ir.Node { |
| | return r.p.objInstIdx(r.objInfo(), r.dict, false) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) objInfo() objInfo { |
| | r.Sync(pkgbits.SyncObject) |
| | if r.Version().Has(pkgbits.DerivedFuncInstance) { |
| | assert(!r.Bool()) |
| | } |
| | idx := r.Reloc(pkgbits.SectionObj) |
| |
|
| | explicits := make([]typeInfo, r.Len()) |
| | for i := range explicits { |
| | explicits[i] = r.typInfo() |
| | } |
| |
|
| | return objInfo{idx, explicits} |
| | } |
| |
|
| | |
| | |
| | func (pr *pkgReader) objInstIdx(info objInfo, dict *readerDict, shaped bool) ir.Node { |
| | explicits := pr.typListIdx(info.explicits, dict) |
| |
|
| | var implicits []*types.Type |
| | if dict != nil { |
| | implicits = dict.targs |
| | } |
| |
|
| | return pr.objIdx(info.idx, implicits, explicits, shaped) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (pr *pkgReader) objIdx(idx index, implicits, explicits []*types.Type, shaped bool) ir.Node { |
| | n, err := pr.objIdxMayFail(idx, implicits, explicits, shaped) |
| | if err != nil { |
| | base.Fatalf("%v", err) |
| | } |
| | return n |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func (pr *pkgReader) objIdxMayFail(idx index, implicits, explicits []*types.Type, shaped bool) (ir.Node, error) { |
| | rname := pr.newReader(pkgbits.SectionName, idx, pkgbits.SyncObject1) |
| | _, sym := rname.qualifiedIdent() |
| | tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) |
| |
|
| | if tag == pkgbits.ObjStub { |
| | assert(!sym.IsBlank()) |
| | switch sym.Pkg { |
| | case types.BuiltinPkg, types.UnsafePkg: |
| | return sym.Def.(ir.Node), nil |
| | } |
| | if pri, ok := objReader[sym]; ok { |
| | return pri.pr.objIdxMayFail(pri.idx, nil, explicits, shaped) |
| | } |
| | if sym.Pkg.Path == "runtime" { |
| | return typecheck.LookupRuntime(sym.Name), nil |
| | } |
| | base.Fatalf("unresolved stub: %v", sym) |
| | } |
| |
|
| | dict, err := pr.objDictIdx(sym, idx, implicits, explicits, shaped) |
| | if err != nil { |
| | return nil, err |
| | } |
| |
|
| | sym = dict.baseSym |
| | if !sym.IsBlank() && sym.Def != nil { |
| | return sym.Def.(*ir.Name), nil |
| | } |
| |
|
| | r := pr.newReader(pkgbits.SectionObj, idx, pkgbits.SyncObject1) |
| | rext := pr.newReader(pkgbits.SectionObjExt, idx, pkgbits.SyncObject1) |
| |
|
| | r.dict = dict |
| | rext.dict = dict |
| |
|
| | do := func(op ir.Op, hasTParams bool) *ir.Name { |
| | pos := r.pos() |
| | setBasePos(pos) |
| | if hasTParams { |
| | r.typeParamNames() |
| | } |
| |
|
| | name := ir.NewDeclNameAt(pos, op, sym) |
| | name.Class = ir.PEXTERN |
| | if !sym.IsBlank() { |
| | if sym.Def != nil { |
| | base.FatalfAt(name.Pos(), "already have a definition for %v", name) |
| | } |
| | assert(sym.Def == nil) |
| | sym.Def = name |
| | } |
| | return name |
| | } |
| |
|
| | switch tag { |
| | default: |
| | panic("unexpected object") |
| |
|
| | case pkgbits.ObjAlias: |
| | name := do(ir.OTYPE, false) |
| |
|
| | if r.Version().Has(pkgbits.AliasTypeParamNames) { |
| | r.typeParamNames() |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | hack := sym.Def == name |
| | if hack { |
| | sym.Def = nil |
| | } |
| | typ := r.typ() |
| | if hack { |
| | if sym.Def != nil { |
| | name = sym.Def.(*ir.Name) |
| | assert(types.IdenticalStrict(name.Type(), typ)) |
| | return name, nil |
| | } |
| | sym.Def = name |
| | } |
| |
|
| | setType(name, typ) |
| | name.SetAlias(true) |
| | return name, nil |
| |
|
| | case pkgbits.ObjConst: |
| | name := do(ir.OLITERAL, false) |
| | typ := r.typ() |
| | val := FixValue(typ, r.Value()) |
| | setType(name, typ) |
| | setValue(name, val) |
| | return name, nil |
| |
|
| | case pkgbits.ObjFunc: |
| | if sym.Name == "init" { |
| | sym = Renameinit() |
| | } |
| |
|
| | npos := r.pos() |
| | setBasePos(npos) |
| | r.typeParamNames() |
| | typ := r.signature(nil) |
| | fpos := r.pos() |
| |
|
| | fn := ir.NewFunc(fpos, npos, sym, typ) |
| | name := fn.Nname |
| | if !sym.IsBlank() { |
| | if sym.Def != nil { |
| | base.FatalfAt(name.Pos(), "already have a definition for %v", name) |
| | } |
| | assert(sym.Def == nil) |
| | sym.Def = name |
| | } |
| |
|
| | if r.hasTypeParams() { |
| | name.Func.SetDupok(true) |
| | if r.dict.shaped { |
| | setType(name, shapeSig(name.Func, r.dict)) |
| | } else { |
| | todoDicts = append(todoDicts, func() { |
| | r.dict.shapedObj = pr.objIdx(idx, implicits, explicits, true).(*ir.Name) |
| | }) |
| | } |
| | } |
| |
|
| | rext.funcExt(name, nil) |
| | return name, nil |
| |
|
| | case pkgbits.ObjType: |
| | name := do(ir.OTYPE, true) |
| | typ := types.NewNamed(name) |
| | setType(name, typ) |
| | if r.hasTypeParams() && r.dict.shaped { |
| | typ.SetHasShape(true) |
| | } |
| |
|
| | |
| | rext.typeExt(name) |
| |
|
| | |
| | |
| | types.DeferCheckSize() |
| | typ.SetUnderlying(r.typWrapped(false)) |
| | types.ResumeCheckSize() |
| |
|
| | if r.hasTypeParams() && !r.dict.shaped { |
| | todoDicts = append(todoDicts, func() { |
| | r.dict.shapedObj = pr.objIdx(idx, implicits, explicits, true).(*ir.Name) |
| | }) |
| | } |
| |
|
| | methods := make([]*types.Field, r.Len()) |
| | for i := range methods { |
| | methods[i] = r.method(rext) |
| | } |
| | if len(methods) != 0 { |
| | typ.SetMethods(methods) |
| | } |
| |
|
| | if !r.dict.shaped { |
| | r.needWrapper(typ) |
| | } |
| |
|
| | return name, nil |
| |
|
| | case pkgbits.ObjVar: |
| | name := do(ir.ONAME, false) |
| | setType(name, r.typ()) |
| | rext.varExt(name) |
| | return name, nil |
| | } |
| | } |
| |
|
| | func (dict *readerDict) mangle(sym *types.Sym) *types.Sym { |
| | if !dict.hasTypeParams() { |
| | return sym |
| | } |
| |
|
| | |
| | |
| | |
| | base, suffix := types.SplitVargenSuffix(sym.Name) |
| |
|
| | var buf strings.Builder |
| | buf.WriteString(base) |
| | buf.WriteByte('[') |
| | for i, targ := range dict.targs { |
| | if i > 0 { |
| | if i == dict.implicits { |
| | buf.WriteByte(';') |
| | } else { |
| | buf.WriteByte(',') |
| | } |
| | } |
| | buf.WriteString(targ.LinkString()) |
| | } |
| | buf.WriteByte(']') |
| | buf.WriteString(suffix) |
| | return sym.Pkg.Lookup(buf.String()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func shapify(targ *types.Type, basic bool) *types.Type { |
| | if targ.Kind() == types.TFORW { |
| | if targ.IsFullyInstantiated() { |
| | |
| | |
| | |
| | |
| | if base.Debug.Shapify != 0 { |
| | base.Warn("skipping shaping of recursive type %v", targ) |
| | } |
| | if targ.HasShape() { |
| | return targ |
| | } |
| | } else { |
| | base.Fatalf("%v is missing its underlying type", targ) |
| | } |
| | } |
| | |
| | |
| | if targ.Kind() == types.TINTER && targ.IsFullyInstantiated() && targ.HasShape() { |
| | return targ |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | pointerShaping := basic && targ.IsPtr() && !targ.Elem().NotInHeap() |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if pointerShaping && !targ.Elem().IsShape() && targ.Elem().HasShape() { |
| | return targ |
| | } |
| | under := targ.Underlying() |
| | if pointerShaping { |
| | under = types.NewPtr(types.Types[types.TUINT8]) |
| | } |
| |
|
| | |
| | |
| | uls := under.LinkString() |
| | if base.Debug.MaxShapeLen != 0 && |
| | len(uls) > base.Debug.MaxShapeLen { |
| | h := hash.Sum32([]byte(uls)) |
| | uls = hex.EncodeToString(h[:]) |
| | } |
| |
|
| | sym := types.ShapePkg.Lookup(uls) |
| | if sym.Def == nil { |
| | name := ir.NewDeclNameAt(under.Pos(), ir.OTYPE, sym) |
| | typ := types.NewNamed(name) |
| | typ.SetUnderlying(under) |
| | sym.Def = typed(typ, name) |
| | } |
| | res := sym.Def.Type() |
| | assert(res.IsShape()) |
| | assert(res.HasShape()) |
| | return res |
| | } |
| |
|
| | |
| | func (pr *pkgReader) objDictIdx(sym *types.Sym, idx index, implicits, explicits []*types.Type, shaped bool) (*readerDict, error) { |
| | r := pr.newReader(pkgbits.SectionObjDict, idx, pkgbits.SyncObject1) |
| |
|
| | dict := readerDict{ |
| | shaped: shaped, |
| | } |
| |
|
| | nimplicits := r.Len() |
| | nexplicits := r.Len() |
| |
|
| | if nimplicits > len(implicits) || nexplicits != len(explicits) { |
| | return nil, fmt.Errorf("%v has %v+%v params, but instantiated with %v+%v args", sym, nimplicits, nexplicits, len(implicits), len(explicits)) |
| | } |
| |
|
| | dict.targs = append(implicits[:nimplicits:nimplicits], explicits...) |
| | dict.implicits = nimplicits |
| |
|
| | |
| | for range dict.targs[dict.implicits:] { |
| | |
| | r.typInfo() |
| | } |
| |
|
| | dict.derived = make([]derivedInfo, r.Len()) |
| | dict.derivedTypes = make([]*types.Type, len(dict.derived)) |
| | for i := range dict.derived { |
| | dict.derived[i] = derivedInfo{idx: r.Reloc(pkgbits.SectionType)} |
| | if r.Version().Has(pkgbits.DerivedInfoNeeded) { |
| | assert(!r.Bool()) |
| | } |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | for _, targ := range dict.targs { |
| | if targ.HasShape() { |
| | dict.shaped = true |
| | break |
| | } |
| | } |
| |
|
| | |
| | |
| | for i, targ := range dict.targs { |
| | basic := r.Bool() |
| | if dict.shaped { |
| | dict.targs[i] = shapify(targ, basic) |
| | } |
| | } |
| |
|
| | dict.baseSym = dict.mangle(sym) |
| |
|
| | dict.typeParamMethodExprs = make([]readerMethodExprInfo, r.Len()) |
| | for i := range dict.typeParamMethodExprs { |
| | typeParamIdx := r.Len() |
| | method := r.selector() |
| |
|
| | dict.typeParamMethodExprs[i] = readerMethodExprInfo{typeParamIdx, method} |
| | } |
| |
|
| | dict.subdicts = make([]objInfo, r.Len()) |
| | for i := range dict.subdicts { |
| | dict.subdicts[i] = r.objInfo() |
| | } |
| |
|
| | dict.rtypes = make([]typeInfo, r.Len()) |
| | for i := range dict.rtypes { |
| | dict.rtypes[i] = r.typInfo() |
| | } |
| |
|
| | dict.itabs = make([]itabInfo, r.Len()) |
| | for i := range dict.itabs { |
| | dict.itabs[i] = itabInfo{typ: r.typInfo(), iface: r.typInfo()} |
| | } |
| |
|
| | return &dict, nil |
| | } |
| |
|
| | func (r *reader) typeParamNames() { |
| | r.Sync(pkgbits.SyncTypeParamNames) |
| |
|
| | for range r.dict.targs[r.dict.implicits:] { |
| | r.pos() |
| | r.localIdent() |
| | } |
| | } |
| |
|
| | func (r *reader) method(rext *reader) *types.Field { |
| | r.Sync(pkgbits.SyncMethod) |
| | npos := r.pos() |
| | sym := r.selector() |
| | r.typeParamNames() |
| | recv := r.param() |
| | typ := r.signature(recv) |
| |
|
| | fpos := r.pos() |
| | fn := ir.NewFunc(fpos, npos, ir.MethodSym(recv.Type, sym), typ) |
| | name := fn.Nname |
| |
|
| | if r.hasTypeParams() { |
| | name.Func.SetDupok(true) |
| | if r.dict.shaped { |
| | typ = shapeSig(name.Func, r.dict) |
| | setType(name, typ) |
| | } |
| | } |
| |
|
| | rext.funcExt(name, sym) |
| |
|
| | meth := types.NewField(name.Func.Pos(), sym, typ) |
| | meth.Nname = name |
| | meth.SetNointerface(name.Func.Pragma&ir.Nointerface != 0) |
| |
|
| | return meth |
| | } |
| |
|
| | func (r *reader) qualifiedIdent() (pkg *types.Pkg, sym *types.Sym) { |
| | r.Sync(pkgbits.SyncSym) |
| | pkg = r.pkg() |
| | if name := r.String(); name != "" { |
| | sym = pkg.Lookup(name) |
| | } |
| | return |
| | } |
| |
|
| | func (r *reader) localIdent() *types.Sym { |
| | r.Sync(pkgbits.SyncLocalIdent) |
| | pkg := r.pkg() |
| | if name := r.String(); name != "" { |
| | return pkg.Lookup(name) |
| | } |
| | return nil |
| | } |
| |
|
| | func (r *reader) selector() *types.Sym { |
| | r.Sync(pkgbits.SyncSelector) |
| | pkg := r.pkg() |
| | name := r.String() |
| | if types.IsExported(name) { |
| | pkg = types.LocalPkg |
| | } |
| | return pkg.Lookup(name) |
| | } |
| |
|
| | func (r *reader) hasTypeParams() bool { |
| | return r.dict.hasTypeParams() |
| | } |
| |
|
| | func (dict *readerDict) hasTypeParams() bool { |
| | return dict != nil && len(dict.targs) != 0 |
| | } |
| |
|
| | |
| |
|
| | func (r *reader) funcExt(name *ir.Name, method *types.Sym) { |
| | r.Sync(pkgbits.SyncFuncExt) |
| |
|
| | fn := name.Func |
| |
|
| | |
| | if !fn.Pos().IsKnown() { |
| | fn.SetPos(name.Pos()) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if name.Sym().Pkg == types.LocalPkg || r.hasTypeParams() { |
| | name.Defn = fn |
| | } |
| |
|
| | fn.Pragma = r.pragmaFlag() |
| | r.linkname(name) |
| |
|
| | if buildcfg.GOARCH == "wasm" { |
| | importmod := r.String() |
| | importname := r.String() |
| | exportname := r.String() |
| |
|
| | if importmod != "" && importname != "" { |
| | fn.WasmImport = &ir.WasmImport{ |
| | Module: importmod, |
| | Name: importname, |
| | } |
| | } |
| | if exportname != "" { |
| | if method != nil { |
| | base.ErrorfAt(fn.Pos(), 0, "cannot use //go:wasmexport on a method") |
| | } |
| | fn.WasmExport = &ir.WasmExport{Name: exportname} |
| | } |
| | } |
| |
|
| | if r.Bool() { |
| | assert(name.Defn == nil) |
| |
|
| | fn.ABI = obj.ABI(r.Uint64()) |
| |
|
| | |
| | for _, f := range name.Type().RecvParams() { |
| | f.Note = r.String() |
| | } |
| |
|
| | if r.Bool() { |
| | fn.Inl = &ir.Inline{ |
| | Cost: int32(r.Len()), |
| | CanDelayResults: r.Bool(), |
| | } |
| | if buildcfg.Experiment.NewInliner { |
| | fn.Inl.Properties = r.String() |
| | } |
| | } |
| | } else { |
| | r.addBody(name.Func, method) |
| | } |
| | r.Sync(pkgbits.SyncEOF) |
| | } |
| |
|
| | func (r *reader) typeExt(name *ir.Name) { |
| | r.Sync(pkgbits.SyncTypeExt) |
| |
|
| | typ := name.Type() |
| |
|
| | if r.hasTypeParams() { |
| | |
| | |
| | typ.SetIsFullyInstantiated(true) |
| | |
| | for _, targ := range r.dict.targs { |
| | if targ.HasShape() { |
| | typ.SetHasShape(true) |
| | break |
| | } |
| | } |
| | } |
| |
|
| | name.SetPragma(r.pragmaFlag()) |
| |
|
| | typecheck.SetBaseTypeIndex(typ, r.Int64(), r.Int64()) |
| | } |
| |
|
| | func (r *reader) varExt(name *ir.Name) { |
| | r.Sync(pkgbits.SyncVarExt) |
| | r.linkname(name) |
| | } |
| |
|
| | func (r *reader) linkname(name *ir.Name) { |
| | assert(name.Op() == ir.ONAME) |
| | r.Sync(pkgbits.SyncLinkname) |
| |
|
| | if idx := r.Int64(); idx >= 0 { |
| | lsym := name.Linksym() |
| | lsym.SymIdx = int32(idx) |
| | lsym.Set(obj.AttrIndexed, true) |
| | } else { |
| | linkname := r.String() |
| | sym := name.Sym() |
| | sym.Linkname = linkname |
| | if sym.Pkg == types.LocalPkg && linkname != "" { |
| | |
| | |
| | |
| | |
| | |
| | |
| | sym.Linksym().Set(obj.AttrLinkname, true) |
| | } |
| | } |
| | } |
| |
|
| | func (r *reader) pragmaFlag() ir.PragmaFlag { |
| | r.Sync(pkgbits.SyncPragma) |
| | return ir.PragmaFlag(r.Int()) |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | var bodyReader = map[*ir.Func]pkgReaderIndex{} |
| |
|
| | |
| | |
| | var importBodyReader = map[*types.Sym]pkgReaderIndex{} |
| |
|
| | |
| | |
| | func bodyReaderFor(fn *ir.Func) (pri pkgReaderIndex, ok bool) { |
| | if fn.Nname.Defn != nil { |
| | pri, ok = bodyReader[fn] |
| | base.AssertfAt(ok, base.Pos, "must have bodyReader for %v", fn) |
| | } else { |
| | pri, ok = importBodyReader[fn.Sym()] |
| | } |
| | return |
| | } |
| |
|
| | |
| | |
| | var todoDicts []func() |
| |
|
| | |
| | |
| | var todoBodies []*ir.Func |
| |
|
| | |
| | |
| | func (r *reader) addBody(fn *ir.Func, method *types.Sym) { |
| | |
| | |
| | assert(fn.Nname.Defn != nil) |
| |
|
| | idx := r.Reloc(pkgbits.SectionBody) |
| |
|
| | pri := pkgReaderIndex{r.p, idx, r.dict, method, nil} |
| | bodyReader[fn] = pri |
| |
|
| | if r.curfn == nil { |
| | todoBodies = append(todoBodies, fn) |
| | return |
| | } |
| |
|
| | pri.funcBody(fn) |
| | } |
| |
|
| | func (pri pkgReaderIndex) funcBody(fn *ir.Func) { |
| | r := pri.asReader(pkgbits.SectionBody, pkgbits.SyncFuncBody) |
| | r.funcBody(fn) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) funcBody(fn *ir.Func) { |
| | r.curfn = fn |
| | r.closureVars = fn.ClosureVars |
| | if len(r.closureVars) != 0 && r.hasTypeParams() { |
| | r.dictParam = r.closureVars[len(r.closureVars)-1] |
| | } |
| |
|
| | ir.WithFunc(fn, func() { |
| | r.declareParams() |
| |
|
| | if r.syntheticBody(fn.Pos()) { |
| | return |
| | } |
| |
|
| | if !r.Bool() { |
| | return |
| | } |
| |
|
| | body := r.stmts() |
| | if body == nil { |
| | body = []ir.Node{typecheck.Stmt(ir.NewBlockStmt(src.NoXPos, nil))} |
| | } |
| | fn.Body = body |
| | fn.Endlineno = r.pos() |
| | }) |
| |
|
| | r.marker.WriteTo(fn) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) syntheticBody(pos src.XPos) bool { |
| | if r.synthetic != nil { |
| | r.synthetic(pos, r) |
| | return true |
| | } |
| |
|
| | |
| | |
| | if r.hasTypeParams() && !r.dict.shaped { |
| | r.callShaped(pos) |
| | return true |
| | } |
| |
|
| | return false |
| | } |
| |
|
| | |
| | |
| | func (r *reader) callShaped(pos src.XPos) { |
| | shapedObj := r.dict.shapedObj |
| | assert(shapedObj != nil) |
| |
|
| | var shapedFn ir.Node |
| | if r.methodSym == nil { |
| | |
| | |
| | assert(shapedObj.Op() == ir.ONAME && shapedObj.Class == ir.PFUNC) |
| | shapedFn = shapedObj |
| | } else { |
| | |
| | |
| | shapedFn = shapedMethodExpr(pos, shapedObj, r.methodSym) |
| | } |
| |
|
| | params := r.syntheticArgs() |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | var args ir.Nodes |
| | if r.methodSym != nil { |
| | args.Append(params[0]) |
| | params = params[1:] |
| | } |
| | args.Append(typecheck.Expr(ir.NewAddrExpr(pos, r.p.dictNameOf(r.dict)))) |
| | args.Append(params...) |
| |
|
| | r.syntheticTailCall(pos, shapedFn, args) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) syntheticArgs() ir.Nodes { |
| | sig := r.curfn.Nname.Type() |
| | return ir.ToNodes(r.curfn.Dcl[:sig.NumRecvs()+sig.NumParams()]) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) syntheticTailCall(pos src.XPos, fn ir.Node, args ir.Nodes) { |
| | |
| | |
| | r.curfn.SetWrapper(true) |
| |
|
| | call := typecheck.Call(pos, fn, args, fn.Type().IsVariadic()).(*ir.CallExpr) |
| |
|
| | var stmt ir.Node |
| | if fn.Type().NumResults() != 0 { |
| | stmt = typecheck.Stmt(ir.NewReturnStmt(pos, []ir.Node{call})) |
| | } else { |
| | stmt = call |
| | } |
| | r.curfn.Body.Append(stmt) |
| | } |
| |
|
| | |
| | func (pr *pkgReader) dictNameOf(dict *readerDict) *ir.Name { |
| | pos := base.AutogeneratedPos |
| |
|
| | |
| | base.AssertfAt(!dict.shaped, pos, "runtime dictionary of shaped object %v", dict.baseSym) |
| |
|
| | sym := dict.baseSym.Pkg.Lookup(objabi.GlobalDictPrefix + "." + dict.baseSym.Name) |
| | if sym.Def != nil { |
| | return sym.Def.(*ir.Name) |
| | } |
| |
|
| | name := ir.NewNameAt(pos, sym, dict.varType()) |
| | name.Class = ir.PEXTERN |
| | sym.Def = name |
| |
|
| | lsym := name.Linksym() |
| | ot := 0 |
| |
|
| | assertOffset := func(section string, offset int) { |
| | base.AssertfAt(ot == offset*types.PtrSize, pos, "writing section %v at offset %v, but it should be at %v*%v", section, ot, offset, types.PtrSize) |
| | } |
| |
|
| | assertOffset("type param method exprs", dict.typeParamMethodExprsOffset()) |
| | for _, info := range dict.typeParamMethodExprs { |
| | typeParam := dict.targs[info.typeParamIdx] |
| | method := typecheck.NewMethodExpr(pos, typeParam, info.method) |
| |
|
| | rsym := method.FuncName().Linksym() |
| | assert(rsym.ABI() == obj.ABIInternal) |
| |
|
| | ot = objw.SymPtr(lsym, ot, rsym, 0) |
| | } |
| |
|
| | assertOffset("subdictionaries", dict.subdictsOffset()) |
| | for _, info := range dict.subdicts { |
| | explicits := pr.typListIdx(info.explicits, dict) |
| |
|
| | |
| | |
| | name := pr.objDictName(info.idx, dict.targs, explicits) |
| |
|
| | ot = objw.SymPtr(lsym, ot, name.Linksym(), 0) |
| | } |
| |
|
| | assertOffset("rtypes", dict.rtypesOffset()) |
| | for _, info := range dict.rtypes { |
| | typ := pr.typIdx(info, dict, true) |
| | ot = objw.SymPtr(lsym, ot, reflectdata.TypeLinksym(typ), 0) |
| |
|
| | |
| | reflectdata.MarkTypeUsedInInterface(typ, lsym) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | assertOffset("itabs", dict.itabsOffset()) |
| | for _, info := range dict.itabs { |
| | typ := pr.typIdx(info.typ, dict, true) |
| | iface := pr.typIdx(info.iface, dict, true) |
| |
|
| | if !typ.IsInterface() && iface.IsInterface() && !iface.IsEmptyInterface() { |
| | ot = objw.SymPtr(lsym, ot, reflectdata.ITabLsym(typ, iface), 0) |
| | } else { |
| | ot += types.PtrSize |
| | } |
| |
|
| | |
| | reflectdata.MarkTypeUsedInInterface(typ, lsym) |
| | reflectdata.MarkTypeUsedInInterface(iface, lsym) |
| | } |
| |
|
| | objw.Global(lsym, int32(ot), obj.DUPOK|obj.RODATA) |
| |
|
| | return name |
| | } |
| |
|
| | |
| | |
| | func (dict *readerDict) typeParamMethodExprsOffset() int { |
| | return 0 |
| | } |
| |
|
| | |
| | |
| | func (dict *readerDict) subdictsOffset() int { |
| | return dict.typeParamMethodExprsOffset() + len(dict.typeParamMethodExprs) |
| | } |
| |
|
| | |
| | |
| | func (dict *readerDict) rtypesOffset() int { |
| | return dict.subdictsOffset() + len(dict.subdicts) |
| | } |
| |
|
| | |
| | |
| | func (dict *readerDict) itabsOffset() int { |
| | return dict.rtypesOffset() + len(dict.rtypes) |
| | } |
| |
|
| | |
| | |
| | func (dict *readerDict) numWords() int64 { |
| | return int64(dict.itabsOffset() + len(dict.itabs)) |
| | } |
| |
|
| | |
| | func (dict *readerDict) varType() *types.Type { |
| | return types.NewArray(types.Types[types.TUINTPTR], dict.numWords()) |
| | } |
| |
|
| | func (r *reader) declareParams() { |
| | r.curfn.DeclareParams(!r.funarghack) |
| |
|
| | for _, name := range r.curfn.Dcl { |
| | if name.Sym().Name == dictParamName { |
| | r.dictParam = name |
| | continue |
| | } |
| |
|
| | r.addLocal(name) |
| | } |
| | } |
| |
|
| | func (r *reader) addLocal(name *ir.Name) { |
| | if r.synthetic == nil { |
| | r.Sync(pkgbits.SyncAddLocal) |
| | if r.p.SyncMarkers() { |
| | want := r.Int() |
| | if have := len(r.locals); have != want { |
| | base.FatalfAt(name.Pos(), "locals table has desynced") |
| | } |
| | } |
| | r.varDictIndex(name) |
| | } |
| |
|
| | r.locals = append(r.locals, name) |
| | } |
| |
|
| | func (r *reader) useLocal() *ir.Name { |
| | r.Sync(pkgbits.SyncUseObjLocal) |
| | if r.Bool() { |
| | return r.locals[r.Len()] |
| | } |
| | return r.closureVars[r.Len()] |
| | } |
| |
|
| | func (r *reader) openScope() { |
| | r.Sync(pkgbits.SyncOpenScope) |
| | pos := r.pos() |
| |
|
| | if base.Flag.Dwarf { |
| | r.scopeVars = append(r.scopeVars, len(r.curfn.Dcl)) |
| | r.marker.Push(pos) |
| | } |
| | } |
| |
|
| | func (r *reader) closeScope() { |
| | r.Sync(pkgbits.SyncCloseScope) |
| | r.lastCloseScopePos = r.pos() |
| |
|
| | r.closeAnotherScope() |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (r *reader) closeAnotherScope() { |
| | r.Sync(pkgbits.SyncCloseAnotherScope) |
| |
|
| | if base.Flag.Dwarf { |
| | scopeVars := r.scopeVars[len(r.scopeVars)-1] |
| | r.scopeVars = r.scopeVars[:len(r.scopeVars)-1] |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | retract := true |
| | for _, n := range r.curfn.Dcl[scopeVars:] { |
| | if !n.AutoTemp() { |
| | retract = false |
| | break |
| | } |
| | } |
| |
|
| | if retract { |
| | |
| | r.marker.Unpush() |
| | } else { |
| | r.marker.Pop(r.lastCloseScopePos) |
| | } |
| | } |
| | } |
| |
|
| | |
| |
|
| | func (r *reader) stmt() ir.Node { |
| | return block(r.stmts()) |
| | } |
| |
|
| | func block(stmts []ir.Node) ir.Node { |
| | switch len(stmts) { |
| | case 0: |
| | return nil |
| | case 1: |
| | return stmts[0] |
| | default: |
| | return ir.NewBlockStmt(stmts[0].Pos(), stmts) |
| | } |
| | } |
| |
|
| | func (r *reader) stmts() ir.Nodes { |
| | assert(ir.CurFunc == r.curfn) |
| | var res ir.Nodes |
| |
|
| | r.Sync(pkgbits.SyncStmts) |
| | for { |
| | tag := codeStmt(r.Code(pkgbits.SyncStmt1)) |
| | if tag == stmtEnd { |
| | r.Sync(pkgbits.SyncStmtsEnd) |
| | return res |
| | } |
| |
|
| | if n := r.stmt1(tag, &res); n != nil { |
| | res.Append(typecheck.Stmt(n)) |
| | } |
| | } |
| | } |
| |
|
| | func (r *reader) stmt1(tag codeStmt, out *ir.Nodes) ir.Node { |
| | var label *types.Sym |
| | if n := len(*out); n > 0 { |
| | if ls, ok := (*out)[n-1].(*ir.LabelStmt); ok { |
| | label = ls.Label |
| | } |
| | } |
| |
|
| | switch tag { |
| | default: |
| | panic("unexpected statement") |
| |
|
| | case stmtAssign: |
| | pos := r.pos() |
| | names, lhs := r.assignList() |
| | rhs := r.multiExpr() |
| |
|
| | if len(rhs) == 0 { |
| | for _, name := range names { |
| | as := ir.NewAssignStmt(pos, name, nil) |
| | as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, name)) |
| | out.Append(typecheck.Stmt(as)) |
| | } |
| | return nil |
| | } |
| |
|
| | if len(lhs) == 1 && len(rhs) == 1 { |
| | n := ir.NewAssignStmt(pos, lhs[0], rhs[0]) |
| | n.Def = r.initDefn(n, names) |
| | return n |
| | } |
| |
|
| | n := ir.NewAssignListStmt(pos, ir.OAS2, lhs, rhs) |
| | n.Def = r.initDefn(n, names) |
| | return n |
| |
|
| | case stmtAssignOp: |
| | op := r.op() |
| | lhs := r.expr() |
| | pos := r.pos() |
| | rhs := r.expr() |
| | return ir.NewAssignOpStmt(pos, op, lhs, rhs) |
| |
|
| | case stmtIncDec: |
| | op := r.op() |
| | lhs := r.expr() |
| | pos := r.pos() |
| | n := ir.NewAssignOpStmt(pos, op, lhs, ir.NewOne(pos, lhs.Type())) |
| | n.IncDec = true |
| | return n |
| |
|
| | case stmtBlock: |
| | out.Append(r.blockStmt()...) |
| | return nil |
| |
|
| | case stmtBranch: |
| | pos := r.pos() |
| | op := r.op() |
| | sym := r.optLabel() |
| | return ir.NewBranchStmt(pos, op, sym) |
| |
|
| | case stmtCall: |
| | pos := r.pos() |
| | op := r.op() |
| | call := r.expr() |
| | stmt := ir.NewGoDeferStmt(pos, op, call) |
| | if op == ir.ODEFER { |
| | x := r.optExpr() |
| | if x != nil { |
| | stmt.DeferAt = x.(ir.Expr) |
| | } |
| | } |
| | return stmt |
| |
|
| | case stmtExpr: |
| | return r.expr() |
| |
|
| | case stmtFor: |
| | return r.forStmt(label) |
| |
|
| | case stmtIf: |
| | return r.ifStmt() |
| |
|
| | case stmtLabel: |
| | pos := r.pos() |
| | sym := r.label() |
| | return ir.NewLabelStmt(pos, sym) |
| |
|
| | case stmtReturn: |
| | pos := r.pos() |
| | results := r.multiExpr() |
| | return ir.NewReturnStmt(pos, results) |
| |
|
| | case stmtSelect: |
| | return r.selectStmt(label) |
| |
|
| | case stmtSend: |
| | pos := r.pos() |
| | ch := r.expr() |
| | value := r.expr() |
| | return ir.NewSendStmt(pos, ch, value) |
| |
|
| | case stmtSwitch: |
| | return r.switchStmt(label) |
| | } |
| | } |
| |
|
| | func (r *reader) assignList() ([]*ir.Name, []ir.Node) { |
| | lhs := make([]ir.Node, r.Len()) |
| | var names []*ir.Name |
| |
|
| | for i := range lhs { |
| | expr, def := r.assign() |
| | lhs[i] = expr |
| | if def { |
| | names = append(names, expr.(*ir.Name)) |
| | } |
| | } |
| |
|
| | return names, lhs |
| | } |
| |
|
| | |
| | |
| | func (r *reader) assign() (ir.Node, bool) { |
| | switch tag := codeAssign(r.Code(pkgbits.SyncAssign)); tag { |
| | default: |
| | panic("unhandled assignee expression") |
| |
|
| | case assignBlank: |
| | return typecheck.AssignExpr(ir.BlankNode), false |
| |
|
| | case assignDef: |
| | pos := r.pos() |
| | setBasePos(pos) |
| | name := r.curfn.NewLocal(pos, r.localIdent(), r.typ()) |
| | r.addLocal(name) |
| | return name, true |
| |
|
| | case assignExpr: |
| | return r.expr(), false |
| | } |
| | } |
| |
|
| | func (r *reader) blockStmt() []ir.Node { |
| | r.Sync(pkgbits.SyncBlockStmt) |
| | r.openScope() |
| | stmts := r.stmts() |
| | r.closeScope() |
| | return stmts |
| | } |
| |
|
| | func (r *reader) forStmt(label *types.Sym) ir.Node { |
| | r.Sync(pkgbits.SyncForStmt) |
| |
|
| | r.openScope() |
| |
|
| | if r.Bool() { |
| | pos := r.pos() |
| | rang := ir.NewRangeStmt(pos, nil, nil, nil, nil, false) |
| | rang.Label = label |
| |
|
| | names, lhs := r.assignList() |
| | if len(lhs) >= 1 { |
| | rang.Key = lhs[0] |
| | if len(lhs) >= 2 { |
| | rang.Value = lhs[1] |
| | } |
| | } |
| | rang.Def = r.initDefn(rang, names) |
| |
|
| | rang.X = r.expr() |
| | if rang.X.Type().IsMap() { |
| | rang.RType = r.rtype(pos) |
| | } |
| | if rang.Key != nil && !ir.IsBlank(rang.Key) { |
| | rang.KeyTypeWord, rang.KeySrcRType = r.convRTTI(pos) |
| | } |
| | if rang.Value != nil && !ir.IsBlank(rang.Value) { |
| | rang.ValueTypeWord, rang.ValueSrcRType = r.convRTTI(pos) |
| | } |
| |
|
| | rang.Body = r.blockStmt() |
| | rang.DistinctVars = r.Bool() |
| | r.closeAnotherScope() |
| |
|
| | return rang |
| | } |
| |
|
| | pos := r.pos() |
| | init := r.stmt() |
| | cond := r.optExpr() |
| | post := r.stmt() |
| | body := r.blockStmt() |
| | perLoopVars := r.Bool() |
| | r.closeAnotherScope() |
| |
|
| | if ir.IsConst(cond, constant.Bool) && !ir.BoolVal(cond) { |
| | return init |
| | } |
| |
|
| | stmt := ir.NewForStmt(pos, init, cond, post, body, perLoopVars) |
| | stmt.Label = label |
| | return stmt |
| | } |
| |
|
| | func (r *reader) ifStmt() ir.Node { |
| | r.Sync(pkgbits.SyncIfStmt) |
| | r.openScope() |
| | pos := r.pos() |
| | init := r.stmts() |
| | cond := r.expr() |
| | staticCond := r.Int() |
| | var then, els []ir.Node |
| | if staticCond >= 0 { |
| | then = r.blockStmt() |
| | } else { |
| | r.lastCloseScopePos = r.pos() |
| | } |
| | if staticCond <= 0 { |
| | els = r.stmts() |
| | } |
| | r.closeAnotherScope() |
| |
|
| | if staticCond != 0 { |
| | |
| | |
| | |
| |
|
| | if cond.Op() != ir.OLITERAL { |
| | init.Append(typecheck.Stmt(ir.NewAssignStmt(pos, ir.BlankNode, cond))) |
| | } |
| | init.Append(then...) |
| | init.Append(els...) |
| | return block(init) |
| | } |
| |
|
| | n := ir.NewIfStmt(pos, cond, then, els) |
| | n.SetInit(init) |
| | return n |
| | } |
| |
|
| | func (r *reader) selectStmt(label *types.Sym) ir.Node { |
| | r.Sync(pkgbits.SyncSelectStmt) |
| |
|
| | pos := r.pos() |
| | clauses := make([]*ir.CommClause, r.Len()) |
| | for i := range clauses { |
| | if i > 0 { |
| | r.closeScope() |
| | } |
| | r.openScope() |
| |
|
| | pos := r.pos() |
| | comm := r.stmt() |
| | body := r.stmts() |
| |
|
| | |
| | |
| | |
| | |
| | |
| | if as, ok := comm.(*ir.AssignStmt); ok && as.Op() == ir.OAS && !as.Def { |
| | if conv, ok := as.Y.(*ir.ConvExpr); ok && conv.Op() == ir.OCONVIFACE { |
| | base.AssertfAt(conv.Implicit(), conv.Pos(), "expected implicit conversion: %v", conv) |
| |
|
| | recv := conv.X |
| | base.AssertfAt(recv.Op() == ir.ORECV, recv.Pos(), "expected receive expression: %v", recv) |
| |
|
| | tmp := r.temp(pos, recv.Type()) |
| |
|
| | |
| | tmpAs := ir.NewAssignStmt(pos, tmp, recv) |
| | tmpAs.Def = true |
| | tmpAs.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, tmp)) |
| | comm = tmpAs |
| |
|
| | |
| | conv.X = tmp |
| | body = append([]ir.Node{as}, body...) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | if as2, ok := comm.(*ir.AssignListStmt); ok && as2.Op() == ir.OAS2 { |
| | init := ir.TakeInit(as2.Rhs[0]) |
| | base.AssertfAt(len(init) == 1 && init[0].Op() == ir.OAS2RECV, as2.Pos(), "unexpected assignment: %+v", as2) |
| |
|
| | comm = init[0] |
| | body = append([]ir.Node{as2}, body...) |
| | } |
| |
|
| | clauses[i] = ir.NewCommStmt(pos, comm, body) |
| | } |
| | if len(clauses) > 0 { |
| | r.closeScope() |
| | } |
| | n := ir.NewSelectStmt(pos, clauses) |
| | n.Label = label |
| | return n |
| | } |
| |
|
| | func (r *reader) switchStmt(label *types.Sym) ir.Node { |
| | r.Sync(pkgbits.SyncSwitchStmt) |
| |
|
| | r.openScope() |
| | pos := r.pos() |
| | init := r.stmt() |
| |
|
| | var tag ir.Node |
| | var ident *ir.Ident |
| | var iface *types.Type |
| | if r.Bool() { |
| | pos := r.pos() |
| | if r.Bool() { |
| | ident = ir.NewIdent(r.pos(), r.localIdent()) |
| | } |
| | x := r.expr() |
| | iface = x.Type() |
| | tag = ir.NewTypeSwitchGuard(pos, ident, x) |
| | } else { |
| | tag = r.optExpr() |
| | } |
| |
|
| | clauses := make([]*ir.CaseClause, r.Len()) |
| | for i := range clauses { |
| | if i > 0 { |
| | r.closeScope() |
| | } |
| | r.openScope() |
| |
|
| | pos := r.pos() |
| | var cases, rtypes []ir.Node |
| | if iface != nil { |
| | cases = make([]ir.Node, r.Len()) |
| | if len(cases) == 0 { |
| | cases = nil |
| | } |
| | for i := range cases { |
| | if r.Bool() { |
| | cases[i] = typecheck.Expr(types.BuiltinPkg.Lookup("nil").Def.(*ir.NilExpr)) |
| | } else { |
| | cases[i] = r.exprType() |
| | } |
| | } |
| | } else { |
| | cases = r.exprList() |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if tag == nil { |
| | for i, cas := range cases { |
| | if cas.Type().IsEmptyInterface() { |
| | for len(rtypes) < i { |
| | rtypes = append(rtypes, nil) |
| | } |
| | rtypes = append(rtypes, reflectdata.TypePtrAt(cas.Pos(), types.Types[types.TBOOL])) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | clause := ir.NewCaseStmt(pos, cases, nil) |
| | clause.RTypes = rtypes |
| |
|
| | if ident != nil { |
| | name := r.curfn.NewLocal(r.pos(), ident.Sym(), r.typ()) |
| | r.addLocal(name) |
| | clause.Var = name |
| | name.Defn = tag |
| | } |
| |
|
| | clause.Body = r.stmts() |
| | clauses[i] = clause |
| | } |
| | if len(clauses) > 0 { |
| | r.closeScope() |
| | } |
| | r.closeScope() |
| |
|
| | n := ir.NewSwitchStmt(pos, tag, clauses) |
| | n.Label = label |
| | if init != nil { |
| | n.SetInit([]ir.Node{init}) |
| | } |
| | return n |
| | } |
| |
|
| | func (r *reader) label() *types.Sym { |
| | r.Sync(pkgbits.SyncLabel) |
| | name := r.String() |
| | if r.inlCall != nil && name != "_" { |
| | name = fmt.Sprintf("~%s·%d", name, inlgen) |
| | } |
| | return typecheck.Lookup(name) |
| | } |
| |
|
| | func (r *reader) optLabel() *types.Sym { |
| | r.Sync(pkgbits.SyncOptLabel) |
| | if r.Bool() { |
| | return r.label() |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | |
| | func (r *reader) initDefn(defn ir.InitNode, names []*ir.Name) bool { |
| | if len(names) == 0 { |
| | return false |
| | } |
| |
|
| | init := make([]ir.Node, len(names)) |
| | for i, name := range names { |
| | name.Defn = defn |
| | init[i] = ir.NewDecl(name.Pos(), ir.ODCL, name) |
| | } |
| | defn.SetInit(init) |
| | return true |
| | } |
| |
|
| | |
| |
|
| | |
| | func (r *reader) expr() (res ir.Node) { |
| | defer func() { |
| | if res != nil && res.Typecheck() == 0 { |
| | base.FatalfAt(res.Pos(), "%v missed typecheck", res) |
| | } |
| | }() |
| |
|
| | switch tag := codeExpr(r.Code(pkgbits.SyncExpr)); tag { |
| | default: |
| | panic("unhandled expression") |
| |
|
| | case exprLocal: |
| | return typecheck.Expr(r.useLocal()) |
| |
|
| | case exprGlobal: |
| | |
| | |
| | return typecheck.Callee(r.obj()) |
| |
|
| | case exprFuncInst: |
| | origPos, pos := r.origPos() |
| | wrapperFn, baseFn, dictPtr := r.funcInst(pos) |
| | if wrapperFn != nil { |
| | return wrapperFn |
| | } |
| | return r.curry(origPos, false, baseFn, dictPtr, nil) |
| |
|
| | case exprConst: |
| | pos := r.pos() |
| | typ := r.typ() |
| | val := FixValue(typ, r.Value()) |
| | return ir.NewBasicLit(pos, typ, val) |
| |
|
| | case exprZero: |
| | pos := r.pos() |
| | typ := r.typ() |
| | return ir.NewZero(pos, typ) |
| |
|
| | case exprCompLit: |
| | return r.compLit() |
| |
|
| | case exprFuncLit: |
| | return r.funcLit() |
| |
|
| | case exprFieldVal: |
| | x := r.expr() |
| | pos := r.pos() |
| | sym := r.selector() |
| |
|
| | return typecheck.XDotField(pos, x, sym) |
| |
|
| | case exprMethodVal: |
| | recv := r.expr() |
| | origPos, pos := r.origPos() |
| | wrapperFn, baseFn, dictPtr := r.methodExpr() |
| |
|
| | |
| | |
| | if wrapperFn, ok := wrapperFn.(*ir.SelectorExpr); ok && wrapperFn.Op() == ir.OMETHEXPR { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if recv.Type().HasShape() { |
| | typ := wrapperFn.Type().Param(0).Type |
| | if !types.Identical(typ, recv.Type()) { |
| | base.FatalfAt(wrapperFn.Pos(), "receiver %L does not match %L", recv, wrapperFn) |
| | } |
| | recv = typecheck.Expr(ir.NewConvExpr(recv.Pos(), ir.OCONVNOP, typ, recv)) |
| | } |
| |
|
| | n := typecheck.XDotMethod(pos, recv, wrapperFn.Sel, false) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | if n.Selection != wrapperFn.Selection { |
| | assert(n.Selection.Sym == wrapperFn.Selection.Sym) |
| | assert(types.Identical(n.Selection.Type, wrapperFn.Selection.Type)) |
| | assert(types.Identical(n.Selection.Type.Recv().Type, wrapperFn.Selection.Type.Recv().Type)) |
| | } |
| |
|
| | wrapper := methodValueWrapper{ |
| | rcvr: n.X.Type(), |
| | method: n.Selection, |
| | } |
| |
|
| | if r.importedDef() { |
| | haveMethodValueWrappers = append(haveMethodValueWrappers, wrapper) |
| | } else { |
| | needMethodValueWrappers = append(needMethodValueWrappers, wrapper) |
| | } |
| | return n |
| | } |
| |
|
| | |
| | |
| | return r.curry(origPos, true, baseFn, recv, dictPtr) |
| |
|
| | case exprMethodExpr: |
| | recv := r.typ() |
| |
|
| | implicits := make([]int, r.Len()) |
| | for i := range implicits { |
| | implicits[i] = r.Len() |
| | } |
| | var deref, addr bool |
| | if r.Bool() { |
| | deref = true |
| | } else if r.Bool() { |
| | addr = true |
| | } |
| |
|
| | origPos, pos := r.origPos() |
| | wrapperFn, baseFn, dictPtr := r.methodExpr() |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | if wrapperFn != nil && len(implicits) == 0 && !deref && !addr { |
| | if !types.Identical(recv, wrapperFn.Type().Param(0).Type) { |
| | base.FatalfAt(pos, "want receiver type %v, but have method %L", recv, wrapperFn) |
| | } |
| | return wrapperFn |
| | } |
| |
|
| | |
| | |
| | |
| | if method, ok := wrapperFn.(*ir.SelectorExpr); ok && method.Op() == ir.OMETHEXPR && !recv.HasShape() { |
| | return typecheck.NewMethodExpr(pos, recv, method.Sel) |
| | } |
| |
|
| | return r.methodExprWrap(origPos, recv, implicits, deref, addr, baseFn, dictPtr) |
| |
|
| | case exprIndex: |
| | x := r.expr() |
| | pos := r.pos() |
| | index := r.expr() |
| | n := typecheck.Expr(ir.NewIndexExpr(pos, x, index)) |
| | switch n.Op() { |
| | case ir.OINDEXMAP: |
| | n := n.(*ir.IndexExpr) |
| | n.RType = r.rtype(pos) |
| | } |
| | return n |
| |
|
| | case exprSlice: |
| | x := r.expr() |
| | pos := r.pos() |
| | var index [3]ir.Node |
| | for i := range index { |
| | index[i] = r.optExpr() |
| | } |
| | op := ir.OSLICE |
| | if index[2] != nil { |
| | op = ir.OSLICE3 |
| | } |
| | return typecheck.Expr(ir.NewSliceExpr(pos, op, x, index[0], index[1], index[2])) |
| |
|
| | case exprAssert: |
| | x := r.expr() |
| | pos := r.pos() |
| | typ := r.exprType() |
| | srcRType := r.rtype(pos) |
| |
|
| | |
| | if typ, ok := typ.(*ir.DynamicType); ok && typ.Op() == ir.ODYNAMICTYPE { |
| | assert := ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, x, typ.RType) |
| | assert.SrcRType = srcRType |
| | assert.ITab = typ.ITab |
| | return typed(typ.Type(), assert) |
| | } |
| | return typecheck.Expr(ir.NewTypeAssertExpr(pos, x, typ.Type())) |
| |
|
| | case exprUnaryOp: |
| | op := r.op() |
| | pos := r.pos() |
| | x := r.expr() |
| |
|
| | switch op { |
| | case ir.OADDR: |
| | return typecheck.Expr(typecheck.NodAddrAt(pos, x)) |
| | case ir.ODEREF: |
| | return typecheck.Expr(ir.NewStarExpr(pos, x)) |
| | } |
| | return typecheck.Expr(ir.NewUnaryExpr(pos, op, x)) |
| |
|
| | case exprBinaryOp: |
| | op := r.op() |
| | x := r.expr() |
| | pos := r.pos() |
| | y := r.expr() |
| |
|
| | switch op { |
| | case ir.OANDAND, ir.OOROR: |
| | return typecheck.Expr(ir.NewLogicalExpr(pos, op, x, y)) |
| | case ir.OLSH, ir.ORSH: |
| | |
| | |
| | if ir.IsConstNode(y) { |
| | val := constant.ToInt(y.Val()) |
| | assert(val.Kind() == constant.Int && constant.Sign(val) >= 0) |
| | } |
| | } |
| | return typecheck.Expr(ir.NewBinaryExpr(pos, op, x, y)) |
| |
|
| | case exprRecv: |
| | x := r.expr() |
| | pos := r.pos() |
| | for i, n := 0, r.Len(); i < n; i++ { |
| | x = Implicit(typecheck.DotField(pos, x, r.Len())) |
| | } |
| | if r.Bool() { |
| | x = Implicit(Deref(pos, x.Type().Elem(), x)) |
| | } else if r.Bool() { |
| | x = Implicit(Addr(pos, x)) |
| | } |
| | return x |
| |
|
| | case exprCall: |
| | var fun ir.Node |
| | var args ir.Nodes |
| | if r.Bool() { |
| | recv := r.expr() |
| | _, method, dictPtr := r.methodExpr() |
| |
|
| | if recv.Type().IsInterface() && method.Op() == ir.OMETHEXPR { |
| | method := method.(*ir.SelectorExpr) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | fun = typecheck.XDotMethod(method.Pos(), recv, method.Sel, true) |
| | } else { |
| | if recv.Type().IsInterface() { |
| | |
| | |
| | if base.Flag.LowerM != 0 { |
| | base.WarnfAt(method.Pos(), "imprecise interface call") |
| | } |
| | } |
| |
|
| | fun = method |
| | args.Append(recv) |
| | } |
| | if dictPtr != nil { |
| | args.Append(dictPtr) |
| | } |
| | } else if r.Bool() { |
| | pos := r.pos() |
| | _, shapedFn, dictPtr := r.funcInst(pos) |
| | fun = shapedFn |
| | args.Append(dictPtr) |
| | } else { |
| | fun = r.expr() |
| | } |
| | pos := r.pos() |
| | args.Append(r.multiExpr()...) |
| | dots := r.Bool() |
| | n := typecheck.Call(pos, fun, args, dots) |
| | switch n.Op() { |
| | case ir.OAPPEND: |
| | n := n.(*ir.CallExpr) |
| | n.RType = r.rtype(pos) |
| | |
| | |
| | if n.IsDDD { |
| | if conv, ok := n.Args[1].(*ir.ConvExpr); ok && conv.Op() == ir.OCONVNOP && conv.Implicit() { |
| | n.Args[1] = conv.X |
| | } |
| | } |
| | case ir.OCOPY: |
| | n := n.(*ir.BinaryExpr) |
| | n.RType = r.rtype(pos) |
| | case ir.ODELETE: |
| | n := n.(*ir.CallExpr) |
| | n.RType = r.rtype(pos) |
| | case ir.OUNSAFESLICE: |
| | n := n.(*ir.BinaryExpr) |
| | n.RType = r.rtype(pos) |
| | } |
| | return n |
| |
|
| | case exprMake: |
| | pos := r.pos() |
| | typ := r.exprType() |
| | extra := r.exprs() |
| | n := typecheck.Expr(ir.NewCallExpr(pos, ir.OMAKE, nil, append([]ir.Node{typ}, extra...))).(*ir.MakeExpr) |
| | n.RType = r.rtype(pos) |
| | return n |
| |
|
| | case exprNew: |
| | pos := r.pos() |
| | if r.Bool() { |
| | |
| | x := r.expr() |
| | x = typecheck.DefaultLit(x, nil) |
| | var init ir.Nodes |
| | addr := ir.NewAddrExpr(pos, r.tempCopy(pos, x, &init)) |
| | addr.SetInit(init) |
| | return typecheck.Expr(addr) |
| | } |
| | |
| | return typecheck.Expr(ir.NewUnaryExpr(pos, ir.ONEW, r.exprType())) |
| |
|
| | case exprSizeof: |
| | return ir.NewUintptr(r.pos(), r.typ().Size()) |
| |
|
| | case exprAlignof: |
| | return ir.NewUintptr(r.pos(), r.typ().Alignment()) |
| |
|
| | case exprOffsetof: |
| | pos := r.pos() |
| | typ := r.typ() |
| | types.CalcSize(typ) |
| |
|
| | var offset int64 |
| | for i := r.Len(); i >= 0; i-- { |
| | field := typ.Field(r.Len()) |
| | offset += field.Offset |
| | typ = field.Type |
| | } |
| |
|
| | return ir.NewUintptr(pos, offset) |
| |
|
| | case exprReshape: |
| | typ := r.typ() |
| | x := r.expr() |
| |
|
| | if types.IdenticalStrict(x.Type(), typ) { |
| | return x |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | if x.Type() == types.UntypedBool && typ.IsBoolean() { |
| | return x |
| | } |
| |
|
| | base.AssertfAt(x.Type().HasShape() || typ.HasShape(), x.Pos(), "%L and %v are not shape types", x, typ) |
| | base.AssertfAt(types.Identical(x.Type(), typ), x.Pos(), "%L is not shape-identical to %v", x, typ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | base.AssertfAt(ir.HasUniquePos(x), x.Pos(), "cannot call SetType(%v) on %L", typ, x) |
| |
|
| | if base.Debug.Reshape != 0 { |
| | base.WarnfAt(x.Pos(), "reshaping %L to %v", x, typ) |
| | } |
| |
|
| | x.SetType(typ) |
| | return x |
| |
|
| | case exprConvert: |
| | implicit := r.Bool() |
| | typ := r.typ() |
| | pos := r.pos() |
| | typeWord, srcRType := r.convRTTI(pos) |
| | dstTypeParam := r.Bool() |
| | identical := r.Bool() |
| | x := r.expr() |
| |
|
| | |
| | x = typecheck.DefaultLit(x, typ) |
| |
|
| | ce := ir.NewConvExpr(pos, ir.OCONV, typ, x) |
| | ce.TypeWord, ce.SrcRType = typeWord, srcRType |
| | if implicit { |
| | ce.SetImplicit(true) |
| | } |
| | n := typecheck.Expr(ce) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | if !identical { |
| | if n, ok := n.(*ir.ConvExpr); ok && n.Op() == ir.OCONVNOP && n.Type().IsInterface() && !n.Type().IsEmptyInterface() && (n.Type().HasShape() || n.X.Type().HasShape()) { |
| | n.SetOp(ir.OCONVIFACE) |
| | } |
| | } |
| |
|
| | |
| | |
| | if dstTypeParam && ir.IsConstNode(n) { |
| | |
| | n = Implicit(ir.NewConvExpr(pos, ir.OCONVNOP, n.Type(), n)) |
| | n.SetTypecheck(1) |
| | } |
| | return n |
| |
|
| | case exprRuntimeBuiltin: |
| | builtin := typecheck.LookupRuntime(r.String()) |
| | return builtin |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (r *reader) funcInst(pos src.XPos) (wrapperFn, baseFn, dictPtr ir.Node) { |
| | |
| | var implicits []*types.Type |
| | if r.dict != nil { |
| | implicits = r.dict.targs |
| | } |
| |
|
| | if r.Bool() { |
| | idx := r.Len() |
| | info := r.dict.subdicts[idx] |
| | explicits := r.p.typListIdx(info.explicits, r.dict) |
| |
|
| | baseFn = r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name) |
| |
|
| | |
| | |
| | dictPtrType := baseFn.Type().Param(0).Type |
| | dictPtr = typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, dictPtrType, r.dictWord(pos, r.dict.subdictsOffset()+idx))) |
| |
|
| | return |
| | } |
| |
|
| | info := r.objInfo() |
| | explicits := r.p.typListIdx(info.explicits, r.dict) |
| |
|
| | wrapperFn = r.p.objIdx(info.idx, implicits, explicits, false).(*ir.Name) |
| | baseFn = r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name) |
| |
|
| | dictName := r.p.objDictName(info.idx, implicits, explicits) |
| | dictPtr = typecheck.Expr(ir.NewAddrExpr(pos, dictName)) |
| |
|
| | return |
| | } |
| |
|
| | func (pr *pkgReader) objDictName(idx index, implicits, explicits []*types.Type) *ir.Name { |
| | rname := pr.newReader(pkgbits.SectionName, idx, pkgbits.SyncObject1) |
| | _, sym := rname.qualifiedIdent() |
| | tag := pkgbits.CodeObj(rname.Code(pkgbits.SyncCodeObj)) |
| |
|
| | if tag == pkgbits.ObjStub { |
| | assert(!sym.IsBlank()) |
| | if pri, ok := objReader[sym]; ok { |
| | return pri.pr.objDictName(pri.idx, nil, explicits) |
| | } |
| | base.Fatalf("unresolved stub: %v", sym) |
| | } |
| |
|
| | dict, err := pr.objDictIdx(sym, idx, implicits, explicits, false) |
| | if err != nil { |
| | base.Fatalf("%v", err) |
| | } |
| |
|
| | return pr.dictNameOf(dict) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (r *reader) curry(origPos src.XPos, ifaceHack bool, fun ir.Node, arg0, arg1 ir.Node) ir.Node { |
| | var captured ir.Nodes |
| | captured.Append(fun, arg0) |
| | if arg1 != nil { |
| | captured.Append(arg1) |
| | } |
| |
|
| | params, results := syntheticSig(fun.Type()) |
| | params = params[len(captured)-1:] |
| | typ := types.NewSignature(nil, params, results) |
| |
|
| | addBody := func(pos src.XPos, r *reader, captured []ir.Node) { |
| | fun := captured[0] |
| |
|
| | var args ir.Nodes |
| | args.Append(captured[1:]...) |
| | args.Append(r.syntheticArgs()...) |
| |
|
| | r.syntheticTailCall(pos, fun, args) |
| | } |
| |
|
| | return r.syntheticClosure(origPos, typ, ifaceHack, captured, addBody) |
| | } |
| |
|
| | |
| | |
| | |
| | func (r *reader) methodExprWrap(origPos src.XPos, recv *types.Type, implicits []int, deref, addr bool, method, dictPtr ir.Node) ir.Node { |
| | var captured ir.Nodes |
| | captured.Append(method) |
| |
|
| | params, results := syntheticSig(method.Type()) |
| |
|
| | |
| | params[0].Type = recv |
| |
|
| | |
| | |
| | |
| | if dictPtr != nil { |
| | captured.Append(dictPtr) |
| | params = append(params[:1], params[2:]...) |
| | } |
| |
|
| | typ := types.NewSignature(nil, params, results) |
| |
|
| | addBody := func(pos src.XPos, r *reader, captured []ir.Node) { |
| | fn := captured[0] |
| | args := r.syntheticArgs() |
| |
|
| | |
| | { |
| | arg := args[0] |
| | for _, ix := range implicits { |
| | arg = Implicit(typecheck.DotField(pos, arg, ix)) |
| | } |
| | if deref { |
| | arg = Implicit(Deref(pos, arg.Type().Elem(), arg)) |
| | } else if addr { |
| | arg = Implicit(Addr(pos, arg)) |
| | } |
| | args[0] = arg |
| | } |
| |
|
| | |
| | if dictPtr != nil { |
| | newArgs := make([]ir.Node, len(args)+1) |
| | newArgs[0] = args[0] |
| | newArgs[1] = captured[1] |
| | copy(newArgs[2:], args[1:]) |
| | args = newArgs |
| | } |
| |
|
| | r.syntheticTailCall(pos, fn, args) |
| | } |
| |
|
| | return r.syntheticClosure(origPos, typ, false, captured, addBody) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (r *reader) syntheticClosure(origPos src.XPos, typ *types.Type, ifaceHack bool, captures ir.Nodes, addBody func(pos src.XPos, r *reader, captured []ir.Node)) ir.Node { |
| | |
| | |
| | |
| | |
| | |
| | isSafe := func(n ir.Node) bool { |
| | if n.Op() == ir.ONAME && n.(*ir.Name).Class == ir.PFUNC { |
| | return true |
| | } |
| | if n.Op() == ir.OMETHEXPR { |
| | return true |
| | } |
| |
|
| | return false |
| | } |
| |
|
| | fn := r.inlClosureFunc(origPos, typ, ir.OCLOSURE) |
| | fn.SetWrapper(true) |
| |
|
| | clo := fn.OClosure |
| | inlPos := clo.Pos() |
| |
|
| | var init ir.Nodes |
| | for i, n := range captures { |
| | if isSafe(n) { |
| | continue |
| | } |
| |
|
| | tmp := r.tempCopy(inlPos, n, &init) |
| | ir.NewClosureVar(origPos, fn, tmp) |
| |
|
| | |
| | |
| | if ifaceHack && i == 1 && n.Type().IsInterface() { |
| | check := ir.NewUnaryExpr(inlPos, ir.OCHECKNIL, ir.NewUnaryExpr(inlPos, ir.OITAB, tmp)) |
| | init.Append(typecheck.Stmt(check)) |
| | } |
| | } |
| |
|
| | pri := pkgReaderIndex{synthetic: func(pos src.XPos, r *reader) { |
| | captured := make([]ir.Node, len(captures)) |
| | next := 0 |
| | for i, n := range captures { |
| | if isSafe(n) { |
| | captured[i] = n |
| | } else { |
| | captured[i] = r.closureVars[next] |
| | next++ |
| | } |
| | } |
| | assert(next == len(r.closureVars)) |
| |
|
| | addBody(origPos, r, captured) |
| | }} |
| | bodyReader[fn] = pri |
| | pri.funcBody(fn) |
| |
|
| | return ir.InitExpr(init, clo) |
| | } |
| |
|
| | |
| | |
| | |
| | func syntheticSig(sig *types.Type) (params, results []*types.Field) { |
| | clone := func(params []*types.Field) []*types.Field { |
| | res := make([]*types.Field, len(params)) |
| | for i, param := range params { |
| | |
| | |
| | |
| | |
| | |
| | |
| | res[i] = types.NewField(base.AutogeneratedPos, param.Sym, param.Type) |
| | res[i].SetIsDDD(param.IsDDD()) |
| | } |
| | return res |
| | } |
| |
|
| | return clone(sig.Params()), clone(sig.Results()) |
| | } |
| |
|
| | func (r *reader) optExpr() ir.Node { |
| | if r.Bool() { |
| | return r.expr() |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (r *reader) methodExpr() (wrapperFn, baseFn, dictPtr ir.Node) { |
| | recv := r.typ() |
| | sig0 := r.typ() |
| | pos := r.pos() |
| | sym := r.selector() |
| |
|
| | |
| | |
| | sig := typecheck.NewMethodType(sig0, recv) |
| |
|
| | if r.Bool() { |
| | idx := r.Len() |
| | word := r.dictWord(pos, r.dict.typeParamMethodExprsOffset()+idx) |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | fn := typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, sig, ir.NewAddrExpr(pos, word))) |
| | return fn, fn, nil |
| | } |
| |
|
| | |
| | |
| | |
| | var implicits []*types.Type |
| | if r.dict != nil { |
| | implicits = r.dict.targs |
| | } |
| |
|
| | if r.Bool() { |
| | idx := r.Len() |
| | info := r.dict.subdicts[idx] |
| | explicits := r.p.typListIdx(info.explicits, r.dict) |
| |
|
| | shapedObj := r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name) |
| | shapedFn := shapedMethodExpr(pos, shapedObj, sym) |
| |
|
| | |
| | |
| | dictPtrType := shapedFn.Type().Param(1).Type |
| | dictPtr := typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, dictPtrType, r.dictWord(pos, r.dict.subdictsOffset()+idx))) |
| |
|
| | return nil, shapedFn, dictPtr |
| | } |
| |
|
| | if r.Bool() { |
| | info := r.objInfo() |
| | explicits := r.p.typListIdx(info.explicits, r.dict) |
| |
|
| | shapedObj := r.p.objIdx(info.idx, implicits, explicits, true).(*ir.Name) |
| | shapedFn := shapedMethodExpr(pos, shapedObj, sym) |
| |
|
| | dict := r.p.objDictName(info.idx, implicits, explicits) |
| | dictPtr := typecheck.Expr(ir.NewAddrExpr(pos, dict)) |
| |
|
| | |
| | if !types.Identical(dictPtr.Type(), shapedFn.Type().Param(1).Type) { |
| | base.FatalfAt(pos, "dict %L, but shaped method %L", dict, shapedFn) |
| | } |
| |
|
| | |
| | |
| | base.AssertfAt(!recv.HasShape(), pos, "shaped receiver %v", recv) |
| | wrapperFn := typecheck.NewMethodExpr(pos, recv, sym) |
| | base.AssertfAt(types.Identical(sig, wrapperFn.Type()), pos, "wrapper %L does not have type %v", wrapperFn, sig) |
| |
|
| | return wrapperFn, shapedFn, dictPtr |
| | } |
| |
|
| | |
| | base.AssertfAt(!recv.HasShape() || recv.IsInterface(), pos, "shaped receiver %v", recv) |
| | fn := typecheck.NewMethodExpr(pos, recv, sym) |
| | return fn, fn, nil |
| | } |
| |
|
| | |
| | |
| | func shapedMethodExpr(pos src.XPos, obj *ir.Name, sym *types.Sym) *ir.SelectorExpr { |
| | assert(obj.Op() == ir.OTYPE) |
| |
|
| | typ := obj.Type() |
| | assert(typ.HasShape()) |
| |
|
| | method := func() *types.Field { |
| | for _, method := range typ.Methods() { |
| | if method.Sym == sym { |
| | return method |
| | } |
| | } |
| |
|
| | base.FatalfAt(pos, "failed to find method %v in shaped type %v", sym, typ) |
| | panic("unreachable") |
| | }() |
| |
|
| | |
| | recv := method.Type.Recv().Type |
| | return typecheck.NewMethodExpr(pos, recv, sym) |
| | } |
| |
|
| | func (r *reader) multiExpr() []ir.Node { |
| | r.Sync(pkgbits.SyncMultiExpr) |
| |
|
| | if r.Bool() { |
| | pos := r.pos() |
| | expr := r.expr() |
| |
|
| | results := make([]ir.Node, r.Len()) |
| | as := ir.NewAssignListStmt(pos, ir.OAS2, nil, []ir.Node{expr}) |
| | as.Def = true |
| | for i := range results { |
| | tmp := r.temp(pos, r.typ()) |
| | tmp.Defn = as |
| | as.PtrInit().Append(ir.NewDecl(pos, ir.ODCL, tmp)) |
| | as.Lhs.Append(tmp) |
| |
|
| | res := ir.Node(tmp) |
| | if r.Bool() { |
| | n := ir.NewConvExpr(pos, ir.OCONV, r.typ(), res) |
| | n.TypeWord, n.SrcRType = r.convRTTI(pos) |
| | n.SetImplicit(true) |
| | res = typecheck.Expr(n) |
| | } |
| | results[i] = res |
| | } |
| |
|
| | |
| | results[0] = ir.InitExpr([]ir.Node{typecheck.Stmt(as)}, results[0]) |
| | return results |
| | } |
| |
|
| | |
| | exprs := make([]ir.Node, r.Len()) |
| | if len(exprs) == 0 { |
| | return nil |
| | } |
| | for i := range exprs { |
| | exprs[i] = r.expr() |
| | } |
| | return exprs |
| | } |
| |
|
| | |
| | func (r *reader) temp(pos src.XPos, typ *types.Type) *ir.Name { |
| | return typecheck.TempAt(pos, r.curfn, typ) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) tempCopy(pos src.XPos, expr ir.Node, init *ir.Nodes) *ir.Name { |
| | tmp := r.temp(pos, expr.Type()) |
| |
|
| | init.Append(typecheck.Stmt(ir.NewDecl(pos, ir.ODCL, tmp))) |
| |
|
| | assign := ir.NewAssignStmt(pos, tmp, expr) |
| | assign.Def = true |
| | init.Append(typecheck.Stmt(ir.NewAssignStmt(pos, tmp, expr))) |
| |
|
| | tmp.Defn = assign |
| |
|
| | return tmp |
| | } |
| |
|
| | func (r *reader) compLit() ir.Node { |
| | r.Sync(pkgbits.SyncCompLit) |
| | pos := r.pos() |
| | typ0 := r.typ() |
| |
|
| | typ := typ0 |
| | if typ.IsPtr() { |
| | typ = typ.Elem() |
| | } |
| | if typ.Kind() == types.TFORW { |
| | base.FatalfAt(pos, "unresolved composite literal type: %v", typ) |
| | } |
| | var rtype ir.Node |
| | if typ.IsMap() { |
| | rtype = r.rtype(pos) |
| | } |
| | isStruct := typ.Kind() == types.TSTRUCT |
| |
|
| | elems := make([]ir.Node, r.Len()) |
| | for i := range elems { |
| | elemp := &elems[i] |
| |
|
| | if isStruct { |
| | sk := ir.NewStructKeyExpr(r.pos(), typ.Field(r.Len()), nil) |
| | *elemp, elemp = sk, &sk.Value |
| | } else if r.Bool() { |
| | kv := ir.NewKeyExpr(r.pos(), r.expr(), nil) |
| | *elemp, elemp = kv, &kv.Value |
| | } |
| |
|
| | *elemp = r.expr() |
| | } |
| |
|
| | lit := typecheck.Expr(ir.NewCompLitExpr(pos, ir.OCOMPLIT, typ, elems)) |
| | if rtype != nil { |
| | lit := lit.(*ir.CompLitExpr) |
| | lit.RType = rtype |
| | } |
| | if typ0.IsPtr() { |
| | lit = typecheck.Expr(typecheck.NodAddrAt(pos, lit)) |
| | lit.SetType(typ0) |
| | } |
| | return lit |
| | } |
| |
|
| | func (r *reader) funcLit() ir.Node { |
| | r.Sync(pkgbits.SyncFuncLit) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | r.suppressInlPos++ |
| | origPos := r.pos() |
| | sig := r.signature(nil) |
| | r.suppressInlPos-- |
| | why := ir.OCLOSURE |
| | if r.Bool() { |
| | why = ir.ORANGE |
| | } |
| |
|
| | fn := r.inlClosureFunc(origPos, sig, why) |
| |
|
| | fn.ClosureVars = make([]*ir.Name, 0, r.Len()) |
| | for len(fn.ClosureVars) < cap(fn.ClosureVars) { |
| | |
| | |
| | ir.NewClosureVar(r.pos(), fn, r.useLocal()) |
| | } |
| | if param := r.dictParam; param != nil { |
| | |
| | |
| | ir.NewClosureVar(param.Pos(), fn, param) |
| | } |
| |
|
| | r.addBody(fn, nil) |
| |
|
| | return fn.OClosure |
| | } |
| |
|
| | |
| | |
| | func (r *reader) inlClosureFunc(origPos src.XPos, sig *types.Type, why ir.Op) *ir.Func { |
| | curfn := r.inlCaller |
| | if curfn == nil { |
| | curfn = r.curfn |
| | } |
| |
|
| | |
| | return ir.NewClosureFunc(origPos, r.inlPos(origPos), why, sig, curfn, typecheck.Target) |
| | } |
| |
|
| | func (r *reader) exprList() []ir.Node { |
| | r.Sync(pkgbits.SyncExprList) |
| | return r.exprs() |
| | } |
| |
|
| | func (r *reader) exprs() []ir.Node { |
| | r.Sync(pkgbits.SyncExprs) |
| | nodes := make([]ir.Node, r.Len()) |
| | if len(nodes) == 0 { |
| | return nil |
| | } |
| | for i := range nodes { |
| | nodes[i] = r.expr() |
| | } |
| | return nodes |
| | } |
| |
|
| | |
| | |
| | func (r *reader) dictWord(pos src.XPos, idx int) ir.Node { |
| | base.AssertfAt(r.dictParam != nil, pos, "expected dictParam in %v", r.curfn) |
| | return typecheck.Expr(ir.NewIndexExpr(pos, r.dictParam, ir.NewInt(pos, int64(idx)))) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) rttiWord(pos src.XPos, idx int) ir.Node { |
| | return typecheck.Expr(ir.NewConvExpr(pos, ir.OCONVNOP, types.NewPtr(types.Types[types.TUINT8]), r.dictWord(pos, idx))) |
| | } |
| |
|
| | |
| | |
| | |
| | func (r *reader) rtype(pos src.XPos) ir.Node { |
| | _, rtype := r.rtype0(pos) |
| | return rtype |
| | } |
| |
|
| | func (r *reader) rtype0(pos src.XPos) (typ *types.Type, rtype ir.Node) { |
| | r.Sync(pkgbits.SyncRType) |
| | if r.Bool() { |
| | idx := r.Len() |
| | info := r.dict.rtypes[idx] |
| | typ = r.p.typIdx(info, r.dict, true) |
| | rtype = r.rttiWord(pos, r.dict.rtypesOffset()+idx) |
| | return |
| | } |
| |
|
| | typ = r.typ() |
| | rtype = reflectdata.TypePtrAt(pos, typ) |
| | return |
| | } |
| |
|
| | |
| | func (r *reader) varDictIndex(name *ir.Name) { |
| | if r.Bool() { |
| | idx := 1 + r.dict.rtypesOffset() + r.Len() |
| | if int(uint16(idx)) != idx { |
| | base.FatalfAt(name.Pos(), "DictIndex overflow for %v: %v", name, idx) |
| | } |
| | name.DictIndex = uint16(idx) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (r *reader) itab(pos src.XPos) (typ *types.Type, typRType ir.Node, iface *types.Type, ifaceRType ir.Node, itab ir.Node) { |
| | typ, typRType = r.rtype0(pos) |
| | iface, ifaceRType = r.rtype0(pos) |
| |
|
| | idx := -1 |
| | if r.Bool() { |
| | idx = r.Len() |
| | } |
| |
|
| | if !typ.IsInterface() && iface.IsInterface() && !iface.IsEmptyInterface() { |
| | if idx >= 0 { |
| | itab = r.rttiWord(pos, r.dict.itabsOffset()+idx) |
| | } else { |
| | base.AssertfAt(!typ.HasShape(), pos, "%v is a shape type", typ) |
| | base.AssertfAt(!iface.HasShape(), pos, "%v is a shape type", iface) |
| |
|
| | lsym := reflectdata.ITabLsym(typ, iface) |
| | itab = typecheck.LinksymAddr(pos, lsym, types.Types[types.TUINT8]) |
| | } |
| | } |
| |
|
| | return |
| | } |
| |
|
| | |
| | |
| | func (r *reader) convRTTI(pos src.XPos) (typeWord, srcRType ir.Node) { |
| | r.Sync(pkgbits.SyncConvRTTI) |
| | src, srcRType0, dst, dstRType, itab := r.itab(pos) |
| | if !dst.IsInterface() { |
| | return |
| | } |
| |
|
| | |
| | switch { |
| | case dst.IsEmptyInterface(): |
| | if !src.IsInterface() { |
| | typeWord = srcRType0 |
| | } |
| | case !src.IsInterface(): |
| | typeWord = itab |
| | default: |
| | typeWord = dstRType |
| | } |
| |
|
| | |
| | if !src.IsInterface() { |
| | srcRType = srcRType0 |
| | } |
| |
|
| | return |
| | } |
| |
|
| | func (r *reader) exprType() ir.Node { |
| | r.Sync(pkgbits.SyncExprType) |
| | pos := r.pos() |
| |
|
| | var typ *types.Type |
| | var rtype, itab ir.Node |
| |
|
| | if r.Bool() { |
| | |
| | typ, rtype, _, _, itab = r.itab(pos) |
| | if !typ.IsInterface() { |
| | rtype = nil |
| | } |
| | } else { |
| | typ, rtype = r.rtype0(pos) |
| |
|
| | if !r.Bool() { |
| | return ir.TypeNode(typ) |
| | } |
| | } |
| |
|
| | dt := ir.NewDynamicType(pos, rtype) |
| | dt.ITab = itab |
| | dt = typed(typ, dt).(*ir.DynamicType) |
| | if st := dt.ToStatic(); st != nil { |
| | return st |
| | } |
| | return dt |
| | } |
| |
|
| | func (r *reader) op() ir.Op { |
| | r.Sync(pkgbits.SyncOp) |
| | return ir.Op(r.Len()) |
| | } |
| |
|
| | |
| |
|
| | func (r *reader) pkgInit(self *types.Pkg, target *ir.Package) { |
| | cgoPragmas := make([][]string, r.Len()) |
| | for i := range cgoPragmas { |
| | cgoPragmas[i] = r.Strings() |
| | } |
| | target.CgoPragmas = cgoPragmas |
| |
|
| | r.pkgInitOrder(target) |
| |
|
| | r.pkgDecls(target) |
| |
|
| | r.Sync(pkgbits.SyncEOF) |
| | } |
| |
|
| | |
| | |
| | func (r *reader) pkgInitOrder(target *ir.Package) { |
| | initOrder := make([]ir.Node, r.Len()) |
| | if len(initOrder) == 0 { |
| | return |
| | } |
| |
|
| | |
| | pos := base.AutogeneratedPos |
| | base.Pos = pos |
| |
|
| | fn := ir.NewFunc(pos, pos, typecheck.Lookup("init"), types.NewSignature(nil, nil, nil)) |
| | fn.SetIsPackageInit(true) |
| | fn.SetInlinabilityChecked(true) |
| |
|
| | typecheck.DeclFunc(fn) |
| | r.curfn = fn |
| |
|
| | for i := range initOrder { |
| | lhs := make([]ir.Node, r.Len()) |
| | for j := range lhs { |
| | lhs[j] = r.obj() |
| | } |
| | rhs := r.expr() |
| | pos := lhs[0].Pos() |
| |
|
| | var as ir.Node |
| | if len(lhs) == 1 { |
| | as = typecheck.Stmt(ir.NewAssignStmt(pos, lhs[0], rhs)) |
| | } else { |
| | as = typecheck.Stmt(ir.NewAssignListStmt(pos, ir.OAS2, lhs, []ir.Node{rhs})) |
| | } |
| |
|
| | for _, v := range lhs { |
| | v.(*ir.Name).Defn = as |
| | } |
| |
|
| | initOrder[i] = as |
| | } |
| |
|
| | fn.Body = initOrder |
| |
|
| | typecheck.FinishFuncBody() |
| | r.curfn = nil |
| | r.locals = nil |
| |
|
| | |
| | staticinit.OutlineMapInits(fn) |
| |
|
| | target.Inits = append(target.Inits, fn) |
| | } |
| |
|
| | func (r *reader) pkgDecls(target *ir.Package) { |
| | r.Sync(pkgbits.SyncDecls) |
| | for { |
| | switch code := codeDecl(r.Code(pkgbits.SyncDecl)); code { |
| | default: |
| | panic(fmt.Sprintf("unhandled decl: %v", code)) |
| |
|
| | case declEnd: |
| | return |
| |
|
| | case declFunc: |
| | names := r.pkgObjs(target) |
| | assert(len(names) == 1) |
| | target.Funcs = append(target.Funcs, names[0].Func) |
| |
|
| | case declMethod: |
| | typ := r.typ() |
| | sym := r.selector() |
| |
|
| | method := typecheck.Lookdot1(nil, sym, typ, typ.Methods(), 0) |
| | target.Funcs = append(target.Funcs, method.Nname.(*ir.Name).Func) |
| |
|
| | case declVar: |
| | names := r.pkgObjs(target) |
| |
|
| | if n := r.Len(); n > 0 { |
| | assert(len(names) == 1) |
| | embeds := make([]ir.Embed, n) |
| | for i := range embeds { |
| | embeds[i] = ir.Embed{Pos: r.pos(), Patterns: r.Strings()} |
| | } |
| | names[0].Embed = &embeds |
| | target.Embeds = append(target.Embeds, names[0]) |
| | } |
| |
|
| | case declOther: |
| | r.pkgObjs(target) |
| | } |
| | } |
| | } |
| |
|
| | func (r *reader) pkgObjs(target *ir.Package) []*ir.Name { |
| | r.Sync(pkgbits.SyncDeclNames) |
| | nodes := make([]*ir.Name, r.Len()) |
| | for i := range nodes { |
| | r.Sync(pkgbits.SyncDeclName) |
| |
|
| | name := r.obj().(*ir.Name) |
| | nodes[i] = name |
| |
|
| | sym := name.Sym() |
| | if sym.IsBlank() { |
| | continue |
| | } |
| |
|
| | switch name.Class { |
| | default: |
| | base.FatalfAt(name.Pos(), "unexpected class: %v", name.Class) |
| |
|
| | case ir.PEXTERN: |
| | target.Externs = append(target.Externs, name) |
| |
|
| | case ir.PFUNC: |
| | assert(name.Type().Recv() == nil) |
| |
|
| | |
| | if strings.HasPrefix(sym.Name, "init.") { |
| | target.Inits = append(target.Inits, name.Func) |
| | } |
| | } |
| |
|
| | if base.Ctxt.Flag_dynlink && types.LocalPkg.Name == "main" && types.IsExported(sym.Name) && name.Op() == ir.ONAME { |
| | assert(!sym.OnExportList()) |
| | target.PluginExports = append(target.PluginExports, name) |
| | sym.SetOnExportList(true) |
| | } |
| |
|
| | if base.Flag.AsmHdr != "" && (name.Op() == ir.OLITERAL || name.Op() == ir.OTYPE) { |
| | assert(!sym.Asm()) |
| | target.AsmHdrDecls = append(target.AsmHdrDecls, name) |
| | sym.SetAsm(true) |
| | } |
| | } |
| |
|
| | return nodes |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | func unifiedHaveInlineBody(fn *ir.Func) bool { |
| | if fn.Inl == nil { |
| | return false |
| | } |
| |
|
| | _, ok := bodyReaderFor(fn) |
| | return ok |
| | } |
| |
|
| | var inlgen = 0 |
| |
|
| | |
| | |
| | func unifiedInlineCall(callerfn *ir.Func, call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExpr { |
| | pri, ok := bodyReaderFor(fn) |
| | if !ok { |
| | base.FatalfAt(call.Pos(), "cannot inline call to %v: missing inline body", fn) |
| | } |
| |
|
| | if !fn.Inl.HaveDcl { |
| | expandInline(fn, pri) |
| | } |
| |
|
| | r := pri.asReader(pkgbits.SectionBody, pkgbits.SyncFuncBody) |
| |
|
| | tmpfn := ir.NewFunc(fn.Pos(), fn.Nname.Pos(), callerfn.Sym(), fn.Type()) |
| |
|
| | r.curfn = tmpfn |
| |
|
| | r.inlCaller = callerfn |
| | r.inlCall = call |
| | r.inlFunc = fn |
| | r.inlTreeIndex = inlIndex |
| | r.inlPosBases = make(map[*src.PosBase]*src.PosBase) |
| | r.funarghack = true |
| |
|
| | r.closureVars = make([]*ir.Name, len(r.inlFunc.ClosureVars)) |
| | for i, cv := range r.inlFunc.ClosureVars { |
| | |
| | |
| | if cv.Outer.Curfn != callerfn { |
| | base.FatalfAt(call.Pos(), "inlining closure call across frames") |
| | } |
| | r.closureVars[i] = cv.Outer |
| | } |
| | if len(r.closureVars) != 0 && r.hasTypeParams() { |
| | r.dictParam = r.closureVars[len(r.closureVars)-1] |
| | } |
| |
|
| | r.declareParams() |
| |
|
| | var inlvars, retvars []*ir.Name |
| | { |
| | sig := r.curfn.Type() |
| | endParams := sig.NumRecvs() + sig.NumParams() |
| | endResults := endParams + sig.NumResults() |
| |
|
| | inlvars = r.curfn.Dcl[:endParams] |
| | retvars = r.curfn.Dcl[endParams:endResults] |
| | } |
| |
|
| | r.delayResults = fn.Inl.CanDelayResults |
| |
|
| | r.retlabel = typecheck.AutoLabel(".i") |
| | inlgen++ |
| |
|
| | init := ir.TakeInit(call) |
| |
|
| | |
| | |
| | |
| | if call.Op() == ir.OCALLFUNC { |
| | inline.CalleeEffects(&init, call.Fun) |
| | } |
| |
|
| | var args ir.Nodes |
| | if call.Op() == ir.OCALLMETH { |
| | base.FatalfAt(call.Pos(), "OCALLMETH missed by typecheck") |
| | } |
| | args.Append(call.Args...) |
| |
|
| | |
| | as2 := ir.NewAssignListStmt(call.Pos(), ir.OAS2, ir.ToNodes(inlvars), args) |
| | as2.Def = true |
| | var as2init ir.Nodes |
| | for _, name := range inlvars { |
| | if ir.IsBlank(name) { |
| | continue |
| | } |
| | |
| | as2init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name)) |
| | name.Defn = as2 |
| | } |
| | as2.SetInit(as2init) |
| | init.Append(typecheck.Stmt(as2)) |
| |
|
| | if !r.delayResults { |
| | |
| | |
| | for _, name := range retvars { |
| | |
| | init.Append(ir.NewDecl(call.Pos(), ir.ODCL, name)) |
| | ras := ir.NewAssignStmt(call.Pos(), name, nil) |
| | init.Append(typecheck.Stmt(ras)) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | init.Append(ir.NewInlineMarkStmt(call.Pos().WithIsStmt(), int64(r.inlTreeIndex))) |
| |
|
| | ir.WithFunc(r.curfn, func() { |
| | if !r.syntheticBody(call.Pos()) { |
| | assert(r.Bool()) |
| |
|
| | r.curfn.Body = r.stmts() |
| | r.curfn.Endlineno = r.pos() |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | readBodies(typecheck.Target, true) |
| |
|
| | |
| | var edit func(ir.Node) ir.Node |
| | edit = func(n ir.Node) ir.Node { |
| | if ret, ok := n.(*ir.ReturnStmt); ok { |
| | n = typecheck.Stmt(r.inlReturn(ret, retvars)) |
| | } |
| | ir.EditChildren(n, edit) |
| | return n |
| | } |
| | edit(r.curfn) |
| | }) |
| |
|
| | body := r.curfn.Body |
| |
|
| | |
| | for _, name := range r.curfn.Dcl { |
| | name.Curfn = callerfn |
| |
|
| | if name.Class != ir.PAUTO { |
| | name.SetPos(r.inlPos(name.Pos())) |
| | name.SetInlFormal(true) |
| | name.Class = ir.PAUTO |
| | } else { |
| | name.SetInlLocal(true) |
| | } |
| | } |
| | callerfn.Dcl = append(callerfn.Dcl, r.curfn.Dcl...) |
| |
|
| | body.Append(ir.NewLabelStmt(call.Pos(), r.retlabel)) |
| |
|
| | res := ir.NewInlinedCallExpr(call.Pos(), body, ir.ToNodes(retvars)) |
| | res.SetInit(init) |
| | res.SetType(call.Type()) |
| | res.SetTypecheck(1) |
| |
|
| | |
| | assert(len(todoBodies) == 0) |
| |
|
| | return res |
| | } |
| |
|
| | |
| | |
| | func (r *reader) inlReturn(ret *ir.ReturnStmt, retvars []*ir.Name) *ir.BlockStmt { |
| | pos := r.inlCall.Pos() |
| |
|
| | block := ir.TakeInit(ret) |
| |
|
| | if results := ret.Results; len(results) != 0 { |
| | assert(len(retvars) == len(results)) |
| |
|
| | as2 := ir.NewAssignListStmt(pos, ir.OAS2, ir.ToNodes(retvars), ret.Results) |
| |
|
| | if r.delayResults { |
| | for _, name := range retvars { |
| | |
| | block.Append(ir.NewDecl(pos, ir.ODCL, name)) |
| | name.Defn = as2 |
| | } |
| | } |
| |
|
| | block.Append(as2) |
| | } |
| |
|
| | block.Append(ir.NewBranchStmt(pos, ir.OGOTO, r.retlabel)) |
| | return ir.NewBlockStmt(pos, block) |
| | } |
| |
|
| | |
| | |
| | func expandInline(fn *ir.Func, pri pkgReaderIndex) { |
| | |
| | |
| | |
| | |
| |
|
| | fndcls := len(fn.Dcl) |
| | topdcls := len(typecheck.Target.Funcs) |
| |
|
| | tmpfn := ir.NewFunc(fn.Pos(), fn.Nname.Pos(), fn.Sym(), fn.Type()) |
| | tmpfn.ClosureVars = fn.ClosureVars |
| |
|
| | { |
| | r := pri.asReader(pkgbits.SectionBody, pkgbits.SyncFuncBody) |
| |
|
| | |
| | r.funarghack = true |
| |
|
| | r.funcBody(tmpfn) |
| | } |
| |
|
| | |
| | for _, name := range tmpfn.Dcl { |
| | name.Curfn = fn |
| | } |
| | fn.Inl.Dcl = tmpfn.Dcl |
| | fn.Inl.HaveDcl = true |
| |
|
| | |
| | assert(fndcls == len(fn.Dcl)) |
| |
|
| | |
| | |
| | |
| | typecheck.Target.Funcs = typecheck.Target.Funcs[:topdcls] |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | var needWrapperTypes []*types.Type |
| |
|
| | |
| | |
| | var haveWrapperTypes []*types.Type |
| |
|
| | |
| | |
| | var needMethodValueWrappers []methodValueWrapper |
| |
|
| | |
| | |
| | |
| | var haveMethodValueWrappers []methodValueWrapper |
| |
|
| | type methodValueWrapper struct { |
| | rcvr *types.Type |
| | method *types.Field |
| | } |
| |
|
| | |
| | |
| | func (r *reader) needWrapper(typ *types.Type) { |
| | if typ.IsPtr() { |
| | return |
| | } |
| |
|
| | |
| | forceNeed := typ == types.ErrorType && base.Ctxt.Pkgpath == "runtime" |
| |
|
| | |
| | |
| | |
| | if r.importedDef() && !forceNeed { |
| | haveWrapperTypes = append(haveWrapperTypes, typ) |
| | } else { |
| | needWrapperTypes = append(needWrapperTypes, typ) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | func (r *reader) importedDef() bool { |
| | return r.p != localPkgReader && !r.hasTypeParams() |
| | } |
| |
|
| | |
| | |
| | func MakeWrappers(target *ir.Package) { |
| | |
| | needWrapperTypes = append(needWrapperTypes, types.ErrorType) |
| |
|
| | seen := make(map[string]*types.Type) |
| |
|
| | for _, typ := range haveWrapperTypes { |
| | wrapType(typ, target, seen, false) |
| | } |
| | haveWrapperTypes = nil |
| |
|
| | for _, typ := range needWrapperTypes { |
| | wrapType(typ, target, seen, true) |
| | } |
| | needWrapperTypes = nil |
| |
|
| | for _, wrapper := range haveMethodValueWrappers { |
| | wrapMethodValue(wrapper.rcvr, wrapper.method, target, false) |
| | } |
| | haveMethodValueWrappers = nil |
| |
|
| | for _, wrapper := range needMethodValueWrappers { |
| | wrapMethodValue(wrapper.rcvr, wrapper.method, target, true) |
| | } |
| | needMethodValueWrappers = nil |
| | } |
| |
|
| | func wrapType(typ *types.Type, target *ir.Package, seen map[string]*types.Type, needed bool) { |
| | key := typ.LinkString() |
| | if prev := seen[key]; prev != nil { |
| | if !types.Identical(typ, prev) { |
| | base.Fatalf("collision: types %v and %v have link string %q", typ, prev, key) |
| | } |
| | return |
| | } |
| | seen[key] = typ |
| |
|
| | if !needed { |
| | |
| | return |
| | } |
| |
|
| | if !typ.IsInterface() { |
| | typecheck.CalcMethods(typ) |
| | } |
| | for _, meth := range typ.AllMethods() { |
| | if meth.Sym.IsBlank() || !meth.IsMethod() { |
| | base.FatalfAt(meth.Pos, "invalid method: %v", meth) |
| | } |
| |
|
| | methodWrapper(0, typ, meth, target) |
| |
|
| | |
| | if !typ.IsInterface() { |
| | methodWrapper(1, typ, meth, target) |
| |
|
| | |
| | |
| | if typ.NotInHeap() { |
| | methodWrapper(2, typ, meth, target) |
| | } |
| | } |
| | } |
| | } |
| |
|
| | func methodWrapper(derefs int, tbase *types.Type, method *types.Field, target *ir.Package) { |
| | wrapper := tbase |
| | for i := 0; i < derefs; i++ { |
| | wrapper = types.NewPtr(wrapper) |
| | } |
| |
|
| | sym := ir.MethodSym(wrapper, method.Sym) |
| | base.Assertf(!sym.Siggen(), "already generated wrapper %v", sym) |
| | sym.SetSiggen(true) |
| |
|
| | wrappee := method.Type.Recv().Type |
| | if types.Identical(wrapper, wrappee) || |
| | !types.IsMethodApplicable(wrapper, method) || |
| | !reflectdata.NeedEmit(tbase) { |
| | return |
| | } |
| |
|
| | |
| | pos := base.AutogeneratedPos |
| |
|
| | fn := newWrapperFunc(pos, sym, wrapper, method) |
| |
|
| | var recv ir.Node = fn.Nname.Type().Recv().Nname.(*ir.Name) |
| |
|
| | |
| | |
| | if wrapper.IsPtr() && types.Identical(wrapper.Elem(), wrappee) { |
| | cond := ir.NewBinaryExpr(pos, ir.OEQ, recv, types.BuiltinPkg.Lookup("nil").Def.(ir.Node)) |
| | then := []ir.Node{ir.NewCallExpr(pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)} |
| | fn.Body.Append(ir.NewIfStmt(pos, cond, then, nil)) |
| | } |
| |
|
| | |
| | |
| | for i := 1; i < derefs; i++ { |
| | recv = Implicit(ir.NewStarExpr(pos, recv)) |
| | } |
| |
|
| | addTailCall(pos, fn, recv, method) |
| |
|
| | finishWrapperFunc(fn, target) |
| | } |
| |
|
| | func wrapMethodValue(recvType *types.Type, method *types.Field, target *ir.Package, needed bool) { |
| | sym := ir.MethodSymSuffix(recvType, method.Sym, "-fm") |
| | if sym.Uniq() { |
| | return |
| | } |
| | sym.SetUniq(true) |
| |
|
| | |
| | pos := base.AutogeneratedPos |
| |
|
| | fn := newWrapperFunc(pos, sym, nil, method) |
| | sym.Def = fn.Nname |
| |
|
| | |
| | recv := ir.NewHiddenParam(pos, fn, typecheck.Lookup(".this"), recvType) |
| |
|
| | if !needed { |
| | return |
| | } |
| |
|
| | addTailCall(pos, fn, recv, method) |
| |
|
| | finishWrapperFunc(fn, target) |
| | } |
| |
|
| | func newWrapperFunc(pos src.XPos, sym *types.Sym, wrapper *types.Type, method *types.Field) *ir.Func { |
| | sig := newWrapperType(wrapper, method) |
| | fn := ir.NewFunc(pos, pos, sym, sig) |
| | fn.DeclareParams(true) |
| | fn.SetDupok(true) |
| |
|
| | return fn |
| | } |
| |
|
| | func finishWrapperFunc(fn *ir.Func, target *ir.Package) { |
| | ir.WithFunc(fn, func() { |
| | typecheck.Stmts(fn.Body) |
| | }) |
| |
|
| | |
| | |
| | |
| | interleaved.DevirtualizeAndInlineFunc(fn, nil) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ir.VisitFuncAndClosures(fn, func(n ir.Node) { |
| | if n, ok := n.(*ir.SelectorExpr); ok && n.Op() == ir.OMETHVALUE { |
| | wrapMethodValue(n.X.Type(), n.Selection, target, true) |
| | } |
| | }) |
| |
|
| | fn.Nname.Defn = fn |
| | target.Funcs = append(target.Funcs, fn) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func newWrapperType(recvType *types.Type, method *types.Field) *types.Type { |
| | clone := func(params []*types.Field) []*types.Field { |
| | res := make([]*types.Field, len(params)) |
| | for i, param := range params { |
| | res[i] = types.NewField(param.Pos, param.Sym, param.Type) |
| | res[i].SetIsDDD(param.IsDDD()) |
| | } |
| | return res |
| | } |
| |
|
| | sig := method.Type |
| |
|
| | var recv *types.Field |
| | if recvType != nil { |
| | recv = types.NewField(sig.Recv().Pos, sig.Recv().Sym, recvType) |
| | } |
| | params := clone(sig.Params()) |
| | results := clone(sig.Results()) |
| |
|
| | return types.NewSignature(recv, params, results) |
| | } |
| |
|
| | func addTailCall(pos src.XPos, fn *ir.Func, recv ir.Node, method *types.Field) { |
| | sig := fn.Nname.Type() |
| | args := make([]ir.Node, sig.NumParams()) |
| | for i, param := range sig.Params() { |
| | args[i] = param.Nname.(*ir.Name) |
| | } |
| |
|
| | dot := typecheck.XDotMethod(pos, recv, method.Sym, true) |
| | call := typecheck.Call(pos, dot, args, method.Type.IsVariadic()).(*ir.CallExpr) |
| |
|
| | if recv.Type() != nil && recv.Type().IsPtr() && method.Type.Recv().Type.IsPtr() && |
| | method.Embedded != 0 && !types.IsInterfaceMethod(method.Type) && |
| | !unifiedHaveInlineBody(ir.MethodExprName(dot).Func) && |
| | !(base.Ctxt.Arch.Name == "ppc64le" && base.Ctxt.Flag_dynlink) { |
| | if base.Debug.TailCall != 0 { |
| | base.WarnfAt(fn.Nname.Type().Recv().Type.Elem().Pos(), "tail call emitted for the method %v wrapper", method.Nname) |
| | } |
| | |
| | fn.Body.Append(ir.NewTailCallStmt(pos, call)) |
| | return |
| | } |
| |
|
| | fn.SetWrapper(true) |
| |
|
| | if method.Type.NumResults() == 0 { |
| | fn.Body.Append(call) |
| | return |
| | } |
| |
|
| | ret := ir.NewReturnStmt(pos, nil) |
| | ret.Results = []ir.Node{call} |
| | fn.Body.Append(ret) |
| | } |
| |
|
| | func setBasePos(pos src.XPos) { |
| | |
| | base.Pos = pos |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | const dictParamName = typecheck.LocalDictName |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func shapeSig(fn *ir.Func, dict *readerDict) *types.Type { |
| | sig := fn.Nname.Type() |
| | oldRecv := sig.Recv() |
| |
|
| | var recv *types.Field |
| | if oldRecv != nil { |
| | recv = types.NewField(oldRecv.Pos, oldRecv.Sym, oldRecv.Type) |
| | } |
| |
|
| | params := make([]*types.Field, 1+sig.NumParams()) |
| | params[0] = types.NewField(fn.Pos(), fn.Sym().Pkg.Lookup(dictParamName), types.NewPtr(dict.varType())) |
| | for i, param := range sig.Params() { |
| | d := types.NewField(param.Pos, param.Sym, param.Type) |
| | d.SetIsDDD(param.IsDDD()) |
| | params[1+i] = d |
| | } |
| |
|
| | results := make([]*types.Field, sig.NumResults()) |
| | for i, result := range sig.Results() { |
| | results[i] = types.NewField(result.Pos, result.Sym, result.Type) |
| | } |
| |
|
| | return types.NewSignature(recv, params, results) |
| | } |
| |
|