Skip to content

Commit

Permalink
Fix ref bugs, add checks, handle boundfns
Browse files Browse the repository at this point in the history
  • Loading branch information
SuperAuguste committed Mar 16, 2023
1 parent 4126e20 commit 46796e2
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 81 deletions.
43 changes: 36 additions & 7 deletions src/analysis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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 }),
Expand Down Expand Up @@ -2666,14 +2689,19 @@ 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
if (param.name_token) |name_token| {
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
Expand All @@ -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: {
Expand Down
131 changes: 57 additions & 74 deletions src/references.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
},
Expand All @@ -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);
}
},
Expand Down Expand Up @@ -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);
}
}
}

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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 => {},
}
},
Expand All @@ -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,
Expand All @@ -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;
Expand Down

0 comments on commit 46796e2

Please sign in to comment.