mirror of
https://github.com/roc-lang/roc.git
synced 2024-11-13 09:49:11 +03:00
Merge remote-tracking branch 'origin/trunk' into hello-web
This commit is contained in:
commit
879038fae6
2
.github/workflows/benchmarks.yml
vendored
2
.github/workflows/benchmarks.yml
vendored
@ -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
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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")
|
||||
|
@ -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()?;
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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())),
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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());
|
||||
|
Loading…
Reference in New Issue
Block a user