mirror of
https://github.com/roc-lang/roc.git
synced 2025-07-23 22:45:14 +00:00
Merge pull request #7005 from smores56/deprecate-backpassing
Deprecate backpassing to prepare for eventual removal
This commit is contained in:
commit
7c7485bb04
37 changed files with 818 additions and 556 deletions
|
@ -1,4 +1,4 @@
|
|||
interface Base64.Decode exposes [fromBytes] imports []
|
||||
module [fromBytes]
|
||||
|
||||
import Bytes.Decode exposing [ByteDecoder, DecodeProblem]
|
||||
|
||||
|
@ -12,8 +12,7 @@ decodeBase64 = \width -> Bytes.Decode.loop loopHelp { remaining: width, string:
|
|||
loopHelp : { remaining : U64, string : Str } -> ByteDecoder (Bytes.Decode.Step { remaining : U64, string : Str } Str)
|
||||
loopHelp = \{ remaining, string } ->
|
||||
if remaining >= 3 then
|
||||
x, y, z <- Bytes.Decode.map3 Bytes.Decode.u8 Bytes.Decode.u8 Bytes.Decode.u8
|
||||
|
||||
Bytes.Decode.map3 Bytes.Decode.u8 Bytes.Decode.u8 Bytes.Decode.u8 \x, y, z ->
|
||||
a : U32
|
||||
a = Num.intCast x
|
||||
b : U32
|
||||
|
@ -29,7 +28,7 @@ loopHelp = \{ remaining, string } ->
|
|||
else if remaining == 0 then
|
||||
Bytes.Decode.succeed (Done string)
|
||||
else if remaining == 2 then
|
||||
x, y <- Bytes.Decode.map2 Bytes.Decode.u8 Bytes.Decode.u8
|
||||
Bytes.Decode.map2 Bytes.Decode.u8 Bytes.Decode.u8 \x, y ->
|
||||
|
||||
a : U32
|
||||
a = Num.intCast x
|
||||
|
@ -40,7 +39,7 @@ loopHelp = \{ remaining, string } ->
|
|||
Done (Str.concat string (bitsToChars combined 1))
|
||||
else
|
||||
# remaining = 1
|
||||
x <- Bytes.Decode.map Bytes.Decode.u8
|
||||
Bytes.Decode.map Bytes.Decode.u8 \x ->
|
||||
|
||||
a : U32
|
||||
a = Num.intCast x
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
app "cfold"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports [pf.Task]
|
||||
provides [main] to pf
|
||||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.Task
|
||||
|
||||
# adapted from https://github.com/koka-lang/koka/blob/master/test/bench/haskell/cfold.hs
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
inputResult <- Task.attempt Task.getInt
|
||||
inputResult = Task.getInt |> Task.result!
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
|
|
|
@ -1,14 +1,13 @@
|
|||
app "deriv"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports [pf.Task]
|
||||
provides [main] to pf
|
||||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.Task
|
||||
|
||||
# based on: https://github.com/koka-lang/koka/blob/master/test/bench/haskell/deriv.hs
|
||||
IO a : Task.Task a []
|
||||
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
inputResult <- Task.attempt Task.getInt
|
||||
inputResult = Task.getInt |> Task.result!
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
|
@ -25,10 +24,11 @@ main =
|
|||
Task.putLine "Error: Failed to get Integer from stdin."
|
||||
|
||||
nestHelp : I64, (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
||||
nestHelp = \s, f, m, x -> when m is
|
||||
nestHelp = \s, f, m, x ->
|
||||
when m is
|
||||
0 -> Task.succeed x
|
||||
_ ->
|
||||
w <- Task.after (f (s - m) x)
|
||||
Task.after (f (s - m) x) \w ->
|
||||
nestHelp s f (m - 1) w
|
||||
|
||||
nest : (I64, Expr -> IO Expr), I64, Expr -> IO Expr
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
app "nqueens"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports [pf.Task]
|
||||
provides [main] to pf
|
||||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.Task
|
||||
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
inputResult <- Task.attempt Task.getInt
|
||||
inputResult = Task.getInt |> Task.result!
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
|
|
|
@ -1,6 +1,20 @@
|
|||
interface Task
|
||||
exposes [Task, succeed, fail, after, map, putLine, putInt, getInt, forever, loop, attempt]
|
||||
imports [pf.Effect]
|
||||
module [
|
||||
Task,
|
||||
await,
|
||||
succeed,
|
||||
fail,
|
||||
after,
|
||||
map,
|
||||
result,
|
||||
putLine,
|
||||
putInt,
|
||||
getInt,
|
||||
forever,
|
||||
loop,
|
||||
attempt,
|
||||
]
|
||||
|
||||
import pf.Effect
|
||||
|
||||
Task ok err : Effect.Effect (Result ok err)
|
||||
|
||||
|
@ -24,7 +38,7 @@ loop = \state, step ->
|
|||
\res ->
|
||||
when res is
|
||||
Ok (Step newState) -> Step newState
|
||||
Ok (Done result) -> Done (Ok result)
|
||||
Ok (Done res2) -> Done (Ok res2)
|
||||
Err e -> Done (Err e)
|
||||
|
||||
Effect.loop state looper
|
||||
|
@ -41,8 +55,17 @@ after : Task a err, (a -> Task b err) -> Task b err
|
|||
after = \effect, transform ->
|
||||
Effect.after
|
||||
effect
|
||||
\result ->
|
||||
when result is
|
||||
\res ->
|
||||
when res is
|
||||
Ok a -> transform a
|
||||
Err err -> Task.fail err
|
||||
|
||||
await : Task a err, (a -> Task b err) -> Task b err
|
||||
await = \effect, transform ->
|
||||
Effect.after
|
||||
effect
|
||||
\res ->
|
||||
when res is
|
||||
Ok a -> transform a
|
||||
Err err -> Task.fail err
|
||||
|
||||
|
@ -50,8 +73,8 @@ attempt : Task a b, (Result a b -> Task c d) -> Task c d
|
|||
attempt = \task, transform ->
|
||||
Effect.after
|
||||
task
|
||||
\result ->
|
||||
when result is
|
||||
\res ->
|
||||
when res is
|
||||
Ok ok -> transform (Ok ok)
|
||||
Err err -> transform (Err err)
|
||||
|
||||
|
@ -59,11 +82,17 @@ map : Task a err, (a -> b) -> Task b err
|
|||
map = \effect, transform ->
|
||||
Effect.map
|
||||
effect
|
||||
\result ->
|
||||
when result is
|
||||
\res ->
|
||||
when res is
|
||||
Ok a -> Ok (transform a)
|
||||
Err err -> Err err
|
||||
|
||||
result : Task ok err -> Task (Result ok err) *
|
||||
result = \effect ->
|
||||
Effect.after
|
||||
effect
|
||||
\res -> Task.succeed res
|
||||
|
||||
putLine : Str -> Task {} *
|
||||
putLine = \line -> Effect.map (Effect.putLine line) (\_ -> Ok {})
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
app "quicksortapp"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports [pf.Task, Quicksort]
|
||||
provides [main] to pf
|
||||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.Task
|
||||
import Quicksort
|
||||
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
inputResult <- Task.attempt Task.getInt
|
||||
inputResult = Task.getInt |> Task.result!
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
app "rbtree-ck"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports [pf.Task]
|
||||
provides [main] to pf
|
||||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.Task
|
||||
|
||||
Color : [Red, Black]
|
||||
|
||||
|
@ -40,7 +39,7 @@ fold = \f, tree, b ->
|
|||
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
inputResult <- Task.attempt Task.getInt
|
||||
inputResult = Task.getInt |> Task.result!
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
app "rbtree-del"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports [pf.Task]
|
||||
provides [main] to pf
|
||||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.Task
|
||||
|
||||
Color : [Red, Black]
|
||||
|
||||
|
@ -13,7 +12,7 @@ ConsList a : [Nil, Cons a (ConsList a)]
|
|||
|
||||
main : Task.Task {} []
|
||||
main =
|
||||
inputResult <- Task.attempt Task.getInt
|
||||
inputResult = Task.getInt |> Task.result!
|
||||
|
||||
when inputResult is
|
||||
Ok n ->
|
||||
|
|
|
@ -2,18 +2,18 @@ app [main] { pf: platform "https://github.com/roc-lang/basic-cli/releases/downlo
|
|||
|
||||
import pf.Stdin
|
||||
import pf.Stdout
|
||||
import pf.Task exposing [await, loop]
|
||||
import pf.Task exposing [Task, loop]
|
||||
|
||||
main =
|
||||
_ <- await (Stdout.line "\nLet's count down from 3 together - all you have to do is press <ENTER>.")
|
||||
_ <- await Stdin.line
|
||||
Stdout.line! "\nLet's count down from 3 together - all you have to do is press <ENTER>."
|
||||
_ = Stdin.line!
|
||||
loop 3 tick
|
||||
|
||||
tick = \n ->
|
||||
if n == 0 then
|
||||
_ <- await (Stdout.line "🎉 SURPRISE! Happy Birthday! 🎂")
|
||||
Stdout.line! "🎉 SURPRISE! Happy Birthday! 🎂"
|
||||
Task.ok (Done {})
|
||||
else
|
||||
_ <- await (n |> Num.toStr |> \s -> "$(s)..." |> Stdout.line)
|
||||
_ <- await Stdin.line
|
||||
Stdout.line! (n |> Num.toStr |> \s -> "$(s)...")
|
||||
_ = Stdin.line!
|
||||
Task.ok (Step (n - 1))
|
||||
|
|
|
@ -5,7 +5,7 @@ import pf.Stdout
|
|||
import pf.Task exposing [Task]
|
||||
|
||||
main =
|
||||
_ <- Task.await (Stdout.line "🗣 Shout into this cave and hear the echo! 👂👂👂")
|
||||
Stdout.line! "🗣 Shout into this cave and hear the echo! 👂👂👂"
|
||||
|
||||
Task.loop {} tick
|
||||
|
||||
|
|
|
@ -55,23 +55,23 @@ numParam = \{ name } ->
|
|||
{ params: [param], parser }
|
||||
|
||||
cliMap : ArgParser a, (a -> b) -> ArgParser b
|
||||
cliMap = \{ params, parser }, mapper -> {
|
||||
params,
|
||||
parser: \args ->
|
||||
(data, afterData) <- parser args
|
||||
|> Result.try
|
||||
cliMap = \{ params, parser }, mapper ->
|
||||
mappedParser = \args ->
|
||||
(data, afterData) = parser? args
|
||||
|
||||
Ok (mapper data, afterData),
|
||||
Ok (mapper data, afterData)
|
||||
|
||||
{
|
||||
params,
|
||||
parser: mappedParser,
|
||||
}
|
||||
|
||||
cliBuild : ArgParser a, ArgParser b, (a, b -> c) -> ArgParser c
|
||||
cliBuild = \firstWeaver, secondWeaver, combine ->
|
||||
allParams = List.concat firstWeaver.params secondWeaver.params
|
||||
combinedParser = \args ->
|
||||
(firstValue, afterFirst) <- firstWeaver.parser args
|
||||
|> Result.try
|
||||
(secondValue, afterSecond) <- secondWeaver.parser afterFirst
|
||||
|> Result.try
|
||||
(firstValue, afterFirst) = firstWeaver.parser? args
|
||||
(secondValue, afterSecond) = secondWeaver.parser? afterFirst
|
||||
|
||||
Ok (combine firstValue secondValue, afterSecond)
|
||||
|
||||
|
|
|
@ -26,8 +26,7 @@ Letter : [A, B, C, Other]
|
|||
|
||||
letterParser : Parser (List U8) Letter
|
||||
letterParser =
|
||||
input <- buildPrimitiveParser
|
||||
|
||||
buildPrimitiveParser \input ->
|
||||
valResult =
|
||||
when input is
|
||||
[] -> Err (ParsingFailure "Nothing to parse")
|
||||
|
|
|
@ -23,6 +23,7 @@ mod cli_run {
|
|||
use serial_test::serial;
|
||||
use std::iter;
|
||||
use std::path::Path;
|
||||
use std::process::ExitStatus;
|
||||
|
||||
#[cfg(all(unix, not(target_os = "macos")))]
|
||||
const ALLOW_VALGRIND: bool = true;
|
||||
|
@ -106,6 +107,11 @@ mod cli_run {
|
|||
assert_multiline_str_eq!(err.as_str(), expected);
|
||||
}
|
||||
|
||||
fn assert_valid_roc_check_status(status: ExitStatus) {
|
||||
// 0 means no errors or warnings, 2 means just warnings
|
||||
assert!(status.code().is_some_and(|code| code == 0 || code == 2))
|
||||
}
|
||||
|
||||
fn check_format_check_as_expected(file: &Path, expects_success_exit_code: bool) {
|
||||
let out = run_roc([CMD_FORMAT, file.to_str().unwrap(), CHECK_FLAG], &[], &[]);
|
||||
|
||||
|
@ -803,7 +809,7 @@ mod cli_run {
|
|||
fn check_virtual_dom_server() {
|
||||
let path = file_path_from_root("examples/virtual-dom-wip", "example-server.roc");
|
||||
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
|
||||
assert!(out.status.success());
|
||||
assert_valid_roc_check_status(out.status);
|
||||
}
|
||||
|
||||
// TODO: write a new test once mono bugs are resolved in investigation
|
||||
|
@ -812,7 +818,7 @@ mod cli_run {
|
|||
fn check_virtual_dom_client() {
|
||||
let path = file_path_from_root("examples/virtual-dom-wip", "example-client.roc");
|
||||
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
|
||||
assert!(out.status.success());
|
||||
assert_valid_roc_check_status(out.status);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -821,7 +827,7 @@ mod cli_run {
|
|||
fn cli_countdown_check() {
|
||||
let path = file_path_from_root("crates/cli/tests/cli", "countdown.roc");
|
||||
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
|
||||
assert!(out.status.success());
|
||||
assert_valid_roc_check_status(out.status);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -830,7 +836,7 @@ mod cli_run {
|
|||
fn cli_echo_check() {
|
||||
let path = file_path_from_root("crates/cli/tests/cli", "echo.roc");
|
||||
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
|
||||
assert!(out.status.success());
|
||||
assert_valid_roc_check_status(out.status);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -839,7 +845,7 @@ mod cli_run {
|
|||
fn cli_file_check() {
|
||||
let path = file_path_from_root("crates/cli/tests/cli", "fileBROKEN.roc");
|
||||
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
|
||||
assert!(out.status.success());
|
||||
assert_valid_roc_check_status(out.status);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -848,7 +854,8 @@ mod cli_run {
|
|||
fn cli_form_check() {
|
||||
let path = file_path_from_root("crates/cli/tests/cli", "form.roc");
|
||||
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
|
||||
assert!(out.status.success());
|
||||
dbg!(out.stdout, out.stderr);
|
||||
assert_valid_roc_check_status(out.status);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -857,7 +864,7 @@ mod cli_run {
|
|||
fn cli_http_get_check() {
|
||||
let path = file_path_from_root("crates/cli/tests/cli", "http-get.roc");
|
||||
let out = run_roc([CMD_CHECK, path.to_str().unwrap()], &[], &[]);
|
||||
assert!(out.status.success());
|
||||
assert_valid_roc_check_status(out.status);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1482,9 +1489,9 @@ mod cli_run {
|
|||
|
||||
Something is off with the body of the main definition:
|
||||
|
||||
6│ main : Str -> Task {} []
|
||||
7│ main = /_ ->
|
||||
8│ "this is a string, not a Task {} [] function like the platform expects."
|
||||
5│ main : Str -> Task {} []
|
||||
6│ main = /_ ->
|
||||
7│ "this is a string, not a Task {} [] function like the platform expects."
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The body is a string of type:
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
app "type-error"
|
||||
packages { pf: "../../../../examples/cli/false-interpreter/platform/main.roc" }
|
||||
imports [pf.Task.{ Task }]
|
||||
provides [main] to pf
|
||||
app [main] { pf: platform "../../../../examples/cli/false-interpreter/platform/main.roc" }
|
||||
|
||||
import pf.Task exposing [Task]
|
||||
|
||||
main : Str -> Task {} []
|
||||
main = \_ ->
|
||||
|
|
|
@ -129,7 +129,7 @@ hashDict = \hasher, dict -> Hash.hashUnordered hasher (toList dict) List.walk
|
|||
|
||||
toInspectorDict : Dict k v -> Inspector f where k implements Inspect & Hash & Eq, v implements Inspect, f implements InspectFormatter
|
||||
toInspectorDict = \dict ->
|
||||
fmt <- Inspect.custom
|
||||
Inspect.custom \fmt ->
|
||||
Inspect.apply (Inspect.dict dict walk Inspect.toInspector Inspect.toInspector) fmt
|
||||
|
||||
## Return an empty dictionary.
|
||||
|
@ -894,7 +894,7 @@ calcNumBuckets = \shifts ->
|
|||
maxBucketCount
|
||||
|
||||
fillBucketsFromData = \buckets0, data, shifts ->
|
||||
buckets1, (key, _), dataIndex <- List.walkWithIndex data buckets0
|
||||
List.walkWithIndex data buckets0 \buckets1, (key, _), dataIndex ->
|
||||
(bucketIndex, distAndFingerprint) = nextWhileLess buckets1 key shifts
|
||||
placeAndShiftUp buckets1 { distAndFingerprint, dataIndex: Num.toU32 dataIndex } bucketIndex
|
||||
|
||||
|
@ -1213,14 +1213,14 @@ expect
|
|||
]
|
||||
|
||||
dict =
|
||||
acc, k <- List.walk badKeys (Dict.empty {})
|
||||
List.walk badKeys (Dict.empty {}) \acc, k ->
|
||||
Dict.update acc k \val ->
|
||||
when val is
|
||||
Present p -> Present (p |> Num.addWrap 1)
|
||||
Missing -> Present 0
|
||||
|
||||
allInsertedCorrectly =
|
||||
acc, k <- List.walk badKeys Bool.true
|
||||
List.walk badKeys Bool.true \acc, k ->
|
||||
acc && Dict.contains dict k
|
||||
|
||||
allInsertedCorrectly
|
||||
|
|
|
@ -138,10 +138,10 @@ dbgInit = \{} -> @DbgFormatter { data: "" }
|
|||
|
||||
dbgList : list, ElemWalker (DbgFormatter, Bool) list elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbgList = \content, walkFn, toDbgInspector ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "["
|
||||
|> \f1 ->
|
||||
(f2, prependSep), elem <- walkFn content (f1, Bool.false)
|
||||
walkFn content (f1, Bool.false) \(f2, prependSep), elem ->
|
||||
f3 =
|
||||
if prependSep then
|
||||
dbgWrite f2 ", "
|
||||
|
@ -157,10 +157,10 @@ dbgList = \content, walkFn, toDbgInspector ->
|
|||
|
||||
dbgSet : set, ElemWalker (DbgFormatter, Bool) set elem, (elem -> Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbgSet = \content, walkFn, toDbgInspector ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "{"
|
||||
|> \f1 ->
|
||||
(f2, prependSep), elem <- walkFn content (f1, Bool.false)
|
||||
walkFn content (f1, Bool.false) \(f2, prependSep), elem ->
|
||||
f3 =
|
||||
if prependSep then
|
||||
dbgWrite f2 ", "
|
||||
|
@ -176,10 +176,10 @@ dbgSet = \content, walkFn, toDbgInspector ->
|
|||
|
||||
dbgDict : dict, KeyValWalker (DbgFormatter, Bool) dict key value, (key -> Inspector DbgFormatter), (value -> Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbgDict = \d, walkFn, keyToInspector, valueToInspector ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "{"
|
||||
|> \f1 ->
|
||||
(f2, prependSep), key, value <- walkFn d (f1, Bool.false)
|
||||
walkFn d (f1, Bool.false) \(f2, prependSep), key, value ->
|
||||
f3 =
|
||||
if prependSep then
|
||||
dbgWrite f2 ", "
|
||||
|
@ -196,24 +196,24 @@ dbgDict = \d, walkFn, keyToInspector, valueToInspector ->
|
|||
dbgTag : Str, List (Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbgTag = \name, fields ->
|
||||
if List.isEmpty fields then
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 name
|
||||
else
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "("
|
||||
|> dbgWrite name
|
||||
|> \f1 ->
|
||||
f2, inspector <- List.walk fields f1
|
||||
List.walk fields f1 \f2, inspector ->
|
||||
dbgWrite f2 " "
|
||||
|> \x -> apply inspector x
|
||||
|> dbgWrite ")"
|
||||
|
||||
dbgTuple : List (Inspector DbgFormatter) -> Inspector DbgFormatter
|
||||
dbgTuple = \fields ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "("
|
||||
|> \f1 ->
|
||||
(f2, prependSep), inspector <- List.walk fields (f1, Bool.false)
|
||||
List.walk fields (f1, Bool.false) \(f2, prependSep), inspector ->
|
||||
f3 =
|
||||
if prependSep then
|
||||
dbgWrite f2 ", "
|
||||
|
@ -227,10 +227,10 @@ dbgTuple = \fields ->
|
|||
|
||||
dbgRecord : List { key : Str, value : Inspector DbgFormatter } -> Inspector DbgFormatter
|
||||
dbgRecord = \fields ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "{"
|
||||
|> \f1 ->
|
||||
(f2, prependSep), { key, value } <- List.walk fields (f1, Bool.false)
|
||||
List.walk fields (f1, Bool.false) \(f2, prependSep), { key, value } ->
|
||||
f3 =
|
||||
if prependSep then
|
||||
dbgWrite f2 ", "
|
||||
|
@ -247,15 +247,15 @@ dbgRecord = \fields ->
|
|||
dbgBool : Bool -> Inspector DbgFormatter
|
||||
dbgBool = \b ->
|
||||
if b then
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "Bool.true"
|
||||
else
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "Bool.false"
|
||||
|
||||
dbgStr : Str -> Inspector DbgFormatter
|
||||
dbgStr = \s ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
f0
|
||||
|> dbgWrite "\""
|
||||
|> dbgWrite s # TODO: Should we be escaping strings for dbg/logging?
|
||||
|
@ -263,77 +263,77 @@ dbgStr = \s ->
|
|||
|
||||
dbgOpaque : * -> Inspector DbgFormatter
|
||||
dbgOpaque = \_ ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "<opaque>"
|
||||
|
||||
dbgFunction : * -> Inspector DbgFormatter
|
||||
dbgFunction = \_ ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 "<function>"
|
||||
|
||||
dbgU8 : U8 -> Inspector DbgFormatter
|
||||
dbgU8 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgI8 : I8 -> Inspector DbgFormatter
|
||||
dbgI8 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgU16 : U16 -> Inspector DbgFormatter
|
||||
dbgU16 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgI16 : I16 -> Inspector DbgFormatter
|
||||
dbgI16 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgU32 : U32 -> Inspector DbgFormatter
|
||||
dbgU32 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgI32 : I32 -> Inspector DbgFormatter
|
||||
dbgI32 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgU64 : U64 -> Inspector DbgFormatter
|
||||
dbgU64 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgI64 : I64 -> Inspector DbgFormatter
|
||||
dbgI64 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgU128 : U128 -> Inspector DbgFormatter
|
||||
dbgU128 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgI128 : I128 -> Inspector DbgFormatter
|
||||
dbgI128 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgF32 : F32 -> Inspector DbgFormatter
|
||||
dbgF32 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgF64 : F64 -> Inspector DbgFormatter
|
||||
dbgF64 = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgDec : Dec -> Inspector DbgFormatter
|
||||
dbgDec = \num ->
|
||||
f0 <- custom
|
||||
custom \f0 ->
|
||||
dbgWrite f0 (num |> Num.toStr)
|
||||
|
||||
dbgWrite : DbgFormatter, Str -> DbgFormatter
|
||||
|
|
|
@ -62,7 +62,7 @@ hashSet = \hasher, @Set inner -> Hash.hash hasher inner
|
|||
|
||||
toInspectorSet : Set k -> Inspector f where k implements Inspect & Hash & Eq, f implements InspectFormatter
|
||||
toInspectorSet = \set ->
|
||||
fmt <- Inspect.custom
|
||||
Inspect.custom \fmt ->
|
||||
Inspect.apply (Inspect.set set walk Inspect.toInspector) fmt
|
||||
|
||||
## Creates a new empty `Set`.
|
||||
|
|
|
@ -12,6 +12,7 @@ use roc_parse::ast::{
|
|||
AssignedField, Collection, ModuleImportParams, OldRecordBuilderField, Pattern, StrLiteral,
|
||||
StrSegment, TypeAnnotation, ValueDef, WhenBranch,
|
||||
};
|
||||
use roc_problem::can::Problem;
|
||||
use roc_region::all::{LineInfo, Loc, Region};
|
||||
|
||||
// BinOp precedence logic adapted from Gluon by Markus Westerlind
|
||||
|
@ -74,13 +75,14 @@ fn desugar_value_def<'a>(
|
|||
src: &'a str,
|
||||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) -> ValueDef<'a> {
|
||||
use ValueDef::*;
|
||||
|
||||
match def {
|
||||
Body(loc_pattern, loc_expr) => Body(
|
||||
desugar_loc_pattern(arena, loc_pattern, src, line_info, module_path),
|
||||
desugar_expr(arena, loc_expr, src, line_info, module_path),
|
||||
desugar_loc_pattern(arena, loc_pattern, src, line_info, module_path, problems),
|
||||
desugar_expr(arena, loc_expr, src, line_info, module_path, problems),
|
||||
),
|
||||
ann @ Annotation(_, _) => *ann,
|
||||
AnnotatedBody {
|
||||
|
@ -93,16 +95,29 @@ fn desugar_value_def<'a>(
|
|||
ann_pattern,
|
||||
ann_type,
|
||||
lines_between,
|
||||
body_pattern: desugar_loc_pattern(arena, body_pattern, src, line_info, module_path),
|
||||
body_expr: desugar_expr(arena, body_expr, src, line_info, module_path),
|
||||
body_pattern: desugar_loc_pattern(
|
||||
arena,
|
||||
body_pattern,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
),
|
||||
body_expr: desugar_expr(arena, body_expr, src, line_info, module_path, problems),
|
||||
},
|
||||
|
||||
Dbg {
|
||||
condition,
|
||||
preceding_comment,
|
||||
} => {
|
||||
let desugared_condition =
|
||||
&*arena.alloc(desugar_expr(arena, condition, src, line_info, module_path));
|
||||
let desugared_condition = &*arena.alloc(desugar_expr(
|
||||
arena,
|
||||
condition,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
Dbg {
|
||||
condition: desugared_condition,
|
||||
preceding_comment: *preceding_comment,
|
||||
|
@ -112,8 +127,14 @@ fn desugar_value_def<'a>(
|
|||
condition,
|
||||
preceding_comment,
|
||||
} => {
|
||||
let desugared_condition =
|
||||
&*arena.alloc(desugar_expr(arena, condition, src, line_info, module_path));
|
||||
let desugared_condition = &*arena.alloc(desugar_expr(
|
||||
arena,
|
||||
condition,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
Expect {
|
||||
condition: desugared_condition,
|
||||
preceding_comment: *preceding_comment,
|
||||
|
@ -123,8 +144,14 @@ fn desugar_value_def<'a>(
|
|||
condition,
|
||||
preceding_comment,
|
||||
} => {
|
||||
let desugared_condition =
|
||||
&*arena.alloc(desugar_expr(arena, condition, src, line_info, module_path));
|
||||
let desugared_condition = &*arena.alloc(desugar_expr(
|
||||
arena,
|
||||
condition,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
ExpectFx {
|
||||
condition: desugared_condition,
|
||||
preceding_comment: *preceding_comment,
|
||||
|
@ -141,7 +168,14 @@ fn desugar_value_def<'a>(
|
|||
params.map(|ModuleImportParams { before, params }| ModuleImportParams {
|
||||
before,
|
||||
params: params.map(|params| {
|
||||
desugar_field_collection(arena, *params, src, line_info, module_path)
|
||||
desugar_field_collection(
|
||||
arena,
|
||||
*params,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
)
|
||||
}),
|
||||
});
|
||||
|
||||
|
@ -174,7 +208,7 @@ fn desugar_value_def<'a>(
|
|||
)),
|
||||
lines_between: &[],
|
||||
body_pattern: new_pat,
|
||||
body_expr: desugar_expr(arena, stmt_expr, src, line_info, module_path),
|
||||
body_expr: desugar_expr(arena, stmt_expr, src, line_info, module_path, problems),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -187,9 +221,17 @@ pub fn desugar_defs_node_values<'a>(
|
|||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
top_level_def: bool,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) {
|
||||
for value_def in defs.value_defs.iter_mut() {
|
||||
*value_def = desugar_value_def(arena, arena.alloc(*value_def), src, line_info, module_path);
|
||||
*value_def = desugar_value_def(
|
||||
arena,
|
||||
arena.alloc(*value_def),
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
);
|
||||
}
|
||||
|
||||
// `desugar_defs_node_values` is called recursively in `desugar_expr`
|
||||
|
@ -312,6 +354,7 @@ pub fn desugar_expr<'a>(
|
|||
src: &'a str,
|
||||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) -> &'a Loc<Expr<'a>> {
|
||||
match &loc_expr.value {
|
||||
Float(..)
|
||||
|
@ -344,6 +387,7 @@ pub fn desugar_expr<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
)));
|
||||
|
||||
arena.alloc(Loc { region, value })
|
||||
|
@ -352,7 +396,7 @@ pub fn desugar_expr<'a>(
|
|||
let region = loc_expr.region;
|
||||
let new_lines = Vec::from_iter_in(
|
||||
lines.iter().map(|segments| {
|
||||
desugar_str_segments(arena, segments, src, line_info, module_path)
|
||||
desugar_str_segments(arena, segments, src, line_info, module_path, problems)
|
||||
}),
|
||||
arena,
|
||||
);
|
||||
|
@ -375,6 +419,7 @@ pub fn desugar_expr<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
)
|
||||
.value,
|
||||
paths,
|
||||
|
@ -389,7 +434,8 @@ pub fn desugar_expr<'a>(
|
|||
target,
|
||||
} => {
|
||||
let intermediate = arena.alloc(Loc::at(loc_expr.region, **sub_expr));
|
||||
let new_sub_loc_expr = desugar_expr(arena, intermediate, src, line_info, module_path);
|
||||
let new_sub_loc_expr =
|
||||
desugar_expr(arena, intermediate, src, line_info, module_path, problems);
|
||||
let new_sub_expr = arena.alloc(new_sub_loc_expr.value);
|
||||
|
||||
arena.alloc(Loc::at(
|
||||
|
@ -413,6 +459,7 @@ pub fn desugar_expr<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
)
|
||||
.value,
|
||||
paths,
|
||||
|
@ -424,7 +471,14 @@ pub fn desugar_expr<'a>(
|
|||
let mut new_items = Vec::with_capacity_in(items.len(), arena);
|
||||
|
||||
for item in items.iter() {
|
||||
new_items.push(desugar_expr(arena, item, src, line_info, module_path));
|
||||
new_items.push(desugar_expr(
|
||||
arena,
|
||||
item,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
}
|
||||
let new_items = new_items.into_bump_slice();
|
||||
let value: Expr<'a> = List(items.replace_items(new_items));
|
||||
|
@ -435,7 +489,8 @@ pub fn desugar_expr<'a>(
|
|||
})
|
||||
}
|
||||
Record(fields) => {
|
||||
let fields = desugar_field_collection(arena, *fields, src, line_info, module_path);
|
||||
let fields =
|
||||
desugar_field_collection(arena, *fields, src, line_info, module_path, problems);
|
||||
arena.alloc(Loc {
|
||||
region: loc_expr.region,
|
||||
value: Record(fields),
|
||||
|
@ -444,7 +499,7 @@ pub fn desugar_expr<'a>(
|
|||
Tuple(fields) => {
|
||||
let mut allocated = Vec::with_capacity_in(fields.len(), arena);
|
||||
for field in fields.iter() {
|
||||
let expr = desugar_expr(arena, field, src, line_info, module_path);
|
||||
let expr = desugar_expr(arena, field, src, line_info, module_path, problems);
|
||||
allocated.push(expr);
|
||||
}
|
||||
let fields = fields.replace_items(allocated.into_bump_slice());
|
||||
|
@ -456,11 +511,12 @@ pub fn desugar_expr<'a>(
|
|||
RecordUpdate { fields, update } => {
|
||||
// NOTE the `update` field is always a `Var { .. }`, we only desugar it to get rid of
|
||||
// any spaces before/after
|
||||
let new_update = desugar_expr(arena, update, src, line_info, module_path);
|
||||
let new_update = desugar_expr(arena, update, src, line_info, module_path, problems);
|
||||
|
||||
let mut allocated = Vec::with_capacity_in(fields.len(), arena);
|
||||
for field in fields.iter() {
|
||||
let value = desugar_field(arena, &field.value, src, line_info, module_path);
|
||||
let value =
|
||||
desugar_field(arena, &field.value, src, line_info, module_path, problems);
|
||||
allocated.push(Loc {
|
||||
value,
|
||||
region: field.region,
|
||||
|
@ -533,8 +589,8 @@ pub fn desugar_expr<'a>(
|
|||
Closure(loc_patterns, loc_ret) => arena.alloc(Loc {
|
||||
region: loc_expr.region,
|
||||
value: Closure(
|
||||
desugar_loc_patterns(arena, loc_patterns, src, line_info, module_path),
|
||||
desugar_expr(arena, loc_ret, src, line_info, module_path),
|
||||
desugar_loc_patterns(arena, loc_patterns, src, line_info, module_path, problems),
|
||||
desugar_expr(arena, loc_ret, src, line_info, module_path, problems),
|
||||
),
|
||||
}),
|
||||
Backpassing(loc_patterns, loc_body, loc_ret) => {
|
||||
|
@ -542,12 +598,19 @@ pub fn desugar_expr<'a>(
|
|||
//
|
||||
// loc_ret
|
||||
|
||||
// first desugar the body, because it may contain |>
|
||||
let desugared_body = desugar_expr(arena, loc_body, src, line_info, module_path);
|
||||
let problem_region = Region::span_across(
|
||||
&Region::across_all(loc_patterns.iter().map(|loc_pattern| &loc_pattern.region)),
|
||||
&loc_body.region,
|
||||
);
|
||||
problems.push(Problem::DeprecatedBackpassing(problem_region));
|
||||
|
||||
let desugared_ret = desugar_expr(arena, loc_ret, src, line_info, module_path);
|
||||
// first desugar the body, because it may contain |>
|
||||
let desugared_body =
|
||||
desugar_expr(arena, loc_body, src, line_info, module_path, problems);
|
||||
|
||||
let desugared_ret = desugar_expr(arena, loc_ret, src, line_info, module_path, problems);
|
||||
let desugared_loc_patterns =
|
||||
desugar_loc_patterns(arena, loc_patterns, src, line_info, module_path);
|
||||
desugar_loc_patterns(arena, loc_patterns, src, line_info, module_path, problems);
|
||||
let closure = Expr::Closure(desugared_loc_patterns, desugared_ret);
|
||||
let loc_closure = Loc::at(loc_expr.region, closure);
|
||||
|
||||
|
@ -583,7 +646,7 @@ pub fn desugar_expr<'a>(
|
|||
RecordBuilder { mapper, fields } => {
|
||||
// NOTE the `mapper` is always a `Var { .. }`, we only desugar it to get rid of
|
||||
// any spaces before/after
|
||||
let new_mapper = desugar_expr(arena, mapper, src, line_info, module_path);
|
||||
let new_mapper = desugar_expr(arena, mapper, src, line_info, module_path, problems);
|
||||
|
||||
if fields.is_empty() {
|
||||
return arena.alloc(Loc {
|
||||
|
@ -607,7 +670,8 @@ pub fn desugar_expr<'a>(
|
|||
|
||||
for field in fields.items {
|
||||
let (name, value, ignored) =
|
||||
match desugar_field(arena, &field.value, src, line_info, module_path) {
|
||||
match desugar_field(arena, &field.value, src, line_info, module_path, problems)
|
||||
{
|
||||
AssignedField::RequiredValue(loc_name, _, loc_val) => {
|
||||
(loc_name, loc_val, false)
|
||||
}
|
||||
|
@ -845,11 +909,20 @@ pub fn desugar_expr<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
),
|
||||
Defs(defs, loc_ret) => {
|
||||
let mut defs = (*defs).clone();
|
||||
desugar_defs_node_values(arena, &mut defs, src, line_info, module_path, false);
|
||||
let loc_ret = desugar_expr(arena, loc_ret, src, line_info, module_path);
|
||||
desugar_defs_node_values(
|
||||
arena,
|
||||
&mut defs,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
false,
|
||||
problems,
|
||||
);
|
||||
let loc_ret = desugar_expr(arena, loc_ret, src, line_info, module_path, problems);
|
||||
|
||||
arena.alloc(Loc::at(loc_expr.region, Defs(arena.alloc(defs), loc_ret)))
|
||||
}
|
||||
|
@ -881,14 +954,21 @@ pub fn desugar_expr<'a>(
|
|||
}
|
||||
};
|
||||
|
||||
desugared_args.push(desugar_expr(arena, arg, src, line_info, module_path));
|
||||
desugared_args.push(desugar_expr(
|
||||
arena,
|
||||
arg,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
}
|
||||
|
||||
let desugared_args = desugared_args.into_bump_slice();
|
||||
|
||||
let mut apply: &Loc<Expr> = arena.alloc(Loc {
|
||||
value: Apply(
|
||||
desugar_expr(arena, loc_fn, src, line_info, module_path),
|
||||
desugar_expr(arena, loc_fn, src, line_info, module_path, problems),
|
||||
desugared_args,
|
||||
*called_via,
|
||||
),
|
||||
|
@ -900,7 +980,8 @@ pub fn desugar_expr<'a>(
|
|||
|
||||
Some(apply_exprs) => {
|
||||
for expr in apply_exprs {
|
||||
let desugared_expr = desugar_expr(arena, expr, src, line_info, module_path);
|
||||
let desugared_expr =
|
||||
desugar_expr(arena, expr, src, line_info, module_path, problems);
|
||||
|
||||
let args = std::slice::from_ref(arena.alloc(apply));
|
||||
|
||||
|
@ -921,17 +1002,31 @@ pub fn desugar_expr<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
let mut desugared_branches = Vec::with_capacity_in(branches.len(), arena);
|
||||
|
||||
for branch in branches.iter() {
|
||||
let desugared_expr =
|
||||
desugar_expr(arena, &branch.value, src, line_info, module_path);
|
||||
let desugared_patterns =
|
||||
desugar_loc_patterns(arena, branch.patterns, src, line_info, module_path);
|
||||
desugar_expr(arena, &branch.value, src, line_info, module_path, problems);
|
||||
let desugared_patterns = desugar_loc_patterns(
|
||||
arena,
|
||||
branch.patterns,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
);
|
||||
|
||||
let desugared_guard = if let Some(guard) = &branch.guard {
|
||||
Some(*desugar_expr(arena, guard, src, line_info, module_path))
|
||||
Some(*desugar_expr(
|
||||
arena,
|
||||
guard,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
@ -969,8 +1064,14 @@ pub fn desugar_expr<'a>(
|
|||
},
|
||||
};
|
||||
let loc_fn_var = arena.alloc(Loc { region, value });
|
||||
let desugared_args =
|
||||
arena.alloc([desugar_expr(arena, loc_arg, src, line_info, module_path)]);
|
||||
let desugared_args = arena.alloc([desugar_expr(
|
||||
arena,
|
||||
loc_arg,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
)]);
|
||||
|
||||
arena.alloc(Loc {
|
||||
value: Apply(loc_fn_var, desugared_args, CalledVia::UnaryOp(op)),
|
||||
|
@ -989,6 +1090,7 @@ pub fn desugar_expr<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
)
|
||||
}
|
||||
ParensAround(expr) => {
|
||||
|
@ -1001,6 +1103,7 @@ pub fn desugar_expr<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
);
|
||||
|
||||
arena.alloc(Loc {
|
||||
|
@ -1016,14 +1119,15 @@ pub fn desugar_expr<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
|
||||
let mut desugared_if_thens = Vec::with_capacity_in(if_thens.len(), arena);
|
||||
|
||||
for (condition, then_branch) in if_thens.iter() {
|
||||
desugared_if_thens.push((
|
||||
*desugar_expr(arena, condition, src, line_info, module_path),
|
||||
*desugar_expr(arena, then_branch, src, line_info, module_path),
|
||||
*desugar_expr(arena, condition, src, line_info, module_path, problems),
|
||||
*desugar_expr(arena, then_branch, src, line_info, module_path, problems),
|
||||
));
|
||||
}
|
||||
|
||||
|
@ -1033,14 +1137,21 @@ pub fn desugar_expr<'a>(
|
|||
})
|
||||
}
|
||||
Expect(condition, continuation) => {
|
||||
let desugared_condition =
|
||||
&*arena.alloc(desugar_expr(arena, condition, src, line_info, module_path));
|
||||
let desugared_condition = &*arena.alloc(desugar_expr(
|
||||
arena,
|
||||
condition,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
let desugared_continuation = &*arena.alloc(desugar_expr(
|
||||
arena,
|
||||
continuation,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
arena.alloc(Loc {
|
||||
value: Expect(desugared_condition, desugared_continuation),
|
||||
|
@ -1056,6 +1167,7 @@ pub fn desugar_expr<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
|
||||
let region = condition.region;
|
||||
|
@ -1068,8 +1180,14 @@ pub fn desugar_expr<'a>(
|
|||
value: inspect_fn,
|
||||
region,
|
||||
});
|
||||
let desugared_inspect_args =
|
||||
arena.alloc([desugar_expr(arena, condition, src, line_info, module_path)]);
|
||||
let desugared_inspect_args = arena.alloc([desugar_expr(
|
||||
arena,
|
||||
condition,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
)]);
|
||||
|
||||
let dbg_str = arena.alloc(Loc {
|
||||
value: Apply(loc_inspect_fn_var, desugared_inspect_args, CalledVia::Space),
|
||||
|
@ -1114,6 +1232,7 @@ fn desugar_str_segments<'a>(
|
|||
src: &'a str,
|
||||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) -> &'a [StrSegment<'a>] {
|
||||
Vec::from_iter_in(
|
||||
segments.iter().map(|segment| match segment {
|
||||
|
@ -1130,6 +1249,7 @@ fn desugar_str_segments<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
);
|
||||
StrSegment::DeprecatedInterpolated(Loc {
|
||||
region: loc_desugared.region,
|
||||
|
@ -1146,6 +1266,7 @@ fn desugar_str_segments<'a>(
|
|||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
);
|
||||
StrSegment::Interpolated(Loc {
|
||||
region: loc_desugared.region,
|
||||
|
@ -1164,11 +1285,12 @@ fn desugar_field_collection<'a>(
|
|||
src: &'a str,
|
||||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) -> Collection<'a, Loc<AssignedField<'a, Expr<'a>>>> {
|
||||
let mut allocated = Vec::with_capacity_in(fields.len(), arena);
|
||||
|
||||
for field in fields.iter() {
|
||||
let value = desugar_field(arena, &field.value, src, line_info, module_path);
|
||||
let value = desugar_field(arena, &field.value, src, line_info, module_path, problems);
|
||||
|
||||
allocated.push(Loc::at(field.region, value));
|
||||
}
|
||||
|
@ -1182,6 +1304,7 @@ fn desugar_field<'a>(
|
|||
src: &'a str,
|
||||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) -> AssignedField<'a, Expr<'a>> {
|
||||
use roc_parse::ast::AssignedField::*;
|
||||
|
||||
|
@ -1192,7 +1315,7 @@ fn desugar_field<'a>(
|
|||
region: loc_str.region,
|
||||
},
|
||||
spaces,
|
||||
desugar_expr(arena, loc_expr, src, line_info, module_path),
|
||||
desugar_expr(arena, loc_expr, src, line_info, module_path, problems),
|
||||
),
|
||||
OptionalValue(loc_str, spaces, loc_expr) => OptionalValue(
|
||||
Loc {
|
||||
|
@ -1200,7 +1323,7 @@ fn desugar_field<'a>(
|
|||
region: loc_str.region,
|
||||
},
|
||||
spaces,
|
||||
desugar_expr(arena, loc_expr, src, line_info, module_path),
|
||||
desugar_expr(arena, loc_expr, src, line_info, module_path, problems),
|
||||
),
|
||||
IgnoredValue(loc_str, spaces, loc_expr) => IgnoredValue(
|
||||
Loc {
|
||||
|
@ -1208,7 +1331,7 @@ fn desugar_field<'a>(
|
|||
region: loc_str.region,
|
||||
},
|
||||
spaces,
|
||||
desugar_expr(arena, loc_expr, src, line_info, module_path),
|
||||
desugar_expr(arena, loc_expr, src, line_info, module_path, problems),
|
||||
),
|
||||
LabelOnly(loc_str) => {
|
||||
// Desugar { x } into { x: x }
|
||||
|
@ -1226,11 +1349,22 @@ fn desugar_field<'a>(
|
|||
region: loc_str.region,
|
||||
},
|
||||
&[],
|
||||
desugar_expr(arena, arena.alloc(loc_expr), src, line_info, module_path),
|
||||
desugar_expr(
|
||||
arena,
|
||||
arena.alloc(loc_expr),
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
),
|
||||
)
|
||||
}
|
||||
SpaceBefore(field, _spaces) => desugar_field(arena, field, src, line_info, module_path),
|
||||
SpaceAfter(field, _spaces) => desugar_field(arena, field, src, line_info, module_path),
|
||||
SpaceBefore(field, _spaces) => {
|
||||
desugar_field(arena, field, src, line_info, module_path, problems)
|
||||
}
|
||||
SpaceAfter(field, _spaces) => {
|
||||
desugar_field(arena, field, src, line_info, module_path, problems)
|
||||
}
|
||||
|
||||
Malformed(string) => Malformed(string),
|
||||
}
|
||||
|
@ -1242,11 +1376,19 @@ fn desugar_loc_patterns<'a>(
|
|||
src: &'a str,
|
||||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) -> &'a [Loc<Pattern<'a>>] {
|
||||
Vec::from_iter_in(
|
||||
loc_patterns.iter().map(|loc_pattern| Loc {
|
||||
region: loc_pattern.region,
|
||||
value: desugar_pattern(arena, loc_pattern.value, src, line_info, module_path),
|
||||
value: desugar_pattern(
|
||||
arena,
|
||||
loc_pattern.value,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
),
|
||||
}),
|
||||
arena,
|
||||
)
|
||||
|
@ -1259,10 +1401,18 @@ fn desugar_loc_pattern<'a>(
|
|||
src: &'a str,
|
||||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) -> &'a Loc<Pattern<'a>> {
|
||||
arena.alloc(Loc {
|
||||
region: loc_pattern.region,
|
||||
value: desugar_pattern(arena, loc_pattern.value, src, line_info, module_path),
|
||||
value: desugar_pattern(
|
||||
arena,
|
||||
loc_pattern.value,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -1272,6 +1422,7 @@ fn desugar_pattern<'a>(
|
|||
src: &'a str,
|
||||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) -> Pattern<'a> {
|
||||
use roc_parse::ast::Pattern::*;
|
||||
|
||||
|
@ -1295,7 +1446,14 @@ fn desugar_pattern<'a>(
|
|||
let desugared_arg_patterns = Vec::from_iter_in(
|
||||
arg_patterns.iter().map(|arg_pattern| Loc {
|
||||
region: arg_pattern.region,
|
||||
value: desugar_pattern(arena, arg_pattern.value, src, line_info, module_path),
|
||||
value: desugar_pattern(
|
||||
arena,
|
||||
arg_pattern.value,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
),
|
||||
}),
|
||||
arena,
|
||||
)
|
||||
|
@ -1306,8 +1464,14 @@ fn desugar_pattern<'a>(
|
|||
RecordDestructure(field_patterns) => {
|
||||
let mut allocated = Vec::with_capacity_in(field_patterns.len(), arena);
|
||||
for field_pattern in field_patterns.iter() {
|
||||
let value =
|
||||
desugar_pattern(arena, field_pattern.value, src, line_info, module_path);
|
||||
let value = desugar_pattern(
|
||||
arena,
|
||||
field_pattern.value,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
);
|
||||
allocated.push(Loc {
|
||||
value,
|
||||
region: field_pattern.region,
|
||||
|
@ -1319,15 +1483,17 @@ fn desugar_pattern<'a>(
|
|||
}
|
||||
RequiredField(name, field_pattern) => RequiredField(
|
||||
name,
|
||||
desugar_loc_pattern(arena, field_pattern, src, line_info, module_path),
|
||||
desugar_loc_pattern(arena, field_pattern, src, line_info, module_path, problems),
|
||||
),
|
||||
OptionalField(name, expr) => OptionalField(
|
||||
name,
|
||||
desugar_expr(arena, expr, src, line_info, module_path, problems),
|
||||
),
|
||||
OptionalField(name, expr) => {
|
||||
OptionalField(name, desugar_expr(arena, expr, src, line_info, module_path))
|
||||
}
|
||||
Tuple(patterns) => {
|
||||
let mut allocated = Vec::with_capacity_in(patterns.len(), arena);
|
||||
for pattern in patterns.iter() {
|
||||
let value = desugar_pattern(arena, pattern.value, src, line_info, module_path);
|
||||
let value =
|
||||
desugar_pattern(arena, pattern.value, src, line_info, module_path, problems);
|
||||
allocated.push(Loc {
|
||||
value,
|
||||
region: pattern.region,
|
||||
|
@ -1340,7 +1506,8 @@ fn desugar_pattern<'a>(
|
|||
List(patterns) => {
|
||||
let mut allocated = Vec::with_capacity_in(patterns.len(), arena);
|
||||
for pattern in patterns.iter() {
|
||||
let value = desugar_pattern(arena, pattern.value, src, line_info, module_path);
|
||||
let value =
|
||||
desugar_pattern(arena, pattern.value, src, line_info, module_path, problems);
|
||||
allocated.push(Loc {
|
||||
value,
|
||||
region: pattern.region,
|
||||
|
@ -1351,14 +1518,14 @@ fn desugar_pattern<'a>(
|
|||
List(patterns)
|
||||
}
|
||||
As(sub_pattern, symbol) => As(
|
||||
desugar_loc_pattern(arena, sub_pattern, src, line_info, module_path),
|
||||
desugar_loc_pattern(arena, sub_pattern, src, line_info, module_path, problems),
|
||||
symbol,
|
||||
),
|
||||
SpaceBefore(sub_pattern, _spaces) => {
|
||||
desugar_pattern(arena, *sub_pattern, src, line_info, module_path)
|
||||
desugar_pattern(arena, *sub_pattern, src, line_info, module_path, problems)
|
||||
}
|
||||
SpaceAfter(sub_pattern, _spaces) => {
|
||||
desugar_pattern(arena, *sub_pattern, src, line_info, module_path)
|
||||
desugar_pattern(arena, *sub_pattern, src, line_info, module_path, problems)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1479,6 +1646,7 @@ fn binop_to_function(binop: BinOp) -> (&'static str, &'static str) {
|
|||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn desugar_bin_ops<'a>(
|
||||
arena: &'a Bump,
|
||||
whole_region: Region,
|
||||
|
@ -1487,19 +1655,27 @@ fn desugar_bin_ops<'a>(
|
|||
src: &'a str,
|
||||
line_info: &mut Option<LineInfo>,
|
||||
module_path: &str,
|
||||
problems: &mut std::vec::Vec<Problem>,
|
||||
) -> &'a Loc<Expr<'a>> {
|
||||
let mut arg_stack: Vec<&'a Loc<Expr>> = Vec::with_capacity_in(lefts.len() + 1, arena);
|
||||
let mut op_stack: Vec<Loc<BinOp>> = Vec::with_capacity_in(lefts.len(), arena);
|
||||
|
||||
for (loc_expr, loc_op) in lefts {
|
||||
arg_stack.push(desugar_expr(arena, loc_expr, src, line_info, module_path));
|
||||
arg_stack.push(desugar_expr(
|
||||
arena,
|
||||
loc_expr,
|
||||
src,
|
||||
line_info,
|
||||
module_path,
|
||||
problems,
|
||||
));
|
||||
match run_binop_step(arena, whole_region, &mut arg_stack, &mut op_stack, *loc_op) {
|
||||
Err(problem) => return problem,
|
||||
Ok(()) => continue,
|
||||
}
|
||||
}
|
||||
|
||||
let mut expr = desugar_expr(arena, right, src, line_info, module_path);
|
||||
let mut expr = desugar_expr(arena, right, src, line_info, module_path, problems);
|
||||
|
||||
for (left, loc_op) in arg_stack.into_iter().zip(op_stack.into_iter()).rev() {
|
||||
expr = arena.alloc(new_op_call_expr(arena, left, loc_op, expr));
|
||||
|
|
|
@ -337,7 +337,15 @@ pub fn canonicalize_module_defs<'a>(
|
|||
// operators, and then again on *their* nested operators, ultimately applying the
|
||||
// rules multiple times unnecessarily.
|
||||
|
||||
crate::desugar::desugar_defs_node_values(arena, loc_defs, src, &mut None, module_path, true);
|
||||
crate::desugar::desugar_defs_node_values(
|
||||
arena,
|
||||
loc_defs,
|
||||
src,
|
||||
&mut None,
|
||||
module_path,
|
||||
true,
|
||||
&mut env.problems,
|
||||
);
|
||||
|
||||
let mut rigid_variables = RigidVariables::default();
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
expr_str,
|
||||
&mut None,
|
||||
arena.alloc("TestPath"),
|
||||
&mut Default::default(),
|
||||
);
|
||||
|
||||
let mut scope = Scope::new(
|
||||
|
|
|
@ -12,7 +12,15 @@ mod suffixed_tests {
|
|||
($src:expr) => {{
|
||||
let arena = &Bump::new();
|
||||
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
|
||||
desugar_defs_node_values(arena, &mut defs, $src, &mut None, "test.roc", true);
|
||||
desugar_defs_node_values(
|
||||
arena,
|
||||
&mut defs,
|
||||
$src,
|
||||
&mut None,
|
||||
"test.roc",
|
||||
true,
|
||||
&mut Default::default(),
|
||||
);
|
||||
|
||||
let snapshot = format!("{:#?}", &defs);
|
||||
println!("{}", snapshot);
|
||||
|
|
|
@ -174,6 +174,7 @@ pub fn can_expr_with<'a>(
|
|||
expr_str,
|
||||
&mut None,
|
||||
arena.alloc("TestPath"),
|
||||
&mut Default::default(),
|
||||
);
|
||||
|
||||
let mut scope = Scope::new(
|
||||
|
|
|
@ -4816,7 +4816,7 @@ mod test_reporting {
|
|||
expression_indentation_end,
|
||||
indoc!(
|
||||
r"
|
||||
f <- Foo.foo
|
||||
f = Foo.foo
|
||||
"
|
||||
),
|
||||
@r#"
|
||||
|
@ -4827,7 +4827,7 @@ mod test_reporting {
|
|||
1│ app "test" provides [main] to "./platform"
|
||||
2│
|
||||
3│ main =
|
||||
4│ f <- Foo.foo
|
||||
4│ f = Foo.foo
|
||||
^
|
||||
|
||||
Looks like the indentation ends prematurely here. Did you mean to have
|
||||
|
@ -6617,34 +6617,6 @@ All branches in an `if` must have the same type!
|
|||
"
|
||||
);
|
||||
|
||||
test_report!(
|
||||
backpassing_type_error,
|
||||
indoc!(
|
||||
r#"
|
||||
x <- List.map ["a", "b"]
|
||||
|
||||
x + 1
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
This 2nd argument to `map` has an unexpected type:
|
||||
|
||||
4│> x <- List.map ["a", "b"]
|
||||
5│>
|
||||
6│> x + 1
|
||||
|
||||
The argument is an anonymous function of type:
|
||||
|
||||
Num * -> Num *
|
||||
|
||||
But `map` needs its 2nd argument to be:
|
||||
|
||||
Str -> Num *
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
expect_expr_type_error,
|
||||
indoc!(
|
||||
|
@ -10198,8 +10170,8 @@ All branches in an `if` must have the same type!
|
|||
|
||||
withOpen : (Handle -> Result {} *) -> Result {} *
|
||||
withOpen = \callback ->
|
||||
handle <- await (open {})
|
||||
{} <- await (callback handle)
|
||||
await (open {}) \handle ->
|
||||
await (callback handle) \_ ->
|
||||
close handle
|
||||
|
||||
withOpen
|
||||
|
@ -10212,8 +10184,8 @@ All branches in an `if` must have the same type!
|
|||
|
||||
10│ withOpen : (Handle -> Result {} *) -> Result {} *
|
||||
11│ withOpen = \callback ->
|
||||
12│> handle <- await (open {})
|
||||
13│> {} <- await (callback handle)
|
||||
12│> await (open {}) \handle ->
|
||||
13│> await (callback handle) \_ ->
|
||||
14│> close handle
|
||||
|
||||
The type annotation on `withOpen` says this `await` call should have the
|
||||
|
@ -10227,6 +10199,7 @@ All branches in an `if` must have the same type!
|
|||
Tip: Any connection between types must use a named type variable, not
|
||||
a `*`! Maybe the annotation on `withOpen` should have a named type
|
||||
variable in place of the `*`?
|
||||
|
||||
"
|
||||
);
|
||||
|
||||
|
@ -10830,7 +10803,7 @@ All branches in an `if` must have the same type!
|
|||
7│ a: <- "a",
|
||||
^^^
|
||||
|
||||
Tip: Remove `<-` to assign the field directly.
|
||||
Tip: Remove <- to assign the field directly.
|
||||
"#
|
||||
);
|
||||
|
||||
|
@ -10962,7 +10935,7 @@ All branches in an `if` must have the same type!
|
|||
6│ { xyz <-
|
||||
^^^
|
||||
|
||||
Note: Record builders need a mapper function before the `<-` to combine
|
||||
Note: Record builders need a mapper function before the <- to combine
|
||||
fields together with.
|
||||
"#
|
||||
);
|
||||
|
@ -11844,6 +11817,32 @@ All branches in an `if` must have the same type!
|
|||
@r"
|
||||
"
|
||||
);
|
||||
|
||||
test_report!(
|
||||
deprecated_backpassing,
|
||||
indoc!(
|
||||
r#"
|
||||
foo = \bar ->
|
||||
baz <- Result.try bar
|
||||
|
||||
Ok (baz * 3)
|
||||
|
||||
foo (Ok 123)
|
||||
"#
|
||||
),
|
||||
@r###"
|
||||
── BACKPASSING DEPRECATED in /code/proj/Main.roc ───────────────────────────────
|
||||
|
||||
Backpassing (<-) like this will soon be deprecated:
|
||||
|
||||
5│ baz <- Result.try bar
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
You should use a ! for awaiting tasks or a ? for trying results, and
|
||||
functions everywhere else.
|
||||
"###
|
||||
);
|
||||
|
||||
test_report!(
|
||||
unknown_shorthand_no_deps,
|
||||
indoc!(
|
||||
|
@ -13881,7 +13880,7 @@ All branches in an `if` must have the same type!
|
|||
"#
|
||||
),
|
||||
@r#"
|
||||
── DEFINITIONs ONLY USED IN RECURSION in /code/proj/Main.roc ───────────────────
|
||||
── DEFINITIONS ONLY USED IN RECURSION in /code/proj/Main.roc ───────────────────
|
||||
|
||||
These 2 definitions are only used in mutual recursion with themselves:
|
||||
|
||||
|
@ -13890,6 +13889,7 @@ All branches in an `if` must have the same type!
|
|||
|
||||
If you don't intend to use or export any of them, they should all be
|
||||
removed!
|
||||
|
||||
"#
|
||||
);
|
||||
|
||||
|
@ -13953,7 +13953,7 @@ All branches in an `if` must have the same type!
|
|||
"#
|
||||
),
|
||||
@r#"
|
||||
── DEFINITIONs ONLY USED IN RECURSION in /code/proj/Main.roc ───────────────────
|
||||
── DEFINITIONS ONLY USED IN RECURSION in /code/proj/Main.roc ───────────────────
|
||||
|
||||
These 2 definitions are only used in mutual recursion with themselves:
|
||||
|
||||
|
@ -13962,6 +13962,7 @@ All branches in an `if` must have the same type!
|
|||
|
||||
If you don't intend to use or export any of them, they should all be
|
||||
removed!
|
||||
|
||||
"#
|
||||
);
|
||||
|
||||
|
|
|
@ -118,6 +118,23 @@ impl std::fmt::Display for UnaryOp {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Suffix {
|
||||
/// (!), e.g. (Stdin.line!)
|
||||
Bang,
|
||||
/// (?), e.g. (parseData? data)
|
||||
Question,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Suffix {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Suffix::Bang => write!(f, "!"),
|
||||
Suffix::Question => write!(f, "?"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum BinOp {
|
||||
// highest precedence
|
||||
|
|
|
@ -54,6 +54,7 @@ pub enum Problem {
|
|||
new_symbol: Symbol,
|
||||
existing_symbol_region: Region,
|
||||
},
|
||||
DeprecatedBackpassing(Region),
|
||||
/// First symbol is the name of the closure with that argument
|
||||
/// Bool is whether the closure is anonymous
|
||||
/// Second symbol is the name of the argument that is unused
|
||||
|
@ -257,6 +258,7 @@ impl Problem {
|
|||
Problem::ExplicitBuiltinImport(_, _) => Warning,
|
||||
Problem::ExplicitBuiltinTypeImport(_, _) => Warning,
|
||||
Problem::ImportShadowsSymbol { .. } => RuntimeError,
|
||||
Problem::DeprecatedBackpassing(_) => Warning,
|
||||
Problem::ExposedButNotDefined(_) => RuntimeError,
|
||||
Problem::UnknownGeneratesWith(_) => RuntimeError,
|
||||
Problem::UnusedArgument(_, _, _, _) => Warning,
|
||||
|
@ -340,6 +342,7 @@ impl Problem {
|
|||
| Problem::ExplicitBuiltinImport(_, region)
|
||||
| Problem::ExplicitBuiltinTypeImport(_, region)
|
||||
| Problem::ImportShadowsSymbol { region, .. }
|
||||
| Problem::DeprecatedBackpassing(region)
|
||||
| Problem::UnknownGeneratesWith(Loc { region, .. })
|
||||
| Problem::UnusedArgument(_, _, _, region)
|
||||
| Problem::UnusedBranchDef(_, region)
|
||||
|
|
|
@ -2479,39 +2479,6 @@ fn expanded_result() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
|
||||
fn backpassing_result() {
|
||||
assert_evals_to!(
|
||||
indoc!(
|
||||
r#"
|
||||
app "test" provides [main] to "./platform"
|
||||
|
||||
a : Result I64 Str
|
||||
a = Ok 1
|
||||
|
||||
f = \x -> Ok (x + 1)
|
||||
g = \y -> Ok (y * 2)
|
||||
|
||||
main : I64
|
||||
main =
|
||||
helper =
|
||||
x <- Result.try a
|
||||
y <- Result.try (f x)
|
||||
z <- Result.try (g y)
|
||||
|
||||
Ok z
|
||||
|
||||
helper
|
||||
|> Result.withDefault 0
|
||||
|
||||
"#
|
||||
),
|
||||
4,
|
||||
i64
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||
#[should_panic(expected = "Shadowing { original_region: @55-56, shadow: @72-73 Ident")]
|
||||
|
|
|
@ -3389,7 +3389,7 @@ fn inspect_custom_type() {
|
|||
|
||||
myToInspector : HelloWorld -> Inspector f where f implements InspectFormatter
|
||||
myToInspector = \@HellowWorld {} ->
|
||||
fmt <- Inspect.custom
|
||||
Inspect.custom \fmt ->
|
||||
Inspect.apply (Inspect.str "Hello, World!\n") fmt
|
||||
|
||||
main =
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use roc_collections::all::MutSet;
|
||||
use roc_module::called_via::Suffix;
|
||||
use roc_module::ident::{Ident, Lowercase, ModuleName};
|
||||
use roc_module::symbol::DERIVABLE_ABILITIES;
|
||||
use roc_problem::can::PrecedenceProblem::BothNonAssociative;
|
||||
|
@ -246,6 +247,26 @@ pub fn can_problem<'b>(
|
|||
title = DUPLICATE_NAME.to_string();
|
||||
}
|
||||
|
||||
Problem::DeprecatedBackpassing(region) => {
|
||||
doc = alloc.stack([
|
||||
alloc.concat([
|
||||
alloc.reflow("Backpassing ("),
|
||||
alloc.backpassing_arrow(),
|
||||
alloc.reflow(") like this will soon be deprecated:"),
|
||||
]),
|
||||
alloc.region(lines.convert_region(region), severity),
|
||||
alloc.concat([
|
||||
alloc.reflow("You should use a "),
|
||||
alloc.suffix(Suffix::Bang),
|
||||
alloc.reflow(" for awaiting tasks or a "),
|
||||
alloc.suffix(Suffix::Question),
|
||||
alloc.reflow(" for trying results, and functions everywhere else."),
|
||||
]),
|
||||
]);
|
||||
|
||||
title = "BACKPASSING DEPRECATED".to_string();
|
||||
}
|
||||
|
||||
Problem::DefsOnlyUsedInRecursion(1, region) => {
|
||||
doc = alloc.stack([
|
||||
alloc.reflow("This definition is only used in recursion with itself:"),
|
||||
|
@ -270,7 +291,7 @@ pub fn can_problem<'b>(
|
|||
),
|
||||
]);
|
||||
|
||||
title = "DEFINITIONs ONLY USED IN RECURSION".to_string();
|
||||
title = "DEFINITIONS ONLY USED IN RECURSION".to_string();
|
||||
}
|
||||
Problem::ExposedButNotDefined(symbol) => {
|
||||
doc = alloc.stack([
|
||||
|
|
|
@ -1265,7 +1265,7 @@ fn to_expr_report<'b>(
|
|||
alloc.concat([
|
||||
alloc.tip(),
|
||||
alloc.reflow("Remove "),
|
||||
alloc.keyword("<-"),
|
||||
alloc.backpassing_arrow(),
|
||||
alloc.reflow(" to assign the field directly.")
|
||||
])
|
||||
}
|
||||
|
@ -1273,7 +1273,7 @@ fn to_expr_report<'b>(
|
|||
alloc.concat([
|
||||
alloc.note(""),
|
||||
alloc.reflow("Record builders need a mapper function before the "),
|
||||
alloc.keyword("<-"),
|
||||
alloc.backpassing_arrow(),
|
||||
alloc.reflow(" to combine fields together with.")
|
||||
])
|
||||
}
|
||||
|
|
|
@ -509,6 +509,10 @@ impl<'a> RocDocAllocator<'a> {
|
|||
self.text(name).annotate(Annotation::Shorthand)
|
||||
}
|
||||
|
||||
pub fn backpassing_arrow(&'a self) -> DocBuilder<'a, Self, Annotation> {
|
||||
self.text("<-").annotate(Annotation::BinOp)
|
||||
}
|
||||
|
||||
pub fn binop(
|
||||
&'a self,
|
||||
content: roc_module::called_via::BinOp,
|
||||
|
@ -523,6 +527,13 @@ impl<'a> RocDocAllocator<'a> {
|
|||
self.text(content.to_string()).annotate(Annotation::UnaryOp)
|
||||
}
|
||||
|
||||
pub fn suffix(
|
||||
&'a self,
|
||||
content: roc_module::called_via::Suffix,
|
||||
) -> DocBuilder<'a, Self, Annotation> {
|
||||
self.text(content.to_string()).annotate(Annotation::UnaryOp)
|
||||
}
|
||||
|
||||
/// Turns off backticks/colors in a block
|
||||
pub fn type_block(
|
||||
&'a self,
|
||||
|
|
|
@ -55,7 +55,7 @@ addFriend = \@Community { people, friends }, from, to ->
|
|||
walkFriendNames : Community, state, (state, Str, Set Str -> state) -> state
|
||||
walkFriendNames = \@Community { people, friends }, s0, nextFn ->
|
||||
(out, _) =
|
||||
(s1, id), friendSet <- List.walk friends (s0, 0)
|
||||
List.walk friends (s0, 0) \(s1, id), friendSet ->
|
||||
(@Person person) =
|
||||
when List.get people id is
|
||||
Ok v -> v
|
||||
|
@ -66,7 +66,7 @@ walkFriendNames = \@Community { people, friends }, s0, nextFn ->
|
|||
|> Str.concat person.lastName
|
||||
|
||||
friendNames =
|
||||
friendsSet, friendId <- Set.walk friendSet (Set.empty {})
|
||||
Set.walk friendSet (Set.empty {}) \friendsSet, friendId ->
|
||||
(@Person friend) =
|
||||
when List.get people friendId is
|
||||
Ok v -> v
|
||||
|
@ -78,4 +78,5 @@ walkFriendNames = \@Community { people, friends }, s0, nextFn ->
|
|||
Set.insert friendsSet friendName
|
||||
|
||||
(nextFn s1 personName friendNames, id + 1)
|
||||
|
||||
out
|
||||
|
|
|
@ -61,7 +61,7 @@ toStr = \{ scopes, stack, state, vars } ->
|
|||
|
||||
with : Str, (Context -> Task {} a) -> Task {} a
|
||||
with = \path, callback ->
|
||||
handle <- File.withOpen path
|
||||
File.withOpen path \handle ->
|
||||
# I cant define scope here and put it in the list in callback. It breaks alias anaysis.
|
||||
# Instead I have to inline this.
|
||||
# root_scope = { data: Some handle, index: 0, buf: [], whileInfo: None }
|
||||
|
@ -72,7 +72,7 @@ getChar : Context -> Task [T U8 Context] [EndOfData, NoScope]
|
|||
getChar = \ctx ->
|
||||
when List.last ctx.scopes is
|
||||
Ok scope ->
|
||||
(T val newScope) <- Task.await (getCharScope scope)
|
||||
(T val newScope) = getCharScope! scope
|
||||
Task.succeed (T val { ctx & scopes: List.set ctx.scopes (List.len ctx.scopes - 1) newScope })
|
||||
|
||||
Err ListWasEmpty ->
|
||||
|
@ -87,7 +87,7 @@ getCharScope = \scope ->
|
|||
Err OutOfBounds ->
|
||||
when scope.data is
|
||||
Some h ->
|
||||
bytes <- Task.await (File.chunk h)
|
||||
bytes = File.chunk! h
|
||||
when List.first bytes is
|
||||
Ok val ->
|
||||
# This starts at 1 because the first character is already being returned.
|
||||
|
|
|
@ -28,8 +28,8 @@ main = \filename ->
|
|||
|
||||
interpretFile : Str -> Task {} [StringErr Str]
|
||||
interpretFile = \filename ->
|
||||
ctx <- Context.with filename
|
||||
result <- Task.attempt (interpretCtx ctx)
|
||||
Context.with filename \ctx ->
|
||||
result = interpretCtx ctx |> Task.result!
|
||||
when result is
|
||||
Ok _ ->
|
||||
Task.succeed {}
|
||||
|
@ -129,11 +129,11 @@ interpretCtxLoop = \ctx ->
|
|||
Task.fail NoScope
|
||||
|
||||
Executing ->
|
||||
# {} <- Task.await (Stdout.line (Context.toStr ctx))
|
||||
result <- Task.attempt (Context.getChar ctx)
|
||||
# Stdout.line! (Context.toStr ctx)
|
||||
result = Context.getChar ctx |> Task.result!
|
||||
when result is
|
||||
Ok (T val newCtx) ->
|
||||
execCtx <- Task.await (stepExecCtx newCtx val)
|
||||
execCtx = stepExecCtx! newCtx val
|
||||
Task.succeed (Step execCtx)
|
||||
|
||||
Err NoScope ->
|
||||
|
@ -151,7 +151,7 @@ interpretCtxLoop = \ctx ->
|
|||
Task.succeed (Step dropCtx)
|
||||
|
||||
InComment ->
|
||||
result <- Task.attempt (Context.getChar ctx)
|
||||
result = Context.getChar ctx |> Task.result!
|
||||
when result is
|
||||
Ok (T val newCtx) ->
|
||||
if val == 0x7D then
|
||||
|
@ -167,7 +167,7 @@ interpretCtxLoop = \ctx ->
|
|||
Task.fail UnexpectedEndOfData
|
||||
|
||||
InNumber accum ->
|
||||
result <- Task.attempt (Context.getChar ctx)
|
||||
result = Context.getChar ctx |> Task.result!
|
||||
when result is
|
||||
Ok (T val newCtx) ->
|
||||
if isDigit val then
|
||||
|
@ -182,7 +182,7 @@ interpretCtxLoop = \ctx ->
|
|||
# outside of number now, this needs to be executed.
|
||||
pushCtx = Context.pushStack newCtx (Number accum)
|
||||
|
||||
execCtx <- Task.await (stepExecCtx { pushCtx & state: Executing } val)
|
||||
execCtx = stepExecCtx! { pushCtx & state: Executing } val
|
||||
Task.succeed (Step execCtx)
|
||||
|
||||
Err NoScope ->
|
||||
|
@ -192,14 +192,14 @@ interpretCtxLoop = \ctx ->
|
|||
Task.fail UnexpectedEndOfData
|
||||
|
||||
InString bytes ->
|
||||
result <- Task.attempt (Context.getChar ctx)
|
||||
result = Context.getChar ctx |> Task.result!
|
||||
when result is
|
||||
Ok (T val newCtx) ->
|
||||
if val == 0x22 then
|
||||
# `"` end of string
|
||||
when Str.fromUtf8 bytes is
|
||||
Ok str ->
|
||||
{} <- Task.await (Stdout.raw str)
|
||||
Stdout.raw! str
|
||||
Task.succeed (Step { newCtx & state: Executing })
|
||||
|
||||
Err _ ->
|
||||
|
@ -214,7 +214,7 @@ interpretCtxLoop = \ctx ->
|
|||
Task.fail UnexpectedEndOfData
|
||||
|
||||
InLambda depth bytes ->
|
||||
result <- Task.attempt (Context.getChar ctx)
|
||||
result = Context.getChar ctx |> Task.result!
|
||||
when result is
|
||||
Ok (T val newCtx) ->
|
||||
if val == 0x5B then
|
||||
|
@ -238,7 +238,7 @@ interpretCtxLoop = \ctx ->
|
|||
Task.fail UnexpectedEndOfData
|
||||
|
||||
InSpecialChar ->
|
||||
result <- Task.attempt (Context.getChar { ctx & state: Executing })
|
||||
result = Context.getChar { ctx & state: Executing } |> Task.result!
|
||||
when result is
|
||||
Ok (T 0xB8 newCtx) ->
|
||||
result2 =
|
||||
|
@ -273,7 +273,7 @@ interpretCtxLoop = \ctx ->
|
|||
Task.fail UnexpectedEndOfData
|
||||
|
||||
LoadChar ->
|
||||
result <- Task.attempt (Context.getChar { ctx & state: Executing })
|
||||
result = Context.getChar { ctx & state: Executing } |> Task.result!
|
||||
when result is
|
||||
Ok (T x newCtx) ->
|
||||
Task.succeed (Step (Context.pushStack newCtx (Number (Num.intCast x))))
|
||||
|
@ -472,7 +472,7 @@ stepExecCtx = \ctx, char ->
|
|||
Ok (T popCtx num) ->
|
||||
when Str.fromUtf8 [Num.intCast num] is
|
||||
Ok str ->
|
||||
{} <- Task.await (Stdout.raw str)
|
||||
Stdout.raw! str
|
||||
Task.succeed popCtx
|
||||
|
||||
Err _ ->
|
||||
|
@ -485,7 +485,7 @@ stepExecCtx = \ctx, char ->
|
|||
# `.` write int
|
||||
when popNumber ctx is
|
||||
Ok (T popCtx num) ->
|
||||
{} <- Task.await (Stdout.raw (Num.toStr (Num.intCast num)))
|
||||
Stdout.raw! (Num.toStr (Num.intCast num))
|
||||
Task.succeed popCtx
|
||||
|
||||
Err e ->
|
||||
|
@ -493,7 +493,7 @@ stepExecCtx = \ctx, char ->
|
|||
|
||||
0x5E ->
|
||||
# `^` read char as int
|
||||
in <- Task.await Stdin.char
|
||||
in = Stdin.char!
|
||||
if in == 255 then
|
||||
# max char sent on EOF. Change to -1
|
||||
Task.succeed (Context.pushStack ctx (Number -1))
|
||||
|
|
|
@ -22,7 +22,8 @@ close = \@Handle handle -> Effect.after (Effect.closeFile handle) Task.succeed
|
|||
|
||||
withOpen : Str, (Handle -> Task {} a) -> Task {} a
|
||||
withOpen = \path, callback ->
|
||||
handle <- Task.await (open path)
|
||||
result <- Task.attempt (callback handle)
|
||||
{} <- Task.await (close handle)
|
||||
handle = open! path
|
||||
result = callback handle |> Task.result!
|
||||
close! handle
|
||||
|
||||
Task.fromResult result
|
||||
|
|
|
@ -1,4 +1,15 @@
|
|||
module [Task, succeed, fail, await, map, onFail, attempt, fromResult, loop]
|
||||
module [
|
||||
Task,
|
||||
succeed,
|
||||
fail,
|
||||
await,
|
||||
map,
|
||||
onFail,
|
||||
attempt,
|
||||
result,
|
||||
fromResult,
|
||||
loop,
|
||||
]
|
||||
|
||||
import pf.Effect
|
||||
|
||||
|
@ -12,7 +23,7 @@ loop = \state, step ->
|
|||
\res ->
|
||||
when res is
|
||||
Ok (Step newState) -> Step newState
|
||||
Ok (Done result) -> Done (Ok result)
|
||||
Ok (Done res2) -> Done (Ok res2)
|
||||
Err e -> Done (Err e)
|
||||
|
||||
Effect.loop state looper
|
||||
|
@ -26,8 +37,8 @@ fail = \val ->
|
|||
Effect.always (Err val)
|
||||
|
||||
fromResult : Result a e -> Task a e
|
||||
fromResult = \result ->
|
||||
when result is
|
||||
fromResult = \res ->
|
||||
when res is
|
||||
Ok a -> succeed a
|
||||
Err e -> fail e
|
||||
|
||||
|
@ -35,8 +46,8 @@ attempt : Task a b, (Result a b -> Task c d) -> Task c d
|
|||
attempt = \effect, transform ->
|
||||
Effect.after
|
||||
effect
|
||||
\result ->
|
||||
when result is
|
||||
\res ->
|
||||
when res is
|
||||
Ok ok -> transform (Ok ok)
|
||||
Err err -> transform (Err err)
|
||||
|
||||
|
@ -44,8 +55,8 @@ await : Task a err, (a -> Task b err) -> Task b err
|
|||
await = \effect, transform ->
|
||||
Effect.after
|
||||
effect
|
||||
\result ->
|
||||
when result is
|
||||
\res ->
|
||||
when res is
|
||||
Ok a -> transform a
|
||||
Err err -> Task.fail err
|
||||
|
||||
|
@ -53,8 +64,8 @@ onFail : Task ok a, (a -> Task ok b) -> Task ok b
|
|||
onFail = \effect, transform ->
|
||||
Effect.after
|
||||
effect
|
||||
\result ->
|
||||
when result is
|
||||
\res ->
|
||||
when res is
|
||||
Ok a -> Task.succeed a
|
||||
Err err -> transform err
|
||||
|
||||
|
@ -62,7 +73,13 @@ map : Task a err, (a -> b) -> Task b err
|
|||
map = \effect, transform ->
|
||||
Effect.after
|
||||
effect
|
||||
\result ->
|
||||
when result is
|
||||
\res ->
|
||||
when res is
|
||||
Ok a -> Task.succeed (transform a)
|
||||
Err err -> Task.fail err
|
||||
|
||||
result : Task ok err -> Task (Result ok err) *
|
||||
result = \effect ->
|
||||
Effect.after
|
||||
effect
|
||||
\res -> Task.succeed res
|
||||
|
|
|
@ -88,8 +88,7 @@ initClientApp = \json, app ->
|
|||
initClientAppHelp json app
|
||||
|
||||
# Call out to JS to patch the DOM, attaching the event listeners
|
||||
_ <- applyPatches patches |> Effect.after
|
||||
|
||||
Effect.after (applyPatches patches) \_ ->
|
||||
Effect.always {
|
||||
app,
|
||||
state,
|
||||
|
@ -222,7 +221,7 @@ dispatchEvent = \platformState, eventData, handlerId ->
|
|||
{ rendered: newRendered, patches } =
|
||||
diff { rendered, patches: [] } newViewUnrendered
|
||||
|
||||
_ <- applyPatches patches |> Effect.after
|
||||
Effect.after (applyPatches patches) \_ ->
|
||||
Effect.always {
|
||||
platformState: {
|
||||
app,
|
||||
|
|
|
@ -540,29 +540,32 @@ expect
|
|||
decodeTuple = \initialState, stepElem, finalizer -> Decode.custom \initialBytes, @Json {} ->
|
||||
# NB: the stepper function must be passed explicitly until #2894 is resolved.
|
||||
decodeElems = \stepper, state, index, bytes ->
|
||||
{ val: newState, rest: beforeCommaOrBreak } <- tryDecode
|
||||
(
|
||||
when stepper state index is
|
||||
TooLong ->
|
||||
{ rest: beforeCommaOrBreak } <- bytes |> anything |> tryDecode
|
||||
bytes
|
||||
|> anything
|
||||
|> tryDecode \{ rest: beforeCommaOrBreak } ->
|
||||
{ result: Ok state, rest: beforeCommaOrBreak }
|
||||
|
||||
Next decoder ->
|
||||
Decode.decodeWith bytes decoder json
|
||||
)
|
||||
|
||||
|> tryDecode \{ val: newState, rest: beforeCommaOrBreak } ->
|
||||
{ result: commaResult, rest: nextBytes } = comma beforeCommaOrBreak
|
||||
|
||||
when commaResult is
|
||||
Ok {} -> decodeElems stepElem newState (index + 1) nextBytes
|
||||
Err _ -> { result: Ok newState, rest: nextBytes }
|
||||
|
||||
{ rest: afterBracketBytes } <- initialBytes |> openBracket |> tryDecode
|
||||
|
||||
{ val: endStateResult, rest: beforeClosingBracketBytes } <- decodeElems stepElem initialState 0 afterBracketBytes |> tryDecode
|
||||
|
||||
{ rest: afterTupleBytes } <- beforeClosingBracketBytes |> closingBracket |> tryDecode
|
||||
|
||||
initialBytes
|
||||
|> openBracket
|
||||
|> tryDecode \{ rest: afterBracketBytes } ->
|
||||
decodeElems stepElem initialState 0 afterBracketBytes
|
||||
|> tryDecode \{ val: endStateResult, rest: beforeClosingBracketBytes } ->
|
||||
beforeClosingBracketBytes
|
||||
|> closingBracket
|
||||
|> tryDecode \{ rest: afterTupleBytes } ->
|
||||
when finalizer endStateResult is
|
||||
Ok val -> { result: Ok val, rest: afterTupleBytes }
|
||||
Err e -> { result: Err e, rest: afterTupleBytes }
|
||||
|
@ -1225,7 +1228,6 @@ decodeRecord = \initialState, stepField, finalizer -> Decode.custom \bytes, @Jso
|
|||
|
||||
Ok objectName ->
|
||||
# Decode the json value
|
||||
{ val: updatedRecord, rest: bytesAfterValue } <-
|
||||
(
|
||||
fieldName = objectName
|
||||
|
||||
|
@ -1242,8 +1244,7 @@ decodeRecord = \initialState, stepField, finalizer -> Decode.custom \bytes, @Jso
|
|||
# Note we need to pass json config options recursively here
|
||||
Decode.decodeWith valueBytes valueDecoder (@Json {})
|
||||
)
|
||||
|> tryDecode
|
||||
|
||||
|> tryDecode \{ val: updatedRecord, rest: bytesAfterValue } ->
|
||||
# Check if another field or '}' for end of object
|
||||
when List.walkUntil bytesAfterValue (AfterObjectValue 0) objectHelp is
|
||||
ObjectFieldNameStart n ->
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue