mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
Merge branch 'trunk' into sqrt-unchecked
This commit is contained in:
commit
d236c28743
59 changed files with 2378 additions and 1138 deletions
3
AUTHORS
3
AUTHORS
|
@ -74,3 +74,6 @@ Ananda Umamil <zweimach@zweimach.org>
|
||||||
SylvanSign <jake.d.bray@gmail.com>
|
SylvanSign <jake.d.bray@gmail.com>
|
||||||
Nikita Mounier <36044205+nikitamounier@users.noreply.github.com>
|
Nikita Mounier <36044205+nikitamounier@users.noreply.github.com>
|
||||||
Cai Bingjun <62678643+C-BJ@users.noreply.github.com>
|
Cai Bingjun <62678643+C-BJ@users.noreply.github.com>
|
||||||
|
Jared Cone <jared.cone@gmail.com>
|
||||||
|
Sean Hagstrom <sean@seanhagstrom.com>
|
||||||
|
Kas Buunk <kasbuunk@icloud.com>
|
||||||
|
|
|
@ -107,7 +107,7 @@ To run the test suite (via `cargo test`), you additionally need to install:
|
||||||
* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781)
|
* [`valgrind`](https://www.valgrind.org/) (needs special treatment to [install on macOS](https://stackoverflow.com/a/61359781)
|
||||||
Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests.
|
Alternatively, you can use `cargo test --no-fail-fast` or `cargo test -p specific_tests` to skip over the valgrind failures & tests.
|
||||||
|
|
||||||
For debugging LLVM IR, we use [DebugIR](https://github.com/vaivaswatha/debugir). This dependency is only required to build with the `--debug` flag, and for normal developtment you should be fine without it.
|
For debugging LLVM IR, we use [DebugIR](https://github.com/vaivaswatha/debugir). This dependency is only required to build with the `--debug` flag, and for normal development you should be fine without it.
|
||||||
|
|
||||||
### libxcb libraries
|
### libxcb libraries
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,7 @@ pub const FLAG_NO_LINK: &str = "no-link";
|
||||||
pub const FLAG_TARGET: &str = "target";
|
pub const FLAG_TARGET: &str = "target";
|
||||||
pub const FLAG_TIME: &str = "time";
|
pub const FLAG_TIME: &str = "time";
|
||||||
pub const FLAG_LINK: &str = "roc-linker";
|
pub const FLAG_LINK: &str = "roc-linker";
|
||||||
|
pub const FLAG_LINKER: &str = "linker";
|
||||||
pub const FLAG_PRECOMPILED: &str = "precompiled-host";
|
pub const FLAG_PRECOMPILED: &str = "precompiled-host";
|
||||||
pub const FLAG_VALGRIND: &str = "valgrind";
|
pub const FLAG_VALGRIND: &str = "valgrind";
|
||||||
pub const FLAG_CHECK: &str = "check";
|
pub const FLAG_CHECK: &str = "check";
|
||||||
|
@ -112,13 +113,21 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(FLAG_LINK)
|
Arg::new(FLAG_LINK)
|
||||||
.long(FLAG_LINK)
|
.long(FLAG_LINK)
|
||||||
.about("Uses the roc linker instead of the system linker.")
|
.about("Deprecated in favor of --linker")
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(FLAG_LINKER)
|
||||||
|
.long(FLAG_LINKER)
|
||||||
|
.about("Sets which linker to use. The surgical linker is enabeld by default only when building for wasm32 or x86_64 Linux, because those are the only targets it currently supports. Otherwise the legacy linker is used by default.")
|
||||||
|
.possible_values(["surgical", "legacy"])
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(FLAG_PRECOMPILED)
|
Arg::new(FLAG_PRECOMPILED)
|
||||||
.long(FLAG_PRECOMPILED)
|
.long(FLAG_PRECOMPILED)
|
||||||
.about("Assumes the host has been precompiled and skips recompiling the host.")
|
.about("Assumes the host has been precompiled and skips recompiling the host. (Enabled by default when using a --target other than `--target host`)")
|
||||||
|
.possible_values(["true", "false"])
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -209,13 +218,21 @@ pub fn build_app<'a>() -> App<'a> {
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(FLAG_LINK)
|
Arg::new(FLAG_LINK)
|
||||||
.long(FLAG_LINK)
|
.long(FLAG_LINK)
|
||||||
.about("Uses the roc linker instead of the system linker.")
|
.about("Deprecated in favor of --linker")
|
||||||
|
.required(false),
|
||||||
|
)
|
||||||
|
.arg(
|
||||||
|
Arg::new(FLAG_LINKER)
|
||||||
|
.long(FLAG_LINKER)
|
||||||
|
.about("Sets which linker to use. The surgical linker is enabeld by default only when building for wasm32 or x86_64 Linux, because those are the only targets it currently supports. Otherwise the legacy linker is used by default.")
|
||||||
|
.possible_values(["surgical", "legacy"])
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new(FLAG_PRECOMPILED)
|
Arg::new(FLAG_PRECOMPILED)
|
||||||
.long(FLAG_PRECOMPILED)
|
.long(FLAG_PRECOMPILED)
|
||||||
.about("Assumes the host has been precompiled and skips recompiling the host.")
|
.about("Assumes the host has been precompiled and skips recompiling the host. (Enabled by default when using a --target other than `--target host`)")
|
||||||
|
.possible_values(["true", "false"])
|
||||||
.required(false),
|
.required(false),
|
||||||
)
|
)
|
||||||
.arg(
|
.arg(
|
||||||
|
@ -309,16 +326,27 @@ pub fn build(matches: &ArgMatches, config: BuildConfig) -> io::Result<i32> {
|
||||||
(false, true) => LinkType::None,
|
(false, true) => LinkType::None,
|
||||||
(false, false) => LinkType::Executable,
|
(false, false) => LinkType::Executable,
|
||||||
};
|
};
|
||||||
let surgically_link = matches.is_present(FLAG_LINK);
|
|
||||||
let precompiled = matches.is_present(FLAG_PRECOMPILED);
|
|
||||||
|
|
||||||
if surgically_link && !roc_linker::supported(&link_type, &triple) {
|
// TODO remove FLAG_LINK from the code base anytime after the end of May 2022
|
||||||
panic!(
|
if matches.is_present(FLAG_LINK) {
|
||||||
"Link type, {:?}, with target, {}, not supported by roc linker",
|
eprintln!("ERROR: The --roc-linker flag has been deprecated because the roc linker is now used automatically where it's supported. (Currently that's only x64 Linux.) No need to use --roc-linker anymore, but you can use the --linker flag to switch linkers.");
|
||||||
link_type, triple
|
process::exit(1);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use surgical linking when supported, or when explicitly requested with --linker surgical
|
||||||
|
let surgically_link = if matches.is_present(FLAG_LINKER) {
|
||||||
|
matches.value_of(FLAG_LINKER) == Some("surgical")
|
||||||
|
} else {
|
||||||
|
roc_linker::supported(&link_type, &triple)
|
||||||
|
};
|
||||||
|
|
||||||
|
let precompiled = if matches.is_present(FLAG_PRECOMPILED) {
|
||||||
|
matches.value_of(FLAG_PRECOMPILED) == Some("true")
|
||||||
|
} else {
|
||||||
|
// When compiling for a different target, default to assuming a precompiled host.
|
||||||
|
// Otherwise compilation would most likely fail!
|
||||||
|
target != Target::System
|
||||||
|
};
|
||||||
let path = Path::new(filename);
|
let path = Path::new(filename);
|
||||||
|
|
||||||
// Spawn the root task
|
// Spawn the root task
|
||||||
|
@ -509,8 +537,9 @@ fn run_with_wasmer(_wasm_path: &std::path::Path, _args: &[String]) {
|
||||||
println!("Running wasm files not support");
|
println!("Running wasm files not support");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
enum Target {
|
enum Target {
|
||||||
Host,
|
System,
|
||||||
Linux32,
|
Linux32,
|
||||||
Linux64,
|
Linux64,
|
||||||
Wasm32,
|
Wasm32,
|
||||||
|
@ -518,7 +547,7 @@ enum Target {
|
||||||
|
|
||||||
impl Default for Target {
|
impl Default for Target {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Target::Host
|
Target::System
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,7 +556,7 @@ impl Target {
|
||||||
use Target::*;
|
use Target::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Host => "host",
|
System => "system",
|
||||||
Linux32 => "linux32",
|
Linux32 => "linux32",
|
||||||
Linux64 => "linux64",
|
Linux64 => "linux64",
|
||||||
Wasm32 => "wasm32",
|
Wasm32 => "wasm32",
|
||||||
|
@ -536,17 +565,17 @@ impl Target {
|
||||||
|
|
||||||
/// NOTE keep up to date!
|
/// NOTE keep up to date!
|
||||||
const OPTIONS: &'static [&'static str] = &[
|
const OPTIONS: &'static [&'static str] = &[
|
||||||
Target::Host.as_str(),
|
Target::System.as_str(),
|
||||||
Target::Linux32.as_str(),
|
Target::Linux32.as_str(),
|
||||||
Target::Linux64.as_str(),
|
Target::Linux64.as_str(),
|
||||||
Target::Wasm32.as_str(),
|
Target::Wasm32.as_str(),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn to_triple(&self) -> Triple {
|
fn to_triple(self) -> Triple {
|
||||||
use Target::*;
|
use Target::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Host => Triple::host(),
|
System => Triple::host(),
|
||||||
Linux32 => Triple {
|
Linux32 => Triple {
|
||||||
architecture: Architecture::X86_32(X86_32Architecture::I386),
|
architecture: Architecture::X86_32(X86_32Architecture::I386),
|
||||||
vendor: Vendor::Unknown,
|
vendor: Vendor::Unknown,
|
||||||
|
@ -589,7 +618,7 @@ impl std::str::FromStr for Target {
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
match s {
|
match s {
|
||||||
"host" => Ok(Target::Host),
|
"system" => Ok(Target::System),
|
||||||
"linux32" => Ok(Target::Linux32),
|
"linux32" => Ok(Target::Linux32),
|
||||||
"linux64" => Ok(Target::Linux64),
|
"linux64" => Ok(Target::Linux64),
|
||||||
"wasm32" => Ok(Target::Wasm32),
|
"wasm32" => Ok(Target::Wasm32),
|
||||||
|
|
|
@ -2,13 +2,11 @@
|
||||||
extern crate pretty_assertions;
|
extern crate pretty_assertions;
|
||||||
|
|
||||||
extern crate bumpalo;
|
extern crate bumpalo;
|
||||||
|
extern crate indoc;
|
||||||
extern crate roc_collections;
|
extern crate roc_collections;
|
||||||
extern crate roc_load;
|
extern crate roc_load;
|
||||||
extern crate roc_module;
|
extern crate roc_module;
|
||||||
|
|
||||||
#[macro_use]
|
|
||||||
extern crate indoc;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod cli_run {
|
mod cli_run {
|
||||||
use cli_utils::helpers::{
|
use cli_utils::helpers::{
|
||||||
|
@ -25,11 +23,12 @@ mod cli_run {
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
|
|
||||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||||
const TEST_SURGICAL_LINKER: bool = true;
|
const TEST_LEGACY_LINKER: bool = true;
|
||||||
|
|
||||||
// Surgical linker currently only supports linux x86_64.
|
// Surgical linker currently only supports linux x86_64,
|
||||||
|
// so we're always testing the legacy linker on other targets.
|
||||||
#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
|
#[cfg(not(all(target_os = "linux", target_arch = "x86_64")))]
|
||||||
const TEST_SURGICAL_LINKER: bool = false;
|
const TEST_LEGACY_LINKER: bool = false;
|
||||||
|
|
||||||
#[cfg(not(target_os = "macos"))]
|
#[cfg(not(target_os = "macos"))]
|
||||||
const ALLOW_VALGRIND: bool = true;
|
const ALLOW_VALGRIND: bool = true;
|
||||||
|
@ -228,6 +227,7 @@ mod cli_run {
|
||||||
($($test_name:ident:$name:expr => $example:expr,)+) => {
|
($($test_name:ident:$name:expr => $example:expr,)+) => {
|
||||||
$(
|
$(
|
||||||
#[test]
|
#[test]
|
||||||
|
#[allow(non_snake_case)]
|
||||||
fn $test_name() {
|
fn $test_name() {
|
||||||
let dir_name = $name;
|
let dir_name = $name;
|
||||||
let example = $example;
|
let example = $example;
|
||||||
|
@ -252,12 +252,7 @@ mod cli_run {
|
||||||
}
|
}
|
||||||
"hello-gui" => {
|
"hello-gui" => {
|
||||||
// Since this one requires opening a window, we do `roc build` on it but don't run it.
|
// Since this one requires opening a window, we do `roc build` on it but don't run it.
|
||||||
if cfg!(all(target_os = "linux", target_arch = "x86_64")) {
|
|
||||||
// The surgical linker can successfully link this on Linux, but the legacy linker errors!
|
|
||||||
build_example(&file_name, &["--optimize", "--roc-linker"]);
|
|
||||||
} else {
|
|
||||||
build_example(&file_name, &["--optimize"]);
|
build_example(&file_name, &["--optimize"]);
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -288,14 +283,14 @@ mod cli_run {
|
||||||
example.use_valgrind,
|
example.use_valgrind,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Also check with the surgical linker.
|
// Also check with the legacy linker.
|
||||||
|
|
||||||
if TEST_SURGICAL_LINKER {
|
if TEST_LEGACY_LINKER {
|
||||||
check_output_with_stdin(
|
check_output_with_stdin(
|
||||||
&file_name,
|
&file_name,
|
||||||
example.stdin,
|
example.stdin,
|
||||||
example.executable_filename,
|
example.executable_filename,
|
||||||
&["--roc-linker"],
|
&["--linker", "legacy"],
|
||||||
example.input_file.and_then(|file| Some(example_file(dir_name, file))),
|
example.input_file.and_then(|file| Some(example_file(dir_name, file))),
|
||||||
example.expected_ending,
|
example.expected_ending,
|
||||||
example.use_valgrind,
|
example.use_valgrind,
|
||||||
|
|
|
@ -468,8 +468,10 @@ fn strFromIntHelp(comptime T: type, int: T) RocStr {
|
||||||
const size = comptime blk: {
|
const size = comptime blk: {
|
||||||
// the string representation of the minimum i128 value uses at most 40 characters
|
// the string representation of the minimum i128 value uses at most 40 characters
|
||||||
var buf: [40]u8 = undefined;
|
var buf: [40]u8 = undefined;
|
||||||
var result = std.fmt.bufPrint(&buf, "{}", .{std.math.minInt(T)}) catch unreachable;
|
var resultMin = std.fmt.bufPrint(&buf, "{}", .{std.math.minInt(T)}) catch unreachable;
|
||||||
break :blk result.len;
|
var resultMax = std.fmt.bufPrint(&buf, "{}", .{std.math.maxInt(T)}) catch unreachable;
|
||||||
|
var result = if (resultMin.len > resultMax.len) resultMin.len else resultMax.len;
|
||||||
|
break :blk result;
|
||||||
};
|
};
|
||||||
|
|
||||||
var buf: [size]u8 = undefined;
|
var buf: [size]u8 = undefined;
|
||||||
|
|
|
@ -15,7 +15,10 @@ interface Dict
|
||||||
intersection,
|
intersection,
|
||||||
difference,
|
difference,
|
||||||
]
|
]
|
||||||
imports [ ]
|
imports
|
||||||
|
[
|
||||||
|
Bool.{ Bool }
|
||||||
|
]
|
||||||
|
|
||||||
empty : Dict k v
|
empty : Dict k v
|
||||||
single : k, v -> Dict k v
|
single : k, v -> Dict k v
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
interface List
|
||||||
|
exposes
|
||||||
|
[
|
||||||
isEmpty,
|
isEmpty,
|
||||||
get,
|
get,
|
||||||
set,
|
set,
|
||||||
|
@ -47,14 +50,23 @@ all,
|
||||||
dropIf,
|
dropIf,
|
||||||
sortAsc,
|
sortAsc,
|
||||||
sortDesc,
|
sortDesc,
|
||||||
|
]
|
||||||
|
imports
|
||||||
|
[
|
||||||
|
Bool.{ Bool }
|
||||||
|
]
|
||||||
|
|
||||||
isEmpty : List a -> Bool
|
isEmpty : List a -> Bool
|
||||||
isEmpty = \list ->
|
isEmpty = \list ->
|
||||||
List.len list == 0
|
List.len list == 0
|
||||||
|
|
||||||
get : List a, Nat -> Result a [ OutOfBounds ]*
|
get : List a, Nat -> Result a [ OutOfBounds ]*
|
||||||
set : List a, Nat, a -> List a
|
|
||||||
replace : List a, Nat, a -> { list : List a, value : a }
|
replace : List a, Nat, a -> { list : List a, value : a }
|
||||||
|
|
||||||
|
set : List a, Nat, a -> List a
|
||||||
|
set = \list, index, value ->
|
||||||
|
(List.replace list index value).list
|
||||||
|
|
||||||
append : List a, a -> List a
|
append : List a, a -> List a
|
||||||
prepend : List a, a -> List a
|
prepend : List a, a -> List a
|
||||||
len : List a -> Nat
|
len : List a -> Nat
|
||||||
|
@ -82,6 +94,8 @@ all : List a, (a -> Bool) -> Bool
|
||||||
|
|
||||||
keepIf : List a, (a -> Bool) -> List a
|
keepIf : List a, (a -> Bool) -> List a
|
||||||
dropIf : List a, (a -> Bool) -> List a
|
dropIf : List a, (a -> Bool) -> List a
|
||||||
|
dropIf = \list, predicate ->
|
||||||
|
List.keepIf list (\e -> Bool.not (predicate e))
|
||||||
|
|
||||||
keepOks : List before, (before -> Result after *) -> List after
|
keepOks : List before, (before -> Result after *) -> List after
|
||||||
keepErrs: List before, (before -> Result * after) -> List after
|
keepErrs: List before, (before -> Result * after) -> List after
|
||||||
|
@ -89,7 +103,7 @@ map : List a, (a -> b) -> List b
|
||||||
map2 : List a, List b, (a, b -> c) -> List c
|
map2 : List a, List b, (a, b -> c) -> List c
|
||||||
map3 : List a, List b, List c, (a, b, c -> d) -> List d
|
map3 : List a, List b, List c, (a, b, c -> d) -> List d
|
||||||
map4 : List a, List b, List c, List d, (a, b, c, d -> e) -> List e
|
map4 : List a, List b, List c, List d, (a, b, c, d -> e) -> List e
|
||||||
mapWithIndex : List a, (a -> b) -> List b
|
mapWithIndex : List a, (a, Nat -> b) -> List b
|
||||||
range : Int a, Int a -> List (Int a)
|
range : Int a, Int a -> List (Int a)
|
||||||
sortWith : List a, (a, a -> [ LT, EQ, GT ] ) -> List a
|
sortWith : List a, (a, a -> [ LT, EQ, GT ] ) -> List a
|
||||||
sortAsc : List (Num a) -> List (Num a)
|
sortAsc : List (Num a) -> List (Num a)
|
||||||
|
@ -112,9 +126,47 @@ drop : List elem, Nat -> List elem
|
||||||
dropAt : List elem, Nat -> List elem
|
dropAt : List elem, Nat -> List elem
|
||||||
|
|
||||||
min : List (Num a) -> Result (Num a) [ ListWasEmpty ]*
|
min : List (Num a) -> Result (Num a) [ ListWasEmpty ]*
|
||||||
|
min = \list ->
|
||||||
|
when List.first list is
|
||||||
|
Ok initial ->
|
||||||
|
Ok (minHelp list initial)
|
||||||
|
|
||||||
|
Err ListWasEmpty ->
|
||||||
|
Err ListWasEmpty
|
||||||
|
|
||||||
|
|
||||||
|
minHelp : List (Num a), Num a -> Num a
|
||||||
|
minHelp = \list, initial ->
|
||||||
|
List.walk list initial \bestSoFar, current ->
|
||||||
|
if current < bestSoFar then
|
||||||
|
current
|
||||||
|
|
||||||
|
else
|
||||||
|
bestSoFar
|
||||||
|
|
||||||
max : List (Num a) -> Result (Num a) [ ListWasEmpty ]*
|
max : List (Num a) -> Result (Num a) [ ListWasEmpty ]*
|
||||||
|
max = \list ->
|
||||||
|
when List.first list is
|
||||||
|
Ok initial ->
|
||||||
|
Ok (maxHelp list initial)
|
||||||
|
|
||||||
|
Err ListWasEmpty ->
|
||||||
|
Err ListWasEmpty
|
||||||
|
|
||||||
|
|
||||||
|
maxHelp : List (Num a), Num a -> Num a
|
||||||
|
maxHelp = \list, initial ->
|
||||||
|
List.walk list initial \bestSoFar, current ->
|
||||||
|
if current > bestSoFar then
|
||||||
|
current
|
||||||
|
|
||||||
|
else
|
||||||
|
bestSoFar
|
||||||
|
|
||||||
joinMap : List a, (a -> List b) -> List b
|
joinMap : List a, (a -> List b) -> List b
|
||||||
|
joinMap = \list, mapper ->
|
||||||
|
List.walk list [] (\state, elem -> List.concat state (mapper elem))
|
||||||
|
|
||||||
find : List elem, (elem -> Bool) -> Result elem [ NotFound ]*
|
find : List elem, (elem -> Bool) -> Result elem [ NotFound ]*
|
||||||
sublist : List elem, { start : Nat, len : Nat } -> List elem
|
sublist : List elem, { start : Nat, len : Nat } -> List elem
|
||||||
intersperse : List elem, elem -> List elem
|
intersperse : List elem, elem -> List elem
|
||||||
|
|
|
@ -44,8 +44,6 @@ interface Num
|
||||||
Binary32,
|
Binary32,
|
||||||
Binary64,
|
Binary64,
|
||||||
|
|
||||||
maxFloat,
|
|
||||||
minFloat,
|
|
||||||
abs,
|
abs,
|
||||||
neg,
|
neg,
|
||||||
add,
|
add,
|
||||||
|
@ -124,6 +122,10 @@ interface Num
|
||||||
maxI128,
|
maxI128,
|
||||||
minU128,
|
minU128,
|
||||||
maxU128,
|
maxU128,
|
||||||
|
minF32,
|
||||||
|
maxF32,
|
||||||
|
minF64,
|
||||||
|
maxF64,
|
||||||
toI8,
|
toI8,
|
||||||
toI8Checked,
|
toI8Checked,
|
||||||
toI16,
|
toI16,
|
||||||
|
@ -144,8 +146,17 @@ interface Num
|
||||||
toU64Checked,
|
toU64Checked,
|
||||||
toU128,
|
toU128,
|
||||||
toU128Checked,
|
toU128Checked,
|
||||||
|
toNat,
|
||||||
|
toNatChecked,
|
||||||
|
toF32,
|
||||||
|
toF32Checked,
|
||||||
|
toF64,
|
||||||
|
toF64Checked,
|
||||||
|
]
|
||||||
|
imports
|
||||||
|
[
|
||||||
|
Bool.{ Bool }
|
||||||
]
|
]
|
||||||
imports [ ]
|
|
||||||
|
|
||||||
Num range : [ @Num range ]
|
Num range : [ @Num range ]
|
||||||
Int range : Num (Integer range)
|
Int range : Num (Integer range)
|
||||||
|
@ -334,6 +345,18 @@ minU128 = 0
|
||||||
maxU128 : U128
|
maxU128 : U128
|
||||||
maxU128 = 0340282366920938463463374607431768211455
|
maxU128 = 0340282366920938463463374607431768211455
|
||||||
|
|
||||||
|
minF32 : F32
|
||||||
|
minF32 = -3.40282347e38
|
||||||
|
|
||||||
|
maxF32 : F32
|
||||||
|
maxF32 = 3.40282347e38
|
||||||
|
|
||||||
|
minF64 : F64
|
||||||
|
minF64 = -1.7976931348623157e308
|
||||||
|
|
||||||
|
maxF64 : F64
|
||||||
|
maxF64 = 1.7976931348623157e308
|
||||||
|
|
||||||
toI8 : Int * -> I8
|
toI8 : Int * -> I8
|
||||||
toI16 : Int * -> I16
|
toI16 : Int * -> I16
|
||||||
toI32 : Int * -> I32
|
toI32 : Int * -> I32
|
||||||
|
@ -344,6 +367,7 @@ toU16 : Int * -> U16
|
||||||
toU32 : Int * -> U32
|
toU32 : Int * -> U32
|
||||||
toU64 : Int * -> U64
|
toU64 : Int * -> U64
|
||||||
toU128 : Int * -> U128
|
toU128 : Int * -> U128
|
||||||
|
toNat : Int * -> Nat
|
||||||
|
|
||||||
toF32 : Num * -> F32
|
toF32 : Num * -> F32
|
||||||
toF64 : Num * -> F64
|
toF64 : Num * -> F64
|
||||||
|
@ -358,5 +382,6 @@ toU16Checked : Int * -> Result U16 [ OutOfBounds ]*
|
||||||
toU32Checked : Int * -> Result U32 [ OutOfBounds ]*
|
toU32Checked : Int * -> Result U32 [ OutOfBounds ]*
|
||||||
toU64Checked : Int * -> Result U64 [ OutOfBounds ]*
|
toU64Checked : Int * -> Result U64 [ OutOfBounds ]*
|
||||||
toU128Checked : Int * -> Result U128 [ OutOfBounds ]*
|
toU128Checked : Int * -> Result U128 [ OutOfBounds ]*
|
||||||
|
toNatChecked : Int * -> Result Nat [ OutOfBounds ]*
|
||||||
toF32Checked : Num * -> Result F32 [ OutOfBounds ]*
|
toF32Checked : Num * -> Result F32 [ OutOfBounds ]*
|
||||||
toF64Checked : Num * -> Result F64 [ OutOfBounds ]*
|
toF64Checked : Num * -> Result F64 [ OutOfBounds ]*
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
interface Result
|
interface Result
|
||||||
exposes [ Result, isOk, isErr, map, mapErr, after, withDefault ]
|
exposes [ Result, isOk, isErr, map, mapErr, after, withDefault ]
|
||||||
imports [ ]
|
imports [ Bool.{ Bool } ]
|
||||||
|
|
||||||
Result ok err : [ Ok ok, Err err ]
|
Result ok err : [ Ok ok, Err err ]
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
interface Dict
|
interface Set
|
||||||
exposes
|
exposes
|
||||||
[
|
[
|
||||||
empty,
|
empty,
|
||||||
|
@ -14,7 +14,7 @@ interface Dict
|
||||||
intersection,
|
intersection,
|
||||||
difference,
|
difference,
|
||||||
]
|
]
|
||||||
imports [ ]
|
imports [ List, Bool.{ Bool }, Dict.{ values } ]
|
||||||
|
|
||||||
empty : Set k
|
empty : Set k
|
||||||
single : k -> Set k
|
single : k -> Set k
|
||||||
|
@ -35,4 +35,4 @@ toDict : Set k -> Dict k {}
|
||||||
|
|
||||||
walk : Set k, state, (state, k -> state) -> state
|
walk : Set k, state, (state, k -> state) -> state
|
||||||
walk = \set, state, step ->
|
walk = \set, state, step ->
|
||||||
Dict.walk (toDict set) state (\s, k, _ -> step s k)
|
Dict.walk (Set.toDict set) state (\s, k, _ -> step s k)
|
||||||
|
|
|
@ -34,7 +34,7 @@ interface Str
|
||||||
toU8,
|
toU8,
|
||||||
toI8,
|
toI8,
|
||||||
]
|
]
|
||||||
imports [ ]
|
imports [ Bool.{ Bool }, Result.{ Result } ]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -955,7 +955,7 @@ pub fn types() -> MutMap<Symbol, (SolvedType, Region)> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// fromUtf8Range : List U8 -> Result Str [ BadUtf8 Utf8Problem, OutOfBounds ]*
|
// fromUtf8Range : List U8, { start : Nat, count : Nat } -> Result Str [ BadUtf8 Utf8Problem, OutOfBounds ]*
|
||||||
{
|
{
|
||||||
let bad_utf8 = SolvedType::TagUnion(
|
let bad_utf8 = SolvedType::TagUnion(
|
||||||
vec![
|
vec![
|
||||||
|
|
|
@ -16,6 +16,7 @@ pub struct MemberVariables {
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct AbilityMemberData {
|
pub struct AbilityMemberData {
|
||||||
pub parent_ability: Symbol,
|
pub parent_ability: Symbol,
|
||||||
|
pub signature_var: Variable,
|
||||||
pub signature: Type,
|
pub signature: Type,
|
||||||
pub variables: MemberVariables,
|
pub variables: MemberVariables,
|
||||||
pub region: Region,
|
pub region: Region,
|
||||||
|
@ -60,15 +61,16 @@ impl AbilitiesStore {
|
||||||
pub fn register_ability(
|
pub fn register_ability(
|
||||||
&mut self,
|
&mut self,
|
||||||
ability: Symbol,
|
ability: Symbol,
|
||||||
members: Vec<(Symbol, Region, Type, MemberVariables)>,
|
members: Vec<(Symbol, Region, Variable, Type, MemberVariables)>,
|
||||||
) {
|
) {
|
||||||
let mut members_vec = Vec::with_capacity(members.len());
|
let mut members_vec = Vec::with_capacity(members.len());
|
||||||
for (member, region, signature, variables) in members.into_iter() {
|
for (member, region, signature_var, signature, variables) in members.into_iter() {
|
||||||
members_vec.push(member);
|
members_vec.push(member);
|
||||||
let old_member = self.ability_members.insert(
|
let old_member = self.ability_members.insert(
|
||||||
member,
|
member,
|
||||||
AbilityMemberData {
|
AbilityMemberData {
|
||||||
parent_ability: ability,
|
parent_ability: ability,
|
||||||
|
signature_var,
|
||||||
signature,
|
signature,
|
||||||
region,
|
region,
|
||||||
variables,
|
variables,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::env::Env;
|
use crate::env::Env;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_collections::all::{ImMap, MutMap, MutSet, SendMap};
|
use roc_collections::all::{ImMap, MutMap, MutSet, SendMap, VecSet};
|
||||||
use roc_module::ident::{Ident, Lowercase, TagName};
|
use roc_module::ident::{Ident, Lowercase, TagName};
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, Symbol};
|
||||||
use roc_parse::ast::{AssignedField, ExtractSpaces, Pattern, Tag, TypeAnnotation, TypeHeader};
|
use roc_parse::ast::{AssignedField, ExtractSpaces, Pattern, Tag, TypeAnnotation, TypeHeader};
|
||||||
|
@ -15,7 +15,7 @@ use roc_types::types::{
|
||||||
pub struct Annotation {
|
pub struct Annotation {
|
||||||
pub typ: Type,
|
pub typ: Type,
|
||||||
pub introduced_variables: IntroducedVariables,
|
pub introduced_variables: IntroducedVariables,
|
||||||
pub references: MutSet<Symbol>,
|
pub references: VecSet<Symbol>,
|
||||||
pub aliases: SendMap<Symbol, Alias>,
|
pub aliases: SendMap<Symbol, Alias>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,8 +58,8 @@ pub struct IntroducedVariables {
|
||||||
pub wildcards: Vec<Loc<Variable>>,
|
pub wildcards: Vec<Loc<Variable>>,
|
||||||
pub lambda_sets: Vec<Variable>,
|
pub lambda_sets: Vec<Variable>,
|
||||||
pub inferred: Vec<Loc<Variable>>,
|
pub inferred: Vec<Loc<Variable>>,
|
||||||
pub named: Vec<NamedVariable>,
|
pub named: VecSet<NamedVariable>,
|
||||||
pub able: Vec<AbleVariable>,
|
pub able: VecSet<AbleVariable>,
|
||||||
pub host_exposed_aliases: MutMap<Symbol, Variable>,
|
pub host_exposed_aliases: MutMap<Symbol, Variable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ impl IntroducedVariables {
|
||||||
first_seen: var.region,
|
first_seen: var.region,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.named.push(named_variable);
|
self.named.insert(named_variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_able(&mut self, name: Lowercase, var: Loc<Variable>, ability: Symbol) {
|
pub fn insert_able(&mut self, name: Lowercase, var: Loc<Variable>, ability: Symbol) {
|
||||||
|
@ -97,7 +97,7 @@ impl IntroducedVariables {
|
||||||
first_seen: var.region,
|
first_seen: var.region,
|
||||||
};
|
};
|
||||||
|
|
||||||
self.able.push(able_variable);
|
self.able.insert(able_variable);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_wildcard(&mut self, var: Loc<Variable>) {
|
pub fn insert_wildcard(&mut self, var: Loc<Variable>) {
|
||||||
|
@ -128,12 +128,7 @@ impl IntroducedVariables {
|
||||||
.extend(other.host_exposed_aliases.clone());
|
.extend(other.host_exposed_aliases.clone());
|
||||||
|
|
||||||
self.named.extend(other.named.iter().cloned());
|
self.named.extend(other.named.iter().cloned());
|
||||||
self.named.sort();
|
|
||||||
self.named.dedup();
|
|
||||||
|
|
||||||
self.able.extend(other.able.iter().cloned());
|
self.able.extend(other.able.iter().cloned());
|
||||||
self.able.sort();
|
|
||||||
self.able.dedup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn union_owned(&mut self, other: Self) {
|
pub fn union_owned(&mut self, other: Self) {
|
||||||
|
@ -143,8 +138,7 @@ impl IntroducedVariables {
|
||||||
self.host_exposed_aliases.extend(other.host_exposed_aliases);
|
self.host_exposed_aliases.extend(other.host_exposed_aliases);
|
||||||
|
|
||||||
self.named.extend(other.named);
|
self.named.extend(other.named);
|
||||||
self.named.sort();
|
self.able.extend(other.able.iter().cloned());
|
||||||
self.named.dedup();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn var_by_name(&self, name: &Lowercase) -> Option<Variable> {
|
pub fn var_by_name(&self, name: &Lowercase) -> Option<Variable> {
|
||||||
|
@ -201,7 +195,7 @@ pub fn canonicalize_annotation(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
) -> Annotation {
|
) -> Annotation {
|
||||||
let mut introduced_variables = IntroducedVariables::default();
|
let mut introduced_variables = IntroducedVariables::default();
|
||||||
let mut references = MutSet::default();
|
let mut references = VecSet::default();
|
||||||
let mut aliases = SendMap::default();
|
let mut aliases = SendMap::default();
|
||||||
|
|
||||||
let typ = can_annotation_help(
|
let typ = can_annotation_help(
|
||||||
|
@ -232,7 +226,7 @@ pub fn canonicalize_annotation_with_possible_clauses(
|
||||||
abilities_in_scope: &[Symbol],
|
abilities_in_scope: &[Symbol],
|
||||||
) -> Annotation {
|
) -> Annotation {
|
||||||
let mut introduced_variables = IntroducedVariables::default();
|
let mut introduced_variables = IntroducedVariables::default();
|
||||||
let mut references = MutSet::default();
|
let mut references = VecSet::default();
|
||||||
let mut aliases = SendMap::default();
|
let mut aliases = SendMap::default();
|
||||||
|
|
||||||
let (annotation, region) = match annotation {
|
let (annotation, region) = match annotation {
|
||||||
|
@ -433,7 +427,7 @@ fn can_annotation_help(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
introduced_variables: &mut IntroducedVariables,
|
introduced_variables: &mut IntroducedVariables,
|
||||||
local_aliases: &mut SendMap<Symbol, Alias>,
|
local_aliases: &mut SendMap<Symbol, Alias>,
|
||||||
references: &mut MutSet<Symbol>,
|
references: &mut VecSet<Symbol>,
|
||||||
) -> Type {
|
) -> Type {
|
||||||
use roc_parse::ast::TypeAnnotation::*;
|
use roc_parse::ast::TypeAnnotation::*;
|
||||||
|
|
||||||
|
@ -861,7 +855,7 @@ fn canonicalize_has_clause(
|
||||||
introduced_variables: &mut IntroducedVariables,
|
introduced_variables: &mut IntroducedVariables,
|
||||||
clause: &Loc<roc_parse::ast::HasClause<'_>>,
|
clause: &Loc<roc_parse::ast::HasClause<'_>>,
|
||||||
abilities_in_scope: &[Symbol],
|
abilities_in_scope: &[Symbol],
|
||||||
references: &mut MutSet<Symbol>,
|
references: &mut VecSet<Symbol>,
|
||||||
) -> Result<(), Type> {
|
) -> Result<(), Type> {
|
||||||
let Loc {
|
let Loc {
|
||||||
region,
|
region,
|
||||||
|
@ -923,7 +917,7 @@ fn can_extension_type<'a>(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
introduced_variables: &mut IntroducedVariables,
|
introduced_variables: &mut IntroducedVariables,
|
||||||
local_aliases: &mut SendMap<Symbol, Alias>,
|
local_aliases: &mut SendMap<Symbol, Alias>,
|
||||||
references: &mut MutSet<Symbol>,
|
references: &mut VecSet<Symbol>,
|
||||||
opt_ext: &Option<&Loc<TypeAnnotation<'a>>>,
|
opt_ext: &Option<&Loc<TypeAnnotation<'a>>>,
|
||||||
ext_problem_kind: roc_problem::can::ExtensionTypeKind,
|
ext_problem_kind: roc_problem::can::ExtensionTypeKind,
|
||||||
) -> Type {
|
) -> Type {
|
||||||
|
@ -1105,7 +1099,7 @@ fn can_assigned_fields<'a>(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
introduced_variables: &mut IntroducedVariables,
|
introduced_variables: &mut IntroducedVariables,
|
||||||
local_aliases: &mut SendMap<Symbol, Alias>,
|
local_aliases: &mut SendMap<Symbol, Alias>,
|
||||||
references: &mut MutSet<Symbol>,
|
references: &mut VecSet<Symbol>,
|
||||||
) -> SendMap<Lowercase, RecordField<Type>> {
|
) -> SendMap<Lowercase, RecordField<Type>> {
|
||||||
use roc_parse::ast::AssignedField::*;
|
use roc_parse::ast::AssignedField::*;
|
||||||
use roc_types::types::RecordField::*;
|
use roc_types::types::RecordField::*;
|
||||||
|
@ -1218,7 +1212,7 @@ fn can_tags<'a>(
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
introduced_variables: &mut IntroducedVariables,
|
introduced_variables: &mut IntroducedVariables,
|
||||||
local_aliases: &mut SendMap<Symbol, Alias>,
|
local_aliases: &mut SendMap<Symbol, Alias>,
|
||||||
references: &mut MutSet<Symbol>,
|
references: &mut VecSet<Symbol>,
|
||||||
) -> Vec<(TagName, Vec<Type>)> {
|
) -> Vec<(TagName, Vec<Type>)> {
|
||||||
let mut tag_types = Vec::with_capacity(tags.len());
|
let mut tag_types = Vec::with_capacity(tags.len());
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,7 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||||
SET_DIFFERENCE => set_difference,
|
SET_DIFFERENCE => set_difference,
|
||||||
SET_TO_LIST => set_to_list,
|
SET_TO_LIST => set_to_list,
|
||||||
SET_FROM_LIST => set_from_list,
|
SET_FROM_LIST => set_from_list,
|
||||||
|
SET_TO_DICT=> set_to_dict,
|
||||||
SET_INSERT => set_insert,
|
SET_INSERT => set_insert,
|
||||||
SET_REMOVE => set_remove,
|
SET_REMOVE => set_remove,
|
||||||
SET_CONTAINS => set_contains,
|
SET_CONTAINS => set_contains,
|
||||||
|
@ -232,24 +233,6 @@ pub fn builtin_defs_map(symbol: Symbol, var_store: &mut VarStore) -> Option<Def>
|
||||||
NUM_SHIFT_RIGHT => num_shift_right_by,
|
NUM_SHIFT_RIGHT => num_shift_right_by,
|
||||||
NUM_SHIFT_RIGHT_ZERO_FILL => num_shift_right_zf_by,
|
NUM_SHIFT_RIGHT_ZERO_FILL => num_shift_right_zf_by,
|
||||||
NUM_INT_CAST=> num_int_cast,
|
NUM_INT_CAST=> num_int_cast,
|
||||||
NUM_MIN_I8=> num_min_i8,
|
|
||||||
NUM_MAX_I8=> num_max_i8,
|
|
||||||
NUM_MIN_U8=> num_min_u8,
|
|
||||||
NUM_MAX_U8=> num_max_u8,
|
|
||||||
NUM_MIN_I16=> num_min_i16,
|
|
||||||
NUM_MAX_I16=> num_max_i16,
|
|
||||||
NUM_MIN_U16=> num_min_u16,
|
|
||||||
NUM_MAX_U16=> num_max_u16,
|
|
||||||
NUM_MIN_I32=> num_min_i32,
|
|
||||||
NUM_MAX_I32=> num_max_i32,
|
|
||||||
NUM_MIN_U32=> num_min_u32,
|
|
||||||
NUM_MAX_U32=> num_max_u32,
|
|
||||||
NUM_MIN_I64=> num_min_i64,
|
|
||||||
NUM_MAX_I64=> num_max_i64,
|
|
||||||
NUM_MIN_U64=> num_min_u64,
|
|
||||||
NUM_MAX_U64=> num_max_u64,
|
|
||||||
NUM_MIN_I128=> num_min_i128,
|
|
||||||
NUM_MAX_I128=> num_max_i128,
|
|
||||||
NUM_TO_I8 => num_to_i8,
|
NUM_TO_I8 => num_to_i8,
|
||||||
NUM_TO_I8_CHECKED => num_to_i8_checked,
|
NUM_TO_I8_CHECKED => num_to_i8_checked,
|
||||||
NUM_TO_I16 => num_to_i16,
|
NUM_TO_I16 => num_to_i16,
|
||||||
|
@ -1503,106 +1486,6 @@ fn num_int_cast(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
|
lowlevel_1(symbol, LowLevel::NumIntCast, var_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Num.minI8: I8
|
|
||||||
fn num_min_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i8>(symbol, var_store, i8::MIN, IntBound::Exact(IntWidth::I8))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.maxI8: I8
|
|
||||||
fn num_max_i8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i8>(symbol, var_store, i8::MAX, IntBound::Exact(IntWidth::I8))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.minU8: U8
|
|
||||||
fn num_min_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<u8>(symbol, var_store, u8::MIN, IntBound::Exact(IntWidth::U8))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.maxU8: U8
|
|
||||||
fn num_max_u8(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<u8>(symbol, var_store, u8::MAX, IntBound::Exact(IntWidth::U8))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.minI16: I16
|
|
||||||
fn num_min_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i16>(symbol, var_store, i16::MIN, IntBound::Exact(IntWidth::I16))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.maxI16: I16
|
|
||||||
fn num_max_i16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i16>(symbol, var_store, i16::MAX, IntBound::Exact(IntWidth::I16))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.minU16: U16
|
|
||||||
fn num_min_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<u16>(symbol, var_store, u16::MIN, IntBound::Exact(IntWidth::U16))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.maxU16: U16
|
|
||||||
fn num_max_u16(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<u16>(symbol, var_store, u16::MAX, IntBound::Exact(IntWidth::U16))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.minI32: I32
|
|
||||||
fn num_min_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i32>(symbol, var_store, i32::MIN, IntBound::Exact(IntWidth::I32))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.maxI32: I32
|
|
||||||
fn num_max_i32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i32>(symbol, var_store, i32::MAX, IntBound::Exact(IntWidth::I32))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.minU32: U32
|
|
||||||
fn num_min_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<u32>(symbol, var_store, u32::MIN, IntBound::Exact(IntWidth::U32))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.maxU32: U32
|
|
||||||
fn num_max_u32(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<u32>(symbol, var_store, u32::MAX, IntBound::Exact(IntWidth::U32))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.minI64: I64
|
|
||||||
fn num_min_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i64>(symbol, var_store, i64::MIN, IntBound::Exact(IntWidth::I64))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.maxI64: I64
|
|
||||||
fn num_max_i64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i64>(symbol, var_store, i64::MAX, IntBound::Exact(IntWidth::I64))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.minU64: U64
|
|
||||||
fn num_min_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<u64>(symbol, var_store, u64::MIN, IntBound::Exact(IntWidth::U64))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.maxU64: U64
|
|
||||||
fn num_max_u64(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<u64>(symbol, var_store, u64::MAX, IntBound::Exact(IntWidth::U64))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.minI128: I128
|
|
||||||
fn num_min_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i128>(
|
|
||||||
symbol,
|
|
||||||
var_store,
|
|
||||||
i128::MIN,
|
|
||||||
IntBound::Exact(IntWidth::I128),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Num.maxI128: I128
|
|
||||||
fn num_max_i128(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
|
||||||
int_min_or_max::<i128>(
|
|
||||||
symbol,
|
|
||||||
var_store,
|
|
||||||
i128::MAX,
|
|
||||||
IntBound::Exact(IntWidth::I128),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// List.isEmpty : List * -> Bool
|
/// List.isEmpty : List * -> Bool
|
||||||
fn list_is_empty(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn list_is_empty(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let list_var = var_store.fresh();
|
let list_var = var_store.fresh();
|
||||||
|
@ -4128,6 +4011,11 @@ fn set_from_list(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
lowlevel_1(symbol, LowLevel::SetFromList, var_store)
|
lowlevel_1(symbol, LowLevel::SetFromList, var_store)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set.toDict : Set k -> Dict k {}
|
||||||
|
fn set_to_dict(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
|
lowlevel_1(symbol, LowLevel::SetToDict, var_store)
|
||||||
|
}
|
||||||
|
|
||||||
/// Set.insert : Set k, k -> Set k
|
/// Set.insert : Set k, k -> Set k
|
||||||
fn set_insert(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
fn set_insert(symbol: Symbol, var_store: &mut VarStore) -> Def {
|
||||||
let dict_var = var_store.fresh();
|
let dict_var = var_store.fresh();
|
||||||
|
@ -5446,36 +5334,6 @@ fn defn_help(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn int_min_or_max<I128>(symbol: Symbol, var_store: &mut VarStore, i: I128, bound: IntBound) -> Def
|
|
||||||
where
|
|
||||||
I128: Into<i128>,
|
|
||||||
{
|
|
||||||
let int_var = var_store.fresh();
|
|
||||||
let int_precision_var = var_store.fresh();
|
|
||||||
let body = int::<I128>(int_var, int_precision_var, i, bound);
|
|
||||||
|
|
||||||
let std = roc_builtins::std::types();
|
|
||||||
let solved = std.get(&symbol).unwrap();
|
|
||||||
let mut free_vars = roc_types::solved_types::FreeVars::default();
|
|
||||||
let signature = roc_types::solved_types::to_type(&solved.0, &mut free_vars, var_store);
|
|
||||||
|
|
||||||
let annotation = crate::def::Annotation {
|
|
||||||
signature,
|
|
||||||
introduced_variables: Default::default(),
|
|
||||||
region: Region::zero(),
|
|
||||||
aliases: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
Def {
|
|
||||||
annotation: Some(annotation),
|
|
||||||
expr_var: int_var,
|
|
||||||
loc_expr: Loc::at_zero(body),
|
|
||||||
loc_pattern: Loc::at_zero(Pattern::Identifier(symbol)),
|
|
||||||
pattern_vars: SendMap::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn num_no_bound() -> NumericBound {
|
fn num_no_bound() -> NumericBound {
|
||||||
NumericBound::None
|
NumericBound::None
|
||||||
}
|
}
|
||||||
|
|
|
@ -344,7 +344,8 @@ pub fn canonicalize_defs<'a>(
|
||||||
|
|
||||||
let mut named = can_ann.introduced_variables.named;
|
let mut named = can_ann.introduced_variables.named;
|
||||||
for loc_lowercase in vars.iter() {
|
for loc_lowercase in vars.iter() {
|
||||||
match named.iter().position(|nv| nv.name == loc_lowercase.value) {
|
let opt_index = named.iter().position(|nv| nv.name == loc_lowercase.value);
|
||||||
|
match opt_index {
|
||||||
Some(index) => {
|
Some(index) => {
|
||||||
// This is a valid lowercase rigid var for the type def.
|
// This is a valid lowercase rigid var for the type def.
|
||||||
let named_variable = named.swap_remove(index);
|
let named_variable = named.swap_remove(index);
|
||||||
|
@ -542,7 +543,13 @@ pub fn canonicalize_defs<'a>(
|
||||||
flex_vars: iv.collect_flex(),
|
flex_vars: iv.collect_flex(),
|
||||||
};
|
};
|
||||||
|
|
||||||
can_members.push((member_sym, name_region, member_annot.typ, variables));
|
can_members.push((
|
||||||
|
member_sym,
|
||||||
|
name_region,
|
||||||
|
var_store.fresh(),
|
||||||
|
member_annot.typ,
|
||||||
|
variables,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Store what symbols a type must define implementations for to have this ability.
|
// Store what symbols a type must define implementations for to have this ability.
|
||||||
|
@ -690,7 +697,7 @@ pub fn sort_can_defs(
|
||||||
if let Some(References { value_lookups, .. }) = env.closures.get(symbol) {
|
if let Some(References { value_lookups, .. }) = env.closures.get(symbol) {
|
||||||
let home = env.home;
|
let home = env.home;
|
||||||
|
|
||||||
for lookup in value_lookups {
|
for lookup in value_lookups.iter() {
|
||||||
if lookup != symbol && lookup.module_id() == home {
|
if lookup != symbol && lookup.module_id() == home {
|
||||||
// DO NOT register a self-call behind a lambda!
|
// DO NOT register a self-call behind a lambda!
|
||||||
//
|
//
|
||||||
|
@ -741,7 +748,7 @@ pub fn sort_can_defs(
|
||||||
|
|
||||||
// if the current symbol is a closure, peek into its body
|
// if the current symbol is a closure, peek into its body
|
||||||
if let Some(References { value_lookups, .. }) = env.closures.get(symbol) {
|
if let Some(References { value_lookups, .. }) = env.closures.get(symbol) {
|
||||||
for lookup in value_lookups {
|
for lookup in value_lookups.iter() {
|
||||||
loc_succ.push(*lookup);
|
loc_succ.push(*lookup);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1306,7 +1313,7 @@ fn canonicalize_pending_value_def<'a>(
|
||||||
let (mut loc_can_expr, can_output) =
|
let (mut loc_can_expr, can_output) =
|
||||||
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
|
canonicalize_expr(env, var_store, scope, loc_expr.region, &loc_expr.value);
|
||||||
|
|
||||||
output.references = output.references.union(can_output.references.clone());
|
output.references.union_mut(&can_output.references);
|
||||||
|
|
||||||
// reset the tailcallable_symbol
|
// reset the tailcallable_symbol
|
||||||
env.tailcallable_symbol = outer_identifier;
|
env.tailcallable_symbol = outer_identifier;
|
||||||
|
@ -1356,7 +1363,7 @@ fn canonicalize_pending_value_def<'a>(
|
||||||
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
||||||
// would result in circular def errors!)
|
// would result in circular def errors!)
|
||||||
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
||||||
refs.value_lookups = refs.value_lookups.without(&symbol);
|
refs.value_lookups.remove(&symbol);
|
||||||
});
|
});
|
||||||
|
|
||||||
// renamed_closure_def = Some(&symbol);
|
// renamed_closure_def = Some(&symbol);
|
||||||
|
@ -1496,7 +1503,7 @@ fn canonicalize_pending_value_def<'a>(
|
||||||
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
// Recursion doesn't count as referencing. (If it did, all recursive functions
|
||||||
// would result in circular def errors!)
|
// would result in circular def errors!)
|
||||||
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
refs_by_symbol.entry(symbol).and_modify(|(_, refs)| {
|
||||||
refs.value_lookups = refs.value_lookups.without(&symbol);
|
refs.value_lookups.remove(&symbol);
|
||||||
});
|
});
|
||||||
|
|
||||||
loc_can_expr.value = Closure(ClosureData {
|
loc_can_expr.value = Closure(ClosureData {
|
||||||
|
@ -1586,7 +1593,7 @@ pub fn can_defs_with_return<'a>(
|
||||||
output
|
output
|
||||||
.introduced_variables
|
.introduced_variables
|
||||||
.union(&defs_output.introduced_variables);
|
.union(&defs_output.introduced_variables);
|
||||||
output.references = output.references.union(defs_output.references);
|
output.references.union_mut(&defs_output.references);
|
||||||
|
|
||||||
// Now that we've collected all the references, check to see if any of the new idents
|
// Now that we've collected all the references, check to see if any of the new idents
|
||||||
// we defined went unused by the return expression. If any were unused, report it.
|
// we defined went unused by the return expression. If any were unused, report it.
|
||||||
|
@ -1640,7 +1647,7 @@ fn closure_recursivity(symbol: Symbol, closures: &MutMap<Symbol, References>) ->
|
||||||
let mut stack = Vec::new();
|
let mut stack = Vec::new();
|
||||||
|
|
||||||
if let Some(references) = closures.get(&symbol) {
|
if let Some(references) = closures.get(&symbol) {
|
||||||
for v in &references.calls {
|
for v in references.calls.iter() {
|
||||||
stack.push(*v);
|
stack.push(*v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1656,7 +1663,7 @@ fn closure_recursivity(symbol: Symbol, closures: &MutMap<Symbol, References>) ->
|
||||||
// if it calls any functions
|
// if it calls any functions
|
||||||
if let Some(nested_references) = closures.get(&nested_symbol) {
|
if let Some(nested_references) = closures.get(&nested_symbol) {
|
||||||
// add its called to the stack
|
// add its called to the stack
|
||||||
for v in &nested_references.calls {
|
for v in nested_references.calls.iter() {
|
||||||
stack.push(*v);
|
stack.push(*v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ use crate::env::Env;
|
||||||
use crate::expr::{ClosureData, Expr, Recursive};
|
use crate::expr::{ClosureData, Expr, Recursive};
|
||||||
use crate::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_collections::all::{MutSet, SendMap};
|
use roc_collections::all::{SendMap, VecSet};
|
||||||
use roc_module::called_via::CalledVia;
|
use roc_module::called_via::CalledVia;
|
||||||
use roc_module::ident::TagName;
|
use roc_module::ident::TagName;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
|
@ -12,7 +12,7 @@ use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::{VarStore, Variable};
|
use roc_types::subs::{VarStore, Variable};
|
||||||
use roc_types::types::{AliasKind, Type, TypeExtension};
|
use roc_types::types::{AliasKind, Type, TypeExtension};
|
||||||
|
|
||||||
#[derive(Default, Clone, Copy)]
|
#[derive(Debug, Default, Clone, Copy)]
|
||||||
pub(crate) struct HostedGeneratedFunctions {
|
pub(crate) struct HostedGeneratedFunctions {
|
||||||
pub(crate) after: bool,
|
pub(crate) after: bool,
|
||||||
pub(crate) map: bool,
|
pub(crate) map: bool,
|
||||||
|
@ -39,7 +39,7 @@ pub(crate) fn build_effect_builtins(
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
effect_symbol: Symbol,
|
effect_symbol: Symbol,
|
||||||
var_store: &mut VarStore,
|
var_store: &mut VarStore,
|
||||||
exposed_symbols: &mut MutSet<Symbol>,
|
exposed_symbols: &mut VecSet<Symbol>,
|
||||||
declarations: &mut Vec<Declaration>,
|
declarations: &mut Vec<Declaration>,
|
||||||
generated_functions: HostedGeneratedFunctions,
|
generated_functions: HostedGeneratedFunctions,
|
||||||
) {
|
) {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::procedure::References;
|
use crate::procedure::References;
|
||||||
use roc_collections::all::{MutMap, MutSet};
|
use roc_collections::all::{MutMap, VecSet};
|
||||||
use roc_module::ident::{Ident, Lowercase, ModuleName};
|
use roc_module::ident::{Ident, Lowercase, ModuleName};
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||||
use roc_problem::can::{Problem, RuntimeError};
|
use roc_problem::can::{Problem, RuntimeError};
|
||||||
|
@ -28,12 +28,12 @@ pub struct Env<'a> {
|
||||||
pub closure_name_symbol: Option<Symbol>,
|
pub closure_name_symbol: Option<Symbol>,
|
||||||
|
|
||||||
/// Symbols of values/functions which were referenced by qualified lookups.
|
/// Symbols of values/functions which were referenced by qualified lookups.
|
||||||
pub qualified_value_lookups: MutSet<Symbol>,
|
pub qualified_value_lookups: VecSet<Symbol>,
|
||||||
|
|
||||||
/// Symbols of types which were referenced by qualified lookups.
|
/// Symbols of types which were referenced by qualified lookups.
|
||||||
pub qualified_type_lookups: MutSet<Symbol>,
|
pub qualified_type_lookups: VecSet<Symbol>,
|
||||||
|
|
||||||
pub top_level_symbols: MutSet<Symbol>,
|
pub top_level_symbols: VecSet<Symbol>,
|
||||||
|
|
||||||
pub ident_ids: IdentIds,
|
pub ident_ids: IdentIds,
|
||||||
pub exposed_ident_ids: IdentIds,
|
pub exposed_ident_ids: IdentIds,
|
||||||
|
@ -54,11 +54,11 @@ impl<'a> Env<'a> {
|
||||||
exposed_ident_ids,
|
exposed_ident_ids,
|
||||||
problems: Vec::new(),
|
problems: Vec::new(),
|
||||||
closures: MutMap::default(),
|
closures: MutMap::default(),
|
||||||
qualified_value_lookups: MutSet::default(),
|
qualified_value_lookups: VecSet::default(),
|
||||||
qualified_type_lookups: MutSet::default(),
|
qualified_type_lookups: VecSet::default(),
|
||||||
tailcallable_symbol: None,
|
tailcallable_symbol: None,
|
||||||
closure_name_symbol: None,
|
closure_name_symbol: None,
|
||||||
top_level_symbols: MutSet::default(),
|
top_level_symbols: VecSet::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +97,8 @@ impl<'a> Env<'a> {
|
||||||
|
|
||||||
Ok(symbol)
|
Ok(symbol)
|
||||||
}
|
}
|
||||||
None => Err(RuntimeError::LookupNotInScope(
|
None => {
|
||||||
|
let error = RuntimeError::LookupNotInScope(
|
||||||
Loc {
|
Loc {
|
||||||
value: ident,
|
value: ident,
|
||||||
region,
|
region,
|
||||||
|
@ -106,7 +107,9 @@ impl<'a> Env<'a> {
|
||||||
.idents()
|
.idents()
|
||||||
.map(|(_, string)| string.as_ref().into())
|
.map(|(_, string)| string.as_ref().into())
|
||||||
.collect(),
|
.collect(),
|
||||||
)),
|
);
|
||||||
|
Err(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
match self.dep_idents.get(&module_id) {
|
match self.dep_idents.get(&module_id) {
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::num::{
|
||||||
use crate::pattern::{canonicalize_pattern, Pattern};
|
use crate::pattern::{canonicalize_pattern, Pattern};
|
||||||
use crate::procedure::References;
|
use crate::procedure::References;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use roc_collections::all::{MutMap, MutSet, SendMap};
|
use roc_collections::all::{MutMap, MutSet, SendMap, VecSet};
|
||||||
use roc_module::called_via::CalledVia;
|
use roc_module::called_via::CalledVia;
|
||||||
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
use roc_module::ident::{ForeignSymbol, Lowercase, TagName};
|
||||||
use roc_module::low_level::LowLevel;
|
use roc_module::low_level::LowLevel;
|
||||||
|
@ -29,12 +29,12 @@ pub struct Output {
|
||||||
pub tail_call: Option<Symbol>,
|
pub tail_call: Option<Symbol>,
|
||||||
pub introduced_variables: IntroducedVariables,
|
pub introduced_variables: IntroducedVariables,
|
||||||
pub aliases: SendMap<Symbol, Alias>,
|
pub aliases: SendMap<Symbol, Alias>,
|
||||||
pub non_closures: MutSet<Symbol>,
|
pub non_closures: VecSet<Symbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Output {
|
impl Output {
|
||||||
pub fn union(&mut self, other: Self) {
|
pub fn union(&mut self, other: Self) {
|
||||||
self.references.union_mut(other.references);
|
self.references.union_mut(&other.references);
|
||||||
|
|
||||||
if let (None, Some(later)) = (self.tail_call, other.tail_call) {
|
if let (None, Some(later)) = (self.tail_call, other.tail_call) {
|
||||||
self.tail_call = Some(later);
|
self.tail_call = Some(later);
|
||||||
|
@ -354,7 +354,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
if let Var(symbol) = &can_update.value {
|
if let Var(symbol) = &can_update.value {
|
||||||
match canonicalize_fields(env, var_store, scope, region, fields.items) {
|
match canonicalize_fields(env, var_store, scope, region, fields.items) {
|
||||||
Ok((can_fields, mut output)) => {
|
Ok((can_fields, mut output)) => {
|
||||||
output.references = output.references.union(update_out.references);
|
output.references.union_mut(&update_out.references);
|
||||||
|
|
||||||
let answer = Update {
|
let answer = Update {
|
||||||
record_var: var_store.fresh(),
|
record_var: var_store.fresh(),
|
||||||
|
@ -432,7 +432,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
let (can_expr, elem_out) =
|
let (can_expr, elem_out) =
|
||||||
canonicalize_expr(env, var_store, scope, loc_elem.region, &loc_elem.value);
|
canonicalize_expr(env, var_store, scope, loc_elem.region, &loc_elem.value);
|
||||||
|
|
||||||
references = references.union(elem_out.references);
|
references.union_mut(&elem_out.references);
|
||||||
|
|
||||||
can_elems.push(can_expr);
|
can_elems.push(can_expr);
|
||||||
}
|
}
|
||||||
|
@ -466,7 +466,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
canonicalize_expr(env, var_store, scope, loc_arg.region, &loc_arg.value);
|
canonicalize_expr(env, var_store, scope, loc_arg.region, &loc_arg.value);
|
||||||
|
|
||||||
args.push((var_store.fresh(), arg_expr));
|
args.push((var_store.fresh(), arg_expr));
|
||||||
output.references = output.references.union(arg_out.references);
|
output.references.union_mut(&arg_out.references);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let ast::Expr::OpaqueRef(name) = loc_fn.value {
|
if let ast::Expr::OpaqueRef(name) = loc_fn.value {
|
||||||
|
@ -753,7 +753,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
let (can_when_branch, branch_references) =
|
let (can_when_branch, branch_references) =
|
||||||
canonicalize_when_branch(env, var_store, scope, region, *branch, &mut output);
|
canonicalize_when_branch(env, var_store, scope, region, *branch, &mut output);
|
||||||
|
|
||||||
output.references = output.references.union(branch_references);
|
output.references.union_mut(&branch_references);
|
||||||
|
|
||||||
can_branches.push(can_when_branch);
|
can_branches.push(can_when_branch);
|
||||||
}
|
}
|
||||||
|
@ -886,8 +886,8 @@ pub fn canonicalize_expr<'a>(
|
||||||
|
|
||||||
branches.push((loc_cond, loc_then));
|
branches.push((loc_cond, loc_then));
|
||||||
|
|
||||||
output.references = output.references.union(cond_output.references);
|
output.references.union_mut(&cond_output.references);
|
||||||
output.references = output.references.union(then_output.references);
|
output.references.union_mut(&then_output.references);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (loc_else, else_output) = canonicalize_expr(
|
let (loc_else, else_output) = canonicalize_expr(
|
||||||
|
@ -898,7 +898,7 @@ pub fn canonicalize_expr<'a>(
|
||||||
&final_else_branch.value,
|
&final_else_branch.value,
|
||||||
);
|
);
|
||||||
|
|
||||||
output.references = output.references.union(else_output.references);
|
output.references.union_mut(&else_output.references);
|
||||||
|
|
||||||
(
|
(
|
||||||
If {
|
If {
|
||||||
|
@ -1167,7 +1167,7 @@ fn canonicalize_fields<'a>(
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
output.references = output.references.union(field_out.references);
|
output.references.union_mut(&field_out.references);
|
||||||
}
|
}
|
||||||
Err(CanonicalizeFieldProblem::InvalidOptionalValue {
|
Err(CanonicalizeFieldProblem::InvalidOptionalValue {
|
||||||
field_name,
|
field_name,
|
||||||
|
|
|
@ -7,7 +7,7 @@ use crate::operator::desugar_def;
|
||||||
use crate::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use crate::scope::Scope;
|
use crate::scope::Scope;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_collections::all::{MutMap, MutSet, SendMap};
|
use roc_collections::all::{MutMap, SendMap, VecSet};
|
||||||
use roc_module::ident::Lowercase;
|
use roc_module::ident::Lowercase;
|
||||||
use roc_module::ident::{Ident, TagName};
|
use roc_module::ident::{Ident, TagName};
|
||||||
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
use roc_module::symbol::{IdentIds, ModuleId, ModuleIds, Symbol};
|
||||||
|
@ -23,9 +23,9 @@ use roc_types::types::{Alias, AliasKind, Type};
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
pub module_id: ModuleId,
|
pub module_id: ModuleId,
|
||||||
pub exposed_imports: MutMap<Symbol, Variable>,
|
pub exposed_imports: MutMap<Symbol, Variable>,
|
||||||
pub exposed_symbols: MutSet<Symbol>,
|
pub exposed_symbols: VecSet<Symbol>,
|
||||||
pub referenced_values: MutSet<Symbol>,
|
pub referenced_values: VecSet<Symbol>,
|
||||||
pub referenced_types: MutSet<Symbol>,
|
pub referenced_types: VecSet<Symbol>,
|
||||||
/// all aliases. `bool` indicates whether it is exposed
|
/// all aliases. `bool` indicates whether it is exposed
|
||||||
pub aliases: MutMap<Symbol, (bool, Alias)>,
|
pub aliases: MutMap<Symbol, (bool, Alias)>,
|
||||||
pub rigid_variables: RigidVariables,
|
pub rigid_variables: RigidVariables,
|
||||||
|
@ -36,7 +36,7 @@ pub struct Module {
|
||||||
pub struct RigidVariables {
|
pub struct RigidVariables {
|
||||||
pub named: MutMap<Variable, Lowercase>,
|
pub named: MutMap<Variable, Lowercase>,
|
||||||
pub able: MutMap<Variable, (Lowercase, Symbol)>,
|
pub able: MutMap<Variable, (Lowercase, Symbol)>,
|
||||||
pub wildcards: MutSet<Variable>,
|
pub wildcards: VecSet<Variable>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -48,8 +48,8 @@ pub struct ModuleOutput {
|
||||||
pub lookups: Vec<(Symbol, Variable, Region)>,
|
pub lookups: Vec<(Symbol, Variable, Region)>,
|
||||||
pub problems: Vec<Problem>,
|
pub problems: Vec<Problem>,
|
||||||
pub ident_ids: IdentIds,
|
pub ident_ids: IdentIds,
|
||||||
pub referenced_values: MutSet<Symbol>,
|
pub referenced_values: VecSet<Symbol>,
|
||||||
pub referenced_types: MutSet<Symbol>,
|
pub referenced_types: VecSet<Symbol>,
|
||||||
pub scope: Scope,
|
pub scope: Scope,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,48 +77,31 @@ fn validate_generate_with<'a>(
|
||||||
(functions, unknown)
|
(functions, unknown)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO trim these down
|
#[derive(Debug)]
|
||||||
#[allow(clippy::too_many_arguments)]
|
enum GeneratedInfo {
|
||||||
pub fn canonicalize_module_defs<'a>(
|
Hosted {
|
||||||
arena: &Bump,
|
|
||||||
loc_defs: &'a [Loc<ast::Def<'a>>],
|
|
||||||
header_for: &roc_parse::header::HeaderFor,
|
|
||||||
home: ModuleId,
|
|
||||||
module_ids: &ModuleIds,
|
|
||||||
exposed_ident_ids: IdentIds,
|
|
||||||
dep_idents: &'a MutMap<ModuleId, IdentIds>,
|
|
||||||
aliases: MutMap<Symbol, Alias>,
|
|
||||||
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
|
||||||
exposed_symbols: &MutSet<Symbol>,
|
|
||||||
var_store: &mut VarStore,
|
|
||||||
) -> Result<ModuleOutput, RuntimeError> {
|
|
||||||
let mut can_exposed_imports = MutMap::default();
|
|
||||||
let mut scope = Scope::new(home, var_store);
|
|
||||||
let mut env = Env::new(home, dep_idents, module_ids, exposed_ident_ids);
|
|
||||||
let num_deps = dep_idents.len();
|
|
||||||
|
|
||||||
for (name, alias) in aliases.into_iter() {
|
|
||||||
scope.add_alias(
|
|
||||||
name,
|
|
||||||
alias.region,
|
|
||||||
alias.type_variables,
|
|
||||||
alias.typ,
|
|
||||||
alias.kind,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Hosted {
|
|
||||||
effect_symbol: Symbol,
|
effect_symbol: Symbol,
|
||||||
generated_functions: HostedGeneratedFunctions,
|
generated_functions: HostedGeneratedFunctions,
|
||||||
|
},
|
||||||
|
Builtin,
|
||||||
|
NotSpecial,
|
||||||
}
|
}
|
||||||
|
|
||||||
let hosted_info = if let HeaderFor::Hosted {
|
impl GeneratedInfo {
|
||||||
|
fn from_header_for<'a>(
|
||||||
|
env: &mut Env,
|
||||||
|
scope: &mut Scope,
|
||||||
|
var_store: &mut VarStore,
|
||||||
|
header_for: &HeaderFor<'a>,
|
||||||
|
) -> Self {
|
||||||
|
match header_for {
|
||||||
|
HeaderFor::Hosted {
|
||||||
generates,
|
generates,
|
||||||
generates_with,
|
generates_with,
|
||||||
} = header_for
|
} => {
|
||||||
{
|
|
||||||
let name: &str = generates.into();
|
let name: &str = generates.into();
|
||||||
let (generated_functions, unknown_generated) = validate_generate_with(generates_with);
|
let (generated_functions, unknown_generated) =
|
||||||
|
validate_generate_with(generates_with);
|
||||||
|
|
||||||
for unknown in unknown_generated {
|
for unknown in unknown_generated {
|
||||||
env.problem(Problem::UnknownGeneratesWith(unknown));
|
env.problem(Problem::UnknownGeneratesWith(unknown));
|
||||||
|
@ -153,13 +136,68 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(Hosted {
|
GeneratedInfo::Hosted {
|
||||||
effect_symbol,
|
effect_symbol,
|
||||||
generated_functions,
|
generated_functions,
|
||||||
})
|
}
|
||||||
} else {
|
}
|
||||||
None
|
HeaderFor::Builtin { generates_with } => {
|
||||||
};
|
debug_assert!(generates_with.is_empty());
|
||||||
|
GeneratedInfo::Builtin
|
||||||
|
}
|
||||||
|
_ => GeneratedInfo::NotSpecial,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn has_no_implementation(expr: &Expr) -> bool {
|
||||||
|
match expr {
|
||||||
|
Expr::RuntimeError(RuntimeError::NoImplementationNamed { .. }) => true,
|
||||||
|
Expr::Closure(closure_data)
|
||||||
|
if matches!(
|
||||||
|
closure_data.loc_body.value,
|
||||||
|
Expr::RuntimeError(RuntimeError::NoImplementationNamed { .. })
|
||||||
|
) =>
|
||||||
|
{
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO trim these down
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
|
pub fn canonicalize_module_defs<'a>(
|
||||||
|
arena: &Bump,
|
||||||
|
loc_defs: &'a [Loc<ast::Def<'a>>],
|
||||||
|
header_for: &roc_parse::header::HeaderFor,
|
||||||
|
home: ModuleId,
|
||||||
|
module_ids: &ModuleIds,
|
||||||
|
exposed_ident_ids: IdentIds,
|
||||||
|
dep_idents: &'a MutMap<ModuleId, IdentIds>,
|
||||||
|
aliases: MutMap<Symbol, Alias>,
|
||||||
|
exposed_imports: MutMap<Ident, (Symbol, Region)>,
|
||||||
|
exposed_symbols: &VecSet<Symbol>,
|
||||||
|
var_store: &mut VarStore,
|
||||||
|
) -> Result<ModuleOutput, RuntimeError> {
|
||||||
|
let mut can_exposed_imports = MutMap::default();
|
||||||
|
let mut scope = Scope::new(home, var_store);
|
||||||
|
let mut env = Env::new(home, dep_idents, module_ids, exposed_ident_ids);
|
||||||
|
let num_deps = dep_idents.len();
|
||||||
|
|
||||||
|
for (name, alias) in aliases.into_iter() {
|
||||||
|
scope.add_alias(
|
||||||
|
name,
|
||||||
|
alias.region,
|
||||||
|
alias.type_variables,
|
||||||
|
alias.typ,
|
||||||
|
alias.kind,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let generated_info =
|
||||||
|
GeneratedInfo::from_header_for(&mut env, &mut scope, var_store, header_for);
|
||||||
|
|
||||||
// Desugar operators (convert them to Apply calls, taking into account
|
// Desugar operators (convert them to Apply calls, taking into account
|
||||||
// operator precedence and associativity rules), before doing other canonicalization.
|
// operator precedence and associativity rules), before doing other canonicalization.
|
||||||
|
@ -215,14 +253,25 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
panic!("TODO gracefully handle shadowing in imports.")
|
panic!("TODO gracefully handle shadowing in imports.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if [
|
||||||
|
Symbol::LIST_LIST,
|
||||||
|
Symbol::STR_STR,
|
||||||
|
Symbol::DICT_DICT,
|
||||||
|
Symbol::SET_SET,
|
||||||
|
Symbol::BOX_BOX_TYPE,
|
||||||
|
]
|
||||||
|
.contains(&symbol)
|
||||||
|
{
|
||||||
|
// These are not aliases but Apply's and we make sure they are always in scope
|
||||||
} else {
|
} else {
|
||||||
// This is a type alias
|
// This is a type alias
|
||||||
|
|
||||||
// the symbol should already be added to the scope when this module is canonicalized
|
// the symbol should already be added to the scope when this module is canonicalized
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
scope.contains_alias(symbol),
|
scope.contains_alias(symbol),
|
||||||
"apparently, {:?} is not actually a type alias",
|
"The {:?} is not a type alias known in {:?}",
|
||||||
symbol
|
symbol,
|
||||||
|
home
|
||||||
);
|
);
|
||||||
|
|
||||||
// but now we know this symbol by a different identifier, so we still need to add it to
|
// but now we know this symbol by a different identifier, so we still need to add it to
|
||||||
|
@ -231,8 +280,11 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
// here we do nothing special
|
// here we do nothing special
|
||||||
}
|
}
|
||||||
Err((_shadowed_symbol, _region)) => {
|
Err((shadowed_symbol, _region)) => {
|
||||||
panic!("TODO gracefully handle shadowing in imports.")
|
panic!(
|
||||||
|
"TODO gracefully handle shadowing in imports, {:?} is shadowed.",
|
||||||
|
shadowed_symbol
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -273,8 +325,8 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
rigid_variables.wildcards.insert(var.value);
|
rigid_variables.wildcards.insert(var.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut referenced_values = MutSet::default();
|
let mut referenced_values = VecSet::default();
|
||||||
let mut referenced_types = MutSet::default();
|
let mut referenced_types = VecSet::default();
|
||||||
|
|
||||||
// Gather up all the symbols that were referenced across all the defs' lookups.
|
// Gather up all the symbols that were referenced across all the defs' lookups.
|
||||||
referenced_values.extend(output.references.value_lookups);
|
referenced_values.extend(output.references.value_lookups);
|
||||||
|
@ -314,12 +366,12 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
(Ok(mut declarations), output) => {
|
(Ok(mut declarations), output) => {
|
||||||
use crate::def::Declaration::*;
|
use crate::def::Declaration::*;
|
||||||
|
|
||||||
if let Some(Hosted {
|
if let GeneratedInfo::Hosted {
|
||||||
effect_symbol,
|
effect_symbol,
|
||||||
generated_functions,
|
generated_functions,
|
||||||
}) = hosted_info
|
} = generated_info
|
||||||
{
|
{
|
||||||
let mut exposed_symbols = MutSet::default();
|
let mut exposed_symbols = VecSet::default();
|
||||||
|
|
||||||
// NOTE this currently builds all functions, not just the ones that the user requested
|
// NOTE this currently builds all functions, not just the ones that the user requested
|
||||||
crate::effect_module::build_effect_builtins(
|
crate::effect_module::build_effect_builtins(
|
||||||
|
@ -350,9 +402,21 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
// Temporary hack: we don't know exactly what symbols are hosted symbols,
|
// Temporary hack: we don't know exactly what symbols are hosted symbols,
|
||||||
// and which are meant to be normal definitions without a body. So for now
|
// and which are meant to be normal definitions without a body. So for now
|
||||||
// we just assume they are hosted functions (meant to be provided by the platform)
|
// we just assume they are hosted functions (meant to be provided by the platform)
|
||||||
if let Some(Hosted { effect_symbol, .. }) = hosted_info {
|
if has_no_implementation(&def.loc_expr.value) {
|
||||||
macro_rules! make_hosted_def {
|
match generated_info {
|
||||||
() => {
|
GeneratedInfo::Builtin => {
|
||||||
|
let symbol = def.pattern_vars.iter().next().unwrap().0;
|
||||||
|
match crate::builtins::builtin_defs_map(*symbol, var_store) {
|
||||||
|
None => {
|
||||||
|
panic!("A builtin module contains a signature without implementation for {:?}", symbol)
|
||||||
|
}
|
||||||
|
Some(mut replacement_def) => {
|
||||||
|
replacement_def.annotation = def.annotation.take();
|
||||||
|
*def = replacement_def;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GeneratedInfo::Hosted { effect_symbol, .. } => {
|
||||||
let symbol = def.pattern_vars.iter().next().unwrap().0;
|
let symbol = def.pattern_vars.iter().next().unwrap().0;
|
||||||
let ident_id = symbol.ident_id();
|
let ident_id = symbol.ident_id();
|
||||||
let ident =
|
let ident =
|
||||||
|
@ -376,27 +440,8 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
);
|
);
|
||||||
|
|
||||||
*def = hosted_def;
|
*def = hosted_def;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
_ => (),
|
||||||
match &def.loc_expr.value {
|
|
||||||
Expr::RuntimeError(RuntimeError::NoImplementationNamed {
|
|
||||||
..
|
|
||||||
}) => {
|
|
||||||
make_hosted_def!();
|
|
||||||
}
|
|
||||||
Expr::Closure(closure_data)
|
|
||||||
if matches!(
|
|
||||||
closure_data.loc_body.value,
|
|
||||||
Expr::RuntimeError(
|
|
||||||
RuntimeError::NoImplementationNamed { .. }
|
|
||||||
)
|
|
||||||
) =>
|
|
||||||
{
|
|
||||||
make_hosted_def!();
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -431,7 +476,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
|
|
||||||
let mut aliases = MutMap::default();
|
let mut aliases = MutMap::default();
|
||||||
|
|
||||||
if let Some(Hosted { effect_symbol, .. }) = hosted_info {
|
if let GeneratedInfo::Hosted { effect_symbol, .. } = generated_info {
|
||||||
// Remove this from exposed_symbols,
|
// Remove this from exposed_symbols,
|
||||||
// so that at the end of the process,
|
// so that at the end of the process,
|
||||||
// we can see if there were any
|
// we can see if there were any
|
||||||
|
@ -495,25 +540,14 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
|
|
||||||
for declaration in declarations.iter_mut() {
|
for declaration in declarations.iter_mut() {
|
||||||
match declaration {
|
match declaration {
|
||||||
Declare(def) => fix_values_captured_in_closure_def(def, &mut MutSet::default()),
|
Declare(def) => fix_values_captured_in_closure_def(def, &mut VecSet::default()),
|
||||||
DeclareRec(defs) => {
|
DeclareRec(defs) => {
|
||||||
fix_values_captured_in_closure_defs(defs, &mut MutSet::default())
|
fix_values_captured_in_closure_defs(defs, &mut VecSet::default())
|
||||||
}
|
}
|
||||||
InvalidCycle(_) | Builtin(_) => {}
|
InvalidCycle(_) | Builtin(_) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this loops over all symbols in the module, we can speed it up by having an
|
|
||||||
// iterator over all builtin symbols
|
|
||||||
for symbol in referenced_values.iter() {
|
|
||||||
if symbol.is_builtin() {
|
|
||||||
// this can fail when the symbol is for builtin types, or has no implementation yet
|
|
||||||
if let Some(def) = crate::builtins::builtin_defs_map(*symbol, var_store) {
|
|
||||||
declarations.push(Declaration::Builtin(def));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let output = ModuleOutput {
|
let output = ModuleOutput {
|
||||||
scope,
|
scope,
|
||||||
aliases,
|
aliases,
|
||||||
|
@ -535,7 +569,7 @@ pub fn canonicalize_module_defs<'a>(
|
||||||
|
|
||||||
fn fix_values_captured_in_closure_def(
|
fn fix_values_captured_in_closure_def(
|
||||||
def: &mut crate::def::Def,
|
def: &mut crate::def::Def,
|
||||||
no_capture_symbols: &mut MutSet<Symbol>,
|
no_capture_symbols: &mut VecSet<Symbol>,
|
||||||
) {
|
) {
|
||||||
// patterns can contain default expressions, so much go over them too!
|
// patterns can contain default expressions, so much go over them too!
|
||||||
fix_values_captured_in_closure_pattern(&mut def.loc_pattern.value, no_capture_symbols);
|
fix_values_captured_in_closure_pattern(&mut def.loc_pattern.value, no_capture_symbols);
|
||||||
|
@ -545,7 +579,7 @@ fn fix_values_captured_in_closure_def(
|
||||||
|
|
||||||
fn fix_values_captured_in_closure_defs(
|
fn fix_values_captured_in_closure_defs(
|
||||||
defs: &mut Vec<crate::def::Def>,
|
defs: &mut Vec<crate::def::Def>,
|
||||||
no_capture_symbols: &mut MutSet<Symbol>,
|
no_capture_symbols: &mut VecSet<Symbol>,
|
||||||
) {
|
) {
|
||||||
// recursive defs cannot capture each other
|
// recursive defs cannot capture each other
|
||||||
for def in defs.iter() {
|
for def in defs.iter() {
|
||||||
|
@ -561,7 +595,7 @@ fn fix_values_captured_in_closure_defs(
|
||||||
|
|
||||||
fn fix_values_captured_in_closure_pattern(
|
fn fix_values_captured_in_closure_pattern(
|
||||||
pattern: &mut crate::pattern::Pattern,
|
pattern: &mut crate::pattern::Pattern,
|
||||||
no_capture_symbols: &mut MutSet<Symbol>,
|
no_capture_symbols: &mut VecSet<Symbol>,
|
||||||
) {
|
) {
|
||||||
use crate::pattern::Pattern::*;
|
use crate::pattern::Pattern::*;
|
||||||
|
|
||||||
|
@ -610,7 +644,7 @@ fn fix_values_captured_in_closure_pattern(
|
||||||
|
|
||||||
fn fix_values_captured_in_closure_expr(
|
fn fix_values_captured_in_closure_expr(
|
||||||
expr: &mut crate::expr::Expr,
|
expr: &mut crate::expr::Expr,
|
||||||
no_capture_symbols: &mut MutSet<Symbol>,
|
no_capture_symbols: &mut VecSet<Symbol>,
|
||||||
) {
|
) {
|
||||||
use crate::expr::Expr::*;
|
use crate::expr::Expr::*;
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::expr::Expr;
|
use crate::expr::Expr;
|
||||||
use crate::pattern::Pattern;
|
use crate::pattern::Pattern;
|
||||||
use roc_collections::all::ImSet;
|
use roc_collections::all::VecSet;
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::Variable;
|
use roc_types::subs::Variable;
|
||||||
|
@ -44,12 +44,12 @@ impl Procedure {
|
||||||
/// so it's important that building the same code gives the same order every time!
|
/// so it's important that building the same code gives the same order every time!
|
||||||
#[derive(Clone, Debug, Default, PartialEq)]
|
#[derive(Clone, Debug, Default, PartialEq)]
|
||||||
pub struct References {
|
pub struct References {
|
||||||
pub bound_symbols: ImSet<Symbol>,
|
pub bound_symbols: VecSet<Symbol>,
|
||||||
pub type_lookups: ImSet<Symbol>,
|
pub type_lookups: VecSet<Symbol>,
|
||||||
pub value_lookups: ImSet<Symbol>,
|
pub value_lookups: VecSet<Symbol>,
|
||||||
/// Aliases or opaque types referenced
|
/// Aliases or opaque types referenced
|
||||||
pub referenced_type_defs: ImSet<Symbol>,
|
pub referenced_type_defs: VecSet<Symbol>,
|
||||||
pub calls: ImSet<Symbol>,
|
pub calls: VecSet<Symbol>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl References {
|
impl References {
|
||||||
|
@ -57,22 +57,15 @@ impl References {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn union(mut self, other: References) -> Self {
|
pub fn union_mut(&mut self, other: &References) {
|
||||||
self.value_lookups = self.value_lookups.union(other.value_lookups);
|
self.value_lookups
|
||||||
self.type_lookups = self.type_lookups.union(other.type_lookups);
|
.extend(other.value_lookups.iter().copied());
|
||||||
self.calls = self.calls.union(other.calls);
|
self.type_lookups.extend(other.type_lookups.iter().copied());
|
||||||
self.bound_symbols = self.bound_symbols.union(other.bound_symbols);
|
self.calls.extend(other.calls.iter().copied());
|
||||||
self.referenced_type_defs = self.referenced_type_defs.union(other.referenced_type_defs);
|
self.bound_symbols
|
||||||
|
.extend(other.bound_symbols.iter().copied());
|
||||||
self
|
self.referenced_type_defs
|
||||||
}
|
.extend(other.referenced_type_defs.iter().copied());
|
||||||
|
|
||||||
pub fn union_mut(&mut self, other: References) {
|
|
||||||
self.value_lookups.extend(other.value_lookups);
|
|
||||||
self.type_lookups.extend(other.type_lookups);
|
|
||||||
self.calls.extend(other.calls);
|
|
||||||
self.bound_symbols.extend(other.bound_symbols);
|
|
||||||
self.referenced_type_defs.extend(other.referenced_type_defs);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_value_lookup(&self, symbol: Symbol) -> bool {
|
pub fn has_value_lookup(&self, symbol: Symbol) -> bool {
|
||||||
|
|
|
@ -95,13 +95,17 @@ impl Scope {
|
||||||
pub fn lookup(&self, ident: &Ident, region: Region) -> Result<Symbol, RuntimeError> {
|
pub fn lookup(&self, ident: &Ident, region: Region) -> Result<Symbol, RuntimeError> {
|
||||||
match self.idents.get(ident) {
|
match self.idents.get(ident) {
|
||||||
Some((symbol, _)) => Ok(*symbol),
|
Some((symbol, _)) => Ok(*symbol),
|
||||||
None => Err(RuntimeError::LookupNotInScope(
|
None => {
|
||||||
|
let error = RuntimeError::LookupNotInScope(
|
||||||
Loc {
|
Loc {
|
||||||
region,
|
region,
|
||||||
value: ident.clone(),
|
value: ident.clone(),
|
||||||
},
|
},
|
||||||
self.idents.keys().map(|v| v.as_ref().into()).collect(),
|
self.idents.keys().map(|v| v.as_ref().into()).collect(),
|
||||||
)),
|
);
|
||||||
|
|
||||||
|
Err(error)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,11 @@ use roc_can::expr::{canonicalize_expr, Expr};
|
||||||
use roc_can::operator;
|
use roc_can::operator;
|
||||||
use roc_can::scope::Scope;
|
use roc_can::scope::Scope;
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds};
|
use roc_module::symbol::{IdentIds, Interns, ModuleId, ModuleIds, Symbol};
|
||||||
use roc_problem::can::Problem;
|
use roc_problem::can::Problem;
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::{VarStore, Variable};
|
use roc_types::subs::{VarStore, Variable};
|
||||||
|
use roc_types::types::Type;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
pub fn test_home() -> ModuleId {
|
pub fn test_home() -> ModuleId {
|
||||||
|
@ -55,6 +56,14 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
||||||
let loc_expr = operator::desugar_expr(arena, &loc_expr);
|
let loc_expr = operator::desugar_expr(arena, &loc_expr);
|
||||||
|
|
||||||
let mut scope = Scope::new(home, &mut var_store);
|
let mut scope = Scope::new(home, &mut var_store);
|
||||||
|
scope.add_alias(
|
||||||
|
Symbol::NUM_INT,
|
||||||
|
Region::zero(),
|
||||||
|
vec![Loc::at_zero(("a".into(), Variable::EMPTY_RECORD))],
|
||||||
|
Type::EmptyRec,
|
||||||
|
roc_types::types::AliasKind::Structural,
|
||||||
|
);
|
||||||
|
|
||||||
let dep_idents = IdentIds::exposed_builtins(0);
|
let dep_idents = IdentIds::exposed_builtins(0);
|
||||||
let mut env = Env::new(home, &dep_idents, &module_ids, IdentIds::default());
|
let mut env = Env::new(home, &dep_idents, &module_ids, IdentIds::default());
|
||||||
let (loc_expr, output) = canonicalize_expr(
|
let (loc_expr, output) = canonicalize_expr(
|
||||||
|
|
|
@ -50,7 +50,7 @@ mod test_can {
|
||||||
assert_eq!(IntValue::I128(expected), actual);
|
assert_eq!(IntValue::I128(expected), actual);
|
||||||
}
|
}
|
||||||
actual => {
|
actual => {
|
||||||
panic!("Expected an Int *, but got: {:?}", actual);
|
panic!("Expected an Num.Int *, but got: {:?}", actual);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -274,7 +274,7 @@ mod test_can {
|
||||||
fn correct_annotated_body() {
|
fn correct_annotated_body() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int * -> Int *
|
f : Num.Int * -> Num.Int *
|
||||||
f = \ a -> a
|
f = \ a -> a
|
||||||
|
|
||||||
f
|
f
|
||||||
|
@ -290,7 +290,7 @@ mod test_can {
|
||||||
fn correct_annotated_body_with_comments() {
|
fn correct_annotated_body_with_comments() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int * -> Int * # comment
|
f : Num.Int * -> Num.Int * # comment
|
||||||
f = \ a -> a
|
f = \ a -> a
|
||||||
|
|
||||||
f
|
f
|
||||||
|
@ -306,7 +306,7 @@ mod test_can {
|
||||||
fn name_mismatch_annotated_body() {
|
fn name_mismatch_annotated_body() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int * -> Int *
|
f : Num.Int * -> Num.Int *
|
||||||
g = \ a -> a
|
g = \ a -> a
|
||||||
|
|
||||||
g
|
g
|
||||||
|
@ -332,7 +332,7 @@ mod test_can {
|
||||||
fn name_mismatch_annotated_body_with_comment() {
|
fn name_mismatch_annotated_body_with_comment() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int * -> Int * # comment
|
f : Num.Int * -> Num.Int * # comment
|
||||||
g = \ a -> a
|
g = \ a -> a
|
||||||
|
|
||||||
g
|
g
|
||||||
|
@ -358,7 +358,7 @@ mod test_can {
|
||||||
fn separated_annotated_body() {
|
fn separated_annotated_body() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int * -> Int *
|
f : Num.Int * -> Num.Int *
|
||||||
|
|
||||||
f = \ a -> a
|
f = \ a -> a
|
||||||
|
|
||||||
|
@ -381,7 +381,7 @@ mod test_can {
|
||||||
fn separated_annotated_body_with_comment() {
|
fn separated_annotated_body_with_comment() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int * -> Int *
|
f : Num.Int * -> Num.Int *
|
||||||
# comment
|
# comment
|
||||||
f = \ a -> a
|
f = \ a -> a
|
||||||
|
|
||||||
|
@ -404,9 +404,9 @@ mod test_can {
|
||||||
fn shadowed_annotation() {
|
fn shadowed_annotation() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int * -> Int *
|
f : Num.Int * -> Num.Int *
|
||||||
|
|
||||||
f : Int * -> Int *
|
f : Num.Int * -> Num.Int *
|
||||||
|
|
||||||
f
|
f
|
||||||
"#
|
"#
|
||||||
|
@ -428,7 +428,7 @@ mod test_can {
|
||||||
fn correct_nested_unannotated_body() {
|
fn correct_nested_unannotated_body() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int *
|
f : Num.Int *
|
||||||
f =
|
f =
|
||||||
g = 42
|
g = 42
|
||||||
|
|
||||||
|
@ -447,9 +447,9 @@ mod test_can {
|
||||||
fn correct_nested_annotated_body() {
|
fn correct_nested_annotated_body() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int *
|
f : Num.Int *
|
||||||
f =
|
f =
|
||||||
g : Int *
|
g : Num.Int *
|
||||||
g = 42
|
g = 42
|
||||||
|
|
||||||
g + 1
|
g + 1
|
||||||
|
@ -467,11 +467,11 @@ mod test_can {
|
||||||
fn correct_nested_body_annotated_multiple_lines() {
|
fn correct_nested_body_annotated_multiple_lines() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int *
|
f : Num.Int *
|
||||||
f =
|
f =
|
||||||
g : Int *
|
g : Num.Int *
|
||||||
g = 42
|
g = 42
|
||||||
h : Int *
|
h : Num.Int *
|
||||||
h = 5
|
h = 5
|
||||||
z = 4
|
z = 4
|
||||||
g + h + z
|
g + h + z
|
||||||
|
@ -489,10 +489,10 @@ mod test_can {
|
||||||
fn correct_nested_body_unannotated_multiple_lines() {
|
fn correct_nested_body_unannotated_multiple_lines() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int *
|
f : Num.Int *
|
||||||
f =
|
f =
|
||||||
g = 42
|
g = 42
|
||||||
h : Int *
|
h : Num.Int *
|
||||||
h = 5
|
h = 5
|
||||||
z = 4
|
z = 4
|
||||||
g + h + z
|
g + h + z
|
||||||
|
@ -509,7 +509,7 @@ mod test_can {
|
||||||
fn correct_double_nested_body() {
|
fn correct_double_nested_body() {
|
||||||
let src = indoc!(
|
let src = indoc!(
|
||||||
r#"
|
r#"
|
||||||
f : Int *
|
f : Num.Int *
|
||||||
f =
|
f =
|
||||||
g =
|
g =
|
||||||
h = 42
|
h = 42
|
||||||
|
|
|
@ -220,3 +220,99 @@ macro_rules! mut_map {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct VecSet<T> {
|
||||||
|
elements: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Default for VecSet<T> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
elements: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: PartialEq> VecSet<T> {
|
||||||
|
pub fn with_capacity(capacity: usize) -> Self {
|
||||||
|
Self {
|
||||||
|
elements: Vec::with_capacity(capacity),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
self.elements.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.elements.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn swap_remove(&mut self, index: usize) -> T {
|
||||||
|
self.elements.swap_remove(index)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn insert(&mut self, value: T) -> bool {
|
||||||
|
if self.elements.contains(&value) {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.elements.push(value);
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn contains(&self, value: &T) -> bool {
|
||||||
|
self.elements.contains(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove(&mut self, value: &T) {
|
||||||
|
match self.elements.iter().position(|x| x == value) {
|
||||||
|
None => {
|
||||||
|
// just do nothing
|
||||||
|
}
|
||||||
|
Some(index) => {
|
||||||
|
self.elements.swap_remove(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter(&self) -> impl Iterator<Item = &T> {
|
||||||
|
self.elements.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<A: Ord> Extend<A> for VecSet<A> {
|
||||||
|
fn extend<T: IntoIterator<Item = A>>(&mut self, iter: T) {
|
||||||
|
let it = iter.into_iter();
|
||||||
|
let hint = it.size_hint();
|
||||||
|
|
||||||
|
match hint {
|
||||||
|
(0, Some(0)) => {
|
||||||
|
// done, do nothing
|
||||||
|
}
|
||||||
|
(1, Some(1)) | (2, Some(2)) => {
|
||||||
|
for value in it {
|
||||||
|
self.insert(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
self.elements.extend(it);
|
||||||
|
|
||||||
|
self.elements.sort();
|
||||||
|
self.elements.dedup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> IntoIterator for VecSet<T> {
|
||||||
|
type Item = T;
|
||||||
|
|
||||||
|
type IntoIter = std::vec::IntoIter<T>;
|
||||||
|
|
||||||
|
fn into_iter(self) -> Self::IntoIter {
|
||||||
|
self.elements.into_iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -596,66 +596,66 @@ pub fn constrain_expr(
|
||||||
NoExpectation(cond_type.clone()),
|
NoExpectation(cond_type.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let mut branch_constraints = Vec::with_capacity(branches.len() + 1);
|
let branch_var = *expr_var;
|
||||||
branch_constraints.push(expr_con);
|
let branch_type = Variable(branch_var);
|
||||||
|
|
||||||
match &expected {
|
let branch_expr_reason =
|
||||||
|
|expected: &Expected<Type>, index, branch_region| match expected {
|
||||||
FromAnnotation(name, arity, ann_source, _typ) => {
|
FromAnnotation(name, arity, ann_source, _typ) => {
|
||||||
// NOTE deviation from elm.
|
// NOTE deviation from elm.
|
||||||
//
|
//
|
||||||
// in elm, `_typ` is used, but because we have this `expr_var` too
|
// in elm, `_typ` is used, but because we have this `expr_var` too
|
||||||
// and need to constrain it, this is what works and gives better error messages
|
// and need to constrain it, this is what works and gives better error messages
|
||||||
let typ = Type::Variable(*expr_var);
|
|
||||||
|
|
||||||
for (index, when_branch) in branches.iter().enumerate() {
|
|
||||||
let pattern_region =
|
|
||||||
Region::across_all(when_branch.patterns.iter().map(|v| &v.region));
|
|
||||||
|
|
||||||
let branch_con = constrain_when_branch(
|
|
||||||
constraints,
|
|
||||||
env,
|
|
||||||
when_branch.value.region,
|
|
||||||
when_branch,
|
|
||||||
PExpected::ForReason(
|
|
||||||
PReason::WhenMatch {
|
|
||||||
index: HumanIndex::zero_based(index),
|
|
||||||
},
|
|
||||||
cond_type.clone(),
|
|
||||||
pattern_region,
|
|
||||||
),
|
|
||||||
FromAnnotation(
|
FromAnnotation(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
*arity,
|
*arity,
|
||||||
AnnotationSource::TypedWhenBranch {
|
AnnotationSource::TypedWhenBranch {
|
||||||
index: HumanIndex::zero_based(index),
|
index,
|
||||||
region: ann_source.region(),
|
region: ann_source.region(),
|
||||||
},
|
},
|
||||||
typ.clone(),
|
branch_type.clone(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
_ => ForReason(
|
||||||
|
Reason::WhenBranch { index },
|
||||||
|
branch_type.clone(),
|
||||||
|
branch_region,
|
||||||
),
|
),
|
||||||
);
|
};
|
||||||
|
|
||||||
branch_constraints.push(branch_con);
|
// Our goal is to constrain and introduce variables in all pattern when branch patterns before
|
||||||
}
|
// looking at their bodies.
|
||||||
|
//
|
||||||
branch_constraints.push(constraints.equal_types_var(
|
// pat1 -> body1
|
||||||
*expr_var,
|
// *^^^ +~~~~
|
||||||
expected,
|
// pat2 -> body2
|
||||||
Category::When,
|
// *^^^ +~~~~
|
||||||
region,
|
//
|
||||||
));
|
// * solve first
|
||||||
|
// + solve second
|
||||||
return constraints.exists_many([cond_var, *expr_var], branch_constraints);
|
//
|
||||||
}
|
// For a single pattern/body pair, we must introduce variables and symbols defined in the
|
||||||
|
// pattern before solving the body, since those definitions are effectively let-bound.
|
||||||
_ => {
|
//
|
||||||
let branch_var = *expr_var;
|
// But also, we'd like to solve all branch pattern constraints in one swoop before looking at
|
||||||
let branch_type = Variable(branch_var);
|
// the bodies, because the patterns may have presence constraints that expect to be built up
|
||||||
|
// together.
|
||||||
|
//
|
||||||
|
// For this reason, we distinguish the two - and introduce variables in the branch patterns
|
||||||
|
// as part of the pattern constraint, solving all of those at once, and then solving the body
|
||||||
|
// constraints.
|
||||||
|
let mut pattern_vars = Vec::with_capacity(branches.len());
|
||||||
|
let mut pattern_headers = SendMap::default();
|
||||||
|
let mut pattern_cons = Vec::with_capacity(branches.len());
|
||||||
let mut branch_cons = Vec::with_capacity(branches.len());
|
let mut branch_cons = Vec::with_capacity(branches.len());
|
||||||
|
|
||||||
for (index, when_branch) in branches.iter().enumerate() {
|
for (index, when_branch) in branches.iter().enumerate() {
|
||||||
let pattern_region =
|
let pattern_region =
|
||||||
Region::across_all(when_branch.patterns.iter().map(|v| &v.region));
|
Region::across_all(when_branch.patterns.iter().map(|v| &v.region));
|
||||||
let branch_con = constrain_when_branch(
|
|
||||||
|
let (new_pattern_vars, new_pattern_headers, pattern_con, branch_con) =
|
||||||
|
constrain_when_branch_help(
|
||||||
constraints,
|
constraints,
|
||||||
env,
|
env,
|
||||||
region,
|
region,
|
||||||
|
@ -667,15 +667,24 @@ pub fn constrain_expr(
|
||||||
cond_type.clone(),
|
cond_type.clone(),
|
||||||
pattern_region,
|
pattern_region,
|
||||||
),
|
),
|
||||||
ForReason(
|
branch_expr_reason(
|
||||||
Reason::WhenBranch {
|
&expected,
|
||||||
index: HumanIndex::zero_based(index),
|
HumanIndex::zero_based(index),
|
||||||
},
|
|
||||||
branch_type.clone(),
|
|
||||||
when_branch.value.region,
|
when_branch.value.region,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
pattern_vars.extend(new_pattern_vars);
|
||||||
|
debug_assert!(
|
||||||
|
pattern_headers
|
||||||
|
.clone()
|
||||||
|
.intersection(new_pattern_headers.clone())
|
||||||
|
.is_empty(),
|
||||||
|
"Two patterns introduce the same symbols - that's a bug!"
|
||||||
|
);
|
||||||
|
pattern_headers.extend(new_pattern_headers);
|
||||||
|
pattern_cons.push(pattern_con);
|
||||||
|
|
||||||
branch_cons.push(branch_con);
|
branch_cons.push(branch_con);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -687,18 +696,36 @@ pub fn constrain_expr(
|
||||||
//
|
//
|
||||||
// The return type of each branch must equal the return type of
|
// The return type of each branch must equal the return type of
|
||||||
// the entire when-expression.
|
// the entire when-expression.
|
||||||
branch_cons.push(constraints.equal_types_var(
|
// branch_cons.extend(pattern_cons);
|
||||||
|
// branch_constraints.push(constraints.and_constraint(pattern_cons));
|
||||||
|
let mut total_cons = Vec::with_capacity(1 + 2 * branches.len() + 1);
|
||||||
|
total_cons.push(expr_con);
|
||||||
|
|
||||||
|
// Solve all the pattern constraints together, introducing variables in the pattern as
|
||||||
|
// need be before solving the bodies.
|
||||||
|
let pattern_constraints = constraints.and_constraint(pattern_cons);
|
||||||
|
let body_constraints = constraints.and_constraint(branch_cons);
|
||||||
|
let when_body_con = constraints.let_constraint(
|
||||||
|
[],
|
||||||
|
pattern_vars,
|
||||||
|
pattern_headers,
|
||||||
|
pattern_constraints,
|
||||||
|
body_constraints,
|
||||||
|
);
|
||||||
|
total_cons.push(when_body_con);
|
||||||
|
|
||||||
|
total_cons.push(constraints.equal_types_var(
|
||||||
branch_var,
|
branch_var,
|
||||||
expected,
|
expected,
|
||||||
Category::When,
|
Category::When,
|
||||||
region,
|
region,
|
||||||
));
|
));
|
||||||
branch_constraints.push(constraints.and_constraint(branch_cons));
|
|
||||||
}
|
let branch_constraints = constraints.and_constraint(total_cons);
|
||||||
}
|
|
||||||
|
|
||||||
// exhautiveness checking happens when converting to mono::Expr
|
// exhautiveness checking happens when converting to mono::Expr
|
||||||
constraints.exists_many([cond_var, *expr_var], branch_constraints)
|
// ...for now
|
||||||
|
constraints.exists([cond_var, *expr_var], branch_constraints)
|
||||||
}
|
}
|
||||||
Access {
|
Access {
|
||||||
record_var,
|
record_var,
|
||||||
|
@ -1087,15 +1114,22 @@ pub fn constrain_expr(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Constrain a when branch, returning (variables in pattern, symbols introduced in pattern, pattern constraint, body constraint).
|
||||||
|
/// We want to constraint all pattern constraints in a "when" before body constraints.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn constrain_when_branch(
|
fn constrain_when_branch_help(
|
||||||
constraints: &mut Constraints,
|
constraints: &mut Constraints,
|
||||||
env: &Env,
|
env: &Env,
|
||||||
region: Region,
|
region: Region,
|
||||||
when_branch: &WhenBranch,
|
when_branch: &WhenBranch,
|
||||||
pattern_expected: PExpected<Type>,
|
pattern_expected: PExpected<Type>,
|
||||||
expr_expected: Expected<Type>,
|
expr_expected: Expected<Type>,
|
||||||
) -> Constraint {
|
) -> (
|
||||||
|
Vec<Variable>,
|
||||||
|
SendMap<Symbol, Loc<Type>>,
|
||||||
|
Constraint,
|
||||||
|
Constraint,
|
||||||
|
) {
|
||||||
let ret_constraint = constrain_expr(
|
let ret_constraint = constrain_expr(
|
||||||
constraints,
|
constraints,
|
||||||
env,
|
env,
|
||||||
|
@ -1123,7 +1157,7 @@ fn constrain_when_branch(
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(loc_guard) = &when_branch.guard {
|
let (pattern_constraints, body_constraints) = if let Some(loc_guard) = &when_branch.guard {
|
||||||
let guard_constraint = constrain_expr(
|
let guard_constraint = constrain_expr(
|
||||||
constraints,
|
constraints,
|
||||||
env,
|
env,
|
||||||
|
@ -1140,18 +1174,19 @@ fn constrain_when_branch(
|
||||||
let state_constraints = constraints.and_constraint(state.constraints);
|
let state_constraints = constraints.and_constraint(state.constraints);
|
||||||
let inner = constraints.let_constraint([], [], [], guard_constraint, ret_constraint);
|
let inner = constraints.let_constraint([], [], [], guard_constraint, ret_constraint);
|
||||||
|
|
||||||
constraints.let_constraint([], state.vars, state.headers, state_constraints, inner)
|
(state_constraints, inner)
|
||||||
} else {
|
} else {
|
||||||
let state_constraints = constraints.and_constraint(state.constraints);
|
let state_constraints = constraints.and_constraint(state.constraints);
|
||||||
constraints.let_constraint(
|
(state_constraints, ret_constraint)
|
||||||
[],
|
};
|
||||||
|
|
||||||
|
(
|
||||||
state.vars,
|
state.vars,
|
||||||
state.headers,
|
state.headers,
|
||||||
state_constraints,
|
pattern_constraints,
|
||||||
ret_constraint,
|
body_constraints,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn constrain_field(
|
fn constrain_field(
|
||||||
constraints: &mut Constraints,
|
constraints: &mut Constraints,
|
||||||
|
|
|
@ -2,12 +2,14 @@ use roc_builtins::std::StdLib;
|
||||||
use roc_can::abilities::AbilitiesStore;
|
use roc_can::abilities::AbilitiesStore;
|
||||||
use roc_can::constraint::{Constraint, Constraints};
|
use roc_can::constraint::{Constraint, Constraints};
|
||||||
use roc_can::def::Declaration;
|
use roc_can::def::Declaration;
|
||||||
|
use roc_can::expected::Expected;
|
||||||
use roc_collections::all::MutMap;
|
use roc_collections::all::MutMap;
|
||||||
use roc_error_macros::internal_error;
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::symbol::{ModuleId, Symbol};
|
use roc_module::symbol::{ModuleId, Symbol};
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::solved_types::{FreeVars, SolvedType};
|
use roc_types::solved_types::{FreeVars, SolvedType};
|
||||||
use roc_types::subs::{VarStore, Variable};
|
use roc_types::subs::{VarStore, Variable};
|
||||||
|
use roc_types::types::{Category, Type};
|
||||||
|
|
||||||
/// The types of all exposed values/functions of a collection of modules
|
/// The types of all exposed values/functions of a collection of modules
|
||||||
#[derive(Clone, Debug, Default)]
|
#[derive(Clone, Debug, Default)]
|
||||||
|
@ -65,17 +67,8 @@ impl ExposedForModule {
|
||||||
let mut imported_values = Vec::new();
|
let mut imported_values = Vec::new();
|
||||||
|
|
||||||
for symbol in it {
|
for symbol in it {
|
||||||
// Today, builtins are not actually imported,
|
let module = exposed_by_module.exposed.get(&symbol.module_id());
|
||||||
// but generated in each module that uses them
|
if let Some(ExposedModuleTypes::Valid { .. }) = module {
|
||||||
//
|
|
||||||
// This will change when we write builtins in roc
|
|
||||||
if symbol.is_builtin() {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(ExposedModuleTypes::Valid { .. }) =
|
|
||||||
exposed_by_module.exposed.get(&symbol.module_id())
|
|
||||||
{
|
|
||||||
imported_values.push(*symbol);
|
imported_values.push(*symbol);
|
||||||
} else {
|
} else {
|
||||||
continue;
|
continue;
|
||||||
|
@ -105,27 +98,53 @@ pub fn constrain_module(
|
||||||
declarations: &[Declaration],
|
declarations: &[Declaration],
|
||||||
home: ModuleId,
|
home: ModuleId,
|
||||||
) -> Constraint {
|
) -> Constraint {
|
||||||
let mut constraint = crate::expr::constrain_decls(constraints, home, declarations);
|
let constraint = crate::expr::constrain_decls(constraints, home, declarations);
|
||||||
|
|
||||||
|
let constraint = frontload_ability_constraints(constraints, abilities_store, constraint);
|
||||||
|
|
||||||
|
// The module constraint should always save the environment at the end.
|
||||||
|
debug_assert!(constraints.contains_save_the_environment(&constraint));
|
||||||
|
|
||||||
|
constraint
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn frontload_ability_constraints(
|
||||||
|
constraints: &mut Constraints,
|
||||||
|
abilities_store: &AbilitiesStore,
|
||||||
|
mut constraint: Constraint,
|
||||||
|
) -> Constraint {
|
||||||
for (member_name, member_data) in abilities_store.root_ability_members().iter() {
|
for (member_name, member_data) in abilities_store.root_ability_members().iter() {
|
||||||
|
// 1. Attach the type of member signature to the reserved signature_var. This is
|
||||||
|
// infallible.
|
||||||
|
let unify_with_signature_var = constraints.equal_types_var(
|
||||||
|
member_data.signature_var,
|
||||||
|
Expected::NoExpectation(member_data.signature.clone()),
|
||||||
|
Category::Storage(std::file!(), std::column!()),
|
||||||
|
Region::zero(),
|
||||||
|
);
|
||||||
|
|
||||||
|
// 2. Store the member signature on the member symbol. This makes sure we generalize it on
|
||||||
|
// the toplevel, as appropriate.
|
||||||
let vars = &member_data.variables;
|
let vars = &member_data.variables;
|
||||||
let rigids = (vars.rigid_vars.iter())
|
let rigids = (vars.rigid_vars.iter())
|
||||||
// For our purposes, in the let constraint, able vars are treated like rigids.
|
// For our purposes, in the let constraint, able vars are treated like rigids.
|
||||||
.chain(vars.able_vars.iter())
|
.chain(vars.able_vars.iter())
|
||||||
.copied();
|
.copied();
|
||||||
let flex = vars.flex_vars.iter().copied();
|
let flex = vars.flex_vars.iter().copied();
|
||||||
constraint = constraints.let_constraint(
|
|
||||||
|
let let_constr = constraints.let_constraint(
|
||||||
rigids,
|
rigids,
|
||||||
flex,
|
flex,
|
||||||
[(*member_name, Loc::at_zero(member_data.signature.clone()))],
|
[(
|
||||||
|
*member_name,
|
||||||
|
Loc::at_zero(Type::Variable(member_data.signature_var)),
|
||||||
|
)],
|
||||||
Constraint::True,
|
Constraint::True,
|
||||||
constraint,
|
constraint,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
constraint = constraints.and_constraint([unify_with_signature_var, let_constr]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The module constraint should always save the environment at the end.
|
|
||||||
debug_assert!(constraints.contains_save_the_environment(&constraint));
|
|
||||||
|
|
||||||
constraint
|
constraint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,17 +189,6 @@ pub fn constrain_builtin_imports(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let is_valid_alias = stdlib.applies.contains(&symbol)
|
|
||||||
// This wasn't a builtin value or Apply; maybe it was a builtin alias.
|
|
||||||
|| roc_types::builtin_aliases::aliases().contains_key(&symbol);
|
|
||||||
|
|
||||||
if !is_valid_alias {
|
|
||||||
panic!(
|
|
||||||
"Could not find {:?} in builtin types {:?} or builtin aliases",
|
|
||||||
symbol, stdlib.types,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -6070,6 +6070,13 @@ fn run_low_level<'a, 'ctx, 'env>(
|
||||||
let key_layout = list_element_layout!(list_layout);
|
let key_layout = list_element_layout!(list_layout);
|
||||||
set_from_list(env, layout_ids, list, key_layout)
|
set_from_list(env, layout_ids, list, key_layout)
|
||||||
}
|
}
|
||||||
|
SetToDict => {
|
||||||
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
let (set, _set_layout) = load_symbol_and_layout(scope, &args[0]);
|
||||||
|
|
||||||
|
set
|
||||||
|
}
|
||||||
ExpectTrue => {
|
ExpectTrue => {
|
||||||
debug_assert_eq!(args.len(), 1);
|
debug_assert_eq!(args.len(), 1);
|
||||||
|
|
||||||
|
|
|
@ -283,7 +283,7 @@ impl<'a> LowLevelCall<'a> {
|
||||||
|
|
||||||
DictSize | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe
|
DictSize | DictEmpty | DictInsert | DictRemove | DictContains | DictGetUnsafe
|
||||||
| DictKeys | DictValues | DictUnion | DictIntersection | DictDifference
|
| DictKeys | DictValues | DictUnion | DictIntersection | DictDifference
|
||||||
| SetFromList => {
|
| SetFromList | SetToDict => {
|
||||||
todo!("{:?}", self.lowlevel);
|
todo!("{:?}", self.lowlevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -30,7 +30,8 @@ impl IdentStr {
|
||||||
// Reserve 1 byte for the discriminant
|
// Reserve 1 byte for the discriminant
|
||||||
const SMALL_STR_BYTES: usize = std::mem::size_of::<Self>() - 1;
|
const SMALL_STR_BYTES: usize = std::mem::size_of::<Self>() - 1;
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
#[inline(always)]
|
||||||
|
pub const fn len(&self) -> usize {
|
||||||
let bytes = self.length.to_ne_bytes();
|
let bytes = self.length.to_ne_bytes();
|
||||||
let last_byte = bytes[mem::size_of::<usize>() - 1];
|
let last_byte = bytes[mem::size_of::<usize>() - 1];
|
||||||
|
|
||||||
|
@ -55,11 +56,11 @@ impl IdentStr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_empty(&self) -> bool {
|
pub const fn is_empty(&self) -> bool {
|
||||||
self.length == 0
|
self.length == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_small_str(&self) -> bool {
|
pub const fn is_small_str(&self) -> bool {
|
||||||
let bytes = self.length.to_ne_bytes();
|
let bytes = self.length.to_ne_bytes();
|
||||||
let last_byte = bytes[mem::size_of::<usize>() - 1];
|
let last_byte = bytes[mem::size_of::<usize>() - 1];
|
||||||
|
|
||||||
|
|
|
@ -5,13 +5,13 @@ use roc_module::symbol::ModuleId;
|
||||||
|
|
||||||
const MODULES: &[(ModuleId, &str)] = &[
|
const MODULES: &[(ModuleId, &str)] = &[
|
||||||
(ModuleId::BOOL, "Bool.roc"),
|
(ModuleId::BOOL, "Bool.roc"),
|
||||||
// (ModuleId::RESULT, "Result.roc"),
|
(ModuleId::RESULT, "Result.roc"),
|
||||||
// (ModuleId::LIST, "List.roc"),
|
(ModuleId::NUM, "Num.roc"),
|
||||||
// (ModuleId::STR, "Str.roc"),
|
(ModuleId::LIST, "List.roc"),
|
||||||
// (ModuleId::DICT, "Dict.roc"),
|
(ModuleId::STR, "Str.roc"),
|
||||||
// (ModuleId::SET, "Set.roc"),
|
(ModuleId::DICT, "Dict.roc"),
|
||||||
// (ModuleId::BOX, "Box.roc"),
|
(ModuleId::SET, "Set.roc"),
|
||||||
// (ModuleId::NUM, "Num.roc"),
|
(ModuleId::BOX, "Box.roc"),
|
||||||
];
|
];
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -35,6 +35,30 @@ fn load<'a>(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Load using only a single thread; used when compiling to webassembly
|
||||||
|
pub fn load_single_threaded<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
load_start: LoadStart<'a>,
|
||||||
|
src_dir: &Path,
|
||||||
|
exposed_types: ExposedByModule,
|
||||||
|
goal_phase: Phase,
|
||||||
|
target_info: TargetInfo,
|
||||||
|
render: RenderTarget,
|
||||||
|
) -> Result<LoadResult<'a>, LoadingProblem<'a>> {
|
||||||
|
let cached_subs = read_cached_subs();
|
||||||
|
|
||||||
|
roc_load_internal::file::load_single_threaded(
|
||||||
|
arena,
|
||||||
|
load_start,
|
||||||
|
src_dir,
|
||||||
|
exposed_types,
|
||||||
|
goal_phase,
|
||||||
|
target_info,
|
||||||
|
cached_subs,
|
||||||
|
render,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn load_and_monomorphize_from_str<'a>(
|
pub fn load_and_monomorphize_from_str<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
filename: PathBuf,
|
filename: PathBuf,
|
||||||
|
@ -114,14 +138,44 @@ pub fn load_and_typecheck<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn load_and_typecheck_str<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
filename: PathBuf,
|
||||||
|
source: &'a str,
|
||||||
|
src_dir: &Path,
|
||||||
|
exposed_types: ExposedByModule,
|
||||||
|
target_info: TargetInfo,
|
||||||
|
render: RenderTarget,
|
||||||
|
) -> Result<LoadedModule, LoadingProblem<'a>> {
|
||||||
|
use LoadResult::*;
|
||||||
|
|
||||||
|
let load_start = LoadStart::from_str(arena, filename, source)?;
|
||||||
|
|
||||||
|
// NOTE: this function is meant for tests, and so we use single-threaded
|
||||||
|
// solving so we don't use too many threads per-test. That gives higher
|
||||||
|
// throughput for the test run overall
|
||||||
|
match load_single_threaded(
|
||||||
|
arena,
|
||||||
|
load_start,
|
||||||
|
src_dir,
|
||||||
|
exposed_types,
|
||||||
|
Phase::SolveTypes,
|
||||||
|
target_info,
|
||||||
|
render,
|
||||||
|
)? {
|
||||||
|
Monomorphized(_) => unreachable!(""),
|
||||||
|
TypeChecked(module) => Ok(module),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const BOOL: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Bool.dat")) as &[_];
|
const BOOL: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Bool.dat")) as &[_];
|
||||||
// const RESULT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Result.dat")) as &[_];
|
const RESULT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Result.dat")) as &[_];
|
||||||
// const LIST: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/List.dat")) as &[_];
|
const LIST: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/List.dat")) as &[_];
|
||||||
// const STR: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Str.dat")) as &[_];
|
const STR: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Str.dat")) as &[_];
|
||||||
// const DICT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Dict.dat")) as &[_];
|
const DICT: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Dict.dat")) as &[_];
|
||||||
// const SET: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Set.dat")) as &[_];
|
const SET: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Set.dat")) as &[_];
|
||||||
// const BOX: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Box.dat")) as &[_];
|
const BOX: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Box.dat")) as &[_];
|
||||||
// const NUM: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Num.dat")) as &[_];
|
const NUM: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/Num.dat")) as &[_];
|
||||||
|
|
||||||
fn deserialize_help(bytes: &[u8]) -> (Subs, Vec<(Symbol, Variable)>) {
|
fn deserialize_help(bytes: &[u8]) -> (Subs, Vec<(Symbol, Variable)>) {
|
||||||
let (subs, slice) = Subs::deserialize(bytes);
|
let (subs, slice) = Subs::deserialize(bytes);
|
||||||
|
@ -132,14 +186,20 @@ fn deserialize_help(bytes: &[u8]) -> (Subs, Vec<(Symbol, Variable)>) {
|
||||||
fn read_cached_subs() -> MutMap<ModuleId, (Subs, Vec<(Symbol, Variable)>)> {
|
fn read_cached_subs() -> MutMap<ModuleId, (Subs, Vec<(Symbol, Variable)>)> {
|
||||||
let mut output = MutMap::default();
|
let mut output = MutMap::default();
|
||||||
|
|
||||||
|
// Wasm seems to re-order definitions between build time and runtime, but only in release mode.
|
||||||
|
// That is very strange, but we can solve it separately
|
||||||
|
if !cfg!(target_family = "wasm") {
|
||||||
output.insert(ModuleId::BOOL, deserialize_help(BOOL));
|
output.insert(ModuleId::BOOL, deserialize_help(BOOL));
|
||||||
// output.insert(ModuleId::RESULT, deserialize_help(RESULT));
|
output.insert(ModuleId::RESULT, deserialize_help(RESULT));
|
||||||
// output.insert(ModuleId::LIST, deserialize_help(LIST));
|
output.insert(ModuleId::NUM, deserialize_help(NUM));
|
||||||
// output.insert(ModuleId::STR, deserialize_help(STR));
|
|
||||||
// output.insert(ModuleId::DICT, deserialize_help(DICT));
|
output.insert(ModuleId::LIST, deserialize_help(LIST));
|
||||||
// output.insert(ModuleId::SET, deserialize_help(SET));
|
output.insert(ModuleId::STR, deserialize_help(STR));
|
||||||
// output.insert(ModuleId::BOX, deserialize_help(BOX));
|
output.insert(ModuleId::DICT, deserialize_help(DICT));
|
||||||
// output.insert(ModuleId::NUM, deserialize_help(NUM));
|
|
||||||
|
output.insert(ModuleId::SET, deserialize_help(SET));
|
||||||
|
output.insert(ModuleId::BOX, deserialize_help(BOX));
|
||||||
|
}
|
||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,12 +4,13 @@ use crossbeam::channel::{bounded, Sender};
|
||||||
use crossbeam::deque::{Injector, Stealer, Worker};
|
use crossbeam::deque::{Injector, Stealer, Worker};
|
||||||
use crossbeam::thread;
|
use crossbeam::thread;
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
|
use roc_builtins::roc::module_source;
|
||||||
use roc_builtins::std::borrow_stdlib;
|
use roc_builtins::std::borrow_stdlib;
|
||||||
use roc_can::abilities::AbilitiesStore;
|
use roc_can::abilities::AbilitiesStore;
|
||||||
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
|
use roc_can::constraint::{Constraint as ConstraintSoa, Constraints};
|
||||||
use roc_can::def::Declaration;
|
use roc_can::def::Declaration;
|
||||||
use roc_can::module::{canonicalize_module_defs, Module};
|
use roc_can::module::{canonicalize_module_defs, Module};
|
||||||
use roc_collections::all::{default_hasher, BumpMap, MutMap, MutSet};
|
use roc_collections::all::{default_hasher, BumpMap, MutMap, MutSet, VecSet};
|
||||||
use roc_constrain::module::{
|
use roc_constrain::module::{
|
||||||
constrain_builtin_imports, constrain_module, ExposedByModule, ExposedForModule,
|
constrain_builtin_imports, constrain_module, ExposedByModule, ExposedForModule,
|
||||||
ExposedModuleTypes,
|
ExposedModuleTypes,
|
||||||
|
@ -40,7 +41,7 @@ use roc_types::solved_types::Solved;
|
||||||
use roc_types::subs::{Subs, VarStore, Variable};
|
use roc_types::subs::{Subs, VarStore, Variable};
|
||||||
use roc_types::types::{Alias, AliasCommon, TypeExtension};
|
use roc_types::types::{Alias, AliasCommon, TypeExtension};
|
||||||
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
use std::collections::hash_map::Entry::{Occupied, Vacant};
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::HashMap;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::ops::ControlFlow;
|
use std::ops::ControlFlow;
|
||||||
|
@ -79,7 +80,7 @@ macro_rules! log {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Struct storing various intermediate stages by their ModuleId
|
/// Struct storing various intermediate stages by their ModuleId
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
struct ModuleCache<'a> {
|
struct ModuleCache<'a> {
|
||||||
module_names: MutMap<ModuleId, PQModuleName<'a>>,
|
module_names: MutMap<ModuleId, PQModuleName<'a>>,
|
||||||
|
|
||||||
|
@ -103,6 +104,70 @@ struct ModuleCache<'a> {
|
||||||
sources: MutMap<ModuleId, (PathBuf, &'a str)>,
|
sources: MutMap<ModuleId, (PathBuf, &'a str)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for ModuleCache<'_> {
|
||||||
|
fn default() -> Self {
|
||||||
|
let mut module_names = MutMap::default();
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::RESULT,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::RESULT)),
|
||||||
|
);
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::LIST,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::LIST)),
|
||||||
|
);
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::STR,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::STR)),
|
||||||
|
);
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::DICT,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::DICT)),
|
||||||
|
);
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::SET,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::SET)),
|
||||||
|
);
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::BOOL,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::BOOL)),
|
||||||
|
);
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::NUM,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::NUM)),
|
||||||
|
);
|
||||||
|
|
||||||
|
module_names.insert(
|
||||||
|
ModuleId::BOX,
|
||||||
|
PQModuleName::Unqualified(ModuleName::from(ModuleName::BOX)),
|
||||||
|
);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
module_names,
|
||||||
|
headers: Default::default(),
|
||||||
|
parsed: Default::default(),
|
||||||
|
aliases: Default::default(),
|
||||||
|
constrained: Default::default(),
|
||||||
|
typechecked: Default::default(),
|
||||||
|
found_specializations: Default::default(),
|
||||||
|
external_specializations_requested: Default::default(),
|
||||||
|
imports: Default::default(),
|
||||||
|
top_level_thunks: Default::default(),
|
||||||
|
documentation: Default::default(),
|
||||||
|
can_problems: Default::default(),
|
||||||
|
type_problems: Default::default(),
|
||||||
|
mono_problems: Default::default(),
|
||||||
|
sources: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn start_phase<'a>(
|
fn start_phase<'a>(
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
phase: Phase,
|
phase: Phase,
|
||||||
|
@ -131,15 +196,17 @@ fn start_phase<'a>(
|
||||||
let task = {
|
let task = {
|
||||||
match phase {
|
match phase {
|
||||||
Phase::LoadHeader => {
|
Phase::LoadHeader => {
|
||||||
let dep_name = state
|
let opt_dep_name = state.module_cache.module_names.get(&module_id);
|
||||||
.module_cache
|
|
||||||
.module_names
|
match opt_dep_name {
|
||||||
.get(&module_id)
|
None => {
|
||||||
.expect("module id is present")
|
panic!("Module {:?} is not in module_cache.module_names", module_id)
|
||||||
.clone();
|
}
|
||||||
|
Some(dep_name) => {
|
||||||
|
let module_name = dep_name.clone();
|
||||||
|
|
||||||
BuildTask::LoadModule {
|
BuildTask::LoadModule {
|
||||||
module_name: dep_name,
|
module_name,
|
||||||
// Provide mutexes of ModuleIds and IdentIds by module,
|
// Provide mutexes of ModuleIds and IdentIds by module,
|
||||||
// so other modules can populate them as they load.
|
// so other modules can populate them as they load.
|
||||||
module_ids: Arc::clone(&state.arc_modules),
|
module_ids: Arc::clone(&state.arc_modules),
|
||||||
|
@ -147,6 +214,8 @@ fn start_phase<'a>(
|
||||||
ident_ids_by_module: Arc::clone(&state.ident_ids_by_module),
|
ident_ids_by_module: Arc::clone(&state.ident_ids_by_module),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Phase::Parse => {
|
Phase::Parse => {
|
||||||
// parse the file
|
// parse the file
|
||||||
let header = state.module_cache.headers.remove(&module_id).unwrap();
|
let header = state.module_cache.headers.remove(&module_id).unwrap();
|
||||||
|
@ -222,12 +291,15 @@ fn start_phase<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let skip_constraint_gen = state.cached_subs.lock().contains_key(&module_id);
|
||||||
|
|
||||||
BuildTask::CanonicalizeAndConstrain {
|
BuildTask::CanonicalizeAndConstrain {
|
||||||
parsed,
|
parsed,
|
||||||
dep_idents,
|
dep_idents,
|
||||||
exposed_symbols,
|
exposed_symbols,
|
||||||
module_ids,
|
module_ids,
|
||||||
aliases,
|
aliases,
|
||||||
|
skip_constraint_gen,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,6 +343,7 @@ fn start_phase<'a>(
|
||||||
solved_subs,
|
solved_subs,
|
||||||
decls,
|
decls,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
|
abilities_store,
|
||||||
} = typechecked;
|
} = typechecked;
|
||||||
|
|
||||||
let mut imported_module_thunks = bumpalo::collections::Vec::new_in(arena);
|
let mut imported_module_thunks = bumpalo::collections::Vec::new_in(arena);
|
||||||
|
@ -294,6 +367,7 @@ fn start_phase<'a>(
|
||||||
decls,
|
decls,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
exposed_to_host: state.exposed_to_host.clone(),
|
exposed_to_host: state.exposed_to_host.clone(),
|
||||||
|
abilities_store,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Phase::MakeSpecializations => {
|
Phase::MakeSpecializations => {
|
||||||
|
@ -316,6 +390,7 @@ fn start_phase<'a>(
|
||||||
procs_base,
|
procs_base,
|
||||||
layout_cache,
|
layout_cache,
|
||||||
module_timing,
|
module_timing,
|
||||||
|
abilities_store,
|
||||||
} = found_specializations;
|
} = found_specializations;
|
||||||
|
|
||||||
BuildTask::MakeSpecializations {
|
BuildTask::MakeSpecializations {
|
||||||
|
@ -326,6 +401,7 @@ fn start_phase<'a>(
|
||||||
layout_cache,
|
layout_cache,
|
||||||
specializations_we_must_make,
|
specializations_we_must_make,
|
||||||
module_timing,
|
module_timing,
|
||||||
|
abilities_store,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -419,6 +495,7 @@ pub struct TypeCheckedModule<'a> {
|
||||||
pub solved_subs: Solved<Subs>,
|
pub solved_subs: Solved<Subs>,
|
||||||
pub decls: Vec<Declaration>,
|
pub decls: Vec<Declaration>,
|
||||||
pub ident_ids: IdentIds,
|
pub ident_ids: IdentIds,
|
||||||
|
pub abilities_store: AbilitiesStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -429,6 +506,7 @@ struct FoundSpecializationsModule<'a> {
|
||||||
procs_base: ProcsBase<'a>,
|
procs_base: ProcsBase<'a>,
|
||||||
subs: Subs,
|
subs: Subs,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
|
abilities_store: AbilitiesStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -529,6 +607,7 @@ enum Msg<'a> {
|
||||||
problems: Vec<roc_mono::ir::MonoProblem>,
|
problems: Vec<roc_mono::ir::MonoProblem>,
|
||||||
solved_subs: Solved<Subs>,
|
solved_subs: Solved<Subs>,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
|
abilities_store: AbilitiesStore,
|
||||||
},
|
},
|
||||||
MadeSpecializations {
|
MadeSpecializations {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
|
@ -574,6 +653,7 @@ struct PlatformData {
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct State<'a> {
|
struct State<'a> {
|
||||||
pub root_id: ModuleId,
|
pub root_id: ModuleId,
|
||||||
|
pub root_subs: Option<Subs>,
|
||||||
pub platform_data: Option<PlatformData>,
|
pub platform_data: Option<PlatformData>,
|
||||||
pub goal_phase: Phase,
|
pub goal_phase: Phase,
|
||||||
pub exposed_types: ExposedByModule,
|
pub exposed_types: ExposedByModule,
|
||||||
|
@ -598,7 +678,7 @@ struct State<'a> {
|
||||||
|
|
||||||
pub declarations_by_id: MutMap<ModuleId, Vec<Declaration>>,
|
pub declarations_by_id: MutMap<ModuleId, Vec<Declaration>>,
|
||||||
|
|
||||||
pub exposed_symbols_by_module: MutMap<ModuleId, MutSet<Symbol>>,
|
pub exposed_symbols_by_module: MutMap<ModuleId, VecSet<Symbol>>,
|
||||||
|
|
||||||
pub timings: MutMap<ModuleId, ModuleTiming>,
|
pub timings: MutMap<ModuleId, ModuleTiming>,
|
||||||
|
|
||||||
|
@ -633,6 +713,7 @@ impl<'a> State<'a> {
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
root_id,
|
root_id,
|
||||||
|
root_subs: None,
|
||||||
target_info,
|
target_info,
|
||||||
platform_data: None,
|
platform_data: None,
|
||||||
goal_phase,
|
goal_phase,
|
||||||
|
@ -742,8 +823,9 @@ enum BuildTask<'a> {
|
||||||
parsed: ParsedModule<'a>,
|
parsed: ParsedModule<'a>,
|
||||||
module_ids: ModuleIds,
|
module_ids: ModuleIds,
|
||||||
dep_idents: MutMap<ModuleId, IdentIds>,
|
dep_idents: MutMap<ModuleId, IdentIds>,
|
||||||
exposed_symbols: MutSet<Symbol>,
|
exposed_symbols: VecSet<Symbol>,
|
||||||
aliases: MutMap<Symbol, Alias>,
|
aliases: MutMap<Symbol, Alias>,
|
||||||
|
skip_constraint_gen: bool,
|
||||||
},
|
},
|
||||||
Solve {
|
Solve {
|
||||||
module: Module,
|
module: Module,
|
||||||
|
@ -767,6 +849,7 @@ enum BuildTask<'a> {
|
||||||
ident_ids: IdentIds,
|
ident_ids: IdentIds,
|
||||||
decls: Vec<Declaration>,
|
decls: Vec<Declaration>,
|
||||||
exposed_to_host: ExposedToHost,
|
exposed_to_host: ExposedToHost,
|
||||||
|
abilities_store: AbilitiesStore,
|
||||||
},
|
},
|
||||||
MakeSpecializations {
|
MakeSpecializations {
|
||||||
module_id: ModuleId,
|
module_id: ModuleId,
|
||||||
|
@ -776,6 +859,7 @@ enum BuildTask<'a> {
|
||||||
layout_cache: LayoutCache<'a>,
|
layout_cache: LayoutCache<'a>,
|
||||||
specializations_we_must_make: Vec<ExternalSpecializations>,
|
specializations_we_must_make: Vec<ExternalSpecializations>,
|
||||||
module_timing: ModuleTiming,
|
module_timing: ModuleTiming,
|
||||||
|
abilities_store: AbilitiesStore,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1053,7 +1137,7 @@ pub fn load<'a>(
|
||||||
|
|
||||||
/// Load using only a single thread; used when compiling to webassembly
|
/// Load using only a single thread; used when compiling to webassembly
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn load_single_threaded<'a>(
|
pub fn load_single_threaded<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
load_start: LoadStart<'a>,
|
load_start: LoadStart<'a>,
|
||||||
src_dir: &Path,
|
src_dir: &Path,
|
||||||
|
@ -1200,7 +1284,6 @@ fn state_thread_step<'a>(
|
||||||
// This is where most of the main thread's work gets done.
|
// This is where most of the main thread's work gets done.
|
||||||
// Everything up to this point has been setting up the threading
|
// Everything up to this point has been setting up the threading
|
||||||
// system which lets this logic work efficiently.
|
// system which lets this logic work efficiently.
|
||||||
let constrained_ident_ids = state.constrained_ident_ids.clone();
|
|
||||||
let arc_modules = state.arc_modules.clone();
|
let arc_modules = state.arc_modules.clone();
|
||||||
|
|
||||||
let render = state.render;
|
let render = state.render;
|
||||||
|
@ -1226,10 +1309,12 @@ fn state_thread_step<'a>(
|
||||||
.into_inner()
|
.into_inner()
|
||||||
.into_module_ids();
|
.into_module_ids();
|
||||||
|
|
||||||
|
// if parsing failed, this module did not add anything to IdentIds
|
||||||
|
let root_exposed_ident_ids = IdentIds::exposed_builtins(0);
|
||||||
let buf = to_parse_problem_report(
|
let buf = to_parse_problem_report(
|
||||||
problem,
|
problem,
|
||||||
module_ids,
|
module_ids,
|
||||||
constrained_ident_ids,
|
root_exposed_ident_ids,
|
||||||
render,
|
render,
|
||||||
);
|
);
|
||||||
Err(LoadingProblem::FormattedReport(buf))
|
Err(LoadingProblem::FormattedReport(buf))
|
||||||
|
@ -1585,9 +1670,11 @@ fn report_unused_imported_modules<'a>(
|
||||||
};
|
};
|
||||||
|
|
||||||
for (unused, region) in unused_imported_modules.drain() {
|
for (unused, region) in unused_imported_modules.drain() {
|
||||||
|
if !unused.is_builtin() {
|
||||||
existing.push(roc_problem::can::Problem::UnusedImport(unused, region));
|
existing.push(roc_problem::can::Problem::UnusedImport(unused, region));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn update<'a>(
|
fn update<'a>(
|
||||||
mut state: State<'a>,
|
mut state: State<'a>,
|
||||||
|
@ -1651,7 +1738,7 @@ fn update<'a>(
|
||||||
state.platform_path = PlatformPath::RootIsPkgConfig;
|
state.platform_path = PlatformPath::RootIsPkgConfig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Interface => {
|
Builtin { .. } | Interface => {
|
||||||
if header.is_root_module {
|
if header.is_root_module {
|
||||||
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
debug_assert!(matches!(state.platform_path, PlatformPath::NotSpecified));
|
||||||
state.platform_path = PlatformPath::RootIsInterface;
|
state.platform_path = PlatformPath::RootIsInterface;
|
||||||
|
@ -1671,8 +1758,7 @@ fn update<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
// This was a dependency. Write it down and keep processing messages.
|
// This was a dependency. Write it down and keep processing messages.
|
||||||
let mut exposed_symbols: MutSet<Symbol> =
|
let mut exposed_symbols: VecSet<Symbol> = VecSet::with_capacity(header.exposes.len());
|
||||||
HashSet::with_capacity_and_hasher(header.exposes.len(), default_hasher());
|
|
||||||
|
|
||||||
// TODO can we avoid this loop by storing them as a Set in Header to begin with?
|
// TODO can we avoid this loop by storing them as a Set in Header to begin with?
|
||||||
for symbol in header.exposes.iter() {
|
for symbol in header.exposes.iter() {
|
||||||
|
@ -1687,6 +1773,132 @@ fn update<'a>(
|
||||||
.exposed_symbols_by_module
|
.exposed_symbols_by_module
|
||||||
.insert(home, exposed_symbols);
|
.insert(home, exposed_symbols);
|
||||||
|
|
||||||
|
// add the prelude
|
||||||
|
let mut header = header;
|
||||||
|
|
||||||
|
if ![ModuleId::RESULT, ModuleId::BOOL].contains(&header.module_id) {
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::RESULT));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::RESULT, Region::zero());
|
||||||
|
|
||||||
|
header.exposed_imports.insert(
|
||||||
|
Ident::from("Result"),
|
||||||
|
(Symbol::RESULT_RESULT, Region::zero()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ![ModuleId::NUM, ModuleId::BOOL, ModuleId::RESULT].contains(&header.module_id) {
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::NUM));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::NUM, Region::zero());
|
||||||
|
|
||||||
|
let prelude_types = [
|
||||||
|
(Ident::from("Num"), Symbol::NUM_NUM),
|
||||||
|
(Ident::from("Int"), Symbol::NUM_INT),
|
||||||
|
(Ident::from("Float"), Symbol::NUM_FLOAT),
|
||||||
|
(Ident::from("Integer"), Symbol::NUM_INTEGER),
|
||||||
|
(Ident::from("FloatingPoint"), Symbol::NUM_FLOATINGPOINT),
|
||||||
|
(Ident::from("Binary32"), Symbol::NUM_BINARY32),
|
||||||
|
(Ident::from("Binary64"), Symbol::NUM_BINARY64),
|
||||||
|
(Ident::from("Signed128"), Symbol::NUM_SIGNED128),
|
||||||
|
(Ident::from("Signed64"), Symbol::NUM_SIGNED64),
|
||||||
|
(Ident::from("Signed32"), Symbol::NUM_SIGNED32),
|
||||||
|
(Ident::from("Signed16"), Symbol::NUM_SIGNED16),
|
||||||
|
(Ident::from("Signed8"), Symbol::NUM_SIGNED8),
|
||||||
|
(Ident::from("Unsigned128"), Symbol::NUM_UNSIGNED128),
|
||||||
|
(Ident::from("Unsigned64"), Symbol::NUM_UNSIGNED64),
|
||||||
|
(Ident::from("Unsigned32"), Symbol::NUM_UNSIGNED32),
|
||||||
|
(Ident::from("Unsigned16"), Symbol::NUM_UNSIGNED16),
|
||||||
|
(Ident::from("Unsigned8"), Symbol::NUM_UNSIGNED8),
|
||||||
|
(Ident::from("Natural"), Symbol::NUM_NATURAL),
|
||||||
|
(Ident::from("Decimal"), Symbol::NUM_DECIMAL),
|
||||||
|
(Ident::from("Nat"), Symbol::NUM_NAT),
|
||||||
|
(Ident::from("I8"), Symbol::NUM_I8),
|
||||||
|
(Ident::from("I16"), Symbol::NUM_I16),
|
||||||
|
(Ident::from("I32"), Symbol::NUM_I32),
|
||||||
|
(Ident::from("I64"), Symbol::NUM_I64),
|
||||||
|
(Ident::from("I128"), Symbol::NUM_I128),
|
||||||
|
(Ident::from("U8"), Symbol::NUM_U8),
|
||||||
|
(Ident::from("U16"), Symbol::NUM_U16),
|
||||||
|
(Ident::from("U32"), Symbol::NUM_U32),
|
||||||
|
(Ident::from("U64"), Symbol::NUM_U64),
|
||||||
|
(Ident::from("U128"), Symbol::NUM_U128),
|
||||||
|
(Ident::from("F32"), Symbol::NUM_F32),
|
||||||
|
(Ident::from("F64"), Symbol::NUM_F64),
|
||||||
|
(Ident::from("Dec"), Symbol::NUM_DEC),
|
||||||
|
];
|
||||||
|
|
||||||
|
for (ident, symbol) in prelude_types {
|
||||||
|
header
|
||||||
|
.exposed_imports
|
||||||
|
.insert(ident, (symbol, Region::zero()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if header.module_id != ModuleId::BOOL {
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::BOOL));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::BOOL, Region::zero());
|
||||||
|
|
||||||
|
header
|
||||||
|
.exposed_imports
|
||||||
|
.insert(Ident::from("Bool"), (Symbol::BOOL_BOOL, Region::zero()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if !header.module_id.is_builtin() {
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::BOX));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::BOX, Region::zero());
|
||||||
|
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::STR));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::STR, Region::zero());
|
||||||
|
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::DICT));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::DICT, Region::zero());
|
||||||
|
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::SET));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::SET, Region::zero());
|
||||||
|
|
||||||
|
header
|
||||||
|
.package_qualified_imported_modules
|
||||||
|
.insert(PackageQualified::Unqualified(ModuleId::LIST));
|
||||||
|
|
||||||
|
header
|
||||||
|
.imported_modules
|
||||||
|
.insert(ModuleId::LIST, Region::zero());
|
||||||
|
}
|
||||||
|
|
||||||
state
|
state
|
||||||
.module_cache
|
.module_cache
|
||||||
.imports
|
.imports
|
||||||
|
@ -1880,6 +2092,7 @@ fn update<'a>(
|
||||||
solved_subs,
|
solved_subs,
|
||||||
decls,
|
decls,
|
||||||
ident_ids,
|
ident_ids,
|
||||||
|
abilities_store,
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
|
@ -1904,6 +2117,7 @@ fn update<'a>(
|
||||||
layout_cache,
|
layout_cache,
|
||||||
problems,
|
problems,
|
||||||
module_timing,
|
module_timing,
|
||||||
|
abilities_store,
|
||||||
} => {
|
} => {
|
||||||
log!("found specializations for {:?}", module_id);
|
log!("found specializations for {:?}", module_id);
|
||||||
|
|
||||||
|
@ -1925,6 +2139,7 @@ fn update<'a>(
|
||||||
procs_base,
|
procs_base,
|
||||||
subs,
|
subs,
|
||||||
module_timing,
|
module_timing,
|
||||||
|
abilities_store,
|
||||||
};
|
};
|
||||||
|
|
||||||
state
|
state
|
||||||
|
@ -2013,6 +2228,14 @@ fn update<'a>(
|
||||||
existing.push(requested);
|
existing.push(requested);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use the subs of the root module;
|
||||||
|
// this is used in the repl to find the type of `main`
|
||||||
|
let subs = if module_id == state.root_id {
|
||||||
|
subs
|
||||||
|
} else {
|
||||||
|
state.root_subs.clone().unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
msg_tx
|
msg_tx
|
||||||
.send(Msg::FinishedAllSpecialization {
|
.send(Msg::FinishedAllSpecialization {
|
||||||
subs,
|
subs,
|
||||||
|
@ -2025,6 +2248,12 @@ fn update<'a>(
|
||||||
// the originally requested module, we're all done!
|
// the originally requested module, we're all done!
|
||||||
return Ok(state);
|
return Ok(state);
|
||||||
} else {
|
} else {
|
||||||
|
// record the subs of the root module;
|
||||||
|
// this is used in the repl to find the type of `main`
|
||||||
|
if module_id == state.root_id {
|
||||||
|
state.root_subs = Some(subs);
|
||||||
|
}
|
||||||
|
|
||||||
state.constrained_ident_ids.insert(module_id, ident_ids);
|
state.constrained_ident_ids.insert(module_id, ident_ids);
|
||||||
|
|
||||||
for (module_id, requested) in external_specializations_requested {
|
for (module_id, requested) in external_specializations_requested {
|
||||||
|
@ -2253,6 +2482,12 @@ fn load_pkg_config<'a>(
|
||||||
header
|
header
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
Ok((ast::Module::Hosted { header }, _parse_state)) => {
|
||||||
|
Err(LoadingProblem::UnexpectedHeader(format!(
|
||||||
|
"expected platform/package module, got Hosted module with header\n{:?}",
|
||||||
|
header
|
||||||
|
)))
|
||||||
|
}
|
||||||
Ok((ast::Module::App { header }, _parse_state)) => {
|
Ok((ast::Module::App { header }, _parse_state)) => {
|
||||||
Err(LoadingProblem::UnexpectedHeader(format!(
|
Err(LoadingProblem::UnexpectedHeader(format!(
|
||||||
"expected platform/package module, got App with header\n{:?}",
|
"expected platform/package module, got App with header\n{:?}",
|
||||||
|
@ -2276,12 +2511,6 @@ fn load_pkg_config<'a>(
|
||||||
|
|
||||||
Ok(pkg_config_module_msg)
|
Ok(pkg_config_module_msg)
|
||||||
}
|
}
|
||||||
Ok((ast::Module::Hosted { header }, _parse_state)) => {
|
|
||||||
Err(LoadingProblem::UnexpectedHeader(format!(
|
|
||||||
"expected platform/package module, got Hosted module with header\n{:?}",
|
|
||||||
header
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
Err(fail) => Err(LoadingProblem::ParsingFailed(
|
Err(fail) => Err(LoadingProblem::ParsingFailed(
|
||||||
fail.map_problem(SyntaxError::Header)
|
fail.map_problem(SyntaxError::Header)
|
||||||
.into_file_error(filename),
|
.into_file_error(filename),
|
||||||
|
@ -2296,6 +2525,68 @@ fn load_pkg_config<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_builtin_module_help<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
filename: &str,
|
||||||
|
src_bytes: &'a str,
|
||||||
|
) -> (HeaderInfo<'a>, roc_parse::state::State<'a>) {
|
||||||
|
let is_root_module = false;
|
||||||
|
let opt_shorthand = None;
|
||||||
|
|
||||||
|
let filename = PathBuf::from(filename);
|
||||||
|
|
||||||
|
let parse_state = roc_parse::state::State::new(src_bytes.as_bytes());
|
||||||
|
let parsed = roc_parse::module::parse_header(arena, parse_state.clone());
|
||||||
|
|
||||||
|
match parsed {
|
||||||
|
Ok((ast::Module::Interface { header }, parse_state)) => {
|
||||||
|
let info = HeaderInfo {
|
||||||
|
loc_name: Loc {
|
||||||
|
region: header.name.region,
|
||||||
|
value: ModuleNameEnum::Interface(header.name.value),
|
||||||
|
},
|
||||||
|
filename,
|
||||||
|
is_root_module,
|
||||||
|
opt_shorthand,
|
||||||
|
packages: &[],
|
||||||
|
exposes: unspace(arena, header.exposes.items),
|
||||||
|
imports: unspace(arena, header.imports.items),
|
||||||
|
extra: HeaderFor::Builtin {
|
||||||
|
generates_with: &[],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
(info, parse_state)
|
||||||
|
}
|
||||||
|
Ok(_) => panic!("invalid header format for builtin module"),
|
||||||
|
Err(e) => panic!(
|
||||||
|
"Hit a parse error in the header of {:?}:\n{:?}",
|
||||||
|
filename, e
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_builtin_module<'a>(
|
||||||
|
arena: &'a Bump,
|
||||||
|
module_ids: Arc<Mutex<PackageModuleIds<'a>>>,
|
||||||
|
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||||
|
module_timing: ModuleTiming,
|
||||||
|
module_id: ModuleId,
|
||||||
|
module_name: &str,
|
||||||
|
) -> (ModuleId, Msg<'a>) {
|
||||||
|
let src_bytes = module_source(module_id);
|
||||||
|
|
||||||
|
let (info, parse_state) = load_builtin_module_help(arena, module_name, src_bytes);
|
||||||
|
|
||||||
|
send_header(
|
||||||
|
info,
|
||||||
|
parse_state,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/// Load a module by its module name, rather than by its filename
|
/// Load a module by its module name, rather than by its filename
|
||||||
fn load_module<'a>(
|
fn load_module<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
|
@ -2306,6 +2597,119 @@ fn load_module<'a>(
|
||||||
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
ident_ids_by_module: Arc<Mutex<MutMap<ModuleId, IdentIds>>>,
|
||||||
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
|
) -> Result<(ModuleId, Msg<'a>), LoadingProblem<'a>> {
|
||||||
let module_start_time = SystemTime::now();
|
let module_start_time = SystemTime::now();
|
||||||
|
|
||||||
|
let parse_start = SystemTime::now();
|
||||||
|
let parse_header_duration = parse_start.elapsed().unwrap();
|
||||||
|
|
||||||
|
// Insert the first entries for this module's timings
|
||||||
|
let mut module_timing = ModuleTiming::new(module_start_time);
|
||||||
|
|
||||||
|
module_timing.read_roc_file = Default::default();
|
||||||
|
module_timing.parse_header = parse_header_duration;
|
||||||
|
match module_name.as_inner().as_str() {
|
||||||
|
"Result" => {
|
||||||
|
return Ok(load_builtin_module(
|
||||||
|
arena,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
ModuleId::RESULT,
|
||||||
|
"Result.roc",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"List" => {
|
||||||
|
return Ok(load_builtin_module(
|
||||||
|
arena,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
ModuleId::LIST,
|
||||||
|
"List.roc",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"Str" => {
|
||||||
|
return Ok(load_builtin_module(
|
||||||
|
arena,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
ModuleId::STR,
|
||||||
|
"Str.roc",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"Dict" => {
|
||||||
|
return Ok(load_builtin_module(
|
||||||
|
arena,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
ModuleId::DICT,
|
||||||
|
"Dict.roc",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"Set" => {
|
||||||
|
return Ok(load_builtin_module(
|
||||||
|
arena,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
ModuleId::SET,
|
||||||
|
"Set.roc",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"Num" => {
|
||||||
|
return Ok(load_builtin_module(
|
||||||
|
arena,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
ModuleId::NUM,
|
||||||
|
"Num.roc",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"Bool" => {
|
||||||
|
return Ok(load_builtin_module(
|
||||||
|
arena,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
ModuleId::BOOL,
|
||||||
|
"Bool.roc",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
"Box" => {
|
||||||
|
return Ok(load_builtin_module(
|
||||||
|
arena,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_timing,
|
||||||
|
ModuleId::BOX,
|
||||||
|
"Box.roc",
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
// fall through
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let (filename, opt_shorthand) = module_name_to_path(src_dir, module_name, arc_shorthands);
|
||||||
|
|
||||||
|
load_filename(
|
||||||
|
arena,
|
||||||
|
filename,
|
||||||
|
false,
|
||||||
|
opt_shorthand,
|
||||||
|
module_ids,
|
||||||
|
ident_ids_by_module,
|
||||||
|
module_start_time,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn module_name_to_path<'a>(
|
||||||
|
src_dir: &Path,
|
||||||
|
module_name: PQModuleName<'a>,
|
||||||
|
arc_shorthands: Arc<Mutex<MutMap<&'a str, PackageName<'a>>>>,
|
||||||
|
) -> (PathBuf, Option<&'a str>) {
|
||||||
let mut filename = PathBuf::new();
|
let mut filename = PathBuf::new();
|
||||||
|
|
||||||
filename.push(src_dir);
|
filename.push(src_dir);
|
||||||
|
@ -2340,15 +2744,7 @@ fn load_module<'a>(
|
||||||
// End with .roc
|
// End with .roc
|
||||||
filename.set_extension(ROC_FILE_EXTENSION);
|
filename.set_extension(ROC_FILE_EXTENSION);
|
||||||
|
|
||||||
load_filename(
|
(filename, opt_shorthand)
|
||||||
arena,
|
|
||||||
filename,
|
|
||||||
false,
|
|
||||||
opt_shorthand,
|
|
||||||
module_ids,
|
|
||||||
ident_ids_by_module,
|
|
||||||
module_start_time,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Find a task according to the following algorithm:
|
/// Find a task according to the following algorithm:
|
||||||
|
@ -2807,6 +3203,18 @@ fn send_header<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make sure when we run the bulitin modules in /compiler/builtins/roc that we
|
||||||
|
// mark these modules as Builtin. Otherwise the builtin functions are not instantiated
|
||||||
|
// and we just have a bunch of definitions with runtime errors in their bodies
|
||||||
|
let extra = {
|
||||||
|
match extra {
|
||||||
|
HeaderFor::Interface if home.is_builtin() => HeaderFor::Builtin {
|
||||||
|
generates_with: &[],
|
||||||
|
},
|
||||||
|
_ => extra,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
home,
|
home,
|
||||||
Msg::Header(ModuleHeader {
|
Msg::Header(ModuleHeader {
|
||||||
|
@ -3218,6 +3626,7 @@ fn run_solve_solve(
|
||||||
solve_aliases.insert(*name, alias.clone());
|
solve_aliases.insert(*name, alias.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let (solved_subs, exposed_vars_by_symbol, problems, abilities_store) = {
|
||||||
let (solved_subs, solved_env, problems, abilities_store) = roc_solve::module::run_solve(
|
let (solved_subs, solved_env, problems, abilities_store) = roc_solve::module::run_solve(
|
||||||
&constraints,
|
&constraints,
|
||||||
actual_constraint,
|
actual_constraint,
|
||||||
|
@ -3227,22 +3636,19 @@ fn run_solve_solve(
|
||||||
abilities_store,
|
abilities_store,
|
||||||
);
|
);
|
||||||
|
|
||||||
let solved_subs = if true {
|
|
||||||
solved_subs
|
|
||||||
} else {
|
|
||||||
panic!();
|
|
||||||
// let mut serialized = Vec::new();
|
|
||||||
// solved_subs.inner().serialize(&mut serialized).unwrap();
|
|
||||||
// let subs = Subs::deserialize(&serialized);
|
|
||||||
//
|
|
||||||
// Solved(subs)
|
|
||||||
};
|
|
||||||
|
|
||||||
let exposed_vars_by_symbol: Vec<_> = solved_env
|
let exposed_vars_by_symbol: Vec<_> = solved_env
|
||||||
.vars_by_symbol()
|
.vars_by_symbol()
|
||||||
.filter(|(k, _)| exposed_symbols.contains(k))
|
.filter(|(k, _)| exposed_symbols.contains(k))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
(
|
||||||
|
solved_subs,
|
||||||
|
exposed_vars_by_symbol,
|
||||||
|
problems,
|
||||||
|
abilities_store,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
(
|
(
|
||||||
solved_subs,
|
solved_subs,
|
||||||
exposed_vars_by_symbol,
|
exposed_vars_by_symbol,
|
||||||
|
@ -3275,24 +3681,23 @@ fn run_solve<'a>(
|
||||||
let (solved_subs, exposed_vars_by_symbol, problems, abilities_store) = {
|
let (solved_subs, exposed_vars_by_symbol, problems, abilities_store) = {
|
||||||
if module_id.is_builtin() {
|
if module_id.is_builtin() {
|
||||||
match cached_subs.lock().remove(&module_id) {
|
match cached_subs.lock().remove(&module_id) {
|
||||||
None => {
|
None => run_solve_solve(
|
||||||
// this should never happen
|
|
||||||
run_solve_solve(
|
|
||||||
imported_builtins,
|
imported_builtins,
|
||||||
exposed_for_module,
|
exposed_for_module,
|
||||||
constraints,
|
constraints,
|
||||||
constraint,
|
constraint,
|
||||||
var_store,
|
var_store,
|
||||||
module,
|
module,
|
||||||
)
|
),
|
||||||
}
|
Some((subs, exposed_vars_by_symbol)) => {
|
||||||
Some((subs, exposed_vars_by_symbol)) => (
|
(
|
||||||
Solved(subs),
|
Solved(subs),
|
||||||
exposed_vars_by_symbol.to_vec(),
|
exposed_vars_by_symbol.to_vec(),
|
||||||
vec![],
|
vec![],
|
||||||
// TODO(abilities) replace when we have abilities for builtins
|
// TODO(abilities) replace when we have abilities for builtins
|
||||||
AbilitiesStore::default(),
|
AbilitiesStore::default(),
|
||||||
),
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
run_solve_solve(
|
run_solve_solve(
|
||||||
|
@ -3387,9 +3792,10 @@ fn canonicalize_and_constrain<'a>(
|
||||||
arena: &'a Bump,
|
arena: &'a Bump,
|
||||||
module_ids: &ModuleIds,
|
module_ids: &ModuleIds,
|
||||||
dep_idents: MutMap<ModuleId, IdentIds>,
|
dep_idents: MutMap<ModuleId, IdentIds>,
|
||||||
exposed_symbols: MutSet<Symbol>,
|
exposed_symbols: VecSet<Symbol>,
|
||||||
aliases: MutMap<Symbol, Alias>,
|
aliases: MutMap<Symbol, Alias>,
|
||||||
parsed: ParsedModule<'a>,
|
parsed: ParsedModule<'a>,
|
||||||
|
skip_constraint_gen: bool,
|
||||||
) -> Result<Msg<'a>, LoadingProblem<'a>> {
|
) -> Result<Msg<'a>, LoadingProblem<'a>> {
|
||||||
let canonicalize_start = SystemTime::now();
|
let canonicalize_start = SystemTime::now();
|
||||||
|
|
||||||
|
@ -3459,12 +3865,16 @@ fn canonicalize_and_constrain<'a>(
|
||||||
|
|
||||||
let mut constraints = Constraints::new();
|
let mut constraints = Constraints::new();
|
||||||
|
|
||||||
let constraint = constrain_module(
|
let constraint = if skip_constraint_gen {
|
||||||
|
roc_can::constraint::Constraint::True
|
||||||
|
} else {
|
||||||
|
constrain_module(
|
||||||
&mut constraints,
|
&mut constraints,
|
||||||
&module_output.scope.abilities_store,
|
&module_output.scope.abilities_store,
|
||||||
&module_output.declarations,
|
&module_output.declarations,
|
||||||
module_id,
|
module_id,
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
let after = roc_types::types::get_type_clone_count();
|
let after = roc_types::types::get_type_clone_count();
|
||||||
|
|
||||||
|
@ -3642,6 +4052,7 @@ fn make_specializations<'a>(
|
||||||
specializations_we_must_make: Vec<ExternalSpecializations>,
|
specializations_we_must_make: Vec<ExternalSpecializations>,
|
||||||
mut module_timing: ModuleTiming,
|
mut module_timing: ModuleTiming,
|
||||||
target_info: TargetInfo,
|
target_info: TargetInfo,
|
||||||
|
abilities_store: AbilitiesStore,
|
||||||
) -> Msg<'a> {
|
) -> Msg<'a> {
|
||||||
let make_specializations_start = SystemTime::now();
|
let make_specializations_start = SystemTime::now();
|
||||||
let mut mono_problems = Vec::new();
|
let mut mono_problems = Vec::new();
|
||||||
|
@ -3657,6 +4068,7 @@ fn make_specializations<'a>(
|
||||||
update_mode_ids: &mut update_mode_ids,
|
update_mode_ids: &mut update_mode_ids,
|
||||||
// call_specialization_counter=0 is reserved
|
// call_specialization_counter=0 is reserved
|
||||||
call_specialization_counter: 1,
|
call_specialization_counter: 1,
|
||||||
|
abilities_store: &abilities_store,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut procs = Procs::new_in(arena);
|
let mut procs = Procs::new_in(arena);
|
||||||
|
@ -3727,6 +4139,7 @@ fn build_pending_specializations<'a>(
|
||||||
target_info: TargetInfo,
|
target_info: TargetInfo,
|
||||||
// TODO remove
|
// TODO remove
|
||||||
exposed_to_host: ExposedToHost,
|
exposed_to_host: ExposedToHost,
|
||||||
|
abilities_store: AbilitiesStore,
|
||||||
) -> Msg<'a> {
|
) -> Msg<'a> {
|
||||||
let find_specializations_start = SystemTime::now();
|
let find_specializations_start = SystemTime::now();
|
||||||
|
|
||||||
|
@ -3753,6 +4166,7 @@ fn build_pending_specializations<'a>(
|
||||||
update_mode_ids: &mut update_mode_ids,
|
update_mode_ids: &mut update_mode_ids,
|
||||||
// call_specialization_counter=0 is reserved
|
// call_specialization_counter=0 is reserved
|
||||||
call_specialization_counter: 1,
|
call_specialization_counter: 1,
|
||||||
|
abilities_store: &abilities_store,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add modules' decls to Procs
|
// Add modules' decls to Procs
|
||||||
|
@ -3806,6 +4220,7 @@ fn build_pending_specializations<'a>(
|
||||||
procs_base,
|
procs_base,
|
||||||
problems,
|
problems,
|
||||||
module_timing,
|
module_timing,
|
||||||
|
abilities_store,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3823,7 +4238,11 @@ fn add_def_to_module<'a>(
|
||||||
use roc_can::pattern::Pattern::*;
|
use roc_can::pattern::Pattern::*;
|
||||||
|
|
||||||
match def.loc_pattern.value {
|
match def.loc_pattern.value {
|
||||||
Identifier(symbol) => {
|
Identifier(symbol)
|
||||||
|
| AbilityMemberSpecialization {
|
||||||
|
ident: symbol,
|
||||||
|
specializes: _,
|
||||||
|
} => {
|
||||||
let is_host_exposed = exposed_to_host.contains_key(&symbol);
|
let is_host_exposed = exposed_to_host.contains_key(&symbol);
|
||||||
|
|
||||||
match def.loc_expr.value {
|
match def.loc_expr.value {
|
||||||
|
@ -3833,10 +4252,15 @@ fn add_def_to_module<'a>(
|
||||||
arguments: loc_args,
|
arguments: loc_args,
|
||||||
loc_body,
|
loc_body,
|
||||||
captured_symbols,
|
captured_symbols,
|
||||||
|
name,
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
// this is a top-level definition, it should not capture anything
|
// this is a top-level definition, it should not capture anything
|
||||||
debug_assert!(captured_symbols.is_empty());
|
debug_assert!(
|
||||||
|
captured_symbols.is_empty(),
|
||||||
|
"{:?}",
|
||||||
|
(symbol, name, symbol.module_id(), &captured_symbols)
|
||||||
|
);
|
||||||
|
|
||||||
// If this is an exposed symbol, we need to
|
// If this is an exposed symbol, we need to
|
||||||
// register it as such. Otherwise, since it
|
// register it as such. Otherwise, since it
|
||||||
|
@ -3984,6 +4408,7 @@ fn run_task<'a>(
|
||||||
dep_idents,
|
dep_idents,
|
||||||
exposed_symbols,
|
exposed_symbols,
|
||||||
aliases,
|
aliases,
|
||||||
|
skip_constraint_gen,
|
||||||
} => canonicalize_and_constrain(
|
} => canonicalize_and_constrain(
|
||||||
arena,
|
arena,
|
||||||
&module_ids,
|
&module_ids,
|
||||||
|
@ -3991,6 +4416,7 @@ fn run_task<'a>(
|
||||||
exposed_symbols,
|
exposed_symbols,
|
||||||
aliases,
|
aliases,
|
||||||
parsed,
|
parsed,
|
||||||
|
skip_constraint_gen,
|
||||||
),
|
),
|
||||||
Solve {
|
Solve {
|
||||||
module,
|
module,
|
||||||
|
@ -4026,6 +4452,7 @@ fn run_task<'a>(
|
||||||
solved_subs,
|
solved_subs,
|
||||||
imported_module_thunks,
|
imported_module_thunks,
|
||||||
exposed_to_host,
|
exposed_to_host,
|
||||||
|
abilities_store,
|
||||||
} => Ok(build_pending_specializations(
|
} => Ok(build_pending_specializations(
|
||||||
arena,
|
arena,
|
||||||
solved_subs,
|
solved_subs,
|
||||||
|
@ -4037,6 +4464,7 @@ fn run_task<'a>(
|
||||||
layout_cache,
|
layout_cache,
|
||||||
target_info,
|
target_info,
|
||||||
exposed_to_host,
|
exposed_to_host,
|
||||||
|
abilities_store,
|
||||||
)),
|
)),
|
||||||
MakeSpecializations {
|
MakeSpecializations {
|
||||||
module_id,
|
module_id,
|
||||||
|
@ -4046,6 +4474,7 @@ fn run_task<'a>(
|
||||||
layout_cache,
|
layout_cache,
|
||||||
specializations_we_must_make,
|
specializations_we_must_make,
|
||||||
module_timing,
|
module_timing,
|
||||||
|
abilities_store,
|
||||||
} => Ok(make_specializations(
|
} => Ok(make_specializations(
|
||||||
arena,
|
arena,
|
||||||
module_id,
|
module_id,
|
||||||
|
@ -4056,6 +4485,7 @@ fn run_task<'a>(
|
||||||
specializations_we_must_make,
|
specializations_we_must_make,
|
||||||
module_timing,
|
module_timing,
|
||||||
target_info,
|
target_info,
|
||||||
|
abilities_store,
|
||||||
)),
|
)),
|
||||||
}?;
|
}?;
|
||||||
|
|
||||||
|
|
|
@ -815,4 +815,65 @@ mod test_load {
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn issue_2863_module_type_does_not_exist() {
|
||||||
|
let modules = vec![
|
||||||
|
(
|
||||||
|
"platform/Package-Config.roc",
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
platform "testplatform"
|
||||||
|
requires {} { main : Str }
|
||||||
|
exposes []
|
||||||
|
packages {}
|
||||||
|
imports []
|
||||||
|
provides [ mainForHost ]
|
||||||
|
|
||||||
|
mainForHost : Str
|
||||||
|
mainForHost = main
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Main",
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test"
|
||||||
|
packages { pf: "platform" }
|
||||||
|
provides [ main ] to pf
|
||||||
|
|
||||||
|
main : DoesNotExist
|
||||||
|
main = 1
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
match multiple_modules(modules) {
|
||||||
|
Err(report) => {
|
||||||
|
assert_eq!(
|
||||||
|
report,
|
||||||
|
indoc!(
|
||||||
|
"
|
||||||
|
── UNRECOGNIZED NAME ───────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
I cannot find a `DoesNotExist` value
|
||||||
|
|
||||||
|
5│ main : DoesNotExist
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Did you mean one of these?
|
||||||
|
|
||||||
|
Dict
|
||||||
|
Result
|
||||||
|
List
|
||||||
|
Nat
|
||||||
|
"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Ok(_) => unreachable!("we expect failure here"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,6 +90,7 @@ impl ModuleName {
|
||||||
pub const DICT: &'static str = "Dict";
|
pub const DICT: &'static str = "Dict";
|
||||||
pub const SET: &'static str = "Set";
|
pub const SET: &'static str = "Set";
|
||||||
pub const RESULT: &'static str = "Result";
|
pub const RESULT: &'static str = "Result";
|
||||||
|
pub const BOX: &'static str = "Box";
|
||||||
|
|
||||||
pub fn as_str(&self) -> &str {
|
pub fn as_str(&self) -> &str {
|
||||||
self.0.as_str()
|
self.0.as_str()
|
||||||
|
|
|
@ -66,6 +66,7 @@ pub enum LowLevel {
|
||||||
DictDifference,
|
DictDifference,
|
||||||
DictWalk,
|
DictWalk,
|
||||||
SetFromList,
|
SetFromList,
|
||||||
|
SetToDict,
|
||||||
NumAdd,
|
NumAdd,
|
||||||
NumAddWrap,
|
NumAddWrap,
|
||||||
NumAddChecked,
|
NumAddChecked,
|
||||||
|
|
|
@ -906,23 +906,23 @@ define_builtins! {
|
||||||
30 DEV_TMP5: "#dev_tmp5"
|
30 DEV_TMP5: "#dev_tmp5"
|
||||||
}
|
}
|
||||||
1 NUM: "Num" => {
|
1 NUM: "Num" => {
|
||||||
0 NUM_NUM: "Num" imported // the Num.Num type alias
|
0 NUM_NUM: "Num" // the Num.Num type alias
|
||||||
1 NUM_AT_NUM: "@Num" // the Num.@Num private tag
|
1 NUM_AT_NUM: "@Num" // the Num.@Num private tag
|
||||||
2 NUM_I128: "I128" imported // the Num.I128 type alias
|
2 NUM_I128: "I128" // the Num.I128 type alias
|
||||||
3 NUM_U128: "U128" imported // the Num.U128 type alias
|
3 NUM_U128: "U128" // the Num.U128 type alias
|
||||||
4 NUM_I64: "I64" imported // the Num.I64 type alias
|
4 NUM_I64: "I64" // the Num.I64 type alias
|
||||||
5 NUM_U64: "U64" imported // the Num.U64 type alias
|
5 NUM_U64: "U64" // the Num.U64 type alias
|
||||||
6 NUM_I32: "I32" imported // the Num.I32 type alias
|
6 NUM_I32: "I32" // the Num.I32 type alias
|
||||||
7 NUM_U32: "U32" imported // the Num.U32 type alias
|
7 NUM_U32: "U32" // the Num.U32 type alias
|
||||||
8 NUM_I16: "I16" imported // the Num.I16 type alias
|
8 NUM_I16: "I16" // the Num.I16 type alias
|
||||||
9 NUM_U16: "U16" imported // the Num.U16 type alias
|
9 NUM_U16: "U16" // the Num.U16 type alias
|
||||||
10 NUM_I8: "I8" imported // the Num.I8 type alias
|
10 NUM_I8: "I8" // the Num.I8 type alias
|
||||||
11 NUM_U8: "U8" imported // the Num.U8 type alias
|
11 NUM_U8: "U8" // the Num.U8 type alias
|
||||||
12 NUM_INTEGER: "Integer" imported // Int : Num Integer
|
12 NUM_INTEGER: "Integer" // Int : Num Integer
|
||||||
13 NUM_AT_INTEGER: "@Integer" // the Int.@Integer private tag
|
13 NUM_AT_INTEGER: "@Integer" // the Int.@Integer private tag
|
||||||
14 NUM_F64: "F64" imported // the Num.F64 type alias
|
14 NUM_F64: "F64" // the Num.F64 type alias
|
||||||
15 NUM_F32: "F32" imported // the Num.F32 type alias
|
15 NUM_F32: "F32" // the Num.F32 type alias
|
||||||
16 NUM_FLOATINGPOINT: "FloatingPoint" imported // Float : Num FloatingPoint
|
16 NUM_FLOATINGPOINT: "FloatingPoint" // Float : Num FloatingPoint
|
||||||
17 NUM_AT_FLOATINGPOINT: "@FloatingPoint" // the Float.@FloatingPoint private tag
|
17 NUM_AT_FLOATINGPOINT: "@FloatingPoint" // the Float.@FloatingPoint private tag
|
||||||
18 NUM_MAX_FLOAT: "maxFloat"
|
18 NUM_MAX_FLOAT: "maxFloat"
|
||||||
19 NUM_MIN_FLOAT: "minFloat"
|
19 NUM_MIN_FLOAT: "minFloat"
|
||||||
|
@ -967,29 +967,29 @@ define_builtins! {
|
||||||
62 NUM_ACOS: "acos"
|
62 NUM_ACOS: "acos"
|
||||||
63 NUM_ASIN: "asin"
|
63 NUM_ASIN: "asin"
|
||||||
64 NUM_AT_SIGNED128: "@Signed128"
|
64 NUM_AT_SIGNED128: "@Signed128"
|
||||||
65 NUM_SIGNED128: "Signed128" imported
|
65 NUM_SIGNED128: "Signed128"
|
||||||
66 NUM_AT_SIGNED64: "@Signed64"
|
66 NUM_AT_SIGNED64: "@Signed64"
|
||||||
67 NUM_SIGNED64: "Signed64" imported
|
67 NUM_SIGNED64: "Signed64"
|
||||||
68 NUM_AT_SIGNED32: "@Signed32"
|
68 NUM_AT_SIGNED32: "@Signed32"
|
||||||
69 NUM_SIGNED32: "Signed32" imported
|
69 NUM_SIGNED32: "Signed32"
|
||||||
70 NUM_AT_SIGNED16: "@Signed16"
|
70 NUM_AT_SIGNED16: "@Signed16"
|
||||||
71 NUM_SIGNED16: "Signed16" imported
|
71 NUM_SIGNED16: "Signed16"
|
||||||
72 NUM_AT_SIGNED8: "@Signed8"
|
72 NUM_AT_SIGNED8: "@Signed8"
|
||||||
73 NUM_SIGNED8: "Signed8" imported
|
73 NUM_SIGNED8: "Signed8"
|
||||||
74 NUM_AT_UNSIGNED128: "@Unsigned128"
|
74 NUM_AT_UNSIGNED128: "@Unsigned128"
|
||||||
75 NUM_UNSIGNED128: "Unsigned128" imported
|
75 NUM_UNSIGNED128: "Unsigned128"
|
||||||
76 NUM_AT_UNSIGNED64: "@Unsigned64"
|
76 NUM_AT_UNSIGNED64: "@Unsigned64"
|
||||||
77 NUM_UNSIGNED64: "Unsigned64" imported
|
77 NUM_UNSIGNED64: "Unsigned64"
|
||||||
78 NUM_AT_UNSIGNED32: "@Unsigned32"
|
78 NUM_AT_UNSIGNED32: "@Unsigned32"
|
||||||
79 NUM_UNSIGNED32: "Unsigned32" imported
|
79 NUM_UNSIGNED32: "Unsigned32"
|
||||||
80 NUM_AT_UNSIGNED16: "@Unsigned16"
|
80 NUM_AT_UNSIGNED16: "@Unsigned16"
|
||||||
81 NUM_UNSIGNED16: "Unsigned16" imported
|
81 NUM_UNSIGNED16: "Unsigned16"
|
||||||
82 NUM_AT_UNSIGNED8: "@Unsigned8"
|
82 NUM_AT_UNSIGNED8: "@Unsigned8"
|
||||||
83 NUM_UNSIGNED8: "Unsigned8" imported
|
83 NUM_UNSIGNED8: "Unsigned8"
|
||||||
84 NUM_AT_BINARY64: "@Binary64"
|
84 NUM_AT_BINARY64: "@Binary64"
|
||||||
85 NUM_BINARY64: "Binary64" imported
|
85 NUM_BINARY64: "Binary64"
|
||||||
86 NUM_AT_BINARY32: "@Binary32"
|
86 NUM_AT_BINARY32: "@Binary32"
|
||||||
87 NUM_BINARY32: "Binary32" imported
|
87 NUM_BINARY32: "Binary32"
|
||||||
88 NUM_BITWISE_AND: "bitwiseAnd"
|
88 NUM_BITWISE_AND: "bitwiseAnd"
|
||||||
89 NUM_BITWISE_XOR: "bitwiseXor"
|
89 NUM_BITWISE_XOR: "bitwiseXor"
|
||||||
90 NUM_BITWISE_OR: "bitwiseOr"
|
90 NUM_BITWISE_OR: "bitwiseOr"
|
||||||
|
@ -1001,16 +1001,16 @@ define_builtins! {
|
||||||
96 NUM_SUB_SATURATED: "subSaturated"
|
96 NUM_SUB_SATURATED: "subSaturated"
|
||||||
97 NUM_MUL_WRAP: "mulWrap"
|
97 NUM_MUL_WRAP: "mulWrap"
|
||||||
98 NUM_MUL_CHECKED: "mulChecked"
|
98 NUM_MUL_CHECKED: "mulChecked"
|
||||||
99 NUM_INT: "Int" imported
|
99 NUM_INT: "Int"
|
||||||
100 NUM_FLOAT: "Float" imported
|
100 NUM_FLOAT: "Float"
|
||||||
101 NUM_AT_NATURAL: "@Natural"
|
101 NUM_AT_NATURAL: "@Natural"
|
||||||
102 NUM_NATURAL: "Natural" imported
|
102 NUM_NATURAL: "Natural"
|
||||||
103 NUM_NAT: "Nat" imported
|
103 NUM_NAT: "Nat"
|
||||||
104 NUM_INT_CAST: "intCast"
|
104 NUM_INT_CAST: "intCast"
|
||||||
105 NUM_IS_MULTIPLE_OF: "isMultipleOf"
|
105 NUM_IS_MULTIPLE_OF: "isMultipleOf"
|
||||||
106 NUM_AT_DECIMAL: "@Decimal"
|
106 NUM_AT_DECIMAL: "@Decimal"
|
||||||
107 NUM_DECIMAL: "Decimal" imported
|
107 NUM_DECIMAL: "Decimal"
|
||||||
108 NUM_DEC: "Dec" imported // the Num.Dectype alias
|
108 NUM_DEC: "Dec" // the Num.Dectype alias
|
||||||
109 NUM_BYTES_TO_U16: "bytesToU16"
|
109 NUM_BYTES_TO_U16: "bytesToU16"
|
||||||
110 NUM_BYTES_TO_U32: "bytesToU32"
|
110 NUM_BYTES_TO_U32: "bytesToU32"
|
||||||
111 NUM_CAST_TO_NAT: "#castToNat"
|
111 NUM_CAST_TO_NAT: "#castToNat"
|
||||||
|
@ -1063,7 +1063,7 @@ define_builtins! {
|
||||||
158 NUM_TO_F64_CHECKED: "toF64Checked"
|
158 NUM_TO_F64_CHECKED: "toF64Checked"
|
||||||
}
|
}
|
||||||
2 BOOL: "Bool" => {
|
2 BOOL: "Bool" => {
|
||||||
0 BOOL_BOOL: "Bool" imported // the Bool.Bool type alias
|
0 BOOL_BOOL: "Bool" // the Bool.Bool type alias
|
||||||
1 BOOL_FALSE: "False" imported // Bool.Bool = [ False, True ]
|
1 BOOL_FALSE: "False" imported // Bool.Bool = [ False, True ]
|
||||||
// NB: not strictly needed; used for finding global tag names in error suggestions
|
// NB: not strictly needed; used for finding global tag names in error suggestions
|
||||||
2 BOOL_TRUE: "True" imported // Bool.Bool = [ False, True ]
|
2 BOOL_TRUE: "True" imported // Bool.Bool = [ False, True ]
|
||||||
|
@ -1079,7 +1079,7 @@ define_builtins! {
|
||||||
0 STR_STR: "Str" imported // the Str.Str type alias
|
0 STR_STR: "Str" imported // the Str.Str type alias
|
||||||
1 STR_AT_STR: "@Str" // the Str.@Str private tag
|
1 STR_AT_STR: "@Str" // the Str.@Str private tag
|
||||||
2 STR_IS_EMPTY: "isEmpty"
|
2 STR_IS_EMPTY: "isEmpty"
|
||||||
3 STR_APPEND: "append"
|
3 STR_APPEND: "#append" // unused
|
||||||
4 STR_CONCAT: "concat"
|
4 STR_CONCAT: "concat"
|
||||||
5 STR_JOIN_WITH: "joinWith"
|
5 STR_JOIN_WITH: "joinWith"
|
||||||
6 STR_SPLIT: "split"
|
6 STR_SPLIT: "split"
|
||||||
|
@ -1174,7 +1174,7 @@ define_builtins! {
|
||||||
58 LIST_REPLACE: "replace"
|
58 LIST_REPLACE: "replace"
|
||||||
}
|
}
|
||||||
5 RESULT: "Result" => {
|
5 RESULT: "Result" => {
|
||||||
0 RESULT_RESULT: "Result" imported // the Result.Result type alias
|
0 RESULT_RESULT: "Result" // the Result.Result type alias
|
||||||
1 RESULT_OK: "Ok" imported // Result.Result a e = [ Ok a, Err e ]
|
1 RESULT_OK: "Ok" imported // Result.Result a e = [ Ok a, Err e ]
|
||||||
// NB: not strictly needed; used for finding global tag names in error suggestions
|
// NB: not strictly needed; used for finding global tag names in error suggestions
|
||||||
2 RESULT_ERR: "Err" imported // Result.Result a e = [ Ok a, Err e ]
|
2 RESULT_ERR: "Err" imported // Result.Result a e = [ Ok a, Err e ]
|
||||||
|
@ -1222,6 +1222,7 @@ define_builtins! {
|
||||||
12 SET_WALK: "walk"
|
12 SET_WALK: "walk"
|
||||||
13 SET_WALK_USER_FUNCTION: "#walk_user_function"
|
13 SET_WALK_USER_FUNCTION: "#walk_user_function"
|
||||||
14 SET_CONTAINS: "contains"
|
14 SET_CONTAINS: "contains"
|
||||||
|
15 SET_TO_DICT: "toDict"
|
||||||
}
|
}
|
||||||
8 BOX: "Box" => {
|
8 BOX: "Box" => {
|
||||||
0 BOX_BOX_TYPE: "Box" imported // the Box.Box opaque type
|
0 BOX_BOX_TYPE: "Box" imported // the Box.Box opaque type
|
||||||
|
|
|
@ -1027,6 +1027,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[bool] {
|
||||||
DictWalk => arena.alloc_slice_copy(&[owned, owned, function, closure_data]),
|
DictWalk => arena.alloc_slice_copy(&[owned, owned, function, closure_data]),
|
||||||
|
|
||||||
SetFromList => arena.alloc_slice_copy(&[owned]),
|
SetFromList => arena.alloc_slice_copy(&[owned]),
|
||||||
|
SetToDict => arena.alloc_slice_copy(&[owned]),
|
||||||
|
|
||||||
ExpectTrue => arena.alloc_slice_copy(&[irrelevant]),
|
ExpectTrue => arena.alloc_slice_copy(&[irrelevant]),
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ use crate::layout::{
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
use roc_builtins::bitcode::{FloatWidth, IntWidth};
|
||||||
|
use roc_can::abilities::AbilitiesStore;
|
||||||
use roc_can::expr::{ClosureData, IntValue};
|
use roc_can::expr::{ClosureData, IntValue};
|
||||||
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
|
use roc_collections::all::{default_hasher, BumpMap, BumpMapDefault, MutMap};
|
||||||
use roc_exhaustive::{Ctor, Guard, RenderAs, TagId};
|
use roc_exhaustive::{Ctor, Guard, RenderAs, TagId};
|
||||||
|
@ -251,11 +252,22 @@ impl<'a> PartialProc<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
enum PartialExprLink {
|
enum PolymorphicExpr {
|
||||||
Aliases(Symbol),
|
/// A root ability member, which must be specialized at a call site, for example
|
||||||
|
/// "hash" which must be specialized to an exact symbol implementing "hash" for a type.
|
||||||
|
AbilityMember(Symbol),
|
||||||
|
/// A polymorphic expression we inline at the usage site.
|
||||||
Expr(roc_can::expr::Expr, Variable),
|
Expr(roc_can::expr::Expr, Variable),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
enum PartialExprLink {
|
||||||
|
/// The root polymorphic expression
|
||||||
|
Sink(PolymorphicExpr),
|
||||||
|
/// A hop in a partial expression alias chain
|
||||||
|
Aliases(Symbol),
|
||||||
|
}
|
||||||
|
|
||||||
/// A table of symbols to polymorphic expressions. For example, in the program
|
/// A table of symbols to polymorphic expressions. For example, in the program
|
||||||
///
|
///
|
||||||
/// n = 1
|
/// n = 1
|
||||||
|
@ -281,8 +293,8 @@ impl PartialExprs {
|
||||||
Self(BumpMap::new_in(arena))
|
Self(BumpMap::new_in(arena))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, symbol: Symbol, expr: roc_can::expr::Expr, expr_var: Variable) {
|
fn insert(&mut self, symbol: Symbol, expr: PolymorphicExpr) {
|
||||||
self.0.insert(symbol, PartialExprLink::Expr(expr, expr_var));
|
self.0.insert(symbol, PartialExprLink::Sink(expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_alias(&mut self, symbol: Symbol, aliases: Symbol) {
|
fn insert_alias(&mut self, symbol: Symbol, aliases: Symbol) {
|
||||||
|
@ -293,7 +305,7 @@ impl PartialExprs {
|
||||||
self.0.contains_key(&symbol)
|
self.0.contains_key(&symbol)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&mut self, mut symbol: Symbol) -> Option<(&roc_can::expr::Expr, Variable)> {
|
fn get(&mut self, mut symbol: Symbol) -> Option<&PolymorphicExpr> {
|
||||||
// In practice the alias chain is very short
|
// In practice the alias chain is very short
|
||||||
loop {
|
loop {
|
||||||
match self.0.get(&symbol) {
|
match self.0.get(&symbol) {
|
||||||
|
@ -303,8 +315,8 @@ impl PartialExprs {
|
||||||
Some(&PartialExprLink::Aliases(real_symbol)) => {
|
Some(&PartialExprLink::Aliases(real_symbol)) => {
|
||||||
symbol = real_symbol;
|
symbol = real_symbol;
|
||||||
}
|
}
|
||||||
Some(PartialExprLink::Expr(expr, var)) => {
|
Some(PartialExprLink::Sink(expr)) => {
|
||||||
return Some((expr, *var));
|
return Some(expr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1119,6 +1131,7 @@ pub struct Env<'a, 'i> {
|
||||||
pub target_info: TargetInfo,
|
pub target_info: TargetInfo,
|
||||||
pub update_mode_ids: &'i mut UpdateModeIds,
|
pub update_mode_ids: &'i mut UpdateModeIds,
|
||||||
pub call_specialization_counter: u32,
|
pub call_specialization_counter: u32,
|
||||||
|
pub abilities_store: &'i AbilitiesStore,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'i> Env<'a, 'i> {
|
impl<'a, 'i> Env<'a, 'i> {
|
||||||
|
@ -1143,7 +1156,7 @@ impl<'a, 'i> Env<'a, 'i> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_imported_symbol(&self, symbol: Symbol) -> bool {
|
pub fn is_imported_symbol(&self, symbol: Symbol) -> bool {
|
||||||
symbol.module_id() != self.home && !symbol.is_builtin()
|
symbol.module_id() != self.home
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4218,10 +4231,14 @@ pub fn with_hole<'a>(
|
||||||
// a proc in this module, or an imported symbol
|
// a proc in this module, or an imported symbol
|
||||||
procs.partial_procs.contains_key(key)
|
procs.partial_procs.contains_key(key)
|
||||||
|| (env.is_imported_symbol(key) && !procs.is_imported_module_thunk(key))
|
|| (env.is_imported_symbol(key) && !procs.is_imported_module_thunk(key))
|
||||||
|
|| env.abilities_store.is_ability_member_name(key)
|
||||||
};
|
};
|
||||||
|
|
||||||
match loc_expr.value {
|
match loc_expr.value {
|
||||||
roc_can::expr::Expr::Var(proc_name) if is_known(proc_name) => {
|
roc_can::expr::Expr::Var(proc_name) if is_known(proc_name) => {
|
||||||
|
// This might be an ability member - if so, use the appropriate specialization.
|
||||||
|
let proc_name = get_specialization(env, fn_var, proc_name).unwrap_or(proc_name);
|
||||||
|
|
||||||
// a call by a known name
|
// a call by a known name
|
||||||
call_by_name(
|
call_by_name(
|
||||||
env,
|
env,
|
||||||
|
@ -4330,8 +4347,30 @@ pub fn with_hole<'a>(
|
||||||
unreachable!("calling a non-closure layout")
|
unreachable!("calling a non-closure layout")
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
UnspecializedExpr(symbol) => match full_layout {
|
UnspecializedExpr(symbol) => match procs.partial_exprs.get(symbol).unwrap()
|
||||||
RawFunctionLayout::Function(arg_layouts, lambda_set, ret_layout) => {
|
{
|
||||||
|
&PolymorphicExpr::AbilityMember(member) => {
|
||||||
|
let proc_name = get_specialization(env, fn_var, member).expect("Recorded as an ability member, but it doesn't have a specialization");
|
||||||
|
|
||||||
|
// a call by a known name
|
||||||
|
return call_by_name(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
fn_var,
|
||||||
|
proc_name,
|
||||||
|
loc_args,
|
||||||
|
layout_cache,
|
||||||
|
assigned,
|
||||||
|
hole,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
PolymorphicExpr::Expr(lambda_expr, lambda_expr_var) => {
|
||||||
|
match full_layout {
|
||||||
|
RawFunctionLayout::Function(
|
||||||
|
arg_layouts,
|
||||||
|
lambda_set,
|
||||||
|
ret_layout,
|
||||||
|
) => {
|
||||||
let closure_data_symbol = env.unique_symbol();
|
let closure_data_symbol = env.unique_symbol();
|
||||||
|
|
||||||
result = match_on_lambda_set(
|
result = match_on_lambda_set(
|
||||||
|
@ -4345,15 +4384,12 @@ pub fn with_hole<'a>(
|
||||||
hole,
|
hole,
|
||||||
);
|
);
|
||||||
|
|
||||||
let (lambda_expr, lambda_expr_var) =
|
|
||||||
procs.partial_exprs.get(symbol).unwrap();
|
|
||||||
|
|
||||||
let snapshot = env.subs.snapshot();
|
let snapshot = env.subs.snapshot();
|
||||||
let cache_snapshot = layout_cache.snapshot();
|
let cache_snapshot = layout_cache.snapshot();
|
||||||
let _unified = roc_unify::unify::unify(
|
let _unified = roc_unify::unify::unify(
|
||||||
env.subs,
|
env.subs,
|
||||||
fn_var,
|
fn_var,
|
||||||
lambda_expr_var,
|
*lambda_expr_var,
|
||||||
roc_unify::unify::Mode::EQ,
|
roc_unify::unify::Mode::EQ,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -4372,6 +4408,8 @@ pub fn with_hole<'a>(
|
||||||
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
RawFunctionLayout::ZeroArgumentThunk(_) => {
|
||||||
unreachable!("calling a non-closure layout")
|
unreachable!("calling a non-closure layout")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
NotASymbol => {
|
NotASymbol => {
|
||||||
// the expression is not a symbol. That means it's an expression
|
// the expression is not a symbol. That means it's an expression
|
||||||
|
@ -4705,6 +4743,43 @@ pub fn with_hole<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_specialization<'a>(
|
||||||
|
env: &mut Env<'a, '_>,
|
||||||
|
symbol_var: Variable,
|
||||||
|
symbol: Symbol,
|
||||||
|
) -> Option<Symbol> {
|
||||||
|
use roc_solve::ability::type_implementing_member;
|
||||||
|
use roc_unify::unify::unify;
|
||||||
|
|
||||||
|
match env.abilities_store.member_def(symbol) {
|
||||||
|
None => {
|
||||||
|
// This is not an ability member, it doesn't need specialization.
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Some(member) => {
|
||||||
|
let snapshot = env.subs.snapshot();
|
||||||
|
let (_, must_implement_ability) = unify(
|
||||||
|
env.subs,
|
||||||
|
symbol_var,
|
||||||
|
member.signature_var,
|
||||||
|
roc_unify::unify::Mode::EQ,
|
||||||
|
)
|
||||||
|
.expect_success("This typechecked previously");
|
||||||
|
env.subs.rollback_to(snapshot);
|
||||||
|
let specializing_type =
|
||||||
|
type_implementing_member(&must_implement_ability, member.parent_ability);
|
||||||
|
|
||||||
|
let specialization = env
|
||||||
|
.abilities_store
|
||||||
|
.get_specialization(symbol, specializing_type)
|
||||||
|
.expect("No specialization is recorded - I thought there would only be a type error here.");
|
||||||
|
|
||||||
|
Some(specialization.symbol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_arguments)]
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn construct_closure_data<'a>(
|
fn construct_closure_data<'a>(
|
||||||
env: &mut Env<'a, '_>,
|
env: &mut Env<'a, '_>,
|
||||||
|
@ -5621,9 +5696,10 @@ pub fn from_can<'a>(
|
||||||
// At the definition site `n = 1` we only know `1` to have the type `[Int *]`,
|
// At the definition site `n = 1` we only know `1` to have the type `[Int *]`,
|
||||||
// which won't be refined until the call `asU8 n`. Add it as a partial expression
|
// which won't be refined until the call `asU8 n`. Add it as a partial expression
|
||||||
// that will be specialized at each concrete usage site.
|
// that will be specialized at each concrete usage site.
|
||||||
procs
|
procs.partial_exprs.insert(
|
||||||
.partial_exprs
|
*symbol,
|
||||||
.insert(*symbol, def.loc_expr.value, def.expr_var);
|
PolymorphicExpr::Expr(def.loc_expr.value, def.expr_var),
|
||||||
|
);
|
||||||
|
|
||||||
let result = from_can(env, variable, cont.value, procs, layout_cache);
|
let result = from_can(env, variable, cont.value, procs, layout_cache);
|
||||||
|
|
||||||
|
@ -6329,7 +6405,7 @@ fn store_pattern_help<'a>(
|
||||||
|
|
||||||
match can_pat {
|
match can_pat {
|
||||||
Identifier(symbol) => {
|
Identifier(symbol) => {
|
||||||
if let Some((_, var)) = procs.partial_exprs.get(outer_symbol) {
|
if let Some(&PolymorphicExpr::Expr(_, var)) = procs.partial_exprs.get(outer_symbol) {
|
||||||
// It might be the case that symbol we're storing hasn't been reified to a value
|
// It might be the case that symbol we're storing hasn't been reified to a value
|
||||||
// yet, if it's polymorphic. Do that now.
|
// yet, if it's polymorphic. Do that now.
|
||||||
stmt = specialize_symbol(
|
stmt = specialize_symbol(
|
||||||
|
@ -6690,7 +6766,19 @@ fn can_reuse_symbol<'a>(
|
||||||
if let roc_can::expr::Expr::Var(symbol) = expr {
|
if let roc_can::expr::Expr::Var(symbol) = expr {
|
||||||
let symbol = *symbol;
|
let symbol = *symbol;
|
||||||
|
|
||||||
if env.is_imported_symbol(symbol) {
|
let arguments = [
|
||||||
|
Symbol::ARG_1,
|
||||||
|
Symbol::ARG_2,
|
||||||
|
Symbol::ARG_3,
|
||||||
|
Symbol::ARG_4,
|
||||||
|
Symbol::ARG_5,
|
||||||
|
Symbol::ARG_6,
|
||||||
|
Symbol::ARG_7,
|
||||||
|
];
|
||||||
|
|
||||||
|
if arguments.contains(&symbol) {
|
||||||
|
Value(symbol)
|
||||||
|
} else if env.is_imported_symbol(symbol) {
|
||||||
Imported(symbol)
|
Imported(symbol)
|
||||||
} else if procs.partial_procs.contains_key(symbol) {
|
} else if procs.partial_procs.contains_key(symbol) {
|
||||||
LocalFunction(symbol)
|
LocalFunction(symbol)
|
||||||
|
@ -6727,6 +6815,13 @@ fn handle_variable_aliasing<'a, BuildRest>(
|
||||||
where
|
where
|
||||||
BuildRest: FnOnce(&mut Env<'a, '_>, &mut Procs<'a>, &mut LayoutCache<'a>) -> Stmt<'a>,
|
BuildRest: FnOnce(&mut Env<'a, '_>, &mut Procs<'a>, &mut LayoutCache<'a>) -> Stmt<'a>,
|
||||||
{
|
{
|
||||||
|
if env.abilities_store.is_ability_member_name(right) {
|
||||||
|
procs
|
||||||
|
.partial_exprs
|
||||||
|
.insert(left, PolymorphicExpr::AbilityMember(right));
|
||||||
|
return build_rest(env, procs, layout_cache);
|
||||||
|
}
|
||||||
|
|
||||||
if procs.partial_exprs.contains(right) {
|
if procs.partial_exprs.contains(right) {
|
||||||
// If `right` links to a partial expression, make sure we link `left` to it as well, so
|
// If `right` links to a partial expression, make sure we link `left` to it as well, so
|
||||||
// that usages of it will be specialized when building the rest of the program.
|
// that usages of it will be specialized when building the rest of the program.
|
||||||
|
@ -6804,7 +6899,7 @@ fn specialize_symbol<'a>(
|
||||||
result: Stmt<'a>,
|
result: Stmt<'a>,
|
||||||
original: Symbol,
|
original: Symbol,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
if let Some((expr, expr_var)) = procs.partial_exprs.get(original) {
|
if let Some(PolymorphicExpr::Expr(expr, expr_var)) = procs.partial_exprs.get(original) {
|
||||||
// Specialize the expression type now, based off the `arg_var` we've been given.
|
// Specialize the expression type now, based off the `arg_var` we've been given.
|
||||||
// TODO: cache the specialized result
|
// TODO: cache the specialized result
|
||||||
let snapshot = env.subs.snapshot();
|
let snapshot = env.subs.snapshot();
|
||||||
|
@ -6812,14 +6907,14 @@ fn specialize_symbol<'a>(
|
||||||
let _unified = roc_unify::unify::unify(
|
let _unified = roc_unify::unify::unify(
|
||||||
env.subs,
|
env.subs,
|
||||||
arg_var.unwrap(),
|
arg_var.unwrap(),
|
||||||
expr_var,
|
*expr_var,
|
||||||
roc_unify::unify::Mode::EQ,
|
roc_unify::unify::Mode::EQ,
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = with_hole(
|
let result = with_hole(
|
||||||
env,
|
env,
|
||||||
expr.clone(),
|
expr.clone(),
|
||||||
expr_var,
|
*expr_var,
|
||||||
procs,
|
procs,
|
||||||
layout_cache,
|
layout_cache,
|
||||||
symbol,
|
symbol,
|
||||||
|
@ -6837,9 +6932,10 @@ fn specialize_symbol<'a>(
|
||||||
None => {
|
None => {
|
||||||
match arg_var {
|
match arg_var {
|
||||||
Some(arg_var) if env.is_imported_symbol(original) => {
|
Some(arg_var) if env.is_imported_symbol(original) => {
|
||||||
let raw = layout_cache
|
let raw = match layout_cache.raw_from_var(env.arena, arg_var, env.subs) {
|
||||||
.raw_from_var(env.arena, arg_var, env.subs)
|
Ok(v) => v,
|
||||||
.expect("creating layout does not fail");
|
Err(e) => return_on_layout_error_help!(env, e),
|
||||||
|
};
|
||||||
|
|
||||||
if procs.is_imported_module_thunk(original) {
|
if procs.is_imported_module_thunk(original) {
|
||||||
let layout = match raw {
|
let layout = match raw {
|
||||||
|
@ -7315,6 +7411,7 @@ fn call_by_name_help<'a>(
|
||||||
add_needed_external(procs, env, original_fn_var, proc_name);
|
add_needed_external(procs, env, original_fn_var, proc_name);
|
||||||
|
|
||||||
debug_assert_ne!(proc_name.module_id(), ModuleId::ATTR);
|
debug_assert_ne!(proc_name.module_id(), ModuleId::ATTR);
|
||||||
|
|
||||||
if procs.is_imported_module_thunk(proc_name) {
|
if procs.is_imported_module_thunk(proc_name) {
|
||||||
force_thunk(
|
force_thunk(
|
||||||
env,
|
env,
|
||||||
|
@ -7323,13 +7420,23 @@ fn call_by_name_help<'a>(
|
||||||
assigned,
|
assigned,
|
||||||
hole,
|
hole,
|
||||||
)
|
)
|
||||||
} else {
|
} else if field_symbols.is_empty() {
|
||||||
debug_assert!(
|
// this is a case like `Str.concat`, an imported standard function, applied to zero arguments
|
||||||
!field_symbols.is_empty(),
|
|
||||||
"{} should be in the list of imported_module_thunks",
|
|
||||||
proc_name
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// imported symbols cannot capture anything
|
||||||
|
let captured = &[];
|
||||||
|
|
||||||
|
construct_closure_data(
|
||||||
|
env,
|
||||||
|
procs,
|
||||||
|
layout_cache,
|
||||||
|
lambda_set,
|
||||||
|
proc_name,
|
||||||
|
captured,
|
||||||
|
assigned,
|
||||||
|
hole,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
argument_layouts.len(),
|
argument_layouts.len(),
|
||||||
field_symbols.len(),
|
field_symbols.len(),
|
||||||
|
@ -7484,8 +7591,6 @@ fn call_by_name_module_thunk<'a>(
|
||||||
assigned: Symbol,
|
assigned: Symbol,
|
||||||
hole: &'a Stmt<'a>,
|
hole: &'a Stmt<'a>,
|
||||||
) -> Stmt<'a> {
|
) -> Stmt<'a> {
|
||||||
debug_assert!(!env.is_imported_symbol(proc_name));
|
|
||||||
|
|
||||||
let top_level_layout = ProcLayout::new(env.arena, &[], *ret_layout);
|
let top_level_layout = ProcLayout::new(env.arena, &[], *ret_layout);
|
||||||
|
|
||||||
let inner_layout = *ret_layout;
|
let inner_layout = *ret_layout;
|
||||||
|
|
|
@ -705,7 +705,7 @@ impl<'a, T> Collection<'a, T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_items(items: &'a [T]) -> Collection<'a, T> {
|
pub const fn with_items(items: &'a [T]) -> Collection<'a, T> {
|
||||||
Collection {
|
Collection {
|
||||||
items,
|
items,
|
||||||
final_comments: None,
|
final_comments: None,
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::parser::{specialize, word1, EPackageEntry, EPackageName, Parser};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::string_literal;
|
use crate::string_literal;
|
||||||
use bumpalo::collections::Vec;
|
use bumpalo::collections::Vec;
|
||||||
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
@ -17,6 +18,10 @@ pub enum HeaderFor<'a> {
|
||||||
generates: UppercaseIdent<'a>,
|
generates: UppercaseIdent<'a>,
|
||||||
generates_with: &'a [Loc<ExposedName<'a>>],
|
generates_with: &'a [Loc<ExposedName<'a>>],
|
||||||
},
|
},
|
||||||
|
/// Only created during canonicalization, never actually parsed from source
|
||||||
|
Builtin {
|
||||||
|
generates_with: &'a [Symbol],
|
||||||
|
},
|
||||||
PkgConfig {
|
PkgConfig {
|
||||||
/// usually `pf`
|
/// usually `pf`
|
||||||
config_shorthand: &'a str,
|
config_shorthand: &'a str,
|
||||||
|
@ -60,11 +65,11 @@ impl<'a> From<ModuleName<'a>> for &'a str {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ModuleName<'a> {
|
impl<'a> ModuleName<'a> {
|
||||||
pub fn new(name: &'a str) -> Self {
|
pub const fn new(name: &'a str) -> Self {
|
||||||
ModuleName(name)
|
ModuleName(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn as_str(&'a self) -> &'a str {
|
pub const fn as_str(&'a self) -> &'a str {
|
||||||
self.0
|
self.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +93,7 @@ impl<'a> From<ExposedName<'a>> for &'a str {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ExposedName<'a> {
|
impl<'a> ExposedName<'a> {
|
||||||
pub fn new(name: &'a str) -> Self {
|
pub const fn new(name: &'a str) -> Self {
|
||||||
ExposedName(name)
|
ExposedName(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -279,16 +279,16 @@ pub struct Loc<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> Loc<T> {
|
impl<T> Loc<T> {
|
||||||
pub fn new(start: u32, end: u32, value: T) -> Loc<T> {
|
pub const fn new(start: u32, end: u32, value: T) -> Loc<T> {
|
||||||
let region = Region::new(Position::new(start), Position::new(end));
|
let region = Region::new(Position::new(start), Position::new(end));
|
||||||
Loc { region, value }
|
Loc { region, value }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn at(region: Region, value: T) -> Loc<T> {
|
pub const fn at(region: Region, value: T) -> Loc<T> {
|
||||||
Loc { region, value }
|
Loc { region, value }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn at_zero(value: T) -> Loc<T> {
|
pub const fn at_zero(value: T) -> Loc<T> {
|
||||||
let region = Region::zero();
|
let region = Region::zero();
|
||||||
Loc { region, value }
|
Loc { region, value }
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
use roc_can::abilities::AbilitiesStore;
|
use roc_can::abilities::AbilitiesStore;
|
||||||
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Loc, Region};
|
use roc_region::all::{Loc, Region};
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
use roc_types::subs::Variable;
|
use roc_types::subs::Variable;
|
||||||
use roc_types::types::{Category, PatternCategory};
|
use roc_types::types::{Category, PatternCategory};
|
||||||
use roc_unify::unify::MustImplementAbility;
|
use roc_unify::unify::MustImplementAbility;
|
||||||
|
use roc_unify::unify::MustImplementConstraints;
|
||||||
|
|
||||||
use crate::solve::{IncompleteAbilityImplementation, TypeError};
|
use crate::solve::{IncompleteAbilityImplementation, TypeError};
|
||||||
|
|
||||||
|
@ -18,17 +20,14 @@ pub enum AbilityImplError {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct DeferredMustImplementAbility(Vec<(Vec<MustImplementAbility>, AbilityImplError)>);
|
pub struct DeferredMustImplementAbility(Vec<(MustImplementConstraints, AbilityImplError)>);
|
||||||
|
|
||||||
impl DeferredMustImplementAbility {
|
impl DeferredMustImplementAbility {
|
||||||
pub fn add(&mut self, must_implement: Vec<MustImplementAbility>, on_error: AbilityImplError) {
|
pub fn add(&mut self, must_implement: MustImplementConstraints, on_error: AbilityImplError) {
|
||||||
self.0.push((must_implement, on_error));
|
self.0.push((must_implement, on_error));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check(self, subs: &mut Subs, abilities_store: &AbilitiesStore) -> Vec<TypeError> {
|
pub fn check(self, subs: &mut Subs, abilities_store: &AbilitiesStore) -> Vec<TypeError> {
|
||||||
// Two passes here. First up let's build up records of what types fully implement
|
|
||||||
// abilities, and what specializations are available/missing for the ones that don't.
|
|
||||||
// Use a vec since these lists should usually be pretty small.
|
|
||||||
let mut good = vec![];
|
let mut good = vec![];
|
||||||
let mut bad = vec![];
|
let mut bad = vec![];
|
||||||
|
|
||||||
|
@ -45,8 +44,21 @@ impl DeferredMustImplementAbility {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
for (mias, _) in self.0.iter() {
|
let mut problems = vec![];
|
||||||
for &mia @ MustImplementAbility { typ, ability } in mias {
|
|
||||||
|
// Keep track of which types that have an incomplete ability were reported as part of
|
||||||
|
// another type error (from an expression or pattern). If we reported an error for a type
|
||||||
|
// that doesn't implement an ability in that context, we don't want to repeat the error
|
||||||
|
// message.
|
||||||
|
let mut reported_in_context = vec![];
|
||||||
|
let mut incomplete_not_in_context = vec![];
|
||||||
|
|
||||||
|
for (constraints, on_error) in self.0.into_iter() {
|
||||||
|
let must_implement = constraints.get_unique();
|
||||||
|
|
||||||
|
// First off, make sure we populate information about which of the "must implement"
|
||||||
|
// constraints are met, and which aren't.
|
||||||
|
for &mia @ MustImplementAbility { typ, ability } in must_implement.iter() {
|
||||||
if is_good!(&mia) || get_bad!(mia).is_some() {
|
if is_good!(&mia) || get_bad!(mia).is_some() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -80,22 +92,16 @@ impl DeferredMustImplementAbility {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Now figure out what errors we need to report.
|
// Now, figure out what errors we need to report.
|
||||||
let mut problems = vec![];
|
|
||||||
|
|
||||||
// Keep track of which types that have an incomplete ability were reported as part of
|
|
||||||
// another type error (from an expression or pattern). If we reported an error for a type
|
|
||||||
// that doesn't implement an ability in that context, we don't want to repeat the error
|
|
||||||
// message.
|
|
||||||
let mut reported_in_context = vec![];
|
|
||||||
let mut incomplete_not_in_context = vec![];
|
|
||||||
|
|
||||||
for (must_implement, on_error) in self.0.into_iter() {
|
|
||||||
use AbilityImplError::*;
|
use AbilityImplError::*;
|
||||||
match on_error {
|
match on_error {
|
||||||
IncompleteAbility => {
|
IncompleteAbility => {
|
||||||
|
// These aren't attached to another type error, so if these must_implement
|
||||||
|
// constraints aren't met, we'll emit a generic "this type doesn't implement an
|
||||||
|
// ability" error message at the end. We only want to do this if it turns out
|
||||||
|
// the "must implement" constraint indeed wasn't part of a more specific type
|
||||||
|
// error.
|
||||||
incomplete_not_in_context.extend(must_implement);
|
incomplete_not_in_context.extend(must_implement);
|
||||||
}
|
}
|
||||||
BadExpr(region, category, var) => {
|
BadExpr(region, category, var) => {
|
||||||
|
@ -138,9 +144,11 @@ impl DeferredMustImplementAbility {
|
||||||
reported_in_context.extend(must_implement);
|
reported_in_context.extend(must_implement);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Go through and attach generic "type does not implement ability" errors, if they were not
|
||||||
|
// part of a larger context.
|
||||||
for mia in incomplete_not_in_context.into_iter() {
|
for mia in incomplete_not_in_context.into_iter() {
|
||||||
if let Some(must_implement) = get_bad!(mia) {
|
if let Some(must_implement) = get_bad!(mia) {
|
||||||
if !reported_in_context.contains(&mia) {
|
if !reported_in_context.contains(&mia) {
|
||||||
|
@ -154,3 +162,29 @@ impl DeferredMustImplementAbility {
|
||||||
problems
|
problems
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Determines what type implements an ability member of a specialized signature, given the
|
||||||
|
/// [MustImplementAbility] constraints of the signature.
|
||||||
|
pub fn type_implementing_member(
|
||||||
|
specialization_must_implement_constraints: &MustImplementConstraints,
|
||||||
|
ability: Symbol,
|
||||||
|
) -> Symbol {
|
||||||
|
debug_assert_eq!({
|
||||||
|
let ability_implementations_for_specialization =
|
||||||
|
specialization_must_implement_constraints
|
||||||
|
.clone()
|
||||||
|
.get_unique();
|
||||||
|
|
||||||
|
ability_implementations_for_specialization.len()
|
||||||
|
},
|
||||||
|
1,
|
||||||
|
"Multiple variables bound to an ability - this is ambiguous and should have been caught in canonicalization: {:?}",
|
||||||
|
specialization_must_implement_constraints
|
||||||
|
);
|
||||||
|
|
||||||
|
specialization_must_implement_constraints
|
||||||
|
.iter_for_ability(ability)
|
||||||
|
.next()
|
||||||
|
.unwrap()
|
||||||
|
.typ
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
// See github.com/rtfeldman/roc/issues/800 for discussion of the large_enum_variant check.
|
||||||
#![allow(clippy::large_enum_variant)]
|
#![allow(clippy::large_enum_variant)]
|
||||||
|
|
||||||
mod ability;
|
pub mod ability;
|
||||||
pub mod module;
|
pub mod module;
|
||||||
pub mod solve;
|
pub mod solve;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::ability::{AbilityImplError, DeferredMustImplementAbility};
|
use crate::ability::{type_implementing_member, AbilityImplError, DeferredMustImplementAbility};
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use roc_can::abilities::{AbilitiesStore, MemberSpecialization};
|
use roc_can::abilities::{AbilitiesStore, MemberSpecialization};
|
||||||
use roc_can::constraint::Constraint::{self, *};
|
use roc_can::constraint::Constraint::{self, *};
|
||||||
|
@ -703,7 +703,6 @@ fn solve(
|
||||||
check_ability_specialization(
|
check_ability_specialization(
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
&new_env,
|
|
||||||
pools,
|
pools,
|
||||||
rank,
|
rank,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
|
@ -812,7 +811,6 @@ fn solve(
|
||||||
check_ability_specialization(
|
check_ability_specialization(
|
||||||
arena,
|
arena,
|
||||||
subs,
|
subs,
|
||||||
&new_env,
|
|
||||||
pools,
|
pools,
|
||||||
rank,
|
rank,
|
||||||
abilities_store,
|
abilities_store,
|
||||||
|
@ -1189,6 +1187,7 @@ fn solve(
|
||||||
match new_desc.content {
|
match new_desc.content {
|
||||||
Content::Structure(FlatType::TagUnion(tags, _)) => {
|
Content::Structure(FlatType::TagUnion(tags, _)) => {
|
||||||
let new_ext = subs.fresh_unnamed_flex_var();
|
let new_ext = subs.fresh_unnamed_flex_var();
|
||||||
|
subs.set_rank(new_ext, new_desc.rank);
|
||||||
let new_union = Content::Structure(FlatType::TagUnion(tags, new_ext));
|
let new_union = Content::Structure(FlatType::TagUnion(tags, new_ext));
|
||||||
new_desc.content = new_union;
|
new_desc.content = new_union;
|
||||||
subs.set(actual, new_desc);
|
subs.set(actual, new_desc);
|
||||||
|
@ -1282,7 +1281,6 @@ fn solve(
|
||||||
fn check_ability_specialization(
|
fn check_ability_specialization(
|
||||||
arena: &Bump,
|
arena: &Bump,
|
||||||
subs: &mut Subs,
|
subs: &mut Subs,
|
||||||
env: &Env,
|
|
||||||
pools: &mut Pools,
|
pools: &mut Pools,
|
||||||
rank: Rank,
|
rank: Rank,
|
||||||
abilities_store: &mut AbilitiesStore,
|
abilities_store: &mut AbilitiesStore,
|
||||||
|
@ -1295,9 +1293,7 @@ fn check_ability_specialization(
|
||||||
// inferred type for the specialization actually aligns with the expected
|
// inferred type for the specialization actually aligns with the expected
|
||||||
// implementation.
|
// implementation.
|
||||||
if let Some((root_symbol, root_data)) = abilities_store.root_name_and_def(symbol) {
|
if let Some((root_symbol, root_data)) = abilities_store.root_name_and_def(symbol) {
|
||||||
let root_signature_var = env
|
let root_signature_var = root_data.signature_var;
|
||||||
.get_var_by_symbol(&root_symbol)
|
|
||||||
.expect("Ability should be registered in env by now!");
|
|
||||||
|
|
||||||
// Check if they unify - if they don't, then the claimed specialization isn't really one,
|
// Check if they unify - if they don't, then the claimed specialization isn't really one,
|
||||||
// and that's a type error!
|
// and that's a type error!
|
||||||
|
@ -1351,16 +1347,8 @@ fn check_ability_specialization(
|
||||||
|
|
||||||
// First, figure out and register for what type does this symbol specialize
|
// First, figure out and register for what type does this symbol specialize
|
||||||
// the ability member.
|
// the ability member.
|
||||||
let mut ability_implementations_for_specialization = must_implement_ability
|
let specialization_type =
|
||||||
.iter()
|
type_implementing_member(&must_implement_ability, root_data.parent_ability);
|
||||||
.filter(|mia| mia.ability == root_data.parent_ability)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
ability_implementations_for_specialization.dedup();
|
|
||||||
|
|
||||||
debug_assert!(ability_implementations_for_specialization.len() == 1, "Multiple variables bound to an ability - this is ambiguous and should have been caught in canonicalization");
|
|
||||||
|
|
||||||
// This is a valid specialization! Record it.
|
|
||||||
let specialization_type = ability_implementations_for_specialization[0].typ;
|
|
||||||
let specialization = MemberSpecialization {
|
let specialization = MemberSpecialization {
|
||||||
symbol,
|
symbol,
|
||||||
region: symbol_loc_var.region,
|
region: symbol_loc_var.region,
|
||||||
|
|
|
@ -17,8 +17,6 @@ mod solve_expr {
|
||||||
|
|
||||||
fn run_load_and_infer(src: &str) -> Result<LoadedModule, std::io::Error> {
|
fn run_load_and_infer(src: &str) -> Result<LoadedModule, std::io::Error> {
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use std::fs::File;
|
|
||||||
use std::io::Write;
|
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use tempfile::tempdir;
|
use tempfile::tempdir;
|
||||||
|
|
||||||
|
@ -40,13 +38,10 @@ mod solve_expr {
|
||||||
let dir = tempdir()?;
|
let dir = tempdir()?;
|
||||||
let filename = PathBuf::from("Test.roc");
|
let filename = PathBuf::from("Test.roc");
|
||||||
let file_path = dir.path().join(filename);
|
let file_path = dir.path().join(filename);
|
||||||
let full_file_path = file_path.clone();
|
let result = roc_load::load_and_typecheck_str(
|
||||||
let mut file = File::create(file_path)?;
|
|
||||||
writeln!(file, "{}", module_src)?;
|
|
||||||
drop(file);
|
|
||||||
let result = roc_load::load_and_typecheck(
|
|
||||||
arena,
|
arena,
|
||||||
full_file_path,
|
file_path,
|
||||||
|
module_src,
|
||||||
dir.path(),
|
dir.path(),
|
||||||
exposed_types,
|
exposed_types,
|
||||||
roc_target::TargetInfo::default_x86_64(),
|
roc_target::TargetInfo::default_x86_64(),
|
||||||
|
@ -125,8 +120,15 @@ mod solve_expr {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn promote_expr_to_module(src: &str) -> String {
|
fn promote_expr_to_module(src: &str) -> String {
|
||||||
let mut buffer =
|
let mut buffer = String::from(indoc!(
|
||||||
String::from("app \"test\" provides [ main ] to \"./platform\"\n\nmain =\n");
|
r#"
|
||||||
|
app "test"
|
||||||
|
imports []
|
||||||
|
provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
main =
|
||||||
|
"#
|
||||||
|
));
|
||||||
|
|
||||||
for line in src.lines() {
|
for line in src.lines() {
|
||||||
// indent the body!
|
// indent the body!
|
||||||
|
@ -2397,7 +2399,7 @@ mod solve_expr {
|
||||||
{ numIdentity, x : numIdentity 42, y }
|
{ numIdentity, x : numIdentity 42, y }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"{ numIdentity : Num a -> Num a, x : Num a, y : F64 }",
|
"{ numIdentity : Num a -> Num a, x : Num a, y : Float * }",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3603,7 +3605,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
app "test" provides [ main ] to "./platform"
|
app "test" imports [ Result.{ Result } ] provides [ main ] to "./platform"
|
||||||
|
|
||||||
boom = \_ -> boom {}
|
boom = \_ -> boom {}
|
||||||
|
|
||||||
|
@ -3820,7 +3822,7 @@ mod solve_expr {
|
||||||
negatePoint { x: 1, y: 2.1, z: 0x3 }
|
negatePoint { x: 1, y: 2.1, z: 0x3 }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"{ x : Num a, y : F64, z : Int * }",
|
"{ x : Num a, y : Float *, z : Int * }",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3837,7 +3839,7 @@ mod solve_expr {
|
||||||
{ a, b }
|
{ a, b }
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"{ a : { x : Num a, y : F64, z : c }, b : { blah : Str, x : Num a, y : F64, z : c } }",
|
"{ a : { x : Num a, y : Float *, z : c }, b : { blah : Str, x : Num a, y : Float *, z : c } }",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4828,7 +4830,7 @@ mod solve_expr {
|
||||||
infer_eq_without_problem(
|
infer_eq_without_problem(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
canIGo : _ -> Result _ _
|
canIGo : _ -> Result.Result _ _
|
||||||
canIGo = \color ->
|
canIGo = \color ->
|
||||||
when color is
|
when color is
|
||||||
"green" -> Ok "go!"
|
"green" -> Ok "go!"
|
||||||
|
@ -5913,4 +5915,40 @@ mod solve_expr {
|
||||||
"U64",
|
"U64",
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn alias_ability_member() {
|
||||||
|
infer_eq_without_problem(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [ thething ] to "./platform"
|
||||||
|
|
||||||
|
Hash has
|
||||||
|
hash : a -> U64 | a has Hash
|
||||||
|
|
||||||
|
thething =
|
||||||
|
itis = hash
|
||||||
|
itis
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
"a -> U64 | a has Hash",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn when_branch_and_body_flipflop() {
|
||||||
|
infer_eq_without_problem(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
func = \record ->
|
||||||
|
when record.tag is
|
||||||
|
A -> { record & tag: B }
|
||||||
|
B -> { record & tag: A }
|
||||||
|
|
||||||
|
func
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
"{ tag : [ A, B ] }a -> { tag : [ A, B ] }a",
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
86
compiler/test_gen/src/gen_abilities.rs
Normal file
86
compiler/test_gen/src/gen_abilities.rs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
#[cfg(feature = "gen-llvm")]
|
||||||
|
use crate::helpers::llvm::assert_evals_to;
|
||||||
|
|
||||||
|
#[cfg(feature = "gen-dev")]
|
||||||
|
use crate::helpers::dev::assert_evals_to;
|
||||||
|
|
||||||
|
#[cfg(feature = "gen-wasm")]
|
||||||
|
use crate::helpers::wasm::assert_evals_to;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use indoc::indoc;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn hash_specialization() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
Hash has
|
||||||
|
hash : a -> U64 | a has Hash
|
||||||
|
|
||||||
|
Id := U64
|
||||||
|
|
||||||
|
hash = \$Id n -> n
|
||||||
|
|
||||||
|
main = hash ($Id 1234)
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1234,
|
||||||
|
u64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn hash_specialization_multiple_add() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
Hash has
|
||||||
|
hash : a -> U64 | a has Hash
|
||||||
|
|
||||||
|
Id := U64
|
||||||
|
|
||||||
|
hash = \$Id n -> n
|
||||||
|
|
||||||
|
One := {}
|
||||||
|
|
||||||
|
hash = \$One _ -> 1
|
||||||
|
|
||||||
|
main = hash ($Id 1234) + hash ($One {})
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1235,
|
||||||
|
u64
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
|
fn alias_member_specialization() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
Hash has
|
||||||
|
hash : a -> U64 | a has Hash
|
||||||
|
|
||||||
|
Id := U64
|
||||||
|
|
||||||
|
hash = \$Id n -> n
|
||||||
|
|
||||||
|
main =
|
||||||
|
aliasedHash = hash
|
||||||
|
aliasedHash ($Id 1234)
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
1234,
|
||||||
|
u64
|
||||||
|
);
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ fn nat_alias() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
i : Nat
|
i : Num.Nat
|
||||||
i = 1
|
i = 1
|
||||||
|
|
||||||
i
|
i
|
||||||
|
@ -2740,6 +2740,166 @@ fn num_to_str() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn num_to_str_u8() {
|
||||||
|
use roc_std::RocStr;
|
||||||
|
|
||||||
|
assert_evals_to!(r#"Num.toStr 0u8"#, RocStr::from("0"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 1u8"#, RocStr::from("1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 10u8"#, RocStr::from("10"), RocStr);
|
||||||
|
|
||||||
|
let max = format!("{}", u8::MAX);
|
||||||
|
assert_evals_to!(r#"Num.toStr Num.maxU8"#, RocStr::from(max.as_str()), RocStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn num_to_str_u16() {
|
||||||
|
use roc_std::RocStr;
|
||||||
|
|
||||||
|
assert_evals_to!(r#"Num.toStr 0u16"#, RocStr::from("0"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 1u16"#, RocStr::from("1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 10u16"#, RocStr::from("10"), RocStr);
|
||||||
|
|
||||||
|
let max = format!("{}", u16::MAX);
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"Num.toStr Num.maxU16"#,
|
||||||
|
RocStr::from(max.as_str()),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn num_to_str_u32() {
|
||||||
|
use roc_std::RocStr;
|
||||||
|
|
||||||
|
assert_evals_to!(r#"Num.toStr 0u32"#, RocStr::from("0"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 1u32"#, RocStr::from("1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 10u32"#, RocStr::from("10"), RocStr);
|
||||||
|
|
||||||
|
let max = format!("{}", u32::MAX);
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"Num.toStr Num.maxU32"#,
|
||||||
|
RocStr::from(max.as_str()),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn num_to_str_u64() {
|
||||||
|
use roc_std::RocStr;
|
||||||
|
|
||||||
|
assert_evals_to!(r#"Num.toStr 0u64"#, RocStr::from("0"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 1u64"#, RocStr::from("1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 10u64"#, RocStr::from("10"), RocStr);
|
||||||
|
|
||||||
|
let max = format!("{}", u64::MAX);
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"Num.toStr Num.maxU64"#,
|
||||||
|
RocStr::from(max.as_str()),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn num_to_str_i8() {
|
||||||
|
use roc_std::RocStr;
|
||||||
|
|
||||||
|
assert_evals_to!(r#"Num.toStr -10i8"#, RocStr::from("-10"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr -1i8"#, RocStr::from("-1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 0i8"#, RocStr::from("0"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 1i8"#, RocStr::from("1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 10i8"#, RocStr::from("10"), RocStr);
|
||||||
|
|
||||||
|
let max = format!("{}", i8::MAX);
|
||||||
|
assert_evals_to!(r#"Num.toStr Num.maxI8"#, RocStr::from(max.as_str()), RocStr);
|
||||||
|
|
||||||
|
let max = format!("{}", i8::MIN);
|
||||||
|
assert_evals_to!(r#"Num.toStr Num.minI8"#, RocStr::from(max.as_str()), RocStr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn num_to_str_i16() {
|
||||||
|
use roc_std::RocStr;
|
||||||
|
|
||||||
|
assert_evals_to!(r#"Num.toStr -10i16"#, RocStr::from("-10"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr -1i16"#, RocStr::from("-1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 0i16"#, RocStr::from("0"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 1i16"#, RocStr::from("1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 10i16"#, RocStr::from("10"), RocStr);
|
||||||
|
|
||||||
|
let max = format!("{}", i16::MAX);
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"Num.toStr Num.maxI16"#,
|
||||||
|
RocStr::from(max.as_str()),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
let max = format!("{}", i16::MIN);
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"Num.toStr Num.minI16"#,
|
||||||
|
RocStr::from(max.as_str()),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn num_to_str_i32() {
|
||||||
|
use roc_std::RocStr;
|
||||||
|
|
||||||
|
assert_evals_to!(r#"Num.toStr -10i32"#, RocStr::from("-10"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr -1i32"#, RocStr::from("-1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 0i32"#, RocStr::from("0"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 1i32"#, RocStr::from("1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 10i32"#, RocStr::from("10"), RocStr);
|
||||||
|
|
||||||
|
let max = format!("{}", i32::MAX);
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"Num.toStr Num.maxI32"#,
|
||||||
|
RocStr::from(max.as_str()),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
let max = format!("{}", i32::MIN);
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"Num.toStr Num.minI32"#,
|
||||||
|
RocStr::from(max.as_str()),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(any(feature = "gen-llvm"))]
|
||||||
|
fn num_to_str_i64() {
|
||||||
|
use roc_std::RocStr;
|
||||||
|
|
||||||
|
assert_evals_to!(r#"Num.toStr -10i64"#, RocStr::from("-10"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr -1i64"#, RocStr::from("-1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 0i64"#, RocStr::from("0"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 1i64"#, RocStr::from("1"), RocStr);
|
||||||
|
assert_evals_to!(r#"Num.toStr 10i64"#, RocStr::from("10"), RocStr);
|
||||||
|
|
||||||
|
let max = format!("{}", i64::MAX);
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"Num.toStr Num.maxI64"#,
|
||||||
|
RocStr::from(max.as_str()),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
|
||||||
|
let max = format!("{}", i64::MIN);
|
||||||
|
assert_evals_to!(
|
||||||
|
r#"Num.toStr Num.minI64"#,
|
||||||
|
RocStr::from(max.as_str()),
|
||||||
|
RocStr
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
|
||||||
fn u8_addition_greater_than_i8() {
|
fn u8_addition_greater_than_i8() {
|
||||||
|
|
|
@ -3266,7 +3266,9 @@ fn box_and_unbox_string() {
|
||||||
assert_evals_to!(
|
assert_evals_to!(
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
Box.unbox (Box.box (Str.concat "Leverage " "agile frameworks to provide a robust synopsis for high level overviews"))
|
Str.concat "Leverage " "agile frameworks to provide a robust synopsis for high level overviews"
|
||||||
|
|> Box.box
|
||||||
|
|> Box.unbox
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
RocStr::from(
|
RocStr::from(
|
||||||
|
@ -3312,6 +3314,7 @@ fn box_and_unbox_tag_union() {
|
||||||
r#"
|
r#"
|
||||||
v : [ A U8, B U8 ] # usually stack allocated
|
v : [ A U8, B U8 ] # usually stack allocated
|
||||||
v = B 27u8
|
v = B 27u8
|
||||||
|
|
||||||
Box.unbox (Box.box v)
|
Box.unbox (Box.box v)
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
// we actually want to compare against the literal float bits
|
// we actually want to compare against the literal float bits
|
||||||
#![allow(clippy::float_cmp)]
|
#![allow(clippy::float_cmp)]
|
||||||
|
|
||||||
|
pub mod gen_abilities;
|
||||||
pub mod gen_compare;
|
pub mod gen_compare;
|
||||||
pub mod gen_dict;
|
pub mod gen_dict;
|
||||||
pub mod gen_list;
|
pub mod gen_list;
|
||||||
|
|
7
compiler/test_mono/generated/specialize_ability_call.txt
Normal file
7
compiler/test_mono/generated/specialize_ability_call.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
procedure Test.5 (Test.8):
|
||||||
|
ret Test.8;
|
||||||
|
|
||||||
|
procedure Test.0 ():
|
||||||
|
let Test.10 : U64 = 1234i64;
|
||||||
|
let Test.9 : U64 = CallByName Test.5 Test.10;
|
||||||
|
ret Test.9;
|
|
@ -1294,6 +1294,25 @@ fn issue_2811() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[mono_test]
|
||||||
|
fn specialize_ability_call() {
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
app "test" provides [ main ] to "./platform"
|
||||||
|
|
||||||
|
Hash has
|
||||||
|
hash : a -> U64 | a has Hash
|
||||||
|
|
||||||
|
Id := U64
|
||||||
|
|
||||||
|
hash : Id -> U64
|
||||||
|
hash = \$Id n -> n
|
||||||
|
|
||||||
|
main = hash ($Id 1234)
|
||||||
|
"#
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
// #[ignore]
|
// #[ignore]
|
||||||
// #[mono_test]
|
// #[mono_test]
|
||||||
// fn static_str_closure() {
|
// fn static_str_closure() {
|
||||||
|
|
|
@ -11,7 +11,6 @@ const NUM_BUILTIN_IMPORTS: usize = 8;
|
||||||
|
|
||||||
/// These can be shared between definitions, they will get instantiated when converted to Type
|
/// These can be shared between definitions, they will get instantiated when converted to Type
|
||||||
const TVAR1: VarId = VarId::from_u32(1);
|
const TVAR1: VarId = VarId::from_u32(1);
|
||||||
const TVAR2: VarId = VarId::from_u32(2);
|
|
||||||
|
|
||||||
pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
|
pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
|
||||||
let mut aliases = HashMap::with_capacity_and_hasher(NUM_BUILTIN_IMPORTS, default_hasher());
|
let mut aliases = HashMap::with_capacity_and_hasher(NUM_BUILTIN_IMPORTS, default_hasher());
|
||||||
|
@ -319,19 +318,6 @@ pub fn aliases() -> MutMap<Symbol, BuiltinAlias> {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// Result ok err : [ Ok ok, Err err ]
|
|
||||||
add_alias(
|
|
||||||
Symbol::RESULT_RESULT,
|
|
||||||
BuiltinAlias {
|
|
||||||
region: Region::zero(),
|
|
||||||
vars: vec![
|
|
||||||
Loc::at(Region::zero(), "ok".into()),
|
|
||||||
Loc::at(Region::zero(), "err".into()),
|
|
||||||
],
|
|
||||||
typ: result_alias_content(flex(TVAR1), flex(TVAR2)),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
// Utf8ByteProblem : [ InvalidStartByte, UnexpectedEndOfSequence, ExpectedContinuation, OverlongEncoding, CodepointTooLarge, EncodesSurrogateHalf ]
|
// Utf8ByteProblem : [ InvalidStartByte, UnexpectedEndOfSequence, ExpectedContinuation, OverlongEncoding, CodepointTooLarge, EncodesSurrogateHalf ]
|
||||||
add_alias(
|
add_alias(
|
||||||
Symbol::STR_UT8_BYTE_PROBLEM,
|
Symbol::STR_UT8_BYTE_PROBLEM,
|
||||||
|
|
|
@ -387,7 +387,15 @@ fn write_content<'a>(
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Symbol::NUM_FLOATINGPOINT => buf.push_str("F64"),
|
Symbol::NUM_FLOATINGPOINT => write_float(
|
||||||
|
env,
|
||||||
|
ctx,
|
||||||
|
get_single_arg(subs, &args),
|
||||||
|
subs,
|
||||||
|
buf,
|
||||||
|
parens,
|
||||||
|
write_parens,
|
||||||
|
),
|
||||||
|
|
||||||
_ => write_parens!(write_parens, buf, {
|
_ => write_parens!(write_parens, buf, {
|
||||||
buf.push_str("Num ");
|
buf.push_str("Num ");
|
||||||
|
@ -408,26 +416,15 @@ fn write_content<'a>(
|
||||||
write_integer(env, ctx, content, subs, buf, parens, write_parens)
|
write_integer(env, ctx, content, subs, buf, parens, write_parens)
|
||||||
}
|
}
|
||||||
|
|
||||||
Symbol::NUM_FLOAT => {
|
Symbol::NUM_FLOAT => write_float(
|
||||||
debug_assert_eq!(args.len(), 1);
|
env,
|
||||||
|
ctx,
|
||||||
let arg_var_index = args
|
get_single_arg(subs, args),
|
||||||
.into_iter()
|
subs,
|
||||||
.next()
|
buf,
|
||||||
.expect("Num was not applied to a type argument!");
|
parens,
|
||||||
let arg_var = subs[arg_var_index];
|
write_parens,
|
||||||
let content = subs.get_content_without_compacting(arg_var);
|
),
|
||||||
|
|
||||||
match content {
|
|
||||||
Alias(Symbol::NUM_BINARY32, _, _, _) => buf.push_str("F32"),
|
|
||||||
Alias(Symbol::NUM_BINARY64, _, _, _) => buf.push_str("F64"),
|
|
||||||
Alias(Symbol::NUM_DECIMAL, _, _, _) => buf.push_str("Dec"),
|
|
||||||
_ => write_parens!(write_parens, buf, {
|
|
||||||
buf.push_str("Float ");
|
|
||||||
write_content(env, ctx, content, subs, buf, parens);
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_ => write_parens!(write_parens, buf, {
|
_ => write_parens!(write_parens, buf, {
|
||||||
write_symbol(env, *symbol, buf);
|
write_symbol(env, *symbol, buf);
|
||||||
|
@ -467,6 +464,27 @@ fn write_content<'a>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_float<'a>(
|
||||||
|
env: &Env,
|
||||||
|
ctx: &mut Context<'a>,
|
||||||
|
content: &Content,
|
||||||
|
subs: &'a Subs,
|
||||||
|
buf: &mut String,
|
||||||
|
parens: Parens,
|
||||||
|
write_parens: bool,
|
||||||
|
) {
|
||||||
|
use crate::subs::Content::*;
|
||||||
|
match content {
|
||||||
|
Alias(Symbol::NUM_BINARY32, _, _, _) => buf.push_str("F32"),
|
||||||
|
Alias(Symbol::NUM_BINARY64, _, _, _) => buf.push_str("F64"),
|
||||||
|
Alias(Symbol::NUM_DECIMAL, _, _, _) => buf.push_str("Dec"),
|
||||||
|
_ => write_parens!(write_parens, buf, {
|
||||||
|
buf.push_str("Float ");
|
||||||
|
write_content(env, ctx, content, subs, buf, parens);
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn write_integer<'a>(
|
fn write_integer<'a>(
|
||||||
env: &Env,
|
env: &Env,
|
||||||
ctx: &mut Context<'a>,
|
ctx: &mut Context<'a>,
|
||||||
|
|
|
@ -3,6 +3,7 @@ use crate::types::{
|
||||||
name_type_var, AliasKind, ErrorType, Problem, RecordField, RecordFieldsError, TypeExt,
|
name_type_var, AliasKind, ErrorType, Problem, RecordField, RecordFieldsError, TypeExt,
|
||||||
};
|
};
|
||||||
use roc_collections::all::{ImMap, ImSet, MutSet, SendMap};
|
use roc_collections::all::{ImMap, ImSet, MutSet, SendMap};
|
||||||
|
use roc_error_macros::internal_error;
|
||||||
use roc_module::ident::{Lowercase, TagName, Uppercase};
|
use roc_module::ident::{Lowercase, TagName, Uppercase};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
@ -4551,6 +4552,13 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
||||||
// We have already marked the variable as copied, so we
|
// We have already marked the variable as copied, so we
|
||||||
// will not repeat this work or crawl this variable again.
|
// will not repeat this work or crawl this variable again.
|
||||||
match desc.content {
|
match desc.content {
|
||||||
|
Structure(Erroneous(_)) => {
|
||||||
|
// Make this into a flex var so that we don't have to copy problems across module
|
||||||
|
// boundaries - the error will be reported locally.
|
||||||
|
env.target.set(copy, make_descriptor(FlexVar(None)));
|
||||||
|
|
||||||
|
copy
|
||||||
|
}
|
||||||
Structure(flat_type) => {
|
Structure(flat_type) => {
|
||||||
let new_flat_type = match flat_type {
|
let new_flat_type = match flat_type {
|
||||||
Apply(symbol, arguments) => {
|
Apply(symbol, arguments) => {
|
||||||
|
@ -4581,7 +4589,9 @@ fn copy_import_to_help(env: &mut CopyImportEnv<'_>, max_rank: Rank, var: Variabl
|
||||||
Func(new_arguments, new_closure_var, new_ret_var)
|
Func(new_arguments, new_closure_var, new_ret_var)
|
||||||
}
|
}
|
||||||
|
|
||||||
same @ EmptyRecord | same @ EmptyTagUnion | same @ Erroneous(_) => same,
|
Erroneous(_) => internal_error!("I thought this was handled above"),
|
||||||
|
|
||||||
|
same @ EmptyRecord | same @ EmptyTagUnion => same,
|
||||||
|
|
||||||
Record(fields, ext_var) => {
|
Record(fields, ext_var) => {
|
||||||
let record_fields = {
|
let record_fields = {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use bitflags::bitflags;
|
use bitflags::bitflags;
|
||||||
use roc_error_macros::todo_abilities;
|
use roc_error_macros::{internal_error, todo_abilities};
|
||||||
use roc_module::ident::{Lowercase, TagName};
|
use roc_module::ident::{Lowercase, TagName};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_types::subs::Content::{self, *};
|
use roc_types::subs::Content::{self, *};
|
||||||
|
@ -134,14 +134,26 @@ pub struct Context {
|
||||||
pub enum Unified {
|
pub enum Unified {
|
||||||
Success {
|
Success {
|
||||||
vars: Pool,
|
vars: Pool,
|
||||||
must_implement_ability: Vec<MustImplementAbility>,
|
must_implement_ability: MustImplementConstraints,
|
||||||
},
|
},
|
||||||
Failure(Pool, ErrorType, ErrorType, DoesNotImplementAbility),
|
Failure(Pool, ErrorType, ErrorType, DoesNotImplementAbility),
|
||||||
BadType(Pool, roc_types::types::Problem),
|
BadType(Pool, roc_types::types::Problem),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Unified {
|
||||||
|
pub fn expect_success(self, err_msg: &'static str) -> (Pool, MustImplementConstraints) {
|
||||||
|
match self {
|
||||||
|
Unified::Success {
|
||||||
|
vars,
|
||||||
|
must_implement_ability,
|
||||||
|
} => (vars, must_implement_ability),
|
||||||
|
_ => internal_error!("{}", err_msg),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Specifies that `type` must implement the ability `ability`.
|
/// Specifies that `type` must implement the ability `ability`.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub struct MustImplementAbility {
|
pub struct MustImplementAbility {
|
||||||
// This only points to opaque type names currently.
|
// This only points to opaque type names currently.
|
||||||
// TODO(abilities) support structural types in general
|
// TODO(abilities) support structural types in general
|
||||||
|
@ -149,12 +161,39 @@ pub struct MustImplementAbility {
|
||||||
pub ability: Symbol,
|
pub ability: Symbol,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
|
pub struct MustImplementConstraints(Vec<MustImplementAbility>);
|
||||||
|
|
||||||
|
impl MustImplementConstraints {
|
||||||
|
pub fn push(&mut self, must_implement: MustImplementAbility) {
|
||||||
|
self.0.push(must_implement)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn extend(&mut self, other: Self) {
|
||||||
|
self.0.extend(other.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.0.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_unique(mut self) -> Vec<MustImplementAbility> {
|
||||||
|
self.0.sort();
|
||||||
|
self.0.dedup();
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn iter_for_ability(&self, ability: Symbol) -> impl Iterator<Item = &MustImplementAbility> {
|
||||||
|
self.0.iter().filter(move |mia| mia.ability == ability)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Outcome {
|
pub struct Outcome {
|
||||||
mismatches: Vec<Mismatch>,
|
mismatches: Vec<Mismatch>,
|
||||||
/// We defer these checks until the end of a solving phase.
|
/// We defer these checks until the end of a solving phase.
|
||||||
/// NOTE: this vector is almost always empty!
|
/// NOTE: this vector is almost always empty!
|
||||||
must_implement_ability: Vec<MustImplementAbility>,
|
must_implement_ability: MustImplementConstraints,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Outcome {
|
impl Outcome {
|
||||||
|
@ -235,8 +274,10 @@ pub fn unify_pool(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
#[cfg(debug_assertions)]
|
||||||
if false {
|
fn debug_print_unified_types(subs: &mut Subs, ctx: &Context, before_unified: bool) {
|
||||||
|
if std::env::var("ROC_PRINT_UNIFICATIONS").is_ok() {
|
||||||
|
let time = if before_unified { "START" } else { "END" };
|
||||||
// if true, print the types that are unified.
|
// if true, print the types that are unified.
|
||||||
//
|
//
|
||||||
// NOTE: names are generated here (when creating an error type) and that modifies names
|
// NOTE: names are generated here (when creating an error type) and that modifies names
|
||||||
|
@ -252,8 +293,11 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
||||||
let content_1 = subs.get(ctx.first).content;
|
let content_1 = subs.get(ctx.first).content;
|
||||||
let content_2 = subs.get(ctx.second).content;
|
let content_2 = subs.get(ctx.second).content;
|
||||||
let mode = if ctx.mode.is_eq() { "~" } else { "+=" };
|
let mode = if ctx.mode.is_eq() { "~" } else { "+=" };
|
||||||
println!(
|
eprintln!(
|
||||||
"{:?} {:?} {} {:?} {:?}",
|
"{}({:?}-{:?}): {:?} {:?} {} {:?} {:?}",
|
||||||
|
time,
|
||||||
|
ctx.first,
|
||||||
|
ctx.second,
|
||||||
ctx.first,
|
ctx.first,
|
||||||
roc_types::subs::SubsFmtContent(&content_1, subs),
|
roc_types::subs::SubsFmtContent(&content_1, subs),
|
||||||
mode,
|
mode,
|
||||||
|
@ -261,7 +305,13 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
||||||
roc_types::subs::SubsFmtContent(&content_2, subs),
|
roc_types::subs::SubsFmtContent(&content_2, subs),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
match &ctx.first_desc.content {
|
}
|
||||||
|
|
||||||
|
fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
debug_print_unified_types(subs, &ctx, true);
|
||||||
|
|
||||||
|
let result = match &ctx.first_desc.content {
|
||||||
FlexVar(opt_name) => unify_flex(subs, &ctx, opt_name, None, &ctx.second_desc.content),
|
FlexVar(opt_name) => unify_flex(subs, &ctx, opt_name, None, &ctx.second_desc.content),
|
||||||
FlexAbleVar(opt_name, ability) => unify_flex(
|
FlexAbleVar(opt_name, ability) => unify_flex(
|
||||||
subs,
|
subs,
|
||||||
|
@ -296,7 +346,12 @@ fn unify_context(subs: &mut Subs, pool: &mut Pool, ctx: Context) -> Outcome {
|
||||||
// Error propagates. Whatever we're comparing it to doesn't matter!
|
// Error propagates. Whatever we're comparing it to doesn't matter!
|
||||||
merge(subs, &ctx, Error)
|
merge(subs, &ctx, Error)
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
debug_print_unified_types(subs, &ctx, false);
|
||||||
|
|
||||||
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
|
@ -50,7 +50,7 @@ fn int_addition() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn float_addition() {
|
fn float_addition() {
|
||||||
expect_success("1.1 + 2", "3.1 : F64");
|
expect_success("1.1 + 2", "3.1 : Float *");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "wasm"))]
|
#[cfg(not(feature = "wasm"))]
|
||||||
|
@ -309,7 +309,7 @@ fn nested_int_list() {
|
||||||
fn nested_float_list() {
|
fn nested_float_list() {
|
||||||
expect_success(
|
expect_success(
|
||||||
r#"[ [ [ 4, 3, 2 ], [ 1, 0.0 ] ], [ [] ], [] ]"#,
|
r#"[ [ [ 4, 3, 2 ], [ 1, 0.0 ] ], [ [] ], [] ]"#,
|
||||||
r#"[ [ [ 4, 3, 2 ], [ 1, 0 ] ], [ [] ], [] ] : List (List (List F64))"#,
|
r#"[ [ [ 4, 3, 2 ], [ 1, 0 ] ], [ [] ], [] ] : List (List (List (Float *)))"#,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,7 +403,7 @@ fn list_contains() {
|
||||||
fn list_sum() {
|
fn list_sum() {
|
||||||
expect_success("List.sum []", "0 : Num *");
|
expect_success("List.sum []", "0 : Num *");
|
||||||
expect_success("List.sum [ 1, 2, 3 ]", "6 : Num *");
|
expect_success("List.sum [ 1, 2, 3 ]", "6 : Num *");
|
||||||
expect_success("List.sum [ 1.1, 2.2, 3.3 ]", "6.6 : F64");
|
expect_success("List.sum [ 1.1, 2.2, 3.3 ]", "6.6 : Float *");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "wasm"))]
|
#[cfg(not(feature = "wasm"))]
|
||||||
|
|
|
@ -1176,6 +1176,7 @@ fn to_expr_report<'b>(
|
||||||
op
|
op
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Reason::ForeignCallArg {
|
Reason::ForeignCallArg {
|
||||||
foreign_symbol,
|
foreign_symbol,
|
||||||
arg_index,
|
arg_index,
|
||||||
|
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue