Closed perimosocordiae closed 2 years ago
Reproducer:
io ::= import "io.ic"
State ::= struct {
(copy) ::= (self: *State) -> State {
io.Print("Copying State now\n")
return State.{}
}
(destroy) ::= (self: *State) -> () {
io.Print("Destroying State now\n")
}
}
Demo ::= scope(State) {
enter ::= jump [state: *State] () {
io.Print("in enter\n")
goto ok()
}
ok ::= block {
before ::= () -> () {
io.Print("in ok.before\n")
}
after ::= jump [state: *State] () {
io.Print("in ok.after\n")
goto done()
}
}
exit ::= () -> () {
io.Print("in exit\n")
}
}
io.Print("before scope\n")
Demo () ok {
io.Print("during scope\n")
}
io.Print("after scope\n")
Output:
before scope
in enter
in ok.before
during scope
in ok.after
after scope
So it turns out we're not destroying the State struct, but also we're never calling the exit
function. I did a little code spelunking and found this suspicious pair of TODOs:
https://github.com/asoffer/Icarus/blob/2cd5779aa733e5153801422685505085cd8de7bc/compiler/emit/yield_stmt.cc#L39-L40
Yeah there's still a fair bit of design work needed here, both for the spec (interaction with labeled yields) and the code emission (do we prefer branching or code duplication)?
At least some of this can be fixed readily. The non-labeled case shouldn't be hard for local yields. Returning out nested blocks isnt bad either.
This is obsoleted by #81
At least, as far as I can tell. I first noticed this in gh-60.
I'll update with a reproducer soon.