| author | |
| committer | |
| log | d0226ac301140cb552dfc3da24cea7693d29c64f |
| tree | accc9db0c3b255655f111bbc25eaf227b9155ace |
| parent | 67a5b6e5e8280ef736d458c4596137c58c2c253a |
| parent | 6608b65100648a1ef5ac1951a744b4f73756378d |
Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31889
Reviewed-by: Andrew Kelley <andrew@ziglang.org>5 files changed, 169 insertions(+), 106 deletions(-)
lib/std/zig/Zir.zig+50-47| ... | ... | @@ -4021,30 +4021,30 @@ pub const DeclContents = struct { |
| 4021 | 4021 | /// This is a simple optional because ZIR guarantees that a `func`/`func_inferred`/`func_fancy` instruction |
| 4022 | 4022 | /// can only occur once per `declaration`. |
| 4023 | 4023 | func_decl: ?Inst.Index, |
| 4024 | explicit_types: std.ArrayList(Inst.Index), | |
| 4024 | type_decls: std.ArrayList(Inst.Index), | |
| 4025 | 4025 | other: std.ArrayList(Inst.Index), |
| 4026 | 4026 | |
| 4027 | 4027 | pub const init: DeclContents = .{ |
| 4028 | 4028 | .func_decl = null, |
| 4029 | .explicit_types = .empty, | |
| 4029 | .type_decls = .empty, | |
| 4030 | 4030 | .other = .empty, |
| 4031 | 4031 | }; |
| 4032 | 4032 | |
| 4033 | 4033 | pub fn clear(contents: *DeclContents) void { |
| 4034 | 4034 | contents.func_decl = null; |
| 4035 | contents.explicit_types.clearRetainingCapacity(); | |
| 4035 | contents.type_decls.clearRetainingCapacity(); | |
| 4036 | 4036 | contents.other.clearRetainingCapacity(); |
| 4037 | 4037 | } |
| 4038 | 4038 | |
| 4039 | 4039 | pub fn deinit(contents: *DeclContents, gpa: Allocator) void { |
| 4040 | contents.explicit_types.deinit(gpa); | |
| 4040 | contents.type_decls.deinit(gpa); | |
| 4041 | 4041 | contents.other.deinit(gpa); |
| 4042 | 4042 | } |
| 4043 | 4043 | }; |
| 4044 | 4044 | |
| 4045 | 4045 | /// Find all tracked ZIR instructions, recursively, within a `declaration` instruction. Does not recurse through |
| 4046 | 4046 | /// nested declarations; to find all declarations, call this function recursively on the type declarations discovered |
| 4047 | /// in `contents.explicit_types`. | |
| 4047 | /// in `contents.type_decls`. | |
| 4048 | 4048 | /// |
| 4049 | 4049 | /// This populates an `ArrayList` because an iterator would need to allocate memory anyway. |
| 4050 | 4050 | pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_inst: Zir.Inst.Index) !void { |
| ... | ... | @@ -4064,15 +4064,49 @@ pub fn findTrackable(zir: Zir, gpa: Allocator, contents: *DeclContents, decl_ins |
| 4064 | 4064 | if (decl.value_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); |
| 4065 | 4065 | } |
| 4066 | 4066 | |
| 4067 | /// Like `findTrackable`, but only considers the `main_struct_inst` instruction. This may return more than | |
| 4068 | /// just that instruction because it will also traverse fields. | |
| 4069 | pub fn findTrackableRoot(zir: Zir, gpa: Allocator, contents: *DeclContents) !void { | |
| 4067 | /// `findTrackable` does not recurse into field expressions in a type. Instead, this function will | |
| 4068 | /// scan specifically field expressions in a given type declaration for trackable ZIR instructions. | |
| 4069 | pub fn findTrackableFields( | |
| 4070 | zir: *const Zir, | |
| 4071 | gpa: Allocator, | |
| 4072 | contents: *DeclContents, | |
| 4073 | type_decl_inst: Zir.Inst.Index, | |
| 4074 | ) Allocator.Error!void { | |
| 4070 | 4075 | contents.clear(); |
| 4071 | 4076 | |
| 4072 | 4077 | var found_defers: std.AutoHashMapUnmanaged(u32, void) = .empty; |
| 4073 | 4078 | defer found_defers.deinit(gpa); |
| 4074 | 4079 | |
| 4075 | try zir.findTrackableInner(gpa, contents, &found_defers, .main_struct_inst); | |
| 4080 | assert(zir.instructions.items(.tag)[@intFromEnum(type_decl_inst)] == .extended); | |
| 4081 | switch (zir.instructions.items(.data)[@intFromEnum(type_decl_inst)].extended.opcode) { | |
| 4082 | .struct_decl => { | |
| 4083 | const struct_decl = zir.getStructDecl(type_decl_inst); | |
| 4084 | var it = struct_decl.iterateFields(); | |
| 4085 | while (it.next()) |field| { | |
| 4086 | try zir.findTrackableBody(gpa, contents, &found_defers, field.type_body); | |
| 4087 | if (field.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); | |
| 4088 | if (field.default_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); | |
| 4089 | } | |
| 4090 | }, | |
| 4091 | .union_decl => { | |
| 4092 | const union_decl = zir.getUnionDecl(type_decl_inst); | |
| 4093 | var it = union_decl.iterateFields(); | |
| 4094 | while (it.next()) |field| { | |
| 4095 | if (field.type_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); | |
| 4096 | if (field.align_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); | |
| 4097 | if (field.value_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); | |
| 4098 | } | |
| 4099 | }, | |
| 4100 | .enum_decl => { | |
| 4101 | const enum_decl = zir.getEnumDecl(type_decl_inst); | |
| 4102 | var it = enum_decl.iterateFields(); | |
| 4103 | while (it.next()) |field| { | |
| 4104 | if (field.value_body) |b| try zir.findTrackableBody(gpa, contents, &found_defers, b); | |
| 4105 | } | |
| 4106 | }, | |
| 4107 | .opaque_decl => {}, | |
| 4108 | else => unreachable, | |
| 4109 | } | |
| 4076 | 4110 | } |
| 4077 | 4111 | |
| 4078 | 4112 | fn findTrackableInner( |
| ... | ... | @@ -4396,49 +4430,18 @@ fn findTrackableInner( |
| 4396 | 4430 | try zir.findTrackableBody(gpa, contents, defers, body); |
| 4397 | 4431 | }, |
| 4398 | 4432 | |
| 4399 | // Reifications and opaque declarations need tracking, but have no bodies. | |
| 4433 | // Reifications need tracking. | |
| 4400 | 4434 | .reify_enum, |
| 4401 | 4435 | .reify_struct, |
| 4402 | 4436 | .reify_union, |
| 4403 | .opaque_decl, | |
| 4404 | 4437 | => return contents.other.append(gpa, inst), |
| 4405 | 4438 | |
| 4406 | // Struct declarations need tracking and have bodies. | |
| 4407 | .struct_decl => { | |
| 4408 | try contents.explicit_types.append(gpa, inst); | |
| 4409 | ||
| 4410 | const struct_decl = zir.getStructDecl(inst); | |
| 4411 | var it = struct_decl.iterateFields(); | |
| 4412 | while (it.next()) |field| { | |
| 4413 | try zir.findTrackableBody(gpa, contents, defers, field.type_body); | |
| 4414 | if (field.align_body) |b| try zir.findTrackableBody(gpa, contents, defers, b); | |
| 4415 | if (field.default_body) |b| try zir.findTrackableBody(gpa, contents, defers, b); | |
| 4416 | } | |
| 4417 | }, | |
| 4418 | ||
| 4419 | // Union declarations need tracking and have bodies. | |
| 4420 | .union_decl => { | |
| 4421 | try contents.explicit_types.append(gpa, inst); | |
| 4422 | ||
| 4423 | const union_decl = zir.getUnionDecl(inst); | |
| 4424 | var it = union_decl.iterateFields(); | |
| 4425 | while (it.next()) |field| { | |
| 4426 | if (field.type_body) |b| try zir.findTrackableBody(gpa, contents, defers, b); | |
| 4427 | if (field.align_body) |b| try zir.findTrackableBody(gpa, contents, defers, b); | |
| 4428 | if (field.value_body) |b| try zir.findTrackableBody(gpa, contents, defers, b); | |
| 4429 | } | |
| 4430 | }, | |
| 4431 | ||
| 4432 | // Enum declarations need tracking and have bodies. | |
| 4433 | .enum_decl => { | |
| 4434 | try contents.explicit_types.append(gpa, inst); | |
| 4435 | ||
| 4436 | const enum_decl = zir.getEnumDecl(inst); | |
| 4437 | var it = enum_decl.iterateFields(); | |
| 4438 | while (it.next()) |field| { | |
| 4439 | if (field.value_body) |b| try zir.findTrackableBody(gpa, contents, defers, b); | |
| 4440 | } | |
| 4441 | }, | |
| 4439 | // Type declarations need tracking. | |
| 4440 | .struct_decl, | |
| 4441 | .union_decl, | |
| 4442 | .enum_decl, | |
| 4443 | .opaque_decl, | |
| 4444 | => return contents.type_decls.append(gpa, inst), | |
| 4442 | 4445 | } |
| 4443 | 4446 | }, |
| 4444 | 4447 |
src/Zcu.zig+46-44| ... | ... | @@ -3361,8 +3361,8 @@ pub fn mapOldZirToNew( |
| 3361 | 3361 | old_inst: Zir.Inst.Index, |
| 3362 | 3362 | new_inst: Zir.Inst.Index, |
| 3363 | 3363 | }; |
| 3364 | var match_stack: std.ArrayList(MatchedZirDecl) = .empty; | |
| 3365 | defer match_stack.deinit(gpa); | |
| 3364 | var pending_matched_type_decls: std.ArrayList(MatchedZirDecl) = .empty; | |
| 3365 | defer pending_matched_type_decls.deinit(gpa); | |
| 3366 | 3366 | |
| 3367 | 3367 | // Used as temporary buffers for namespace declaration instructions |
| 3368 | 3368 | var old_contents: Zir.DeclContents = .init; |
| ... | ... | @@ -3370,42 +3370,13 @@ pub fn mapOldZirToNew( |
| 3370 | 3370 | var new_contents: Zir.DeclContents = .init; |
| 3371 | 3371 | defer new_contents.deinit(gpa); |
| 3372 | 3372 | |
| 3373 | // Map the main struct inst (and anything in its fields) | |
| 3374 | { | |
| 3375 | try old_zir.findTrackableRoot(gpa, &old_contents); | |
| 3376 | try new_zir.findTrackableRoot(gpa, &new_contents); | |
| 3377 | ||
| 3378 | assert(old_contents.explicit_types.items[0] == .main_struct_inst); | |
| 3379 | assert(new_contents.explicit_types.items[0] == .main_struct_inst); | |
| 3380 | ||
| 3381 | assert(old_contents.func_decl == null); | |
| 3382 | assert(new_contents.func_decl == null); | |
| 3383 | ||
| 3384 | // We don't have any smart way of matching up these instructions, so we correlate them based on source order | |
| 3385 | // in their respective arrays. | |
| 3386 | ||
| 3387 | const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len); | |
| 3388 | try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types)); | |
| 3389 | for ( | |
| 3390 | old_contents.explicit_types.items[0..num_explicit_types], | |
| 3391 | new_contents.explicit_types.items[0..num_explicit_types], | |
| 3392 | ) |old_inst, new_inst| { | |
| 3393 | // Here we use `match_stack`, so that we will recursively consider declarations on these types. | |
| 3394 | match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst }); | |
| 3395 | } | |
| 3396 | ||
| 3397 | const num_other = @min(old_contents.other.items.len, new_contents.other.items.len); | |
| 3398 | try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other)); | |
| 3399 | for ( | |
| 3400 | old_contents.other.items[0..num_other], | |
| 3401 | new_contents.other.items[0..num_other], | |
| 3402 | ) |old_inst, new_inst| { | |
| 3403 | // These instructions don't have declarations, so we just modify `inst_map` directly. | |
| 3404 | inst_map.putAssumeCapacity(old_inst, new_inst); | |
| 3405 | } | |
| 3406 | } | |
| 3373 | // Map the main struct inst to start off with. | |
| 3374 | try pending_matched_type_decls.append(gpa, .{ | |
| 3375 | .old_inst = .main_struct_inst, | |
| 3376 | .new_inst = .main_struct_inst, | |
| 3377 | }); | |
| 3407 | 3378 | |
| 3408 | while (match_stack.pop()) |match_item| { | |
| 3379 | while (pending_matched_type_decls.pop()) |match_item| { | |
| 3409 | 3380 | // There are some properties of type declarations which cannot change across incremental |
| 3410 | 3381 | // updates. If they have, we need to ignore this mapping. These properties are essentially |
| 3411 | 3382 | // everything passed into `InternPool.getDeclaredStructType` (likewise for unions, enums, |
| ... | ... | @@ -3461,9 +3432,41 @@ pub fn mapOldZirToNew( |
| 3461 | 3432 | else => unreachable, |
| 3462 | 3433 | } |
| 3463 | 3434 | |
| 3464 | // Match the namespace declaration itself | |
| 3435 | // Match the container declaration itself | |
| 3465 | 3436 | try inst_map.put(gpa, match_item.old_inst, match_item.new_inst); |
| 3466 | 3437 | |
| 3438 | { | |
| 3439 | // First, map the fields... | |
| 3440 | try old_zir.findTrackableFields(gpa, &old_contents, match_item.old_inst); | |
| 3441 | try new_zir.findTrackableFields(gpa, &new_contents, match_item.new_inst); | |
| 3442 | ||
| 3443 | // This isn't a `.declaration`, so we shouldn't see a function declaration. | |
| 3444 | assert(old_contents.func_decl == null); | |
| 3445 | assert(new_contents.func_decl == null); | |
| 3446 | ||
| 3447 | // We don't have any smart way of matching up these instructions, so we correlate them based on source order | |
| 3448 | // in their respective arrays. | |
| 3449 | ||
| 3450 | const num_type_decls = @min(old_contents.type_decls.items.len, new_contents.type_decls.items.len); | |
| 3451 | try pending_matched_type_decls.ensureUnusedCapacity(gpa, @intCast(num_type_decls)); | |
| 3452 | for ( | |
| 3453 | old_contents.type_decls.items[0..num_type_decls], | |
| 3454 | new_contents.type_decls.items[0..num_type_decls], | |
| 3455 | ) |old_inst, new_inst| { | |
| 3456 | pending_matched_type_decls.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst }); | |
| 3457 | } | |
| 3458 | ||
| 3459 | const num_other = @min(old_contents.other.items.len, new_contents.other.items.len); | |
| 3460 | try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other)); | |
| 3461 | for ( | |
| 3462 | old_contents.other.items[0..num_other], | |
| 3463 | new_contents.other.items[0..num_other], | |
| 3464 | ) |old_inst, new_inst| { | |
| 3465 | // These instructions don't have declarations, so we just modify `inst_map` directly. | |
| 3466 | inst_map.putAssumeCapacity(old_inst, new_inst); | |
| 3467 | } | |
| 3468 | } | |
| 3469 | ||
| 3467 | 3470 | // Maps decl name to `declaration` instruction. |
| 3468 | 3471 | var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .empty; |
| 3469 | 3472 | defer named_decls.deinit(gpa); |
| ... | ... | @@ -3537,14 +3540,13 @@ pub fn mapOldZirToNew( |
| 3537 | 3540 | // We don't have any smart way of matching up these instructions, so we correlate them based on source order |
| 3538 | 3541 | // in their respective arrays. |
| 3539 | 3542 | |
| 3540 | const num_explicit_types = @min(old_contents.explicit_types.items.len, new_contents.explicit_types.items.len); | |
| 3541 | try match_stack.ensureUnusedCapacity(gpa, @intCast(num_explicit_types)); | |
| 3543 | const num_type_decls = @min(old_contents.type_decls.items.len, new_contents.type_decls.items.len); | |
| 3544 | try pending_matched_type_decls.ensureUnusedCapacity(gpa, @intCast(num_type_decls)); | |
| 3542 | 3545 | for ( |
| 3543 | old_contents.explicit_types.items[0..num_explicit_types], | |
| 3544 | new_contents.explicit_types.items[0..num_explicit_types], | |
| 3546 | old_contents.type_decls.items[0..num_type_decls], | |
| 3547 | new_contents.type_decls.items[0..num_type_decls], | |
| 3545 | 3548 | ) |old_inst, new_inst| { |
| 3546 | // Here we use `match_stack`, so that we will recursively consider declarations on these types. | |
| 3547 | match_stack.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst }); | |
| 3549 | pending_matched_type_decls.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst }); | |
| 3548 | 3550 | } |
| 3549 | 3551 | |
| 3550 | 3552 | const num_other = @min(old_contents.other.items.len, new_contents.other.items.len); |
src/Zcu/PerThread.zig+7-15| ... | ... | @@ -1073,8 +1073,6 @@ pub fn ensureMemoizedStateUpToDate( |
| 1073 | 1073 | |
| 1074 | 1074 | const unit: AnalUnit = .wrap(.{ .memoized_state = stage }); |
| 1075 | 1075 | |
| 1076 | log.debug("ensureMemoizedStateUpToDate", .{}); | |
| 1077 | ||
| 1078 | 1076 | assert(!zcu.analysis_in_progress.contains(unit)); |
| 1079 | 1077 | |
| 1080 | 1078 | const was_outdated = zcu.clearOutdatedState(unit); |
| ... | ... | @@ -1142,6 +1140,8 @@ fn analyzeMemoizedState( |
| 1142 | 1140 | const comp = zcu.comp; |
| 1143 | 1141 | const gpa = comp.gpa; |
| 1144 | 1142 | |
| 1143 | log.debug("analyzeMemoizedState({t})", .{stage}); | |
| 1144 | ||
| 1145 | 1145 | const unit: AnalUnit = .wrap(.{ .memoized_state = stage }); |
| 1146 | 1146 | |
| 1147 | 1147 | try zcu.analysis_in_progress.putNoClobber(gpa, unit, reason); |
| ... | ... | @@ -1182,8 +1182,6 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU |
| 1182 | 1182 | |
| 1183 | 1183 | const anal_unit: AnalUnit = .wrap(.{ .@"comptime" = cu_id }); |
| 1184 | 1184 | |
| 1185 | log.debug("ensureComptimeUnitUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1186 | ||
| 1187 | 1185 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 1188 | 1186 | |
| 1189 | 1187 | // Determine whether or not this `ComptimeUnit` is outdated. For this kind of `AnalUnit`, that's |
| ... | ... | @@ -1345,8 +1343,6 @@ pub fn ensureTypeLayoutUpToDate( |
| 1345 | 1343 | |
| 1346 | 1344 | const anal_unit: AnalUnit = .wrap(.{ .type_layout = ty.toIntern() }); |
| 1347 | 1345 | |
| 1348 | log.debug("ensureTypeLayoutUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1349 | ||
| 1350 | 1346 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 1351 | 1347 | |
| 1352 | 1348 | const was_outdated: bool = outdated: { |
| ... | ... | @@ -1413,6 +1409,8 @@ pub fn ensureTypeLayoutUpToDate( |
| 1413 | 1409 | }; |
| 1414 | 1410 | defer sema.deinit(); |
| 1415 | 1411 | |
| 1412 | log.debug("ensureTypeLayoutUpToDate {f} (out of date, resolving)", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1413 | ||
| 1416 | 1414 | const result = switch (ty.zigTypeTag(zcu)) { |
| 1417 | 1415 | .@"enum" => Sema.type_resolution.resolveEnumLayout(&sema, ty), |
| 1418 | 1416 | .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty), |
| ... | ... | @@ -1478,8 +1476,6 @@ pub fn ensureStructDefaultsUpToDate( |
| 1478 | 1476 | |
| 1479 | 1477 | const anal_unit: AnalUnit = .wrap(.{ .struct_defaults = ty.toIntern() }); |
| 1480 | 1478 | |
| 1481 | log.debug("ensureStructDefaultsUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1482 | ||
| 1483 | 1479 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 1484 | 1480 | |
| 1485 | 1481 | const was_outdated: bool = outdated: { |
| ... | ... | @@ -1536,6 +1532,8 @@ pub fn ensureStructDefaultsUpToDate( |
| 1536 | 1532 | }; |
| 1537 | 1533 | defer sema.deinit(); |
| 1538 | 1534 | |
| 1535 | log.debug("ensureStructDefaultsUpToDate {f} (out of date, resolving)", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1536 | ||
| 1539 | 1537 | const new_failed: bool = if (Sema.type_resolution.resolveStructDefaults(&sema, ty)) failed: { |
| 1540 | 1538 | break :failed false; |
| 1541 | 1539 | } else |err| switch (err) { |
| ... | ... | @@ -1584,8 +1582,6 @@ pub fn ensureNavValUpToDate( |
| 1584 | 1582 | const anal_unit: AnalUnit = .wrap(.{ .nav_val = nav_id }); |
| 1585 | 1583 | const nav = ip.getNav(nav_id); |
| 1586 | 1584 | |
| 1587 | log.debug("ensureNavValUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1588 | ||
| 1589 | 1585 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 1590 | 1586 | |
| 1591 | 1587 | try zcu.ensureNavValAnalysisQueued(nav_id); |
| ... | ... | @@ -1946,8 +1942,6 @@ pub fn ensureNavTypeUpToDate( |
| 1946 | 1942 | const anal_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id }); |
| 1947 | 1943 | const nav = ip.getNav(nav_id); |
| 1948 | 1944 | |
| 1949 | log.debug("ensureNavTypeUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 1950 | ||
| 1951 | 1945 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 1952 | 1946 | |
| 1953 | 1947 | try zcu.ensureNavValAnalysisQueued(nav_id); |
| ... | ... | @@ -2191,8 +2185,6 @@ pub fn ensureFuncBodyUpToDate( |
| 2191 | 2185 | |
| 2192 | 2186 | const anal_unit: AnalUnit = .wrap(.{ .func = func_index }); |
| 2193 | 2187 | |
| 2194 | log.debug("ensureFuncBodyUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 2195 | ||
| 2196 | 2188 | assert(!zcu.analysis_in_progress.contains(anal_unit)); |
| 2197 | 2189 | |
| 2198 | 2190 | const func = zcu.funcInfo(func_index); |
| ... | ... | @@ -2282,7 +2274,7 @@ fn analyzeFuncBody( |
| 2282 | 2274 | else |
| 2283 | 2275 | .none; |
| 2284 | 2276 | |
| 2285 | log.debug("analyze and generate fn body {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 2277 | log.debug("analyzeFuncBody {f}", .{zcu.fmtAnalUnit(anal_unit)}); | |
| 2286 | 2278 | |
| 2287 | 2279 | var air = try pt.analyzeFuncBodyInner(func_index, reason); |
| 2288 | 2280 | var air_owned = true; |
test/incremental/add_field_and_nested_struct_uses_changed_decl created+25| ... | ... | @@ -0,0 +1,25 @@ |
| 1 | #update=initial version | |
| 2 | #file=main.zig | |
| 3 | pub fn main() void { | |
| 4 | _ = @as(S, undefined); | |
| 5 | } | |
| 6 | // To reproduce the original bug, the inner struct must perform a namespace lookup | |
| 7 | // or a scope lookup when resolving its field type. | |
| 8 | const SomeType = u8; | |
| 9 | const S = struct { | |
| 10 | foo: struct { inner: SomeType }, | |
| 11 | }; | |
| 12 | #expect_stdout="" | |
| 13 | #update=add field to outer struct, change decl used by inner struct | |
| 14 | #file=main.zig | |
| 15 | pub fn main() void { | |
| 16 | _ = @as(S, undefined); | |
| 17 | } | |
| 18 | // To reproduce the original bug, the inner struct must perform a namespace lookup | |
| 19 | // or a scope lookup when resolving its field type. | |
| 20 | const SomeType = u16; | |
| 21 | const S = struct { | |
| 22 | foo: struct { inner: SomeType }, | |
| 23 | bar: u32, | |
| 24 | }; | |
| 25 | #expect_stdout="" |
test/incremental/do_nothing created+41| ... | ... | @@ -0,0 +1,41 @@ |
| 1 | // TODO: it'd be great if we could actually check that no analysis happened! | |
| 2 | #update=initial version | |
| 3 | #file=main.zig | |
| 4 | pub fn main() void { | |
| 5 | const ptr: *const O = @ptrFromInt(0x1000); | |
| 6 | _ = ptr; | |
| 7 | } | |
| 8 | const S = struct { foo: u32, nested: struct { x: u16 } }; | |
| 9 | const U = union(enum) { a, b, c: S }; | |
| 10 | const E = enum(u8) { a = @typeInfo(U).@"union".fields.len, b = 0, c }; | |
| 11 | const O = opaque { | |
| 12 | comptime { | |
| 13 | _ = @as(S, undefined); | |
| 14 | _ = @as(U, undefined); | |
| 15 | _ = @as(E, undefined); | |
| 16 | const Wrapper = struct { val: S }; | |
| 17 | const wrapper: Wrapper = .{ .val = .{ .foo = 123, .nested = .{ .x = 456 } } }; | |
| 18 | _ = wrapper; | |
| 19 | } | |
| 20 | }; | |
| 21 | #expect_stdout="" | |
| 22 | #update=do literally nothing | |
| 23 | #file=main.zig | |
| 24 | pub fn main() void { | |
| 25 | const ptr: *const O = @ptrFromInt(0x1000); | |
| 26 | _ = ptr; | |
| 27 | } | |
| 28 | const S = struct { foo: u32, nested: struct { x: u16 } }; | |
| 29 | const U = union(enum) { a, b, c: S }; | |
| 30 | const E = enum(u8) { a = @typeInfo(U).@"union".fields.len, b = 0, c }; | |
| 31 | const O = opaque { | |
| 32 | comptime { | |
| 33 | _ = @as(S, undefined); | |
| 34 | _ = @as(U, undefined); | |
| 35 | _ = @as(E, undefined); | |
| 36 | const Wrapper = struct { val: S }; | |
| 37 | const wrapper: Wrapper = .{ .val = .{ .foo = 123, .nested = .{ .x = 456 } } }; | |
| 38 | _ = wrapper; | |
| 39 | } | |
| 40 | }; | |
| 41 | #expect_stdout="" |