various intern pool & comptime interpreter changes (#1179)
* intern_pool: add getUnsignedInt * add an empty struct literal * resolve array length as usize in comptime interpreter * use only one global intern pool * store analysis errors in `DocumentStore.Handle` * add typed undefined value * add typed null value
This commit is contained in:
parent
f6c808a4b3
commit
029f5094ff
@ -20,24 +20,16 @@ pub const ComptimeInterpreter = @This();
|
|||||||
const log = std.log.scoped(.zls_comptime_interpreter);
|
const log = std.log.scoped(.zls_comptime_interpreter);
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
ip: InternPool,
|
ip: *InternPool,
|
||||||
document_store: *DocumentStore,
|
document_store: *DocumentStore,
|
||||||
uri: DocumentStore.Uri,
|
uri: DocumentStore.Uri,
|
||||||
namespaces: std.MultiArrayList(Namespace) = .{},
|
namespaces: std.MultiArrayList(Namespace) = .{},
|
||||||
|
|
||||||
/// Interpreter diagnostic errors
|
|
||||||
errors: std.AutoArrayHashMapUnmanaged(Ast.Node.Index, InterpreterError) = .{},
|
|
||||||
|
|
||||||
pub fn getHandle(interpreter: *ComptimeInterpreter) *const DocumentStore.Handle {
|
pub fn getHandle(interpreter: *ComptimeInterpreter) *const DocumentStore.Handle {
|
||||||
// This interpreter is loaded from a known-valid handle so a valid handle must exist
|
// This interpreter is loaded from a known-valid handle so a valid handle must exist
|
||||||
return interpreter.document_store.getHandle(interpreter.uri).?;
|
return interpreter.document_store.getHandle(interpreter.uri).?;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const InterpreterError = struct {
|
|
||||||
code: []const u8,
|
|
||||||
message: []const u8,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub fn recordError(
|
pub fn recordError(
|
||||||
interpreter: *ComptimeInterpreter,
|
interpreter: *ComptimeInterpreter,
|
||||||
node_idx: Ast.Node.Index,
|
node_idx: Ast.Node.Index,
|
||||||
@ -47,25 +39,21 @@ pub fn recordError(
|
|||||||
) error{OutOfMemory}!void {
|
) error{OutOfMemory}!void {
|
||||||
const message = try std.fmt.allocPrint(interpreter.allocator, fmt, args);
|
const message = try std.fmt.allocPrint(interpreter.allocator, fmt, args);
|
||||||
errdefer interpreter.allocator.free(message);
|
errdefer interpreter.allocator.free(message);
|
||||||
const previous = try interpreter.errors.fetchPut(interpreter.allocator, node_idx, .{
|
const handle = interpreter.document_store.handles.get(interpreter.uri).?;
|
||||||
|
try handle.analysis_errors.append(interpreter.document_store.allocator, .{
|
||||||
|
.loc = offsets.nodeToLoc(handle.tree, node_idx),
|
||||||
.code = code,
|
.code = code,
|
||||||
.message = message,
|
.message = message,
|
||||||
});
|
});
|
||||||
if (previous) |p| interpreter.allocator.free(p.value.message);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(interpreter: *ComptimeInterpreter) void {
|
pub fn deinit(interpreter: *ComptimeInterpreter) void {
|
||||||
for (interpreter.errors.values()) |err| {
|
for (
|
||||||
interpreter.allocator.free(err.message);
|
interpreter.namespaces.items(.decls),
|
||||||
}
|
interpreter.namespaces.items(.usingnamespaces),
|
||||||
|
) |*decls, *usingnamespaces| {
|
||||||
interpreter.errors.deinit(interpreter.allocator);
|
decls.deinit(interpreter.allocator);
|
||||||
interpreter.ip.deinit(interpreter.allocator);
|
usingnamespaces.deinit(interpreter.allocator);
|
||||||
|
|
||||||
var i: usize = 0;
|
|
||||||
while (i < interpreter.namespaces.len) : (i += 1) {
|
|
||||||
interpreter.namespaces.items(.decls)[i].deinit(interpreter.allocator);
|
|
||||||
interpreter.namespaces.items(.usingnamespaces)[i].deinit(interpreter.allocator);
|
|
||||||
}
|
}
|
||||||
interpreter.namespaces.deinit(interpreter.allocator);
|
interpreter.namespaces.deinit(interpreter.allocator);
|
||||||
}
|
}
|
||||||
@ -240,7 +228,7 @@ pub fn interpret(
|
|||||||
container_field.ast.type_expr,
|
container_field.ast.type_expr,
|
||||||
"expected_type",
|
"expected_type",
|
||||||
"expected type 'type', found '{}'",
|
"expected type 'type', found '{}'",
|
||||||
.{init_value_ty.fmt(interpreter.ip)},
|
.{init_value_ty.fmt(interpreter.ip.*)},
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -470,7 +458,7 @@ pub fn interpret(
|
|||||||
const can_have_fields: bool = switch (inner_ty) {
|
const can_have_fields: bool = switch (inner_ty) {
|
||||||
.simple_type => |simple| switch (simple) {
|
.simple_type => |simple| switch (simple) {
|
||||||
.type => blk: {
|
.type => blk: {
|
||||||
if (interpreter.huntItDown(val.getNamespace(interpreter.ip), field_name, options)) |decl_index| {
|
if (interpreter.huntItDown(val.getNamespace(interpreter.ip.*), field_name, options)) |decl_index| {
|
||||||
const decl = interpreter.ip.getDecl(decl_index);
|
const decl = interpreter.ip.getDecl(decl_index);
|
||||||
return InterpretResult{ .value = Value{
|
return InterpretResult{ .value = Value{
|
||||||
.interpreter = interpreter,
|
.interpreter = interpreter,
|
||||||
@ -560,7 +548,7 @@ pub fn interpret(
|
|||||||
.interpreter = interpreter,
|
.interpreter = interpreter,
|
||||||
.node_idx = data[node_idx].rhs,
|
.node_idx = data[node_idx].rhs,
|
||||||
.index = try interpreter.ip.get(interpreter.allocator, .{ .int_u64_value = .{
|
.index = try interpreter.ip.get(interpreter.allocator, .{ .int_u64_value = .{
|
||||||
.ty = .comptime_int_type,
|
.ty = .usize_type,
|
||||||
.int = array_info.len,
|
.int = array_info.len,
|
||||||
} }),
|
} }),
|
||||||
} };
|
} };
|
||||||
@ -575,7 +563,7 @@ pub fn interpret(
|
|||||||
node_idx,
|
node_idx,
|
||||||
"null_unwrap",
|
"null_unwrap",
|
||||||
"tried to unwrap optional of type `{}` which was null",
|
"tried to unwrap optional of type `{}` which was null",
|
||||||
.{optional_info.payload_type.fmt(interpreter.ip)},
|
.{optional_info.payload_type.fmt(interpreter.ip.*)},
|
||||||
);
|
);
|
||||||
return error.InvalidOperation;
|
return error.InvalidOperation;
|
||||||
}
|
}
|
||||||
@ -645,6 +633,8 @@ pub fn interpret(
|
|||||||
.slice,
|
.slice,
|
||||||
.aggregate,
|
.aggregate,
|
||||||
.union_value,
|
.union_value,
|
||||||
|
.null_value,
|
||||||
|
.undefined_value,
|
||||||
.unknown_value,
|
.unknown_value,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
};
|
};
|
||||||
@ -655,14 +645,14 @@ pub fn interpret(
|
|||||||
node_idx,
|
node_idx,
|
||||||
"undeclared_identifier",
|
"undeclared_identifier",
|
||||||
"`{}` has no member '{s}'",
|
"`{}` has no member '{s}'",
|
||||||
.{ accessed_ty.fmt(interpreter.ip), field_name },
|
.{ accessed_ty.fmt(interpreter.ip.*), field_name },
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
try interpreter.recordError(
|
try interpreter.recordError(
|
||||||
node_idx,
|
node_idx,
|
||||||
"invalid_field_access",
|
"invalid_field_access",
|
||||||
"`{}` does not support field access",
|
"`{}` does not support field access",
|
||||||
.{accessed_ty.fmt(interpreter.ip)},
|
.{accessed_ty.fmt(interpreter.ip.*)},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return error.InvalidOperation;
|
return error.InvalidOperation;
|
||||||
@ -702,7 +692,7 @@ pub fn interpret(
|
|||||||
if_info.ast.cond_expr,
|
if_info.ast.cond_expr,
|
||||||
"invalid_if_condition",
|
"invalid_if_condition",
|
||||||
"expected `bool` but found `{}`",
|
"expected `bool` but found `{}`",
|
||||||
.{condition_ty.fmt(interpreter.ip)},
|
.{condition_ty.fmt(interpreter.ip.*)},
|
||||||
);
|
);
|
||||||
return error.InvalidOperation;
|
return error.InvalidOperation;
|
||||||
},
|
},
|
||||||
@ -850,7 +840,7 @@ pub fn interpret(
|
|||||||
const val = interpreter.ip.indexToKey(ir_value.index);
|
const val = interpreter.ip.indexToKey(ir_value.index);
|
||||||
const ty = val.typeOf();
|
const ty = val.typeOf();
|
||||||
|
|
||||||
try writer.print("@as({}, {})", .{ ty.fmt(interpreter.ip), val.fmt(interpreter.ip) });
|
try writer.print("@as({}, {})", .{ ty.fmt(interpreter.ip.*), val.fmt(interpreter.ip.*) });
|
||||||
if (index != params.len - 1)
|
if (index != params.len - 1)
|
||||||
try writer.writeAll(", ");
|
try writer.writeAll(", ");
|
||||||
}
|
}
|
||||||
@ -897,7 +887,7 @@ pub fn interpret(
|
|||||||
defer interpreter.allocator.free(import_uri);
|
defer interpreter.allocator.free(import_uri);
|
||||||
|
|
||||||
var handle = interpreter.document_store.getOrLoadHandle(import_uri) orelse return error.ImportFailure;
|
var handle = interpreter.document_store.getOrLoadHandle(import_uri) orelse return error.ImportFailure;
|
||||||
_ = try interpreter.document_store.ensureInterpreterExists(handle.uri);
|
_ = try interpreter.document_store.ensureInterpreterExists(handle.uri, interpreter.ip);
|
||||||
|
|
||||||
return InterpretResult{
|
return InterpretResult{
|
||||||
.value = Value{
|
.value = Value{
|
||||||
@ -927,7 +917,7 @@ pub fn interpret(
|
|||||||
try writer.writeAll("incompatible types: ");
|
try writer.writeAll("incompatible types: ");
|
||||||
for (types, 0..) |ty, i| {
|
for (types, 0..) |ty, i| {
|
||||||
if (i != 0) try writer.writeAll(", ");
|
if (i != 0) try writer.writeAll(", ");
|
||||||
try writer.print("`{}`", .{ty.fmt(interpreter.ip)});
|
try writer.print("`{}`", .{ty.fmt(interpreter.ip.*)});
|
||||||
}
|
}
|
||||||
|
|
||||||
try interpreter.recordError(node_idx, "invalid_typeof", "{s}", .{output.items});
|
try interpreter.recordError(node_idx, "invalid_typeof", "{s}", .{output.items});
|
||||||
@ -952,7 +942,7 @@ pub fn interpret(
|
|||||||
|
|
||||||
if (ty != .type_type) return error.InvalidBuiltin;
|
if (ty != .type_type) return error.InvalidBuiltin;
|
||||||
|
|
||||||
const value_namespace = interpreter.ip.indexToKey(ty).getNamespace(interpreter.ip);
|
const value_namespace = interpreter.ip.indexToKey(ty).getNamespace(interpreter.ip.*);
|
||||||
if (value_namespace == .none) return error.InvalidBuiltin;
|
if (value_namespace == .none) return error.InvalidBuiltin;
|
||||||
|
|
||||||
const name = interpreter.ip.indexToKey(field_name.index).bytes; // TODO add checks
|
const name = interpreter.ip.indexToKey(field_name.index).bytes; // TODO add checks
|
||||||
@ -1137,7 +1127,7 @@ pub fn interpret(
|
|||||||
node_idx,
|
node_idx,
|
||||||
"invalid_deref",
|
"invalid_deref",
|
||||||
"expected type `bool` but got `{}`",
|
"expected type `bool` but got `{}`",
|
||||||
.{ty.fmt(interpreter.ip)},
|
.{ty.fmt(interpreter.ip.*)},
|
||||||
);
|
);
|
||||||
return error.InvalidOperation;
|
return error.InvalidOperation;
|
||||||
}
|
}
|
||||||
@ -1259,7 +1249,7 @@ pub fn call(
|
|||||||
param.type_expr,
|
param.type_expr,
|
||||||
"expected_type",
|
"expected_type",
|
||||||
"expected type 'type', found '{}'",
|
"expected type 'type', found '{}'",
|
||||||
.{tex_ty.fmt(interpreter.ip)},
|
.{tex_ty.fmt(interpreter.ip.*)},
|
||||||
);
|
);
|
||||||
return error.InvalidCast;
|
return error.InvalidCast;
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@ const translate_c = @import("translate_c.zig");
|
|||||||
const ComptimeInterpreter = @import("ComptimeInterpreter.zig");
|
const ComptimeInterpreter = @import("ComptimeInterpreter.zig");
|
||||||
const AstGen = @import("stage2/AstGen.zig");
|
const AstGen = @import("stage2/AstGen.zig");
|
||||||
const Zir = @import("stage2/Zir.zig");
|
const Zir = @import("stage2/Zir.zig");
|
||||||
|
const InternPool = @import("analyser/InternPool.zig");
|
||||||
|
|
||||||
const DocumentStore = @This();
|
const DocumentStore = @This();
|
||||||
|
|
||||||
@ -73,6 +74,9 @@ pub const Handle = struct {
|
|||||||
/// Contains one entry for every cimport in the document
|
/// Contains one entry for every cimport in the document
|
||||||
cimports: std.MultiArrayList(CImportHandle) = .{},
|
cimports: std.MultiArrayList(CImportHandle) = .{},
|
||||||
|
|
||||||
|
/// error messages from comptime_interpreter or astgen_analyser
|
||||||
|
analysis_errors: std.ArrayListUnmanaged(ErrorMessage) = .{},
|
||||||
|
|
||||||
/// `DocumentStore.build_files` is guaranteed to contain this uri
|
/// `DocumentStore.build_files` is guaranteed to contain this uri
|
||||||
/// uri memory managed by its build_file
|
/// uri memory managed by its build_file
|
||||||
associated_build_file: ?Uri = null,
|
associated_build_file: ?Uri = null,
|
||||||
@ -97,7 +101,18 @@ pub const Handle = struct {
|
|||||||
allocator.free(source);
|
allocator.free(source);
|
||||||
}
|
}
|
||||||
self.cimports.deinit(allocator);
|
self.cimports.deinit(allocator);
|
||||||
|
|
||||||
|
for (self.analysis_errors.items) |err| {
|
||||||
|
allocator.free(err.message);
|
||||||
}
|
}
|
||||||
|
self.analysis_errors.deinit(allocator);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ErrorMessage = struct {
|
||||||
|
loc: offsets.Loc,
|
||||||
|
code: []const u8,
|
||||||
|
message: []const u8,
|
||||||
};
|
};
|
||||||
|
|
||||||
allocator: std.mem.Allocator,
|
allocator: std.mem.Allocator,
|
||||||
@ -209,7 +224,7 @@ pub fn refreshDocument(self: *DocumentStore, uri: Uri, new_text: [:0]const u8) !
|
|||||||
const tracy_zone = tracy.trace(@src());
|
const tracy_zone = tracy.trace(@src());
|
||||||
defer tracy_zone.end();
|
defer tracy_zone.end();
|
||||||
|
|
||||||
const handle = self.handles.get(uri) orelse unreachable;
|
const handle = self.handles.get(uri).?;
|
||||||
|
|
||||||
// TODO: Handle interpreter cross reference
|
// TODO: Handle interpreter cross reference
|
||||||
if (handle.interpreter) |int| {
|
if (handle.interpreter) |int| {
|
||||||
@ -255,6 +270,12 @@ pub fn refreshDocument(self: *DocumentStore, uri: Uri, new_text: [:0]const u8) !
|
|||||||
handle.cimports.deinit(self.allocator);
|
handle.cimports.deinit(self.allocator);
|
||||||
handle.cimports = new_cimports;
|
handle.cimports = new_cimports;
|
||||||
|
|
||||||
|
for (handle.analysis_errors.items) |err| {
|
||||||
|
self.allocator.free(err.message);
|
||||||
|
}
|
||||||
|
handle.analysis_errors.deinit(self.allocator);
|
||||||
|
handle.analysis_errors = .{};
|
||||||
|
|
||||||
if (old_import_count != new_import_count or
|
if (old_import_count != new_import_count or
|
||||||
old_cimport_count != new_cimport_count)
|
old_cimport_count != new_cimport_count)
|
||||||
{
|
{
|
||||||
@ -1125,7 +1146,7 @@ pub fn wantZir(self: DocumentStore) bool {
|
|||||||
return !can_run_ast_check;
|
return !can_run_ast_check;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensureInterpreterExists(self: *DocumentStore, uri: Uri) !*ComptimeInterpreter {
|
pub fn ensureInterpreterExists(self: *DocumentStore, uri: Uri, ip: *InternPool) !*ComptimeInterpreter {
|
||||||
var handle = self.handles.get(uri).?;
|
var handle = self.handles.get(uri).?;
|
||||||
if (handle.interpreter != null) return handle.interpreter.?;
|
if (handle.interpreter != null) return handle.interpreter.?;
|
||||||
|
|
||||||
@ -1133,9 +1154,6 @@ pub fn ensureInterpreterExists(self: *DocumentStore, uri: Uri) !*ComptimeInterpr
|
|||||||
var interpreter = try self.allocator.create(ComptimeInterpreter);
|
var interpreter = try self.allocator.create(ComptimeInterpreter);
|
||||||
errdefer self.allocator.destroy(interpreter);
|
errdefer self.allocator.destroy(interpreter);
|
||||||
|
|
||||||
var ip = try ComptimeInterpreter.InternPool.init(self.allocator);
|
|
||||||
errdefer ip.deinit(self.allocator);
|
|
||||||
|
|
||||||
interpreter.* = ComptimeInterpreter{
|
interpreter.* = ComptimeInterpreter{
|
||||||
.allocator = self.allocator,
|
.allocator = self.allocator,
|
||||||
.ip = ip,
|
.ip = ip,
|
||||||
|
@ -1571,6 +1571,10 @@ pub fn create(
|
|||||||
|
|
||||||
try configuration.configChanged(config, &server.runtime_zig_version, allocator, config_path);
|
try configuration.configChanged(config, &server.runtime_zig_version, allocator, config_path);
|
||||||
|
|
||||||
|
if (config.dangerous_comptime_experiments_do_not_enable) {
|
||||||
|
server.analyser.ip = try analyser.InternPool.init(allocator);
|
||||||
|
}
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +178,14 @@ pub const UnionValue = packed struct {
|
|||||||
val: Index,
|
val: Index,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
pub const NullValue = packed struct {
|
||||||
|
ty: Index,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const UndefinedValue = packed struct {
|
||||||
|
ty: Index,
|
||||||
|
};
|
||||||
|
|
||||||
pub const UnknownValue = packed struct {
|
pub const UnknownValue = packed struct {
|
||||||
ty: Index,
|
ty: Index,
|
||||||
};
|
};
|
||||||
@ -236,6 +244,8 @@ pub const Key = union(enum) {
|
|||||||
slice: Slice,
|
slice: Slice,
|
||||||
aggregate: Aggregate,
|
aggregate: Aggregate,
|
||||||
union_value: UnionValue,
|
union_value: UnionValue,
|
||||||
|
null_value: NullValue,
|
||||||
|
undefined_value: UndefinedValue,
|
||||||
unknown_value: UnknownValue,
|
unknown_value: UnknownValue,
|
||||||
|
|
||||||
// error
|
// error
|
||||||
@ -288,6 +298,8 @@ pub const Key = union(enum) {
|
|||||||
.slice => .slice,
|
.slice => .slice,
|
||||||
.aggregate => .aggregate,
|
.aggregate => .aggregate,
|
||||||
.union_value => .union_value,
|
.union_value => .union_value,
|
||||||
|
.null_value => .null_value,
|
||||||
|
.undefined_value => .undefined_value,
|
||||||
.unknown_value => .unknown_value,
|
.unknown_value => .unknown_value,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -326,6 +338,7 @@ pub const Key = union(enum) {
|
|||||||
.anyerror => .ErrorSet,
|
.anyerror => .ErrorSet,
|
||||||
.noreturn => .NoReturn,
|
.noreturn => .NoReturn,
|
||||||
.anyframe_type => .AnyFrame,
|
.anyframe_type => .AnyFrame,
|
||||||
|
.empty_struct_literal => .Struct,
|
||||||
.null_type => .Null,
|
.null_type => .Null,
|
||||||
.undefined_type => .Undefined,
|
.undefined_type => .Undefined,
|
||||||
.enum_literal_type => .EnumLiteral,
|
.enum_literal_type => .EnumLiteral,
|
||||||
@ -377,6 +390,8 @@ pub const Key = union(enum) {
|
|||||||
.slice,
|
.slice,
|
||||||
.aggregate,
|
.aggregate,
|
||||||
.union_value,
|
.union_value,
|
||||||
|
.null_value,
|
||||||
|
.undefined_value,
|
||||||
.unknown_value,
|
.unknown_value,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
};
|
};
|
||||||
@ -426,6 +441,8 @@ pub const Key = union(enum) {
|
|||||||
.slice => |slice_info| slice_info.ty,
|
.slice => |slice_info| slice_info.ty,
|
||||||
.aggregate => |aggregate_info| aggregate_info.ty,
|
.aggregate => |aggregate_info| aggregate_info.ty,
|
||||||
.union_value => |union_info| union_info.ty,
|
.union_value => |union_info| union_info.ty,
|
||||||
|
.null_value => |null_info| null_info.ty,
|
||||||
|
.undefined_value => |undefined_info| undefined_info.ty,
|
||||||
.unknown_value => |unknown_info| unknown_info.ty,
|
.unknown_value => |unknown_info| unknown_info.ty,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -617,6 +634,7 @@ pub const Key = union(enum) {
|
|||||||
.enum_literal_type,
|
.enum_literal_type,
|
||||||
=> Index.none,
|
=> Index.none,
|
||||||
|
|
||||||
|
.empty_struct_literal => Index.empty_aggregate,
|
||||||
.void => Index.void_value,
|
.void => Index.void_value,
|
||||||
.noreturn => Index.unreachable_value,
|
.noreturn => Index.unreachable_value,
|
||||||
.null_type => Index.null_value,
|
.null_type => Index.null_value,
|
||||||
@ -710,6 +728,8 @@ pub const Key = union(enum) {
|
|||||||
.slice,
|
.slice,
|
||||||
.aggregate,
|
.aggregate,
|
||||||
.union_value,
|
.union_value,
|
||||||
|
.null_value,
|
||||||
|
.undefined_value,
|
||||||
.unknown_value,
|
.unknown_value,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
};
|
};
|
||||||
@ -728,6 +748,7 @@ pub const Key = union(enum) {
|
|||||||
.int_i64_value => |int_value| int_value.int == 0,
|
.int_i64_value => |int_value| int_value.int == 0,
|
||||||
.int_big_value => |int_value| int_value.int.orderAgainstScalar(0).compare(.eq),
|
.int_big_value => |int_value| int_value.int.orderAgainstScalar(0).compare(.eq),
|
||||||
|
|
||||||
|
.null_value => true,
|
||||||
.optional_value => false,
|
.optional_value => false,
|
||||||
.unknown_value => unreachable,
|
.unknown_value => unreachable,
|
||||||
|
|
||||||
@ -735,6 +756,25 @@ pub const Key = union(enum) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If the value fits in a u64, return it, otherwise null.
|
||||||
|
/// Asserts not undefined.
|
||||||
|
pub fn getUnsignedInt(val: Key) !?u64 {
|
||||||
|
return switch (val) {
|
||||||
|
.simple_value => |simple| switch (simple) {
|
||||||
|
.null_value => 0,
|
||||||
|
.bool_true => 1,
|
||||||
|
.bool_false => 0,
|
||||||
|
.the_only_possible_value => 0,
|
||||||
|
else => null,
|
||||||
|
},
|
||||||
|
.int_u64_value => |int_value| int_value.int,
|
||||||
|
.int_i64_value => |int_value| @intCast(u64, int_value.int),
|
||||||
|
.int_big_value => |int_value| int_value.int.to(u64) catch null,
|
||||||
|
.null_value => 0,
|
||||||
|
else => null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
pub const FormatContext = struct {
|
pub const FormatContext = struct {
|
||||||
key: Key,
|
key: Key,
|
||||||
options: FormatOptions = .{},
|
options: FormatOptions = .{},
|
||||||
@ -795,6 +835,7 @@ pub const Key = union(enum) {
|
|||||||
|
|
||||||
.null_type => try writer.writeAll("@TypeOf(null)"),
|
.null_type => try writer.writeAll("@TypeOf(null)"),
|
||||||
.undefined_type => try writer.writeAll("@TypeOf(undefined)"),
|
.undefined_type => try writer.writeAll("@TypeOf(undefined)"),
|
||||||
|
.empty_struct_literal => try writer.writeAll("@TypeOf(.{})"),
|
||||||
.enum_literal_type => try writer.writeAll("@TypeOf(.enum_literal)"),
|
.enum_literal_type => try writer.writeAll("@TypeOf(.enum_literal)"),
|
||||||
|
|
||||||
.atomic_order => try writer.writeAll("std.builtin.AtomicOrder"),
|
.atomic_order => try writer.writeAll("std.builtin.AtomicOrder"),
|
||||||
@ -998,6 +1039,8 @@ pub const Key = union(enum) {
|
|||||||
union_value.val.fmt(ip),
|
union_value.val.fmt(ip),
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
.null_value => try writer.print("null", .{}),
|
||||||
|
.undefined_value => try writer.print("undefined", .{}),
|
||||||
.unknown_value => try writer.print("(unknown value)", .{}),
|
.unknown_value => try writer.print("(unknown value)", .{}),
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -1061,6 +1104,7 @@ pub const Index = enum(u32) {
|
|||||||
comptime_float_type,
|
comptime_float_type,
|
||||||
noreturn_type,
|
noreturn_type,
|
||||||
anyframe_type,
|
anyframe_type,
|
||||||
|
empty_struct_literal,
|
||||||
null_type,
|
null_type,
|
||||||
undefined_type,
|
undefined_type,
|
||||||
enum_literal_type,
|
enum_literal_type,
|
||||||
@ -1263,6 +1307,12 @@ pub const Tag = enum(u8) {
|
|||||||
/// A union value.
|
/// A union value.
|
||||||
/// data is index to UnionValue.
|
/// data is index to UnionValue.
|
||||||
union_value,
|
union_value,
|
||||||
|
/// A null value.
|
||||||
|
/// data is index to type which may be unknown.
|
||||||
|
null_value,
|
||||||
|
/// A undefined value.
|
||||||
|
/// data is index to type which may be unknown.
|
||||||
|
undefined_value,
|
||||||
/// A unknown value.
|
/// A unknown value.
|
||||||
/// data is index to type which may also be unknown.
|
/// data is index to type which may also be unknown.
|
||||||
unknown_value,
|
unknown_value,
|
||||||
@ -1295,6 +1345,7 @@ pub const SimpleType = enum(u32) {
|
|||||||
comptime_float,
|
comptime_float,
|
||||||
noreturn,
|
noreturn,
|
||||||
anyframe_type,
|
anyframe_type,
|
||||||
|
empty_struct_literal,
|
||||||
null_type,
|
null_type,
|
||||||
undefined_type,
|
undefined_type,
|
||||||
enum_literal_type,
|
enum_literal_type,
|
||||||
@ -1373,6 +1424,7 @@ pub fn init(gpa: Allocator) Allocator.Error!InternPool {
|
|||||||
.{ .index = .comptime_float_type, .key = .{ .simple_type = .comptime_float } },
|
.{ .index = .comptime_float_type, .key = .{ .simple_type = .comptime_float } },
|
||||||
.{ .index = .noreturn_type, .key = .{ .simple_type = .noreturn } },
|
.{ .index = .noreturn_type, .key = .{ .simple_type = .noreturn } },
|
||||||
.{ .index = .anyframe_type, .key = .{ .simple_type = .anyframe_type } },
|
.{ .index = .anyframe_type, .key = .{ .simple_type = .anyframe_type } },
|
||||||
|
.{ .index = .empty_struct_literal, .key = .{ .simple_type = .empty_struct_literal } },
|
||||||
.{ .index = .null_type, .key = .{ .simple_type = .null_type } },
|
.{ .index = .null_type, .key = .{ .simple_type = .null_type } },
|
||||||
.{ .index = .undefined_type, .key = .{ .simple_type = .undefined_type } },
|
.{ .index = .undefined_type, .key = .{ .simple_type = .undefined_type } },
|
||||||
.{ .index = .enum_literal_type, .key = .{ .simple_type = .enum_literal_type } },
|
.{ .index = .enum_literal_type, .key = .{ .simple_type = .enum_literal_type } },
|
||||||
@ -1409,7 +1461,7 @@ pub fn init(gpa: Allocator) Allocator.Error!InternPool {
|
|||||||
.{ .index = .bool_true, .key = .{ .simple_value = .bool_true } },
|
.{ .index = .bool_true, .key = .{ .simple_value = .bool_true } },
|
||||||
.{ .index = .bool_false, .key = .{ .simple_value = .bool_false } },
|
.{ .index = .bool_false, .key = .{ .simple_value = .bool_false } },
|
||||||
|
|
||||||
.{ .index = .empty_aggregate, .key = .{ .aggregate = .{ .ty = .none, .values = &.{} } } },
|
.{ .index = .empty_aggregate, .key = .{ .aggregate = .{ .ty = .empty_struct_literal, .values = &.{} } } },
|
||||||
.{ .index = .zero_usize, .key = .{ .int_u64_value = .{ .ty = .usize_type, .int = 0 } } },
|
.{ .index = .zero_usize, .key = .{ .int_u64_value = .{ .ty = .usize_type, .int = 0 } } },
|
||||||
.{ .index = .one_usize, .key = .{ .int_u64_value = .{ .ty = .usize_type, .int = 1 } } },
|
.{ .index = .one_usize, .key = .{ .int_u64_value = .{ .ty = .usize_type, .int = 1 } } },
|
||||||
.{ .index = .the_only_possible_value, .key = .{ .simple_value = .the_only_possible_value } },
|
.{ .index = .the_only_possible_value, .key = .{ .simple_value = .the_only_possible_value } },
|
||||||
@ -1515,6 +1567,8 @@ pub fn indexToKey(ip: InternPool, index: Index) Key {
|
|||||||
.slice => .{ .slice = ip.extraData(Slice, data) },
|
.slice => .{ .slice = ip.extraData(Slice, data) },
|
||||||
.aggregate => .{ .aggregate = ip.extraData(Aggregate, data) },
|
.aggregate => .{ .aggregate = ip.extraData(Aggregate, data) },
|
||||||
.union_value => .{ .union_value = ip.extraData(UnionValue, data) },
|
.union_value => .{ .union_value = ip.extraData(UnionValue, data) },
|
||||||
|
.null_value => .{ .null_value = .{ .ty = @intToEnum(Index, data) } },
|
||||||
|
.undefined_value => .{ .undefined_value = .{ .ty = @intToEnum(Index, data) } },
|
||||||
.unknown_value => .{ .unknown_value = .{ .ty = @intToEnum(Index, data) } },
|
.unknown_value => .{ .unknown_value = .{ .ty = @intToEnum(Index, data) } },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -1545,6 +1599,8 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
|
|||||||
}),
|
}),
|
||||||
.float_16_value => |float_val| @bitCast(u16, float_val),
|
.float_16_value => |float_val| @bitCast(u16, float_val),
|
||||||
.float_32_value => |float_val| @bitCast(u32, float_val),
|
.float_32_value => |float_val| @bitCast(u32, float_val),
|
||||||
|
.null_value => |null_val| @enumToInt(null_val.ty),
|
||||||
|
.undefined_value => |undefined_val| @enumToInt(undefined_val.ty),
|
||||||
.unknown_value => |unknown_val| @enumToInt(unknown_val.ty),
|
.unknown_value => |unknown_val| @enumToInt(unknown_val.ty),
|
||||||
inline else => |data| try ip.addExtra(gpa, data), // TODO sad stage1 noises :(
|
inline else => |data| try ip.addExtra(gpa, data), // TODO sad stage1 noises :(
|
||||||
};
|
};
|
||||||
|
@ -175,6 +175,8 @@ pub fn dotCompletions(
|
|||||||
.slice,
|
.slice,
|
||||||
.aggregate,
|
.aggregate,
|
||||||
.union_value,
|
.union_value,
|
||||||
|
.null_value,
|
||||||
|
.undefined_value,
|
||||||
.unknown_value,
|
.unknown_value,
|
||||||
=> unreachable,
|
=> unreachable,
|
||||||
}
|
}
|
||||||
|
@ -16,6 +16,7 @@ const Analyser = @This();
|
|||||||
gpa: std.mem.Allocator,
|
gpa: std.mem.Allocator,
|
||||||
arena: std.heap.ArenaAllocator,
|
arena: std.heap.ArenaAllocator,
|
||||||
store: *DocumentStore,
|
store: *DocumentStore,
|
||||||
|
ip: ?InternPool,
|
||||||
bound_type_params: std.AutoHashMapUnmanaged(Ast.full.FnProto.Param, TypeWithHandle) = .{},
|
bound_type_params: std.AutoHashMapUnmanaged(Ast.full.FnProto.Param, TypeWithHandle) = .{},
|
||||||
using_trail: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{},
|
using_trail: std.AutoHashMapUnmanaged(Ast.Node.Index, void) = .{},
|
||||||
resolved_nodes: std.HashMapUnmanaged(NodeWithUri, ?TypeWithHandle, NodeWithUri.Context, std.hash_map.default_max_load_percentage) = .{},
|
resolved_nodes: std.HashMapUnmanaged(NodeWithUri, ?TypeWithHandle, NodeWithUri.Context, std.hash_map.default_max_load_percentage) = .{},
|
||||||
@ -25,6 +26,7 @@ pub fn init(gpa: std.mem.Allocator, store: *DocumentStore) Analyser {
|
|||||||
.gpa = gpa,
|
.gpa = gpa,
|
||||||
.arena = std.heap.ArenaAllocator.init(gpa),
|
.arena = std.heap.ArenaAllocator.init(gpa),
|
||||||
.store = store,
|
.store = store,
|
||||||
|
.ip = null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -32,6 +34,7 @@ pub fn deinit(self: *Analyser) void {
|
|||||||
self.bound_type_params.deinit(self.gpa);
|
self.bound_type_params.deinit(self.gpa);
|
||||||
self.using_trail.deinit(self.gpa);
|
self.using_trail.deinit(self.gpa);
|
||||||
self.resolved_nodes.deinit(self.gpa);
|
self.resolved_nodes.deinit(self.gpa);
|
||||||
|
if (self.ip) |*intern_pool| intern_pool.deinit(self.gpa);
|
||||||
self.arena.deinit();
|
self.arena.deinit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -823,7 +826,7 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e
|
|||||||
|
|
||||||
log.info("Invoking interpreter!", .{});
|
log.info("Invoking interpreter!", .{});
|
||||||
|
|
||||||
const interpreter = analyser.store.ensureInterpreterExists(handle.uri) catch |err| {
|
const interpreter = analyser.store.ensureInterpreterExists(handle.uri, &analyser.ip.?) catch |err| {
|
||||||
log.err("Failed to interpret file: {s}", .{@errorName(err)});
|
log.err("Failed to interpret file: {s}", .{@errorName(err)});
|
||||||
if (@errorReturnTrace()) |trace| {
|
if (@errorReturnTrace()) |trace| {
|
||||||
std.debug.dumpStackTrace(trace.*);
|
std.debug.dumpStackTrace(trace.*);
|
||||||
|
@ -82,7 +82,7 @@ fn typeToCompletion(
|
|||||||
.@"comptime" => |co| try analyser.completions.dotCompletions(
|
.@"comptime" => |co| try analyser.completions.dotCompletions(
|
||||||
allocator,
|
allocator,
|
||||||
list,
|
list,
|
||||||
&co.interpreter.ip,
|
co.interpreter.ip,
|
||||||
co.value.index,
|
co.value.index,
|
||||||
type_handle.type.is_type_val,
|
type_handle.type.is_type_val,
|
||||||
co.value.node_idx,
|
co.value.node_idx,
|
||||||
|
@ -164,22 +164,16 @@ pub fn generateDiagnostics(server: *Server, handle: DocumentStore.Handle) error{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handle.interpreter) |int| {
|
try diagnostics.ensureUnusedCapacity(allocator, handle.analysis_errors.items.len);
|
||||||
try diagnostics.ensureUnusedCapacity(allocator, int.errors.count());
|
for (handle.analysis_errors.items) |err| {
|
||||||
|
|
||||||
var err_it = int.errors.iterator();
|
|
||||||
|
|
||||||
while (err_it.next()) |err| {
|
|
||||||
diagnostics.appendAssumeCapacity(.{
|
diagnostics.appendAssumeCapacity(.{
|
||||||
.range = offsets.nodeToRange(tree, err.key_ptr.*, server.offset_encoding),
|
.range = offsets.locToRange(handle.tree.source, err.loc, server.offset_encoding),
|
||||||
.severity = .Error,
|
.severity = .Error,
|
||||||
.code = .{ .string = err.value_ptr.code },
|
.code = .{ .string = err.code },
|
||||||
.source = "zls",
|
.source = "zls",
|
||||||
.message = err.value_ptr.message,
|
.message = err.message,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// try diagnostics.appendSlice(allocator, handle.interpreter.?.diagnostics.items);
|
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.uri = handle.uri,
|
.uri = handle.uri,
|
||||||
|
@ -68,7 +68,7 @@ pub fn hoverSymbol(server: *Server, decl_handle: Analyser.DeclWithHandle, markup
|
|||||||
|
|
||||||
const resolved_type_str = if (resolved_type) |rt|
|
const resolved_type_str = if (resolved_type) |rt|
|
||||||
if (rt.type.is_type_val) switch (rt.type.data) {
|
if (rt.type.is_type_val) switch (rt.type.data) {
|
||||||
.@"comptime" => |co| try std.fmt.allocPrint(server.arena.allocator(), "{}", .{co.value.index.fmt(co.interpreter.ip)}),
|
.@"comptime" => |co| try std.fmt.allocPrint(server.arena.allocator(), "{}", .{co.value.index.fmt(co.interpreter.ip.*)}),
|
||||||
else => "type",
|
else => "type",
|
||||||
} else switch (rt.type.data) { // TODO: Investigate random weird numbers like 897 that cause index of bounds
|
} else switch (rt.type.data) { // TODO: Investigate random weird numbers like 897 that cause index of bounds
|
||||||
.pointer,
|
.pointer,
|
||||||
|
@ -63,11 +63,9 @@ pub const SrcLoc = struct {
|
|||||||
const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);
|
const end = start + @intCast(u32, tree.tokenSlice(tok_index).len);
|
||||||
return Span{ .start = start, .end = end, .main = start };
|
return Span{ .start = start, .end = end, .main = start };
|
||||||
},
|
},
|
||||||
.node_offset => |traced_off| {
|
.node_offset => |node_off| {
|
||||||
const node_off = traced_off.x;
|
|
||||||
const tree = src_loc.handle.tree;
|
const tree = src_loc.handle.tree;
|
||||||
const node = src_loc.declRelativeToNodeIndex(node_off);
|
const node = src_loc.declRelativeToNodeIndex(node_off);
|
||||||
assert(src_loc.handle.tree_loaded);
|
|
||||||
return nodeToSpan(tree, node);
|
return nodeToSpan(tree, node);
|
||||||
},
|
},
|
||||||
.node_offset_main_token => |node_off| {
|
.node_offset_main_token => |node_off| {
|
||||||
@ -79,7 +77,6 @@ pub const SrcLoc = struct {
|
|||||||
.node_offset_bin_op => |node_off| {
|
.node_offset_bin_op => |node_off| {
|
||||||
const tree = src_loc.handle.tree;
|
const tree = src_loc.handle.tree;
|
||||||
const node = src_loc.declRelativeToNodeIndex(node_off);
|
const node = src_loc.declRelativeToNodeIndex(node_off);
|
||||||
assert(src_loc.handle.tree_loaded);
|
|
||||||
return nodeToSpan(tree, node);
|
return nodeToSpan(tree, node);
|
||||||
},
|
},
|
||||||
.node_offset_initializer => |node_off| {
|
.node_offset_initializer => |node_off| {
|
||||||
@ -594,7 +591,7 @@ pub const SrcLoc = struct {
|
|||||||
src_loc: SrcLoc,
|
src_loc: SrcLoc,
|
||||||
node_off: i32,
|
node_off: i32,
|
||||||
arg_index: u32,
|
arg_index: u32,
|
||||||
) !Span {
|
) Span {
|
||||||
const tree = src_loc.handle.tree;
|
const tree = src_loc.handle.tree;
|
||||||
const node_datas = tree.nodes.items(.data);
|
const node_datas = tree.nodes.items(.data);
|
||||||
const node_tags = tree.nodes.items(.tag);
|
const node_tags = tree.nodes.items(.tag);
|
||||||
@ -611,7 +608,7 @@ pub const SrcLoc = struct {
|
|||||||
return nodeToSpan(tree, param);
|
return nodeToSpan(tree, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn nodeToSpan(tree: *const Ast, node: u32) Span {
|
pub fn nodeToSpan(tree: Ast, node: u32) Span {
|
||||||
return tokensToSpan(
|
return tokensToSpan(
|
||||||
tree,
|
tree,
|
||||||
tree.firstToken(node),
|
tree.firstToken(node),
|
||||||
@ -620,7 +617,7 @@ pub const SrcLoc = struct {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tokensToSpan(tree: *const Ast, start: Ast.TokenIndex, end: Ast.TokenIndex, main: Ast.TokenIndex) Span {
|
fn tokensToSpan(tree: Ast, start: Ast.TokenIndex, end: Ast.TokenIndex, main: Ast.TokenIndex) Span {
|
||||||
const token_starts = tree.tokens.items(.start);
|
const token_starts = tree.tokens.items(.start);
|
||||||
var start_tok = start;
|
var start_tok = start;
|
||||||
var end_tok = end;
|
var end_tok = end;
|
||||||
|
@ -2096,6 +2096,7 @@ pub const Inst = struct {
|
|||||||
comptime_float_type,
|
comptime_float_type,
|
||||||
noreturn_type,
|
noreturn_type,
|
||||||
anyframe_type,
|
anyframe_type,
|
||||||
|
empty_struct_literal,
|
||||||
null_type,
|
null_type,
|
||||||
undefined_type,
|
undefined_type,
|
||||||
enum_literal_type,
|
enum_literal_type,
|
||||||
|
@ -134,7 +134,7 @@ test "ComptimeInterpreter - variable lookup" {
|
|||||||
defer context.deinit();
|
defer context.deinit();
|
||||||
|
|
||||||
const result = try context.interpret(context.findVar("bar"));
|
const result = try context.interpret(context.findVar("bar"));
|
||||||
try expectEqualKey(context.interpreter.ip, .{ .int_u64_value = .{ .ty = .comptime_int_type, .int = 3 } }, result.val);
|
try expectEqualKey(context.interpreter.ip.*, .{ .int_u64_value = .{ .ty = .comptime_int_type, .int = 3 } }, result.val);
|
||||||
}
|
}
|
||||||
|
|
||||||
test "ComptimeInterpreter - field access" {
|
test "ComptimeInterpreter - field access" {
|
||||||
@ -294,6 +294,7 @@ const KV = struct {
|
|||||||
const Context = struct {
|
const Context = struct {
|
||||||
config: *zls.Config,
|
config: *zls.Config,
|
||||||
document_store: *zls.DocumentStore,
|
document_store: *zls.DocumentStore,
|
||||||
|
ip: *InternPool,
|
||||||
interpreter: *ComptimeInterpreter,
|
interpreter: *ComptimeInterpreter,
|
||||||
|
|
||||||
pub fn init(source: []const u8) !Context {
|
pub fn init(source: []const u8) !Context {
|
||||||
@ -306,6 +307,12 @@ const Context = struct {
|
|||||||
var interpreter = try allocator.create(ComptimeInterpreter);
|
var interpreter = try allocator.create(ComptimeInterpreter);
|
||||||
errdefer allocator.destroy(interpreter);
|
errdefer allocator.destroy(interpreter);
|
||||||
|
|
||||||
|
var ip = try allocator.create(InternPool);
|
||||||
|
errdefer allocator.destroy(ip);
|
||||||
|
|
||||||
|
ip.* = try InternPool.init(allocator);
|
||||||
|
errdefer ip.deinit(allocator);
|
||||||
|
|
||||||
config.* = .{};
|
config.* = .{};
|
||||||
document_store.* = .{
|
document_store.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
@ -325,7 +332,7 @@ const Context = struct {
|
|||||||
|
|
||||||
interpreter.* = .{
|
interpreter.* = .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.ip = try InternPool.init(allocator),
|
.ip = ip,
|
||||||
.document_store = document_store,
|
.document_store = document_store,
|
||||||
.uri = handle.uri,
|
.uri = handle.uri,
|
||||||
};
|
};
|
||||||
@ -337,6 +344,7 @@ const Context = struct {
|
|||||||
return .{
|
return .{
|
||||||
.config = config,
|
.config = config,
|
||||||
.document_store = document_store,
|
.document_store = document_store,
|
||||||
|
.ip = ip,
|
||||||
.interpreter = interpreter,
|
.interpreter = interpreter,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -344,10 +352,12 @@ const Context = struct {
|
|||||||
pub fn deinit(self: *Context) void {
|
pub fn deinit(self: *Context) void {
|
||||||
self.interpreter.deinit();
|
self.interpreter.deinit();
|
||||||
self.document_store.deinit();
|
self.document_store.deinit();
|
||||||
|
self.ip.deinit(allocator);
|
||||||
|
|
||||||
allocator.destroy(self.config);
|
allocator.destroy(self.config);
|
||||||
allocator.destroy(self.document_store);
|
allocator.destroy(self.document_store);
|
||||||
allocator.destroy(self.interpreter);
|
allocator.destroy(self.interpreter);
|
||||||
|
allocator.destroy(self.ip);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(self: *Context, func_node: Ast.Node.Index, arguments: []const KV) !KV {
|
pub fn call(self: *Context, func_node: Ast.Node.Index, arguments: []const KV) !KV {
|
||||||
@ -428,8 +438,8 @@ fn testCall(
|
|||||||
|
|
||||||
const result = try context.call(context.findFn("Foo"), arguments);
|
const result = try context.call(context.findFn("Foo"), arguments);
|
||||||
|
|
||||||
try expectEqualKey(context.interpreter.ip, Key{ .simple_type = .type }, result.ty);
|
try expectEqualKey(context.interpreter.ip.*, Key{ .simple_type = .type }, result.ty);
|
||||||
try expectEqualKey(context.interpreter.ip, expected_ty, result.val);
|
try expectEqualKey(context.interpreter.ip.*, expected_ty, result.val);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn testExpr(
|
fn testExpr(
|
||||||
@ -446,7 +456,7 @@ fn testExpr(
|
|||||||
|
|
||||||
const result = try context.interpret(context.findVar("foobarbaz"));
|
const result = try context.interpret(context.findVar("foobarbaz"));
|
||||||
|
|
||||||
try expectEqualKey(context.interpreter.ip, expected, result.val);
|
try expectEqualKey(context.interpreter.ip.*, expected, result.val);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn expectEqualKey(ip: InternPool, expected: Key, actual: ?Key) !void {
|
fn expectEqualKey(ip: InternPool, expected: Key, actual: ?Key) !void {
|
||||||
|
Loading…
Reference in New Issue
Block a user