| author | |
| committer | |
| log | 28caaea0938e938de96cc66a49f670005a2df9d4 |
| tree | 7e2975d48dd85296bc79d6918d6520c689ebc268 |
| parent | f40f81cbfb0a867b32d4406e198550730de268cd |
| signature |
AstGen emits an error when a closure over a known-runtime value crosses
a namespace boundary. This usually makes sense: however, this usage is
actually valid if the capture is within a `@TypeOf` operand. Sema
already has a special case to allow such closure within `@TypeOf` when
AstGen could not determine a value to be runtime-known. This commit
simply introduces analagous logic to AstGen to allow `var`s to cross
namespace boundaries within `@TypeOf`.3 files changed, 26 insertions(+), 1 deletions(-)
src/AstGen.zig+6-1| ... | ... | @@ -7468,7 +7468,7 @@ fn localVarRef( |
| 7468 | 7468 | } |
| 7469 | 7469 | |
| 7470 | 7470 | // Can't close over a runtime variable |
| 7471 | if (num_namespaces_out != 0 and !local_ptr.maybe_comptime) { | |
| 7471 | if (num_namespaces_out != 0 and !local_ptr.maybe_comptime and !gz.is_typeof) { | |
| 7472 | 7472 | const ident_name = try astgen.identifierTokenString(ident_token); |
| 7473 | 7473 | return astgen.failNodeNotes(ident, "mutable '{s}' not accessible from here", .{ident_name}, &.{ |
| 7474 | 7474 | try astgen.errNoteTok(local_ptr.token_src, "declared mutable here", .{}), |
| ... | ... | @@ -8041,6 +8041,7 @@ fn typeOf( |
| 8041 | 8041 | |
| 8042 | 8042 | var typeof_scope = gz.makeSubBlock(scope); |
| 8043 | 8043 | typeof_scope.is_comptime = false; |
| 8044 | typeof_scope.is_typeof = true; | |
| 8044 | 8045 | typeof_scope.c_import = false; |
| 8045 | 8046 | defer typeof_scope.unstack(); |
| 8046 | 8047 | |
| ... | ... | @@ -10882,6 +10883,9 @@ const GenZir = struct { |
| 10882 | 10883 | /// whenever we know Sema will analyze the current block with `is_comptime`, |
| 10883 | 10884 | /// for instance when we're within a `struct_decl` or a `block_comptime`. |
| 10884 | 10885 | is_comptime: bool, |
| 10886 | /// Whether we're in an expression within a `@TypeOf` operand. In this case, closure of runtime | |
| 10887 | /// variables is permitted where it is usually not. | |
| 10888 | is_typeof: bool = false, | |
| 10885 | 10889 | /// This is set to true for inline loops; false otherwise. |
| 10886 | 10890 | is_inline: bool = false, |
| 10887 | 10891 | c_import: bool = false, |
| ... | ... | @@ -10953,6 +10957,7 @@ const GenZir = struct { |
| 10953 | 10957 | fn makeSubBlock(gz: *GenZir, scope: *Scope) GenZir { |
| 10954 | 10958 | return .{ |
| 10955 | 10959 | .is_comptime = gz.is_comptime, |
| 10960 | .is_typeof = gz.is_typeof, | |
| 10956 | 10961 | .c_import = gz.c_import, |
| 10957 | 10962 | .decl_node_index = gz.decl_node_index, |
| 10958 | 10963 | .decl_line = gz.decl_line, |
test/behavior/eval.zig+10| ... | ... | @@ -991,6 +991,16 @@ test "closure capture type of runtime-known parameter" { |
| 991 | 991 | try S.b(c); |
| 992 | 992 | } |
| 993 | 993 | |
| 994 | test "closure capture type of runtime-known var" { | |
| 995 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 996 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO | |
| 997 | ||
| 998 | var x: u32 = 1234; | |
| 999 | const S = struct { val: @TypeOf(x + 100) }; | |
| 1000 | const s: S = .{ .val = x }; | |
| 1001 | try expect(s.val == 1234); | |
| 1002 | } | |
| 1003 | ||
| 994 | 1004 | test "comptime break passing through runtime condition converted to runtime break" { |
| 995 | 1005 | if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO |
| 996 | 1006 | if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; |
test/run_translated_c.zig+10| ... | ... | @@ -1895,4 +1895,14 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void { |
| 1895 | 1895 | \\ return 0; |
| 1896 | 1896 | \\} |
| 1897 | 1897 | , ""); |
| 1898 | ||
| 1899 | cases.add("Closure over local in typeof", | |
| 1900 | \\#include <stdlib.h> | |
| 1901 | \\int main(void) { | |
| 1902 | \\ int x = 123; | |
| 1903 | \\ union { typeof(x) val; } u = { x }; | |
| 1904 | \\ if (u.val != 123) abort(); | |
| 1905 | \\ return 0; | |
| 1906 | \\} | |
| 1907 | , ""); | |
| 1898 | 1908 | } |