roc
roc copied to clipboard
`roc check` panics on incorrect opaque destructure
Needs minimization, but the crash here is because the next function is destructuring its first argument with @Task when it should be @SimTask instead.
roc check on this hello world file panics with:
'assertion failed: is_recursion_var(env.subs, *recursion_var)', /Users/rtfeldman/code/roc/crates/compiler/unify/src/unify.rs:2609:13
app "helloWorld"
packages { pf: "cli/cli-platform/main.roc" }
imports [pf.Stdout, pf.Program.{ Program }]
provides [main] to pf
main = Program.noArgs mainTask
mainTask =
Stdout.line "Hello, World!"
|> Program.exit 0
Task ok err fx := [
Always (Result ok err),
Run (Effect (Task ok err fx)),
]
Effect a : [
FileWriteUtf8 Str Str (Result {} [NotFound, Malformed] -> a),
FileReadUtf8 Str (Result Str [NotFound, Malformed] -> a),
StdoutLine Str a,
StdinLine (Str -> a),
]
# Task API
succeed : ok -> Task ok * *
succeed = \ok -> @Task (Always (Ok ok))
fail : err -> Task * err *
fail = \err -> @Task (Always (Err err))
await : Task a err fx, (a -> Task b err fx) -> Task b err fx
await = \@Task task, aToTaskB ->
when task is
Always (Ok a) -> aToTaskB a
Always (Err err) -> @Task (Always (Err err))
Run effect ->
effect
|> mapEffect \effectTask -> await effectTask aToTaskB
|> Run
|> @Task
# Specific tasks (would be exposed by various different modules as normal)
stdoutLine : Str -> Task {} * [Write [Stdout]*]*
stdoutLine = \line ->
StdoutLine line (@Task (Always (Ok {})))
|> Run
|> @Task
stdinLine : Task Str * [Read [Stdin]*]*
stdinLine =
StdinLine \line -> @Task (Always (Ok line))
|> Run
|> @Task
fileWriteUtf8 : Str, Str -> Task {} [FileWriteErr [NotFound, Malformed]]* [Write [File]*]*
fileWriteUtf8 = \path, contents ->
FileWriteUtf8 path contents \result ->
@Task (Always (Result.mapErr result FileWriteErr))
|> Run
|> @Task
fileReadUtf8 : Str -> Task Str [FileReadErr [NotFound, Malformed]]* [Read [File]*]*
fileReadUtf8 = \path ->
FileReadUtf8 path \result ->
@Task (Always (Result.mapErr result FileReadErr))
|> Run
|> @Task
mapEffect : Effect a, (a -> b) -> Effect b
mapEffect = \effect, aToB ->
when effect is
FileWriteUtf8 path str resultToA -> FileWriteUtf8 path str \result ->
aToB (resultToA result)
FileReadUtf8 path resultToA -> FileReadUtf8 path \result ->
aToB (resultToA result)
StdoutLine line a -> StdoutLine line (aToB a)
StdinLine strToA -> StdinLine \str -> aToB (strToA str)
# Simulation
SimTask ok err fx := [
Always (Result ok err),
Run (SimEffect (SimTask ok err fx)),
]
SimEffect a : [
FileWriteUtf8 (Str, Str -> Result {} [NotFound, Malformed]) a,
FileReadUtf8 (Str -> Result Str [NotFound, Malformed]) a,
StdoutLine (Str -> a),
StdinLine Str a,
]
andThen : SimTask a err fx, (a -> SimTask b err fx) -> SimTask b err fx
andThen = \@Task task, aToTaskB ->
when task is
Always (Ok a) -> aToTaskB a
Always (Err err) -> @SimTask (Always (Err err))
Run effect ->
effect
|> mapSimEffect \effectTask -> andThen effectTask aToTaskB
|> Run
|> @SimTask
mapSimEffect : SimEffect a, (a -> b) -> SimEffect b
mapSimEffect = \effect, aToB ->
when effect is
FileWriteUtf8 fn a -> FileWriteUtf8 fn (aToB a)
FileReadUtf8 fn a -> FileReadUtf8 fn (aToB a)
StdoutLine strToA -> StdoutLine \str -> aToB (strToA str)
StdinLine line a -> StdinLine line (aToB a)
simulate : SimTask a err fx, Task a err fx -> Result {} Str
simulate = \@SimTask sim, @Task task ->
when T sim task is
T (Always simResult) (Always actualResult) ->
if simResult == actualResult then
Ok {}
else
Err "Always results were different"
T (Run simEffect) (Run actualEffect) ->
when T simEffect actualEffect is
T (StdoutLine lineToA) (StdoutLine line a) ->
simulate (lineToA line) a
T (StdinLine line a) (StdinLine lineToA) ->
simulate a (lineToA line)
T (FileReadUtf8 pathToResult a) (FileReadUtf8 path resultToA) ->
simulate a (resultToA (pathToResult path))
T (FileWriteUtf8 pathAndContentsToResult a) (FileWriteUtf8 path contents resultToA) ->
simulate a (resultToA (pathAndContentsToResult path contents))
T _ _ ->
Err "The simulation expected [TODO] to run next but the actual task ran [TODO]"
T (Always (Ok _)) (Run _) ->
Err "Simulation expected (Task.succeed [TODO]) but the actual task was a [TODO]"
T (Always (Err _)) (Run _) ->
Err "Simulation expected (Task.fail [TODO]) but the actual task was a [TODO]"
T (Run _) (Always (Ok _)) ->
Err "Simulation expected a [TODO] but the actual task was a (Task.succeed [TODO])"
T (Run _) (Always (Err _)) ->
Err "Simulation expected a [TODO] but the actual task was a (Task.fail [TODO])"