mirror of
https://github.com/golang/go.git
synced 2024-09-21 10:28:27 +00:00
[dev.regabi] cmd/compile: arrange for typecheck1 to end in switch
Ending typecheck1 in the switch makes it safe for each case to do an appropriate type assertion. The main change is dropping the computation of "ok" and using the syntax nodes themselves to decide what's OK. Passes buildall w/ toolstash -cmp. Change-Id: I2a1873a51e3f1194d74bb87a6653cb9857a02a1b Reviewed-on: https://go-review.googlesource.com/c/go/+/275444 Trust: Russ Cox <rsc@golang.org> Reviewed-by: Matthew Dempsky <mdempsky@google.com>
This commit is contained in:
parent
dcc640e839
commit
ef5964dd6b
@ -307,17 +307,91 @@ func typecheck(n ir.Node, top int) (res ir.Node) {
|
||||
return n
|
||||
}
|
||||
|
||||
n.SetTypecheck(2)
|
||||
|
||||
typecheck_tcstack = append(typecheck_tcstack, n)
|
||||
n = typecheck1(n, top)
|
||||
|
||||
n.SetTypecheck(2)
|
||||
n = typecheck1(n, top)
|
||||
n.SetTypecheck(1)
|
||||
|
||||
last := len(typecheck_tcstack) - 1
|
||||
typecheck_tcstack[last] = nil
|
||||
typecheck_tcstack = typecheck_tcstack[:last]
|
||||
|
||||
_, isExpr := n.(ir.Expr)
|
||||
_, isStmt := n.(ir.Stmt)
|
||||
isMulti := false
|
||||
switch n.Op() {
|
||||
case ir.OCALLFUNC, ir.OCALLINTER, ir.OCALLMETH:
|
||||
if t := n.Left().Type(); t != nil && t.Kind() == types.TFUNC {
|
||||
nr := t.NumResults()
|
||||
isMulti = nr > 1
|
||||
if nr == 0 {
|
||||
isExpr = false
|
||||
}
|
||||
}
|
||||
case ir.OAPPEND:
|
||||
// Must be used (and not BinaryExpr/UnaryExpr).
|
||||
isStmt = false
|
||||
case ir.OCLOSE, ir.ODELETE, ir.OPANIC, ir.OPRINT, ir.OPRINTN, ir.OVARKILL, ir.OVARLIVE:
|
||||
// Must not be used.
|
||||
isExpr = false
|
||||
isStmt = true
|
||||
case ir.OCOPY, ir.ORECOVER, ir.ORECV:
|
||||
// Can be used or not.
|
||||
isStmt = true
|
||||
}
|
||||
|
||||
t := n.Type()
|
||||
if t != nil && !t.IsFuncArgStruct() && n.Op() != ir.OTYPE {
|
||||
switch t.Kind() {
|
||||
case types.TFUNC, // might have TANY; wait until it's called
|
||||
types.TANY, types.TFORW, types.TIDEAL, types.TNIL, types.TBLANK:
|
||||
break
|
||||
|
||||
default:
|
||||
checkwidth(t)
|
||||
}
|
||||
}
|
||||
if t != nil {
|
||||
n = evalConst(n)
|
||||
t = n.Type()
|
||||
}
|
||||
|
||||
// TODO(rsc): Lots of the complexity here is because typecheck can
|
||||
// see OTYPE, ONAME, and OLITERAL nodes multiple times.
|
||||
// Once we make the IR a proper tree, we should be able to simplify
|
||||
// this code a bit, especially the final case.
|
||||
switch {
|
||||
case top&(ctxStmt|ctxExpr) == ctxExpr && !isExpr && n.Op() != ir.OTYPE && !isMulti:
|
||||
if !n.Diag() {
|
||||
base.Errorf("%v used as value", n)
|
||||
n.SetDiag(true)
|
||||
}
|
||||
if t != nil {
|
||||
n.SetType(nil)
|
||||
}
|
||||
|
||||
case top&ctxType == 0 && n.Op() == ir.OTYPE && t != nil:
|
||||
if !n.Type().Broke() {
|
||||
base.Errorf("type %v is not an expression", n.Type())
|
||||
}
|
||||
n.SetType(nil)
|
||||
|
||||
case top&(ctxStmt|ctxExpr) == ctxStmt && !isStmt && t != nil:
|
||||
if !n.Diag() {
|
||||
base.Errorf("%v evaluated but not used", n)
|
||||
n.SetDiag(true)
|
||||
}
|
||||
n.SetType(nil)
|
||||
|
||||
case top&(ctxType|ctxExpr) == ctxType && n.Op() != ir.OTYPE && n.Op() != ir.ONONAME && (t != nil || n.Op() == ir.ONAME):
|
||||
base.Errorf("%v is not a type", n)
|
||||
if t != nil {
|
||||
n.SetType(nil)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
base.Pos = lno
|
||||
return n
|
||||
}
|
||||
@ -335,8 +409,7 @@ func indexlit(n ir.Node) ir.Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// The result of typecheck1 MUST be assigned back to n, e.g.
|
||||
// n.Left = typecheck1(n.Left, top)
|
||||
// typecheck1 should ONLY be called from typecheck.
|
||||
func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
if enableTrace && base.Flag.LowerT {
|
||||
defer tracePrint("typecheck1", n)(&res)
|
||||
@ -345,7 +418,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
switch n.Op() {
|
||||
case ir.OLITERAL, ir.ONAME, ir.ONONAME, ir.OTYPE:
|
||||
if n.Sym() == nil {
|
||||
break
|
||||
return n
|
||||
}
|
||||
|
||||
if n.Op() == ir.ONAME && n.SubOp() != 0 && top&ctxCallee == 0 {
|
||||
@ -361,34 +434,29 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
}
|
||||
|
||||
ok := 0
|
||||
switch n.Op() {
|
||||
// until typecheck is complete, do nothing.
|
||||
default:
|
||||
ir.Dump("typecheck", n)
|
||||
|
||||
base.Fatalf("typecheck %v", n.Op())
|
||||
panic("unreachable")
|
||||
|
||||
// names
|
||||
case ir.OLITERAL:
|
||||
ok |= ctxExpr
|
||||
|
||||
if n.Type() == nil && n.Val().Kind() == constant.String {
|
||||
base.Fatalf("string literal missing type")
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.ONIL, ir.ONONAME:
|
||||
ok |= ctxExpr
|
||||
return n
|
||||
|
||||
case ir.ONAME:
|
||||
if n.Name().Decldepth == 0 {
|
||||
n.Name().Decldepth = decldepth
|
||||
}
|
||||
if n.SubOp() != 0 {
|
||||
ok |= ctxCallee
|
||||
break
|
||||
return n
|
||||
}
|
||||
|
||||
if top&ctxAssign == 0 {
|
||||
// not a write to the variable
|
||||
if ir.IsBlank(n) {
|
||||
@ -396,11 +464,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
n.Name().SetUsed(true)
|
||||
}
|
||||
|
||||
ok |= ctxExpr
|
||||
return n
|
||||
|
||||
case ir.OPACK:
|
||||
base.Errorf("use of package %v without selector", n.Sym())
|
||||
@ -409,14 +475,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
|
||||
// types (ODEREF is with exprs)
|
||||
case ir.OTYPE:
|
||||
ok |= ctxType
|
||||
|
||||
if n.Type() == nil {
|
||||
return n
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OTSLICE:
|
||||
ok |= ctxType
|
||||
n := n.(*ir.SliceType)
|
||||
n.Elem = typecheck(n.Elem, ctxType)
|
||||
if n.Elem.Type() == nil {
|
||||
@ -425,9 +489,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
t := types.NewSlice(n.Elem.Type())
|
||||
n.SetOTYPE(t)
|
||||
checkwidth(t)
|
||||
return n
|
||||
|
||||
case ir.OTARRAY:
|
||||
ok |= ctxType
|
||||
n := n.(*ir.ArrayType)
|
||||
n.Elem = typecheck(n.Elem, ctxType)
|
||||
if n.Elem.Type() == nil {
|
||||
@ -469,9 +533,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
t := types.NewArray(n.Elem.Type(), bound)
|
||||
n.SetOTYPE(t)
|
||||
checkwidth(t)
|
||||
return n
|
||||
|
||||
case ir.OTMAP:
|
||||
ok |= ctxType
|
||||
n := n.(*ir.MapType)
|
||||
n.Key = typecheck(n.Key, ctxType)
|
||||
n.Elem = typecheck(n.Elem, ctxType)
|
||||
@ -488,9 +552,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
n.SetOTYPE(types.NewMap(l.Type(), r.Type()))
|
||||
mapqueue = append(mapqueue, n) // check map keys when all types are settled
|
||||
return n
|
||||
|
||||
case ir.OTCHAN:
|
||||
ok |= ctxType
|
||||
n := n.(*ir.ChanType)
|
||||
n.Elem = typecheck(n.Elem, ctxType)
|
||||
l := n.Elem
|
||||
@ -501,21 +565,22 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
base.Errorf("chan of incomplete (or unallocatable) type not allowed")
|
||||
}
|
||||
n.SetOTYPE(types.NewChan(l.Type(), n.Dir))
|
||||
return n
|
||||
|
||||
case ir.OTSTRUCT:
|
||||
ok |= ctxType
|
||||
n := n.(*ir.StructType)
|
||||
n.SetOTYPE(tostruct(n.Fields))
|
||||
return n
|
||||
|
||||
case ir.OTINTER:
|
||||
ok |= ctxType
|
||||
n := n.(*ir.InterfaceType)
|
||||
n.SetOTYPE(tointerface(n.Methods))
|
||||
return n
|
||||
|
||||
case ir.OTFUNC:
|
||||
ok |= ctxType
|
||||
n := n.(*ir.FuncType)
|
||||
n.SetOTYPE(functype(n.Recv, n.Params, n.Results))
|
||||
return n
|
||||
|
||||
// type or expr
|
||||
case ir.ODEREF:
|
||||
@ -528,11 +593,10 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
return n
|
||||
}
|
||||
if l.Op() == ir.OTYPE {
|
||||
ok |= ctxType
|
||||
n.SetOTYPE(types.NewPtr(l.Type()))
|
||||
// Ensure l.Type gets dowidth'd for the backend. Issue 20174.
|
||||
checkwidth(l.Type())
|
||||
break
|
||||
return n
|
||||
}
|
||||
|
||||
if !t.IsPtr() {
|
||||
@ -541,12 +605,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
break
|
||||
base.Errorf("%v is not a type", l)
|
||||
return n
|
||||
}
|
||||
|
||||
ok |= ctxExpr
|
||||
n.SetType(t.Elem())
|
||||
return n
|
||||
|
||||
// arithmetic exprs
|
||||
case ir.OASOP,
|
||||
@ -573,7 +637,6 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
var op ir.Op
|
||||
var r ir.Node
|
||||
if n.Op() == ir.OASOP {
|
||||
ok |= ctxStmt
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetRight(typecheck(n.Right(), ctxExpr))
|
||||
l = n.Left()
|
||||
@ -591,7 +654,6 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
// TODO(marvin): Fix Node.EType type union.
|
||||
op = n.SubOp()
|
||||
} else {
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetRight(typecheck(n.Right(), ctxExpr))
|
||||
l = n.Left()
|
||||
@ -629,8 +691,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
if (l.Type() == types.UntypedFloat || l.Type() == types.UntypedComplex) && r.Op() == ir.OLITERAL {
|
||||
n.SetType(types.UntypedInt)
|
||||
}
|
||||
|
||||
break
|
||||
return n
|
||||
}
|
||||
|
||||
// For "x == x && len(s)", it's better to report that "len(s)" (type int)
|
||||
@ -815,9 +876,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
n.SetType(t)
|
||||
return n
|
||||
|
||||
case ir.OBITNOT, ir.ONEG, ir.ONOT, ir.OPLUS:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
l := n.Left()
|
||||
t := l.Type()
|
||||
@ -832,11 +893,10 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
n.SetType(t)
|
||||
return n
|
||||
|
||||
// exprs
|
||||
case ir.OADDR:
|
||||
ok |= ctxExpr
|
||||
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
if n.Left().Type() == nil {
|
||||
n.SetType(nil)
|
||||
@ -871,13 +931,10 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
n.SetType(types.NewPtr(n.Left().Type()))
|
||||
return n
|
||||
|
||||
case ir.OCOMPLIT:
|
||||
ok |= ctxExpr
|
||||
n = typecheckcomplit(n)
|
||||
if n.Type() == nil {
|
||||
return n
|
||||
}
|
||||
return typecheckcomplit(n)
|
||||
|
||||
case ir.OXDOT, ir.ODOT:
|
||||
if n.Op() == ir.OXDOT {
|
||||
@ -903,12 +960,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
s := n.Sym()
|
||||
|
||||
if n.Left().Op() == ir.OTYPE {
|
||||
n = typecheckMethodExpr(n)
|
||||
if n.Type() == nil {
|
||||
return n
|
||||
}
|
||||
ok = ctxExpr
|
||||
break
|
||||
return typecheckMethodExpr(n)
|
||||
}
|
||||
|
||||
if t.IsPtr() && !t.Elem().IsInterface() {
|
||||
@ -952,21 +1004,12 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
return n
|
||||
}
|
||||
|
||||
switch n.Op() {
|
||||
case ir.ODOTINTER, ir.ODOTMETH:
|
||||
if top&ctxCallee != 0 {
|
||||
ok |= ctxCallee
|
||||
} else {
|
||||
n = typecheckpartialcall(n, s)
|
||||
ok |= ctxExpr
|
||||
}
|
||||
|
||||
default:
|
||||
ok |= ctxExpr
|
||||
if (n.Op() == ir.ODOTINTER || n.Op() == ir.ODOTMETH) && top&ctxCallee == 0 {
|
||||
n = typecheckpartialcall(n, s)
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.ODOTTYPE:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetLeft(defaultlit(n.Left(), nil))
|
||||
l := n.Left()
|
||||
@ -1009,9 +1052,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
return n
|
||||
}
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OINDEX:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetLeft(defaultlit(n.Left(), nil))
|
||||
n.SetLeft(implicitstar(n.Left()))
|
||||
@ -1045,7 +1088,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
|
||||
if n.Right().Type() != nil && !n.Right().Type().IsInteger() {
|
||||
base.Errorf("non-integer %s index %v", why, n.Right())
|
||||
break
|
||||
return n
|
||||
}
|
||||
|
||||
if !n.Bounded() && ir.IsConst(n.Right(), constant.Int) {
|
||||
@ -1067,9 +1110,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
n.SetOp(ir.OINDEXMAP)
|
||||
n.SetIndexMapLValue(false)
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.ORECV:
|
||||
ok |= ctxStmt | ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetLeft(defaultlit(n.Left(), nil))
|
||||
l := n.Left()
|
||||
@ -1091,9 +1134,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
n.SetType(t.Elem())
|
||||
return n
|
||||
|
||||
case ir.OSEND:
|
||||
ok |= ctxStmt
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetRight(typecheck(n.Right(), ctxExpr))
|
||||
n.SetLeft(defaultlit(n.Left(), nil))
|
||||
@ -1115,14 +1158,13 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
if n.Right().Type() == nil {
|
||||
return n
|
||||
}
|
||||
return 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.
|
||||
ok |= ctxExpr
|
||||
|
||||
t := n.Type()
|
||||
if t == nil {
|
||||
base.Fatalf("no type specified for OSLICEHEADER")
|
||||
@ -1160,14 +1202,13 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
|
||||
n.List().SetFirst(l)
|
||||
n.List().SetSecond(c)
|
||||
return 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.
|
||||
ok |= ctxExpr
|
||||
|
||||
t := n.Type()
|
||||
|
||||
if t == nil {
|
||||
@ -1203,9 +1244,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
base.Fatalf("len for OMAKESLICECOPY must be non-negative")
|
||||
}
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OSLICE, ir.OSLICE3:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
low, high, max := n.SliceBounds()
|
||||
hasmax := n.Op().IsSlice3()
|
||||
@ -1277,6 +1318,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
return n
|
||||
|
||||
// call and call like
|
||||
case ir.OCALL:
|
||||
@ -1306,6 +1348,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
case ir.OAPPEND, ir.ODELETE, ir.OMAKE, ir.OPRINT, ir.OPRINTN, ir.ORECOVER:
|
||||
n.SetOp(l.SubOp())
|
||||
n.SetLeft(nil)
|
||||
n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
|
||||
|
||||
case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
|
||||
typecheckargs(n)
|
||||
@ -1331,8 +1374,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
n = ir.NodAt(n.Pos(), l.SubOp(), arg1, arg2)
|
||||
n = initExpr(old.Init().Slice(), n) // typecheckargs can add to old.Init
|
||||
}
|
||||
n = typecheck1(n, top)
|
||||
return n
|
||||
return typecheck(n, top)
|
||||
}
|
||||
|
||||
n.SetLeft(defaultlit(n.Left(), nil))
|
||||
@ -1346,8 +1388,6 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
// pick off before type-checking arguments
|
||||
ok |= ctxExpr
|
||||
|
||||
arg, ok := needOneArg(n, "conversion to %v", l.Type())
|
||||
if !ok {
|
||||
n.SetType(nil)
|
||||
@ -1356,8 +1396,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
|
||||
n = ir.NodAt(n.Pos(), ir.OCONV, arg, nil)
|
||||
n.SetType(l.Type())
|
||||
n = typecheck1(n, top)
|
||||
return n
|
||||
return typecheck1(n, top)
|
||||
}
|
||||
|
||||
typecheckargs(n)
|
||||
@ -1403,11 +1442,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
typecheckaste(ir.OCALL, n.Left(), n.IsDDD(), t.Params(), n.List(), func() string { return fmt.Sprintf("argument to %v", n.Left()) })
|
||||
ok |= ctxStmt
|
||||
if t.NumResults() == 0 {
|
||||
break
|
||||
return n
|
||||
}
|
||||
ok |= ctxExpr
|
||||
if t.NumResults() == 1 {
|
||||
n.SetType(l.Type().Results().Field(0).Type)
|
||||
|
||||
@ -1420,24 +1457,23 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
// and we want to avoid the temporaries, so we do the rewrite earlier than is typical.
|
||||
n.SetOp(ir.OGETG)
|
||||
}
|
||||
|
||||
break
|
||||
return n
|
||||
}
|
||||
|
||||
// multiple return
|
||||
if top&(ctxMultiOK|ctxStmt) == 0 {
|
||||
base.Errorf("multiple-value %v() in single-value context", l)
|
||||
break
|
||||
return n
|
||||
}
|
||||
|
||||
n.SetType(l.Type().Results())
|
||||
return n
|
||||
|
||||
case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
|
||||
ok |= ctxExpr
|
||||
n.SetType(types.Types[types.TUINTPTR])
|
||||
return n
|
||||
|
||||
case ir.OCAP, ir.OLEN:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetLeft(defaultlit(n.Left(), nil))
|
||||
n.SetLeft(implicitstar(n.Left()))
|
||||
@ -1461,9 +1497,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
n.SetType(types.Types[types.TINT])
|
||||
return n
|
||||
|
||||
case ir.OREAL, ir.OIMAG:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
l := n.Left()
|
||||
t := l.Type()
|
||||
@ -1485,9 +1521,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OCOMPLEX:
|
||||
ok |= ctxExpr
|
||||
l := typecheck(n.Left(), ctxExpr)
|
||||
r := typecheck(n.Right(), ctxExpr)
|
||||
if l.Type() == nil || r.Type() == nil {
|
||||
@ -1525,6 +1561,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
t = types.Types[types.TCOMPLEX128]
|
||||
}
|
||||
n.SetType(t)
|
||||
return n
|
||||
|
||||
case ir.OCLOSE:
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
@ -1546,11 +1583,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
ok |= ctxStmt
|
||||
return n
|
||||
|
||||
case ir.ODELETE:
|
||||
ok |= ctxStmt
|
||||
typecheckargs(n)
|
||||
args := n.List()
|
||||
if args.Len() == 0 {
|
||||
@ -1580,9 +1615,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
args.SetSecond(assignconv(r, l.Type().Key(), "delete"))
|
||||
return n
|
||||
|
||||
case ir.OAPPEND:
|
||||
ok |= ctxExpr
|
||||
typecheckargs(n)
|
||||
args := n.List()
|
||||
if args.Len() == 0 {
|
||||
@ -1625,11 +1660,11 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
|
||||
if t.Elem().IsKind(types.TUINT8) && args.Second().Type().IsString() {
|
||||
args.SetSecond(defaultlit(args.Second(), types.Types[types.TSTRING]))
|
||||
break
|
||||
return n
|
||||
}
|
||||
|
||||
args.SetSecond(assignconv(args.Second(), t.Underlying(), "append"))
|
||||
break
|
||||
return n
|
||||
}
|
||||
|
||||
as := args.Slice()[1:]
|
||||
@ -1640,9 +1675,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
as[i] = assignconv(n, t.Elem(), "append")
|
||||
checkwidth(as[i].Type()) // ensure width is calculated for backend
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OCOPY:
|
||||
ok |= ctxStmt | ctxExpr
|
||||
n.SetType(types.Types[types.TINT])
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetLeft(defaultlit(n.Left(), nil))
|
||||
@ -1656,7 +1691,7 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
// copy([]byte, string)
|
||||
if n.Left().Type().IsSlice() && n.Right().Type().IsString() {
|
||||
if types.Identical(n.Left().Type().Elem(), types.ByteType) {
|
||||
break
|
||||
return n
|
||||
}
|
||||
base.Errorf("arguments to copy have different element types: %L and string", n.Left().Type())
|
||||
n.SetType(nil)
|
||||
@ -1680,9 +1715,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OCONV:
|
||||
ok |= ctxExpr
|
||||
checkwidth(n.Type()) // ensure width is calculated for backend
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetLeft(convlit1(n.Left(), n.Type(), true, nil))
|
||||
@ -1717,16 +1752,16 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
// do not convert to []byte literal. See CL 125796.
|
||||
// generated code and compiler memory footprint is better without it.
|
||||
case ir.OSTR2BYTES:
|
||||
break
|
||||
// ok
|
||||
|
||||
case ir.OSTR2RUNES:
|
||||
if n.Left().Op() == ir.OLITERAL {
|
||||
n = stringtoruneslit(n)
|
||||
}
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OMAKE:
|
||||
ok |= ctxExpr
|
||||
args := n.List().Slice()
|
||||
if len(args) == 0 {
|
||||
base.Errorf("missing argument to make")
|
||||
@ -1832,9 +1867,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
|
||||
nn.SetType(t)
|
||||
n = nn
|
||||
return n
|
||||
|
||||
case ir.ONEW:
|
||||
ok |= ctxExpr
|
||||
if n.Left() == nil {
|
||||
// Fatalf because the OCALL above checked for us,
|
||||
// so this must be an internally-generated mistake.
|
||||
@ -1849,9 +1884,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
n.SetLeft(l)
|
||||
n.SetType(types.NewPtr(t))
|
||||
return n
|
||||
|
||||
case ir.OPRINT, ir.OPRINTN:
|
||||
ok |= ctxStmt
|
||||
typecheckargs(n)
|
||||
ls := n.List().Slice()
|
||||
for i1, n1 := range ls {
|
||||
@ -1862,18 +1897,18 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
ls[i1] = defaultlit(ls[i1], nil)
|
||||
}
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OPANIC:
|
||||
ok |= ctxStmt
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetLeft(defaultlit(n.Left(), types.Types[types.TINTER]))
|
||||
if n.Left().Type() == nil {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.ORECOVER:
|
||||
ok |= ctxExpr | ctxStmt
|
||||
if n.List().Len() != 0 {
|
||||
base.Errorf("too many arguments to recover")
|
||||
n.SetType(nil)
|
||||
@ -1881,16 +1916,16 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
n.SetType(types.Types[types.TINTER])
|
||||
return n
|
||||
|
||||
case ir.OCLOSURE:
|
||||
ok |= ctxExpr
|
||||
typecheckclosure(n, top)
|
||||
if n.Type() == nil {
|
||||
return n
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OITAB:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
t := n.Left().Type()
|
||||
if t == nil {
|
||||
@ -1901,14 +1936,15 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
base.Fatalf("OITAB of %v", t)
|
||||
}
|
||||
n.SetType(types.NewPtr(types.Types[types.TUINTPTR]))
|
||||
return n
|
||||
|
||||
case ir.OIDATA:
|
||||
// Whoever creates the OIDATA node must know a priori the concrete type at that moment,
|
||||
// usually by just having checked the OITAB.
|
||||
base.Fatalf("cannot typecheck interface data %v", n)
|
||||
panic("unreachable")
|
||||
|
||||
case ir.OSPTR:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
t := n.Left().Type()
|
||||
if t == nil {
|
||||
@ -1923,33 +1959,33 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
} else {
|
||||
n.SetType(types.NewPtr(t.Elem()))
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OCLOSUREREAD:
|
||||
ok |= ctxExpr
|
||||
return n
|
||||
|
||||
case ir.OCFUNC:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetType(types.Types[types.TUINTPTR])
|
||||
return n
|
||||
|
||||
case ir.OCONVNOP:
|
||||
ok |= ctxExpr
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
return n
|
||||
|
||||
// statements
|
||||
case ir.OAS:
|
||||
ok |= ctxStmt
|
||||
|
||||
typecheckas(n)
|
||||
|
||||
// Code that creates temps does not bother to set defn, so do it here.
|
||||
if n.Left().Op() == ir.ONAME && ir.IsAutoTmp(n.Left()) {
|
||||
n.Left().Name().Defn = n
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OAS2:
|
||||
ok |= ctxStmt
|
||||
typecheckas2(n)
|
||||
return n
|
||||
|
||||
case ir.OBREAK,
|
||||
ir.OCONTINUE,
|
||||
@ -1958,14 +1994,13 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
ir.OFALL,
|
||||
ir.OVARKILL,
|
||||
ir.OVARLIVE:
|
||||
ok |= ctxStmt
|
||||
return n
|
||||
|
||||
case ir.OBLOCK:
|
||||
ok |= ctxStmt
|
||||
typecheckslice(n.List().Slice(), ctxStmt)
|
||||
return n
|
||||
|
||||
case ir.OLABEL:
|
||||
ok |= ctxStmt
|
||||
decldepth++
|
||||
if n.Sym().IsBlank() {
|
||||
// Empty identifier is valid but useless.
|
||||
@ -1973,21 +2008,21 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
// See issues 7538, 11589, 11593.
|
||||
n = ir.NodAt(n.Pos(), ir.OBLOCK, nil, nil)
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.ODEFER:
|
||||
ok |= ctxStmt
|
||||
n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr))
|
||||
if !n.Left().Diag() {
|
||||
checkdefergo(n)
|
||||
}
|
||||
return n
|
||||
|
||||
case ir.OGO:
|
||||
ok |= ctxStmt
|
||||
n.SetLeft(typecheck(n.Left(), ctxStmt|ctxExpr))
|
||||
checkdefergo(n)
|
||||
return n
|
||||
|
||||
case ir.OFOR, ir.OFORUNTIL:
|
||||
ok |= ctxStmt
|
||||
typecheckslice(n.Init().Slice(), ctxStmt)
|
||||
decldepth++
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
@ -2004,9 +2039,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
typecheckslice(n.Body().Slice(), ctxStmt)
|
||||
decldepth--
|
||||
return n
|
||||
|
||||
case ir.OIF:
|
||||
ok |= ctxStmt
|
||||
typecheckslice(n.Init().Slice(), ctxStmt)
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
n.SetLeft(defaultlit(n.Left(), nil))
|
||||
@ -2018,9 +2053,9 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
typecheckslice(n.Body().Slice(), ctxStmt)
|
||||
typecheckslice(n.Rlist().Slice(), ctxStmt)
|
||||
return n
|
||||
|
||||
case ir.ORETURN:
|
||||
ok |= ctxStmt
|
||||
typecheckargs(n)
|
||||
if Curfn == nil {
|
||||
base.Errorf("return outside function")
|
||||
@ -2029,24 +2064,25 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
}
|
||||
|
||||
if hasNamedResults(Curfn) && n.List().Len() == 0 {
|
||||
break
|
||||
return n
|
||||
}
|
||||
typecheckaste(ir.ORETURN, nil, false, Curfn.Type().Results(), n.List(), func() string { return "return argument" })
|
||||
return n
|
||||
|
||||
case ir.ORETJMP:
|
||||
ok |= ctxStmt
|
||||
return n
|
||||
|
||||
case ir.OSELECT:
|
||||
ok |= ctxStmt
|
||||
typecheckselect(n)
|
||||
return n
|
||||
|
||||
case ir.OSWITCH:
|
||||
ok |= ctxStmt
|
||||
typecheckswitch(n)
|
||||
return n
|
||||
|
||||
case ir.ORANGE:
|
||||
ok |= ctxStmt
|
||||
typecheckrange(n)
|
||||
return n
|
||||
|
||||
case ir.OTYPESW:
|
||||
base.Errorf("use of .(type) outside type switch")
|
||||
@ -2054,64 +2090,22 @@ func typecheck1(n ir.Node, top int) (res ir.Node) {
|
||||
return n
|
||||
|
||||
case ir.ODCLFUNC:
|
||||
ok |= ctxStmt
|
||||
typecheckfunc(n.(*ir.Func))
|
||||
return n
|
||||
|
||||
case ir.ODCLCONST:
|
||||
ok |= ctxStmt
|
||||
n.SetLeft(typecheck(n.Left(), ctxExpr))
|
||||
return n
|
||||
|
||||
case ir.ODCLTYPE:
|
||||
ok |= ctxStmt
|
||||
n.SetLeft(typecheck(n.Left(), ctxType))
|
||||
checkwidth(n.Left().Type())
|
||||
}
|
||||
|
||||
t := n.Type()
|
||||
if t != nil && !t.IsFuncArgStruct() && n.Op() != ir.OTYPE {
|
||||
switch t.Kind() {
|
||||
case types.TFUNC, // might have TANY; wait until it's called
|
||||
types.TANY, types.TFORW, types.TIDEAL, types.TNIL, types.TBLANK:
|
||||
break
|
||||
|
||||
default:
|
||||
checkwidth(t)
|
||||
}
|
||||
}
|
||||
|
||||
n = evalConst(n)
|
||||
if n.Op() == ir.OTYPE && top&ctxType == 0 {
|
||||
if !n.Type().Broke() {
|
||||
base.Errorf("type %v is not an expression", n.Type())
|
||||
}
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
if top&(ctxExpr|ctxType) == ctxType && n.Op() != ir.OTYPE {
|
||||
base.Errorf("%v is not a type", n)
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
// TODO(rsc): simplify
|
||||
if (top&(ctxCallee|ctxExpr|ctxType) != 0) && top&ctxStmt == 0 && ok&(ctxExpr|ctxType|ctxCallee) == 0 {
|
||||
base.Errorf("%v used as value", n)
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
if (top&ctxStmt != 0) && top&(ctxCallee|ctxExpr|ctxType) == 0 && ok&ctxStmt == 0 {
|
||||
if !n.Diag() {
|
||||
base.Errorf("%v evaluated but not used", n)
|
||||
n.SetDiag(true)
|
||||
}
|
||||
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
return n
|
||||
// No return n here!
|
||||
// Individual cases can type-assert n, introducing a new one.
|
||||
// Each must execute its own return n.
|
||||
}
|
||||
|
||||
func typecheckargs(n ir.Node) {
|
||||
|
@ -32,7 +32,13 @@ func maybeEdit(x Node, edit func(Node) Node) Node {
|
||||
return edit(x)
|
||||
}
|
||||
|
||||
// A miniStmt is a miniNode with extra fields common to expressions.
|
||||
// An Expr is a Node that can appear as an expression.
|
||||
type Expr interface {
|
||||
Node
|
||||
isExpr()
|
||||
}
|
||||
|
||||
// A miniExpr is a miniNode with extra fields common to expressions.
|
||||
// TODO(rsc): Once we are sure about the contents, compact the bools
|
||||
// into a bit field and leave extra bits available for implementations
|
||||
// embedding miniExpr. Right now there are ~60 unused bits sitting here.
|
||||
@ -52,6 +58,8 @@ const (
|
||||
miniExprBounded
|
||||
)
|
||||
|
||||
func (*miniExpr) isExpr() {}
|
||||
|
||||
func (n *miniExpr) Type() *types.Type { return n.typ }
|
||||
func (n *miniExpr) SetType(x *types.Type) { n.typ = x }
|
||||
func (n *miniExpr) Opt() interface{} { return n.opt }
|
||||
@ -192,6 +200,8 @@ func NewCallExpr(pos src.XPos, fun Node, args []Node) *CallExpr {
|
||||
return n
|
||||
}
|
||||
|
||||
func (*CallExpr) isStmt() {}
|
||||
|
||||
func (n *CallExpr) Orig() Node { return n.orig }
|
||||
func (n *CallExpr) SetOrig(x Node) { n.orig = x }
|
||||
func (n *CallExpr) Left() Node { return n.X }
|
||||
|
@ -114,6 +114,8 @@ func NewFunc(pos src.XPos) *Func {
|
||||
return f
|
||||
}
|
||||
|
||||
func (f *Func) isStmt() {}
|
||||
|
||||
func (f *Func) Func() *Func { return f }
|
||||
func (f *Func) Body() Nodes { return f.body }
|
||||
func (f *Func) PtrBody() *Nodes { return &f.body }
|
||||
|
@ -121,6 +121,8 @@ type Name struct {
|
||||
Outer *Name
|
||||
}
|
||||
|
||||
func (n *Name) isExpr() {}
|
||||
|
||||
// NewNameAt returns a new ONAME Node associated with symbol s at position pos.
|
||||
// The caller is responsible for setting Curfn.
|
||||
func NewNameAt(pos src.XPos, sym *types.Sym) *Name {
|
||||
|
@ -27,15 +27,26 @@ func NewDecl(pos src.XPos, op Op, x Node) *Decl {
|
||||
return n
|
||||
}
|
||||
|
||||
func (*Decl) isStmt() {}
|
||||
|
||||
func (n *Decl) Left() Node { return n.X }
|
||||
func (n *Decl) SetLeft(x Node) { n.X = x }
|
||||
|
||||
// A Stmt is a Node that can appear as a statement.
|
||||
// This includes statement-like expressions such as <-c and f().
|
||||
type Stmt interface {
|
||||
Node
|
||||
isStmt()
|
||||
}
|
||||
|
||||
// A miniStmt is a miniNode with extra fields common to statements.
|
||||
type miniStmt struct {
|
||||
miniNode
|
||||
init Nodes
|
||||
}
|
||||
|
||||
func (*miniStmt) isStmt() {}
|
||||
|
||||
func (n *miniStmt) Init() Nodes { return n.init }
|
||||
func (n *miniStmt) SetInit(x Nodes) { n.init = x }
|
||||
func (n *miniStmt) PtrInit() *Nodes { return &n.init }
|
||||
|
@ -10,7 +10,7 @@ import "unsafe"
|
||||
|
||||
const C = 1
|
||||
|
||||
var x1, x int
|
||||
var x, x1, x2 int
|
||||
var b bool
|
||||
var s string
|
||||
var c chan int
|
||||
@ -120,7 +120,6 @@ func _() {
|
||||
_ = print(1) // ERROR "print\(1\) used as value"
|
||||
println(1) // ok
|
||||
_ = println(1) // ERROR "println\(1\) used as value"
|
||||
(x) // ERROR "x evaluated but not used"
|
||||
c <- 1 // ok
|
||||
slice[1:1] // ERROR "slice\[1:1\] evaluated but not used"
|
||||
array[1:1] // ERROR "array\[1:1\] evaluated but not used"
|
||||
@ -137,6 +136,8 @@ func _() {
|
||||
unsafe.Alignof(t.X) // ERROR "unsafe.Alignof\(t.X\) evaluated but not used"
|
||||
unsafe.Offsetof(t.X) // ERROR "unsafe.Offsetof\(t.X\) evaluated but not used"
|
||||
unsafe.Sizeof(t) // ERROR "unsafe.Sizeof\(t\) evaluated but not used"
|
||||
_ = new(x) // ERROR "x is not a type"
|
||||
_ = int // ERROR "type int is not an expression"
|
||||
(x) // ERROR "x evaluated but not used"
|
||||
_ = new(x2) // ERROR "x2 is not a type"
|
||||
_ = new(1 + 1) // ERROR "1 \+ 1 is not a type"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user