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...@@ -2207,8 +2207,11 @@ pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) Inn
2207 };2207 };
22082208
2209 const decl_tv = try decl.typedValue();2209 const decl_tv = try decl.typedValue();
2210 const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer);2210 const ty_payload = try scope.arena().create(Type.Payload.Pointer);
2211 ty_payload.* = .{ .pointee_type = decl_tv.ty };2211 ty_payload.* = .{
2212 .base = .{ .tag = .single_const_pointer },
2213 .pointee_type = decl_tv.ty,
2214 };
2212 const val_payload = try scope.arena().create(Value.Payload.DeclRef);2215 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
2213 val_payload.* = .{ .decl = decl };2216 val_payload.* = .{ .decl = decl };
22142217
...@@ -2432,6 +2435,15 @@ pub fn cmpNumeric(...@@ -2432,6 +2435,15 @@ pub fn cmpNumeric(
2432 return self.addBinOp(b, src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);2435 return self.addBinOp(b, src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
2433}2436}
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
2435fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {2447fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
2436 if (signed) {2448 if (signed) {
2437 const int_payload = try scope.arena().create(Type.Payload.IntSigned);2449 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...@@ -2509,14 +2521,12 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
25092521
2510 // T to ?T2522 // T to ?T
2511 if (dest_type.zigTypeTag() == .Optional) {2523 if (dest_type.zigTypeTag() == .Optional) {
2512 const child_type = dest_type.elemType();2524 var buf: Type.Payload.Pointer = undefined;
2513 if (inst.value()) |val| {2525 const child_type = dest_type.optionalChild(&buf);
2514 if (child_type.eql(inst.ty)) {2526 if (child_type.eql(inst.ty)) {
2515 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });2527 return self.wrapOptional(scope, dest_type, inst);
2516 }2528 } else if (try self.coerceNum(scope, child_type, inst)) |some| {
2517 return self.fail(scope, inst.src, "TODO optional wrap {} to {}", .{ val, dest_type });2529 return self.wrapOptional(scope, dest_type, some);
2518 } else if (child_type.eql(inst.ty)) {
2519 return self.fail(scope, inst.src, "TODO optional wrap {}", .{dest_type});
2520 }2530 }
2521 }2531 }
25222532
...@@ -2534,39 +2544,8 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst...@@ -2534,39 +2544,8 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
2534 }2544 }
25352545
2536 // comptime known number to other number2546 // comptime known number to other number
2537 if (inst.value()) |val| {2547 if (try self.coerceNum(scope, dest_type, inst)) |some|
2538 const src_zig_tag = inst.ty.zigTypeTag();2548 return some;
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 }
25702549
2571 // integer widening2550 // integer widening
2572 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {2551 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...@@ -2598,6 +2577,42 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
2598 return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });2577 return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
2599}2578}
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
2601pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {2616pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
2602 if (ptr.ty.isConstPtr())2617 if (ptr.ty.isConstPtr())
2603 return self.fail(scope, src, "cannot assign to constant", .{});2618 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:...@@ -2885,15 +2900,12 @@ pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs:
2885 return Value.initPayload(val_payload);2900 return Value.initPayload(val_payload);
2886}2901}
28872902
2888pub fn singleMutPtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type) error{OutOfMemory}!Type {2903pub fn singlePtrType(self: *Module, scope: *Scope, src: usize, mutable: bool, elem_ty: Type) error{OutOfMemory}!Type {
2889 const type_payload = try scope.arena().create(Type.Payload.SingleMutPointer);2904 const type_payload = try scope.arena().create(Type.Payload.Pointer);
2890 type_payload.* = .{ .pointee_type = elem_ty };2905 type_payload.* = .{
2891 return Type.initPayload(&type_payload.base);2906 .base = .{ .tag = if (mutable) .single_mut_pointer else .single_const_pointer },
2892}2907 .pointee_type = elem_ty,
28932908 };
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 };
2897 return Type.initPayload(&type_payload.base);2909 return Type.initPayload(&type_payload.base);
2898}2910}
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...@@ -113,6 +113,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
113 .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)),113 .Period => return rlWrap(mod, scope, rl, try field(mod, scope, node.castTag(.Period).?)),
114 .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)),114 .Deref => return rlWrap(mod, scope, rl, try deref(mod, scope, node.castTag(.Deref).?)),
115 .BoolNot => return rlWrap(mod, scope, rl, try boolNot(mod, scope, node.castTag(.BoolNot).?)),115 .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).?)),
116 .FloatLiteral => return rlWrap(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)),117 .FloatLiteral => return rlWrap(mod, scope, rl, try floatLiteral(mod, scope, node.castTag(.FloatLiteral).?)),
117 .UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)),118 .UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)),
118 .BoolLiteral => return rlWrap(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)),119 .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...@@ -122,6 +123,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
122 .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)),123 .Block => return rlWrapVoid(mod, scope, rl, node, try blockExpr(mod, scope, node.castTag(.Block).?)),
123 .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?),124 .LabeledBlock => return labeledBlockExpr(mod, scope, rl, node.castTag(.LabeledBlock).?),
124 .Break => return rlWrap(mod, scope, rl, try breakExpr(mod, scope, node.castTag(.Break).?)),125 .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
126 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),128 .Defer => return mod.failNode(scope, node, "TODO implement astgen.expr for .Defer", .{}),
127 .Catch => return mod.failNode(scope, node, "TODO implement astgen.expr for .Catch", .{}),129 .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...@@ -131,7 +133,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
131 .MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}),133 .MergeErrorSets => return mod.failNode(scope, node, "TODO implement astgen.expr for .MergeErrorSets", .{}),
132 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),134 .Range => return mod.failNode(scope, node, "TODO implement astgen.expr for .Range", .{}),
133 .OrElse => return mod.failNode(scope, node, "TODO implement astgen.expr for .OrElse", .{}),135 .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", .{}),
135 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),136 .Await => return mod.failNode(scope, node, "TODO implement astgen.expr for .Await", .{}),
136 .BitNot => return mod.failNode(scope, node, "TODO implement astgen.expr for .BitNot", .{}),137 .BitNot => return mod.failNode(scope, node, "TODO implement astgen.expr for .BitNot", .{}),
137 .Negation => return mod.failNode(scope, node, "TODO implement astgen.expr for .Negation", .{}),138 .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...@@ -140,7 +141,6 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
140 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),141 .Try => return mod.failNode(scope, node, "TODO implement astgen.expr for .Try", .{}),
141 .ArrayType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayType", .{}),142 .ArrayType => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayType", .{}),
142 .ArrayTypeSentinel => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayTypeSentinel", .{}),143 .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", .{}),
144 .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}),144 .SliceType => return mod.failNode(scope, node, "TODO implement astgen.expr for .SliceType", .{}),
145 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),145 .Slice => return mod.failNode(scope, node, "TODO implement astgen.expr for .Slice", .{}),
146 .ArrayAccess => return mod.failNode(scope, node, "TODO implement astgen.expr for .ArrayAccess", .{}),146 .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...@@ -425,6 +425,10 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr
425 return addZIRUnOp(mod, scope, src, .boolnot, operand);425 return addZIRUnOp(mod, scope, src, .boolnot, operand);
426}426}
427427
428fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
429 return expr(mod, scope, .lvalue, node.rhs);
430}
431
428fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {432fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
429 const tree = scope.tree();433 const tree = scope.tree();
430 const src = tree.token_locs[node.op_token].start;434 const src = tree.token_locs[node.op_token].start;
...@@ -436,6 +440,50 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn...@@ -436,6 +440,50 @@ fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) Inn
436 return addZIRUnOp(mod, scope, src, .optional_type, operand);440 return addZIRUnOp(mod, scope, src, .optional_type, operand);
437}441}
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
439fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {487fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst {
440 const tree = scope.tree();488 const tree = scope.tree();
441 const src = tree.token_locs[node.rtoken].start;489 const src = tree.token_locs[node.rtoken].start;
...@@ -520,13 +568,77 @@ fn simpleBinOp(...@@ -520,13 +568,77 @@ fn simpleBinOp(
520 return rlWrap(mod, scope, rl, result);568 return rlWrap(mod, scope, rl, result);
521}569}
522570
523fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst {571const CondKind = union(enum) {
524 if (if_node.payload) |payload| {572 bool,
525 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for optionals", .{});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 }
526 }598 }
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 };
527 if (if_node.@"else") |else_node| {639 if (if_node.@"else") |else_node| {
528 if (else_node.payload) |payload| {640 if (else_node.payload) |payload| {
529 return mod.failNode(scope, payload, "TODO implement astgen.IfExpr for error unions", .{});641 cond_kind = .{ .err_union = null };
530 }642 }
531 }643 }
532 var block_scope: Scope.GenZIR = .{644 var block_scope: Scope.GenZIR = .{
...@@ -539,11 +651,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -539,11 +651,7 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
539651
540 const tree = scope.tree();652 const tree = scope.tree();
541 const if_src = tree.token_locs[if_node.if_token].start;653 const if_src = tree.token_locs[if_node.if_token].start;
542 const bool_type = try addZIRInstConst(mod, scope, if_src, .{654 const cond = try cond_kind.cond(mod, &block_scope, if_src, if_node.condition);
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);
547655
548 const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{656 const condbr = try addZIRInstSpecial(mod, &block_scope.base, if_src, zir.Inst.CondBr, .{
549 .condition = cond,657 .condition = cond,
...@@ -554,6 +662,8 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -554,6 +662,8 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
554 const block = try addZIRInstBlock(mod, scope, if_src, .{662 const block = try addZIRInstBlock(mod, scope, if_src, .{
555 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),663 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
556 });664 });
665
666 const then_src = tree.token_locs[if_node.body.lastToken()].start;
557 var then_scope: Scope.GenZIR = .{667 var then_scope: Scope.GenZIR = .{
558 .parent = scope,668 .parent = scope,
559 .decl = block_scope.decl,669 .decl = block_scope.decl,
...@@ -562,6 +672,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -562,6 +672,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
562 };672 };
563 defer then_scope.instructions.deinit(mod.gpa);673 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
565 // Most result location types can be forwarded directly; however678 // Most result location types can be forwarded directly; however
566 // if we need to write to a pointer which has an inferred type,679 // if we need to write to a pointer which has an inferred type,
567 // proper type inference requires peer type resolution on the if's680 // 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...@@ -571,10 +684,9 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
571 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },684 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = block },
572 };685 };
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);
575 if (!then_result.tag.isNoReturn()) {688 if (!then_result.tag.isNoReturn()) {
576 const then_src = tree.token_locs[if_node.body.lastToken()].start;689 _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
577 _ = try addZIRInst(mod, &then_scope.base, then_src, zir.Inst.Break, .{
578 .block = block,690 .block = block,
579 .operand = then_result,691 .operand = then_result,
580 }, .{});692 }, .{});
...@@ -592,10 +704,13 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -592,10 +704,13 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
592 defer else_scope.instructions.deinit(mod.gpa);704 defer else_scope.instructions.deinit(mod.gpa);
593705
594 if (if_node.@"else") |else_node| {706 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);
596 if (!else_result.tag.isNoReturn()) {712 if (!else_result.tag.isNoReturn()) {
597 const else_src = tree.token_locs[else_node.body.lastToken()].start;713 _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{
598 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{
599 .block = block,714 .block = block,
600 .operand = else_result,715 .operand = else_result,
601 }, .{});716 }, .{});
...@@ -616,12 +731,11 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn...@@ -616,12 +731,11 @@ fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) Inn
616}731}
617732
618fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst {733fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst {
619 if (while_node.payload) |payload| {734 var cond_kind: CondKind = .bool;
620 return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for optionals", .{});735 if (while_node.payload) |_| cond_kind = .{ .optional = null };
621 }
622 if (while_node.@"else") |else_node| {736 if (while_node.@"else") |else_node| {
623 if (else_node.payload) |payload| {737 if (else_node.payload) |payload| {
624 return mod.failNode(scope, payload, "TODO implement astgen.whileExpr for error unions", .{});738 cond_kind = .{ .err_union = null };
625 }739 }
626 }740 }
627741
...@@ -651,15 +765,11 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -651,15 +765,11 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
651765
652 const tree = scope.tree();766 const tree = scope.tree();
653 const while_src = tree.token_locs[while_node.while_token].start;767 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 });
658 const void_type = try addZIRInstConst(mod, scope, while_src, .{768 const void_type = try addZIRInstConst(mod, scope, while_src, .{
659 .ty = Type.initTag(.type),769 .ty = Type.initTag(.type),
660 .val = Value.initTag(.void_type),770 .val = Value.initTag(.void_type),
661 });771 });
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
664 const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{774 const condbr = try addZIRInstSpecial(mod, &continue_scope.base, while_src, zir.Inst.CondBr, .{
665 .condition = cond,775 .condition = cond,
...@@ -682,6 +792,8 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -682,6 +792,8 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
682 const while_block = try addZIRInstBlock(mod, scope, while_src, .{792 const while_block = try addZIRInstBlock(mod, scope, while_src, .{
683 .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items),793 .instructions = try expr_scope.arena.dupe(*zir.Inst, expr_scope.instructions.items),
684 });794 });
795
796 const then_src = tree.token_locs[while_node.body.lastToken()].start;
685 var then_scope: Scope.GenZIR = .{797 var then_scope: Scope.GenZIR = .{
686 .parent = &continue_scope.base,798 .parent = &continue_scope.base,
687 .decl = continue_scope.decl,799 .decl = continue_scope.decl,
...@@ -690,6 +802,9 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -690,6 +802,9 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
690 };802 };
691 defer then_scope.instructions.deinit(mod.gpa);803 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
693 // Most result location types can be forwarded directly; however808 // Most result location types can be forwarded directly; however
694 // if we need to write to a pointer which has an inferred type,809 // if we need to write to a pointer which has an inferred type,
695 // proper type inference requires peer type resolution on the while's810 // 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...@@ -699,10 +814,9 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
699 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },814 .inferred_ptr, .bitcasted_ptr, .block_ptr => .{ .block_ptr = while_block },
700 };815 };
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);
703 if (!then_result.tag.isNoReturn()) {818 if (!then_result.tag.isNoReturn()) {
704 const then_src = tree.token_locs[while_node.body.lastToken()].start;819 _ = try addZIRInst(mod, then_sub_scope, then_src, zir.Inst.Break, .{
705 _ = try addZIRInst(mod, &then_scope.base, then_src, zir.Inst.Break, .{
706 .block = cond_block,820 .block = cond_block,
707 .operand = then_result,821 .operand = then_result,
708 }, .{});822 }, .{});
...@@ -720,10 +834,13 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W...@@ -720,10 +834,13 @@ fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.W
720 defer else_scope.instructions.deinit(mod.gpa);834 defer else_scope.instructions.deinit(mod.gpa);
721835
722 if (while_node.@"else") |else_node| {836 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);
724 if (!else_result.tag.isNoReturn()) {842 if (!else_result.tag.isNoReturn()) {
725 const else_src = tree.token_locs[else_node.body.lastToken()].start;843 _ = try addZIRInst(mod, else_sub_scope, else_src, zir.Inst.Break, .{
726 _ = try addZIRInst(mod, &else_scope.base, else_src, zir.Inst.Break, .{
727 .block = while_block,844 .block = while_block,
728 .operand = else_result,845 .operand = else_result,
729 }, .{});846 }, .{});
...@@ -796,7 +913,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo...@@ -796,7 +913,7 @@ fn identifier(mod: *Module, scope: *Scope, rl: ResultLoc, ident: *ast.Node.OneTo
796 const int_type_payload = try scope.arena().create(Value.Payload.IntType);913 const int_type_payload = try scope.arena().create(Value.Payload.IntType);
797 int_type_payload.* = .{ .signed = is_signed, .bits = bit_count };914 int_type_payload.* = .{ .signed = is_signed, .bits = bit_count };
798 const result = try addZIRInstConst(mod, scope, src, .{915 const result = try addZIRInstConst(mod, scope, src, .{
799 .ty = Type.initTag(.comptime_int),916 .ty = Type.initTag(.type),
800 .val = Value.initPayload(&int_type_payload.base),917 .val = Value.initPayload(&int_type_payload.base),
801 });918 });
802 return rlWrap(mod, scope, rl, result);919 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 {...@@ -671,6 +671,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
671 .intcast => return self.genIntCast(inst.castTag(.intcast).?),671 .intcast => return self.genIntCast(inst.castTag(.intcast).?),
672 .isnonnull => return self.genIsNonNull(inst.castTag(.isnonnull).?),672 .isnonnull => return self.genIsNonNull(inst.castTag(.isnonnull).?),
673 .isnull => return self.genIsNull(inst.castTag(.isnull).?),673 .isnull => return self.genIsNull(inst.castTag(.isnull).?),
674 .iserr => return self.genIsErr(inst.castTag(.iserr).?),
674 .load => return self.genLoad(inst.castTag(.load).?),675 .load => return self.genLoad(inst.castTag(.load).?),
675 .loop => return self.genLoop(inst.castTag(.loop).?),676 .loop => return self.genLoop(inst.castTag(.loop).?),
676 .not => return self.genNot(inst.castTag(.not).?),677 .not => return self.genNot(inst.castTag(.not).?),
...@@ -682,6 +683,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -682,6 +683,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
682 .sub => return self.genSub(inst.castTag(.sub).?),683 .sub => return self.genSub(inst.castTag(.sub).?),
683 .unreach => return MCValue{ .unreach = {} },684 .unreach => return MCValue{ .unreach = {} },
684 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),685 .unwrap_optional => return self.genUnwrapOptional(inst.castTag(.unwrap_optional).?),
686 .wrap_optional => return self.genWrapOptional(inst.castTag(.wrap_optional).?),
685 }687 }
686 }688 }
687689
...@@ -840,6 +842,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -840,6 +842,22 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
840 }842 }
841 }843 }
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
843 fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue {861 fn genLoad(self: *Self, inst: *ir.Inst.UnOp) !MCValue {
844 const elem_ty = inst.base.ty;862 const elem_ty = inst.base.ty;
845 if (!elem_ty.hasCodeGenBits())863 if (!elem_ty.hasCodeGenBits())
...@@ -1374,6 +1392,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1374,6 +1392,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1374 }1392 }
1375 }1393 }
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
1377 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {1401 fn genLoop(self: *Self, inst: *ir.Inst.Loop) !MCValue {
1378 // A loop is a setup to be able to jump back to the beginning.1402 // A loop is a setup to be able to jump back to the beginning.
1379 const start_index = self.code.items.len;1403 const start_index = self.code.items.len;
...@@ -2028,9 +2052,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2028,9 +2052,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2028 return mcv;2052 return mcv;
2029 }2053 }
20302054
2031 fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) !MCValue {2055 fn genTypedValue(self: *Self, src: usize, typed_value: TypedValue) InnerError!MCValue {
2032 if (typed_value.val.isUndef())2056 if (typed_value.val.isUndef())
2033 return MCValue.undef;2057 return MCValue{ .undef = {} };
2034 const ptr_bits = self.target.cpu.arch.ptrBitWidth();2058 const ptr_bits = self.target.cpu.arch.ptrBitWidth();
2035 const ptr_bytes: u64 = @divExact(ptr_bits, 8);2059 const ptr_bytes: u64 = @divExact(ptr_bits, 8);
2036 switch (typed_value.ty.zigTypeTag()) {2060 switch (typed_value.ty.zigTypeTag()) {
...@@ -2055,6 +2079,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2055,6 +2079,21 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2055 },2079 },
2056 .ComptimeInt => unreachable, // semantic analysis prevents this2080 .ComptimeInt => unreachable, // semantic analysis prevents this
2057 .ComptimeFloat => unreachable, // semantic analysis prevents this2081 .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 },
2058 else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),2097 else => return self.fail(src, "TODO implement const of type '{}'", .{typed_value.ty}),
2059 }2098 }
2060 }2099 }
...@@ -2160,7 +2199,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2160,7 +2199,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2160 };2199 };
2161 }2200 }
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 {
2164 @setCold(true);2203 @setCold(true);
2165 assert(self.err_msg == null);2204 assert(self.err_msg == null);
2166 self.err_msg = try ErrorMsg.create(self.bin_file.base.allocator, src, format, args);2205 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 {...@@ -68,6 +68,7 @@ pub const Inst = struct {
68 dbg_stmt,68 dbg_stmt,
69 isnonnull,69 isnonnull,
70 isnull,70 isnull,
71 iserr,
71 /// Read a value from a pointer.72 /// Read a value from a pointer.
72 load,73 load,
73 loop,74 loop,
...@@ -83,6 +84,7 @@ pub const Inst = struct {...@@ -83,6 +84,7 @@ pub const Inst = struct {
83 floatcast,84 floatcast,
84 intcast,85 intcast,
85 unwrap_optional,86 unwrap_optional,
87 wrap_optional,
8688
87 pub fn Type(tag: Tag) type {89 pub fn Type(tag: Tag) type {
88 return switch (tag) {90 return switch (tag) {
...@@ -99,11 +101,13 @@ pub const Inst = struct {...@@ -99,11 +101,13 @@ pub const Inst = struct {
99 .not,101 .not,
100 .isnonnull,102 .isnonnull,
101 .isnull,103 .isnull,
104 .iserr,
102 .ptrtoint,105 .ptrtoint,
103 .floatcast,106 .floatcast,
104 .intcast,107 .intcast,
105 .load,108 .load,
106 .unwrap_optional,109 .unwrap_optional,
110 .wrap_optional,
107 => UnOp,111 => UnOp,
108112
109 .add,113 .add,
src-self-hosted/type.zig+100-46
...@@ -107,6 +107,17 @@ pub const Type = extern union {...@@ -107,6 +107,17 @@ pub const Type = extern union {
107 return @fieldParentPtr(T, "base", self.ptr_otherwise);107 return @fieldParentPtr(T, "base", self.ptr_otherwise);
108 }108 }
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
110 pub fn eql(a: Type, b: Type) bool {121 pub fn eql(a: Type, b: Type) bool {
111 // As a shortcut, if the small tags / addresses match, we're done.122 // As a shortcut, if the small tags / addresses match, we're done.
112 if (a.tag_if_small_enough == b.tag_if_small_enough)123 if (a.tag_if_small_enough == b.tag_if_small_enough)
...@@ -126,8 +137,8 @@ pub const Type = extern union {...@@ -126,8 +137,8 @@ pub const Type = extern union {
126 .Null => return true,137 .Null => return true,
127 .Pointer => {138 .Pointer => {
128 // Hot path for common case:139 // Hot path for common case:
129 if (a.cast(Payload.SingleConstPointer)) |a_payload| {140 if (a.castPointer()) |a_payload| {
130 if (b.cast(Payload.SingleConstPointer)) |b_payload| {141 if (b.castPointer()) |b_payload| {
131 return eql(a_payload.pointee_type, b_payload.pointee_type);142 return eql(a_payload.pointee_type, b_payload.pointee_type);
132 }143 }
133 }144 }
...@@ -185,7 +196,9 @@ pub const Type = extern union {...@@ -185,7 +196,9 @@ pub const Type = extern union {
185 return true;196 return true;
186 },197 },
187 .Optional => {198 .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));
189 },202 },
190 .Float,203 .Float,
191 .Struct,204 .Struct,
...@@ -249,7 +262,8 @@ pub const Type = extern union {...@@ -249,7 +262,8 @@ pub const Type = extern union {
249 }262 }
250 },263 },
251 .Optional => {264 .Optional => {
252 std.hash.autoHash(&hasher, self.elemType().hash());265 var buf: Payload.Pointer = undefined;
266 std.hash.autoHash(&hasher, self.optionalChild(&buf).hash());
253 },267 },
254 .Float,268 .Float,
255 .Struct,269 .Struct,
...@@ -326,8 +340,6 @@ pub const Type = extern union {...@@ -326,8 +340,6 @@ pub const Type = extern union {
326 };340 };
327 return Type{ .ptr_otherwise = &new_payload.base };341 return Type{ .ptr_otherwise = &new_payload.base };
328 },342 },
329 .single_const_pointer => return self.copyPayloadSingleField(allocator, Payload.SingleConstPointer, "pointee_type"),
330 .single_mut_pointer => return self.copyPayloadSingleField(allocator, Payload.SingleMutPointer, "pointee_type"),
331 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),343 .int_signed => return self.copyPayloadShallow(allocator, Payload.IntSigned),
332 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),344 .int_unsigned => return self.copyPayloadShallow(allocator, Payload.IntUnsigned),
333 .function => {345 .function => {
...@@ -346,8 +358,11 @@ pub const Type = extern union {...@@ -346,8 +358,11 @@ pub const Type = extern union {
346 return Type{ .ptr_otherwise = &new_payload.base };358 return Type{ .ptr_otherwise = &new_payload.base };
347 },359 },
348 .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"),360 .optional => return self.copyPayloadSingleField(allocator, Payload.Optional, "child_type"),
349 .optional_single_mut_pointer => return self.copyPayloadSingleField(allocator, Payload.OptionalSingleMutPointer, "pointee_type"),361 .single_const_pointer,
350 .optional_single_const_pointer => return self.copyPayloadSingleField(allocator, Payload.OptionalSingleConstPointer, "pointee_type"),362 .single_mut_pointer,
363 .optional_single_mut_pointer,
364 .optional_single_const_pointer,
365 => return self.copyPayloadSingleField(allocator, Payload.Pointer, "pointee_type"),
351 }366 }
352 }367 }
353368
...@@ -441,13 +456,13 @@ pub const Type = extern union {...@@ -441,13 +456,13 @@ pub const Type = extern union {
441 continue;456 continue;
442 },457 },
443 .single_const_pointer => {458 .single_const_pointer => {
444 const payload = @fieldParentPtr(Payload.SingleConstPointer, "base", ty.ptr_otherwise);459 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
445 try out_stream.writeAll("*const ");460 try out_stream.writeAll("*const ");
446 ty = payload.pointee_type;461 ty = payload.pointee_type;
447 continue;462 continue;
448 },463 },
449 .single_mut_pointer => {464 .single_mut_pointer => {
450 const payload = @fieldParentPtr(Payload.SingleMutPointer, "base", ty.ptr_otherwise);465 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
451 try out_stream.writeAll("*");466 try out_stream.writeAll("*");
452 ty = payload.pointee_type;467 ty = payload.pointee_type;
453 continue;468 continue;
...@@ -467,13 +482,13 @@ pub const Type = extern union {...@@ -467,13 +482,13 @@ pub const Type = extern union {
467 continue;482 continue;
468 },483 },
469 .optional_single_const_pointer => {484 .optional_single_const_pointer => {
470 const payload = @fieldParentPtr(Payload.OptionalSingleConstPointer, "base", ty.ptr_otherwise);485 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
471 try out_stream.writeAll("?*const ");486 try out_stream.writeAll("?*const ");
472 ty = payload.pointee_type;487 ty = payload.pointee_type;
473 continue;488 continue;
474 },489 },
475 .optional_single_mut_pointer => {490 .optional_single_mut_pointer => {
476 const payload = @fieldParentPtr(Payload.OptionalSingleMutPointer, "base", ty.ptr_otherwise);491 const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
477 try out_stream.writeAll("?*");492 try out_stream.writeAll("?*");
478 ty = payload.pointee_type;493 ty = payload.pointee_type;
479 continue;494 continue;
...@@ -658,7 +673,8 @@ pub const Type = extern union {...@@ -658,7 +673,8 @@ pub const Type = extern union {
658 },673 },
659674
660 .optional => {675 .optional => {
661 const child_type = self.cast(Payload.Optional).?.child_type;676 var buf: Payload.Pointer = undefined;
677 const child_type = self.optionalChild(&buf);
662 if (!child_type.hasCodeGenBits()) return 1;678 if (!child_type.hasCodeGenBits()) return 1;
663679
664 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())680 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
...@@ -750,7 +766,8 @@ pub const Type = extern union {...@@ -750,7 +766,8 @@ pub const Type = extern union {
750 },766 },
751767
752 .optional => {768 .optional => {
753 const child_type = self.cast(Payload.Optional).?.child_type;769 var buf: Payload.Pointer = undefined;
770 const child_type = self.optionalChild(&buf);
754 if (!child_type.hasCodeGenBits()) return 1;771 if (!child_type.hasCodeGenBits()) return 1;
755772
756 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())773 if (child_type.zigTypeTag() == .Pointer and !child_type.isCPtr())
...@@ -990,7 +1007,23 @@ pub const Type = extern union {...@@ -990,7 +1007,23 @@ pub const Type = extern union {
990 };1007 };
991 }1008 }
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.
994 pub fn elemType(self: Type) Type {1027 pub fn elemType(self: Type) Type {
995 return switch (self.tag()) {1028 return switch (self.tag()) {
996 .u8,1029 .u8,
...@@ -1033,16 +1066,60 @@ pub const Type = extern union {...@@ -1033,16 +1066,60 @@ pub const Type = extern union {
1033 .function,1066 .function,
1034 .int_unsigned,1067 .int_unsigned,
1035 .int_signed,1068 .int_signed,
1069 .optional,
1070 .optional_single_const_pointer,
1071 .optional_single_mut_pointer,
1036 => unreachable,1072 => unreachable,
10371073
1038 .array => self.cast(Payload.Array).?.elem_type,1074 .array => self.cast(Payload.Array).?.elem_type,
1039 .single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type,1075 .single_const_pointer => self.castPointer().?.pointee_type,
1040 .single_mut_pointer => self.cast(Payload.SingleMutPointer).?.pointee_type,1076 .single_mut_pointer => self.castPointer().?.pointee_type,
1041 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),1077 .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
1042 .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),1078 .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()) {
1043 .optional => self.cast(Payload.Optional).?.child_type,1085 .optional => self.cast(Payload.Optional).?.child_type,
1044 .optional_single_mut_pointer => self.cast(Payload.OptionalSingleMutPointer).?.pointee_type,1086 .optional_single_mut_pointer => {
1045 .optional_single_const_pointer => self.cast(Payload.OptionalSingleConstPointer).?.pointee_type,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,
1046 };1123 };
1047 }1124 }
10481125
...@@ -1901,13 +1978,8 @@ pub const Type = extern union {...@@ -1901,13 +1978,8 @@ pub const Type = extern union {
1901 ty = array.elem_type;1978 ty = array.elem_type;
1902 continue;1979 continue;
1903 },1980 },
1904 .single_const_pointer => {1981 .single_const_pointer, .single_mut_pointer => {
1905 const ptr = ty.cast(Payload.SingleConstPointer).?;1982 const ptr = ty.castPointer().?;
1906 ty = ptr.pointee_type;
1907 continue;
1908 },
1909 .single_mut_pointer => {
1910 const ptr = ty.cast(Payload.SingleMutPointer).?;
1911 ty = ptr.pointee_type;1983 ty = ptr.pointee_type;
1912 continue;1984 continue;
1913 },1985 },
...@@ -2049,14 +2121,8 @@ pub const Type = extern union {...@@ -2049,14 +2121,8 @@ pub const Type = extern union {
2049 len: u64,2121 len: u64,
2050 };2122 };
20512123
2052 pub const SingleConstPointer = struct {2124 pub const Pointer = struct {
2053 base: Payload = Payload{ .tag = .single_const_pointer },2125 base: Payload,
2054
2055 pointee_type: Type,
2056 };
2057
2058 pub const SingleMutPointer = struct {
2059 base: Payload = Payload{ .tag = .single_mut_pointer },
20602126
2061 pointee_type: Type,2127 pointee_type: Type,
2062 };2128 };
...@@ -2086,18 +2152,6 @@ pub const Type = extern union {...@@ -2086,18 +2152,6 @@ pub const Type = extern union {
20862152
2087 child_type: Type,2153 child_type: Type,
2088 };2154 };
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 };
2101 };2155 };
2102};2156};
21032157
src-self-hosted/zir.zig+38-1
...@@ -151,6 +151,8 @@ pub const Inst = struct {...@@ -151,6 +151,8 @@ pub const Inst = struct {
151 isnonnull,151 isnonnull,
152 /// Return a boolean true if an optional is null. `x == null`152 /// Return a boolean true if an optional is null. `x == null`
153 isnull,153 isnull,
154 /// Return a boolean true if value is an error
155 iserr,
154 /// A labeled block of code that loops forever. At the end of the body it is implied156 /// A labeled block of code that loops forever. At the end of the body it is implied
155 /// to repeat; no explicit "repeat" instruction terminates loop bodies.157 /// to repeat; no explicit "repeat" instruction terminates loop bodies.
156 loop,158 loop,
...@@ -192,6 +194,8 @@ pub const Inst = struct {...@@ -192,6 +194,8 @@ pub const Inst = struct {
192 single_const_ptr_type,194 single_const_ptr_type,
193 /// Create a mutable pointer type based on the element type. `*T`195 /// Create a mutable pointer type based on the element type. `*T`
194 single_mut_ptr_type,196 single_mut_ptr_type,
197 /// Create a pointer type with attributes
198 ptr_type,
195 /// Write a value to a pointer. For loading, see `deref`.199 /// Write a value to a pointer. For loading, see `deref`.
196 store,200 store,
197 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.201 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
...@@ -217,6 +221,10 @@ pub const Inst = struct {...@@ -217,6 +221,10 @@ pub const Inst = struct {
217 unwrap_optional_safe,221 unwrap_optional_safe,
218 /// Same as previous, but without safety checks. Used for orelse, if and while222 /// Same as previous, but without safety checks. Used for orelse, if and while
219 unwrap_optional_unsafe,223 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
221 pub fn Type(tag: Tag) type {229 pub fn Type(tag: Tag) type {
222 return switch (tag) {230 return switch (tag) {
...@@ -235,6 +243,7 @@ pub const Inst = struct {...@@ -235,6 +243,7 @@ pub const Inst = struct {
235 .@"return",243 .@"return",
236 .isnull,244 .isnull,
237 .isnonnull,245 .isnonnull,
246 .iserr,
238 .ptrtoint,247 .ptrtoint,
239 .alloc,248 .alloc,
240 .ensure_result_used,249 .ensure_result_used,
...@@ -248,6 +257,8 @@ pub const Inst = struct {...@@ -248,6 +257,8 @@ pub const Inst = struct {
248 .optional_type,257 .optional_type,
249 .unwrap_optional_safe,258 .unwrap_optional_safe,
250 .unwrap_optional_unsafe,259 .unwrap_optional_unsafe,
260 .unwrap_err_safe,
261 .unwrap_err_unsafe,
251 => UnOp,262 => UnOp,
252263
253 .add,264 .add,
...@@ -305,6 +316,7 @@ pub const Inst = struct {...@@ -305,6 +316,7 @@ pub const Inst = struct {
305 .fntype => FnType,316 .fntype => FnType,
306 .elemptr => ElemPtr,317 .elemptr => ElemPtr,
307 .condbr => CondBr,318 .condbr => CondBr,
319 .ptr_type => PtrType,
308 };320 };
309 }321 }
310322
...@@ -360,6 +372,7 @@ pub const Inst = struct {...@@ -360,6 +372,7 @@ pub const Inst = struct {
360 .inttype,372 .inttype,
361 .isnonnull,373 .isnonnull,
362 .isnull,374 .isnull,
375 .iserr,
363 .mod_rem,376 .mod_rem,
364 .mul,377 .mul,
365 .mulwrap,378 .mulwrap,
...@@ -382,6 +395,9 @@ pub const Inst = struct {...@@ -382,6 +395,9 @@ pub const Inst = struct {
382 .optional_type,395 .optional_type,
383 .unwrap_optional_safe,396 .unwrap_optional_safe,
384 .unwrap_optional_unsafe,397 .unwrap_optional_unsafe,
398 .unwrap_err_safe,
399 .unwrap_err_unsafe,
400 .ptr_type,
385 => false,401 => false,
386402
387 .@"break",403 .@"break",
...@@ -811,6 +827,24 @@ pub const Inst = struct {...@@ -811,6 +827,24 @@ pub const Inst = struct {
811 },827 },
812 kw_args: struct {},828 kw_args: struct {},
813 };829 };
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 };
814};848};
815849
816pub const ErrorMsg = struct {850pub const ErrorMsg = struct {
...@@ -1992,9 +2026,11 @@ const EmitZIR = struct {...@@ -1992,9 +2026,11 @@ const EmitZIR = struct {
1992 .ptrtoint => try self.emitUnOp(inst.src, new_body, inst.castTag(.ptrtoint).?, .ptrtoint),2026 .ptrtoint => try self.emitUnOp(inst.src, new_body, inst.castTag(.ptrtoint).?, .ptrtoint),
1993 .isnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnull).?, .isnull),2027 .isnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnull).?, .isnull),
1994 .isnonnull => try self.emitUnOp(inst.src, new_body, inst.castTag(.isnonnull).?, .isnonnull),2028 .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),
1995 .load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref),2030 .load => try self.emitUnOp(inst.src, new_body, inst.castTag(.load).?, .deref),
1996 .ref => try self.emitUnOp(inst.src, new_body, inst.castTag(.ref).?, .ref),2031 .ref => try self.emitUnOp(inst.src, new_body, inst.castTag(.ref).?, .ref),
1997 .unwrap_optional => try self.emitUnOp(inst.src, new_body, inst.castTag(.unwrap_optional).?, .unwrap_optional_unsafe),2032 .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
1999 .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add),2035 .add => try self.emitBinOp(inst.src, new_body, inst.castTag(.add).?, .add),
2000 .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub),2036 .sub => try self.emitBinOp(inst.src, new_body, inst.castTag(.sub).?, .sub),
...@@ -2338,6 +2374,7 @@ const EmitZIR = struct {...@@ -2338,6 +2374,7 @@ const EmitZIR = struct {
2338 }2374 }
2339 },2375 },
2340 .Optional => {2376 .Optional => {
2377 var buf: Type.Payload.Pointer = undefined;
2341 const inst = try self.arena.allocator.create(Inst.UnOp);2378 const inst = try self.arena.allocator.create(Inst.UnOp);
2342 inst.* = .{2379 inst.* = .{
2343 .base = .{2380 .base = .{
...@@ -2345,7 +2382,7 @@ const EmitZIR = struct {...@@ -2345,7 +2382,7 @@ const EmitZIR = struct {
2345 .tag = .optional_type,2382 .tag = .optional_type,
2346 },2383 },
2347 .positionals = .{2384 .positionals = .{
2348 .operand = (try self.emitType(src, ty.elemType())).inst,2385 .operand = (try self.emitType(src, ty.optionalChild(&buf))).inst,
2349 },2386 },
2350 .kw_args = .{},2387 .kw_args = .{},
2351 };2388 };
src-self-hosted/zir_sema.zig+31-13
...@@ -53,6 +53,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -53,6 +53,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
53 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),53 .ret_type => return analyzeInstRetType(mod, scope, old_inst.castTag(.ret_type).?),
54 .single_const_ptr_type => return analyzeInstSingleConstPtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?),54 .single_const_ptr_type => return analyzeInstSingleConstPtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?),
55 .single_mut_ptr_type => return analyzeInstSingleMutPtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?),55 .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).?),
56 .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?),57 .store => return analyzeInstStore(mod, scope, old_inst.castTag(.store).?),
57 .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?),58 .str => return analyzeInstStr(mod, scope, old_inst.castTag(.str).?),
58 .int => {59 .int => {
...@@ -103,11 +104,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!...@@ -103,11 +104,14 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
103 .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?),104 .condbr => return analyzeInstCondBr(mod, scope, old_inst.castTag(.condbr).?),
104 .isnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnull).?, true),105 .isnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnull).?, true),
105 .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false),106 .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false),
107 .iserr => return analyzeInstIsErr(mod, scope, old_inst.castTag(.iserr).?, true),
106 .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),108 .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),
107 .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),109 .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),
108 .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),110 .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
109 .unwrap_optional_safe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_safe).?, true),111 .unwrap_optional_safe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_safe).?, true),
110 .unwrap_optional_unsafe => return analyzeInstUnwrapOptional(mod, scope, old_inst.castTag(.unwrap_optional_unsafe).?, false),112 .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),
111 }115 }
112}116}
113117
...@@ -316,7 +320,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr...@@ -316,7 +320,7 @@ fn analyzeInstRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerErr
316320
317fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {321fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
318 const operand = try resolveInst(mod, scope, inst.positionals.operand);322 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
321 if (operand.value()) |val| {325 if (operand.value()) |val| {
322 const ref_payload = try scope.arena().create(Value.Payload.RefVal);326 const ref_payload = try scope.arena().create(Value.Payload.RefVal);
...@@ -357,7 +361,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst....@@ -357,7 +361,7 @@ fn analyzeInstEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.
357361
358fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {362fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
359 const var_type = try resolveType(mod, scope, inst.positionals.operand);363 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);
361 const b = try mod.requireRuntimeBlock(scope, inst.base.src);365 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
362 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);366 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
363}367}
...@@ -673,15 +677,17 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp...@@ -673,15 +677,17 @@ fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp
673677
674 return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) {678 return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) {
675 .single_const_pointer => blk: {679 .single_const_pointer => blk: {
676 const payload = try scope.arena().create(Type.Payload.OptionalSingleConstPointer);680 const payload = try scope.arena().create(Type.Payload.Pointer);
677 payload.* = .{681 payload.* = .{
682 .base = .{ .tag = .optional_single_const_pointer },
678 .pointee_type = child_type.elemType(),683 .pointee_type = child_type.elemType(),
679 };684 };
680 break :blk &payload.base;685 break :blk &payload.base;
681 },686 },
682 .single_mut_pointer => blk: {687 .single_mut_pointer => blk: {
683 const payload = try scope.arena().create(Type.Payload.OptionalSingleMutPointer);688 const payload = try scope.arena().create(Type.Payload.Pointer);
684 payload.* = .{689 payload.* = .{
690 .base = .{ .tag = .optional_single_mut_pointer },
685 .pointee_type = child_type.elemType(),691 .pointee_type = child_type.elemType(),
686 };692 };
687 break :blk &payload.base;693 break :blk &payload.base;
...@@ -704,11 +710,8 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp...@@ -704,11 +710,8 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
704 return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{operand.ty.elemType()});710 return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{operand.ty.elemType()});
705 }711 }
706712
707 const child_type = operand.ty.elemType().elemType();713 const child_type = try operand.ty.elemType().optionalChildAlloc(scope.arena());
708 const child_pointer = if (operand.ty.isConstPtr())714 const child_pointer = try mod.singlePtrType(scope, unwrap.base.src, operand.ty.isConstPtr(), child_type);
709 try mod.singleConstPtrType(scope, unwrap.base.src, child_type)
710 else
711 try mod.singleMutPtrType(scope, unwrap.base.src, child_type);
712715
713 if (operand.value()) |val| {716 if (operand.value()) |val| {
714 if (val.isNull()) {717 if (val.isNull()) {
...@@ -728,6 +731,10 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp...@@ -728,6 +731,10 @@ fn analyzeInstUnwrapOptional(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp
728 return mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional, operand);731 return mod.addUnOp(b, unwrap.base.src, child_pointer, .unwrap_optional, operand);
729}732}
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
731fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {738fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
732 const return_type = try resolveType(mod, scope, fntype.positionals.return_type);739 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...@@ -912,8 +919,11 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
912 // required a larger index.919 // required a larger index.
913 const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));920 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);922 const type_payload = try scope.arena().create(Type.Payload.Pointer);
916 type_payload.* = .{ .pointee_type = array_ptr.ty.elemType().elemType() };923 type_payload.* = .{
924 .base = .{ .tag = .single_const_pointer },
925 .pointee_type = array_ptr.ty.elemType().elemType(),
926 };
917927
918 return mod.constInst(scope, inst.base.src, .{928 return mod.constInst(scope, inst.base.src, .{
919 .ty = Type.initPayload(&type_payload.base),929 .ty = Type.initPayload(&type_payload.base),
...@@ -1165,6 +1175,10 @@ fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, inver...@@ -1165,6 +1175,10 @@ fn analyzeInstIsNonNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, inver
1165 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);1175 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);
1166}1176}
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
1168fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {1182fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {
1169 const uncasted_cond = try resolveInst(mod, scope, inst.positionals.condition);1183 const uncasted_cond = try resolveInst(mod, scope, inst.positionals.condition);
1170 const cond = try mod.coerce(scope, Type.initTag(.bool), uncasted_cond);1184 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...@@ -1278,12 +1292,16 @@ fn analyzeDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerErr
12781292
1279fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {1293fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1280 const elem_type = try resolveType(mod, scope, inst.positionals.operand);1294 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);
1282 return mod.constType(scope, inst.base.src, ty);1296 return mod.constType(scope, inst.base.src, ty);
1283}1297}
12841298
1285fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {1299fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1286 const elem_type = try resolveType(mod, scope, inst.positionals.operand);1300 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);
1288 return mod.constType(scope, inst.base.src, ty);1302 return mod.constType(scope, inst.base.src, ty);
1289}1303}
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}