mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-02 16:21:11 +00:00
Merge remote-tracking branch 'origin/trunk' into precedence-error
This commit is contained in:
commit
604dbf7215
19 changed files with 226 additions and 56 deletions
|
@ -32,7 +32,9 @@ Create `~/.config/cargo` and add this to it:
|
||||||
|
|
||||||
```
|
```
|
||||||
[build]
|
[build]
|
||||||
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
|
# Link with lld, per https://github.com/rust-lang/rust/issues/39915#issuecomment-538049306
|
||||||
|
# Use target-cpu=native, per https://deterministic.space/high-performance-rust.html
|
||||||
|
rustflags = ["-C", "link-arg=-fuse-ld=lld", "-C", "target-cpu=native"]
|
||||||
```
|
```
|
||||||
|
|
||||||
Then install `lld` version 9 (e.g. with `$ sudo apt-get install lld-9`)
|
Then install `lld` version 9 (e.g. with `$ sudo apt-get install lld-9`)
|
||||||
|
|
4
Cargo.lock
generated
4
Cargo.lock
generated
|
@ -568,6 +568,10 @@ dependencies = [
|
||||||
"roc_types",
|
"roc_types",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "roc_builtins_bitcode"
|
||||||
|
version = "0.1.0"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roc_can"
|
name = "roc_can"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
|
@ -10,6 +10,7 @@ members = [
|
||||||
"compiler/types",
|
"compiler/types",
|
||||||
"compiler/uniq",
|
"compiler/uniq",
|
||||||
"compiler/builtins",
|
"compiler/builtins",
|
||||||
|
"compiler/builtins/bitcode",
|
||||||
"compiler/constrain",
|
"compiler/constrain",
|
||||||
"compiler/unify",
|
"compiler/unify",
|
||||||
"compiler/solve",
|
"compiler/solve",
|
||||||
|
@ -23,3 +24,7 @@ members = [
|
||||||
"cli"
|
"cli"
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# Optimizations based on https://deterministic.space/high-performance-rust.html
|
||||||
|
[profile.release]
|
||||||
|
lto = "fat"
|
||||||
|
codegen-units = 1
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
mkdir -p $HOME/.cargo
|
mkdir -p $HOME/.cargo
|
||||||
echo -e "[build]\nrustflags = [\"-C\", \"link-arg=-fuse-ld=lld\"]" > $HOME/.cargo/config
|
echo -e "[build]\nrustflags = [\"-C\", \"link-arg=-fuse-ld=lld\", \"-C\", \"target-cpu=native\"]" > $HOME/.cargo/config
|
||||||
|
|
||||||
ln -s /usr/bin/lld-8 /usr/local/bin/ld.lld
|
ln -s /usr/bin/lld-8 /usr/local/bin/ld.lld
|
||||||
|
|
|
@ -8,7 +8,9 @@ use inkwell::passes::PassManager;
|
||||||
use inkwell::types::BasicType;
|
use inkwell::types::BasicType;
|
||||||
use inkwell::OptimizationLevel;
|
use inkwell::OptimizationLevel;
|
||||||
use roc_collections::all::ImMap;
|
use roc_collections::all::ImMap;
|
||||||
use roc_gen::llvm::build::{build_proc, build_proc_header, get_call_conventions};
|
use roc_gen::llvm::build::{
|
||||||
|
build_proc, build_proc_header, get_call_conventions, module_from_builtins,
|
||||||
|
};
|
||||||
use roc_gen::llvm::convert::basic_type_from_layout;
|
use roc_gen::llvm::convert::basic_type_from_layout;
|
||||||
use roc_mono::expr::{Expr, Procs};
|
use roc_mono::expr::{Expr, Procs};
|
||||||
use roc_mono::layout::Layout;
|
use roc_mono::layout::Layout;
|
||||||
|
@ -65,7 +67,7 @@ fn gen(src: &str, target: Triple, dest_filename: &Path) {
|
||||||
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
||||||
|
|
||||||
let context = Context::create();
|
let context = Context::create();
|
||||||
let module = context.create_module("app");
|
let module = module_from_builtins(&context, "app");
|
||||||
let builder = context.create_builder();
|
let builder = context.create_builder();
|
||||||
let fpm = PassManager::create(&module);
|
let fpm = PassManager::create(&module);
|
||||||
|
|
||||||
|
@ -74,17 +76,14 @@ fn gen(src: &str, target: Triple, dest_filename: &Path) {
|
||||||
fpm.initialize();
|
fpm.initialize();
|
||||||
|
|
||||||
// Compute main_fn_type before moving subs to Env
|
// Compute main_fn_type before moving subs to Env
|
||||||
let pointer_bytes = target.pointer_width().unwrap().bytes() as u32;
|
let ptr_bytes = target.pointer_width().unwrap().bytes() as u32;
|
||||||
let layout = Layout::from_content(&arena, content, &subs, pointer_bytes)
|
let layout = Layout::from_content(&arena, content, &subs, ptr_bytes).unwrap_or_else(|err| {
|
||||||
.unwrap_or_else(|err| panic!("Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}", err, subs));
|
panic!(
|
||||||
|
"Code gen error in test: could not convert to layout. Err was {:?} and Subs were {:?}",
|
||||||
|
err, subs
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
let execution_engine = module
|
|
||||||
.create_jit_execution_engine(OptimizationLevel::None)
|
|
||||||
.expect("Error creating JIT execution engine for test");
|
|
||||||
|
|
||||||
let ptr_bytes = execution_engine
|
|
||||||
.get_target_data()
|
|
||||||
.get_pointer_byte_size(None);
|
|
||||||
let main_fn_type =
|
let main_fn_type =
|
||||||
basic_type_from_layout(&arena, &context, &layout, ptr_bytes).fn_type(&[], false);
|
basic_type_from_layout(&arena, &context, &layout, ptr_bytes).fn_type(&[], false);
|
||||||
let main_fn_name = "$Test.main";
|
let main_fn_name = "$Test.main";
|
||||||
|
@ -109,7 +108,7 @@ fn gen(src: &str, target: Triple, dest_filename: &Path) {
|
||||||
&mut procs,
|
&mut procs,
|
||||||
home,
|
home,
|
||||||
&mut ident_ids,
|
&mut ident_ids,
|
||||||
pointer_bytes,
|
ptr_bytes,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Put this module's ident_ids back in the interns, so we can use them in env.
|
// Put this module's ident_ids back in the interns, so we can use them in env.
|
||||||
|
|
13
compiler/builtins/bitcode/Cargo.toml
Normal file
13
compiler/builtins/bitcode/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
[package]
|
||||||
|
name = "roc_builtins_bitcode"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Richard Feldman <richard.t.feldman@gmail.com>"]
|
||||||
|
repository = "https://github.com/rtfeldman/roc"
|
||||||
|
readme = "README.md"
|
||||||
|
edition = "2018"
|
||||||
|
description = "Generate LLVM bitcode for Roc builtins"
|
||||||
|
license = "Apache-2.0"
|
||||||
|
|
||||||
|
|
||||||
|
[build]
|
||||||
|
target-dir="~/code/roc/copmiler/builtins/bitcode/"
|
56
compiler/builtins/bitcode/README.md
Normal file
56
compiler/builtins/bitcode/README.md
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
# Bitcode for Builtins
|
||||||
|
|
||||||
|
Roc's builtins are implemented in the compiler using LLVM only.
|
||||||
|
When their implementations are simple enough (e.g. addition), they
|
||||||
|
can be implemented directly in Inkwell.
|
||||||
|
|
||||||
|
When their implementations are complex enough, it's nicer to
|
||||||
|
implement them in a higher-level language like Rust, compile the
|
||||||
|
result to LLVM bitcode, and import that bitcode into the compiler.
|
||||||
|
|
||||||
|
Here is the process for doing that.
|
||||||
|
|
||||||
|
## Building the bitcode
|
||||||
|
|
||||||
|
The source we'll use to generate the bitcode is in `src/lib.rs` in this directory.
|
||||||
|
|
||||||
|
To generate the bitcode, `cd` into `compiler/builtins/bitcode/` and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
$ cargo rustc --release --lib -- --emit=llvm-bc
|
||||||
|
```
|
||||||
|
|
||||||
|
Then look in the root `roc` source directory under `target/release/deps/` for a file
|
||||||
|
with a name like `roc_builtins_bitcode-8da0901c58a73ebf.bc` - except
|
||||||
|
probably with a different hash before the `.bc`. If there's more than one
|
||||||
|
`*.bc` file in that directory, delete the whole `deps/` directory and re-run
|
||||||
|
the `cargo rustc` command above to regenerate it.
|
||||||
|
|
||||||
|
> If you want to take a look at the human-readable LLVM IR rather than the
|
||||||
|
> bitcode, run this instead and look for a `.ll` file instead of a `.bc` file:
|
||||||
|
>
|
||||||
|
> ```bash
|
||||||
|
> $ cargo rustc --release --lib -- --emit=llvm-ir
|
||||||
|
> ```
|
||||||
|
|
||||||
|
## Importing the bitcode
|
||||||
|
|
||||||
|
The bitcode is a bunch of bytes that aren't particularly human-readable.
|
||||||
|
Since Roc is designed to be distributed as a single binary, these bytes
|
||||||
|
need to be included in the raw source somewhere.
|
||||||
|
|
||||||
|
The `llvm/src/build.rs` file statically imports these raw bytes
|
||||||
|
using the [`include_bytes!` macro](https://doc.rust-lang.org/std/macro.include_bytes.html),
|
||||||
|
so we just need to move the `.bc` file from the previous step to the correct
|
||||||
|
location.
|
||||||
|
|
||||||
|
The current `.bc` file is located at:
|
||||||
|
|
||||||
|
```
|
||||||
|
compiler/gen/src/llvm/builtins.bc
|
||||||
|
```
|
||||||
|
|
||||||
|
...so you want to overwrite it with the new `.bc` file in `target/deps/`
|
||||||
|
|
||||||
|
Once that's done, `git status` should show that the `builtins.bc` file
|
||||||
|
has been changed. Commit that change and you're done!
|
10
compiler/builtins/bitcode/src/lib.rs
Normal file
10
compiler/builtins/bitcode/src/lib.rs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
#![crate_type = "lib"]
|
||||||
|
#![no_std]
|
||||||
|
|
||||||
|
// TODO replace this with a normal Inkwell build_cast call - this was just
|
||||||
|
// used as a proof of concept for getting bitcode importing working!
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn i64_to_f64_(num: i64) -> f64 {
|
||||||
|
num as f64
|
||||||
|
}
|
|
@ -2,6 +2,7 @@ use bumpalo::collections::Vec;
|
||||||
use bumpalo::Bump;
|
use bumpalo::Bump;
|
||||||
use inkwell::builder::Builder;
|
use inkwell::builder::Builder;
|
||||||
use inkwell::context::Context;
|
use inkwell::context::Context;
|
||||||
|
use inkwell::memory_buffer::MemoryBuffer;
|
||||||
use inkwell::module::{Linkage, Module};
|
use inkwell::module::{Linkage, Module};
|
||||||
use inkwell::passes::PassManager;
|
use inkwell::passes::PassManager;
|
||||||
use inkwell::types::{BasicTypeEnum, IntType, StructType};
|
use inkwell::types::{BasicTypeEnum, IntType, StructType};
|
||||||
|
@ -47,6 +48,14 @@ impl<'a, 'ctx, 'env> Env<'a, 'ctx, 'env> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn module_from_builtins<'ctx>(ctx: &'ctx Context, module_name: &str) -> Module<'ctx> {
|
||||||
|
let memory_buffer =
|
||||||
|
MemoryBuffer::create_from_memory_range(include_bytes!("builtins.bc"), module_name);
|
||||||
|
|
||||||
|
Module::parse_bitcode_from_buffer(&memory_buffer, ctx)
|
||||||
|
.unwrap_or_else(|err| panic!("Unable to import builtins bitcode. LLVM error: {:?}", err))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_passes(fpm: &PassManager<FunctionValue<'_>>) {
|
pub fn add_passes(fpm: &PassManager<FunctionValue<'_>>) {
|
||||||
// tail-call elimination is always on
|
// tail-call elimination is always on
|
||||||
fpm.add_instruction_combining_pass();
|
fpm.add_instruction_combining_pass();
|
||||||
|
@ -1069,6 +1078,31 @@ fn call_with_args<'a, 'ctx, 'env>(
|
||||||
|
|
||||||
BasicValueEnum::IntValue(int_val)
|
BasicValueEnum::IntValue(int_val)
|
||||||
}
|
}
|
||||||
|
Symbol::NUM_TO_FLOAT => {
|
||||||
|
// TODO specialize this to be not just for i64!
|
||||||
|
let builtin_fn_name = "i64_to_f64_";
|
||||||
|
|
||||||
|
let fn_val = env
|
||||||
|
.module
|
||||||
|
.get_function(builtin_fn_name)
|
||||||
|
.unwrap_or_else(|| panic!("Unrecognized builtin function: {:?} - if you're working on the Roc compiler, do you need to rebuild the bitcode? See compiler/builtins/bitcode/README.md", builtin_fn_name));
|
||||||
|
|
||||||
|
let mut arg_vals: Vec<BasicValueEnum> = Vec::with_capacity_in(args.len(), env.arena);
|
||||||
|
|
||||||
|
for (arg, _layout) in args.iter() {
|
||||||
|
arg_vals.push(*arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
let call = env
|
||||||
|
.builder
|
||||||
|
.build_call(fn_val, arg_vals.into_bump_slice(), "call_builtin");
|
||||||
|
|
||||||
|
call.set_call_convention(DEFAULT_CALLING_CONVENTION);
|
||||||
|
|
||||||
|
call.try_as_basic_value()
|
||||||
|
.left()
|
||||||
|
.unwrap_or_else(|| panic!("LLVM error: Invalid call for builtin {:?}", symbol))
|
||||||
|
}
|
||||||
Symbol::FLOAT_EQ => {
|
Symbol::FLOAT_EQ => {
|
||||||
debug_assert!(args.len() == 2);
|
debug_assert!(args.len() == 2);
|
||||||
|
|
||||||
|
|
BIN
compiler/gen/src/llvm/builtins.bc
Normal file
BIN
compiler/gen/src/llvm/builtins.bc
Normal file
Binary file not shown.
|
@ -344,4 +344,17 @@ mod gen_builtins {
|
||||||
i64
|
i64
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn int_to_float() {
|
||||||
|
assert_evals_to!(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
Num.toFloat 0x9
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
9.0,
|
||||||
|
f64
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,7 @@ macro_rules! assert_llvm_evals_to {
|
||||||
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
||||||
|
|
||||||
let context = Context::create();
|
let context = Context::create();
|
||||||
let module = context.create_module("app");
|
let module = roc_gen::llvm::build::module_from_builtins(&context, "app");
|
||||||
let builder = context.create_builder();
|
let builder = context.create_builder();
|
||||||
let fpm = inkwell::passes::PassManager::create(&module);
|
let fpm = inkwell::passes::PassManager::create(&module);
|
||||||
|
|
||||||
|
@ -142,7 +142,7 @@ macro_rules! assert_opt_evals_to {
|
||||||
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
let (content, mut subs) = infer_expr(subs, &mut unify_problems, &constraint, var);
|
||||||
|
|
||||||
let context = Context::create();
|
let context = Context::create();
|
||||||
let module = context.create_module("app");
|
let module = roc_gen::llvm::build::module_from_builtins(&context, "app");
|
||||||
let builder = context.create_builder();
|
let builder = context.create_builder();
|
||||||
let fpm = PassManager::create(&module);
|
let fpm = PassManager::create(&module);
|
||||||
|
|
||||||
|
|
|
@ -133,6 +133,6 @@ impl std::fmt::Display for BinOp {
|
||||||
Pizza => "|>",
|
Pizza => "|>",
|
||||||
};
|
};
|
||||||
|
|
||||||
write!(f, "({})", as_str)
|
write!(f, "{}", as_str)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ edition = "2018"
|
||||||
roc_collections = { path = "../collections" }
|
roc_collections = { path = "../collections" }
|
||||||
roc_region = { path = "../region" }
|
roc_region = { path = "../region" }
|
||||||
roc_module = { path = "../module" }
|
roc_module = { path = "../module" }
|
||||||
|
roc_parse = { path = "../parse" }
|
||||||
roc_problem = { path = "../problem" }
|
roc_problem = { path = "../problem" }
|
||||||
roc_types = { path = "../types" }
|
roc_types = { path = "../types" }
|
||||||
roc_load = { path = "../load" }
|
roc_load = { path = "../load" }
|
||||||
|
@ -15,7 +16,6 @@ roc_can = { path = "../can" }
|
||||||
roc_solve = { path = "../solve" }
|
roc_solve = { path = "../solve" }
|
||||||
inlinable_string = "0.1.0"
|
inlinable_string = "0.1.0"
|
||||||
|
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
roc_constrain = { path = "../constrain" }
|
roc_constrain = { path = "../constrain" }
|
||||||
roc_builtins = { path = "../builtins" }
|
roc_builtins = { path = "../builtins" }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::report::ReportText::{Batch, Module, Region, Value};
|
use crate::report::ReportText::{Batch, BinOp, Module, Region, Value};
|
||||||
use roc_can::expected::{Expected, PExpected};
|
use roc_can::expected::{Expected, PExpected};
|
||||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
use roc_problem::can::PrecedenceProblem::BothNonAssociative;
|
use roc_problem::can::PrecedenceProblem::BothNonAssociative;
|
||||||
|
@ -27,6 +27,7 @@ pub struct Palette {
|
||||||
pub line_number: Color,
|
pub line_number: Color,
|
||||||
pub gutter_bar: Color,
|
pub gutter_bar: Color,
|
||||||
pub module_name: Color,
|
pub module_name: Color,
|
||||||
|
pub binop: Color,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
|
@ -52,6 +53,7 @@ pub const TEST_PALETTE: Palette = Palette {
|
||||||
line_number: Color::Cyan,
|
line_number: Color::Cyan,
|
||||||
gutter_bar: Color::Magenta,
|
gutter_bar: Color::Magenta,
|
||||||
module_name: Color::Green,
|
module_name: Color::Green,
|
||||||
|
binop: Color::Green,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
|
@ -314,10 +316,21 @@ pub fn can_problem(filename: PathBuf, problem: Problem) -> Report {
|
||||||
texts.push(plain_text("\". Adding an underscore at the start of a variable name is a way of saying that the variable is not used."));
|
texts.push(plain_text("\". Adding an underscore at the start of a variable name is a way of saying that the variable is not used."));
|
||||||
}
|
}
|
||||||
Problem::PrecedenceProblem(BothNonAssociative(region, left_bin_op, right_bin_op)) => {
|
Problem::PrecedenceProblem(BothNonAssociative(region, left_bin_op, right_bin_op)) => {
|
||||||
texts.push(plain_text(&*format!(
|
if left_bin_op.value == right_bin_op.value {
|
||||||
"You cannot mix {} and {} without parentheses",
|
texts.push(plain_text("Using more than one "));
|
||||||
left_bin_op.value, right_bin_op.value
|
texts.push(BinOp(left_bin_op.value));
|
||||||
)));
|
texts.push(plain_text(
|
||||||
|
" like this requires parentheses, to clarify how things should be grouped.",
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
texts.push(plain_text("Using "));
|
||||||
|
texts.push(BinOp(left_bin_op.value));
|
||||||
|
texts.push(plain_text(" and "));
|
||||||
|
texts.push(BinOp(right_bin_op.value));
|
||||||
|
texts.push(plain_text(
|
||||||
|
" together requires parentheses, to clarify how they should be grouped.",
|
||||||
|
))
|
||||||
|
}
|
||||||
texts.push(Region(region));
|
texts.push(Region(region));
|
||||||
}
|
}
|
||||||
Problem::UnsupportedPattern(_pattern_type, _region) => {
|
Problem::UnsupportedPattern(_pattern_type, _region) => {
|
||||||
|
@ -371,6 +384,8 @@ pub enum ReportText {
|
||||||
/// The documentation for this symbol.
|
/// The documentation for this symbol.
|
||||||
Docs(Symbol),
|
Docs(Symbol),
|
||||||
|
|
||||||
|
BinOp(roc_parse::operator::BinOp),
|
||||||
|
|
||||||
/// Many ReportText that should be concatenated together.
|
/// Many ReportText that should be concatenated together.
|
||||||
Batch(Vec<ReportText>),
|
Batch(Vec<ReportText>),
|
||||||
}
|
}
|
||||||
|
@ -575,6 +590,9 @@ impl ReportText {
|
||||||
report_text.render_ci(buf, subs, home, src_lines, interns);
|
report_text.render_ci(buf, subs, home, src_lines, interns);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BinOp(bin_op) => {
|
||||||
|
buf.push_str(bin_op.to_string().as_str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -716,6 +734,9 @@ impl ReportText {
|
||||||
report_text.render_color_terminal(buf, subs, home, src_lines, interns, palette);
|
report_text.render_color_terminal(buf, subs, home, src_lines, interns, palette);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BinOp(bin_op) => {
|
||||||
|
buf.push_str(&palette.binop.render(bin_op.to_string().as_str()));
|
||||||
|
}
|
||||||
_ => panic!("TODO implement more ReportTexts in render color terminal"),
|
_ => panic!("TODO implement more ReportTexts in render color terminal"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -304,23 +304,22 @@ mod test_reporting {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// hits a TODO in reporting
|
// #[test]
|
||||||
// #[test]
|
// fn report_shadow() {
|
||||||
// fn report_shadow() {
|
// report_problem_as(
|
||||||
// report_problem_as(
|
// indoc!(
|
||||||
// indoc!(
|
// r#"
|
||||||
// r#"
|
// i = 1
|
||||||
// i = 1
|
|
||||||
//
|
//
|
||||||
// s = \i ->
|
// s = \i ->
|
||||||
// i + 1
|
// i + 1
|
||||||
//
|
//
|
||||||
// s i
|
// s i
|
||||||
// "#
|
// "#
|
||||||
// ),
|
// ),
|
||||||
// indoc!(r#" "#),
|
// indoc!(r#" "#),
|
||||||
// )
|
// )
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn report_unsupported_top_level_def() {
|
// fn report_unsupported_top_level_def() {
|
||||||
|
@ -355,7 +354,7 @@ mod test_reporting {
|
||||||
),
|
),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
You cannot mix (!=) and (==) without parentheses
|
Using != and == together requires parentheses, to clarify how they should be grouped.
|
||||||
|
|
||||||
3 ┆ if selectedId != thisId == adminsId then
|
3 ┆ if selectedId != thisId == adminsId then
|
||||||
┆ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
┆ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -372,7 +371,7 @@ mod test_reporting {
|
||||||
r#"
|
r#"
|
||||||
if
|
if
|
||||||
1
|
1
|
||||||
!= 2
|
== 2
|
||||||
== 3
|
== 3
|
||||||
then
|
then
|
||||||
2
|
2
|
||||||
|
@ -383,10 +382,10 @@ mod test_reporting {
|
||||||
),
|
),
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
You cannot mix (!=) and (==) without parentheses
|
Using more than one == like this requires parentheses, to clarify how things should be grouped.
|
||||||
|
|
||||||
2 ┆> 1
|
2 ┆> 1
|
||||||
3 ┆> != 2
|
3 ┆> == 2
|
||||||
4 ┆> == 3
|
4 ┆> == 3
|
||||||
|
|
||||||
"#
|
"#
|
||||||
|
|
|
@ -9,7 +9,9 @@ mod helpers;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test_solve {
|
mod test_solve {
|
||||||
use crate::helpers::{assert_correct_variable_usage, can_expr, infer_expr, CanExprOut};
|
use crate::helpers::{
|
||||||
|
assert_correct_variable_usage, can_expr, infer_expr, with_larger_debug_stack, CanExprOut,
|
||||||
|
};
|
||||||
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
use roc_types::pretty_print::{content_to_string, name_all_type_vars};
|
||||||
use roc_types::subs::Subs;
|
use roc_types::subs::Subs;
|
||||||
|
|
||||||
|
@ -2220,9 +2222,10 @@ mod test_solve {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn quicksort_partition() {
|
fn quicksort_partition() {
|
||||||
infer_eq_without_problem(
|
with_larger_debug_stack(|| {
|
||||||
indoc!(
|
infer_eq_without_problem(
|
||||||
r#"
|
indoc!(
|
||||||
|
r#"
|
||||||
swap : Int, Int, List a -> List a
|
swap : Int, Int, List a -> List a
|
||||||
swap = \i, j, list ->
|
swap = \i, j, list ->
|
||||||
when Pair (List.get list i) (List.get list j) is
|
when Pair (List.get list i) (List.get list j) is
|
||||||
|
@ -2261,9 +2264,10 @@ mod test_solve {
|
||||||
|
|
||||||
partition
|
partition
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int, Int, List Int -> [ Pair Int (List Int) ]",
|
"Int, Int, List Int -> [ Pair Int (List Int) ]",
|
||||||
);
|
);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -792,7 +792,7 @@ fn write_error_type_help(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Function(arguments, result) => {
|
Function(arguments, result) => {
|
||||||
let use_parens = parens != Parens::Unnecessary;
|
let write_parens = parens != Parens::Unnecessary;
|
||||||
|
|
||||||
if write_parens {
|
if write_parens {
|
||||||
buf.push(')');
|
buf.push(')');
|
||||||
|
@ -815,10 +815,10 @@ fn write_error_type_help(
|
||||||
buf.push(')');
|
buf.push(')');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Record(fields, ext) {
|
Record(fields, ext) => {
|
||||||
buf.push('{');
|
buf.push('{');
|
||||||
buf.push('}');
|
buf.push('}');
|
||||||
write_ext(ext, buf);
|
write_type_ext(ext, buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
Infinite => {
|
Infinite => {
|
||||||
|
@ -836,6 +836,16 @@ pub enum TypeExt {
|
||||||
RigidOpen(Lowercase),
|
RigidOpen(Lowercase),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn write_type_ext(ext: TypeExt, buf: &mut String) {
|
||||||
|
use TypeExt::*;
|
||||||
|
match ext {
|
||||||
|
Closed => {}
|
||||||
|
FlexOpen(lowercase) | RigidOpen(lowercase) => {
|
||||||
|
buf.push_str(lowercase.as_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static THE_LETTER_A: u32 = 'a' as u32;
|
static THE_LETTER_A: u32 = 'a' as u32;
|
||||||
|
|
||||||
pub fn name_type_var(letters_used: u32, taken: &mut MutSet<Lowercase>) -> (Lowercase, u32) {
|
pub fn name_type_var(letters_used: u32, taken: &mut MutSet<Lowercase>) -> (Lowercase, u32) {
|
||||||
|
|
|
@ -15,7 +15,7 @@ in our imaginations...so Rube Goldberg it is!)
|
||||||
1. `cd` into `examples/hello-world/`
|
1. `cd` into `examples/hello-world/`
|
||||||
2. Run `cargo run hello.roc` to compile the Roc source code into a `hello.o` file.
|
2. Run `cargo run hello.roc` to compile the Roc source code into a `hello.o` file.
|
||||||
3. Run `gcc -shared hello.o -o libhello_from_roc.so` to generate `libhello_from_roc.so`. (This filename must begin with `lib` and end in `.so` or else `host.rs` won't be able to find it!)
|
3. Run `gcc -shared hello.o -o libhello_from_roc.so` to generate `libhello_from_roc.so`. (This filename must begin with `lib` and end in `.so` or else `host.rs` won't be able to find it!)
|
||||||
4. Move `libhello_from_roc.so` onto the system library path, e.g. with `sudo mv libhello_from_roc.so /usr/local/lib/`
|
4. Move `libhello_from_roc.so` onto the system library path, e.g. with `sudo mv libhello_from_roc.so /usr/local/lib/` on macOS, or `sudo mv libhello_from_roc.so /usr/local/lib /usr/lib` on Linux.
|
||||||
5. Run `rustc host.rs -o hello` to generate the `hello` executable.
|
5. Run `rustc host.rs -o hello` to generate the `hello` executable.
|
||||||
6. Run `./hello` to see the greeting!
|
6. Run `./hello` to see the greeting!
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue