| author | |
| committer | |
| log | 7a881435ed54b0cf59f48679c3912600b3bd0d58 |
| tree | 551acc0660ddd455edcc6ee4ab4644b7a9bc8363 |
| parent | 2a96209c4060bbf8a41fbe34e687a7a4741d2fe1 |
| parent | 69a3c4e279238874cc74cf6acd5eb0426d5b65ee |
| signature |
Stage2 fixes8 files changed, 86 insertions(+), 30 deletions(-)
src/AstGen.zig+4-2| ... | ... | @@ -4265,10 +4265,13 @@ fn structDeclInner( |
| 4265 | 4265 | // are in scope, so that field types, alignments, and default value expressions |
| 4266 | 4266 | // can refer to decls within the struct itself. |
| 4267 | 4267 | astgen.advanceSourceCursorToNode(node); |
| 4268 | // If `node == 0` then this is the root struct and all the declarations should | |
| 4269 | // be relative to the beginning of the file. | |
| 4270 | const decl_line = if (node == 0) 0 else astgen.source_line; | |
| 4268 | 4271 | var block_scope: GenZir = .{ |
| 4269 | 4272 | .parent = &namespace.base, |
| 4270 | 4273 | .decl_node_index = node, |
| 4271 | .decl_line = astgen.source_line, | |
| 4274 | .decl_line = decl_line, | |
| 4272 | 4275 | .astgen = astgen, |
| 4273 | 4276 | .force_comptime = true, |
| 4274 | 4277 | .in_defer = false, |
| ... | ... | @@ -11756,7 +11759,6 @@ fn scanDecls(astgen: *AstGen, namespace: *Scope.Namespace, members: []const Ast. |
| 11756 | 11759 | } |
| 11757 | 11760 | } |
| 11758 | 11761 | |
| 11759 | // const index_name = try astgen.identAsString(index_token); | |
| 11760 | 11762 | var s = namespace.parent; |
| 11761 | 11763 | while (true) switch (s.tag) { |
| 11762 | 11764 | .local_val => { |
src/Sema.zig+23-25| ... | ... | @@ -78,6 +78,9 @@ post_hoc_blocks: std.AutoHashMapUnmanaged(Air.Inst.Index, *LabeledBlock) = .{}, |
| 78 | 78 | err: ?*Module.ErrorMsg = null, |
| 79 | 79 | /// True when analyzing a generic instantiation. Used to suppress some errors. |
| 80 | 80 | is_generic_instantiation: bool = false, |
| 81 | /// Set to true when analyzing a func type instruction so that nested generic | |
| 82 | /// function types will emit generic poison instead of a partial type. | |
| 83 | no_partial_func_ty: bool = false, | |
| 81 | 84 | |
| 82 | 85 | const std = @import("std"); |
| 83 | 86 | const math = std.math; |
| ... | ... | @@ -4068,6 +4071,19 @@ fn zirValidateArrayInit( |
| 4068 | 4071 | |
| 4069 | 4072 | // Determine whether the value stored to this pointer is comptime-known. |
| 4070 | 4073 | |
| 4074 | if (array_ty.isTuple()) { | |
| 4075 | if (array_ty.structFieldValueComptime(i)) |opv| { | |
| 4076 | element_vals[i] = opv; | |
| 4077 | continue; | |
| 4078 | } | |
| 4079 | } else { | |
| 4080 | // Array has one possible value, so value is always comptime-known | |
| 4081 | if (opt_opv) |opv| { | |
| 4082 | element_vals[i] = opv; | |
| 4083 | continue; | |
| 4084 | } | |
| 4085 | } | |
| 4086 | ||
| 4071 | 4087 | const elem_ptr_air_ref = sema.inst_map.get(elem_ptr).?; |
| 4072 | 4088 | const elem_ptr_air_inst = Air.refToIndex(elem_ptr_air_ref).?; |
| 4073 | 4089 | // Find the block index of the elem_ptr so that we can look at the next |
| ... | ... | @@ -4084,19 +4100,6 @@ fn zirValidateArrayInit( |
| 4084 | 4100 | } |
| 4085 | 4101 | first_block_index = @minimum(first_block_index, block_index); |
| 4086 | 4102 | |
| 4087 | if (array_ty.isTuple()) { | |
| 4088 | if (array_ty.structFieldValueComptime(i)) |opv| { | |
| 4089 | element_vals[i] = opv; | |
| 4090 | continue; | |
| 4091 | } | |
| 4092 | } else { | |
| 4093 | // Array has one possible value, so value is always comptime-known | |
| 4094 | if (opt_opv) |opv| { | |
| 4095 | element_vals[i] = opv; | |
| 4096 | continue; | |
| 4097 | } | |
| 4098 | } | |
| 4099 | ||
| 4100 | 4103 | // If the next instructon is a store with a comptime operand, this element |
| 4101 | 4104 | // is comptime. |
| 4102 | 4105 | const next_air_inst = block.instructions.items[block_index + 1]; |
| ... | ... | @@ -5938,10 +5941,9 @@ fn analyzeCall( |
| 5938 | 5941 | undefined, |
| 5939 | 5942 | ) catch |err| switch (err) { |
| 5940 | 5943 | error.NeededSourceLocation => { |
| 5941 | sema.inst_map.clearRetainingCapacity(); | |
| 5944 | _ = sema.inst_map.remove(inst); | |
| 5942 | 5945 | const decl = sema.mod.declPtr(block.src_decl); |
| 5943 | 5946 | child_block.src_decl = block.src_decl; |
| 5944 | arg_i = 0; | |
| 5945 | 5947 | try sema.analyzeInlineCallArg( |
| 5946 | 5948 | block, |
| 5947 | 5949 | &child_block, |
| ... | ... | @@ -7917,6 +7919,7 @@ fn funcCommon( |
| 7917 | 7919 | if (cc_workaround == .Inline and is_noinline) { |
| 7918 | 7920 | return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{}); |
| 7919 | 7921 | } |
| 7922 | if (is_generic and sema.no_partial_func_ty) return error.GenericPoison; | |
| 7920 | 7923 | |
| 7921 | 7924 | break :fn_ty try Type.Tag.function.create(sema.arena, .{ |
| 7922 | 7925 | .param_types = param_types, |
| ... | ... | @@ -8097,25 +8100,19 @@ fn zirParam( |
| 8097 | 8100 | // Make sure any nested param instructions don't clobber our work. |
| 8098 | 8101 | const prev_params = block.params; |
| 8099 | 8102 | const prev_preallocated_new_func = sema.preallocated_new_func; |
| 8103 | const prev_no_partial_func_type = sema.no_partial_func_ty; | |
| 8100 | 8104 | block.params = .{}; |
| 8101 | 8105 | sema.preallocated_new_func = null; |
| 8106 | sema.no_partial_func_ty = true; | |
| 8102 | 8107 | defer { |
| 8103 | 8108 | block.params.deinit(sema.gpa); |
| 8104 | 8109 | block.params = prev_params; |
| 8105 | 8110 | sema.preallocated_new_func = prev_preallocated_new_func; |
| 8111 | sema.no_partial_func_ty = prev_no_partial_func_type; | |
| 8106 | 8112 | } |
| 8107 | 8113 | |
| 8108 | 8114 | if (sema.resolveBody(block, body, inst)) |param_ty_inst| { |
| 8109 | 8115 | if (sema.analyzeAsType(block, src, param_ty_inst)) |param_ty| { |
| 8110 | if (param_ty.zigTypeTag() == .Fn and param_ty.fnInfo().is_generic) { | |
| 8111 | // zirFunc will not emit error.GenericPoison to build a | |
| 8112 | // partial type for generic functions but we still need to | |
| 8113 | // detect if a function parameter is a generic function | |
| 8114 | // to force the parent function to also be generic. | |
| 8115 | if (!sema.inst_map.contains(inst)) { | |
| 8116 | break :err error.GenericPoison; | |
| 8117 | } | |
| 8118 | } | |
| 8119 | 8116 | break :param_ty param_ty; |
| 8120 | 8117 | } else |err| break :err err; |
| 8121 | 8118 | } else |err| break :err err; |
| ... | ... | @@ -26140,11 +26137,12 @@ fn analyzeSlice( |
| 26140 | 26137 | var array_ty = ptr_ptr_child_ty; |
| 26141 | 26138 | var slice_ty = ptr_ptr_ty; |
| 26142 | 26139 | var ptr_or_slice = ptr_ptr; |
| 26143 | var elem_ty = ptr_ptr_child_ty.childType(); | |
| 26140 | var elem_ty: Type = undefined; | |
| 26144 | 26141 | var ptr_sentinel: ?Value = null; |
| 26145 | 26142 | switch (ptr_ptr_child_ty.zigTypeTag()) { |
| 26146 | 26143 | .Array => { |
| 26147 | 26144 | ptr_sentinel = ptr_ptr_child_ty.sentinel(); |
| 26145 | elem_ty = ptr_ptr_child_ty.childType(); | |
| 26148 | 26146 | }, |
| 26149 | 26147 | .Pointer => switch (ptr_ptr_child_ty.ptrSize()) { |
| 26150 | 26148 | .One => { |
src/value.zig+6| ... | ... | @@ -2689,6 +2689,12 @@ pub const Value = extern union { |
| 2689 | 2689 | // to have only one possible value itself. |
| 2690 | 2690 | .the_only_possible_value => return val, |
| 2691 | 2691 | |
| 2692 | // pointer to integer casted to pointer of array | |
| 2693 | .int_u64, .int_i64 => { | |
| 2694 | assert(index == 0); | |
| 2695 | return val; | |
| 2696 | }, | |
| 2697 | ||
| 2692 | 2698 | else => unreachable, |
| 2693 | 2699 | } |
| 2694 | 2700 | } |
test/behavior/generics.zig+15| ... | ... | @@ -342,3 +342,18 @@ test "generic instantiation of tagged union with only one field" { |
| 342 | 342 | try expect(S.foo(.{ .s = "a" }) == 1); |
| 343 | 343 | try expect(S.foo(.{ .s = "ab" }) == 2); |
| 344 | 344 | } |
| 345 | ||
| 346 | test "nested generic function" { | |
| 347 | const S = struct { | |
| 348 | fn foo(comptime T: type, callback: *const fn (user_data: T) anyerror!void, data: T) anyerror!void { | |
| 349 | try callback(data); | |
| 350 | } | |
| 351 | fn bar(a: u32) anyerror!void { | |
| 352 | try expect(a == 123); | |
| 353 | } | |
| 354 | ||
| 355 | fn g(_: *const fn (anytype) void) void {} | |
| 356 | }; | |
| 357 | try expect(@typeInfo(@TypeOf(S.g)).Fn.is_generic); | |
| 358 | try S.foo(u32, S.bar, 123); | |
| 359 | } |
test/behavior/tuple.zig+11| ... | ... | @@ -290,3 +290,14 @@ test "coerce tuple to tuple" { |
| 290 | 290 | }; |
| 291 | 291 | try S.foo(.{123}); |
| 292 | 292 | } |
| 293 | ||
| 294 | test "tuple type with void field" { | |
| 295 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | |
| 296 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 297 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 298 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 299 | ||
| 300 | const T = std.meta.Tuple(&[_]type{void}); | |
| 301 | const x = T{{}}; | |
| 302 | try expect(@TypeOf(x[0]) == void); | |
| 303 | } |
test/cases/compile_errors/comptime_parameter_not_declared_as_such.zig+4-3| ... | ... | @@ -1,5 +1,6 @@ |
| 1 | 1 | fn f(_: anytype) void {} |
| 2 | fn g(h: *const fn (anytype) void) void { | |
| 2 | const T = *const fn (anytype) void; | |
| 3 | fn g(h: T) void { | |
| 3 | 4 | h({}); |
| 4 | 5 | } |
| 5 | 6 | pub export fn entry() void { |
| ... | ... | @@ -19,5 +20,5 @@ pub export fn entry1() void { |
| 19 | 20 | // backend=stage2 |
| 20 | 21 | // target=native |
| 21 | 22 | // |
| 22 | // :2:6: error: parameter of type '*const fn(anytype) void' must be declared comptime | |
| 23 | // :9:34: error: parameter of type 'comptime_int' must be declared comptime | |
| 23 | // :3:6: error: parameter of type '*const fn(anytype) void' must be declared comptime | |
| 24 | // :10:34: error: parameter of type 'comptime_int' must be declared comptime |
test/cases/compile_errors/error_in_typeof_param.zig created+14| ... | ... | @@ -0,0 +1,14 @@ |
| 1 | fn getSize() usize { | |
| 2 | return 2; | |
| 3 | } | |
| 4 | pub fn expectEqual(expected: anytype, _: @TypeOf(expected)) !void {} | |
| 5 | pub export fn entry() void { | |
| 6 | try expectEqual(2, getSize()); | |
| 7 | } | |
| 8 | ||
| 9 | // error | |
| 10 | // backend=stage2 | |
| 11 | // target=native | |
| 12 | // | |
| 13 | // :6:31: error: unable to resolve comptime value | |
| 14 | // :6:31: note: argument to parameter with comptime only type must be comptime known |
test/cases/compile_errors/slice_of_non_array_type.zig created+9| ... | ... | @@ -0,0 +1,9 @@ |
| 1 | comptime { | |
| 2 | _ = 1[0..]; | |
| 3 | } | |
| 4 | ||
| 5 | // error | |
| 6 | // backend=stage2 | |
| 7 | // target=native | |
| 8 | // | |
| 9 | // :2:10: error: slice of non-array type 'comptime_int' |