| author | |
| committer | |
| log | e42b7702eb2c74b923aa88492886c3f316188e99 |
| tree | 7e4d18651c354ffb7f846316a9661059d963483d |
| parent | 14aa08fcd3ca6ef32fff9422969cb684cb81b9d7 |
| parent | 129a4fb251f8eab22eacf219fbf81006baec3251 |
9 files changed, 136 insertions(+), 44 deletions(-)
ci/azure/pipelines.yml+13-5| ... | @@ -40,12 +40,20 @@ jobs: | ... | @@ -40,12 +40,20 @@ jobs: |
| 40 | timeoutInMinutes: 360 | 40 | timeoutInMinutes: 360 |
| 41 | 41 | ||
| 42 | steps: | 42 | steps: |
| 43 | - powershell: | | ||
| 44 | (New-Object Net.WebClient).DownloadFile("https://github.com/msys2/msys2-installer/releases/download/2020-06-02/msys2-base-x86_64-20200602.sfx.exe", "sfx.exe") | ||
| 45 | .\sfx.exe -y -o\ | ||
| 46 | del sfx.exe | ||
| 47 | displayName: Download/Extract/Install MSYS2 | ||
| 43 | - script: | | 48 | - script: | |
| 44 | git clone https://github.com/msys2/msys2-ci-base.git %CD:~0,2%\msys64 | 49 | @REM install updated filesystem package first without dependency checking |
| 45 | %CD:~0,2%\msys64\usr\bin\rm -rf %CD:~0,2%\msys64\.git | 50 | @REM because of: https://github.com/msys2/MSYS2-packages/issues/2021 |
| 46 | set PATH=%CD:~0,2%\msys64\usr\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem | 51 | %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Sydd filesystem" |
| 47 | %CD:~0,2%\msys64\usr\bin\pacman --noconfirm -Syyuu | 52 | displayName: Workaround filesystem dash MSYS2 dependency issue |
| 48 | displayName: Install and Update MSYS2 | 53 | - script: | |
| 54 | %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" | ||
| 55 | %CD:~0,2%\msys64\usr\bin\bash -lc "pacman --noconfirm -Syuu" | ||
| 56 | displayName: Update MSYS2 | ||
| 49 | - task: DownloadSecureFile@1 | 57 | - task: DownloadSecureFile@1 |
| 50 | inputs: | 58 | inputs: |
| 51 | secureFile: s3cfg | 59 | secureFile: s3cfg |
ci/azure/windows_msvc_install+1-1| ... | @@ -4,7 +4,7 @@ set -x | ... | @@ -4,7 +4,7 @@ set -x |
| 4 | set -e | 4 | set -e |
| 5 | 5 | ||
| 6 | pacman -Su --needed --noconfirm | 6 | pacman -Su --needed --noconfirm |
| 7 | pacman -S --needed --noconfirm wget p7zip python3-pip | 7 | pacman -S --needed --noconfirm wget p7zip python3-pip tar xz |
| 8 | pip install s3cmd | 8 | pip install s3cmd |
| 9 | wget -nv "https://ziglang.org/deps/llvm%2bclang%2blld-10.0.0-x86_64-windows-msvc-release-mt.tar.xz" | 9 | wget -nv "https://ziglang.org/deps/llvm%2bclang%2blld-10.0.0-x86_64-windows-msvc-release-mt.tar.xz" |
| 10 | tar xf llvm+clang+lld-10.0.0-x86_64-windows-msvc-release-mt.tar.xz | 10 | tar xf llvm+clang+lld-10.0.0-x86_64-windows-msvc-release-mt.tar.xz |
doc/langref.html.in+1-1| ... | @@ -9738,7 +9738,7 @@ pub fn main() !void { | ... | @@ -9738,7 +9738,7 @@ pub fn main() !void { |
| 9738 | } | 9738 | } |
| 9739 | {#code_end#} | 9739 | {#code_end#} |
| 9740 | <pre><code>$ wasmtime --dir=. preopens.wasm | 9740 | <pre><code>$ wasmtime --dir=. preopens.wasm |
| 9741 | 0: { .fd = 3, .Dir = '.' } | 9741 | 0: Preopen{ .fd = 3, .type = PreopenType{ .Dir = '.' } } |
| 9742 | </code></pre> | 9742 | </code></pre> |
| 9743 | {#header_close#} | 9743 | {#header_close#} |
| 9744 | {#header_close#} | 9744 | {#header_close#} |
lib/std/fs/wasi.zig+41-35| ... | @@ -5,13 +5,39 @@ const Allocator = mem.Allocator; | ... | @@ -5,13 +5,39 @@ const Allocator = mem.Allocator; |
| 5 | 5 | ||
| 6 | usingnamespace std.os.wasi; | 6 | usingnamespace std.os.wasi; |
| 7 | 7 | ||
| 8 | /// Type of WASI preopen. | 8 | /// Type-tag of WASI preopen. |
| 9 | /// | 9 | /// |
| 10 | /// WASI currently offers only `Dir` as a valid preopen resource. | 10 | /// WASI currently offers only `Dir` as a valid preopen resource. |
| 11 | pub const PreopenType = enum { | 11 | pub const PreopenTypeTag = enum { |
| 12 | Dir, | 12 | Dir, |
| 13 | }; | 13 | }; |
| 14 | 14 | ||
| 15 | /// Type of WASI preopen. | ||
| 16 | /// | ||
| 17 | /// WASI currently offers only `Dir` as a valid preopen resource. | ||
| 18 | pub const PreopenType = union(PreopenTypeTag) { | ||
| 19 | /// Preopened directory type. | ||
| 20 | Dir: []const u8, | ||
| 21 | |||
| 22 | const Self = @This(); | ||
| 23 | |||
| 24 | pub fn eql(self: Self, other: PreopenType) bool { | ||
| 25 | if (!mem.eql(u8, @tagName(self), @tagName(other))) return false; | ||
| 26 | |||
| 27 | switch (self) { | ||
| 28 | PreopenTypeTag.Dir => |this_path| return mem.eql(u8, this_path, other.Dir), | ||
| 29 | } | ||
| 30 | } | ||
| 31 | |||
| 32 | pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void { | ||
| 33 | try out_stream.print("PreopenType{{ ", .{}); | ||
| 34 | switch (self) { | ||
| 35 | PreopenType.Dir => |path| try out_stream.print(".Dir = '{}'", .{path}), | ||
| 36 | } | ||
| 37 | return out_stream.print(" }}", .{}); | ||
| 38 | } | ||
| 39 | }; | ||
| 40 | |||
| 15 | /// WASI preopen struct. This struct consists of a WASI file descriptor | 41 | /// WASI preopen struct. This struct consists of a WASI file descriptor |
| 16 | /// and type of WASI preopen. It can be obtained directly from the WASI | 42 | /// and type of WASI preopen. It can be obtained directly from the WASI |
| 17 | /// runtime using `PreopenList.populate()` method. | 43 | /// runtime using `PreopenList.populate()` method. |
| ... | @@ -20,29 +46,15 @@ pub const Preopen = struct { | ... | @@ -20,29 +46,15 @@ pub const Preopen = struct { |
| 20 | fd: fd_t, | 46 | fd: fd_t, |
| 21 | 47 | ||
| 22 | /// Type of the preopen. | 48 | /// Type of the preopen. |
| 23 | @"type": union(PreopenType) { | 49 | @"type": PreopenType, |
| 24 | /// Path to a preopened directory. | ||
| 25 | Dir: []const u8, | ||
| 26 | }, | ||
| 27 | 50 | ||
| 28 | const Self = @This(); | 51 | /// Construct new `Preopen` instance. |
| 29 | 52 | pub fn new(fd: fd_t, preopen_type: PreopenType) Preopen { | |
| 30 | /// Construct new `Preopen` instance of type `PreopenType.Dir` from | 53 | return Preopen{ |
| 31 | /// WASI file descriptor and WASI path. | ||
| 32 | pub fn newDir(fd: fd_t, path: []const u8) Self { | ||
| 33 | return Self{ | ||
| 34 | .fd = fd, | 54 | .fd = fd, |
| 35 | .@"type" = .{ .Dir = path }, | 55 | .@"type" = preopen_type, |
| 36 | }; | 56 | }; |
| 37 | } | 57 | } |
| 38 | |||
| 39 | pub fn format(self: Self, comptime fmt: []const u8, options: std.fmt.FormatOptions, out_stream: var) !void { | ||
| 40 | try out_stream.print("{{ .fd = {}, ", .{self.fd}); | ||
| 41 | switch (self.@"type") { | ||
| 42 | PreopenType.Dir => |path| try out_stream.print(".Dir = '{}'", .{path}), | ||
| 43 | } | ||
| 44 | return out_stream.print(" }}", .{}); | ||
| 45 | } | ||
| 46 | }; | 58 | }; |
| 47 | 59 | ||
| 48 | /// Dynamically-sized array list of WASI preopens. This struct is a | 60 | /// Dynamically-sized array list of WASI preopens. This struct is a |
| ... | @@ -113,24 +125,18 @@ pub const PreopenList = struct { | ... | @@ -113,24 +125,18 @@ pub const PreopenList = struct { |
| 113 | ESUCCESS => {}, | 125 | ESUCCESS => {}, |
| 114 | else => |err| return os.unexpectedErrno(err), | 126 | else => |err| return os.unexpectedErrno(err), |
| 115 | } | 127 | } |
| 116 | const preopen = Preopen.newDir(fd, path_buf); | 128 | const preopen = Preopen.new(fd, PreopenType{ .Dir = path_buf }); |
| 117 | try self.buffer.append(preopen); | 129 | try self.buffer.append(preopen); |
| 118 | fd += 1; | 130 | fd += 1; |
| 119 | } | 131 | } |
| 120 | } | 132 | } |
| 121 | 133 | ||
| 122 | /// Find preopen by path. If the preopen exists, return it. | 134 | /// Find preopen by type. If the preopen exists, return it. |
| 123 | /// Otherwise, return `null`. | 135 | /// Otherwise, return `null`. |
| 124 | /// | 136 | pub fn find(self: Self, preopen_type: PreopenType) ?*const Preopen { |
| 125 | /// TODO make the function more generic by searching by `PreopenType` union. This will | 137 | for (self.buffer.items) |*preopen| { |
| 126 | /// be needed in the future when WASI extends its capabilities to resources | 138 | if (preopen.@"type".eql(preopen_type)) { |
| 127 | /// other than preopened directories. | 139 | return preopen; |
| 128 | pub fn find(self: Self, path: []const u8) ?*const Preopen { | ||
| 129 | for (self.buffer.items) |preopen| { | ||
| 130 | switch (preopen.@"type") { | ||
| 131 | PreopenType.Dir => |preopen_path| { | ||
| 132 | if (mem.eql(u8, path, preopen_path)) return &preopen; | ||
| 133 | }, | ||
| 134 | } | 140 | } |
| 135 | } | 141 | } |
| 136 | return null; | 142 | return null; |
| ... | @@ -156,7 +162,7 @@ test "extracting WASI preopens" { | ... | @@ -156,7 +162,7 @@ test "extracting WASI preopens" { |
| 156 | try preopens.populate(); | 162 | try preopens.populate(); |
| 157 | 163 | ||
| 158 | std.testing.expectEqual(@as(usize, 1), preopens.asSlice().len); | 164 | std.testing.expectEqual(@as(usize, 1), preopens.asSlice().len); |
| 159 | const preopen = preopens.find(".") orelse unreachable; | 165 | const preopen = preopens.find(PreopenType{ .Dir = "." }) orelse unreachable; |
| 160 | std.testing.expect(std.mem.eql(u8, ".", preopen.@"type".Dir)); | 166 | std.testing.expect(preopen.@"type".eql(PreopenType{ .Dir = "." })); |
| 161 | std.testing.expectEqual(@as(usize, 3), preopen.fd); | 167 | std.testing.expectEqual(@as(usize, 3), preopen.fd); |
| 162 | } | 168 | } |
lib/std/testing.zig+1-1| ... | @@ -215,7 +215,7 @@ fn getCwdOrWasiPreopen() std.fs.Dir { | ... | @@ -215,7 +215,7 @@ fn getCwdOrWasiPreopen() std.fs.Dir { |
| 215 | defer preopens.deinit(); | 215 | defer preopens.deinit(); |
| 216 | preopens.populate() catch | 216 | preopens.populate() catch |
| 217 | @panic("unable to make tmp dir for testing: unable to populate preopens"); | 217 | @panic("unable to make tmp dir for testing: unable to populate preopens"); |
| 218 | const preopen = preopens.find(".") orelse | 218 | const preopen = preopens.find(std.fs.wasi.PreopenType{ .Dir = "." }) orelse |
| 219 | @panic("unable to make tmp dir for testing: didn't find '.' in the preopens"); | 219 | @panic("unable to make tmp dir for testing: didn't find '.' in the preopens"); |
| 220 | 220 | ||
| 221 | return std.fs.Dir{ .fd = preopen.fd }; | 221 | return std.fs.Dir{ .fd = preopen.fd }; |
src/analyze.cpp+6| ... | @@ -9597,6 +9597,12 @@ void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) { | ... | @@ -9597,6 +9597,12 @@ void copy_const_val(CodeGen *g, ZigValue *dest, ZigValue *src) { |
| 9597 | break; | 9597 | break; |
| 9598 | } | 9598 | } |
| 9599 | } | 9599 | } |
| 9600 | } else if (dest->type->id == ZigTypeIdUnion) { | ||
| 9601 | bigint_init_bigint(&dest->data.x_union.tag, &src->data.x_union.tag); | ||
| 9602 | dest->data.x_union.payload = g->pass1_arena->create<ZigValue>(); | ||
| 9603 | copy_const_val(g, dest->data.x_union.payload, src->data.x_union.payload); | ||
| 9604 | dest->data.x_union.payload->parent.id = ConstParentIdUnion; | ||
| 9605 | dest->data.x_union.payload->parent.data.p_union.union_val = dest; | ||
| 9600 | } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) { | 9606 | } else if (type_has_optional_repr(dest->type) && dest->data.x_optional != nullptr) { |
| 9601 | dest->data.x_optional = g->pass1_arena->create<ZigValue>(); | 9607 | dest->data.x_optional = g->pass1_arena->create<ZigValue>(); |
| 9602 | copy_const_val(g, dest->data.x_optional, src->data.x_optional); | 9608 | copy_const_val(g, dest->data.x_optional, src->data.x_optional); |
src/ir.cpp+31-1| ... | @@ -28861,7 +28861,37 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, | ... | @@ -28861,7 +28861,37 @@ static IrInstGen *ir_analyze_instruction_check_switch_prongs(IrAnalyze *ira, |
| 28861 | ir_add_error(ira, &instruction->base.base, | 28861 | ir_add_error(ira, &instruction->base.base, |
| 28862 | buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); | 28862 | buf_sprintf("else prong required when switching on type '%s'", buf_ptr(&switch_type->name))); |
| 28863 | return ira->codegen->invalid_inst_gen; | 28863 | return ira->codegen->invalid_inst_gen; |
| 28864 | } | 28864 | } else if(switch_type->id == ZigTypeIdMetaType) { |
| 28865 | HashMap<const ZigType*, IrInstGen*, type_ptr_hash, type_ptr_eql> prevs; | ||
| 28866 | // HashMap doubles capacity when reaching 60% capacity, | ||
| 28867 | // because we know the size at init we can avoid reallocation by doubling it here | ||
| 28868 | prevs.init(instruction->range_count * 2); | ||
| 28869 | for (size_t range_i = 0; range_i < instruction->range_count; range_i += 1) { | ||
| 28870 | IrInstSrcCheckSwitchProngsRange *range = &instruction->ranges[range_i]; | ||
| 28871 | |||
| 28872 | IrInstGen *value = range->start->child; | ||
| 28873 | IrInstGen *casted_value = ir_implicit_cast(ira, value, switch_type); | ||
| 28874 | if (type_is_invalid(casted_value->value->type)) { | ||
| 28875 | prevs.deinit(); | ||
| 28876 | return ira->codegen->invalid_inst_gen; | ||
| 28877 | } | ||
| 28878 | |||
| 28879 | ZigValue *const_expr_val = ir_resolve_const(ira, casted_value, UndefBad); | ||
| 28880 | if (!const_expr_val) { | ||
| 28881 | prevs.deinit(); | ||
| 28882 | return ira->codegen->invalid_inst_gen; | ||
| 28883 | } | ||
| 28884 | |||
| 28885 | auto entry = prevs.put_unique(const_expr_val->data.x_type, value); | ||
| 28886 | if(entry != nullptr) { | ||
| 28887 | ErrorMsg *msg = ir_add_error(ira, &value->base, buf_sprintf("duplicate switch value")); | ||
| 28888 | add_error_note(ira->codegen, msg, entry->value->base.source_node, buf_sprintf("previous value is here")); | ||
| 28889 | prevs.deinit(); | ||
| 28890 | return ira->codegen->invalid_inst_gen; | ||
| 28891 | } | ||
| 28892 | } | ||
| 28893 | prevs.deinit(); | ||
| 28894 | } | ||
| 28865 | return ir_const_void(ira, &instruction->base.base); | 28895 | return ir_const_void(ira, &instruction->base.base); |
| 28866 | } | 28896 | } |
| 28867 | 28897 |
test/compile_errors.zig+34| ... | @@ -4362,6 +4362,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -4362,6 +4362,40 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 4362 | "tmp.zig:5:14: note: previous value is here", | 4362 | "tmp.zig:5:14: note: previous value is here", |
| 4363 | }); | 4363 | }); |
| 4364 | 4364 | ||
| 4365 | cases.add("switch expression - duplicate type", | ||
| 4366 | \\fn foo(comptime T: type, x: T) u8 { | ||
| 4367 | \\ return switch (T) { | ||
| 4368 | \\ u32 => 0, | ||
| 4369 | \\ u64 => 1, | ||
| 4370 | \\ u32 => 2, | ||
| 4371 | \\ else => 3, | ||
| 4372 | \\ }; | ||
| 4373 | \\} | ||
| 4374 | \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); } | ||
| 4375 | , &[_][]const u8{ | ||
| 4376 | "tmp.zig:5:9: error: duplicate switch value", | ||
| 4377 | "tmp.zig:3:9: note: previous value is here", | ||
| 4378 | }); | ||
| 4379 | |||
| 4380 | cases.add("switch expression - duplicate type (struct alias)", | ||
| 4381 | \\const Test = struct { | ||
| 4382 | \\ bar: i32, | ||
| 4383 | \\}; | ||
| 4384 | \\const Test2 = Test; | ||
| 4385 | \\fn foo(comptime T: type, x: T) u8 { | ||
| 4386 | \\ return switch (T) { | ||
| 4387 | \\ Test => 0, | ||
| 4388 | \\ u64 => 1, | ||
| 4389 | \\ Test2 => 2, | ||
| 4390 | \\ else => 3, | ||
| 4391 | \\ }; | ||
| 4392 | \\} | ||
| 4393 | \\export fn entry() usize { return @sizeOf(@TypeOf(foo(u32, 0))); } | ||
| 4394 | , &[_][]const u8{ | ||
| 4395 | "tmp.zig:9:9: error: duplicate switch value", | ||
| 4396 | "tmp.zig:7:9: note: previous value is here", | ||
| 4397 | }); | ||
| 4398 | |||
| 4365 | cases.add("switch expression - switch on pointer type with no else", | 4399 | cases.add("switch expression - switch on pointer type with no else", |
| 4366 | \\fn foo(x: *u8) void { | 4400 | \\fn foo(x: *u8) void { |
| 4367 | \\ switch (x) { | 4401 | \\ switch (x) { |
test/stage1/behavior/type_info.zig+8| ... | @@ -402,3 +402,11 @@ test "type info for async frames" { | ... | @@ -402,3 +402,11 @@ test "type info for async frames" { |
| 402 | else => unreachable, | 402 | else => unreachable, |
| 403 | } | 403 | } |
| 404 | } | 404 | } |
| 405 | |||
| 406 | test "type info: value is correctly copied" { | ||
| 407 | comptime { | ||
| 408 | var ptrInfo = @typeInfo([]u32); | ||
| 409 | ptrInfo.Pointer.size = .One; | ||
| 410 | expect(@typeInfo([]u32).Pointer.size == .Slice); | ||
| 411 | } | ||
| 412 | } |