Report builtins type errors during load building as appropriate

This commit is contained in:
Ayaz Hafiz 2022-11-22 10:36:41 -06:00 committed by Richard Feldman
parent bcb423dae8
commit f8d51473d8
No known key found for this signature in database
GPG key ID: F1F21AA5B1D9E43B
5 changed files with 142 additions and 123 deletions

View file

@ -6,6 +6,7 @@ use roc_load::{EntryPoint, ExpectMetadata, LoadedModule, MonomorphizedModule};
use roc_module::symbol::{Interns, ModuleId};
use roc_mono::ir::OptLevel;
use roc_region::all::LineInfo;
use roc_reporting::cli::report_problems;
use roc_solve_problem::TypeError;
use std::ops::Deref;
use std::path::{Path, PathBuf};
@ -21,7 +22,7 @@ pub struct CodeGenTiming {
}
pub fn report_problems_monomorphized(loaded: &mut MonomorphizedModule) -> Problems {
report_problems_help(
report_problems(
loaded.total_problems(),
&loaded.sources,
&loaded.interns,
@ -31,7 +32,7 @@ pub fn report_problems_monomorphized(loaded: &mut MonomorphizedModule) -> Proble
}
pub fn report_problems_typechecked(loaded: &mut LoadedModule) -> Problems {
report_problems_help(
report_problems(
loaded.total_problems(),
&loaded.sources,
&loaded.interns,
@ -40,123 +41,6 @@ pub fn report_problems_typechecked(loaded: &mut LoadedModule) -> Problems {
)
}
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Problems {
pub errors: usize,
pub warnings: usize,
}
impl Problems {
pub fn exit_code(&self) -> i32 {
// 0 means no problems, 1 means errors, 2 means warnings
if self.errors > 0 {
1
} else {
self.warnings.min(1) as i32
}
}
}
fn report_problems_help(
total_problems: usize,
sources: &MutMap<ModuleId, (PathBuf, Box<str>)>,
interns: &Interns,
can_problems: &mut MutMap<ModuleId, Vec<roc_problem::can::Problem>>,
type_problems: &mut MutMap<ModuleId, Vec<TypeError>>,
) -> Problems {
use roc_reporting::report::{
can_problem, type_problem, Report, RocDocAllocator, Severity::*, DEFAULT_PALETTE,
};
let palette = DEFAULT_PALETTE;
// This will often over-allocate total memory, but it means we definitely
// never need to re-allocate either the warnings or the errors vec!
let mut warnings = Vec::with_capacity(total_problems);
let mut errors = Vec::with_capacity(total_problems);
for (home, (module_path, src)) in sources.iter() {
let mut src_lines: Vec<&str> = Vec::new();
src_lines.extend(src.split('\n'));
let lines = LineInfo::new(&src_lines.join("\n"));
// Report parsing and canonicalization problems
let alloc = RocDocAllocator::new(&src_lines, *home, interns);
let problems = can_problems.remove(home).unwrap_or_default();
for problem in problems.into_iter() {
let report = can_problem(&alloc, &lines, module_path.clone(), problem);
let severity = report.severity;
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
match severity {
Warning => {
warnings.push(buf);
}
RuntimeError => {
errors.push(buf);
}
}
}
let problems = type_problems.remove(home).unwrap_or_default();
for problem in problems {
if let Some(report) = type_problem(&alloc, &lines, module_path.clone(), problem) {
let severity = report.severity;
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
match severity {
Warning => {
warnings.push(buf);
}
RuntimeError => {
errors.push(buf);
}
}
}
}
}
let problems_reported;
// Only print warnings if there are no errors
if errors.is_empty() {
problems_reported = warnings.len();
for warning in warnings.iter() {
println!("\n{}\n", warning);
}
} else {
problems_reported = errors.len();
for error in errors.iter() {
println!("\n{}\n", error);
}
}
// If we printed any problems, print a horizontal rule at the end,
// and then clear any ANSI escape codes (e.g. colors) we've used.
//
// The horizontal rule is nice when running the program right after
// compiling it, as it lets you clearly see where the compiler
// errors/warnings end and the program output begins.
if problems_reported > 0 {
println!("{}\u{001B}[0m\n", Report::horizontal_rule(&palette));
}
Problems {
errors: errors.len(),
warnings: warnings.len(),
}
}
pub enum CodeObject {
MemoryBuffer(MemoryBuffer),
Vector(Vec<u8>),

View file

@ -72,6 +72,7 @@ fn write_types_for_module_dummy(output_path: &Path) {
fn write_types_for_module_real(module_id: ModuleId, filename: &str, output_path: &Path) {
use roc_can::module::TypeState;
use roc_load_internal::file::{LoadingProblem, Threading};
use roc_reporting::cli::report_problems;
let arena = Bump::new();
let src_dir = PathBuf::from(".");
@ -90,7 +91,7 @@ fn write_types_for_module_real(module_id: ModuleId, filename: &str, output_path:
Threading::AllAvailable,
);
let module = match res_module {
let mut module = match res_module {
Ok(v) => v,
Err(LoadingProblem::FormattedReport(report)) => {
panic!("{}", report);
@ -100,8 +101,16 @@ fn write_types_for_module_real(module_id: ModuleId, filename: &str, output_path:
}
};
if module.total_problems() > 0 {
panic!("Problems were found! Refusing to build cached subs.\nTry building with {}=1 to see them.", ROC_SKIP_SUBS_CACHE);
let problems = report_problems(
module.total_problems(),
&module.sources,
&module.interns,
&mut module.can_problems,
&mut module.type_problems,
);
if problems.errors + problems.warnings > 0 {
panic!("Problems were found! Refusing to build cached subs.");
}
let subs = module.solved.into_inner();

View file

@ -133,7 +133,9 @@ fn find_names_needed(
}
_ => panic!(
"unfixable recursive type in roc_types::pretty_print {:?} {:?} {:?}",
recursive, variable, content
recursive,
variable,
subs.dbg(recursive)
),
}
}

123
crates/reporting/src/cli.rs Normal file
View file

@ -0,0 +1,123 @@
use std::path::PathBuf;
use roc_collections::MutMap;
use roc_module::symbol::{Interns, ModuleId};
use roc_region::all::LineInfo;
use roc_solve_problem::TypeError;
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
pub struct Problems {
pub errors: usize,
pub warnings: usize,
}
impl Problems {
pub fn exit_code(&self) -> i32 {
// 0 means no problems, 1 means errors, 2 means warnings
if self.errors > 0 {
1
} else {
self.warnings.min(1) as i32
}
}
}
pub fn report_problems(
total_problems: usize,
sources: &MutMap<ModuleId, (PathBuf, Box<str>)>,
interns: &Interns,
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,
};
let palette = DEFAULT_PALETTE;
// This will often over-allocate total memory, but it means we definitely
// never need to re-allocate either the warnings or the errors vec!
let mut warnings = Vec::with_capacity(total_problems);
let mut errors = Vec::with_capacity(total_problems);
for (home, (module_path, src)) in sources.iter() {
let mut src_lines: Vec<&str> = Vec::new();
src_lines.extend(src.split('\n'));
let lines = LineInfo::new(&src_lines.join("\n"));
// Report parsing and canonicalization problems
let alloc = RocDocAllocator::new(&src_lines, *home, interns);
let problems = can_problems.remove(home).unwrap_or_default();
for problem in problems.into_iter() {
let report = can_problem(&alloc, &lines, module_path.clone(), problem);
let severity = report.severity;
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
match severity {
Warning => {
warnings.push(buf);
}
RuntimeError => {
errors.push(buf);
}
}
}
let problems = type_problems.remove(home).unwrap_or_default();
for problem in problems {
if let Some(report) = type_problem(&alloc, &lines, module_path.clone(), problem) {
let severity = report.severity;
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
match severity {
Warning => {
warnings.push(buf);
}
RuntimeError => {
errors.push(buf);
}
}
}
}
}
let problems_reported;
// Only print warnings if there are no errors
if errors.is_empty() {
problems_reported = warnings.len();
for warning in warnings.iter() {
println!("\n{}\n", warning);
}
} else {
problems_reported = errors.len();
for error in errors.iter() {
println!("\n{}\n", error);
}
}
// If we printed any problems, print a horizontal rule at the end,
// and then clear any ANSI escape codes (e.g. colors) we've used.
//
// The horizontal rule is nice when running the program right after
// compiling it, as it lets you clearly see where the compiler
// errors/warnings end and the program output begins.
if problems_reported > 0 {
println!("{}\u{001B}[0m\n", Report::horizontal_rule(&palette));
}
Problems {
errors: errors.len(),
warnings: warnings.len(),
}
}

View file

@ -3,5 +3,6 @@
// See github.com/roc-lang/roc/issues/800 for discussion of the large_enum_variant check.
#![allow(clippy::large_enum_variant)]
pub mod cli;
pub mod error;
pub mod report;