aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/typecheck/typecheck.go
diff options
context:
space:
mode:
authorCuong Manh Le <cuong.manhle.vn@gmail.com>2020-12-29 12:09:51 +0700
committerCuong Manh Le <cuong.manhle.vn@gmail.com>2020-12-29 07:55:55 +0000
commite34c44a7c46d63a96e262f837670052759cd4569 (patch)
treed0b397fa9a77a4a1b4e07d6bf9e10906d5ca4c3c /src/cmd/compile/internal/typecheck/typecheck.go
parenta5ec920160da51166ee22ac0e5335f51a5d36d8e (diff)
downloadgo-e34c44a7c46d63a96e262f837670052759cd4569.tar.gz
go-e34c44a7c46d63a96e262f837670052759cd4569.zip
[dev.regabi] cmd/compile: refactoring typecheck arith
Currently, the tcArith logic is complicated and involes many un-necessary checks for some ir.Op. This CL refactors how it works: - Add a new tcShiftOp function, which only does necessary works for typechecking OLSH/ORSH. That ends up moving OLSH/ORSH to a separated case in typecheck1. - Move OASOP to separated case, so its logic is detached from tcArith. - Move OANDAND/OOROR to separated case, which does some validation dedicated to logical operators only. Passes toolstash -cmp. Change-Id: I0db7b7c7a3e52d6f9e9d87eee6967871f1c32200 Reviewed-on: https://go-review.googlesource.com/c/go/+/279442 Trust: Cuong Manh Le <cuong.manhle.vn@gmail.com> Run-TryBot: Cuong Manh Le <cuong.manhle.vn@gmail.com> 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.go114
1 files changed, 92 insertions, 22 deletions
diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go
index ff9178b597..e29d58cefa 100644
--- a/src/cmd/compile/internal/typecheck/typecheck.go
+++ b/src/cmd/compile/internal/typecheck/typecheck.go
@@ -672,28 +672,98 @@ func typecheck1(n ir.Node, top int) ir.Node {
case ir.ODEREF:
n := n.(*ir.StarExpr)
return tcStar(n, top)
- // arithmetic exprs
- case ir.OASOP,
- ir.OADD,
- ir.OAND,
- ir.OANDAND,
- ir.OANDNOT,
- ir.ODIV,
- ir.OEQ,
- ir.OGE,
- ir.OGT,
- ir.OLE,
- ir.OLT,
- ir.OLSH,
- ir.ORSH,
- ir.OMOD,
- ir.OMUL,
- ir.ONE,
- ir.OOR,
- ir.OOROR,
- ir.OSUB,
- ir.OXOR:
- return tcArith(n)
+
+ // x op= y
+ case ir.OASOP:
+ n := n.(*ir.AssignOpStmt)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ checkassign(n, n.X)
+ if n.IncDec && !okforarith[n.X.Type().Kind()] {
+ base.Errorf("invalid operation: %v (non-numeric type %v)", n, n.X.Type())
+ return n
+ }
+ switch n.AsOp {
+ case ir.OLSH, ir.ORSH:
+ n.X, n.Y, _ = tcShift(n, n.X, n.Y)
+ case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD, ir.OMUL, ir.OOR, ir.OSUB, ir.OXOR:
+ n.X, n.Y, _ = tcArith(n, n.AsOp, n.X, n.Y)
+ default:
+ base.Fatalf("invalid assign op: %v", n.AsOp)
+ }
+ return n
+
+ // logical operators
+ case ir.OANDAND, ir.OOROR:
+ n := n.(*ir.LogicalExpr)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ // 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.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
+ }
+ l, r, t := tcArith(n, n.Op(), n.X, n.Y)
+ n.X, n.Y = l, r
+ n.SetType(t)
+ return n
+
+ // shift operators
+ case ir.OLSH, ir.ORSH:
+ n := n.(*ir.BinaryExpr)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ l, r, t := tcShift(n, n.X, n.Y)
+ n.X, n.Y = l, r
+ n.SetType(t)
+ return n
+
+ // comparison operators
+ case ir.OEQ, ir.OGE, ir.OGT, ir.OLE, ir.OLT, ir.ONE:
+ n := n.(*ir.BinaryExpr)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ l, r, t := tcArith(n, n.Op(), n.X, n.Y)
+ if t != nil {
+ n.X, n.Y = l, r
+ n.SetType(types.UntypedBool)
+ if con := EvalConst(n); con.Op() == ir.OLITERAL {
+ return con
+ }
+ n.X, n.Y = defaultlit2(l, r, true)
+ }
+ return n
+
+ // binary operators
+ case ir.OADD, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD, ir.OMUL, ir.OOR, ir.OSUB, ir.OXOR:
+ n := n.(*ir.BinaryExpr)
+ n.X, n.Y = Expr(n.X), Expr(n.Y)
+ l, r, t := tcArith(n, n.Op(), n.X, n.Y)
+ if t != nil && t.Kind() == types.TSTRING && n.Op() == ir.OADD {
+ // create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
+ 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
+ }
+ n.X, n.Y = l, r
+ n.SetType(t)
+ return n
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
n := n.(*ir.UnaryExpr)