Newer
Older
// least.
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")
}
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 {
// Stack growth can't handle uintptr arguments that may
// be pointers (as we don't know which are pointers
// when creating the stack map). Thus uintptrkeepalive
// functions (and all transitive callees) must be
// nosplit.
//
// N.B. uintptrescapes implies uintptrkeepalive but it
// is OK since the arguments must escape to the heap.
//
// TODO(prattmic): Add recursive nosplit check of callees.
// TODO(prattmic): Functions with no body (i.e.,
// assembly) must also be nosplit, but we can't check
// that here.
w.p.errorf(decl, "go:uintptrkeepalive requires go:nosplit")
}
} else {
if base.Flag.Complete || decl.Name.Value == "init" {
// Linknamed functions are allowed to have no body. Hopefully
// the linkname target has a body. See issue 23311.
// Wasmimport functions are also allowed to have no body.
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)
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("")
}
}
w.Bool(false) // stub extension
w.Reloc(pkgbits.RelocBody, 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))
// No LSym.SymIdx info yet.
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))
}
// @@@ Function bodies
// bodyIdx returns the index for the given function body (specified by
// block), adding it to the export data
func (pw *pkgWriter) bodyIdx(sig *types2.Signature, block *syntax.BlockStmt, dict *writerDict) (idx pkgbits.Index, closureVars []posVar) {
w := pw.newWriter(pkgbits.RelocBody, pkgbits.SyncFuncBody)
w.sig = sig
w.dict = dict
w.funcargs(sig)
if w.Bool(block != nil) {
w.stmts(block.List)
w.pos(block.Rbrace)
}
return w.Flush(), w.closureVars
}
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) {
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
}
// 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(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(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)
Matthew Dempsky
committed
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)
}
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
{
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.Bool(base.Debug.LoopVar > 0)
w.closeAnotherScope()
}
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
// 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)
// Like w.localIdent, but we don't have a types2.Object.
w.Sync(pkgbits.SyncLocalIdent)
w.pkg(w.p.curpkg)
w.String(tag.Value)
}
w.expr(guard.X)
} else {
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
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(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, 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(tagType, cas)
}
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
obj, inst := lookupObj(w.p, expr)
Robert Griesemer
committed
targs := inst.TypeArgs
if tv, ok := w.p.maybeTypeAndValue(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
}
// With shape types (and particular pointer shaping), we may have
// an expression of type "go.shape.*uint8", but need to reshape it
// to another shape-identical type to allow use in field
// selection, indexing, etc.
if typ := tv.Type; !tv.IsBuiltin() && !isTuple(typ) && !isUntyped(typ) {
w.Code(exprReshape)
w.typ(typ)
// fallthrough
}
}
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)) { // need deref
typ = recv
} else if w.Bool(isPtrTo(recv, typ)) { // need addr
typ = recv
}
w.pos(expr)
w.methodExpr(expr, typ, sel)
Matthew Dempsky
committed
}
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(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])
w.implicitConvExpr(commonType, expr.X)
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, 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() {
fun := 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) // method call
typ := w.recvExpr(selector, sel)
w.methodExpr(selector, typ, sel)
return
}
}
w.Bool(false) // not a method call (i.e., normal function call)
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)
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)
}
}
// recvExpr writes out expr.X, but handles any implicit addressing,
// dereferencing, and field selections appropriate for the method
// selection.
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
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)) { // needs deref
typ = recv
} else if w.Bool(isPtrTo(recv, typ)) { // needs addr
typ = recv
}
return typ
}
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
// funcInst writes a reference to an instantiated function.
func (w *writer) funcInst(obj *types2.Func, targs *types2.TypeList) {
info := w.p.objInstIdx(obj, targs, w.dict)
// Type arguments list contains derived types; we can emit a static
// call to the shaped function, but need to dynamically compute the
// runtime dictionary pointer.
if w.Bool(info.anyDerived()) {
w.Len(w.dict.subdictIdx(info))
return
}
// Type arguments list is statically known; we can emit a static
// call with a statically reference to the respective runtime
// dictionary.
w.objInfo(info)
}
// methodExpr writes out a reference to the method selected by
// expr. sel should be the corresponding types2.Selection, and recv
// the type produced after any implicit addressing, dereferencing, and
// field selection. (Note: recv might differ from sel.Obj()'s receiver
// parameter in the case of interface types, and is needed for
// handling type parameter methods.)
func (w *writer) methodExpr(expr *syntax.SelectorExpr, recv types2.Type, sel *types2.Selection) {