Newer
Older
w.stmts(block.List)
w.pos(block.Rbrace)
}
return w.Flush(), w.closureVars
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
}
func (w *writer) funcargs(sig *types2.Signature) {
do := func(params *types2.Tuple, result bool) {
for i := 0; i < params.Len(); i++ {
w.funcarg(params.At(i), result)
}
}
if recv := sig.Recv(); recv != nil {
w.funcarg(recv, false)
}
do(sig.Params(), false)
do(sig.Results(), true)
}
func (w *writer) funcarg(param *types2.Var, result bool) {
if param.Name() != "" || result {
w.addLocal(param)
}
}
// addLocal records the declaration of a new local variable.
func (w *writer) addLocal(obj *types2.Var) {
w.Sync(pkgbits.SyncAddLocal)
idx := len(w.localsIdx)
if w.p.SyncMarkers() {
if w.localsIdx == nil {
w.localsIdx = make(map[*types2.Var]int)
}
w.localsIdx[obj] = idx
}
// useLocal writes a reference to the given local or free variable
// into the bitstream.
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
}
}
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)
Matthew Dempsky
committed
var typ types2.Type
if stmt.Op != syntax.Shl && stmt.Op != syntax.Shr {
typ = w.p.typeOf(stmt.Lhs)
}
w.implicitConvExpr(stmt, typ, stmt.Rhs)
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)
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)
resultTypes := w.sig.Results()
Matthew Dempsky
committed
dstType := func(i int) types2.Type {
return resultTypes.At(i).Type()
}
Matthew Dempsky
committed
w.multiExpr(stmt, dstType, unpackListExpr(stmt.Results))
case *syntax.SelectStmt:
w.Code(stmtSelect)
w.selectStmt(stmt)
case *syntax.SendStmt:
Matthew Dempsky
committed
chanType := types2.CoreType(w.p.typeOf(stmt.Chan)).(*types2.Chan)
w.Code(stmtSend)
w.pos(stmt)
w.expr(stmt.Chan)
w.implicitConvExpr(stmt, chanType.Elem(), 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.assignStmt(decl, namesAsExpr(decl.NameList), decl.Values)
// assignStmt writes out an assignment for "lhs = rhs".
Matthew Dempsky
committed
func (w *writer) assignStmt(pos poser, lhs0, rhs0 syntax.Expr) {
lhs := unpackListExpr(lhs0)
rhs := unpackListExpr(rhs0)
w.Code(stmtAssign)
w.pos(pos)
Matthew Dempsky
committed
// As if w.assignList(lhs0).
w.Len(len(lhs))
for _, expr := range lhs {
w.assign(expr)
}
Matthew Dempsky
committed
dstType := func(i int) types2.Type {
dst := lhs[i]
// Finding dstType is somewhat involved, because for VarDecl
// statements, the Names are only added to the info.{Defs,Uses}
// maps, not to info.Types.
if name, ok := unparen(dst).(*syntax.Name); ok {
if name.Value == "_" {
return nil // ok: no implicit conversion
} 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()
Matthew Dempsky
committed
} else {
Matthew Dempsky
committed
w.p.fatalf(dst, "cannot find type of destination object: %v", dst)
Matthew Dempsky
committed
}
}
Matthew Dempsky
committed
return w.p.typeOf(dst)
Matthew Dempsky
committed
}
Matthew Dempsky
committed
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.assignList(rang.Lhs)
w.expr(rang.X)
xtyp := w.p.typeOf(rang.X)
if _, isMap := types2.CoreType(xtyp).(*types2.Map); isMap {
w.rtype(xtyp)
}
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
{
lhs := unpackListExpr(rang.Lhs)
assign := func(i int, src types2.Type) {
if i >= len(lhs) {
return
}
dst := unparen(lhs[i])
if name, ok := dst.(*syntax.Name); ok && name.Value == "_" {
return
}
var dstType types2.Type
if rang.Def {
// For `:=` assignments, the LHS names only appear in Defs,
// not Types (as used by typeOf).
dstType = w.p.info.Defs[dst.(*syntax.Name)].(*types2.Var).Type()
} else {
dstType = w.p.typeOf(dst)
}
w.convRTTI(src, dstType)
}
keyType, valueType := w.p.rangeTypes(rang.X)
assign(0, keyType)
assign(1, valueType)
}
} 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()
}
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
// rangeTypes returns the types of values produced by ranging over
// expr.
func (pw *pkgWriter) rangeTypes(expr syntax.Expr) (key, value types2.Type) {
typ := pw.typeOf(expr)
switch typ := types2.CoreType(typ).(type) {
case *types2.Pointer: // must be pointer to array
return types2.Typ[types2.Int], types2.CoreType(typ.Elem()).(*types2.Array).Elem()
case *types2.Array:
return types2.Typ[types2.Int], typ.Elem()
case *types2.Slice:
return types2.Typ[types2.Int], typ.Elem()
case *types2.Basic:
if typ.Info()&types2.IsString != 0 {
return types2.Typ[types2.Int], runeTypeName.Type()
}
case *types2.Map:
return typ.Key(), typ.Elem()
case *types2.Chan:
return typ.Elem(), nil
}
pw.fatalf(expr, "unexpected range type: %v", typ)
panic("unreachable")
}
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, tagType types2.Type
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.String(tag.Value)
}
w.expr(guard.X)
} else {
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
tag := stmt.Tag
if tag != nil {
tagType = w.p.typeOf(tag)
} else {
tagType = types2.Typ[types2.Bool]
}
// Walk is going to emit comparisons between the tag value and
// each case expression, and we want these comparisons to always
// have the same type. If there are any case values that can't be
// converted to the tag value's type, then convert everything to
// `any` instead.
Outer:
for _, clause := range stmt.Body {
for _, cas := range unpackListExpr(clause.Cases) {
if casType := w.p.typeOf(cas); !types2.AssignableTo(casType, tagType) {
tagType = types2.NewInterfaceType(nil, nil)
break Outer
}
}
}
if w.Bool(tag != nil) {
w.implicitConvExpr(tag, 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 := unpackListExpr(clause.Cases)
if iface != nil {
w.Len(len(cases))
for _, cas := range cases {
if w.Bool(isNil(w.p.info, cas)) {
continue
}
w.exprType(iface, cas)
}
} else {
// As if w.exprList(clause.Cases),
// but with implicit conversions to tagType.
w.Sync(pkgbits.SyncExprList)
w.Sync(pkgbits.SyncExprs)
w.Len(len(cases))
for _, cas := range cases {
w.implicitConvExpr(cas, tagType, cas)
}
}
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
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 {
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)
Cuong Manh Le
committed
typ := idealType(tv)
assert(typ != nil)
w.typ(typ)
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))
if _, isNil := obj.(*types2.Nil); isNil {
w.Code(exprNil)
w.pos(expr)
w.typ(tv.Type)
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) {
tv, ok := w.p.info.Types[expr.X]
assert(ok)
assert(tv.IsType())
typInfo := w.p.typIdx(tv.Type, w.dict)
if w.Bool(typInfo.derived) {
methodInfo := w.p.selectorIdx(sel.Obj())
idx := w.dict.methodExprIdx(typInfo, methodInfo)
w.Len(idx)
break
}
w.typInfo(typInfo)
Matthew Dempsky
committed
} else {
w.expr(expr.X)
}
w.pos(expr)
w.selector(sel.Obj())
case *syntax.IndexExpr:
_ = w.p.typeOf(expr.Index) // ensure this is an index expression, not an instantiation
xtyp := w.p.typeOf(expr.X)
Matthew Dempsky
committed
var keyType types2.Type
if mapType, ok := types2.CoreType(xtyp).(*types2.Map); ok {
Matthew Dempsky
committed
keyType = mapType.Key()
}
w.Code(exprIndex)
w.expr(expr.X)
w.pos(expr)
w.implicitConvExpr(expr, 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 {
Matthew Dempsky
committed
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
}
Matthew Dempsky
committed
var commonType types2.Type
switch expr.Op {
case syntax.Shl, syntax.Shr:
// ok: operands are allowed to have different types
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])
Matthew Dempsky
committed
w.implicitConvExpr(expr, commonType, expr.X)
Matthew Dempsky
committed
w.implicitConvExpr(expr, commonType, 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)
Matthew Dempsky
committed
w.Bool(false) // explicit
w.typ(tv.Type)
w.pos(expr)
w.convRTTI(w.p.typeOf(expr.ArgList[0]), tv.Type)
Cuong Manh Le
committed
w.Bool(isTypeParam(tv.Type))
w.expr(expr.ArgList[0])
break
}
var rtype types2.Type
if tv.IsBuiltin() {
switch obj, _ := lookupObj(w.p.info, expr.Fun); obj.Name() {
Matthew Dempsky
committed
case "make":
assert(len(expr.ArgList) >= 1)
assert(!expr.HasDots)
w.Code(exprMake)
w.pos(expr)
w.exprType(nil, expr.ArgList[0])
Matthew Dempsky
committed
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))
}
Matthew Dempsky
committed
return
case "new":
assert(len(expr.ArgList) == 1)
assert(!expr.HasDots)
w.Code(exprNew)
w.pos(expr)
w.exprType(nil, expr.ArgList[0])
Matthew Dempsky
committed
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 { // "copy(g())"
typ = tuple.At(0).Type()
}
rtype = sliceElem(typ)
case "delete":
typ := w.p.typeOf(expr.ArgList[0])
if tuple, ok := typ.(*types2.Tuple); ok { // "delete(g())"
typ = tuple.At(0).Type()
}
rtype = typ
case "Slice":
rtype = sliceElem(w.p.typeOf(expr))
Matthew Dempsky
committed
}
}
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)
Matthew Dempsky
committed
sigType := types2.CoreType(tv.Type).(*types2.Signature)
paramTypes := sigType.Params()
w.Code(exprCall)
writeFunExpr()
Matthew Dempsky
committed
Matthew Dempsky
committed
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()
Matthew Dempsky
committed
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()
}
Matthew Dempsky
committed
func (w *writer) optExpr(expr syntax.Expr) {
if w.Bool(expr != nil) {
w.expr(expr)
}
}
Matthew Dempsky
committed
// multiExpr writes a sequence of expressions, where the i'th value is
// implicitly converted to dstType(i). It also handles when exprs is a
// single, multi-valued expression (e.g., the multi-valued argument in
// an f(g()) call, or the RHS operand in a comma-ok assignment).
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)
Matthew Dempsky
committed
w.Bool(true) // N:1 assignment
w.pos(pos)
w.expr(expr)
w.Len(tuple.Len())
for i := 0; i < tuple.Len(); i++ {
src := tuple.At(i).Type()
// TODO(mdempsky): Investigate not writing src here. I think
// the reader should be able to infer it from expr anyway.
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)
Matthew Dempsky
committed
}
}
Matthew Dempsky
committed
return
}
}
Matthew Dempsky
committed
w.Bool(false) // N:N assignment
w.Len(len(exprs))
Matthew Dempsky
committed
for i, expr := range exprs {
w.implicitConvExpr(pos, dstType(i), expr)
}
}
// implicitConvExpr is like expr, but if dst is non-nil and different from
Matthew Dempsky
committed
// expr's type, then an implicit conversion operation is inserted at
// pos.
func (w *writer) implicitConvExpr(pos poser, dst types2.Type, expr syntax.Expr) {
Matthew Dempsky
committed
src := w.p.typeOf(expr)
if dst != nil && !types2.Identical(src, dst) {
if !types2.AssignableTo(src, dst) {
w.p.fatalf(pos, "%v is not assignable to %v", src, dst)
}
w.Code(exprConvert)
w.Bool(true) // implicit
w.typ(dst)
w.pos(pos)
w.convRTTI(src, dst)
Cuong Manh Le
committed
w.Bool(isTypeParam(dst))
Matthew Dempsky
committed
// fallthrough
}
w.expr(expr)
}
func (w *writer) compLit(lit *syntax.CompositeLit) {
typ := w.p.typeOf(lit)
w.Sync(pkgbits.SyncCompLit)
w.typ(typ)
if ptr, ok := types2.CoreType(typ).(*types2.Pointer); ok {
typ = ptr.Elem()
}
Matthew Dempsky
committed
var keyType, elemType types2.Type
var structType *types2.Struct
switch typ0 := typ; typ := types2.CoreType(typ).(type) {
Matthew Dempsky
committed
default:
w.p.fatalf(lit, "unexpected composite literal type: %v", typ)
case *types2.Array:
elemType = typ.Elem()
case *types2.Map:
w.rtype(typ0)
Matthew Dempsky
committed
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 {
Matthew Dempsky
committed
elemType := elemType
if structType != nil {
if kv, ok := elem.(*syntax.KeyValueExpr); ok {
// use position of expr.Key rather than of elem (which has position of ':')
w.pos(kv.Key)
Matthew Dempsky
committed
i = fieldIndex(w.p.info, structType, kv.Key.(*syntax.Name))
elem = kv.Value
} else {
w.pos(elem)
}
Matthew Dempsky
committed
elemType = structType.Field(i).Type()
w.Len(i)
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.implicitConvExpr(kv.Key, keyType, kv.Key)
elem = kv.Value
}
}
w.pos(elem)
w.implicitConvExpr(elem, 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.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)
}
}
// rtype writes information so that the reader can construct an
// expression of type *runtime._type representing typ.
func (w *writer) rtype(typ types2.Type) {
w.Sync(pkgbits.SyncRType)
w.typNeeded(typ)
}
// typNeeded writes a reference to typ, and records that its
// *runtime._type is needed.
func (w *writer) typNeeded(typ types2.Type) {
info := w.p.typIdx(typ, w.dict)
w.typInfo(info)
if info.derived {
w.dict.derived[info.idx].needed = true
}
}
// convRTTI writes information so that the reader can construct
// expressions for converting from src to dst.
func (w *writer) convRTTI(src, dst types2.Type) {
w.Sync(pkgbits.SyncConvRTTI)
w.typNeeded(src)
w.typNeeded(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, ok := w.p.info.Types[typ]
assert(ok)
assert(tv.IsType())
info := w.p.typIdx(tv.Type, w.dict)
w.Sync(pkgbits.SyncExprType)
w.pos(typ)
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)
if info.derived {
w.dict.derived[info.idx].needed = true
}