| author | |
| committer | |
| log | d8fb377e2a5caf1ff6132b619a1b46d3b030496b |
| tree | 5c12cfe219de00ae1879fdce67544e70d5e263d1 |
| parent | 624e643872130de5b6f6f1f120c8cf60a31f58e8 |
| parent | 13b2f1e90ba9e373c655fc881836209c4fa381fa |
| signature |
Stage2: more optionals stuff7 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 | }; |
| 2208 | 2208 | ||
| 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 }; |
| 2214 | 2217 | ||
| ... | @@ -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 | } |
| 2434 | 2437 | ||
| 2438 | fn 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 | |||
| 2435 | fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type { | 2447 | fn 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 |
| 2509 | 2521 | ||
| 2510 | // T to ?T | 2522 | // 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 | } |
| 2522 | 2532 | ||
| ... | @@ -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 | } |
| 2535 | 2545 | ||
| 2536 | // comptime known number to other number | 2546 | // 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 | } | ||
| 2570 | 2549 | ||
| 2571 | // integer widening | 2550 | // 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 | } |
| 2600 | 2579 | ||
| 2580 | pub 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 | |||
| 2601 | pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst { | 2616 | pub 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 | } |
| 2887 | 2902 | ||
| 2888 | pub fn singleMutPtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type) error{OutOfMemory}!Type { | 2903 | pub 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, |
| 2893 | 2908 | }; | |
| 2894 | pub 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 | } |
| 2899 | 2911 |
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).?)), | ||
| 125 | 127 | ||
| 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 | } |
| 427 | 427 | ||
| 428 | fn addressOf(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { | ||
| 429 | return expr(mod, scope, .lvalue, node.rhs); | ||
| 430 | } | ||
| 431 | |||
| 428 | fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { | 432 | fn 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 | } |
| 438 | 442 | ||
| 443 | fn 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 | |||
| 439 | fn unwrapOptional(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node.SimpleSuffixOp) InnerError!*zir.Inst { | 487 | fn 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 | } |
| 522 | 570 | ||
| 523 | fn ifExpr(mod: *Module, scope: *Scope, rl: ResultLoc, if_node: *ast.Node.If) InnerError!*zir.Inst { | 571 | const 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 | |||
| 636 | fn 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 |
| 539 | 651 | ||
| 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); | ||
| 547 | 655 | ||
| 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); |
| 564 | 674 | ||
| 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; however | 678 | // 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's | 680 | // 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 | }; |
| 573 | 686 | ||
| 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); |
| 593 | 705 | ||
| 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 | } |
| 617 | 732 | ||
| 618 | fn whileExpr(mod: *Module, scope: *Scope, rl: ResultLoc, while_node: *ast.Node.While) InnerError!*zir.Inst { | 733 | fn 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 | } |
| 627 | 741 | ||
| ... | @@ -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 |
| 651 | 765 | ||
| 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); |
| 663 | 773 | ||
| 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); |
| 692 | 804 | ||
| 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; however | 808 | // 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's | 810 | // 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 | }; |
| 701 | 816 | ||
| 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); |
| 721 | 835 | ||
| 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 | } |
| 687 | 689 | ||
| ... | @@ -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 | } |
| 842 | 844 | ||
| 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 | } |
| 1376 | 1394 | ||
| 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 | } |
| 2030 | 2054 | ||
| 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 this | 2080 | .ComptimeInt => unreachable, // semantic analysis prevents this |
| 2057 | .ComptimeFloat => unreachable, // semantic analysis prevents this | 2081 | .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 | } |
| 2162 | 2201 | ||
| 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, | ||
| 86 | 88 | ||
| 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, |
| 108 | 112 | ||
| 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 | } |
| 109 | 109 | ||
| 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 | } |
| 353 | 368 | ||
| ... | @@ -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 | }, |
| 659 | 674 | ||
| 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; |
| 663 | 679 | ||
| 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 | }, |
| 751 | 767 | ||
| 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; |
| 755 | 772 | ||
| 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 | } |
| 992 | 1009 | ||
| 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, |
| 1037 | 1073 | ||
| 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 | } |
| 1048 | 1125 | ||
| ... | @@ -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 | }; |
| 2051 | 2123 | ||
| 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 }, | ||
| 2060 | 2126 | ||
| 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 { |
| 2086 | 2152 | ||
| 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 | }; |
| 2103 | 2157 |
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 implied | 156 | /// 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 while | 222 | /// 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, | ||
| 220 | 228 | ||
| 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, |
| 252 | 263 | ||
| 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 | } |
| 310 | 322 | ||
| ... | @@ -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, |
| 386 | 402 | ||
| 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 | }; |
| 815 | 849 | ||
| 816 | pub const ErrorMsg = struct { | 850 | pub 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), | ||
| 1998 | 2034 | ||
| 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 | } |
| 113 | 117 | ||
| ... | @@ -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 |
| 316 | 320 | ||
| 317 | fn analyzeInstRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 321 | fn 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); |
| 320 | 324 | ||
| 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. |
| 357 | 361 | ||
| 358 | fn analyzeInstAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 362 | fn 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 |
| 673 | 677 | ||
| 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 | } |
| 706 | 712 | ||
| 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); | ||
| 712 | 715 | ||
| 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 | } |
| 730 | 733 | ||
| 734 | fn 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 | |||
| 731 | fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { | 738 | fn 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); |
| 733 | 740 | ||
| ... | @@ -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)); |
| 914 | 921 | ||
| 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 | }; | ||
| 917 | 927 | ||
| 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 | } |
| 1167 | 1177 | ||
| 1178 | fn 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 | |||
| 1168 | fn analyzeInstCondBr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst { | 1182 | fn 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 |
| 1278 | 1292 | ||
| 1279 | fn analyzeInstSingleConstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1293 | fn 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 | } |
| 1284 | 1298 | ||
| 1285 | fn analyzeInstSingleMutPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst { | 1299 | fn 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 | |||
| 1305 | fn analyzeInstPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst { | ||
| 1306 | return mod.fail(scope, inst.base.src, "TODO implement ptr_type", .{}); | ||
| 1307 | } |