allocgate defeated

This commit is contained in:
Matt Knight 2021-12-01 21:16:15 -08:00 committed by Auguste Rame
parent 227dcb4650
commit f9133ffdec
14 changed files with 73 additions and 73 deletions

View File

@ -21,7 +21,7 @@ const BuildFile = struct {
builtin_uri: ?[]const u8 = null, builtin_uri: ?[]const u8 = null,
pub fn destroy(self: *BuildFile, allocator: *std.mem.Allocator) void { pub fn destroy(self: *BuildFile, allocator: std.mem.Allocator) void {
if (self.builtin_uri) |builtin_uri| allocator.free(builtin_uri); if (self.builtin_uri) |builtin_uri| allocator.free(builtin_uri);
allocator.destroy(self); allocator.destroy(self);
} }
@ -45,7 +45,7 @@ pub const Handle = struct {
} }
}; };
allocator: *std.mem.Allocator, allocator: std.mem.Allocator,
handles: std.StringHashMap(*Handle), handles: std.StringHashMap(*Handle),
zig_exe_path: ?[]const u8, zig_exe_path: ?[]const u8,
build_files: std.ArrayListUnmanaged(*BuildFile), build_files: std.ArrayListUnmanaged(*BuildFile),
@ -53,7 +53,7 @@ build_runner_path: []const u8,
build_runner_cache_path: []const u8, build_runner_cache_path: []const u8,
std_uri: ?[]const u8, std_uri: ?[]const u8,
pub fn init(self: *DocumentStore, allocator: *std.mem.Allocator, zig_exe_path: ?[]const u8, build_runner_path: []const u8, build_runner_cache_path: []const u8, zig_lib_path: ?[]const u8) !void { pub fn init(self: *DocumentStore, allocator: std.mem.Allocator, zig_exe_path: ?[]const u8, build_runner_path: []const u8, build_runner_cache_path: []const u8, zig_lib_path: ?[]const u8) !void {
self.allocator = allocator; self.allocator = allocator;
self.handles = std.StringHashMap(*Handle).init(allocator); self.handles = std.StringHashMap(*Handle).init(allocator);
self.zig_exe_path = zig_exe_path; self.zig_exe_path = zig_exe_path;
@ -63,7 +63,7 @@ pub fn init(self: *DocumentStore, allocator: *std.mem.Allocator, zig_exe_path: ?
self.std_uri = try stdUriFromLibPath(allocator, zig_lib_path); self.std_uri = try stdUriFromLibPath(allocator, zig_lib_path);
} }
fn loadBuildAssociatedConfiguration(allocator: *std.mem.Allocator, build_file: *BuildFile, build_file_path: []const u8) !void { fn loadBuildAssociatedConfiguration(allocator: std.mem.Allocator, build_file: *BuildFile, build_file_path: []const u8) !void {
const directory_path = build_file_path[0 .. build_file_path.len - "build.zig".len]; const directory_path = build_file_path[0 .. build_file_path.len - "build.zig".len];
const options = std.json.ParseOptions{ .allocator = allocator }; const options = std.json.ParseOptions{ .allocator = allocator };
@ -93,7 +93,7 @@ fn loadBuildAssociatedConfiguration(allocator: *std.mem.Allocator, build_file: *
const LoadPackagesContext = struct { const LoadPackagesContext = struct {
build_file: *BuildFile, build_file: *BuildFile,
allocator: *std.mem.Allocator, allocator: std.mem.Allocator,
build_runner_path: []const u8, build_runner_path: []const u8,
build_runner_cache_path: []const u8, build_runner_cache_path: []const u8,
zig_exe_path: []const u8, zig_exe_path: []const u8,
@ -563,7 +563,7 @@ pub fn applyChanges(self: *DocumentStore, handle: *Handle, content_changes: std.
try self.refreshDocument(handle); try self.refreshDocument(handle);
} }
pub fn uriFromImportStr(self: *DocumentStore, allocator: *std.mem.Allocator, handle: Handle, import_str: []const u8) !?[]const u8 { pub fn uriFromImportStr(self: *DocumentStore, allocator: std.mem.Allocator, handle: Handle, import_str: []const u8) !?[]const u8 {
if (std.mem.eql(u8, import_str, "std")) { if (std.mem.eql(u8, import_str, "std")) {
if (self.std_uri) |uri| return try allocator.dupe(u8, uri) else { if (self.std_uri) |uri| return try allocator.dupe(u8, uri) else {
log.debug("Cannot resolve std library import, path is null.", .{}); log.debug("Cannot resolve std library import, path is null.", .{});
@ -676,7 +676,7 @@ pub fn resolveImport(self: *DocumentStore, handle: *Handle, import_str: []const
} }
} }
fn stdUriFromLibPath(allocator: *std.mem.Allocator, zig_lib_path: ?[]const u8) !?[]const u8 { fn stdUriFromLibPath(allocator: std.mem.Allocator, zig_lib_path: ?[]const u8) !?[]const u8 {
if (zig_lib_path) |zpath| { if (zig_lib_path) |zpath| {
const std_path = std.fs.path.resolve(allocator, &[_][]const u8{ const std_path = std.fs.path.resolve(allocator, &[_][]const u8{
zpath, "./std/std.zig", zpath, "./std/std.zig",
@ -734,7 +734,7 @@ fn tagStoreCompletionItems(self: DocumentStore, arena: *std.heap.ArenaAllocator,
} }
var result_set = analysis.CompletionSet{}; var result_set = analysis.CompletionSet{};
try result_set.ensureTotalCapacity(&arena.allocator, max_len); try result_set.ensureTotalCapacity(arena.allocator(), max_len);
for (@field(base.document_scope, name).entries.items(.key)) |completion| { for (@field(base.document_scope, name).entries.items(.key)) |completion| {
result_set.putAssumeCapacityNoClobber(completion, {}); result_set.putAssumeCapacityNoClobber(completion, {});
} }

View File

@ -8,7 +8,7 @@ const ast = @import("./ast.zig");
var using_trail: std.ArrayList([*]const u8) = undefined; var using_trail: std.ArrayList([*]const u8) = undefined;
var resolve_trail: std.ArrayList(NodeWithHandle) = undefined; var resolve_trail: std.ArrayList(NodeWithHandle) = undefined;
pub fn init(allocator: *std.mem.Allocator) void { pub fn init(allocator: std.mem.Allocator) void {
using_trail = std.ArrayList([*]const u8).init(allocator); using_trail = std.ArrayList([*]const u8).init(allocator);
resolve_trail = std.ArrayList(NodeWithHandle).init(allocator); resolve_trail = std.ArrayList(NodeWithHandle).init(allocator);
} }
@ -18,7 +18,7 @@ pub fn deinit() void {
} }
/// Gets a declaration's doc comments. Caller owns returned memory. /// Gets a declaration's doc comments. Caller owns returned memory.
pub fn getDocComments(allocator: *std.mem.Allocator, tree: Ast, node: Ast.Node.Index, format: types.MarkupContent.Kind) !?[]const u8 { pub fn getDocComments(allocator: std.mem.Allocator, tree: Ast, node: Ast.Node.Index, format: types.MarkupContent.Kind) !?[]const u8 {
const base = tree.nodes.items(.main_token)[node]; const base = tree.nodes.items(.main_token)[node];
const base_kind = tree.nodes.items(.tag)[node]; const base_kind = tree.nodes.items(.tag)[node];
const tokens = tree.tokens.items(.tag); const tokens = tree.tokens.items(.tag);
@ -66,7 +66,7 @@ pub fn getDocCommentTokenIndex(tokens: []std.zig.Token.Tag, base_token: Ast.Toke
} else idx + 1; } else idx + 1;
} }
pub fn collectDocComments(allocator: *std.mem.Allocator, tree: Ast, doc_comments: Ast.TokenIndex, format: types.MarkupContent.Kind, container_doc: bool) ![]const u8 { pub fn collectDocComments(allocator: std.mem.Allocator, tree: Ast, doc_comments: Ast.TokenIndex, format: types.MarkupContent.Kind, container_doc: bool) ![]const u8 {
var lines = std.ArrayList([]const u8).init(allocator); var lines = std.ArrayList([]const u8).init(allocator);
defer lines.deinit(); defer lines.deinit();
const tokens = tree.tokens.items(.tag); const tokens = tree.tokens.items(.tag);
@ -94,7 +94,7 @@ pub fn getFunctionSignature(tree: Ast, func: Ast.full.FnProto) []const u8 {
} }
/// Creates snippet insert text for a function. Caller owns returned memory. /// Creates snippet insert text for a function. Caller owns returned memory.
pub fn getFunctionSnippet(allocator: *std.mem.Allocator, tree: Ast, func: Ast.full.FnProto, skip_self_param: bool) ![]const u8 { pub fn getFunctionSnippet(allocator: std.mem.Allocator, tree: Ast, func: Ast.full.FnProto, skip_self_param: bool) ![]const u8 {
const name_index = func.name_token.?; const name_index = func.name_token.?;
var buffer = std.ArrayList(u8).init(allocator); var buffer = std.ArrayList(u8).init(allocator);
@ -1093,7 +1093,7 @@ pub const TypeWithHandle = struct {
}; };
pub fn resolveTypeOfNode(store: *DocumentStore, arena: *std.heap.ArenaAllocator, node_handle: NodeWithHandle) error{OutOfMemory}!?TypeWithHandle { pub fn resolveTypeOfNode(store: *DocumentStore, arena: *std.heap.ArenaAllocator, node_handle: NodeWithHandle) error{OutOfMemory}!?TypeWithHandle {
var bound_type_params = BoundTypeParams.init(&arena.allocator); var bound_type_params = BoundTypeParams.init(arena.allocator());
return resolveTypeOfNodeInternal(store, arena, node_handle, &bound_type_params); return resolveTypeOfNodeInternal(store, arena, node_handle, &bound_type_params);
} }
@ -1139,7 +1139,7 @@ pub fn getFieldAccessType(store: *DocumentStore, arena: *std.heap.ArenaAllocator
.handle = handle, .handle = handle,
}); });
var bound_type_params = BoundTypeParams.init(&arena.allocator); var bound_type_params = BoundTypeParams.init(arena.allocator());
while (true) { while (true) {
const tok = tokenizer.next(); const tok = tokenizer.next();
@ -1450,7 +1450,7 @@ pub fn documentPositionContext(arena: *std.heap.ArenaAllocator, document: types.
const line = doc_position.line; const line = doc_position.line;
const line_mem_start = @ptrToInt(line.ptr) - @ptrToInt(document.mem.ptr); const line_mem_start = @ptrToInt(line.ptr) - @ptrToInt(document.mem.ptr);
var stack = try std.ArrayList(StackState).initCapacity(&arena.allocator, 8); var stack = try std.ArrayList(StackState).initCapacity(arena.allocator(), 8);
{ {
var held_line = document.borrowNullTerminatedSlice( var held_line = document.borrowNullTerminatedSlice(
line_mem_start, line_mem_start,
@ -1579,7 +1579,7 @@ pub fn documentPositionContext(arena: *std.heap.ArenaAllocator, document: types.
}; };
} }
fn addOutlineNodes(allocator: *std.mem.Allocator, tree: Ast, child: Ast.Node.Index, context: *GetDocumentSymbolsContext) anyerror!void { fn addOutlineNodes(allocator: std.mem.Allocator, tree: Ast, child: Ast.Node.Index, context: *GetDocumentSymbolsContext) anyerror!void {
switch (tree.nodes.items(.tag)[child]) { switch (tree.nodes.items(.tag)[child]) {
.string_literal, .string_literal,
.integer_literal, .integer_literal,
@ -1730,7 +1730,7 @@ const GetDocumentSymbolsContext = struct {
encoding: offsets.Encoding, encoding: offsets.Encoding,
}; };
fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: Ast, node: Ast.Node.Index, context: *GetDocumentSymbolsContext) anyerror!void { fn getDocumentSymbolsInternal(allocator: std.mem.Allocator, tree: Ast, node: Ast.Node.Index, context: *GetDocumentSymbolsContext) anyerror!void {
const name = getDeclName(tree, node) orelse return; const name = getDeclName(tree, node) orelse return;
if (name.len == 0) if (name.len == 0)
return; return;
@ -1814,7 +1814,7 @@ fn getDocumentSymbolsInternal(allocator: *std.mem.Allocator, tree: Ast, node: As
}; };
} }
pub fn getDocumentSymbols(allocator: *std.mem.Allocator, tree: Ast, encoding: offsets.Encoding) ![]types.DocumentSymbol { pub fn getDocumentSymbols(allocator: std.mem.Allocator, tree: Ast, encoding: offsets.Encoding) ![]types.DocumentSymbol {
var symbols = try std.ArrayList(types.DocumentSymbol).initCapacity(allocator, tree.rootDecls().len); var symbols = try std.ArrayList(types.DocumentSymbol).initCapacity(allocator, tree.rootDecls().len);
var context = GetDocumentSymbolsContext{ var context = GetDocumentSymbolsContext{
@ -2057,7 +2057,7 @@ fn iterateSymbolsContainerInternal(store: *DocumentStore, arena: *std.heap.Arena
} }
pub fn iterateSymbolsContainer(store: *DocumentStore, arena: *std.heap.ArenaAllocator, container_handle: NodeWithHandle, orig_handle: *DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool) error{OutOfMemory}!void { pub fn iterateSymbolsContainer(store: *DocumentStore, arena: *std.heap.ArenaAllocator, container_handle: NodeWithHandle, orig_handle: *DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool) error{OutOfMemory}!void {
var use_trail = std.ArrayList(*const Ast.Node.Index).init(&arena.allocator); var use_trail = std.ArrayList(*const Ast.Node.Index).init(arena.allocator());
return try iterateSymbolsContainerInternal(store, arena, container_handle, orig_handle, callback, context, instance_access, &use_trail); return try iterateSymbolsContainerInternal(store, arena, container_handle, orig_handle, callback, context, instance_access, &use_trail);
} }
@ -2119,7 +2119,7 @@ fn iterateSymbolsGlobalInternal(store: *DocumentStore, arena: *std.heap.ArenaAll
} }
pub fn iterateSymbolsGlobal(store: *DocumentStore, arena: *std.heap.ArenaAllocator, handle: *DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype) error{OutOfMemory}!void { pub fn iterateSymbolsGlobal(store: *DocumentStore, arena: *std.heap.ArenaAllocator, handle: *DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype) error{OutOfMemory}!void {
var use_trail = std.ArrayList(*const Ast.Node.Index).init(&arena.allocator); var use_trail = std.ArrayList(*const Ast.Node.Index).init(arena.allocator());
return try iterateSymbolsGlobalInternal(store, arena, handle, source_index, callback, context, &use_trail); return try iterateSymbolsGlobalInternal(store, arena, handle, source_index, callback, context, &use_trail);
} }
@ -2330,7 +2330,7 @@ pub const DocumentScope = struct {
} }
} }
pub fn deinit(self: *DocumentScope, allocator: *std.mem.Allocator) void { pub fn deinit(self: *DocumentScope, allocator: std.mem.Allocator) void {
for (self.scopes) |*scope| { for (self.scopes) |*scope| {
scope.decls.deinit(); scope.decls.deinit();
allocator.free(scope.uses); allocator.free(scope.uses);
@ -2371,7 +2371,7 @@ pub const Scope = struct {
} }
}; };
pub fn makeDocumentScope(allocator: *std.mem.Allocator, tree: Ast) !DocumentScope { pub fn makeDocumentScope(allocator: std.mem.Allocator, tree: Ast) !DocumentScope {
var scopes = std.ArrayListUnmanaged(Scope){}; var scopes = std.ArrayListUnmanaged(Scope){};
var error_completions = CompletionSet{}; var error_completions = CompletionSet{};
var enum_completions = CompletionSet{}; var enum_completions = CompletionSet{};
@ -2419,7 +2419,7 @@ const ScopeContext = struct {
tree: Ast, tree: Ast,
}; };
fn makeInnerScope(allocator: *std.mem.Allocator, context: ScopeContext, node_idx: Ast.Node.Index) error{OutOfMemory}!void { fn makeInnerScope(allocator: std.mem.Allocator, context: ScopeContext, node_idx: Ast.Node.Index) error{OutOfMemory}!void {
const scopes = context.scopes; const scopes = context.scopes;
const tree = context.tree; const tree = context.tree;
const tags = tree.nodes.items(.tag); const tags = tree.nodes.items(.tag);
@ -2535,7 +2535,7 @@ fn makeInnerScope(allocator: *std.mem.Allocator, context: ScopeContext, node_idx
// Whether we have already visited the root node. // Whether we have already visited the root node.
var had_root = true; var had_root = true;
fn makeScopeInternal(allocator: *std.mem.Allocator, context: ScopeContext, node_idx: Ast.Node.Index) error{OutOfMemory}!void { fn makeScopeInternal(allocator: std.mem.Allocator, context: ScopeContext, node_idx: Ast.Node.Index) error{OutOfMemory}!void {
const scopes = context.scopes; const scopes = context.scopes;
const tree = context.tree; const tree = context.tree;
const tags = tree.nodes.items(.tag); const tags = tree.nodes.items(.tag);

View File

@ -6,12 +6,12 @@ const RequestHeader = struct {
/// null implies "application/vscode-jsonrpc; charset=utf-8" /// null implies "application/vscode-jsonrpc; charset=utf-8"
content_type: ?[]const u8, content_type: ?[]const u8,
pub fn deinit(self: @This(), allocator: *std.mem.Allocator) void { pub fn deinit(self: @This(), allocator: std.mem.Allocator) void {
if (self.content_type) |ct| allocator.free(ct); if (self.content_type) |ct| allocator.free(ct);
} }
}; };
pub fn readRequestHeader(allocator: *std.mem.Allocator, instream: anytype) !RequestHeader { pub fn readRequestHeader(allocator: std.mem.Allocator, instream: anytype) !RequestHeader {
var r = RequestHeader{ var r = RequestHeader{
.content_length = undefined, .content_length = undefined,
.content_type = null, .content_type = null,

@ -1 +1 @@
Subproject commit a282c26da51e5d2c01fec5c744e321ae248cf409 Subproject commit 8c6e3b14c85e2354545c4048cd1fa5ed08a36077

View File

@ -49,7 +49,7 @@ pub fn log(comptime message_level: std.log.Level, comptime scope: @Type(.EnumLit
var arena = std.heap.ArenaAllocator.init(allocator); var arena = std.heap.ArenaAllocator.init(allocator);
defer arena.deinit(); defer arena.deinit();
var message = std.fmt.allocPrint(&arena.allocator, "[{s}-{s}] " ++ format, .{ @tagName(message_level), @tagName(scope) } ++ args) catch { var message = std.fmt.allocPrint(arena.allocator(), "[{s}-{s}] " ++ format, .{ @tagName(message_level), @tagName(scope) } ++ args) catch {
std.debug.print("Failed to allocPrint message.\n", .{}); std.debug.print("Failed to allocPrint message.\n", .{});
return; return;
}; };
@ -75,7 +75,7 @@ pub fn log(comptime message_level: std.log.Level, comptime scope: @Type(.EnumLit
// Code is largely based off of https://github.com/andersfr/zig-lsp/blob/master/server.zig // Code is largely based off of https://github.com/andersfr/zig-lsp/blob/master/server.zig
var stdout: std.io.BufferedWriter(4096, std.fs.File.Writer) = undefined; var stdout: std.io.BufferedWriter(4096, std.fs.File.Writer) = undefined;
var allocator: *std.mem.Allocator = undefined; var allocator: std.mem.Allocator = undefined;
var document_store: DocumentStore = undefined; var document_store: DocumentStore = undefined;
@ -117,7 +117,7 @@ const no_semantic_tokens_response =
/// Sends a request or response /// Sends a request or response
fn send(arena: *std.heap.ArenaAllocator, reqOrRes: anytype) !void { fn send(arena: *std.heap.ArenaAllocator, reqOrRes: anytype) !void {
var arr = std.ArrayList(u8).init(&arena.allocator); var arr = std.ArrayList(u8).init(arena.allocator());
try std.json.stringify(reqOrRes, .{}, arr.writer()); try std.json.stringify(reqOrRes, .{}, arr.writer());
const stdout_stream = stdout.writer(); const stdout_stream = stdout.writer();
@ -195,7 +195,7 @@ fn astLocationToRange(loc: Ast.Location) types.Range {
fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Handle, config: Config) !void { fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Handle, config: Config) !void {
const tree = handle.tree; const tree = handle.tree;
var diagnostics = std.ArrayList(types.Diagnostic).init(&arena.allocator); var diagnostics = std.ArrayList(types.Diagnostic).init(arena.allocator());
for (tree.errors) |err| { for (tree.errors) |err| {
const loc = tree.tokenLocation(0, err.token); const loc = tree.tokenLocation(0, err.token);
@ -209,7 +209,7 @@ fn publishDiagnostics(arena: *std.heap.ArenaAllocator, handle: DocumentStore.Han
.severity = .Error, .severity = .Error,
.code = @tagName(err.tag), .code = @tagName(err.tag),
.source = "zls", .source = "zls",
.message = try arena.allocator.dupe(u8, fbs.getWritten()), .message = try arena.allocator().dupe(u8, fbs.getWritten()),
// .relatedInformation = undefined // .relatedInformation = undefined
}); });
} }
@ -386,7 +386,7 @@ fn nodeToCompletion(arena: *std.heap.ArenaAllocator, list: *std.ArrayList(types.
const insert_text = if (use_snippets) blk: { const insert_text = if (use_snippets) blk: {
const skip_self_param = !(parent_is_type_val orelse true) and const skip_self_param = !(parent_is_type_val orelse true) and
try analysis.hasSelfParam(arena, &document_store, handle, func); try analysis.hasSelfParam(arena, &document_store, handle, func);
break :blk try analysis.getFunctionSnippet(&arena.allocator, tree, func, skip_self_param); break :blk try analysis.getFunctionSnippet(arena.allocator(), tree, func, skip_self_param);
} else tree.tokenSlice(func.name_token.?); } else tree.tokenSlice(func.name_token.?);
const is_type_function = analysis.isTypeFunction(handle.tree, func); const is_type_function = analysis.isTypeFunction(handle.tree, func);
@ -596,7 +596,7 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle
if (try analysis.resolveVarDeclAlias(&document_store, arena, .{ .node = node, .handle = handle })) |result| { if (try analysis.resolveVarDeclAlias(&document_store, arena, .{ .node = node, .handle = handle })) |result| {
return try hoverSymbol(id, arena, result); return try hoverSymbol(id, arena, result);
} }
doc_str = try analysis.getDocComments(&arena.allocator, tree, node, hover_kind); doc_str = try analysis.getDocComments(arena.allocator(), tree, node, hover_kind);
var buf: [1]Ast.Node.Index = undefined; var buf: [1]Ast.Node.Index = undefined;
@ -613,7 +613,7 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle
}, },
.param_decl => |param| def: { .param_decl => |param| def: {
if (param.first_doc_comment) |doc_comments| { if (param.first_doc_comment) |doc_comments| {
doc_str = try analysis.collectDocComments(&arena.allocator, handle.tree, doc_comments, hover_kind, false); doc_str = try analysis.collectDocComments(arena.allocator(), handle.tree, doc_comments, hover_kind, false);
} }
const first_token = param.first_doc_comment orelse const first_token = param.first_doc_comment orelse
@ -637,13 +637,13 @@ fn hoverSymbol(id: types.RequestId, arena: *std.heap.ArenaAllocator, decl_handle
if (hover_kind == .Markdown) { if (hover_kind == .Markdown) {
hover_text = hover_text =
if (doc_str) |doc| if (doc_str) |doc|
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```\n{s}", .{ def_str, doc }) try std.fmt.allocPrint(arena.allocator(), "```zig\n{s}\n```\n{s}", .{ def_str, doc })
else else
try std.fmt.allocPrint(&arena.allocator, "```zig\n{s}\n```", .{def_str}); try std.fmt.allocPrint(arena.allocator(), "```zig\n{s}\n```", .{def_str});
} else { } else {
hover_text = hover_text =
if (doc_str) |doc| if (doc_str) |doc|
try std.fmt.allocPrint(&arena.allocator, "{s}\n{s}", .{ def_str, doc }) try std.fmt.allocPrint(arena.allocator(), "{s}\n{s}", .{ def_str, doc })
else else
def_str; def_str;
} }
@ -705,7 +705,7 @@ fn hoverDefinitionBuiltin(arena: *std.heap.ArenaAllocator, id: types.RequestId,
.Hover = .{ .Hover = .{
.contents = .{ .contents = .{
.value = try std.fmt.allocPrint( .value = try std.fmt.allocPrint(
&arena.allocator, arena.allocator(),
"```zig\n{s}\n```\n{s}", "```zig\n{s}\n```\n{s}",
.{ builtin.signature, builtin.documentation }, .{ builtin.signature, builtin.documentation },
), ),
@ -770,7 +770,7 @@ fn gotoDefinitionString(arena: *std.heap.ArenaAllocator, id: types.RequestId, po
const import_str = analysis.getImportStr(tree, 0, pos_index) orelse return try respondGeneric(id, null_result_response); const import_str = analysis.getImportStr(tree, 0, pos_index) orelse return try respondGeneric(id, null_result_response);
const uri = (try document_store.uriFromImportStr( const uri = (try document_store.uriFromImportStr(
&arena.allocator, arena.allocator(),
handle.*, handle.*,
import_str, import_str,
)) orelse return try respondGeneric(id, null_result_response); )) orelse return try respondGeneric(id, null_result_response);
@ -793,7 +793,7 @@ fn renameDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId,
const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
var workspace_edit = types.WorkspaceEdit{ var workspace_edit = types.WorkspaceEdit{
.changes = std.StringHashMap([]types.TextEdit).init(&arena.allocator), .changes = std.StringHashMap([]types.TextEdit).init(arena.allocator()),
}; };
try rename.renameSymbol(arena, &document_store, decl, new_name, &workspace_edit.changes.?, offset_encoding); try rename.renameSymbol(arena, &document_store, decl, new_name, &workspace_edit.changes.?, offset_encoding);
try send(arena, types.Response{ try send(arena, types.Response{
@ -806,7 +806,7 @@ fn renameDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.Reques
const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response);
var workspace_edit = types.WorkspaceEdit{ var workspace_edit = types.WorkspaceEdit{
.changes = std.StringHashMap([]types.TextEdit).init(&arena.allocator), .changes = std.StringHashMap([]types.TextEdit).init(arena.allocator()),
}; };
try rename.renameSymbol(arena, &document_store, decl, new_name, &workspace_edit.changes.?, offset_encoding); try rename.renameSymbol(arena, &document_store, decl, new_name, &workspace_edit.changes.?, offset_encoding);
try send(arena, types.Response{ try send(arena, types.Response{
@ -819,7 +819,7 @@ fn renameDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, h
const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
var workspace_edit = types.WorkspaceEdit{ var workspace_edit = types.WorkspaceEdit{
.changes = std.StringHashMap([]types.TextEdit).init(&arena.allocator), .changes = std.StringHashMap([]types.TextEdit).init(arena.allocator()),
}; };
try rename.renameLabel(arena, decl, new_name, &workspace_edit.changes.?, offset_encoding); try rename.renameLabel(arena, decl, new_name, &workspace_edit.changes.?, offset_encoding);
try send(arena, types.Response{ try send(arena, types.Response{
@ -830,7 +830,7 @@ fn renameDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, h
fn referencesDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, include_decl: bool, skip_std_references: bool) !void { fn referencesDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, include_decl: bool, skip_std_references: bool) !void {
const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolGlobal(arena, pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
var locs = std.ArrayList(types.Location).init(&arena.allocator); var locs = std.ArrayList(types.Location).init(arena.allocator());
try references.symbolReferences( try references.symbolReferences(
arena, arena,
&document_store, &document_store,
@ -849,7 +849,7 @@ fn referencesDefinitionGlobal(arena: *std.heap.ArenaAllocator, id: types.Request
fn referencesDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, include_decl: bool, config: Config) !void { fn referencesDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, include_decl: bool, config: Config) !void {
const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response); const decl = (try getSymbolFieldAccess(handle, arena, position, range, config)) orelse return try respondGeneric(id, null_result_response);
var locs = std.ArrayList(types.Location).init(&arena.allocator); var locs = std.ArrayList(types.Location).init(arena.allocator());
try references.symbolReferences(arena, &document_store, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append, config.skip_std_references); try references.symbolReferences(arena, &document_store, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append, config.skip_std_references);
try send(arena, types.Response{ try send(arena, types.Response{
.id = id, .id = id,
@ -859,7 +859,7 @@ fn referencesDefinitionFieldAccess(arena: *std.heap.ArenaAllocator, id: types.Re
fn referencesDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, include_decl: bool) !void { fn referencesDefinitionLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, pos_index: usize, include_decl: bool) !void {
const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response); const decl = (try getLabelGlobal(pos_index, handle)) orelse return try respondGeneric(id, null_result_response);
var locs = std.ArrayList(types.Location).init(&arena.allocator); var locs = std.ArrayList(types.Location).init(arena.allocator());
try references.labelReferences(arena, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append); try references.labelReferences(arena, decl, offset_encoding, include_decl, &locs, std.ArrayList(types.Location).append);
try send(arena, types.Response{ try send(arena, types.Response{
.id = id, .id = id,
@ -902,7 +902,7 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.Decl
const doc = if (param.first_doc_comment) |doc_comments| const doc = if (param.first_doc_comment) |doc_comments|
types.MarkupContent{ types.MarkupContent{
.kind = doc_kind, .kind = doc_kind,
.value = try analysis.collectDocComments(&context.arena.allocator, tree, doc_comments, doc_kind, false), .value = try analysis.collectDocComments(context.arena.allocator(), tree, doc_comments, doc_kind, false),
} }
else else
null; null;
@ -966,7 +966,7 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.Decl
} }
fn completeLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void { fn completeLabel(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void {
var completions = std.ArrayList(types.CompletionItem).init(&arena.allocator); var completions = std.ArrayList(types.CompletionItem).init(arena.allocator());
const context = DeclToCompletionContext{ const context = DeclToCompletionContext{
.completions = &completions, .completions = &completions,
@ -1032,7 +1032,7 @@ fn completeBuiltin(arena: *std.heap.ArenaAllocator, id: types.RequestId, config:
} }
fn completeGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void { fn completeGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_index: usize, handle: *DocumentStore.Handle, config: Config) !void {
var completions = std.ArrayList(types.CompletionItem).init(&arena.allocator); var completions = std.ArrayList(types.CompletionItem).init(arena.allocator());
const context = DeclToCompletionContext{ const context = DeclToCompletionContext{
.completions = &completions, .completions = &completions,
@ -1055,7 +1055,7 @@ fn completeGlobal(arena: *std.heap.ArenaAllocator, id: types.RequestId, pos_inde
} }
fn completeFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, config: Config) !void { fn completeFieldAccess(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle, position: offsets.DocumentPosition, range: analysis.SourceRange, config: Config) !void {
var completions = std.ArrayList(types.CompletionItem).init(&arena.allocator); var completions = std.ArrayList(types.CompletionItem).init(arena.allocator());
const line_mem_start = @ptrToInt(position.line.ptr) - @ptrToInt(handle.document.mem.ptr); const line_mem_start = @ptrToInt(position.line.ptr) - @ptrToInt(handle.document.mem.ptr);
var held_range = handle.document.borrowNullTerminatedSlice(line_mem_start + range.start, line_mem_start + range.end); var held_range = handle.document.borrowNullTerminatedSlice(line_mem_start + range.start, line_mem_start + range.end);
@ -1113,7 +1113,7 @@ fn completeDot(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *Do
fn documentSymbol(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle) !void { fn documentSymbol(arena: *std.heap.ArenaAllocator, id: types.RequestId, handle: *DocumentStore.Handle) !void {
try send(arena, types.Response{ try send(arena, types.Response{
.id = id, .id = id,
.result = .{ .DocumentSymbols = try analysis.getDocumentSymbols(&arena.allocator, handle.tree, offset_encoding) }, .result = .{ .DocumentSymbols = try analysis.getDocumentSymbols(arena.allocator(), handle.tree, offset_encoding) },
}); });
} }
@ -1827,11 +1827,11 @@ pub fn main() anyerror!void {
defer arena.deinit(); defer arena.deinit();
while (keep_running) { while (keep_running) {
const headers = readRequestHeader(&arena.allocator, reader) catch |err| { const headers = readRequestHeader(arena.allocator(), reader) catch |err| {
logger.err("{s}; exiting!", .{@errorName(err)}); logger.err("{s}; exiting!", .{@errorName(err)});
return; return;
}; };
const buf = try arena.allocator.alloc(u8, headers.content_length); const buf = try arena.allocator().alloc(u8, headers.content_length);
try reader.readNoEof(buf); try reader.readNoEof(buf);
try processJsonRpc(&arena, &json_parser, buf, config); try processJsonRpc(&arena, &json_parser, buf, config);

View File

@ -416,7 +416,7 @@ fn symbolReferencesInternal(arena: *std.heap.ArenaAllocator, store: *DocumentSto
try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler); try symbolReferencesInternal(arena, store, .{ .node = datas[node].lhs, .handle = handle }, decl, encoding, context, handler);
const rhs_str = tree.tokenSlice(datas[node].rhs); const rhs_str = tree.tokenSlice(datas[node].rhs);
var bound_type_params = analysis.BoundTypeParams.init(&arena.allocator); var bound_type_params = analysis.BoundTypeParams.init(arena.allocator());
const left_type = try analysis.resolveFieldAccessLhsType( const left_type = try analysis.resolveFieldAccessLhsType(
store, store,
arena, arena,
@ -503,7 +503,7 @@ pub fn symbolReferences(arena: *std.heap.ArenaAllocator, store: *DocumentStore,
.ast_node => { .ast_node => {
try symbolReferencesInternal(arena, store, .{ .node = 0, .handle = curr_handle }, decl_handle, encoding, context, handler); try symbolReferencesInternal(arena, store, .{ .node = 0, .handle = curr_handle }, decl_handle, encoding, context, handler);
var imports = std.ArrayList(*DocumentStore.Handle).init(&arena.allocator); var imports = std.ArrayList(*DocumentStore.Handle).init(arena.allocator());
var handle_it = store.handles.iterator(); var handle_it = store.handles.iterator();
while (handle_it.next()) |entry| { while (handle_it.next()) |entry| {

View File

@ -8,7 +8,7 @@ const offsets = @import("./offsets.zig");
// TODO Use a map to array lists and collect at the end instead? // TODO Use a map to array lists and collect at the end instead?
const RefHandlerContext = struct { const RefHandlerContext = struct {
edits: *std.StringHashMap([]types.TextEdit), edits: *std.StringHashMap([]types.TextEdit),
allocator: *std.mem.Allocator, allocator: std.mem.Allocator,
new_name: []const u8, new_name: []const u8,
}; };
@ -29,7 +29,7 @@ pub fn renameSymbol(arena: *std.heap.ArenaAllocator, store: *DocumentStore, decl
std.debug.assert(decl_handle.decl.* != .label_decl); std.debug.assert(decl_handle.decl.* != .label_decl);
try references.symbolReferences(arena, store, decl_handle, encoding, true, RefHandlerContext{ try references.symbolReferences(arena, store, decl_handle, encoding, true, RefHandlerContext{
.edits = edits, .edits = edits,
.allocator = &arena.allocator, .allocator = arena.allocator(),
.new_name = new_name, .new_name = new_name,
}, refHandler, true); }, refHandler, true);
} }
@ -38,7 +38,7 @@ pub fn renameLabel(arena: *std.heap.ArenaAllocator, decl_handle: analysis.DeclWi
std.debug.assert(decl_handle.decl.* == .label_decl); std.debug.assert(decl_handle.decl.* == .label_decl);
try references.labelReferences(arena, decl_handle, encoding, true, RefHandlerContext{ try references.labelReferences(arena, decl_handle, encoding, true, RefHandlerContext{
.edits = edits, .edits = edits,
.allocator = &arena.allocator, .allocator = arena.allocator(),
.new_name = new_name, .new_name = new_name,
}, refHandler); }, refHandler);
} }

View File

@ -97,7 +97,7 @@ fn fromDynamicTreeInternal(arena: *std.heap.ArenaAllocator, value: std.json.Valu
if (value.Array.items.len == 0) { if (value.Array.items.len == 0) {
out.* = &[0]Child{}; out.* = &[0]Child{};
} else { } else {
var slice = try arena.allocator.alloc(Child, value.Array.items.len); var slice = try arena.allocator().alloc(Child, value.Array.items.len);
for (value.Array.items) |arr_item, idx| { for (value.Array.items) |arr_item, idx| {
try fromDynamicTreeInternal(arena, arr_item, &slice[idx]); try fromDynamicTreeInternal(arena, arr_item, &slice[idx]);
} }

View File

@ -57,7 +57,7 @@ const Builder = struct {
arr: std.ArrayList(u32), arr: std.ArrayList(u32),
encoding: offsets.Encoding, encoding: offsets.Encoding,
fn init(allocator: *std.mem.Allocator, handle: *DocumentStore.Handle, encoding: offsets.Encoding) Builder { fn init(allocator: std.mem.Allocator, handle: *DocumentStore.Handle, encoding: offsets.Encoding) Builder {
return Builder{ return Builder{
.handle = handle, .handle = handle,
.arr = std.ArrayList(u32).init(allocator), .arr = std.ArrayList(u32).init(allocator),
@ -415,7 +415,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D
if (child.decl.* == .param_decl) { if (child.decl.* == .param_decl) {
return try writeToken(builder, main_token, .parameter); return try writeToken(builder, main_token, .parameter);
} }
var bound_type_params = analysis.BoundTypeParams.init(&arena.allocator); var bound_type_params = analysis.BoundTypeParams.init(arena.allocator());
if (try child.resolveType(store, arena, &bound_type_params)) |decl_type| { if (try child.resolveType(store, arena, &bound_type_params)) |decl_type| {
try colorIdentifierBasedOnType(builder, decl_type, main_token, .{}); try colorIdentifierBasedOnType(builder, decl_type, main_token, .{});
} else { } else {
@ -867,7 +867,7 @@ fn writeNodeTokens(builder: *Builder, arena: *std.heap.ArenaAllocator, store: *D
// TODO This is basically exactly the same as what is done in analysis.resolveTypeOfNode, with the added // TODO This is basically exactly the same as what is done in analysis.resolveTypeOfNode, with the added
// writeToken code. // writeToken code.
// Maybe we can hook into it insead? Also applies to Identifier and VarDecl // Maybe we can hook into it insead? Also applies to Identifier and VarDecl
var bound_type_params = analysis.BoundTypeParams.init(&arena.allocator); var bound_type_params = analysis.BoundTypeParams.init(arena.allocator());
const lhs_type = try analysis.resolveFieldAccessLhsType( const lhs_type = try analysis.resolveFieldAccessLhsType(
store, store,
arena, arena,

View File

@ -13,7 +13,7 @@ fn write(text: []const u8) void {
stdout.writeAll(text) catch @panic("Could not write to stdout"); stdout.writeAll(text) catch @panic("Could not write to stdout");
} }
pub fn wizard(allocator: *std.mem.Allocator) !void { pub fn wizard(allocator: std.mem.Allocator) !void {
@setEvalBranchQuota(2500); @setEvalBranchQuota(2500);
write( write(
\\Welcome to the ZLS configuration wizard! \\Welcome to the ZLS configuration wizard!
@ -227,7 +227,7 @@ pub fn wizard(allocator: *std.mem.Allocator) !void {
write("\n\nThank you for choosing ZLS!\n"); write("\n\nThank you for choosing ZLS!\n");
} }
pub fn findZig(allocator: *std.mem.Allocator) !?[]const u8 { pub fn findZig(allocator: std.mem.Allocator) !?[]const u8 {
const env_path = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) { const env_path = std.process.getEnvVarOwned(allocator, "PATH") catch |err| switch (err) {
error.EnvironmentVariableNotFound => { error.EnvironmentVariableNotFound => {
return null; return null;

View File

@ -13,7 +13,7 @@ fn fnProtoToSignatureInfo(document_store: *DocumentStore, arena: *std.heap.Arena
const tree = handle.tree; const tree = handle.tree;
const token_starts = tree.tokens.items(.start); const token_starts = tree.tokens.items(.start);
const alloc = &arena.allocator; const alloc = arena.allocator();
const label = analysis.getFunctionSignature(tree, proto); const label = analysis.getFunctionSignature(tree, proto);
const proto_comments = (try analysis.getDocComments(alloc, tree, fn_node, .Markdown)) orelse ""; const proto_comments = (try analysis.getDocComments(alloc, tree, fn_node, .Markdown)) orelse "";
@ -119,7 +119,7 @@ pub fn getSignatureInfo(document_store: *DocumentStore, arena: *std.heap.ArenaAl
}; };
} }
}; };
const alloc = &arena.allocator; const alloc = arena.allocator();
var symbol_stack = try std.ArrayListUnmanaged(StackSymbol).initCapacity(alloc, 8); var symbol_stack = try std.ArrayListUnmanaged(StackSymbol).initCapacity(alloc, 8);
var curr_commas: u32 = 0; var curr_commas: u32 = 0;
var comma_stack = try std.ArrayListUnmanaged(u32).initCapacity(alloc, 4); var comma_stack = try std.ArrayListUnmanaged(u32).initCapacity(alloc, 4);

View File

@ -15,7 +15,7 @@ pub fn main() !void {
var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
defer arena.deinit(); defer arena.deinit();
const allocator = &arena.allocator; const allocator = arena.allocator();
const builder = try Builder.create(allocator, "", "", "", ""); const builder = try Builder.create(allocator, "", "", "", "");
defer builder.destroy(); defer builder.destroy();

View File

@ -19,7 +19,7 @@ const reserved_escapes = blk: {
}; };
/// Returns a URI from a path, caller owns the memory allocated with `allocator` /// Returns a URI from a path, caller owns the memory allocated with `allocator`
pub fn fromPath(allocator: *std.mem.Allocator, path: []const u8) ![]const u8 { pub fn fromPath(allocator: std.mem.Allocator, path: []const u8) ![]const u8 {
if (path.len == 0) return ""; if (path.len == 0) return "";
const prefix = if (builtin.os.tag == .windows) "file:///" else "file://"; const prefix = if (builtin.os.tag == .windows) "file:///" else "file://";
@ -51,14 +51,14 @@ pub fn fromPath(allocator: *std.mem.Allocator, path: []const u8) ![]const u8 {
/// Move along `rel` from `base` with a single allocation. /// Move along `rel` from `base` with a single allocation.
/// `base` is a URI of a folder, `rel` is a raw relative path. /// `base` is a URI of a folder, `rel` is a raw relative path.
pub fn pathRelative(allocator: *std.mem.Allocator, base: []const u8, rel: []const u8) ![]const u8 { pub fn pathRelative(allocator: std.mem.Allocator, base: []const u8, rel: []const u8) ![]const u8 {
const max_size = base.len + rel.len * 3 + 1; const max_size = base.len + rel.len * 3 + 1;
var result = try allocator.alloc(u8, max_size); var result = try allocator.alloc(u8, max_size);
errdefer allocator.free(result); errdefer allocator.free(result);
std.mem.copy(u8, result, base); std.mem.copy(u8, result, base);
var result_index: usize = base.len; var result_index: usize = base.len;
var it = std.mem.tokenize(u8, rel, "/"); var it = std.mem.tokenize(u8, rel, "/");
while (it.next()) |component| { while (it.next()) |component| {
if (std.mem.eql(u8, component, ".")) { if (std.mem.eql(u8, component, ".")) {
@ -87,7 +87,7 @@ pub fn pathRelative(allocator: *std.mem.Allocator, base: []const u8, rel: []cons
} }
} }
return allocator.resize(result, result_index); return allocator.resize(result, result_index) orelse error.FailedResize;
} }
// Original code: https://github.com/andersfr/zig-lsp/blob/master/uri.zig // Original code: https://github.com/andersfr/zig-lsp/blob/master/uri.zig
@ -101,7 +101,7 @@ fn parseHex(c: u8) !u8 {
} }
/// Caller should free memory /// Caller should free memory
pub fn parse(allocator: *std.mem.Allocator, str: []const u8) ![]u8 { pub fn parse(allocator: std.mem.Allocator, str: []const u8) ![]u8 {
if (str.len < 7 or !std.mem.eql(u8, "file://", str[0..7])) return error.UriBadScheme; if (str.len < 7 or !std.mem.eql(u8, "file://", str[0..7])) return error.UriBadScheme;
const uri = try allocator.alloc(u8, str.len - (if (std.fs.path.sep == '\\') 8 else 7)); const uri = try allocator.alloc(u8, str.len - (if (std.fs.path.sep == '\\') 8 else 7));

@ -1 +1 @@
Subproject commit 56da848c9aa8b5637114acff48576773a0ee998e Subproject commit 5e0d781eee025cfea271dd10c1939d201fe4fd25