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:
Techatrix 2023-05-09 06:25:26 +02:00 committed by GitHub
parent f6c808a4b3
commit 029f5094ff
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 146 additions and 71 deletions

View File

@ -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;
} }

View File

@ -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,9 +101,20 @@ 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,
config: *const Config, config: *const Config,
runtime_zig_version: *const ?ZigVersionWrapper, runtime_zig_version: *const ?ZigVersionWrapper,
@ -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,

View File

@ -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;
} }

View File

@ -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 :(
}; };

View File

@ -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,
} }

View File

@ -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.*);

View File

@ -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,

View File

@ -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| {
diagnostics.appendAssumeCapacity(.{
var err_it = int.errors.iterator(); .range = offsets.locToRange(handle.tree.source, err.loc, server.offset_encoding),
.severity = .Error,
while (err_it.next()) |err| { .code = .{ .string = err.code },
diagnostics.appendAssumeCapacity(.{ .source = "zls",
.range = offsets.nodeToRange(tree, err.key_ptr.*, server.offset_encoding), .message = err.message,
.severity = .Error, });
.code = .{ .string = err.value_ptr.code },
.source = "zls",
.message = err.value_ptr.message,
});
}
} }
// try diagnostics.appendSlice(allocator, handle.interpreter.?.diagnostics.items);
return .{ return .{
.uri = handle.uri, .uri = handle.uri,

View File

@ -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,

View File

@ -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;

View File

@ -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,

View File

@ -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 {