Merge remote-tracking branch 'origin/trunk' into update_zig_09

This commit is contained in:
Folkert 2022-05-07 22:29:43 +02:00
commit 3e141967bd
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
9 changed files with 351 additions and 225 deletions

View file

@ -85,6 +85,8 @@ indoc = "1.0.3"
serial_test = "0.5.1"
criterion = { git = "https://github.com/Anton-4/criterion.rs"}
cli_utils = { path = "../cli_utils" }
strum = "0.24.0"
strum_macros = "0.24"
# Wasmer singlepass compiler only works on x86_64.
[target.'cfg(target_arch = "x86_64")'.dev-dependencies]

View file

@ -3,16 +3,15 @@ extern crate const_format;
use build::BuiltFile;
use bumpalo::Bump;
use clap::Command;
use clap::{Arg, ArgMatches};
use clap::{Arg, ArgMatches, Command};
use roc_build::link::LinkType;
use roc_error_macros::user_error;
use roc_load::{LoadingProblem, Threading};
use roc_mono::ir::OptLevel;
use std::env;
use std::ffi::OsStr;
use std::io;
use std::path::Path;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::process;
use target_lexicon::BinaryFormat;
use target_lexicon::{
@ -96,6 +95,16 @@ pub fn build_app<'a>() -> Command<'a> {
.possible_values(["true", "false"])
.required(false);
let roc_file_to_run = Arg::new(ROC_FILE)
.help("The .roc file of an app to run")
.allow_invalid_utf8(true);
let args_for_app = Arg::new(ARGS_FOR_APP)
.help("Arguments to pass into the app being run")
.requires(ROC_FILE)
.allow_invalid_utf8(true)
.multiple_values(true);
let app = Command::new("roc")
.version(concatcp!(VERSION, "\n"))
.about("Runs the given .roc file, if there are no compilation errors.\nUse one of the SUBCOMMANDS below to do something else!")
@ -132,6 +141,7 @@ pub fn build_app<'a>() -> Command<'a> {
.arg(
Arg::new(ROC_FILE)
.help("The .roc file to build")
.allow_invalid_utf8(true)
.required(true),
)
)
@ -148,11 +158,8 @@ pub fn build_app<'a>() -> Command<'a> {
.arg(flag_linker.clone())
.arg(flag_precompiled.clone())
.arg(flag_valgrind.clone())
.arg(
Arg::new(ROC_FILE)
.help("The .roc file of an app to run")
.required(true),
)
.arg(roc_file_to_run.clone().required(true))
.arg(args_for_app.clone())
)
.subcommand(Command::new(CMD_FORMAT)
.about("Format a .roc file using standard Roc formatting")
@ -177,6 +184,7 @@ pub fn build_app<'a>() -> Command<'a> {
.arg(
Arg::new(ROC_FILE)
.help("The .roc file of an app to check")
.allow_invalid_utf8(true)
.required(true),
)
)
@ -200,17 +208,8 @@ pub fn build_app<'a>() -> Command<'a> {
.arg(flag_linker)
.arg(flag_precompiled)
.arg(flag_valgrind)
.arg(
Arg::new(ROC_FILE)
.help("The .roc file of an app to build and run")
.required(false),
)
.arg(
Arg::new(ARGS_FOR_APP)
.help("Arguments to pass into the app being run")
.requires(ROC_FILE)
.multiple_values(true),
);
.arg(roc_file_to_run.required(false))
.arg(args_for_app);
if cfg!(feature = "editor") {
app.subcommand(
@ -236,8 +235,8 @@ pub fn docs(files: Vec<PathBuf>) {
#[derive(Debug, PartialEq, Eq)]
pub enum BuildConfig {
BuildOnly,
BuildAndRun { roc_file_arg_index: usize },
BuildAndRunIfNoErrors { roc_file_arg_index: usize },
BuildAndRun,
BuildAndRunIfNoErrors,
}
pub enum FormatMode {
@ -255,7 +254,7 @@ pub fn build(
use BuildConfig::*;
let arena = Bump::new();
let filename = matches.value_of(ROC_FILE).unwrap();
let filename = matches.value_of_os(ROC_FILE).unwrap();
let original_cwd = std::env::current_dir()?;
let opt_level = match (
@ -372,7 +371,7 @@ pub fn build(
// Return a nonzero exit code if there were problems
Ok(problems.exit_code())
}
BuildAndRun { roc_file_arg_index } => {
BuildAndRun => {
if problems.errors > 0 || problems.warnings > 0 {
println!(
"\x1B[{}m{}\x1B[39m {} and \x1B[{}m{}\x1B[39m {} found in {} ms.\n\nRunning program anyway…\n\n\x1B[36m{}\x1B[39m",
@ -403,15 +402,11 @@ pub fn build(
);
}
roc_run(
arena,
&original_cwd,
triple,
roc_file_arg_index,
&binary_path,
)
let args = matches.values_of_os(ARGS_FOR_APP).unwrap_or_default();
roc_run(arena, &original_cwd, triple, args, &binary_path)
}
BuildAndRunIfNoErrors { roc_file_arg_index } => {
BuildAndRunIfNoErrors => {
if problems.errors == 0 {
if problems.warnings > 0 {
println!(
@ -427,13 +422,9 @@ pub fn build(
);
}
roc_run(
arena,
&original_cwd,
triple,
roc_file_arg_index,
&binary_path,
)
let args = matches.values_of_os(ARGS_FOR_APP).unwrap_or_default();
roc_run(arena, &original_cwd, triple, args, &binary_path)
} else {
println!(
"\x1B[{}m{}\x1B[39m {} and \x1B[{}m{}\x1B[39m {} found in {} ms.\n\nYou can run the program anyway with: \x1B[32mroc run {}\x1B[39m",
@ -460,7 +451,7 @@ pub fn build(
"warnings"
},
total_time.as_millis(),
filename
filename.to_string_lossy()
);
Ok(problems.exit_code())
@ -479,17 +470,14 @@ pub fn build(
}
}
#[cfg(target_family = "unix")]
fn roc_run(
fn roc_run<'a, I: IntoIterator<Item = &'a OsStr>>(
arena: Bump, // This should be passed an owned value, not a reference, so we can usefully mem::forget it!
cwd: &Path,
triple: Triple,
roc_file_arg_index: usize,
args: I,
binary_path: &Path,
) -> io::Result<i32> {
use std::os::unix::process::CommandExt;
let mut cmd = match triple.architecture {
match triple.architecture {
Architecture::Wasm32 => {
// If possible, report the generated executable name relative to the current dir.
let generated_filename = binary_path
@ -500,19 +488,44 @@ fn roc_run(
// since the process is about to exit anyway.
std::mem::forget(arena);
let args = std::env::args()
.skip(roc_file_arg_index)
.collect::<Vec<_>>();
if cfg!(target_family = "unix") {
use std::os::unix::ffi::OsStrExt;
run_with_wasmer(generated_filename, &args);
return Ok(0);
run_with_wasmer(
generated_filename,
args.into_iter().map(|os_str| os_str.as_bytes()),
);
} else {
run_with_wasmer(
generated_filename,
args.into_iter().map(|os_str| {
os_str.to_str().expect(
"Roc does not currently support passing non-UTF8 arguments to Wasmer.",
)
}),
);
}
Ok(0)
}
_ => {
if cfg!(target_family = "unix") {
roc_run_unix(cwd, args, binary_path)
} else {
roc_run_non_unix(arena, cwd, args, binary_path)
}
}
_ => std::process::Command::new(&binary_path),
};
if let Architecture::Wasm32 = triple.architecture {
cmd.arg(binary_path);
}
}
fn roc_run_unix<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
cwd: &Path,
args: I,
binary_path: &Path,
) -> io::Result<i32> {
use std::os::unix::process::CommandExt;
let mut cmd = std::process::Command::new(&binary_path);
// Forward all the arguments after the .roc file argument
// to the new process. This way, you can do things like:
@ -521,10 +534,8 @@ fn roc_run(
//
// ...and have it so that app.roc will receive only `foo`,
// `bar`, and `baz` as its arguments.
for (index, arg) in std::env::args().enumerate() {
if index > roc_file_arg_index {
cmd.arg(arg);
}
for arg in args {
cmd.arg(arg);
}
// This is much faster than spawning a subprocess if we're on a UNIX system!
@ -536,29 +547,36 @@ fn roc_run(
Err(err)
}
#[cfg(not(target_family = "unix"))]
fn roc_run(cmd: &mut Command) -> io::Result<i32> {
// Run the compiled app
let exit_status = cmd
.spawn()
.unwrap_or_else(|err| panic!("Failed to run app after building it: {:?}", err))
.wait()
.expect("TODO gracefully handle block_on failing when `roc` spawns a subprocess for the compiled app");
fn roc_run_non_unix<I: IntoIterator<Item = S>, S: AsRef<OsStr>>(
_arena: Bump, // This should be passed an owned value, not a reference, so we can usefully mem::forget it!
_cwd: &Path,
_args: I,
_binary_path: &Path,
) -> io::Result<i32> {
todo!("TODO support running roc programs on non-UNIX targets");
// let mut cmd = std::process::Command::new(&binary_path);
// `roc [FILE]` exits with the same status code as the app it ran.
//
// If you want to know whether there were compilation problems
// via status code, use either `roc build` or `roc check` instead!
match exit_status.code() {
Some(code) => Ok(code),
None => {
todo!("TODO gracefully handle the `roc [FILE]` subprocess terminating with a signal.");
}
}
// // Run the compiled app
// let exit_status = cmd
// .spawn()
// .unwrap_or_else(|err| panic!("Failed to run app after building it: {:?}", err))
// .wait()
// .expect("TODO gracefully handle block_on failing when `roc` spawns a subprocess for the compiled app");
// // `roc [FILE]` exits with the same status code as the app it ran.
// //
// // If you want to know whether there were compilation problems
// // via status code, use either `roc build` or `roc check` instead!
// match exit_status.code() {
// Some(code) => Ok(code),
// None => {
// todo!("TODO gracefully handle the `roc [FILE]` subprocess terminating with a signal.");
// }
// }
}
#[cfg(feature = "run-wasm32")]
fn run_with_wasmer(wasm_path: &std::path::Path, args: &[String]) {
fn run_with_wasmer<I: Iterator<Item = S>, S: AsRef<[u8]>>(wasm_path: &std::path::Path, args: I) {
use wasmer::{Instance, Module, Store};
let store = Store::default();
@ -589,8 +607,8 @@ fn run_with_wasmer(wasm_path: &std::path::Path, args: &[String]) {
}
#[cfg(not(feature = "run-wasm32"))]
fn run_with_wasmer(_wasm_path: &std::path::Path, _args: &[String]) {
println!("Running wasm files not support");
fn run_with_wasmer<I: Iterator<Item = S>, S: AsRef<[u8]>>(_wasm_path: &std::path::Path, _args: I) {
println!("Running wasm files is not supported on this target.");
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]

View file

@ -27,43 +27,31 @@ fn main() -> io::Result<()> {
let exit_code = match matches.subcommand() {
None => {
match matches.index_of(ROC_FILE) {
Some(arg_index) => {
let roc_file_arg_index = arg_index + 1; // Not sure why this +1 is necessary, but it is!
if matches.is_present(ROC_FILE) {
build(
&matches,
BuildConfig::BuildAndRunIfNoErrors,
Triple::host(),
LinkType::Executable,
)
} else {
launch_editor(None)?;
build(
&matches,
BuildConfig::BuildAndRunIfNoErrors { roc_file_arg_index },
Triple::host(),
LinkType::Executable,
)
}
None => {
launch_editor(None)?;
Ok(0)
}
Ok(0)
}
}
Some((CMD_RUN, matches)) => {
match matches.index_of(ROC_FILE) {
Some(arg_index) => {
let roc_file_arg_index = arg_index + 1; // Not sure why this +1 is necessary, but it is!
if matches.is_present(ROC_FILE) {
build(
matches,
BuildConfig::BuildAndRun,
Triple::host(),
LinkType::Executable,
)
} else {
eprintln!("What .roc file do you want to run? Specify it at the end of the `roc run` command.");
build(
matches,
BuildConfig::BuildAndRun { roc_file_arg_index },
Triple::host(),
LinkType::Executable,
)
}
None => {
eprintln!("What .roc file do you want to run? Specify it at the end of the `roc run` command.");
Ok(1)
}
Ok(1)
}
}
Some((CMD_BUILD, matches)) => {
@ -90,7 +78,7 @@ fn main() -> io::Result<()> {
let arena = bumpalo::Bump::new();
let emit_timings = matches.is_present(FLAG_TIME);
let filename = matches.value_of(ROC_FILE).unwrap();
let filename = matches.value_of_os(ROC_FILE).unwrap();
let roc_file_path = PathBuf::from(filename);
let src_dir = roc_file_path.parent().unwrap().to_owned();

View file

@ -14,10 +14,29 @@ mod cli_run {
known_bad_file, run_cmd, run_roc, run_with_valgrind, Out, ValgrindError,
ValgrindErrorXWhat,
};
use const_format::concatcp;
use indoc::indoc;
use roc_cli::{CMD_BUILD, CMD_CHECK, CMD_FORMAT, CMD_RUN};
use roc_test_utils::assert_multiline_str_eq;
use serial_test::serial;
use std::iter;
use std::path::{Path, PathBuf};
use strum::IntoEnumIterator;
use strum_macros::EnumIter;
const OPTIMIZE_FLAG: &str = concatcp!("--", roc_cli::FLAG_OPTIMIZE);
const VALGRIND_FLAG: &str = concatcp!("--", roc_cli::FLAG_VALGRIND);
const LINKER_FLAG: &str = concatcp!("--", roc_cli::FLAG_LINKER);
const CHECK_FLAG: &str = concatcp!("--", roc_cli::FLAG_CHECK);
#[allow(dead_code)]
const TARGET_FLAG: &str = concatcp!("--", roc_cli::FLAG_TARGET);
#[derive(Debug, EnumIter)]
enum CliMode {
RocBuild,
RocRun,
Roc,
}
#[cfg(not(debug_assertions))]
use roc_collections::all::MutMap;
@ -65,7 +84,7 @@ mod cli_run {
}
fn check_compile_error(file: &Path, flags: &[&str], expected: &str) {
let compile_out = run_roc(&[&["check", file.to_str().unwrap()], flags].concat());
let compile_out = run_roc([CMD_CHECK, file.to_str().unwrap()].iter().chain(flags), &[]);
let err = compile_out.stdout.trim();
let err = strip_colors(err);
@ -77,19 +96,41 @@ mod cli_run {
}
fn check_format_check_as_expected(file: &Path, expects_success_exit_code: bool) {
let flags = &["--check"];
let out = run_roc(&[&["format", file.to_str().unwrap()], &flags[..]].concat());
if expects_success_exit_code {
assert!(out.status.success());
} else {
assert!(!out.status.success());
}
let out = run_roc([CMD_FORMAT, file.to_str().unwrap(), CHECK_FLAG], &[]);
assert_eq!(out.status.success(), expects_success_exit_code);
}
fn build_example(file: &Path, flags: &[&str]) -> Out {
let compile_out = run_roc(&[&["build", file.to_str().unwrap()], flags].concat());
if !compile_out.stderr.is_empty() {
panic!("roc build had stderr: {}", compile_out.stderr);
fn run_roc_on<'a, I: IntoIterator<Item = &'a str>>(
file: &'a Path,
args: I,
stdin: &[&str],
input_file: Option<PathBuf>,
) -> Out {
let compile_out = match input_file {
Some(input_file) => run_roc(
// converting these all to String avoids lifetime issues
args.into_iter().map(|arg| arg.to_string()).chain([
file.to_str().unwrap().to_string(),
input_file.to_str().unwrap().to_string(),
]),
stdin,
),
None => run_roc(
args.into_iter().chain(iter::once(file.to_str().unwrap())),
stdin,
),
};
if !compile_out.stderr.is_empty() &&
// If there is any stderr, it should be reporting the runtime and that's it!
!(compile_out.stderr.starts_with("runtime: ")
&& compile_out.stderr.ends_with("ms\n"))
{
panic!(
"`roc` command had unexpected stderr: {}",
compile_out.stderr
);
}
assert!(compile_out.status.success(), "bad status {:?}", compile_out);
@ -106,89 +147,104 @@ mod cli_run {
expected_ending: &str,
use_valgrind: bool,
) {
let mut all_flags = vec![];
all_flags.extend_from_slice(flags);
for cli_mode in CliMode::iter() {
let flags = {
let mut vec = flags.to_vec();
if use_valgrind {
all_flags.extend_from_slice(&["--valgrind"]);
}
if use_valgrind {
vec.push(VALGRIND_FLAG);
}
build_example(file, &all_flags[..]);
let out = if use_valgrind && ALLOW_VALGRIND {
let (valgrind_out, raw_xml) = if let Some(ref input_file) = input_file {
run_with_valgrind(
stdin,
&[
file.with_file_name(executable_filename).to_str().unwrap(),
input_file.to_str().unwrap(),
],
)
} else {
run_with_valgrind(
stdin,
&[file.with_file_name(executable_filename).to_str().unwrap()],
)
vec.into_iter()
};
if valgrind_out.status.success() {
let memory_errors = extract_valgrind_errors(&raw_xml).unwrap_or_else(|err| {
panic!("failed to parse the `valgrind` xml output. Error was:\n\n{:?}\n\nvalgrind xml was: \"{}\"\n\nvalgrind stdout was: \"{}\"\n\nvalgrind stderr was: \"{}\"", err, raw_xml, valgrind_out.stdout, valgrind_out.stderr);
});
let out = match cli_mode {
CliMode::RocBuild => {
run_roc_on(file, iter::once(CMD_BUILD).chain(flags.clone()), &[], None);
if !memory_errors.is_empty() {
for error in memory_errors {
let ValgrindError {
kind,
what: _,
xwhat,
} = error;
println!("Valgrind Error: {}\n", kind);
if use_valgrind && ALLOW_VALGRIND {
let (valgrind_out, raw_xml) = if let Some(ref input_file) = input_file {
run_with_valgrind(
stdin.clone().iter().copied(),
&[
file.with_file_name(executable_filename).to_str().unwrap(),
input_file.clone().to_str().unwrap(),
],
)
} else {
run_with_valgrind(
stdin.clone().iter().copied(),
&[file.with_file_name(executable_filename).to_str().unwrap()],
)
};
if let Some(ValgrindErrorXWhat {
text,
leakedbytes: _,
leakedblocks: _,
}) = xwhat
{
println!(" {}", text);
if valgrind_out.status.success() {
let memory_errors = extract_valgrind_errors(&raw_xml).unwrap_or_else(|err| {
panic!("failed to parse the `valgrind` xml output. Error was:\n\n{:?}\n\nvalgrind xml was: \"{}\"\n\nvalgrind stdout was: \"{}\"\n\nvalgrind stderr was: \"{}\"", err, raw_xml, valgrind_out.stdout, valgrind_out.stderr);
});
if !memory_errors.is_empty() {
for error in memory_errors {
let ValgrindError {
kind,
what: _,
xwhat,
} = error;
println!("Valgrind Error: {}\n", kind);
if let Some(ValgrindErrorXWhat {
text,
leakedbytes: _,
leakedblocks: _,
}) = xwhat
{
println!(" {}", text);
}
}
panic!("Valgrind reported memory errors");
}
} else {
let exit_code = match valgrind_out.status.code() {
Some(code) => format!("exit code {}", code),
None => "no exit code".to_string(),
};
panic!("`valgrind` exited with {}. valgrind stdout was: \"{}\"\n\nvalgrind stderr was: \"{}\"", exit_code, valgrind_out.stdout, valgrind_out.stderr);
}
}
panic!(
"Valgrind reported memory errors in {:?} with flags {:?}",
file, flags
);
}
} else {
let exit_code = match valgrind_out.status.code() {
Some(code) => format!("exit code {}", code),
None => "no exit code".to_string(),
};
panic!("`valgrind` exited with {}. valgrind stdout was: \"{}\"\n\nvalgrind stderr was: \"{}\"", exit_code, valgrind_out.stdout, valgrind_out.stderr);
valgrind_out
} else if let Some(ref input_file) = input_file {
run_cmd(
file.with_file_name(executable_filename).to_str().unwrap(),
stdin.iter().copied(),
&[input_file.to_str().unwrap()],
)
} else {
run_cmd(
file.with_file_name(executable_filename).to_str().unwrap(),
stdin.iter().copied(),
&[],
)
}
}
CliMode::Roc => run_roc_on(file, flags.clone(), stdin, input_file.clone()),
CliMode::RocRun => run_roc_on(
file,
iter::once(CMD_RUN).chain(flags.clone()),
stdin,
input_file.clone(),
),
};
if !&out.stdout.ends_with(expected_ending) {
panic!(
"expected output to end with {:?} but instead got {:#?} - stderr was: {:#?}",
expected_ending, out.stdout, out.stderr
);
}
valgrind_out
} else if let Some(input_file) = input_file {
run_cmd(
file.with_file_name(executable_filename).to_str().unwrap(),
stdin,
&[input_file.to_str().unwrap()],
)
} else {
run_cmd(
file.with_file_name(executable_filename).to_str().unwrap(),
stdin,
&[],
)
};
if !&out.stdout.ends_with(expected_ending) {
panic!(
"expected output to end with {:?} but instead got {:#?} - stderr was: {:#?}",
expected_ending, out.stdout, out.stderr
);
assert!(out.status.success());
}
assert!(out.status.success());
}
#[cfg(feature = "wasm32-cli-run")]
@ -202,9 +258,13 @@ mod cli_run {
) {
assert_eq!(input_file, None, "Wasm does not support input files");
let mut flags = flags.to_vec();
flags.push("--target=wasm32");
flags.push(concatcp!(TARGET_FLAG, "=wasm32"));
let compile_out = run_roc(&[&["build", file.to_str().unwrap()], flags.as_slice()].concat());
let compile_out = run_roc(
[CMD_BUILD, file.to_str().unwrap()]
.iter()
.chain(flags.as_slice()),
);
if !compile_out.stderr.is_empty() {
panic!("{}", compile_out.stderr);
}
@ -261,7 +321,7 @@ mod cli_run {
}
"hello-gui" | "breakout" => {
// Since these require opening a window, we do `roc build` on them but don't run them.
build_example(&file_name, &["--optimize"]);
run_roc_on(&file_name, [CMD_BUILD, OPTIMIZE_FLAG], &[], None);
return;
}
@ -286,7 +346,7 @@ mod cli_run {
&file_name,
example.stdin,
example.executable_filename,
&["--optimize"],
&[OPTIMIZE_FLAG],
example.input_file.and_then(|file| Some(example_file(dir_name, file))),
example.expected_ending,
example.use_valgrind,
@ -299,7 +359,7 @@ mod cli_run {
&file_name,
example.stdin,
example.executable_filename,
&["--linker", "legacy"],
&[LINKER_FLAG, "legacy"],
example.input_file.and_then(|file| Some(example_file(dir_name, file))),
example.expected_ending,
example.use_valgrind,
@ -516,7 +576,7 @@ mod cli_run {
&file_name,
benchmark.stdin,
benchmark.executable_filename,
&["--optimize"],
&[OPTIMIZE_FLAG],
benchmark.input_file.and_then(|file| Some(examples_dir("benchmarks").join(file))),
benchmark.expected_ending,
benchmark.use_valgrind,
@ -558,7 +618,7 @@ mod cli_run {
&file_name,
benchmark.stdin,
benchmark.executable_filename,
&["--optimize"],
&[OPTIMIZE_FLAG],
benchmark.input_file.and_then(|file| Some(examples_dir("benchmarks").join(file))),
benchmark.expected_ending,
);
@ -590,7 +650,7 @@ mod cli_run {
&file_name,
benchmark.stdin,
benchmark.executable_filename,
&["--target=x86_32"],
[concatcp!(TARGET_FLAG, "=x86_32")],
benchmark.input_file.and_then(|file| Some(examples_dir("benchmarks").join(file))),
benchmark.expected_ending,
benchmark.use_valgrind,
@ -600,7 +660,7 @@ mod cli_run {
&file_name,
benchmark.stdin,
benchmark.executable_filename,
&["--target=x86_32", "--optimize"],
[concatcp!(TARGET_FLAG, "=x86_32"), OPTIMIZE_FLAG],
benchmark.input_file.and_then(|file| Some(examples_dir("benchmarks").join(file))),
benchmark.expected_ending,
benchmark.use_valgrind,
@ -819,7 +879,7 @@ mod cli_run {
&fixture_file("multi-dep-str", "Main.roc"),
&[],
"multi-dep-str",
&["--optimize"],
&[OPTIMIZE_FLAG],
None,
"I am Dep2.str2\n",
true,
@ -847,7 +907,7 @@ mod cli_run {
&fixture_file("multi-dep-thunk", "Main.roc"),
&[],
"multi-dep-thunk",
&["--optimize"],
&[OPTIMIZE_FLAG],
None,
"I am Dep2.value2\n",
true,