1
0
mirror of https://github.com/golang/go synced 2024-11-11 20:01:37 -07:00

[dev.regabi] cmd/compile: split up typecheck1 [generated]

typecheck1 is the largest non-machine-generated function in the compiler.
weighing in at 1,747 lines. Since we are destroying the git blame history
anyway, now is a good time to split each different case into its own function,
making future work on this function more manageable.

[git-generate]
cd src/cmd/compile/internal/typecheck
rf '
	# Remove tracing print from typecheck1 - the one in typecheck is fine.
	# Removing it lets us remove the named result.
	# That lets all the cut-out functions not have named results.
	rm typecheck.go:/^func typecheck1/+0,/^func typecheck1/+4
	sub typecheck.go:/^func typecheck1/+/\(res ir\.Node\)/ ir.Node

	mv typecheckselect tcSelect
	mv typecheckswitch tcSwitch
	mv typecheckrange tcRange
	mv typecheckfunc tcFunc
	mv checkdefergo tcGoDefer
	mv typecheckclosure tcClosure
	mv check typecheck
	mv typecheckcomplit tcCompLit
	mv typecheckas tcAssign
	mv typecheckas2 tcAssignList
	mv typecheckpartialcall tcCallPart
	mv typecheckExprSwitch tcSwitchExpr
	mv typecheckTypeSwitch tcSwitchType

	mv typecheck1:/^\tcase ir.ORETURN:/+2,/^\tcase /-2 tcReturn
	add typecheck.go:/^func tcReturn/-0 \
		// tcReturn typechecks an ORETURN node.
	mv typecheck1:/^\tcase ir.OIF:/+2,/^\tcase /-2 tcIf
	add typecheck.go:/^func tcIf/-0 \
		// tcIf typechecks an OIF node.
	mv typecheck1:/^\tcase ir.OFOR,/+2,/^\tcase /-2 tcFor
	add typecheck.go:/^func tcFor/-0 \
		// tcFor typechecks an OFOR node.
	mv typecheck1:/^\tcase ir.OSPTR:/+2,/^\tcase /-2 tcSPtr
	add typecheck.go:/^func tcSPtr/-0 \
		// tcSPtr typechecks an OSPTR node.
	mv typecheck1:/^\tcase ir.OITAB:/+2,/^\tcase /-2 tcITab
	add typecheck.go:/^func tcITab/-0 \
		// tcITab typechecks an OITAB node.
	mv typecheck1:/^\tcase ir.ORECOVER:/+2,/^\tcase /-2 tcRecover
	add typecheck.go:/^func tcRecover/-0 \
		// tcRecover typechecks an ORECOVER node.
	mv typecheck1:/^\tcase ir.OPANIC:/+2,/^\tcase /-2 tcPanic
	add typecheck.go:/^func tcPanic/-0 \
		// tcPanic typechecks an OPANIC node.
	mv typecheck1:/^\tcase ir.OPRINT,/+2,/^\tcase /-2 tcPrint
	add typecheck.go:/^func tcPrint/-0 \
		// tcPrint typechecks an OPRINT or OPRINTN node.
	mv typecheck1:/^\tcase ir.ONEW:/+2,/^\tcase /-2 tcNew
	add typecheck.go:/^func tcNew/-0 \
		// tcNew typechecks an ONEW node.
	mv typecheck1:/^\tcase ir.OMAKE:/+2,/^\tcase /-2 tcMake
	add typecheck.go:/^func tcMake/-0 \
		// tcMake typechecks an OMAKE node.
	mv typecheck1:/^\tcase ir.OCONV:/+2,/^\tcase /-2 tcConv
	add typecheck.go:/^func tcConv/-0 \
		// tcConv typechecks an OCONV node.
	mv typecheck1:/^\tcase ir.OCOPY:/+2,/^\tcase /-2 tcCopy
	add typecheck.go:/^func tcCopy/-0 \
		// tcCopy typechecks an OCOPY node.
	mv typecheck1:/^\tcase ir.OAPPEND:/+2,/^\tcase /-2 tcAppend
	add typecheck.go:/^func tcAppend/-0 \
		// tcAppend typechecks an OAPPEND node.
	mv typecheck1:/^\tcase ir.ODELETE:/+2,/^\tcase /-2 tcDelete
	add typecheck.go:/^func tcDelete/-0 \
		// tcDelete typechecks an ODELETE node.
	mv typecheck1:/^\tcase ir.OCLOSE:/+2,/^\tcase /-2 tcClose
	add typecheck.go:/^func tcClose/-0 \
		// tcClose typechecks an OCLOSE node.
	mv typecheck1:/^\tcase ir.OCOMPLEX:/+2,/^\tcase /-2 tcComplex
	add typecheck.go:/^func tcComplex/-0 \
		// tcComplex typechecks an OCOMPLEX node.
	mv typecheck1:/^\tcase ir.OREAL,/+2,/^\tcase /-2 tcRealImag
	add typecheck.go:/^func tcRealImag/-0 \
		// tcRealImag typechecks an OREAL or OIMAG node.
	mv typecheck1:/^\tcase ir.OCAP,/+2,/^\tcase /-2 tcLenCap
	add typecheck.go:/^func tcLenCap/-0 \
		// tcLenCap typechecks an OLEN or OCAP node.
	mv typecheck1:/^\tcase ir.OCALL:/+2,/^\tcase /-2 tcCall
	add typecheck.go:/^func tcCall/-0 \
		// tcCall typechecks an OCALL node.
	mv typecheck1:/^\tcase ir.OSLICE,/+2,/^\tcase /-3 tcSlice
	add typecheck.go:/^func tcSlice/-0 \
		// tcSlice typechecks an OSLICE or OSLICE3 node.
	# move type assertion above comment
	mv typecheck1:/^\tcase ir.OMAKESLICECOPY:/+/n := n/-+ typecheck1:/^\tcase ir.OMAKESLICECOPY:/+0
	mv typecheck1:/^\tcase ir.OMAKESLICECOPY:/+2,/^\tcase /-2 tcMakeSliceCopy
	add typecheck.go:/^func tcMakeSliceCopy/-0 \
		// tcMakeSliceCopy typechecks an OMAKESLICECOPY node.
	# move type assertion above comment
	mv typecheck1:/^\tcase ir.OSLICEHEADER:/+/n := n/-+ typecheck1:/^\tcase ir.OSLICEHEADER:/+0
	mv typecheck1:/^\tcase ir.OSLICEHEADER:/+2,/^\tcase /-2 tcSliceHeader
	add typecheck.go:/^func tcSliceHeader/-0 \
		// tcSliceHeader typechecks an OSLICEHEADER node.
	mv typecheck1:/^\tcase ir.OSEND:/+2,/^\tcase /-2 tcSend
	add typecheck.go:/^func tcSend/-0 \
		// tcSend typechecks an OSEND node.
	mv typecheck1:/^\tcase ir.ORECV:/+2,/^\tcase /-2 tcRecv
	add typecheck.go:/^func tcRecv/-0 \
		// tcRecv typechecks an ORECV node.
	mv typecheck1:/^\tcase ir.OINDEX:/+2,/^\tcase /-2 tcIndex
	add typecheck.go:/^func tcIndex/-0 \
		// tcIndex typechecks an OINDEX node.
	mv typecheck1:/^\tcase ir.ODOTTYPE:/+2,/^\tcase /-2 tcDotType
	add typecheck.go:/^func tcDotType/-0 \
		// tcDotType typechecks an ODOTTYPE node.
	mv typecheck1:/^\tcase ir.OXDOT,/+2,/^\tcase /-2 tcDot
	add typecheck.go:/^func tcDot/-0 \
		// tcDot typechecks an OXDOT or ODOT node.
	mv typecheck1:/^\tcase ir.OADDR:/+2,/^\tcase /-2 tcAddr
	add typecheck.go:/^func tcAddr/-0 \
		// tcAddr typechecks an OADDR node.
	mv typecheck1:/^\tcase ir.OBITNOT,/+2,/^\tcase /-3 tcUnaryArith
	add typecheck.go:/^func tcUnaryArith/-0 \
		// tcUnaryArith typechecks a unary arithmetic expression.
	mv typecheck1:/^\t\tir.OXOR:/+1,/^\tcase /-2 tcArith
	add typecheck.go:/^func tcArith/-0 \
		// tcArith typechecks a binary arithmetic expression.
	mv typecheck1:/^\tcase ir.ODEREF:/+2,/^\tcase /-2 tcStar
	add typecheck.go:/^func tcStar/-0 \
		// tcStar typechecks an ODEREF node, which may be an expression or a type.
	mv typecheck1:/^\tcase ir.OTFUNC:/+2,/^\tcase /-2 tcFuncType
	add typecheck.go:/^func tcFuncType/-0 \
		// tcFuncType typechecks an OTFUNC node.
	mv typecheck1:/^\tcase ir.OTINTER:/+2,/^\tcase /-2 tcInterfaceType
	add typecheck.go:/^func tcInterfaceType/-0 \
		// tcInterfaceType typechecks an OTINTER node.
	mv typecheck1:/^\tcase ir.OTSTRUCT:/+2,/^\tcase /-2 tcStructType
	add typecheck.go:/^func tcStructType/-0 \
		// tcStructType typechecks an OTSTRUCT node.
	mv typecheck1:/^\tcase ir.OTCHAN:/+2,/^\tcase /-2 tcChanType
	add typecheck.go:/^func tcChanType/-0 \
		// tcChanType typechecks an OTCHAN node.
	mv typecheck1:/^\tcase ir.OTMAP:/+2,/^\tcase /-2 tcMapType
	add typecheck.go:/^func tcMapType/-0 \
		// tcMapType typechecks an OTMAP node.
	mv typecheck1:/^\tcase ir.OTARRAY:/+2,/^\tcase /-2 tcArrayType
	add typecheck.go:/^func tcArrayType/-0 \
		// tcArrayType typechecks an OTARRAY node.
	mv typecheck1:/^\tcase ir.OTSLICE:/+2,/^\tcase /-2 tcSliceType
	add typecheck.go:/^func tcSliceType/-0 \
		// tcSliceType typechecks an OTSLICE node.
	mv \
		tcAssign \
		tcAssignList \
		tcFor \
		tcGoDefer \
		tcIf \
		tcRange \
		tcReturn \
		tcSelect \
		tcSend \
		tcSwitch \
		tcSwitchExpr \
		tcSwitchType \
		typeSet \
		typeSetEntry \
		typeSet.add \
		stmt1.go
	mv stmt1.go stmt.go

	mv \
		tcAddr \
		tcArith \
		tcArrayType \
		tcChanType \
		tcClosure \
		tcCompLit \
		tcConv \
		tcDot \
		tcDotType \
		tcFuncType \
		tcITab \
		tcIndex \
		tcInterfaceType \
		tcLenCap \
		tcMapType \
		tcRecv \
		tcSPtr \
		tcSlice \
		tcSliceHeader \
		tcSliceType \
		tcStar \
		tcStructType \
		tcUnaryArith \
		expr.go

	mv \
		tcClosure \
		tcCallPart \
		tcFunc \
		tcCall \
		tcAppend \
		tcClose \
		tcComplex \
		tcCopy \
		tcDelete \
		tcMake \
		tcMakeSliceCopy \
		tcNew \
		tcPanic \
		tcPrint \
		tcRealImag \
		tcRecover \
		func1.go
	mv func1.go func.go

	mv \
		tcArrayType \
		tcChanType \
		tcFuncType \
		tcInterfaceType \
		tcMapType \
		tcSliceType \
		tcStructType \
		type.go
'

Change-Id: I0fb0a3039005bc1783575291daff1e6c306895ff
Reviewed-on: https://go-review.googlesource.com/c/go/+/279429
Trust: Russ Cox <rsc@golang.org>
Run-TryBot: Russ Cox <rsc@golang.org>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
Russ Cox 2020-12-23 00:43:42 -05:00
parent b9693d7627
commit 0256ba99a8
6 changed files with 2257 additions and 2042 deletions

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,8 @@ import (
"cmd/compile/internal/types"
"fmt"
"go/constant"
"go/token"
)
// package all the arguments that match a ... T parameter into a []T.
@ -156,66 +158,6 @@ func CaptureVars(fn *ir.Func) {
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) {
@ -380,7 +322,67 @@ func makepartialcall(dot *ir.SelectorExpr, t0 *types.Type, meth *types.Sym) *ir.
return fn
}
func typecheckpartialcall(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
// tcClosure 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 tcClosure(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)
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)
}
func tcCallPart(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
switch n.Op() {
case ir.ODOTINTER, ir.ODOTMETH:
break
@ -396,3 +398,632 @@ func typecheckpartialcall(n ir.Node, sym *types.Sym) *ir.CallPartExpr {
return ir.NewCallPartExpr(dot.Pos(), dot.X, dot.Selection, fn)
}
// type check function definition
// To be called by typecheck, not directly.
// (Call typecheckFunc instead.)
func tcFunc(n *ir.Func) {
if base.EnableTrace && base.Flag.LowerT {
defer tracePrint("typecheckfunc", n)(nil)
}
for _, ln := range n.Dcl {
if ln.Op() == ir.ONAME && (ln.Class_ == ir.PPARAM || ln.Class_ == ir.PPARAMOUT) {
ln.Decldepth = 1
}
}
n.Nname = AssignExpr(n.Nname).(*ir.Name)
t := n.Nname.Type()
if t == nil {
return
}
n.SetType(t)
rcvr := t.Recv()
if rcvr != nil && n.Shortname != nil {
m := addmethod(n, n.Shortname, t, true, n.Pragma&ir.Nointerface != 0)
if m == nil {
return
}
n.Nname.SetSym(ir.MethodSym(rcvr.Type, n.Shortname))
Declare(n.Nname, ir.PFUNC)
}
if base.Ctxt.Flag_dynlink && !inimport && n.Nname != nil {
NeedFuncSym(n.Sym())
}
}
// tcCall typechecks an OCALL node.
func tcCall(n *ir.CallExpr, top int) ir.Node {
n.Use = ir.CallUseExpr
if top == ctxStmt {
n.Use = ir.CallUseStmt
}
Stmts(n.Init()) // imported rewritten f(g()) calls (#30907)
n.X = typecheck(n.X, ctxExpr|ctxType|ctxCallee)
if n.X.Diag() {
n.SetDiag(true)
}
l := n.X
if l.Op() == ir.ONAME && l.(*ir.Name).BuiltinOp != 0 {
l := l.(*ir.Name)
if n.IsDDD && l.BuiltinOp != ir.OAPPEND {
base.Errorf("invalid use of ... with builtin %v", l)
}
// builtin: OLEN, OCAP, etc.
switch l.BuiltinOp {
default:
base.Fatalf("unknown builtin %v", l)
case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
n.SetOp(l.BuiltinOp)
n.X = nil
n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
return typecheck(n, top)
case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
typecheckargs(n)
fallthrough
case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
arg, ok := needOneArg(n, "%v", n.Op())
if !ok {
n.SetType(nil)
return n
}
u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
return typecheck(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
case ir.OCOMPLEX, ir.OCOPY:
typecheckargs(n)
arg1, arg2, ok := needTwoArgs(n)
if !ok {
n.SetType(nil)
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
}
panic("unreachable")
}
n.X = DefaultLit(n.X, nil)
l = n.X
if l.Op() == ir.OTYPE {
if n.IsDDD {
if !l.Type().Broke() {
base.Errorf("invalid use of ... in type conversion to %v", l.Type())
}
n.SetDiag(true)
}
// pick off before type-checking arguments
arg, ok := needOneArg(n, "conversion to %v", l.Type())
if !ok {
n.SetType(nil)
return n
}
n := ir.NewConvExpr(n.Pos(), ir.OCONV, nil, arg)
n.SetType(l.Type())
return typecheck1(n, top)
}
typecheckargs(n)
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
types.CheckSize(t)
switch l.Op() {
case ir.ODOTINTER:
n.SetOp(ir.OCALLINTER)
case ir.ODOTMETH:
l := l.(*ir.SelectorExpr)
n.SetOp(ir.OCALLMETH)
// typecheckaste was used here but there wasn't enough
// information further down the call chain to know if we
// were testing a method receiver for unexported fields.
// It isn't necessary, so just do a sanity check.
tp := t.Recv().Type
if l.X == nil || !types.Identical(l.X.Type(), tp) {
base.Fatalf("method receiver")
}
default:
n.SetOp(ir.OCALLFUNC)
if t.Kind() != types.TFUNC {
// TODO(mdempsky): Remove "o.Sym() != nil" once we stop
// using ir.Name for numeric literals.
if o := ir.Orig(l); o.Name() != nil && o.Sym() != nil && types.BuiltinPkg.Lookup(o.Sym().Name).Def != nil {
// be more specific when the non-function
// name matches a predeclared function
base.Errorf("cannot call non-function %L, declared at %s",
l, base.FmtPos(o.Name().Pos()))
} else {
base.Errorf("cannot call non-function %L", l)
}
n.SetType(nil)
return n
}
}
typecheckaste(ir.OCALL, n.X, n.IsDDD, t.Params(), n.Args, func() string { return fmt.Sprintf("argument to %v", n.X) })
if t.NumResults() == 0 {
return n
}
if t.NumResults() == 1 {
n.SetType(l.Type().Results().Field(0).Type)
if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME {
if sym := n.X.(*ir.Name).Sym(); types.IsRuntimePkg(sym.Pkg) && sym.Name == "getg" {
// Emit code for runtime.getg() directly instead of calling function.
// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
// so that the ordering pass can make sure to preserve the semantics of the original code
// (in particular, the exact time of the function call) by introducing temporaries.
// In this case, we know getg() always returns the same result within a given function
// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
n.SetOp(ir.OGETG)
}
}
return n
}
// multiple return
if top&(ctxMultiOK|ctxStmt) == 0 {
base.Errorf("multiple-value %v() in single-value context", l)
return n
}
n.SetType(l.Type().Results())
return n
}
// tcAppend typechecks an OAPPEND node.
func tcAppend(n *ir.CallExpr) ir.Node {
typecheckargs(n)
args := n.Args
if len(args) == 0 {
base.Errorf("missing arguments to append")
n.SetType(nil)
return n
}
t := args[0].Type()
if t == nil {
n.SetType(nil)
return n
}
n.SetType(t)
if !t.IsSlice() {
if ir.IsNil(args[0]) {
base.Errorf("first argument to append must be typed slice; have untyped nil")
n.SetType(nil)
return n
}
base.Errorf("first argument to append must be slice; have %L", t)
n.SetType(nil)
return n
}
if n.IsDDD {
if len(args) == 1 {
base.Errorf("cannot use ... on first argument to append")
n.SetType(nil)
return n
}
if len(args) != 2 {
base.Errorf("too many arguments to append")
n.SetType(nil)
return n
}
if t.Elem().IsKind(types.TUINT8) && args[1].Type().IsString() {
args[1] = DefaultLit(args[1], types.Types[types.TSTRING])
return n
}
args[1] = AssignConv(args[1], t.Underlying(), "append")
return n
}
as := args[1:]
for i, n := range as {
if n.Type() == nil {
continue
}
as[i] = AssignConv(n, t.Elem(), "append")
types.CheckSize(as[i].Type()) // ensure width is calculated for backend
}
return n
}
// tcClose typechecks an OCLOSE node.
func tcClose(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
n.X = DefaultLit(n.X, nil)
l := n.X
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
if !t.IsChan() {
base.Errorf("invalid operation: %v (non-chan type %v)", n, t)
n.SetType(nil)
return n
}
if !t.ChanDir().CanSend() {
base.Errorf("invalid operation: %v (cannot close receive-only channel)", n)
n.SetType(nil)
return n
}
return n
}
// tcComplex typechecks an OCOMPLEX node.
func tcComplex(n *ir.BinaryExpr) ir.Node {
l := Expr(n.X)
r := Expr(n.Y)
if l.Type() == nil || r.Type() == nil {
n.SetType(nil)
return n
}
l, r = defaultlit2(l, r, false)
if l.Type() == nil || r.Type() == nil {
n.SetType(nil)
return n
}
n.X = l
n.Y = r
if !types.Identical(l.Type(), r.Type()) {
base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
n.SetType(nil)
return n
}
var t *types.Type
switch l.Type().Kind() {
default:
base.Errorf("invalid operation: %v (arguments have type %v, expected floating-point)", n, l.Type())
n.SetType(nil)
return n
case types.TIDEAL:
t = types.UntypedComplex
case types.TFLOAT32:
t = types.Types[types.TCOMPLEX64]
case types.TFLOAT64:
t = types.Types[types.TCOMPLEX128]
}
n.SetType(t)
return n
}
// tcCopy typechecks an OCOPY node.
func tcCopy(n *ir.BinaryExpr) ir.Node {
n.SetType(types.Types[types.TINT])
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
}
// copy([]byte, string)
if n.X.Type().IsSlice() && n.Y.Type().IsString() {
if types.Identical(n.X.Type().Elem(), types.ByteType) {
return n
}
base.Errorf("arguments to copy have different element types: %L and string", n.X.Type())
n.SetType(nil)
return n
}
if !n.X.Type().IsSlice() || !n.Y.Type().IsSlice() {
if !n.X.Type().IsSlice() && !n.Y.Type().IsSlice() {
base.Errorf("arguments to copy must be slices; have %L, %L", n.X.Type(), n.Y.Type())
} else if !n.X.Type().IsSlice() {
base.Errorf("first argument to copy should be slice; have %L", n.X.Type())
} else {
base.Errorf("second argument to copy should be slice or string; have %L", n.Y.Type())
}
n.SetType(nil)
return n
}
if !types.Identical(n.X.Type().Elem(), n.Y.Type().Elem()) {
base.Errorf("arguments to copy have different element types: %L and %L", n.X.Type(), n.Y.Type())
n.SetType(nil)
return n
}
return n
}
// tcDelete typechecks an ODELETE node.
func tcDelete(n *ir.CallExpr) ir.Node {
typecheckargs(n)
args := n.Args
if len(args) == 0 {
base.Errorf("missing arguments to delete")
n.SetType(nil)
return n
}
if len(args) == 1 {
base.Errorf("missing second (key) argument to delete")
n.SetType(nil)
return n
}
if len(args) != 2 {
base.Errorf("too many arguments to delete")
n.SetType(nil)
return n
}
l := args[0]
r := args[1]
if l.Type() != nil && !l.Type().IsMap() {
base.Errorf("first argument to delete must be map; have %L", l.Type())
n.SetType(nil)
return n
}
args[1] = AssignConv(r, l.Type().Key(), "delete")
return n
}
// tcMake typechecks an OMAKE node.
func tcMake(n *ir.CallExpr) ir.Node {
args := n.Args
if len(args) == 0 {
base.Errorf("missing argument to make")
n.SetType(nil)
return n
}
n.Args.Set(nil)
l := args[0]
l = typecheck(l, ctxType)
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
i := 1
var nn ir.Node
switch t.Kind() {
default:
base.Errorf("cannot make type %v", t)
n.SetType(nil)
return n
case types.TSLICE:
if i >= len(args) {
base.Errorf("missing len argument to make(%v)", t)
n.SetType(nil)
return n
}
l = args[i]
i++
l = Expr(l)
var r ir.Node
if i < len(args) {
r = args[i]
i++
r = Expr(r)
}
if l.Type() == nil || (r != nil && r.Type() == nil) {
n.SetType(nil)
return n
}
if !checkmake(t, "len", &l) || r != nil && !checkmake(t, "cap", &r) {
n.SetType(nil)
return n
}
if ir.IsConst(l, constant.Int) && r != nil && ir.IsConst(r, constant.Int) && constant.Compare(l.Val(), token.GTR, r.Val()) {
base.Errorf("len larger than cap in make(%v)", t)
n.SetType(nil)
return n
}
nn = ir.NewMakeExpr(n.Pos(), ir.OMAKESLICE, l, r)
case types.TMAP:
if i < len(args) {
l = args[i]
i++
l = Expr(l)
l = DefaultLit(l, types.Types[types.TINT])
if l.Type() == nil {
n.SetType(nil)
return n
}
if !checkmake(t, "size", &l) {
n.SetType(nil)
return n
}
} else {
l = ir.NewInt(0)
}
nn = ir.NewMakeExpr(n.Pos(), ir.OMAKEMAP, l, nil)
nn.SetEsc(n.Esc())
case types.TCHAN:
l = nil
if i < len(args) {
l = args[i]
i++
l = Expr(l)
l = DefaultLit(l, types.Types[types.TINT])
if l.Type() == nil {
n.SetType(nil)
return n
}
if !checkmake(t, "buffer", &l) {
n.SetType(nil)
return n
}
} else {
l = ir.NewInt(0)
}
nn = ir.NewMakeExpr(n.Pos(), ir.OMAKECHAN, l, nil)
}
if i < len(args) {
base.Errorf("too many arguments to make(%v)", t)
n.SetType(nil)
return n
}
nn.SetType(t)
return nn
}
// tcMakeSliceCopy typechecks an OMAKESLICECOPY node.
func tcMakeSliceCopy(n *ir.MakeExpr) ir.Node {
// Errors here are Fatalf instead of Errorf because only the compiler
// can construct an OMAKESLICECOPY node.
// Components used in OMAKESCLICECOPY that are supplied by parsed source code
// have already been typechecked in OMAKE and OCOPY earlier.
t := n.Type()
if t == nil {
base.Fatalf("no type specified for OMAKESLICECOPY")
}
if !t.IsSlice() {
base.Fatalf("invalid type %v for OMAKESLICECOPY", n.Type())
}
if n.Len == nil {
base.Fatalf("missing len argument for OMAKESLICECOPY")
}
if n.Cap == nil {
base.Fatalf("missing slice argument to copy for OMAKESLICECOPY")
}
n.Len = Expr(n.Len)
n.Cap = Expr(n.Cap)
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")
}
if ir.IsConst(n.Len, constant.Int) {
if ir.ConstOverflow(n.Len.Val(), types.Types[types.TINT]) {
base.Fatalf("len for OMAKESLICECOPY too large")
}
if constant.Sign(n.Len.Val()) < 0 {
base.Fatalf("len for OMAKESLICECOPY must be non-negative")
}
}
return n
}
// tcNew typechecks an ONEW node.
func tcNew(n *ir.UnaryExpr) ir.Node {
if n.X == nil {
// Fatalf because the OCALL above checked for us,
// so this must be an internally-generated mistake.
base.Fatalf("missing argument to new")
}
l := n.X
l = typecheck(l, ctxType)
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
n.X = l
n.SetType(types.NewPtr(t))
return n
}
// tcPanic typechecks an OPANIC node.
func tcPanic(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
n.X = DefaultLit(n.X, types.Types[types.TINTER])
if n.X.Type() == nil {
n.SetType(nil)
return n
}
return n
}
// tcPrint typechecks an OPRINT or OPRINTN node.
func tcPrint(n *ir.CallExpr) ir.Node {
typecheckargs(n)
ls := n.Args
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])
} else {
ls[i1] = DefaultLit(ls[i1], nil)
}
}
return n
}
// tcRealImag typechecks an OREAL or OIMAG node.
func tcRealImag(n *ir.UnaryExpr) ir.Node {
n.X = Expr(n.X)
l := n.X
t := l.Type()
if t == nil {
n.SetType(nil)
return n
}
// Determine result type.
switch t.Kind() {
case types.TIDEAL:
n.SetType(types.UntypedFloat)
case types.TCOMPLEX64:
n.SetType(types.Types[types.TFLOAT32])
case types.TCOMPLEX128:
n.SetType(types.Types[types.TFLOAT64])
default:
base.Errorf("invalid argument %L for %v", l, n.Op())
n.SetType(nil)
return n
}
return n
}
// tcRecover typechecks an ORECOVER node.
func tcRecover(n *ir.CallExpr) ir.Node {
if len(n.Args) != 0 {
base.Errorf("too many arguments to recover")
n.SetType(nil)
return n
}
n.SetType(types.Types[types.TINTER])
return n
}

View File

@ -11,33 +11,6 @@ import (
"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)
@ -136,8 +109,326 @@ func typecheckrangeExpr(n *ir.RangeStmt) {
}
}
// type check assignment.
// if this assignment is the definition of a var on the left side,
// fill in the var's type.
func tcAssign(n *ir.AssignStmt) {
if base.EnableTrace && base.Flag.LowerT {
defer tracePrint("typecheckas", n)(nil)
}
// delicate little dance.
// the definition of n may refer to this assignment
// as its definition, in which case it will call typecheckas.
// in that case, do not call typecheck back, or it will cycle.
// 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)
if !ir.DeclaredBy(n.X, n) || n.X.Name().Ntype != nil {
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)
checkassign(n, n.X)
if n.Y != nil && n.Y.Type() != nil {
if n.Y.Type().IsFuncArgStruct() {
base.Errorf("assignment mismatch: 1 variable but %v returns %d values", n.Y.(*ir.CallExpr).X, n.Y.Type().NumFields())
// Multi-value RHS isn't actually valid for OAS; nil out
// to indicate failed typechecking.
n.Y.SetType(nil)
} else if n.X.Type() != nil {
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.X.SetType(n.Y.Type())
}
// second half of dance.
// now that right is done, typecheck the left
// just to get it over with. see dance above.
n.SetTypecheck(1)
if n.X.Typecheck() == 0 {
n.X = AssignExpr(n.X)
}
if !ir.IsBlank(n.X) {
types.CheckSize(n.X.Type()) // ensure width is calculated for backend
}
}
func tcAssignList(n *ir.AssignListStmt) {
if base.EnableTrace && base.Flag.LowerT {
defer tracePrint("typecheckas2", n)(nil)
}
ls := n.Lhs
for i1, n1 := range ls {
// delicate little dance.
n1 = Resolve(n1)
ls[i1] = n1
if !ir.DeclaredBy(n1, n) || n1.Name().Ntype != nil {
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)
} else {
Exprs(n.Rhs)
}
checkassignlist(n, n.Lhs)
var l ir.Node
var r ir.Node
if cl == cr {
// easy
ls := n.Lhs
rs := n.Rhs
for il, nl := range ls {
nr := rs[il]
if nl.Type() != nil && nr.Type() != nil {
rs[il] = AssignConv(nr, nl.Type(), "assignment")
}
if ir.DeclaredBy(nl, n) && nl.Name().Ntype == nil {
rs[il] = DefaultLit(rs[il], nil)
nl.SetType(rs[il].Type())
}
}
goto out
}
l = n.Lhs[0]
r = n.Rhs[0]
// x,y,z = f()
if cr == 1 {
if r.Type() == nil {
goto out
}
switch r.Op() {
case ir.OCALLMETH, ir.OCALLINTER, ir.OCALLFUNC:
if !r.Type().IsFuncArgStruct() {
break
}
cr = r.Type().NumFields()
if cr != cl {
goto mismatch
}
r.(*ir.CallExpr).Use = ir.CallUseList
n.SetOp(ir.OAS2FUNC)
for i, l := range n.Lhs {
f := r.Type().Field(i)
if f.Type != nil && l.Type() != nil {
checkassignto(f.Type, l)
}
if ir.DeclaredBy(l, n) && l.Name().Ntype == nil {
l.SetType(f.Type)
}
}
goto out
}
}
// x, ok = y
if cl == 2 && cr == 1 {
if r.Type() == nil {
goto out
}
switch r.Op() {
case ir.OINDEXMAP, ir.ORECV, ir.ODOTTYPE:
switch r.Op() {
case ir.OINDEXMAP:
n.SetOp(ir.OAS2MAPR)
case ir.ORECV:
n.SetOp(ir.OAS2RECV)
case ir.ODOTTYPE:
r := r.(*ir.TypeAssertExpr)
n.SetOp(ir.OAS2DOTTYPE)
r.SetOp(ir.ODOTTYPE2)
}
if l.Type() != nil {
checkassignto(r.Type(), l)
}
if ir.DeclaredBy(l, n) {
l.SetType(r.Type())
}
l := n.Lhs[1]
if l.Type() != nil && !l.Type().IsBoolean() {
checkassignto(types.Types[types.TBOOL], l)
}
if ir.DeclaredBy(l, n) && l.Name().Ntype == nil {
l.SetType(types.Types[types.TBOOL])
}
goto out
}
}
mismatch:
switch r.Op() {
default:
base.Errorf("assignment mismatch: %d variables but %d values", cl, cr)
case ir.OCALLFUNC, ir.OCALLMETH, ir.OCALLINTER:
r := r.(*ir.CallExpr)
base.Errorf("assignment mismatch: %d variables but %v returns %d values", cl, r.X, cr)
}
// second half of dance
out:
n.SetTypecheck(1)
ls = n.Lhs
for i1, n1 := range ls {
if n1.Typecheck() == 0 {
ls[i1] = AssignExpr(ls[i1])
}
}
}
// tcFor typechecks an OFOR node.
func tcFor(n *ir.ForStmt) ir.Node {
Stmts(n.Init())
decldepth++
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 = Stmt(n.Post)
if n.Op() == ir.OFORUNTIL {
Stmts(n.Late)
}
Stmts(n.Body)
decldepth--
return n
}
func tcGoDefer(n *ir.GoDeferStmt) {
what := "defer"
if n.Op() == ir.OGO {
what = "go"
}
switch n.Call.Op() {
// ok
case ir.OCALLINTER,
ir.OCALLMETH,
ir.OCALLFUNC,
ir.OCLOSE,
ir.OCOPY,
ir.ODELETE,
ir.OPANIC,
ir.OPRINT,
ir.OPRINTN,
ir.ORECOVER:
return
case ir.OAPPEND,
ir.OCAP,
ir.OCOMPLEX,
ir.OIMAG,
ir.OLEN,
ir.OMAKE,
ir.OMAKESLICE,
ir.OMAKECHAN,
ir.OMAKEMAP,
ir.ONEW,
ir.OREAL,
ir.OLITERAL: // conversion or unsafe.Alignof, Offsetof, Sizeof
if orig := ir.Orig(n.Call); orig.Op() == ir.OCONV {
break
}
base.ErrorfAt(n.Pos(), "%s discards result of %v", what, n.Call)
return
}
// type is broken or missing, most likely a method call on a broken type
// we will warn about the broken type elsewhere. no need to emit a potentially confusing error
if n.Call.Type() == nil || n.Call.Type().Broke() {
return
}
if !n.Diag() {
// The syntax made sure it was a call, so this must be
// a conversion.
n.SetDiag(true)
base.ErrorfAt(n.Pos(), "%s requires function call, not conversion", what)
}
}
// tcIf typechecks an OIF node.
func tcIf(n *ir.IfStmt) ir.Node {
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)
}
}
Stmts(n.Body)
Stmts(n.Else)
return n
}
// range
func tcRange(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--
}
// tcReturn typechecks an ORETURN node.
func tcReturn(n *ir.ReturnStmt) ir.Node {
typecheckargs(n)
if ir.CurFunc == nil {
base.Errorf("return outside function")
n.SetType(nil)
return n
}
if ir.HasNamedResults(ir.CurFunc) && len(n.Results) == 0 {
return n
}
typecheckaste(ir.ORETURN, nil, false, ir.CurFunc.Type().Results(), n.Results, func() string { return "return argument" })
return n
}
// select
func typecheckselect(sel *ir.SelectStmt) {
func tcSelect(sel *ir.SelectStmt) {
var def ir.Node
lno := ir.SetPos(sel)
Stmts(sel.Init())
@ -219,35 +510,43 @@ func typecheckselect(sel *ir.SelectStmt) {
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)
// tcSend typechecks an OSEND node.
func tcSend(n *ir.SendStmt) ir.Node {
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
}
if !t.IsChan() {
base.Errorf("invalid operation: %v (send to non-chan type %v)", n, t)
return n
}
// 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
if !t.ChanDir().CanSend() {
base.Errorf("invalid operation: %v (send to receive-only type %v)", n, t)
return n
}
n.Value = AssignConv(n.Value, t.Elem(), "send")
if n.Value.Type() == nil {
return n
}
s.m[ls] = append(prevs, typeSetEntry{pos, typ})
return n
}
type typeSetEntry struct {
pos src.XPos
typ *types.Type
// tcSwitch typechecks a switch statement.
func tcSwitch(n *ir.SwitchStmt) {
Stmts(n.Init())
if n.Tag != nil && n.Tag.Op() == ir.OTYPESW {
tcSwitchType(n)
} else {
tcSwitchExpr(n)
}
}
func typecheckExprSwitch(n *ir.SwitchStmt) {
func tcSwitchExpr(n *ir.SwitchStmt) {
t := types.Types[types.TBOOL]
if n.Tag != nil {
n.Tag = Expr(n.Tag)
@ -328,7 +627,7 @@ func typecheckExprSwitch(n *ir.SwitchStmt) {
}
}
func typecheckTypeSwitch(n *ir.SwitchStmt) {
func tcSwitchType(n *ir.SwitchStmt) {
guard := n.Tag.(*ir.TypeSwitchGuard)
guard.X = Expr(guard.X)
t := guard.X.Type()
@ -358,7 +657,7 @@ func typecheckTypeSwitch(n *ir.SwitchStmt) {
}
for i := range ls {
ls[i] = check(ls[i], ctxExpr|ctxType)
ls[i] = typecheck(ls[i], ctxExpr|ctxType)
n1 := ls[i]
if t == nil || n1.Type() == nil {
continue
@ -424,12 +723,30 @@ func typecheckTypeSwitch(n *ir.SwitchStmt) {
}
}
// 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)
}
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})
}

View File

@ -81,7 +81,7 @@ func NodNil() ir.Node {
// 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)
n.X = typecheck(n.X, ctxType|ctxExpr)
if n.X.Diag() {
n.SetDiag(true)
}

View File

@ -0,0 +1,122 @@
// 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"
)
// tcArrayType typechecks an OTARRAY node.
func tcArrayType(n *ir.ArrayType) ir.Node {
n.Elem = typecheck(n.Elem, ctxType)
if n.Elem.Type() == nil {
return n
}
if n.Len == nil { // [...]T
if !n.Diag() {
n.SetDiag(true)
base.Errorf("use of [...] array outside of array literal")
}
return n
}
n.Len = indexlit(Expr(n.Len))
size := n.Len
if ir.ConstType(size) != constant.Int {
switch {
case size.Type() == nil:
// Error already reported elsewhere.
case size.Type().IsInteger() && size.Op() != ir.OLITERAL:
base.Errorf("non-constant array bound %v", size)
default:
base.Errorf("invalid array bound %v", size)
}
return n
}
v := size.Val()
if ir.ConstOverflow(v, types.Types[types.TINT]) {
base.Errorf("array bound is too large")
return n
}
if constant.Sign(v) < 0 {
base.Errorf("array bound must be non-negative")
return n
}
bound, _ := constant.Int64Val(v)
t := types.NewArray(n.Elem.Type(), bound)
n.SetOTYPE(t)
types.CheckSize(t)
return n
}
// tcChanType typechecks an OTCHAN node.
func tcChanType(n *ir.ChanType) ir.Node {
n.Elem = typecheck(n.Elem, ctxType)
l := n.Elem
if l.Type() == nil {
return n
}
if l.Type().NotInHeap() {
base.Errorf("chan of incomplete (or unallocatable) type not allowed")
}
n.SetOTYPE(types.NewChan(l.Type(), n.Dir))
return n
}
// tcFuncType typechecks an OTFUNC node.
func tcFuncType(n *ir.FuncType) ir.Node {
n.SetOTYPE(NewFuncType(n.Recv, n.Params, n.Results))
return n
}
// tcInterfaceType typechecks an OTINTER node.
func tcInterfaceType(n *ir.InterfaceType) ir.Node {
n.SetOTYPE(tointerface(n.Methods))
return n
}
// tcMapType typechecks an OTMAP node.
func tcMapType(n *ir.MapType) ir.Node {
n.Key = typecheck(n.Key, ctxType)
n.Elem = typecheck(n.Elem, ctxType)
l := n.Key
r := n.Elem
if l.Type() == nil || r.Type() == nil {
return n
}
if l.Type().NotInHeap() {
base.Errorf("incomplete (or unallocatable) map key not allowed")
}
if r.Type().NotInHeap() {
base.Errorf("incomplete (or unallocatable) map value not allowed")
}
n.SetOTYPE(types.NewMap(l.Type(), r.Type()))
mapqueue = append(mapqueue, n) // check map keys when all types are settled
return n
}
// tcSliceType typechecks an OTSLICE node.
func tcSliceType(n *ir.SliceType) ir.Node {
n.Elem = typecheck(n.Elem, ctxType)
if n.Elem.Type() == nil {
return n
}
t := types.NewSlice(n.Elem.Type())
n.SetOTYPE(t)
types.CheckSize(t)
return n
}
// tcStructType typechecks an OTSTRUCT node.
func tcStructType(n *ir.StructType) ir.Node {
n.SetOTYPE(NewStructType(n.Fields))
return n
}

File diff suppressed because it is too large Load Diff