more forward declarations

This commit is contained in:
agra
2026-02-24 17:37:52 +02:00
parent 97475d6cfe
commit 566121c45a
13 changed files with 867 additions and 88 deletions

View File

@@ -1084,7 +1084,7 @@ pub const Server = struct {
};
var hints = std.ArrayList(lsp.InlayHint).empty;
collectInlayHints(self.allocator, root, sema.symbols, doc.source, &hints);
collectInlayHints(self.allocator, root, sema.symbols, sema.fn_signatures, doc.source, &hints);
self.collectCallHints(doc, root, &hints);
const result_json = try lsp.inlayHintsJson(self.allocator, hints.items);
try self.sendResponse(id_json, result_json);
@@ -1094,37 +1094,46 @@ pub const Server = struct {
allocator: std.mem.Allocator,
node: *const sx.ast.Node,
symbols: []const sx.sema.Symbol,
fn_signatures: std.StringHashMap(sx.sema.FnSignature),
source: [:0]const u8,
hints: *std.ArrayList(lsp.InlayHint),
) void {
switch (node.data) {
.root => |r| {
for (r.decls) |decl| collectInlayHints(allocator, decl, symbols, source, hints);
for (r.decls) |decl| collectInlayHints(allocator, decl, symbols, fn_signatures, source, hints);
},
.block => |b| {
for (b.stmts) |stmt| collectInlayHints(allocator, stmt, symbols, source, hints);
for (b.stmts) |stmt| collectInlayHints(allocator, stmt, symbols, fn_signatures, source, hints);
},
.fn_decl => |fd| {
collectInlayHints(allocator, fd.body, symbols, source, hints);
collectInlayHints(allocator, fd.body, symbols, fn_signatures, source, hints);
// Return type hint for arrow functions without explicit return type
if (fd.return_type == null and fd.is_arrow) {
if (fn_signatures.get(fd.name)) |sig| {
if (sig.return_type != .void_type) {
addReturnTypeHint(allocator, node.span, source, sig.return_type, hints);
}
}
}
},
.lambda => |lm| {
collectInlayHints(allocator, lm.body, symbols, source, hints);
collectInlayHints(allocator, lm.body, symbols, fn_signatures, source, hints);
},
.if_expr => |ie| {
if (ie.binding_name) |bname| {
addBindingHint(allocator, bname, node.span, symbols, source, hints);
}
collectInlayHints(allocator, ie.then_branch, symbols, source, hints);
if (ie.else_branch) |eb| collectInlayHints(allocator, eb, symbols, source, hints);
collectInlayHints(allocator, ie.then_branch, symbols, fn_signatures, source, hints);
if (ie.else_branch) |eb| collectInlayHints(allocator, eb, symbols, fn_signatures, source, hints);
},
.while_expr => |we| {
if (we.binding_name) |bname| {
addBindingHint(allocator, bname, node.span, symbols, source, hints);
}
collectInlayHints(allocator, we.body, symbols, source, hints);
collectInlayHints(allocator, we.body, symbols, fn_signatures, source, hints);
},
.for_expr => |fe| {
collectInlayHints(allocator, fe.body, symbols, source, hints);
collectInlayHints(allocator, fe.body, symbols, fn_signatures, source, hints);
},
.var_decl => |vd| {
// Only show hint when type is inferred (:= syntax)
@@ -1135,9 +1144,22 @@ pub const Server = struct {
.const_decl => |cd| {
// Skip if explicit type annotation
if (cd.type_annotation != null) return;
// Handle lambda with return type hint
if (cd.value.data == .lambda) {
const lam = cd.value.data.lambda;
collectInlayHints(allocator, lam.body, symbols, fn_signatures, source, hints);
if (lam.return_type == null) {
if (fn_signatures.get(cd.name)) |sig| {
if (sig.return_type != .void_type) {
addReturnTypeHint(allocator, cd.value.span, source, sig.return_type, hints);
}
}
}
return;
}
// Skip functions, types, structs, enums, unions, comptime, foreign, library
switch (cd.value.data) {
.lambda, .fn_decl, .type_expr, .struct_decl, .enum_decl, .union_decl,
.fn_decl, .type_expr, .struct_decl, .enum_decl, .union_decl,
.comptime_expr, .foreign_expr, .library_decl,
=> return,
else => {},
@@ -1241,6 +1263,47 @@ pub const Server = struct {
}
}
fn addReturnTypeHint(
allocator: std.mem.Allocator,
span: sx.ast.Span,
source: [:0]const u8,
return_type: sx.types.Type,
hints: *std.ArrayList(lsp.InlayHint),
) void {
// Find '(' from span start
var pos: u32 = span.start;
while (pos < source.len and source[pos] != '(') : (pos += 1) {}
if (pos >= source.len) return;
// Match nested parens to find closing ')'
var depth: u32 = 0;
while (pos < source.len) : (pos += 1) {
if (source[pos] == '(') {
depth += 1;
} else if (source[pos] == ')') {
depth -= 1;
if (depth == 0) break;
}
}
if (pos >= source.len or depth != 0) return;
// Place hint right after ')'
const loc = sx.errors.SourceLoc.compute(source, pos + 1);
if (loc.line == 0 or loc.col == 0) return;
const type_name = return_type.displayName(allocator) catch return;
const label = std.fmt.allocPrint(allocator, "-> {s}", .{type_name}) catch return;
hints.append(allocator, .{
.line = loc.line - 1,
.character = loc.col - 1,
.label = label,
.kind = 1,
.padding_left = true,
.padding_right = true,
}) catch {};
}
fn findSymbolAtSpan(symbols: []const sx.sema.Symbol, span_start: u32, name: []const u8) ?sx.sema.Symbol {
for (symbols) |sym| {
if (sym.def_span.start == span_start and std.mem.eql(u8, sym.name, name)) {