mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-04 20:28:02 +00:00
roc test stops if there are type errors
This commit is contained in:
parent
b5a195eaf0
commit
0a4ec1958b
2 changed files with 70 additions and 45 deletions
|
@ -360,7 +360,7 @@ pub fn test(_matches: &ArgMatches, _triple: Triple) -> io::Result<i32> {
|
|||
#[cfg(not(windows))]
|
||||
pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
|
||||
use roc_gen_llvm::llvm::build::LlvmBackendMode;
|
||||
use roc_load::{ExecutionMode, LoadConfig};
|
||||
use roc_load::{ExecutionMode, LoadConfig, LoadMonomorphizedError};
|
||||
use roc_packaging::cache;
|
||||
use roc_target::TargetInfo;
|
||||
|
||||
|
@ -425,16 +425,24 @@ pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
|
|||
threading,
|
||||
exec_mode: ExecutionMode::Test,
|
||||
};
|
||||
let loaded = roc_load::load_and_monomorphize(
|
||||
let load_result = roc_load::load_and_monomorphize(
|
||||
arena,
|
||||
path.to_path_buf(),
|
||||
subs_by_module,
|
||||
RocCacheDir::Persistent(cache::roc_cache_dir().as_path()),
|
||||
load_config,
|
||||
)
|
||||
.unwrap();
|
||||
);
|
||||
|
||||
let mut loaded = match load_result {
|
||||
Ok(loaded) => loaded,
|
||||
Err(LoadMonomorphizedError::LoadingProblem(problem)) => {
|
||||
return handle_loading_problem(problem);
|
||||
}
|
||||
Err(LoadMonomorphizedError::ErrorModule(module)) => {
|
||||
return handle_error_module(module, start_time.elapsed(), filename, false);
|
||||
}
|
||||
};
|
||||
|
||||
let mut loaded = loaded;
|
||||
let mut expectations = std::mem::take(&mut loaded.expectations);
|
||||
let loaded = loaded;
|
||||
|
||||
|
@ -733,35 +741,51 @@ pub fn build(
|
|||
}
|
||||
}
|
||||
}
|
||||
Err(BuildFileError::ErrorModule {
|
||||
mut module,
|
||||
total_time,
|
||||
}) => {
|
||||
debug_assert!(module.total_problems() > 0);
|
||||
|
||||
let problems = roc_build::program::report_problems_typechecked(&mut module);
|
||||
|
||||
print_problems(problems, total_time);
|
||||
|
||||
print!(".\n\nYou can run the program anyway with \x1B[32mroc run");
|
||||
|
||||
// If you're running "main.roc" then you can just do `roc run`
|
||||
// to re-run the program.
|
||||
if filename != DEFAULT_ROC_FILENAME {
|
||||
print!(" {}", &filename.to_string_lossy());
|
||||
}
|
||||
|
||||
println!("\x1B[39m");
|
||||
|
||||
Ok(problems.exit_code())
|
||||
Err(BuildFileError::ErrorModule { module, total_time }) => {
|
||||
handle_error_module(module, total_time, filename, true)
|
||||
}
|
||||
Err(BuildFileError::LoadingProblem(LoadingProblem::FormattedReport(report))) => {
|
||||
print!("{}", report);
|
||||
Err(BuildFileError::LoadingProblem(problem)) => handle_loading_problem(problem),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_error_module(
|
||||
mut module: roc_load::LoadedModule,
|
||||
total_time: std::time::Duration,
|
||||
filename: &OsStr,
|
||||
print_run_anyway_hint: bool,
|
||||
) -> io::Result<i32> {
|
||||
debug_assert!(module.total_problems() > 0);
|
||||
|
||||
let problems = roc_build::program::report_problems_typechecked(&mut module);
|
||||
|
||||
print_problems(problems, total_time);
|
||||
|
||||
if print_run_anyway_hint {
|
||||
// If you're running "main.roc" then you can just do `roc run`
|
||||
// to re-run the program.
|
||||
print!(".\n\nYou can run the program anyway with \x1B[32mroc run");
|
||||
|
||||
if filename != DEFAULT_ROC_FILENAME {
|
||||
print!(" {}", &filename.to_string_lossy());
|
||||
}
|
||||
|
||||
println!("\x1B[39m");
|
||||
}
|
||||
|
||||
Ok(problems.exit_code())
|
||||
}
|
||||
|
||||
fn handle_loading_problem(problem: LoadingProblem) -> io::Result<i32> {
|
||||
match problem {
|
||||
LoadingProblem::FormattedReport(report) => {
|
||||
print!("{}", report);
|
||||
Ok(1)
|
||||
}
|
||||
Err(other) => {
|
||||
panic!("build_file failed with error:\n{:?}", other);
|
||||
_ => {
|
||||
// TODO: tighten up the types here, we should always end up with a
|
||||
// formatted report from load.
|
||||
print!("Failed with error: {:?}", problem);
|
||||
Ok(1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,20 +97,28 @@ pub struct LoadConfig {
|
|||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum ExecutionMode {
|
||||
Test,
|
||||
Check,
|
||||
Executable,
|
||||
/// Like [`ExecutionMode::Executable`], but stops in the presence of type errors.
|
||||
ExecutableIfCheck,
|
||||
/// Test is like [`ExecutionMode::ExecutableIfCheck`], but rather than producing a proper
|
||||
/// executable, run tests.
|
||||
Test,
|
||||
}
|
||||
|
||||
impl ExecutionMode {
|
||||
fn goal_phase(&self) -> Phase {
|
||||
match self {
|
||||
ExecutionMode::Test | ExecutionMode::Executable => Phase::MakeSpecializations,
|
||||
ExecutionMode::Check | ExecutionMode::ExecutableIfCheck => Phase::SolveTypes,
|
||||
ExecutionMode::Executable => Phase::MakeSpecializations,
|
||||
ExecutionMode::Check | ExecutionMode::ExecutableIfCheck | ExecutionMode::Test => {
|
||||
Phase::SolveTypes
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn build_if_checks(&self) -> bool {
|
||||
matches!(self, Self::ExecutableIfCheck | Self::Test)
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct storing various intermediate stages by their ModuleId
|
||||
|
@ -2615,7 +2623,7 @@ fn update<'a>(
|
|||
let finish_type_checking = is_host_exposed &&
|
||||
(state.goal_phase() == Phase::SolveTypes)
|
||||
// If we're running in check-and-then-build mode, only exit now there are errors.
|
||||
&& (!matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck) || state.module_cache.total_problems() > 0);
|
||||
&& (!state.exec_mode.build_if_checks() || state.module_cache.total_problems() > 0);
|
||||
|
||||
if finish_type_checking {
|
||||
debug_assert!(work.is_empty());
|
||||
|
@ -2623,7 +2631,7 @@ fn update<'a>(
|
|||
|
||||
state.timings.insert(module_id, module_timing);
|
||||
|
||||
if matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck) {
|
||||
if state.exec_mode.build_if_checks() {
|
||||
// We there may outstanding modules in the typecheked cache whose ident IDs
|
||||
// aren't registered; transfer all of their idents over to the state, since
|
||||
// we're now done and ready to report errors.
|
||||
|
@ -2677,9 +2685,7 @@ fn update<'a>(
|
|||
},
|
||||
);
|
||||
|
||||
if state.goal_phase() > Phase::SolveTypes
|
||||
|| matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck)
|
||||
{
|
||||
if state.goal_phase() > Phase::SolveTypes || state.exec_mode.build_if_checks() {
|
||||
let layout_cache = state.layout_caches.pop().unwrap_or_else(|| {
|
||||
LayoutCache::new(state.layout_interner.fork(), state.target_info)
|
||||
});
|
||||
|
@ -2703,17 +2709,12 @@ fn update<'a>(
|
|||
state.timings.insert(module_id, module_timing);
|
||||
}
|
||||
|
||||
let work = if is_host_exposed
|
||||
&& matches!(state.exec_mode, ExecutionMode::ExecutableIfCheck)
|
||||
{
|
||||
let work = if is_host_exposed && state.exec_mode.build_if_checks() {
|
||||
debug_assert!(
|
||||
work.is_empty(),
|
||||
"work left over after host exposed is checked"
|
||||
);
|
||||
|
||||
// Update the goal phase to target full codegen.
|
||||
state.exec_mode = ExecutionMode::Executable;
|
||||
|
||||
// Load the find + make specializations portion of the dependency graph.
|
||||
state
|
||||
.dependencies
|
||||
|
@ -2785,7 +2786,7 @@ fn update<'a>(
|
|||
layout_cache,
|
||||
..
|
||||
} => {
|
||||
debug_assert!(state.goal_phase() == Phase::MakeSpecializations);
|
||||
debug_assert!(state.goal_phase() == Phase::MakeSpecializations || state.exec_mode.build_if_checks());
|
||||
|
||||
log!("made specializations for {:?}", module_id);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue