mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 12:18:19 +00:00
Merge pull request #4659 from roc-lang/expect-print-values
Expect print values
This commit is contained in:
commit
f34a558c41
15 changed files with 414 additions and 78 deletions
9
.gitignore
vendored
9
.gitignore
vendored
|
@ -18,9 +18,16 @@ zig-cache
|
|||
*.ll
|
||||
*.bc
|
||||
|
||||
#valgrind
|
||||
# valgrind
|
||||
vgcore.*
|
||||
|
||||
# roc cache files
|
||||
*.rh1
|
||||
*.rm1
|
||||
preprocessedhost
|
||||
metadata
|
||||
roc-cheaty-lib.so
|
||||
|
||||
#editors
|
||||
.idea/
|
||||
.vscode/
|
||||
|
|
|
@ -15,7 +15,7 @@ mod cli_run {
|
|||
};
|
||||
use const_format::concatcp;
|
||||
use indoc::indoc;
|
||||
use roc_cli::{CMD_BUILD, CMD_CHECK, CMD_FORMAT, CMD_RUN};
|
||||
use roc_cli::{CMD_BUILD, CMD_CHECK, CMD_DEV, CMD_FORMAT, CMD_RUN, CMD_TEST};
|
||||
use roc_test_utils::assert_multiline_str_eq;
|
||||
use serial_test::serial;
|
||||
use std::iter;
|
||||
|
@ -44,6 +44,8 @@ mod cli_run {
|
|||
enum TestCliCommands {
|
||||
Many,
|
||||
Run,
|
||||
Test,
|
||||
Dev,
|
||||
}
|
||||
|
||||
const OPTIMIZE_FLAG: &str = concatcp!("--", roc_cli::FLAG_OPTIMIZE);
|
||||
|
@ -58,6 +60,8 @@ mod cli_run {
|
|||
Roc, // buildAndRunIfNoErrors
|
||||
RocBuild, // buildOnly
|
||||
RocRun, // buildAndRun
|
||||
RocTest,
|
||||
RocDev,
|
||||
}
|
||||
|
||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||
|
@ -177,11 +181,15 @@ mod cli_run {
|
|||
match test_cli_commands {
|
||||
TestCliCommands::Many => vec![CliMode::RocBuild, CliMode::RocRun],
|
||||
TestCliCommands::Run => vec![CliMode::RocRun],
|
||||
TestCliCommands::Test => vec![],
|
||||
TestCliCommands::Dev => vec![],
|
||||
}
|
||||
} else {
|
||||
match test_cli_commands {
|
||||
TestCliCommands::Many => vec![CliMode::RocBuild, CliMode::RocRun, CliMode::Roc],
|
||||
TestCliCommands::Run => vec![CliMode::Roc],
|
||||
TestCliCommands::Test => vec![CliMode::RocTest],
|
||||
TestCliCommands::Dev => vec![CliMode::RocDev],
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -270,9 +278,41 @@ mod cli_run {
|
|||
roc_app_args,
|
||||
extra_env,
|
||||
),
|
||||
CliMode::RocTest => {
|
||||
// here failure is what we expect
|
||||
|
||||
run_roc_on(
|
||||
file,
|
||||
iter::once(CMD_TEST).chain(flags.clone()),
|
||||
stdin,
|
||||
roc_app_args,
|
||||
extra_env,
|
||||
)
|
||||
}
|
||||
CliMode::RocDev => {
|
||||
// here failure is what we expect
|
||||
|
||||
run_roc_on(
|
||||
file,
|
||||
iter::once(CMD_DEV).chain(flags.clone()),
|
||||
stdin,
|
||||
roc_app_args,
|
||||
extra_env,
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
let actual = strip_colors(&out.stdout);
|
||||
let mut actual = strip_colors(&out.stdout);
|
||||
|
||||
// e.g. "1 failed and 0 passed in 123 ms."
|
||||
if let Some(split) = actual.rfind("passed in ") {
|
||||
let (before_first_digit, _) = actual.split_at(split);
|
||||
actual = format!("{}passed in <ignored for test> ms.", before_first_digit);
|
||||
}
|
||||
|
||||
let self_path = file.display().to_string();
|
||||
actual = actual.replace(&self_path, "<ignored for tests>");
|
||||
|
||||
if !actual.ends_with(expected_ending) {
|
||||
panic!(
|
||||
"expected output to end with:\n{}\nbut instead got:\n{}\n stderr was:\n{}",
|
||||
|
@ -280,7 +320,7 @@ mod cli_run {
|
|||
);
|
||||
}
|
||||
|
||||
if !out.status.success() {
|
||||
if !out.status.success() && !matches!(cli_mode, CliMode::RocTest) {
|
||||
// We don't need stdout, Cargo prints it for us.
|
||||
panic!(
|
||||
"Example program exited with status {:?}\nstderr was:\n{:#?}",
|
||||
|
@ -511,6 +551,74 @@ mod cli_run {
|
|||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(windows, ignore)]
|
||||
fn expects_dev_and_test() {
|
||||
// these are in the same test function so we don't have to worry about race conditions
|
||||
// on the building of the platform
|
||||
|
||||
test_roc_app(
|
||||
"crates/cli_testing_examples/expects",
|
||||
"expects.roc",
|
||||
"expects",
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
indoc!(
|
||||
r#"
|
||||
This expectation failed:
|
||||
|
||||
14│ expect x != x
|
||||
^^^^^^
|
||||
|
||||
When it failed, these variables had these values:
|
||||
|
||||
x : Num *
|
||||
x = 42
|
||||
|
||||
[<ignored for tests> 15:9] 42
|
||||
[<ignored for tests> 16:9] "Fjoer en ferdjer frieten oan dyn geve lea"
|
||||
Program finished!
|
||||
"#
|
||||
),
|
||||
UseValgrind::Yes,
|
||||
TestCliCommands::Dev,
|
||||
);
|
||||
|
||||
test_roc_app(
|
||||
"crates/cli_testing_examples/expects",
|
||||
"expects.roc",
|
||||
"expects",
|
||||
&[],
|
||||
&[],
|
||||
&[],
|
||||
indoc!(
|
||||
r#"
|
||||
This expectation failed:
|
||||
|
||||
6│> expect
|
||||
7│> a = 1
|
||||
8│> b = 2
|
||||
9│>
|
||||
10│> a == b
|
||||
|
||||
When it failed, these variables had these values:
|
||||
|
||||
a : Num *
|
||||
a = 1
|
||||
|
||||
b : Num *
|
||||
b = 2
|
||||
|
||||
|
||||
|
||||
1 failed and 0 passed in <ignored for test> ms."#
|
||||
),
|
||||
UseValgrind::Yes,
|
||||
TestCliCommands::Test,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg_attr(
|
||||
windows,
|
||||
|
|
17
crates/cli_testing_examples/expects/expects.roc
Normal file
17
crates/cli_testing_examples/expects/expects.roc
Normal file
|
@ -0,0 +1,17 @@
|
|||
app "expects"
|
||||
packages { pf: "zig-platform/main.roc" }
|
||||
imports []
|
||||
provides [main] to pf
|
||||
|
||||
expect
|
||||
a = 1
|
||||
b = 2
|
||||
|
||||
a == b
|
||||
|
||||
main =
|
||||
x = 42
|
||||
expect x != x
|
||||
dbg x
|
||||
dbg "Fjoer en ferdjer frieten oan dyn geve lea"
|
||||
"Program finished!\n"
|
142
crates/cli_testing_examples/expects/zig-platform/host.zig
Normal file
142
crates/cli_testing_examples/expects/zig-platform/host.zig
Normal file
|
@ -0,0 +1,142 @@
|
|||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const str = @import("str");
|
||||
const RocStr = str.RocStr;
|
||||
const testing = std.testing;
|
||||
const expectEqual = testing.expectEqual;
|
||||
const expect = testing.expect;
|
||||
|
||||
comptime {
|
||||
// This is a workaround for https://github.com/ziglang/zig/issues/8218
|
||||
// which is only necessary on macOS.
|
||||
//
|
||||
// Once that issue is fixed, we can undo the changes in
|
||||
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
|
||||
// -fcompiler-rt in link.rs instead of doing this. Note that this
|
||||
// workaround is present in many host.zig files, so make sure to undo
|
||||
// it everywhere!
|
||||
if (builtin.os.tag == .macos) {
|
||||
_ = @import("compiler_rt");
|
||||
}
|
||||
}
|
||||
|
||||
const Align = 2 * @alignOf(usize);
|
||||
extern fn malloc(size: usize) callconv(.C) ?*align(Align) anyopaque;
|
||||
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*anyopaque;
|
||||
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
|
||||
extern fn memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void;
|
||||
extern fn memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void;
|
||||
|
||||
const DEBUG: bool = false;
|
||||
|
||||
export fn roc_alloc(size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||
if (DEBUG) {
|
||||
var ptr = malloc(size);
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("alloc: {d} (alignment {d}, size {d})\n", .{ ptr, alignment, size }) catch unreachable;
|
||||
return ptr;
|
||||
} else {
|
||||
return malloc(size);
|
||||
}
|
||||
}
|
||||
|
||||
export fn roc_realloc(c_ptr: *anyopaque, new_size: usize, old_size: usize, alignment: u32) callconv(.C) ?*anyopaque {
|
||||
if (DEBUG) {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
|
||||
}
|
||||
|
||||
return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size);
|
||||
}
|
||||
|
||||
export fn roc_dealloc(c_ptr: *anyopaque, alignment: u32) callconv(.C) void {
|
||||
if (DEBUG) {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
|
||||
}
|
||||
|
||||
free(@alignCast(Align, @ptrCast([*]u8, c_ptr)));
|
||||
}
|
||||
|
||||
export fn roc_panic(c_ptr: *anyopaque, tag_id: u32) callconv(.C) void {
|
||||
_ = tag_id;
|
||||
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
const msg = @ptrCast([*:0]const u8, c_ptr);
|
||||
stderr.print("Application crashed with message\n\n {s}\n\nShutting down\n", .{msg}) catch unreachable;
|
||||
std.process.exit(0);
|
||||
}
|
||||
|
||||
export fn roc_memcpy(dst: [*]u8, src: [*]u8, size: usize) callconv(.C) void {
|
||||
return memcpy(dst, src, size);
|
||||
}
|
||||
|
||||
export fn roc_memset(dst: [*]u8, value: i32, size: usize) callconv(.C) void {
|
||||
return memset(dst, value, size);
|
||||
}
|
||||
|
||||
extern fn kill(pid: c_int, sig: c_int) c_int;
|
||||
extern fn shm_open(name: *const i8, oflag: c_int, mode: c_uint) c_int;
|
||||
extern fn mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) *anyopaque;
|
||||
extern fn getppid() c_int;
|
||||
|
||||
fn roc_getppid() callconv(.C) c_int {
|
||||
return getppid();
|
||||
}
|
||||
|
||||
fn roc_getppid_windows_stub() callconv(.C) c_int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
fn roc_send_signal(pid: c_int, sig: c_int) callconv(.C) c_int {
|
||||
return kill(pid, sig);
|
||||
}
|
||||
fn roc_shm_open(name: *const i8, oflag: c_int, mode: c_uint) callconv(.C) c_int {
|
||||
return shm_open(name, oflag, mode);
|
||||
}
|
||||
fn roc_mmap(addr: ?*anyopaque, length: c_uint, prot: c_int, flags: c_int, fd: c_int, offset: c_uint) callconv(.C) *anyopaque {
|
||||
return mmap(addr, length, prot, flags, fd, offset);
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (builtin.os.tag == .macos or builtin.os.tag == .linux) {
|
||||
@export(roc_getppid, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
@export(roc_mmap, .{ .name = "roc_mmap", .linkage = .Strong });
|
||||
@export(roc_send_signal, .{ .name = "roc_send_signal", .linkage = .Strong });
|
||||
@export(roc_shm_open, .{ .name = "roc_shm_open", .linkage = .Strong });
|
||||
}
|
||||
|
||||
if (builtin.os.tag == .windows) {
|
||||
@export(roc_getppid_windows_stub, .{ .name = "roc_getppid", .linkage = .Strong });
|
||||
}
|
||||
}
|
||||
|
||||
const mem = std.mem;
|
||||
const Allocator = mem.Allocator;
|
||||
|
||||
extern fn roc__mainForHost_1_exposed_generic(*RocStr) void;
|
||||
|
||||
const Unit = extern struct {};
|
||||
|
||||
pub fn main() u8 {
|
||||
const stdout = std.io.getStdOut().writer();
|
||||
const stderr = std.io.getStdErr().writer();
|
||||
|
||||
var timer = std.time.Timer.start() catch unreachable;
|
||||
|
||||
// actually call roc to populate the callresult
|
||||
var callresult = RocStr.empty();
|
||||
roc__mainForHost_1_exposed_generic(&callresult);
|
||||
|
||||
const nanos = timer.read();
|
||||
const seconds = (@intToFloat(f64, nanos) / 1_000_000_000.0);
|
||||
|
||||
// stdout the result
|
||||
stdout.print("{s}", .{callresult.asSlice()}) catch unreachable;
|
||||
|
||||
callresult.deinit();
|
||||
|
||||
stderr.print("runtime: {d:.3}ms\n", .{seconds * 1000}) catch unreachable;
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
platform "echo-in-zig"
|
||||
requires {} { main : Str }
|
||||
exposes []
|
||||
packages {}
|
||||
imports []
|
||||
provides [mainForHost]
|
||||
|
||||
mainForHost : Str
|
||||
mainForHost = main
|
|
@ -10,11 +10,12 @@ use roc_module::low_level::LowLevel;
|
|||
use roc_module::symbol::Symbol;
|
||||
|
||||
use roc_mono::ir::{
|
||||
Call, CallType, Expr, HigherOrderLowLevel, HostExposedLayouts, ListLiteralElement, Literal,
|
||||
ModifyRc, OptLevel, Proc, Stmt,
|
||||
Call, CallType, EntryPoint, Expr, HigherOrderLowLevel, HostExposedLayouts, ListLiteralElement,
|
||||
Literal, ModifyRc, OptLevel, Proc, ProcLayout, SingleEntryPoint, Stmt,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, CapturesNiche, Layout, RawFunctionLayout, STLayoutInterner, UnionLayout,
|
||||
Builtin, CapturesNiche, FieldOrderHash, Layout, RawFunctionLayout, STLayoutInterner,
|
||||
UnionLayout,
|
||||
};
|
||||
|
||||
// just using one module for now
|
||||
|
@ -136,7 +137,7 @@ pub fn spec_program<'a, I>(
|
|||
arena: &'a Bump,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
opt_level: OptLevel,
|
||||
opt_entry_point: Option<roc_mono::ir::EntryPoint<'a>>,
|
||||
entry_point: roc_mono::ir::EntryPoint<'a>,
|
||||
procs: I,
|
||||
) -> Result<morphic_lib::Solutions>
|
||||
where
|
||||
|
@ -226,30 +227,70 @@ where
|
|||
m.add_func(func_name, spec)?;
|
||||
}
|
||||
|
||||
if let Some(entry_point) = opt_entry_point {
|
||||
// the entry point wrapper
|
||||
let roc_main_bytes = func_name_bytes_help(
|
||||
entry_point.symbol,
|
||||
entry_point.layout.arguments.iter().copied(),
|
||||
CapturesNiche::no_niche(),
|
||||
&entry_point.layout.result,
|
||||
);
|
||||
let roc_main = FuncName(&roc_main_bytes);
|
||||
match entry_point {
|
||||
EntryPoint::Single(SingleEntryPoint {
|
||||
symbol: entry_point_symbol,
|
||||
layout: entry_point_layout,
|
||||
}) => {
|
||||
// the entry point wrapper
|
||||
let roc_main_bytes = func_name_bytes_help(
|
||||
entry_point_symbol,
|
||||
entry_point_layout.arguments.iter().copied(),
|
||||
CapturesNiche::no_niche(),
|
||||
&entry_point_layout.result,
|
||||
);
|
||||
let roc_main = FuncName(&roc_main_bytes);
|
||||
|
||||
let mut env = Env::new(arena);
|
||||
let mut env = Env::new(arena);
|
||||
|
||||
let entry_point_function = build_entry_point(
|
||||
&mut env,
|
||||
interner,
|
||||
entry_point.layout,
|
||||
roc_main,
|
||||
&host_exposed_functions,
|
||||
)?;
|
||||
let entry_point_function = build_entry_point(
|
||||
&mut env,
|
||||
interner,
|
||||
entry_point_layout,
|
||||
Some(roc_main),
|
||||
&host_exposed_functions,
|
||||
)?;
|
||||
|
||||
type_definitions.extend(env.type_names);
|
||||
type_definitions.extend(env.type_names);
|
||||
|
||||
let entry_point_name = FuncName(ENTRY_POINT_NAME);
|
||||
m.add_func(entry_point_name, entry_point_function)?;
|
||||
let entry_point_name = FuncName(ENTRY_POINT_NAME);
|
||||
m.add_func(entry_point_name, entry_point_function)?;
|
||||
}
|
||||
EntryPoint::Expects { symbols } => {
|
||||
// construct a big pattern match picking one of the expects at random
|
||||
let layout: ProcLayout<'a> = ProcLayout {
|
||||
arguments: &[],
|
||||
result: Layout::Struct {
|
||||
field_order_hash: FieldOrderHash::from_ordered_fields(&[]),
|
||||
field_layouts: &[],
|
||||
},
|
||||
captures_niche: CapturesNiche::no_niche(),
|
||||
};
|
||||
|
||||
let host_exposed: Vec<_> = symbols
|
||||
.iter()
|
||||
.map(|symbol| {
|
||||
(
|
||||
func_name_bytes_help(
|
||||
*symbol,
|
||||
[],
|
||||
CapturesNiche::no_niche(),
|
||||
&layout.result,
|
||||
),
|
||||
[].as_slice(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let mut env = Env::new(arena);
|
||||
let entry_point_function =
|
||||
build_entry_point(&mut env, interner, layout, None, &host_exposed)?;
|
||||
|
||||
type_definitions.extend(env.type_names);
|
||||
|
||||
let entry_point_name = FuncName(ENTRY_POINT_NAME);
|
||||
m.add_func(entry_point_name, entry_point_function)?;
|
||||
}
|
||||
}
|
||||
|
||||
for union_layout in type_definitions {
|
||||
|
@ -286,10 +327,11 @@ where
|
|||
let mut p = ProgramBuilder::new();
|
||||
p.add_mod(MOD_APP, main_module)?;
|
||||
|
||||
if opt_entry_point.is_some() {
|
||||
let entry_point_name = FuncName(ENTRY_POINT_NAME);
|
||||
p.add_entry_point(EntryPointName(ENTRY_POINT_NAME), MOD_APP, entry_point_name)?;
|
||||
}
|
||||
p.add_entry_point(
|
||||
EntryPointName(ENTRY_POINT_NAME),
|
||||
MOD_APP,
|
||||
FuncName(ENTRY_POINT_NAME),
|
||||
)?;
|
||||
|
||||
p.build()?
|
||||
};
|
||||
|
@ -324,7 +366,7 @@ fn build_entry_point<'a>(
|
|||
env: &mut Env<'a>,
|
||||
interner: &STLayoutInterner<'a>,
|
||||
layout: roc_mono::ir::ProcLayout<'a>,
|
||||
func_name: FuncName,
|
||||
entry_point_function: Option<FuncName>,
|
||||
host_exposed_functions: &[([u8; SIZE], &'a [Layout<'a>])],
|
||||
) -> Result<FuncDef> {
|
||||
let mut builder = FuncDefBuilder::new();
|
||||
|
@ -332,7 +374,7 @@ fn build_entry_point<'a>(
|
|||
|
||||
let mut cases = Vec::new();
|
||||
|
||||
{
|
||||
if let Some(entry_point_function) = entry_point_function {
|
||||
let block = builder.add_block();
|
||||
|
||||
// to the modelling language, the arguments appear out of thin air
|
||||
|
@ -352,7 +394,7 @@ fn build_entry_point<'a>(
|
|||
|
||||
let name_bytes = [0; 16];
|
||||
let spec_var = CalleeSpecVar(&name_bytes);
|
||||
let result = builder.add_call(block, spec_var, MOD_APP, func_name, argument)?;
|
||||
let result = builder.add_call(block, spec_var, MOD_APP, entry_point_function, argument)?;
|
||||
|
||||
// to the modelling language, the result disappears into the void
|
||||
let unit_type = builder.add_tuple_type(&[])?;
|
||||
|
@ -365,7 +407,7 @@ fn build_entry_point<'a>(
|
|||
for (name_bytes, layouts) in host_exposed_functions {
|
||||
let host_exposed_func_name = FuncName(name_bytes);
|
||||
|
||||
if host_exposed_func_name == func_name {
|
||||
if Some(host_exposed_func_name) == entry_point_function {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -392,7 +434,11 @@ fn build_entry_point<'a>(
|
|||
}
|
||||
|
||||
let unit_type = builder.add_tuple_type(&[])?;
|
||||
let unit_value = builder.add_choice(outer_block, &cases)?;
|
||||
let unit_value = if cases.is_empty() {
|
||||
builder.add_make_tuple(outer_block, &[])?
|
||||
} else {
|
||||
builder.add_choice(outer_block, &cases)?
|
||||
};
|
||||
|
||||
let root = BlockExpr(outer_block, unit_value);
|
||||
let spec = builder.build(unit_type, unit_type, root)?;
|
||||
|
|
|
@ -3,7 +3,7 @@ use roc_error_macros::internal_error;
|
|||
use roc_gen_llvm::llvm::build::{module_from_builtins, LlvmBackendMode};
|
||||
use roc_gen_llvm::llvm::externs::add_default_roc_externs;
|
||||
use roc_load::{EntryPoint, ExpectMetadata, LoadedModule, MonomorphizedModule};
|
||||
use roc_mono::ir::OptLevel;
|
||||
use roc_mono::ir::{OptLevel, SingleEntryPoint};
|
||||
use roc_reporting::cli::{report_problems, Problems};
|
||||
use std::ops::Deref;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
@ -188,18 +188,18 @@ fn gen_from_mono_module_llvm<'a>(
|
|||
// expects that would confuse the surgical linker
|
||||
add_default_roc_externs(&env);
|
||||
|
||||
let opt_entry_point = match loaded.entry_point {
|
||||
let entry_point = match loaded.entry_point {
|
||||
EntryPoint::Executable { symbol, layout, .. } => {
|
||||
Some(roc_mono::ir::EntryPoint { symbol, layout })
|
||||
roc_mono::ir::EntryPoint::Single(SingleEntryPoint { symbol, layout })
|
||||
}
|
||||
EntryPoint::Test => None,
|
||||
EntryPoint::Test => roc_mono::ir::EntryPoint::Expects { symbols: &[] },
|
||||
};
|
||||
|
||||
roc_gen_llvm::llvm::build::build_procedures(
|
||||
&env,
|
||||
opt_level,
|
||||
loaded.procedures,
|
||||
opt_entry_point,
|
||||
entry_point,
|
||||
Some(&app_ll_file),
|
||||
);
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::annotation::IntroducedVariables;
|
|||
use crate::annotation::OwnedNamedOrAble;
|
||||
use crate::derive;
|
||||
use crate::env::Env;
|
||||
use crate::expr::get_lookup_symbols;
|
||||
use crate::expr::AnnotatedMark;
|
||||
use crate::expr::ClosureData;
|
||||
use crate::expr::Declarations;
|
||||
|
@ -2414,10 +2415,12 @@ fn decl_to_let(decl: Declaration, loc_ret: Loc<Expr>) -> Loc<Expr> {
|
|||
|
||||
for ((expect_region, condition_region), condition) in it {
|
||||
let region = Region::span_across(&expect_region, &loc_ret.region);
|
||||
let lookups_in_cond = get_lookup_symbols(&condition);
|
||||
|
||||
let expr = Expr::Expect {
|
||||
loc_condition: Box::new(Loc::at(condition_region, condition)),
|
||||
loc_continuation: Box::new(loc_ret),
|
||||
lookups_in_cond: vec![],
|
||||
lookups_in_cond,
|
||||
};
|
||||
|
||||
loc_ret = Loc::at(region, expr);
|
||||
|
|
|
@ -2778,7 +2778,7 @@ pub struct DestructureDef {
|
|||
pub pattern_vars: VecMap<Symbol, Variable>,
|
||||
}
|
||||
|
||||
fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
||||
pub(crate) fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
||||
let mut stack: Vec<&Expr> = vec![expr];
|
||||
let mut lookups: Vec<ExpectLookup> = Vec::new();
|
||||
|
||||
|
@ -2840,8 +2840,16 @@ fn get_lookup_symbols(expr: &Expr) -> Vec<ExpectLookup> {
|
|||
|
||||
stack.push(&final_else.value);
|
||||
}
|
||||
Expr::LetRec(_, _, _) => todo!(),
|
||||
Expr::LetNonRec { .. } => todo!(),
|
||||
Expr::LetRec(defs, expr, _illegal_cycle_mark) => {
|
||||
for def in defs {
|
||||
stack.push(&def.loc_expr.value);
|
||||
}
|
||||
stack.push(&expr.value);
|
||||
}
|
||||
Expr::LetNonRec(def, expr) => {
|
||||
stack.push(&def.loc_expr.value);
|
||||
stack.push(&expr.value);
|
||||
}
|
||||
Expr::Call(boxed_expr, args, _called_via) => {
|
||||
stack.reserve(1 + args.len());
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ use roc_error_macros::internal_error;
|
|||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::ir::{
|
||||
BranchInfo, CallType, CrashTag, EntryPoint, JoinPointId, ListLiteralElement, ModifyRc,
|
||||
OptLevel, ProcLayout,
|
||||
OptLevel, ProcLayout, SingleEntryPoint,
|
||||
};
|
||||
use roc_mono::layout::{
|
||||
Builtin, CapturesNiche, LambdaName, LambdaSet, Layout, LayoutIds, RawFunctionLayout,
|
||||
|
@ -4170,29 +4170,23 @@ pub fn build_procedures<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
opt_level: OptLevel,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
opt_entry_point: Option<EntryPoint<'a>>,
|
||||
entry_point: EntryPoint<'a>,
|
||||
debug_output_file: Option<&Path>,
|
||||
) {
|
||||
build_procedures_help(
|
||||
env,
|
||||
opt_level,
|
||||
procedures,
|
||||
opt_entry_point,
|
||||
debug_output_file,
|
||||
);
|
||||
build_procedures_help(env, opt_level, procedures, entry_point, debug_output_file);
|
||||
}
|
||||
|
||||
pub fn build_wasm_test_wrapper<'a, 'ctx, 'env>(
|
||||
env: &Env<'a, 'ctx, 'env>,
|
||||
opt_level: OptLevel,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
entry_point: EntryPoint<'a>,
|
||||
entry_point: SingleEntryPoint<'a>,
|
||||
) -> (&'static str, FunctionValue<'ctx>) {
|
||||
let mod_solutions = build_procedures_help(
|
||||
env,
|
||||
opt_level,
|
||||
procedures,
|
||||
Some(entry_point),
|
||||
EntryPoint::Single(entry_point),
|
||||
Some(&std::env::temp_dir().join("test.ll")),
|
||||
);
|
||||
|
||||
|
@ -4203,13 +4197,13 @@ pub fn build_procedures_return_main<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
opt_level: OptLevel,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
entry_point: EntryPoint<'a>,
|
||||
entry_point: SingleEntryPoint<'a>,
|
||||
) -> (&'static str, FunctionValue<'ctx>) {
|
||||
let mod_solutions = build_procedures_help(
|
||||
env,
|
||||
opt_level,
|
||||
procedures,
|
||||
Some(entry_point),
|
||||
EntryPoint::Single(entry_point),
|
||||
Some(&std::env::temp_dir().join("test.ll")),
|
||||
);
|
||||
|
||||
|
@ -4221,13 +4215,14 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>(
|
|||
opt_level: OptLevel,
|
||||
expects: &[Symbol],
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
opt_entry_point: Option<EntryPoint<'a>>,
|
||||
) -> Vec<'a, &'a str> {
|
||||
let entry_point = EntryPoint::Expects { symbols: expects };
|
||||
|
||||
let mod_solutions = build_procedures_help(
|
||||
env,
|
||||
opt_level,
|
||||
procedures,
|
||||
opt_entry_point,
|
||||
entry_point,
|
||||
Some(&std::env::temp_dir().join("test.ll")),
|
||||
);
|
||||
|
||||
|
@ -4249,7 +4244,11 @@ pub fn build_procedures_expose_expects<'a, 'ctx, 'env>(
|
|||
let func_solutions = mod_solutions.func_solutions(func_name).unwrap();
|
||||
|
||||
let mut it = func_solutions.specs();
|
||||
let func_spec = it.next().unwrap();
|
||||
let func_spec = match it.next() {
|
||||
Some(spec) => spec,
|
||||
None => panic!("no specialization for expect {}", symbol),
|
||||
};
|
||||
|
||||
debug_assert!(
|
||||
it.next().is_none(),
|
||||
"we expect only one specialization of this symbol"
|
||||
|
@ -4289,7 +4288,7 @@ fn build_procedures_help<'a, 'ctx, 'env>(
|
|||
env: &Env<'a, 'ctx, 'env>,
|
||||
opt_level: OptLevel,
|
||||
procedures: MutMap<(Symbol, ProcLayout<'a>), roc_mono::ir::Proc<'a>>,
|
||||
opt_entry_point: Option<EntryPoint<'a>>,
|
||||
entry_point: EntryPoint<'a>,
|
||||
debug_output_file: Option<&Path>,
|
||||
) -> &'a ModSolutions {
|
||||
let mut layout_ids = roc_mono::layout::LayoutIds::default();
|
||||
|
@ -4301,7 +4300,7 @@ fn build_procedures_help<'a, 'ctx, 'env>(
|
|||
env.arena,
|
||||
env.layout_interner,
|
||||
opt_level,
|
||||
opt_entry_point,
|
||||
entry_point,
|
||||
it,
|
||||
) {
|
||||
Err(e) => panic!("Error in alias analysis: {}", e),
|
||||
|
|
|
@ -119,11 +119,17 @@ pub enum OptLevel {
|
|||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct EntryPoint<'a> {
|
||||
pub struct SingleEntryPoint<'a> {
|
||||
pub symbol: Symbol,
|
||||
pub layout: ProcLayout<'a>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum EntryPoint<'a> {
|
||||
Single(SingleEntryPoint<'a>),
|
||||
Expects { symbols: &'a [Symbol] },
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct PartialProcId(usize);
|
||||
|
||||
|
|
|
@ -106,7 +106,7 @@ pub fn helper(
|
|||
debug_assert_eq!(exposed_to_host.values.len(), 1);
|
||||
let entry_point = match loaded.entry_point {
|
||||
EntryPoint::Executable { symbol, layout, .. } => {
|
||||
roc_mono::ir::EntryPoint { symbol, layout }
|
||||
roc_mono::ir::SingleEntryPoint { symbol, layout }
|
||||
}
|
||||
EntryPoint::Test => {
|
||||
unreachable!()
|
||||
|
|
|
@ -240,7 +240,7 @@ fn create_llvm_module<'a>(
|
|||
|
||||
let entry_point = match entry_point {
|
||||
EntryPoint::Executable { symbol, layout, .. } => {
|
||||
roc_mono::ir::EntryPoint { symbol, layout }
|
||||
roc_mono::ir::SingleEntryPoint { symbol, layout }
|
||||
}
|
||||
EntryPoint::Test => {
|
||||
unreachable!()
|
||||
|
|
|
@ -235,7 +235,7 @@ fn mono_module_to_dylib<'a>(
|
|||
|
||||
let entry_point = match entry_point {
|
||||
EntryPoint::Executable { symbol, layout, .. } => {
|
||||
roc_mono::ir::EntryPoint { symbol, layout }
|
||||
roc_mono::ir::SingleEntryPoint { symbol, layout }
|
||||
}
|
||||
EntryPoint::Test => {
|
||||
unreachable!()
|
||||
|
|
|
@ -19,7 +19,7 @@ use roc_gen_llvm::{
|
|||
run_roc_dylib,
|
||||
};
|
||||
use roc_intern::{GlobalInterner, SingleThreadedInterner};
|
||||
use roc_load::{EntryPoint, Expectations, MonomorphizedModule};
|
||||
use roc_load::{Expectations, MonomorphizedModule};
|
||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||
use roc_mono::{ir::OptLevel, layout::Layout};
|
||||
use roc_region::all::Region;
|
||||
|
@ -724,7 +724,6 @@ pub fn expect_mono_module_to_dylib<'a>(
|
|||
let MonomorphizedModule {
|
||||
toplevel_expects,
|
||||
procedures,
|
||||
entry_point,
|
||||
interns,
|
||||
layout_interner,
|
||||
..
|
||||
|
@ -762,13 +761,6 @@ pub fn expect_mono_module_to_dylib<'a>(
|
|||
// platform to provide them.
|
||||
add_default_roc_externs(&env);
|
||||
|
||||
let opt_entry_point = match entry_point {
|
||||
EntryPoint::Executable { symbol, layout, .. } => {
|
||||
Some(roc_mono::ir::EntryPoint { symbol, layout })
|
||||
}
|
||||
EntryPoint::Test => None,
|
||||
};
|
||||
|
||||
let capacity = toplevel_expects.pure.len() + toplevel_expects.fx.len();
|
||||
let mut expect_symbols = BumpVec::with_capacity_in(capacity, env.arena);
|
||||
|
||||
|
@ -780,7 +772,6 @@ pub fn expect_mono_module_to_dylib<'a>(
|
|||
opt_level,
|
||||
&expect_symbols,
|
||||
procedures,
|
||||
opt_entry_point,
|
||||
);
|
||||
|
||||
let expects_fx = bumpalo::collections::Vec::from_iter_in(
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue