Correctly handle inferred error sets, add self argument support when evaluating bound type params, semanticToken scaffolding
This commit is contained in:
parent
5c78e88b19
commit
112f6d735a
@ -277,7 +277,14 @@ fn resolveReturnType(
|
||||
}
|
||||
|
||||
return switch (fn_decl.return_type) {
|
||||
.Explicit, .InferErrorSet => |return_type| try resolveTypeOfNodeInternal(store, arena, .{
|
||||
.InferErrorSet => |return_type| block: {
|
||||
const child_type = (try resolveTypeOfNodeInternal(store, arena, .{
|
||||
.node = return_type,
|
||||
.handle = handle,
|
||||
}, bound_type_params)) orelse return null;
|
||||
break :block NodeWithHandle{ .node = try makeErrorUnionType(arena, child_type.node), .handle = child_type.handle };
|
||||
},
|
||||
.Explicit => |return_type| try resolveTypeOfNodeInternal(store, arena, .{
|
||||
.node = return_type,
|
||||
.handle = handle,
|
||||
}, bound_type_params),
|
||||
@ -345,9 +352,22 @@ fn resolveDerefType(
|
||||
return null;
|
||||
}
|
||||
|
||||
fn makeSliceType(arena: *std.heap.ArenaAllocator, child_type: *ast.Node) ?*ast.Node {
|
||||
fn makeErrorUnionType(arena: *std.heap.ArenaAllocator, child_type: *ast.Node) !*ast.Node {
|
||||
// TODO: Better values for fields, better way to do this?
|
||||
var slice_type = arena.allocator.create(ast.Node.PrefixOp) catch return null;
|
||||
var error_union_type = try arena.allocator.create(ast.Node.InfixOp);
|
||||
error_union_type.* = .{
|
||||
.op_token = child_type.firstToken(),
|
||||
.op = .ErrorUnion,
|
||||
.lhs = child_type, // This is a dummy value
|
||||
.rhs = child_type,
|
||||
};
|
||||
|
||||
return &error_union_type.base;
|
||||
}
|
||||
|
||||
fn makeSliceType(arena: *std.heap.ArenaAllocator, child_type: *ast.Node) !*ast.Node {
|
||||
// TODO: Better values for fields, better way to do this?
|
||||
var slice_type = try arena.allocator.create(ast.Node.PrefixOp);
|
||||
slice_type.* = .{
|
||||
.op_token = child_type.firstToken(),
|
||||
.op = .{
|
||||
@ -389,7 +409,7 @@ fn resolveBracketAccessType(
|
||||
.node = pop.rhs,
|
||||
.handle = lhs.handle,
|
||||
}, bound_type_params);
|
||||
return NodeWithHandle{ .node = makeSliceType(arena, pop.rhs) orelse return null, .handle = lhs.handle };
|
||||
return NodeWithHandle{ .node = try makeSliceType(arena, pop.rhs), .handle = lhs.handle };
|
||||
},
|
||||
.PtrType => {
|
||||
if (pop.rhs.cast(std.zig.ast.Node.PrefixOp)) |child_pop| {
|
||||
@ -455,9 +475,17 @@ fn resolveTypeOfNodeInternal(
|
||||
|
||||
const decl = (try resolveTypeOfNodeInternal(store, arena, .{ .node = call.lhs, .handle = handle }, bound_type_params)) orelse return null;
|
||||
if (decl.node.cast(ast.Node.FnProto)) |fn_decl| {
|
||||
var has_self_param: u8 = 0;
|
||||
if (call.lhs.cast(ast.Node.InfixOp)) |lhs_infix_op| {
|
||||
if (lhs_infix_op.op == .Period) {
|
||||
has_self_param = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Bidn type params to the expressions passed in the calls.
|
||||
const param_len = std.math.min(call.params_len, fn_decl.params_len);
|
||||
const param_len = std.math.min(call.params_len + has_self_param, fn_decl.params_len);
|
||||
for (fn_decl.paramsConst()) |*decl_param, param_idx| {
|
||||
if (param_idx < has_self_param) continue;
|
||||
if (param_idx >= param_len) break;
|
||||
|
||||
const type_param = switch (decl_param.param_type) {
|
||||
@ -467,11 +495,11 @@ fn resolveTypeOfNodeInternal(
|
||||
if (!type_param) continue;
|
||||
|
||||
const call_param_type = (try resolveTypeOfNodeInternal(store, arena, .{
|
||||
.node = call.paramsConst()[param_idx],
|
||||
.node = call.paramsConst()[param_idx - has_self_param],
|
||||
.handle = handle,
|
||||
}, bound_type_params)) orelse continue;
|
||||
|
||||
try bound_type_params.putNoClobber(decl_param, call_param_type);
|
||||
_ = try bound_type_params.put(decl_param, call_param_type);
|
||||
}
|
||||
|
||||
return try resolveReturnType(store, arena, fn_decl, decl.handle, bound_type_params);
|
||||
|
22
src/main.zig
22
src/main.zig
@ -28,7 +28,7 @@ const ClientCapabilities = struct {
|
||||
var client_capabilities = ClientCapabilities{};
|
||||
|
||||
const initialize_response =
|
||||
\\,"result":{"capabilities":{"signatureHelpProvider":{"triggerCharacters":["(",","]},"textDocumentSync":1,"completionProvider":{"resolveProvider":false,"triggerCharacters":[".",":","@"]},"documentHighlightProvider":false,"hoverProvider":true,"codeActionProvider":false,"declarationProvider":true,"definitionProvider":true,"typeDefinitionProvider":true,"implementationProvider":false,"referencesProvider":false,"documentSymbolProvider":true,"colorProvider":false,"documentFormattingProvider":false,"documentRangeFormattingProvider":false,"foldingRangeProvider":false,"selectionRangeProvider":false,"workspaceSymbolProvider":false,"semanticTokensProvider":{"legend":{"tokenTypes":["type","struct","enum","parameter","variable","enumMember","function","member","keyword","modifier","comment","string","number","operator"],"tokenModifiers":["definition","async","documentation"]},"rangeProvider":false,"documentProvider":true},"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":true}}}}}
|
||||
\\,"result":{"capabilities":{"signatureHelpProvider":{"triggerCharacters":["(",","]},"textDocumentSync":1,"completionProvider":{"resolveProvider":false,"triggerCharacters":[".",":","@"]},"documentHighlightProvider":false,"hoverProvider":true,"codeActionProvider":false,"declarationProvider":true,"definitionProvider":true,"typeDefinitionProvider":true,"implementationProvider":false,"referencesProvider":false,"documentSymbolProvider":true,"colorProvider":false,"documentFormattingProvider":false,"documentRangeFormattingProvider":false,"foldingRangeProvider":false,"selectionRangeProvider":false,"workspaceSymbolProvider":false,"rangeProvider":false,"documentProvider":true},"workspace":{"workspaceFolders":{"supported":true,"changeNotifications":true}},"semanticTokensProvider":{"documentProvider":true, "legend":{"tokenTypes":["type","struct","enum","union","parameter","variable","tagField","field","function","keyword","modifier","comment","string","number","operator"],"tokenModifiers":["definition","async","documentation"]}}}}
|
||||
;
|
||||
|
||||
const not_implemented_response =
|
||||
@ -947,8 +947,24 @@ fn processJsonRpc(parser: *std.json.Parser, json: []const u8, config: Config) !v
|
||||
// Semantic highlighting
|
||||
else if (std.mem.eql(u8, method, "textDocument/semanticTokens")) {
|
||||
const params = root.Object.getValue("params").?.Object;
|
||||
// TODO Implement this (we dont get here from vscode atm even when we get the client capab.)
|
||||
return try respondGeneric(id, empty_array_response);
|
||||
const document = params.getValue("textDocument").?.Object;
|
||||
const uri = document.getValue("uri").?.String;
|
||||
|
||||
const handle = document_store.getHandle(uri) orelse {
|
||||
std.debug.warn("Trying to complete in non existent document {}", .{uri});
|
||||
return try respondGeneric(id, no_completions_response);
|
||||
};
|
||||
|
||||
// TODO Actually test this in some editor, VSCode won't send me requests -_-'.
|
||||
const semantic_tokens = @import("semantic_tokens.zig");
|
||||
|
||||
const token_array = try semantic_tokens.writeAllSemanticTokens(allocator, handle.*);
|
||||
defer allocator.free(token_array);
|
||||
|
||||
return try send(types.Response{
|
||||
.id = id,
|
||||
.result = .{ .SemanticTokens = token_array },
|
||||
});
|
||||
}
|
||||
// Autocomplete / Signatures
|
||||
else if (std.mem.eql(u8, method, "textDocument/completion")) {
|
||||
|
90
src/semantic_tokens.zig
Normal file
90
src/semantic_tokens.zig
Normal file
@ -0,0 +1,90 @@
|
||||
const std = @import("std");
|
||||
const DocumentStore = @import("document_store.zig");
|
||||
const ast = std.zig.ast;
|
||||
|
||||
// ["type","struct","enum","union","parameter","variable","tagField","field","function","keyword","modifier","comment","string","number","operator"]
|
||||
const TokenType = enum(u32) {
|
||||
type,
|
||||
@"struct",
|
||||
@"enum",
|
||||
@"union",
|
||||
parameter,
|
||||
variable,
|
||||
tagField,
|
||||
field,
|
||||
function,
|
||||
keyword,
|
||||
modifier,
|
||||
comment,
|
||||
string,
|
||||
number,
|
||||
operator,
|
||||
};
|
||||
|
||||
const TokenModifiers = packed struct {
|
||||
definition: bool = false,
|
||||
@"async": bool = false,
|
||||
documentation: bool = false,
|
||||
|
||||
pub fn toInt(value: u32) TokenModifiers {
|
||||
return @bitCast(TokenModifiers, value);
|
||||
}
|
||||
|
||||
fn toInt(self: TokenModifiers) u32 {
|
||||
return @bitCast(u32, self);
|
||||
}
|
||||
|
||||
fn with(lhs: TokenModifiers, rhs: TokenModifiers) TokenModifiers {
|
||||
return fromInt(toInt(lhs) | toInt(rhs));
|
||||
}
|
||||
|
||||
fn intersect(lhs: TokenModifiers, rhs: TokenModifiers) TokenModifiers {
|
||||
return fromInt(toInt(lhs) & toInt(rhs));
|
||||
}
|
||||
};
|
||||
|
||||
const Builder = struct {
|
||||
tree: *ast.Tree,
|
||||
current_token: ?ast.TokenIndex,
|
||||
arr: std.ArrayList(u32),
|
||||
|
||||
fn printToken(start_idx: usize, token: ast.TokenIndex, token_type: TokenType, token_modifiers: TokenModifiers) !void {
|
||||
const delta_loc = self.tree.tokenLocationLoc(start_idx, token_loc);
|
||||
try out_stream.print(prefix ++ "{},{},{},{},{}", .{
|
||||
// TODO Is +1 on the column here correct? I think so.
|
||||
delta_loc.line, delta_loc.column + 1,
|
||||
token_loc.end - token_loc.start, @enumToInt(token_type),
|
||||
token_modifiers.toInt(),
|
||||
});
|
||||
}
|
||||
|
||||
fn create(allocator: *std.mem.Allocator, tree: *ast.Tree) Builder {
|
||||
return Builder{
|
||||
.tree = tree,
|
||||
.current_token = null,
|
||||
.arr = std.ArrayList(u32).init(allocator),
|
||||
};
|
||||
}
|
||||
|
||||
fn add(self: *Builder, out_stream: var, token: ast.TokenIndex, token_type: TokenType, token_modifiers: TokenModifiers) !void {
|
||||
if (self.current_token) |current_token| {
|
||||
std.debug.assert(token > current_token);
|
||||
try out_stream.print(",");
|
||||
try printToken(self.tree.token_locs[current_token].end, token, token_type, token_modifiers);
|
||||
} else {
|
||||
try printToken(0, token, token_type, token_modifiers);
|
||||
}
|
||||
self.current_token = token;
|
||||
}
|
||||
|
||||
pub fn toOwnedSlice(self: *Builder) []u32 {
|
||||
return self.arr.toOwnedSlice();
|
||||
}
|
||||
};
|
||||
|
||||
pub fn writeAllSemanticTokens(allocator: *std.mem.Allocator, handle: DocumentStore.Handle) ![]u32 {
|
||||
// TODO Actual implementation
|
||||
var builder = Builder.create(allocator, handle.tree);
|
||||
|
||||
return builder.toOwnedSlice();
|
||||
}
|
@ -58,7 +58,8 @@ pub const ResponseParams = union(enum) {
|
||||
CompletionList: CompletionList,
|
||||
Location: Location,
|
||||
Hover: Hover,
|
||||
DocumentSymbols: []DocumentSymbol
|
||||
DocumentSymbols: []DocumentSymbol,
|
||||
SemanticTokens: []u32,
|
||||
};
|
||||
|
||||
/// JSONRPC error
|
||||
|
Loading…
Reference in New Issue
Block a user