self-hosted: implicit cast comptime ints to other ints
we now have successful exit codes from main linking against libcmaster
parent
33fbd8c1d3
commit
f5a67dba08
|
@ -139,7 +139,15 @@ pub const Inst = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn copyVal(base: *Inst, comp: *Compilation) !*Value {
|
||||||
|
if (base.parent.?.ref_count == 0) {
|
||||||
|
return base.val.KnownValue.derefAndCopy(comp);
|
||||||
|
}
|
||||||
|
return base.val.KnownValue.copy(comp);
|
||||||
|
}
|
||||||
|
|
||||||
fn getAsParam(param: *Inst) !*Inst {
|
fn getAsParam(param: *Inst) !*Inst {
|
||||||
|
param.ref_count -= 1;
|
||||||
const child = param.child orelse return error.SemanticAnalysisFailed;
|
const child = param.child orelse return error.SemanticAnalysisFailed;
|
||||||
switch (child.val) {
|
switch (child.val) {
|
||||||
IrVal.Unknown => return error.SemanticAnalysisFailed,
|
IrVal.Unknown => return error.SemanticAnalysisFailed,
|
||||||
|
@ -1715,8 +1723,37 @@ const Analyze = struct {
|
||||||
// }
|
// }
|
||||||
//}
|
//}
|
||||||
|
|
||||||
|
// cast from comptime-known integer to another integer where the value fits
|
||||||
|
if (target.isCompTime() and (from_type.id == Type.Id.Int or from_type.id == Type.Id.ComptimeInt)) cast: {
|
||||||
|
const target_val = target.val.KnownValue;
|
||||||
|
const from_int = &target_val.cast(Value.Int).?.big_int;
|
||||||
|
const fits = fits: {
|
||||||
|
if (dest_type.cast(Type.ComptimeInt)) |ctint| {
|
||||||
|
break :fits true;
|
||||||
|
}
|
||||||
|
if (dest_type.cast(Type.Int)) |int| {
|
||||||
|
break :fits (from_int.positive or from_int.eqZero() or int.key.is_signed) and
|
||||||
|
int.key.bit_count >= from_int.bitcount();
|
||||||
|
}
|
||||||
|
break :cast;
|
||||||
|
};
|
||||||
|
if (!fits) {
|
||||||
|
try ira.addCompileError(
|
||||||
|
source_instr.span,
|
||||||
|
"integer value '{}' cannot be stored in type '{}'",
|
||||||
|
from_int,
|
||||||
|
dest_type.name,
|
||||||
|
);
|
||||||
|
return error.SemanticAnalysisFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
const new_val = try target.copyVal(ira.irb.comp);
|
||||||
|
new_val.setType(dest_type, ira.irb.comp);
|
||||||
|
return ira.irb.buildConstValue(source_instr.scope, source_instr.span, new_val);
|
||||||
|
}
|
||||||
|
|
||||||
// cast from number literal to another type
|
// cast from number literal to another type
|
||||||
//// cast from number literal to *const integer
|
// cast from number literal to *const integer
|
||||||
//if (actual_type->id == TypeTableEntryIdComptimeFloat ||
|
//if (actual_type->id == TypeTableEntryIdComptimeFloat ||
|
||||||
// actual_type->id == TypeTableEntryIdComptimeInt)
|
// actual_type->id == TypeTableEntryIdComptimeInt)
|
||||||
//{
|
//{
|
||||||
|
|
|
@ -5,6 +5,7 @@ const Compilation = @import("compilation.zig").Compilation;
|
||||||
const ObjectFile = @import("codegen.zig").ObjectFile;
|
const ObjectFile = @import("codegen.zig").ObjectFile;
|
||||||
const llvm = @import("llvm.zig");
|
const llvm = @import("llvm.zig");
|
||||||
const Buffer = std.Buffer;
|
const Buffer = std.Buffer;
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
|
||||||
/// Values are ref-counted, heap-allocated, and copy-on-write
|
/// Values are ref-counted, heap-allocated, and copy-on-write
|
||||||
/// If there is only 1 ref then write need not copy
|
/// If there is only 1 ref then write need not copy
|
||||||
|
@ -34,6 +35,12 @@ pub const Value = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn setType(base: *Value, new_type: *Type, comp: *Compilation) void {
|
||||||
|
base.typeof.base.deref(comp);
|
||||||
|
new_type.base.ref();
|
||||||
|
base.typeof = new_type;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn getRef(base: *Value) *Value {
|
pub fn getRef(base: *Value) *Value {
|
||||||
base.ref();
|
base.ref();
|
||||||
return base;
|
return base;
|
||||||
|
@ -60,6 +67,28 @@ pub const Value = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn derefAndCopy(self: *Value, comp: *Compilation) (error{OutOfMemory}!*Value) {
|
||||||
|
if (self.ref_count.get() == 1) {
|
||||||
|
// ( ͡° ͜ʖ ͡°)
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(self.ref_count.decr() != 1);
|
||||||
|
return self.copy(comp);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy(base: *Value, comp: *Compilation) (error{OutOfMemory}!*Value) {
|
||||||
|
switch (base.id) {
|
||||||
|
Id.Type => unreachable,
|
||||||
|
Id.Fn => unreachable,
|
||||||
|
Id.Void => unreachable,
|
||||||
|
Id.Bool => unreachable,
|
||||||
|
Id.NoReturn => unreachable,
|
||||||
|
Id.Ptr => unreachable,
|
||||||
|
Id.Int => return &(try @fieldParentPtr(Int, "base", base).copy(comp)).base,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const Id = enum {
|
pub const Id = enum {
|
||||||
Type,
|
Type,
|
||||||
Fn,
|
Fn,
|
||||||
|
@ -256,6 +285,26 @@ pub const Value = struct {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn copy(old: *Int, comp: *Compilation) !*Int {
|
||||||
|
old.base.typeof.base.ref();
|
||||||
|
errdefer old.base.typeof.base.deref(comp);
|
||||||
|
|
||||||
|
const new = try comp.gpa().create(Value.Int{
|
||||||
|
.base = Value{
|
||||||
|
.id = Value.Id.Int,
|
||||||
|
.typeof = old.base.typeof,
|
||||||
|
.ref_count = std.atomic.Int(usize).init(1),
|
||||||
|
},
|
||||||
|
.big_int = undefined,
|
||||||
|
});
|
||||||
|
errdefer comp.gpa().destroy(new);
|
||||||
|
|
||||||
|
new.big_int = try old.big_int.clone();
|
||||||
|
errdefer new.big_int.deinit();
|
||||||
|
|
||||||
|
return new;
|
||||||
|
}
|
||||||
|
|
||||||
pub fn destroy(self: *Int, comp: *Compilation) void {
|
pub fn destroy(self: *Int, comp: *Compilation) void {
|
||||||
self.big_int.deinit();
|
self.big_int.deinit();
|
||||||
comp.gpa().destroy(self);
|
comp.gpa().destroy(self);
|
||||||
|
|
|
@ -118,7 +118,7 @@ pub const Int = struct {
|
||||||
|
|
||||||
fn bitcount(self: Int) usize {
|
fn bitcount(self: Int) usize {
|
||||||
const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
|
const u_bit_count = (self.len - 1) * Limb.bit_count + (Limb.bit_count - @clz(self.limbs[self.len - 1]));
|
||||||
return usize(@boolToInt(!self.positive)) + u_bit_count;
|
return @boolToInt(!self.positive) + u_bit_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn sizeInBase(self: Int, base: usize) usize {
|
pub fn sizeInBase(self: Int, base: usize) usize {
|
||||||
|
@ -275,6 +275,7 @@ pub const Int = struct {
|
||||||
self.positive = positive;
|
self.positive = positive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO make this call format instead of the other way around
|
||||||
pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 {
|
pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 {
|
||||||
if (base < 2 or base > 16) {
|
if (base < 2 or base > 16) {
|
||||||
return error.InvalidBase;
|
return error.InvalidBase;
|
||||||
|
@ -357,6 +358,21 @@ pub const Int = struct {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// for the std lib format function
|
||||||
|
/// TODO make this non-allocating
|
||||||
|
pub fn format(
|
||||||
|
self: Int,
|
||||||
|
comptime fmt: []const u8,
|
||||||
|
context: var,
|
||||||
|
comptime FmtError: type,
|
||||||
|
output: fn (@typeOf(context), []const u8) FmtError!void,
|
||||||
|
) FmtError!void {
|
||||||
|
// TODO look at fmt and support other bases
|
||||||
|
const str = self.toString(self.allocator, 10) catch @panic("TODO make this non allocating");
|
||||||
|
defer self.allocator.free(str);
|
||||||
|
return output(context, str);
|
||||||
|
}
|
||||||
|
|
||||||
// returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
|
// returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
|
||||||
pub fn cmpAbs(a: Int, b: Int) i8 {
|
pub fn cmpAbs(a: Int, b: Int) i8 {
|
||||||
if (a.len < b.len) {
|
if (a.len < b.len) {
|
||||||
|
|
|
@ -21,4 +21,10 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||||
\\ defer return;
|
\\ defer return;
|
||||||
\\}
|
\\}
|
||||||
, "1.zig", 2, 11, "cannot return from defer expression");
|
, "1.zig", 2, 11, "cannot return from defer expression");
|
||||||
|
|
||||||
|
try ctx.testCompileError(
|
||||||
|
\\export fn entry() c_int {
|
||||||
|
\\ return 36893488147419103232;
|
||||||
|
\\}
|
||||||
|
, "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue