Merge remote-tracking branch 'origin/trunk' into hello-web

This commit is contained in:
Folkert 2021-09-20 23:11:54 +02:00
commit 879038fae6
17 changed files with 352 additions and 130 deletions

View File

@ -42,4 +42,4 @@ jobs:
run: cd ci/bench-runner && cargo build --release && cd ../..
- name: run benchmarks with regression check
run: ./ci/bench-runner/target/release/bench-runner --check-executables-changed
run: echo "TODO re-enable benchmarks once race condition is fixed"#./ci/bench-runner/target/release/bench-runner --check-executables-changed

View File

@ -258,3 +258,88 @@ pub fn build_file<'a>(
total_time,
})
}
#[allow(clippy::too_many_arguments)]
pub fn check_file(
arena: &Bump,
src_dir: PathBuf,
roc_file_path: PathBuf,
emit_timings: bool,
) -> Result<usize, LoadingProblem> {
let compilation_start = SystemTime::now();
// only used for generating errors. We don't do code generation, so hardcoding should be fine
// we need monomorphization for when exhaustiveness checking
let ptr_bytes = 8;
// Step 1: compile the app and generate the .o file
let subs_by_module = MutMap::default();
// Release builds use uniqueness optimizations
let stdlib = arena.alloc(roc_builtins::std::standard_stdlib());
let mut loaded = roc_load::file::load_and_monomorphize(
arena,
roc_file_path,
stdlib,
src_dir.as_path(),
subs_by_module,
ptr_bytes,
builtin_defs_map,
)?;
let buf = &mut String::with_capacity(1024);
let mut it = loaded.timings.iter().peekable();
while let Some((module_id, module_timing)) = it.next() {
let module_name = loaded.interns.module_name(*module_id);
buf.push_str(" ");
if module_name.is_empty() {
// the App module
buf.push_str("Application Module");
} else {
buf.push_str(module_name);
}
buf.push('\n');
report_timing(buf, "Read .roc file from disk", module_timing.read_roc_file);
report_timing(buf, "Parse header", module_timing.parse_header);
report_timing(buf, "Parse body", module_timing.parse_body);
report_timing(buf, "Canonicalize", module_timing.canonicalize);
report_timing(buf, "Constrain", module_timing.constrain);
report_timing(buf, "Solve", module_timing.solve);
report_timing(
buf,
"Find Specializations",
module_timing.find_specializations,
);
report_timing(
buf,
"Make Specializations",
module_timing.make_specializations,
);
report_timing(buf, "Other", module_timing.other());
buf.push('\n');
report_timing(buf, "Total", module_timing.total());
if it.peek().is_some() {
buf.push('\n');
}
}
let compilation_end = compilation_start.elapsed().unwrap();
if emit_timings {
println!(
"\n\nCompilation finished!\n\nHere's how long each module took to compile:\n\n{}",
buf
);
println!("Finished checking in {} ms\n", compilation_end.as_millis(),);
}
Ok(program::report_problems(&mut loaded))
}

View File

@ -26,6 +26,7 @@ pub const CMD_BUILD: &str = "build";
pub const CMD_REPL: &str = "repl";
pub const CMD_EDIT: &str = "edit";
pub const CMD_DOCS: &str = "docs";
pub const CMD_CHECK: &str = "check";
pub const FLAG_DEBUG: &str = "debug";
pub const FLAG_DEV: &str = "dev";
@ -124,6 +125,20 @@ pub fn build_app<'a>() -> App<'a> {
.subcommand(App::new(CMD_REPL)
.about("Launch the interactive Read Eval Print Loop (REPL)")
)
.subcommand(App::new(CMD_CHECK)
.about("Build a binary from the given .roc file, but don't run it")
.arg(
Arg::with_name(FLAG_TIME)
.long(FLAG_TIME)
.help("Prints detailed compilation time information.")
.required(false),
)
.arg(
Arg::with_name(ROC_FILE)
.help("The .roc file of an app to run")
.required(true),
)
)
.subcommand(
App::new(CMD_DOCS)
.about("Generate documentation for Roc modules")

View File

@ -1,7 +1,9 @@
use roc_cli::build::check_file;
use roc_cli::{
build_app, docs, repl, BuildConfig, CMD_BUILD, CMD_DOCS, CMD_EDIT, CMD_REPL, CMD_RUN,
DIRECTORY_OR_FILES, ROC_FILE,
build_app, docs, repl, BuildConfig, CMD_BUILD, CMD_CHECK, CMD_DOCS, CMD_EDIT, CMD_REPL,
CMD_RUN, DIRECTORY_OR_FILES, FLAG_TIME, ROC_FILE,
};
use roc_load::file::LoadingProblem;
use std::fs::{self, FileType};
use std::io;
use std::path::{Path, PathBuf};
@ -52,6 +54,31 @@ If you're building the compiler from source you'll want to do `cargo run [FILE]`
Ok(1)
}
Some(CMD_CHECK) => {
let arena = bumpalo::Bump::new();
let matches = matches.subcommand_matches(CMD_CHECK).unwrap();
let emit_timings = matches.is_present(FLAG_TIME);
let filename = matches.value_of(ROC_FILE).unwrap();
let roc_file_path = PathBuf::from(filename);
let src_dir = roc_file_path.parent().unwrap().to_owned();
match check_file(&arena, src_dir, roc_file_path, emit_timings) {
Ok(number_of_errors) => {
let exit_code = if number_of_errors != 0 { 1 } else { 0 };
Ok(exit_code)
}
Err(LoadingProblem::FormattedReport(report)) => {
print!("{}", report);
Ok(1)
}
Err(other) => {
panic!("build_file failed with error:\n{:?}", other);
}
}
}
Some(CMD_REPL) => {
repl::main()?;

View File

@ -107,12 +107,13 @@ pub fn gen_and_eval<'a>(
}
for problem in type_problems {
let report = type_problem(&alloc, module_path.clone(), problem);
let mut buf = String::new();
if let Some(report) = type_problem(&alloc, module_path.clone(), problem) {
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
report.render_color_terminal(&mut buf, &alloc, &palette);
lines.push(buf);
lines.push(buf);
}
}
for problem in mono_problems {

View File

@ -56,7 +56,7 @@ fn find_zig_str_path() -> PathBuf {
return zig_str_path;
}
panic!("cannot find `str.zig`")
panic!("cannot find `str.zig`. Launch me from either the root of the roc repo or one level down(roc/examples, roc/cli...)")
}
fn find_wasi_libc_path() -> PathBuf {

View File

@ -74,18 +74,19 @@ pub fn report_problems(loaded: &mut MonomorphizedModule) -> usize {
let problems = loaded.type_problems.remove(home).unwrap_or_default();
for problem in problems {
let report = type_problem(&alloc, module_path.clone(), problem);
let severity = report.severity;
let mut buf = String::new();
if let Some(report) = type_problem(&alloc, module_path.clone(), problem) {
let severity = report.severity;
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
report.render_color_terminal(&mut buf, &alloc, &palette);
match severity {
Warning => {
warnings.push(buf);
}
RuntimeError => {
errors.push(buf);
match severity {
Warning => {
warnings.push(buf);
}
RuntimeError => {
errors.push(buf);
}
}
}
}

View File

@ -145,12 +145,13 @@ pub fn helper<'a>(
}
for problem in type_problems {
let report = type_problem(&alloc, module_path.clone(), problem);
let mut buf = String::new();
if let Some(report) = type_problem(&alloc, module_path.clone(), problem) {
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
report.render_color_terminal(&mut buf, &alloc, &palette);
lines.push(buf);
lines.push(buf);
}
}
for problem in mono_problems {

View File

@ -1,6 +1,7 @@
use crate::exhaustive::{Ctor, RenderAs, TagId, Union};
use crate::ir::{
BranchInfo, DestructType, Env, Expr, JoinPointId, Literal, Param, Pattern, Procs, Stmt,
BranchInfo, DestructType, Env, Expr, FloatPrecision, IntPrecision, JoinPointId, Literal, Param,
Pattern, Procs, Stmt,
};
use crate::layout::{Builtin, Layout, LayoutCache, UnionLayout};
use roc_collections::all::{MutMap, MutSet};
@ -85,8 +86,8 @@ enum Test<'a> {
union: crate::exhaustive::Union,
arguments: Vec<(Pattern<'a>, Layout<'a>)>,
},
IsInt(i128),
IsFloat(u64),
IsInt(i128, IntPrecision),
IsFloat(u64, FloatPrecision),
IsDecimal(RocDec),
IsStr(Box<str>),
IsBit(bool),
@ -95,6 +96,7 @@ enum Test<'a> {
num_alts: usize,
},
}
use std::hash::{Hash, Hasher};
impl<'a> Hash for Test<'a> {
fn hash<H: Hasher>(&self, state: &mut H) {
@ -106,13 +108,15 @@ impl<'a> Hash for Test<'a> {
tag_id.hash(state);
// The point of this custom implementation is to not hash the tag arguments
}
IsInt(v) => {
IsInt(v, width) => {
state.write_u8(1);
v.hash(state);
width.hash(state);
}
IsFloat(v) => {
IsFloat(v, width) => {
state.write_u8(2);
v.hash(state);
width.hash(state);
}
IsStr(v) => {
state.write_u8(3);
@ -306,8 +310,8 @@ fn tests_are_complete_help(last_test: &Test, number_of_tests: usize) -> bool {
Test::IsCtor { union, .. } => number_of_tests == union.alternatives.len(),
Test::IsByte { num_alts, .. } => number_of_tests == *num_alts,
Test::IsBit(_) => number_of_tests == 2,
Test::IsInt(_) => false,
Test::IsFloat(_) => false,
Test::IsInt(_, _) => false,
Test::IsFloat(_, _) => false,
Test::IsDecimal(_) => false,
Test::IsStr(_) => false,
}
@ -561,8 +565,8 @@ fn test_at_path<'a>(
tag_id: *tag_id,
num_alts: union.alternatives.len(),
},
IntLiteral(v) => IsInt(*v),
FloatLiteral(v) => IsFloat(*v),
IntLiteral(v, precision) => IsInt(*v, *precision),
FloatLiteral(v, precision) => IsFloat(*v, *precision),
DecimalLiteral(v) => IsDecimal(*v),
StrLiteral(v) => IsStr(v.clone()),
};
@ -807,8 +811,9 @@ fn to_relevant_branch_help<'a>(
_ => None,
},
IntLiteral(int) => match test {
IsInt(is_int) if int == *is_int => {
IntLiteral(int, p1) => match test {
IsInt(is_int, p2) if int == *is_int => {
debug_assert_eq!(p1, *p2);
start.extend(end);
Some(Branch {
goal: branch.goal,
@ -819,8 +824,9 @@ fn to_relevant_branch_help<'a>(
_ => None,
},
FloatLiteral(float) => match test {
IsFloat(test_float) if float == *test_float => {
FloatLiteral(float, p1) => match test {
IsFloat(test_float, p2) if float == *test_float => {
debug_assert_eq!(p1, *p2);
start.extend(end);
Some(Branch {
goal: branch.goal,
@ -928,8 +934,8 @@ fn needs_tests(pattern: &Pattern) -> bool {
| AppliedTag { .. }
| BitLiteral { .. }
| EnumLiteral { .. }
| IntLiteral(_)
| FloatLiteral(_)
| IntLiteral(_, _)
| FloatLiteral(_, _)
| DecimalLiteral(_)
| StrLiteral(_) => true,
}
@ -1280,22 +1286,22 @@ fn test_to_equality<'a>(
_ => unreachable!("{:?}", (cond_layout, union)),
}
}
Test::IsInt(test_int) => {
Test::IsInt(test_int, precision) => {
// TODO don't downcast i128 here
debug_assert!(test_int <= i64::MAX as i128);
let lhs = Expr::Literal(Literal::Int(test_int as i128));
let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int64), lhs));
stores.push((lhs_symbol, precision.as_layout(), lhs));
(stores, lhs_symbol, rhs_symbol, None)
}
Test::IsFloat(test_int) => {
Test::IsFloat(test_int, precision) => {
// TODO maybe we can actually use i64 comparison here?
let test_float = f64::from_bits(test_int as u64);
let lhs = Expr::Literal(Literal::Float(test_float));
let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, Layout::Builtin(Builtin::Float64), lhs));
stores.push((lhs_symbol, precision.as_layout(), lhs));
(stores, lhs_symbol, rhs_symbol, None)
}
@ -1303,7 +1309,7 @@ fn test_to_equality<'a>(
Test::IsDecimal(test_dec) => {
let lhs = Expr::Literal(Literal::Int(test_dec.0));
let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, Layout::Builtin(Builtin::Int128), lhs));
stores.push((lhs_symbol, *cond_layout, lhs));
(stores, lhs_symbol, rhs_symbol, None)
}
@ -1737,8 +1743,8 @@ fn decide_to_branching<'a>(
);
let tag = match test {
Test::IsInt(v) => v as u64,
Test::IsFloat(v) => v as u64,
Test::IsInt(v, _) => v as u64,
Test::IsFloat(v, _) => v as u64,
Test::IsBit(v) => v as u64,
Test::IsByte { tag_id, .. } => tag_id as u64,
Test::IsCtor { tag_id, .. } => tag_id as u64,

View File

@ -65,8 +65,8 @@ fn simplify(pattern: &crate::ir::Pattern) -> Pattern {
use crate::ir::Pattern::*;
match pattern {
IntLiteral(v) => Literal(Literal::Int(*v)),
FloatLiteral(v) => Literal(Literal::Float(*v)),
IntLiteral(v, _) => Literal(Literal::Int(*v)),
FloatLiteral(v, _) => Literal(Literal::Float(*v)),
DecimalLiteral(v) => Literal(Literal::Decimal(*v)),
StrLiteral(v) => Literal(Literal::Str(v.clone())),

View File

@ -2774,13 +2774,13 @@ pub fn with_hole<'a>(
IntOrFloat::SignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(int)),
Layout::Builtin(int_precision_to_builtin(precision)),
precision.as_layout(),
hole,
),
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(int)),
Layout::Builtin(int_precision_to_builtin(precision)),
precision.as_layout(),
hole,
),
_ => unreachable!("unexpected float precision for integer"),
@ -2792,7 +2792,7 @@ pub fn with_hole<'a>(
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(float)),
Layout::Builtin(float_precision_to_builtin(precision)),
precision.as_layout(),
hole,
),
IntOrFloat::DecimalFloatType => {
@ -2824,19 +2824,19 @@ pub fn with_hole<'a>(
IntOrFloat::SignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num.into())),
Layout::Builtin(int_precision_to_builtin(precision)),
precision.as_layout(),
hole,
),
IntOrFloat::UnsignedIntType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Int(num.into())),
Layout::Builtin(int_precision_to_builtin(precision)),
precision.as_layout(),
hole,
),
IntOrFloat::BinaryFloatType(precision) => Stmt::Let(
assigned,
Expr::Literal(Literal::Float(num as f64)),
Layout::Builtin(float_precision_to_builtin(precision)),
precision.as_layout(),
hole,
),
IntOrFloat::DecimalFloatType => {
@ -5634,8 +5634,8 @@ fn store_pattern_help<'a>(
// do nothing
return StorePattern::NotProductive(stmt);
}
IntLiteral(_)
| FloatLiteral(_)
IntLiteral(_, _)
| FloatLiteral(_, _)
| DecimalLiteral(_)
| EnumLiteral { .. }
| BitLiteral { .. }
@ -5769,8 +5769,8 @@ fn store_tag_pattern<'a>(
Underscore => {
// ignore
}
IntLiteral(_)
| FloatLiteral(_)
IntLiteral(_, _)
| FloatLiteral(_, _)
| DecimalLiteral(_)
| EnumLiteral { .. }
| BitLiteral { .. }
@ -5845,8 +5845,8 @@ fn store_newtype_pattern<'a>(
Underscore => {
// ignore
}
IntLiteral(_)
| FloatLiteral(_)
IntLiteral(_, _)
| FloatLiteral(_, _)
| DecimalLiteral(_)
| EnumLiteral { .. }
| BitLiteral { .. }
@ -5921,8 +5921,8 @@ fn store_record_destruct<'a>(
// internally. But `y` is never used, so we must make sure it't not stored/loaded.
return StorePattern::NotProductive(stmt);
}
IntLiteral(_)
| FloatLiteral(_)
IntLiteral(_, _)
| FloatLiteral(_, _)
| DecimalLiteral(_)
| EnumLiteral { .. }
| BitLiteral { .. }
@ -6892,8 +6892,8 @@ fn call_specialized_proc<'a>(
pub enum Pattern<'a> {
Identifier(Symbol),
Underscore,
IntLiteral(i128),
FloatLiteral(u64),
IntLiteral(i128, IntPrecision),
FloatLiteral(u64, FloatPrecision),
DecimalLiteral(RocDec),
BitLiteral {
value: bool,
@ -6971,22 +6971,36 @@ fn from_can_pattern_help<'a>(
match can_pattern {
Underscore => Ok(Pattern::Underscore),
Identifier(symbol) => Ok(Pattern::Identifier(*symbol)),
IntLiteral(_, _, int) => Ok(Pattern::IntLiteral(*int as i128)),
IntLiteral(var, _, int) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
IntOrFloat::SignedIntType(precision) | IntOrFloat::UnsignedIntType(precision) => {
Ok(Pattern::IntLiteral(*int as i128, precision))
}
other => {
panic!(
"Invalid precision for int pattern: {:?} has {:?}",
can_pattern, other
)
}
}
}
FloatLiteral(var, float_str, float) => {
// TODO: Can I reuse num_argument_to_int_or_float here if I pass in true?
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, true) {
IntOrFloat::SignedIntType(_) => {
panic!("Invalid percision for float literal = {:?}", var)
IntOrFloat::SignedIntType(_) | IntOrFloat::UnsignedIntType(_) => {
panic!("Invalid precision for float pattern {:?}", var)
}
IntOrFloat::UnsignedIntType(_) => {
panic!("Invalid percision for float literal = {:?}", var)
IntOrFloat::BinaryFloatType(precision) => {
Ok(Pattern::FloatLiteral(f64::to_bits(*float), precision))
}
IntOrFloat::BinaryFloatType(_) => Ok(Pattern::FloatLiteral(f64::to_bits(*float))),
IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(float_str) {
Some(d) => d,
None => panic!("Invalid decimal for float literal = {}. TODO: Make this a nice, user-friendly error message", float_str),
};
Some(d) => d,
None => panic!(
r"Invalid decimal for float literal = {}. TODO: Make this a nice, user-friendly error message",
float_str
),
};
Ok(Pattern::DecimalLiteral(dec))
}
}
@ -7003,9 +7017,15 @@ fn from_can_pattern_help<'a>(
}
NumLiteral(var, num_str, num) => {
match num_argument_to_int_or_float(env.subs, env.ptr_bytes, *var, false) {
IntOrFloat::SignedIntType(_) => Ok(Pattern::IntLiteral(*num as i128)),
IntOrFloat::UnsignedIntType(_) => Ok(Pattern::IntLiteral(*num as i128)),
IntOrFloat::BinaryFloatType(_) => Ok(Pattern::FloatLiteral(*num as u64)),
IntOrFloat::SignedIntType(precision) => {
Ok(Pattern::IntLiteral(*num as i128, precision))
}
IntOrFloat::UnsignedIntType(precision) => {
Ok(Pattern::IntLiteral(*num as i128, precision))
}
IntOrFloat::BinaryFloatType(precision) => {
Ok(Pattern::FloatLiteral(*num as u64, precision))
}
IntOrFloat::DecimalFloatType => {
let dec = match RocDec::from_str(num_str) {
Some(d) => d,
@ -7587,7 +7607,7 @@ fn from_can_record_destruct<'a>(
})
}
#[derive(Debug)]
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum IntPrecision {
Usize,
I128,
@ -7597,11 +7617,45 @@ pub enum IntPrecision {
I8,
}
impl IntPrecision {
pub fn as_layout(&self) -> Layout<'static> {
Layout::Builtin(self.as_builtin())
}
pub fn as_builtin(&self) -> Builtin<'static> {
use IntPrecision::*;
match self {
I128 => Builtin::Int128,
I64 => Builtin::Int64,
I32 => Builtin::Int32,
I16 => Builtin::Int16,
I8 => Builtin::Int8,
Usize => Builtin::Usize,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Hash)]
pub enum FloatPrecision {
F64,
F32,
}
impl FloatPrecision {
pub fn as_layout(&self) -> Layout<'static> {
Layout::Builtin(self.as_builtin())
}
pub fn as_builtin(&self) -> Builtin<'static> {
use FloatPrecision::*;
match self {
F64 => Builtin::Float64,
F32 => Builtin::Float32,
}
}
}
#[derive(Debug)]
pub enum IntOrFloat {
SignedIntType(IntPrecision),
UnsignedIntType(IntPrecision),
@ -7609,26 +7663,6 @@ pub enum IntOrFloat {
DecimalFloatType,
}
fn float_precision_to_builtin(precision: FloatPrecision) -> Builtin<'static> {
use FloatPrecision::*;
match precision {
F64 => Builtin::Float64,
F32 => Builtin::Float32,
}
}
fn int_precision_to_builtin(precision: IntPrecision) -> Builtin<'static> {
use IntPrecision::*;
match precision {
I128 => Builtin::Int128,
I64 => Builtin::Int64,
I32 => Builtin::Int32,
I16 => Builtin::Int16,
I8 => Builtin::Int8,
Usize => Builtin::Usize,
}
}
/// Given the `a` in `Num a`, determines whether it's an int or a float
pub fn num_argument_to_int_or_float(
subs: &Subs,

View File

@ -1192,7 +1192,7 @@ fn not_found<'b>(
alloc.reflow(" missing up-top"),
]);
let default_yes = alloc.reflow("these names seem close though:");
let default_yes = alloc.reflow("Did you mean one of these?");
let to_details = |no_suggestion_details, yes_suggestion_details| {
if suggestions.is_empty() {
@ -1240,7 +1240,7 @@ fn module_not_found<'b>(
]);
let default_yes = alloc
.reflow("Is there an import missing? Perhaps there is a typo, these names seem close:");
.reflow("Is there an import missing? Perhaps there is a typo. Did you mean one of these?");
let to_details = |no_suggestion_details, yes_suggestion_details| {
if suggestions.is_empty() {

View File

@ -16,28 +16,32 @@ pub fn type_problem<'b>(
alloc: &'b RocDocAllocator<'b>,
filename: PathBuf,
problem: solve::TypeError,
) -> Report<'b> {
) -> Option<Report<'b>> {
use solve::TypeError::*;
fn report(title: String, doc: RocDocBuilder<'_>, filename: PathBuf) -> Report<'_> {
Report {
fn report(title: String, doc: RocDocBuilder<'_>, filename: PathBuf) -> Option<Report<'_>> {
Some(Report {
title,
filename,
doc,
severity: Severity::RuntimeError,
}
})
}
match problem {
BadExpr(region, category, found, expected) => {
to_expr_report(alloc, filename, region, category, found, expected)
}
BadPattern(region, category, found, expected) => {
to_pattern_report(alloc, filename, region, category, found, expected)
}
CircularType(region, symbol, overall_type) => {
to_circular_report(alloc, filename, region, symbol, overall_type)
}
BadExpr(region, category, found, expected) => Some(to_expr_report(
alloc, filename, region, category, found, expected,
)),
BadPattern(region, category, found, expected) => Some(to_pattern_report(
alloc, filename, region, category, found, expected,
)),
CircularType(region, symbol, overall_type) => Some(to_circular_report(
alloc,
filename,
region,
symbol,
overall_type,
)),
UnexposedLookup(symbol) => {
let title = "UNRECOGNIZED NAME".to_string();
let doc = alloc
@ -97,6 +101,8 @@ pub fn type_problem<'b>(
report(title, doc, filename)
}
SolvedTypeError => None, // Don't re-report cascading errors - see https://github.com/rtfeldman/roc/pull/1711
other => panic!("unhandled bad type: {:?}", other),
}
}

View File

@ -154,8 +154,9 @@ mod test_reporting {
}
for problem in type_problems {
let report = type_problem(&alloc, filename.clone(), problem.clone());
reports.push(report);
if let Some(report) = type_problem(&alloc, filename.clone(), problem.clone()) {
reports.push(report);
}
}
for problem in mono_problems {
@ -541,7 +542,7 @@ mod test_reporting {
8 4 -> bar baz "yay"
^^^
these names seem close though:
Did you mean one of these?
baz
Nat
@ -739,7 +740,7 @@ mod test_reporting {
<cyan>3<reset><cyan><reset> <white>theAdmin<reset>
<red>^^^^^^^^<reset>
these names seem close though:
Did you mean one of these?
Decimal
Dec
@ -1491,7 +1492,7 @@ mod test_reporting {
2 { foo: 2 } -> foo
^^^
these names seem close though:
Did you mean one of these?
Bool
U8
@ -1947,7 +1948,7 @@ mod test_reporting {
2 f = \_ -> ok 4
^^
these names seem close though:
Did you mean one of these?
U8
f
@ -3634,8 +3635,8 @@ mod test_reporting {
1 Foo.test
^^^^^^^^
Is there an import missing? Perhaps there is a typo, these names seem
close:
Is there an import missing? Perhaps there is a typo. Did you mean one
of these?
Bool
Num
@ -5797,7 +5798,7 @@ mod test_reporting {
1 [ "foo", bar("") ]
^^^
these names seem close though:
Did you mean one of these?
Nat
Str

View File

@ -1778,4 +1778,48 @@ mod gen_num {
u32
);
}
#[test]
fn when_on_i32() {
assert_evals_to!(
indoc!(
r#"
app "test" provides [ main ] to "./platform"
x : I32
x = 0
main : I32
main =
when x is
0 -> 42
_ -> -1
"#
),
42,
i32
);
}
#[test]
fn when_on_i16() {
assert_evals_to!(
indoc!(
r#"
app "test" provides [ main ] to "./platform"
x : I16
x = 0
main : I16
main =
when x is
0 -> 42
_ -> -1
"#
),
42,
i16
);
}
}

View File

@ -143,12 +143,13 @@ fn create_llvm_module<'a>(
}
for problem in type_problems {
let report = type_problem(&alloc, module_path.clone(), problem);
let mut buf = String::new();
if let Some(report) = type_problem(&alloc, module_path.clone(), problem) {
let mut buf = String::new();
report.render_color_terminal(&mut buf, &alloc, &palette);
report.render_color_terminal(&mut buf, &alloc, &palette);
lines.push(buf);
lines.push(buf);
}
}
for problem in mono_problems {

View File

@ -29,10 +29,10 @@ extern fn roc__mainForHost_1_Fx_caller(*const u8, [*]u8, [*]u8) void;
extern fn roc__mainForHost_1_Fx_size() i64;
extern fn roc__mainForHost_1_Fx_result_size() i64;
const Align = extern struct { a: usize, b: usize };
extern fn malloc(size: usize) callconv(.C) ?*align(@alignOf(Align)) c_void;
extern fn realloc(c_ptr: [*]align(@alignOf(Align)) u8, size: usize) callconv(.C) ?*c_void;
extern fn free(c_ptr: [*]align(@alignOf(Align)) u8) callconv(.C) void;
const Align = 2 * @alignOf(usize);
extern fn malloc(size: usize) callconv(.C) ?*align(Align) c_void;
extern fn realloc(c_ptr: [*]align(Align) u8, size: usize) callconv(.C) ?*c_void;
extern fn free(c_ptr: [*]align(Align) u8) callconv(.C) void;
const DEBUG: bool = false;
@ -53,7 +53,7 @@ export fn roc_realloc(c_ptr: *c_void, new_size: usize, old_size: usize, alignmen
stdout.print("realloc: {d} (alignment {d}, old_size {d})\n", .{ c_ptr, alignment, old_size }) catch unreachable;
}
return realloc(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)), new_size);
return realloc(@alignCast(Align, @ptrCast([*]u8, c_ptr)), new_size);
}
export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
@ -62,7 +62,7 @@ export fn roc_dealloc(c_ptr: *c_void, alignment: u32) callconv(.C) void {
stdout.print("dealloc: {d} (alignment {d})\n", .{ c_ptr, alignment }) catch unreachable;
}
free(@alignCast(@alignOf(Align), @ptrCast([*]u8, c_ptr)));
free(@alignCast(Align, @ptrCast([*]u8, c_ptr)));
}
export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
@ -76,7 +76,7 @@ export fn roc_panic(c_ptr: *c_void, tag_id: u32) callconv(.C) void {
const Unit = extern struct {};
pub fn main() u8 {
pub export fn main() callconv(.C) u8 {
const allocator = std.heap.page_allocator;
const size = @intCast(usize, roc__mainForHost_size());