Merge pull request #4661 from roc-lang/roc-test-dev

`test` has `dev` behavior, and `dev` does not exit if there are warnings
This commit is contained in:
Ayaz 2022-12-03 12:26:00 -06:00 committed by GitHub
commit c61c42bff7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 341 additions and 194 deletions

2
Cargo.lock generated
View file

@ -3880,6 +3880,7 @@ dependencies = [
"roc_collections",
"roc_error_macros",
"roc_module",
"roc_problem",
"roc_region",
]
@ -4247,6 +4248,7 @@ dependencies = [
"roc_mono",
"roc_packaging",
"roc_parse",
"roc_problem",
"roc_region",
"roc_reporting",
"roc_std",

View file

@ -359,8 +359,9 @@ 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_build::program::report_problems_monomorphized;
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,18 +426,26 @@ 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 problems = report_problems_monomorphized(&mut loaded);
let mut loaded = loaded;
let mut expectations = std::mem::take(&mut loaded.expectations);
let loaded = loaded;
let interns = loaded.interns.clone();
@ -449,6 +458,19 @@ pub fn test(matches: &ArgMatches, triple: Triple) -> io::Result<i32> {
)
.unwrap();
// Print warnings before running tests.
{
debug_assert_eq!(
problems.errors, 0,
"if there were errors, we would have already exited."
);
if problems.warnings > 0 {
print_problems(problems, start_time.elapsed());
println!(".\n\nRunning tests…\n\n\x1B[36m{}\x1B[39m", "".repeat(80));
}
}
// Run the tests.
let arena = &bumpalo::Bump::new();
let interns = arena.alloc(interns);
@ -733,35 +755,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)
}
}
}

View file

@ -11,3 +11,4 @@ roc_collections = { path = "../collections" }
roc_region = { path = "../region" }
roc_module = { path = "../module" }
roc_error_macros = { path = "../../error_macros" }
roc_problem = { path = "../problem" }

View file

@ -7,6 +7,7 @@ use roc_module::{
ident::{Lowercase, TagIdIntType, TagName},
symbol::Symbol,
};
use roc_problem::Severity;
use roc_region::all::Region;
use self::Pattern::*;
@ -149,6 +150,17 @@ pub enum Error {
},
}
impl Error {
pub fn severity(&self) -> Severity {
use Severity::*;
match self {
Error::Incomplete(..) => RuntimeError,
Error::Redundant { .. } => Warning,
Error::Unmatchable { .. } => Warning,
}
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Context {
BadArg,

View file

@ -101,14 +101,14 @@ pub fn load_and_monomorphize_from_str<'a>(
exposed_types: ExposedByModule,
roc_cache_dir: RocCacheDir<'_>,
load_config: LoadConfig,
) -> Result<MonomorphizedModule<'a>, LoadingProblem<'a>> {
) -> Result<MonomorphizedModule<'a>, LoadMonomorphizedError<'a>> {
use LoadResult::*;
let load_start = LoadStart::from_str(arena, filename, src, roc_cache_dir, src_dir)?;
match load(arena, load_start, exposed_types, roc_cache_dir, load_config)? {
Monomorphized(module) => Ok(module),
TypeChecked(_) => unreachable!(""),
TypeChecked(module) => Err(LoadMonomorphizedError::ErrorModule(module)),
}
}

View file

@ -45,6 +45,7 @@ use roc_parse::header::{HeaderFor, ModuleNameEnum, PackageName};
use roc_parse::ident::UppercaseIdent;
use roc_parse::module::module_defs;
use roc_parse::parser::{FileError, Parser, SourceError, SyntaxError};
use roc_problem::Severity;
use roc_region::all::{LineInfo, Loc, Region};
use roc_reporting::report::{Annotation, Palette, RenderTarget};
use roc_solve::module::{extract_module_owned_implementations, Solved, SolvedModule};
@ -97,20 +98,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
@ -141,18 +150,22 @@ struct ModuleCache<'a> {
}
impl<'a> ModuleCache<'a> {
pub fn total_problems(&self) -> usize {
let mut total = 0;
fn has_can_errors(&self) -> bool {
self.can_problems
.values()
.flatten()
.any(|problem| problem.severity() == Severity::RuntimeError)
}
for problems in self.can_problems.values() {
total += problems.len();
}
fn has_type_errors(&self) -> bool {
self.type_problems
.values()
.flatten()
.any(|problem| problem.severity() == Severity::RuntimeError)
}
for problems in self.type_problems.values() {
total += problems.len();
}
total
pub fn has_errors(&self) -> bool {
self.has_can_errors() || self.has_type_errors()
}
}
@ -2615,7 +2628,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.has_errors());
if finish_type_checking {
debug_assert!(work.is_empty());
@ -2623,7 +2636,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 +2690,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 +2714,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 +2791,10 @@ 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);
@ -5987,7 +5996,7 @@ fn run_task<'a>(
}
fn to_file_problem_report(filename: &Path, error: io::ErrorKind) -> String {
use roc_reporting::report::{Report, RocDocAllocator, Severity, DEFAULT_PALETTE};
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
use ven_pretty::DocAllocator;
let src_lines: Vec<&str> = Vec::new();
@ -6074,7 +6083,7 @@ fn to_import_cycle_report(
filename: PathBuf,
render: RenderTarget,
) -> String {
use roc_reporting::report::{Report, RocDocAllocator, Severity, DEFAULT_PALETTE};
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
use ven_pretty::DocAllocator;
// import_cycle looks like CycleModule, Import1, ..., ImportN, CycleModule
@ -6134,7 +6143,7 @@ fn to_incorrect_module_name_report<'a>(
src: &'a [u8],
render: RenderTarget,
) -> String {
use roc_reporting::report::{Report, RocDocAllocator, Severity, DEFAULT_PALETTE};
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
use ven_pretty::DocAllocator;
let IncorrectModuleName {
@ -6220,7 +6229,7 @@ fn to_parse_problem_report<'a>(
}
fn to_missing_platform_report(module_id: ModuleId, other: PlatformPath) -> String {
use roc_reporting::report::{Report, RocDocAllocator, Severity, DEFAULT_PALETTE};
use roc_reporting::report::{Report, RocDocAllocator, DEFAULT_PALETTE};
use ven_pretty::DocAllocator;
use PlatformPath::*;

View file

@ -7,6 +7,8 @@ use roc_parse::pattern::PatternType;
use roc_region::all::{Loc, Region};
use roc_types::types::AliasKind;
use crate::Severity;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct CycleEntry {
pub symbol: Symbol,
@ -205,6 +207,71 @@ pub enum Problem {
}
impl Problem {
pub fn severity(&self) -> Severity {
use Severity::{RuntimeError, Warning};
match self {
Problem::UnusedDef(_, _) => Warning,
Problem::UnusedImport(_, _) => Warning,
Problem::UnusedModuleImport(_, _) => Warning,
Problem::ExposedButNotDefined(_) => RuntimeError,
Problem::UnknownGeneratesWith(_) => RuntimeError,
Problem::UnusedArgument(_, _, _, _) => Warning,
Problem::UnusedBranchDef(_, _) => Warning,
Problem::PrecedenceProblem(_) => RuntimeError,
Problem::UnsupportedPattern(_, _) => RuntimeError,
Problem::Shadowing { .. } => RuntimeError,
Problem::CyclicAlias(..) => RuntimeError,
Problem::BadRecursion(_) => RuntimeError,
Problem::PhantomTypeArgument { .. } => Warning,
Problem::UnboundTypeVariable { .. } => RuntimeError,
Problem::DuplicateRecordFieldValue { .. } => Warning,
Problem::DuplicateRecordFieldType { .. } => RuntimeError,
Problem::InvalidOptionalValue { .. } => RuntimeError,
Problem::DuplicateTag { .. } => RuntimeError,
Problem::RuntimeError(_) => RuntimeError,
Problem::SignatureDefMismatch { .. } => RuntimeError,
Problem::InvalidAliasRigid { .. } => RuntimeError,
Problem::InvalidInterpolation(_) => RuntimeError,
Problem::InvalidHexadecimal(_) => RuntimeError,
Problem::InvalidUnicodeCodePt(_) => RuntimeError,
Problem::NestedDatatype { .. } => RuntimeError,
Problem::InvalidExtensionType { .. } => RuntimeError,
Problem::AbilityHasTypeVariables { .. } => RuntimeError,
Problem::HasClauseIsNotAbility { .. } => RuntimeError,
Problem::IllegalHasClause { .. } => RuntimeError,
Problem::DuplicateHasAbility { .. } => Warning,
Problem::AbilityMemberMissingHasClause { .. } => RuntimeError,
Problem::AbilityMemberMultipleBoundVars { .. } => RuntimeError,
Problem::AbilityNotOnToplevel { .. } => RuntimeError, // Ideally, could be compiled
Problem::AbilityUsedAsType(_, _, _) => RuntimeError,
Problem::NestedSpecialization(_, _) => RuntimeError, // Ideally, could be compiled
Problem::IllegalDerivedAbility(_) => RuntimeError,
Problem::ImplementationNotFound { .. } => RuntimeError,
Problem::NotAnAbilityMember { .. } => RuntimeError,
Problem::OptionalAbilityImpl { .. } => RuntimeError,
Problem::QualifiedAbilityImpl { .. } => RuntimeError,
Problem::AbilityImplNotIdent { .. } => RuntimeError,
Problem::DuplicateImpl { .. } => Warning, // First impl is used at runtime
Problem::NotAnAbility(_) => Warning,
Problem::ImplementsNonRequired { .. } => Warning,
Problem::DoesNotImplementAbility { .. } => RuntimeError,
Problem::NotBoundInAllPatterns { .. } => RuntimeError,
Problem::NoIdentifiersIntroduced(_) => Warning,
Problem::OverloadedSpecialization { .. } => Warning, // Ideally, will compile
Problem::UnnecessaryOutputWildcard { .. } => Warning,
// TODO: sometimes this can just be a warning, e.g. if you have [1, .., .., 2] but we
// don't catch that yet.
Problem::MultipleListRestPattern { .. } => RuntimeError,
Problem::BadTypeArguments { .. } => RuntimeError,
// TODO: this can be a warning instead if we recover the program by
// injecting a crash message
Problem::UnappliedCrash { .. } => RuntimeError,
Problem::OverAppliedCrash { .. } => RuntimeError,
Problem::DefsOnlyUsedInRecursion(_, _) => Warning,
}
}
/// Returns a Region value from the Problem, if possible.
/// Some problems have more than one region; in those cases,
/// this tries to pick the one that's closest to the original

View file

@ -3,3 +3,15 @@
// See github.com/roc-lang/roc/issues/800 for discussion of the large_enum_variant check.
#![allow(clippy::large_enum_variant)]
pub mod can;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Severity {
/// This will cause a runtime error if some code get srun
/// (e.g. type mismatch, naming error)
RuntimeError,
/// This will never cause the code to misbehave,
/// but should be cleaned up
/// (e.g. unused def, unused import)
Warning,
}

View file

@ -1,7 +1,7 @@
//! Provides types to describe problems that can occur during solving.
use roc_can::expected::{Expected, PExpected};
use roc_module::{ident::Lowercase, symbol::Symbol};
use roc_problem::can::CycleEntry;
use roc_problem::{can::CycleEntry, Severity};
use roc_region::all::Region;
use roc_types::types::{Category, ErrorType, PatternCategory};
@ -31,6 +31,27 @@ pub enum TypeError {
},
}
impl TypeError {
pub fn severity(&self) -> Severity {
use Severity::*;
match self {
TypeError::BadExpr(..) => RuntimeError,
TypeError::BadPattern(..) => RuntimeError,
TypeError::CircularType(..) => RuntimeError,
TypeError::CircularDef(_) => RuntimeError,
TypeError::UnexposedLookup(_) => RuntimeError,
TypeError::UnfulfilledAbility(_) => RuntimeError,
TypeError::BadExprMissingAbility(_, _, _, _) => RuntimeError,
TypeError::BadPatternMissingAbility(_, _, _, _) => RuntimeError,
// NB: if bidirectional exhaustiveness checking is implemented, the other direction
// is also not a runtime error.
TypeError::Exhaustive(exhtv) => exhtv.severity(),
TypeError::StructuralSpecialization { .. } => RuntimeError,
TypeError::WrongSpecialization { .. } => RuntimeError,
}
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
pub enum Unfulfilled {
/// No claimed implementation of an ability for an opaque type.

View file

@ -7,7 +7,7 @@ use roc_build::link::llvm_module_to_dylib;
use roc_collections::all::MutSet;
use roc_gen_llvm::llvm::externs::add_default_roc_externs;
use roc_gen_llvm::{llvm::build::LlvmBackendMode, run_roc::RocCallResult};
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, Threading};
use roc_load::{EntryPoint, ExecutionMode, LoadConfig, LoadMonomorphizedError, Threading};
use roc_mono::ir::{CrashTag, OptLevel};
use roc_packaging::cache::RocCacheDir;
use roc_region::all::LineInfo;
@ -87,7 +87,9 @@ fn create_llvm_module<'a>(
let mut loaded = match loaded {
Ok(x) => x,
Err(roc_load::LoadingProblem::FormattedReport(report)) => {
Err(LoadMonomorphizedError::LoadingProblem(roc_load::LoadingProblem::FormattedReport(
report,
))) => {
println!("{}", report);
panic!();
}

View file

@ -16,6 +16,7 @@ const EXPANDED_STACK_SIZE: usize = 8 * 1024 * 1024;
use roc_collections::all::MutMap;
use roc_load::ExecutionMode;
use roc_load::LoadConfig;
use roc_load::LoadMonomorphizedError;
use roc_load::Threading;
use roc_module::symbol::Symbol;
use roc_mono::ir::Proc;
@ -113,7 +114,9 @@ fn compiles_to_ir(test_name: &str, src: &str) {
let mut loaded = match loaded {
Ok(x) => x,
Err(roc_load::LoadingProblem::FormattedReport(report)) => {
Err(LoadMonomorphizedError::LoadingProblem(roc_load::LoadingProblem::FormattedReport(
report,
))) => {
println!("{}", report);
panic!();
}

View file

@ -20,6 +20,7 @@ roc_load = {path = "../compiler/load"}
roc_module = {path = "../compiler/module"}
roc_mono = {path = "../compiler/mono"}
roc_parse = {path = "../compiler/parse"}
roc_problem = {path = "../compiler/problem"}
roc_region = {path = "../compiler/region"}
roc_packaging = {path = "../packaging"}
roc_reporting = {path = "../reporting"}

View file

@ -1,7 +1,8 @@
use bumpalo::Bump;
use roc_load::{ExecutionMode, LoadConfig, Threading};
use roc_load::{ExecutionMode, LoadConfig, LoadMonomorphizedError, Threading};
use roc_packaging::cache::{self, RocCacheDir};
use roc_reporting::report::{Palette, Severity};
use roc_problem::Severity;
use roc_reporting::report::Palette;
use std::path::PathBuf;
use roc_fmt::annotation::Formattable;
@ -72,7 +73,13 @@ pub fn compile_to_mono<'a, 'i, I: Iterator<Item = &'i str>>(
let mut loaded = match loaded {
Ok(v) => v,
Err(LoadingProblem::FormattedReport(report)) => {
Err(LoadMonomorphizedError::ErrorModule(m)) => {
todo!(
"error while loading module: {:?}",
(m.can_problems, m.type_problems)
);
}
Err(LoadMonomorphizedError::LoadingProblem(LoadingProblem::FormattedReport(report))) => {
return (
None,
Problems {

View file

@ -87,7 +87,7 @@ mod test {
use indoc::indoc;
use pretty_assertions::assert_eq;
use roc_gen_llvm::{llvm::build::LlvmBackendMode, run_roc::RocCallResult, run_roc_dylib};
use roc_load::{ExecutionMode, LoadConfig, Threading};
use roc_load::{ExecutionMode, LoadConfig, LoadMonomorphizedError, Threading};
use roc_packaging::cache::RocCacheDir;
use roc_reporting::report::{RenderTarget, DEFAULT_PALETTE};
use target_lexicon::Triple;
@ -119,7 +119,7 @@ mod test {
threading: Threading::Single,
exec_mode: ExecutionMode::Test,
};
let loaded = roc_load::load_and_monomorphize_from_str(
let loaded = match roc_load::load_and_monomorphize_from_str(
arena,
filename,
source,
@ -127,8 +127,13 @@ mod test {
Default::default(),
RocCacheDir::Disallowed,
load_config,
)
.unwrap();
) {
Ok(m) => m,
Err(LoadMonomorphizedError::ErrorModule(m)) => {
panic!("{:?}", (m.can_problems, m.type_problems))
}
Err(e) => panic!("{e:?}"),
};
let mut loaded = loaded;
let mut expectations = std::mem::take(&mut loaded.expectations);
@ -442,8 +447,8 @@ mod test {
main = 0
expect
vec1 = { x: 1.0f64, y: 2.0f64 }
vec2 = { x: 4.0f64, y: 8.0f64 }
vec1 = { x: 1u8, y: 2u8 }
vec2 = { x: 4u8, y: 8u8 }
vec1 == vec2
"#
@ -453,17 +458,17 @@ mod test {
This expectation failed:
5> expect
6> vec1 = { x: 1.0f64, y: 2.0f64 }
7> vec2 = { x: 4.0f64, y: 8.0f64 }
6> vec1 = { x: 1u8, y: 2u8 }
7> vec2 = { x: 4u8, y: 8u8 }
8>
9> vec1 == vec2
When it failed, these variables had these values:
vec1 : { x : F64, y : F64 }
vec1 : { x : U8, y : U8 }
vec1 = { x: 1, y: 2 }
vec2 : { x : F64, y : F64 }
vec2 : { x : U8, y : U8 }
vec2 = { x: 4, y: 8 }
"#
),

View file

@ -29,9 +29,8 @@ pub fn report_problems(
can_problems: &mut MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
type_problems: &mut MutMap<ModuleId, Vec<TypeError>>,
) -> Problems {
use crate::report::{
can_problem, type_problem, Report, RocDocAllocator, Severity::*, DEFAULT_PALETTE,
};
use crate::report::{can_problem, type_problem, Report, RocDocAllocator, DEFAULT_PALETTE};
use roc_problem::Severity::*;
let palette = DEFAULT_PALETTE;
// This will often over-allocate total memory, but it means we definitely

View file

@ -6,12 +6,13 @@ use roc_problem::can::{
BadPattern, CycleEntry, ExtensionTypeKind, FloatErrorKind, IntErrorKind, Problem, RuntimeError,
ShadowKind,
};
use roc_problem::Severity;
use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Loc, Region};
use roc_types::types::AliasKind;
use std::path::PathBuf;
use crate::error::r#type::suggest;
use crate::report::{Annotation, Report, RocDocAllocator, RocDocBuilder, Severity};
use crate::report::{Annotation, Report, RocDocAllocator, RocDocBuilder};
use ven_pretty::DocAllocator;
const SYNTAX_PROBLEM: &str = "SYNTAX PROBLEM";
@ -67,7 +68,7 @@ pub fn can_problem<'b>(
) -> Report<'b> {
let doc;
let title;
let severity;
let severity = problem.severity();
match problem {
Problem::UnusedDef(symbol, region) => {
@ -86,7 +87,6 @@ pub fn can_problem<'b>(
]);
title = UNUSED_DEF.to_string();
severity = Severity::Warning;
}
Problem::UnusedImport(symbol, region) => {
doc = alloc.stack([
@ -103,7 +103,6 @@ pub fn can_problem<'b>(
]);
title = UNUSED_IMPORT.to_string();
severity = Severity::Warning;
}
Problem::UnusedModuleImport(module_id, region) => {
doc = alloc.stack([
@ -121,7 +120,6 @@ pub fn can_problem<'b>(
]);
title = UNUSED_IMPORT.to_string();
severity = Severity::Warning;
}
Problem::DefsOnlyUsedInRecursion(1, region) => {
doc = alloc.stack([
@ -133,7 +131,6 @@ pub fn can_problem<'b>(
]);
title = "DEFINITION ONLY USED IN RECURSION".to_string();
severity = Severity::Warning;
}
Problem::DefsOnlyUsedInRecursion(n, region) => {
doc = alloc.stack([
@ -149,7 +146,6 @@ pub fn can_problem<'b>(
]);
title = "DEFINITIONs ONLY USED IN RECURSION".to_string();
severity = Severity::Warning;
}
Problem::ExposedButNotDefined(symbol) => {
doc = alloc.stack([
@ -165,7 +161,6 @@ pub fn can_problem<'b>(
]);
title = MISSING_DEFINITION.to_string();
severity = Severity::RuntimeError;
}
Problem::UnknownGeneratesWith(loc_ident) => {
doc = alloc.stack([
@ -180,7 +175,6 @@ pub fn can_problem<'b>(
]);
title = UNKNOWN_GENERATES_WITH.to_string();
severity = Severity::RuntimeError;
}
Problem::UnusedArgument(closure_symbol, is_anonymous, argument_symbol, region) => {
let line = "\". Adding an underscore at the start of a variable name is a way of saying that the variable is not used.";
@ -215,7 +209,6 @@ pub fn can_problem<'b>(
]);
title = UNUSED_ARG.to_string();
severity = Severity::Warning;
}
Problem::UnusedBranchDef(symbol, region) => {
doc = alloc.stack([
@ -236,7 +229,6 @@ pub fn can_problem<'b>(
]);
title = UNUSED_DEF.to_string();
severity = Severity::Warning;
}
Problem::PrecedenceProblem(BothNonAssociative(region, left_bin_op, right_bin_op)) => {
doc = alloc.stack([
@ -265,7 +257,6 @@ pub fn can_problem<'b>(
]);
title = SYNTAX_PROBLEM.to_string();
severity = Severity::RuntimeError;
}
Problem::UnsupportedPattern(BadPattern::Unsupported(pattern_type), region) => {
use roc_parse::pattern::PatternType::*;
@ -296,7 +287,6 @@ pub fn can_problem<'b>(
]);
title = SYNTAX_PROBLEM.to_string();
severity = Severity::RuntimeError;
}
Problem::Shadowing {
original_region,
@ -308,7 +298,6 @@ pub fn can_problem<'b>(
doc = res_doc;
title = res_title.to_string();
severity = Severity::RuntimeError;
}
Problem::CyclicAlias(symbol, region, others, alias_kind) => {
let answer = crate::error::r#type::cyclic_alias(
@ -317,7 +306,6 @@ pub fn can_problem<'b>(
doc = answer.0;
title = answer.1;
severity = Severity::RuntimeError;
}
Problem::PhantomTypeArgument {
typ: alias,
@ -345,7 +333,6 @@ pub fn can_problem<'b>(
]);
title = UNUSED_ALIAS_PARAM.to_string();
severity = Severity::RuntimeError;
}
Problem::UnboundTypeVariable {
typ: alias,
@ -382,12 +369,10 @@ pub fn can_problem<'b>(
doc = alloc.stack(stack);
title = UNBOUND_TYPE_VARIABLE.to_string();
severity = Severity::RuntimeError;
}
Problem::BadRecursion(entries) => {
doc = to_circular_def_doc(alloc, lines, &entries);
title = CIRCULAR_DEF.to_string();
severity = Severity::RuntimeError;
}
Problem::DuplicateRecordFieldValue {
field_name,
@ -422,7 +407,6 @@ pub fn can_problem<'b>(
]);
title = DUPLICATE_FIELD_NAME.to_string();
severity = Severity::Warning;
}
Problem::InvalidOptionalValue {
field_name,
@ -471,7 +455,6 @@ pub fn can_problem<'b>(
]);
title = DUPLICATE_FIELD_NAME.to_string();
severity = Severity::Warning;
}
Problem::DuplicateTag {
tag_name,
@ -506,7 +489,6 @@ pub fn can_problem<'b>(
]);
title = DUPLICATE_TAG_NAME.to_string();
severity = Severity::Warning;
}
Problem::SignatureDefMismatch {
ref annotation_pattern,
@ -523,7 +505,6 @@ pub fn can_problem<'b>(
]);
title = NAMING_PROBLEM.to_string();
severity = Severity::RuntimeError;
}
Problem::InvalidAliasRigid {
alias_name: type_name,
@ -546,7 +527,6 @@ pub fn can_problem<'b>(
]);
title = SYNTAX_PROBLEM.to_string();
severity = Severity::RuntimeError;
}
Problem::InvalidHexadecimal(region) => {
doc = alloc.stack([
@ -563,7 +543,6 @@ pub fn can_problem<'b>(
]);
title = INVALID_UNICODE.to_string();
severity = Severity::RuntimeError;
}
Problem::InvalidUnicodeCodePt(region) => {
doc = alloc.stack([
@ -573,7 +552,6 @@ pub fn can_problem<'b>(
]);
title = INVALID_UNICODE.to_string();
severity = Severity::RuntimeError;
}
Problem::InvalidInterpolation(region) => {
doc = alloc.stack([
@ -590,14 +568,12 @@ pub fn can_problem<'b>(
]);
title = SYNTAX_PROBLEM.to_string();
severity = Severity::RuntimeError;
}
Problem::RuntimeError(runtime_error) => {
let answer = pretty_runtime_error(alloc, lines, runtime_error);
doc = answer.0;
title = answer.1.to_string();
severity = Severity::RuntimeError;
}
Problem::NestedDatatype {
alias,
@ -625,7 +601,6 @@ pub fn can_problem<'b>(
]);
title = NESTED_DATATYPE.to_string();
severity = Severity::RuntimeError;
}
Problem::InvalidExtensionType { region, kind } => {
@ -653,7 +628,6 @@ pub fn can_problem<'b>(
]);
title = INVALID_EXTENSION_TYPE.to_string();
severity = Severity::RuntimeError;
}
Problem::AbilityHasTypeVariables {
@ -672,7 +646,6 @@ pub fn can_problem<'b>(
),
]);
title = ABILITY_HAS_TYPE_VARIABLES.to_string();
severity = Severity::RuntimeError;
}
Problem::HasClauseIsNotAbility {
@ -683,7 +656,6 @@ pub fn can_problem<'b>(
alloc.region(lines.convert_region(clause_region)),
]);
title = HAS_CLAUSE_IS_NOT_AN_ABILITY.to_string();
severity = Severity::RuntimeError;
}
Problem::IllegalHasClause { region } => {
@ -702,7 +674,6 @@ pub fn can_problem<'b>(
]),
]);
title = ILLEGAL_HAS_CLAUSE.to_string();
severity = Severity::RuntimeError;
}
Problem::DuplicateHasAbility { ability, region } => {
@ -720,7 +691,6 @@ pub fn can_problem<'b>(
]),
]);
title = "DUPLICATE BOUND ABILITY".to_string();
severity = Severity::Warning;
}
Problem::AbilityMemberMissingHasClause {
@ -755,7 +725,6 @@ pub fn can_problem<'b>(
.reflow("Otherwise, the function does not need to be part of the ability!")]),
]);
title = ABILITY_MEMBER_MISSING_HAS_CLAUSE.to_string();
severity = Severity::RuntimeError;
}
Problem::AbilityMemberMultipleBoundVars {
@ -783,7 +752,6 @@ pub fn can_problem<'b>(
])
]);
title = ABILITY_MEMBER_BINDS_MULTIPLE_VARIABLES.to_string();
severity = Severity::RuntimeError;
}
Problem::AbilityNotOnToplevel { region } => {
@ -795,7 +763,6 @@ pub fn can_problem<'b>(
alloc.reflow("Abilities can only be defined on the top-level of a Roc module."),
]);
title = ABILITY_NOT_ON_TOPLEVEL.to_string();
severity = Severity::RuntimeError;
}
Problem::AbilityUsedAsType(suggested_var_name, ability, region) => {
@ -823,7 +790,6 @@ pub fn can_problem<'b>(
])),
]);
title = ABILITY_USED_AS_TYPE.to_string();
severity = Severity::RuntimeError;
}
Problem::NestedSpecialization(member, region) => {
doc = alloc.stack([
@ -836,7 +802,6 @@ pub fn can_problem<'b>(
alloc.reflow("Specializations can only be defined on the top-level of a module."),
]);
title = SPECIALIZATION_NOT_ON_TOPLEVEL.to_string();
severity = Severity::Warning;
}
Problem::IllegalDerivedAbility(region) => {
doc = alloc.stack([
@ -848,7 +813,6 @@ pub fn can_problem<'b>(
.append(list_builtin_abilities(alloc)),
]);
title = ILLEGAL_DERIVE.to_string();
severity = Severity::Warning;
}
Problem::NotAnAbility(region) => {
doc = alloc.stack([
@ -857,7 +821,6 @@ pub fn can_problem<'b>(
alloc.reflow("Only abilities can be implemented."),
]);
title = NOT_AN_ABILITY.to_string();
severity = Severity::Warning;
}
Problem::NotAnAbilityMember {
ability,
@ -872,7 +835,6 @@ pub fn can_problem<'b>(
alloc.reflow("Only implementations for members an ability has can be specified in this location.")
]);
title = NOT_AN_ABILITY_MEMBER.to_string();
severity = Severity::RuntimeError;
}
Problem::ImplementationNotFound { member, region } => {
let member_str = member.as_str(alloc.interns);
@ -884,7 +846,6 @@ pub fn can_problem<'b>(
alloc.tip().append(alloc.concat([alloc.reflow("consider adding a value of name "), alloc.symbol_unqualified(member), alloc.reflow(" in this scope, or using another variable that implements this ability member, like "), alloc.type_str(&format!("{{ {}: my{} }}", member_str, member_str))]))
]);
title = IMPLEMENTATION_NOT_FOUND.to_string();
severity = Severity::RuntimeError;
}
Problem::OptionalAbilityImpl { ability, region } => {
let hint = if ability.is_builtin() {
@ -903,7 +864,6 @@ pub fn can_problem<'b>(
hint,
]);
title = OPTIONAL_ABILITY_IMPLEMENTATION.to_string();
severity = Severity::RuntimeError;
}
Problem::QualifiedAbilityImpl { region } => {
doc = alloc.stack([
@ -914,7 +874,6 @@ pub fn can_problem<'b>(
),
]);
title = QUALIFIED_ABILITY_IMPLEMENTATION.to_string();
severity = Severity::RuntimeError;
}
Problem::AbilityImplNotIdent { region } => {
doc = alloc.stack([
@ -926,7 +885,6 @@ pub fn can_problem<'b>(
alloc.tip().append(alloc.reflow("consider defining this expression as a variable."))
]);
title = ABILITY_IMPLEMENTATION_NOT_IDENTIFIER.to_string();
severity = Severity::RuntimeError;
}
Problem::DuplicateImpl {
original,
@ -941,7 +899,6 @@ pub fn can_problem<'b>(
.reflow("Only one custom implementation can be defined for an ability member."),
]);
title = DUPLICATE_IMPLEMENTATION.to_string();
severity = Severity::RuntimeError;
}
Problem::ImplementsNonRequired {
region,
@ -966,7 +923,6 @@ pub fn can_problem<'b>(
),
]);
title = UNNECESSARY_IMPLEMENTATIONS.to_string();
severity = Severity::Warning;
}
Problem::DoesNotImplementAbility {
region,
@ -991,7 +947,6 @@ pub fn can_problem<'b>(
),
]);
title = INCOMPLETE_ABILITY_IMPLEMENTATION.to_string();
severity = Severity::RuntimeError;
}
Problem::NotBoundInAllPatterns {
unbound_symbol,
@ -1012,7 +967,6 @@ pub fn can_problem<'b>(
]),
]);
title = "NAME NOT BOUND IN ALL PATTERNS".to_string();
severity = Severity::RuntimeError;
}
Problem::NoIdentifiersIntroduced(region) => {
doc = alloc.stack([
@ -1021,7 +975,6 @@ pub fn can_problem<'b>(
alloc.reflow("If you don't need to use the value on the right-hand-side of this assignment, consider removing the assignment. Since Roc is purely functional, assignments that don't introduce variables cannot affect a program's behavior!"),
]);
title = "UNNECESSARY DEFINITION".to_string();
severity = Severity::Warning;
}
Problem::OverloadedSpecialization {
ability_member,
@ -1041,7 +994,6 @@ pub fn can_problem<'b>(
alloc.reflow("Ability specializations can only provide implementations for one opaque type, since all opaque types are different!"),
]);
title = "OVERLOADED SPECIALIZATION".to_string();
severity = Severity::Warning;
}
Problem::UnnecessaryOutputWildcard { region } => {
doc = alloc.stack([
@ -1061,7 +1013,6 @@ pub fn can_problem<'b>(
alloc.reflow("You can safely remove this to make the code more concise without changing what it means."),
]);
title = "UNNECESSARY WILDCARD".to_string();
severity = Severity::Warning;
}
Problem::MultipleListRestPattern { region } => {
doc = alloc.stack([
@ -1074,7 +1025,6 @@ pub fn can_problem<'b>(
]),
]);
title = "MULTIPLE LIST REST PATTERNS".to_string();
severity = Severity::RuntimeError;
}
Problem::BadTypeArguments {
symbol,
@ -1114,7 +1064,6 @@ pub fn can_problem<'b>(
} else {
"TOO FEW TYPE ARGUMENTS".to_string()
};
severity = Severity::RuntimeError;
}
Problem::UnappliedCrash { region } => {
doc = alloc.stack([
@ -1128,7 +1077,6 @@ pub fn can_problem<'b>(
])
]);
title = "UNAPPLIED CRASH".to_string();
severity = Severity::RuntimeError;
}
Problem::OverAppliedCrash { region } => {
doc = alloc.stack([
@ -1144,7 +1092,6 @@ pub fn can_problem<'b>(
]),
]);
title = "OVERAPPLIED CRASH".to_string();
severity = Severity::RuntimeError;
}
};

View file

@ -3,6 +3,7 @@ use std::path::PathBuf;
use bumpalo::Bump;
use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_parse::ast::Expr;
use roc_problem::Severity;
use roc_region::all::{LineColumnRegion, LineInfo, Region};
use roc_types::{
subs::{Subs, Variable},
@ -154,7 +155,7 @@ impl<'a> Renderer<'a> {
title: "EXPECT FAILED".into(),
doc,
filename: self.filename.clone(),
severity: crate::report::Severity::RuntimeError,
severity: Severity::RuntimeError,
};
let mut buf = String::new();
@ -225,7 +226,7 @@ impl<'a> Renderer<'a> {
title: "EXPECT PANICKED".into(),
doc,
filename: self.filename.clone(),
severity: crate::report::Severity::RuntimeError,
severity: Severity::RuntimeError,
};
let mut buf = String::new();

View file

@ -1,8 +1,9 @@
use roc_parse::parser::{ENumber, FileError, PList, SyntaxError};
use roc_problem::Severity;
use roc_region::all::{LineColumn, LineColumnRegion, LineInfo, Position, Region};
use std::path::PathBuf;
use crate::report::{Report, RocDocAllocator, RocDocBuilder, Severity};
use crate::report::{Report, RocDocAllocator, RocDocBuilder};
use ven_pretty::DocAllocator;
pub fn parse_problem<'a>(

View file

@ -1,5 +1,7 @@
#![allow(clippy::too_many_arguments)]
use crate::error::canonicalize::{to_circular_def_doc, CIRCULAR_DEF};
use crate::report::{Annotation, Report, RocDocAllocator, RocDocBuilder, Severity};
use crate::report::{Annotation, Report, RocDocAllocator, RocDocBuilder};
use roc_can::expected::{Expected, PExpected};
use roc_collections::all::{HumanIndex, MutSet, SendMap};
use roc_collections::VecMap;
@ -8,6 +10,7 @@ use roc_exhaustive::{CtorName, ListArity};
use roc_module::called_via::{BinOp, CalledVia};
use roc_module::ident::{IdentStr, Lowercase, TagName};
use roc_module::symbol::Symbol;
use roc_problem::Severity;
use roc_region::all::{LineInfo, Region};
use roc_solve_problem::{
NotDerivableContext, NotDerivableDecode, NotDerivableEq, TypeError, UnderivableReason,
@ -38,26 +41,30 @@ pub fn type_problem<'b>(
) -> Option<Report<'b>> {
use TypeError::*;
fn report(title: String, doc: RocDocBuilder<'_>, filename: PathBuf) -> Option<Report<'_>> {
Some(Report {
title,
filename,
doc,
severity: Severity::RuntimeError,
})
}
let severity = problem.severity();
let report =
move |title: String, doc: RocDocBuilder<'b>, filename: PathBuf| -> Option<Report<'b>> {
Some(Report {
title,
filename,
doc,
severity,
})
};
match problem {
BadExpr(region, category, found, expected) => Some(to_expr_report(
alloc, lines, filename, region, category, found, expected,
alloc, lines, filename, severity, region, category, found, expected,
)),
BadPattern(region, category, found, expected) => Some(to_pattern_report(
alloc, lines, filename, region, category, found, expected,
alloc, lines, filename, severity, region, category, found, expected,
)),
CircularType(region, symbol, overall_type) => Some(to_circular_report(
alloc,
lines,
filename,
severity,
region,
symbol,
overall_type,
@ -103,7 +110,7 @@ pub fn type_problem<'b>(
title: "TYPE MISMATCH".to_string(),
filename,
doc: alloc.stack(stack),
severity: Severity::RuntimeError,
severity,
};
Some(report)
}
@ -125,7 +132,7 @@ pub fn type_problem<'b>(
title: "TYPE MISMATCH".to_string(),
filename,
doc: alloc.stack(stack),
severity: Severity::RuntimeError,
severity,
};
Some(report)
}
@ -133,7 +140,6 @@ pub fn type_problem<'b>(
CircularDef(entries) => {
let doc = to_circular_def_doc(alloc, lines, &entries);
let title = CIRCULAR_DEF.to_string();
let severity = Severity::RuntimeError;
Some(Report {
title,
@ -169,7 +175,7 @@ pub fn type_problem<'b>(
title: "ILLEGAL SPECIALIZATION".to_string(),
filename,
doc: alloc.stack(stack),
severity: Severity::RuntimeError,
severity,
})
}
WrongSpecialization {
@ -198,7 +204,7 @@ pub fn type_problem<'b>(
title: "WRONG SPECIALIZATION TYPE".to_string(),
filename,
doc: alloc.stack(stack),
severity: Severity::RuntimeError,
severity,
})
}
}
@ -451,11 +457,11 @@ pub fn cyclic_alias<'b>(
(doc, "CYCLIC ALIAS".to_string())
}
#[allow(clippy::too_many_arguments)]
fn report_mismatch<'b>(
alloc: &'b RocDocAllocator<'b>,
lines: &LineInfo,
filename: PathBuf,
severity: Severity,
category: &Category,
found: ErrorType,
expected_type: ErrorType,
@ -492,15 +498,15 @@ fn report_mismatch<'b>(
title: "TYPE MISMATCH".to_string(),
filename,
doc: alloc.stack(lines),
severity: Severity::RuntimeError,
severity,
}
}
#[allow(clippy::too_many_arguments)]
fn report_bad_type<'b>(
alloc: &'b RocDocAllocator<'b>,
lines: &LineInfo,
filename: PathBuf,
severity: Severity,
category: &Category,
found: ErrorType,
expected_type: ErrorType,
@ -535,7 +541,7 @@ fn report_bad_type<'b>(
title: "TYPE MISMATCH".to_string(),
filename,
doc: alloc.stack(lines),
severity: Severity::RuntimeError,
severity,
}
}
@ -563,6 +569,7 @@ fn to_expr_report<'b>(
alloc: &'b RocDocAllocator<'b>,
lines: &LineInfo,
filename: PathBuf,
severity: Severity,
expr_region: roc_region::all::Region,
category: Category,
found: ErrorType,
@ -590,6 +597,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
opt_sym,
".",
field,
@ -620,7 +628,7 @@ fn to_expr_report<'b>(
alloc.region(lines.convert_region(expr_region)),
comparison,
]),
severity: Severity::RuntimeError,
severity,
}
}
Expected::FromAnnotation(name, _arity, annotation_source, expected_type) => {
@ -743,7 +751,7 @@ fn to_expr_report<'b>(
},
comparison,
]),
severity: Severity::RuntimeError,
severity,
}
}
Expected::ForReason(reason, expected_type, region) => match reason {
@ -760,6 +768,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -799,6 +808,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -837,6 +847,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -865,6 +876,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -899,6 +911,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -924,6 +937,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -963,6 +977,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -978,6 +993,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -1013,6 +1029,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -1031,6 +1048,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
Some(symbol),
"",
field,
@ -1045,6 +1063,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -1087,7 +1106,7 @@ fn to_expr_report<'b>(
filename,
title: "TOO MANY ARGS".to_string(),
doc: alloc.stack(lines),
severity: Severity::RuntimeError,
severity,
}
}
n => {
@ -1122,7 +1141,7 @@ fn to_expr_report<'b>(
filename,
title: "TOO MANY ARGS".to_string(),
doc: alloc.stack(lines),
severity: Severity::RuntimeError,
severity,
}
} else {
let lines = vec![
@ -1149,7 +1168,7 @@ fn to_expr_report<'b>(
filename,
title: "TOO FEW ARGS".to_string(),
doc: alloc.stack(lines),
severity: Severity::RuntimeError,
severity,
}
}
}
@ -1166,6 +1185,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -1190,6 +1210,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -1241,6 +1262,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -1281,6 +1303,7 @@ fn to_expr_report<'b>(
alloc,
lines,
filename,
severity,
&category,
found,
expected_type,
@ -1334,7 +1357,7 @@ fn to_expr_report<'b>(
title: "TYPE MISMATCH".to_string(),
filename,
doc: alloc.stack(lines),
severity: Severity::RuntimeError,
severity,
}
}
@ -1371,7 +1394,7 @@ fn to_expr_report<'b>(
filename,
title: "TYPE MISMATCH".to_string(),
doc,
severity: Severity::RuntimeError,
severity,
}
}
@ -1407,7 +1430,7 @@ fn to_expr_report<'b>(
filename,
title: "TYPE MISMATCH".to_string(),
doc: alloc.stack(lines),
severity: Severity::RuntimeError,
severity,
}
}
@ -1756,6 +1779,7 @@ fn to_pattern_report<'b>(
alloc: &'b RocDocAllocator<'b>,
lines: &LineInfo,
filename: PathBuf,
severity: Severity,
expr_region: roc_region::all::Region,
category: PatternCategory,
found: ErrorType,
@ -1782,7 +1806,7 @@ fn to_pattern_report<'b>(
filename,
title: "TYPE MISMATCH".to_string(),
doc,
severity: Severity::RuntimeError,
severity,
}
}
@ -1825,7 +1849,7 @@ fn to_pattern_report<'b>(
filename,
title: "TYPE MISMATCH".to_string(),
doc,
severity: Severity::RuntimeError,
severity,
}
}
PReason::WhenMatch { index, sub_pattern } => {
@ -1905,7 +1929,7 @@ fn to_pattern_report<'b>(
filename,
title: "TYPE MISMATCH".to_string(),
doc,
severity: Severity::RuntimeError,
severity,
}
}
PReason::ListElem => {
@ -1932,7 +1956,7 @@ fn to_pattern_report<'b>(
filename,
title: "TYPE MISMATCH".to_string(),
doc,
severity: Severity::RuntimeError,
severity,
}
}
PReason::TagArg { .. } | PReason::PatternGuard => {
@ -2007,6 +2031,7 @@ fn to_circular_report<'b>(
alloc: &'b RocDocAllocator<'b>,
lines: &LineInfo,
filename: PathBuf,
severity: Severity,
region: roc_region::all::Region,
symbol: Symbol,
overall_type: ErrorType,
@ -2031,7 +2056,7 @@ fn to_circular_report<'b>(
]),
])
},
severity: Severity::RuntimeError,
severity,
}
}
@ -4077,11 +4102,11 @@ fn type_problem_to_pretty<'b>(
}
}
#[allow(clippy::too_many_arguments)]
fn report_record_field_typo<'b>(
alloc: &'b RocDocAllocator<'b>,
lines: &LineInfo,
filename: PathBuf,
severity: Severity,
opt_sym: Option<Symbol>,
field_prefix: &str,
field: &Lowercase,
@ -4163,7 +4188,7 @@ fn report_record_field_typo<'b>(
filename,
title: "TYPE MISMATCH".to_string(),
doc,
severity: Severity::RuntimeError,
severity,
}
}
@ -4176,6 +4201,8 @@ fn exhaustive_problem<'a>(
use roc_exhaustive::Context::*;
use roc_exhaustive::Error::*;
let severity = problem.severity();
match problem {
Incomplete(region, context, missing) => match context {
BadArg => {
@ -4198,7 +4225,7 @@ fn exhaustive_problem<'a>(
filename,
title: "UNSAFE PATTERN".to_string(),
doc,
severity: Severity::RuntimeError,
severity,
}
}
BadDestruct => {
@ -4222,7 +4249,7 @@ fn exhaustive_problem<'a>(
filename,
title: "UNSAFE PATTERN".to_string(),
doc,
severity: Severity::RuntimeError,
severity,
}
}
BadCase => {
@ -4246,7 +4273,7 @@ fn exhaustive_problem<'a>(
filename,
title: "UNSAFE PATTERN".to_string(),
doc,
severity: Severity::RuntimeError,
severity,
}
}
},
@ -4275,7 +4302,7 @@ fn exhaustive_problem<'a>(
filename,
title: "REDUNDANT PATTERN".to_string(),
doc,
severity: Severity::Warning,
severity,
}
}
Unmatchable {
@ -4303,7 +4330,7 @@ fn exhaustive_problem<'a>(
filename,
title: "UNMATCHABLE PATTERN".to_string(),
doc,
severity: Severity::Warning,
severity,
}
}
}

View file

@ -1,6 +1,7 @@
use roc_module::ident::Ident;
use roc_module::ident::{Lowercase, ModuleName, TagName, Uppercase};
use roc_module::symbol::{Interns, ModuleId, PQModuleName, PackageQualified, Symbol};
use roc_problem::Severity;
use roc_region::all::LineColumnRegion;
use std::fmt;
use std::path::{Path, PathBuf};
@ -99,18 +100,6 @@ pub fn pretty_header_with_path(title: &str, path: &Path) -> String {
header
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Severity {
/// This will cause a runtime error if some code get srun
/// (e.g. type mismatch, naming error)
RuntimeError,
/// This will never cause the code to misbehave,
/// but should be cleaned up
/// (e.g. unused def, unused import)
Warning,
}
#[derive(Clone, Copy, Debug)]
pub enum RenderTarget {
ColorTerminal,

View file

@ -19,9 +19,10 @@ mod test_reporting {
use roc_parse::module::parse_header;
use roc_parse::state::State;
use roc_parse::test_helpers::parse_expr_with;
use roc_problem::Severity;
use roc_region::all::LineInfo;
use roc_reporting::report::{
can_problem, parse_problem, type_problem, RenderTarget, Report, Severity, ANSI_STYLE_CODES,
can_problem, parse_problem, type_problem, RenderTarget, Report, ANSI_STYLE_CODES,
DEFAULT_PALETTE,
};
use roc_reporting::report::{RocDocAllocator, RocDocBuilder};

View file

@ -5,6 +5,8 @@ app "env"
main : Task {} []
main =
f = ""
task =
Env.decode "EDITOR"
|> Task.await (\editor -> Stdout.line "Your favorite editor is \(editor)!")