mirror of https://github.com/golang/go.git
internal/abi, cmd/compile, runtime: deduplicate rangefunc consts
Change-Id: I61ec5a7fa0c10f95ae2261c3349743d6fda2c1d2 Reviewed-on: https://go-review.googlesource.com/c/go/+/587596 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Keith Randall <khr@golang.org> Auto-Submit: Keith Randall <khr@golang.org>
This commit is contained in:
parent
b0b1d42db3
commit
997b6969fd
|
|
@ -136,38 +136,38 @@ patterns to the yield function for a loop body.
|
|||
|
||||
The state values are:
|
||||
|
||||
const DONE = 0 // body of loop has exited in a non-panic way
|
||||
const READY = 1 // body of loop has not exited yet, is not running
|
||||
const PANIC = 2 // body of loop is either currently running, or has panicked
|
||||
const EXHAUSTED = 3 // iterator function call, e.g. f(func(x t){...}), returned so the sequence is "exhausted".
|
||||
abi.RF_DONE = 0 // body of loop has exited in a non-panic way
|
||||
abi.RF_READY = 1 // body of loop has not exited yet, is not running
|
||||
abi.RF_PANIC = 2 // body of loop is either currently running, or has panicked
|
||||
abi.RF_EXHAUSTED = 3 // iterator function call, e.g. f(func(x t){...}), returned so the sequence is "exhausted".
|
||||
|
||||
const MISSING_PANIC = 4 // used to report errors.
|
||||
abi.RF_MISSING_PANIC = 4 // used to report errors.
|
||||
|
||||
The value of #stateK transitions
|
||||
(1) before calling the iterator function,
|
||||
|
||||
var #stateN = READY
|
||||
var #stateN = abi.RF_READY
|
||||
|
||||
(2) after the iterator function call returns,
|
||||
|
||||
if #stateN == PANIC {
|
||||
panic(runtime.panicrangestate(MISSING_PANIC))
|
||||
if #stateN == abi.RF_PANIC {
|
||||
panic(runtime.panicrangestate(abi.RF_MISSING_PANIC))
|
||||
}
|
||||
#stateN = EXHAUSTED
|
||||
#stateN = abi.RF_EXHAUSTED
|
||||
|
||||
(3) at the beginning of the iteration of the loop body,
|
||||
|
||||
if #stateN != READY { runtime.panicrangestate(#stateN) }
|
||||
#stateN = PANIC
|
||||
if #stateN != abi.RF_READY { runtime.panicrangestate(#stateN) }
|
||||
#stateN = abi.RF_PANIC
|
||||
|
||||
(4) when loop iteration continues, and
|
||||
|
||||
#stateN = READY
|
||||
#stateN = abi.RF_READY
|
||||
[return true]
|
||||
|
||||
(5) when control flow exits the loop body.
|
||||
|
||||
#stateN = DONE
|
||||
#stateN = abi.RF_DONE
|
||||
[return false]
|
||||
|
||||
For example:
|
||||
|
|
@ -181,21 +181,21 @@ For example:
|
|||
becomes
|
||||
|
||||
{
|
||||
var #state1 = READY
|
||||
var #state1 = abi.RF_READY
|
||||
f(func(x T1) bool {
|
||||
if #state1 != READY { runtime.panicrangestate(#state1) }
|
||||
#state1 = PANIC
|
||||
if #state1 != abi.RF_READY { runtime.panicrangestate(#state1) }
|
||||
#state1 = abi.RF_PANIC
|
||||
...
|
||||
if ... { #state1 = DONE ; return false }
|
||||
if ... { #state1 = abi.RF_DONE ; return false }
|
||||
...
|
||||
#state1 = READY
|
||||
#state1 = abi.RF_READY
|
||||
return true
|
||||
})
|
||||
if #state1 == PANIC {
|
||||
if #state1 == abi.RF_PANIC {
|
||||
// the code for the loop body did not return normally
|
||||
panic(runtime.panicrangestate(MISSING_PANIC))
|
||||
panic(runtime.panicrangestate(abi.RF_MISSING_PANIC))
|
||||
}
|
||||
#state1 = EXHAUSTED
|
||||
#state1 = abi.RF_EXHAUSTED
|
||||
}
|
||||
|
||||
# Nested Loops
|
||||
|
|
@ -230,40 +230,40 @@ becomes
|
|||
var (
|
||||
#next int
|
||||
)
|
||||
var #state1 = READY
|
||||
var #state1 = abi.RF_READY
|
||||
f(func() bool {
|
||||
if #state1 != READY { runtime.panicrangestate(#state1) }
|
||||
#state1 = PANIC
|
||||
var #state2 = READY
|
||||
if #state1 != abi.RF_READY { runtime.panicrangestate(#state1) }
|
||||
#state1 = abi.RF_PANIC
|
||||
var #state2 = abi.RF_READY
|
||||
g(func() bool {
|
||||
if #state2 != READY { runtime.panicrangestate(#state2) }
|
||||
if #state2 != abi.RF_READY { runtime.panicrangestate(#state2) }
|
||||
...
|
||||
{
|
||||
// return a, b
|
||||
#rv1, #rv2 = a, b
|
||||
#next = -1
|
||||
#state2 = DONE
|
||||
#state2 = abi.RF_DONE
|
||||
return false
|
||||
}
|
||||
...
|
||||
#state2 = READY
|
||||
#state2 = abi.RF_READY
|
||||
return true
|
||||
})
|
||||
if #state2 == PANIC {
|
||||
panic(runtime.panicrangestate(MISSING_PANIC))
|
||||
if #state2 == abi.RF_PANIC {
|
||||
panic(runtime.panicrangestate(abi.RF_MISSING_PANIC))
|
||||
}
|
||||
#state2 = EXHAUSTED
|
||||
#state2 = abi.RF_EXHAUSTED
|
||||
if #next < 0 {
|
||||
#state1 = DONE
|
||||
#state1 = abi.RF_DONE
|
||||
return false
|
||||
}
|
||||
#state1 = READY
|
||||
#state1 = abi.RF_READY
|
||||
return true
|
||||
})
|
||||
if #state1 == PANIC {
|
||||
panic(runtime.panicrangestate(MISSING_PANIC))
|
||||
if #state1 == abi.RF_PANIC {
|
||||
panic(runtime.panicrangestate(abi.RF_MISSING_PANIC))
|
||||
}
|
||||
#state1 = EXHAUSTED
|
||||
#state1 = abi.RF_EXHAUSTED
|
||||
if #next == -1 {
|
||||
return
|
||||
}
|
||||
|
|
@ -293,7 +293,7 @@ add one or both of these to the #next checks:
|
|||
if #next >= perLoopStep*N+1 { // error checking
|
||||
// TODO reason about what exactly can appear
|
||||
// here given full or partial checking.
|
||||
runtime.panicrangestate(DONE)
|
||||
runtime.panicrangestate(abi.RF_DONE)
|
||||
}
|
||||
rv := #next & 1 == 1 // code generates into #next&1
|
||||
#next = 0
|
||||
|
|
@ -322,68 +322,68 @@ becomes
|
|||
|
||||
{
|
||||
var #next int
|
||||
var #state1 = READY
|
||||
var #state1 = abi.RF_READY
|
||||
f(func() { // 1,2
|
||||
if #state1 != READY { runtime.panicrangestate(#state1) }
|
||||
#state1 = PANIC
|
||||
var #state2 = READY
|
||||
if #state1 != abi.RF_READY { runtime.panicrangestate(#state1) }
|
||||
#state1 = abi.RF_PANIC
|
||||
var #state2 = abi.RF_READY
|
||||
g(func() { // 3,4
|
||||
if #state2 != READY { runtime.panicrangestate(#state2) }
|
||||
#state2 = PANIC
|
||||
var #state3 = READY
|
||||
if #state2 != abi.RF_READY { runtime.panicrangestate(#state2) }
|
||||
#state2 = abi.RF_PANIC
|
||||
var #state3 = abi.RF_READY
|
||||
h(func() { // 5,6
|
||||
if #state3 != READY { runtime.panicrangestate(#state3) }
|
||||
#state3 = PANIC
|
||||
if #state3 != abi.RF_READY { runtime.panicrangestate(#state3) }
|
||||
#state3 = abi.RF_PANIC
|
||||
...
|
||||
{
|
||||
// break F
|
||||
#next = 2
|
||||
#state3 = DONE
|
||||
#state3 = abi.RF_DONE
|
||||
return false
|
||||
}
|
||||
...
|
||||
{
|
||||
// continue F
|
||||
#next = 1
|
||||
#state3 = DONE
|
||||
#state3 = abi.RF_DONE
|
||||
return false
|
||||
}
|
||||
...
|
||||
#state3 = READY
|
||||
#state3 = abi.RF_READY
|
||||
return true
|
||||
})
|
||||
if #state3 == PANIC {
|
||||
panic(runtime.panicrangestate(MISSING_PANIC))
|
||||
if #state3 == abi.RF_PANIC {
|
||||
panic(runtime.panicrangestate(abi.RF_MISSING_PANIC))
|
||||
}
|
||||
#state3 = EXHAUSTED
|
||||
#state3 = abi.RF_EXHAUSTED
|
||||
if #next != 0 {
|
||||
// no breaks or continues targeting this loop
|
||||
#state2 = DONE
|
||||
#state2 = abi.RF_DONE
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
if #state2 == PANIC {
|
||||
panic(runtime.panicrangestate(MISSING_PANIC))
|
||||
if #state2 == abi.RF_PANIC {
|
||||
panic(runtime.panicrangestate(abi.RF_MISSING_PANIC))
|
||||
}
|
||||
#state2 = EXHAUSTED
|
||||
#state2 = abi.RF_EXHAUSTED
|
||||
if #next != 0 { // just exited g, test for break/continue applied to f/F
|
||||
if #next >= 1 {
|
||||
if #next >= 3 { runtime.panicrangestate(DONE) } // error
|
||||
if #next >= 3 { runtime.panicrangestate(abi.RF_DONE) } // error
|
||||
rv := #next&1 == 1
|
||||
#next = 0
|
||||
return rv
|
||||
}
|
||||
#state1 = DONE
|
||||
#state1 = abi.RF_DONE
|
||||
return false
|
||||
}
|
||||
...
|
||||
return true
|
||||
})
|
||||
if #state1 == PANIC {
|
||||
panic(runtime.panicrangestate(MISSING_PANIC))
|
||||
if #state1 == abi.RF_PANIC {
|
||||
panic(runtime.panicrangestate(abi.RF_MISSING_PANIC))
|
||||
}
|
||||
#state1 = EXHAUSTED
|
||||
#state1 = abi.RF_EXHAUSTED
|
||||
}
|
||||
|
||||
Note that the post-h checks only consider a break,
|
||||
|
|
@ -423,48 +423,48 @@ becomes
|
|||
Top: print("start\n")
|
||||
{
|
||||
var #next int
|
||||
var #state1 = READY
|
||||
var #state1 = abi.RF_READY
|
||||
f(func() {
|
||||
if #state1 != READY{ runtime.panicrangestate(#state1) }
|
||||
#state1 = PANIC
|
||||
var #state2 = READY
|
||||
if #state1 != abi.RF_READY{ runtime.panicrangestate(#state1) }
|
||||
#state1 = abi.RF_PANIC
|
||||
var #state2 = abi.RF_READY
|
||||
g(func() {
|
||||
if #state2 != READY { runtime.panicrangestate(#state2) }
|
||||
#state2 = PANIC
|
||||
if #state2 != abi.RF_READY { runtime.panicrangestate(#state2) }
|
||||
#state2 = abi.RF_PANIC
|
||||
...
|
||||
var #state3 bool = READY
|
||||
var #state3 bool = abi.RF_READY
|
||||
h(func() {
|
||||
if #state3 != READY { runtime.panicrangestate(#state3) }
|
||||
#state3 = PANIC
|
||||
if #state3 != abi.RF_READY { runtime.panicrangestate(#state3) }
|
||||
#state3 = abi.RF_PANIC
|
||||
...
|
||||
{
|
||||
// goto Top
|
||||
#next = -3
|
||||
#state3 = DONE
|
||||
#state3 = abi.RF_DONE
|
||||
return false
|
||||
}
|
||||
...
|
||||
#state3 = READY
|
||||
#state3 = abi.RF_READY
|
||||
return true
|
||||
})
|
||||
if #next < 0 {
|
||||
#state2 = DONE
|
||||
#state2 = abi.RF_DONE
|
||||
return false
|
||||
}
|
||||
#state2 = READY
|
||||
#state2 = abi.RF_READY
|
||||
return true
|
||||
})
|
||||
if #state2 == PANIC {runtime.panicrangestate(MISSING_PANIC)}
|
||||
#state2 = EXHAUSTED
|
||||
if #state2 == abi.RF_PANIC {runtime.panicrangestate(abi.RF_MISSING_PANIC)}
|
||||
#state2 = abi.RF_EXHAUSTED
|
||||
if #next < 0 {
|
||||
#state1 = DONE
|
||||
#state1 = abi.RF_DONE
|
||||
return false
|
||||
}
|
||||
#state1 = READY
|
||||
#state1 = abi.RF_READY
|
||||
return true
|
||||
})
|
||||
if #state1 == PANIC {runtime.panicrangestate(MISSING_PANIC)}
|
||||
#state1 = EXHAUSTED
|
||||
if #state1 == abi.RF_PANIC {runtime.panicrangestate(abi.RF_MISSING_PANIC)}
|
||||
#state1 = abi.RF_EXHAUSTED
|
||||
if #next == -3 {
|
||||
#next = 0
|
||||
goto Top
|
||||
|
|
@ -531,6 +531,7 @@ import (
|
|||
"cmd/compile/internal/types2"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
"internal/abi"
|
||||
"os"
|
||||
)
|
||||
|
||||
|
|
@ -593,14 +594,6 @@ type forLoop struct {
|
|||
|
||||
type State int
|
||||
|
||||
const (
|
||||
DONE = State(iota) // body of loop has exited in a non-panic way
|
||||
READY // body of loop has not exited yet, is not running
|
||||
PANIC // body of loop is either currently running, or has panicked
|
||||
EXHAUSTED // iterator function return, i.e., sequence is "exhausted"
|
||||
MISSING_PANIC // an error code, not really a state.
|
||||
)
|
||||
|
||||
// Rewrite rewrites all the range-over-funcs in the files.
|
||||
// It returns the set of function literals generated from rangefunc loop bodies.
|
||||
// This allows for rangefunc loop bodies to be distingushed by debuggers.
|
||||
|
|
@ -788,7 +781,7 @@ func (r *rewriter) stateVar(pos syntax.Pos) (*types2.Var, *syntax.VarDecl) {
|
|||
setValueType(n, typ)
|
||||
r.info.Defs[n] = obj
|
||||
|
||||
return obj, &syntax.VarDecl{NameList: []*syntax.Name{n}, Values: r.stateConst(READY)}
|
||||
return obj, &syntax.VarDecl{NameList: []*syntax.Name{n}, Values: r.stateConst(abi.RF_READY)}
|
||||
}
|
||||
|
||||
// editReturn returns the replacement for the return statement x.
|
||||
|
|
@ -827,7 +820,7 @@ func (r *rewriter) editReturn(x *syntax.ReturnStmt) syntax.Stmt {
|
|||
bl.List = append(bl.List, &syntax.AssignStmt{Lhs: r.next(), Rhs: r.intConst(next)})
|
||||
if r.checkFuncMisuse() {
|
||||
// mark this loop as exited, the others (which will be exited if iterators do not interfere) have not, yet.
|
||||
bl.List = append(bl.List, r.setState(DONE, x.Pos()))
|
||||
bl.List = append(bl.List, r.setState(abi.RF_DONE, x.Pos()))
|
||||
}
|
||||
bl.List = append(bl.List, &syntax.ReturnStmt{Results: r.useObj(r.false)})
|
||||
setPos(bl, x.Pos())
|
||||
|
|
@ -912,13 +905,13 @@ func (r *rewriter) editBranch(x *syntax.BranchStmt) syntax.Stmt {
|
|||
// Simple break or continue.
|
||||
// Continue returns true, break returns false, optionally both adjust state,
|
||||
// neither modifies #next.
|
||||
var state State
|
||||
var state abi.RF_State
|
||||
if x.Tok == syntax.Continue {
|
||||
ret = &syntax.ReturnStmt{Results: r.useObj(r.true)}
|
||||
state = READY
|
||||
state = abi.RF_READY
|
||||
} else {
|
||||
ret = &syntax.ReturnStmt{Results: r.useObj(r.false)}
|
||||
state = DONE
|
||||
state = abi.RF_DONE
|
||||
}
|
||||
var stmts []syntax.Stmt
|
||||
if r.checkFuncMisuse() {
|
||||
|
|
@ -966,7 +959,7 @@ func (r *rewriter) editBranch(x *syntax.BranchStmt) syntax.Stmt {
|
|||
if r.checkFuncMisuse() {
|
||||
// Set #stateK for this loop.
|
||||
// The exterior loops have not exited yet, and the iterator might interfere.
|
||||
bl.List = append(bl.List, r.setState(DONE, x.Pos()))
|
||||
bl.List = append(bl.List, r.setState(abi.RF_DONE, x.Pos()))
|
||||
}
|
||||
|
||||
bl.List = append(bl.List, ret)
|
||||
|
|
@ -1081,16 +1074,16 @@ func (r *rewriter) endLoop(loop *forLoop) {
|
|||
block.List = append(block.List, call)
|
||||
|
||||
if r.checkFuncMisuse() {
|
||||
// iteratorFunc has exited, check for swallowed panic, and set body state to EXHAUSTED
|
||||
// iteratorFunc has exited, check for swallowed panic, and set body state to abi.RF_EXHAUSTED
|
||||
nif := &syntax.IfStmt{
|
||||
Cond: r.cond(syntax.Eql, r.useObj(loop.stateVar), r.stateConst(PANIC)),
|
||||
Cond: r.cond(syntax.Eql, r.useObj(loop.stateVar), r.stateConst(abi.RF_PANIC)),
|
||||
Then: &syntax.BlockStmt{
|
||||
List: []syntax.Stmt{r.callPanic(start, r.stateConst(MISSING_PANIC))},
|
||||
List: []syntax.Stmt{r.callPanic(start, r.stateConst(abi.RF_MISSING_PANIC))},
|
||||
},
|
||||
}
|
||||
setPos(nif, end)
|
||||
block.List = append(block.List, nif)
|
||||
block.List = append(block.List, r.setState(EXHAUSTED, end))
|
||||
block.List = append(block.List, r.setState(abi.RF_EXHAUSTED, end))
|
||||
}
|
||||
block.List = append(block.List, checks...)
|
||||
|
||||
|
|
@ -1112,13 +1105,13 @@ func (r *rewriter) cond(op syntax.Operator, x, y syntax.Expr) *syntax.Operation
|
|||
return cond
|
||||
}
|
||||
|
||||
func (r *rewriter) setState(val State, pos syntax.Pos) *syntax.AssignStmt {
|
||||
func (r *rewriter) setState(val abi.RF_State, pos syntax.Pos) *syntax.AssignStmt {
|
||||
ss := r.setStateAt(len(r.forStack)-1, val)
|
||||
setPos(ss, pos)
|
||||
return ss
|
||||
}
|
||||
|
||||
func (r *rewriter) setStateAt(index int, stateVal State) *syntax.AssignStmt {
|
||||
func (r *rewriter) setStateAt(index int, stateVal abi.RF_State) *syntax.AssignStmt {
|
||||
loop := r.forStack[index]
|
||||
return &syntax.AssignStmt{
|
||||
Lhs: r.useObj(loop.stateVar),
|
||||
|
|
@ -1183,15 +1176,15 @@ func (r *rewriter) bodyFunc(body []syntax.Stmt, lhs []syntax.Expr, def bool, fty
|
|||
|
||||
if r.checkFuncMisuse() {
|
||||
bodyFunc.Body.List = append(bodyFunc.Body.List, r.assertReady(start, loop))
|
||||
bodyFunc.Body.List = append(bodyFunc.Body.List, r.setState(PANIC, start))
|
||||
bodyFunc.Body.List = append(bodyFunc.Body.List, r.setState(abi.RF_PANIC, start))
|
||||
}
|
||||
|
||||
// Original loop body (already rewritten by editStmt during inspect).
|
||||
bodyFunc.Body.List = append(bodyFunc.Body.List, body...)
|
||||
|
||||
// end of loop body, set state to READY and return true to continue iteration
|
||||
// end of loop body, set state to abi.RF_READY and return true to continue iteration
|
||||
if r.checkFuncMisuse() {
|
||||
bodyFunc.Body.List = append(bodyFunc.Body.List, r.setState(READY, end))
|
||||
bodyFunc.Body.List = append(bodyFunc.Body.List, r.setState(abi.RF_READY, end))
|
||||
}
|
||||
ret := &syntax.ReturnStmt{Results: r.useObj(r.true)}
|
||||
ret.SetPos(end)
|
||||
|
|
@ -1230,7 +1223,7 @@ func (r *rewriter) checks(loop *forLoop, pos syntax.Pos) []syntax.Stmt {
|
|||
// if #next != 0 {
|
||||
// if #next >= perLoopStep*N-1 { // this loop
|
||||
// if #next >= perLoopStep*N+1 { // error checking
|
||||
// runtime.panicrangestate(DONE)
|
||||
// runtime.panicrangestate(abi.RF_DONE)
|
||||
// }
|
||||
// rv := #next & 1 == 1 // code generates into #next&1
|
||||
// #next = 0
|
||||
|
|
@ -1243,7 +1236,7 @@ func (r *rewriter) checks(loop *forLoop, pos syntax.Pos) []syntax.Stmt {
|
|||
// Note: next < 0 also handles gotos handled by outer loops.
|
||||
// We set checkRet in that case to trigger this check.
|
||||
if r.checkFuncMisuse() {
|
||||
list = append(list, r.ifNext(syntax.Lss, 0, false, r.setStateAt(curLoopIndex, DONE), retStmt(r.useObj(r.false))))
|
||||
list = append(list, r.ifNext(syntax.Lss, 0, false, r.setStateAt(curLoopIndex, abi.RF_DONE), retStmt(r.useObj(r.false))))
|
||||
} else {
|
||||
list = append(list, r.ifNext(syntax.Lss, 0, false, retStmt(r.useObj(r.false))))
|
||||
}
|
||||
|
|
@ -1252,22 +1245,22 @@ func (r *rewriter) checks(loop *forLoop, pos syntax.Pos) []syntax.Stmt {
|
|||
depthStep := perLoopStep * (curLoop)
|
||||
|
||||
if r.checkFuncMisuse() {
|
||||
list = append(list, r.ifNext(syntax.Gtr, depthStep, false, r.callPanic(pos, r.stateConst(DONE))))
|
||||
list = append(list, r.ifNext(syntax.Gtr, depthStep, false, r.callPanic(pos, r.stateConst(abi.RF_DONE))))
|
||||
} else {
|
||||
list = append(list, r.ifNext(syntax.Gtr, depthStep, true))
|
||||
}
|
||||
|
||||
if r.checkFuncMisuse() {
|
||||
if loop.checkContinue {
|
||||
list = append(list, r.ifNext(syntax.Eql, depthStep-1, true, r.setStateAt(curLoopIndex, READY), retStmt(r.useObj(r.true))))
|
||||
list = append(list, r.ifNext(syntax.Eql, depthStep-1, true, r.setStateAt(curLoopIndex, abi.RF_READY), retStmt(r.useObj(r.true))))
|
||||
}
|
||||
|
||||
if loop.checkBreak {
|
||||
list = append(list, r.ifNext(syntax.Eql, depthStep, true, r.setStateAt(curLoopIndex, DONE), retStmt(r.useObj(r.false))))
|
||||
list = append(list, r.ifNext(syntax.Eql, depthStep, true, r.setStateAt(curLoopIndex, abi.RF_DONE), retStmt(r.useObj(r.false))))
|
||||
}
|
||||
|
||||
if loop.checkContinue || loop.checkBreak {
|
||||
list = append(list, r.ifNext(syntax.Gtr, 0, false, r.setStateAt(curLoopIndex, DONE), retStmt(r.useObj(r.false))))
|
||||
list = append(list, r.ifNext(syntax.Gtr, 0, false, r.setStateAt(curLoopIndex, abi.RF_DONE), retStmt(r.useObj(r.false))))
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -1327,12 +1320,12 @@ func setValueType(x syntax.Expr, typ syntax.Type) {
|
|||
|
||||
// assertReady returns the statement:
|
||||
//
|
||||
// if #stateK != READY { runtime.panicrangestate(#stateK) }
|
||||
// if #stateK != abi.RF_READY { runtime.panicrangestate(#stateK) }
|
||||
//
|
||||
// where #stateK is the state variable for loop.
|
||||
func (r *rewriter) assertReady(start syntax.Pos, loop *forLoop) syntax.Stmt {
|
||||
nif := &syntax.IfStmt{
|
||||
Cond: r.cond(syntax.Neq, r.useObj(loop.stateVar), r.stateConst(READY)),
|
||||
Cond: r.cond(syntax.Neq, r.useObj(loop.stateVar), r.stateConst(abi.RF_READY)),
|
||||
Then: &syntax.BlockStmt{
|
||||
List: []syntax.Stmt{r.callPanic(start, r.useObj(loop.stateVar))},
|
||||
},
|
||||
|
|
@ -1389,7 +1382,7 @@ func (r *rewriter) intConst(c int) *syntax.BasicLit {
|
|||
return lit
|
||||
}
|
||||
|
||||
func (r *rewriter) stateConst(s State) *syntax.BasicLit {
|
||||
func (r *rewriter) stateConst(s abi.RF_State) *syntax.BasicLit {
|
||||
return r.intConst(int(s))
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,18 @@
|
|||
// Copyright 2024 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package abi
|
||||
|
||||
type RF_State int
|
||||
|
||||
// These constants are shared between the compiler, which uses them for state functions
|
||||
// and panic indicators, and the runtime, which turns them into more meaningful strings
|
||||
// For best code generation, RF_DONE and RF_READY should be 0 and 1.
|
||||
const (
|
||||
RF_DONE = RF_State(iota) // body of loop has exited in a non-panic way
|
||||
RF_READY // body of loop has not exited yet, is not running -- this is not a panic index
|
||||
RF_PANIC // body of loop is either currently running, or has panicked
|
||||
RF_EXHAUSTED // iterator function return, i.e., sequence is "exhausted"
|
||||
RF_MISSING_PANIC = 4 // body of loop panicked but iterator function defer-recovered it away
|
||||
)
|
||||
|
|
@ -304,21 +304,14 @@ var rangeMissingPanicError = error(errorString("range function recovered a loop
|
|||
|
||||
//go:noinline
|
||||
func panicrangestate(state int) {
|
||||
const (
|
||||
// These duplicate magic numbers in cmd/compile/internal/rangefunc
|
||||
DONE = 0 // body of loop has exited in a non-panic way
|
||||
PANIC = 2 // body of loop is either currently running, or has panicked
|
||||
EXHAUSTED = 3 // iterator function return, i.e., sequence is "exhausted"
|
||||
MISSING_PANIC = 4 // body of loop panicked but iterator function defer-recovered it away
|
||||
)
|
||||
switch state {
|
||||
case DONE:
|
||||
switch abi.RF_State(state) {
|
||||
case abi.RF_DONE:
|
||||
panic(rangeDoneError)
|
||||
case PANIC:
|
||||
case abi.RF_PANIC:
|
||||
panic(rangePanicError)
|
||||
case EXHAUSTED:
|
||||
case abi.RF_EXHAUSTED:
|
||||
panic(rangeExhaustedError)
|
||||
case MISSING_PANIC:
|
||||
case abi.RF_MISSING_PANIC:
|
||||
panic(rangeMissingPanicError)
|
||||
}
|
||||
throw("unexpected state passed to panicrangestate")
|
||||
|
|
|
|||
Loading…
Reference in New Issue