Merge remote-tracking branch 'origin/trunk' into remove-old-expect-logic

This commit is contained in:
Folkert 2022-07-06 13:03:41 +02:00
commit f05274faef
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
1139 changed files with 23491 additions and 21403 deletions

View file

@ -2,7 +2,7 @@ on:
schedule:
- cron: '0 9 * * *'
name: Nightly Release Apple Silicon
name: Nightly Release macOS Apple Silicon
jobs:
test-and-build:

View file

@ -0,0 +1,52 @@
on:
schedule:
- cron: '0 9 * * 1' # 9=9am utc+0, 1=monday
name: Nightly Release macOS x86_64
env:
ZIG_VERSION: 0.9.1
LLVM_SYS_130_PREFIX: /usr/local/opt/llvm
jobs:
test-and-build:
name: Rust tests, build and package nightly release
runs-on: [macos-12]
timeout-minutes: 90
steps:
- uses: actions/checkout@v2
- name: Install zig
run: |
curl -L -o zig.tar.xz https://ziglang.org/download/${ZIG_VERSION}/zig-macos-x86_64-${ZIG_VERSION}.tar.xz && tar -xf zig.tar.xz
echo "${GITHUB_WORKSPACE}/zig-macos-x86_64-${ZIG_VERSION}" >> $GITHUB_PATH
- name: zig version
run: zig version
- name: Install LLVM
run: brew install llvm@13
- name: execute rust tests
uses: actions-rs/cargo@v1
with:
command: test
args: --locked # no --release yet until #3166 is fixed
- name: write version to file
run: ./ci/write_version.sh
- name: build release
uses: actions-rs/cargo@v1
with:
command: build
args: --release --locked
- name: package release
run: ./ci/package_release.sh roc_darwin_x86_64.tar.gz
- name: Create pre-release with test_archive.tar.gz
uses: Anton-4/deploy-nightly@1609d8dfe211b078674801113ab7a2ec2938b2a9
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # automatically provided by github actions
with:
upload_url: https://uploads.github.com/repos/rtfeldman/roc/releases/51880579/assets{?name,label}
release_id: 51880579
asset_path: ./roc_darwin_x86_64.tar.gz
asset_name: roc_nightly-macos_x86_64-$$.tar.gz # $$ inserts 6 char commit hash and date (YYYY-MM-DD)
asset_content_type: application/gzip
max_releases: 3

21
.github/workflows/stale.yml vendored Normal file
View file

@ -0,0 +1,21 @@
name: 'Close stale PRs'
on:
schedule:
- cron: '30 1 * * *'
jobs:
stale:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/stale@v5
with:
delete-branch: true
exempt-pr-labels: 'blocked'
days-before-issue-close: -1
days-before-pr-stale: 30
days-before-pr-close: 30
stale-pr-message: 'Thank you for your contribution! Sometimes PRs end up staying open for a long time without activity, which can make the list of open PRs get long and time-consuming to review. To keep things manageable for reviewers, this bot automatically closes PRs that havent had activity in 60 days. This PR hasnt had activity in 30 days, so it will be automatically closed if there is no more activity in the next 30 days. Keep in mind that PRs marked `Closed` are not deleted, so no matter what, the PR will still be right here in the repo. You can always access it and reopen it anytime you like!'
stale-pr-label: 'inactive for 30 days'
close-pr-label: 'auto-closed'

View file

@ -84,3 +84,4 @@ Drake Bennion <drake.bennion@gmail.com>
Hashi364 <49736221+Kiyoshi364@users.noreply.github.com>
Jared Forsyth <jared@jaredforsyth.com>
Patrick Kilgore <git@pck.email>
Marten/Qqwy <w-m@wmcode.nl>

1239
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,56 +1,56 @@
[workspace]
members = [
"compiler/ident",
"compiler/region",
"compiler/collections",
"compiler/exhaustive",
"compiler/module",
"compiler/parse",
"compiler/can",
"compiler/problem",
"compiler/types",
"compiler/builtins",
"compiler/constrain",
"compiler/unify",
"compiler/solve",
"compiler/late_solve",
"compiler/fmt",
"compiler/derive_key",
"compiler/mono",
"compiler/alias_analysis",
"compiler/test_mono",
"compiler/test_derive",
"compiler/load",
"compiler/load_internal",
"compiler/gen_llvm",
"compiler/gen_dev",
"compiler/gen_wasm",
"compiler/build",
"compiler/arena_pool",
"compiler/test_gen",
"compiler/roc_target",
"compiler/debug_flags",
"vendor/inkwell",
"vendor/pathfinding",
"vendor/pretty",
"bindgen",
"editor",
"ast",
"cli",
"code_markup",
"highlight",
"error_macros",
"reporting",
"repl_cli",
"repl_eval",
"repl_test",
"repl_wasm",
"test_utils",
"utils",
"docs",
"docs_cli",
"linker",
"wasi-libc-sys",
"crates/compiler/ident",
"crates/compiler/region",
"crates/compiler/collections",
"crates/compiler/exhaustive",
"crates/compiler/module",
"crates/compiler/parse",
"crates/compiler/can",
"crates/compiler/problem",
"crates/compiler/types",
"crates/compiler/builtins",
"crates/compiler/constrain",
"crates/compiler/unify",
"crates/compiler/solve",
"crates/compiler/late_solve",
"crates/compiler/fmt",
"crates/compiler/derive_key",
"crates/compiler/mono",
"crates/compiler/alias_analysis",
"crates/compiler/test_mono",
"crates/compiler/test_derive",
"crates/compiler/load",
"crates/compiler/load_internal",
"crates/compiler/gen_llvm",
"crates/compiler/gen_dev",
"crates/compiler/gen_wasm",
"crates/compiler/build",
"crates/compiler/arena_pool",
"crates/compiler/test_gen",
"crates/compiler/roc_target",
"crates/compiler/debug_flags",
"crates/vendor/inkwell",
"crates/vendor/pathfinding",
"crates/vendor/pretty",
"crates/bindgen",
"crates/editor",
"crates/ast",
"crates/cli",
"crates/code_markup",
"crates/highlight",
"crates/error_macros",
"crates/reporting",
"crates/repl_cli",
"crates/repl_eval",
"crates/repl_test",
"crates/repl_wasm",
"crates/test_utils",
"crates/utils",
"crates/docs",
"crates/docs_cli",
"crates/linker",
"crates/wasi-libc-sys",
]
exclude = [
# Examples sometimes have Rust hosts in their platforms. The compiler should ignore those.
@ -58,10 +58,10 @@ exclude = [
"ci/bench-runner",
# Ignore building these normally. They are only imported by tests.
# The tests will still correctly build them.
"cli_utils",
"compiler/test_mono_macros",
"crates/cli_utils",
"crates/compiler/test_mono_macros",
# `cargo build` would cause roc_std to be built with default features which errors on windows
"roc_std",
"crates/roc_std",
]
# Needed to be able to run `cargo run -p roc_cli --no-default-features` -
# see www/build.sh for more.

View file

@ -53,15 +53,19 @@ install-zig-llvm-valgrind-clippy-rustfmt:
copy-dirs:
FROM +install-zig-llvm-valgrind-clippy-rustfmt
COPY --dir bindgen cli cli_utils compiler docs docs_cli editor ast code_markup error_macros highlight utils test_utils reporting repl_cli repl_eval repl_test repl_wasm repl_www roc_std vendor examples linker Cargo.toml Cargo.lock version.txt www wasi-libc-sys ./
COPY --dir crates repl_www examples Cargo.toml Cargo.lock version.txt www ./
test-zig:
FROM +install-zig-llvm-valgrind-clippy-rustfmt
COPY --dir compiler/builtins/bitcode ./
COPY --dir crates/compiler/builtins/bitcode ./
RUN cd bitcode && ./run-tests.sh && ./run-wasm-tests.sh
build-rust-test:
FROM +copy-dirs
RUN echo "deb http://deb.debian.org/debian testing main contrib non-free" >> /etc/apt/sources.list # to get gcc 10.3
RUN apt -y update
RUN apt -y install gcc-10 g++-10 && rm /usr/bin/gcc && ln -s /usr/bin/gcc-10 /usr/bin/gcc # gcc-9 maybe causes segfault
RUN gcc --version
RUN --mount=type=cache,target=$SCCACHE_DIR \
cargo test --locked --release --features with_sound --workspace --no-run && sccache --show-stats
@ -80,7 +84,7 @@ check-rustfmt:
check-typos:
RUN cargo install typos-cli --version 1.0.11 # version set to prevent confusion if the version is updated automatically
COPY --dir .github ci cli cli_utils compiler docs editor examples ast code_markup highlight utils linker nightly_benches packages roc_std www *.md LEGAL_DETAILS shell.nix version.txt ./
COPY --dir .github ci crates examples nightly_benches www *.md LEGAL_DETAILS flake.nix version.txt ./
RUN typos
test-rust:
@ -91,6 +95,7 @@ test-rust:
ENV ROC_NUM_WORKERS=1
# run one of the benchmarks to make sure the host is compiled
# not pre-compiling the host can cause race conditions
RUN gcc --version
RUN echo "4" | cargo run --release examples/benchmarks/NQueens.roc
RUN --mount=type=cache,target=$SCCACHE_DIR \
cargo test --locked --release --features with_sound --workspace && sccache --show-stats
@ -102,7 +107,7 @@ test-rust:
cargo test --locked --release --package test_gen --no-default-features --features gen-wasm -- --test-threads=1 && sccache --show-stats
# repl_test: build the compiler for wasm target, then run the tests on native target
RUN --mount=type=cache,target=$SCCACHE_DIR \
repl_test/test_wasm.sh && sccache --show-stats
crates/repl_test/test_wasm.sh && sccache --show-stats
# run i386 (32-bit linux) cli tests
# NOTE: disabled until zig 0.9
# RUN echo "4" | cargo run --locked --release --features="target-x86" -- --target=x86_32 examples/benchmarks/NQueens.roc
@ -147,13 +152,13 @@ prep-bench-folder:
ENV RUSTFLAGS="-C link-arg=-fuse-ld=lld -C target-cpu=native"
ARG BENCH_SUFFIX=branch
RUN cargo criterion -V
RUN --mount=type=cache,target=$SCCACHE_DIR cd cli && cargo criterion --no-run
RUN mkdir -p bench-folder/compiler/builtins/bitcode/src
RUN --mount=type=cache,target=$SCCACHE_DIR cd crates/cli && cargo criterion --no-run
RUN mkdir -p bench-folder/crates/compiler/builtins/bitcode/src
RUN mkdir -p bench-folder/target/release/deps
RUN mkdir -p bench-folder/examples/benchmarks
RUN cp examples/benchmarks/*.roc bench-folder/examples/benchmarks/
RUN cp -r examples/benchmarks/platform bench-folder/examples/benchmarks/
RUN cp compiler/builtins/bitcode/src/str.zig bench-folder/compiler/builtins/bitcode/src
RUN cp crates/compiler/builtins/bitcode/src/str.zig bench-folder/crates/compiler/builtins/bitcode/src
RUN cp target/release/roc bench-folder/target/release
# copy the most recent time bench to bench-folder
RUN cp target/release/deps/`ls -t target/release/deps/ | grep time_bench | head -n 1` bench-folder/target/release/deps/time_bench

View file

@ -17,6 +17,7 @@ Many programs can however be compiled correctly. Check out [examples](examples)
- [Linux x86](getting_started/linux_x86.md)
- [MacOS Apple Silicon](getting_started/macos_apple_silicon.md)
- [MacOS x86](getting_started/macos_x86.md)
- [Windows](getting_started/windows.md)
- [Other](getting_started/other.md)

View file

@ -1,3 +1,3 @@
#!/usr/bin/env bash
cp target/release/roc ./roc # to be able to exclude "target" later in the tar command
tar -czvf $1 --exclude="target" --exclude="zig-cache" roc LICENSE LEGAL_DETAILS examples/hello-world compiler/builtins/bitcode/src/ roc_std
tar -czvf $1 --exclude="target" --exclude="zig-cache" roc LICENSE LEGAL_DETAILS examples/hello-world crates/compiler/builtins/bitcode/src/ crates/roc_std

View file

@ -1 +0,0 @@
../../../examples/interactive/cli-platform

View file

@ -1,120 +0,0 @@
use roc_error_macros::internal_error;
use roc_module::{
ident::{Lowercase, TagName},
symbol::Symbol,
};
use roc_types::subs::{Content, FlatType, GetSubsSlice, Subs, SubsFmtContent, Variable};
#[derive(Hash)]
pub enum FlatEncodable<'a> {
Immediate(Symbol),
Key(FlatEncodableKey<'a>),
}
#[derive(Hash, PartialEq, Eq, Debug)]
pub enum FlatEncodableKey<'a> {
List(/* takes one variable */),
Set(/* takes one variable */),
Dict(/* takes two variables */),
// Unfortunate that we must allocate here, c'est la vie
Record(Vec<&'a Lowercase>),
TagUnion(Vec<(&'a TagName, u16)>),
}
macro_rules! unexpected {
($subs:expr, $var:expr) => {
internal_error!(
"Invalid content for toEncoder: {:?}",
SubsFmtContent($subs.get_content_without_compacting($var), $subs)
)
};
}
impl FlatEncodable<'_> {
pub(crate) fn from_var(subs: &Subs, var: Variable) -> FlatEncodable {
use FlatEncodable::*;
match *subs.get_content_without_compacting(var) {
Content::Structure(flat_type) => match flat_type {
FlatType::Apply(sym, _) => match sym {
Symbol::LIST_LIST => Key(FlatEncodableKey::List()),
Symbol::SET_SET => Key(FlatEncodableKey::Set()),
Symbol::DICT_DICT => Key(FlatEncodableKey::Dict()),
Symbol::STR_STR => Immediate(Symbol::ENCODE_STRING),
_ => unexpected!(subs, var),
},
FlatType::Record(fields, ext) => {
debug_assert!(matches!(
subs.get_content_without_compacting(ext),
Content::Structure(FlatType::EmptyRecord)
));
let mut field_names: Vec<_> =
subs.get_subs_slice(fields.field_names()).iter().collect();
field_names.sort();
Key(FlatEncodableKey::Record(field_names))
}
FlatType::TagUnion(tags, ext) | FlatType::RecursiveTagUnion(_, tags, ext) => {
// The recursion var doesn't matter, because the derived implementation will only
// look on the surface of the tag union type, and more over the payloads of the
// arguments will be left generic for the monomorphizer to fill in with the
// appropriate type. That is,
// [ A t1, B t1 t2 ]
// and
// [ A t1, B t1 t2 ] as R
// look the same on the surface, because `R` is only somewhere inside of the
// `t`-prefixed payload types.
debug_assert!(matches!(
subs.get_content_without_compacting(ext),
Content::Structure(FlatType::EmptyTagUnion)
));
let mut tag_names_and_payload_sizes: Vec<_> = tags
.iter_all()
.map(|(name_index, payload_slice_index)| {
let payload_slice = subs[payload_slice_index];
let payload_size = payload_slice.length;
let name = &subs[name_index];
(name, payload_size)
})
.collect();
tag_names_and_payload_sizes.sort_by_key(|t| t.0);
Key(FlatEncodableKey::TagUnion(tag_names_and_payload_sizes))
}
FlatType::FunctionOrTagUnion(name_index, _, _) => {
Key(FlatEncodableKey::TagUnion(vec![(&subs[name_index], 0)]))
}
FlatType::EmptyRecord => Key(FlatEncodableKey::Record(vec![])),
FlatType::EmptyTagUnion => Key(FlatEncodableKey::TagUnion(vec![])),
//
FlatType::Erroneous(_) => unexpected!(subs, var),
FlatType::Func(..) => unexpected!(subs, var),
},
Content::Alias(sym, _, real_var, _) => match sym {
Symbol::NUM_U8 => Immediate(Symbol::ENCODE_U8),
Symbol::NUM_U16 => Immediate(Symbol::ENCODE_U16),
Symbol::NUM_U32 => Immediate(Symbol::ENCODE_U32),
Symbol::NUM_U64 => Immediate(Symbol::ENCODE_U64),
Symbol::NUM_U128 => Immediate(Symbol::ENCODE_U128),
Symbol::NUM_I8 => Immediate(Symbol::ENCODE_I8),
Symbol::NUM_I16 => Immediate(Symbol::ENCODE_I16),
Symbol::NUM_I32 => Immediate(Symbol::ENCODE_I32),
Symbol::NUM_I64 => Immediate(Symbol::ENCODE_I64),
Symbol::NUM_I128 => Immediate(Symbol::ENCODE_I128),
Symbol::NUM_DEC => Immediate(Symbol::ENCODE_DEC),
Symbol::NUM_F32 => Immediate(Symbol::ENCODE_F32),
Symbol::NUM_F64 => Immediate(Symbol::ENCODE_F64),
// TODO: I believe it is okay to unwrap opaques here because derivers are only used
// by the backend, and the backend treats opaques like structural aliases.
_ => Self::from_var(subs, real_var),
},
Content::RangedNumber(real_var, _) => Self::from_var(subs, real_var),
//
Content::RecursionVar { .. } => unexpected!(subs, var),
Content::Error => unexpected!(subs, var),
Content::FlexVar(_)
| Content::RigidVar(_)
| Content::FlexAbleVar(_, _)
| Content::RigidAbleVar(_, _) => unexpected!(subs, var),
Content::LambdaSet(_) => unexpected!(subs, var),
}
}
}

View file

@ -1,63 +0,0 @@
//! To avoid duplicating derived implementations for the same type, derived implementations are
//! addressed by a key of their type content. However, different derived implementations can be
//! reused based on different properties of the type. For example:
//!
//! - `Eq` does not care about surface type representations; its derived implementations can be
//! uniquely addressed by the [`Layout`][crate::layout::Layout] of a type.
//! - `Encoding` must care about surface type representations; for example, `{ a: "" }` and
//! `{ b: "" }` have different derived implementations. However, it does not need to distinguish
//! between e.g. required and optional record fields.
//! - `Decoding` is like encoding, but has some differences. For one, it *does* need to distinguish
//! between required and optional record fields.
//!
//! For these reasons the content keying is based on a [`Strategy`] as well.
pub mod encoding;
use encoding::{FlatEncodable, FlatEncodableKey};
use roc_module::symbol::Symbol;
use roc_types::subs::{Subs, Variable};
#[derive(Hash, PartialEq, Eq, Debug)]
#[repr(u8)]
enum Strategy {
Encoding,
#[allow(unused)]
Decoding,
}
#[derive(Hash, PartialEq, Eq, Debug)]
pub enum Derived<R>
where
R: std::hash::Hash + PartialEq + Eq + std::fmt::Debug,
{
/// If a derived implementation name is well-known ahead-of-time, we can inline the symbol
/// directly rather than associating a key for an implementation to be made later on.
Immediate(Symbol),
/// Key of the derived implementation to use. This allows association of derived implementation
/// names to a key, when the key is known ahead-of-time but the implementation (and it's name)
/// is yet-to-be-made.
Key(DeriveKey<R>),
}
#[derive(Hash, PartialEq, Eq, Debug)]
pub struct DeriveKey<R>
where
R: std::hash::Hash + PartialEq + Eq + std::fmt::Debug,
{
strategy: Strategy,
pub repr: R,
}
impl<'a> Derived<FlatEncodableKey<'a>> {
pub fn encoding(subs: &'a Subs, var: Variable) -> Self {
match encoding::FlatEncodable::from_var(subs, var) {
FlatEncodable::Immediate(imm) => Derived::Immediate(imm),
FlatEncodable::Key(repr) => Derived::Key(DeriveKey {
strategy: Strategy::Encoding,
repr,
}),
}
}
}

View file

@ -1,884 +0,0 @@
#[macro_use]
extern crate indoc;
#[macro_use]
extern crate pretty_assertions;
#[macro_use]
extern crate maplit;
extern crate bumpalo;
extern crate roc_collections;
extern crate roc_load_internal;
extern crate roc_module;
mod helpers;
#[cfg(test)]
mod test_load {
use crate::helpers::fixtures_dir;
use bumpalo::Bump;
use roc_can::def::Declaration::*;
use roc_can::def::Def;
use roc_constrain::module::ExposedByModule;
use roc_load_internal::file::Threading;
use roc_load_internal::file::{LoadResult, LoadStart, LoadedModule, LoadingProblem, Phase};
use roc_module::ident::ModuleName;
use roc_module::symbol::{Interns, ModuleId};
use roc_problem::can::Problem;
use roc_region::all::LineInfo;
use roc_reporting::report::can_problem;
use roc_reporting::report::RenderTarget;
use roc_reporting::report::RocDocAllocator;
use roc_target::TargetInfo;
use roc_types::pretty_print::name_and_print_var;
use roc_types::pretty_print::DebugPrint;
use roc_types::subs::Subs;
use std::collections::HashMap;
use std::path::{Path, PathBuf};
fn load_and_typecheck<'a>(
arena: &'a Bump,
filename: PathBuf,
src_dir: &Path,
exposed_types: ExposedByModule,
target_info: TargetInfo,
) -> Result<LoadedModule, LoadingProblem<'a>> {
use LoadResult::*;
let load_start = LoadStart::from_path(arena, filename, RenderTarget::Generic)?;
match roc_load_internal::file::load(
arena,
load_start,
src_dir,
exposed_types,
Phase::SolveTypes,
target_info,
Default::default(), // these tests will re-compile the builtins
RenderTarget::Generic,
Threading::Single,
)? {
Monomorphized(_) => unreachable!(""),
TypeChecked(module) => Ok(module),
}
}
const TARGET_INFO: roc_target::TargetInfo = roc_target::TargetInfo::default_x86_64();
// HELPERS
fn format_can_problems(
problems: Vec<Problem>,
home: ModuleId,
interns: &Interns,
filename: PathBuf,
src: &str,
) -> String {
use ven_pretty::DocAllocator;
let src_lines: Vec<&str> = src.split('\n').collect();
let lines = LineInfo::new(src);
let alloc = RocDocAllocator::new(&src_lines, home, interns);
let reports = problems
.into_iter()
.map(|problem| can_problem(&alloc, &lines, filename.clone(), problem).pretty(&alloc));
let mut buf = String::new();
alloc
.stack(reports)
.append(alloc.line())
.1
.render_raw(70, &mut roc_reporting::report::CiWrite::new(&mut buf))
.unwrap();
buf
}
fn multiple_modules(subdir: &str, files: Vec<(&str, &str)>) -> Result<LoadedModule, String> {
let arena = Bump::new();
let arena = &arena;
match multiple_modules_help(subdir, arena, files) {
Err(io_error) => panic!("IO trouble: {:?}", io_error),
Ok(Err(LoadingProblem::FormattedReport(buf))) => Err(buf),
Ok(Err(loading_problem)) => Err(format!("{:?}", loading_problem)),
Ok(Ok(mut loaded_module)) => {
let home = loaded_module.module_id;
let (filepath, src) = loaded_module.sources.get(&home).unwrap();
let can_problems = loaded_module.can_problems.remove(&home).unwrap_or_default();
if !can_problems.is_empty() {
return Err(format_can_problems(
can_problems,
home,
&loaded_module.interns,
filepath.clone(),
src,
));
}
assert!(loaded_module
.type_problems
.remove(&home)
.unwrap_or_default()
.is_empty(),);
Ok(loaded_module)
}
}
}
fn multiple_modules_help<'a>(
subdir: &str,
arena: &'a Bump,
mut files: Vec<(&str, &str)>,
) -> Result<Result<LoadedModule, roc_load_internal::file::LoadingProblem<'a>>, std::io::Error>
{
use std::fs::{self, File};
use std::io::Write;
let mut file_handles: Vec<_> = Vec::new();
// Use a deterministic temporary directory.
// We can't have all tests use "tmp" because tests run in parallel,
// so append the test name to the tmp path.
let tmp = format!("tmp/{}", subdir);
let dir = roc_test_utils::TmpDir::new(&tmp);
let app_module = files.pop().unwrap();
for (name, source) in files {
let mut filename = PathBuf::from(name);
filename.set_extension("roc");
let file_path = dir.path().join(filename.clone());
// Create any necessary intermediate directories (e.g. /platform)
fs::create_dir_all(file_path.parent().unwrap())?;
let mut file = File::create(file_path)?;
writeln!(file, "{}", source)?;
file_handles.push(file);
}
let result = {
let (name, source) = app_module;
let filename = PathBuf::from(name);
let file_path = dir.path().join(filename);
let full_file_path = file_path.clone();
let mut file = File::create(file_path)?;
writeln!(file, "{}", source)?;
file_handles.push(file);
load_and_typecheck(
arena,
full_file_path,
dir.path(),
Default::default(),
TARGET_INFO,
)
};
Ok(result)
}
fn load_fixture(
dir_name: &str,
module_name: &str,
subs_by_module: ExposedByModule,
) -> LoadedModule {
let src_dir = fixtures_dir().join(dir_name);
let filename = src_dir.join(format!("{}.roc", module_name));
let arena = Bump::new();
let loaded = load_and_typecheck(
&arena,
filename,
src_dir.as_path(),
subs_by_module,
TARGET_INFO,
);
let mut loaded_module = match loaded {
Ok(x) => x,
Err(roc_load_internal::file::LoadingProblem::FormattedReport(report)) => {
println!("{}", report);
panic!("{}", report);
}
Err(e) => panic!("{:?}", e),
};
let home = loaded_module.module_id;
assert_eq!(
loaded_module.can_problems.remove(&home).unwrap_or_default(),
Vec::new()
);
assert!(loaded_module
.type_problems
.remove(&home)
.unwrap_or_default()
.is_empty());
let expected_name = loaded_module
.interns
.module_ids
.get_name(loaded_module.module_id)
.expect("Test ModuleID not found in module_ids");
// App module names are hardcoded and not based on anything user-specified
if expected_name.as_str() != ModuleName::APP {
assert_eq!(&expected_name.as_str(), &module_name);
}
loaded_module
}
fn expect_def(
interns: &Interns,
subs: &mut Subs,
home: ModuleId,
def: &Def,
expected_types: &mut HashMap<&str, &str>,
) {
for (symbol, expr_var) in &def.pattern_vars {
let actual_str =
name_and_print_var(*expr_var, subs, home, interns, DebugPrint::NOTHING);
let fully_qualified = symbol.fully_qualified(interns, home).to_string();
let expected_type = expected_types
.remove(fully_qualified.as_str())
.unwrap_or_else(|| {
panic!("Defs included an unexpected symbol: {:?}", fully_qualified)
});
assert_eq!((&symbol, expected_type), (&symbol, actual_str.as_str()));
}
}
fn expect_types(mut loaded_module: LoadedModule, mut expected_types: HashMap<&str, &str>) {
let home = loaded_module.module_id;
let mut subs = loaded_module.solved.into_inner();
assert_eq!(
loaded_module.can_problems.remove(&home).unwrap_or_default(),
Vec::new()
);
assert!(loaded_module
.type_problems
.remove(&home)
.unwrap_or_default()
.is_empty());
for decl in loaded_module.declarations_by_id.remove(&home).unwrap() {
match decl {
Declare(def) => expect_def(
&loaded_module.interns,
&mut subs,
home,
&def,
&mut expected_types,
),
DeclareRec(defs, cycle_mark) => {
assert!(!cycle_mark.is_illegal(&subs));
for def in defs {
expect_def(
&loaded_module.interns,
&mut subs,
home,
&def,
&mut expected_types,
);
}
}
Builtin(_) => {}
cycle @ InvalidCycle(_) => {
panic!("Unexpected cyclic def in module declarations: {:?}", cycle);
}
expects @ Expects(_) => {
// at least at the moment this does not happen
panic!("Unexpected expects in module declarations: {:?}", expects);
}
};
}
assert_eq!(
expected_types,
HashMap::default(),
"Some expected types were not found in the defs"
);
}
// TESTS
#[test]
fn import_transitive_alias() {
// this had a bug where NodeColor was HostExposed, and it's `actual_var` conflicted
// with variables in the importee
let modules = vec![
(
"RBTree",
indoc!(
r#"
interface RBTree exposes [RedBlackTree, empty] imports []
# The color of a node. Leaves are considered Black.
NodeColor : [Red, Black]
RedBlackTree k v : [Node NodeColor k v (RedBlackTree k v) (RedBlackTree k v), Empty]
# Create an empty dictionary.
empty : RedBlackTree k v
empty =
Empty
"#
),
),
(
"Main",
indoc!(
r#"
interface Other exposes [empty] imports [RBTree]
empty : RBTree.RedBlackTree I64 I64
empty = RBTree.empty
"#
),
),
];
assert!(multiple_modules("import_transitive_alias", modules).is_ok());
}
#[test]
fn interface_with_deps() {
let subs_by_module = Default::default();
let src_dir = fixtures_dir().join("interface_with_deps");
let filename = src_dir.join("Primary.roc");
let arena = Bump::new();
let loaded = load_and_typecheck(
&arena,
filename,
src_dir.as_path(),
subs_by_module,
TARGET_INFO,
);
let mut loaded_module = loaded.expect("Test module failed to load");
let home = loaded_module.module_id;
assert_eq!(
loaded_module.can_problems.remove(&home).unwrap_or_default(),
Vec::new()
);
assert!(loaded_module
.type_problems
.remove(&home)
.unwrap_or_default()
.is_empty(),);
let def_count: usize = loaded_module
.declarations_by_id
.remove(&loaded_module.module_id)
.unwrap()
.into_iter()
.map(|decl| decl.def_count())
.sum();
let expected_name = loaded_module
.interns
.module_ids
.get_name(loaded_module.module_id)
.expect("Test ModuleID not found in module_ids");
assert_eq!(expected_name.as_str(), "Primary");
assert_eq!(def_count, 10);
}
#[test]
fn load_unit() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("no_deps", "Unit", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"unit" => "Unit",
},
);
}
#[test]
fn import_alias() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "ImportAlias", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"unit" => "Dep1.Unit",
},
);
}
#[test]
fn test_load_and_typecheck() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "WithBuiltins", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"floatTest" => "F64",
"divisionFn" => "Float a, Float a -> Float a",
"x" => "Float *",
"divisionTest" => "F64",
"intTest" => "I64",
"constantNum" => "Num *",
"divisionTest" => "F64",
"divDep1ByDep2" => "Float *",
"fromDep2" => "Float *",
},
);
}
#[test]
fn iface_quicksort() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "Quicksort", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"swap" => "Nat, Nat, List a -> List a",
"partition" => "Nat, Nat, List (Num a) -> [Pair Nat (List (Num a))]",
"partitionHelp" => "Nat, Nat, List (Num a), Nat, Num a -> [Pair Nat (List (Num a))]",
"quicksort" => "List (Num a), Nat, Nat -> List (Num a)",
},
);
}
#[test]
fn quicksort_one_def() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("app_with_deps", "QuicksortOneDef", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"quicksort" => "List (Num a) -> List (Num a)",
},
);
}
#[test]
fn app_quicksort() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("app_with_deps", "Quicksort", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"swap" => "Nat, Nat, List a -> List a",
"partition" => "Nat, Nat, List (Num a) -> [Pair Nat (List (Num a))]",
"partitionHelp" => "Nat, Nat, List (Num a), Nat, Num a -> [Pair Nat (List (Num a))]",
"quicksort" => "List (Num a), Nat, Nat -> List (Num a)",
},
);
}
#[test]
fn load_astar() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "AStar", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"findPath" => "{ costFunction : position, position -> F64, end : position, moveFunction : position -> Set position, start : position } -> Result (List position) [KeyNotFound]*",
"initialModel" => "position -> Model position",
"reconstructPath" => "Dict position position, position -> List position",
"updateCost" => "position, position, Model position -> Model position",
"cheapestOpen" => "(position -> F64), Model position -> Result position [KeyNotFound]*",
"astar" => "(position, position -> F64), (position -> Set position), position, Model position -> [Err [KeyNotFound]*, Ok (List position)]*",
},
);
}
#[test]
fn load_principal_types() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("no_deps", "Principal", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"intVal" => "Str",
"identity" => "a -> a",
},
);
}
#[test]
fn iface_dep_types() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "Primary", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"blah2" => "Float *",
"blah3" => "Str",
"str" => "Str",
"alwaysThree" => "* -> Float *",
"identity" => "a -> a",
"z" => "Float *",
"w" => "Dep1.Identity {}",
"succeed" => "a -> Dep1.Identity a",
"yay" => "Res.Res {} err",
"withDefault" => "Res.Res a err, a -> a",
},
);
}
#[test]
fn app_dep_types() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("app_with_deps", "Primary", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"blah2" => "Float *",
"blah3" => "Str",
"str" => "Str",
"alwaysThree" => "* -> Float *",
"identity" => "a -> a",
"z" => "Float *",
"w" => "Dep1.Identity {}",
"succeed" => "a -> Dep1.Identity a",
"yay" => "Res.Res {} err",
"withDefault" => "Res.Res a err, a -> a",
},
);
}
#[test]
fn imported_dep_regression() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "OneDep", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"str" => "Str",
},
);
}
#[test]
fn parse_problem() {
let modules = vec![(
"Main",
indoc!(
r#"
interface Main exposes [main] imports []
main = [
"#
),
)];
match multiple_modules("parse_problem", modules) {
Err(report) => assert_eq!(
report,
indoc!(
"
UNFINISHED LIST tmp/parse_problem/Main
I cannot find the end of this list:
3 main = [
^
You could change it to something like [1, 2, 3] or even just [].
Anything where there is an open and a close square bracket, and where
the elements of the list are separated by commas.
Note: I may be confused by indentation"
)
),
Ok(_) => unreachable!("we expect failure here"),
}
}
#[test]
#[should_panic(expected = "FILE NOT FOUND")]
fn file_not_found() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("interface_with_deps", "invalid$name", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"str" => "Str",
},
);
}
#[test]
#[should_panic(expected = "FILE NOT FOUND")]
fn imported_file_not_found() {
let subs_by_module = Default::default();
let loaded_module = load_fixture("no_deps", "MissingDep", subs_by_module);
expect_types(
loaded_module,
hashmap! {
"str" => "Str",
},
);
}
#[test]
fn platform_does_not_exist() {
let modules = vec![(
"Main",
indoc!(
r#"
app "example"
packages { pf: "./zzz-does-not-exist/main.roc" }
imports []
provides [main] to pf
main = ""
"#
),
)];
match multiple_modules("platform_does_not_exist", modules) {
Err(report) => {
assert!(report.contains("FILE NOT FOUND"), "report=({})", report);
assert!(
report.contains("zzz-does-not-exist/main.roc"),
"report=({})",
report
);
}
Ok(_) => unreachable!("we expect failure here"),
}
}
#[test]
fn platform_parse_error() {
let modules = vec![
(
"platform/main.roc",
indoc!(
r#"
platform "hello-c"
requires {} { main : Str }
exposes []
packages {}
imports []
provides [mainForHost]
blah 1 2 3 # causing a parse error on purpose
mainForHost : Str
"#
),
),
(
"Main",
indoc!(
r#"
app "hello-world"
packages { pf: "platform/main.roc" }
imports []
provides [main] to pf
main = "Hello, World!\n"
"#
),
),
];
match multiple_modules("platform_parse_error", modules) {
Err(report) => {
assert!(report.contains("NOT END OF FILE"));
assert!(report.contains("blah 1 2 3 # causing a parse error on purpose"));
}
Ok(_) => unreachable!("we expect failure here"),
}
}
#[test]
// See https://github.com/rtfeldman/roc/issues/2413
fn platform_exposes_main_return_by_pointer_issue() {
let modules = vec![
(
"platform/main.roc",
indoc!(
r#"
platform "hello-world"
requires {} { main : { content: Str, other: Str } }
exposes []
packages {}
imports []
provides [mainForHost]
mainForHost : { content: Str, other: Str }
mainForHost = main
"#
),
),
(
"Main",
indoc!(
r#"
app "hello-world"
packages { pf: "platform/main.roc" }
imports []
provides [main] to pf
main = { content: "Hello, World!\n", other: "" }
"#
),
),
];
assert!(multiple_modules("platform_exposes_main_return_by_pointer_issue", modules).is_ok());
}
#[test]
fn opaque_wrapped_unwrapped_outside_defining_module() {
let modules = vec![
(
"Age",
indoc!(
r#"
interface Age exposes [Age] imports []
Age := U32
"#
),
),
(
"Main",
indoc!(
r#"
interface Main exposes [twenty, readAge] imports [Age.{ Age }]
twenty = @Age 20
readAge = \@Age n -> n
"#
),
),
];
let err = multiple_modules("opaque_wrapped_unwrapped_outside_defining_module", modules)
.unwrap_err();
assert_eq!(
err,
indoc!(
r#"
OPAQUE TYPE DECLARED OUTSIDE SCOPE ...rapped_outside_defining_module/Main
The unwrapped opaque type Age referenced here:
3 twenty = @Age 20
^^^^
is imported from another module:
1 interface Main exposes [twenty, readAge] imports [Age.{ Age }]
^^^^^^^^^^^
Note: Opaque types can only be wrapped and unwrapped in the module they are defined in!
OPAQUE TYPE DECLARED OUTSIDE SCOPE ...rapped_outside_defining_module/Main
The unwrapped opaque type Age referenced here:
5 readAge = \@Age n -> n
^^^^
is imported from another module:
1 interface Main exposes [twenty, readAge] imports [Age.{ Age }]
^^^^^^^^^^^
Note: Opaque types can only be wrapped and unwrapped in the module they are defined in!
UNUSED IMPORT tmp/opaque_wrapped_unwrapped_outside_defining_module/Main
Nothing from Age is used in this module.
1 interface Main exposes [twenty, readAge] imports [Age.{ Age }]
^^^^^^^^^^^
Since Age isn't used, you don't need to import it.
"#
),
"\n{}",
err
);
}
#[test]
fn issue_2863_module_type_does_not_exist() {
let modules = vec![
(
"platform/main.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/main.roc" }
provides [main] to pf
main : DoesNotExist
main = 1
"#
),
),
];
match multiple_modules("issue_2863_module_type_does_not_exist", modules) {
Err(report) => {
assert_eq!(
report,
indoc!(
"
UNRECOGNIZED NAME tmp/issue_2863_module_type_does_not_exist/Main
Nothing is named `DoesNotExist` in this scope.
5 main : DoesNotExist
^^^^^^^^^^^^
Did you mean one of these?
Dict
Result
List
Box
"
)
)
}
Ok(_) => unreachable!("we expect failure here"),
}
}
}

View file

@ -1,18 +0,0 @@
//! Auto-derivers of builtin ability methods.
use roc_types::subs::{Content, Descriptor, Mark, OptVariable, Rank, Subs, Variable};
pub fn synth_var(subs: &mut Subs, content: Content) -> Variable {
let descriptor = Descriptor {
content,
// NOTE: this is incorrect, but that is irrelevant - derivers may only be called during
// monomorphization (or later), at which point we do not care about variable
// generalization. Hence ranks should not matter.
rank: Rank::toplevel(),
mark: Mark::NONE,
copy: OptVariable::NONE,
};
subs.fresh(descriptor)
}
pub mod encoding;

File diff suppressed because it is too large Load diff

View file

@ -1,17 +0,0 @@
procedure Test.2 (Test.6, #Attr.12):
let Test.1 : U8 = StructAtIndex 0 #Attr.12;
let Test.11 : {U8} = Struct {Test.1};
ret Test.11;
procedure Test.4 (Test.5, #Attr.12):
let Test.1 : U8 = StructAtIndex 0 #Attr.12;
ret Test.1;
procedure Test.0 ():
let Test.1 : U8 = 1i64;
let Test.8 : {} = Struct {};
let Test.10 : {} = Struct {};
let Test.14 : {U8} = Struct {Test.1};
let Test.9 : {U8} = CallByName Test.2 Test.10 Test.14;
let Test.7 : U8 = CallByName Test.4 Test.8 Test.9;
ret Test.7;

View file

@ -1,30 +0,0 @@
procedure Test.4 (Test.30):
joinpoint Test.14 Test.5:
let Test.24 : Int1 = 1i64;
let Test.25 : Int1 = GetTagId Test.5;
let Test.26 : Int1 = lowlevel Eq Test.24 Test.25;
if Test.26 then
let Test.15 : Int1 = false;
ret Test.15;
else
let Test.20 : [C I64, C ] = UnionAtIndex (Id 0) (Index 0) Test.5;
let Test.21 : U8 = 1i64;
let Test.22 : U8 = GetTagId Test.20;
let Test.23 : Int1 = lowlevel Eq Test.21 Test.22;
if Test.23 then
let Test.16 : Int1 = true;
ret Test.16;
else
let Test.8 : [<rnu><null>, C [C I64, C ] *self] = UnionAtIndex (Id 0) (Index 1) Test.5;
jump Test.14 Test.8;
in
jump Test.14 Test.30;
procedure Test.0 ():
let Test.29 : I64 = 3i64;
let Test.27 : [C I64, C ] = Just Test.29;
let Test.28 : [<rnu><null>, C [C I64, C ] *self] = Nil ;
let Test.13 : [<rnu><null>, C [C I64, C ] *self] = Cons Test.27 Test.28;
let Test.12 : Int1 = CallByName Test.4 Test.13;
dec Test.13;
ret Test.12;

View file

@ -1,40 +0,0 @@
procedure List.9 (#Attr.2):
let List.146 : U64 = 0i64;
let List.147 : U64 = lowlevel ListLen #Attr.2;
let List.142 : Int1 = lowlevel NotEq List.146 List.147;
if List.142 then
let List.145 : U64 = 0i64;
let List.144 : I64 = lowlevel ListGetUnsafe #Attr.2 List.145;
let List.143 : [C Int1, C I64] = Ok List.144;
ret List.143;
else
let List.141 : Int1 = true;
let List.140 : [C Int1, C I64] = Err List.141;
ret List.140;
procedure Str.27 (#Attr.2):
let #Attr.3 : {I64, U8} = lowlevel StrToNum #Attr.2;
let Str.70 : U8 = StructAtIndex 1 #Attr.3;
let Str.71 : U8 = 0i64;
let Str.67 : Int1 = lowlevel NumGt Str.70 Str.71;
if Str.67 then
let Str.69 : Int1 = false;
let Str.68 : [C Int1, C I64] = Err Str.69;
ret Str.68;
else
let Str.66 : I64 = StructAtIndex 0 #Attr.3;
let Str.65 : [C Int1, C I64] = Ok Str.66;
ret Str.65;
procedure Test.0 ():
let Test.4 : Int1 = true;
if Test.4 then
let Test.6 : List I64 = Array [];
let Test.5 : [C Int1, C I64] = CallByName List.9 Test.6;
dec Test.6;
ret Test.5;
else
let Test.3 : Str = "";
let Test.2 : [C Int1, C I64] = CallByName Str.27 Test.3;
dec Test.3;
ret Test.2;

View file

@ -1,6 +0,0 @@
procedure Test.0 ():
let Test.19 : [C [<rnnu>C [C *self, C ]], C ] = SystemTool ;
let Test.17 : [<rnnu>C [C *self, C ]] = Job Test.19;
let Test.16 : [C [<rnnu>C [C *self, C ]], C ] = FromJob Test.17;
let Test.7 : [<rnnu>C [C *self, C ]] = Job Test.16;
ret Test.7;

View file

@ -1,25 +0,0 @@
procedure Num.19 (#Attr.2, #Attr.3):
let Num.274 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.274;
procedure Test.4 (Test.6):
let Test.16 : Int1 = 1i64;
let Test.17 : Int1 = GetTagId Test.6;
let Test.18 : Int1 = lowlevel Eq Test.16 Test.17;
if Test.18 then
let Test.12 : I64 = 0i64;
ret Test.12;
else
let Test.7 : [<rnu><null>, C I64 *self] = UnionAtIndex (Id 0) (Index 1) Test.6;
let Test.14 : I64 = 1i64;
let Test.15 : I64 = CallByName Test.4 Test.7;
let Test.13 : I64 = CallByName Num.19 Test.14 Test.15;
ret Test.13;
procedure Test.0 ():
let Test.3 : [<rnu><null>, C I64 *self] = Nil ;
let Test.9 : I64 = CallByName Test.4 Test.3;
let Test.10 : I64 = CallByName Test.4 Test.3;
dec Test.3;
let Test.8 : I64 = CallByName Num.19 Test.9 Test.10;
ret Test.8;

View file

@ -1,45 +0,0 @@
procedure List.3 (List.64, List.65, List.66):
let List.143 : {List I64, I64} = CallByName List.57 List.64 List.65 List.66;
let List.142 : List I64 = StructAtIndex 0 List.143;
inc List.142;
dec List.143;
ret List.142;
procedure List.57 (#Attr.2, #Attr.3, #Attr.4):
let List.148 : U64 = lowlevel ListLen #Attr.2;
let List.146 : Int1 = lowlevel NumLt #Attr.3 List.148;
if List.146 then
let List.147 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.147;
else
let List.145 : {List I64, I64} = Struct {#Attr.2, #Attr.4};
ret List.145;
procedure List.6 (#Attr.2):
let List.141 : U64 = lowlevel ListLen #Attr.2;
ret List.141;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.273 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.273;
procedure Test.1 ():
let Test.8 : List I64 = Array [1i64, 2i64, 3i64];
ret Test.8;
procedure Test.2 (Test.3):
let Test.12 : U64 = 0i64;
let Test.13 : I64 = 0i64;
let Test.11 : List I64 = CallByName List.3 Test.3 Test.12 Test.13;
ret Test.11;
procedure Test.0 ():
let Test.10 : List I64 = CallByName Test.1;
let Test.9 : List I64 = CallByName Test.2 Test.10;
let Test.5 : U64 = CallByName List.6 Test.9;
dec Test.9;
let Test.7 : List I64 = CallByName Test.1;
let Test.6 : U64 = CallByName List.6 Test.7;
dec Test.7;
let Test.4 : U64 = CallByName Num.19 Test.5 Test.6;
ret Test.4;

View file

@ -1,23 +0,0 @@
procedure List.2 (#Attr.2, #Attr.3):
let List.145 : U64 = lowlevel ListLen #Attr.2;
let List.142 : Int1 = lowlevel NumLt #Attr.3 List.145;
if List.142 then
let List.144 : I64 = lowlevel ListGetUnsafe #Attr.2 #Attr.3;
let List.143 : [C {}, C I64] = Ok List.144;
ret List.143;
else
let List.141 : {} = Struct {};
let List.140 : [C {}, C I64] = Err List.141;
ret List.140;
procedure Test.1 (Test.2):
let Test.6 : List I64 = Array [1i64, 2i64, 3i64];
let Test.7 : U64 = 0i64;
let Test.5 : [C {}, C I64] = CallByName List.2 Test.6 Test.7;
dec Test.6;
ret Test.5;
procedure Test.0 ():
let Test.4 : {} = Struct {};
let Test.3 : [C {}, C I64] = CallByName Test.1 Test.4;
ret Test.3;

View file

@ -1,27 +0,0 @@
procedure List.3 (List.64, List.65, List.66):
let List.141 : {List I64, I64} = CallByName List.57 List.64 List.65 List.66;
let List.140 : List I64 = StructAtIndex 0 List.141;
inc List.140;
dec List.141;
ret List.140;
procedure List.57 (#Attr.2, #Attr.3, #Attr.4):
let List.146 : U64 = lowlevel ListLen #Attr.2;
let List.144 : Int1 = lowlevel NumLt #Attr.3 List.146;
if List.144 then
let List.145 : {List I64, I64} = lowlevel ListReplaceUnsafe #Attr.2 #Attr.3 #Attr.4;
ret List.145;
else
let List.143 : {List I64, I64} = Struct {#Attr.2, #Attr.4};
ret List.143;
procedure Test.2 (Test.3):
let Test.6 : U64 = 0i64;
let Test.7 : I64 = 0i64;
let Test.5 : List I64 = CallByName List.3 Test.3 Test.6 Test.7;
ret Test.5;
procedure Test.0 ():
let Test.1 : List I64 = Array [1i64, 2i64, 3i64];
let Test.4 : List I64 = CallByName Test.2 Test.1;
ret Test.4;

View file

@ -1,22 +0,0 @@
procedure List.28 (#Attr.2, #Attr.3):
let List.143 : List I64 = lowlevel ListSortWith { xs: `#Attr.#arg1` } #Attr.2 Num.46 #Attr.3;
let Bool.14 : Int1 = lowlevel ListIsUnique #Attr.2;
if Bool.14 then
ret List.143;
else
decref #Attr.2;
ret List.143;
procedure List.54 (List.98):
let List.141 : {} = Struct {};
let List.140 : List I64 = CallByName List.28 List.98 List.141;
ret List.140;
procedure Num.46 (#Attr.2, #Attr.3):
let Num.273 : U8 = lowlevel NumCompare #Attr.2 #Attr.3;
ret Num.273;
procedure Test.0 ():
let Test.2 : List I64 = Array [4i64, 3i64, 2i64, 1i64];
let Test.1 : List I64 = CallByName List.54 Test.2;
ret Test.1;

View file

@ -1,21 +0,0 @@
procedure Num.19 (#Attr.2, #Attr.3):
let Num.273 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.273;
procedure Test.5 (Test.7, Test.8):
let Test.17 : U64 = 1i64;
ret Test.17;
procedure Test.6 (Test.7, Test.8):
let Test.14 : U64 = 1i64;
ret Test.14;
procedure Test.0 ():
let Test.15 : U8 = 100i64;
let Test.16 : U32 = 100i64;
let Test.10 : U64 = CallByName Test.5 Test.15 Test.16;
let Test.12 : U32 = 100i64;
let Test.13 : U8 = 100i64;
let Test.11 : U64 = CallByName Test.6 Test.12 Test.13;
let Test.9 : U64 = CallByName Num.19 Test.10 Test.11;
ret Test.9;

View file

@ -1,6 +0,0 @@
procedure Test.0 ():
let Test.11 : [<rnu><null>, C *self] = Z ;
let Test.10 : [<rnu><null>, C *self] = S Test.11;
let Test.9 : [<rnu><null>, C *self] = S Test.10;
let Test.3 : [<rnu><null>, C *self] = S Test.9;
ret Test.3;

View file

@ -1,53 +0,0 @@
procedure Num.19 (#Attr.2, #Attr.3):
let Num.274 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.274;
procedure Num.21 (#Attr.2, #Attr.3):
let Num.273 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
ret Num.273;
procedure Test.1 ():
let Test.26 : I64 = 1i64;
ret Test.26;
procedure Test.2 ():
let Test.22 : I64 = 2i64;
ret Test.22;
procedure Test.3 (Test.6):
let Test.25 : I64 = CallByName Test.1;
let Test.24 : I64 = CallByName Num.19 Test.6 Test.25;
ret Test.24;
procedure Test.4 (Test.7):
let Test.21 : I64 = CallByName Test.2;
let Test.20 : I64 = CallByName Num.21 Test.7 Test.21;
ret Test.20;
procedure Test.5 (Test.8, Test.9):
joinpoint Test.15 Test.14:
ret Test.14;
in
switch Test.8:
case 0:
let Test.16 : I64 = CallByName Test.3 Test.9;
jump Test.15 Test.16;
default:
let Test.17 : I64 = CallByName Test.4 Test.9;
jump Test.15 Test.17;
procedure Test.0 ():
joinpoint Test.19 Test.12:
let Test.13 : I64 = 42i64;
let Test.11 : I64 = CallByName Test.5 Test.12 Test.13;
ret Test.11;
in
let Test.23 : Int1 = true;
if Test.23 then
let Test.3 : Int1 = false;
jump Test.19 Test.3;
else
let Test.4 : Int1 = true;
jump Test.19 Test.4;

View file

@ -23,7 +23,7 @@ roc_reporting = { path = "../reporting" }
arrayvec = "0.7.2"
bumpalo = { version = "3.8.0", features = ["collections"] }
page_size = "0.4.2"
snafu = { version = "0.6.10", features = ["backtraces"] }
snafu = { version = "0.7.1", features = ["backtraces"] }
ven_graph = { path = "../vendor/pathfinding" }
libc = "0.2.106"

View file

@ -1,5 +1,5 @@
use crate::{
ast_error::{ASTNodeIdWithoutExprId, ASTResult},
ast_error::{ASTNodeIdWithoutExprIdSnafu, ASTResult},
mem_pool::pool::Pool,
};
@ -43,14 +43,14 @@ impl ASTNodeId {
pub fn to_expr_id(&self) -> ASTResult<ExprId> {
match self {
ASTNodeId::AExprId(expr_id) => Ok(*expr_id),
_ => ASTNodeIdWithoutExprId { ast_node_id: *self }.fail()?,
_ => ASTNodeIdWithoutExprIdSnafu { ast_node_id: *self }.fail()?,
}
}
pub fn to_def_id(&self) -> ASTResult<DefId> {
match self {
ASTNodeId::ADefId(def_id) => Ok(*def_id),
_ => ASTNodeIdWithoutExprId { ast_node_id: *self }.fail()?,
_ => ASTNodeIdWithoutExprIdSnafu { ast_node_id: *self }.fail()?,
}
}
}

View file

@ -16,7 +16,7 @@ use roc_problem::can::{MalformedPatternProblem, Problem, RuntimeError, ShadowKin
use roc_region::all::Region;
use roc_types::subs::Variable;
use crate::ast_error::{ASTResult, UnexpectedPattern2Variant};
use crate::ast_error::{ASTResult, UnexpectedPattern2VariantSnafu};
use crate::constrain::Constraint;
use crate::lang::core::expr::expr_to_expr2::to_expr_id;
use crate::lang::env::Env;
@ -517,7 +517,7 @@ pub fn symbols_from_pattern(pool: &Pool, initial: &Pattern2) -> Vec<Symbol> {
pub fn get_identifier_string(pattern: &Pattern2, interns: &Interns) -> ASTResult<String> {
match pattern {
Pattern2::Identifier(symbol) => Ok(symbol.as_str(interns).to_string()),
other => UnexpectedPattern2Variant {
other => UnexpectedPattern2VariantSnafu {
required_pattern2: "Identifier".to_string(),
encountered_pattern2: format!("{:?}", other),
}

View file

@ -3,7 +3,7 @@ use roc_module::{called_via::CalledVia, symbol::Symbol};
use roc_parse::ast::StrLiteral;
use crate::{
ast_error::{ASTResult, UnexpectedASTNode},
ast_error::{ASTResult, UnexpectedASTNodeSnafu},
lang::{
core::expr::{
expr2::{ArrString, ARR_STRING_CAPACITY},
@ -225,7 +225,7 @@ pub fn update_str_expr(
}
}
Expr2::Str(old_pool_str) => Either::OldPoolStr(*old_pool_str),
other => UnexpectedASTNode {
other => UnexpectedASTNodeSnafu {
required_node_type: "SmallStr or Str",
encountered_node_type: format!("{:?}", other),
}

View file

@ -3,7 +3,7 @@ use indexmap::IndexMap;
use roc_mono::layout::UnionLayout;
use roc_target::{Architecture, TargetInfo};
use std::convert::TryInto;
use std::fmt::Display;
use std::fmt::{Display, Write};
pub static TEMPLATE: &[u8] = include_bytes!("../templates/template.rs");
pub static HEADER: &[u8] = include_bytes!("../templates/header.rs");
@ -95,24 +95,32 @@ pub fn emit(types_and_targets: &[(Types, TargetInfo)]) -> String {
1 => {
let arch = arch_to_str(targets.get(0).unwrap().architecture);
buf.push_str(&format!("#[cfg(target_arch = \"{arch}\")]"));
write!(buf, "#[cfg(target_arch = \"{arch}\")]").unwrap();
}
_ => {
// We should never have a decl recorded with 0 targets!
debug_assert_ne!(targets.len(), 0);
let alternatives = targets
.iter()
.map(|target_info| {
format!(
let mut it = targets.iter().peekable();
writeln!(buf, "#[cfg(any(").unwrap();
while let Some(target_info) = it.next() {
write!(
buf,
"{indent}{INDENT}target_arch = \"{}\"",
arch_to_str(target_info.architecture)
)
})
.collect::<Vec<_>>()
.join(",\n");
.unwrap();
buf.push_str(&format!("#[cfg(any(\n{alternatives}\n{indent}))]"));
if it.peek().is_some() {
buf.push_str(",\n");
} else {
buf.push('\n');
}
}
write!(buf, "{indent}))]").unwrap();
}
}
@ -365,16 +373,18 @@ pub struct {name} {{
if let Some(payload_id) = opt_payload_id {
let payload_type = types.get_type(*payload_id);
buf.push_str(&format!("{INDENT}{tag_name}: "));
write!(buf, "{INDENT}{tag_name}: ").unwrap();
if payload_type.has_pointer(types) {
// types with pointers need ManuallyDrop
// because rust unions don't (and can't)
// know how to drop them automatically!
buf.push_str(&format!(
"core::mem::ManuallyDrop<{}>,\n",
writeln!(
buf,
"core::mem::ManuallyDrop<{}>,",
type_name(*payload_id, types)
));
)
.unwrap();
} else {
buf.push_str(&type_name(*payload_id, types));
buf.push_str(",\n");
@ -392,9 +402,7 @@ pub struct {name} {{
// (Do this even if theoretically shouldn't be necessary, since
// there's no runtime cost and it more explicitly syncs the
// union's size with what we think it should be.)
buf.push_str(&format!(
"{INDENT}_sizer: [u8; {size_rounded_to_alignment}],\n"
));
writeln!(buf, "{INDENT}_sizer: [u8; {size_rounded_to_alignment}],").unwrap();
}
buf.push('}');
@ -1154,9 +1162,7 @@ fn write_impl_tags<
write_indents(indentations + 1, buf);
buf.push_str(&format!(
"{discriminant_name}::{tag_name} => {branch_str}\n"
));
writeln!(buf, "{discriminant_name}::{tag_name} => {branch_str}").unwrap();
}
write_indents(indentations, buf);
@ -1192,18 +1198,18 @@ fn add_enumeration<I: ExactSizeIterator<Item = S>, S: AsRef<str> + Display>(
);
for (index, tag_name) in tags.enumerate() {
buf.push_str(&format!("{INDENT}{tag_name} = {index},\n"));
writeln!(buf, "{INDENT}{tag_name} = {index},").unwrap();
write_indents(3, &mut debug_buf);
debug_buf.push_str(&format!(
"Self::{tag_name} => f.write_str(\"{name}::{tag_name}\"),\n"
));
writeln!(
debug_buf,
"Self::{tag_name} => f.write_str(\"{name}::{tag_name}\"),"
)
.unwrap();
}
buf.push_str(&format!(
"}}\n\n{debug_buf}{INDENT}{INDENT}}}\n{INDENT}}}\n}}"
));
write!(buf, "}}\n\n{debug_buf}{INDENT}{INDENT}}}\n{INDENT}}}\n}}").unwrap();
add_decl(impls, None, target_info, buf);
}
@ -1237,7 +1243,7 @@ fn add_struct<S: Display>(
format!("{label}")
};
buf.push_str(&format!("{INDENT}pub {label}: {type_str},\n",));
writeln!(buf, "{INDENT}pub {label}: {type_str},",).unwrap();
}
buf.push('}');

View file

@ -1,9 +1,5 @@
use crate::types::{Env, Types};
use bumpalo::Bump;
use roc_can::{
def::{Declaration, Def},
pattern::Pattern,
};
use roc_load::{LoadedModule, Threading};
use roc_reporting::report::RenderTarget;
use roc_target::{Architecture, TargetInfo};
@ -27,7 +23,7 @@ pub fn load_types(
mut type_problems,
mut declarations_by_id,
mut solved,
interns,
mut interns,
..
} = roc_load::load_and_typecheck(
arena,
@ -54,50 +50,33 @@ pub fn load_types(
);
}
let defs_iter = decls.iter().flat_map(|decl| match decl {
Declaration::Declare(def) => {
vec![def.clone()]
}
Declaration::DeclareRec(defs, cycle_mark) => {
if cycle_mark.is_illegal(subs) {
Vec::new()
} else {
defs.clone()
}
}
Declaration::Builtin(..) => {
unreachable!("Builtin decl in userspace module?")
}
Declaration::InvalidCycle(..) => Vec::new(),
Declaration::Expects(..) => Vec::new(),
});
let variables = (0..decls.len()).filter_map(|index| {
use roc_can::expr::DeclarationTag::*;
let vars_iter = defs_iter.filter_map(
|Def {
loc_pattern,
pattern_vars,
..
}| {
if let Pattern::Identifier(sym) = loc_pattern.value {
let var = pattern_vars
.get(&sym)
.expect("Indetifier known but it has no var?");
Some(*var)
} else {
// figure out if we need to export non-identifier defs - when
// would that happen?
match decls.declarations[index] {
Value | Function(_) | Recursive(_) | TailRecursive(_) => Some(decls.variables[index]),
Destructure(_) => {
// figure out if we need to export non-identifier defs - when would that
// happen?
None
}
},
);
MutualRecursion { .. } => {
// handled by future iterations
None
}
Expectation => {
// not publicly visible
None
}
}
});
let types_and_targets = Architecture::iter()
.map(|arch| {
let target_info = arch.into();
let mut env = Env::new(arena, subs, &interns, target_info);
let mut env = Env::new(arena, subs, &mut interns, target_info);
(env.vars_to_types(vars_iter.clone()), target_info)
(env.vars_to_types(variables.clone()), target_info)
})
.collect();

View file

@ -419,7 +419,12 @@ pub struct Env<'a> {
}
impl<'a> Env<'a> {
pub fn new(arena: &'a Bump, subs: &'a Subs, interns: &'a Interns, target: TargetInfo) -> Self {
pub fn new(
arena: &'a Bump,
subs: &'a Subs,
interns: &'a mut Interns,
target: TargetInfo,
) -> Self {
Env {
arena,
subs,

Some files were not shown because too many files have changed in this diff Show more