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(
13181318 return arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
13191319 }
13201320 },
1321 .ty, .coerced_ty => |ty_inst| {
1321 .ty, .coerced_ty => {
13221322 if (types.array != .none) {
13231323 const result = try arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, types.elem, types.sentinel, false);
13241324 return rvalue(gz, rl, result, node);
13251325 } else {
1326 const elem_type = try gz.addUnNode(.elem_type, ty_inst, node);
1327 return arrayInitExprRlTy(gz, scope, node, array_init.ast.elements, elem_type, types.sentinel, false);
1326 const result = try arrayInitExprRlNone(gz, scope, node, array_init.ast.elements, .array_init_anon);
1327 return rvalue(gz, rl, result, node);
13281328 }
13291329 },
13301330 .ptr => |ptr_inst| {
......@@ -1559,7 +1559,7 @@ fn structInitExpr(
15591559 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
15601560 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init_ref);
15611561 } 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);
15631563 }
15641564 },
15651565 .none => {
......@@ -1568,12 +1568,13 @@ fn structInitExpr(
15681568 _ = try gz.addUnNode(.validate_struct_init_ty, ty_inst, node);
15691569 return structInitExprRlTy(gz, scope, node, struct_init, ty_inst, .struct_init);
15701570 } else {
1571 return structInitExprRlNone(gz, scope, node, struct_init, .struct_init_anon);
1571 return structInitExprRlNone(gz, scope, node, struct_init, .none, .struct_init_anon);
15721572 }
15731573 },
15741574 .ty, .coerced_ty => |ty_inst| {
15751575 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);
15771578 }
15781579 const inner_ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
15791580 _ = try gz.addUnNode(.validate_struct_init_ty, inner_ty_inst, node);
......@@ -1586,7 +1587,7 @@ fn structInitExpr(
15861587 // We treat this case differently so that we don't get a crash when
15871588 // analyzing field_base_ptr against an alloc_inferred_mut.
15881589 // 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);
15901591 return rvalue(gz, rl, result, node);
15911592 } else {
15921593 return structInitExprRlPtr(gz, scope, rl, node, struct_init, ptr_inst);
......@@ -1596,7 +1597,7 @@ fn structInitExpr(
15961597 // This condition is here for the same reason as the above condition in `inferred_ptr`.
15971598 // See corresponding logic in arrayInitExpr.
15981599 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);
16001601 return rvalue(gz, rl, result, node);
16011602 }
16021603
......@@ -1610,6 +1611,7 @@ fn structInitExprRlNone(
16101611 scope: *Scope,
16111612 node: Ast.Node.Index,
16121613 struct_init: Ast.full.StructInit,
1614 ty_inst: Zir.Inst.Ref,
16131615 tag: Zir.Inst.Tag,
16141616) InnerError!Zir.Inst.Ref {
16151617 const astgen = gz.astgen;
......@@ -1624,9 +1626,16 @@ fn structInitExprRlNone(
16241626 for (struct_init.ast.fields) |field_init| {
16251627 const name_token = tree.firstToken(field_init) - 2;
16261628 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;
16271636 setExtra(astgen, extra_index, Zir.Inst.StructInitAnon.Item{
16281637 .field_name = str_index,
1629 .init = try expr(gz, scope, .none, field_init),
1638 .init = try expr(gz, scope, sub_rl, field_init),
16301639 });
16311640 extra_index += field_size;
16321641 }
......@@ -2350,6 +2359,7 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
23502359 .closure_get,
23512360 .array_base_ptr,
23522361 .field_base_ptr,
2362 .param_type,
23532363 => break :b false,
23542364
23552365 // ZIR instructions that are always `noreturn`.
......@@ -7846,10 +7856,15 @@ fn callExpr(
78467856 });
78477857 var extra_index = try reserveExtra(astgen, call.ast.params.len);
78487858
7849 for (call.ast.params) |param_node| {
7850 // Parameters are always temporary values, they have no
7851 // meaningful result location. Sema will coerce them.
7852 const arg_ref = try expr(gz, scope, .none, param_node);
7859 for (call.ast.params) |param_node, i| {
7860 const param_type = try gz.add(.{
7861 .tag = .param_type,
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);
78537868 astgen.extra.items[extra_index] = @enumToInt(arg_ref);
78547869 extra_index += 1;
78557870 }
src/Sema.zig+40-2
......@@ -738,6 +738,7 @@ fn analyzeBodyInner(
738738 .optional_payload_unsafe => try sema.zirOptionalPayload(block, inst, false),
739739 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, inst, false),
740740 .optional_type => try sema.zirOptionalType(block, inst),
741 .param_type => try sema.zirParamType(block, inst),
741742 .ptr_type => try sema.zirPtrType(block, inst),
742743 .ptr_type_simple => try sema.zirPtrTypeSimple(block, inst),
743744 .ref => try sema.zirRef(block, inst),
......@@ -3638,6 +3639,39 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
36383639 return sema.storePtr(block, src, ptr, operand);
36393640}
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
36413675fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
36423676 const tracy = trace(@src());
36433677 defer tracy.end();
......@@ -6613,6 +6647,7 @@ fn analyzeAs(
66136647) CompileError!Air.Inst.Ref {
66146648 const dest_ty = try sema.resolveType(block, src, zir_dest_type);
66156649 const operand = sema.resolveInst(zir_operand);
6650 if (dest_ty.tag() == .var_args_param) return operand;
66166651 return sema.coerce(block, dest_ty, operand, src);
66176652}
66186653
......@@ -12140,7 +12175,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1214012175fn unionInit(
1214112176 sema: *Sema,
1214212177 block: *Block,
12143 init: Air.Inst.Ref,
12178 uncasted_init: Air.Inst.Ref,
1214412179 init_src: LazySrcLoc,
1214512180 union_ty: Type,
1214612181 union_ty_src: LazySrcLoc,
......@@ -12148,6 +12183,8 @@ fn unionInit(
1214812183 field_src: LazySrcLoc,
1214912184) CompileError!Air.Inst.Ref {
1215012185 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
1215212189 if (try sema.resolveMaybeUndefVal(block, init_src, init)) |init_val| {
1215312190 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
1262012657 const ty_src = inst_data.src();
1262112658 const field_src = inst_data.src();
1262212659 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);
1262312661 const field_name = sema.code.nullTerminatedString(extra.name_start);
1262412662 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
1262512663}
......@@ -18964,7 +19002,7 @@ fn beginComptimePtrLoad(
1896419002 if (coerce_in_mem_ok) {
1896519003 deref.pointee = TypedValue{
1896619004 .ty = field_ty,
18967 .val = try tv.val.fieldValue(sema.arena, field_index),
19005 .val = tv.val.fieldValue(tv.ty, field_index),
1896819006 };
1896919007 break :blk deref;
1897019008 }
src/Zir.zig+15
......@@ -464,6 +464,14 @@ pub const Inst = struct {
464464 /// Merge two error sets into one, `E1 || E2`.
465465 /// Uses the `pl_node` field with payload `Bin`.
466466 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,
467475 /// Turns an R-Value into a const L-Value. In other words, it takes a value,
468476 /// stores it in a memory location, and returns a const pointer to it. If the value
469477 /// is `comptime`, the memory location is global static constant data. Otherwise,
......@@ -1077,6 +1085,7 @@ pub const Inst = struct {
10771085 .mul,
10781086 .mulwrap,
10791087 .mul_sat,
1088 .param_type,
10801089 .ref,
10811090 .shl,
10821091 .shl_sat,
......@@ -1266,6 +1275,7 @@ pub const Inst = struct {
12661275 .mulwrap = .pl_node,
12671276 .mul_sat = .pl_node,
12681277
1278 .param_type = .param_type,
12691279 .param = .pl_tok,
12701280 .param_comptime = .pl_tok,
12711281 .param_anytype = .str_tok,
......@@ -2213,6 +2223,10 @@ pub const Inst = struct {
22132223 /// Points to a `Block`.
22142224 payload_index: u32,
22152225 },
2226 param_type: struct {
2227 callee: Ref,
2228 param_index: u32,
2229 },
22162230 @"unreachable": struct {
22172231 /// Offset from Decl AST node index.
22182232 /// `Tag` determines which kind of AST node this points to.
......@@ -2288,6 +2302,7 @@ pub const Inst = struct {
22882302 ptr_type,
22892303 int_type,
22902304 bool_br,
2305 param_type,
22912306 @"unreachable",
22922307 @"break",
22932308 switch_capture,
src/print_zir.zig+11
......@@ -252,6 +252,7 @@ const Writer = struct {
252252 => try self.writeBoolBr(stream, inst),
253253
254254 .array_type_sentinel => try self.writeArrayTypeSentinel(stream, inst),
255 .param_type => try self.writeParamType(stream, inst),
255256 .ptr_type_simple => try self.writePtrTypeSimple(stream, inst),
256257 .ptr_type => try self.writePtrType(stream, inst),
257258 .int => try self.writeInt(stream, inst),
......@@ -558,6 +559,16 @@ const Writer = struct {
558559 try self.writeSrc(stream, inst_data.src());
559560 }
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
561572 fn writePtrTypeSimple(
562573 self: *Writer,
563574 stream: anytype,
src/type.zig+2
......@@ -3724,6 +3724,8 @@ pub const Type = extern union {
37243724 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
37253725 .pointer => ty.castTag(.pointer).?.data.pointee_type,
37263726
3727 .var_args_param => ty,
3728
37273729 else => unreachable,
37283730 };
37293731 }
src/value.zig+11-4
......@@ -2659,8 +2659,7 @@ pub const Value = extern union {
26592659 };
26602660 }
26612661
2662 pub fn fieldValue(val: Value, allocator: Allocator, index: usize) error{OutOfMemory}!Value {
2663 _ = allocator;
2662 pub fn fieldValue(val: Value, ty: Type, index: usize) Value {
26642663 switch (val.tag()) {
26652664 .aggregate => {
26662665 const field_values = val.castTag(.aggregate).?.data;
......@@ -2671,8 +2670,16 @@ pub const Value = extern union {
26712670 // TODO assert the tag is correct
26722671 return payload.val;
26732672 },
2674 // Structs which have only one possible value need to consist of members which have only one possible value.
2675 .the_only_possible_value => return val,
2673
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
26772684 else => unreachable,
26782685 }
test/behavior/call.zig+20
......@@ -98,3 +98,23 @@ test "comptime call with bound function as parameter" {
9898 var inst: S = undefined;
9999 try expectEqual(?i32, S.ReturnType(inst.call_me_maybe));
100100}
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}