import (
"bufio"
"cmd/compile/internal/base"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/obj/x86"
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
return typenamesym(t).Linksym()
}
- TypecheckInit()
+ typecheck.Init()
os.Exit(m.Run())
}
import (
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
func mkParamResultField(t *types.Type, s *types.Sym, which ir.Class) *types.Field {
field := types.NewField(src.NoXPos, s, t)
- n := NewName(s)
+ n := typecheck.NewName(s)
n.Class_ = which
field.Nname = n
n.SetType(t)
}
func mkFuncType(rcvr *types.Type, ins []*types.Type, outs []*types.Type) *types.Type {
- q := lookup("?")
+ q := typecheck.Lookup("?")
inf := []*types.Field{}
for _, it := range ins {
inf = append(inf, mkParamResultField(it, q, ir.PPARAM))
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"fmt"
return closure
}
if memhashvarlen == nil {
- memhashvarlen = sysfunc("memhash_varlen")
+ memhashvarlen = typecheck.LookupRuntimeFunc("memhash_varlen")
}
ot := 0
ot = dsymptr(closure, ot, memhashvarlen, 0)
}
base.Pos = base.AutogeneratedPos // less confusing than end of input
- dclcontext = ir.PEXTERN
+ typecheck.DeclContext = ir.PEXTERN
// func sym(p *T, h uintptr) uintptr
args := []*ir.Field{
- ir.NewField(base.Pos, lookup("p"), nil, types.NewPtr(t)),
- ir.NewField(base.Pos, lookup("h"), nil, types.Types[types.TUINTPTR]),
+ ir.NewField(base.Pos, typecheck.Lookup("p"), nil, types.NewPtr(t)),
+ ir.NewField(base.Pos, typecheck.Lookup("h"), nil, types.Types[types.TUINTPTR]),
}
results := []*ir.Field{ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR])}
tfn := ir.NewFuncType(base.Pos, nil, args, results)
- fn := dclfunc(sym, tfn)
+ fn := typecheck.DeclFunc(sym, tfn)
np := ir.AsNode(tfn.Type().Params().Field(0).Nname)
nh := ir.AsNode(tfn.Type().Params().Field(1).Nname)
hashel := hashfor(t.Elem())
// for i := 0; i < nelem; i++
- ni := temp(types.Types[types.TINT])
+ ni := typecheck.Temp(types.Types[types.TINT])
init := ir.NewAssignStmt(base.Pos, ni, ir.NewInt(0))
cond := ir.NewBinaryExpr(base.Pos, ir.OLT, ni, ir.NewInt(t.NumElem()))
post := ir.NewAssignStmt(base.Pos, ni, ir.NewBinaryExpr(base.Pos, ir.OADD, ni, ir.NewInt(1)))
nx := ir.NewIndexExpr(base.Pos, np, ni)
nx.SetBounded(true)
- na := nodAddr(nx)
+ na := typecheck.NodAddr(nx)
call.Args.Append(na)
call.Args.Append(nh)
loop.Body.Append(ir.NewAssignStmt(base.Pos, nh, call))
hashel := hashfor(f.Type)
call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
- na := nodAddr(nx)
+ na := typecheck.NodAddr(nx)
call.Args.Append(na)
call.Args.Append(nh)
fn.Body.Append(ir.NewAssignStmt(base.Pos, nh, call))
hashel := hashmem(f.Type)
call := ir.NewCallExpr(base.Pos, ir.OCALL, hashel, nil)
nx := ir.NewSelectorExpr(base.Pos, ir.OXDOT, np, f.Sym) // TODO: fields from other packages?
- na := nodAddr(nx)
+ na := typecheck.NodAddr(nx)
call.Args.Append(na)
call.Args.Append(nh)
call.Args.Append(ir.NewInt(size))
ir.DumpList("genhash body", fn.Body)
}
- funcbody()
+ typecheck.FinishFuncBody()
fn.SetDupok(true)
- typecheckFunc(fn)
+ typecheck.Func(fn)
ir.CurFunc = fn
- typecheckslice(fn.Body, ctxStmt)
+ typecheck.Stmts(fn.Body)
ir.CurFunc = nil
if base.Debug.DclStack != 0 {
}
fn.SetNilCheckDisabled(true)
- Target.Decls = append(Target.Decls, fn)
+ typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
// Build closure. It doesn't close over any variables, so
// it contains just the function pointer.
sym = typesymprefix(".hash", t)
}
- n := NewName(sym)
+ n := typecheck.NewName(sym)
ir.MarkFunc(n)
- n.SetType(functype(nil, []*ir.Field{
+ n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
}, []*ir.Field{
// sysClosure returns a closure which will call the
// given runtime function (with no closed-over variables).
func sysClosure(name string) *obj.LSym {
- s := sysvar(name + "·f")
+ s := typecheck.LookupRuntimeVar(name + "·f")
if len(s.P) == 0 {
- f := sysfunc(name)
+ f := typecheck.LookupRuntimeFunc(name)
dsymptr(s, 0, f, 0)
ggloblsym(s, int32(types.PtrSize), obj.DUPOK|obj.RODATA)
}
return closure
}
if memequalvarlen == nil {
- memequalvarlen = sysvar("memequal_varlen") // asm func
+ memequalvarlen = typecheck.LookupRuntimeVar("memequal_varlen") // asm func
}
ot := 0
ot = dsymptr(closure, ot, memequalvarlen, 0)
// Autogenerate code for equality of structs and arrays.
base.Pos = base.AutogeneratedPos // less confusing than end of input
- dclcontext = ir.PEXTERN
+ typecheck.DeclContext = ir.PEXTERN
// func sym(p, q *T) bool
tfn := ir.NewFuncType(base.Pos, nil,
- []*ir.Field{ir.NewField(base.Pos, lookup("p"), nil, types.NewPtr(t)), ir.NewField(base.Pos, lookup("q"), nil, types.NewPtr(t))},
- []*ir.Field{ir.NewField(base.Pos, lookup("r"), nil, types.Types[types.TBOOL])})
+ []*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("p"), nil, types.NewPtr(t)), ir.NewField(base.Pos, typecheck.Lookup("q"), nil, types.NewPtr(t))},
+ []*ir.Field{ir.NewField(base.Pos, typecheck.Lookup("r"), nil, types.Types[types.TBOOL])})
- fn := dclfunc(sym, tfn)
+ fn := typecheck.DeclFunc(sym, tfn)
np := ir.AsNode(tfn.Type().Params().Field(0).Nname)
nq := ir.AsNode(tfn.Type().Params().Field(1).Nname)
nr := ir.AsNode(tfn.Type().Results().Field(0).Nname)
// Label to jump to if an equality test fails.
- neq := autolabel(".neq")
+ neq := typecheck.AutoLabel(".neq")
// We reach here only for types that have equality but
// cannot be handled by the standard algorithms,
} else {
// Generate a for loop.
// for i := 0; i < nelem; i++
- i := temp(types.Types[types.TINT])
+ i := typecheck.Temp(types.Types[types.TINT])
init := ir.NewAssignStmt(base.Pos, i, ir.NewInt(0))
cond := ir.NewBinaryExpr(base.Pos, ir.OLT, i, ir.NewInt(nelem))
post := ir.NewAssignStmt(base.Pos, i, ir.NewBinaryExpr(base.Pos, ir.OADD, i, ir.NewInt(1)))
// ret:
// return
- ret := autolabel(".ret")
+ ret := typecheck.AutoLabel(".ret")
fn.Body.Append(ir.NewLabelStmt(base.Pos, ret))
fn.Body.Append(ir.NewReturnStmt(base.Pos, nil))
ir.DumpList("geneq body", fn.Body)
}
- funcbody()
+ typecheck.FinishFuncBody()
fn.SetDupok(true)
- typecheckFunc(fn)
+ typecheck.Func(fn)
ir.CurFunc = fn
- typecheckslice(fn.Body, ctxStmt)
+ typecheck.Stmts(fn.Body)
ir.CurFunc = nil
if base.Debug.DclStack != 0 {
// neither of which can be nil, and our comparisons
// are shallow.
fn.SetNilCheckDisabled(true)
- Target.Decls = append(Target.Decls, fn)
+ typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
// Generate a closure which points at the function we just generated.
dsymptr(closure, 0, sym.Linksym(), 0)
// which can be used to construct string equality comparison.
// eqlen must be evaluated before eqmem, and shortcircuiting is required.
func eqstring(s, t ir.Node) (eqlen *ir.BinaryExpr, eqmem *ir.CallExpr) {
- s = conv(s, types.Types[types.TSTRING])
- t = conv(t, types.Types[types.TSTRING])
+ s = typecheck.Conv(s, types.Types[types.TSTRING])
+ t = typecheck.Conv(t, types.Types[types.TSTRING])
sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
tptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, t)
- slen := conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, s), types.Types[types.TUINTPTR])
- tlen := conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, t), types.Types[types.TUINTPTR])
+ slen := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, s), types.Types[types.TUINTPTR])
+ tlen := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, t), types.Types[types.TUINTPTR])
- fn := syslook("memequal")
- fn = substArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8])
+ fn := typecheck.LookupRuntime("memequal")
+ fn = typecheck.SubstArgTypes(fn, types.Types[types.TUINT8], types.Types[types.TUINT8])
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, []ir.Node{sptr, tptr, ir.Copy(slen)})
- TypecheckCall(call)
+ typecheck.Call(call)
cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, slen, tlen)
- cmp = typecheck(cmp, ctxExpr).(*ir.BinaryExpr)
+ cmp = typecheck.Expr(cmp).(*ir.BinaryExpr)
cmp.SetType(types.Types[types.TBOOL])
return cmp, call
}
// func efaceeq(typ *uintptr, x, y unsafe.Pointer) (ret bool)
var fn ir.Node
if s.Type().IsEmptyInterface() {
- fn = syslook("efaceeq")
+ fn = typecheck.LookupRuntime("efaceeq")
} else {
- fn = syslook("ifaceeq")
+ fn = typecheck.LookupRuntime("ifaceeq")
}
stab := ir.NewUnaryExpr(base.Pos, ir.OITAB, s)
tdata.SetTypecheck(1)
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, []ir.Node{stab, sdata, tdata})
- TypecheckCall(call)
+ typecheck.Call(call)
cmp := ir.NewBinaryExpr(base.Pos, ir.OEQ, stab, ttab)
- cmp = typecheck(cmp, ctxExpr).(*ir.BinaryExpr)
+ cmp = typecheck.Expr(cmp).(*ir.BinaryExpr)
cmp.SetType(types.Types[types.TBOOL])
return cmp, call
}
// eqmem returns the node
// memequal(&p.field, &q.field [, size])
func eqmem(p ir.Node, q ir.Node, field *types.Sym, size int64) ir.Node {
- nx := typecheck(nodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)), ctxExpr)
- ny := typecheck(nodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)), ctxExpr)
+ nx := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, p, field)))
+ ny := typecheck.Expr(typecheck.NodAddr(ir.NewSelectorExpr(base.Pos, ir.OXDOT, q, field)))
fn, needsize := eqmemfunc(size, nx.Type().Elem())
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
func eqmemfunc(size int64, t *types.Type) (fn *ir.Name, needsize bool) {
switch size {
default:
- fn = syslook("memequal")
+ fn = typecheck.LookupRuntime("memequal")
needsize = true
case 1, 2, 4, 8, 16:
buf := fmt.Sprintf("memequal%d", int(size)*8)
- fn = syslook(buf)
+ fn = typecheck.LookupRuntime(buf)
}
- fn = substArgTypes(fn, t, t)
+ fn = typecheck.SubstArgTypes(fn, t, t)
return fn, needsize
}
+++ /dev/null
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
- "cmd/compile/internal/ir"
- "cmd/compile/internal/types"
-)
-
-type exporter struct {
- marked map[*types.Type]bool // types already seen by markType
-}
-
-// markObject visits a reachable object.
-func (p *exporter) markObject(n ir.Node) {
- if n.Op() == ir.ONAME {
- n := n.(*ir.Name)
- if n.Class_ == ir.PFUNC {
- inlFlood(n, exportsym)
- }
- }
-
- p.markType(n.Type())
-}
-
-// markType recursively visits types reachable from t to identify
-// functions whose inline bodies may be needed.
-func (p *exporter) markType(t *types.Type) {
- if p.marked[t] {
- return
- }
- p.marked[t] = true
-
- // If this is a named type, mark all of its associated
- // methods. Skip interface types because t.Methods contains
- // only their unexpanded method set (i.e., exclusive of
- // interface embeddings), and the switch statement below
- // handles their full method set.
- if t.Sym() != nil && t.Kind() != types.TINTER {
- for _, m := range t.Methods().Slice() {
- if types.IsExported(m.Sym.Name) {
- p.markObject(ir.AsNode(m.Nname))
- }
- }
- }
-
- // Recursively mark any types that can be produced given a
- // value of type t: dereferencing a pointer; indexing or
- // iterating over an array, slice, or map; receiving from a
- // channel; accessing a struct field or interface method; or
- // calling a function.
- //
- // Notably, we don't mark function parameter types, because
- // the user already needs some way to construct values of
- // those types.
- switch t.Kind() {
- case types.TPTR, types.TARRAY, types.TSLICE:
- p.markType(t.Elem())
-
- case types.TCHAN:
- if t.ChanDir().CanRecv() {
- p.markType(t.Elem())
- }
-
- case types.TMAP:
- p.markType(t.Key())
- p.markType(t.Elem())
-
- case types.TSTRUCT:
- for _, f := range t.FieldSlice() {
- if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
- p.markType(f.Type)
- }
- }
-
- case types.TFUNC:
- for _, f := range t.Results().FieldSlice() {
- p.markType(f.Type)
- }
-
- case types.TINTER:
- for _, f := range t.FieldSlice() {
- if types.IsExported(f.Sym.Name) {
- p.markType(f.Type)
- }
- }
- }
-}
-
-// ----------------------------------------------------------------------------
-// Export format
-
-// Tags. Must be < 0.
-const (
- // Objects
- packageTag = -(iota + 1)
- constTag
- typeTag
- varTag
- funcTag
- endTag
-
- // Types
- namedTag
- arrayTag
- sliceTag
- dddTag
- structTag
- pointerTag
- signatureTag
- interfaceTag
- mapTag
- chanTag
-
- // Values
- falseTag
- trueTag
- int64Tag
- floatTag
- fractionTag // not used by gc
- complexTag
- stringTag
- nilTag
- unknownTag // not used by gc (only appears in packages with errors)
-
- // Type aliases
- aliasTag
-)
-
-var predecl []*types.Type // initialized lazily
-
-func predeclared() []*types.Type {
- if predecl == nil {
- // initialize lazily to be sure that all
- // elements have been initialized before
- predecl = []*types.Type{
- // basic types
- types.Types[types.TBOOL],
- types.Types[types.TINT],
- types.Types[types.TINT8],
- types.Types[types.TINT16],
- types.Types[types.TINT32],
- types.Types[types.TINT64],
- types.Types[types.TUINT],
- types.Types[types.TUINT8],
- types.Types[types.TUINT16],
- types.Types[types.TUINT32],
- types.Types[types.TUINT64],
- types.Types[types.TUINTPTR],
- types.Types[types.TFLOAT32],
- types.Types[types.TFLOAT64],
- types.Types[types.TCOMPLEX64],
- types.Types[types.TCOMPLEX128],
- types.Types[types.TSTRING],
-
- // basic type aliases
- types.ByteType,
- types.RuneType,
-
- // error
- types.ErrorType,
-
- // untyped types
- types.UntypedBool,
- types.UntypedInt,
- types.UntypedRune,
- types.UntypedFloat,
- types.UntypedComplex,
- types.UntypedString,
- types.Types[types.TNIL],
-
- // package unsafe
- types.Types[types.TUNSAFEPTR],
-
- // invalid type (package contains errors)
- types.Types[types.Txxx],
-
- // any type, for builtin export data
- types.Types[types.TANY],
- }
- }
- return predecl
-}
+++ /dev/null
-// Code generated by mkbuiltin.go. DO NOT EDIT.
-
-package gc
-
-import (
- "cmd/compile/internal/base"
- "cmd/compile/internal/ir"
- "cmd/compile/internal/types"
-)
-
-var runtimeDecls = [...]struct {
- name string
- tag int
- typ int
-}{
- {"newobject", funcTag, 4},
- {"mallocgc", funcTag, 8},
- {"panicdivide", funcTag, 9},
- {"panicshift", funcTag, 9},
- {"panicmakeslicelen", funcTag, 9},
- {"panicmakeslicecap", funcTag, 9},
- {"throwinit", funcTag, 9},
- {"panicwrap", funcTag, 9},
- {"gopanic", funcTag, 11},
- {"gorecover", funcTag, 14},
- {"goschedguarded", funcTag, 9},
- {"goPanicIndex", funcTag, 16},
- {"goPanicIndexU", funcTag, 18},
- {"goPanicSliceAlen", funcTag, 16},
- {"goPanicSliceAlenU", funcTag, 18},
- {"goPanicSliceAcap", funcTag, 16},
- {"goPanicSliceAcapU", funcTag, 18},
- {"goPanicSliceB", funcTag, 16},
- {"goPanicSliceBU", funcTag, 18},
- {"goPanicSlice3Alen", funcTag, 16},
- {"goPanicSlice3AlenU", funcTag, 18},
- {"goPanicSlice3Acap", funcTag, 16},
- {"goPanicSlice3AcapU", funcTag, 18},
- {"goPanicSlice3B", funcTag, 16},
- {"goPanicSlice3BU", funcTag, 18},
- {"goPanicSlice3C", funcTag, 16},
- {"goPanicSlice3CU", funcTag, 18},
- {"printbool", funcTag, 19},
- {"printfloat", funcTag, 21},
- {"printint", funcTag, 23},
- {"printhex", funcTag, 25},
- {"printuint", funcTag, 25},
- {"printcomplex", funcTag, 27},
- {"printstring", funcTag, 29},
- {"printpointer", funcTag, 30},
- {"printuintptr", funcTag, 31},
- {"printiface", funcTag, 30},
- {"printeface", funcTag, 30},
- {"printslice", funcTag, 30},
- {"printnl", funcTag, 9},
- {"printsp", funcTag, 9},
- {"printlock", funcTag, 9},
- {"printunlock", funcTag, 9},
- {"concatstring2", funcTag, 34},
- {"concatstring3", funcTag, 35},
- {"concatstring4", funcTag, 36},
- {"concatstring5", funcTag, 37},
- {"concatstrings", funcTag, 39},
- {"cmpstring", funcTag, 40},
- {"intstring", funcTag, 43},
- {"slicebytetostring", funcTag, 44},
- {"slicebytetostringtmp", funcTag, 45},
- {"slicerunetostring", funcTag, 48},
- {"stringtoslicebyte", funcTag, 50},
- {"stringtoslicerune", funcTag, 53},
- {"slicecopy", funcTag, 54},
- {"decoderune", funcTag, 55},
- {"countrunes", funcTag, 56},
- {"convI2I", funcTag, 57},
- {"convT16", funcTag, 58},
- {"convT32", funcTag, 58},
- {"convT64", funcTag, 58},
- {"convTstring", funcTag, 58},
- {"convTslice", funcTag, 58},
- {"convT2E", funcTag, 59},
- {"convT2Enoptr", funcTag, 59},
- {"convT2I", funcTag, 59},
- {"convT2Inoptr", funcTag, 59},
- {"assertE2I", funcTag, 57},
- {"assertE2I2", funcTag, 60},
- {"assertI2I", funcTag, 57},
- {"assertI2I2", funcTag, 60},
- {"panicdottypeE", funcTag, 61},
- {"panicdottypeI", funcTag, 61},
- {"panicnildottype", funcTag, 62},
- {"ifaceeq", funcTag, 64},
- {"efaceeq", funcTag, 64},
- {"fastrand", funcTag, 66},
- {"makemap64", funcTag, 68},
- {"makemap", funcTag, 69},
- {"makemap_small", funcTag, 70},
- {"mapaccess1", funcTag, 71},
- {"mapaccess1_fast32", funcTag, 72},
- {"mapaccess1_fast64", funcTag, 72},
- {"mapaccess1_faststr", funcTag, 72},
- {"mapaccess1_fat", funcTag, 73},
- {"mapaccess2", funcTag, 74},
- {"mapaccess2_fast32", funcTag, 75},
- {"mapaccess2_fast64", funcTag, 75},
- {"mapaccess2_faststr", funcTag, 75},
- {"mapaccess2_fat", funcTag, 76},
- {"mapassign", funcTag, 71},
- {"mapassign_fast32", funcTag, 72},
- {"mapassign_fast32ptr", funcTag, 72},
- {"mapassign_fast64", funcTag, 72},
- {"mapassign_fast64ptr", funcTag, 72},
- {"mapassign_faststr", funcTag, 72},
- {"mapiterinit", funcTag, 77},
- {"mapdelete", funcTag, 77},
- {"mapdelete_fast32", funcTag, 78},
- {"mapdelete_fast64", funcTag, 78},
- {"mapdelete_faststr", funcTag, 78},
- {"mapiternext", funcTag, 79},
- {"mapclear", funcTag, 80},
- {"makechan64", funcTag, 82},
- {"makechan", funcTag, 83},
- {"chanrecv1", funcTag, 85},
- {"chanrecv2", funcTag, 86},
- {"chansend1", funcTag, 88},
- {"closechan", funcTag, 30},
- {"writeBarrier", varTag, 90},
- {"typedmemmove", funcTag, 91},
- {"typedmemclr", funcTag, 92},
- {"typedslicecopy", funcTag, 93},
- {"selectnbsend", funcTag, 94},
- {"selectnbrecv", funcTag, 95},
- {"selectnbrecv2", funcTag, 97},
- {"selectsetpc", funcTag, 98},
- {"selectgo", funcTag, 99},
- {"block", funcTag, 9},
- {"makeslice", funcTag, 100},
- {"makeslice64", funcTag, 101},
- {"makeslicecopy", funcTag, 102},
- {"growslice", funcTag, 104},
- {"memmove", funcTag, 105},
- {"memclrNoHeapPointers", funcTag, 106},
- {"memclrHasPointers", funcTag, 106},
- {"memequal", funcTag, 107},
- {"memequal0", funcTag, 108},
- {"memequal8", funcTag, 108},
- {"memequal16", funcTag, 108},
- {"memequal32", funcTag, 108},
- {"memequal64", funcTag, 108},
- {"memequal128", funcTag, 108},
- {"f32equal", funcTag, 109},
- {"f64equal", funcTag, 109},
- {"c64equal", funcTag, 109},
- {"c128equal", funcTag, 109},
- {"strequal", funcTag, 109},
- {"interequal", funcTag, 109},
- {"nilinterequal", funcTag, 109},
- {"memhash", funcTag, 110},
- {"memhash0", funcTag, 111},
- {"memhash8", funcTag, 111},
- {"memhash16", funcTag, 111},
- {"memhash32", funcTag, 111},
- {"memhash64", funcTag, 111},
- {"memhash128", funcTag, 111},
- {"f32hash", funcTag, 111},
- {"f64hash", funcTag, 111},
- {"c64hash", funcTag, 111},
- {"c128hash", funcTag, 111},
- {"strhash", funcTag, 111},
- {"interhash", funcTag, 111},
- {"nilinterhash", funcTag, 111},
- {"int64div", funcTag, 112},
- {"uint64div", funcTag, 113},
- {"int64mod", funcTag, 112},
- {"uint64mod", funcTag, 113},
- {"float64toint64", funcTag, 114},
- {"float64touint64", funcTag, 115},
- {"float64touint32", funcTag, 116},
- {"int64tofloat64", funcTag, 117},
- {"uint64tofloat64", funcTag, 118},
- {"uint32tofloat64", funcTag, 119},
- {"complex128div", funcTag, 120},
- {"racefuncenter", funcTag, 31},
- {"racefuncenterfp", funcTag, 9},
- {"racefuncexit", funcTag, 9},
- {"raceread", funcTag, 31},
- {"racewrite", funcTag, 31},
- {"racereadrange", funcTag, 121},
- {"racewriterange", funcTag, 121},
- {"msanread", funcTag, 121},
- {"msanwrite", funcTag, 121},
- {"msanmove", funcTag, 122},
- {"checkptrAlignment", funcTag, 123},
- {"checkptrArithmetic", funcTag, 125},
- {"libfuzzerTraceCmp1", funcTag, 127},
- {"libfuzzerTraceCmp2", funcTag, 129},
- {"libfuzzerTraceCmp4", funcTag, 130},
- {"libfuzzerTraceCmp8", funcTag, 131},
- {"libfuzzerTraceConstCmp1", funcTag, 127},
- {"libfuzzerTraceConstCmp2", funcTag, 129},
- {"libfuzzerTraceConstCmp4", funcTag, 130},
- {"libfuzzerTraceConstCmp8", funcTag, 131},
- {"x86HasPOPCNT", varTag, 6},
- {"x86HasSSE41", varTag, 6},
- {"x86HasFMA", varTag, 6},
- {"armHasVFPv4", varTag, 6},
- {"arm64HasATOMICS", varTag, 6},
-}
-
-func runtimeTypes() []*types.Type {
- var typs [132]*types.Type
- typs[0] = types.ByteType
- typs[1] = types.NewPtr(typs[0])
- typs[2] = types.Types[types.TANY]
- typs[3] = types.NewPtr(typs[2])
- typs[4] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
- typs[5] = types.Types[types.TUINTPTR]
- typs[6] = types.Types[types.TBOOL]
- typs[7] = types.Types[types.TUNSAFEPTR]
- typs[8] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
- typs[9] = functype(nil, nil, nil)
- typs[10] = types.Types[types.TINTER]
- typs[11] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])}, nil)
- typs[12] = types.Types[types.TINT32]
- typs[13] = types.NewPtr(typs[12])
- typs[14] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[13])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])})
- typs[15] = types.Types[types.TINT]
- typs[16] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil)
- typs[17] = types.Types[types.TUINT]
- typs[18] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[17]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil)
- typs[19] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}, nil)
- typs[20] = types.Types[types.TFLOAT64]
- typs[21] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, nil)
- typs[22] = types.Types[types.TINT64]
- typs[23] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, nil)
- typs[24] = types.Types[types.TUINT64]
- typs[25] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, nil)
- typs[26] = types.Types[types.TCOMPLEX128]
- typs[27] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])}, nil)
- typs[28] = types.Types[types.TSTRING]
- typs[29] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, nil)
- typs[30] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, nil)
- typs[31] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
- typs[32] = types.NewArray(typs[0], 32)
- typs[33] = types.NewPtr(typs[32])
- typs[34] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
- typs[35] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
- typs[36] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
- typs[37] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
- typs[38] = types.NewSlice(typs[28])
- typs[39] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[38])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
- typs[40] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
- typs[41] = types.NewArray(typs[0], 4)
- typs[42] = types.NewPtr(typs[41])
- typs[43] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[42]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
- typs[44] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
- typs[45] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
- typs[46] = types.RuneType
- typs[47] = types.NewSlice(typs[46])
- typs[48] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[47])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
- typs[49] = types.NewSlice(typs[0])
- typs[50] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[49])})
- typs[51] = types.NewArray(typs[46], 32)
- typs[52] = types.NewPtr(typs[51])
- typs[53] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[52]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[47])})
- typs[54] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
- typs[55] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[46]), ir.NewField(base.Pos, nil, nil, typs[15])})
- typs[56] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
- typs[57] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])})
- typs[58] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
- typs[59] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])})
- typs[60] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2]), ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[61] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1])}, nil)
- typs[62] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, nil)
- typs[63] = types.NewPtr(typs[5])
- typs[64] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[65] = types.Types[types.TUINT32]
- typs[66] = functype(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])})
- typs[67] = types.NewMap(typs[2], typs[2])
- typs[68] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
- typs[69] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
- typs[70] = functype(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
- typs[71] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
- typs[72] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
- typs[73] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
- typs[74] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[75] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[76] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[77] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
- typs[78] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, nil)
- typs[79] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
- typs[80] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67])}, nil)
- typs[81] = types.NewChan(typs[2], types.Cboth)
- typs[82] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])})
- typs[83] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])})
- typs[84] = types.NewChan(typs[2], types.Crecv)
- typs[85] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
- typs[86] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[87] = types.NewChan(typs[2], types.Csend)
- typs[88] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
- typs[89] = types.NewArray(typs[0], 3)
- typs[90] = tostruct([]*ir.Field{ir.NewField(base.Pos, lookup("enabled"), nil, typs[6]), ir.NewField(base.Pos, lookup("pad"), nil, typs[89]), ir.NewField(base.Pos, lookup("needed"), nil, typs[6]), ir.NewField(base.Pos, lookup("cgo"), nil, typs[6]), ir.NewField(base.Pos, lookup("alignme"), nil, typs[24])})
- typs[91] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
- typs[92] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
- typs[93] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
- typs[94] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[95] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[96] = types.NewPtr(typs[6])
- typs[97] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[96]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[98] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63])}, nil)
- typs[99] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[100] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
- typs[101] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
- typs[102] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
- typs[103] = types.NewSlice(typs[2])
- typs[104] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[103]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[103])})
- typs[105] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
- typs[106] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
- typs[107] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[108] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[109] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
- typs[110] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])})
- typs[111] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])})
- typs[112] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])})
- typs[113] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])})
- typs[114] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])})
- typs[115] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])})
- typs[116] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])})
- typs[117] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
- typs[118] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
- typs[119] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
- typs[120] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26]), ir.NewField(base.Pos, nil, nil, typs[26])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])})
- typs[121] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
- typs[122] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
- typs[123] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
- typs[124] = types.NewSlice(typs[7])
- typs[125] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[124])}, nil)
- typs[126] = types.Types[types.TUINT8]
- typs[127] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[126]), ir.NewField(base.Pos, nil, nil, typs[126])}, nil)
- typs[128] = types.Types[types.TUINT16]
- typs[129] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[128]), ir.NewField(base.Pos, nil, nil, typs[128])}, nil)
- typs[130] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65]), ir.NewField(base.Pos, nil, nil, typs[65])}, nil)
- typs[131] = functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, nil)
- return typs[:]
-}
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
- "fmt"
)
func (p *noder) funcLit(expr *syntax.FuncLit) ir.Node {
return clo
}
-// typecheckclosure typechecks an OCLOSURE node. It also creates the named
-// function associated with the closure.
-// TODO: This creation of the named function should probably really be done in a
-// separate pass from type-checking.
-func typecheckclosure(clo *ir.ClosureExpr, top int) {
- fn := clo.Func
- // Set current associated iota value, so iota can be used inside
- // function in ConstSpec, see issue #22344
- if x := getIotaValue(); x >= 0 {
- fn.Iota = x
- }
-
- fn.ClosureType = typecheck(fn.ClosureType, ctxType)
- clo.SetType(fn.ClosureType.Type())
- fn.SetClosureCalled(top&ctxCallee != 0)
-
- // Do not typecheck fn twice, otherwise, we will end up pushing
- // fn to Target.Decls multiple times, causing initLSym called twice.
- // See #30709
- if fn.Typecheck() == 1 {
- return
- }
-
- for _, ln := range fn.ClosureVars {
- n := ln.Defn
- if !n.Name().Captured() {
- n.Name().SetCaptured(true)
- if n.Name().Decldepth == 0 {
- base.Fatalf("typecheckclosure: var %v does not have decldepth assigned", n)
- }
-
- // Ignore assignments to the variable in straightline code
- // preceding the first capturing by a closure.
- if n.Name().Decldepth == decldepth {
- n.Name().SetAssigned(false)
- }
- }
- }
-
- fn.Nname.SetSym(closurename(ir.CurFunc))
- ir.MarkFunc(fn.Nname)
- typecheckFunc(fn)
-
- // Type check the body now, but only if we're inside a function.
- // At top level (in a variable initialization: curfn==nil) we're not
- // ready to type check code yet; we'll check it later, because the
- // underlying closure function we create is added to Target.Decls.
- if ir.CurFunc != nil && clo.Type() != nil {
- oldfn := ir.CurFunc
- ir.CurFunc = fn
- olddd := decldepth
- decldepth = 1
- typecheckslice(fn.Body, ctxStmt)
- decldepth = olddd
- ir.CurFunc = oldfn
- }
-
- Target.Decls = append(Target.Decls, fn)
-}
-
-// globClosgen is like Func.Closgen, but for the global scope.
-var globClosgen int32
-
-// closurename generates a new unique name for a closure within
-// outerfunc.
-func closurename(outerfunc *ir.Func) *types.Sym {
- outer := "glob."
- prefix := "func"
- gen := &globClosgen
-
- if outerfunc != nil {
- if outerfunc.OClosure != nil {
- prefix = ""
- }
-
- outer = ir.FuncName(outerfunc)
-
- // There may be multiple functions named "_". In those
- // cases, we can't use their individual Closgens as it
- // would lead to name clashes.
- if !ir.IsBlank(outerfunc.Nname) {
- gen = &outerfunc.Closgen
- }
- }
-
- *gen++
- return lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
-}
-
-// capturevarscomplete is set to true when the capturevars phase is done.
-var capturevarscomplete bool
-
-// capturevars is called in a separate phase after all typechecking is done.
-// It decides whether each variable captured by a closure should be captured
-// by value or by reference.
-// We use value capturing for values <= 128 bytes that are never reassigned
-// after capturing (effectively constant).
-func capturevars(fn *ir.Func) {
- lno := base.Pos
- base.Pos = fn.Pos()
- cvars := fn.ClosureVars
- out := cvars[:0]
- for _, v := range cvars {
- if v.Type() == nil {
- // If v.Type is nil, it means v looked like it
- // was going to be used in the closure, but
- // isn't. This happens in struct literals like
- // s{f: x} where we can't distinguish whether
- // f is a field identifier or expression until
- // resolving s.
- continue
- }
- out = append(out, v)
-
- // type check the & of closed variables outside the closure,
- // so that the outer frame also grabs them and knows they escape.
- types.CalcSize(v.Type())
-
- var outer ir.Node
- outer = v.Outer
- outermost := v.Defn.(*ir.Name)
-
- // out parameters will be assigned to implicitly upon return.
- if outermost.Class_ != ir.PPARAMOUT && !outermost.Name().Addrtaken() && !outermost.Name().Assigned() && v.Type().Width <= 128 {
- v.SetByval(true)
- } else {
- outermost.Name().SetAddrtaken(true)
- outer = nodAddr(outer)
- }
-
- if base.Flag.LowerM > 1 {
- var name *types.Sym
- if v.Curfn != nil && v.Curfn.Nname != nil {
- name = v.Curfn.Sym()
- }
- how := "ref"
- if v.Byval() {
- how = "value"
- }
- base.WarnfAt(v.Pos(), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym(), outermost.Name().Addrtaken(), outermost.Name().Assigned(), int32(v.Type().Width))
- }
-
- outer = typecheck(outer, ctxExpr)
- fn.ClosureEnter.Append(outer)
- }
-
- fn.ClosureVars = out
- base.Pos = lno
-}
-
// transformclosure is called in a separate phase after escape analysis.
// It transform closure bodies to properly reference captured variables.
func transformclosure(fn *ir.Func) {
// we introduce function param &v *T
// and v remains PAUTOHEAP with &v heapaddr
// (accesses will implicitly deref &v).
- addr := NewName(lookup("&" + v.Sym().Name))
+ addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
addr.SetType(types.NewPtr(v.Type()))
v.Heapaddr = addr
v = addr
} else {
// Declare variable holding addresses taken from closure
// and initialize in entry prologue.
- addr := NewName(lookup("&" + v.Sym().Name))
+ addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
addr.SetType(types.NewPtr(v.Type()))
addr.Class_ = ir.PAUTO
addr.SetUsed(true)
v.Heapaddr = addr
var src ir.Node = cr
if v.Byval() {
- src = nodAddr(cr)
+ src = typecheck.NodAddr(cr)
}
body = append(body, ir.NewAssignStmt(base.Pos, addr, src))
}
}
if len(body) > 0 {
- typecheckslice(body, ctxStmt)
+ typecheck.Stmts(body)
fn.Enter.Set(body)
fn.SetNeedctxt(true)
}
}
}
-// closureType returns the struct type used to hold all the information
-// needed in the closure for clo (clo must be a OCLOSURE node).
-// The address of a variable of the returned type can be cast to a func.
-func closureType(clo *ir.ClosureExpr) *types.Type {
- // Create closure in the form of a composite literal.
- // supposing the closure captures an int i and a string s
- // and has one float64 argument and no results,
- // the generated code looks like:
- //
- // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
- //
- // The use of the struct provides type information to the garbage
- // collector so that it can walk the closure. We could use (in this case)
- // [3]unsafe.Pointer instead, but that would leave the gc in the dark.
- // The information appears in the binary in the form of type descriptors;
- // the struct is unnamed so that closures in multiple packages with the
- // same struct type can share the descriptor.
- fields := []*ir.Field{
- ir.NewField(base.Pos, lookup(".F"), nil, types.Types[types.TUINTPTR]),
- }
- for _, v := range clo.Func.ClosureVars {
- typ := v.Type()
- if !v.Byval() {
- typ = types.NewPtr(typ)
- }
- fields = append(fields, ir.NewField(base.Pos, v.Sym(), nil, typ))
- }
- typ := tostruct(fields)
- typ.SetNoalg(true)
- return typ
-}
-
func walkclosure(clo *ir.ClosureExpr, init *ir.Nodes) ir.Node {
fn := clo.Func
}
closuredebugruntimecheck(clo)
- typ := closureType(clo)
+ typ := typecheck.ClosureType(clo)
clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
clos.SetEsc(clo.Esc())
clos.List.Set(append([]ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, fn.Nname)}, fn.ClosureEnter...))
- addr := nodAddr(clos)
+ addr := typecheck.NodAddr(clos)
addr.SetEsc(clo.Esc())
// Force type conversion from *struct to the func type.
- cfn := convnop(addr, clo.Type())
+ cfn := typecheck.ConvNop(addr, clo.Type())
// non-escaping temp to use, if any.
if x := clo.Prealloc; x != nil {
return walkexpr(cfn, init)
}
-func typecheckpartialcall(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
- switch n.Op() {
- case ir.ODOTINTER, ir.ODOTMETH:
- break
-
- default:
- base.Fatalf("invalid typecheckpartialcall")
- }
- dot := n.(*ir.SelectorExpr)
-
- // Create top-level function.
- fn := makepartialcall(dot, dot.Type(), sym)
- fn.SetWrapper(true)
-
- return ir.NewCallPartExpr(dot.Pos(), dot.X, dot.Selection, fn)
-}
-
-// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
-// for partial calls.
-func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.Func {
- rcvrtype := dot.X.Type()
- sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
-
- if sym.Uniq() {
- return sym.Def.(*ir.Func)
- }
- sym.SetUniq(true)
-
- savecurfn := ir.CurFunc
- saveLineNo := base.Pos
- ir.CurFunc = nil
-
- // Set line number equal to the line number where the method is declared.
- var m *types.Field
- if lookdot0(meth, rcvrtype, &m, false) == 1 && m.Pos.IsKnown() {
- base.Pos = m.Pos
- }
- // Note: !m.Pos.IsKnown() happens for method expressions where
- // the method is implicitly declared. The Error method of the
- // built-in error type is one such method. We leave the line
- // number at the use of the method expression in this
- // case. See issue 29389.
-
- tfn := ir.NewFuncType(base.Pos, nil,
- structargs(t0.Params(), true),
- structargs(t0.Results(), false))
-
- fn := dclfunc(sym, tfn)
- fn.SetDupok(true)
- fn.SetNeedctxt(true)
-
- // Declare and initialize variable holding receiver.
- cr := ir.NewClosureRead(rcvrtype, types.Rnd(int64(types.PtrSize), int64(rcvrtype.Align)))
- ptr := NewName(lookup(".this"))
- declare(ptr, ir.PAUTO)
- ptr.SetUsed(true)
- var body []ir.Node
- if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
- ptr.SetType(rcvrtype)
- body = append(body, ir.NewAssignStmt(base.Pos, ptr, cr))
- } else {
- ptr.SetType(types.NewPtr(rcvrtype))
- body = append(body, ir.NewAssignStmt(base.Pos, ptr, nodAddr(cr)))
- }
-
- call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil)
- call.Args.Set(ir.ParamNames(tfn.Type()))
- call.IsDDD = tfn.Type().IsVariadic()
- if t0.NumResults() != 0 {
- ret := ir.NewReturnStmt(base.Pos, nil)
- ret.Results = []ir.Node{call}
- body = append(body, ret)
- } else {
- body = append(body, call)
- }
-
- fn.Body.Set(body)
- funcbody()
-
- typecheckFunc(fn)
- // Need to typecheck the body of the just-generated wrapper.
- // typecheckslice() requires that Curfn is set when processing an ORETURN.
- ir.CurFunc = fn
- typecheckslice(fn.Body, ctxStmt)
- sym.Def = fn
- Target.Decls = append(Target.Decls, fn)
- ir.CurFunc = savecurfn
- base.Pos = saveLineNo
-
- return fn
-}
-
-// partialCallType returns the struct type used to hold all the information
-// needed in the closure for n (n must be a OCALLPART node).
-// The address of a variable of the returned type can be cast to a func.
-func partialCallType(n *ir.CallPartExpr) *types.Type {
- t := tostruct([]*ir.Field{
- ir.NewField(base.Pos, lookup("F"), nil, types.Types[types.TUINTPTR]),
- ir.NewField(base.Pos, lookup("R"), nil, n.X.Type()),
- })
- t.SetNoalg(true)
- return t
-}
-
func walkpartialcall(n *ir.CallPartExpr, init *ir.Nodes) ir.Node {
// Create closure in the form of a composite literal.
// For x.M with receiver (x) type T, the generated code looks like:
n.X = cheapexpr(n.X, init)
n.X = walkexpr(n.X, nil)
- tab := typecheck(ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X), ctxExpr)
+ tab := typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X))
c := ir.NewUnaryExpr(base.Pos, ir.OCHECKNIL, tab)
c.SetTypecheck(1)
init.Append(c)
}
- typ := partialCallType(n)
+ typ := typecheck.PartialCallType(n)
clos := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
clos.SetEsc(n.Esc())
clos.List = []ir.Node{ir.NewUnaryExpr(base.Pos, ir.OCFUNC, n.Func.Nname), n.X}
- addr := nodAddr(clos)
+ addr := typecheck.NodAddr(clos)
addr.SetEsc(n.Esc())
// Force type conversion from *struct to the func type.
- cfn := convnop(addr, n.Type())
+ cfn := typecheck.ConvNop(addr, n.Type())
// non-escaping temp to use, if any.
if x := n.Prealloc; x != nil {
"bytes"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src"
"fmt"
- "strings"
)
func EnableNoWriteBarrierRecCheck() {
var nowritebarrierrecCheck *nowritebarrierrecChecker
-// redeclare emits a diagnostic about symbol s being redeclared at pos.
-func redeclare(pos src.XPos, s *types.Sym, where string) {
- if !s.Lastlineno.IsKnown() {
- pkgName := dotImportRefs[s.Def.(*ir.Ident)]
- base.ErrorfAt(pos, "%v redeclared %s\n"+
- "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
- } else {
- prevPos := s.Lastlineno
-
- // When an import and a declaration collide in separate files,
- // present the import as the "redeclared", because the declaration
- // is visible where the import is, but not vice versa.
- // See issue 4510.
- if s.Def == nil {
- pos, prevPos = prevPos, pos
- }
-
- base.ErrorfAt(pos, "%v redeclared %s\n"+
- "\t%v: previous declaration", s, where, base.FmtPos(prevPos))
- }
-}
-
-var vargen int
-
-// declare individual names - var, typ, const
-
-var declare_typegen int
-
-// declare records that Node n declares symbol n.Sym in the specified
-// declaration context.
-func declare(n *ir.Name, ctxt ir.Class) {
- if ir.IsBlank(n) {
- return
- }
-
- s := n.Sym()
-
- // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
- if !inimport && !typecheckok && s.Pkg != types.LocalPkg {
- base.ErrorfAt(n.Pos(), "cannot declare name %v", s)
- }
-
- gen := 0
- if ctxt == ir.PEXTERN {
- if s.Name == "init" {
- base.ErrorfAt(n.Pos(), "cannot declare init - must be func")
- }
- if s.Name == "main" && s.Pkg.Name == "main" {
- base.ErrorfAt(n.Pos(), "cannot declare main - must be func")
- }
- Target.Externs = append(Target.Externs, n)
- } else {
- if ir.CurFunc == nil && ctxt == ir.PAUTO {
- base.Pos = n.Pos()
- base.Fatalf("automatic outside function")
- }
- if ir.CurFunc != nil && ctxt != ir.PFUNC && n.Op() == ir.ONAME {
- ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
- }
- if n.Op() == ir.OTYPE {
- declare_typegen++
- gen = declare_typegen
- } else if n.Op() == ir.ONAME && ctxt == ir.PAUTO && !strings.Contains(s.Name, "·") {
- vargen++
- gen = vargen
- }
- types.Pushdcl(s)
- n.Curfn = ir.CurFunc
- }
-
- if ctxt == ir.PAUTO {
- n.SetFrameOffset(0)
- }
-
- if s.Block == types.Block {
- // functype will print errors about duplicate function arguments.
- // Don't repeat the error here.
- if ctxt != ir.PPARAM && ctxt != ir.PPARAMOUT {
- redeclare(n.Pos(), s, "in this block")
- }
- }
-
- s.Block = types.Block
- s.Lastlineno = base.Pos
- s.Def = n
- n.Vargen = int32(gen)
- n.Class_ = ctxt
- if ctxt == ir.PFUNC {
- n.Sym().SetFunc(true)
- }
-
- autoexport(n, ctxt)
-}
-
-// declare variables from grammar
-// new_name_list (type | [type] = expr_list)
-func variter(vl []*ir.Name, t ir.Ntype, el []ir.Node) []ir.Node {
- var init []ir.Node
- doexpr := len(el) > 0
-
- if len(el) == 1 && len(vl) > 1 {
- e := el[0]
- as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
- as2.Rhs = []ir.Node{e}
- for _, v := range vl {
- as2.Lhs.Append(v)
- declare(v, dclcontext)
- v.Ntype = t
- v.Defn = as2
- if ir.CurFunc != nil {
- init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
- }
- }
-
- return append(init, as2)
- }
-
- for i, v := range vl {
- var e ir.Node
- if doexpr {
- if i >= len(el) {
- base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
- break
- }
- e = el[i]
- }
-
- declare(v, dclcontext)
- v.Ntype = t
-
- if e != nil || ir.CurFunc != nil || ir.IsBlank(v) {
- if ir.CurFunc != nil {
- init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
- }
- as := ir.NewAssignStmt(base.Pos, v, e)
- init = append(init, as)
- if e != nil {
- v.Defn = as
- }
- }
- }
-
- if len(el) > len(vl) {
- base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
- }
- return init
-}
-
// oldname returns the Node that declares symbol s in the current scope.
// If no such Node currently exists, an ONONAME Node is returned instead.
// Automatically creates a new closure variable if the referenced symbol was
c := n.Name().Innermost
if c == nil || c.Curfn != ir.CurFunc {
// Do not have a closure var for the active closure yet; make one.
- c = NewName(s)
+ c = typecheck.NewName(s)
c.Class_ = ir.PAUTOHEAP
c.SetIsClosureVar(true)
c.SetIsDDD(n.IsDDD())
return n
}
-// := declarations
-func colasname(n ir.Node) bool {
- switch n.Op() {
- case ir.ONAME,
- ir.ONONAME,
- ir.OPACK,
- ir.OTYPE,
- ir.OLITERAL:
- return n.Sym() != nil
- }
-
- return false
-}
-
-func colasdefn(left []ir.Node, defn ir.Node) {
- for _, n := range left {
- if n.Sym() != nil {
- n.Sym().SetUniq(true)
- }
- }
-
- var nnew, nerr int
- for i, n := range left {
- if ir.IsBlank(n) {
- continue
- }
- if !colasname(n) {
- base.ErrorfAt(defn.Pos(), "non-name %v on left side of :=", n)
- nerr++
- continue
- }
-
- if !n.Sym().Uniq() {
- base.ErrorfAt(defn.Pos(), "%v repeated on left side of :=", n.Sym())
- n.SetDiag(true)
- nerr++
- continue
- }
-
- n.Sym().SetUniq(false)
- if n.Sym().Block == types.Block {
- continue
- }
-
- nnew++
- n := NewName(n.Sym())
- declare(n, dclcontext)
- n.Defn = defn
- defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n))
- left[i] = n
- }
-
- if nnew == 0 && nerr == 0 {
- base.ErrorfAt(defn.Pos(), "no new variables on left side of :=")
- }
-}
-
-// declare the function proper
-// and declare the arguments.
-// called in extern-declaration context
-// returns in auto-declaration context.
-func funchdr(fn *ir.Func) {
- // change the declaration context from extern to auto
- funcStack = append(funcStack, funcStackEnt{ir.CurFunc, dclcontext})
- ir.CurFunc = fn
- dclcontext = ir.PAUTO
-
- types.Markdcl()
-
- if fn.Nname.Ntype != nil {
- funcargs(fn.Nname.Ntype.(*ir.FuncType))
- } else {
- funcargs2(fn.Type())
- }
-}
-
-func funcargs(nt *ir.FuncType) {
- if nt.Op() != ir.OTFUNC {
- base.Fatalf("funcargs %v", nt.Op())
- }
-
- // re-start the variable generation number
- // we want to use small numbers for the return variables,
- // so let them have the chunk starting at 1.
- //
- // TODO(mdempsky): This is ugly, and only necessary because
- // esc.go uses Vargen to figure out result parameters' index
- // within the result tuple.
- vargen = len(nt.Results)
-
- // declare the receiver and in arguments.
- if nt.Recv != nil {
- funcarg(nt.Recv, ir.PPARAM)
- }
- for _, n := range nt.Params {
- funcarg(n, ir.PPARAM)
- }
-
- oldvargen := vargen
- vargen = 0
-
- // declare the out arguments.
- gen := len(nt.Params)
- for _, n := range nt.Results {
- if n.Sym == nil {
- // Name so that escape analysis can track it. ~r stands for 'result'.
- n.Sym = lookupN("~r", gen)
- gen++
- }
- if n.Sym.IsBlank() {
- // Give it a name so we can assign to it during return. ~b stands for 'blank'.
- // The name must be different from ~r above because if you have
- // func f() (_ int)
- // func g() int
- // f is allowed to use a plain 'return' with no arguments, while g is not.
- // So the two cases must be distinguished.
- n.Sym = lookupN("~b", gen)
- gen++
- }
-
- funcarg(n, ir.PPARAMOUT)
- }
-
- vargen = oldvargen
-}
-
-func funcarg(n *ir.Field, ctxt ir.Class) {
- if n.Sym == nil {
- return
- }
-
- name := ir.NewNameAt(n.Pos, n.Sym)
- n.Decl = name
- name.Ntype = n.Ntype
- name.SetIsDDD(n.IsDDD)
- declare(name, ctxt)
-
- vargen++
- n.Decl.Vargen = int32(vargen)
-}
-
-// Same as funcargs, except run over an already constructed TFUNC.
-// This happens during import, where the hidden_fndcl rule has
-// used functype directly to parse the function's type.
-func funcargs2(t *types.Type) {
- if t.Kind() != types.TFUNC {
- base.Fatalf("funcargs2 %v", t)
- }
-
- for _, f := range t.Recvs().Fields().Slice() {
- funcarg2(f, ir.PPARAM)
- }
- for _, f := range t.Params().Fields().Slice() {
- funcarg2(f, ir.PPARAM)
- }
- for _, f := range t.Results().Fields().Slice() {
- funcarg2(f, ir.PPARAMOUT)
- }
-}
-
-func funcarg2(f *types.Field, ctxt ir.Class) {
- if f.Sym == nil {
- return
- }
- n := ir.NewNameAt(f.Pos, f.Sym)
- f.Nname = n
- n.SetType(f.Type)
- n.SetIsDDD(f.IsDDD())
- declare(n, ctxt)
-}
-
-var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
-
-type funcStackEnt struct {
- curfn *ir.Func
- dclcontext ir.Class
-}
-
-func CheckFuncStack() {
- if len(funcStack) != 0 {
- base.Fatalf("funcStack is non-empty: %v", len(funcStack))
- }
-}
-
-// finish the body.
-// called in auto-declaration context.
-// returns in extern-declaration context.
-func funcbody() {
- // change the declaration context from auto to previous context
- types.Popdcl()
- var e funcStackEnt
- funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
- ir.CurFunc, dclcontext = e.curfn, e.dclcontext
-}
-
-// structs, functions, and methods.
-// they don't belong here, but where do they belong?
-func checkembeddedtype(t *types.Type) {
- if t == nil {
- return
- }
-
- if t.Sym() == nil && t.IsPtr() {
- t = t.Elem()
- if t.IsInterface() {
- base.Errorf("embedded type cannot be a pointer to interface")
- }
- }
-
- if t.IsPtr() || t.IsUnsafePtr() {
- base.Errorf("embedded type cannot be a pointer")
- } else if t.Kind() == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() {
- t.ForwardType().Embedlineno = base.Pos
- }
-}
-
-// checkdupfields emits errors for duplicately named fields or methods in
-// a list of struct or interface types.
-func checkdupfields(what string, fss ...[]*types.Field) {
- seen := make(map[*types.Sym]bool)
- for _, fs := range fss {
- for _, f := range fs {
- if f.Sym == nil || f.Sym.IsBlank() {
- continue
- }
- if seen[f.Sym] {
- base.ErrorfAt(f.Pos, "duplicate %s %s", what, f.Sym.Name)
- continue
- }
- seen[f.Sym] = true
- }
- }
-}
-
-// convert a parsed id/type list into
-// a type for struct/interface/arglist
-func tostruct(l []*ir.Field) *types.Type {
- lno := base.Pos
-
- fields := make([]*types.Field, len(l))
- for i, n := range l {
- base.Pos = n.Pos
-
- if n.Ntype != nil {
- n.Type = typecheckNtype(n.Ntype).Type()
- n.Ntype = nil
- }
- f := types.NewField(n.Pos, n.Sym, n.Type)
- if n.Embedded {
- checkembeddedtype(n.Type)
- f.Embedded = 1
- }
- f.Note = n.Note
- fields[i] = f
- }
- checkdupfields("field", fields)
-
- base.Pos = lno
- return types.NewStruct(types.LocalPkg, fields)
-}
-
-func tointerface(nmethods []*ir.Field) *types.Type {
- if len(nmethods) == 0 {
- return types.Types[types.TINTER]
- }
-
- lno := base.Pos
-
- methods := make([]*types.Field, len(nmethods))
- for i, n := range nmethods {
- base.Pos = n.Pos
- if n.Ntype != nil {
- n.Type = typecheckNtype(n.Ntype).Type()
- n.Ntype = nil
- }
- methods[i] = types.NewField(n.Pos, n.Sym, n.Type)
- }
-
- base.Pos = lno
- return types.NewInterface(types.LocalPkg, methods)
-}
-
func fakeRecv() *ir.Field {
return ir.NewField(base.Pos, nil, nil, types.FakeRecvType())
}
-func fakeRecvField() *types.Field {
- return types.NewField(src.NoXPos, nil, types.FakeRecvType())
-}
-
-// turn a parsed function declaration into a type
-func functype(nrecv *ir.Field, nparams, nresults []*ir.Field) *types.Type {
- funarg := func(n *ir.Field) *types.Field {
- lno := base.Pos
- base.Pos = n.Pos
-
- if n.Ntype != nil {
- n.Type = typecheckNtype(n.Ntype).Type()
- n.Ntype = nil
- }
-
- f := types.NewField(n.Pos, n.Sym, n.Type)
- f.SetIsDDD(n.IsDDD)
- if n.Decl != nil {
- n.Decl.SetType(f.Type)
- f.Nname = n.Decl
- }
-
- base.Pos = lno
- return f
- }
- funargs := func(nn []*ir.Field) []*types.Field {
- res := make([]*types.Field, len(nn))
- for i, n := range nn {
- res[i] = funarg(n)
- }
- return res
- }
-
- var recv *types.Field
- if nrecv != nil {
- recv = funarg(nrecv)
- }
-
- t := types.NewSignature(types.LocalPkg, recv, funargs(nparams), funargs(nresults))
- checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice())
- return t
-}
-
-// Add a method, declared as a function.
-// - msym is the method symbol
-// - t is function type (with receiver)
-// Returns a pointer to the existing or added Field; or nil if there's an error.
-func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
- if msym == nil {
- base.Fatalf("no method symbol")
- }
-
- // get parent type sym
- rf := t.Recv() // ptr to this structure
- if rf == nil {
- base.Errorf("missing receiver")
- return nil
- }
-
- mt := types.ReceiverBaseType(rf.Type)
- if mt == nil || mt.Sym() == nil {
- pa := rf.Type
- t := pa
- if t != nil && t.IsPtr() {
- if t.Sym() != nil {
- base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
- return nil
- }
- t = t.Elem()
- }
-
- switch {
- case t == nil || t.Broke():
- // rely on typecheck having complained before
- case t.Sym() == nil:
- base.Errorf("invalid receiver type %v (%v is not a defined type)", pa, t)
- case t.IsPtr():
- base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
- case t.IsInterface():
- base.Errorf("invalid receiver type %v (%v is an interface type)", pa, t)
- default:
- // Should have picked off all the reasons above,
- // but just in case, fall back to generic error.
- base.Errorf("invalid receiver type %v (%L / %L)", pa, pa, t)
- }
- return nil
- }
-
- if local && mt.Sym().Pkg != types.LocalPkg {
- base.Errorf("cannot define new methods on non-local type %v", mt)
- return nil
- }
-
- if msym.IsBlank() {
- return nil
- }
-
- if mt.IsStruct() {
- for _, f := range mt.Fields().Slice() {
- if f.Sym == msym {
- base.Errorf("type %v has both field and method named %v", mt, msym)
- f.SetBroke(true)
- return nil
- }
- }
- }
-
- for _, f := range mt.Methods().Slice() {
- if msym.Name != f.Sym.Name {
- continue
- }
- // types.Identical only checks that incoming and result parameters match,
- // so explicitly check that the receiver parameters match too.
- if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
- base.Errorf("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
- }
- return f
- }
-
- f := types.NewField(base.Pos, msym, t)
- f.Nname = n.Nname
- f.SetNointerface(nointerface)
-
- mt.Methods().Append(f)
- return f
-}
-
// funcsym returns s·f.
func funcsym(s *types.Sym) *types.Sym {
// funcsymsmu here serves to protect not just mutations of funcsyms (below),
}
}
-func dclfunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
- if tfn.Op() != ir.OTFUNC {
- base.Fatalf("expected OTFUNC node, got %v", tfn)
- }
-
- fn := ir.NewFunc(base.Pos)
- fn.Nname = ir.NewFuncNameAt(base.Pos, sym, fn)
- fn.Nname.Defn = fn
- fn.Nname.Ntype = tfn
- ir.MarkFunc(fn.Nname)
- funchdr(fn)
- fn.Nname.Ntype = typecheckNtype(fn.Nname.Ntype)
- return fn
-}
-
type nowritebarrierrecChecker struct {
// extraCalls contains extra function calls that may not be
// visible during later analysis. It maps from the ODCLFUNC of
// important to handle it for this check, so we model it
// directly. This has to happen before transformclosure since
// it's a lot harder to work out the argument after.
- for _, n := range Target.Decls {
+ for _, n := range typecheck.Target.Decls {
if n.Op() != ir.ODCLFUNC {
continue
}
// q is the queue of ODCLFUNC Nodes to visit in BFS order.
var q ir.NameQueue
- for _, n := range Target.Decls {
+ for _, n := range typecheck.Target.Decls {
if n.Op() != ir.ODCLFUNC {
continue
}
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
p.errorAt(pos, "go:embed cannot apply to var without type")
return exprs
}
- if dclcontext != ir.PEXTERN {
+ if typecheck.DeclContext != ir.PEXTERN {
p.errorAt(pos, "go:embed cannot apply to var inside func")
return exprs
}
v := names[0]
- Target.Embeds = append(Target.Embeds, v)
+ typecheck.Target.Embeds = append(typecheck.Target.Embeds, v)
v.Embed = new([]ir.Embed)
for _, e := range embeds {
*v.Embed = append(*v.Embed, ir.Embed{Pos: p.makeXPos(e.Pos), Patterns: e.Patterns})
}
func dumpembeds() {
- for _, v := range Target.Embeds {
+ for _, v := range typecheck.Target.Embeds {
initEmbed(v)
}
}
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
call := call.(*ir.CallExpr)
- fixVariadicCall(call)
+ typecheck.FixVariadicCall(call)
// Pick out the function callee, if statically known.
var fn *ir.Name
return "too large for stack"
}
- if n.Op() == ir.OCLOSURE && closureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
+ if n.Op() == ir.OCLOSURE && typecheck.ClosureType(n.(*ir.ClosureExpr)).Size() >= ir.MaxImplicitStackVarSize {
return "too large for stack"
}
- if n.Op() == ir.OCALLPART && partialCallType(n.(*ir.CallPartExpr)).Size() >= ir.MaxImplicitStackVarSize {
+ if n.Op() == ir.OCALLPART && typecheck.PartialCallType(n.(*ir.CallPartExpr)).Size() >= ir.MaxImplicitStackVarSize {
return "too large for stack"
}
// Allocate a local stack variable to hold the pointer to the heap copy.
// temp will add it to the function declaration list automatically.
- heapaddr := temp(types.NewPtr(n.Type()))
- heapaddr.SetSym(lookup("&" + n.Sym().Name))
+ heapaddr := typecheck.Temp(types.NewPtr(n.Type()))
+ heapaddr.SetSym(typecheck.Lookup("&" + n.Sym().Name))
heapaddr.SetPos(n.Pos())
// Unset AutoTemp to persist the &foo variable name through SSA to
// Preserve a copy so we can still write code referring to the original,
// and substitute that copy into the function declaration list
// so that analyses of the local (on-stack) variables use it.
- stackcopy := NewName(n.Sym())
+ stackcopy := typecheck.NewName(n.Sym())
stackcopy.SetType(n.Type())
stackcopy.SetFrameOffset(n.FrameOffset())
stackcopy.Class_ = n.Class_
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/bio"
- "cmd/internal/src"
"fmt"
"go/constant"
)
}
}
-// exportsym marks n for export (or reexport).
-func exportsym(n *ir.Name) {
- if n.Sym().OnExportList() {
- return
- }
- n.Sym().SetOnExportList(true)
-
- if base.Flag.E != 0 {
- fmt.Printf("export symbol %v\n", n.Sym())
- }
-
- Target.Exports = append(Target.Exports, n)
-}
-
-func initname(s string) bool {
- return s == "init"
-}
-
-func autoexport(n *ir.Name, ctxt ir.Class) {
- if n.Sym().Pkg != types.LocalPkg {
- return
- }
- if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || dclcontext != ir.PEXTERN {
- return
- }
- if n.Type() != nil && n.Type().IsKind(types.TFUNC) && ir.IsMethod(n) {
- return
- }
-
- if types.IsExported(n.Sym().Name) || initname(n.Sym().Name) {
- exportsym(n)
- }
- if base.Flag.AsmHdr != "" && !n.Sym().Asm() {
- n.Sym().SetAsm(true)
- Target.Asms = append(Target.Asms, n)
- }
-}
-
func dumpexport(bout *bio.Writer) {
p := &exporter{marked: make(map[*types.Type]bool)}
- for _, n := range Target.Exports {
+ for _, n := range typecheck.Target.Exports {
p.markObject(n)
}
// The linker also looks for the $$ marker - use char after $$ to distinguish format.
exportf(bout, "\n$$B\n") // indicate binary export format
off := bout.Offset()
- iexport(bout.Writer)
+ typecheck.WriteExports(bout.Writer)
size := bout.Offset() - off
exportf(bout, "\n$$\n")
}
}
-func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class) *ir.Name {
- if n := s.PkgDef(); n != nil {
- base.Fatalf("importsym of symbol that already exists: %v", n)
- }
-
- n := ir.NewDeclNameAt(pos, op, s)
- n.Class_ = ctxt // TODO(mdempsky): Move this into NewDeclNameAt too?
- s.SetPkgDef(n)
- s.Importdef = ipkg
- return n
-}
-
-// importtype returns the named type declared by symbol s.
-// If no such type has been declared yet, a forward declaration is returned.
-// ipkg is the package being imported
-func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *ir.Name {
- n := importsym(ipkg, pos, s, ir.OTYPE, ir.PEXTERN)
- n.SetType(types.NewNamed(n))
- return n
-}
-
-// importobj declares symbol s as an imported object representable by op.
-// ipkg is the package being imported
-func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class, t *types.Type) *ir.Name {
- n := importsym(ipkg, pos, s, op, ctxt)
- n.SetType(t)
- if ctxt == ir.PFUNC {
- n.Sym().SetFunc(true)
- }
- return n
-}
-
-// importconst declares symbol s as an imported constant with type t and value val.
-// ipkg is the package being imported
-func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) *ir.Name {
- n := importobj(ipkg, pos, s, ir.OLITERAL, ir.PEXTERN, t)
- n.SetVal(val)
- return n
-}
-
-// importfunc declares symbol s as an imported function with type t.
-// ipkg is the package being imported
-func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
- n := importobj(ipkg, pos, s, ir.ONAME, ir.PFUNC, t)
-
- fn := ir.NewFunc(pos)
- fn.SetType(t)
- n.SetFunc(fn)
- fn.Nname = n
-
- return n
-}
-
-// importvar declares symbol s as an imported variable with type t.
-// ipkg is the package being imported
-func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
- return importobj(ipkg, pos, s, ir.ONAME, ir.PEXTERN, t)
-}
-
-// importalias declares symbol s as an imported type alias with type t.
-// ipkg is the package being imported
-func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
- return importobj(ipkg, pos, s, ir.OTYPE, ir.PEXTERN, t)
-}
-
func dumpasmhdr() {
b, err := bio.Create(base.Flag.AsmHdr)
if err != nil {
base.Fatalf("%v", err)
}
fmt.Fprintf(b, "// generated by compile -asmhdr from package %s\n\n", types.LocalPkg.Name)
- for _, n := range Target.Asms {
+ for _, n := range typecheck.Target.Asms {
if n.Sym().IsBlank() {
continue
}
b.Close()
}
+
+type exporter struct {
+ marked map[*types.Type]bool // types already seen by markType
+}
+
+// markObject visits a reachable object.
+func (p *exporter) markObject(n ir.Node) {
+ if n.Op() == ir.ONAME {
+ n := n.(*ir.Name)
+ if n.Class_ == ir.PFUNC {
+ inlFlood(n, typecheck.Export)
+ }
+ }
+
+ p.markType(n.Type())
+}
+
+// markType recursively visits types reachable from t to identify
+// functions whose inline bodies may be needed.
+func (p *exporter) markType(t *types.Type) {
+ if p.marked[t] {
+ return
+ }
+ p.marked[t] = true
+
+ // If this is a named type, mark all of its associated
+ // methods. Skip interface types because t.Methods contains
+ // only their unexpanded method set (i.e., exclusive of
+ // interface embeddings), and the switch statement below
+ // handles their full method set.
+ if t.Sym() != nil && t.Kind() != types.TINTER {
+ for _, m := range t.Methods().Slice() {
+ if types.IsExported(m.Sym.Name) {
+ p.markObject(ir.AsNode(m.Nname))
+ }
+ }
+ }
+
+ // Recursively mark any types that can be produced given a
+ // value of type t: dereferencing a pointer; indexing or
+ // iterating over an array, slice, or map; receiving from a
+ // channel; accessing a struct field or interface method; or
+ // calling a function.
+ //
+ // Notably, we don't mark function parameter types, because
+ // the user already needs some way to construct values of
+ // those types.
+ switch t.Kind() {
+ case types.TPTR, types.TARRAY, types.TSLICE:
+ p.markType(t.Elem())
+
+ case types.TCHAN:
+ if t.ChanDir().CanRecv() {
+ p.markType(t.Elem())
+ }
+
+ case types.TMAP:
+ p.markType(t.Key())
+ p.markType(t.Elem())
+
+ case types.TSTRUCT:
+ for _, f := range t.FieldSlice() {
+ if types.IsExported(f.Sym.Name) || f.Embedded != 0 {
+ p.markType(f.Type)
+ }
+ }
+
+ case types.TFUNC:
+ for _, f := range t.Results().FieldSlice() {
+ p.markType(f.Type)
+ }
+
+ case types.TINTER:
+ for _, f := range t.FieldSlice() {
+ if types.IsExported(f.Sym.Name) {
+ p.markType(f.Type)
+ }
+ }
+ }
+}
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
- "cmd/compile/internal/base"
- "cmd/compile/internal/ir"
- "cmd/compile/internal/types"
- "cmd/internal/obj"
- "cmd/internal/src"
- "strconv"
-)
-
-// sysfunc looks up Go function name in package runtime. This function
-// must follow the internal calling convention.
-func sysfunc(name string) *obj.LSym {
- s := ir.Pkgs.Runtime.Lookup(name)
- s.SetFunc(true)
- return s.Linksym()
-}
-
-// sysvar looks up a variable (or assembly function) name in package
-// runtime. If this is a function, it may have a special calling
-// convention.
-func sysvar(name string) *obj.LSym {
- return ir.Pkgs.Runtime.Lookup(name).Linksym()
-}
-
-// autotmpname returns the name for an autotmp variable numbered n.
-func autotmpname(n int) string {
- // Give each tmp a different name so that they can be registerized.
- // Add a preceding . to avoid clashing with legal names.
- const prefix = ".autotmp_"
- // Start with a buffer big enough to hold a large n.
- b := []byte(prefix + " ")[:len(prefix)]
- b = strconv.AppendInt(b, int64(n), 10)
- return types.InternString(b)
-}
-
-// make a new Node off the books
-func tempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
- if curfn == nil {
- base.Fatalf("no curfn for tempAt")
- }
- if curfn.Op() == ir.OCLOSURE {
- ir.Dump("tempAt", curfn)
- base.Fatalf("adding tempAt to wrong closure function")
- }
- if t == nil {
- base.Fatalf("tempAt called with nil type")
- }
-
- s := &types.Sym{
- Name: autotmpname(len(curfn.Dcl)),
- Pkg: types.LocalPkg,
- }
- n := ir.NewNameAt(pos, s)
- s.Def = n
- n.SetType(t)
- n.Class_ = ir.PAUTO
- n.SetEsc(ir.EscNever)
- n.Curfn = curfn
- n.SetUsed(true)
- n.SetAutoTemp(true)
- curfn.Dcl = append(curfn.Dcl, n)
-
- types.CalcSize(t)
-
- return n
-}
-
-func temp(t *types.Type) *ir.Name {
- return tempAt(base.Pos, ir.CurFunc, t)
-}
package gc
import (
- "cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
"cmd/compile/internal/types"
"cmd/internal/obj"
var pragcgobuf [][]string
-var decldepth int32
-
-var inimport bool // set during import
-
var zerosize int64
-var (
- okforeq [types.NTYPE]bool
- okforadd [types.NTYPE]bool
- okforand [types.NTYPE]bool
- okfornone [types.NTYPE]bool
- okforbool [types.NTYPE]bool
- okforcap [types.NTYPE]bool
- okforlen [types.NTYPE]bool
- okforarith [types.NTYPE]bool
-)
-
-var (
- okfor [ir.OEND][]bool
- iscmp [ir.OEND]bool
-)
-
var (
funcsymsmu sync.Mutex // protects funcsyms and associated package lookups (see func funcsym)
funcsyms []*types.Sym
)
-var dclcontext ir.Class // PEXTERN/PAUTO
-
-var typecheckok bool
-
// interface to back end
type Arch struct {
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/objabi"
// Q: is this needed?
savepos := base.Pos
- savedclcontext := dclcontext
+ savedclcontext := typecheck.DeclContext
savedcurfn := ir.CurFunc
base.Pos = base.AutogeneratedPos
- dclcontext = ir.PEXTERN
+ typecheck.DeclContext = ir.PEXTERN
// At the moment we don't support wrapping a method, we'd need machinery
// below to handle the receiver. Panic if we see this scenario.
var noReceiver *ir.Field
tfn := ir.NewFuncType(base.Pos,
noReceiver,
- structargs(ft.Params(), true),
- structargs(ft.Results(), false))
+ typecheck.NewFuncParams(ft.Params(), true),
+ typecheck.NewFuncParams(ft.Results(), false))
// Reuse f's types.Sym to create a new ODCLFUNC/function.
- fn := dclfunc(f.Nname.Sym(), tfn)
+ fn := typecheck.DeclFunc(f.Nname.Sym(), tfn)
fn.SetDupok(true)
fn.SetWrapper(true) // ignore frame for panic+recover matching
}
fn.Body.Append(tail)
- funcbody()
+ typecheck.FinishFuncBody()
if base.Debug.DclStack != 0 {
types.CheckDclstack()
}
- typecheckFunc(fn)
+ typecheck.Func(fn)
ir.CurFunc = fn
- typecheckslice(fn.Body, ctxStmt)
+ typecheck.Stmts(fn.Body)
escapeFuncs([]*ir.Func{fn}, false)
- Target.Decls = append(Target.Decls, fn)
+ typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
// Restore previous context.
base.Pos = savepos
- dclcontext = savedclcontext
+ typecheck.DeclContext = savedclcontext
ir.CurFunc = savedcurfn
}
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
)
// the name, normally "pkg.init", is altered to "pkg.init.0".
var renameinitgen int
-// Function collecting autotmps generated during typechecking,
-// to be included in the package-level init function.
-var initTodo = ir.NewFunc(base.Pos)
-
func renameinit() *types.Sym {
- s := lookupN("init.", renameinitgen)
+ s := typecheck.LookupNum("init.", renameinitgen)
renameinitgen++
return s
}
// 2) Initialize all the variables that have initializers.
// 3) Run any init functions.
func fninit() *ir.Name {
- nf := initOrder(Target.Decls)
+ nf := initOrder(typecheck.Target.Decls)
var deps []*obj.LSym // initTask records for packages the current package depends on
var fns []*obj.LSym // functions to call for package initialization
// Find imported packages with init tasks.
- for _, pkg := range Target.Imports {
- n := resolve(ir.NewIdent(base.Pos, pkg.Lookup(".inittask")))
+ for _, pkg := range typecheck.Target.Imports {
+ n := typecheck.Resolve(ir.NewIdent(base.Pos, pkg.Lookup(".inittask")))
if n.Op() == ir.ONONAME {
continue
}
// Make a function that contains all the initialization statements.
if len(nf) > 0 {
base.Pos = nf[0].Pos() // prolog/epilog gets line number of first init stmt
- initializers := lookup("init")
- fn := dclfunc(initializers, ir.NewFuncType(base.Pos, nil, nil, nil))
- for _, dcl := range initTodo.Dcl {
+ initializers := typecheck.Lookup("init")
+ fn := typecheck.DeclFunc(initializers, ir.NewFuncType(base.Pos, nil, nil, nil))
+ for _, dcl := range typecheck.InitTodoFunc.Dcl {
dcl.Curfn = fn
}
- fn.Dcl = append(fn.Dcl, initTodo.Dcl...)
- initTodo.Dcl = nil
+ fn.Dcl = append(fn.Dcl, typecheck.InitTodoFunc.Dcl...)
+ typecheck.InitTodoFunc.Dcl = nil
fn.Body.Set(nf)
- funcbody()
+ typecheck.FinishFuncBody()
- typecheckFunc(fn)
+ typecheck.Func(fn)
ir.CurFunc = fn
- typecheckslice(nf, ctxStmt)
+ typecheck.Stmts(nf)
ir.CurFunc = nil
- Target.Decls = append(Target.Decls, fn)
+ typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
fns = append(fns, initializers.Linksym())
}
- if initTodo.Dcl != nil {
+ if typecheck.InitTodoFunc.Dcl != nil {
// We only generate temps using initTodo if there
// are package-scope initialization statements, so
// something's weird if we get here.
base.Fatalf("initTodo still has declarations")
}
- initTodo = nil
+ typecheck.InitTodoFunc = nil
// Record user init functions.
- for _, fn := range Target.Inits {
+ for _, fn := range typecheck.Target.Inits {
// Skip init functions with empty bodies.
if len(fn.Body) == 1 {
if stmt := fn.Body[0]; stmt.Op() == ir.OBLOCK && len(stmt.(*ir.BlockStmt).List) == 0 {
}
// Make an .inittask structure.
- sym := lookup(".inittask")
- task := NewName(sym)
+ sym := typecheck.Lookup(".inittask")
+ task := typecheck.NewName(sym)
task.SetType(types.Types[types.TUINT8]) // fake type
task.Class_ = ir.PEXTERN
sym.Def = task
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src"
func InlinePackage() {
// Find functions that can be inlined and clone them before walk expands them.
- ir.VisitFuncsBottomUp(Target.Decls, func(list []*ir.Func, recursive bool) {
+ ir.VisitFuncsBottomUp(typecheck.Target.Decls, func(list []*ir.Func, recursive bool) {
numfns := numNonClosures(list)
for _, n := range list {
if !recursive || numfns > 1 {
})
}
-// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
-// the ->sym can be re-used in the local package, so peel it off the receiver's type.
-func fnpkg(fn *ir.Name) *types.Pkg {
- if ir.IsMethod(fn) {
- // method
- rcvr := fn.Type().Recv().Type
-
- if rcvr.IsPtr() {
- rcvr = rcvr.Elem()
- }
- if rcvr.Sym() == nil {
- base.Fatalf("receiver with no sym: [%v] %L (%v)", fn.Sym(), fn, rcvr)
- }
- return rcvr.Sym().Pkg
- }
-
- // non-method
- return fn.Sym().Pkg
-}
-
-// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
-// because they're a copy of an already checked body.
-func typecheckinl(fn *ir.Func) {
- lno := ir.SetPos(fn.Nname)
-
- expandInline(fn)
-
- // typecheckinl is only for imported functions;
- // their bodies may refer to unsafe as long as the package
- // was marked safe during import (which was checked then).
- // the ->inl of a local function has been typechecked before caninl copied it.
- pkg := fnpkg(fn.Nname)
-
- if pkg == types.LocalPkg || pkg == nil {
- return // typecheckinl on local function
- }
-
- if base.Flag.LowerM > 2 || base.Debug.Export != 0 {
- fmt.Printf("typecheck import [%v] %L { %v }\n", fn.Sym(), fn, ir.Nodes(fn.Inl.Body))
- }
-
- savefn := ir.CurFunc
- ir.CurFunc = fn
- typecheckslice(fn.Inl.Body, ctxStmt)
- ir.CurFunc = savefn
-
- // During expandInline (which imports fn.Func.Inl.Body),
- // declarations are added to fn.Func.Dcl by funcHdr(). Move them
- // to fn.Func.Inl.Dcl for consistency with how local functions
- // behave. (Append because typecheckinl may be called multiple
- // times.)
- fn.Inl.Dcl = append(fn.Inl.Dcl, fn.Dcl...)
- fn.Dcl = nil
-
- base.Pos = lno
-}
-
// Caninl determines whether fn is inlineable.
// If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
// fn and ->nbody will already have been typechecked.
}
fn.SetExportInline(true)
- typecheckinl(fn)
+ typecheck.ImportedBody(fn)
// Recursively identify all referenced functions for
// reexport. We want to include even non-called functions,
as.Rhs.Set(inlconv2list(as.Rhs[0].(*ir.InlinedCallExpr)))
as.SetOp(ir.OAS2)
as.SetTypecheck(0)
- n = typecheck(as, ctxStmt)
+ n = typecheck.Stmt(as)
}
}
inlMap[fn] = false
}()
if base.Debug.TypecheckInl == 0 {
- typecheckinl(fn)
+ typecheck.ImportedBody(fn)
}
// We have a function node, and it has an inlineable body.
}
if v.Byval() {
- iv := typecheck(inlvar(v), ctxExpr)
+ iv := typecheck.Expr(inlvar(v))
ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, iv))
- ninit.Append(typecheck(ir.NewAssignStmt(base.Pos, iv, o), ctxStmt))
+ ninit.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, iv, o)))
inlvars[v] = iv
} else {
- addr := NewName(lookup("&" + v.Sym().Name))
+ addr := typecheck.NewName(typecheck.Lookup("&" + v.Sym().Name))
addr.SetType(types.NewPtr(v.Type()))
- ia := typecheck(inlvar(addr), ctxExpr)
+ ia := typecheck.Expr(inlvar(addr))
ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, ia))
- ninit.Append(typecheck(ir.NewAssignStmt(base.Pos, ia, nodAddr(o)), ctxStmt))
+ ninit.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, ia, typecheck.NodAddr(o))))
inlvars[addr] = ia
// When capturing by reference, all occurrence of the captured var
// must be substituted with dereference of the temporary address
- inlvars[v] = typecheck(ir.NewStarExpr(base.Pos, ia), ctxExpr)
+ inlvars[v] = typecheck.Expr(ir.NewStarExpr(base.Pos, ia))
}
}
}
// nothing should have moved to the heap yet.
base.Fatalf("impossible: %v", ln)
}
- inlf := typecheck(inlvar(ln), ctxExpr)
+ inlf := typecheck.Expr(inlvar(ln))
inlvars[ln] = inlf
if base.Flag.GenDwarfInl > 0 {
if ln.Class_ == ir.PPARAM {
if n := ir.AsNode(t.Nname); n != nil && !ir.IsBlank(n) && !strings.HasPrefix(n.Sym().Name, "~r") {
n := n.(*ir.Name)
m = inlvar(n)
- m = typecheck(m, ctxExpr)
+ m = typecheck.Expr(m)
inlvars[n] = m
delayretvars = false // found a named result parameter
} else {
vas = ir.NewAssignStmt(base.Pos, nil, nil)
vas.X = inlParam(param, vas, inlvars)
if len(varargs) == 0 {
- vas.Y = nodnil()
+ vas.Y = typecheck.NodNil()
vas.Y.SetType(param.Type)
} else {
lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type).(ir.Ntype), nil)
}
if len(as.Rhs) != 0 {
- ninit.Append(typecheck(as, ctxStmt))
+ ninit.Append(typecheck.Stmt(as))
}
if vas != nil {
- ninit.Append(typecheck(vas, ctxStmt))
+ ninit.Append(typecheck.Stmt(vas))
}
if !delayretvars {
for _, n := range retvars {
ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n))
ras := ir.NewAssignStmt(base.Pos, n, nil)
- ninit.Append(typecheck(ras, ctxStmt))
+ ninit.Append(typecheck.Stmt(ras))
}
}
- retlabel := autolabel(".i")
+ retlabel := typecheck.AutoLabel(".i")
inlgen++
lab := ir.NewLabelStmt(base.Pos, retlabel)
body = append(body, lab)
- typecheckslice(body, ctxStmt)
+ typecheck.Stmts(body)
if base.Flag.GenDwarfInl > 0 {
for _, v := range inlfvars {
fmt.Printf("inlvar %+v\n", var_)
}
- n := NewName(var_.Sym())
+ n := typecheck.NewName(var_.Sym())
n.SetType(var_.Type())
n.Class_ = ir.PAUTO
n.SetUsed(true)
// Synthesize a variable to store the inlined function's results in.
func retvar(t *types.Field, i int) ir.Node {
- n := NewName(lookupN("~R", i))
+ n := typecheck.NewName(typecheck.LookupNum("~R", i))
n.SetType(t.Type)
n.Class_ = ir.PAUTO
n.SetUsed(true)
// Synthesize a variable to store the inlined function's arguments
// when they come from a multiple return call.
func argvar(t *types.Type, i int) ir.Node {
- n := NewName(lookupN("~arg", i))
+ n := typecheck.NewName(typecheck.LookupNum("~arg", i))
n.SetType(t.Elem())
n.Class_ = ir.PAUTO
n.SetUsed(true)
}
}
- init = append(init, typecheck(as, ctxStmt))
+ init = append(init, typecheck.Stmt(as))
}
init = append(init, ir.NewBranchStmt(base.Pos, ir.OGOTO, subst.retlabel))
- typecheckslice(init, ctxStmt)
+ typecheck.Stmts(init)
return ir.NewBlockStmt(base.Pos, init)
case ir.OGOTO:
m.SetPos(subst.updatedPos(m.Pos()))
m.PtrInit().Set(nil)
p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
- m.Label = lookup(p)
+ m.Label = typecheck.Lookup(p)
return m
case ir.OLABEL:
m.SetPos(subst.updatedPos(m.Pos()))
m.PtrInit().Set(nil)
p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
- m.Label = lookup(p)
+ m.Label = typecheck.Lookup(p)
return m
}
dt := ir.NewTypeAssertExpr(sel.Pos(), sel.X, nil)
dt.SetType(typ)
- x := typecheck(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel), ctxExpr|ctxCallee)
+ x := typecheck.Callee(ir.NewSelectorExpr(sel.Pos(), ir.OXDOT, dt, sel.Sel))
switch x.Op() {
case ir.ODOTMETH:
x := x.(*ir.SelectorExpr)
"cmd/compile/internal/ir"
"cmd/compile/internal/logopt"
"cmd/compile/internal/ssa"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/bio"
"cmd/internal/dwarf"
}
}
-// Target is the package being compiled.
-var Target *ir.Package
-
// Main parses flags and Go source files specified in the command-line
// arguments, type-checks the parsed Go package, compiles functions to machine
// code, and finally writes the compiled package definition to disk.
return typenamesym(t).Linksym()
}
- Target = new(ir.Package)
+ typecheck.Target = new(ir.Package)
- NeedFuncSym = makefuncsym
- NeedITab = func(t, iface *types.Type) { itabname(t, iface) }
- NeedRuntimeType = addsignat // TODO(rsc): typenamesym for lock?
+ typecheck.NeedFuncSym = makefuncsym
+ typecheck.NeedITab = func(t, iface *types.Type) { itabname(t, iface) }
+ typecheck.NeedRuntimeType = addsignat // TODO(rsc): typenamesym for lock?
base.AutogeneratedPos = makePos(src.NewFileBase("<autogenerated>", "<autogenerated>"), 1, 0)
types.TypeLinkSym = func(t *types.Type) *obj.LSym {
return typenamesym(t).Linksym()
}
- TypecheckInit()
+ typecheck.Init()
// Parse input.
base.Timer.Start("fe", "parse")
recordPackageName()
// Typecheck.
- TypecheckPackage()
+ typecheck.Package()
// With all user code typechecked, it's now safe to verify unused dot imports.
checkDotImports()
// Build init task.
if initTask := fninit(); initTask != nil {
- exportsym(initTask)
+ typecheck.Export(initTask)
}
// Inlining
}
// Devirtualize.
- for _, n := range Target.Decls {
+ for _, n := range typecheck.Target.Decls {
if n.Op() == ir.ODCLFUNC {
devirtualize(n.(*ir.Func))
}
// Large values are also moved off stack in escape analysis;
// because large values may contain pointers, it must happen early.
base.Timer.Start("fe", "escapes")
- escapes(Target.Decls)
+ escapes(typecheck.Target.Decls)
// Collect information for go:nowritebarrierrec
// checking. This must happen before transformclosure.
// This needs to happen before walk, because closures must be transformed
// before walk reaches a call of a closure.
base.Timer.Start("fe", "xclosures")
- for _, n := range Target.Decls {
+ for _, n := range typecheck.Target.Decls {
if n.Op() == ir.ODCLFUNC {
n := n.(*ir.Func)
if n.OClosure != nil {
// Don't use range--walk can add functions to Target.Decls.
base.Timer.Start("be", "compilefuncs")
fcount := int64(0)
- for i := 0; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
+ for i := 0; i < len(typecheck.Target.Decls); i++ {
+ n := typecheck.Target.Decls[i]
if n.Op() == ir.ODCLFUNC {
funccompile(n.(*ir.Func))
fcount++
}
CheckLargeStacks()
- CheckFuncStack()
+ typecheck.CheckFuncStack()
if len(compilequeue) != 0 {
base.Fatalf("%d uncompiled functions", len(compilequeue))
func cgoSymABIs() {
// The linker expects an ABI0 wrapper for all cgo-exported
// functions.
- for _, prag := range Target.CgoPragmas {
+ for _, prag := range typecheck.Target.CgoPragmas {
switch prag[0] {
case "cgo_export_static", "cgo_export_dynamic":
if symabiRefs == nil {
return "", false
}
-// loadsys loads the definitions for the low-level runtime functions,
-// so that the compiler can generate calls to them,
-// but does not make them visible to user code.
-func loadsys() {
- types.Block = 1
-
- inimport = true
- typecheckok = true
-
- typs := runtimeTypes()
- for _, d := range &runtimeDecls {
- sym := ir.Pkgs.Runtime.Lookup(d.name)
- typ := typs[d.typ]
- switch d.tag {
- case funcTag:
- importfunc(ir.Pkgs.Runtime, src.NoXPos, sym, typ)
- case varTag:
- importvar(ir.Pkgs.Runtime, src.NoXPos, sym, typ)
- default:
- base.Fatalf("unhandled declaration tag %v", d.tag)
- }
- }
-
- typecheckok = false
- inimport = false
-}
-
// myheight tracks the local package's height based on packages
// imported so far.
var myheight int
base.Errorf("import %s: unexpected package format byte: %v", file, c)
base.ErrorExit()
}
- fingerprint = iimport(importpkg, imp)
+ fingerprint = typecheck.ReadImports(importpkg, imp)
default:
base.Errorf("no import in %q", path_)
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/syntax"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/objabi"
"cmd/internal/src"
func (p *noder) funcBody(fn *ir.Func, block *syntax.BlockStmt) {
oldScope := p.scope
p.scope = 0
- funchdr(fn)
+ typecheck.StartFuncBody(fn)
if block != nil {
body := p.stmts(block.List)
fn.Endlineno = base.Pos
}
- funcbody()
+ typecheck.FinishFuncBody()
p.scope = oldScope
}
p.checkUnused(pragma)
}
- Target.Decls = append(Target.Decls, p.decls(p.file.DeclList)...)
+ typecheck.Target.Decls = append(typecheck.Target.Decls, p.decls(p.file.DeclList)...)
base.Pos = src.NoXPos
clearImports()
p.errorAt(l.pos, "//go:linkname only allowed in Go files that import \"unsafe\"")
continue
}
- n := ir.AsNode(lookup(l.local).Def)
+ n := ir.AsNode(typecheck.Lookup(l.local).Def)
if n == nil || n.Op() != ir.ONAME {
// TODO(mdempsky): Change to p.errorAt before Go 1.17 release.
// base.WarnfAt(p.makeXPos(l.pos), "//go:linkname must refer to declared function or variable (will be an error in Go 1.17)")
}
n.Sym().Linkname = l.remote
}
- Target.CgoPragmas = append(Target.CgoPragmas, p.pragcgobuf...)
+ typecheck.Target.CgoPragmas = append(typecheck.Target.CgoPragmas, p.pragcgobuf...)
}
func (p *noder) decls(decls []syntax.Decl) (l []ir.Node) {
}
if !ipkg.Direct {
- Target.Imports = append(Target.Imports, ipkg)
+ typecheck.Target.Imports = append(typecheck.Target.Imports, ipkg)
}
ipkg.Direct = true
if imp.LocalPkgName != nil {
my = p.name(imp.LocalPkgName)
} else {
- my = lookup(ipkg.Name)
+ my = typecheck.Lookup(ipkg.Name)
}
pack := ir.NewPkgName(p.pos(imp), my, ipkg)
return
}
if my.Def != nil {
- redeclare(pack.Pos(), my, "as imported package name")
+ typecheck.Redeclared(pack.Pos(), my, "as imported package name")
}
my.Def = pack
my.Lastlineno = pack.Pos()
}
p.setlineno(decl)
- return variter(names, typ, exprs)
+ return typecheck.DeclVars(names, typ, exprs)
}
// constState tracks state between constant specifiers within a
if decl.Values == nil {
v = ir.DeepCopy(n.Pos(), v)
}
- declare(n, dclcontext)
+ typecheck.Declare(n, typecheck.DeclContext)
n.Ntype = typ
n.Defn = v
func (p *noder) typeDecl(decl *syntax.TypeDecl) ir.Node {
n := p.declName(ir.OTYPE, decl.Name)
- declare(n, dclcontext)
+ typecheck.Declare(n, typecheck.DeclContext)
// decl.Type may be nil but in that case we got a syntax error during parsing
typ := p.typeExprOrNil(decl.Type)
if len(t.Params) > 0 || len(t.Results) > 0 {
base.ErrorfAt(f.Pos(), "func init must have no arguments and no return values")
}
- Target.Inits = append(Target.Inits, f)
+ typecheck.Target.Inits = append(typecheck.Target.Inits, f)
}
if types.LocalPkg.Name == "main" && name.Name == "main" {
}
if fun.Recv == nil {
- declare(f.Nname, ir.PFUNC)
+ typecheck.Declare(f.Nname, ir.PFUNC)
}
p.funcBody(f, fun.Body)
pos, op := p.pos(expr), p.unOp(expr.Op)
switch op {
case ir.OADDR:
- return nodAddrAt(pos, x)
+ return typecheck.NodAddrAt(pos, x)
case ir.ODEREF:
return ir.NewStarExpr(pos, x)
}
}
sym := p.packname(typ)
- n := ir.NewField(p.pos(typ), lookup(sym.Name), importName(sym).(ir.Ntype), nil)
+ n := ir.NewField(p.pos(typ), typecheck.Lookup(sym.Name), importName(sym).(ir.Ntype), nil)
n.Embedded = true
if isStar {
}
newOrErr = true
- n := NewName(sym)
- declare(n, dclcontext)
+ n := typecheck.NewName(sym)
+ typecheck.Declare(n, typecheck.DeclContext)
n.Defn = defn
defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n))
res[i] = n
n.List.Set(p.exprList(clause.Cases))
}
if tswitch != nil && tswitch.Tag != nil {
- nn := NewName(tswitch.Tag.Sym())
- declare(nn, dclcontext)
+ nn := typecheck.NewName(tswitch.Tag.Sym())
+ typecheck.Declare(nn, typecheck.DeclContext)
n.Vars = []ir.Node{nn}
// keep track of the instances for reporting unused
nn.Defn = tswitch
}
func (p *noder) name(name *syntax.Name) *types.Sym {
- return lookup(name.Value)
+ return typecheck.Lookup(name.Value)
}
func (p *noder) mkname(name *syntax.Name) ir.Node {
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/bio"
"cmd/internal/obj"
}
func dumpdata() {
- numExterns := len(Target.Externs)
- numDecls := len(Target.Decls)
+ numExterns := len(typecheck.Target.Externs)
+ numDecls := len(typecheck.Target.Decls)
- dumpglobls(Target.Externs)
+ dumpglobls(typecheck.Target.Externs)
dumpfuncsyms()
addptabs()
- numExports := len(Target.Exports)
- addsignats(Target.Externs)
+ numExports := len(typecheck.Target.Exports)
+ addsignats(typecheck.Target.Externs)
dumpsignats()
dumptabs()
numPTabs, numITabs := CountTabs()
// In the typical case, we loop 0 or 1 times.
// It was not until issue 24761 that we found any code that required a loop at all.
for {
- for i := numDecls; i < len(Target.Decls); i++ {
- n := Target.Decls[i]
+ for i := numDecls; i < len(typecheck.Target.Decls); i++ {
+ n := typecheck.Target.Decls[i]
if n.Op() == ir.ODCLFUNC {
funccompile(n.(*ir.Func))
}
}
- numDecls = len(Target.Decls)
+ numDecls = len(typecheck.Target.Decls)
compileFunctions()
dumpsignats()
- if numDecls == len(Target.Decls) {
+ if numDecls == len(typecheck.Target.Decls) {
break
}
}
// Dump extra globals.
- dumpglobls(Target.Externs[numExterns:])
+ dumpglobls(typecheck.Target.Externs[numExterns:])
if zerosize > 0 {
zero := ir.Pkgs.Map.Lookup("zero")
addGCLocals()
- if numExports != len(Target.Exports) {
+ if numExports != len(typecheck.Target.Exports) {
base.Fatalf("Target.Exports changed after compile functions loop")
}
newNumPTabs, newNumITabs := CountTabs()
func dumpLinkerObj(bout *bio.Writer) {
printObjHeader(bout)
- if len(Target.CgoPragmas) != 0 {
+ if len(typecheck.Target.CgoPragmas) != 0 {
// write empty export section; must be before cgo section
fmt.Fprintf(bout, "\n$$\n\n$$\n\n")
fmt.Fprintf(bout, "\n$$ // cgo\n")
- if err := json.NewEncoder(bout).Encode(Target.CgoPragmas); err != nil {
+ if err := json.NewEncoder(bout).Encode(typecheck.Target.CgoPragmas); err != nil {
base.Fatalf("serializing pragcgobuf: %v", err)
}
fmt.Fprintf(bout, "\n$$\n\n")
if !base.Ctxt.Flag_dynlink || types.LocalPkg.Name != "main" {
return
}
- for _, exportn := range Target.Exports {
+ for _, exportn := range typecheck.Target.Exports {
s := exportn.Sym()
nn := ir.AsNode(s.Def)
if nn == nil {
slicedataGen++
symname := fmt.Sprintf(".gobytes.%d", slicedataGen)
sym := types.LocalPkg.Lookup(symname)
- symnode := NewName(sym)
+ symnode := typecheck.NewName(sym)
sym.Def = symnode
lsym := sym.Linksym()
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
// append typechecks stmt and appends it to out.
func (o *Order) append(stmt ir.Node) {
- o.out = append(o.out, typecheck(stmt, ctxStmt))
+ o.out = append(o.out, typecheck.Stmt(stmt))
}
// newTemp allocates a new temporary with the given type,
}
}
if v == nil {
- v = temp(t)
+ v = typecheck.Temp(t)
}
if clear {
o.append(ir.NewAssignStmt(base.Pos, v, nil))
}
a := ir.SepCopy(n).(*ir.UnaryExpr)
a.X = l
- return typecheck(a, ctxExpr)
+ return typecheck.Expr(a)
}
return o.copyExpr(n)
}
a := ir.SepCopy(n).(*ir.UnaryExpr)
a.X = l
- return typecheck(a, ctxExpr)
+ return typecheck.Expr(a)
case ir.ODOT:
n := n.(*ir.SelectorExpr)
}
a := ir.SepCopy(n).(*ir.SelectorExpr)
a.X = l
- return typecheck(a, ctxExpr)
+ return typecheck.Expr(a)
case ir.ODOTPTR:
n := n.(*ir.SelectorExpr)
}
a := ir.SepCopy(n).(*ir.SelectorExpr)
a.X = l
- return typecheck(a, ctxExpr)
+ return typecheck.Expr(a)
case ir.ODEREF:
n := n.(*ir.StarExpr)
}
a := ir.SepCopy(n).(*ir.StarExpr)
a.X = l
- return typecheck(a, ctxExpr)
+ return typecheck.Expr(a)
case ir.OINDEX, ir.OINDEXMAP:
n := n.(*ir.IndexExpr)
a := ir.SepCopy(n).(*ir.IndexExpr)
a.X = l
a.Index = r
- return typecheck(a, ctxExpr)
+ return typecheck.Expr(a)
default:
base.Fatalf("order.safeExpr %v", n.Op())
func (o *Order) addrTemp(n ir.Node) ir.Node {
if n.Op() == ir.OLITERAL || n.Op() == ir.ONIL {
// TODO: expand this to all static composite literal nodes?
- n = defaultlit(n, nil)
+ n = typecheck.DefaultLit(n, nil)
types.CalcSize(n.Type())
vstat := readonlystaticname(n.Type())
var s InitSchedule
if s.out != nil {
base.Fatalf("staticassign of const generated code: %+v", n)
}
- vstat = typecheck(vstat, ctxExpr).(*ir.Name)
+ vstat = typecheck.Expr(vstat).(*ir.Name)
return vstat
}
if isaddrokay(n) {
var out []ir.Node
for i := len(o.temp) - 1; i >= int(mark); i-- {
n := o.temp[i]
- out = append(out, typecheck(ir.NewUnaryExpr(base.Pos, ir.OVARKILL, n), ctxStmt))
+ out = append(out, typecheck.Stmt(ir.NewUnaryExpr(base.Pos, ir.OVARKILL, n)))
}
return out
}
mk.Cap = cp.Y
// Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
mk.SetBounded(mk.Len.Op() == ir.OLEN && ir.SameSafeExpr(mk.Len.(*ir.UnaryExpr).X, cp.Y))
- as.Y = typecheck(mk, ctxExpr)
+ as.Y = typecheck.Expr(mk)
s[1] = nil // remove separate copy call
}
}
n := nn.(*ir.CallExpr)
- fixVariadicCall(n)
+ typecheck.FixVariadicCall(n)
n.X = o.expr(n.X, nil)
o.exprList(n.Args)
x := o.copyExpr(arg.X)
arg.X = x
x.Name().SetAddrtaken(true) // ensure SSA keeps the x variable
- n.Body.Append(typecheck(ir.NewUnaryExpr(base.Pos, ir.OVARLIVE, x), ctxStmt))
+ n.Body.Append(typecheck.Stmt(ir.NewUnaryExpr(base.Pos, ir.OVARLIVE, x)))
}
}
}
t := o.newTemp(m.Type(), false)
n.Lhs[i] = t
a := ir.NewAssignStmt(base.Pos, m, t)
- post = append(post, typecheck(a, ctxStmt))
+ post = append(post, typecheck.Stmt(a))
}
}
l2.Assigned = false
}
l2 = o.copyExpr(l2)
- r := o.expr(typecheck(ir.NewBinaryExpr(n.Pos(), n.AsOp, l2, n.Y), ctxExpr), nil)
- as := typecheck(ir.NewAssignStmt(n.Pos(), l1, r), ctxStmt)
+ r := o.expr(typecheck.Expr(ir.NewBinaryExpr(n.Pos(), n.AsOp, l2, n.Y)), nil)
+ as := typecheck.Stmt(ir.NewAssignStmt(n.Pos(), l1, r))
o.mapAssign(as)
o.cleanTemp(t)
return
if r.Type().IsString() && r.Type() != types.Types[types.TSTRING] {
r = ir.NewConvExpr(base.Pos, ir.OCONV, nil, r)
r.SetType(types.Types[types.TSTRING])
- r = typecheck(r, ctxExpr)
+ r = typecheck.Expr(r)
}
n.X = o.copyExpr(r)
if len(init) > 0 && init[0].Op() == ir.ODCL && init[0].(*ir.Decl).X == n {
init = init[1:]
}
- dcl := typecheck(ir.NewDecl(base.Pos, ir.ODCL, n), ctxStmt)
+ dcl := typecheck.Stmt(ir.NewDecl(base.Pos, ir.ODCL, n))
ncas.PtrInit().Append(dcl)
}
tmp := o.newTemp(t, t.HasPointers())
- as := typecheck(ir.NewAssignStmt(base.Pos, n, conv(tmp, n.Type())), ctxStmt)
+ as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, n, typecheck.Conv(tmp, n.Type())))
ncas.PtrInit().Append(as)
r.Lhs[i] = tmp
}
// Evaluate left-hand side.
lhs := o.expr(n.X, nil)
- o.out = append(o.out, typecheck(ir.NewAssignStmt(base.Pos, r, lhs), ctxStmt))
+ o.out = append(o.out, typecheck.Stmt(ir.NewAssignStmt(base.Pos, r, lhs)))
// Evaluate right-hand side, save generated code.
saveout := o.out
t := o.markTemp()
o.edge()
rhs := o.expr(n.Y, nil)
- o.out = append(o.out, typecheck(ir.NewAssignStmt(base.Pos, r, rhs), ctxStmt))
+ o.out = append(o.out, typecheck.Stmt(ir.NewAssignStmt(base.Pos, r, rhs)))
o.cleanTemp(t)
gen := o.out
o.out = saveout
case ir.OCLOSURE:
n := n.(*ir.ClosureExpr)
if n.Transient() && len(n.Func.ClosureVars) > 0 {
- n.Prealloc = o.newTemp(closureType(n), false)
+ n.Prealloc = o.newTemp(typecheck.ClosureType(n), false)
}
return n
n := n.(*ir.CallPartExpr)
n.X = o.expr(n.X, nil)
if n.Transient() {
- t := partialCallType(n)
+ t := typecheck.PartialCallType(n)
n.Prealloc = o.newTemp(t, false)
}
return n
// Emit the creation of the map (with all its static entries).
m := o.newTemp(n.Type(), false)
as := ir.NewAssignStmt(base.Pos, m, n)
- typecheck(as, ctxStmt)
+ typecheck.Stmt(as)
o.stmt(as)
// Emit eval+insert of dynamic entries, one at a time.
for _, r := range dynamics {
as := ir.NewAssignStmt(base.Pos, ir.NewIndexExpr(base.Pos, m, r.Key), r.Value)
- typecheck(as, ctxStmt) // Note: this converts the OINDEX to an OINDEXMAP
+ typecheck.Stmt(as) // Note: this converts the OINDEX to an OINDEXMAP
o.stmt(as)
}
return m
as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
as.Lhs.Set(left)
as.Rhs.Set(tmplist)
- o.stmt(typecheck(as, ctxStmt))
+ o.stmt(typecheck.Stmt(as))
}
// okAs2 orders OAS2XXX with ok.
if tmp1 != nil {
r := ir.NewAssignStmt(base.Pos, n.Lhs[0], tmp1)
- o.mapAssign(typecheck(r, ctxStmt))
+ o.mapAssign(typecheck.Stmt(r))
n.Lhs[0] = tmp1
}
if tmp2 != nil {
- r := ir.NewAssignStmt(base.Pos, n.Lhs[1], conv(tmp2, n.Lhs[1].Type()))
- o.mapAssign(typecheck(r, ctxStmt))
+ r := ir.NewAssignStmt(base.Pos, n.Lhs[1], typecheck.Conv(tmp2, n.Lhs[1].Type()))
+ o.mapAssign(typecheck.Stmt(r))
n.Lhs[1] = tmp2
}
}
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/dwarf"
"cmd/internal/obj"
}
if f.Config.NeedsFpScratch && scratchUsed {
- s.scratchFpMem = tempAt(src.NoXPos, s.curfn, types.Types[types.TUINT64])
+ s.scratchFpMem = typecheck.TempAt(src.NoXPos, s.curfn, types.Types[types.TUINT64])
}
sort.Sort(byStackVar(fn.Dcl))
return
}
- dclcontext = ir.PAUTO
+ typecheck.DeclContext = ir.PAUTO
ir.CurFunc = fn
compile(fn)
ir.CurFunc = nil
- dclcontext = ir.PEXTERN
+ typecheck.DeclContext = ir.PEXTERN
}
func compile(fn *ir.Func) {
import (
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
"reflect"
if s == nil {
s = &types.Sym{Name: "."}
}
- n := NewName(s)
+ n := typecheck.NewName(s)
n.SetType(t)
n.SetFrameOffset(xoffset)
n.Class_ = cl
func TestStackvarSort(t *testing.T) {
nod := func(xoffset int64, t *types.Type, s *types.Sym, cl ir.Class) *ir.Name {
- n := NewName(s)
+ n := typecheck.NewName(s)
n.SetType(t)
n.SetFrameOffset(xoffset)
n.Class_ = cl
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/sys"
"unicode/utf8"
)
-// range
-func typecheckrange(n *ir.RangeStmt) {
- // Typechecking order is important here:
- // 0. first typecheck range expression (slice/map/chan),
- // it is evaluated only once and so logically it is not part of the loop.
- // 1. typecheck produced values,
- // this part can declare new vars and so it must be typechecked before body,
- // because body can contain a closure that captures the vars.
- // 2. decldepth++ to denote loop body.
- // 3. typecheck body.
- // 4. decldepth--.
- typecheckrangeExpr(n)
-
- // second half of dance, the first half being typecheckrangeExpr
- n.SetTypecheck(1)
- ls := n.Vars
- for i1, n1 := range ls {
- if n1.Typecheck() == 0 {
- ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
- }
- }
-
- decldepth++
- typecheckslice(n.Body, ctxStmt)
- decldepth--
-}
-
-func typecheckrangeExpr(n *ir.RangeStmt) {
- n.X = typecheck(n.X, ctxExpr)
-
- t := n.X.Type()
- if t == nil {
- return
- }
- // delicate little dance. see typecheckas2
- ls := n.Vars
- for i1, n1 := range ls {
- if !ir.DeclaredBy(n1, n) {
- ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
- }
- }
-
- if t.IsPtr() && t.Elem().IsArray() {
- t = t.Elem()
- }
- n.SetType(t)
-
- var t1, t2 *types.Type
- toomany := false
- switch t.Kind() {
- default:
- base.ErrorfAt(n.Pos(), "cannot range over %L", n.X)
- return
-
- case types.TARRAY, types.TSLICE:
- t1 = types.Types[types.TINT]
- t2 = t.Elem()
-
- case types.TMAP:
- t1 = t.Key()
- t2 = t.Elem()
-
- case types.TCHAN:
- if !t.ChanDir().CanRecv() {
- base.ErrorfAt(n.Pos(), "invalid operation: range %v (receive from send-only type %v)", n.X, n.X.Type())
- return
- }
-
- t1 = t.Elem()
- t2 = nil
- if len(n.Vars) == 2 {
- toomany = true
- }
-
- case types.TSTRING:
- t1 = types.Types[types.TINT]
- t2 = types.RuneType
- }
-
- if len(n.Vars) > 2 || toomany {
- base.ErrorfAt(n.Pos(), "too many variables in range")
- }
-
- var v1, v2 ir.Node
- if len(n.Vars) != 0 {
- v1 = n.Vars[0]
- }
- if len(n.Vars) > 1 {
- v2 = n.Vars[1]
- }
-
- // this is not only an optimization but also a requirement in the spec.
- // "if the second iteration variable is the blank identifier, the range
- // clause is equivalent to the same clause with only the first variable
- // present."
- if ir.IsBlank(v2) {
- if v1 != nil {
- n.Vars = []ir.Node{v1}
- }
- v2 = nil
- }
-
- if v1 != nil {
- if ir.DeclaredBy(v1, n) {
- v1.SetType(t1)
- } else if v1.Type() != nil {
- if op, why := assignop(t1, v1.Type()); op == ir.OXXX {
- base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t1, v1, why)
- }
- }
- checkassign(n, v1)
- }
-
- if v2 != nil {
- if ir.DeclaredBy(v2, n) {
- v2.SetType(t2)
- } else if v2.Type() != nil {
- if op, why := assignop(t2, v2.Type()); op == ir.OXXX {
- base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t2, v2, why)
- }
- }
- checkassign(n, v2)
- }
-}
-
func cheapComputableIndex(width int64) bool {
switch thearch.LinkArch.Family {
// MIPS does not have R+R addressing
// order.stmt arranged for a copy of the array/slice variable if needed.
ha := a
- hv1 := temp(types.Types[types.TINT])
- hn := temp(types.Types[types.TINT])
+ hv1 := typecheck.Temp(types.Types[types.TINT])
+ hn := typecheck.Temp(types.Types[types.TINT])
init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
init = append(init, ir.NewAssignStmt(base.Pos, hn, ir.NewUnaryExpr(base.Pos, ir.OLEN, ha)))
ifGuard.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, hv1, hn)
nfor.SetOp(ir.OFORUNTIL)
- hp := temp(types.NewPtr(nrange.Type().Elem()))
+ hp := typecheck.Temp(types.NewPtr(nrange.Type().Elem()))
tmp := ir.NewIndexExpr(base.Pos, ha, ir.NewInt(0))
tmp.SetBounded(true)
- init = append(init, ir.NewAssignStmt(base.Pos, hp, nodAddr(tmp)))
+ init = append(init, ir.NewAssignStmt(base.Pos, hp, typecheck.NodAddr(tmp)))
// Use OAS2 to correctly handle assignments
// of the form "v1, a[v1] := range".
// advancing the pointer is safe and won't go past the
// end of the allocation.
as := ir.NewAssignStmt(base.Pos, hp, addptr(hp, t.Elem().Width))
- nfor.Late = []ir.Node{typecheck(as, ctxStmt)}
+ nfor.Late = []ir.Node{typecheck.Stmt(as)}
case types.TMAP:
// order.stmt allocated the iterator for us.
keysym := th.Field(0).Sym // depends on layout of iterator struct. See reflect.go:hiter
elemsym := th.Field(1).Sym // ditto
- fn := syslook("mapiterinit")
+ fn := typecheck.LookupRuntime("mapiterinit")
- fn = substArgTypes(fn, t.Key(), t.Elem(), th)
- init = append(init, mkcall1(fn, nil, nil, typename(t), ha, nodAddr(hit)))
- nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), nodnil())
+ fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), th)
+ init = append(init, mkcall1(fn, nil, nil, typename(t), ha, typecheck.NodAddr(hit)))
+ nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym), typecheck.NodNil())
- fn = syslook("mapiternext")
- fn = substArgTypes(fn, th)
- nfor.Post = mkcall1(fn, nil, nil, nodAddr(hit))
+ fn = typecheck.LookupRuntime("mapiternext")
+ fn = typecheck.SubstArgTypes(fn, th)
+ nfor.Post = mkcall1(fn, nil, nil, typecheck.NodAddr(hit))
key := ir.NewStarExpr(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, hit, keysym))
if v1 == nil {
// order.stmt arranged for a copy of the channel variable.
ha := a
- hv1 := temp(t.Elem())
+ hv1 := typecheck.Temp(t.Elem())
hv1.SetTypecheck(1)
if t.Elem().HasPointers() {
init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
}
- hb := temp(types.Types[types.TBOOL])
+ hb := typecheck.Temp(types.Types[types.TBOOL])
nfor.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, hb, ir.NewBool(false))
a := ir.NewAssignListStmt(base.Pos, ir.OAS2RECV, nil, nil)
// order.stmt arranged for a copy of the string variable.
ha := a
- hv1 := temp(types.Types[types.TINT])
- hv1t := temp(types.Types[types.TINT])
- hv2 := temp(types.RuneType)
+ hv1 := typecheck.Temp(types.Types[types.TINT])
+ hv1t := typecheck.Temp(types.Types[types.TINT])
+ hv2 := typecheck.Temp(types.RuneType)
// hv1 := 0
init = append(init, ir.NewAssignStmt(base.Pos, hv1, nil))
// hv2 := rune(ha[hv1])
nind := ir.NewIndexExpr(base.Pos, ha, hv1)
nind.SetBounded(true)
- body = append(body, ir.NewAssignStmt(base.Pos, hv2, conv(nind, types.RuneType)))
+ body = append(body, ir.NewAssignStmt(base.Pos, hv2, typecheck.Conv(nind, types.RuneType)))
// if hv2 < utf8.RuneSelf
nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
// hv2, hv1 = decoderune(ha, hv1)
eif.Lhs = []ir.Node{hv2, hv1}
- fn := syslook("decoderune")
+ fn := typecheck.LookupRuntime("decoderune")
eif.Rhs = []ir.Node{mkcall1(fn, fn.Type().Results(), nil, ha, hv1)}
body = append(body, nif)
}
}
- typecheckslice(init, ctxStmt)
+ typecheck.Stmts(init)
if ifGuard != nil {
ifGuard.PtrInit().Append(init...)
- ifGuard = typecheck(ifGuard, ctxStmt).(*ir.IfStmt)
+ ifGuard = typecheck.Stmt(ifGuard).(*ir.IfStmt)
} else {
nfor.PtrInit().Append(init...)
}
- typecheckslice(nfor.Cond.Init(), ctxStmt)
+ typecheck.Stmts(nfor.Cond.Init())
- nfor.Cond = typecheck(nfor.Cond, ctxExpr)
- nfor.Cond = defaultlit(nfor.Cond, nil)
- nfor.Post = typecheck(nfor.Post, ctxStmt)
- typecheckslice(body, ctxStmt)
+ nfor.Cond = typecheck.Expr(nfor.Cond)
+ nfor.Cond = typecheck.DefaultLit(nfor.Cond, nil)
+ nfor.Post = typecheck.Stmt(nfor.Post)
+ typecheck.Stmts(body)
nfor.Body.Append(body...)
nfor.Body.Append(nrange.Body...)
t := m.Type()
// instantiate mapclear(typ *type, hmap map[any]any)
- fn := syslook("mapclear")
- fn = substArgTypes(fn, t.Key(), t.Elem())
+ fn := typecheck.LookupRuntime("mapclear")
+ fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
n := mkcall1(fn, nil, nil, typename(t), m)
- return walkstmt(typecheck(n, ctxStmt))
+ return walkstmt(typecheck.Stmt(n))
}
// Lower n into runtime·memclr if possible, for
n.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(0))
// hp = &a[0]
- hp := temp(types.Types[types.TUNSAFEPTR])
+ hp := typecheck.Temp(types.Types[types.TUNSAFEPTR])
ix := ir.NewIndexExpr(base.Pos, a, ir.NewInt(0))
ix.SetBounded(true)
- addr := convnop(nodAddr(ix), types.Types[types.TUNSAFEPTR])
+ addr := typecheck.ConvNop(typecheck.NodAddr(ix), types.Types[types.TUNSAFEPTR])
n.Body.Append(ir.NewAssignStmt(base.Pos, hp, addr))
// hn = len(a) * sizeof(elem(a))
- hn := temp(types.Types[types.TUINTPTR])
- mul := conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(elemsize)), types.Types[types.TUINTPTR])
+ hn := typecheck.Temp(types.Types[types.TUINTPTR])
+ mul := typecheck.Conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, ir.NewUnaryExpr(base.Pos, ir.OLEN, a), ir.NewInt(elemsize)), types.Types[types.TUINTPTR])
n.Body.Append(ir.NewAssignStmt(base.Pos, hn, mul))
var fn ir.Node
n.Body.Append(v1)
- n.Cond = typecheck(n.Cond, ctxExpr)
- n.Cond = defaultlit(n.Cond, nil)
- typecheckslice(n.Body, ctxStmt)
+ n.Cond = typecheck.Expr(n.Cond)
+ n.Cond = typecheck.DefaultLit(n.Cond, nil)
+ typecheck.Stmts(n.Body)
return walkstmt(n)
}
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/gcprog"
"cmd/internal/obj"
return s
}
-// f is method type, with receiver.
-// return function type, receiver as first argument (or not).
-func methodfunc(f *types.Type, receiver *types.Type) *types.Type {
- inLen := f.Params().Fields().Len()
- if receiver != nil {
- inLen++
- }
- in := make([]*ir.Field, 0, inLen)
-
- if receiver != nil {
- d := ir.NewField(base.Pos, nil, nil, receiver)
- in = append(in, d)
- }
-
- for _, t := range f.Params().Fields().Slice() {
- d := ir.NewField(base.Pos, nil, nil, t.Type)
- d.IsDDD = t.IsDDD()
- in = append(in, d)
- }
-
- outLen := f.Results().Fields().Len()
- out := make([]*ir.Field, 0, outLen)
- for _, t := range f.Results().Fields().Slice() {
- d := ir.NewField(base.Pos, nil, nil, t.Type)
- out = append(out, d)
- }
-
- return functype(nil, in, out)
-}
-
// methods returns the methods of the non-interface type t, sorted by name.
// Generates stub functions as needed.
func methods(t *types.Type) []*Sig {
if mt == nil {
return nil
}
- expandmeth(mt)
+ typecheck.CalcMethods(mt)
// type stored in interface word
it := t
name: method,
isym: ir.MethodSym(it, method),
tsym: ir.MethodSym(t, method),
- type_: methodfunc(f.Type, t),
- mtype: methodfunc(f.Type, nil),
+ type_: typecheck.NewMethodType(f.Type, t),
+ mtype: typecheck.NewMethodType(f.Type, nil),
}
ms = append(ms, sig)
sig := &Sig{
name: f.Sym,
mtype: f.Type,
- type_: methodfunc(f.Type, nil),
+ type_: typecheck.NewMethodType(f.Type, nil),
}
methods = append(methods, sig)
s.Def = n
}
- n := nodAddr(ir.AsNode(s.Def))
+ n := typecheck.NodAddr(ir.AsNode(s.Def))
n.SetType(types.NewPtr(s.Def.Type()))
n.SetTypecheck(1)
return n
}
s := ir.Pkgs.Itab.Lookup(t.ShortString() + "," + itype.ShortString())
if s.Def == nil {
- n := NewName(s)
+ n := typecheck.NewName(s)
n.SetType(types.Types[types.TUINT8])
n.Class_ = ir.PEXTERN
n.SetTypecheck(1)
itabs = append(itabs, itabEntry{t: t, itype: itype, lsym: s.Linksym()})
}
- n := nodAddr(ir.AsNode(s.Def))
+ n := typecheck.NodAddr(ir.AsNode(s.Def))
n.SetType(types.NewPtr(s.Def.Type()))
n.SetTypecheck(1)
return n
if base.Ctxt.Pkgpath != "runtime" || (tbase != types.Types[tbase.Kind()] && tbase != types.ByteType && tbase != types.RuneType && tbase != types.ErrorType) { // int, float, etc
// named types from other files are defined only by those files
if tbase.Sym() != nil && tbase.Sym().Pkg != types.LocalPkg {
- if i := BaseTypeIndex(t); i >= 0 {
+ if i := typecheck.BaseTypeIndex(t); i >= 0 {
lsym.Pkg = tbase.Sym().Pkg.Prefix
lsym.SymIdx = int32(i)
lsym.Set(obj.AttrIndexed, true)
// The latter is the type of an auto-generated wrapper.
dtypesym(types.NewPtr(types.ErrorType))
- dtypesym(functype(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.ErrorType)}, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.Types[types.TSTRING])}))
+ dtypesym(typecheck.NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.ErrorType)}, []*ir.Field{ir.NewField(base.Pos, nil, nil, types.Types[types.TSTRING])}))
// add paths for runtime and main, which 6l imports implicitly.
dimportpath(ir.Pkgs.Runtime)
}
s := ir.Pkgs.Map.Lookup("zero")
if s.Def == nil {
- x := NewName(s)
+ x := typecheck.NewName(s)
x.SetType(types.Types[types.TUINT8])
x.Class_ = ir.PEXTERN
x.SetTypecheck(1)
s.Def = x
}
- z := nodAddr(ir.AsNode(s.Def))
+ z := typecheck.NodAddr(ir.AsNode(s.Def))
z.SetType(types.NewPtr(types.Types[types.TUINT8]))
z.SetTypecheck(1)
return z
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
)
-// select
-func typecheckselect(sel *ir.SelectStmt) {
- var def ir.Node
- lno := ir.SetPos(sel)
- typecheckslice(sel.Init(), ctxStmt)
- for _, ncase := range sel.Cases {
- ncase := ncase.(*ir.CaseStmt)
-
- if len(ncase.List) == 0 {
- // default
- if def != nil {
- base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
- } else {
- def = ncase
- }
- } else if len(ncase.List) > 1 {
- base.ErrorfAt(ncase.Pos(), "select cases cannot be lists")
- } else {
- ncase.List[0] = typecheck(ncase.List[0], ctxStmt)
- n := ncase.List[0]
- ncase.Comm = n
- ncase.List.Set(nil)
- oselrecv2 := func(dst, recv ir.Node, colas bool) {
- n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, nil, nil)
- n.Lhs = []ir.Node{dst, ir.BlankNode}
- n.Rhs = []ir.Node{recv}
- n.Def = colas
- n.SetTypecheck(1)
- ncase.Comm = n
- }
- switch n.Op() {
- default:
- pos := n.Pos()
- if n.Op() == ir.ONAME {
- // We don't have the right position for ONAME nodes (see #15459 and
- // others). Using ncase.Pos for now as it will provide the correct
- // line number (assuming the expression follows the "case" keyword
- // on the same line). This matches the approach before 1.10.
- pos = ncase.Pos()
- }
- base.ErrorfAt(pos, "select case must be receive, send or assign recv")
-
- case ir.OAS:
- // convert x = <-c into x, _ = <-c
- // remove implicit conversions; the eventual assignment
- // will reintroduce them.
- n := n.(*ir.AssignStmt)
- if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
- r := r.(*ir.ConvExpr)
- if r.Implicit() {
- n.Y = r.X
- }
- }
- if n.Y.Op() != ir.ORECV {
- base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
- break
- }
- oselrecv2(n.X, n.Y, n.Def)
-
- case ir.OAS2RECV:
- n := n.(*ir.AssignListStmt)
- if n.Rhs[0].Op() != ir.ORECV {
- base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
- break
- }
- n.SetOp(ir.OSELRECV2)
-
- case ir.ORECV:
- // convert <-c into _, _ = <-c
- n := n.(*ir.UnaryExpr)
- oselrecv2(ir.BlankNode, n, false)
-
- case ir.OSEND:
- break
- }
- }
-
- typecheckslice(ncase.Body, ctxStmt)
- }
-
- base.Pos = lno
-}
-
func walkselect(sel *ir.SelectStmt) {
lno := ir.SetPos(sel)
if len(sel.Compiled) != 0 {
switch n.Op() {
case ir.OSEND:
n := n.(*ir.SendStmt)
- n.Value = nodAddr(n.Value)
- n.Value = typecheck(n.Value, ctxExpr)
+ n.Value = typecheck.NodAddr(n.Value)
+ n.Value = typecheck.Expr(n.Value)
case ir.OSELRECV2:
n := n.(*ir.AssignListStmt)
if !ir.IsBlank(n.Lhs[0]) {
- n.Lhs[0] = nodAddr(n.Lhs[0])
- n.Lhs[0] = typecheck(n.Lhs[0], ctxExpr)
+ n.Lhs[0] = typecheck.NodAddr(n.Lhs[0])
+ n.Lhs[0] = typecheck.Expr(n.Lhs[0])
}
}
}
ch := recv.X
elem := n.Lhs[0]
if ir.IsBlank(elem) {
- elem = nodnil()
+ elem = typecheck.NodNil()
}
if ir.IsBlank(n.Lhs[1]) {
// if selectnbrecv(&v, c) { body } else { default body }
} else {
// TODO(cuonglm): make this use selectnbrecv()
// if selectnbrecv2(&v, &received, c) { body } else { default body }
- receivedp := typecheck(nodAddr(n.Lhs[1]), ctxExpr)
+ receivedp := typecheck.Expr(typecheck.NodAddr(n.Lhs[1]))
call = mkcall1(chanfn("selectnbrecv2", 2, ch.Type()), types.Types[types.TBOOL], r.PtrInit(), elem, receivedp, ch)
}
}
- r.Cond = typecheck(call, ctxExpr)
+ r.Cond = typecheck.Expr(call)
r.Body.Set(cas.Body)
r.Else.Set(append(dflt.Init(), dflt.Body...))
return []ir.Node{r, ir.NewBranchStmt(base.Pos, ir.OBREAK, nil)}
// generate sel-struct
base.Pos = sellineno
- selv := temp(types.NewArray(scasetype(), int64(ncas)))
- init = append(init, typecheck(ir.NewAssignStmt(base.Pos, selv, nil), ctxStmt))
+ selv := typecheck.Temp(types.NewArray(scasetype(), int64(ncas)))
+ init = append(init, typecheck.Stmt(ir.NewAssignStmt(base.Pos, selv, nil)))
// No initialization for order; runtime.selectgo is responsible for that.
- order := temp(types.NewArray(types.Types[types.TUINT16], 2*int64(ncas)))
+ order := typecheck.Temp(types.NewArray(types.Types[types.TUINT16], 2*int64(ncas)))
var pc0, pcs ir.Node
if base.Flag.Race {
- pcs = temp(types.NewArray(types.Types[types.TUINTPTR], int64(ncas)))
- pc0 = typecheck(nodAddr(ir.NewIndexExpr(base.Pos, pcs, ir.NewInt(0))), ctxExpr)
+ pcs = typecheck.Temp(types.NewArray(types.Types[types.TUINTPTR], int64(ncas)))
+ pc0 = typecheck.Expr(typecheck.NodAddr(ir.NewIndexExpr(base.Pos, pcs, ir.NewInt(0))))
} else {
- pc0 = nodnil()
+ pc0 = typecheck.NodNil()
}
// register cases
casorder[i] = cas
setField := func(f string, val ir.Node) {
- r := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, ir.NewIndexExpr(base.Pos, selv, ir.NewInt(int64(i))), lookup(f)), val)
- init = append(init, typecheck(r, ctxStmt))
+ r := ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, ir.NewIndexExpr(base.Pos, selv, ir.NewInt(int64(i))), typecheck.Lookup(f)), val)
+ init = append(init, typecheck.Stmt(r))
}
- c = convnop(c, types.Types[types.TUNSAFEPTR])
+ c = typecheck.ConvNop(c, types.Types[types.TUNSAFEPTR])
setField("c", c)
if !ir.IsBlank(elem) {
- elem = convnop(elem, types.Types[types.TUNSAFEPTR])
+ elem = typecheck.ConvNop(elem, types.Types[types.TUNSAFEPTR])
setField("elem", elem)
}
// TODO(mdempsky): There should be a cleaner way to
// handle this.
if base.Flag.Race {
- r := mkcall("selectsetpc", nil, nil, nodAddr(ir.NewIndexExpr(base.Pos, pcs, ir.NewInt(int64(i)))))
+ r := mkcall("selectsetpc", nil, nil, typecheck.NodAddr(ir.NewIndexExpr(base.Pos, pcs, ir.NewInt(int64(i)))))
init = append(init, r)
}
}
// run the select
base.Pos = sellineno
- chosen := temp(types.Types[types.TINT])
- recvOK := temp(types.Types[types.TBOOL])
+ chosen := typecheck.Temp(types.Types[types.TINT])
+ recvOK := typecheck.Temp(types.Types[types.TBOOL])
r := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
r.Lhs = []ir.Node{chosen, recvOK}
- fn := syslook("selectgo")
+ fn := typecheck.LookupRuntime("selectgo")
r.Rhs = []ir.Node{mkcall1(fn, fn.Type().Results(), nil, bytePtrToIndex(selv, 0), bytePtrToIndex(order, 0), pc0, ir.NewInt(int64(nsends)), ir.NewInt(int64(nrecvs)), ir.NewBool(dflt == nil))}
- init = append(init, typecheck(r, ctxStmt))
+ init = append(init, typecheck.Stmt(r))
// selv and order are no longer alive after selectgo.
init = append(init, ir.NewUnaryExpr(base.Pos, ir.OVARKILL, selv))
// dispatch cases
dispatch := func(cond ir.Node, cas *ir.CaseStmt) {
- cond = typecheck(cond, ctxExpr)
- cond = defaultlit(cond, nil)
+ cond = typecheck.Expr(cond)
+ cond = typecheck.DefaultLit(cond, nil)
r := ir.NewIfStmt(base.Pos, cond, nil, nil)
n := n.(*ir.AssignListStmt)
if !ir.IsBlank(n.Lhs[1]) {
x := ir.NewAssignStmt(base.Pos, n.Lhs[1], recvOK)
- r.Body.Append(typecheck(x, ctxStmt))
+ r.Body.Append(typecheck.Stmt(x))
}
}
// bytePtrToIndex returns a Node representing "(*byte)(&n[i])".
func bytePtrToIndex(n ir.Node, i int64) ir.Node {
- s := nodAddr(ir.NewIndexExpr(base.Pos, n, ir.NewInt(i)))
+ s := typecheck.NodAddr(ir.NewIndexExpr(base.Pos, n, ir.NewInt(i)))
t := types.NewPtr(types.Types[types.TUINT8])
- return convnop(s, t)
+ return typecheck.ConvNop(s, t)
}
var scase *types.Type
// Keep in sync with src/runtime/select.go.
func scasetype() *types.Type {
if scase == nil {
- scase = tostruct([]*ir.Field{
- ir.NewField(base.Pos, lookup("c"), nil, types.Types[types.TUNSAFEPTR]),
- ir.NewField(base.Pos, lookup("elem"), nil, types.Types[types.TUNSAFEPTR]),
+ scase = typecheck.NewStructType([]*ir.Field{
+ ir.NewField(base.Pos, typecheck.Lookup("c"), nil, types.Types[types.TUNSAFEPTR]),
+ ir.NewField(base.Pos, typecheck.Lookup("elem"), nil, types.Types[types.TUNSAFEPTR]),
})
scase.SetNoalg(true)
}
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"fmt"
if loff != 0 || !types.Identical(typ, l.Type()) {
dst = ir.NewNameOffsetExpr(base.Pos, l, loff, typ)
}
- s.append(ir.NewAssignStmt(base.Pos, dst, conv(r, typ)))
+ s.append(ir.NewAssignStmt(base.Pos, dst, typecheck.Conv(r, typ)))
return true
case ir.ONIL:
// Use readonlystaticname for read-only node.
func staticname(t *types.Type) *ir.Name {
// Don't use lookupN; it interns the resulting string, but these are all unique.
- n := NewName(lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
+ n := typecheck.NewName(typecheck.Lookup(fmt.Sprintf("%s%d", obj.StaticNamePref, statuniqgen)))
statuniqgen++
- declare(n, ir.PEXTERN)
+ typecheck.Declare(n, ir.PEXTERN)
n.SetType(t)
n.Sym().Linksym().Set(obj.AttrLocal, true)
return n
splitnode = func(r ir.Node) (ir.Node, ir.Node) {
if r.Op() == ir.OKEY {
kv := r.(*ir.KeyExpr)
- k = indexconst(kv.Key)
+ k = typecheck.IndexConst(kv.Key)
if k < 0 {
base.Fatalf("fixedlit: invalid index %v", kv.Key)
}
// build list of assignments: var[index] = expr
ir.SetPos(a)
as := ir.NewAssignStmt(base.Pos, a, value)
- as = typecheck(as, ctxStmt).(*ir.AssignStmt)
+ as = typecheck.Stmt(as).(*ir.AssignStmt)
switch kind {
case initKindStatic:
genAsStatic(as)
fixedlit(ctxt, initKindDynamic, n, vstat, init)
// copy static to slice
- var_ = typecheck(var_, ctxExpr|ctxAssign)
+ var_ = typecheck.AssignExpr(var_)
name, offset, ok := stataddr(var_)
if !ok || name.Class_ != ir.PEXTERN {
base.Fatalf("slicelit: %v", var_)
}
// make new auto *array (3 declare)
- vauto := temp(types.NewPtr(t))
+ vauto := typecheck.Temp(types.NewPtr(t))
// set auto to point at new temp or heap (3 assign)
var a ir.Node
if vstat == nil {
a = ir.NewAssignStmt(base.Pos, x, nil)
- a = typecheck(a, ctxStmt)
+ a = typecheck.Stmt(a)
init.Append(a) // zero new temp
} else {
// Declare that we're about to initialize all of x.
init.Append(ir.NewUnaryExpr(base.Pos, ir.OVARDEF, x))
}
- a = nodAddr(x)
+ a = typecheck.NodAddr(x)
} else if n.Esc() == ir.EscNone {
- a = temp(t)
+ a = typecheck.Temp(t)
if vstat == nil {
- a = ir.NewAssignStmt(base.Pos, temp(t), nil)
- a = typecheck(a, ctxStmt)
+ a = ir.NewAssignStmt(base.Pos, typecheck.Temp(t), nil)
+ a = typecheck.Stmt(a)
init.Append(a) // zero new temp
a = a.(*ir.AssignStmt).X
} else {
init.Append(ir.NewUnaryExpr(base.Pos, ir.OVARDEF, a))
}
- a = nodAddr(a)
+ a = typecheck.NodAddr(a)
} else {
a = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(t))
}
for _, value := range n.List {
if value.Op() == ir.OKEY {
kv := value.(*ir.KeyExpr)
- index = indexconst(kv.Key)
+ index = typecheck.IndexConst(kv.Key)
if index < 0 {
base.Fatalf("slicelit: invalid index %v", kv.Key)
}
// build list of vauto[c] = expr
ir.SetPos(value)
- as := typecheck(ir.NewAssignStmt(base.Pos, a, value), ctxStmt)
+ as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, a, value))
as = orderStmtInPlace(as, map[string][]*ir.Name{})
as = walkstmt(as)
init.Append(as)
// make slice out of heap (6)
a = ir.NewAssignStmt(base.Pos, var_, ir.NewSliceExpr(base.Pos, ir.OSLICE, vauto))
- a = typecheck(a, ctxStmt)
+ a = typecheck.Stmt(a)
a = orderStmtInPlace(a, map[string][]*ir.Name{})
a = walkstmt(a)
init.Append(a)
// for i = 0; i < len(vstatk); i++ {
// map[vstatk[i]] = vstate[i]
// }
- i := temp(types.Types[types.TINT])
+ i := typecheck.Temp(types.Types[types.TINT])
rhs := ir.NewIndexExpr(base.Pos, vstate, i)
rhs.SetBounded(true)
// Build list of var[c] = expr.
// Use temporaries so that mapassign1 can have addressable key, elem.
// TODO(josharian): avoid map key temporaries for mapfast_* assignments with literal keys.
- tmpkey := temp(m.Type().Key())
- tmpelem := temp(m.Type().Elem())
+ tmpkey := typecheck.Temp(m.Type().Key())
+ tmpelem := typecheck.Temp(m.Type().Elem())
for _, r := range entries {
r := r.(*ir.KeyExpr)
if n.Alloc != nil {
// n.Right is stack temporary used as backing store.
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n.Alloc, nil)) // zero backing store, just in case (#18410)
- r = nodAddr(n.Alloc)
+ r = typecheck.NodAddr(n.Alloc)
} else {
r = ir.NewUnaryExpr(base.Pos, ir.ONEW, ir.TypeNode(n.X.Type()))
r.SetEsc(n.Esc())
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, r))
var_ = ir.NewStarExpr(base.Pos, var_)
- var_ = typecheck(var_, ctxExpr|ctxAssign)
+ var_ = typecheck.AssignExpr(var_)
anylit(n.X, var_, init)
case ir.OSTRUCTLIT, ir.OARRAYLIT:
for _, a := range n.List {
if a.Op() == ir.OKEY {
kv := a.(*ir.KeyExpr)
- k = indexconst(kv.Key)
+ k = typecheck.IndexConst(kv.Key)
if k < 0 {
base.Fatalf("initplan arraylit: invalid index %v", kv.Key)
}
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/ssa"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/obj/x86"
ssaCaches = make([]ssa.Cache, base.Flag.LowerC)
// Set up some runtime functions we'll need to call.
- ir.Syms.AssertE2I = sysfunc("assertE2I")
- ir.Syms.AssertE2I2 = sysfunc("assertE2I2")
- ir.Syms.AssertI2I = sysfunc("assertI2I")
- ir.Syms.AssertI2I2 = sysfunc("assertI2I2")
- ir.Syms.Deferproc = sysfunc("deferproc")
- ir.Syms.DeferprocStack = sysfunc("deferprocStack")
- ir.Syms.Deferreturn = sysfunc("deferreturn")
- ir.Syms.Duffcopy = sysfunc("duffcopy")
- ir.Syms.Duffzero = sysfunc("duffzero")
- ir.Syms.GCWriteBarrier = sysfunc("gcWriteBarrier")
- ir.Syms.Goschedguarded = sysfunc("goschedguarded")
- ir.Syms.Growslice = sysfunc("growslice")
- ir.Syms.Msanread = sysfunc("msanread")
- ir.Syms.Msanwrite = sysfunc("msanwrite")
- ir.Syms.Msanmove = sysfunc("msanmove")
- ir.Syms.Newobject = sysfunc("newobject")
- ir.Syms.Newproc = sysfunc("newproc")
- ir.Syms.Panicdivide = sysfunc("panicdivide")
- ir.Syms.PanicdottypeE = sysfunc("panicdottypeE")
- ir.Syms.PanicdottypeI = sysfunc("panicdottypeI")
- ir.Syms.Panicnildottype = sysfunc("panicnildottype")
- ir.Syms.Panicoverflow = sysfunc("panicoverflow")
- ir.Syms.Panicshift = sysfunc("panicshift")
- ir.Syms.Raceread = sysfunc("raceread")
- ir.Syms.Racereadrange = sysfunc("racereadrange")
- ir.Syms.Racewrite = sysfunc("racewrite")
- ir.Syms.Racewriterange = sysfunc("racewriterange")
- ir.Syms.X86HasPOPCNT = sysvar("x86HasPOPCNT") // bool
- ir.Syms.X86HasSSE41 = sysvar("x86HasSSE41") // bool
- ir.Syms.X86HasFMA = sysvar("x86HasFMA") // bool
- ir.Syms.ARMHasVFPv4 = sysvar("armHasVFPv4") // bool
- ir.Syms.ARM64HasATOMICS = sysvar("arm64HasATOMICS") // bool
- ir.Syms.Typedmemclr = sysfunc("typedmemclr")
- ir.Syms.Typedmemmove = sysfunc("typedmemmove")
- ir.Syms.Udiv = sysvar("udiv") // asm func with special ABI
- ir.Syms.WriteBarrier = sysvar("writeBarrier") // struct { bool; ... }
- ir.Syms.Zerobase = sysvar("zerobase")
+ ir.Syms.AssertE2I = typecheck.LookupRuntimeFunc("assertE2I")
+ ir.Syms.AssertE2I2 = typecheck.LookupRuntimeFunc("assertE2I2")
+ ir.Syms.AssertI2I = typecheck.LookupRuntimeFunc("assertI2I")
+ ir.Syms.AssertI2I2 = typecheck.LookupRuntimeFunc("assertI2I2")
+ ir.Syms.Deferproc = typecheck.LookupRuntimeFunc("deferproc")
+ ir.Syms.DeferprocStack = typecheck.LookupRuntimeFunc("deferprocStack")
+ ir.Syms.Deferreturn = typecheck.LookupRuntimeFunc("deferreturn")
+ ir.Syms.Duffcopy = typecheck.LookupRuntimeFunc("duffcopy")
+ ir.Syms.Duffzero = typecheck.LookupRuntimeFunc("duffzero")
+ ir.Syms.GCWriteBarrier = typecheck.LookupRuntimeFunc("gcWriteBarrier")
+ ir.Syms.Goschedguarded = typecheck.LookupRuntimeFunc("goschedguarded")
+ ir.Syms.Growslice = typecheck.LookupRuntimeFunc("growslice")
+ ir.Syms.Msanread = typecheck.LookupRuntimeFunc("msanread")
+ ir.Syms.Msanwrite = typecheck.LookupRuntimeFunc("msanwrite")
+ ir.Syms.Msanmove = typecheck.LookupRuntimeFunc("msanmove")
+ ir.Syms.Newobject = typecheck.LookupRuntimeFunc("newobject")
+ ir.Syms.Newproc = typecheck.LookupRuntimeFunc("newproc")
+ ir.Syms.Panicdivide = typecheck.LookupRuntimeFunc("panicdivide")
+ ir.Syms.PanicdottypeE = typecheck.LookupRuntimeFunc("panicdottypeE")
+ ir.Syms.PanicdottypeI = typecheck.LookupRuntimeFunc("panicdottypeI")
+ ir.Syms.Panicnildottype = typecheck.LookupRuntimeFunc("panicnildottype")
+ ir.Syms.Panicoverflow = typecheck.LookupRuntimeFunc("panicoverflow")
+ ir.Syms.Panicshift = typecheck.LookupRuntimeFunc("panicshift")
+ ir.Syms.Raceread = typecheck.LookupRuntimeFunc("raceread")
+ ir.Syms.Racereadrange = typecheck.LookupRuntimeFunc("racereadrange")
+ ir.Syms.Racewrite = typecheck.LookupRuntimeFunc("racewrite")
+ ir.Syms.Racewriterange = typecheck.LookupRuntimeFunc("racewriterange")
+ ir.Syms.X86HasPOPCNT = typecheck.LookupRuntimeVar("x86HasPOPCNT") // bool
+ ir.Syms.X86HasSSE41 = typecheck.LookupRuntimeVar("x86HasSSE41") // bool
+ ir.Syms.X86HasFMA = typecheck.LookupRuntimeVar("x86HasFMA") // bool
+ ir.Syms.ARMHasVFPv4 = typecheck.LookupRuntimeVar("armHasVFPv4") // bool
+ ir.Syms.ARM64HasATOMICS = typecheck.LookupRuntimeVar("arm64HasATOMICS") // bool
+ ir.Syms.Typedmemclr = typecheck.LookupRuntimeFunc("typedmemclr")
+ ir.Syms.Typedmemmove = typecheck.LookupRuntimeFunc("typedmemmove")
+ ir.Syms.Udiv = typecheck.LookupRuntimeVar("udiv") // asm func with special ABI
+ ir.Syms.WriteBarrier = typecheck.LookupRuntimeVar("writeBarrier") // struct { bool; ... }
+ ir.Syms.Zerobase = typecheck.LookupRuntimeVar("zerobase")
// asm funcs with special ABI
if thearch.LinkArch.Name == "amd64" {
GCWriteBarrierReg = map[int16]*obj.LSym{
- x86.REG_AX: sysfunc("gcWriteBarrier"),
- x86.REG_CX: sysfunc("gcWriteBarrierCX"),
- x86.REG_DX: sysfunc("gcWriteBarrierDX"),
- x86.REG_BX: sysfunc("gcWriteBarrierBX"),
- x86.REG_BP: sysfunc("gcWriteBarrierBP"),
- x86.REG_SI: sysfunc("gcWriteBarrierSI"),
- x86.REG_R8: sysfunc("gcWriteBarrierR8"),
- x86.REG_R9: sysfunc("gcWriteBarrierR9"),
+ x86.REG_AX: typecheck.LookupRuntimeFunc("gcWriteBarrier"),
+ x86.REG_CX: typecheck.LookupRuntimeFunc("gcWriteBarrierCX"),
+ x86.REG_DX: typecheck.LookupRuntimeFunc("gcWriteBarrierDX"),
+ x86.REG_BX: typecheck.LookupRuntimeFunc("gcWriteBarrierBX"),
+ x86.REG_BP: typecheck.LookupRuntimeFunc("gcWriteBarrierBP"),
+ x86.REG_SI: typecheck.LookupRuntimeFunc("gcWriteBarrierSI"),
+ x86.REG_R8: typecheck.LookupRuntimeFunc("gcWriteBarrierR8"),
+ x86.REG_R9: typecheck.LookupRuntimeFunc("gcWriteBarrierR9"),
}
}
if thearch.LinkArch.Family == sys.Wasm {
- BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("goPanicIndex")
- BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("goPanicIndexU")
- BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("goPanicSliceAlen")
- BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("goPanicSliceAlenU")
- BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("goPanicSliceAcap")
- BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("goPanicSliceAcapU")
- BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("goPanicSliceB")
- BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("goPanicSliceBU")
- BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("goPanicSlice3Alen")
- BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("goPanicSlice3AlenU")
- BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("goPanicSlice3Acap")
- BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("goPanicSlice3AcapU")
- BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("goPanicSlice3B")
- BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("goPanicSlice3BU")
- BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("goPanicSlice3C")
- BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("goPanicSlice3CU")
+ BoundsCheckFunc[ssa.BoundsIndex] = typecheck.LookupRuntimeFunc("goPanicIndex")
+ BoundsCheckFunc[ssa.BoundsIndexU] = typecheck.LookupRuntimeFunc("goPanicIndexU")
+ BoundsCheckFunc[ssa.BoundsSliceAlen] = typecheck.LookupRuntimeFunc("goPanicSliceAlen")
+ BoundsCheckFunc[ssa.BoundsSliceAlenU] = typecheck.LookupRuntimeFunc("goPanicSliceAlenU")
+ BoundsCheckFunc[ssa.BoundsSliceAcap] = typecheck.LookupRuntimeFunc("goPanicSliceAcap")
+ BoundsCheckFunc[ssa.BoundsSliceAcapU] = typecheck.LookupRuntimeFunc("goPanicSliceAcapU")
+ BoundsCheckFunc[ssa.BoundsSliceB] = typecheck.LookupRuntimeFunc("goPanicSliceB")
+ BoundsCheckFunc[ssa.BoundsSliceBU] = typecheck.LookupRuntimeFunc("goPanicSliceBU")
+ BoundsCheckFunc[ssa.BoundsSlice3Alen] = typecheck.LookupRuntimeFunc("goPanicSlice3Alen")
+ BoundsCheckFunc[ssa.BoundsSlice3AlenU] = typecheck.LookupRuntimeFunc("goPanicSlice3AlenU")
+ BoundsCheckFunc[ssa.BoundsSlice3Acap] = typecheck.LookupRuntimeFunc("goPanicSlice3Acap")
+ BoundsCheckFunc[ssa.BoundsSlice3AcapU] = typecheck.LookupRuntimeFunc("goPanicSlice3AcapU")
+ BoundsCheckFunc[ssa.BoundsSlice3B] = typecheck.LookupRuntimeFunc("goPanicSlice3B")
+ BoundsCheckFunc[ssa.BoundsSlice3BU] = typecheck.LookupRuntimeFunc("goPanicSlice3BU")
+ BoundsCheckFunc[ssa.BoundsSlice3C] = typecheck.LookupRuntimeFunc("goPanicSlice3C")
+ BoundsCheckFunc[ssa.BoundsSlice3CU] = typecheck.LookupRuntimeFunc("goPanicSlice3CU")
} else {
- BoundsCheckFunc[ssa.BoundsIndex] = sysfunc("panicIndex")
- BoundsCheckFunc[ssa.BoundsIndexU] = sysfunc("panicIndexU")
- BoundsCheckFunc[ssa.BoundsSliceAlen] = sysfunc("panicSliceAlen")
- BoundsCheckFunc[ssa.BoundsSliceAlenU] = sysfunc("panicSliceAlenU")
- BoundsCheckFunc[ssa.BoundsSliceAcap] = sysfunc("panicSliceAcap")
- BoundsCheckFunc[ssa.BoundsSliceAcapU] = sysfunc("panicSliceAcapU")
- BoundsCheckFunc[ssa.BoundsSliceB] = sysfunc("panicSliceB")
- BoundsCheckFunc[ssa.BoundsSliceBU] = sysfunc("panicSliceBU")
- BoundsCheckFunc[ssa.BoundsSlice3Alen] = sysfunc("panicSlice3Alen")
- BoundsCheckFunc[ssa.BoundsSlice3AlenU] = sysfunc("panicSlice3AlenU")
- BoundsCheckFunc[ssa.BoundsSlice3Acap] = sysfunc("panicSlice3Acap")
- BoundsCheckFunc[ssa.BoundsSlice3AcapU] = sysfunc("panicSlice3AcapU")
- BoundsCheckFunc[ssa.BoundsSlice3B] = sysfunc("panicSlice3B")
- BoundsCheckFunc[ssa.BoundsSlice3BU] = sysfunc("panicSlice3BU")
- BoundsCheckFunc[ssa.BoundsSlice3C] = sysfunc("panicSlice3C")
- BoundsCheckFunc[ssa.BoundsSlice3CU] = sysfunc("panicSlice3CU")
+ BoundsCheckFunc[ssa.BoundsIndex] = typecheck.LookupRuntimeFunc("panicIndex")
+ BoundsCheckFunc[ssa.BoundsIndexU] = typecheck.LookupRuntimeFunc("panicIndexU")
+ BoundsCheckFunc[ssa.BoundsSliceAlen] = typecheck.LookupRuntimeFunc("panicSliceAlen")
+ BoundsCheckFunc[ssa.BoundsSliceAlenU] = typecheck.LookupRuntimeFunc("panicSliceAlenU")
+ BoundsCheckFunc[ssa.BoundsSliceAcap] = typecheck.LookupRuntimeFunc("panicSliceAcap")
+ BoundsCheckFunc[ssa.BoundsSliceAcapU] = typecheck.LookupRuntimeFunc("panicSliceAcapU")
+ BoundsCheckFunc[ssa.BoundsSliceB] = typecheck.LookupRuntimeFunc("panicSliceB")
+ BoundsCheckFunc[ssa.BoundsSliceBU] = typecheck.LookupRuntimeFunc("panicSliceBU")
+ BoundsCheckFunc[ssa.BoundsSlice3Alen] = typecheck.LookupRuntimeFunc("panicSlice3Alen")
+ BoundsCheckFunc[ssa.BoundsSlice3AlenU] = typecheck.LookupRuntimeFunc("panicSlice3AlenU")
+ BoundsCheckFunc[ssa.BoundsSlice3Acap] = typecheck.LookupRuntimeFunc("panicSlice3Acap")
+ BoundsCheckFunc[ssa.BoundsSlice3AcapU] = typecheck.LookupRuntimeFunc("panicSlice3AcapU")
+ BoundsCheckFunc[ssa.BoundsSlice3B] = typecheck.LookupRuntimeFunc("panicSlice3B")
+ BoundsCheckFunc[ssa.BoundsSlice3BU] = typecheck.LookupRuntimeFunc("panicSlice3BU")
+ BoundsCheckFunc[ssa.BoundsSlice3C] = typecheck.LookupRuntimeFunc("panicSlice3C")
+ BoundsCheckFunc[ssa.BoundsSlice3CU] = typecheck.LookupRuntimeFunc("panicSlice3CU")
}
if thearch.LinkArch.PtrSize == 4 {
- ExtendCheckFunc[ssa.BoundsIndex] = sysvar("panicExtendIndex")
- ExtendCheckFunc[ssa.BoundsIndexU] = sysvar("panicExtendIndexU")
- ExtendCheckFunc[ssa.BoundsSliceAlen] = sysvar("panicExtendSliceAlen")
- ExtendCheckFunc[ssa.BoundsSliceAlenU] = sysvar("panicExtendSliceAlenU")
- ExtendCheckFunc[ssa.BoundsSliceAcap] = sysvar("panicExtendSliceAcap")
- ExtendCheckFunc[ssa.BoundsSliceAcapU] = sysvar("panicExtendSliceAcapU")
- ExtendCheckFunc[ssa.BoundsSliceB] = sysvar("panicExtendSliceB")
- ExtendCheckFunc[ssa.BoundsSliceBU] = sysvar("panicExtendSliceBU")
- ExtendCheckFunc[ssa.BoundsSlice3Alen] = sysvar("panicExtendSlice3Alen")
- ExtendCheckFunc[ssa.BoundsSlice3AlenU] = sysvar("panicExtendSlice3AlenU")
- ExtendCheckFunc[ssa.BoundsSlice3Acap] = sysvar("panicExtendSlice3Acap")
- ExtendCheckFunc[ssa.BoundsSlice3AcapU] = sysvar("panicExtendSlice3AcapU")
- ExtendCheckFunc[ssa.BoundsSlice3B] = sysvar("panicExtendSlice3B")
- ExtendCheckFunc[ssa.BoundsSlice3BU] = sysvar("panicExtendSlice3BU")
- ExtendCheckFunc[ssa.BoundsSlice3C] = sysvar("panicExtendSlice3C")
- ExtendCheckFunc[ssa.BoundsSlice3CU] = sysvar("panicExtendSlice3CU")
+ ExtendCheckFunc[ssa.BoundsIndex] = typecheck.LookupRuntimeVar("panicExtendIndex")
+ ExtendCheckFunc[ssa.BoundsIndexU] = typecheck.LookupRuntimeVar("panicExtendIndexU")
+ ExtendCheckFunc[ssa.BoundsSliceAlen] = typecheck.LookupRuntimeVar("panicExtendSliceAlen")
+ ExtendCheckFunc[ssa.BoundsSliceAlenU] = typecheck.LookupRuntimeVar("panicExtendSliceAlenU")
+ ExtendCheckFunc[ssa.BoundsSliceAcap] = typecheck.LookupRuntimeVar("panicExtendSliceAcap")
+ ExtendCheckFunc[ssa.BoundsSliceAcapU] = typecheck.LookupRuntimeVar("panicExtendSliceAcapU")
+ ExtendCheckFunc[ssa.BoundsSliceB] = typecheck.LookupRuntimeVar("panicExtendSliceB")
+ ExtendCheckFunc[ssa.BoundsSliceBU] = typecheck.LookupRuntimeVar("panicExtendSliceBU")
+ ExtendCheckFunc[ssa.BoundsSlice3Alen] = typecheck.LookupRuntimeVar("panicExtendSlice3Alen")
+ ExtendCheckFunc[ssa.BoundsSlice3AlenU] = typecheck.LookupRuntimeVar("panicExtendSlice3AlenU")
+ ExtendCheckFunc[ssa.BoundsSlice3Acap] = typecheck.LookupRuntimeVar("panicExtendSlice3Acap")
+ ExtendCheckFunc[ssa.BoundsSlice3AcapU] = typecheck.LookupRuntimeVar("panicExtendSlice3AcapU")
+ ExtendCheckFunc[ssa.BoundsSlice3B] = typecheck.LookupRuntimeVar("panicExtendSlice3B")
+ ExtendCheckFunc[ssa.BoundsSlice3BU] = typecheck.LookupRuntimeVar("panicExtendSlice3BU")
+ ExtendCheckFunc[ssa.BoundsSlice3C] = typecheck.LookupRuntimeVar("panicExtendSlice3C")
+ ExtendCheckFunc[ssa.BoundsSlice3CU] = typecheck.LookupRuntimeVar("panicExtendSlice3CU")
}
// Wasm (all asm funcs with special ABIs)
- ir.Syms.WasmMove = sysvar("wasmMove")
- ir.Syms.WasmZero = sysvar("wasmZero")
- ir.Syms.WasmDiv = sysvar("wasmDiv")
- ir.Syms.WasmTruncS = sysvar("wasmTruncS")
- ir.Syms.WasmTruncU = sysvar("wasmTruncU")
- ir.Syms.SigPanic = sysfunc("sigpanic")
+ ir.Syms.WasmMove = typecheck.LookupRuntimeVar("wasmMove")
+ ir.Syms.WasmZero = typecheck.LookupRuntimeVar("wasmZero")
+ ir.Syms.WasmDiv = typecheck.LookupRuntimeVar("wasmDiv")
+ ir.Syms.WasmTruncS = typecheck.LookupRuntimeVar("wasmTruncS")
+ ir.Syms.WasmTruncU = typecheck.LookupRuntimeVar("wasmTruncU")
+ ir.Syms.SigPanic = typecheck.LookupRuntimeFunc("sigpanic")
}
// getParam returns the Field of ith param of node n (which is a
// Create the deferBits variable and stack slot. deferBits is a
// bitmask showing which of the open-coded defers in this function
// have been activated.
- deferBitsTemp := tempAt(src.NoXPos, s.curfn, types.Types[types.TUINT8])
+ deferBitsTemp := typecheck.TempAt(src.NoXPos, s.curfn, types.Types[types.TUINT8])
s.deferBitsTemp = deferBitsTemp
// For this value, AuxInt is initialized to zero by default
startDeferBits := s.entryNewValue0(ssa.OpConst8, types.Types[types.TUINT8])
func (s *state) Debug_checknil() bool { return s.f.Frontend().Debug_checknil() }
func ssaMarker(name string) *ir.Name {
- return NewName(&types.Sym{Name: name})
+ return typecheck.NewName(&types.Sym{Name: name})
}
var (
func softfloatInit() {
// Some of these operations get transformed by sfcall.
softFloatOps = map[ssa.Op]sfRtCallDef{
- ssa.OpAdd32F: sfRtCallDef{sysfunc("fadd32"), types.TFLOAT32},
- ssa.OpAdd64F: sfRtCallDef{sysfunc("fadd64"), types.TFLOAT64},
- ssa.OpSub32F: sfRtCallDef{sysfunc("fadd32"), types.TFLOAT32},
- ssa.OpSub64F: sfRtCallDef{sysfunc("fadd64"), types.TFLOAT64},
- ssa.OpMul32F: sfRtCallDef{sysfunc("fmul32"), types.TFLOAT32},
- ssa.OpMul64F: sfRtCallDef{sysfunc("fmul64"), types.TFLOAT64},
- ssa.OpDiv32F: sfRtCallDef{sysfunc("fdiv32"), types.TFLOAT32},
- ssa.OpDiv64F: sfRtCallDef{sysfunc("fdiv64"), types.TFLOAT64},
-
- ssa.OpEq64F: sfRtCallDef{sysfunc("feq64"), types.TBOOL},
- ssa.OpEq32F: sfRtCallDef{sysfunc("feq32"), types.TBOOL},
- ssa.OpNeq64F: sfRtCallDef{sysfunc("feq64"), types.TBOOL},
- ssa.OpNeq32F: sfRtCallDef{sysfunc("feq32"), types.TBOOL},
- ssa.OpLess64F: sfRtCallDef{sysfunc("fgt64"), types.TBOOL},
- ssa.OpLess32F: sfRtCallDef{sysfunc("fgt32"), types.TBOOL},
- ssa.OpLeq64F: sfRtCallDef{sysfunc("fge64"), types.TBOOL},
- ssa.OpLeq32F: sfRtCallDef{sysfunc("fge32"), types.TBOOL},
-
- ssa.OpCvt32to32F: sfRtCallDef{sysfunc("fint32to32"), types.TFLOAT32},
- ssa.OpCvt32Fto32: sfRtCallDef{sysfunc("f32toint32"), types.TINT32},
- ssa.OpCvt64to32F: sfRtCallDef{sysfunc("fint64to32"), types.TFLOAT32},
- ssa.OpCvt32Fto64: sfRtCallDef{sysfunc("f32toint64"), types.TINT64},
- ssa.OpCvt64Uto32F: sfRtCallDef{sysfunc("fuint64to32"), types.TFLOAT32},
- ssa.OpCvt32Fto64U: sfRtCallDef{sysfunc("f32touint64"), types.TUINT64},
- ssa.OpCvt32to64F: sfRtCallDef{sysfunc("fint32to64"), types.TFLOAT64},
- ssa.OpCvt64Fto32: sfRtCallDef{sysfunc("f64toint32"), types.TINT32},
- ssa.OpCvt64to64F: sfRtCallDef{sysfunc("fint64to64"), types.TFLOAT64},
- ssa.OpCvt64Fto64: sfRtCallDef{sysfunc("f64toint64"), types.TINT64},
- ssa.OpCvt64Uto64F: sfRtCallDef{sysfunc("fuint64to64"), types.TFLOAT64},
- ssa.OpCvt64Fto64U: sfRtCallDef{sysfunc("f64touint64"), types.TUINT64},
- ssa.OpCvt32Fto64F: sfRtCallDef{sysfunc("f32to64"), types.TFLOAT64},
- ssa.OpCvt64Fto32F: sfRtCallDef{sysfunc("f64to32"), types.TFLOAT32},
+ ssa.OpAdd32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
+ ssa.OpAdd64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
+ ssa.OpSub32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fadd32"), types.TFLOAT32},
+ ssa.OpSub64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fadd64"), types.TFLOAT64},
+ ssa.OpMul32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fmul32"), types.TFLOAT32},
+ ssa.OpMul64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fmul64"), types.TFLOAT64},
+ ssa.OpDiv32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fdiv32"), types.TFLOAT32},
+ ssa.OpDiv64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fdiv64"), types.TFLOAT64},
+
+ ssa.OpEq64F: sfRtCallDef{typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
+ ssa.OpEq32F: sfRtCallDef{typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
+ ssa.OpNeq64F: sfRtCallDef{typecheck.LookupRuntimeFunc("feq64"), types.TBOOL},
+ ssa.OpNeq32F: sfRtCallDef{typecheck.LookupRuntimeFunc("feq32"), types.TBOOL},
+ ssa.OpLess64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fgt64"), types.TBOOL},
+ ssa.OpLess32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fgt32"), types.TBOOL},
+ ssa.OpLeq64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fge64"), types.TBOOL},
+ ssa.OpLeq32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fge32"), types.TBOOL},
+
+ ssa.OpCvt32to32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fint32to32"), types.TFLOAT32},
+ ssa.OpCvt32Fto32: sfRtCallDef{typecheck.LookupRuntimeFunc("f32toint32"), types.TINT32},
+ ssa.OpCvt64to32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fint64to32"), types.TFLOAT32},
+ ssa.OpCvt32Fto64: sfRtCallDef{typecheck.LookupRuntimeFunc("f32toint64"), types.TINT64},
+ ssa.OpCvt64Uto32F: sfRtCallDef{typecheck.LookupRuntimeFunc("fuint64to32"), types.TFLOAT32},
+ ssa.OpCvt32Fto64U: sfRtCallDef{typecheck.LookupRuntimeFunc("f32touint64"), types.TUINT64},
+ ssa.OpCvt32to64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fint32to64"), types.TFLOAT64},
+ ssa.OpCvt64Fto32: sfRtCallDef{typecheck.LookupRuntimeFunc("f64toint32"), types.TINT32},
+ ssa.OpCvt64to64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fint64to64"), types.TFLOAT64},
+ ssa.OpCvt64Fto64: sfRtCallDef{typecheck.LookupRuntimeFunc("f64toint64"), types.TINT64},
+ ssa.OpCvt64Uto64F: sfRtCallDef{typecheck.LookupRuntimeFunc("fuint64to64"), types.TFLOAT64},
+ ssa.OpCvt64Fto64U: sfRtCallDef{typecheck.LookupRuntimeFunc("f64touint64"), types.TUINT64},
+ ssa.OpCvt32Fto64F: sfRtCallDef{typecheck.LookupRuntimeFunc("f32to64"), types.TFLOAT64},
+ ssa.OpCvt64Fto32F: sfRtCallDef{typecheck.LookupRuntimeFunc("f64to32"), types.TFLOAT32},
}
}
} else {
pos = n.Pos()
}
- argTemp := tempAt(pos.WithNotStmt(), s.curfn, t)
+ argTemp := typecheck.TempAt(pos.WithNotStmt(), s.curfn, t)
argTemp.SetOpenDeferSlot(true)
var addrArgTemp *ssa.Value
// Use OpVarLive to make sure stack slots for the args, etc. are not
testLateExpansion = ssa.LateCallExpansionEnabledWithin(s.f)
// Make a defer struct d on the stack.
t := deferstruct(stksize)
- d := tempAt(n.Pos(), s.curfn, t)
+ d := typecheck.TempAt(n.Pos(), s.curfn, t)
s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, d, s.mem())
addr := s.addr(d)
if commaok && !canSSAType(n.Type()) {
// unSSAable type, use temporary.
// TODO: get rid of some of these temporaries.
- tmp = tempAt(n.Pos(), s.curfn, n.Type())
+ tmp = typecheck.TempAt(n.Pos(), s.curfn, n.Type())
s.vars[memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, tmp.(*ir.Name), s.mem())
addr = s.addr(tmp)
}
}
func (e *ssafn) Auto(pos src.XPos, t *types.Type) *ir.Name {
- return tempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
+ return typecheck.TempAt(pos, e.curfn, t) // Note: adds new auto to e.curfn.Func.Dcl list
}
func (e *ssafn) SplitString(name ssa.LocalSlot) (ssa.LocalSlot, ssa.LocalSlot) {
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
"fmt"
- "sort"
- "strconv"
"strings"
"sync"
"unicode"
largeStackFrames []largeStack
)
-func lookup(name string) *types.Sym {
- return types.LocalPkg.Lookup(name)
-}
-
-// lookupN looks up the symbol starting with prefix and ending with
-// the decimal n. If prefix is too long, lookupN panics.
-func lookupN(prefix string, n int) *types.Sym {
- var buf [20]byte // plenty long enough for all current users
- copy(buf[:], prefix)
- b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
- return types.LocalPkg.LookupBytes(b)
-}
-
-// autolabel generates a new Name node for use with
-// an automatically generated label.
-// prefix is a short mnemonic (e.g. ".s" for switch)
-// to help with debugging.
-// It should begin with "." to avoid conflicts with
-// user labels.
-func autolabel(prefix string) *types.Sym {
- if prefix[0] != '.' {
- base.Fatalf("autolabel prefix must start with '.', have %q", prefix)
- }
- fn := ir.CurFunc
- if ir.CurFunc == nil {
- base.Fatalf("autolabel outside function")
- }
- n := fn.Label
- fn.Label++
- return lookupN(prefix, int(n))
-}
-
// dotImports tracks all PkgNames that have been dot-imported.
var dotImports []*ir.PkgName
-// dotImportRefs maps idents introduced by importDot back to the
-// ir.PkgName they were dot-imported through.
-var dotImportRefs map[*ir.Ident]*ir.PkgName
-
// find all the exported symbols in package referenced by PkgName,
// and make them available in the current package
func importDot(pack *ir.PkgName) {
- if dotImportRefs == nil {
- dotImportRefs = make(map[*ir.Ident]*ir.PkgName)
+ if typecheck.DotImportRefs == nil {
+ typecheck.DotImportRefs = make(map[*ir.Ident]*ir.PkgName)
}
opkg := pack.Pkg
for _, s := range opkg.Syms {
if s.Def == nil {
- if _, ok := declImporter[s]; !ok {
+ if _, ok := typecheck.DeclImporter[s]; !ok {
continue
}
}
if !types.IsExported(s.Name) || strings.ContainsRune(s.Name, 0xb7) { // 0xb7 = center dot
continue
}
- s1 := lookup(s.Name)
+ s1 := typecheck.Lookup(s.Name)
if s1.Def != nil {
pkgerror := fmt.Sprintf("during import %q", opkg.Path)
- redeclare(base.Pos, s1, pkgerror)
+ typecheck.Redeclared(base.Pos, s1, pkgerror)
continue
}
id := ir.NewIdent(src.NoXPos, s)
- dotImportRefs[id] = pack
+ typecheck.DotImportRefs[id] = pack
s1.Def = id
s1.Block = 1
}
// No longer needed; release memory.
dotImports = nil
- dotImportRefs = nil
-}
-
-// nodAddr returns a node representing &n at base.Pos.
-func nodAddr(n ir.Node) *ir.AddrExpr {
- return nodAddrAt(base.Pos, n)
-}
-
-// nodAddrPos returns a node representing &n at position pos.
-func nodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr {
- return ir.NewAddrExpr(pos, n)
-}
-
-// newname returns a new ONAME Node associated with symbol s.
-func NewName(s *types.Sym) *ir.Name {
- n := ir.NewNameAt(base.Pos, s)
- n.Curfn = ir.CurFunc
- return n
-}
-
-func nodnil() ir.Node {
- n := ir.NewNilExpr(base.Pos)
- n.SetType(types.Types[types.TNIL])
- return n
-}
-
-func isptrto(t *types.Type, et types.Kind) bool {
- if t == nil {
- return false
- }
- if !t.IsPtr() {
- return false
- }
- t = t.Elem()
- if t == nil {
- return false
- }
- if t.Kind() != et {
- return false
- }
- return true
-}
-
-// Is type src assignment compatible to type dst?
-// If so, return op code to use in conversion.
-// If not, return OXXX. In this case, the string return parameter may
-// hold a reason why. In all other cases, it'll be the empty string.
-func assignop(src, dst *types.Type) (ir.Op, string) {
- if src == dst {
- return ir.OCONVNOP, ""
- }
- if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
- return ir.OXXX, ""
- }
-
- // 1. src type is identical to dst.
- if types.Identical(src, dst) {
- return ir.OCONVNOP, ""
- }
-
- // 2. src and dst have identical underlying types
- // and either src or dst is not a named type or
- // both are empty interface types.
- // For assignable but different non-empty interface types,
- // we want to recompute the itab. Recomputing the itab ensures
- // that itabs are unique (thus an interface with a compile-time
- // type I has an itab with interface type I).
- if types.Identical(src.Underlying(), dst.Underlying()) {
- if src.IsEmptyInterface() {
- // Conversion between two empty interfaces
- // requires no code.
- return ir.OCONVNOP, ""
- }
- if (src.Sym() == nil || dst.Sym() == nil) && !src.IsInterface() {
- // Conversion between two types, at least one unnamed,
- // needs no conversion. The exception is nonempty interfaces
- // which need to have their itab updated.
- return ir.OCONVNOP, ""
- }
- }
-
- // 3. dst is an interface type and src implements dst.
- if dst.IsInterface() && src.Kind() != types.TNIL {
- var missing, have *types.Field
- var ptr int
- if implements(src, dst, &missing, &have, &ptr) {
- // Call itabname so that (src, dst)
- // gets added to itabs early, which allows
- // us to de-virtualize calls through this
- // type/interface pair later. See peekitabs in reflect.go
- if types.IsDirectIface(src) && !dst.IsEmptyInterface() {
- NeedITab(src, dst)
- }
-
- return ir.OCONVIFACE, ""
- }
-
- // we'll have complained about this method anyway, suppress spurious messages.
- if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
- return ir.OCONVIFACE, ""
- }
-
- var why string
- if isptrto(src, types.TINTER) {
- why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
- } else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
- why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
- } else if have != nil && have.Sym == missing.Sym {
- why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
- "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
- } else if ptr != 0 {
- why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
- } else if have != nil {
- why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
- "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
- } else {
- why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
- }
-
- return ir.OXXX, why
- }
-
- if isptrto(dst, types.TINTER) {
- why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
- return ir.OXXX, why
- }
-
- if src.IsInterface() && dst.Kind() != types.TBLANK {
- var missing, have *types.Field
- var ptr int
- var why string
- if implements(dst, src, &missing, &have, &ptr) {
- why = ": need type assertion"
- }
- return ir.OXXX, why
- }
-
- // 4. src is a bidirectional channel value, dst is a channel type,
- // src and dst have identical element types, and
- // either src or dst is not a named type.
- if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
- if types.Identical(src.Elem(), dst.Elem()) && (src.Sym() == nil || dst.Sym() == nil) {
- return ir.OCONVNOP, ""
- }
- }
-
- // 5. src is the predeclared identifier nil and dst is a nillable type.
- if src.Kind() == types.TNIL {
- switch dst.Kind() {
- case types.TPTR,
- types.TFUNC,
- types.TMAP,
- types.TCHAN,
- types.TINTER,
- types.TSLICE:
- return ir.OCONVNOP, ""
- }
- }
-
- // 6. rule about untyped constants - already converted by defaultlit.
-
- // 7. Any typed value can be assigned to the blank identifier.
- if dst.Kind() == types.TBLANK {
- return ir.OCONVNOP, ""
- }
-
- return ir.OXXX, ""
-}
-
-// Can we convert a value of type src to a value of type dst?
-// If so, return op code to use in conversion (maybe OCONVNOP).
-// If not, return OXXX. In this case, the string return parameter may
-// hold a reason why. In all other cases, it'll be the empty string.
-// srcConstant indicates whether the value of type src is a constant.
-func convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
- if src == dst {
- return ir.OCONVNOP, ""
- }
- if src == nil || dst == nil {
- return ir.OXXX, ""
- }
-
- // Conversions from regular to go:notinheap are not allowed
- // (unless it's unsafe.Pointer). These are runtime-specific
- // rules.
- // (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
- if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
- why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
- return ir.OXXX, why
- }
- // (b) Disallow string to []T where T is go:notinheap.
- if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Kind() == types.ByteType.Kind() || dst.Elem().Kind() == types.RuneType.Kind()) {
- why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
- return ir.OXXX, why
- }
-
- // 1. src can be assigned to dst.
- op, why := assignop(src, dst)
- if op != ir.OXXX {
- return op, why
- }
-
- // The rules for interfaces are no different in conversions
- // than assignments. If interfaces are involved, stop now
- // with the good message from assignop.
- // Otherwise clear the error.
- if src.IsInterface() || dst.IsInterface() {
- return ir.OXXX, why
- }
-
- // 2. Ignoring struct tags, src and dst have identical underlying types.
- if types.IdenticalIgnoreTags(src.Underlying(), dst.Underlying()) {
- return ir.OCONVNOP, ""
- }
-
- // 3. src and dst are unnamed pointer types and, ignoring struct tags,
- // their base types have identical underlying types.
- if src.IsPtr() && dst.IsPtr() && src.Sym() == nil && dst.Sym() == nil {
- if types.IdenticalIgnoreTags(src.Elem().Underlying(), dst.Elem().Underlying()) {
- return ir.OCONVNOP, ""
- }
- }
-
- // 4. src and dst are both integer or floating point types.
- if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
- if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
- return ir.OCONVNOP, ""
- }
- return ir.OCONV, ""
- }
-
- // 5. src and dst are both complex types.
- if src.IsComplex() && dst.IsComplex() {
- if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
- return ir.OCONVNOP, ""
- }
- return ir.OCONV, ""
- }
-
- // Special case for constant conversions: any numeric
- // conversion is potentially okay. We'll validate further
- // within evconst. See #38117.
- if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
- return ir.OCONV, ""
- }
-
- // 6. src is an integer or has type []byte or []rune
- // and dst is a string type.
- if src.IsInteger() && dst.IsString() {
- return ir.ORUNESTR, ""
- }
-
- if src.IsSlice() && dst.IsString() {
- if src.Elem().Kind() == types.ByteType.Kind() {
- return ir.OBYTES2STR, ""
- }
- if src.Elem().Kind() == types.RuneType.Kind() {
- return ir.ORUNES2STR, ""
- }
- }
-
- // 7. src is a string and dst is []byte or []rune.
- // String to slice.
- if src.IsString() && dst.IsSlice() {
- if dst.Elem().Kind() == types.ByteType.Kind() {
- return ir.OSTR2BYTES, ""
- }
- if dst.Elem().Kind() == types.RuneType.Kind() {
- return ir.OSTR2RUNES, ""
- }
- }
-
- // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
- if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
- return ir.OCONVNOP, ""
- }
-
- // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
- if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
- return ir.OCONVNOP, ""
- }
-
- // src is map and dst is a pointer to corresponding hmap.
- // This rule is needed for the implementation detail that
- // go gc maps are implemented as a pointer to a hmap struct.
- if src.Kind() == types.TMAP && dst.IsPtr() &&
- src.MapType().Hmap == dst.Elem() {
- return ir.OCONVNOP, ""
- }
-
- return ir.OXXX, ""
-}
-
-func assignconv(n ir.Node, t *types.Type, context string) ir.Node {
- return assignconvfn(n, t, func() string { return context })
-}
-
-// Convert node n for assignment to type t.
-func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node {
- if n == nil || n.Type() == nil || n.Type().Broke() {
- return n
- }
-
- if t.Kind() == types.TBLANK && n.Type().Kind() == types.TNIL {
- base.Errorf("use of untyped nil")
- }
-
- n = convlit1(n, t, false, context)
- if n.Type() == nil {
- return n
- }
- if t.Kind() == types.TBLANK {
- return n
- }
-
- // Convert ideal bool from comparison to plain bool
- // if the next step is non-bool (like interface{}).
- if n.Type() == types.UntypedBool && !t.IsBoolean() {
- if n.Op() == ir.ONAME || n.Op() == ir.OLITERAL {
- r := ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n)
- r.SetType(types.Types[types.TBOOL])
- r.SetTypecheck(1)
- r.SetImplicit(true)
- n = r
- }
- }
-
- if types.Identical(n.Type(), t) {
- return n
- }
-
- op, why := assignop(n.Type(), t)
- if op == ir.OXXX {
- base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why)
- op = ir.OCONV
- }
-
- r := ir.NewConvExpr(base.Pos, op, t, n)
- r.SetTypecheck(1)
- r.SetImplicit(true)
- return r
+ typecheck.DotImportRefs = nil
}
// backingArrayPtrLen extracts the pointer and length from a slice or string.
return ptr, length
}
-func syslook(name string) *ir.Name {
- s := ir.Pkgs.Runtime.Lookup(name)
- if s == nil || s.Def == nil {
- base.Fatalf("syslook: can't find runtime.%s", name)
- }
- return ir.AsNode(s.Def).(*ir.Name)
-}
-
// updateHasCall checks whether expression n contains any function
// calls and sets the n.HasCall flag if so.
func updateHasCall(n ir.Node) {
}
a := ir.Copy(n).(*ir.UnaryExpr)
a.X = l
- return walkexpr(typecheck(a, ctxExpr), init)
+ return walkexpr(typecheck.Expr(a), init)
case ir.ODOT, ir.ODOTPTR:
n := n.(*ir.SelectorExpr)
}
a := ir.Copy(n).(*ir.SelectorExpr)
a.X = l
- return walkexpr(typecheck(a, ctxExpr), init)
+ return walkexpr(typecheck.Expr(a), init)
case ir.ODEREF:
n := n.(*ir.StarExpr)
}
a := ir.Copy(n).(*ir.StarExpr)
a.X = l
- return walkexpr(typecheck(a, ctxExpr), init)
+ return walkexpr(typecheck.Expr(a), init)
case ir.OINDEX, ir.OINDEXMAP:
n := n.(*ir.IndexExpr)
a := ir.Copy(n).(*ir.IndexExpr)
a.X = l
a.Index = r
- return walkexpr(typecheck(a, ctxExpr), init)
+ return walkexpr(typecheck.Expr(a), init)
case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT:
n := n.(*ir.CompLitExpr)
}
func copyexpr(n ir.Node, t *types.Type, init *ir.Nodes) ir.Node {
- l := temp(t)
+ l := typecheck.Temp(t)
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, l, n))
return l
}
return copyexpr(n, n.Type(), init)
}
-// Code to resolve elided DOTs in embedded types.
-
-// A Dlist stores a pointer to a TFIELD Type embedded within
-// a TSTRUCT or TINTER Type.
-type Dlist struct {
- field *types.Field
-}
-
-// dotlist is used by adddot1 to record the path of embedded fields
-// used to access a target field or method.
-// Must be non-nil so that dotpath returns a non-nil slice even if d is zero.
-var dotlist = make([]Dlist, 10)
-
-// lookdot0 returns the number of fields or methods named s associated
-// with Type t. If exactly one exists, it will be returned in *save
-// (if save is not nil).
-func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int {
- u := t
- if u.IsPtr() {
- u = u.Elem()
- }
-
- c := 0
- if u.IsStruct() || u.IsInterface() {
- for _, f := range u.Fields().Slice() {
- if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) {
- if save != nil {
- *save = f
- }
- c++
- }
- }
- }
-
- u = t
- if t.Sym() != nil && t.IsPtr() && !t.Elem().IsPtr() {
- // If t is a defined pointer type, then x.m is shorthand for (*x).m.
- u = t.Elem()
- }
- u = types.ReceiverBaseType(u)
- if u != nil {
- for _, f := range u.Methods().Slice() {
- if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
- if save != nil {
- *save = f
- }
- c++
- }
- }
- }
-
- return c
-}
-
-// adddot1 returns the number of fields or methods named s at depth d in Type t.
-// If exactly one exists, it will be returned in *save (if save is not nil),
-// and dotlist will contain the path of embedded fields traversed to find it,
-// in reverse order. If none exist, more will indicate whether t contains any
-// embedded fields at depth d, so callers can decide whether to retry at
-// a greater depth.
-func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) {
- if t.Recur() {
- return
- }
- t.SetRecur(true)
- defer t.SetRecur(false)
-
- var u *types.Type
- d--
- if d < 0 {
- // We've reached our target depth. If t has any fields/methods
- // named s, then we're done. Otherwise, we still need to check
- // below for embedded fields.
- c = lookdot0(s, t, save, ignorecase)
- if c != 0 {
- return c, false
- }
- }
-
- u = t
- if u.IsPtr() {
- u = u.Elem()
- }
- if !u.IsStruct() && !u.IsInterface() {
- return c, false
- }
-
- for _, f := range u.Fields().Slice() {
- if f.Embedded == 0 || f.Sym == nil {
- continue
- }
- if d < 0 {
- // Found an embedded field at target depth.
- return c, true
- }
- a, more1 := adddot1(s, f.Type, d, save, ignorecase)
- if a != 0 && c == 0 {
- dotlist[d].field = f
- }
- c += a
- if more1 {
- more = true
- }
- }
-
- return c, more
-}
-
-// dotpath computes the unique shortest explicit selector path to fully qualify
-// a selection expression x.f, where x is of type t and f is the symbol s.
-// If no such path exists, dotpath returns nil.
-// If there are multiple shortest paths to the same depth, ambig is true.
-func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []Dlist, ambig bool) {
- // The embedding of types within structs imposes a tree structure onto
- // types: structs parent the types they embed, and types parent their
- // fields or methods. Our goal here is to find the shortest path to
- // a field or method named s in the subtree rooted at t. To accomplish
- // that, we iteratively perform depth-first searches of increasing depth
- // until we either find the named field/method or exhaust the tree.
- for d := 0; ; d++ {
- if d > len(dotlist) {
- dotlist = append(dotlist, Dlist{})
- }
- if c, more := adddot1(s, t, d, save, ignorecase); c == 1 {
- return dotlist[:d], false
- } else if c > 1 {
- return nil, true
- } else if !more {
- return nil, false
- }
- }
-}
-
-// in T.field
-// find missing fields that
-// will give shortest unique addressing.
-// modify the tree with missing type names.
-func adddot(n *ir.SelectorExpr) *ir.SelectorExpr {
- n.X = typecheck(n.X, ctxType|ctxExpr)
- if n.X.Diag() {
- n.SetDiag(true)
- }
- t := n.X.Type()
- if t == nil {
- return n
- }
-
- if n.X.Op() == ir.OTYPE {
- return n
- }
-
- s := n.Sel
- if s == nil {
- return n
- }
-
- switch path, ambig := dotpath(s, t, nil, false); {
- case path != nil:
- // rebuild elided dots
- for c := len(path) - 1; c >= 0; c-- {
- dot := ir.NewSelectorExpr(base.Pos, ir.ODOT, n.X, path[c].field.Sym)
- dot.SetImplicit(true)
- dot.SetType(path[c].field.Type)
- n.X = dot
- }
- case ambig:
- base.Errorf("ambiguous selector %v", n)
- n.X = nil
- }
-
- return n
-}
-
-// Code to help generate trampoline functions for methods on embedded
-// types. These are approx the same as the corresponding adddot
-// routines except that they expect to be called with unique tasks and
-// they return the actual methods.
-
-type Symlink struct {
- field *types.Field
-}
-
-var slist []Symlink
-
-func expand0(t *types.Type) {
- u := t
- if u.IsPtr() {
- u = u.Elem()
- }
-
- if u.IsInterface() {
- for _, f := range u.Fields().Slice() {
- if f.Sym.Uniq() {
- continue
- }
- f.Sym.SetUniq(true)
- slist = append(slist, Symlink{field: f})
- }
-
- return
- }
-
- u = types.ReceiverBaseType(t)
- if u != nil {
- for _, f := range u.Methods().Slice() {
- if f.Sym.Uniq() {
- continue
- }
- f.Sym.SetUniq(true)
- slist = append(slist, Symlink{field: f})
- }
- }
-}
-
-func expand1(t *types.Type, top bool) {
- if t.Recur() {
- return
- }
- t.SetRecur(true)
-
- if !top {
- expand0(t)
- }
-
- u := t
- if u.IsPtr() {
- u = u.Elem()
- }
-
- if u.IsStruct() || u.IsInterface() {
- for _, f := range u.Fields().Slice() {
- if f.Embedded == 0 {
- continue
- }
- if f.Sym == nil {
- continue
- }
- expand1(f.Type, false)
- }
- }
-
- t.SetRecur(false)
-}
-
-func expandmeth(t *types.Type) {
- if t == nil || t.AllMethods().Len() != 0 {
- return
- }
-
- // mark top-level method symbols
- // so that expand1 doesn't consider them.
- for _, f := range t.Methods().Slice() {
- f.Sym.SetUniq(true)
- }
-
- // generate all reachable methods
- slist = slist[:0]
- expand1(t, true)
-
- // check each method to be uniquely reachable
- var ms []*types.Field
- for i, sl := range slist {
- slist[i].field = nil
- sl.field.Sym.SetUniq(false)
-
- var f *types.Field
- path, _ := dotpath(sl.field.Sym, t, &f, false)
- if path == nil {
- continue
- }
-
- // dotpath may have dug out arbitrary fields, we only want methods.
- if !f.IsMethod() {
- continue
- }
-
- // add it to the base type method list
- f = f.Copy()
- f.Embedded = 1 // needs a trampoline
- for _, d := range path {
- if d.field.Type.IsPtr() {
- f.Embedded = 2
- break
- }
- }
- ms = append(ms, f)
- }
-
- for _, f := range t.Methods().Slice() {
- f.Sym.SetUniq(false)
- }
-
- ms = append(ms, t.Methods().Slice()...)
- sort.Sort(types.MethodsByName(ms))
- t.AllMethods().Set(ms)
-}
-
-// Given funarg struct list, return list of fn args.
-func structargs(tl *types.Type, mustname bool) []*ir.Field {
- var args []*ir.Field
- gen := 0
- for _, t := range tl.Fields().Slice() {
- s := t.Sym
- if mustname && (s == nil || s.Name == "_") {
- // invent a name so that we can refer to it in the trampoline
- s = lookupN(".anon", gen)
- gen++
- }
- a := ir.NewField(base.Pos, s, nil, t.Type)
- a.Pos = t.Pos
- a.IsDDD = t.IsDDD()
- args = append(args, a)
- }
-
- return args
-}
-
// Generate a wrapper function to convert from
// a receiver of type T to a receiver of type U.
// That is,
}
base.Pos = base.AutogeneratedPos
- dclcontext = ir.PEXTERN
+ typecheck.DeclContext = ir.PEXTERN
tfn := ir.NewFuncType(base.Pos,
- ir.NewField(base.Pos, lookup(".this"), nil, rcvr),
- structargs(method.Type.Params(), true),
- structargs(method.Type.Results(), false))
+ ir.NewField(base.Pos, typecheck.Lookup(".this"), nil, rcvr),
+ typecheck.NewFuncParams(method.Type.Params(), true),
+ typecheck.NewFuncParams(method.Type.Results(), false))
- fn := dclfunc(newnam, tfn)
+ fn := typecheck.DeclFunc(newnam, tfn)
fn.SetDupok(true)
nthis := ir.AsNode(tfn.Type().Recv().Nname)
if rcvr.IsPtr() && rcvr.Elem() == methodrcvr {
// generating wrapper from *T to T.
n := ir.NewIfStmt(base.Pos, nil, nil, nil)
- n.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, nthis, nodnil())
- call := ir.NewCallExpr(base.Pos, ir.OCALL, syslook("panicwrap"), nil)
+ n.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, nthis, typecheck.NodNil())
+ call := ir.NewCallExpr(base.Pos, ir.OCALL, typecheck.LookupRuntime("panicwrap"), nil)
n.Body = []ir.Node{call}
fn.Body.Append(n)
}
- dot := adddot(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
+ dot := typecheck.AddImplicitDots(ir.NewSelectorExpr(base.Pos, ir.OXDOT, nthis, method.Sym))
// generate call
// It's not possible to use a tail call when dynamic linking on ppc64le. The
// generate tail call: adjust pointer receiver and jump to embedded method.
left := dot.X // skip final .M
if !left.Type().IsPtr() {
- left = nodAddr(left)
+ left = typecheck.NodAddr(left)
}
- as := ir.NewAssignStmt(base.Pos, nthis, convnop(left, rcvr))
+ as := ir.NewAssignStmt(base.Pos, nthis, typecheck.ConvNop(left, rcvr))
fn.Body.Append(as)
fn.Body.Append(ir.NewBranchStmt(base.Pos, ir.ORETJMP, ir.MethodSym(methodrcvr, method.Sym)))
} else {
ir.DumpList("genwrapper body", fn.Body)
}
- funcbody()
+ typecheck.FinishFuncBody()
if base.Debug.DclStack != 0 {
types.CheckDclstack()
}
- typecheckFunc(fn)
+ typecheck.Func(fn)
ir.CurFunc = fn
- typecheckslice(fn.Body, ctxStmt)
+ typecheck.Stmts(fn.Body)
// Inline calls within (*T).M wrappers. This is safe because we only
// generate those wrappers within the same compilation unit as (T).M.
escapeFuncs([]*ir.Func{fn}, false)
ir.CurFunc = nil
- Target.Decls = append(Target.Decls, fn)
+ typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
}
func hashmem(t *types.Type) ir.Node {
sym := ir.Pkgs.Runtime.Lookup("memhash")
- n := NewName(sym)
+ n := typecheck.NewName(sym)
ir.MarkFunc(n)
- n.SetType(functype(nil, []*ir.Field{
+ n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
ir.NewField(base.Pos, nil, nil, types.Types[types.TUINTPTR]),
return n
}
-func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, followptr bool) {
- if t == nil {
- return nil, false
- }
-
- path, ambig := dotpath(s, t, &m, ignorecase)
- if path == nil {
- if ambig {
- base.Errorf("%v.%v is ambiguous", t, s)
- }
- return nil, false
- }
-
- for _, d := range path {
- if d.field.Type.IsPtr() {
- followptr = true
- break
- }
- }
-
- if !m.IsMethod() {
- base.Errorf("%v.%v is a field, not a method", t, s)
- return nil, followptr
- }
-
- return m, followptr
-}
-
-func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool {
- t0 := t
- if t == nil {
- return false
- }
-
- if t.IsInterface() {
- i := 0
- tms := t.Fields().Slice()
- for _, im := range iface.Fields().Slice() {
- for i < len(tms) && tms[i].Sym != im.Sym {
- i++
- }
- if i == len(tms) {
- *m = im
- *samename = nil
- *ptr = 0
- return false
- }
- tm := tms[i]
- if !types.Identical(tm.Type, im.Type) {
- *m = im
- *samename = tm
- *ptr = 0
- return false
- }
- }
-
- return true
- }
-
- t = types.ReceiverBaseType(t)
- var tms []*types.Field
- if t != nil {
- expandmeth(t)
- tms = t.AllMethods().Slice()
- }
- i := 0
- for _, im := range iface.Fields().Slice() {
- if im.Broke() {
- continue
- }
- for i < len(tms) && tms[i].Sym != im.Sym {
- i++
- }
- if i == len(tms) {
- *m = im
- *samename, _ = ifacelookdot(im.Sym, t, true)
- *ptr = 0
- return false
- }
- tm := tms[i]
- if tm.Nointerface() || !types.Identical(tm.Type, im.Type) {
- *m = im
- *samename = tm
- *ptr = 0
- return false
- }
- followptr := tm.Embedded == 2
-
- // if pointer receiver in method,
- // the method does not exist for value types.
- rcvr := tm.Type.Recv().Type
- if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !types.IsInterfaceMethod(tm.Type) {
- if false && base.Flag.LowerR != 0 {
- base.Errorf("interface pointer mismatch")
- }
-
- *m = im
- *samename = nil
- *ptr = 1
- return false
- }
- }
-
- return true
-}
-
func ngotype(n ir.Node) *types.Sym {
if n.Type() != nil {
return typenamesym(n.Type())
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/src"
"go/constant"
"sort"
)
-// typecheckswitch typechecks a switch statement.
-func typecheckswitch(n *ir.SwitchStmt) {
- typecheckslice(n.Init(), ctxStmt)
- if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
- typecheckTypeSwitch(n)
- } else {
- typecheckExprSwitch(n)
- }
-}
-
-func typecheckTypeSwitch(n *ir.SwitchStmt) {
- guard := n.Tag.(*ir.TypeSwitchGuard)
- guard.X = typecheck(guard.X, ctxExpr)
- t := guard.X.Type()
- if t != nil && !t.IsInterface() {
- base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", guard.X)
- t = nil
- }
-
- // We don't actually declare the type switch's guarded
- // declaration itself. So if there are no cases, we won't
- // notice that it went unused.
- if v := guard.Tag; v != nil && !ir.IsBlank(v) && len(n.Cases) == 0 {
- base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym())
- }
-
- var defCase, nilCase ir.Node
- var ts typeSet
- for _, ncase := range n.Cases {
- ncase := ncase.(*ir.CaseStmt)
- ls := ncase.List
- if len(ls) == 0 { // default:
- if defCase != nil {
- base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
- } else {
- defCase = ncase
- }
- }
-
- for i := range ls {
- ls[i] = typecheck(ls[i], ctxExpr|ctxType)
- n1 := ls[i]
- if t == nil || n1.Type() == nil {
- continue
- }
-
- var missing, have *types.Field
- var ptr int
- if ir.IsNil(n1) { // case nil:
- if nilCase != nil {
- base.ErrorfAt(ncase.Pos(), "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
- } else {
- nilCase = ncase
- }
- continue
- }
- if n1.Op() != ir.OTYPE {
- base.ErrorfAt(ncase.Pos(), "%L is not a type", n1)
- continue
- }
- if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke() {
- if have != nil && !have.Broke() {
- base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
- " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", guard.X, n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
- } else if ptr != 0 {
- base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
- " (%v method has pointer receiver)", guard.X, n1.Type(), missing.Sym)
- } else {
- base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
- " (missing %v method)", guard.X, n1.Type(), missing.Sym)
- }
- continue
- }
-
- ts.add(ncase.Pos(), n1.Type())
- }
-
- if len(ncase.Vars) != 0 {
- // Assign the clause variable's type.
- vt := t
- if len(ls) == 1 {
- if ls[0].Op() == ir.OTYPE {
- vt = ls[0].Type()
- } else if !ir.IsNil(ls[0]) {
- // Invalid single-type case;
- // mark variable as broken.
- vt = nil
- }
- }
-
- nvar := ncase.Vars[0]
- nvar.SetType(vt)
- if vt != nil {
- nvar = typecheck(nvar, ctxExpr|ctxAssign)
- } else {
- // Clause variable is broken; prevent typechecking.
- nvar.SetTypecheck(1)
- nvar.SetWalkdef(1)
- }
- ncase.Vars[0] = nvar
- }
-
- typecheckslice(ncase.Body, ctxStmt)
- }
-}
-
-type typeSet struct {
- m map[string][]typeSetEntry
-}
-
-type typeSetEntry struct {
- pos src.XPos
- typ *types.Type
-}
-
-func (s *typeSet) add(pos src.XPos, typ *types.Type) {
- if s.m == nil {
- s.m = make(map[string][]typeSetEntry)
- }
-
- // LongString does not uniquely identify types, so we need to
- // disambiguate collisions with types.Identical.
- // TODO(mdempsky): Add a method that *is* unique.
- ls := typ.LongString()
- prevs := s.m[ls]
- for _, prev := range prevs {
- if types.Identical(typ, prev.typ) {
- base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos))
- return
- }
- }
- s.m[ls] = append(prevs, typeSetEntry{pos, typ})
-}
-
-func typecheckExprSwitch(n *ir.SwitchStmt) {
- t := types.Types[types.TBOOL]
- if n.Tag != nil {
- n.Tag = typecheck(n.Tag, ctxExpr)
- n.Tag = defaultlit(n.Tag, nil)
- t = n.Tag.Type()
- }
-
- var nilonly string
- if t != nil {
- switch {
- case t.IsMap():
- nilonly = "map"
- case t.Kind() == types.TFUNC:
- nilonly = "func"
- case t.IsSlice():
- nilonly = "slice"
-
- case !types.IsComparable(t):
- if t.IsStruct() {
- base.ErrorfAt(n.Pos(), "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, types.IncomparableField(t).Type)
- } else {
- base.ErrorfAt(n.Pos(), "cannot switch on %L", n.Tag)
- }
- t = nil
- }
- }
-
- var defCase ir.Node
- var cs constSet
- for _, ncase := range n.Cases {
- ncase := ncase.(*ir.CaseStmt)
- ls := ncase.List
- if len(ls) == 0 { // default:
- if defCase != nil {
- base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
- } else {
- defCase = ncase
- }
- }
-
- for i := range ls {
- ir.SetPos(ncase)
- ls[i] = typecheck(ls[i], ctxExpr)
- ls[i] = defaultlit(ls[i], t)
- n1 := ls[i]
- if t == nil || n1.Type() == nil {
- continue
- }
-
- if nilonly != "" && !ir.IsNil(n1) {
- base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Tag)
- } else if t.IsInterface() && !n1.Type().IsInterface() && !types.IsComparable(n1.Type()) {
- base.ErrorfAt(ncase.Pos(), "invalid case %L in switch (incomparable type)", n1)
- } else {
- op1, _ := assignop(n1.Type(), t)
- op2, _ := assignop(t, n1.Type())
- if op1 == ir.OXXX && op2 == ir.OXXX {
- if n.Tag != nil {
- base.ErrorfAt(ncase.Pos(), "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Tag, n1.Type(), t)
- } else {
- base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type())
- }
- }
- }
-
- // Don't check for duplicate bools. Although the spec allows it,
- // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
- // (2) it would disallow useful things like
- // case GOARCH == "arm" && GOARM == "5":
- // case GOARCH == "arm":
- // which would both evaluate to false for non-ARM compiles.
- if !n1.Type().IsBoolean() {
- cs.add(ncase.Pos(), n1, "case", "switch")
- }
- }
-
- typecheckslice(ncase.Body, ctxStmt)
- }
-}
-
// walkswitch walks a switch statement.
func walkswitch(sw *ir.SwitchStmt) {
// Guard against double walk, see #25776.
// convert switch {...} to switch true {...}
if cond == nil {
cond = ir.NewBool(true)
- cond = typecheck(cond, ctxExpr)
- cond = defaultlit(cond, nil)
+ cond = typecheck.Expr(cond)
+ cond = typecheck.DefaultLit(cond, nil)
}
// Given "switch string(byteslice)",
var body ir.Nodes
for _, ncase := range sw.Cases {
ncase := ncase.(*ir.CaseStmt)
- label := autolabel(".s")
+ label := typecheck.AutoLabel(".s")
jmp := ir.NewBranchStmt(ncase.Pos(), ir.OGOTO, label)
// Process case dispatch.
s.facename = walkexpr(s.facename, sw.PtrInit())
s.facename = copyexpr(s.facename, s.facename.Type(), &sw.Compiled)
- s.okname = temp(types.Types[types.TBOOL])
+ s.okname = typecheck.Temp(types.Types[types.TBOOL])
// Get interface descriptor word.
// For empty interfaces this will be the type.
// h := e._type.hash
// Use a similar strategy for non-empty interfaces.
ifNil := ir.NewIfStmt(base.Pos, nil, nil, nil)
- ifNil.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, itab, nodnil())
+ ifNil.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, itab, typecheck.NodNil())
base.Pos = base.Pos.WithNotStmt() // disable statement marks after the first check.
- ifNil.Cond = typecheck(ifNil.Cond, ctxExpr)
- ifNil.Cond = defaultlit(ifNil.Cond, nil)
+ ifNil.Cond = typecheck.Expr(ifNil.Cond)
+ ifNil.Cond = typecheck.DefaultLit(ifNil.Cond, nil)
// ifNil.Nbody assigned at end.
sw.Compiled.Append(ifNil)
}
caseVarInitialized := false
- label := autolabel(".s")
+ label := typecheck.AutoLabel(".s")
jmp := ir.NewBranchStmt(ncase.Pos(), ir.OGOTO, label)
if len(ncase.List) == 0 { // default:
ir.NewDecl(ncase.Pos(), ir.ODCL, caseVar),
ir.NewAssignStmt(ncase.Pos(), caseVar, val),
}
- typecheckslice(l, ctxStmt)
+ typecheck.Stmts(l)
body.Append(l...)
}
body.Append(ncase.Body...)
ir.NewDecl(pos, ir.ODCL, caseVar),
ir.NewAssignStmt(pos, caseVar, nil),
}
- typecheckslice(l, ctxStmt)
+ typecheck.Stmts(l)
body.Append(l...)
} else {
caseVar = ir.BlankNode
nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
leaf(i, nif)
base.Pos = base.Pos.WithNotStmt()
- nif.Cond = typecheck(nif.Cond, ctxExpr)
- nif.Cond = defaultlit(nif.Cond, nil)
+ nif.Cond = typecheck.Expr(nif.Cond)
+ nif.Cond = typecheck.DefaultLit(nif.Cond, nil)
out.Append(nif)
out = &nif.Else
}
nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
nif.Cond = less(half)
base.Pos = base.Pos.WithNotStmt()
- nif.Cond = typecheck(nif.Cond, ctxExpr)
- nif.Cond = defaultlit(nif.Cond, nil)
+ nif.Cond = typecheck.Expr(nif.Cond)
+ nif.Cond = typecheck.DefaultLit(nif.Cond, nil)
do(lo, half, &nif.Body)
do(half, hi, &nif.Else)
out.Append(nif)
+++ /dev/null
-// Copyright 2017 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// This file implements convertions between *types.Node and *Node.
-// TODO(gri) try to eliminate these soon
-
-package gc
+++ /dev/null
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package gc
-
-import (
- "cmd/compile/internal/base"
- "cmd/compile/internal/ir"
- "cmd/compile/internal/types"
-)
-
-// evalunsafe evaluates a package unsafe operation and returns the result.
-func evalunsafe(n ir.Node) int64 {
- switch n.Op() {
- case ir.OALIGNOF, ir.OSIZEOF:
- n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
- n.X = defaultlit(n.X, nil)
- tr := n.X.Type()
- if tr == nil {
- return 0
- }
- types.CalcSize(tr)
- if n.Op() == ir.OALIGNOF {
- return int64(tr.Align)
- }
- return tr.Width
-
- case ir.OOFFSETOF:
- // must be a selector.
- n := n.(*ir.UnaryExpr)
- if n.X.Op() != ir.OXDOT {
- base.Errorf("invalid expression %v", n)
- return 0
- }
- sel := n.X.(*ir.SelectorExpr)
-
- // Remember base of selector to find it back after dot insertion.
- // Since r->left may be mutated by typechecking, check it explicitly
- // first to track it correctly.
- sel.X = typecheck(sel.X, ctxExpr)
- sbase := sel.X
-
- tsel := typecheck(sel, ctxExpr)
- n.X = tsel
- if tsel.Type() == nil {
- return 0
- }
- switch tsel.Op() {
- case ir.ODOT, ir.ODOTPTR:
- break
- case ir.OCALLPART:
- base.Errorf("invalid expression %v: argument is a method value", n)
- return 0
- default:
- base.Errorf("invalid expression %v", n)
- return 0
- }
-
- // Sum offsets for dots until we reach sbase.
- var v int64
- var next ir.Node
- for r := tsel; r != sbase; r = next {
- switch r.Op() {
- case ir.ODOTPTR:
- // For Offsetof(s.f), s may itself be a pointer,
- // but accessing f must not otherwise involve
- // indirection via embedded pointer types.
- r := r.(*ir.SelectorExpr)
- if r.X != sbase {
- base.Errorf("invalid expression %v: selector implies indirection of embedded %v", n, r.X)
- return 0
- }
- fallthrough
- case ir.ODOT:
- r := r.(*ir.SelectorExpr)
- v += r.Offset
- next = r.X
- default:
- ir.Dump("unsafenmagic", tsel)
- base.Fatalf("impossible %v node after dot insertion", r.Op())
- }
- }
- return v
- }
-
- base.Fatalf("unexpected op %v", n.Op())
- return 0
-}
import (
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/objabi"
// Final typecheck for any unused variables.
for i, ln := range fn.Dcl {
if ln.Op() == ir.ONAME && (ln.Class_ == ir.PAUTO || ln.Class_ == ir.PAUTOHEAP) {
- ln = typecheck(ln, ctxExpr|ctxAssign).(*ir.Name)
+ ln = typecheck.AssignExpr(ln).(*ir.Name)
fn.Dcl[i] = ln
}
}
n.PtrInit().Set(nil)
n.X = walkexpr(n.X, &init)
- call := walkexpr(mkcall1(chanfn("chanrecv1", 2, n.X.Type()), nil, &init, n.X, nodnil()), &init)
+ call := walkexpr(mkcall1(chanfn("chanrecv1", 2, n.X.Type()), nil, &init, n.X, typecheck.NodNil()), &init)
return ir.InitExpr(init, call)
case ir.OBREAK,
}
nn := ir.NewAssignStmt(base.Pos, v.Name().Heapaddr, callnew(v.Type()))
nn.Def = true
- return walkstmt(typecheck(nn, ctxStmt))
+ return walkstmt(typecheck.Stmt(nn))
}
return n
if cl == ir.PPARAMOUT {
var ln ir.Node = ln
if ir.IsParamStackCopy(ln) {
- ln = walkexpr(typecheck(ir.NewStarExpr(base.Pos, ln.Name().Heapaddr), ctxExpr), nil)
+ ln = walkexpr(typecheck.Expr(ir.NewStarExpr(base.Pos, ln.Name().Heapaddr)), nil)
}
rl = append(rl, ln)
}
n := n.(*ir.Name)
nn := ir.NewStarExpr(base.Pos, n.Name().Heapaddr)
nn.X.MarkNonNil()
- return walkexpr(typecheck(nn, ctxExpr), init)
+ return walkexpr(typecheck.Expr(nn), init)
}
n = walkexpr1(n, init)
// walk of y%1 may have replaced it by 0.
// Check whether n with its updated args is itself now a constant.
t := n.Type()
- n = evalConst(n)
+ n = typecheck.EvalConst(n)
if n.Type() != t {
base.Fatalf("evconst changed Type: %v had type %v, now %v", n, t, n.Type())
}
if n.Op() == ir.OLITERAL {
- n = typecheck(n, ctxExpr)
+ n = typecheck.Expr(n)
// Emit string symbol now to avoid emitting
// any concurrently during the backend.
if v := n.Val(); v.Kind() == constant.String {
n := n.(*ir.UnaryExpr)
if isRuneCount(n) {
// Replace len([]rune(string)) with runtime.countrunes(string).
- return mkcall("countrunes", n.Type(), init, conv(n.X.(*ir.ConvExpr).X, types.Types[types.TSTRING]))
+ return mkcall("countrunes", n.Type(), init, typecheck.Conv(n.X.(*ir.ConvExpr).X, types.Types[types.TSTRING]))
}
n.X = walkexpr(n.X, init)
}
if t.IsArray() {
safeexpr(n.X, init)
- con := origIntConst(n, t.NumElem())
+ con := typecheck.OrigInt(n, t.NumElem())
con.SetTypecheck(1)
return con
}
case ir.ORECOVER:
n := n.(*ir.CallExpr)
- return mkcall("gorecover", n.Type(), init, nodAddr(ir.RegFP))
+ return mkcall("gorecover", n.Type(), init, typecheck.NodAddr(ir.RegFP))
case ir.OCLOSUREREAD, ir.OCFUNC:
return n
if n.Op() == ir.OASOP {
// Rewrite x op= y into x = x op y.
- n = ir.NewAssignStmt(base.Pos, left, typecheck(ir.NewBinaryExpr(base.Pos, n.(*ir.AssignOpStmt).AsOp, left, right), ctxExpr))
+ n = ir.NewAssignStmt(base.Pos, left, typecheck.Expr(ir.NewBinaryExpr(base.Pos, n.(*ir.AssignOpStmt).AsOp, left, right)))
} else {
n.(*ir.AssignStmt).X = left
}
recv := as.Y.(*ir.UnaryExpr)
recv.X = walkexpr(recv.X, init)
- n1 := nodAddr(as.X)
+ n1 := typecheck.NodAddr(as.X)
r := recv.X // the channel
return mkcall1(chanfn("chanrecv1", 2, r.Type()), nil, init, r, n1)
r.X = walkexpr(r.X, init)
var n1 ir.Node
if ir.IsBlank(n.Lhs[0]) {
- n1 = nodnil()
+ n1 = typecheck.NodNil()
} else {
- n1 = nodAddr(n.Lhs[0])
+ n1 = typecheck.NodAddr(n.Lhs[0])
}
fn := chanfn("chanrecv2", 2, r.X.Type())
ok := n.Lhs[1]
call := mkcall1(fn, types.Types[types.TBOOL], init, r.X, n1)
- return typecheck(ir.NewAssignStmt(base.Pos, ok, call), ctxStmt)
+ return typecheck.Stmt(ir.NewAssignStmt(base.Pos, ok, call))
// a,b = m[i]
case ir.OAS2MAPR:
} else {
// standard version takes key by reference
// order.expr made sure key is addressable.
- key = nodAddr(r.Index)
+ key = typecheck.NodAddr(r.Index)
}
// from:
// don't generate a = *var if a is _
if ir.IsBlank(a) {
- return walkexpr(typecheck(n, ctxStmt), init)
+ return walkexpr(typecheck.Stmt(n), init)
}
- var_ := temp(types.NewPtr(t.Elem()))
+ var_ := typecheck.Temp(types.NewPtr(t.Elem()))
var_.SetTypecheck(1)
var_.MarkNonNil() // mapaccess always returns a non-nil pointer
init.Append(walkexpr(n, init))
as := ir.NewAssignStmt(base.Pos, a, ir.NewStarExpr(base.Pos, var_))
- return walkexpr(typecheck(as, ctxStmt), init)
+ return walkexpr(typecheck.Stmt(as), init)
case ir.ODELETE:
n := n.(*ir.CallExpr)
fast := mapfast(t)
if fast == mapslow {
// order.stmt made sure key is addressable.
- key = nodAddr(key)
+ key = typecheck.NodAddr(key)
}
return mkcall1(mapfndel(mapdelete[fast], t), nil, init, typename(t), map_, key)
}
if ir.Names.Staticuint64s == nil {
- ir.Names.Staticuint64s = NewName(ir.Pkgs.Runtime.Lookup("staticuint64s"))
+ ir.Names.Staticuint64s = typecheck.NewName(ir.Pkgs.Runtime.Lookup("staticuint64s"))
ir.Names.Staticuint64s.Class_ = ir.PEXTERN
// The actual type is [256]uint64, but we use [256*8]uint8 so we can address
// individual bytes.
ir.Names.Staticuint64s.SetType(types.NewArray(types.Types[types.TUINT8], 256*8))
- ir.Names.Zerobase = NewName(ir.Pkgs.Runtime.Lookup("zerobase"))
+ ir.Names.Zerobase = typecheck.NewName(ir.Pkgs.Runtime.Lookup("zerobase"))
ir.Names.Zerobase.Class_ = ir.PEXTERN
ir.Names.Zerobase.SetType(types.Types[types.TUINTPTR])
}
value = n.X
case !fromType.IsInterface() && n.Esc() == ir.EscNone && fromType.Width <= 1024:
// n.Left does not escape. Use a stack temporary initialized to n.Left.
- value = temp(fromType)
- init.Append(typecheck(ir.NewAssignStmt(base.Pos, value, n.X), ctxStmt))
+ value = typecheck.Temp(fromType)
+ init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, value, n.X)))
}
if value != nil {
// Value is identical to n.Left.
// Construct the interface directly: {type/itab, &value}.
- l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), typecheck(nodAddr(value), ctxExpr))
+ l := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), typecheck.Expr(typecheck.NodAddr(value)))
l.SetType(toType)
l.SetTypecheck(n.Typecheck())
return l
// e = iface{tmp, i.data}
if toType.IsEmptyInterface() && fromType.IsInterface() && !fromType.IsEmptyInterface() {
// Evaluate the input interface.
- c := temp(fromType)
+ c := typecheck.Temp(fromType)
init.Append(ir.NewAssignStmt(base.Pos, c, n.X))
// Get the itab out of the interface.
- tmp := temp(types.NewPtr(types.Types[types.TUINT8]))
- init.Append(ir.NewAssignStmt(base.Pos, tmp, typecheck(ir.NewUnaryExpr(base.Pos, ir.OITAB, c), ctxExpr)))
+ tmp := typecheck.Temp(types.NewPtr(types.Types[types.TUINT8]))
+ init.Append(ir.NewAssignStmt(base.Pos, tmp, typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, c))))
// Get the type out of the itab.
- nif := ir.NewIfStmt(base.Pos, typecheck(ir.NewBinaryExpr(base.Pos, ir.ONE, tmp, nodnil()), ctxExpr), nil, nil)
+ nif := ir.NewIfStmt(base.Pos, typecheck.Expr(ir.NewBinaryExpr(base.Pos, ir.ONE, tmp, typecheck.NodNil())), nil, nil)
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, tmp, itabType(tmp))}
init.Append(nif)
// Use a specialized conversion routine that only returns a data pointer.
// ptr = convT2X(val)
// e = iface{typ/tab, ptr}
- fn := syslook(fnname)
+ fn := typecheck.LookupRuntime(fnname)
types.CalcSize(fromType)
- fn = substArgTypes(fn, fromType)
+ fn = typecheck.SubstArgTypes(fn, fromType)
types.CalcSize(fn.Type())
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
call.Args = []ir.Node{n.X}
- e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), safeexpr(walkexpr(typecheck(call, ctxExpr), init), init))
+ e := ir.NewBinaryExpr(base.Pos, ir.OEFACE, typeword(), safeexpr(walkexpr(typecheck.Expr(call), init), init))
e.SetType(toType)
e.SetTypecheck(1)
return e
if !ir.IsAssignable(v) {
v = copyexpr(v, v.Type(), init)
}
- v = nodAddr(v)
+ v = typecheck.NodAddr(v)
}
types.CalcSize(fromType)
- fn := syslook(fnname)
- fn = substArgTypes(fn, fromType, toType)
+ fn := typecheck.LookupRuntime(fnname)
+ fn = typecheck.SubstArgTypes(fn, fromType, toType)
types.CalcSize(fn.Type())
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
call.Args = []ir.Node{tab, v}
- return walkexpr(typecheck(call, ctxExpr), init)
+ return walkexpr(typecheck.Expr(call), init)
case ir.OCONV, ir.OCONVNOP:
n := n.(*ir.ConvExpr)
return n
}
fn := types.BasicTypeNames[param] + "to" + types.BasicTypeNames[result]
- return conv(mkcall(fn, types.Types[result], init, conv(n.X, types.Types[param])), n.Type())
+ return typecheck.Conv(mkcall(fn, types.Types[result], init, typecheck.Conv(n.X, types.Types[param])), n.Type())
case ir.ODIV, ir.OMOD:
n := n.(*ir.BinaryExpr)
if types.IsComplex[et] && n.Op() == ir.ODIV {
t := n.Type()
- call := mkcall("complex128div", types.Types[types.TCOMPLEX128], init, conv(n.X, types.Types[types.TCOMPLEX128]), conv(n.Y, types.Types[types.TCOMPLEX128]))
- return conv(call, t)
+ call := mkcall("complex128div", types.Types[types.TCOMPLEX128], init, typecheck.Conv(n.X, types.Types[types.TCOMPLEX128]), typecheck.Conv(n.Y, types.Types[types.TCOMPLEX128]))
+ return typecheck.Conv(call, t)
}
// Nothing to do for float divisions.
} else {
fn += "mod"
}
- return mkcall(fn, n.Type(), init, conv(n.X, types.Types[et]), conv(n.Y, types.Types[et]))
+ return mkcall(fn, n.Type(), init, typecheck.Conv(n.X, types.Types[et]), typecheck.Conv(n.Y, types.Types[et]))
}
return n
if fast == mapslow {
// standard version takes key by reference.
// order.expr made sure key is addressable.
- key = nodAddr(key)
+ key = typecheck.NodAddr(key)
}
call = mkcall1(mapfn(mapassign[fast], t), nil, init, typename(t), map_, key)
} else {
if fast == mapslow {
// standard version takes key by reference.
// order.expr made sure key is addressable.
- key = nodAddr(key)
+ key = typecheck.NodAddr(key)
}
if w := t.Elem().Width; w <= zeroValSize {
if n.Type().Elem().Width >= ir.MaxImplicitStackVarSize {
base.Fatalf("large ONEW with EscNone: %v", n)
}
- r := temp(n.Type().Elem())
- init.Append(typecheck(ir.NewAssignStmt(base.Pos, r, nil), ctxStmt)) // zero temp
- return typecheck(nodAddr(r), ctxExpr)
+ r := typecheck.Temp(n.Type().Elem())
+ init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, r, nil))) // zero temp
+ return typecheck.Expr(typecheck.NodAddr(r))
}
return callnew(n.Type().Elem())
case ir.OCLOSE:
// cannot use chanfn - closechan takes any, not chan any
n := n.(*ir.UnaryExpr)
- fn := syslook("closechan")
- fn = substArgTypes(fn, n.X.Type())
+ fn := typecheck.LookupRuntime("closechan")
+ fn = typecheck.SubstArgTypes(fn, n.X.Type())
return mkcall1(fn, nil, init, n.X)
case ir.OMAKECHAN:
argtype = types.Types[types.TINT]
}
- return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, typename(n.Type()), conv(size, argtype))
+ return mkcall1(chanfn(fnname, 1, n.Type()), n.Type(), init, typename(n.Type()), typecheck.Conv(size, argtype))
case ir.OMAKEMAP:
n := n.(*ir.MakeExpr)
// Allocate hmap on stack.
// var hv hmap
- hv := temp(hmapType)
- init.Append(typecheck(ir.NewAssignStmt(base.Pos, hv, nil), ctxStmt))
+ hv := typecheck.Temp(hmapType)
+ init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, hv, nil)))
// h = &hv
- h = nodAddr(hv)
+ h = typecheck.NodAddr(hv)
// Allocate one bucket pointed to by hmap.buckets on stack if hint
// is not larger than BUCKETSIZE. In case hint is larger than
nif.Likely = true
// var bv bmap
- bv := temp(bmap(t))
+ bv := typecheck.Temp(bmap(t))
nif.Body.Append(ir.NewAssignStmt(base.Pos, bv, nil))
// b = &bv
- b := nodAddr(bv)
+ b := typecheck.NodAddr(bv)
// h.buckets = b
bsym := hmapType.Field(5).Sym // hmap.buckets see reflect.go:hmap
rand := mkcall("fastrand", types.Types[types.TUINT32], init)
hashsym := hmapType.Field(4).Sym // hmap.hash0 see reflect.go:hmap
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, hashsym), rand))
- return convnop(h, t)
+ return typecheck.ConvNop(h, t)
}
// Call runtime.makehmap to allocate an
// hmap on the heap and initialize hmap's hash0 field.
- fn := syslook("makemap_small")
- fn = substArgTypes(fn, t.Key(), t.Elem())
+ fn := typecheck.LookupRuntime("makemap_small")
+ fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem())
return mkcall1(fn, n.Type(), init)
}
if n.Esc() != ir.EscNone {
- h = nodnil()
+ h = typecheck.NodNil()
}
// Map initialization with a variable or large hint is
// more complicated. We therefore generate a call to
argtype = types.Types[types.TINT]
}
- fn := syslook(fnname)
- fn = substArgTypes(fn, hmapType, t.Key(), t.Elem())
- return mkcall1(fn, n.Type(), init, typename(n.Type()), conv(hint, argtype), h)
+ fn := typecheck.LookupRuntime(fnname)
+ fn = typecheck.SubstArgTypes(fn, hmapType, t.Key(), t.Elem())
+ return mkcall1(fn, n.Type(), init, typename(n.Type()), typecheck.Conv(hint, argtype), h)
case ir.OMAKESLICE:
n := n.(*ir.MakeExpr)
}
// var arr [r]T
// n = arr[:l]
- i := indexconst(r)
+ i := typecheck.IndexConst(r)
if i < 0 {
base.Fatalf("walkexpr: invalid index %v", r)
}
// if len < 0 { panicmakeslicelen() }
// panicmakeslicecap()
// }
- nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, conv(l, types.Types[types.TUINT64]), ir.NewInt(i)), nil, nil)
+ nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(l, types.Types[types.TUINT64]), ir.NewInt(i)), nil, nil)
niflen := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OLT, l, ir.NewInt(0)), nil, nil)
niflen.Body = []ir.Node{mkcall("panicmakeslicelen", nil, init)}
nif.Body.Append(niflen, mkcall("panicmakeslicecap", nil, init))
- init.Append(typecheck(nif, ctxStmt))
+ init.Append(typecheck.Stmt(nif))
t = types.NewArray(t.Elem(), i) // [r]T
- var_ := temp(t)
+ var_ := typecheck.Temp(t)
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, var_, nil)) // zero temp
r := ir.NewSliceExpr(base.Pos, ir.OSLICE, var_) // arr[:l]
r.SetSliceBounds(nil, l, nil)
// The conv is necessary in case n.Type is named.
- return walkexpr(typecheck(conv(r, n.Type()), ctxExpr), init)
+ return walkexpr(typecheck.Expr(typecheck.Conv(r, n.Type())), init)
}
// n escapes; set up a call to makeslice.
m := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
m.SetType(t)
- fn := syslook(fnname)
- m.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), conv(len, argtype), conv(cap, argtype))
+ fn := typecheck.LookupRuntime(fnname)
+ m.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), typecheck.Conv(len, argtype), typecheck.Conv(cap, argtype))
m.Ptr.MarkNonNil()
- m.LenCap = []ir.Node{conv(len, types.Types[types.TINT]), conv(cap, types.Types[types.TINT])}
- return walkexpr(typecheck(m, ctxExpr), init)
+ m.LenCap = []ir.Node{typecheck.Conv(len, types.Types[types.TINT]), typecheck.Conv(cap, types.Types[types.TINT])}
+ return walkexpr(typecheck.Expr(m), init)
case ir.OMAKESLICECOPY:
n := n.(*ir.MakeExpr)
base.Errorf("%v can't be allocated in Go; it is incomplete (or unallocatable)", t.Elem())
}
- length := conv(n.Len, types.Types[types.TINT])
+ length := typecheck.Conv(n.Len, types.Types[types.TINT])
copylen := ir.NewUnaryExpr(base.Pos, ir.OLEN, n.Cap)
copyptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, n.Cap)
// We do not check for overflow of len(to)*elem.Width here
// since len(from) is an existing checked slice capacity
// with same elem.Width for the from slice.
- size := ir.NewBinaryExpr(base.Pos, ir.OMUL, conv(length, types.Types[types.TUINTPTR]), conv(ir.NewInt(t.Elem().Width), types.Types[types.TUINTPTR]))
+ size := ir.NewBinaryExpr(base.Pos, ir.OMUL, typecheck.Conv(length, types.Types[types.TUINTPTR]), typecheck.Conv(ir.NewInt(t.Elem().Width), types.Types[types.TUINTPTR]))
// instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
- fn := syslook("mallocgc")
+ fn := typecheck.LookupRuntime("mallocgc")
sh := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
- sh.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, nodnil(), ir.NewBool(false))
+ sh.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, size, typecheck.NodNil(), ir.NewBool(false))
sh.Ptr.MarkNonNil()
sh.LenCap = []ir.Node{length, length}
sh.SetType(t)
- s := temp(t)
- r := typecheck(ir.NewAssignStmt(base.Pos, s, sh), ctxStmt)
+ s := typecheck.Temp(t)
+ r := typecheck.Stmt(ir.NewAssignStmt(base.Pos, s, sh))
r = walkexpr(r, init)
init.Append(r)
// instantiate memmove(to *any, frm *any, size uintptr)
- fn = syslook("memmove")
- fn = substArgTypes(fn, t.Elem(), t.Elem())
+ fn = typecheck.LookupRuntime("memmove")
+ fn = typecheck.SubstArgTypes(fn, t.Elem(), t.Elem())
ncopy := mkcall1(fn, nil, init, ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), copyptr, size)
- init.Append(walkexpr(typecheck(ncopy, ctxStmt), init))
+ init.Append(walkexpr(typecheck.Stmt(ncopy), init))
return s
}
// Replace make+copy with runtime.makeslicecopy.
// instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
- fn := syslook("makeslicecopy")
+ fn := typecheck.LookupRuntime("makeslicecopy")
s := ir.NewSliceHeaderExpr(base.Pos, nil, nil, nil, nil)
- s.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[types.TUNSAFEPTR]))
+ s.Ptr = mkcall1(fn, types.Types[types.TUNSAFEPTR], init, typename(t.Elem()), length, copylen, typecheck.Conv(copyptr, types.Types[types.TUNSAFEPTR]))
s.Ptr.MarkNonNil()
s.LenCap = []ir.Node{length, length}
s.SetType(t)
- return walkexpr(typecheck(s, ctxExpr), init)
+ return walkexpr(typecheck.Expr(s), init)
case ir.ORUNESTR:
n := n.(*ir.ConvExpr)
- a := nodnil()
+ a := typecheck.NodNil()
if n.Esc() == ir.EscNone {
t := types.NewArray(types.Types[types.TUINT8], 4)
- a = nodAddr(temp(t))
+ a = typecheck.NodAddr(typecheck.Temp(t))
}
// intstring(*[4]byte, rune)
- return mkcall("intstring", n.Type(), init, a, conv(n.X, types.Types[types.TINT64]))
+ return mkcall("intstring", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TINT64]))
case ir.OBYTES2STR, ir.ORUNES2STR:
n := n.(*ir.ConvExpr)
- a := nodnil()
+ a := typecheck.NodNil()
if n.Esc() == ir.EscNone {
// Create temporary buffer for string on stack.
t := types.NewArray(types.Types[types.TUINT8], tmpstringbufsize)
- a = nodAddr(temp(t))
+ a = typecheck.NodAddr(typecheck.Temp(t))
}
if n.Op() == ir.ORUNES2STR {
// slicerunetostring(*[32]byte, []rune) string
t := types.NewArray(types.Types[types.TUINT8], int64(len(sc)))
var a ir.Node
if n.Esc() == ir.EscNone && len(sc) <= int(ir.MaxImplicitStackVarSize) {
- a = nodAddr(temp(t))
+ a = typecheck.NodAddr(typecheck.Temp(t))
} else {
a = callnew(t)
}
- p := temp(t.PtrTo()) // *[n]byte
- init.Append(typecheck(ir.NewAssignStmt(base.Pos, p, a), ctxStmt))
+ p := typecheck.Temp(t.PtrTo()) // *[n]byte
+ init.Append(typecheck.Stmt(ir.NewAssignStmt(base.Pos, p, a)))
// Copy from the static string data to the [n]byte.
if len(sc) > 0 {
- as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, convnop(ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), t.PtrTo())))
+ as := ir.NewAssignStmt(base.Pos, ir.NewStarExpr(base.Pos, p), ir.NewStarExpr(base.Pos, typecheck.ConvNop(ir.NewUnaryExpr(base.Pos, ir.OSPTR, s), t.PtrTo())))
appendWalkStmt(init, as)
}
return walkexpr(slice, init)
}
- a := nodnil()
+ a := typecheck.NodNil()
if n.Esc() == ir.EscNone {
// Create temporary buffer for slice on stack.
t := types.NewArray(types.Types[types.TUINT8], tmpstringbufsize)
- a = nodAddr(temp(t))
+ a = typecheck.NodAddr(typecheck.Temp(t))
}
// stringtoslicebyte(*32[byte], string) []byte
- return mkcall("stringtoslicebyte", n.Type(), init, a, conv(s, types.Types[types.TSTRING]))
+ return mkcall("stringtoslicebyte", n.Type(), init, a, typecheck.Conv(s, types.Types[types.TSTRING]))
case ir.OSTR2BYTESTMP:
// []byte(string) conversion that creates a slice
case ir.OSTR2RUNES:
n := n.(*ir.ConvExpr)
- a := nodnil()
+ a := typecheck.NodNil()
if n.Esc() == ir.EscNone {
// Create temporary buffer for slice on stack.
t := types.NewArray(types.Types[types.TINT32], tmpstringbufsize)
- a = nodAddr(temp(t))
+ a = typecheck.NodAddr(typecheck.Temp(t))
}
// stringtoslicerune(*[32]rune, string) []rune
- return mkcall("stringtoslicerune", n.Type(), init, a, conv(n.X, types.Types[types.TSTRING]))
+ return mkcall("stringtoslicerune", n.Type(), init, a, typecheck.Conv(n.X, types.Types[types.TSTRING]))
case ir.OARRAYLIT, ir.OSLICELIT, ir.OMAPLIT, ir.OSTRUCTLIT, ir.OPTRLIT:
if isStaticCompositeLiteral(n) && !canSSAType(n.Type()) {
// Make direct reference to the static data. See issue 12841.
vstat := readonlystaticname(n.Type())
fixedlit(inInitFunction, initKindStatic, n, vstat, init)
- return typecheck(vstat, ctxExpr)
+ return typecheck.Expr(vstat)
}
- var_ := temp(n.Type())
+ var_ := typecheck.Temp(n.Type())
anylit(n, var_, init)
return var_
case ir.OSEND:
n := n.(*ir.SendStmt)
n1 := n.Value
- n1 = assignconv(n1, n.Chan.Type().Elem(), "chan send")
+ n1 = typecheck.AssignConv(n1, n.Chan.Type().Elem(), "chan send")
n1 = walkexpr(n1, init)
- n1 = nodAddr(n1)
+ n1 = typecheck.NodAddr(n1)
return mkcall1(chanfn("chansend1", 2, n.Chan.Type()), nil, init, n.Chan, n1)
case ir.OCLOSURE:
// Any assignment to an lvalue that might cause a function call must be
// deferred until all the returned values have been read.
if fncall(l, r.Type) {
- tmp := ir.Node(temp(r.Type))
- tmp = typecheck(tmp, ctxExpr)
+ tmp := ir.Node(typecheck.Temp(r.Type))
+ tmp = typecheck.Expr(tmp)
a := convas(ir.NewAssignStmt(base.Pos, l, tmp), &mm)
mm.Append(a)
l = tmp
return append(nn, mm...)
}
-// package all the arguments that match a ... T parameter into a []T.
-func mkdotargslice(typ *types.Type, args []ir.Node) ir.Node {
- var n ir.Node
- if len(args) == 0 {
- n = nodnil()
- n.SetType(typ)
- } else {
- lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
- lit.List.Append(args...)
- lit.SetImplicit(true)
- n = lit
- }
-
- n = typecheck(n, ctxExpr)
- if n.Type() == nil {
- base.Fatalf("mkdotargslice: typecheck failed")
- }
- return n
-}
-
-// fixVariadicCall rewrites calls to variadic functions to use an
-// explicit ... argument if one is not already present.
-func fixVariadicCall(call *ir.CallExpr) {
- fntype := call.X.Type()
- if !fntype.IsVariadic() || call.IsDDD {
- return
- }
-
- vi := fntype.NumParams() - 1
- vt := fntype.Params().Field(vi).Type
-
- args := call.Args
- extra := args[vi:]
- slice := mkdotargslice(vt, extra)
- for i := range extra {
- extra[i] = nil // allow GC
- }
-
- call.Args.Set(append(args[:vi], slice))
- call.IsDDD = true
-}
-
func walkCall(n *ir.CallExpr, init *ir.Nodes) {
if len(n.Rargs) != 0 {
return // already walked
}
if base.Flag.Cfg.Instrumenting || fncall(arg, t) {
// make assignment of fncall to tempAt
- tmp := temp(t)
+ tmp := typecheck.Temp(t)
a := convas(ir.NewAssignStmt(base.Pos, tmp, arg), init)
tempAssigns = append(tempAssigns, a)
// replace arg with temp
for i, n := range nn.Args {
if n.Op() == ir.OLITERAL {
if n.Type() == types.UntypedRune {
- n = defaultlit(n, types.RuneType)
+ n = typecheck.DefaultLit(n, types.RuneType)
}
switch n.Val().Kind() {
case constant.Int:
- n = defaultlit(n, types.Types[types.TINT64])
+ n = typecheck.DefaultLit(n, types.Types[types.TINT64])
case constant.Float:
- n = defaultlit(n, types.Types[types.TFLOAT64])
+ n = typecheck.DefaultLit(n, types.Types[types.TFLOAT64])
}
}
if n.Op() != ir.OLITERAL && n.Type() != nil && n.Type().Kind() == types.TIDEAL {
- n = defaultlit(n, types.Types[types.TINT64])
+ n = typecheck.DefaultLit(n, types.Types[types.TINT64])
}
- n = defaultlit(n, nil)
+ n = typecheck.DefaultLit(n, nil)
nn.Args[i] = n
if n.Type() == nil || n.Type().Kind() == types.TFORW {
continue
switch n.Type().Kind() {
case types.TINTER:
if n.Type().IsEmptyInterface() {
- on = syslook("printeface")
+ on = typecheck.LookupRuntime("printeface")
} else {
- on = syslook("printiface")
+ on = typecheck.LookupRuntime("printiface")
}
- on = substArgTypes(on, n.Type()) // any-1
+ on = typecheck.SubstArgTypes(on, n.Type()) // any-1
case types.TPTR:
if n.Type().Elem().NotInHeap() {
- on = syslook("printuintptr")
+ on = typecheck.LookupRuntime("printuintptr")
n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
n.SetType(types.Types[types.TUNSAFEPTR])
n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
}
fallthrough
case types.TCHAN, types.TMAP, types.TFUNC, types.TUNSAFEPTR:
- on = syslook("printpointer")
- on = substArgTypes(on, n.Type()) // any-1
+ on = typecheck.LookupRuntime("printpointer")
+ on = typecheck.SubstArgTypes(on, n.Type()) // any-1
case types.TSLICE:
- on = syslook("printslice")
- on = substArgTypes(on, n.Type()) // any-1
+ on = typecheck.LookupRuntime("printslice")
+ on = typecheck.SubstArgTypes(on, n.Type()) // any-1
case types.TUINT, types.TUINT8, types.TUINT16, types.TUINT32, types.TUINT64, types.TUINTPTR:
if types.IsRuntimePkg(n.Type().Sym().Pkg) && n.Type().Sym().Name == "hex" {
- on = syslook("printhex")
+ on = typecheck.LookupRuntime("printhex")
} else {
- on = syslook("printuint")
+ on = typecheck.LookupRuntime("printuint")
}
case types.TINT, types.TINT8, types.TINT16, types.TINT32, types.TINT64:
- on = syslook("printint")
+ on = typecheck.LookupRuntime("printint")
case types.TFLOAT32, types.TFLOAT64:
- on = syslook("printfloat")
+ on = typecheck.LookupRuntime("printfloat")
case types.TCOMPLEX64, types.TCOMPLEX128:
- on = syslook("printcomplex")
+ on = typecheck.LookupRuntime("printcomplex")
case types.TBOOL:
- on = syslook("printbool")
+ on = typecheck.LookupRuntime("printbool")
case types.TSTRING:
cs := ""
if ir.IsConst(n, constant.String) {
}
switch cs {
case " ":
- on = syslook("printsp")
+ on = typecheck.LookupRuntime("printsp")
case "\n":
- on = syslook("printnl")
+ on = typecheck.LookupRuntime("printnl")
default:
- on = syslook("printstring")
+ on = typecheck.LookupRuntime("printstring")
}
default:
badtype(ir.OPRINT, n.Type(), nil)
calls = append(calls, mkcall("printunlock", nil, init))
- typecheckslice(calls, ctxStmt)
+ typecheck.Stmts(calls)
walkexprlist(calls, init)
r := ir.NewBlockStmt(base.Pos, nil)
r.List.Set(calls)
- return walkstmt(typecheck(r, ctxStmt))
+ return walkstmt(typecheck.Stmt(r))
}
func callnew(t *types.Type) ir.Node {
}
if ir.IsBlank(n.X) {
- n.Y = defaultlit(n.Y, nil)
+ n.Y = typecheck.DefaultLit(n.Y, nil)
return n
}
if !types.Identical(lt, rt) {
- n.Y = assignconv(n.Y, lt, "assignment")
+ n.Y = typecheck.AssignConv(n.Y, lt, "assignment")
n.Y = walkexpr(n.Y, init)
}
types.CalcSize(n.Y.Type())
return n
}
- q := ir.Node(temp(n.Type()))
- as := typecheck(ir.NewAssignStmt(base.Pos, q, n), ctxStmt)
+ q := ir.Node(typecheck.Temp(n.Type()))
+ as := typecheck.Stmt(ir.NewAssignStmt(base.Pos, q, n))
*early = append(*early, as)
return q
}
if stackcopy := v.Name().Stackcopy; stackcopy != nil {
nn = append(nn, walkstmt(ir.NewDecl(base.Pos, ir.ODCL, v)))
if stackcopy.Class_ == ir.PPARAM {
- nn = append(nn, walkstmt(typecheck(ir.NewAssignStmt(base.Pos, v, stackcopy), ctxStmt)))
+ nn = append(nn, walkstmt(typecheck.Stmt(ir.NewAssignStmt(base.Pos, v, stackcopy))))
}
}
}
continue
}
if stackcopy := v.Name().Stackcopy; stackcopy != nil && stackcopy.Class_ == ir.PPARAMOUT {
- nn = append(nn, walkstmt(typecheck(ir.NewAssignStmt(base.Pos, stackcopy, v), ctxStmt)))
+ nn = append(nn, walkstmt(typecheck.Stmt(ir.NewAssignStmt(base.Pos, stackcopy, v))))
}
}
}
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, va)
- TypecheckCall(call)
+ typecheck.Call(call)
call.SetType(t)
return walkexpr(call, init).(*ir.CallExpr)
}
func mkcall(name string, t *types.Type, init *ir.Nodes, args ...ir.Node) *ir.CallExpr {
- return vmkcall(syslook(name), t, init, args)
+ return vmkcall(typecheck.LookupRuntime(name), t, init, args)
}
func mkcall1(fn ir.Node, t *types.Type, init *ir.Nodes, args ...ir.Node) *ir.CallExpr {
return vmkcall(fn, t, init, args)
}
-func conv(n ir.Node, t *types.Type) ir.Node {
- if types.Identical(n.Type(), t) {
- return n
- }
- n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
- n.SetType(t)
- n = typecheck(n, ctxExpr)
- return n
-}
-
-// convnop converts node n to type t using the OCONVNOP op
-// and typechecks the result with ctxExpr.
-func convnop(n ir.Node, t *types.Type) ir.Node {
- if types.Identical(n.Type(), t) {
- return n
- }
- n = ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n)
- n.SetType(t)
- n = typecheck(n, ctxExpr)
- return n
-}
-
// byteindex converts n, which is byte-sized, to an int used to index into an array.
// We cannot use conv, because we allow converting bool to int here,
// which is forbidden in user code.
if !t.IsChan() {
base.Fatalf("chanfn %v", t)
}
- fn := syslook(name)
+ fn := typecheck.LookupRuntime(name)
switch n {
default:
base.Fatalf("chanfn %d", n)
case 1:
- fn = substArgTypes(fn, t.Elem())
+ fn = typecheck.SubstArgTypes(fn, t.Elem())
case 2:
- fn = substArgTypes(fn, t.Elem(), t.Elem())
+ fn = typecheck.SubstArgTypes(fn, t.Elem(), t.Elem())
}
return fn
}
if !t.IsMap() {
base.Fatalf("mapfn %v", t)
}
- fn := syslook(name)
- fn = substArgTypes(fn, t.Key(), t.Elem(), t.Key(), t.Elem())
+ fn := typecheck.LookupRuntime(name)
+ fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), t.Key(), t.Elem())
return fn
}
if !t.IsMap() {
base.Fatalf("mapfn %v", t)
}
- fn := syslook(name)
- fn = substArgTypes(fn, t.Key(), t.Elem(), t.Key())
+ fn := typecheck.LookupRuntime(name)
+ fn = typecheck.SubstArgTypes(fn, t.Key(), t.Elem(), t.Key())
return fn
}
}
func writebarrierfn(name string, l *types.Type, r *types.Type) ir.Node {
- fn := syslook(name)
- fn = substArgTypes(fn, l, r)
+ fn := typecheck.LookupRuntime(name)
+ fn = typecheck.SubstArgTypes(fn, l, r)
return fn
}
base.Fatalf("addstr count %d too small", c)
}
- buf := nodnil()
+ buf := typecheck.NodNil()
if n.Esc() == ir.EscNone {
sz := int64(0)
for _, n1 := range n.List {
if sz < tmpstringbufsize {
// Create temporary buffer for result string on stack.
t := types.NewArray(types.Types[types.TUINT8], tmpstringbufsize)
- buf = nodAddr(temp(t))
+ buf = typecheck.NodAddr(typecheck.Temp(t))
}
}
// build list of string arguments
args := []ir.Node{buf}
for _, n2 := range n.List {
- args = append(args, conv(n2, types.Types[types.TSTRING]))
+ args = append(args, typecheck.Conv(n2, types.Types[types.TSTRING]))
}
var fn string
slice.SetEsc(ir.EscNone)
}
- cat := syslook(fn)
+ cat := typecheck.LookupRuntime(fn)
r := ir.NewCallExpr(base.Pos, ir.OCALL, cat, nil)
r.Args.Set(args)
- r1 := typecheck(r, ctxExpr)
+ r1 := typecheck.Expr(r)
r1 = walkexpr(r1, init)
r1.SetType(n.Type())
var nodes ir.Nodes
// var s []T
- s := temp(l1.Type())
+ s := typecheck.Temp(l1.Type())
nodes.Append(ir.NewAssignStmt(base.Pos, s, l1)) // s = l1
elemtype := s.Type().Elem()
// n := len(s) + len(l2)
- nn := temp(types.Types[types.TINT])
+ nn := typecheck.Temp(types.Types[types.TINT])
nodes.Append(ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), ir.NewUnaryExpr(base.Pos, ir.OLEN, l2))))
// if uint(n) > uint(cap(s))
nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
- nuint := conv(nn, types.Types[types.TUINT])
- scapuint := conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT])
+ nuint := typecheck.Conv(nn, types.Types[types.TUINT])
+ scapuint := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT])
nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, nuint, scapuint)
// instantiate growslice(typ *type, []any, int) []any
- fn := syslook("growslice")
- fn = substArgTypes(fn, elemtype, elemtype)
+ fn := typecheck.LookupRuntime("growslice")
+ fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
// s = growslice(T, s, n)
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn))}
ir.CurFunc.SetWBPos(n.Pos())
// instantiate typedslicecopy(typ *type, dstPtr *any, dstLen int, srcPtr *any, srcLen int) int
- fn := syslook("typedslicecopy")
- fn = substArgTypes(fn, l1.Type().Elem(), l2.Type().Elem())
+ fn := typecheck.LookupRuntime("typedslicecopy")
+ fn = typecheck.SubstArgTypes(fn, l1.Type().Elem(), l2.Type().Elem())
ptr1, len1 := backingArrayPtrLen(cheapexpr(slice, &nodes))
ptr2, len2 := backingArrayPtrLen(l2)
ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, typename(elemtype), ptr1, len1, ptr2, len2)
ptr1, len1 := backingArrayPtrLen(cheapexpr(slice, &nodes))
ptr2, len2 := backingArrayPtrLen(l2)
- fn := syslook("slicecopy")
- fn = substArgTypes(fn, ptr1.Type().Elem(), ptr2.Type().Elem())
+ fn := typecheck.LookupRuntime("slicecopy")
+ fn = typecheck.SubstArgTypes(fn, ptr1.Type().Elem(), ptr2.Type().Elem())
ncopy = mkcall1(fn, types.Types[types.TINT], &nodes, ptr1, len1, ptr2, len2, ir.NewInt(elemtype.Width))
} else {
// memmove(&s[len(l1)], &l2[0], len(l2)*sizeof(T))
ix := ir.NewIndexExpr(base.Pos, s, ir.NewUnaryExpr(base.Pos, ir.OLEN, l1))
ix.SetBounded(true)
- addr := nodAddr(ix)
+ addr := typecheck.NodAddr(ix)
sptr := ir.NewUnaryExpr(base.Pos, ir.OSPTR, l2)
- nwid := cheapexpr(conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, l2), types.Types[types.TUINTPTR]), &nodes)
+ nwid := cheapexpr(typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OLEN, l2), types.Types[types.TUINTPTR]), &nodes)
nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(elemtype.Width))
// instantiate func memmove(to *any, frm *any, length uintptr)
- fn := syslook("memmove")
- fn = substArgTypes(fn, elemtype, elemtype)
+ fn := typecheck.LookupRuntime("memmove")
+ fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
ncopy = mkcall1(fn, nil, &nodes, addr, sptr, nwid)
}
ln := append(nodes, ncopy)
- typecheckslice(ln, ctxStmt)
+ typecheck.Stmts(ln)
walkstmtlist(ln)
init.Append(ln...)
return s
// isAppendOfMake made sure all possible positive values of l2 fit into an uint.
// The case of l2 overflow when converting from e.g. uint to int is handled by an explicit
// check of l2 < 0 at runtime which is generated below.
- l2 := conv(n.Args[1].(*ir.MakeExpr).Len, types.Types[types.TINT])
- l2 = typecheck(l2, ctxExpr)
+ l2 := typecheck.Conv(n.Args[1].(*ir.MakeExpr).Len, types.Types[types.TINT])
+ l2 = typecheck.Expr(l2)
n.Args[1] = l2 // walkAppendArgs expects l2 in n.List.Second().
walkAppendArgs(n, init)
nodes = append(nodes, nifneg)
// s := l1
- s := temp(l1.Type())
+ s := typecheck.Temp(l1.Type())
nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, l1))
elemtype := s.Type().Elem()
// n := len(s) + l2
- nn := temp(types.Types[types.TINT])
+ nn := typecheck.Temp(types.Types[types.TINT])
nodes = append(nodes, ir.NewAssignStmt(base.Pos, nn, ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, s), l2)))
// if uint(n) > uint(cap(s))
- nuint := conv(nn, types.Types[types.TUINT])
- capuint := conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT])
+ nuint := typecheck.Conv(nn, types.Types[types.TUINT])
+ capuint := typecheck.Conv(ir.NewUnaryExpr(base.Pos, ir.OCAP, s), types.Types[types.TUINT])
nif := ir.NewIfStmt(base.Pos, ir.NewBinaryExpr(base.Pos, ir.OGT, nuint, capuint), nil, nil)
// instantiate growslice(typ *type, old []any, newcap int) []any
- fn := syslook("growslice")
- fn = substArgTypes(fn, elemtype, elemtype)
+ fn := typecheck.LookupRuntime("growslice")
+ fn = typecheck.SubstArgTypes(fn, elemtype, elemtype)
// s = growslice(T, s, n)
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, s, mkcall1(fn, s.Type(), nif.PtrInit(), typename(elemtype), s, nn))}
nodes = append(nodes, ir.NewAssignStmt(base.Pos, s, nt))
// lptr := &l1[0]
- l1ptr := temp(l1.Type().Elem().PtrTo())
+ l1ptr := typecheck.Temp(l1.Type().Elem().PtrTo())
tmp := ir.NewUnaryExpr(base.Pos, ir.OSPTR, l1)
nodes = append(nodes, ir.NewAssignStmt(base.Pos, l1ptr, tmp))
// sptr := &s[0]
- sptr := temp(elemtype.PtrTo())
+ sptr := typecheck.Temp(elemtype.PtrTo())
tmp = ir.NewUnaryExpr(base.Pos, ir.OSPTR, s)
nodes = append(nodes, ir.NewAssignStmt(base.Pos, sptr, tmp))
// hp := &s[len(l1)]
ix := ir.NewIndexExpr(base.Pos, s, ir.NewUnaryExpr(base.Pos, ir.OLEN, l1))
ix.SetBounded(true)
- hp := convnop(nodAddr(ix), types.Types[types.TUNSAFEPTR])
+ hp := typecheck.ConvNop(typecheck.NodAddr(ix), types.Types[types.TUNSAFEPTR])
// hn := l2 * sizeof(elem(s))
- hn := conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, l2, ir.NewInt(elemtype.Width)), types.Types[types.TUINTPTR])
+ hn := typecheck.Conv(ir.NewBinaryExpr(base.Pos, ir.OMUL, l2, ir.NewInt(elemtype.Width)), types.Types[types.TUINTPTR])
clrname := "memclrNoHeapPointers"
hasPointers := elemtype.HasPointers()
nodes = append(nodes, clr...)
}
- typecheckslice(nodes, ctxStmt)
+ typecheck.Stmts(nodes)
walkstmtlist(nodes)
init.Append(nodes...)
return s
for i, n := range ls {
n = cheapexpr(n, init)
if !types.Identical(n.Type(), nsrc.Type().Elem()) {
- n = assignconv(n, nsrc.Type().Elem(), "append")
+ n = typecheck.AssignConv(n, nsrc.Type().Elem(), "append")
n = walkexpr(n, init)
}
ls[i] = n
var l []ir.Node
- ns := temp(nsrc.Type())
+ ns := typecheck.Temp(nsrc.Type())
l = append(l, ir.NewAssignStmt(base.Pos, ns, nsrc)) // s = src
na := ir.NewInt(int64(argc)) // const argc
nif := ir.NewIfStmt(base.Pos, nil, nil, nil) // if cap(s) - len(s) < argc
nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, ir.NewBinaryExpr(base.Pos, ir.OSUB, ir.NewUnaryExpr(base.Pos, ir.OCAP, ns), ir.NewUnaryExpr(base.Pos, ir.OLEN, ns)), na)
- fn := syslook("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
- fn = substArgTypes(fn, ns.Type().Elem(), ns.Type().Elem())
+ fn := typecheck.LookupRuntime("growslice") // growslice(<type>, old []T, mincap int) (ret []T)
+ fn = typecheck.SubstArgTypes(fn, ns.Type().Elem(), ns.Type().Elem())
nif.Body = []ir.Node{ir.NewAssignStmt(base.Pos, ns, mkcall1(fn, ns.Type(), nif.PtrInit(), typename(ns.Type().Elem()), ns,
ir.NewBinaryExpr(base.Pos, ir.OADD, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns), na)))}
l = append(l, nif)
- nn := temp(types.Types[types.TINT])
+ nn := typecheck.Temp(types.Types[types.TINT])
l = append(l, ir.NewAssignStmt(base.Pos, nn, ir.NewUnaryExpr(base.Pos, ir.OLEN, ns))) // n = len(s)
slice := ir.NewSliceExpr(base.Pos, ir.OSLICE, ns) // ...s[:n+argc]
}
}
- typecheckslice(l, ctxStmt)
+ typecheck.Stmts(l)
walkstmtlist(l)
init.Append(l...)
return ns
n.Y = cheapexpr(n.Y, init)
ptrR, lenR := backingArrayPtrLen(n.Y)
- fn := syslook("slicecopy")
- fn = substArgTypes(fn, ptrL.Type().Elem(), ptrR.Type().Elem())
+ fn := typecheck.LookupRuntime("slicecopy")
+ fn = typecheck.SubstArgTypes(fn, ptrL.Type().Elem(), ptrR.Type().Elem())
return mkcall1(fn, n.Type(), init, ptrL, lenL, ptrR, lenR, ir.NewInt(n.X.Type().Elem().Width))
}
n.X = walkexpr(n.X, init)
n.Y = walkexpr(n.Y, init)
- nl := temp(n.X.Type())
- nr := temp(n.Y.Type())
+ nl := typecheck.Temp(n.X.Type())
+ nr := typecheck.Temp(n.Y.Type())
var l []ir.Node
l = append(l, ir.NewAssignStmt(base.Pos, nl, n.X))
l = append(l, ir.NewAssignStmt(base.Pos, nr, n.Y))
nfrm := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nr)
nto := ir.NewUnaryExpr(base.Pos, ir.OSPTR, nl)
- nlen := temp(types.Types[types.TINT])
+ nlen := typecheck.Temp(types.Types[types.TINT])
// n = len(to)
l = append(l, ir.NewAssignStmt(base.Pos, nlen, ir.NewUnaryExpr(base.Pos, ir.OLEN, nl)))
ne.Likely = true
l = append(l, ne)
- fn := syslook("memmove")
- fn = substArgTypes(fn, nl.Type().Elem(), nl.Type().Elem())
- nwid := ir.Node(temp(types.Types[types.TUINTPTR]))
- setwid := ir.NewAssignStmt(base.Pos, nwid, conv(nlen, types.Types[types.TUINTPTR]))
+ fn := typecheck.LookupRuntime("memmove")
+ fn = typecheck.SubstArgTypes(fn, nl.Type().Elem(), nl.Type().Elem())
+ nwid := ir.Node(typecheck.Temp(types.Types[types.TUINTPTR]))
+ setwid := ir.NewAssignStmt(base.Pos, nwid, typecheck.Conv(nlen, types.Types[types.TUINTPTR]))
ne.Body.Append(setwid)
nwid = ir.NewBinaryExpr(base.Pos, ir.OMUL, nwid, ir.NewInt(nl.Type().Elem().Width))
call := mkcall1(fn, nil, init, nto, nfrm, nwid)
ne.Body.Append(call)
- typecheckslice(l, ctxStmt)
+ typecheck.Stmts(l)
walkstmtlist(l)
init.Append(l...)
return nlen
// is handled by walkcompare.
switch a, _ := types.AlgType(t); a {
case types.AMEM:
- n := syslook("memequal")
- n = substArgTypes(n, t, t)
+ n := typecheck.LookupRuntime("memequal")
+ n = typecheck.SubstArgTypes(n, t, t)
return n, true
case types.ASPECIAL:
sym := typesymprefix(".eq", t)
- n := NewName(sym)
+ n := typecheck.NewName(sym)
ir.MarkFunc(n)
- n.SetType(functype(nil, []*ir.Field{
+ n.SetType(typecheck.NewFuncType(nil, []*ir.Field{
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
ir.NewField(base.Pos, nil, nil, types.NewPtr(t)),
}, []*ir.Field{
tab.SetTypecheck(1)
eqtype = ir.NewBinaryExpr(base.Pos, eq, tab, rtyp)
} else {
- nonnil := ir.NewBinaryExpr(base.Pos, brcom(eq), nodnil(), tab)
+ nonnil := ir.NewBinaryExpr(base.Pos, brcom(eq), typecheck.NodNil(), tab)
match := ir.NewBinaryExpr(base.Pos, eq, itabType(tab), rtyp)
eqtype = ir.NewLogicalExpr(base.Pos, andor, nonnil, match)
}
fn, needsize := eqfor(t)
call := ir.NewCallExpr(base.Pos, ir.OCALL, fn, nil)
- call.Args.Append(nodAddr(cmpl))
- call.Args.Append(nodAddr(cmpr))
+ call.Args.Append(typecheck.NodAddr(cmpl))
+ call.Args.Append(typecheck.NodAddr(cmpr))
if needsize {
call.Args.Append(ir.NewInt(t.Width))
}
} else {
elemType := t.Elem().ToUnsigned()
cmplw := ir.Node(ir.NewIndexExpr(base.Pos, cmpl, ir.NewInt(i)))
- cmplw = conv(cmplw, elemType) // convert to unsigned
- cmplw = conv(cmplw, convType) // widen
+ cmplw = typecheck.Conv(cmplw, elemType) // convert to unsigned
+ cmplw = typecheck.Conv(cmplw, convType) // widen
cmprw := ir.Node(ir.NewIndexExpr(base.Pos, cmpr, ir.NewInt(i)))
- cmprw = conv(cmprw, elemType)
- cmprw = conv(cmprw, convType)
+ cmprw = typecheck.Conv(cmprw, elemType)
+ cmprw = typecheck.Conv(cmprw, convType)
// For code like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
// ssa will generate a single large load.
for offset := int64(1); offset < step; offset++ {
lb := ir.Node(ir.NewIndexExpr(base.Pos, cmpl, ir.NewInt(i+offset)))
- lb = conv(lb, elemType)
- lb = conv(lb, convType)
+ lb = typecheck.Conv(lb, elemType)
+ lb = typecheck.Conv(lb, convType)
lb = ir.NewBinaryExpr(base.Pos, ir.OLSH, lb, ir.NewInt(8*t.Elem().Width*offset))
cmplw = ir.NewBinaryExpr(base.Pos, ir.OOR, cmplw, lb)
rb := ir.Node(ir.NewIndexExpr(base.Pos, cmpr, ir.NewInt(i+offset)))
- rb = conv(rb, elemType)
- rb = conv(rb, convType)
+ rb = typecheck.Conv(rb, elemType)
+ rb = typecheck.Conv(rb, convType)
rb = ir.NewBinaryExpr(base.Pos, ir.OLSH, rb, ir.NewInt(8*t.Elem().Width*offset))
cmprw = ir.NewBinaryExpr(base.Pos, ir.OOR, cmprw, rb)
}
expr = ir.NewBool(n.Op() == ir.OEQ)
// We still need to use cmpl and cmpr, in case they contain
// an expression which might panic. See issue 23837.
- t := temp(cmpl.Type())
- a1 := typecheck(ir.NewAssignStmt(base.Pos, t, cmpl), ctxStmt)
- a2 := typecheck(ir.NewAssignStmt(base.Pos, t, cmpr), ctxStmt)
+ t := typecheck.Temp(cmpl.Type())
+ a1 := typecheck.Stmt(ir.NewAssignStmt(base.Pos, t, cmpl))
+ a2 := typecheck.Stmt(ir.NewAssignStmt(base.Pos, t, cmpr))
init.Append(a1, a2)
}
return finishcompare(n, expr, init)
n = copyexpr(n, n.Type(), init)
}
- return conv(n, t)
+ return typecheck.Conv(n, t)
}
func walkcompareInterface(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
convType = types.Types[types.TUINT16]
step = 2
}
- ncsubstr := conv(ir.NewIndexExpr(base.Pos, ncs, ir.NewInt(int64(i))), convType)
+ ncsubstr := typecheck.Conv(ir.NewIndexExpr(base.Pos, ncs, ir.NewInt(int64(i))), convType)
csubstr := int64(s[i])
// Calculate large constant from bytes as sequence of shifts and ors.
// Like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
// ssa will combine this into a single large load.
for offset := 1; offset < step; offset++ {
- b := conv(ir.NewIndexExpr(base.Pos, ncs, ir.NewInt(int64(i+offset))), convType)
+ b := typecheck.Conv(ir.NewIndexExpr(base.Pos, ncs, ir.NewInt(int64(i+offset))), convType)
b = ir.NewBinaryExpr(base.Pos, ir.OLSH, b, ir.NewInt(int64(8*offset)))
ncsubstr = ir.NewBinaryExpr(base.Pos, ir.OOR, ncsubstr, b)
csubstr |= int64(s[i+offset]) << uint8(8*offset)
}
} else {
// sys_cmpstring(s1, s2) :: 0
- r = mkcall("cmpstring", types.Types[types.TINT], init, conv(n.X, types.Types[types.TSTRING]), conv(n.Y, types.Types[types.TSTRING]))
+ r = mkcall("cmpstring", types.Types[types.TINT], init, typecheck.Conv(n.X, types.Types[types.TSTRING]), typecheck.Conv(n.Y, types.Types[types.TSTRING]))
r = ir.NewBinaryExpr(base.Pos, n.Op(), r, ir.NewInt(0))
}
// The result of finishcompare MUST be assigned back to n, e.g.
// n.Left = finishcompare(n.Left, x, r, init)
func finishcompare(n *ir.BinaryExpr, r ir.Node, init *ir.Nodes) ir.Node {
- r = typecheck(r, ctxExpr)
- r = conv(r, n.Type())
+ r = typecheck.Expr(r)
+ r = typecheck.Conv(r, n.Type())
r = walkexpr(r, init)
return r
}
origArgs := make([]ir.Node, len(n.Args))
var funcArgs []*ir.Field
for i, arg := range n.Args {
- s := lookupN("a", i)
+ s := typecheck.LookupNum("a", i)
if !isBuiltinCall && arg.Op() == ir.OCONVNOP && arg.Type().IsUintptr() && arg.(*ir.ConvExpr).X.Type().IsUnsafePtr() {
origArgs[i] = arg
arg = arg.(*ir.ConvExpr).X
t := ir.NewFuncType(base.Pos, nil, funcArgs, nil)
wrapCall_prgen++
- sym := lookupN("wrap·", wrapCall_prgen)
- fn := dclfunc(sym, t)
+ sym := typecheck.LookupNum("wrap·", wrapCall_prgen)
+ fn := typecheck.DeclFunc(sym, t)
args := ir.ParamNames(t.Type())
for i, origArg := range origArgs {
}
fn.Body = []ir.Node{call}
- funcbody()
+ typecheck.FinishFuncBody()
- typecheckFunc(fn)
- typecheckslice(fn.Body, ctxStmt)
- Target.Decls = append(Target.Decls, fn)
+ typecheck.Func(fn)
+ typecheck.Stmts(fn.Body)
+ typecheck.Target.Decls = append(typecheck.Target.Decls, fn)
call = ir.NewCallExpr(base.Pos, ir.OCALL, fn.Nname, n.Args)
- return walkexpr(typecheck(call, ctxStmt), init)
-}
-
-// substArgTypes substitutes the given list of types for
-// successive occurrences of the "any" placeholder in the
-// type syntax expression n.Type.
-// The result of substArgTypes MUST be assigned back to old, e.g.
-// n.Left = substArgTypes(n.Left, t1, t2)
-func substArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
- n := old.CloneName()
-
- for _, t := range types_ {
- types.CalcSize(t)
- }
- n.SetType(types.SubstAny(n.Type(), &types_))
- if len(types_) > 0 {
- base.Fatalf("substArgTypes: too many argument types")
- }
- return n
+ return walkexpr(typecheck.Stmt(call), init)
}
// canMergeLoads reports whether the backend optimization passes for
}
n.X = cheapexpr(n.X, init)
- init.Append(mkcall("checkptrAlignment", nil, init, convnop(n.X, types.Types[types.TUNSAFEPTR]), typename(elem), conv(count, types.Types[types.TUINTPTR])))
+ init.Append(mkcall("checkptrAlignment", nil, init, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]), typename(elem), typecheck.Conv(count, types.Types[types.TUINTPTR])))
return n
}
n := n.(*ir.ConvExpr)
if n.X.Type().IsUnsafePtr() {
n.X = cheapexpr(n.X, init)
- originals = append(originals, convnop(n.X, types.Types[types.TUNSAFEPTR]))
+ originals = append(originals, typecheck.ConvNop(n.X, types.Types[types.TUNSAFEPTR]))
}
}
}
cheap := cheapexpr(n, init)
- slice := mkdotargslice(types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
+ slice := typecheck.MakeDotArgs(types.NewSlice(types.Types[types.TUNSAFEPTR]), originals)
slice.SetEsc(ir.EscNone)
- init.Append(mkcall("checkptrArithmetic", nil, init, convnop(cheap, types.Types[types.TUNSAFEPTR]), slice))
+ init.Append(mkcall("checkptrArithmetic", nil, init, typecheck.ConvNop(cheap, types.Types[types.TUNSAFEPTR]), slice))
// TODO(khr): Mark backing store of slice as dead. This will allow us to reuse
// the backing store for multiple calls to checkptrArithmetic.
// appendWalkStmt typechecks and walks stmt and then appends it to init.
func appendWalkStmt(init *ir.Nodes, stmt ir.Node) {
op := stmt.Op()
- n := typecheck(stmt, ctxStmt)
+ n := typecheck.Stmt(stmt)
if op == ir.OAS || op == ir.OAS2 {
// If the assignment has side effects, walkexpr will append them
// directly to init for us, while walkstmt will wrap it in an OBLOCK.
--- /dev/null
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import "cmd/compile/internal/types"
+
+// ----------------------------------------------------------------------------
+// Export format
+
+// Tags. Must be < 0.
+const (
+ // Objects
+ packageTag = -(iota + 1)
+ constTag
+ typeTag
+ varTag
+ funcTag
+ endTag
+
+ // Types
+ namedTag
+ arrayTag
+ sliceTag
+ dddTag
+ structTag
+ pointerTag
+ signatureTag
+ interfaceTag
+ mapTag
+ chanTag
+
+ // Values
+ falseTag
+ trueTag
+ int64Tag
+ floatTag
+ fractionTag // not used by gc
+ complexTag
+ stringTag
+ nilTag
+ unknownTag // not used by gc (only appears in packages with errors)
+
+ // Type aliases
+ aliasTag
+)
+
+var predecl []*types.Type // initialized lazily
+
+func predeclared() []*types.Type {
+ if predecl == nil {
+ // initialize lazily to be sure that all
+ // elements have been initialized before
+ predecl = []*types.Type{
+ // basic types
+ types.Types[types.TBOOL],
+ types.Types[types.TINT],
+ types.Types[types.TINT8],
+ types.Types[types.TINT16],
+ types.Types[types.TINT32],
+ types.Types[types.TINT64],
+ types.Types[types.TUINT],
+ types.Types[types.TUINT8],
+ types.Types[types.TUINT16],
+ types.Types[types.TUINT32],
+ types.Types[types.TUINT64],
+ types.Types[types.TUINTPTR],
+ types.Types[types.TFLOAT32],
+ types.Types[types.TFLOAT64],
+ types.Types[types.TCOMPLEX64],
+ types.Types[types.TCOMPLEX128],
+ types.Types[types.TSTRING],
+
+ // basic type aliases
+ types.ByteType,
+ types.RuneType,
+
+ // error
+ types.ErrorType,
+
+ // untyped types
+ types.UntypedBool,
+ types.UntypedInt,
+ types.UntypedRune,
+ types.UntypedFloat,
+ types.UntypedComplex,
+ types.UntypedString,
+ types.Types[types.TNIL],
+
+ // package unsafe
+ types.Types[types.TUNSAFEPTR],
+
+ // invalid type (package contains errors)
+ types.Types[types.Txxx],
+
+ // any type, for builtin export data
+ types.Types[types.TANY],
+ }
+ }
+ return predecl
+}
--- /dev/null
+// Code generated by mkbuiltin.go. DO NOT EDIT.
+
+package typecheck
+
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+)
+
+var runtimeDecls = [...]struct {
+ name string
+ tag int
+ typ int
+}{
+ {"newobject", funcTag, 4},
+ {"mallocgc", funcTag, 8},
+ {"panicdivide", funcTag, 9},
+ {"panicshift", funcTag, 9},
+ {"panicmakeslicelen", funcTag, 9},
+ {"panicmakeslicecap", funcTag, 9},
+ {"throwinit", funcTag, 9},
+ {"panicwrap", funcTag, 9},
+ {"gopanic", funcTag, 11},
+ {"gorecover", funcTag, 14},
+ {"goschedguarded", funcTag, 9},
+ {"goPanicIndex", funcTag, 16},
+ {"goPanicIndexU", funcTag, 18},
+ {"goPanicSliceAlen", funcTag, 16},
+ {"goPanicSliceAlenU", funcTag, 18},
+ {"goPanicSliceAcap", funcTag, 16},
+ {"goPanicSliceAcapU", funcTag, 18},
+ {"goPanicSliceB", funcTag, 16},
+ {"goPanicSliceBU", funcTag, 18},
+ {"goPanicSlice3Alen", funcTag, 16},
+ {"goPanicSlice3AlenU", funcTag, 18},
+ {"goPanicSlice3Acap", funcTag, 16},
+ {"goPanicSlice3AcapU", funcTag, 18},
+ {"goPanicSlice3B", funcTag, 16},
+ {"goPanicSlice3BU", funcTag, 18},
+ {"goPanicSlice3C", funcTag, 16},
+ {"goPanicSlice3CU", funcTag, 18},
+ {"printbool", funcTag, 19},
+ {"printfloat", funcTag, 21},
+ {"printint", funcTag, 23},
+ {"printhex", funcTag, 25},
+ {"printuint", funcTag, 25},
+ {"printcomplex", funcTag, 27},
+ {"printstring", funcTag, 29},
+ {"printpointer", funcTag, 30},
+ {"printuintptr", funcTag, 31},
+ {"printiface", funcTag, 30},
+ {"printeface", funcTag, 30},
+ {"printslice", funcTag, 30},
+ {"printnl", funcTag, 9},
+ {"printsp", funcTag, 9},
+ {"printlock", funcTag, 9},
+ {"printunlock", funcTag, 9},
+ {"concatstring2", funcTag, 34},
+ {"concatstring3", funcTag, 35},
+ {"concatstring4", funcTag, 36},
+ {"concatstring5", funcTag, 37},
+ {"concatstrings", funcTag, 39},
+ {"cmpstring", funcTag, 40},
+ {"intstring", funcTag, 43},
+ {"slicebytetostring", funcTag, 44},
+ {"slicebytetostringtmp", funcTag, 45},
+ {"slicerunetostring", funcTag, 48},
+ {"stringtoslicebyte", funcTag, 50},
+ {"stringtoslicerune", funcTag, 53},
+ {"slicecopy", funcTag, 54},
+ {"decoderune", funcTag, 55},
+ {"countrunes", funcTag, 56},
+ {"convI2I", funcTag, 57},
+ {"convT16", funcTag, 58},
+ {"convT32", funcTag, 58},
+ {"convT64", funcTag, 58},
+ {"convTstring", funcTag, 58},
+ {"convTslice", funcTag, 58},
+ {"convT2E", funcTag, 59},
+ {"convT2Enoptr", funcTag, 59},
+ {"convT2I", funcTag, 59},
+ {"convT2Inoptr", funcTag, 59},
+ {"assertE2I", funcTag, 57},
+ {"assertE2I2", funcTag, 60},
+ {"assertI2I", funcTag, 57},
+ {"assertI2I2", funcTag, 60},
+ {"panicdottypeE", funcTag, 61},
+ {"panicdottypeI", funcTag, 61},
+ {"panicnildottype", funcTag, 62},
+ {"ifaceeq", funcTag, 64},
+ {"efaceeq", funcTag, 64},
+ {"fastrand", funcTag, 66},
+ {"makemap64", funcTag, 68},
+ {"makemap", funcTag, 69},
+ {"makemap_small", funcTag, 70},
+ {"mapaccess1", funcTag, 71},
+ {"mapaccess1_fast32", funcTag, 72},
+ {"mapaccess1_fast64", funcTag, 72},
+ {"mapaccess1_faststr", funcTag, 72},
+ {"mapaccess1_fat", funcTag, 73},
+ {"mapaccess2", funcTag, 74},
+ {"mapaccess2_fast32", funcTag, 75},
+ {"mapaccess2_fast64", funcTag, 75},
+ {"mapaccess2_faststr", funcTag, 75},
+ {"mapaccess2_fat", funcTag, 76},
+ {"mapassign", funcTag, 71},
+ {"mapassign_fast32", funcTag, 72},
+ {"mapassign_fast32ptr", funcTag, 72},
+ {"mapassign_fast64", funcTag, 72},
+ {"mapassign_fast64ptr", funcTag, 72},
+ {"mapassign_faststr", funcTag, 72},
+ {"mapiterinit", funcTag, 77},
+ {"mapdelete", funcTag, 77},
+ {"mapdelete_fast32", funcTag, 78},
+ {"mapdelete_fast64", funcTag, 78},
+ {"mapdelete_faststr", funcTag, 78},
+ {"mapiternext", funcTag, 79},
+ {"mapclear", funcTag, 80},
+ {"makechan64", funcTag, 82},
+ {"makechan", funcTag, 83},
+ {"chanrecv1", funcTag, 85},
+ {"chanrecv2", funcTag, 86},
+ {"chansend1", funcTag, 88},
+ {"closechan", funcTag, 30},
+ {"writeBarrier", varTag, 90},
+ {"typedmemmove", funcTag, 91},
+ {"typedmemclr", funcTag, 92},
+ {"typedslicecopy", funcTag, 93},
+ {"selectnbsend", funcTag, 94},
+ {"selectnbrecv", funcTag, 95},
+ {"selectnbrecv2", funcTag, 97},
+ {"selectsetpc", funcTag, 98},
+ {"selectgo", funcTag, 99},
+ {"block", funcTag, 9},
+ {"makeslice", funcTag, 100},
+ {"makeslice64", funcTag, 101},
+ {"makeslicecopy", funcTag, 102},
+ {"growslice", funcTag, 104},
+ {"memmove", funcTag, 105},
+ {"memclrNoHeapPointers", funcTag, 106},
+ {"memclrHasPointers", funcTag, 106},
+ {"memequal", funcTag, 107},
+ {"memequal0", funcTag, 108},
+ {"memequal8", funcTag, 108},
+ {"memequal16", funcTag, 108},
+ {"memequal32", funcTag, 108},
+ {"memequal64", funcTag, 108},
+ {"memequal128", funcTag, 108},
+ {"f32equal", funcTag, 109},
+ {"f64equal", funcTag, 109},
+ {"c64equal", funcTag, 109},
+ {"c128equal", funcTag, 109},
+ {"strequal", funcTag, 109},
+ {"interequal", funcTag, 109},
+ {"nilinterequal", funcTag, 109},
+ {"memhash", funcTag, 110},
+ {"memhash0", funcTag, 111},
+ {"memhash8", funcTag, 111},
+ {"memhash16", funcTag, 111},
+ {"memhash32", funcTag, 111},
+ {"memhash64", funcTag, 111},
+ {"memhash128", funcTag, 111},
+ {"f32hash", funcTag, 111},
+ {"f64hash", funcTag, 111},
+ {"c64hash", funcTag, 111},
+ {"c128hash", funcTag, 111},
+ {"strhash", funcTag, 111},
+ {"interhash", funcTag, 111},
+ {"nilinterhash", funcTag, 111},
+ {"int64div", funcTag, 112},
+ {"uint64div", funcTag, 113},
+ {"int64mod", funcTag, 112},
+ {"uint64mod", funcTag, 113},
+ {"float64toint64", funcTag, 114},
+ {"float64touint64", funcTag, 115},
+ {"float64touint32", funcTag, 116},
+ {"int64tofloat64", funcTag, 117},
+ {"uint64tofloat64", funcTag, 118},
+ {"uint32tofloat64", funcTag, 119},
+ {"complex128div", funcTag, 120},
+ {"racefuncenter", funcTag, 31},
+ {"racefuncenterfp", funcTag, 9},
+ {"racefuncexit", funcTag, 9},
+ {"raceread", funcTag, 31},
+ {"racewrite", funcTag, 31},
+ {"racereadrange", funcTag, 121},
+ {"racewriterange", funcTag, 121},
+ {"msanread", funcTag, 121},
+ {"msanwrite", funcTag, 121},
+ {"msanmove", funcTag, 122},
+ {"checkptrAlignment", funcTag, 123},
+ {"checkptrArithmetic", funcTag, 125},
+ {"libfuzzerTraceCmp1", funcTag, 127},
+ {"libfuzzerTraceCmp2", funcTag, 129},
+ {"libfuzzerTraceCmp4", funcTag, 130},
+ {"libfuzzerTraceCmp8", funcTag, 131},
+ {"libfuzzerTraceConstCmp1", funcTag, 127},
+ {"libfuzzerTraceConstCmp2", funcTag, 129},
+ {"libfuzzerTraceConstCmp4", funcTag, 130},
+ {"libfuzzerTraceConstCmp8", funcTag, 131},
+ {"x86HasPOPCNT", varTag, 6},
+ {"x86HasSSE41", varTag, 6},
+ {"x86HasFMA", varTag, 6},
+ {"armHasVFPv4", varTag, 6},
+ {"arm64HasATOMICS", varTag, 6},
+}
+
+func runtimeTypes() []*types.Type {
+ var typs [132]*types.Type
+ typs[0] = types.ByteType
+ typs[1] = types.NewPtr(typs[0])
+ typs[2] = types.Types[types.TANY]
+ typs[3] = types.NewPtr(typs[2])
+ typs[4] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
+ typs[5] = types.Types[types.TUINTPTR]
+ typs[6] = types.Types[types.TBOOL]
+ typs[7] = types.Types[types.TUNSAFEPTR]
+ typs[8] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+ typs[9] = NewFuncType(nil, nil, nil)
+ typs[10] = types.Types[types.TINTER]
+ typs[11] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])}, nil)
+ typs[12] = types.Types[types.TINT32]
+ typs[13] = types.NewPtr(typs[12])
+ typs[14] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[13])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[10])})
+ typs[15] = types.Types[types.TINT]
+ typs[16] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil)
+ typs[17] = types.Types[types.TUINT]
+ typs[18] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[17]), ir.NewField(base.Pos, nil, nil, typs[15])}, nil)
+ typs[19] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])}, nil)
+ typs[20] = types.Types[types.TFLOAT64]
+ typs[21] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, nil)
+ typs[22] = types.Types[types.TINT64]
+ typs[23] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, nil)
+ typs[24] = types.Types[types.TUINT64]
+ typs[25] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, nil)
+ typs[26] = types.Types[types.TCOMPLEX128]
+ typs[27] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])}, nil)
+ typs[28] = types.Types[types.TSTRING]
+ typs[29] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, nil)
+ typs[30] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, nil)
+ typs[31] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+ typs[32] = types.NewArray(typs[0], 32)
+ typs[33] = types.NewPtr(typs[32])
+ typs[34] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+ typs[35] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+ typs[36] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+ typs[37] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+ typs[38] = types.NewSlice(typs[28])
+ typs[39] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[38])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+ typs[40] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
+ typs[41] = types.NewArray(typs[0], 4)
+ typs[42] = types.NewPtr(typs[41])
+ typs[43] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[42]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+ typs[44] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+ typs[45] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+ typs[46] = types.RuneType
+ typs[47] = types.NewSlice(typs[46])
+ typs[48] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[47])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])})
+ typs[49] = types.NewSlice(typs[0])
+ typs[50] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[33]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[49])})
+ typs[51] = types.NewArray(typs[46], 32)
+ typs[52] = types.NewPtr(typs[51])
+ typs[53] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[52]), ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[47])})
+ typs[54] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
+ typs[55] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[46]), ir.NewField(base.Pos, nil, nil, typs[15])})
+ typs[56] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[28])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
+ typs[57] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])})
+ typs[58] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+ typs[59] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2])})
+ typs[60] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[2]), ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[61] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1])}, nil)
+ typs[62] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1])}, nil)
+ typs[63] = types.NewPtr(typs[5])
+ typs[64] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[65] = types.Types[types.TUINT32]
+ typs[66] = NewFuncType(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])})
+ typs[67] = types.NewMap(typs[2], typs[2])
+ typs[68] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
+ typs[69] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
+ typs[70] = NewFuncType(nil, nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[67])})
+ typs[71] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
+ typs[72] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
+ typs[73] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])})
+ typs[74] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[75] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[76] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[1])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[77] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+ typs[78] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67]), ir.NewField(base.Pos, nil, nil, typs[2])}, nil)
+ typs[79] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+ typs[80] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[67])}, nil)
+ typs[81] = types.NewChan(typs[2], types.Cboth)
+ typs[82] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])})
+ typs[83] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[81])})
+ typs[84] = types.NewChan(typs[2], types.Crecv)
+ typs[85] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+ typs[86] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[84]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[87] = types.NewChan(typs[2], types.Csend)
+ typs[88] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+ typs[89] = types.NewArray(typs[0], 3)
+ typs[90] = NewStructType([]*ir.Field{ir.NewField(base.Pos, Lookup("enabled"), nil, typs[6]), ir.NewField(base.Pos, Lookup("pad"), nil, typs[89]), ir.NewField(base.Pos, Lookup("needed"), nil, typs[6]), ir.NewField(base.Pos, Lookup("cgo"), nil, typs[6]), ir.NewField(base.Pos, Lookup("alignme"), nil, typs[24])})
+ typs[91] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+ typs[92] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3])}, nil)
+ typs[93] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15])})
+ typs[94] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[87]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[95] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[96] = types.NewPtr(typs[6])
+ typs[97] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[96]), ir.NewField(base.Pos, nil, nil, typs[84])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[98] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[63])}, nil)
+ typs[99] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[63]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[100] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+ typs[101] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+ typs[102] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[15]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7])})
+ typs[103] = types.NewSlice(typs[2])
+ typs[104] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[103]), ir.NewField(base.Pos, nil, nil, typs[15])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[103])})
+ typs[105] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+ typs[106] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+ typs[107] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[108] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[3]), ir.NewField(base.Pos, nil, nil, typs[3])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[109] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[7])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[6])})
+ typs[110] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])})
+ typs[111] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[5])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5])})
+ typs[112] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22]), ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])})
+ typs[113] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])})
+ typs[114] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])})
+ typs[115] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])})
+ typs[116] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])})
+ typs[117] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[22])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
+ typs[118] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
+ typs[119] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[20])})
+ typs[120] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26]), ir.NewField(base.Pos, nil, nil, typs[26])}, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[26])})
+ typs[121] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+ typs[122] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+ typs[123] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[1]), ir.NewField(base.Pos, nil, nil, typs[5])}, nil)
+ typs[124] = types.NewSlice(typs[7])
+ typs[125] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[7]), ir.NewField(base.Pos, nil, nil, typs[124])}, nil)
+ typs[126] = types.Types[types.TUINT8]
+ typs[127] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[126]), ir.NewField(base.Pos, nil, nil, typs[126])}, nil)
+ typs[128] = types.Types[types.TUINT16]
+ typs[129] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[128]), ir.NewField(base.Pos, nil, nil, typs[128])}, nil)
+ typs[130] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[65]), ir.NewField(base.Pos, nil, nil, typs[65])}, nil)
+ typs[131] = NewFuncType(nil, []*ir.Field{ir.NewField(base.Pos, nil, nil, typs[24]), ir.NewField(base.Pos, nil, nil, typs[24])}, nil)
+ return typs[:]
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gc_test
+package typecheck
import (
"bytes"
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gc
+package typecheck
import (
- "cmd/compile/internal/base"
- "cmd/compile/internal/ir"
- "cmd/compile/internal/types"
- "cmd/internal/src"
"fmt"
"go/constant"
"go/token"
"math/big"
"strings"
"unicode"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
)
func roundFloat(v constant.Value, sz int64) constant.Value {
// TODO(mdempsky): Replace these with better APIs.
func convlit(n ir.Node, t *types.Type) ir.Node { return convlit1(n, t, false, nil) }
-func defaultlit(n ir.Node, t *types.Type) ir.Node { return convlit1(n, t, false, nil) }
+func DefaultLit(n ir.Node, t *types.Type) ir.Node { return convlit1(n, t, false, nil) }
// convlit1 converts an untyped expression n to type t. If n already
// has a type, convlit1 has no effect.
case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT, ir.OREAL, ir.OIMAG:
ot := operandType(n.Op(), t)
if ot == nil {
- n = defaultlit(n, nil)
+ n = DefaultLit(n, nil)
break
}
case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT, ir.OOROR, ir.OANDAND, ir.OCOMPLEX:
ot := operandType(n.Op(), t)
if ot == nil {
- n = defaultlit(n, nil)
+ n = DefaultLit(n, nil)
break
}
ir.ORSH: token.SHR,
}
-// evalConst returns a constant-evaluated expression equivalent to n.
-// If n is not a constant, evalConst returns n.
-// Otherwise, evalConst returns a new OLITERAL with the same value as n,
+// EvalConst returns a constant-evaluated expression equivalent to n.
+// If n is not a constant, EvalConst returns n.
+// Otherwise, EvalConst returns a new OLITERAL with the same value as n,
// and with .Orig pointing back to n.
-func evalConst(n ir.Node) ir.Node {
+func EvalConst(n ir.Node) ir.Node {
// Pick off just the opcodes that can be constant evaluated.
switch n.Op() {
case ir.OPLUS, ir.ONEG, ir.OBITNOT, ir.ONOT:
if n.Type().IsUnsigned() {
prec = uint(n.Type().Size() * 8)
}
- return origConst(n, constant.UnaryOp(tokenForOp[n.Op()], nl.Val(), prec))
+ return OrigConst(n, constant.UnaryOp(tokenForOp[n.Op()], nl.Val(), prec))
}
case ir.OADD, ir.OSUB, ir.OMUL, ir.ODIV, ir.OMOD, ir.OOR, ir.OXOR, ir.OAND, ir.OANDNOT:
if n.Op() == ir.ODIV && n.Type().IsInteger() {
tok = token.QUO_ASSIGN // integer division
}
- return origConst(n, constant.BinaryOp(nl.Val(), tok, rval))
+ return OrigConst(n, constant.BinaryOp(nl.Val(), tok, rval))
}
case ir.OOROR, ir.OANDAND:
n := n.(*ir.LogicalExpr)
nl, nr := n.X, n.Y
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
- return origConst(n, constant.BinaryOp(nl.Val(), tokenForOp[n.Op()], nr.Val()))
+ return OrigConst(n, constant.BinaryOp(nl.Val(), tokenForOp[n.Op()], nr.Val()))
}
case ir.OEQ, ir.ONE, ir.OLT, ir.OLE, ir.OGT, ir.OGE:
n := n.(*ir.BinaryExpr)
nl, nr := n.X, n.Y
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
- return origBoolConst(n, constant.Compare(nl.Val(), tokenForOp[n.Op()], nr.Val()))
+ return OrigBool(n, constant.Compare(nl.Val(), tokenForOp[n.Op()], nr.Val()))
}
case ir.OLSH, ir.ORSH:
n.SetType(nil)
break
}
- return origConst(n, constant.Shift(toint(nl.Val()), tokenForOp[n.Op()], uint(s)))
+ return OrigConst(n, constant.Shift(toint(nl.Val()), tokenForOp[n.Op()], uint(s)))
}
case ir.OCONV, ir.ORUNESTR:
n := n.(*ir.ConvExpr)
nl := n.X
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
- return origConst(n, convertVal(nl.Val(), n.Type(), true))
+ return OrigConst(n, convertVal(nl.Val(), n.Type(), true))
}
case ir.OCONVNOP:
if ir.OKForConst[n.Type().Kind()] && nl.Op() == ir.OLITERAL {
// set so n.Orig gets OCONV instead of OCONVNOP
n.SetOp(ir.OCONV)
- return origConst(n, nl.Val())
+ return OrigConst(n, nl.Val())
}
case ir.OADDSTR:
for _, c := range s {
strs = append(strs, ir.StringVal(c))
}
- return origConst(n, constant.MakeString(strings.Join(strs, "")))
+ return OrigConst(n, constant.MakeString(strings.Join(strs, "")))
}
newList := make([]ir.Node, 0, need)
for i := 0; i < len(s); i++ {
nl := ir.Copy(n).(*ir.AddStringExpr)
nl.List.Set(s[i:i2])
- newList = append(newList, origConst(nl, constant.MakeString(strings.Join(strs, ""))))
+ newList = append(newList, OrigConst(nl, constant.MakeString(strings.Join(strs, ""))))
i = i2 - 1
} else {
newList = append(newList, s[i])
switch nl.Type().Kind() {
case types.TSTRING:
if ir.IsConst(nl, constant.String) {
- return origIntConst(n, int64(len(ir.StringVal(nl))))
+ return OrigInt(n, int64(len(ir.StringVal(nl))))
}
case types.TARRAY:
if !anyCallOrChan(nl) {
- return origIntConst(n, nl.Type().NumElem())
+ return OrigInt(n, nl.Type().NumElem())
}
}
case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
n := n.(*ir.UnaryExpr)
- return origIntConst(n, evalunsafe(n))
+ return OrigInt(n, evalunsafe(n))
case ir.OREAL:
n := n.(*ir.UnaryExpr)
nl := n.X
if nl.Op() == ir.OLITERAL {
- return origConst(n, constant.Real(nl.Val()))
+ return OrigConst(n, constant.Real(nl.Val()))
}
case ir.OIMAG:
n := n.(*ir.UnaryExpr)
nl := n.X
if nl.Op() == ir.OLITERAL {
- return origConst(n, constant.Imag(nl.Val()))
+ return OrigConst(n, constant.Imag(nl.Val()))
}
case ir.OCOMPLEX:
n := n.(*ir.BinaryExpr)
nl, nr := n.X, n.Y
if nl.Op() == ir.OLITERAL && nr.Op() == ir.OLITERAL {
- return origConst(n, makeComplex(nl.Val(), nr.Val()))
+ return OrigConst(n, makeComplex(nl.Val(), nr.Val()))
}
}
ir.OBITNOT: "bitwise complement",
}
-// origConst returns an OLITERAL with orig n and value v.
-func origConst(n ir.Node, v constant.Value) ir.Node {
+// OrigConst returns an OLITERAL with orig n and value v.
+func OrigConst(n ir.Node, v constant.Value) ir.Node {
lno := ir.SetPos(n)
v = convertVal(v, n.Type(), false)
base.Pos = lno
return ir.NewConstExpr(v, n)
}
-func origBoolConst(n ir.Node, v bool) ir.Node {
- return origConst(n, constant.MakeBool(v))
+func OrigBool(n ir.Node, v bool) ir.Node {
+ return OrigConst(n, constant.MakeBool(v))
}
-func origIntConst(n ir.Node, v int64) ir.Node {
- return origConst(n, constant.MakeInt64(v))
+func OrigInt(n ir.Node, v int64) ir.Node {
+ return OrigConst(n, constant.MakeInt64(v))
}
// defaultlit on both nodes simultaneously;
return nil
}
-// indexconst checks if Node n contains a constant expression
+// IndexConst checks if Node n contains a constant expression
// representable as a non-negative int and returns its value.
// If n is not a constant expression, not representable as an
// integer, or negative, it returns -1. If n is too large, it
// returns -2.
-func indexconst(n ir.Node) int64 {
+func IndexConst(n ir.Node) int64 {
if n.Op() != ir.OLITERAL {
return -1
}
}
return show
}
+
+// evalunsafe evaluates a package unsafe operation and returns the result.
+func evalunsafe(n ir.Node) int64 {
+ switch n.Op() {
+ case ir.OALIGNOF, ir.OSIZEOF:
+ n := n.(*ir.UnaryExpr)
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
+ tr := n.X.Type()
+ if tr == nil {
+ return 0
+ }
+ types.CalcSize(tr)
+ if n.Op() == ir.OALIGNOF {
+ return int64(tr.Align)
+ }
+ return tr.Width
+
+ case ir.OOFFSETOF:
+ // must be a selector.
+ n := n.(*ir.UnaryExpr)
+ if n.X.Op() != ir.OXDOT {
+ base.Errorf("invalid expression %v", n)
+ return 0
+ }
+ sel := n.X.(*ir.SelectorExpr)
+
+ // Remember base of selector to find it back after dot insertion.
+ // Since r->left may be mutated by typechecking, check it explicitly
+ // first to track it correctly.
+ sel.X = Expr(sel.X)
+ sbase := sel.X
+
+ tsel := Expr(sel)
+ n.X = tsel
+ if tsel.Type() == nil {
+ return 0
+ }
+ switch tsel.Op() {
+ case ir.ODOT, ir.ODOTPTR:
+ break
+ case ir.OCALLPART:
+ base.Errorf("invalid expression %v: argument is a method value", n)
+ return 0
+ default:
+ base.Errorf("invalid expression %v", n)
+ return 0
+ }
+
+ // Sum offsets for dots until we reach sbase.
+ var v int64
+ var next ir.Node
+ for r := tsel; r != sbase; r = next {
+ switch r.Op() {
+ case ir.ODOTPTR:
+ // For Offsetof(s.f), s may itself be a pointer,
+ // but accessing f must not otherwise involve
+ // indirection via embedded pointer types.
+ r := r.(*ir.SelectorExpr)
+ if r.X != sbase {
+ base.Errorf("invalid expression %v: selector implies indirection of embedded %v", n, r.X)
+ return 0
+ }
+ fallthrough
+ case ir.ODOT:
+ r := r.(*ir.SelectorExpr)
+ v += r.Offset
+ next = r.X
+ default:
+ ir.Dump("unsafenmagic", tsel)
+ base.Fatalf("impossible %v node after dot insertion", r.Op())
+ }
+ }
+ return v
+ }
+
+ base.Fatalf("unexpected op %v", n.Op())
+ return 0
+}
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+)
+
+var DeclContext ir.Class // PEXTERN/PAUTO
+
+func AssignDefn(left []ir.Node, defn ir.Node) {
+ for _, n := range left {
+ if n.Sym() != nil {
+ n.Sym().SetUniq(true)
+ }
+ }
+
+ var nnew, nerr int
+ for i, n := range left {
+ if ir.IsBlank(n) {
+ continue
+ }
+ if !assignableName(n) {
+ base.ErrorfAt(defn.Pos(), "non-name %v on left side of :=", n)
+ nerr++
+ continue
+ }
+
+ if !n.Sym().Uniq() {
+ base.ErrorfAt(defn.Pos(), "%v repeated on left side of :=", n.Sym())
+ n.SetDiag(true)
+ nerr++
+ continue
+ }
+
+ n.Sym().SetUniq(false)
+ if n.Sym().Block == types.Block {
+ continue
+ }
+
+ nnew++
+ n := NewName(n.Sym())
+ Declare(n, DeclContext)
+ n.Defn = defn
+ defn.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n))
+ left[i] = n
+ }
+
+ if nnew == 0 && nerr == 0 {
+ base.ErrorfAt(defn.Pos(), "no new variables on left side of :=")
+ }
+}
+
+// := declarations
+func assignableName(n ir.Node) bool {
+ switch n.Op() {
+ case ir.ONAME,
+ ir.ONONAME,
+ ir.OPACK,
+ ir.OTYPE,
+ ir.OLITERAL:
+ return n.Sym() != nil
+ }
+
+ return false
+}
+
+func DeclFunc(sym *types.Sym, tfn ir.Ntype) *ir.Func {
+ if tfn.Op() != ir.OTFUNC {
+ base.Fatalf("expected OTFUNC node, got %v", tfn)
+ }
+
+ fn := ir.NewFunc(base.Pos)
+ fn.Nname = ir.NewFuncNameAt(base.Pos, sym, fn)
+ fn.Nname.Defn = fn
+ fn.Nname.Ntype = tfn
+ ir.MarkFunc(fn.Nname)
+ StartFuncBody(fn)
+ fn.Nname.Ntype = typecheckNtype(fn.Nname.Ntype)
+ return fn
+}
+
+// declare variables from grammar
+// new_name_list (type | [type] = expr_list)
+func DeclVars(vl []*ir.Name, t ir.Ntype, el []ir.Node) []ir.Node {
+ var init []ir.Node
+ doexpr := len(el) > 0
+
+ if len(el) == 1 && len(vl) > 1 {
+ e := el[0]
+ as2 := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
+ as2.Rhs = []ir.Node{e}
+ for _, v := range vl {
+ as2.Lhs.Append(v)
+ Declare(v, DeclContext)
+ v.Ntype = t
+ v.Defn = as2
+ if ir.CurFunc != nil {
+ init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
+ }
+ }
+
+ return append(init, as2)
+ }
+
+ for i, v := range vl {
+ var e ir.Node
+ if doexpr {
+ if i >= len(el) {
+ base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
+ break
+ }
+ e = el[i]
+ }
+
+ Declare(v, DeclContext)
+ v.Ntype = t
+
+ if e != nil || ir.CurFunc != nil || ir.IsBlank(v) {
+ if ir.CurFunc != nil {
+ init = append(init, ir.NewDecl(base.Pos, ir.ODCL, v))
+ }
+ as := ir.NewAssignStmt(base.Pos, v, e)
+ init = append(init, as)
+ if e != nil {
+ v.Defn = as
+ }
+ }
+ }
+
+ if len(el) > len(vl) {
+ base.Errorf("assignment mismatch: %d variables but %d values", len(vl), len(el))
+ }
+ return init
+}
+
+// Declare records that Node n declares symbol n.Sym in the specified
+// declaration context.
+func Declare(n *ir.Name, ctxt ir.Class) {
+ if ir.IsBlank(n) {
+ return
+ }
+
+ s := n.Sym()
+
+ // kludgy: typecheckok means we're past parsing. Eg genwrapper may declare out of package names later.
+ if !inimport && !TypecheckAllowed && s.Pkg != types.LocalPkg {
+ base.ErrorfAt(n.Pos(), "cannot declare name %v", s)
+ }
+
+ gen := 0
+ if ctxt == ir.PEXTERN {
+ if s.Name == "init" {
+ base.ErrorfAt(n.Pos(), "cannot declare init - must be func")
+ }
+ if s.Name == "main" && s.Pkg.Name == "main" {
+ base.ErrorfAt(n.Pos(), "cannot declare main - must be func")
+ }
+ Target.Externs = append(Target.Externs, n)
+ } else {
+ if ir.CurFunc == nil && ctxt == ir.PAUTO {
+ base.Pos = n.Pos()
+ base.Fatalf("automatic outside function")
+ }
+ if ir.CurFunc != nil && ctxt != ir.PFUNC && n.Op() == ir.ONAME {
+ ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
+ }
+ if n.Op() == ir.OTYPE {
+ declare_typegen++
+ gen = declare_typegen
+ } else if n.Op() == ir.ONAME && ctxt == ir.PAUTO && !strings.Contains(s.Name, "·") {
+ vargen++
+ gen = vargen
+ }
+ types.Pushdcl(s)
+ n.Curfn = ir.CurFunc
+ }
+
+ if ctxt == ir.PAUTO {
+ n.SetFrameOffset(0)
+ }
+
+ if s.Block == types.Block {
+ // functype will print errors about duplicate function arguments.
+ // Don't repeat the error here.
+ if ctxt != ir.PPARAM && ctxt != ir.PPARAMOUT {
+ Redeclared(n.Pos(), s, "in this block")
+ }
+ }
+
+ s.Block = types.Block
+ s.Lastlineno = base.Pos
+ s.Def = n
+ n.Vargen = int32(gen)
+ n.Class_ = ctxt
+ if ctxt == ir.PFUNC {
+ n.Sym().SetFunc(true)
+ }
+
+ autoexport(n, ctxt)
+}
+
+// Export marks n for export (or reexport).
+func Export(n *ir.Name) {
+ if n.Sym().OnExportList() {
+ return
+ }
+ n.Sym().SetOnExportList(true)
+
+ if base.Flag.E != 0 {
+ fmt.Printf("export symbol %v\n", n.Sym())
+ }
+
+ Target.Exports = append(Target.Exports, n)
+}
+
+// Redeclared emits a diagnostic about symbol s being redeclared at pos.
+func Redeclared(pos src.XPos, s *types.Sym, where string) {
+ if !s.Lastlineno.IsKnown() {
+ pkgName := DotImportRefs[s.Def.(*ir.Ident)]
+ base.ErrorfAt(pos, "%v redeclared %s\n"+
+ "\t%v: previous declaration during import %q", s, where, base.FmtPos(pkgName.Pos()), pkgName.Pkg.Path)
+ } else {
+ prevPos := s.Lastlineno
+
+ // When an import and a declaration collide in separate files,
+ // present the import as the "redeclared", because the declaration
+ // is visible where the import is, but not vice versa.
+ // See issue 4510.
+ if s.Def == nil {
+ pos, prevPos = prevPos, pos
+ }
+
+ base.ErrorfAt(pos, "%v redeclared %s\n"+
+ "\t%v: previous declaration", s, where, base.FmtPos(prevPos))
+ }
+}
+
+// declare the function proper
+// and declare the arguments.
+// called in extern-declaration context
+// returns in auto-declaration context.
+func StartFuncBody(fn *ir.Func) {
+ // change the declaration context from extern to auto
+ funcStack = append(funcStack, funcStackEnt{ir.CurFunc, DeclContext})
+ ir.CurFunc = fn
+ DeclContext = ir.PAUTO
+
+ types.Markdcl()
+
+ if fn.Nname.Ntype != nil {
+ funcargs(fn.Nname.Ntype.(*ir.FuncType))
+ } else {
+ funcargs2(fn.Type())
+ }
+}
+
+// finish the body.
+// called in auto-declaration context.
+// returns in extern-declaration context.
+func FinishFuncBody() {
+ // change the declaration context from auto to previous context
+ types.Popdcl()
+ var e funcStackEnt
+ funcStack, e = funcStack[:len(funcStack)-1], funcStack[len(funcStack)-1]
+ ir.CurFunc, DeclContext = e.curfn, e.dclcontext
+}
+
+func CheckFuncStack() {
+ if len(funcStack) != 0 {
+ base.Fatalf("funcStack is non-empty: %v", len(funcStack))
+ }
+}
+
+// turn a parsed function declaration into a type
+func NewFuncType(nrecv *ir.Field, nparams, nresults []*ir.Field) *types.Type {
+ funarg := func(n *ir.Field) *types.Field {
+ lno := base.Pos
+ base.Pos = n.Pos
+
+ if n.Ntype != nil {
+ n.Type = typecheckNtype(n.Ntype).Type()
+ n.Ntype = nil
+ }
+
+ f := types.NewField(n.Pos, n.Sym, n.Type)
+ f.SetIsDDD(n.IsDDD)
+ if n.Decl != nil {
+ n.Decl.SetType(f.Type)
+ f.Nname = n.Decl
+ }
+
+ base.Pos = lno
+ return f
+ }
+ funargs := func(nn []*ir.Field) []*types.Field {
+ res := make([]*types.Field, len(nn))
+ for i, n := range nn {
+ res[i] = funarg(n)
+ }
+ return res
+ }
+
+ var recv *types.Field
+ if nrecv != nil {
+ recv = funarg(nrecv)
+ }
+
+ t := types.NewSignature(types.LocalPkg, recv, funargs(nparams), funargs(nresults))
+ checkdupfields("argument", t.Recvs().FieldSlice(), t.Params().FieldSlice(), t.Results().FieldSlice())
+ return t
+}
+
+// convert a parsed id/type list into
+// a type for struct/interface/arglist
+func NewStructType(l []*ir.Field) *types.Type {
+ lno := base.Pos
+
+ fields := make([]*types.Field, len(l))
+ for i, n := range l {
+ base.Pos = n.Pos
+
+ if n.Ntype != nil {
+ n.Type = typecheckNtype(n.Ntype).Type()
+ n.Ntype = nil
+ }
+ f := types.NewField(n.Pos, n.Sym, n.Type)
+ if n.Embedded {
+ checkembeddedtype(n.Type)
+ f.Embedded = 1
+ }
+ f.Note = n.Note
+ fields[i] = f
+ }
+ checkdupfields("field", fields)
+
+ base.Pos = lno
+ return types.NewStruct(types.LocalPkg, fields)
+}
+
+// Add a method, declared as a function.
+// - msym is the method symbol
+// - t is function type (with receiver)
+// Returns a pointer to the existing or added Field; or nil if there's an error.
+func addmethod(n *ir.Func, msym *types.Sym, t *types.Type, local, nointerface bool) *types.Field {
+ if msym == nil {
+ base.Fatalf("no method symbol")
+ }
+
+ // get parent type sym
+ rf := t.Recv() // ptr to this structure
+ if rf == nil {
+ base.Errorf("missing receiver")
+ return nil
+ }
+
+ mt := types.ReceiverBaseType(rf.Type)
+ if mt == nil || mt.Sym() == nil {
+ pa := rf.Type
+ t := pa
+ if t != nil && t.IsPtr() {
+ if t.Sym() != nil {
+ base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
+ return nil
+ }
+ t = t.Elem()
+ }
+
+ switch {
+ case t == nil || t.Broke():
+ // rely on typecheck having complained before
+ case t.Sym() == nil:
+ base.Errorf("invalid receiver type %v (%v is not a defined type)", pa, t)
+ case t.IsPtr():
+ base.Errorf("invalid receiver type %v (%v is a pointer type)", pa, t)
+ case t.IsInterface():
+ base.Errorf("invalid receiver type %v (%v is an interface type)", pa, t)
+ default:
+ // Should have picked off all the reasons above,
+ // but just in case, fall back to generic error.
+ base.Errorf("invalid receiver type %v (%L / %L)", pa, pa, t)
+ }
+ return nil
+ }
+
+ if local && mt.Sym().Pkg != types.LocalPkg {
+ base.Errorf("cannot define new methods on non-local type %v", mt)
+ return nil
+ }
+
+ if msym.IsBlank() {
+ return nil
+ }
+
+ if mt.IsStruct() {
+ for _, f := range mt.Fields().Slice() {
+ if f.Sym == msym {
+ base.Errorf("type %v has both field and method named %v", mt, msym)
+ f.SetBroke(true)
+ return nil
+ }
+ }
+ }
+
+ for _, f := range mt.Methods().Slice() {
+ if msym.Name != f.Sym.Name {
+ continue
+ }
+ // types.Identical only checks that incoming and result parameters match,
+ // so explicitly check that the receiver parameters match too.
+ if !types.Identical(t, f.Type) || !types.Identical(t.Recv().Type, f.Type.Recv().Type) {
+ base.Errorf("method redeclared: %v.%v\n\t%v\n\t%v", mt, msym, f.Type, t)
+ }
+ return f
+ }
+
+ f := types.NewField(base.Pos, msym, t)
+ f.Nname = n.Nname
+ f.SetNointerface(nointerface)
+
+ mt.Methods().Append(f)
+ return f
+}
+
+func autoexport(n *ir.Name, ctxt ir.Class) {
+ if n.Sym().Pkg != types.LocalPkg {
+ return
+ }
+ if (ctxt != ir.PEXTERN && ctxt != ir.PFUNC) || DeclContext != ir.PEXTERN {
+ return
+ }
+ if n.Type() != nil && n.Type().IsKind(types.TFUNC) && ir.IsMethod(n) {
+ return
+ }
+
+ if types.IsExported(n.Sym().Name) || initname(n.Sym().Name) {
+ Export(n)
+ }
+ if base.Flag.AsmHdr != "" && !n.Sym().Asm() {
+ n.Sym().SetAsm(true)
+ Target.Asms = append(Target.Asms, n)
+ }
+}
+
+// checkdupfields emits errors for duplicately named fields or methods in
+// a list of struct or interface types.
+func checkdupfields(what string, fss ...[]*types.Field) {
+ seen := make(map[*types.Sym]bool)
+ for _, fs := range fss {
+ for _, f := range fs {
+ if f.Sym == nil || f.Sym.IsBlank() {
+ continue
+ }
+ if seen[f.Sym] {
+ base.ErrorfAt(f.Pos, "duplicate %s %s", what, f.Sym.Name)
+ continue
+ }
+ seen[f.Sym] = true
+ }
+ }
+}
+
+// structs, functions, and methods.
+// they don't belong here, but where do they belong?
+func checkembeddedtype(t *types.Type) {
+ if t == nil {
+ return
+ }
+
+ if t.Sym() == nil && t.IsPtr() {
+ t = t.Elem()
+ if t.IsInterface() {
+ base.Errorf("embedded type cannot be a pointer to interface")
+ }
+ }
+
+ if t.IsPtr() || t.IsUnsafePtr() {
+ base.Errorf("embedded type cannot be a pointer")
+ } else if t.Kind() == types.TFORW && !t.ForwardType().Embedlineno.IsKnown() {
+ t.ForwardType().Embedlineno = base.Pos
+ }
+}
+
+// declare individual names - var, typ, const
+
+var declare_typegen int
+
+func fakeRecvField() *types.Field {
+ return types.NewField(src.NoXPos, nil, types.FakeRecvType())
+}
+
+var funcStack []funcStackEnt // stack of previous values of Curfn/dclcontext
+
+type funcStackEnt struct {
+ curfn *ir.Func
+ dclcontext ir.Class
+}
+
+func funcarg(n *ir.Field, ctxt ir.Class) {
+ if n.Sym == nil {
+ return
+ }
+
+ name := ir.NewNameAt(n.Pos, n.Sym)
+ n.Decl = name
+ name.Ntype = n.Ntype
+ name.SetIsDDD(n.IsDDD)
+ Declare(name, ctxt)
+
+ vargen++
+ n.Decl.Vargen = int32(vargen)
+}
+
+func funcarg2(f *types.Field, ctxt ir.Class) {
+ if f.Sym == nil {
+ return
+ }
+ n := ir.NewNameAt(f.Pos, f.Sym)
+ f.Nname = n
+ n.SetType(f.Type)
+ n.SetIsDDD(f.IsDDD())
+ Declare(n, ctxt)
+}
+
+func funcargs(nt *ir.FuncType) {
+ if nt.Op() != ir.OTFUNC {
+ base.Fatalf("funcargs %v", nt.Op())
+ }
+
+ // re-start the variable generation number
+ // we want to use small numbers for the return variables,
+ // so let them have the chunk starting at 1.
+ //
+ // TODO(mdempsky): This is ugly, and only necessary because
+ // esc.go uses Vargen to figure out result parameters' index
+ // within the result tuple.
+ vargen = len(nt.Results)
+
+ // declare the receiver and in arguments.
+ if nt.Recv != nil {
+ funcarg(nt.Recv, ir.PPARAM)
+ }
+ for _, n := range nt.Params {
+ funcarg(n, ir.PPARAM)
+ }
+
+ oldvargen := vargen
+ vargen = 0
+
+ // declare the out arguments.
+ gen := len(nt.Params)
+ for _, n := range nt.Results {
+ if n.Sym == nil {
+ // Name so that escape analysis can track it. ~r stands for 'result'.
+ n.Sym = LookupNum("~r", gen)
+ gen++
+ }
+ if n.Sym.IsBlank() {
+ // Give it a name so we can assign to it during return. ~b stands for 'blank'.
+ // The name must be different from ~r above because if you have
+ // func f() (_ int)
+ // func g() int
+ // f is allowed to use a plain 'return' with no arguments, while g is not.
+ // So the two cases must be distinguished.
+ n.Sym = LookupNum("~b", gen)
+ gen++
+ }
+
+ funcarg(n, ir.PPARAMOUT)
+ }
+
+ vargen = oldvargen
+}
+
+// Same as funcargs, except run over an already constructed TFUNC.
+// This happens during import, where the hidden_fndcl rule has
+// used functype directly to parse the function's type.
+func funcargs2(t *types.Type) {
+ if t.Kind() != types.TFUNC {
+ base.Fatalf("funcargs2 %v", t)
+ }
+
+ for _, f := range t.Recvs().Fields().Slice() {
+ funcarg2(f, ir.PPARAM)
+ }
+ for _, f := range t.Params().Fields().Slice() {
+ funcarg2(f, ir.PPARAM)
+ }
+ for _, f := range t.Results().Fields().Slice() {
+ funcarg2(f, ir.PPARAMOUT)
+ }
+}
+
+func initname(s string) bool {
+ return s == "init"
+}
+
+func tointerface(nmethods []*ir.Field) *types.Type {
+ if len(nmethods) == 0 {
+ return types.Types[types.TINTER]
+ }
+
+ lno := base.Pos
+
+ methods := make([]*types.Field, len(nmethods))
+ for i, n := range nmethods {
+ base.Pos = n.Pos
+ if n.Ntype != nil {
+ n.Type = typecheckNtype(n.Ntype).Type()
+ n.Ntype = nil
+ }
+ methods[i] = types.NewField(n.Pos, n.Sym, n.Type)
+ }
+
+ base.Pos = lno
+ return types.NewInterface(types.LocalPkg, methods)
+}
+
+var vargen int
+
+func Temp(t *types.Type) *ir.Name {
+ return TempAt(base.Pos, ir.CurFunc, t)
+}
+
+// make a new Node off the books
+func TempAt(pos src.XPos, curfn *ir.Func, t *types.Type) *ir.Name {
+ if curfn == nil {
+ base.Fatalf("no curfn for tempAt")
+ }
+ if curfn.Op() == ir.OCLOSURE {
+ ir.Dump("tempAt", curfn)
+ base.Fatalf("adding tempAt to wrong closure function")
+ }
+ if t == nil {
+ base.Fatalf("tempAt called with nil type")
+ }
+
+ s := &types.Sym{
+ Name: autotmpname(len(curfn.Dcl)),
+ Pkg: types.LocalPkg,
+ }
+ n := ir.NewNameAt(pos, s)
+ s.Def = n
+ n.SetType(t)
+ n.Class_ = ir.PAUTO
+ n.SetEsc(ir.EscNever)
+ n.Curfn = curfn
+ n.SetUsed(true)
+ n.SetAutoTemp(true)
+ curfn.Dcl = append(curfn.Dcl, n)
+
+ types.CalcSize(t)
+
+ return n
+}
+
+// autotmpname returns the name for an autotmp variable numbered n.
+func autotmpname(n int) string {
+ // Give each tmp a different name so that they can be registerized.
+ // Add a preceding . to avoid clashing with legal names.
+ const prefix = ".autotmp_"
+ // Start with a buffer big enough to hold a large n.
+ b := []byte(prefix + " ")[:len(prefix)]
+ b = strconv.AppendInt(b, int64(n), 10)
+ return types.InternString(b)
+}
+
+// f is method type, with receiver.
+// return function type, receiver as first argument (or not).
+func NewMethodType(f *types.Type, receiver *types.Type) *types.Type {
+ inLen := f.Params().Fields().Len()
+ if receiver != nil {
+ inLen++
+ }
+ in := make([]*ir.Field, 0, inLen)
+
+ if receiver != nil {
+ d := ir.NewField(base.Pos, nil, nil, receiver)
+ in = append(in, d)
+ }
+
+ for _, t := range f.Params().Fields().Slice() {
+ d := ir.NewField(base.Pos, nil, nil, t.Type)
+ d.IsDDD = t.IsDDD()
+ in = append(in, d)
+ }
+
+ outLen := f.Results().Fields().Len()
+ out := make([]*ir.Field, 0, outLen)
+ for _, t := range f.Results().Fields().Slice() {
+ d := ir.NewField(base.Pos, nil, nil, t.Type)
+ out = append(out, d)
+ }
+
+ return NewFuncType(nil, in, out)
+}
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+ "go/constant"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+)
+
+// importalias declares symbol s as an imported type alias with type t.
+// ipkg is the package being imported
+func importalias(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
+ return importobj(ipkg, pos, s, ir.OTYPE, ir.PEXTERN, t)
+}
+
+// importconst declares symbol s as an imported constant with type t and value val.
+// ipkg is the package being imported
+func importconst(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type, val constant.Value) *ir.Name {
+ n := importobj(ipkg, pos, s, ir.OLITERAL, ir.PEXTERN, t)
+ n.SetVal(val)
+ return n
+}
+
+// importfunc declares symbol s as an imported function with type t.
+// ipkg is the package being imported
+func importfunc(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
+ n := importobj(ipkg, pos, s, ir.ONAME, ir.PFUNC, t)
+
+ fn := ir.NewFunc(pos)
+ fn.SetType(t)
+ n.SetFunc(fn)
+ fn.Nname = n
+
+ return n
+}
+
+// importobj declares symbol s as an imported object representable by op.
+// ipkg is the package being imported
+func importobj(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class, t *types.Type) *ir.Name {
+ n := importsym(ipkg, pos, s, op, ctxt)
+ n.SetType(t)
+ if ctxt == ir.PFUNC {
+ n.Sym().SetFunc(true)
+ }
+ return n
+}
+
+func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op ir.Op, ctxt ir.Class) *ir.Name {
+ if n := s.PkgDef(); n != nil {
+ base.Fatalf("importsym of symbol that already exists: %v", n)
+ }
+
+ n := ir.NewDeclNameAt(pos, op, s)
+ n.Class_ = ctxt // TODO(mdempsky): Move this into NewDeclNameAt too?
+ s.SetPkgDef(n)
+ s.Importdef = ipkg
+ return n
+}
+
+// importtype returns the named type declared by symbol s.
+// If no such type has been declared yet, a forward declaration is returned.
+// ipkg is the package being imported
+func importtype(ipkg *types.Pkg, pos src.XPos, s *types.Sym) *ir.Name {
+ n := importsym(ipkg, pos, s, ir.OTYPE, ir.PEXTERN)
+ n.SetType(types.NewNamed(n))
+ return n
+}
+
+// importvar declares symbol s as an imported variable with type t.
+// ipkg is the package being imported
+func importvar(ipkg *types.Pkg, pos src.XPos, s *types.Sym, t *types.Type) *ir.Name {
+ return importobj(ipkg, pos, s, ir.ONAME, ir.PEXTERN, t)
+}
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+
+ "fmt"
+)
+
+// package all the arguments that match a ... T parameter into a []T.
+func MakeDotArgs(typ *types.Type, args []ir.Node) ir.Node {
+ var n ir.Node
+ if len(args) == 0 {
+ n = NodNil()
+ n.SetType(typ)
+ } else {
+ lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(typ).(ir.Ntype), nil)
+ lit.List.Append(args...)
+ lit.SetImplicit(true)
+ n = lit
+ }
+
+ n = Expr(n)
+ if n.Type() == nil {
+ base.Fatalf("mkdotargslice: typecheck failed")
+ }
+ return n
+}
+
+// FixVariadicCall rewrites calls to variadic functions to use an
+// explicit ... argument if one is not already present.
+func FixVariadicCall(call *ir.CallExpr) {
+ fntype := call.X.Type()
+ if !fntype.IsVariadic() || call.IsDDD {
+ return
+ }
+
+ vi := fntype.NumParams() - 1
+ vt := fntype.Params().Field(vi).Type
+
+ args := call.Args
+ extra := args[vi:]
+ slice := MakeDotArgs(vt, extra)
+ for i := range extra {
+ extra[i] = nil // allow GC
+ }
+
+ call.Args.Set(append(args[:vi], slice))
+ call.IsDDD = true
+}
+
+// ClosureType returns the struct type used to hold all the information
+// needed in the closure for clo (clo must be a OCLOSURE node).
+// The address of a variable of the returned type can be cast to a func.
+func ClosureType(clo *ir.ClosureExpr) *types.Type {
+ // Create closure in the form of a composite literal.
+ // supposing the closure captures an int i and a string s
+ // and has one float64 argument and no results,
+ // the generated code looks like:
+ //
+ // clos = &struct{.F uintptr; i *int; s *string}{func.1, &i, &s}
+ //
+ // The use of the struct provides type information to the garbage
+ // collector so that it can walk the closure. We could use (in this case)
+ // [3]unsafe.Pointer instead, but that would leave the gc in the dark.
+ // The information appears in the binary in the form of type descriptors;
+ // the struct is unnamed so that closures in multiple packages with the
+ // same struct type can share the descriptor.
+ fields := []*ir.Field{
+ ir.NewField(base.Pos, Lookup(".F"), nil, types.Types[types.TUINTPTR]),
+ }
+ for _, v := range clo.Func.ClosureVars {
+ typ := v.Type()
+ if !v.Byval() {
+ typ = types.NewPtr(typ)
+ }
+ fields = append(fields, ir.NewField(base.Pos, v.Sym(), nil, typ))
+ }
+ typ := NewStructType(fields)
+ typ.SetNoalg(true)
+ return typ
+}
+
+// PartialCallType returns the struct type used to hold all the information
+// needed in the closure for n (n must be a OCALLPART node).
+// The address of a variable of the returned type can be cast to a func.
+func PartialCallType(n *ir.CallPartExpr) *types.Type {
+ t := NewStructType([]*ir.Field{
+ ir.NewField(base.Pos, Lookup("F"), nil, types.Types[types.TUINTPTR]),
+ ir.NewField(base.Pos, Lookup("R"), nil, n.X.Type()),
+ })
+ t.SetNoalg(true)
+ return t
+}
+
+// CaptureVars is called in a separate phase after all typechecking is done.
+// It decides whether each variable captured by a closure should be captured
+// by value or by reference.
+// We use value capturing for values <= 128 bytes that are never reassigned
+// after capturing (effectively constant).
+func CaptureVars(fn *ir.Func) {
+ lno := base.Pos
+ base.Pos = fn.Pos()
+ cvars := fn.ClosureVars
+ out := cvars[:0]
+ for _, v := range cvars {
+ if v.Type() == nil {
+ // If v.Type is nil, it means v looked like it
+ // was going to be used in the closure, but
+ // isn't. This happens in struct literals like
+ // s{f: x} where we can't distinguish whether
+ // f is a field identifier or expression until
+ // resolving s.
+ continue
+ }
+ out = append(out, v)
+
+ // type check the & of closed variables outside the closure,
+ // so that the outer frame also grabs them and knows they escape.
+ types.CalcSize(v.Type())
+
+ var outer ir.Node
+ outer = v.Outer
+ outermost := v.Defn.(*ir.Name)
+
+ // out parameters will be assigned to implicitly upon return.
+ if outermost.Class_ != ir.PPARAMOUT && !outermost.Name().Addrtaken() && !outermost.Name().Assigned() && v.Type().Width <= 128 {
+ v.SetByval(true)
+ } else {
+ outermost.Name().SetAddrtaken(true)
+ outer = NodAddr(outer)
+ }
+
+ if base.Flag.LowerM > 1 {
+ var name *types.Sym
+ if v.Curfn != nil && v.Curfn.Nname != nil {
+ name = v.Curfn.Sym()
+ }
+ how := "ref"
+ if v.Byval() {
+ how = "value"
+ }
+ base.WarnfAt(v.Pos(), "%v capturing by %s: %v (addr=%v assign=%v width=%d)", name, how, v.Sym(), outermost.Name().Addrtaken(), outermost.Name().Assigned(), int32(v.Type().Width))
+ }
+
+ outer = Expr(outer)
+ fn.ClosureEnter.Append(outer)
+ }
+
+ fn.ClosureVars = out
+ base.Pos = lno
+}
+
+// typecheckclosure typechecks an OCLOSURE node. It also creates the named
+// function associated with the closure.
+// TODO: This creation of the named function should probably really be done in a
+// separate pass from type-checking.
+func typecheckclosure(clo *ir.ClosureExpr, top int) {
+ fn := clo.Func
+ // Set current associated iota value, so iota can be used inside
+ // function in ConstSpec, see issue #22344
+ if x := getIotaValue(); x >= 0 {
+ fn.Iota = x
+ }
+
+ fn.ClosureType = check(fn.ClosureType, ctxType)
+ clo.SetType(fn.ClosureType.Type())
+ fn.SetClosureCalled(top&ctxCallee != 0)
+
+ // Do not typecheck fn twice, otherwise, we will end up pushing
+ // fn to Target.Decls multiple times, causing initLSym called twice.
+ // See #30709
+ if fn.Typecheck() == 1 {
+ return
+ }
+
+ for _, ln := range fn.ClosureVars {
+ n := ln.Defn
+ if !n.Name().Captured() {
+ n.Name().SetCaptured(true)
+ if n.Name().Decldepth == 0 {
+ base.Fatalf("typecheckclosure: var %v does not have decldepth assigned", n)
+ }
+
+ // Ignore assignments to the variable in straightline code
+ // preceding the first capturing by a closure.
+ if n.Name().Decldepth == decldepth {
+ n.Name().SetAssigned(false)
+ }
+ }
+ }
+
+ fn.Nname.SetSym(closurename(ir.CurFunc))
+ ir.MarkFunc(fn.Nname)
+ Func(fn)
+
+ // Type check the body now, but only if we're inside a function.
+ // At top level (in a variable initialization: curfn==nil) we're not
+ // ready to type check code yet; we'll check it later, because the
+ // underlying closure function we create is added to Target.Decls.
+ if ir.CurFunc != nil && clo.Type() != nil {
+ oldfn := ir.CurFunc
+ ir.CurFunc = fn
+ olddd := decldepth
+ decldepth = 1
+ Stmts(fn.Body)
+ decldepth = olddd
+ ir.CurFunc = oldfn
+ }
+
+ Target.Decls = append(Target.Decls, fn)
+}
+
+// Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
+// because they're a copy of an already checked body.
+func ImportedBody(fn *ir.Func) {
+ lno := ir.SetPos(fn.Nname)
+
+ ImportBody(fn)
+
+ // typecheckinl is only for imported functions;
+ // their bodies may refer to unsafe as long as the package
+ // was marked safe during import (which was checked then).
+ // the ->inl of a local function has been typechecked before caninl copied it.
+ pkg := fnpkg(fn.Nname)
+
+ if pkg == types.LocalPkg || pkg == nil {
+ return // typecheckinl on local function
+ }
+
+ if base.Flag.LowerM > 2 || base.Debug.Export != 0 {
+ fmt.Printf("typecheck import [%v] %L { %v }\n", fn.Sym(), fn, ir.Nodes(fn.Inl.Body))
+ }
+
+ savefn := ir.CurFunc
+ ir.CurFunc = fn
+ Stmts(fn.Inl.Body)
+ ir.CurFunc = savefn
+
+ // During expandInline (which imports fn.Func.Inl.Body),
+ // declarations are added to fn.Func.Dcl by funcHdr(). Move them
+ // to fn.Func.Inl.Dcl for consistency with how local functions
+ // behave. (Append because typecheckinl may be called multiple
+ // times.)
+ fn.Inl.Dcl = append(fn.Inl.Dcl, fn.Dcl...)
+ fn.Dcl = nil
+
+ base.Pos = lno
+}
+
+// Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
+// the ->sym can be re-used in the local package, so peel it off the receiver's type.
+func fnpkg(fn *ir.Name) *types.Pkg {
+ if ir.IsMethod(fn) {
+ // method
+ rcvr := fn.Type().Recv().Type
+
+ if rcvr.IsPtr() {
+ rcvr = rcvr.Elem()
+ }
+ if rcvr.Sym() == nil {
+ base.Fatalf("receiver with no sym: [%v] %L (%v)", fn.Sym(), fn, rcvr)
+ }
+ return rcvr.Sym().Pkg
+ }
+
+ // non-method
+ return fn.Sym().Pkg
+}
+
+// CaptureVarsComplete is set to true when the capturevars phase is done.
+var CaptureVarsComplete bool
+
+// closurename generates a new unique name for a closure within
+// outerfunc.
+func closurename(outerfunc *ir.Func) *types.Sym {
+ outer := "glob."
+ prefix := "func"
+ gen := &globClosgen
+
+ if outerfunc != nil {
+ if outerfunc.OClosure != nil {
+ prefix = ""
+ }
+
+ outer = ir.FuncName(outerfunc)
+
+ // There may be multiple functions named "_". In those
+ // cases, we can't use their individual Closgens as it
+ // would lead to name clashes.
+ if !ir.IsBlank(outerfunc.Nname) {
+ gen = &outerfunc.Closgen
+ }
+ }
+
+ *gen++
+ return Lookup(fmt.Sprintf("%s.%s%d", outer, prefix, *gen))
+}
+
+// globClosgen is like Func.Closgen, but for the global scope.
+var globClosgen int32
+
+// makepartialcall returns a DCLFUNC node representing the wrapper function (*-fm) needed
+// for partial calls.
+func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.Func {
+ rcvrtype := dot.X.Type()
+ sym := ir.MethodSymSuffix(rcvrtype, meth, "-fm")
+
+ if sym.Uniq() {
+ return sym.Def.(*ir.Func)
+ }
+ sym.SetUniq(true)
+
+ savecurfn := ir.CurFunc
+ saveLineNo := base.Pos
+ ir.CurFunc = nil
+
+ // Set line number equal to the line number where the method is declared.
+ var m *types.Field
+ if lookdot0(meth, rcvrtype, &m, false) == 1 && m.Pos.IsKnown() {
+ base.Pos = m.Pos
+ }
+ // Note: !m.Pos.IsKnown() happens for method expressions where
+ // the method is implicitly declared. The Error method of the
+ // built-in error type is one such method. We leave the line
+ // number at the use of the method expression in this
+ // case. See issue 29389.
+
+ tfn := ir.NewFuncType(base.Pos, nil,
+ NewFuncParams(t0.Params(), true),
+ NewFuncParams(t0.Results(), false))
+
+ fn := DeclFunc(sym, tfn)
+ fn.SetDupok(true)
+ fn.SetNeedctxt(true)
+
+ // Declare and initialize variable holding receiver.
+ cr := ir.NewClosureRead(rcvrtype, types.Rnd(int64(types.PtrSize), int64(rcvrtype.Align)))
+ ptr := NewName(Lookup(".this"))
+ Declare(ptr, ir.PAUTO)
+ ptr.SetUsed(true)
+ var body []ir.Node
+ if rcvrtype.IsPtr() || rcvrtype.IsInterface() {
+ ptr.SetType(rcvrtype)
+ body = append(body, ir.NewAssignStmt(base.Pos, ptr, cr))
+ } else {
+ ptr.SetType(types.NewPtr(rcvrtype))
+ body = append(body, ir.NewAssignStmt(base.Pos, ptr, NodAddr(cr)))
+ }
+
+ call := ir.NewCallExpr(base.Pos, ir.OCALL, ir.NewSelectorExpr(base.Pos, ir.OXDOT, ptr, meth), nil)
+ call.Args.Set(ir.ParamNames(tfn.Type()))
+ call.IsDDD = tfn.Type().IsVariadic()
+ if t0.NumResults() != 0 {
+ ret := ir.NewReturnStmt(base.Pos, nil)
+ ret.Results = []ir.Node{call}
+ body = append(body, ret)
+ } else {
+ body = append(body, call)
+ }
+
+ fn.Body.Set(body)
+ FinishFuncBody()
+
+ Func(fn)
+ // Need to typecheck the body of the just-generated wrapper.
+ // typecheckslice() requires that Curfn is set when processing an ORETURN.
+ ir.CurFunc = fn
+ Stmts(fn.Body)
+ sym.Def = fn
+ Target.Decls = append(Target.Decls, fn)
+ ir.CurFunc = savecurfn
+ base.Pos = saveLineNo
+
+ return fn
+}
+
+func typecheckpartialcall(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
+ switch n.Op() {
+ case ir.ODOTINTER, ir.ODOTMETH:
+ break
+
+ default:
+ base.Fatalf("invalid typecheckpartialcall")
+ }
+ dot := n.(*ir.SelectorExpr)
+
+ // Create top-level function.
+ fn := makepartialcall(dot, dot.Type(), sym)
+ fn.SetWrapper(true)
+
+ return ir.NewCallPartExpr(dot.Pos(), dot.X, dot.Selection, fn)
+}
// they're expected to change much more rapidly, so they're omitted
// here. See exportWriter's varExt/funcExt/etc methods for details.
-package gc
+package typecheck
import (
"bufio"
"bytes"
- "cmd/compile/internal/base"
- "cmd/compile/internal/ir"
- "cmd/compile/internal/types"
- "cmd/internal/goobj"
- "cmd/internal/src"
"crypto/md5"
"encoding/binary"
"fmt"
"math/big"
"sort"
"strings"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+ "cmd/internal/goobj"
+ "cmd/internal/src"
)
// Current indexed export format version. Increase with each format change.
interfaceType
)
-func iexport(out *bufio.Writer) {
+func WriteExports(out *bufio.Writer) {
p := iexporter{
allPkgs: map[*types.Pkg]bool{},
stringIndex: map[string]uint64{},
case ir.OLITERAL:
// Constant.
// TODO(mdempsky): Do we still need this typecheck? If so, why?
- n = typecheck(n, ctxExpr).(*ir.Name)
+ n = Expr(n).(*ir.Name)
w.tag('C')
w.pos(n.Pos())
w.value(n.Type(), n.Val())
// Indexed package import.
// See iexport.go for the export data format.
-package gc
+package typecheck
import (
- "cmd/compile/internal/base"
- "cmd/compile/internal/ir"
- "cmd/compile/internal/types"
- "cmd/internal/bio"
- "cmd/internal/goobj"
- "cmd/internal/obj"
- "cmd/internal/src"
"encoding/binary"
"fmt"
"go/constant"
"math/big"
"os"
"strings"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+ "cmd/internal/bio"
+ "cmd/internal/goobj"
+ "cmd/internal/obj"
+ "cmd/internal/src"
)
// An iimporterAndOffset identifies an importer and an offset within
}
var (
- // declImporter maps from imported identifiers to an importer
+ // DeclImporter maps from imported identifiers to an importer
// and offset where that identifier's declaration can be read.
- declImporter = map[*types.Sym]iimporterAndOffset{}
+ DeclImporter = map[*types.Sym]iimporterAndOffset{}
// inlineImporter is like declImporter, but for inline bodies
// for function and method symbols.
return n.(*ir.Name)
}
- r := importReaderFor(id.Sym(), declImporter)
+ r := importReaderFor(id.Sym(), DeclImporter)
if r == nil {
// Can happen if user tries to reference an undeclared name.
return n
return r.doDecl(n.Sym())
}
-func expandInline(fn *ir.Func) {
+func ImportBody(fn *ir.Func) {
if fn.Inl.Body != nil {
return
}
return i
}
-func iimport(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintType) {
+func ReadImports(pkg *types.Pkg, in *bio.Reader) (fingerprint goobj.FingerprintType) {
ird := &intReader{in, pkg}
version := ird.uint64()
s := pkg.Lookup(p.stringAt(ird.uint64()))
off := ird.uint64()
- if _, ok := declImporter[s]; !ok {
- declImporter[s] = iimporterAndOffset{p, off}
+ if _, ok := DeclImporter[s]; !ok {
+ DeclImporter[s] = iimporterAndOffset{p, off}
}
}
}
base.Fatalf("%v already has inline body", fn)
}
- funchdr(fn)
+ StartFuncBody(fn)
body := r.stmtList()
- funcbody()
+ FinishFuncBody()
if body == nil {
//
// Make sure empty body is not interpreted as
// names after import. That's okay: swt.go only needs
// Sym for diagnostics anyway.
caseVar := ir.NewNameAt(cas.Pos(), r.ident())
- declare(caseVar, dclcontext)
+ Declare(caseVar, DeclContext)
cas.Vars = []ir.Node{caseVar}
caseVar.Defn = sw.(*ir.SwitchStmt).Tag
}
pos := r.pos()
typ := r.typ()
- n := npos(pos, nodnil())
+ n := npos(pos, NodNil())
n.SetType(typ)
return n
return ir.NewUnaryExpr(r.pos(), op, r.expr())
case ir.OADDR:
- return nodAddrAt(r.pos(), r.expr())
+ return NodAddrAt(r.pos(), r.expr())
case ir.ODEREF:
return ir.NewStarExpr(r.pos(), r.expr())
lhs := ir.NewDeclNameAt(pos, ir.ONAME, r.ident())
lhs.SetType(r.typ())
- declare(lhs, ir.PAUTO)
+ Declare(lhs, ir.PAUTO)
var stmts ir.Nodes
stmts.Append(ir.NewDecl(base.Pos, ir.ODCL, lhs))
var sym *types.Sym
pos := r.pos()
if label := r.string(); label != "" {
- sym = lookup(label)
+ sym = Lookup(label)
}
return ir.NewBranchStmt(pos, op, sym)
case ir.OLABEL:
- return ir.NewLabelStmt(r.pos(), lookup(r.string()))
+ return ir.NewLabelStmt(r.pos(), Lookup(r.string()))
case ir.OEND:
return nil
// +build darwin dragonfly freebsd linux netbsd openbsd
-package gc
+package typecheck
import (
"os"
// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd
-package gc
+package typecheck
import (
"io"
var b bytes.Buffer
fmt.Fprintln(&b, "// Code generated by mkbuiltin.go. DO NOT EDIT.")
fmt.Fprintln(&b)
- fmt.Fprintln(&b, "package gc")
+ fmt.Fprintln(&b, "package typecheck")
fmt.Fprintln(&b)
fmt.Fprintln(&b, `import (`)
fmt.Fprintln(&b, ` "cmd/compile/internal/ir"`)
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+)
+
+// range
+func typecheckrange(n *ir.RangeStmt) {
+ // Typechecking order is important here:
+ // 0. first typecheck range expression (slice/map/chan),
+ // it is evaluated only once and so logically it is not part of the loop.
+ // 1. typecheck produced values,
+ // this part can declare new vars and so it must be typechecked before body,
+ // because body can contain a closure that captures the vars.
+ // 2. decldepth++ to denote loop body.
+ // 3. typecheck body.
+ // 4. decldepth--.
+ typecheckrangeExpr(n)
+
+ // second half of dance, the first half being typecheckrangeExpr
+ n.SetTypecheck(1)
+ ls := n.Vars
+ for i1, n1 := range ls {
+ if n1.Typecheck() == 0 {
+ ls[i1] = AssignExpr(ls[i1])
+ }
+ }
+
+ decldepth++
+ Stmts(n.Body)
+ decldepth--
+}
+
+func typecheckrangeExpr(n *ir.RangeStmt) {
+ n.X = Expr(n.X)
+
+ t := n.X.Type()
+ if t == nil {
+ return
+ }
+ // delicate little dance. see typecheckas2
+ ls := n.Vars
+ for i1, n1 := range ls {
+ if !ir.DeclaredBy(n1, n) {
+ ls[i1] = AssignExpr(ls[i1])
+ }
+ }
+
+ if t.IsPtr() && t.Elem().IsArray() {
+ t = t.Elem()
+ }
+ n.SetType(t)
+
+ var t1, t2 *types.Type
+ toomany := false
+ switch t.Kind() {
+ default:
+ base.ErrorfAt(n.Pos(), "cannot range over %L", n.X)
+ return
+
+ case types.TARRAY, types.TSLICE:
+ t1 = types.Types[types.TINT]
+ t2 = t.Elem()
+
+ case types.TMAP:
+ t1 = t.Key()
+ t2 = t.Elem()
+
+ case types.TCHAN:
+ if !t.ChanDir().CanRecv() {
+ base.ErrorfAt(n.Pos(), "invalid operation: range %v (receive from send-only type %v)", n.X, n.X.Type())
+ return
+ }
+
+ t1 = t.Elem()
+ t2 = nil
+ if len(n.Vars) == 2 {
+ toomany = true
+ }
+
+ case types.TSTRING:
+ t1 = types.Types[types.TINT]
+ t2 = types.RuneType
+ }
+
+ if len(n.Vars) > 2 || toomany {
+ base.ErrorfAt(n.Pos(), "too many variables in range")
+ }
+
+ var v1, v2 ir.Node
+ if len(n.Vars) != 0 {
+ v1 = n.Vars[0]
+ }
+ if len(n.Vars) > 1 {
+ v2 = n.Vars[1]
+ }
+
+ // this is not only an optimization but also a requirement in the spec.
+ // "if the second iteration variable is the blank identifier, the range
+ // clause is equivalent to the same clause with only the first variable
+ // present."
+ if ir.IsBlank(v2) {
+ if v1 != nil {
+ n.Vars = []ir.Node{v1}
+ }
+ v2 = nil
+ }
+
+ if v1 != nil {
+ if ir.DeclaredBy(v1, n) {
+ v1.SetType(t1)
+ } else if v1.Type() != nil {
+ if op, why := assignop(t1, v1.Type()); op == ir.OXXX {
+ base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t1, v1, why)
+ }
+ }
+ checkassign(n, v1)
+ }
+
+ if v2 != nil {
+ if ir.DeclaredBy(v2, n) {
+ v2.SetType(t2)
+ } else if v2.Type() != nil {
+ if op, why := assignop(t2, v2.Type()); op == ir.OXXX {
+ base.ErrorfAt(n.Pos(), "cannot assign type %v to %L in range%s", t2, v2, why)
+ }
+ }
+ checkassign(n, v2)
+ }
+}
+
+// select
+func typecheckselect(sel *ir.SelectStmt) {
+ var def ir.Node
+ lno := ir.SetPos(sel)
+ Stmts(sel.Init())
+ for _, ncase := range sel.Cases {
+ ncase := ncase.(*ir.CaseStmt)
+
+ if len(ncase.List) == 0 {
+ // default
+ if def != nil {
+ base.ErrorfAt(ncase.Pos(), "multiple defaults in select (first at %v)", ir.Line(def))
+ } else {
+ def = ncase
+ }
+ } else if len(ncase.List) > 1 {
+ base.ErrorfAt(ncase.Pos(), "select cases cannot be lists")
+ } else {
+ ncase.List[0] = Stmt(ncase.List[0])
+ n := ncase.List[0]
+ ncase.Comm = n
+ ncase.List.Set(nil)
+ oselrecv2 := func(dst, recv ir.Node, colas bool) {
+ n := ir.NewAssignListStmt(n.Pos(), ir.OSELRECV2, nil, nil)
+ n.Lhs = []ir.Node{dst, ir.BlankNode}
+ n.Rhs = []ir.Node{recv}
+ n.Def = colas
+ n.SetTypecheck(1)
+ ncase.Comm = n
+ }
+ switch n.Op() {
+ default:
+ pos := n.Pos()
+ if n.Op() == ir.ONAME {
+ // We don't have the right position for ONAME nodes (see #15459 and
+ // others). Using ncase.Pos for now as it will provide the correct
+ // line number (assuming the expression follows the "case" keyword
+ // on the same line). This matches the approach before 1.10.
+ pos = ncase.Pos()
+ }
+ base.ErrorfAt(pos, "select case must be receive, send or assign recv")
+
+ case ir.OAS:
+ // convert x = <-c into x, _ = <-c
+ // remove implicit conversions; the eventual assignment
+ // will reintroduce them.
+ n := n.(*ir.AssignStmt)
+ if r := n.Y; r.Op() == ir.OCONVNOP || r.Op() == ir.OCONVIFACE {
+ r := r.(*ir.ConvExpr)
+ if r.Implicit() {
+ n.Y = r.X
+ }
+ }
+ if n.Y.Op() != ir.ORECV {
+ base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
+ break
+ }
+ oselrecv2(n.X, n.Y, n.Def)
+
+ case ir.OAS2RECV:
+ n := n.(*ir.AssignListStmt)
+ if n.Rhs[0].Op() != ir.ORECV {
+ base.ErrorfAt(n.Pos(), "select assignment must have receive on right hand side")
+ break
+ }
+ n.SetOp(ir.OSELRECV2)
+
+ case ir.ORECV:
+ // convert <-c into _, _ = <-c
+ n := n.(*ir.UnaryExpr)
+ oselrecv2(ir.BlankNode, n, false)
+
+ case ir.OSEND:
+ break
+ }
+ }
+
+ Stmts(ncase.Body)
+ }
+
+ base.Pos = lno
+}
+
+type typeSet struct {
+ m map[string][]typeSetEntry
+}
+
+func (s *typeSet) add(pos src.XPos, typ *types.Type) {
+ if s.m == nil {
+ s.m = make(map[string][]typeSetEntry)
+ }
+
+ // LongString does not uniquely identify types, so we need to
+ // disambiguate collisions with types.Identical.
+ // TODO(mdempsky): Add a method that *is* unique.
+ ls := typ.LongString()
+ prevs := s.m[ls]
+ for _, prev := range prevs {
+ if types.Identical(typ, prev.typ) {
+ base.ErrorfAt(pos, "duplicate case %v in type switch\n\tprevious case at %s", typ, base.FmtPos(prev.pos))
+ return
+ }
+ }
+ s.m[ls] = append(prevs, typeSetEntry{pos, typ})
+}
+
+type typeSetEntry struct {
+ pos src.XPos
+ typ *types.Type
+}
+
+func typecheckExprSwitch(n *ir.SwitchStmt) {
+ t := types.Types[types.TBOOL]
+ if n.Tag != nil {
+ n.Tag = Expr(n.Tag)
+ n.Tag = DefaultLit(n.Tag, nil)
+ t = n.Tag.Type()
+ }
+
+ var nilonly string
+ if t != nil {
+ switch {
+ case t.IsMap():
+ nilonly = "map"
+ case t.Kind() == types.TFUNC:
+ nilonly = "func"
+ case t.IsSlice():
+ nilonly = "slice"
+
+ case !types.IsComparable(t):
+ if t.IsStruct() {
+ base.ErrorfAt(n.Pos(), "cannot switch on %L (struct containing %v cannot be compared)", n.Tag, types.IncomparableField(t).Type)
+ } else {
+ base.ErrorfAt(n.Pos(), "cannot switch on %L", n.Tag)
+ }
+ t = nil
+ }
+ }
+
+ var defCase ir.Node
+ var cs constSet
+ for _, ncase := range n.Cases {
+ ncase := ncase.(*ir.CaseStmt)
+ ls := ncase.List
+ if len(ls) == 0 { // default:
+ if defCase != nil {
+ base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
+ } else {
+ defCase = ncase
+ }
+ }
+
+ for i := range ls {
+ ir.SetPos(ncase)
+ ls[i] = Expr(ls[i])
+ ls[i] = DefaultLit(ls[i], t)
+ n1 := ls[i]
+ if t == nil || n1.Type() == nil {
+ continue
+ }
+
+ if nilonly != "" && !ir.IsNil(n1) {
+ base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (can only compare %s %v to nil)", n1, nilonly, n.Tag)
+ } else if t.IsInterface() && !n1.Type().IsInterface() && !types.IsComparable(n1.Type()) {
+ base.ErrorfAt(ncase.Pos(), "invalid case %L in switch (incomparable type)", n1)
+ } else {
+ op1, _ := assignop(n1.Type(), t)
+ op2, _ := assignop(t, n1.Type())
+ if op1 == ir.OXXX && op2 == ir.OXXX {
+ if n.Tag != nil {
+ base.ErrorfAt(ncase.Pos(), "invalid case %v in switch on %v (mismatched types %v and %v)", n1, n.Tag, n1.Type(), t)
+ } else {
+ base.ErrorfAt(ncase.Pos(), "invalid case %v in switch (mismatched types %v and bool)", n1, n1.Type())
+ }
+ }
+ }
+
+ // Don't check for duplicate bools. Although the spec allows it,
+ // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and
+ // (2) it would disallow useful things like
+ // case GOARCH == "arm" && GOARM == "5":
+ // case GOARCH == "arm":
+ // which would both evaluate to false for non-ARM compiles.
+ if !n1.Type().IsBoolean() {
+ cs.add(ncase.Pos(), n1, "case", "switch")
+ }
+ }
+
+ Stmts(ncase.Body)
+ }
+}
+
+func typecheckTypeSwitch(n *ir.SwitchStmt) {
+ guard := n.Tag.(*ir.TypeSwitchGuard)
+ guard.X = Expr(guard.X)
+ t := guard.X.Type()
+ if t != nil && !t.IsInterface() {
+ base.ErrorfAt(n.Pos(), "cannot type switch on non-interface value %L", guard.X)
+ t = nil
+ }
+
+ // We don't actually declare the type switch's guarded
+ // declaration itself. So if there are no cases, we won't
+ // notice that it went unused.
+ if v := guard.Tag; v != nil && !ir.IsBlank(v) && len(n.Cases) == 0 {
+ base.ErrorfAt(v.Pos(), "%v declared but not used", v.Sym())
+ }
+
+ var defCase, nilCase ir.Node
+ var ts typeSet
+ for _, ncase := range n.Cases {
+ ncase := ncase.(*ir.CaseStmt)
+ ls := ncase.List
+ if len(ls) == 0 { // default:
+ if defCase != nil {
+ base.ErrorfAt(ncase.Pos(), "multiple defaults in switch (first at %v)", ir.Line(defCase))
+ } else {
+ defCase = ncase
+ }
+ }
+
+ for i := range ls {
+ ls[i] = check(ls[i], ctxExpr|ctxType)
+ n1 := ls[i]
+ if t == nil || n1.Type() == nil {
+ continue
+ }
+
+ var missing, have *types.Field
+ var ptr int
+ if ir.IsNil(n1) { // case nil:
+ if nilCase != nil {
+ base.ErrorfAt(ncase.Pos(), "multiple nil cases in type switch (first at %v)", ir.Line(nilCase))
+ } else {
+ nilCase = ncase
+ }
+ continue
+ }
+ if n1.Op() != ir.OTYPE {
+ base.ErrorfAt(ncase.Pos(), "%L is not a type", n1)
+ continue
+ }
+ if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke() {
+ if have != nil && !have.Broke() {
+ base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
+ " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", guard.X, n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else if ptr != 0 {
+ base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
+ " (%v method has pointer receiver)", guard.X, n1.Type(), missing.Sym)
+ } else {
+ base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+
+ " (missing %v method)", guard.X, n1.Type(), missing.Sym)
+ }
+ continue
+ }
+
+ ts.add(ncase.Pos(), n1.Type())
+ }
+
+ if len(ncase.Vars) != 0 {
+ // Assign the clause variable's type.
+ vt := t
+ if len(ls) == 1 {
+ if ls[0].Op() == ir.OTYPE {
+ vt = ls[0].Type()
+ } else if !ir.IsNil(ls[0]) {
+ // Invalid single-type case;
+ // mark variable as broken.
+ vt = nil
+ }
+ }
+
+ nvar := ncase.Vars[0]
+ nvar.SetType(vt)
+ if vt != nil {
+ nvar = AssignExpr(nvar)
+ } else {
+ // Clause variable is broken; prevent typechecking.
+ nvar.SetTypecheck(1)
+ nvar.SetWalkdef(1)
+ }
+ ncase.Vars[0] = nvar
+ }
+
+ Stmts(ncase.Body)
+ }
+}
+
+// typecheckswitch typechecks a switch statement.
+func typecheckswitch(n *ir.SwitchStmt) {
+ Stmts(n.Init())
+ if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
+ typecheckTypeSwitch(n)
+ } else {
+ typecheckExprSwitch(n)
+ }
+}
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+ "fmt"
+ "sort"
+ "strconv"
+ "strings"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+ "cmd/internal/src"
+)
+
+func AssignConv(n ir.Node, t *types.Type, context string) ir.Node {
+ return assignconvfn(n, t, func() string { return context })
+}
+
+// DotImportRefs maps idents introduced by importDot back to the
+// ir.PkgName they were dot-imported through.
+var DotImportRefs map[*ir.Ident]*ir.PkgName
+
+// LookupNum looks up the symbol starting with prefix and ending with
+// the decimal n. If prefix is too long, LookupNum panics.
+func LookupNum(prefix string, n int) *types.Sym {
+ var buf [20]byte // plenty long enough for all current users
+ copy(buf[:], prefix)
+ b := strconv.AppendInt(buf[:len(prefix)], int64(n), 10)
+ return types.LocalPkg.LookupBytes(b)
+}
+
+// Given funarg struct list, return list of fn args.
+func NewFuncParams(tl *types.Type, mustname bool) []*ir.Field {
+ var args []*ir.Field
+ gen := 0
+ for _, t := range tl.Fields().Slice() {
+ s := t.Sym
+ if mustname && (s == nil || s.Name == "_") {
+ // invent a name so that we can refer to it in the trampoline
+ s = LookupNum(".anon", gen)
+ gen++
+ }
+ a := ir.NewField(base.Pos, s, nil, t.Type)
+ a.Pos = t.Pos
+ a.IsDDD = t.IsDDD()
+ args = append(args, a)
+ }
+
+ return args
+}
+
+// newname returns a new ONAME Node associated with symbol s.
+func NewName(s *types.Sym) *ir.Name {
+ n := ir.NewNameAt(base.Pos, s)
+ n.Curfn = ir.CurFunc
+ return n
+}
+
+// NodAddr returns a node representing &n at base.Pos.
+func NodAddr(n ir.Node) *ir.AddrExpr {
+ return NodAddrAt(base.Pos, n)
+}
+
+// nodAddrPos returns a node representing &n at position pos.
+func NodAddrAt(pos src.XPos, n ir.Node) *ir.AddrExpr {
+ return ir.NewAddrExpr(pos, n)
+}
+
+func NodNil() ir.Node {
+ n := ir.NewNilExpr(base.Pos)
+ n.SetType(types.Types[types.TNIL])
+ return n
+}
+
+// in T.field
+// find missing fields that
+// will give shortest unique addressing.
+// modify the tree with missing type names.
+func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr {
+ n.X = check(n.X, ctxType|ctxExpr)
+ if n.X.Diag() {
+ n.SetDiag(true)
+ }
+ t := n.X.Type()
+ if t == nil {
+ return n
+ }
+
+ if n.X.Op() == ir.OTYPE {
+ return n
+ }
+
+ s := n.Sel
+ if s == nil {
+ return n
+ }
+
+ switch path, ambig := dotpath(s, t, nil, false); {
+ case path != nil:
+ // rebuild elided dots
+ for c := len(path) - 1; c >= 0; c-- {
+ dot := ir.NewSelectorExpr(base.Pos, ir.ODOT, n.X, path[c].field.Sym)
+ dot.SetImplicit(true)
+ dot.SetType(path[c].field.Type)
+ n.X = dot
+ }
+ case ambig:
+ base.Errorf("ambiguous selector %v", n)
+ n.X = nil
+ }
+
+ return n
+}
+
+func CalcMethods(t *types.Type) {
+ if t == nil || t.AllMethods().Len() != 0 {
+ return
+ }
+
+ // mark top-level method symbols
+ // so that expand1 doesn't consider them.
+ for _, f := range t.Methods().Slice() {
+ f.Sym.SetUniq(true)
+ }
+
+ // generate all reachable methods
+ slist = slist[:0]
+ expand1(t, true)
+
+ // check each method to be uniquely reachable
+ var ms []*types.Field
+ for i, sl := range slist {
+ slist[i].field = nil
+ sl.field.Sym.SetUniq(false)
+
+ var f *types.Field
+ path, _ := dotpath(sl.field.Sym, t, &f, false)
+ if path == nil {
+ continue
+ }
+
+ // dotpath may have dug out arbitrary fields, we only want methods.
+ if !f.IsMethod() {
+ continue
+ }
+
+ // add it to the base type method list
+ f = f.Copy()
+ f.Embedded = 1 // needs a trampoline
+ for _, d := range path {
+ if d.field.Type.IsPtr() {
+ f.Embedded = 2
+ break
+ }
+ }
+ ms = append(ms, f)
+ }
+
+ for _, f := range t.Methods().Slice() {
+ f.Sym.SetUniq(false)
+ }
+
+ ms = append(ms, t.Methods().Slice()...)
+ sort.Sort(types.MethodsByName(ms))
+ t.AllMethods().Set(ms)
+}
+
+// adddot1 returns the number of fields or methods named s at depth d in Type t.
+// If exactly one exists, it will be returned in *save (if save is not nil),
+// and dotlist will contain the path of embedded fields traversed to find it,
+// in reverse order. If none exist, more will indicate whether t contains any
+// embedded fields at depth d, so callers can decide whether to retry at
+// a greater depth.
+func adddot1(s *types.Sym, t *types.Type, d int, save **types.Field, ignorecase bool) (c int, more bool) {
+ if t.Recur() {
+ return
+ }
+ t.SetRecur(true)
+ defer t.SetRecur(false)
+
+ var u *types.Type
+ d--
+ if d < 0 {
+ // We've reached our target depth. If t has any fields/methods
+ // named s, then we're done. Otherwise, we still need to check
+ // below for embedded fields.
+ c = lookdot0(s, t, save, ignorecase)
+ if c != 0 {
+ return c, false
+ }
+ }
+
+ u = t
+ if u.IsPtr() {
+ u = u.Elem()
+ }
+ if !u.IsStruct() && !u.IsInterface() {
+ return c, false
+ }
+
+ for _, f := range u.Fields().Slice() {
+ if f.Embedded == 0 || f.Sym == nil {
+ continue
+ }
+ if d < 0 {
+ // Found an embedded field at target depth.
+ return c, true
+ }
+ a, more1 := adddot1(s, f.Type, d, save, ignorecase)
+ if a != 0 && c == 0 {
+ dotlist[d].field = f
+ }
+ c += a
+ if more1 {
+ more = true
+ }
+ }
+
+ return c, more
+}
+
+// dotlist is used by adddot1 to record the path of embedded fields
+// used to access a target field or method.
+// Must be non-nil so that dotpath returns a non-nil slice even if d is zero.
+var dotlist = make([]dlist, 10)
+
+// Convert node n for assignment to type t.
+func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node {
+ if n == nil || n.Type() == nil || n.Type().Broke() {
+ return n
+ }
+
+ if t.Kind() == types.TBLANK && n.Type().Kind() == types.TNIL {
+ base.Errorf("use of untyped nil")
+ }
+
+ n = convlit1(n, t, false, context)
+ if n.Type() == nil {
+ return n
+ }
+ if t.Kind() == types.TBLANK {
+ return n
+ }
+
+ // Convert ideal bool from comparison to plain bool
+ // if the next step is non-bool (like interface{}).
+ if n.Type() == types.UntypedBool && !t.IsBoolean() {
+ if n.Op() == ir.ONAME || n.Op() == ir.OLITERAL {
+ r := ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n)
+ r.SetType(types.Types[types.TBOOL])
+ r.SetTypecheck(1)
+ r.SetImplicit(true)
+ n = r
+ }
+ }
+
+ if types.Identical(n.Type(), t) {
+ return n
+ }
+
+ op, why := assignop(n.Type(), t)
+ if op == ir.OXXX {
+ base.Errorf("cannot use %L as type %v in %s%s", n, t, context(), why)
+ op = ir.OCONV
+ }
+
+ r := ir.NewConvExpr(base.Pos, op, t, n)
+ r.SetTypecheck(1)
+ r.SetImplicit(true)
+ return r
+}
+
+// Is type src assignment compatible to type dst?
+// If so, return op code to use in conversion.
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
+func assignop(src, dst *types.Type) (ir.Op, string) {
+ if src == dst {
+ return ir.OCONVNOP, ""
+ }
+ if src == nil || dst == nil || src.Kind() == types.TFORW || dst.Kind() == types.TFORW || src.Underlying() == nil || dst.Underlying() == nil {
+ return ir.OXXX, ""
+ }
+
+ // 1. src type is identical to dst.
+ if types.Identical(src, dst) {
+ return ir.OCONVNOP, ""
+ }
+
+ // 2. src and dst have identical underlying types
+ // and either src or dst is not a named type or
+ // both are empty interface types.
+ // For assignable but different non-empty interface types,
+ // we want to recompute the itab. Recomputing the itab ensures
+ // that itabs are unique (thus an interface with a compile-time
+ // type I has an itab with interface type I).
+ if types.Identical(src.Underlying(), dst.Underlying()) {
+ if src.IsEmptyInterface() {
+ // Conversion between two empty interfaces
+ // requires no code.
+ return ir.OCONVNOP, ""
+ }
+ if (src.Sym() == nil || dst.Sym() == nil) && !src.IsInterface() {
+ // Conversion between two types, at least one unnamed,
+ // needs no conversion. The exception is nonempty interfaces
+ // which need to have their itab updated.
+ return ir.OCONVNOP, ""
+ }
+ }
+
+ // 3. dst is an interface type and src implements dst.
+ if dst.IsInterface() && src.Kind() != types.TNIL {
+ var missing, have *types.Field
+ var ptr int
+ if implements(src, dst, &missing, &have, &ptr) {
+ // Call itabname so that (src, dst)
+ // gets added to itabs early, which allows
+ // us to de-virtualize calls through this
+ // type/interface pair later. See peekitabs in reflect.go
+ if types.IsDirectIface(src) && !dst.IsEmptyInterface() {
+ NeedITab(src, dst)
+ }
+
+ return ir.OCONVIFACE, ""
+ }
+
+ // we'll have complained about this method anyway, suppress spurious messages.
+ if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) {
+ return ir.OCONVIFACE, ""
+ }
+
+ var why string
+ if isptrto(src, types.TINTER) {
+ why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src)
+ } else if have != nil && have.Sym == missing.Sym && have.Nointerface() {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (%v method is marked 'nointerface')", src, dst, missing.Sym)
+ } else if have != nil && have.Sym == missing.Sym {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (wrong type for %v method)\n"+
+ "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else if ptr != 0 {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (%v method has pointer receiver)", src, dst, missing.Sym)
+ } else if have != nil {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)\n"+
+ "\t\thave %v%S\n\t\twant %v%S", src, dst, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
+ } else {
+ why = fmt.Sprintf(":\n\t%v does not implement %v (missing %v method)", src, dst, missing.Sym)
+ }
+
+ return ir.OXXX, why
+ }
+
+ if isptrto(dst, types.TINTER) {
+ why := fmt.Sprintf(":\n\t%v is pointer to interface, not interface", dst)
+ return ir.OXXX, why
+ }
+
+ if src.IsInterface() && dst.Kind() != types.TBLANK {
+ var missing, have *types.Field
+ var ptr int
+ var why string
+ if implements(dst, src, &missing, &have, &ptr) {
+ why = ": need type assertion"
+ }
+ return ir.OXXX, why
+ }
+
+ // 4. src is a bidirectional channel value, dst is a channel type,
+ // src and dst have identical element types, and
+ // either src or dst is not a named type.
+ if src.IsChan() && src.ChanDir() == types.Cboth && dst.IsChan() {
+ if types.Identical(src.Elem(), dst.Elem()) && (src.Sym() == nil || dst.Sym() == nil) {
+ return ir.OCONVNOP, ""
+ }
+ }
+
+ // 5. src is the predeclared identifier nil and dst is a nillable type.
+ if src.Kind() == types.TNIL {
+ switch dst.Kind() {
+ case types.TPTR,
+ types.TFUNC,
+ types.TMAP,
+ types.TCHAN,
+ types.TINTER,
+ types.TSLICE:
+ return ir.OCONVNOP, ""
+ }
+ }
+
+ // 6. rule about untyped constants - already converted by defaultlit.
+
+ // 7. Any typed value can be assigned to the blank identifier.
+ if dst.Kind() == types.TBLANK {
+ return ir.OCONVNOP, ""
+ }
+
+ return ir.OXXX, ""
+}
+
+// Can we convert a value of type src to a value of type dst?
+// If so, return op code to use in conversion (maybe OCONVNOP).
+// If not, return OXXX. In this case, the string return parameter may
+// hold a reason why. In all other cases, it'll be the empty string.
+// srcConstant indicates whether the value of type src is a constant.
+func convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) {
+ if src == dst {
+ return ir.OCONVNOP, ""
+ }
+ if src == nil || dst == nil {
+ return ir.OXXX, ""
+ }
+
+ // Conversions from regular to go:notinheap are not allowed
+ // (unless it's unsafe.Pointer). These are runtime-specific
+ // rules.
+ // (a) Disallow (*T) to (*U) where T is go:notinheap but U isn't.
+ if src.IsPtr() && dst.IsPtr() && dst.Elem().NotInHeap() && !src.Elem().NotInHeap() {
+ why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable), but %v is not", dst.Elem(), src.Elem())
+ return ir.OXXX, why
+ }
+ // (b) Disallow string to []T where T is go:notinheap.
+ if src.IsString() && dst.IsSlice() && dst.Elem().NotInHeap() && (dst.Elem().Kind() == types.ByteType.Kind() || dst.Elem().Kind() == types.RuneType.Kind()) {
+ why := fmt.Sprintf(":\n\t%v is incomplete (or unallocatable)", dst.Elem())
+ return ir.OXXX, why
+ }
+
+ // 1. src can be assigned to dst.
+ op, why := assignop(src, dst)
+ if op != ir.OXXX {
+ return op, why
+ }
+
+ // The rules for interfaces are no different in conversions
+ // than assignments. If interfaces are involved, stop now
+ // with the good message from assignop.
+ // Otherwise clear the error.
+ if src.IsInterface() || dst.IsInterface() {
+ return ir.OXXX, why
+ }
+
+ // 2. Ignoring struct tags, src and dst have identical underlying types.
+ if types.IdenticalIgnoreTags(src.Underlying(), dst.Underlying()) {
+ return ir.OCONVNOP, ""
+ }
+
+ // 3. src and dst are unnamed pointer types and, ignoring struct tags,
+ // their base types have identical underlying types.
+ if src.IsPtr() && dst.IsPtr() && src.Sym() == nil && dst.Sym() == nil {
+ if types.IdenticalIgnoreTags(src.Elem().Underlying(), dst.Elem().Underlying()) {
+ return ir.OCONVNOP, ""
+ }
+ }
+
+ // 4. src and dst are both integer or floating point types.
+ if (src.IsInteger() || src.IsFloat()) && (dst.IsInteger() || dst.IsFloat()) {
+ if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
+ return ir.OCONVNOP, ""
+ }
+ return ir.OCONV, ""
+ }
+
+ // 5. src and dst are both complex types.
+ if src.IsComplex() && dst.IsComplex() {
+ if types.SimType[src.Kind()] == types.SimType[dst.Kind()] {
+ return ir.OCONVNOP, ""
+ }
+ return ir.OCONV, ""
+ }
+
+ // Special case for constant conversions: any numeric
+ // conversion is potentially okay. We'll validate further
+ // within evconst. See #38117.
+ if srcConstant && (src.IsInteger() || src.IsFloat() || src.IsComplex()) && (dst.IsInteger() || dst.IsFloat() || dst.IsComplex()) {
+ return ir.OCONV, ""
+ }
+
+ // 6. src is an integer or has type []byte or []rune
+ // and dst is a string type.
+ if src.IsInteger() && dst.IsString() {
+ return ir.ORUNESTR, ""
+ }
+
+ if src.IsSlice() && dst.IsString() {
+ if src.Elem().Kind() == types.ByteType.Kind() {
+ return ir.OBYTES2STR, ""
+ }
+ if src.Elem().Kind() == types.RuneType.Kind() {
+ return ir.ORUNES2STR, ""
+ }
+ }
+
+ // 7. src is a string and dst is []byte or []rune.
+ // String to slice.
+ if src.IsString() && dst.IsSlice() {
+ if dst.Elem().Kind() == types.ByteType.Kind() {
+ return ir.OSTR2BYTES, ""
+ }
+ if dst.Elem().Kind() == types.RuneType.Kind() {
+ return ir.OSTR2RUNES, ""
+ }
+ }
+
+ // 8. src is a pointer or uintptr and dst is unsafe.Pointer.
+ if (src.IsPtr() || src.IsUintptr()) && dst.IsUnsafePtr() {
+ return ir.OCONVNOP, ""
+ }
+
+ // 9. src is unsafe.Pointer and dst is a pointer or uintptr.
+ if src.IsUnsafePtr() && (dst.IsPtr() || dst.IsUintptr()) {
+ return ir.OCONVNOP, ""
+ }
+
+ // src is map and dst is a pointer to corresponding hmap.
+ // This rule is needed for the implementation detail that
+ // go gc maps are implemented as a pointer to a hmap struct.
+ if src.Kind() == types.TMAP && dst.IsPtr() &&
+ src.MapType().Hmap == dst.Elem() {
+ return ir.OCONVNOP, ""
+ }
+
+ return ir.OXXX, ""
+}
+
+// Code to resolve elided DOTs in embedded types.
+
+// A dlist stores a pointer to a TFIELD Type embedded within
+// a TSTRUCT or TINTER Type.
+type dlist struct {
+ field *types.Field
+}
+
+// dotpath computes the unique shortest explicit selector path to fully qualify
+// a selection expression x.f, where x is of type t and f is the symbol s.
+// If no such path exists, dotpath returns nil.
+// If there are multiple shortest paths to the same depth, ambig is true.
+func dotpath(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) (path []dlist, ambig bool) {
+ // The embedding of types within structs imposes a tree structure onto
+ // types: structs parent the types they embed, and types parent their
+ // fields or methods. Our goal here is to find the shortest path to
+ // a field or method named s in the subtree rooted at t. To accomplish
+ // that, we iteratively perform depth-first searches of increasing depth
+ // until we either find the named field/method or exhaust the tree.
+ for d := 0; ; d++ {
+ if d > len(dotlist) {
+ dotlist = append(dotlist, dlist{})
+ }
+ if c, more := adddot1(s, t, d, save, ignorecase); c == 1 {
+ return dotlist[:d], false
+ } else if c > 1 {
+ return nil, true
+ } else if !more {
+ return nil, false
+ }
+ }
+}
+
+func expand0(t *types.Type) {
+ u := t
+ if u.IsPtr() {
+ u = u.Elem()
+ }
+
+ if u.IsInterface() {
+ for _, f := range u.Fields().Slice() {
+ if f.Sym.Uniq() {
+ continue
+ }
+ f.Sym.SetUniq(true)
+ slist = append(slist, symlink{field: f})
+ }
+
+ return
+ }
+
+ u = types.ReceiverBaseType(t)
+ if u != nil {
+ for _, f := range u.Methods().Slice() {
+ if f.Sym.Uniq() {
+ continue
+ }
+ f.Sym.SetUniq(true)
+ slist = append(slist, symlink{field: f})
+ }
+ }
+}
+
+func expand1(t *types.Type, top bool) {
+ if t.Recur() {
+ return
+ }
+ t.SetRecur(true)
+
+ if !top {
+ expand0(t)
+ }
+
+ u := t
+ if u.IsPtr() {
+ u = u.Elem()
+ }
+
+ if u.IsStruct() || u.IsInterface() {
+ for _, f := range u.Fields().Slice() {
+ if f.Embedded == 0 {
+ continue
+ }
+ if f.Sym == nil {
+ continue
+ }
+ expand1(f.Type, false)
+ }
+ }
+
+ t.SetRecur(false)
+}
+
+func ifacelookdot(s *types.Sym, t *types.Type, ignorecase bool) (m *types.Field, followptr bool) {
+ if t == nil {
+ return nil, false
+ }
+
+ path, ambig := dotpath(s, t, &m, ignorecase)
+ if path == nil {
+ if ambig {
+ base.Errorf("%v.%v is ambiguous", t, s)
+ }
+ return nil, false
+ }
+
+ for _, d := range path {
+ if d.field.Type.IsPtr() {
+ followptr = true
+ break
+ }
+ }
+
+ if !m.IsMethod() {
+ base.Errorf("%v.%v is a field, not a method", t, s)
+ return nil, followptr
+ }
+
+ return m, followptr
+}
+
+func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool {
+ t0 := t
+ if t == nil {
+ return false
+ }
+
+ if t.IsInterface() {
+ i := 0
+ tms := t.Fields().Slice()
+ for _, im := range iface.Fields().Slice() {
+ for i < len(tms) && tms[i].Sym != im.Sym {
+ i++
+ }
+ if i == len(tms) {
+ *m = im
+ *samename = nil
+ *ptr = 0
+ return false
+ }
+ tm := tms[i]
+ if !types.Identical(tm.Type, im.Type) {
+ *m = im
+ *samename = tm
+ *ptr = 0
+ return false
+ }
+ }
+
+ return true
+ }
+
+ t = types.ReceiverBaseType(t)
+ var tms []*types.Field
+ if t != nil {
+ CalcMethods(t)
+ tms = t.AllMethods().Slice()
+ }
+ i := 0
+ for _, im := range iface.Fields().Slice() {
+ if im.Broke() {
+ continue
+ }
+ for i < len(tms) && tms[i].Sym != im.Sym {
+ i++
+ }
+ if i == len(tms) {
+ *m = im
+ *samename, _ = ifacelookdot(im.Sym, t, true)
+ *ptr = 0
+ return false
+ }
+ tm := tms[i]
+ if tm.Nointerface() || !types.Identical(tm.Type, im.Type) {
+ *m = im
+ *samename = tm
+ *ptr = 0
+ return false
+ }
+ followptr := tm.Embedded == 2
+
+ // if pointer receiver in method,
+ // the method does not exist for value types.
+ rcvr := tm.Type.Recv().Type
+ if rcvr.IsPtr() && !t0.IsPtr() && !followptr && !types.IsInterfaceMethod(tm.Type) {
+ if false && base.Flag.LowerR != 0 {
+ base.Errorf("interface pointer mismatch")
+ }
+
+ *m = im
+ *samename = nil
+ *ptr = 1
+ return false
+ }
+ }
+
+ return true
+}
+
+func isptrto(t *types.Type, et types.Kind) bool {
+ if t == nil {
+ return false
+ }
+ if !t.IsPtr() {
+ return false
+ }
+ t = t.Elem()
+ if t == nil {
+ return false
+ }
+ if t.Kind() != et {
+ return false
+ }
+ return true
+}
+
+// lookdot0 returns the number of fields or methods named s associated
+// with Type t. If exactly one exists, it will be returned in *save
+// (if save is not nil).
+func lookdot0(s *types.Sym, t *types.Type, save **types.Field, ignorecase bool) int {
+ u := t
+ if u.IsPtr() {
+ u = u.Elem()
+ }
+
+ c := 0
+ if u.IsStruct() || u.IsInterface() {
+ for _, f := range u.Fields().Slice() {
+ if f.Sym == s || (ignorecase && f.IsMethod() && strings.EqualFold(f.Sym.Name, s.Name)) {
+ if save != nil {
+ *save = f
+ }
+ c++
+ }
+ }
+ }
+
+ u = t
+ if t.Sym() != nil && t.IsPtr() && !t.Elem().IsPtr() {
+ // If t is a defined pointer type, then x.m is shorthand for (*x).m.
+ u = t.Elem()
+ }
+ u = types.ReceiverBaseType(u)
+ if u != nil {
+ for _, f := range u.Methods().Slice() {
+ if f.Embedded == 0 && (f.Sym == s || (ignorecase && strings.EqualFold(f.Sym.Name, s.Name))) {
+ if save != nil {
+ *save = f
+ }
+ c++
+ }
+ }
+ }
+
+ return c
+}
+
+var slist []symlink
+
+// Code to help generate trampoline functions for methods on embedded
+// types. These are approx the same as the corresponding adddot
+// routines except that they expect to be called with unique tasks and
+// they return the actual methods.
+
+type symlink struct {
+ field *types.Field
+}
--- /dev/null
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package typecheck
+
+import (
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
+ "cmd/internal/obj"
+ "cmd/internal/src"
+)
+
+func LookupRuntime(name string) *ir.Name {
+ s := ir.Pkgs.Runtime.Lookup(name)
+ if s == nil || s.Def == nil {
+ base.Fatalf("syslook: can't find runtime.%s", name)
+ }
+ return ir.AsNode(s.Def).(*ir.Name)
+}
+
+// SubstArgTypes substitutes the given list of types for
+// successive occurrences of the "any" placeholder in the
+// type syntax expression n.Type.
+// The result of SubstArgTypes MUST be assigned back to old, e.g.
+// n.Left = SubstArgTypes(n.Left, t1, t2)
+func SubstArgTypes(old *ir.Name, types_ ...*types.Type) *ir.Name {
+ n := old.CloneName()
+
+ for _, t := range types_ {
+ types.CalcSize(t)
+ }
+ n.SetType(types.SubstAny(n.Type(), &types_))
+ if len(types_) > 0 {
+ base.Fatalf("substArgTypes: too many argument types")
+ }
+ return n
+}
+
+// AutoLabel generates a new Name node for use with
+// an automatically generated label.
+// prefix is a short mnemonic (e.g. ".s" for switch)
+// to help with debugging.
+// It should begin with "." to avoid conflicts with
+// user labels.
+func AutoLabel(prefix string) *types.Sym {
+ if prefix[0] != '.' {
+ base.Fatalf("autolabel prefix must start with '.', have %q", prefix)
+ }
+ fn := ir.CurFunc
+ if ir.CurFunc == nil {
+ base.Fatalf("autolabel outside function")
+ }
+ n := fn.Label
+ fn.Label++
+ return LookupNum(prefix, int(n))
+}
+
+func Lookup(name string) *types.Sym {
+ return types.LocalPkg.Lookup(name)
+}
+
+// loadsys loads the definitions for the low-level runtime functions,
+// so that the compiler can generate calls to them,
+// but does not make them visible to user code.
+func loadsys() {
+ types.Block = 1
+
+ inimport = true
+ TypecheckAllowed = true
+
+ typs := runtimeTypes()
+ for _, d := range &runtimeDecls {
+ sym := ir.Pkgs.Runtime.Lookup(d.name)
+ typ := typs[d.typ]
+ switch d.tag {
+ case funcTag:
+ importfunc(ir.Pkgs.Runtime, src.NoXPos, sym, typ)
+ case varTag:
+ importvar(ir.Pkgs.Runtime, src.NoXPos, sym, typ)
+ default:
+ base.Fatalf("unhandled declaration tag %v", d.tag)
+ }
+ }
+
+ TypecheckAllowed = false
+ inimport = false
+}
+
+// LookupRuntimeFunc looks up Go function name in package runtime. This function
+// must follow the internal calling convention.
+func LookupRuntimeFunc(name string) *obj.LSym {
+ s := ir.Pkgs.Runtime.Lookup(name)
+ s.SetFunc(true)
+ return s.Linksym()
+}
+
+// LookupRuntimeVar looks up a variable (or assembly function) name in package
+// runtime. If this is a function, it may have a special calling
+// convention.
+func LookupRuntimeVar(name string) *obj.LSym {
+ return ir.Pkgs.Runtime.Lookup(name).Linksym()
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gc
+//go:generate go run mkbuiltin.go
+
+package typecheck
+
+import "cmd/compile/internal/ir"
+
+// Target is the package being compiled.
+var Target *ir.Package
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package gc
+package typecheck
import (
- "cmd/compile/internal/base"
- "cmd/compile/internal/ir"
- "cmd/compile/internal/types"
"fmt"
"go/constant"
"go/token"
"strings"
+
+ "cmd/compile/internal/base"
+ "cmd/compile/internal/ir"
+ "cmd/compile/internal/types"
)
+// Function collecting autotmps generated during typechecking,
+// to be included in the package-level init function.
+var InitTodoFunc = ir.NewFunc(base.Pos)
+
+var inimport bool // set during import
+
+var decldepth int32
+
+var TypecheckAllowed bool
+
var (
NeedFuncSym = func(*types.Sym) {}
NeedITab = func(t, itype *types.Type) {}
NeedRuntimeType = func(*types.Type) {}
)
-func TypecheckInit() {
+func Init() {
initUniverse()
- dclcontext = ir.PEXTERN
+ DeclContext = ir.PEXTERN
base.Timer.Start("fe", "loadsys")
loadsys()
}
-func TypecheckPackage() {
- finishUniverse()
+func Package() {
+ declareUniverse()
- typecheckok = true
+ TypecheckAllowed = true
// Process top-level declarations in phases.
for i := 0; i < len(Target.Decls); i++ {
n := Target.Decls[i]
if op := n.Op(); op != ir.ODCL && op != ir.OAS && op != ir.OAS2 && (op != ir.ODCLTYPE || !n.(*ir.Decl).X.Name().Alias()) {
- Target.Decls[i] = typecheck(n, ctxStmt)
+ Target.Decls[i] = Stmt(n)
}
}
for i := 0; i < len(Target.Decls); i++ {
n := Target.Decls[i]
if op := n.Op(); op == ir.ODCL || op == ir.OAS || op == ir.OAS2 || op == ir.ODCLTYPE && n.(*ir.Decl).X.Name().Alias() {
- Target.Decls[i] = typecheck(n, ctxStmt)
+ Target.Decls[i] = Stmt(n)
}
}
for i := 0; i < len(Target.Decls); i++ {
n := Target.Decls[i]
if n.Op() == ir.ODCLFUNC {
- TypecheckFuncBody(n.(*ir.Func))
+ FuncBody(n.(*ir.Func))
fcount++
}
}
base.Timer.Start("fe", "typecheck", "externdcls")
for i, n := range Target.Externs {
if n.Op() == ir.ONAME {
- Target.Externs[i] = typecheck(Target.Externs[i], ctxExpr)
+ Target.Externs[i] = Expr(Target.Externs[i])
}
}
// Phase 5: With all user code type-checked, it's now safe to verify map keys.
- checkMapKeys()
+ CheckMapKeys()
// Phase 6: Decide how to capture closed variables.
// This needs to run before escape analysis,
n := n.(*ir.Func)
if n.OClosure != nil {
ir.CurFunc = n
- capturevars(n)
+ CaptureVars(n)
}
}
}
- capturevarscomplete = true
+ CaptureVarsComplete = true
ir.CurFunc = nil
if base.Debug.TypecheckInl != 0 {
// Typecheck imported function bodies if Debug.l > 1,
// otherwise lazily when used or re-exported.
- TypecheckImports()
+ AllImportedBodies()
}
}
-func TypecheckAssignExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr|ctxAssign) }
-func TypecheckExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr) }
-func TypecheckStmt(n ir.Node) ir.Node { return typecheck(n, ctxStmt) }
+func AssignExpr(n ir.Node) ir.Node { return check(n, ctxExpr|ctxAssign) }
+func Expr(n ir.Node) ir.Node { return check(n, ctxExpr) }
+func Stmt(n ir.Node) ir.Node { return check(n, ctxStmt) }
-func TypecheckExprs(exprs []ir.Node) { typecheckslice(exprs, ctxExpr) }
-func TypecheckStmts(stmts []ir.Node) { typecheckslice(stmts, ctxStmt) }
+func Exprs(exprs []ir.Node) { typecheckslice(exprs, ctxExpr) }
+func Stmts(stmts []ir.Node) { typecheckslice(stmts, ctxStmt) }
-func TypecheckCall(call *ir.CallExpr) {
+func Call(call *ir.CallExpr) {
t := call.X.Type()
if t == nil {
panic("misuse of Call")
if t.NumResults() > 0 {
ctx = ctxExpr | ctxMultiOK
}
- if typecheck(call, ctx) != call {
+ if check(call, ctx) != call {
panic("bad typecheck")
}
}
-func TypecheckCallee(n ir.Node) ir.Node {
- return typecheck(n, ctxExpr|ctxCallee)
+func Callee(n ir.Node) ir.Node {
+ return check(n, ctxExpr|ctxCallee)
}
-func TypecheckFuncBody(n *ir.Func) {
+func FuncBody(n *ir.Func) {
ir.CurFunc = n
decldepth = 1
errorsBefore := base.Errors()
- typecheckslice(n.Body, ctxStmt)
- checkreturn(n)
+ Stmts(n.Body)
+ CheckReturn(n)
if base.Errors() > errorsBefore {
n.Body.Set(nil) // type errors; do not compile
}
var importlist []*ir.Func
-func TypecheckImports() {
+func AllImportedBodies() {
for _, n := range importlist {
if n.Inl != nil {
- typecheckinl(n)
+ ImportedBody(n)
}
}
}
var typecheckdefstack []ir.Node
-// resolve ONONAME to definition, if any.
-func resolve(n ir.Node) (res ir.Node) {
+// Resolve ONONAME to definition, if any.
+func Resolve(n ir.Node) (res ir.Node) {
if n == nil || n.Op() != ir.ONONAME {
return n
}
if sym := n.Sym(); sym.Pkg != types.LocalPkg {
// We might have an ir.Ident from oldname or importDot.
if id, ok := n.(*ir.Ident); ok {
- if pkgName := dotImportRefs[id]; pkgName != nil {
+ if pkgName := DotImportRefs[id]; pkgName != nil {
pkgName.Used = true
}
}
func typecheckslice(l []ir.Node, top int) {
for i := range l {
- l[i] = typecheck(l[i], top)
+ l[i] = check(l[i], top)
}
}
var typecheck_tcstack []ir.Node
-func typecheckFunc(fn *ir.Func) {
- new := typecheck(fn, ctxStmt)
+func Func(fn *ir.Func) {
+ new := Stmt(fn)
if new != fn {
base.Fatalf("typecheck changed func")
}
}
func typecheckNtype(n ir.Ntype) ir.Ntype {
- return typecheck(n, ctxType).(ir.Ntype)
+ return check(n, ctxType).(ir.Ntype)
}
-// typecheck type checks node n.
-// The result of typecheck MUST be assigned back to n, e.g.
-// n.Left = typecheck(n.Left, top)
-func typecheck(n ir.Node, top int) (res ir.Node) {
+// check type checks node n.
+// The result of check MUST be assigned back to n, e.g.
+// n.Left = check(n.Left, top)
+func check(n ir.Node, top int) (res ir.Node) {
// cannot type check until all the source has been parsed
- if !typecheckok {
+ if !TypecheckAllowed {
base.Fatalf("early typecheck")
}
}
// Resolve definition of name and value of iota lazily.
- n = resolve(n)
+ n = Resolve(n)
// Skip typecheck if already done.
// But re-typecheck ONAME/OTYPE/OLITERAL/OPACK node in case context has changed.
}
}
if t != nil {
- n = evalConst(n)
+ n = EvalConst(n)
t = n.Type()
}
// n.Left = indexlit(n.Left)
func indexlit(n ir.Node) ir.Node {
if n != nil && n.Type() != nil && n.Type().Kind() == types.TIDEAL {
- return defaultlit(n, types.Types[types.TINT])
+ return DefaultLit(n, types.Types[types.TINT])
}
return n
}
case ir.OTSLICE:
n := n.(*ir.SliceType)
- n.Elem = typecheck(n.Elem, ctxType)
+ n.Elem = check(n.Elem, ctxType)
if n.Elem.Type() == nil {
return n
}
case ir.OTARRAY:
n := n.(*ir.ArrayType)
- n.Elem = typecheck(n.Elem, ctxType)
+ n.Elem = check(n.Elem, ctxType)
if n.Elem.Type() == nil {
return n
}
}
return n
}
- n.Len = indexlit(typecheck(n.Len, ctxExpr))
+ n.Len = indexlit(Expr(n.Len))
size := n.Len
if ir.ConstType(size) != constant.Int {
switch {
case ir.OTMAP:
n := n.(*ir.MapType)
- n.Key = typecheck(n.Key, ctxType)
- n.Elem = typecheck(n.Elem, ctxType)
+ n.Key = check(n.Key, ctxType)
+ n.Elem = check(n.Elem, ctxType)
l := n.Key
r := n.Elem
if l.Type() == nil || r.Type() == nil {
case ir.OTCHAN:
n := n.(*ir.ChanType)
- n.Elem = typecheck(n.Elem, ctxType)
+ n.Elem = check(n.Elem, ctxType)
l := n.Elem
if l.Type() == nil {
return n
case ir.OTSTRUCT:
n := n.(*ir.StructType)
- n.SetOTYPE(tostruct(n.Fields))
+ n.SetOTYPE(NewStructType(n.Fields))
return n
case ir.OTINTER:
case ir.OTFUNC:
n := n.(*ir.FuncType)
- n.SetOTYPE(functype(n.Recv, n.Params, n.Results))
+ n.SetOTYPE(NewFuncType(n.Recv, n.Params, n.Results))
return n
// type or expr
case ir.ODEREF:
n := n.(*ir.StarExpr)
- n.X = typecheck(n.X, ctxExpr|ctxType)
+ n.X = check(n.X, ctxExpr|ctxType)
l := n.X
t := l.Type()
if t == nil {
l, r = n.X, n.Y
setLR = func() { n.X = l; n.Y = r }
}
- l = typecheck(l, ctxExpr)
- r = typecheck(r, ctxExpr)
+ l = Expr(l)
+ r = Expr(r)
setLR()
if l.Type() == nil || r.Type() == nil {
n.SetType(nil)
op = n.AsOp
}
if op == ir.OLSH || op == ir.ORSH {
- r = defaultlit(r, types.Types[types.TUINT])
+ r = DefaultLit(r, types.Types[types.TUINT])
setLR()
t := r.Type()
if !t.IsInteger() {
if iscmp[n.Op()] {
t = types.UntypedBool
n.SetType(t)
- if con := evalConst(n); con.Op() == ir.OLITERAL {
+ if con := EvalConst(n); con.Op() == ir.OLITERAL {
return con
}
l, r = defaultlit2(l, r, true)
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
l := n.X
t := l.Type()
if t == nil {
// exprs
case ir.OADDR:
n := n.(*ir.AddrExpr)
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
if n.X.Type() == nil {
n.SetType(nil)
return n
base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
}
r.Name().SetAddrtaken(true)
- if r.Name().IsClosureVar() && !capturevarscomplete {
+ if r.Name().IsClosureVar() && !CaptureVarsComplete {
// Mark the original variable as Addrtaken so that capturevars
// knows not to pass it by value.
// But if the capturevars phase is complete, don't touch it,
r.Name().Defn.Name().SetAddrtaken(true)
}
}
- n.X = defaultlit(n.X, nil)
+ n.X = DefaultLit(n.X, nil)
if n.X.Type() == nil {
n.SetType(nil)
return n
case ir.OXDOT, ir.ODOT:
n := n.(*ir.SelectorExpr)
if n.Op() == ir.OXDOT {
- n = adddot(n)
+ n = AddImplicitDots(n)
n.SetOp(ir.ODOT)
if n.X == nil {
n.SetType(nil)
}
}
- n.X = typecheck(n.X, ctxExpr|ctxType)
+ n.X = check(n.X, ctxExpr|ctxType)
- n.X = defaultlit(n.X, nil)
+ n.X = DefaultLit(n.X, nil)
t := n.X.Type()
if t == nil {
case ir.ODOTTYPE:
n := n.(*ir.TypeAssertExpr)
- n.X = typecheck(n.X, ctxExpr)
- n.X = defaultlit(n.X, nil)
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
l := n.X
t := l.Type()
if t == nil {
}
if n.Ntype != nil {
- n.Ntype = typecheck(n.Ntype, ctxType)
+ n.Ntype = check(n.Ntype, ctxType)
n.SetType(n.Ntype.Type())
n.Ntype = nil
if n.Type() == nil {
case ir.OINDEX:
n := n.(*ir.IndexExpr)
- n.X = typecheck(n.X, ctxExpr)
- n.X = defaultlit(n.X, nil)
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
n.X = implicitstar(n.X)
l := n.X
- n.Index = typecheck(n.Index, ctxExpr)
+ n.Index = Expr(n.Index)
r := n.Index
t := l.Type()
if t == nil || r.Type() == nil {
}
case types.TMAP:
- n.Index = assignconv(n.Index, t.Key(), "map index")
+ n.Index = AssignConv(n.Index, t.Key(), "map index")
n.SetType(t.Elem())
n.SetOp(ir.OINDEXMAP)
n.Assigned = false
case ir.ORECV:
n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
- n.X = defaultlit(n.X, nil)
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
l := n.X
t := l.Type()
if t == nil {
case ir.OSEND:
n := n.(*ir.SendStmt)
- n.Chan = typecheck(n.Chan, ctxExpr)
- n.Value = typecheck(n.Value, ctxExpr)
- n.Chan = defaultlit(n.Chan, nil)
+ n.Chan = Expr(n.Chan)
+ n.Value = Expr(n.Value)
+ n.Chan = DefaultLit(n.Chan, nil)
t := n.Chan.Type()
if t == nil {
return n
return n
}
- n.Value = assignconv(n.Value, t.Elem(), "send")
+ n.Value = AssignConv(n.Value, t.Elem(), "send")
if n.Value.Type() == nil {
return n
}
base.Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x)
}
- n.Ptr = typecheck(n.Ptr, ctxExpr)
- l := typecheck(n.LenCap[0], ctxExpr)
- c := typecheck(n.LenCap[1], ctxExpr)
- l = defaultlit(l, types.Types[types.TINT])
- c = defaultlit(c, types.Types[types.TINT])
+ n.Ptr = Expr(n.Ptr)
+ l := Expr(n.LenCap[0])
+ c := Expr(n.LenCap[1])
+ l = DefaultLit(l, types.Types[types.TINT])
+ c = DefaultLit(c, types.Types[types.TINT])
if ir.IsConst(l, constant.Int) && ir.Int64Val(l) < 0 {
base.Fatalf("len for OSLICEHEADER must be non-negative")
base.Fatalf("missing slice argument to copy for OMAKESLICECOPY")
}
- n.Len = typecheck(n.Len, ctxExpr)
- n.Cap = typecheck(n.Cap, ctxExpr)
+ n.Len = Expr(n.Len)
+ n.Cap = Expr(n.Cap)
- n.Len = defaultlit(n.Len, types.Types[types.TINT])
+ n.Len = DefaultLit(n.Len, types.Types[types.TINT])
if !n.Len.Type().IsInteger() && n.Type().Kind() != types.TIDEAL {
base.Errorf("non-integer len argument in OMAKESLICECOPY")
case ir.OSLICE, ir.OSLICE3:
n := n.(*ir.SliceExpr)
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
low, high, max := n.SliceBounds()
hasmax := n.Op().IsSlice3()
- low = typecheck(low, ctxExpr)
- high = typecheck(high, ctxExpr)
- max = typecheck(max, ctxExpr)
- n.X = defaultlit(n.X, nil)
+ low = Expr(low)
+ high = Expr(high)
+ max = Expr(max)
+ n.X = DefaultLit(n.X, nil)
low = indexlit(low)
high = indexlit(high)
max = indexlit(max)
return n
}
- addr := nodAddr(n.X)
+ addr := NodAddr(n.X)
addr.SetImplicit(true)
- n.X = typecheck(addr, ctxExpr)
+ n.X = Expr(addr)
l = n.X
}
t := l.Type()
if top == ctxStmt {
n.Use = ir.CallUseStmt
}
- typecheckslice(n.Init(), ctxStmt) // imported rewritten f(g()) calls (#30907)
- n.X = typecheck(n.X, ctxExpr|ctxType|ctxCallee)
+ Stmts(n.Init()) // imported rewritten f(g()) calls (#30907)
+ n.X = check(n.X, ctxExpr|ctxType|ctxCallee)
if n.X.Diag() {
n.SetDiag(true)
}
n.SetOp(l.BuiltinOp)
n.X = nil
n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
- return typecheck(n, top)
+ return check(n, top)
case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
typecheckargs(n)
return n
}
u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
- return typecheck(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
+ return check(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
case ir.OCOMPLEX, ir.OCOPY:
typecheckargs(n)
return n
}
b := ir.NewBinaryExpr(n.Pos(), l.BuiltinOp, arg1, arg2)
- return typecheck(ir.InitExpr(n.Init(), b), top) // typecheckargs can add to old.Init
+ return check(ir.InitExpr(n.Init(), b), top) // typecheckargs can add to old.Init
}
panic("unreachable")
}
- n.X = defaultlit(n.X, nil)
+ n.X = DefaultLit(n.X, nil)
l = n.X
if l.Op() == ir.OTYPE {
if n.IsDDD {
case ir.OCAP, ir.OLEN:
n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
- n.X = defaultlit(n.X, nil)
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
n.X = implicitstar(n.X)
l := n.X
t := l.Type()
case ir.OREAL, ir.OIMAG:
n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
l := n.X
t := l.Type()
if t == nil {
case ir.OCOMPLEX:
n := n.(*ir.BinaryExpr)
- l := typecheck(n.X, ctxExpr)
- r := typecheck(n.Y, ctxExpr)
+ l := Expr(n.X)
+ r := Expr(n.Y)
if l.Type() == nil || r.Type() == nil {
n.SetType(nil)
return n
case ir.OCLOSE:
n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
- n.X = defaultlit(n.X, nil)
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
l := n.X
t := l.Type()
if t == nil {
return n
}
- args[1] = assignconv(r, l.Type().Key(), "delete")
+ args[1] = AssignConv(r, l.Type().Key(), "delete")
return n
case ir.OAPPEND:
}
if t.Elem().IsKind(types.TUINT8) && args[1].Type().IsString() {
- args[1] = defaultlit(args[1], types.Types[types.TSTRING])
+ args[1] = DefaultLit(args[1], types.Types[types.TSTRING])
return n
}
- args[1] = assignconv(args[1], t.Underlying(), "append")
+ args[1] = AssignConv(args[1], t.Underlying(), "append")
return n
}
if n.Type() == nil {
continue
}
- as[i] = assignconv(n, t.Elem(), "append")
+ as[i] = AssignConv(n, t.Elem(), "append")
types.CheckSize(as[i].Type()) // ensure width is calculated for backend
}
return n
case ir.OCOPY:
n := n.(*ir.BinaryExpr)
n.SetType(types.Types[types.TINT])
- n.X = typecheck(n.X, ctxExpr)
- n.X = defaultlit(n.X, nil)
- n.Y = typecheck(n.Y, ctxExpr)
- n.Y = defaultlit(n.Y, nil)
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, nil)
+ n.Y = Expr(n.Y)
+ n.Y = DefaultLit(n.Y, nil)
if n.X.Type() == nil || n.Y.Type() == nil {
n.SetType(nil)
return n
case ir.OCONV:
n := n.(*ir.ConvExpr)
types.CheckSize(n.Type()) // ensure width is calculated for backend
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
n.X = convlit1(n.X, n.Type(), true, nil)
t := n.X.Type()
if t == nil || n.Type() == nil {
n.Args.Set(nil)
l := args[0]
- l = typecheck(l, ctxType)
+ l = check(l, ctxType)
t := l.Type()
if t == nil {
n.SetType(nil)
l = args[i]
i++
- l = typecheck(l, ctxExpr)
+ l = Expr(l)
var r ir.Node
if i < len(args) {
r = args[i]
i++
- r = typecheck(r, ctxExpr)
+ r = Expr(r)
}
if l.Type() == nil || (r != nil && r.Type() == nil) {
if i < len(args) {
l = args[i]
i++
- l = typecheck(l, ctxExpr)
- l = defaultlit(l, types.Types[types.TINT])
+ l = Expr(l)
+ l = DefaultLit(l, types.Types[types.TINT])
if l.Type() == nil {
n.SetType(nil)
return n
if i < len(args) {
l = args[i]
i++
- l = typecheck(l, ctxExpr)
- l = defaultlit(l, types.Types[types.TINT])
+ l = Expr(l)
+ l = DefaultLit(l, types.Types[types.TINT])
if l.Type() == nil {
n.SetType(nil)
return n
base.Fatalf("missing argument to new")
}
l := n.X
- l = typecheck(l, ctxType)
+ l = check(l, ctxType)
t := l.Type()
if t == nil {
n.SetType(nil)
for i1, n1 := range ls {
// Special case for print: int constant is int64, not int.
if ir.IsConst(n1, constant.Int) {
- ls[i1] = defaultlit(ls[i1], types.Types[types.TINT64])
+ ls[i1] = DefaultLit(ls[i1], types.Types[types.TINT64])
} else {
- ls[i1] = defaultlit(ls[i1], nil)
+ ls[i1] = DefaultLit(ls[i1], nil)
}
}
return n
case ir.OPANIC:
n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
- n.X = defaultlit(n.X, types.Types[types.TINTER])
+ n.X = Expr(n.X)
+ n.X = DefaultLit(n.X, types.Types[types.TINTER])
if n.X.Type() == nil {
n.SetType(nil)
return n
case ir.OITAB:
n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
t := n.X.Type()
if t == nil {
n.SetType(nil)
case ir.OSPTR:
n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
t := n.X.Type()
if t == nil {
n.SetType(nil)
case ir.OCFUNC:
n := n.(*ir.UnaryExpr)
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
n.SetType(types.Types[types.TUINTPTR])
return n
case ir.OCONVNOP:
n := n.(*ir.ConvExpr)
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
return n
// statements
case ir.OBLOCK:
n := n.(*ir.BlockStmt)
- typecheckslice(n.List, ctxStmt)
+ Stmts(n.List)
return n
case ir.OLABEL:
case ir.ODEFER, ir.OGO:
n := n.(*ir.GoDeferStmt)
- n.Call = typecheck(n.Call, ctxStmt|ctxExpr)
+ n.Call = check(n.Call, ctxStmt|ctxExpr)
if !n.Call.Diag() {
checkdefergo(n)
}
case ir.OFOR, ir.OFORUNTIL:
n := n.(*ir.ForStmt)
- typecheckslice(n.Init(), ctxStmt)
+ Stmts(n.Init())
decldepth++
- n.Cond = typecheck(n.Cond, ctxExpr)
- n.Cond = defaultlit(n.Cond, nil)
+ n.Cond = Expr(n.Cond)
+ n.Cond = DefaultLit(n.Cond, nil)
if n.Cond != nil {
t := n.Cond.Type()
if t != nil && !t.IsBoolean() {
base.Errorf("non-bool %L used as for condition", n.Cond)
}
}
- n.Post = typecheck(n.Post, ctxStmt)
+ n.Post = Stmt(n.Post)
if n.Op() == ir.OFORUNTIL {
- typecheckslice(n.Late, ctxStmt)
+ Stmts(n.Late)
}
- typecheckslice(n.Body, ctxStmt)
+ Stmts(n.Body)
decldepth--
return n
case ir.OIF:
n := n.(*ir.IfStmt)
- typecheckslice(n.Init(), ctxStmt)
- n.Cond = typecheck(n.Cond, ctxExpr)
- n.Cond = defaultlit(n.Cond, nil)
+ Stmts(n.Init())
+ n.Cond = Expr(n.Cond)
+ n.Cond = DefaultLit(n.Cond, nil)
if n.Cond != nil {
t := n.Cond.Type()
if t != nil && !t.IsBoolean() {
base.Errorf("non-bool %L used as if condition", n.Cond)
}
}
- typecheckslice(n.Body, ctxStmt)
- typecheckslice(n.Else, ctxStmt)
+ Stmts(n.Body)
+ Stmts(n.Else)
return n
case ir.ORETURN:
case ir.ODCLCONST:
n := n.(*ir.Decl)
- n.X = typecheck(n.X, ctxExpr)
+ n.X = Expr(n.X)
return n
case ir.ODCLTYPE:
n := n.(*ir.Decl)
- n.X = typecheck(n.X, ctxType)
+ n.X = check(n.X, ctxType)
types.CheckSize(n.X.Type())
return n
}
case *ir.CallExpr:
list = n.Args
if n.IsDDD {
- typecheckslice(list, ctxExpr)
+ Exprs(list)
return
}
case *ir.ReturnStmt:
list = n.Results
}
if len(list) != 1 {
- typecheckslice(list, ctxExpr)
+ Exprs(list)
return
}
// will reassociate them later when it's appropriate.
static := ir.CurFunc == nil
if static {
- ir.CurFunc = initTodo
+ ir.CurFunc = InitTodoFunc
}
list = nil
for _, f := range t.FieldSlice() {
- t := temp(f.Type)
+ t := Temp(f.Type)
as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, t))
as.Lhs.Append(t)
list = append(list, t)
n.Results.Set(list)
}
- n.PtrInit().Append(typecheck(as, ctxStmt))
+ n.PtrInit().Append(Stmt(as))
}
func checksliceindex(l ir.Node, r ir.Node, tp *types.Type) bool {
}
star := ir.NewStarExpr(base.Pos, n)
star.SetImplicit(true)
- return typecheck(star, ctxExpr)
+ return Expr(star)
}
func needOneArg(n *ir.CallExpr, f string, args ...interface{}) (ir.Node, bool) {
n.SetType(nil)
return n
}
- expandmeth(mt)
+ CalcMethods(mt)
ms = mt.AllMethods()
// The method expression T.m requires a wrapper when T
}
me := ir.NewMethodExpr(n.Pos(), n.X.Type(), m)
- me.SetType(methodfunc(m.Type, n.X.Type()))
+ me.SetType(NewMethodType(m.Type, n.X.Type()))
f := NewName(ir.MethodSym(t, m.Sym))
f.Class_ = ir.PFUNC
f.SetType(me.Type())
if n.X.Type().IsPtr() {
star := ir.NewStarExpr(base.Pos, n.X)
star.SetImplicit(true)
- n.X = typecheck(star, ctxExpr)
+ n.X = Expr(star)
}
n.SetOp(ir.ODOTINTER)
if !types.Identical(rcvr, tt) {
if rcvr.IsPtr() && types.Identical(rcvr.Elem(), tt) {
checklvalue(n.X, "call pointer method on")
- addr := nodAddr(n.X)
+ addr := NodAddr(n.X)
addr.SetImplicit(true)
- n.X = typecheck(addr, ctxType|ctxExpr)
+ n.X = check(addr, ctxType|ctxExpr)
} else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
star := ir.NewStarExpr(base.Pos, n.X)
star.SetImplicit(true)
- n.X = typecheck(star, ctxType|ctxExpr)
+ n.X = check(star, ctxType|ctxExpr)
} else if tt.IsPtr() && tt.Elem().IsPtr() && types.Identical(derefall(tt), derefall(rcvr)) {
base.Errorf("calling method %v with receiver %L requires explicit dereference", n.Sel, n.X)
for tt.IsPtr() {
}
star := ir.NewStarExpr(base.Pos, n.X)
star.SetImplicit(true)
- n.X = typecheck(star, ctxType|ctxExpr)
+ n.X = check(star, ctxType|ctxExpr)
tt = tt.Elem()
}
} else {
// For *T, return &T{...}.
n.Ntype = ir.TypeNode(t.Elem())
- addr := nodAddrAt(n.Pos(), n)
+ addr := NodAddrAt(n.Pos(), n)
addr.SetImplicit(true)
return addr
}
// Need to handle [...]T arrays specially.
if array, ok := n.Ntype.(*ir.ArrayType); ok && array.Elem != nil && array.Len == nil {
- array.Elem = typecheck(array.Elem, ctxType)
+ array.Elem = check(array.Elem, ctxType)
elemType := array.Elem.Type()
if elemType == nil {
n.SetType(nil)
return n
}
- n.Ntype = ir.Node(typecheck(n.Ntype, ctxType)).(ir.Ntype)
+ n.Ntype = ir.Node(check(n.Ntype, ctxType)).(ir.Ntype)
t := n.Ntype.Type()
if t == nil {
n.SetType(nil)
for i3, l := range n.List {
ir.SetPos(l)
if l.Op() != ir.OKEY {
- n.List[i3] = typecheck(l, ctxExpr)
+ n.List[i3] = Expr(l)
base.Errorf("missing key in map literal")
continue
}
r := l.Key
r = pushtype(r, t.Key())
- r = typecheck(r, ctxExpr)
- l.Key = assignconv(r, t.Key(), "map key")
+ r = Expr(r)
+ l.Key = AssignConv(r, t.Key(), "map key")
cs.add(base.Pos, l.Key, "key", "map literal")
r = l.Value
r = pushtype(r, t.Elem())
- r = typecheck(r, ctxExpr)
- l.Value = assignconv(r, t.Elem(), "map value")
+ r = Expr(r)
+ l.Value = AssignConv(r, t.Elem(), "map value")
}
n.SetOp(ir.OMAPLIT)
ls := n.List
for i, n1 := range ls {
ir.SetPos(n1)
- n1 = typecheck(n1, ctxExpr)
+ n1 = Expr(n1)
ls[i] = n1
if i >= t.NumFields() {
if !errored {
base.Errorf("implicit assignment of unexported field '%s' in %v literal", s.Name, t)
}
// No pushtype allowed here. Must name fields for that.
- n1 = assignconv(n1, f.Type, "field value")
+ n1 = AssignConv(n1, f.Type, "field value")
sk := ir.NewStructKeyExpr(base.Pos, f.Sym, n1)
sk.Offset = f.Offset
ls[i] = sk
// package, because of import dot. Redirect to correct sym
// before we do the lookup.
s := key.Sym()
- if id, ok := key.(*ir.Ident); ok && dotImportRefs[id] != nil {
- s = lookup(s.Name)
+ if id, ok := key.(*ir.Ident); ok && DotImportRefs[id] != nil {
+ s = Lookup(s.Name)
}
// An OXDOT uses the Sym field to hold
base.Errorf("mixture of field:value and value initializers")
errored = true
}
- ls[i] = typecheck(ls[i], ctxExpr)
+ ls[i] = Expr(ls[i])
continue
}
l := l.(*ir.StructKeyExpr)
l.Offset = f.Offset
// No pushtype allowed here. Tried and rejected.
- l.Value = typecheck(l.Value, ctxExpr)
- l.Value = assignconv(l.Value, f.Type, "field value")
+ l.Value = Expr(l.Value)
+ l.Value = AssignConv(l.Value, f.Type, "field value")
}
}
var kv *ir.KeyExpr
if elt.Op() == ir.OKEY {
elt := elt.(*ir.KeyExpr)
- elt.Key = typecheck(elt.Key, ctxExpr)
- key = indexconst(elt.Key)
+ elt.Key = Expr(elt.Key)
+ key = IndexConst(elt.Key)
if key < 0 {
if !elt.Key.Diag() {
if key == -2 {
}
r = pushtype(r, elemType)
- r = typecheck(r, ctxExpr)
- r = assignconv(r, elemType, ctx)
+ r = Expr(r)
+ r = AssignConv(r, elemType, ctx)
if kv != nil {
kv.Value = r
} else {
// if the variable has a type (ntype) then typechecking
// will not look at defn, so it is okay (and desirable,
// so that the conversion below happens).
- n.X = resolve(n.X)
+ n.X = Resolve(n.X)
if !ir.DeclaredBy(n.X, n) || n.X.Name().Ntype != nil {
- n.X = typecheck(n.X, ctxExpr|ctxAssign)
+ n.X = AssignExpr(n.X)
}
// Use ctxMultiOK so we can emit an "N variables but M values" error
// to be consistent with typecheckas2 (#26616).
- n.Y = typecheck(n.Y, ctxExpr|ctxMultiOK)
+ n.Y = check(n.Y, ctxExpr|ctxMultiOK)
checkassign(n, n.X)
if n.Y != nil && n.Y.Type() != nil {
if n.Y.Type().IsFuncArgStruct() {
// to indicate failed typechecking.
n.Y.SetType(nil)
} else if n.X.Type() != nil {
- n.Y = assignconv(n.Y, n.X.Type(), "assignment")
+ n.Y = AssignConv(n.Y, n.X.Type(), "assignment")
}
}
if ir.DeclaredBy(n.X, n) && n.X.Name().Ntype == nil {
- n.Y = defaultlit(n.Y, nil)
+ n.Y = DefaultLit(n.Y, nil)
n.X.SetType(n.Y.Type())
}
n.SetTypecheck(1)
if n.X.Typecheck() == 0 {
- n.X = typecheck(n.X, ctxExpr|ctxAssign)
+ n.X = AssignExpr(n.X)
}
if !ir.IsBlank(n.X) {
types.CheckSize(n.X.Type()) // ensure width is calculated for backend
ls := n.Lhs
for i1, n1 := range ls {
// delicate little dance.
- n1 = resolve(n1)
+ n1 = Resolve(n1)
ls[i1] = n1
if !ir.DeclaredBy(n1, n) || n1.Name().Ntype != nil {
- ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
+ ls[i1] = AssignExpr(ls[i1])
}
}
cl := len(n.Lhs)
cr := len(n.Rhs)
if cl > 1 && cr == 1 {
- n.Rhs[0] = typecheck(n.Rhs[0], ctxExpr|ctxMultiOK)
+ n.Rhs[0] = check(n.Rhs[0], ctxExpr|ctxMultiOK)
} else {
- typecheckslice(n.Rhs, ctxExpr)
+ Exprs(n.Rhs)
}
checkassignlist(n, n.Lhs)
for il, nl := range ls {
nr := rs[il]
if nl.Type() != nil && nr.Type() != nil {
- rs[il] = assignconv(nr, nl.Type(), "assignment")
+ rs[il] = AssignConv(nr, nl.Type(), "assignment")
}
if ir.DeclaredBy(nl, n) && nl.Name().Ntype == nil {
- rs[il] = defaultlit(rs[il], nil)
+ rs[il] = DefaultLit(rs[il], nil)
nl.SetType(rs[il].Type())
}
}
ls = n.Lhs
for i1, n1 := range ls {
if n1.Typecheck() == 0 {
- ls[i1] = typecheck(ls[i1], ctxExpr|ctxAssign)
+ ls[i1] = AssignExpr(ls[i1])
}
}
}
}
}
- n.Nname = typecheck(n.Nname, ctxExpr|ctxAssign).(*ir.Name)
+ n.Nname = AssignExpr(n.Nname).(*ir.Name)
t := n.Nname.Type()
if t == nil {
return
}
n.Nname.SetSym(ir.MethodSym(rcvr.Type, n.Shortname))
- declare(n.Nname, ir.PFUNC)
+ Declare(n.Nname, ir.PFUNC)
}
if base.Ctxt.Flag_dynlink && !inimport && n.Nname != nil {
nn := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(n.Type()).(ir.Ntype), nil)
nn.List.Set(l)
- return typecheck(nn, ctxExpr)
+ return Expr(nn)
}
var mapqueue []*ir.MapType
-func checkMapKeys() {
+func CheckMapKeys() {
for _, n := range mapqueue {
k := n.Type().MapType().Key
if !k.Broke() && !types.IsComparable(k) {
base.ErrorfAt(n.Pos(), "xxx")
}
- e = typecheck(e, ctxExpr)
+ e = Expr(e)
if e.Type() == nil {
goto ret
}
}
if n.Name().Defn.Op() == ir.ONAME {
- n.Name().Defn = typecheck(n.Name().Defn, ctxExpr)
+ n.Name().Defn = Expr(n.Name().Defn)
n.SetType(n.Name().Defn.Type())
break
}
- n.Name().Defn = typecheck(n.Name().Defn, ctxStmt) // fills in n.Type
+ n.Name().Defn = Stmt(n.Name().Defn) // fills in n.Type
case ir.OTYPE:
n := n.(*ir.Name)
// are the same as for index expressions. Factor the code better;
// for instance, indexlit might be called here and incorporate some
// of the bounds checks done for make.
- n = defaultlit(n, types.Types[types.TINT])
+ n = DefaultLit(n, types.Types[types.TINT])
*np = n
return true
return false
}
-// checkreturn makes sure that fn terminates appropriately.
-func checkreturn(fn *ir.Func) {
+// CheckReturn makes sure that fn terminates appropriately.
+func CheckReturn(fn *ir.Func) {
if fn.Type().NumResults() != 0 && len(fn.Body) != 0 {
markBreak(fn)
if !isTermNodes(fn.Body) {
}
return fnpkg(fn.Nname)
}
+
+func Conv(n ir.Node, t *types.Type) ir.Node {
+ if types.Identical(n.Type(), t) {
+ return n
+ }
+ n = ir.NewConvExpr(base.Pos, ir.OCONV, nil, n)
+ n.SetType(t)
+ n = Expr(n)
+ return n
+}
+
+// ConvNop converts node n to type t using the OCONVNOP op
+// and typechecks the result with ctxExpr.
+func ConvNop(n ir.Node, t *types.Type) ir.Node {
+ if types.Identical(n.Type(), t) {
+ return n
+ }
+ n = ir.NewConvExpr(base.Pos, ir.OCONVNOP, nil, n)
+ n.SetType(t)
+ n = Expr(n)
+ return n
+}
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// TODO(gri) This file should probably become part of package types.
-
-package gc
+package typecheck
import (
+ "go/constant"
+
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
"cmd/compile/internal/types"
"cmd/internal/src"
- "go/constant"
+)
+
+var (
+ okfor [ir.OEND][]bool
+ iscmp [ir.OEND]bool
+)
+
+var (
+ okforeq [types.NTYPE]bool
+ okforadd [types.NTYPE]bool
+ okforand [types.NTYPE]bool
+ okfornone [types.NTYPE]bool
+ okforbool [types.NTYPE]bool
+ okforcap [types.NTYPE]bool
+ okforlen [types.NTYPE]bool
+ okforarith [types.NTYPE]bool
)
var basicTypes = [...]struct {
s = types.BuiltinPkg.Lookup("false")
s.Def = ir.NewConstAt(src.NoXPos, s, types.UntypedBool, constant.MakeBool(false))
- s = lookup("_")
+ s = Lookup("_")
types.BlankSym = s
s.Block = -100
s.Def = NewName(s)
types.Types[types.TNIL] = types.New(types.TNIL)
s = types.BuiltinPkg.Lookup("nil")
- nnil := nodnil()
+ nnil := NodNil()
nnil.(*ir.NilExpr).SetSym(s)
s.Def = nnil
sig := types.NewSignature(types.NoPkg, fakeRecvField(), nil, []*types.Field{
types.NewField(src.NoXPos, nil, types.Types[types.TSTRING]),
})
- method := types.NewField(src.NoXPos, lookup("Error"), sig)
+ method := types.NewField(src.NoXPos, Lookup("Error"), sig)
return types.NewInterface(types.NoPkg, []*types.Field{method})
}
-// finishUniverse makes the universe block visible within the current package.
-func finishUniverse() {
+// declareUniverse makes the universe block visible within the current package.
+func declareUniverse() {
// Operationally, this is similar to a dot import of builtinpkg, except
// that we silently skip symbols that are already declared in the
// package block rather than emitting a redeclared symbol error.
if s.Def == nil {
continue
}
- s1 := lookup(s.Name)
+ s1 := Lookup(s.Name)
if s1.Def != nil {
continue
}
s1.Block = s.Block
}
- ir.RegFP = NewName(lookup(".fp"))
+ ir.RegFP = NewName(Lookup(".fp"))
ir.RegFP.SetType(types.Types[types.TINT32])
ir.RegFP.Class_ = ir.PPARAM
ir.RegFP.SetUsed(true)