From 46796e2c688d258c5cf94d607a44be77013d3299 Mon Sep 17 00:00:00 2001 From: Auguste Rame <19855629+SuperAuguste@users.noreply.github.com> Date: Wed, 15 Mar 2023 22:50:45 -0400 Subject: [PATCH] Fix ref bugs, add checks, handle boundfns --- src/analysis.zig | 43 ++++++++++++--- src/references.zig | 131 ++++++++++++++++++++------------------------- 2 files changed, 93 insertions(+), 81 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index a76f3ccbe..47a3b6958 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -1916,26 +1916,49 @@ pub const DeclWithHandle = struct { if (pay.param.type_expr == 0) { var func_decl = Declaration{ .ast_node = pay.func }; + var func_buf: [1]Ast.Node.Index = undefined; + const func = tree.fullFnProto(&func_buf, pay.func).?; + + var func_params_len: usize = 0; + + var it = func.iterate(&tree); + while (ast.nextFnParam(&it)) |_| { + func_params_len += 1; + } + var refs = try references.callsiteReferences(analyser.arena, analyser, .{ .decl = &func_decl, .handle = self.handle, - }, false, false, true); + }, false, false, false); + + // TODO: Set `workspace` to true; current problems + // - we gather dependencies, not dependents + // - stack overflow due to cyclically anytype resolution(?) var possible = std.ArrayListUnmanaged(Type.EitherEntry){}; for (refs.items) |ref| { var handle = analyser.store.getOrLoadHandle(ref.uri).?; - var buf: [1]Ast.Node.Index = undefined; - var call = handle.tree.fullCall(&buf, ref.call_node).?; + var call_buf: [1]Ast.Node.Index = undefined; + var call = handle.tree.fullCall(&call_buf, ref.call_node).?; - if (pay.param_idx >= call.ast.params.len) continue; + const real_param_idx = if (func_params_len != 0 and pay.param_idx != 0 and call.ast.params.len == func_params_len - 1) + pay.param_idx - 1 + else + pay.param_idx; + + if (real_param_idx >= call.ast.params.len) continue; if (try analyser.resolveTypeOfNode(.{ - .node = call.ast.params[pay.param_idx], // TODO: self call (-1) + // TODO?: this is a """heuristic based approach""" + // perhaps it would be better to use proper self detection + // maybe it'd be a perf issue and this is fine? + // you figure it out future contributor <3 + .node = call.ast.params[real_param_idx], .handle = handle, })) |ty| { - var loc = offsets.tokenToPosition(handle.tree, main_tokens[call.ast.params[pay.param_idx]], .@"utf-8"); + var loc = offsets.tokenToPosition(handle.tree, main_tokens[call.ast.params[real_param_idx]], .@"utf-8"); try possible.append(analyser.arena, .{ // TODO: Dedup .type_with_handle = ty, .descriptor = try std.fmt.allocPrint(analyser.arena, "{s}:{d}:{d}", .{ handle.uri, loc.line + 1, loc.character + 1 }), @@ -2666,6 +2689,11 @@ fn makeScopeInternal(context: ScopeContext, node_idx: Ast.Node.Index) error{OutO ); defer context.popScope(); + // NOTE: We count the param index ourselves + // as param_i stops counting; TODO: change this + + var param_index: usize = 0; + var it = func.iterate(&tree); while (ast.nextFnParam(&it)) |param| { // Add parameter decls @@ -2673,7 +2701,7 @@ fn makeScopeInternal(context: ScopeContext, node_idx: Ast.Node.Index) error{OutO if (try scopes.items(.decls)[scope_index].fetchPut( allocator, tree.tokenSlice(name_token), - .{ .param_payload = .{ .param = param, .param_idx = @intCast(u16, it.param_i), .func = node_idx } }, + .{ .param_payload = .{ .param = param, .param_idx = @intCast(u16, param_index), .func = node_idx } }, )) |existing| { _ = existing; // TODO record a redefinition error @@ -2682,6 +2710,7 @@ fn makeScopeInternal(context: ScopeContext, node_idx: Ast.Node.Index) error{OutO // Visit parameter types to pick up any error sets and enum // completions try makeScopeInternal(context, param.type_expr); + param_index += 1; } if (fn_tag == .fn_decl) blk: { diff --git a/src/references.zig b/src/references.zig index 6dac4f26b..a412cc3b0 100644 --- a/src/references.zig +++ b/src/references.zig @@ -107,7 +107,7 @@ const Builder = struct { starts[identifier_token], )) orelse return; - if (std.meta.eql(builder.decl_handle, child)) { + if (builder.decl_handle.eql(child)) { try builder.add(handle, identifier_token); } }, @@ -127,7 +127,7 @@ const Builder = struct { !left_type.type.is_type_val, )) orelse return; - if (std.meta.eql(builder.decl_handle, child)) { + if (builder.decl_handle.eql(child)) { try builder.add(handle, datas[node].rhs); } }, @@ -187,17 +187,15 @@ pub fn symbolReferences( } var handle_dependencies = std.ArrayListUnmanaged([]const u8){}; - defer { - for (handle_dependencies.items) |uri| { - allocator.free(uri); - } - handle_dependencies.deinit(allocator); - } + defer handle_dependencies.deinit(allocator); try analyser.store.collectDependencies(allocator, handle.*, &handle_dependencies); try dependencies.ensureUnusedCapacity(allocator, handle_dependencies.items.len); for (handle_dependencies.items) |uri| { - dependencies.putAssumeCapacity(uri, {}); + var gop = dependencies.getOrPutAssumeCapacity(uri); + if (gop.found_existing) { + allocator.free(uri); + } } } @@ -277,7 +275,7 @@ const CallBuilder = struct { const handle = self.handle; const node_tags = tree.nodes.items(.tag); - // const datas = tree.nodes.items(.data); + const datas = tree.nodes.items(.data); // const token_tags = tree.tokens.items(.tag); const starts = tree.tokens.items(.start); @@ -310,7 +308,26 @@ const CallBuilder = struct { try builder.add(handle, node); } }, - // TODO: Field access + .field_access => { + const left_type = try builder.analyser.resolveFieldAccessLhsType( + (try builder.analyser.resolveTypeOfNode(.{ .node = datas[called_node].lhs, .handle = handle })) orelse return, + ); + + const left_type_node = switch (left_type.type.data) { + .other => |n| n, + else => return, + }; + + const child = (try builder.analyser.lookupSymbolContainer( + .{ .node = left_type_node, .handle = left_type.handle }, + offsets.tokenToSlice(tree, datas[called_node].rhs), + !left_type.type.is_type_val, + )) orelse return; + + if (builder.decl_handle.eql(child)) { + try builder.add(handle, node); + } + }, else => {}, } }, @@ -330,7 +347,7 @@ pub fn callsiteReferences( /// search other files for references workspace: bool, ) error{OutOfMemory}!std.ArrayListUnmanaged(Callsite) { - std.debug.assert(decl_handle.decl.* != .label_decl); // use `labelReferences` instead + std.debug.assert(decl_handle.decl.* == .ast_node); var builder = CallBuilder{ .allocator = allocator, @@ -342,76 +359,42 @@ pub fn callsiteReferences( const curr_handle = decl_handle.handle; if (include_decl) try builder.add(curr_handle, decl_handle.nameToken()); - switch (decl_handle.decl.*) { - .ast_node, - .pointer_payload, - .switch_payload, - .array_payload, - .array_index, - => { - try builder.collectReferences(curr_handle, 0); - - if (decl_handle.decl.* != .ast_node or !workspace) return builder.callsites; + try builder.collectReferences(curr_handle, 0); - var dependencies = std.StringArrayHashMapUnmanaged(void){}; - defer { - for (dependencies.keys()) |uri| { - allocator.free(uri); - } - dependencies.deinit(allocator); - } + if (!workspace) return builder.callsites; - for (analyser.store.handles.values()) |handle| { - if (skip_std_references and std.mem.indexOf(u8, handle.uri, "std") != null) { - if (!include_decl or !std.mem.eql(u8, handle.uri, curr_handle.uri)) - continue; - } - - var handle_dependencies = std.ArrayListUnmanaged([]const u8){}; - defer { - for (handle_dependencies.items) |uri| { - allocator.free(uri); - } - handle_dependencies.deinit(allocator); - } - try analyser.store.collectDependencies(allocator, handle.*, &handle_dependencies); + var dependencies = std.StringArrayHashMapUnmanaged(void){}; + defer { + for (dependencies.keys()) |uri| { + allocator.free(uri); + } + dependencies.deinit(allocator); + } - try dependencies.ensureUnusedCapacity(allocator, handle_dependencies.items.len); - for (handle_dependencies.items) |uri| { - dependencies.putAssumeCapacity(uri, {}); - } - } + for (analyser.store.handles.values()) |handle| { + if (skip_std_references and std.mem.indexOf(u8, handle.uri, "std") != null) { + if (!include_decl or !std.mem.eql(u8, handle.uri, curr_handle.uri)) + continue; + } - for (dependencies.keys()) |uri| { - if (std.mem.eql(u8, uri, curr_handle.uri)) continue; - const handle = analyser.store.getHandle(uri) orelse continue; + var handle_dependencies = std.ArrayListUnmanaged([]const u8){}; + defer handle_dependencies.deinit(allocator); + try analyser.store.collectDependencies(allocator, handle.*, &handle_dependencies); - try builder.collectReferences(handle, 0); + try dependencies.ensureUnusedCapacity(allocator, handle_dependencies.items.len); + for (handle_dependencies.items) |uri| { + var gop = dependencies.getOrPutAssumeCapacity(uri); + if (gop.found_existing) { + allocator.free(uri); } - }, - .param_payload => |payload| blk: { - // Rename the param tok. - for (curr_handle.document_scope.scopes.items(.data)) |scope_data| { - if (scope_data != .function) continue; - - const proto = scope_data.function; - - var buf: [1]Ast.Node.Index = undefined; - const fn_proto = curr_handle.tree.fullFnProto(&buf, proto).?; + } + } - var it = fn_proto.iterate(&curr_handle.tree); - while (ast.nextFnParam(&it)) |candidate| { - if (!std.meta.eql(candidate, payload.param)) continue; + for (dependencies.keys()) |uri| { + if (std.mem.eql(u8, uri, curr_handle.uri)) continue; + const handle = analyser.store.getOrLoadHandle(uri) orelse continue; - if (curr_handle.tree.nodes.items(.tag)[proto] != .fn_decl) break :blk; - try builder.collectReferences(curr_handle, curr_handle.tree.nodes.items(.data)[proto].rhs); - break :blk; - } - } - log.warn("Could not find param decl's function", .{}); - }, - .label_decl => unreachable, // handled separately by labelReferences - .error_token => {}, + try builder.collectReferences(handle, 0); } return builder.callsites;