| | |
| | |
| | |
| |
|
| | package noder |
| |
|
| | import ( |
| | "fmt" |
| | "go/constant" |
| | "go/token" |
| | "go/version" |
| | "internal/buildcfg" |
| | "internal/pkgbits" |
| | "os" |
| | "strings" |
| |
|
| | "cmd/compile/internal/base" |
| | "cmd/compile/internal/ir" |
| | "cmd/compile/internal/syntax" |
| | "cmd/compile/internal/types" |
| | "cmd/compile/internal/types2" |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| |
|
| | type index = pkgbits.Index |
| |
|
| | func assert(p bool) { base.Assert(p) } |
| |
|
| | |
| | |
| | type pkgWriter struct { |
| | pkgbits.PkgEncoder |
| |
|
| | m posMap |
| | curpkg *types2.Package |
| | info *types2.Info |
| | rangeFuncBodyClosures map[*syntax.FuncLit]bool |
| |
|
| | |
| |
|
| | posBasesIdx map[*syntax.PosBase]index |
| | pkgsIdx map[*types2.Package]index |
| | typsIdx map[types2.Type]index |
| | objsIdx map[types2.Object]index |
| |
|
| | |
| |
|
| | funDecls map[*types2.Func]*syntax.FuncDecl |
| | typDecls map[*types2.TypeName]typeDeclGen |
| |
|
| | |
| | |
| | linknames map[types2.Object]string |
| |
|
| | |
| | |
| | cgoPragmas [][]string |
| | } |
| |
|
| | |
| | |
| | func newPkgWriter(m posMap, pkg *types2.Package, info *types2.Info, otherInfo map[*syntax.FuncLit]bool) *pkgWriter { |
| | |
| | version := pkgbits.V2 |
| | return &pkgWriter{ |
| | PkgEncoder: pkgbits.NewPkgEncoder(version, base.Debug.SyncFrames), |
| |
|
| | m: m, |
| | curpkg: pkg, |
| | info: info, |
| | rangeFuncBodyClosures: otherInfo, |
| |
|
| | pkgsIdx: make(map[*types2.Package]index), |
| | objsIdx: make(map[types2.Object]index), |
| | typsIdx: make(map[types2.Type]index), |
| |
|
| | posBasesIdx: make(map[*syntax.PosBase]index), |
| |
|
| | funDecls: make(map[*types2.Func]*syntax.FuncDecl), |
| | typDecls: make(map[*types2.TypeName]typeDeclGen), |
| |
|
| | linknames: make(map[types2.Object]string), |
| | } |
| | } |
| |
|
| | |
| | func (pw *pkgWriter) errorf(p poser, msg string, args ...any) { |
| | base.ErrorfAt(pw.m.pos(p), 0, msg, args...) |
| | } |
| |
|
| | |
| | func (pw *pkgWriter) fatalf(p poser, msg string, args ...any) { |
| | base.FatalfAt(pw.m.pos(p), msg, args...) |
| | } |
| |
|
| | |
| | |
| | func (pw *pkgWriter) unexpected(what string, p poser) { |
| | pw.fatalf(p, "unexpected %s: %v (%T)", what, p, p) |
| | } |
| |
|
| | func (pw *pkgWriter) typeAndValue(x syntax.Expr) syntax.TypeAndValue { |
| | tv, ok := pw.maybeTypeAndValue(x) |
| | if !ok { |
| | pw.fatalf(x, "missing Types entry: %v", syntax.String(x)) |
| | } |
| | return tv |
| | } |
| |
|
| | func (pw *pkgWriter) maybeTypeAndValue(x syntax.Expr) (syntax.TypeAndValue, bool) { |
| | tv := x.GetTypeInfo() |
| |
|
| | |
| | |
| | |
| | if name, ok := x.(*syntax.Name); ok { |
| | if inst, ok := pw.info.Instances[name]; ok { |
| | tv.Type = inst.Type |
| | } |
| | } |
| |
|
| | return tv, tv.Type != nil |
| | } |
| |
|
| | |
| | func (pw *pkgWriter) typeOf(expr syntax.Expr) types2.Type { |
| | tv := pw.typeAndValue(expr) |
| | if !tv.IsValue() { |
| | pw.fatalf(expr, "expected value: %v", syntax.String(expr)) |
| | } |
| | return tv.Type |
| | } |
| |
|
| | |
| | type writer struct { |
| | p *pkgWriter |
| |
|
| | *pkgbits.Encoder |
| |
|
| | |
| | sig *types2.Signature |
| |
|
| | |
| | |
| | |
| |
|
| | |
| | |
| | localsIdx map[*types2.Var]int |
| |
|
| | |
| | |
| | closureVars []posVar |
| | closureVarsIdx map[*types2.Var]int |
| |
|
| | dict *writerDict |
| |
|
| | |
| | |
| | derived bool |
| | } |
| |
|
| | |
| | type writerDict struct { |
| | |
| | |
| | implicits []*types2.TypeParam |
| |
|
| | |
| | |
| | derived []derivedInfo |
| |
|
| | |
| | |
| | derivedIdx map[types2.Type]index |
| |
|
| | |
| | typeParamMethodExprs []writerMethodExprInfo |
| | subdicts []objInfo |
| | rtypes []typeInfo |
| | itabs []itabInfo |
| | } |
| |
|
| | type itabInfo struct { |
| | typ typeInfo |
| | iface typeInfo |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (dict *writerDict) typeParamIndex(typ *types2.TypeParam) int { |
| | for idx, implicit := range dict.implicits { |
| | if implicit == typ { |
| | return idx |
| | } |
| | } |
| |
|
| | return len(dict.implicits) + typ.Index() |
| | } |
| |
|
| | |
| | type derivedInfo struct { |
| | idx index |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type typeInfo struct { |
| | idx index |
| | derived bool |
| | } |
| |
|
| | |
| | |
| | type objInfo struct { |
| | idx index |
| | explicits []typeInfo |
| | } |
| |
|
| | |
| | |
| | |
| | type selectorInfo struct { |
| | pkgIdx index |
| | nameIdx index |
| | } |
| |
|
| | |
| | |
| | func (info objInfo) anyDerived() bool { |
| | for _, explicit := range info.explicits { |
| | if explicit.derived { |
| | return true |
| | } |
| | } |
| | return false |
| | } |
| |
|
| | |
| | |
| | func (info objInfo) equals(other objInfo) bool { |
| | if info.idx != other.idx { |
| | return false |
| | } |
| | assert(len(info.explicits) == len(other.explicits)) |
| | for i, targ := range info.explicits { |
| | if targ != other.explicits[i] { |
| | return false |
| | } |
| | } |
| | return true |
| | } |
| |
|
| | type writerMethodExprInfo struct { |
| | typeParamIdx int |
| | methodInfo selectorInfo |
| | } |
| |
|
| | |
| | |
| | |
| | func (dict *writerDict) typeParamMethodExprIdx(typeParamIdx int, methodInfo selectorInfo) int { |
| | newInfo := writerMethodExprInfo{typeParamIdx, methodInfo} |
| |
|
| | for idx, oldInfo := range dict.typeParamMethodExprs { |
| | if oldInfo == newInfo { |
| | return idx |
| | } |
| | } |
| |
|
| | idx := len(dict.typeParamMethodExprs) |
| | dict.typeParamMethodExprs = append(dict.typeParamMethodExprs, newInfo) |
| | return idx |
| | } |
| |
|
| | |
| | |
| | |
| | func (dict *writerDict) subdictIdx(newInfo objInfo) int { |
| | for idx, oldInfo := range dict.subdicts { |
| | if oldInfo.equals(newInfo) { |
| | return idx |
| | } |
| | } |
| |
|
| | idx := len(dict.subdicts) |
| | dict.subdicts = append(dict.subdicts, newInfo) |
| | return idx |
| | } |
| |
|
| | |
| | |
| | |
| | func (dict *writerDict) rtypeIdx(newInfo typeInfo) int { |
| | for idx, oldInfo := range dict.rtypes { |
| | if oldInfo == newInfo { |
| | return idx |
| | } |
| | } |
| |
|
| | idx := len(dict.rtypes) |
| | dict.rtypes = append(dict.rtypes, newInfo) |
| | return idx |
| | } |
| |
|
| | |
| | |
| | |
| | func (dict *writerDict) itabIdx(typInfo, ifaceInfo typeInfo) int { |
| | newInfo := itabInfo{typInfo, ifaceInfo} |
| |
|
| | for idx, oldInfo := range dict.itabs { |
| | if oldInfo == newInfo { |
| | return idx |
| | } |
| | } |
| |
|
| | idx := len(dict.itabs) |
| | dict.itabs = append(dict.itabs, newInfo) |
| | return idx |
| | } |
| |
|
| | func (pw *pkgWriter) newWriter(k pkgbits.SectionKind, marker pkgbits.SyncMarker) *writer { |
| | return &writer{ |
| | Encoder: pw.NewEncoder(k, marker), |
| | p: pw, |
| | } |
| | } |
| |
|
| | |
| |
|
| | |
| | func (w *writer) pos(p poser) { |
| | w.Sync(pkgbits.SyncPos) |
| | pos := p.Pos() |
| |
|
| | |
| | if !w.Bool(pos.IsKnown()) { |
| | return |
| | } |
| |
|
| | |
| | w.posBase(pos.Base()) |
| | w.Uint(pos.Line()) |
| | w.Uint(pos.Col()) |
| | } |
| |
|
| | |
| | |
| | func (w *writer) posBase(b *syntax.PosBase) { |
| | w.Reloc(pkgbits.SectionPosBase, w.p.posBaseIdx(b)) |
| | } |
| |
|
| | |
| | func (pw *pkgWriter) posBaseIdx(b *syntax.PosBase) index { |
| | if idx, ok := pw.posBasesIdx[b]; ok { |
| | return idx |
| | } |
| |
|
| | w := pw.newWriter(pkgbits.SectionPosBase, pkgbits.SyncPosBase) |
| | w.p.posBasesIdx[b] = w.Idx |
| |
|
| | w.String(trimFilename(b)) |
| |
|
| | if !w.Bool(b.IsFileBase()) { |
| | w.pos(b) |
| | w.Uint(b.Line()) |
| | w.Uint(b.Col()) |
| | } |
| |
|
| | return w.Flush() |
| | } |
| |
|
| | |
| |
|
| | |
| | func (w *writer) pkg(pkg *types2.Package) { |
| | w.pkgRef(w.p.pkgIdx(pkg)) |
| | } |
| |
|
| | func (w *writer) pkgRef(idx index) { |
| | w.Sync(pkgbits.SyncPkg) |
| | w.Reloc(pkgbits.SectionPkg, idx) |
| | } |
| |
|
| | |
| | |
| | func (pw *pkgWriter) pkgIdx(pkg *types2.Package) index { |
| | if idx, ok := pw.pkgsIdx[pkg]; ok { |
| | return idx |
| | } |
| |
|
| | w := pw.newWriter(pkgbits.SectionPkg, pkgbits.SyncPkgDef) |
| | pw.pkgsIdx[pkg] = w.Idx |
| |
|
| | |
| | |
| | |
| | |
| | switch pkg { |
| | case nil: |
| | w.String("builtin") |
| | case types2.Unsafe: |
| | w.String("unsafe") |
| | default: |
| | |
| | var path string |
| | if pkg != w.p.curpkg { |
| | path = pkg.Path() |
| | } |
| | base.Assertf(path != "builtin" && path != "unsafe", "unexpected path for user-defined package: %q", path) |
| | w.String(path) |
| | w.String(pkg.Name()) |
| |
|
| | w.Len(len(pkg.Imports())) |
| | for _, imp := range pkg.Imports() { |
| | w.pkg(imp) |
| | } |
| | } |
| |
|
| | return w.Flush() |
| | } |
| |
|
| | |
| |
|
| | var ( |
| | anyTypeName = types2.Universe.Lookup("any").(*types2.TypeName) |
| | comparableTypeName = types2.Universe.Lookup("comparable").(*types2.TypeName) |
| | runeTypeName = types2.Universe.Lookup("rune").(*types2.TypeName) |
| | ) |
| |
|
| | |
| | func (w *writer) typ(typ types2.Type) { |
| | w.typInfo(w.p.typIdx(typ, w.dict)) |
| | } |
| |
|
| | |
| | |
| | func (w *writer) typInfo(info typeInfo) { |
| | w.Sync(pkgbits.SyncType) |
| | if w.Bool(info.derived) { |
| | w.Len(int(info.idx)) |
| | w.derived = true |
| | } else { |
| | w.Reloc(pkgbits.SectionType, info.idx) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo { |
| | |
| | |
| | |
| | |
| | for { |
| | if alias, ok := typ.(*types2.Alias); ok && !isGlobal(alias.Obj()) { |
| | typ = alias.Rhs() |
| | } else { |
| | break |
| | } |
| | } |
| |
|
| | if idx, ok := pw.typsIdx[typ]; ok { |
| | return typeInfo{idx: idx, derived: false} |
| | } |
| | if dict != nil { |
| | if idx, ok := dict.derivedIdx[typ]; ok { |
| | return typeInfo{idx: idx, derived: true} |
| | } |
| | } |
| |
|
| | w := pw.newWriter(pkgbits.SectionType, pkgbits.SyncTypeIdx) |
| | w.dict = dict |
| |
|
| | switch typ := typ.(type) { |
| | default: |
| | base.Fatalf("unexpected type: %v (%T)", typ, typ) |
| |
|
| | case *types2.Basic: |
| | switch kind := typ.Kind(); { |
| | case kind == types2.Invalid: |
| | base.Fatalf("unexpected types2.Invalid") |
| |
|
| | case types2.Typ[kind] == typ: |
| | w.Code(pkgbits.TypeBasic) |
| | w.Len(int(kind)) |
| |
|
| | default: |
| | |
| | obj := types2.Universe.Lookup(typ.Name()).(*types2.TypeName) |
| | assert(obj.Type() == typ) |
| |
|
| | w.Code(pkgbits.TypeNamed) |
| | w.namedType(obj, nil) |
| | } |
| |
|
| | case *types2.Named: |
| | w.Code(pkgbits.TypeNamed) |
| | w.namedType(splitNamed(typ)) |
| |
|
| | case *types2.Alias: |
| | w.Code(pkgbits.TypeNamed) |
| | w.namedType(splitAlias(typ)) |
| |
|
| | case *types2.TypeParam: |
| | w.derived = true |
| | w.Code(pkgbits.TypeTypeParam) |
| | w.Len(w.dict.typeParamIndex(typ)) |
| |
|
| | case *types2.Array: |
| | w.Code(pkgbits.TypeArray) |
| | w.Uint64(uint64(typ.Len())) |
| | w.typ(typ.Elem()) |
| |
|
| | case *types2.Chan: |
| | w.Code(pkgbits.TypeChan) |
| | w.Len(int(typ.Dir())) |
| | w.typ(typ.Elem()) |
| |
|
| | case *types2.Map: |
| | w.Code(pkgbits.TypeMap) |
| | w.typ(typ.Key()) |
| | w.typ(typ.Elem()) |
| |
|
| | case *types2.Pointer: |
| | w.Code(pkgbits.TypePointer) |
| | w.typ(typ.Elem()) |
| |
|
| | case *types2.Signature: |
| | base.Assertf(typ.TypeParams() == nil, "unexpected type params: %v", typ) |
| | w.Code(pkgbits.TypeSignature) |
| | w.signature(typ) |
| |
|
| | case *types2.Slice: |
| | w.Code(pkgbits.TypeSlice) |
| | w.typ(typ.Elem()) |
| |
|
| | case *types2.Struct: |
| | w.Code(pkgbits.TypeStruct) |
| | w.structType(typ) |
| |
|
| | case *types2.Interface: |
| | |
| | |
| | |
| | |
| | if types2.Unalias(typ) == types2.Unalias(anyTypeName.Type()) { |
| | w.Code(pkgbits.TypeNamed) |
| | w.obj(anyTypeName, nil) |
| | break |
| | } |
| |
|
| | w.Code(pkgbits.TypeInterface) |
| | w.interfaceType(typ) |
| |
|
| | case *types2.Union: |
| | w.Code(pkgbits.TypeUnion) |
| | w.unionType(typ) |
| | } |
| |
|
| | if w.derived { |
| | idx := index(len(dict.derived)) |
| | dict.derived = append(dict.derived, derivedInfo{idx: w.Flush()}) |
| | dict.derivedIdx[typ] = idx |
| | return typeInfo{idx: idx, derived: true} |
| | } |
| |
|
| | pw.typsIdx[typ] = w.Idx |
| | return typeInfo{idx: w.Flush(), derived: false} |
| | } |
| |
|
| | |
| | func (w *writer) namedType(obj *types2.TypeName, targs *types2.TypeList) { |
| | |
| | |
| | if w.p.hasImplicitTypeParams(obj) { |
| | w.derived = true |
| | } |
| |
|
| | w.obj(obj, targs) |
| | } |
| |
|
| | func (w *writer) structType(typ *types2.Struct) { |
| | w.Len(typ.NumFields()) |
| | for i := 0; i < typ.NumFields(); i++ { |
| | f := typ.Field(i) |
| | w.pos(f) |
| | w.selector(f) |
| | w.typ(f.Type()) |
| | w.String(typ.Tag(i)) |
| | w.Bool(f.Embedded()) |
| | } |
| | } |
| |
|
| | func (w *writer) unionType(typ *types2.Union) { |
| | w.Len(typ.Len()) |
| | for i := 0; i < typ.Len(); i++ { |
| | t := typ.Term(i) |
| | w.Bool(t.Tilde()) |
| | w.typ(t.Type()) |
| | } |
| | } |
| |
|
| | func (w *writer) interfaceType(typ *types2.Interface) { |
| | |
| | |
| | |
| | if typ.NumEmbeddeds() == 0 && !typ.IsMethodSet() { |
| | |
| | |
| | |
| | assert(typ == comparableTypeName.Type().(*types2.Named).Underlying()) |
| |
|
| | |
| | w.Len(0) |
| | w.Len(1) |
| | w.Bool(false) |
| | w.typ(comparableTypeName.Type()) |
| | return |
| | } |
| |
|
| | w.Len(typ.NumExplicitMethods()) |
| | w.Len(typ.NumEmbeddeds()) |
| |
|
| | if typ.NumExplicitMethods() == 0 && typ.NumEmbeddeds() == 1 { |
| | w.Bool(typ.IsImplicit()) |
| | } else { |
| | |
| | |
| | |
| | assert(!typ.IsImplicit()) |
| | } |
| |
|
| | for i := 0; i < typ.NumExplicitMethods(); i++ { |
| | m := typ.ExplicitMethod(i) |
| | sig := m.Type().(*types2.Signature) |
| | assert(sig.TypeParams() == nil) |
| |
|
| | w.pos(m) |
| | w.selector(m) |
| | w.signature(sig) |
| | } |
| |
|
| | for i := 0; i < typ.NumEmbeddeds(); i++ { |
| | w.typ(typ.EmbeddedType(i)) |
| | } |
| | } |
| |
|
| | func (w *writer) signature(sig *types2.Signature) { |
| | w.Sync(pkgbits.SyncSignature) |
| | w.params(sig.Params()) |
| | w.params(sig.Results()) |
| | w.Bool(sig.Variadic()) |
| | } |
| |
|
| | func (w *writer) params(typ *types2.Tuple) { |
| | w.Sync(pkgbits.SyncParams) |
| | w.Len(typ.Len()) |
| | for i := 0; i < typ.Len(); i++ { |
| | w.param(typ.At(i)) |
| | } |
| | } |
| |
|
| | func (w *writer) param(param *types2.Var) { |
| | w.Sync(pkgbits.SyncParam) |
| | w.pos(param) |
| | w.localIdent(param) |
| | w.typ(param.Type()) |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | func (w *writer) obj(obj types2.Object, explicits *types2.TypeList) { |
| | w.objInfo(w.p.objInstIdx(obj, explicits, w.dict)) |
| | } |
| |
|
| | |
| | |
| | func (w *writer) objInfo(info objInfo) { |
| | w.Sync(pkgbits.SyncObject) |
| | if w.Version().Has(pkgbits.DerivedFuncInstance) { |
| | w.Bool(false) |
| | } |
| | w.Reloc(pkgbits.SectionObj, info.idx) |
| |
|
| | w.Len(len(info.explicits)) |
| | for _, info := range info.explicits { |
| | w.typInfo(info) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func (pw *pkgWriter) objInstIdx(obj types2.Object, explicits *types2.TypeList, dict *writerDict) objInfo { |
| | explicitInfos := make([]typeInfo, explicits.Len()) |
| | for i := range explicitInfos { |
| | explicitInfos[i] = pw.typIdx(explicits.At(i), dict) |
| | } |
| | return objInfo{idx: pw.objIdx(obj), explicits: explicitInfos} |
| | } |
| |
|
| | |
| | |
| | func (pw *pkgWriter) objIdx(obj types2.Object) index { |
| | |
| | |
| |
|
| | if idx, ok := pw.objsIdx[obj]; ok { |
| | return idx |
| | } |
| |
|
| | dict := &writerDict{ |
| | derivedIdx: make(map[types2.Type]index), |
| | } |
| |
|
| | if isDefinedType(obj) && obj.Pkg() == pw.curpkg { |
| | decl, ok := pw.typDecls[obj.(*types2.TypeName)] |
| | assert(ok) |
| | dict.implicits = decl.implicits |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | w := pw.newWriter(pkgbits.SectionObj, pkgbits.SyncObject1) |
| | wext := pw.newWriter(pkgbits.SectionObjExt, pkgbits.SyncObject1) |
| | wname := pw.newWriter(pkgbits.SectionName, pkgbits.SyncObject1) |
| | wdict := pw.newWriter(pkgbits.SectionObjDict, pkgbits.SyncObject1) |
| |
|
| | pw.objsIdx[obj] = w.Idx |
| | assert(wext.Idx == w.Idx) |
| | assert(wname.Idx == w.Idx) |
| | assert(wdict.Idx == w.Idx) |
| |
|
| | w.dict = dict |
| | wext.dict = dict |
| |
|
| | code := w.doObj(wext, obj) |
| | w.Flush() |
| | wext.Flush() |
| |
|
| | wname.qualifiedIdent(obj) |
| | wname.Code(code) |
| | wname.Flush() |
| |
|
| | wdict.objDict(obj, w.dict) |
| | wdict.Flush() |
| |
|
| | return w.Idx |
| | } |
| |
|
| | |
| | |
| | func (w *writer) doObj(wext *writer, obj types2.Object) pkgbits.CodeObj { |
| | if obj.Pkg() != w.p.curpkg { |
| | return pkgbits.ObjStub |
| | } |
| |
|
| | switch obj := obj.(type) { |
| | default: |
| | w.p.unexpected("object", obj) |
| | panic("unreachable") |
| |
|
| | case *types2.Const: |
| | w.pos(obj) |
| | w.typ(obj.Type()) |
| | w.Value(obj.Val()) |
| | return pkgbits.ObjConst |
| |
|
| | case *types2.Func: |
| | decl, ok := w.p.funDecls[obj] |
| | assert(ok) |
| | sig := obj.Type().(*types2.Signature) |
| |
|
| | w.pos(obj) |
| | w.typeParamNames(sig.TypeParams()) |
| | w.signature(sig) |
| | w.pos(decl) |
| | wext.funcExt(obj) |
| | return pkgbits.ObjFunc |
| |
|
| | case *types2.TypeName: |
| | if obj.IsAlias() { |
| | w.pos(obj) |
| | rhs := obj.Type() |
| | var tparams *types2.TypeParamList |
| | if alias, ok := rhs.(*types2.Alias); ok { |
| | assert(alias.TypeArgs() == nil) |
| | tparams = alias.TypeParams() |
| | rhs = alias.Rhs() |
| | } |
| | if w.Version().Has(pkgbits.AliasTypeParamNames) { |
| | w.typeParamNames(tparams) |
| | } |
| | assert(w.Version().Has(pkgbits.AliasTypeParamNames) || tparams.Len() == 0) |
| | w.typ(rhs) |
| | return pkgbits.ObjAlias |
| | } |
| |
|
| | named := obj.Type().(*types2.Named) |
| | assert(named.TypeArgs() == nil) |
| |
|
| | w.pos(obj) |
| | w.typeParamNames(named.TypeParams()) |
| | wext.typeExt(obj) |
| | w.typ(named.Underlying()) |
| |
|
| | w.Len(named.NumMethods()) |
| | for i := 0; i < named.NumMethods(); i++ { |
| | w.method(wext, named.Method(i)) |
| | } |
| |
|
| | return pkgbits.ObjType |
| |
|
| | case *types2.Var: |
| | w.pos(obj) |
| | w.typ(obj.Type()) |
| | wext.varExt(obj) |
| | return pkgbits.ObjVar |
| | } |
| | } |
| |
|
| | |
| | func (w *writer) objDict(obj types2.Object, dict *writerDict) { |
| | |
| | |
| | |
| |
|
| | w.dict = dict |
| |
|
| | w.Len(len(dict.implicits)) |
| |
|
| | tparams := objTypeParams(obj) |
| | ntparams := tparams.Len() |
| | w.Len(ntparams) |
| | for i := 0; i < ntparams; i++ { |
| | w.typ(tparams.At(i).Constraint()) |
| | } |
| |
|
| | nderived := len(dict.derived) |
| | w.Len(nderived) |
| | for _, typ := range dict.derived { |
| | w.Reloc(pkgbits.SectionType, typ.idx) |
| | if w.Version().Has(pkgbits.DerivedInfoNeeded) { |
| | w.Bool(false) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | for _, implicit := range dict.implicits { |
| | w.Bool(implicit.Underlying().(*types2.Interface).IsMethodSet()) |
| | } |
| | for i := 0; i < ntparams; i++ { |
| | tparam := tparams.At(i) |
| | w.Bool(tparam.Underlying().(*types2.Interface).IsMethodSet()) |
| | } |
| |
|
| | w.Len(len(dict.typeParamMethodExprs)) |
| | for _, info := range dict.typeParamMethodExprs { |
| | w.Len(info.typeParamIdx) |
| | w.selectorInfo(info.methodInfo) |
| | } |
| |
|
| | w.Len(len(dict.subdicts)) |
| | for _, info := range dict.subdicts { |
| | w.objInfo(info) |
| | } |
| |
|
| | w.Len(len(dict.rtypes)) |
| | for _, info := range dict.rtypes { |
| | w.typInfo(info) |
| | } |
| |
|
| | w.Len(len(dict.itabs)) |
| | for _, info := range dict.itabs { |
| | w.typInfo(info.typ) |
| | w.typInfo(info.iface) |
| | } |
| |
|
| | assert(len(dict.derived) == nderived) |
| | } |
| |
|
| | func (w *writer) typeParamNames(tparams *types2.TypeParamList) { |
| | w.Sync(pkgbits.SyncTypeParamNames) |
| |
|
| | ntparams := tparams.Len() |
| | for i := 0; i < ntparams; i++ { |
| | tparam := tparams.At(i).Obj() |
| | w.pos(tparam) |
| | w.localIdent(tparam) |
| | } |
| | } |
| |
|
| | func (w *writer) method(wext *writer, meth *types2.Func) { |
| | decl, ok := w.p.funDecls[meth] |
| | assert(ok) |
| | sig := meth.Type().(*types2.Signature) |
| |
|
| | w.Sync(pkgbits.SyncMethod) |
| | w.pos(meth) |
| | w.selector(meth) |
| | w.typeParamNames(sig.RecvTypeParams()) |
| | w.param(sig.Recv()) |
| | w.signature(sig) |
| |
|
| | w.pos(decl) |
| | wext.funcExt(meth) |
| | } |
| |
|
| | |
| | |
| | func (w *writer) qualifiedIdent(obj types2.Object) { |
| | w.Sync(pkgbits.SyncSym) |
| |
|
| | name := obj.Name() |
| | if isDefinedType(obj) && obj.Pkg() == w.p.curpkg { |
| | decl, ok := w.p.typDecls[obj.(*types2.TypeName)] |
| | assert(ok) |
| | if decl.gen != 0 { |
| | |
| | |
| | |
| | |
| | |
| | name = fmt.Sprintf("%s·%v", name, decl.gen) |
| | } |
| | } |
| |
|
| | w.pkg(obj.Pkg()) |
| | w.String(name) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| |
|
| | |
| | |
| | |
| | func (w *writer) localIdent(obj types2.Object) { |
| | assert(!isGlobal(obj)) |
| | w.Sync(pkgbits.SyncLocalIdent) |
| | w.pkg(obj.Pkg()) |
| | w.String(obj.Name()) |
| | } |
| |
|
| | |
| | |
| | func (w *writer) selector(obj types2.Object) { |
| | w.selectorInfo(w.p.selectorIdx(obj)) |
| | } |
| |
|
| | func (w *writer) selectorInfo(info selectorInfo) { |
| | w.Sync(pkgbits.SyncSelector) |
| | w.pkgRef(info.pkgIdx) |
| | w.StringRef(info.nameIdx) |
| | } |
| |
|
| | func (pw *pkgWriter) selectorIdx(obj types2.Object) selectorInfo { |
| | pkgIdx := pw.pkgIdx(obj.Pkg()) |
| | nameIdx := pw.StringIdx(obj.Name()) |
| | return selectorInfo{pkgIdx: pkgIdx, nameIdx: nameIdx} |
| | } |
| |
|
| | |
| |
|
| | func (w *writer) funcExt(obj *types2.Func) { |
| | decl, ok := w.p.funDecls[obj] |
| | assert(ok) |
| |
|
| | |
| | |
| | |
| |
|
| | pragma := asPragmaFlag(decl.Pragma) |
| | if pragma&ir.Systemstack != 0 && pragma&ir.Nosplit != 0 { |
| | w.p.errorf(decl, "go:nosplit and go:systemstack cannot be combined") |
| | } |
| | wi := asWasmImport(decl.Pragma) |
| | we := asWasmExport(decl.Pragma) |
| |
|
| | if decl.Body != nil { |
| | if pragma&ir.Noescape != 0 { |
| | w.p.errorf(decl, "can only use //go:noescape with external func implementations") |
| | } |
| | if wi != nil { |
| | w.p.errorf(decl, "can only use //go:wasmimport with external func implementations") |
| | } |
| | if (pragma&ir.UintptrKeepAlive != 0 && pragma&ir.UintptrEscapes == 0) && pragma&ir.Nosplit == 0 { |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | w.p.errorf(decl, "go:uintptrkeepalive requires go:nosplit") |
| | } |
| | } else { |
| | if base.Flag.Complete || decl.Name.Value == "init" { |
| | |
| | |
| | |
| | if _, ok := w.p.linknames[obj]; !ok && wi == nil { |
| | w.p.errorf(decl, "missing function body") |
| | } |
| | } |
| | } |
| |
|
| | sig, block := obj.Type().(*types2.Signature), decl.Body |
| | body, closureVars := w.p.bodyIdx(sig, block, w.dict) |
| | if len(closureVars) > 0 { |
| | fmt.Fprintln(os.Stderr, "CLOSURE", closureVars) |
| | } |
| | assert(len(closureVars) == 0) |
| |
|
| | w.Sync(pkgbits.SyncFuncExt) |
| | w.pragmaFlag(pragma) |
| | w.linkname(obj) |
| |
|
| | if buildcfg.GOARCH == "wasm" { |
| | if wi != nil { |
| | w.String(wi.Module) |
| | w.String(wi.Name) |
| | } else { |
| | w.String("") |
| | w.String("") |
| | } |
| | if we != nil { |
| | w.String(we.Name) |
| | } else { |
| | w.String("") |
| | } |
| | } |
| |
|
| | w.Bool(false) |
| | w.Reloc(pkgbits.SectionBody, body) |
| | w.Sync(pkgbits.SyncEOF) |
| | } |
| |
|
| | func (w *writer) typeExt(obj *types2.TypeName) { |
| | decl, ok := w.p.typDecls[obj] |
| | assert(ok) |
| |
|
| | w.Sync(pkgbits.SyncTypeExt) |
| |
|
| | w.pragmaFlag(asPragmaFlag(decl.Pragma)) |
| |
|
| | |
| | w.Int64(-1) |
| | w.Int64(-1) |
| | } |
| |
|
| | func (w *writer) varExt(obj *types2.Var) { |
| | w.Sync(pkgbits.SyncVarExt) |
| | w.linkname(obj) |
| | } |
| |
|
| | func (w *writer) linkname(obj types2.Object) { |
| | w.Sync(pkgbits.SyncLinkname) |
| | w.Int64(-1) |
| | w.String(w.p.linknames[obj]) |
| | } |
| |
|
| | func (w *writer) pragmaFlag(p ir.PragmaFlag) { |
| | w.Sync(pkgbits.SyncPragma) |
| | w.Int(int(p)) |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | func (pw *pkgWriter) bodyIdx(sig *types2.Signature, block *syntax.BlockStmt, dict *writerDict) (idx index, closureVars []posVar) { |
| | w := pw.newWriter(pkgbits.SectionBody, pkgbits.SyncFuncBody) |
| | w.sig = sig |
| | w.dict = dict |
| |
|
| | w.declareParams(sig) |
| | if w.Bool(block != nil) { |
| | w.stmts(block.List) |
| | w.pos(block.Rbrace) |
| | } |
| |
|
| | return w.Flush(), w.closureVars |
| | } |
| |
|
| | func (w *writer) declareParams(sig *types2.Signature) { |
| | addLocals := func(params *types2.Tuple) { |
| | for i := 0; i < params.Len(); i++ { |
| | w.addLocal(params.At(i)) |
| | } |
| | } |
| |
|
| | if recv := sig.Recv(); recv != nil { |
| | w.addLocal(recv) |
| | } |
| | addLocals(sig.Params()) |
| | addLocals(sig.Results()) |
| | } |
| |
|
| | |
| | func (w *writer) addLocal(obj *types2.Var) { |
| | idx := len(w.localsIdx) |
| |
|
| | w.Sync(pkgbits.SyncAddLocal) |
| | if w.p.SyncMarkers() { |
| | w.Int(idx) |
| | } |
| | w.varDictIndex(obj) |
| |
|
| | if w.localsIdx == nil { |
| | w.localsIdx = make(map[*types2.Var]int) |
| | } |
| | w.localsIdx[obj] = idx |
| | } |
| |
|
| | |
| | |
| | func (w *writer) useLocal(pos syntax.Pos, obj *types2.Var) { |
| | w.Sync(pkgbits.SyncUseObjLocal) |
| |
|
| | if idx, ok := w.localsIdx[obj]; w.Bool(ok) { |
| | w.Len(idx) |
| | return |
| | } |
| |
|
| | idx, ok := w.closureVarsIdx[obj] |
| | if !ok { |
| | if w.closureVarsIdx == nil { |
| | w.closureVarsIdx = make(map[*types2.Var]int) |
| | } |
| | idx = len(w.closureVars) |
| | w.closureVars = append(w.closureVars, posVar{pos, obj}) |
| | w.closureVarsIdx[obj] = idx |
| | } |
| | w.Len(idx) |
| | } |
| |
|
| | func (w *writer) openScope(pos syntax.Pos) { |
| | w.Sync(pkgbits.SyncOpenScope) |
| | w.pos(pos) |
| | } |
| |
|
| | func (w *writer) closeScope(pos syntax.Pos) { |
| | w.Sync(pkgbits.SyncCloseScope) |
| | w.pos(pos) |
| | w.closeAnotherScope() |
| | } |
| |
|
| | func (w *writer) closeAnotherScope() { |
| | w.Sync(pkgbits.SyncCloseAnotherScope) |
| | } |
| |
|
| | |
| |
|
| | |
| | func (w *writer) stmt(stmt syntax.Stmt) { |
| | var stmts []syntax.Stmt |
| | if stmt != nil { |
| | stmts = []syntax.Stmt{stmt} |
| | } |
| | w.stmts(stmts) |
| | } |
| |
|
| | func (w *writer) stmts(stmts []syntax.Stmt) { |
| | dead := false |
| | w.Sync(pkgbits.SyncStmts) |
| | var lastLabel = -1 |
| | for i, stmt := range stmts { |
| | if _, ok := stmt.(*syntax.LabeledStmt); ok { |
| | lastLabel = i |
| | } |
| | } |
| | for i, stmt := range stmts { |
| | if dead && i > lastLabel { |
| | |
| | |
| | |
| | if _, ok := stmt.(*syntax.LabeledStmt); !ok { |
| | continue |
| | } |
| | } |
| | w.stmt1(stmt) |
| | dead = w.p.terminates(stmt) |
| | } |
| | w.Code(stmtEnd) |
| | w.Sync(pkgbits.SyncStmtsEnd) |
| | } |
| |
|
| | func (w *writer) stmt1(stmt syntax.Stmt) { |
| | switch stmt := stmt.(type) { |
| | default: |
| | w.p.unexpected("statement", stmt) |
| |
|
| | case nil, *syntax.EmptyStmt: |
| | return |
| |
|
| | case *syntax.AssignStmt: |
| | switch { |
| | case stmt.Rhs == nil: |
| | w.Code(stmtIncDec) |
| | w.op(binOps[stmt.Op]) |
| | w.expr(stmt.Lhs) |
| | w.pos(stmt) |
| |
|
| | case stmt.Op != 0 && stmt.Op != syntax.Def: |
| | w.Code(stmtAssignOp) |
| | w.op(binOps[stmt.Op]) |
| | w.expr(stmt.Lhs) |
| | w.pos(stmt) |
| |
|
| | var typ types2.Type |
| | if stmt.Op != syntax.Shl && stmt.Op != syntax.Shr { |
| | typ = w.p.typeOf(stmt.Lhs) |
| | } |
| | w.implicitConvExpr(typ, stmt.Rhs) |
| |
|
| | default: |
| | w.assignStmt(stmt, stmt.Lhs, stmt.Rhs) |
| | } |
| |
|
| | case *syntax.BlockStmt: |
| | w.Code(stmtBlock) |
| | w.blockStmt(stmt) |
| |
|
| | case *syntax.BranchStmt: |
| | w.Code(stmtBranch) |
| | w.pos(stmt) |
| | var op ir.Op |
| | switch stmt.Tok { |
| | case syntax.Break: |
| | op = ir.OBREAK |
| | case syntax.Continue: |
| | op = ir.OCONTINUE |
| | case syntax.Fallthrough: |
| | op = ir.OFALL |
| | case syntax.Goto: |
| | op = ir.OGOTO |
| | } |
| | w.op(op) |
| | w.optLabel(stmt.Label) |
| |
|
| | case *syntax.CallStmt: |
| | w.Code(stmtCall) |
| | w.pos(stmt) |
| | var op ir.Op |
| | switch stmt.Tok { |
| | case syntax.Defer: |
| | op = ir.ODEFER |
| | case syntax.Go: |
| | op = ir.OGO |
| | } |
| | w.op(op) |
| | w.expr(stmt.Call) |
| | if stmt.Tok == syntax.Defer { |
| | w.optExpr(stmt.DeferAt) |
| | } |
| |
|
| | case *syntax.DeclStmt: |
| | for _, decl := range stmt.DeclList { |
| | w.declStmt(decl) |
| | } |
| |
|
| | case *syntax.ExprStmt: |
| | w.Code(stmtExpr) |
| | w.expr(stmt.X) |
| |
|
| | case *syntax.ForStmt: |
| | w.Code(stmtFor) |
| | w.forStmt(stmt) |
| |
|
| | case *syntax.IfStmt: |
| | w.Code(stmtIf) |
| | w.ifStmt(stmt) |
| |
|
| | case *syntax.LabeledStmt: |
| | w.Code(stmtLabel) |
| | w.pos(stmt) |
| | w.label(stmt.Label) |
| | w.stmt1(stmt.Stmt) |
| |
|
| | case *syntax.ReturnStmt: |
| | w.Code(stmtReturn) |
| | w.pos(stmt) |
| |
|
| | resultTypes := w.sig.Results() |
| | dstType := func(i int) types2.Type { |
| | return resultTypes.At(i).Type() |
| | } |
| | w.multiExpr(stmt, dstType, syntax.UnpackListExpr(stmt.Results)) |
| |
|
| | case *syntax.SelectStmt: |
| | w.Code(stmtSelect) |
| | w.selectStmt(stmt) |
| |
|
| | case *syntax.SendStmt: |
| | chanType := types2.CoreType(w.p.typeOf(stmt.Chan)).(*types2.Chan) |
| |
|
| | w.Code(stmtSend) |
| | w.pos(stmt) |
| | w.expr(stmt.Chan) |
| | w.implicitConvExpr(chanType.Elem(), stmt.Value) |
| |
|
| | case *syntax.SwitchStmt: |
| | w.Code(stmtSwitch) |
| | w.switchStmt(stmt) |
| | } |
| | } |
| |
|
| | func (w *writer) assignList(expr syntax.Expr) { |
| | exprs := syntax.UnpackListExpr(expr) |
| | w.Len(len(exprs)) |
| |
|
| | for _, expr := range exprs { |
| | w.assign(expr) |
| | } |
| | } |
| |
|
| | func (w *writer) assign(expr syntax.Expr) { |
| | expr = syntax.Unparen(expr) |
| |
|
| | if name, ok := expr.(*syntax.Name); ok { |
| | if name.Value == "_" { |
| | w.Code(assignBlank) |
| | return |
| | } |
| |
|
| | if obj, ok := w.p.info.Defs[name]; ok { |
| | obj := obj.(*types2.Var) |
| |
|
| | w.Code(assignDef) |
| | w.pos(obj) |
| | w.localIdent(obj) |
| | w.typ(obj.Type()) |
| |
|
| | |
| | |
| | w.addLocal(obj) |
| | return |
| | } |
| | } |
| |
|
| | w.Code(assignExpr) |
| | w.expr(expr) |
| | } |
| |
|
| | func (w *writer) declStmt(decl syntax.Decl) { |
| | switch decl := decl.(type) { |
| | default: |
| | w.p.unexpected("declaration", decl) |
| |
|
| | case *syntax.ConstDecl, *syntax.TypeDecl: |
| |
|
| | case *syntax.VarDecl: |
| | w.assignStmt(decl, namesAsExpr(decl.NameList), decl.Values) |
| | } |
| | } |
| |
|
| | |
| | func (w *writer) assignStmt(pos poser, lhs0, rhs0 syntax.Expr) { |
| | lhs := syntax.UnpackListExpr(lhs0) |
| | rhs := syntax.UnpackListExpr(rhs0) |
| |
|
| | w.Code(stmtAssign) |
| | w.pos(pos) |
| |
|
| | |
| | w.Len(len(lhs)) |
| | for _, expr := range lhs { |
| | w.assign(expr) |
| | } |
| |
|
| | dstType := func(i int) types2.Type { |
| | dst := lhs[i] |
| |
|
| | |
| | |
| | |
| | if name, ok := syntax.Unparen(dst).(*syntax.Name); ok { |
| | if name.Value == "_" { |
| | return nil |
| | } else if def, ok := w.p.info.Defs[name].(*types2.Var); ok { |
| | return def.Type() |
| | } else if use, ok := w.p.info.Uses[name].(*types2.Var); ok { |
| | return use.Type() |
| | } else { |
| | w.p.fatalf(dst, "cannot find type of destination object: %v", dst) |
| | } |
| | } |
| |
|
| | return w.p.typeOf(dst) |
| | } |
| |
|
| | w.multiExpr(pos, dstType, rhs) |
| | } |
| |
|
| | func (w *writer) blockStmt(stmt *syntax.BlockStmt) { |
| | w.Sync(pkgbits.SyncBlockStmt) |
| | w.openScope(stmt.Pos()) |
| | w.stmts(stmt.List) |
| | w.closeScope(stmt.Rbrace) |
| | } |
| |
|
| | func (w *writer) forStmt(stmt *syntax.ForStmt) { |
| | w.Sync(pkgbits.SyncForStmt) |
| | w.openScope(stmt.Pos()) |
| |
|
| | if rang, ok := stmt.Init.(*syntax.RangeClause); w.Bool(ok) { |
| | w.pos(rang) |
| | w.assignList(rang.Lhs) |
| | w.expr(rang.X) |
| |
|
| | xtyp := w.p.typeOf(rang.X) |
| | if _, isMap := types2.CoreType(xtyp).(*types2.Map); isMap { |
| | w.rtype(xtyp) |
| | } |
| | { |
| | lhs := syntax.UnpackListExpr(rang.Lhs) |
| | assign := func(i int, src types2.Type) { |
| | if i >= len(lhs) { |
| | return |
| | } |
| | dst := syntax.Unparen(lhs[i]) |
| | if name, ok := dst.(*syntax.Name); ok && name.Value == "_" { |
| | return |
| | } |
| |
|
| | var dstType types2.Type |
| | if rang.Def { |
| | |
| | |
| | dstType = w.p.info.Defs[dst.(*syntax.Name)].(*types2.Var).Type() |
| | } else { |
| | dstType = w.p.typeOf(dst) |
| | } |
| |
|
| | w.convRTTI(src, dstType) |
| | } |
| |
|
| | keyType, valueType := types2.RangeKeyVal(w.p.typeOf(rang.X)) |
| | assign(0, keyType) |
| | assign(1, valueType) |
| | } |
| |
|
| | } else { |
| | if stmt.Cond != nil && w.p.staticBool(&stmt.Cond) < 0 { |
| | stmt.Post = nil |
| | stmt.Body.List = nil |
| | } |
| |
|
| | w.pos(stmt) |
| | w.stmt(stmt.Init) |
| | w.optExpr(stmt.Cond) |
| | w.stmt(stmt.Post) |
| | } |
| |
|
| | w.blockStmt(stmt.Body) |
| | w.Bool(w.distinctVars(stmt)) |
| | w.closeAnotherScope() |
| | } |
| |
|
| | func (w *writer) distinctVars(stmt *syntax.ForStmt) bool { |
| | lv := base.Debug.LoopVar |
| | fileVersion := w.p.info.FileVersions[stmt.Pos().Base()] |
| | is122 := fileVersion == "" || version.Compare(fileVersion, "go1.22") >= 0 |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | return is122 || lv > 0 && lv != 3 |
| | } |
| |
|
| | func (w *writer) ifStmt(stmt *syntax.IfStmt) { |
| | cond := w.p.staticBool(&stmt.Cond) |
| |
|
| | w.Sync(pkgbits.SyncIfStmt) |
| | w.openScope(stmt.Pos()) |
| | w.pos(stmt) |
| | w.stmt(stmt.Init) |
| | w.expr(stmt.Cond) |
| | w.Int(cond) |
| | if cond >= 0 { |
| | w.blockStmt(stmt.Then) |
| | } else { |
| | w.pos(stmt.Then.Rbrace) |
| | } |
| | if cond <= 0 { |
| | w.stmt(stmt.Else) |
| | } |
| | w.closeAnotherScope() |
| | } |
| |
|
| | func (w *writer) selectStmt(stmt *syntax.SelectStmt) { |
| | w.Sync(pkgbits.SyncSelectStmt) |
| |
|
| | w.pos(stmt) |
| | w.Len(len(stmt.Body)) |
| | for i, clause := range stmt.Body { |
| | if i > 0 { |
| | w.closeScope(clause.Pos()) |
| | } |
| | w.openScope(clause.Pos()) |
| |
|
| | w.pos(clause) |
| | w.stmt(clause.Comm) |
| | w.stmts(clause.Body) |
| | } |
| | if len(stmt.Body) > 0 { |
| | w.closeScope(stmt.Rbrace) |
| | } |
| | } |
| |
|
| | func (w *writer) switchStmt(stmt *syntax.SwitchStmt) { |
| | w.Sync(pkgbits.SyncSwitchStmt) |
| |
|
| | w.openScope(stmt.Pos()) |
| | w.pos(stmt) |
| | w.stmt(stmt.Init) |
| |
|
| | var iface, tagType types2.Type |
| | var tagTypeIsChan bool |
| | if guard, ok := stmt.Tag.(*syntax.TypeSwitchGuard); w.Bool(ok) { |
| | iface = w.p.typeOf(guard.X) |
| |
|
| | w.pos(guard) |
| | if tag := guard.Lhs; w.Bool(tag != nil) { |
| | w.pos(tag) |
| |
|
| | |
| | w.Sync(pkgbits.SyncLocalIdent) |
| | w.pkg(w.p.curpkg) |
| | w.String(tag.Value) |
| | } |
| | w.expr(guard.X) |
| | } else { |
| | tag := stmt.Tag |
| |
|
| | var tagValue constant.Value |
| | if tag != nil { |
| | tv := w.p.typeAndValue(tag) |
| | tagType = tv.Type |
| | tagValue = tv.Value |
| | _, tagTypeIsChan = tagType.Underlying().(*types2.Chan) |
| | } else { |
| | tagType = types2.Typ[types2.Bool] |
| | tagValue = constant.MakeBool(true) |
| | } |
| |
|
| | if tagValue != nil { |
| | |
| | |
| | func() { |
| | var target *syntax.CaseClause |
| | Outer: |
| | for _, clause := range stmt.Body { |
| | if clause.Cases == nil { |
| | target = clause |
| | } |
| | for _, cas := range syntax.UnpackListExpr(clause.Cases) { |
| | tv := w.p.typeAndValue(cas) |
| | if tv.Value == nil { |
| | return |
| | } |
| | if constant.Compare(tagValue, token.EQL, tv.Value) { |
| | target = clause |
| | break Outer |
| | } |
| | } |
| | } |
| | |
| |
|
| | if target != nil { |
| | if hasFallthrough(target.Body) { |
| | return |
| | } |
| |
|
| | |
| | target.Cases = nil |
| | stmt.Body = []*syntax.CaseClause{target} |
| | } else { |
| | stmt.Body = nil |
| | } |
| |
|
| | |
| | tag = nil |
| | stmt.Tag = nil |
| | tagType = types2.Typ[types2.Bool] |
| | }() |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | if !tagTypeIsChan { |
| | Outer: |
| | for _, clause := range stmt.Body { |
| | for _, cas := range syntax.UnpackListExpr(clause.Cases) { |
| | if casType := w.p.typeOf(cas); !types2.AssignableTo(casType, tagType) && (types2.IsInterface(casType) || types2.IsInterface(tagType)) { |
| | tagType = types2.NewInterfaceType(nil, nil) |
| | break Outer |
| | } |
| | } |
| | } |
| | } |
| |
|
| | if w.Bool(tag != nil) { |
| | w.implicitConvExpr(tagType, tag) |
| | } |
| | } |
| |
|
| | w.Len(len(stmt.Body)) |
| | for i, clause := range stmt.Body { |
| | if i > 0 { |
| | w.closeScope(clause.Pos()) |
| | } |
| | w.openScope(clause.Pos()) |
| |
|
| | w.pos(clause) |
| |
|
| | cases := syntax.UnpackListExpr(clause.Cases) |
| | if iface != nil { |
| | w.Len(len(cases)) |
| | for _, cas := range cases { |
| | if w.Bool(isNil(w.p, cas)) { |
| | continue |
| | } |
| | w.exprType(iface, cas) |
| | } |
| | } else { |
| | |
| | |
| |
|
| | w.Sync(pkgbits.SyncExprList) |
| | w.Sync(pkgbits.SyncExprs) |
| | w.Len(len(cases)) |
| | for _, cas := range cases { |
| | typ := tagType |
| | if tagTypeIsChan { |
| | typ = nil |
| | } |
| | w.implicitConvExpr(typ, cas) |
| | } |
| | } |
| |
|
| | if obj, ok := w.p.info.Implicits[clause]; ok { |
| | |
| | |
| | |
| | |
| | |
| | pos := clause.Pos() |
| | if typs := syntax.UnpackListExpr(clause.Cases); len(typs) != 0 { |
| | pos = typeExprEndPos(typs[len(typs)-1]) |
| | } |
| | w.pos(pos) |
| |
|
| | obj := obj.(*types2.Var) |
| | w.typ(obj.Type()) |
| | w.addLocal(obj) |
| | } |
| |
|
| | w.stmts(clause.Body) |
| | } |
| | if len(stmt.Body) > 0 { |
| | w.closeScope(stmt.Rbrace) |
| | } |
| |
|
| | w.closeScope(stmt.Rbrace) |
| | } |
| |
|
| | func (w *writer) label(label *syntax.Name) { |
| | w.Sync(pkgbits.SyncLabel) |
| |
|
| | |
| | w.String(label.Value) |
| | } |
| |
|
| | func (w *writer) optLabel(label *syntax.Name) { |
| | w.Sync(pkgbits.SyncOptLabel) |
| | if w.Bool(label != nil) { |
| | w.label(label) |
| | } |
| | } |
| |
|
| | |
| |
|
| | |
| | func (w *writer) expr(expr syntax.Expr) { |
| | base.Assertf(expr != nil, "missing expression") |
| |
|
| | expr = syntax.Unparen(expr) |
| |
|
| | obj, inst := lookupObj(w.p, expr) |
| | targs := inst.TypeArgs |
| |
|
| | if tv, ok := w.p.maybeTypeAndValue(expr); ok { |
| | if tv.IsRuntimeHelper() { |
| | if pkg := obj.Pkg(); pkg != nil && pkg.Name() == "runtime" { |
| | objName := obj.Name() |
| | w.Code(exprRuntimeBuiltin) |
| | w.String(objName) |
| | return |
| | } |
| | } |
| |
|
| | if tv.IsType() { |
| | w.p.fatalf(expr, "unexpected type expression %v", syntax.String(expr)) |
| | } |
| |
|
| | if tv.Value != nil { |
| | w.Code(exprConst) |
| | w.pos(expr) |
| | typ := idealType(tv) |
| | assert(typ != nil) |
| | w.typ(typ) |
| | w.Value(tv.Value) |
| | return |
| | } |
| |
|
| | if _, isNil := obj.(*types2.Nil); isNil { |
| | w.Code(exprZero) |
| | w.pos(expr) |
| | w.typ(tv.Type) |
| | return |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | if typ := tv.Type; !tv.IsBuiltin() && !isTuple(typ) && !isUntyped(typ) { |
| | w.Code(exprReshape) |
| | w.typ(typ) |
| | |
| | } |
| | } |
| |
|
| | if obj != nil { |
| | if targs.Len() != 0 { |
| | obj := obj.(*types2.Func) |
| |
|
| | w.Code(exprFuncInst) |
| | w.pos(expr) |
| | w.funcInst(obj, targs) |
| | return |
| | } |
| |
|
| | if isGlobal(obj) { |
| | w.Code(exprGlobal) |
| | w.obj(obj, nil) |
| | return |
| | } |
| |
|
| | obj := obj.(*types2.Var) |
| | assert(!obj.IsField()) |
| |
|
| | w.Code(exprLocal) |
| | w.useLocal(expr.Pos(), obj) |
| | return |
| | } |
| |
|
| | switch expr := expr.(type) { |
| | default: |
| | w.p.unexpected("expression", expr) |
| |
|
| | case *syntax.CompositeLit: |
| | w.Code(exprCompLit) |
| | w.compLit(expr) |
| |
|
| | case *syntax.FuncLit: |
| | w.Code(exprFuncLit) |
| | w.funcLit(expr) |
| |
|
| | case *syntax.SelectorExpr: |
| | sel, ok := w.p.info.Selections[expr] |
| | assert(ok) |
| |
|
| | switch sel.Kind() { |
| | default: |
| | w.p.fatalf(expr, "unexpected selection kind: %v", sel.Kind()) |
| |
|
| | case types2.FieldVal: |
| | w.Code(exprFieldVal) |
| | w.expr(expr.X) |
| | w.pos(expr) |
| | w.selector(sel.Obj()) |
| |
|
| | case types2.MethodVal: |
| | w.Code(exprMethodVal) |
| | typ := w.recvExpr(expr, sel) |
| | w.pos(expr) |
| | w.methodExpr(expr, typ, sel) |
| |
|
| | case types2.MethodExpr: |
| | w.Code(exprMethodExpr) |
| |
|
| | tv := w.p.typeAndValue(expr.X) |
| | assert(tv.IsType()) |
| |
|
| | index := sel.Index() |
| | implicits := index[:len(index)-1] |
| |
|
| | typ := tv.Type |
| | w.typ(typ) |
| |
|
| | w.Len(len(implicits)) |
| | for _, ix := range implicits { |
| | w.Len(ix) |
| | typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type() |
| | } |
| |
|
| | recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type() |
| | if w.Bool(isPtrTo(typ, recv)) { |
| | typ = recv |
| | } else if w.Bool(isPtrTo(recv, typ)) { |
| | typ = recv |
| | } |
| |
|
| | w.pos(expr) |
| | w.methodExpr(expr, typ, sel) |
| | } |
| |
|
| | case *syntax.IndexExpr: |
| | _ = w.p.typeOf(expr.Index) |
| |
|
| | xtyp := w.p.typeOf(expr.X) |
| |
|
| | var keyType types2.Type |
| | if mapType, ok := types2.CoreType(xtyp).(*types2.Map); ok { |
| | keyType = mapType.Key() |
| | } |
| |
|
| | w.Code(exprIndex) |
| | w.expr(expr.X) |
| | w.pos(expr) |
| | w.implicitConvExpr(keyType, expr.Index) |
| | if keyType != nil { |
| | w.rtype(xtyp) |
| | } |
| |
|
| | case *syntax.SliceExpr: |
| | w.Code(exprSlice) |
| | w.expr(expr.X) |
| | w.pos(expr) |
| | for _, n := range &expr.Index { |
| | w.optExpr(n) |
| | } |
| |
|
| | case *syntax.AssertExpr: |
| | iface := w.p.typeOf(expr.X) |
| |
|
| | w.Code(exprAssert) |
| | w.expr(expr.X) |
| | w.pos(expr) |
| | w.exprType(iface, expr.Type) |
| | w.rtype(iface) |
| |
|
| | case *syntax.Operation: |
| | if expr.Y == nil { |
| | w.Code(exprUnaryOp) |
| | w.op(unOps[expr.Op]) |
| | w.pos(expr) |
| | w.expr(expr.X) |
| | break |
| | } |
| |
|
| | var commonType types2.Type |
| | switch expr.Op { |
| | case syntax.Shl, syntax.Shr: |
| | |
| | default: |
| | xtyp := w.p.typeOf(expr.X) |
| | ytyp := w.p.typeOf(expr.Y) |
| | switch { |
| | case types2.AssignableTo(xtyp, ytyp): |
| | commonType = ytyp |
| | case types2.AssignableTo(ytyp, xtyp): |
| | commonType = xtyp |
| | default: |
| | w.p.fatalf(expr, "failed to find common type between %v and %v", xtyp, ytyp) |
| | } |
| | } |
| |
|
| | w.Code(exprBinaryOp) |
| | w.op(binOps[expr.Op]) |
| | w.implicitConvExpr(commonType, expr.X) |
| | w.pos(expr) |
| | w.implicitConvExpr(commonType, expr.Y) |
| |
|
| | case *syntax.CallExpr: |
| | tv := w.p.typeAndValue(expr.Fun) |
| | if tv.IsType() { |
| | assert(len(expr.ArgList) == 1) |
| | assert(!expr.HasDots) |
| | w.convertExpr(tv.Type, expr.ArgList[0], false) |
| | break |
| | } |
| |
|
| | var rtype types2.Type |
| | if tv.IsBuiltin() { |
| | switch obj, _ := lookupObj(w.p, syntax.Unparen(expr.Fun)); obj.Name() { |
| | case "make": |
| | assert(len(expr.ArgList) >= 1) |
| | assert(!expr.HasDots) |
| |
|
| | w.Code(exprMake) |
| | w.pos(expr) |
| | w.exprType(nil, expr.ArgList[0]) |
| | w.exprs(expr.ArgList[1:]) |
| |
|
| | typ := w.p.typeOf(expr) |
| | switch coreType := types2.CoreType(typ).(type) { |
| | default: |
| | w.p.fatalf(expr, "unexpected core type: %v", coreType) |
| | case *types2.Chan: |
| | w.rtype(typ) |
| | case *types2.Map: |
| | w.rtype(typ) |
| | case *types2.Slice: |
| | w.rtype(sliceElem(typ)) |
| | } |
| |
|
| | return |
| |
|
| | case "new": |
| | assert(len(expr.ArgList) == 1) |
| | assert(!expr.HasDots) |
| | arg := expr.ArgList[0] |
| |
|
| | w.Code(exprNew) |
| | w.pos(expr) |
| | tv := w.p.typeAndValue(arg) |
| | if w.Bool(!tv.IsType()) { |
| | w.expr(arg) |
| | } else { |
| | w.exprType(nil, arg) |
| | } |
| | return |
| |
|
| | case "Sizeof": |
| | assert(len(expr.ArgList) == 1) |
| | assert(!expr.HasDots) |
| |
|
| | w.Code(exprSizeof) |
| | w.pos(expr) |
| | w.typ(w.p.typeOf(expr.ArgList[0])) |
| | return |
| |
|
| | case "Alignof": |
| | assert(len(expr.ArgList) == 1) |
| | assert(!expr.HasDots) |
| |
|
| | w.Code(exprAlignof) |
| | w.pos(expr) |
| | w.typ(w.p.typeOf(expr.ArgList[0])) |
| | return |
| |
|
| | case "Offsetof": |
| | assert(len(expr.ArgList) == 1) |
| | assert(!expr.HasDots) |
| | selector := syntax.Unparen(expr.ArgList[0]).(*syntax.SelectorExpr) |
| | index := w.p.info.Selections[selector].Index() |
| |
|
| | w.Code(exprOffsetof) |
| | w.pos(expr) |
| | w.typ(deref2(w.p.typeOf(selector.X))) |
| | w.Len(len(index) - 1) |
| | for _, idx := range index { |
| | w.Len(idx) |
| | } |
| | return |
| |
|
| | case "append": |
| | rtype = sliceElem(w.p.typeOf(expr)) |
| | case "copy": |
| | typ := w.p.typeOf(expr.ArgList[0]) |
| | if tuple, ok := typ.(*types2.Tuple); ok { |
| | typ = tuple.At(0).Type() |
| | } |
| | rtype = sliceElem(typ) |
| | case "delete": |
| | typ := w.p.typeOf(expr.ArgList[0]) |
| | if tuple, ok := typ.(*types2.Tuple); ok { |
| | typ = tuple.At(0).Type() |
| | } |
| | rtype = typ |
| | case "Slice": |
| | rtype = sliceElem(w.p.typeOf(expr)) |
| | } |
| | } |
| |
|
| | writeFunExpr := func() { |
| | fun := syntax.Unparen(expr.Fun) |
| |
|
| | if selector, ok := fun.(*syntax.SelectorExpr); ok { |
| | if sel, ok := w.p.info.Selections[selector]; ok && sel.Kind() == types2.MethodVal { |
| | w.Bool(true) |
| | typ := w.recvExpr(selector, sel) |
| | w.methodExpr(selector, typ, sel) |
| | return |
| | } |
| | } |
| |
|
| | w.Bool(false) |
| |
|
| | if obj, inst := lookupObj(w.p, fun); w.Bool(obj != nil && inst.TypeArgs.Len() != 0) { |
| | obj := obj.(*types2.Func) |
| |
|
| | w.pos(fun) |
| | w.funcInst(obj, inst.TypeArgs) |
| | return |
| | } |
| |
|
| | w.expr(fun) |
| | } |
| |
|
| | sigType := types2.CoreType(tv.Type).(*types2.Signature) |
| | paramTypes := sigType.Params() |
| |
|
| | w.Code(exprCall) |
| | writeFunExpr() |
| | w.pos(expr) |
| |
|
| | paramType := func(i int) types2.Type { |
| | if sigType.Variadic() && !expr.HasDots && i >= paramTypes.Len()-1 { |
| | return paramTypes.At(paramTypes.Len() - 1).Type().(*types2.Slice).Elem() |
| | } |
| | return paramTypes.At(i).Type() |
| | } |
| |
|
| | w.multiExpr(expr, paramType, expr.ArgList) |
| | w.Bool(expr.HasDots) |
| | if rtype != nil { |
| | w.rtype(rtype) |
| | } |
| | } |
| | } |
| |
|
| | func sliceElem(typ types2.Type) types2.Type { |
| | return types2.CoreType(typ).(*types2.Slice).Elem() |
| | } |
| |
|
| | func (w *writer) optExpr(expr syntax.Expr) { |
| | if w.Bool(expr != nil) { |
| | w.expr(expr) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func (w *writer) recvExpr(expr *syntax.SelectorExpr, sel *types2.Selection) types2.Type { |
| | index := sel.Index() |
| | implicits := index[:len(index)-1] |
| |
|
| | w.Code(exprRecv) |
| | w.expr(expr.X) |
| | w.pos(expr) |
| | w.Len(len(implicits)) |
| |
|
| | typ := w.p.typeOf(expr.X) |
| | for _, ix := range implicits { |
| | typ = deref2(typ).Underlying().(*types2.Struct).Field(ix).Type() |
| | w.Len(ix) |
| | } |
| |
|
| | recv := sel.Obj().(*types2.Func).Type().(*types2.Signature).Recv().Type() |
| | if w.Bool(isPtrTo(typ, recv)) { |
| | typ = recv |
| | } else if w.Bool(isPtrTo(recv, typ)) { |
| | typ = recv |
| | } |
| |
|
| | return typ |
| | } |
| |
|
| | |
| | func (w *writer) funcInst(obj *types2.Func, targs *types2.TypeList) { |
| | info := w.p.objInstIdx(obj, targs, w.dict) |
| |
|
| | |
| | |
| | |
| | if w.Bool(info.anyDerived()) { |
| | w.Len(w.dict.subdictIdx(info)) |
| | return |
| | } |
| |
|
| | |
| | |
| | |
| | w.objInfo(info) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func (w *writer) methodExpr(expr *syntax.SelectorExpr, recv types2.Type, sel *types2.Selection) { |
| | fun := sel.Obj().(*types2.Func) |
| | sig := fun.Type().(*types2.Signature) |
| |
|
| | w.typ(recv) |
| | w.typ(sig) |
| | w.pos(expr) |
| | w.selector(fun) |
| |
|
| | |
| | |
| | if typeParam, ok := types2.Unalias(recv).(*types2.TypeParam); w.Bool(ok) { |
| | typeParamIdx := w.dict.typeParamIndex(typeParam) |
| | methodInfo := w.p.selectorIdx(fun) |
| |
|
| | w.Len(w.dict.typeParamMethodExprIdx(typeParamIdx, methodInfo)) |
| | return |
| | } |
| |
|
| | if isInterface(recv) != isInterface(sig.Recv().Type()) { |
| | w.p.fatalf(expr, "isInterface inconsistency: %v and %v", recv, sig.Recv().Type()) |
| | } |
| |
|
| | if !isInterface(recv) { |
| | if named, ok := types2.Unalias(deref2(recv)).(*types2.Named); ok { |
| | obj, targs := splitNamed(named) |
| | info := w.p.objInstIdx(obj, targs, w.dict) |
| |
|
| | |
| | |
| | |
| | |
| | if w.p.hasImplicitTypeParams(obj) || info.anyDerived() { |
| | w.Bool(true) |
| | w.Len(w.dict.subdictIdx(info)) |
| | return |
| | } |
| |
|
| | |
| | |
| | |
| | if targs.Len() != 0 { |
| | w.Bool(false) |
| | w.Bool(true) |
| | w.objInfo(info) |
| | return |
| | } |
| | } |
| | } |
| |
|
| | w.Bool(false) |
| | w.Bool(false) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | func (w *writer) multiExpr(pos poser, dstType func(int) types2.Type, exprs []syntax.Expr) { |
| | w.Sync(pkgbits.SyncMultiExpr) |
| |
|
| | if len(exprs) == 1 { |
| | expr := exprs[0] |
| | if tuple, ok := w.p.typeOf(expr).(*types2.Tuple); ok { |
| | assert(tuple.Len() > 1) |
| | w.Bool(true) |
| | w.pos(pos) |
| | w.expr(expr) |
| |
|
| | w.Len(tuple.Len()) |
| | for i := 0; i < tuple.Len(); i++ { |
| | src := tuple.At(i).Type() |
| | |
| | |
| | w.typ(src) |
| | if dst := dstType(i); w.Bool(dst != nil && !types2.Identical(src, dst)) { |
| | if src == nil || dst == nil { |
| | w.p.fatalf(pos, "src is %v, dst is %v", src, dst) |
| | } |
| | if !types2.AssignableTo(src, dst) { |
| | w.p.fatalf(pos, "%v is not assignable to %v", src, dst) |
| | } |
| | w.typ(dst) |
| | w.convRTTI(src, dst) |
| | } |
| | } |
| | return |
| | } |
| | } |
| |
|
| | w.Bool(false) |
| | w.Len(len(exprs)) |
| | for i, expr := range exprs { |
| | w.implicitConvExpr(dstType(i), expr) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func (w *writer) implicitConvExpr(dst types2.Type, expr syntax.Expr) { |
| | w.convertExpr(dst, expr, true) |
| | } |
| |
|
| | func (w *writer) convertExpr(dst types2.Type, expr syntax.Expr, implicit bool) { |
| | src := w.p.typeOf(expr) |
| |
|
| | |
| | identical := dst == nil || types2.Identical(src, dst) |
| | if implicit && identical { |
| | w.expr(expr) |
| | return |
| | } |
| |
|
| | if implicit && !types2.AssignableTo(src, dst) { |
| | w.p.fatalf(expr, "%v is not assignable to %v", src, dst) |
| | } |
| |
|
| | w.Code(exprConvert) |
| | w.Bool(implicit) |
| | w.typ(dst) |
| | w.pos(expr) |
| | w.convRTTI(src, dst) |
| | w.Bool(isTypeParam(dst)) |
| | w.Bool(identical) |
| | w.expr(expr) |
| | } |
| |
|
| | func (w *writer) compLit(lit *syntax.CompositeLit) { |
| | typ := w.p.typeOf(lit) |
| |
|
| | w.Sync(pkgbits.SyncCompLit) |
| | w.pos(lit) |
| | w.typ(typ) |
| |
|
| | if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok { |
| | typ = ptr.Elem() |
| | } |
| | var keyType, elemType types2.Type |
| | var structType *types2.Struct |
| | switch typ0 := typ; typ := types2.CoreType(typ).(type) { |
| | default: |
| | w.p.fatalf(lit, "unexpected composite literal type: %v", typ) |
| | case *types2.Array: |
| | elemType = typ.Elem() |
| | case *types2.Map: |
| | w.rtype(typ0) |
| | keyType, elemType = typ.Key(), typ.Elem() |
| | case *types2.Slice: |
| | elemType = typ.Elem() |
| | case *types2.Struct: |
| | structType = typ |
| | } |
| |
|
| | w.Len(len(lit.ElemList)) |
| | for i, elem := range lit.ElemList { |
| | elemType := elemType |
| | if structType != nil { |
| | if kv, ok := elem.(*syntax.KeyValueExpr); ok { |
| | |
| | w.pos(kv.Key) |
| | i = fieldIndex(w.p.info, structType, kv.Key.(*syntax.Name)) |
| | elem = kv.Value |
| | } else { |
| | w.pos(elem) |
| | } |
| | elemType = structType.Field(i).Type() |
| | w.Len(i) |
| | } else { |
| | if kv, ok := elem.(*syntax.KeyValueExpr); w.Bool(ok) { |
| | |
| | w.pos(kv.Key) |
| | w.implicitConvExpr(keyType, kv.Key) |
| | elem = kv.Value |
| | } |
| | } |
| | w.implicitConvExpr(elemType, elem) |
| | } |
| | } |
| |
|
| | func (w *writer) funcLit(expr *syntax.FuncLit) { |
| | sig := w.p.typeOf(expr).(*types2.Signature) |
| |
|
| | body, closureVars := w.p.bodyIdx(sig, expr.Body, w.dict) |
| |
|
| | w.Sync(pkgbits.SyncFuncLit) |
| | w.pos(expr) |
| | w.signature(sig) |
| | w.Bool(w.p.rangeFuncBodyClosures[expr]) |
| |
|
| | w.Len(len(closureVars)) |
| | for _, cv := range closureVars { |
| | w.pos(cv.pos) |
| | w.useLocal(cv.pos, cv.var_) |
| | } |
| |
|
| | w.Reloc(pkgbits.SectionBody, body) |
| | } |
| |
|
| | type posVar struct { |
| | pos syntax.Pos |
| | var_ *types2.Var |
| | } |
| |
|
| | func (p posVar) String() string { |
| | return p.pos.String() + ":" + p.var_.String() |
| | } |
| |
|
| | func (w *writer) exprs(exprs []syntax.Expr) { |
| | w.Sync(pkgbits.SyncExprs) |
| | w.Len(len(exprs)) |
| | for _, expr := range exprs { |
| | w.expr(expr) |
| | } |
| | } |
| |
|
| | |
| | |
| | func (w *writer) rtype(typ types2.Type) { |
| | typ = types2.Default(typ) |
| |
|
| | info := w.p.typIdx(typ, w.dict) |
| | w.rtypeInfo(info) |
| | } |
| |
|
| | func (w *writer) rtypeInfo(info typeInfo) { |
| | w.Sync(pkgbits.SyncRType) |
| |
|
| | if w.Bool(info.derived) { |
| | w.Len(w.dict.rtypeIdx(info)) |
| | } else { |
| | w.typInfo(info) |
| | } |
| | } |
| |
|
| | |
| | |
| | func (w *writer) varDictIndex(obj *types2.Var) { |
| | info := w.p.typIdx(obj.Type(), w.dict) |
| | if w.Bool(info.derived) { |
| | w.Len(w.dict.rtypeIdx(info)) |
| | } |
| | } |
| |
|
| | |
| | func isUntyped(typ types2.Type) bool { |
| | |
| | basic, ok := typ.(*types2.Basic) |
| | return ok && basic.Info()&types2.IsUntyped != 0 |
| | } |
| |
|
| | |
| | func isTuple(typ types2.Type) bool { |
| | |
| | _, ok := typ.(*types2.Tuple) |
| | return ok |
| | } |
| |
|
| | func (w *writer) itab(typ, iface types2.Type) { |
| | typ = types2.Default(typ) |
| | iface = types2.Default(iface) |
| |
|
| | typInfo := w.p.typIdx(typ, w.dict) |
| | ifaceInfo := w.p.typIdx(iface, w.dict) |
| |
|
| | w.rtypeInfo(typInfo) |
| | w.rtypeInfo(ifaceInfo) |
| | if w.Bool(typInfo.derived || ifaceInfo.derived) { |
| | w.Len(w.dict.itabIdx(typInfo, ifaceInfo)) |
| | } |
| | } |
| |
|
| | |
| | |
| | func (w *writer) convRTTI(src, dst types2.Type) { |
| | w.Sync(pkgbits.SyncConvRTTI) |
| | w.itab(src, dst) |
| | } |
| |
|
| | func (w *writer) exprType(iface types2.Type, typ syntax.Expr) { |
| | base.Assertf(iface == nil || isInterface(iface), "%v must be nil or an interface type", iface) |
| |
|
| | tv := w.p.typeAndValue(typ) |
| | assert(tv.IsType()) |
| |
|
| | w.Sync(pkgbits.SyncExprType) |
| | w.pos(typ) |
| |
|
| | if w.Bool(iface != nil && !iface.Underlying().(*types2.Interface).Empty()) { |
| | w.itab(tv.Type, iface) |
| | } else { |
| | w.rtype(tv.Type) |
| |
|
| | info := w.p.typIdx(tv.Type, w.dict) |
| | w.Bool(info.derived) |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | func isInterface(typ types2.Type) bool { |
| | if _, ok := types2.Unalias(typ).(*types2.TypeParam); ok { |
| | |
| | |
| | |
| | base.Fatalf("%v is a type parameter", typ) |
| | } |
| |
|
| | _, ok := typ.Underlying().(*types2.Interface) |
| | return ok |
| | } |
| |
|
| | |
| | func (w *writer) op(op ir.Op) { |
| | |
| | |
| | |
| | assert(op != 0) |
| | w.Sync(pkgbits.SyncOp) |
| | w.Len(int(op)) |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| |
|
| | type typeDeclGen struct { |
| | *syntax.TypeDecl |
| | gen int |
| |
|
| | |
| | implicits []*types2.TypeParam |
| | } |
| |
|
| | type fileImports struct { |
| | importedEmbed, importedUnsafe bool |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | type declCollector struct { |
| | pw *pkgWriter |
| | typegen *int |
| | file *fileImports |
| | withinFunc bool |
| | implicits []*types2.TypeParam |
| | } |
| |
|
| | func (c *declCollector) withTParams(obj types2.Object) *declCollector { |
| | tparams := objTypeParams(obj) |
| | n := tparams.Len() |
| | if n == 0 { |
| | return c |
| | } |
| |
|
| | copy := *c |
| | copy.implicits = copy.implicits[:len(copy.implicits):len(copy.implicits)] |
| | for i := 0; i < n; i++ { |
| | copy.implicits = append(copy.implicits, tparams.At(i)) |
| | } |
| | return © |
| | } |
| |
|
| | func (c *declCollector) Visit(n syntax.Node) syntax.Visitor { |
| | pw := c.pw |
| |
|
| | switch n := n.(type) { |
| | case *syntax.File: |
| | pw.checkPragmas(n.Pragma, ir.GoBuildPragma, false) |
| |
|
| | case *syntax.ImportDecl: |
| | pw.checkPragmas(n.Pragma, 0, false) |
| |
|
| | switch pw.info.PkgNameOf(n).Imported().Path() { |
| | case "embed": |
| | c.file.importedEmbed = true |
| | case "unsafe": |
| | c.file.importedUnsafe = true |
| | } |
| |
|
| | case *syntax.ConstDecl: |
| | pw.checkPragmas(n.Pragma, 0, false) |
| |
|
| | case *syntax.FuncDecl: |
| | pw.checkPragmas(n.Pragma, funcPragmas, false) |
| |
|
| | obj := pw.info.Defs[n.Name].(*types2.Func) |
| | pw.funDecls[obj] = n |
| |
|
| | return c.withTParams(obj) |
| |
|
| | case *syntax.TypeDecl: |
| | obj := pw.info.Defs[n.Name].(*types2.TypeName) |
| | d := typeDeclGen{TypeDecl: n, implicits: c.implicits} |
| |
|
| | if n.Alias { |
| | pw.checkPragmas(n.Pragma, 0, false) |
| | } else { |
| | pw.checkPragmas(n.Pragma, 0, false) |
| |
|
| | |
| | if c.withinFunc { |
| | *c.typegen++ |
| | d.gen = *c.typegen |
| | } |
| | } |
| |
|
| | pw.typDecls[obj] = d |
| |
|
| | |
| | |
| | |
| | |
| | return c.withTParams(obj) |
| |
|
| | case *syntax.VarDecl: |
| | pw.checkPragmas(n.Pragma, 0, true) |
| |
|
| | if p, ok := n.Pragma.(*pragmas); ok && len(p.Embeds) > 0 { |
| | if err := checkEmbed(n, c.file.importedEmbed, c.withinFunc); err != nil { |
| | pw.errorf(p.Embeds[0].Pos, "%s", err) |
| | } |
| | } |
| |
|
| | case *syntax.BlockStmt: |
| | if !c.withinFunc { |
| | copy := *c |
| | copy.withinFunc = true |
| | return © |
| | } |
| | } |
| |
|
| | return c |
| | } |
| |
|
| | func (pw *pkgWriter) collectDecls(noders []*noder) { |
| | var typegen int |
| | for _, p := range noders { |
| | var file fileImports |
| |
|
| | syntax.Walk(p.file, &declCollector{ |
| | pw: pw, |
| | typegen: &typegen, |
| | file: &file, |
| | }) |
| |
|
| | pw.cgoPragmas = append(pw.cgoPragmas, p.pragcgobuf...) |
| |
|
| | for _, l := range p.linknames { |
| | if !file.importedUnsafe { |
| | pw.errorf(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"") |
| | continue |
| | } |
| | if strings.Contains(l.remote, "[") && strings.Contains(l.remote, "]") { |
| | pw.errorf(l.pos, "//go:linkname reference of an instantiation is not allowed") |
| | continue |
| | } |
| |
|
| | switch obj := pw.curpkg.Scope().Lookup(l.local).(type) { |
| | case *types2.Func, *types2.Var: |
| | if _, ok := pw.linknames[obj]; !ok { |
| | pw.linknames[obj] = l.remote |
| | } else { |
| | pw.errorf(l.pos, "duplicate //go:linkname for %s", l.local) |
| | } |
| |
|
| | default: |
| | if types.AllowsGoVersion(1, 18) { |
| | pw.errorf(l.pos, "//go:linkname must refer to declared function or variable") |
| | } |
| | } |
| | } |
| | } |
| | } |
| |
|
| | func (pw *pkgWriter) checkPragmas(p syntax.Pragma, allowed ir.PragmaFlag, embedOK bool) { |
| | if p == nil { |
| | return |
| | } |
| | pragma := p.(*pragmas) |
| |
|
| | for _, pos := range pragma.Pos { |
| | if pos.Flag&^allowed != 0 { |
| | pw.errorf(pos.Pos, "misplaced compiler directive") |
| | } |
| | } |
| |
|
| | if !embedOK { |
| | for _, e := range pragma.Embeds { |
| | pw.errorf(e.Pos, "misplaced go:embed directive") |
| | } |
| | } |
| | } |
| |
|
| | func (w *writer) pkgInit(noders []*noder) { |
| | w.Len(len(w.p.cgoPragmas)) |
| | for _, cgoPragma := range w.p.cgoPragmas { |
| | w.Strings(cgoPragma) |
| | } |
| |
|
| | w.pkgInitOrder() |
| |
|
| | w.Sync(pkgbits.SyncDecls) |
| | for _, p := range noders { |
| | for _, decl := range p.file.DeclList { |
| | w.pkgDecl(decl) |
| | } |
| | } |
| | w.Code(declEnd) |
| |
|
| | w.Sync(pkgbits.SyncEOF) |
| | } |
| |
|
| | func (w *writer) pkgInitOrder() { |
| | |
| | w.Len(len(w.p.info.InitOrder)) |
| | for _, init := range w.p.info.InitOrder { |
| | w.Len(len(init.Lhs)) |
| | for _, v := range init.Lhs { |
| | w.obj(v, nil) |
| | } |
| | w.expr(init.Rhs) |
| | } |
| | } |
| |
|
| | func (w *writer) pkgDecl(decl syntax.Decl) { |
| | switch decl := decl.(type) { |
| | default: |
| | w.p.unexpected("declaration", decl) |
| |
|
| | case *syntax.ImportDecl: |
| |
|
| | case *syntax.ConstDecl: |
| | w.Code(declOther) |
| | w.pkgObjs(decl.NameList...) |
| |
|
| | case *syntax.FuncDecl: |
| | if decl.Name.Value == "_" { |
| | break |
| | } |
| |
|
| | obj := w.p.info.Defs[decl.Name].(*types2.Func) |
| | sig := obj.Type().(*types2.Signature) |
| |
|
| | if sig.RecvTypeParams() != nil || sig.TypeParams() != nil { |
| | break |
| | } |
| |
|
| | if recv := sig.Recv(); recv != nil { |
| | w.Code(declMethod) |
| | w.typ(recvBase(recv)) |
| | w.selector(obj) |
| | break |
| | } |
| |
|
| | w.Code(declFunc) |
| | w.pkgObjs(decl.Name) |
| |
|
| | case *syntax.TypeDecl: |
| | if len(decl.TParamList) != 0 { |
| | break |
| | } |
| |
|
| | if decl.Name.Value == "_" { |
| | break |
| | } |
| |
|
| | name := w.p.info.Defs[decl.Name].(*types2.TypeName) |
| | |
| | |
| | if iface, ok := name.Type().Underlying().(*types2.Interface); ok && !iface.IsMethodSet() { |
| | break |
| | } |
| |
|
| | w.Code(declOther) |
| | w.pkgObjs(decl.Name) |
| |
|
| | case *syntax.VarDecl: |
| | w.Code(declVar) |
| | w.pkgObjs(decl.NameList...) |
| |
|
| | var embeds []pragmaEmbed |
| | if p, ok := decl.Pragma.(*pragmas); ok { |
| | embeds = p.Embeds |
| | } |
| | w.Len(len(embeds)) |
| | for _, embed := range embeds { |
| | w.pos(embed.Pos) |
| | w.Strings(embed.Patterns) |
| | } |
| | } |
| | } |
| |
|
| | func (w *writer) pkgObjs(names ...*syntax.Name) { |
| | w.Sync(pkgbits.SyncDeclNames) |
| | w.Len(len(names)) |
| |
|
| | for _, name := range names { |
| | obj, ok := w.p.info.Defs[name] |
| | assert(ok) |
| |
|
| | w.Sync(pkgbits.SyncDeclName) |
| | w.obj(obj, nil) |
| | } |
| | } |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | func (pw *pkgWriter) staticBool(ep *syntax.Expr) int { |
| | if val := pw.typeAndValue(*ep).Value; val != nil { |
| | if constant.BoolVal(val) { |
| | return +1 |
| | } else { |
| | return -1 |
| | } |
| | } |
| |
|
| | if e, ok := (*ep).(*syntax.Operation); ok { |
| | switch e.Op { |
| | case syntax.Not: |
| | return pw.staticBool(&e.X) |
| |
|
| | case syntax.AndAnd: |
| | x := pw.staticBool(&e.X) |
| | if x < 0 { |
| | *ep = e.X |
| | return x |
| | } |
| |
|
| | y := pw.staticBool(&e.Y) |
| | if x > 0 || y < 0 { |
| | if pw.typeAndValue(e.X).Value != nil { |
| | *ep = e.Y |
| | } |
| | return y |
| | } |
| |
|
| | case syntax.OrOr: |
| | x := pw.staticBool(&e.X) |
| | if x > 0 { |
| | *ep = e.X |
| | return x |
| | } |
| |
|
| | y := pw.staticBool(&e.Y) |
| | if x < 0 || y > 0 { |
| | if pw.typeAndValue(e.X).Value != nil { |
| | *ep = e.Y |
| | } |
| | return y |
| | } |
| | } |
| | } |
| |
|
| | return 0 |
| | } |
| |
|
| | |
| | |
| | |
| | func (pw *pkgWriter) hasImplicitTypeParams(obj *types2.TypeName) bool { |
| | if obj.Pkg() == pw.curpkg { |
| | decl, ok := pw.typDecls[obj] |
| | assert(ok) |
| | if len(decl.implicits) != 0 { |
| | return true |
| | } |
| | } |
| | return false |
| | } |
| |
|
| | |
| | func isDefinedType(obj types2.Object) bool { |
| | if obj, ok := obj.(*types2.TypeName); ok { |
| | return !obj.IsAlias() |
| | } |
| | return false |
| | } |
| |
|
| | |
| | |
| | |
| | func isGlobal(obj types2.Object) bool { |
| | return obj.Parent() == obj.Pkg().Scope() |
| | } |
| |
|
| | |
| | |
| | |
| | func lookupObj(p *pkgWriter, expr syntax.Expr) (obj types2.Object, inst types2.Instance) { |
| | if index, ok := expr.(*syntax.IndexExpr); ok { |
| | args := syntax.UnpackListExpr(index.Index) |
| | if len(args) == 1 { |
| | tv := p.typeAndValue(args[0]) |
| | if tv.IsValue() { |
| | return |
| | } |
| | } |
| |
|
| | expr = index.X |
| | } |
| |
|
| | |
| | if sel, ok := expr.(*syntax.SelectorExpr); ok { |
| | if !isPkgQual(p.info, sel) { |
| | return |
| | } |
| | expr = sel.Sel |
| | } |
| |
|
| | if name, ok := expr.(*syntax.Name); ok { |
| | obj = p.info.Uses[name] |
| | inst = p.info.Instances[name] |
| | } |
| | return |
| | } |
| |
|
| | |
| | |
| | func isPkgQual(info *types2.Info, sel *syntax.SelectorExpr) bool { |
| | if name, ok := sel.X.(*syntax.Name); ok { |
| | _, isPkgName := info.Uses[name].(*types2.PkgName) |
| | return isPkgName |
| | } |
| | return false |
| | } |
| |
|
| | |
| | |
| | func isNil(p *pkgWriter, expr syntax.Expr) bool { |
| | tv := p.typeAndValue(expr) |
| | return tv.IsNil() |
| | } |
| |
|
| | |
| | |
| | func (pw *pkgWriter) isBuiltin(expr syntax.Expr, builtin string) bool { |
| | if name, ok := syntax.Unparen(expr).(*syntax.Name); ok && name.Value == builtin { |
| | return pw.typeAndValue(name).IsBuiltin() |
| | } |
| | return false |
| | } |
| |
|
| | |
| | func recvBase(recv *types2.Var) *types2.Named { |
| | typ := types2.Unalias(recv.Type()) |
| | if ptr, ok := typ.(*types2.Pointer); ok { |
| | typ = types2.Unalias(ptr.Elem()) |
| | } |
| | return typ.(*types2.Named) |
| | } |
| |
|
| | |
| | func namesAsExpr(names []*syntax.Name) syntax.Expr { |
| | if len(names) == 1 { |
| | return names[0] |
| | } |
| |
|
| | exprs := make([]syntax.Expr, len(names)) |
| | for i, name := range names { |
| | exprs[i] = name |
| | } |
| | return &syntax.ListExpr{ElemList: exprs} |
| | } |
| |
|
| | |
| | func fieldIndex(info *types2.Info, str *types2.Struct, key *syntax.Name) int { |
| | field := info.Uses[key].(*types2.Var) |
| |
|
| | for i := 0; i < str.NumFields(); i++ { |
| | if str.Field(i) == field { |
| | return i |
| | } |
| | } |
| |
|
| | panic(fmt.Sprintf("%s: %v is not a field of %v", key.Pos(), field, str)) |
| | } |
| |
|
| | |
| | func objTypeParams(obj types2.Object) *types2.TypeParamList { |
| | switch obj := obj.(type) { |
| | case *types2.Func: |
| | sig := obj.Type().(*types2.Signature) |
| | if sig.Recv() != nil { |
| | return sig.RecvTypeParams() |
| | } |
| | return sig.TypeParams() |
| | case *types2.TypeName: |
| | switch t := obj.Type().(type) { |
| | case *types2.Named: |
| | return t.TypeParams() |
| | case *types2.Alias: |
| | return t.TypeParams() |
| | } |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | func splitNamed(typ *types2.Named) (*types2.TypeName, *types2.TypeList) { |
| | base.Assertf(typ.TypeParams().Len() == typ.TypeArgs().Len(), "use of uninstantiated type: %v", typ) |
| |
|
| | orig := typ.Origin() |
| | base.Assertf(orig.TypeArgs() == nil, "origin %v of %v has type arguments", orig, typ) |
| | base.Assertf(typ.Obj() == orig.Obj(), "%v has object %v, but %v has object %v", typ, typ.Obj(), orig, orig.Obj()) |
| |
|
| | return typ.Obj(), typ.TypeArgs() |
| | } |
| |
|
| | |
| | func splitAlias(typ *types2.Alias) (*types2.TypeName, *types2.TypeList) { |
| | orig := typ.Origin() |
| | base.Assertf(typ.Obj() == orig.Obj(), "alias type %v has object %v, but %v has object %v", typ, typ.Obj(), orig, orig.Obj()) |
| |
|
| | return typ.Obj(), typ.TypeArgs() |
| | } |
| |
|
| | func asPragmaFlag(p syntax.Pragma) ir.PragmaFlag { |
| | if p == nil { |
| | return 0 |
| | } |
| | return p.(*pragmas).Flag |
| | } |
| |
|
| | func asWasmImport(p syntax.Pragma) *WasmImport { |
| | if p == nil { |
| | return nil |
| | } |
| | return p.(*pragmas).WasmImport |
| | } |
| |
|
| | func asWasmExport(p syntax.Pragma) *WasmExport { |
| | if p == nil { |
| | return nil |
| | } |
| | return p.(*pragmas).WasmExport |
| | } |
| |
|
| | |
| | func isPtrTo(from, to types2.Type) bool { |
| | ptr, ok := types2.Unalias(from).(*types2.Pointer) |
| | return ok && types2.Identical(ptr.Elem(), to) |
| | } |
| |
|
| | |
| | |
| | func hasFallthrough(stmts []syntax.Stmt) bool { |
| | |
| | |
| | stmt := lastNonEmptyStmt(stmts) |
| | for { |
| | ls, ok := stmt.(*syntax.LabeledStmt) |
| | if !ok { |
| | break |
| | } |
| | stmt = ls.Stmt |
| | } |
| | last, ok := stmt.(*syntax.BranchStmt) |
| | return ok && last.Tok == syntax.Fallthrough |
| | } |
| |
|
| | |
| | |
| | func lastNonEmptyStmt(stmts []syntax.Stmt) syntax.Stmt { |
| | for i := len(stmts) - 1; i >= 0; i-- { |
| | stmt := stmts[i] |
| | if _, ok := stmt.(*syntax.EmptyStmt); !ok { |
| | return stmt |
| | } |
| | } |
| | return nil |
| | } |
| |
|
| | |
| | |
| | func (pw *pkgWriter) terminates(stmt syntax.Stmt) bool { |
| | switch stmt := stmt.(type) { |
| | case *syntax.BranchStmt: |
| | if stmt.Tok == syntax.Goto { |
| | return true |
| | } |
| | case *syntax.ReturnStmt: |
| | return true |
| | case *syntax.ExprStmt: |
| | if call, ok := syntax.Unparen(stmt.X).(*syntax.CallExpr); ok { |
| | if pw.isBuiltin(call.Fun, "panic") { |
| | return true |
| | } |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | case *syntax.IfStmt: |
| | cond := pw.staticBool(&stmt.Cond) |
| | return (cond < 0 || pw.terminates(stmt.Then)) && (cond > 0 || pw.terminates(stmt.Else)) |
| | case *syntax.BlockStmt: |
| | return pw.terminates(lastNonEmptyStmt(stmt.List)) |
| | } |
| |
|
| | return false |
| | } |
| |
|