mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 20:28:02 +00:00
WIP
This commit is contained in:
parent
743030fc99
commit
8a566dc339
260 changed files with 6344 additions and 2958 deletions
20
.github/workflows/basic_cli_build_release.yml
vendored
20
.github/workflows/basic_cli_build_release.yml
vendored
|
@ -1,5 +1,5 @@
|
|||
on:
|
||||
#pull_request:
|
||||
# pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
# this cancels workflows currently in progress if you start a new one
|
||||
|
@ -11,7 +11,7 @@ env:
|
|||
# use .tar.gz for quick testing
|
||||
ARCHIVE_FORMAT: .tar.br
|
||||
# Make a new basic-cli git tag and set it here before starting this workflow
|
||||
RELEASE_TAG: 0.14.0
|
||||
RELEASE_TAG: 0.16.0
|
||||
|
||||
jobs:
|
||||
prepare:
|
||||
|
@ -34,14 +34,14 @@ jobs:
|
|||
fi
|
||||
|
||||
# get latest nightly releases
|
||||
#- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_x86_64-latest.tar.gz
|
||||
#- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_arm64-latest.tar.gz
|
||||
#- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_x86_64-latest.tar.gz
|
||||
#- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_apple_silicon-latest.tar.gz
|
||||
- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_x86_64-TESTING.tar.gz
|
||||
- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_arm64-TESTING.tar.gz
|
||||
- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_x86_64-TESTING.tar.gz
|
||||
- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_apple_silicon-TESTING.tar.gz
|
||||
- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_x86_64-latest.tar.gz
|
||||
- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_arm64-latest.tar.gz
|
||||
- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_x86_64-latest.tar.gz
|
||||
- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_apple_silicon-latest.tar.gz
|
||||
#- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_x86_64-TESTING.tar.gz
|
||||
#- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-linux_arm64-TESTING.tar.gz
|
||||
#- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_x86_64-TESTING.tar.gz
|
||||
#- run: curl -fOL https://github.com/roc-lang/roc/releases/download/nightly/roc_nightly-macos_apple_silicon-TESTING.tar.gz
|
||||
|
||||
- name: Save roc_nightly archives
|
||||
uses: actions/upload-artifact@v4
|
||||
|
|
|
@ -24,4 +24,4 @@ jobs:
|
|||
|
||||
# for skipped tests; see #6946, #6947
|
||||
- name: cargo test without --release
|
||||
run: nix develop -c sh -c 'export ROC_CHECK_MONO_IR=1 && cargo test -- --skip tests/exhaustive/match_on_result_with_uninhabited_error_destructuring_in_lambda_syntax.txt --skip tests::identity_lambda --skip tests::issue_2300 --skip tests::issue_2582_specialize_result_value --skip tests::sum_lambda'
|
||||
run: nix develop -c sh -c 'export ROC_CHECK_MONO_IR=1 && cargo test'
|
||||
|
|
|
@ -275,10 +275,6 @@ main =
|
|||
|
||||
const UNFORMATTED_ROC: &str = r#"app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
|
||||
import pf.Stdout
|
||||
import pf.Stdin
|
||||
|
||||
main =
|
||||
Stdout.line! "What's your name?"
|
||||
name = Stdin.line!
|
||||
|
|
|
@ -322,6 +322,81 @@ mod cli_tests {
|
|||
insta::assert_snapshot!(cli_test_out.normalize_stdout_and_stderr());
|
||||
}
|
||||
|
||||
mod no_platform {
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn roc_check_markdown_docs() {
|
||||
let cli_build = ExecCli::new(
|
||||
CMD_CHECK,
|
||||
file_from_root("crates/cli/tests/markdown", "form.md"),
|
||||
);
|
||||
|
||||
let expected_out =
|
||||
"0 error and 0 warning found in <ignored for test> ms\n0 error and 0 warning found in <ignored for test> ms\n";
|
||||
|
||||
cli_build.run().assert_clean_stdout(expected_out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn import_in_expect() {
|
||||
let cli_build = ExecCli::new(
|
||||
CMD_TEST,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/module_params",
|
||||
"ImportInExpect.roc",
|
||||
),
|
||||
);
|
||||
|
||||
let expected_out = r#"
|
||||
0 failed and 3 passed in <ignored for test> ms.
|
||||
"#;
|
||||
|
||||
cli_build.run().assert_clean_stdout(expected_out);
|
||||
}
|
||||
}
|
||||
|
||||
mod test_platform_basic_cli {
|
||||
|
||||
use super::*;
|
||||
use roc_cli::CMD_RUN;
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn module_params_different_types() {
|
||||
let cli_build = ExecCli::new(
|
||||
CMD_RUN,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/module_params",
|
||||
"different_types.roc",
|
||||
),
|
||||
);
|
||||
|
||||
let expected_out = "Write something:\n42\n";
|
||||
|
||||
cli_build
|
||||
.run_executable(false, Some("42"), None)
|
||||
.assert_clean_stdout(expected_out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn module_params_issue_7116() {
|
||||
let cli_build = ExecCli::new(
|
||||
CMD_RUN,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/module_params",
|
||||
"issue_7116.roc",
|
||||
),
|
||||
);
|
||||
|
||||
cli_build.run().assert_zero_exit();
|
||||
}
|
||||
}
|
||||
|
||||
mod test_platform_simple_zig {
|
||||
use super::*;
|
||||
use roc_cli::{CMD_BUILD, CMD_DEV, CMD_TEST};
|
||||
|
@ -655,7 +730,6 @@ mod cli_tests {
|
|||
mod test_platform_effects_zig {
|
||||
use super::*;
|
||||
use cli_test_utils::helpers::file_from_root;
|
||||
use roc_cli::CMD_BUILD;
|
||||
|
||||
static BUILD_PLATFORM_HOST: std::sync::Once = std::sync::Once::new();
|
||||
|
||||
|
@ -665,7 +739,7 @@ mod cli_tests {
|
|||
let cli_build = ExecCli::new(
|
||||
CMD_BUILD,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/effects/platform/",
|
||||
"crates/cli/tests/test-projects/test-platform-effects-zig/",
|
||||
"app-stub.roc",
|
||||
),
|
||||
)
|
||||
|
@ -692,7 +766,7 @@ mod cli_tests {
|
|||
|
||||
let cli_build = ExecCli::new(
|
||||
CMD_BUILD,
|
||||
file_from_root("crates/cli/tests/test-projects/effects", "print-line.roc"),
|
||||
file_from_root("crates/cli/tests/test-projects/effectful", "print-line.roc"),
|
||||
);
|
||||
|
||||
let expected_output = "You entered: hi there!\nIt is known\n";
|
||||
|
@ -714,7 +788,7 @@ mod cli_tests {
|
|||
let cli_build = ExecCli::new(
|
||||
CMD_BUILD,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/effects",
|
||||
"crates/cli/tests/test-projects/effectful",
|
||||
"combine-tasks.roc",
|
||||
),
|
||||
);
|
||||
|
@ -738,7 +812,7 @@ mod cli_tests {
|
|||
let cli_build = ExecCli::new(
|
||||
CMD_BUILD,
|
||||
file_from_root(
|
||||
"crates/cli/tests/test-projects/effects",
|
||||
"crates/cli/tests/test-projects/effectful",
|
||||
"inspect-logging.roc",
|
||||
),
|
||||
);
|
||||
|
@ -780,18 +854,117 @@ mod cli_tests {
|
|||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn roc_check_markdown_docs() {
|
||||
fn effectful_form() {
|
||||
build_platform_host();
|
||||
|
||||
let cli_build = ExecCli::new(
|
||||
CMD_CHECK,
|
||||
file_from_root("crates/cli/tests/markdown", "form.md"),
|
||||
roc_cli::CMD_DEV,
|
||||
file_from_root("crates/cli/tests/test-projects/effectful", "form.roc"),
|
||||
);
|
||||
|
||||
let expected_out =
|
||||
"0 error and 0 warning found in <ignored for test> ms\n0 error and 0 warning found in <ignored for test> ms\n";
|
||||
let expected_out = r#"
|
||||
What's your first name?
|
||||
What's your last name?
|
||||
|
||||
cli_build.run().assert_clean_stdout(expected_out);
|
||||
Hi, Agus Zubiaga!
|
||||
|
||||
How old are you?
|
||||
|
||||
Nice! You can vote!
|
||||
|
||||
Bye! 👋
|
||||
"#;
|
||||
|
||||
cli_build
|
||||
.run_executable(false, Some("Agus\nZubiaga\n27\n"), None)
|
||||
.assert_clean_stdout(expected_out);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn effectful_hello() {
|
||||
todo!();
|
||||
// test_roc_app(
|
||||
// "crates/cli/tests/test-projects/effectful",
|
||||
// "hello.roc",
|
||||
// &[],
|
||||
// &[],
|
||||
// &[],
|
||||
// indoc!(
|
||||
// r#"
|
||||
// I'm an effect 👻
|
||||
// "#
|
||||
// ),
|
||||
// UseValgrind::No,
|
||||
// TestCliCommands::Dev,
|
||||
// );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn effectful_loops() {
|
||||
todo!();
|
||||
// test_roc_app(
|
||||
// "crates/cli/tests/test-projects/effectful",
|
||||
// "loops.roc",
|
||||
// &[],
|
||||
// &[],
|
||||
// &[],
|
||||
// indoc!(
|
||||
// r#"
|
||||
// Lu
|
||||
// Marce
|
||||
// Joaquin
|
||||
// Chloé
|
||||
// Mati
|
||||
// Pedro
|
||||
// "#
|
||||
// ),
|
||||
// UseValgrind::No,
|
||||
// TestCliCommands::Dev,
|
||||
// );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn effectful_untyped_passed_fx() {
|
||||
todo!();
|
||||
// test_roc_app(
|
||||
// "crates/cli/tests/test-projects/effectful",
|
||||
// "untyped_passed_fx.roc",
|
||||
// &[],
|
||||
// &[],
|
||||
// &[],
|
||||
// indoc!(
|
||||
// r#"
|
||||
// Before hello
|
||||
// Hello, World!
|
||||
// After hello
|
||||
// "#
|
||||
// ),
|
||||
// UseValgrind::No,
|
||||
// TestCliCommands::Dev,
|
||||
// );
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn effectful_ignore_result() {
|
||||
todo!();
|
||||
// test_roc_app(
|
||||
// "crates/cli/tests/test-projects/effectful",
|
||||
// "ignore_result.roc",
|
||||
// &[],
|
||||
// &[],
|
||||
// &[],
|
||||
// indoc!(
|
||||
// r#"
|
||||
// I asked for input and I ignored it. Deal with it! 😎
|
||||
// "#
|
||||
// ),
|
||||
// UseValgrind::No,
|
||||
// TestCliCommands::Dev,
|
||||
// );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
21
crates/cli/tests/test-projects/effectful/combine-tasks.roc
Normal file
21
crates/cli/tests/test-projects/effectful/combine-tasks.roc
Normal file
|
@ -0,0 +1,21 @@
|
|||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
|
||||
main! = \{} ->
|
||||
multipleIn =
|
||||
{ sequential <-
|
||||
a: Ok 123,
|
||||
b: Ok "abc",
|
||||
c: Ok [123],
|
||||
_d: Ok ["abc"],
|
||||
_: Ok (Dict.single "a" "b"),
|
||||
}?
|
||||
|
||||
PlatformTasks.putLine! "For multiple tasks: $(Inspect.toStr multipleIn)"
|
||||
|
||||
sequential : Result a err, Result b err, (a, b -> c) -> Result c err
|
||||
sequential = \firstTask, secondTask, mapper ->
|
||||
first = firstTask
|
||||
second = secondTask
|
||||
Ok (mapper first second)
|
27
crates/cli/tests/test-projects/effectful/form.roc
Normal file
27
crates/cli/tests/test-projects/effectful/form.roc
Normal file
|
@ -0,0 +1,27 @@
|
|||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
first = ask! "What's your first name?"
|
||||
last = ask! "What's your last name?"
|
||||
|
||||
Effect.putLine! "\nHi, $(first) $(last)!\n"
|
||||
|
||||
when Str.toU8 (ask! "How old are you?") is
|
||||
Err InvalidNumStr ->
|
||||
Effect.putLine! "Enter a valid number"
|
||||
|
||||
Ok age if age >= 18 ->
|
||||
Effect.putLine! "\nNice! You can vote!"
|
||||
|
||||
Ok age ->
|
||||
Effect.putLine! "\nYou'll be able to vote in $(Num.toStr (18 - age)) years"
|
||||
|
||||
Effect.putLine! "\nBye! 👋"
|
||||
|
||||
ask! : Str => Str
|
||||
ask! = \question ->
|
||||
Effect.putLine! question
|
||||
Effect.getLine! {}
|
7
crates/cli/tests/test-projects/effectful/hello.roc
Normal file
7
crates/cli/tests/test-projects/effectful/hello.roc
Normal file
|
@ -0,0 +1,7 @@
|
|||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
Effect.putLine! "I'm an effect 👻"
|
|
@ -0,0 +1,8 @@
|
|||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
_ = Effect.getLine! {}
|
||||
Effect.putLine! "I asked for input and I ignored it. Deal with it! 😎"
|
|
@ -1,12 +1,12 @@
|
|||
#
|
||||
# Shows how Roc values can be logged
|
||||
#
|
||||
app [main] { pf: platform "platform/main.roc" }
|
||||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
import Community
|
||||
|
||||
main =
|
||||
main! = \{} ->
|
||||
Community.empty
|
||||
|> Community.addPerson {
|
||||
firstName: "John",
|
16
crates/cli/tests/test-projects/effectful/loops.roc
Normal file
16
crates/cli/tests/test-projects/effectful/loops.roc
Normal file
|
@ -0,0 +1,16 @@
|
|||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
friends = ["Lu", "Marce", "Joaquin", "Chloé", "Mati", "Pedro"]
|
||||
printAll! friends
|
||||
|
||||
printAll! : List Str => {}
|
||||
printAll! = \friends ->
|
||||
when friends is
|
||||
[] -> {}
|
||||
[first, .. as remaining] ->
|
||||
Effect.putLine! first
|
||||
printAll! remaining
|
27
crates/cli/tests/test-projects/effectful/print-line.roc
Normal file
27
crates/cli/tests/test-projects/effectful/print-line.roc
Normal file
|
@ -0,0 +1,27 @@
|
|||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
["Welcome!", "What's your name?"]
|
||||
|> forEach! Effect.putLine!
|
||||
|
||||
line = Effect.getLine! {}
|
||||
|
||||
if line == "secret" then
|
||||
Effect.putLine! "You found the secret"
|
||||
Effect.putLine! "Congratulations!"
|
||||
else
|
||||
{}
|
||||
|
||||
Effect.putLine! "You entered: $(line)"
|
||||
Effect.putLine! "It is known"
|
||||
|
||||
forEach! : List a, (a => {}) => {}
|
||||
forEach! = \l, f! ->
|
||||
when l is
|
||||
[] -> {}
|
||||
[x, .. as xs] ->
|
||||
f! x
|
||||
forEach! xs f!
|
|
@ -0,0 +1,12 @@
|
|||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.Effect
|
||||
|
||||
main! : {} => {}
|
||||
main! = \{} ->
|
||||
logged! "hello" (\{} -> Effect.putLine! "Hello, World!")
|
||||
|
||||
logged! = \name, fx! ->
|
||||
Effect.putLine! "Before $(name)"
|
||||
fx! {}
|
||||
Effect.putLine! "After $(name)"
|
|
@ -1,21 +0,0 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
|
||||
main =
|
||||
multipleIn =
|
||||
{ sequential <-
|
||||
a: Task.ok 123,
|
||||
b: Task.ok "abc",
|
||||
c: Task.ok [123],
|
||||
_d: Task.ok ["abc"],
|
||||
_: Task.ok (Dict.single "a" "b"),
|
||||
}!
|
||||
|
||||
PlatformTasks.putLine! "For multiple tasks: $(Inspect.toStr multipleIn)"
|
||||
|
||||
sequential : Task a err, Task b err, (a, b -> c) -> Task c err
|
||||
sequential = \firstTask, secondTask, mapper ->
|
||||
first = firstTask!
|
||||
second = secondTask!
|
||||
Task.ok (mapper first second)
|
|
@ -1,7 +0,0 @@
|
|||
hosted PlatformTasks
|
||||
exposes [putLine, getLine]
|
||||
imports []
|
||||
|
||||
putLine : Str -> Task {} *
|
||||
|
||||
getLine : Task Str *
|
|
@ -1,4 +0,0 @@
|
|||
app [main] { pf: platform "main.roc" }
|
||||
|
||||
# just a stubbed app for building the test platform
|
||||
main = Task.ok {}
|
|
@ -1,9 +0,0 @@
|
|||
platform "effects"
|
||||
requires {} { main : Task {} [] }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Task {} []
|
||||
mainForHost = main
|
|
@ -1,11 +0,0 @@
|
|||
app [main] { pf: platform "platform/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
|
||||
main : Task {} []
|
||||
main =
|
||||
line = PlatformTasks.getLine!
|
||||
PlatformTasks.putLine! "You entered: $(line)"
|
||||
PlatformTasks.putLine! "It is known"
|
||||
|
||||
Task.ok {}
|
3
crates/cli/tests/test-projects/module_params/Alias.roc
Normal file
3
crates/cli/tests/test-projects/module_params/Alias.roc
Normal file
|
@ -0,0 +1,3 @@
|
|||
module { passed } -> [exposed]
|
||||
|
||||
exposed = passed
|
|
@ -0,0 +1,15 @@
|
|||
module []
|
||||
|
||||
https = \url -> "https://$(url)"
|
||||
|
||||
expect
|
||||
import Api { appId: "one", protocol: https }
|
||||
Api.baseUrl == "https://api.example.com/one"
|
||||
|
||||
expect
|
||||
import Api { appId: "two", protocol: https }
|
||||
Api.getUser 1 == "https://api.example.com/two/users/1"
|
||||
|
||||
expect
|
||||
import NoParams
|
||||
NoParams.hello == "hello!"
|
|
@ -0,0 +1,3 @@
|
|||
module [hello]
|
||||
|
||||
hello = "hello!"
|
|
@ -0,0 +1,14 @@
|
|||
app [main] {
|
||||
cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br",
|
||||
}
|
||||
|
||||
import cli.Stdout
|
||||
import cli.Stdin
|
||||
|
||||
import Alias { passed: Stdin.line } as In
|
||||
import Alias { passed: Stdout.line } as Out
|
||||
|
||||
main =
|
||||
Out.exposed! "Write something:"
|
||||
input = In.exposed!
|
||||
Out.exposed! input
|
11
crates/cli/tests/test-projects/module_params/issue_7116.roc
Normal file
11
crates/cli/tests/test-projects/module_params/issue_7116.roc
Normal file
|
@ -0,0 +1,11 @@
|
|||
app [main] {
|
||||
cli: platform "https://github.com/roc-lang/basic-cli/releases/download/0.16.0/O00IPk-Krg_diNS2dVWlI0ZQP794Vctxzv0ha96mK0E.tar.br",
|
||||
}
|
||||
|
||||
import Alias { passed: Task.ok {} }
|
||||
|
||||
main =
|
||||
Task.loop! {} loop
|
||||
|
||||
loop = \{} ->
|
||||
Task.map Alias.exposed \x -> Done x
|
|
@ -1,7 +1,7 @@
|
|||
app [main] { pf: platform "../effects/platform/main.roc" }
|
||||
app [main!] { pf: platform "../test-platform-effects-zig/main.roc" }
|
||||
|
||||
import pf.PlatformTasks
|
||||
import Menu { echo: PlatformTasks.putLine }
|
||||
import pf.Effect
|
||||
import Menu { echo: \str -> Effect.putLine! str }
|
||||
|
||||
main =
|
||||
main! = \{} ->
|
||||
Menu.menu "Agus"
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
hosted Effect
|
||||
exposes [putLine!, getLine!]
|
||||
imports []
|
||||
|
||||
putLine! : Str => {}
|
||||
|
||||
getLine! : {} => Str
|
|
@ -0,0 +1,4 @@
|
|||
app [main!] { pf: platform "main.roc" }
|
||||
|
||||
# just a stubbed app for building the test platform
|
||||
main! = Ok {}
|
|
@ -12,9 +12,6 @@ const Allocator = mem.Allocator;
|
|||
|
||||
extern fn roc__mainForHost_1_exposed_generic([*]u8) void;
|
||||
extern fn roc__mainForHost_1_exposed_size() i64;
|
||||
extern fn roc__mainForHost_0_caller(*const u8, [*]u8, [*]u8) void;
|
||||
extern fn roc__mainForHost_0_size() i64;
|
||||
extern fn roc__mainForHost_0_result_size() i64;
|
||||
|
||||
const Align = 2 * @alignOf(usize);
|
||||
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
|
||||
|
@ -124,40 +121,9 @@ pub export fn main() u8 {
|
|||
|
||||
roc__mainForHost_1_exposed_generic(output);
|
||||
|
||||
call_the_closure(output);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn call_the_closure(closure_data_pointer: [*]u8) void {
|
||||
const allocator = std.heap.page_allocator;
|
||||
|
||||
const size = roc__mainForHost_0_result_size();
|
||||
|
||||
if (size == 0) {
|
||||
// the function call returns an empty record
|
||||
// allocating 0 bytes causes issues because the allocator will return a NULL pointer
|
||||
// So it's special-cased
|
||||
const flags: u8 = 0;
|
||||
var result: [1]u8 = .{0};
|
||||
roc__mainForHost_0_caller(&flags, closure_data_pointer, &result);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const raw_output = allocator.alignedAlloc(u8, @alignOf(u64), @as(usize, @intCast(size))) catch unreachable;
|
||||
var output = @as([*]u8, @ptrCast(raw_output));
|
||||
|
||||
defer {
|
||||
allocator.free(raw_output);
|
||||
}
|
||||
|
||||
const flags: u8 = 0;
|
||||
roc__mainForHost_0_caller(&flags, closure_data_pointer, output);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pub export fn roc_fx_getLine() str.RocStr {
|
||||
return roc_fx_getLine_help() catch return str.RocStr.empty();
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
platform "effects"
|
||||
requires {} { main! : {} => {} }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost!]
|
||||
|
||||
mainForHost! : {} => {}
|
||||
mainForHost! = \{} -> main! {}
|
|
@ -222,8 +222,8 @@ sequence = \taskList ->
|
|||
Task.loop (taskList, List.withCapacity (List.len taskList)) \(tasks, values) ->
|
||||
when tasks is
|
||||
[task, .. as rest] ->
|
||||
value = task!
|
||||
Task.ok (Step (rest, List.append values value))
|
||||
Task.map task \value ->
|
||||
Step (rest, List.append values value)
|
||||
|
||||
[] ->
|
||||
Task.ok (Done values)
|
||||
|
|
|
@ -4,7 +4,9 @@ use crate::scope::{PendingAbilitiesInScope, Scope, SymbolLookup};
|
|||
use roc_collections::{ImMap, MutSet, SendMap, VecMap, VecSet};
|
||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_parse::ast::{AssignedField, ExtractSpaces, Pattern, Tag, TypeAnnotation, TypeHeader};
|
||||
use roc_parse::ast::{
|
||||
AssignedField, ExtractSpaces, FunctionArrow, Pattern, Tag, TypeAnnotation, TypeHeader,
|
||||
};
|
||||
use roc_problem::can::ShadowKind;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{VarStore, Variable};
|
||||
|
@ -448,7 +450,7 @@ pub fn find_type_def_symbols(
|
|||
stack.push(&t.value);
|
||||
}
|
||||
}
|
||||
Function(arguments, result) => {
|
||||
Function(arguments, _arrow, result) => {
|
||||
for t in arguments.iter() {
|
||||
stack.push(&t.value);
|
||||
}
|
||||
|
@ -554,7 +556,7 @@ fn can_annotation_help(
|
|||
use roc_parse::ast::TypeAnnotation::*;
|
||||
|
||||
match annotation {
|
||||
Function(argument_types, return_type) => {
|
||||
Function(argument_types, arrow, return_type) => {
|
||||
let mut args = Vec::new();
|
||||
|
||||
for arg in *argument_types {
|
||||
|
@ -589,7 +591,12 @@ fn can_annotation_help(
|
|||
introduced_variables.insert_lambda_set(lambda_set);
|
||||
let closure = Type::Variable(lambda_set);
|
||||
|
||||
Type::Function(args, Box::new(closure), Box::new(ret))
|
||||
let fx_type = match arrow {
|
||||
FunctionArrow::Pure => Type::Pure,
|
||||
FunctionArrow::Effectful => Type::Effectful,
|
||||
};
|
||||
|
||||
Type::Function(args, Box::new(closure), Box::new(ret), Box::new(fx_type))
|
||||
}
|
||||
Apply(module_name, ident, type_arguments) => {
|
||||
let symbol = match make_apply_symbol(env, region, scope, module_name, ident, references)
|
||||
|
|
|
@ -418,6 +418,7 @@ fn defn(
|
|||
expr_var: var_store.fresh(),
|
||||
pattern_vars: SendMap::default(),
|
||||
annotation: None,
|
||||
kind: crate::def::DefKind::Let,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -446,6 +447,7 @@ fn defn_help(
|
|||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: ret_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: Vec::new(),
|
||||
|
@ -547,6 +549,7 @@ fn to_num_checked(symbol: Symbol, var_store: &mut VarStore, lowlevel: LowLevel)
|
|||
expr_var: record_var,
|
||||
pattern_vars: SendMap::default(),
|
||||
annotation: None,
|
||||
kind: crate::def::DefKind::Let,
|
||||
};
|
||||
|
||||
let body = LetNonRec(Box::new(def), Box::new(no_region(cont)));
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::abilities::SpecializationId;
|
|||
use crate::exhaustive::{ExhaustiveContext, SketchedRows};
|
||||
use crate::expected::{Expected, PExpected};
|
||||
use roc_collections::soa::{index_push_new, slice_extend_new};
|
||||
use roc_module::ident::TagName;
|
||||
use roc_module::ident::{IdentSuffix, TagName};
|
||||
use roc_module::symbol::{ModuleId, Symbol};
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::{ExhaustiveMark, IllegalCycleMark, Variable};
|
||||
|
@ -29,6 +29,8 @@ pub struct Constraints {
|
|||
pub eq: Vec<Eq>,
|
||||
pub pattern_eq: Vec<PatternEq>,
|
||||
pub cycles: Vec<Cycle>,
|
||||
pub fx_call_constraints: Vec<FxCallConstraint>,
|
||||
pub fx_suffix_constraints: Vec<FxSuffixConstraint>,
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Constraints {
|
||||
|
@ -50,6 +52,8 @@ impl std::fmt::Debug for Constraints {
|
|||
.field("eq", &self.eq)
|
||||
.field("pattern_eq", &self.pattern_eq)
|
||||
.field("cycles", &self.cycles)
|
||||
.field("fx_call_constraints", &self.fx_call_constraints)
|
||||
.field("fx_suffix_constraints", &self.fx_suffix_constraints)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
@ -81,6 +85,8 @@ impl Constraints {
|
|||
let eq = Vec::new();
|
||||
let pattern_eq = Vec::new();
|
||||
let cycles = Vec::new();
|
||||
let fx_call_constraints = Vec::with_capacity(16);
|
||||
let fx_suffix_constraints = Vec::new();
|
||||
|
||||
categories.extend([
|
||||
Category::Record,
|
||||
|
@ -130,6 +136,8 @@ impl Constraints {
|
|||
eq,
|
||||
pattern_eq,
|
||||
cycles,
|
||||
fx_call_constraints,
|
||||
fx_suffix_constraints,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -574,6 +582,64 @@ impl Constraints {
|
|||
Constraint::Lookup(symbol, expected_index, region)
|
||||
}
|
||||
|
||||
pub fn fx_call(
|
||||
&mut self,
|
||||
call_fx_var: Variable,
|
||||
call_kind: FxCallKind,
|
||||
call_region: Region,
|
||||
expectation: Option<FxExpectation>,
|
||||
) -> Constraint {
|
||||
let constraint = FxCallConstraint {
|
||||
call_fx_var,
|
||||
call_kind,
|
||||
call_region,
|
||||
expectation,
|
||||
};
|
||||
|
||||
let constraint_index = index_push_new(&mut self.fx_call_constraints, constraint);
|
||||
|
||||
Constraint::FxCall(constraint_index)
|
||||
}
|
||||
|
||||
pub fn fx_pattern_suffix(
|
||||
&mut self,
|
||||
symbol: Symbol,
|
||||
type_index: TypeOrVar,
|
||||
region: Region,
|
||||
) -> Constraint {
|
||||
let constraint = FxSuffixConstraint {
|
||||
kind: FxSuffixKind::Pattern(symbol),
|
||||
type_index,
|
||||
region,
|
||||
};
|
||||
|
||||
let constraint_index = index_push_new(&mut self.fx_suffix_constraints, constraint);
|
||||
|
||||
Constraint::FxSuffix(constraint_index)
|
||||
}
|
||||
|
||||
pub fn fx_record_field_suffix(
|
||||
&mut self,
|
||||
suffix: IdentSuffix,
|
||||
variable: Variable,
|
||||
region: Region,
|
||||
) -> Constraint {
|
||||
let type_index = Self::push_type_variable(variable);
|
||||
let constraint = FxSuffixConstraint {
|
||||
kind: FxSuffixKind::RecordField(suffix),
|
||||
type_index,
|
||||
region,
|
||||
};
|
||||
|
||||
let constraint_index = index_push_new(&mut self.fx_suffix_constraints, constraint);
|
||||
|
||||
Constraint::FxSuffix(constraint_index)
|
||||
}
|
||||
|
||||
pub fn flex_to_pure(&mut self, fx_var: Variable) -> Constraint {
|
||||
Constraint::FlexToPure(fx_var)
|
||||
}
|
||||
|
||||
pub fn contains_save_the_environment(&self, constraint: &Constraint) -> bool {
|
||||
match constraint {
|
||||
Constraint::SaveTheEnvironment => true,
|
||||
|
@ -598,6 +664,10 @@ impl Constraints {
|
|||
| Constraint::Store(..)
|
||||
| Constraint::Lookup(..)
|
||||
| Constraint::Pattern(..)
|
||||
| Constraint::ExpectEffectful(..)
|
||||
| Constraint::FxCall(_)
|
||||
| Constraint::FxSuffix(_)
|
||||
| Constraint::FlexToPure(_)
|
||||
| Constraint::True
|
||||
| Constraint::IsOpenType(_)
|
||||
| Constraint::IncludesTag(_)
|
||||
|
@ -770,6 +840,14 @@ pub enum Constraint {
|
|||
Index<PatternCategory>,
|
||||
Region,
|
||||
),
|
||||
/// Check call fx against enclosing function fx
|
||||
FxCall(Index<FxCallConstraint>),
|
||||
/// Require idents to be accurately suffixed
|
||||
FxSuffix(Index<FxSuffixConstraint>),
|
||||
/// Set an fx var as pure if flex (no effectful functions were called)
|
||||
FlexToPure(Variable),
|
||||
/// Expect statement or ignored def to be effectful
|
||||
ExpectEffectful(Variable, ExpectEffectfulReason, Region),
|
||||
/// Used for things that always unify, e.g. blanks and runtime errors
|
||||
True,
|
||||
SaveTheEnvironment,
|
||||
|
@ -842,6 +920,56 @@ pub struct Cycle {
|
|||
pub expr_regions: Slice<Region>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct FxCallConstraint {
|
||||
pub call_fx_var: Variable,
|
||||
pub call_kind: FxCallKind,
|
||||
pub call_region: Region,
|
||||
pub expectation: Option<FxExpectation>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct FxExpectation {
|
||||
pub fx_var: Variable,
|
||||
pub ann_region: Option<Region>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FxCallKind {
|
||||
Call(Option<Symbol>),
|
||||
Stmt,
|
||||
Ignored,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct FxSuffixConstraint {
|
||||
pub type_index: TypeOrVar,
|
||||
pub kind: FxSuffixKind,
|
||||
pub region: Region,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum FxSuffixKind {
|
||||
Let(Symbol),
|
||||
Pattern(Symbol),
|
||||
RecordField(IdentSuffix),
|
||||
}
|
||||
|
||||
impl FxSuffixKind {
|
||||
pub fn suffix(&self) -> IdentSuffix {
|
||||
match self {
|
||||
Self::Let(symbol) | Self::Pattern(symbol) => symbol.suffix(),
|
||||
Self::RecordField(suffix) => *suffix,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ExpectEffectfulReason {
|
||||
Stmt,
|
||||
Ignored,
|
||||
}
|
||||
|
||||
/// Custom impl to limit vertical space used by the debug output
|
||||
impl std::fmt::Debug for Constraint {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
|
@ -858,6 +986,18 @@ impl std::fmt::Debug for Constraint {
|
|||
Self::Pattern(arg0, arg1, arg2, arg3) => {
|
||||
write!(f, "Pattern({arg0:?}, {arg1:?}, {arg2:?}, {arg3:?})")
|
||||
}
|
||||
Self::FxCall(arg0) => {
|
||||
write!(f, "FxCall({arg0:?})")
|
||||
}
|
||||
Self::FxSuffix(arg0) => {
|
||||
write!(f, "FxSuffix({arg0:?})")
|
||||
}
|
||||
Self::ExpectEffectful(arg0, arg1, arg2) => {
|
||||
write!(f, "EffectfulStmt({arg0:?}, {arg1:?}, {arg2:?})")
|
||||
}
|
||||
Self::FlexToPure(arg0) => {
|
||||
write!(f, "FlexToPure({arg0:?})")
|
||||
}
|
||||
Self::True => write!(f, "True"),
|
||||
Self::SaveTheEnvironment => write!(f, "SaveTheEnvironment"),
|
||||
Self::Let(arg0, arg1) => f.debug_tuple("Let").field(arg0).field(arg1).finish(),
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{
|
||||
def::Def,
|
||||
def::{Def, DefKind},
|
||||
expr::{
|
||||
ClosureData, Expr, Field, OpaqueWrapFunctionData, StructAccessorData, WhenBranchPattern,
|
||||
},
|
||||
|
@ -378,6 +378,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
expr_var,
|
||||
pattern_vars,
|
||||
annotation,
|
||||
kind,
|
||||
}| Def {
|
||||
loc_pattern: loc_pattern.map(|p| deep_copy_pattern_help(env, copied, p)),
|
||||
loc_expr: loc_expr.map(|e| go_help!(e)),
|
||||
|
@ -386,6 +387,11 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
// Annotation should only be used in constraining, don't clone before
|
||||
// constraining :)
|
||||
annotation: annotation.clone(),
|
||||
kind: match kind {
|
||||
DefKind::Let => DefKind::Let,
|
||||
DefKind::Stmt(v) => DefKind::Stmt(sub!(*v)),
|
||||
DefKind::Ignored(v) => DefKind::Ignored(sub!(*v)),
|
||||
},
|
||||
},
|
||||
)
|
||||
.collect(),
|
||||
|
@ -399,6 +405,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
expr_var,
|
||||
pattern_vars,
|
||||
annotation,
|
||||
kind,
|
||||
} = &**def;
|
||||
let def = Def {
|
||||
loc_pattern: loc_pattern.map(|p| deep_copy_pattern_help(env, copied, p)),
|
||||
|
@ -408,18 +415,20 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
// Annotation should only be used in constraining, don't clone before
|
||||
// constraining :)
|
||||
annotation: annotation.clone(),
|
||||
kind: *kind,
|
||||
};
|
||||
LetNonRec(Box::new(def), Box::new(body.map(|e| go_help!(e))))
|
||||
}
|
||||
|
||||
Call(f, args, called_via) => {
|
||||
let (fn_var, fn_expr, clos_var, ret_var) = &**f;
|
||||
let (fn_var, fn_expr, clos_var, ret_var, fx_var) = &**f;
|
||||
Call(
|
||||
Box::new((
|
||||
sub!(*fn_var),
|
||||
fn_expr.map(|e| go_help!(e)),
|
||||
sub!(*clos_var),
|
||||
sub!(*ret_var),
|
||||
sub!(*fx_var),
|
||||
)),
|
||||
args.iter()
|
||||
.map(|(var, expr)| (sub!(*var), expr.map(|e| go_help!(e))))
|
||||
|
@ -456,6 +465,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
function_type,
|
||||
closure_type,
|
||||
return_type,
|
||||
fx_type,
|
||||
early_returns,
|
||||
name,
|
||||
captured_symbols,
|
||||
|
@ -466,6 +476,7 @@ fn deep_copy_expr_help<C: CopyEnv>(env: &mut C, copied: &mut Vec<Variable>, expr
|
|||
function_type: sub!(*function_type),
|
||||
closure_type: sub!(*closure_type),
|
||||
return_type: sub!(*return_type),
|
||||
fx_type: sub!(*fx_type),
|
||||
early_returns: early_returns
|
||||
.iter()
|
||||
.map(|(var, region)| (sub!(*var), *region))
|
||||
|
@ -974,7 +985,7 @@ fn deep_copy_type_vars<C: CopyEnv>(
|
|||
|
||||
// Everything else is a mechanical descent.
|
||||
Structure(flat_type) => match flat_type {
|
||||
EmptyRecord | EmptyTagUnion => Structure(flat_type),
|
||||
EmptyRecord | EmptyTagUnion | EffectfulFunc => Structure(flat_type),
|
||||
Apply(symbol, arguments) => {
|
||||
descend_slice!(arguments);
|
||||
|
||||
|
@ -983,15 +994,21 @@ fn deep_copy_type_vars<C: CopyEnv>(
|
|||
Structure(Apply(symbol, new_arguments))
|
||||
})
|
||||
}
|
||||
Func(arguments, closure_var, ret_var) => {
|
||||
Func(arguments, closure_var, ret_var, fx_var) => {
|
||||
descend_slice!(arguments);
|
||||
|
||||
let new_closure_var = descend_var!(closure_var);
|
||||
let new_ret_var = descend_var!(ret_var);
|
||||
let new_fx_var = descend_var!(fx_var);
|
||||
|
||||
perform_clone!({
|
||||
let new_arguments = clone_var_slice!(arguments);
|
||||
Structure(Func(new_arguments, new_closure_var, new_ret_var))
|
||||
Structure(Func(
|
||||
new_arguments,
|
||||
new_closure_var,
|
||||
new_ret_var,
|
||||
new_fx_var,
|
||||
))
|
||||
})
|
||||
}
|
||||
Record(fields, ext_var) => {
|
||||
|
@ -1180,6 +1197,8 @@ fn deep_copy_type_vars<C: CopyEnv>(
|
|||
})
|
||||
}
|
||||
ErasedLambda => ErasedLambda,
|
||||
Pure => Pure,
|
||||
Effectful => Effectful,
|
||||
|
||||
RangedNumber(range) => {
|
||||
perform_clone!(RangedNumber(range))
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! Pretty-prints the canonical AST back to check our work - do things look reasonable?
|
||||
|
||||
use crate::def::Def;
|
||||
use crate::def::{Def, DefKind};
|
||||
use crate::expr::Expr::{self, *};
|
||||
use crate::expr::{
|
||||
ClosureData, DeclarationTag, Declarations, FunctionDef, OpaqueWrapFunctionData,
|
||||
|
@ -107,9 +107,14 @@ fn def<'a>(c: &Ctx, f: &'a Arena<'a>, d: &'a Def) -> DocBuilder<'a, Arena<'a>> {
|
|||
expr_var: _,
|
||||
pattern_vars: _,
|
||||
annotation: _,
|
||||
kind,
|
||||
} = d;
|
||||
|
||||
def_help(c, f, &loc_pattern.value, &loc_expr.value)
|
||||
match kind {
|
||||
DefKind::Let => def_help(c, f, &loc_pattern.value, &loc_expr.value),
|
||||
DefKind::Ignored(_) => def_help(c, f, &loc_pattern.value, &loc_expr.value),
|
||||
DefKind::Stmt(_) => expr(c, EPrec::Free, f, &loc_expr.value),
|
||||
}
|
||||
}
|
||||
|
||||
fn def_symbol_help<'a>(
|
||||
|
@ -267,7 +272,7 @@ fn expr<'a>(c: &Ctx, p: EPrec, f: &'a Arena<'a>, e: &'a Expr) -> DocBuilder<'a,
|
|||
.append(expr(c, Free, f, &body.value))
|
||||
.group(),
|
||||
Call(fun, args, _) => {
|
||||
let (_, fun, _, _) = &**fun;
|
||||
let (_, fun, _, _, _) = &**fun;
|
||||
maybe_paren!(
|
||||
Free,
|
||||
p,
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::annotation::IntroducedVariables;
|
|||
use crate::annotation::OwnedNamedOrAble;
|
||||
use crate::derive;
|
||||
use crate::env::Env;
|
||||
use crate::env::FxMode;
|
||||
use crate::expr::canonicalize_record;
|
||||
use crate::expr::get_lookup_symbols;
|
||||
use crate::expr::AnnotatedMark;
|
||||
|
@ -69,6 +70,7 @@ pub struct Def {
|
|||
pub expr_var: Variable,
|
||||
pub pattern_vars: SendMap<Symbol, Variable>,
|
||||
pub annotation: Option<Annotation>,
|
||||
pub kind: DefKind,
|
||||
}
|
||||
|
||||
impl Def {
|
||||
|
@ -89,6 +91,38 @@ impl Def {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum DefKind {
|
||||
/// A def that introduces identifiers
|
||||
Let,
|
||||
/// A standalone statement with an fx variable
|
||||
Stmt(Variable),
|
||||
/// Ignored result, must be effectful
|
||||
Ignored(Variable),
|
||||
}
|
||||
|
||||
impl DefKind {
|
||||
pub fn map_var<F: Fn(Variable) -> Variable>(self, f: F) -> Self {
|
||||
match self {
|
||||
DefKind::Let => DefKind::Let,
|
||||
DefKind::Stmt(v) => DefKind::Stmt(f(v)),
|
||||
DefKind::Ignored(v) => DefKind::Ignored(f(v)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_pattern(var_store: &mut VarStore, pattern: &Loc<Pattern>) -> Self {
|
||||
if BindingsFromPattern::new(pattern)
|
||||
.peekable()
|
||||
.peek()
|
||||
.is_none()
|
||||
{
|
||||
DefKind::Ignored(var_store.fresh())
|
||||
} else {
|
||||
DefKind::Let
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Annotation {
|
||||
pub signature: Type,
|
||||
|
@ -127,6 +161,7 @@ impl Annotation {
|
|||
arg_types,
|
||||
Box::new(Type::Variable(var_store.fresh())),
|
||||
Box::new(self.signature.clone()),
|
||||
Box::new(Type::Variable(var_store.fresh())),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -194,22 +229,25 @@ enum PendingValueDef<'a> {
|
|||
Option<Loc<ast::TypeAnnotation<'a>>>,
|
||||
Loc<ast::StrLiteral<'a>>,
|
||||
),
|
||||
/// A standalone statement
|
||||
Stmt(&'a Loc<ast::Expr<'a>>),
|
||||
}
|
||||
|
||||
impl PendingValueDef<'_> {
|
||||
fn loc_pattern(&self) -> &Loc<Pattern> {
|
||||
fn loc_pattern(&self) -> Option<&Loc<Pattern>> {
|
||||
match self {
|
||||
PendingValueDef::AnnotationOnly(loc_pattern, _) => loc_pattern,
|
||||
PendingValueDef::Body(loc_pattern, _) => loc_pattern,
|
||||
PendingValueDef::TypedBody(_, loc_pattern, _, _) => loc_pattern,
|
||||
PendingValueDef::AnnotationOnly(loc_pattern, _) => Some(loc_pattern),
|
||||
PendingValueDef::Body(loc_pattern, _) => Some(loc_pattern),
|
||||
PendingValueDef::TypedBody(_, loc_pattern, _, _) => Some(loc_pattern),
|
||||
PendingValueDef::ImportParams {
|
||||
loc_pattern,
|
||||
symbol: _,
|
||||
variable: _,
|
||||
module_id: _,
|
||||
opt_provided: _,
|
||||
} => loc_pattern,
|
||||
PendingValueDef::IngestedFile(loc_pattern, _, _) => loc_pattern,
|
||||
} => Some(loc_pattern),
|
||||
PendingValueDef::IngestedFile(loc_pattern, _, _) => Some(loc_pattern),
|
||||
PendingValueDef::Stmt(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1181,19 +1219,18 @@ fn canonicalize_value_defs<'a>(
|
|||
}
|
||||
PendingValue::InvalidIngestedFile => { /* skip */ }
|
||||
PendingValue::ImportNameConflict => { /* skip */ }
|
||||
PendingValue::StmtAfterExpr => { /* skip */ }
|
||||
}
|
||||
}
|
||||
|
||||
let mut symbol_to_index: Vec<(IdentId, u32)> = Vec::with_capacity(pending_value_defs.len());
|
||||
|
||||
for (def_index, pending_def) in pending_value_defs.iter().enumerate() {
|
||||
let mut new_bindings = BindingsFromPattern::new(pending_def.loc_pattern()).peekable();
|
||||
let Some(loc_pattern) = pending_def.loc_pattern() else {
|
||||
continue;
|
||||
};
|
||||
|
||||
if new_bindings.peek().is_none() {
|
||||
env.problem(Problem::NoIdentifiersIntroduced(
|
||||
pending_def.loc_pattern().region,
|
||||
));
|
||||
}
|
||||
let new_bindings = BindingsFromPattern::new(loc_pattern).peekable();
|
||||
|
||||
for (s, r) in new_bindings {
|
||||
// store the top-level defs, used to ensure that closures won't capture them
|
||||
|
@ -1230,6 +1267,14 @@ fn canonicalize_value_defs<'a>(
|
|||
|
||||
output = temp_output.output;
|
||||
|
||||
if let (PatternType::TopLevelDef, DefKind::Ignored(_)) =
|
||||
(pattern_type, temp_output.def.kind)
|
||||
{
|
||||
env.problems.push(Problem::NoIdentifiersIntroduced(
|
||||
temp_output.def.loc_pattern.region,
|
||||
))
|
||||
}
|
||||
|
||||
defs.push(Some(temp_output.def));
|
||||
|
||||
def_ordering.insert_symbol_references(def_id as u32, &temp_output.references)
|
||||
|
@ -2215,6 +2260,7 @@ fn single_can_def(
|
|||
expr_var: Variable,
|
||||
opt_loc_annotation: Option<Loc<crate::annotation::Annotation>>,
|
||||
pattern_vars: SendMap<Symbol, Variable>,
|
||||
kind: DefKind,
|
||||
) -> Def {
|
||||
let def_annotation = opt_loc_annotation.map(|loc_annotation| Annotation {
|
||||
signature: loc_annotation.value.typ,
|
||||
|
@ -2232,6 +2278,7 @@ fn single_can_def(
|
|||
},
|
||||
pattern_vars,
|
||||
annotation: def_annotation,
|
||||
kind,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2354,6 +2401,7 @@ fn canonicalize_pending_value_def<'a>(
|
|||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
fx_type: var_store.fresh(),
|
||||
early_returns: scope.early_returns.clone(),
|
||||
name: symbol,
|
||||
captured_symbols: Vec::new(),
|
||||
|
@ -2371,6 +2419,7 @@ fn canonicalize_pending_value_def<'a>(
|
|||
expr_var,
|
||||
Some(Loc::at(loc_ann.region, type_annotation)),
|
||||
vars_by_symbol.clone(),
|
||||
DefKind::Let,
|
||||
);
|
||||
|
||||
DefOutput {
|
||||
|
@ -2406,10 +2455,13 @@ fn canonicalize_pending_value_def<'a>(
|
|||
loc_can_pattern,
|
||||
loc_expr,
|
||||
Some(Loc::at(loc_ann.region, type_annotation)),
|
||||
DefKind::Let,
|
||||
)
|
||||
}
|
||||
Body(loc_can_pattern, loc_expr) => {
|
||||
//
|
||||
let def_kind = DefKind::from_pattern(var_store, &loc_can_pattern);
|
||||
|
||||
canonicalize_pending_body(
|
||||
env,
|
||||
output,
|
||||
|
@ -2418,6 +2470,20 @@ fn canonicalize_pending_value_def<'a>(
|
|||
loc_can_pattern,
|
||||
loc_expr,
|
||||
None,
|
||||
def_kind,
|
||||
)
|
||||
}
|
||||
Stmt(loc_expr) => {
|
||||
let fx_var = var_store.fresh();
|
||||
canonicalize_pending_body(
|
||||
env,
|
||||
output,
|
||||
scope,
|
||||
var_store,
|
||||
Loc::at(loc_expr.region, Pattern::Underscore),
|
||||
loc_expr,
|
||||
None,
|
||||
DefKind::Stmt(fx_var),
|
||||
)
|
||||
}
|
||||
ImportParams {
|
||||
|
@ -2458,6 +2524,7 @@ fn canonicalize_pending_value_def<'a>(
|
|||
var_store.fresh(),
|
||||
None,
|
||||
SendMap::default(),
|
||||
DefKind::Let,
|
||||
);
|
||||
|
||||
DefOutput {
|
||||
|
@ -2527,6 +2594,7 @@ fn canonicalize_pending_value_def<'a>(
|
|||
var_store.fresh(),
|
||||
opt_loc_can_ann,
|
||||
SendMap::default(),
|
||||
DefKind::Let,
|
||||
);
|
||||
|
||||
DefOutput {
|
||||
|
@ -2565,6 +2633,7 @@ fn canonicalize_pending_body<'a>(
|
|||
loc_expr: &'a Loc<ast::Expr>,
|
||||
|
||||
opt_loc_annotation: Option<Loc<crate::annotation::Annotation>>,
|
||||
kind: DefKind,
|
||||
) -> DefOutput {
|
||||
let mut loc_value = &loc_expr.value;
|
||||
|
||||
|
@ -2683,6 +2752,7 @@ fn canonicalize_pending_body<'a>(
|
|||
expr_var,
|
||||
opt_loc_annotation,
|
||||
vars_by_symbol,
|
||||
kind,
|
||||
);
|
||||
|
||||
DefOutput {
|
||||
|
@ -3017,6 +3087,7 @@ enum PendingValue<'a> {
|
|||
SignatureDefMismatch,
|
||||
InvalidIngestedFile,
|
||||
ImportNameConflict,
|
||||
StmtAfterExpr,
|
||||
}
|
||||
|
||||
struct PendingExpectOrDbg<'a> {
|
||||
|
@ -3071,10 +3142,7 @@ fn to_pending_value_def<'a>(
|
|||
loc_pattern.region,
|
||||
);
|
||||
|
||||
PendingValue::Def(PendingValueDef::AnnotationOnly(
|
||||
loc_can_pattern,
|
||||
loc_ann,
|
||||
))
|
||||
PendingValue::Def(PendingValueDef::AnnotationOnly(loc_can_pattern, loc_ann))
|
||||
}
|
||||
Body(loc_pattern, loc_expr) => {
|
||||
// This takes care of checking for shadowing and adding idents to scope.
|
||||
|
@ -3180,15 +3248,17 @@ fn to_pending_value_def<'a>(
|
|||
// Generate a symbol for the module params def
|
||||
// We do this even if params weren't provided so that solve can report if they are missing
|
||||
let params_sym = scope.gen_unique_symbol();
|
||||
let params_region = module_import.params.map(|p| p.params.region).unwrap_or(region);
|
||||
let params_region = module_import
|
||||
.params
|
||||
.map(|p| p.params.region)
|
||||
.unwrap_or(region);
|
||||
let params_var = var_store.fresh();
|
||||
let params =
|
||||
PendingModuleImportParams {
|
||||
symbol: params_sym,
|
||||
variable: params_var,
|
||||
loc_pattern: Loc::at(params_region, Pattern::Identifier(params_sym)),
|
||||
opt_provided: module_import.params.map(|p| p.params.value),
|
||||
};
|
||||
let params = PendingModuleImportParams {
|
||||
symbol: params_sym,
|
||||
variable: params_var,
|
||||
loc_pattern: Loc::at(params_region, Pattern::Identifier(params_sym)),
|
||||
opt_provided: module_import.params.map(|p| p.params.value),
|
||||
};
|
||||
let provided_params = if module_import.params.is_some() {
|
||||
// Only add params to scope if they are provided
|
||||
Some((params_var, params_sym))
|
||||
|
@ -3217,8 +3287,12 @@ fn to_pending_value_def<'a>(
|
|||
.map(|kw| kw.item.items)
|
||||
.unwrap_or_default();
|
||||
|
||||
if exposed_names.is_empty() && !env.home.is_builtin() && module_id.is_automatically_imported() {
|
||||
env.problems.push(Problem::ExplicitBuiltinImport(module_id, region));
|
||||
if exposed_names.is_empty()
|
||||
&& !env.home.is_builtin()
|
||||
&& module_id.is_automatically_imported()
|
||||
{
|
||||
env.problems
|
||||
.push(Problem::ExplicitBuiltinImport(module_id, region));
|
||||
}
|
||||
|
||||
let exposed_ids = env
|
||||
|
@ -3238,7 +3312,9 @@ fn to_pending_value_def<'a>(
|
|||
let symbol = Symbol::new(module_id, ident_id);
|
||||
exposed_symbols.push((symbol, loc_name.region));
|
||||
|
||||
if let Err((_shadowed_symbol, existing_symbol_region)) = scope.import_symbol(ident, symbol, loc_name.region) {
|
||||
if let Err((_shadowed_symbol, existing_symbol_region)) =
|
||||
scope.import_symbol(ident, symbol, loc_name.region)
|
||||
{
|
||||
if symbol.is_automatically_imported() {
|
||||
env.problem(Problem::ExplicitBuiltinTypeImport(
|
||||
symbol,
|
||||
|
@ -3253,14 +3329,12 @@ fn to_pending_value_def<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
None => {
|
||||
env.problem(Problem::RuntimeError(RuntimeError::ValueNotExposed {
|
||||
module_name: module_name.clone(),
|
||||
ident,
|
||||
region: loc_name.region,
|
||||
exposed_values: exposed_ids.exposed_values(),
|
||||
}))
|
||||
}
|
||||
None => env.problem(Problem::RuntimeError(RuntimeError::ValueNotExposed {
|
||||
module_name: module_name.clone(),
|
||||
ident,
|
||||
region: loc_name.region,
|
||||
exposed_values: exposed_ids.exposed_values(),
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3275,12 +3349,12 @@ fn to_pending_value_def<'a>(
|
|||
let loc_name = ingested_file.name.item;
|
||||
|
||||
let symbol = match scope.introduce(loc_name.value.into(), loc_name.region) {
|
||||
Ok(symbol ) => symbol,
|
||||
Ok(symbol) => symbol,
|
||||
Err((original, shadow, _)) => {
|
||||
env.problem(Problem::Shadowing {
|
||||
original_region: original.region,
|
||||
shadow,
|
||||
kind: ShadowKind::Variable
|
||||
kind: ShadowKind::Variable,
|
||||
});
|
||||
|
||||
return PendingValue::InvalidIngestedFile;
|
||||
|
@ -3289,9 +3363,20 @@ fn to_pending_value_def<'a>(
|
|||
|
||||
let loc_pattern = Loc::at(loc_name.region, Pattern::Identifier(symbol));
|
||||
|
||||
PendingValue::Def(PendingValueDef::IngestedFile(loc_pattern, ingested_file.annotation.map(|ann| ann.annotation), ingested_file.path))
|
||||
PendingValue::Def(PendingValueDef::IngestedFile(
|
||||
loc_pattern,
|
||||
ingested_file.annotation.map(|ann| ann.annotation),
|
||||
ingested_file.path,
|
||||
))
|
||||
}
|
||||
StmtAfterExpr => PendingValue::StmtAfterExpr,
|
||||
Stmt(expr) => {
|
||||
if env.fx_mode == FxMode::Task {
|
||||
internal_error!("a Stmt was not desugared correctly, should have been converted to a Body(...) in desguar")
|
||||
}
|
||||
|
||||
PendingValue::Def(PendingValueDef::Stmt(expr))
|
||||
}
|
||||
Stmt(_) => internal_error!("a Stmt was not desugared correctly, should have been converted to a Body(...) in desguar"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#![allow(clippy::manual_map)]
|
||||
|
||||
use crate::env::Env;
|
||||
use crate::env::{Env, FxMode};
|
||||
use crate::scope::Scope;
|
||||
use crate::suffixed::{apply_try_function, unwrap_suffixed_expression, EUnwrapped};
|
||||
use bumpalo::collections::Vec;
|
||||
|
@ -11,8 +11,8 @@ use roc_module::called_via::{BinOp, CalledVia};
|
|||
use roc_module::ident::ModuleName;
|
||||
use roc_parse::ast::Expr::{self, *};
|
||||
use roc_parse::ast::{
|
||||
AssignedField, Collection, Defs, ModuleImportParams, Pattern, StrLiteral, StrSegment,
|
||||
TypeAnnotation, ValueDef, WhenBranch,
|
||||
is_expr_suffixed, AssignedField, Collection, Defs, ModuleImportParams, Pattern, StrLiteral,
|
||||
StrSegment, TypeAnnotation, ValueDef, WhenBranch,
|
||||
};
|
||||
use roc_problem::can::Problem;
|
||||
use roc_region::all::{Loc, Region};
|
||||
|
@ -200,11 +200,29 @@ fn desugar_value_def<'a>(
|
|||
}
|
||||
IngestedFileImport(_) => *def,
|
||||
|
||||
StmtAfterExpr => internal_error!(
|
||||
"StmtAfterExpression is only created during desugaring, so it shouldn't exist here."
|
||||
),
|
||||
|
||||
Stmt(stmt_expr) => {
|
||||
if env.fx_mode == FxMode::PurityInference {
|
||||
// In purity inference mode, statements aren't fully desugared here
|
||||
// so we can provide better errors
|
||||
return Stmt(desugar_expr(env, scope, stmt_expr));
|
||||
}
|
||||
|
||||
// desugar `stmt_expr!` to
|
||||
// _ : {}
|
||||
// _ = stmt_expr!
|
||||
|
||||
let desugared_expr = desugar_expr(env, scope, stmt_expr);
|
||||
|
||||
if !is_expr_suffixed(&desugared_expr.value) {
|
||||
env.problems.push(Problem::StmtAfterExpr(stmt_expr.region));
|
||||
|
||||
return ValueDef::StmtAfterExpr;
|
||||
}
|
||||
|
||||
let region = stmt_expr.region;
|
||||
let new_pat = env
|
||||
.arena
|
||||
|
@ -221,7 +239,7 @@ fn desugar_value_def<'a>(
|
|||
)),
|
||||
lines_between: &[],
|
||||
body_pattern: new_pat,
|
||||
body_expr: desugar_expr(env, scope, stmt_expr),
|
||||
body_expr: desugared_expr,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -364,7 +382,7 @@ pub fn desugar_value_def_suffixed<'a>(arena: &'a Bump, value_def: ValueDef<'a>)
|
|||
|
||||
// TODO support desugaring of Dbg and ExpectFx
|
||||
Dbg { .. } | ExpectFx { .. } => value_def,
|
||||
ModuleImport { .. } | IngestedFileImport(_) => value_def,
|
||||
ModuleImport { .. } | IngestedFileImport(_) | StmtAfterExpr => value_def,
|
||||
|
||||
Stmt(..) => {
|
||||
internal_error!(
|
||||
|
@ -387,7 +405,6 @@ pub fn desugar_expr<'a>(
|
|||
| NonBase10Int { .. }
|
||||
| SingleQuote(_)
|
||||
| AccessorFunction(_)
|
||||
| Var { .. }
|
||||
| Underscore { .. }
|
||||
| MalformedIdent(_, _)
|
||||
| MalformedClosure
|
||||
|
@ -401,6 +418,23 @@ pub fn desugar_expr<'a>(
|
|||
| Crash
|
||||
| Try => loc_expr,
|
||||
|
||||
Var { module_name, ident } => {
|
||||
if env.fx_mode == FxMode::Task && ident.ends_with('!') {
|
||||
env.arena.alloc(Loc::at(
|
||||
Region::new(loc_expr.region.start(), loc_expr.region.end().sub(1)),
|
||||
TrySuffix {
|
||||
expr: env.arena.alloc(Var {
|
||||
module_name,
|
||||
ident: ident.trim_end_matches('!'),
|
||||
}),
|
||||
target: roc_parse::ast::TryTarget::Task,
|
||||
},
|
||||
))
|
||||
} else {
|
||||
loc_expr
|
||||
}
|
||||
}
|
||||
|
||||
Str(str_literal) => match str_literal {
|
||||
StrLiteral::PlainLine(_) => loc_expr,
|
||||
StrLiteral::Line(segments) => {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::def::Def;
|
||||
use crate::def::{Def, DefKind};
|
||||
use crate::expr::{AnnotatedMark, ClosureData, Expr, Recursive};
|
||||
use crate::pattern::Pattern;
|
||||
use crate::scope::Scope;
|
||||
|
@ -33,7 +33,7 @@ pub fn build_host_exposed_def(
|
|||
|
||||
let def_body = {
|
||||
match typ.shallow_structural_dealias() {
|
||||
Type::Function(args, _, _) => {
|
||||
Type::Function(args, _, _, fx) if **fx == Type::Pure => {
|
||||
for i in 0..args.len() {
|
||||
let name = format!("closure_arg_{ident}_{i}");
|
||||
|
||||
|
@ -72,6 +72,7 @@ pub fn build_host_exposed_def(
|
|||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
fx_type: var_store.fresh(),
|
||||
early_returns: vec![],
|
||||
name: task_closure_symbol,
|
||||
captured_symbols,
|
||||
|
@ -99,6 +100,7 @@ pub fn build_host_exposed_def(
|
|||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
fx_type: var_store.fresh(),
|
||||
early_returns: vec![],
|
||||
name: symbol,
|
||||
captured_symbols: std::vec::Vec::new(),
|
||||
|
@ -107,6 +109,47 @@ pub fn build_host_exposed_def(
|
|||
loc_body: Box::new(Loc::at_zero(body)),
|
||||
})
|
||||
}
|
||||
Type::Function(args, _, _, fx) if **fx == Type::Effectful => {
|
||||
for i in 0..args.len() {
|
||||
let name = format!("{ident}_arg_{i}");
|
||||
|
||||
let arg_symbol = {
|
||||
let ident = name.clone().into();
|
||||
scope.introduce(ident, Region::zero()).unwrap()
|
||||
};
|
||||
|
||||
let arg_var = var_store.fresh();
|
||||
|
||||
arguments.push((
|
||||
arg_var,
|
||||
AnnotatedMark::new(var_store),
|
||||
Loc::at_zero(Pattern::Identifier(arg_symbol)),
|
||||
));
|
||||
|
||||
linked_symbol_arguments.push((arg_var, Expr::Var(arg_symbol, arg_var)));
|
||||
}
|
||||
|
||||
let ident_without_bang = ident.trim_end_matches('!');
|
||||
let foreign_symbol_name = format!("roc_fx_{ident_without_bang}");
|
||||
let foreign_call = Expr::ForeignCall {
|
||||
foreign_symbol: foreign_symbol_name.into(),
|
||||
args: linked_symbol_arguments,
|
||||
ret_var: var_store.fresh(),
|
||||
};
|
||||
|
||||
Expr::Closure(ClosureData {
|
||||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
fx_type: var_store.fresh(),
|
||||
early_returns: vec![],
|
||||
name: symbol,
|
||||
captured_symbols: std::vec::Vec::new(),
|
||||
recursive: Recursive::NotRecursive,
|
||||
arguments,
|
||||
loc_body: Box::new(Loc::at_zero(foreign_call)),
|
||||
})
|
||||
}
|
||||
_ => {
|
||||
// not a function
|
||||
|
||||
|
@ -128,6 +171,7 @@ pub fn build_host_exposed_def(
|
|||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
fx_type: var_store.fresh(),
|
||||
early_returns: vec![],
|
||||
name: task_closure_symbol,
|
||||
captured_symbols,
|
||||
|
@ -167,6 +211,7 @@ pub fn build_host_exposed_def(
|
|||
expr_var,
|
||||
pattern_vars,
|
||||
annotation: Some(def_annotation),
|
||||
kind: DefKind::Let,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,11 +223,13 @@ fn build_fresh_opaque_variables(
|
|||
let ok_var = var_store.fresh();
|
||||
let err_var = var_store.fresh();
|
||||
let result_var = var_store.fresh();
|
||||
let fx_var = var_store.fresh();
|
||||
|
||||
let actual = Type::Function(
|
||||
vec![Type::EmptyRec],
|
||||
Box::new(Type::Variable(closure_var)),
|
||||
Box::new(Type::Variable(result_var)),
|
||||
Box::new(Type::Variable(fx_var)),
|
||||
);
|
||||
|
||||
let type_arguments = vec![
|
|
@ -45,6 +45,8 @@ pub struct Env<'a> {
|
|||
|
||||
pub opt_shorthand: Option<&'a str>,
|
||||
|
||||
pub fx_mode: FxMode,
|
||||
|
||||
pub src: &'a str,
|
||||
|
||||
/// Lazily calculated line info. This data is only needed if the code contains calls to `dbg`,
|
||||
|
@ -54,6 +56,7 @@ pub struct Env<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Env<'a> {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
arena: &'a Bump,
|
||||
src: &'a str,
|
||||
|
@ -62,6 +65,7 @@ impl<'a> Env<'a> {
|
|||
dep_idents: &'a IdentIdsByModule,
|
||||
qualified_module_ids: &'a PackageModuleIds<'a>,
|
||||
opt_shorthand: Option<&'a str>,
|
||||
fx_mode: FxMode,
|
||||
) -> Env<'a> {
|
||||
Env {
|
||||
arena,
|
||||
|
@ -79,6 +83,7 @@ impl<'a> Env<'a> {
|
|||
home_params_record: None,
|
||||
opt_shorthand,
|
||||
line_info: arena.alloc(None),
|
||||
fx_mode,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -237,3 +242,9 @@ impl<'a> Env<'a> {
|
|||
self.line_info.as_ref().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum FxMode {
|
||||
PurityInference,
|
||||
Task,
|
||||
}
|
||||
|
|
|
@ -141,7 +141,9 @@ fn index_var(
|
|||
| Content::RigidAbleVar(_, _)
|
||||
| Content::LambdaSet(_)
|
||||
| Content::ErasedLambda
|
||||
| Content::RangedNumber(..) => return Err(TypeError),
|
||||
| Content::RangedNumber(..)
|
||||
| Content::Pure
|
||||
| Content::Effectful => return Err(TypeError),
|
||||
Content::Error => return Err(TypeError),
|
||||
Content::RecursionVar {
|
||||
structure,
|
||||
|
@ -150,7 +152,8 @@ fn index_var(
|
|||
var = *structure;
|
||||
}
|
||||
Content::Structure(structure) => match structure {
|
||||
FlatType::Func(_, _, _) => return Err(TypeError),
|
||||
FlatType::Func(_, _, _, _) => return Err(TypeError),
|
||||
FlatType::EffectfulFunc => return Err(TypeError),
|
||||
FlatType::Apply(Symbol::LIST_LIST, args) => {
|
||||
match (subs.get_subs_slice(*args), ctor) {
|
||||
([elem_var], IndexCtor::List) => {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::abilities::SpecializationId;
|
||||
use crate::annotation::{freshen_opaque_def, IntroducedVariables};
|
||||
use crate::builtins::builtin_defs_map;
|
||||
use crate::def::{can_defs_with_return, Annotation, Def};
|
||||
use crate::def::{can_defs_with_return, Annotation, Def, DefKind};
|
||||
use crate::env::Env;
|
||||
use crate::num::{
|
||||
finish_parsing_base, finish_parsing_float, finish_parsing_num, float_expr_from_result,
|
||||
|
@ -155,7 +155,7 @@ pub enum Expr {
|
|||
/// This is *only* for calling functions, not for tag application.
|
||||
/// The Tag variant contains any applied values inside it.
|
||||
Call(
|
||||
Box<(Variable, Loc<Expr>, Variable, Variable)>,
|
||||
Box<(Variable, Loc<Expr>, Variable, Variable, Variable)>,
|
||||
Vec<(Variable, Loc<Expr>)>,
|
||||
CalledVia,
|
||||
),
|
||||
|
@ -407,6 +407,7 @@ pub struct ClosureData {
|
|||
pub function_type: Variable,
|
||||
pub closure_type: Variable,
|
||||
pub return_type: Variable,
|
||||
pub fx_type: Variable,
|
||||
pub early_returns: Vec<(Variable, Region)>,
|
||||
pub name: Symbol,
|
||||
pub captured_symbols: Vec<(Symbol, Variable)>,
|
||||
|
@ -484,6 +485,7 @@ impl StructAccessorData {
|
|||
function_type: function_var,
|
||||
closure_type: closure_var,
|
||||
return_type: field_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -558,6 +560,7 @@ impl OpaqueWrapFunctionData {
|
|||
function_type: function_var,
|
||||
closure_type: closure_var,
|
||||
return_type: opaque_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: function_name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -927,6 +930,7 @@ pub fn canonicalize_expr<'a>(
|
|||
fn_expr,
|
||||
var_store.fresh(),
|
||||
var_store.fresh(),
|
||||
var_store.fresh(),
|
||||
)),
|
||||
args,
|
||||
*application_style,
|
||||
|
@ -966,6 +970,7 @@ pub fn canonicalize_expr<'a>(
|
|||
fn_expr,
|
||||
var_store.fresh(),
|
||||
var_store.fresh(),
|
||||
var_store.fresh(),
|
||||
)),
|
||||
args,
|
||||
*application_style,
|
||||
|
@ -1687,6 +1692,7 @@ fn canonicalize_closure_body<'a>(
|
|||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: return_type_var,
|
||||
fx_type: var_store.fresh(),
|
||||
early_returns: scope.early_returns.clone(),
|
||||
name: symbol,
|
||||
captured_symbols,
|
||||
|
@ -2282,6 +2288,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
expr_var: def.expr_var,
|
||||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
kind: def.kind,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -2303,6 +2310,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
expr_var: def.expr_var,
|
||||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
kind: def.kind,
|
||||
};
|
||||
|
||||
let loc_expr = Loc {
|
||||
|
@ -2317,6 +2325,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
function_type,
|
||||
closure_type,
|
||||
return_type,
|
||||
fx_type,
|
||||
early_returns,
|
||||
recursive,
|
||||
name,
|
||||
|
@ -2334,6 +2343,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
function_type,
|
||||
closure_type,
|
||||
return_type,
|
||||
fx_type,
|
||||
early_returns,
|
||||
recursive,
|
||||
name,
|
||||
|
@ -2442,10 +2452,11 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
}
|
||||
|
||||
Call(boxed_tuple, args, called_via) => {
|
||||
let (fn_var, loc_expr, closure_var, expr_var) = *boxed_tuple;
|
||||
let (fn_var, loc_expr, closure_var, expr_var, fx_var) = *boxed_tuple;
|
||||
|
||||
match loc_expr.value {
|
||||
Var(symbol, _) if symbol.is_builtin() => {
|
||||
// NOTE: This assumes builtins are not effectful!
|
||||
match builtin_defs_map(symbol, var_store) {
|
||||
Some(Def {
|
||||
loc_expr:
|
||||
|
@ -2489,6 +2500,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
expr_var,
|
||||
pattern_vars,
|
||||
annotation: None,
|
||||
kind: DefKind::Let,
|
||||
};
|
||||
|
||||
loc_answer = Loc {
|
||||
|
@ -2513,7 +2525,7 @@ pub fn inline_calls(var_store: &mut VarStore, expr: Expr) -> Expr {
|
|||
_ => {
|
||||
// For now, we only inline calls to builtins. Leave this alone!
|
||||
Call(
|
||||
Box::new((fn_var, loc_expr, closure_var, expr_var)),
|
||||
Box::new((fn_var, loc_expr, closure_var, expr_var, fx_var)),
|
||||
args,
|
||||
called_via,
|
||||
)
|
||||
|
@ -2781,6 +2793,7 @@ fn desugar_str_segments(var_store: &mut VarStore, segments: Vec<StrSegment>) ->
|
|||
fn_expr,
|
||||
var_store.fresh(),
|
||||
var_store.fresh(),
|
||||
var_store.fresh(),
|
||||
)),
|
||||
vec![
|
||||
(var_store.fresh(), empty_string),
|
||||
|
@ -2817,6 +2830,7 @@ fn desugar_str_segments(var_store: &mut VarStore, segments: Vec<StrSegment>) ->
|
|||
fn_expr,
|
||||
var_store.fresh(),
|
||||
var_store.fresh(),
|
||||
var_store.fresh(),
|
||||
)),
|
||||
vec![
|
||||
(var_store.fresh(), loc_new_expr),
|
||||
|
@ -2910,6 +2924,7 @@ impl Declarations {
|
|||
let function_def = FunctionDef {
|
||||
closure_type: loc_closure_data.value.closure_type,
|
||||
return_type: loc_closure_data.value.return_type,
|
||||
fx_type: loc_closure_data.value.fx_type,
|
||||
early_returns: loc_closure_data.value.early_returns,
|
||||
captured_symbols: loc_closure_data.value.captured_symbols,
|
||||
arguments: loc_closure_data.value.arguments,
|
||||
|
@ -2962,6 +2977,7 @@ impl Declarations {
|
|||
let function_def = FunctionDef {
|
||||
closure_type: loc_closure_data.value.closure_type,
|
||||
return_type: loc_closure_data.value.return_type,
|
||||
fx_type: loc_closure_data.value.fx_type,
|
||||
early_returns: loc_closure_data.value.early_returns,
|
||||
captured_symbols: loc_closure_data.value.captured_symbols,
|
||||
arguments: loc_closure_data.value.arguments,
|
||||
|
@ -3143,6 +3159,7 @@ impl Declarations {
|
|||
let function_def = FunctionDef {
|
||||
closure_type: closure_data.closure_type,
|
||||
return_type: closure_data.return_type,
|
||||
fx_type: closure_data.fx_type,
|
||||
early_returns: closure_data.early_returns,
|
||||
captured_symbols: closure_data.captured_symbols,
|
||||
arguments: closure_data.arguments,
|
||||
|
@ -3184,6 +3201,7 @@ impl Declarations {
|
|||
function_type: var_store.fresh(),
|
||||
closure_type: var_store.fresh(),
|
||||
return_type: var_store.fresh(),
|
||||
fx_type: var_store.fresh(),
|
||||
early_returns: vec![],
|
||||
name: self.symbols[index].value,
|
||||
captured_symbols: vec![],
|
||||
|
@ -3197,6 +3215,7 @@ impl Declarations {
|
|||
let function_def = FunctionDef {
|
||||
closure_type: loc_closure_data.value.closure_type,
|
||||
return_type: loc_closure_data.value.return_type,
|
||||
fx_type: loc_closure_data.value.fx_type,
|
||||
early_returns: loc_closure_data.value.early_returns,
|
||||
captured_symbols: loc_closure_data.value.captured_symbols,
|
||||
arguments: loc_closure_data.value.arguments,
|
||||
|
@ -3332,6 +3351,7 @@ impl DeclarationTag {
|
|||
pub struct FunctionDef {
|
||||
pub closure_type: Variable,
|
||||
pub return_type: Variable,
|
||||
pub fx_type: Variable,
|
||||
pub early_returns: Vec<(Variable, Region)>,
|
||||
pub captured_symbols: Vec<(Symbol, Variable)>,
|
||||
pub arguments: Vec<(Variable, AnnotatedMark, Loc<Pattern>)>,
|
||||
|
|
|
@ -14,6 +14,7 @@ pub mod copy;
|
|||
pub mod def;
|
||||
mod derive;
|
||||
pub mod desugar;
|
||||
pub mod effect_module;
|
||||
pub mod env;
|
||||
pub mod exhaustive;
|
||||
pub mod expected;
|
||||
|
@ -25,7 +26,6 @@ pub mod procedure;
|
|||
pub mod scope;
|
||||
pub mod string;
|
||||
pub mod suffixed;
|
||||
pub mod task_module;
|
||||
pub mod traverse;
|
||||
|
||||
pub use derive::DERIVED_REGION;
|
||||
|
|
|
@ -2,9 +2,9 @@ use std::path::Path;
|
|||
|
||||
use crate::abilities::{AbilitiesStore, ImplKey, PendingAbilitiesStore, ResolvedImpl};
|
||||
use crate::annotation::{canonicalize_annotation, AnnotationFor};
|
||||
use crate::def::{canonicalize_defs, report_unused_imports, Def};
|
||||
use crate::def::{canonicalize_defs, report_unused_imports, Def, DefKind};
|
||||
use crate::desugar::desugar_record_destructures;
|
||||
use crate::env::Env;
|
||||
use crate::env::{Env, FxMode};
|
||||
use crate::expr::{
|
||||
ClosureData, DbgLookup, Declarations, ExpectLookup, Expr, Output, PendingDerives,
|
||||
};
|
||||
|
@ -226,6 +226,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
symbols_from_requires: &[(Loc<Symbol>, Loc<TypeAnnotation<'a>>)],
|
||||
var_store: &mut VarStore,
|
||||
opt_shorthand: Option<&'a str>,
|
||||
fx_mode: FxMode,
|
||||
) -> ModuleOutput {
|
||||
let mut can_exposed_imports = MutMap::default();
|
||||
|
||||
|
@ -247,6 +248,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
dep_idents,
|
||||
qualified_module_ids,
|
||||
opt_shorthand,
|
||||
fx_mode,
|
||||
);
|
||||
|
||||
for (name, alias) in aliases.into_iter() {
|
||||
|
@ -533,7 +535,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
aliases: Default::default(),
|
||||
};
|
||||
|
||||
let hosted_def = crate::task_module::build_host_exposed_def(
|
||||
let hosted_def = crate::effect_module::build_host_exposed_def(
|
||||
&mut scope, *symbol, &ident, var_store, annotation,
|
||||
);
|
||||
|
||||
|
@ -586,7 +588,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
aliases: Default::default(),
|
||||
};
|
||||
|
||||
let hosted_def = crate::task_module::build_host_exposed_def(
|
||||
let hosted_def = crate::effect_module::build_host_exposed_def(
|
||||
&mut scope, *symbol, &ident, var_store, annotation,
|
||||
);
|
||||
|
||||
|
@ -655,6 +657,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
expr_var: var_store.fresh(),
|
||||
pattern_vars,
|
||||
annotation: None,
|
||||
kind: DefKind::Let,
|
||||
};
|
||||
|
||||
declarations.push_def(def);
|
||||
|
|
|
@ -683,6 +683,7 @@ pub fn unwrap_suffixed_expression_defs_help<'a>(
|
|||
Annotation(..) | Dbg{..} | Expect{..} | ExpectFx{..} | Stmt(..) | ModuleImport{..} | IngestedFileImport(_) => None,
|
||||
AnnotatedBody { body_pattern, body_expr, ann_type, ann_pattern, .. } => Some((body_pattern, body_expr, Some((ann_pattern, ann_type)))),
|
||||
Body (def_pattern, def_expr) => Some((def_pattern, def_expr, None)),
|
||||
StmtAfterExpr => None,
|
||||
};
|
||||
|
||||
match maybe_suffixed_value_def {
|
||||
|
|
|
@ -292,7 +292,7 @@ pub fn walk_expr<V: Visitor>(visitor: &mut V, expr: &Expr, var: Variable) {
|
|||
visitor.visit_expr(&body.value, body.region, var);
|
||||
}
|
||||
Expr::Call(f, args, _called_via) => {
|
||||
let (fn_var, loc_fn, _closure_var, _ret_var) = &**f;
|
||||
let (fn_var, loc_fn, _closure_var, _ret_var, _fx_var) = &**f;
|
||||
walk_call(visitor, *fn_var, loc_fn, args);
|
||||
}
|
||||
Expr::Crash { msg, .. } => {
|
||||
|
|
|
@ -62,6 +62,7 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
&dep_idents,
|
||||
&qualified_module_ids,
|
||||
None,
|
||||
roc_can::env::FxMode::PurityInference,
|
||||
);
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
|
|
|
@ -24,19 +24,19 @@ Defs {
|
|||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@11-15 Apply(
|
||||
@11-15 Var {
|
||||
@11-14 Apply(
|
||||
@11-14 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@11-15 Defs(
|
||||
@11-14 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@11-15,
|
||||
@11-14,
|
||||
],
|
||||
space_before: [
|
||||
Slice { start: 0, length: 0 },
|
||||
|
@ -66,19 +66,19 @@ Defs {
|
|||
body_pattern: @11-15 Identifier {
|
||||
ident: "#!0_stmt",
|
||||
},
|
||||
body_expr: @11-15 Var {
|
||||
body_expr: @11-14 Var {
|
||||
module_name: "",
|
||||
ident: "foo",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@11-15 Var {
|
||||
@11-14 Var {
|
||||
module_name: "",
|
||||
ident: "#!0_stmt",
|
||||
},
|
||||
),
|
||||
@11-15 Closure(
|
||||
@11-14 Closure(
|
||||
[
|
||||
@11-15 Underscore(
|
||||
"#!stmt",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
expression: snapshot
|
||||
snapshot_kind: text
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
|
@ -51,19 +52,19 @@ Defs {
|
|||
ident: "msg",
|
||||
},
|
||||
],
|
||||
@31-42 Apply(
|
||||
@31-42 Var {
|
||||
@31-43 Apply(
|
||||
@31-43 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@31-42 Defs(
|
||||
@31-43 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@31-42,
|
||||
@31-43,
|
||||
],
|
||||
space_before: [
|
||||
Slice { start: 0, length: 0 },
|
||||
|
@ -93,8 +94,8 @@ Defs {
|
|||
body_pattern: @31-43 Identifier {
|
||||
ident: "#!0_stmt",
|
||||
},
|
||||
body_expr: @31-42 Apply(
|
||||
@31-42 Var {
|
||||
body_expr: @31-43 Apply(
|
||||
@31-43 Var {
|
||||
module_name: "",
|
||||
ident: "line",
|
||||
},
|
||||
|
@ -111,12 +112,12 @@ Defs {
|
|||
},
|
||||
],
|
||||
},
|
||||
@31-42 Var {
|
||||
@31-43 Var {
|
||||
module_name: "",
|
||||
ident: "#!0_stmt",
|
||||
},
|
||||
),
|
||||
@31-42 Closure(
|
||||
@31-43 Closure(
|
||||
[
|
||||
@31-43 Underscore(
|
||||
"#!stmt",
|
||||
|
|
|
@ -53,6 +53,7 @@ Defs {
|
|||
[],
|
||||
),
|
||||
],
|
||||
Pure,
|
||||
@22-30 Apply(
|
||||
"",
|
||||
"Task",
|
||||
|
|
|
@ -62,6 +62,7 @@ Defs {
|
|||
[],
|
||||
),
|
||||
],
|
||||
Pure,
|
||||
@34-45 Apply(
|
||||
"",
|
||||
"Task",
|
||||
|
|
|
@ -24,17 +24,17 @@ Defs {
|
|||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@17-24 Apply(
|
||||
@17-24 Var {
|
||||
@17-23 Apply(
|
||||
@17-23 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@17-24 Var {
|
||||
@17-23 Var {
|
||||
module_name: "",
|
||||
ident: "getFoo",
|
||||
},
|
||||
@17-24 Closure(
|
||||
@17-23 Closure(
|
||||
[
|
||||
@11-14 Identifier {
|
||||
ident: "foo",
|
||||
|
|
|
@ -30,28 +30,28 @@ Defs {
|
|||
ident: "await",
|
||||
},
|
||||
[
|
||||
@15-17 Var {
|
||||
@15-16 Var {
|
||||
module_name: "",
|
||||
ident: "a",
|
||||
},
|
||||
@11-17 Closure(
|
||||
[
|
||||
@15-17 Identifier {
|
||||
@15-16 Identifier {
|
||||
ident: "#!0_arg",
|
||||
},
|
||||
],
|
||||
@11-17 LowLevelDbg(
|
||||
(
|
||||
"test.roc:2",
|
||||
"in",
|
||||
"i",
|
||||
),
|
||||
@15-17 Apply(
|
||||
@15-17 Var {
|
||||
@15-16 Apply(
|
||||
@15-16 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@15-17 Var {
|
||||
@15-16 Var {
|
||||
module_name: "",
|
||||
ident: "#!0_arg",
|
||||
},
|
||||
|
|
|
@ -48,7 +48,7 @@ Defs {
|
|||
"1",
|
||||
),
|
||||
],
|
||||
value: @97-99 Var {
|
||||
value: @97-98 Var {
|
||||
module_name: "",
|
||||
ident: "c",
|
||||
},
|
||||
|
|
|
@ -128,7 +128,7 @@ Defs {
|
|||
"#!stmt",
|
||||
),
|
||||
],
|
||||
@45-54 Var {
|
||||
@45-53 Var {
|
||||
module_name: "",
|
||||
ident: "printBar",
|
||||
},
|
||||
|
|
|
@ -70,13 +70,13 @@ Defs {
|
|||
module_name: "",
|
||||
ident: "a",
|
||||
},
|
||||
@92-94 Var {
|
||||
@92-93 Var {
|
||||
module_name: "",
|
||||
ident: "b",
|
||||
},
|
||||
),
|
||||
],
|
||||
final_else: @128-130 Var {
|
||||
final_else: @128-129 Var {
|
||||
module_name: "",
|
||||
ident: "c",
|
||||
},
|
||||
|
@ -91,7 +91,7 @@ Defs {
|
|||
"B",
|
||||
),
|
||||
],
|
||||
value: @156-158 Var {
|
||||
value: @156-157 Var {
|
||||
module_name: "",
|
||||
ident: "d",
|
||||
},
|
||||
|
|
|
@ -63,7 +63,7 @@ Defs {
|
|||
},
|
||||
],
|
||||
},
|
||||
@29-31 Var {
|
||||
@29-30 Var {
|
||||
module_name: "",
|
||||
ident: "x",
|
||||
},
|
||||
|
|
|
@ -85,26 +85,26 @@ Defs {
|
|||
),
|
||||
],
|
||||
},
|
||||
@79-87 Apply(
|
||||
@79-87 Var {
|
||||
@79-86 Apply(
|
||||
@79-86 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@79-87 Var {
|
||||
@79-86 Var {
|
||||
module_name: "",
|
||||
ident: "isFalse",
|
||||
},
|
||||
@79-87 Closure(
|
||||
@79-86 Closure(
|
||||
[
|
||||
@79-87 Identifier {
|
||||
@79-86 Identifier {
|
||||
ident: "#!0_arg",
|
||||
},
|
||||
],
|
||||
@76-189 If {
|
||||
if_thens: [
|
||||
(
|
||||
@79-87 Var {
|
||||
@79-86 Var {
|
||||
module_name: "",
|
||||
ident: "#!0_arg",
|
||||
},
|
||||
|
@ -124,26 +124,26 @@ Defs {
|
|||
),
|
||||
),
|
||||
],
|
||||
final_else: @125-132 Apply(
|
||||
@125-132 Var {
|
||||
final_else: @125-131 Apply(
|
||||
@125-131 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@125-132 Var {
|
||||
@125-131 Var {
|
||||
module_name: "",
|
||||
ident: "isTrue",
|
||||
},
|
||||
@125-132 Closure(
|
||||
@125-131 Closure(
|
||||
[
|
||||
@125-132 Identifier {
|
||||
@125-131 Identifier {
|
||||
ident: "#!1_arg",
|
||||
},
|
||||
],
|
||||
@76-189 If {
|
||||
if_thens: [
|
||||
(
|
||||
@125-132 Var {
|
||||
@125-131 Var {
|
||||
module_name: "",
|
||||
ident: "#!1_arg",
|
||||
},
|
||||
|
|
|
@ -24,19 +24,19 @@ Defs {
|
|||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@11-15 Apply(
|
||||
@11-15 Var {
|
||||
@11-14 Apply(
|
||||
@11-14 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@11-15 Defs(
|
||||
@11-14 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@11-15,
|
||||
@11-14,
|
||||
],
|
||||
space_before: [
|
||||
Slice { start: 0, length: 0 },
|
||||
|
@ -66,37 +66,37 @@ Defs {
|
|||
body_pattern: @11-15 Identifier {
|
||||
ident: "#!2_stmt",
|
||||
},
|
||||
body_expr: @11-15 Var {
|
||||
body_expr: @11-14 Var {
|
||||
module_name: "",
|
||||
ident: "foo",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@11-15 Var {
|
||||
@11-14 Var {
|
||||
module_name: "",
|
||||
ident: "#!2_stmt",
|
||||
},
|
||||
),
|
||||
@11-15 Closure(
|
||||
@11-14 Closure(
|
||||
[
|
||||
@11-15 Underscore(
|
||||
"#!stmt",
|
||||
),
|
||||
],
|
||||
@20-24 Apply(
|
||||
@20-24 Var {
|
||||
@20-23 Apply(
|
||||
@20-23 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@20-24 Defs(
|
||||
@20-23 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@20-24,
|
||||
@20-23,
|
||||
],
|
||||
space_before: [
|
||||
Slice { start: 0, length: 0 },
|
||||
|
@ -126,25 +126,25 @@ Defs {
|
|||
body_pattern: @20-24 Identifier {
|
||||
ident: "#!1_stmt",
|
||||
},
|
||||
body_expr: @20-24 Var {
|
||||
body_expr: @20-23 Var {
|
||||
module_name: "",
|
||||
ident: "bar",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@20-24 Var {
|
||||
@20-23 Var {
|
||||
module_name: "",
|
||||
ident: "#!1_stmt",
|
||||
},
|
||||
),
|
||||
@20-24 Closure(
|
||||
@20-23 Closure(
|
||||
[
|
||||
@20-24 Underscore(
|
||||
"#!stmt",
|
||||
),
|
||||
],
|
||||
@29-33 Var {
|
||||
@29-32 Var {
|
||||
module_name: "",
|
||||
ident: "baz",
|
||||
},
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
expression: snapshot
|
||||
snapshot_kind: text
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
|
@ -94,14 +95,14 @@ Defs {
|
|||
"#!stmt",
|
||||
),
|
||||
],
|
||||
@33-55 Apply(
|
||||
@33-55 Var {
|
||||
@33-56 Apply(
|
||||
@33-56 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@33-55 Apply(
|
||||
@33-55 Var {
|
||||
@33-56 Apply(
|
||||
@33-56 Var {
|
||||
module_name: "Stdout",
|
||||
ident: "line",
|
||||
},
|
||||
|
@ -116,7 +117,7 @@ Defs {
|
|||
Pizza,
|
||||
),
|
||||
),
|
||||
@33-55 Closure(
|
||||
@33-56 Closure(
|
||||
[
|
||||
@28-30 RecordDestructure(
|
||||
[],
|
||||
|
|
|
@ -45,17 +45,17 @@ Defs {
|
|||
@11-12 Identifier {
|
||||
ident: "x",
|
||||
},
|
||||
@27-29 Apply(
|
||||
@27-29 Var {
|
||||
@27-28 Apply(
|
||||
@27-28 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@27-29 Var {
|
||||
@27-28 Var {
|
||||
module_name: "",
|
||||
ident: "b",
|
||||
},
|
||||
@27-29 Closure(
|
||||
@27-28 Closure(
|
||||
[
|
||||
@23-24 Identifier {
|
||||
ident: "a",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
expression: snapshot
|
||||
snapshot_kind: text
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
|
@ -24,19 +25,19 @@ Defs {
|
|||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@11-56 Apply(
|
||||
@11-56 Var {
|
||||
@11-57 Apply(
|
||||
@11-57 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@11-56 Defs(
|
||||
@11-57 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@11-56,
|
||||
@11-57,
|
||||
],
|
||||
space_before: [
|
||||
Slice { start: 0, length: 0 },
|
||||
|
@ -66,8 +67,8 @@ Defs {
|
|||
body_pattern: @11-57 Identifier {
|
||||
ident: "#!0_stmt",
|
||||
},
|
||||
body_expr: @11-56 Apply(
|
||||
@11-56 Var {
|
||||
body_expr: @11-57 Apply(
|
||||
@11-57 Var {
|
||||
module_name: "",
|
||||
ident: "line",
|
||||
},
|
||||
|
@ -101,12 +102,12 @@ Defs {
|
|||
},
|
||||
],
|
||||
},
|
||||
@11-56 Var {
|
||||
@11-57 Var {
|
||||
module_name: "",
|
||||
ident: "#!0_stmt",
|
||||
},
|
||||
),
|
||||
@11-56 Closure(
|
||||
@11-57 Closure(
|
||||
[
|
||||
@11-57 Underscore(
|
||||
"#!stmt",
|
||||
|
|
|
@ -24,17 +24,17 @@ Defs {
|
|||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@20-31 Apply(
|
||||
@20-31 Var {
|
||||
@20-30 Apply(
|
||||
@20-30 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@20-31 Var {
|
||||
@20-30 Var {
|
||||
module_name: "Stdin",
|
||||
ident: "line",
|
||||
},
|
||||
@20-31 Closure(
|
||||
@20-30 Closure(
|
||||
[
|
||||
@11-17 Identifier {
|
||||
ident: "result",
|
||||
|
|
|
@ -30,19 +30,19 @@ Defs {
|
|||
ident: "x",
|
||||
},
|
||||
],
|
||||
@28-30 Apply(
|
||||
@28-30 Var {
|
||||
@28-29 Apply(
|
||||
@28-29 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@14-30 Defs(
|
||||
@14-29 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
EitherIndex(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@28-30,
|
||||
@28-29,
|
||||
],
|
||||
space_before: [
|
||||
Slice { start: 0, length: 0 },
|
||||
|
@ -73,19 +73,19 @@ Defs {
|
|||
body_pattern: @24-25 Identifier {
|
||||
ident: "#!0_expr",
|
||||
},
|
||||
body_expr: @28-30 Var {
|
||||
body_expr: @28-29 Var {
|
||||
module_name: "",
|
||||
ident: "x",
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
@28-30 Var {
|
||||
@28-29 Var {
|
||||
module_name: "",
|
||||
ident: "#!0_expr",
|
||||
},
|
||||
),
|
||||
@28-30 Closure(
|
||||
@28-29 Closure(
|
||||
[
|
||||
@24-25 Identifier {
|
||||
ident: "r",
|
||||
|
|
|
@ -24,24 +24,24 @@ Defs {
|
|||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@15-19 Apply(
|
||||
@15-19 Var {
|
||||
@15-18 Apply(
|
||||
@15-18 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
[
|
||||
@15-19 Var {
|
||||
@15-18 Var {
|
||||
module_name: "",
|
||||
ident: "foo",
|
||||
},
|
||||
@15-19 Closure(
|
||||
@15-18 Closure(
|
||||
[
|
||||
@11-12 Identifier {
|
||||
ident: "a",
|
||||
},
|
||||
],
|
||||
@15-19 Apply(
|
||||
@15-19 Var {
|
||||
@15-18 Apply(
|
||||
@15-18 Var {
|
||||
module_name: "Task",
|
||||
ident: "await",
|
||||
},
|
||||
|
@ -50,7 +50,7 @@ Defs {
|
|||
module_name: "",
|
||||
ident: "bar",
|
||||
},
|
||||
@15-19 Closure(
|
||||
@15-18 Closure(
|
||||
[
|
||||
@28-33 Identifier {
|
||||
ident: "#!0_arg",
|
||||
|
|
|
@ -30,18 +30,18 @@ Defs {
|
|||
ident: "await",
|
||||
},
|
||||
[
|
||||
@16-24 Var {
|
||||
@16-23 Var {
|
||||
module_name: "",
|
||||
ident: "getList",
|
||||
},
|
||||
@11-120 Closure(
|
||||
[
|
||||
@16-24 Identifier {
|
||||
@16-23 Identifier {
|
||||
ident: "#!2_arg",
|
||||
},
|
||||
],
|
||||
@11-120 When(
|
||||
@16-24 Var {
|
||||
@16-23 Var {
|
||||
module_name: "",
|
||||
ident: "#!2_arg",
|
||||
},
|
||||
|
|
|
@ -30,18 +30,18 @@ Defs {
|
|||
ident: "await",
|
||||
},
|
||||
[
|
||||
@16-24 Var {
|
||||
@16-23 Var {
|
||||
module_name: "",
|
||||
ident: "getList",
|
||||
},
|
||||
@11-74 Closure(
|
||||
[
|
||||
@16-24 Identifier {
|
||||
@16-23 Identifier {
|
||||
ident: "#!0_arg",
|
||||
},
|
||||
],
|
||||
@11-74 When(
|
||||
@16-24 Var {
|
||||
@16-23 Var {
|
||||
module_name: "",
|
||||
ident: "#!0_arg",
|
||||
},
|
||||
|
|
|
@ -415,7 +415,7 @@ mod test_can {
|
|||
let arena = Bump::new();
|
||||
let CanExprOut { problems, .. } = can_expr_with(&arena, test_home(), src);
|
||||
|
||||
assert_eq!(problems.len(), 2);
|
||||
assert_eq!(problems.len(), 1);
|
||||
println!("{problems:#?}");
|
||||
assert!(problems.iter().any(|problem| matches!(
|
||||
problem,
|
||||
|
|
|
@ -6,7 +6,7 @@ mod suffixed_tests {
|
|||
use bumpalo::Bump;
|
||||
use insta::assert_snapshot;
|
||||
use roc_can::desugar::desugar_defs_node_values;
|
||||
use roc_can::env::Env;
|
||||
use roc_can::env::{Env, FxMode};
|
||||
use roc_can::scope::Scope;
|
||||
use roc_module::symbol::{IdentIds, ModuleIds, PackageModuleIds};
|
||||
use roc_parse::test_helpers::parse_defs_with;
|
||||
|
@ -34,6 +34,7 @@ mod suffixed_tests {
|
|||
&dep_idents,
|
||||
&qualified_module_ids,
|
||||
None,
|
||||
FxMode::Task,
|
||||
);
|
||||
|
||||
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
|
||||
|
|
|
@ -315,6 +315,7 @@
|
|||
"type": "object",
|
||||
"required": [
|
||||
"arguments",
|
||||
"fx",
|
||||
"lambda_type",
|
||||
"ret",
|
||||
"type"
|
||||
|
@ -326,6 +327,9 @@
|
|||
"$ref": "#/definitions/Variable"
|
||||
}
|
||||
},
|
||||
"fx": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
"lambda_type": {
|
||||
"$ref": "#/definitions/Variable"
|
||||
},
|
||||
|
@ -510,6 +514,20 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"EffectfulFunc"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
@ -528,6 +546,34 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Pure"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Effectful"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
|
|
|
@ -77,6 +77,8 @@ impl AsSchema<Content> for subs::Content {
|
|||
} => B::Recursive(opt_name.as_schema(subs), structure.as_schema(subs)),
|
||||
A::LambdaSet(lambda_set) => lambda_set.as_schema(subs),
|
||||
A::ErasedLambda => B::ErasedLambda(),
|
||||
A::Pure => B::Pure(),
|
||||
A::Effectful => B::Effectful(),
|
||||
A::Structure(flat_type) => flat_type.as_schema(subs),
|
||||
A::Alias(name, type_vars, real_var, kind) => B::Alias(
|
||||
name.as_schema(subs),
|
||||
|
@ -96,10 +98,11 @@ impl AsSchema<Content> for subs::FlatType {
|
|||
subs::FlatType::Apply(symbol, variables) => {
|
||||
Content::Apply(symbol.as_schema(subs), variables.as_schema(subs))
|
||||
}
|
||||
subs::FlatType::Func(arguments, closure, ret) => Content::Function(
|
||||
subs::FlatType::Func(arguments, closure, ret, fx) => Content::Function(
|
||||
arguments.as_schema(subs),
|
||||
closure.as_schema(subs),
|
||||
ret.as_schema(subs),
|
||||
fx.as_schema(subs),
|
||||
),
|
||||
subs::FlatType::Record(fields, ext) => {
|
||||
Content::Record(fields.as_schema(subs), ext.as_schema(subs))
|
||||
|
@ -124,6 +127,7 @@ impl AsSchema<Content> for subs::FlatType {
|
|||
),
|
||||
subs::FlatType::EmptyRecord => Content::EmptyRecord(),
|
||||
subs::FlatType::EmptyTagUnion => Content::EmptyTagUnion(),
|
||||
subs::FlatType::EffectfulFunc => Content::EffectfulFunc(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -73,6 +73,7 @@ impl_content! {
|
|||
arguments: Vec<Variable>,
|
||||
lambda_type: Variable,
|
||||
ret: Variable,
|
||||
fx: Variable,
|
||||
},
|
||||
Record {
|
||||
fields: HashMap<String, RecordField>,
|
||||
|
@ -98,9 +99,12 @@ impl_content! {
|
|||
},
|
||||
EmptyRecord {},
|
||||
EmptyTagUnion {},
|
||||
EffectfulFunc {},
|
||||
RangedNumber {
|
||||
range: NumericRange,
|
||||
},
|
||||
Pure {},
|
||||
Effectful {},
|
||||
Error {},
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,10 @@ use crate::builtins::{
|
|||
use crate::pattern::{constrain_pattern, PatternState};
|
||||
use roc_can::annotation::IntroducedVariables;
|
||||
use roc_can::constraint::{
|
||||
Constraint, Constraints, ExpectedTypeIndex, Generalizable, OpportunisticResolve, TypeOrVar,
|
||||
Constraint, Constraints, ExpectEffectfulReason, ExpectedTypeIndex, FxCallKind, FxExpectation,
|
||||
Generalizable, OpportunisticResolve, TypeOrVar,
|
||||
};
|
||||
use roc_can::def::Def;
|
||||
use roc_can::def::{Def, DefKind};
|
||||
use roc_can::exhaustive::{sketch_pattern_to_rows, sketch_when_branches, ExhaustiveContext};
|
||||
use roc_can::expected::Expected::{self, *};
|
||||
use roc_can::expected::PExpected;
|
||||
|
@ -58,6 +59,30 @@ pub struct Env {
|
|||
pub rigids: MutMap<Lowercase, Variable>,
|
||||
pub resolutions_to_make: Vec<OpportunisticResolve>,
|
||||
pub home: ModuleId,
|
||||
/// The enclosing function's fx var to be unified with inner calls
|
||||
pub fx_expectation: Option<FxExpectation>,
|
||||
}
|
||||
|
||||
impl Env {
|
||||
pub fn with_fx_expectation<F, T>(
|
||||
&mut self,
|
||||
fx_var: Variable,
|
||||
ann_region: Option<Region>,
|
||||
f: F,
|
||||
) -> T
|
||||
where
|
||||
F: FnOnce(&mut Env) -> T,
|
||||
{
|
||||
let prev = self.fx_expectation.take();
|
||||
|
||||
self.fx_expectation = Some(FxExpectation { fx_var, ann_region });
|
||||
|
||||
let result = f(self);
|
||||
|
||||
self.fx_expectation = prev;
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn constrain_untyped_args(
|
||||
|
@ -67,6 +92,7 @@ fn constrain_untyped_args(
|
|||
arguments: &[(Variable, AnnotatedMark, Loc<Pattern>)],
|
||||
closure_type: Type,
|
||||
return_type: Type,
|
||||
fx_type: Type,
|
||||
) -> (Vec<Variable>, PatternState, Type) {
|
||||
let mut vars = Vec::with_capacity(arguments.len());
|
||||
let mut pattern_types = Vec::with_capacity(arguments.len());
|
||||
|
@ -97,8 +123,12 @@ fn constrain_untyped_args(
|
|||
vars.push(*pattern_var);
|
||||
}
|
||||
|
||||
let function_type =
|
||||
Type::Function(pattern_types, Box::new(closure_type), Box::new(return_type));
|
||||
let function_type = Type::Function(
|
||||
pattern_types,
|
||||
Box::new(closure_type),
|
||||
Box::new(return_type),
|
||||
Box::new(fx_type),
|
||||
);
|
||||
|
||||
(vars, pattern_state, function_type)
|
||||
}
|
||||
|
@ -109,10 +139,10 @@ fn constrain_untyped_closure(
|
|||
env: &mut Env,
|
||||
region: Region,
|
||||
expected: ExpectedTypeIndex,
|
||||
|
||||
fn_var: Variable,
|
||||
closure_var: Variable,
|
||||
ret_var: Variable,
|
||||
fx_var: Variable,
|
||||
early_returns: &[(Variable, Region)],
|
||||
arguments: &[(Variable, AnnotatedMark, Loc<Pattern>)],
|
||||
loc_body_expr: &Loc<Expr>,
|
||||
|
@ -122,6 +152,7 @@ fn constrain_untyped_closure(
|
|||
let closure_type = Type::Variable(closure_var);
|
||||
let return_type = Type::Variable(ret_var);
|
||||
let return_type_index = constraints.push_variable(ret_var);
|
||||
let fx_type = Type::Variable(fx_var);
|
||||
let (mut vars, pattern_state, function_type) = constrain_untyped_args(
|
||||
types,
|
||||
constraints,
|
||||
|
@ -129,9 +160,11 @@ fn constrain_untyped_closure(
|
|||
arguments,
|
||||
closure_type,
|
||||
return_type,
|
||||
fx_type,
|
||||
);
|
||||
|
||||
vars.push(ret_var);
|
||||
vars.push(fx_var);
|
||||
vars.push(closure_var);
|
||||
vars.push(fn_var);
|
||||
|
||||
|
@ -141,14 +174,16 @@ fn constrain_untyped_closure(
|
|||
loc_body_expr.region,
|
||||
));
|
||||
|
||||
let ret_constraint = constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
loc_body_expr.region,
|
||||
&loc_body_expr.value,
|
||||
body_type,
|
||||
);
|
||||
let ret_constraint = env.with_fx_expectation(fx_var, None, |env| {
|
||||
constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
loc_body_expr.region,
|
||||
&loc_body_expr.value,
|
||||
body_type,
|
||||
)
|
||||
});
|
||||
|
||||
let mut early_return_constraints = Vec::with_capacity(early_returns.len());
|
||||
for (early_return_variable, early_return_region) in early_returns {
|
||||
|
@ -199,6 +234,7 @@ fn constrain_untyped_closure(
|
|||
ret_constraint,
|
||||
Generalizable(true),
|
||||
),
|
||||
constraints.and_constraint(pattern_state.delayed_fx_suffix_constraints),
|
||||
constraints.equal_types_with_storage(
|
||||
function_type,
|
||||
expected,
|
||||
|
@ -208,6 +244,7 @@ fn constrain_untyped_closure(
|
|||
),
|
||||
early_returns_constraint,
|
||||
closure_constraint,
|
||||
constraints.flex_to_pure(fx_var),
|
||||
];
|
||||
|
||||
constraints.exists_many(vars, cons)
|
||||
|
@ -247,6 +284,10 @@ pub fn constrain_expr(
|
|||
let (field_type, field_con) =
|
||||
constrain_field(types, constraints, env, field_var, loc_field_expr);
|
||||
|
||||
let check_field_con =
|
||||
constraints.fx_record_field_suffix(label.suffix(), field_var, field.region);
|
||||
let field_con = constraints.and_constraint([field_con, check_field_con]);
|
||||
|
||||
field_vars.push(field_var);
|
||||
field_types.insert(label.clone(), RecordField::Required(field_type));
|
||||
|
||||
|
@ -472,7 +513,7 @@ pub fn constrain_expr(
|
|||
}
|
||||
}
|
||||
Call(boxed, loc_args, called_via) => {
|
||||
let (fn_var, loc_fn, closure_var, ret_var) = &**boxed;
|
||||
let (fn_var, loc_fn, closure_var, ret_var, fx_var) = &**boxed;
|
||||
// The expression that evaluates to the function being called, e.g. `foo` in
|
||||
// (foo) bar baz
|
||||
let opt_symbol = if let Var(symbol, _) | AbilityMember(symbol, _, _) = loc_fn.value {
|
||||
|
@ -503,6 +544,9 @@ pub fn constrain_expr(
|
|||
// The function's return type
|
||||
let ret_type = Variable(*ret_var);
|
||||
|
||||
// The function's effect type
|
||||
let fx_type = Variable(*fx_var);
|
||||
|
||||
// type of values captured in the closure
|
||||
let closure_type = Variable(*closure_var);
|
||||
|
||||
|
@ -512,6 +556,7 @@ pub fn constrain_expr(
|
|||
vars.push(*fn_var);
|
||||
vars.push(*ret_var);
|
||||
vars.push(*closure_var);
|
||||
vars.push(*fx_var);
|
||||
|
||||
let mut arg_types = Vec::with_capacity(loc_args.len());
|
||||
let mut arg_cons = Vec::with_capacity(loc_args.len());
|
||||
|
@ -546,7 +591,8 @@ pub fn constrain_expr(
|
|||
let arguments = types.from_old_type_slice(arg_types.iter());
|
||||
let lambda_set = types.from_old_type(&closure_type);
|
||||
let ret = types.from_old_type(&ret_type);
|
||||
let typ = types.function(arguments, lambda_set, ret);
|
||||
let fx = types.from_old_type(&fx_type);
|
||||
let typ = types.function(arguments, lambda_set, ret, fx);
|
||||
constraints.push_type(types, typ)
|
||||
};
|
||||
let expected_fn_type =
|
||||
|
@ -560,7 +606,18 @@ pub fn constrain_expr(
|
|||
fn_con,
|
||||
constraints.equal_types_var(*fn_var, expected_fn_type, category.clone(), fn_region),
|
||||
constraints.and_constraint(arg_cons),
|
||||
constraints.equal_types_var(*ret_var, expected_final_type, category, region),
|
||||
constraints.equal_types_var(
|
||||
*ret_var,
|
||||
expected_final_type,
|
||||
category.clone(),
|
||||
region,
|
||||
),
|
||||
constraints.fx_call(
|
||||
*fx_var,
|
||||
FxCallKind::Call(opt_symbol),
|
||||
region,
|
||||
env.fx_expectation,
|
||||
),
|
||||
];
|
||||
|
||||
let and_constraint = constraints.and_constraint(and_cons);
|
||||
|
@ -646,6 +703,7 @@ pub fn constrain_expr(
|
|||
function_type: fn_var,
|
||||
closure_type: closure_var,
|
||||
return_type: ret_var,
|
||||
fx_type: fx_var,
|
||||
early_returns,
|
||||
arguments,
|
||||
loc_body: boxed,
|
||||
|
@ -663,6 +721,7 @@ pub fn constrain_expr(
|
|||
*fn_var,
|
||||
*closure_var,
|
||||
*ret_var,
|
||||
*fx_var,
|
||||
early_returns,
|
||||
arguments,
|
||||
boxed,
|
||||
|
@ -1288,6 +1347,7 @@ pub fn constrain_expr(
|
|||
vec![record_type],
|
||||
Box::new(closure_type),
|
||||
Box::new(field_type),
|
||||
Box::new(Type::Variable(Variable::PURE)),
|
||||
));
|
||||
constraints.push_type(types, typ)
|
||||
};
|
||||
|
@ -1397,7 +1457,15 @@ pub fn constrain_expr(
|
|||
);
|
||||
|
||||
while let Some(def) = stack.pop() {
|
||||
body_con = constrain_def(types, constraints, env, def, body_con)
|
||||
body_con = match def.kind {
|
||||
DefKind::Let => constrain_let_def(types, constraints, env, def, body_con, None),
|
||||
DefKind::Stmt(fx_var) => {
|
||||
constrain_stmt_def(types, constraints, env, def, body_con, fx_var)
|
||||
}
|
||||
DefKind::Ignored(fx_var) => {
|
||||
constrain_let_def(types, constraints, env, def, body_con, Some(fx_var))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
body_con
|
||||
|
@ -1668,6 +1736,7 @@ pub fn constrain_expr(
|
|||
vec![argument_type],
|
||||
Box::new(closure_type),
|
||||
Box::new(opaque_type),
|
||||
Box::new(Type::Variable(Variable::PURE)),
|
||||
));
|
||||
constraints.push_type(types, typ)
|
||||
};
|
||||
|
@ -1853,11 +1922,12 @@ fn constrain_function_def(
|
|||
|
||||
let signature_index = constraints.push_type(types, signature);
|
||||
|
||||
let (arg_types, _signature_closure_type, ret_type) = match types[signature] {
|
||||
TypeTag::Function(signature_closure_type, ret_type) => (
|
||||
let (arg_types, _signature_closure_type, ret_type, fx_type) = match types[signature] {
|
||||
TypeTag::Function(signature_closure_type, ret_type, fx_type) => (
|
||||
types.get_type_arguments(signature),
|
||||
signature_closure_type,
|
||||
ret_type,
|
||||
fx_type,
|
||||
),
|
||||
_ => {
|
||||
// aliases, or just something weird
|
||||
|
@ -1917,6 +1987,7 @@ fn constrain_function_def(
|
|||
expr_var,
|
||||
function_def.closure_type,
|
||||
function_def.return_type,
|
||||
function_def.fx_type,
|
||||
&function_def.early_returns,
|
||||
&function_def.arguments,
|
||||
loc_body_expr,
|
||||
|
@ -1949,6 +2020,10 @@ fn constrain_function_def(
|
|||
home: env.home,
|
||||
rigids: ftv,
|
||||
resolutions_to_make: vec![],
|
||||
fx_expectation: Some(FxExpectation {
|
||||
fx_var: function_def.fx_type,
|
||||
ann_region: Some(annotation.region),
|
||||
}),
|
||||
};
|
||||
|
||||
let region = loc_function_def.region;
|
||||
|
@ -1958,14 +2033,17 @@ fn constrain_function_def(
|
|||
vars: Vec::with_capacity(function_def.arguments.len()),
|
||||
constraints: Vec::with_capacity(1),
|
||||
delayed_is_open_constraints: vec![],
|
||||
delayed_fx_suffix_constraints: Vec::with_capacity(function_def.arguments.len()),
|
||||
};
|
||||
let mut vars = Vec::with_capacity(argument_pattern_state.vars.capacity() + 1);
|
||||
let closure_var = function_def.closure_type;
|
||||
|
||||
let ret_type_index = constraints.push_type(types, ret_type);
|
||||
let fx_type_index = constraints.push_type(types, fx_type);
|
||||
|
||||
vars.push(function_def.return_type);
|
||||
vars.push(function_def.closure_type);
|
||||
vars.push(function_def.fx_type);
|
||||
|
||||
let mut def_pattern_state = PatternState::default();
|
||||
|
||||
|
@ -2043,8 +2121,9 @@ fn constrain_function_def(
|
|||
);
|
||||
let lambda_set = types.from_old_type(&Type::Variable(function_def.closure_type));
|
||||
let ret_var = types.from_old_type(&Type::Variable(function_def.return_type));
|
||||
let fx_var = types.from_old_type(&Type::Variable(function_def.fx_type));
|
||||
|
||||
let fn_type = types.function(pattern_types, lambda_set, ret_var);
|
||||
let fn_type = types.function(pattern_types, lambda_set, ret_var, fx_var);
|
||||
constraints.push_type(types, fn_type)
|
||||
};
|
||||
|
||||
|
@ -2065,6 +2144,13 @@ fn constrain_function_def(
|
|||
let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints);
|
||||
|
||||
let cons = [
|
||||
// Store fx type first so errors are reported at call site
|
||||
constraints.store(
|
||||
fx_type_index,
|
||||
function_def.fx_type,
|
||||
std::file!(),
|
||||
std::line!(),
|
||||
),
|
||||
constraints.let_constraint(
|
||||
[],
|
||||
argument_pattern_state.vars,
|
||||
|
@ -2090,9 +2176,12 @@ fn constrain_function_def(
|
|||
Category::Lambda,
|
||||
region,
|
||||
),
|
||||
// Check argument suffixes against usage
|
||||
constraints.and_constraint(argument_pattern_state.delayed_fx_suffix_constraints),
|
||||
// Finally put the solved closure type into the dedicated def expr variable.
|
||||
constraints.store(signature_index, expr_var, std::file!(), std::line!()),
|
||||
closure_constraint,
|
||||
constraints.flex_to_pure(function_def.fx_type),
|
||||
];
|
||||
|
||||
let expr_con = constraints.exists_many(vars, cons);
|
||||
|
@ -2119,6 +2208,7 @@ fn constrain_function_def(
|
|||
expr_var,
|
||||
function_def.closure_type,
|
||||
function_def.return_type,
|
||||
function_def.fx_type,
|
||||
&function_def.early_returns,
|
||||
&function_def.arguments,
|
||||
loc_expr,
|
||||
|
@ -2190,6 +2280,7 @@ fn constrain_destructure_def(
|
|||
home: env.home,
|
||||
rigids: ftv,
|
||||
resolutions_to_make: vec![],
|
||||
fx_expectation: env.fx_expectation,
|
||||
};
|
||||
|
||||
let signature_index = constraints.push_type(types, signature);
|
||||
|
@ -2292,6 +2383,7 @@ fn constrain_value_def(
|
|||
home: env.home,
|
||||
rigids: ftv,
|
||||
resolutions_to_make: vec![],
|
||||
fx_expectation: env.fx_expectation,
|
||||
};
|
||||
|
||||
let loc_pattern = Loc::at(loc_symbol.region, Pattern::Identifier(loc_symbol.value));
|
||||
|
@ -2404,6 +2496,7 @@ fn constrain_when_branch_help(
|
|||
vars: Vec::with_capacity(2),
|
||||
constraints: Vec::with_capacity(2),
|
||||
delayed_is_open_constraints: Vec::new(),
|
||||
delayed_fx_suffix_constraints: Vec::new(),
|
||||
};
|
||||
|
||||
for (i, loc_pattern) in when_branch.patterns.iter().enumerate() {
|
||||
|
@ -2428,6 +2521,9 @@ fn constrain_when_branch_help(
|
|||
state
|
||||
.delayed_is_open_constraints
|
||||
.extend(partial_state.delayed_is_open_constraints);
|
||||
state
|
||||
.delayed_fx_suffix_constraints
|
||||
.extend(partial_state.delayed_fx_suffix_constraints);
|
||||
|
||||
if i == 0 {
|
||||
state.headers.extend(partial_state.headers);
|
||||
|
@ -2579,6 +2675,7 @@ pub fn constrain_decls(
|
|||
home,
|
||||
rigids: MutMap::default(),
|
||||
resolutions_to_make: vec![],
|
||||
fx_expectation: None,
|
||||
};
|
||||
|
||||
debug_assert_eq!(declarations.declarations.len(), declarations.symbols.len());
|
||||
|
@ -2755,6 +2852,7 @@ pub(crate) fn constrain_def_pattern(
|
|||
vars: Vec::with_capacity(1),
|
||||
constraints: Vec::with_capacity(1),
|
||||
delayed_is_open_constraints: vec![],
|
||||
delayed_fx_suffix_constraints: vec![],
|
||||
};
|
||||
|
||||
constrain_pattern(
|
||||
|
@ -2810,6 +2908,7 @@ fn constrain_typed_def(
|
|||
home: env.home,
|
||||
resolutions_to_make: vec![],
|
||||
rigids: ftv,
|
||||
fx_expectation: env.fx_expectation,
|
||||
};
|
||||
|
||||
let signature_index = constraints.push_type(types, signature);
|
||||
|
@ -2841,13 +2940,14 @@ fn constrain_typed_def(
|
|||
function_type: fn_var,
|
||||
closure_type: closure_var,
|
||||
return_type: ret_var,
|
||||
fx_type: fx_var,
|
||||
captured_symbols,
|
||||
arguments,
|
||||
loc_body,
|
||||
name,
|
||||
..
|
||||
}),
|
||||
TypeTag::Function(_signature_closure_type, ret_type),
|
||||
TypeTag::Function(_signature_closure_type, ret_type, fx_type),
|
||||
) => {
|
||||
let arg_types = types.get_type_arguments(signature);
|
||||
|
||||
|
@ -2862,14 +2962,18 @@ fn constrain_typed_def(
|
|||
vars: Vec::with_capacity(arguments.len()),
|
||||
constraints: Vec::with_capacity(1),
|
||||
delayed_is_open_constraints: vec![],
|
||||
delayed_fx_suffix_constraints: Vec::with_capacity(arguments.len()),
|
||||
};
|
||||
let mut vars = Vec::with_capacity(argument_pattern_state.vars.capacity() + 1);
|
||||
let ret_var = *ret_var;
|
||||
let closure_var = *closure_var;
|
||||
let fx_var = *fx_var;
|
||||
let ret_type_index = constraints.push_type(types, ret_type);
|
||||
let fx_type_index = constraints.push_type(types, fx_type);
|
||||
|
||||
vars.push(ret_var);
|
||||
vars.push(closure_var);
|
||||
vars.push(fx_var);
|
||||
|
||||
constrain_typed_function_arguments(
|
||||
types,
|
||||
|
@ -2899,8 +3003,9 @@ fn constrain_typed_def(
|
|||
types.from_old_type_slice(arguments.iter().map(|a| Type::Variable(a.0)));
|
||||
let lambda_set = types.from_old_type(&Type::Variable(closure_var));
|
||||
let ret_var = types.from_old_type(&Type::Variable(ret_var));
|
||||
let fx_var = types.from_old_type(&Type::Variable(fx_var));
|
||||
|
||||
let fn_type = types.function(arg_types, lambda_set, ret_var);
|
||||
let fn_type = types.function(arg_types, lambda_set, ret_var, fx_var);
|
||||
constraints.push_type(types, fn_type)
|
||||
};
|
||||
|
||||
|
@ -2913,20 +3018,25 @@ fn constrain_typed_def(
|
|||
ret_type_index,
|
||||
));
|
||||
|
||||
let ret_constraint = constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
loc_body_expr.region,
|
||||
&loc_body_expr.value,
|
||||
body_type,
|
||||
);
|
||||
let ret_constraint = env.with_fx_expectation(fx_var, Some(annotation.region), |env| {
|
||||
constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
loc_body_expr.region,
|
||||
&loc_body_expr.value,
|
||||
body_type,
|
||||
)
|
||||
});
|
||||
|
||||
let ret_constraint = attach_resolution_constraints(constraints, env, ret_constraint);
|
||||
|
||||
vars.push(*fn_var);
|
||||
let defs_constraint = constraints.and_constraint(argument_pattern_state.constraints);
|
||||
|
||||
let cons = [
|
||||
// Store fx type first so errors are reported at call site
|
||||
constraints.store(fx_type_index, fx_var, std::file!(), std::line!()),
|
||||
constraints.let_constraint(
|
||||
[],
|
||||
argument_pattern_state.vars,
|
||||
|
@ -2936,6 +3046,8 @@ fn constrain_typed_def(
|
|||
// This is a syntactic function, it can be generalized
|
||||
Generalizable(true),
|
||||
),
|
||||
// Check argument suffixes against usage
|
||||
constraints.and_constraint(argument_pattern_state.delayed_fx_suffix_constraints),
|
||||
// Store the inferred ret var into the function type now, so that
|
||||
// when we check that the solved function type matches the annotation, we can
|
||||
// display the fully inferred return variable.
|
||||
|
@ -2951,6 +3063,7 @@ fn constrain_typed_def(
|
|||
constraints.store(signature_index, *fn_var, std::file!(), std::line!()),
|
||||
constraints.store(signature_index, expr_var, std::file!(), std::line!()),
|
||||
closure_constraint,
|
||||
constraints.flex_to_pure(fx_var),
|
||||
];
|
||||
|
||||
let expr_con = constraints.exists_many(vars, cons);
|
||||
|
@ -3318,12 +3431,13 @@ fn attach_resolution_constraints(
|
|||
constraints.and_constraint([constraint, resolution_constrs])
|
||||
}
|
||||
|
||||
fn constrain_def(
|
||||
fn constrain_let_def(
|
||||
types: &mut Types,
|
||||
constraints: &mut Constraints,
|
||||
env: &mut Env,
|
||||
def: &Def,
|
||||
body_con: Constraint,
|
||||
ignored_fx_var: Option<Variable>,
|
||||
) -> Constraint {
|
||||
match &def.annotation {
|
||||
Some(annotation) => constrain_typed_def(types, constraints, env, def, body_con, annotation),
|
||||
|
@ -3338,14 +3452,49 @@ fn constrain_def(
|
|||
// no annotation, so no extra work with rigids
|
||||
|
||||
let expected = constraints.push_expected_type(NoExpectation(expr_type_index));
|
||||
let expr_con = constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
def.loc_expr.region,
|
||||
&def.loc_expr.value,
|
||||
expected,
|
||||
);
|
||||
|
||||
let expr_con = match ignored_fx_var {
|
||||
None => constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
def.loc_expr.region,
|
||||
&def.loc_expr.value,
|
||||
expected,
|
||||
),
|
||||
Some(fx_var) => {
|
||||
let expr_con = env.with_fx_expectation(fx_var, None, |env| {
|
||||
constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
def.loc_expr.region,
|
||||
&def.loc_expr.value,
|
||||
expected,
|
||||
)
|
||||
});
|
||||
|
||||
// Ignored def must be effectful, otherwise it's dead code
|
||||
let effectful_constraint = Constraint::ExpectEffectful(
|
||||
fx_var,
|
||||
ExpectEffectfulReason::Ignored,
|
||||
def.loc_pattern.region,
|
||||
);
|
||||
|
||||
let enclosing_fx_constraint = constraints.fx_call(
|
||||
fx_var,
|
||||
FxCallKind::Ignored,
|
||||
def.loc_pattern.region,
|
||||
env.fx_expectation,
|
||||
);
|
||||
|
||||
constraints.and_constraint([
|
||||
expr_con,
|
||||
enclosing_fx_constraint,
|
||||
effectful_constraint,
|
||||
])
|
||||
}
|
||||
};
|
||||
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
|
||||
|
||||
let generalizable = Generalizable(is_generalizable_expr(&def.loc_expr.value));
|
||||
|
@ -3363,6 +3512,77 @@ fn constrain_def(
|
|||
}
|
||||
}
|
||||
|
||||
fn constrain_stmt_def(
|
||||
types: &mut Types,
|
||||
constraints: &mut Constraints,
|
||||
env: &mut Env,
|
||||
def: &Def,
|
||||
body_con: Constraint,
|
||||
fx_var: Variable,
|
||||
) -> Constraint {
|
||||
let region = def.loc_expr.region;
|
||||
|
||||
// Try to extract the fn name and region if the stmt is a call to a named function
|
||||
let (fn_name, error_region) = if let Expr::Call(boxed, _, _) = &def.loc_expr.value {
|
||||
let loc_fn_expr = &boxed.1;
|
||||
|
||||
match loc_fn_expr.value {
|
||||
Var(symbol, _) | ParamsVar { symbol, .. } => (Some(symbol), loc_fn_expr.region),
|
||||
_ => (None, def.loc_expr.region),
|
||||
}
|
||||
} else {
|
||||
(None, def.loc_expr.region)
|
||||
};
|
||||
|
||||
// Statement expressions must return an empty record
|
||||
let empty_record_index = constraints.push_type(types, Types::EMPTY_RECORD);
|
||||
let expect_empty_record = constraints.push_expected_type(ForReason(
|
||||
Reason::Stmt(fn_name),
|
||||
empty_record_index,
|
||||
error_region,
|
||||
));
|
||||
|
||||
let expr_con = env.with_fx_expectation(fx_var, None, |env| {
|
||||
constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
region,
|
||||
&def.loc_expr.value,
|
||||
expect_empty_record,
|
||||
)
|
||||
});
|
||||
|
||||
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
|
||||
|
||||
let generalizable = Generalizable(is_generalizable_expr(&def.loc_expr.value));
|
||||
|
||||
let body_con = constraints.let_constraint(
|
||||
std::iter::empty(),
|
||||
std::iter::empty(),
|
||||
std::iter::empty(),
|
||||
expr_con,
|
||||
body_con,
|
||||
generalizable,
|
||||
);
|
||||
|
||||
// Stmt expr must be effectful, otherwise it's dead code
|
||||
let effectful_constraint =
|
||||
Constraint::ExpectEffectful(fx_var, ExpectEffectfulReason::Stmt, region);
|
||||
|
||||
let fx_call_kind = match fn_name {
|
||||
None => FxCallKind::Stmt,
|
||||
Some(name) => FxCallKind::Call(Some(name)),
|
||||
};
|
||||
|
||||
// We have to unify the stmt fx with the enclosing fx
|
||||
// since we used the former to constrain the expr.
|
||||
let enclosing_fx_constraint =
|
||||
constraints.fx_call(fx_var, fx_call_kind, error_region, env.fx_expectation);
|
||||
|
||||
constraints.and_constraint([body_con, effectful_constraint, enclosing_fx_constraint])
|
||||
}
|
||||
|
||||
/// Create a let-constraint for a non-recursive def.
|
||||
/// Recursive defs should always use `constrain_recursive_defs`.
|
||||
pub(crate) fn constrain_def_make_constraint(
|
||||
|
@ -3700,6 +3920,7 @@ fn constraint_recursive_function(
|
|||
expr_var,
|
||||
function_def.closure_type,
|
||||
function_def.return_type,
|
||||
function_def.fx_type,
|
||||
&function_def.early_returns,
|
||||
&function_def.arguments,
|
||||
loc_expr,
|
||||
|
@ -3747,11 +3968,12 @@ fn constraint_recursive_function(
|
|||
signature_index,
|
||||
));
|
||||
|
||||
let (arg_types, _signature_closure_type, ret_type) = match types[signature] {
|
||||
TypeTag::Function(signature_closure_type, ret_type) => (
|
||||
let (arg_types, _signature_closure_type, ret_type, fx_type) = match types[signature] {
|
||||
TypeTag::Function(signature_closure_type, ret_type, fx_type) => (
|
||||
types.get_type_arguments(signature),
|
||||
signature_closure_type,
|
||||
ret_type,
|
||||
fx_type,
|
||||
),
|
||||
_ => todo!("TODO {:?}", (loc_symbol, types[signature])),
|
||||
};
|
||||
|
@ -3764,14 +3986,18 @@ fn constraint_recursive_function(
|
|||
vars: Vec::with_capacity(function_def.arguments.len()),
|
||||
constraints: Vec::with_capacity(1),
|
||||
delayed_is_open_constraints: vec![],
|
||||
delayed_fx_suffix_constraints: Vec::with_capacity(function_def.arguments.len()),
|
||||
};
|
||||
let mut vars = Vec::with_capacity(argument_pattern_state.vars.capacity() + 1);
|
||||
let ret_var = function_def.return_type;
|
||||
let fx_var = function_def.fx_type;
|
||||
let closure_var = function_def.closure_type;
|
||||
let ret_type_index = constraints.push_type(types, ret_type);
|
||||
let fx_type_index = constraints.push_type(types, fx_type);
|
||||
|
||||
vars.push(ret_var);
|
||||
vars.push(closure_var);
|
||||
vars.push(fx_var);
|
||||
|
||||
let mut def_pattern_state = PatternState::default();
|
||||
|
||||
|
@ -3819,11 +4045,11 @@ fn constraint_recursive_function(
|
|||
let fn_type = {
|
||||
// TODO(types-soa) optimize for Variable
|
||||
let lambda_set = types.from_old_type(&Type::Variable(closure_var));
|
||||
let typ = types.function(pattern_types, lambda_set, ret_type);
|
||||
let typ = types.function(pattern_types, lambda_set, ret_type, fx_type);
|
||||
constraints.push_type(types, typ)
|
||||
};
|
||||
|
||||
let expr_con = {
|
||||
let expr_con = env.with_fx_expectation(fx_var, Some(annotation.region), |env| {
|
||||
let expected = constraints.push_expected_type(NoExpectation(ret_type_index));
|
||||
constrain_expr(
|
||||
types,
|
||||
|
@ -3833,13 +4059,14 @@ fn constraint_recursive_function(
|
|||
&loc_body_expr.value,
|
||||
expected,
|
||||
)
|
||||
};
|
||||
});
|
||||
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
|
||||
|
||||
vars.push(expr_var);
|
||||
|
||||
let state_constraints = constraints.and_constraint(argument_pattern_state.constraints);
|
||||
let cons = [
|
||||
constraints.store(fx_type_index, fx_var, std::file!(), std::line!()),
|
||||
constraints.let_constraint(
|
||||
[],
|
||||
argument_pattern_state.vars,
|
||||
|
@ -3849,12 +4076,15 @@ fn constraint_recursive_function(
|
|||
// Syntactic function can be generalized
|
||||
Generalizable(true),
|
||||
),
|
||||
// Check argument suffixes against usage
|
||||
constraints.and_constraint(argument_pattern_state.delayed_fx_suffix_constraints),
|
||||
constraints.equal_types(fn_type, annotation_expected, Category::Lambda, region),
|
||||
// "fn_var is equal to the closure's type" - fn_var is used in code gen
|
||||
// Store type into AST vars. We use Store so errors aren't reported twice
|
||||
constraints.store(signature_index, expr_var, std::file!(), std::line!()),
|
||||
constraints.store(ret_type_index, ret_var, std::file!(), std::line!()),
|
||||
closure_constraint,
|
||||
constraints.flex_to_pure(fx_var),
|
||||
];
|
||||
|
||||
let and_constraint = constraints.and_constraint(cons);
|
||||
|
@ -4305,13 +4535,14 @@ fn rec_defs_help(
|
|||
function_type: fn_var,
|
||||
closure_type: closure_var,
|
||||
return_type: ret_var,
|
||||
fx_type: fx_var,
|
||||
captured_symbols,
|
||||
arguments,
|
||||
loc_body,
|
||||
name,
|
||||
..
|
||||
}),
|
||||
TypeTag::Function(_closure_type, ret_type),
|
||||
TypeTag::Function(_closure_type, ret_type, fx_type),
|
||||
) => {
|
||||
// NOTE if we ever have trouble with closure type unification, the ignored
|
||||
// `_closure_type` here is a good place to start investigating
|
||||
|
@ -4327,15 +4558,19 @@ fn rec_defs_help(
|
|||
vars: Vec::with_capacity(arguments.len()),
|
||||
constraints: Vec::with_capacity(1),
|
||||
delayed_is_open_constraints: vec![],
|
||||
delayed_fx_suffix_constraints: Vec::with_capacity(arguments.len()),
|
||||
};
|
||||
let mut vars =
|
||||
Vec::with_capacity(argument_pattern_state.vars.capacity() + 1);
|
||||
let ret_var = *ret_var;
|
||||
let fx_var = *fx_var;
|
||||
let closure_var = *closure_var;
|
||||
let ret_type_index = constraints.push_type(types, ret_type);
|
||||
let fx_type_index = constraints.push_type(types, fx_type);
|
||||
|
||||
vars.push(ret_var);
|
||||
vars.push(closure_var);
|
||||
vars.push(fx_var);
|
||||
|
||||
constrain_typed_function_arguments(
|
||||
types,
|
||||
|
@ -4364,22 +4599,24 @@ fn rec_defs_help(
|
|||
let fn_type_index = {
|
||||
// TODO(types-soa) optimize for variable
|
||||
let lambda_set = types.from_old_type(&Type::Variable(closure_var));
|
||||
let typ = types.function(pattern_types, lambda_set, ret_type);
|
||||
let typ = types.function(pattern_types, lambda_set, ret_type, fx_type);
|
||||
constraints.push_type(types, typ)
|
||||
};
|
||||
let expr_con = {
|
||||
let body_type =
|
||||
constraints.push_expected_type(NoExpectation(ret_type_index));
|
||||
let expr_con =
|
||||
env.with_fx_expectation(fx_var, Some(annotation.region), |env| {
|
||||
let body_type =
|
||||
constraints.push_expected_type(NoExpectation(ret_type_index));
|
||||
|
||||
constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
loc_body_expr.region,
|
||||
&loc_body_expr.value,
|
||||
body_type,
|
||||
)
|
||||
});
|
||||
|
||||
constrain_expr(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
loc_body_expr.region,
|
||||
&loc_body_expr.value,
|
||||
body_type,
|
||||
)
|
||||
};
|
||||
let expr_con = attach_resolution_constraints(constraints, env, expr_con);
|
||||
|
||||
vars.push(*fn_var);
|
||||
|
@ -4388,6 +4625,8 @@ fn rec_defs_help(
|
|||
constraints.and_constraint(argument_pattern_state.constraints);
|
||||
let expected_index = constraints.push_expected_type(expected);
|
||||
let cons = [
|
||||
// Store fx type first so errors are reported at call site
|
||||
constraints.store(fx_type_index, fx_var, std::file!(), std::line!()),
|
||||
constraints.let_constraint(
|
||||
[],
|
||||
argument_pattern_state.vars,
|
||||
|
@ -4396,6 +4635,10 @@ fn rec_defs_help(
|
|||
expr_con,
|
||||
generalizable,
|
||||
),
|
||||
// Check argument suffixes against usage
|
||||
constraints.and_constraint(
|
||||
argument_pattern_state.delayed_fx_suffix_constraints,
|
||||
),
|
||||
constraints.equal_types(
|
||||
fn_type_index,
|
||||
expected_index,
|
||||
|
@ -4413,6 +4656,7 @@ fn rec_defs_help(
|
|||
),
|
||||
constraints.store(ret_type_index, ret_var, std::file!(), std::line!()),
|
||||
closure_constraint,
|
||||
constraints.flex_to_pure(fx_var),
|
||||
];
|
||||
|
||||
let and_constraint = constraints.and_constraint(cons);
|
||||
|
|
|
@ -56,6 +56,7 @@ fn constrain_params(
|
|||
home,
|
||||
rigids: MutMap::default(),
|
||||
resolutions_to_make: vec![],
|
||||
fx_expectation: None,
|
||||
};
|
||||
|
||||
let index = constraints.push_variable(module_params.whole_var);
|
||||
|
@ -114,6 +115,7 @@ fn constrain_symbols_from_requires(
|
|||
home,
|
||||
rigids,
|
||||
resolutions_to_make: vec![],
|
||||
fx_expectation: None,
|
||||
};
|
||||
let pattern = Loc::at_zero(roc_can::pattern::Pattern::Identifier(loc_symbol.value));
|
||||
|
||||
|
@ -181,6 +183,7 @@ pub fn frontload_ability_constraints(
|
|||
home,
|
||||
rigids,
|
||||
resolutions_to_make: vec![],
|
||||
fx_expectation: None,
|
||||
};
|
||||
let pattern = Loc::at_zero(roc_can::pattern::Pattern::Identifier(*member_name));
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ use roc_can::pattern::Pattern::{self, *};
|
|||
use roc_can::pattern::{DestructType, ListPatterns, RecordDestruct, TupleDestruct};
|
||||
use roc_collections::all::{HumanIndex, SendMap};
|
||||
use roc_collections::VecMap;
|
||||
use roc_module::ident::Lowercase;
|
||||
use roc_module::ident::{IdentSuffix, Lowercase};
|
||||
use roc_module::symbol::Symbol;
|
||||
use roc_region::all::{Loc, Region};
|
||||
use roc_types::subs::Variable;
|
||||
|
@ -22,6 +22,7 @@ pub struct PatternState {
|
|||
pub vars: Vec<Variable>,
|
||||
pub constraints: Vec<Constraint>,
|
||||
pub delayed_is_open_constraints: Vec<Constraint>,
|
||||
pub delayed_fx_suffix_constraints: Vec<Constraint>,
|
||||
}
|
||||
|
||||
/// If there is a type annotation, the pattern state headers can be optimized by putting the
|
||||
|
@ -247,6 +248,29 @@ pub fn constrain_pattern(
|
|||
region: Region,
|
||||
expected: PExpectedTypeIndex,
|
||||
state: &mut PatternState,
|
||||
) {
|
||||
constrain_pattern_help(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
pattern,
|
||||
region,
|
||||
expected,
|
||||
state,
|
||||
true,
|
||||
);
|
||||
}
|
||||
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn constrain_pattern_help(
|
||||
types: &mut Types,
|
||||
constraints: &mut Constraints,
|
||||
env: &mut Env,
|
||||
pattern: &Pattern,
|
||||
region: Region,
|
||||
expected: PExpectedTypeIndex,
|
||||
state: &mut PatternState,
|
||||
is_shallow: bool,
|
||||
) {
|
||||
match pattern {
|
||||
Underscore => {
|
||||
|
@ -276,6 +300,27 @@ pub fn constrain_pattern(
|
|||
.push(constraints.is_open_type(type_index));
|
||||
}
|
||||
|
||||
// Identifiers introduced in nested patterns get let constraints
|
||||
// and therefore don't need fx_pattern_suffix constraints.
|
||||
if is_shallow {
|
||||
match symbol.suffix() {
|
||||
IdentSuffix::None => {
|
||||
// Unsuffixed identifiers should be constrained after we know if they're functions
|
||||
state
|
||||
.delayed_fx_suffix_constraints
|
||||
.push(constraints.fx_pattern_suffix(*symbol, type_index, region));
|
||||
}
|
||||
IdentSuffix::Bang => {
|
||||
// Bang suffixed identifiers are always required to be functions
|
||||
// We constrain this before the function's body,
|
||||
// so that we don't think it's pure and complain about leftover statements
|
||||
state
|
||||
.constraints
|
||||
.push(constraints.fx_pattern_suffix(*symbol, type_index, region));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
state.headers.insert(
|
||||
*symbol,
|
||||
Loc {
|
||||
|
@ -297,7 +342,7 @@ pub fn constrain_pattern(
|
|||
},
|
||||
);
|
||||
|
||||
constrain_pattern(
|
||||
constrain_pattern_help(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
|
@ -305,6 +350,7 @@ pub fn constrain_pattern(
|
|||
subpattern.region,
|
||||
expected,
|
||||
state,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -530,7 +576,7 @@ pub fn constrain_pattern(
|
|||
));
|
||||
state.vars.push(*guard_var);
|
||||
|
||||
constrain_pattern(
|
||||
constrain_pattern_help(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
|
@ -538,6 +584,7 @@ pub fn constrain_pattern(
|
|||
loc_pattern.region,
|
||||
expected,
|
||||
state,
|
||||
false,
|
||||
);
|
||||
|
||||
pat_type
|
||||
|
@ -628,7 +675,7 @@ pub fn constrain_pattern(
|
|||
));
|
||||
state.vars.push(*guard_var);
|
||||
|
||||
constrain_pattern(
|
||||
constrain_pattern_help(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
|
@ -636,6 +683,7 @@ pub fn constrain_pattern(
|
|||
loc_guard.region,
|
||||
expected,
|
||||
state,
|
||||
false,
|
||||
);
|
||||
|
||||
RecordField::Demanded(pat_type)
|
||||
|
@ -751,7 +799,7 @@ pub fn constrain_pattern(
|
|||
loc_pat.region,
|
||||
));
|
||||
|
||||
constrain_pattern(
|
||||
constrain_pattern_help(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
|
@ -759,6 +807,7 @@ pub fn constrain_pattern(
|
|||
loc_pat.region,
|
||||
expected,
|
||||
state,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -807,7 +856,7 @@ pub fn constrain_pattern(
|
|||
pattern_type,
|
||||
region,
|
||||
));
|
||||
constrain_pattern(
|
||||
constrain_pattern_help(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
|
@ -815,6 +864,7 @@ pub fn constrain_pattern(
|
|||
loc_pattern.region,
|
||||
expected,
|
||||
state,
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -872,7 +922,7 @@ pub fn constrain_pattern(
|
|||
// First, add a constraint for the argument "who"
|
||||
let arg_pattern_expected = constraints
|
||||
.push_pat_expected_type(PExpected::NoExpectation(arg_pattern_type_index));
|
||||
constrain_pattern(
|
||||
constrain_pattern_help(
|
||||
types,
|
||||
constraints,
|
||||
env,
|
||||
|
@ -880,6 +930,7 @@ pub fn constrain_pattern(
|
|||
loc_arg_pattern.region,
|
||||
arg_pattern_expected,
|
||||
state,
|
||||
false,
|
||||
);
|
||||
|
||||
// Next, link `whole_var` to the opaque type of "@Id who"
|
||||
|
|
|
@ -78,6 +78,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
this_decode_with_var_slice,
|
||||
this_decode_with_clos_var,
|
||||
this_decode_with_ret_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -91,6 +92,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
Loc::at_zero(decode_with_var),
|
||||
this_decode_with_clos_var,
|
||||
this_decode_with_ret_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
let decode_with_call = Call(
|
||||
decode_with_fn,
|
||||
|
@ -139,6 +141,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
args_slice,
|
||||
fn_clos_var,
|
||||
decode_with_result_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -147,6 +150,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: decode_with_result_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: sorted_inner_decoder_captures,
|
||||
|
@ -184,6 +188,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
this_decode_custom_args,
|
||||
this_decode_custom_clos_var,
|
||||
this_decode_custom_ret_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -197,6 +202,7 @@ fn wrap_in_decode_custom_decode_with(
|
|||
Loc::at_zero(decode_custom_var),
|
||||
this_decode_custom_clos_var,
|
||||
this_decode_custom_ret_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
let decode_custom_call = Call(
|
||||
decode_custom_fn,
|
||||
|
|
|
@ -65,6 +65,7 @@ pub(crate) fn decoder(env: &mut Env<'_>, _def_symbol: Symbol) -> (Expr, Variable
|
|||
elem_decoder_var_slice,
|
||||
this_decode_list_clos_var,
|
||||
this_decode_list_ret_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -78,6 +79,7 @@ pub(crate) fn decoder(env: &mut Env<'_>, _def_symbol: Symbol) -> (Expr, Variable
|
|||
Loc::at_zero(decode_list_member),
|
||||
this_decode_list_clos_var,
|
||||
this_decode_list_ret_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
let decode_list_call = Call(
|
||||
|
|
|
@ -112,6 +112,7 @@ pub(crate) fn decoder(
|
|||
.insert_into_vars([initial_state_var, step_var, finalizer_var]),
|
||||
decode_record_lambda_set,
|
||||
record_decoder_var,
|
||||
Variable::PURE,
|
||||
);
|
||||
|
||||
synth_var(env.subs, Content::Structure(flat_type))
|
||||
|
@ -130,6 +131,7 @@ pub(crate) fn decoder(
|
|||
)),
|
||||
decode_record_lambda_set,
|
||||
record_decoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
vec![
|
||||
(initial_state_var, Loc::at_zero(initial_state)),
|
||||
|
@ -342,7 +344,12 @@ pub(super) fn step_field(
|
|||
|
||||
env.subs.set_content(
|
||||
function_type,
|
||||
Content::Structure(FlatType::Func(args_slice, closure_type, keep_or_skip_var)),
|
||||
Content::Structure(FlatType::Func(
|
||||
args_slice,
|
||||
closure_type,
|
||||
keep_or_skip_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -350,6 +357,7 @@ pub(super) fn step_field(
|
|||
function_type,
|
||||
closure_type,
|
||||
return_type: keep_or_skip_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: step_field_closure,
|
||||
captured_symbols: Vec::new(),
|
||||
|
@ -406,8 +414,12 @@ fn custom_decoder(env: &mut Env<'_>, args: DecodingFieldArgs) -> (Variable, Expr
|
|||
let decode_custom_closure_var = env.subs.fresh_unnamed_flex_var();
|
||||
let this_decode_custom_var = {
|
||||
let subs_slice = env.subs.insert_into_vars([this_custom_callback_var]);
|
||||
let flat_type =
|
||||
FlatType::Func(subs_slice, decode_custom_closure_var, decode_custom_ret_var);
|
||||
let flat_type = FlatType::Func(
|
||||
subs_slice,
|
||||
decode_custom_closure_var,
|
||||
decode_custom_ret_var,
|
||||
Variable::PURE,
|
||||
);
|
||||
|
||||
synth_var(env.subs, Content::Structure(flat_type))
|
||||
};
|
||||
|
@ -421,6 +433,7 @@ fn custom_decoder(env: &mut Env<'_>, args: DecodingFieldArgs) -> (Variable, Expr
|
|||
Loc::at_zero(Expr::Var(Symbol::DECODE_CUSTOM, this_decode_custom_var)),
|
||||
decode_custom_closure_var,
|
||||
decode_custom_ret_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
vec![(this_custom_callback_var, Loc::at_zero(custom_callback))],
|
||||
CalledVia::Space,
|
||||
|
@ -576,6 +589,7 @@ fn custom_decoder_lambda(env: &mut Env<'_>, args: DecodingFieldArgs) -> (Variabl
|
|||
subs_slice,
|
||||
custom_callback_lambda_set_var,
|
||||
custom_callback_ret_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -587,6 +601,7 @@ fn custom_decoder_lambda(env: &mut Env<'_>, args: DecodingFieldArgs) -> (Variabl
|
|||
function_type: this_custom_callback_var,
|
||||
closure_type: custom_callback_lambda_set_var,
|
||||
return_type: custom_callback_ret_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: custom_closure_symbol,
|
||||
captured_symbols: vec![(state_arg_symbol, state_record_var)],
|
||||
|
@ -985,6 +1000,7 @@ pub(super) fn finalizer(
|
|||
env.subs.insert_into_vars([state_record_var, fmt_arg_var]),
|
||||
closure_type,
|
||||
return_type_var,
|
||||
Variable::PURE,
|
||||
);
|
||||
|
||||
// Fix up function_var so it's not Content::Error anymore
|
||||
|
@ -995,6 +1011,7 @@ pub(super) fn finalizer(
|
|||
function_type: function_var,
|
||||
closure_type,
|
||||
return_type: return_type_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: function_symbol,
|
||||
captured_symbols: Vec::new(),
|
||||
|
@ -1275,7 +1292,12 @@ fn make_decode_with_vars(
|
|||
.insert_into_vars([bytes_arg_var, decoder_var, fmt_arg_var]);
|
||||
let this_decode_with_var = synth_var(
|
||||
env.subs,
|
||||
Content::Structure(FlatType::Func(subs_slice, lambda_set_var, rec_var)),
|
||||
Content::Structure(FlatType::Func(
|
||||
subs_slice,
|
||||
lambda_set_var,
|
||||
rec_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
env.unify(decode_with_var, this_decode_with_var);
|
||||
|
@ -1325,6 +1347,7 @@ pub(super) fn decode_with(
|
|||
Loc::at_zero(Expr::Var(Symbol::DECODE_DECODE_WITH, this_decode_with_var)),
|
||||
lambda_set_var,
|
||||
rec_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
vec![
|
||||
(Variable::LIST_U8, Loc::at_zero(bytes_arg_expr)),
|
||||
|
|
|
@ -102,6 +102,7 @@ pub(crate) fn decoder(env: &mut Env, _def_symbol: Symbol, arity: u32) -> (Expr,
|
|||
.insert_into_vars([state_var, step_var, finalizer_var]),
|
||||
decode_record_lambda_set,
|
||||
tuple_decoder_var,
|
||||
Variable::PURE,
|
||||
);
|
||||
|
||||
synth_var(env.subs, Content::Structure(flat_type))
|
||||
|
@ -120,6 +121,7 @@ pub(crate) fn decoder(env: &mut Env, _def_symbol: Symbol, arity: u32) -> (Expr,
|
|||
)),
|
||||
decode_record_lambda_set,
|
||||
tuple_decoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
vec![
|
||||
(state_var, Loc::at_zero(initial_state)),
|
||||
|
@ -276,7 +278,12 @@ fn step_elem(
|
|||
.insert_into_vars([bytes_arg_var, decoder_var, fmt_arg_var]);
|
||||
let this_decode_with_var = synth_var(
|
||||
env.subs,
|
||||
Content::Structure(FlatType::Func(subs_slice, lambda_set_var, rec_var)),
|
||||
Content::Structure(FlatType::Func(
|
||||
subs_slice,
|
||||
lambda_set_var,
|
||||
rec_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
env.unify(decode_with_var, this_decode_with_var);
|
||||
|
@ -490,6 +497,7 @@ fn step_elem(
|
|||
Loc::at_zero(Expr::Var(Symbol::DECODE_DECODE_WITH, this_decode_with_var)),
|
||||
lambda_set_var,
|
||||
rec_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
vec![
|
||||
(
|
||||
|
@ -545,6 +553,7 @@ fn step_elem(
|
|||
subs_slice,
|
||||
custom_callback_lambda_set_var,
|
||||
custom_callback_ret_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -556,6 +565,7 @@ fn step_elem(
|
|||
function_type: this_custom_callback_var,
|
||||
closure_type: custom_callback_lambda_set_var,
|
||||
return_type: custom_callback_ret_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: custom_closure_symbol,
|
||||
captured_symbols: vec![(state_arg_symbol, state_record_var)],
|
||||
|
@ -582,8 +592,12 @@ fn step_elem(
|
|||
let decode_custom_closure_var = env.subs.fresh_unnamed_flex_var();
|
||||
let this_decode_custom_var = {
|
||||
let subs_slice = env.subs.insert_into_vars([this_custom_callback_var]);
|
||||
let flat_type =
|
||||
FlatType::Func(subs_slice, decode_custom_closure_var, decode_custom_ret_var);
|
||||
let flat_type = FlatType::Func(
|
||||
subs_slice,
|
||||
decode_custom_closure_var,
|
||||
decode_custom_ret_var,
|
||||
Variable::PURE,
|
||||
);
|
||||
|
||||
synth_var(env.subs, Content::Structure(flat_type))
|
||||
};
|
||||
|
@ -597,6 +611,7 @@ fn step_elem(
|
|||
Loc::at_zero(Expr::Var(Symbol::DECODE_CUSTOM, this_decode_custom_var)),
|
||||
decode_custom_closure_var,
|
||||
decode_custom_ret_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
vec![(this_custom_callback_var, Loc::at_zero(custom_callback))],
|
||||
CalledVia::Space,
|
||||
|
@ -703,7 +718,12 @@ fn step_elem(
|
|||
|
||||
env.subs.set_content(
|
||||
function_type,
|
||||
Content::Structure(FlatType::Func(args_slice, closure_type, keep_or_skip_var)),
|
||||
Content::Structure(FlatType::Func(
|
||||
args_slice,
|
||||
closure_type,
|
||||
keep_or_skip_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
)
|
||||
};
|
||||
|
||||
|
@ -711,6 +731,7 @@ fn step_elem(
|
|||
function_type,
|
||||
closure_type,
|
||||
return_type: keep_or_skip_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: step_elem_closure,
|
||||
captured_symbols: Vec::new(),
|
||||
|
@ -888,6 +909,7 @@ fn finalizer(
|
|||
env.subs.insert_into_vars([state_record_var]),
|
||||
closure_type,
|
||||
return_type_var,
|
||||
Variable::PURE,
|
||||
);
|
||||
|
||||
// Fix up function_var so it's not Content::Error anymore
|
||||
|
@ -898,6 +920,7 @@ fn finalizer(
|
|||
function_type: function_var,
|
||||
closure_type,
|
||||
return_type: return_type_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: function_symbol,
|
||||
captured_symbols: Vec::new(),
|
||||
|
|
|
@ -132,6 +132,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
elem_var_slice,
|
||||
to_encoder_clos_var,
|
||||
elem_encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -146,6 +147,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
Loc::at_zero(to_encoder_var),
|
||||
to_encoder_clos_var,
|
||||
elem_encoder_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// toEncoder elem
|
||||
|
@ -180,6 +182,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
elem_var_slice,
|
||||
to_elem_encoder_lset,
|
||||
elem_encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -188,6 +191,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
function_type: to_elem_encoder_fn_var,
|
||||
closure_type: to_elem_encoder_lset,
|
||||
return_type: elem_encoder_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: to_elem_encoder_sym,
|
||||
captured_symbols: vec![],
|
||||
|
@ -216,6 +220,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
this_encode_list_args_slice,
|
||||
this_encode_list_clos_var,
|
||||
this_list_encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -230,6 +235,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
Loc::at_zero(encode_list),
|
||||
this_encode_list_clos_var,
|
||||
this_list_encoder_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Encode.list lst to_elem_encoder
|
||||
|
@ -274,6 +280,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
list_var_slice,
|
||||
fn_clos_var,
|
||||
this_encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -282,6 +289,7 @@ fn to_encoder_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: this_encoder_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -354,6 +362,7 @@ fn to_encoder_record(
|
|||
field_var_slice,
|
||||
to_encoder_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -368,6 +377,7 @@ fn to_encoder_record(
|
|||
Loc::at_zero(to_encoder_var),
|
||||
to_encoder_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// toEncoder rcd.a
|
||||
|
@ -435,6 +445,7 @@ fn to_encoder_record(
|
|||
fields_list_var_slice,
|
||||
encode_record_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -449,6 +460,7 @@ fn to_encoder_record(
|
|||
Loc::at_zero(encode_record_var),
|
||||
encode_record_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Encode.record [ { key: .., value: .. }, .. ]
|
||||
|
@ -484,6 +496,7 @@ fn to_encoder_record(
|
|||
record_var_slice,
|
||||
fn_clos_var,
|
||||
this_encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -492,6 +505,7 @@ fn to_encoder_record(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: this_encoder_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -557,6 +571,7 @@ fn to_encoder_tuple(
|
|||
elem_var_slice,
|
||||
to_encoder_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -571,6 +586,7 @@ fn to_encoder_tuple(
|
|||
Loc::at_zero(to_encoder_var),
|
||||
to_encoder_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// toEncoder tup.0
|
||||
|
@ -618,6 +634,7 @@ fn to_encoder_tuple(
|
|||
elem_encoders_list_var_slice,
|
||||
encode_tuple_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -632,6 +649,7 @@ fn to_encoder_tuple(
|
|||
Loc::at_zero(encode_tuple_var),
|
||||
encode_tuple_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Encode.tuple [ { key: .., value: .. }, .. ]
|
||||
|
@ -667,6 +685,7 @@ fn to_encoder_tuple(
|
|||
tuple_var_slice,
|
||||
fn_clos_var,
|
||||
this_encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -675,6 +694,7 @@ fn to_encoder_tuple(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: this_encoder_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -757,6 +777,7 @@ fn to_encoder_tag_union(
|
|||
var_slice_of_sym_var,
|
||||
to_encoder_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -772,6 +793,7 @@ fn to_encoder_tag_union(
|
|||
Loc::at_zero(to_encoder_var),
|
||||
to_encoder_clos_var,
|
||||
encoder_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// toEncoder rcd.a
|
||||
|
@ -817,6 +839,7 @@ fn to_encoder_tag_union(
|
|||
this_encode_tag_args_var_slice,
|
||||
this_encode_tag_clos_var,
|
||||
this_encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -831,6 +854,7 @@ fn to_encoder_tag_union(
|
|||
Loc::at_zero(encode_tag_var),
|
||||
this_encode_tag_clos_var,
|
||||
this_encoder_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Encode.tag "A" [ Encode.toEncoder v1, Encode.toEncoder v2 ]
|
||||
|
@ -905,6 +929,7 @@ fn to_encoder_tag_union(
|
|||
tag_union_var_slice,
|
||||
fn_clos_var,
|
||||
this_encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -918,6 +943,7 @@ fn to_encoder_tag_union(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: this_encoder_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -973,6 +999,7 @@ fn wrap_in_encode_custom(
|
|||
this_append_with_args_var_slice,
|
||||
this_append_with_clos_var,
|
||||
Variable::LIST_U8,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -986,6 +1013,7 @@ fn wrap_in_encode_custom(
|
|||
Loc::at_zero(Var(Symbol::ENCODE_APPEND_WITH, this_append_with_fn_var)),
|
||||
this_append_with_clos_var,
|
||||
Variable::LIST_U8,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Encode.appendWith bytes encoder fmt
|
||||
|
@ -1022,7 +1050,12 @@ fn wrap_in_encode_custom(
|
|||
let args_slice = env.subs.insert_into_vars(vec![bytes_var, fmt_var]);
|
||||
env.subs.set_content(
|
||||
fn_var,
|
||||
Content::Structure(FlatType::Func(args_slice, fn_clos_var, Variable::LIST_U8)),
|
||||
Content::Structure(FlatType::Func(
|
||||
args_slice,
|
||||
fn_clos_var,
|
||||
Variable::LIST_U8,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
// \bytes, fmt -[[fn_name captured_var]]-> Encode.appendWith bytes encoder fmt
|
||||
|
@ -1030,6 +1063,7 @@ fn wrap_in_encode_custom(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: Variable::LIST_U8,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![(captured_symbol, captured_var)],
|
||||
|
@ -1065,6 +1099,7 @@ fn wrap_in_encode_custom(
|
|||
this_custom_args_var_slice,
|
||||
this_custom_clos_var,
|
||||
this_custom_encoder_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -1078,6 +1113,7 @@ fn wrap_in_encode_custom(
|
|||
Loc::at_zero(Var(Symbol::ENCODE_CUSTOM, this_custom_fn_var)),
|
||||
this_custom_clos_var, // -[clos]->
|
||||
this_custom_encoder_var, // t' ~ Encoder fmt
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Encode.custom \bytes, fmt -> Encode.appendWith bytes encoder fmt
|
||||
|
|
|
@ -475,6 +475,7 @@ fn call_hash_ability_member(
|
|||
this_arguments_slice,
|
||||
this_hash_clos_var,
|
||||
this_out_hasher_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -489,6 +490,7 @@ fn call_hash_ability_member(
|
|||
Loc::at_zero(hash_fn_head),
|
||||
this_hash_clos_var,
|
||||
this_out_hasher_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
let hash_arguments = vec![
|
||||
|
@ -532,7 +534,12 @@ fn build_outer_derived_closure(
|
|||
let args_slice = env.subs.insert_into_vars([hasher_var, val_var]);
|
||||
env.subs.set_content(
|
||||
fn_var,
|
||||
Content::Structure(FlatType::Func(args_slice, fn_clos_var, body_var)),
|
||||
Content::Structure(FlatType::Func(
|
||||
args_slice,
|
||||
fn_clos_var,
|
||||
body_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
(fn_var, fn_clos_var)
|
||||
|
@ -542,6 +549,7 @@ fn build_outer_derived_closure(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: body_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![],
|
||||
|
|
|
@ -137,6 +137,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
elem_var_slice,
|
||||
to_inspector_clos_var,
|
||||
elem_inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -152,6 +153,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
Loc::at_zero(to_inspector_var),
|
||||
to_inspector_clos_var,
|
||||
elem_inspector_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// toInspector elem
|
||||
|
@ -186,6 +188,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
elem_var_slice,
|
||||
to_elem_inspector_lset,
|
||||
elem_inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -194,6 +197,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
function_type: to_elem_inspector_fn_var,
|
||||
closure_type: to_elem_inspector_lset,
|
||||
return_type: elem_inspector_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: to_elem_inspector_sym,
|
||||
captured_symbols: vec![],
|
||||
|
@ -223,6 +227,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
this_inspect_list_args_slice,
|
||||
this_inspect_list_clos_var,
|
||||
this_list_inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -237,6 +242,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
Loc::at_zero(inspect_list),
|
||||
this_inspect_list_clos_var,
|
||||
this_list_inspector_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Inspect.list lst to_elem_inspector
|
||||
|
@ -285,6 +291,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
list_var_slice,
|
||||
fn_clos_var,
|
||||
this_inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -293,6 +300,7 @@ fn to_inspector_list(env: &mut Env<'_>, fn_name: Symbol) -> (Expr, Variable) {
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: this_inspector_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -365,6 +373,7 @@ fn to_inspector_record(
|
|||
field_var_slice,
|
||||
to_inspector_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -380,6 +389,7 @@ fn to_inspector_record(
|
|||
Loc::at_zero(to_inspector_var),
|
||||
to_inspector_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// toInspector rcd.a
|
||||
|
@ -447,6 +457,7 @@ fn to_inspector_record(
|
|||
fields_list_var_slice,
|
||||
inspect_record_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -461,6 +472,7 @@ fn to_inspector_record(
|
|||
Loc::at_zero(inspect_record_var),
|
||||
inspect_record_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Inspect.record [ { key: .., value: .. }, .. ]
|
||||
|
@ -496,6 +508,7 @@ fn to_inspector_record(
|
|||
record_var_slice,
|
||||
fn_clos_var,
|
||||
this_inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -504,6 +517,7 @@ fn to_inspector_record(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: this_inspector_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -569,6 +583,7 @@ fn to_inspector_tuple(
|
|||
elem_var_slice,
|
||||
to_inspector_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -584,6 +599,7 @@ fn to_inspector_tuple(
|
|||
Loc::at_zero(to_inspector_var),
|
||||
to_inspector_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// toInspector tup.0
|
||||
|
@ -631,6 +647,7 @@ fn to_inspector_tuple(
|
|||
elem_inspectors_list_var_slice,
|
||||
inspect_tuple_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -645,6 +662,7 @@ fn to_inspector_tuple(
|
|||
Loc::at_zero(inspect_tuple_var),
|
||||
inspect_tuple_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Inspect.tuple [ { key: .., value: .. }, .. ]
|
||||
|
@ -680,6 +698,7 @@ fn to_inspector_tuple(
|
|||
tuple_var_slice,
|
||||
fn_clos_var,
|
||||
this_inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -688,6 +707,7 @@ fn to_inspector_tuple(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: this_inspector_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -770,6 +790,7 @@ fn to_inspector_tag_union(
|
|||
var_slice_of_sym_var,
|
||||
to_inspector_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -785,6 +806,7 @@ fn to_inspector_tag_union(
|
|||
Loc::at_zero(to_inspector_var),
|
||||
to_inspector_clos_var,
|
||||
inspector_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// toInspector rcd.a
|
||||
|
@ -834,6 +856,7 @@ fn to_inspector_tag_union(
|
|||
this_inspect_tag_args_var_slice,
|
||||
this_inspect_tag_clos_var,
|
||||
this_inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -848,6 +871,7 @@ fn to_inspector_tag_union(
|
|||
Loc::at_zero(inspect_tag_var),
|
||||
this_inspect_tag_clos_var,
|
||||
this_inspector_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Inspect.tag "A" [ Inspect.toInspector v1, Inspect.toInspector v2 ]
|
||||
|
@ -922,6 +946,7 @@ fn to_inspector_tag_union(
|
|||
tag_union_var_slice,
|
||||
fn_clos_var,
|
||||
this_inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -935,6 +960,7 @@ fn to_inspector_tag_union(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: this_inspector_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![],
|
||||
|
@ -979,6 +1005,7 @@ fn wrap_in_inspect_custom(
|
|||
this_apply_args_var_slice,
|
||||
this_apply_clos_var,
|
||||
fmt_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -992,6 +1019,7 @@ fn wrap_in_inspect_custom(
|
|||
Loc::at_zero(Var(Symbol::INSPECT_APPLY, this_apply_fn_var)),
|
||||
this_apply_clos_var,
|
||||
fmt_var,
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Inspect.apply inspector fmt
|
||||
|
@ -1026,7 +1054,12 @@ fn wrap_in_inspect_custom(
|
|||
let args_slice = env.subs.insert_into_vars(vec![fmt_var]);
|
||||
env.subs.set_content(
|
||||
fn_var,
|
||||
Content::Structure(FlatType::Func(args_slice, fn_clos_var, fmt_var)),
|
||||
Content::Structure(FlatType::Func(
|
||||
args_slice,
|
||||
fn_clos_var,
|
||||
fmt_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
// \fmt -[[fn_name captured_var]]-> Inspect.apply inspector fmt
|
||||
|
@ -1034,6 +1067,7 @@ fn wrap_in_inspect_custom(
|
|||
function_type: fn_var,
|
||||
closure_type: fn_clos_var,
|
||||
return_type: fmt_var,
|
||||
fx_type: Variable::PURE,
|
||||
early_returns: vec![],
|
||||
name: fn_name,
|
||||
captured_symbols: vec![(captured_symbol, captured_var)],
|
||||
|
@ -1062,6 +1096,7 @@ fn wrap_in_inspect_custom(
|
|||
this_custom_args_var_slice,
|
||||
this_custom_clos_var,
|
||||
this_custom_inspector_var,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
|
||||
|
@ -1075,6 +1110,7 @@ fn wrap_in_inspect_custom(
|
|||
Loc::at_zero(Var(Symbol::INSPECT_CUSTOM, this_custom_fn_var)),
|
||||
this_custom_clos_var, // -[clos]->
|
||||
this_custom_inspector_var, // t' ~ Inspector fmt
|
||||
Variable::PURE,
|
||||
));
|
||||
|
||||
// Inspect.custom \fmt -> Inspect.apply inspector fmt
|
||||
|
|
|
@ -4,6 +4,7 @@ use std::iter::once;
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use roc_can::abilities::SpecializationLambdaSets;
|
||||
use roc_can::def::DefKind;
|
||||
use roc_can::expr::Expr;
|
||||
use roc_can::pattern::Pattern;
|
||||
use roc_can::{def::Def, module::ExposedByModule};
|
||||
|
@ -90,6 +91,7 @@ fn build_derived_body(
|
|||
expr_var: body_type,
|
||||
pattern_vars: once((derived_symbol, body_type)).collect(),
|
||||
annotation: None,
|
||||
kind: DefKind::Let,
|
||||
};
|
||||
|
||||
(def, specialization_lambda_sets)
|
||||
|
|
|
@ -81,7 +81,7 @@ impl FlatDecodable {
|
|||
Err(Underivable) // yet
|
||||
}
|
||||
//
|
||||
FlatType::Func(..) => Err(Underivable),
|
||||
FlatType::Func(..) | FlatType::EffectfulFunc => Err(Underivable),
|
||||
},
|
||||
Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) {
|
||||
Some(lambda) => lambda,
|
||||
|
@ -101,6 +101,7 @@ impl FlatDecodable {
|
|||
| Content::FlexAbleVar(_, _)
|
||||
| Content::RigidAbleVar(_, _) => Err(UnboundVar),
|
||||
Content::LambdaSet(_) | Content::ErasedLambda => Err(Underivable),
|
||||
Content::Pure | Content::Effectful => Err(Underivable),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ impl FlatEncodable {
|
|||
}
|
||||
FlatType::EmptyRecord => Ok(Key(FlatEncodableKey::Record(vec![]))),
|
||||
FlatType::EmptyTagUnion => Ok(Key(FlatEncodableKey::TagUnion(vec![]))),
|
||||
FlatType::Func(..) => Err(Underivable),
|
||||
FlatType::Func(..) | FlatType::EffectfulFunc => Err(Underivable),
|
||||
},
|
||||
Content::Alias(sym, _, real_var, _) => match from_builtin_symbol(sym) {
|
||||
Some(lambda) => lambda,
|
||||
|
@ -135,6 +135,7 @@ impl FlatEncodable {
|
|||
| Content::FlexAbleVar(_, _)
|
||||
| Content::RigidAbleVar(_, _) => Err(UnboundVar),
|
||||
Content::LambdaSet(_) | Content::ErasedLambda => Err(Underivable),
|
||||
Content::Pure | Content::Effectful => Err(Underivable),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -112,7 +112,7 @@ impl FlatHash {
|
|||
FlatType::EmptyRecord => Ok(Key(FlatHashKey::Record(vec![]))),
|
||||
FlatType::EmptyTagUnion => Ok(Key(FlatHashKey::TagUnion(vec![]))),
|
||||
//
|
||||
FlatType::Func(..) => Err(Underivable),
|
||||
FlatType::Func(..) | FlatType::EffectfulFunc => Err(Underivable),
|
||||
},
|
||||
Content::Alias(sym, _, real_var, _) => match builtin_symbol_to_hash_lambda(sym) {
|
||||
Some(lambda) => Ok(lambda),
|
||||
|
@ -146,6 +146,7 @@ impl FlatHash {
|
|||
| Content::FlexAbleVar(_, _)
|
||||
| Content::RigidAbleVar(_, _) => Err(UnboundVar),
|
||||
Content::LambdaSet(_) | Content::ErasedLambda => Err(Underivable),
|
||||
Content::Pure | Content::Effectful => Err(Underivable),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,9 @@ impl FlatInspectable {
|
|||
FlatType::EmptyRecord => Key(FlatInspectableKey::Record(Vec::new())),
|
||||
FlatType::EmptyTagUnion => Key(FlatInspectableKey::TagUnion(Vec::new())),
|
||||
FlatType::Func(..) => Immediate(Symbol::INSPECT_FUNCTION),
|
||||
FlatType::EffectfulFunc => {
|
||||
unreachable!("There must have been a bug in the solver, because we're trying to derive Inspect on a non-concrete type.");
|
||||
}
|
||||
},
|
||||
Content::Alias(sym, _, real_var, kind) => match Self::from_builtin_alias(sym) {
|
||||
Some(lambda) => lambda,
|
||||
|
@ -178,7 +181,9 @@ impl FlatInspectable {
|
|||
| Content::FlexAbleVar(_, _)
|
||||
| Content::RigidAbleVar(_, _)
|
||||
| Content::LambdaSet(_)
|
||||
| Content::ErasedLambda => {
|
||||
| Content::ErasedLambda
|
||||
| Content::Pure
|
||||
| Content::Effectful => {
|
||||
unreachable!("There must have been a bug in the solver, because we're trying to derive Inspect on a non-concrete type.");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,8 +4,8 @@ use crate::{
|
|||
Buf,
|
||||
};
|
||||
use roc_parse::ast::{
|
||||
AbilityImpls, AssignedField, Collection, Expr, ExtractSpaces, ImplementsAbilities,
|
||||
ImplementsAbility, ImplementsClause, Tag, TypeAnnotation, TypeHeader,
|
||||
AbilityImpls, AssignedField, Collection, Expr, ExtractSpaces, FunctionArrow,
|
||||
ImplementsAbilities, ImplementsAbility, ImplementsClause, Tag, TypeAnnotation, TypeHeader,
|
||||
};
|
||||
use roc_parse::ident::UppercaseIdent;
|
||||
use roc_region::all::Loc;
|
||||
|
@ -149,7 +149,7 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
}
|
||||
|
||||
Wildcard | Inferred | BoundVariable(_) | Malformed(_) => false,
|
||||
Function(args, result) => {
|
||||
Function(args, _arrow, result) => {
|
||||
result.value.is_multiline()
|
||||
|| args.iter().any(|loc_arg| loc_arg.value.is_multiline())
|
||||
}
|
||||
|
@ -195,7 +195,7 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
let self_is_multiline = self.is_multiline();
|
||||
|
||||
match self {
|
||||
Function(args, ret) => {
|
||||
Function(args, arrow, ret) => {
|
||||
let needs_parens = parens != Parens::NotNeeded;
|
||||
|
||||
buf.indent(indent);
|
||||
|
@ -236,7 +236,11 @@ impl<'a> Formattable for TypeAnnotation<'a> {
|
|||
buf.spaces(1);
|
||||
}
|
||||
|
||||
buf.push_str("->");
|
||||
match arrow {
|
||||
FunctionArrow::Pure => buf.push_str("->"),
|
||||
FunctionArrow::Effectful => buf.push_str("=>"),
|
||||
}
|
||||
|
||||
buf.spaces(1);
|
||||
|
||||
ret.value
|
||||
|
|
|
@ -4,6 +4,7 @@ use crate::expr::fmt_str_literal;
|
|||
use crate::pattern::fmt_pattern;
|
||||
use crate::spaces::{fmt_default_newline, fmt_default_spaces, fmt_spaces, INDENT};
|
||||
use crate::Buf;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_parse::ast::{
|
||||
AbilityMember, Defs, Expr, ExtractSpaces, ImportAlias, ImportAsKeyword, ImportExposingKeyword,
|
||||
ImportedModuleName, IngestedFileAnnotation, IngestedFileImport, ModuleImport,
|
||||
|
@ -423,6 +424,7 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
ModuleImport(module_import) => module_import.is_multiline(),
|
||||
IngestedFileImport(ingested_file_import) => ingested_file_import.is_multiline(),
|
||||
Stmt(loc_expr) => loc_expr.is_multiline(),
|
||||
StmtAfterExpr => internal_error!("shouldn't exist before can"),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,6 +466,7 @@ impl<'a> Formattable for ValueDef<'a> {
|
|||
ModuleImport(module_import) => module_import.format(buf, indent),
|
||||
IngestedFileImport(ingested_file_import) => ingested_file_import.format(buf, indent),
|
||||
Stmt(loc_expr) => loc_expr.format_with_options(buf, parens, newlines, indent),
|
||||
StmtAfterExpr => internal_error!("shouldn't exist before can"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4324,7 +4324,7 @@ fn expose_function_to_host<'a, 'ctx>(
|
|||
return_layout: InLayout<'a>,
|
||||
layout_ids: &mut LayoutIds<'a>,
|
||||
) {
|
||||
let ident_string = symbol.as_str(&env.interns);
|
||||
let ident_string = symbol.as_unsuffixed_str(&env.interns);
|
||||
|
||||
let proc_layout = ProcLayout {
|
||||
arguments,
|
||||
|
@ -5564,7 +5564,7 @@ pub fn build_procedures<'a>(
|
|||
let getter_fn = function_value_by_func_spec(env, FuncBorrowSpec::Some(*func_spec), symbol);
|
||||
|
||||
let name = getter_fn.get_name().to_str().unwrap();
|
||||
let getter_name = symbol.as_str(&env.interns);
|
||||
let getter_name = symbol.as_unsuffixed_str(&env.interns);
|
||||
|
||||
// Add the getter function to the module.
|
||||
let _ = expose_function_to_host_help_c_abi(
|
||||
|
@ -5830,7 +5830,7 @@ fn build_procedures_help<'a>(
|
|||
GenTest | WasmGenTest | CliTest => { /* no host, or exposing types is not supported */ }
|
||||
Binary | BinaryDev | BinaryGlue => {
|
||||
for (proc_name, alias_name, hels) in host_exposed_lambda_sets.iter() {
|
||||
let ident_string = proc_name.name().as_str(&env.interns);
|
||||
let ident_string = proc_name.name().as_unsuffixed_str(&env.interns);
|
||||
let fn_name: String = format!("{}_{}", ident_string, hels.id.0);
|
||||
|
||||
expose_alias_to_host(
|
||||
|
|
|
@ -177,6 +177,7 @@ pub fn can_expr_with<'a>(
|
|||
&dep_idents,
|
||||
&module_ids,
|
||||
None,
|
||||
roc_can::env::FxMode::PurityInference,
|
||||
);
|
||||
|
||||
// Desugar operators (convert them to Apply calls, taking into account
|
||||
|
@ -203,6 +204,7 @@ pub fn can_expr_with<'a>(
|
|||
rigids: MutMap::default(),
|
||||
home,
|
||||
resolutions_to_make: vec![],
|
||||
fx_expectation: None,
|
||||
},
|
||||
loc_expr.region,
|
||||
&loc_expr.value,
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,8 +4,8 @@ use roc_can::scope::Scope;
|
|||
use roc_collections::VecSet;
|
||||
use roc_module::ident::ModuleName;
|
||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||
use roc_parse::ast::AssignedField;
|
||||
use roc_parse::ast::{self, ExtractSpaces, TypeHeader};
|
||||
use roc_parse::ast::{AssignedField, FunctionArrow};
|
||||
use roc_parse::ast::{CommentOrNewline, TypeDef, ValueDef};
|
||||
|
||||
// Documentation generation requirements
|
||||
|
@ -53,6 +53,7 @@ pub enum TypeAnnotation {
|
|||
},
|
||||
Function {
|
||||
args: Vec<TypeAnnotation>,
|
||||
arrow: FunctionArrow,
|
||||
output: Box<TypeAnnotation>,
|
||||
},
|
||||
ObscuredTagUnion,
|
||||
|
@ -282,6 +283,10 @@ fn generate_entry_docs(
|
|||
// Don't generate docs for ingested file imports
|
||||
}
|
||||
|
||||
ValueDef::StmtAfterExpr { .. } => {
|
||||
// Ignore. Canonicalization will produce an error.
|
||||
}
|
||||
|
||||
ValueDef::Stmt(loc_expr) => {
|
||||
if let roc_parse::ast::Expr::Var {
|
||||
ident: identifier, ..
|
||||
|
@ -443,7 +448,7 @@ fn contains_unexposed_type(
|
|||
|
||||
Malformed(_) | Inferred | Wildcard | BoundVariable(_) => false,
|
||||
|
||||
Function(loc_args, loc_ret) => {
|
||||
Function(loc_args, _arrow, loc_ret) => {
|
||||
let loc_args_contains_unexposed_type = loc_args.iter().any(|loc_arg| {
|
||||
contains_unexposed_type(&loc_arg.value, exposed_module_ids, module_ids)
|
||||
});
|
||||
|
@ -611,7 +616,7 @@ fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) ->
|
|||
ast::TypeAnnotation::SpaceAfter(&sub_type_ann, _) => {
|
||||
type_to_docs(in_func_type_ann, sub_type_ann)
|
||||
}
|
||||
ast::TypeAnnotation::Function(ast_arg_anns, output_ann) => {
|
||||
ast::TypeAnnotation::Function(ast_arg_anns, arrow, output_ann) => {
|
||||
let mut doc_arg_anns = Vec::new();
|
||||
|
||||
for ast_arg_ann in ast_arg_anns {
|
||||
|
@ -620,6 +625,7 @@ fn type_to_docs(in_func_type_ann: bool, type_annotation: ast::TypeAnnotation) ->
|
|||
|
||||
Function {
|
||||
args: doc_arg_anns,
|
||||
arrow,
|
||||
output: Box::new(type_to_docs(true, output_ann.value)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ use parking_lot::Mutex;
|
|||
use roc_builtins::roc::module_source;
|
||||
use roc_can::abilities::{AbilitiesStore, PendingAbilitiesStore, ResolvedImpl};
|
||||
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints, TypeOrVar};
|
||||
use roc_can::env::FxMode;
|
||||
use roc_can::expr::{DbgLookup, Declarations, ExpectLookup, PendingDerives};
|
||||
use roc_can::module::{
|
||||
canonicalize_module_defs, ExposedByModule, ExposedForModule, ExposedModuleTypes, Module,
|
||||
|
@ -33,7 +34,7 @@ use roc_debug_flags::{
|
|||
use roc_derive::SharedDerivedModule;
|
||||
use roc_error_macros::internal_error;
|
||||
use roc_late_solve::{AbilitiesView, WorldAbilities};
|
||||
use roc_module::ident::{Ident, ModuleName, QualifiedModuleName};
|
||||
use roc_module::ident::{Ident, IdentSuffix, ModuleName, QualifiedModuleName};
|
||||
use roc_module::symbol::{
|
||||
IdentIds, IdentIdsByModule, Interns, ModuleId, ModuleIds, PQModuleName, PackageModuleIds,
|
||||
PackageQualified, Symbol,
|
||||
|
@ -318,6 +319,7 @@ fn start_phase<'a>(
|
|||
exposed_module_ids: state.exposed_modules,
|
||||
exec_mode: state.exec_mode,
|
||||
imported_module_params,
|
||||
fx_mode: state.fx_mode,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -710,6 +712,7 @@ struct State<'a> {
|
|||
pub platform_path: PlatformPath<'a>,
|
||||
pub target: Target,
|
||||
pub(self) function_kind: FunctionKind,
|
||||
pub fx_mode: FxMode,
|
||||
|
||||
/// Note: only packages and platforms actually expose any modules;
|
||||
/// for all others, this will be empty.
|
||||
|
@ -797,6 +800,7 @@ impl<'a> State<'a> {
|
|||
cache_dir,
|
||||
target,
|
||||
function_kind,
|
||||
fx_mode: FxMode::Task,
|
||||
platform_data: None,
|
||||
platform_path: PlatformPath::NotSpecified,
|
||||
module_cache: ModuleCache::default(),
|
||||
|
@ -900,6 +904,7 @@ enum BuildTask<'a> {
|
|||
skip_constraint_gen: bool,
|
||||
exec_mode: ExecutionMode,
|
||||
imported_module_params: VecMap<ModuleId, ModuleParams>,
|
||||
fx_mode: FxMode,
|
||||
},
|
||||
Solve {
|
||||
module: Module,
|
||||
|
@ -2235,6 +2240,7 @@ fn update<'a>(
|
|||
config_shorthand,
|
||||
provides,
|
||||
exposes_ids,
|
||||
requires,
|
||||
..
|
||||
} => {
|
||||
work.extend(state.dependencies.notify_package(config_shorthand));
|
||||
|
@ -2269,6 +2275,12 @@ fn update<'a>(
|
|||
if header.is_root_module {
|
||||
state.exposed_modules = exposes_ids;
|
||||
}
|
||||
|
||||
if requires.iter().any(|requires| {
|
||||
IdentSuffix::from_name(requires.value.ident.value).is_bang()
|
||||
}) {
|
||||
state.fx_mode = FxMode::PurityInference;
|
||||
}
|
||||
}
|
||||
Builtin { .. } | Module { .. } => {
|
||||
if header.is_root_module {
|
||||
|
@ -2276,11 +2288,18 @@ fn update<'a>(
|
|||
state.platform_path = PlatformPath::RootIsModule;
|
||||
}
|
||||
}
|
||||
Hosted { .. } => {
|
||||
Hosted { exposes, .. } => {
|
||||
if header.is_root_module {
|
||||
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||
state.platform_path = PlatformPath::RootIsHosted;
|
||||
}
|
||||
|
||||
if exposes
|
||||
.iter()
|
||||
.any(|exposed| exposed.value.is_effectful_fn())
|
||||
{
|
||||
state.fx_mode = FxMode::PurityInference;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4394,7 +4413,12 @@ fn synth_list_len_type(subs: &mut Subs) -> Variable {
|
|||
let fn_args_slice = slice_extend_new(&mut subs.variables, [list_a]);
|
||||
subs.set_content(
|
||||
fn_var,
|
||||
Content::Structure(FlatType::Func(fn_args_slice, clos_list_len, Variable::U64)),
|
||||
Content::Structure(FlatType::Func(
|
||||
fn_args_slice,
|
||||
clos_list_len,
|
||||
Variable::U64,
|
||||
Variable::PURE,
|
||||
)),
|
||||
);
|
||||
fn_var
|
||||
}
|
||||
|
@ -5050,6 +5074,7 @@ fn canonicalize_and_constrain<'a>(
|
|||
exposed_module_ids: &[ModuleId],
|
||||
exec_mode: ExecutionMode,
|
||||
imported_module_params: VecMap<ModuleId, ModuleParams>,
|
||||
fx_mode: FxMode,
|
||||
) -> CanAndCon {
|
||||
let canonicalize_start = Instant::now();
|
||||
|
||||
|
@ -5093,6 +5118,7 @@ fn canonicalize_and_constrain<'a>(
|
|||
&symbols_from_requires,
|
||||
&mut var_store,
|
||||
opt_shorthand,
|
||||
fx_mode,
|
||||
);
|
||||
|
||||
let mut types = Types::new();
|
||||
|
@ -6276,6 +6302,7 @@ fn run_task<'a>(
|
|||
exposed_module_ids,
|
||||
exec_mode,
|
||||
imported_module_params,
|
||||
fx_mode,
|
||||
} => {
|
||||
let can_and_con = canonicalize_and_constrain(
|
||||
arena,
|
||||
|
@ -6289,6 +6316,7 @@ fn run_task<'a>(
|
|||
exposed_module_ids,
|
||||
exec_mode,
|
||||
imported_module_params,
|
||||
fx_mode,
|
||||
);
|
||||
|
||||
Ok(Msg::CanonicalizedAndConstrained(can_and_con))
|
||||
|
|
|
@ -846,49 +846,6 @@ fn platform_does_not_exist() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn platform_parse_error() {
|
||||
let modules = vec![
|
||||
(
|
||||
"platform/main.roc",
|
||||
indoc!(
|
||||
r#"
|
||||
platform "hello-c"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
blah 1 2 3 # causing a parse error on purpose
|
||||
|
||||
mainForHost : Str
|
||||
"#
|
||||
),
|
||||
),
|
||||
(
|
||||
"main.roc",
|
||||
indoc!(
|
||||
r#"
|
||||
app "hello-world"
|
||||
packages { pf: "platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
main = "Hello, World!\n"
|
||||
"#
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
match multiple_modules("platform_parse_error", modules) {
|
||||
Err(report) => {
|
||||
assert!(report.contains("STATEMENT AFTER EXPRESSION"));
|
||||
assert!(report.contains("blah 1 2 3 # causing a parse error on purpose"));
|
||||
}
|
||||
Ok(_) => unreachable!("we expect failure here"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
// See https://github.com/roc-lang/roc/issues/2413
|
||||
fn platform_exposes_main_return_by_pointer_issue() {
|
||||
|
|
|
@ -92,7 +92,7 @@ impl<'a> LowerParams<'a> {
|
|||
.retain(|(sym, _)| !home_param_symbols.contains(sym));
|
||||
|
||||
if let Some(ann) = &mut decls.annotations[index] {
|
||||
if let Type::Function(args, _, _) = &mut ann.signature {
|
||||
if let Type::Function(args, _, _, _) = &mut ann.signature {
|
||||
args.push(Type::Variable(var));
|
||||
}
|
||||
}
|
||||
|
@ -218,6 +218,7 @@ impl<'a> LowerParams<'a> {
|
|||
captured_symbols: _,
|
||||
name: _,
|
||||
function_type: _,
|
||||
fx_type: _,
|
||||
closure_type: _,
|
||||
return_type: _,
|
||||
early_returns: _,
|
||||
|
@ -519,6 +520,7 @@ impl<'a> LowerParams<'a> {
|
|||
Loc::at_zero(Var(symbol, var)),
|
||||
self.var_store.fresh(),
|
||||
self.var_store.fresh(),
|
||||
self.var_store.fresh(),
|
||||
));
|
||||
|
||||
let body = Call(
|
||||
|
@ -539,6 +541,7 @@ impl<'a> LowerParams<'a> {
|
|||
function_type: self.var_store.fresh(),
|
||||
closure_type: self.var_store.fresh(),
|
||||
return_type: self.var_store.fresh(),
|
||||
fx_type: self.var_store.fresh(),
|
||||
early_returns: vec![],
|
||||
name: self.unique_symbol(),
|
||||
captured_symbols,
|
||||
|
@ -563,6 +566,7 @@ impl<'a> LowerParams<'a> {
|
|||
Loc::at_zero(Var(symbol, var)),
|
||||
self.var_store.fresh(),
|
||||
self.var_store.fresh(),
|
||||
self.var_store.fresh(),
|
||||
));
|
||||
|
||||
Call(
|
||||
|
|
|
@ -57,8 +57,8 @@ pub fn remove_module_param_arguments(
|
|||
drop_last_argument(expected);
|
||||
|
||||
if let (
|
||||
ErrorType::Function(found_args, _, _),
|
||||
ErrorType::Function(expected_args, _, _),
|
||||
ErrorType::Function(found_args, _, _, _),
|
||||
ErrorType::Function(expected_args, _, _, _),
|
||||
) = (found, expected)
|
||||
{
|
||||
if found_args.len() > expected_args.len() {
|
||||
|
@ -99,7 +99,12 @@ pub fn remove_module_param_arguments(
|
|||
| TypeError::IngestedFileUnsupportedType(_, _)
|
||||
| TypeError::UnexpectedModuleParams(_, _)
|
||||
| TypeError::MissingModuleParams(_, _, _)
|
||||
| TypeError::ModuleParamsMismatch(_, _, _, _) => {}
|
||||
| TypeError::ModuleParamsMismatch(_, _, _, _)
|
||||
| TypeError::FxInPureFunction(_, _, _)
|
||||
| TypeError::FxInTopLevel(_, _)
|
||||
| TypeError::ExpectedEffectful(_, _)
|
||||
| TypeError::UnsuffixedEffectfulFunction(_, _)
|
||||
| TypeError::SuffixedPureFunction(_, _) => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -182,13 +187,14 @@ fn remove_for_reason(
|
|||
}
|
||||
| Reason::CrashArg
|
||||
| Reason::ImportParams(_)
|
||||
| Reason::Stmt(_)
|
||||
| Reason::FunctionOutput => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn drop_last_argument(err_type: &mut ErrorType) {
|
||||
match err_type {
|
||||
ErrorType::Function(arguments, _, _) => {
|
||||
ErrorType::Function(arguments, _, _, _) => {
|
||||
arguments.pop();
|
||||
}
|
||||
// Irrelevant
|
||||
|
@ -204,6 +210,7 @@ fn drop_last_argument(err_type: &mut ErrorType) {
|
|||
| ErrorType::RecursiveTagUnion(_, _, _, _)
|
||||
| ErrorType::Alias(_, _, _, _)
|
||||
| ErrorType::Range(_)
|
||||
| ErrorType::Error => {}
|
||||
| ErrorType::Error
|
||||
| ErrorType::EffectfulFunc => {}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -236,6 +236,10 @@ impl Lowercase {
|
|||
pub fn as_str(&self) -> &str {
|
||||
self.0.as_str()
|
||||
}
|
||||
|
||||
pub fn suffix(&self) -> IdentSuffix {
|
||||
IdentSuffix::from_name(self.0.as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Lowercase> for String {
|
||||
|
@ -362,3 +366,67 @@ impl fmt::Display for Uppercase {
|
|||
fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum IdentSuffix {
|
||||
None,
|
||||
Bang,
|
||||
}
|
||||
|
||||
impl IdentSuffix {
|
||||
#[inline(always)]
|
||||
pub const fn from_name(name: &str) -> Self {
|
||||
// Checking bytes directly so it can be const.
|
||||
// This should be fine since the suffix is ASCII.
|
||||
let bytes = name.as_bytes();
|
||||
let len = bytes.len();
|
||||
|
||||
debug_assert!(len > 0, "Ident name must not be empty");
|
||||
|
||||
if bytes[len - 1] == b'!' {
|
||||
IdentSuffix::Bang
|
||||
} else {
|
||||
IdentSuffix::None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_none(&self) -> bool {
|
||||
match self {
|
||||
IdentSuffix::None => true,
|
||||
IdentSuffix::Bang => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_bang(&self) -> bool {
|
||||
match self {
|
||||
IdentSuffix::None => false,
|
||||
IdentSuffix::Bang => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod suffix_test {
|
||||
use crate::ident::IdentSuffix;
|
||||
|
||||
#[test]
|
||||
fn ends_with_bang() {
|
||||
assert_eq!(IdentSuffix::from_name("foo!"), IdentSuffix::Bang)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ends_without_bang() {
|
||||
assert_eq!(IdentSuffix::from_name("foo"), IdentSuffix::None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid() {
|
||||
assert_eq!(IdentSuffix::from_name("foo!bar"), IdentSuffix::None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic]
|
||||
fn empty_panics() {
|
||||
IdentSuffix::from_name("");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::ident::{Ident, Lowercase, ModuleName};
|
||||
use crate::ident::{Ident, IdentSuffix, Lowercase, ModuleName};
|
||||
use crate::module_err::{ModuleError, ModuleResult};
|
||||
use roc_collections::{SmallStringInterner, VecMap};
|
||||
use roc_error_macros::internal_error;
|
||||
|
@ -79,7 +79,7 @@ impl Symbol {
|
|||
|
||||
Self {
|
||||
module_id: module_id.0,
|
||||
ident_id: ident_id.0,
|
||||
ident_id: ident_id.raw(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -88,13 +88,17 @@ impl Symbol {
|
|||
}
|
||||
|
||||
pub const fn ident_id(self) -> IdentId {
|
||||
IdentId(self.ident_id)
|
||||
IdentId::from_raw(self.ident_id)
|
||||
}
|
||||
|
||||
pub const fn is_builtin(self) -> bool {
|
||||
self.module_id().is_builtin()
|
||||
}
|
||||
|
||||
pub const fn suffix(self) -> IdentSuffix {
|
||||
self.ident_id().suffix()
|
||||
}
|
||||
|
||||
pub fn is_derivable_ability(self) -> bool {
|
||||
self.derivable_ability().is_some()
|
||||
}
|
||||
|
@ -146,12 +150,16 @@ impl Symbol {
|
|||
.unwrap_or_else(|| {
|
||||
internal_error!(
|
||||
"ident_string's IdentIds did not contain an entry for {} in module {:?}",
|
||||
self.ident_id().0,
|
||||
self.ident_id().index(),
|
||||
self.module_id()
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_unsuffixed_str(self, interns: &Interns) -> &str {
|
||||
self.as_str(interns).trim_end_matches('!')
|
||||
}
|
||||
|
||||
pub const fn as_u64(self) -> u64 {
|
||||
u64::from_ne_bytes(self.to_ne_bytes())
|
||||
}
|
||||
|
@ -246,11 +254,9 @@ impl fmt::Debug for Symbol {
|
|||
impl fmt::Display for Symbol {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let module_id = self.module_id();
|
||||
let ident_id = self.ident_id();
|
||||
let ident_id = self.ident_id().index();
|
||||
|
||||
match ident_id {
|
||||
IdentId(value) => write!(f, "{module_id:?}.{value:?}"),
|
||||
}
|
||||
write!(f, "{module_id:?}.{ident_id:?}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,10 +325,6 @@ impl Interns {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_index(module_id: ModuleId, ident_id: u32) -> Symbol {
|
||||
Symbol::new(module_id, IdentId(ident_id))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_module_ident_ids<'a>(
|
||||
|
@ -637,28 +639,59 @@ impl ModuleIds {
|
|||
}
|
||||
}
|
||||
|
||||
/// An ID that is assigned to interned string identifiers within a module.
|
||||
/// By turning these strings into numbers, post-canonicalization processes
|
||||
/// like unification and optimization can run a lot faster.
|
||||
///
|
||||
/// This ID is unique within a given module, not globally - so to turn this back into
|
||||
/// a string, you would need a ModuleId, an IdentId, and a Map<ModuleId, Map<IdentId, String>>.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct IdentId(u32);
|
||||
mod ident_id {
|
||||
use crate::ident::IdentSuffix;
|
||||
|
||||
impl IdentId {
|
||||
pub const fn index(self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
/// An ID that is assigned to interned string identifiers within a module.
|
||||
/// By turning these strings into numbers, post-canonicalization processes
|
||||
/// like unification and optimization can run a lot faster.
|
||||
///
|
||||
/// The index is not guaranteed to know to exist.
|
||||
pub unsafe fn from_index(index: u32) -> Self {
|
||||
Self(index)
|
||||
/// This ID is unique within a given module, not globally - so to turn this back into
|
||||
/// a string, you would need a ModuleId, an IdentId, and a Map<ModuleId, Map<IdentId, String>>.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub struct IdentId(u32);
|
||||
|
||||
const BANG_FLAG: u32 = 1u32 << 31;
|
||||
const UNSUFFIXED: u32 = !BANG_FLAG;
|
||||
|
||||
impl IdentId {
|
||||
pub const fn index(self) -> usize {
|
||||
(self.0 & UNSUFFIXED) as usize
|
||||
}
|
||||
|
||||
pub const fn suffix(self) -> IdentSuffix {
|
||||
if self.0 & BANG_FLAG > 0 {
|
||||
IdentSuffix::Bang
|
||||
} else {
|
||||
IdentSuffix::None
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) const fn raw(self) -> u32 {
|
||||
self.0
|
||||
}
|
||||
|
||||
pub(super) const fn from_raw(raw: u32) -> Self {
|
||||
Self(raw)
|
||||
}
|
||||
|
||||
pub(super) const fn from_index(index: usize, suffix: IdentSuffix) -> Self {
|
||||
assert!(index as u32 <= UNSUFFIXED, "IdentId index too large");
|
||||
|
||||
match suffix {
|
||||
IdentSuffix::None => Self(index as u32),
|
||||
IdentSuffix::Bang => Self((index as u32) | BANG_FLAG),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) const fn from_index_named(index: usize, name: &str) -> Self {
|
||||
Self::from_index(index, IdentSuffix::from_name(name))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub use ident_id::IdentId;
|
||||
|
||||
/// Stores a mapping between Ident and IdentId.
|
||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||
pub struct IdentIds {
|
||||
|
@ -670,15 +703,15 @@ impl IdentIds {
|
|||
self.interner
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(index, ident)| (IdentId(index as u32), ident))
|
||||
.map(|(index, ident)| (IdentId::from_index_named(index, ident), ident))
|
||||
}
|
||||
|
||||
pub fn add_str(&mut self, ident_name: &str) -> IdentId {
|
||||
IdentId(self.interner.insert(ident_name) as u32)
|
||||
IdentId::from_index_named(self.interner.insert(ident_name), ident_name)
|
||||
}
|
||||
|
||||
pub fn duplicate_ident(&mut self, ident_id: IdentId) -> IdentId {
|
||||
IdentId(self.interner.duplicate(ident_id.0 as usize) as u32)
|
||||
IdentId::from_index(self.interner.duplicate(ident_id.index()), ident_id.suffix())
|
||||
}
|
||||
|
||||
pub fn get_or_insert(&mut self, name: &str) -> IdentId {
|
||||
|
@ -692,7 +725,7 @@ impl IdentIds {
|
|||
// TODO fix when same ident_name is present multiple times, see issue #2548
|
||||
pub fn update_key(&mut self, old_name: &str, new_name: &str) -> Result<IdentId, String> {
|
||||
match self.interner.find_and_update(old_name, new_name) {
|
||||
Some(index) => Ok(IdentId(index as u32)),
|
||||
Some(index) => Ok(IdentId::from_index_named(index, new_name)),
|
||||
None => Err(format!("The identifier {old_name:?} is not in IdentIds")),
|
||||
}
|
||||
}
|
||||
|
@ -705,12 +738,12 @@ impl IdentIds {
|
|||
/// This is used, for example, during canonicalization of an Expr::Closure
|
||||
/// to generate a unique symbol to refer to that closure.
|
||||
pub fn gen_unique(&mut self) -> IdentId {
|
||||
IdentId(self.interner.insert_index_str() as u32)
|
||||
IdentId::from_index(self.interner.insert_index_str(), IdentSuffix::None)
|
||||
}
|
||||
|
||||
pub fn is_generated_id(&self, id: IdentId) -> bool {
|
||||
self.interner
|
||||
.try_get(id.0 as usize)
|
||||
.try_get(id.index())
|
||||
.map_or(false, |str| str.starts_with(|c: char| c.is_ascii_digit()))
|
||||
}
|
||||
|
||||
|
@ -718,18 +751,18 @@ impl IdentIds {
|
|||
pub fn get_id(&self, ident_name: &str) -> Option<IdentId> {
|
||||
self.interner
|
||||
.find_index(ident_name)
|
||||
.map(|i| IdentId(i as u32))
|
||||
.map(|i| IdentId::from_index_named(i, ident_name))
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn get_id_many<'a>(&'a self, ident_name: &'a str) -> impl Iterator<Item = IdentId> + 'a {
|
||||
self.interner
|
||||
.find_indices(ident_name)
|
||||
.map(|i| IdentId(i as u32))
|
||||
.map(|i| IdentId::from_index_named(i, ident_name))
|
||||
}
|
||||
|
||||
pub fn get_name(&self, id: IdentId) -> Option<&str> {
|
||||
self.interner.try_get(id.0 as usize)
|
||||
self.interner.try_get(id.index())
|
||||
}
|
||||
|
||||
pub fn get_name_str_res(&self, ident_id: IdentId) -> ModuleResult<&str> {
|
||||
|
@ -1013,10 +1046,10 @@ macro_rules! define_builtins {
|
|||
$(
|
||||
$(
|
||||
$(#[$ident_meta])*
|
||||
pub const $ident_const: Symbol = Symbol::new(ModuleId::$module_const, IdentId($ident_id));
|
||||
pub const $ident_const: Symbol = Symbol::new(ModuleId::$module_const, IdentId::from_index_named($ident_id, $ident_name));
|
||||
)*
|
||||
$(
|
||||
pub const $u_ident_const: Symbol = Symbol::new(ModuleId::$module_const, IdentId($u_ident_id));
|
||||
pub const $u_ident_const: Symbol = Symbol::new(ModuleId::$module_const, IdentId::from_index_named($u_ident_id, $u_ident_name));
|
||||
)*
|
||||
)+
|
||||
|
||||
|
@ -1038,9 +1071,11 @@ macro_rules! define_builtins {
|
|||
// release builds, this condition is either `if true`
|
||||
// or `if false` and will get optimized out.
|
||||
debug_assert_eq!($exposed_apply_type, $ident_name.chars().next().unwrap().is_uppercase());
|
||||
// Types should not be suffixed
|
||||
debug_assert!(IdentSuffix::from_name($ident_name).is_none());
|
||||
|
||||
if $exposed_apply_type {
|
||||
scope.insert($ident_name.into(), (Symbol::new(ModuleId::$module_const, IdentId($ident_id)), Region::zero()));
|
||||
scope.insert($ident_name.into(), (Symbol::new(ModuleId::$module_const, IdentId::from_index($ident_id, IdentSuffix::None)), Region::zero()));
|
||||
}
|
||||
)?
|
||||
)*
|
||||
|
@ -1059,7 +1094,7 @@ macro_rules! define_builtins {
|
|||
$(
|
||||
$(
|
||||
if $exposed_type {
|
||||
($ident_name, (Symbol::new(ModuleId::$module_const, IdentId($ident_id)), Region::zero()))
|
||||
($ident_name, (Symbol::new(ModuleId::$module_const, IdentId::from_raw($ident_id)), Region::zero()))
|
||||
} else {
|
||||
unreachable!()
|
||||
},
|
||||
|
@ -1474,6 +1509,7 @@ define_builtins! {
|
|||
87 LIST_CLONE: "clone"
|
||||
88 LIST_LEN_USIZE: "lenUsize"
|
||||
89 LIST_CONCAT_UTF8: "concatUtf8"
|
||||
90 LIST_WALK_FX: "walk!"
|
||||
}
|
||||
7 RESULT: "Result" => {
|
||||
0 RESULT_RESULT: "Result" exposed_type=true // the Result.Result type alias
|
||||
|
|
|
@ -2482,6 +2482,9 @@ fn from_can_let<'a>(
|
|||
|
||||
lower_rest!(variable, cont.value)
|
||||
}
|
||||
ImportParams(_, _, None) => {
|
||||
lower_rest!(variable, cont.value)
|
||||
}
|
||||
Var(original, _) | AbilityMember(original, _, _)
|
||||
if procs.get_partial_proc(original).is_none() =>
|
||||
{
|
||||
|
@ -2617,6 +2620,7 @@ fn from_can_let<'a>(
|
|||
expr_var: def.expr_var,
|
||||
pattern_vars: std::iter::once((anon_name, def.expr_var)).collect(),
|
||||
annotation: None,
|
||||
kind: def.kind,
|
||||
});
|
||||
|
||||
// f = #lam
|
||||
|
@ -2626,6 +2630,7 @@ fn from_can_let<'a>(
|
|||
expr_var: def.expr_var,
|
||||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
kind: def.kind,
|
||||
});
|
||||
|
||||
let new_inner = LetNonRec(new_def, cont);
|
||||
|
@ -2645,6 +2650,7 @@ fn from_can_let<'a>(
|
|||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
expr_var: def.expr_var,
|
||||
kind: def.kind,
|
||||
};
|
||||
|
||||
let new_inner = LetNonRec(Box::new(new_def), cont);
|
||||
|
@ -2684,6 +2690,7 @@ fn from_can_let<'a>(
|
|||
pattern_vars: def.pattern_vars,
|
||||
annotation: def.annotation,
|
||||
expr_var: def.expr_var,
|
||||
kind: def.kind,
|
||||
};
|
||||
|
||||
let new_inner = LetNonRec(Box::new(new_def), cont);
|
||||
|
@ -4491,7 +4498,7 @@ pub fn with_hole<'a>(
|
|||
|
||||
debug_assert!(!matches!(
|
||||
env.subs.get_content_without_compacting(variant_var),
|
||||
Content::Structure(FlatType::Func(_, _, _))
|
||||
Content::Structure(FlatType::Func(_, _, _, _))
|
||||
));
|
||||
convert_tag_union(
|
||||
env,
|
||||
|
@ -4516,7 +4523,7 @@ pub fn with_hole<'a>(
|
|||
|
||||
let content = env.subs.get_content_without_compacting(variable);
|
||||
|
||||
if let Content::Structure(FlatType::Func(arg_vars, _, ret_var)) = content {
|
||||
if let Content::Structure(FlatType::Func(arg_vars, _, ret_var, _fx_var)) = content {
|
||||
let ret_var = *ret_var;
|
||||
let arg_vars = *arg_vars;
|
||||
|
||||
|
@ -5452,7 +5459,7 @@ pub fn with_hole<'a>(
|
|||
}
|
||||
|
||||
Call(boxed, loc_args, _) => {
|
||||
let (fn_var, loc_expr, _lambda_set_var, _ret_var) = *boxed;
|
||||
let (fn_var, loc_expr, _lambda_set_var, _ret_var, _fx_var) = *boxed;
|
||||
|
||||
// even if a call looks like it's by name, it may in fact be by-pointer.
|
||||
// E.g. in `(\f, x -> f x)` the call is in fact by pointer.
|
||||
|
@ -6160,7 +6167,7 @@ fn late_resolve_ability_specialization(
|
|||
if let Some(spec_symbol) = opt_resolved {
|
||||
// Fast path: specialization is monomorphic, was found during solving.
|
||||
spec_symbol
|
||||
} else if let Content::Structure(FlatType::Func(_, lambda_set, _)) =
|
||||
} else if let Content::Structure(FlatType::Func(_, lambda_set, _, _fx_var)) =
|
||||
env.subs.get_content_without_compacting(specialization_var)
|
||||
{
|
||||
// Fast path: the member is a function, so the lambda set will tell us the
|
||||
|
@ -6885,7 +6892,7 @@ fn register_capturing_closure<'a>(
|
|||
let is_self_recursive = !matches!(recursive, roc_can::expr::Recursive::NotRecursive);
|
||||
|
||||
let captured_symbols = match *env.subs.get_content_without_compacting(function_type) {
|
||||
Content::Structure(FlatType::Func(args, closure_var, ret)) => {
|
||||
Content::Structure(FlatType::Func(args, closure_var, ret, _fx_var)) => {
|
||||
let lambda_set_layout = {
|
||||
LambdaSet::from_var_pub(
|
||||
layout_cache,
|
||||
|
@ -7289,6 +7296,7 @@ fn to_opt_branches<'a>(
|
|||
roc_can::pattern::Pattern::Identifier(symbol),
|
||||
),
|
||||
pattern_vars: std::iter::once((symbol, variable)).collect(),
|
||||
kind: roc_can::def::DefKind::Let,
|
||||
};
|
||||
let new_expr =
|
||||
roc_can::expr::Expr::LetNonRec(Box::new(def), Box::new(loc_expr));
|
||||
|
@ -10089,7 +10097,7 @@ pub fn find_lambda_sets(
|
|||
|
||||
// ignore the lambda set of top-level functions
|
||||
match subs.get_without_compacting(initial).content {
|
||||
Content::Structure(FlatType::Func(arguments, _, result)) => {
|
||||
Content::Structure(FlatType::Func(arguments, _, result, _fx)) => {
|
||||
let arguments = &subs.variables[arguments.indices()];
|
||||
|
||||
stack.extend(arguments.iter().copied());
|
||||
|
@ -10126,7 +10134,7 @@ fn find_lambda_sets_help(
|
|||
FlatType::Apply(_, arguments) => {
|
||||
stack.extend(subs.get_subs_slice(*arguments).iter().rev());
|
||||
}
|
||||
FlatType::Func(arguments, lambda_set_var, ret_var) => {
|
||||
FlatType::Func(arguments, lambda_set_var, ret_var, _fx_var) => {
|
||||
use std::collections::hash_map::Entry;
|
||||
// Only insert a lambda_set_var if we didn't already have a value for this key.
|
||||
if let Entry::Vacant(entry) = result.entry(*lambda_set_var) {
|
||||
|
@ -10172,6 +10180,7 @@ fn find_lambda_sets_help(
|
|||
}
|
||||
FlatType::EmptyRecord => {}
|
||||
FlatType::EmptyTagUnion => {}
|
||||
FlatType::EffectfulFunc => {}
|
||||
},
|
||||
Content::Alias(_, _, actual, _) => {
|
||||
stack.push(*actual);
|
||||
|
@ -10185,6 +10194,7 @@ fn find_lambda_sets_help(
|
|||
}
|
||||
}
|
||||
Content::ErasedLambda => {}
|
||||
Content::Pure | Content::Effectful => {}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -515,6 +515,7 @@ impl<'a> RawFunctionLayout<'a> {
|
|||
internal_error!("lambda set should only appear under a function, where it's handled independently.");
|
||||
}
|
||||
ErasedLambda => internal_error!("erased lambda type should only appear under a function, where it's handled independently"),
|
||||
Pure | Effectful => internal_error!("fx vars should only appear under a function"),
|
||||
Structure(flat_type) => Self::layout_from_flat_type(env, flat_type),
|
||||
RangedNumber(..) => Layout::new_help(env, var, content).then(Self::ZeroArgumentThunk),
|
||||
|
||||
|
@ -592,7 +593,7 @@ impl<'a> RawFunctionLayout<'a> {
|
|||
let arena = env.arena;
|
||||
|
||||
match flat_type {
|
||||
Func(args, closure_var, ret_var) => {
|
||||
Func(args, closure_var, ret_var, _fx_var) => {
|
||||
let mut fn_args = Vec::with_capacity_in(args.len(), arena);
|
||||
|
||||
let mut cache_criteria = CACHEABLE;
|
||||
|
@ -2150,7 +2151,7 @@ fn lambda_set_size(subs: &Subs, var: Variable) -> (usize, usize, usize) {
|
|||
stack.push((*var, depth_any + 1, depth_lset));
|
||||
}
|
||||
}
|
||||
FlatType::Func(args, lset, ret) => {
|
||||
FlatType::Func(args, lset, ret, _fx_var) => {
|
||||
for var in subs.get_subs_slice(*args) {
|
||||
stack.push((*var, depth_any + 1, depth_lset));
|
||||
}
|
||||
|
@ -2191,7 +2192,7 @@ fn lambda_set_size(subs: &Subs, var: Variable) -> (usize, usize, usize) {
|
|||
}
|
||||
stack.push((ext.var(), depth_any + 1, depth_lset));
|
||||
}
|
||||
FlatType::EmptyRecord | FlatType::EmptyTagUnion => {}
|
||||
FlatType::EmptyRecord | FlatType::EmptyTagUnion | FlatType::EffectfulFunc => {}
|
||||
},
|
||||
Content::FlexVar(_)
|
||||
| Content::RigidVar(_)
|
||||
|
@ -2199,7 +2200,9 @@ fn lambda_set_size(subs: &Subs, var: Variable) -> (usize, usize, usize) {
|
|||
| Content::RigidAbleVar(_, _)
|
||||
| Content::RangedNumber(_)
|
||||
| Content::Error
|
||||
| Content::ErasedLambda => {}
|
||||
| Content::ErasedLambda
|
||||
| Content::Pure
|
||||
| Content::Effectful => {}
|
||||
}
|
||||
}
|
||||
(max_depth_any_ctor, max_depth_only_lset, total)
|
||||
|
@ -2479,6 +2482,9 @@ impl<'a> Layout<'a> {
|
|||
ErasedLambda => {
|
||||
internal_error!("erased lambda type should only appear under a function, where it's handled independently.");
|
||||
}
|
||||
Pure | Effectful => {
|
||||
internal_error!("fx vars should only appear under a function, where they're handled independently.");
|
||||
}
|
||||
Structure(flat_type) => layout_from_flat_type(env, flat_type),
|
||||
|
||||
Alias(symbol, _args, actual_var, _) => {
|
||||
|
@ -3315,7 +3321,7 @@ fn layout_from_flat_type<'a>(
|
|||
}
|
||||
}
|
||||
}
|
||||
Func(args, closure_var, ret_var) => {
|
||||
Func(args, closure_var, ret_var, _fx_var) => {
|
||||
if env.is_seen(closure_var) {
|
||||
// TODO(recursive-layouts): after the naked pointer is updated, we can cache `var` to
|
||||
// point to the updated layout.
|
||||
|
@ -3459,6 +3465,9 @@ fn layout_from_flat_type<'a>(
|
|||
}
|
||||
EmptyTagUnion => cacheable(Ok(Layout::VOID)),
|
||||
EmptyRecord => cacheable(Ok(Layout::UNIT)),
|
||||
EffectfulFunc => {
|
||||
internal_error!("Cannot create a layout for an unconstrained EffectfulFunc")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4598,7 +4607,7 @@ fn layout_from_num_content<'a>(content: &Content) -> Cacheable<LayoutResult<'a>>
|
|||
Alias(_, _, _, _) => {
|
||||
todo!("TODO recursively resolve type aliases in num_from_content");
|
||||
}
|
||||
Structure(_) | RangedNumber(..) | LambdaSet(_) | ErasedLambda => {
|
||||
Structure(_) | RangedNumber(..) | LambdaSet(_) | ErasedLambda | Pure | Effectful => {
|
||||
panic!("Invalid Num.Num type application: {content:?}");
|
||||
}
|
||||
Error => Err(LayoutProblem::Erroneous),
|
||||
|
@ -4640,7 +4649,7 @@ impl LayoutId {
|
|||
// Returns something like "#UserApp_foo_1" when given a symbol that interns to "foo"
|
||||
// and a LayoutId of 1.
|
||||
pub fn to_symbol_string(self, symbol: Symbol, interns: &Interns) -> String {
|
||||
let ident_string = symbol.as_str(interns);
|
||||
let ident_string = symbol.as_unsuffixed_str(interns);
|
||||
let module_string = interns.module_ids.get_name(symbol.module_id()).unwrap();
|
||||
format!("{}_{}_{}", module_string, ident_string, self.0)
|
||||
}
|
||||
|
@ -4648,12 +4657,12 @@ impl LayoutId {
|
|||
// Returns something like "roc__foo_1_exposed" when given a symbol that interns to "foo"
|
||||
// and a LayoutId of 1.
|
||||
pub fn to_exposed_symbol_string(self, symbol: Symbol, interns: &Interns) -> String {
|
||||
let ident_string = symbol.as_str(interns);
|
||||
let ident_string = symbol.as_unsuffixed_str(interns);
|
||||
format!("roc__{}_{}_exposed", ident_string, self.0)
|
||||
}
|
||||
|
||||
pub fn to_exposed_generic_symbol_string(self, symbol: Symbol, interns: &Interns) -> String {
|
||||
let ident_string = symbol.as_str(interns);
|
||||
let ident_string = symbol.as_unsuffixed_str(interns);
|
||||
format!("roc__{}_{}_exposed_generic", ident_string, self.0)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -394,6 +394,7 @@ pub enum StrLiteral<'a> {
|
|||
/// Values that can be tried, extracting success values or "returning early" on failure
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum TryTarget {
|
||||
// TODO: Remove when purity inference replaces Task fully
|
||||
/// Tasks suffixed with ! are `Task.await`ed
|
||||
Task,
|
||||
/// Results suffixed with ? are `Result.try`ed
|
||||
|
@ -841,6 +842,8 @@ pub enum ValueDef<'a> {
|
|||
IngestedFileImport(IngestedFileImport<'a>),
|
||||
|
||||
Stmt(&'a Loc<Expr<'a>>),
|
||||
|
||||
StmtAfterExpr,
|
||||
}
|
||||
|
||||
impl<'a> ValueDef<'a> {
|
||||
|
@ -1093,7 +1096,9 @@ impl<'a, 'b> Iterator for RecursiveValueDefIter<'a, 'b> {
|
|||
}
|
||||
}
|
||||
ValueDef::Stmt(loc_expr) => self.push_pending_from_expr(&loc_expr.value),
|
||||
ValueDef::Annotation(_, _) | ValueDef::IngestedFileImport(_) => {}
|
||||
ValueDef::Annotation(_, _)
|
||||
| ValueDef::IngestedFileImport(_)
|
||||
| ValueDef::StmtAfterExpr => {}
|
||||
}
|
||||
|
||||
self.index += 1;
|
||||
|
@ -1530,10 +1535,22 @@ impl ImplementsAbilities<'_> {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum FunctionArrow {
|
||||
/// ->
|
||||
Pure,
|
||||
/// =>
|
||||
Effectful,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
pub enum TypeAnnotation<'a> {
|
||||
/// A function. The types of its arguments, then the type of its return value.
|
||||
Function(&'a [Loc<TypeAnnotation<'a>>], &'a Loc<TypeAnnotation<'a>>),
|
||||
/// A function. The types of its arguments, the type of arrow used, then the type of its return value.
|
||||
Function(
|
||||
&'a [Loc<TypeAnnotation<'a>>],
|
||||
FunctionArrow,
|
||||
&'a Loc<TypeAnnotation<'a>>,
|
||||
),
|
||||
|
||||
/// Applying a type to some arguments (e.g. Map.Map String Int)
|
||||
Apply(&'a str, &'a str, &'a [Loc<TypeAnnotation<'a>>]),
|
||||
|
@ -2740,6 +2757,7 @@ impl<'a> Malformed for ValueDef<'a> {
|
|||
annotation,
|
||||
}) => path.is_malformed() || annotation.is_malformed(),
|
||||
ValueDef::Stmt(loc_expr) => loc_expr.is_malformed(),
|
||||
ValueDef::StmtAfterExpr => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2755,7 +2773,7 @@ impl<'a> Malformed for ModuleImportParams<'a> {
|
|||
impl<'a> Malformed for TypeAnnotation<'a> {
|
||||
fn is_malformed(&self) -> bool {
|
||||
match self {
|
||||
TypeAnnotation::Function(args, ret) => {
|
||||
TypeAnnotation::Function(args, _arrow, ret) => {
|
||||
args.iter().any(|arg| arg.is_malformed()) || ret.is_malformed()
|
||||
}
|
||||
TypeAnnotation::Apply(_, _, args) => args.iter().any(|arg| arg.is_malformed()),
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue