authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-19 11:35:49+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-02-19 20:21:19+02:00
loge02749224357a33cffcaf9970d14c199adc3d892
tree90970730e6d00583eeb8789e035d1f1dd8edc466
parent2f0204aca303daf899a97c740719a62398adc206

stage2: support anon init through error unions and optionals


5 files changed, 183 insertions(+), 14 deletions(-)

src/AstGen.zig+7-2
...@@ -1384,7 +1384,8 @@ fn arrayInitExprRlPtr(...@@ -1384,7 +1384,8 @@ fn arrayInitExprRlPtr(
1384 array_ty: Zir.Inst.Ref,1384 array_ty: Zir.Inst.Ref,
1385) InnerError!Zir.Inst.Ref {1385) InnerError!Zir.Inst.Ref {
1386 if (array_ty == .none) {1386 if (array_ty == .none) {
1387 return arrayInitExprRlPtrInner(gz, scope, node, result_ptr, elements);1387 const base_ptr = try gz.addUnNode(.array_base_ptr, result_ptr, node);
1388 return arrayInitExprRlPtrInner(gz, scope, node, base_ptr, elements);
1388 }1389 }
13891390
1390 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr);1391 var as_scope = try gz.makeCoercionScope(scope, array_ty, result_ptr);
...@@ -1493,6 +1494,7 @@ fn structInitExpr(...@@ -1493,6 +1494,7 @@ fn structInitExpr(
14931494
1494 switch (rl) {1495 switch (rl) {
1495 .discard => {1496 .discard => {
1497 // TODO if a type expr is given the fields should be validated for that type
1496 if (struct_init.ast.type_expr != 0)1498 if (struct_init.ast.type_expr != 0)
1497 _ = try typeExpr(gz, scope, struct_init.ast.type_expr);1499 _ = try typeExpr(gz, scope, struct_init.ast.type_expr);
1498 for (struct_init.ast.fields) |field_init| {1500 for (struct_init.ast.fields) |field_init| {
...@@ -1567,7 +1569,8 @@ fn structInitExprRlPtr(...@@ -1567,7 +1569,8 @@ fn structInitExprRlPtr(
1567 result_ptr: Zir.Inst.Ref,1569 result_ptr: Zir.Inst.Ref,
1568) InnerError!Zir.Inst.Ref {1570) InnerError!Zir.Inst.Ref {
1569 if (struct_init.ast.type_expr == 0) {1571 if (struct_init.ast.type_expr == 0) {
1570 return structInitExprRlPtrInner(gz, scope, node, struct_init, result_ptr);1572 const base_ptr = try gz.addUnNode(.field_base_ptr, result_ptr, node);
1573 return structInitExprRlPtrInner(gz, scope, node, struct_init, base_ptr);
1571 }1574 }
1572 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);1575 const ty_inst = try typeExpr(gz, scope, struct_init.ast.type_expr);
15731576
...@@ -2281,6 +2284,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner...@@ -2281,6 +2284,8 @@ fn unusedResultExpr(gz: *GenZir, scope: *Scope, statement: Ast.Node.Index) Inner
2281 .ret_err_value_code,2284 .ret_err_value_code,
2282 .extended,2285 .extended,
2283 .closure_get,2286 .closure_get,
2287 .array_base_ptr,
2288 .field_base_ptr,
2284 => break :b false,2289 => break :b false,
22852290
2286 // ZIR instructions that are always `noreturn`.2291 // ZIR instructions that are always `noreturn`.
src/Sema.zig+97-12
...@@ -739,6 +739,8 @@ fn analyzeBodyInner(...@@ -739,6 +739,8 @@ fn analyzeBodyInner(
739 .@"await" => try sema.zirAwait(block, inst, false),739 .@"await" => try sema.zirAwait(block, inst, false),
740 .await_nosuspend => try sema.zirAwait(block, inst, true),740 .await_nosuspend => try sema.zirAwait(block, inst, true),
741 .extended => try sema.zirExtended(block, inst),741 .extended => try sema.zirExtended(block, inst),
742 .array_base_ptr => try sema.zirArrayBasePtr(block, inst),
743 .field_base_ptr => try sema.zirFieldBasePtr(block, inst),
742744
743 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),745 .clz => try sema.zirBitCount(block, inst, .clz, Value.clz),
744 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),746 .ctz => try sema.zirBitCount(block, inst, .ctz, Value.ctz),
...@@ -2584,6 +2586,59 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -2584,6 +2586,59 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
2584 }2586 }
2585}2587}
25862588
2589fn zirArrayBasePtr(
2590 sema: *Sema,
2591 block: *Block,
2592 inst: Zir.Inst.Index,
2593) CompileError!Air.Inst.Ref {
2594 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2595 const src = inst_data.src();
2596
2597 const start_ptr = sema.resolveInst(inst_data.operand);
2598 var base_ptr = start_ptr;
2599 while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
2600 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false),
2601 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false),
2602 else => break,
2603 };
2604
2605 const elem_ty = sema.typeOf(base_ptr).childType();
2606 switch (elem_ty.zigTypeTag()) {
2607 .Array, .Vector => return base_ptr,
2608 .Struct => if (elem_ty.isTuple()) return base_ptr,
2609 else => {},
2610 }
2611 return sema.fail(block, src, "type '{}' does not support array initialization syntax", .{
2612 sema.typeOf(start_ptr).childType(),
2613 });
2614}
2615
2616fn zirFieldBasePtr(
2617 sema: *Sema,
2618 block: *Block,
2619 inst: Zir.Inst.Index,
2620) CompileError!Air.Inst.Ref {
2621 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2622 const src = inst_data.src();
2623
2624 const start_ptr = sema.resolveInst(inst_data.operand);
2625 var base_ptr = start_ptr;
2626 while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
2627 .ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false),
2628 .Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false),
2629 else => break,
2630 };
2631
2632 const elem_ty = sema.typeOf(base_ptr).childType();
2633 switch (elem_ty.zigTypeTag()) {
2634 .Struct, .Union => return base_ptr,
2635 else => {},
2636 }
2637 return sema.fail(block, src, "type '{}' does not support struct initialization syntax", .{
2638 sema.typeOf(start_ptr).childType(),
2639 });
2640}
2641
2587fn zirValidateStructInit(2642fn zirValidateStructInit(
2588 sema: *Sema,2643 sema: *Sema,
2589 block: *Block,2644 block: *Block,
...@@ -4377,7 +4432,9 @@ fn analyzeCall(...@@ -4377,7 +4432,9 @@ fn analyzeCall(
4377 if (payload.data.error_set.tag() == .error_set_inferred) {4432 if (payload.data.error_set.tag() == .error_set_inferred) {
4378 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);4433 const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
4379 node.data = .{ .func = module_fn };4434 node.data = .{ .func = module_fn };
4380 parent_func.?.inferred_error_sets.prepend(node);4435 if (parent_func) |some| {
4436 some.inferred_error_sets.prepend(node);
4437 }
43814438
4382 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);4439 const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);
4383 break :blk try Type.Tag.error_union.create(sema.arena, .{4440 break :blk try Type.Tag.error_union.create(sema.arena, .{
...@@ -5198,9 +5255,20 @@ fn zirOptionalPayloadPtr(...@@ -5198,9 +5255,20 @@ fn zirOptionalPayloadPtr(
51985255
5199 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5256 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5200 const optional_ptr = sema.resolveInst(inst_data.operand);5257 const optional_ptr = sema.resolveInst(inst_data.operand);
5258 const src = inst_data.src();
5259
5260 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check);
5261}
5262
5263fn analyzeOptionalPayloadPtr(
5264 sema: *Sema,
5265 block: *Block,
5266 src: LazySrcLoc,
5267 optional_ptr: Air.Inst.Ref,
5268 safety_check: bool,
5269) CompileError!Air.Inst.Ref {
5201 const optional_ptr_ty = sema.typeOf(optional_ptr);5270 const optional_ptr_ty = sema.typeOf(optional_ptr);
5202 assert(optional_ptr_ty.zigTypeTag() == .Pointer);5271 assert(optional_ptr_ty.zigTypeTag() == .Pointer);
5203 const src = inst_data.src();
52045272
5205 const opt_type = optional_ptr_ty.elemType();5273 const opt_type = optional_ptr_ty.elemType();
5206 if (opt_type.zigTypeTag() != .Optional) {5274 if (opt_type.zigTypeTag() != .Optional) {
...@@ -5216,8 +5284,10 @@ fn zirOptionalPayloadPtr(...@@ -5216,8 +5284,10 @@ fn zirOptionalPayloadPtr(
52165284
5217 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| {5285 if (try sema.resolveDefinedValue(block, src, optional_ptr)) |pointer_val| {
5218 if (try sema.pointerDeref(block, src, pointer_val, optional_ptr_ty)) |val| {5286 if (try sema.pointerDeref(block, src, pointer_val, optional_ptr_ty)) |val| {
5219 if (val.isNull()) {5287 if (safety_check) {
5220 return sema.fail(block, src, "unable to unwrap null", .{});5288 if (val.isNull()) {
5289 return sema.fail(block, src, "unable to unwrap null", .{});
5290 }
5221 }5291 }
5222 // The same Value represents the pointer to the optional and the payload.5292 // The same Value represents the pointer to the optional and the payload.
5223 return sema.addConstant(5293 return sema.addConstant(
...@@ -5333,8 +5403,19 @@ fn zirErrUnionPayloadPtr(...@@ -5333,8 +5403,19 @@ fn zirErrUnionPayloadPtr(
5333 defer tracy.end();5403 defer tracy.end();
53345404
5335 const inst_data = sema.code.instructions.items(.data)[inst].un_node;5405 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
5336 const src = inst_data.src();
5337 const operand = sema.resolveInst(inst_data.operand);5406 const operand = sema.resolveInst(inst_data.operand);
5407 const src = inst_data.src();
5408
5409 return sema.analyzeErrUnionPayloadPtr(block, src, operand, safety_check);
5410}
5411
5412fn analyzeErrUnionPayloadPtr(
5413 sema: *Sema,
5414 block: *Block,
5415 src: LazySrcLoc,
5416 operand: Air.Inst.Ref,
5417 safety_check: bool,
5418) CompileError!Air.Inst.Ref {
5338 const operand_ty = sema.typeOf(operand);5419 const operand_ty = sema.typeOf(operand);
5339 assert(operand_ty.zigTypeTag() == .Pointer);5420 assert(operand_ty.zigTypeTag() == .Pointer);
53405421
...@@ -5350,9 +5431,12 @@ fn zirErrUnionPayloadPtr(...@@ -5350,9 +5431,12 @@ fn zirErrUnionPayloadPtr(
53505431
5351 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {5432 if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
5352 if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| {5433 if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| {
5353 if (val.getError()) |name| {5434 if (safety_check) {
5354 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});5435 if (val.getError()) |name| {
5436 return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
5437 }
5355 }5438 }
5439
5356 return sema.addConstant(5440 return sema.addConstant(
5357 operand_pointer_ty,5441 operand_pointer_ty,
5358 try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),5442 try Value.Tag.eu_payload_ptr.create(sema.arena, pointer_val),
...@@ -12859,7 +12943,7 @@ fn zirCUndef(...@@ -12859,7 +12943,7 @@ fn zirCUndef(
12859 extended: Zir.Inst.Extended.InstData,12943 extended: Zir.Inst.Extended.InstData,
12860) CompileError!Air.Inst.Ref {12944) CompileError!Air.Inst.Ref {
12861 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;12945 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
12862 const src: LazySrcLoc = .{ .node_offset = extra.node };12946 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
1286312947
12864 const name = try sema.resolveConstString(block, src, extra.operand);12948 const name = try sema.resolveConstString(block, src, extra.operand);
12865 try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name});12949 try block.c_import_buf.?.writer().print("#undefine {s}\n", .{name});
...@@ -12872,7 +12956,7 @@ fn zirCInclude(...@@ -12872,7 +12956,7 @@ fn zirCInclude(
12872 extended: Zir.Inst.Extended.InstData,12956 extended: Zir.Inst.Extended.InstData,
12873) CompileError!Air.Inst.Ref {12957) CompileError!Air.Inst.Ref {
12874 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;12958 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
12875 const src: LazySrcLoc = .{ .node_offset = extra.node };12959 const src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
1287612960
12877 const name = try sema.resolveConstString(block, src, extra.operand);12961 const name = try sema.resolveConstString(block, src, extra.operand);
12878 try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});12962 try block.c_import_buf.?.writer().print("#include <{s}>\n", .{name});
...@@ -12885,12 +12969,13 @@ fn zirCDefine(...@@ -12885,12 +12969,13 @@ fn zirCDefine(
12885 extended: Zir.Inst.Extended.InstData,12969 extended: Zir.Inst.Extended.InstData,
12886) CompileError!Air.Inst.Ref {12970) CompileError!Air.Inst.Ref {
12887 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;12971 const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
12888 const src: LazySrcLoc = .{ .node_offset = extra.node };12972 const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
12973 const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
1288912974
12890 const name = try sema.resolveConstString(block, src, extra.lhs);12975 const name = try sema.resolveConstString(block, name_src, extra.lhs);
12891 const rhs = sema.resolveInst(extra.rhs);12976 const rhs = sema.resolveInst(extra.rhs);
12892 if (sema.typeOf(rhs).zigTypeTag() != .Void) {12977 if (sema.typeOf(rhs).zigTypeTag() != .Void) {
12893 const value = try sema.resolveConstString(block, src, extra.rhs);12978 const value = try sema.resolveConstString(block, val_src, extra.rhs);
12894 try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });12979 try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });
12895 } else {12980 } else {
12896 try block.c_import_buf.?.writer().print("#define {s}\n", .{name});12981 try block.c_import_buf.?.writer().print("#define {s}\n", .{name});
src/Zir.zig+16
...@@ -643,6 +643,18 @@ pub const Inst = struct {...@@ -643,6 +643,18 @@ pub const Inst = struct {
643 /// Result is a pointer to the value.643 /// Result is a pointer to the value.
644 /// Uses the `switch_capture` field.644 /// Uses the `switch_capture` field.
645 switch_capture_multi_ref,645 switch_capture_multi_ref,
646 /// Given a
647 /// *A returns *A
648 /// *E!A returns *A
649 /// *?A returns *A
650 /// Uses the `un_node` field.
651 array_base_ptr,
652 /// Given a
653 /// *S returns *S
654 /// *E!S returns *S
655 /// *?S returns *S
656 /// Uses the `un_node` field.
657 field_base_ptr,
646 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct658 /// Given a set of `field_ptr` instructions, assumes they are all part of a struct
647 /// initialization expression, and emits compile errors for duplicate fields659 /// initialization expression, and emits compile errors for duplicate fields
648 /// as well as missing fields, if applicable.660 /// as well as missing fields, if applicable.
...@@ -1087,6 +1099,8 @@ pub const Inst = struct {...@@ -1087,6 +1099,8 @@ pub const Inst = struct {
1087 .switch_block,1099 .switch_block,
1088 .switch_cond,1100 .switch_cond,
1089 .switch_cond_ref,1101 .switch_cond_ref,
1102 .array_base_ptr,
1103 .field_base_ptr,
1090 .validate_struct_init,1104 .validate_struct_init,
1091 .validate_struct_init_comptime,1105 .validate_struct_init_comptime,
1092 .validate_array_init,1106 .validate_array_init,
...@@ -1340,6 +1354,8 @@ pub const Inst = struct {...@@ -1340,6 +1354,8 @@ pub const Inst = struct {
1340 .switch_capture_ref = .switch_capture,1354 .switch_capture_ref = .switch_capture,
1341 .switch_capture_multi = .switch_capture,1355 .switch_capture_multi = .switch_capture,
1342 .switch_capture_multi_ref = .switch_capture,1356 .switch_capture_multi_ref = .switch_capture,
1357 .array_base_ptr = .un_node,
1358 .field_base_ptr = .un_node,
1343 .validate_struct_init = .pl_node,1359 .validate_struct_init = .pl_node,
1344 .validate_struct_init_comptime = .pl_node,1360 .validate_struct_init_comptime = .pl_node,
1345 .validate_array_init = .pl_node,1361 .validate_array_init = .pl_node,
src/print_zir.zig+2
...@@ -235,6 +235,8 @@ const Writer = struct {...@@ -235,6 +235,8 @@ const Writer = struct {
235 .fence,235 .fence,
236 .switch_cond,236 .switch_cond,
237 .switch_cond_ref,237 .switch_cond_ref,
238 .array_base_ptr,
239 .field_base_ptr,
238 => try self.writeUnNode(stream, inst),240 => try self.writeUnNode(stream, inst),
239241
240 .ref,242 .ref,
test/behavior/struct.zig+61
...@@ -1199,3 +1199,64 @@ test "for loop over pointers to struct, getting field from struct pointer" {...@@ -1199,3 +1199,64 @@ test "for loop over pointers to struct, getting field from struct pointer" {
1199 };1199 };
1200 try S.doTheTest();1200 try S.doTheTest();
1201}1201}
1202
1203test "anon init through error unions and optionals" {
1204 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1205 if (true) return error.SkipZigTest; // TODO
1206
1207 const S = struct {
1208 a: u32,
1209
1210 fn foo() anyerror!?anyerror!@This() {
1211 return @This(){ .a = 1 };
1212 }
1213 fn bar() ?anyerror![2]u8 {
1214 return [2]u8{ 1, 2 };
1215 }
1216
1217 fn doTheTest() !void {
1218 var a = ((foo() catch unreachable).?) catch unreachable;
1219 var b = (bar().?) catch unreachable;
1220 try expect(a.a + b[1] == 3);
1221 }
1222 };
1223
1224 try S.doTheTest();
1225 comptime try S.doTheTest();
1226}
1227
1228test "anon init through optional" {
1229 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1230 // not sure why this is needed, we only do the test at comptime
1231 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
1232
1233 const S = struct {
1234 a: u32,
1235
1236 fn doTheTest() !void {
1237 var s: ?@This() = null;
1238 s = .{ .a = 1 };
1239 try expect(s.?.a == 1);
1240 }
1241 };
1242 // try S.doTheTest(); // TODO
1243 comptime try S.doTheTest();
1244}
1245
1246test "anon init through error union" {
1247 if (builtin.zig_backend == .stage1) return error.SkipZigTest;
1248 // not sure why this is needed, we only do the test at comptime
1249 if (builtin.zig_backend != .stage2_llvm) return error.SkipZigTest;
1250
1251 const S = struct {
1252 a: u32,
1253
1254 fn doTheTest() !void {
1255 var s: anyerror!@This() = error.Foo;
1256 s = .{ .a = 1 };
1257 try expect((try s).a == 1);
1258 }
1259 };
1260 // try S.doTheTest(); // TODO
1261 comptime try S.doTheTest();
1262}