| 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,6 +362,9 @@ pub fn renderError(tree: Ast, parse_error: Error, stream: anytype) !void { |
| 362 | .wrong_equal_var_decl => { | 362 | .wrong_equal_var_decl => { |
| 363 | return stream.writeAll("variable initialized with '==' instead of '='"); | 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 | .expected_token => { | 369 | .expected_token => { |
| 367 | const found_tag = token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)]; | 370 | const found_tag = token_tags[parse_error.token + @boolToInt(parse_error.token_is_prev)]; |
| ... | @@ -2743,6 +2746,7 @@ pub const Error = struct { | ... | @@ -2743,6 +2746,7 @@ pub const Error = struct { |
| 2743 | c_style_container, | 2746 | c_style_container, |
| 2744 | expected_var_const, | 2747 | expected_var_const, |
| 2745 | wrong_equal_var_decl, | 2748 | wrong_equal_var_decl, |
| 2749 | var_const_decl, | ||
| 2746 | 2750 | ||
| 2747 | zig_style_container, | 2751 | zig_style_container, |
| 2748 | previous_field, | 2752 | previous_field, |
lib/std/zig/parse.zig+7| ... | @@ -471,6 +471,13 @@ const Parser = struct { | ... | @@ -471,6 +471,13 @@ const Parser = struct { |
| 471 | // There is not allowed to be a decl after a field with no comma. | 471 | // There is not allowed to be a decl after a field with no comma. |
| 472 | // Report error but recover parser. | 472 | // Report error but recover parser. |
| 473 | try p.warn(.expected_comma_after_field); | 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 | p.findNextContainerMember(); | 481 | p.findNextContainerMember(); |
| 475 | continue; | 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,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 | test "zig fmt: while continue expr" { | 5253 | test "zig fmt: while continue expr" { |
| 5242 | try testCanonical( | 5254 | try testCanonical( |
| 5243 | \\test { | 5255 | \\test { |
src/AstGen.zig+18-2| ... | @@ -2463,6 +2463,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As | ... | @@ -2463,6 +2463,7 @@ fn addEnsureResult(gz: *GenZir, maybe_unused_result: Zir.Inst.Ref, statement: As |
| 2463 | .is_non_null_ptr, | 2463 | .is_non_null_ptr, |
| 2464 | .is_non_err, | 2464 | .is_non_err, |
| 2465 | .is_non_err_ptr, | 2465 | .is_non_err_ptr, |
| 2466 | .ret_is_non_err, | ||
| 2466 | .mod_rem, | 2467 | .mod_rem, |
| 2467 | .mul, | 2468 | .mul, |
| 2468 | .mulwrap, | 2469 | .mulwrap, |
| ... | @@ -4486,9 +4487,24 @@ fn structDeclInner( | ... | @@ -4486,9 +4487,24 @@ fn structDeclInner( |
| 4486 | .container_field_align, | 4487 | .container_field_align, |
| 4487 | .container_field, | 4488 | .container_field, |
| 4488 | .@"comptime", | 4489 | .@"comptime", |
| 4490 | .test_decl, | ||
| 4489 | => continue, | 4491 | => continue, |
| 4490 | else => { | 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,7 +7028,7 @@ fn ret(gz: *GenZir, scope: *Scope, node: Ast.Node.Index) InnerError!Zir.Inst.Ref |
| 7012 | 7028 | ||
| 7013 | // Emit conditional branch for generating errdefers. | 7029 | // Emit conditional branch for generating errdefers. |
| 7014 | const result = if (ri.rl == .ptr) try gz.addUnNode(.load, ri.rl.ptr.inst, node) else operand; | 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 | const condbr = try gz.addCondBr(.condbr, node); | 7032 | const condbr = try gz.addCondBr(.condbr, node); |
| 7017 | 7033 | ||
| 7018 | var then_scope = gz.makeSubBlock(scope); | 7034 | var then_scope = gz.makeSubBlock(scope); |
src/Module.zig+22-9| ... | @@ -528,10 +528,10 @@ pub const Decl = struct { | ... | @@ -528,10 +528,10 @@ pub const Decl = struct { |
| 528 | /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it | 528 | /// Decl is marked alive, then it sends the Decl to the linker. Otherwise it |
| 529 | /// deletes the Decl on the spot. | 529 | /// deletes the Decl on the spot. |
| 530 | alive: bool, | 530 | alive: bool, |
| 531 | /// Whether the Decl is a `usingnamespace` declaration. | ||
| 532 | is_usingnamespace: bool, | ||
| 533 | /// If true `name` is already fully qualified. | 531 | /// If true `name` is already fully qualified. |
| 534 | name_fully_qualified: bool = false, | 532 | name_fully_qualified: bool = false, |
| 533 | /// What kind of a declaration is this. | ||
| 534 | kind: Kind, | ||
| 535 | 535 | ||
| 536 | /// Represents the position of the code in the output file. | 536 | /// Represents the position of the code in the output file. |
| 537 | /// This is populated regardless of semantic analysis and code generation. | 537 | /// This is populated regardless of semantic analysis and code generation. |
| ... | @@ -551,6 +551,14 @@ pub const Decl = struct { | ... | @@ -551,6 +551,14 @@ pub const Decl = struct { |
| 551 | /// typed_value may need to be regenerated. | 551 | /// typed_value may need to be regenerated. |
| 552 | dependencies: DepsTable = .{}, | 552 | dependencies: DepsTable = .{}, |
| 553 | 553 | ||
| 554 | pub const Kind = enum { | ||
| 555 | @"usingnamespace", | ||
| 556 | @"test", | ||
| 557 | @"comptime", | ||
| 558 | named, | ||
| 559 | anon, | ||
| 560 | }; | ||
| 561 | |||
| 554 | pub const Index = enum(u32) { | 562 | pub const Index = enum(u32) { |
| 555 | _, | 563 | _, |
| 556 | 564 | ||
| ... | @@ -4438,7 +4446,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { | ... | @@ -4438,7 +4446,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4438 | // not the struct itself. | 4446 | // not the struct itself. |
| 4439 | try sema.resolveTypeLayout(decl_tv.ty); | 4447 | try sema.resolveTypeLayout(decl_tv.ty); |
| 4440 | 4448 | ||
| 4441 | if (decl.is_usingnamespace) { | 4449 | if (decl.kind == .@"usingnamespace") { |
| 4442 | if (!decl_tv.ty.eql(Type.type, mod)) { | 4450 | if (!decl_tv.ty.eql(Type.type, mod)) { |
| 4443 | return sema.fail(&block_scope, ty_src, "expected type, found {}", .{ | 4451 | return sema.fail(&block_scope, ty_src, "expected type, found {}", .{ |
| 4444 | decl_tv.ty.fmt(mod), | 4452 | decl_tv.ty.fmt(mod), |
| ... | @@ -4964,26 +4972,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -4964,26 +4972,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 4964 | 4972 | ||
| 4965 | // Every Decl needs a name. | 4973 | // Every Decl needs a name. |
| 4966 | var is_named_test = false; | 4974 | var is_named_test = false; |
| 4975 | var kind: Decl.Kind = .named; | ||
| 4967 | const decl_name: [:0]const u8 = switch (decl_name_index) { | 4976 | const decl_name: [:0]const u8 = switch (decl_name_index) { |
| 4968 | 0 => name: { | 4977 | 0 => name: { |
| 4969 | if (export_bit) { | 4978 | if (export_bit) { |
| 4970 | const i = iter.usingnamespace_index; | 4979 | const i = iter.usingnamespace_index; |
| 4971 | iter.usingnamespace_index += 1; | 4980 | iter.usingnamespace_index += 1; |
| 4981 | kind = .@"usingnamespace"; | ||
| 4972 | break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); | 4982 | break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); |
| 4973 | } else { | 4983 | } else { |
| 4974 | const i = iter.comptime_index; | 4984 | const i = iter.comptime_index; |
| 4975 | iter.comptime_index += 1; | 4985 | iter.comptime_index += 1; |
| 4986 | kind = .@"comptime"; | ||
| 4976 | break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i}); | 4987 | break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i}); |
| 4977 | } | 4988 | } |
| 4978 | }, | 4989 | }, |
| 4979 | 1 => name: { | 4990 | 1 => name: { |
| 4980 | const i = iter.unnamed_test_index; | 4991 | const i = iter.unnamed_test_index; |
| 4981 | iter.unnamed_test_index += 1; | 4992 | iter.unnamed_test_index += 1; |
| 4993 | kind = .@"test"; | ||
| 4982 | break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i}); | 4994 | break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i}); |
| 4983 | }, | 4995 | }, |
| 4984 | 2 => name: { | 4996 | 2 => name: { |
| 4985 | is_named_test = true; | 4997 | is_named_test = true; |
| 4986 | const test_name = zir.nullTerminatedString(decl_doccomment_index); | 4998 | const test_name = zir.nullTerminatedString(decl_doccomment_index); |
| 4999 | kind = .@"test"; | ||
| 4987 | break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name}); | 5000 | break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name}); |
| 4988 | }, | 5001 | }, |
| 4989 | else => name: { | 5002 | else => name: { |
| ... | @@ -4991,6 +5004,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -4991,6 +5004,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 4991 | if (raw_name.len == 0) { | 5004 | if (raw_name.len == 0) { |
| 4992 | is_named_test = true; | 5005 | is_named_test = true; |
| 4993 | const test_name = zir.nullTerminatedString(decl_name_index + 1); | 5006 | const test_name = zir.nullTerminatedString(decl_name_index + 1); |
| 5007 | kind = .@"test"; | ||
| 4994 | break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); | 5008 | break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); |
| 4995 | } else { | 5009 | } else { |
| 4996 | break :name try gpa.dupeZ(u8, raw_name); | 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,8 +5012,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 4998 | }, | 5012 | }, |
| 4999 | }; | 5013 | }; |
| 5000 | const is_exported = export_bit and decl_name_index != 0; | 5014 | const is_exported = export_bit and decl_name_index != 0; |
| 5001 | const is_usingnamespace = export_bit and decl_name_index == 0; | 5015 | if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); |
| 5002 | if (is_usingnamespace) try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); | ||
| 5003 | 5016 | ||
| 5004 | // We create a Decl for it regardless of analysis status. | 5017 | // We create a Decl for it regardless of analysis status. |
| 5005 | const gop = try namespace.decls.getOrPutContextAdapted( | 5018 | const gop = try namespace.decls.getOrPutContextAdapted( |
| ... | @@ -5012,8 +5025,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err | ... | @@ -5012,8 +5025,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5012 | if (!gop.found_existing) { | 5025 | if (!gop.found_existing) { |
| 5013 | const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope); | 5026 | const new_decl_index = try mod.allocateNewDecl(namespace, decl_node, iter.parent_decl.src_scope); |
| 5014 | const new_decl = mod.declPtr(new_decl_index); | 5027 | const new_decl = mod.declPtr(new_decl_index); |
| 5028 | new_decl.kind = kind; | ||
| 5015 | new_decl.name = decl_name; | 5029 | new_decl.name = decl_name; |
| 5016 | if (is_usingnamespace) { | 5030 | if (kind == .@"usingnamespace") { |
| 5017 | namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub); | 5031 | namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub); |
| 5018 | } | 5032 | } |
| 5019 | log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace }); | 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,7 +5072,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5058 | } | 5072 | } |
| 5059 | new_decl.is_pub = is_pub; | 5073 | new_decl.is_pub = is_pub; |
| 5060 | new_decl.is_exported = is_exported; | 5074 | new_decl.is_exported = is_exported; |
| 5061 | new_decl.is_usingnamespace = is_usingnamespace; | ||
| 5062 | new_decl.has_align = has_align; | 5075 | new_decl.has_align = has_align; |
| 5063 | new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace; | 5076 | new_decl.has_linksection_or_addrspace = has_linksection_or_addrspace; |
| 5064 | new_decl.zir_decl_index = @intCast(u32, decl_sub_index); | 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,7 +5089,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err |
| 5076 | 5089 | ||
| 5077 | decl.is_pub = is_pub; | 5090 | decl.is_pub = is_pub; |
| 5078 | decl.is_exported = is_exported; | 5091 | decl.is_exported = is_exported; |
| 5079 | decl.is_usingnamespace = is_usingnamespace; | 5092 | decl.kind = kind; |
| 5080 | decl.has_align = has_align; | 5093 | decl.has_align = has_align; |
| 5081 | decl.has_linksection_or_addrspace = has_linksection_or_addrspace; | 5094 | decl.has_linksection_or_addrspace = has_linksection_or_addrspace; |
| 5082 | decl.zir_decl_index = @intCast(u32, decl_sub_index); | 5095 | decl.zir_decl_index = @intCast(u32, decl_sub_index); |
| ... | @@ -5635,7 +5648,7 @@ pub fn allocateNewDecl( | ... | @@ -5635,7 +5648,7 @@ pub fn allocateNewDecl( |
| 5635 | .has_linksection_or_addrspace = false, | 5648 | .has_linksection_or_addrspace = false, |
| 5636 | .has_align = false, | 5649 | .has_align = false, |
| 5637 | .alive = false, | 5650 | .alive = false, |
| 5638 | .is_usingnamespace = false, | 5651 | .kind = .anon, |
| 5639 | }; | 5652 | }; |
| 5640 | 5653 | ||
| 5641 | return decl_and_index.decl_index; | 5654 | return decl_and_index.decl_index; |
src/Sema.zig+76-27| ... | @@ -953,6 +953,7 @@ fn analyzeBodyInner( | ... | @@ -953,6 +953,7 @@ fn analyzeBodyInner( |
| 953 | .int_type => try sema.zirIntType(block, inst), | 953 | .int_type => try sema.zirIntType(block, inst), |
| 954 | .is_non_err => try sema.zirIsNonErr(block, inst), | 954 | .is_non_err => try sema.zirIsNonErr(block, inst), |
| 955 | .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), | 955 | .is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst), |
| 956 | .ret_is_non_err => try sema.zirRetIsNonErr(block, inst), | ||
| 956 | .is_non_null => try sema.zirIsNonNull(block, inst), | 957 | .is_non_null => try sema.zirIsNonNull(block, inst), |
| 957 | .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst), | 958 | .is_non_null_ptr => try sema.zirIsNonNullPtr(block, inst), |
| 958 | .merge_error_sets => try sema.zirMergeErrorSets(block, inst), | 959 | .merge_error_sets => try sema.zirMergeErrorSets(block, inst), |
| ... | @@ -9004,7 +9005,7 @@ fn zirParam( | ... | @@ -9004,7 +9005,7 @@ fn zirParam( |
| 9004 | else => |e| return e, | 9005 | else => |e| return e, |
| 9005 | } or comptime_syntax; | 9006 | } or comptime_syntax; |
| 9006 | if (sema.inst_map.get(inst)) |arg| { | 9007 | if (sema.inst_map.get(inst)) |arg| { |
| 9007 | if (is_comptime) { | 9008 | if (is_comptime and sema.preallocated_new_func != null) { |
| 9008 | // We have a comptime value for this parameter so it should be elided from the | 9009 | // We have a comptime value for this parameter so it should be elided from the |
| 9009 | // function type of the function instruction in this block. | 9010 | // function type of the function instruction in this block. |
| 9010 | const coerced_arg = try sema.coerce(block, param_ty, arg, src); | 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,6 +10289,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 10288 | .ret_err_value_code, | 10289 | .ret_err_value_code, |
| 10289 | .restore_err_ret_index, | 10290 | .restore_err_ret_index, |
| 10290 | .is_non_err, | 10291 | .is_non_err, |
| 10292 | .ret_is_non_err, | ||
| 10291 | .condbr, | 10293 | .condbr, |
| 10292 | => {}, | 10294 | => {}, |
| 10293 | else => break, | 10295 | else => break, |
| ... | @@ -16215,11 +16217,54 @@ fn typeInfoDecls( | ... | @@ -16215,11 +16217,54 @@ fn typeInfoDecls( |
| 16215 | }; | 16217 | }; |
| 16216 | try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena)); | 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; | 16220 | var decl_vals = std.ArrayList(Value).init(sema.gpa); |
| 16219 | const decls_vals = try decls_anon_decl.arena().alloc(Value, decls_len); | 16221 | defer decl_vals.deinit(); |
| 16220 | for (decls_vals) |*decls_val, i| { | 16222 | |
| 16221 | const decl_index = opt_namespace.?.decls.keys()[i]; | 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 | const decl = sema.mod.declPtr(decl_index); | 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 | const name_val = v: { | 16268 | const name_val = v: { |
| 16224 | var anon_decl = try block.startAnonDecl(); | 16269 | var anon_decl = try block.startAnonDecl(); |
| 16225 | defer anon_decl.deinit(); | 16270 | defer anon_decl.deinit(); |
| ... | @@ -16229,37 +16274,21 @@ fn typeInfoDecls( | ... | @@ -16229,37 +16274,21 @@ fn typeInfoDecls( |
| 16229 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), | 16274 | try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]), |
| 16230 | 0, // default alignment | 16275 | 0, // default alignment |
| 16231 | ); | 16276 | ); |
| 16232 | break :v try Value.Tag.slice.create(decls_anon_decl.arena(), .{ | 16277 | break :v try Value.Tag.slice.create(decls_anon_decl, .{ |
| 16233 | .ptr = try Value.Tag.decl_ref.create(decls_anon_decl.arena(), new_decl), | 16278 | .ptr = try Value.Tag.decl_ref.create(decls_anon_decl, new_decl), |
| 16234 | .len = try Value.Tag.int_u64.create(decls_anon_decl.arena(), bytes.len), | 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 | fields.* = .{ | 16284 | fields.* = .{ |
| 16240 | //name: []const u8, | 16285 | //name: []const u8, |
| 16241 | name_val, | 16286 | name_val, |
| 16242 | //is_pub: bool, | 16287 | //is_pub: bool, |
| 16243 | Value.makeBool(decl.is_pub), | 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 | fn zirTypeof(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 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,7 +16606,7 @@ fn zirIsNonErr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai |
| 16577 | const src = inst_data.src(); | 16606 | const src = inst_data.src(); |
| 16578 | const operand = try sema.resolveInst(inst_data.operand); | 16607 | const operand = try sema.resolveInst(inst_data.operand); |
| 16579 | try sema.checkErrorType(block, src, sema.typeOf(operand)); | 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 | fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 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,6 +16621,16 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError |
| 16592 | return sema.analyzeIsNonErr(block, src, loaded); | 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 | fn zirCondbr( | 16634 | fn zirCondbr( |
| 16596 | sema: *Sema, | 16635 | sema: *Sema, |
| 16597 | parent_block: *Block, | 16636 | parent_block: *Block, |
| ... | @@ -29847,6 +29886,11 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -29847,6 +29886,11 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { |
| 29847 | }, | 29886 | }, |
| 29848 | .have_layout, .fully_resolved_wip, .fully_resolved => return, | 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 | struct_obj.status = .layout_wip; | 29894 | struct_obj.status = .layout_wip; |
| 29851 | for (struct_obj.fields.values()) |field, i| { | 29895 | for (struct_obj.fields.values()) |field, i| { |
| 29852 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { | 29896 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { |
| ... | @@ -30026,6 +30070,11 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { | ... | @@ -30026,6 +30070,11 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void { |
| 30026 | }, | 30070 | }, |
| 30027 | .have_layout, .fully_resolved_wip, .fully_resolved => return, | 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 | union_obj.status = .layout_wip; | 30078 | union_obj.status = .layout_wip; |
| 30030 | for (union_obj.fields.values()) |field, i| { | 30079 | for (union_obj.fields.values()) |field, i| { |
| 30031 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { | 30080 | sema.resolveTypeLayout(field.ty) catch |err| switch (err) { |
src/Zir.zig+6| ... | @@ -481,6 +481,9 @@ pub const Inst = struct { | ... | @@ -481,6 +481,9 @@ pub const Inst = struct { |
| 481 | /// Return a boolean false if dereferenced pointer is an error | 481 | /// Return a boolean false if dereferenced pointer is an error |
| 482 | /// Uses the `un_node` field. | 482 | /// Uses the `un_node` field. |
| 483 | is_non_err_ptr, | 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 | /// A labeled block of code that loops forever. At the end of the body will have either | 487 | /// A labeled block of code that loops forever. At the end of the body will have either |
| 485 | /// a `repeat` instruction or a `repeat_inline` instruction. | 488 | /// a `repeat` instruction or a `repeat_inline` instruction. |
| 486 | /// Uses the `pl_node` field. The AST node is either a for loop or while loop. | 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,6 +1086,7 @@ pub const Inst = struct { |
| 1083 | .is_non_null_ptr, | 1086 | .is_non_null_ptr, |
| 1084 | .is_non_err, | 1087 | .is_non_err, |
| 1085 | .is_non_err_ptr, | 1088 | .is_non_err_ptr, |
| 1089 | .ret_is_non_err, | ||
| 1086 | .mod_rem, | 1090 | .mod_rem, |
| 1087 | .mul, | 1091 | .mul, |
| 1088 | .mulwrap, | 1092 | .mulwrap, |
| ... | @@ -1386,6 +1390,7 @@ pub const Inst = struct { | ... | @@ -1386,6 +1390,7 @@ pub const Inst = struct { |
| 1386 | .is_non_null_ptr, | 1390 | .is_non_null_ptr, |
| 1387 | .is_non_err, | 1391 | .is_non_err, |
| 1388 | .is_non_err_ptr, | 1392 | .is_non_err_ptr, |
| 1393 | .ret_is_non_err, | ||
| 1389 | .mod_rem, | 1394 | .mod_rem, |
| 1390 | .mul, | 1395 | .mul, |
| 1391 | .mulwrap, | 1396 | .mulwrap, |
| ... | @@ -1640,6 +1645,7 @@ pub const Inst = struct { | ... | @@ -1640,6 +1645,7 @@ pub const Inst = struct { |
| 1640 | .is_non_null_ptr = .un_node, | 1645 | .is_non_null_ptr = .un_node, |
| 1641 | .is_non_err = .un_node, | 1646 | .is_non_err = .un_node, |
| 1642 | .is_non_err_ptr = .un_node, | 1647 | .is_non_err_ptr = .un_node, |
| 1648 | .ret_is_non_err = .un_node, | ||
| 1643 | .loop = .pl_node, | 1649 | .loop = .pl_node, |
| 1644 | .repeat = .node, | 1650 | .repeat = .node, |
| 1645 | .repeat_inline = .node, | 1651 | .repeat_inline = .node, |
src/print_zir.zig+1| ... | @@ -179,6 +179,7 @@ const Writer = struct { | ... | @@ -179,6 +179,7 @@ const Writer = struct { |
| 179 | .is_non_null_ptr, | 179 | .is_non_null_ptr, |
| 180 | .is_non_err, | 180 | .is_non_err, |
| 181 | .is_non_err_ptr, | 181 | .is_non_err_ptr, |
| 182 | .ret_is_non_err, | ||
| 182 | .typeof, | 183 | .typeof, |
| 183 | .struct_init_empty, | 184 | .struct_init_empty, |
| 184 | .type_info, | 185 | .type_info, |
src/value.zig+10-2| ... | @@ -2193,8 +2193,16 @@ pub const Value = extern union { | ... | @@ -2193,8 +2193,16 @@ pub const Value = extern union { |
| 2193 | const payload_ty = ty.errorUnionPayload(); | 2193 | const payload_ty = ty.errorUnionPayload(); |
| 2194 | return eqlAdvanced(a_payload, payload_ty, b_payload, payload_ty, mod, opt_sema); | 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"), | 2196 | .eu_payload_ptr => { |
| 2197 | .opt_payload_ptr => @panic("TODO: Implement more pointer eql cases"), | 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 | .function => { | 2206 | .function => { |
| 2199 | const a_payload = a.castTag(.function).?.data; | 2207 | const a_payload = a.castTag(.function).?.data; |
| 2200 | const b_payload = b.castTag(.function).?.data; | 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,3 +148,14 @@ test "simple else prong doesn't emit an error for unreachable else prong" { |
| 148 | }; | 148 | }; |
| 149 | try expect(a == 1); | 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,3 +566,27 @@ test "value from struct @typeInfo default_value can be loaded at comptime" { |
| 566 | try expect(@ptrCast(*const u8, a).* == 1); | 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,3 +23,4 @@ const T = struct { |
| 23 | // :5:5: error: union field missing name | 23 | // :5:5: error: union field missing name |
| 24 | // :8:5: error: tuple field has a name | 24 | // :8:5: error: tuple field has a name |
| 25 | // :15:5: error: tuple declarations cannot contain declarations | 25 | // :15:5: error: tuple declarations cannot contain declarations |
| 26 | // :12:5: note: tuple field here |