Merge remote-tracking branch 'origin/trunk' into list-str-capacity

This commit is contained in:
Folkert 2022-04-04 19:55:04 +02:00
commit 68536e4026
No known key found for this signature in database
GPG key ID: 1F17F6FFD112B97C
31 changed files with 181 additions and 277 deletions

View file

@ -4,7 +4,7 @@ use crate::lang::core::{expr::expr2::ExprId, header::AppHeader};
pub fn parse_from_string(_header_str: &str, ast_node_id: ExprId) -> AppHeader {
AppHeader {
app_name: "\"untitled-app\"".to_owned(),
packages_base: "\"platform\"".to_owned(),
packages_base: "\"c-platform\"".to_owned(),
imports: vec![],
provides: vec!["main".to_owned()],
ast_node_id,

View file

@ -243,7 +243,7 @@ fn add_header_mn_list(
str_vec
.iter()
.enumerate()
.map(|(indx, provide_str)| {
.flat_map(|(indx, provide_str)| {
let provide_str = header_val_mn(
provide_str.to_owned(),
ast_node_id,
@ -266,7 +266,6 @@ fn add_header_mn_list(
vec![provide_str]
}
})
.flatten()
.collect()
}

View file

@ -395,7 +395,7 @@ fn tree_as_string_helper(
.to_owned();
let child = mark_node_pool.get(child_id);
let child_str = format!("{}", mark_node_pool.get(child_id)).replace("\n", "\\n");
let child_str = format!("{}", mark_node_pool.get(child_id)).replace('\n', "\\n");
full_str.push_str(&format!("{} mn_id {}\n", child_str, child_id));

View file

@ -947,7 +947,7 @@ fn link_macos(
Err(_) => "".to_string(),
};
for roc_link_flag in roc_link_flags.split_whitespace() {
ld_command.arg(roc_link_flag.to_string());
ld_command.arg(roc_link_flag);
}
ld_command.args(&[

View file

@ -266,6 +266,7 @@ pub fn gen_from_mono_module_llvm(
|| name.starts_with("roc_builtins.dec")
|| name.starts_with("list.RocList")
|| name.starts_with("dict.RocDict")
|| name.contains("incref")
|| name.contains("decref")
{
function.add_attribute(AttributeLoc::Function, enum_attr);

View file

@ -155,6 +155,7 @@ comptime {
exportUtilsFn(utils.increfC, "incref");
exportUtilsFn(utils.decrefC, "decref");
exportUtilsFn(utils.decrefCheckNullC, "decref_check_null");
exportUtilsFn(utils.allocateWithRefcountC, "allocate_with_refcount");
exportExpectFn(expect.expectFailedC, "expect_failed");
exportExpectFn(expect.getExpectFailuresC, "get_expect_failures");
exportExpectFn(expect.deinitFailuresC, "deinit_failures");

View file

@ -1,5 +1,6 @@
const std = @import("std");
const always_inline = std.builtin.CallOptions.Modifier.always_inline;
const Monotonic = std.builtin.AtomicOrder.Monotonic;
pub fn WithOverflow(comptime T: type) type {
return extern struct { value: T, has_overflowed: bool };
@ -120,10 +121,32 @@ pub const IntWidth = enum(u8) {
I128 = 9,
};
const Refcount = enum {
none,
normal,
atomic,
};
const RC_TYPE = Refcount.normal;
pub fn increfC(ptr_to_refcount: *isize, amount: isize) callconv(.C) void {
if (RC_TYPE == Refcount.none) return;
var refcount = ptr_to_refcount.*;
var masked_amount = if (refcount == REFCOUNT_MAX_ISIZE) 0 else amount;
ptr_to_refcount.* = refcount + masked_amount;
if (refcount < REFCOUNT_MAX_ISIZE) {
switch (RC_TYPE) {
Refcount.normal => {
ptr_to_refcount.* = std.math.min(refcount + amount, REFCOUNT_MAX_ISIZE);
},
Refcount.atomic => {
var next = std.math.min(refcount + amount, REFCOUNT_MAX_ISIZE);
while (@cmpxchgWeak(isize, ptr_to_refcount, refcount, next, Monotonic, Monotonic)) |found| {
refcount = found;
next = std.math.min(refcount + amount, REFCOUNT_MAX_ISIZE);
}
},
Refcount.none => unreachable,
}
}
}
pub fn decrefC(
@ -169,71 +192,51 @@ inline fn decref_ptr_to_refcount(
refcount_ptr: [*]isize,
alignment: u32,
) void {
const refcount: isize = refcount_ptr[0];
if (RC_TYPE == Refcount.none) return;
const extra_bytes = std.math.max(alignment, @sizeOf(usize));
if (refcount == REFCOUNT_ONE_ISIZE) {
dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment);
} else if (refcount < 0) {
refcount_ptr[0] = refcount - 1;
switch (RC_TYPE) {
Refcount.normal => {
const refcount: isize = refcount_ptr[0];
if (refcount == REFCOUNT_ONE_ISIZE) {
dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment);
} else if (refcount < REFCOUNT_MAX_ISIZE) {
refcount_ptr[0] = refcount - 1;
}
},
Refcount.atomic => {
if (refcount_ptr[0] < REFCOUNT_MAX_ISIZE) {
var last = @atomicRmw(isize, &refcount_ptr[0], std.builtin.AtomicRmwOp.Sub, 1, Monotonic);
if (last == REFCOUNT_ONE_ISIZE) {
dealloc(@ptrCast([*]u8, refcount_ptr) - (extra_bytes - @sizeOf(usize)), alignment);
}
}
},
Refcount.none => unreachable,
}
}
pub fn allocateWithRefcountC(
data_bytes: usize,
element_alignment: u32,
) callconv(.C) [*]u8 {
return allocateWithRefcount(data_bytes, element_alignment);
}
pub fn allocateWithRefcount(
data_bytes: usize,
element_alignment: u32,
) [*]u8 {
const alignment = std.math.max(@sizeOf(usize), element_alignment);
const first_slot_offset = std.math.max(@sizeOf(usize), element_alignment);
const ptr_width = @sizeOf(usize);
const alignment = std.math.max(ptr_width, element_alignment);
const length = alignment + data_bytes;
switch (alignment) {
16 => {
// TODO handle alloc failing!
var new_bytes: [*]align(16) u8 = @alignCast(16, alloc(length, alignment) orelse unreachable);
var new_bytes: [*]u8 = alloc(length, alignment) orelse unreachable;
var as_usize_array = @ptrCast([*]usize, new_bytes);
as_usize_array[0] = 0;
as_usize_array[1] = REFCOUNT_ONE;
const data_ptr = new_bytes + alignment;
const refcount_ptr = @ptrCast([*]usize, @alignCast(ptr_width, data_ptr) - ptr_width);
refcount_ptr[0] = if (RC_TYPE == Refcount.none) REFCOUNT_MAX_ISIZE else REFCOUNT_ONE;
var as_u8_array = @ptrCast([*]u8, new_bytes);
const first_slot = as_u8_array + first_slot_offset;
return first_slot;
},
8 => {
// TODO handle alloc failing!
var raw = alloc(length, alignment) orelse unreachable;
var new_bytes: [*]align(8) u8 = @alignCast(8, raw);
var as_isize_array = @ptrCast([*]isize, new_bytes);
as_isize_array[0] = REFCOUNT_ONE_ISIZE;
var as_u8_array = @ptrCast([*]u8, new_bytes);
const first_slot = as_u8_array + first_slot_offset;
return first_slot;
},
4 => {
// TODO handle alloc failing!
var raw = alloc(length, alignment) orelse unreachable;
var new_bytes: [*]align(@alignOf(isize)) u8 = @alignCast(@alignOf(isize), raw);
var as_isize_array = @ptrCast([*]isize, new_bytes);
as_isize_array[0] = REFCOUNT_ONE_ISIZE;
var as_u8_array = @ptrCast([*]u8, new_bytes);
const first_slot = as_u8_array + first_slot_offset;
return first_slot;
},
else => {
// const stdout = std.io.getStdOut().writer();
// stdout.print("alignment: {d}", .{alignment}) catch unreachable;
// @panic("allocateWithRefcount with invalid alignment");
unreachable;
},
}
return data_ptr;
}
pub const CSlice = extern struct {

View file

@ -371,6 +371,7 @@ pub const DEC_MUL_WITH_OVERFLOW: &str = "roc_builtins.dec.mul_with_overflow";
pub const DEC_DIV: &str = "roc_builtins.dec.div";
pub const UTILS_TEST_PANIC: &str = "roc_builtins.utils.test_panic";
pub const UTILS_ALLOCATE_WITH_REFCOUNT: &str = "roc_builtins.utils.allocate_with_refcount";
pub const UTILS_INCREF: &str = "roc_builtins.utils.incref";
pub const UTILS_DECREF: &str = "roc_builtins.utils.decref";
pub const UTILS_DECREF_CHECK_NULL: &str = "roc_builtins.utils.decref_check_null";

View file

@ -166,8 +166,7 @@ fn sort_type_defs_before_introduction(
Ok(result) => result
.iter()
.rev()
.map(|group_index| sccs[*group_index].iter())
.flatten()
.flat_map(|group_index| sccs[*group_index].iter())
.copied()
.collect(),

View file

@ -281,8 +281,7 @@ pub fn canonicalize_module_defs<'a>(
let transitive_builtins: Vec<Symbol> = referenced_values
.iter()
.filter(|s| s.is_builtin())
.map(|s| crate::builtins::builtin_dependencies(*s))
.flatten()
.flat_map(|s| crate::builtins::builtin_dependencies(*s))
.copied()
.collect();

View file

@ -110,7 +110,7 @@ pub enum ParsedNumResult {
pub fn finish_parsing_num(raw: &str) -> Result<ParsedNumResult, (&str, IntErrorKind)> {
// Ignore underscores.
let radix = 10;
from_str_radix(raw.replace("_", "").as_str(), radix).map_err(|e| (raw, e))
from_str_radix(raw.replace('_', "").as_str(), radix).map_err(|e| (raw, e))
}
#[inline(always)]
@ -128,9 +128,9 @@ pub fn finish_parsing_base(
// Ignore underscores, insert - when negative to get correct underflow/overflow behavior
(if is_negative {
from_str_radix(format!("-{}", raw.replace("_", "")).as_str(), radix)
from_str_radix(format!("-{}", raw.replace('_', "")).as_str(), radix)
} else {
from_str_radix(raw.replace("_", "").as_str(), radix)
from_str_radix(raw.replace('_', "").as_str(), radix)
})
.and_then(|parsed| match parsed {
ParsedNumResult::Float(..) => Err(IntErrorKind::FloatSuffix),
@ -154,7 +154,7 @@ pub fn finish_parsing_float(raw: &str) -> Result<(f64, FloatBound), (&str, Float
};
// Ignore underscores.
match raw_without_suffix.replace("_", "").parse::<f64>() {
match raw_without_suffix.replace('_', "").parse::<f64>() {
Ok(float) if float.is_finite() => Ok((float, bound)),
Ok(float) => {
if float.is_sign_positive() {

View file

@ -185,8 +185,7 @@ fn is_exhaustive(matrix: &RefPatternMatrix, n: usize) -> PatternMatrix {
alt_list
.iter()
.cloned()
.map(is_alt_exhaustive)
.flatten()
.flat_map(is_alt_exhaustive)
.collect()
}
}

View file

@ -2063,8 +2063,7 @@ fn reserve_with_refcount_union_as_block_of_memory<'a, 'ctx, 'env>(
let alignment_bytes = fields
.iter()
.map(|tag| tag.iter().map(|l| l.alignment_bytes(env.target_info)))
.flatten()
.flat_map(|tag| tag.iter().map(|l| l.alignment_bytes(env.target_info)))
.max()
.unwrap_or(0);
@ -2077,15 +2076,11 @@ fn reserve_with_refcount_help<'a, 'ctx, 'env>(
stack_size: u32,
alignment_bytes: u32,
) -> PointerValue<'ctx> {
let ctx = env.context;
let len_type = env.ptr_int();
let value_bytes_intvalue = len_type.const_int(stack_size as u64, false);
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info);
allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue, rc1)
allocate_with_refcount_help(env, basic_type, alignment_bytes, value_bytes_intvalue)
}
pub fn allocate_with_refcount<'a, 'ctx, 'env>(
@ -2106,74 +2101,22 @@ pub fn allocate_with_refcount_help<'a, 'ctx, 'env>(
value_type: impl BasicType<'ctx>,
alignment_bytes: u32,
number_of_data_bytes: IntValue<'ctx>,
initial_refcount: IntValue<'ctx>,
) -> PointerValue<'ctx> {
let builder = env.builder;
let ptr = call_bitcode_fn(
env,
&[
number_of_data_bytes.into(),
env.alignment_const(alignment_bytes).into(),
],
roc_builtins::bitcode::UTILS_ALLOCATE_WITH_REFCOUNT,
)
.into_pointer_value();
let len_type = env.ptr_int();
let ptr_width_u32 = env.target_info.ptr_width() as u32;
let ptr_type = value_type.ptr_type(AddressSpace::Generic);
let extra_bytes = alignment_bytes.max(ptr_width_u32);
let ptr = {
// number of bytes we will allocated
let number_of_bytes = builder.build_int_add(
len_type.const_int(extra_bytes as u64, false),
number_of_data_bytes,
"add_extra_bytes",
);
env.call_alloc(number_of_bytes, alignment_bytes)
};
// We must return a pointer to the first element:
let data_ptr = {
let int_type = env.ptr_int();
let as_usize_ptr = builder
.build_bitcast(
ptr,
int_type.ptr_type(AddressSpace::Generic),
"to_usize_ptr",
)
.into_pointer_value();
let index = match extra_bytes {
n if n == ptr_width_u32 => 1,
n if n == 2 * ptr_width_u32 => 2,
_ => unreachable!("invalid extra_bytes, {}", extra_bytes),
};
let index_intvalue = int_type.const_int(index, false);
let ptr_type = value_type.ptr_type(AddressSpace::Generic);
unsafe {
builder.build_pointer_cast(
env.builder
.build_in_bounds_gep(as_usize_ptr, &[index_intvalue], "get_data_ptr"),
ptr_type,
"alloc_cast_to_desired",
)
}
};
let refcount_ptr = match extra_bytes {
n if n == ptr_width_u32 => {
// the allocated pointer is the same as the refcounted pointer
unsafe { PointerToRefcount::from_ptr(env, ptr) }
}
n if n == 2 * ptr_width_u32 => {
// the refcount is stored just before the start of the actual data
// but in this case (because of alignment) not at the start of the allocated buffer
PointerToRefcount::from_ptr_to_data(env, data_ptr)
}
n => unreachable!("invalid extra_bytes {}", n),
};
// let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.ptr_bytes);
refcount_ptr.set_refcount(env, initial_refcount);
data_ptr
env.builder
.build_bitcast(ptr, ptr_type, "alloc_cast_to_desired")
.into_pointer_value()
}
macro_rules! dict_key_value_layout {

View file

@ -1286,7 +1286,6 @@ pub fn allocate_list<'a, 'ctx, 'env>(
number_of_elements: IntValue<'ctx>,
) -> PointerValue<'ctx> {
let builder = env.builder;
let ctx = env.context;
let len_type = env.ptr_int();
let elem_bytes = elem_layout.stack_size(env.target_info) as u64;
@ -1294,13 +1293,9 @@ pub fn allocate_list<'a, 'ctx, 'env>(
let number_of_data_bytes =
builder.build_int_mul(bytes_per_element, number_of_elements, "data_length");
// the refcount of a new list is initially 1
// we assume that the list is indeed used (dead variables are eliminated)
let rc1 = crate::llvm::refcounting::refcount_1(ctx, env.target_info);
let basic_type = basic_type_from_layout(env, elem_layout);
let alignment_bytes = elem_layout.alignment_bytes(env.target_info);
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes, rc1)
allocate_with_refcount_help(env, basic_type, alignment_bytes, number_of_data_bytes)
}
pub fn store_list<'a, 'ctx, 'env>(
@ -1312,10 +1307,8 @@ pub fn store_list<'a, 'ctx, 'env>(
let struct_type = super::convert::zig_list_type(env);
let mut struct_val;
// Store the pointer
struct_val = builder
let mut struct_val = builder
.build_insert_value(
struct_type.get_undef(),
pass_as_opaque(env, pointer_to_first_element),

View file

@ -8,7 +8,6 @@ use crate::llvm::build_list::{incrementing_elem_loop, list_len, load_list};
use crate::llvm::convert::basic_type_from_layout;
use bumpalo::collections::Vec;
use inkwell::basic_block::BasicBlock;
use inkwell::context::Context;
use inkwell::module::Linkage;
use inkwell::types::{AnyTypeEnum, BasicMetadataTypeEnum, BasicType, BasicTypeEnum};
use inkwell::values::{
@ -18,22 +17,10 @@ use inkwell::{AddressSpace, IntPredicate};
use roc_module::symbol::Interns;
use roc_module::symbol::Symbol;
use roc_mono::layout::{Builtin, Layout, LayoutIds, UnionLayout};
use roc_target::TargetInfo;
use super::build::load_roc_value;
use super::convert::{argument_type_from_layout, argument_type_from_union_layout};
/// "Infinite" reference count, for static values
/// Ref counts are encoded as negative numbers where isize::MIN represents 1
pub const REFCOUNT_MAX: usize = 0_usize;
pub fn refcount_1(ctx: &Context, target_info: TargetInfo) -> IntValue<'_> {
match target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => ctx.i32_type().const_int(i32::MIN as u64, false),
roc_target::PtrWidth::Bytes8 => ctx.i64_type().const_int(i64::MIN as u64, false),
}
}
pub struct PointerToRefcount<'ctx> {
value: PointerValue<'ctx>,
}
@ -96,7 +83,14 @@ impl<'ctx> PointerToRefcount<'ctx> {
pub fn is_1<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>) -> IntValue<'ctx> {
let current = self.get_refcount(env);
let one = refcount_1(env.context, env.target_info);
let one = match env.target_info.ptr_width() {
roc_target::PtrWidth::Bytes4 => {
env.context.i32_type().const_int(i32::MIN as u64, false)
}
roc_target::PtrWidth::Bytes8 => {
env.context.i64_type().const_int(i64::MIN as u64, false)
}
};
env.builder
.build_int_compare(IntPredicate::EQ, current, one, "is_one")
@ -125,38 +119,7 @@ impl<'ctx> PointerToRefcount<'ctx> {
}
fn increment<'a, 'env>(&self, amount: IntValue<'ctx>, env: &Env<'a, 'ctx, 'env>) {
let refcount = self.get_refcount(env);
let builder = env.builder;
let refcount_type = env.ptr_int();
let is_static_allocation = builder.build_int_compare(
IntPredicate::EQ,
refcount,
refcount_type.const_int(REFCOUNT_MAX as u64, false),
"refcount_max_check",
);
let block = env.builder.get_insert_block().expect("to be in a function");
let parent = block.get_parent().unwrap();
let modify_block = env
.context
.append_basic_block(parent, "inc_refcount_modify");
let cont_block = env.context.append_basic_block(parent, "inc_refcount_cont");
env.builder
.build_conditional_branch(is_static_allocation, cont_block, modify_block);
{
env.builder.position_at_end(modify_block);
let incremented = builder.build_int_add(refcount, amount, "increment_refcount");
self.set_refcount(env, incremented);
env.builder.build_unconditional_branch(cont_block);
}
env.builder.position_at_end(cont_block);
incref_pointer(env, self.value, amount);
}
pub fn decrement<'a, 'env>(&self, env: &Env<'a, 'ctx, 'env>, layout: &Layout<'a>) {
@ -232,6 +195,25 @@ impl<'ctx> PointerToRefcount<'ctx> {
}
}
fn incref_pointer<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
pointer: PointerValue<'ctx>,
amount: IntValue<'ctx>,
) {
call_void_bitcode_fn(
env,
&[
env.builder.build_bitcast(
pointer,
env.ptr_int().ptr_type(AddressSpace::Generic),
"to_isize_ptr",
),
amount.into(),
],
roc_builtins::bitcode::UTILS_INCREF,
);
}
fn decref_pointer<'a, 'ctx, 'env>(
env: &Env<'a, 'ctx, 'env>,
pointer: PointerValue<'ctx>,

View file

@ -121,8 +121,7 @@ fn start_phase<'a>(
Recurse(new) => {
return new
.into_iter()
.map(|(module_id, phase)| start_phase(module_id, phase, arena, state))
.flatten()
.flat_map(|(module_id, phase)| start_phase(module_id, phase, arena, state))
.collect()
}
}

View file

@ -5971,7 +5971,7 @@ fn substitute_in_stmt_help<'a>(
if opt_remainder.is_some() || opt_continuation.is_some() {
let remainder = opt_remainder.unwrap_or(remainder);
let continuation = opt_continuation.unwrap_or_else(|| *continuation);
let continuation = opt_continuation.unwrap_or(*continuation);
Some(arena.alloc(Join {
id: *id,

View file

@ -1194,8 +1194,7 @@ impl<'a> Layout<'a> {
match variant {
NonRecursive(fields) => fields
.iter()
.map(|ls| ls.iter())
.flatten()
.flat_map(|ls| ls.iter())
.any(|f| f.contains_refcounted()),
Recursive(_)
| NullableWrapped { .. }

View file

@ -117,7 +117,7 @@ fn insert_jumps<'a>(
if opt_remainder.is_some() || opt_continuation.is_some() {
let remainder = opt_remainder.unwrap_or(remainder);
let continuation = opt_continuation.unwrap_or_else(|| *continuation);
let continuation = opt_continuation.unwrap_or(*continuation);
Some(arena.alloc(Join {
id: *id,

View file

@ -966,8 +966,7 @@ impl Type {
Self::contains_symbol_ext(ext, rep_symbol)
|| tags
.iter()
.map(|v| v.1.iter())
.flatten()
.flat_map(|v| v.1.iter())
.any(|arg| arg.contains_symbol(rep_symbol))
}
@ -1026,8 +1025,7 @@ impl Type {
Self::contains_variable_ext(ext, rep_variable)
|| tags
.iter()
.map(|v| v.1.iter())
.flatten()
.flat_map(|v| v.1.iter())
.any(|arg| arg.contains_variable(rep_variable))
}
@ -1235,7 +1233,7 @@ impl Type {
substitution.clear();
substitution.insert(rec_var, Type::Variable(new_rec_var));
for typ in tags.iter_mut().map(|v| v.1.iter_mut()).flatten() {
for typ in tags.iter_mut().flat_map(|v| v.1.iter_mut()) {
typ.substitute(&substitution);
}
@ -1353,7 +1351,7 @@ fn symbols_help(initial: &Type) -> Vec<Symbol> {
}
RecursiveTagUnion(_, tags, ext) | TagUnion(tags, ext) => {
stack.extend(ext);
stack.extend(tags.iter().map(|v| v.1.iter()).flatten());
stack.extend(tags.iter().flat_map(|v| v.1.iter()));
}
Record(fields, ext) => {
@ -2377,8 +2375,7 @@ pub fn gather_fields_unsorted_iter(
let it = stack
.into_iter()
.map(|fields| fields.iter_all())
.flatten()
.flat_map(|fields| fields.iter_all())
.map(move |(i1, i2, i3)| {
let field_name: &Lowercase = &subs[i1];
let variable = subs[i2];
@ -2462,8 +2459,7 @@ pub fn gather_tags_unsorted_iter(
let it = stack
.into_iter()
.map(|union_tags| union_tags.iter_all())
.flatten()
.flat_map(|union_tags| union_tags.iter_all())
.map(move |(i1, i2)| {
let tag_name: &TagName = &subs[i1];
let subs_slice = subs[i2];

View file

@ -262,11 +262,7 @@ fn check_valid_range(
range: VariableSubsSlice,
mode: Mode,
) -> Outcome {
let slice = subs
.get_subs_slice(range)
.iter()
.copied()
.collect::<Vec<_>>();
let slice = subs.get_subs_slice(range).to_vec();
let mut it = slice.iter().peekable();
while let Some(&possible_var) = it.next() {
@ -1432,7 +1428,7 @@ fn unify_recursion(
} => {
// NOTE: structure and other_structure may not be unified yet, but will be
// we should not do that here, it would create an infinite loop!
let name = (*opt_name).or_else(|| *other_opt_name);
let name = (*opt_name).or(*other_opt_name);
merge(
subs,
ctx,

View file

@ -83,7 +83,7 @@ pub fn generate_docs_html(filenames: Vec<PathBuf>, build_dir: &Path) {
// Write each package's module docs html file
for loaded_module in package.modules.iter_mut() {
for module_docs in loaded_module.documentation.values() {
let module_dir = build_dir.join(module_docs.name.replace(".", "/").as_str());
let module_dir = build_dir.join(module_docs.name.replace('.', "/").as_str());
fs::create_dir_all(&module_dir)
.expect("TODO gracefully handle not being able to create the module dir");

View file

@ -70,7 +70,7 @@ impl fmt::Display for CodeLines {
.collect::<Vec<String>>()
.join(" ");
let escaped_row_str = row_str.replace("\n", "\\n");
let escaped_row_str = row_str.replace('\n', "\\n");
write!(f, "\n{}", escaped_row_str)?;
}

View file

@ -1,4 +1,5 @@
use super::keyboard_input;
use super::resources::strings::PLATFORM_NAME;
use crate::editor::mvc::ed_view;
use crate::editor::mvc::ed_view::RenderedWgpu;
use crate::editor::resources::strings::{HELLO_WORLD, NOTHING_OPENED};
@ -17,7 +18,6 @@ use crate::graphics::{
primitives::text::{build_glyph_brush, example_code_glyph_rect, queue_text_draw, Text},
};
use crate::ui::text::caret_w_select::CaretPos;
use crate::ui::util::path_to_string;
use bumpalo::Bump;
use cgmath::Vector2;
use fs_extra::dir::{copy, ls, CopyOptions, DirEntryAttr, DirEntryValue};
@ -31,6 +31,7 @@ use roc_types::subs::VarStore;
use std::collections::HashSet;
use std::fs::{self, File};
use std::io::Write;
use std::path::PathBuf;
use std::{error::Error, io, path::Path};
use wgpu::{CommandEncoder, LoadOp, RenderPass, TextureView};
use wgpu_glyph::GlyphBrush;
@ -125,7 +126,7 @@ fn run_event_loop(project_dir_path_opt: Option<&Path>) -> Result<(), Box<dyn Err
let code_arena = Bump::new();
let (file_path_str, code_str) = read_main_roc_file(project_dir_path_opt);
println!("Loading file {}...", file_path_str);
println!("Loading file {:?}...", file_path_str);
let file_path = Path::new(&file_path_str);
@ -266,7 +267,6 @@ fn run_event_loop(project_dir_path_opt: Option<&Path>) -> Result<(), Box<dyn Err
} => {
keyboard_modifiers = modifiers;
}
Event::MainEventsCleared => window.request_redraw(),
Event::RedrawRequested { .. } => {
// Get a command encoder for the current frame
let mut encoder =
@ -467,9 +467,7 @@ fn begin_render_pass<'a>(
})
}
type PathStr = String;
fn read_main_roc_file(project_dir_path_opt: Option<&Path>) -> (PathStr, String) {
fn read_main_roc_file(project_dir_path_opt: Option<&Path>) -> (PathBuf, String) {
if let Some(project_dir_path) = project_dir_path_opt {
let mut ls_config = HashSet::new();
ls_config.insert(DirEntryAttr::FullName);
@ -478,64 +476,58 @@ fn read_main_roc_file(project_dir_path_opt: Option<&Path>) -> (PathStr, String)
.unwrap_or_else(|err| panic!("Failed to list items in project directory: {:?}", err))
.items;
let file_names = dir_items
.iter()
.map(|info_hash_map| {
info_hash_map
.values()
.map(|dir_entry_value| {
if let DirEntryValue::String(file_name) = dir_entry_value {
Some(file_name)
} else {
None
}
})
.flatten() // remove None
.collect::<Vec<&String>>()
})
.flatten();
let file_names = dir_items.iter().flat_map(|info_hash_map| {
info_hash_map
.values()
.filter_map(|dir_entry_value| {
if let DirEntryValue::String(file_name) = dir_entry_value {
Some(file_name)
} else {
None
}
})
.collect::<Vec<&String>>()
});
let roc_file_names: Vec<&String> = file_names
.filter(|file_name| file_name.contains(".roc"))
.collect();
let project_dir_path_str = path_to_string(project_dir_path);
if let Some(&roc_file_name) = roc_file_names.first() {
let full_roc_file_path_str = path_to_string(&project_dir_path.join(roc_file_name));
let file_as_str = std::fs::read_to_string(&Path::new(&full_roc_file_path_str))
.unwrap_or_else(|err| panic!("In the provided project {:?}, I found the roc file {}, but I failed to read it: {}", &project_dir_path_str, &full_roc_file_path_str, err));
let full_roc_file_path = project_dir_path.join(roc_file_name);
let file_as_str = std::fs::read_to_string(&Path::new(&full_roc_file_path))
.unwrap_or_else(|err| panic!("In the provided project {:?}, I found the roc file {:?}, but I failed to read it: {}", &project_dir_path, full_roc_file_path, err));
(full_roc_file_path_str, file_as_str)
(full_roc_file_path, file_as_str)
} else {
init_new_roc_project(&project_dir_path_str)
init_new_roc_project(project_dir_path)
}
} else {
init_new_roc_project("new-roc-project")
init_new_roc_project(Path::new("./new-roc-project"))
}
}
// returns path and content of app file
fn init_new_roc_project(project_dir_path_str: &str) -> (PathStr, String) {
let orig_platform_path = Path::new("./examples/hello-c/platform");
fn init_new_roc_project(project_dir_path: &Path) -> (PathBuf, String) {
let orig_platform_path = Path::new("./examples/hello-world").join(PLATFORM_NAME);
let project_dir_path = Path::new(project_dir_path_str);
let roc_file_path_str = vec![project_dir_path_str, "/UntitledApp.roc"].join("");
let roc_file_path = Path::new("./new-roc-project/UntitledApp.roc");
let project_platform_path_str = vec![project_dir_path_str, "/platform"].join("");
let project_platform_path = Path::new(&project_platform_path_str);
let project_platform_path = project_dir_path.join(PLATFORM_NAME);
if !project_dir_path.exists() {
fs::create_dir(project_dir_path).expect("Failed to create dir for roc project.");
}
copy_roc_platform_if_not_exists(orig_platform_path, project_platform_path, project_dir_path);
copy_roc_platform_if_not_exists(
&orig_platform_path,
&project_platform_path,
project_dir_path,
);
let code_str = create_roc_file_if_not_exists(project_dir_path, roc_file_path);
(roc_file_path_str, code_str)
(roc_file_path.to_path_buf(), code_str)
}
// returns contents of file

View file

@ -220,7 +220,9 @@ impl<'a> EdModule<'a> {
pub mod test_ed_model {
use crate::editor::ed_error::EdResult;
use crate::editor::mvc::ed_model;
use crate::editor::resources::strings::{nr_hello_world_lines, HELLO_WORLD, PLATFORM_STR};
use crate::editor::resources::strings::{
nr_hello_world_lines, HELLO_WORLD, PLATFORM_NAME, PLATFORM_STR,
};
use crate::ui::text::caret_w_select::test_caret_w_select::convert_dsl_to_selection;
use crate::ui::text::caret_w_select::test_caret_w_select::convert_selection_to_dsl;
use crate::ui::text::caret_w_select::CaretPos;
@ -307,7 +309,7 @@ pub mod test_ed_model {
let temp_dir = tempdir().expect("Failed to create temporary directory for test.");
let platform_dir = temp_dir.path().join("platform");
let platform_dir = temp_dir.path().join(PLATFORM_NAME);
fs::create_dir(platform_dir.clone()).expect("Failed to create platform directory");
let package_config_path = platform_dir.join("Package-Config.roc");
let mut package_config_file =

View file

@ -137,7 +137,7 @@ fn markup_to_wgpu_helper<'a>(
} => {
let highlight_color = map_get(&code_style.ed_theme.syntax_high_map, syn_high_style)?;
let full_content = markup_node.get_full_content().replace("\n", "\\n"); // any \n left here should be escaped so that it can be shown as \n
let full_content = markup_node.get_full_content().replace('\n', "\\n"); // any \n left here should be escaped so that it can be shown as \n
let glyph_text = glyph_brush::OwnedText::new(&full_content)
.with_color(colors::to_slice(*highlight_color))

View file

@ -17,7 +17,7 @@ For convenience and consistency, there is only one way to format roc.
pub const HELLO_WORLD: &str = r#"
app "test-app"
packages { pf: "platform" }
packages { pf: "c-platform" }
imports []
provides [ main ] to pf
@ -29,6 +29,8 @@ pub fn nr_hello_world_lines() -> usize {
HELLO_WORLD.matches('\n').count() - 1
}
pub const PLATFORM_NAME: &str = "c-platform";
pub const PLATFORM_STR: &str = r#"
platform "test-platform"
requires {} { main : Str }

View file

@ -187,7 +187,6 @@ fn run_event_loop(title: &str, root: RocElem) -> Result<(), Box<dyn Error>> {
} => {
keyboard_modifiers = modifiers;
}
Event::MainEventsCleared => window.request_redraw(),
Event::RedrawRequested { .. } => {
// Get a command cmd_encoder for the current frame
let mut cmd_encoder =

View file

@ -416,7 +416,7 @@ fn preprocess_impl(
})
.map(|(_, reloc)| reloc)
.filter(|reloc| matches!(reloc.kind(), RelocationKind::Elf(6)))
.map(|reloc| {
.filter_map(|reloc| {
for symbol in app_syms.iter() {
if reloc.target() == RelocationTarget::Symbol(symbol.index()) {
return Some((symbol.name().unwrap().to_string(), symbol.index().0));
@ -424,7 +424,6 @@ fn preprocess_impl(
}
None
})
.flatten()
.collect();
for sym in app_syms.iter() {

View file

@ -1823,11 +1823,11 @@ fn to_precord_report<'a>(
}
PRecord::IndentColon(_) => {
unreachable!("because `{ foo }` is a valid field; the colon is not required")
unreachable!("because `foo` is a valid field; the colon is not required")
}
PRecord::IndentOptional(_) => {
unreachable!("because `{ foo }` is a valid field; the question mark is not required")
unreachable!("because `foo` is a valid field; the question mark is not required")
}
PRecord::Space(error, pos) => to_space_report(alloc, lines, filename, &error, pos),
@ -2288,10 +2288,10 @@ fn to_trecord_report<'a>(
},
ETypeRecord::Colon(_) => {
unreachable!("because `{ foo }` is a valid field; the colon is not required")
unreachable!("because `foo` is a valid field; the colon is not required")
}
ETypeRecord::Optional(_) => {
unreachable!("because `{ foo }` is a valid field; the question mark is not required")
unreachable!("because `foo` is a valid field; the question mark is not required")
}
ETypeRecord::Type(tipe, pos) => to_type_report(alloc, lines, filename, tipe, pos),
@ -2371,11 +2371,11 @@ fn to_trecord_report<'a>(
}
ETypeRecord::IndentColon(_) => {
unreachable!("because `{ foo }` is a valid field; the colon is not required")
unreachable!("because `foo` is a valid field; the colon is not required")
}
ETypeRecord::IndentOptional(_) => {
unreachable!("because `{ foo }` is a valid field; the question mark is not required")
unreachable!("because `foo` is a valid field; the question mark is not required")
}
ETypeRecord::Space(error, pos) => to_space_report(alloc, lines, filename, &error, pos),

View file

@ -774,7 +774,7 @@ fn preprocess_op(
debug_assert_eq!(inputs.len(), 1);
let cont_binding = continuations_in_scope[continuation]
.ok_or_else(|| ErrorKind::ContinuationNotInScope(*continuation))?;
.ok_or(ErrorKind::ContinuationNotInScope(*continuation))?;
check_type(ctx.nc, tc, cont_binding.arg_type, input_types[0])?;
@ -1045,7 +1045,7 @@ fn preprocess_op(
let field_types = try_get_tuple_field_types(ctx.nc, tc, tuple_type)?;
let field_type = *field_types
.get(*field_idx as usize)
.ok_or_else(|| ErrorKind::TupleFieldOutOfRange(*field_idx))?;
.ok_or(ErrorKind::TupleFieldOutOfRange(*field_idx))?;
let value = graph_builder.add_op(
block,
ir::OpKind::GetTupleField {
@ -1068,7 +1068,7 @@ fn preprocess_op(
.collect();
let this_variant_type = *tc_variant_types
.get(*variant_idx as usize)
.ok_or_else(|| ErrorKind::UnionVariantOutOfRange(*variant_idx))?;
.ok_or(ErrorKind::UnionVariantOutOfRange(*variant_idx))?;
check_type(ctx.nc, tc, this_variant_type, input_types[0])?;
let union_type = tc.types.get_or_insert(TypeData::Union {
variants: tc_variant_types,
@ -1089,7 +1089,7 @@ fn preprocess_op(
let variant_types = try_get_union_variant_types(ctx.nc, tc, input_types[0])?;
let this_variant_type = *variant_types
.get(*variant_idx as usize)
.ok_or_else(|| ErrorKind::UnionVariantOutOfRange(*variant_idx))?;
.ok_or(ErrorKind::UnionVariantOutOfRange(*variant_idx))?;
let value = graph_builder.add_op(
block,
ir::OpKind::UnwrapUnion {