stage2: gen optional types
This commit is contained in:
@@ -2476,6 +2476,24 @@ pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst
|
||||
}
|
||||
assert(inst.ty.zigTypeTag() != .Undefined);
|
||||
|
||||
// null to ?T
|
||||
if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) {
|
||||
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = inst.ty.onePossibleValue().? });
|
||||
}
|
||||
|
||||
// T to ?T
|
||||
if (dest_type.zigTypeTag() == .Optional) {
|
||||
const child_type = dest_type.elemType();
|
||||
if (inst.value()) |val| {
|
||||
if (child_type.eql(inst.ty)) {
|
||||
return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
|
||||
}
|
||||
return self.fail(scope, inst.src, "TODO optional wrap {} to {}", .{ val, inst.ty });
|
||||
} else if (child_type.eql(inst.ty)) {
|
||||
return self.fail(scope, inst.src, "TODO optional wrap {}", .{inst.ty});
|
||||
}
|
||||
}
|
||||
|
||||
// *[N]T to []T
|
||||
if (inst.ty.isSinglePointer() and dest_type.isSlice() and
|
||||
(!inst.ty.isConstPtr() or dest_type.isConstPtr()))
|
||||
|
||||
@@ -105,6 +105,7 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: *ast.Node) InnerEr
|
||||
.UndefinedLiteral => return rlWrap(mod, scope, rl, try undefLiteral(mod, scope, node.castTag(.UndefinedLiteral).?)),
|
||||
.BoolLiteral => return rlWrap(mod, scope, rl, try boolLiteral(mod, scope, node.castTag(.BoolLiteral).?)),
|
||||
.NullLiteral => return rlWrap(mod, scope, rl, try nullLiteral(mod, scope, node.castTag(.NullLiteral).?)),
|
||||
.OptionalType => return rlWrap(mod, scope, rl, try optionalType(mod, scope, node.castTag(.OptionalType).?)),
|
||||
else => return mod.failNode(scope, node, "TODO implement astgen.Expr for {}", .{@tagName(node.tag)}),
|
||||
}
|
||||
}
|
||||
@@ -293,6 +294,17 @@ fn boolNot(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerErr
|
||||
return addZIRUnOp(mod, scope, src, .boolnot, operand);
|
||||
}
|
||||
|
||||
fn optionalType(mod: *Module, scope: *Scope, node: *ast.Node.SimplePrefixOp) InnerError!*zir.Inst {
|
||||
const tree = scope.tree();
|
||||
const src = tree.token_locs[node.op_token].start;
|
||||
const meta_type = try addZIRInstConst(mod, scope, src, .{
|
||||
.ty = Type.initTag(.type),
|
||||
.val = Value.initTag(.type_type),
|
||||
});
|
||||
const operand = try expr(mod, scope, .{ .ty = meta_type }, node.rhs);
|
||||
return addZIRUnOp(mod, scope, src, .optional_type, operand);
|
||||
}
|
||||
|
||||
/// Identifier token -> String (allocated in scope.arena())
|
||||
pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {
|
||||
const tree = scope.tree();
|
||||
|
||||
@@ -569,16 +569,16 @@ pub const Type = extern union {
|
||||
.single_const_pointer_to_comptime_int,
|
||||
.const_slice_u8,
|
||||
.array_u8_sentinel_0,
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
=> true,
|
||||
// TODO lazy types
|
||||
.array => self.elemType().hasCodeGenBits() and self.arrayLen() != 0,
|
||||
.single_const_pointer => self.elemType().hasCodeGenBits(),
|
||||
.single_mut_pointer => self.elemType().hasCodeGenBits(),
|
||||
.int_signed => self.cast(Payload.IntSigned).?.bits == 0,
|
||||
.int_unsigned => self.cast(Payload.IntUnsigned).?.bits == 0,
|
||||
.optional,
|
||||
.optional_single_mut_pointer,
|
||||
.optional_single_const_pointer,
|
||||
=> true,
|
||||
|
||||
.c_void,
|
||||
.void,
|
||||
|
||||
@@ -212,6 +212,8 @@ pub const Inst = struct {
|
||||
@"unreachable",
|
||||
/// Bitwise XOR. `^`
|
||||
xor,
|
||||
/// Create an optional type '?T'
|
||||
optional_type,
|
||||
|
||||
pub fn Type(tag: Tag) type {
|
||||
return switch (tag) {
|
||||
@@ -240,6 +242,7 @@ pub const Inst = struct {
|
||||
.typeof,
|
||||
.single_const_ptr_type,
|
||||
.single_mut_ptr_type,
|
||||
.optional_type,
|
||||
=> UnOp,
|
||||
|
||||
.add,
|
||||
@@ -372,6 +375,7 @@ pub const Inst = struct {
|
||||
.subwrap,
|
||||
.typeof,
|
||||
.xor,
|
||||
.optional_type,
|
||||
=> false,
|
||||
|
||||
.@"break",
|
||||
@@ -2242,6 +2246,20 @@ const EmitZIR = struct {
|
||||
std.debug.panic("TODO implement emitType for {}", .{ty});
|
||||
}
|
||||
},
|
||||
.Optional => {
|
||||
const inst = try self.arena.allocator.create(Inst.UnOp);
|
||||
inst.* = .{
|
||||
.base = .{
|
||||
.src = src,
|
||||
.tag = .optional_type,
|
||||
},
|
||||
.positionals = .{
|
||||
.operand = (try self.emitType(src, ty.elemType())).inst,
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
return self.emitUnnamedDecl(&inst.base);
|
||||
},
|
||||
else => std.debug.panic("TODO implement emitType for {}", .{ty}),
|
||||
},
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!
|
||||
.isnonnull => return analyzeInstIsNonNull(mod, scope, old_inst.castTag(.isnonnull).?, false),
|
||||
.boolnot => return analyzeInstBoolNot(mod, scope, old_inst.castTag(.boolnot).?),
|
||||
.typeof => return analyzeInstTypeOf(mod, scope, old_inst.castTag(.typeof).?),
|
||||
.optional_type => return analyzeInstOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -620,6 +621,34 @@ fn analyzeInstIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) I
|
||||
return mod.fail(scope, inttype.base.src, "TODO implement inttype", .{});
|
||||
}
|
||||
|
||||
fn analyzeInstOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst {
|
||||
const child_type = try resolveType(mod, scope, optional.positionals.operand);
|
||||
|
||||
return mod.constType(scope, optional.base.src, Type.initPayload(switch (child_type.tag()) {
|
||||
.single_const_pointer => blk: {
|
||||
const payload = try scope.arena().create(Type.Payload.OptionalSingleConstPointer);
|
||||
payload.* = .{
|
||||
.pointee_type = child_type.elemType(),
|
||||
};
|
||||
break :blk &payload.base;
|
||||
},
|
||||
.single_mut_pointer => blk: {
|
||||
const payload = try scope.arena().create(Type.Payload.OptionalSingleMutPointer);
|
||||
payload.* = .{
|
||||
.pointee_type = child_type.elemType(),
|
||||
};
|
||||
break :blk &payload.base;
|
||||
},
|
||||
else => blk: {
|
||||
const payload = try scope.arena().create(Type.Payload.Optional);
|
||||
payload.* = .{
|
||||
.child_type = child_type,
|
||||
};
|
||||
break :blk &payload.base;
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
fn analyzeInstFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType) InnerError!*Inst {
|
||||
const return_type = try resolveType(mod, scope, fntype.positionals.return_type);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user