mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 05:44:20 +00:00
commit
317722b37b
145 changed files with 8788 additions and 432 deletions
|
|
@ -406,7 +406,7 @@ pub fn build(b: *std.Build) !void {
|
|||
const optimization_modes = chosen_opt_modes_buf[0..chosen_mode_index];
|
||||
|
||||
const fmt_include_paths = &.{ "lib", "src", "test", "tools", "build.zig", "build.zig.zon" };
|
||||
const fmt_exclude_paths = &.{"test/cases"};
|
||||
const fmt_exclude_paths = &.{ "test/cases", "test/behavior/zon" };
|
||||
const do_fmt = b.addFmt(.{
|
||||
.paths = fmt_include_paths,
|
||||
.exclude_paths = fmt_exclude_paths,
|
||||
|
|
|
|||
2
lib/compiler/aro/aro/Value.zig
vendored
2
lib/compiler/aro/aro/Value.zig
vendored
|
|
@ -473,7 +473,7 @@ pub fn toInt(v: Value, comptime T: type, comp: *const Compilation) ?T {
|
|||
if (comp.interner.get(v.ref()) != .int) return null;
|
||||
var space: BigIntSpace = undefined;
|
||||
const big_int = v.toBigInt(&space, comp);
|
||||
return big_int.to(T) catch null;
|
||||
return big_int.toInt(T) catch null;
|
||||
}
|
||||
|
||||
const ComplexOp = enum {
|
||||
|
|
|
|||
4
lib/compiler/aro/backend/Interner.zig
vendored
4
lib/compiler/aro/backend/Interner.zig
vendored
|
|
@ -628,13 +628,13 @@ pub fn put(i: *Interner, gpa: Allocator, key: Key) !Ref {
|
|||
if (data.fitsInTwosComp(.unsigned, 32)) {
|
||||
i.items.appendAssumeCapacity(.{
|
||||
.tag = .u32,
|
||||
.data = data.to(u32) catch unreachable,
|
||||
.data = data.toInt(u32) catch unreachable,
|
||||
});
|
||||
break :int;
|
||||
} else if (data.fitsInTwosComp(.signed, 32)) {
|
||||
i.items.appendAssumeCapacity(.{
|
||||
.tag = .i32,
|
||||
.data = @bitCast(data.to(i32) catch unreachable),
|
||||
.data = @bitCast(data.toInt(i32) catch unreachable),
|
||||
});
|
||||
break :int;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1235,6 +1235,8 @@ test "shrink large object to large object" {
|
|||
}
|
||||
|
||||
test "shrink large object to large object with larger alignment" {
|
||||
if (!builtin.link_libc and builtin.os.tag == .wasi) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/22731
|
||||
|
||||
var gpa = GeneralPurposeAllocator(test_config){};
|
||||
defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");
|
||||
const allocator = gpa.allocator();
|
||||
|
|
@ -1307,6 +1309,8 @@ test "non-page-allocator backing allocator" {
|
|||
}
|
||||
|
||||
test "realloc large object to larger alignment" {
|
||||
if (!builtin.link_libc and builtin.os.tag == .wasi) return error.SkipZigTest; // https://github.com/ziglang/zig/issues/22731
|
||||
|
||||
var gpa = GeneralPurposeAllocator(test_config){};
|
||||
defer std.testing.expect(gpa.deinit() == .ok) catch @panic("leak");
|
||||
const allocator = gpa.allocator();
|
||||
|
|
|
|||
|
|
@ -2175,10 +2175,13 @@ pub const Const = struct {
|
|||
TargetTooSmall,
|
||||
};
|
||||
|
||||
/// Convert self to type T.
|
||||
/// Deprecated; use `toInt`.
|
||||
pub const to = toInt;
|
||||
|
||||
/// Convert self to integer type T.
|
||||
///
|
||||
/// Returns an error if self cannot be narrowed into the requested type without truncation.
|
||||
pub fn to(self: Const, comptime T: type) ConvertError!T {
|
||||
pub fn toInt(self: Const, comptime T: type) ConvertError!T {
|
||||
switch (@typeInfo(T)) {
|
||||
.int => |info| {
|
||||
// Make sure -0 is handled correctly.
|
||||
|
|
@ -2216,7 +2219,26 @@ pub const Const = struct {
|
|||
}
|
||||
}
|
||||
},
|
||||
else => @compileError("cannot convert Const to type " ++ @typeName(T)),
|
||||
else => @compileError("expected int type, found '" ++ @typeName(T) ++ "'"),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert self to float type T.
|
||||
pub fn toFloat(self: Const, comptime T: type) T {
|
||||
if (self.limbs.len == 0) return 0;
|
||||
|
||||
const base = std.math.maxInt(std.math.big.Limb) + 1;
|
||||
var result: f128 = 0;
|
||||
var i: usize = self.limbs.len;
|
||||
while (i != 0) {
|
||||
i -= 1;
|
||||
const limb: f128 = @floatFromInt(self.limbs[i]);
|
||||
result = @mulAdd(f128, base, result, limb);
|
||||
}
|
||||
if (self.positive) {
|
||||
return @floatCast(result);
|
||||
} else {
|
||||
return @floatCast(-result);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2775,11 +2797,19 @@ pub const Managed = struct {
|
|||
|
||||
pub const ConvertError = Const.ConvertError;
|
||||
|
||||
/// Convert self to type T.
|
||||
/// Deprecated; use `toInt`.
|
||||
pub const to = toInt;
|
||||
|
||||
/// Convert self to integer type T.
|
||||
///
|
||||
/// Returns an error if self cannot be narrowed into the requested type without truncation.
|
||||
pub fn to(self: Managed, comptime T: type) ConvertError!T {
|
||||
return self.toConst().to(T);
|
||||
pub fn toInt(self: Managed, comptime T: type) ConvertError!T {
|
||||
return self.toConst().toInt(T);
|
||||
}
|
||||
|
||||
/// Convert self to float type T.
|
||||
pub fn toFloat(self: Managed, comptime T: type) T {
|
||||
return self.toConst().toFloat(T);
|
||||
}
|
||||
|
||||
/// Set self from the string representation `value`.
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -518,28 +518,28 @@ test "set" {
|
|||
defer a.deinit();
|
||||
|
||||
try a.setInt(5);
|
||||
try testing.expect((try a.p.to(u32)) == 5);
|
||||
try testing.expect((try a.q.to(u32)) == 1);
|
||||
try testing.expect((try a.p.toInt(u32)) == 5);
|
||||
try testing.expect((try a.q.toInt(u32)) == 1);
|
||||
|
||||
try a.setRatio(7, 3);
|
||||
try testing.expect((try a.p.to(u32)) == 7);
|
||||
try testing.expect((try a.q.to(u32)) == 3);
|
||||
try testing.expect((try a.p.toInt(u32)) == 7);
|
||||
try testing.expect((try a.q.toInt(u32)) == 3);
|
||||
|
||||
try a.setRatio(9, 3);
|
||||
try testing.expect((try a.p.to(i32)) == 3);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == 3);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
|
||||
try a.setRatio(-9, 3);
|
||||
try testing.expect((try a.p.to(i32)) == -3);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == -3);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
|
||||
try a.setRatio(9, -3);
|
||||
try testing.expect((try a.p.to(i32)) == -3);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == -3);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
|
||||
try a.setRatio(-9, -3);
|
||||
try testing.expect((try a.p.to(i32)) == 3);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == 3);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
}
|
||||
|
||||
test "setFloat" {
|
||||
|
|
@ -547,24 +547,24 @@ test "setFloat" {
|
|||
defer a.deinit();
|
||||
|
||||
try a.setFloat(f64, 2.5);
|
||||
try testing.expect((try a.p.to(i32)) == 5);
|
||||
try testing.expect((try a.q.to(i32)) == 2);
|
||||
try testing.expect((try a.p.toInt(i32)) == 5);
|
||||
try testing.expect((try a.q.toInt(i32)) == 2);
|
||||
|
||||
try a.setFloat(f32, -2.5);
|
||||
try testing.expect((try a.p.to(i32)) == -5);
|
||||
try testing.expect((try a.q.to(i32)) == 2);
|
||||
try testing.expect((try a.p.toInt(i32)) == -5);
|
||||
try testing.expect((try a.q.toInt(i32)) == 2);
|
||||
|
||||
try a.setFloat(f32, 3.141593);
|
||||
|
||||
// = 3.14159297943115234375
|
||||
try testing.expect((try a.p.to(u32)) == 3294199);
|
||||
try testing.expect((try a.q.to(u32)) == 1048576);
|
||||
try testing.expect((try a.p.toInt(u32)) == 3294199);
|
||||
try testing.expect((try a.q.toInt(u32)) == 1048576);
|
||||
|
||||
try a.setFloat(f64, 72.141593120712409172417410926841290461290467124);
|
||||
|
||||
// = 72.1415931207124145885245525278151035308837890625
|
||||
try testing.expect((try a.p.to(u128)) == 5076513310880537);
|
||||
try testing.expect((try a.q.to(u128)) == 70368744177664);
|
||||
try testing.expect((try a.p.toInt(u128)) == 5076513310880537);
|
||||
try testing.expect((try a.q.toInt(u128)) == 70368744177664);
|
||||
}
|
||||
|
||||
test "setFloatString" {
|
||||
|
|
@ -574,8 +574,8 @@ test "setFloatString" {
|
|||
try a.setFloatString("72.14159312071241458852455252781510353");
|
||||
|
||||
// = 72.1415931207124145885245525278151035308837890625
|
||||
try testing.expect((try a.p.to(u128)) == 7214159312071241458852455252781510353);
|
||||
try testing.expect((try a.q.to(u128)) == 100000000000000000000000000000000000);
|
||||
try testing.expect((try a.p.toInt(u128)) == 7214159312071241458852455252781510353);
|
||||
try testing.expect((try a.q.toInt(u128)) == 100000000000000000000000000000000000);
|
||||
}
|
||||
|
||||
test "toFloat" {
|
||||
|
|
@ -612,8 +612,8 @@ test "copy" {
|
|||
defer b.deinit();
|
||||
|
||||
try a.copyInt(b);
|
||||
try testing.expect((try a.p.to(u32)) == 5);
|
||||
try testing.expect((try a.q.to(u32)) == 1);
|
||||
try testing.expect((try a.p.toInt(u32)) == 5);
|
||||
try testing.expect((try a.q.toInt(u32)) == 1);
|
||||
|
||||
var c = try Int.initSet(testing.allocator, 7);
|
||||
defer c.deinit();
|
||||
|
|
@ -621,8 +621,8 @@ test "copy" {
|
|||
defer d.deinit();
|
||||
|
||||
try a.copyRatio(c, d);
|
||||
try testing.expect((try a.p.to(u32)) == 7);
|
||||
try testing.expect((try a.q.to(u32)) == 3);
|
||||
try testing.expect((try a.p.toInt(u32)) == 7);
|
||||
try testing.expect((try a.q.toInt(u32)) == 3);
|
||||
|
||||
var e = try Int.initSet(testing.allocator, 9);
|
||||
defer e.deinit();
|
||||
|
|
@ -630,8 +630,8 @@ test "copy" {
|
|||
defer f.deinit();
|
||||
|
||||
try a.copyRatio(e, f);
|
||||
try testing.expect((try a.p.to(u32)) == 3);
|
||||
try testing.expect((try a.q.to(u32)) == 1);
|
||||
try testing.expect((try a.p.toInt(u32)) == 3);
|
||||
try testing.expect((try a.q.toInt(u32)) == 1);
|
||||
}
|
||||
|
||||
test "negate" {
|
||||
|
|
@ -639,16 +639,16 @@ test "negate" {
|
|||
defer a.deinit();
|
||||
|
||||
try a.setInt(-50);
|
||||
try testing.expect((try a.p.to(i32)) == -50);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == -50);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
|
||||
a.negate();
|
||||
try testing.expect((try a.p.to(i32)) == 50);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == 50);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
|
||||
a.negate();
|
||||
try testing.expect((try a.p.to(i32)) == -50);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == -50);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
}
|
||||
|
||||
test "abs" {
|
||||
|
|
@ -656,16 +656,16 @@ test "abs" {
|
|||
defer a.deinit();
|
||||
|
||||
try a.setInt(-50);
|
||||
try testing.expect((try a.p.to(i32)) == -50);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == -50);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
|
||||
a.abs();
|
||||
try testing.expect((try a.p.to(i32)) == 50);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == 50);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
|
||||
a.abs();
|
||||
try testing.expect((try a.p.to(i32)) == 50);
|
||||
try testing.expect((try a.q.to(i32)) == 1);
|
||||
try testing.expect((try a.p.toInt(i32)) == 50);
|
||||
try testing.expect((try a.q.toInt(i32)) == 1);
|
||||
}
|
||||
|
||||
test "swap" {
|
||||
|
|
@ -677,19 +677,19 @@ test "swap" {
|
|||
try a.setRatio(50, 23);
|
||||
try b.setRatio(17, 3);
|
||||
|
||||
try testing.expect((try a.p.to(u32)) == 50);
|
||||
try testing.expect((try a.q.to(u32)) == 23);
|
||||
try testing.expect((try a.p.toInt(u32)) == 50);
|
||||
try testing.expect((try a.q.toInt(u32)) == 23);
|
||||
|
||||
try testing.expect((try b.p.to(u32)) == 17);
|
||||
try testing.expect((try b.q.to(u32)) == 3);
|
||||
try testing.expect((try b.p.toInt(u32)) == 17);
|
||||
try testing.expect((try b.q.toInt(u32)) == 3);
|
||||
|
||||
a.swap(&b);
|
||||
|
||||
try testing.expect((try a.p.to(u32)) == 17);
|
||||
try testing.expect((try a.q.to(u32)) == 3);
|
||||
try testing.expect((try a.p.toInt(u32)) == 17);
|
||||
try testing.expect((try a.q.toInt(u32)) == 3);
|
||||
|
||||
try testing.expect((try b.p.to(u32)) == 50);
|
||||
try testing.expect((try b.q.to(u32)) == 23);
|
||||
try testing.expect((try b.p.toInt(u32)) == 50);
|
||||
try testing.expect((try b.q.toInt(u32)) == 23);
|
||||
}
|
||||
|
||||
test "order" {
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ pub const valgrind = @import("valgrind.zig");
|
|||
pub const wasm = @import("wasm.zig");
|
||||
pub const zig = @import("zig.zig");
|
||||
pub const zip = @import("zip.zig");
|
||||
pub const zon = @import("zon.zig");
|
||||
pub const start = @import("start.zig");
|
||||
|
||||
const root = @import("root");
|
||||
|
|
|
|||
|
|
@ -9448,7 +9448,18 @@ fn builtinCall(
|
|||
} else if (str.len == 0) {
|
||||
return astgen.failTok(str_lit_token, "import path cannot be empty", .{});
|
||||
}
|
||||
const result = try gz.addStrTok(.import, str.index, str_lit_token);
|
||||
const res_ty = try ri.rl.resultType(gz, node) orelse .none;
|
||||
const payload_index = try addExtra(gz.astgen, Zir.Inst.Import{
|
||||
.res_ty = res_ty,
|
||||
.path = str.index,
|
||||
});
|
||||
const result = try gz.add(.{
|
||||
.tag = .import,
|
||||
.data = .{ .pl_tok = .{
|
||||
.src_tok = gz.tokenIndexToRelative(str_lit_token),
|
||||
.payload_index = payload_index,
|
||||
} },
|
||||
});
|
||||
const gop = try astgen.imports.getOrPut(astgen.gpa, str.index);
|
||||
if (!gop.found_existing) {
|
||||
gop.value_ptr.* = str_lit_token;
|
||||
|
|
@ -11551,9 +11562,21 @@ fn parseStrLit(
|
|||
}
|
||||
}
|
||||
|
||||
fn failWithStrLitError(astgen: *AstGen, err: std.zig.string_literal.Error, token: Ast.TokenIndex, bytes: []const u8, offset: u32) InnerError {
|
||||
fn failWithStrLitError(
|
||||
astgen: *AstGen,
|
||||
err: std.zig.string_literal.Error,
|
||||
token: Ast.TokenIndex,
|
||||
bytes: []const u8,
|
||||
offset: u32,
|
||||
) InnerError {
|
||||
const raw_string = bytes[offset..];
|
||||
return err.lower(raw_string, offset, AstGen.failOff, .{ astgen, token });
|
||||
return failOff(
|
||||
astgen,
|
||||
token,
|
||||
@intCast(offset + err.offset()),
|
||||
"{}",
|
||||
.{err.fmt(raw_string)},
|
||||
);
|
||||
}
|
||||
|
||||
fn failNode(
|
||||
|
|
|
|||
|
|
@ -483,7 +483,7 @@ pub const Inst = struct {
|
|||
/// Uses the `pl_node` union field. `payload_index` points to a `FuncFancy`.
|
||||
func_fancy,
|
||||
/// Implements the `@import` builtin.
|
||||
/// Uses the `str_tok` field.
|
||||
/// Uses the `pl_tok` field.
|
||||
import,
|
||||
/// Integer literal that fits in a u64. Uses the `int` union field.
|
||||
int,
|
||||
|
|
@ -1673,7 +1673,7 @@ pub const Inst = struct {
|
|||
.func = .pl_node,
|
||||
.func_inferred = .pl_node,
|
||||
.func_fancy = .pl_node,
|
||||
.import = .str_tok,
|
||||
.import = .pl_tok,
|
||||
.int = .int,
|
||||
.int_big = .str,
|
||||
.float = .float,
|
||||
|
|
@ -3841,6 +3841,13 @@ pub const Inst = struct {
|
|||
/// If `.none`, restore unconditionally.
|
||||
operand: Ref,
|
||||
};
|
||||
|
||||
pub const Import = struct {
|
||||
/// The result type of the import, or `.none` if none was available.
|
||||
res_ty: Ref,
|
||||
/// The import path.
|
||||
path: NullTerminatedString,
|
||||
};
|
||||
};
|
||||
|
||||
pub const SpecialProng = enum { none, @"else", under };
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ pub const Node = union(enum) {
|
|||
/// A floating-point literal.
|
||||
float_literal: f128,
|
||||
/// A Unicode codepoint literal.
|
||||
char_literal: u32,
|
||||
char_literal: u21,
|
||||
/// An enum literal. The string is the literal, i.e. `foo` for `.foo`.
|
||||
enum_literal: NullTerminatedString,
|
||||
/// A string literal.
|
||||
|
|
@ -96,7 +96,7 @@ pub const Node = union(enum) {
|
|||
} } },
|
||||
.float_literal_small => .{ .float_literal = @as(f32, @bitCast(repr.data)) },
|
||||
.float_literal => .{ .float_literal = @bitCast(zoir.extra[repr.data..][0..4].*) },
|
||||
.char_literal => .{ .char_literal = repr.data },
|
||||
.char_literal => .{ .char_literal = @intCast(repr.data) },
|
||||
.enum_literal => .{ .enum_literal = @enumFromInt(repr.data) },
|
||||
.string_literal => .{ .string_literal = s: {
|
||||
const start, const len = zoir.extra[repr.data..][0..2].*;
|
||||
|
|
|
|||
|
|
@ -3,6 +3,8 @@
|
|||
gpa: Allocator,
|
||||
tree: Ast,
|
||||
|
||||
options: Options,
|
||||
|
||||
nodes: std.MultiArrayList(Zoir.Node.Repr),
|
||||
extra: std.ArrayListUnmanaged(u32),
|
||||
limbs: std.ArrayListUnmanaged(std.math.big.Limb),
|
||||
|
|
@ -12,12 +14,21 @@ string_table: std.HashMapUnmanaged(u32, void, StringIndexContext, std.hash_map.d
|
|||
compile_errors: std.ArrayListUnmanaged(Zoir.CompileError),
|
||||
error_notes: std.ArrayListUnmanaged(Zoir.CompileError.Note),
|
||||
|
||||
pub fn generate(gpa: Allocator, tree: Ast) Allocator.Error!Zoir {
|
||||
pub const Options = struct {
|
||||
/// When false, string literals are not parsed. `string_literal` nodes will contain empty
|
||||
/// strings, and errors that normally occur during string parsing will not be raised.
|
||||
///
|
||||
/// `parseStrLit` and `strLitSizeHint` may be used to parse string literals after the fact.
|
||||
parse_str_lits: bool = true,
|
||||
};
|
||||
|
||||
pub fn generate(gpa: Allocator, tree: Ast, options: Options) Allocator.Error!Zoir {
|
||||
assert(tree.mode == .zon);
|
||||
|
||||
var zg: ZonGen = .{
|
||||
.gpa = gpa,
|
||||
.tree = tree,
|
||||
.options = options,
|
||||
.nodes = .empty,
|
||||
.extra = .empty,
|
||||
.limbs = .empty,
|
||||
|
|
@ -250,7 +261,20 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator
|
|||
.block_two_semicolon,
|
||||
.block,
|
||||
.block_semicolon,
|
||||
=> try zg.addErrorNode(node, "blocks are not allowed in ZON", .{}),
|
||||
=> {
|
||||
const size = switch (node_tags[node]) {
|
||||
.block_two, .block_two_semicolon => @intFromBool(node_datas[node].lhs != 0) + @intFromBool(node_datas[node].rhs != 0),
|
||||
.block, .block_semicolon => node_datas[node].rhs - node_datas[node].lhs,
|
||||
else => unreachable,
|
||||
};
|
||||
if (size == 0) {
|
||||
try zg.addErrorNodeNotes(node, "void literals are not available in ZON", .{}, &.{
|
||||
try zg.errNoteNode(node, "void union payloads can be represented by enum literals", .{}),
|
||||
});
|
||||
} else {
|
||||
try zg.addErrorNode(node, "blocks are not allowed in ZON", .{});
|
||||
}
|
||||
},
|
||||
|
||||
.array_init_one,
|
||||
.array_init_one_comma,
|
||||
|
|
@ -403,58 +427,37 @@ fn expr(zg: *ZonGen, node: Ast.Node.Index, dest_node: Zoir.Node.Index) Allocator
|
|||
.ast_node = node,
|
||||
});
|
||||
|
||||
// For short initializers, track the names on the stack rather than going through gpa.
|
||||
var sfba_state = std.heap.stackFallback(256, gpa);
|
||||
const sfba = sfba_state.get();
|
||||
var field_names: std.AutoHashMapUnmanaged(Zoir.NullTerminatedString, Ast.TokenIndex) = .empty;
|
||||
defer field_names.deinit(sfba);
|
||||
|
||||
var reported_any_duplicate = false;
|
||||
|
||||
for (full.ast.fields, names_start.., first_elem..) |elem_node, extra_name_idx, elem_dest_node| {
|
||||
const name_token = tree.firstToken(elem_node) - 2;
|
||||
zg.extra.items[extra_name_idx] = @intFromEnum(zg.identAsString(name_token) catch |err| switch (err) {
|
||||
error.BadString => undefined, // doesn't matter, there's an error
|
||||
if (zg.identAsString(name_token)) |name_str| {
|
||||
zg.extra.items[extra_name_idx] = @intFromEnum(name_str);
|
||||
const gop = try field_names.getOrPut(sfba, name_str);
|
||||
if (gop.found_existing and !reported_any_duplicate) {
|
||||
reported_any_duplicate = true;
|
||||
const earlier_token = gop.value_ptr.*;
|
||||
try zg.addErrorTokNotes(earlier_token, "duplicate struct field name", .{}, &.{
|
||||
try zg.errNoteTok(name_token, "duplicate name here", .{}),
|
||||
});
|
||||
}
|
||||
gop.value_ptr.* = name_token;
|
||||
} else |err| switch (err) {
|
||||
error.BadString => {}, // there's an error, so it's fine to not populate `zg.extra`
|
||||
error.OutOfMemory => |e| return e,
|
||||
});
|
||||
}
|
||||
try zg.expr(elem_node, @enumFromInt(elem_dest_node));
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn parseStrLit(zg: *ZonGen, token: Ast.TokenIndex, offset: u32) !u32 {
|
||||
const raw_string = zg.tree.tokenSlice(token)[offset..];
|
||||
const start = zg.string_bytes.items.len;
|
||||
switch (try std.zig.string_literal.parseWrite(zg.string_bytes.writer(zg.gpa), raw_string)) {
|
||||
.success => return @intCast(start),
|
||||
.failure => |err| {
|
||||
try zg.lowerStrLitError(err, token, raw_string, offset);
|
||||
return error.BadString;
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn parseMultilineStrLit(zg: *ZonGen, node: Ast.Node.Index) !u32 {
|
||||
const gpa = zg.gpa;
|
||||
const tree = zg.tree;
|
||||
const string_bytes = &zg.string_bytes;
|
||||
|
||||
const first_tok, const last_tok = bounds: {
|
||||
const node_data = tree.nodes.items(.data)[node];
|
||||
break :bounds .{ node_data.lhs, node_data.rhs };
|
||||
};
|
||||
|
||||
const str_index: u32 = @intCast(string_bytes.items.len);
|
||||
|
||||
// First line: do not append a newline.
|
||||
{
|
||||
const line_bytes = tree.tokenSlice(first_tok)[2..];
|
||||
try string_bytes.appendSlice(gpa, line_bytes);
|
||||
}
|
||||
// Following lines: each line prepends a newline.
|
||||
for (first_tok + 1..last_tok + 1) |tok_idx| {
|
||||
const line_bytes = tree.tokenSlice(@intCast(tok_idx))[2..];
|
||||
try string_bytes.ensureUnusedCapacity(gpa, line_bytes.len + 1);
|
||||
string_bytes.appendAssumeCapacity('\n');
|
||||
string_bytes.appendSliceAssumeCapacity(line_bytes);
|
||||
}
|
||||
|
||||
return @intCast(str_index);
|
||||
}
|
||||
|
||||
fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) !u32 {
|
||||
const tree = zg.tree;
|
||||
assert(tree.tokens.items(.tag)[ident_token] == .identifier);
|
||||
|
|
@ -464,7 +467,18 @@ fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) !u32 {
|
|||
try zg.string_bytes.appendSlice(zg.gpa, ident_name);
|
||||
return @intCast(start);
|
||||
} else {
|
||||
const start = try zg.parseStrLit(ident_token, 1);
|
||||
const offset = 1;
|
||||
const start: u32 = @intCast(zg.string_bytes.items.len);
|
||||
const raw_string = zg.tree.tokenSlice(ident_token)[offset..];
|
||||
try zg.string_bytes.ensureUnusedCapacity(zg.gpa, raw_string.len);
|
||||
switch (try std.zig.string_literal.parseWrite(zg.string_bytes.writer(zg.gpa), raw_string)) {
|
||||
.success => {},
|
||||
.failure => |err| {
|
||||
try zg.lowerStrLitError(err, ident_token, raw_string, offset);
|
||||
return error.BadString;
|
||||
},
|
||||
}
|
||||
|
||||
const slice = zg.string_bytes.items[start..];
|
||||
if (mem.indexOfScalar(u8, slice, 0) != null) {
|
||||
try zg.addErrorTok(ident_token, "identifier cannot contain null bytes", .{});
|
||||
|
|
@ -477,19 +491,93 @@ fn appendIdentStr(zg: *ZonGen, ident_token: Ast.TokenIndex) !u32 {
|
|||
}
|
||||
}
|
||||
|
||||
/// Estimates the size of a string node without parsing it.
|
||||
pub fn strLitSizeHint(tree: Ast, node: Ast.Node.Index) usize {
|
||||
switch (tree.nodes.items(.tag)[node]) {
|
||||
// Parsed string literals are typically around the size of the raw strings.
|
||||
.string_literal => {
|
||||
const token = tree.nodes.items(.main_token)[node];
|
||||
const raw_string = tree.tokenSlice(token);
|
||||
return raw_string.len;
|
||||
},
|
||||
// Multiline string literal lengths can be computed exactly.
|
||||
.multiline_string_literal => {
|
||||
const first_tok, const last_tok = bounds: {
|
||||
const node_data = tree.nodes.items(.data)[node];
|
||||
break :bounds .{ node_data.lhs, node_data.rhs };
|
||||
};
|
||||
|
||||
var size = tree.tokenSlice(first_tok)[2..].len;
|
||||
for (first_tok + 1..last_tok + 1) |tok_idx| {
|
||||
size += 1; // Newline
|
||||
size += tree.tokenSlice(@intCast(tok_idx))[2..].len;
|
||||
}
|
||||
return size;
|
||||
},
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
/// Parses the given node as a string literal.
|
||||
pub fn parseStrLit(
|
||||
tree: Ast,
|
||||
node: Ast.Node.Index,
|
||||
writer: anytype,
|
||||
) error{OutOfMemory}!std.zig.string_literal.Result {
|
||||
switch (tree.nodes.items(.tag)[node]) {
|
||||
.string_literal => {
|
||||
const token = tree.nodes.items(.main_token)[node];
|
||||
const raw_string = tree.tokenSlice(token);
|
||||
return std.zig.string_literal.parseWrite(writer, raw_string);
|
||||
},
|
||||
.multiline_string_literal => {
|
||||
const first_tok, const last_tok = bounds: {
|
||||
const node_data = tree.nodes.items(.data)[node];
|
||||
break :bounds .{ node_data.lhs, node_data.rhs };
|
||||
};
|
||||
|
||||
// First line: do not append a newline.
|
||||
{
|
||||
const line_bytes = tree.tokenSlice(first_tok)[2..];
|
||||
try writer.writeAll(line_bytes);
|
||||
}
|
||||
|
||||
// Following lines: each line prepends a newline.
|
||||
for (first_tok + 1..last_tok + 1) |tok_idx| {
|
||||
const line_bytes = tree.tokenSlice(@intCast(tok_idx))[2..];
|
||||
try writer.writeByte('\n');
|
||||
try writer.writeAll(line_bytes);
|
||||
}
|
||||
|
||||
return .success;
|
||||
},
|
||||
// Node must represent a string
|
||||
else => unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
const StringLiteralResult = union(enum) {
|
||||
nts: Zoir.NullTerminatedString,
|
||||
slice: struct { start: u32, len: u32 },
|
||||
};
|
||||
|
||||
fn strLitAsString(zg: *ZonGen, str_node: Ast.Node.Index) !StringLiteralResult {
|
||||
if (!zg.options.parse_str_lits) return .{ .slice = .{ .start = 0, .len = 0 } };
|
||||
|
||||
const gpa = zg.gpa;
|
||||
const string_bytes = &zg.string_bytes;
|
||||
const str_index = switch (zg.tree.nodes.items(.tag)[str_node]) {
|
||||
.string_literal => try zg.parseStrLit(zg.tree.nodes.items(.main_token)[str_node], 0),
|
||||
.multiline_string_literal => try zg.parseMultilineStrLit(str_node),
|
||||
else => unreachable,
|
||||
};
|
||||
const str_index: u32 = @intCast(zg.string_bytes.items.len);
|
||||
const size_hint = strLitSizeHint(zg.tree, str_node);
|
||||
try string_bytes.ensureUnusedCapacity(zg.gpa, size_hint);
|
||||
switch (try parseStrLit(zg.tree, str_node, zg.string_bytes.writer(zg.gpa))) {
|
||||
.success => {},
|
||||
.failure => |err| {
|
||||
const token = zg.tree.nodes.items(.main_token)[str_node];
|
||||
const raw_string = zg.tree.tokenSlice(token);
|
||||
try zg.lowerStrLitError(err, token, raw_string, 0);
|
||||
return error.BadString;
|
||||
},
|
||||
}
|
||||
const key: []const u8 = string_bytes.items[str_index..];
|
||||
if (std.mem.indexOfScalar(u8, key, 0) != null) return .{ .slice = .{
|
||||
.start = str_index,
|
||||
|
|
@ -540,7 +628,7 @@ fn numberLiteral(zg: *ZonGen, num_node: Ast.Node.Index, src_node: Ast.Node.Index
|
|||
if (unsigned_num == 0 and sign == .negative) {
|
||||
try zg.addErrorTokNotes(num_token, "integer literal '-0' is ambiguous", .{}, &.{
|
||||
try zg.errNoteTok(num_token, "use '0' for an integer zero", .{}),
|
||||
try zg.errNoteTok(num_token, "use '-0.0' for a flaoting-point signed zero", .{}),
|
||||
try zg.errNoteTok(num_token, "use '-0.0' for a floating-point signed zero", .{}),
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
@ -679,8 +767,20 @@ fn setNode(zg: *ZonGen, dest: Zoir.Node.Index, repr: Zoir.Node.Repr) void {
|
|||
zg.nodes.set(@intFromEnum(dest), repr);
|
||||
}
|
||||
|
||||
fn lowerStrLitError(zg: *ZonGen, err: std.zig.string_literal.Error, token: Ast.TokenIndex, raw_string: []const u8, offset: u32) Allocator.Error!void {
|
||||
return err.lower(raw_string, offset, ZonGen.addErrorTokOff, .{ zg, token });
|
||||
fn lowerStrLitError(
|
||||
zg: *ZonGen,
|
||||
err: std.zig.string_literal.Error,
|
||||
token: Ast.TokenIndex,
|
||||
raw_string: []const u8,
|
||||
offset: u32,
|
||||
) Allocator.Error!void {
|
||||
return ZonGen.addErrorTokOff(
|
||||
zg,
|
||||
token,
|
||||
@intCast(offset + err.offset()),
|
||||
"{}",
|
||||
.{err.fmt(raw_string)},
|
||||
);
|
||||
}
|
||||
|
||||
fn lowerNumberError(zg: *ZonGen, err: std.zig.number_literal.Error, token: Ast.TokenIndex, bytes: []const u8) Allocator.Error!void {
|
||||
|
|
|
|||
|
|
@ -39,40 +39,82 @@ pub const Error = union(enum) {
|
|||
/// `''`. Not returned for string literals.
|
||||
empty_char_literal,
|
||||
|
||||
/// Returns `func(first_args[0], ..., first_args[n], offset + bad_idx, format, args)`.
|
||||
pub fn lower(
|
||||
const FormatMessage = struct {
|
||||
err: Error,
|
||||
raw_string: []const u8,
|
||||
offset: u32,
|
||||
comptime func: anytype,
|
||||
first_args: anytype,
|
||||
) @typeInfo(@TypeOf(func)).@"fn".return_type.? {
|
||||
switch (err) {
|
||||
inline else => |bad_index_or_void, tag| {
|
||||
const bad_index: u32 = switch (@TypeOf(bad_index_or_void)) {
|
||||
void => 0,
|
||||
else => @intCast(bad_index_or_void),
|
||||
};
|
||||
const fmt_str: []const u8, const args = switch (tag) {
|
||||
.invalid_escape_character => .{ "invalid escape character: '{c}'", .{raw_string[bad_index]} },
|
||||
.expected_hex_digit => .{ "expected hex digit, found '{c}'", .{raw_string[bad_index]} },
|
||||
.empty_unicode_escape_sequence => .{ "empty unicode escape sequence", .{} },
|
||||
.expected_hex_digit_or_rbrace => .{ "expected hex digit or '}}', found '{c}'", .{raw_string[bad_index]} },
|
||||
.invalid_unicode_codepoint => .{ "unicode escape does not correspond to a valid unicode scalar value", .{} },
|
||||
.expected_lbrace => .{ "expected '{{', found '{c}'", .{raw_string[bad_index]} },
|
||||
.expected_rbrace => .{ "expected '}}', found '{c}'", .{raw_string[bad_index]} },
|
||||
.expected_single_quote => .{ "expected singel quote ('), found '{c}'", .{raw_string[bad_index]} },
|
||||
.invalid_character => .{ "invalid byte in string or character literal: '{c}'", .{raw_string[bad_index]} },
|
||||
.empty_char_literal => .{ "empty character literal", .{} },
|
||||
};
|
||||
return @call(.auto, func, first_args ++ .{
|
||||
offset + bad_index,
|
||||
fmt_str,
|
||||
args,
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
fn formatMessage(
|
||||
self: FormatMessage,
|
||||
comptime f: []const u8,
|
||||
options: std.fmt.FormatOptions,
|
||||
writer: anytype,
|
||||
) !void {
|
||||
_ = f;
|
||||
_ = options;
|
||||
switch (self.err) {
|
||||
.invalid_escape_character => |bad_index| try writer.print(
|
||||
"invalid escape character: '{c}'",
|
||||
.{self.raw_string[bad_index]},
|
||||
),
|
||||
.expected_hex_digit => |bad_index| try writer.print(
|
||||
"expected hex digit, found '{c}'",
|
||||
.{self.raw_string[bad_index]},
|
||||
),
|
||||
.empty_unicode_escape_sequence => try writer.writeAll(
|
||||
"empty unicode escape sequence",
|
||||
),
|
||||
.expected_hex_digit_or_rbrace => |bad_index| try writer.print(
|
||||
"expected hex digit or '}}', found '{c}'",
|
||||
.{self.raw_string[bad_index]},
|
||||
),
|
||||
.invalid_unicode_codepoint => try writer.writeAll(
|
||||
"unicode escape does not correspond to a valid unicode scalar value",
|
||||
),
|
||||
.expected_lbrace => |bad_index| try writer.print(
|
||||
"expected '{{', found '{c}'",
|
||||
.{self.raw_string[bad_index]},
|
||||
),
|
||||
.expected_rbrace => |bad_index| try writer.print(
|
||||
"expected '}}', found '{c}'",
|
||||
.{self.raw_string[bad_index]},
|
||||
),
|
||||
.expected_single_quote => |bad_index| try writer.print(
|
||||
"expected single quote ('), found '{c}'",
|
||||
.{self.raw_string[bad_index]},
|
||||
),
|
||||
.invalid_character => |bad_index| try writer.print(
|
||||
"invalid byte in string or character literal: '{c}'",
|
||||
.{self.raw_string[bad_index]},
|
||||
),
|
||||
.empty_char_literal => try writer.writeAll(
|
||||
"empty character literal",
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fmt(self: @This(), raw_string: []const u8) std.fmt.Formatter(formatMessage) {
|
||||
return .{ .data = .{
|
||||
.err = self,
|
||||
.raw_string = raw_string,
|
||||
} };
|
||||
}
|
||||
|
||||
pub fn offset(err: Error) usize {
|
||||
return switch (err) {
|
||||
inline .invalid_escape_character,
|
||||
.expected_hex_digit,
|
||||
.empty_unicode_escape_sequence,
|
||||
.expected_hex_digit_or_rbrace,
|
||||
.invalid_unicode_codepoint,
|
||||
.expected_lbrace,
|
||||
.expected_rbrace,
|
||||
.expected_single_quote,
|
||||
.invalid_character,
|
||||
=> |n| n,
|
||||
.empty_char_literal => 0,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
/// Asserts the slice starts and ends with single-quotes.
|
||||
|
|
|
|||
45
lib/std/zon.zig
Normal file
45
lib/std/zon.zig
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
//! ZON parsing and stringification.
|
||||
//!
|
||||
//! ZON ("Zig Object Notation") is a textual file format. Outside of `nan` and `inf` literals, ZON's
|
||||
//! grammar is a subset of Zig's.
|
||||
//!
|
||||
//! Supported Zig primitives:
|
||||
//! * boolean literals
|
||||
//! * number literals (including `nan` and `inf`)
|
||||
//! * character literals
|
||||
//! * enum literals
|
||||
//! * `null` literals
|
||||
//! * string literals
|
||||
//! * multiline string literals
|
||||
//!
|
||||
//! Supported Zig container types:
|
||||
//! * anonymous struct literals
|
||||
//! * anonymous tuple literals
|
||||
//!
|
||||
//! Here is an example ZON object:
|
||||
//! ```
|
||||
//! .{
|
||||
//! .a = 1.5,
|
||||
//! .b = "hello, world!",
|
||||
//! .c = .{ true, false },
|
||||
//! .d = .{ 1, 2, 3 },
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! Individual primitives are also valid ZON, for example:
|
||||
//! ```
|
||||
//! "This string is a valid ZON object."
|
||||
//! ```
|
||||
//!
|
||||
//! ZON may not contain type names.
|
||||
//!
|
||||
//! ZON does not have syntax for pointers, but the parsers will allocate as needed to match the
|
||||
//! given Zig types. Similarly, the serializer will traverse pointers.
|
||||
|
||||
pub const parse = @import("zon/parse.zig");
|
||||
pub const stringify = @import("zon/stringify.zig");
|
||||
|
||||
test {
|
||||
_ = parse;
|
||||
_ = stringify;
|
||||
}
|
||||
3449
lib/std/zon/parse.zig
Normal file
3449
lib/std/zon/parse.zig
Normal file
File diff suppressed because it is too large
Load diff
2306
lib/std/zon/stringify.zig
Normal file
2306
lib/std/zon/stringify.zig
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -2220,7 +2220,10 @@ pub fn update(comp: *Compilation, main_progress_node: std.Progress.Node) !void {
|
|||
try comp.astgen_work_queue.ensureUnusedCapacity(zcu.import_table.count());
|
||||
for (zcu.import_table.values()) |file_index| {
|
||||
if (zcu.fileByIndex(file_index).mod.isBuiltin()) continue;
|
||||
comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
if (file.getMode() == .zig) {
|
||||
comp.astgen_work_queue.writeItemAssumeCapacity(file_index);
|
||||
}
|
||||
}
|
||||
if (comp.file_system_inputs) |fsi| {
|
||||
for (zcu.import_table.values()) |file_index| {
|
||||
|
|
@ -3206,10 +3209,16 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
|||
if (error_msg) |msg| {
|
||||
try addModuleErrorMsg(zcu, &bundle, msg.*);
|
||||
} else {
|
||||
// Must be ZIR errors. Note that this may include AST errors.
|
||||
// addZirErrorMessages asserts that the tree is loaded.
|
||||
_ = try file.getTree(gpa);
|
||||
try addZirErrorMessages(&bundle, file);
|
||||
// Must be ZIR or Zoir errors. Note that this may include AST errors.
|
||||
_ = try file.getTree(gpa); // Tree must be loaded.
|
||||
if (file.zir_loaded) {
|
||||
try addZirErrorMessages(&bundle, file);
|
||||
} else if (file.zoir != null) {
|
||||
try addZoirErrorMessages(&bundle, file);
|
||||
} else {
|
||||
// Either Zir or Zoir must have been loaded.
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
}
|
||||
var sorted_failed_analysis: std.AutoArrayHashMapUnmanaged(InternPool.AnalUnit, *Zcu.ErrorMsg).DataList.Slice = s: {
|
||||
|
|
@ -3623,6 +3632,15 @@ pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
|
|||
return eb.addZirErrorMessages(file.zir, file.tree, file.source, src_path);
|
||||
}
|
||||
|
||||
pub fn addZoirErrorMessages(eb: *ErrorBundle.Wip, file: *Zcu.File) !void {
|
||||
assert(file.source_loaded);
|
||||
assert(file.tree_loaded);
|
||||
const gpa = eb.gpa;
|
||||
const src_path = try file.fullPath(gpa);
|
||||
defer gpa.free(src_path);
|
||||
return eb.addZoirErrorMessages(file.zoir.?, file.tree, file.source, src_path);
|
||||
}
|
||||
|
||||
pub fn performAllTheWork(
|
||||
comp: *Compilation,
|
||||
main_progress_node: std.Progress.Node,
|
||||
|
|
@ -4272,6 +4290,7 @@ fn workerAstGenFile(
|
|||
wg: *WaitGroup,
|
||||
src: Zcu.AstGenSrc,
|
||||
) void {
|
||||
assert(file.getMode() == .zig);
|
||||
const child_prog_node = prog_node.start(file.sub_file_path, 0);
|
||||
defer child_prog_node.end();
|
||||
|
||||
|
|
@ -4325,7 +4344,7 @@ fn workerAstGenFile(
|
|||
const imported_path_digest = pt.zcu.filePathDigest(res.file_index);
|
||||
break :blk .{ res, imported_path_digest };
|
||||
};
|
||||
if (import_result.is_new) {
|
||||
if (import_result.is_new and import_result.file.getMode() == .zig) {
|
||||
log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
|
||||
file.sub_file_path, import_path, import_result.file.sub_file_path,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -4389,7 +4389,7 @@ pub const LoadedEnumType = struct {
|
|||
// Auto-numbered enum. Convert `int_tag_val` to field index.
|
||||
const field_index = switch (ip.indexToKey(int_tag_val).int.storage) {
|
||||
inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null,
|
||||
.big_int => |x| x.to(u32) catch return null,
|
||||
.big_int => |x| x.toInt(u32) catch return null,
|
||||
.lazy_align, .lazy_size => unreachable,
|
||||
};
|
||||
return if (field_index < self.names.len) field_index else null;
|
||||
|
|
@ -7957,7 +7957,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||
.big_int => |big_int| {
|
||||
items.appendAssumeCapacity(.{
|
||||
.tag = .int_u8,
|
||||
.data = big_int.to(u8) catch unreachable,
|
||||
.data = big_int.toInt(u8) catch unreachable,
|
||||
});
|
||||
break :b;
|
||||
},
|
||||
|
|
@ -7974,7 +7974,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||
.big_int => |big_int| {
|
||||
items.appendAssumeCapacity(.{
|
||||
.tag = .int_u16,
|
||||
.data = big_int.to(u16) catch unreachable,
|
||||
.data = big_int.toInt(u16) catch unreachable,
|
||||
});
|
||||
break :b;
|
||||
},
|
||||
|
|
@ -7991,7 +7991,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||
.big_int => |big_int| {
|
||||
items.appendAssumeCapacity(.{
|
||||
.tag = .int_u32,
|
||||
.data = big_int.to(u32) catch unreachable,
|
||||
.data = big_int.toInt(u32) catch unreachable,
|
||||
});
|
||||
break :b;
|
||||
},
|
||||
|
|
@ -8006,7 +8006,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||
},
|
||||
.i32_type => switch (int.storage) {
|
||||
.big_int => |big_int| {
|
||||
const casted = big_int.to(i32) catch unreachable;
|
||||
const casted = big_int.toInt(i32) catch unreachable;
|
||||
items.appendAssumeCapacity(.{
|
||||
.tag = .int_i32,
|
||||
.data = @as(u32, @bitCast(casted)),
|
||||
|
|
@ -8024,7 +8024,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||
},
|
||||
.usize_type => switch (int.storage) {
|
||||
.big_int => |big_int| {
|
||||
if (big_int.to(u32)) |casted| {
|
||||
if (big_int.toInt(u32)) |casted| {
|
||||
items.appendAssumeCapacity(.{
|
||||
.tag = .int_usize,
|
||||
.data = casted,
|
||||
|
|
@ -8045,14 +8045,14 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||
},
|
||||
.comptime_int_type => switch (int.storage) {
|
||||
.big_int => |big_int| {
|
||||
if (big_int.to(u32)) |casted| {
|
||||
if (big_int.toInt(u32)) |casted| {
|
||||
items.appendAssumeCapacity(.{
|
||||
.tag = .int_comptime_int_u32,
|
||||
.data = casted,
|
||||
});
|
||||
break :b;
|
||||
} else |_| {}
|
||||
if (big_int.to(i32)) |casted| {
|
||||
if (big_int.toInt(i32)) |casted| {
|
||||
items.appendAssumeCapacity(.{
|
||||
.tag = .int_comptime_int_i32,
|
||||
.data = @as(u32, @bitCast(casted)),
|
||||
|
|
@ -8082,7 +8082,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, tid: Zcu.PerThread.Id, key: Key) All
|
|||
}
|
||||
switch (int.storage) {
|
||||
.big_int => |big_int| {
|
||||
if (big_int.to(u32)) |casted| {
|
||||
if (big_int.toInt(u32)) |casted| {
|
||||
items.appendAssumeCapacity(.{
|
||||
.tag = .int_small,
|
||||
.data = try addExtra(extra, IntSmall{
|
||||
|
|
|
|||
50
src/Sema.zig
50
src/Sema.zig
|
|
@ -187,6 +187,7 @@ const Alignment = InternPool.Alignment;
|
|||
const AnalUnit = InternPool.AnalUnit;
|
||||
const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
|
||||
const Cache = std.Build.Cache;
|
||||
const LowerZon = @import("Sema/LowerZon.zig");
|
||||
|
||||
pub const default_branch_quota = 1000;
|
||||
pub const default_reference_trace_len = 2;
|
||||
|
|
@ -5790,7 +5791,7 @@ fn addNullTerminatedStrLit(sema: *Sema, string: InternPool.NullTerminatedString)
|
|||
return sema.addStrLit(string.toString(), string.length(&sema.pt.zcu.intern_pool));
|
||||
}
|
||||
|
||||
fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError!Air.Inst.Ref {
|
||||
pub fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError!Air.Inst.Ref {
|
||||
const pt = sema.pt;
|
||||
const array_ty = try pt.arrayType(.{
|
||||
.len = len,
|
||||
|
|
@ -13964,9 +13965,10 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
|
|||
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].str_tok;
|
||||
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
|
||||
const extra = sema.code.extraData(Zir.Inst.Import, inst_data.payload_index).data;
|
||||
const operand_src = block.tokenOffset(inst_data.src_tok);
|
||||
const operand = inst_data.get(sema.code);
|
||||
const operand = sema.code.nullTerminatedString(extra.path);
|
||||
|
||||
const result = pt.importFile(block.getFileScope(zcu), operand) catch |err| switch (err) {
|
||||
error.ImportOutsideModulePath => {
|
||||
|
|
@ -13983,12 +13985,42 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
|
|||
return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
|
||||
},
|
||||
};
|
||||
try sema.declareDependency(.{ .file = result.file_index });
|
||||
try pt.ensureFileAnalyzed(result.file_index);
|
||||
const ty = zcu.fileRootType(result.file_index);
|
||||
try sema.declareDependency(.{ .interned = ty });
|
||||
try sema.addTypeReferenceEntry(operand_src, ty);
|
||||
return Air.internedToRef(ty);
|
||||
switch (result.file.getMode()) {
|
||||
.zig => {
|
||||
try sema.declareDependency(.{ .file = result.file_index });
|
||||
try pt.ensureFileAnalyzed(result.file_index);
|
||||
const ty = zcu.fileRootType(result.file_index);
|
||||
try sema.declareDependency(.{ .interned = ty });
|
||||
try sema.addTypeReferenceEntry(operand_src, ty);
|
||||
return Air.internedToRef(ty);
|
||||
},
|
||||
.zon => {
|
||||
_ = result.file.getTree(zcu.gpa) catch |err| {
|
||||
// TODO: these errors are file system errors; make sure an update() will
|
||||
// retry this and not cache the file system error, which may be transient.
|
||||
return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ result.file.sub_file_path, @errorName(err) });
|
||||
};
|
||||
|
||||
if (extra.res_ty == .none) {
|
||||
return sema.fail(block, operand_src, "'@import' of ZON must have a known result type", .{});
|
||||
}
|
||||
const res_ty_inst = try sema.resolveInst(extra.res_ty);
|
||||
const res_ty = try sema.analyzeAsType(block, operand_src, res_ty_inst);
|
||||
if (res_ty.isGenericPoison()) {
|
||||
return sema.fail(block, operand_src, "'@import' of ZON must have a known result type", .{});
|
||||
}
|
||||
|
||||
const interned = try LowerZon.run(
|
||||
sema,
|
||||
result.file,
|
||||
result.file_index,
|
||||
res_ty,
|
||||
operand_src,
|
||||
block,
|
||||
);
|
||||
return Air.internedToRef(interned);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
|
||||
|
|
|
|||
858
src/Sema/LowerZon.zig
Normal file
858
src/Sema/LowerZon.zig
Normal file
|
|
@ -0,0 +1,858 @@
|
|||
const std = @import("std");
|
||||
const Zcu = @import("../Zcu.zig");
|
||||
const Sema = @import("../Sema.zig");
|
||||
const Air = @import("../Air.zig");
|
||||
const InternPool = @import("../InternPool.zig");
|
||||
const Type = @import("../Type.zig");
|
||||
const Value = @import("../Value.zig");
|
||||
const Zir = std.zig.Zir;
|
||||
const AstGen = std.zig.AstGen;
|
||||
const CompileError = Zcu.CompileError;
|
||||
const Ast = std.zig.Ast;
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
const File = Zcu.File;
|
||||
const LazySrcLoc = Zcu.LazySrcLoc;
|
||||
const Ref = std.zig.Zir.Inst.Ref;
|
||||
const NullTerminatedString = InternPool.NullTerminatedString;
|
||||
const NumberLiteralError = std.zig.number_literal.Error;
|
||||
const NodeIndex = std.zig.Ast.Node.Index;
|
||||
const Zoir = std.zig.Zoir;
|
||||
|
||||
const LowerZon = @This();
|
||||
|
||||
sema: *Sema,
|
||||
file: *File,
|
||||
file_index: Zcu.File.Index,
|
||||
import_loc: LazySrcLoc,
|
||||
block: *Sema.Block,
|
||||
base_node_inst: InternPool.TrackedInst.Index,
|
||||
|
||||
/// Lowers the given file as ZON.
|
||||
pub fn run(
|
||||
sema: *Sema,
|
||||
file: *File,
|
||||
file_index: Zcu.File.Index,
|
||||
res_ty: Type,
|
||||
import_loc: LazySrcLoc,
|
||||
block: *Sema.Block,
|
||||
) CompileError!InternPool.Index {
|
||||
const pt = sema.pt;
|
||||
|
||||
_ = try file.getZoir(pt.zcu);
|
||||
|
||||
const tracked_inst = try pt.zcu.intern_pool.trackZir(pt.zcu.gpa, pt.tid, .{
|
||||
.file = file_index,
|
||||
.inst = .main_struct_inst, // this is the only trackable instruction in a ZON file
|
||||
});
|
||||
|
||||
var lower_zon: LowerZon = .{
|
||||
.sema = sema,
|
||||
.file = file,
|
||||
.file_index = file_index,
|
||||
.import_loc = import_loc,
|
||||
.block = block,
|
||||
.base_node_inst = tracked_inst,
|
||||
};
|
||||
|
||||
try lower_zon.checkType(res_ty);
|
||||
|
||||
return lower_zon.lowerExpr(.root, res_ty);
|
||||
}
|
||||
|
||||
/// Validate that `ty` is a valid ZON type. If not, emit a compile error.
|
||||
/// i.e. no nested optionals, no error sets, etc.
|
||||
fn checkType(self: *LowerZon, ty: Type) !void {
|
||||
var visited: std.AutoHashMapUnmanaged(InternPool.Index, void) = .empty;
|
||||
try self.checkTypeInner(ty, null, &visited);
|
||||
}
|
||||
|
||||
fn checkTypeInner(
|
||||
self: *LowerZon,
|
||||
ty: Type,
|
||||
parent_opt_ty: ?Type,
|
||||
/// Visited structs and unions (not tuples). These are tracked because they are the only way in
|
||||
/// which a type can be self-referential, so must be tracked to avoid loops. Tracking more types
|
||||
/// consumes memory unnecessarily, and would be complicated by optionals.
|
||||
/// Allocated into `self.sema.arena`.
|
||||
visited: *std.AutoHashMapUnmanaged(InternPool.Index, void),
|
||||
) !void {
|
||||
const sema = self.sema;
|
||||
const pt = sema.pt;
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
switch (ty.zigTypeTag(zcu)) {
|
||||
.bool,
|
||||
.int,
|
||||
.float,
|
||||
.null,
|
||||
.@"enum",
|
||||
.comptime_float,
|
||||
.comptime_int,
|
||||
.enum_literal,
|
||||
=> {},
|
||||
|
||||
.noreturn,
|
||||
.void,
|
||||
.type,
|
||||
.undefined,
|
||||
.error_union,
|
||||
.error_set,
|
||||
.@"fn",
|
||||
.frame,
|
||||
.@"anyframe",
|
||||
.@"opaque",
|
||||
=> return self.failUnsupportedResultType(ty, null),
|
||||
|
||||
.pointer => {
|
||||
const ptr_info = ty.ptrInfo(zcu);
|
||||
if (!ptr_info.flags.is_const) {
|
||||
return self.failUnsupportedResultType(
|
||||
ty,
|
||||
"ZON does not allow mutable pointers",
|
||||
);
|
||||
}
|
||||
switch (ptr_info.flags.size) {
|
||||
.one => try self.checkTypeInner(
|
||||
.fromInterned(ptr_info.child),
|
||||
parent_opt_ty, // preserved
|
||||
visited,
|
||||
),
|
||||
.slice => try self.checkTypeInner(
|
||||
.fromInterned(ptr_info.child),
|
||||
null,
|
||||
visited,
|
||||
),
|
||||
.many => return self.failUnsupportedResultType(ty, "ZON does not allow many-pointers"),
|
||||
.c => return self.failUnsupportedResultType(ty, "ZON does not allow C pointers"),
|
||||
}
|
||||
},
|
||||
.optional => if (parent_opt_ty) |p| {
|
||||
return self.failUnsupportedResultType(p, "ZON does not allow nested optionals");
|
||||
} else try self.checkTypeInner(
|
||||
ty.optionalChild(zcu),
|
||||
ty,
|
||||
visited,
|
||||
),
|
||||
.array, .vector => {
|
||||
try self.checkTypeInner(ty.childType(zcu), null, visited);
|
||||
},
|
||||
.@"struct" => if (ty.isTuple(zcu)) {
|
||||
const tuple_info = ip.indexToKey(ty.toIntern()).tuple_type;
|
||||
const field_types = tuple_info.types.get(ip);
|
||||
for (field_types) |field_type| {
|
||||
try self.checkTypeInner(.fromInterned(field_type), null, visited);
|
||||
}
|
||||
} else {
|
||||
const gop = try visited.getOrPut(sema.arena, ty.toIntern());
|
||||
if (gop.found_existing) return;
|
||||
try ty.resolveFields(pt);
|
||||
const struct_info = zcu.typeToStruct(ty).?;
|
||||
for (struct_info.field_types.get(ip)) |field_type| {
|
||||
try self.checkTypeInner(.fromInterned(field_type), null, visited);
|
||||
}
|
||||
},
|
||||
.@"union" => {
|
||||
const gop = try visited.getOrPut(sema.arena, ty.toIntern());
|
||||
if (gop.found_existing) return;
|
||||
try ty.resolveFields(pt);
|
||||
const union_info = zcu.typeToUnion(ty).?;
|
||||
for (union_info.field_types.get(ip)) |field_type| {
|
||||
if (field_type != .void_type) {
|
||||
try self.checkTypeInner(.fromInterned(field_type), null, visited);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn nodeSrc(self: *LowerZon, node: Zoir.Node.Index) LazySrcLoc {
|
||||
return .{
|
||||
.base_node_inst = self.base_node_inst,
|
||||
.offset = .{ .node_abs = node.getAstNode(self.file.zoir.?) },
|
||||
};
|
||||
}
|
||||
|
||||
fn failUnsupportedResultType(
|
||||
self: *LowerZon,
|
||||
ty: Type,
|
||||
opt_note: ?[]const u8,
|
||||
) error{ AnalysisFail, OutOfMemory } {
|
||||
@branchHint(.cold);
|
||||
const sema = self.sema;
|
||||
const gpa = sema.gpa;
|
||||
const pt = sema.pt;
|
||||
return sema.failWithOwnedErrorMsg(self.block, msg: {
|
||||
const msg = try sema.errMsg(self.import_loc, "type '{}' is not available in ZON", .{ty.fmt(pt)});
|
||||
errdefer msg.destroy(gpa);
|
||||
if (opt_note) |n| try sema.errNote(self.import_loc, msg, "{s}", .{n});
|
||||
break :msg msg;
|
||||
});
|
||||
}
|
||||
|
||||
fn fail(
|
||||
self: *LowerZon,
|
||||
node: Zoir.Node.Index,
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) error{ AnalysisFail, OutOfMemory } {
|
||||
@branchHint(.cold);
|
||||
const err_msg = try Zcu.ErrorMsg.create(self.sema.pt.zcu.gpa, self.nodeSrc(node), format, args);
|
||||
try self.sema.pt.zcu.errNote(self.import_loc, err_msg, "imported here", .{});
|
||||
return self.sema.failWithOwnedErrorMsg(self.block, err_msg);
|
||||
}
|
||||
|
||||
fn lowerExpr(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) CompileError!InternPool.Index {
|
||||
const pt = self.sema.pt;
|
||||
return self.lowerExprInner(node, res_ty) catch |err| switch (err) {
|
||||
error.WrongType => return self.fail(
|
||||
node,
|
||||
"expected type '{}'",
|
||||
.{res_ty.fmt(pt)},
|
||||
),
|
||||
else => |e| return e,
|
||||
};
|
||||
}
|
||||
|
||||
fn lowerExprInner(
|
||||
self: *LowerZon,
|
||||
node: Zoir.Node.Index,
|
||||
res_ty: Type,
|
||||
) (CompileError || error{WrongType})!InternPool.Index {
|
||||
const pt = self.sema.pt;
|
||||
switch (res_ty.zigTypeTag(pt.zcu)) {
|
||||
.optional => return pt.intern(.{
|
||||
.opt = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.val = if (node.get(self.file.zoir.?) == .null) b: {
|
||||
break :b .none;
|
||||
} else b: {
|
||||
const child_type = res_ty.optionalChild(pt.zcu);
|
||||
break :b try self.lowerExprInner(node, child_type);
|
||||
},
|
||||
},
|
||||
}),
|
||||
.pointer => {
|
||||
const ptr_info = res_ty.ptrInfo(pt.zcu);
|
||||
switch (ptr_info.flags.size) {
|
||||
.one => return pt.intern(.{ .ptr = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.base_addr = .{
|
||||
.uav = .{
|
||||
.orig_ty = res_ty.toIntern(),
|
||||
.val = try self.lowerExprInner(node, .fromInterned(ptr_info.child)),
|
||||
},
|
||||
},
|
||||
.byte_offset = 0,
|
||||
} }),
|
||||
.slice => return self.lowerSlice(node, res_ty),
|
||||
else => {
|
||||
// Unsupported pointer type, checked in `lower`
|
||||
unreachable;
|
||||
},
|
||||
}
|
||||
},
|
||||
.bool => return self.lowerBool(node),
|
||||
.int, .comptime_int => return self.lowerInt(node, res_ty),
|
||||
.float, .comptime_float => return self.lowerFloat(node, res_ty),
|
||||
.null => return self.lowerNull(node),
|
||||
.@"enum" => return self.lowerEnum(node, res_ty),
|
||||
.enum_literal => return self.lowerEnumLiteral(node),
|
||||
.array => return self.lowerArray(node, res_ty),
|
||||
.@"struct" => return self.lowerStructOrTuple(node, res_ty),
|
||||
.@"union" => return self.lowerUnion(node, res_ty),
|
||||
.vector => return self.lowerVector(node, res_ty),
|
||||
|
||||
.type,
|
||||
.noreturn,
|
||||
.undefined,
|
||||
.error_union,
|
||||
.error_set,
|
||||
.@"fn",
|
||||
.@"opaque",
|
||||
.frame,
|
||||
.@"anyframe",
|
||||
.void,
|
||||
=> return self.fail(node, "type '{}' not available in ZON", .{res_ty.fmt(pt)}),
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerBool(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
|
||||
return switch (node.get(self.file.zoir.?)) {
|
||||
.true => .bool_true,
|
||||
.false => .bool_false,
|
||||
else => return error.WrongType,
|
||||
};
|
||||
}
|
||||
|
||||
fn lowerInt(
|
||||
self: *LowerZon,
|
||||
node: Zoir.Node.Index,
|
||||
res_ty: Type,
|
||||
) !InternPool.Index {
|
||||
@setFloatMode(.strict);
|
||||
return switch (node.get(self.file.zoir.?)) {
|
||||
.int_literal => |int| switch (int) {
|
||||
.small => |val| {
|
||||
const rhs: i32 = val;
|
||||
|
||||
// If our result is a fixed size integer, check that our value is not out of bounds
|
||||
if (res_ty.zigTypeTag(self.sema.pt.zcu) == .int) {
|
||||
const lhs_info = res_ty.intInfo(self.sema.pt.zcu);
|
||||
|
||||
// If lhs is unsigned and rhs is less than 0, we're out of bounds
|
||||
if (lhs_info.signedness == .unsigned and rhs < 0) return self.fail(
|
||||
node,
|
||||
"type '{}' cannot represent integer value '{}'",
|
||||
.{ res_ty.fmt(self.sema.pt), rhs },
|
||||
);
|
||||
|
||||
// If lhs has less than the 32 bits rhs can hold, we need to check the max and
|
||||
// min values
|
||||
if (std.math.cast(u5, lhs_info.bits)) |bits| {
|
||||
const min_int: i32 = if (lhs_info.signedness == .unsigned or bits == 0) b: {
|
||||
break :b 0;
|
||||
} else b: {
|
||||
break :b -(@as(i32, 1) << (bits - 1));
|
||||
};
|
||||
const max_int: i32 = if (bits == 0) b: {
|
||||
break :b 0;
|
||||
} else b: {
|
||||
break :b (@as(i32, 1) << (bits - @intFromBool(lhs_info.signedness == .signed))) - 1;
|
||||
};
|
||||
if (rhs < min_int or rhs > max_int) {
|
||||
return self.fail(
|
||||
node,
|
||||
"type '{}' cannot represent integer value '{}'",
|
||||
.{ res_ty.fmt(self.sema.pt), rhs },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self.sema.pt.intern(.{ .int = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.storage = .{ .i64 = rhs },
|
||||
} });
|
||||
},
|
||||
.big => |val| {
|
||||
if (res_ty.zigTypeTag(self.sema.pt.zcu) == .int) {
|
||||
const int_info = res_ty.intInfo(self.sema.pt.zcu);
|
||||
if (!val.fitsInTwosComp(int_info.signedness, int_info.bits)) {
|
||||
return self.fail(
|
||||
node,
|
||||
"type '{}' cannot represent integer value '{}'",
|
||||
.{ res_ty.fmt(self.sema.pt), val },
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return self.sema.pt.intern(.{ .int = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.storage = .{ .big_int = val },
|
||||
} });
|
||||
},
|
||||
},
|
||||
.float_literal => |val| {
|
||||
// Check for fractional components
|
||||
if (@rem(val, 1) != 0) {
|
||||
return self.fail(
|
||||
node,
|
||||
"fractional component prevents float value '{}' from coercion to type '{}'",
|
||||
.{ val, res_ty.fmt(self.sema.pt) },
|
||||
);
|
||||
}
|
||||
|
||||
// Create a rational representation of the float
|
||||
var rational = try std.math.big.Rational.init(self.sema.arena);
|
||||
rational.setFloat(f128, val) catch |err| switch (err) {
|
||||
error.NonFiniteFloat => unreachable,
|
||||
error.OutOfMemory => return error.OutOfMemory,
|
||||
};
|
||||
|
||||
// The float is reduced in rational.setFloat, so we assert that denominator is equal to
|
||||
// one
|
||||
const big_one = std.math.big.int.Const{ .limbs = &.{1}, .positive = true };
|
||||
assert(rational.q.toConst().eqlAbs(big_one));
|
||||
|
||||
// Check that the result is in range of the result type
|
||||
const int_info = res_ty.intInfo(self.sema.pt.zcu);
|
||||
if (!rational.p.fitsInTwosComp(int_info.signedness, int_info.bits)) {
|
||||
return self.fail(
|
||||
node,
|
||||
"type '{}' cannot represent integer value '{}'",
|
||||
.{ val, res_ty.fmt(self.sema.pt) },
|
||||
);
|
||||
}
|
||||
|
||||
return self.sema.pt.intern(.{
|
||||
.int = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.storage = .{ .big_int = rational.p.toConst() },
|
||||
},
|
||||
});
|
||||
},
|
||||
.char_literal => |val| {
|
||||
// If our result is a fixed size integer, check that our value is not out of bounds
|
||||
if (res_ty.zigTypeTag(self.sema.pt.zcu) == .int) {
|
||||
const dest_info = res_ty.intInfo(self.sema.pt.zcu);
|
||||
const unsigned_bits = dest_info.bits - @intFromBool(dest_info.signedness == .signed);
|
||||
if (unsigned_bits < 21) {
|
||||
const out_of_range: u21 = @as(u21, 1) << @intCast(unsigned_bits);
|
||||
if (val >= out_of_range) {
|
||||
return self.fail(
|
||||
node,
|
||||
"type '{}' cannot represent integer value '{}'",
|
||||
.{ res_ty.fmt(self.sema.pt), val },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
return self.sema.pt.intern(.{
|
||||
.int = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.storage = .{ .i64 = val },
|
||||
},
|
||||
});
|
||||
},
|
||||
|
||||
else => return error.WrongType,
|
||||
};
|
||||
}
|
||||
|
||||
fn lowerFloat(
|
||||
self: *LowerZon,
|
||||
node: Zoir.Node.Index,
|
||||
res_ty: Type,
|
||||
) !InternPool.Index {
|
||||
@setFloatMode(.strict);
|
||||
const value = switch (node.get(self.file.zoir.?)) {
|
||||
.int_literal => |int| switch (int) {
|
||||
.small => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),
|
||||
.big => |val| try self.sema.pt.floatValue(res_ty, val.toFloat(f128)),
|
||||
},
|
||||
.float_literal => |val| try self.sema.pt.floatValue(res_ty, val),
|
||||
.char_literal => |val| try self.sema.pt.floatValue(res_ty, @as(f128, @floatFromInt(val))),
|
||||
.pos_inf => b: {
|
||||
if (res_ty.toIntern() == .comptime_float_type) return self.fail(
|
||||
node,
|
||||
"expected type '{}'",
|
||||
.{res_ty.fmt(self.sema.pt)},
|
||||
);
|
||||
break :b try self.sema.pt.floatValue(res_ty, std.math.inf(f128));
|
||||
},
|
||||
.neg_inf => b: {
|
||||
if (res_ty.toIntern() == .comptime_float_type) return self.fail(
|
||||
node,
|
||||
"expected type '{}'",
|
||||
.{res_ty.fmt(self.sema.pt)},
|
||||
);
|
||||
break :b try self.sema.pt.floatValue(res_ty, -std.math.inf(f128));
|
||||
},
|
||||
.nan => b: {
|
||||
if (res_ty.toIntern() == .comptime_float_type) return self.fail(
|
||||
node,
|
||||
"expected type '{}'",
|
||||
.{res_ty.fmt(self.sema.pt)},
|
||||
);
|
||||
break :b try self.sema.pt.floatValue(res_ty, std.math.nan(f128));
|
||||
},
|
||||
else => return error.WrongType,
|
||||
};
|
||||
return value.toIntern();
|
||||
}
|
||||
|
||||
fn lowerNull(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
|
||||
switch (node.get(self.file.zoir.?)) {
|
||||
.null => return .null_value,
|
||||
else => return error.WrongType,
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerArray(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||
const array_info = res_ty.arrayInfo(self.sema.pt.zcu);
|
||||
const nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
|
||||
.array_literal => |nodes| nodes,
|
||||
.empty_literal => .{ .start = node, .len = 0 },
|
||||
else => return error.WrongType,
|
||||
};
|
||||
|
||||
if (nodes.len != array_info.len) {
|
||||
return error.WrongType;
|
||||
}
|
||||
|
||||
const elems = try self.sema.arena.alloc(
|
||||
InternPool.Index,
|
||||
nodes.len + @intFromBool(array_info.sentinel != null),
|
||||
);
|
||||
|
||||
for (0..nodes.len) |i| {
|
||||
elems[i] = try self.lowerExpr(nodes.at(@intCast(i)), array_info.elem_type);
|
||||
}
|
||||
|
||||
if (array_info.sentinel) |sentinel| {
|
||||
elems[elems.len - 1] = sentinel.toIntern();
|
||||
}
|
||||
|
||||
return self.sema.pt.intern(.{ .aggregate = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.storage = .{ .elems = elems },
|
||||
} });
|
||||
}
|
||||
|
||||
fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||
const ip = &self.sema.pt.zcu.intern_pool;
|
||||
switch (node.get(self.file.zoir.?)) {
|
||||
.enum_literal => |field_name| {
|
||||
const field_name_interned = try ip.getOrPutString(
|
||||
self.sema.gpa,
|
||||
self.sema.pt.tid,
|
||||
field_name.get(self.file.zoir.?),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
const field_index = res_ty.enumFieldIndex(field_name_interned, self.sema.pt.zcu) orelse {
|
||||
return self.fail(
|
||||
node,
|
||||
"enum {} has no member named '{}'",
|
||||
.{
|
||||
res_ty.fmt(self.sema.pt),
|
||||
std.zig.fmtId(field_name.get(self.file.zoir.?)),
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
const value = try self.sema.pt.enumValueFieldIndex(res_ty, field_index);
|
||||
|
||||
return value.toIntern();
|
||||
},
|
||||
else => return error.WrongType,
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerEnumLiteral(self: *LowerZon, node: Zoir.Node.Index) !InternPool.Index {
|
||||
const ip = &self.sema.pt.zcu.intern_pool;
|
||||
switch (node.get(self.file.zoir.?)) {
|
||||
.enum_literal => |field_name| {
|
||||
const field_name_interned = try ip.getOrPutString(
|
||||
self.sema.gpa,
|
||||
self.sema.pt.tid,
|
||||
field_name.get(self.file.zoir.?),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
return self.sema.pt.intern(.{ .enum_literal = field_name_interned });
|
||||
},
|
||||
else => return error.WrongType,
|
||||
}
|
||||
}
|
||||
|
||||
fn lowerStructOrTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||
const ip = &self.sema.pt.zcu.intern_pool;
|
||||
return switch (ip.indexToKey(res_ty.toIntern())) {
|
||||
.tuple_type => self.lowerTuple(node, res_ty),
|
||||
.struct_type => self.lowerStruct(node, res_ty),
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
fn lowerTuple(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||
const ip = &self.sema.pt.zcu.intern_pool;
|
||||
|
||||
const tuple_info = ip.indexToKey(res_ty.toIntern()).tuple_type;
|
||||
|
||||
const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
|
||||
.array_literal => |nodes| nodes,
|
||||
.empty_literal => .{ .start = node, .len = 0 },
|
||||
else => return error.WrongType,
|
||||
};
|
||||
|
||||
const field_types = tuple_info.types.get(ip);
|
||||
const elems = try self.sema.arena.alloc(InternPool.Index, field_types.len);
|
||||
|
||||
const field_comptime_vals = tuple_info.values.get(ip);
|
||||
if (field_comptime_vals.len > 0) {
|
||||
@memcpy(elems, field_comptime_vals);
|
||||
} else {
|
||||
@memset(elems, .none);
|
||||
}
|
||||
|
||||
for (0..elem_nodes.len) |i| {
|
||||
if (i >= elems.len) {
|
||||
const elem_node = elem_nodes.at(@intCast(i));
|
||||
return self.fail(
|
||||
elem_node,
|
||||
"index {} outside tuple of length {}",
|
||||
.{
|
||||
elems.len,
|
||||
elem_nodes.at(@intCast(i)).getAstNode(self.file.zoir.?),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
const val = try self.lowerExpr(elem_nodes.at(@intCast(i)), .fromInterned(field_types[i]));
|
||||
|
||||
if (elems[i] != .none and val != elems[i]) {
|
||||
const elem_node = elem_nodes.at(@intCast(i));
|
||||
return self.fail(
|
||||
elem_node,
|
||||
"value stored in comptime field does not match the default value of the field",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
|
||||
elems[i] = val;
|
||||
}
|
||||
|
||||
for (elems, 0..) |val, i| {
|
||||
if (val == .none) {
|
||||
return self.fail(node, "missing tuple field with index {}", .{i});
|
||||
}
|
||||
}
|
||||
|
||||
return self.sema.pt.intern(.{ .aggregate = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.storage = .{ .elems = elems },
|
||||
} });
|
||||
}
|
||||
|
||||
fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||
const ip = &self.sema.pt.zcu.intern_pool;
|
||||
const gpa = self.sema.gpa;
|
||||
|
||||
try res_ty.resolveFields(self.sema.pt);
|
||||
try res_ty.resolveStructFieldInits(self.sema.pt);
|
||||
const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;
|
||||
|
||||
const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
|
||||
.struct_literal => |fields| fields,
|
||||
.empty_literal => .{ .names = &.{}, .vals = .{ .start = node, .len = 0 } },
|
||||
else => return error.WrongType,
|
||||
};
|
||||
|
||||
const field_values = try self.sema.arena.alloc(InternPool.Index, struct_info.field_names.len);
|
||||
|
||||
const field_defaults = struct_info.field_inits.get(ip);
|
||||
if (field_defaults.len > 0) {
|
||||
@memcpy(field_values, field_defaults);
|
||||
} else {
|
||||
@memset(field_values, .none);
|
||||
}
|
||||
|
||||
for (0..fields.names.len) |i| {
|
||||
const field_name = try ip.getOrPutString(
|
||||
gpa,
|
||||
self.sema.pt.tid,
|
||||
fields.names[i].get(self.file.zoir.?),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
const field_node = fields.vals.at(@intCast(i));
|
||||
|
||||
const name_index = struct_info.nameIndex(ip, field_name) orelse {
|
||||
return self.fail(field_node, "unexpected field '{}'", .{field_name.fmt(ip)});
|
||||
};
|
||||
|
||||
const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]);
|
||||
field_values[name_index] = try self.lowerExpr(field_node, field_type);
|
||||
|
||||
if (struct_info.comptime_bits.getBit(ip, name_index)) {
|
||||
const val = ip.indexToKey(field_values[name_index]);
|
||||
const default = ip.indexToKey(field_defaults[name_index]);
|
||||
if (!val.eql(default, ip)) {
|
||||
return self.fail(
|
||||
field_node,
|
||||
"value stored in comptime field does not match the default value of the field",
|
||||
.{},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const field_names = struct_info.field_names.get(ip);
|
||||
for (field_values, field_names) |*value, name| {
|
||||
if (value.* == .none) return self.fail(node, "missing field '{}'", .{name.fmt(ip)});
|
||||
}
|
||||
|
||||
return self.sema.pt.intern(.{ .aggregate = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.storage = .{
|
||||
.elems = field_values,
|
||||
},
|
||||
} });
|
||||
}
|
||||
|
||||
fn lowerSlice(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||
const ip = &self.sema.pt.zcu.intern_pool;
|
||||
const gpa = self.sema.gpa;
|
||||
|
||||
const ptr_info = res_ty.ptrInfo(self.sema.pt.zcu);
|
||||
|
||||
assert(ptr_info.flags.size == .slice);
|
||||
|
||||
// String literals
|
||||
const string_alignment = ptr_info.flags.alignment == .none or ptr_info.flags.alignment == .@"1";
|
||||
const string_sentinel = ptr_info.sentinel == .none or ptr_info.sentinel == .zero_u8;
|
||||
if (string_alignment and ptr_info.child == .u8_type and string_sentinel) {
|
||||
switch (node.get(self.file.zoir.?)) {
|
||||
.string_literal => |val| {
|
||||
const ip_str = try ip.getOrPutString(gpa, self.sema.pt.tid, val, .maybe_embedded_nulls);
|
||||
const str_ref = try self.sema.addStrLit(ip_str, val.len);
|
||||
return (try self.sema.coerce(
|
||||
self.block,
|
||||
res_ty,
|
||||
str_ref,
|
||||
self.nodeSrc(node),
|
||||
)).toInterned().?;
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
// Slice literals
|
||||
const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
|
||||
.array_literal => |nodes| nodes,
|
||||
.empty_literal => .{ .start = node, .len = 0 },
|
||||
else => return error.WrongType,
|
||||
};
|
||||
|
||||
const elems = try self.sema.arena.alloc(InternPool.Index, elem_nodes.len + @intFromBool(ptr_info.sentinel != .none));
|
||||
|
||||
for (elems, 0..) |*elem, i| {
|
||||
elem.* = try self.lowerExpr(elem_nodes.at(@intCast(i)), .fromInterned(ptr_info.child));
|
||||
}
|
||||
|
||||
if (ptr_info.sentinel != .none) {
|
||||
elems[elems.len - 1] = ptr_info.sentinel;
|
||||
}
|
||||
|
||||
const array_ty = try self.sema.pt.intern(.{ .array_type = .{
|
||||
.len = elems.len,
|
||||
.sentinel = ptr_info.sentinel,
|
||||
.child = ptr_info.child,
|
||||
} });
|
||||
|
||||
const array = try self.sema.pt.intern(.{ .aggregate = .{
|
||||
.ty = array_ty,
|
||||
.storage = .{ .elems = elems },
|
||||
} });
|
||||
|
||||
const many_item_ptr_type = try self.sema.pt.intern(.{ .ptr_type = .{
|
||||
.child = ptr_info.child,
|
||||
.sentinel = ptr_info.sentinel,
|
||||
.flags = b: {
|
||||
var flags = ptr_info.flags;
|
||||
flags.size = .many;
|
||||
break :b flags;
|
||||
},
|
||||
.packed_offset = ptr_info.packed_offset,
|
||||
} });
|
||||
|
||||
const many_item_ptr = try self.sema.pt.intern(.{
|
||||
.ptr = .{
|
||||
.ty = many_item_ptr_type,
|
||||
.base_addr = .{
|
||||
.uav = .{
|
||||
.orig_ty = (try self.sema.pt.singleConstPtrType(.fromInterned(array_ty))).toIntern(),
|
||||
.val = array,
|
||||
},
|
||||
},
|
||||
.byte_offset = 0,
|
||||
},
|
||||
});
|
||||
|
||||
const len = (try self.sema.pt.intValue(.usize, elems.len)).toIntern();
|
||||
|
||||
return self.sema.pt.intern(.{ .slice = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.ptr = many_item_ptr,
|
||||
.len = len,
|
||||
} });
|
||||
}
|
||||
|
||||
fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||
const ip = &self.sema.pt.zcu.intern_pool;
|
||||
try res_ty.resolveFields(self.sema.pt);
|
||||
const union_info = self.sema.pt.zcu.typeToUnion(res_ty).?;
|
||||
const enum_tag_info = union_info.loadTagType(ip);
|
||||
|
||||
const field_name, const maybe_field_node = switch (node.get(self.file.zoir.?)) {
|
||||
.enum_literal => |name| b: {
|
||||
const field_name = try ip.getOrPutString(
|
||||
self.sema.gpa,
|
||||
self.sema.pt.tid,
|
||||
name.get(self.file.zoir.?),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
break :b .{ field_name, null };
|
||||
},
|
||||
.struct_literal => b: {
|
||||
const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
|
||||
.struct_literal => |fields| fields,
|
||||
else => return self.fail(node, "expected type '{}'", .{res_ty.fmt(self.sema.pt)}),
|
||||
};
|
||||
if (fields.names.len != 1) {
|
||||
return error.WrongType;
|
||||
}
|
||||
const field_name = try ip.getOrPutString(
|
||||
self.sema.gpa,
|
||||
self.sema.pt.tid,
|
||||
fields.names[0].get(self.file.zoir.?),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
break :b .{ field_name, fields.vals.at(0) };
|
||||
},
|
||||
else => return error.WrongType,
|
||||
};
|
||||
|
||||
const name_index = enum_tag_info.nameIndex(ip, field_name) orelse {
|
||||
return error.WrongType;
|
||||
};
|
||||
const tag = try self.sema.pt.enumValueFieldIndex(.fromInterned(union_info.enum_tag_ty), name_index);
|
||||
const field_type: Type = .fromInterned(union_info.field_types.get(ip)[name_index]);
|
||||
const val = if (maybe_field_node) |field_node| b: {
|
||||
if (field_type.toIntern() == .void_type) {
|
||||
return self.fail(field_node, "expected type 'void'", .{});
|
||||
}
|
||||
break :b try self.lowerExpr(field_node, field_type);
|
||||
} else b: {
|
||||
if (field_type.toIntern() != .void_type) {
|
||||
return error.WrongType;
|
||||
}
|
||||
break :b .void_value;
|
||||
};
|
||||
return ip.getUnion(self.sema.pt.zcu.gpa, self.sema.pt.tid, .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.tag = tag.toIntern(),
|
||||
.val = val,
|
||||
});
|
||||
}
|
||||
|
||||
fn lowerVector(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.Index {
|
||||
const ip = &self.sema.pt.zcu.intern_pool;
|
||||
|
||||
const vector_info = ip.indexToKey(res_ty.toIntern()).vector_type;
|
||||
|
||||
const elem_nodes: Zoir.Node.Index.Range = switch (node.get(self.file.zoir.?)) {
|
||||
.array_literal => |nodes| nodes,
|
||||
.empty_literal => .{ .start = node, .len = 0 },
|
||||
else => return error.WrongType,
|
||||
};
|
||||
|
||||
const elems = try self.sema.arena.alloc(InternPool.Index, vector_info.len);
|
||||
|
||||
if (elem_nodes.len != vector_info.len) {
|
||||
return self.fail(
|
||||
node,
|
||||
"expected {} vector elements; found {}",
|
||||
.{ vector_info.len, elem_nodes.len },
|
||||
);
|
||||
}
|
||||
|
||||
for (elems, 0..) |*elem, i| {
|
||||
elem.* = try self.lowerExpr(elem_nodes.at(@intCast(i)), .fromInterned(vector_info.child));
|
||||
}
|
||||
|
||||
return self.sema.pt.intern(.{ .aggregate = .{
|
||||
.ty = res_ty.toIntern(),
|
||||
.storage = .{ .elems = elems },
|
||||
} });
|
||||
}
|
||||
|
|
@ -270,7 +270,7 @@ pub fn getUnsignedIntInner(
|
|||
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
||||
.undef => unreachable,
|
||||
.int => |int| switch (int.storage) {
|
||||
.big_int => |big_int| big_int.to(u64) catch null,
|
||||
.big_int => |big_int| big_int.toInt(u64) catch null,
|
||||
.u64 => |x| x,
|
||||
.i64 => |x| std.math.cast(u64, x),
|
||||
.lazy_align => |ty| (try Type.fromInterned(ty).abiAlignmentInner(strat.toLazy(), zcu, tid)).scalar.toByteUnits() orelse 0,
|
||||
|
|
@ -311,7 +311,7 @@ pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 {
|
|||
.bool_true => 1,
|
||||
else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
||||
.int => |int| switch (int.storage) {
|
||||
.big_int => |big_int| big_int.to(i64) catch unreachable,
|
||||
.big_int => |big_int| big_int.toInt(i64) catch unreachable,
|
||||
.i64 => |x| x,
|
||||
.u64 => |x| @intCast(x),
|
||||
.lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0),
|
||||
|
|
@ -898,7 +898,7 @@ pub fn readFromPackedMemory(
|
|||
pub fn toFloat(val: Value, comptime T: type, zcu: *Zcu) T {
|
||||
return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
|
||||
.int => |int| switch (int.storage) {
|
||||
.big_int => |big_int| @floatCast(bigIntToFloat(big_int.limbs, big_int.positive)),
|
||||
.big_int => |big_int| big_int.toFloat(T),
|
||||
inline .u64, .i64 => |x| {
|
||||
if (T == f80) {
|
||||
@panic("TODO we can't lower this properly on non-x86 llvm backend yet");
|
||||
|
|
@ -915,25 +915,6 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *Zcu) T {
|
|||
};
|
||||
}
|
||||
|
||||
/// TODO move this to std lib big int code
|
||||
fn bigIntToFloat(limbs: []const std.math.big.Limb, positive: bool) f128 {
|
||||
if (limbs.len == 0) return 0;
|
||||
|
||||
const base = std.math.maxInt(std.math.big.Limb) + 1;
|
||||
var result: f128 = 0;
|
||||
var i: usize = limbs.len;
|
||||
while (i != 0) {
|
||||
i -= 1;
|
||||
const limb: f128 = @floatFromInt(limbs[i]);
|
||||
result = @mulAdd(f128, base, result, limb);
|
||||
}
|
||||
if (positive) {
|
||||
return result;
|
||||
} else {
|
||||
return -result;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn clz(val: Value, ty: Type, zcu: *Zcu) u64 {
|
||||
var bigint_buf: BigIntSpace = undefined;
|
||||
const bigint = val.toBigInt(&bigint_buf, zcu);
|
||||
|
|
@ -1548,7 +1529,7 @@ pub fn floatFromIntScalar(val: Value, float_ty: Type, pt: Zcu.PerThread, comptim
|
|||
.undef => try pt.undefValue(float_ty),
|
||||
.int => |int| switch (int.storage) {
|
||||
.big_int => |big_int| {
|
||||
const float = bigIntToFloat(big_int.limbs, big_int.positive);
|
||||
const float = big_int.toFloat(f128);
|
||||
return pt.floatValue(float_ty, float);
|
||||
},
|
||||
inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, pt),
|
||||
|
|
@ -4583,7 +4564,7 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
|
|||
.int => switch (ip.indexToKey(val.toIntern()).int.storage) {
|
||||
.lazy_align, .lazy_size => unreachable, // `val` is fully resolved
|
||||
inline .u64, .i64 => |x| std.math.cast(T, x) orelse return error.TypeMismatch,
|
||||
.big_int => |big| big.to(T) catch return error.TypeMismatch,
|
||||
.big_int => |big| big.toInt(T) catch return error.TypeMismatch,
|
||||
},
|
||||
|
||||
.float => val.toFloat(T, zcu),
|
||||
|
|
|
|||
40
src/Zcu.zig
40
src/Zcu.zig
|
|
@ -39,6 +39,8 @@ const AnalUnit = InternPool.AnalUnit;
|
|||
const BuiltinFn = std.zig.BuiltinFn;
|
||||
const LlvmObject = @import("codegen/llvm.zig").Object;
|
||||
const dev = @import("dev.zig");
|
||||
const Zoir = std.zig.Zoir;
|
||||
const ZonGen = std.zig.ZonGen;
|
||||
|
||||
comptime {
|
||||
@setEvalBranchQuota(4000);
|
||||
|
|
@ -672,6 +674,8 @@ pub const File = struct {
|
|||
tree: Ast,
|
||||
/// Whether this is populated or not depends on `zir_loaded`.
|
||||
zir: Zir,
|
||||
/// Cached Zoir, generated lazily.
|
||||
zoir: ?Zoir = null,
|
||||
/// Module that this file is a part of, managed externally.
|
||||
mod: *Package.Module,
|
||||
/// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
|
||||
|
|
@ -704,7 +708,19 @@ pub const File = struct {
|
|||
root: *Package.Module,
|
||||
};
|
||||
|
||||
pub fn getMode(self: File) Ast.Mode {
|
||||
if (std.mem.endsWith(u8, self.sub_file_path, ".zon")) {
|
||||
return .zon;
|
||||
} else if (std.mem.endsWith(u8, self.sub_file_path, ".zig")) {
|
||||
return .zig;
|
||||
} else {
|
||||
// `Module.importFile` rejects all other extensions
|
||||
unreachable;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unload(file: *File, gpa: Allocator) void {
|
||||
if (file.zoir) |zoir| zoir.deinit(gpa);
|
||||
file.unloadTree(gpa);
|
||||
file.unloadSource(gpa);
|
||||
file.unloadZir(gpa);
|
||||
|
|
@ -778,11 +794,24 @@ pub const File = struct {
|
|||
if (file.tree_loaded) return &file.tree;
|
||||
|
||||
const source = try file.getSource(gpa);
|
||||
file.tree = try Ast.parse(gpa, source.bytes, .zig);
|
||||
file.tree = try Ast.parse(gpa, source.bytes, file.getMode());
|
||||
file.tree_loaded = true;
|
||||
return &file.tree;
|
||||
}
|
||||
|
||||
pub fn getZoir(file: *File, zcu: *Zcu) !*const Zoir {
|
||||
if (file.zoir) |*zoir| return zoir;
|
||||
|
||||
assert(file.tree_loaded);
|
||||
assert(file.tree.mode == .zon);
|
||||
file.zoir = try ZonGen.generate(zcu.gpa, file.tree, .{});
|
||||
if (file.zoir.?.hasCompileErrors()) {
|
||||
try zcu.failed_files.putNoClobber(zcu.gpa, file, null);
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
return &file.zoir.?;
|
||||
}
|
||||
|
||||
pub fn fullyQualifiedNameLen(file: File) usize {
|
||||
const ext = std.fs.path.extension(file.sub_file_path);
|
||||
return file.sub_file_path.len - ext.len;
|
||||
|
|
@ -895,6 +924,7 @@ pub const File = struct {
|
|||
pub const Index = InternPool.FileIndex;
|
||||
};
|
||||
|
||||
/// Represents the contents of a file loaded with `@embedFile`.
|
||||
pub const EmbedFile = struct {
|
||||
/// Module that this file is a part of, managed externally.
|
||||
owner: *Package.Module,
|
||||
|
|
@ -2372,6 +2402,12 @@ pub const LazySrcLoc = struct {
|
|||
break :inst .{ info.file, info.inst };
|
||||
};
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
|
||||
// If we're relative to .main_struct_inst, we know the ast node is the root and don't need to resolve the ZIR,
|
||||
// which may not exist e.g. in the case of errors in ZON files.
|
||||
if (zir_inst == .main_struct_inst) return .{ file, 0 };
|
||||
|
||||
// Otherwise, make sure ZIR is loaded.
|
||||
assert(file.zir_loaded);
|
||||
|
||||
const zir = file.zir;
|
||||
|
|
@ -3461,8 +3497,6 @@ pub fn atomicPtrAlignment(
|
|||
}
|
||||
|
||||
/// Returns null in the following cases:
|
||||
/// * `@TypeOf(.{})`
|
||||
/// * A struct which has no fields (`struct {}`).
|
||||
/// * Not a struct.
|
||||
pub fn typeToStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType {
|
||||
if (ty.ip_index == .none) return null;
|
||||
|
|
|
|||
|
|
@ -1867,6 +1867,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
|
|||
const zcu = pt.zcu;
|
||||
const gpa = zcu.gpa;
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
assert(file.getMode() == .zig);
|
||||
assert(zcu.fileRootType(file_index) == .none);
|
||||
|
||||
if (file.status != .success_zir) {
|
||||
|
|
@ -2022,7 +2023,9 @@ pub fn importFile(
|
|||
if (mod.deps.get(import_string)) |pkg| {
|
||||
return pt.importPkg(pkg);
|
||||
}
|
||||
if (!std.mem.endsWith(u8, import_string, ".zig")) {
|
||||
if (!std.mem.endsWith(u8, import_string, ".zig") and
|
||||
!std.mem.endsWith(u8, import_string, ".zon"))
|
||||
{
|
||||
return error.ModuleNotFound;
|
||||
}
|
||||
const gpa = zcu.gpa;
|
||||
|
|
|
|||
|
|
@ -13776,8 +13776,8 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
|
|||
};
|
||||
const bit_count = extra.type.scalarBits(self);
|
||||
const val: i64 = if (bit_count <= 64)
|
||||
bigint.to(i64) catch unreachable
|
||||
else if (bigint.to(u64)) |val|
|
||||
bigint.toInt(i64) catch unreachable
|
||||
else if (bigint.toInt(u64)) |val|
|
||||
@bitCast(val)
|
||||
else |_| {
|
||||
const limbs = try record.addManyAsSlice(
|
||||
|
|
@ -14276,9 +14276,9 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
|
|||
else => unreachable,
|
||||
},
|
||||
};
|
||||
const val: i64 = if (bigint.to(i64)) |val|
|
||||
const val: i64 = if (bigint.toInt(i64)) |val|
|
||||
val
|
||||
else |_| if (bigint.to(u64)) |val|
|
||||
else |_| if (bigint.toInt(u64)) |val|
|
||||
@bitCast(val)
|
||||
else |_| {
|
||||
const limbs_len = std.math.divCeil(u32, extra.bit_width, 64) catch unreachable;
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ pub fn run(
|
|||
process.exit(2);
|
||||
}
|
||||
} else {
|
||||
const zoir = try std.zig.ZonGen.generate(gpa, tree);
|
||||
const zoir = try std.zig.ZonGen.generate(gpa, tree, .{});
|
||||
defer zoir.deinit(gpa);
|
||||
|
||||
if (zoir.hasCompileErrors()) {
|
||||
|
|
@ -335,7 +335,7 @@ fn fmtPathFile(
|
|||
}
|
||||
},
|
||||
.zon => {
|
||||
var zoir = try std.zig.ZonGen.generate(gpa, tree);
|
||||
var zoir = try std.zig.ZonGen.generate(gpa, tree, .{});
|
||||
defer zoir.deinit(gpa);
|
||||
|
||||
if (zoir.hasCompileErrors()) {
|
||||
|
|
|
|||
|
|
@ -6278,7 +6278,7 @@ fn cmdAstCheck(
|
|||
}
|
||||
},
|
||||
.zon => {
|
||||
const zoir = try ZonGen.generate(gpa, file.tree);
|
||||
const zoir = try ZonGen.generate(gpa, file.tree, .{});
|
||||
defer zoir.deinit(gpa);
|
||||
|
||||
if (zoir.hasCompileErrors()) {
|
||||
|
|
|
|||
|
|
@ -488,7 +488,6 @@ const Writer = struct {
|
|||
.enum_literal,
|
||||
.decl_ref,
|
||||
.decl_val,
|
||||
.import,
|
||||
.ret_err_value,
|
||||
.ret_err_value_code,
|
||||
.param_anytype,
|
||||
|
|
@ -515,6 +514,8 @@ const Writer = struct {
|
|||
.declaration => try self.writeDeclaration(stream, inst),
|
||||
|
||||
.extended => try self.writeExtended(stream, inst),
|
||||
|
||||
.import => try self.writeImport(stream, inst),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2842,4 +2843,13 @@ const Writer = struct {
|
|||
try stream.writeByte('\n');
|
||||
}
|
||||
}
|
||||
|
||||
fn writeImport(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
|
||||
const inst_data = self.code.instructions.items(.data)[@intFromEnum(inst)].pl_tok;
|
||||
const extra = self.code.extraData(Zir.Inst.Import, inst_data.payload_index).data;
|
||||
try self.writeInstRef(stream, extra.res_ty);
|
||||
const import_path = self.code.nullTerminatedString(extra.path);
|
||||
try stream.print(", \"{}\") ", .{std.zig.fmtEscapes(import_path)});
|
||||
try self.writeSrcTok(stream, inst_data.src_tok);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
519
test/behavior/zon.zig
Normal file
519
test/behavior/zon.zig
Normal file
|
|
@ -0,0 +1,519 @@
|
|||
const std = @import("std");
|
||||
|
||||
const expect = std.testing.expect;
|
||||
const expectEqual = std.testing.expectEqual;
|
||||
const expectEqualDeep = std.testing.expectEqualDeep;
|
||||
const expectEqualSlices = std.testing.expectEqualSlices;
|
||||
const expectEqualStrings = std.testing.expectEqualStrings;
|
||||
|
||||
test "bool" {
|
||||
try expectEqual(true, @as(bool, @import("zon/true.zon")));
|
||||
try expectEqual(false, @as(bool, @import("zon/false.zon")));
|
||||
}
|
||||
|
||||
test "optional" {
|
||||
const some: ?u32 = @import("zon/some.zon");
|
||||
const none: ?u32 = @import("zon/none.zon");
|
||||
const @"null": @TypeOf(null) = @import("zon/none.zon");
|
||||
try expectEqual(@as(u32, 10), some);
|
||||
try expectEqual(@as(?u32, null), none);
|
||||
try expectEqual(null, @"null");
|
||||
}
|
||||
|
||||
test "union" {
|
||||
// No tag
|
||||
{
|
||||
const Union = union {
|
||||
x: f32,
|
||||
y: bool,
|
||||
z: void,
|
||||
};
|
||||
|
||||
const union1: Union = @import("zon/union1.zon");
|
||||
const union2: Union = @import("zon/union2.zon");
|
||||
const union3: Union = @import("zon/union3.zon");
|
||||
|
||||
try expectEqual(1.5, union1.x);
|
||||
try expectEqual(true, union2.y);
|
||||
try expectEqual({}, union3.z);
|
||||
}
|
||||
|
||||
// Inferred tag
|
||||
{
|
||||
const Union = union(enum) {
|
||||
x: f32,
|
||||
y: bool,
|
||||
z: void,
|
||||
};
|
||||
|
||||
const union1: Union = comptime @import("zon/union1.zon");
|
||||
const union2: Union = @import("zon/union2.zon");
|
||||
const union3: Union = @import("zon/union3.zon");
|
||||
|
||||
try expectEqual(1.5, union1.x);
|
||||
try expectEqual(true, union2.y);
|
||||
try expectEqual({}, union3.z);
|
||||
}
|
||||
|
||||
// Explicit tag
|
||||
{
|
||||
const Tag = enum(i128) {
|
||||
x = -1,
|
||||
y = 2,
|
||||
z = 1,
|
||||
};
|
||||
const Union = union(Tag) {
|
||||
x: f32,
|
||||
y: bool,
|
||||
z: void,
|
||||
};
|
||||
|
||||
const union1: Union = @import("zon/union1.zon");
|
||||
const union2: Union = @import("zon/union2.zon");
|
||||
const union3: Union = @import("zon/union3.zon");
|
||||
|
||||
try expectEqual(1.5, union1.x);
|
||||
try expectEqual(true, union2.y);
|
||||
try expectEqual({}, union3.z);
|
||||
}
|
||||
}
|
||||
|
||||
test "struct" {
|
||||
const Vec0 = struct {};
|
||||
const Vec1 = struct { x: f32 };
|
||||
const Vec2 = struct { x: f32, y: f32 };
|
||||
const Escaped = struct { @"0": f32, foo: f32 };
|
||||
try expectEqual(Vec0{}, @as(Vec0, @import("zon/vec0.zon")));
|
||||
try expectEqual(Vec1{ .x = 1.5 }, @as(Vec1, @import("zon/vec1.zon")));
|
||||
try expectEqual(Vec2{ .x = 1.5, .y = 2 }, @as(Vec2, @import("zon/vec2.zon")));
|
||||
try expectEqual(Escaped{ .@"0" = 1.5, .foo = 2 }, @as(Escaped, @import("zon/escaped_struct.zon")));
|
||||
}
|
||||
|
||||
test "struct default fields" {
|
||||
const Vec3 = struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32 = 123.4,
|
||||
};
|
||||
try expectEqual(Vec3{ .x = 1.5, .y = 2.0, .z = 123.4 }, @as(Vec3, @import("zon/vec2.zon")));
|
||||
const ascribed: Vec3 = @import("zon/vec2.zon");
|
||||
try expectEqual(Vec3{ .x = 1.5, .y = 2.0, .z = 123.4 }, ascribed);
|
||||
|
||||
const Vec2 = struct {
|
||||
x: f32 = 20.0,
|
||||
y: f32 = 10.0,
|
||||
};
|
||||
try expectEqual(Vec2{ .x = 1.5, .y = 2.0 }, @as(Vec2, @import("zon/vec2.zon")));
|
||||
}
|
||||
|
||||
test "struct enum field" {
|
||||
const Struct = struct {
|
||||
x: enum { x, y, z },
|
||||
};
|
||||
try expectEqual(Struct{ .x = .z }, @as(Struct, @import("zon/enum_field.zon")));
|
||||
}
|
||||
|
||||
test "tuple" {
|
||||
const Tuple = struct { f32, bool, []const u8, u16 };
|
||||
try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
|
||||
}
|
||||
|
||||
test "comptime fields" {
|
||||
// Test setting comptime tuple fields to the correct value
|
||||
{
|
||||
const Tuple = struct {
|
||||
comptime f32 = 1.2,
|
||||
comptime bool = true,
|
||||
comptime []const u8 = "hello",
|
||||
comptime u16 = 3,
|
||||
};
|
||||
try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
|
||||
}
|
||||
|
||||
// Test setting comptime struct fields to the correct value
|
||||
{
|
||||
const Vec2 = struct {
|
||||
comptime x: f32 = 1.5,
|
||||
comptime y: f32 = 2.0,
|
||||
};
|
||||
try expectEqualDeep(Vec2{}, @as(Vec2, @import("zon/vec2.zon")));
|
||||
}
|
||||
|
||||
// Test allowing comptime tuple fields to be set to their defaults
|
||||
{
|
||||
const Tuple = struct {
|
||||
f32,
|
||||
bool,
|
||||
[]const u8,
|
||||
u16,
|
||||
comptime u8 = 255,
|
||||
};
|
||||
try expectEqualDeep(Tuple{ 1.2, true, "hello", 3 }, @as(Tuple, @import("zon/tuple.zon")));
|
||||
}
|
||||
|
||||
// Test allowing comptime struct fields to be set to their defaults
|
||||
{
|
||||
const Vec2 = struct {
|
||||
comptime x: f32 = 1.5,
|
||||
comptime y: f32 = 2.0,
|
||||
};
|
||||
try expectEqualDeep(Vec2{}, @as(Vec2, @import("zon/slice-empty.zon")));
|
||||
}
|
||||
}
|
||||
|
||||
test "char" {
|
||||
try expectEqual(@as(u8, 'a'), @as(u8, @import("zon/a.zon")));
|
||||
try expectEqual(@as(u8, 'z'), @as(u8, @import("zon/z.zon")));
|
||||
}
|
||||
|
||||
test "arrays" {
|
||||
try expectEqual([0]u8{}, @as([0]u8, @import("zon/vec0.zon")));
|
||||
try expectEqual([0:1]u8{}, @as([0:1]u8, @import("zon/vec0.zon")));
|
||||
try expectEqual(1, @as([0:1]u8, @import("zon/vec0.zon"))[0]);
|
||||
try expectEqual([4]u8{ 'a', 'b', 'c', 'd' }, @as([4]u8, @import("zon/array.zon")));
|
||||
try expectEqual([4:2]u8{ 'a', 'b', 'c', 'd' }, @as([4:2]u8, @import("zon/array.zon")));
|
||||
try expectEqual(2, @as([4:2]u8, @import("zon/array.zon"))[4]);
|
||||
}
|
||||
|
||||
test "slices, arrays, tuples" {
|
||||
{
|
||||
const expected_slice: []const u8 = &.{};
|
||||
const found_slice: []const u8 = @import("zon/slice-empty.zon");
|
||||
try expectEqualSlices(u8, expected_slice, found_slice);
|
||||
|
||||
const expected_array: [0]u8 = .{};
|
||||
const found_array: [0]u8 = @import("zon/slice-empty.zon");
|
||||
try expectEqual(expected_array, found_array);
|
||||
|
||||
const T = struct {};
|
||||
const expected_tuple: T = .{};
|
||||
const found_tuple: T = @import("zon/slice-empty.zon");
|
||||
try expectEqual(expected_tuple, found_tuple);
|
||||
}
|
||||
|
||||
{
|
||||
const expected_slice: []const u8 = &.{1};
|
||||
const found_slice: []const u8 = @import("zon/slice1_no_newline.zon");
|
||||
try expectEqualSlices(u8, expected_slice, found_slice);
|
||||
|
||||
const expected_array: [1]u8 = .{1};
|
||||
const found_array: [1]u8 = @import("zon/slice1_no_newline.zon");
|
||||
try expectEqual(expected_array, found_array);
|
||||
|
||||
const T = struct { u8 };
|
||||
const expected_tuple: T = .{1};
|
||||
const found_tuple: T = @import("zon/slice1_no_newline.zon");
|
||||
try expectEqual(expected_tuple, found_tuple);
|
||||
}
|
||||
|
||||
{
|
||||
const expected_slice: []const u8 = &.{ 'a', 'b', 'c' };
|
||||
const found_slice: []const u8 = @import("zon/slice-abc.zon");
|
||||
try expectEqualSlices(u8, expected_slice, found_slice);
|
||||
|
||||
const expected_array: [3]u8 = .{ 'a', 'b', 'c' };
|
||||
const found_array: [3]u8 = @import("zon/slice-abc.zon");
|
||||
try expectEqual(expected_array, found_array);
|
||||
|
||||
const T = struct { u8, u8, u8 };
|
||||
const expected_tuple: T = .{ 'a', 'b', 'c' };
|
||||
const found_tuple: T = @import("zon/slice-abc.zon");
|
||||
try expectEqual(expected_tuple, found_tuple);
|
||||
}
|
||||
}
|
||||
|
||||
test "string literals" {
|
||||
try expectEqualSlices(u8, "abc", @import("zon/abc.zon"));
|
||||
try expectEqualSlices(u8, "ab\\c", @import("zon/abc-escaped.zon"));
|
||||
const zero_terminated: [:0]const u8 = @import("zon/abc.zon");
|
||||
try expectEqualDeep(zero_terminated, "abc");
|
||||
try expectEqual(0, zero_terminated[zero_terminated.len]);
|
||||
try expectEqualStrings(
|
||||
\\Hello, world!
|
||||
\\This is a multiline string!
|
||||
\\ There are no escapes, we can, for example, include \n in the string
|
||||
, @import("zon/multiline_string.zon"));
|
||||
try expectEqualStrings("a\nb\x00c", @import("zon/string_embedded_null.zon"));
|
||||
}
|
||||
|
||||
test "enum literals" {
|
||||
const Enum = enum {
|
||||
foo,
|
||||
bar,
|
||||
baz,
|
||||
@"0\na",
|
||||
};
|
||||
try expectEqual(Enum.foo, @as(Enum, @import("zon/foo.zon")));
|
||||
try expectEqual(.foo, @as(@TypeOf(.foo), @import("zon/foo.zon")));
|
||||
try expectEqual(Enum.@"0\na", @as(Enum, @import("zon/escaped_enum.zon")));
|
||||
}
|
||||
|
||||
test "int" {
|
||||
const T = struct {
|
||||
u8,
|
||||
i16,
|
||||
i14,
|
||||
i32,
|
||||
i8,
|
||||
i8,
|
||||
u8,
|
||||
u8,
|
||||
u65,
|
||||
u65,
|
||||
i128,
|
||||
i128,
|
||||
i66,
|
||||
i66,
|
||||
i8,
|
||||
i8,
|
||||
i16,
|
||||
i16,
|
||||
i16,
|
||||
i16,
|
||||
i16,
|
||||
i16,
|
||||
u65,
|
||||
i66,
|
||||
i66,
|
||||
u65,
|
||||
i66,
|
||||
i66,
|
||||
u65,
|
||||
i66,
|
||||
i66,
|
||||
};
|
||||
const expected: T = .{
|
||||
// Test various numbers and types
|
||||
10,
|
||||
24,
|
||||
-4,
|
||||
-123,
|
||||
|
||||
// Test limits
|
||||
127,
|
||||
-128,
|
||||
|
||||
// Test characters
|
||||
'a',
|
||||
'z',
|
||||
|
||||
// Test big integers
|
||||
36893488147419103231,
|
||||
36893488147419103231,
|
||||
-18446744073709551615, // Only a big int due to negation
|
||||
-9223372036854775809, // Only a big int due to negation
|
||||
|
||||
// Test big integer limits
|
||||
36893488147419103231,
|
||||
-36893488147419103232,
|
||||
|
||||
// Test parsing whole number floats as integers
|
||||
-1,
|
||||
123,
|
||||
|
||||
// Test non-decimal integers
|
||||
0xff,
|
||||
-0xff,
|
||||
0o77,
|
||||
-0o77,
|
||||
0b11,
|
||||
-0b11,
|
||||
|
||||
// Test non-decimal big integers
|
||||
0x1ffffffffffffffff,
|
||||
0x1ffffffffffffffff,
|
||||
-0x1ffffffffffffffff,
|
||||
0x1ffffffffffffffff,
|
||||
0x1ffffffffffffffff,
|
||||
-0x1ffffffffffffffff,
|
||||
0x1ffffffffffffffff,
|
||||
0x1ffffffffffffffff,
|
||||
-0x1ffffffffffffffff,
|
||||
};
|
||||
const actual: T = @import("zon/ints.zon");
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "floats" {
|
||||
const T = struct {
|
||||
f16,
|
||||
f32,
|
||||
f64,
|
||||
f128,
|
||||
f16,
|
||||
f16,
|
||||
f32,
|
||||
f32,
|
||||
f32,
|
||||
f32,
|
||||
f32,
|
||||
f32,
|
||||
f128,
|
||||
f32,
|
||||
f32,
|
||||
f32,
|
||||
f32,
|
||||
f32,
|
||||
};
|
||||
const expected: T = .{
|
||||
// Test decimals
|
||||
0.5,
|
||||
123.456,
|
||||
-123.456,
|
||||
42.5,
|
||||
|
||||
// Test whole numbers with and without decimals
|
||||
5.0,
|
||||
5.0,
|
||||
-102,
|
||||
-102,
|
||||
|
||||
// Test characters and negated characters
|
||||
'a',
|
||||
'z',
|
||||
|
||||
// Test big integers
|
||||
36893488147419103231,
|
||||
-36893488147419103231,
|
||||
0x1ffffffffffffffff,
|
||||
0x1ffffffffffffffff,
|
||||
|
||||
// Exponents, underscores
|
||||
123.0E+77,
|
||||
|
||||
// Hexadecimal
|
||||
0x103.70p-5,
|
||||
-0x103.70,
|
||||
0x1234_5678.9ABC_CDEFp-10,
|
||||
};
|
||||
const actual: T = @import("zon/floats.zon");
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
test "inf and nan" {
|
||||
// f32
|
||||
{
|
||||
const actual: struct { f32, f32, f32 } = @import("zon/inf_and_nan.zon");
|
||||
try expect(std.math.isNan(actual[0]));
|
||||
try expect(std.math.isPositiveInf(actual[1]));
|
||||
try expect(std.math.isNegativeInf(actual[2]));
|
||||
}
|
||||
|
||||
// f128
|
||||
{
|
||||
const actual: struct { f128, f128, f128 } = @import("zon/inf_and_nan.zon");
|
||||
try expect(std.math.isNan(actual[0]));
|
||||
try expect(std.math.isPositiveInf(actual[1]));
|
||||
try expect(std.math.isNegativeInf(actual[2]));
|
||||
}
|
||||
}
|
||||
|
||||
test "vector" {
|
||||
{
|
||||
const actual: @Vector(0, bool) = @import("zon/vec0.zon");
|
||||
const expected: @Vector(0, bool) = .{};
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
{
|
||||
const actual: @Vector(3, bool) = @import("zon/vec3_bool.zon");
|
||||
const expected: @Vector(3, bool) = .{ false, false, true };
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
{
|
||||
const actual: @Vector(0, f32) = @import("zon/vec0.zon");
|
||||
const expected: @Vector(0, f32) = .{};
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
{
|
||||
const actual: @Vector(3, f32) = @import("zon/vec3_float.zon");
|
||||
const expected: @Vector(3, f32) = .{ 1.5, 2.5, 3.5 };
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
{
|
||||
const actual: @Vector(0, u8) = @import("zon/vec0.zon");
|
||||
const expected: @Vector(0, u8) = .{};
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
{
|
||||
const actual: @Vector(3, u8) = @import("zon/vec3_int.zon");
|
||||
const expected: @Vector(3, u8) = .{ 2, 4, 6 };
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
{
|
||||
const actual: @Vector(0, *const u8) = @import("zon/vec0.zon");
|
||||
const expected: @Vector(0, *const u8) = .{};
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
{
|
||||
const actual: @Vector(3, *const u8) = @import("zon/vec3_int.zon");
|
||||
const expected: @Vector(3, *const u8) = .{ &2, &4, &6 };
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
|
||||
{
|
||||
const actual: @Vector(0, ?*const u8) = @import("zon/vec0.zon");
|
||||
const expected: @Vector(0, ?*const u8) = .{};
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
{
|
||||
const actual: @Vector(3, ?*const u8) = @import("zon/vec3_int_opt.zon");
|
||||
const expected: @Vector(3, ?*const u8) = .{ &2, null, &6 };
|
||||
try expectEqual(expected, actual);
|
||||
}
|
||||
}
|
||||
|
||||
test "pointers" {
|
||||
// Primitive with varying levels of pointers
|
||||
try expectEqual(@as(u8, 'a'), @as(*const u8, @import("zon/a.zon")).*);
|
||||
try expectEqual(@as(u8, 'a'), @as(*const *const u8, @import("zon/a.zon")).*.*);
|
||||
try expectEqual(@as(u8, 'a'), @as(*const *const *const u8, @import("zon/a.zon")).*.*.*);
|
||||
|
||||
// Primitive optional with varying levels of pointers
|
||||
try expectEqual(@as(u8, 'a'), @as(?*const u8, @import("zon/a.zon")).?.*);
|
||||
try expectEqual(null, @as(?*const u8, @import("zon/none.zon")));
|
||||
|
||||
try expectEqual(@as(u8, 'a'), @as(*const ?u8, @import("zon/a.zon")).*.?);
|
||||
try expectEqual(null, @as(*const ?u8, @import("zon/none.zon")).*);
|
||||
|
||||
try expectEqual(@as(u8, 'a'), @as(?*const *const u8, @import("zon/a.zon")).?.*.*);
|
||||
try expectEqual(null, @as(?*const *const u8, @import("zon/none.zon")));
|
||||
|
||||
try expectEqual(@as(u8, 'a'), @as(*const ?*const u8, @import("zon/a.zon")).*.?.*);
|
||||
try expectEqual(null, @as(*const ?*const u8, @import("zon/none.zon")).*);
|
||||
|
||||
try expectEqual(@as(u8, 'a'), @as(*const *const ?u8, @import("zon/a.zon")).*.*.?);
|
||||
try expectEqual(null, @as(*const *const ?u8, @import("zon/none.zon")).*.*);
|
||||
|
||||
try expectEqual([3]u8{ 2, 4, 6 }, @as(*const [3]u8, @import("zon/vec3_int.zon")).*);
|
||||
|
||||
// A complicated type with nested internal pointers and string allocations
|
||||
{
|
||||
const Inner = struct {
|
||||
f1: *const ?*const []const u8,
|
||||
f2: *const ?*const []const u8,
|
||||
};
|
||||
const Outer = struct {
|
||||
f1: *const ?*const Inner,
|
||||
f2: *const ?*const Inner,
|
||||
};
|
||||
const expected: Outer = .{
|
||||
.f1 = &&.{
|
||||
.f1 = &null,
|
||||
.f2 = &&"foo",
|
||||
},
|
||||
.f2 = &null,
|
||||
};
|
||||
|
||||
const found: ?*const Outer = @import("zon/complex.zon");
|
||||
try std.testing.expectEqualDeep(expected, found.?.*);
|
||||
}
|
||||
}
|
||||
|
||||
test "recursive" {
|
||||
const Recursive = struct { foo: ?*const @This() };
|
||||
const expected: Recursive = .{ .foo = &.{ .foo = null } };
|
||||
try expectEqualDeep(expected, @as(Recursive, @import("zon/recursive.zon")));
|
||||
}
|
||||
1
test/behavior/zon/a.zon
Normal file
1
test/behavior/zon/a.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
'a'
|
||||
1
test/behavior/zon/abc-escaped.zon
Normal file
1
test/behavior/zon/abc-escaped.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
"ab\\c"
|
||||
1
test/behavior/zon/abc.zon
Normal file
1
test/behavior/zon/abc.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
"abc"
|
||||
1
test/behavior/zon/array.zon
Normal file
1
test/behavior/zon/array.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ 'a', 'b', 'c', 'd' }
|
||||
7
test/behavior/zon/complex.zon
Normal file
7
test/behavior/zon/complex.zon
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
.{
|
||||
.f1 = .{
|
||||
.f1 = null,
|
||||
.f2 = "foo",
|
||||
},
|
||||
.f2 = null,
|
||||
}
|
||||
1
test/behavior/zon/enum_field.zon
Normal file
1
test/behavior/zon/enum_field.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ .x = .z }
|
||||
1
test/behavior/zon/escaped_enum.zon
Normal file
1
test/behavior/zon/escaped_enum.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.@"0\na"
|
||||
2
test/behavior/zon/escaped_struct.zon
Normal file
2
test/behavior/zon/escaped_struct.zon
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
.{ .@"0" = 1.5, .@"foo" = 2 }
|
||||
4
test/behavior/zon/false.zon
Normal file
4
test/behavior/zon/false.zon
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// Comment
|
||||
false // Another comment
|
||||
// Yet another comment
|
||||
|
||||
25
test/behavior/zon/floats.zon
Normal file
25
test/behavior/zon/floats.zon
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
.{
|
||||
0.5,
|
||||
123.456,
|
||||
-123.456,
|
||||
42.5,
|
||||
|
||||
5.0,
|
||||
5,
|
||||
-102.0,
|
||||
-102,
|
||||
|
||||
'a',
|
||||
'z',
|
||||
|
||||
36893488147419103231,
|
||||
-36893488147419103231,
|
||||
0x1ffffffffffffffff,
|
||||
0x1ffffffffffffffff,
|
||||
|
||||
12_3.0E+77,
|
||||
|
||||
0x103.70p-5,
|
||||
-0x103.70,
|
||||
0x1234_5678.9ABC_CDEFp-10,
|
||||
}
|
||||
1
test/behavior/zon/foo.zon
Normal file
1
test/behavior/zon/foo.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.foo
|
||||
5
test/behavior/zon/inf_and_nan.zon
Normal file
5
test/behavior/zon/inf_and_nan.zon
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
.{
|
||||
nan,
|
||||
inf,
|
||||
-inf,
|
||||
}
|
||||
40
test/behavior/zon/ints.zon
Normal file
40
test/behavior/zon/ints.zon
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
.{
|
||||
10,
|
||||
24,
|
||||
-4,
|
||||
-123,
|
||||
|
||||
127,
|
||||
-128,
|
||||
|
||||
'a',
|
||||
'z',
|
||||
|
||||
36893488147419103231,
|
||||
368934_881_474191032_31,
|
||||
-18446744073709551615,
|
||||
-9223372036854775809,
|
||||
|
||||
36893488147419103231,
|
||||
-36893488147419103232,
|
||||
|
||||
-1.0,
|
||||
123.0,
|
||||
|
||||
0xff,
|
||||
-0xff,
|
||||
0o77,
|
||||
-0o77,
|
||||
0b11,
|
||||
-0b11,
|
||||
|
||||
0x1ffffffffffffffff,
|
||||
0x1ffffffffffffffff,
|
||||
-0x1ffffffffffffffff,
|
||||
0o3777777777777777777777,
|
||||
0o3777777777777777777777,
|
||||
-0o3777777777777777777777,
|
||||
0b11111111111111111111111111111111111111111111111111111111111111111,
|
||||
0b11111111111111111111111111111111111111111111111111111111111111111,
|
||||
-0b11111111111111111111111111111111111111111111111111111111111111111,
|
||||
}
|
||||
4
test/behavior/zon/multiline_string.zon
Normal file
4
test/behavior/zon/multiline_string.zon
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
// zig fmt: off
|
||||
\\Hello, world!
|
||||
\\This is a multiline string!
|
||||
\\ There are no escapes, we can, for example, include \n in the string
|
||||
1
test/behavior/zon/none.zon
Normal file
1
test/behavior/zon/none.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
null
|
||||
1
test/behavior/zon/recursive.zon
Normal file
1
test/behavior/zon/recursive.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ .foo = .{ .foo = null } }
|
||||
1
test/behavior/zon/slice-abc.zon
Normal file
1
test/behavior/zon/slice-abc.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{'a', 'b', 'c'}
|
||||
1
test/behavior/zon/slice-empty.zon
Normal file
1
test/behavior/zon/slice-empty.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{}
|
||||
1
test/behavior/zon/slice1_no_newline.zon
Normal file
1
test/behavior/zon/slice1_no_newline.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ 1 }
|
||||
1
test/behavior/zon/some.zon
Normal file
1
test/behavior/zon/some.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
10
|
||||
1
test/behavior/zon/string_embedded_null.zon
Normal file
1
test/behavior/zon/string_embedded_null.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
"a\nb\x00c"
|
||||
1
test/behavior/zon/true.zon
Normal file
1
test/behavior/zon/true.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
true
|
||||
1
test/behavior/zon/tuple.zon
Normal file
1
test/behavior/zon/tuple.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ 1.2, true, "hello", 3 }
|
||||
1
test/behavior/zon/union1.zon
Normal file
1
test/behavior/zon/union1.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ .x = 1.5 }
|
||||
1
test/behavior/zon/union2.zon
Normal file
1
test/behavior/zon/union2.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ .y = true }
|
||||
1
test/behavior/zon/union3.zon
Normal file
1
test/behavior/zon/union3.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.z
|
||||
1
test/behavior/zon/vec0.zon
Normal file
1
test/behavior/zon/vec0.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{}
|
||||
1
test/behavior/zon/vec1.zon
Normal file
1
test/behavior/zon/vec1.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ .x = 1.5 }
|
||||
1
test/behavior/zon/vec2.zon
Normal file
1
test/behavior/zon/vec2.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ .x = 1.5, .y = 2 }
|
||||
1
test/behavior/zon/vec3_bool.zon
Normal file
1
test/behavior/zon/vec3_bool.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ false, false, true }
|
||||
1
test/behavior/zon/vec3_float.zon
Normal file
1
test/behavior/zon/vec3_float.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ 1.5, 2.5, 3.5 }
|
||||
1
test/behavior/zon/vec3_int.zon
Normal file
1
test/behavior/zon/vec3_int.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ 2, 4, 6 }
|
||||
1
test/behavior/zon/vec3_int_opt.zon
Normal file
1
test/behavior/zon/vec3_int_opt.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
.{ 2, null, 6 }
|
||||
1
test/behavior/zon/z.zon
Normal file
1
test/behavior/zon/z.zon
Normal file
|
|
@ -0,0 +1 @@
|
|||
'z'
|
||||
9
test/cases/compile_errors/@import_zon_addr_slice.zig
Normal file
9
test/cases/compile_errors/@import_zon_addr_slice.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
pub fn main() void {
|
||||
const f: struct { value: []const i32 } = @import("zon/addr_slice.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/addr_slice.zon
|
||||
//
|
||||
// addr_slice.zon:2:14: error: pointers are not available in ZON
|
||||
10
test/cases/compile_errors/@import_zon_array_len.zig
Normal file
10
test/cases/compile_errors/@import_zon_array_len.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: [4]u8 = @import("zon/array.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/array.zon
|
||||
//
|
||||
// array.zon:1:2: error: expected type '[4]u8'
|
||||
// tmp.zig:2:30: note: imported here
|
||||
9
test/cases/compile_errors/@import_zon_bad_import.zig
Normal file
9
test/cases/compile_errors/@import_zon_bad_import.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
_ = @import(
|
||||
"bogus-does-not-exist.zon",
|
||||
);
|
||||
}
|
||||
|
||||
// error
|
||||
//
|
||||
// :3:9: error: unable to open 'bogus-does-not-exist.zon': FileNotFound
|
||||
125
test/cases/compile_errors/@import_zon_bad_type.zig
Normal file
125
test/cases/compile_errors/@import_zon_bad_type.zig
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
export fn testVoid() void {
|
||||
const f: void = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testInStruct() void {
|
||||
const f: struct { f: [*]const u8 } = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testError() void {
|
||||
const f: struct { error{foo} } = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testInUnion() void {
|
||||
const f: union(enum) { a: void, b: [*c]const u8 } = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testInVector() void {
|
||||
const f: @Vector(0, [*c]const u8) = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testInOpt() void {
|
||||
const f: *const ?[*c]const u8 = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testComptimeField() void {
|
||||
const f: struct { comptime foo: ??u8 = null } = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testEnumLiteral() void {
|
||||
const f: @TypeOf(.foo) = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testNestedOpt1() void {
|
||||
const f: ??u8 = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testNestedOpt2() void {
|
||||
const f: ?*const ?u8 = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testNestedOpt3() void {
|
||||
const f: *const ?*const ?*const u8 = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testOpt() void {
|
||||
const f: ?u8 = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testNonExhaustiveEnum() void {
|
||||
const f: enum(u8) { _ } = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testUntaggedUnion() void {
|
||||
const f: union { foo: void } = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testTaggedUnionVoid() void {
|
||||
const f: union(enum) { foo: void } = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testVisited() void {
|
||||
const V = struct {
|
||||
?f32, // Adds `?f32` to the visited list
|
||||
??f32, // `?f32` is already visited, we need to detect the nested opt anyway
|
||||
f32,
|
||||
};
|
||||
const f: V = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testMutablePointer() void {
|
||||
const f: *i32 = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/neg_inf.zon
|
||||
//
|
||||
// tmp.zig:2:29: error: type 'void' is not available in ZON
|
||||
// tmp.zig:7:50: error: type '[*]const u8' is not available in ZON
|
||||
// tmp.zig:7:50: note: ZON does not allow many-pointers
|
||||
// tmp.zig:12:46: error: type 'error{foo}' is not available in ZON
|
||||
// tmp.zig:17:65: error: type '[*c]const u8' is not available in ZON
|
||||
// tmp.zig:17:65: note: ZON does not allow C pointers
|
||||
// tmp.zig:22:49: error: type '[*c]const u8' is not available in ZON
|
||||
// tmp.zig:22:49: note: ZON does not allow C pointers
|
||||
// tmp.zig:27:45: error: type '[*c]const u8' is not available in ZON
|
||||
// tmp.zig:27:45: note: ZON does not allow C pointers
|
||||
// tmp.zig:32:61: error: type '??u8' is not available in ZON
|
||||
// tmp.zig:32:61: note: ZON does not allow nested optionals
|
||||
// tmp.zig:42:29: error: type '??u8' is not available in ZON
|
||||
// tmp.zig:42:29: note: ZON does not allow nested optionals
|
||||
// tmp.zig:47:36: error: type '?*const ?u8' is not available in ZON
|
||||
// tmp.zig:47:36: note: ZON does not allow nested optionals
|
||||
// tmp.zig:52:50: error: type '?*const ?*const u8' is not available in ZON
|
||||
// tmp.zig:52:50: note: ZON does not allow nested optionals
|
||||
// tmp.zig:82:26: error: type '??f32' is not available in ZON
|
||||
// tmp.zig:82:26: note: ZON does not allow nested optionals
|
||||
// tmp.zig:87:29: error: type '*i32' is not available in ZON
|
||||
// tmp.zig:87:29: note: ZON does not allow mutable pointers
|
||||
// neg_inf.zon:1:1: error: expected type '@Type(.enum_literal)'
|
||||
// tmp.zig:37:38: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type '?u8'
|
||||
// tmp.zig:57:28: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testNonExhaustiveEnum__enum_490'
|
||||
// tmp.zig:62:39: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testUntaggedUnion__union_492'
|
||||
// tmp.zig:67:44: note: imported here
|
||||
// neg_inf.zon:1:1: error: expected type 'tmp.testTaggedUnionVoid__union_495'
|
||||
// tmp.zig:72:50: note: imported here
|
||||
10
test/cases/compile_errors/@import_zon_comptime_inf.zig
Normal file
10
test/cases/compile_errors/@import_zon_comptime_inf.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: comptime_float = @import("zon/inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/inf.zon
|
||||
//
|
||||
// inf.zon:1:1: error: expected type 'comptime_float'
|
||||
// tmp.zig:2:39: note: imported here
|
||||
10
test/cases/compile_errors/@import_zon_comptime_nan.zig
Normal file
10
test/cases/compile_errors/@import_zon_comptime_nan.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: comptime_float = @import("zon/nan.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/nan.zon
|
||||
//
|
||||
// nan.zon:1:1: error: expected type 'comptime_float'
|
||||
// tmp.zig:2:39: note: imported here
|
||||
10
test/cases/compile_errors/@import_zon_comptime_neg_inf.zig
Normal file
10
test/cases/compile_errors/@import_zon_comptime_neg_inf.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: comptime_float = @import("zon/neg_inf.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/neg_inf.zon
|
||||
//
|
||||
// neg_inf.zon:1:1: error: expected type 'comptime_float'
|
||||
// tmp.zig:2:39: note: imported here
|
||||
9
test/cases/compile_errors/@import_zon_doc_comment.zig
Normal file
9
test/cases/compile_errors/@import_zon_doc_comment.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: struct { foo: type } = @import("zon/doc_comment.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/doc_comment.zon
|
||||
//
|
||||
// doc_comment.zon:1:1: error: expected expression, found 'a document comment'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: f32 = @import("zon/double_negation_float.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/double_negation_float.zon
|
||||
//
|
||||
// double_negation_float.zon:1:1: error: expected number or 'inf' after '-'
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: i32 = @import("zon/double_negation_int.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/double_negation_int.zon
|
||||
//
|
||||
// double_negation_int.zon:1:1: error: expected number or 'inf' after '-'
|
||||
11
test/cases/compile_errors/@import_zon_enum_embedded_null.zig
Normal file
11
test/cases/compile_errors/@import_zon_enum_embedded_null.zig
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
const std = @import("std");
|
||||
export fn entry() void {
|
||||
const E = enum { foo };
|
||||
const f: struct { E, E } = @import("zon/enum_embedded_null.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/enum_embedded_null.zon
|
||||
//
|
||||
// enum_embedded_null.zon:2:6: error: identifier cannot contain null bytes
|
||||
11
test/cases/compile_errors/@import_zon_expected_void.zig
Normal file
11
test/cases/compile_errors/@import_zon_expected_void.zig
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export fn entry() void {
|
||||
const U = union(enum) { a: void };
|
||||
const f: U = @import("zon/simple_union.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/simple_union.zon
|
||||
//
|
||||
// simple_union.zon:1:9: error: expected type 'void'
|
||||
// tmp.zig:3:26: note: imported here
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: u8 = @import("zon/invalid_character.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/invalid_character.zon
|
||||
//
|
||||
// invalid_character.zon:1:3: error: invalid escape character: 'a'
|
||||
9
test/cases/compile_errors/@import_zon_invalid_number.zig
Normal file
9
test/cases/compile_errors/@import_zon_invalid_number.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: u128 = @import("zon/invalid_number.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/invalid_number.zon
|
||||
//
|
||||
// invalid_number.zon:1:19: error: invalid digit 'a' for decimal base
|
||||
9
test/cases/compile_errors/@import_zon_invalid_string.zig
Normal file
9
test/cases/compile_errors/@import_zon_invalid_string.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: []const u8 = @import("zon/invalid_string.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/invalid_string.zon
|
||||
//
|
||||
// invalid_string.zon:1:5: error: invalid escape character: 'a'
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: u128 = @import("zon/leading_zero_in_integer.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/leading_zero_in_integer.zon
|
||||
//
|
||||
// leading_zero_in_integer.zon:1:1: error: number '0012' has leading zero
|
||||
// leading_zero_in_integer.zon:1:1: note: use '0o' prefix for octal literals
|
||||
9
test/cases/compile_errors/@import_zon_neg_char.zig
Normal file
9
test/cases/compile_errors/@import_zon_neg_char.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: u8 = @import("zon/neg_char.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/neg_char.zon
|
||||
//
|
||||
// neg_char.zon:1:1: error: expected number or 'inf' after '-'
|
||||
9
test/cases/compile_errors/@import_zon_neg_nan.zig
Normal file
9
test/cases/compile_errors/@import_zon_neg_nan.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: u8 = @import("zon/neg_nan.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/neg_nan.zon
|
||||
//
|
||||
// neg_nan.zon:1:1: error: expected number or 'inf' after '-'
|
||||
11
test/cases/compile_errors/@import_zon_negative_zero.zig
Normal file
11
test/cases/compile_errors/@import_zon_negative_zero.zig
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
export fn entry() void {
|
||||
const f: i8 = @import("zon/negative_zero.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/negative_zero.zon
|
||||
//
|
||||
// negative_zero.zon:1:2: error: integer literal '-0' is ambiguous
|
||||
// negative_zero.zon:1:2: note: use '0' for an integer zero
|
||||
// negative_zero.zon:1:2: note: use '-0.0' for a floating-point signed zero
|
||||
9
test/cases/compile_errors/@import_zon_no_rt.zig
Normal file
9
test/cases/compile_errors/@import_zon_no_rt.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f = @import("zon/simple_union.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/simple_union.zon
|
||||
//
|
||||
// tmp.zig:2:23: error: '@import' of ZON must have a known result type
|
||||
10
test/cases/compile_errors/@import_zon_number_fail_limits.zig
Normal file
10
test/cases/compile_errors/@import_zon_number_fail_limits.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: i66 = @import("zon/large_number.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/large_number.zon
|
||||
//
|
||||
// large_number.zon:1:1: error: type 'i66' cannot represent integer value '36893488147419103232'
|
||||
// tmp.zig:2:28: note: imported here
|
||||
16
test/cases/compile_errors/@import_zon_oob_char_0.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_char_0.zig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export fn entry() void {
|
||||
{
|
||||
const f: u6 = @import("zon/char_32.zon");
|
||||
_ = f;
|
||||
}
|
||||
{
|
||||
const f: u5 = @import("zon/char_32.zon");
|
||||
_ = f;
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/char_32.zon
|
||||
//
|
||||
// char_32.zon:1:1: error: type 'u5' cannot represent integer value '32'
|
||||
// tmp.zig:7:31: note: imported here
|
||||
16
test/cases/compile_errors/@import_zon_oob_char_1.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_char_1.zig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export fn entry() void {
|
||||
{
|
||||
const f: i7 = @import("zon/char_32.zon");
|
||||
_ = f;
|
||||
}
|
||||
{
|
||||
const f: i6 = @import("zon/char_32.zon");
|
||||
_ = f;
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/char_32.zon
|
||||
//
|
||||
// char_32.zon:1:1: error: type 'i6' cannot represent integer value '32'
|
||||
// tmp.zig:7:31: note: imported here
|
||||
16
test/cases/compile_errors/@import_zon_oob_int_0.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_int_0.zig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export fn entry() void {
|
||||
{
|
||||
const f: u6 = @import("zon/int_32.zon");
|
||||
_ = f;
|
||||
}
|
||||
{
|
||||
const f: u5 = @import("zon/int_32.zon");
|
||||
_ = f;
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/int_32.zon
|
||||
//
|
||||
// int_32.zon:1:1: error: type 'u5' cannot represent integer value '32'
|
||||
// tmp.zig:7:31: note: imported here
|
||||
16
test/cases/compile_errors/@import_zon_oob_int_1.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_int_1.zig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export fn entry() void {
|
||||
{
|
||||
const f: i7 = @import("zon/int_32.zon");
|
||||
_ = f;
|
||||
}
|
||||
{
|
||||
const f: i6 = @import("zon/int_32.zon");
|
||||
_ = f;
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/int_32.zon
|
||||
//
|
||||
// int_32.zon:1:1: error: type 'i6' cannot represent integer value '32'
|
||||
// tmp.zig:7:31: note: imported here
|
||||
16
test/cases/compile_errors/@import_zon_oob_int_2.zig
Normal file
16
test/cases/compile_errors/@import_zon_oob_int_2.zig
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
export fn entry() void {
|
||||
{
|
||||
const f: i7 = @import("zon/int_neg_33.zon");
|
||||
_ = f;
|
||||
}
|
||||
{
|
||||
const f: i6 = @import("zon/int_neg_33.zon");
|
||||
_ = f;
|
||||
}
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/int_neg_33.zon
|
||||
//
|
||||
// int_neg_33.zon:1:1: error: type 'i6' cannot represent integer value '-33'
|
||||
// tmp.zig:7:31: note: imported here
|
||||
10
test/cases/compile_errors/@import_zon_oob_int_3.zig
Normal file
10
test/cases/compile_errors/@import_zon_oob_int_3.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: u64 = @import("zon/int_neg_33.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/int_neg_33.zon
|
||||
//
|
||||
// int_neg_33.zon:1:1: error: type 'u64' cannot represent integer value '-33'
|
||||
// tmp.zig:2:28: note: imported here
|
||||
82
test/cases/compile_errors/@import_zon_opt_in_err.zig
Normal file
82
test/cases/compile_errors/@import_zon_opt_in_err.zig
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
export fn testFloatA() void {
|
||||
const f: ?f32 = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testFloatB() void {
|
||||
const f: *const ?f32 = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testFloatC() void {
|
||||
const f: ?*const f32 = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testBool() void {
|
||||
const f: ?bool = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testInt() void {
|
||||
const f: ?i32 = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
const Enum = enum { foo };
|
||||
export fn testEnum() void {
|
||||
const f: ?Enum = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testEnumLit() void {
|
||||
const f: ?@TypeOf(.foo) = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testArray() void {
|
||||
const f: ?[1]u8 = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
const Union = union {};
|
||||
export fn testUnion() void {
|
||||
const f: ?Union = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testSlice() void {
|
||||
const f: ?[]const u8 = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
export fn testVector() void {
|
||||
const f: ?@Vector(3, f32) = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/vec2.zon
|
||||
//
|
||||
// vec2.zon:1:2: error: expected type '?f32'
|
||||
// tmp.zig:2:29: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '*const ?f32'
|
||||
// tmp.zig:7:36: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?*const f32'
|
||||
// tmp.zig:12:36: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?bool'
|
||||
// tmp.zig:17:30: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?i32'
|
||||
// tmp.zig:22:29: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?tmp.Enum'
|
||||
// tmp.zig:28:30: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?@Type(.enum_literal)'
|
||||
// tmp.zig:33:39: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?[1]u8'
|
||||
// tmp.zig:38:31: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?tmp.Union'
|
||||
// tmp.zig:44:31: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?[]const u8'
|
||||
// tmp.zig:49:36: note: imported here
|
||||
// vec2.zon:1:2: error: expected type '?@Vector(3, f32)'
|
||||
// tmp.zig:54:41: note: imported here
|
||||
19
test/cases/compile_errors/@import_zon_opt_in_err_struct.zig
Normal file
19
test/cases/compile_errors/@import_zon_opt_in_err_struct.zig
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
const Struct = struct { f: bool };
|
||||
export fn testStruct() void {
|
||||
const f: ?Struct = @import("zon/nan.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
const Tuple = struct { bool };
|
||||
export fn testTuple() void {
|
||||
const f: ?Tuple = @import("zon/nan.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/nan.zon
|
||||
//
|
||||
//nan.zon:1:1: error: expected type '?tmp.Struct'
|
||||
//tmp.zig:3:32: note: imported here
|
||||
//nan.zon:1:1: error: expected type '?struct { bool }'
|
||||
//tmp.zig:9:31: note: imported here
|
||||
10
test/cases/compile_errors/@import_zon_string_as_array.zig
Normal file
10
test/cases/compile_errors/@import_zon_string_as_array.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: [5]u8 = @import("zon/hello.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/hello.zon
|
||||
//
|
||||
// hello.zon:1:1: error: expected type '[5]u8'
|
||||
// tmp.zig:2:30: note: imported here
|
||||
11
test/cases/compile_errors/@import_zon_struct_dup_field.zig
Normal file
11
test/cases/compile_errors/@import_zon_struct_dup_field.zig
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
const std = @import("std");
|
||||
export fn entry() void {
|
||||
const f: struct { name: u8 } = @import("zon/struct_dup_field.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/struct_dup_field.zon
|
||||
//
|
||||
// struct_dup_field.zon:2:6: error: duplicate struct field name
|
||||
// struct_dup_field.zon:3:6: note: duplicate name here
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
export fn entry() void {
|
||||
const Vec2 = struct {
|
||||
comptime x: f32 = 1.5,
|
||||
comptime y: f32 = 2.5,
|
||||
};
|
||||
const f: Vec2 = @import("zon/vec2.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/vec2.zon
|
||||
//
|
||||
// vec2.zon:1:19: error: value stored in comptime field does not match the default value of the field
|
||||
// tmp.zig:6:29: note: imported here
|
||||
9
test/cases/compile_errors/@import_zon_syntax_error.zig
Normal file
9
test/cases/compile_errors/@import_zon_syntax_error.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: bool = @import("zon/syntax_error.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/syntax_error.zon
|
||||
//
|
||||
// syntax_error.zon:3:13: error: expected ',' after initializer
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
export fn entry() void {
|
||||
const T = struct {
|
||||
comptime f32 = 1.5,
|
||||
comptime f32 = 2.5,
|
||||
};
|
||||
const f: T = @import("zon/tuple.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/tuple.zon
|
||||
//
|
||||
// tuple.zon:1:9: error: value stored in comptime field does not match the default value of the field
|
||||
// tmp.zig:6:26: note: imported here
|
||||
9
test/cases/compile_errors/@import_zon_type_decl.zig
Normal file
9
test/cases/compile_errors/@import_zon_type_decl.zig
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export fn entry() void {
|
||||
const f: struct { foo: type } = @import("zon/type_decl.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/type_decl.zon
|
||||
//
|
||||
// type_decl.zon:2:12: error: types are not available in ZON
|
||||
10
test/cases/compile_errors/@import_zon_type_expr_array.zig
Normal file
10
test/cases/compile_errors/@import_zon_type_expr_array.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: [3]i32 = @import("zon/type_expr_array.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/type_expr_array.zon
|
||||
//
|
||||
// type_expr_array.zon:1:1: error: types are not available in ZON
|
||||
// type_expr_array.zon:1:1: note: replace the type with '.'
|
||||
10
test/cases/compile_errors/@import_zon_type_expr_fn.zig
Normal file
10
test/cases/compile_errors/@import_zon_type_expr_fn.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: i32 = @import("zon/type_expr_fn.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/type_expr_fn.zon
|
||||
//
|
||||
// type_expr_fn.zon:1:1: error: types are not available in ZON
|
||||
// type_expr_fn.zon:1:1: note: replace the type with '.'
|
||||
10
test/cases/compile_errors/@import_zon_type_expr_struct.zig
Normal file
10
test/cases/compile_errors/@import_zon_type_expr_struct.zig
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export fn entry() void {
|
||||
const f: struct { x: f32, y: f32 } = @import("zon/type_expr_struct.zon");
|
||||
_ = f;
|
||||
}
|
||||
|
||||
// error
|
||||
// imports=zon/type_expr_struct.zon
|
||||
//
|
||||
// type_expr_struct.zon:1:1: error: types are not available in ZON
|
||||
// type_expr_struct.zon:1:1: note: replace the type with '.'
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue