Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 9 additions & 24 deletions src/hexer/eraiser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@ one pass that implements them.
stood for becomes `tmp[1]`.
- `let/var local = rcall(args)` retypes `local` to the success tuple and gets
that same check; every other use of `local` projects onto `local[1]`.
- `result = x` and `return x` build the tuple. `result` itself already IS the
tuple, so `return result` needs no rebuild — and must not get one, see
`trRet`.
- `result[0] = Success` is set once, at `result`'s declaration: every path
that changes the code half leaves the routine right away. So `result = x`,
like any other use of `result` (and of a retyped local, whose check has
passed), is simply `result[1] = x`. Rebuilding the whole tuple there would
nest `x` one level deep, which hides a `.passive` call from `cps`: it ends
a state only where a suspension point is the ROOT of the value.
- `return x` builds the tuple. `result` itself already IS the tuple, so
`return result` needs no rebuild — and must not get one, see `trRet`.
- `raise e` becomes `raise (e, result)`.

**Doing the whole job here is the point.** The control-flow half (the temps
Expand Down Expand Up @@ -727,24 +732,6 @@ proc trTry(c: var Context; dest: var TokenBuf; n: var Cursor) =
n = tryStart
skip n

proc trAsgn(c: var Context; dest: var TokenBuf; n: var Cursor) =
var nn = n.childCursor
if nn.kind == Symbol and ((nn.symId == c.resultSym and c.canRaise) or
c.tupleVars.contains(nn.symId)):
let isResultSym = nn.symId == c.resultSym
copyInto dest, n:
dest.addSubtree n # the destination, NOT projected: it IS the tuple
inc n
let typ = if isResultSym: c.retType else: getType(c.typeCache, n)
let maybeClose = produceSuccessTuple(c, dest, typ, n.info)
tr c, dest, n
if maybeClose:
dest.addParRi() # tuple constructor
else:
copyInto dest, n:
tr c, dest, n
tr c, dest, n

proc trBreak(c: var Context; dest: var TokenBuf; n: var Cursor) =
## Leaving a `block` or a loop runs the `finally` of every `try` between
## here and it — but not of any `try` further out, which we are still in.
Expand Down Expand Up @@ -848,8 +835,6 @@ proc tr(c: var Context; dest: var TokenBuf; n: var Cursor) =
trScope c, dest, n
of StmtsS:
trStmtList c, dest, n
of AsgnS:
trAsgn c, dest, n
of RetS:
trRet c, dest, n
of RaiseS:
Expand All @@ -864,7 +849,7 @@ proc tr(c: var Context; dest: var TokenBuf; n: var Cursor) =
trLoopOrBlock c, dest, n
of MacroS, TemplateS, TypeS:
takeTree dest, n
of CallS, CmdS, IteratorS, EmitS, IfS, WhenS,
of AsgnS, CallS, CmdS, IteratorS, EmitS, IfS, WhenS,
ContinueS, ForS, CaseS, YldS,
PragmasS, PragmaxS, InclS, ExclS, IncludeS, ImportS, ImportasS,
FromimportS, ImportexceptS, ExportS, ExportexceptS, CommentS,
Expand Down
53 changes: 53 additions & 0 deletions tests/nimony/cps/tpassiveraises_result.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# `result = passiveCall()` inside a raising coroutine.
#
# `cps` ends a state where it finds a suspension point at the ROOT of a
# statement. The eraiser used to rewrite `result = v` into
# `result = (Success, v)`, which pushed the passive call one level down: the
# state boundary then fell after the whole assignment, and the routine either
# returned 0 or did not compile at all (`cps.nim: state != -1`).

import std / syncio

proc step() {.passive.} = discard

proc get(x: int): int {.passive.} =
step()
result = x * 10

proc viaResult(x: int): int {.passive, raises.} =
if x < 0: raise SyntaxError
result = get(x)

proc tail(x: int): int {.passive, raises.} =
if x < 0: raise SyntaxError
get(x)

proc viaReturn(x: int): int {.passive, raises.} =
if x < 0: raise SyntaxError
return get(x)

proc reassign(x: int): int {.passive, raises.} =
var y = viaResult(x) # `y` holds the success tuple
y = get(y) # a passive, non-raising call into it
result = y

proc raiseAfter(x: int): int {.passive, raises.} =
result = get(x)
if result > 30: raise SyntaxError

proc main() {.passive.} =
for i in [3, -1]:
try:
echo viaResult(i)
echo tail(i)
echo viaReturn(i)
echo reassign(i)
echo raiseAfter(i)
except:
echo "caught ", i
try:
echo raiseAfter(5)
except:
echo "caught 5"

main()
7 changes: 7 additions & 0 deletions tests/nimony/cps/tpassiveraises_result.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
30
30
30
300
30
caught -1
caught 5
Loading