-
Notifications
You must be signed in to change notification settings - Fork 302
PatternMatchFailure on nested case of Requests continuations #6183
Description
Describe and demonstrate the bug
I'm seeing PatternMatchFailures when using nested handle ... with clauses (I want to replace certain calls to optimise performance). I can't pinpoint the issue. Here is a very simple example:
handler : { Stream () } r -> r
handler prog =
go : Request { Stream () } r -> r
go = cases
{ emit _ -> cont } ->
handle cont () with cases
{ r } -> r
{ emit _ -> cont } ->
handle cont () with go
other -> todo other
handle prog with go
If I replace the inner cases with a catch-all like so, it stops compiling (PatternMatchFailure):
handler : { Stream () } r -> r
handler prog =
go : Request { Stream () } r -> r
go = cases
{ emit _ -> cont } ->
handle cont () with cases
-- { r } -> r
{ emit _ -> cont } ->
handle cont () with go
other -> todo other
other -> todo other
handle prog with go
This (somewhat nonsensical handler) compiles fine
handleRand2 : {Random} r -> r
handleRand2 prog =
step1 : Request {Random } r -> r
step1 = cases
{nat! -> cont } ->
handle cont 0 with step2
other -> todo "other0"
step2 : Request {Random} r -> r
step2 = cases
{ nat! -> cont } ->
handle cont 1 with step2
other -> todo "other1"
handle prog with step1
But again, inlining step2 directly results in a PatternMatchFailure:
handleRand : {Random} r -> r
handleRand prog =
go : Request {Random } r -> r
go = cases
{ r } -> r
{nat! -> cont } ->
handle cont 0 with cases
{ r } -> r
{ nat! -> cont } ->
handle cont 1 with go
other -> todo "other1"
other -> todo "other0"
handle prog with go
I can't tell for sure, but it looks like if you have a 'catch-all' inside of a nested case that handles a Request, it will throw a PatternMatchFailure. The above examples can again be fixed by listing all the cases:
handleRand : {Random} r -> r
handleRand prog =
go : Request {Random } r -> r
go = cases
{ r } -> r
{nat! -> cont } ->
handle cont 0 with cases
{ r } -> r
{ nat! -> cont } ->
handle cont 1 with go
{ bytes n -> cont } ->
handle cont Bytes.empty with go
{ split! -> cont } ->
handle cont (todo "wtf") with go
other -> todo "other0"
handle prog with go
Environment (please complete the following information):
ucm --version1.1.0- OS/Architecture: ubuntu linux
Additional context
I'm trying to optimise certain call trees, and I would like to avoid exhaustively listing all the cases (which can be quite large in my example). This is also important for working with fixed points, as you need the catch-all to capture the remaining requests to pass on.