aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/typecheck/typecheck.go
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2020-12-23 00:43:42 -0500
committerRuss Cox <rsc@golang.org>2020-12-23 06:38:34 +0000
commit0256ba99a893f2faf870105fc93fff94e5caf241 (patch)
treec5bf15e6d6d6d68db1f3f7b01cb4d5fd696216e0 /src/cmd/compile/internal/typecheck/typecheck.go
parentb9693d7627089204e6c2448f543c3512d86dae70 (diff)
downloadgo-0256ba99a893f2faf870105fc93fff94e5caf241.tar.gz
go-0256ba99a893f2faf870105fc93fff94e5caf241.zip
[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>
Diffstat (limited to 'src/cmd/compile/internal/typecheck/typecheck.go')
-rw-r--r--src/cmd/compile/internal/typecheck/typecheck.go1984
1 files changed, 64 insertions, 1920 deletions
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index 2abf0a7824..bf43402d3d 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -122,9 +122,9 @@ func Package() {
}
}
-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 AssignExpr(n ir.Node) ir.Node { return typecheck(n, ctxExpr|ctxAssign) }
+func Expr(n ir.Node) ir.Node { return typecheck(n, ctxExpr) }
+func Stmt(n ir.Node) ir.Node { return typecheck(n, ctxStmt) }
func Exprs(exprs []ir.Node) { typecheckslice(exprs, ctxExpr) }
func Stmts(stmts []ir.Node) { typecheckslice(stmts, ctxStmt) }
@@ -138,13 +138,13 @@ func Call(call *ir.CallExpr) {
if t.NumResults() > 0 {
ctx = ctxExpr | ctxMultiOK
}
- if check(call, ctx) != call {
+ if typecheck(call, ctx) != call {
panic("bad typecheck")
}
}
func Callee(n ir.Node) ir.Node {
- return check(n, ctxExpr|ctxCallee)
+ return typecheck(n, ctxExpr|ctxCallee)
}
func FuncBody(n *ir.Func) {
@@ -277,7 +277,7 @@ func Resolve(n ir.Node) (res ir.Node) {
func typecheckslice(l []ir.Node, top int) {
for i := range l {
- l[i] = check(l[i], top)
+ l[i] = typecheck(l[i], top)
}
}
@@ -367,13 +367,13 @@ func Func(fn *ir.Func) {
}
func typecheckNtype(n ir.Ntype) ir.Ntype {
- return check(n, ctxType).(ir.Ntype)
+ return typecheck(n, ctxType).(ir.Ntype)
}
-// 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) {
+// 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) {
// cannot type check until all the source has been parsed
if !TypecheckAllowed {
base.Fatalf("early typecheck")
@@ -572,11 +572,7 @@ func indexlit(n ir.Node) ir.Node {
}
// typecheck1 should ONLY be called from typecheck.
-func typecheck1(n ir.Node, top int) (res ir.Node) {
- if base.EnableTrace && base.Flag.LowerT {
- defer tracePrint("typecheck1", n)(&res)
- }
-
+func typecheck1(n ir.Node, top int) ir.Node {
switch n.Op() {
case ir.OLITERAL, ir.ONAME, ir.ONONAME, ir.OTYPE:
if n.Sym() == nil {
@@ -653,136 +649,35 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
case ir.OTSLICE:
n := n.(*ir.SliceType)
- n.Elem = check(n.Elem, ctxType)
- if n.Elem.Type() == nil {
- return n
- }
- t := types.NewSlice(n.Elem.Type())
- n.SetOTYPE(t)
- types.CheckSize(t)
- return n
+ return tcSliceType(n)
case ir.OTARRAY:
n := n.(*ir.ArrayType)
- n.Elem = check(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
+ return tcArrayType(n)
case ir.OTMAP:
n := n.(*ir.MapType)
- 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 {
- 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
+ return tcMapType(n)
case ir.OTCHAN:
n := n.(*ir.ChanType)
- n.Elem = check(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
+ return tcChanType(n)
case ir.OTSTRUCT:
n := n.(*ir.StructType)
- n.SetOTYPE(NewStructType(n.Fields))
- return n
+ return tcStructType(n)
case ir.OTINTER:
n := n.(*ir.InterfaceType)
- n.SetOTYPE(tointerface(n.Methods))
- return n
+ return tcInterfaceType(n)
case ir.OTFUNC:
n := n.(*ir.FuncType)
- n.SetOTYPE(NewFuncType(n.Recv, n.Params, n.Results))
- return n
-
+ return tcFuncType(n)
// type or expr
case ir.ODEREF:
n := n.(*ir.StarExpr)
- n.X = check(n.X, ctxExpr|ctxType)
- l := n.X
- t := l.Type()
- if t == nil {
- n.SetType(nil)
- return n
- }
- if l.Op() == ir.OTYPE {
- n.SetOTYPE(types.NewPtr(l.Type()))
- // Ensure l.Type gets dowidth'd for the backend. Issue 20174.
- types.CheckSize(l.Type())
- return n
- }
-
- if !t.IsPtr() {
- if top&(ctxExpr|ctxStmt) != 0 {
- base.Errorf("invalid indirect of %L", n.X)
- n.SetType(nil)
- return n
- }
- base.Errorf("%v is not a type", l)
- return n
- }
-
- n.SetType(t.Elem())
- return n
-
+ return tcStar(n, top)
// arithmetic exprs
case ir.OASOP,
ir.OADD,
@@ -804,858 +699,56 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
ir.OOROR,
ir.OSUB,
ir.OXOR:
- var l, r ir.Node
- var setLR func()
- switch n := n.(type) {
- case *ir.AssignOpStmt:
- l, r = n.X, n.Y
- setLR = func() { n.X = l; n.Y = r }
- case *ir.BinaryExpr:
- l, r = n.X, n.Y
- setLR = func() { n.X = l; n.Y = r }
- case *ir.LogicalExpr:
- l, r = n.X, n.Y
- setLR = func() { n.X = l; n.Y = r }
- }
- l = Expr(l)
- r = Expr(r)
- setLR()
- if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
- }
- op := n.Op()
- if n.Op() == ir.OASOP {
- n := n.(*ir.AssignOpStmt)
- checkassign(n, l)
- if n.IncDec && !okforarith[l.Type().Kind()] {
- base.Errorf("invalid operation: %v (non-numeric type %v)", n, l.Type())
- n.SetType(nil)
- return n
- }
- // TODO(marvin): Fix Node.EType type union.
- op = n.AsOp
- }
- if op == ir.OLSH || op == ir.ORSH {
- r = DefaultLit(r, types.Types[types.TUINT])
- setLR()
- t := r.Type()
- if !t.IsInteger() {
- base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type())
- n.SetType(nil)
- return n
- }
- if t.IsSigned() && !types.AllowsGoVersion(curpkg(), 1, 13) {
- base.ErrorfVers("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type())
- n.SetType(nil)
- return n
- }
- t = l.Type()
- if t != nil && t.Kind() != types.TIDEAL && !t.IsInteger() {
- base.Errorf("invalid operation: %v (shift of type %v)", n, t)
- n.SetType(nil)
- return n
- }
-
- // no defaultlit for left
- // the outer context gives the type
- n.SetType(l.Type())
- if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL {
- n.SetType(types.UntypedInt)
- }
- return n
- }
-
- // For "x == x && len(s)", it's better to report that "len(s)" (type int)
- // can't be used with "&&" than to report that "x == x" (type untyped bool)
- // can't be converted to int (see issue #41500).
- if n.Op() == ir.OANDAND || n.Op() == ir.OOROR {
- n := n.(*ir.LogicalExpr)
- if !n.X.Type().IsBoolean() {
- base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.X.Type()))
- n.SetType(nil)
- return n
- }
- if !n.Y.Type().IsBoolean() {
- base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(n.Y.Type()))
- n.SetType(nil)
- return n
- }
- }
-
- // ideal mixed with non-ideal
- l, r = defaultlit2(l, r, false)
- setLR()
-
- if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
- }
- t := l.Type()
- if t.Kind() == types.TIDEAL {
- t = r.Type()
- }
- et := t.Kind()
- if et == types.TIDEAL {
- et = types.TINT
- }
- aop := ir.OXXX
- if iscmp[n.Op()] && t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
- // comparison is okay as long as one side is
- // assignable to the other. convert so they have
- // the same type.
- //
- // the only conversion that isn't a no-op is concrete == interface.
- // in that case, check comparability of the concrete type.
- // The conversion allocates, so only do it if the concrete type is huge.
- converted := false
- if r.Type().Kind() != types.TBLANK {
- aop, _ = assignop(l.Type(), r.Type())
- if aop != ir.OXXX {
- if r.Type().IsInterface() && !l.Type().IsInterface() && !types.IsComparable(l.Type()) {
- base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(l.Type()))
- n.SetType(nil)
- return n
- }
-
- types.CalcSize(l.Type())
- if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 {
- l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
- l.SetTypecheck(1)
- setLR()
- }
-
- t = r.Type()
- converted = true
- }
- }
-
- if !converted && l.Type().Kind() != types.TBLANK {
- aop, _ = assignop(r.Type(), l.Type())
- if aop != ir.OXXX {
- if l.Type().IsInterface() && !r.Type().IsInterface() && !types.IsComparable(r.Type()) {
- base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(r.Type()))
- n.SetType(nil)
- return n
- }
-
- types.CalcSize(r.Type())
- if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 {
- r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
- r.SetTypecheck(1)
- setLR()
- }
-
- t = l.Type()
- }
- }
-
- et = t.Kind()
- }
-
- if t.Kind() != types.TIDEAL && !types.Identical(l.Type(), r.Type()) {
- l, r = defaultlit2(l, r, true)
- if l.Type() == nil || r.Type() == nil {
- n.SetType(nil)
- return n
- }
- if l.Type().IsInterface() == r.Type().IsInterface() || aop == 0 {
- base.Errorf("invalid operation: %v (mismatched types %v and %v)", n, l.Type(), r.Type())
- n.SetType(nil)
- return n
- }
- }
-
- if t.Kind() == types.TIDEAL {
- t = mixUntyped(l.Type(), r.Type())
- }
- if dt := defaultType(t); !okfor[op][dt.Kind()] {
- base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, op, typekind(t))
- n.SetType(nil)
- return n
- }
-
- // okfor allows any array == array, map == map, func == func.
- // restrict to slice/map/func == nil and nil == slice/map/func.
- if l.Type().IsArray() && !types.IsComparable(l.Type()) {
- base.Errorf("invalid operation: %v (%v cannot be compared)", n, l.Type())
- n.SetType(nil)
- return n
- }
-
- if l.Type().IsSlice() && !ir.IsNil(l) && !ir.IsNil(r) {
- base.Errorf("invalid operation: %v (slice can only be compared to nil)", n)
- n.SetType(nil)
- return n
- }
-
- if l.Type().IsMap() && !ir.IsNil(l) && !ir.IsNil(r) {
- base.Errorf("invalid operation: %v (map can only be compared to nil)", n)
- n.SetType(nil)
- return n
- }
-
- if l.Type().Kind() == types.TFUNC && !ir.IsNil(l) && !ir.IsNil(r) {
- base.Errorf("invalid operation: %v (func can only be compared to nil)", n)
- n.SetType(nil)
- return n
- }
-
- if l.Type().IsStruct() {
- if f := types.IncomparableField(l.Type()); f != nil {
- base.Errorf("invalid operation: %v (struct containing %v cannot be compared)", n, f.Type)
- n.SetType(nil)
- return n
- }
- }
-
- if iscmp[n.Op()] {
- t = types.UntypedBool
- n.SetType(t)
- if con := EvalConst(n); con.Op() == ir.OLITERAL {
- return con
- }
- l, r = defaultlit2(l, r, true)
- setLR()
- return n
- }
-
- if et == types.TSTRING && n.Op() == ir.OADD {
- // create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
- n := n.(*ir.BinaryExpr)
- var add *ir.AddStringExpr
- if l.Op() == ir.OADDSTR {
- add = l.(*ir.AddStringExpr)
- add.SetPos(n.Pos())
- } else {
- add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
- }
- if r.Op() == ir.OADDSTR {
- r := r.(*ir.AddStringExpr)
- add.List.Append(r.List.Take()...)
- } else {
- add.List.Append(r)
- }
- add.SetType(t)
- return add
- }
-
- if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
- if constant.Sign(r.Val()) == 0 {
- base.Errorf("division by zero")
- n.SetType(nil)
- return n
- }
- }
-
- n.SetType(t)
- return n
+ return tcArith(n)
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
n := n.(*ir.UnaryExpr)
- n.X = Expr(n.X)
- l := n.X
- t := l.Type()
- if t == nil {
- n.SetType(nil)
- return n
- }
- if !okfor[n.Op()][defaultType(t).Kind()] {
- base.Errorf("invalid operation: %v (operator %v not defined on %s)", n, n.Op(), typekind(t))
- n.SetType(nil)
- return n
- }
-
- n.SetType(t)
- return n
+ return tcUnaryArith(n)
// exprs
case ir.OADDR:
n := n.(*ir.AddrExpr)
- n.X = Expr(n.X)
- if n.X.Type() == nil {
- n.SetType(nil)
- return n
- }
-
- switch n.X.Op() {
- case ir.OARRAYLIT, ir.OMAPLIT, ir.OSLICELIT, ir.OSTRUCTLIT:
- n.SetOp(ir.OPTRLIT)
-
- default:
- checklvalue(n.X, "take the address of")
- r := ir.OuterValue(n.X)
- if r.Op() == ir.ONAME {
- r := r.(*ir.Name)
- if ir.Orig(r) != r {
- base.Fatalf("found non-orig name node %v", r) // TODO(mdempsky): What does this mean?
- }
- r.Name().SetAddrtaken(true)
- 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,
- // in case l.Name's containing function has not yet been compiled.
- r.Name().Defn.Name().SetAddrtaken(true)
- }
- }
- n.X = DefaultLit(n.X, nil)
- if n.X.Type() == nil {
- n.SetType(nil)
- return n
- }
- }
-
- n.SetType(types.NewPtr(n.X.Type()))
- return n
+ return tcAddr(n)
case ir.OCOMPLIT:
- return typecheckcomplit(n.(*ir.CompLitExpr))
+ return tcCompLit(n.(*ir.CompLitExpr))
case ir.OXDOT, ir.ODOT:
n := n.(*ir.SelectorExpr)
- if n.Op() == ir.OXDOT {
- n = AddImplicitDots(n)
- n.SetOp(ir.ODOT)
- if n.X == nil {
- n.SetType(nil)
- return n
- }
- }
-
- n.X = check(n.X, ctxExpr|ctxType)
-
- n.X = DefaultLit(n.X, nil)
-
- t := n.X.Type()
- if t == nil {
- base.UpdateErrorDot(ir.Line(n), fmt.Sprint(n.X), fmt.Sprint(n))
- n.SetType(nil)
- return n
- }
-
- s := n.Sel
-
- if n.X.Op() == ir.OTYPE {
- return typecheckMethodExpr(n)
- }
-
- if t.IsPtr() && !t.Elem().IsInterface() {
- t = t.Elem()
- if t == nil {
- n.SetType(nil)
- return n
- }
- n.SetOp(ir.ODOTPTR)
- types.CheckSize(t)
- }
-
- if n.Sel.IsBlank() {
- base.Errorf("cannot refer to blank field or method")
- n.SetType(nil)
- return n
- }
-
- if lookdot(n, t, 0) == nil {
- // Legitimate field or method lookup failed, try to explain the error
- switch {
- case t.IsEmptyInterface():
- base.Errorf("%v undefined (type %v is interface with no methods)", n, n.X.Type())
-
- case t.IsPtr() && t.Elem().IsInterface():
- // Pointer to interface is almost always a mistake.
- base.Errorf("%v undefined (type %v is pointer to interface, not interface)", n, n.X.Type())
-
- case lookdot(n, t, 1) != nil:
- // Field or method matches by name, but it is not exported.
- base.Errorf("%v undefined (cannot refer to unexported field or method %v)", n, n.Sel)
-
- default:
- if mt := lookdot(n, t, 2); mt != nil && visible(mt.Sym) { // Case-insensitive lookup.
- base.Errorf("%v undefined (type %v has no field or method %v, but does have %v)", n, n.X.Type(), n.Sel, mt.Sym)
- } else {
- base.Errorf("%v undefined (type %v has no field or method %v)", n, n.X.Type(), n.Sel)
- }
- }
- n.SetType(nil)
- return n
- }
-
- if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
- return typecheckpartialcall(n, s)
- }
- return n
+ return tcDot(n, top)
case ir.ODOTTYPE:
n := n.(*ir.TypeAssertExpr)
- 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.IsInterface() {
- base.Errorf("invalid type assertion: %v (non-interface type %v on left)", n, t)
- n.SetType(nil)
- return n
- }
-
- if n.Ntype != nil {
- n.Ntype = check(n.Ntype, ctxType)
- n.SetType(n.Ntype.Type())
- n.Ntype = nil
- if n.Type() == nil {
- return n
- }
- }
-
- if n.Type() != nil && !n.Type().IsInterface() {
- var missing, have *types.Field
- var ptr int
- if !implements(n.Type(), t, &missing, &have, &ptr) {
- if have != nil && have.Sym == missing.Sym {
- base.Errorf("impossible type assertion:\n\t%v does not implement %v (wrong type for %v method)\n"+
- "\t\thave %v%S\n\t\twant %v%S", n.Type(), t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
- } else if ptr != 0 {
- base.Errorf("impossible type assertion:\n\t%v does not implement %v (%v method has pointer receiver)", n.Type(), t, missing.Sym)
- } else if have != nil {
- base.Errorf("impossible type assertion:\n\t%v does not implement %v (missing %v method)\n"+
- "\t\thave %v%S\n\t\twant %v%S", n.Type(), t, missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type)
- } else {
- base.Errorf("impossible type assertion:\n\t%v does not implement %v (missing %v method)", n.Type(), t, missing.Sym)
- }
- n.SetType(nil)
- return n
- }
- }
- return n
+ return tcDotType(n)
case ir.OINDEX:
n := n.(*ir.IndexExpr)
- n.X = Expr(n.X)
- n.X = DefaultLit(n.X, nil)
- n.X = implicitstar(n.X)
- l := n.X
- n.Index = Expr(n.Index)
- r := n.Index
- t := l.Type()
- if t == nil || r.Type() == nil {
- n.SetType(nil)
- return n
- }
- switch t.Kind() {
- default:
- base.Errorf("invalid operation: %v (type %v does not support indexing)", n, t)
- n.SetType(nil)
- return n
-
- case types.TSTRING, types.TARRAY, types.TSLICE:
- n.Index = indexlit(n.Index)
- if t.IsString() {
- n.SetType(types.ByteType)
- } else {
- n.SetType(t.Elem())
- }
- why := "string"
- if t.IsArray() {
- why = "array"
- } else if t.IsSlice() {
- why = "slice"
- }
-
- if n.Index.Type() != nil && !n.Index.Type().IsInteger() {
- base.Errorf("non-integer %s index %v", why, n.Index)
- return n
- }
-
- if !n.Bounded() && ir.IsConst(n.Index, constant.Int) {
- x := n.Index.Val()
- if constant.Sign(x) < 0 {
- base.Errorf("invalid %s index %v (index must be non-negative)", why, n.Index)
- } else if t.IsArray() && constant.Compare(x, token.GEQ, constant.MakeInt64(t.NumElem())) {
- base.Errorf("invalid array index %v (out of bounds for %d-element array)", n.Index, t.NumElem())
- } else if ir.IsConst(n.X, constant.String) && constant.Compare(x, token.GEQ, constant.MakeInt64(int64(len(ir.StringVal(n.X))))) {
- base.Errorf("invalid string index %v (out of bounds for %d-byte string)", n.Index, len(ir.StringVal(n.X)))
- } else if ir.ConstOverflow(x, types.Types[types.TINT]) {
- base.Errorf("invalid %s index %v (index too large)", why, n.Index)
- }
- }
-
- case types.TMAP:
- n.Index = AssignConv(n.Index, t.Key(), "map index")
- n.SetType(t.Elem())
- n.SetOp(ir.OINDEXMAP)
- n.Assigned = false
- }
- return n
+ return tcIndex(n)
case ir.ORECV:
n := n.(*ir.UnaryExpr)
- 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 (receive from non-chan type %v)", n, t)
- n.SetType(nil)
- return n
- }
-
- if !t.ChanDir().CanRecv() {
- base.Errorf("invalid operation: %v (receive from send-only type %v)", n, t)
- n.SetType(nil)
- return n
- }
-
- n.SetType(t.Elem())
- return n
+ return tcRecv(n)
case ir.OSEND:
n := n.(*ir.SendStmt)
- 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
- }
-
- 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
- }
- return n
+ return tcSend(n)
case ir.OSLICEHEADER:
- // Errors here are Fatalf instead of Errorf because only the compiler
- // can construct an OSLICEHEADER node.
- // Components used in OSLICEHEADER that are supplied by parsed source code
- // have already been typechecked in e.g. OMAKESLICE earlier.
n := n.(*ir.SliceHeaderExpr)
- t := n.Type()
- if t == nil {
- base.Fatalf("no type specified for OSLICEHEADER")
- }
-
- if !t.IsSlice() {
- base.Fatalf("invalid type %v for OSLICEHEADER", n.Type())
- }
-
- if n.Ptr == nil || n.Ptr.Type() == nil || !n.Ptr.Type().IsUnsafePtr() {
- base.Fatalf("need unsafe.Pointer for OSLICEHEADER")
- }
-
- if x := len(n.LenCap); x != 2 {
- base.Fatalf("expected 2 params (len, cap) for OSLICEHEADER, got %d", x)
- }
-
- 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")
- }
-
- if ir.IsConst(c, constant.Int) && ir.Int64Val(c) < 0 {
- base.Fatalf("cap for OSLICEHEADER must be non-negative")
- }
-
- if ir.IsConst(l, constant.Int) && ir.IsConst(c, constant.Int) && constant.Compare(l.Val(), token.GTR, c.Val()) {
- base.Fatalf("len larger than cap for OSLICEHEADER")
- }
-
- n.LenCap[0] = l
- n.LenCap[1] = c
- return n
+ return tcSliceHeader(n)
case ir.OMAKESLICECOPY:
- // 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.
n := n.(*ir.MakeExpr)
- 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
+ return tcMakeSliceCopy(n)
case ir.OSLICE, ir.OSLICE3:
n := n.(*ir.SliceExpr)
- n.X = Expr(n.X)
- low, high, max := n.SliceBounds()
- hasmax := n.Op().IsSlice3()
- low = Expr(low)
- high = Expr(high)
- max = Expr(max)
- n.X = DefaultLit(n.X, nil)
- low = indexlit(low)
- high = indexlit(high)
- max = indexlit(max)
- n.SetSliceBounds(low, high, max)
- l := n.X
- if l.Type() == nil {
- n.SetType(nil)
- return n
- }
- if l.Type().IsArray() {
- if !ir.IsAssignable(n.X) {
- base.Errorf("invalid operation %v (slice of unaddressable value)", n)
- n.SetType(nil)
- return n
- }
-
- addr := NodAddr(n.X)
- addr.SetImplicit(true)
- n.X = Expr(addr)
- l = n.X
- }
- t := l.Type()
- var tp *types.Type
- if t.IsString() {
- if hasmax {
- base.Errorf("invalid operation %v (3-index slice of string)", n)
- n.SetType(nil)
- return n
- }
- n.SetType(t)
- n.SetOp(ir.OSLICESTR)
- } else if t.IsPtr() && t.Elem().IsArray() {
- tp = t.Elem()
- n.SetType(types.NewSlice(tp.Elem()))
- types.CalcSize(n.Type())
- if hasmax {
- n.SetOp(ir.OSLICE3ARR)
- } else {
- n.SetOp(ir.OSLICEARR)
- }
- } else if t.IsSlice() {
- n.SetType(t)
- } else {
- base.Errorf("cannot slice %v (type %v)", l, t)
- n.SetType(nil)
- return n
- }
-
- if low != nil && !checksliceindex(l, low, tp) {
- n.SetType(nil)
- return n
- }
- if high != nil && !checksliceindex(l, high, tp) {
- n.SetType(nil)
- return n
- }
- if max != nil && !che