| author | |
| committer | |
| log | bae35bdf2d8919b60dee9a0af3afbdd93dd72b59 |
| tree | bff6e4b5f81840d82febef78b28e75d9dc1083e3 |
| parent | bcd7eb012ac3d4a6365eea0b69aa89b0aef57243 |
* AstGen: restore the param_type ZIR instruction and pass it to the
expression for function call arguments. This does not solve the
problem for generic function parameters, but it catches stage2 up to
stage1 which also does not solve the problem for generic function
parameters.
- Most of the enhancements in this commit will still be needed for a
more sophisticated further improvement to handle generic function
types.
- In Sema, handling of `as` coercion recognizes the `var_args_param`
Type Tag and passes the operand through doing no coercion.
- That was the last ZIR tag and we are now using all 256 ZIR tags.
* AstGen: array init and struct init expressions use the anon form even
when the result location has a type. Prevents the type system
incorrectly believing, for example, that a tuple is actually an array
when the result location is a param_type of a function with `anytype`
parameter.
* Sema: add missing coercion in `unionInit` to coerce the init to the
corresponding union field type.
* `Value.fieldValue` now takes a type and does not take an allocator.
closes #11293
After this commit, stage2 passes all the parser tests.7 files changed, 127 insertions(+), 19 deletions(-)
src/AstGen.zig+28-13| ... | @@ -1318,13 +1318,13 @@ fn arrayInitExpr( | ... | @@ -1318,13 +1318,13 @@ fn arrayInitExpr( |
| 1318 | return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); | 1318 | return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); |
| 1319 | } | 1319 | } |
| 1320 | }, | 1320 | }, |
| 1321 | .ty, .coerced_ty => |ty_inst| { | 1321 | .ty, .coerced_ty => { |
| 1322 | if (types.array != .none) { | 1322 | if (types.array != .none) { |
| 1323 | const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false); | 1323 | const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false); |
| 1324 | return rvalue(gz, rl, result, node); | 1324 | return rvalue(gz, rl, result, node); |
| 1325 | } else { | 1325 | } else { |
| 1326 | const elem_type = try gz.addUnNode(.elem_type, ty_inst, node); | 1326 | const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon); |
| 1327 | return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.sentinel, false); | 1327 | return rvalue(gz, rl, result, node); |
| 1328 | } | 1328 | } |
| 1329 | }, | 1329 | }, |
| 1330 | .ptr => |ptr_inst| { | 1330 | .ptr => |ptr_inst| { |
| ... | @@ -1559,7 +1559,7 @@ fn structInitExpr( | ... | @@ -1559,7 +1559,7 @@ fn structInitExpr( |
| 1559 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | 1559 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); |
| 1560 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref); | 1560 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref); |
| 1561 | } else { | 1561 | } else { |
| 1562 | return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon_ref); | 1562 | return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon_ref); |
| 1563 | } | 1563 | } |
| 1564 | }, | 1564 | }, |
| 1565 | .none => { | 1565 | .none => { |
| ... | @@ -1568,12 +1568,13 @@ fn structInitExpr( | ... | @@ -1568,12 +1568,13 @@ fn structInitExpr( |
| 1568 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); | 1568 | _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node); |
| 1569 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); | 1569 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); |
| 1570 | } else { | 1570 | } else { |
| 1571 | return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon); | 1571 | return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); |
| 1572 | } | 1572 | } |
| 1573 | }, | 1573 | }, |
| 1574 | .ty, .coerced_ty => |ty_inst| { | 1574 | .ty, .coerced_ty => |ty_inst| { |
| 1575 | if (struct_init.ast.type_expr == 0) { | 1575 | if (struct_init.ast.type_expr == 0) { |
| 1576 | return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init); | 1576 | const result = try structInitExprRlNone(gz, scope, node, struct_init, ty_inst, .struct_init_anon); |
| 1577 | return rvalue(gz, rl, result, node); | ||
| 1577 | } | 1578 | } |
| 1578 | const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); | 1579 | const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr); |
| 1579 | _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node); | 1580 | _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node); |
| ... | @@ -1586,7 +1587,7 @@ fn structInitExpr( | ... | @@ -1586,7 +1587,7 @@ fn structInitExpr( |
| 1586 | // We treat this case differently so that we don't get a crash when | 1587 | // We treat this case differently so that we don't get a crash when |
| 1587 | // analyzing field_base_ptr against an alloc_inferred_mut. | 1588 | // analyzing field_base_ptr against an alloc_inferred_mut. |
| 1588 | // See corresponding logic in arrayInitExpr. | 1589 | // See corresponding logic in arrayInitExpr. |
| 1589 | const result = try structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon); | 1590 | const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); |
| 1590 | return rvalue(gz, rl, result, node); | 1591 | return rvalue(gz, rl, result, node); |
| 1591 | } else { | 1592 | } else { |
| 1592 | return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst); | 1593 | return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst); |
| ... | @@ -1596,7 +1597,7 @@ fn structInitExpr( | ... | @@ -1596,7 +1597,7 @@ fn structInitExpr( |
| 1596 | // This condition is here for the same reason as the above condition in `inferred_ptr`. | 1597 | // This condition is here for the same reason as the above condition in `inferred_ptr`. |
| 1597 | // See corresponding logic in arrayInitExpr. | 1598 | // See corresponding logic in arrayInitExpr. |
| 1598 | if (struct_init.ast.type_expr == 0 and astgen.isInferred(block_gz.rl_ptr)) { | 1599 | if (struct_init.ast.type_expr == 0 and astgen.isInferred(block_gz.rl_ptr)) { |
| 1599 | const result = try structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon); | 1600 | const result = try structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon); |
| 1600 | return rvalue(gz, rl, result, node); | 1601 | return rvalue(gz, rl, result, node); |
| 1601 | } | 1602 | } |
| 1602 | 1603 | ||
| ... | @@ -1610,6 +1611,7 @@ fn structInitExprRlNone( | ... | @@ -1610,6 +1611,7 @@ fn structInitExprRlNone( |
| 1610 | scope: *Scope, | 1611 | scope: *Scope, |
| 1611 | node: Ast.Node.Index, | 1612 | node: Ast.Node.Index, |
| 1612 | struct_init: Ast.full.StructInit, | 1613 | struct_init: Ast.full.StructInit, |
| 1614 | ty_inst: Zir.Inst.Ref, | ||
| 1613 | tag: Zir.Inst.Tag, | 1615 | tag: Zir.Inst.Tag, |
| 1614 | ) InnerError!Zir.Inst.Ref { | 1616 | ) InnerError!Zir.Inst.Ref { |
| 1615 | const astgen = gz.astgen; | 1617 | const astgen = gz.astgen; |
| ... | @@ -1624,9 +1626,16 @@ fn structInitExprRlNone( | ... | @@ -1624,9 +1626,16 @@ fn structInitExprRlNone( |
| 1624 | for (struct_init.ast.fields) |field_init| { | 1626 | for (struct_init.ast.fields) |field_init| { |
| 1625 | const name_token = tree.firstToken(field_init) - 2; | 1627 | const name_token = tree.firstToken(field_init) - 2; |
| 1626 | const str_index = try astgen.identAsString(name_token); | 1628 | const str_index = try astgen.identAsString(name_token); |
| 1629 | const sub_rl: ResultLoc = if (ty_inst != .none) | ||
| 1630 | ResultLoc{ .ty = try gz.addPlNode(.field_type, field_init, Zir.Inst.FieldType{ | ||
| 1631 | .container_type = ty_inst, | ||
| 1632 | .name_start = str_index, | ||
| 1633 | }) } | ||
| 1634 | else | ||
| 1635 | .none; | ||
| 1627 | setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{ | 1636 | setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{ |
| 1628 | .field_name = str_index, | 1637 | .field_name = str_index, |
| 1629 | .init = try expr(gz, scope, .none, field_init), | 1638 | .init = try expr(gz, scope, sub_rl, field_init), |
| 1630 | }); | 1639 | }); |
| 1631 | extra_index += field_size; | 1640 | extra_index += field_size; |
| 1632 | } | 1641 | } |
| ... | @@ -2350,6 +2359,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner | ... | @@ -2350,6 +2359,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner |
| 2350 | .closure_get, | 2359 | .closure_get, |
| 2351 | .array_base_ptr, | 2360 | .array_base_ptr, |
| 2352 | .field_base_ptr, | 2361 | .field_base_ptr, |
| 2362 | .param_type, | ||
| 2353 | => break :b false, | 2363 | => break :b false, |
| 2354 | 2364 | ||
| 2355 | // ZIR instructions that are always `noreturn`. | 2365 | // ZIR instructions that are always `noreturn`. |
| ... | @@ -7846,10 +7856,15 @@ fn callExpr( | ... | @@ -7846,10 +7856,15 @@ fn callExpr( |
| 7846 | }); | 7856 | }); |
| 7847 | var extra_index = try reserveExtra(astgen, call.ast.params.len); | 7857 | var extra_index = try reserveExtra(astgen, call.ast.params.len); |
| 7848 | 7858 | ||
| 7849 | for (call.ast.params) |param_node| { | 7859 | for (call.ast.params) |param_node, i| { |
| 7850 | // Parameters are always temporary values, they have no | 7860 | const param_type = try gz.add(.{ |
| 7851 | // meaningful result location. Sema will coerce them. | 7861 | .tag = .param_type, |
| 7852 | const arg_ref = try expr(gz, scope, .none, param_node); | 7862 | .data = .{ .param_type = .{ |
| 7863 | .callee = callee, | ||
| 7864 | .param_index = @intCast(u32, i), | ||
| 7865 | } }, | ||
| 7866 | }); | ||
| 7867 | const arg_ref = try expr(gz, scope, .{ .coerced_ty = param_type }, param_node); | ||
| 7853 | astgen.extra.items[extra_index] = @enumToInt(arg_ref); | 7868 | astgen.extra.items[extra_index] = @enumToInt(arg_ref); |
| 7854 | extra_index += 1; | 7869 | extra_index += 1; |
| 7855 | } | 7870 | } |
src/Sema.zig+40-2| ... | @@ -738,6 +738,7 @@ fn analyzeBodyInner( | ... | @@ -738,6 +738,7 @@ fn analyzeBodyInner( |
| 738 | .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), | 738 | .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false), |
| 739 | .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), | 739 | .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false), |
| 740 | .optional_type => try sema.zirOptionalType(block, inst), | 740 | .optional_type => try sema.zirOptionalType(block, inst), |
| 741 | .param_type => try sema.zirParamType(block, inst), | ||
| 741 | .ptr_type => try sema.zirPtrType(block, inst), | 742 | .ptr_type => try sema.zirPtrType(block, inst), |
| 742 | .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst), | 743 | .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst), |
| 743 | .ref => try sema.zirRef(block, inst), | 744 | .ref => try sema.zirRef(block, inst), |
| ... | @@ -3638,6 +3639,39 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v | ... | @@ -3638,6 +3639,39 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v |
| 3638 | return sema.storePtr(block, src, ptr, operand); | 3639 | return sema.storePtr(block, src, ptr, operand); |
| 3639 | } | 3640 | } |
| 3640 | 3641 | ||
| 3642 | fn zirParamType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | ||
| 3643 | const callee_src = sema.src; | ||
| 3644 | |||
| 3645 | const inst_data = sema.code.instructions.items(.data)[inst].param_type; | ||
| 3646 | const callee = sema.resolveInst(inst_data.callee); | ||
| 3647 | const callee_ty = sema.typeOf(callee); | ||
| 3648 | var param_index = inst_data.param_index; | ||
| 3649 | |||
| 3650 | const fn_ty = if (callee_ty.tag() == .bound_fn) fn_ty: { | ||
| 3651 | const bound_fn_val = try sema.resolveConstValue(block, callee_src, callee); | ||
| 3652 | const bound_fn = bound_fn_val.castTag(.bound_fn).?.data; | ||
| 3653 | const fn_ty = sema.typeOf(bound_fn.func_inst); | ||
| 3654 | param_index += 1; | ||
| 3655 | break :fn_ty fn_ty; | ||
| 3656 | } else callee_ty; | ||
| 3657 | |||
| 3658 | const fn_info = if (fn_ty.zigTypeTag() == .Pointer) | ||
| 3659 | fn_ty.childType().fnInfo() | ||
| 3660 | else | ||
| 3661 | fn_ty.fnInfo(); | ||
| 3662 | |||
| 3663 | if (param_index >= fn_info.param_types.len) { | ||
| 3664 | assert(fn_info.is_var_args); | ||
| 3665 | return sema.addType(Type.initTag(.var_args_param)); | ||
| 3666 | } | ||
| 3667 | |||
| 3668 | if (fn_info.param_types[param_index].tag() == .generic_poison) { | ||
| 3669 | return sema.addType(Type.initTag(.var_args_param)); | ||
| 3670 | } | ||
| 3671 | |||
| 3672 | return sema.addType(fn_info.param_types[param_index]); | ||
| 3673 | } | ||
| 3674 | |||
| 3641 | fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 3675 | fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| 3642 | const tracy = trace(@src()); | 3676 | const tracy = trace(@src()); |
| 3643 | defer tracy.end(); | 3677 | defer tracy.end(); |
| ... | @@ -6613,6 +6647,7 @@ fn analyzeAs( | ... | @@ -6613,6 +6647,7 @@ fn analyzeAs( |
| 6613 | ) CompileError!Air.Inst.Ref { | 6647 | ) CompileError!Air.Inst.Ref { |
| 6614 | const dest_ty = try sema.resolveType(block, src, zir_dest_type); | 6648 | const dest_ty = try sema.resolveType(block, src, zir_dest_type); |
| 6615 | const operand = sema.resolveInst(zir_operand); | 6649 | const operand = sema.resolveInst(zir_operand); |
| 6650 | if (dest_ty.tag() == .var_args_param) return operand; | ||
| 6616 | return sema.coerce(block, dest_ty, operand, src); | 6651 | return sema.coerce(block, dest_ty, operand, src); |
| 6617 | } | 6652 | } |
| 6618 | 6653 | ||
| ... | @@ -12140,7 +12175,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -12140,7 +12175,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 12140 | fn unionInit( | 12175 | fn unionInit( |
| 12141 | sema: *Sema, | 12176 | sema: *Sema, |
| 12142 | block: *Block, | 12177 | block: *Block, |
| 12143 | init: Air.Inst.Ref, | 12178 | uncasted_init: Air.Inst.Ref, |
| 12144 | init_src: LazySrcLoc, | 12179 | init_src: LazySrcLoc, |
| 12145 | union_ty: Type, | 12180 | union_ty: Type, |
| 12146 | union_ty_src: LazySrcLoc, | 12181 | union_ty_src: LazySrcLoc, |
| ... | @@ -12148,6 +12183,8 @@ fn unionInit( | ... | @@ -12148,6 +12183,8 @@ fn unionInit( |
| 12148 | field_src: LazySrcLoc, | 12183 | field_src: LazySrcLoc, |
| 12149 | ) CompileError!Air.Inst.Ref { | 12184 | ) CompileError!Air.Inst.Ref { |
| 12150 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src); | 12185 | const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src); |
| 12186 | const field = union_ty.unionFields().values()[field_index]; | ||
| 12187 | const init = try sema.coerce(block, field.ty, uncasted_init, init_src); | ||
| 12151 | 12188 | ||
| 12152 | if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| { | 12189 | if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| { |
| 12153 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); | 12190 | const tag_val = try Value.Tag.enum_field_index.create(sema.arena, field_index); |
| ... | @@ -12620,6 +12657,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A | ... | @@ -12620,6 +12657,7 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 12620 | const ty_src = inst_data.src(); | 12657 | const ty_src = inst_data.src(); |
| 12621 | const field_src = inst_data.src(); | 12658 | const field_src = inst_data.src(); |
| 12622 | const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); | 12659 | const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); |
| 12660 | if (aggregate_ty.tag() == .var_args_param) return sema.addType(aggregate_ty); | ||
| 12623 | const field_name = sema.code.nullTerminatedString(extra.name_start); | 12661 | const field_name = sema.code.nullTerminatedString(extra.name_start); |
| 12624 | return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); | 12662 | return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); |
| 12625 | } | 12663 | } |
| ... | @@ -18964,7 +19002,7 @@ fn beginComptimePtrLoad( | ... | @@ -18964,7 +19002,7 @@ fn beginComptimePtrLoad( |
| 18964 | if (coerce_in_mem_ok) { | 19002 | if (coerce_in_mem_ok) { |
| 18965 | deref.pointee = TypedValue{ | 19003 | deref.pointee = TypedValue{ |
| 18966 | .ty = field_ty, | 19004 | .ty = field_ty, |
| 18967 | .val = try tv.val.fieldValue(sema.arena, field_index), | 19005 | .val = tv.val.fieldValue(tv.ty, field_index), |
| 18968 | }; | 19006 | }; |
| 18969 | break :blk deref; | 19007 | break :blk deref; |
| 18970 | } | 19008 | } |
src/Zir.zig+15| ... | @@ -464,6 +464,14 @@ pub const Inst = struct { | ... | @@ -464,6 +464,14 @@ pub const Inst = struct { |
| 464 | /// Merge two error sets into one, `E1 || E2`. | 464 | /// Merge two error sets into one, `E1 || E2`. |
| 465 | /// Uses the `pl_node` field with payload `Bin`. | 465 | /// Uses the `pl_node` field with payload `Bin`. |
| 466 | merge_error_sets, | 466 | merge_error_sets, |
| 467 | /// Given a reference to a function and a parameter index, returns the | ||
| 468 | /// type of the parameter. The only usage of this instruction is for the | ||
| 469 | /// result location of parameters of function calls. In the case of a function's | ||
| 470 | /// parameter type being `anytype`, it is the type coercion's job to detect this | ||
| 471 | /// scenario and skip the coercion, so that semantic analysis of this instruction | ||
| 472 | /// is not in a position where it must create an invalid type. | ||
| 473 | /// Uses the `param_type` union field. | ||
| 474 | param_type, | ||
| 467 | /// Turns an R-Value into a const L-Value. In other words, it takes a value, | 475 | /// Turns an R-Value into a const L-Value. In other words, it takes a value, |
| 468 | /// stores it in a memory location, and returns a const pointer to it. If the value | 476 | /// stores it in a memory location, and returns a const pointer to it. If the value |
| 469 | /// is `comptime`, the memory location is global static constant data. Otherwise, | 477 | /// is `comptime`, the memory location is global static constant data. Otherwise, |
| ... | @@ -1077,6 +1085,7 @@ pub const Inst = struct { | ... | @@ -1077,6 +1085,7 @@ pub const Inst = struct { |
| 1077 | .mul, | 1085 | .mul, |
| 1078 | .mulwrap, | 1086 | .mulwrap, |
| 1079 | .mul_sat, | 1087 | .mul_sat, |
| 1088 | .param_type, | ||
| 1080 | .ref, | 1089 | .ref, |
| 1081 | .shl, | 1090 | .shl, |
| 1082 | .shl_sat, | 1091 | .shl_sat, |
| ... | @@ -1266,6 +1275,7 @@ pub const Inst = struct { | ... | @@ -1266,6 +1275,7 @@ pub const Inst = struct { |
| 1266 | .mulwrap = .pl_node, | 1275 | .mulwrap = .pl_node, |
| 1267 | .mul_sat = .pl_node, | 1276 | .mul_sat = .pl_node, |
| 1268 | 1277 | ||
| 1278 | .param_type = .param_type, | ||
| 1269 | .param = .pl_tok, | 1279 | .param = .pl_tok, |
| 1270 | .param_comptime = .pl_tok, | 1280 | .param_comptime = .pl_tok, |
| 1271 | .param_anytype = .str_tok, | 1281 | .param_anytype = .str_tok, |
| ... | @@ -2213,6 +2223,10 @@ pub const Inst = struct { | ... | @@ -2213,6 +2223,10 @@ pub const Inst = struct { |
| 2213 | /// Points to a `Block`. | 2223 | /// Points to a `Block`. |
| 2214 | payload_index: u32, | 2224 | payload_index: u32, |
| 2215 | }, | 2225 | }, |
| 2226 | param_type: struct { | ||
| 2227 | callee: Ref, | ||
| 2228 | param_index: u32, | ||
| 2229 | }, | ||
| 2216 | @"unreachable": struct { | 2230 | @"unreachable": struct { |
| 2217 | /// Offset from Decl AST node index. | 2231 | /// Offset from Decl AST node index. |
| 2218 | /// `Tag` determines which kind of AST node this points to. | 2232 | /// `Tag` determines which kind of AST node this points to. |
| ... | @@ -2288,6 +2302,7 @@ pub const Inst = struct { | ... | @@ -2288,6 +2302,7 @@ pub const Inst = struct { |
| 2288 | ptr_type, | 2302 | ptr_type, |
| 2289 | int_type, | 2303 | int_type, |
| 2290 | bool_br, | 2304 | bool_br, |
| 2305 | param_type, | ||
| 2291 | @"unreachable", | 2306 | @"unreachable", |
| 2292 | @"break", | 2307 | @"break", |
| 2293 | switch_capture, | 2308 | switch_capture, |
src/print_zir.zig+11| ... | @@ -252,6 +252,7 @@ const Writer = struct { | ... | @@ -252,6 +252,7 @@ const Writer = struct { |
| 252 | => try self.writeBoolBr(stream, inst), | 252 | => try self.writeBoolBr(stream, inst), |
| 253 | 253 | ||
| 254 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), | 254 | .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst), |
| 255 | .param_type => try self.writeParamType(stream, inst), | ||
| 255 | .ptr_type_simple => try self.writePtrTypeSimple(stream, inst), | 256 | .ptr_type_simple => try self.writePtrTypeSimple(stream, inst), |
| 256 | .ptr_type => try self.writePtrType(stream, inst), | 257 | .ptr_type => try self.writePtrType(stream, inst), |
| 257 | .int => try self.writeInt(stream, inst), | 258 | .int => try self.writeInt(stream, inst), |
| ... | @@ -558,6 +559,16 @@ const Writer = struct { | ... | @@ -558,6 +559,16 @@ const Writer = struct { |
| 558 | try self.writeSrc(stream, inst_data.src()); | 559 | try self.writeSrc(stream, inst_data.src()); |
| 559 | } | 560 | } |
| 560 | 561 | ||
| 562 | fn writeParamType( | ||
| 563 | self: *Writer, | ||
| 564 | stream: anytype, | ||
| 565 | inst: Zir.Inst.Index, | ||
| 566 | ) (@TypeOf(stream).Error || error{OutOfMemory})!void { | ||
| 567 | const inst_data = self.code.instructions.items(.data)[inst].param_type; | ||
| 568 | try self.writeInstRef(stream, inst_data.callee); | ||
| 569 | try stream.print(", {d})", .{inst_data.param_index}); | ||
| 570 | } | ||
| 571 | |||
| 561 | fn writePtrTypeSimple( | 572 | fn writePtrTypeSimple( |
| 562 | self: *Writer, | 573 | self: *Writer, |
| 563 | stream: anytype, | 574 | stream: anytype, |
src/type.zig+2| ... | @@ -3724,6 +3724,8 @@ pub const Type = extern union { | ... | @@ -3724,6 +3724,8 @@ pub const Type = extern union { |
| 3724 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), | 3724 | .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int), |
| 3725 | .pointer => ty.castTag(.pointer).?.data.pointee_type, | 3725 | .pointer => ty.castTag(.pointer).?.data.pointee_type, |
| 3726 | 3726 | ||
| 3727 | .var_args_param => ty, | ||
| 3728 | |||
| 3727 | else => unreachable, | 3729 | else => unreachable, |
| 3728 | }; | 3730 | }; |
| 3729 | } | 3731 | } |
src/value.zig+11-4| ... | @@ -2659,8 +2659,7 @@ pub const Value = extern union { | ... | @@ -2659,8 +2659,7 @@ pub const Value = extern union { |
| 2659 | }; | 2659 | }; |
| 2660 | } | 2660 | } |
| 2661 | 2661 | ||
| 2662 | pub fn fieldValue(val: Value, allocator: Allocator, index: usize) error{OutOfMemory}!Value { | 2662 | pub fn fieldValue(val: Value, ty: Type, index: usize) Value { |
| 2663 | _ = allocator; | ||
| 2664 | switch (val.tag()) { | 2663 | switch (val.tag()) { |
| 2665 | .aggregate => { | 2664 | .aggregate => { |
| 2666 | const field_values = val.castTag(.aggregate).?.data; | 2665 | const field_values = val.castTag(.aggregate).?.data; |
| ... | @@ -2671,8 +2670,16 @@ pub const Value = extern union { | ... | @@ -2671,8 +2670,16 @@ pub const Value = extern union { |
| 2671 | // TODO assert the tag is correct | 2670 | // TODO assert the tag is correct |
| 2672 | return payload.val; | 2671 | return payload.val; |
| 2673 | }, | 2672 | }, |
| 2674 | // Structs which have only one possible value need to consist of members which have only one possible value. | 2673 | |
| 2675 | .the_only_possible_value => return val, | 2674 | .the_only_possible_value => return ty.onePossibleValue().?, |
| 2675 | |||
| 2676 | .empty_struct_value => { | ||
| 2677 | if (ty.isTupleOrAnonStruct()) { | ||
| 2678 | const tuple = ty.tupleFields(); | ||
| 2679 | return tuple.values[index]; | ||
| 2680 | } | ||
| 2681 | unreachable; | ||
| 2682 | }, | ||
| 2676 | 2683 | ||
| 2677 | else => unreachable, | 2684 | else => unreachable, |
| 2678 | } | 2685 | } |
test/behavior/call.zig+20| ... | @@ -98,3 +98,23 @@ test "comptime call with bound function as parameter" { | ... | @@ -98,3 +98,23 @@ test "comptime call with bound function as parameter" { |
| 98 | var inst: S = undefined; | 98 | var inst: S = undefined; |
| 99 | try expectEqual(?i32, S.ReturnType(inst.call_me_maybe)); | 99 | try expectEqual(?i32, S.ReturnType(inst.call_me_maybe)); |
| 100 | } | 100 | } |
| 101 | |||
| 102 | test "result location of function call argument through runtime condition and struct init" { | ||
| 103 | if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO | ||
| 104 | if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO | ||
| 105 | if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; // TODO | ||
| 106 | |||
| 107 | const E = enum { a, b }; | ||
| 108 | const S = struct { | ||
| 109 | e: E, | ||
| 110 | }; | ||
| 111 | const namespace = struct { | ||
| 112 | fn foo(s: S) !void { | ||
| 113 | try expect(s.e == .b); | ||
| 114 | } | ||
| 115 | }; | ||
| 116 | var runtime = true; | ||
| 117 | try namespace.foo(.{ | ||
| 118 | .e = if (!runtime) .a else .b, | ||
| 119 | }); | ||
| 120 | } |