| author | |
| committer | |
| log | 2a92b04b9dc21356f383b12af9040ca79f268267 |
| tree | 830ecfe5f91d60ad32754163ef87adbe9c6dfa25 |
| parent | c2d37224c843feb84f4522ec35d192968b786e08 |
| parent | d8128c272a087bbfc0b33a786c18267f49cd4982 |
| signature |
compile error improvements and bug fixes13 files changed, 216 insertions(+), 40 deletions(-)
lib/std/zig/Ast.zig+4| ... | ... | @@ -362,6 +362,9 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 362 | 362 | .wrong_equal_var_decl => { |
| 363 | 363 | return stream.writeAll("variable initialized with '==' instead of '='"); |
| 364 | 364 | }, |
| 365 | .var_const_decl => { | |
| 366 | return stream.writeAll("use 'var' or 'const' to declare variable"); | |
| 367 | }, | |
| 365 | 368 | |
| 366 | 369 | .expected_token => { |
| 367 | 370 | const found_tag = token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)]; |
| ... | ... | @@ -2743,6 +2746,7 @@ pub const Error = struct { |
| 2743 | 2746 | c_style_container, |
| 2744 | 2747 | expected_var_const, |
| 2745 | 2748 | wrong_equal_var_decl, |
| 2749 | var_const_decl, | |
| 2746 | 2750 | |
| 2747 | 2751 | zig_style_container, |
| 2748 | 2752 | previous_field, |
lib/std/zig/parse.zig+7| ... | ... | @@ -471,6 +471,13 @@ const Parser = struct { |
| 471 | 471 | // There is not allowed to be a decl after a field with no comma. |
| 472 | 472 | // Report error but recover parser. |
| 473 | 473 | try p.warn(.expected_comma_after_field); |
| 474 | if (p.token_tags[p.tok_i] == .semicolon and p.token_tags[identifier] == .identifier) { | |
| 475 | try p.warnMsg(.{ | |
| 476 | .tag = .var_const_decl, | |
| 477 | .is_note = true, | |
| 478 | .token = identifier, | |
| 479 | }); | |
| 480 | } | |
| 474 | 481 | p.findNextContainerMember(); |
| 475 | 482 | continue; |
| 476 | 483 | }, |
lib/std/zig/parser_test.zig+12| ... | ... | @@ -5238,6 +5238,18 @@ test "zig fmt: missing const/var before local variable" { |
| 5238 | 5238 | }); |
| 5239 | 5239 | } |
| 5240 | 5240 | |
| 5241 | test "zig fmt: missing const/var before local variable" { | |
| 5242 | try testError( | |
| 5243 | \\std = foo, | |
| 5244 | \\std = foo; | |
| 5245 | \\*u32 = foo; | |
| 5246 | , &.{ | |
| 5247 | .expected_comma_after_field, | |
| 5248 | .var_const_decl, | |
| 5249 | .expected_comma_after_field, | |
| 5250 | }); | |
| 5251 | } | |
| 5252 | ||
| 5241 | 5253 | test "zig fmt: while continue expr" { |
| 5242 | 5254 | try testCanonical( |
| 5243 | 5255 | \\test { |
src/AstGen.zig+18-2| ... | ... | @@ -2463,6 +2463,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2463 | 2463 | .is_non_null_ptr, |
| 2464 | 2464 | .is_non_err, |
| 2465 | 2465 | .is_non_err_ptr, |
| 2466 | .ret_is_non_err, | |
| 2466 | 2467 | .mod_rem, |
| 2467 | 2468 | .mul, |
| 2468 | 2469 | .mulwrap, |
| ... | ... | @@ -4486,9 +4487,24 @@ fn structDeclInner( |
| 4486 | 4487 | .container_field_align, |
| 4487 | 4488 | .container_field, |
| 4488 | 4489 | .@"comptime", |
| 4490 | .test_decl, | |
| 4489 | 4491 | => continue, |
| 4490 | 4492 | else => { |
| 4491 | return astgen.failNode(member_node, "tuple declarations cannot contain declarations", .{}); | |
| 4493 | const tuple_member = for (container_decl.ast.members) |maybe_tuple| switch (node_tags[maybe_tuple]) { | |
| 4494 | .container_field_init, | |
| 4495 | .container_field_align, | |
| 4496 | .container_field, | |
| 4497 | => break maybe_tuple, | |
| 4498 | else => {}, | |
| 4499 | } else unreachable; | |
| 4500 | return astgen.failNodeNotes( | |
| 4501 | member_node, | |
| 4502 | "tuple declarations cannot contain declarations", | |
| 4503 | .{}, | |
| 4504 | &[_]u32{ | |
| 4505 | try astgen.errNoteNode(tuple_member, "tuple field here", .{}), | |
| 4506 | }, | |
| 4507 | ); | |
| 4492 | 4508 | }, |
| 4493 | 4509 | } |
| 4494 | 4510 | }; |
| ... | ... | @@ -7012,7 +7028,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 7012 | 7028 | |
| 7013 | 7029 | // Emit conditional branch for generating errdefers. |
| 7014 | 7030 | const result = if (ri.rl == .ptr) try gz.addUnNode(.load, ri.rl.ptr.inst, node) else operand; |
| 7015 | const is_non_err = try gz.addUnNode(.is_non_err, result, node); | |
| 7031 | const is_non_err = try gz.addUnNode(.ret_is_non_err, result, node); | |
| 7016 | 7032 | const condbr = try gz.addCondBr(.condbr, node); |
| 7017 | 7033 | |
| 7018 | 7034 | var then_scope = gz.makeSubBlock(scope); |
src/Module.zig+22-9| ... | ... | @@ -528,10 +528,10 @@ pub const Decl = struct { |
| 528 | 528 | /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it |
| 529 | 529 | /// deletes the Decl on the spot. |
| 530 | 530 | alive: bool, |
| 531 | /// Whether the Decl is a `usingnamespace` declaration. | |
| 532 | is_usingnamespace: bool, | |
| 533 | 531 | /// If true `name` is already fully qualified. |
| 534 | 532 | name_fully_qualified: bool = false, |
| 533 | /// What kind of a declaration is this. | |
| 534 | kind: Kind, | |
| 535 | 535 | |
| 536 | 536 | /// Represents the position of the code in the output file. |
| 537 | 537 | /// This is populated regardless of semantic analysis and code generation. |
| ... | ... | @@ -551,6 +551,14 @@ pub const Decl = struct { |
| 551 | 551 | /// typed_value may need to be regenerated. |
| 552 | 552 | dependencies: DepsTable = .{}, |
| 553 | 553 | |
| 554 | pub const Kind = enum { | |
| 555 | @"usingnamespace", | |
| 556 | @"test", | |
| 557 | @"comptime", | |
| 558 | named, | |
| 559 | anon, | |
| 560 | }; | |
| 561 | ||
| 554 | 562 | pub const Index = enum(u32) { |
| 555 | 563 | _, |
| 556 | 564 | |
| ... | ... | @@ -4438,7 +4446,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4438 | 4446 | // not the struct itself. |
| 4439 | 4447 | try sema.resolveTypeLayout(decl_tv.ty); |
| 4440 | 4448 | |
| 4441 | if (decl.is_usingnamespace) { | |
| 4449 | if (decl.kind == .@"usingnamespace") { | |
| 4442 | 4450 | if (!decl_tv.ty.eql(Type.type, mod)) { |
| 4443 | 4451 | return sema.fail(&block_scope, ty_src, "expected type, found {}", .{ |
| 4444 | 4452 | decl_tv.ty.fmt(mod), |
| ... | ... | @@ -4964,26 +4972,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 4964 | 4972 | |
| 4965 | 4973 | // Every Decl needs a name. |
| 4966 | 4974 | var is_named_test = false; |
| 4975 | var kind: Decl.Kind = .named; | |
| 4967 | 4976 | const decl_name: [:0]const u8 = switch (decl_name_index) { |
| 4968 | 4977 | 0 => name: { |
| 4969 | 4978 | if (export_bit) { |
| 4970 | 4979 | const i = iter.usingnamespace_index; |
| 4971 | 4980 | iter.usingnamespace_index += 1; |
| 4981 | kind = .@"usingnamespace"; | |
| 4972 | 4982 | break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); |
| 4973 | 4983 | } else { |
| 4974 | 4984 | const i = iter.comptime_index; |
| 4975 | 4985 | iter.comptime_index += 1; |
| 4986 | kind = .@"comptime"; | |
| 4976 | 4987 | break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i}); |
| 4977 | 4988 | } |
| 4978 | 4989 | }, |
| 4979 | 4990 | 1 => name: { |
| 4980 | 4991 | const i = iter.unnamed_test_index; |
| 4981 | 4992 | iter.unnamed_test_index += 1; |
| 4993 | kind = .@"test"; | |
| 4982 | 4994 | break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i}); |
| 4983 | 4995 | }, |
| 4984 | 4996 | 2 => name: { |
| 4985 | 4997 | is_named_test = true; |
| 4986 | 4998 | const test_name = zir.nullTerminatedString(decl_doccomment_index); |
| 4999 | kind = .@"test"; | |
| 4987 | 5000 | break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name}); |
| 4988 | 5001 | }, |
| 4989 | 5002 | else => name: { |
| ... | ... | @@ -4991,6 +5004,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 4991 | 5004 | if (raw_name.len == 0) { |
| 4992 | 5005 | is_named_test = true; |
| 4993 | 5006 | const test_name = zir.nullTerminatedString(decl_name_index + 1); |
| 5007 | kind = .@"test"; | |
| 4994 | 5008 | break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); |
| 4995 | 5009 | } else { |
| 4996 | 5010 | break :name try gpa.dupeZ(u8, raw_name); |
| ... | ... | @@ -4998,8 +5012,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 4998 | 5012 | }, |
| 4999 | 5013 | }; |
| 5000 | 5014 | const is_exported = export_bit and decl_name_index != 0; |
| 5001 | const is_usingnamespace = export_bit and decl_name_index == 0; | |
| 5002 | if (is_usingnamespace) try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); | |
| 5015 | if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); | |
| 5003 | 5016 | |
| 5004 | 5017 | // We create a Decl for it regardless of analysis status. |
| 5005 | 5018 | const gop = try namespace.decls.getOrPutContextAdapted( |
| ... | ... | @@ -5012,8 +5025,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5012 | 5025 | if (!gop.found_existing) { |
| 5013 | 5026 | const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope); |
| 5014 | 5027 | const new_decl = mod.declPtr(new_decl_index); |
| 5028 | new_decl.kind = kind; | |
| 5015 | 5029 | new_decl.name = decl_name; |
| 5016 | if (is_usingnamespace) { | |
| 5030 | if (kind == .@"usingnamespace") { | |
| 5017 | 5031 | namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub); |
| 5018 | 5032 | } |
| 5019 | 5033 | log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace }); |
| ... | ... | @@ -5058,7 +5072,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5058 | 5072 | } |
| 5059 | 5073 | new_decl.is_pub = is_pub; |
| 5060 | 5074 | new_decl.is_exported = is_exported; |
| 5061 | new_decl.is_usingnamespace = is_usingnamespace; | |
| 5062 | 5075 | new_decl.has_align = has_align; |
| 5063 | 5076 | new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace; |
| 5064 | 5077 | new_decl.zir_decl_index = @intCast(u32, decl_sub_index); |
| ... | ... | @@ -5076,7 +5089,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5076 | 5089 | |
| 5077 | 5090 | decl.is_pub = is_pub; |
| 5078 | 5091 | decl.is_exported = is_exported; |
| 5079 | decl.is_usingnamespace = is_usingnamespace; | |
| 5092 | decl.kind = kind; | |
| 5080 | 5093 | decl.has_align = has_align; |
| 5081 | 5094 | decl.has_linksection_or_addrspace = has_linksection_or_addrspace; |
| 5082 | 5095 | decl.zir_decl_index = @intCast(u32, decl_sub_index); |
| ... | ... | @@ -5635,7 +5648,7 @@ pub fn allocateNewDecl( |
| 5635 | 5648 | .has_linksection_or_addrspace = false, |
| 5636 | 5649 | .has_align = false, |
| 5637 | 5650 | .alive = false, |
| 5638 | .is_usingnamespace = false, | |
| 5651 | .kind = .anon, | |
| 5639 | 5652 | }; |
| 5640 | 5653 | |
| 5641 | 5654 | return decl_and_index.decl_index; |
src/Sema.zig+76-27| ... | ... | @@ -953,6 +953,7 @@ fn analyzeBodyInner( |
| 953 | 953 | .int_type => try sema.zirIntType(block, inst), |
| 954 | 954 | .is_non_err => try sema.zirIsNonErr(block, inst), |
| 955 | 955 | .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), |
| 956 | .ret_is_non_err => try sema.zirRetIsNonErr(block, inst), | |
| 956 | 957 | .is_non_null => try sema.zirIsNonNull(block, inst), |
| 957 | 958 | .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst), |
| 958 | 959 | .merge_error_sets => try sema.zirMergeErrorSets(block, inst), |
| ... | ... | @@ -9004,7 +9005,7 @@ fn zirParam( |
| 9004 | 9005 | else => |e| return e, |
| 9005 | 9006 | } or comptime_syntax; |
| 9006 | 9007 | if (sema.inst_map.get(inst)) |arg| { |
| 9007 | if (is_comptime) { | |
| 9008 | if (is_comptime and sema.preallocated_new_func != null) { | |
| 9008 | 9009 | // We have a comptime value for this parameter so it should be elided from the |
| 9009 | 9010 | // function type of the function instruction in this block. |
| 9010 | 9011 | const coerced_arg = try sema.coerce(block, param_ty, arg, src); |
| ... | ... | @@ -10288,6 +10289,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10288 | 10289 | .ret_err_value_code, |
| 10289 | 10290 | .restore_err_ret_index, |
| 10290 | 10291 | .is_non_err, |
| 10292 | .ret_is_non_err, | |
| 10291 | 10293 | .condbr, |
| 10292 | 10294 | => {}, |
| 10293 | 10295 | else => break, |
| ... | ... | @@ -16215,11 +16217,54 @@ fn typeInfoDecls( |
| 16215 | 16217 | }; |
| 16216 | 16218 | try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena)); |
| 16217 | 16219 | |
| 16218 | const decls_len = if (opt_namespace) |ns| ns.decls.count() else 0; | |
| 16219 | const decls_vals = try decls_anon_decl.arena().alloc(Value, decls_len); | |
| 16220 | for (decls_vals) |*decls_val, i| { | |
| 16221 | const decl_index = opt_namespace.?.decls.keys()[i]; | |
| 16220 | var decl_vals = std.ArrayList(Value).init(sema.gpa); | |
| 16221 | defer decl_vals.deinit(); | |
| 16222 | ||
| 16223 | var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa); | |
| 16224 | defer seen_namespaces.deinit(); | |
| 16225 | ||
| 16226 | if (opt_namespace) |some| { | |
| 16227 | try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), some, &decl_vals, &seen_namespaces); | |
| 16228 | } | |
| 16229 | ||
| 16230 | const new_decl = try decls_anon_decl.finish( | |
| 16231 | try Type.Tag.array.create(decls_anon_decl.arena(), .{ | |
| 16232 | .len = decl_vals.items.len, | |
| 16233 | .elem_type = declaration_ty, | |
| 16234 | }), | |
| 16235 | try Value.Tag.aggregate.create( | |
| 16236 | decls_anon_decl.arena(), | |
| 16237 | try decls_anon_decl.arena().dupe(Value, decl_vals.items), | |
| 16238 | ), | |
| 16239 | 0, // default alignment | |
| 16240 | ); | |
| 16241 | return try Value.Tag.slice.create(sema.arena, .{ | |
| 16242 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 16243 | .len = try Value.Tag.int_u64.create(sema.arena, decl_vals.items.len), | |
| 16244 | }); | |
| 16245 | } | |
| 16246 | ||
| 16247 | fn typeInfoNamespaceDecls( | |
| 16248 | sema: *Sema, | |
| 16249 | block: *Block, | |
| 16250 | decls_anon_decl: Allocator, | |
| 16251 | namespace: *Namespace, | |
| 16252 | decl_vals: *std.ArrayList(Value), | |
| 16253 | seen_namespaces: *std.AutoHashMap(*Namespace, void), | |
| 16254 | ) !void { | |
| 16255 | const gop = try seen_namespaces.getOrPut(namespace); | |
| 16256 | if (gop.found_existing) return; | |
| 16257 | const decls = namespace.decls.keys(); | |
| 16258 | for (decls) |decl_index| { | |
| 16222 | 16259 | const decl = sema.mod.declPtr(decl_index); |
| 16260 | if (decl.kind == .@"usingnamespace") { | |
| 16261 | try sema.mod.ensureDeclAnalyzed(decl_index); | |
| 16262 | var buf: Value.ToTypeBuffer = undefined; | |
| 16263 | const new_ns = decl.val.toType(&buf).getNamespace().?; | |
| 16264 | try sema.typeInfoNamespaceDecls(block, decls_anon_decl, new_ns, decl_vals, seen_namespaces); | |
| 16265 | continue; | |
| 16266 | } | |
| 16267 | if (decl.kind != .named) continue; | |
| 16223 | 16268 | const name_val = v: { |
| 16224 | 16269 | var anon_decl = try block.startAnonDecl(); |
| 16225 | 16270 | defer anon_decl.deinit(); |
| ... | ... | @@ -16229,37 +16274,21 @@ fn typeInfoDecls( |
| 16229 | 16274 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| 16230 | 16275 | 0, // default alignment |
| 16231 | 16276 | ); |
| 16232 | break :v try Value.Tag.slice.create(decls_anon_decl.arena(), .{ | |
| 16233 | .ptr = try Value.Tag.decl_ref.create(decls_anon_decl.arena(), new_decl), | |
| 16234 | .len = try Value.Tag.int_u64.create(decls_anon_decl.arena(), bytes.len), | |
| 16277 | break :v try Value.Tag.slice.create(decls_anon_decl, .{ | |
| 16278 | .ptr = try Value.Tag.decl_ref.create(decls_anon_decl, new_decl), | |
| 16279 | .len = try Value.Tag.int_u64.create(decls_anon_decl, bytes.len), | |
| 16235 | 16280 | }); |
| 16236 | 16281 | }; |
| 16237 | 16282 | |
| 16238 | const fields = try decls_anon_decl.arena().create([2]Value); | |
| 16283 | const fields = try decls_anon_decl.create([2]Value); | |
| 16239 | 16284 | fields.* = .{ |
| 16240 | 16285 | //name: []const u8, |
| 16241 | 16286 | name_val, |
| 16242 | 16287 | //is_pub: bool, |
| 16243 | 16288 | Value.makeBool(decl.is_pub), |
| 16244 | 16289 | }; |
| 16245 | decls_val.* = try Value.Tag.aggregate.create(decls_anon_decl.arena(), fields); | |
| 16290 | try decl_vals.append(try Value.Tag.aggregate.create(decls_anon_decl, fields)); | |
| 16246 | 16291 | } |
| 16247 | ||
| 16248 | const new_decl = try decls_anon_decl.finish( | |
| 16249 | try Type.Tag.array.create(decls_anon_decl.arena(), .{ | |
| 16250 | .len = decls_vals.len, | |
| 16251 | .elem_type = declaration_ty, | |
| 16252 | }), | |
| 16253 | try Value.Tag.aggregate.create( | |
| 16254 | decls_anon_decl.arena(), | |
| 16255 | try decls_anon_decl.arena().dupe(Value, decls_vals), | |
| 16256 | ), | |
| 16257 | 0, // default alignment | |
| 16258 | ); | |
| 16259 | return try Value.Tag.slice.create(sema.arena, .{ | |
| 16260 | .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl), | |
| 16261 | .len = try Value.Tag.int_u64.create(sema.arena, decls_vals.len), | |
| 16262 | }); | |
| 16263 | 16292 | } |
| 16264 | 16293 | |
| 16265 | 16294 | fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -16577,7 +16606,7 @@ fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16577 | 16606 | const src = inst_data.src(); |
| 16578 | 16607 | const operand = try sema.resolveInst(inst_data.operand); |
| 16579 | 16608 | try sema.checkErrorType(block, src, sema.typeOf(operand)); |
| 16580 | return sema.analyzeIsNonErr(block, inst_data.src(), operand); | |
| 16609 | return sema.analyzeIsNonErr(block, src, operand); | |
| 16581 | 16610 | } |
| 16582 | 16611 | |
| 16583 | 16612 | fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | ... | @@ -16592,6 +16621,16 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 16592 | 16621 | return sema.analyzeIsNonErr(block, src, loaded); |
| 16593 | 16622 | } |
| 16594 | 16623 | |
| 16624 | fn zirRetIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 16625 | const tracy = trace(@src()); | |
| 16626 | defer tracy.end(); | |
| 16627 | ||
| 16628 | const inst_data = sema.code.instructions.items(.data)[inst].un_node; | |
| 16629 | const src = inst_data.src(); | |
| 16630 | const operand = try sema.resolveInst(inst_data.operand); | |
| 16631 | return sema.analyzeIsNonErr(block, src, operand); | |
| 16632 | } | |
| 16633 | ||
| 16595 | 16634 | fn zirCondbr( |
| 16596 | 16635 | sema: *Sema, |
| 16597 | 16636 | parent_block: *Block, |
| ... | ... | @@ -29847,6 +29886,11 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 29847 | 29886 | }, |
| 29848 | 29887 | .have_layout, .fully_resolved_wip, .fully_resolved => return, |
| 29849 | 29888 | } |
| 29889 | const prev_status = struct_obj.status; | |
| 29890 | errdefer if (struct_obj.status == .layout_wip) { | |
| 29891 | struct_obj.status = prev_status; | |
| 29892 | }; | |
| 29893 | ||
| 29850 | 29894 | struct_obj.status = .layout_wip; |
| 29851 | 29895 | for (struct_obj.fields.values()) |field, i| { |
| 29852 | 29896 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { |
| ... | ... | @@ -30026,6 +30070,11 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 30026 | 30070 | }, |
| 30027 | 30071 | .have_layout, .fully_resolved_wip, .fully_resolved => return, |
| 30028 | 30072 | } |
| 30073 | const prev_status = union_obj.status; | |
| 30074 | errdefer if (union_obj.status == .layout_wip) { | |
| 30075 | union_obj.status = prev_status; | |
| 30076 | }; | |
| 30077 | ||
| 30029 | 30078 | union_obj.status = .layout_wip; |
| 30030 | 30079 | for (union_obj.fields.values()) |field, i| { |
| 30031 | 30080 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { |
src/Zir.zig+6| ... | ... | @@ -481,6 +481,9 @@ pub const Inst = struct { |
| 481 | 481 | /// Return a boolean false if dereferenced pointer is an error |
| 482 | 482 | /// Uses the `un_node` field. |
| 483 | 483 | is_non_err_ptr, |
| 484 | /// Same as `is_non_er` but doesn't validate that the type can be an error. | |
| 485 | /// Uses the `un_node` field. | |
| 486 | ret_is_non_err, | |
| 484 | 487 | /// A labeled block of code that loops forever. At the end of the body will have either |
| 485 | 488 | /// a `repeat` instruction or a `repeat_inline` instruction. |
| 486 | 489 | /// Uses the `pl_node` field. The AST node is either a for loop or while loop. |
| ... | ... | @@ -1083,6 +1086,7 @@ pub const Inst = struct { |
| 1083 | 1086 | .is_non_null_ptr, |
| 1084 | 1087 | .is_non_err, |
| 1085 | 1088 | .is_non_err_ptr, |
| 1089 | .ret_is_non_err, | |
| 1086 | 1090 | .mod_rem, |
| 1087 | 1091 | .mul, |
| 1088 | 1092 | .mulwrap, |
| ... | ... | @@ -1386,6 +1390,7 @@ pub const Inst = struct { |
| 1386 | 1390 | .is_non_null_ptr, |
| 1387 | 1391 | .is_non_err, |
| 1388 | 1392 | .is_non_err_ptr, |
| 1393 | .ret_is_non_err, | |
| 1389 | 1394 | .mod_rem, |
| 1390 | 1395 | .mul, |
| 1391 | 1396 | .mulwrap, |
| ... | ... | @@ -1640,6 +1645,7 @@ pub const Inst = struct { |
| 1640 | 1645 | .is_non_null_ptr = .un_node, |
| 1641 | 1646 | .is_non_err = .un_node, |
| 1642 | 1647 | .is_non_err_ptr = .un_node, |
| 1648 | .ret_is_non_err = .un_node, | |
| 1643 | 1649 | .loop = .pl_node, |
| 1644 | 1650 | .repeat = .node, |
| 1645 | 1651 | .repeat_inline = .node, |
src/print_zir.zig+1| ... | ... | @@ -179,6 +179,7 @@ const Writer = struct { |
| 179 | 179 | .is_non_null_ptr, |
| 180 | 180 | .is_non_err, |
| 181 | 181 | .is_non_err_ptr, |
| 182 | .ret_is_non_err, | |
| 182 | 183 | .typeof, |
| 183 | 184 | .struct_init_empty, |
| 184 | 185 | .type_info, |
src/value.zig+10-2| ... | ... | @@ -2193,8 +2193,16 @@ pub const Value = extern union { |
| 2193 | 2193 | const payload_ty = ty.errorUnionPayload(); |
| 2194 | 2194 | return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, opt_sema); |
| 2195 | 2195 | }, |
| 2196 | .eu_payload_ptr => @panic("TODO: Implement more pointer eql cases"), | |
| 2197 | .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"), | |
| 2196 | .eu_payload_ptr => { | |
| 2197 | const a_payload = a.castTag(.eu_payload_ptr).?.data; | |
| 2198 | const b_payload = b.castTag(.eu_payload_ptr).?.data; | |
| 2199 | return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, opt_sema); | |
| 2200 | }, | |
| 2201 | .opt_payload_ptr => { | |
| 2202 | const a_payload = a.castTag(.opt_payload_ptr).?.data; | |
| 2203 | const b_payload = b.castTag(.opt_payload_ptr).?.data; | |
| 2204 | return eqlAdvanced(a_payload.container_ptr, ty, b_payload.container_ptr, ty, mod, opt_sema); | |
| 2205 | }, | |
| 2198 | 2206 | .function => { |
| 2199 | 2207 | const a_payload = a.castTag(.function).?.data; |
| 2200 | 2208 | const b_payload = b.castTag(.function).?.data; |
test/behavior/defer.zig+11| ... | ... | @@ -148,3 +148,14 @@ test "simple else prong doesn't emit an error for unreachable else prong" { |
| 148 | 148 | }; |
| 149 | 149 | try expect(a == 1); |
| 150 | 150 | } |
| 151 | ||
| 152 | test "errdefer used in function that doesn't return an error" { | |
| 153 | const S = struct { | |
| 154 | fn foo() u8 { | |
| 155 | var a: u8 = 5; | |
| 156 | errdefer a += 1; | |
| 157 | return a; | |
| 158 | } | |
| 159 | }; | |
| 160 | try expect(S.foo() == 5); | |
| 161 | } |
test/behavior/type_info.zig+24| ... | ... | @@ -566,3 +566,27 @@ test "value from struct @typeInfo default_value can be loaded at comptime" { |
| 566 | 566 | try expect(@ptrCast(*const u8, a).* == 1); |
| 567 | 567 | } |
| 568 | 568 | } |
| 569 | ||
| 570 | test "@typeInfo decls and usingnamespace" { | |
| 571 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | |
| 572 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | |
| 573 | if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; // TODO | |
| 574 | ||
| 575 | const A = struct { | |
| 576 | const x = 5; | |
| 577 | const y = 34; | |
| 578 | ||
| 579 | comptime {} | |
| 580 | }; | |
| 581 | const B = struct { | |
| 582 | usingnamespace A; | |
| 583 | const z = 56; | |
| 584 | ||
| 585 | test {} | |
| 586 | }; | |
| 587 | const decls = @typeInfo(B).Struct.decls; | |
| 588 | try expect(decls.len == 3); | |
| 589 | try expectEqualStrings(decls[0].name, "x"); | |
| 590 | try expectEqualStrings(decls[1].name, "y"); | |
| 591 | try expectEqualStrings(decls[2].name, "z"); | |
| 592 | } |
test/cases/compile_errors/nested_generic_function_param_type_mismatch.zig created+24| ... | ... | @@ -0,0 +1,24 @@ |
| 1 | pub fn sort( | |
| 2 | comptime T: type, | |
| 3 | items: []T, | |
| 4 | context: anytype, | |
| 5 | lessThan: *const fn (context: @TypeOf(context), lhs: T, rhs: T) u32, | |
| 6 | ) void { | |
| 7 | _ = items; | |
| 8 | _ = lessThan; | |
| 9 | } | |
| 10 | fn foo(_: void, _: u8, _: u8) u32 { | |
| 11 | return 0; | |
| 12 | } | |
| 13 | pub export fn entry() void { | |
| 14 | var items = [_]u8{ 3, 5, 7, 2, 6, 9, 4 }; | |
| 15 | sort(u8, &items, void, foo); | |
| 16 | } | |
| 17 | ||
| 18 | // error | |
| 19 | // backend=llvm | |
| 20 | // target=native | |
| 21 | // | |
| 22 | // :15:28: error: expected type '*const fn(comptime type, u8, u8) u32', found '*const fn(void, u8, u8) u32' | |
| 23 | // :15:28: note: pointer type child 'fn(void, u8, u8) u32' cannot cast into pointer type child 'fn(comptime type, u8, u8) u32' | |
| 24 | // :15:28: note: non-generic function cannot cast into a generic function |
test/cases/compile_errors/tuple_declarations.zig+1| ... | ... | @@ -23,3 +23,4 @@ const T = struct { |
| 23 | 23 | // :5:5: error: union field missing name |
| 24 | 24 | // :8:5: error: tuple field has a name |
| 25 | 25 | // :15:5: error: tuple declarations cannot contain declarations |
| 26 | // :12:5: note: tuple field here |