Branching type resolution (#1031)
* Branching type resolution * Add condition information to completions (borked rn i give up) * Fix completion conditional descriptor * Multi gotodef * Multi hover * Reenable references * Fix getAllTypesWithHandles
This commit is contained in:
		
							parent
							
								
									515a0e4727
								
							
						
					
					
						commit
						2ce59a3bc3
					
				
							
								
								
									
										191
									
								
								src/Server.zig
									
									
									
									
									
								
							
							
						
						
									
										191
									
								
								src/Server.zig
									
									
									
									
									
								
							@ -545,6 +545,7 @@ pub fn typeToCompletion(
 | 
				
			|||||||
    list: *std.ArrayListUnmanaged(types.CompletionItem),
 | 
					    list: *std.ArrayListUnmanaged(types.CompletionItem),
 | 
				
			||||||
    field_access: analysis.FieldAccessReturn,
 | 
					    field_access: analysis.FieldAccessReturn,
 | 
				
			||||||
    orig_handle: *const DocumentStore.Handle,
 | 
					    orig_handle: *const DocumentStore.Handle,
 | 
				
			||||||
 | 
					    either_descriptor: ?[]const u8,
 | 
				
			||||||
) error{OutOfMemory}!void {
 | 
					) error{OutOfMemory}!void {
 | 
				
			||||||
    var allocator = server.arena.allocator();
 | 
					    var allocator = server.arena.allocator();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -587,6 +588,7 @@ pub fn typeToCompletion(
 | 
				
			|||||||
                orig_handle,
 | 
					                orig_handle,
 | 
				
			||||||
                type_handle.type.is_type_val,
 | 
					                type_handle.type.is_type_val,
 | 
				
			||||||
                null,
 | 
					                null,
 | 
				
			||||||
 | 
					                either_descriptor,
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        .other => |n| try server.nodeToCompletion(
 | 
					        .other => |n| try server.nodeToCompletion(
 | 
				
			||||||
@ -596,6 +598,7 @@ pub fn typeToCompletion(
 | 
				
			|||||||
            orig_handle,
 | 
					            orig_handle,
 | 
				
			||||||
            type_handle.type.is_type_val,
 | 
					            type_handle.type.is_type_val,
 | 
				
			||||||
            null,
 | 
					            null,
 | 
				
			||||||
 | 
					            either_descriptor,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        .primitive, .array_index => {},
 | 
					        .primitive, .array_index => {},
 | 
				
			||||||
        .@"comptime" => |co| try analyser.completions.dotCompletions(
 | 
					        .@"comptime" => |co| try analyser.completions.dotCompletions(
 | 
				
			||||||
@ -606,6 +609,10 @@ pub fn typeToCompletion(
 | 
				
			|||||||
            type_handle.type.is_type_val,
 | 
					            type_handle.type.is_type_val,
 | 
				
			||||||
            co.value.node_idx,
 | 
					            co.value.node_idx,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
 | 
					        .either => |bruh| {
 | 
				
			||||||
 | 
					            for (bruh) |a|
 | 
				
			||||||
 | 
					                try server.typeToCompletion(list, .{ .original = a.type_with_handle }, orig_handle, a.descriptor);
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -617,6 +624,7 @@ pub fn nodeToCompletion(
 | 
				
			|||||||
    orig_handle: *const DocumentStore.Handle,
 | 
					    orig_handle: *const DocumentStore.Handle,
 | 
				
			||||||
    is_type_val: bool,
 | 
					    is_type_val: bool,
 | 
				
			||||||
    parent_is_type_val: ?bool,
 | 
					    parent_is_type_val: ?bool,
 | 
				
			||||||
 | 
					    either_descriptor: ?[]const u8,
 | 
				
			||||||
) error{OutOfMemory}!void {
 | 
					) error{OutOfMemory}!void {
 | 
				
			||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
@ -643,8 +651,17 @@ pub fn nodeToCompletion(
 | 
				
			|||||||
        doc_kind,
 | 
					        doc_kind,
 | 
				
			||||||
    )) |doc_comments| .{ .MarkupContent = types.MarkupContent{
 | 
					    )) |doc_comments| .{ .MarkupContent = types.MarkupContent{
 | 
				
			||||||
        .kind = doc_kind,
 | 
					        .kind = doc_kind,
 | 
				
			||||||
        .value = doc_comments,
 | 
					        .value = if (either_descriptor) |ed|
 | 
				
			||||||
    } } else null;
 | 
					            try std.fmt.allocPrint(allocator, "`Conditionally available: {s}`\n\n{s}", .{ ed, doc_comments })
 | 
				
			||||||
 | 
					        else
 | 
				
			||||||
 | 
					            doc_comments,
 | 
				
			||||||
 | 
					    } } else (if (either_descriptor) |ed|
 | 
				
			||||||
 | 
					        .{ .MarkupContent = types.MarkupContent{
 | 
				
			||||||
 | 
					            .kind = doc_kind,
 | 
				
			||||||
 | 
					            .value = try std.fmt.allocPrint(allocator, "`Conditionally available: {s}`", .{ed}),
 | 
				
			||||||
 | 
					        } }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					        null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ast.isContainer(handle.tree, node)) {
 | 
					    if (ast.isContainer(handle.tree, node)) {
 | 
				
			||||||
        const context = DeclToCompletionContext{
 | 
					        const context = DeclToCompletionContext{
 | 
				
			||||||
@ -652,8 +669,10 @@ pub fn nodeToCompletion(
 | 
				
			|||||||
            .completions = list,
 | 
					            .completions = list,
 | 
				
			||||||
            .orig_handle = orig_handle,
 | 
					            .orig_handle = orig_handle,
 | 
				
			||||||
            .parent_is_type_val = is_type_val,
 | 
					            .parent_is_type_val = is_type_val,
 | 
				
			||||||
 | 
					            .either_descriptor = either_descriptor,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        try analysis.iterateSymbolsContainer(
 | 
					        try analysis.iterateSymbolsContainer(
 | 
				
			||||||
 | 
					            allocator,
 | 
				
			||||||
            &server.document_store,
 | 
					            &server.document_store,
 | 
				
			||||||
            node_handle,
 | 
					            node_handle,
 | 
				
			||||||
            orig_handle,
 | 
					            orig_handle,
 | 
				
			||||||
@ -678,7 +697,7 @@ pub fn nodeToCompletion(
 | 
				
			|||||||
                const use_snippets = server.config.enable_snippets and server.client_capabilities.supports_snippets;
 | 
					                const use_snippets = server.config.enable_snippets and server.client_capabilities.supports_snippets;
 | 
				
			||||||
                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(&server.document_store, handle, func);
 | 
					                        try analysis.hasSelfParam(allocator, &server.document_store, handle, func);
 | 
				
			||||||
                    break :blk try analysis.getFunctionSnippet(server.arena.allocator(), tree, func, skip_self_param);
 | 
					                    break :blk try analysis.getFunctionSnippet(server.arena.allocator(), tree, func, skip_self_param);
 | 
				
			||||||
                } else tree.tokenSlice(func.name_token.?);
 | 
					                } else tree.tokenSlice(func.name_token.?);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -702,11 +721,12 @@ pub fn nodeToCompletion(
 | 
				
			|||||||
            const var_decl = tree.fullVarDecl(node).?;
 | 
					            const var_decl = tree.fullVarDecl(node).?;
 | 
				
			||||||
            const is_const = token_tags[var_decl.ast.mut_token] == .keyword_const;
 | 
					            const is_const = token_tags[var_decl.ast.mut_token] == .keyword_const;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (try analysis.resolveVarDeclAlias(&server.document_store, node_handle)) |result| {
 | 
					            if (try analysis.resolveVarDeclAlias(allocator, &server.document_store, node_handle)) |result| {
 | 
				
			||||||
                const context = DeclToCompletionContext{
 | 
					                const context = DeclToCompletionContext{
 | 
				
			||||||
                    .server = server,
 | 
					                    .server = server,
 | 
				
			||||||
                    .completions = list,
 | 
					                    .completions = list,
 | 
				
			||||||
                    .orig_handle = orig_handle,
 | 
					                    .orig_handle = orig_handle,
 | 
				
			||||||
 | 
					                    .either_descriptor = either_descriptor,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
                return try declToCompletion(context, result);
 | 
					                return try declToCompletion(context, result);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -780,7 +800,7 @@ pub fn nodeToCompletion(
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (unwrapped) |actual_type| {
 | 
					            if (unwrapped) |actual_type| {
 | 
				
			||||||
                try server.typeToCompletion(list, .{ .original = actual_type }, orig_handle);
 | 
					                try server.typeToCompletion(list, .{ .original = actual_type }, orig_handle, either_descriptor);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return;
 | 
					            return;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -847,7 +867,7 @@ pub fn gotoDefinitionSymbol(
 | 
				
			|||||||
    const name_token = switch (decl_handle.decl.*) {
 | 
					    const name_token = switch (decl_handle.decl.*) {
 | 
				
			||||||
        .ast_node => |node| block: {
 | 
					        .ast_node => |node| block: {
 | 
				
			||||||
            if (resolve_alias) {
 | 
					            if (resolve_alias) {
 | 
				
			||||||
                if (try analysis.resolveVarDeclAlias(&server.document_store, .{ .node = node, .handle = handle })) |result| {
 | 
					                if (try analysis.resolveVarDeclAlias(server.arena.allocator(), &server.document_store, .{ .node = node, .handle = handle })) |result| {
 | 
				
			||||||
                    handle = result.handle;
 | 
					                    handle = result.handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    break :block result.nameToken();
 | 
					                    break :block result.nameToken();
 | 
				
			||||||
@ -865,22 +885,21 @@ pub fn gotoDefinitionSymbol(
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn hoverSymbol(server: *Server, decl_handle: analysis.DeclWithHandle) error{OutOfMemory}!?types.Hover {
 | 
					pub fn hoverSymbol(server: *Server, decl_handle: analysis.DeclWithHandle, markup_kind: types.MarkupKind) error{OutOfMemory}!?[]const u8 {
 | 
				
			||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const handle = decl_handle.handle;
 | 
					    const handle = decl_handle.handle;
 | 
				
			||||||
    const tree = handle.tree;
 | 
					    const tree = handle.tree;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const hover_kind: types.MarkupKind = if (server.client_capabilities.hover_supports_md) .markdown else .plaintext;
 | 
					 | 
				
			||||||
    var doc_str: ?[]const u8 = null;
 | 
					    var doc_str: ?[]const u8 = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const def_str = switch (decl_handle.decl.*) {
 | 
					    const def_str = switch (decl_handle.decl.*) {
 | 
				
			||||||
        .ast_node => |node| def: {
 | 
					        .ast_node => |node| def: {
 | 
				
			||||||
            if (try analysis.resolveVarDeclAlias(&server.document_store, .{ .node = node, .handle = handle })) |result| {
 | 
					            if (try analysis.resolveVarDeclAlias(server.arena.allocator(), &server.document_store, .{ .node = node, .handle = handle })) |result| {
 | 
				
			||||||
                return try server.hoverSymbol(result);
 | 
					                return try server.hoverSymbol(result, markup_kind);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            doc_str = try analysis.getDocComments(server.arena.allocator(), tree, node, hover_kind);
 | 
					            doc_str = try analysis.getDocComments(server.arena.allocator(), tree, node, markup_kind);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var buf: [1]Ast.Node.Index = undefined;
 | 
					            var buf: [1]Ast.Node.Index = undefined;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -897,7 +916,7 @@ pub fn hoverSymbol(server: *Server, decl_handle: analysis.DeclWithHandle) error{
 | 
				
			|||||||
        .param_payload => |pay| def: {
 | 
					        .param_payload => |pay| def: {
 | 
				
			||||||
            const param = pay.param;
 | 
					            const param = pay.param;
 | 
				
			||||||
            if (param.first_doc_comment) |doc_comments| {
 | 
					            if (param.first_doc_comment) |doc_comments| {
 | 
				
			||||||
                doc_str = try analysis.collectDocComments(server.arena.allocator(), handle.tree, doc_comments, hover_kind, false);
 | 
					                doc_str = try analysis.collectDocComments(server.arena.allocator(), handle.tree, doc_comments, markup_kind, false);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const first_token = ast.paramFirstToken(tree, param);
 | 
					            const first_token = ast.paramFirstToken(tree, param);
 | 
				
			||||||
@ -918,7 +937,7 @@ pub fn hoverSymbol(server: *Server, decl_handle: analysis.DeclWithHandle) error{
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    var bound_type_params = analysis.BoundTypeParams{};
 | 
					    var bound_type_params = analysis.BoundTypeParams{};
 | 
				
			||||||
    defer bound_type_params.deinit(server.document_store.allocator);
 | 
					    defer bound_type_params.deinit(server.document_store.allocator);
 | 
				
			||||||
    const resolved_type = try decl_handle.resolveType(&server.document_store, &bound_type_params);
 | 
					    const resolved_type = try decl_handle.resolveType(server.arena.allocator(), &server.document_store, &bound_type_params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    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) {
 | 
				
			||||||
@ -965,7 +984,7 @@ pub fn hoverSymbol(server: *Server, decl_handle: analysis.DeclWithHandle) error{
 | 
				
			|||||||
        "unknown";
 | 
					        "unknown";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var hover_text: []const u8 = undefined;
 | 
					    var hover_text: []const u8 = undefined;
 | 
				
			||||||
    if (hover_kind == .markdown) {
 | 
					    if (markup_kind == .markdown) {
 | 
				
			||||||
        hover_text =
 | 
					        hover_text =
 | 
				
			||||||
            if (doc_str) |doc|
 | 
					            if (doc_str) |doc|
 | 
				
			||||||
            try std.fmt.allocPrint(server.arena.allocator(), "```zig\n{s}\n```\n```zig\n({s})\n```\n{s}", .{ def_str, resolved_type_str, doc })
 | 
					            try std.fmt.allocPrint(server.arena.allocator(), "```zig\n{s}\n```\n```zig\n({s})\n```\n{s}", .{ def_str, resolved_type_str, doc })
 | 
				
			||||||
@ -979,12 +998,7 @@ pub fn hoverSymbol(server: *Server, decl_handle: analysis.DeclWithHandle) error{
 | 
				
			|||||||
            try std.fmt.allocPrint(server.arena.allocator(), "{s} ({s})", .{ def_str, resolved_type_str });
 | 
					            try std.fmt.allocPrint(server.arena.allocator(), "{s} ({s})", .{ def_str, resolved_type_str });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return types.Hover{
 | 
					    return hover_text;
 | 
				
			||||||
        .contents = .{ .MarkupContent = .{
 | 
					 | 
				
			||||||
            .kind = hover_kind,
 | 
					 | 
				
			||||||
            .value = hover_text,
 | 
					 | 
				
			||||||
        } },
 | 
					 | 
				
			||||||
    };
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn getLabelGlobal(pos_index: usize, handle: *const DocumentStore.Handle) error{OutOfMemory}!?analysis.DeclWithHandle {
 | 
					pub fn getLabelGlobal(pos_index: usize, handle: *const DocumentStore.Handle) error{OutOfMemory}!?analysis.DeclWithHandle {
 | 
				
			||||||
@ -1008,7 +1022,7 @@ pub fn getSymbolGlobal(
 | 
				
			|||||||
    const name = identifierFromPosition(pos_index, handle.*);
 | 
					    const name = identifierFromPosition(pos_index, handle.*);
 | 
				
			||||||
    if (name.len == 0) return null;
 | 
					    if (name.len == 0) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return try analysis.lookupSymbolGlobal(&server.document_store, handle, name, pos_index);
 | 
					    return try analysis.lookupSymbolGlobal(server.arena.allocator(), &server.document_store, handle, name, pos_index);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn gotoDefinitionLabel(
 | 
					pub fn gotoDefinitionLabel(
 | 
				
			||||||
@ -1072,8 +1086,17 @@ pub fn hoverDefinitionLabel(server: *Server, pos_index: usize, handle: *const Do
 | 
				
			|||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const markup_kind: types.MarkupKind = if (server.client_capabilities.hover_supports_md) .markdown else .plaintext;
 | 
				
			||||||
    const decl = (try getLabelGlobal(pos_index, handle)) orelse return null;
 | 
					    const decl = (try getLabelGlobal(pos_index, handle)) orelse return null;
 | 
				
			||||||
    return try server.hoverSymbol(decl);
 | 
					
 | 
				
			||||||
 | 
					    return .{
 | 
				
			||||||
 | 
					        .contents = .{
 | 
				
			||||||
 | 
					            .MarkupContent = .{
 | 
				
			||||||
 | 
					                .kind = markup_kind,
 | 
				
			||||||
 | 
					                .value = (try server.hoverSymbol(decl, markup_kind)) orelse return null,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn hoverDefinitionBuiltin(server: *Server, pos_index: usize, handle: *const DocumentStore.Handle) error{OutOfMemory}!?types.Hover {
 | 
					pub fn hoverDefinitionBuiltin(server: *Server, pos_index: usize, handle: *const DocumentStore.Handle) error{OutOfMemory}!?types.Hover {
 | 
				
			||||||
@ -1130,16 +1153,26 @@ pub fn hoverDefinitionGlobal(server: *Server, pos_index: usize, handle: *const D
 | 
				
			|||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const markup_kind: types.MarkupKind = if (server.client_capabilities.hover_supports_md) .markdown else .plaintext;
 | 
				
			||||||
    const decl = (try server.getSymbolGlobal(pos_index, handle)) orelse return null;
 | 
					    const decl = (try server.getSymbolGlobal(pos_index, handle)) orelse return null;
 | 
				
			||||||
    return try server.hoverSymbol(decl);
 | 
					
 | 
				
			||||||
 | 
					    return .{
 | 
				
			||||||
 | 
					        .contents = .{
 | 
				
			||||||
 | 
					            .MarkupContent = .{
 | 
				
			||||||
 | 
					                .kind = markup_kind,
 | 
				
			||||||
 | 
					                .value = (try server.hoverSymbol(decl, markup_kind)) orelse return null,
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn getSymbolFieldAccess(
 | 
					/// Multiple when using branched types
 | 
				
			||||||
 | 
					pub fn getSymbolFieldAccesses(
 | 
				
			||||||
    server: *Server,
 | 
					    server: *Server,
 | 
				
			||||||
    handle: *const DocumentStore.Handle,
 | 
					    handle: *const DocumentStore.Handle,
 | 
				
			||||||
    source_index: usize,
 | 
					    source_index: usize,
 | 
				
			||||||
    loc: offsets.Loc,
 | 
					    loc: offsets.Loc,
 | 
				
			||||||
) error{OutOfMemory}!?analysis.DeclWithHandle {
 | 
					) error{OutOfMemory}!?[]const analysis.DeclWithHandle {
 | 
				
			||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -1149,20 +1182,29 @@ pub fn getSymbolFieldAccess(
 | 
				
			|||||||
    var held_range = try server.arena.allocator().dupeZ(u8, offsets.locToSlice(handle.text, loc));
 | 
					    var held_range = try server.arena.allocator().dupeZ(u8, offsets.locToSlice(handle.text, loc));
 | 
				
			||||||
    var tokenizer = std.zig.Tokenizer.init(held_range);
 | 
					    var tokenizer = std.zig.Tokenizer.init(held_range);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (try analysis.getFieldAccessType(&server.document_store, handle, source_index, &tokenizer)) |result| {
 | 
					    var decls_with_handles = std.ArrayListUnmanaged(analysis.DeclWithHandle){};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (try analysis.getFieldAccessType(server.arena.allocator(), &server.document_store, handle, source_index, &tokenizer)) |result| {
 | 
				
			||||||
        const container_handle = result.unwrapped orelse result.original;
 | 
					        const container_handle = result.unwrapped orelse result.original;
 | 
				
			||||||
        const container_handle_node = switch (container_handle.type.data) {
 | 
					
 | 
				
			||||||
            .other => |n| n,
 | 
					        const container_handle_nodes = try container_handle.getAllTypesWithHandles(server.arena.allocator());
 | 
				
			||||||
            else => return null,
 | 
					
 | 
				
			||||||
        };
 | 
					        for (container_handle_nodes) |ty| {
 | 
				
			||||||
        return try analysis.lookupSymbolContainer(
 | 
					            const container_handle_node = switch (ty.type.data) {
 | 
				
			||||||
            &server.document_store,
 | 
					                .other => |n| n,
 | 
				
			||||||
            .{ .node = container_handle_node, .handle = container_handle.handle },
 | 
					                else => continue,
 | 
				
			||||||
            name,
 | 
					            };
 | 
				
			||||||
            true,
 | 
					            try decls_with_handles.append(server.arena.allocator(), (try analysis.lookupSymbolContainer(
 | 
				
			||||||
        );
 | 
					                server.arena.allocator(),
 | 
				
			||||||
 | 
					                &server.document_store,
 | 
				
			||||||
 | 
					                .{ .node = container_handle_node, .handle = ty.handle },
 | 
				
			||||||
 | 
					                name,
 | 
				
			||||||
 | 
					                true,
 | 
				
			||||||
 | 
					            )) orelse continue);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null;
 | 
					
 | 
				
			||||||
 | 
					    return try decls_with_handles.toOwnedSlice(server.arena.allocator());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn gotoDefinitionFieldAccess(
 | 
					pub fn gotoDefinitionFieldAccess(
 | 
				
			||||||
@ -1171,12 +1213,22 @@ pub fn gotoDefinitionFieldAccess(
 | 
				
			|||||||
    source_index: usize,
 | 
					    source_index: usize,
 | 
				
			||||||
    loc: offsets.Loc,
 | 
					    loc: offsets.Loc,
 | 
				
			||||||
    resolve_alias: bool,
 | 
					    resolve_alias: bool,
 | 
				
			||||||
) error{OutOfMemory}!?types.Location {
 | 
					) error{OutOfMemory}!?[]const types.Location {
 | 
				
			||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const decl = (try server.getSymbolFieldAccess(handle, source_index, loc)) orelse return null;
 | 
					    const accesses = (try server.getSymbolFieldAccesses(handle, source_index, loc)) orelse return null;
 | 
				
			||||||
    return try server.gotoDefinitionSymbol(decl, resolve_alias);
 | 
					    var locs = std.ArrayListUnmanaged(types.Location){};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (accesses) |access| {
 | 
				
			||||||
 | 
					        if (try server.gotoDefinitionSymbol(access, resolve_alias)) |l|
 | 
				
			||||||
 | 
					            try locs.append(server.arena.allocator(), l);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (locs.items.len == 0)
 | 
				
			||||||
 | 
					        return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return try locs.toOwnedSlice(server.arena.allocator());
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn hoverDefinitionFieldAccess(
 | 
					pub fn hoverDefinitionFieldAccess(
 | 
				
			||||||
@ -1188,8 +1240,24 @@ pub fn hoverDefinitionFieldAccess(
 | 
				
			|||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const decl = (try server.getSymbolFieldAccess(handle, source_index, loc)) orelse return null;
 | 
					    const markup_kind: types.MarkupKind = if (server.client_capabilities.hover_supports_md) .markdown else .plaintext;
 | 
				
			||||||
    return try server.hoverSymbol(decl);
 | 
					    const decls = (try server.getSymbolFieldAccesses(handle, source_index, loc)) orelse return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    var content = std.ArrayListUnmanaged(types.MarkedString){};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    for (decls) |decl| {
 | 
				
			||||||
 | 
					        try content.append(server.arena.allocator(), .{
 | 
				
			||||||
 | 
					            .string = (try server.hoverSymbol(decl, markup_kind)) orelse continue,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Yes, this is deprecated; the issue is that there's no better
 | 
				
			||||||
 | 
					    // solution for multiple hover entries :(
 | 
				
			||||||
 | 
					    return .{
 | 
				
			||||||
 | 
					        .contents = .{
 | 
				
			||||||
 | 
					            .array_of_MarkedString = try content.toOwnedSlice(server.arena.allocator()),
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn gotoDefinitionString(
 | 
					pub fn gotoDefinitionString(
 | 
				
			||||||
@ -1248,6 +1316,7 @@ const DeclToCompletionContext = struct {
 | 
				
			|||||||
    completions: *std.ArrayListUnmanaged(types.CompletionItem),
 | 
					    completions: *std.ArrayListUnmanaged(types.CompletionItem),
 | 
				
			||||||
    orig_handle: *const DocumentStore.Handle,
 | 
					    orig_handle: *const DocumentStore.Handle,
 | 
				
			||||||
    parent_is_type_val: ?bool = null,
 | 
					    parent_is_type_val: ?bool = null,
 | 
				
			||||||
 | 
					    either_descriptor: ?[]const u8 = null,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.DeclWithHandle) error{OutOfMemory}!void {
 | 
					pub fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.DeclWithHandle) error{OutOfMemory}!void {
 | 
				
			||||||
@ -1265,6 +1334,7 @@ pub fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.
 | 
				
			|||||||
            context.orig_handle,
 | 
					            context.orig_handle,
 | 
				
			||||||
            false,
 | 
					            false,
 | 
				
			||||||
            context.parent_is_type_val,
 | 
					            context.parent_is_type_val,
 | 
				
			||||||
 | 
					            context.either_descriptor,
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        .param_payload => |pay| {
 | 
					        .param_payload => |pay| {
 | 
				
			||||||
            const Documentation = @TypeOf(@as(types.CompletionItem, undefined).documentation);
 | 
					            const Documentation = @TypeOf(@as(types.CompletionItem, undefined).documentation);
 | 
				
			||||||
@ -1273,7 +1343,10 @@ pub fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.
 | 
				
			|||||||
            const doc_kind: types.MarkupKind = if (context.server.client_capabilities.completion_doc_supports_md) .markdown else .plaintext;
 | 
					            const doc_kind: types.MarkupKind = if (context.server.client_capabilities.completion_doc_supports_md) .markdown else .plaintext;
 | 
				
			||||||
            const doc: Documentation = if (param.first_doc_comment) |doc_comments| .{ .MarkupContent = types.MarkupContent{
 | 
					            const doc: Documentation = if (param.first_doc_comment) |doc_comments| .{ .MarkupContent = types.MarkupContent{
 | 
				
			||||||
                .kind = doc_kind,
 | 
					                .kind = doc_kind,
 | 
				
			||||||
                .value = try analysis.collectDocComments(allocator, tree, doc_comments, doc_kind, false),
 | 
					                .value = if (context.either_descriptor) |ed|
 | 
				
			||||||
 | 
					                    try std.fmt.allocPrint(allocator, "`Conditionally available: {s}`\n\n{s}", .{ ed, try analysis.collectDocComments(allocator, tree, doc_comments, doc_kind, false) })
 | 
				
			||||||
 | 
					                else
 | 
				
			||||||
 | 
					                    try analysis.collectDocComments(allocator, tree, doc_comments, doc_kind, false),
 | 
				
			||||||
            } } else null;
 | 
					            } } else null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const first_token = ast.paramFirstToken(tree, param);
 | 
					            const first_token = ast.paramFirstToken(tree, param);
 | 
				
			||||||
@ -1416,7 +1489,7 @@ pub fn completeGlobal(server: *Server, pos_index: usize, handle: *const Document
 | 
				
			|||||||
        .completions = &completions,
 | 
					        .completions = &completions,
 | 
				
			||||||
        .orig_handle = handle,
 | 
					        .orig_handle = handle,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
    try analysis.iterateSymbolsGlobal(&server.document_store, handle, pos_index, declToCompletion, context);
 | 
					    try analysis.iterateSymbolsGlobal(server.arena.allocator(), &server.document_store, handle, pos_index, declToCompletion, context);
 | 
				
			||||||
    try populateSnippedCompletions(server.arena.allocator(), &completions, &snipped_data.generic, server.config.*, null);
 | 
					    try populateSnippedCompletions(server.arena.allocator(), &completions, &snipped_data.generic, server.config.*, null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (server.client_capabilities.label_details_support) {
 | 
					    if (server.client_capabilities.label_details_support) {
 | 
				
			||||||
@ -1439,8 +1512,8 @@ pub fn completeFieldAccess(server: *Server, handle: *const DocumentStore.Handle,
 | 
				
			|||||||
    var held_loc = try allocator.dupeZ(u8, offsets.locToSlice(handle.text, loc));
 | 
					    var held_loc = try allocator.dupeZ(u8, offsets.locToSlice(handle.text, loc));
 | 
				
			||||||
    var tokenizer = std.zig.Tokenizer.init(held_loc);
 | 
					    var tokenizer = std.zig.Tokenizer.init(held_loc);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const result = (try analysis.getFieldAccessType(&server.document_store, handle, source_index, &tokenizer)) orelse return null;
 | 
					    const result = (try analysis.getFieldAccessType(allocator, &server.document_store, handle, source_index, &tokenizer)) orelse return null;
 | 
				
			||||||
    try server.typeToCompletion(&completions, result, handle);
 | 
					    try server.typeToCompletion(&completions, result, handle, null);
 | 
				
			||||||
    if (server.client_capabilities.label_details_support) {
 | 
					    if (server.client_capabilities.label_details_support) {
 | 
				
			||||||
        for (completions.items) |*item| {
 | 
					        for (completions.items) |*item| {
 | 
				
			||||||
            try formatDetailledLabel(item, allocator);
 | 
					            try formatDetailledLabel(item, allocator);
 | 
				
			||||||
@ -2335,7 +2408,7 @@ pub fn signatureHelpHandler(server: *Server, request: types.SignatureHelpParams)
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn gotoHandler(server: *Server, request: types.TextDocumentPositionParams, resolve_alias: bool) Error!?types.Location {
 | 
					pub fn gotoHandler(server: *Server, request: types.TextDocumentPositionParams, resolve_alias: bool) Error!?types.Definition {
 | 
				
			||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2347,14 +2420,14 @@ pub fn gotoHandler(server: *Server, request: types.TextDocumentPositionParams, r
 | 
				
			|||||||
    const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.text, source_index, true);
 | 
					    const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.text, source_index, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return switch (pos_context) {
 | 
					    return switch (pos_context) {
 | 
				
			||||||
        .builtin => |loc| try server.gotoDefinitionBuiltin(handle, loc),
 | 
					        .builtin => |loc| .{ .Location = (try server.gotoDefinitionBuiltin(handle, loc)) orelse return null },
 | 
				
			||||||
        .var_access => try server.gotoDefinitionGlobal(source_index, handle, resolve_alias),
 | 
					        .var_access => .{ .Location = (try server.gotoDefinitionGlobal(source_index, handle, resolve_alias)) orelse return null },
 | 
				
			||||||
        .field_access => |loc| try server.gotoDefinitionFieldAccess(handle, source_index, loc, resolve_alias),
 | 
					        .field_access => |loc| .{ .array_of_Location = (try server.gotoDefinitionFieldAccess(handle, source_index, loc, resolve_alias)) orelse return null },
 | 
				
			||||||
        .import_string_literal,
 | 
					        .import_string_literal,
 | 
				
			||||||
        .cinclude_string_literal,
 | 
					        .cinclude_string_literal,
 | 
				
			||||||
        .embedfile_string_literal,
 | 
					        .embedfile_string_literal,
 | 
				
			||||||
        => try server.gotoDefinitionString(pos_context, handle),
 | 
					        => .{ .Location = (try server.gotoDefinitionString(pos_context, handle)) orelse return null },
 | 
				
			||||||
        .label => try server.gotoDefinitionLabel(source_index, handle),
 | 
					        .label => .{ .Location = (try server.gotoDefinitionLabel(source_index, handle)) orelse return null },
 | 
				
			||||||
        else => null,
 | 
					        else => null,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -2362,7 +2435,7 @@ pub fn gotoHandler(server: *Server, request: types.TextDocumentPositionParams, r
 | 
				
			|||||||
fn gotoDefinitionHandler(
 | 
					fn gotoDefinitionHandler(
 | 
				
			||||||
    server: *Server,
 | 
					    server: *Server,
 | 
				
			||||||
    request: types.TextDocumentPositionParams,
 | 
					    request: types.TextDocumentPositionParams,
 | 
				
			||||||
) Error!?types.Location {
 | 
					) Error!?types.Definition {
 | 
				
			||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2372,7 +2445,7 @@ fn gotoDefinitionHandler(
 | 
				
			|||||||
fn gotoDeclarationHandler(
 | 
					fn gotoDeclarationHandler(
 | 
				
			||||||
    server: *Server,
 | 
					    server: *Server,
 | 
				
			||||||
    request: types.TextDocumentPositionParams,
 | 
					    request: types.TextDocumentPositionParams,
 | 
				
			||||||
) Error!?types.Location {
 | 
					) Error!?types.Definition {
 | 
				
			||||||
    const tracy_zone = tracy.trace(@src());
 | 
					    const tracy_zone = tracy.trace(@src());
 | 
				
			||||||
    defer tracy_zone.end();
 | 
					    defer tracy_zone.end();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2553,9 +2626,17 @@ pub fn generalReferencesHandler(server: *Server, request: GeneralReferencesReque
 | 
				
			|||||||
    const source_index = offsets.positionToIndex(handle.text, request.position(), server.offset_encoding);
 | 
					    const source_index = offsets.positionToIndex(handle.text, request.position(), server.offset_encoding);
 | 
				
			||||||
    const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.text, source_index, true);
 | 
					    const pos_context = try analysis.getPositionContext(server.arena.allocator(), handle.text, source_index, true);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // TODO: Make this work with branching types
 | 
				
			||||||
    const decl = switch (pos_context) {
 | 
					    const decl = switch (pos_context) {
 | 
				
			||||||
        .var_access => try server.getSymbolGlobal(source_index, handle),
 | 
					        .var_access => try server.getSymbolGlobal(source_index, handle),
 | 
				
			||||||
        .field_access => |range| try server.getSymbolFieldAccess(handle, source_index, range),
 | 
					        .field_access => |range| z: {
 | 
				
			||||||
 | 
					            const a = try server.getSymbolFieldAccesses(handle, source_index, range);
 | 
				
			||||||
 | 
					            if (a) |b| {
 | 
				
			||||||
 | 
					                if (b.len != 0) break :z b[0];
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            break :z null;
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        .label => try getLabelGlobal(source_index, handle),
 | 
					        .label => try getLabelGlobal(source_index, handle),
 | 
				
			||||||
        else => null,
 | 
					        else => null,
 | 
				
			||||||
    } orelse return null;
 | 
					    } orelse return null;
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										286
									
								
								src/analysis.zig
									
									
									
									
									
								
							
							
						
						
									
										286
									
								
								src/analysis.zig
									
									
									
									
									
								
							@ -186,7 +186,7 @@ pub fn getFunctionSnippet(allocator: std.mem.Allocator, tree: Ast, func: Ast.ful
 | 
				
			|||||||
    return buffer.toOwnedSlice(allocator);
 | 
					    return buffer.toOwnedSlice(allocator);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn hasSelfParam(document_store: *DocumentStore, handle: *const DocumentStore.Handle, func: Ast.full.FnProto) !bool {
 | 
					pub fn hasSelfParam(arena: std.mem.Allocator, document_store: *DocumentStore, handle: *const DocumentStore.Handle, func: Ast.full.FnProto) !bool {
 | 
				
			||||||
    // Non-decl prototypes cannot have a self parameter.
 | 
					    // Non-decl prototypes cannot have a self parameter.
 | 
				
			||||||
    if (func.name_token == null) return false;
 | 
					    if (func.name_token == null) return false;
 | 
				
			||||||
    if (func.ast.params.len == 0) return false;
 | 
					    if (func.ast.params.len == 0) return false;
 | 
				
			||||||
@ -199,7 +199,7 @@ pub fn hasSelfParam(document_store: *DocumentStore, handle: *const DocumentStore
 | 
				
			|||||||
    const token_starts = tree.tokens.items(.start);
 | 
					    const token_starts = tree.tokens.items(.start);
 | 
				
			||||||
    const in_container = innermostContainer(handle, token_starts[func.ast.fn_token]);
 | 
					    const in_container = innermostContainer(handle, token_starts[func.ast.fn_token]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (try resolveTypeOfNode(document_store, .{
 | 
					    if (try resolveTypeOfNode(arena, document_store, .{
 | 
				
			||||||
        .node = param.type_expr,
 | 
					        .node = param.type_expr,
 | 
				
			||||||
        .handle = handle,
 | 
					        .handle = handle,
 | 
				
			||||||
    })) |resolved_type| {
 | 
					    })) |resolved_type| {
 | 
				
			||||||
@ -208,7 +208,7 @@ pub fn hasSelfParam(document_store: *DocumentStore, handle: *const DocumentStore
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (ast.fullPtrType(tree, param.type_expr)) |ptr_type| {
 | 
					    if (ast.fullPtrType(tree, param.type_expr)) |ptr_type| {
 | 
				
			||||||
        if (try resolveTypeOfNode(document_store, .{
 | 
					        if (try resolveTypeOfNode(arena, document_store, .{
 | 
				
			||||||
            .node = ptr_type.ast.child_type,
 | 
					            .node = ptr_type.ast.child_type,
 | 
				
			||||||
            .handle = handle,
 | 
					            .handle = handle,
 | 
				
			||||||
        })) |resolved_prefix_op| {
 | 
					        })) |resolved_prefix_op| {
 | 
				
			||||||
@ -323,7 +323,7 @@ pub fn getDeclName(tree: Ast, node: Ast.Node.Index) ?[]const u8 {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn resolveVarDeclAliasInternal(store: *DocumentStore, node_handle: NodeWithHandle, root: bool) error{OutOfMemory}!?DeclWithHandle {
 | 
					fn resolveVarDeclAliasInternal(arena: std.mem.Allocator, store: *DocumentStore, node_handle: NodeWithHandle, root: bool) error{OutOfMemory}!?DeclWithHandle {
 | 
				
			||||||
    _ = root;
 | 
					    _ = root;
 | 
				
			||||||
    const handle = node_handle.handle;
 | 
					    const handle = node_handle.handle;
 | 
				
			||||||
    const tree = handle.tree;
 | 
					    const tree = handle.tree;
 | 
				
			||||||
@ -334,6 +334,7 @@ fn resolveVarDeclAliasInternal(store: *DocumentStore, node_handle: NodeWithHandl
 | 
				
			|||||||
    if (node_tags[node_handle.node] == .identifier) {
 | 
					    if (node_tags[node_handle.node] == .identifier) {
 | 
				
			||||||
        const token = main_tokens[node_handle.node];
 | 
					        const token = main_tokens[node_handle.node];
 | 
				
			||||||
        return try lookupSymbolGlobal(
 | 
					        return try lookupSymbolGlobal(
 | 
				
			||||||
 | 
					            arena,
 | 
				
			||||||
            store,
 | 
					            store,
 | 
				
			||||||
            handle,
 | 
					            handle,
 | 
				
			||||||
            tree.tokenSlice(token),
 | 
					            tree.tokenSlice(token),
 | 
				
			||||||
@ -349,13 +350,13 @@ fn resolveVarDeclAliasInternal(store: *DocumentStore, node_handle: NodeWithHandl
 | 
				
			|||||||
            if (!std.mem.eql(u8, name, "@import") and !std.mem.eql(u8, name, "@cImport"))
 | 
					            if (!std.mem.eql(u8, name, "@import") and !std.mem.eql(u8, name, "@cImport"))
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const inner_node = (try resolveTypeOfNode(store, .{ .node = lhs, .handle = handle })) orelse return null;
 | 
					            const inner_node = (try resolveTypeOfNode(arena, store, .{ .node = lhs, .handle = handle })) orelse return null;
 | 
				
			||||||
            // assert root node
 | 
					            // assert root node
 | 
				
			||||||
            std.debug.assert(inner_node.type.data.other == 0);
 | 
					            std.debug.assert(inner_node.type.data.other == 0);
 | 
				
			||||||
            break :block NodeWithHandle{ .node = inner_node.type.data.other, .handle = inner_node.handle };
 | 
					            break :block NodeWithHandle{ .node = inner_node.type.data.other, .handle = inner_node.handle };
 | 
				
			||||||
        } else if (try resolveVarDeclAliasInternal(store, .{ .node = lhs, .handle = handle }, false)) |decl_handle| block: {
 | 
					        } else if (try resolveVarDeclAliasInternal(arena, store, .{ .node = lhs, .handle = handle }, false)) |decl_handle| block: {
 | 
				
			||||||
            if (decl_handle.decl.* != .ast_node) return null;
 | 
					            if (decl_handle.decl.* != .ast_node) return null;
 | 
				
			||||||
            const resolved = (try resolveTypeOfNode(store, .{ .node = decl_handle.decl.ast_node, .handle = decl_handle.handle })) orelse return null;
 | 
					            const resolved = (try resolveTypeOfNode(arena, store, .{ .node = decl_handle.decl.ast_node, .handle = decl_handle.handle })) orelse return null;
 | 
				
			||||||
            const resolved_node = switch (resolved.type.data) {
 | 
					            const resolved_node = switch (resolved.type.data) {
 | 
				
			||||||
                .other => |n| n,
 | 
					                .other => |n| n,
 | 
				
			||||||
                else => return null,
 | 
					                else => return null,
 | 
				
			||||||
@ -364,7 +365,7 @@ fn resolveVarDeclAliasInternal(store: *DocumentStore, node_handle: NodeWithHandl
 | 
				
			|||||||
            break :block NodeWithHandle{ .node = resolved_node, .handle = resolved.handle };
 | 
					            break :block NodeWithHandle{ .node = resolved_node, .handle = resolved.handle };
 | 
				
			||||||
        } else return null;
 | 
					        } else return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return try lookupSymbolContainer(store, container_node, tree.tokenSlice(datas[node_handle.node].rhs), false);
 | 
					        return try lookupSymbolContainer(arena, store, container_node, tree.tokenSlice(datas[node_handle.node].rhs), false);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -375,7 +376,7 @@ fn resolveVarDeclAliasInternal(store: *DocumentStore, node_handle: NodeWithHandl
 | 
				
			|||||||
/// const decl = @import("decl-file.zig").decl;
 | 
					/// const decl = @import("decl-file.zig").decl;
 | 
				
			||||||
/// const other = decl.middle.other;
 | 
					/// const other = decl.middle.other;
 | 
				
			||||||
///```
 | 
					///```
 | 
				
			||||||
pub fn resolveVarDeclAlias(store: *DocumentStore, decl_handle: NodeWithHandle) !?DeclWithHandle {
 | 
					pub fn resolveVarDeclAlias(arena: std.mem.Allocator, store: *DocumentStore, decl_handle: NodeWithHandle) !?DeclWithHandle {
 | 
				
			||||||
    const decl = decl_handle.node;
 | 
					    const decl = decl_handle.node;
 | 
				
			||||||
    const handle = decl_handle.handle;
 | 
					    const handle = decl_handle.handle;
 | 
				
			||||||
    const tree = handle.tree;
 | 
					    const tree = handle.tree;
 | 
				
			||||||
@ -392,7 +393,7 @@ pub fn resolveVarDeclAlias(store: *DocumentStore, decl_handle: NodeWithHandle) !
 | 
				
			|||||||
            if (!std.mem.eql(u8, tree.tokenSlice(var_decl.ast.mut_token + 1), name))
 | 
					            if (!std.mem.eql(u8, tree.tokenSlice(var_decl.ast.mut_token + 1), name))
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return try resolveVarDeclAliasInternal(store, .{ .node = base_exp, .handle = handle }, true);
 | 
					            return try resolveVarDeclAliasInternal(arena, store, .{ .node = base_exp, .handle = handle }, true);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -440,7 +441,7 @@ fn findReturnStatement(tree: Ast, fn_decl: Ast.full.FnProto, body: Ast.Node.Inde
 | 
				
			|||||||
    return findReturnStatementInternal(tree, fn_decl, body, &already_found);
 | 
					    return findReturnStatementInternal(tree, fn_decl, body, &already_found);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn resolveReturnType(store: *DocumentStore, fn_decl: Ast.full.FnProto, handle: *const DocumentStore.Handle, bound_type_params: *BoundTypeParams, fn_body: ?Ast.Node.Index) !?TypeWithHandle {
 | 
					pub fn resolveReturnType(arena: std.mem.Allocator, store: *DocumentStore, fn_decl: Ast.full.FnProto, handle: *const DocumentStore.Handle, bound_type_params: *BoundTypeParams, fn_body: ?Ast.Node.Index) !?TypeWithHandle {
 | 
				
			||||||
    const tree = handle.tree;
 | 
					    const tree = handle.tree;
 | 
				
			||||||
    if (isTypeFunction(tree, fn_decl) and fn_body != null) {
 | 
					    if (isTypeFunction(tree, fn_decl) and fn_body != null) {
 | 
				
			||||||
        // If this is a type function and it only contains a single return statement that returns
 | 
					        // If this is a type function and it only contains a single return statement that returns
 | 
				
			||||||
@ -448,7 +449,7 @@ pub fn resolveReturnType(store: *DocumentStore, fn_decl: Ast.full.FnProto, handl
 | 
				
			|||||||
        const ret = findReturnStatement(tree, fn_decl, fn_body.?) orelse return null;
 | 
					        const ret = findReturnStatement(tree, fn_decl, fn_body.?) orelse return null;
 | 
				
			||||||
        const data = tree.nodes.items(.data)[ret];
 | 
					        const data = tree.nodes.items(.data)[ret];
 | 
				
			||||||
        if (data.lhs != 0) {
 | 
					        if (data.lhs != 0) {
 | 
				
			||||||
            return try resolveTypeOfNodeInternal(store, .{
 | 
					            return try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                .node = data.lhs,
 | 
					                .node = data.lhs,
 | 
				
			||||||
                .handle = handle,
 | 
					                .handle = handle,
 | 
				
			||||||
            }, bound_type_params);
 | 
					            }, bound_type_params);
 | 
				
			||||||
@ -460,7 +461,7 @@ pub fn resolveReturnType(store: *DocumentStore, fn_decl: Ast.full.FnProto, handl
 | 
				
			|||||||
    if (fn_decl.ast.return_type == 0) return null;
 | 
					    if (fn_decl.ast.return_type == 0) return null;
 | 
				
			||||||
    const return_type = fn_decl.ast.return_type;
 | 
					    const return_type = fn_decl.ast.return_type;
 | 
				
			||||||
    const ret = .{ .node = return_type, .handle = handle };
 | 
					    const ret = .{ .node = return_type, .handle = handle };
 | 
				
			||||||
    const child_type = (try resolveTypeOfNodeInternal(store, ret, bound_type_params)) orelse
 | 
					    const child_type = (try resolveTypeOfNodeInternal(arena, store, ret, bound_type_params)) orelse
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const is_inferred_error = tree.tokens.items(.tag)[tree.firstToken(return_type) - 1] == .bang;
 | 
					    const is_inferred_error = tree.tokens.items(.tag)[tree.firstToken(return_type) - 1] == .bang;
 | 
				
			||||||
@ -477,14 +478,14 @@ pub fn resolveReturnType(store: *DocumentStore, fn_decl: Ast.full.FnProto, handl
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Resolves the child type of an optional type
 | 
					/// Resolves the child type of an optional type
 | 
				
			||||||
fn resolveUnwrapOptionalType(store: *DocumentStore, opt: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
					fn resolveUnwrapOptionalType(arena: std.mem.Allocator, store: *DocumentStore, opt: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
				
			||||||
    const opt_node = switch (opt.type.data) {
 | 
					    const opt_node = switch (opt.type.data) {
 | 
				
			||||||
        .other => |n| n,
 | 
					        .other => |n| n,
 | 
				
			||||||
        else => return null,
 | 
					        else => return null,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (opt.handle.tree.nodes.items(.tag)[opt_node] == .optional_type) {
 | 
					    if (opt.handle.tree.nodes.items(.tag)[opt_node] == .optional_type) {
 | 
				
			||||||
        return ((try resolveTypeOfNodeInternal(store, .{
 | 
					        return ((try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
            .node = opt.handle.tree.nodes.items(.data)[opt_node].lhs,
 | 
					            .node = opt.handle.tree.nodes.items(.data)[opt_node].lhs,
 | 
				
			||||||
            .handle = opt.handle,
 | 
					            .handle = opt.handle,
 | 
				
			||||||
        }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
					        }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
				
			||||||
@ -493,18 +494,18 @@ fn resolveUnwrapOptionalType(store: *DocumentStore, opt: TypeWithHandle, bound_t
 | 
				
			|||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn resolveUnwrapErrorType(store: *DocumentStore, rhs: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
					fn resolveUnwrapErrorType(arena: std.mem.Allocator, store: *DocumentStore, rhs: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
				
			||||||
    const rhs_node = switch (rhs.type.data) {
 | 
					    const rhs_node = switch (rhs.type.data) {
 | 
				
			||||||
        .other => |n| n,
 | 
					        .other => |n| n,
 | 
				
			||||||
        .error_union => |n| return TypeWithHandle{
 | 
					        .error_union => |n| return TypeWithHandle{
 | 
				
			||||||
            .type = .{ .data = .{ .other = n }, .is_type_val = rhs.type.is_type_val },
 | 
					            .type = .{ .data = .{ .other = n }, .is_type_val = rhs.type.is_type_val },
 | 
				
			||||||
            .handle = rhs.handle,
 | 
					            .handle = rhs.handle,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        .primitive, .slice, .pointer, .array_index, .@"comptime" => return null,
 | 
					        .primitive, .slice, .pointer, .array_index, .@"comptime", .either => return null,
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (rhs.handle.tree.nodes.items(.tag)[rhs_node] == .error_union) {
 | 
					    if (rhs.handle.tree.nodes.items(.tag)[rhs_node] == .error_union) {
 | 
				
			||||||
        return ((try resolveTypeOfNodeInternal(store, .{
 | 
					        return ((try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
            .node = rhs.handle.tree.nodes.items(.data)[rhs_node].rhs,
 | 
					            .node = rhs.handle.tree.nodes.items(.data)[rhs_node].rhs,
 | 
				
			||||||
            .handle = rhs.handle,
 | 
					            .handle = rhs.handle,
 | 
				
			||||||
        }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
					        }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
				
			||||||
@ -514,7 +515,7 @@ fn resolveUnwrapErrorType(store: *DocumentStore, rhs: TypeWithHandle, bound_type
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Resolves the child type of a deref type
 | 
					/// Resolves the child type of a deref type
 | 
				
			||||||
fn resolveDerefType(store: *DocumentStore, deref: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
					fn resolveDerefType(arena: std.mem.Allocator, store: *DocumentStore, deref: TypeWithHandle, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
				
			||||||
    const deref_node = switch (deref.type.data) {
 | 
					    const deref_node = switch (deref.type.data) {
 | 
				
			||||||
        .other => |n| n,
 | 
					        .other => |n| n,
 | 
				
			||||||
        .pointer => |n| return TypeWithHandle{
 | 
					        .pointer => |n| return TypeWithHandle{
 | 
				
			||||||
@ -533,7 +534,7 @@ fn resolveDerefType(store: *DocumentStore, deref: TypeWithHandle, bound_type_par
 | 
				
			|||||||
    if (ast.fullPtrType(tree, deref_node)) |ptr_type| {
 | 
					    if (ast.fullPtrType(tree, deref_node)) |ptr_type| {
 | 
				
			||||||
        switch (token_tag) {
 | 
					        switch (token_tag) {
 | 
				
			||||||
            .asterisk => {
 | 
					            .asterisk => {
 | 
				
			||||||
                return ((try resolveTypeOfNodeInternal(store, .{
 | 
					                return ((try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                    .node = ptr_type.ast.child_type,
 | 
					                    .node = ptr_type.ast.child_type,
 | 
				
			||||||
                    .handle = deref.handle,
 | 
					                    .handle = deref.handle,
 | 
				
			||||||
                }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
					                }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
				
			||||||
@ -546,7 +547,7 @@ fn resolveDerefType(store: *DocumentStore, deref: TypeWithHandle, bound_type_par
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Resolves slicing and array access
 | 
					/// Resolves slicing and array access
 | 
				
			||||||
fn resolveBracketAccessType(store: *DocumentStore, lhs: TypeWithHandle, rhs: enum { Single, Range }, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
					fn resolveBracketAccessType(arena: std.mem.Allocator, store: *DocumentStore, lhs: TypeWithHandle, rhs: enum { Single, Range }, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
				
			||||||
    const lhs_node = switch (lhs.type.data) {
 | 
					    const lhs_node = switch (lhs.type.data) {
 | 
				
			||||||
        .other => |n| n,
 | 
					        .other => |n| n,
 | 
				
			||||||
        else => return null,
 | 
					        else => return null,
 | 
				
			||||||
@ -559,7 +560,7 @@ fn resolveBracketAccessType(store: *DocumentStore, lhs: TypeWithHandle, rhs: enu
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    if (tag == .array_type or tag == .array_type_sentinel) {
 | 
					    if (tag == .array_type or tag == .array_type_sentinel) {
 | 
				
			||||||
        if (rhs == .Single)
 | 
					        if (rhs == .Single)
 | 
				
			||||||
            return ((try resolveTypeOfNodeInternal(store, .{
 | 
					            return ((try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                .node = data.rhs,
 | 
					                .node = data.rhs,
 | 
				
			||||||
                .handle = lhs.handle,
 | 
					                .handle = lhs.handle,
 | 
				
			||||||
            }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
					            }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
				
			||||||
@ -570,7 +571,7 @@ fn resolveBracketAccessType(store: *DocumentStore, lhs: TypeWithHandle, rhs: enu
 | 
				
			|||||||
    } else if (ast.fullPtrType(tree, lhs_node)) |ptr_type| {
 | 
					    } else if (ast.fullPtrType(tree, lhs_node)) |ptr_type| {
 | 
				
			||||||
        if (ptr_type.size == .Slice) {
 | 
					        if (ptr_type.size == .Slice) {
 | 
				
			||||||
            if (rhs == .Single) {
 | 
					            if (rhs == .Single) {
 | 
				
			||||||
                return ((try resolveTypeOfNodeInternal(store, .{
 | 
					                return ((try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                    .node = ptr_type.ast.child_type,
 | 
					                    .node = ptr_type.ast.child_type,
 | 
				
			||||||
                    .handle = lhs.handle,
 | 
					                    .handle = lhs.handle,
 | 
				
			||||||
                }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
					                }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
				
			||||||
@ -583,8 +584,8 @@ fn resolveBracketAccessType(store: *DocumentStore, lhs: TypeWithHandle, rhs: enu
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Called to remove one level of pointerness before a field access
 | 
					/// Called to remove one level of pointerness before a field access
 | 
				
			||||||
pub fn resolveFieldAccessLhsType(store: *DocumentStore, lhs: TypeWithHandle, bound_type_params: *BoundTypeParams) !TypeWithHandle {
 | 
					pub fn resolveFieldAccessLhsType(arena: std.mem.Allocator, store: *DocumentStore, lhs: TypeWithHandle, bound_type_params: *BoundTypeParams) !TypeWithHandle {
 | 
				
			||||||
    return (try resolveDerefType(store, lhs, bound_type_params)) orelse lhs;
 | 
					    return (try resolveDerefType(arena, store, lhs, bound_type_params)) orelse lhs;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub const BoundTypeParams = std.AutoHashMapUnmanaged(Ast.full.FnProto.Param, TypeWithHandle);
 | 
					pub const BoundTypeParams = std.AutoHashMapUnmanaged(Ast.full.FnProto.Param, TypeWithHandle);
 | 
				
			||||||
@ -622,7 +623,12 @@ pub fn isTypeIdent(text: []const u8) bool {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Resolves the type of a node
 | 
					/// Resolves the type of a node
 | 
				
			||||||
pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHandle, bound_type_params: *BoundTypeParams) error{OutOfMemory}!?TypeWithHandle {
 | 
					pub fn resolveTypeOfNodeInternal(
 | 
				
			||||||
 | 
					    arena: std.mem.Allocator,
 | 
				
			||||||
 | 
					    store: *DocumentStore,
 | 
				
			||||||
 | 
					    node_handle: NodeWithHandle,
 | 
				
			||||||
 | 
					    bound_type_params: *BoundTypeParams,
 | 
				
			||||||
 | 
					) error{OutOfMemory}!?TypeWithHandle {
 | 
				
			||||||
    // If we were asked to resolve this node before,
 | 
					    // If we were asked to resolve this node before,
 | 
				
			||||||
    // it is self-referential and we cannot resolve it.
 | 
					    // it is self-referential and we cannot resolve it.
 | 
				
			||||||
    for (resolve_trail.items) |i| {
 | 
					    for (resolve_trail.items) |i| {
 | 
				
			||||||
@ -651,14 +657,14 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
            const var_decl = tree.fullVarDecl(node).?;
 | 
					            const var_decl = tree.fullVarDecl(node).?;
 | 
				
			||||||
            if (var_decl.ast.type_node != 0) {
 | 
					            if (var_decl.ast.type_node != 0) {
 | 
				
			||||||
                const decl_type = .{ .node = var_decl.ast.type_node, .handle = handle };
 | 
					                const decl_type = .{ .node = var_decl.ast.type_node, .handle = handle };
 | 
				
			||||||
                if (try resolveTypeOfNodeInternal(store, decl_type, bound_type_params)) |typ|
 | 
					                if (try resolveTypeOfNodeInternal(arena, store, decl_type, bound_type_params)) |typ|
 | 
				
			||||||
                    return typ.instanceTypeVal();
 | 
					                    return typ.instanceTypeVal();
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (var_decl.ast.init_node == 0)
 | 
					            if (var_decl.ast.init_node == 0)
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const value = .{ .node = var_decl.ast.init_node, .handle = handle };
 | 
					            const value = .{ .node = var_decl.ast.init_node, .handle = handle };
 | 
				
			||||||
            return try resolveTypeOfNodeInternal(store, value, bound_type_params);
 | 
					            return try resolveTypeOfNodeInternal(arena, store, value, bound_type_params);
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        .identifier => {
 | 
					        .identifier => {
 | 
				
			||||||
            const name = offsets.nodeToSlice(tree, node);
 | 
					            const name = offsets.nodeToSlice(tree, node);
 | 
				
			||||||
@ -671,6 +677,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (try lookupSymbolGlobal(
 | 
					            if (try lookupSymbolGlobal(
 | 
				
			||||||
 | 
					                arena,
 | 
				
			||||||
                store,
 | 
					                store,
 | 
				
			||||||
                handle,
 | 
					                handle,
 | 
				
			||||||
                name,
 | 
					                name,
 | 
				
			||||||
@ -686,7 +693,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    else => {},
 | 
					                    else => {},
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return try child.resolveType(store, bound_type_params);
 | 
					                return try child.resolveType(arena, store, bound_type_params);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            return null;
 | 
					            return null;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -703,7 +710,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
            const call = tree.fullCall(¶ms, node) orelse unreachable;
 | 
					            const call = tree.fullCall(¶ms, node) orelse unreachable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const callee = .{ .node = call.ast.fn_expr, .handle = handle };
 | 
					            const callee = .{ .node = call.ast.fn_expr, .handle = handle };
 | 
				
			||||||
            const decl = (try resolveTypeOfNodeInternal(store, callee, bound_type_params)) orelse
 | 
					            const decl = (try resolveTypeOfNodeInternal(arena, store, callee, bound_type_params)) orelse
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (decl.type.is_type_val) return null;
 | 
					            if (decl.type.is_type_val) return null;
 | 
				
			||||||
@ -720,7 +727,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
                // TODO: Back-parse to extract the self argument?
 | 
					                // TODO: Back-parse to extract the self argument?
 | 
				
			||||||
                var it = fn_decl.iterate(&decl.handle.tree);
 | 
					                var it = fn_decl.iterate(&decl.handle.tree);
 | 
				
			||||||
                if (token_tags[call.ast.lparen - 2] == .period) {
 | 
					                if (token_tags[call.ast.lparen - 2] == .period) {
 | 
				
			||||||
                    if (try hasSelfParam(store, decl.handle, fn_decl)) {
 | 
					                    if (try hasSelfParam(arena, store, decl.handle, fn_decl)) {
 | 
				
			||||||
                        _ = ast.nextFnParam(&it);
 | 
					                        _ = ast.nextFnParam(&it);
 | 
				
			||||||
                        expected_params -= 1;
 | 
					                        expected_params -= 1;
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
@ -736,6 +743,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    const argument = .{ .node = call.ast.params[i], .handle = handle };
 | 
					                    const argument = .{ .node = call.ast.params[i], .handle = handle };
 | 
				
			||||||
                    const argument_type = (try resolveTypeOfNodeInternal(
 | 
					                    const argument_type = (try resolveTypeOfNodeInternal(
 | 
				
			||||||
 | 
					                        arena,
 | 
				
			||||||
                        store,
 | 
					                        store,
 | 
				
			||||||
                        argument,
 | 
					                        argument,
 | 
				
			||||||
                        bound_type_params,
 | 
					                        bound_type_params,
 | 
				
			||||||
@ -748,7 +756,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                const has_body = decl.handle.tree.nodes.items(.tag)[decl_node] == .fn_decl;
 | 
					                const has_body = decl.handle.tree.nodes.items(.tag)[decl_node] == .fn_decl;
 | 
				
			||||||
                const body = decl.handle.tree.nodes.items(.data)[decl_node].rhs;
 | 
					                const body = decl.handle.tree.nodes.items(.data)[decl_node].rhs;
 | 
				
			||||||
                if (try resolveReturnType(store, fn_decl, decl.handle, bound_type_params, if (has_body) body else null)) |ret| {
 | 
					                if (try resolveReturnType(arena, store, fn_decl, decl.handle, bound_type_params, if (has_body) body else null)) |ret| {
 | 
				
			||||||
                    return ret;
 | 
					                    return ret;
 | 
				
			||||||
                } else if (store.config.use_comptime_interpreter) {
 | 
					                } else if (store.config.use_comptime_interpreter) {
 | 
				
			||||||
                    // TODO: Better case-by-case; we just use the ComptimeInterpreter when all else fails,
 | 
					                    // TODO: Better case-by-case; we just use the ComptimeInterpreter when all else fails,
 | 
				
			||||||
@ -826,7 +834,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
        .address_of,
 | 
					        .address_of,
 | 
				
			||||||
        => {
 | 
					        => {
 | 
				
			||||||
            const base = .{ .node = datas[node].lhs, .handle = handle };
 | 
					            const base = .{ .node = datas[node].lhs, .handle = handle };
 | 
				
			||||||
            const base_type = (try resolveTypeOfNodeInternal(store, base, bound_type_params)) orelse
 | 
					            const base_type = (try resolveTypeOfNodeInternal(arena, store, base, bound_type_params)) orelse
 | 
				
			||||||
                return null;
 | 
					                return null;
 | 
				
			||||||
            return switch (node_tags[node]) {
 | 
					            return switch (node_tags[node]) {
 | 
				
			||||||
                .@"comptime",
 | 
					                .@"comptime",
 | 
				
			||||||
@ -844,13 +852,13 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
                .slice,
 | 
					                .slice,
 | 
				
			||||||
                .slice_sentinel,
 | 
					                .slice_sentinel,
 | 
				
			||||||
                .slice_open,
 | 
					                .slice_open,
 | 
				
			||||||
                => try resolveBracketAccessType(store, base_type, .Range, bound_type_params),
 | 
					                => try resolveBracketAccessType(arena, store, base_type, .Range, bound_type_params),
 | 
				
			||||||
                .deref => try resolveDerefType(store, base_type, bound_type_params),
 | 
					                .deref => try resolveDerefType(arena, store, base_type, bound_type_params),
 | 
				
			||||||
                .unwrap_optional => try resolveUnwrapOptionalType(store, base_type, bound_type_params),
 | 
					                .unwrap_optional => try resolveUnwrapOptionalType(arena, store, base_type, bound_type_params),
 | 
				
			||||||
                .array_access => try resolveBracketAccessType(store, base_type, .Single, bound_type_params),
 | 
					                .array_access => try resolveBracketAccessType(arena, store, base_type, .Single, bound_type_params),
 | 
				
			||||||
                .@"orelse" => try resolveUnwrapOptionalType(store, base_type, bound_type_params),
 | 
					                .@"orelse" => try resolveUnwrapOptionalType(arena, store, base_type, bound_type_params),
 | 
				
			||||||
                .@"catch" => try resolveUnwrapErrorType(store, base_type, bound_type_params),
 | 
					                .@"catch" => try resolveUnwrapErrorType(arena, store, base_type, bound_type_params),
 | 
				
			||||||
                .@"try" => try resolveUnwrapErrorType(store, base_type, bound_type_params),
 | 
					                .@"try" => try resolveUnwrapErrorType(arena, store, base_type, bound_type_params),
 | 
				
			||||||
                .address_of => {
 | 
					                .address_of => {
 | 
				
			||||||
                    const lhs_node = switch (base_type.type.data) {
 | 
					                    const lhs_node = switch (base_type.type.data) {
 | 
				
			||||||
                        .other => |n| n,
 | 
					                        .other => |n| n,
 | 
				
			||||||
@ -869,8 +877,9 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            // If we are accessing a pointer type, remove one pointerness level :)
 | 
					            // If we are accessing a pointer type, remove one pointerness level :)
 | 
				
			||||||
            const left_type = try resolveFieldAccessLhsType(
 | 
					            const left_type = try resolveFieldAccessLhsType(
 | 
				
			||||||
 | 
					                arena,
 | 
				
			||||||
                store,
 | 
					                store,
 | 
				
			||||||
                (try resolveTypeOfNodeInternal(store, .{
 | 
					                (try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                    .node = datas[node].lhs,
 | 
					                    .node = datas[node].lhs,
 | 
				
			||||||
                    .handle = handle,
 | 
					                    .handle = handle,
 | 
				
			||||||
                }, bound_type_params)) orelse return null,
 | 
					                }, bound_type_params)) orelse return null,
 | 
				
			||||||
@ -883,12 +892,13 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
            };
 | 
					            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (try lookupSymbolContainer(
 | 
					            if (try lookupSymbolContainer(
 | 
				
			||||||
 | 
					                arena,
 | 
				
			||||||
                store,
 | 
					                store,
 | 
				
			||||||
                .{ .node = left_type_node, .handle = left_type.handle },
 | 
					                .{ .node = left_type_node, .handle = left_type.handle },
 | 
				
			||||||
                tree.tokenSlice(datas[node].rhs),
 | 
					                tree.tokenSlice(datas[node].rhs),
 | 
				
			||||||
                !left_type.type.is_type_val,
 | 
					                !left_type.type.is_type_val,
 | 
				
			||||||
            )) |child| {
 | 
					            )) |child| {
 | 
				
			||||||
                return try child.resolveType(store, bound_type_params);
 | 
					                return try child.resolveType(arena, store, bound_type_params);
 | 
				
			||||||
            } else return null;
 | 
					            } else return null;
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        .array_type,
 | 
					        .array_type,
 | 
				
			||||||
@ -942,7 +952,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
            if (cast_map.has(call_name)) {
 | 
					            if (cast_map.has(call_name)) {
 | 
				
			||||||
                if (params.len < 1) return null;
 | 
					                if (params.len < 1) return null;
 | 
				
			||||||
                return ((try resolveTypeOfNodeInternal(store, .{
 | 
					                return ((try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                    .node = params[0],
 | 
					                    .node = params[0],
 | 
				
			||||||
                    .handle = handle,
 | 
					                    .handle = handle,
 | 
				
			||||||
                }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
					                }, bound_type_params)) orelse return null).instanceTypeVal();
 | 
				
			||||||
@ -952,7 +962,7 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
            // TODO Do peer type resolution, we just keep the first for now.
 | 
					            // TODO Do peer type resolution, we just keep the first for now.
 | 
				
			||||||
            if (std.mem.eql(u8, call_name, "@TypeOf")) {
 | 
					            if (std.mem.eql(u8, call_name, "@TypeOf")) {
 | 
				
			||||||
                if (params.len < 1) return null;
 | 
					                if (params.len < 1) return null;
 | 
				
			||||||
                var resolved_type = (try resolveTypeOfNodeInternal(store, .{
 | 
					                var resolved_type = (try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                    .node = params[0],
 | 
					                    .node = params[0],
 | 
				
			||||||
                    .handle = handle,
 | 
					                    .handle = handle,
 | 
				
			||||||
                }, bound_type_params)) orelse return null;
 | 
					                }, bound_type_params)) orelse return null;
 | 
				
			||||||
@ -1033,6 +1043,50 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
            .type = .{ .data = .{ .other = node }, .is_type_val = false },
 | 
					            .type = .{ .data = .{ .other = node }, .is_type_val = false },
 | 
				
			||||||
            .handle = handle,
 | 
					            .handle = handle,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
 | 
					        .@"if", .if_simple => {
 | 
				
			||||||
 | 
					            const if_node = ast.fullIf(tree, node).?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // TODO: Fix allocator need
 | 
				
			||||||
 | 
					            var either = std.ArrayList(Type.EitherEntry).init(arena);
 | 
				
			||||||
 | 
					            if (try resolveTypeOfNodeInternal(arena, store, .{ .handle = handle, .node = if_node.ast.then_expr }, bound_type_params)) |t|
 | 
				
			||||||
 | 
					                try either.append(.{ .type_with_handle = t, .descriptor = tree.getNodeSource(if_node.ast.cond_expr) });
 | 
				
			||||||
 | 
					            if (try resolveTypeOfNodeInternal(arena, store, .{ .handle = handle, .node = if_node.ast.else_expr }, bound_type_params)) |t|
 | 
				
			||||||
 | 
					                try either.append(.{ .type_with_handle = t, .descriptor = try std.fmt.allocPrint(arena, "!({s})", .{tree.getNodeSource(if_node.ast.cond_expr)}) });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return TypeWithHandle{
 | 
				
			||||||
 | 
					                .type = .{ .data = .{ .either = try either.toOwnedSlice() }, .is_type_val = false },
 | 
				
			||||||
 | 
					                .handle = handle,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        .@"switch",
 | 
				
			||||||
 | 
					        .switch_comma,
 | 
				
			||||||
 | 
					        => {
 | 
				
			||||||
 | 
					            const extra = tree.extraData(datas[node].rhs, Ast.Node.SubRange);
 | 
				
			||||||
 | 
					            const cases = tree.extra_data[extra.start..extra.end];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            var either = std.ArrayList(Type.EitherEntry).init(arena);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            for (cases) |case| {
 | 
				
			||||||
 | 
					                const switch_case = tree.fullSwitchCase(case).?;
 | 
				
			||||||
 | 
					                var descriptor = std.ArrayList(u8).init(arena);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                for (switch_case.ast.values, 0..) |vals, index| {
 | 
				
			||||||
 | 
					                    try descriptor.appendSlice(tree.getNodeSource(vals));
 | 
				
			||||||
 | 
					                    if (index != switch_case.ast.values.len - 1) try descriptor.appendSlice(", ");
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                if (try resolveTypeOfNodeInternal(arena, store, .{ .handle = handle, .node = switch_case.ast.target_expr }, bound_type_params)) |t|
 | 
				
			||||||
 | 
					                    try either.append(.{
 | 
				
			||||||
 | 
					                        .type_with_handle = t,
 | 
				
			||||||
 | 
					                        .descriptor = try descriptor.toOwnedSlice(),
 | 
				
			||||||
 | 
					                    });
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return TypeWithHandle{
 | 
				
			||||||
 | 
					                .type = .{ .data = .{ .either = try either.toOwnedSlice() }, .is_type_val = false },
 | 
				
			||||||
 | 
					                .handle = handle,
 | 
				
			||||||
 | 
					            };
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
        else => {},
 | 
					        else => {},
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
@ -1041,12 +1095,18 @@ pub fn resolveTypeOfNodeInternal(store: *DocumentStore, node_handle: NodeWithHan
 | 
				
			|||||||
// TODO Reorganize this file, perhaps split into a couple as well
 | 
					// TODO Reorganize this file, perhaps split into a couple as well
 | 
				
			||||||
// TODO Make this better, nested levels of type vals
 | 
					// TODO Make this better, nested levels of type vals
 | 
				
			||||||
pub const Type = struct {
 | 
					pub const Type = struct {
 | 
				
			||||||
 | 
					    pub const EitherEntry = struct {
 | 
				
			||||||
 | 
					        type_with_handle: TypeWithHandle,
 | 
				
			||||||
 | 
					        descriptor: []const u8,
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    data: union(enum) {
 | 
					    data: union(enum) {
 | 
				
			||||||
        pointer: Ast.Node.Index,
 | 
					        pointer: Ast.Node.Index,
 | 
				
			||||||
        slice: Ast.Node.Index,
 | 
					        slice: Ast.Node.Index,
 | 
				
			||||||
        error_union: Ast.Node.Index,
 | 
					        error_union: Ast.Node.Index,
 | 
				
			||||||
        other: Ast.Node.Index,
 | 
					        other: Ast.Node.Index,
 | 
				
			||||||
        primitive: Ast.Node.Index,
 | 
					        primitive: Ast.Node.Index,
 | 
				
			||||||
 | 
					        either: []const EitherEntry,
 | 
				
			||||||
        array_index,
 | 
					        array_index,
 | 
				
			||||||
        @"comptime": struct {
 | 
					        @"comptime": struct {
 | 
				
			||||||
            interpreter: *ComptimeInterpreter,
 | 
					            interpreter: *ComptimeInterpreter,
 | 
				
			||||||
@ -1071,6 +1131,20 @@ pub const TypeWithHandle = struct {
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Resolves possible types of a type (single for all except array_index and either)
 | 
				
			||||||
 | 
					    pub fn getAllTypesWithHandles(ty: TypeWithHandle, arena: std.mem.Allocator) ![]const TypeWithHandle {
 | 
				
			||||||
 | 
					        var all_types = std.ArrayListUnmanaged(TypeWithHandle){};
 | 
				
			||||||
 | 
					        try ty.getAllTypesWithHandlesArrayList(arena, &all_types);
 | 
				
			||||||
 | 
					        return try all_types.toOwnedSlice(arena);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn getAllTypesWithHandlesArrayList(ty: TypeWithHandle, arena: std.mem.Allocator, all_types: *std.ArrayListUnmanaged(TypeWithHandle)) !void {
 | 
				
			||||||
 | 
					        switch (ty.type.data) {
 | 
				
			||||||
 | 
					            .either => |e| for (e) |i| try i.type_with_handle.getAllTypesWithHandlesArrayList(arena, all_types),
 | 
				
			||||||
 | 
					            else => try all_types.append(arena, ty),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn instanceTypeVal(self: TypeWithHandle) ?TypeWithHandle {
 | 
					    fn instanceTypeVal(self: TypeWithHandle) ?TypeWithHandle {
 | 
				
			||||||
        if (!self.type.is_type_val) return null;
 | 
					        if (!self.type.is_type_val) return null;
 | 
				
			||||||
        return TypeWithHandle{
 | 
					        return TypeWithHandle{
 | 
				
			||||||
@ -1166,10 +1240,14 @@ pub const TypeWithHandle = struct {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn resolveTypeOfNode(store: *DocumentStore, node_handle: NodeWithHandle) error{OutOfMemory}!?TypeWithHandle {
 | 
					pub fn resolveTypeOfNode(
 | 
				
			||||||
 | 
					    arena: std.mem.Allocator,
 | 
				
			||||||
 | 
					    store: *DocumentStore,
 | 
				
			||||||
 | 
					    node_handle: NodeWithHandle,
 | 
				
			||||||
 | 
					) error{OutOfMemory}!?TypeWithHandle {
 | 
				
			||||||
    var bound_type_params = BoundTypeParams{};
 | 
					    var bound_type_params = BoundTypeParams{};
 | 
				
			||||||
    defer bound_type_params.deinit(store.allocator);
 | 
					    defer bound_type_params.deinit(store.allocator);
 | 
				
			||||||
    return resolveTypeOfNodeInternal(store, node_handle, &bound_type_params);
 | 
					    return resolveTypeOfNodeInternal(arena, store, node_handle, &bound_type_params);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Collects all `@import`'s we can find into a slice of import paths (without quotes).
 | 
					/// Collects all `@import`'s we can find into a slice of import paths (without quotes).
 | 
				
			||||||
@ -1235,7 +1313,7 @@ pub const FieldAccessReturn = struct {
 | 
				
			|||||||
    unwrapped: ?TypeWithHandle = null,
 | 
					    unwrapped: ?TypeWithHandle = null,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn getFieldAccessType(store: *DocumentStore, handle: *const DocumentStore.Handle, source_index: usize, tokenizer: *std.zig.Tokenizer) !?FieldAccessReturn {
 | 
					pub fn getFieldAccessType(arena: std.mem.Allocator, store: *DocumentStore, handle: *const DocumentStore.Handle, source_index: usize, tokenizer: *std.zig.Tokenizer) !?FieldAccessReturn {
 | 
				
			||||||
    var current_type: ?TypeWithHandle = null;
 | 
					    var current_type: ?TypeWithHandle = null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var bound_type_params = BoundTypeParams{};
 | 
					    var bound_type_params = BoundTypeParams{};
 | 
				
			||||||
@ -1246,17 +1324,18 @@ pub fn getFieldAccessType(store: *DocumentStore, handle: *const DocumentStore.Ha
 | 
				
			|||||||
        switch (tok.tag) {
 | 
					        switch (tok.tag) {
 | 
				
			||||||
            .eof => return FieldAccessReturn{
 | 
					            .eof => return FieldAccessReturn{
 | 
				
			||||||
                .original = current_type orelse return null,
 | 
					                .original = current_type orelse return null,
 | 
				
			||||||
                .unwrapped = try resolveDerefType(store, current_type orelse return null, &bound_type_params),
 | 
					                .unwrapped = try resolveDerefType(arena, store, current_type orelse return null, &bound_type_params),
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            .identifier => {
 | 
					            .identifier => {
 | 
				
			||||||
                const ct_handle = if (current_type) |c| c.handle else handle;
 | 
					                const ct_handle = if (current_type) |c| c.handle else handle;
 | 
				
			||||||
                if (try lookupSymbolGlobal(
 | 
					                if (try lookupSymbolGlobal(
 | 
				
			||||||
 | 
					                    arena,
 | 
				
			||||||
                    store,
 | 
					                    store,
 | 
				
			||||||
                    ct_handle,
 | 
					                    ct_handle,
 | 
				
			||||||
                    tokenizer.buffer[tok.loc.start..tok.loc.end],
 | 
					                    tokenizer.buffer[tok.loc.start..tok.loc.end],
 | 
				
			||||||
                    source_index,
 | 
					                    source_index,
 | 
				
			||||||
                )) |child| {
 | 
					                )) |child| {
 | 
				
			||||||
                    current_type = (try child.resolveType(store, &bound_type_params)) orelse return null;
 | 
					                    current_type = (try child.resolveType(arena, store, &bound_type_params)) orelse return null;
 | 
				
			||||||
                } else return null;
 | 
					                } else return null;
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            .period => {
 | 
					            .period => {
 | 
				
			||||||
@ -1268,7 +1347,7 @@ pub fn getFieldAccessType(store: *DocumentStore, handle: *const DocumentStore.Ha
 | 
				
			|||||||
                            if (ct.isFunc()) return null;
 | 
					                            if (ct.isFunc()) return null;
 | 
				
			||||||
                            return FieldAccessReturn{
 | 
					                            return FieldAccessReturn{
 | 
				
			||||||
                                .original = ct,
 | 
					                                .original = ct,
 | 
				
			||||||
                                .unwrapped = try resolveDerefType(store, ct, &bound_type_params),
 | 
					                                .unwrapped = try resolveDerefType(arena, store, ct, &bound_type_params),
 | 
				
			||||||
                            };
 | 
					                            };
 | 
				
			||||||
                        } else {
 | 
					                        } else {
 | 
				
			||||||
                            return null;
 | 
					                            return null;
 | 
				
			||||||
@ -1279,34 +1358,46 @@ pub fn getFieldAccessType(store: *DocumentStore, handle: *const DocumentStore.Ha
 | 
				
			|||||||
                            if (current_type) |ct| {
 | 
					                            if (current_type) |ct| {
 | 
				
			||||||
                                return FieldAccessReturn{
 | 
					                                return FieldAccessReturn{
 | 
				
			||||||
                                    .original = ct,
 | 
					                                    .original = ct,
 | 
				
			||||||
                                    .unwrapped = try resolveDerefType(store, ct, &bound_type_params),
 | 
					                                    .unwrapped = try resolveDerefType(arena, store, ct, &bound_type_params),
 | 
				
			||||||
                                };
 | 
					                                };
 | 
				
			||||||
                            } else {
 | 
					                            } else {
 | 
				
			||||||
                                return null;
 | 
					                                return null;
 | 
				
			||||||
                            }
 | 
					                            }
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        current_type = try resolveFieldAccessLhsType(store, current_type orelse return null, &bound_type_params);
 | 
					                        current_type = try resolveFieldAccessLhsType(arena, store, current_type orelse return null, &bound_type_params);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        const current_type_node = switch (current_type.?.type.data) {
 | 
					                        const current_type_nodes = try current_type.?.getAllTypesWithHandles(arena);
 | 
				
			||||||
                            .other => |n| n,
 | 
					 | 
				
			||||||
                            else => return null,
 | 
					 | 
				
			||||||
                        };
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
                        if (try lookupSymbolContainer(
 | 
					                        // TODO: Return all options instead of first valid one
 | 
				
			||||||
                            store,
 | 
					                        // (this would require a huge rewrite and im lazy)
 | 
				
			||||||
                            .{ .node = current_type_node, .handle = current_type.?.handle },
 | 
					                        for (current_type_nodes) |ty| {
 | 
				
			||||||
                            tokenizer.buffer[after_period.loc.start..after_period.loc.end],
 | 
					                            const current_type_node = switch (ty.type.data) {
 | 
				
			||||||
                            !current_type.?.type.is_type_val,
 | 
					                                .other => |n| n,
 | 
				
			||||||
                        )) |child| {
 | 
					                                else => continue,
 | 
				
			||||||
                            current_type.? = (try child.resolveType(
 | 
					                            };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                            if (try lookupSymbolContainer(
 | 
				
			||||||
 | 
					                                arena,
 | 
				
			||||||
                                store,
 | 
					                                store,
 | 
				
			||||||
                                &bound_type_params,
 | 
					                                .{ .node = current_type_node, .handle = ty.handle },
 | 
				
			||||||
                            )) orelse return null;
 | 
					                                tokenizer.buffer[after_period.loc.start..after_period.loc.end],
 | 
				
			||||||
                        } else return null;
 | 
					                                !current_type.?.type.is_type_val,
 | 
				
			||||||
 | 
					                            )) |child| {
 | 
				
			||||||
 | 
					                                current_type.? = (try child.resolveType(
 | 
				
			||||||
 | 
					                                    arena,
 | 
				
			||||||
 | 
					                                    store,
 | 
				
			||||||
 | 
					                                    &bound_type_params,
 | 
				
			||||||
 | 
					                                )) orelse continue;
 | 
				
			||||||
 | 
					                                break;
 | 
				
			||||||
 | 
					                            } else continue;
 | 
				
			||||||
 | 
					                        } else {
 | 
				
			||||||
 | 
					                            return null;
 | 
				
			||||||
 | 
					                        }
 | 
				
			||||||
                    },
 | 
					                    },
 | 
				
			||||||
                    .question_mark => {
 | 
					                    .question_mark => {
 | 
				
			||||||
                        current_type = (try resolveUnwrapOptionalType(
 | 
					                        current_type = (try resolveUnwrapOptionalType(
 | 
				
			||||||
 | 
					                            arena,
 | 
				
			||||||
                            store,
 | 
					                            store,
 | 
				
			||||||
                            current_type orelse return null,
 | 
					                            current_type orelse return null,
 | 
				
			||||||
                            &bound_type_params,
 | 
					                            &bound_type_params,
 | 
				
			||||||
@ -1320,6 +1411,7 @@ pub fn getFieldAccessType(store: *DocumentStore, handle: *const DocumentStore.Ha
 | 
				
			|||||||
            },
 | 
					            },
 | 
				
			||||||
            .period_asterisk => {
 | 
					            .period_asterisk => {
 | 
				
			||||||
                current_type = (try resolveDerefType(
 | 
					                current_type = (try resolveDerefType(
 | 
				
			||||||
 | 
					                    arena,
 | 
				
			||||||
                    store,
 | 
					                    store,
 | 
				
			||||||
                    current_type orelse return null,
 | 
					                    current_type orelse return null,
 | 
				
			||||||
                    &bound_type_params,
 | 
					                    &bound_type_params,
 | 
				
			||||||
@ -1346,7 +1438,7 @@ pub fn getFieldAccessType(store: *DocumentStore, handle: *const DocumentStore.Ha
 | 
				
			|||||||
                    const body = cur_tree.nodes.items(.data)[current_type_node].rhs;
 | 
					                    const body = cur_tree.nodes.items(.data)[current_type_node].rhs;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    // TODO Actually bind params here when calling functions instead of just skipping args.
 | 
					                    // TODO Actually bind params here when calling functions instead of just skipping args.
 | 
				
			||||||
                    if (try resolveReturnType(store, func, current_type.?.handle, &bound_type_params, if (has_body) body else null)) |ret| {
 | 
					                    if (try resolveReturnType(arena, store, func, current_type.?.handle, &bound_type_params, if (has_body) body else null)) |ret| {
 | 
				
			||||||
                        current_type = ret;
 | 
					                        current_type = ret;
 | 
				
			||||||
                        // Skip to the right paren
 | 
					                        // Skip to the right paren
 | 
				
			||||||
                        var paren_count: usize = 1;
 | 
					                        var paren_count: usize = 1;
 | 
				
			||||||
@ -1377,7 +1469,7 @@ pub fn getFieldAccessType(store: *DocumentStore, handle: *const DocumentStore.Ha
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                } else return null;
 | 
					                } else return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                current_type = (try resolveBracketAccessType(store, current_type orelse return null, if (is_range) .Range else .Single, &bound_type_params)) orelse return null;
 | 
					                current_type = (try resolveBracketAccessType(arena, store, current_type orelse return null, if (is_range) .Range else .Single, &bound_type_params)) orelse return null;
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            else => {
 | 
					            else => {
 | 
				
			||||||
                log.debug("Unimplemented token: {}", .{tok.tag});
 | 
					                log.debug("Unimplemented token: {}", .{tok.tag});
 | 
				
			||||||
@ -1389,7 +1481,7 @@ pub fn getFieldAccessType(store: *DocumentStore, handle: *const DocumentStore.Ha
 | 
				
			|||||||
    if (current_type) |ct| {
 | 
					    if (current_type) |ct| {
 | 
				
			||||||
        return FieldAccessReturn{
 | 
					        return FieldAccessReturn{
 | 
				
			||||||
            .original = ct,
 | 
					            .original = ct,
 | 
				
			||||||
            .unwrapped = try resolveDerefType(store, ct, &bound_type_params),
 | 
					            .unwrapped = try resolveDerefType(arena, store, ct, &bound_type_params),
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        return null;
 | 
					        return null;
 | 
				
			||||||
@ -1991,12 +2083,13 @@ pub const DeclWithHandle = struct {
 | 
				
			|||||||
        };
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn resolveType(self: DeclWithHandle, store: *DocumentStore, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
					    pub fn resolveType(self: DeclWithHandle, arena: std.mem.Allocator, store: *DocumentStore, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
 | 
				
			||||||
        const tree = self.handle.tree;
 | 
					        const tree = self.handle.tree;
 | 
				
			||||||
        const node_tags = tree.nodes.items(.tag);
 | 
					        const node_tags = tree.nodes.items(.tag);
 | 
				
			||||||
        const main_tokens = tree.nodes.items(.main_token);
 | 
					        const main_tokens = tree.nodes.items(.main_token);
 | 
				
			||||||
        return switch (self.decl.*) {
 | 
					        return switch (self.decl.*) {
 | 
				
			||||||
            .ast_node => |node| try resolveTypeOfNodeInternal(
 | 
					            .ast_node => |node| try resolveTypeOfNodeInternal(
 | 
				
			||||||
 | 
					                arena,
 | 
				
			||||||
                store,
 | 
					                store,
 | 
				
			||||||
                .{ .node = node, .handle = self.handle },
 | 
					                .{ .node = node, .handle = self.handle },
 | 
				
			||||||
                bound_type_params,
 | 
					                bound_type_params,
 | 
				
			||||||
@ -2016,22 +2109,25 @@ pub const DeclWithHandle = struct {
 | 
				
			|||||||
                    }
 | 
					                    }
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                return ((try resolveTypeOfNodeInternal(
 | 
					                return ((try resolveTypeOfNodeInternal(
 | 
				
			||||||
 | 
					                    arena,
 | 
				
			||||||
                    store,
 | 
					                    store,
 | 
				
			||||||
                    .{ .node = param_decl.type_expr, .handle = self.handle },
 | 
					                    .{ .node = param_decl.type_expr, .handle = self.handle },
 | 
				
			||||||
                    bound_type_params,
 | 
					                    bound_type_params,
 | 
				
			||||||
                )) orelse return null).instanceTypeVal();
 | 
					                )) orelse return null).instanceTypeVal();
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
            .pointer_payload => |pay| try resolveUnwrapOptionalType(
 | 
					            .pointer_payload => |pay| try resolveUnwrapOptionalType(
 | 
				
			||||||
 | 
					                arena,
 | 
				
			||||||
                store,
 | 
					                store,
 | 
				
			||||||
                (try resolveTypeOfNodeInternal(store, .{
 | 
					                (try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                    .node = pay.condition,
 | 
					                    .node = pay.condition,
 | 
				
			||||||
                    .handle = self.handle,
 | 
					                    .handle = self.handle,
 | 
				
			||||||
                }, bound_type_params)) orelse return null,
 | 
					                }, bound_type_params)) orelse return null,
 | 
				
			||||||
                bound_type_params,
 | 
					                bound_type_params,
 | 
				
			||||||
            ),
 | 
					            ),
 | 
				
			||||||
            .array_payload => |pay| try resolveBracketAccessType(
 | 
					            .array_payload => |pay| try resolveBracketAccessType(
 | 
				
			||||||
 | 
					                arena,
 | 
				
			||||||
                store,
 | 
					                store,
 | 
				
			||||||
                (try resolveTypeOfNodeInternal(store, .{
 | 
					                (try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                    .node = pay.array_expr,
 | 
					                    .node = pay.array_expr,
 | 
				
			||||||
                    .handle = self.handle,
 | 
					                    .handle = self.handle,
 | 
				
			||||||
                }, bound_type_params)) orelse return null,
 | 
					                }, bound_type_params)) orelse return null,
 | 
				
			||||||
@ -2046,7 +2142,7 @@ pub const DeclWithHandle = struct {
 | 
				
			|||||||
            .switch_payload => |pay| {
 | 
					            .switch_payload => |pay| {
 | 
				
			||||||
                if (pay.items.len == 0) return null;
 | 
					                if (pay.items.len == 0) return null;
 | 
				
			||||||
                // TODO Peer type resolution, we just use the first item for now.
 | 
					                // TODO Peer type resolution, we just use the first item for now.
 | 
				
			||||||
                const switch_expr_type = (try resolveTypeOfNodeInternal(store, .{
 | 
					                const switch_expr_type = (try resolveTypeOfNodeInternal(arena, store, .{
 | 
				
			||||||
                    .node = pay.switch_expr,
 | 
					                    .node = pay.switch_expr,
 | 
				
			||||||
                    .handle = self.handle,
 | 
					                    .handle = self.handle,
 | 
				
			||||||
                }, bound_type_params)) orelse return null;
 | 
					                }, bound_type_params)) orelse return null;
 | 
				
			||||||
@ -2065,6 +2161,7 @@ pub const DeclWithHandle = struct {
 | 
				
			|||||||
                        if (switch_expr_type.handle.tree.fullContainerField(node)) |container_field| {
 | 
					                        if (switch_expr_type.handle.tree.fullContainerField(node)) |container_field| {
 | 
				
			||||||
                            if (container_field.ast.type_expr != 0) {
 | 
					                            if (container_field.ast.type_expr != 0) {
 | 
				
			||||||
                                return ((try resolveTypeOfNodeInternal(
 | 
					                                return ((try resolveTypeOfNodeInternal(
 | 
				
			||||||
 | 
					                                    arena,
 | 
				
			||||||
                                    store,
 | 
					                                    store,
 | 
				
			||||||
                                    .{ .node = container_field.ast.type_expr, .handle = switch_expr_type.handle },
 | 
					                                    .{ .node = container_field.ast.type_expr, .handle = switch_expr_type.handle },
 | 
				
			||||||
                                    bound_type_params,
 | 
					                                    bound_type_params,
 | 
				
			||||||
@ -2097,7 +2194,7 @@ fn findContainerScopeIndex(container_handle: NodeWithHandle) ?usize {
 | 
				
			|||||||
    } else null;
 | 
					    } else null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn iterateSymbolsContainerInternal(store: *DocumentStore, container_handle: NodeWithHandle, orig_handle: *const DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool, use_trail: *std.ArrayList(Ast.Node.Index)) error{OutOfMemory}!void {
 | 
					fn iterateSymbolsContainerInternal(arena: std.mem.Allocator, store: *DocumentStore, container_handle: NodeWithHandle, orig_handle: *const DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool, use_trail: *std.ArrayList(Ast.Node.Index)) error{OutOfMemory}!void {
 | 
				
			||||||
    const container = container_handle.node;
 | 
					    const container = container_handle.node;
 | 
				
			||||||
    const handle = container_handle.handle;
 | 
					    const handle = container_handle.handle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2144,7 +2241,7 @@ fn iterateSymbolsContainerInternal(store: *DocumentStore, container_handle: Node
 | 
				
			|||||||
        try use_trail.append(use);
 | 
					        try use_trail.append(use);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const lhs = tree.nodes.items(.data)[use].lhs;
 | 
					        const lhs = tree.nodes.items(.data)[use].lhs;
 | 
				
			||||||
        const use_expr = (try resolveTypeOfNode(store, .{
 | 
					        const use_expr = (try resolveTypeOfNode(arena, store, .{
 | 
				
			||||||
            .node = lhs,
 | 
					            .node = lhs,
 | 
				
			||||||
            .handle = handle,
 | 
					            .handle = handle,
 | 
				
			||||||
        })) orelse continue;
 | 
					        })) orelse continue;
 | 
				
			||||||
@ -2154,6 +2251,7 @@ fn iterateSymbolsContainerInternal(store: *DocumentStore, container_handle: Node
 | 
				
			|||||||
            else => continue,
 | 
					            else => continue,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
        try iterateSymbolsContainerInternal(
 | 
					        try iterateSymbolsContainerInternal(
 | 
				
			||||||
 | 
					            arena,
 | 
				
			||||||
            store,
 | 
					            store,
 | 
				
			||||||
            .{ .node = use_expr_node, .handle = use_expr.handle },
 | 
					            .{ .node = use_expr_node, .handle = use_expr.handle },
 | 
				
			||||||
            orig_handle,
 | 
					            orig_handle,
 | 
				
			||||||
@ -2195,10 +2293,10 @@ pub fn iterateEnclosingScopes(document_scope: DocumentScope, source_index: usize
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn iterateSymbolsContainer(store: *DocumentStore, container_handle: NodeWithHandle, orig_handle: *const DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool) error{OutOfMemory}!void {
 | 
					pub fn iterateSymbolsContainer(arena: std.mem.Allocator, store: *DocumentStore, container_handle: NodeWithHandle, orig_handle: *const DocumentStore.Handle, comptime callback: anytype, context: anytype, instance_access: bool) error{OutOfMemory}!void {
 | 
				
			||||||
    var use_trail = std.ArrayList(Ast.Node.Index).init(store.allocator);
 | 
					    var use_trail = std.ArrayList(Ast.Node.Index).init(store.allocator);
 | 
				
			||||||
    defer use_trail.deinit();
 | 
					    defer use_trail.deinit();
 | 
				
			||||||
    return try iterateSymbolsContainerInternal(store, container_handle, orig_handle, callback, context, instance_access, &use_trail);
 | 
					    return try iterateSymbolsContainerInternal(arena, store, container_handle, orig_handle, callback, context, instance_access, &use_trail);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn iterateLabels(handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype) error{OutOfMemory}!void {
 | 
					pub fn iterateLabels(handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype) error{OutOfMemory}!void {
 | 
				
			||||||
@ -2217,7 +2315,7 @@ pub fn iterateLabels(handle: *const DocumentStore.Handle, source_index: usize, c
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn iterateSymbolsGlobalInternal(store: *DocumentStore, handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype, use_trail: *std.ArrayList(Ast.Node.Index)) error{OutOfMemory}!void {
 | 
					fn iterateSymbolsGlobalInternal(arena: std.mem.Allocator, store: *DocumentStore, handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype, use_trail: *std.ArrayList(Ast.Node.Index)) error{OutOfMemory}!void {
 | 
				
			||||||
    const scope_decls = handle.document_scope.scopes.items(.decls);
 | 
					    const scope_decls = handle.document_scope.scopes.items(.decls);
 | 
				
			||||||
    const scope_uses = handle.document_scope.scopes.items(.uses);
 | 
					    const scope_uses = handle.document_scope.scopes.items(.uses);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2236,6 +2334,7 @@ fn iterateSymbolsGlobalInternal(store: *DocumentStore, handle: *const DocumentSt
 | 
				
			|||||||
            try use_trail.append(use);
 | 
					            try use_trail.append(use);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const use_expr = (try resolveTypeOfNode(
 | 
					            const use_expr = (try resolveTypeOfNode(
 | 
				
			||||||
 | 
					                arena,
 | 
				
			||||||
                store,
 | 
					                store,
 | 
				
			||||||
                .{ .node = handle.tree.nodes.items(.data)[use].lhs, .handle = handle },
 | 
					                .{ .node = handle.tree.nodes.items(.data)[use].lhs, .handle = handle },
 | 
				
			||||||
            )) orelse continue;
 | 
					            )) orelse continue;
 | 
				
			||||||
@ -2244,6 +2343,7 @@ fn iterateSymbolsGlobalInternal(store: *DocumentStore, handle: *const DocumentSt
 | 
				
			|||||||
                else => continue,
 | 
					                else => continue,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            try iterateSymbolsContainerInternal(
 | 
					            try iterateSymbolsContainerInternal(
 | 
				
			||||||
 | 
					                arena,
 | 
				
			||||||
                store,
 | 
					                store,
 | 
				
			||||||
                .{ .node = use_expr_node, .handle = use_expr.handle },
 | 
					                .{ .node = use_expr_node, .handle = use_expr.handle },
 | 
				
			||||||
                handle,
 | 
					                handle,
 | 
				
			||||||
@ -2256,10 +2356,10 @@ fn iterateSymbolsGlobalInternal(store: *DocumentStore, handle: *const DocumentSt
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn iterateSymbolsGlobal(store: *DocumentStore, handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype) error{OutOfMemory}!void {
 | 
					pub fn iterateSymbolsGlobal(arena: std.mem.Allocator, store: *DocumentStore, handle: *const DocumentStore.Handle, source_index: usize, comptime callback: anytype, context: anytype) error{OutOfMemory}!void {
 | 
				
			||||||
    var use_trail = std.ArrayList(Ast.Node.Index).init(store.allocator);
 | 
					    var use_trail = std.ArrayList(Ast.Node.Index).init(store.allocator);
 | 
				
			||||||
    defer use_trail.deinit();
 | 
					    defer use_trail.deinit();
 | 
				
			||||||
    return try iterateSymbolsGlobalInternal(store, handle, source_index, callback, context, &use_trail);
 | 
					    return try iterateSymbolsGlobalInternal(arena, store, handle, source_index, callback, context, &use_trail);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn innermostBlockScopeIndex(handle: DocumentStore.Handle, source_index: usize) usize {
 | 
					pub fn innermostBlockScopeIndex(handle: DocumentStore.Handle, source_index: usize) usize {
 | 
				
			||||||
@ -2304,7 +2404,7 @@ pub fn innermostContainer(handle: *const DocumentStore.Handle, source_index: usi
 | 
				
			|||||||
    return TypeWithHandle.typeVal(.{ .node = current, .handle = handle });
 | 
					    return TypeWithHandle.typeVal(.{ .node = current, .handle = handle });
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn resolveUse(store: *DocumentStore, uses: []const Ast.Node.Index, symbol: []const u8, handle: *const DocumentStore.Handle) error{OutOfMemory}!?DeclWithHandle {
 | 
					fn resolveUse(arena: std.mem.Allocator, store: *DocumentStore, uses: []const Ast.Node.Index, symbol: []const u8, handle: *const DocumentStore.Handle) error{OutOfMemory}!?DeclWithHandle {
 | 
				
			||||||
    if (uses.len == 0) return null;
 | 
					    if (uses.len == 0) return null;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // If we were asked to resolve this symbol before,
 | 
					    // If we were asked to resolve this symbol before,
 | 
				
			||||||
@ -2318,7 +2418,7 @@ fn resolveUse(store: *DocumentStore, uses: []const Ast.Node.Index, symbol: []con
 | 
				
			|||||||
        if (handle.tree.nodes.items(.data).len <= index) continue;
 | 
					        if (handle.tree.nodes.items(.data).len <= index) continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const expr = .{ .node = handle.tree.nodes.items(.data)[index].lhs, .handle = handle };
 | 
					        const expr = .{ .node = handle.tree.nodes.items(.data)[index].lhs, .handle = handle };
 | 
				
			||||||
        const expr_type_node = (try resolveTypeOfNode(store, expr)) orelse
 | 
					        const expr_type_node = (try resolveTypeOfNode(arena, store, expr)) orelse
 | 
				
			||||||
            continue;
 | 
					            continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const expr_type = .{
 | 
					        const expr_type = .{
 | 
				
			||||||
@ -2329,7 +2429,7 @@ fn resolveUse(store: *DocumentStore, uses: []const Ast.Node.Index, symbol: []con
 | 
				
			|||||||
            .handle = expr_type_node.handle,
 | 
					            .handle = expr_type_node.handle,
 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (try lookupSymbolContainer(store, expr_type, symbol, false)) |candidate| {
 | 
					        if (try lookupSymbolContainer(arena, store, expr_type, symbol, false)) |candidate| {
 | 
				
			||||||
            if (candidate.handle == handle or candidate.isPublic()) {
 | 
					            if (candidate.handle == handle or candidate.isPublic()) {
 | 
				
			||||||
                return candidate;
 | 
					                return candidate;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@ -2338,7 +2438,11 @@ fn resolveUse(store: *DocumentStore, uses: []const Ast.Node.Index, symbol: []con
 | 
				
			|||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn lookupLabel(handle: *const DocumentStore.Handle, symbol: []const u8, source_index: usize) error{OutOfMemory}!?DeclWithHandle {
 | 
					pub fn lookupLabel(
 | 
				
			||||||
 | 
					    handle: *const DocumentStore.Handle,
 | 
				
			||||||
 | 
					    symbol: []const u8,
 | 
				
			||||||
 | 
					    source_index: usize,
 | 
				
			||||||
 | 
					) error{OutOfMemory}!?DeclWithHandle {
 | 
				
			||||||
    const scope_decls = handle.document_scope.scopes.items(.decls);
 | 
					    const scope_decls = handle.document_scope.scopes.items(.decls);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var scope_iterator = iterateEnclosingScopes(handle.document_scope, source_index);
 | 
					    var scope_iterator = iterateEnclosingScopes(handle.document_scope, source_index);
 | 
				
			||||||
@ -2357,7 +2461,7 @@ pub fn lookupLabel(handle: *const DocumentStore.Handle, symbol: []const u8, sour
 | 
				
			|||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn lookupSymbolGlobal(store: *DocumentStore, handle: *const DocumentStore.Handle, symbol: []const u8, source_index: usize) error{OutOfMemory}!?DeclWithHandle {
 | 
					pub fn lookupSymbolGlobal(arena: std.mem.Allocator, store: *DocumentStore, handle: *const DocumentStore.Handle, symbol: []const u8, source_index: usize) error{OutOfMemory}!?DeclWithHandle {
 | 
				
			||||||
    const innermost_scope_idx = innermostBlockScopeIndex(handle.*, source_index);
 | 
					    const innermost_scope_idx = innermostBlockScopeIndex(handle.*, source_index);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const scope_locs = handle.document_scope.scopes.items(.loc);
 | 
					    const scope_locs = handle.document_scope.scopes.items(.loc);
 | 
				
			||||||
@ -2381,7 +2485,7 @@ pub fn lookupSymbolGlobal(store: *DocumentStore, handle: *const DocumentStore.Ha
 | 
				
			|||||||
                    .handle = handle,
 | 
					                    .handle = handle,
 | 
				
			||||||
                };
 | 
					                };
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            if (try resolveUse(store, scope_uses[curr].items, symbol, handle)) |result| return result;
 | 
					            if (try resolveUse(arena, store, scope_uses[curr].items, symbol, handle)) |result| return result;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        if (curr == 0) break;
 | 
					        if (curr == 0) break;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -2389,6 +2493,7 @@ pub fn lookupSymbolGlobal(store: *DocumentStore, handle: *const DocumentStore.Ha
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub fn lookupSymbolContainer(
 | 
					pub fn lookupSymbolContainer(
 | 
				
			||||||
 | 
					    arena: std.mem.Allocator,
 | 
				
			||||||
    store: *DocumentStore,
 | 
					    store: *DocumentStore,
 | 
				
			||||||
    container_handle: NodeWithHandle,
 | 
					    container_handle: NodeWithHandle,
 | 
				
			||||||
    symbol: []const u8,
 | 
					    symbol: []const u8,
 | 
				
			||||||
@ -2422,7 +2527,7 @@ pub fn lookupSymbolContainer(
 | 
				
			|||||||
            return DeclWithHandle{ .decl = candidate.value_ptr, .handle = handle };
 | 
					            return DeclWithHandle{ .decl = candidate.value_ptr, .handle = handle };
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        if (try resolveUse(store, scope_uses[container_scope_index].items, symbol, handle)) |result| return result;
 | 
					        if (try resolveUse(arena, store, scope_uses[container_scope_index].items, symbol, handle)) |result| return result;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return null;
 | 
					    return null;
 | 
				
			||||||
@ -2723,7 +2828,7 @@ fn makeScopeInternal(allocator: std.mem.Allocator, context: ScopeContext, node_i
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            try scopes.append(allocator, .{
 | 
					            try scopes.append(allocator, .{
 | 
				
			||||||
                .loc = offsets.nodeToLoc(tree, node_idx),
 | 
					                .loc = offsets.nodeToLoc(tree, node_idx),
 | 
				
			||||||
                .data = .{ .container = node_idx },
 | 
					                .data = .{ .block = node_idx },
 | 
				
			||||||
            });
 | 
					            });
 | 
				
			||||||
            const scope_index = scopes.len - 1;
 | 
					            const scope_index = scopes.len - 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -2731,11 +2836,6 @@ fn makeScopeInternal(allocator: std.mem.Allocator, context: ScopeContext, node_i
 | 
				
			|||||||
            const statements = ast.blockStatements(tree, node_idx, &buffer).?;
 | 
					            const statements = ast.blockStatements(tree, node_idx, &buffer).?;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            for (statements) |idx| {
 | 
					            for (statements) |idx| {
 | 
				
			||||||
                if (tags[idx] == .@"usingnamespace") {
 | 
					 | 
				
			||||||
                    try scopes.items(.uses)[scope_index].append(allocator, idx);
 | 
					 | 
				
			||||||
                    continue;
 | 
					 | 
				
			||||||
                }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
                try makeScopeInternal(allocator, context, idx);
 | 
					                try makeScopeInternal(allocator, context, idx);
 | 
				
			||||||
                if (tree.fullVarDecl(idx)) |var_decl| {
 | 
					                if (tree.fullVarDecl(idx)) |var_decl| {
 | 
				
			||||||
                    const name = tree.tokenSlice(var_decl.ast.mut_token + 1);
 | 
					                    const name = tree.tokenSlice(var_decl.ast.mut_token + 1);
 | 
				
			||||||
 | 
				
			|||||||
@ -89,6 +89,7 @@ fn handleUnusedFunctionParameter(builder: *Builder, actions: *std.ArrayListUnman
 | 
				
			|||||||
    const token_starts = tree.tokens.items(.start);
 | 
					    const token_starts = tree.tokens.items(.start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const decl = (try analysis.lookupSymbolGlobal(
 | 
					    const decl = (try analysis.lookupSymbolGlobal(
 | 
				
			||||||
 | 
					        builder.arena,
 | 
				
			||||||
        builder.document_store,
 | 
					        builder.document_store,
 | 
				
			||||||
        builder.handle,
 | 
					        builder.handle,
 | 
				
			||||||
        identifier_name,
 | 
					        identifier_name,
 | 
				
			||||||
@ -134,6 +135,7 @@ fn handleUnusedVariableOrConstant(builder: *Builder, actions: *std.ArrayListUnma
 | 
				
			|||||||
    const token_starts = tree.tokens.items(.start);
 | 
					    const token_starts = tree.tokens.items(.start);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const decl = (try analysis.lookupSymbolGlobal(
 | 
					    const decl = (try analysis.lookupSymbolGlobal(
 | 
				
			||||||
 | 
					        builder.arena,
 | 
				
			||||||
        builder.document_store,
 | 
					        builder.document_store,
 | 
				
			||||||
        builder.handle,
 | 
					        builder.handle,
 | 
				
			||||||
        identifier_name,
 | 
					        identifier_name,
 | 
				
			||||||
 | 
				
			|||||||
@ -81,7 +81,7 @@ fn writeCallHint(builder: *Builder, call: Ast.full.Call, decl_handle: analysis.D
 | 
				
			|||||||
    var i: usize = 0;
 | 
					    var i: usize = 0;
 | 
				
			||||||
    var it = fn_proto.iterate(&decl_tree);
 | 
					    var it = fn_proto.iterate(&decl_tree);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (try analysis.hasSelfParam(builder.store, decl_handle.handle, fn_proto)) {
 | 
					    if (try analysis.hasSelfParam(builder.arena, builder.store, decl_handle.handle, fn_proto)) {
 | 
				
			||||||
        _ = ast.nextFnParam(&it);
 | 
					        _ = ast.nextFnParam(&it);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -177,7 +177,7 @@ fn writeCallNodeHint(builder: *Builder, call: Ast.full.Call) !void {
 | 
				
			|||||||
            const source_index = offsets.tokenToIndex(tree, main_tokens[call.ast.fn_expr]);
 | 
					            const source_index = offsets.tokenToIndex(tree, main_tokens[call.ast.fn_expr]);
 | 
				
			||||||
            const name = offsets.tokenToSlice(tree, main_tokens[call.ast.fn_expr]);
 | 
					            const name = offsets.tokenToSlice(tree, main_tokens[call.ast.fn_expr]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (try analysis.lookupSymbolGlobal(builder.store, handle, name, source_index)) |decl_handle| {
 | 
					            if (try analysis.lookupSymbolGlobal(builder.arena, builder.store, handle, name, source_index)) |decl_handle| {
 | 
				
			||||||
                try writeCallHint(builder, call, decl_handle);
 | 
					                try writeCallHint(builder, call, decl_handle);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
@ -194,11 +194,12 @@ fn writeCallNodeHint(builder: *Builder, call: Ast.full.Call) !void {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            // note: we have the ast node, traversing it would probably yield better results
 | 
					            // note: we have the ast node, traversing it would probably yield better results
 | 
				
			||||||
            // than trying to re-tokenize and re-parse it
 | 
					            // than trying to re-tokenize and re-parse it
 | 
				
			||||||
            if (try analysis.getFieldAccessType(builder.store, handle, rhs_loc.end, &tokenizer)) |result| {
 | 
					            if (try analysis.getFieldAccessType(builder.arena, builder.store, handle, rhs_loc.end, &tokenizer)) |result| {
 | 
				
			||||||
                const container_handle = result.unwrapped orelse result.original;
 | 
					                const container_handle = result.unwrapped orelse result.original;
 | 
				
			||||||
                switch (container_handle.type.data) {
 | 
					                switch (container_handle.type.data) {
 | 
				
			||||||
                    .other => |container_handle_node| {
 | 
					                    .other => |container_handle_node| {
 | 
				
			||||||
                        if (try analysis.lookupSymbolContainer(
 | 
					                        if (try analysis.lookupSymbolContainer(
 | 
				
			||||||
 | 
					                            builder.arena,
 | 
				
			||||||
                            builder.store,
 | 
					                            builder.store,
 | 
				
			||||||
                            .{ .node = container_handle_node, .handle = container_handle.handle },
 | 
					                            .{ .node = container_handle_node, .handle = container_handle.handle },
 | 
				
			||||||
                            tree.tokenSlice(rhsToken),
 | 
					                            tree.tokenSlice(rhsToken),
 | 
				
			||||||
 | 
				
			|||||||
@ -99,6 +99,7 @@ const Builder = struct {
 | 
				
			|||||||
                const identifier_token = main_tokens[node];
 | 
					                const identifier_token = main_tokens[node];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const child = (try analysis.lookupSymbolGlobal(
 | 
					                const child = (try analysis.lookupSymbolGlobal(
 | 
				
			||||||
 | 
					                    builder.allocator,
 | 
				
			||||||
                    builder.store,
 | 
					                    builder.store,
 | 
				
			||||||
                    handle,
 | 
					                    handle,
 | 
				
			||||||
                    offsets.tokenToSlice(handle.tree, identifier_token),
 | 
					                    offsets.tokenToSlice(handle.tree, identifier_token),
 | 
				
			||||||
@ -113,8 +114,10 @@ const Builder = struct {
 | 
				
			|||||||
                var bound_type_params = analysis.BoundTypeParams{};
 | 
					                var bound_type_params = analysis.BoundTypeParams{};
 | 
				
			||||||
                defer bound_type_params.deinit(builder.store.allocator);
 | 
					                defer bound_type_params.deinit(builder.store.allocator);
 | 
				
			||||||
                const left_type = try analysis.resolveFieldAccessLhsType(
 | 
					                const left_type = try analysis.resolveFieldAccessLhsType(
 | 
				
			||||||
 | 
					                    builder.allocator,
 | 
				
			||||||
                    builder.store,
 | 
					                    builder.store,
 | 
				
			||||||
                    (try analysis.resolveTypeOfNodeInternal(
 | 
					                    (try analysis.resolveTypeOfNodeInternal(
 | 
				
			||||||
 | 
					                        builder.allocator,
 | 
				
			||||||
                        builder.store,
 | 
					                        builder.store,
 | 
				
			||||||
                        .{ .node = datas[node].lhs, .handle = handle },
 | 
					                        .{ .node = datas[node].lhs, .handle = handle },
 | 
				
			||||||
                        &bound_type_params,
 | 
					                        &bound_type_params,
 | 
				
			||||||
@ -128,6 +131,7 @@ const Builder = struct {
 | 
				
			|||||||
                };
 | 
					                };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                const child = (try analysis.lookupSymbolContainer(
 | 
					                const child = (try analysis.lookupSymbolContainer(
 | 
				
			||||||
 | 
					                    self.builder.allocator,
 | 
				
			||||||
                    builder.store,
 | 
					                    builder.store,
 | 
				
			||||||
                    .{ .node = left_type_node, .handle = left_type.handle },
 | 
					                    .{ .node = left_type_node, .handle = left_type.handle },
 | 
				
			||||||
                    offsets.tokenToSlice(handle.tree, datas[node].rhs),
 | 
					                    offsets.tokenToSlice(handle.tree, datas[node].rhs),
 | 
				
			||||||
 | 
				
			|||||||
@ -344,7 +344,7 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe
 | 
				
			|||||||
            try writeToken(builder, var_decl.comptime_token, .keyword);
 | 
					            try writeToken(builder, var_decl.comptime_token, .keyword);
 | 
				
			||||||
            try writeToken(builder, var_decl.ast.mut_token, .keyword);
 | 
					            try writeToken(builder, var_decl.ast.mut_token, .keyword);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (try analysis.resolveTypeOfNode(builder.store, .{ .node = node, .handle = handle })) |decl_type| {
 | 
					            if (try analysis.resolveTypeOfNode(allocator, builder.store, .{ .node = node, .handle = handle })) |decl_type| {
 | 
				
			||||||
                try colorIdentifierBasedOnType(builder, decl_type, var_decl.ast.mut_token + 1, .{ .declaration = true });
 | 
					                try colorIdentifierBasedOnType(builder, decl_type, var_decl.ast.mut_token + 1, .{ .declaration = true });
 | 
				
			||||||
            } else {
 | 
					            } else {
 | 
				
			||||||
                try writeTokenMod(builder, var_decl.ast.mut_token + 1, .variable, .{ .declaration = true });
 | 
					                try writeTokenMod(builder, var_decl.ast.mut_token + 1, .variable, .{ .declaration = true });
 | 
				
			||||||
@ -417,6 +417,7 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            if (try analysis.lookupSymbolGlobal(
 | 
					            if (try analysis.lookupSymbolGlobal(
 | 
				
			||||||
 | 
					                allocator,
 | 
				
			||||||
                builder.store,
 | 
					                builder.store,
 | 
				
			||||||
                handle,
 | 
					                handle,
 | 
				
			||||||
                name,
 | 
					                name,
 | 
				
			||||||
@ -428,7 +429,7 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe
 | 
				
			|||||||
                var bound_type_params = analysis.BoundTypeParams{};
 | 
					                var bound_type_params = analysis.BoundTypeParams{};
 | 
				
			||||||
                defer bound_type_params.deinit(builder.store.allocator);
 | 
					                defer bound_type_params.deinit(builder.store.allocator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (try child.resolveType(builder.store, &bound_type_params)) |decl_type| {
 | 
					                if (try child.resolveType(allocator, builder.store, &bound_type_params)) |decl_type| {
 | 
				
			||||||
                    try colorIdentifierBasedOnType(builder, decl_type, main_token, .{});
 | 
					                    try colorIdentifierBasedOnType(builder, decl_type, main_token, .{});
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    try writeTokenMod(builder, main_token, .variable, .{});
 | 
					                    try writeTokenMod(builder, main_token, .variable, .{});
 | 
				
			||||||
@ -659,6 +660,7 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe
 | 
				
			|||||||
                try callWriteNodeTokens(allocator, .{ builder, struct_init.ast.type_expr });
 | 
					                try callWriteNodeTokens(allocator, .{ builder, struct_init.ast.type_expr });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                field_token_type = if (try analysis.resolveTypeOfNode(
 | 
					                field_token_type = if (try analysis.resolveTypeOfNode(
 | 
				
			||||||
 | 
					                    allocator,
 | 
				
			||||||
                    builder.store,
 | 
					                    builder.store,
 | 
				
			||||||
                    .{ .node = struct_init.ast.type_expr, .handle = handle },
 | 
					                    .{ .node = struct_init.ast.type_expr, .handle = handle },
 | 
				
			||||||
                )) |struct_type| switch (struct_type.type.data) {
 | 
					                )) |struct_type| switch (struct_type.type.data) {
 | 
				
			||||||
@ -878,8 +880,10 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe
 | 
				
			|||||||
            defer bound_type_params.deinit(builder.store.allocator);
 | 
					            defer bound_type_params.deinit(builder.store.allocator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            const lhs_type = try analysis.resolveFieldAccessLhsType(
 | 
					            const lhs_type = try analysis.resolveFieldAccessLhsType(
 | 
				
			||||||
 | 
					                allocator,
 | 
				
			||||||
                builder.store,
 | 
					                builder.store,
 | 
				
			||||||
                (try analysis.resolveTypeOfNodeInternal(
 | 
					                (try analysis.resolveTypeOfNodeInternal(
 | 
				
			||||||
 | 
					                    allocator,
 | 
				
			||||||
                    builder.store,
 | 
					                    builder.store,
 | 
				
			||||||
                    .{ .node = data.lhs, .handle = handle },
 | 
					                    .{ .node = data.lhs, .handle = handle },
 | 
				
			||||||
                    &bound_type_params,
 | 
					                    &bound_type_params,
 | 
				
			||||||
@ -891,6 +895,7 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe
 | 
				
			|||||||
                else => return,
 | 
					                else => return,
 | 
				
			||||||
            };
 | 
					            };
 | 
				
			||||||
            if (try analysis.lookupSymbolContainer(
 | 
					            if (try analysis.lookupSymbolContainer(
 | 
				
			||||||
 | 
					                allocator,
 | 
				
			||||||
                builder.store,
 | 
					                builder.store,
 | 
				
			||||||
                .{ .node = left_type_node, .handle = lhs_type.handle },
 | 
					                .{ .node = left_type_node, .handle = lhs_type.handle },
 | 
				
			||||||
                tree.tokenSlice(data.rhs),
 | 
					                tree.tokenSlice(data.rhs),
 | 
				
			||||||
@ -915,7 +920,7 @@ fn writeNodeTokens(builder: *Builder, maybe_node: ?Ast.Node.Index) error{OutOfMe
 | 
				
			|||||||
                    else => {},
 | 
					                    else => {},
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if (try decl_type.resolveType(builder.store, &bound_type_params)) |resolved_type| {
 | 
					                if (try decl_type.resolveType(allocator, builder.store, &bound_type_params)) |resolved_type| {
 | 
				
			||||||
                    try colorIdentifierBasedOnType(builder, resolved_type, data.rhs, .{});
 | 
					                    try colorIdentifierBasedOnType(builder, resolved_type, data.rhs, .{});
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
				
			|||||||
@ -15,7 +15,7 @@ fn fnProtoToSignatureInfo(document_store: *DocumentStore, alloc: std.mem.Allocat
 | 
				
			|||||||
    const proto_comments = (try analysis.getDocComments(alloc, tree, fn_node, .markdown)) orelse "";
 | 
					    const proto_comments = (try analysis.getDocComments(alloc, tree, fn_node, .markdown)) orelse "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const arg_idx = if (skip_self_param) blk: {
 | 
					    const arg_idx = if (skip_self_param) blk: {
 | 
				
			||||||
        const has_self_param = try analysis.hasSelfParam(document_store, handle, proto);
 | 
					        const has_self_param = try analysis.hasSelfParam(alloc, document_store, handle, proto);
 | 
				
			||||||
        break :blk commas + @boolToInt(has_self_param);
 | 
					        break :blk commas + @boolToInt(has_self_param);
 | 
				
			||||||
    } else commas;
 | 
					    } else commas;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -257,6 +257,7 @@ pub fn getSignatureInfo(document_store: *DocumentStore, alloc: std.mem.Allocator
 | 
				
			|||||||
                // Resolve the expression.
 | 
					                // Resolve the expression.
 | 
				
			||||||
                var tokenizer = std.zig.Tokenizer.init(held_expr);
 | 
					                var tokenizer = std.zig.Tokenizer.init(held_expr);
 | 
				
			||||||
                if (try analysis.getFieldAccessType(
 | 
					                if (try analysis.getFieldAccessType(
 | 
				
			||||||
 | 
					                    alloc,
 | 
				
			||||||
                    document_store,
 | 
					                    document_store,
 | 
				
			||||||
                    handle,
 | 
					                    handle,
 | 
				
			||||||
                    expr_start,
 | 
					                    expr_start,
 | 
				
			||||||
@ -292,6 +293,7 @@ pub fn getSignatureInfo(document_store: *DocumentStore, alloc: std.mem.Allocator
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
                    const skip_self_param = !type_handle.type.is_type_val;
 | 
					                    const skip_self_param = !type_handle.type.is_type_val;
 | 
				
			||||||
                    const decl_handle = (try analysis.lookupSymbolContainer(
 | 
					                    const decl_handle = (try analysis.lookupSymbolContainer(
 | 
				
			||||||
 | 
					                        alloc,
 | 
				
			||||||
                        document_store,
 | 
					                        document_store,
 | 
				
			||||||
                        .{ .node = node, .handle = type_handle.handle },
 | 
					                        .{ .node = node, .handle = type_handle.handle },
 | 
				
			||||||
                        name,
 | 
					                        name,
 | 
				
			||||||
@ -310,6 +312,7 @@ pub fn getSignatureInfo(document_store: *DocumentStore, alloc: std.mem.Allocator
 | 
				
			|||||||
                    };
 | 
					                    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                    if (try analysis.resolveVarDeclAlias(
 | 
					                    if (try analysis.resolveVarDeclAlias(
 | 
				
			||||||
 | 
					                        alloc,
 | 
				
			||||||
                        document_store,
 | 
					                        document_store,
 | 
				
			||||||
                        .{ .node = node, .handle = decl_handle.handle },
 | 
					                        .{ .node = node, .handle = decl_handle.handle },
 | 
				
			||||||
                    )) |resolved| {
 | 
					                    )) |resolved| {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user