authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2020-08-18 00:15:36+03:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2020-08-18 00:15:36+03:00
logd8fb377e2a5caf1ff6132b619a1b46d3b030496b
tree5c12cfe219de00ae1879fdce67544e70d5e263d1
parent624e643872130de5b6f6f1f120c8cf60a31f58e8
parent13b2f1e90ba9e373c655fc881836209c4fa381fa
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #6060 from Vexu/stage2

Stage2: more optionals stuff

7 files changed, 429 insertions(+), 148 deletions(-)

src-self-hosted/Module.zig+64-52
......@@ -2207,8 +2207,11 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
22072207 };
22082208
22092209 const decl_tv = try decl.typedValue();
2210 const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
2211 ty_payload.* = .{ .pointee_type = decl_tv.ty };
2210 const ty_payload = try scope.arena().create(Type.Payload.Pointer);
2211 ty_payload.* = .{
2212 .base = .{ .tag = .single_const_pointer },
2213 .pointee_type = decl_tv.ty,
2214 };
22122215 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
22132216 val_payload.* = .{ .decl = decl };
22142217
......@@ -2432,6 +2435,15 @@ pub fn cmpNumeric(
24322435 return self.addBinOp(b, src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
24332436}
24342437
2438fn wrapOptional(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2439 if (inst.value()) |val| {
2440 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2441 }
2442
2443 const b = try self.requireRuntimeBlock(scope, inst.src);
2444 return self.addUnOp(b, inst.src, dest_type, .wrap_optional, inst);
2445}
2446
24352447fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
24362448 if (signed) {
24372449 const int_payload = try scope.arena().create(Type.Payload.IntSigned);
......@@ -2509,14 +2521,12 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25092521
25102522 // T to ?T
25112523 if (dest_type.zigTypeTag() == .Optional) {
2512 const child_type = dest_type.elemType();
2513 if (inst.value()) |val| {
2514 if (child_type.eql(inst.ty)) {
2515 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2516 }
2517 return self.fail(scope, inst.src, "TODO optional wrap {} to {}", .{ val, dest_type });
2518 } else if (child_type.eql(inst.ty)) {
2519 return self.fail(scope, inst.src, "TODO optional wrap {}", .{dest_type});
2524 var buf: Type.Payload.Pointer = undefined;
2525 const child_type = dest_type.optionalChild(&buf);
2526 if (child_type.eql(inst.ty)) {
2527 return self.wrapOptional(scope, dest_type, inst);
2528 } else if (try self.coerceNum(scope, child_type, inst)) |some| {
2529 return self.wrapOptional(scope, dest_type, some);
25202530 }
25212531 }
25222532
......@@ -2534,39 +2544,8 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25342544 }
25352545
25362546 // comptime known number to other number
2537 if (inst.value()) |val| {
2538 const src_zig_tag = inst.ty.zigTypeTag();
2539 const dst_zig_tag = dest_type.zigTypeTag();
2540
2541 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
2542 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2543 if (val.floatHasFraction()) {
2544 return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
2545 }
2546 return self.fail(scope, inst.src, "TODO float to int", .{});
2547 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2548 if (!val.intFitsInType(dest_type, self.target())) {
2549 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
2550 }
2551 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2552 }
2553 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
2554 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2555 const res = val.floatCast(scope.arena(), dest_type, self.target()) catch |err| switch (err) {
2556 error.Overflow => return self.fail(
2557 scope,
2558 inst.src,
2559 "cast of value {} to type '{}' loses information",
2560 .{ val, dest_type },
2561 ),
2562 error.OutOfMemory => return error.OutOfMemory,
2563 };
2564 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = res });
2565 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2566 return self.fail(scope, inst.src, "TODO int to float", .{});
2567 }
2568 }
2569 }
2547 if (try self.coerceNum(scope, dest_type, inst)) |some|
2548 return some;
25702549
25712550 // integer widening
25722551 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
......@@ -2598,6 +2577,42 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25982577 return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
25992578}
26002579
2580pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !?*Inst {
2581 const val = inst.value() orelse return null;
2582 const src_zig_tag = inst.ty.zigTypeTag();
2583 const dst_zig_tag = dest_type.zigTypeTag();
2584
2585 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
2586 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2587 if (val.floatHasFraction()) {
2588 return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
2589 }
2590 return self.fail(scope, inst.src, "TODO float to int", .{});
2591 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2592 if (!val.intFitsInType(dest_type, self.target())) {
2593 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
2594 }
2595 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2596 }
2597 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
2598 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2599 const res = val.floatCast(scope.arena(), dest_type, self.target()) catch |err| switch (err) {
2600 error.Overflow => return self.fail(
2601 scope,
2602 inst.src,
2603 "cast of value {} to type '{}' loses information",
2604 .{ val, dest_type },
2605 ),
2606 error.OutOfMemory => return error.OutOfMemory,
2607 };
2608 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = res });
2609 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2610 return self.fail(scope, inst.src, "TODO int to float", .{});
2611 }
2612 }
2613 return null;
2614}
2615
26012616pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
26022617 if (ptr.ty.isConstPtr())
26032618 return self.fail(scope, src, "cannot assign to constant", .{});
......@@ -2885,15 +2900,12 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
28852900 return Value.initPayload(val_payload);
28862901}
28872902
2888pub fn singleMutPtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type) error{OutOfMemory}!Type {
2889 const type_payload = try scope.arena().create(Type.Payload.SingleMutPointer);
2890 type_payload.* = .{ .pointee_type = elem_ty };
2891 return Type.initPayload(&type_payload.base);
2892}
2893
2894pub fn singleConstPtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type) error{OutOfMemory}!Type {
2895 const type_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
2896 type_payload.* = .{ .pointee_type = elem_ty };
2903pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) error{OutOfMemory}!Type {
2904 const type_payload = try scope.arena().create(Type.Payload.Pointer);
2905 type_payload.* = .{
2906 .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer },
2907 .pointee_type = elem_ty,
2908 };
28972909 return Type.initPayload(&type_payload.base);
28982910}
28992911
src-self-hosted/astgen.zig+150-33
......@@ -113,6 +113,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
113113 .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)),
114114 .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)),
115115 .BoolNot => return rlWrap(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)),
116 .AddressOf => return rlWrap(mod, scope, rl, try addressOf(mod, scope, node.castTag(.AddressOf).?)),
116117 .FloatLiteral => return rlWrap(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)),
117118 .UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)),
118119 .BoolLiteral => return rlWrap(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)),
......@@ -122,6 +123,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
122123 .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)),
123124 .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?),
124125 .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)),
126 .PtrType => return rlWrap(mod, scope, rl, try ptrType(mod, scope, node.castTag(.PtrType).?)),
125127
126128 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
127129 .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),
......@@ -131,7 +133,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
131133 .MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}),
132134 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
133135 .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),
134 .AddressOf => return mod.failNode(scope, node, "TODO implement astgen.expr for .AddressOf", .{}),
135136 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
136137 .BitNot => return mod.failNode(scope, node, "TODO implement astgen.expr for .BitNot", .{}),
137138 .Negation => return mod.failNode(scope, node, "TODO implement astgen.expr for .Negation", .{}),
......@@ -140,7 +141,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
140141 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
141142 .ArrayType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayType", .{}),
142143 .ArrayTypeSentinel => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayTypeSentinel", .{}),
143 .PtrType => return mod.failNode(scope, node, "TODO implement astgen.expr for .PtrType", .{}),
144144 .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}),
145145 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
146146 .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),
......@@ -425,6 +425,10 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr
425425 return addZIRUnOp(mod, scope, src, .boolnot, operand);
426426}
427427
428fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
429 return expr(mod, scope, .lvalue, node.rhs);
430}
431
428432fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
429433 const tree = scope.tree();
430434 const src = tree.token_locs[node.op_token].start;
......@@ -436,6 +440,50 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn
436440 return addZIRUnOp(mod, scope, src, .optional_type, operand);
437441}
438442
443fn ptrType(mod: *Module, scope: *Scope, node: *ast.Node.PtrType) InnerError!*zir.Inst {
444 const tree = scope.tree();
445 const src = tree.token_locs[node.op_token].start;
446 const meta_type = try addZIRInstConst(mod, scope, src, .{
447 .ty = Type.initTag(.type),
448 .val = Value.initTag(.type_type),
449 });
450
451 const simple = node.ptr_info.allowzero_token == null and
452 node.ptr_info.align_info == null and
453 node.ptr_info.volatile_token == null and
454 node.ptr_info.sentinel == null;
455
456 if (simple) {
457 const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
458 return addZIRUnOp(mod, scope, src, if (node.ptr_info.const_token == null)
459 .single_mut_ptr_type
460 else
461 .single_const_ptr_type, child_type);
462 }
463
464 var kw_args: std.meta.fieldInfo(zir.Inst.PtrType, "kw_args").field_type = .{};
465 kw_args.@"allowzero" = node.ptr_info.allowzero_token != null;
466 if (node.ptr_info.align_info) |some| {
467 kw_args.@"align" = try expr(mod, scope, .none, some.node);
468 if (some.bit_range) |bit_range| {
469 kw_args.align_bit_start = try expr(mod, scope, .none, bit_range.start);
470 kw_args.align_bit_end = try expr(mod, scope, .none, bit_range.end);
471 }
472 }
473 kw_args.@"const" = node.ptr_info.const_token != null;
474 kw_args.@"volatile" = node.ptr_info.volatile_token != null;
475 if (node.ptr_info.sentinel) |some| {
476 kw_args.sentinel = try expr(mod, scope, .none, some);
477 }
478
479 const child_type = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
480 if (kw_args.sentinel) |some| {
481 kw_args.sentinel = try addZIRBinOp(mod, scope, some.src, .as, child_type, some);
482 }
483
484 return addZIRInst(mod, scope, src, zir.Inst.PtrType, .{ .child_type = child_type }, kw_args);
485}
486
439487fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
440488 const tree = scope.tree();
441489 const src = tree.token_locs[node.rtoken].start;
......@@ -520,13 +568,77 @@ fn simpleBinOp(
520568 return rlWrap(mod, scope, rl, result);
521569}
522570
523fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst {
524 if (if_node.payload) |payload| {
525 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{});
571const CondKind = union(enum) {
572 bool,
573 optional: ?*zir.Inst,
574 err_union: ?*zir.Inst,
575
576 fn cond(self: *CondKind, mod: *Module, block_scope: *Scope.GenZIR, src: usize, cond_node: *ast.Node) !*zir.Inst {
577 switch (self.*) {
578 .bool => {
579 const bool_type = try addZIRInstConst(mod, &block_scope.base, src, .{
580 .ty = Type.initTag(.type),
581 .val = Value.initTag(.bool_type),
582 });
583 return try expr(mod, &block_scope.base, .{ .ty = bool_type }, cond_node);
584 },
585 .optional => {
586 const cond_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);
587 self.* = .{ .optional = cond_ptr };
588 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, cond_ptr);
589 return try addZIRUnOp(mod, &block_scope.base, src, .isnonnull, result);
590 },
591 .err_union => {
592 const err_ptr = try expr(mod, &block_scope.base, .lvalue, cond_node);
593 self.* = .{ .err_union = err_ptr };
594 const result = try addZIRUnOp(mod, &block_scope.base, src, .deref, err_ptr);
595 return try addZIRUnOp(mod, &block_scope.base, src, .iserr, result);
596 },
597 }
526598 }
599
600 fn thenSubScope(self: CondKind, mod: *Module, then_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
601 if (self == .bool) return &then_scope.base;
602
603 const payload = payload_node.?.castTag(.PointerPayload).?;
604 const is_ptr = payload.ptr_token != null;
605 const ident_node = payload.value_symbol.castTag(.Identifier).?;
606
607 // This intentionally does not support @"_" syntax.
608 const ident_name = then_scope.base.tree().tokenSlice(ident_node.token);
609 if (mem.eql(u8, ident_name, "_")) {
610 if (is_ptr)
611 return mod.failTok(&then_scope.base, payload.ptr_token.?, "pointer modifier invalid on discard", .{});
612 return &then_scope.base;
613 }
614
615 return mod.failNode(&then_scope.base, payload.value_symbol, "TODO implement payload symbols", .{});
616 }
617
618 fn elseSubScope(self: CondKind, mod: *Module, else_scope: *Scope.GenZIR, src: usize, payload_node: ?*ast.Node) !*Scope {
619 if (self != .err_union) return &else_scope.base;
620
621 const payload_ptr = try addZIRUnOp(mod, &else_scope.base, src, .unwrap_err_unsafe, self.err_union.?);
622
623 const payload = payload_node.?.castTag(.Payload).?;
624 const ident_node = payload.error_symbol.castTag(.Identifier).?;
625
626 // This intentionally does not support @"_" syntax.
627 const ident_name = else_scope.base.tree().tokenSlice(ident_node.token);
628 if (mem.eql(u8, ident_name, "_")) {
629 return &else_scope.base;
630 }
631
632 return mod.failNode(&else_scope.base, payload.error_symbol, "TODO implement payload symbols", .{});
633 }
634};
635
636fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst {
637 var cond_kind: CondKind = .bool;
638 if (if_node.payload) |_| cond_kind = .{ .optional = null };
527639 if (if_node.@"else") |else_node| {
528640 if (else_node.payload) |payload| {
529 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for error unions", .{});
641 cond_kind = .{ .err_union = null };
530642 }
531643 }
532644 var block_scope: Scope.GenZIR = .{
......@@ -539,11 +651,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
539651
540652 const tree = scope.tree();
541653 const if_src = tree.token_locs[if_node.if_token].start;
542 const bool_type = try addZIRInstConst(mod, scope, if_src, .{
543 .ty = Type.initTag(.type),
544 .val = Value.initTag(.bool_type),
545 });
546 const cond = try expr(mod, &block_scope.base, .{ .ty = bool_type }, if_node.condition);
654 const cond = try cond_kind.cond(mod, &block_scope, if_src, if_node.condition);
547655
548656 const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{
549657 .condition = cond,
......@@ -554,6 +662,8 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
554662 const block = try addZIRInstBlock(mod, scope, if_src, .{
555663 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
556664 });
665
666 const then_src = tree.token_locs[if_node.body.lastToken()].start;
557667 var then_scope: Scope.GenZIR = .{
558668 .parent = scope,
559669 .decl = block_scope.decl,
......@@ -562,6 +672,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
562672 };
563673 defer then_scope.instructions.deinit(mod.gpa);
564674
675 // declare payload to the then_scope
676 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, if_node.payload);
677
565678 // Most result location types can be forwarded directly; however
566679 // if we need to write to a pointer which has an inferred type,
567680 // proper type inference requires peer type resolution on the if's
......@@ -571,10 +684,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
571684 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
572685 };
573686
574 const then_result = try expr(mod, &then_scope.base, branch_rl, if_node.body);
687 const then_result = try expr(mod, then_sub_scope, branch_rl, if_node.body);
575688 if (!then_result.tag.isNoReturn()) {
576 const then_src = tree.token_locs[if_node.body.lastToken()].start;
577 _ = try addZIRInst(mod, &then_scope.base, then_src, zir.Inst.Break, .{
689 _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
578690 .block = block,
579691 .operand = then_result,
580692 }, .{});
......@@ -592,10 +704,13 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
592704 defer else_scope.instructions.deinit(mod.gpa);
593705
594706 if (if_node.@"else") |else_node| {
595 const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body);
707 const else_src = tree.token_locs[else_node.body.lastToken()].start;
708 // declare payload to the then_scope
709 const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload);
710
711 const else_result = try expr(mod, else_sub_scope, branch_rl, else_node.body);
596712 if (!else_result.tag.isNoReturn()) {
597 const else_src = tree.token_locs[else_node.body.lastToken()].start;
598 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{
713 _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{
599714 .block = block,
600715 .operand = else_result,
601716 }, .{});
......@@ -616,12 +731,11 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
616731}
617732
618733fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst {
619 if (while_node.payload) |payload| {
620 return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for optionals", .{});
621 }
734 var cond_kind: CondKind = .bool;
735 if (while_node.payload) |_| cond_kind = .{ .optional = null };
622736 if (while_node.@"else") |else_node| {
623737 if (else_node.payload) |payload| {
624 return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for error unions", .{});
738 cond_kind = .{ .err_union = null };
625739 }
626740 }
627741
......@@ -651,15 +765,11 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
651765
652766 const tree = scope.tree();
653767 const while_src = tree.token_locs[while_node.while_token].start;
654 const bool_type = try addZIRInstConst(mod, scope, while_src, .{
655 .ty = Type.initTag(.type),
656 .val = Value.initTag(.bool_type),
657 });
658768 const void_type = try addZIRInstConst(mod, scope, while_src, .{
659769 .ty = Type.initTag(.type),
660770 .val = Value.initTag(.void_type),
661771 });
662 const cond = try expr(mod, &continue_scope.base, .{ .ty = bool_type }, while_node.condition);
772 const cond = try cond_kind.cond(mod, &continue_scope, while_src, while_node.condition);
663773
664774 const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{
665775 .condition = cond,
......@@ -682,6 +792,8 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
682792 const while_block = try addZIRInstBlock(mod, scope, while_src, .{
683793 .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items),
684794 });
795
796 const then_src = tree.token_locs[while_node.body.lastToken()].start;
685797 var then_scope: Scope.GenZIR = .{
686798 .parent = &continue_scope.base,
687799 .decl = continue_scope.decl,
......@@ -690,6 +802,9 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
690802 };
691803 defer then_scope.instructions.deinit(mod.gpa);
692804
805 // declare payload to the then_scope
806 const then_sub_scope = try cond_kind.thenSubScope(mod, &then_scope, then_src, while_node.payload);
807
693808 // Most result location types can be forwarded directly; however
694809 // if we need to write to a pointer which has an inferred type,
695810 // proper type inference requires peer type resolution on the while's
......@@ -699,10 +814,9 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
699814 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },
700815 };
701816
702 const then_result = try expr(mod, &then_scope.base, branch_rl, while_node.body);
817 const then_result = try expr(mod, then_sub_scope, branch_rl, while_node.body);
703818 if (!then_result.tag.isNoReturn()) {
704 const then_src = tree.token_locs[while_node.body.lastToken()].start;
705 _ = try addZIRInst(mod, &then_scope.base, then_src, zir.Inst.Break, .{
819 _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
706820 .block = cond_block,
707821 .operand = then_result,
708822 }, .{});
......@@ -720,10 +834,13 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
720834 defer else_scope.instructions.deinit(mod.gpa);
721835
722836 if (while_node.@"else") |else_node| {
723 const else_result = try expr(mod, &else_scope.base, branch_rl, else_node.body);
837 const else_src = tree.token_locs[else_node.body.lastToken()].start;
838 // declare payload to the then_scope
839 const else_sub_scope = try cond_kind.elseSubScope(mod, &else_scope, else_src, else_node.payload);
840
841 const else_result = try expr(mod, else_sub_scope, branch_rl, else_node.body);
724842 if (!else_result.tag.isNoReturn()) {
725 const else_src = tree.token_locs[else_node.body.lastToken()].start;
726 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{
843 _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{
727844 .block = while_block,
728845 .operand = else_result,
729846 }, .{});
......@@ -796,7 +913,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
796913 const int_type_payload = try scope.arena().create(Value.Payload.IntType);
797914 int_type_payload.* = .{ .signed = is_signed, .bits = bit_count };
798915 const result = try addZIRInstConst(mod, scope, src, .{
799 .ty = Type.initTag(.comptime_int),
916 .ty = Type.initTag(.type),
800917 .val = Value.initPayload(&int_type_payload.base),
801918 });
802919 return rlWrap(mod, scope, rl, result);
src-self-hosted/codegen.zig+42-3
......@@ -671,6 +671,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
671671 .intcast => return self.genIntCast(inst.castTag(.intcast).?),
672672 .isnonnull => return self.genIsNonNull(inst.castTag(.isnonnull).?),
673673 .isnull => return self.genIsNull(inst.castTag(.isnull).?),
674 .iserr => return self.genIsErr(inst.castTag(.iserr).?),
674675 .load => return self.genLoad(inst.castTag(.load).?),
675676 .loop => return self.genLoop(inst.castTag(.loop).?),
676677 .not => return self.genNot(inst.castTag(.not).?),
......@@ -682,6 +683,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
682683 .sub => return self.genSub(inst.castTag(.sub).?),
683684 .unreach => return MCValue{ .unreach = {} },
684685 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
686 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
685687 }
686688 }
687689
......@@ -840,6 +842,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
840842 }
841843 }
842844
845 fn genWrapOptional(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
846 const optional_ty = inst.base.ty;
847
848 // No side effects, so if it's unreferenced, do nothing.
849 if (inst.base.isUnused())
850 return MCValue.dead;
851
852 // Optional type is just a boolean true
853 if (optional_ty.abiSize(self.target.*) == 1)
854 return MCValue{ .immediate = 1 };
855
856 switch (arch) {
857 else => return self.fail(inst.base.src, "TODO implement wrap optional for {}", .{self.target.cpu.arch}),
858 }
859 }
860
843861 fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
844862 const elem_ty = inst.base.ty;
845863 if (!elem_ty.hasCodeGenBits())
......@@ -1374,6 +1392,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
13741392 }
13751393 }
13761394
1395 fn genIsErr(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
1396 switch (arch) {
1397 else => return self.fail(inst.base.src, "TODO implement iserr for {}", .{self.target.cpu.arch}),
1398 }
1399 }
1400
13771401 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {
13781402 // A loop is a setup to be able to jump back to the beginning.
13791403 const start_index = self.code.items.len;
......@@ -2028,9 +2052,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20282052 return mcv;
20292053 }
20302054
2031 fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) !MCValue {
2055 fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) InnerError!MCValue {
20322056 if (typed_value.val.isUndef())
2033 return MCValue.undef;
2057 return MCValue{ .undef = {} };
20342058 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
20352059 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
20362060 switch (typed_value.ty.zigTypeTag()) {
......@@ -2055,6 +2079,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
20552079 },
20562080 .ComptimeInt => unreachable, // semantic analysis prevents this
20572081 .ComptimeFloat => unreachable, // semantic analysis prevents this
2082 .Optional => {
2083 if (typed_value.ty.isPtrLikeOptional()) {
2084 if (typed_value.val.isNull())
2085 return MCValue{ .immediate = 0 };
2086
2087 var buf: Type.Payload.Pointer = undefined;
2088 return self.genTypedValue(src, .{
2089 .ty = typed_value.ty.optionalChild(&buf),
2090 .val = typed_value.val,
2091 });
2092 } else if (typed_value.ty.abiSize(self.target.*) == 1) {
2093 return MCValue{ .immediate = @boolToInt(typed_value.val.isNull()) };
2094 }
2095 return self.fail(src, "TODO non pointer optionals", .{});
2096 },
20582097 else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),
20592098 }
20602099 }
......@@ -2160,7 +2199,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
21602199 };
21612200 }
21622201
2163 fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) error{ CodegenFail, OutOfMemory } {
2202 fn fail(self: *Self, src: usize, comptime format: []const u8, args: anytype) InnerError {
21642203 @setCold(true);
21652204 assert(self.err_msg == null);
21662205 self.err_msg = try ErrorMsg.create(self.bin_file.base.allocator, src, format, args);
src-self-hosted/ir.zig+4
......@@ -68,6 +68,7 @@ pub const Inst = struct {
6868 dbg_stmt,
6969 isnonnull,
7070 isnull,
71 iserr,
7172 /// Read a value from a pointer.
7273 load,
7374 loop,
......@@ -83,6 +84,7 @@ pub const Inst = struct {
8384 floatcast,
8485 intcast,
8586 unwrap_optional,
87 wrap_optional,
8688
8789 pub fn Type(tag: Tag) type {
8890 return switch (tag) {
......@@ -99,11 +101,13 @@ pub const Inst = struct {
99101 .not,
100102 .isnonnull,
101103 .isnull,
104 .iserr,
102105 .ptrtoint,
103106 .floatcast,
104107 .intcast,
105108 .load,
106109 .unwrap_optional,
110 .wrap_optional,
107111 => UnOp,
108112
109113 .add,
src-self-hosted/type.zig+100-46
......@@ -107,6 +107,17 @@ pub const Type = extern union {
107107 return @fieldParentPtr(T, "base", self.ptr_otherwise);
108108 }
109109
110 pub fn castPointer(self: Type) ?*Payload.Pointer {
111 return switch (self.tag()) {
112 .single_const_pointer,
113 .single_mut_pointer,
114 .optional_single_const_pointer,
115 .optional_single_mut_pointer,
116 => @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise),
117 else => null,
118 };
119 }
120
110121 pub fn eql(a: Type, b: Type) bool {
111122 // As a shortcut, if the small tags / addresses match, we're done.
112123 if (a.tag_if_small_enough == b.tag_if_small_enough)
......@@ -126,8 +137,8 @@ pub const Type = extern union {
126137 .Null => return true,
127138 .Pointer => {
128139 // Hot path for common case:
129 if (a.cast(Payload.SingleConstPointer)) |a_payload| {
130 if (b.cast(Payload.SingleConstPointer)) |b_payload| {
140 if (a.castPointer()) |a_payload| {
141 if (b.castPointer()) |b_payload| {
131142 return eql(a_payload.pointee_type, b_payload.pointee_type);
132143 }
133144 }
......@@ -185,7 +196,9 @@ pub const Type = extern union {
185196 return true;
186197 },
187198 .Optional => {
188 return a.elemType().eql(b.elemType());
199 var buf_a: Payload.Pointer = undefined;
200 var buf_b: Payload.Pointer = undefined;
201 return a.optionalChild(&buf_a).eql(b.optionalChild(&buf_b));
189202 },
190203 .Float,
191204 .Struct,
......@@ -249,7 +262,8 @@ pub const Type = extern union {
249262 }
250263 },
251264 .Optional => {
252 std.hash.autoHash(&hasher, self.elemType().hash());
265 var buf: Payload.Pointer = undefined;
266 std.hash.autoHash(&hasher, self.optionalChild(&buf).hash());
253267 },
254268 .Float,
255269 .Struct,
......@@ -326,8 +340,6 @@ pub const Type = extern union {
326340 };
327341 return Type{ .ptr_otherwise = &new_payload.base };
328342 },
329 .single_const_pointer => return self.copyPayloadSingleField(allocator, Payload.SingleConstPointer, "pointee_type"),
330 .single_mut_pointer => return self.copyPayloadSingleField(allocator, Payload.SingleMutPointer, "pointee_type"),
331343 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
332344 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
333345 .function => {
......@@ -346,8 +358,11 @@ pub const Type = extern union {
346358 return Type{ .ptr_otherwise = &new_payload.base };
347359 },
348360 .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"),
349 .optional_single_mut_pointer => return self.copyPayloadSingleField(allocator, Payload.OptionalSingleMutPointer, "pointee_type"),
350 .optional_single_const_pointer => return self.copyPayloadSingleField(allocator, Payload.OptionalSingleConstPointer, "pointee_type"),
361 .single_const_pointer,
362 .single_mut_pointer,
363 .optional_single_mut_pointer,
364 .optional_single_const_pointer,
365 => return self.copyPayloadSingleField(allocator, Payload.Pointer, "pointee_type"),
351366 }
352367 }
353368
......@@ -441,13 +456,13 @@ pub const Type = extern union {
441456 continue;
442457 },
443458 .single_const_pointer => {
444 const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", ty.ptr_otherwise);
459 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
445460 try out_stream.writeAll("*const ");
446461 ty = payload.pointee_type;
447462 continue;
448463 },
449464 .single_mut_pointer => {
450 const payload = @fieldParentPtr(Payload.SingleMutPointer, "base", ty.ptr_otherwise);
465 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
451466 try out_stream.writeAll("*");
452467 ty = payload.pointee_type;
453468 continue;
......@@ -467,13 +482,13 @@ pub const Type = extern union {
467482 continue;
468483 },
469484 .optional_single_const_pointer => {
470 const payload = @fieldParentPtr(Payload.OptionalSingleConstPointer, "base", ty.ptr_otherwise);
485 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
471486 try out_stream.writeAll("?*const ");
472487 ty = payload.pointee_type;
473488 continue;
474489 },
475490 .optional_single_mut_pointer => {
476 const payload = @fieldParentPtr(Payload.OptionalSingleMutPointer, "base", ty.ptr_otherwise);
491 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
477492 try out_stream.writeAll("?*");
478493 ty = payload.pointee_type;
479494 continue;
......@@ -658,7 +673,8 @@ pub const Type = extern union {
658673 },
659674
660675 .optional => {
661 const child_type = self.cast(Payload.Optional).?.child_type;
676 var buf: Payload.Pointer = undefined;
677 const child_type = self.optionalChild(&buf);
662678 if (!child_type.hasCodeGenBits()) return 1;
663679
664680 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
......@@ -750,7 +766,8 @@ pub const Type = extern union {
750766 },
751767
752768 .optional => {
753 const child_type = self.cast(Payload.Optional).?.child_type;
769 var buf: Payload.Pointer = undefined;
770 const child_type = self.optionalChild(&buf);
754771 if (!child_type.hasCodeGenBits()) return 1;
755772
756773 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
......@@ -990,7 +1007,23 @@ pub const Type = extern union {
9901007 };
9911008 }
9921009
993 /// Asserts the type is a pointer, optional or array type.
1010 /// Asserts that the type is an optional
1011 pub fn isPtrLikeOptional(self: Type) bool {
1012 switch (self.tag()) {
1013 .optional_single_const_pointer, .optional_single_mut_pointer => return true,
1014 .optional => {
1015 var buf: Payload.Pointer = undefined;
1016 const child_type = self.optionalChild(&buf);
1017 // optionals of zero sized pointers behave like bools
1018 if (!child_type.hasCodeGenBits()) return false;
1019
1020 return child_type.zigTypeTag() == .Pointer and !child_type.isCPtr();
1021 },
1022 else => unreachable,
1023 }
1024 }
1025
1026 /// Asserts the type is a pointer or array type.
9941027 pub fn elemType(self: Type) Type {
9951028 return switch (self.tag()) {
9961029 .u8,
......@@ -1033,16 +1066,60 @@ pub const Type = extern union {
10331066 .function,
10341067 .int_unsigned,
10351068 .int_signed,
1069 .optional,
1070 .optional_single_const_pointer,
1071 .optional_single_mut_pointer,
10361072 => unreachable,
10371073
10381074 .array => self.cast(Payload.Array).?.elem_type,
1039 .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type,
1040 .single_mut_pointer => self.cast(Payload.SingleMutPointer).?.pointee_type,
1075 .single_const_pointer => self.castPointer().?.pointee_type,
1076 .single_mut_pointer => self.castPointer().?.pointee_type,
10411077 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
10421078 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
1079 };
1080 }
1081
1082 /// Asserts that the type is an optional.
1083 pub fn optionalChild(self: Type, buf: *Payload.Pointer) Type {
1084 return switch (self.tag()) {
10431085 .optional => self.cast(Payload.Optional).?.child_type,
1044 .optional_single_mut_pointer => self.cast(Payload.OptionalSingleMutPointer).?.pointee_type,
1045 .optional_single_const_pointer => self.cast(Payload.OptionalSingleConstPointer).?.pointee_type,
1086 .optional_single_mut_pointer => {
1087 buf.* = .{
1088 .base = .{ .tag = .single_mut_pointer },
1089 .pointee_type = self.castPointer().?.pointee_type,
1090 };
1091 return Type.initPayload(&buf.base);
1092 },
1093 .optional_single_const_pointer => {
1094 buf.* = .{
1095 .base = .{ .tag = .single_const_pointer },
1096 .pointee_type = self.castPointer().?.pointee_type,
1097 };
1098 return Type.initPayload(&buf.base);
1099 },
1100 else => unreachable,
1101 };
1102 }
1103
1104 /// Asserts that the type is an optional.
1105 /// Same as `optionalChild` but allocates the buffer if needed.
1106 pub fn optionalChildAlloc(self: Type, allocator: *Allocator) !Type {
1107 return switch (self.tag()) {
1108 .optional => self.cast(Payload.Optional).?.child_type,
1109 .optional_single_mut_pointer, .optional_single_const_pointer => {
1110 const payload = try allocator.create(Payload.Pointer);
1111 payload.* = .{
1112 .base = .{
1113 .tag = if (self.tag() == .optional_single_const_pointer)
1114 .single_const_pointer
1115 else
1116 .single_mut_pointer,
1117 },
1118 .pointee_type = self.castPointer().?.pointee_type,
1119 };
1120 return Type.initPayload(&payload.base);
1121 },
1122 else => unreachable,
10461123 };
10471124 }
10481125
......@@ -1901,13 +1978,8 @@ pub const Type = extern union {
19011978 ty = array.elem_type;
19021979 continue;
19031980 },
1904 .single_const_pointer => {
1905 const ptr = ty.cast(Payload.SingleConstPointer).?;
1906 ty = ptr.pointee_type;
1907 continue;
1908 },
1909 .single_mut_pointer => {
1910 const ptr = ty.cast(Payload.SingleMutPointer).?;
1981 .single_const_pointer, .single_mut_pointer => {
1982 const ptr = ty.castPointer().?;
19111983 ty = ptr.pointee_type;
19121984 continue;
19131985 },
......@@ -2049,14 +2121,8 @@ pub const Type = extern union {
20492121 len: u64,
20502122 };
20512123
2052 pub const SingleConstPointer = struct {
2053 base: Payload = Payload{ .tag = .single_const_pointer },
2054
2055 pointee_type: Type,
2056 };
2057
2058 pub const SingleMutPointer = struct {
2059 base: Payload = Payload{ .tag = .single_mut_pointer },
2124 pub const Pointer = struct {
2125 base: Payload,
20602126
20612127 pointee_type: Type,
20622128 };
......@@ -2086,18 +2152,6 @@ pub const Type = extern union {
20862152
20872153 child_type: Type,
20882154 };
2089
2090 pub const OptionalSingleConstPointer = struct {
2091 base: Payload = Payload{ .tag = .optional_single_const_pointer },
2092
2093 pointee_type: Type,
2094 };
2095
2096 pub const OptionalSingleMutPointer = struct {
2097 base: Payload = Payload{ .tag = .optional_single_mut_pointer },
2098
2099 pointee_type: Type,
2100 };
21012155 };
21022156};
21032157
src-self-hosted/zir.zig+38-1
......@@ -151,6 +151,8 @@ pub const Inst = struct {
151151 isnonnull,
152152 /// Return a boolean true if an optional is null. `x == null`
153153 isnull,
154 /// Return a boolean true if value is an error
155 iserr,
154156 /// A labeled block of code that loops forever. At the end of the body it is implied
155157 /// to repeat; no explicit "repeat" instruction terminates loop bodies.
156158 loop,
......@@ -192,6 +194,8 @@ pub const Inst = struct {
192194 single_const_ptr_type,
193195 /// Create a mutable pointer type based on the element type. `*T`
194196 single_mut_ptr_type,
197 /// Create a pointer type with attributes
198 ptr_type,
195199 /// Write a value to a pointer. For loading, see `deref`.
196200 store,
197201 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
......@@ -217,6 +221,10 @@ pub const Inst = struct {
217221 unwrap_optional_safe,
218222 /// Same as previous, but without safety checks. Used for orelse, if and while
219223 unwrap_optional_unsafe,
224 /// Gets the payload of an error union
225 unwrap_err_safe,
226 /// Same as previous, but without safety checks. Used for orelse, if and while
227 unwrap_err_unsafe,
220228
221229 pub fn Type(tag: Tag) type {
222230 return switch (tag) {
......@@ -235,6 +243,7 @@ pub const Inst = struct {
235243 .@"return",
236244 .isnull,
237245 .isnonnull,
246 .iserr,
238247 .ptrtoint,
239248 .alloc,
240249 .ensure_result_used,
......@@ -248,6 +257,8 @@ pub const Inst = struct {
248257 .optional_type,
249258 .unwrap_optional_safe,
250259 .unwrap_optional_unsafe,
260 .unwrap_err_safe,
261 .unwrap_err_unsafe,
251262 => UnOp,
252263
253264 .add,
......@@ -305,6 +316,7 @@ pub const Inst = struct {
305316 .fntype => FnType,
306317 .elemptr => ElemPtr,
307318 .condbr => CondBr,
319 .ptr_type => PtrType,
308320 };
309321 }
310322
......@@ -360,6 +372,7 @@ pub const Inst = struct {
360372 .inttype,
361373 .isnonnull,
362374 .isnull,
375 .iserr,
363376 .mod_rem,
364377 .mul,
365378 .mulwrap,
......@@ -382,6 +395,9 @@ pub const Inst = struct {
382395 .optional_type,
383396 .unwrap_optional_safe,
384397 .unwrap_optional_unsafe,
398 .unwrap_err_safe,
399 .unwrap_err_unsafe,
400 .ptr_type,
385401 => false,
386402
387403 .@"break",
......@@ -811,6 +827,24 @@ pub const Inst = struct {
811827 },
812828 kw_args: struct {},
813829 };
830
831 pub const PtrType = struct {
832 pub const base_tag = Tag.ptr_type;
833 base: Inst,
834
835 positionals: struct {
836 child_type: *Inst,
837 },
838 kw_args: struct {
839 @"allowzero": bool = false,
840 @"align": ?*Inst = null,
841 align_bit_start: ?*Inst = null,
842 align_bit_end: ?*Inst = null,
843 @"const": bool = true,
844 @"volatile": bool = false,
845 sentinel: ?*Inst = null,
846 },
847 };
814848};
815849
816850pub const ErrorMsg = struct {
......@@ -1992,9 +2026,11 @@ const EmitZIR = struct {
19922026 .ptrtoint => try self.emitUnOp(inst.src, new_body, inst.castTag(.ptrtoint).?, .ptrtoint),
19932027 .isnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnull).?, .isnull),
19942028 .isnonnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnonnull).?, .isnonnull),
2029 .iserr => try self.emitUnOp(inst.src, new_body, inst.castTag(.iserr).?, .iserr),
19952030 .load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref),
19962031 .ref => try self.emitUnOp(inst.src, new_body, inst.castTag(.ref).?, .ref),
19972032 .unwrap_optional => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional).?, .unwrap_optional_unsafe),
2033 .wrap_optional => try self.emitCast(inst.src, new_body, inst.castTag(.wrap_optional).?, .as),
19982034
19992035 .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add),
20002036 .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub),
......@@ -2338,6 +2374,7 @@ const EmitZIR = struct {
23382374 }
23392375 },
23402376 .Optional => {
2377 var buf: Type.Payload.Pointer = undefined;
23412378 const inst = try self.arena.allocator.create(Inst.UnOp);
23422379 inst.* = .{
23432380 .base = .{
......@@ -2345,7 +2382,7 @@ const EmitZIR = struct {
23452382 .tag = .optional_type,
23462383 },
23472384 .positionals = .{
2348 .operand = (try self.emitType(src, ty.elemType())).inst,
2385 .operand = (try self.emitType(src, ty.optionalChild(&buf))).inst,
23492386 },
23502387 .kw_args = .{},
23512388 };
src-self-hosted/zir_sema.zig+31-13
......@@ -53,6 +53,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
5353 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),
5454 .single_const_ptr_type => return analyzeInstSingleConstPtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?),
5555 .single_mut_ptr_type => return analyzeInstSingleMutPtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?),
56 .ptr_type => return analyzeInstPtrType(mod, scope, old_inst.castTag(.ptr_type).?),
5657 .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?),
5758 .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?),
5859 .int => {
......@@ -103,11 +104,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
103104 .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?),
104105 .isnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnull).?, true),
105106 .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false),
107 .iserr => return analyzeInstIsErr(mod, scope, old_inst.castTag(.iserr).?, true),
106108 .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),
107109 .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),
108110 .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
109111 .unwrap_optional_safe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_safe).?, true),
110112 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),
113 .unwrap_err_safe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_safe).?, true),
114 .unwrap_err_unsafe => return analyzeInstUnwrapErr(mod, scope, old_inst.castTag(.unwrap_err_unsafe).?, false),
111115 }
112116}
113117
......@@ -316,7 +320,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr
316320
317321fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
318322 const operand = try resolveInst(mod, scope, inst.positionals.operand);
319 const ptr_type = try mod.singleConstPtrType(scope, inst.base.src, operand.ty);
323 const ptr_type = try mod.singlePtrType(scope, inst.base.src, false, operand.ty);
320324
321325 if (operand.value()) |val| {
322326 const ref_payload = try scope.arena().create(Value.Payload.RefVal);
......@@ -357,7 +361,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
357361
358362fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
359363 const var_type = try resolveType(mod, scope, inst.positionals.operand);
360 const ptr_type = try mod.singleMutPtrType(scope, inst.base.src, var_type);
364 const ptr_type = try mod.singlePtrType(scope, inst.base.src, true, var_type);
361365 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
362366 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
363367}
......@@ -673,15 +677,17 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp
673677
674678 return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) {
675679 .single_const_pointer => blk: {
676 const payload = try scope.arena().create(Type.Payload.OptionalSingleConstPointer);
680 const payload = try scope.arena().create(Type.Payload.Pointer);
677681 payload.* = .{
682 .base = .{ .tag = .optional_single_const_pointer },
678683 .pointee_type = child_type.elemType(),
679684 };
680685 break :blk &payload.base;
681686 },
682687 .single_mut_pointer => blk: {
683 const payload = try scope.arena().create(Type.Payload.OptionalSingleMutPointer);
688 const payload = try scope.arena().create(Type.Payload.Pointer);
684689 payload.* = .{
690 .base = .{ .tag = .optional_single_mut_pointer },
685691 .pointee_type = child_type.elemType(),
686692 };
687693 break :blk &payload.base;
......@@ -704,11 +710,8 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
704710 return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{operand.ty.elemType()});
705711 }
706712
707 const child_type = operand.ty.elemType().elemType();
708 const child_pointer = if (operand.ty.isConstPtr())
709 try mod.singleConstPtrType(scope, unwrap.base.src, child_type)
710 else
711 try mod.singleMutPtrType(scope, unwrap.base.src, child_type);
713 const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena());
714 const child_pointer = try mod.singlePtrType(scope, unwrap.base.src, operand.ty.isConstPtr(), child_type);
712715
713716 if (operand.value()) |val| {
714717 if (val.isNull()) {
......@@ -728,6 +731,10 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
728731 return mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional, operand);
729732}
730733
734fn analyzeInstUnwrapErr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {
735 return mod.fail(scope, unwrap.base.src, "TODO implement analyzeInstUnwrapErr", .{});
736}
737
731738fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
732739 const return_type = try resolveType(mod, scope, fntype.positionals.return_type);
733740
......@@ -912,8 +919,11 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
912919 // required a larger index.
913920 const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));
914921
915 const type_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
916 type_payload.* = .{ .pointee_type = array_ptr.ty.elemType().elemType() };
922 const type_payload = try scope.arena().create(Type.Payload.Pointer);
923 type_payload.* = .{
924 .base = .{ .tag = .single_const_pointer },
925 .pointee_type = array_ptr.ty.elemType().elemType(),
926 };
917927
918928 return mod.constInst(scope, inst.base.src, .{
919929 .ty = Type.initPayload(&type_payload.base),
......@@ -1165,6 +1175,10 @@ fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, inver
11651175 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);
11661176}
11671177
1178fn analyzeInstIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst {
1179 return mod.fail(scope, inst.base.src, "TODO implement analyzeInstIsErr", .{});
1180}
1181
11681182fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {
11691183 const uncasted_cond = try resolveInst(mod, scope, inst.positionals.condition);
11701184 const cond = try mod.coerce(scope, Type.initTag(.bool), uncasted_cond);
......@@ -1278,12 +1292,16 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr
12781292
12791293fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
12801294 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
1281 const ty = try mod.singleConstPtrType(scope, inst.base.src, elem_type);
1295 const ty = try mod.singlePtrType(scope, inst.base.src, false, elem_type);
12821296 return mod.constType(scope, inst.base.src, ty);
12831297}
12841298
12851299fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
12861300 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
1287 const ty = try mod.singleMutPtrType(scope, inst.base.src, elem_type);
1301 const ty = try mod.singlePtrType(scope, inst.base.src, true, elem_type);
12881302 return mod.constType(scope, inst.base.src, ty);
12891303}
1304
1305fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst {
1306 return mod.fail(scope, inst.base.src, "TODO implement ptr_type", .{});
1307}