Merge branch 'main' into drop_specialization

Signed-off-by: J Teeuwissen <jelleteeuwissen@hotmail.nl>
This commit is contained in:
J Teeuwissen 2023-04-26 20:26:37 +02:00 committed by GitHub
commit 7439ee0c8c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
229 changed files with 3602 additions and 2412 deletions

1
Cargo.lock generated
View file

@ -3741,6 +3741,7 @@ dependencies = [
"quickcheck", "quickcheck",
"quickcheck_macros", "quickcheck_macros",
"roc_collections", "roc_collections",
"roc_error_macros",
"roc_module", "roc_module",
"roc_region", "roc_region",
] ]

16
FAQ.md
View file

@ -188,23 +188,19 @@ would be unable to infer a type—and you'd have to write a type annotation. Thi
situations where the editor would not be able to reliably tell you the type of part of your program, unlike today situations where the editor would not be able to reliably tell you the type of part of your program, unlike today
where it can accurately tell you the type of anything, even if you have no type annotations in your entire code base. where it can accurately tell you the type of anything, even if you have no type annotations in your entire code base.
### Arbitrary-rank types assuming that's right, here is a proposed new FAQ entry:
Unlike arbitrary-rank (aka "Rank-N") types, both Rank-1 and Rank-2 type systems are compatible with principal ### Higher-rank types
type inference. Roc currently uses Rank-1 types, and the benefits of Rank-N over Rank-2 don't seem worth
sacrificing principal type inference to attain, so let's focus on the trade-offs between Rank-1 and Rank-2.
Supporting Rank-2 types in Roc has been discussed before, but it has several important downsides: Roc uses a Rank-1 type system. Other languages, like Haskell, support Rank-2 or even arbitrary-rank (aka "Rank-N") types. Supporting higher-rank types in Roc has been discussed before, but it has several important downsides:
- It would remove principal decidable type inference. (Only Rank-1 types are compatible with principal decidable type inference; Rank-2 types are decidable but the inferred types are not principal, and Rank 3+ types are not even fully decidable.)
- It would increase the complexity of the language. - It would increase the complexity of the language.
- It would make some compiler error messages more confusing (e.g. they might mention `forall` because that was the most general type that could be inferred, even if that wasn't helpful or related to the actual problem). - It would make some compiler error messages more confusing (e.g. they might mention `forall` because that was the most general type that could be inferred, even if that wasn't helpful or related to the actual problem).
- It would substantially increase the complexity of the type checker, which would necessarily slow it down. - It would substantially increase the complexity of the type checker, which would necessarily slow it down.
- Most significantly, it would make the runtime slower, because Roc compiles programs by fully specializing all function calls to their type instances (this is sometimes called monomorphization). It's unclear how we could fully specialize programs containing Rank-2 types, which means compiling programs that included Rank-2 types (or higher) would require losing specialization in general—which would substantially degrade runtime performance.
No implementation of Rank-2 types can remove any of these downsides. Thus far, we've been able to come up As such, the plan is for Roc to stick with Rank-1 types indefinitely.
with sufficiently nice APIs that only require Rank-1 types, and we haven't seen a really compelling use case
where the gap between the Rank-2 and Rank-1 designs was big enough to justify switching to Rank-2.
As such, the plan is for Roc to stick with Rank-1 types indefinitely. In Roc's case, the benefits of Rank-1's faster compilation with nicer error messages and a simpler type system outweigh Rank-2's benefits of expanded API options.
### Higher-kinded polymorphism ### Higher-kinded polymorphism

View file

@ -12,11 +12,11 @@ If you'd like to contribute, check out [good first issues](https://github.com/ro
## Sponsors ## Sponsors
We are very grateful for our corporate sponsors [Vendr](https://www.vendr.com/), [rwx](https://www.rwx.com), and [Tweede golf](https://tweedegolf.nl/en). We are very grateful for our corporate sponsors [Vendr](https://www.vendr.com/), [RWX](https://www.rwx.com), and [Tweede golf](https://tweedegolf.nl/en).
[<img src="https://user-images.githubusercontent.com/1094080/223597445-81755626-a080-4299-a38c-3c92e7548489.png" height="60" alt="Vendr logo"/>](https://www.vendr.com) [<img src="https://user-images.githubusercontent.com/1094080/223597445-81755626-a080-4299-a38c-3c92e7548489.png" height="60" alt="Vendr logo"/>](https://www.vendr.com)
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
[<img src="https://www.rwx.com/rwx_banner.svg" height="60" alt="rwx logo"/>](https://www.rwx.com) [<img src="https://www.rwx.com/rwx_banner.svg" height="60" alt="RWX logo"/>](https://www.rwx.com)
&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;
[<img src="https://user-images.githubusercontent.com/1094080/183123052-856815b1-8cc9-410a-83b0-589f03613188.svg" height="60" alt="tweede golf logo"/>](https://tweedegolf.nl/en) [<img src="https://user-images.githubusercontent.com/1094080/183123052-856815b1-8cc9-410a-83b0-589f03613188.svg" height="60" alt="tweede golf logo"/>](https://tweedegolf.nl/en)

View file

@ -1959,8 +1959,8 @@ pub mod test_constrain {
}; };
use indoc::indoc; use indoc::indoc;
fn run_solve<'a>( fn run_solve(
arena: &'a Bump, arena: &Bump,
mempool: &mut Pool, mempool: &mut Pool,
aliases: MutMap<Symbol, roc_types::types::Alias>, aliases: MutMap<Symbol, roc_types::types::Alias>,
rigid_variables: MutMap<Variable, Lowercase>, rigid_variables: MutMap<Variable, Lowercase>,

View file

@ -183,7 +183,7 @@ impl Pool {
} }
} }
pub fn get<'a, 'b, T>(&'a self, node_id: NodeId<T>) -> &'b T { pub fn get<'b, T>(&self, node_id: NodeId<T>) -> &'b T {
unsafe { unsafe {
let node_ptr = self.get_ptr(node_id) as *const T; let node_ptr = self.get_ptr(node_id) as *const T;

View file

@ -100,11 +100,11 @@ pub fn format(files: std::vec::Vec<PathBuf>, mode: FormatMode) -> Result<(), Str
let mut before_file = file.clone(); let mut before_file = file.clone();
before_file.set_extension("roc-format-failed-ast-before"); before_file.set_extension("roc-format-failed-ast-before");
std::fs::write(&before_file, &format!("{:#?}\n", ast_normalized)).unwrap(); std::fs::write(&before_file, format!("{:#?}\n", ast_normalized)).unwrap();
let mut after_file = file.clone(); let mut after_file = file.clone();
after_file.set_extension("roc-format-failed-ast-after"); after_file.set_extension("roc-format-failed-ast-after");
std::fs::write(&after_file, &format!("{:#?}\n", reparsed_ast_normalized)).unwrap(); std::fs::write(&after_file, format!("{:#?}\n", reparsed_ast_normalized)).unwrap();
internal_error!( internal_error!(
"Formatting bug; formatting didn't reparse as the same tree\n\n\ "Formatting bug; formatting didn't reparse as the same tree\n\n\

View file

@ -1234,9 +1234,10 @@ fn run_wasm<I: Iterator<Item = S>, S: AsRef<[u8]>>(_wasm_path: &std::path::Path,
println!("Running wasm files is not supported on this target."); println!("Running wasm files is not supported on this target.");
} }
#[derive(Debug, Copy, Clone, EnumIter, IntoStaticStr, PartialEq, Eq)] #[derive(Debug, Copy, Clone, EnumIter, IntoStaticStr, PartialEq, Eq, Default)]
pub enum Target { pub enum Target {
#[strum(serialize = "system")] #[strum(serialize = "system")]
#[default]
System, System,
#[strum(serialize = "linux32")] #[strum(serialize = "linux32")]
Linux32, Linux32,
@ -1248,12 +1249,6 @@ pub enum Target {
Wasm32, Wasm32,
} }
impl Default for Target {
fn default() -> Self {
Target::System
}
}
impl Target { impl Target {
pub fn to_triple(self) -> Triple { pub fn to_triple(self) -> Triple {
use Target::*; use Target::*;

View file

@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const str = @import("str"); const str = @import("glue").str;
const RocStr = str.RocStr; const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
const expectEqual = testing.expectEqual; const expectEqual = testing.expectEqual;

View file

@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const str = @import("str"); const str = @import("glue").str;
const RocStr = str.RocStr; const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
const expectEqual = testing.expectEqual; const expectEqual = testing.expectEqual;

View file

@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const str = @import("str"); const str = @import("glue").str;
const RocStr = str.RocStr; const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
const expectEqual = testing.expectEqual; const expectEqual = testing.expectEqual;

View file

@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const str = @import("str"); const str = @import("glue").str;
const RocStr = str.RocStr; const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
const expectEqual = testing.expectEqual; const expectEqual = testing.expectEqual;

View file

@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const str = @import("str"); const str = @import("glue").str;
const RocStr = str.RocStr; const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
const expectEqual = testing.expectEqual; const expectEqual = testing.expectEqual;

View file

@ -1,6 +1,6 @@
const std = @import("std"); const std = @import("std");
const builtin = @import("builtin"); const builtin = @import("builtin");
const str = @import("str"); const str = @import("glue").str;
const RocStr = str.RocStr; const RocStr = str.RocStr;
const testing = std.testing; const testing = std.testing;
const expectEqual = testing.expectEqual; const expectEqual = testing.expectEqual;

View file

@ -13,8 +13,8 @@ use crate::{
slow_pool::{MarkNodeId, SlowPool}, slow_pool::{MarkNodeId, SlowPool},
}; };
pub fn ast_to_mark_nodes<'a>( pub fn ast_to_mark_nodes(
env: &mut Env<'a>, env: &mut Env<'_>,
ast: &AST, ast: &AST,
mark_node_pool: &mut SlowPool, mark_node_pool: &mut SlowPool,
interns: &Interns, interns: &Interns,

View file

@ -35,8 +35,8 @@ pub fn add_node(
mark_node_id mark_node_id
} }
pub fn def2_to_markup<'a>( pub fn def2_to_markup(
env: &mut Env<'a>, env: &mut Env<'_>,
def2: &Def2, def2: &Def2,
def2_node_id: DefId, def2_node_id: DefId,
mark_node_pool: &mut SlowPool, mark_node_pool: &mut SlowPool,

View file

@ -35,8 +35,8 @@ use roc_module::{module_err::ModuleResult, symbol::Interns};
use super::from_def2::add_node; use super::from_def2::add_node;
// make Markup Nodes: generate String representation, assign Highlighting Style // make Markup Nodes: generate String representation, assign Highlighting Style
pub fn expr2_to_markup<'a>( pub fn expr2_to_markup(
env: &Env<'a>, env: &Env<'_>,
expr2: &Expr2, expr2: &Expr2,
expr2_node_id: ExprId, expr2_node_id: ExprId,
mark_node_pool: &mut SlowPool, mark_node_pool: &mut SlowPool,

View file

@ -258,7 +258,7 @@ pub fn make_nested_mn(children_ids: Vec<MarkNodeId>, newlines_at_end: usize) ->
} }
} }
pub fn get_string<'a>(env: &Env<'a>, pool_str: &PoolStr) -> String { pub fn get_string(env: &Env<'_>, pool_str: &PoolStr) -> String {
pool_str.as_str(env.pool).to_owned() pool_str.as_str(env.pool).to_owned()
} }

View file

@ -19,13 +19,13 @@ use super::{
}; };
// represents for example: `main = "Hello, World!"` // represents for example: `main = "Hello, World!"`
pub fn assignment_mark_node<'a>( pub fn assignment_mark_node(
identifier_id: IdentId, identifier_id: IdentId,
expr_mark_node_id: MarkNodeId, expr_mark_node_id: MarkNodeId,
ast_node_id: ASTNodeId, ast_node_id: ASTNodeId,
mark_node_pool: &mut SlowPool, mark_node_pool: &mut SlowPool,
mark_id_ast_id_map: &mut MarkIdAstIdMap, mark_id_ast_id_map: &mut MarkIdAstIdMap,
env: &Env<'a>, env: &Env<'_>,
) -> ASTResult<MarkupNode> { ) -> ASTResult<MarkupNode> {
let val_name = env.ident_ids.get_name_str_res(identifier_id)?; let val_name = env.ident_ids.get_name_str_res(identifier_id)?;

View file

@ -487,9 +487,9 @@ impl<'a> Env<'a> {
} }
} }
fn apply_refcount_operation<'a>( fn apply_refcount_operation(
builder: &mut FuncDefBuilder, builder: &mut FuncDefBuilder,
env: &mut Env<'a>, env: &mut Env<'_>,
block: BlockId, block: BlockId,
modify_rc: &ModifyRc, modify_rc: &ModifyRc,
) -> Result<()> { ) -> Result<()> {

View file

@ -1,6 +1,6 @@
use crate::target::{arch_str, target_zig_str}; use crate::target::{arch_str, target_zig_str};
use libloading::{Error, Library}; use libloading::{Error, Library};
use roc_command_utils::{cargo, clang, get_lib_path, rustup, zig}; use roc_command_utils::{cargo, clang, rustup, zig};
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_mono::ir::OptLevel; use roc_mono::ir::OptLevel;
use std::collections::HashMap; use std::collections::HashMap;
@ -63,31 +63,57 @@ pub fn legacy_host_filename(target: &Triple) -> Option<String> {
) )
} }
fn find_zig_str_path() -> PathBuf { // Attempts to find a file that is stored relative to the roc executable.
// First try using the lib path relative to the executable location. // Since roc is built in target/debug/roc, we may need to drop that path to find the file.
let lib_path_opt = get_lib_path(); // This is used to avoid depending on the current working directory.
pub fn get_relative_path(sub_path: &Path) -> Option<PathBuf> {
if sub_path.is_absolute() {
internal_error!(
"get_relative_path requires sub_path to be relative, instead got {:?}",
sub_path
);
}
let exe_relative_str_path_opt = std::env::current_exe().ok();
if let Some(lib_path) = lib_path_opt { if let Some(exe_relative_str_path) = exe_relative_str_path_opt {
let zig_str_path = lib_path.join("str.zig"); #[cfg(windows)]
let exe_relative_str_path = roc_command_utils::strip_windows_prefix(&exe_relative_str_path);
if std::path::Path::exists(&zig_str_path) { let mut curr_parent_opt = exe_relative_str_path.parent();
return zig_str_path;
// We need to support paths like ./roc, ./bin/roc, ./target/debug/roc and tests like ./target/debug/deps/valgrind-63c787aa176d1277
// This requires dropping up to 3 directories.
for _ in 0..=3 {
if let Some(curr_parent) = curr_parent_opt {
let potential_path = curr_parent.join(sub_path);
if std::path::Path::exists(&potential_path) {
return Some(potential_path);
} else {
curr_parent_opt = curr_parent.parent();
}
} else {
break;
}
} }
} }
let zig_str_path = PathBuf::from("crates/compiler/builtins/bitcode/src/str.zig"); None
}
if std::path::Path::exists(&zig_str_path) { fn find_zig_glue_path() -> PathBuf {
return zig_str_path; // First try using the repo path relative to the executable location.
let path = get_relative_path(Path::new("crates/compiler/builtins/bitcode/src/glue.zig"));
if let Some(path) = path {
return path;
}
// Fallback on a lib path relative to the executable location.
let path = get_relative_path(Path::new("lib/glue.zig"));
if let Some(path) = path {
return path;
} }
// when running the tests, we start in the /cli directory internal_error!("cannot find `glue.zig`. Check the source code in find_zig_glue_path() to show all the paths I tried.")
let zig_str_path = PathBuf::from("../compiler/builtins/bitcode/src/str.zig");
if std::path::Path::exists(&zig_str_path) {
return zig_str_path;
}
internal_error!("cannot find `str.zig`. Check the source code in find_zig_str_path() to show all the paths I tried.")
} }
fn find_wasi_libc_path() -> PathBuf { fn find_wasi_libc_path() -> PathBuf {
@ -107,7 +133,6 @@ pub fn build_zig_host_native(
env_home: &str, env_home: &str,
emit_bin: &str, emit_bin: &str,
zig_host_src: &str, zig_host_src: &str,
zig_str_path: &str,
target: &str, target: &str,
opt_level: OptLevel, opt_level: OptLevel,
shared_lib_path: Option<&Path>, shared_lib_path: Option<&Path>,
@ -138,8 +163,8 @@ pub fn build_zig_host_native(
zig_host_src, zig_host_src,
&format!("-femit-bin={}", emit_bin), &format!("-femit-bin={}", emit_bin),
"--pkg-begin", "--pkg-begin",
"str", "glue",
zig_str_path, find_zig_glue_path().to_str().unwrap(),
"--pkg-end", "--pkg-end",
// include libc // include libc
"-lc", "-lc",
@ -180,7 +205,6 @@ pub fn build_zig_host_native(
env_home: &str, env_home: &str,
emit_bin: &str, emit_bin: &str,
zig_host_src: &str, zig_host_src: &str,
zig_str_path: &str,
target: &str, target: &str,
opt_level: OptLevel, opt_level: OptLevel,
shared_lib_path: Option<&Path>, shared_lib_path: Option<&Path>,
@ -211,8 +235,8 @@ pub fn build_zig_host_native(
zig_host_src, zig_host_src,
&format!("-femit-bin={}", emit_bin), &format!("-femit-bin={}", emit_bin),
"--pkg-begin", "--pkg-begin",
"str", "glue",
zig_str_path, find_zig_glue_path().to_str().unwrap(),
"--pkg-end", "--pkg-end",
// include the zig runtime // include the zig runtime
// "-fcompiler-rt", compiler-rt causes segfaults on windows; investigate why // "-fcompiler-rt", compiler-rt causes segfaults on windows; investigate why
@ -240,7 +264,6 @@ pub fn build_zig_host_native(
env_home: &str, env_home: &str,
emit_bin: &str, emit_bin: &str,
zig_host_src: &str, zig_host_src: &str,
zig_str_path: &str,
_target: &str, _target: &str,
opt_level: OptLevel, opt_level: OptLevel,
shared_lib_path: Option<&Path>, shared_lib_path: Option<&Path>,
@ -306,8 +329,8 @@ pub fn build_zig_host_native(
zig_host_src, zig_host_src,
&format!("-femit-bin={}", emit_bin), &format!("-femit-bin={}", emit_bin),
"--pkg-begin", "--pkg-begin",
"str", "glue",
zig_str_path, find_zig_glue_path().to_str().unwrap(),
"--pkg-end", "--pkg-end",
// include the zig runtime // include the zig runtime
"--pkg-begin", "--pkg-begin",
@ -332,7 +355,6 @@ pub fn build_zig_host_wasm32(
env_home: &str, env_home: &str,
emit_bin: &str, emit_bin: &str,
zig_host_src: &str, zig_host_src: &str,
zig_str_path: &str,
opt_level: OptLevel, opt_level: OptLevel,
shared_lib_path: Option<&Path>, shared_lib_path: Option<&Path>,
) -> Command { ) -> Command {
@ -356,13 +378,18 @@ pub fn build_zig_host_wasm32(
// //
// https://github.com/ziglang/zig/issues/9414 // https://github.com/ziglang/zig/issues/9414
let mut zig_cmd = zig(); let mut zig_cmd = zig();
let args = &[
zig_cmd
.env_clear()
.env("PATH", env_path)
.env("HOME", env_home)
.args([
"build-obj", "build-obj",
zig_host_src, zig_host_src,
emit_bin, emit_bin,
"--pkg-begin", "--pkg-begin",
"str", "glue",
zig_str_path, find_zig_glue_path().to_str().unwrap(),
"--pkg-end", "--pkg-end",
// include the zig runtime // include the zig runtime
// "-fcompiler-rt", // "-fcompiler-rt",
@ -374,13 +401,7 @@ pub fn build_zig_host_wasm32(
// "-femit-llvm-ir=/home/folkertdev/roc/roc/crates/cli_testing_examples/benchmarks/platform/host.ll", // "-femit-llvm-ir=/home/folkertdev/roc/roc/crates/cli_testing_examples/benchmarks/platform/host.ll",
"-fPIC", "-fPIC",
"--strip", "--strip",
]; ]);
zig_cmd
.env_clear()
.env("PATH", env_path)
.env("HOME", env_home)
.args(args);
if matches!(opt_level, OptLevel::Optimize) { if matches!(opt_level, OptLevel::Optimize) {
zig_cmd.args(["-O", "ReleaseSafe"]); zig_cmd.args(["-O", "ReleaseSafe"]);
@ -424,7 +445,6 @@ pub fn build_c_host_native(
env_home, env_home,
dest, dest,
sources[0], sources[0],
find_zig_str_path().to_str().unwrap(),
get_target_str(target), get_target_str(target),
opt_level, opt_level,
Some(shared_lib_path), Some(shared_lib_path),
@ -558,15 +578,6 @@ pub fn rebuild_host(
if zig_host_src.exists() { if zig_host_src.exists() {
// Compile host.zig // Compile host.zig
let zig_str_path = find_zig_str_path();
debug_assert!(
std::path::Path::exists(&zig_str_path),
"Cannot find str.zig, looking at {:?}",
&zig_str_path
);
let zig_cmd = match target.architecture { let zig_cmd = match target.architecture {
Architecture::Wasm32 => { Architecture::Wasm32 => {
let emit_bin = if matches!(opt_level, OptLevel::Development) { let emit_bin = if matches!(opt_level, OptLevel::Development) {
@ -579,7 +590,6 @@ pub fn rebuild_host(
&env_home, &env_home,
&emit_bin, &emit_bin,
zig_host_src.to_str().unwrap(), zig_host_src.to_str().unwrap(),
zig_str_path.to_str().unwrap(),
opt_level, opt_level,
shared_lib_path, shared_lib_path,
) )
@ -589,7 +599,6 @@ pub fn rebuild_host(
&env_home, &env_home,
host_dest.to_str().unwrap(), host_dest.to_str().unwrap(),
zig_host_src.to_str().unwrap(), zig_host_src.to_str().unwrap(),
zig_str_path.to_str().unwrap(),
get_target_str(target), get_target_str(target),
opt_level, opt_level,
shared_lib_path, shared_lib_path,
@ -600,7 +609,6 @@ pub fn rebuild_host(
&env_home, &env_home,
host_dest.to_str().unwrap(), host_dest.to_str().unwrap(),
zig_host_src.to_str().unwrap(), zig_host_src.to_str().unwrap(),
zig_str_path.to_str().unwrap(),
"i386-linux-musl", "i386-linux-musl",
opt_level, opt_level,
shared_lib_path, shared_lib_path,
@ -611,7 +619,6 @@ pub fn rebuild_host(
&env_home, &env_home,
host_dest.to_str().unwrap(), host_dest.to_str().unwrap(),
zig_host_src.to_str().unwrap(), zig_host_src.to_str().unwrap(),
zig_str_path.to_str().unwrap(),
target_zig_str(target), target_zig_str(target),
opt_level, opt_level,
shared_lib_path, shared_lib_path,
@ -719,7 +726,7 @@ pub fn rebuild_host(
if matches!(opt_level, OptLevel::Optimize) { if matches!(opt_level, OptLevel::Optimize) {
rustc_cmd.arg("-O"); rustc_cmd.arg("-O");
} else if matches!(opt_level, OptLevel::Size) { } else if matches!(opt_level, OptLevel::Size) {
rustc_cmd.arg("-C opt-level=s"); rustc_cmd.args(["-C", "opt-level=s"]);
} }
run_build_command(rustc_cmd, "host.rs", 0); run_build_command(rustc_cmd, "host.rs", 0);
@ -1100,7 +1107,7 @@ fn link_linux(
// Keep NIX_ env vars // Keep NIX_ env vars
.envs( .envs(
env::vars() env::vars()
.filter(|&(ref k, _)| k.starts_with("NIX_")) .filter(|(k, _)| k.starts_with("NIX_"))
.collect::<HashMap<String, String>>(), .collect::<HashMap<String, String>>(),
) )
.args([ .args([
@ -1273,7 +1280,6 @@ fn link_wasm32(
input_paths: &[&str], input_paths: &[&str],
_link_type: LinkType, _link_type: LinkType,
) -> io::Result<(Child, PathBuf)> { ) -> io::Result<(Child, PathBuf)> {
let zig_str_path = find_zig_str_path();
let wasi_libc_path = find_wasi_libc_path(); let wasi_libc_path = find_wasi_libc_path();
let child = zig() let child = zig()
@ -1289,8 +1295,8 @@ fn link_wasm32(
"-target", "-target",
"wasm32-wasi-musl", "wasm32-wasi-musl",
"--pkg-begin", "--pkg-begin",
"str", "glue",
zig_str_path.to_str().unwrap(), find_zig_glue_path().to_str().unwrap(),
"--pkg-end", "--pkg-end",
"--strip", "--strip",
"-O", "-O",
@ -1309,8 +1315,6 @@ fn link_windows(
input_paths: &[&str], input_paths: &[&str],
link_type: LinkType, link_type: LinkType,
) -> io::Result<(Child, PathBuf)> { ) -> io::Result<(Child, PathBuf)> {
let zig_str_path = find_zig_str_path();
match link_type { match link_type {
LinkType::Dylib => { LinkType::Dylib => {
let child = zig() let child = zig()
@ -1322,8 +1326,8 @@ fn link_windows(
"-target", "-target",
"native", "native",
"--pkg-begin", "--pkg-begin",
"str", "glue",
zig_str_path.to_str().unwrap(), find_zig_glue_path().to_str().unwrap(),
"--pkg-end", "--pkg-end",
"--strip", "--strip",
"-O", "-O",

View file

@ -0,0 +1,7 @@
// This is a glue package that just re-exports other libs useful for zig hosts.
// Long term, a slimmed down version of these libraries without all of the roc builtins should be create via `roc glue`.
// We also should make RocList use comptime types in order to make it nice to use in zig.
pub const dec = @import("dec.zig");
pub const list = @import("list.zig");
pub const str = @import("str.zig");

View file

@ -133,6 +133,7 @@ comptime {
exportStrFn(str.countSegments, "count_segments"); exportStrFn(str.countSegments, "count_segments");
exportStrFn(str.countGraphemeClusters, "count_grapheme_clusters"); exportStrFn(str.countGraphemeClusters, "count_grapheme_clusters");
exportStrFn(str.countUtf8Bytes, "count_utf8_bytes"); exportStrFn(str.countUtf8Bytes, "count_utf8_bytes");
exportStrFn(str.isEmpty, "is_empty");
exportStrFn(str.getCapacity, "capacity"); exportStrFn(str.getCapacity, "capacity");
exportStrFn(str.startsWith, "starts_with"); exportStrFn(str.startsWith, "starts_with");
exportStrFn(str.startsWithScalar, "starts_with_scalar"); exportStrFn(str.startsWithScalar, "starts_with_scalar");

View file

@ -1525,6 +1525,10 @@ pub fn countUtf8Bytes(string: RocStr) callconv(.C) usize {
return string.len(); return string.len();
} }
pub fn isEmpty(string: RocStr) callconv(.C) bool {
return string.isEmpty();
}
pub fn getCapacity(string: RocStr) callconv(.C) usize { pub fn getCapacity(string: RocStr) callconv(.C) usize {
return string.getCapacity(); return string.getCapacity();
} }

View file

@ -34,6 +34,7 @@ interface Num
Binary32, Binary32,
Binary64, Binary64,
abs, abs,
absDiff,
neg, neg,
add, add,
sub, sub,
@ -643,6 +644,27 @@ toFrac : Num * -> Frac *
## Calling this on an unsigned integer (like [U32] or [U64]) never does anything. ## Calling this on an unsigned integer (like [U32] or [U64]) never does anything.
abs : Num a -> Num a abs : Num a -> Num a
## Return the absolute difference between two numbers.
##
## ```
## Num.absDiff 5 3
##
## Num.absDiff -3 5
##
## Num.absDiff 3.0 5.0
## ```
##
## If the answer to this operation can't fit in the return value (e.g. an
## [I8] answer that's higher than 127 or lower than -128), the result is an
## *overflow*. For [F64] and [F32], overflow results in an answer of either
## ∞ or -∞. For all other number types, overflow results in a panic.
absDiff : Num a, Num a -> Num a
absDiff = \a, b ->
if a > b then
a - b
else
b - a
## Return a negative number when given a positive one, and vice versa. ## Return a negative number when given a positive one, and vice versa.
## ``` ## ```
## Num.neg 5 ## Num.neg 5

View file

@ -308,6 +308,7 @@ pub const STR_SPLIT: &str = "roc_builtins.str.str_split";
pub const STR_TO_SCALARS: &str = "roc_builtins.str.to_scalars"; pub const STR_TO_SCALARS: &str = "roc_builtins.str.to_scalars";
pub const STR_COUNT_GRAPEHEME_CLUSTERS: &str = "roc_builtins.str.count_grapheme_clusters"; pub const STR_COUNT_GRAPEHEME_CLUSTERS: &str = "roc_builtins.str.count_grapheme_clusters";
pub const STR_COUNT_UTF8_BYTES: &str = "roc_builtins.str.count_utf8_bytes"; pub const STR_COUNT_UTF8_BYTES: &str = "roc_builtins.str.count_utf8_bytes";
pub const STR_IS_EMPTY: &str = "roc_builtins.str.is_empty";
pub const STR_CAPACITY: &str = "roc_builtins.str.capacity"; pub const STR_CAPACITY: &str = "roc_builtins.str.capacity";
pub const STR_STARTS_WITH: &str = "roc_builtins.str.starts_with"; pub const STR_STARTS_WITH: &str = "roc_builtins.str.starts_with";
pub const STR_STARTS_WITH_SCALAR: &str = "roc_builtins.str.starts_with_scalar"; pub const STR_STARTS_WITH_SCALAR: &str = "roc_builtins.str.starts_with_scalar";

View file

@ -1134,7 +1134,7 @@ fn canonicalize_has_clause(
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn can_extension_type<'a>( fn can_extension_type(
env: &mut Env, env: &mut Env,
pol: CanPolarity, pol: CanPolarity,
scope: &mut Scope, scope: &mut Scope,
@ -1142,7 +1142,7 @@ fn can_extension_type<'a>(
introduced_variables: &mut IntroducedVariables, introduced_variables: &mut IntroducedVariables,
local_aliases: &mut VecMap<Symbol, Alias>, local_aliases: &mut VecMap<Symbol, Alias>,
references: &mut VecSet<Symbol>, references: &mut VecSet<Symbol>,
opt_ext: &Option<&Loc<TypeAnnotation<'a>>>, opt_ext: &Option<&Loc<TypeAnnotation<'_>>>,
ext_problem_kind: roc_problem::can::ExtensionTypeKind, ext_problem_kind: roc_problem::can::ExtensionTypeKind,
) -> (Type, ExtImplicitOpenness) { ) -> (Type, ExtImplicitOpenness) {
fn valid_record_ext_type(typ: &Type) -> bool { fn valid_record_ext_type(typ: &Type) -> bool {
@ -1451,10 +1451,10 @@ fn can_assigned_fields<'a>(
// TODO trim down these arguments! // TODO trim down these arguments!
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn can_assigned_tuple_elems<'a>( fn can_assigned_tuple_elems(
env: &mut Env, env: &mut Env,
pol: CanPolarity, pol: CanPolarity,
elems: &&[Loc<TypeAnnotation<'a>>], elems: &&[Loc<TypeAnnotation<'_>>],
scope: &mut Scope, scope: &mut Scope,
var_store: &mut VarStore, var_store: &mut VarStore,
introduced_variables: &mut IntroducedVariables, introduced_variables: &mut IntroducedVariables,

View file

@ -85,6 +85,7 @@ macro_rules! map_symbol_to_lowlevel_and_arity {
// these are used internally and not tied to a symbol // these are used internally and not tied to a symbol
LowLevel::Hash => unimplemented!(), LowLevel::Hash => unimplemented!(),
LowLevel::PtrCast => unimplemented!(), LowLevel::PtrCast => unimplemented!(),
LowLevel::PtrWrite => unimplemented!(),
LowLevel::RefCountInc => unimplemented!(), LowLevel::RefCountInc => unimplemented!(),
LowLevel::RefCountDec => unimplemented!(), LowLevel::RefCountDec => unimplemented!(),
LowLevel::RefCountIsUnique => unimplemented!(), LowLevel::RefCountIsUnique => unimplemented!(),

View file

@ -1050,9 +1050,7 @@ fn canonicalize_value_defs<'a>(
let mut symbol_to_index: Vec<(IdentId, u32)> = Vec::with_capacity(pending_value_defs.len()); let mut symbol_to_index: Vec<(IdentId, u32)> = Vec::with_capacity(pending_value_defs.len());
for (def_index, pending_def) in pending_value_defs.iter().enumerate() { for (def_index, pending_def) in pending_value_defs.iter().enumerate() {
let mut new_bindings = BindingsFromPattern::new(pending_def.loc_pattern()) let mut new_bindings = BindingsFromPattern::new(pending_def.loc_pattern()).peekable();
.into_iter()
.peekable();
if new_bindings.peek().is_none() { if new_bindings.peek().is_none() {
env.problem(Problem::NoIdentifiersIntroduced( env.problem(Problem::NoIdentifiersIntroduced(
@ -1339,8 +1337,8 @@ fn canonicalize_type_defs<'a>(
/// Resolve all pending abilities, to add them to scope. /// Resolve all pending abilities, to add them to scope.
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn resolve_abilities<'a>( fn resolve_abilities(
env: &mut Env<'a>, env: &mut Env<'_>,
output: &mut Output, output: &mut Output,
var_store: &mut VarStore, var_store: &mut VarStore,
scope: &mut Scope, scope: &mut Scope,
@ -2813,8 +2811,8 @@ fn to_pending_value_def<'a>(
} }
/// Make aliases recursive /// Make aliases recursive
fn correct_mutual_recursive_type_alias<'a>( fn correct_mutual_recursive_type_alias(
env: &mut Env<'a>, env: &mut Env<'_>,
original_aliases: VecMap<Symbol, Alias>, original_aliases: VecMap<Symbol, Alias>,
var_store: &mut VarStore, var_store: &mut VarStore,
) -> VecMap<Symbol, Alias> { ) -> VecMap<Symbol, Alias> {
@ -3022,8 +3020,8 @@ fn correct_mutual_recursive_type_alias<'a>(
unsafe { VecMap::zip(symbols_introduced, aliases) } unsafe { VecMap::zip(symbols_introduced, aliases) }
} }
fn make_tag_union_of_alias_recursive<'a>( fn make_tag_union_of_alias_recursive(
env: &mut Env<'a>, env: &mut Env<'_>,
alias_name: Symbol, alias_name: Symbol,
alias: &mut Alias, alias: &mut Alias,
others: Vec<Symbol>, others: Vec<Symbol>,
@ -3215,8 +3213,8 @@ fn make_tag_union_recursive_help<'a, 'b>(
} }
} }
fn mark_cyclic_alias<'a>( fn mark_cyclic_alias(
env: &mut Env<'a>, env: &mut Env<'_>,
typ: &mut Type, typ: &mut Type,
symbol: Symbol, symbol: Symbol,
alias_kind: AliasKind, alias_kind: AliasKind,

View file

@ -1378,31 +1378,31 @@ pub fn canonicalize_expr<'a>(
// Below this point, we shouln't see any of these nodes anymore because // Below this point, we shouln't see any of these nodes anymore because
// operator desugaring should have removed them! // operator desugaring should have removed them!
bad_expr @ ast::Expr::ParensAround(_) => { bad_expr @ ast::Expr::ParensAround(_) => {
panic!( internal_error!(
"A ParensAround did not get removed during operator desugaring somehow: {:#?}", "A ParensAround did not get removed during operator desugaring somehow: {:#?}",
bad_expr bad_expr
); );
} }
bad_expr @ ast::Expr::SpaceBefore(_, _) => { bad_expr @ ast::Expr::SpaceBefore(_, _) => {
panic!( internal_error!(
"A SpaceBefore did not get removed during operator desugaring somehow: {:#?}", "A SpaceBefore did not get removed during operator desugaring somehow: {:#?}",
bad_expr bad_expr
); );
} }
bad_expr @ ast::Expr::SpaceAfter(_, _) => { bad_expr @ ast::Expr::SpaceAfter(_, _) => {
panic!( internal_error!(
"A SpaceAfter did not get removed during operator desugaring somehow: {:#?}", "A SpaceAfter did not get removed during operator desugaring somehow: {:#?}",
bad_expr bad_expr
); );
} }
bad_expr @ ast::Expr::BinOps { .. } => { bad_expr @ ast::Expr::BinOps { .. } => {
panic!( internal_error!(
"A binary operator chain did not get desugared somehow: {:#?}", "A binary operator chain did not get desugared somehow: {:#?}",
bad_expr bad_expr
); );
} }
bad_expr @ ast::Expr::UnaryOp(_, _) => { bad_expr @ ast::Expr::UnaryOp(_, _) => {
panic!( internal_error!(
"A unary operator did not get desugared somehow: {:#?}", "A unary operator did not get desugared somehow: {:#?}",
bad_expr bad_expr
); );
@ -1814,7 +1814,7 @@ fn canonicalize_field<'a>(
// A label with no value, e.g. `{ name }` (this is sugar for { name: name }) // A label with no value, e.g. `{ name }` (this is sugar for { name: name })
LabelOnly(_) => { LabelOnly(_) => {
panic!("Somehow a LabelOnly record field was not desugared!"); internal_error!("Somehow a LabelOnly record field was not desugared!");
} }
SpaceBefore(sub_field, _) | SpaceAfter(sub_field, _) => { SpaceBefore(sub_field, _) | SpaceAfter(sub_field, _) => {
@ -1822,7 +1822,7 @@ fn canonicalize_field<'a>(
} }
Malformed(_string) => { Malformed(_string) => {
panic!("TODO canonicalize malformed record field"); internal_error!("TODO canonicalize malformed record field");
} }
} }
} }

View file

@ -195,11 +195,11 @@ enum GeneratedInfo {
} }
impl GeneratedInfo { impl GeneratedInfo {
fn from_header_type<'a>( fn from_header_type(
env: &mut Env, env: &mut Env,
scope: &mut Scope, scope: &mut Scope,
var_store: &mut VarStore, var_store: &mut VarStore,
header_type: &HeaderType<'a>, header_type: &HeaderType<'_>,
) -> Self { ) -> Self {
match header_type { match header_type {
HeaderType::Hosted { HeaderType::Hosted {
@ -338,7 +338,7 @@ pub fn canonicalize_module_defs<'a>(
can_exposed_imports.insert(symbol, region); can_exposed_imports.insert(symbol, region);
} }
Err((_shadowed_symbol, _region)) => { Err((_shadowed_symbol, _region)) => {
panic!("TODO gracefully handle shadowing in imports.") internal_error!("TODO gracefully handle shadowing in imports.")
} }
} }
} else { } else {
@ -359,7 +359,7 @@ pub fn canonicalize_module_defs<'a>(
// here we do nothing special // here we do nothing special
} }
Err((shadowed_symbol, _region)) => { Err((shadowed_symbol, _region)) => {
panic!( internal_error!(
"TODO gracefully handle shadowing in imports, {:?} is shadowed.", "TODO gracefully handle shadowing in imports, {:?} is shadowed.",
shadowed_symbol shadowed_symbol
) )
@ -523,7 +523,7 @@ pub fn canonicalize_module_defs<'a>(
GeneratedInfo::Builtin => { GeneratedInfo::Builtin => {
match crate::builtins::builtin_defs_map(*symbol, var_store) { match crate::builtins::builtin_defs_map(*symbol, var_store) {
None => { None => {
panic!("A builtin module contains a signature without implementation for {:?}", symbol) internal_error!("A builtin module contains a signature without implementation for {:?}", symbol)
} }
Some(replacement_def) => { Some(replacement_def) => {
declarations.update_builtin_def(index, replacement_def); declarations.update_builtin_def(index, replacement_def);
@ -581,7 +581,7 @@ pub fn canonicalize_module_defs<'a>(
GeneratedInfo::Builtin => { GeneratedInfo::Builtin => {
match crate::builtins::builtin_defs_map(*symbol, var_store) { match crate::builtins::builtin_defs_map(*symbol, var_store) {
None => { None => {
panic!("A builtin module contains a signature without implementation for {:?}", symbol) internal_error!("A builtin module contains a signature without implementation for {:?}", symbol)
} }
Some(replacement_def) => { Some(replacement_def) => {
declarations.update_builtin_def(index, replacement_def); declarations.update_builtin_def(index, replacement_def);

View file

@ -2,6 +2,7 @@
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_error_macros::internal_error;
use roc_module::called_via::BinOp::Pizza; use roc_module::called_via::BinOp::Pizza;
use roc_module::called_via::{BinOp, CalledVia}; use roc_module::called_via::{BinOp, CalledVia};
use roc_module::ident::ModuleName; use roc_module::ident::ModuleName;
@ -592,7 +593,7 @@ fn binop_step<'a>(
// //
// By design, Roc neither allows custom operators nor has any built-in operators with // By design, Roc neither allows custom operators nor has any built-in operators with
// the same precedence and different associativity, so this should never happen! // the same precedence and different associativity, so this should never happen!
panic!("BinOps had the same associativity, but different precedence. This should never happen!"); internal_error!("BinOps had the same associativity, but different precedence. This should never happen!");
} }
} }
} }

View file

@ -321,8 +321,8 @@ pub fn canonicalize_def_header_pattern<'a>(
#[derive(PartialEq, Eq, Clone, Copy)] #[derive(PartialEq, Eq, Clone, Copy)]
pub struct PermitShadows(pub bool); pub struct PermitShadows(pub bool);
fn canonicalize_pattern_symbol<'a>( fn canonicalize_pattern_symbol(
env: &mut Env<'a>, env: &mut Env<'_>,
scope: &mut Scope, scope: &mut Scope,
output: &mut Output, output: &mut Output,
region: Region, region: Region,

View file

@ -1,4 +1,5 @@
use roc_collections::{VecMap, VecSet}; use roc_collections::{VecMap, VecSet};
use roc_error_macros::internal_error;
use roc_module::ident::Ident; use roc_module::ident::Ident;
use roc_module::symbol::{IdentId, IdentIds, ModuleId, Symbol}; use roc_module::symbol::{IdentId, IdentIds, ModuleId, Symbol};
use roc_problem::can::RuntimeError; use roc_problem::can::RuntimeError;
@ -470,9 +471,13 @@ pub fn create_alias(
} }
if !hidden.is_empty() { if !hidden.is_empty() {
panic!( internal_error!(
"Found unbound type variables {:?} \n in type alias {:?} {:?} {:?} : {:?}", "Found unbound type variables {:?} \n in type alias {:?} {:?} {:?} : {:?}",
hidden, name, &vars, &infer_ext_in_output_variables, &typ hidden,
name,
&vars,
&infer_ext_in_output_variables,
&typ
) )
} }

View file

@ -1,6 +1,7 @@
// use bumpalo::collections::string::String; // use bumpalo::collections::string::String;
// use bumpalo::collections::vec::Vec; // use bumpalo::collections::vec::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_error_macros::internal_error;
use roc_parse::ast::Expr; use roc_parse::ast::Expr;
// use roc_parse::ast::{Attempting, Expr}; // use roc_parse::ast::{Attempting, Expr};
// use roc_parse::ident; // use roc_parse::ident;
@ -12,7 +13,7 @@ use roc_region::all::Region;
// use std::iter::Peekable; // use std::iter::Peekable;
pub fn canonical_string_literal<'a>(_arena: &Bump, _raw: &'a str, _region: Region) -> Expr<'a> { pub fn canonical_string_literal<'a>(_arena: &Bump, _raw: &'a str, _region: Region) -> Expr<'a> {
panic!("TODO restore canonicalization"); internal_error!("TODO restore canonicalization");
} }
// let mut problems = std::vec::Vec::new(); // let mut problems = std::vec::Vec::new();

View file

@ -122,7 +122,7 @@ pub fn walk_decls<V: Visitor>(visitor: &mut V, decls: &Declarations) {
None => Pattern::Identifier(loc_symbol.value), None => Pattern::Identifier(loc_symbol.value),
}; };
let function_def = &decls.function_bodies[function_index.index() as usize]; let function_def = &decls.function_bodies[function_index.index()];
DeclarationInfo::Function { DeclarationInfo::Function {
loc_symbol, loc_symbol,
@ -133,7 +133,7 @@ pub fn walk_decls<V: Visitor>(visitor: &mut V, decls: &Declarations) {
} }
} }
Destructure(destructure_index) => { Destructure(destructure_index) => {
let destructure = &decls.destructs[destructure_index.index() as usize]; let destructure = &decls.destructs[destructure_index.index()];
let loc_pattern = &destructure.loc_pattern; let loc_pattern = &destructure.loc_pattern;
let loc_expr = &decls.expressions[index]; let loc_expr = &decls.expressions[index];

View file

@ -2600,7 +2600,7 @@ pub fn constrain_decls(
cycle_mark, cycle_mark,
); );
index += length as usize; index += length;
} }
} }

View file

@ -55,7 +55,6 @@ pub(crate) fn derive_to_encoder(
// Generalized tuple var so we can reuse this impl between many tuples: // Generalized tuple var so we can reuse this impl between many tuples:
// if arity = n, this is (t1, ..., tn) for fresh t1, ..., tn. // if arity = n, this is (t1, ..., tn) for fresh t1, ..., tn.
let flex_elems = (0..arity) let flex_elems = (0..arity)
.into_iter()
.map(|idx| (idx as usize, env.subs.fresh_unnamed_flex_var())) .map(|idx| (idx as usize, env.subs.fresh_unnamed_flex_var()))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let elems = TupleElems::insert_into_subs(env.subs, flex_elems); let elems = TupleElems::insert_into_subs(env.subs, flex_elems);

View file

@ -131,7 +131,6 @@ fn hash_tuple(env: &mut Env<'_>, fn_name: Symbol, arity: u32) -> (Variable, Expr
// TODO: avoid an allocation here by pre-allocating the indices and variables `TupleElems` // TODO: avoid an allocation here by pre-allocating the indices and variables `TupleElems`
// will be instantiated with. // will be instantiated with.
let flex_elems: Vec<_> = (0..arity) let flex_elems: Vec<_> = (0..arity)
.into_iter()
.map(|i| (i as usize, env.subs.fresh_unnamed_flex_var())) .map(|i| (i as usize, env.subs.fresh_unnamed_flex_var()))
.collect(); .collect();
let elems = TupleElems::insert_into_subs(env.subs, flex_elems); let elems = TupleElems::insert_into_subs(env.subs, flex_elems);

View file

@ -65,15 +65,15 @@ impl Newlines {
pub trait Formattable { pub trait Formattable {
fn is_multiline(&self) -> bool; fn is_multiline(&self) -> bool;
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
); );
fn format<'buf>(&self, buf: &mut Buf<'buf>, indent: u16) { fn format(&self, buf: &mut Buf<'_>, indent: u16) {
self.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent); self.format_with_options(buf, Parens::NotNeeded, Newlines::No, indent);
} }
} }
@ -87,9 +87,9 @@ where
(*self).is_multiline() (*self).is_multiline()
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -97,7 +97,7 @@ where
(*self).format_with_options(buf, parens, newlines, indent) (*self).format_with_options(buf, parens, newlines, indent)
} }
fn format<'buf>(&self, buf: &mut Buf<'buf>, indent: u16) { fn format(&self, buf: &mut Buf<'_>, indent: u16) {
(*self).format(buf, indent) (*self).format(buf, indent)
} }
} }
@ -120,9 +120,9 @@ where
self.value.is_multiline() self.value.is_multiline()
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -131,7 +131,7 @@ where
.format_with_options(buf, parens, newlines, indent) .format_with_options(buf, parens, newlines, indent)
} }
fn format<'buf>(&self, buf: &mut Buf<'buf>, indent: u16) { fn format(&self, buf: &mut Buf<'_>, indent: u16) {
self.value.format(buf, indent) self.value.format(buf, indent)
} }
} }
@ -141,9 +141,9 @@ impl<'a> Formattable for UppercaseIdent<'a> {
false false
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
_indent: u16, _indent: u16,
@ -206,9 +206,9 @@ impl<'a> Formattable for TypeAnnotation<'a> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -424,9 +424,9 @@ impl<'a> Formattable for AssignedField<'a, TypeAnnotation<'a>> {
is_multiline_assigned_field_help(self) is_multiline_assigned_field_help(self)
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -441,9 +441,9 @@ impl<'a> Formattable for AssignedField<'a, Expr<'a>> {
is_multiline_assigned_field_help(self) is_multiline_assigned_field_help(self)
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -466,9 +466,9 @@ fn is_multiline_assigned_field_help<T: Formattable>(afield: &AssignedField<'_, T
} }
} }
fn format_assigned_field_help<'a, 'buf, T>( fn format_assigned_field_help<T>(
zelf: &AssignedField<'a, T>, zelf: &AssignedField<'_, T>,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
indent: u16, indent: u16,
separator_spaces: usize, separator_spaces: usize,
is_multiline: bool, is_multiline: bool,
@ -545,9 +545,9 @@ impl<'a> Formattable for Tag<'a> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -592,9 +592,9 @@ impl<'a> Formattable for HasClause<'a> {
false false
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -623,9 +623,9 @@ impl<'a> Formattable for HasImpls<'a> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -662,9 +662,9 @@ impl<'a> Formattable for HasAbility<'a> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -703,9 +703,9 @@ impl<'a> Formattable for HasAbilities<'a> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,

View file

@ -15,9 +15,9 @@ impl<'a> Formattable for Defs<'a> {
!self.tags.is_empty() !self.tags.is_empty()
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -57,9 +57,9 @@ impl<'a> Formattable for TypeDef<'a> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -171,9 +171,9 @@ impl<'a> Formattable for TypeHeader<'a> {
self.vars.iter().any(|v| v.is_multiline()) self.vars.iter().any(|v| v.is_multiline())
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -205,9 +205,9 @@ impl<'a> Formattable for ValueDef<'a> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -314,8 +314,8 @@ fn should_outdent(mut rhs: &TypeAnnotation) -> bool {
} }
} }
fn fmt_dbg_in_def<'a, 'buf>( fn fmt_dbg_in_def<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
condition: &'a Loc<Expr<'a>>, condition: &'a Loc<Expr<'a>>,
is_multiline: bool, is_multiline: bool,
indent: u16, indent: u16,
@ -335,8 +335,8 @@ fn fmt_dbg_in_def<'a, 'buf>(
condition.format(buf, return_indent); condition.format(buf, return_indent);
} }
fn fmt_expect<'a, 'buf>( fn fmt_expect<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
condition: &'a Loc<Expr<'a>>, condition: &'a Loc<Expr<'a>>,
is_multiline: bool, is_multiline: bool,
indent: u16, indent: u16,
@ -356,8 +356,8 @@ fn fmt_expect<'a, 'buf>(
condition.format(buf, return_indent); condition.format(buf, return_indent);
} }
fn fmt_expect_fx<'a, 'buf>( fn fmt_expect_fx<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
condition: &'a Loc<Expr<'a>>, condition: &'a Loc<Expr<'a>>,
is_multiline: bool, is_multiline: bool,
indent: u16, indent: u16,
@ -377,28 +377,19 @@ fn fmt_expect_fx<'a, 'buf>(
condition.format(buf, return_indent); condition.format(buf, return_indent);
} }
pub fn fmt_value_def<'a, 'buf>( pub fn fmt_value_def(buf: &mut Buf<'_>, def: &roc_parse::ast::ValueDef<'_>, indent: u16) {
buf: &mut Buf<'buf>,
def: &roc_parse::ast::ValueDef<'a>,
indent: u16,
) {
def.format(buf, indent); def.format(buf, indent);
} }
pub fn fmt_type_def<'a, 'buf>(buf: &mut Buf<'buf>, def: &roc_parse::ast::TypeDef<'a>, indent: u16) { pub fn fmt_type_def(buf: &mut Buf<'_>, def: &roc_parse::ast::TypeDef<'_>, indent: u16) {
def.format(buf, indent); def.format(buf, indent);
} }
pub fn fmt_defs<'a, 'buf>(buf: &mut Buf<'buf>, defs: &Defs<'a>, indent: u16) { pub fn fmt_defs(buf: &mut Buf<'_>, defs: &Defs<'_>, indent: u16) {
defs.format(buf, indent); defs.format(buf, indent);
} }
pub fn fmt_body<'a, 'buf>( pub fn fmt_body<'a>(buf: &mut Buf<'_>, pattern: &'a Pattern<'a>, body: &'a Expr<'a>, indent: u16) {
buf: &mut Buf<'buf>,
pattern: &'a Pattern<'a>,
body: &'a Expr<'a>,
indent: u16,
) {
pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent); pattern.format_with_options(buf, Parens::InApply, Newlines::No, indent);
buf.indent(indent); buf.indent(indent);
buf.push_str(" ="); buf.push_str(" =");
@ -462,9 +453,9 @@ impl<'a> Formattable for AbilityMember<'a> {
self.name.value.is_multiline() || self.typ.is_multiline() self.name.value.is_multiline() || self.typ.is_multiline()
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,

View file

@ -103,9 +103,9 @@ impl<'a> Formattable for Expr<'a> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -551,7 +551,7 @@ fn starts_with_newline(expr: &Expr) -> bool {
} }
} }
fn format_str_segment<'a, 'buf>(seg: &StrSegment<'a>, buf: &mut Buf<'buf>, indent: u16) { fn format_str_segment(seg: &StrSegment<'_>, buf: &mut Buf<'_>, indent: u16) {
use StrSegment::*; use StrSegment::*;
match seg { match seg {
@ -614,7 +614,7 @@ fn push_op(buf: &mut Buf, op: BinOp) {
} }
} }
pub fn fmt_str_literal<'buf>(buf: &mut Buf<'buf>, literal: StrLiteral, indent: u16) { pub fn fmt_str_literal(buf: &mut Buf<'_>, literal: StrLiteral, indent: u16) {
use roc_parse::ast::StrLiteral::*; use roc_parse::ast::StrLiteral::*;
match literal { match literal {
@ -673,8 +673,8 @@ pub fn fmt_str_literal<'buf>(buf: &mut Buf<'buf>, literal: StrLiteral, indent: u
} }
} }
fn fmt_binops<'a, 'buf>( fn fmt_binops<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
lefts: &'a [(Loc<Expr<'a>>, Loc<BinOp>)], lefts: &'a [(Loc<Expr<'a>>, Loc<BinOp>)],
loc_right_side: &'a Loc<Expr<'a>>, loc_right_side: &'a Loc<Expr<'a>>,
part_of_multi_line_binops: bool, part_of_multi_line_binops: bool,
@ -704,9 +704,9 @@ fn fmt_binops<'a, 'buf>(
loc_right_side.format_with_options(buf, Parens::InOperator, Newlines::Yes, indent); loc_right_side.format_with_options(buf, Parens::InOperator, Newlines::Yes, indent);
} }
fn format_spaces<'a, 'buf>( fn format_spaces(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
spaces: &[CommentOrNewline<'a>], spaces: &[CommentOrNewline<'_>],
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
) { ) {
@ -738,8 +738,8 @@ fn is_when_patterns_multiline(when_branch: &WhenBranch) -> bool {
is_multiline_patterns is_multiline_patterns
} }
fn fmt_when<'a, 'buf>( fn fmt_when<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
loc_condition: &'a Loc<Expr<'a>>, loc_condition: &'a Loc<Expr<'a>>,
branches: &[&'a WhenBranch<'a>], branches: &[&'a WhenBranch<'a>],
indent: u16, indent: u16,
@ -920,8 +920,8 @@ fn fmt_when<'a, 'buf>(
} }
} }
fn fmt_dbg<'a, 'buf>( fn fmt_dbg<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
condition: &'a Loc<Expr<'a>>, condition: &'a Loc<Expr<'a>>,
continuation: &'a Loc<Expr<'a>>, continuation: &'a Loc<Expr<'a>>,
is_multiline: bool, is_multiline: bool,
@ -947,8 +947,8 @@ fn fmt_dbg<'a, 'buf>(
continuation.format(buf, indent); continuation.format(buf, indent);
} }
fn fmt_expect<'a, 'buf>( fn fmt_expect<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
condition: &'a Loc<Expr<'a>>, condition: &'a Loc<Expr<'a>>,
continuation: &'a Loc<Expr<'a>>, continuation: &'a Loc<Expr<'a>>,
is_multiline: bool, is_multiline: bool,
@ -974,8 +974,8 @@ fn fmt_expect<'a, 'buf>(
continuation.format(buf, indent); continuation.format(buf, indent);
} }
fn fmt_if<'a, 'buf>( fn fmt_if<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
branches: &'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)], branches: &'a [(Loc<Expr<'a>>, Loc<Expr<'a>>)],
final_else: &'a Loc<Expr<'a>>, final_else: &'a Loc<Expr<'a>>,
is_multiline: bool, is_multiline: bool,
@ -1123,8 +1123,8 @@ fn fmt_if<'a, 'buf>(
final_else.format(buf, return_indent); final_else.format(buf, return_indent);
} }
fn fmt_closure<'a, 'buf>( fn fmt_closure<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
loc_patterns: &'a [Loc<Pattern<'a>>], loc_patterns: &'a [Loc<Pattern<'a>>],
loc_ret: &'a Loc<Expr<'a>>, loc_ret: &'a Loc<Expr<'a>>,
indent: u16, indent: u16,
@ -1224,8 +1224,8 @@ fn fmt_closure<'a, 'buf>(
} }
} }
fn fmt_backpassing<'a, 'buf>( fn fmt_backpassing<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
loc_patterns: &'a [Loc<Pattern<'a>>], loc_patterns: &'a [Loc<Pattern<'a>>],
loc_body: &'a Loc<Expr<'a>>, loc_body: &'a Loc<Expr<'a>>,
loc_ret: &'a Loc<Expr<'a>>, loc_ret: &'a Loc<Expr<'a>>,
@ -1312,8 +1312,8 @@ fn pattern_needs_parens_when_backpassing(pat: &Pattern) -> bool {
} }
} }
fn fmt_record<'a, 'buf>( fn fmt_record<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
update: Option<&'a Loc<Expr<'a>>>, update: Option<&'a Loc<Expr<'a>>>,
fields: Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>, fields: Collection<'a, Loc<AssignedField<'a, Expr<'a>>>>,
indent: u16, indent: u16,
@ -1404,9 +1404,9 @@ fn fmt_record<'a, 'buf>(
} }
} }
fn format_field_multiline<'a, 'buf, T>( fn format_field_multiline<T>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
field: &AssignedField<'a, T>, field: &AssignedField<'_, T>,
indent: u16, indent: u16,
separator_prefix: &str, separator_prefix: &str,
) where ) where

View file

@ -44,9 +44,9 @@ macro_rules! keywords {
false false
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: crate::annotation::Parens, _parens: crate::annotation::Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -86,9 +86,9 @@ impl<V: Formattable> Formattable for Option<V> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: crate::annotation::Parens, parens: crate::annotation::Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -111,9 +111,9 @@ impl<'a> Formattable for ProvidesTo<'a> {
|| self.to_keyword.is_multiline() || self.to_keyword.is_multiline()
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: crate::annotation::Parens, _parens: crate::annotation::Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -130,9 +130,9 @@ impl<'a> Formattable for PlatformRequires<'a> {
is_collection_multiline(&self.rigids) || self.signature.is_multiline() is_collection_multiline(&self.rigids) || self.signature.is_multiline()
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: crate::annotation::Parens, _parens: crate::annotation::Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -146,9 +146,9 @@ impl<'a, V: Formattable> Formattable for Spaces<'a, V> {
!self.before.is_empty() || !self.after.is_empty() || self.item.is_multiline() !self.before.is_empty() || !self.after.is_empty() || self.item.is_multiline()
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: crate::annotation::Parens, parens: crate::annotation::Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -164,9 +164,9 @@ impl<'a, K: Formattable, V: Formattable> Formattable for KeywordItem<'a, K, V> {
self.keyword.is_multiline() || self.item.is_multiline() self.keyword.is_multiline() || self.item.is_multiline()
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -177,7 +177,7 @@ impl<'a, K: Formattable, V: Formattable> Formattable for KeywordItem<'a, K, V> {
} }
} }
pub fn fmt_interface_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a InterfaceHeader<'a>) { pub fn fmt_interface_header<'a>(buf: &mut Buf<'_>, header: &'a InterfaceHeader<'a>) {
buf.indent(0); buf.indent(0);
buf.push_str("interface"); buf.push_str("interface");
let indent = INDENT; let indent = INDENT;
@ -193,7 +193,7 @@ pub fn fmt_interface_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a Interface
fmt_imports(buf, header.imports.item, indent); fmt_imports(buf, header.imports.item, indent);
} }
pub fn fmt_hosted_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a HostedHeader<'a>) { pub fn fmt_hosted_header<'a>(buf: &mut Buf<'_>, header: &'a HostedHeader<'a>) {
buf.indent(0); buf.indent(0);
buf.push_str("hosted"); buf.push_str("hosted");
let indent = INDENT; let indent = INDENT;
@ -210,7 +210,7 @@ pub fn fmt_hosted_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a HostedHeader
fmt_exposes(buf, header.generates_with.item, indent); fmt_exposes(buf, header.generates_with.item, indent);
} }
pub fn fmt_app_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a AppHeader<'a>) { pub fn fmt_app_header<'a>(buf: &mut Buf<'_>, header: &'a AppHeader<'a>) {
buf.indent(0); buf.indent(0);
buf.push_str("app"); buf.push_str("app");
let indent = INDENT; let indent = INDENT;
@ -229,7 +229,7 @@ pub fn fmt_app_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a AppHeader<'a>)
header.provides.format(buf, indent); header.provides.format(buf, indent);
} }
pub fn fmt_package_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a PackageHeader<'a>) { pub fn fmt_package_header<'a>(buf: &mut Buf<'_>, header: &'a PackageHeader<'a>) {
buf.indent(0); buf.indent(0);
buf.push_str("package"); buf.push_str("package");
let indent = INDENT; let indent = INDENT;
@ -243,7 +243,7 @@ pub fn fmt_package_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a PackageHead
fmt_packages(buf, header.packages.item, indent); fmt_packages(buf, header.packages.item, indent);
} }
pub fn fmt_platform_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a PlatformHeader<'a>) { pub fn fmt_platform_header<'a>(buf: &mut Buf<'_>, header: &'a PlatformHeader<'a>) {
buf.indent(0); buf.indent(0);
buf.push_str("platform"); buf.push_str("platform");
let indent = INDENT; let indent = INDENT;
@ -262,7 +262,7 @@ pub fn fmt_platform_header<'a, 'buf>(buf: &mut Buf<'buf>, header: &'a PlatformHe
fmt_provides(buf, header.provides.item, None, indent); fmt_provides(buf, header.provides.item, None, indent);
} }
fn fmt_requires<'a, 'buf>(buf: &mut Buf<'buf>, requires: &PlatformRequires<'a>, indent: u16) { fn fmt_requires(buf: &mut Buf<'_>, requires: &PlatformRequires<'_>, indent: u16) {
fmt_collection(buf, indent, Braces::Curly, requires.rigids, Newlines::No); fmt_collection(buf, indent, Braces::Curly, requires.rigids, Newlines::No);
buf.push_str(" {"); buf.push_str(" {");
@ -276,9 +276,9 @@ impl<'a> Formattable for TypedIdent<'a> {
false false
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -293,7 +293,7 @@ impl<'a> Formattable for TypedIdent<'a> {
} }
} }
fn fmt_package_name<'buf>(buf: &mut Buf<'buf>, name: PackageName, indent: u16) { fn fmt_package_name(buf: &mut Buf<'_>, name: PackageName, indent: u16) {
buf.indent(indent); buf.indent(indent);
buf.push('"'); buf.push('"');
buf.push_str_allow_spaces(name.to_str()); buf.push_str_allow_spaces(name.to_str());
@ -312,9 +312,9 @@ impl<'a, T: Formattable> Formattable for Spaced<'a, T> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: crate::annotation::Parens, parens: crate::annotation::Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,
@ -335,16 +335,16 @@ impl<'a, T: Formattable> Formattable for Spaced<'a, T> {
} }
} }
fn fmt_imports<'a, 'buf>( fn fmt_imports<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
loc_entries: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>, loc_entries: Collection<'a, Loc<Spaced<'a, ImportsEntry<'a>>>>,
indent: u16, indent: u16,
) { ) {
fmt_collection(buf, indent, Braces::Square, loc_entries, Newlines::No) fmt_collection(buf, indent, Braces::Square, loc_entries, Newlines::No)
} }
fn fmt_provides<'a, 'buf>( fn fmt_provides<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
loc_exposed_names: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>, loc_exposed_names: Collection<'a, Loc<Spaced<'a, ExposedName<'a>>>>,
loc_provided_types: Option<Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>>, loc_provided_types: Option<Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>>,
indent: u16, indent: u16,
@ -356,7 +356,7 @@ fn fmt_provides<'a, 'buf>(
} }
} }
fn fmt_to<'buf>(buf: &mut Buf<'buf>, to: To, indent: u16) { fn fmt_to(buf: &mut Buf<'_>, to: To, indent: u16) {
match to { match to {
To::ExistingPackage(name) => { To::ExistingPackage(name) => {
buf.push_str(name); buf.push_str(name);
@ -365,8 +365,8 @@ fn fmt_to<'buf>(buf: &mut Buf<'buf>, to: To, indent: u16) {
} }
} }
fn fmt_exposes<'buf, N: Formattable + Copy + core::fmt::Debug>( fn fmt_exposes<N: Formattable + Copy + core::fmt::Debug>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
loc_entries: Collection<'_, Loc<Spaced<'_, N>>>, loc_entries: Collection<'_, Loc<Spaced<'_, N>>>,
indent: u16, indent: u16,
) { ) {
@ -374,17 +374,17 @@ fn fmt_exposes<'buf, N: Formattable + Copy + core::fmt::Debug>(
} }
pub trait FormatName { pub trait FormatName {
fn format<'buf>(&self, buf: &mut Buf<'buf>); fn format(&self, buf: &mut Buf<'_>);
} }
impl<'a> FormatName for &'a str { impl<'a> FormatName for &'a str {
fn format<'buf>(&self, buf: &mut Buf<'buf>) { fn format(&self, buf: &mut Buf<'_>) {
buf.push_str(self) buf.push_str(self)
} }
} }
impl<'a> FormatName for ModuleName<'a> { impl<'a> FormatName for ModuleName<'a> {
fn format<'buf>(&self, buf: &mut Buf<'buf>) { fn format(&self, buf: &mut Buf<'_>) {
buf.push_str(self.as_str()); buf.push_str(self.as_str());
} }
} }
@ -394,9 +394,9 @@ impl<'a> Formattable for ModuleName<'a> {
false false
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
_indent: u16, _indent: u16,
@ -410,9 +410,9 @@ impl<'a> Formattable for ExposedName<'a> {
false false
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -423,13 +423,13 @@ impl<'a> Formattable for ExposedName<'a> {
} }
impl<'a> FormatName for ExposedName<'a> { impl<'a> FormatName for ExposedName<'a> {
fn format<'buf>(&self, buf: &mut Buf<'buf>) { fn format(&self, buf: &mut Buf<'_>) {
buf.push_str(self.as_str()); buf.push_str(self.as_str());
} }
} }
fn fmt_packages<'a, 'buf>( fn fmt_packages<'a>(
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
loc_entries: Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>, loc_entries: Collection<'a, Loc<Spaced<'a, PackageEntry<'a>>>>,
indent: u16, indent: u16,
) { ) {
@ -441,9 +441,9 @@ impl<'a> Formattable for PackageEntry<'a> {
false false
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -457,9 +457,9 @@ impl<'a> Formattable for ImportsEntry<'a> {
false false
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -467,14 +467,14 @@ impl<'a> Formattable for ImportsEntry<'a> {
fmt_imports_entry(buf, self, indent); fmt_imports_entry(buf, self, indent);
} }
} }
fn fmt_packages_entry<'a, 'buf>(buf: &mut Buf<'buf>, entry: &PackageEntry<'a>, indent: u16) { fn fmt_packages_entry(buf: &mut Buf<'_>, entry: &PackageEntry<'_>, indent: u16) {
buf.push_str(entry.shorthand); buf.push_str(entry.shorthand);
buf.push(':'); buf.push(':');
fmt_default_spaces(buf, entry.spaces_after_shorthand, indent); fmt_default_spaces(buf, entry.spaces_after_shorthand, indent);
fmt_package_name(buf, entry.package_name.value, indent); fmt_package_name(buf, entry.package_name.value, indent);
} }
fn fmt_imports_entry<'a, 'buf>(buf: &mut Buf<'buf>, entry: &ImportsEntry<'a>, indent: u16) { fn fmt_imports_entry(buf: &mut Buf<'_>, entry: &ImportsEntry<'_>, indent: u16) {
use roc_parse::header::ImportsEntry::*; use roc_parse::header::ImportsEntry::*;
buf.indent(indent); buf.indent(indent);

View file

@ -4,12 +4,7 @@ use crate::spaces::{fmt_comments_only, fmt_spaces, NewlineAt, INDENT};
use crate::Buf; use crate::Buf;
use roc_parse::ast::{Base, CommentOrNewline, Pattern, PatternAs}; use roc_parse::ast::{Base, CommentOrNewline, Pattern, PatternAs};
pub fn fmt_pattern<'a, 'buf>( pub fn fmt_pattern<'a>(buf: &mut Buf<'_>, pattern: &'a Pattern<'a>, indent: u16, parens: Parens) {
buf: &mut Buf<'buf>,
pattern: &'a Pattern<'a>,
indent: u16,
parens: Parens,
) {
pattern.format_with_options(buf, parens, Newlines::No, indent); pattern.format_with_options(buf, parens, Newlines::No, indent);
} }
@ -18,9 +13,9 @@ impl<'a> Formattable for PatternAs<'a> {
self.spaces_before.iter().any(|s| s.is_comment()) self.spaces_before.iter().any(|s| s.is_comment())
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
_parens: Parens, _parens: Parens,
_newlines: Newlines, _newlines: Newlines,
indent: u16, indent: u16,
@ -85,9 +80,9 @@ impl<'a> Formattable for Pattern<'a> {
} }
} }
fn format_with_options<'buf>( fn format_with_options(
&self, &self,
buf: &mut Buf<'buf>, buf: &mut Buf<'_>,
parens: Parens, parens: Parens,
newlines: Newlines, newlines: Newlines,
indent: u16, indent: u16,

View file

@ -21,22 +21,14 @@ use crate::{Ast, Buf};
/// The number of spaces to indent. /// The number of spaces to indent.
pub const INDENT: u16 = 4; pub const INDENT: u16 = 4;
pub fn fmt_default_spaces<'a, 'buf>( pub fn fmt_default_spaces(buf: &mut Buf<'_>, spaces: &[CommentOrNewline<'_>], indent: u16) {
buf: &mut Buf<'buf>,
spaces: &[CommentOrNewline<'a>],
indent: u16,
) {
if spaces.is_empty() { if spaces.is_empty() {
buf.spaces(1); buf.spaces(1);
} else { } else {
fmt_spaces(buf, spaces.iter(), indent); fmt_spaces(buf, spaces.iter(), indent);
} }
} }
pub fn fmt_default_newline<'a, 'buf>( pub fn fmt_default_newline(buf: &mut Buf<'_>, spaces: &[CommentOrNewline<'_>], indent: u16) {
buf: &mut Buf<'buf>,
spaces: &[CommentOrNewline<'a>],
indent: u16,
) {
if spaces.is_empty() { if spaces.is_empty() {
buf.newline(); buf.newline();
} else { } else {
@ -153,7 +145,7 @@ pub fn fmt_comments_only<'a, 'buf, I>(
} }
} }
fn fmt_comment<'buf>(buf: &mut Buf<'buf>, comment: &str) { fn fmt_comment(buf: &mut Buf<'_>, comment: &str) {
// The '#' in a comment should always be preceded by a newline or a space, // The '#' in a comment should always be preceded by a newline or a space,
// unless it's the very beginning of the buffer. // unless it's the very beginning of the buffer.
if !buf.is_empty() && !buf.ends_with_space() && !buf.ends_with_newline() { if !buf.is_empty() && !buf.ends_with_space() && !buf.ends_with_newline() {
@ -192,7 +184,7 @@ where
count count
} }
fn fmt_docs<'buf>(buf: &mut Buf<'buf>, docs: &str) { fn fmt_docs(buf: &mut Buf<'_>, docs: &str) {
// The "##" in a doc comment should always be preceded by a newline or a space, // The "##" in a doc comment should always be preceded by a newline or a space,
// unless it's the very beginning of the buffer. // unless it's the very beginning of the buffer.
if !buf.is_empty() && !buf.ends_with_space() && !buf.ends_with_newline() { if !buf.is_empty() && !buf.ends_with_space() && !buf.ends_with_newline() {

File diff suppressed because it is too large Load diff

View file

@ -7,13 +7,15 @@ use roc_builtins::bitcode::{self, FloatWidth, IntWidth};
use roc_collections::all::MutMap; use roc_collections::all::MutMap;
use roc_error_macros::internal_error; use roc_error_macros::internal_error;
use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_mono::code_gen_help::CodeGenHelp; use roc_mono::code_gen_help::{CallerProc, CodeGenHelp, HelperOp};
use roc_mono::ir::{ use roc_mono::ir::{
BranchInfo, JoinPointId, ListLiteralElement, Literal, Param, ProcLayout, SelfRecursive, Stmt, BranchInfo, HigherOrderLowLevel, JoinPointId, ListLiteralElement, Literal, Param, ProcLayout,
SelfRecursive, Stmt,
}; };
use roc_mono::layout::{ use roc_mono::layout::{
Builtin, InLayout, Layout, LayoutInterner, STLayoutInterner, TagIdIntType, UnionLayout, Builtin, InLayout, Layout, LayoutInterner, STLayoutInterner, TagIdIntType, UnionLayout,
}; };
use roc_mono::low_level::HigherOrder;
use roc_target::TargetInfo; use roc_target::TargetInfo;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -62,15 +64,15 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
!Self::float_callee_saved(reg) !Self::float_callee_saved(reg)
} }
fn setup_stack<'a>( fn setup_stack(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'_, u8>,
general_saved_regs: &[GeneralReg], general_saved_regs: &[GeneralReg],
float_saved_regs: &[FloatReg], float_saved_regs: &[FloatReg],
requested_stack_size: i32, requested_stack_size: i32,
fn_call_stack_size: i32, fn_call_stack_size: i32,
) -> i32; ) -> i32;
fn cleanup_stack<'a>( fn cleanup_stack(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'_, u8>,
general_saved_regs: &[GeneralReg], general_saved_regs: &[GeneralReg],
float_saved_regs: &[FloatReg], float_saved_regs: &[FloatReg],
aligned_stack_size: i32, aligned_stack_size: i32,
@ -78,9 +80,9 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
); );
/// load_args updates the storage manager to know where every arg is stored. /// load_args updates the storage manager to know where every arg is stored.
fn load_args<'a, 'r>( fn load_args<'a>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, Self>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, Self>,
layout_interner: &mut STLayoutInterner<'a>, layout_interner: &mut STLayoutInterner<'a>,
args: &'a [(InLayout<'a>, Symbol)], args: &'a [(InLayout<'a>, Symbol)],
// ret_layout is needed because if it is a complex type, we pass a pointer as the first arg. // ret_layout is needed because if it is a complex type, we pass a pointer as the first arg.
@ -89,9 +91,9 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
/// store_args stores the args in registers and on the stack for function calling. /// store_args stores the args in registers and on the stack for function calling.
/// It also updates the amount of temporary stack space needed in the storage manager. /// It also updates the amount of temporary stack space needed in the storage manager.
fn store_args<'a, 'r>( fn store_args<'a>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, Self>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, Self>,
layout_interner: &mut STLayoutInterner<'a>, layout_interner: &mut STLayoutInterner<'a>,
dst: &Symbol, dst: &Symbol,
args: &[Symbol], args: &[Symbol],
@ -102,9 +104,9 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
/// return_complex_symbol returns the specified complex/non-primative symbol. /// return_complex_symbol returns the specified complex/non-primative symbol.
/// It uses the layout to determine how the data should be returned. /// It uses the layout to determine how the data should be returned.
fn return_complex_symbol<'a, 'r>( fn return_complex_symbol<'a>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, Self>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, Self>,
layout_interner: &mut STLayoutInterner<'a>, layout_interner: &mut STLayoutInterner<'a>,
sym: &Symbol, sym: &Symbol,
layout: &InLayout<'a>, layout: &InLayout<'a>,
@ -112,9 +114,9 @@ pub trait CallConv<GeneralReg: RegTrait, FloatReg: RegTrait, ASM: Assembler<Gene
/// load_returned_complex_symbol loads a complex symbol that was returned from a function call. /// load_returned_complex_symbol loads a complex symbol that was returned from a function call.
/// It uses the layout to determine how the data should be loaded into the symbol. /// It uses the layout to determine how the data should be loaded into the symbol.
fn load_returned_complex_symbol<'a, 'r>( fn load_returned_complex_symbol<'a>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, Self>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, Self>,
layout_interner: &mut STLayoutInterner<'a>, layout_interner: &mut STLayoutInterner<'a>,
sym: &Symbol, sym: &Symbol,
layout: &InLayout<'a>, layout: &InLayout<'a>,
@ -184,9 +186,9 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
src2: GeneralReg, src2: GeneralReg,
); );
fn shl_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn shl_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, CC>,
dst: GeneralReg, dst: GeneralReg,
src1: GeneralReg, src1: GeneralReg,
src2: GeneralReg, src2: GeneralReg,
@ -194,9 +196,9 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
ASM: Assembler<GeneralReg, FloatReg>, ASM: Assembler<GeneralReg, FloatReg>,
CC: CallConv<GeneralReg, FloatReg, ASM>; CC: CallConv<GeneralReg, FloatReg, ASM>;
fn shr_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn shr_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, CC>,
dst: GeneralReg, dst: GeneralReg,
src1: GeneralReg, src1: GeneralReg,
src2: GeneralReg, src2: GeneralReg,
@ -204,9 +206,9 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
ASM: Assembler<GeneralReg, FloatReg>, ASM: Assembler<GeneralReg, FloatReg>,
CC: CallConv<GeneralReg, FloatReg, ASM>; CC: CallConv<GeneralReg, FloatReg, ASM>;
fn sar_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn sar_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, CC>,
dst: GeneralReg, dst: GeneralReg,
src1: GeneralReg, src1: GeneralReg,
src2: GeneralReg, src2: GeneralReg,
@ -216,6 +218,13 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
fn call(buf: &mut Vec<'_, u8>, relocs: &mut Vec<'_, Relocation>, fn_name: String); fn call(buf: &mut Vec<'_, u8>, relocs: &mut Vec<'_, Relocation>, fn_name: String);
fn function_pointer(
buf: &mut Vec<'_, u8>,
relocs: &mut Vec<'_, Relocation>,
fn_name: String,
dst: GeneralReg,
);
/// Jumps by an offset of offset bytes unconditionally. /// Jumps by an offset of offset bytes unconditionally.
/// It should always generate the same number of bytes to enable replacement if offset changes. /// It should always generate the same number of bytes to enable replacement if offset changes.
/// It returns the base offset to calculate the jump from (generally the instruction after the jump). /// It returns the base offset to calculate the jump from (generally the instruction after the jump).
@ -359,9 +368,9 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
src1: GeneralReg, src1: GeneralReg,
src2: GeneralReg, src2: GeneralReg,
); );
fn umul_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn umul_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, CC>,
dst: GeneralReg, dst: GeneralReg,
src1: GeneralReg, src1: GeneralReg,
src2: GeneralReg, src2: GeneralReg,
@ -369,18 +378,18 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
ASM: Assembler<GeneralReg, FloatReg>, ASM: Assembler<GeneralReg, FloatReg>,
CC: CallConv<GeneralReg, FloatReg, ASM>; CC: CallConv<GeneralReg, FloatReg, ASM>;
fn idiv_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn idiv_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, CC>,
dst: GeneralReg, dst: GeneralReg,
src1: GeneralReg, src1: GeneralReg,
src2: GeneralReg, src2: GeneralReg,
) where ) where
ASM: Assembler<GeneralReg, FloatReg>, ASM: Assembler<GeneralReg, FloatReg>,
CC: CallConv<GeneralReg, FloatReg, ASM>; CC: CallConv<GeneralReg, FloatReg, ASM>;
fn udiv_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn udiv_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, GeneralReg, FloatReg, ASM, CC>,
dst: GeneralReg, dst: GeneralReg,
src1: GeneralReg, src1: GeneralReg,
src2: GeneralReg, src2: GeneralReg,
@ -447,20 +456,6 @@ pub trait Assembler<GeneralReg: RegTrait, FloatReg: RegTrait>: Sized + Copy {
fn to_float_freg64_freg32(buf: &mut Vec<'_, u8>, dst: FloatReg, src: FloatReg); fn to_float_freg64_freg32(buf: &mut Vec<'_, u8>, dst: FloatReg, src: FloatReg);
fn lte_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>,
dst: GeneralReg,
src1: GeneralReg,
src2: GeneralReg,
);
fn gte_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>,
dst: GeneralReg,
src1: GeneralReg,
src2: GeneralReg,
);
fn set_if_overflow(buf: &mut Vec<'_, u8>, dst: GeneralReg); fn set_if_overflow(buf: &mut Vec<'_, u8>, dst: GeneralReg);
fn ret(buf: &mut Vec<'_, u8>); fn ret(buf: &mut Vec<'_, u8>);
@ -489,6 +484,7 @@ pub struct Backend64Bit<
interns: &'r mut Interns, interns: &'r mut Interns,
helper_proc_gen: CodeGenHelp<'a>, helper_proc_gen: CodeGenHelp<'a>,
helper_proc_symbols: Vec<'a, (Symbol, ProcLayout<'a>)>, helper_proc_symbols: Vec<'a, (Symbol, ProcLayout<'a>)>,
caller_procs: Vec<'a, CallerProc<'a>>,
buf: Vec<'a, u8>, buf: Vec<'a, u8>,
relocs: Vec<'a, Relocation>, relocs: Vec<'a, Relocation>,
proc_name: Option<String>, proc_name: Option<String>,
@ -526,6 +522,7 @@ pub fn new_backend_64bit<
layout_interner, layout_interner,
helper_proc_gen: CodeGenHelp::new(env.arena, target_info, env.module_id), helper_proc_gen: CodeGenHelp::new(env.arena, target_info, env.module_id),
helper_proc_symbols: bumpalo::vec![in env.arena], helper_proc_symbols: bumpalo::vec![in env.arena],
caller_procs: bumpalo::vec![in env.arena],
proc_name: None, proc_name: None,
is_self_recursive: None, is_self_recursive: None,
buf: bumpalo::vec![in env.arena], buf: bumpalo::vec![in env.arena],
@ -567,6 +564,9 @@ impl<
fn interns(&self) -> &Interns { fn interns(&self) -> &Interns {
self.interns self.interns
} }
fn interns_mut(&mut self) -> &mut Interns {
self.interns
}
fn interner(&self) -> &STLayoutInterner<'a> { fn interner(&self) -> &STLayoutInterner<'a> {
self.layout_interner self.layout_interner
} }
@ -577,12 +577,14 @@ impl<
&mut STLayoutInterner<'a>, &mut STLayoutInterner<'a>,
&mut Interns, &mut Interns,
&mut CodeGenHelp<'a>, &mut CodeGenHelp<'a>,
&mut Vec<'a, CallerProc<'a>>,
) { ) {
( (
self.env.module_id, self.env.module_id,
self.layout_interner, self.layout_interner,
self.interns, self.interns,
&mut self.helper_proc_gen, &mut self.helper_proc_gen,
&mut self.caller_procs,
) )
} }
fn helper_proc_gen_mut(&mut self) -> &mut CodeGenHelp<'a> { fn helper_proc_gen_mut(&mut self) -> &mut CodeGenHelp<'a> {
@ -738,6 +740,12 @@ impl<
(out.into_bump_slice(), offset) (out.into_bump_slice(), offset)
} }
fn build_fn_pointer(&mut self, dst: &Symbol, fn_name: String) {
let reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
ASM::function_pointer(&mut self.buf, &mut self.relocs, fn_name, reg)
}
fn build_fn_call( fn build_fn_call(
&mut self, &mut self,
dst: &Symbol, dst: &Symbol,
@ -746,11 +754,6 @@ impl<
arg_layouts: &[InLayout<'a>], arg_layouts: &[InLayout<'a>],
ret_layout: &InLayout<'a>, ret_layout: &InLayout<'a>,
) { ) {
if let Some(SelfRecursive::SelfRecursive(id)) = self.is_self_recursive {
if &fn_name == self.proc_name.as_ref().unwrap() && self.join_map.contains_key(&id) {
return self.build_jump(&id, args, arg_layouts, ret_layout);
}
}
// Save used caller saved regs. // Save used caller saved regs.
self.storage_manager self.storage_manager
.push_used_caller_saved_regs_to_stack(&mut self.buf); .push_used_caller_saved_regs_to_stack(&mut self.buf);
@ -1221,6 +1224,9 @@ impl<
.load_to_general_reg(&mut self.buf, src2); .load_to_general_reg(&mut self.buf, src2);
ASM::eq_reg64_reg64_reg64(&mut self.buf, width, dst_reg, src1_reg, src2_reg); ASM::eq_reg64_reg64_reg64(&mut self.buf, width, dst_reg, src1_reg, src2_reg);
} }
Layout::F32 => todo!("NumEq: layout, {:?}", self.layout_interner.dbg(Layout::F32)),
Layout::F64 => todo!("NumEq: layout, {:?}", self.layout_interner.dbg(Layout::F64)),
Layout::DEC => todo!("NumEq: layout, {:?}", self.layout_interner.dbg(Layout::DEC)),
Layout::STR => { Layout::STR => {
// use a zig call // use a zig call
self.build_fn_call( self.build_fn_call(
@ -1241,7 +1247,33 @@ impl<
let dst_reg = self.storage_manager.load_to_general_reg(&mut self.buf, dst); let dst_reg = self.storage_manager.load_to_general_reg(&mut self.buf, dst);
ASM::eq_reg64_reg64_reg64(&mut self.buf, width, dst_reg, dst_reg, tmp_reg); ASM::eq_reg64_reg64_reg64(&mut self.buf, width, dst_reg, dst_reg, tmp_reg);
} }
x => todo!("NumEq: layout, {:?}", x), other => {
let ident_ids = self
.interns
.all_ident_ids
.get_mut(&self.env.module_id)
.unwrap();
// generate a proc
let (eq_symbol, eq_linker_data) = self.helper_proc_gen.gen_refcount_proc(
ident_ids,
self.layout_interner,
other,
HelperOp::Eq,
);
let fn_name = self.function_symbol_to_string(
eq_symbol,
[other, other].into_iter(),
None,
Layout::U8,
);
self.helper_proc_symbols.extend(eq_linker_data);
self.build_fn_call(dst, fn_name, &[*src1, *src2], &[other, other], &Layout::U8)
}
} }
} }
@ -1304,126 +1336,6 @@ impl<
} }
} }
fn build_num_lt(
&mut self,
dst: &Symbol,
src1: &Symbol,
src2: &Symbol,
arg_layout: &InLayout<'a>,
) {
match self.layout_interner.get(*arg_layout) {
Layout::Builtin(Builtin::Int(IntWidth::I64)) => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src1);
let src2_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src2);
ASM::signed_compare_reg64(
&mut self.buf,
RegisterWidth::W64,
CompareOperation::LessThan,
dst_reg,
src1_reg,
src2_reg,
);
}
Layout::Builtin(Builtin::Int(IntWidth::U64)) => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src1);
let src2_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src2);
ASM::unsigned_compare_reg64(
&mut self.buf,
RegisterWidth::W64,
CompareOperation::LessThan,
dst_reg,
src1_reg,
src2_reg,
);
}
Layout::Builtin(Builtin::Float(width)) => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::cmp_freg_freg_reg64(
&mut self.buf,
dst_reg,
src1_reg,
src2_reg,
width,
CompareOperation::LessThan,
);
}
x => todo!("NumLt: layout, {:?}", x),
}
}
fn build_num_gt(
&mut self,
dst: &Symbol,
src1: &Symbol,
src2: &Symbol,
arg_layout: &InLayout<'a>,
) {
match self.layout_interner.get(*arg_layout) {
Layout::Builtin(Builtin::Int(IntWidth::I64)) => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src1);
let src2_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src2);
ASM::signed_compare_reg64(
&mut self.buf,
RegisterWidth::W64,
CompareOperation::GreaterThan,
dst_reg,
src1_reg,
src2_reg,
);
}
Layout::Builtin(Builtin::Int(IntWidth::U64)) => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src1);
let src2_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src2);
ASM::unsigned_compare_reg64(
&mut self.buf,
RegisterWidth::W64,
CompareOperation::GreaterThan,
dst_reg,
src1_reg,
src2_reg,
);
}
Layout::Builtin(Builtin::Float(width)) => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::cmp_freg_freg_reg64(
&mut self.buf,
dst_reg,
src1_reg,
src2_reg,
width,
CompareOperation::GreaterThan,
);
}
x => todo!("NumGt: layout, {:?}", x),
}
}
fn build_num_to_frac( fn build_num_to_frac(
&mut self, &mut self,
dst: &Symbol, dst: &Symbol,
@ -1482,6 +1394,26 @@ impl<
} }
} }
fn build_num_lt(
&mut self,
dst: &Symbol,
src1: &Symbol,
src2: &Symbol,
arg_layout: &InLayout<'a>,
) {
self.compare(CompareOperation::LessThan, dst, src1, src2, arg_layout)
}
fn build_num_gt(
&mut self,
dst: &Symbol,
src1: &Symbol,
src2: &Symbol,
arg_layout: &InLayout<'a>,
) {
self.compare(CompareOperation::GreaterThan, dst, src1, src2, arg_layout)
}
fn build_num_lte( fn build_num_lte(
&mut self, &mut self,
dst: &Symbol, dst: &Symbol,
@ -1489,39 +1421,13 @@ impl<
src2: &Symbol, src2: &Symbol,
arg_layout: &InLayout<'a>, arg_layout: &InLayout<'a>,
) { ) {
match *arg_layout { self.compare(
single_register_int_builtins!() => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src1);
let src2_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src2);
ASM::lte_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
Layout::F64 | Layout::F32 => {
let width = if *arg_layout == Layout::F64 {
FloatWidth::F64
} else {
FloatWidth::F32
};
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::cmp_freg_freg_reg64(
&mut self.buf,
dst_reg,
src1_reg,
src2_reg,
width,
CompareOperation::LessThanOrEqual, CompareOperation::LessThanOrEqual,
); dst,
} src1,
x => todo!("NumLte: layout, {:?}", x), src2,
} arg_layout,
)
} }
fn build_num_gte( fn build_num_gte(
@ -1531,38 +1437,178 @@ impl<
src2: &Symbol, src2: &Symbol,
arg_layout: &InLayout<'a>, arg_layout: &InLayout<'a>,
) { ) {
match *arg_layout { self.compare(
single_register_int_builtins!() => {
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src1);
let src2_reg = self
.storage_manager
.load_to_general_reg(&mut self.buf, src2);
ASM::gte_reg64_reg64_reg64(&mut self.buf, dst_reg, src1_reg, src2_reg);
}
Layout::F64 | Layout::F32 => {
let width = if *arg_layout == Layout::F64 {
FloatWidth::F64
} else {
FloatWidth::F32
};
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::cmp_freg_freg_reg64(
&mut self.buf,
dst_reg,
src1_reg,
src2_reg,
width,
CompareOperation::GreaterThanOrEqual, CompareOperation::GreaterThanOrEqual,
); dst,
src1,
src2,
arg_layout,
)
} }
x => todo!("NumGte: layout, {:?}", x),
fn build_higher_order_lowlevel(
&mut self,
dst: &Symbol,
higher_order: &HigherOrderLowLevel<'a>,
ret_layout: InLayout<'a>,
) {
let ident_ids = self
.interns
.all_ident_ids
.get_mut(&self.env.module_id)
.unwrap();
let (inc_n_data_symbol, inc_n_data_linker_data) = self.helper_proc_gen.gen_refcount_proc(
ident_ids,
self.layout_interner,
Layout::UNIT,
HelperOp::Inc,
);
let caller_proc = CallerProc::new(
self.env.arena,
self.env.module_id,
ident_ids,
self.layout_interner,
&higher_order.passed_function,
higher_order.closure_env_layout,
);
match higher_order.op {
HigherOrder::ListMap { xs } => {
let old_element_layout = higher_order.passed_function.argument_layouts[0];
let new_element_layout = higher_order.passed_function.return_layout;
let input_list_layout = Layout::Builtin(Builtin::List(old_element_layout));
let input_list_in_layout = self.layout_interner.insert(input_list_layout);
let caller = self.debug_symbol("caller");
let data = self.debug_symbol("data");
let alignment = self.debug_symbol("alignment");
let old_element_width = self.debug_symbol("old_element_width");
let new_element_width = self.debug_symbol("new_element_width");
self.load_layout_alignment(new_element_layout, alignment);
self.load_layout_stack_size(old_element_layout, old_element_width);
self.load_layout_stack_size(new_element_layout, new_element_width);
self.helper_proc_symbols.extend(inc_n_data_linker_data);
self.helper_proc_symbols
.extend([(caller_proc.proc_symbol, caller_proc.proc_layout)]);
let inc_n_data_string = self.function_symbol_to_string(
inc_n_data_symbol,
std::iter::empty(),
None,
Layout::UNIT,
);
let caller_string = self.function_symbol_to_string(
caller_proc.proc_symbol,
std::iter::empty(),
None,
Layout::UNIT,
);
self.caller_procs.push(caller_proc);
let inc_n_data = Symbol::DEV_TMP5;
self.build_fn_pointer(&inc_n_data, inc_n_data_string);
self.build_fn_pointer(&caller, caller_string);
if let Some(_closure_data_layout) = higher_order.closure_env_layout {
let data_symbol = higher_order.passed_function.captured_environment;
self.storage_manager
.ensure_symbol_on_stack(&mut self.buf, &data_symbol);
let (new_elem_offset, _) =
self.storage_manager.stack_offset_and_size(&data_symbol);
// Load address of output element into register.
let reg = self.storage_manager.claim_general_reg(&mut self.buf, &data);
ASM::add_reg64_reg64_imm32(
&mut self.buf,
reg,
CC::BASE_PTR_REG,
new_elem_offset,
);
} else {
// use a null pointer
self.load_literal(&data, &Layout::U64, &Literal::Int(0u128.to_be_bytes()));
}
self.load_literal(
&Symbol::DEV_TMP3,
&Layout::BOOL,
&Literal::Bool(higher_order.passed_function.owns_captured_environment),
);
// list: RocList,
// caller: Caller1,
// data: Opaque,
// inc_n_data: IncN,
// data_is_owned: bool,
// alignment: u32,
// old_element_width: usize,
// new_element_width: usize,
let arguments = [
xs,
caller,
data,
inc_n_data,
Symbol::DEV_TMP3,
alignment,
old_element_width,
new_element_width,
];
let ptr = Layout::U64;
let usize_ = Layout::U64;
let layouts = [
input_list_in_layout,
ptr,
ptr,
ptr,
Layout::BOOL,
Layout::U32,
usize_,
usize_,
];
// Setup the return location.
let base_offset = self
.storage_manager
.claim_stack_area(dst, self.layout_interner.stack_size(ret_layout));
self.build_fn_call(
&Symbol::DEV_TMP4,
bitcode::LIST_MAP.to_string(),
&arguments,
&layouts,
&ret_layout,
);
self.free_symbol(&Symbol::DEV_TMP3);
self.free_symbol(&Symbol::DEV_TMP5);
// Return list value from fn call
self.storage_manager.copy_symbol_to_stack_offset(
self.layout_interner,
&mut self.buf,
base_offset,
&Symbol::DEV_TMP4,
&ret_layout,
);
self.free_symbol(&Symbol::DEV_TMP4);
}
HigherOrder::ListMap2 { .. } => todo!(),
HigherOrder::ListMap3 { .. } => todo!(),
HigherOrder::ListMap4 { .. } => todo!(),
HigherOrder::ListSortWith { .. } => todo!(),
} }
} }
@ -1589,8 +1635,7 @@ impl<
.storage_manager .storage_manager
.claim_stack_area(dst, self.layout_interner.stack_size(*ret_layout)); .claim_stack_area(dst, self.layout_interner.stack_size(*ret_layout));
let lowlevel_args = bumpalo::vec![ let lowlevel_args = [
in self.env.arena;
capacity, capacity,
// alignment // alignment
Symbol::DEV_TMP, Symbol::DEV_TMP,
@ -1727,13 +1772,12 @@ impl<
.storage_manager .storage_manager
.claim_stack_area(dst, self.layout_interner.stack_size(*ret_layout)); .claim_stack_area(dst, self.layout_interner.stack_size(*ret_layout));
let lowlevel_args = bumpalo::vec![ let lowlevel_args = [
in self.env.arena;
list, list,
// element // element
Symbol::DEV_TMP, Symbol::DEV_TMP,
// element_width // element_width
Symbol::DEV_TMP2 Symbol::DEV_TMP2,
]; ];
let lowlevel_arg_layouts = [list_layout, Layout::U64, Layout::U64]; let lowlevel_arg_layouts = [list_layout, Layout::U64, Layout::U64];
@ -1776,7 +1820,7 @@ impl<
self.storage_manager.with_tmp_general_reg( self.storage_manager.with_tmp_general_reg(
&mut self.buf, &mut self.buf,
|storage_manager, buf, list_ptr| { |storage_manager, buf, list_ptr| {
ASM::mov_reg64_base32(buf, list_ptr, base_offset as i32); ASM::mov_reg64_base32(buf, list_ptr, base_offset);
storage_manager.with_tmp_general_reg(buf, |storage_manager, buf, tmp| { storage_manager.with_tmp_general_reg(buf, |storage_manager, buf, tmp| {
// calculate `element_width * index` // calculate `element_width * index`
ASM::mov_reg64_imm64(buf, tmp, ret_stack_size as i64); ASM::mov_reg64_imm64(buf, tmp, ret_stack_size as i64);
@ -2004,8 +2048,7 @@ impl<
.storage_manager .storage_manager
.claim_stack_area(dst, self.layout_interner.stack_size(*ret_layout)); .claim_stack_area(dst, self.layout_interner.stack_size(*ret_layout));
let lowlevel_args = bumpalo::vec![ let lowlevel_args = [
in self.env.arena;
list, list,
// alignment // alignment
Symbol::DEV_TMP, Symbol::DEV_TMP,
@ -2195,27 +2238,16 @@ impl<
} }
} }
fn expr_box(&mut self, sym: Symbol, value: Symbol, element_layout: InLayout<'a>) { fn build_ptr_write(
let element_width_symbol = Symbol::DEV_TMP; &mut self,
self.load_layout_stack_size(element_layout, element_width_symbol); sym: Symbol,
ptr: Symbol,
// Load allocation alignment (u32) value: Symbol,
let element_alignment_symbol = Symbol::DEV_TMP2; element_layout: InLayout<'a>,
self.load_layout_alignment(Layout::U32, element_alignment_symbol); ) {
self.allocate_with_refcount(
Symbol::DEV_TMP3,
element_width_symbol,
element_alignment_symbol,
);
self.free_symbol(&element_width_symbol);
self.free_symbol(&element_alignment_symbol);
// Fill pointer with the value
let ptr_reg = self let ptr_reg = self
.storage_manager .storage_manager
.load_to_general_reg(&mut self.buf, &Symbol::DEV_TMP3); .load_to_general_reg(&mut self.buf, &ptr);
let element_width = self.layout_interner.stack_size(element_layout) as u64; let element_width = self.layout_interner.stack_size(element_layout) as u64;
let element_offset = 0; let element_offset = 0;
@ -2237,6 +2269,26 @@ impl<
// box is just a pointer on the stack // box is just a pointer on the stack
let base_offset = self.storage_manager.claim_stack_area(&sym, 8); let base_offset = self.storage_manager.claim_stack_area(&sym, 8);
ASM::mov_base32_reg64(&mut self.buf, base_offset, ptr_reg); ASM::mov_base32_reg64(&mut self.buf, base_offset, ptr_reg);
}
fn expr_box(&mut self, sym: Symbol, value: Symbol, element_layout: InLayout<'a>) {
let element_width_symbol = Symbol::DEV_TMP;
self.load_layout_stack_size(element_layout, element_width_symbol);
// Load allocation alignment (u32)
let element_alignment_symbol = Symbol::DEV_TMP2;
self.load_layout_alignment(Layout::U32, element_alignment_symbol);
self.allocate_with_refcount(
Symbol::DEV_TMP3,
element_width_symbol,
element_alignment_symbol,
);
self.free_symbol(&element_width_symbol);
self.free_symbol(&element_alignment_symbol);
self.build_ptr_write(sym, Symbol::DEV_TMP3, value, element_layout);
self.free_symbol(&Symbol::DEV_TMP3); self.free_symbol(&Symbol::DEV_TMP3);
} }
@ -2662,6 +2714,28 @@ impl<
FloatWidth::F64 => ASM::sqrt_freg64_freg64(buf, dst_reg, src_reg), FloatWidth::F64 => ASM::sqrt_freg64_freg64(buf, dst_reg, src_reg),
} }
} }
fn build_num_int_cast(
&mut self,
dst: &Symbol,
src: &Symbol,
source: IntWidth,
target: IntWidth,
) {
let buf = &mut self.buf;
let dst_reg = self.storage_manager.claim_general_reg(buf, dst);
let src_reg = self.storage_manager.load_to_general_reg(buf, src);
if source.stack_size() == target.stack_size() {
match source.stack_size() {
8 => ASM::mov_reg64_reg64(buf, dst_reg, src_reg),
_ => todo!("int cast from {source:?} to {target:?}"),
}
} else {
todo!("int cast from {source:?} to {target:?}");
}
}
} }
/// This impl block is for ir related instructions that need backend specific information. /// This impl block is for ir related instructions that need backend specific information.
@ -2675,6 +2749,61 @@ impl<
CC: CallConv<GeneralReg, FloatReg, ASM>, CC: CallConv<GeneralReg, FloatReg, ASM>,
> Backend64Bit<'a, 'r, GeneralReg, FloatReg, ASM, CC> > Backend64Bit<'a, 'r, GeneralReg, FloatReg, ASM, CC>
{ {
fn compare(
&mut self,
op: CompareOperation,
dst: &Symbol,
src1: &Symbol,
src2: &Symbol,
arg_layout: &InLayout<'a>,
) {
match *arg_layout {
single_register_integers!() => {
let buf = &mut self.buf;
let dst = self.storage_manager.claim_general_reg(buf, dst);
let src1 = self.storage_manager.load_to_general_reg(buf, src1);
let src2 = self.storage_manager.load_to_general_reg(buf, src2);
let int_width = arg_layout.try_int_width().unwrap();
let register_width = match int_width.stack_size() {
8 => RegisterWidth::W64,
4 => RegisterWidth::W32,
2 => RegisterWidth::W16,
1 => RegisterWidth::W8,
_ => unreachable!(),
};
if int_width.is_signed() {
ASM::signed_compare_reg64(buf, register_width, op, dst, src1, src2)
} else {
ASM::unsigned_compare_reg64(buf, register_width, op, dst, src1, src2)
}
}
Layout::F32 | Layout::F64 => {
let float_width = match *arg_layout {
Layout::F32 => FloatWidth::F32,
Layout::F64 => FloatWidth::F64,
_ => unreachable!(),
};
let dst_reg = self.storage_manager.claim_general_reg(&mut self.buf, dst);
let src1_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src1);
let src2_reg = self.storage_manager.load_to_float_reg(&mut self.buf, src2);
ASM::cmp_freg_freg_reg64(
&mut self.buf,
dst_reg,
src1_reg,
src2_reg,
float_width,
op,
);
}
x => todo!("NumLt: layout, {:?}", x),
}
}
fn allocate_with_refcount( fn allocate_with_refcount(
&mut self, &mut self,
dst: Symbol, dst: Symbol,
@ -2709,6 +2838,62 @@ impl<
ASM::mov_base32_reg64(buf, base_offset + 16, tmp_reg); ASM::mov_base32_reg64(buf, base_offset + 16, tmp_reg);
} }
fn unbox_to_stack(
buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>,
dst: Symbol,
stack_size: u32,
ptr_reg: GeneralReg,
tmp_reg: GeneralReg,
) {
let mut copied = 0;
let size = stack_size as i32;
let base_offset = storage_manager.claim_stack_area(&dst, stack_size);
if size - copied >= 8 {
for _ in (0..(size - copied)).step_by(8) {
ASM::mov_reg64_mem64_offset32(buf, tmp_reg, ptr_reg, copied);
ASM::mov_base32_reg64(buf, base_offset, tmp_reg);
copied += 8;
}
}
if size - copied > 0 {
panic!("value only partially copied");
}
/*
if size - copied >= 4 {
for _ in (0..(size - copied)).step_by(4) {
ASM::mov_reg32_base32(buf, reg, from_offset + copied);
ASM::mov_base32_reg32(buf, to_offset + copied, reg);
copied += 4;
}
}
if size - copied >= 2 {
for _ in (0..(size - copied)).step_by(2) {
ASM::mov_reg16_base32(buf, reg, from_offset + copied);
ASM::mov_base32_reg16(buf, to_offset + copied, reg);
copied += 2;
}
}
if size - copied >= 1 {
for _ in (0..(size - copied)).step_by(1) {
ASM::mov_reg8_base32(buf, reg, from_offset + copied);
ASM::mov_base32_reg8(buf, to_offset + copied, reg);
copied += 1;
}
}
*/
}
fn ptr_read( fn ptr_read(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, 'r, GeneralReg, FloatReg, ASM, CC>,
@ -2766,6 +2951,15 @@ impl<
ASM::mov_reg64_mem64_offset32(buf, dst_reg, ptr_reg, 0); ASM::mov_reg64_mem64_offset32(buf, dst_reg, ptr_reg, 0);
} }
Layout::Struct { .. } => {
// put it on the stack
let stack_size = layout_interner.stack_size(element_in_layout);
storage_manager.with_tmp_general_reg(buf, |storage_manager, buf, tmp_reg| {
Self::unbox_to_stack(buf, storage_manager, dst, stack_size, ptr_reg, tmp_reg);
});
}
_ => todo!("unboxing of {:?}", layout_interner.dbg(element_in_layout)), _ => todo!("unboxing of {:?}", layout_interner.dbg(element_in_layout)),
} }
} }

View file

@ -654,7 +654,15 @@ impl<
} }
let base_offset = self.claim_stack_area(sym, struct_size); let base_offset = self.claim_stack_area(sym, struct_size);
if let Layout::Struct { field_layouts, .. } = layout_interner.get(*layout) { let mut in_layout = *layout;
let layout = loop {
match layout_interner.get(in_layout) {
Layout::LambdaSet(inner) => in_layout = inner.runtime_representation(),
other => break other,
}
};
if let Layout::Struct { field_layouts, .. } = layout {
let mut current_offset = base_offset; let mut current_offset = base_offset;
for (field, field_layout) in fields.iter().zip(field_layouts.iter()) { for (field, field_layout) in fields.iter().zip(field_layouts.iter()) {
self.copy_symbol_to_stack_offset( self.copy_symbol_to_stack_offset(
@ -670,7 +678,13 @@ impl<
} else { } else {
// This is a single element struct. Just copy the single field to the stack. // This is a single element struct. Just copy the single field to the stack.
debug_assert_eq!(fields.len(), 1); debug_assert_eq!(fields.len(), 1);
self.copy_symbol_to_stack_offset(layout_interner, buf, base_offset, &fields[0], layout); self.copy_symbol_to_stack_offset(
layout_interner,
buf,
base_offset,
&fields[0],
&in_layout,
);
} }
} }

View file

@ -216,8 +216,8 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
} }
#[inline(always)] #[inline(always)]
fn setup_stack<'a>( fn setup_stack(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'_, u8>,
saved_general_regs: &[X86_64GeneralReg], saved_general_regs: &[X86_64GeneralReg],
saved_float_regs: &[X86_64FloatReg], saved_float_regs: &[X86_64FloatReg],
requested_stack_size: i32, requested_stack_size: i32,
@ -233,8 +233,8 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
} }
#[inline(always)] #[inline(always)]
fn cleanup_stack<'a>( fn cleanup_stack(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'_, u8>,
saved_general_regs: &[X86_64GeneralReg], saved_general_regs: &[X86_64GeneralReg],
saved_float_regs: &[X86_64FloatReg], saved_float_regs: &[X86_64FloatReg],
aligned_stack_size: i32, aligned_stack_size: i32,
@ -250,11 +250,11 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
} }
#[inline(always)] #[inline(always)]
fn load_args<'a, 'r>( fn load_args<'a>(
_buf: &mut Vec<'a, u8>, _buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager< storage_manager: &mut StorageManager<
'a, 'a,
'r, '_,
X86_64GeneralReg, X86_64GeneralReg,
X86_64FloatReg, X86_64FloatReg,
X86_64Assembler, X86_64Assembler,
@ -284,11 +284,11 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
} }
#[inline(always)] #[inline(always)]
fn store_args<'a, 'r>( fn store_args<'a>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager< storage_manager: &mut StorageManager<
'a, 'a,
'r, '_,
X86_64GeneralReg, X86_64GeneralReg,
X86_64FloatReg, X86_64FloatReg,
X86_64Assembler, X86_64Assembler,
@ -330,11 +330,11 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
storage_manager.update_fn_call_stack_size(state.tmp_stack_offset as u32); storage_manager.update_fn_call_stack_size(state.tmp_stack_offset as u32);
} }
fn return_complex_symbol<'a, 'r>( fn return_complex_symbol<'a>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager< storage_manager: &mut StorageManager<
'a, 'a,
'r, '_,
X86_64GeneralReg, X86_64GeneralReg,
X86_64FloatReg, X86_64FloatReg,
X86_64Assembler, X86_64Assembler,
@ -388,11 +388,11 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Syste
} }
} }
fn load_returned_complex_symbol<'a, 'r>( fn load_returned_complex_symbol<'a>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager< storage_manager: &mut StorageManager<
'a, 'a,
'r, '_,
X86_64GeneralReg, X86_64GeneralReg,
X86_64FloatReg, X86_64FloatReg,
X86_64Assembler, X86_64Assembler,
@ -447,10 +447,10 @@ impl X64_64SystemVStoreArgs {
const FLOAT_PARAM_REGS: &'static [X86_64FloatReg] = X86_64SystemV::FLOAT_PARAM_REGS; const FLOAT_PARAM_REGS: &'static [X86_64FloatReg] = X86_64SystemV::FLOAT_PARAM_REGS;
const FLOAT_RETURN_REGS: &'static [X86_64FloatReg] = X86_64SystemV::FLOAT_RETURN_REGS; const FLOAT_RETURN_REGS: &'static [X86_64FloatReg] = X86_64SystemV::FLOAT_RETURN_REGS;
fn store_arg<'a, 'r>( fn store_arg<'a>(
&mut self, &mut self,
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut X86_64StorageManager<'a, 'r, X86_64SystemV>, storage_manager: &mut X86_64StorageManager<'a, '_, X86_64SystemV>,
layout_interner: &mut STLayoutInterner<'a>, layout_interner: &mut STLayoutInterner<'a>,
sym: Symbol, sym: Symbol,
in_layout: InLayout<'a>, in_layout: InLayout<'a>,
@ -537,10 +537,10 @@ impl X64_64SystemVStoreArgs {
} }
} }
fn store_arg_general<'a, 'r>( fn store_arg_general<'a>(
&mut self, &mut self,
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut X86_64StorageManager<'a, 'r, X86_64SystemV>, storage_manager: &mut X86_64StorageManager<'a, '_, X86_64SystemV>,
sym: Symbol, sym: Symbol,
) { ) {
if self.general_i < Self::GENERAL_PARAM_REGS.len() { if self.general_i < Self::GENERAL_PARAM_REGS.len() {
@ -562,10 +562,10 @@ impl X64_64SystemVStoreArgs {
} }
} }
fn store_arg_float<'a, 'r>( fn store_arg_float<'a>(
&mut self, &mut self,
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut X86_64StorageManager<'a, 'r, X86_64SystemV>, storage_manager: &mut X86_64StorageManager<'a, '_, X86_64SystemV>,
sym: Symbol, sym: Symbol,
) { ) {
if self.float_i < Self::FLOAT_PARAM_REGS.len() { if self.float_i < Self::FLOAT_PARAM_REGS.len() {
@ -598,9 +598,9 @@ type X86_64StorageManager<'a, 'r, CallConv> =
StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, X86_64Assembler, CallConv>; StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, X86_64Assembler, CallConv>;
impl X64_64SystemVLoadArgs { impl X64_64SystemVLoadArgs {
fn load_arg<'a, 'r>( fn load_arg<'a>(
&mut self, &mut self,
storage_manager: &mut X86_64StorageManager<'a, 'r, X86_64SystemV>, storage_manager: &mut X86_64StorageManager<'a, '_, X86_64SystemV>,
layout_interner: &mut STLayoutInterner<'a>, layout_interner: &mut STLayoutInterner<'a>,
sym: Symbol, sym: Symbol,
in_layout: InLayout<'a>, in_layout: InLayout<'a>,
@ -645,9 +645,9 @@ impl X64_64SystemVLoadArgs {
} }
} }
fn load_arg_general<'a, 'r>( fn load_arg_general(
&mut self, &mut self,
storage_manager: &mut X86_64StorageManager<'a, 'r, X86_64SystemV>, storage_manager: &mut X86_64StorageManager<'_, '_, X86_64SystemV>,
sym: Symbol, sym: Symbol,
) { ) {
if self.general_i < X86_64SystemV::GENERAL_PARAM_REGS.len() { if self.general_i < X86_64SystemV::GENERAL_PARAM_REGS.len() {
@ -660,9 +660,9 @@ impl X64_64SystemVLoadArgs {
} }
} }
fn load_arg_float<'a, 'r>( fn load_arg_float(
&mut self, &mut self,
storage_manager: &mut X86_64StorageManager<'a, 'r, X86_64SystemV>, storage_manager: &mut X86_64StorageManager<'_, '_, X86_64SystemV>,
sym: Symbol, sym: Symbol,
) { ) {
if self.general_i < X86_64SystemV::GENERAL_PARAM_REGS.len() { if self.general_i < X86_64SystemV::GENERAL_PARAM_REGS.len() {
@ -783,8 +783,8 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
} }
#[inline(always)] #[inline(always)]
fn setup_stack<'a>( fn setup_stack(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'_, u8>,
saved_general_regs: &[X86_64GeneralReg], saved_general_regs: &[X86_64GeneralReg],
saved_float_regs: &[X86_64FloatReg], saved_float_regs: &[X86_64FloatReg],
requested_stack_size: i32, requested_stack_size: i32,
@ -800,8 +800,8 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
} }
#[inline(always)] #[inline(always)]
fn cleanup_stack<'a>( fn cleanup_stack(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'_, u8>,
saved_general_regs: &[X86_64GeneralReg], saved_general_regs: &[X86_64GeneralReg],
saved_float_regs: &[X86_64FloatReg], saved_float_regs: &[X86_64FloatReg],
aligned_stack_size: i32, aligned_stack_size: i32,
@ -817,9 +817,9 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
} }
#[inline(always)] #[inline(always)]
fn load_args<'a, 'r>( fn load_args<'a>(
_buf: &mut Vec<'a, u8>, _buf: &mut Vec<'a, u8>,
storage_manager: &mut X86_64StorageManager<'a, 'r, X86_64WindowsFastcall>, storage_manager: &mut X86_64StorageManager<'a, '_, X86_64WindowsFastcall>,
layout_interner: &mut STLayoutInterner<'a>, layout_interner: &mut STLayoutInterner<'a>,
args: &'a [(InLayout<'a>, Symbol)], args: &'a [(InLayout<'a>, Symbol)],
ret_layout: &InLayout<'a>, ret_layout: &InLayout<'a>,
@ -861,11 +861,11 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
} }
#[inline(always)] #[inline(always)]
fn store_args<'a, 'r>( fn store_args<'a>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager< storage_manager: &mut StorageManager<
'a, 'a,
'r, '_,
X86_64GeneralReg, X86_64GeneralReg,
X86_64FloatReg, X86_64FloatReg,
X86_64Assembler, X86_64Assembler,
@ -938,11 +938,11 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
storage_manager.update_fn_call_stack_size(tmp_stack_offset as u32); storage_manager.update_fn_call_stack_size(tmp_stack_offset as u32);
} }
fn return_complex_symbol<'a, 'r>( fn return_complex_symbol<'a>(
_buf: &mut Vec<'a, u8>, _buf: &mut Vec<'a, u8>,
_storage_manager: &mut StorageManager< _storage_manager: &mut StorageManager<
'a, 'a,
'r, '_,
X86_64GeneralReg, X86_64GeneralReg,
X86_64FloatReg, X86_64FloatReg,
X86_64Assembler, X86_64Assembler,
@ -955,11 +955,11 @@ impl CallConv<X86_64GeneralReg, X86_64FloatReg, X86_64Assembler> for X86_64Windo
todo!("Returning complex symbols for X86_64"); todo!("Returning complex symbols for X86_64");
} }
fn load_returned_complex_symbol<'a, 'r>( fn load_returned_complex_symbol<'a>(
_buf: &mut Vec<'a, u8>, _buf: &mut Vec<'a, u8>,
_storage_manager: &mut StorageManager< _storage_manager: &mut StorageManager<
'a, 'a,
'r, '_,
X86_64GeneralReg, X86_64GeneralReg,
X86_64FloatReg, X86_64FloatReg,
X86_64Assembler, X86_64Assembler,
@ -985,8 +985,8 @@ impl X86_64WindowsFastcall {
} }
#[inline(always)] #[inline(always)]
fn x86_64_generic_setup_stack<'a>( fn x86_64_generic_setup_stack(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'_, u8>,
saved_general_regs: &[X86_64GeneralReg], saved_general_regs: &[X86_64GeneralReg],
saved_float_regs: &[X86_64FloatReg], saved_float_regs: &[X86_64FloatReg],
requested_stack_size: i32, requested_stack_size: i32,
@ -1042,8 +1042,8 @@ fn x86_64_generic_setup_stack<'a>(
#[inline(always)] #[inline(always)]
#[allow(clippy::unnecessary_wraps)] #[allow(clippy::unnecessary_wraps)]
fn x86_64_generic_cleanup_stack<'a>( fn x86_64_generic_cleanup_stack(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'_, u8>,
saved_general_regs: &[X86_64GeneralReg], saved_general_regs: &[X86_64GeneralReg],
saved_float_regs: &[X86_64FloatReg], saved_float_regs: &[X86_64FloatReg],
aligned_stack_size: i32, aligned_stack_size: i32,
@ -1172,6 +1172,21 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
}); });
} }
#[inline(always)]
fn function_pointer(
buf: &mut Vec<'_, u8>,
relocs: &mut Vec<'_, Relocation>,
fn_name: String,
dst: X86_64GeneralReg,
) {
lea_reg64(buf, dst);
relocs.push(Relocation::LinkedFunction {
offset: buf.len() as u64 - 4,
name: fn_name,
});
}
#[inline(always)] #[inline(always)]
fn imul_reg64_reg64_reg64( fn imul_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>, buf: &mut Vec<'_, u8>,
@ -1183,9 +1198,9 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
imul_reg64_reg64(buf, dst, src2); imul_reg64_reg64(buf, dst, src2);
} }
fn umul_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn umul_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
dst: X86_64GeneralReg, dst: X86_64GeneralReg,
src1: X86_64GeneralReg, src1: X86_64GeneralReg,
src2: X86_64GeneralReg, src2: X86_64GeneralReg,
@ -1267,9 +1282,9 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
} }
} }
fn idiv_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn idiv_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
dst: X86_64GeneralReg, dst: X86_64GeneralReg,
src1: X86_64GeneralReg, src1: X86_64GeneralReg,
src2: X86_64GeneralReg, src2: X86_64GeneralReg,
@ -1287,9 +1302,9 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
mov_reg64_reg64(buf, dst, X86_64GeneralReg::RAX); mov_reg64_reg64(buf, dst, X86_64GeneralReg::RAX);
} }
fn udiv_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn udiv_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
dst: X86_64GeneralReg, dst: X86_64GeneralReg,
src1: X86_64GeneralReg, src1: X86_64GeneralReg,
src2: X86_64GeneralReg, src2: X86_64GeneralReg,
@ -1607,17 +1622,13 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
src1: X86_64GeneralReg, src1: X86_64GeneralReg,
src2: X86_64GeneralReg, src2: X86_64GeneralReg,
) { ) {
cmp_reg64_reg64(buf, register_width, src1, src2);
match operation { match operation {
CompareOperation::LessThan => { CompareOperation::LessThan => setl_reg64(buf, dst),
cmp_reg64_reg64(buf, register_width, src1, src2); CompareOperation::LessThanOrEqual => setle_reg64(buf, dst),
setl_reg64(buf, dst); CompareOperation::GreaterThan => setg_reg64(buf, dst),
} CompareOperation::GreaterThanOrEqual => setge_reg64(buf, dst),
CompareOperation::LessThanOrEqual => todo!(),
CompareOperation::GreaterThan => {
cmp_reg64_reg64(buf, register_width, src1, src2);
setg_reg64(buf, dst);
}
CompareOperation::GreaterThanOrEqual => todo!(),
} }
} }
@ -1629,18 +1640,13 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
src1: X86_64GeneralReg, src1: X86_64GeneralReg,
src2: X86_64GeneralReg, src2: X86_64GeneralReg,
) { ) {
match operation {
CompareOperation::LessThan => {
cmp_reg64_reg64(buf, register_width, src1, src2); cmp_reg64_reg64(buf, register_width, src1, src2);
setb_reg64(buf, dst);
}
CompareOperation::LessThanOrEqual => todo!(),
CompareOperation::GreaterThan => {
cmp_reg64_reg64(buf, register_width, src1, src2);
seta_reg64(buf, dst);
}
CompareOperation::GreaterThanOrEqual => todo!(), match operation {
CompareOperation::LessThan => setb_reg64(buf, dst),
CompareOperation::LessThanOrEqual => setbe_reg64(buf, dst),
CompareOperation::GreaterThan => seta_reg64(buf, dst),
CompareOperation::GreaterThanOrEqual => setae_reg64(buf, dst),
} }
} }
@ -1691,28 +1697,6 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
cvtsi2sd_freg64_reg64(buf, dst, src); cvtsi2sd_freg64_reg64(buf, dst, src);
} }
#[inline(always)]
fn lte_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>,
dst: X86_64GeneralReg,
src1: X86_64GeneralReg,
src2: X86_64GeneralReg,
) {
cmp_reg64_reg64(buf, RegisterWidth::W64, src1, src2);
setle_reg64(buf, dst);
}
#[inline(always)]
fn gte_reg64_reg64_reg64(
buf: &mut Vec<'_, u8>,
dst: X86_64GeneralReg,
src1: X86_64GeneralReg,
src2: X86_64GeneralReg,
) {
cmp_reg64_reg64(buf, RegisterWidth::W64, src1, src2);
setge_reg64(buf, dst);
}
#[inline(always)] #[inline(always)]
fn ret(buf: &mut Vec<'_, u8>) { fn ret(buf: &mut Vec<'_, u8>) {
ret(buf); ret(buf);
@ -1734,9 +1718,9 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
binop_move_src_to_dst_reg64(buf, xor_reg64_reg64, dst, src1, src2) binop_move_src_to_dst_reg64(buf, xor_reg64_reg64, dst, src1, src2)
} }
fn shl_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn shl_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
dst: X86_64GeneralReg, dst: X86_64GeneralReg,
src1: X86_64GeneralReg, src1: X86_64GeneralReg,
src2: X86_64GeneralReg, src2: X86_64GeneralReg,
@ -1747,9 +1731,9 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
shift_reg64_reg64_reg64(buf, storage_manager, shl_reg64_reg64, dst, src1, src2) shift_reg64_reg64_reg64(buf, storage_manager, shl_reg64_reg64, dst, src1, src2)
} }
fn shr_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn shr_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
dst: X86_64GeneralReg, dst: X86_64GeneralReg,
src1: X86_64GeneralReg, src1: X86_64GeneralReg,
src2: X86_64GeneralReg, src2: X86_64GeneralReg,
@ -1760,9 +1744,9 @@ impl Assembler<X86_64GeneralReg, X86_64FloatReg> for X86_64Assembler {
shift_reg64_reg64_reg64(buf, storage_manager, shr_reg64_reg64, dst, src1, src2) shift_reg64_reg64_reg64(buf, storage_manager, shr_reg64_reg64, dst, src1, src2)
} }
fn sar_reg64_reg64_reg64<'a, 'r, ASM, CC>( fn sar_reg64_reg64_reg64<'a, ASM, CC>(
buf: &mut Vec<'a, u8>, buf: &mut Vec<'a, u8>,
storage_manager: &mut StorageManager<'a, 'r, X86_64GeneralReg, X86_64FloatReg, ASM, CC>, storage_manager: &mut StorageManager<'a, '_, X86_64GeneralReg, X86_64FloatReg, ASM, CC>,
dst: X86_64GeneralReg, dst: X86_64GeneralReg,
src1: X86_64GeneralReg, src1: X86_64GeneralReg,
src2: X86_64GeneralReg, src2: X86_64GeneralReg,
@ -2398,6 +2382,25 @@ fn mov_reg64_imm64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg, imm: i64) {
} }
} }
/// `LEA r64, m` -> Store effective address for m in register r64.
#[inline(always)]
fn lea_reg64(buf: &mut Vec<'_, u8>, dst: X86_64GeneralReg) {
let rex = add_opcode_extension(dst, REX_W);
let rex = add_reg_extension(dst, rex);
let dst_mod = dst as u8 % 8;
#[allow(clippy::unusual_byte_groupings)]
buf.extend([
rex,
0x8d,
0b00_000_101 | (dst_mod << 3),
0x00,
0x00,
0x00,
0x00,
])
}
/// `MOV r/m64,r64` -> Move r64 to r/m64. /// `MOV r/m64,r64` -> Move r64 to r/m64.
/// This will not generate anything if dst and src are the same. /// This will not generate anything if dst and src are the same.
#[inline(always)] #[inline(always)]
@ -2959,7 +2962,13 @@ fn setae_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
set_reg64_help(0x93, buf, reg); set_reg64_help(0x93, buf, reg);
} }
/// `SETLE r/m64` -> Set byte if less or equal (ZF=1 or SF≠ OF). /// `SETBE r/m64` -> Set byte if below or equal (CF=1 or ZF=1).
#[inline(always)]
fn setbe_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
set_reg64_help(0x96, buf, reg);
}
/// `SETLE r/m64` -> Set byte if less or equal (ZF=1 or SF ≠ OF).
#[inline(always)] #[inline(always)]
fn setle_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) { fn setle_reg64(buf: &mut Vec<'_, u8>, reg: X86_64GeneralReg) {
set_reg64_help(0x9e, buf, reg); set_reg64_help(0x9e, buf, reg);
@ -3413,6 +3422,15 @@ mod tests {
); );
} }
#[test]
fn test_lea_reg64() {
disassembler_test!(
lea_reg64,
|reg| format!("lea {}, [rip]", reg),
ALL_GENERAL_REGS
);
}
#[test] #[test]
fn test_mov_reg64_reg64() { fn test_mov_reg64_reg64() {
disassembler_test!( disassembler_test!(
@ -3764,8 +3782,8 @@ mod tests {
cmp_reg64_reg64, cmp_reg64_reg64,
|_, dst: X86_64GeneralReg, src: X86_64GeneralReg| format!( |_, dst: X86_64GeneralReg, src: X86_64GeneralReg| format!(
"cmp {}, {}", "cmp {}, {}",
dbg!(dst.low_16bits_string()), dst.low_16bits_string(),
dbg!(src.low_16bits_string()) src.low_16bits_string()
), ),
[RegisterWidth::W16], [RegisterWidth::W16],
ALL_GENERAL_REGS, ALL_GENERAL_REGS,
@ -3776,8 +3794,8 @@ mod tests {
cmp_reg64_reg64, cmp_reg64_reg64,
|_, dst: X86_64GeneralReg, src: X86_64GeneralReg| format!( |_, dst: X86_64GeneralReg, src: X86_64GeneralReg| format!(
"cmp {}, {}", "cmp {}, {}",
dbg!(dst.low_32bits_string()), dst.low_32bits_string(),
dbg!(src.low_32bits_string()) src.low_32bits_string()
), ),
[RegisterWidth::W32], [RegisterWidth::W32],
ALL_GENERAL_REGS, ALL_GENERAL_REGS,

View file

@ -12,10 +12,10 @@ use roc_error_macros::internal_error;
use roc_module::ident::ModuleName; use roc_module::ident::ModuleName;
use roc_module::low_level::{LowLevel, LowLevelWrapperType}; use roc_module::low_level::{LowLevel, LowLevelWrapperType};
use roc_module::symbol::{Interns, ModuleId, Symbol}; use roc_module::symbol::{Interns, ModuleId, Symbol};
use roc_mono::code_gen_help::CodeGenHelp; use roc_mono::code_gen_help::{CallerProc, CodeGenHelp};
use roc_mono::ir::{ use roc_mono::ir::{
BranchInfo, CallType, Expr, JoinPointId, ListLiteralElement, Literal, Param, Proc, ProcLayout, BranchInfo, CallType, Expr, HigherOrderLowLevel, JoinPointId, ListLiteralElement, Literal,
SelfRecursive, Stmt, Param, Proc, ProcLayout, SelfRecursive, Stmt,
}; };
use roc_mono::layout::{ use roc_mono::layout::{
Builtin, InLayout, Layout, LayoutIds, LayoutInterner, STLayoutInterner, TagIdIntType, Builtin, InLayout, Layout, LayoutIds, LayoutInterner, STLayoutInterner, TagIdIntType,
@ -65,8 +65,21 @@ pub enum Relocation {
trait Backend<'a> { trait Backend<'a> {
fn env(&self) -> &Env<'a>; fn env(&self) -> &Env<'a>;
fn interns(&self) -> &Interns; fn interns(&self) -> &Interns;
fn interns_mut(&mut self) -> &mut Interns;
fn interner(&self) -> &STLayoutInterner<'a>; fn interner(&self) -> &STLayoutInterner<'a>;
fn debug_symbol(&mut self, name: &str) -> Symbol {
let module_id = self.env().module_id;
let ident_ids = self
.interns_mut()
.all_ident_ids
.get_mut(&module_id)
.unwrap();
let ident_id = ident_ids.add_str(name);
Symbol::new(self.env().module_id, ident_id)
}
// This method is suboptimal, but it seems to be the only way to make rust understand // This method is suboptimal, but it seems to be the only way to make rust understand
// that all of these values can be mutable at the same time. By returning them together, // that all of these values can be mutable at the same time. By returning them together,
// rust understands that they are part of a single use of mutable self. // rust understands that they are part of a single use of mutable self.
@ -77,6 +90,7 @@ trait Backend<'a> {
&mut STLayoutInterner<'a>, &mut STLayoutInterner<'a>,
&mut Interns, &mut Interns,
&mut CodeGenHelp<'a>, &mut CodeGenHelp<'a>,
&mut Vec<'a, CallerProc<'a>>,
); );
fn function_symbol_to_string<'b, I>( fn function_symbol_to_string<'b, I>(
@ -201,7 +215,7 @@ trait Backend<'a> {
// If this layout requires a new RC proc, we get enough info to create a linker symbol // If this layout requires a new RC proc, we get enough info to create a linker symbol
// for it. Here we don't create linker symbols at this time, but in Wasm backend, we do. // for it. Here we don't create linker symbols at this time, but in Wasm backend, we do.
let (rc_stmt, new_specializations) = { let (rc_stmt, new_specializations) = {
let (module_id, layout_interner, interns, rc_proc_gen) = let (module_id, layout_interner, interns, rc_proc_gen, _) =
self.module_interns_helpers_mut(); self.module_interns_helpers_mut();
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap(); let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
@ -329,7 +343,7 @@ trait Backend<'a> {
arg_layouts, arg_layouts,
ret_layout, ret_layout,
); );
} else if sym.is_builtin() { } else if func_sym.name().is_builtin() {
// These builtins can be built through `build_fn_call` as well, but the // These builtins can be built through `build_fn_call` as well, but the
// implementation in `build_builtin` inlines some of the symbols. // implementation in `build_builtin` inlines some of the symbols.
return self.build_builtin( return self.build_builtin(
@ -373,6 +387,9 @@ trait Backend<'a> {
layout, layout,
) )
} }
CallType::HigherOrder(higher_order) => {
self.build_higher_order_lowlevel(sym, higher_order, *layout)
}
x => todo!("the call type, {:?}", x), x => todo!("the call type, {:?}", x),
} }
} }
@ -486,6 +503,22 @@ trait Backend<'a> {
); );
self.build_num_add(sym, &args[0], &args[1], ret_layout) self.build_num_add(sym, &args[0], &args[1], ret_layout)
} }
LowLevel::NumAddWrap => {
debug_assert_eq!(
2,
args.len(),
"NumAdd: expected to have exactly two argument"
);
debug_assert_eq!(
arg_layouts[0], arg_layouts[1],
"NumAdd: expected all arguments of to have the same layout"
);
debug_assert_eq!(
arg_layouts[0], *ret_layout,
"NumAdd: expected to have the same argument and return layout"
);
self.build_num_add(sym, &args[0], &args[1], ret_layout)
}
LowLevel::NumAddChecked => { LowLevel::NumAddChecked => {
self.build_num_add_checked(sym, &args[0], &args[1], &arg_layouts[0], ret_layout) self.build_num_add_checked(sym, &args[0], &args[1], &arg_layouts[0], ret_layout)
} }
@ -1070,6 +1103,14 @@ trait Backend<'a> {
); );
self.build_ptr_cast(sym, &args[0]) self.build_ptr_cast(sym, &args[0])
} }
LowLevel::PtrWrite => {
let element_layout = match self.interner().get(*ret_layout) {
Layout::Boxed(boxed) => boxed,
_ => unreachable!(),
};
self.build_ptr_write(*sym, args[0], args[1], element_layout);
}
LowLevel::RefCountDec => self.build_fn_call( LowLevel::RefCountDec => self.build_fn_call(
sym, sym,
bitcode::UTILS_DECREF.to_string(), bitcode::UTILS_DECREF.to_string(),
@ -1084,6 +1125,34 @@ trait Backend<'a> {
arg_layouts, arg_layouts,
ret_layout, ret_layout,
), ),
LowLevel::NumToStr => {
let arg_layout = arg_layouts[0];
let intrinsic = match self.interner().get(arg_layout) {
Layout::Builtin(Builtin::Int(width)) => &bitcode::STR_FROM_INT[width],
Layout::Builtin(Builtin::Float(width)) => &bitcode::STR_FROM_FLOAT[width],
Layout::Builtin(Builtin::Decimal) => bitcode::DEC_TO_STR,
x => internal_error!("NumToStr is not defined for {:?}", x),
};
self.build_fn_call(sym, intrinsic.to_string(), args, arg_layouts, ret_layout)
}
LowLevel::StrIsEmpty => {
let intrinsic = bitcode::STR_IS_EMPTY.to_string();
self.build_fn_call(sym, intrinsic, args, arg_layouts, ret_layout);
}
LowLevel::NumIntCast => {
let source_width = match self.interner().get(arg_layouts[0]) {
Layout::Builtin(Builtin::Int(width)) => width,
_ => unreachable!(),
};
let target_width = match self.interner().get(*ret_layout) {
Layout::Builtin(Builtin::Int(width)) => width,
_ => unreachable!(),
};
self.build_num_int_cast(sym, &args[0], source_width, target_width)
}
x => todo!("low level, {:?}", x), x => todo!("low level, {:?}", x),
} }
} }
@ -1133,16 +1202,24 @@ trait Backend<'a> {
self.build_fn_call(sym, fn_name, args, arg_layouts, ret_layout) self.build_fn_call(sym, fn_name, args, arg_layouts, ret_layout)
} }
Symbol::BOOL_TRUE => { Symbol::BOOL_TRUE => {
let bool_layout = Layout::BOOL; const LITERAL: &Literal<'static> = &Literal::Bool(true);
self.load_literal(&Symbol::DEV_TMP, &bool_layout, &Literal::Bool(true)); const BOOL_LAYOUT: &InLayout<'static> = &Layout::BOOL;
self.return_symbol(&Symbol::DEV_TMP, &bool_layout);
self.free_symbol(&Symbol::DEV_TMP) if self.env().lazy_literals {
self.literal_map().insert(*sym, (LITERAL, BOOL_LAYOUT));
} else {
self.load_literal(sym, BOOL_LAYOUT, LITERAL);
}
} }
Symbol::BOOL_FALSE => { Symbol::BOOL_FALSE => {
let bool_layout = Layout::BOOL; const LITERAL: &Literal<'static> = &Literal::Bool(false);
self.load_literal(&Symbol::DEV_TMP, &bool_layout, &Literal::Bool(false)); const BOOL_LAYOUT: &InLayout<'static> = &Layout::BOOL;
self.return_symbol(&Symbol::DEV_TMP, &bool_layout);
self.free_symbol(&Symbol::DEV_TMP) if self.env().lazy_literals {
self.literal_map().insert(*sym, (LITERAL, BOOL_LAYOUT));
} else {
self.load_literal(sym, BOOL_LAYOUT, LITERAL);
}
} }
Symbol::STR_IS_VALID_SCALAR => { Symbol::STR_IS_VALID_SCALAR => {
// just call the function // just call the function
@ -1184,9 +1261,20 @@ trait Backend<'a> {
ret_layout: &InLayout<'a>, ret_layout: &InLayout<'a>,
); );
fn build_fn_pointer(&mut self, dst: &Symbol, fn_name: String);
/// Move a returned value into `dst` /// Move a returned value into `dst`
fn move_return_value(&mut self, dst: &Symbol, ret_layout: &InLayout<'a>); fn move_return_value(&mut self, dst: &Symbol, ret_layout: &InLayout<'a>);
/// build_num_abs stores the absolute value of src into dst.
fn build_num_int_cast(
&mut self,
dst: &Symbol,
src: &Symbol,
source: IntWidth,
target: IntWidth,
);
/// build_num_abs stores the absolute value of src into dst. /// build_num_abs stores the absolute value of src into dst.
fn build_num_abs(&mut self, dst: &Symbol, src: &Symbol, layout: &InLayout<'a>); fn build_num_abs(&mut self, dst: &Symbol, src: &Symbol, layout: &InLayout<'a>);
@ -1348,6 +1436,14 @@ trait Backend<'a> {
/// build_list_len returns the length of a list. /// build_list_len returns the length of a list.
fn build_list_len(&mut self, dst: &Symbol, list: &Symbol); fn build_list_len(&mut self, dst: &Symbol, list: &Symbol);
/// generate a call to a higher-order lowlevel
fn build_higher_order_lowlevel(
&mut self,
dst: &Symbol,
holl: &HigherOrderLowLevel<'a>,
ret_layout: InLayout<'a>,
);
/// build_list_with_capacity creates and returns a list with the given capacity. /// build_list_with_capacity creates and returns a list with the given capacity.
fn build_list_with_capacity( fn build_list_with_capacity(
&mut self, &mut self,
@ -1416,6 +1512,14 @@ trait Backend<'a> {
/// build_refcount_getptr loads the pointer to the reference count of src into dst. /// build_refcount_getptr loads the pointer to the reference count of src into dst.
fn build_ptr_cast(&mut self, dst: &Symbol, src: &Symbol); fn build_ptr_cast(&mut self, dst: &Symbol, src: &Symbol);
fn build_ptr_write(
&mut self,
sym: Symbol,
ptr: Symbol,
value: Symbol,
element_layout: InLayout<'a>,
);
/// literal_map gets the map from symbol to literal and layout, used for lazy loading and literal folding. /// literal_map gets the map from symbol to literal and layout, used for lazy loading and literal folding.
fn literal_map(&mut self) -> &mut MutMap<Symbol, (*const Literal<'a>, *const InLayout<'a>)>; fn literal_map(&mut self) -> &mut MutMap<Symbol, (*const Literal<'a>, *const InLayout<'a>)>;

View file

@ -246,10 +246,16 @@ fn build_object<'a, B: Backend<'a>>(
// Generate IR for specialized helper procs (refcounting & equality) // Generate IR for specialized helper procs (refcounting & equality)
let helper_procs = { let helper_procs = {
let (module_id, _interner, interns, helper_proc_gen) = backend.module_interns_helpers_mut(); let (module_id, _interner, interns, helper_proc_gen, caller_procs) =
backend.module_interns_helpers_mut();
let mut owned_caller_procs = bumpalo::collections::Vec::new_in(arena);
std::mem::swap(caller_procs, &mut owned_caller_procs);
let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap(); let ident_ids = interns.all_ident_ids.get_mut(&module_id).unwrap();
let helper_procs = helper_proc_gen.take_procs(); let mut helper_procs = helper_proc_gen.take_procs();
helper_procs.extend(owned_caller_procs.into_iter().map(|cp| cp.proc));
module_id.register_debug_idents(ident_ids); module_id.register_debug_idents(ident_ids);
helper_procs helper_procs

View file

@ -1247,7 +1247,7 @@ pub(crate) fn run_low_level<'a, 'ctx, 'env>(
unreachable!("The {:?} operation is turned into mono Expr", op) unreachable!("The {:?} operation is turned into mono Expr", op)
} }
PtrCast | RefCountInc | RefCountDec => { PtrCast | PtrWrite | RefCountInc | RefCountDec => {
unreachable!("Not used in LLVM backend: {:?}", op); unreachable!("Not used in LLVM backend: {:?}", op);
} }

View file

@ -885,7 +885,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
self.code_builder.f32_eq(); self.code_builder.f32_eq();
} }
ValueType::F64 => { ValueType::F64 => {
self.code_builder.f64_const(f64::from_bits(*value as u64)); self.code_builder.f64_const(f64::from_bits(*value));
self.code_builder.f64_eq(); self.code_builder.f64_eq();
} }
} }
@ -1114,7 +1114,7 @@ impl<'a, 'r> WasmBackend<'a, 'r> {
match storage { match storage {
StoredValue::VirtualMachineStack { value_type, .. } => { StoredValue::VirtualMachineStack { value_type, .. } => {
match (lit, value_type) { match (lit, value_type) {
(Literal::Float(x), ValueType::F64) => self.code_builder.f64_const(*x as f64), (Literal::Float(x), ValueType::F64) => self.code_builder.f64_const(*x),
(Literal::Float(x), ValueType::F32) => self.code_builder.f32_const(*x as f32), (Literal::Float(x), ValueType::F32) => self.code_builder.f32_const(*x as f32),
(Literal::Int(x), ValueType::I64) => { (Literal::Int(x), ValueType::I64) => {
self.code_builder.i64_const(i128::from_ne_bytes(*x) as i64) self.code_builder.i64_const(i128::from_ne_bytes(*x) as i64)

View file

@ -506,7 +506,7 @@ impl<'a> CodeBuilder<'a> {
stack_size stack_size
); );
let new_len = stack_size - pops as usize; let new_len = stack_size - pops;
current_stack.truncate(new_len); current_stack.truncate(new_len);
if push { if push {
current_stack.push(Symbol::WASM_TMP); current_stack.push(Symbol::WASM_TMP);

View file

@ -1956,6 +1956,8 @@ impl<'a> LowLevelCall<'a> {
backend.storage.load_symbols(code_builder, self.arguments); backend.storage.load_symbols(code_builder, self.arguments);
} }
PtrWrite => todo!("{:?}", self.lowlevel),
Hash => todo!("{:?}", self.lowlevel), Hash => todo!("{:?}", self.lowlevel),
Eq | NotEq => self.eq_or_neq(backend), Eq | NotEq => self.eq_or_neq(backend),

View file

@ -2347,8 +2347,8 @@ macro_rules! debug_check_ir {
} }
/// Report modules that are imported, but from which nothing is used /// Report modules that are imported, but from which nothing is used
fn report_unused_imported_modules<'a>( fn report_unused_imported_modules(
state: &mut State<'a>, state: &mut State<'_>,
module_id: ModuleId, module_id: ModuleId,
constrained_module: &ConstrainedModule, constrained_module: &ConstrainedModule,
) { ) {

View file

@ -115,6 +115,7 @@ pub enum LowLevel {
Not, Not,
Hash, Hash,
PtrCast, PtrCast,
PtrWrite,
RefCountInc, RefCountInc,
RefCountDec, RefCountDec,
RefCountIsUnique, RefCountIsUnique,
@ -220,6 +221,7 @@ macro_rules! map_symbol_to_lowlevel {
// these are used internally and not tied to a symbol // these are used internally and not tied to a symbol
LowLevel::Hash => unimplemented!(), LowLevel::Hash => unimplemented!(),
LowLevel::PtrCast => unimplemented!(), LowLevel::PtrCast => unimplemented!(),
LowLevel::PtrWrite => unimplemented!(),
LowLevel::RefCountInc => unimplemented!(), LowLevel::RefCountInc => unimplemented!(),
LowLevel::RefCountDec => unimplemented!(), LowLevel::RefCountDec => unimplemented!(),
LowLevel::RefCountIsUnique => unimplemented!(), LowLevel::RefCountIsUnique => unimplemented!(),

View file

@ -1253,6 +1253,7 @@ define_builtins! {
152 NUM_COUNT_LEADING_ZERO_BITS: "countLeadingZeroBits" 152 NUM_COUNT_LEADING_ZERO_BITS: "countLeadingZeroBits"
153 NUM_COUNT_TRAILING_ZERO_BITS: "countTrailingZeroBits" 153 NUM_COUNT_TRAILING_ZERO_BITS: "countTrailingZeroBits"
154 NUM_COUNT_ONE_BITS: "countOneBits" 154 NUM_COUNT_ONE_BITS: "countOneBits"
155 NUM_ABS_DIFF: "absDiff"
} }
4 BOOL: "Bool" => { 4 BOOL: "Bool" => {
0 BOOL_BOOL: "Bool" exposed_type=true // the Bool.Bool type alias 0 BOOL_BOOL: "Bool" exposed_type=true // the Bool.Bool type alias

View file

@ -1031,7 +1031,7 @@ pub fn lowlevel_borrow_signature(arena: &Bump, op: LowLevel) -> &[Ownership] {
unreachable!("These lowlevel operations are turned into mono Expr's") unreachable!("These lowlevel operations are turned into mono Expr's")
} }
PtrCast | RefCountInc | RefCountDec | RefCountIsUnique => { PtrCast | PtrWrite | RefCountInc | RefCountDec | RefCountIsUnique => {
unreachable!("Only inserted *after* borrow checking: {:?}", op); unreachable!("Only inserted *after* borrow checking: {:?}", op);
} }
} }

View file

@ -6,8 +6,8 @@ use roc_module::symbol::{IdentIds, ModuleId, Symbol};
use roc_target::TargetInfo; use roc_target::TargetInfo;
use crate::ir::{ use crate::ir::{
Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, Proc, ProcLayout, Call, CallSpecId, CallType, Expr, HostExposedLayouts, JoinPointId, ModifyRc, PassedFunction,
SelfRecursive, Stmt, UpdateModeId, Proc, ProcLayout, SelfRecursive, Stmt, UpdateModeId,
}; };
use crate::layout::{ use crate::layout::{
Builtin, InLayout, LambdaName, Layout, LayoutInterner, Niche, STLayoutInterner, UnionLayout, Builtin, InLayout, LambdaName, Layout, LayoutInterner, Niche, STLayoutInterner, UnionLayout,
@ -21,6 +21,7 @@ const LAYOUT_UNIT: InLayout = Layout::UNIT;
const ARG_1: Symbol = Symbol::ARG_1; const ARG_1: Symbol = Symbol::ARG_1;
const ARG_2: Symbol = Symbol::ARG_2; const ARG_2: Symbol = Symbol::ARG_2;
const ARG_3: Symbol = Symbol::ARG_3;
/// "Infinite" reference count, for static values /// "Infinite" reference count, for static values
/// Ref counts are encoded as negative numbers where isize::MIN represents 1 /// Ref counts are encoded as negative numbers where isize::MIN represents 1
@ -584,6 +585,175 @@ impl<'a> CodeGenHelp<'a> {
} }
} }
pub struct CallerProc<'a> {
pub proc_symbol: Symbol,
pub proc_layout: ProcLayout<'a>,
pub proc: Proc<'a>,
}
impl<'a> CallerProc<'a> {
fn create_symbol(home: ModuleId, ident_ids: &mut IdentIds, debug_name: &str) -> Symbol {
let ident_id = ident_ids.add_str(debug_name);
Symbol::new(home, ident_id)
}
fn create_caller_proc_symbol(
home: ModuleId,
ident_ids: &mut IdentIds,
operation: &str,
wrapped_function: Symbol,
) -> Symbol {
let debug_name = format!("#help_{}_{}_{:?}", "caller", operation, wrapped_function,);
Self::create_symbol(home, ident_ids, &debug_name)
}
pub fn new(
arena: &'a Bump,
home: ModuleId,
ident_ids: &mut IdentIds,
layout_interner: &mut STLayoutInterner<'a>,
passed_function: &PassedFunction<'a>,
capture_layout: Option<InLayout<'a>>,
) -> Self {
let mut ctx = Context {
new_linker_data: Vec::new_in(arena),
recursive_union: None,
op: HelperOp::Eq,
};
let box_capture_layout = if let Some(capture_layout) = capture_layout {
layout_interner.insert(Layout::Boxed(capture_layout))
} else {
layout_interner.insert(Layout::Boxed(Layout::UNIT))
};
let box_argument_layout =
layout_interner.insert(Layout::Boxed(passed_function.argument_layouts[0]));
let box_return_layout =
layout_interner.insert(Layout::Boxed(passed_function.return_layout));
let proc_layout = ProcLayout {
arguments: arena.alloc([box_capture_layout, box_argument_layout, box_return_layout]),
result: Layout::UNIT,
niche: Niche::NONE,
};
let proc_symbol =
Self::create_caller_proc_symbol(home, ident_ids, "map", passed_function.name.name());
ctx.new_linker_data.push((proc_symbol, proc_layout));
let unbox_capture = Expr::ExprUnbox {
symbol: Symbol::ARG_1,
};
let unbox_argument = Expr::ExprUnbox {
symbol: Symbol::ARG_2,
};
let unboxed_capture = Self::create_symbol(home, ident_ids, "unboxed_capture");
let unboxed_argument = Self::create_symbol(home, ident_ids, "unboxed_argument");
let call_result = Self::create_symbol(home, ident_ids, "call_result");
let unit_symbol = Self::create_symbol(home, ident_ids, "unit_symbol");
let ignored = Self::create_symbol(home, ident_ids, "ignored");
let call = Expr::Call(Call {
call_type: CallType::ByName {
name: passed_function.name,
ret_layout: passed_function.return_layout,
arg_layouts: passed_function.argument_layouts,
specialization_id: passed_function.specialization_id,
},
arguments: if capture_layout.is_some() {
arena.alloc([unboxed_argument, unboxed_capture])
} else {
arena.alloc([unboxed_argument])
},
});
let ptr_write = Expr::Call(Call {
call_type: CallType::LowLevel {
op: LowLevel::PtrWrite,
update_mode: UpdateModeId::BACKEND_DUMMY,
},
arguments: arena.alloc([Symbol::ARG_3, call_result]),
});
let mut body = Stmt::Let(
unboxed_argument,
unbox_argument,
passed_function.argument_layouts[0],
arena.alloc(Stmt::Let(
call_result,
call,
passed_function.return_layout,
arena.alloc(Stmt::Let(
ignored,
ptr_write,
box_return_layout,
arena.alloc(Stmt::Let(
unit_symbol,
Expr::Struct(&[]),
Layout::UNIT,
arena.alloc(Stmt::Ret(unit_symbol)),
)),
)),
)),
);
if let Some(capture_layout) = capture_layout {
body = Stmt::Let(
unboxed_capture,
unbox_capture,
capture_layout,
arena.alloc(body),
);
}
let args: &'a [(InLayout<'a>, Symbol)] = {
arena.alloc([
(box_capture_layout, ARG_1),
(box_argument_layout, ARG_2),
(box_return_layout, ARG_3),
])
};
let proc = Proc {
name: LambdaName::no_niche(proc_symbol),
args,
body,
closure_data_layout: None,
ret_layout: Layout::UNIT,
is_self_recursive: SelfRecursive::NotSelfRecursive,
host_exposed_layouts: HostExposedLayouts::NotHostExposed,
};
if false {
let allocator = ven_pretty::BoxAllocator;
let doc = proc
.to_doc::<_, (), _>(
&allocator,
layout_interner,
true,
crate::ir::Parens::NotNeeded,
)
.1
.pretty(80)
.to_string();
println!("{}", doc);
}
Self {
proc_symbol,
proc_layout,
proc,
}
}
}
fn let_lowlevel<'a>( fn let_lowlevel<'a>(
arena: &'a Bump, arena: &'a Bump,
result_layout: InLayout<'a>, result_layout: InLayout<'a>,

View file

@ -25,9 +25,9 @@ use crate::{
/** /**
Insert the reference count operations for procedures. Insert the reference count operations for procedures.
*/ */
pub fn insert_inc_dec_operations<'a, 'i>( pub fn insert_inc_dec_operations<'a>(
arena: &'a Bump, arena: &'a Bump,
layout_interner: &'i STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
procedures: &mut HashMap<(Symbol, ProcLayout), Proc<'a>, BuildHasherDefault<WyHash>>, procedures: &mut HashMap<(Symbol, ProcLayout), Proc<'a>, BuildHasherDefault<WyHash>>,
) { ) {
// Create a SymbolRcTypesEnv for the procedures as they get referenced but should be marked as non reference counted. // Create a SymbolRcTypesEnv for the procedures as they get referenced but should be marked as non reference counted.
@ -401,9 +401,9 @@ impl<'v> RefcountEnvironment<'v> {
/** /**
Insert the reference counting operations into a statement. Insert the reference counting operations into a statement.
*/ */
fn insert_inc_dec_operations_proc<'a, 'i>( fn insert_inc_dec_operations_proc<'a>(
arena: &'a Bump, arena: &'a Bump,
mut symbol_rc_types_env: SymbolRcTypesEnv<'a, 'i>, mut symbol_rc_types_env: SymbolRcTypesEnv<'a, '_>,
proc: &mut Proc<'a>, proc: &mut Proc<'a>,
) { ) {
// Clone the symbol_rc_types_env and insert the symbols in the current procedure. // Clone the symbol_rc_types_env and insert the symbols in the current procedure.

View file

@ -282,8 +282,9 @@ impl AbilityAliases {
} }
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum CapturedSymbols<'a> { pub enum CapturedSymbols<'a> {
#[default]
None, None,
Captured(&'a [(Symbol, Variable)]), Captured(&'a [(Symbol, Variable)]),
} }
@ -297,12 +298,6 @@ impl<'a> CapturedSymbols<'a> {
} }
} }
impl<'a> Default for CapturedSymbols<'a> {
fn default() -> Self {
CapturedSymbols::None
}
}
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub struct Proc<'a> { pub struct Proc<'a> {
pub name: LambdaName<'a>, pub name: LambdaName<'a>,
@ -2725,8 +2720,8 @@ fn patterns_to_when<'a>(
/// { x } -> body /// { x } -> body
/// ///
/// conversion of one-pattern when expressions will do the most optimal thing /// conversion of one-pattern when expressions will do the most optimal thing
fn pattern_to_when<'a>( fn pattern_to_when(
env: &mut Env<'a, '_>, env: &mut Env<'_, '_>,
pattern_var: Variable, pattern_var: Variable,
pattern: Loc<roc_can::pattern::Pattern>, pattern: Loc<roc_can::pattern::Pattern>,
body_var: Variable, body_var: Variable,
@ -5743,8 +5738,8 @@ fn compile_struct_like<'a, L, UnusedLayout>(
} }
#[inline(always)] #[inline(always)]
fn late_resolve_ability_specialization<'a>( fn late_resolve_ability_specialization(
env: &mut Env<'a, '_>, env: &mut Env<'_, '_>,
member: Symbol, member: Symbol,
specialization_id: Option<SpecializationId>, specialization_id: Option<SpecializationId>,
specialization_var: Variable, specialization_var: Variable,

View file

@ -1193,7 +1193,7 @@ fn extract<'a>(
/// FIND IRRELEVANT BRANCHES /// FIND IRRELEVANT BRANCHES
fn is_irrelevant_to<'a>(selected_path: &[PathInstruction], branch: &Branch<'a>) -> bool { fn is_irrelevant_to(selected_path: &[PathInstruction], branch: &Branch<'_>) -> bool {
match branch match branch
.patterns .patterns
.iter() .iter()
@ -1720,7 +1720,7 @@ fn test_to_comparison<'a>(
Test::IsFloat(test_int, precision) => { Test::IsFloat(test_int, precision) => {
// TODO maybe we can actually use i64 comparison here? // TODO maybe we can actually use i64 comparison here?
let test_float = f64::from_bits(test_int as u64); let test_float = f64::from_bits(test_int);
let lhs = Expr::Literal(Literal::Float(test_float)); let lhs = Expr::Literal(Literal::Float(test_float));
let lhs_symbol = env.unique_symbol(); let lhs_symbol = env.unique_symbol();
stores.push((lhs_symbol, Layout::float_width(precision), lhs)); stores.push((lhs_symbol, Layout::float_width(precision), lhs));
@ -2240,7 +2240,7 @@ fn decide_to_branching<'a>(
let tag = match test { let tag = match test {
Test::IsInt(v, _) => i128::from_ne_bytes(v) as u64, Test::IsInt(v, _) => i128::from_ne_bytes(v) as u64,
Test::IsFloat(v, _) => v as u64, Test::IsFloat(v, _) => v,
Test::IsBit(v) => v as u64, Test::IsBit(v) => v as u64,
Test::IsByte { tag_id, .. } => tag_id as u64, Test::IsByte { tag_id, .. } => tag_id as u64,
Test::IsCtor { tag_id, .. } => tag_id as u64, Test::IsCtor { tag_id, .. } => tag_id as u64,

View file

@ -457,7 +457,7 @@ macro_rules! cached {
} }
pub type TagIdIntType = u16; pub type TagIdIntType = u16;
pub const MAX_ENUM_SIZE: usize = (std::mem::size_of::<TagIdIntType>() * 8) as usize; pub const MAX_ENUM_SIZE: usize = std::mem::size_of::<TagIdIntType>() * 8;
const GENERATE_NULLABLE: bool = true; const GENERATE_NULLABLE: bool = true;
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
@ -898,7 +898,7 @@ impl<'a> UnionLayout<'a> {
} => { } => {
debug_assert_ne!(nullable_id, tag_id != 0); debug_assert_ne!(nullable_id, tag_id != 0);
other_fields[index as usize] other_fields[index]
} }
}; };

View file

@ -23,7 +23,7 @@ macro_rules! cache_interned_layouts {
)* )*
} }
fn fill_reserved_layouts<'a>(interner: &mut STLayoutInterner<'a>) { fn fill_reserved_layouts(interner: &mut STLayoutInterner<'_>) {
assert!(interner.is_empty()); assert!(interner.is_empty());
$( $(
interner.insert($layout); interner.insert($layout);
@ -433,6 +433,22 @@ impl<'a> InLayout<'a> {
pub fn index(&self) -> usize { pub fn index(&self) -> usize {
self.0 self.0
} }
pub fn try_int_width(self) -> Option<IntWidth> {
match self {
Layout::U8 => Some(IntWidth::U8),
Layout::U16 => Some(IntWidth::U16),
Layout::U32 => Some(IntWidth::U32),
Layout::U64 => Some(IntWidth::U64),
Layout::U128 => Some(IntWidth::U128),
Layout::I8 => Some(IntWidth::I8),
Layout::I16 => Some(IntWidth::I16),
Layout::I32 => Some(IntWidth::I32),
Layout::I64 => Some(IntWidth::I64),
Layout::I128 => Some(IntWidth::I128),
_ => None,
}
}
} }
/// A concurrent interner, suitable for usage between threads. /// A concurrent interner, suitable for usage between threads.

View file

@ -1128,8 +1128,8 @@ impl<'a> ReuseEnvironment<'a> {
/** /**
Check if a layout can be reused. by verifying if the layout is a union and if the tag is not nullable. Check if a layout can be reused. by verifying if the layout is a union and if the tag is not nullable.
*/ */
fn can_reuse_layout<'a, 'i>( fn can_reuse_layout<'a>(
layout_interner: &'i STLayoutInterner<'a>, layout_interner: &STLayoutInterner<'a>,
environment: &ReuseEnvironment<'a>, environment: &ReuseEnvironment<'a>,
layout: &InLayout<'a>, layout: &InLayout<'a>,
) -> Reuse { ) -> Reuse {

View file

@ -14,6 +14,7 @@ version.workspace = true
roc_collections = { path = "../collections" } roc_collections = { path = "../collections" }
roc_module = { path = "../module" } roc_module = { path = "../module" }
roc_region = { path = "../region" } roc_region = { path = "../region" }
roc_error_macros = { path = "../../error_macros" }
bumpalo.workspace = true bumpalo.workspace = true
encode_unicode.workspace = true encode_unicode.workspace = true

View file

@ -21,6 +21,7 @@ use crate::type_annotation;
use bumpalo::collections::Vec; use bumpalo::collections::Vec;
use bumpalo::Bump; use bumpalo::Bump;
use roc_collections::soa::Slice; use roc_collections::soa::Slice;
use roc_error_macros::internal_error;
use roc_module::called_via::{BinOp, CalledVia, UnaryOp}; use roc_module::called_via::{BinOp, CalledVia, UnaryOp};
use roc_region::all::{Loc, Position, Region}; use roc_region::all::{Loc, Position, Region};
@ -2479,10 +2480,10 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
// TODO: make this state impossible to represent in Ident::Access, // TODO: make this state impossible to represent in Ident::Access,
// by splitting out parts[0] into a separate field with a type of `&'a str`, // by splitting out parts[0] into a separate field with a type of `&'a str`,
// rather than a `&'a [Accessor<'a>]`. // rather than a `&'a [Accessor<'a>]`.
panic!("Parsed an Ident::Access with a first part of a tuple index"); internal_error!("Parsed an Ident::Access with a first part of a tuple index");
} }
None => { None => {
panic!("Parsed an Ident::Access with no parts"); internal_error!("Parsed an Ident::Access with no parts");
} }
}; };

View file

@ -105,14 +105,14 @@ impl Position {
#[must_use] #[must_use]
pub const fn bump_column(self, count: u32) -> Self { pub const fn bump_column(self, count: u32) -> Self {
Self { Self {
offset: self.offset + count as u32, offset: self.offset + count,
} }
} }
#[must_use] #[must_use]
pub fn bump_invisible(self, count: u32) -> Self { pub fn bump_invisible(self, count: u32) -> Self {
Self { Self {
offset: self.offset + count as u32, offset: self.offset + count,
} }
} }
@ -126,7 +126,7 @@ impl Position {
#[must_use] #[must_use]
pub const fn sub(self, count: u32) -> Self { pub const fn sub(self, count: u32) -> Self {
Self { Self {
offset: self.offset - count as u32, offset: self.offset - count,
} }
} }
@ -376,7 +376,7 @@ impl LineInfo {
let column = offset - self.line_offsets[line]; let column = offset - self.line_offsets[line];
LineColumn { LineColumn {
line: line as u32, line: line as u32,
column: column as u32, column,
} }
} }

View file

@ -2537,14 +2537,14 @@ enum TypeToVar {
} }
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
fn type_to_variable<'a>( fn type_to_variable(
subs: &mut Subs, subs: &mut Subs,
rank: Rank, rank: Rank,
pools: &mut Pools, pools: &mut Pools,
problems: &mut Vec<TypeError>, problems: &mut Vec<TypeError>,
abilities_store: &AbilitiesStore, abilities_store: &AbilitiesStore,
obligation_cache: &mut ObligationCache, obligation_cache: &mut ObligationCache,
arena: &'a bumpalo::Bump, arena: &bumpalo::Bump,
aliases: &mut Aliases, aliases: &mut Aliases,
types: &mut Types, types: &mut Types,
typ: Index<TypeTag>, typ: Index<TypeTag>,

File diff suppressed because it is too large Load diff

View file

@ -1200,7 +1200,7 @@ fn list_count_if_str() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_map_on_empty_list_with_int_layout() { fn list_map_on_empty_list_with_int_layout() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -1218,7 +1218,7 @@ fn list_map_on_empty_list_with_int_layout() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_map_on_non_empty_list() { fn list_map_on_non_empty_list() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -1236,7 +1236,7 @@ fn list_map_on_non_empty_list() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_map_changes_input() { fn list_map_changes_input() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -1254,7 +1254,7 @@ fn list_map_changes_input() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_map_on_big_list() { fn list_map_on_big_list() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -1274,7 +1274,7 @@ fn list_map_on_big_list() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_map_with_type_change() { fn list_map_with_type_change() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -1293,7 +1293,7 @@ fn list_map_with_type_change() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_map_using_defined_function() { fn list_map_using_defined_function() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -1315,7 +1315,7 @@ fn list_map_using_defined_function() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_map_all_inline() { fn list_map_all_inline() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
@ -1328,9 +1328,30 @@ fn list_map_all_inline() {
); );
} }
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_map_closure_int() {
assert_evals_to!(
indoc!(
r#"
int : I64
int = 123
single : List I64
single =
[0]
List.map single (\x -> x + int)
"#
),
RocList::from_slice(&[123]),
RocList<i64>
);
}
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn list_map_closure() { fn list_map_closure_float() {
assert_evals_to!( assert_evals_to!(
indoc!( indoc!(
r#" r#"
@ -2926,7 +2947,7 @@ fn list_any_empty_with_unknown_element_type() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn list_all() { fn list_all() {
assert_evals_to!("List.all [] (\\e -> e > 3)", true, bool); assert_evals_to!("List.all [] (\\e -> e > 3)", true, bool);
assert_evals_to!("List.all [1, 2, 3] (\\e -> e > 3)", false, bool); assert_evals_to!("List.all [1, 2, 3] (\\e -> e > 3)", false, bool);

View file

@ -3113,7 +3113,7 @@ fn when_on_i16() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-wasm", feature = "gen-dev"))]
fn num_to_str() { fn num_to_str() {
use roc_std::RocStr; use roc_std::RocStr;
@ -3998,3 +3998,84 @@ fn num_count_one_bits() {
assert_evals_to!(r#"Num.countOneBits 0u32"#, 0, usize); assert_evals_to!(r#"Num.countOneBits 0u32"#, 0, usize);
assert_evals_to!(r#"Num.countOneBits 0b0010_1111u64"#, 5, usize); assert_evals_to!(r#"Num.countOneBits 0b0010_1111u64"#, 5, usize);
} }
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn num_abs_diff_int() {
assert_evals_to!(r#"Num.absDiff 0u8 0u8"#, 0, u8);
assert_evals_to!(r#"Num.absDiff 1u8 2u8"#, 1, u8);
assert_evals_to!(r#"Num.absDiff 2u8 1u8"#, 1, u8);
assert_evals_to!(r#"Num.absDiff -1 1"#, 2, i64);
assert_evals_to!(r#"Num.absDiff 1 -1"#, 2, i64);
assert_evals_to!(r#"Num.absDiff Num.minI64 -1"#, i64::MAX, i64);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
fn num_abs_diff_large_bits() {
assert_evals_to!(r#"Num.absDiff 0u128 0u128"#, 0, u128);
assert_evals_to!(r#"Num.absDiff 1u128 2u128"#, 1, u128);
assert_evals_to!(r#"Num.absDiff -1i128 1i128"#, 2, i128);
assert_evals_to!(r#"Num.absDiff Num.minI128 -1i128"#, i128::MAX, i128);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn num_abs_diff_float() {
assert_evals_to!(r#"Num.absDiff 0.0 0.0"#, 0.0, f64);
assert_evals_to!(r#"Num.absDiff 1.0 2.0"#, 1.0, f64);
assert_evals_to!(r#"Num.absDiff 2.0 1.0"#, 1.0, f64);
assert_evals_to!(r#"Num.absDiff -1.0 1.0"#, 2.0, f64);
assert_evals_to!(r#"Num.absDiff 1.0 -1.0"#, 2.0, f64);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[should_panic(expected = r#"Roc failed with message: "integer subtraction overflowed!"#)]
fn num_abs_max_overflow() {
assert_evals_to!(r#"Num.absDiff Num.maxI64 -1"#, 0, i64);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
#[should_panic(expected = r#"Roc failed with message: "integer subtraction overflowed!"#)]
fn num_abs_int_min_overflow() {
assert_evals_to!(r#"Num.absDiff Num.minI64 0"#, 0, i64);
}
#[test]
#[cfg(any(feature = "gen-llvm"))]
#[should_panic(expected = r#"Roc failed with message: "integer subtraction overflowed!"#)]
fn num_abs_large_bits_min_overflow() {
assert_evals_to!(r#"Num.absDiff Num.minI128 0"#, 0, i128);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-wasm"))]
fn num_abs_float_overflow() {
assert_evals_to!("Num.absDiff Num.maxF64 Num.minF64", f64::INFINITY, f64);
}
#[test]
#[cfg(any(feature = "gen-llvm", feature = "gen-dev", feature = "gen-wasm"))]
fn bool_in_switch() {
assert_evals_to!(
indoc!(
r#"
app "test" provides [main] to "./platform"
loop : [ Continue {}, Break {} ]
loop = Continue {}
all = \{} ->
when loop is
Continue {} -> Bool.true
Break {} -> Bool.false
main = all {}
"#
),
true,
bool
);
}

View file

@ -497,23 +497,23 @@ fn str_concat_empty() {
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn small_str_is_empty() { fn small_str_is_empty() {
assert_evals_to!(r#"Str.isEmpty "abc""#, false, bool); assert_evals_to!(r#"Str.isEmpty "abc""#, false, bool);
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn big_str_is_empty() { fn big_str_is_empty() {
assert_evals_to!( assert_evals_to!(
r#"Str.isEmpty "this is more than 15 chars long""#, r#"Str.isEmpty "this is more than 23 chars long""#,
false, false,
bool bool
); );
} }
#[test] #[test]
#[cfg(any(feature = "gen-llvm"))] #[cfg(any(feature = "gen-llvm", feature = "gen-dev"))]
fn empty_str_is_empty() { fn empty_str_is_empty() {
assert_evals_to!(r#"Str.isEmpty """#, true, bool); assert_evals_to!(r#"Str.isEmpty """#, true, bool);
} }

View file

@ -907,7 +907,9 @@ fn alignment_in_multi_tag_pattern_match() {
{ bool, int } { bool, int }
Empty -> Empty ->
{ bool: Bool.false, int: 0 } # dev backend codegen bug means we cannot use this inline
false = Bool.false
{ bool: false, int: 0 }
#" #"
), ),
(32i64, true), (32i64, true),
@ -924,7 +926,8 @@ fn alignment_in_multi_tag_pattern_match() {
Three bool color int -> Three bool color int ->
{ bool, color, int } { bool, color, int }
Empty -> Empty ->
{ bool: Bool.false, color: Red, int: 0 } false = Bool.false
{ bool: false, color: Red, int: 0 }
#" #"
), ),
(32i64, true, 2u8), (32i64, true, 2u8),

View file

@ -86,16 +86,16 @@ procedure List.92 (List.430, List.431, List.432):
ret List.515; ret List.515;
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.277 : U64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.280 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.277; ret Num.280;
procedure Num.22 (#Attr.2, #Attr.3): procedure Num.22 (#Attr.2, #Attr.3):
let Num.278 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; let Num.281 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.278; ret Num.281;
procedure Num.77 (#Attr.2, #Attr.3): procedure Num.77 (#Attr.2, #Attr.3):
let Num.276 : U64 = lowlevel NumSubSaturated #Attr.2 #Attr.3; let Num.279 : U64 = lowlevel NumSubSaturated #Attr.2 #Attr.3;
ret Num.276; ret Num.279;
procedure Test.1 (Test.2): procedure Test.1 (Test.2):
let Test.13 : U64 = 0i64; let Test.13 : U64 = 0i64;

View file

@ -46,8 +46,8 @@ procedure List.9 (List.287):
ret List.496; ret List.496;
procedure Num.22 (#Attr.2, #Attr.3): procedure Num.22 (#Attr.2, #Attr.3):
let Num.275 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; let Num.278 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Result.5 (Result.12, Result.13): procedure Result.5 (Result.12, Result.13):
let Result.39 : U8 = 1i64; let Result.39 : U8 = 1i64;

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.276 : I128 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.279 : I128 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.276; ret Num.279;
procedure Test.0 (): procedure Test.0 ():
let Test.6 : I128 = 18446744073709551616i64; let Test.6 : I128 = 18446744073709551616i64;

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.275 : U128 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.278 : U128 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Test.0 (): procedure Test.0 ():
let Test.2 : U128 = 170141183460469231731687303715884105728u128; let Test.2 : U128 = 170141183460469231731687303715884105728u128;

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.275 : U64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.278 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Test.0 (): procedure Test.0 ():
let Test.2 : U64 = 9999999999999999999i64; let Test.2 : U64 = 9999999999999999999i64;

View file

@ -40,12 +40,12 @@ procedure List.92 (List.430, List.431, List.432):
ret List.497; ret List.497;
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.275 : U64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.278 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Num.22 (#Attr.2, #Attr.3): procedure Num.22 (#Attr.2, #Attr.3):
let Num.276 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; let Num.279 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.276; ret Num.279;
procedure Str.3 (#Attr.2, #Attr.3): procedure Str.3 (#Attr.2, #Attr.3):
let Str.300 : Str = lowlevel StrConcat #Attr.2 #Attr.3; let Str.300 : Str = lowlevel StrConcat #Attr.2 #Attr.3;

View file

@ -79,12 +79,12 @@ procedure List.82 (List.526, List.527, List.528):
jump List.508 List.526 List.527 List.528; jump List.508 List.526 List.527 List.528;
procedure Num.20 (#Attr.2, #Attr.3): procedure Num.20 (#Attr.2, #Attr.3):
let Num.276 : U64 = lowlevel NumSub #Attr.2 #Attr.3; let Num.279 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.276; ret Num.279;
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Num.278 : Int1 = lowlevel NumGt #Attr.2 #Attr.3; let Num.281 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.278; ret Num.281;
procedure Test.0 (): procedure Test.0 ():
let Test.3 : {} = Struct {}; let Test.3 : {} = Struct {};

View file

@ -25,8 +25,8 @@ procedure List.66 (#Attr.2, #Attr.3):
ret List.499; ret List.499;
procedure Num.22 (#Attr.2, #Attr.3): procedure Num.22 (#Attr.2, #Attr.3):
let Num.275 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; let Num.278 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Test.2 (Test.5): procedure Test.2 (Test.5):
dec Test.5; dec Test.5;

View file

@ -285,24 +285,24 @@ procedure List.92 (List.430, List.431, List.432):
ret List.592; ret List.592;
procedure Num.127 (#Attr.2): procedure Num.127 (#Attr.2):
let Num.301 : U8 = lowlevel NumIntCast #Attr.2; let Num.304 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.301;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.304 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.304; ret Num.304;
procedure Num.20 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.302 : U64 = lowlevel NumSub #Attr.2 #Attr.3; let Num.307 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.302; ret Num.307;
procedure Num.22 (#Attr.2, #Attr.3): procedure Num.20 (#Attr.2, #Attr.3):
let Num.305 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; let Num.305 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.305; ret Num.305;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.308 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.308;
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Num.303 : Int1 = lowlevel NumGt #Attr.2 #Attr.3; let Num.306 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.303; ret Num.306;
procedure Str.12 (#Attr.2): procedure Str.12 (#Attr.2):
let Str.315 : List U8 = lowlevel StrToUtf8 #Attr.2; let Str.315 : List U8 = lowlevel StrToUtf8 #Attr.2;

View file

@ -169,24 +169,24 @@ procedure List.92 (List.430, List.431, List.432):
ret List.525; ret List.525;
procedure Num.127 (#Attr.2): procedure Num.127 (#Attr.2):
let Num.282 : U8 = lowlevel NumIntCast #Attr.2; let Num.285 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.282;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.285 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.285; ret Num.285;
procedure Num.20 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.283 : U64 = lowlevel NumSub #Attr.2 #Attr.3; let Num.288 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.283; ret Num.288;
procedure Num.22 (#Attr.2, #Attr.3): procedure Num.20 (#Attr.2, #Attr.3):
let Num.286 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; let Num.286 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.286; ret Num.286;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.289 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.289;
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Num.284 : Int1 = lowlevel NumGt #Attr.2 #Attr.3; let Num.287 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.284; ret Num.287;
procedure Str.12 (#Attr.2): procedure Str.12 (#Attr.2):
let Str.313 : List U8 = lowlevel StrToUtf8 #Attr.2; let Str.313 : List U8 = lowlevel StrToUtf8 #Attr.2;

View file

@ -176,24 +176,24 @@ procedure List.92 (List.430, List.431, List.432):
ret List.525; ret List.525;
procedure Num.127 (#Attr.2): procedure Num.127 (#Attr.2):
let Num.282 : U8 = lowlevel NumIntCast #Attr.2; let Num.285 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.282;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.285 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.285; ret Num.285;
procedure Num.20 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.283 : U64 = lowlevel NumSub #Attr.2 #Attr.3; let Num.288 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.283; ret Num.288;
procedure Num.22 (#Attr.2, #Attr.3): procedure Num.20 (#Attr.2, #Attr.3):
let Num.286 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; let Num.286 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.286; ret Num.286;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.289 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.289;
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Num.284 : Int1 = lowlevel NumGt #Attr.2 #Attr.3; let Num.287 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.284; ret Num.287;
procedure Str.12 (#Attr.2): procedure Str.12 (#Attr.2):
let Str.313 : List U8 = lowlevel StrToUtf8 #Attr.2; let Str.313 : List U8 = lowlevel StrToUtf8 #Attr.2;

View file

@ -53,8 +53,8 @@ procedure List.8 (#Attr.2, #Attr.3):
ret List.504; ret List.504;
procedure Num.127 (#Attr.2): procedure Num.127 (#Attr.2):
let Num.276 : U8 = lowlevel NumIntCast #Attr.2; let Num.279 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.276; ret Num.279;
procedure Str.12 (#Attr.2): procedure Str.12 (#Attr.2):
let Str.312 : List U8 = lowlevel StrToUtf8 #Attr.2; let Str.312 : List U8 = lowlevel StrToUtf8 #Attr.2;

View file

@ -178,24 +178,24 @@ procedure List.92 (List.430, List.431, List.432):
ret List.531; ret List.531;
procedure Num.127 (#Attr.2): procedure Num.127 (#Attr.2):
let Num.284 : U8 = lowlevel NumIntCast #Attr.2; let Num.287 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.284;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.287 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.287; ret Num.287;
procedure Num.20 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.285 : U64 = lowlevel NumSub #Attr.2 #Attr.3; let Num.290 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.285; ret Num.290;
procedure Num.22 (#Attr.2, #Attr.3): procedure Num.20 (#Attr.2, #Attr.3):
let Num.288 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; let Num.288 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.288; ret Num.288;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.291 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.291;
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Num.286 : Int1 = lowlevel NumGt #Attr.2 #Attr.3; let Num.289 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.286; ret Num.289;
procedure Str.12 (#Attr.2): procedure Str.12 (#Attr.2):
let Str.313 : List U8 = lowlevel StrToUtf8 #Attr.2; let Str.313 : List U8 = lowlevel StrToUtf8 #Attr.2;

View file

@ -181,24 +181,24 @@ procedure List.92 (List.430, List.431, List.432):
ret List.531; ret List.531;
procedure Num.127 (#Attr.2): procedure Num.127 (#Attr.2):
let Num.284 : U8 = lowlevel NumIntCast #Attr.2; let Num.287 : U8 = lowlevel NumIntCast #Attr.2;
ret Num.284;
procedure Num.19 (#Attr.2, #Attr.3):
let Num.287 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.287; ret Num.287;
procedure Num.20 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.285 : U64 = lowlevel NumSub #Attr.2 #Attr.3; let Num.290 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.285; ret Num.290;
procedure Num.22 (#Attr.2, #Attr.3): procedure Num.20 (#Attr.2, #Attr.3):
let Num.288 : Int1 = lowlevel NumLt #Attr.2 #Attr.3; let Num.288 : U64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.288; ret Num.288;
procedure Num.22 (#Attr.2, #Attr.3):
let Num.291 : Int1 = lowlevel NumLt #Attr.2 #Attr.3;
ret Num.291;
procedure Num.24 (#Attr.2, #Attr.3): procedure Num.24 (#Attr.2, #Attr.3):
let Num.286 : Int1 = lowlevel NumGt #Attr.2 #Attr.3; let Num.289 : Int1 = lowlevel NumGt #Attr.2 #Attr.3;
ret Num.286; ret Num.289;
procedure Str.12 (#Attr.2): procedure Str.12 (#Attr.2):
let Str.313 : List U8 = lowlevel StrToUtf8 #Attr.2; let Str.313 : List U8 = lowlevel StrToUtf8 #Attr.2;

View file

@ -1,10 +1,10 @@
procedure Num.20 (#Attr.2, #Attr.3): procedure Num.20 (#Attr.2, #Attr.3):
let Num.276 : I64 = lowlevel NumSub #Attr.2 #Attr.3; let Num.279 : I64 = lowlevel NumSub #Attr.2 #Attr.3;
ret Num.276; ret Num.279;
procedure Num.21 (#Attr.2, #Attr.3): procedure Num.21 (#Attr.2, #Attr.3):
let Num.275 : I64 = lowlevel NumMul #Attr.2 #Attr.3; let Num.278 : I64 = lowlevel NumMul #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Test.1 (Test.15, Test.16): procedure Test.1 (Test.15, Test.16):
joinpoint Test.7 Test.2 Test.3: joinpoint Test.7 Test.2 Test.3:

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.275 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.278 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Test.1 (Test.8): procedure Test.1 (Test.8):
let Test.3 : I64 = 10i64; let Test.3 : I64 = 10i64;

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.276 : U8 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.279 : U8 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.276; ret Num.279;
procedure Test.1 (Test.9): procedure Test.1 (Test.9):
let Test.4 : U8 = 10i64; let Test.4 : U8 = 10i64;

View file

@ -3,8 +3,8 @@ procedure Bool.1 ():
ret Bool.23; ret Bool.23;
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.275 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.278 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Test.3 (Test.4): procedure Test.3 (Test.4):
ret Test.4; ret Test.4;

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.277 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.280 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.277; ret Num.280;
procedure Test.2 (Test.3): procedure Test.2 (Test.3):
switch Test.3: switch Test.3:

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.276 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.279 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.276; ret Num.279;
procedure Test.2 (Test.3, Test.1): procedure Test.2 (Test.3, Test.1):
let Test.17 : Int1 = false; let Test.17 : Int1 = false;

View file

@ -3,8 +3,8 @@ procedure List.6 (#Attr.2):
ret List.494; ret List.494;
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.277 : U64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.280 : U64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.277; ret Num.280;
procedure Test.0 (): procedure Test.0 ():
let Test.1 : List I64 = Array [1i64, 2i64]; let Test.1 : List I64 = Array [1i64, 2i64];

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.275 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.278 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Test.0 (): procedure Test.0 ():
let Test.2 : I64 = 1i64; let Test.2 : I64 = 1i64;

View file

@ -1,6 +1,6 @@
procedure Num.45 (#Attr.2): procedure Num.45 (#Attr.2):
let Num.275 : I64 = lowlevel NumRound #Attr.2; let Num.278 : I64 = lowlevel NumRound #Attr.2;
ret Num.275; ret Num.278;
procedure Test.0 (): procedure Test.0 ():
let Test.2 : Float64 = 3.6f64; let Test.2 : Float64 = 3.6f64;

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.275 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.278 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Test.0 (): procedure Test.0 ():
let Test.1 : I64 = 3i64; let Test.1 : I64 = 3i64;

View file

@ -1,22 +1,22 @@
procedure Num.30 (#Attr.2): procedure Num.30 (#Attr.2):
let Num.282 : I64 = 0i64; let Num.285 : I64 = 0i64;
let Num.281 : Int1 = lowlevel Eq #Attr.2 Num.282; let Num.284 : Int1 = lowlevel Eq #Attr.2 Num.285;
ret Num.281; ret Num.284;
procedure Num.39 (#Attr.2, #Attr.3): procedure Num.39 (#Attr.2, #Attr.3):
let Num.277 : I64 = lowlevel NumDivTruncUnchecked #Attr.2 #Attr.3; let Num.280 : I64 = lowlevel NumDivTruncUnchecked #Attr.2 #Attr.3;
ret Num.277; ret Num.280;
procedure Num.40 (Num.247, Num.248): procedure Num.40 (Num.250, Num.251):
let Num.278 : Int1 = CallByName Num.30 Num.248; let Num.281 : Int1 = CallByName Num.30 Num.251;
if Num.278 then if Num.281 then
let Num.280 : {} = Struct {}; let Num.283 : {} = Struct {};
let Num.279 : [C {}, C I64] = TagId(0) Num.280; let Num.282 : [C {}, C I64] = TagId(0) Num.283;
ret Num.279; ret Num.282;
else else
let Num.276 : I64 = CallByName Num.39 Num.247 Num.248; let Num.279 : I64 = CallByName Num.39 Num.250 Num.251;
let Num.275 : [C {}, C I64] = TagId(1) Num.276; let Num.278 : [C {}, C I64] = TagId(1) Num.279;
ret Num.275; ret Num.278;
procedure Test.0 (): procedure Test.0 ():
let Test.8 : I64 = 1000i64; let Test.8 : I64 = 1000i64;

View file

@ -1,6 +1,6 @@
procedure Num.19 (#Attr.2, #Attr.3): procedure Num.19 (#Attr.2, #Attr.3):
let Num.275 : I64 = lowlevel NumAdd #Attr.2 #Attr.3; let Num.278 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
ret Num.275; ret Num.278;
procedure Test.0 (): procedure Test.0 ():
let Test.10 : I64 = 41i64; let Test.10 : I64 = 41i64;

Some files were not shown because too many files have changed in this diff Show more