authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-06-16 21:13:10-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-06-16 21:13:10-04:00
log751518787ae9772eb063a4911a10bf30b2c2a19c
tree4dd5a4613a04760571da1088648704ec3c72e353
parent3ee4d23ebdd149e734ca33904a4786d5bd3fa8aa
parent472b7ef7e6db4bdd4717ff5b44b63e233853bb06
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #1109 from ziglang/pass-by-non-copying-value

allow passing by non-copying value

16 files changed, 306 insertions(+), 344 deletions(-)

doc/langref.html.in+14-23
......@@ -2818,39 +2818,30 @@ fn foo() void { }
28182818 {#code_end#}
28192819 {#header_open|Pass-by-value Parameters#}
28202820 <p>
2821 In Zig, structs, unions, and enums with payloads cannot be passed by value
2822 to a function.
2821 In Zig, structs, unions, and enums with payloads can be passed directly to a function:
28232822 </p>
2824 {#code_begin|test_err|not copyable; cannot pass by value#}
2825const Foo = struct {
2823 {#code_begin|test#}
2824const Point = struct {
28262825 x: i32,
2826 y: i32,
28272827};
28282828
2829fn bar(foo: Foo) void {}
2830
2831test "pass aggregate type by value to function" {
2832 bar(Foo {.x = 12,});
2829fn foo(point: Point) i32 {
2830 return point.x + point.y;
28332831}
2834 {#code_end#}
2835 <p>
2836 Instead, one must use <code>*const</code>. Zig allows implicitly casting something
2837 to a const pointer to it:
2838 </p>
2839 {#code_begin|test#}
2840const Foo = struct {
2841 x: i32,
2842};
28432832
2844fn bar(foo: *const Foo) void {}
2833const assert = @import("std").debug.assert;
28452834
2846test "implicitly cast to const pointer" {
2847 bar(Foo {.x = 12,});
2835test "pass aggregate type by non-copy value to function" {
2836 assert(foo(Point{ .x = 1, .y = 2 }) == 3);
28482837}
28492838 {#code_end#}
28502839 <p>
2851 However,
2852 the C ABI does allow passing structs and unions by value. So functions which
2853 use the C calling convention may pass structs and unions by value.
2840 In this case, the value may be passed by reference, or by value, whichever way
2841 Zig decides will be faster.
2842 </p>
2843 <p>
2844 For extern functions, Zig follows the C ABI for passing structs and unions by value.
28542845 </p>
28552846 {#header_close#}
28562847 {#header_open|Function Reflection#}
src/analyze.cpp+4-7
......@@ -1135,7 +1135,10 @@ TypeTableEntry *get_fn_type(CodeGen *g, FnTypeId *fn_type_id) {
11351135 gen_param_info->src_index = i;
11361136 gen_param_info->gen_index = SIZE_MAX;
11371137
1138 type_ensure_zero_bits_known(g, type_entry);
1138 ensure_complete_type(g, type_entry);
1139 if (type_is_invalid(type_entry))
1140 return g->builtin_types.entry_invalid;
1141
11391142 if (type_has_bits(type_entry)) {
11401143 TypeTableEntry *gen_type;
11411144 if (handle_is_ptr(type_entry)) {
......@@ -1546,12 +1549,6 @@ static TypeTableEntry *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *c
15461549 case TypeTableEntryIdUnion:
15471550 case TypeTableEntryIdFn:
15481551 case TypeTableEntryIdPromise:
1549 ensure_complete_type(g, type_entry);
1550 if (calling_convention_allows_zig_types(fn_type_id.cc) && !type_is_copyable(g, type_entry)) {
1551 add_node_error(g, param_node->data.param_decl.type,
1552 buf_sprintf("type '%s' is not copyable; cannot pass by value", buf_ptr(&type_entry->name)));
1553 return g->builtin_types.entry_invalid;
1554 }
15551552 break;
15561553 }
15571554 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
src/codegen.cpp-21
......@@ -326,13 +326,6 @@ static void addLLVMArgAttr(LLVMValueRef arg_val, unsigned param_index, const cha
326326 return addLLVMAttr(arg_val, param_index + 1, attr_name);
327327}
328328
329static void addLLVMCallsiteAttr(LLVMValueRef call_instr, unsigned param_index, const char *attr_name) {
330 unsigned kind_id = LLVMGetEnumAttributeKindForName(attr_name, strlen(attr_name));
331 assert(kind_id != 0);
332 LLVMAttributeRef llvm_attr = LLVMCreateEnumAttribute(LLVMGetGlobalContext(), kind_id, 0);
333 LLVMAddCallSiteAttribute(call_instr, param_index + 1, llvm_attr);
334}
335
336329static bool is_symbol_available(CodeGen *g, Buf *name) {
337330 return g->exported_symbol_names.maybe_get(name) == nullptr && g->external_prototypes.maybe_get(name) == nullptr;
338331}
......@@ -581,11 +574,6 @@ static LLVMValueRef fn_llvm_value(CodeGen *g, FnTableEntry *fn_table_entry) {
581574 if (param_type->id == TypeTableEntryIdPointer) {
582575 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "nonnull");
583576 }
584 // Note: byval is disabled on windows due to an LLVM bug:
585 // https://github.com/ziglang/zig/issues/536
586 if (is_byval && g->zig_target.os != OsWindows) {
587 addLLVMArgAttr(fn_table_entry->llvm_value, (unsigned)gen_index, "byval");
588 }
589577 }
590578
591579 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
31143102 }
31153103
31163104
3117 for (size_t param_i = 0; param_i < fn_type_id->param_count; param_i += 1) {
3118 FnGenParamInfo *gen_info = &fn_type->data.fn.gen_param_info[param_i];
3119 // Note: byval is disabled on windows due to an LLVM bug:
3120 // https://github.com/ziglang/zig/issues/536
3121 if (gen_info->is_byval && g->zig_target.os != OsWindows) {
3122 addLLVMCallsiteAttr(result, (unsigned)gen_info->gen_index, "byval");
3123 }
3124 }
3125
31263105 if (instruction->is_async) {
31273106 LLVMValueRef payload_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, err_union_payload_index, "");
31283107 LLVMBuildStore(g->builder, result, payload_ptr);
src/ir.cpp+34-23
......@@ -10463,13 +10463,6 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Typ
1046310463 zig_unreachable();
1046410464}
1046510465
10466static IrInstruction *ir_implicit_byval_const_ref_cast(IrAnalyze *ira, IrInstruction *inst) {
10467 if (type_is_copyable(ira->codegen, inst->value.type))
10468 return inst;
10469 TypeTableEntry *const_ref_type = get_pointer_to_type(ira->codegen, inst->value.type, true);
10470 return ir_implicit_cast(ira, inst, const_ref_type);
10471}
10472
1047310466static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr) {
1047410467 TypeTableEntry *type_entry = ptr->value.type;
1047510468 if (type_is_invalid(type_entry)) {
......@@ -12283,7 +12276,7 @@ static bool ir_analyze_fn_call_generic_arg(IrAnalyze *ira, AstNode *fn_proto_nod
1228312276 IrInstruction *casted_arg;
1228412277 if (is_var_args) {
1228512278 arg_part_of_generic_id = true;
12286 casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
12279 casted_arg = arg;
1228712280 } else {
1228812281 if (param_decl_node->data.param_decl.var_token == nullptr) {
1228912282 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
1229612289 return false;
1229712290 } else {
1229812291 arg_part_of_generic_id = true;
12299 casted_arg = ir_implicit_byval_const_ref_cast(ira, arg);
12292 casted_arg = arg;
1230012293 }
1230112294 }
1230212295
......@@ -12515,9 +12508,18 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1251512508
1251612509 size_t next_proto_i = 0;
1251712510 if (first_arg_ptr) {
12518 IrInstruction *first_arg;
1251912511 assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
12520 if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
12512
12513 bool first_arg_known_bare = false;
12514 if (fn_type_id->next_param_index >= 1) {
12515 TypeTableEntry *param_type = fn_type_id->param_info[next_proto_i].type;
12516 if (type_is_invalid(param_type))
12517 return ira->codegen->builtin_types.entry_invalid;
12518 first_arg_known_bare = param_type->id != TypeTableEntryIdPointer;
12519 }
12520
12521 IrInstruction *first_arg;
12522 if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
1252112523 first_arg = first_arg_ptr;
1252212524 } else {
1252312525 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
1266712669 size_t next_proto_i = 0;
1266812670
1266912671 if (first_arg_ptr) {
12670 IrInstruction *first_arg;
1267112672 assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
12672 if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
12673
12674 bool first_arg_known_bare = false;
12675 if (fn_type_id->next_param_index >= 1) {
12676 TypeTableEntry *param_type = fn_type_id->param_info[next_proto_i].type;
12677 if (type_is_invalid(param_type))
12678 return ira->codegen->builtin_types.entry_invalid;
12679 first_arg_known_bare = param_type->id != TypeTableEntryIdPointer;
12680 }
12681
12682 IrInstruction *first_arg;
12683 if (!first_arg_known_bare && handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
1267312684 first_arg = first_arg_ptr;
1267412685 } else {
1267512686 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
1280212813 return ira->codegen->builtin_types.entry_invalid;
1280312814 }
1280412815 if (inst_fn_type_id.async_allocator_type == nullptr) {
12805 IrInstruction *casted_inst = ir_implicit_byval_const_ref_cast(ira, uncasted_async_allocator_inst);
12806 if (type_is_invalid(casted_inst->value.type))
12807 return ira->codegen->builtin_types.entry_invalid;
12808 inst_fn_type_id.async_allocator_type = casted_inst->value.type;
12816 inst_fn_type_id.async_allocator_type = uncasted_async_allocator_inst->value.type;
1280912817 }
1281012818 async_allocator_inst = ir_implicit_cast(ira, uncasted_async_allocator_inst, inst_fn_type_id.async_allocator_type);
1281112819 if (type_is_invalid(async_allocator_inst->value.type))
......@@ -12866,9 +12874,16 @@ static TypeTableEntry *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCall *cal
1286612874 IrInstruction **casted_args = allocate<IrInstruction *>(call_param_count);
1286712875 size_t next_arg_index = 0;
1286812876 if (first_arg_ptr) {
12869 IrInstruction *first_arg;
1287012877 assert(first_arg_ptr->value.type->id == TypeTableEntryIdPointer);
12871 if (handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type)) {
12878
12879 TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
12880 if (type_is_invalid(param_type))
12881 return ira->codegen->builtin_types.entry_invalid;
12882
12883 IrInstruction *first_arg;
12884 if (param_type->id == TypeTableEntryIdPointer &&
12885 handle_is_ptr(first_arg_ptr->value.type->data.pointer.child_type))
12886 {
1287212887 first_arg = first_arg_ptr;
1287312888 } else {
1287412889 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
1287612891 return ira->codegen->builtin_types.entry_invalid;
1287712892 }
1287812893
12879 TypeTableEntry *param_type = fn_type_id->param_info[next_arg_index].type;
12880 if (type_is_invalid(param_type))
12881 return ira->codegen->builtin_types.entry_invalid;
12882
1288312894 IrInstruction *casted_arg = ir_implicit_cast(ira, first_arg, param_type);
1288412895 if (type_is_invalid(casted_arg->value.type))
1288512896 return ira->codegen->builtin_types.entry_invalid;
std/array_list.zig+13-13
......@@ -29,36 +29,36 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
2929 };
3030 }
3131
32 pub fn deinit(self: *const Self) void {
32 pub fn deinit(self: Self) void {
3333 self.allocator.free(self.items);
3434 }
3535
36 pub fn toSlice(self: *const Self) []align(A) T {
36 pub fn toSlice(self: Self) []align(A) T {
3737 return self.items[0..self.len];
3838 }
3939
40 pub fn toSliceConst(self: *const Self) []align(A) const T {
40 pub fn toSliceConst(self: Self) []align(A) const T {
4141 return self.items[0..self.len];
4242 }
4343
44 pub fn at(self: *const Self, n: usize) T {
44 pub fn at(self: Self, n: usize) T {
4545 return self.toSliceConst()[n];
4646 }
4747
4848 /// Sets the value at index `i`, or returns `error.OutOfBounds` if
4949 /// the index is not in range.
50 pub fn setOrError(self: *const Self, i: usize, item: *const T) !void {
50 pub fn setOrError(self: Self, i: usize, item: T) !void {
5151 if (i >= self.len) return error.OutOfBounds;
52 self.items[i] = item.*;
52 self.items[i] = item;
5353 }
5454
5555 /// Sets the value at index `i`, asserting that the value is in range.
56 pub fn set(self: *const Self, i: usize, item: *const T) void {
56 pub fn set(self: *Self, i: usize, item: T) void {
5757 assert(i < self.len);
58 self.items[i] = item.*;
58 self.items[i] = item;
5959 }
6060
61 pub fn count(self: *const Self) usize {
61 pub fn count(self: Self) usize {
6262 return self.len;
6363 }
6464
......@@ -81,12 +81,12 @@ pub fn AlignedArrayList(comptime T: type, comptime A: u29) type {
8181 return result;
8282 }
8383
84 pub fn insert(self: *Self, n: usize, item: *const T) !void {
84 pub fn insert(self: *Self, n: usize, item: T) !void {
8585 try self.ensureCapacity(self.len + 1);
8686 self.len += 1;
8787
8888 mem.copy(T, self.items[n + 1 .. self.len], self.items[n .. self.len - 1]);
89 self.items[n] = item.*;
89 self.items[n] = item;
9090 }
9191
9292 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 {
9797 mem.copy(T, self.items[n .. n + items.len], items);
9898 }
9999
100 pub fn append(self: *Self, item: *const T) !void {
100 pub fn append(self: *Self, item: T) !void {
101101 const new_item_ptr = try self.addOne();
102 new_item_ptr.* = item.*;
102 new_item_ptr.* = item;
103103 }
104104
105105 pub fn appendSlice(self: *Self, items: []align(A) const T) !void {
std/build.zig+1-1
......@@ -234,7 +234,7 @@ pub const Builder = struct {
234234 defer wanted_steps.deinit();
235235
236236 if (step_names.len == 0) {
237 try wanted_steps.append(&self.default_step);
237 try wanted_steps.append(self.default_step);
238238 } else {
239239 for (step_names) |step_name| {
240240 const s = try self.getTopLevelStepByName(step_name);
std/fmt/index.zig+6-2
......@@ -162,8 +162,6 @@ pub fn formatType(
162162 },
163163 builtin.TypeInfo.Pointer.Size.Many => {
164164 if (ptr_info.child == u8) {
165 //This is a bit of a hack, but it made more sense to
166 // do this check here than have formatText do it
167165 if (fmt[0] == 's') {
168166 const len = std.cstr.len(value);
169167 return formatText(value[0..len], fmt, context, Errors, output);
......@@ -176,6 +174,12 @@ pub fn formatType(
176174 return output(context, casted_value);
177175 },
178176 },
177 builtin.TypeId.Array => |info| {
178 if (info.child == u8) {
179 return formatText(value, fmt, context, Errors, output);
180 }
181 return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
182 },
179183 else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
180184 }
181185}
std/json.zig+1-1
......@@ -1326,7 +1326,7 @@ pub const Parser = struct {
13261326 },
13271327 // Array Parent -> [ ..., <array>, value ]
13281328 Value.Array => |*array| {
1329 try array.append(value);
1329 try array.append(value.*);
13301330 p.state = State.ArrayValue;
13311331 },
13321332 else => {
std/math/big/int.zig+144-202
......@@ -18,39 +18,6 @@ comptime {
1818 debug.assert(Limb.is_signed == false);
1919}
2020
21const wrapped_buffer_size = 512;
22
23// Converts primitive integer values onto a stack-based big integer, or passes through existing
24// Int types with no modifications. This can fail at runtime if using a very large dynamic
25// integer but it is very unlikely and is considered a user error.
26fn wrapInt(allocator: *Allocator, bn: var) *const Int {
27 const T = @typeOf(bn);
28 switch (@typeInfo(T)) {
29 TypeId.Pointer => |info| {
30 if (info.child == Int) {
31 return bn;
32 } else {
33 @compileError("cannot set Int using type " ++ @typeName(T));
34 }
35 },
36 else => {
37 var s = allocator.create(Int) catch unreachable;
38 s.* = Int{
39 .allocator = allocator,
40 .positive = false,
41 .limbs = block: {
42 var limbs = allocator.alloc(Limb, Int.default_capacity) catch unreachable;
43 limbs[0] = 0;
44 break :block limbs;
45 },
46 .len = 1,
47 };
48 s.set(bn) catch unreachable;
49 return s;
50 },
51 }
52}
53
5421pub const Int = struct {
5522 allocator: *Allocator,
5623 positive: bool,
......@@ -93,11 +60,11 @@ pub const Int = struct {
9360 self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);
9461 }
9562
96 pub fn deinit(self: *const Int) void {
63 pub fn deinit(self: Int) void {
9764 self.allocator.free(self.limbs);
9865 }
9966
100 pub fn clone(other: *const Int) !Int {
67 pub fn clone(other: Int) !Int {
10168 return Int{
10269 .allocator = other.allocator,
10370 .positive = other.positive,
......@@ -110,8 +77,8 @@ pub const Int = struct {
11077 };
11178 }
11279
113 pub fn copy(self: *Int, other: *const Int) !void {
114 if (self == other) {
80 pub fn copy(self: *Int, other: Int) !void {
81 if (self == &other) {
11582 return;
11683 }
11784
......@@ -125,7 +92,7 @@ pub const Int = struct {
12592 mem.swap(Int, self, other);
12693 }
12794
128 pub fn dump(self: *const Int) void {
95 pub fn dump(self: Int) void {
12996 for (self.limbs) |limb| {
13097 debug.warn("{x} ", limb);
13198 }
......@@ -140,20 +107,20 @@ pub const Int = struct {
140107 r.positive = true;
141108 }
142109
143 pub fn isOdd(r: *const Int) bool {
110 pub fn isOdd(r: Int) bool {
144111 return r.limbs[0] & 1 != 0;
145112 }
146113
147 pub fn isEven(r: *const Int) bool {
114 pub fn isEven(r: Int) bool {
148115 return !r.isOdd();
149116 }
150117
151 fn bitcount(self: *const Int) usize {
118 fn bitcount(self: Int) usize {
152119 const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
153120 return usize(!self.positive) + u_bit_count;
154121 }
155122
156 pub fn sizeInBase(self: *const Int, base: usize) usize {
123 pub fn sizeInBase(self: Int, base: usize) usize {
157124 return (self.bitcount() / math.log2(base)) + 1;
158125 }
159126
......@@ -219,7 +186,7 @@ pub const Int = struct {
219186 TargetTooSmall,
220187 };
221188
222 pub fn to(self: *const Int, comptime T: type) ConvertError!T {
189 pub fn to(self: Int, comptime T: type) ConvertError!T {
223190 switch (@typeId(T)) {
224191 TypeId.Int => {
225192 const UT = if (T.is_signed) @IntType(false, T.bit_count - 1) else T;
......@@ -286,16 +253,28 @@ pub const Int = struct {
286253 i += 1;
287254 }
288255
256 // TODO values less than limb size should guarantee non allocating
257 var base_buffer: [512]u8 = undefined;
258 const base_al = &std.heap.FixedBufferAllocator.init(base_buffer[0..]).allocator;
259 const base_ap = try Int.initSet(base_al, base);
260
261 var d_buffer: [512]u8 = undefined;
262 var d_fba = std.heap.FixedBufferAllocator.init(d_buffer[0..]);
263 const d_al = &d_fba.allocator;
264
289265 try self.set(0);
290266 for (value[i..]) |ch| {
291267 const d = try charToDigit(ch, base);
292 try self.mul(self, base);
293 try self.add(self, d);
268 d_fba.end_index = 0;
269 const d_ap = try Int.initSet(d_al, d);
270
271 try self.mul(self.*, base_ap);
272 try self.add(self.*, d_ap);
294273 }
295274 self.positive = positive;
296275 }
297276
298 pub fn toString(self: *const Int, allocator: *Allocator, base: u8) ![]const u8 {
277 pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 {
299278 if (base < 2 or base > 16) {
300279 return error.InvalidBase;
301280 }
......@@ -345,7 +324,7 @@ pub const Int = struct {
345324 var b = try Int.initSet(allocator, limb_base);
346325
347326 while (q.len >= 2) {
348 try Int.divTrunc(&q, &r, &q, &b);
327 try Int.divTrunc(&q, &r, q, b);
349328
350329 var r_word = r.limbs[0];
351330 var i: usize = 0;
......@@ -378,12 +357,7 @@ pub const Int = struct {
378357 }
379358
380359 // returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
381 pub fn cmpAbs(a: *const Int, bv: var) i8 {
382 // TODO: Thread-local buffer.
383 var buffer: [wrapped_buffer_size]u8 = undefined;
384 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
385 var b = wrapInt(&stack.allocator, bv);
386
360 pub fn cmpAbs(a: Int, b: Int) i8 {
387361 if (a.len < b.len) {
388362 return -1;
389363 }
......@@ -408,11 +382,7 @@ pub const Int = struct {
408382 }
409383
410384 // returns -1, 0, 1 if a < b, a == b or a > b respectively.
411 pub fn cmp(a: *const Int, bv: var) i8 {
412 var buffer: [wrapped_buffer_size]u8 = undefined;
413 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
414 var b = wrapInt(&stack.allocator, bv);
415
385 pub fn cmp(a: Int, b: Int) i8 {
416386 if (a.positive != b.positive) {
417387 return if (a.positive) i8(1) else -1;
418388 } else {
......@@ -422,17 +392,17 @@ pub const Int = struct {
422392 }
423393
424394 // if a == 0
425 pub fn eqZero(a: *const Int) bool {
395 pub fn eqZero(a: Int) bool {
426396 return a.len == 1 and a.limbs[0] == 0;
427397 }
428398
429399 // if |a| == |b|
430 pub fn eqAbs(a: *const Int, b: var) bool {
400 pub fn eqAbs(a: Int, b: Int) bool {
431401 return cmpAbs(a, b) == 0;
432402 }
433403
434404 // if a == b
435 pub fn eq(a: *const Int, b: var) bool {
405 pub fn eq(a: Int, b: Int) bool {
436406 return cmp(a, b) == 0;
437407 }
438408
......@@ -473,12 +443,7 @@ pub const Int = struct {
473443 }
474444
475445 // r = a + b
476 pub fn add(r: *Int, av: var, bv: var) Allocator.Error!void {
477 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
478 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
479 var a = wrapInt(&stack.allocator, av);
480 var b = wrapInt(&stack.allocator, bv);
481
446 pub fn add(r: *Int, a: Int, b: Int) Allocator.Error!void {
482447 if (a.eqZero()) {
483448 try r.copy(b);
484449 return;
......@@ -547,12 +512,7 @@ pub const Int = struct {
547512 }
548513
549514 // r = a - b
550 pub fn sub(r: *Int, av: var, bv: var) !void {
551 var buffer: [wrapped_buffer_size]u8 = undefined;
552 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
553 var a = wrapInt(&stack.allocator, av);
554 var b = wrapInt(&stack.allocator, bv);
555
515 pub fn sub(r: *Int, a: Int, b: Int) !void {
556516 if (a.positive != b.positive) {
557517 if (a.positive) {
558518 // (a) - (-b) => a + b
......@@ -632,14 +592,9 @@ pub const Int = struct {
632592 // rma = a * b
633593 //
634594 // For greatest efficiency, ensure rma does not alias a or b.
635 pub fn mul(rma: *Int, av: var, bv: var) !void {
636 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
637 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
638 var a = wrapInt(&stack.allocator, av);
639 var b = wrapInt(&stack.allocator, bv);
640
595 pub fn mul(rma: *Int, a: Int, b: Int) !void {
641596 var r = rma;
642 var aliased = rma == a or rma == b;
597 var aliased = rma.limbs.ptr == a.limbs.ptr or rma.limbs.ptr == b.limbs.ptr;
643598
644599 var sr: Int = undefined;
645600 if (aliased) {
......@@ -714,29 +669,29 @@ pub const Int = struct {
714669 }
715670 }
716671
717 pub fn divFloor(q: *Int, r: *Int, a: var, b: var) !void {
672 pub fn divFloor(q: *Int, r: *Int, a: Int, b: Int) !void {
718673 try div(q, r, a, b);
719674
720675 // Trunc -> Floor.
721676 if (!q.positive) {
722 try q.sub(q, 1);
723 try r.add(q, 1);
677 // TODO values less than limb size should guarantee non allocating
678 var one_buffer: [512]u8 = undefined;
679 const one_al = &std.heap.FixedBufferAllocator.init(one_buffer[0..]).allocator;
680 const one_ap = try Int.initSet(one_al, 1);
681
682 try q.sub(q.*, one_ap);
683 try r.add(q.*, one_ap);
724684 }
725685 r.positive = b.positive;
726686 }
727687
728 pub fn divTrunc(q: *Int, r: *Int, a: var, b: var) !void {
688 pub fn divTrunc(q: *Int, r: *Int, a: Int, b: Int) !void {
729689 try div(q, r, a, b);
730690 r.positive = a.positive;
731691 }
732692
733693 // Truncates by default.
734 fn div(quo: *Int, rem: *Int, av: var, bv: var) !void {
735 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
736 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
737 var a = wrapInt(&stack.allocator, av);
738 var b = wrapInt(&stack.allocator, bv);
739
694 fn div(quo: *Int, rem: *Int, a: Int, b: Int) !void {
740695 if (b.eqZero()) {
741696 @panic("division by zero");
742697 }
......@@ -821,8 +776,8 @@ pub const Int = struct {
821776
822777 // Normalize so y > Limb.bit_count / 2 (i.e. leading bit is set)
823778 const norm_shift = @clz(y.limbs[y.len - 1]);
824 try x.shiftLeft(x, norm_shift);
825 try y.shiftLeft(y, norm_shift);
779 try x.shiftLeft(x.*, norm_shift);
780 try y.shiftLeft(y.*, norm_shift);
826781
827782 const n = x.len - 1;
828783 const t = y.len - 1;
......@@ -832,10 +787,10 @@ pub const Int = struct {
832787 mem.set(Limb, q.limbs[0..q.len], 0);
833788
834789 // 2.
835 try tmp.shiftLeft(y, Limb.bit_count * (n - t));
836 while (x.cmp(&tmp) >= 0) {
790 try tmp.shiftLeft(y.*, Limb.bit_count * (n - t));
791 while (x.cmp(tmp) >= 0) {
837792 q.limbs[n - t] += 1;
838 try x.sub(x, tmp);
793 try x.sub(x.*, tmp);
839794 }
840795
841796 // 3.
......@@ -864,7 +819,7 @@ pub const Int = struct {
864819 r.limbs[2] = carry;
865820 r.normN(3);
866821
867 if (r.cmpAbs(&tmp) <= 0) {
822 if (r.cmpAbs(tmp) <= 0) {
868823 break;
869824 }
870825
......@@ -873,13 +828,13 @@ pub const Int = struct {
873828
874829 // 3.3
875830 try tmp.set(q.limbs[i - t - 1]);
876 try tmp.mul(&tmp, y);
877 try tmp.shiftLeft(&tmp, Limb.bit_count * (i - t - 1));
878 try x.sub(x, &tmp);
831 try tmp.mul(tmp, y.*);
832 try tmp.shiftLeft(tmp, Limb.bit_count * (i - t - 1));
833 try x.sub(x.*, tmp);
879834
880835 if (!x.positive) {
881 try tmp.shiftLeft(y, Limb.bit_count * (i - t - 1));
882 try x.add(x, &tmp);
836 try tmp.shiftLeft(y.*, Limb.bit_count * (i - t - 1));
837 try x.add(x.*, tmp);
883838 q.limbs[i - t - 1] -= 1;
884839 }
885840 }
......@@ -887,16 +842,12 @@ pub const Int = struct {
887842 // Denormalize
888843 q.normN(q.len);
889844
890 try r.shiftRight(x, norm_shift);
845 try r.shiftRight(x.*, norm_shift);
891846 r.normN(r.len);
892847 }
893848
894849 // r = a << shift, in other words, r = a * 2^shift
895 pub fn shiftLeft(r: *Int, av: var, shift: usize) !void {
896 var buffer: [wrapped_buffer_size]u8 = undefined;
897 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
898 var a = wrapInt(&stack.allocator, av);
899
850 pub fn shiftLeft(r: *Int, a: Int, shift: usize) !void {
900851 try r.ensureCapacity(a.len + (shift / Limb.bit_count) + 1);
901852 llshl(r.limbs[0..], a.limbs[0..a.len], shift);
902853 r.norm1(a.len + (shift / Limb.bit_count) + 1);
......@@ -927,11 +878,7 @@ pub const Int = struct {
927878 }
928879
929880 // r = a >> shift
930 pub fn shiftRight(r: *Int, av: var, shift: usize) !void {
931 var buffer: [wrapped_buffer_size]u8 = undefined;
932 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
933 var a = wrapInt(&stack.allocator, av);
934
881 pub fn shiftRight(r: *Int, a: Int, shift: usize) !void {
935882 if (a.len <= shift / Limb.bit_count) {
936883 r.len = 1;
937884 r.limbs[0] = 0;
......@@ -966,12 +913,7 @@ pub const Int = struct {
966913 }
967914
968915 // r = a | b
969 pub fn bitOr(r: *Int, av: var, bv: var) !void {
970 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
971 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
972 var a = wrapInt(&stack.allocator, av);
973 var b = wrapInt(&stack.allocator, bv);
974
916 pub fn bitOr(r: *Int, a: Int, b: Int) !void {
975917 if (a.len > b.len) {
976918 try r.ensureCapacity(a.len);
977919 llor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
......@@ -998,12 +940,7 @@ pub const Int = struct {
998940 }
999941
1000942 // r = a & b
1001 pub fn bitAnd(r: *Int, av: var, bv: var) !void {
1002 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
1003 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
1004 var a = wrapInt(&stack.allocator, av);
1005 var b = wrapInt(&stack.allocator, bv);
1006
943 pub fn bitAnd(r: *Int, a: Int, b: Int) !void {
1007944 if (a.len > b.len) {
1008945 try r.ensureCapacity(b.len);
1009946 lland(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
......@@ -1027,12 +964,7 @@ pub const Int = struct {
1027964 }
1028965
1029966 // r = a ^ b
1030 pub fn bitXor(r: *Int, av: var, bv: var) !void {
1031 var buffer: [2 * wrapped_buffer_size]u8 = undefined;
1032 var stack = std.heap.FixedBufferAllocator.init(buffer[0..]);
1033 var a = wrapInt(&stack.allocator, av);
1034 var b = wrapInt(&stack.allocator, bv);
1035
967 pub fn bitXor(r: *Int, a: Int, b: Int) !void {
1036968 if (a.len > b.len) {
1037969 try r.ensureCapacity(a.len);
1038970 llxor(r.limbs[0..], a.limbs[0..a.len], b.limbs[0..b.len]);
......@@ -1065,7 +997,7 @@ pub const Int = struct {
1065997// may be untested in some cases.
1066998
1067999const u256 = @IntType(false, 256);
1068var al = debug.global_allocator;
1000const al = debug.global_allocator;
10691001
10701002test "big.int comptime_int set" {
10711003 comptime var s = 0xefffffff00000001eeeeeeefaaaaaaab;
......@@ -1198,7 +1130,7 @@ test "big.int bitcount + sizeInBase" {
11981130 debug.assert(a.sizeInBase(2) >= 32);
11991131 debug.assert(a.sizeInBase(10) >= 10);
12001132
1201 try a.shiftLeft(&a, 5000);
1133 try a.shiftLeft(a, 5000);
12021134 debug.assert(a.bitcount() == 5032);
12031135 debug.assert(a.sizeInBase(2) >= 5032);
12041136 a.positive = false;
......@@ -1320,40 +1252,40 @@ test "big.int compare" {
13201252 var a = try Int.initSet(al, -11);
13211253 var b = try Int.initSet(al, 10);
13221254
1323 debug.assert(a.cmpAbs(&b) == 1);
1324 debug.assert(a.cmp(&b) == -1);
1255 debug.assert(a.cmpAbs(b) == 1);
1256 debug.assert(a.cmp(b) == -1);
13251257}
13261258
13271259test "big.int compare similar" {
13281260 var a = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeee);
13291261 var b = try Int.initSet(al, 0xffffffffeeeeeeeeffffffffeeeeeeef);
13301262
1331 debug.assert(a.cmpAbs(&b) == -1);
1332 debug.assert(b.cmpAbs(&a) == 1);
1263 debug.assert(a.cmpAbs(b) == -1);
1264 debug.assert(b.cmpAbs(a) == 1);
13331265}
13341266
13351267test "big.int compare different limb size" {
13361268 var a = try Int.initSet(al, @maxValue(Limb) + 1);
13371269 var b = try Int.initSet(al, 1);
13381270
1339 debug.assert(a.cmpAbs(&b) == 1);
1340 debug.assert(b.cmpAbs(&a) == -1);
1271 debug.assert(a.cmpAbs(b) == 1);
1272 debug.assert(b.cmpAbs(a) == -1);
13411273}
13421274
13431275test "big.int compare multi-limb" {
13441276 var a = try Int.initSet(al, -0x7777777799999999ffffeeeeffffeeeeffffeeeef);
13451277 var b = try Int.initSet(al, 0x7777777799999999ffffeeeeffffeeeeffffeeeee);
13461278
1347 debug.assert(a.cmpAbs(&b) == 1);
1348 debug.assert(a.cmp(&b) == -1);
1279 debug.assert(a.cmpAbs(b) == 1);
1280 debug.assert(a.cmp(b) == -1);
13491281}
13501282
13511283test "big.int equality" {
13521284 var a = try Int.initSet(al, 0xffffffff1);
13531285 var b = try Int.initSet(al, -0xffffffff1);
13541286
1355 debug.assert(a.eqAbs(&b));
1356 debug.assert(!a.eq(&b));
1287 debug.assert(a.eqAbs(b));
1288 debug.assert(!a.eq(b));
13571289}
13581290
13591291test "big.int abs" {
......@@ -1381,7 +1313,7 @@ test "big.int add single-single" {
13811313 var b = try Int.initSet(al, 5);
13821314
13831315 var c = try Int.init(al);
1384 try c.add(&a, &b);
1316 try c.add(a, b);
13851317
13861318 debug.assert((try c.to(u32)) == 55);
13871319}
......@@ -1392,10 +1324,10 @@ test "big.int add multi-single" {
13921324
13931325 var c = try Int.init(al);
13941326
1395 try c.add(&a, &b);
1327 try c.add(a, b);
13961328 debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
13971329
1398 try c.add(&b, &a);
1330 try c.add(b, a);
13991331 debug.assert((try c.to(DoubleLimb)) == @maxValue(Limb) + 2);
14001332}
14011333
......@@ -1406,7 +1338,7 @@ test "big.int add multi-multi" {
14061338 var b = try Int.initSet(al, op2);
14071339
14081340 var c = try Int.init(al);
1409 try c.add(&a, &b);
1341 try c.add(a, b);
14101342
14111343 debug.assert((try c.to(u128)) == op1 + op2);
14121344}
......@@ -1416,7 +1348,7 @@ test "big.int add zero-zero" {
14161348 var b = try Int.initSet(al, 0);
14171349
14181350 var c = try Int.init(al);
1419 try c.add(&a, &b);
1351 try c.add(a, b);
14201352
14211353 debug.assert((try c.to(u32)) == 0);
14221354}
......@@ -1426,7 +1358,7 @@ test "big.int add alias multi-limb nonzero-zero" {
14261358 var a = try Int.initSet(al, op1);
14271359 var b = try Int.initSet(al, 0);
14281360
1429 try a.add(&a, &b);
1361 try a.add(a, b);
14301362
14311363 debug.assert((try a.to(u128)) == op1);
14321364}
......@@ -1434,16 +1366,21 @@ test "big.int add alias multi-limb nonzero-zero" {
14341366test "big.int add sign" {
14351367 var a = try Int.init(al);
14361368
1437 try a.add(1, 2);
1369 const one = try Int.initSet(al, 1);
1370 const two = try Int.initSet(al, 2);
1371 const neg_one = try Int.initSet(al, -1);
1372 const neg_two = try Int.initSet(al, -2);
1373
1374 try a.add(one, two);
14381375 debug.assert((try a.to(i32)) == 3);
14391376
1440 try a.add(-1, 2);
1377 try a.add(neg_one, two);
14411378 debug.assert((try a.to(i32)) == 1);
14421379
1443 try a.add(1, -2);
1380 try a.add(one, neg_two);
14441381 debug.assert((try a.to(i32)) == -1);
14451382
1446 try a.add(-1, -2);
1383 try a.add(neg_one, neg_two);
14471384 debug.assert((try a.to(i32)) == -3);
14481385}
14491386
......@@ -1452,7 +1389,7 @@ test "big.int sub single-single" {
14521389 var b = try Int.initSet(al, 5);
14531390
14541391 var c = try Int.init(al);
1455 try c.sub(&a, &b);
1392 try c.sub(a, b);
14561393
14571394 debug.assert((try c.to(u32)) == 45);
14581395}
......@@ -1462,7 +1399,7 @@ test "big.int sub multi-single" {
14621399 var b = try Int.initSet(al, 1);
14631400
14641401 var c = try Int.init(al);
1465 try c.sub(&a, &b);
1402 try c.sub(a, b);
14661403
14671404 debug.assert((try c.to(Limb)) == @maxValue(Limb));
14681405}
......@@ -1475,7 +1412,7 @@ test "big.int sub multi-multi" {
14751412 var b = try Int.initSet(al, op2);
14761413
14771414 var c = try Int.init(al);
1478 try c.sub(&a, &b);
1415 try c.sub(a, b);
14791416
14801417 debug.assert((try c.to(u128)) == op1 - op2);
14811418}
......@@ -1485,7 +1422,7 @@ test "big.int sub equal" {
14851422 var b = try Int.initSet(al, 0x11efefefefefefefefefefefef);
14861423
14871424 var c = try Int.init(al);
1488 try c.sub(&a, &b);
1425 try c.sub(a, b);
14891426
14901427 debug.assert((try c.to(u32)) == 0);
14911428}
......@@ -1493,19 +1430,24 @@ test "big.int sub equal" {
14931430test "big.int sub sign" {
14941431 var a = try Int.init(al);
14951432
1496 try a.sub(1, 2);
1433 const one = try Int.initSet(al, 1);
1434 const two = try Int.initSet(al, 2);
1435 const neg_one = try Int.initSet(al, -1);
1436 const neg_two = try Int.initSet(al, -2);
1437
1438 try a.sub(one, two);
14971439 debug.assert((try a.to(i32)) == -1);
14981440
1499 try a.sub(-1, 2);
1441 try a.sub(neg_one, two);
15001442 debug.assert((try a.to(i32)) == -3);
15011443
1502 try a.sub(1, -2);
1444 try a.sub(one, neg_two);
15031445 debug.assert((try a.to(i32)) == 3);
15041446
1505 try a.sub(-1, -2);
1447 try a.sub(neg_one, neg_two);
15061448 debug.assert((try a.to(i32)) == 1);
15071449
1508 try a.sub(-2, -1);
1450 try a.sub(neg_two, neg_one);
15091451 debug.assert((try a.to(i32)) == -1);
15101452}
15111453
......@@ -1514,7 +1456,7 @@ test "big.int mul single-single" {
15141456 var b = try Int.initSet(al, 5);
15151457
15161458 var c = try Int.init(al);
1517 try c.mul(&a, &b);
1459 try c.mul(a, b);
15181460
15191461 debug.assert((try c.to(u64)) == 250);
15201462}
......@@ -1524,7 +1466,7 @@ test "big.int mul multi-single" {
15241466 var b = try Int.initSet(al, 2);
15251467
15261468 var c = try Int.init(al);
1527 try c.mul(&a, &b);
1469 try c.mul(a, b);
15281470
15291471 debug.assert((try c.to(DoubleLimb)) == 2 * @maxValue(Limb));
15301472}
......@@ -1536,7 +1478,7 @@ test "big.int mul multi-multi" {
15361478 var b = try Int.initSet(al, op2);
15371479
15381480 var c = try Int.init(al);
1539 try c.mul(&a, &b);
1481 try c.mul(a, b);
15401482
15411483 debug.assert((try c.to(u256)) == op1 * op2);
15421484}
......@@ -1545,7 +1487,7 @@ test "big.int mul alias r with a" {
15451487 var a = try Int.initSet(al, @maxValue(Limb));
15461488 var b = try Int.initSet(al, 2);
15471489
1548 try a.mul(&a, &b);
1490 try a.mul(a, b);
15491491
15501492 debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
15511493}
......@@ -1554,7 +1496,7 @@ test "big.int mul alias r with b" {
15541496 var a = try Int.initSet(al, @maxValue(Limb));
15551497 var b = try Int.initSet(al, 2);
15561498
1557 try a.mul(&b, &a);
1499 try a.mul(b, a);
15581500
15591501 debug.assert((try a.to(DoubleLimb)) == 2 * @maxValue(Limb));
15601502}
......@@ -1562,7 +1504,7 @@ test "big.int mul alias r with b" {
15621504test "big.int mul alias r with a and b" {
15631505 var a = try Int.initSet(al, @maxValue(Limb));
15641506
1565 try a.mul(&a, &a);
1507 try a.mul(a, a);
15661508
15671509 debug.assert((try a.to(DoubleLimb)) == @maxValue(Limb) * @maxValue(Limb));
15681510}
......@@ -1572,7 +1514,7 @@ test "big.int mul a*0" {
15721514 var b = try Int.initSet(al, 0);
15731515
15741516 var c = try Int.init(al);
1575 try c.mul(&a, &b);
1517 try c.mul(a, b);
15761518
15771519 debug.assert((try c.to(u32)) == 0);
15781520}
......@@ -1582,7 +1524,7 @@ test "big.int mul 0*0" {
15821524 var b = try Int.initSet(al, 0);
15831525
15841526 var c = try Int.init(al);
1585 try c.mul(&a, &b);
1527 try c.mul(a, b);
15861528
15871529 debug.assert((try c.to(u32)) == 0);
15881530}
......@@ -1593,7 +1535,7 @@ test "big.int div single-single no rem" {
15931535
15941536 var q = try Int.init(al);
15951537 var r = try Int.init(al);
1596 try Int.divTrunc(&q, &r, &a, &b);
1538 try Int.divTrunc(&q, &r, a, b);
15971539
15981540 debug.assert((try q.to(u32)) == 10);
15991541 debug.assert((try r.to(u32)) == 0);
......@@ -1605,7 +1547,7 @@ test "big.int div single-single with rem" {
16051547
16061548 var q = try Int.init(al);
16071549 var r = try Int.init(al);
1608 try Int.divTrunc(&q, &r, &a, &b);
1550 try Int.divTrunc(&q, &r, a, b);
16091551
16101552 debug.assert((try q.to(u32)) == 9);
16111553 debug.assert((try r.to(u32)) == 4);
......@@ -1620,7 +1562,7 @@ test "big.int div multi-single no rem" {
16201562
16211563 var q = try Int.init(al);
16221564 var r = try Int.init(al);
1623 try Int.divTrunc(&q, &r, &a, &b);
1565 try Int.divTrunc(&q, &r, a, b);
16241566
16251567 debug.assert((try q.to(u64)) == op1 / op2);
16261568 debug.assert((try r.to(u64)) == 0);
......@@ -1635,7 +1577,7 @@ test "big.int div multi-single with rem" {
16351577
16361578 var q = try Int.init(al);
16371579 var r = try Int.init(al);
1638 try Int.divTrunc(&q, &r, &a, &b);
1580 try Int.divTrunc(&q, &r, a, b);
16391581
16401582 debug.assert((try q.to(u64)) == op1 / op2);
16411583 debug.assert((try r.to(u64)) == 3);
......@@ -1650,7 +1592,7 @@ test "big.int div multi>2-single" {
16501592
16511593 var q = try Int.init(al);
16521594 var r = try Int.init(al);
1653 try Int.divTrunc(&q, &r, &a, &b);
1595 try Int.divTrunc(&q, &r, a, b);
16541596
16551597 debug.assert((try q.to(u128)) == op1 / op2);
16561598 debug.assert((try r.to(u32)) == 0x3e4e);
......@@ -1662,7 +1604,7 @@ test "big.int div single-single q < r" {
16621604
16631605 var q = try Int.init(al);
16641606 var r = try Int.init(al);
1665 try Int.divTrunc(&q, &r, &a, &b);
1607 try Int.divTrunc(&q, &r, a, b);
16661608
16671609 debug.assert((try q.to(u64)) == 0);
16681610 debug.assert((try r.to(u64)) == 0x0078f432);
......@@ -1674,7 +1616,7 @@ test "big.int div single-single q == r" {
16741616
16751617 var q = try Int.init(al);
16761618 var r = try Int.init(al);
1677 try Int.divTrunc(&q, &r, &a, &b);
1619 try Int.divTrunc(&q, &r, a, b);
16781620
16791621 debug.assert((try q.to(u64)) == 1);
16801622 debug.assert((try r.to(u64)) == 0);
......@@ -1684,7 +1626,7 @@ test "big.int div q=0 alias" {
16841626 var a = try Int.initSet(al, 3);
16851627 var b = try Int.initSet(al, 10);
16861628
1687 try Int.divTrunc(&a, &b, &a, &b);
1629 try Int.divTrunc(&a, &b, a, b);
16881630
16891631 debug.assert((try a.to(u64)) == 0);
16901632 debug.assert((try b.to(u64)) == 3);
......@@ -1698,7 +1640,7 @@ test "big.int div multi-multi q < r" {
16981640
16991641 var q = try Int.init(al);
17001642 var r = try Int.init(al);
1701 try Int.divTrunc(&q, &r, &a, &b);
1643 try Int.divTrunc(&q, &r, a, b);
17021644
17031645 debug.assert((try q.to(u128)) == 0);
17041646 debug.assert((try r.to(u128)) == op1);
......@@ -1713,7 +1655,7 @@ test "big.int div trunc single-single +/+" {
17131655
17141656 var q = try Int.init(al);
17151657 var r = try Int.init(al);
1716 try Int.divTrunc(&q, &r, &a, &b);
1658 try Int.divTrunc(&q, &r, a, b);
17171659
17181660 // n = q * d + r
17191661 // 5 = 1 * 3 + 2
......@@ -1733,7 +1675,7 @@ test "big.int div trunc single-single -/+" {
17331675
17341676 var q = try Int.init(al);
17351677 var r = try Int.init(al);
1736 try Int.divTrunc(&q, &r, &a, &b);
1678 try Int.divTrunc(&q, &r, a, b);
17371679
17381680 // n = q * d + r
17391681 // -5 = 1 * -3 - 2
......@@ -1753,7 +1695,7 @@ test "big.int div trunc single-single +/-" {
17531695
17541696 var q = try Int.init(al);
17551697 var r = try Int.init(al);
1756 try Int.divTrunc(&q, &r, &a, &b);
1698 try Int.divTrunc(&q, &r, a, b);
17571699
17581700 // n = q * d + r
17591701 // 5 = -1 * -3 + 2
......@@ -1773,7 +1715,7 @@ test "big.int div trunc single-single -/-" {
17731715
17741716 var q = try Int.init(al);
17751717 var r = try Int.init(al);
1776 try Int.divTrunc(&q, &r, &a, &b);
1718 try Int.divTrunc(&q, &r, a, b);
17771719
17781720 // n = q * d + r
17791721 // -5 = 1 * -3 - 2
......@@ -1793,7 +1735,7 @@ test "big.int div floor single-single +/+" {
17931735
17941736 var q = try Int.init(al);
17951737 var r = try Int.init(al);
1796 try Int.divFloor(&q, &r, &a, &b);
1738 try Int.divFloor(&q, &r, a, b);
17971739
17981740 // n = q * d + r
17991741 // 5 = 1 * 3 + 2
......@@ -1813,7 +1755,7 @@ test "big.int div floor single-single -/+" {
18131755
18141756 var q = try Int.init(al);
18151757 var r = try Int.init(al);
1816 try Int.divFloor(&q, &r, &a, &b);
1758 try Int.divFloor(&q, &r, a, b);
18171759
18181760 // n = q * d + r
18191761 // -5 = -2 * 3 + 1
......@@ -1833,7 +1775,7 @@ test "big.int div floor single-single +/-" {
18331775
18341776 var q = try Int.init(al);
18351777 var r = try Int.init(al);
1836 try Int.divFloor(&q, &r, &a, &b);
1778 try Int.divFloor(&q, &r, a, b);
18371779
18381780 // n = q * d + r
18391781 // 5 = -2 * -3 - 1
......@@ -1853,7 +1795,7 @@ test "big.int div floor single-single -/-" {
18531795
18541796 var q = try Int.init(al);
18551797 var r = try Int.init(al);
1856 try Int.divFloor(&q, &r, &a, &b);
1798 try Int.divFloor(&q, &r, a, b);
18571799
18581800 // n = q * d + r
18591801 // -5 = 2 * -3 + 1
......@@ -1870,7 +1812,7 @@ test "big.int div multi-multi with rem" {
18701812
18711813 var q = try Int.init(al);
18721814 var r = try Int.init(al);
1873 try Int.divTrunc(&q, &r, &a, &b);
1815 try Int.divTrunc(&q, &r, a, b);
18741816
18751817 debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
18761818 debug.assert((try r.to(u128)) == 0x28de0acacd806823638);
......@@ -1882,7 +1824,7 @@ test "big.int div multi-multi no rem" {
18821824
18831825 var q = try Int.init(al);
18841826 var r = try Int.init(al);
1885 try Int.divTrunc(&q, &r, &a, &b);
1827 try Int.divTrunc(&q, &r, a, b);
18861828
18871829 debug.assert((try q.to(u128)) == 0xe38f38e39161aaabd03f0f1b);
18881830 debug.assert((try r.to(u128)) == 0);
......@@ -1894,7 +1836,7 @@ test "big.int div multi-multi (2 branch)" {
18941836
18951837 var q = try Int.init(al);
18961838 var r = try Int.init(al);
1897 try Int.divTrunc(&q, &r, &a, &b);
1839 try Int.divTrunc(&q, &r, a, b);
18981840
18991841 debug.assert((try q.to(u128)) == 0x10000000000000000);
19001842 debug.assert((try r.to(u128)) == 0x44444443444444431111111111111111);
......@@ -1906,7 +1848,7 @@ test "big.int div multi-multi (3.1/3.3 branch)" {
19061848
19071849 var q = try Int.init(al);
19081850 var r = try Int.init(al);
1909 try Int.divTrunc(&q, &r, &a, &b);
1851 try Int.divTrunc(&q, &r, a, b);
19101852
19111853 debug.assert((try q.to(u128)) == 0xfffffffffffffffffff);
19121854 debug.assert((try r.to(u256)) == 0x1111111111111111111110b12222222222222222282);
......@@ -1943,17 +1885,17 @@ test "big.int shift-left multi" {
19431885test "big.int shift-right negative" {
19441886 var a = try Int.init(al);
19451887
1946 try a.shiftRight(-20, 2);
1888 try a.shiftRight(try Int.initSet(al, -20), 2);
19471889 debug.assert((try a.to(i32)) == -20 >> 2);
19481890
1949 try a.shiftRight(-5, 10);
1891 try a.shiftRight(try Int.initSet(al, -5), 10);
19501892 debug.assert((try a.to(i32)) == -5 >> 10);
19511893}
19521894
19531895test "big.int shift-left negative" {
19541896 var a = try Int.init(al);
19551897
1956 try a.shiftRight(-10, 1232);
1898 try a.shiftRight(try Int.initSet(al, -10), 1232);
19571899 debug.assert((try a.to(i32)) == -10 >> 1232);
19581900}
19591901
......@@ -1961,7 +1903,7 @@ test "big.int bitwise and simple" {
19611903 var a = try Int.initSet(al, 0xffffffff11111111);
19621904 var b = try Int.initSet(al, 0xeeeeeeee22222222);
19631905
1964 try a.bitAnd(&a, &b);
1906 try a.bitAnd(a, b);
19651907
19661908 debug.assert((try a.to(u64)) == 0xeeeeeeee00000000);
19671909}
......@@ -1970,7 +1912,7 @@ test "big.int bitwise and multi-limb" {
19701912 var a = try Int.initSet(al, @maxValue(Limb) + 1);
19711913 var b = try Int.initSet(al, @maxValue(Limb));
19721914
1973 try a.bitAnd(&a, &b);
1915 try a.bitAnd(a, b);
19741916
19751917 debug.assert((try a.to(u128)) == 0);
19761918}
......@@ -1979,7 +1921,7 @@ test "big.int bitwise xor simple" {
19791921 var a = try Int.initSet(al, 0xffffffff11111111);
19801922 var b = try Int.initSet(al, 0xeeeeeeee22222222);
19811923
1982 try a.bitXor(&a, &b);
1924 try a.bitXor(a, b);
19831925
19841926 debug.assert((try a.to(u64)) == 0x1111111133333333);
19851927}
......@@ -1988,7 +1930,7 @@ test "big.int bitwise xor multi-limb" {
19881930 var a = try Int.initSet(al, @maxValue(Limb) + 1);
19891931 var b = try Int.initSet(al, @maxValue(Limb));
19901932
1991 try a.bitXor(&a, &b);
1933 try a.bitXor(a, b);
19921934
19931935 debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) ^ @maxValue(Limb));
19941936}
......@@ -1997,7 +1939,7 @@ test "big.int bitwise or simple" {
19971939 var a = try Int.initSet(al, 0xffffffff11111111);
19981940 var b = try Int.initSet(al, 0xeeeeeeee22222222);
19991941
2000 try a.bitOr(&a, &b);
1942 try a.bitOr(a, b);
20011943
20021944 debug.assert((try a.to(u64)) == 0xffffffff33333333);
20031945}
......@@ -2006,7 +1948,7 @@ test "big.int bitwise or multi-limb" {
20061948 var a = try Int.initSet(al, @maxValue(Limb) + 1);
20071949 var b = try Int.initSet(al, @maxValue(Limb));
20081950
2009 try a.bitOr(&a, &b);
1951 try a.bitOr(a, b);
20101952
20111953 // TODO: big.int.cpp or is wrong on multi-limb.
20121954 debug.assert((try a.to(DoubleLimb)) == (@maxValue(Limb) + 1) + @maxValue(Limb));
......@@ -2015,9 +1957,9 @@ test "big.int bitwise or multi-limb" {
20151957test "big.int var args" {
20161958 var a = try Int.initSet(al, 5);
20171959
2018 try a.add(&a, 6);
1960 try a.add(a, try Int.initSet(al, 6));
20191961 debug.assert((try a.to(u64)) == 11);
20201962
2021 debug.assert(a.cmp(11) == 0);
2022 debug.assert(a.cmp(14) <= 0);
1963 debug.assert(a.cmp(try Int.initSet(al, 11)) == 0);
1964 debug.assert(a.cmp(try Int.initSet(al, 14)) <= 0);
20231965}
std/mem.zig+3-7
......@@ -40,16 +40,12 @@ pub const Allocator = struct {
4040
4141 /// Call destroy with the result
4242 /// TODO once #733 is solved, this will replace create
43 pub fn construct(self: *Allocator, init: var) t: {
44 // TODO this is a workaround for type getting parsed as Error!&const T
45 const T = @typeOf(init).Child;
46 break :t Error!*T;
47 } {
48 const T = @typeOf(init).Child;
43 pub fn construct(self: *Allocator, init: var) Error!*@typeOf(init) {
44 const T = @typeOf(init);
4945 if (@sizeOf(T) == 0) return &{};
5046 const slice = try self.alloc(T, 1);
5147 const ptr = &slice[0];
52 ptr.* = init.*;
48 ptr.* = init;
5349 return ptr;
5450 }
5551
test/behavior.zig+1
......@@ -13,6 +13,7 @@ comptime {
1313 _ = @import("cases/bugs/656.zig");
1414 _ = @import("cases/bugs/828.zig");
1515 _ = @import("cases/bugs/920.zig");
16 _ = @import("cases/byval_arg_var.zig");
1617 _ = @import("cases/cast.zig");
1718 _ = @import("cases/const_slice_child.zig");
1819 _ = @import("cases/coroutines.zig");
test/cases/byval_arg_var.zig created+27
......@@ -0,0 +1,27 @@
1const std = @import("std");
2
3var result: []const u8 = "wrong";
4
5test "aoeu" {
6 start();
7 blowUpStack(10);
8
9 std.debug.assert(std.mem.eql(u8, result, "string literal"));
10}
11
12fn start() void {
13 foo("string literal");
14}
15
16fn foo(x: var) void {
17 bar(x);
18}
19
20fn bar(x: var) void {
21 result = x;
22}
23
24fn blowUpStack(x: u32) void {
25 if (x == 0) return;
26 blowUpStack(x - 1);
27}
test/cases/cast.zig-8
......@@ -318,14 +318,6 @@ fn testCastConstArrayRefToConstSlice() void {
318318 assert(mem.eql(u8, slice, "aoeu"));
319319}
320320
321test "var args implicitly casts by value arg to const ref" {
322 foo("hello");
323}
324
325fn foo(args: ...) void {
326 assert(@typeOf(args[0]) == *const [5]u8);
327}
328
329321test "peer type resolution: error and [N]T" {
330322 // TODO: implicit error!T to error!U where T can implicitly cast to U
331323 //assert(mem.eql(u8, try testPeerErrorAndArray(0), "OK"));
test/cases/fn.zig+57
......@@ -119,3 +119,60 @@ test "assign inline fn to const variable" {
119119}
120120
121121inline fn inlineFn() void {}
122
123test "pass by non-copying value" {
124 assert(addPointCoords(Point{ .x = 1, .y = 2 }) == 3);
125}
126
127const Point = struct {
128 x: i32,
129 y: i32,
130};
131
132fn addPointCoords(pt: Point) i32 {
133 return pt.x + pt.y;
134}
135
136test "pass by non-copying value through var arg" {
137 assert(addPointCoordsVar(Point{ .x = 1, .y = 2 }) == 3);
138}
139
140fn addPointCoordsVar(pt: var) i32 {
141 comptime assert(@typeOf(pt) == Point);
142 return pt.x + pt.y;
143}
144
145test "pass by non-copying value as method" {
146 var pt = Point2{ .x = 1, .y = 2 };
147 assert(pt.addPointCoords() == 3);
148}
149
150const Point2 = struct {
151 x: i32,
152 y: i32,
153
154 fn addPointCoords(self: Point2) i32 {
155 return self.x + self.y;
156 }
157};
158
159test "pass by non-copying value as method, which is generic" {
160 var pt = Point3{ .x = 1, .y = 2 };
161 assert(pt.addPointCoords(i32) == 3);
162}
163
164const Point3 = struct {
165 x: i32,
166 y: i32,
167
168 fn addPointCoords(self: Point3, comptime T: type) i32 {
169 return self.x + self.y;
170 }
171};
172
173test "pass by non-copying value as method, at comptime" {
174 comptime {
175 var pt = Point2{ .x = 1, .y = 2 };
176 assert(pt.addPointCoords() == 3);
177 }
178}
test/cases/var_args.zig-12
......@@ -75,18 +75,6 @@ test "array of var args functions" {
7575 assert(!foos[1]());
7676}
7777
78test "pass array and slice of same array to var args should have same pointers" {
79 const array = "hi";
80 const slice: []const u8 = array;
81 return assertSlicePtrsEql(array, slice);
82}
83
84fn assertSlicePtrsEql(args: ...) void {
85 const s1 = ([]const u8)(args[0]);
86 const s2 = args[1];
87 assert(s1.ptr == s2.ptr);
88}
89
9078test "pass zero length array to var args param" {
9179 doNothingWithFirstArg("");
9280}
test/compile_errors.zig+1-24
......@@ -2215,7 +2215,7 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
22152215 \\ derp.init();
22162216 \\}
22172217 ,
2218 ".tmp_source.zig:14:5: error: expected type 'i32', found '*const Foo'",
2218 ".tmp_source.zig:14:5: error: expected type 'i32', found 'Foo'",
22192219 );
22202220
22212221 cases.add(
......@@ -2573,15 +2573,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
25732573 break :x tc;
25742574 });
25752575
2576 cases.add(
2577 "pass non-copyable type by value to function",
2578 \\const Point = struct { x: i32, y: i32, };
2579 \\fn foo(p: Point) void { }
2580 \\export fn entry() usize { return @sizeOf(@typeOf(foo)); }
2581 ,
2582 ".tmp_source.zig:2:11: error: type 'Point' is not copyable; cannot pass by value",
2583 );
2584
25852576 cases.add(
25862577 "implicit cast from array to mutable slice",
25872578 \\var global_array: [10]i32 = undefined;
......@@ -4066,20 +4057,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
40664057 ".tmp_source.zig:3:5: note: field 'A' has type 'i32'",
40674058 );
40684059
4069 cases.add(
4070 "self-referencing function pointer field",
4071 \\const S = struct {
4072 \\ f: fn(_: S) void,
4073 \\};
4074 \\fn f(_: S) void {
4075 \\}
4076 \\export fn entry() void {
4077 \\ var _ = S { .f = f };
4078 \\}
4079 ,
4080 ".tmp_source.zig:4:9: error: type 'S' is not copyable; cannot pass by value",
4081 );
4082
40834060 cases.add(
40844061 "taking offset of void field in struct",
40854062 \\const Empty = struct {