add proper error messages for ingested files

This commit is contained in:
Brendan Hansknecht 2023-04-07 18:16:43 -07:00
parent 62fcc71be3
commit e5b88366fe
No known key found for this signature in database
GPG key ID: 0EA784685083E75B
5 changed files with 86 additions and 25 deletions

View file

@ -757,10 +757,21 @@ pub fn build(
roc_run(&arena, opt_level, triple, args, bytes, expect_metadata) roc_run(&arena, opt_level, triple, args, bytes, expect_metadata)
} }
BuildAndRunIfNoErrors => { BuildAndRunIfNoErrors => {
if problems.fatally_errored {
problems.print_to_stdout(total_time);
println!(
".\n\nCannot run program due to fatal error…\n\n\x1B[36m{}\x1B[39m",
"".repeat(80)
);
// Return a nonzero exit code due to falta problem
return Ok(problems.exit_code());
}
debug_assert_eq!( debug_assert_eq!(
problems.errors, 0, problems.errors, 0,
"if there are errors, they should have been returned as an error variant" "if there are non-fatal errors, they should have been returned as an error variant"
); );
if problems.warnings > 0 { if problems.warnings > 0 {
problems.print_to_stdout(total_time); problems.print_to_stdout(total_time);
println!( println!(

View file

@ -4186,9 +4186,11 @@ pub fn with_hole<'a>(
Layout::STR, Layout::STR,
hole, hole,
), ),
_ => unreachable!( _ => {
"All of these cases should be dealt during solve, generating proper errors" // This will not manifest as a real runtime error and is just returned to have a value here.
), // The actual type error during solve will be fatal.
runtime_error(env, "Invalid type for ingested file")
}
} }
} }
SingleQuote(_, _, character, _) => { SingleQuote(_, _, character, _) => {

View file

@ -1771,7 +1771,7 @@ fn solve(
state state
} }
IngestedFile(type_index, _, bytes) => { IngestedFile(type_index, file_path, bytes) => {
let actual = either_type_index_to_var( let actual = either_type_index_to_var(
subs, subs,
rank, rank,
@ -1794,34 +1794,37 @@ fn solve(
) { ) {
// List U8 always valid. // List U8 always valid.
subs.rollback_to(snapshot); subs.rollback_to(snapshot);
state return state;
} else if let Success { .. } = unify( }
subs.rollback_to(snapshot);
let snapshot = subs.snapshot();
// We explicitly match on the last unify to get the type in the case it errors.
match unify(
&mut UEnv::new(subs), &mut UEnv::new(subs),
actual, actual,
Variable::STR, Variable::STR,
Mode::EQ, Mode::EQ,
Polarity::OF_VALUE, Polarity::OF_VALUE,
) { ) {
// Str only valid if valid utf8. Success { .. } => {
if std::str::from_utf8(bytes).is_err() { // Str only valid if valid utf8.
todo!("add type error due to not being a utf8 string"); if let Err(err) = std::str::from_utf8(bytes) {
let problem = TypeError::IngestedFileBadUtf8(file_path.clone(), err);
problems.push(problem);
}
subs.rollback_to(snapshot);
state
} }
Failure(_, actual_type, _, _) => {
subs.rollback_to(snapshot);
subs.rollback_to(snapshot); let problem =
state TypeError::IngestedFileUnsupportedType(file_path.clone(), actual_type);
} else { problems.push(problem);
// Unexpected type. state
todo!("Add type error for unsupported ingested file type"); }
// let problem = TypeError::BadExpr(
// *region,
// Category::Lookup(*symbol),
// actual_type,
// expectation.replace_ref(expected_type),
// );
// problems.push(problem);
// subs.rollback_to(snapshot);
// state
} }
} }
}; };

View file

@ -1,4 +1,6 @@
//! Provides types to describe problems that can occur during solving. //! Provides types to describe problems that can occur during solving.
use std::{path::Path, str::Utf8Error};
use roc_can::expected::{Expected, PExpected}; use roc_can::expected::{Expected, PExpected};
use roc_module::{ident::Lowercase, symbol::Symbol}; use roc_module::{ident::Lowercase, symbol::Symbol};
use roc_problem::{can::CycleEntry, Severity}; use roc_problem::{can::CycleEntry, Severity};
@ -29,6 +31,8 @@ pub enum TypeError {
expected_opaque: Symbol, expected_opaque: Symbol,
found_opaque: Symbol, found_opaque: Symbol,
}, },
IngestedFileBadUtf8(Box<Path>, Utf8Error),
IngestedFileUnsupportedType(Box<Path>, ErrorType),
} }
impl TypeError { impl TypeError {
@ -48,6 +52,8 @@ impl TypeError {
TypeError::Exhaustive(exhtv) => exhtv.severity(), TypeError::Exhaustive(exhtv) => exhtv.severity(),
TypeError::StructuralSpecialization { .. } => RuntimeError, TypeError::StructuralSpecialization { .. } => RuntimeError,
TypeError::WrongSpecialization { .. } => RuntimeError, TypeError::WrongSpecialization { .. } => RuntimeError,
TypeError::IngestedFileBadUtf8(..) => Fatal,
TypeError::IngestedFileUnsupportedType(..) => Fatal,
} }
} }
} }

View file

@ -209,6 +209,45 @@ pub fn type_problem<'b>(
severity, severity,
}) })
} }
IngestedFileBadUtf8(file_path, utf8_err) => {
let stack = [
alloc.concat([
alloc.reflow("Failed to load "),
alloc.text(format!("{:?}", file_path)),
alloc.reflow(" as Str:"),
]),
alloc.text(format!("{}", utf8_err)),
];
Some(Report {
title: "INVALID UTF-8".to_string(),
filename,
doc: alloc.stack(stack),
severity,
})
}
IngestedFileUnsupportedType(file_path, typ) => {
let stack = [
alloc.concat([
alloc.text(format!("{:?}", file_path)),
alloc.reflow(" is annotated to be a "),
alloc.inline_type_block(error_type_to_doc(alloc, typ)),
alloc.reflow("."),
]),
alloc.concat([
alloc.reflow("Ingested files can only be of type "),
alloc.type_str("List U8"),
alloc.reflow(" or "),
alloc.type_str("Str"),
alloc.reflow("."),
]),
];
Some(Report {
title: "INVALID TYPE FOR INGESTED FILE".to_string(),
filename,
doc: alloc.stack(stack),
severity,
})
}
} }
} }