Skip to content

Commit 9d89be4

Browse files
FnControlOptionTechatrix
authored andcommitted
Fix resolved type of @This() in a generic function
When looking for the innermost container, only add type parameters that are defined outside of the container. For example: fn Foo(A: type) type { return struct { fn bar(B: type) @this() { ... } } } Only `A` should be added to the set of type parameters for `Foo(A)`.
1 parent 8d6d7da commit 9d89be4

File tree

3 files changed

+66
-2
lines changed

3 files changed

+66
-2
lines changed

src/analysis.zig

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5695,12 +5695,21 @@ pub fn innermostContainer(analyser: *Analyser, handle: *DocumentStore.Handle, so
56955695
.is_type_val = true,
56965696
};
56975697

5698+
var pending_meta_params: TokenToTypeMap = .empty;
5699+
defer pending_meta_params.deinit(analyser.gpa);
5700+
56985701
var current: DocumentScope.Scope.Index = .root;
56995702
var meta_params: TokenToTypeMap = .empty;
57005703
var scope_iterator = iterateEnclosingScopes(&document_scope, source_index);
57015704
while (scope_iterator.next().unwrap()) |scope_index| {
57025705
switch (document_scope.getScopeTag(scope_index)) {
5703-
.container => current = scope_index,
5706+
.container => {
5707+
current = scope_index;
5708+
for (pending_meta_params.keys(), pending_meta_params.values()) |token_handle, ty| {
5709+
try meta_params.put(analyser.arena, token_handle, ty);
5710+
}
5711+
pending_meta_params.clearRetainingCapacity();
5712+
},
57045713
.function => {
57055714
const function_node = document_scope.getScopeAstNode(scope_index).?;
57065715
var buf: [1]Ast.Node.Index = undefined;
@@ -5712,7 +5721,7 @@ pub fn innermostContainer(analyser: *Analyser, handle: *DocumentStore.Handle, so
57125721
const param_name_token = param.name_token orelse continue;
57135722
const token_handle: TokenWithHandle = .{ .token = param_name_token, .handle = handle };
57145723
const ty: Type = .{ .data = .{ .type_parameter = token_handle }, .is_type_val = true };
5715-
try meta_params.put(analyser.arena, token_handle, ty);
5724+
try pending_meta_params.put(analyser.gpa, token_handle, ty);
57165725
}
57175726
},
57185727
else => {},

tests/lsp_features/completion.zig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4322,6 +4322,22 @@ test "insert replace behaviour - file system completions" {
43224322
// zig fmt: on
43234323
}
43244324

4325+
test "generic function with @This() as self param" {
4326+
try testCompletion(
4327+
\\const Foo = struct {
4328+
\\ fn bar(_: *const @This(), comptime _: type) void {}
4329+
\\};
4330+
\\const foo: Foo = .{};
4331+
\\const _ = foo.<cursor>
4332+
, &.{
4333+
.{
4334+
.label = "bar",
4335+
.kind = .Function,
4336+
.detail = "fn (_: *const Foo, comptime _: type) void",
4337+
},
4338+
});
4339+
}
4340+
43254341
fn testCompletion(source: []const u8, expected_completions: []const Completion) !void {
43264342
try testCompletionWithOptions(source, expected_completions, .{});
43274343
}

tests/lsp_features/semantic_tokens.zig

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2086,6 +2086,45 @@ test "weird code" {
20862086
, &.{}, .{ .mode = .zon });
20872087
}
20882088

2089+
test "generic function with @This() as self param" {
2090+
try testSemanticTokens(
2091+
\\const Demo = struct {
2092+
\\ fn bar(_: *@This(), comptime _: type) void {}
2093+
\\};
2094+
\\test {
2095+
\\ var demo: Demo = .{};
2096+
\\ Demo.bar(&demo, usize);
2097+
\\ demo.bar(usize);
2098+
\\}
2099+
, &.{
2100+
.{ "const", .keyword, .{} },
2101+
.{ "Demo", .namespace, .{ .declaration = true } },
2102+
.{ "=", .operator, .{} },
2103+
.{ "struct", .keyword, .{} },
2104+
.{ "fn", .keyword, .{} },
2105+
.{ "bar", .method, .{ .declaration = true, .generic = true } },
2106+
.{ "_", .parameter, .{ .declaration = true } },
2107+
.{ "@This", .builtin, .{} },
2108+
.{ "comptime", .keyword, .{} },
2109+
.{ "_", .typeParameter, .{ .declaration = true } },
2110+
.{ "type", .type, .{} },
2111+
.{ "void", .type, .{} },
2112+
.{ "test", .keyword, .{} },
2113+
.{ "var", .keyword, .{} },
2114+
.{ "demo", .variable, .{ .declaration = true, .mutable = true } },
2115+
.{ "Demo", .namespace, .{} },
2116+
.{ "=", .operator, .{} },
2117+
.{ "Demo", .namespace, .{} },
2118+
.{ "bar", .function, .{ .generic = true } },
2119+
.{ "&", .operator, .{} },
2120+
.{ "demo", .variable, .{ .mutable = true } },
2121+
.{ "usize", .type, .{} },
2122+
.{ "demo", .variable, .{ .mutable = true } },
2123+
.{ "bar", .function, .{ .generic = true } },
2124+
.{ "usize", .type, .{} },
2125+
});
2126+
}
2127+
20892128
const TokenData = struct {
20902129
[]const u8,
20912130
zls.semantic_tokens.TokenType,

0 commit comments

Comments
 (0)