authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-25 18:27:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-03-26 00:27:12-04:00
logbae35bdf2d8919b60dee9a0af3afbdd93dd72b59
treebff6e4b5f81840d82febef78b28e75d9dc1083e3
parentbcd7eb012ac3d4a6365eea0b69aa89b0aef57243

stage2: result location types for function call arguments

* 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 when1587 // 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 }
16021603
...@@ -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,
23542364
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);
78487858
7849 for (call.ast.params) |param_node| {7859 for (call.ast.params) |param_node, i| {
7850 // Parameters are always temporary values, they have no7860 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}
36403641
3642fn 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
3641fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {3675fn 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}
66186653
...@@ -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
12140fn unionInit(12175fn 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);
1215112188
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 value476 /// 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,
12681277
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),
253253
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 }
560561
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,
37263726
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 }
26612661
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 correct2670 // 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 },
26762683
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
102test "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}