Newer
Older
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
}
}
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)
}
// @@@ Statements
// stmt writes the given statement into the function body bitstream.
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) {
w.Sync(pkgbits.SyncStmts)
for _, stmt := range stmts {
w.stmt1(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)
w.expr(stmt.Rhs)
default:
w.Code(stmtAssign)
w.assignList(stmt.Lhs)
w.exprList(stmt.Rhs)
}
case *syntax.BlockStmt:
w.Code(stmtBlock)
w.blockStmt(stmt)
case *syntax.BranchStmt:
w.Code(stmtBranch)
w.pos(stmt)
w.op(branchOps[stmt.Tok])
w.optLabel(stmt.Label)
case *syntax.CallStmt:
w.Code(stmtCall)
w.pos(stmt)
w.op(callOps[stmt.Tok])
w.expr(stmt.Call)
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)
w.exprList(stmt.Results)
case *syntax.SelectStmt:
w.Code(stmtSelect)
w.selectStmt(stmt)
case *syntax.SendStmt:
w.Code(stmtSend)
w.pos(stmt)
w.expr(stmt.Chan)
w.expr(stmt.Value)
case *syntax.SwitchStmt:
w.Code(stmtSwitch)
w.switchStmt(stmt)
}
}
func (w *writer) assignList(expr syntax.Expr) {
exprs := unpackListExpr(expr)
w.Len(len(exprs))
for _, expr := range exprs {
Matthew Dempsky
committed
w.assign(expr)
}
}
func (w *writer) assign(expr syntax.Expr) {
expr = unparen(expr)
if name, ok := expr.(*syntax.Name); ok {
if name.Value == "_" {
w.Code(assignBlank)
return
Matthew Dempsky
committed
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())
// TODO(mdempsky): Minimize locals index size by deferring
// this until the variables actually come into scope.
w.addLocal(obj)
return
}
Matthew Dempsky
committed
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.Code(stmtAssign)
w.assignList(namesAsExpr(decl.NameList))
w.exprList(decl.Values)
}
}
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.assignList(rang.Lhs)
w.expr(rang.X)
} else {
w.pos(stmt)
w.stmt(stmt.Init)
Matthew Dempsky
committed
w.optExpr(stmt.Cond)
w.stmt(stmt.Post)
}
w.blockStmt(stmt.Body)
w.closeAnotherScope()
}
func (w *writer) ifStmt(stmt *syntax.IfStmt) {
w.Sync(pkgbits.SyncIfStmt)
w.openScope(stmt.Pos())
w.pos(stmt)
w.stmt(stmt.Init)
w.expr(stmt.Cond)
w.blockStmt(stmt.Then)
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 types2.Type
if guard, ok := stmt.Tag.(*syntax.TypeSwitchGuard); w.Bool(ok) {
tv, ok := w.p.info.Types[guard.X]
assert(ok && tv.IsValue())
iface = tv.Type
w.pos(guard)
if tag := guard.Lhs; w.Bool(tag != nil) {
w.pos(tag)
w.String(tag.Value)
}
w.expr(guard.X)
} else {
Matthew Dempsky
committed
w.optExpr(stmt.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)
if iface != nil {
cases := unpackListExpr(clause.Cases)
w.Len(len(cases))
for _, cas := range cases {
w.exprType(iface, cas, true)
}
} else {
w.exprList(clause.Cases)
}
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
if obj, ok := w.p.info.Implicits[clause]; ok {
// TODO(mdempsky): These pos details are quirkish, but also
// necessary so the variable's position is correct for DWARF
// scope assignment later. It would probably be better for us to
// instead just set the variable's DWARF scoping info earlier so
// we can give it the correct position information.
pos := clause.Pos()
if typs := 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)
// TODO(mdempsky): Replace label strings with dense indices.
w.String(label.Value)
}
func (w *writer) optLabel(label *syntax.Name) {
w.Sync(pkgbits.SyncOptLabel)
if w.Bool(label != nil) {
w.label(label)
}
}
// @@@ Expressions
// expr writes the given expression into the function body bitstream.
func (w *writer) expr(expr syntax.Expr) {
Matthew Dempsky
committed
base.Assertf(expr != nil, "missing expression")
expr = unparen(expr) // skip parens; unneeded after typecheck
Robert Griesemer
committed
obj, inst := lookupObj(w.p.info, expr)
targs := inst.TypeArgs
if tv, ok := w.p.info.Types[expr]; ok {
Matthew Dempsky
committed
// TODO(mdempsky): Be more judicious about which types are marked as "needed".
Robert Griesemer
committed
if inst.Type != nil {
w.needType(inst.Type)
} else {
w.needType(tv.Type)
}
Matthew Dempsky
committed
if tv.IsType() {
Matthew Dempsky
committed
w.p.fatalf(expr, "unexpected type expression %v", syntax.String(expr))
}
if tv.Value != nil {
w.Code(exprConst)
w.pos(expr)
w.Value(tv.Value)
// TODO(mdempsky): These details are only important for backend
// diagnostics. Explore writing them out separately.
w.op(constExprOp(expr))
w.String(syntax.String(expr))
return
}
}
if obj != nil {
if isGlobal(obj) {
w.Code(exprGlobal)
w.obj(obj, targs)
return
}
obj := obj.(*types2.Var)
assert(!obj.IsField())
assert(targs.Len() == 0)
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)
w.Code(exprSelector)
Matthew Dempsky
committed
if w.Bool(sel.Kind() == types2.MethodExpr) {
w.exprType(nil, expr.X, false)
} else {
w.expr(expr.X)
}
w.pos(expr)
w.selector(sel.Obj())
case *syntax.IndexExpr:
tv, ok := w.p.info.Types[expr.Index]
assert(ok && tv.IsValue())
w.Code(exprIndex)
w.expr(expr.X)
w.pos(expr)
w.expr(expr.Index)
case *syntax.SliceExpr:
w.Code(exprSlice)
w.expr(expr.X)
w.pos(expr)
for _, n := range &expr.Index {
Matthew Dempsky
committed
w.optExpr(n)
}
case *syntax.AssertExpr:
tv, ok := w.p.info.Types[expr.X]
assert(ok && tv.IsValue())
w.Code(exprAssert)
w.expr(expr.X)
w.pos(expr)
w.exprType(tv.Type, expr.Type, false)
case *syntax.Operation:
if expr.Y == nil {
w.Code(exprUnaryOp)
w.op(unOps[expr.Op])
w.pos(expr)
w.expr(expr.X)
break
}
w.Code(exprBinaryOp)
w.op(binOps[expr.Op])
w.expr(expr.X)
w.pos(expr)
w.expr(expr.Y)
case *syntax.CallExpr:
tv, ok := w.p.info.Types[expr.Fun]
assert(ok)
if tv.IsType() {
assert(len(expr.ArgList) == 1)
assert(!expr.HasDots)
w.Code(exprConvert)
w.typ(tv.Type)
w.pos(expr)
w.expr(expr.ArgList[0])
break
}
Matthew Dempsky
committed
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
if name, ok := unparen(expr.Fun).(*syntax.Name); ok && tv.IsBuiltin() {
switch name.Value {
case "make":
assert(len(expr.ArgList) >= 1)
assert(!expr.HasDots)
w.Code(exprMake)
w.pos(expr)
w.exprType(nil, expr.ArgList[0], false)
w.exprs(expr.ArgList[1:])
return
case "new":
assert(len(expr.ArgList) == 1)
assert(!expr.HasDots)
w.Code(exprNew)
w.pos(expr)
w.exprType(nil, expr.ArgList[0], false)
return
}
}
writeFunExpr := func() {
if selector, ok := unparen(expr.Fun).(*syntax.SelectorExpr); ok {
if sel, ok := w.p.info.Selections[selector]; ok && sel.Kind() == types2.MethodVal {
w.expr(selector.X)
w.Bool(true) // method call
w.pos(selector)
w.selector(sel.Obj())
return
}
}
Robert Griesemer
committed
w.expr(expr.Fun)
w.Bool(false) // not a method call (i.e., normal function call)
w.Code(exprCall)
writeFunExpr()
if w.Bool(len(expr.ArgList) == 1 && isMultiValueExpr(w.p.info, expr.ArgList[0])) {
// f(g()) call
assert(!expr.HasDots)
w.expr(expr.ArgList[0])
} else {
w.exprs(expr.ArgList)
w.Bool(expr.HasDots)
}
Matthew Dempsky
committed
func (w *writer) optExpr(expr syntax.Expr) {
if w.Bool(expr != nil) {
w.expr(expr)
}
}
func (w *writer) compLit(lit *syntax.CompositeLit) {
tv, ok := w.p.info.Types[lit]
assert(ok)
w.Sync(pkgbits.SyncCompLit)
w.pos(lit)
w.typ(tv.Type)
typ := tv.Type
if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok {
typ = ptr.Elem()
}
str, isStruct := types2.CoreType(typ).(*types2.Struct)
w.Len(len(lit.ElemList))
for i, elem := range lit.ElemList {
if isStruct {
if kv, ok := elem.(*syntax.KeyValueExpr); ok {
// use position of expr.Key rather than of elem (which has position of ':')
w.pos(kv.Key)
w.Len(fieldIndex(w.p.info, str, kv.Key.(*syntax.Name)))
elem = kv.Value
} else {
w.pos(elem)
}
} else {
if kv, ok := elem.(*syntax.KeyValueExpr); w.Bool(ok) {
// use position of expr.Key rather than of elem (which has position of ':')
w.pos(kv.Key)
w.expr(kv.Key)
elem = kv.Value
}
}
w.pos(elem)
w.expr(elem)
}
}
func (w *writer) funcLit(expr *syntax.FuncLit) {
tv, ok := w.p.info.Types[expr]
assert(ok)
sig := tv.Type.(*types2.Signature)
body, closureVars := w.p.bodyIdx(sig, expr.Body, w.dict)
w.Sync(pkgbits.SyncFuncLit)
w.pos(expr)
w.signature(sig)
w.Len(len(closureVars))
for _, cv := range closureVars {
w.pos(cv.pos)
w.useLocal(cv.pos, cv.var_)
w.Reloc(pkgbits.RelocBody, body)
type posVar struct {
pos syntax.Pos
var_ *types2.Var
}
func (w *writer) exprList(expr syntax.Expr) {
w.Sync(pkgbits.SyncExprList)
w.exprs(unpackListExpr(expr))
}
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) exprType(iface types2.Type, typ syntax.Expr, nilOK bool) {
base.Assertf(iface == nil || isInterface(iface), "%v must be nil or an interface type", iface)
tv, ok := w.p.info.Types[typ]
assert(ok)
w.Sync(pkgbits.SyncExprType)
if nilOK && w.Bool(tv.IsNil()) {
return
}
assert(tv.IsType())
info := w.p.typIdx(tv.Type, w.dict)
w.pos(typ)
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
if w.Bool(info.derived && iface != nil && !iface.Underlying().(*types2.Interface).Empty()) {
ifaceInfo := w.p.typIdx(iface, w.dict)
idx := -1
for i, itab := range w.dict.itabs {
if itab.typIdx == info.idx && itab.iface == ifaceInfo {
idx = i
}
}
if idx < 0 {
idx = len(w.dict.itabs)
w.dict.itabs = append(w.dict.itabs, itabInfo{typIdx: info.idx, iface: ifaceInfo})
}
w.Len(idx)
return
}
w.typInfo(info)
}
// isInterface reports whether typ is known to be an interface type.
// If typ is a type parameter, then isInterface reports an internal
// compiler error instead.
func isInterface(typ types2.Type) bool {
if _, ok := typ.(*types2.TypeParam); ok {
// typ is a type parameter and may be instantiated as either a
// concrete or interface type, so the writer can't depend on
// knowing this.
base.Fatalf("%v is a type parameter", typ)
}
_, ok := typ.Underlying().(*types2.Interface)
return ok
}
// op writes an Op into the bitstream.
func (w *writer) op(op ir.Op) {
// TODO(mdempsky): Remove in favor of explicit codes? Would make
// export data more stable against internal refactorings, but low
// priority at the moment.
assert(op != 0)
w.Sync(pkgbits.SyncOp)
w.Len(int(op))
Matthew Dempsky
committed
func (w *writer) needType(typ types2.Type) {
// Decompose tuple into component element types.
if typ, ok := typ.(*types2.Tuple); ok {
for i := 0; i < typ.Len(); i++ {
w.needType(typ.At(i).Type())
}
return
}
if info := w.p.typIdx(typ, w.dict); info.derived {
w.dict.derived[info.idx].needed = true
}
}
// @@@ Package initialization
// Caution: This code is still clumsy, because toolstash -cmp is
// particularly sensitive to it.
type typeDeclGen struct {
*syntax.TypeDecl
gen int
// Implicit type parameters in scope at this type declaration.
implicits []*types2.TypeName
type fileImports struct {
importedEmbed, importedUnsafe bool
}
// declCollector is a visitor type that collects compiler-needed
// information about declarations that types2 doesn't track.
//
// Notably, it maps declared types and functions back to their
// declaration statement, keeps track of implicit type parameters, and
// assigns unique type "generation" numbers to local defined types.
type declCollector struct {
pw *pkgWriter
typegen *int
file *fileImports
withinFunc bool
implicits []*types2.TypeName
}
func (c *declCollector) withTParams(obj types2.Object) *declCollector {
tparams := objTypeParams(obj)
Robert Griesemer
committed
n := tparams.Len()
if n == 0 {
return c
}
copy := *c
copy.implicits = copy.implicits[:len(copy.implicits):len(copy.implicits)]
Robert Griesemer
committed
for i := 0; i < n; i++ {
Robert Griesemer
committed
copy.implicits = append(copy.implicits, tparams.At(i).Obj())
Robert Griesemer
committed
}
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 pkgNameOf(pw.info, 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, typePragmas, false)
// Assign a unique ID to function-scoped defined types.
if c.withinFunc {
*c.typegen++
d.gen = *c.typegen
}
}
pw.typDecls[obj] = d
// TODO(mdempsky): Omit? Not strictly necessary; only matters for
// type declarations within function literals within parameterized
// type declarations, but types2 the function literals will be
// constant folded away.
return c.withTParams(obj)
case *syntax.VarDecl:
pw.checkPragmas(n.Pragma, 0, true)
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
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
}
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:
pw.errorf(l.pos, "//go:linkname must refer to declared function or variable")
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
}
}
}
}
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.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) 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 // skip blank functions
}
obj := w.p.info.Defs[decl.Name].(*types2.Func)
sig := obj.Type().(*types2.Signature)
if sig.RecvTypeParams() != nil || sig.TypeParams() != nil {
break // skip generic functions
}
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 // skip generic type decls
}
if decl.Name.Value == "_" {
break // skip blank type decls
}
name := w.p.info.Defs[decl.Name].(*types2.TypeName)
// Skip type declarations for interfaces that are only usable as
// type parameter bounds.
Robert Griesemer
committed
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.pos(decl)
w.pkgObjs(decl.NameList...)
w.exprList(decl.Values)
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)
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
w.obj(obj, nil)
}
}
// @@@ Helpers
// isDefinedType reports whether obj is a defined type.
func isDefinedType(obj types2.Object) bool {
if obj, ok := obj.(*types2.TypeName); ok {
return !obj.IsAlias()
}
return false
}
// isGlobal reports whether obj was declared at package scope.
//
// Caveat: blank objects are not declared.
func isGlobal(obj types2.Object) bool {
return obj.Parent() == obj.Pkg().Scope()
}
// lookupObj returns the object that expr refers to, if any. If expr
Robert Griesemer
committed
// is an explicit instantiation of a generic object, then the instance
// object is returned as well.
func lookupObj(info *types2.Info, expr syntax.Expr) (obj types2.Object, inst types2.Instance) {
if index, ok := expr.(*syntax.IndexExpr); ok {
Robert Griesemer
committed
args := unpackListExpr(index.Index)
if len(args) == 1 {
tv, ok := info.Types[args[0]]
assert(ok)
if tv.IsValue() {
return // normal index expression
}
}
expr = index.X
}
// Strip package qualifier, if present.
if sel, ok := expr.(*syntax.SelectorExpr); ok {
if !isPkgQual(info, sel) {
return // normal selector expression
}
expr = sel.Sel
}
if name, ok := expr.(*syntax.Name); ok {
Robert Griesemer
committed
obj = info.Uses[name]
inst = info.Instances[name]
}
return
}
// isPkgQual reports whether the given selector expression is a
// package-qualified identifier.
func isPkgQual(info *types2.Info, sel *syntax.SelectorExpr) bool {