mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.regabi] cmd/compile: cleanup for concrete types - typecheck
An automated rewrite will add concrete type assertions after a test of n.Op(), when n can be safely type-asserted (meaning, n is not reassigned a different type, n is not reassigned and then used outside the scope of the type assertion, and so on). This sequence of CLs handles the code that the automated rewrite does not: adding specific types to function arguments, adjusting code not to call n.Left() etc when n may have multiple representations, and so on. This CL focuses on typecheck.go. Passes buildall w/ toolstash -cmp. Change-Id: I32d1d3b813b0a088b1750c9fd28cd858ed813f1d Reviewed-on: https://go-review.googlesource.com/c/go/+/277920 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
f6efa3d4a4
commit
4ac6a6317b
1 changed files with 248 additions and 140 deletions
|
|
@ -250,7 +250,7 @@ func typecheck(n ir.Node, top int) (res ir.Node) {
|
||||||
|
|
||||||
// Skip over parens.
|
// Skip over parens.
|
||||||
for n.Op() == ir.OPAREN {
|
for n.Op() == ir.OPAREN {
|
||||||
n = n.Left()
|
n = n.(*ir.ParenExpr).Left()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resolve definition of name and value of iota lazily.
|
// Resolve definition of name and value of iota lazily.
|
||||||
|
|
@ -439,10 +439,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
if n.Op() == ir.ONAME && n.SubOp() != 0 && top&ctxCallee == 0 {
|
if n.Op() == ir.ONAME {
|
||||||
base.Errorf("use of builtin %v not in function call", n.Sym())
|
if n.SubOp() != 0 && top&ctxCallee == 0 {
|
||||||
n.SetType(nil)
|
base.Errorf("use of builtin %v not in function call", n.Sym())
|
||||||
return n
|
n.SetType(nil)
|
||||||
|
return n
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typecheckdef(n)
|
typecheckdef(n)
|
||||||
|
|
@ -651,19 +653,29 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
ir.OOROR,
|
ir.OOROR,
|
||||||
ir.OSUB,
|
ir.OSUB,
|
||||||
ir.OXOR:
|
ir.OXOR:
|
||||||
var l ir.Node
|
var l, r ir.Node
|
||||||
var op ir.Op
|
var setLR func()
|
||||||
var r ir.Node
|
switch n := n.(type) {
|
||||||
|
case *ir.AssignOpStmt:
|
||||||
|
l, r = n.Left(), n.Right()
|
||||||
|
setLR = func() { n.SetLeft(l); n.SetRight(r) }
|
||||||
|
case *ir.BinaryExpr:
|
||||||
|
l, r = n.Left(), n.Right()
|
||||||
|
setLR = func() { n.SetLeft(l); n.SetRight(r) }
|
||||||
|
case *ir.LogicalExpr:
|
||||||
|
l, r = n.Left(), n.Right()
|
||||||
|
setLR = func() { n.SetLeft(l); n.SetRight(r) }
|
||||||
|
}
|
||||||
|
l = typecheck(l, ctxExpr)
|
||||||
|
r = typecheck(r, ctxExpr)
|
||||||
|
setLR()
|
||||||
|
if l.Type() == nil || r.Type() == nil {
|
||||||
|
n.SetType(nil)
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
op := n.Op()
|
||||||
if n.Op() == ir.OASOP {
|
if n.Op() == ir.OASOP {
|
||||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
checkassign(n, l)
|
||||||
n.SetRight(typecheck(n.Right(), ctxExpr))
|
|
||||||
l = n.Left()
|
|
||||||
r = n.Right()
|
|
||||||
checkassign(n, n.Left())
|
|
||||||
if l.Type() == nil || r.Type() == nil {
|
|
||||||
n.SetType(nil)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
if n.Implicit() && !okforarith[l.Type().Kind()] {
|
if n.Implicit() && !okforarith[l.Type().Kind()] {
|
||||||
base.Errorf("invalid operation: %v (non-numeric type %v)", n, l.Type())
|
base.Errorf("invalid operation: %v (non-numeric type %v)", n, l.Type())
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
|
|
@ -671,20 +683,10 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
}
|
}
|
||||||
// TODO(marvin): Fix Node.EType type union.
|
// TODO(marvin): Fix Node.EType type union.
|
||||||
op = n.SubOp()
|
op = n.SubOp()
|
||||||
} else {
|
|
||||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
|
||||||
n.SetRight(typecheck(n.Right(), ctxExpr))
|
|
||||||
l = n.Left()
|
|
||||||
r = n.Right()
|
|
||||||
if l.Type() == nil || r.Type() == nil {
|
|
||||||
n.SetType(nil)
|
|
||||||
return n
|
|
||||||
}
|
|
||||||
op = n.Op()
|
|
||||||
}
|
}
|
||||||
if op == ir.OLSH || op == ir.ORSH {
|
if op == ir.OLSH || op == ir.ORSH {
|
||||||
r = defaultlit(r, types.Types[types.TUINT])
|
r = defaultlit(r, types.Types[types.TUINT])
|
||||||
n.SetRight(r)
|
setLR()
|
||||||
t := r.Type()
|
t := r.Type()
|
||||||
if !t.IsInteger() {
|
if !t.IsInteger() {
|
||||||
base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type())
|
base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type())
|
||||||
|
|
@ -730,9 +732,8 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
|
|
||||||
// ideal mixed with non-ideal
|
// ideal mixed with non-ideal
|
||||||
l, r = defaultlit2(l, r, false)
|
l, r = defaultlit2(l, r, false)
|
||||||
|
setLR()
|
||||||
|
|
||||||
n.SetLeft(l)
|
|
||||||
n.SetRight(r)
|
|
||||||
if l.Type() == nil || r.Type() == nil {
|
if l.Type() == nil || r.Type() == nil {
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
return n
|
return n
|
||||||
|
|
@ -768,7 +769,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 {
|
if r.Type().IsInterface() == l.Type().IsInterface() || l.Type().Width >= 1<<16 {
|
||||||
l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
|
l = ir.NewConvExpr(base.Pos, aop, r.Type(), l)
|
||||||
l.SetTypecheck(1)
|
l.SetTypecheck(1)
|
||||||
n.SetLeft(l)
|
setLR()
|
||||||
}
|
}
|
||||||
|
|
||||||
t = r.Type()
|
t = r.Type()
|
||||||
|
|
@ -789,7 +790,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 {
|
if r.Type().IsInterface() == l.Type().IsInterface() || r.Type().Width >= 1<<16 {
|
||||||
r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
|
r = ir.NewConvExpr(base.Pos, aop, l.Type(), r)
|
||||||
r.SetTypecheck(1)
|
r.SetTypecheck(1)
|
||||||
n.SetRight(r)
|
setLR()
|
||||||
}
|
}
|
||||||
|
|
||||||
t = l.Type()
|
t = l.Type()
|
||||||
|
|
@ -858,29 +859,30 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
if iscmp[n.Op()] {
|
if iscmp[n.Op()] {
|
||||||
t = types.UntypedBool
|
t = types.UntypedBool
|
||||||
n.SetType(t)
|
n.SetType(t)
|
||||||
n = evalConst(n)
|
if con := evalConst(n); con.Op() == ir.OLITERAL {
|
||||||
if n.Op() != ir.OLITERAL {
|
return con
|
||||||
l, r = defaultlit2(l, r, true)
|
|
||||||
n.SetLeft(l)
|
|
||||||
n.SetRight(r)
|
|
||||||
}
|
}
|
||||||
|
l, r = defaultlit2(l, r, true)
|
||||||
|
setLR()
|
||||||
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
if et == types.TSTRING && n.Op() == ir.OADD {
|
if et == types.TSTRING && n.Op() == ir.OADD {
|
||||||
// create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
|
// create or update OADDSTR node with list of strings in x + y + z + (w + v) + ...
|
||||||
|
var add *ir.AddStringExpr
|
||||||
if l.Op() == ir.OADDSTR {
|
if l.Op() == ir.OADDSTR {
|
||||||
orig := n
|
add = l.(*ir.AddStringExpr)
|
||||||
n = l
|
add.SetPos(n.Pos())
|
||||||
n.SetPos(orig.Pos())
|
|
||||||
} else {
|
} else {
|
||||||
n = ir.NodAt(n.Pos(), ir.OADDSTR, nil, nil)
|
add = ir.NewAddStringExpr(n.Pos(), []ir.Node{l})
|
||||||
n.PtrList().Set1(l)
|
|
||||||
}
|
}
|
||||||
if r.Op() == ir.OADDSTR {
|
if r.Op() == ir.OADDSTR {
|
||||||
n.PtrList().AppendNodes(r.PtrList())
|
add.PtrList().AppendNodes(r.PtrList())
|
||||||
} else {
|
} else {
|
||||||
n.PtrList().Append(r)
|
add.PtrList().Append(r)
|
||||||
}
|
}
|
||||||
|
add.SetType(t)
|
||||||
|
return add
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
|
if (op == ir.ODIV || op == ir.OMOD) && ir.IsConst(r, constant.Int) {
|
||||||
|
|
@ -950,11 +952,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OCOMPLIT:
|
case ir.OCOMPLIT:
|
||||||
return typecheckcomplit(n)
|
return typecheckcomplit(n.(*ir.CompLitExpr))
|
||||||
|
|
||||||
case ir.OXDOT, ir.ODOT:
|
case ir.OXDOT, ir.ODOT:
|
||||||
|
n := n.(*ir.SelectorExpr)
|
||||||
if n.Op() == ir.OXDOT {
|
if n.Op() == ir.OXDOT {
|
||||||
n = adddot(n)
|
n = adddot(n).(*ir.SelectorExpr)
|
||||||
n.SetOp(ir.ODOT)
|
n.SetOp(ir.ODOT)
|
||||||
if n.Left() == nil {
|
if n.Left() == nil {
|
||||||
n.SetType(nil)
|
n.SetType(nil)
|
||||||
|
|
@ -1021,7 +1024,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
|
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
|
||||||
n = typecheckpartialcall(n, s)
|
return typecheckpartialcall(n, s)
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
|
@ -1286,9 +1289,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
n.SetLeft(nodAddr(n.Left()))
|
addr := nodAddr(n.Left())
|
||||||
n.Left().SetImplicit(true)
|
addr.SetImplicit(true)
|
||||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
n.SetLeft(typecheck(addr, ctxExpr))
|
||||||
l = n.Left()
|
l = n.Left()
|
||||||
}
|
}
|
||||||
t := l.Type()
|
t := l.Type()
|
||||||
|
|
@ -1338,9 +1341,10 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
|
|
||||||
// call and call like
|
// call and call like
|
||||||
case ir.OCALL:
|
case ir.OCALL:
|
||||||
n.(*ir.CallExpr).Use = ir.CallUseExpr
|
n := n.(*ir.CallExpr)
|
||||||
|
n.Use = ir.CallUseExpr
|
||||||
if top == ctxStmt {
|
if top == ctxStmt {
|
||||||
n.(*ir.CallExpr).Use = ir.CallUseStmt
|
n.Use = ir.CallUseStmt
|
||||||
}
|
}
|
||||||
typecheckslice(n.Init().Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907)
|
typecheckslice(n.Init().Slice(), ctxStmt) // imported rewritten f(g()) calls (#30907)
|
||||||
n.SetLeft(typecheck(n.Left(), ctxExpr|ctxType|ctxCallee))
|
n.SetLeft(typecheck(n.Left(), ctxExpr|ctxType|ctxCallee))
|
||||||
|
|
@ -1350,7 +1354,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
|
|
||||||
l := n.Left()
|
l := n.Left()
|
||||||
|
|
||||||
if l.Op() == ir.ONAME && l.SubOp() != 0 {
|
if l.Op() == ir.ONAME && l.(*ir.Name).SubOp() != 0 {
|
||||||
if n.IsDDD() && l.SubOp() != ir.OAPPEND {
|
if n.IsDDD() && l.SubOp() != ir.OAPPEND {
|
||||||
base.Errorf("invalid use of ... with builtin %v", l)
|
base.Errorf("invalid use of ... with builtin %v", l)
|
||||||
}
|
}
|
||||||
|
|
@ -1408,7 +1412,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
n = ir.NodAt(n.Pos(), ir.OCONV, arg, nil)
|
n := ir.NodAt(n.Pos(), ir.OCONV, arg, nil)
|
||||||
n.SetType(l.Type())
|
n.SetType(l.Type())
|
||||||
return typecheck1(n, top)
|
return typecheck1(n, top)
|
||||||
}
|
}
|
||||||
|
|
@ -1463,14 +1467,16 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
if t.NumResults() == 1 {
|
if t.NumResults() == 1 {
|
||||||
n.SetType(l.Type().Results().Field(0).Type)
|
n.SetType(l.Type().Results().Field(0).Type)
|
||||||
|
|
||||||
if n.Op() == ir.OCALLFUNC && n.Left().Op() == ir.ONAME && isRuntimePkg(n.Left().Sym().Pkg) && n.Left().Sym().Name == "getg" {
|
if n.Op() == ir.OCALLFUNC && n.Left().Op() == ir.ONAME {
|
||||||
// Emit code for runtime.getg() directly instead of calling function.
|
if sym := n.Left().(*ir.Name).Sym(); isRuntimePkg(sym.Pkg) && sym.Name == "getg" {
|
||||||
// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
|
// Emit code for runtime.getg() directly instead of calling function.
|
||||||
// so that the ordering pass can make sure to preserve the semantics of the original code
|
// Most such rewrites (for example the similar one for math.Sqrt) should be done in walk,
|
||||||
// (in particular, the exact time of the function call) by introducing temporaries.
|
// so that the ordering pass can make sure to preserve the semantics of the original code
|
||||||
// In this case, we know getg() always returns the same result within a given function
|
// (in particular, the exact time of the function call) by introducing temporaries.
|
||||||
// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
|
// In this case, we know getg() always returns the same result within a given function
|
||||||
n.SetOp(ir.OGETG)
|
// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
|
||||||
|
n.SetOp(ir.OGETG)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
@ -1733,6 +1739,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OCONV:
|
case ir.OCONV:
|
||||||
|
n := n.(*ir.ConvExpr)
|
||||||
checkwidth(n.Type()) // ensure width is calculated for backend
|
checkwidth(n.Type()) // ensure width is calculated for backend
|
||||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||||
n.SetLeft(convlit1(n.Left(), n.Type(), true, nil))
|
n.SetLeft(convlit1(n.Left(), n.Type(), true, nil))
|
||||||
|
|
@ -1771,7 +1778,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
|
|
||||||
case ir.OSTR2RUNES:
|
case ir.OSTR2RUNES:
|
||||||
if n.Left().Op() == ir.OLITERAL {
|
if n.Left().Op() == ir.OLITERAL {
|
||||||
n = stringtoruneslit(n)
|
return stringtoruneslit(n)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
|
|
@ -1881,8 +1888,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
nn.SetType(t)
|
nn.SetType(t)
|
||||||
n = nn
|
return nn
|
||||||
return n
|
|
||||||
|
|
||||||
case ir.ONEW:
|
case ir.ONEW:
|
||||||
if n.Left() == nil {
|
if n.Left() == nil {
|
||||||
|
|
@ -1990,6 +1996,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
|
|
||||||
// statements
|
// statements
|
||||||
case ir.OAS:
|
case ir.OAS:
|
||||||
|
n := n.(*ir.AssignStmt)
|
||||||
typecheckas(n)
|
typecheckas(n)
|
||||||
|
|
||||||
// Code that creates temps does not bother to set defn, so do it here.
|
// Code that creates temps does not bother to set defn, so do it here.
|
||||||
|
|
@ -1999,7 +2006,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OAS2:
|
case ir.OAS2:
|
||||||
typecheckas2(n)
|
typecheckas2(n.(*ir.AssignListStmt))
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OBREAK,
|
case ir.OBREAK,
|
||||||
|
|
@ -2026,6 +2033,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.ODEFER, ir.OGO:
|
case ir.ODEFER, ir.OGO:
|
||||||
|
n := n.(*ir.GoDeferStmt)
|
||||||
n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr))
|
n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr))
|
||||||
if !n.Left().Diag() {
|
if !n.Left().Diag() {
|
||||||
checkdefergo(n)
|
checkdefergo(n)
|
||||||
|
|
@ -2083,15 +2091,15 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OSELECT:
|
case ir.OSELECT:
|
||||||
typecheckselect(n)
|
typecheckselect(n.(*ir.SelectStmt))
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OSWITCH:
|
case ir.OSWITCH:
|
||||||
typecheckswitch(n)
|
typecheckswitch(n.(*ir.SwitchStmt))
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.ORANGE:
|
case ir.ORANGE:
|
||||||
typecheckrange(n)
|
typecheckrange(n.(*ir.RangeStmt))
|
||||||
return n
|
return n
|
||||||
|
|
||||||
case ir.OTYPESW:
|
case ir.OTYPESW:
|
||||||
|
|
@ -2119,13 +2127,26 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckargs(n ir.Node) {
|
func typecheckargs(n ir.Node) {
|
||||||
if n.List().Len() != 1 || n.IsDDD() {
|
var list []ir.Node
|
||||||
typecheckslice(n.List().Slice(), ctxExpr)
|
switch n := n.(type) {
|
||||||
|
default:
|
||||||
|
base.Fatalf("typecheckargs %+v", n.Op())
|
||||||
|
case *ir.CallExpr:
|
||||||
|
list = n.List().Slice()
|
||||||
|
if n.IsDDD() {
|
||||||
|
typecheckslice(list, ctxExpr)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
case *ir.ReturnStmt:
|
||||||
|
list = n.List().Slice()
|
||||||
|
}
|
||||||
|
if len(list) != 1 {
|
||||||
|
typecheckslice(list, ctxExpr)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
typecheckslice(n.List().Slice(), ctxExpr|ctxMultiOK)
|
typecheckslice(list, ctxExpr|ctxMultiOK)
|
||||||
t := n.List().First().Type()
|
t := list[0].Type()
|
||||||
if t == nil || !t.IsFuncArgStruct() {
|
if t == nil || !t.IsFuncArgStruct() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -2138,7 +2159,7 @@ func typecheckargs(n ir.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
as := ir.Nod(ir.OAS2, nil, nil)
|
as := ir.Nod(ir.OAS2, nil, nil)
|
||||||
as.PtrRlist().AppendNodes(n.PtrList())
|
as.PtrRlist().Append(list...)
|
||||||
|
|
||||||
// If we're outside of function context, then this call will
|
// If we're outside of function context, then this call will
|
||||||
// be executed during the generated init function. However,
|
// be executed during the generated init function. However,
|
||||||
|
|
@ -2149,16 +2170,24 @@ func typecheckargs(n ir.Node) {
|
||||||
if static {
|
if static {
|
||||||
Curfn = initTodo
|
Curfn = initTodo
|
||||||
}
|
}
|
||||||
|
list = nil
|
||||||
for _, f := range t.FieldSlice() {
|
for _, f := range t.FieldSlice() {
|
||||||
t := temp(f.Type)
|
t := temp(f.Type)
|
||||||
as.PtrInit().Append(ir.Nod(ir.ODCL, t, nil))
|
as.PtrInit().Append(ir.Nod(ir.ODCL, t, nil))
|
||||||
as.PtrList().Append(t)
|
as.PtrList().Append(t)
|
||||||
n.PtrList().Append(t)
|
list = append(list, t)
|
||||||
}
|
}
|
||||||
if static {
|
if static {
|
||||||
Curfn = nil
|
Curfn = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch n := n.(type) {
|
||||||
|
case *ir.CallExpr:
|
||||||
|
n.PtrList().Set(list)
|
||||||
|
case *ir.ReturnStmt:
|
||||||
|
n.PtrList().Set(list)
|
||||||
|
}
|
||||||
|
|
||||||
n.PtrInit().Append(typecheck(as, ctxStmt))
|
n.PtrInit().Append(typecheck(as, ctxStmt))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2201,7 +2230,7 @@ func checksliceconst(lo ir.Node, hi ir.Node) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkdefergo(n ir.Node) {
|
func checkdefergo(n *ir.GoDeferStmt) {
|
||||||
what := "defer"
|
what := "defer"
|
||||||
if n.Op() == ir.OGO {
|
if n.Op() == ir.OGO {
|
||||||
what = "go"
|
what = "go"
|
||||||
|
|
@ -2269,13 +2298,12 @@ func implicitstar(n ir.Node) ir.Node {
|
||||||
if !t.IsArray() {
|
if !t.IsArray() {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
n = ir.Nod(ir.ODEREF, n, nil)
|
star := ir.Nod(ir.ODEREF, n, nil)
|
||||||
n.SetImplicit(true)
|
star.SetImplicit(true)
|
||||||
n = typecheck(n, ctxExpr)
|
return typecheck(star, ctxExpr)
|
||||||
return n
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func needOneArg(n ir.Node, f string, args ...interface{}) (ir.Node, bool) {
|
func needOneArg(n *ir.CallExpr, f string, args ...interface{}) (ir.Node, bool) {
|
||||||
if n.List().Len() == 0 {
|
if n.List().Len() == 0 {
|
||||||
p := fmt.Sprintf(f, args...)
|
p := fmt.Sprintf(f, args...)
|
||||||
base.Errorf("missing argument to %s: %v", p, n)
|
base.Errorf("missing argument to %s: %v", p, n)
|
||||||
|
|
@ -2291,7 +2319,7 @@ func needOneArg(n ir.Node, f string, args ...interface{}) (ir.Node, bool) {
|
||||||
return n.List().First(), true
|
return n.List().First(), true
|
||||||
}
|
}
|
||||||
|
|
||||||
func needTwoArgs(n ir.Node) (ir.Node, ir.Node, bool) {
|
func needTwoArgs(n *ir.CallExpr) (ir.Node, ir.Node, bool) {
|
||||||
if n.List().Len() != 2 {
|
if n.List().Len() != 2 {
|
||||||
if n.List().Len() < 2 {
|
if n.List().Len() < 2 {
|
||||||
base.Errorf("not enough arguments in call to %v", n)
|
base.Errorf("not enough arguments in call to %v", n)
|
||||||
|
|
@ -2334,7 +2362,7 @@ func lookdot1(errnode ir.Node, s *types.Sym, t *types.Type, fs *types.Fields, do
|
||||||
|
|
||||||
// typecheckMethodExpr checks selector expressions (ODOT) where the
|
// typecheckMethodExpr checks selector expressions (ODOT) where the
|
||||||
// base expression is a type expression (OTYPE).
|
// base expression is a type expression (OTYPE).
|
||||||
func typecheckMethodExpr(n ir.Node) (res ir.Node) {
|
func typecheckMethodExpr(n *ir.SelectorExpr) (res ir.Node) {
|
||||||
if enableTrace && base.Flag.LowerT {
|
if enableTrace && base.Flag.LowerT {
|
||||||
defer tracePrint("typecheckMethodExpr", n)(&res)
|
defer tracePrint("typecheckMethodExpr", n)(&res)
|
||||||
}
|
}
|
||||||
|
|
@ -2417,7 +2445,7 @@ func derefall(t *types.Type) *types.Type {
|
||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
func lookdot(n ir.Node, t *types.Type, dostrcmp int) *types.Field {
|
func lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field {
|
||||||
s := n.Sym()
|
s := n.Sym()
|
||||||
|
|
||||||
dowidth(t)
|
dowidth(t)
|
||||||
|
|
@ -2449,14 +2477,14 @@ func lookdot(n ir.Node, t *types.Type, dostrcmp int) *types.Field {
|
||||||
n.SetType(f1.Type)
|
n.SetType(f1.Type)
|
||||||
if t.IsInterface() {
|
if t.IsInterface() {
|
||||||
if n.Left().Type().IsPtr() {
|
if n.Left().Type().IsPtr() {
|
||||||
n.SetLeft(ir.Nod(ir.ODEREF, n.Left(), nil)) // implicitstar
|
star := ir.Nod(ir.ODEREF, n.Left(), nil)
|
||||||
n.Left().SetImplicit(true)
|
star.SetImplicit(true)
|
||||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
n.SetLeft(typecheck(star, ctxExpr))
|
||||||
}
|
}
|
||||||
|
|
||||||
n.SetOp(ir.ODOTINTER)
|
n.SetOp(ir.ODOTINTER)
|
||||||
}
|
}
|
||||||
n.(*ir.SelectorExpr).Selection = f1
|
n.Selection = f1
|
||||||
return f1
|
return f1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2471,13 +2499,13 @@ func lookdot(n ir.Node, t *types.Type, dostrcmp int) *types.Field {
|
||||||
if !types.Identical(rcvr, tt) {
|
if !types.Identical(rcvr, tt) {
|
||||||
if rcvr.IsPtr() && types.Identical(rcvr.Elem(), tt) {
|
if rcvr.IsPtr() && types.Identical(rcvr.Elem(), tt) {
|
||||||
checklvalue(n.Left(), "call pointer method on")
|
checklvalue(n.Left(), "call pointer method on")
|
||||||
n.SetLeft(nodAddr(n.Left()))
|
addr := nodAddr(n.Left())
|
||||||
n.Left().SetImplicit(true)
|
addr.SetImplicit(true)
|
||||||
n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr))
|
n.SetLeft(typecheck(addr, ctxType|ctxExpr))
|
||||||
} else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
|
} else if tt.IsPtr() && (!rcvr.IsPtr() || rcvr.IsPtr() && rcvr.Elem().NotInHeap()) && types.Identical(tt.Elem(), rcvr) {
|
||||||
n.SetLeft(ir.Nod(ir.ODEREF, n.Left(), nil))
|
star := ir.Nod(ir.ODEREF, n.Left(), nil)
|
||||||
n.Left().SetImplicit(true)
|
star.SetImplicit(true)
|
||||||
n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr))
|
n.SetLeft(typecheck(star, ctxType|ctxExpr))
|
||||||
} else if tt.IsPtr() && tt.Elem().IsPtr() && types.Identical(derefall(tt), derefall(rcvr)) {
|
} 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.Sym(), n.Left())
|
base.Errorf("calling method %v with receiver %L requires explicit dereference", n.Sym(), n.Left())
|
||||||
for tt.IsPtr() {
|
for tt.IsPtr() {
|
||||||
|
|
@ -2485,9 +2513,9 @@ func lookdot(n ir.Node, t *types.Type, dostrcmp int) *types.Field {
|
||||||
if rcvr.IsPtr() && !tt.Elem().IsPtr() {
|
if rcvr.IsPtr() && !tt.Elem().IsPtr() {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
n.SetLeft(ir.Nod(ir.ODEREF, n.Left(), nil))
|
star := ir.Nod(ir.ODEREF, n.Left(), nil)
|
||||||
n.Left().SetImplicit(true)
|
star.SetImplicit(true)
|
||||||
n.SetLeft(typecheck(n.Left(), ctxType|ctxExpr))
|
n.SetLeft(typecheck(star, ctxType|ctxExpr))
|
||||||
tt = tt.Elem()
|
tt = tt.Elem()
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -2495,13 +2523,16 @@ func lookdot(n ir.Node, t *types.Type, dostrcmp int) *types.Field {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pll := n
|
implicit, ll := n.Implicit(), n.Left()
|
||||||
ll := n.Left()
|
for ll != nil && (ll.Op() == ir.ODOT || ll.Op() == ir.ODOTPTR || ll.Op() == ir.ODEREF) {
|
||||||
for ll.Left() != nil && (ll.Op() == ir.ODOT || ll.Op() == ir.ODOTPTR || ll.Op() == ir.ODEREF) {
|
switch l := ll.(type) {
|
||||||
pll = ll
|
case *ir.SelectorExpr:
|
||||||
ll = ll.Left()
|
implicit, ll = l.Implicit(), l.Left()
|
||||||
|
case *ir.StarExpr:
|
||||||
|
implicit, ll = l.Implicit(), l.Left()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if pll.Implicit() && ll.Type().IsPtr() && ll.Type().Sym() != nil && ll.Type().Sym().Def != nil && ir.AsNode(ll.Type().Sym().Def).Op() == ir.OTYPE {
|
if implicit && ll.Type().IsPtr() && ll.Type().Sym() != nil && ll.Type().Sym().Def != nil && ir.AsNode(ll.Type().Sym().Def).Op() == ir.OTYPE {
|
||||||
// It is invalid to automatically dereference a named pointer type when selecting a method.
|
// It is invalid to automatically dereference a named pointer type when selecting a method.
|
||||||
// Make n.Left == ll to clarify error message.
|
// Make n.Left == ll to clarify error message.
|
||||||
n.SetLeft(ll)
|
n.SetLeft(ll)
|
||||||
|
|
@ -2512,7 +2543,7 @@ func lookdot(n ir.Node, t *types.Type, dostrcmp int) *types.Field {
|
||||||
n.SetOffset(f2.Offset)
|
n.SetOffset(f2.Offset)
|
||||||
n.SetType(f2.Type)
|
n.SetType(f2.Type)
|
||||||
n.SetOp(ir.ODOTMETH)
|
n.SetOp(ir.ODOTMETH)
|
||||||
n.(*ir.SelectorExpr).Selection = f2
|
n.Selection = f2
|
||||||
|
|
||||||
return f2
|
return f2
|
||||||
}
|
}
|
||||||
|
|
@ -2742,8 +2773,12 @@ func iscomptype(t *types.Type) bool {
|
||||||
|
|
||||||
// pushtype adds elided type information for composite literals if
|
// pushtype adds elided type information for composite literals if
|
||||||
// appropriate, and returns the resulting expression.
|
// appropriate, and returns the resulting expression.
|
||||||
func pushtype(n ir.Node, t *types.Type) ir.Node {
|
func pushtype(nn ir.Node, t *types.Type) ir.Node {
|
||||||
if n == nil || n.Op() != ir.OCOMPLIT || n.Right() != nil {
|
if nn == nil || nn.Op() != ir.OCOMPLIT {
|
||||||
|
return nn
|
||||||
|
}
|
||||||
|
n := nn.(*ir.CompLitExpr)
|
||||||
|
if n.Right() != nil {
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2756,16 +2791,16 @@ func pushtype(n ir.Node, t *types.Type) ir.Node {
|
||||||
// For *T, return &T{...}.
|
// For *T, return &T{...}.
|
||||||
n.SetRight(ir.TypeNode(t.Elem()))
|
n.SetRight(ir.TypeNode(t.Elem()))
|
||||||
|
|
||||||
n = nodAddrAt(n.Pos(), n)
|
addr := ir.NodAt(n.Pos(), ir.OADDR, n, nil)
|
||||||
n.SetImplicit(true)
|
addr.SetImplicit(true)
|
||||||
|
return addr
|
||||||
}
|
}
|
||||||
|
|
||||||
return n
|
return n
|
||||||
}
|
}
|
||||||
|
|
||||||
// The result of typecheckcomplit MUST be assigned back to n, e.g.
|
// The result of typecheckcomplit MUST be assigned back to n, e.g.
|
||||||
// n.Left = typecheckcomplit(n.Left)
|
// n.Left = typecheckcomplit(n.Left)
|
||||||
func typecheckcomplit(n ir.Node) (res ir.Node) {
|
func typecheckcomplit(n *ir.CompLitExpr) (res ir.Node) {
|
||||||
if enableTrace && base.Flag.LowerT {
|
if enableTrace && base.Flag.LowerT {
|
||||||
defer tracePrint("typecheckcomplit", n)(&res)
|
defer tracePrint("typecheckcomplit", n)(&res)
|
||||||
}
|
}
|
||||||
|
|
@ -2782,7 +2817,7 @@ func typecheckcomplit(n ir.Node) (res ir.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save original node (including n.Right)
|
// Save original node (including n.Right)
|
||||||
n.(ir.OrigNode).SetOrig(ir.Copy(n))
|
n.SetOrig(ir.Copy(n))
|
||||||
|
|
||||||
setlineno(n.Right())
|
setlineno(n.Right())
|
||||||
|
|
||||||
|
|
@ -2833,6 +2868,7 @@ func typecheckcomplit(n ir.Node) (res ir.Node) {
|
||||||
base.Errorf("missing key in map literal")
|
base.Errorf("missing key in map literal")
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
l := l.(*ir.KeyExpr)
|
||||||
|
|
||||||
r := l.Left()
|
r := l.Left()
|
||||||
r = pushtype(r, t.Key())
|
r = pushtype(r, t.Key())
|
||||||
|
|
@ -2876,9 +2912,9 @@ func typecheckcomplit(n ir.Node) (res ir.Node) {
|
||||||
}
|
}
|
||||||
// No pushtype allowed here. Must name fields for that.
|
// No pushtype allowed here. Must name fields for that.
|
||||||
n1 = assignconv(n1, f.Type, "field value")
|
n1 = assignconv(n1, f.Type, "field value")
|
||||||
n1 = nodSym(ir.OSTRUCTKEY, n1, f.Sym)
|
sk := nodSym(ir.OSTRUCTKEY, n1, f.Sym)
|
||||||
n1.SetOffset(f.Offset)
|
sk.SetOffset(f.Offset)
|
||||||
ls[i] = n1
|
ls[i] = sk
|
||||||
}
|
}
|
||||||
if len(ls) < t.NumFields() {
|
if len(ls) < t.NumFields() {
|
||||||
base.Errorf("too few values in %v", n)
|
base.Errorf("too few values in %v", n)
|
||||||
|
|
@ -2892,7 +2928,8 @@ func typecheckcomplit(n ir.Node) (res ir.Node) {
|
||||||
setlineno(l)
|
setlineno(l)
|
||||||
|
|
||||||
if l.Op() == ir.OKEY {
|
if l.Op() == ir.OKEY {
|
||||||
key := l.Left()
|
kv := l.(*ir.KeyExpr)
|
||||||
|
key := kv.Left()
|
||||||
|
|
||||||
// Sym might have resolved to name in other top-level
|
// Sym might have resolved to name in other top-level
|
||||||
// package, because of import dot. Redirect to correct sym
|
// package, because of import dot. Redirect to correct sym
|
||||||
|
|
@ -2911,7 +2948,7 @@ func typecheckcomplit(n ir.Node) (res ir.Node) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
l = ir.NewStructKeyExpr(l.Pos(), s, l.Right())
|
l = ir.NewStructKeyExpr(l.Pos(), s, kv.Right())
|
||||||
ls[i] = l
|
ls[i] = l
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2923,6 +2960,7 @@ func typecheckcomplit(n ir.Node) (res ir.Node) {
|
||||||
ls[i] = typecheck(ls[i], ctxExpr)
|
ls[i] = typecheck(ls[i], ctxExpr)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
l := l.(*ir.StructKeyExpr)
|
||||||
|
|
||||||
f := lookdot1(nil, l.Sym(), t, t.Fields(), 0)
|
f := lookdot1(nil, l.Sym(), t, t.Fields(), 0)
|
||||||
if f == nil {
|
if f == nil {
|
||||||
|
|
@ -2983,8 +3021,9 @@ func typecheckarraylit(elemType *types.Type, bound int64, elts []ir.Node, ctx st
|
||||||
for i, elt := range elts {
|
for i, elt := range elts {
|
||||||
setlineno(elt)
|
setlineno(elt)
|
||||||
r := elts[i]
|
r := elts[i]
|
||||||
var kv ir.Node
|
var kv *ir.KeyExpr
|
||||||
if elt.Op() == ir.OKEY {
|
if elt.Op() == ir.OKEY {
|
||||||
|
elt := elt.(*ir.KeyExpr)
|
||||||
elt.SetLeft(typecheck(elt.Left(), ctxExpr))
|
elt.SetLeft(typecheck(elt.Left(), ctxExpr))
|
||||||
key = indexconst(elt.Left())
|
key = indexconst(elt.Left())
|
||||||
if key < 0 {
|
if key < 0 {
|
||||||
|
|
@ -3104,9 +3143,9 @@ func checkassign(stmt ir.Node, n ir.Node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case n.Op() == ir.ODOT && n.Left().Op() == ir.OINDEXMAP:
|
case n.Op() == ir.ODOT && n.(*ir.SelectorExpr).Left().Op() == ir.OINDEXMAP:
|
||||||
base.Errorf("cannot assign to struct field %v in map", n)
|
base.Errorf("cannot assign to struct field %v in map", n)
|
||||||
case (n.Op() == ir.OINDEX && n.Left().Type().IsString()) || n.Op() == ir.OSLICESTR:
|
case (n.Op() == ir.OINDEX && n.(*ir.IndexExpr).Left().Type().IsString()) || n.Op() == ir.OSLICESTR:
|
||||||
base.Errorf("cannot assign to %v (strings are immutable)", n)
|
base.Errorf("cannot assign to %v (strings are immutable)", n)
|
||||||
case n.Op() == ir.OLITERAL && n.Sym() != nil && isGoConst(n):
|
case n.Op() == ir.OLITERAL && n.Sym() != nil && isGoConst(n):
|
||||||
base.Errorf("cannot assign to %v (declared const)", n)
|
base.Errorf("cannot assign to %v (declared const)", n)
|
||||||
|
|
@ -3147,19 +3186,40 @@ func samesafeexpr(l ir.Node, r ir.Node) bool {
|
||||||
return l == r
|
return l == r
|
||||||
|
|
||||||
case ir.ODOT, ir.ODOTPTR:
|
case ir.ODOT, ir.ODOTPTR:
|
||||||
|
l := l.(*ir.SelectorExpr)
|
||||||
|
r := r.(*ir.SelectorExpr)
|
||||||
return l.Sym() != nil && r.Sym() != nil && l.Sym() == r.Sym() && samesafeexpr(l.Left(), r.Left())
|
return l.Sym() != nil && r.Sym() != nil && l.Sym() == r.Sym() && samesafeexpr(l.Left(), r.Left())
|
||||||
|
|
||||||
case ir.ODEREF, ir.OCONVNOP,
|
case ir.ODEREF:
|
||||||
ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG:
|
l := l.(*ir.StarExpr)
|
||||||
|
r := r.(*ir.StarExpr)
|
||||||
|
return samesafeexpr(l.Left(), r.Left())
|
||||||
|
|
||||||
|
case ir.ONOT, ir.OBITNOT, ir.OPLUS, ir.ONEG:
|
||||||
|
l := l.(*ir.UnaryExpr)
|
||||||
|
r := r.(*ir.UnaryExpr)
|
||||||
|
return samesafeexpr(l.Left(), r.Left())
|
||||||
|
|
||||||
|
case ir.OCONVNOP:
|
||||||
|
l := l.(*ir.ConvExpr)
|
||||||
|
r := r.(*ir.ConvExpr)
|
||||||
return samesafeexpr(l.Left(), r.Left())
|
return samesafeexpr(l.Left(), r.Left())
|
||||||
|
|
||||||
case ir.OCONV:
|
case ir.OCONV:
|
||||||
|
l := l.(*ir.ConvExpr)
|
||||||
|
r := r.(*ir.ConvExpr)
|
||||||
// Some conversions can't be reused, such as []byte(str).
|
// Some conversions can't be reused, such as []byte(str).
|
||||||
// Allow only numeric-ish types. This is a bit conservative.
|
// Allow only numeric-ish types. This is a bit conservative.
|
||||||
return issimple[l.Type().Kind()] && samesafeexpr(l.Left(), r.Left())
|
return issimple[l.Type().Kind()] && samesafeexpr(l.Left(), r.Left())
|
||||||
|
|
||||||
case ir.OINDEX, ir.OINDEXMAP,
|
case ir.OINDEX, ir.OINDEXMAP:
|
||||||
ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD:
|
l := l.(*ir.IndexExpr)
|
||||||
|
r := r.(*ir.IndexExpr)
|
||||||
|
return samesafeexpr(l.Left(), r.Left()) && samesafeexpr(l.Right(), r.Right())
|
||||||
|
|
||||||
|
case ir.OADD, ir.OSUB, ir.OOR, ir.OXOR, ir.OMUL, ir.OLSH, ir.ORSH, ir.OAND, ir.OANDNOT, ir.ODIV, ir.OMOD:
|
||||||
|
l := l.(*ir.BinaryExpr)
|
||||||
|
r := r.(*ir.BinaryExpr)
|
||||||
return samesafeexpr(l.Left(), r.Left()) && samesafeexpr(l.Right(), r.Right())
|
return samesafeexpr(l.Left(), r.Left()) && samesafeexpr(l.Right(), r.Right())
|
||||||
|
|
||||||
case ir.OLITERAL:
|
case ir.OLITERAL:
|
||||||
|
|
@ -3175,7 +3235,7 @@ func samesafeexpr(l ir.Node, r ir.Node) bool {
|
||||||
// type check assignment.
|
// type check assignment.
|
||||||
// if this assignment is the definition of a var on the left side,
|
// if this assignment is the definition of a var on the left side,
|
||||||
// fill in the var's type.
|
// fill in the var's type.
|
||||||
func typecheckas(n ir.Node) {
|
func typecheckas(n *ir.AssignStmt) {
|
||||||
if enableTrace && base.Flag.LowerT {
|
if enableTrace && base.Flag.LowerT {
|
||||||
defer tracePrint("typecheckas", n)(nil)
|
defer tracePrint("typecheckas", n)(nil)
|
||||||
}
|
}
|
||||||
|
|
@ -3199,7 +3259,7 @@ func typecheckas(n ir.Node) {
|
||||||
checkassign(n, n.Left())
|
checkassign(n, n.Left())
|
||||||
if n.Right() != nil && n.Right().Type() != nil {
|
if n.Right() != nil && n.Right().Type() != nil {
|
||||||
if n.Right().Type().IsFuncArgStruct() {
|
if n.Right().Type().IsFuncArgStruct() {
|
||||||
base.Errorf("assignment mismatch: 1 variable but %v returns %d values", n.Right().Left(), n.Right().Type().NumFields())
|
base.Errorf("assignment mismatch: 1 variable but %v returns %d values", n.Right().(*ir.CallExpr).Left(), n.Right().Type().NumFields())
|
||||||
// Multi-value RHS isn't actually valid for OAS; nil out
|
// Multi-value RHS isn't actually valid for OAS; nil out
|
||||||
// to indicate failed typechecking.
|
// to indicate failed typechecking.
|
||||||
n.Right().SetType(nil)
|
n.Right().SetType(nil)
|
||||||
|
|
@ -3233,7 +3293,7 @@ func checkassignto(src *types.Type, dst ir.Node) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func typecheckas2(n ir.Node) {
|
func typecheckas2(n *ir.AssignListStmt) {
|
||||||
if enableTrace && base.Flag.LowerT {
|
if enableTrace && base.Flag.LowerT {
|
||||||
defer tracePrint("typecheckas2", n)(nil)
|
defer tracePrint("typecheckas2", n)(nil)
|
||||||
}
|
}
|
||||||
|
|
@ -3400,7 +3460,7 @@ func typecheckfunc(n *ir.Func) {
|
||||||
|
|
||||||
// The result of stringtoruneslit MUST be assigned back to n, e.g.
|
// The result of stringtoruneslit MUST be assigned back to n, e.g.
|
||||||
// n.Left = stringtoruneslit(n.Left)
|
// n.Left = stringtoruneslit(n.Left)
|
||||||
func stringtoruneslit(n ir.Node) ir.Node {
|
func stringtoruneslit(n *ir.ConvExpr) ir.Node {
|
||||||
if n.Left().Op() != ir.OLITERAL || n.Left().Val().Kind() != constant.String {
|
if n.Left().Op() != ir.OLITERAL || n.Left().Val().Kind() != constant.String {
|
||||||
base.Fatalf("stringtoarraylit %v", n)
|
base.Fatalf("stringtoarraylit %v", n)
|
||||||
}
|
}
|
||||||
|
|
@ -3683,19 +3743,25 @@ func markBreak(fn *ir.Func) {
|
||||||
|
|
||||||
case ir.OBREAK:
|
case ir.OBREAK:
|
||||||
if n.Sym() == nil {
|
if n.Sym() == nil {
|
||||||
if implicit != nil {
|
setHasBreak(implicit)
|
||||||
implicit.SetHasBreak(true)
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if lab := labels[n.Sym()]; lab != nil {
|
setHasBreak(labels[n.Sym()])
|
||||||
lab.SetHasBreak(true)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OTYPESW, ir.OSELECT, ir.ORANGE:
|
case ir.OFOR, ir.OFORUNTIL, ir.OSWITCH, ir.OSELECT, ir.ORANGE:
|
||||||
old := implicit
|
old := implicit
|
||||||
implicit = n
|
implicit = n
|
||||||
sym := n.Sym()
|
var sym *types.Sym
|
||||||
|
switch n := n.(type) {
|
||||||
|
case *ir.ForStmt:
|
||||||
|
sym = n.Sym()
|
||||||
|
case *ir.RangeStmt:
|
||||||
|
sym = n.Sym()
|
||||||
|
case *ir.SelectStmt:
|
||||||
|
sym = n.Sym()
|
||||||
|
case *ir.SwitchStmt:
|
||||||
|
sym = n.Sym()
|
||||||
|
}
|
||||||
if sym != nil {
|
if sym != nil {
|
||||||
if labels == nil {
|
if labels == nil {
|
||||||
// Map creation delayed until we need it - most functions don't.
|
// Map creation delayed until we need it - most functions don't.
|
||||||
|
|
@ -3715,6 +3781,39 @@ func markBreak(fn *ir.Func) {
|
||||||
mark(fn)
|
mark(fn)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func controlLabel(n ir.Node) *types.Sym {
|
||||||
|
switch n := n.(type) {
|
||||||
|
default:
|
||||||
|
base.Fatalf("controlLabel %+v", n.Op())
|
||||||
|
return nil
|
||||||
|
case *ir.ForStmt:
|
||||||
|
return n.Sym()
|
||||||
|
case *ir.RangeStmt:
|
||||||
|
return n.Sym()
|
||||||
|
case *ir.SelectStmt:
|
||||||
|
return n.Sym()
|
||||||
|
case *ir.SwitchStmt:
|
||||||
|
return n.Sym()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func setHasBreak(n ir.Node) {
|
||||||
|
switch n := n.(type) {
|
||||||
|
default:
|
||||||
|
base.Fatalf("setHasBreak %+v", n.Op())
|
||||||
|
case nil:
|
||||||
|
// ignore
|
||||||
|
case *ir.ForStmt:
|
||||||
|
n.SetHasBreak(true)
|
||||||
|
case *ir.RangeStmt:
|
||||||
|
n.SetHasBreak(true)
|
||||||
|
case *ir.SelectStmt:
|
||||||
|
n.SetHasBreak(true)
|
||||||
|
case *ir.SwitchStmt:
|
||||||
|
n.SetHasBreak(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// isTermNodes reports whether the Nodes list ends with a terminating statement.
|
// isTermNodes reports whether the Nodes list ends with a terminating statement.
|
||||||
func isTermNodes(l ir.Nodes) bool {
|
func isTermNodes(l ir.Nodes) bool {
|
||||||
s := l.Slice()
|
s := l.Slice()
|
||||||
|
|
@ -3752,23 +3851,32 @@ func isTermNode(n ir.Node) bool {
|
||||||
case ir.OIF:
|
case ir.OIF:
|
||||||
return isTermNodes(n.Body()) && isTermNodes(n.Rlist())
|
return isTermNodes(n.Body()) && isTermNodes(n.Rlist())
|
||||||
|
|
||||||
case ir.OSWITCH, ir.OTYPESW, ir.OSELECT:
|
case ir.OSWITCH:
|
||||||
if n.HasBreak() {
|
if n.HasBreak() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
def := false
|
def := false
|
||||||
for _, n1 := range n.List().Slice() {
|
for _, cas := range n.List().Slice() {
|
||||||
if !isTermNodes(n1.Body()) {
|
cas := cas.(*ir.CaseStmt)
|
||||||
|
if !isTermNodes(cas.Body()) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if n1.List().Len() == 0 { // default
|
if cas.List().Len() == 0 { // default
|
||||||
def = true
|
def = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return def
|
||||||
|
|
||||||
if n.Op() != ir.OSELECT && !def {
|
case ir.OSELECT:
|
||||||
|
if n.HasBreak() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
for _, cas := range n.List().Slice() {
|
||||||
|
cas := cas.(*ir.CaseStmt)
|
||||||
|
if !isTermNodes(cas.Body()) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue