Merge pull request #1109 from ziglang/pass-by-non-copying-value
allow passing by non-copying value
This commit is contained in:
commit
751518787a
@ -2818,39 +2818,30 @@ fn foo() void { }
|
|||||||
{#code_end#}
|
{#code_end#}
|
||||||
{#header_open|Pass-by-value Parameters#}
|
{#header_open|Pass-by-value Parameters#}
|
||||||
<p>
|
<p>
|
||||||
In Zig, structs, unions, and enums with payloads cannot be passed by value
|
In Zig, structs, unions, and enums with payloads can be passed directly to a function:
|
||||||
to a function.
|
|
||||||
</p>
|
|
||||||
{#code_begin|test_err|not copyable; cannot pass by value#}
|
|
||||||
const Foo = struct {
|
|
||||||
x: i32,
|
|
||||||
};
|
|
||||||
|
|
||||||
fn bar(foo: Foo) void {}
|
|
||||||
|
|
||||||
test "pass aggregate type by value to function" {
|
|
||||||
bar(Foo {.x = 12,});
|
|
||||||
}
|
|
||||||
{#code_end#}
|
|
||||||
<p>
|
|
||||||
Instead, one must use <code>*const</code>. Zig allows implicitly casting something
|
|
||||||
to a const pointer to it:
|
|
||||||
</p>
|
</p>
|
||||||
{#code_begin|test#}
|
{#code_begin|test#}
|
||||||
const Foo = struct {
|
const Point = struct {
|
||||||
x: i32,
|
x: i32,
|
||||||
|
y: i32,
|
||||||
};
|
};
|
||||||
|
|
||||||
fn bar(foo: *const Foo) void {}
|
fn foo(point: Point) i32 {
|
||||||
|
return point.x + point.y;
|
||||||
|
}
|
||||||
|
|
||||||
test "implicitly cast to const pointer" {
|
const assert = @import("std").debug.assert;
|
||||||
bar(Foo {.x = 12,});
|
|
||||||
|
test "pass aggregate type by non-copy value to function" {
|
||||||
|
assert(foo(Point{ .x = 1, .y = 2 }) == 3);
|
||||||
}
|
}
|
||||||
{#code_end#}
|
{#code_end#}
|
||||||
<p>
|
<p>
|
||||||
However,
|
In this case, the value may be passed by reference, or by value, whichever way
|
||||||
the C ABI does allow passing structs and unions by value. So functions which
|
Zig decides will be faster.
|
||||||
use the C calling convention may pass structs and unions by value.
|
</p>
|
||||||
|
<p>
|
||||||
|
For extern functions, Zig follows the C ABI for passing structs and unions by value.
|
||||||
</p>
|
</p>
|
||||||
{#header_close#}
|
{#header_close#}
|
||||||
{#header_open|Function Reflection#}
|
{#header_open|Function Reflection#}
|
||||||
|
@ -1135,7 +1135,10 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
|
|||||||
gen_param_info->src_index = i;
|
gen_param_info->src_index = i;
|
||||||
gen_param_info->gen_index = SIZE_MAX;
|
gen_param_info->gen_index = SIZE_MAX;
|
||||||
|
|
||||||
type_ensure_zero_bits_known(g, type_entry);
|
ensure_complete_type(g, type_entry);
|
||||||
|
if (type_is_invalid(type_entry))
|
||||||
|
return g->builtin_types.entry_invalid;
|
||||||
|
|
||||||
if (type_has_bits(type_entry)) {
|
if (type_has_bits(type_entry)) {
|
||||||
TypeTableEntry *gen_type;
|
TypeTableEntry *gen_type;
|
||||||
if (handle_is_ptr(type_entry)) {
|
if (handle_is_ptr(type_entry)) {
|
||||||
@ -1546,12 +1549,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
|
|||||||
case TypeTableEntryIdUnion:
|
case TypeTableEntryIdUnion:
|
||||||
case TypeTableEntryIdFn:
|
case TypeTableEntryIdFn:
|
||||||
case TypeTableEntryIdPromise:
|
case TypeTableEntryIdPromise:
|
||||||
ensure_complete_type(g, type_entry);
|
|
||||||
if (calling_convention_allows_zig_types(fn_type_id.cc) && !type_is_copyable(g, type_entry)) {
|
|
||||||
add_node_error(g, param_node->data.param_decl.type,
|
|
||||||
buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
|
|
||||||
return g->builtin_types.entry_invalid;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
|
FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
|
||||||
|
@ -326,13 +326,6 @@ static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const cha
|
|||||||
return addLLVMAttr(arg_val, param_index + 1, attr_name);
|
return addLLVMAttr(arg_val, param_index + 1, attr_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void addLLVMCallsiteAttr(LLVMValueRef call_instr, unsigned param_index, const char *attr_name) {
|
|
||||||
unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
|
|
||||||
assert(kind_id != 0);
|
|
||||||
LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, 0);
|
|
||||||
LLVMAddCallSiteAttribute(call_instr, param_index + 1, llvm_attr);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_symbol_available(CodeGen *g, Buf *name) {
|
static bool is_symbol_available(CodeGen *g, Buf *name) {
|
||||||
return g->exported_symbol_names.maybe_get(name) == nullptr && g->external_prototypes.maybe_get(name) == nullptr;
|
return g->exported_symbol_names.maybe_get(name) == nullptr && g->external_prototypes.maybe_get(name) == nullptr;
|
||||||
}
|
}
|
||||||
@ -581,11 +574,6 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
|
|||||||
if (param_type->id == TypeTableEntryIdPointer) {
|
if (param_type->id == TypeTableEntryIdPointer) {
|
||||||
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
|
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
|
||||||
}
|
}
|
||||||
// Note: byval is disabled on windows due to an LLVM bug:
|
|
||||||
// https://github.com/ziglang/zig/issues/536
|
|
||||||
if (is_byval && g->zig_target.os != OsWindows) {
|
|
||||||
addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
|
uint32_t err_ret_trace_arg_index = get_err_ret_trace_arg_index(g, fn_table_entry);
|
||||||
@ -3114,15 +3102,6 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
|
|
||||||
FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
|
|
||||||
// Note: byval is disabled on windows due to an LLVM bug:
|
|
||||||
// https://github.com/ziglang/zig/issues/536
|
|
||||||
if (gen_info->is_byval && g->zig_target.os != OsWindows) {
|
|
||||||
addLLVMCallsiteAttr(result, (unsigned)gen_info->gen_index, "byval");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (instruction->is_async) {
|
if (instruction->is_async) {
|
||||||
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
|
LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
|
||||||
LLVMBuildStore(g->builder, result, payload_ptr);
|
LLVMBuildStore(g->builder, result, payload_ptr);
|
||||||
|
57
src/ir.cpp
57
src/ir.cpp
@ -10463,13 +10463,6 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
|
|||||||
zig_unreachable();
|
zig_unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static IrInstruction *ir_implicit_byval_const_ref_cast(IrAnalyze *ira, IrInstruction *inst) {
|
|
||||||
if (type_is_copyable(ira->codegen, inst->value.type))
|
|
||||||
return inst;
|
|
||||||
TypeTableEntry *const_ref_type = get_pointer_to_type(ira->codegen, inst->value.type, true);
|
|
||||||
return ir_implicit_cast(ira, inst, const_ref_type);
|
|
||||||
}
|
|
||||||
|
|
||||||
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
|
static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
|
||||||
TypeTableEntry *type_entry = ptr->value.type;
|
TypeTableEntry *type_entry = ptr->value.type;
|
||||||
if (type_is_invalid(type_entry)) {
|
if (type_is_invalid(type_entry)) {
|
||||||
@ -12283,7 +12276,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
|||||||
IrInstruction *casted_arg;
|
IrInstruction *casted_arg;
|
||||||
if (is_var_args) {
|
if (is_var_args) {
|
||||||
arg_part_of_generic_id = true;
|
arg_part_of_generic_id = true;
|
||||||
casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
|
casted_arg = arg;
|
||||||
} else {
|
} else {
|
||||||
if (param_decl_node->data.param_decl.var_token == nullptr) {
|
if (param_decl_node->data.param_decl.var_token == nullptr) {
|
||||||
AstNode *param_type_node = param_decl_node->data.param_decl.type;
|
AstNode *param_type_node = param_decl_node->data.param_decl.type;
|
||||||
@ -12296,7 +12289,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
|
|||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
arg_part_of_generic_id = true;
|
arg_part_of_generic_id = true;
|
||||||
casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
|
casted_arg = arg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -12515,9 +12508,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
|||||||
|
|
||||||
size_t next_proto_i = 0;
|
size_t next_proto_i = 0;
|
||||||
if (first_arg_ptr) {
|
if (first_arg_ptr) {
|
||||||
IrInstruction *first_arg;
|
|
||||||
assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
|
assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
|
||||||
if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
|
|
||||||
|
bool first_arg_known_bare = false;
|
||||||
|
if (fn_type_id->next_param_index >= 1) {
|
||||||
|
TypeTableEntry *param_type = fn_type_id->param_info[next_proto_i].type;
|
||||||
|
if (type_is_invalid(param_type))
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
first_arg_known_bare = param_type->id != TypeTableEntryIdPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrInstruction *first_arg;
|
||||||
|
if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
|
||||||
first_arg = first_arg_ptr;
|
first_arg = first_arg_ptr;
|
||||||
} else {
|
} else {
|
||||||
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
|
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
|
||||||
@ -12667,9 +12669,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
|||||||
size_t next_proto_i = 0;
|
size_t next_proto_i = 0;
|
||||||
|
|
||||||
if (first_arg_ptr) {
|
if (first_arg_ptr) {
|
||||||
IrInstruction *first_arg;
|
|
||||||
assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
|
assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
|
||||||
if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
|
|
||||||
|
bool first_arg_known_bare = false;
|
||||||
|
if (fn_type_id->next_param_index >= 1) {
|
||||||
|
TypeTableEntry *param_type = fn_type_id->param_info[next_proto_i].type;
|
||||||
|
if (type_is_invalid(param_type))
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
first_arg_known_bare = param_type->id != TypeTableEntryIdPointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
IrInstruction *first_arg;
|
||||||
|
if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
|
||||||
first_arg = first_arg_ptr;
|
first_arg = first_arg_ptr;
|
||||||
} else {
|
} else {
|
||||||
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
|
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
|
||||||
@ -12802,10 +12813,7 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
|||||||
return ira->codegen->builtin_types.entry_invalid;
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
}
|
}
|
||||||
if (inst_fn_type_id.async_allocator_type == nullptr) {
|
if (inst_fn_type_id.async_allocator_type == nullptr) {
|
||||||
IrInstruction *casted_inst = ir_implicit_byval_const_ref_cast(ira, uncasted_async_allocator_inst);
|
inst_fn_type_id.async_allocator_type = uncasted_async_allocator_inst->value.type;
|
||||||
if (type_is_invalid(casted_inst->value.type))
|
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
|
||||||
inst_fn_type_id.async_allocator_type = casted_inst->value.type;
|
|
||||||
}
|
}
|
||||||
async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, inst_fn_type_id.async_allocator_type);
|
async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, inst_fn_type_id.async_allocator_type);
|
||||||
if (type_is_invalid(async_allocator_inst->value.type))
|
if (type_is_invalid(async_allocator_inst->value.type))
|
||||||
@ -12866,9 +12874,16 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
|||||||
IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
|
IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
|
||||||
size_t next_arg_index = 0;
|
size_t next_arg_index = 0;
|
||||||
if (first_arg_ptr) {
|
if (first_arg_ptr) {
|
||||||
IrInstruction *first_arg;
|
|
||||||
assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
|
assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
|
||||||
if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
|
|
||||||
|
TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
|
||||||
|
if (type_is_invalid(param_type))
|
||||||
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
|
||||||
|
IrInstruction *first_arg;
|
||||||
|
if (param_type->id == TypeTableEntryIdPointer &&
|
||||||
|
handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type))
|
||||||
|
{
|
||||||
first_arg = first_arg_ptr;
|
first_arg = first_arg_ptr;
|
||||||
} else {
|
} else {
|
||||||
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
|
first_arg = ir_get_deref(ira, first_arg_ptr, first_arg_ptr);
|
||||||
@ -12876,10 +12891,6 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
|
|||||||
return ira->codegen->builtin_types.entry_invalid;
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
}
|
}
|
||||||
|
|
||||||
TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
|
|
||||||
if (type_is_invalid(param_type))
|
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
|
||||||
|
|
||||||
IrInstruction *casted_arg = ir_implicit_cast(ira, first_arg, param_type);
|
IrInstruction *casted_arg = ir_implicit_cast(ira, first_arg, param_type);
|
||||||
if (type_is_invalid(casted_arg->value.type))
|
if (type_is_invalid(casted_arg->value.type))
|
||||||
return ira->codegen->builtin_types.entry_invalid;
|
return ira->codegen->builtin_types.entry_invalid;
|
||||||
|
@ -29,36 +29,36 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *const Self) void {
|
pub fn deinit(self: Self) void {
|
||||||
self.allocator.free(self.items);
|
self.allocator.free(self.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toSlice(self: *const Self) []align(A) T {
|
pub fn toSlice(self: Self) []align(A) T {
|
||||||
return self.items[0..self.len];
|
return self.items[0..self.len];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toSliceConst(self: *const Self) []align(A) const T {
|
pub fn toSliceConst(self: Self) []align(A) const T {
|
||||||
return self.items[0..self.len];
|
return self.items[0..self.len];
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn at(self: *const Self, n: usize) T {
|
pub fn at(self: Self, n: usize) T {
|
||||||
return self.toSliceConst()[n];
|
return self.toSliceConst()[n];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value at index `i`, or returns `error.OutOfBounds` if
|
/// Sets the value at index `i`, or returns `error.OutOfBounds` if
|
||||||
/// the index is not in range.
|
/// the index is not in range.
|
||||||
pub fn setOrError(self: *const Self, i: usize, item: *const T) !void {
|
pub fn setOrError(self: Self, i: usize, item: T) !void {
|
||||||
if (i >= self.len) return error.OutOfBounds;
|
if (i >= self.len) return error.OutOfBounds;
|
||||||
self.items[i] = item.*;
|
self.items[i] = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets the value at index `i`, asserting that the value is in range.
|
/// Sets the value at index `i`, asserting that the value is in range.
|
||||||
pub fn set(self: *const Self, i: usize, item: *const T) void {
|
pub fn set(self: *Self, i: usize, item: T) void {
|
||||||
assert(i < self.len);
|
assert(i < self.len);
|
||||||
self.items[i] = item.*;
|
self.items[i] = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn count(self: *const Self) usize {
|
pub fn count(self: Self) usize {
|
||||||
return self.len;
|
return self.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,12 +81,12 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert(self: *Self, n: usize, item: *const T) !void {
|
pub fn insert(self: *Self, n: usize, item: T) !void {
|
||||||
try self.ensureCapacity(self.len + 1);
|
try self.ensureCapacity(self.len + 1);
|
||||||
self.len += 1;
|
self.len += 1;
|
||||||
|
|
||||||
mem.copy(T, self.items[n + 1 .. self.len], self.items[n .. self.len - 1]);
|
mem.copy(T, self.items[n + 1 .. self.len], self.items[n .. self.len - 1]);
|
||||||
self.items[n] = item.*;
|
self.items[n] = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insertSlice(self: *Self, n: usize, items: []align(A) const T) !void {
|
pub fn insertSlice(self: *Self, n: usize, items: []align(A) const T) !void {
|
||||||
@ -97,9 +97,9 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
|
|||||||
mem.copy(T, self.items[n .. n + items.len], items);
|
mem.copy(T, self.items[n .. n + items.len], items);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn append(self: *Self, item: *const T) !void {
|
pub fn append(self: *Self, item: T) !void {
|
||||||
const new_item_ptr = try self.addOne();
|
const new_item_ptr = try self.addOne();
|
||||||
new_item_ptr.* = item.*;
|
new_item_ptr.* = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn appendSlice(self: *Self, items: []align(A) const T) !void {
|
pub fn appendSlice(self: *Self, items: []align(A) const T) !void {
|
||||||
|
@ -234,7 +234,7 @@ pub const Builder = struct {
|
|||||||
defer wanted_steps.deinit();
|
defer wanted_steps.deinit();
|
||||||
|
|
||||||
if (step_names.len == 0) {
|
if (step_names.len == 0) {
|
||||||
try wanted_steps.append(&self.default_step);
|
try wanted_steps.append(self.default_step);
|
||||||
} else {
|
} else {
|
||||||
for (step_names) |step_name| {
|
for (step_names) |step_name| {
|
||||||
const s = try self.getTopLevelStepByName(step_name);
|
const s = try self.getTopLevelStepByName(step_name);
|
||||||
|
@ -162,8 +162,6 @@ pub fn formatType(
|
|||||||
},
|
},
|
||||||
builtin.TypeInfo.Pointer.Size.Many => {
|
builtin.TypeInfo.Pointer.Size.Many => {
|
||||||
if (ptr_info.child == u8) {
|
if (ptr_info.child == u8) {
|
||||||
//This is a bit of a hack, but it made more sense to
|
|
||||||
// do this check here than have formatText do it
|
|
||||||
if (fmt[0] == 's') {
|
if (fmt[0] == 's') {
|
||||||
const len = std.cstr.len(value);
|
const len = std.cstr.len(value);
|
||||||
return formatText(value[0..len], fmt, context, Errors, output);
|
return formatText(value[0..len], fmt, context, Errors, output);
|
||||||
@ -176,6 +174,12 @@ pub fn formatType(
|
|||||||
return output(context, casted_value);
|
return output(context, casted_value);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
builtin.TypeId.Array => |info| {
|
||||||
|
if (info.child == u8) {
|
||||||
|
return formatText(value, fmt, context, Errors, output);
|
||||||
|
}
|
||||||
|
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
|
||||||
|
},
|
||||||
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
|
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1326,7 +1326,7 @@ pub const Parser = struct {
|
|||||||
},
|
},
|
||||||
// Array Parent -> [ ..., <array>, value ]
|
// Array Parent -> [ ..., <array>, value ]
|
||||||
Value.Array => |*array| {
|
Value.Array => |*array| {
|
||||||
try array.append(value);
|
try array.append(value.*);
|
||||||
p.state = State.ArrayValue;
|
p.state = State.ArrayValue;
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
|
@ -18,39 +18,6 @@ comptime {
|
|||||||
debug.assert(Limb.is_signed == false);
|
debug.assert(Limb.is_signed == false);
|
||||||
}
|
}
|
||||||
|
|
||||||
const wrapped_buffer_size = 512;
|
|
||||||
|
|
||||||
// Converts primitive integer values onto a stack-based big integer, or passes through existing
|
|
||||||
// Int types with no modifications. This can fail at runtime if using a very large dynamic
|
|
||||||
// integer but it is very unlikely and is considered a user error.
|
|
||||||
fn wrapInt(allocator: *Allocator, bn: var) *const Int {
|
|
||||||
const T = @typeOf(bn);
|
|
||||||
switch (@typeInfo(T)) {
|
|
||||||
TypeId.Pointer => |info| {
|
|
||||||
if (info.child == Int) {
|
|
||||||
return bn;
|
|
||||||
} else {
|
|
||||||
@compileError("cannot set Int using type " ++ @typeName(T));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
else => {
|
|
||||||
var s = allocator.create(Int) catch unreachable;
|
|
||||||
s.* = Int{
|
|
||||||
.allocator = allocator,
|
|
||||||
.positive = false,
|
|
||||||
.limbs = block: {
|
|
||||||
var limbs = allocator.alloc(Limb, Int.default_capacity) catch unreachable;
|
|
||||||
limbs[0] = 0;
|
|
||||||
break :block limbs;
|
|
||||||
},
|
|
||||||
.len = 1,
|
|
||||||
};
|
|
||||||
s.set(bn) catch unreachable;
|
|
||||||
return s;
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub const Int = struct {
|
pub const Int = struct {
|
||||||
allocator: *Allocator,
|
allocator: *Allocator,
|
||||||
positive: bool,
|
positive: bool,
|
||||||
@ -93,11 +60,11 @@ pub const Int = struct {
|
|||||||
self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);
|
self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *const Int) void {
|
pub fn deinit(self: Int) void {
|
||||||
self.allocator.free(self.limbs);
|
self.allocator.free(self.limbs);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone(other: *const Int) !Int {
|
pub fn clone(other: Int) !Int {
|
||||||
return Int{
|
return Int{
|
||||||
.allocator = other.allocator,
|
.allocator = other.allocator,
|
||||||
.positive = other.positive,
|
.positive = other.positive,
|
||||||
@ -110,8 +77,8 @@ pub const Int = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn copy(self: *Int, other: *const Int) !void {
|
pub fn copy(self: *Int, other: Int) !void {
|
||||||
if (self == other) {
|
if (self == &other) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,7 +92,7 @@ pub const Int = struct {
|
|||||||
mem.swap(Int, self, other);
|
mem.swap(Int, self, other);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump(self: *const Int) void {
|
pub fn dump(self: Int) void {
|
||||||
for (self.limbs) |limb| {
|
for (self.limbs) |limb| {
|
||||||
debug.warn("{x} ", limb);
|
debug.warn("{x} ", limb);
|
||||||
}
|
}
|
||||||
@ -140,20 +107,20 @@ pub const Int = struct {
|
|||||||
r.positive = true;
|
r.positive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isOdd(r: *const Int) bool {
|
pub fn isOdd(r: Int) bool {
|
||||||
return r.limbs[0] & 1 != 0;
|
return r.limbs[0] & 1 != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isEven(r: *const Int) bool {
|
pub fn isEven(r: Int) bool {
|
||||||
return !r.isOdd();
|
return !r.isOdd();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bitcount(self: *const Int) usize {
|
fn bitcount(self: Int) usize {
|
||||||
const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
|
const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
|
||||||
return usize(!self.positive) + u_bit_count;
|
return usize(!self.positive) + u_bit_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sizeInBase(self: *const Int, base: usize) usize {
|
pub fn sizeInBase(self: Int, base: usize) usize {
|
||||||
return (self.bitcount() / math.log2(base)) + 1;
|
return (self.bitcount() / math.log2(base)) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,7 +186,7 @@ pub const Int = struct {
|
|||||||
TargetTooSmall,
|
TargetTooSmall,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn to(self: *const Int, comptime T: type) ConvertError!T {
|
pub fn to(self: Int, comptime T: type) ConvertError!T {
|
||||||
switch (@typeId(T)) {
|
switch (@typeId(T)) {
|
||||||
TypeId.Int => {
|
TypeId.Int => {
|
||||||
const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T;
|
const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T;
|
||||||
@ -286,16 +253,28 @@ pub const Int = struct {
|
|||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO values less than limb size should guarantee non allocating
|
||||||
|
var base_buffer: [512]u8 = undefined;
|
||||||
|
const base_al = &std.heap.FixedBufferAllocator.init(base_buffer[0..]).allocator;
|
||||||
|
const base_ap = try Int.initSet(base_al, base);
|
||||||
|
|
||||||
|
var d_buffer: [512]u8 = undefined;
|
||||||
|
var d_fba = std.heap.FixedBufferAllocator.init(d_buffer[0..]);
|
||||||
|
const d_al = &d_fba.allocator;
|
||||||
|
|
||||||
try self.set(0);
|
try self.set(0);
|
||||||
for (value[i..]) |ch| {
|
for (value[i..]) |ch| {
|
||||||
const d = try charToDigit(ch, base);
|
const d = try charToDigit(ch, base);
|
||||||
try self.mul(self, base);
|
d_fba.end_index = 0;
|
||||||
try self.add(self, d);
|
const d_ap = try Int.initSet(d_al, d);
|
||||||
|
|
||||||
|
try self.mul(self.*, base_ap);
|
||||||
|
try self.add(self.*, d_ap);
|
||||||
}
|
}
|
||||||
self.positive = positive;
|
self.positive = positive;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn toString(self: *const Int, allocator: *Allocator, base: u8) ![]const u8 {
|
pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 {
|
||||||
if (base < 2 or base > 16) {
|
if (base < 2 or base > 16) {
|
||||||
return error.InvalidBase;
|
return error.InvalidBase;
|
||||||
}
|
}
|
||||||
@ -345,7 +324,7 @@ pub const Int = struct {
|
|||||||
var b = try Int.initSet(allocator, limb_base);
|
var b = try Int.initSet(allocator, limb_base);
|
||||||
|
|
||||||
while (q.len >= 2) {
|
while (q.len >= 2) {
|
||||||
try Int.divTrunc(&q, &r, &q, &b);
|
try Int.divTrunc(&q, &r, q, b);
|
||||||
|
|
||||||
var r_word = r.limbs[0];
|
var r_word = r.limbs[0];
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
@ -378,12 +357,7 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
|
// returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
|
||||||
pub fn cmpAbs(a: *const Int, bv: var) i8 {
|
pub fn cmpAbs(a: Int, b: Int) i8 {
|
||||||
// TODO: Thread-local buffer.
|
|
||||||
var buffer: [wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var b = wrapInt(&stack.allocator, bv);
|
|
||||||
|
|
||||||
if (a.len < b.len) {
|
if (a.len < b.len) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -408,11 +382,7 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// returns -1, 0, 1 if a < b, a == b or a > b respectively.
|
// returns -1, 0, 1 if a < b, a == b or a > b respectively.
|
||||||
pub fn cmp(a: *const Int, bv: var) i8 {
|
pub fn cmp(a: Int, b: Int) i8 {
|
||||||
var buffer: [wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var b = wrapInt(&stack.allocator, bv);
|
|
||||||
|
|
||||||
if (a.positive != b.positive) {
|
if (a.positive != b.positive) {
|
||||||
return if (a.positive) i8(1) else -1;
|
return if (a.positive) i8(1) else -1;
|
||||||
} else {
|
} else {
|
||||||
@ -422,17 +392,17 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if a == 0
|
// if a == 0
|
||||||
pub fn eqZero(a: *const Int) bool {
|
pub fn eqZero(a: Int) bool {
|
||||||
return a.len == 1 and a.limbs[0] == 0;
|
return a.len == 1 and a.limbs[0] == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if |a| == |b|
|
// if |a| == |b|
|
||||||
pub fn eqAbs(a: *const Int, b: var) bool {
|
pub fn eqAbs(a: Int, b: Int) bool {
|
||||||
return cmpAbs(a, b) == 0;
|
return cmpAbs(a, b) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if a == b
|
// if a == b
|
||||||
pub fn eq(a: *const Int, b: var) bool {
|
pub fn eq(a: Int, b: Int) bool {
|
||||||
return cmp(a, b) == 0;
|
return cmp(a, b) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -473,12 +443,7 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// r = a + b
|
// r = a + b
|
||||||
pub fn add(r: *Int, av: var, bv: var) Allocator.Error!void {
|
pub fn add(r: *Int, a: Int, b: Int) Allocator.Error!void {
|
||||||
var buffer: [2 * wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var a = wrapInt(&stack.allocator, av);
|
|
||||||
var b = wrapInt(&stack.allocator, bv);
|
|
||||||
|
|
||||||
if (a.eqZero()) {
|
if (a.eqZero()) {
|
||||||
try r.copy(b);
|
try r.copy(b);
|
||||||
return;
|
return;
|
||||||
@ -547,12 +512,7 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// r = a - b
|
// r = a - b
|
||||||
pub fn sub(r: *Int, av: var, bv: var) !void {
|
pub fn sub(r: *Int, a: Int, b: Int) !void {
|
||||||
var buffer: [wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var a = wrapInt(&stack.allocator, av);
|
|
||||||
var b = wrapInt(&stack.allocator, bv);
|
|
||||||
|
|
||||||
if (a.positive != b.positive) {
|
if (a.positive != b.positive) {
|
||||||
if (a.positive) {
|
if (a.positive) {
|
||||||
// (a) - (-b) => a + b
|
// (a) - (-b) => a + b
|
||||||
@ -632,14 +592,9 @@ pub const Int = struct {
|
|||||||
// rma = a * b
|
// rma = a * b
|
||||||
//
|
//
|
||||||
// For greatest efficiency, ensure rma does not alias a or b.
|
// For greatest efficiency, ensure rma does not alias a or b.
|
||||||
pub fn mul(rma: *Int, av: var, bv: var) !void {
|
pub fn mul(rma: *Int, a: Int, b: Int) !void {
|
||||||
var buffer: [2 * wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var a = wrapInt(&stack.allocator, av);
|
|
||||||
var b = wrapInt(&stack.allocator, bv);
|
|
||||||
|
|
||||||
var r = rma;
|
var r = rma;
|
||||||
var aliased = rma == a or rma == b;
|
var aliased = rma.limbs.ptr == a.limbs.ptr or rma.limbs.ptr == b.limbs.ptr;
|
||||||
|
|
||||||
var sr: Int = undefined;
|
var sr: Int = undefined;
|
||||||
if (aliased) {
|
if (aliased) {
|
||||||
@ -714,29 +669,29 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn divFloor(q: *Int, r: *Int, a: var, b: var) !void {
|
pub fn divFloor(q: *Int, r: *Int, a: Int, b: Int) !void {
|
||||||
try div(q, r, a, b);
|
try div(q, r, a, b);
|
||||||
|
|
||||||
// Trunc -> Floor.
|
// Trunc -> Floor.
|
||||||
if (!q.positive) {
|
if (!q.positive) {
|
||||||
try q.sub(q, 1);
|
// TODO values less than limb size should guarantee non allocating
|
||||||
try r.add(q, 1);
|
var one_buffer: [512]u8 = undefined;
|
||||||
|
const one_al = &std.heap.FixedBufferAllocator.init(one_buffer[0..]).allocator;
|
||||||
|
const one_ap = try Int.initSet(one_al, 1);
|
||||||
|
|
||||||
|
try q.sub(q.*, one_ap);
|
||||||
|
try r.add(q.*, one_ap);
|
||||||
}
|
}
|
||||||
r.positive = b.positive;
|
r.positive = b.positive;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn divTrunc(q: *Int, r: *Int, a: var, b: var) !void {
|
pub fn divTrunc(q: *Int, r: *Int, a: Int, b: Int) !void {
|
||||||
try div(q, r, a, b);
|
try div(q, r, a, b);
|
||||||
r.positive = a.positive;
|
r.positive = a.positive;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Truncates by default.
|
// Truncates by default.
|
||||||
fn div(quo: *Int, rem: *Int, av: var, bv: var) !void {
|
fn div(quo: *Int, rem: *Int, a: Int, b: Int) !void {
|
||||||
var buffer: [2 * wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var a = wrapInt(&stack.allocator, av);
|
|
||||||
var b = wrapInt(&stack.allocator, bv);
|
|
||||||
|
|
||||||
if (b.eqZero()) {
|
if (b.eqZero()) {
|
||||||
@panic("division by zero");
|
@panic("division by zero");
|
||||||
}
|
}
|
||||||
@ -821,8 +776,8 @@ pub const Int = struct {
|
|||||||
|
|
||||||
// Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set)
|
// Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set)
|
||||||
const norm_shift = @clz(y.limbs[y.len - 1]);
|
const norm_shift = @clz(y.limbs[y.len - 1]);
|
||||||
try x.shiftLeft(x, norm_shift);
|
try x.shiftLeft(x.*, norm_shift);
|
||||||
try y.shiftLeft(y, norm_shift);
|
try y.shiftLeft(y.*, norm_shift);
|
||||||
|
|
||||||
const n = x.len - 1;
|
const n = x.len - 1;
|
||||||
const t = y.len - 1;
|
const t = y.len - 1;
|
||||||
@ -832,10 +787,10 @@ pub const Int = struct {
|
|||||||
mem.set(Limb, q.limbs[0..q.len], 0);
|
mem.set(Limb, q.limbs[0..q.len], 0);
|
||||||
|
|
||||||
// 2.
|
// 2.
|
||||||
try tmp.shiftLeft(y, Limb.bit_count * (n - t));
|
try tmp.shiftLeft(y.*, Limb.bit_count * (n - t));
|
||||||
while (x.cmp(&tmp) >= 0) {
|
while (x.cmp(tmp) >= 0) {
|
||||||
q.limbs[n - t] += 1;
|
q.limbs[n - t] += 1;
|
||||||
try x.sub(x, tmp);
|
try x.sub(x.*, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3.
|
// 3.
|
||||||
@ -864,7 +819,7 @@ pub const Int = struct {
|
|||||||
r.limbs[2] = carry;
|
r.limbs[2] = carry;
|
||||||
r.normN(3);
|
r.normN(3);
|
||||||
|
|
||||||
if (r.cmpAbs(&tmp) <= 0) {
|
if (r.cmpAbs(tmp) <= 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -873,13 +828,13 @@ pub const Int = struct {
|
|||||||
|
|
||||||
// 3.3
|
// 3.3
|
||||||
try tmp.set(q.limbs[i - t - 1]);
|
try tmp.set(q.limbs[i - t - 1]);
|
||||||
try tmp.mul(&tmp, y);
|
try tmp.mul(tmp, y.*);
|
||||||
try tmp.shiftLeft(&tmp, Limb.bit_count * (i - t - 1));
|
try tmp.shiftLeft(tmp, Limb.bit_count * (i - t - 1));
|
||||||
try x.sub(x, &tmp);
|
try x.sub(x.*, tmp);
|
||||||
|
|
||||||
if (!x.positive) {
|
if (!x.positive) {
|
||||||
try tmp.shiftLeft(y, Limb.bit_count * (i - t - 1));
|
try tmp.shiftLeft(y.*, Limb.bit_count * (i - t - 1));
|
||||||
try x.add(x, &tmp);
|
try x.add(x.*, tmp);
|
||||||
q.limbs[i - t - 1] -= 1;
|
q.limbs[i - t - 1] -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -887,16 +842,12 @@ pub const Int = struct {
|
|||||||
// Denormalize
|
// Denormalize
|
||||||
q.normN(q.len);
|
q.normN(q.len);
|
||||||
|
|
||||||
try r.shiftRight(x, norm_shift);
|
try r.shiftRight(x.*, norm_shift);
|
||||||
r.normN(r.len);
|
r.normN(r.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
// r = a << shift, in other words, r = a * 2^shift
|
// r = a << shift, in other words, r = a * 2^shift
|
||||||
pub fn shiftLeft(r: *Int, av: var, shift: usize) !void {
|
pub fn shiftLeft(r: *Int, a: Int, shift: usize) !void {
|
||||||
var buffer: [wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var a = wrapInt(&stack.allocator, av);
|
|
||||||
|
|
||||||
try r.ensureCapacity(a.len + (shift / Limb.bit_count) + 1);
|
try r.ensureCapacity(a.len + (shift / Limb.bit_count) + 1);
|
||||||
llshl(r.limbs[0..], a.limbs[0..a.len], shift);
|
llshl(r.limbs[0..], a.limbs[0..a.len], shift);
|
||||||
r.norm1(a.len + (shift / Limb.bit_count) + 1);
|
r.norm1(a.len + (shift / Limb.bit_count) + 1);
|
||||||
@ -927,11 +878,7 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// r = a >> shift
|
// r = a >> shift
|
||||||
pub fn shiftRight(r: *Int, av: var, shift: usize) !void {
|
pub fn shiftRight(r: *Int, a: Int, shift: usize) !void {
|
||||||
var buffer: [wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var a = wrapInt(&stack.allocator, av);
|
|
||||||
|
|
||||||
if (a.len <= shift / Limb.bit_count) {
|
if (a.len <= shift / Limb.bit_count) {
|
||||||
r.len = 1;
|
r.len = 1;
|
||||||
r.limbs[0] = 0;
|
r.limbs[0] = 0;
|
||||||
@ -966,12 +913,7 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// r = a | b
|
// r = a | b
|
||||||
pub fn bitOr(r: *Int, av: var, bv: var) !void {
|
pub fn bitOr(r: *Int, a: Int, b: Int) !void {
|
||||||
var buffer: [2 * wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var a = wrapInt(&stack.allocator, av);
|
|
||||||
var b = wrapInt(&stack.allocator, bv);
|
|
||||||
|
|
||||||
if (a.len > b.len) {
|
if (a.len > b.len) {
|
||||||
try r.ensureCapacity(a.len);
|
try r.ensureCapacity(a.len);
|
||||||
llor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
|
llor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
|
||||||
@ -998,12 +940,7 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// r = a & b
|
// r = a & b
|
||||||
pub fn bitAnd(r: *Int, av: var, bv: var) !void {
|
pub fn bitAnd(r: *Int, a: Int, b: Int) !void {
|
||||||
var buffer: [2 * wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var a = wrapInt(&stack.allocator, av);
|
|
||||||
var b = wrapInt(&stack.allocator, bv);
|
|
||||||
|
|
||||||
if (a.len > b.len) {
|
if (a.len > b.len) {
|
||||||
try r.ensureCapacity(b.len);
|
try r.ensureCapacity(b.len);
|
||||||
lland(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
|
lland(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
|
||||||
@ -1027,12 +964,7 @@ pub const Int = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// r = a ^ b
|
// r = a ^ b
|
||||||
pub fn bitXor(r: *Int, av: var, bv: var) !void {
|
pub fn bitXor(r: *Int, a: Int, b: Int) !void {
|
||||||
var buffer: [2 * wrapped_buffer_size]u8 = undefined;
|
|
||||||
var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
|
|
||||||
var a = wrapInt(&stack.allocator, av);
|
|
||||||
var b = wrapInt(&stack.allocator, bv);
|
|
||||||
|
|
||||||
if (a.len > b.len) {
|
if (a.len > b.len) {
|
||||||
try r.ensureCapacity(a.len);
|
try r.ensureCapacity(a.len);
|
||||||
llxor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
|
llxor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
|
||||||
@ -1065,7 +997,7 @@ pub const Int = struct {
|
|||||||
// may be untested in some cases.
|
// may be untested in some cases.
|
||||||
|
|
||||||
const u256 = @IntType(false, 256);
|
const u256 = @IntType(false, 256);
|
||||||
var al = debug.global_allocator;
|
const al = debug.global_allocator;
|
||||||
|
|
||||||
test "big.int comptime_int set" {
|
test "big.int comptime_int set" {
|
||||||
comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab;
|
comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab;
|
||||||
@ -1198,7 +1130,7 @@ test "big.int bitcount + sizeInBase" {
|
|||||||
debug.assert(a.sizeInBase(2) >= 32);
|
debug.assert(a.sizeInBase(2) >= 32);
|
||||||
debug.assert(a.sizeInBase(10) >= 10);
|
debug.assert(a.sizeInBase(10) >= 10);
|
||||||
|
|
||||||
try a.shiftLeft(&a, 5000);
|
try a.shiftLeft(a, 5000);
|
||||||
debug.assert(a.bitcount() == 5032);
|
debug.assert(a.bitcount() == 5032);
|
||||||
debug.assert(a.sizeInBase(2) >= 5032);
|
debug.assert(a.sizeInBase(2) >= 5032);
|
||||||
a.positive = false;
|
a.positive = false;
|
||||||
@ -1320,40 +1252,40 @@ test "big.int compare" {
|
|||||||
var a = try Int.initSet(al, -11);
|
var a = try Int.initSet(al, -11);
|
||||||
var b = try Int.initSet(al, 10);
|
var b = try Int.initSet(al, 10);
|
||||||
|
|
||||||
debug.assert(a.cmpAbs(&b) == 1);
|
debug.assert(a.cmpAbs(b) == 1);
|
||||||
debug.assert(a.cmp(&b) == -1);
|
debug.assert(a.cmp(b) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "big.int compare similar" {
|
test "big.int compare similar" {
|
||||||
var a = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeee);
|
var a = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeee);
|
||||||
var b = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeef);
|
var b = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeef);
|
||||||
|
|
||||||
debug.assert(a.cmpAbs(&b) == -1);
|
debug.assert(a.cmpAbs(b) == -1);
|
||||||
debug.assert(b.cmpAbs(&a) == 1);
|
debug.assert(b.cmpAbs(a) == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "big.int compare different limb size" {
|
test "big.int compare different limb size" {
|
||||||
var a = try Int.initSet(al, @maxValue(Limb) + 1);
|
var a = try Int.initSet(al, @maxValue(Limb) + 1);
|
||||||
var b = try Int.initSet(al, 1);
|
var b = try Int.initSet(al, 1);
|
||||||
|
|
||||||
debug.assert(a.cmpAbs(&b) == 1);
|
debug.assert(a.cmpAbs(b) == 1);
|
||||||
debug.assert(b.cmpAbs(&a) == -1);
|
debug.assert(b.cmpAbs(a) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "big.int compare multi-limb" {
|
test "big.int compare multi-limb" {
|
||||||
var a = try Int.initSet(al, -0x7777777799999999ffffeeeeffffeeeeffffeeeef);
|
var a = try Int.initSet(al, -0x7777777799999999ffffeeeeffffeeeeffffeeeef);
|
||||||
var b = try Int.initSet(al, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
|
var b = try Int.initSet(al, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
|
||||||
|
|
||||||
debug.assert(a.cmpAbs(&b) == 1);
|
debug.assert(a.cmpAbs(b) == 1);
|
||||||
debug.assert(a.cmp(&b) == -1);
|
debug.assert(a.cmp(b) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "big.int equality" {
|
test "big.int equality" {
|
||||||
var a = try Int.initSet(al, 0xffffffff1);
|
var a = try Int.initSet(al, 0xffffffff1);
|
||||||
var b = try Int.initSet(al, -0xffffffff1);
|
var b = try Int.initSet(al, -0xffffffff1);
|
||||||
|
|
||||||
debug.assert(a.eqAbs(&b));
|
debug.assert(a.eqAbs(b));
|
||||||
debug.assert(!a.eq(&b));
|
debug.assert(!a.eq(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "big.int abs" {
|
test "big.int abs" {
|
||||||
@ -1381,7 +1313,7 @@ test "big.int add single-single" {
|
|||||||
var b = try Int.initSet(al, 5);
|
var b = try Int.initSet(al, 5);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.add(&a, &b);
|
try c.add(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u32)) == 55);
|
debug.assert((try c.to(u32)) == 55);
|
||||||
}
|
}
|
||||||
@ -1392,10 +1324,10 @@ test "big.int add multi-single" {
|
|||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
|
|
||||||
try c.add(&a, &b);
|
try c.add(a, b);
|
||||||
debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
|
debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
|
||||||
|
|
||||||
try c.add(&b, &a);
|
try c.add(b, a);
|
||||||
debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
|
debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1406,7 +1338,7 @@ test "big.int add multi-multi" {
|
|||||||
var b = try Int.initSet(al, op2);
|
var b = try Int.initSet(al, op2);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.add(&a, &b);
|
try c.add(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u128)) == op1 + op2);
|
debug.assert((try c.to(u128)) == op1 + op2);
|
||||||
}
|
}
|
||||||
@ -1416,7 +1348,7 @@ test "big.int add zero-zero" {
|
|||||||
var b = try Int.initSet(al, 0);
|
var b = try Int.initSet(al, 0);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.add(&a, &b);
|
try c.add(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u32)) == 0);
|
debug.assert((try c.to(u32)) == 0);
|
||||||
}
|
}
|
||||||
@ -1426,7 +1358,7 @@ test "big.int add alias multi-limb nonzero-zero" {
|
|||||||
var a = try Int.initSet(al, op1);
|
var a = try Int.initSet(al, op1);
|
||||||
var b = try Int.initSet(al, 0);
|
var b = try Int.initSet(al, 0);
|
||||||
|
|
||||||
try a.add(&a, &b);
|
try a.add(a, b);
|
||||||
|
|
||||||
debug.assert((try a.to(u128)) == op1);
|
debug.assert((try a.to(u128)) == op1);
|
||||||
}
|
}
|
||||||
@ -1434,16 +1366,21 @@ test "big.int add alias multi-limb nonzero-zero" {
|
|||||||
test "big.int add sign" {
|
test "big.int add sign" {
|
||||||
var a = try Int.init(al);
|
var a = try Int.init(al);
|
||||||
|
|
||||||
try a.add(1, 2);
|
const one = try Int.initSet(al, 1);
|
||||||
|
const two = try Int.initSet(al, 2);
|
||||||
|
const neg_one = try Int.initSet(al, -1);
|
||||||
|
const neg_two = try Int.initSet(al, -2);
|
||||||
|
|
||||||
|
try a.add(one, two);
|
||||||
debug.assert((try a.to(i32)) == 3);
|
debug.assert((try a.to(i32)) == 3);
|
||||||
|
|
||||||
try a.add(-1, 2);
|
try a.add(neg_one, two);
|
||||||
debug.assert((try a.to(i32)) == 1);
|
debug.assert((try a.to(i32)) == 1);
|
||||||
|
|
||||||
try a.add(1, -2);
|
try a.add(one, neg_two);
|
||||||
debug.assert((try a.to(i32)) == -1);
|
debug.assert((try a.to(i32)) == -1);
|
||||||
|
|
||||||
try a.add(-1, -2);
|
try a.add(neg_one, neg_two);
|
||||||
debug.assert((try a.to(i32)) == -3);
|
debug.assert((try a.to(i32)) == -3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1452,7 +1389,7 @@ test "big.int sub single-single" {
|
|||||||
var b = try Int.initSet(al, 5);
|
var b = try Int.initSet(al, 5);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.sub(&a, &b);
|
try c.sub(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u32)) == 45);
|
debug.assert((try c.to(u32)) == 45);
|
||||||
}
|
}
|
||||||
@ -1462,7 +1399,7 @@ test "big.int sub multi-single" {
|
|||||||
var b = try Int.initSet(al, 1);
|
var b = try Int.initSet(al, 1);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.sub(&a, &b);
|
try c.sub(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(Limb)) == @maxValue(Limb));
|
debug.assert((try c.to(Limb)) == @maxValue(Limb));
|
||||||
}
|
}
|
||||||
@ -1475,7 +1412,7 @@ test "big.int sub multi-multi" {
|
|||||||
var b = try Int.initSet(al, op2);
|
var b = try Int.initSet(al, op2);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.sub(&a, &b);
|
try c.sub(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u128)) == op1 - op2);
|
debug.assert((try c.to(u128)) == op1 - op2);
|
||||||
}
|
}
|
||||||
@ -1485,7 +1422,7 @@ test "big.int sub equal" {
|
|||||||
var b = try Int.initSet(al, 0x11efefefefefefefefefefefef);
|
var b = try Int.initSet(al, 0x11efefefefefefefefefefefef);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.sub(&a, &b);
|
try c.sub(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u32)) == 0);
|
debug.assert((try c.to(u32)) == 0);
|
||||||
}
|
}
|
||||||
@ -1493,19 +1430,24 @@ test "big.int sub equal" {
|
|||||||
test "big.int sub sign" {
|
test "big.int sub sign" {
|
||||||
var a = try Int.init(al);
|
var a = try Int.init(al);
|
||||||
|
|
||||||
try a.sub(1, 2);
|
const one = try Int.initSet(al, 1);
|
||||||
|
const two = try Int.initSet(al, 2);
|
||||||
|
const neg_one = try Int.initSet(al, -1);
|
||||||
|
const neg_two = try Int.initSet(al, -2);
|
||||||
|
|
||||||
|
try a.sub(one, two);
|
||||||
debug.assert((try a.to(i32)) == -1);
|
debug.assert((try a.to(i32)) == -1);
|
||||||
|
|
||||||
try a.sub(-1, 2);
|
try a.sub(neg_one, two);
|
||||||
debug.assert((try a.to(i32)) == -3);
|
debug.assert((try a.to(i32)) == -3);
|
||||||
|
|
||||||
try a.sub(1, -2);
|
try a.sub(one, neg_two);
|
||||||
debug.assert((try a.to(i32)) == 3);
|
debug.assert((try a.to(i32)) == 3);
|
||||||
|
|
||||||
try a.sub(-1, -2);
|
try a.sub(neg_one, neg_two);
|
||||||
debug.assert((try a.to(i32)) == 1);
|
debug.assert((try a.to(i32)) == 1);
|
||||||
|
|
||||||
try a.sub(-2, -1);
|
try a.sub(neg_two, neg_one);
|
||||||
debug.assert((try a.to(i32)) == -1);
|
debug.assert((try a.to(i32)) == -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1514,7 +1456,7 @@ test "big.int mul single-single" {
|
|||||||
var b = try Int.initSet(al, 5);
|
var b = try Int.initSet(al, 5);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.mul(&a, &b);
|
try c.mul(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u64)) == 250);
|
debug.assert((try c.to(u64)) == 250);
|
||||||
}
|
}
|
||||||
@ -1524,7 +1466,7 @@ test "big.int mul multi-single" {
|
|||||||
var b = try Int.initSet(al, 2);
|
var b = try Int.initSet(al, 2);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.mul(&a, &b);
|
try c.mul(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(DoubleLimb)) == 2 * @maxValue(Limb));
|
debug.assert((try c.to(DoubleLimb)) == 2 * @maxValue(Limb));
|
||||||
}
|
}
|
||||||
@ -1536,7 +1478,7 @@ test "big.int mul multi-multi" {
|
|||||||
var b = try Int.initSet(al, op2);
|
var b = try Int.initSet(al, op2);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.mul(&a, &b);
|
try c.mul(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u256)) == op1 * op2);
|
debug.assert((try c.to(u256)) == op1 * op2);
|
||||||
}
|
}
|
||||||
@ -1545,7 +1487,7 @@ test "big.int mul alias r with a" {
|
|||||||
var a = try Int.initSet(al, @maxValue(Limb));
|
var a = try Int.initSet(al, @maxValue(Limb));
|
||||||
var b = try Int.initSet(al, 2);
|
var b = try Int.initSet(al, 2);
|
||||||
|
|
||||||
try a.mul(&a, &b);
|
try a.mul(a, b);
|
||||||
|
|
||||||
debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
|
debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
|
||||||
}
|
}
|
||||||
@ -1554,7 +1496,7 @@ test "big.int mul alias r with b" {
|
|||||||
var a = try Int.initSet(al, @maxValue(Limb));
|
var a = try Int.initSet(al, @maxValue(Limb));
|
||||||
var b = try Int.initSet(al, 2);
|
var b = try Int.initSet(al, 2);
|
||||||
|
|
||||||
try a.mul(&b, &a);
|
try a.mul(b, a);
|
||||||
|
|
||||||
debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
|
debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
|
||||||
}
|
}
|
||||||
@ -1562,7 +1504,7 @@ test "big.int mul alias r with b" {
|
|||||||
test "big.int mul alias r with a and b" {
|
test "big.int mul alias r with a and b" {
|
||||||
var a = try Int.initSet(al, @maxValue(Limb));
|
var a = try Int.initSet(al, @maxValue(Limb));
|
||||||
|
|
||||||
try a.mul(&a, &a);
|
try a.mul(a, a);
|
||||||
|
|
||||||
debug.assert((try a.to(DoubleLimb)) == @maxValue(Limb) * @maxValue(Limb));
|
debug.assert((try a.to(DoubleLimb)) == @maxValue(Limb) * @maxValue(Limb));
|
||||||
}
|
}
|
||||||
@ -1572,7 +1514,7 @@ test "big.int mul a*0" {
|
|||||||
var b = try Int.initSet(al, 0);
|
var b = try Int.initSet(al, 0);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.mul(&a, &b);
|
try c.mul(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u32)) == 0);
|
debug.assert((try c.to(u32)) == 0);
|
||||||
}
|
}
|
||||||
@ -1582,7 +1524,7 @@ test "big.int mul 0*0" {
|
|||||||
var b = try Int.initSet(al, 0);
|
var b = try Int.initSet(al, 0);
|
||||||
|
|
||||||
var c = try Int.init(al);
|
var c = try Int.init(al);
|
||||||
try c.mul(&a, &b);
|
try c.mul(a, b);
|
||||||
|
|
||||||
debug.assert((try c.to(u32)) == 0);
|
debug.assert((try c.to(u32)) == 0);
|
||||||
}
|
}
|
||||||
@ -1593,7 +1535,7 @@ test "big.int div single-single no rem" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u32)) == 10);
|
debug.assert((try q.to(u32)) == 10);
|
||||||
debug.assert((try r.to(u32)) == 0);
|
debug.assert((try r.to(u32)) == 0);
|
||||||
@ -1605,7 +1547,7 @@ test "big.int div single-single with rem" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u32)) == 9);
|
debug.assert((try q.to(u32)) == 9);
|
||||||
debug.assert((try r.to(u32)) == 4);
|
debug.assert((try r.to(u32)) == 4);
|
||||||
@ -1620,7 +1562,7 @@ test "big.int div multi-single no rem" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u64)) == op1 / op2);
|
debug.assert((try q.to(u64)) == op1 / op2);
|
||||||
debug.assert((try r.to(u64)) == 0);
|
debug.assert((try r.to(u64)) == 0);
|
||||||
@ -1635,7 +1577,7 @@ test "big.int div multi-single with rem" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u64)) == op1 / op2);
|
debug.assert((try q.to(u64)) == op1 / op2);
|
||||||
debug.assert((try r.to(u64)) == 3);
|
debug.assert((try r.to(u64)) == 3);
|
||||||
@ -1650,7 +1592,7 @@ test "big.int div multi>2-single" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u128)) == op1 / op2);
|
debug.assert((try q.to(u128)) == op1 / op2);
|
||||||
debug.assert((try r.to(u32)) == 0x3e4e);
|
debug.assert((try r.to(u32)) == 0x3e4e);
|
||||||
@ -1662,7 +1604,7 @@ test "big.int div single-single q < r" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u64)) == 0);
|
debug.assert((try q.to(u64)) == 0);
|
||||||
debug.assert((try r.to(u64)) == 0x0078f432);
|
debug.assert((try r.to(u64)) == 0x0078f432);
|
||||||
@ -1674,7 +1616,7 @@ test "big.int div single-single q == r" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u64)) == 1);
|
debug.assert((try q.to(u64)) == 1);
|
||||||
debug.assert((try r.to(u64)) == 0);
|
debug.assert((try r.to(u64)) == 0);
|
||||||
@ -1684,7 +1626,7 @@ test "big.int div q=0 alias" {
|
|||||||
var a = try Int.initSet(al, 3);
|
var a = try Int.initSet(al, 3);
|
||||||
var b = try Int.initSet(al, 10);
|
var b = try Int.initSet(al, 10);
|
||||||
|
|
||||||
try Int.divTrunc(&a, &b, &a, &b);
|
try Int.divTrunc(&a, &b, a, b);
|
||||||
|
|
||||||
debug.assert((try a.to(u64)) == 0);
|
debug.assert((try a.to(u64)) == 0);
|
||||||
debug.assert((try b.to(u64)) == 3);
|
debug.assert((try b.to(u64)) == 3);
|
||||||
@ -1698,7 +1640,7 @@ test "big.int div multi-multi q < r" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u128)) == 0);
|
debug.assert((try q.to(u128)) == 0);
|
||||||
debug.assert((try r.to(u128)) == op1);
|
debug.assert((try r.to(u128)) == op1);
|
||||||
@ -1713,7 +1655,7 @@ test "big.int div trunc single-single +/+" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
// n = q * d + r
|
// n = q * d + r
|
||||||
// 5 = 1 * 3 + 2
|
// 5 = 1 * 3 + 2
|
||||||
@ -1733,7 +1675,7 @@ test "big.int div trunc single-single -/+" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
// n = q * d + r
|
// n = q * d + r
|
||||||
// -5 = 1 * -3 - 2
|
// -5 = 1 * -3 - 2
|
||||||
@ -1753,7 +1695,7 @@ test "big.int div trunc single-single +/-" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
// n = q * d + r
|
// n = q * d + r
|
||||||
// 5 = -1 * -3 + 2
|
// 5 = -1 * -3 + 2
|
||||||
@ -1773,7 +1715,7 @@ test "big.int div trunc single-single -/-" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
// n = q * d + r
|
// n = q * d + r
|
||||||
// -5 = 1 * -3 - 2
|
// -5 = 1 * -3 - 2
|
||||||
@ -1793,7 +1735,7 @@ test "big.int div floor single-single +/+" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divFloor(&q, &r, &a, &b);
|
try Int.divFloor(&q, &r, a, b);
|
||||||
|
|
||||||
// n = q * d + r
|
// n = q * d + r
|
||||||
// 5 = 1 * 3 + 2
|
// 5 = 1 * 3 + 2
|
||||||
@ -1813,7 +1755,7 @@ test "big.int div floor single-single -/+" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divFloor(&q, &r, &a, &b);
|
try Int.divFloor(&q, &r, a, b);
|
||||||
|
|
||||||
// n = q * d + r
|
// n = q * d + r
|
||||||
// -5 = -2 * 3 + 1
|
// -5 = -2 * 3 + 1
|
||||||
@ -1833,7 +1775,7 @@ test "big.int div floor single-single +/-" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divFloor(&q, &r, &a, &b);
|
try Int.divFloor(&q, &r, a, b);
|
||||||
|
|
||||||
// n = q * d + r
|
// n = q * d + r
|
||||||
// 5 = -2 * -3 - 1
|
// 5 = -2 * -3 - 1
|
||||||
@ -1853,7 +1795,7 @@ test "big.int div floor single-single -/-" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divFloor(&q, &r, &a, &b);
|
try Int.divFloor(&q, &r, a, b);
|
||||||
|
|
||||||
// n = q * d + r
|
// n = q * d + r
|
||||||
// -5 = 2 * -3 + 1
|
// -5 = 2 * -3 + 1
|
||||||
@ -1870,7 +1812,7 @@ test "big.int div multi-multi with rem" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
|
debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
|
||||||
debug.assert((try r.to(u128)) == 0x28de0acacd806823638);
|
debug.assert((try r.to(u128)) == 0x28de0acacd806823638);
|
||||||
@ -1882,7 +1824,7 @@ test "big.int div multi-multi no rem" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
|
debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
|
||||||
debug.assert((try r.to(u128)) == 0);
|
debug.assert((try r.to(u128)) == 0);
|
||||||
@ -1894,7 +1836,7 @@ test "big.int div multi-multi (2 branch)" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u128)) == 0x10000000000000000);
|
debug.assert((try q.to(u128)) == 0x10000000000000000);
|
||||||
debug.assert((try r.to(u128)) == 0x44444443444444431111111111111111);
|
debug.assert((try r.to(u128)) == 0x44444443444444431111111111111111);
|
||||||
@ -1906,7 +1848,7 @@ test "big.int div multi-multi (3.1/3.3 branch)" {
|
|||||||
|
|
||||||
var q = try Int.init(al);
|
var q = try Int.init(al);
|
||||||
var r = try Int.init(al);
|
var r = try Int.init(al);
|
||||||
try Int.divTrunc(&q, &r, &a, &b);
|
try Int.divTrunc(&q, &r, a, b);
|
||||||
|
|
||||||
debug.assert((try q.to(u128)) == 0xfffffffffffffffffff);
|
debug.assert((try q.to(u128)) == 0xfffffffffffffffffff);
|
||||||
debug.assert((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282);
|
debug.assert((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282);
|
||||||
@ -1943,17 +1885,17 @@ test "big.int shift-left multi" {
|
|||||||
test "big.int shift-right negative" {
|
test "big.int shift-right negative" {
|
||||||
var a = try Int.init(al);
|
var a = try Int.init(al);
|
||||||
|
|
||||||
try a.shiftRight(-20, 2);
|
try a.shiftRight(try Int.initSet(al, -20), 2);
|
||||||
debug.assert((try a.to(i32)) == -20 >> 2);
|
debug.assert((try a.to(i32)) == -20 >> 2);
|
||||||
|
|
||||||
try a.shiftRight(-5, 10);
|
try a.shiftRight(try Int.initSet(al, -5), 10);
|
||||||
debug.assert((try a.to(i32)) == -5 >> 10);
|
debug.assert((try a.to(i32)) == -5 >> 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "big.int shift-left negative" {
|
test "big.int shift-left negative" {
|
||||||
var a = try Int.init(al);
|
var a = try Int.init(al);
|
||||||
|
|
||||||
try a.shiftRight(-10, 1232);
|
try a.shiftRight(try Int.initSet(al, -10), 1232);
|
||||||
debug.assert((try a.to(i32)) == -10 >> 1232);
|
debug.assert((try a.to(i32)) == -10 >> 1232);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1961,7 +1903,7 @@ test "big.int bitwise and simple" {
|
|||||||
var a = try Int.initSet(al, 0xffffffff11111111);
|
var a = try Int.initSet(al, 0xffffffff11111111);
|
||||||
var b = try Int.initSet(al, 0xeeeeeeee22222222);
|
var b = try Int.initSet(al, 0xeeeeeeee22222222);
|
||||||
|
|
||||||
try a.bitAnd(&a, &b);
|
try a.bitAnd(a, b);
|
||||||
|
|
||||||
debug.assert((try a.to(u64)) == 0xeeeeeeee00000000);
|
debug.assert((try a.to(u64)) == 0xeeeeeeee00000000);
|
||||||
}
|
}
|
||||||
@ -1970,7 +1912,7 @@ test "big.int bitwise and multi-limb" {
|
|||||||
var a = try Int.initSet(al, @maxValue(Limb) + 1);
|
var a = try Int.initSet(al, @maxValue(Limb) + 1);
|
||||||
var b = try Int.initSet(al, @maxValue(Limb));
|
var b = try Int.initSet(al, @maxValue(Limb));
|
||||||
|
|
||||||
try a.bitAnd(&a, &b);
|
try a.bitAnd(a, b);
|
||||||
|
|
||||||
debug.assert((try a.to(u128)) == 0);
|
debug.assert((try a.to(u128)) == 0);
|
||||||
}
|
}
|
||||||
@ -1979,7 +1921,7 @@ test "big.int bitwise xor simple" {
|
|||||||
var a = try Int.initSet(al, 0xffffffff11111111);
|
var a = try Int.initSet(al, 0xffffffff11111111);
|
||||||
var b = try Int.initSet(al, 0xeeeeeeee22222222);
|
var b = try Int.initSet(al, 0xeeeeeeee22222222);
|
||||||
|
|
||||||
try a.bitXor(&a, &b);
|
try a.bitXor(a, b);
|
||||||
|
|
||||||
debug.assert((try a.to(u64)) == 0x1111111133333333);
|
debug.assert((try a.to(u64)) == 0x1111111133333333);
|
||||||
}
|
}
|
||||||
@ -1988,7 +1930,7 @@ test "big.int bitwise xor multi-limb" {
|
|||||||
var a = try Int.initSet(al, @maxValue(Limb) + 1);
|
var a = try Int.initSet(al, @maxValue(Limb) + 1);
|
||||||
var b = try Int.initSet(al, @maxValue(Limb));
|
var b = try Int.initSet(al, @maxValue(Limb));
|
||||||
|
|
||||||
try a.bitXor(&a, &b);
|
try a.bitXor(a, b);
|
||||||
|
|
||||||
debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) ^ @maxValue(Limb));
|
debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) ^ @maxValue(Limb));
|
||||||
}
|
}
|
||||||
@ -1997,7 +1939,7 @@ test "big.int bitwise or simple" {
|
|||||||
var a = try Int.initSet(al, 0xffffffff11111111);
|
var a = try Int.initSet(al, 0xffffffff11111111);
|
||||||
var b = try Int.initSet(al, 0xeeeeeeee22222222);
|
var b = try Int.initSet(al, 0xeeeeeeee22222222);
|
||||||
|
|
||||||
try a.bitOr(&a, &b);
|
try a.bitOr(a, b);
|
||||||
|
|
||||||
debug.assert((try a.to(u64)) == 0xffffffff33333333);
|
debug.assert((try a.to(u64)) == 0xffffffff33333333);
|
||||||
}
|
}
|
||||||
@ -2006,7 +1948,7 @@ test "big.int bitwise or multi-limb" {
|
|||||||
var a = try Int.initSet(al, @maxValue(Limb) + 1);
|
var a = try Int.initSet(al, @maxValue(Limb) + 1);
|
||||||
var b = try Int.initSet(al, @maxValue(Limb));
|
var b = try Int.initSet(al, @maxValue(Limb));
|
||||||
|
|
||||||
try a.bitOr(&a, &b);
|
try a.bitOr(a, b);
|
||||||
|
|
||||||
// TODO: big.int.cpp or is wrong on multi-limb.
|
// TODO: big.int.cpp or is wrong on multi-limb.
|
||||||
debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) + @maxValue(Limb));
|
debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) + @maxValue(Limb));
|
||||||
@ -2015,9 +1957,9 @@ test "big.int bitwise or multi-limb" {
|
|||||||
test "big.int var args" {
|
test "big.int var args" {
|
||||||
var a = try Int.initSet(al, 5);
|
var a = try Int.initSet(al, 5);
|
||||||
|
|
||||||
try a.add(&a, 6);
|
try a.add(a, try Int.initSet(al, 6));
|
||||||
debug.assert((try a.to(u64)) == 11);
|
debug.assert((try a.to(u64)) == 11);
|
||||||
|
|
||||||
debug.assert(a.cmp(11) == 0);
|
debug.assert(a.cmp(try Int.initSet(al, 11)) == 0);
|
||||||
debug.assert(a.cmp(14) <= 0);
|
debug.assert(a.cmp(try Int.initSet(al, 14)) <= 0);
|
||||||
}
|
}
|
||||||
|
10
std/mem.zig
10
std/mem.zig
@ -40,16 +40,12 @@ pub const Allocator = struct {
|
|||||||
|
|
||||||
/// Call destroy with the result
|
/// Call destroy with the result
|
||||||
/// TODO once #733 is solved, this will replace create
|
/// TODO once #733 is solved, this will replace create
|
||||||
pub fn construct(self: *Allocator, init: var) t: {
|
pub fn construct(self: *Allocator, init: var) Error!*@typeOf(init) {
|
||||||
// TODO this is a workaround for type getting parsed as Error!&const T
|
const T = @typeOf(init);
|
||||||
const T = @typeOf(init).Child;
|
|
||||||
break :t Error!*T;
|
|
||||||
} {
|
|
||||||
const T = @typeOf(init).Child;
|
|
||||||
if (@sizeOf(T) == 0) return &{};
|
if (@sizeOf(T) == 0) return &{};
|
||||||
const slice = try self.alloc(T, 1);
|
const slice = try self.alloc(T, 1);
|
||||||
const ptr = &slice[0];
|
const ptr = &slice[0];
|
||||||
ptr.* = init.*;
|
ptr.* = init;
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ comptime {
|
|||||||
_ = @import("cases/bugs/656.zig");
|
_ = @import("cases/bugs/656.zig");
|
||||||
_ = @import("cases/bugs/828.zig");
|
_ = @import("cases/bugs/828.zig");
|
||||||
_ = @import("cases/bugs/920.zig");
|
_ = @import("cases/bugs/920.zig");
|
||||||
|
_ = @import("cases/byval_arg_var.zig");
|
||||||
_ = @import("cases/cast.zig");
|
_ = @import("cases/cast.zig");
|
||||||
_ = @import("cases/const_slice_child.zig");
|
_ = @import("cases/const_slice_child.zig");
|
||||||
_ = @import("cases/coroutines.zig");
|
_ = @import("cases/coroutines.zig");
|
||||||
|
27
test/cases/byval_arg_var.zig
Normal file
27
test/cases/byval_arg_var.zig
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
|
||||||
|
var result: []const u8 = "wrong";
|
||||||
|
|
||||||
|
test "aoeu" {
|
||||||
|
start();
|
||||||
|
blowUpStack(10);
|
||||||
|
|
||||||
|
std.debug.assert(std.mem.eql(u8, result, "string literal"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn start() void {
|
||||||
|
foo("string literal");
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(x: var) void {
|
||||||
|
bar(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(x: var) void {
|
||||||
|
result = x;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn blowUpStack(x: u32) void {
|
||||||
|
if (x == 0) return;
|
||||||
|
blowUpStack(x - 1);
|
||||||
|
}
|
@ -318,14 +318,6 @@ fn testCastConstArrayRefToConstSlice() void {
|
|||||||
assert(mem.eql(u8, slice, "aoeu"));
|
assert(mem.eql(u8, slice, "aoeu"));
|
||||||
}
|
}
|
||||||
|
|
||||||
test "var args implicitly casts by value arg to const ref" {
|
|
||||||
foo("hello");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn foo(args: ...) void {
|
|
||||||
assert(@typeOf(args[0]) == *const [5]u8);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "peer type resolution: error and [N]T" {
|
test "peer type resolution: error and [N]T" {
|
||||||
// TODO: implicit error!T to error!U where T can implicitly cast to U
|
// TODO: implicit error!T to error!U where T can implicitly cast to U
|
||||||
//assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
|
//assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
|
||||||
|
@ -119,3 +119,60 @@ test "assign inline fn to const variable" {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline fn inlineFn() void {}
|
inline fn inlineFn() void {}
|
||||||
|
|
||||||
|
test "pass by non-copying value" {
|
||||||
|
assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Point = struct {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
};
|
||||||
|
|
||||||
|
fn addPointCoords(pt: Point) i32 {
|
||||||
|
return pt.x + pt.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "pass by non-copying value through var arg" {
|
||||||
|
assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn addPointCoordsVar(pt: var) i32 {
|
||||||
|
comptime assert(@typeOf(pt) == Point);
|
||||||
|
return pt.x + pt.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
test "pass by non-copying value as method" {
|
||||||
|
var pt = Point2{ .x = 1, .y = 2 };
|
||||||
|
assert(pt.addPointCoords() == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Point2 = struct {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
|
||||||
|
fn addPointCoords(self: Point2) i32 {
|
||||||
|
return self.x + self.y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "pass by non-copying value as method, which is generic" {
|
||||||
|
var pt = Point3{ .x = 1, .y = 2 };
|
||||||
|
assert(pt.addPointCoords(i32) == 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
const Point3 = struct {
|
||||||
|
x: i32,
|
||||||
|
y: i32,
|
||||||
|
|
||||||
|
fn addPointCoords(self: Point3, comptime T: type) i32 {
|
||||||
|
return self.x + self.y;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "pass by non-copying value as method, at comptime" {
|
||||||
|
comptime {
|
||||||
|
var pt = Point2{ .x = 1, .y = 2 };
|
||||||
|
assert(pt.addPointCoords() == 3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -75,18 +75,6 @@ test "array of var args functions" {
|
|||||||
assert(!foos[1]());
|
assert(!foos[1]());
|
||||||
}
|
}
|
||||||
|
|
||||||
test "pass array and slice of same array to var args should have same pointers" {
|
|
||||||
const array = "hi";
|
|
||||||
const slice: []const u8 = array;
|
|
||||||
return assertSlicePtrsEql(array, slice);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn assertSlicePtrsEql(args: ...) void {
|
|
||||||
const s1 = ([]const u8)(args[0]);
|
|
||||||
const s2 = args[1];
|
|
||||||
assert(s1.ptr == s2.ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
test "pass zero length array to var args param" {
|
test "pass zero length array to var args param" {
|
||||||
doNothingWithFirstArg("");
|
doNothingWithFirstArg("");
|
||||||
}
|
}
|
||||||
|
@ -2215,7 +2215,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
\\ derp.init();
|
\\ derp.init();
|
||||||
\\}
|
\\}
|
||||||
,
|
,
|
||||||
".tmp_source.zig:14:5: error: expected type 'i32', found '*const Foo'",
|
".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'",
|
||||||
);
|
);
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
@ -2573,15 +2573,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
break :x tc;
|
break :x tc;
|
||||||
});
|
});
|
||||||
|
|
||||||
cases.add(
|
|
||||||
"pass non-copyable type by value to function",
|
|
||||||
\\const Point = struct { x: i32, y: i32, };
|
|
||||||
\\fn foo(p: Point) void { }
|
|
||||||
\\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
|
|
||||||
,
|
|
||||||
".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value",
|
|
||||||
);
|
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
"implicit cast from array to mutable slice",
|
"implicit cast from array to mutable slice",
|
||||||
\\var global_array: [10]i32 = undefined;
|
\\var global_array: [10]i32 = undefined;
|
||||||
@ -4066,20 +4057,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
|
|||||||
".tmp_source.zig:3:5: note: field 'A' has type 'i32'",
|
".tmp_source.zig:3:5: note: field 'A' has type 'i32'",
|
||||||
);
|
);
|
||||||
|
|
||||||
cases.add(
|
|
||||||
"self-referencing function pointer field",
|
|
||||||
\\const S = struct {
|
|
||||||
\\ f: fn(_: S) void,
|
|
||||||
\\};
|
|
||||||
\\fn f(_: S) void {
|
|
||||||
\\}
|
|
||||||
\\export fn entry() void {
|
|
||||||
\\ var _ = S { .f = f };
|
|
||||||
\\}
|
|
||||||
,
|
|
||||||
".tmp_source.zig:4:9: error: type 'S' is not copyable; cannot pass by value",
|
|
||||||
);
|
|
||||||
|
|
||||||
cases.add(
|
cases.add(
|
||||||
"taking offset of void field in struct",
|
"taking offset of void field in struct",
|
||||||
\\const Empty = struct {
|
\\const Empty = struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user