Merge branch 'trunk' into singleton-to-single

This commit is contained in:
Richard Feldman 2021-03-15 00:42:59 -04:00 committed by GitHub
commit 1f29fc4358
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 1124 additions and 467 deletions

1
Cargo.lock generated
View File

@ -2895,6 +2895,7 @@ dependencies = [
"roc_solve",
"roc_types",
"roc_unify",
"serde_json",
"target-lexicon",
"tempfile",
]

View File

@ -80,6 +80,7 @@ libloading = "0.6"
# This way, GitHub Actions works and nobody's builds get broken.
inkwell = { git = "https://github.com/rtfeldman/inkwell", tag = "llvm10-0.release3" }
target-lexicon = "0.10"
tempfile = "3.1.0"
[dev-dependencies]
pretty_assertions = "0.5.1"

View File

@ -7,10 +7,11 @@ use roc_can::builtins::builtin_defs_map;
use roc_collections::all::MutMap;
use roc_gen::llvm::build::OptLevel;
use roc_load::file::LoadingProblem;
use std::fs;
use std::env;
use std::path::PathBuf;
use std::time::{Duration, SystemTime};
use target_lexicon::Triple;
use tempfile::Builder;
fn report_timing(buf: &mut String, label: &str, duration: Duration) {
buf.push_str(&format!(
@ -52,8 +53,14 @@ pub fn build_file<'a>(
)?;
let path_to_platform = loaded.platform_path.clone();
let app_o_file = roc_file_path.with_file_name("roc_app.o");
let app_o_file = Builder::new()
.prefix("roc_app")
.suffix(".o")
.tempfile()
.map_err(|err| {
todo!("TODO Gracefully handle tempfile creation error {:?}", err);
})?;
let app_o_file = app_o_file.path();
let buf = &mut String::with_capacity(1024);
let mut it = loaded.timings.iter().peekable();
@ -96,13 +103,12 @@ pub fn build_file<'a>(
}
}
let cwd = app_o_file.parent().unwrap();
let cwd = roc_file_path.parent().unwrap();
let binary_path = cwd.join(&*loaded.output_path); // TODO should join ".exe" on Windows
let code_gen_timing = program::gen_from_mono_module(
&arena,
loaded,
roc_file_path,
&roc_file_path,
Triple::host(),
&app_o_file,
opt_level,
@ -119,16 +125,21 @@ pub fn build_file<'a>(
let compilation_end = compilation_start.elapsed().unwrap();
let size = std::fs::metadata(&app_o_file).unwrap().len();
let size = std::fs::metadata(&app_o_file)
.unwrap_or_else(|err| {
panic!(
"Could not open {:?} - which was supposed to have been generated. Error: {:?}",
app_o_file, err
);
})
.len();
if emit_debug_info {
println!(
"\n\nCompilation finished! Here's how long each module took to compile:\n\n{}",
"\n\nCompilation finished!\n\nHere's how long each module took to compile:\n\n{}",
buf
);
println!("\nSuccess! 🎉\n\n\t{}\n", app_o_file.display());
println!(
"Finished compilation and code gen in {} ms\n\nProduced a app.o file of size {:?}\n",
compilation_end.as_millis(),
@ -138,6 +149,7 @@ pub fn build_file<'a>(
// Step 2: link the precompiled host and compiled app
let mut host_input_path = PathBuf::from(cwd);
host_input_path.push(&*path_to_platform);
host_input_path.push("host.o");
@ -161,7 +173,7 @@ pub fn build_file<'a>(
link(
target,
binary_path,
&[host_input_path.as_path().to_str().unwrap(), app_o_file.as_path().to_str().unwrap()],
&[host_input_path.as_path().to_str().unwrap(), app_o_file.to_str().unwrap()],
link_type
)
.map_err(|_| {
@ -177,16 +189,21 @@ pub fn build_file<'a>(
println!("Finished linking in {} ms\n", link_end.as_millis());
}
// Clean up the leftover .o file from the Roc, if possible.
// (If cleaning it up fails, that's fine. No need to take action.)
// TODO compile the app_o_file to a tmpdir, as an extra precaution.
let _ = fs::remove_file(app_o_file);
// If the cmd errored out, return the Err.
cmd_result?;
// If possible, report the generated executable name relative to the current dir.
let generated_filename = binary_path
.strip_prefix(env::current_dir().unwrap())
.unwrap_or(&binary_path);
let total_end = compilation_start.elapsed().unwrap();
println!("Finished entire process in {} ms\n", total_end.as_millis());
println!(
"🎉 Built {} in {} ms",
generated_filename.to_str().unwrap(),
total_end.as_millis()
);
Ok(binary_path)
}

View File

@ -18,6 +18,15 @@ mod cli_run {
use serial_test::serial;
use std::path::Path;
#[cfg(not(target_os = "macos"))]
const ALLOW_VALGRIND: bool = true;
// Disallow valgrind on macOS by default, because it reports a ton
// of false positives. For local development on macOS, feel free to
// change this to true!
#[cfg(target_os = "macos")]
const ALLOW_VALGRIND: bool = false;
fn check_output(
file: &Path,
executable_filename: &str,
@ -49,7 +58,7 @@ mod cli_run {
}
assert!(compile_out.status.success());
let out = if use_valgrind {
let out = if use_valgrind && ALLOW_VALGRIND {
let (valgrind_out, raw_xml) = run_with_valgrind(
stdin_str,
&[file.with_file_name(executable_filename).to_str().unwrap()],

View File

@ -5,6 +5,21 @@ const testing = std.testing;
const expectEqual = testing.expectEqual;
const expect = testing.expect;
comptime {
// This is a workaround for https://github.com/ziglang/zig/issues/8218
// which is only necessary on macOS.
//
// Once that issue is fixed, we can undo the changes in
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
// -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
const mem = std.mem;
const Allocator = mem.Allocator;

View File

@ -5,6 +5,20 @@ const testing = std.testing;
const expectEqual = testing.expectEqual;
const expect = testing.expect;
comptime {
// This is a workaround for https://github.com/ziglang/zig/issues/8218
// which is only necessary on macOS.
//
// Once that issue is fixed, we can undo the changes in
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
// -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
const mem = std.mem;
const Allocator = mem.Allocator;

View File

@ -27,6 +27,7 @@ bumpalo = { version = "3.2", features = ["collections"] }
inlinable_string = "0.1.0"
libloading = "0.6"
tempfile = "3.1.0"
serde_json = "1.0"
# NOTE: rtfeldman/inkwell is a fork of TheDan64/inkwell which does not change anything.
#
# The reason for this fork is that the way Inkwell is designed, you have to use

View File

@ -55,6 +55,109 @@ fn find_zig_str_path() -> PathBuf {
panic!("cannot find `str.zig`")
}
#[cfg(not(target_os = "macos"))]
fn build_zig_host(
env_path: &str,
env_home: &str,
emit_bin: &str,
zig_host_src: &str,
zig_str_path: &str,
) -> Output {
Command::new("zig")
.env_clear()
.env("PATH", env_path)
.env("HOME", env_home)
.args(&[
"build-obj",
zig_host_src,
emit_bin,
"--pkg-begin",
"str",
zig_str_path,
"--pkg-end",
// include the zig runtime
"-fcompiler-rt",
// include libc
"--library",
"c",
])
.output()
.unwrap()
}
#[cfg(target_os = "macos")]
fn build_zig_host(
env_path: &str,
env_home: &str,
emit_bin: &str,
zig_host_src: &str,
zig_str_path: &str,
) -> Output {
use serde_json::Value;
// Run `zig env` to find the location of zig's std/ directory
let zig_env_output = Command::new("zig").args(&["env"]).output().unwrap();
let zig_env_json = if zig_env_output.status.success() {
std::str::from_utf8(&zig_env_output.stdout).unwrap_or_else(|utf8_err| {
panic!(
"`zig env` failed; its stderr output was invalid utf8 ({:?})",
utf8_err
);
})
} else {
match std::str::from_utf8(&zig_env_output.stderr) {
Ok(stderr) => panic!("`zig env` failed - stderr output was: {:?}", stderr),
Err(utf8_err) => panic!(
"`zig env` failed; its stderr output was invalid utf8 ({:?})",
utf8_err
),
}
};
let mut zig_compiler_rt_path = match serde_json::from_str(zig_env_json) {
Ok(Value::Object(map)) => match map.get("std_dir") {
Some(Value::String(std_dir)) => PathBuf::from(Path::new(std_dir)),
_ => {
panic!("Expected JSON containing a `std_dir` String field from `zig env`, but got: {:?}", zig_env_json);
}
},
_ => {
panic!(
"Expected JSON containing a `std_dir` field from `zig env`, but got: {:?}",
zig_env_json
);
}
};
zig_compiler_rt_path.push("special");
zig_compiler_rt_path.push("compiler_rt.zig");
Command::new("zig")
.env_clear()
.env("PATH", &env_path)
.env("HOME", &env_home)
.args(&[
"build-obj",
zig_host_src,
&emit_bin,
"--pkg-begin",
"str",
zig_str_path,
"--pkg-end",
// include the zig runtime
"--pkg-begin",
"compiler_rt",
zig_compiler_rt_path.to_str().unwrap(),
"--pkg-end",
// include libc
"--library",
"c",
])
.output()
.unwrap()
}
pub fn rebuild_host(host_input_path: &Path) {
let c_host_src = host_input_path.with_file_name("host.c");
let c_host_dest = host_input_path.with_file_name("c_host.o");
@ -79,28 +182,17 @@ pub fn rebuild_host(host_input_path: &Path) {
&zig_str_path
);
let output = Command::new("zig")
.env_clear()
.env("PATH", &env_path)
.env("HOME", &env_home)
.args(&[
"build-obj",
zig_host_src.to_str().unwrap(),
validate_output(
"host.zig",
"zig",
build_zig_host(
&env_path,
&env_home,
&emit_bin,
"--pkg-begin",
"str",
zig_host_src.to_str().unwrap(),
zig_str_path.to_str().unwrap(),
"--pkg-end",
// include the zig runtime
"-fcompiler-rt",
// include libc
"--library",
"c",
])
.output()
.unwrap();
validate_output("host.zig", "zig", output);
),
);
} else {
// Compile host.c
let output = Command::new("clang")
@ -351,7 +443,11 @@ fn link_macos(
// Don't allow LD_ env vars to affect this
.env_clear()
.args(&[
"--gc-sections",
// NOTE: we don't do --gc-sections on macOS because the default
// macOS linker doesn't support it, but it's a performance
// optimization, so if we ever switch to a different linker,
// we'd like to re-enable it on macOS!
// "--gc-sections",
link_type_arg,
"-arch",
target.architecture.to_string().as_str(),

View File

@ -23,7 +23,7 @@ pub struct CodeGenTiming {
pub fn gen_from_mono_module(
arena: &Bump,
mut loaded: MonomorphizedModule,
_file_path: PathBuf,
roc_file_path: &Path,
target: Triple,
app_o_file: &Path,
opt_level: OptLevel,
@ -92,7 +92,7 @@ pub fn gen_from_mono_module(
use inkwell::module::Linkage;
let app_ll_file = {
let mut temp = std::path::PathBuf::from(app_o_file);
let mut temp = PathBuf::from(roc_file_path);
temp.set_extension("ll");
temp
@ -215,10 +215,10 @@ pub fn gen_from_mono_module(
if emit_debug_info {
module.strip_debug_info();
let mut app_ll_dbg_file = std::path::PathBuf::from(app_o_file);
let mut app_ll_dbg_file = PathBuf::from(roc_file_path);
app_ll_dbg_file.set_extension("dbg.ll");
let mut app_bc_file = std::path::PathBuf::from(app_o_file);
let mut app_bc_file = PathBuf::from(roc_file_path);
app_bc_file.set_extension("bc");
use std::process::Command;

View File

@ -420,6 +420,9 @@ fn binop_to_function(binop: BinOp) -> (&'static str, &'static str) {
And => (ModuleName::BOOL, "and"),
Or => (ModuleName::BOOL, "or"),
Pizza => unreachable!("Cannot desugar the |> operator"),
Assignment => unreachable!("Cannot desugar the = operator"),
HasType => unreachable!("Cannot desugar the : operator"),
Backpassing => unreachable!("Cannot desugar the <- operator"),
}
}

View File

@ -390,6 +390,9 @@ fn fmt_bin_op<'a>(
operator::BinOp::And => buf.push_str("&&"),
operator::BinOp::Or => buf.push_str("||"),
operator::BinOp::Pizza => buf.push_str("|>"),
operator::BinOp::Assignment => unreachable!(),
operator::BinOp::HasType => unreachable!(),
operator::BinOp::Backpassing => unreachable!(),
}
buf.push(' ');

View File

@ -42,6 +42,9 @@ pub enum BinOp {
And,
Or,
Pizza, // lowest precedence
Assignment,
HasType,
Backpassing,
}
#[derive(Clone, Debug, PartialEq, Eq)]
@ -83,6 +86,7 @@ impl BinOp {
Equals | NotEquals | LessThan | GreaterThan | LessThanOrEq | GreaterThanOrEq => {
NonAssociative
}
Assignment | HasType | Backpassing => unreachable!(),
}
}
@ -95,6 +99,7 @@ impl BinOp {
And => 3,
Or => 2,
Pizza => 1,
Assignment | HasType | Backpassing => unreachable!(),
}
}
}
@ -131,6 +136,9 @@ impl std::fmt::Display for BinOp {
And => "&&",
Or => "||",
Pizza => "|>",
Assignment => "=",
HasType => ":",
Backpassing => "<-",
};
write!(f, "{}", as_str)

View File

@ -117,6 +117,22 @@ where
)
}
pub fn check_indent<'a, E>(
min_indent: u16,
indent_problem: fn(Row, Col) -> E,
) -> impl Parser<'a, (), E>
where
E: 'a,
{
move |_, state: State<'a>| {
if state.column > min_indent {
Ok((NoProgress, (), state))
} else {
Err((NoProgress, indent_problem(state.line, state.column), state))
}
}
}
pub fn space0_e<'a, E>(
min_indent: u16,
space_problem: fn(BadInputError, Row, Col) -> E,
@ -128,28 +144,6 @@ where
spaces_help_help(min_indent, space_problem, indent_problem)
}
pub fn space1_e<'a, E>(
min_indent: u16,
space_problem: fn(BadInputError, Row, Col) -> E,
indent_problem: fn(Row, Col) -> E,
no_parse_problem: fn(Row, Col) -> E,
) -> impl Parser<'a, &'a [CommentOrNewline<'a>], E>
where
E: 'a,
{
move |arena, state| match space0_e(min_indent, space_problem, indent_problem)
.parse(arena, state)
{
Ok((NoProgress, _, state)) => Err((
NoProgress,
no_parse_problem(state.line, state.column),
state,
)),
Ok((MadeProgress, spaces, state)) => Ok((MadeProgress, spaces, state)),
Err(bad) => Err(bad),
}
}
pub fn spaces_till_end_of_line<'a, E: 'a>(
tab_problem: fn(Row, Col) -> E,
) -> impl Parser<'a, Option<&'a str>, E> {

File diff suppressed because it is too large Load Diff

View File

@ -254,7 +254,12 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
if state.has_reached_end() {
Ok((NoProgress, (), state))
} else {
Err((NoProgress, SyntaxError::ConditionFailed, state))
dbg!(state);
Err((
NoProgress,
SyntaxError::NotEndOfFile(state.line, state.column),
state,
))
}
}
}

View File

@ -11,6 +11,20 @@ pub enum NumLiteral<'a> {
},
}
pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> {
move |_arena, state: State<'a>| {
match state.bytes.get(0) {
Some(first_byte) if (*first_byte as char).is_ascii_digit() => {
parse_number_base(false, &state.bytes, state)
}
_ => {
// this is not a number at all
Err((Progress::NoProgress, Number::End, state))
}
}
}
}
pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, Number> {
move |_arena, state: State<'a>| {
match state.bytes.get(0) {

View File

@ -1,6 +1,6 @@
use bumpalo::collections::vec::Vec;
use bumpalo::Bump;
use roc_region::all::{Located, Region};
use roc_region::all::{Located, Position, Region};
use std::fmt;
use Progress::*;
@ -37,7 +37,15 @@ impl<'a> State<'a> {
}
/// Returns whether the parser has reached the end of the input
pub fn has_reached_end(&self) -> bool {
pub const fn get_position(&self) -> Position {
Position {
row: self.line,
col: self.column,
}
}
/// Returns whether the parser has reached the end of the input
pub const fn has_reached_end(&self) -> bool {
self.bytes.is_empty()
}
@ -183,6 +191,7 @@ pub enum SyntaxError<'a> {
Expr(EExpr<'a>),
Header(EHeader<'a>),
Space(BadInputError),
NotEndOfFile(Row, Col),
}
#[derive(Debug, Clone, PartialEq, Eq)]

View File

@ -640,6 +640,33 @@ mod test_parse {
assert_eq!(Ok(expected), actual);
}
#[test]
fn newline_and_spaces_before_less_than() {
let arena = Bump::new();
let spaced_int = arena.alloc(Num("1")).after(&[Newline]);
let tuple = arena.alloc((
Located::new(0, 0, 4, 5, spaced_int),
Located::new(1, 1, 4, 5, LessThan),
Located::new(1, 1, 6, 7, Num("2")),
));
let newlines = bumpalo::vec![in &arena; Newline, Newline];
let def = Def::Body(
arena.alloc(Located::new(0, 0, 0, 1, Identifier("x"))),
arena.alloc(Located::new(0, 1, 4, 7, BinOp(tuple))),
);
let loc_def = &*arena.alloc(Located::new(0, 1, 0, 7, def));
let defs = &[loc_def];
let ret = Expr::SpaceBefore(arena.alloc(Num("42")), newlines.into_bump_slice());
let loc_ret = Located::new(3, 3, 0, 2, ret);
let expected = Defs(defs, arena.alloc(loc_ret));
// let expected = BinOp(tuple);
let actual = parse_expr_with(&arena, "x = 1\n < 2\n\n42");
assert_eq!(Ok(expected), actual);
}
#[test]
fn comment_with_non_ascii() {
let arena = Bump::new();
@ -1314,21 +1341,18 @@ mod test_parse {
},
));
let args = &[&*arg1, &*arg2];
let apply_expr = Expr::Apply(
arena.alloc(Located::new(
0,
0,
1,
5,
Var {
module_name: "",
ident: "whee",
},
)),
args,
CalledVia::Space,
let function = Located::new(
0,
0,
1,
5,
Var {
module_name: "",
ident: "whee",
},
);
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 1, 13, apply_expr)), loc_op);
let unary = Located::new(0, 0, 0, 5, UnaryOp(arena.alloc(function), loc_op));
let expected = Expr::Apply(arena.alloc(unary), args, CalledVia::Space);
let actual = parse_expr_with(&arena, "-whee 12 foo");
assert_eq!(Ok(expected), actual);
@ -1350,21 +1374,19 @@ mod test_parse {
},
));
let args = &[&*arg1, &*arg2];
let apply_expr = Expr::Apply(
arena.alloc(Located::new(
0,
0,
1,
5,
Var {
module_name: "",
ident: "whee",
},
)),
args,
CalledVia::Space,
let function = Located::new(
0,
0,
1,
5,
Var {
module_name: "",
ident: "whee",
},
);
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 1, 13, apply_expr)), loc_op);
let unary = Located::new(0, 0, 0, 5, UnaryOp(arena.alloc(function), loc_op));
let expected = Expr::Apply(arena.alloc(unary), args, CalledVia::Space);
let actual = parse_expr_with(&arena, "!whee 12 foo");
assert_eq!(Ok(expected), actual);
@ -1400,7 +1422,7 @@ mod test_parse {
args,
CalledVia::Space,
)));
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 1, 15, apply_expr)), loc_op);
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 2, 14, apply_expr)), loc_op);
let actual = parse_expr_with(&arena, "-(whee 12 foo)");
assert_eq!(Ok(expected), actual);
@ -1436,7 +1458,7 @@ mod test_parse {
args,
CalledVia::Space,
)));
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 1, 15, apply_expr)), loc_op);
let expected = UnaryOp(arena.alloc(Located::new(0, 0, 2, 14, apply_expr)), loc_op);
let actual = parse_expr_with(&arena, "!(whee 12 foo)");
assert_eq!(Ok(expected), actual);

View File

@ -3,7 +3,7 @@ use std::fmt;
/// TODO replace Located with this
pub type Loc<T> = Located<T>;
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
pub struct Region {
pub start_line: u32,
pub end_line: u32,
@ -107,6 +107,20 @@ impl Region {
end_line,
}
}
pub const fn start(&self) -> Position {
Position {
row: self.start_line,
col: self.start_col,
}
}
pub const fn end(&self) -> Position {
Position {
row: self.end_line,
col: self.end_col,
}
}
}
#[test]
@ -132,6 +146,12 @@ impl fmt::Debug for Region {
}
}
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Default)]
pub struct Position {
pub row: u32,
pub col: u16,
}
#[derive(Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct Located<T> {
pub region: Region,

View File

@ -125,6 +125,22 @@ fn to_syntax_report<'a>(
report(doc)
}
NotEndOfFile(row, col) => {
let surroundings = Region::from_rows_cols(start_row, start_col, *row, *col);
let region = Region::from_row_col(*row, *col);
let doc = alloc.stack(vec![
alloc.reflow(r"I expected to reach the end of the file, but got stuck here:"),
alloc.region_with_subregion(surroundings, region),
alloc.concat(vec![alloc.reflow("no hints")]),
]);
Report {
filename,
doc,
title: "NOT END OF FILE".to_string(),
}
}
SyntaxError::Eof(region) => {
let doc = alloc.stack(vec![alloc.reflow("End of Field"), alloc.region(*region)]);
@ -393,7 +409,7 @@ fn to_expr_report<'a>(
alloc.vcat(vec![
alloc.text("x = 4").indent(4),
alloc.text("y = 2").indent(4),
alloc.text("").indent(4),
alloc.text(""),
alloc.text("x + y").indent(4),
]),
]);
@ -2702,7 +2718,7 @@ fn to_provides_report<'a>(
.reflow(r"I am partway through parsing a provides list, but I got stuck here:"),
alloc.region_with_subregion(surroundings, region),
alloc.concat(vec![alloc.reflow(
"I was expecting a type name, value name or function name next, like ",
"I was expecting a type name, value name or function name next, like",
)]),
alloc
.parser_suggestion("provides [ Animal, default, tame ]")
@ -2764,7 +2780,7 @@ fn to_exposes_report<'a>(
alloc.reflow(r"I am partway through parsing a exposes list, but I got stuck here:"),
alloc.region_with_subregion(surroundings, region),
alloc.concat(vec![alloc.reflow(
"I was expecting a type name, value name or function name next, like ",
"I was expecting a type name, value name or function name next, like",
)]),
alloc
.parser_suggestion("exposes [ Animal, default, tame ]")

View File

@ -65,6 +65,7 @@ mod test_reporting {
problems: can_problems,
..
} = can_expr(arena, expr_src)?;
dbg!(&loc_expr);
let mut subs = Subs::new(var_store.into());
for (var, name) in output.introduced_variables.name_by_var {
@ -4124,12 +4125,12 @@ mod test_reporting {
indoc!(
r#"
SYNTAX PROBLEM
I trying to parse a record field access here:
1 foo.bar.
^
So I expect to see a lowercase letter next, like .name or .height.
"#
),
@ -4147,12 +4148,12 @@ mod test_reporting {
indoc!(
r#"
SYNTAX PROBLEM
I am very confused by this expression:
1 @Foo.Bar
^^^^
Looks like a private tag is treated like a module name. Maybe you
wanted a qualified name, like Json.Decode.string?
"#
@ -4199,18 +4200,18 @@ mod test_reporting {
x == 5
Num.add 1 2
x y
{ x, y }
"#
),
indoc!(
r#"
TOO MANY ARGS
The `add` function expects 2 arguments, but it got 4 instead:
4 Num.add 1 2
^^^^^^^
This value is not a function, but it was given 3 arguments:
3 x == 5
^
Are there any missing commas? Or missing parentheses?
"#
),
@ -4679,18 +4680,18 @@ mod test_reporting {
indoc!(
r#"
MISSING FINAL EXPRESSION
I am partway through parsing a definition, but I got stuck here:
1 f : Foo.foo
^
This definition is missing a final expression. A nested definition
must be followed by either another definition, or an expression
x = 4
y = 2
x + y
"#
),
@ -5055,13 +5056,13 @@ mod test_reporting {
indoc!(
r#"
UNFINISHED ARGUMENT LIST
I am partway through parsing a function argument list, but I got stuck
at this comma:
1 \a,,b -> 1
^
I was expecting an argument pattern before this, so try adding an
argument before the comma and see if that helps?
"#
@ -5080,13 +5081,13 @@ mod test_reporting {
indoc!(
r#"
UNFINISHED ARGUMENT LIST
I am partway through parsing a function argument list, but I got stuck
at this comma:
1 \,b -> 1
^
I was expecting an argument pattern before this, so try adding an
argument before the comma and see if that helps?
"#
@ -5488,12 +5489,12 @@ mod test_reporting {
indoc!(
r#"
SYNTAX PROBLEM
I trying to parse a record field access here:
1 Num.add . 23
^
So I expect to see a lowercase letter next, like .name or .height.
"#
),
@ -5727,22 +5728,24 @@ mod test_reporting {
indoc!(
r#"
main =
5 : I64
(\x -> x) : I64
3
"#
),
indoc!(
r#"
UNKNOWN OPERATOR
This looks like an operator, but it's not one I recognize!
1 main =
2 5 : I64
^
2 (\x -> x) : I64
^
The has-type operator : can only occur in a definition's type
signature, like
increment : I64 -> I64
increment = \x -> x + 1
"#
@ -5789,15 +5792,15 @@ mod test_reporting {
indoc!(
r#"
WEIRD PROVIDES
I am partway through parsing a provides list, but I got stuck here:
3 imports [base.Task, Base64 ]
4 provides [ main, @Foo ] to base
^
I was expecting a type name, value name or function name next, like
I was expecting a type name, value name or function name next, like
provides [ Animal, default, tame ]
"#
),
@ -5809,7 +5812,7 @@ mod test_reporting {
report_header_problem_as(
indoc!(
r#"
interface Foobar
interface Foobar
exposes [ main, @Foo ]
imports [base.Task, Base64 ]
"#
@ -5817,15 +5820,15 @@ mod test_reporting {
indoc!(
r#"
WEIRD EXPOSES
I am partway through parsing a exposes list, but I got stuck here:
1 interface Foobar
1 interface Foobar
2 exposes [ main, @Foo ]
^
I was expecting a type name, value name or function name next, like
I was expecting a type name, value name or function name next, like
exposes [ Animal, default, tame ]
"#
),
@ -5837,7 +5840,7 @@ mod test_reporting {
report_header_problem_as(
indoc!(
r#"
interface foobar
interface foobar
exposes [ main, @Foo ]
imports [base.Task, Base64 ]
"#
@ -5845,12 +5848,12 @@ mod test_reporting {
indoc!(
r#"
WEIRD MODULE NAME
I am partway through parsing a header, but got stuck here:
1 interface foobar
1 interface foobar
^
I am expecting a module name next, like BigNum or Main. Module names
must start with an uppercase letter.
"#
@ -5863,7 +5866,7 @@ mod test_reporting {
report_header_problem_as(
indoc!(
r#"
app foobar
app foobar
exposes [ main, @Foo ]
imports [base.Task, Base64 ]
"#
@ -5871,16 +5874,66 @@ mod test_reporting {
indoc!(
r#"
WEIRD APP NAME
I am partway through parsing a header, but got stuck here:
1 app foobar
1 app foobar
^
I am expecting an application name next, like app "main" or
app "editor". App names are surrounded by quotation marks.
"#
),
)
}
#[test]
fn apply_unary_negative() {
report_problem_as(
indoc!(
r#"
foo = 3
-foo 1 2
"#
),
indoc!(
r#"
TOO MANY ARGS
This value is not a function, but it was given 2 arguments:
3 -foo 1 2
^^^^
Are there any missing commas? Or missing parentheses?
"#
),
)
}
#[test]
fn apply_unary_not() {
report_problem_as(
indoc!(
r#"
foo = True
!foo 1 2
"#
),
indoc!(
r#"
TOO MANY ARGS
This value is not a function, but it was given 2 arguments:
3 !foo 1 2
^^^^
Are there any missing commas? Or missing parentheses?
"#
),
)
}
}

View File

@ -738,7 +738,9 @@ fn list_repeat() {
RocList<i64>
);
assert_evals_to!("List.repeat 2 []", &[&[], &[]], &'static [&'static [i64]]);
let empty_lists: &'static [&'static [i64]] = &[&[], &[]];
assert_evals_to!("List.repeat 2 []", empty_lists, &'static [&'static [i64]]);
assert_evals_to!(
indoc!(
r#"
@ -749,7 +751,7 @@ fn list_repeat() {
List.repeat 2 noStrs
"#
),
&[&[], &[]],
empty_lists,
&'static [&'static [i64]]
);

View File

@ -196,6 +196,8 @@ fn contains() {
#[test]
fn from_list() {
let empty_list: &'static [i64] = &[];
assert_evals_to!(
indoc!(
r#"
@ -216,7 +218,7 @@ fn from_list() {
|> Set.toList
"#
),
&[],
empty_list,
&[i64]
);
@ -231,7 +233,7 @@ fn from_list() {
|> Set.toList
"#
),
&[],
empty_list,
&[i64]
);
}

4
examples/.gitignore vendored
View File

@ -8,4 +8,8 @@ benchmarks/nqueens
benchmarks/deriv
benchmarks/cfold
benchmarks/rbtree-insert
benchmarks/rbtree-del
benchmarks/closure
benchmarks/test-astar
benchmarks/test-base64
effect-example

Binary file not shown.

View File

@ -6,6 +6,20 @@ const expectEqual = testing.expectEqual;
const expect = testing.expect;
const maxInt = std.math.maxInt;
comptime {
// This is a workaround for https://github.com/ziglang/zig/issues/8218
// which is only necessary on macOS.
//
// Once that issue is fixed, we can undo the changes in
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
// -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
const mem = std.mem;
const Allocator = mem.Allocator;

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -5,6 +5,20 @@ const testing = std.testing;
const expectEqual = testing.expectEqual;
const expect = testing.expect;
comptime {
// This is a workaround for https://github.com/ziglang/zig/issues/8218
// which is only necessary on macOS.
//
// Once that issue is fixed, we can undo the changes in
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
// -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
const mem = std.mem;
const Allocator = mem.Allocator;

View File

@ -3,6 +3,20 @@ const testing = std.testing;
const expectEqual = testing.expectEqual;
const expect = testing.expect;
comptime {
// This is a workaround for https://github.com/ziglang/zig/issues/8218
// which is only necessary on macOS.
//
// Once that issue is fixed, we can undo the changes in
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
// -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
const mem = std.mem;
const Allocator = mem.Allocator;

View File

@ -5,6 +5,20 @@ const testing = std.testing;
const expectEqual = testing.expectEqual;
const expect = testing.expect;
comptime {
// This is a workaround for https://github.com/ziglang/zig/issues/8218
// which is only necessary on macOS.
//
// Once that issue is fixed, we can undo the changes in
// 177cf12e0555147faa4d436e52fc15175c2c4ff0 and go back to passing
// -fcompiler-rt in link.rs instead of doing this. Note that this
// workaround is present in many host.zig files, so make sure to undo
// it everywhere!
if (std.builtin.os.tag == .macos) {
_ = @import("compiler_rt");
}
}
const mem = std.mem;
const Allocator = mem.Allocator;