| author | |
| committer | |
| log | 17f057c5568bda6b011a213c95aa9538f6fb6a78 |
| tree | d988df1935461c2b28f88cea5f6f50effb240128 |
| parent | f0deef1d79db272fa80ef0323b4382ee1936a3e4 |
* stage1: change the `@typeName` of `@TypeOf(undefined)`,
`@TypeOf(null)`, and `@TypeOf(.foo)` to match stage2.
* move passing behavior tests to the passing-for-stage2 section.16 files changed, 369 insertions(+), 263 deletions(-)
src/Sema.zig+21-13| ... | ... | @@ -2771,20 +2771,16 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins |
| 2771 | 2771 | // expression of a variable declaration. We need the memory to be in the new |
| 2772 | 2772 | // anonymous Decl's arena. |
| 2773 | 2773 | |
| 2774 | var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); | |
| 2775 | errdefer new_decl_arena.deinit(); | |
| 2774 | var anon_decl = try block.startAnonDecl(); | |
| 2775 | defer anon_decl.deinit(); | |
| 2776 | 2776 | |
| 2777 | const bytes = try new_decl_arena.allocator.dupeZ(u8, zir_bytes); | |
| 2777 | const bytes = try anon_decl.arena().dupeZ(u8, zir_bytes); | |
| 2778 | 2778 | |
| 2779 | const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len); | |
| 2780 | const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes[0 .. bytes.len + 1]); | |
| 2779 | const new_decl = try anon_decl.finish( | |
| 2780 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | |
| 2781 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 2782 | ); | |
| 2781 | 2783 | |
| 2782 | const new_decl = try sema.mod.createAnonymousDecl(block, .{ | |
| 2783 | .ty = decl_ty, | |
| 2784 | .val = decl_val, | |
| 2785 | }); | |
| 2786 | errdefer sema.mod.abortAnonDecl(new_decl); | |
| 2787 | try new_decl.finalizeNewArena(&new_decl_arena); | |
| 2788 | 2784 | return sema.analyzeDeclRef(new_decl); |
| 2789 | 2785 | } |
| 2790 | 2786 | |
| ... | ... | @@ -9741,8 +9737,20 @@ fn zirReify(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I |
| 9741 | 9737 | |
| 9742 | 9738 | fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 9743 | 9739 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; |
| 9744 | const src = inst_data.src(); | |
| 9745 | return sema.fail(block, src, "TODO: Sema.zirTypeName", .{}); | |
| 9740 | const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; | |
| 9741 | const ty = try sema.resolveType(block, ty_src, inst_data.operand); | |
| 9742 | ||
| 9743 | var anon_decl = try block.startAnonDecl(); | |
| 9744 | defer anon_decl.deinit(); | |
| 9745 | ||
| 9746 | const bytes = try ty.nameAlloc(anon_decl.arena()); | |
| 9747 | ||
| 9748 | const new_decl = try anon_decl.finish( | |
| 9749 | try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len), | |
| 9750 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | |
| 9751 | ); | |
| 9752 | ||
| 9753 | return sema.analyzeDeclRef(new_decl); | |
| 9746 | 9754 | } |
| 9747 | 9755 | |
| 9748 | 9756 | fn zirFrameType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
src/stage1/codegen.cpp+3-3| ... | ... | @@ -8755,17 +8755,17 @@ static void define_builtin_types(CodeGen *g) { |
| 8755 | 8755 | } |
| 8756 | 8756 | { |
| 8757 | 8757 | ZigType *entry = new_type_table_entry(ZigTypeIdEnumLiteral); |
| 8758 | buf_init_from_str(&entry->name, "(enum literal)"); | |
| 8758 | buf_init_from_str(&entry->name, "@Type(.EnumLiteral)"); | |
| 8759 | 8759 | g->builtin_types.entry_enum_literal = entry; |
| 8760 | 8760 | } |
| 8761 | 8761 | { |
| 8762 | 8762 | ZigType *entry = new_type_table_entry(ZigTypeIdUndefined); |
| 8763 | buf_init_from_str(&entry->name, "(undefined)"); | |
| 8763 | buf_init_from_str(&entry->name, "@Type(.Undefined)"); | |
| 8764 | 8764 | g->builtin_types.entry_undef = entry; |
| 8765 | 8765 | } |
| 8766 | 8766 | { |
| 8767 | 8767 | ZigType *entry = new_type_table_entry(ZigTypeIdNull); |
| 8768 | buf_init_from_str(&entry->name, "(null)"); | |
| 8768 | buf_init_from_str(&entry->name, "@Type(.Null)"); | |
| 8769 | 8769 | g->builtin_types.entry_null = entry; |
| 8770 | 8770 | } |
| 8771 | 8771 | { |
src/type.zig+107| ... | ... | @@ -1197,6 +1197,113 @@ pub const Type = extern union { |
| 1197 | 1197 | } |
| 1198 | 1198 | } |
| 1199 | 1199 | |
| 1200 | /// Returns a name suitable for `@typeName`. | |
| 1201 | pub fn nameAlloc(ty: Type, arena: *Allocator) Allocator.Error![:0]const u8 { | |
| 1202 | const t = ty.tag(); | |
| 1203 | switch (t) { | |
| 1204 | .inferred_alloc_const => unreachable, | |
| 1205 | .inferred_alloc_mut => unreachable, | |
| 1206 | .generic_poison => unreachable, | |
| 1207 | ||
| 1208 | .u1, | |
| 1209 | .u8, | |
| 1210 | .i8, | |
| 1211 | .u16, | |
| 1212 | .i16, | |
| 1213 | .u32, | |
| 1214 | .i32, | |
| 1215 | .u64, | |
| 1216 | .i64, | |
| 1217 | .u128, | |
| 1218 | .i128, | |
| 1219 | .usize, | |
| 1220 | .isize, | |
| 1221 | .c_short, | |
| 1222 | .c_ushort, | |
| 1223 | .c_int, | |
| 1224 | .c_uint, | |
| 1225 | .c_long, | |
| 1226 | .c_ulong, | |
| 1227 | .c_longlong, | |
| 1228 | .c_ulonglong, | |
| 1229 | .c_longdouble, | |
| 1230 | .c_void, | |
| 1231 | .f16, | |
| 1232 | .f32, | |
| 1233 | .f64, | |
| 1234 | .f128, | |
| 1235 | .bool, | |
| 1236 | .void, | |
| 1237 | .type, | |
| 1238 | .anyerror, | |
| 1239 | .@"anyframe", | |
| 1240 | .comptime_int, | |
| 1241 | .comptime_float, | |
| 1242 | .noreturn, | |
| 1243 | .var_args_param, | |
| 1244 | .bound_fn, | |
| 1245 | => return @tagName(t), | |
| 1246 | ||
| 1247 | .enum_literal => return "@Type(.EnumLiteral)", | |
| 1248 | .@"null" => return "@Type(.Null)", | |
| 1249 | .@"undefined" => return "@Type(.Undefined)", | |
| 1250 | ||
| 1251 | .empty_struct, .empty_struct_literal => return "struct {}", | |
| 1252 | ||
| 1253 | .@"struct" => { | |
| 1254 | const struct_obj = ty.castTag(.@"struct").?.data; | |
| 1255 | return try arena.dupeZ(u8, std.mem.sliceTo(struct_obj.owner_decl.name, 0)); | |
| 1256 | }, | |
| 1257 | .@"union", .union_tagged => { | |
| 1258 | const union_obj = ty.cast(Payload.Union).?.data; | |
| 1259 | return try arena.dupeZ(u8, std.mem.sliceTo(union_obj.owner_decl.name, 0)); | |
| 1260 | }, | |
| 1261 | .enum_full, .enum_nonexhaustive => { | |
| 1262 | const enum_full = ty.cast(Payload.EnumFull).?.data; | |
| 1263 | return try arena.dupeZ(u8, std.mem.sliceTo(enum_full.owner_decl.name, 0)); | |
| 1264 | }, | |
| 1265 | .enum_simple => { | |
| 1266 | const enum_simple = ty.castTag(.enum_simple).?.data; | |
| 1267 | return try arena.dupeZ(u8, std.mem.sliceTo(enum_simple.owner_decl.name, 0)); | |
| 1268 | }, | |
| 1269 | .enum_numbered => { | |
| 1270 | const enum_numbered = ty.castTag(.enum_numbered).?.data; | |
| 1271 | return try arena.dupeZ(u8, std.mem.sliceTo(enum_numbered.owner_decl.name, 0)); | |
| 1272 | }, | |
| 1273 | .@"opaque" => { | |
| 1274 | // TODO use declaration name | |
| 1275 | return "opaque {}"; | |
| 1276 | }, | |
| 1277 | ||
| 1278 | .anyerror_void_error_union => return "anyerror!void", | |
| 1279 | .const_slice_u8 => return "[]const u8", | |
| 1280 | .fn_noreturn_no_args => return "fn() noreturn", | |
| 1281 | .fn_void_no_args => return "fn() void", | |
| 1282 | .fn_naked_noreturn_no_args => return "fn() callconv(.Naked) noreturn", | |
| 1283 | .fn_ccc_void_no_args => return "fn() callconv(.C) void", | |
| 1284 | .single_const_pointer_to_comptime_int => return "*const comptime_int", | |
| 1285 | .manyptr_u8 => return "[*]u8", | |
| 1286 | .manyptr_const_u8 => return "[*]const u8", | |
| 1287 | .atomic_order => return "AtomicOrder", | |
| 1288 | .atomic_rmw_op => return "AtomicRmwOp", | |
| 1289 | .calling_convention => return "CallingConvention", | |
| 1290 | .address_space => return "AddressSpace", | |
| 1291 | .float_mode => return "FloatMode", | |
| 1292 | .reduce_op => return "ReduceOp", | |
| 1293 | .call_options => return "CallOptions", | |
| 1294 | .export_options => return "ExportOptions", | |
| 1295 | .extern_options => return "ExternOptions", | |
| 1296 | .type_info => return "TypeInfo", | |
| 1297 | ||
| 1298 | else => { | |
| 1299 | // TODO this is wasteful and also an incorrect implementation of `@typeName` | |
| 1300 | var buf = std.ArrayList(u8).init(arena); | |
| 1301 | try buf.writer().print("{}", .{ty}); | |
| 1302 | return try buf.toOwnedSliceSentinel(0); | |
| 1303 | }, | |
| 1304 | } | |
| 1305 | } | |
| 1306 | ||
| 1200 | 1307 | /// Anything that reports hasCodeGenBits() false returns false here as well. |
| 1201 | 1308 | /// `generic_poison` will return false. |
| 1202 | 1309 | pub fn requiresComptime(ty: Type) bool { |
test/behavior.zig+3-4| ... | ... | @@ -24,11 +24,11 @@ test { |
| 24 | 24 | _ = @import("behavior/defer.zig"); |
| 25 | 25 | _ = @import("behavior/enum.zig"); |
| 26 | 26 | _ = @import("behavior/error.zig"); |
| 27 | _ = @import("behavior/error.zig"); | |
| 28 | 27 | _ = @import("behavior/generics.zig"); |
| 29 | 28 | _ = @import("behavior/hasdecl.zig"); |
| 30 | 29 | _ = @import("behavior/hasfield.zig"); |
| 31 | 30 | _ = @import("behavior/if.zig"); |
| 31 | _ = @import("behavior/import.zig"); | |
| 32 | 32 | _ = @import("behavior/int128.zig"); |
| 33 | 33 | _ = @import("behavior/member_func.zig"); |
| 34 | 34 | _ = @import("behavior/null.zig"); |
| ... | ... | @@ -73,7 +73,9 @@ test { |
| 73 | 73 | _ = @import("behavior/slice.zig"); |
| 74 | 74 | _ = @import("behavior/struct_llvm.zig"); |
| 75 | 75 | _ = @import("behavior/switch.zig"); |
| 76 | _ = @import("behavior/undefined.zig"); | |
| 76 | 77 | _ = @import("behavior/union.zig"); |
| 78 | _ = @import("behavior/void.zig"); | |
| 77 | 79 | _ = @import("behavior/widening.zig"); |
| 78 | 80 | |
| 79 | 81 | if (builtin.zig_is_stage2) { |
| ... | ... | @@ -151,7 +153,6 @@ test { |
| 151 | 153 | _ = @import("behavior/fn_in_struct_in_comptime.zig"); |
| 152 | 154 | _ = @import("behavior/for_stage1.zig"); |
| 153 | 155 | _ = @import("behavior/if_stage1.zig"); |
| 154 | _ = @import("behavior/import.zig"); | |
| 155 | 156 | _ = @import("behavior/incomplete_struct_param_tld.zig"); |
| 156 | 157 | _ = @import("behavior/inttoptr.zig"); |
| 157 | 158 | _ = @import("behavior/ir_block_deps.zig"); |
| ... | ... | @@ -183,13 +184,11 @@ test { |
| 183 | 184 | _ = @import("behavior/type.zig"); |
| 184 | 185 | _ = @import("behavior/type_info.zig"); |
| 185 | 186 | _ = @import("behavior/typename.zig"); |
| 186 | _ = @import("behavior/undefined.zig"); | |
| 187 | 187 | _ = @import("behavior/union_stage1.zig"); |
| 188 | 188 | _ = @import("behavior/union_with_members.zig"); |
| 189 | 189 | _ = @import("behavior/usingnamespace_stage1.zig"); |
| 190 | 190 | _ = @import("behavior/var_args.zig"); |
| 191 | 191 | _ = @import("behavior/vector.zig"); |
| 192 | _ = @import("behavior/void.zig"); | |
| 193 | 192 | if (builtin.target.cpu.arch == .wasm32) { |
| 194 | 193 | _ = @import("behavior/wasm.zig"); |
| 195 | 194 | } |
test/behavior/enum.zig+22| ... | ... | @@ -583,3 +583,25 @@ test "peer type resolution with enum literal" { |
| 583 | 583 | try expect(Items.two == .two); |
| 584 | 584 | try expect(.two == Items.two); |
| 585 | 585 | } |
| 586 | ||
| 587 | const MultipleChoice = enum(u32) { | |
| 588 | A = 20, | |
| 589 | B = 40, | |
| 590 | C = 60, | |
| 591 | D = 1000, | |
| 592 | }; | |
| 593 | ||
| 594 | fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void { | |
| 595 | try expect(@enumToInt(x) == 60); | |
| 596 | try expect(1234 == switch (x) { | |
| 597 | MultipleChoice.A => 1, | |
| 598 | MultipleChoice.B => 2, | |
| 599 | MultipleChoice.C => @as(u32, 1234), | |
| 600 | MultipleChoice.D => 4, | |
| 601 | }); | |
| 602 | } | |
| 603 | ||
| 604 | test "enum with specified tag values" { | |
| 605 | try testEnumWithSpecifiedTagValues(MultipleChoice.C); | |
| 606 | comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C); | |
| 607 | } |
test/behavior/enum_stage1.zig-22| ... | ... | @@ -2,28 +2,6 @@ const expect = @import("std").testing.expect; |
| 2 | 2 | const mem = @import("std").mem; |
| 3 | 3 | const Tag = @import("std").meta.Tag; |
| 4 | 4 | |
| 5 | const MultipleChoice = enum(u32) { | |
| 6 | A = 20, | |
| 7 | B = 40, | |
| 8 | C = 60, | |
| 9 | D = 1000, | |
| 10 | }; | |
| 11 | ||
| 12 | fn testEnumWithSpecifiedTagValues(x: MultipleChoice) !void { | |
| 13 | try expect(@enumToInt(x) == 60); | |
| 14 | try expect(1234 == switch (x) { | |
| 15 | MultipleChoice.A => 1, | |
| 16 | MultipleChoice.B => 2, | |
| 17 | MultipleChoice.C => @as(u32, 1234), | |
| 18 | MultipleChoice.D => 4, | |
| 19 | }); | |
| 20 | } | |
| 21 | ||
| 22 | test "enum with specified tag values" { | |
| 23 | try testEnumWithSpecifiedTagValues(MultipleChoice.C); | |
| 24 | comptime try testEnumWithSpecifiedTagValues(MultipleChoice.C); | |
| 25 | } | |
| 26 | ||
| 27 | 5 | test "non-exhaustive enum" { |
| 28 | 6 | const S = struct { |
| 29 | 7 | const E = enum(u8) { |
test/behavior/fn.zig+81| ... | ... | @@ -163,3 +163,84 @@ fn fComplexCallconvRet(x: u32) callconv(blk: { |
| 163 | 163 | test "function with complex callconv and return type expressions" { |
| 164 | 164 | try expect(fComplexCallconvRet(3).x == 9); |
| 165 | 165 | } |
| 166 | ||
| 167 | test "pass by non-copying value" { | |
| 168 | try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); | |
| 169 | } | |
| 170 | ||
| 171 | const Point = struct { | |
| 172 | x: i32, | |
| 173 | y: i32, | |
| 174 | }; | |
| 175 | ||
| 176 | fn addPointCoords(pt: Point) i32 { | |
| 177 | return pt.x + pt.y; | |
| 178 | } | |
| 179 | ||
| 180 | test "pass by non-copying value through var arg" { | |
| 181 | try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3); | |
| 182 | } | |
| 183 | ||
| 184 | fn addPointCoordsVar(pt: anytype) !i32 { | |
| 185 | comptime try expect(@TypeOf(pt) == Point); | |
| 186 | return pt.x + pt.y; | |
| 187 | } | |
| 188 | ||
| 189 | test "pass by non-copying value as method" { | |
| 190 | var pt = Point2{ .x = 1, .y = 2 }; | |
| 191 | try expect(pt.addPointCoords() == 3); | |
| 192 | } | |
| 193 | ||
| 194 | const Point2 = struct { | |
| 195 | x: i32, | |
| 196 | y: i32, | |
| 197 | ||
| 198 | fn addPointCoords(self: Point2) i32 { | |
| 199 | return self.x + self.y; | |
| 200 | } | |
| 201 | }; | |
| 202 | ||
| 203 | test "pass by non-copying value as method, which is generic" { | |
| 204 | var pt = Point3{ .x = 1, .y = 2 }; | |
| 205 | try expect(pt.addPointCoords(i32) == 3); | |
| 206 | } | |
| 207 | ||
| 208 | const Point3 = struct { | |
| 209 | x: i32, | |
| 210 | y: i32, | |
| 211 | ||
| 212 | fn addPointCoords(self: Point3, comptime T: type) i32 { | |
| 213 | _ = T; | |
| 214 | return self.x + self.y; | |
| 215 | } | |
| 216 | }; | |
| 217 | ||
| 218 | test "pass by non-copying value as method, at comptime" { | |
| 219 | comptime { | |
| 220 | var pt = Point2{ .x = 1, .y = 2 }; | |
| 221 | try expect(pt.addPointCoords() == 3); | |
| 222 | } | |
| 223 | } | |
| 224 | ||
| 225 | test "implicit cast fn call result to optional in field result" { | |
| 226 | const S = struct { | |
| 227 | fn entry() !void { | |
| 228 | var x = Foo{ | |
| 229 | .field = optionalPtr(), | |
| 230 | }; | |
| 231 | try expect(x.field.?.* == 999); | |
| 232 | } | |
| 233 | ||
| 234 | const glob: i32 = 999; | |
| 235 | ||
| 236 | fn optionalPtr() *const i32 { | |
| 237 | return &glob; | |
| 238 | } | |
| 239 | ||
| 240 | const Foo = struct { | |
| 241 | field: ?*const i32, | |
| 242 | }; | |
| 243 | }; | |
| 244 | try S.entry(); | |
| 245 | comptime try S.entry(); | |
| 246 | } |
test/behavior/fn_stage1.zig-81| ... | ... | @@ -56,87 +56,6 @@ fn numberLiteralArg(a: anytype) !void { |
| 56 | 56 | try expect(a == 3); |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | test "pass by non-copying value" { | |
| 60 | try expect(addPointCoords(Point{ .x = 1, .y = 2 }) == 3); | |
| 61 | } | |
| 62 | ||
| 63 | const Point = struct { | |
| 64 | x: i32, | |
| 65 | y: i32, | |
| 66 | }; | |
| 67 | ||
| 68 | fn addPointCoords(pt: Point) i32 { | |
| 69 | return pt.x + pt.y; | |
| 70 | } | |
| 71 | ||
| 72 | test "pass by non-copying value through var arg" { | |
| 73 | try expect((try addPointCoordsVar(Point{ .x = 1, .y = 2 })) == 3); | |
| 74 | } | |
| 75 | ||
| 76 | fn addPointCoordsVar(pt: anytype) !i32 { | |
| 77 | comptime try expect(@TypeOf(pt) == Point); | |
| 78 | return pt.x + pt.y; | |
| 79 | } | |
| 80 | ||
| 81 | test "pass by non-copying value as method" { | |
| 82 | var pt = Point2{ .x = 1, .y = 2 }; | |
| 83 | try expect(pt.addPointCoords() == 3); | |
| 84 | } | |
| 85 | ||
| 86 | const Point2 = struct { | |
| 87 | x: i32, | |
| 88 | y: i32, | |
| 89 | ||
| 90 | fn addPointCoords(self: Point2) i32 { | |
| 91 | return self.x + self.y; | |
| 92 | } | |
| 93 | }; | |
| 94 | ||
| 95 | test "pass by non-copying value as method, which is generic" { | |
| 96 | var pt = Point3{ .x = 1, .y = 2 }; | |
| 97 | try expect(pt.addPointCoords(i32) == 3); | |
| 98 | } | |
| 99 | ||
| 100 | const Point3 = struct { | |
| 101 | x: i32, | |
| 102 | y: i32, | |
| 103 | ||
| 104 | fn addPointCoords(self: Point3, comptime T: type) i32 { | |
| 105 | _ = T; | |
| 106 | return self.x + self.y; | |
| 107 | } | |
| 108 | }; | |
| 109 | ||
| 110 | test "pass by non-copying value as method, at comptime" { | |
| 111 | comptime { | |
| 112 | var pt = Point2{ .x = 1, .y = 2 }; | |
| 113 | try expect(pt.addPointCoords() == 3); | |
| 114 | } | |
| 115 | } | |
| 116 | ||
| 117 | test "implicit cast fn call result to optional in field result" { | |
| 118 | const S = struct { | |
| 119 | fn entry() !void { | |
| 120 | var x = Foo{ | |
| 121 | .field = optionalPtr(), | |
| 122 | }; | |
| 123 | try expect(x.field.?.* == 999); | |
| 124 | } | |
| 125 | ||
| 126 | const glob: i32 = 999; | |
| 127 | ||
| 128 | fn optionalPtr() *const i32 { | |
| 129 | return &glob; | |
| 130 | } | |
| 131 | ||
| 132 | const Foo = struct { | |
| 133 | field: ?*const i32, | |
| 134 | }; | |
| 135 | }; | |
| 136 | try S.entry(); | |
| 137 | comptime try S.entry(); | |
| 138 | } | |
| 139 | ||
| 140 | 59 | test "function call with anon list literal" { |
| 141 | 60 | const S = struct { |
| 142 | 61 | fn doTheTest() !void { |
test/behavior/for.zig+56| ... | ... | @@ -60,3 +60,59 @@ test "ignore lval with underscore (for loop)" { |
| 60 | 60 | break; |
| 61 | 61 | } |
| 62 | 62 | } |
| 63 | ||
| 64 | test "basic for loop" { | |
| 65 | const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; | |
| 66 | ||
| 67 | var buffer: [expected_result.len]u8 = undefined; | |
| 68 | var buf_index: usize = 0; | |
| 69 | ||
| 70 | const array = [_]u8{ 9, 8, 7, 6 }; | |
| 71 | for (array) |item| { | |
| 72 | buffer[buf_index] = item; | |
| 73 | buf_index += 1; | |
| 74 | } | |
| 75 | for (array) |item, index| { | |
| 76 | _ = item; | |
| 77 | buffer[buf_index] = @intCast(u8, index); | |
| 78 | buf_index += 1; | |
| 79 | } | |
| 80 | const array_ptr = &array; | |
| 81 | for (array_ptr) |item| { | |
| 82 | buffer[buf_index] = item; | |
| 83 | buf_index += 1; | |
| 84 | } | |
| 85 | for (array_ptr) |item, index| { | |
| 86 | _ = item; | |
| 87 | buffer[buf_index] = @intCast(u8, index); | |
| 88 | buf_index += 1; | |
| 89 | } | |
| 90 | const unknown_size: []const u8 = &array; | |
| 91 | for (unknown_size) |item| { | |
| 92 | buffer[buf_index] = item; | |
| 93 | buf_index += 1; | |
| 94 | } | |
| 95 | for (unknown_size) |_, index| { | |
| 96 | buffer[buf_index] = @intCast(u8, index); | |
| 97 | buf_index += 1; | |
| 98 | } | |
| 99 | ||
| 100 | try expect(mem.eql(u8, buffer[0..buf_index], &expected_result)); | |
| 101 | } | |
| 102 | ||
| 103 | test "for with null and T peer types and inferred result location type" { | |
| 104 | const S = struct { | |
| 105 | fn doTheTest(slice: []const u8) !void { | |
| 106 | if (for (slice) |item| { | |
| 107 | if (item == 10) { | |
| 108 | break item; | |
| 109 | } | |
| 110 | } else null) |v| { | |
| 111 | _ = v; | |
| 112 | @panic("fail"); | |
| 113 | } | |
| 114 | } | |
| 115 | }; | |
| 116 | try S.doTheTest(&[_]u8{ 1, 2 }); | |
| 117 | comptime try S.doTheTest(&[_]u8{ 1, 2 }); | |
| 118 | } |
test/behavior/for_stage1.zig-56| ... | ... | @@ -26,45 +26,6 @@ fn mangleString(s: []u8) void { |
| 26 | 26 | } |
| 27 | 27 | } |
| 28 | 28 | |
| 29 | test "basic for loop" { | |
| 30 | const expected_result = [_]u8{ 9, 8, 7, 6, 0, 1, 2, 3 } ** 3; | |
| 31 | ||
| 32 | var buffer: [expected_result.len]u8 = undefined; | |
| 33 | var buf_index: usize = 0; | |
| 34 | ||
| 35 | const array = [_]u8{ 9, 8, 7, 6 }; | |
| 36 | for (array) |item| { | |
| 37 | buffer[buf_index] = item; | |
| 38 | buf_index += 1; | |
| 39 | } | |
| 40 | for (array) |item, index| { | |
| 41 | _ = item; | |
| 42 | buffer[buf_index] = @intCast(u8, index); | |
| 43 | buf_index += 1; | |
| 44 | } | |
| 45 | const array_ptr = &array; | |
| 46 | for (array_ptr) |item| { | |
| 47 | buffer[buf_index] = item; | |
| 48 | buf_index += 1; | |
| 49 | } | |
| 50 | for (array_ptr) |item, index| { | |
| 51 | _ = item; | |
| 52 | buffer[buf_index] = @intCast(u8, index); | |
| 53 | buf_index += 1; | |
| 54 | } | |
| 55 | const unknown_size: []const u8 = &array; | |
| 56 | for (unknown_size) |item| { | |
| 57 | buffer[buf_index] = item; | |
| 58 | buf_index += 1; | |
| 59 | } | |
| 60 | for (unknown_size) |_, index| { | |
| 61 | buffer[buf_index] = @intCast(u8, index); | |
| 62 | buf_index += 1; | |
| 63 | } | |
| 64 | ||
| 65 | try expect(mem.eql(u8, buffer[0..buf_index], &expected_result)); | |
| 66 | } | |
| 67 | ||
| 68 | 29 | test "2 break statements and an else" { |
| 69 | 30 | const S = struct { |
| 70 | 31 | fn entry(t: bool, f: bool) !void { |
| ... | ... | @@ -82,23 +43,6 @@ test "2 break statements and an else" { |
| 82 | 43 | comptime try S.entry(true, false); |
| 83 | 44 | } |
| 84 | 45 | |
| 85 | test "for with null and T peer types and inferred result location type" { | |
| 86 | const S = struct { | |
| 87 | fn doTheTest(slice: []const u8) !void { | |
| 88 | if (for (slice) |item| { | |
| 89 | if (item == 10) { | |
| 90 | break item; | |
| 91 | } | |
| 92 | } else null) |v| { | |
| 93 | _ = v; | |
| 94 | @panic("fail"); | |
| 95 | } | |
| 96 | } | |
| 97 | }; | |
| 98 | try S.doTheTest(&[_]u8{ 1, 2 }); | |
| 99 | comptime try S.doTheTest(&[_]u8{ 1, 2 }); | |
| 100 | } | |
| 101 | ||
| 102 | 46 | test "for copies its payload" { |
| 103 | 47 | const S = struct { |
| 104 | 48 | fn doTheTest() !void { |
test/behavior/import.zig+2-2| ... | ... | @@ -3,7 +3,7 @@ const expectEqual = @import("std").testing.expectEqual; |
| 3 | 3 | const a_namespace = @import("import/a_namespace.zig"); |
| 4 | 4 | |
| 5 | 5 | test "call fn via namespace lookup" { |
| 6 | try expectEqual(@as(i32, 1234), a_namespace.foo()); | |
| 6 | try expect(@as(i32, 1234) == a_namespace.foo()); | |
| 7 | 7 | } |
| 8 | 8 | |
| 9 | 9 | test "importing the same thing gives the same import" { |
| ... | ... | @@ -14,7 +14,7 @@ test "import in non-toplevel scope" { |
| 14 | 14 | const S = struct { |
| 15 | 15 | usingnamespace @import("import/a_namespace.zig"); |
| 16 | 16 | }; |
| 17 | try expectEqual(@as(i32, 1234), S.foo()); | |
| 17 | try expect(@as(i32, 1234) == S.foo()); | |
| 18 | 18 | } |
| 19 | 19 | |
| 20 | 20 | test "import empty file" { |
test/behavior/null.zig+25| ... | ... | @@ -115,3 +115,28 @@ test "optional pointer to 0 bit type null value at runtime" { |
| 115 | 115 | var x: ?*EmptyStruct = null; |
| 116 | 116 | try expect(x == null); |
| 117 | 117 | } |
| 118 | ||
| 119 | test "if var maybe pointer" { | |
| 120 | try expect(shouldBeAPlus1(Particle{ | |
| 121 | .a = 14, | |
| 122 | .b = 1, | |
| 123 | .c = 1, | |
| 124 | .d = 1, | |
| 125 | }) == 15); | |
| 126 | } | |
| 127 | fn shouldBeAPlus1(p: Particle) u64 { | |
| 128 | var maybe_particle: ?Particle = p; | |
| 129 | if (maybe_particle) |*particle| { | |
| 130 | particle.a += 1; | |
| 131 | } | |
| 132 | if (maybe_particle) |particle| { | |
| 133 | return particle.a; | |
| 134 | } | |
| 135 | return 0; | |
| 136 | } | |
| 137 | const Particle = struct { | |
| 138 | a: u64, | |
| 139 | b: u64, | |
| 140 | c: u64, | |
| 141 | d: u64, | |
| 142 | }; |
test/behavior/undefined.zig+1-1| ... | ... | @@ -65,5 +65,5 @@ test "assign undefined to struct with method" { |
| 65 | 65 | |
| 66 | 66 | test "type name of undefined" { |
| 67 | 67 | const x = undefined; |
| 68 | try expect(mem.eql(u8, @typeName(@TypeOf(x)), "(undefined)")); | |
| 68 | try expect(mem.eql(u8, @typeName(@TypeOf(x)), "@Type(.Undefined)")); | |
| 69 | 69 | } |
test/behavior/while.zig+37| ... | ... | @@ -153,6 +153,20 @@ test "while with optional as condition with else" { |
| 153 | 153 | try expect(got_else == 1); |
| 154 | 154 | } |
| 155 | 155 | |
| 156 | test "while with error union condition" { | |
| 157 | numbers_left = 10; | |
| 158 | var sum: i32 = 0; | |
| 159 | var got_else: i32 = 0; | |
| 160 | while (getNumberOrErr()) |value| { | |
| 161 | sum += value; | |
| 162 | } else |err| { | |
| 163 | try expect(err == error.OutOfNumbers); | |
| 164 | got_else += 1; | |
| 165 | } | |
| 166 | try expect(sum == 45); | |
| 167 | try expect(got_else == 1); | |
| 168 | } | |
| 169 | ||
| 156 | 170 | test "while on bool with else result follow else prong" { |
| 157 | 171 | const result = while (returnFalse()) { |
| 158 | 172 | break @as(i32, 10); |
| ... | ... | @@ -199,3 +213,26 @@ fn returnFalse() bool { |
| 199 | 213 | fn returnTrue() bool { |
| 200 | 214 | return true; |
| 201 | 215 | } |
| 216 | ||
| 217 | test "return with implicit cast from while loop" { | |
| 218 | returnWithImplicitCastFromWhileLoopTest() catch unreachable; | |
| 219 | } | |
| 220 | fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { | |
| 221 | while (true) { | |
| 222 | return; | |
| 223 | } | |
| 224 | } | |
| 225 | ||
| 226 | test "while on error union with else result follow else prong" { | |
| 227 | const result = while (returnError()) |value| { | |
| 228 | break value; | |
| 229 | } else |_| @as(i32, 2); | |
| 230 | try expect(result == 2); | |
| 231 | } | |
| 232 | ||
| 233 | test "while on error union with else result follow break prong" { | |
| 234 | const result = while (returnSuccess(10)) |value| { | |
| 235 | break value; | |
| 236 | } else |_| @as(i32, 2); | |
| 237 | try expect(result == 10); | |
| 238 | } |
test/behavior/while_stage1.zig-70| ... | ... | @@ -1,76 +1,6 @@ |
| 1 | 1 | const std = @import("std"); |
| 2 | 2 | const expect = std.testing.expect; |
| 3 | 3 | |
| 4 | test "return with implicit cast from while loop" { | |
| 5 | returnWithImplicitCastFromWhileLoopTest() catch unreachable; | |
| 6 | } | |
| 7 | fn returnWithImplicitCastFromWhileLoopTest() anyerror!void { | |
| 8 | while (true) { | |
| 9 | return; | |
| 10 | } | |
| 11 | } | |
| 12 | ||
| 13 | test "while with error union condition" { | |
| 14 | numbers_left = 10; | |
| 15 | var sum: i32 = 0; | |
| 16 | var got_else: i32 = 0; | |
| 17 | while (getNumberOrErr()) |value| { | |
| 18 | sum += value; | |
| 19 | } else |err| { | |
| 20 | try expect(err == error.OutOfNumbers); | |
| 21 | got_else += 1; | |
| 22 | } | |
| 23 | try expect(sum == 45); | |
| 24 | try expect(got_else == 1); | |
| 25 | } | |
| 26 | ||
| 27 | var numbers_left: i32 = undefined; | |
| 28 | fn getNumberOrErr() anyerror!i32 { | |
| 29 | return if (numbers_left == 0) error.OutOfNumbers else x: { | |
| 30 | numbers_left -= 1; | |
| 31 | break :x numbers_left; | |
| 32 | }; | |
| 33 | } | |
| 34 | fn getNumberOrNull() ?i32 { | |
| 35 | return if (numbers_left == 0) null else x: { | |
| 36 | numbers_left -= 1; | |
| 37 | break :x numbers_left; | |
| 38 | }; | |
| 39 | } | |
| 40 | ||
| 41 | test "while on error union with else result follow else prong" { | |
| 42 | const result = while (returnError()) |value| { | |
| 43 | break value; | |
| 44 | } else |_| @as(i32, 2); | |
| 45 | try expect(result == 2); | |
| 46 | } | |
| 47 | ||
| 48 | test "while on error union with else result follow break prong" { | |
| 49 | const result = while (returnSuccess(10)) |value| { | |
| 50 | break value; | |
| 51 | } else |_| @as(i32, 2); | |
| 52 | try expect(result == 10); | |
| 53 | } | |
| 54 | ||
| 55 | fn returnNull() ?i32 { | |
| 56 | return null; | |
| 57 | } | |
| 58 | fn returnOptional(x: i32) ?i32 { | |
| 59 | return x; | |
| 60 | } | |
| 61 | fn returnError() anyerror!i32 { | |
| 62 | return error.YouWantedAnError; | |
| 63 | } | |
| 64 | fn returnSuccess(x: i32) anyerror!i32 { | |
| 65 | return x; | |
| 66 | } | |
| 67 | fn returnFalse() bool { | |
| 68 | return false; | |
| 69 | } | |
| 70 | fn returnTrue() bool { | |
| 71 | return true; | |
| 72 | } | |
| 73 | ||
| 74 | 4 | test "while bool 2 break statements and an else" { |
| 75 | 5 | const S = struct { |
| 76 | 6 | fn entry(t: bool, f: bool) !void { |
test/compile_errors.zig+11-11| ... | ... | @@ -2674,7 +2674,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 2674 | 2674 | \\ } |
| 2675 | 2675 | \\} |
| 2676 | 2676 | , &[_][]const u8{ |
| 2677 | "tmp.zig:3:9: error: expected type 'error{Hi}', found '(enum literal)'", | |
| 2677 | "tmp.zig:3:9: error: expected type 'error{Hi}', found '@Type(.EnumLiteral)'", | |
| 2678 | 2678 | }); |
| 2679 | 2679 | |
| 2680 | 2680 | ctx.objErrStage1("@sizeOf bad type", |
| ... | ... | @@ -2682,7 +2682,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 2682 | 2682 | \\ return @sizeOf(@TypeOf(null)); |
| 2683 | 2683 | \\} |
| 2684 | 2684 | , &[_][]const u8{ |
| 2685 | "tmp.zig:2:20: error: no size available for type '(null)'", | |
| 2685 | "tmp.zig:2:20: error: no size available for type '@Type(.Null)'", | |
| 2686 | 2686 | }); |
| 2687 | 2687 | |
| 2688 | 2688 | ctx.objErrStage1("generic function where return type is self-referenced", |
| ... | ... | @@ -5783,7 +5783,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 5783 | 5783 | \\ |
| 5784 | 5784 | \\export fn entry() usize { return @sizeOf(@TypeOf(a)); } |
| 5785 | 5785 | , &[_][]const u8{ |
| 5786 | "tmp.zig:1:16: error: expected type '*u8', found '(null)'", | |
| 5786 | "tmp.zig:1:16: error: expected type '*u8', found '@Type(.Null)'", | |
| 5787 | 5787 | }); |
| 5788 | 5788 | |
| 5789 | 5789 | ctx.objErrStage1("indexing an array of size zero", |
| ... | ... | @@ -7506,12 +7506,12 @@ pub fn addCases(ctx: *TestContext) !void { |
| 7506 | 7506 | \\}; |
| 7507 | 7507 | , &[_][]const u8{ |
| 7508 | 7508 | "tmp.zig:2:4: error: variable of type '*const comptime_int' must be const or comptime", |
| 7509 | "tmp.zig:6:4: error: variable of type '(undefined)' must be const or comptime", | |
| 7509 | "tmp.zig:6:4: error: variable of type '@Type(.Undefined)' must be const or comptime", | |
| 7510 | 7510 | "tmp.zig:10:4: error: variable of type 'comptime_int' must be const or comptime", |
| 7511 | 7511 | "tmp.zig:10:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type", |
| 7512 | 7512 | "tmp.zig:14:4: error: variable of type 'comptime_float' must be const or comptime", |
| 7513 | 7513 | "tmp.zig:14:4: note: to modify this variable at runtime, it must be given an explicit fixed-size number type", |
| 7514 | "tmp.zig:18:4: error: variable of type '(null)' must be const or comptime", | |
| 7514 | "tmp.zig:18:4: error: variable of type '@Type(.Null)' must be const or comptime", | |
| 7515 | 7515 | "tmp.zig:22:4: error: variable of type 'Opaque' not allowed", |
| 7516 | 7516 | "tmp.zig:26:4: error: variable of type 'type' must be const or comptime", |
| 7517 | 7517 | "tmp.zig:30:4: error: variable of type '(bound fn(*const Foo) void)' must be const or comptime", |
| ... | ... | @@ -8278,8 +8278,8 @@ pub fn addCases(ctx: *TestContext) !void { |
| 8278 | 8278 | , &[_][]const u8{ |
| 8279 | 8279 | "tmp.zig:2:18: error: Opaque return type 'FooType' not allowed", |
| 8280 | 8280 | "tmp.zig:1:1: note: type declared here", |
| 8281 | "tmp.zig:5:18: error: Null return type '(null)' not allowed", | |
| 8282 | "tmp.zig:8:18: error: Undefined return type '(undefined)' not allowed", | |
| 8281 | "tmp.zig:5:18: error: Null return type '@Type(.Null)' not allowed", | |
| 8282 | "tmp.zig:8:18: error: Undefined return type '@Type(.Undefined)' not allowed", | |
| 8283 | 8283 | }); |
| 8284 | 8284 | |
| 8285 | 8285 | ctx.objErrStage1("generic function returning opaque type", |
| ... | ... | @@ -8300,9 +8300,9 @@ pub fn addCases(ctx: *TestContext) !void { |
| 8300 | 8300 | "tmp.zig:6:16: error: call to generic function with Opaque return type 'FooType' not allowed", |
| 8301 | 8301 | "tmp.zig:2:1: note: function declared here", |
| 8302 | 8302 | "tmp.zig:1:1: note: type declared here", |
| 8303 | "tmp.zig:9:16: error: call to generic function with Null return type '(null)' not allowed", | |
| 8303 | "tmp.zig:9:16: error: call to generic function with Null return type '@Type(.Null)' not allowed", | |
| 8304 | 8304 | "tmp.zig:2:1: note: function declared here", |
| 8305 | "tmp.zig:12:16: error: call to generic function with Undefined return type '(undefined)' not allowed", | |
| 8305 | "tmp.zig:12:16: error: call to generic function with Undefined return type '@Type(.Undefined)' not allowed", | |
| 8306 | 8306 | "tmp.zig:2:1: note: function declared here", |
| 8307 | 8307 | }); |
| 8308 | 8308 | |
| ... | ... | @@ -8329,9 +8329,9 @@ pub fn addCases(ctx: *TestContext) !void { |
| 8329 | 8329 | \\} |
| 8330 | 8330 | , &[_][]const u8{ |
| 8331 | 8331 | "tmp.zig:3:28: error: parameter of opaque type 'FooType' not allowed", |
| 8332 | "tmp.zig:8:28: error: parameter of type '(null)' not allowed", | |
| 8332 | "tmp.zig:8:28: error: parameter of type '@Type(.Null)' not allowed", | |
| 8333 | 8333 | "tmp.zig:12:11: error: parameter of opaque type 'FooType' not allowed", |
| 8334 | "tmp.zig:17:11: error: parameter of type '(null)' not allowed", | |
| 8334 | "tmp.zig:17:11: error: parameter of type '@Type(.Null)' not allowed", | |
| 8335 | 8335 | }); |
| 8336 | 8336 | |
| 8337 | 8337 | ctx.objErrStage1( // fixed bug #2032 |