| author | |
| committer | |
| log | 2c4ac44f25743f5b7ae9db6bc570ab71f15fd83b |
| tree | 5936a2c47c13ea1fcd5bd37ce523754517be38cf |
| parent | d0c022f7347b5cda34751a986a535aee3b1f45dc |
| signature |
This fixes an issue with the implementation of #18816. Consider the
following code:
```zig
pub fn Wrap(comptime T: type) type {
return struct {
pub const T1 = T;
inner: struct { x: T1 },
};
}
```
Previously, the type of `inner` was not considered to be "capturing" any
value, as `T1` is a decl. However, since it is declared within a generic
function, this decl reference depends on the context, and thus should be
treated as a capture.
AstGen has been augmented to tunnel references to decls through closure
when the decl was declared in a potentially-generic context (i.e. within
a function).6 files changed, 194 insertions(+), 65 deletions(-)
lib/std/zig/AstGen.zig+90-26| ... | @@ -44,6 +44,9 @@ compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, | ... | @@ -44,6 +44,9 @@ compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{}, |
| 44 | /// The topmost block of the current function. | 44 | /// The topmost block of the current function. |
| 45 | fn_block: ?*GenZir = null, | 45 | fn_block: ?*GenZir = null, |
| 46 | fn_var_args: bool = false, | 46 | fn_var_args: bool = false, |
| 47 | /// Whether we are somewhere within a function. If `true`, any container decls may be | ||
| 48 | /// generic and thus must be tunneled through closure. | ||
| 49 | within_fn: bool = false, | ||
| 47 | /// The return type of the current function. This may be a trivial `Ref`, or | 50 | /// The return type of the current function. This may be a trivial `Ref`, or |
| 48 | /// otherwise it refers to a `ret_type` instruction. | 51 | /// otherwise it refers to a `ret_type` instruction. |
| 49 | fn_ret_ty: Zir.Inst.Ref = .none, | 52 | fn_ret_ty: Zir.Inst.Ref = .none, |
| ... | @@ -4050,6 +4053,11 @@ fn fnDecl( | ... | @@ -4050,6 +4053,11 @@ fn fnDecl( |
| 4050 | }; | 4053 | }; |
| 4051 | defer fn_gz.unstack(); | 4054 | defer fn_gz.unstack(); |
| 4052 | 4055 | ||
| 4056 | // Set this now, since parameter types, return type, etc may be generic. | ||
| 4057 | const prev_within_fn = astgen.within_fn; | ||
| 4058 | defer astgen.within_fn = prev_within_fn; | ||
| 4059 | astgen.within_fn = true; | ||
| 4060 | |||
| 4053 | const is_pub = fn_proto.visib_token != null; | 4061 | const is_pub = fn_proto.visib_token != null; |
| 4054 | const is_export = blk: { | 4062 | const is_export = blk: { |
| 4055 | const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false; | 4063 | const maybe_export_token = fn_proto.extern_export_inline_token orelse break :blk false; |
| ... | @@ -4311,6 +4319,10 @@ fn fnDecl( | ... | @@ -4311,6 +4319,10 @@ fn fnDecl( |
| 4311 | 4319 | ||
| 4312 | const prev_fn_block = astgen.fn_block; | 4320 | const prev_fn_block = astgen.fn_block; |
| 4313 | const prev_fn_ret_ty = astgen.fn_ret_ty; | 4321 | const prev_fn_ret_ty = astgen.fn_ret_ty; |
| 4322 | defer { | ||
| 4323 | astgen.fn_block = prev_fn_block; | ||
| 4324 | astgen.fn_ret_ty = prev_fn_ret_ty; | ||
| 4325 | } | ||
| 4314 | astgen.fn_block = &fn_gz; | 4326 | astgen.fn_block = &fn_gz; |
| 4315 | astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: { | 4327 | astgen.fn_ret_ty = if (is_inferred_error or ret_ref.toIndex() != null) r: { |
| 4316 | // We're essentially guaranteed to need the return type at some point, | 4328 | // We're essentially guaranteed to need the return type at some point, |
| ... | @@ -4319,10 +4331,6 @@ fn fnDecl( | ... | @@ -4319,10 +4331,6 @@ fn fnDecl( |
| 4319 | // return type now so the rest of the function can use it. | 4331 | // return type now so the rest of the function can use it. |
| 4320 | break :r try fn_gz.addNode(.ret_type, decl_node); | 4332 | break :r try fn_gz.addNode(.ret_type, decl_node); |
| 4321 | } else ret_ref; | 4333 | } else ret_ref; |
| 4322 | defer { | ||
| 4323 | astgen.fn_block = prev_fn_block; | ||
| 4324 | astgen.fn_ret_ty = prev_fn_ret_ty; | ||
| 4325 | } | ||
| 4326 | 4334 | ||
| 4327 | const prev_var_args = astgen.fn_var_args; | 4335 | const prev_var_args = astgen.fn_var_args; |
| 4328 | astgen.fn_var_args = is_var_args; | 4336 | astgen.fn_var_args = is_var_args; |
| ... | @@ -4768,11 +4776,14 @@ fn testDecl( | ... | @@ -4768,11 +4776,14 @@ fn testDecl( |
| 4768 | }; | 4776 | }; |
| 4769 | defer fn_block.unstack(); | 4777 | defer fn_block.unstack(); |
| 4770 | 4778 | ||
| 4779 | const prev_within_fn = astgen.within_fn; | ||
| 4771 | const prev_fn_block = astgen.fn_block; | 4780 | const prev_fn_block = astgen.fn_block; |
| 4772 | const prev_fn_ret_ty = astgen.fn_ret_ty; | 4781 | const prev_fn_ret_ty = astgen.fn_ret_ty; |
| 4782 | astgen.within_fn = true; | ||
| 4773 | astgen.fn_block = &fn_block; | 4783 | astgen.fn_block = &fn_block; |
| 4774 | astgen.fn_ret_ty = .anyerror_void_error_union_type; | 4784 | astgen.fn_ret_ty = .anyerror_void_error_union_type; |
| 4775 | defer { | 4785 | defer { |
| 4786 | astgen.within_fn = prev_within_fn; | ||
| 4776 | astgen.fn_block = prev_fn_block; | 4787 | astgen.fn_block = prev_fn_block; |
| 4777 | astgen.fn_ret_ty = prev_fn_ret_ty; | 4788 | astgen.fn_ret_ty = prev_fn_ret_ty; |
| 4778 | } | 4789 | } |
| ... | @@ -4871,6 +4882,7 @@ fn structDeclInner( | ... | @@ -4871,6 +4882,7 @@ fn structDeclInner( |
| 4871 | .node = node, | 4882 | .node = node, |
| 4872 | .inst = decl_inst, | 4883 | .inst = decl_inst, |
| 4873 | .declaring_gz = gz, | 4884 | .declaring_gz = gz, |
| 4885 | .maybe_generic = astgen.within_fn, | ||
| 4874 | }; | 4886 | }; |
| 4875 | defer namespace.deinit(gpa); | 4887 | defer namespace.deinit(gpa); |
| 4876 | 4888 | ||
| ... | @@ -5195,6 +5207,7 @@ fn unionDeclInner( | ... | @@ -5195,6 +5207,7 @@ fn unionDeclInner( |
| 5195 | .node = node, | 5207 | .node = node, |
| 5196 | .inst = decl_inst, | 5208 | .inst = decl_inst, |
| 5197 | .declaring_gz = gz, | 5209 | .declaring_gz = gz, |
| 5210 | .maybe_generic = astgen.within_fn, | ||
| 5198 | }; | 5211 | }; |
| 5199 | defer namespace.deinit(gpa); | 5212 | defer namespace.deinit(gpa); |
| 5200 | 5213 | ||
| ... | @@ -5543,6 +5556,7 @@ fn containerDecl( | ... | @@ -5543,6 +5556,7 @@ fn containerDecl( |
| 5543 | .node = node, | 5556 | .node = node, |
| 5544 | .inst = decl_inst, | 5557 | .inst = decl_inst, |
| 5545 | .declaring_gz = gz, | 5558 | .declaring_gz = gz, |
| 5559 | .maybe_generic = astgen.within_fn, | ||
| 5546 | }; | 5560 | }; |
| 5547 | defer namespace.deinit(gpa); | 5561 | defer namespace.deinit(gpa); |
| 5548 | 5562 | ||
| ... | @@ -5709,6 +5723,7 @@ fn containerDecl( | ... | @@ -5709,6 +5723,7 @@ fn containerDecl( |
| 5709 | .node = node, | 5723 | .node = node, |
| 5710 | .inst = decl_inst, | 5724 | .inst = decl_inst, |
| 5711 | .declaring_gz = gz, | 5725 | .declaring_gz = gz, |
| 5726 | .maybe_generic = astgen.within_fn, | ||
| 5712 | }; | 5727 | }; |
| 5713 | defer namespace.deinit(gpa); | 5728 | defer namespace.deinit(gpa); |
| 5714 | 5729 | ||
| ... | @@ -8247,9 +8262,14 @@ fn localVarRef( | ... | @@ -8247,9 +8262,14 @@ fn localVarRef( |
| 8247 | const name_str_index = try astgen.identAsString(ident_token); | 8262 | const name_str_index = try astgen.identAsString(ident_token); |
| 8248 | var s = scope; | 8263 | var s = scope; |
| 8249 | var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already | 8264 | var found_already: ?Ast.Node.Index = null; // we have found a decl with the same name already |
| 8265 | var found_needs_tunnel: bool = undefined; // defined when `found_already != null` | ||
| 8266 | var found_namespaces_out: u32 = undefined; // defined when `found_already != null` | ||
| 8267 | |||
| 8268 | // The number of namespaces above `gz` we currently are | ||
| 8250 | var num_namespaces_out: u32 = 0; | 8269 | var num_namespaces_out: u32 = 0; |
| 8251 | // defined when `num_namespaces_out != 0` | 8270 | // defined by `num_namespaces_out != 0` |
| 8252 | var capturing_namespace: *Scope.Namespace = undefined; | 8271 | var capturing_namespace: *Scope.Namespace = undefined; |
| 8272 | |||
| 8253 | while (true) switch (s.tag) { | 8273 | while (true) switch (s.tag) { |
| 8254 | .local_val => { | 8274 | .local_val => { |
| 8255 | const local_val = s.cast(Scope.LocalVal).?; | 8275 | const local_val = s.cast(Scope.LocalVal).?; |
| ... | @@ -8267,9 +8287,8 @@ fn localVarRef( | ... | @@ -8267,9 +8287,8 @@ fn localVarRef( |
| 8267 | gz, | 8287 | gz, |
| 8268 | ident, | 8288 | ident, |
| 8269 | num_namespaces_out, | 8289 | num_namespaces_out, |
| 8270 | capturing_namespace, | 8290 | .{ .ref = local_val.inst }, |
| 8271 | local_val.inst, | 8291 | .{ .token = local_val.token_src }, |
| 8272 | local_val.token_src, | ||
| 8273 | ) else local_val.inst; | 8292 | ) else local_val.inst; |
| 8274 | 8293 | ||
| 8275 | return rvalueNoCoercePreRef(gz, ri, value_inst, ident); | 8294 | return rvalueNoCoercePreRef(gz, ri, value_inst, ident); |
| ... | @@ -8298,9 +8317,8 @@ fn localVarRef( | ... | @@ -8298,9 +8317,8 @@ fn localVarRef( |
| 8298 | gz, | 8317 | gz, |
| 8299 | ident, | 8318 | ident, |
| 8300 | num_namespaces_out, | 8319 | num_namespaces_out, |
| 8301 | capturing_namespace, | 8320 | .{ .ref = local_ptr.ptr }, |
| 8302 | local_ptr.ptr, | 8321 | .{ .token = local_ptr.token_src }, |
| 8303 | local_ptr.token_src, | ||
| 8304 | ) else local_ptr.ptr; | 8322 | ) else local_ptr.ptr; |
| 8305 | 8323 | ||
| 8306 | switch (ri.rl) { | 8324 | switch (ri.rl) { |
| ... | @@ -8329,6 +8347,8 @@ fn localVarRef( | ... | @@ -8329,6 +8347,8 @@ fn localVarRef( |
| 8329 | } | 8347 | } |
| 8330 | // We found a match but must continue looking for ambiguous references to decls. | 8348 | // We found a match but must continue looking for ambiguous references to decls. |
| 8331 | found_already = i; | 8349 | found_already = i; |
| 8350 | found_needs_tunnel = ns.maybe_generic; | ||
| 8351 | found_namespaces_out = num_namespaces_out; | ||
| 8332 | } | 8352 | } |
| 8333 | num_namespaces_out += 1; | 8353 | num_namespaces_out += 1; |
| 8334 | capturing_namespace = ns; | 8354 | capturing_namespace = ns; |
| ... | @@ -8343,6 +8363,29 @@ fn localVarRef( | ... | @@ -8343,6 +8363,29 @@ fn localVarRef( |
| 8343 | 8363 | ||
| 8344 | // Decl references happen by name rather than ZIR index so that when unrelated | 8364 | // Decl references happen by name rather than ZIR index so that when unrelated |
| 8345 | // decls are modified, ZIR code containing references to them can be unmodified. | 8365 | // decls are modified, ZIR code containing references to them can be unmodified. |
| 8366 | |||
| 8367 | if (found_namespaces_out > 0 and found_needs_tunnel) { | ||
| 8368 | switch (ri.rl) { | ||
| 8369 | .ref, .ref_coerced_ty => return tunnelThroughClosure( | ||
| 8370 | gz, | ||
| 8371 | ident, | ||
| 8372 | found_namespaces_out, | ||
| 8373 | .{ .decl_ref = name_str_index }, | ||
| 8374 | .{ .node = found_already.? }, | ||
| 8375 | ), | ||
| 8376 | else => { | ||
| 8377 | const result = try tunnelThroughClosure( | ||
| 8378 | gz, | ||
| 8379 | ident, | ||
| 8380 | found_namespaces_out, | ||
| 8381 | .{ .decl_val = name_str_index }, | ||
| 8382 | .{ .node = found_already.? }, | ||
| 8383 | ); | ||
| 8384 | return rvalueNoCoercePreRef(gz, ri, result, ident); | ||
| 8385 | }, | ||
| 8386 | } | ||
| 8387 | } | ||
| 8388 | |||
| 8346 | switch (ri.rl) { | 8389 | switch (ri.rl) { |
| 8347 | .ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token), | 8390 | .ref, .ref_coerced_ty => return gz.addStrTok(.decl_ref, name_str_index, ident_token), |
| 8348 | else => { | 8391 | else => { |
| ... | @@ -8361,17 +8404,22 @@ fn tunnelThroughClosure( | ... | @@ -8361,17 +8404,22 @@ fn tunnelThroughClosure( |
| 8361 | inner_ref_node: Ast.Node.Index, | 8404 | inner_ref_node: Ast.Node.Index, |
| 8362 | /// The number of namespaces being tunnelled through. At least 1. | 8405 | /// The number of namespaces being tunnelled through. At least 1. |
| 8363 | num_tunnels: u32, | 8406 | num_tunnels: u32, |
| 8364 | /// The namespace being captured from. | ||
| 8365 | ns: *Scope.Namespace, | ||
| 8366 | /// The value being captured. | 8407 | /// The value being captured. |
| 8367 | value: Zir.Inst.Ref, | 8408 | value: union(enum) { |
| 8368 | /// The token of the value's declaration. | 8409 | ref: Zir.Inst.Ref, |
| 8369 | token: Ast.TokenIndex, | 8410 | decl_val: Zir.NullTerminatedString, |
| 8411 | decl_ref: Zir.NullTerminatedString, | ||
| 8412 | }, | ||
| 8413 | /// The location of the value's declaration. | ||
| 8414 | decl_src: union(enum) { | ||
| 8415 | token: Ast.TokenIndex, | ||
| 8416 | node: Ast.Node.Index, | ||
| 8417 | }, | ||
| 8370 | ) !Zir.Inst.Ref { | 8418 | ) !Zir.Inst.Ref { |
| 8371 | const value_inst = value.toIndex() orelse { | 8419 | switch (value) { |
| 8372 | // For trivial values, we don't need a tunnel; just return the ref. | 8420 | .ref => |v| if (v.toIndex() == null) return v, // trivia value; do not need tunnel |
| 8373 | return value; | 8421 | .decl_val, .decl_ref => {}, |
| 8374 | }; | 8422 | } |
| 8375 | 8423 | ||
| 8376 | const astgen = gz.astgen; | 8424 | const astgen = gz.astgen; |
| 8377 | const gpa = astgen.gpa; | 8425 | const gpa = astgen.gpa; |
| ... | @@ -8382,7 +8430,7 @@ fn tunnelThroughClosure( | ... | @@ -8382,7 +8430,7 @@ fn tunnelThroughClosure( |
| 8382 | var sfba = std.heap.stackFallback(@sizeOf(usize) * 2, astgen.arena); | 8430 | var sfba = std.heap.stackFallback(@sizeOf(usize) * 2, astgen.arena); |
| 8383 | var intermediate_tunnels = try sfba.get().alloc(*Scope.Namespace, num_tunnels - 1); | 8431 | var intermediate_tunnels = try sfba.get().alloc(*Scope.Namespace, num_tunnels - 1); |
| 8384 | 8432 | ||
| 8385 | { | 8433 | const root_ns = ns: { |
| 8386 | var i: usize = num_tunnels - 1; | 8434 | var i: usize = num_tunnels - 1; |
| 8387 | var scope: *Scope = gz.parent; | 8435 | var scope: *Scope = gz.parent; |
| 8388 | while (i > 0) { | 8436 | while (i > 0) { |
| ... | @@ -8392,15 +8440,27 @@ fn tunnelThroughClosure( | ... | @@ -8392,15 +8440,27 @@ fn tunnelThroughClosure( |
| 8392 | } | 8440 | } |
| 8393 | scope = scope.parent().?; | 8441 | scope = scope.parent().?; |
| 8394 | } | 8442 | } |
| 8395 | } | 8443 | while (true) { |
| 8444 | if (scope.cast(Scope.Namespace)) |ns| break :ns ns; | ||
| 8445 | scope = scope.parent().?; | ||
| 8446 | } | ||
| 8447 | }; | ||
| 8396 | 8448 | ||
| 8397 | // Now that we know the scopes we're tunneling through, begin adding | 8449 | // Now that we know the scopes we're tunneling through, begin adding |
| 8398 | // captures as required, starting with the outermost namespace. | 8450 | // captures as required, starting with the outermost namespace. |
| 8451 | const root_capture = Zir.Inst.Capture.wrap(switch (value) { | ||
| 8452 | .ref => |v| .{ .instruction = v.toIndex().? }, | ||
| 8453 | .decl_val => |str| .{ .decl_val = str }, | ||
| 8454 | .decl_ref => |str| .{ .decl_ref = str }, | ||
| 8455 | }); | ||
| 8399 | var cur_capture_index = std.math.cast( | 8456 | var cur_capture_index = std.math.cast( |
| 8400 | u16, | 8457 | u16, |
| 8401 | (try ns.captures.getOrPut(gpa, Zir.Inst.Capture.wrap(.{ .inst = value_inst }))).index, | 8458 | (try root_ns.captures.getOrPut(gpa, root_capture)).index, |
| 8402 | ) orelse return astgen.failNodeNotes(ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{ | 8459 | ) orelse return astgen.failNodeNotes(root_ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{ |
| 8403 | try astgen.errNoteTok(token, "captured value here", .{}), | 8460 | switch (decl_src) { |
| 8461 | .token => |t| try astgen.errNoteTok(t, "captured value here", .{}), | ||
| 8462 | .node => |n| try astgen.errNoteNode(n, "captured value here", .{}), | ||
| 8463 | }, | ||
| 8404 | try astgen.errNoteNode(inner_ref_node, "value used here", .{}), | 8464 | try astgen.errNoteNode(inner_ref_node, "value used here", .{}), |
| 8405 | }); | 8465 | }); |
| 8406 | 8466 | ||
| ... | @@ -8409,7 +8469,10 @@ fn tunnelThroughClosure( | ... | @@ -8409,7 +8469,10 @@ fn tunnelThroughClosure( |
| 8409 | u16, | 8469 | u16, |
| 8410 | (try tunnel_ns.captures.getOrPut(gpa, Zir.Inst.Capture.wrap(.{ .nested = cur_capture_index }))).index, | 8470 | (try tunnel_ns.captures.getOrPut(gpa, Zir.Inst.Capture.wrap(.{ .nested = cur_capture_index }))).index, |
| 8411 | ) orelse return astgen.failNodeNotes(tunnel_ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{ | 8471 | ) orelse return astgen.failNodeNotes(tunnel_ns.node, "this compiler implementation only supports up to 65536 captures per namespace", .{}, &.{ |
| 8412 | try astgen.errNoteTok(token, "captured value here", .{}), | 8472 | switch (decl_src) { |
| 8473 | .token => |t| try astgen.errNoteTok(t, "captured value here", .{}), | ||
| 8474 | .node => |n| try astgen.errNoteNode(n, "captured value here", .{}), | ||
| 8475 | }, | ||
| 8413 | try astgen.errNoteNode(inner_ref_node, "value used here", .{}), | 8476 | try astgen.errNoteNode(inner_ref_node, "value used here", .{}), |
| 8414 | }); | 8477 | }); |
| 8415 | } | 8478 | } |
| ... | @@ -11752,6 +11815,7 @@ const Scope = struct { | ... | @@ -11752,6 +11815,7 @@ const Scope = struct { |
| 11752 | decls: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{}, | 11815 | decls: std.AutoHashMapUnmanaged(Zir.NullTerminatedString, Ast.Node.Index) = .{}, |
| 11753 | node: Ast.Node.Index, | 11816 | node: Ast.Node.Index, |
| 11754 | inst: Zir.Inst.Index, | 11817 | inst: Zir.Inst.Index, |
| 11818 | maybe_generic: bool, | ||
| 11755 | 11819 | ||
| 11756 | /// The astgen scope containing this namespace. | 11820 | /// The astgen scope containing this namespace. |
| 11757 | /// Only valid during astgen. | 11821 | /// Only valid during astgen. |
lib/std/zig/Zir.zig+36-12| ... | @@ -3057,26 +3057,50 @@ pub const Inst = struct { | ... | @@ -3057,26 +3057,50 @@ pub const Inst = struct { |
| 3057 | }; | 3057 | }; |
| 3058 | 3058 | ||
| 3059 | /// Represents a single value being captured in a type declaration's closure. | 3059 | /// Represents a single value being captured in a type declaration's closure. |
| 3060 | /// If high bit is 0, this represents a `Zir.Inst,Index`. | 3060 | pub const Capture = packed struct(u32) { |
| 3061 | /// If high bit is 1, this represents an index into the last closure. | 3061 | tag: enum(u2) { |
| 3062 | pub const Capture = enum(u32) { | 3062 | /// `data` is a `u16` index into the parent closure. |
| 3063 | _, | 3063 | nested, |
| 3064 | /// `data` is a `Zir.Inst.Index` to an instruction whose value is being captured. | ||
| 3065 | instruction, | ||
| 3066 | /// `data` is a `NullTerminatedString` to a decl name. | ||
| 3067 | decl_val, | ||
| 3068 | /// `data` is a `NullTerminatedString` to a decl name. | ||
| 3069 | decl_ref, | ||
| 3070 | }, | ||
| 3071 | data: u30, | ||
| 3064 | pub const Unwrapped = union(enum) { | 3072 | pub const Unwrapped = union(enum) { |
| 3065 | inst: Zir.Inst.Index, | ||
| 3066 | nested: u16, | 3073 | nested: u16, |
| 3074 | instruction: Zir.Inst.Index, | ||
| 3075 | decl_val: NullTerminatedString, | ||
| 3076 | decl_ref: NullTerminatedString, | ||
| 3067 | }; | 3077 | }; |
| 3068 | pub fn wrap(cap: Unwrapped) Capture { | 3078 | pub fn wrap(cap: Unwrapped) Capture { |
| 3069 | return switch (cap) { | 3079 | return switch (cap) { |
| 3070 | .inst => |inst| @enumFromInt(@intFromEnum(inst)), | 3080 | .nested => |idx| .{ |
| 3071 | .nested => |idx| @enumFromInt((1 << 31) | @as(u32, idx)), | 3081 | .tag = .nested, |
| 3082 | .data = idx, | ||
| 3083 | }, | ||
| 3084 | .instruction => |inst| .{ | ||
| 3085 | .tag = .instruction, | ||
| 3086 | .data = @intCast(@intFromEnum(inst)), | ||
| 3087 | }, | ||
| 3088 | .decl_val => |str| .{ | ||
| 3089 | .tag = .decl_val, | ||
| 3090 | .data = @intCast(@intFromEnum(str)), | ||
| 3091 | }, | ||
| 3092 | .decl_ref => |str| .{ | ||
| 3093 | .tag = .decl_ref, | ||
| 3094 | .data = @intCast(@intFromEnum(str)), | ||
| 3095 | }, | ||
| 3072 | }; | 3096 | }; |
| 3073 | } | 3097 | } |
| 3074 | pub fn unwrap(cap: Capture) Unwrapped { | 3098 | pub fn unwrap(cap: Capture) Unwrapped { |
| 3075 | const raw = @intFromEnum(cap); | 3099 | return switch (cap.tag) { |
| 3076 | const tag: u1 = @intCast(raw >> 31); | 3100 | .nested => .{ .nested = @intCast(cap.data) }, |
| 3077 | return switch (tag) { | 3101 | .instruction => .{ .instruction = @enumFromInt(cap.data) }, |
| 3078 | 0 => .{ .inst = @enumFromInt(raw) }, | 3102 | .decl_val => .{ .decl_val = @enumFromInt(cap.data) }, |
| 3079 | 1 => .{ .nested = @truncate(raw) }, | 3103 | .decl_ref => .{ .decl_ref = @enumFromInt(cap.data) }, |
| 3080 | }; | 3104 | }; |
| 3081 | } | 3105 | } |
| 3082 | }; | 3106 | }; |
src/Autodoc.zig+19-3| ... | @@ -459,11 +459,21 @@ const Scope = struct { | ... | @@ -459,11 +459,21 @@ const Scope = struct { |
| 459 | NotRequested: u32, // instr_index | 459 | NotRequested: u32, // instr_index |
| 460 | }; | 460 | }; |
| 461 | 461 | ||
| 462 | fn getCapture(scope: Scope, idx: u16) struct { Zir.Inst.Index, *Scope } { | 462 | fn getCapture(scope: Scope, idx: u16) struct { |
| 463 | union(enum) { inst: Zir.Inst.Index, decl: Zir.NullTerminatedString }, | ||
| 464 | *Scope, | ||
| 465 | } { | ||
| 463 | const parent = scope.parent.?; | 466 | const parent = scope.parent.?; |
| 464 | return switch (scope.captures[idx].unwrap()) { | 467 | return switch (scope.captures[idx].unwrap()) { |
| 465 | .inst => |inst| .{ inst, parent }, | ||
| 466 | .nested => |parent_idx| parent.getCapture(parent_idx), | 468 | .nested => |parent_idx| parent.getCapture(parent_idx), |
| 469 | .instruction => |inst| .{ | ||
| 470 | .{ .inst = inst }, | ||
| 471 | parent, | ||
| 472 | }, | ||
| 473 | .decl_val, .decl_ref => |str| .{ | ||
| 474 | .{ .decl = str }, | ||
| 475 | parent, | ||
| 476 | }, | ||
| 467 | }; | 477 | }; |
| 468 | } | 478 | } |
| 469 | 479 | ||
| ... | @@ -4048,7 +4058,13 @@ fn walkInstruction( | ... | @@ -4048,7 +4058,13 @@ fn walkInstruction( |
| 4048 | }, | 4058 | }, |
| 4049 | .closure_get => { | 4059 | .closure_get => { |
| 4050 | const captured, const scope = parent_scope.getCapture(extended.small); | 4060 | const captured, const scope = parent_scope.getCapture(extended.small); |
| 4051 | return self.walkInstruction(file, scope, parent_src, captured, need_type, call_ctx); | 4061 | switch (captured) { |
| 4062 | .inst => |cap_inst| return self.walkInstruction(file, scope, parent_src, cap_inst, need_type, call_ctx), | ||
| 4063 | .decl => |str| { | ||
| 4064 | const decl_status = parent_scope.resolveDeclName(str, file, inst.toOptional()); | ||
| 4065 | return .{ .expr = .{ .declRef = decl_status } }; | ||
| 4066 | }, | ||
| 4067 | } | ||
| 4052 | }, | 4068 | }, |
| 4053 | } | 4069 | } |
| 4054 | }, | 4070 | }, |
src/InternPool.zig+13-4| ... | @@ -503,22 +503,29 @@ pub const OptionalNullTerminatedString = enum(u32) { | ... | @@ -503,22 +503,29 @@ pub const OptionalNullTerminatedString = enum(u32) { |
| 503 | }; | 503 | }; |
| 504 | 504 | ||
| 505 | /// A single value captured in the closure of a namespace type. This is not a plain | 505 | /// A single value captured in the closure of a namespace type. This is not a plain |
| 506 | /// `Index` because we must differentiate between runtime-known values (where we | 506 | /// `Index` because we must differentiate between the following cases: |
| 507 | /// store the type) and comptime-known values (where we store the value). | 507 | /// * runtime-known value (where we store the type) |
| 508 | /// * comptime-known value (where we store the value) | ||
| 509 | /// * decl val (so that we can analyze the value lazily) | ||
| 510 | /// * decl ref (so that we can analyze the reference lazily) | ||
| 508 | pub const CaptureValue = packed struct(u32) { | 511 | pub const CaptureValue = packed struct(u32) { |
| 509 | tag: enum { @"comptime", runtime }, | 512 | tag: enum { @"comptime", runtime, decl_val, decl_ref }, |
| 510 | idx: u31, | 513 | idx: u30, |
| 511 | 514 | ||
| 512 | pub fn wrap(val: Unwrapped) CaptureValue { | 515 | pub fn wrap(val: Unwrapped) CaptureValue { |
| 513 | return switch (val) { | 516 | return switch (val) { |
| 514 | .@"comptime" => |i| .{ .tag = .@"comptime", .idx = @intCast(@intFromEnum(i)) }, | 517 | .@"comptime" => |i| .{ .tag = .@"comptime", .idx = @intCast(@intFromEnum(i)) }, |
| 515 | .runtime => |i| .{ .tag = .runtime, .idx = @intCast(@intFromEnum(i)) }, | 518 | .runtime => |i| .{ .tag = .runtime, .idx = @intCast(@intFromEnum(i)) }, |
| 519 | .decl_val => |i| .{ .tag = .decl_val, .idx = @intCast(@intFromEnum(i)) }, | ||
| 520 | .decl_ref => |i| .{ .tag = .decl_ref, .idx = @intCast(@intFromEnum(i)) }, | ||
| 516 | }; | 521 | }; |
| 517 | } | 522 | } |
| 518 | pub fn unwrap(val: CaptureValue) Unwrapped { | 523 | pub fn unwrap(val: CaptureValue) Unwrapped { |
| 519 | return switch (val.tag) { | 524 | return switch (val.tag) { |
| 520 | .@"comptime" => .{ .@"comptime" = @enumFromInt(val.idx) }, | 525 | .@"comptime" => .{ .@"comptime" = @enumFromInt(val.idx) }, |
| 521 | .runtime => .{ .runtime = @enumFromInt(val.idx) }, | 526 | .runtime => .{ .runtime = @enumFromInt(val.idx) }, |
| 527 | .decl_val => .{ .decl_val = @enumFromInt(val.idx) }, | ||
| 528 | .decl_ref => .{ .decl_ref = @enumFromInt(val.idx) }, | ||
| 522 | }; | 529 | }; |
| 523 | } | 530 | } |
| 524 | 531 | ||
| ... | @@ -527,6 +534,8 @@ pub const CaptureValue = packed struct(u32) { | ... | @@ -527,6 +534,8 @@ pub const CaptureValue = packed struct(u32) { |
| 527 | @"comptime": Index, | 534 | @"comptime": Index, |
| 528 | /// Index refers to the type. | 535 | /// Index refers to the type. |
| 529 | runtime: Index, | 536 | runtime: Index, |
| 537 | decl_val: DeclIndex, | ||
| 538 | decl_ref: DeclIndex, | ||
| 530 | }; | 539 | }; |
| 531 | 540 | ||
| 532 | pub const Slice = struct { | 541 | pub const Slice = struct { |
src/Sema.zig+21-11| ... | @@ -2671,26 +2671,34 @@ fn analyzeAsInt( | ... | @@ -2671,26 +2671,34 @@ fn analyzeAsInt( |
| 2671 | 2671 | ||
| 2672 | /// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`, | 2672 | /// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`, |
| 2673 | /// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`. | 2673 | /// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`. |
| 2674 | fn getCaptures(sema: *Sema, parent_namespace: ?InternPool.NamespaceIndex, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue { | 2674 | fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue { |
| 2675 | const zcu = sema.mod; | 2675 | const zcu = sema.mod; |
| 2676 | const ip = &zcu.intern_pool; | 2676 | const ip = &zcu.intern_pool; |
| 2677 | const parent_captures: InternPool.CaptureValue.Slice = if (parent_namespace) |p| parent: { | 2677 | const parent_captures: InternPool.CaptureValue.Slice = zcu.namespacePtr(block.namespace).ty.getCaptures(zcu); |
| 2678 | break :parent zcu.namespacePtr(p).ty.getCaptures(zcu); | ||
| 2679 | } else undefined; // never used so `undefined` is safe | ||
| 2680 | 2678 | ||
| 2681 | const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len); | 2679 | const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len); |
| 2682 | 2680 | ||
| 2683 | for (sema.code.extra[extra_index..][0..captures_len], captures) |raw, *capture| { | 2681 | for (sema.code.extra[extra_index..][0..captures_len], captures) |raw, *capture| { |
| 2684 | const zir_capture: Zir.Inst.Capture = @enumFromInt(raw); | 2682 | const zir_capture: Zir.Inst.Capture = @bitCast(raw); |
| 2685 | capture.* = switch (zir_capture.unwrap()) { | 2683 | capture.* = switch (zir_capture.unwrap()) { |
| 2686 | .inst => |inst| InternPool.CaptureValue.wrap(capture: { | 2684 | .nested => |parent_idx| parent_captures.get(ip)[parent_idx], |
| 2685 | .instruction => |inst| InternPool.CaptureValue.wrap(capture: { | ||
| 2687 | const air_ref = try sema.resolveInst(inst.toRef()); | 2686 | const air_ref = try sema.resolveInst(inst.toRef()); |
| 2688 | if (try sema.resolveValueResolveLazy(air_ref)) |val| { | 2687 | if (try sema.resolveValueResolveLazy(air_ref)) |val| { |
| 2689 | break :capture .{ .@"comptime" = val.toIntern() }; | 2688 | break :capture .{ .@"comptime" = val.toIntern() }; |
| 2690 | } | 2689 | } |
| 2691 | break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() }; | 2690 | break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() }; |
| 2692 | }), | 2691 | }), |
| 2693 | .nested => |parent_idx| parent_captures.get(ip)[parent_idx], | 2692 | .decl_val => |str| capture: { |
| 2693 | const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str)); | ||
| 2694 | const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc? | ||
| 2695 | break :capture InternPool.CaptureValue.wrap(.{ .decl_val = decl }); | ||
| 2696 | }, | ||
| 2697 | .decl_ref => |str| capture: { | ||
| 2698 | const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str)); | ||
| 2699 | const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc? | ||
| 2700 | break :capture InternPool.CaptureValue.wrap(.{ .decl_ref = decl }); | ||
| 2701 | }, | ||
| 2694 | }; | 2702 | }; |
| 2695 | } | 2703 | } |
| 2696 | 2704 | ||
| ... | @@ -2727,7 +2735,7 @@ fn zirStructDecl( | ... | @@ -2727,7 +2735,7 @@ fn zirStructDecl( |
| 2727 | break :blk decls_len; | 2735 | break :blk decls_len; |
| 2728 | } else 0; | 2736 | } else 0; |
| 2729 | 2737 | ||
| 2730 | const captures = try sema.getCaptures(block.namespace, extra_index, captures_len); | 2738 | const captures = try sema.getCaptures(block, extra_index, captures_len); |
| 2731 | extra_index += captures_len; | 2739 | extra_index += captures_len; |
| 2732 | 2740 | ||
| 2733 | if (small.has_backing_int) { | 2741 | if (small.has_backing_int) { |
| ... | @@ -2944,7 +2952,7 @@ fn zirEnumDecl( | ... | @@ -2944,7 +2952,7 @@ fn zirEnumDecl( |
| 2944 | break :blk decls_len; | 2952 | break :blk decls_len; |
| 2945 | } else 0; | 2953 | } else 0; |
| 2946 | 2954 | ||
| 2947 | const captures = try sema.getCaptures(block.namespace, extra_index, captures_len); | 2955 | const captures = try sema.getCaptures(block, extra_index, captures_len); |
| 2948 | extra_index += captures_len; | 2956 | extra_index += captures_len; |
| 2949 | 2957 | ||
| 2950 | const decls = sema.code.bodySlice(extra_index, decls_len); | 2958 | const decls = sema.code.bodySlice(extra_index, decls_len); |
| ... | @@ -3209,7 +3217,7 @@ fn zirUnionDecl( | ... | @@ -3209,7 +3217,7 @@ fn zirUnionDecl( |
| 3209 | break :blk decls_len; | 3217 | break :blk decls_len; |
| 3210 | } else 0; | 3218 | } else 0; |
| 3211 | 3219 | ||
| 3212 | const captures = try sema.getCaptures(block.namespace, extra_index, captures_len); | 3220 | const captures = try sema.getCaptures(block, extra_index, captures_len); |
| 3213 | extra_index += captures_len; | 3221 | extra_index += captures_len; |
| 3214 | 3222 | ||
| 3215 | const wip_ty = switch (try ip.getUnionType(gpa, .{ | 3223 | const wip_ty = switch (try ip.getUnionType(gpa, .{ |
| ... | @@ -3315,7 +3323,7 @@ fn zirOpaqueDecl( | ... | @@ -3315,7 +3323,7 @@ fn zirOpaqueDecl( |
| 3315 | break :blk decls_len; | 3323 | break :blk decls_len; |
| 3316 | } else 0; | 3324 | } else 0; |
| 3317 | 3325 | ||
| 3318 | const captures = try sema.getCaptures(block.namespace, extra_index, captures_len); | 3326 | const captures = try sema.getCaptures(block, extra_index, captures_len); |
| 3319 | extra_index += captures_len; | 3327 | extra_index += captures_len; |
| 3320 | 3328 | ||
| 3321 | const wip_ty = switch (try ip.getOpaqueType(gpa, .{ | 3329 | const wip_ty = switch (try ip.getOpaqueType(gpa, .{ |
| ... | @@ -17268,6 +17276,8 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -17268,6 +17276,8 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 17268 | const capture_ty = switch (captures.get(ip)[extended.small].unwrap()) { | 17276 | const capture_ty = switch (captures.get(ip)[extended.small].unwrap()) { |
| 17269 | .@"comptime" => |index| return Air.internedToRef(index), | 17277 | .@"comptime" => |index| return Air.internedToRef(index), |
| 17270 | .runtime => |index| index, | 17278 | .runtime => |index| index, |
| 17279 | .decl_val => |decl_index| return sema.analyzeDeclVal(block, src, decl_index), | ||
| 17280 | .decl_ref => |decl_index| return sema.analyzeDeclRef(decl_index), | ||
| 17271 | }; | 17281 | }; |
| 17272 | 17282 | ||
| 17273 | // The comptime case is handled already above. Runtime case below. | 17283 | // The comptime case is handled already above. Runtime case below. |
src/print_zir.zig+15-9| ... | @@ -1427,11 +1427,11 @@ const Writer = struct { | ... | @@ -1427,11 +1427,11 @@ const Writer = struct { |
| 1427 | try stream.writeAll("{}, "); | 1427 | try stream.writeAll("{}, "); |
| 1428 | } else { | 1428 | } else { |
| 1429 | try stream.writeAll("{ "); | 1429 | try stream.writeAll("{ "); |
| 1430 | try self.writeCapture(stream, @enumFromInt(self.code.extra[extra_index])); | 1430 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); |
| 1431 | extra_index += 1; | 1431 | extra_index += 1; |
| 1432 | for (1..captures_len) |_| { | 1432 | for (1..captures_len) |_| { |
| 1433 | try stream.writeAll(", "); | 1433 | try stream.writeAll(", "); |
| 1434 | try self.writeCapture(stream, @enumFromInt(self.code.extra[extra_index])); | 1434 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); |
| 1435 | extra_index += 1; | 1435 | extra_index += 1; |
| 1436 | } | 1436 | } |
| 1437 | try stream.writeAll(" }, "); | 1437 | try stream.writeAll(" }, "); |
| ... | @@ -1652,11 +1652,11 @@ const Writer = struct { | ... | @@ -1652,11 +1652,11 @@ const Writer = struct { |
| 1652 | try stream.writeAll("{}, "); | 1652 | try stream.writeAll("{}, "); |
| 1653 | } else { | 1653 | } else { |
| 1654 | try stream.writeAll("{ "); | 1654 | try stream.writeAll("{ "); |
| 1655 | try self.writeCapture(stream, @enumFromInt(self.code.extra[extra_index])); | 1655 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); |
| 1656 | extra_index += 1; | 1656 | extra_index += 1; |
| 1657 | for (1..captures_len) |_| { | 1657 | for (1..captures_len) |_| { |
| 1658 | try stream.writeAll(", "); | 1658 | try stream.writeAll(", "); |
| 1659 | try self.writeCapture(stream, @enumFromInt(self.code.extra[extra_index])); | 1659 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); |
| 1660 | extra_index += 1; | 1660 | extra_index += 1; |
| 1661 | } | 1661 | } |
| 1662 | try stream.writeAll(" }, "); | 1662 | try stream.writeAll(" }, "); |
| ... | @@ -1817,11 +1817,11 @@ const Writer = struct { | ... | @@ -1817,11 +1817,11 @@ const Writer = struct { |
| 1817 | try stream.writeAll("{}, "); | 1817 | try stream.writeAll("{}, "); |
| 1818 | } else { | 1818 | } else { |
| 1819 | try stream.writeAll("{ "); | 1819 | try stream.writeAll("{ "); |
| 1820 | try self.writeCapture(stream, @enumFromInt(self.code.extra[extra_index])); | 1820 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); |
| 1821 | extra_index += 1; | 1821 | extra_index += 1; |
| 1822 | for (1..captures_len) |_| { | 1822 | for (1..captures_len) |_| { |
| 1823 | try stream.writeAll(", "); | 1823 | try stream.writeAll(", "); |
| 1824 | try self.writeCapture(stream, @enumFromInt(self.code.extra[extra_index])); | 1824 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); |
| 1825 | extra_index += 1; | 1825 | extra_index += 1; |
| 1826 | } | 1826 | } |
| 1827 | try stream.writeAll(" }, "); | 1827 | try stream.writeAll(" }, "); |
| ... | @@ -1930,11 +1930,11 @@ const Writer = struct { | ... | @@ -1930,11 +1930,11 @@ const Writer = struct { |
| 1930 | try stream.writeAll("{}, "); | 1930 | try stream.writeAll("{}, "); |
| 1931 | } else { | 1931 | } else { |
| 1932 | try stream.writeAll("{ "); | 1932 | try stream.writeAll("{ "); |
| 1933 | try self.writeCapture(stream, @enumFromInt(self.code.extra[extra_index])); | 1933 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); |
| 1934 | extra_index += 1; | 1934 | extra_index += 1; |
| 1935 | for (1..captures_len) |_| { | 1935 | for (1..captures_len) |_| { |
| 1936 | try stream.writeAll(", "); | 1936 | try stream.writeAll(", "); |
| 1937 | try self.writeCapture(stream, @enumFromInt(self.code.extra[extra_index])); | 1937 | try self.writeCapture(stream, @bitCast(self.code.extra[extra_index])); |
| 1938 | extra_index += 1; | 1938 | extra_index += 1; |
| 1939 | } | 1939 | } |
| 1940 | try stream.writeAll(" }, "); | 1940 | try stream.writeAll(" }, "); |
| ... | @@ -2808,8 +2808,14 @@ const Writer = struct { | ... | @@ -2808,8 +2808,14 @@ const Writer = struct { |
| 2808 | 2808 | ||
| 2809 | fn writeCapture(self: *Writer, stream: anytype, capture: Zir.Inst.Capture) !void { | 2809 | fn writeCapture(self: *Writer, stream: anytype, capture: Zir.Inst.Capture) !void { |
| 2810 | switch (capture.unwrap()) { | 2810 | switch (capture.unwrap()) { |
| 2811 | .inst => |inst| return self.writeInstIndex(stream, inst), | ||
| 2812 | .nested => |i| return stream.print("[{d}]", .{i}), | 2811 | .nested => |i| return stream.print("[{d}]", .{i}), |
| 2812 | .instruction => |inst| return self.writeInstIndex(stream, inst), | ||
| 2813 | .decl_val => |str| try stream.print("decl_val \"{}\"", .{ | ||
| 2814 | std.zig.fmtEscapes(self.code.nullTerminatedString(str)), | ||
| 2815 | }), | ||
| 2816 | .decl_ref => |str| try stream.print("decl_ref \"{}\"", .{ | ||
| 2817 | std.zig.fmtEscapes(self.code.nullTerminatedString(str)), | ||
| 2818 | }), | ||
| 2813 | } | 2819 | } |
| 2814 | } | 2820 | } |
| 2815 | 2821 |