| author | |
| committer | |
| log | 5c1fe5861389462f309e3f0b69096a85f330dc20 |
| tree | 947c6d050169327de882ea79db3a47101df4df0f |
| parent | 75eaf15740bc42167592f3bdd7205236828191c7 |
5 files changed, 81 insertions(+), 4 deletions(-)
src-self-hosted/Module.zig+18| ... | @@ -2476,6 +2476,24 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst | ... | @@ -2476,6 +2476,24 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst |
| 2476 | } | 2476 | } |
| 2477 | assert(inst.ty.zigTypeTag() != .Undefined); | 2477 | assert(inst.ty.zigTypeTag() != .Undefined); |
| 2478 | 2478 | ||
| 2479 | // null to ?T | ||
| 2480 | if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) { | ||
| 2481 | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = inst.ty.onePossibleValue().? }); | ||
| 2482 | } | ||
| 2483 | |||
| 2484 | // T to ?T | ||
| 2485 | if (dest_type.zigTypeTag() == .Optional) { | ||
| 2486 | const child_type = dest_type.elemType(); | ||
| 2487 | if (inst.value()) |val| { | ||
| 2488 | if (child_type.eql(inst.ty)) { | ||
| 2489 | return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val }); | ||
| 2490 | } | ||
| 2491 | return self.fail(scope, inst.src, "TODO optional wrap {} to {}", .{ val, inst.ty }); | ||
| 2492 | } else if (child_type.eql(inst.ty)) { | ||
| 2493 | return self.fail(scope, inst.src, "TODO optional wrap {}", .{inst.ty}); | ||
| 2494 | } | ||
| 2495 | } | ||
| 2496 | |||
| 2479 | // *[N]T to []T | 2497 | // *[N]T to []T |
| 2480 | if (inst.ty.isSinglePointer() and dest_type.isSlice() and | 2498 | if (inst.ty.isSinglePointer() and dest_type.isSlice() and |
| 2481 | (!inst.ty.isConstPtr() or dest_type.isConstPtr())) | 2499 | (!inst.ty.isConstPtr() or dest_type.isConstPtr())) |
src-self-hosted/astgen.zig+12| ... | @@ -105,6 +105,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr | ... | @@ -105,6 +105,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr |
| 105 | .UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)), | 105 | .UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)), |
| 106 | .BoolLiteral => return rlWrap(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)), | 106 | .BoolLiteral => return rlWrap(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)), |
| 107 | .NullLiteral => return rlWrap(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)), | 107 | .NullLiteral => return rlWrap(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)), |
| 108 | .OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)), | ||
| 108 | else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}), | 109 | else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}), |
| 109 | } | 110 | } |
| 110 | } | 111 | } |
| ... | @@ -293,6 +294,17 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr | ... | @@ -293,6 +294,17 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr |
| 293 | return addZIRUnOp(mod, scope, src, .boolnot, operand); | 294 | return addZIRUnOp(mod, scope, src, .boolnot, operand); |
| 294 | } | 295 | } |
| 295 | 296 | ||
| 297 | fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst { | ||
| 298 | const tree = scope.tree(); | ||
| 299 | const src = tree.token_locs[node.op_token].start; | ||
| 300 | const meta_type = try addZIRInstConst(mod, scope, src, .{ | ||
| 301 | .ty = Type.initTag(.type), | ||
| 302 | .val = Value.initTag(.type_type), | ||
| 303 | }); | ||
| 304 | const operand = try expr(mod, scope, .{ .ty = meta_type }, node.rhs); | ||
| 305 | return addZIRUnOp(mod, scope, src, .optional_type, operand); | ||
| 306 | } | ||
| 307 | |||
| 296 | /// Identifier token -> String (allocated in scope.arena()) | 308 | /// Identifier token -> String (allocated in scope.arena()) |
| 297 | pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 { | 309 | pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 { |
| 298 | const tree = scope.tree(); | 310 | const tree = scope.tree(); |
src-self-hosted/type.zig+4-4| ... | @@ -569,16 +569,16 @@ pub const Type = extern union { | ... | @@ -569,16 +569,16 @@ pub const Type = extern union { |
| 569 | .single_const_pointer_to_comptime_int, | 569 | .single_const_pointer_to_comptime_int, |
| 570 | .const_slice_u8, | 570 | .const_slice_u8, |
| 571 | .array_u8_sentinel_0, | 571 | .array_u8_sentinel_0, |
| 572 | .optional, | ||
| 573 | .optional_single_mut_pointer, | ||
| 574 | .optional_single_const_pointer, | ||
| 575 | => true, | ||
| 572 | // TODO lazy types | 576 | // TODO lazy types |
| 573 | .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, | 577 | .array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0, |
| 574 | .single_const_pointer => self.elemType().hasCodeGenBits(), | 578 | .single_const_pointer => self.elemType().hasCodeGenBits(), |
| 575 | .single_mut_pointer => self.elemType().hasCodeGenBits(), | 579 | .single_mut_pointer => self.elemType().hasCodeGenBits(), |
| 576 | .int_signed => self.cast(Payload.IntSigned).?.bits == 0, | 580 | .int_signed => self.cast(Payload.IntSigned).?.bits == 0, |
| 577 | .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, | 581 | .int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0, |
| 578 | .optional, | ||
| 579 | .optional_single_mut_pointer, | ||
| 580 | .optional_single_const_pointer, | ||
| 581 | => true, | ||
| 582 | 582 | ||
| 583 | .c_void, | 583 | .c_void, |
| 584 | .void, | 584 | .void, |
src-self-hosted/zir.zig+18| ... | @@ -212,6 +212,8 @@ pub const Inst = struct { | ... | @@ -212,6 +212,8 @@ pub const Inst = struct { |
| 212 | @"unreachable", | 212 | @"unreachable", |
| 213 | /// Bitwise XOR. `^` | 213 | /// Bitwise XOR. `^` |
| 214 | xor, | 214 | xor, |
| 215 | /// Create an optional type '?T' | ||
| 216 | optional_type, | ||
| 215 | 217 | ||
| 216 | pub fn Type(tag: Tag) type { | 218 | pub fn Type(tag: Tag) type { |
| 217 | return switch (tag) { | 219 | return switch (tag) { |
| ... | @@ -240,6 +242,7 @@ pub const Inst = struct { | ... | @@ -240,6 +242,7 @@ pub const Inst = struct { |
| 240 | .typeof, | 242 | .typeof, |
| 241 | .single_const_ptr_type, | 243 | .single_const_ptr_type, |
| 242 | .single_mut_ptr_type, | 244 | .single_mut_ptr_type, |
| 245 | .optional_type, | ||
| 243 | => UnOp, | 246 | => UnOp, |
| 244 | 247 | ||
| 245 | .add, | 248 | .add, |
| ... | @@ -372,6 +375,7 @@ pub const Inst = struct { | ... | @@ -372,6 +375,7 @@ pub const Inst = struct { |
| 372 | .subwrap, | 375 | .subwrap, |
| 373 | .typeof, | 376 | .typeof, |
| 374 | .xor, | 377 | .xor, |
| 378 | .optional_type, | ||
| 375 | => false, | 379 | => false, |
| 376 | 380 | ||
| 377 | .@"break", | 381 | .@"break", |
| ... | @@ -2242,6 +2246,20 @@ const EmitZIR = struct { | ... | @@ -2242,6 +2246,20 @@ const EmitZIR = struct { |
| 2242 | std.debug.panic("TODO implement emitType for {}", .{ty}); | 2246 | std.debug.panic("TODO implement emitType for {}", .{ty}); |
| 2243 | } | 2247 | } |
| 2244 | }, | 2248 | }, |
| 2249 | .Optional => { | ||
| 2250 | const inst = try self.arena.allocator.create(Inst.UnOp); | ||
| 2251 | inst.* = .{ | ||
| 2252 | .base = .{ | ||
| 2253 | .src = src, | ||
| 2254 | .tag = .optional_type, | ||
| 2255 | }, | ||
| 2256 | .positionals = .{ | ||
| 2257 | .operand = (try self.emitType(src, ty.elemType())).inst, | ||
| 2258 | }, | ||
| 2259 | .kw_args = .{}, | ||
| 2260 | }; | ||
| 2261 | return self.emitUnnamedDecl(&inst.base); | ||
| 2262 | }, | ||
| 2245 | else => std.debug.panic("TODO implement emitType for {}", .{ty}), | 2263 | else => std.debug.panic("TODO implement emitType for {}", .{ty}), |
| 2246 | }, | 2264 | }, |
| 2247 | } | 2265 | } |
src-self-hosted/zir_sema.zig+29| ... | @@ -106,6 +106,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! | ... | @@ -106,6 +106,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError! |
| 106 | .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false), | 106 | .isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false), |
| 107 | .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?), | 107 | .boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?), |
| 108 | .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?), | 108 | .typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?), |
| 109 | .optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?), | ||
| 109 | } | 110 | } |
| 110 | } | 111 | } |
| 111 | 112 | ||
| ... | @@ -620,6 +621,34 @@ fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) I | ... | @@ -620,6 +621,34 @@ fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) I |
| 620 | return mod.fail(scope, inttype.base.src, "TODO implement inttype", .{}); | 621 | return mod.fail(scope, inttype.base.src, "TODO implement inttype", .{}); |
| 621 | } | 622 | } |
| 622 | 623 | ||
| 624 | fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst { | ||
| 625 | const child_type = try resolveType(mod, scope, optional.positionals.operand); | ||
| 626 | |||
| 627 | return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) { | ||
| 628 | .single_const_pointer => blk: { | ||
| 629 | const payload = try scope.arena().create(Type.Payload.OptionalSingleConstPointer); | ||
| 630 | payload.* = .{ | ||
| 631 | .pointee_type = child_type.elemType(), | ||
| 632 | }; | ||
| 633 | break :blk &payload.base; | ||
| 634 | }, | ||
| 635 | .single_mut_pointer => blk: { | ||
| 636 | const payload = try scope.arena().create(Type.Payload.OptionalSingleMutPointer); | ||
| 637 | payload.* = .{ | ||
| 638 | .pointee_type = child_type.elemType(), | ||
| 639 | }; | ||
| 640 | break :blk &payload.base; | ||
| 641 | }, | ||
| 642 | else => blk: { | ||
| 643 | const payload = try scope.arena().create(Type.Payload.Optional); | ||
| 644 | payload.* = .{ | ||
| 645 | .child_type = child_type, | ||
| 646 | }; | ||
| 647 | break :blk &payload.base; | ||
| 648 | }, | ||
| 649 | })); | ||
| 650 | } | ||
| 651 | |||
| 623 | fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { | 652 | fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst { |
| 624 | const return_type = try resolveType(mod, scope, fntype.positionals.return_type); | 653 | const return_type = try resolveType(mod, scope, fntype.positionals.return_type); |
| 625 | 654 |