Skip to content

Commit 015f619

Browse files
committed
refactor some function analysis code
1 parent 25ac14e commit 015f619

File tree

2 files changed

+88
-112
lines changed

2 files changed

+88
-112
lines changed

src/analysis.zig

Lines changed: 32 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -811,28 +811,36 @@ fn findReturnStatement(tree: Ast, body: Ast.Node.Index) ?Ast.Node.Index {
811811
return findReturnStatementInternal(tree, body, &already_found);
812812
}
813813

814-
pub fn resolveReturnType(analyser: *Analyser, fn_decl: Ast.full.FnProto, handle: *DocumentStore.Handle, fn_body: ?Ast.Node.Index) error{OutOfMemory}!?Type {
815-
const tree = handle.tree;
816-
if (isTypeFunction(tree, fn_decl) and fn_body != null) {
814+
pub fn resolveReturnType(analyser: *Analyser, func_type: Type) error{OutOfMemory}!?Type {
815+
const func_node_handle = func_type.data.other; // this assumes that function types can only be Ast nodes
816+
const tree = func_node_handle.handle.tree;
817+
const func_node = func_node_handle.node;
818+
819+
var buf: [1]Ast.Node.Index = undefined;
820+
const fn_proto = tree.fullFnProto(&buf, func_node).?;
821+
const has_body = tree.nodes.items(.tag)[func_node] == .fn_decl;
822+
823+
if (isTypeFunction(tree, fn_proto) and has_body) {
824+
const body = tree.nodes.items(.data)[func_node].rhs;
817825
// If this is a type function and it only contains a single return statement that returns
818826
// a container declaration, we will return that declaration.
819-
const ret = findReturnStatement(tree, fn_body.?) orelse return null;
827+
const ret = findReturnStatement(tree, body) orelse return null;
820828
const data = tree.nodes.items(.data)[ret];
821829
if (data.lhs != 0) {
822-
return try analyser.resolveTypeOfNodeInternal(.{ .node = data.lhs, .handle = handle });
830+
return try analyser.resolveTypeOfNodeInternal(.{ .node = data.lhs, .handle = func_node_handle.handle });
823831
}
824832

825833
return null;
826834
}
827835

828-
if (fn_decl.ast.return_type == 0) return null;
829-
const return_type = fn_decl.ast.return_type;
830-
const ret: NodeWithHandle = .{ .node = return_type, .handle = handle };
836+
if (fn_proto.ast.return_type == 0) return null;
837+
const return_type = fn_proto.ast.return_type;
838+
const ret: NodeWithHandle = .{ .node = return_type, .handle = func_node_handle.handle };
831839
const child_type = (try analyser.resolveTypeOfNodeInternal(ret)) orelse
832840
return null;
833841
if (!child_type.is_type_val) return null;
834842

835-
if (ast.hasInferredError(tree, fn_decl)) {
843+
if (ast.hasInferredError(tree, fn_proto)) {
836844
const child_type_ptr = try analyser.arena.allocator().create(Type);
837845
child_type_ptr.* = child_type;
838846
return Type{
@@ -1542,11 +1550,7 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e
15421550
}, argument_type);
15431551
}
15441552

1545-
const has_body = func_tree.nodes.items(.tag)[func_node] == .fn_decl;
1546-
const body = func_tree.nodes.items(.data)[func_node].rhs;
1547-
if (try analyser.resolveReturnType(fn_proto, func_handle, if (has_body) body else null)) |ret| {
1548-
return ret;
1549-
}
1553+
return try analyser.resolveReturnType(func_ty);
15501554
},
15511555
.container_field,
15521556
.container_field_init,
@@ -2646,6 +2650,10 @@ pub const Type = struct {
26462650
}
26472651
}
26482652

2653+
pub fn isContainerType(self: Type) bool {
2654+
return self.data == .container;
2655+
}
2656+
26492657
fn isContainerKind(self: Type, container_kind_tok: std.zig.Token.Tag) bool {
26502658
const scope_handle = switch (self.data) {
26512659
.container => |s| s,
@@ -3231,22 +3239,9 @@ pub fn getFieldAccessType(
32313239

32323240
// Can't call a function type, we need a function type instance.
32333241
if (current_type.?.is_type_val) return null;
3234-
// this assumes that function types can only be Ast nodes
3235-
const current_type_node_handle = ty.data.other;
3236-
const current_type_node = current_type_node_handle.node;
3237-
const current_type_handle = current_type_node_handle.handle;
3238-
3239-
const cur_tree = current_type_handle.tree;
3240-
var buf: [1]Ast.Node.Index = undefined;
3241-
const func = cur_tree.fullFnProto(&buf, current_type_node).?;
3242-
// Check if the function has a body and if so, pass it
3243-
// so the type can be resolved if it's a generic function returning
3244-
// an anonymous struct
3245-
const has_body = cur_tree.nodes.items(.tag)[current_type_node] == .fn_decl;
3246-
const body = cur_tree.nodes.items(.data)[current_type_node].rhs;
32473242

32483243
// TODO Actually bind params here when calling functions instead of just skipping args.
3249-
current_type = try analyser.resolveReturnType(func, current_type_handle, if (has_body) body else null) orelse return null;
3244+
current_type = try analyser.resolveReturnType(ty) orelse return null;
32503245

32513246
if (do_unwrap_error_payload) {
32523247
if (try analyser.resolveUnwrapErrorUnionType(current_type.?, .payload)) |unwrapped| current_type = unwrapped;
@@ -4689,27 +4684,16 @@ pub fn resolveExpressionTypeFromAncestors(
46894684
if (fn_type.is_type_val) return null;
46904685

46914686
const fn_node_handle = fn_type.data.other; // this assumes that function types can only be Ast nodes
4692-
const fn_node = fn_node_handle.node;
4693-
const fn_handle = fn_node_handle.handle;
4694-
const fn_tree = fn_handle.tree;
4695-
4696-
var fn_buf: [1]Ast.Node.Index = undefined;
4697-
const fn_proto = fn_tree.fullFnProto(&fn_buf, fn_node).?;
4698-
4699-
var param_iter = fn_proto.iterate(&fn_tree);
4700-
if (try analyser.isInstanceCall(handle, call, fn_type)) {
4701-
_ = ast.nextFnParam(&param_iter);
4702-
}
4687+
const param_decl: Declaration.Param = .{
4688+
.param_index = @truncate(arg_index + @intFromBool(try analyser.hasSelfParam(fn_type))),
4689+
.func = fn_node_handle.node,
4690+
};
4691+
const param = param_decl.get(fn_node_handle.handle.tree) orelse return null;
47034692

4704-
var param_index: usize = 0;
4705-
while (ast.nextFnParam(&param_iter)) |param| : (param_index += 1) {
4706-
if (param_index == arg_index) {
4707-
return try analyser.resolveTypeOfNode(.{
4708-
.node = param.type_expr,
4709-
.handle = fn_handle,
4710-
});
4711-
}
4712-
}
4693+
return try analyser.resolveTypeOfNode(.{
4694+
.node = param.type_expr,
4695+
.handle = fn_node_handle.handle,
4696+
});
47134697
},
47144698
.assign => {
47154699
if (node == datas[ancestors[0]].rhs) {

src/features/completions.zig

Lines changed: 56 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,30 +1467,25 @@ fn collectVarAccessContainerNodes(
14671467
const symbol_decl = try analyser.lookupSymbolGlobal(handle, handle.tree.source[loc.start..loc.end], loc.end) orelse return;
14681468
const result = try symbol_decl.resolveType(analyser) orelse return;
14691469
const type_expr = try analyser.resolveDerefType(result) orelse result;
1470-
if (type_expr.isFunc()) {
1471-
const fn_proto_node_handle = type_expr.data.other; // this assumes that function types can only be Ast nodes
1472-
const fn_proto_node = fn_proto_node_handle.node;
1473-
const fn_proto_handle = fn_proto_node_handle.handle;
1474-
if (dot_context.likely == .enum_comparison or dot_context.need_ret_type) { // => we need f()'s return type
1475-
var buf: [1]Ast.Node.Index = undefined;
1476-
const full_fn_proto = fn_proto_handle.tree.fullFnProto(&buf, fn_proto_node).?;
1477-
const has_body = fn_proto_handle.tree.nodes.items(.tag)[fn_proto_node] == .fn_decl;
1478-
const body = fn_proto_handle.tree.nodes.items(.data)[fn_proto_node].rhs;
1479-
var node_type = try analyser.resolveReturnType(full_fn_proto, fn_proto_handle, if (has_body) body else null) orelse return;
1480-
if (try analyser.resolveUnwrapErrorUnionType(node_type, .payload)) |unwrapped| node_type = unwrapped;
1481-
try node_type.getAllTypesWithHandlesArrayList(arena, types_with_handles);
1482-
return;
1483-
}
1484-
const fn_param_decl = Analyser.Declaration{ .function_parameter = .{
1485-
.func = fn_proto_node,
1486-
.param_index = @intCast(dot_context.fn_arg_index),
1487-
} };
1488-
const fn_param_decl_with_handle = Analyser.DeclWithHandle{ .decl = fn_param_decl, .handle = fn_proto_handle };
1489-
const param_type = try fn_param_decl_with_handle.resolveType(analyser) orelse return;
1490-
try types_with_handles.append(arena, param_type);
1470+
if (!type_expr.isFunc()) {
1471+
try type_expr.getAllTypesWithHandlesArrayList(arena, types_with_handles);
14911472
return;
14921473
}
1493-
try type_expr.getAllTypesWithHandlesArrayList(arena, types_with_handles);
1474+
1475+
if (dot_context.likely == .enum_comparison or dot_context.need_ret_type) { // => we need f()'s return type
1476+
var node_type = try analyser.resolveReturnType(type_expr) orelse return;
1477+
if (try analyser.resolveUnwrapErrorUnionType(node_type, .payload)) |unwrapped| node_type = unwrapped;
1478+
try node_type.getAllTypesWithHandlesArrayList(arena, types_with_handles);
1479+
return;
1480+
}
1481+
const func_node_handle = type_expr.data.other; // this assumes that function types can only be Ast nodes
1482+
const fn_param_decl: Analyser.Declaration = .{ .function_parameter = .{
1483+
.func = func_node_handle.node,
1484+
.param_index = @intCast(dot_context.fn_arg_index),
1485+
} };
1486+
const fn_param_decl_with_handle = Analyser.DeclWithHandle{ .decl = fn_param_decl, .handle = func_node_handle.handle };
1487+
const param_type = try fn_param_decl_with_handle.resolveType(analyser) orelse return;
1488+
try types_with_handles.append(arena, param_type);
14941489
}
14951490

14961491
fn collectFieldAccessContainerNodes(
@@ -1528,50 +1523,47 @@ fn collectFieldAccessContainerNodes(
15281523
if (dot_context.likely == .enum_assignment or dot_context.likely == .struct_field) {
15291524
if (try analyser.resolveOptionalUnwrap(node_type)) |unwrapped| node_type = unwrapped;
15301525
}
1531-
if (node_type.isFunc()) {
1532-
const fn_proto_node_handle = node_type.data.other; // this assumes that function types can only be Ast nodes
1533-
const fn_proto_node = fn_proto_node_handle.node;
1534-
const fn_proto_handle = fn_proto_node_handle.handle;
1535-
var buf: [1]Ast.Node.Index = undefined;
1536-
const full_fn_proto = fn_proto_handle.tree.fullFnProto(&buf, fn_proto_node).?;
1537-
if (dot_context.need_ret_type) { // => we need f()'s return type
1538-
const has_body = fn_proto_handle.tree.nodes.items(.tag)[fn_proto_node] == .fn_decl;
1539-
const body = fn_proto_handle.tree.nodes.items(.data)[fn_proto_node].rhs;
1540-
node_type = try analyser.resolveReturnType(full_fn_proto, fn_proto_handle, if (has_body) body else null) orelse continue;
1541-
if (try analyser.resolveUnwrapErrorUnionType(node_type, .payload)) |unwrapped| node_type = unwrapped;
1542-
try node_type.getAllTypesWithHandlesArrayList(arena, types_with_handles);
1543-
continue;
1544-
}
1545-
var maybe_fn_param: ?Ast.full.FnProto.Param = undefined;
1546-
var fn_param_iter = full_fn_proto.iterate(&fn_proto_handle.tree);
1547-
// don't have the luxury of referencing an `Ast.full.Call`
1548-
// check if the first symbol is a `T` or an instance_of_T
1549-
const additional_index: usize = blk: {
1550-
// `loc` points to offsets within `handle`, not `node_type.decl.handle`
1551-
const field_access_slice = handle.tree.source[loc.start..loc.end];
1552-
if (field_access_slice[0] == '@') break :blk 1; // assume `@import("..").some.Other{.}`
1553-
var symbol_iter = std.mem.tokenizeScalar(u8, field_access_slice, '.');
1554-
const first_symbol = symbol_iter.next() orelse continue;
1555-
const symbol_decl = try analyser.lookupSymbolGlobal(handle, first_symbol, loc.start) orelse continue;
1556-
const symbol_type = try symbol_decl.resolveType(analyser) orelse continue;
1557-
if (!symbol_type.is_type_val) { // then => instance_of_T
1558-
if (try analyser.hasSelfParam(node_type)) break :blk 2;
1559-
}
1560-
break :blk 1; // is `T`, no SelfParam
1561-
};
1562-
for (dot_context.fn_arg_index + additional_index) |_| maybe_fn_param = ast.nextFnParam(&fn_param_iter);
1563-
const param = maybe_fn_param orelse continue;
1564-
if (param.type_expr == 0) continue;
1565-
const param_rcts = try collectContainerNodes(
1566-
builder,
1567-
fn_proto_handle,
1568-
offsets.nodeToLoc(fn_proto_handle.tree, param.type_expr).end,
1569-
dot_context,
1570-
);
1571-
for (param_rcts) |prct| try types_with_handles.append(arena, prct);
1526+
if (!node_type.isFunc()) {
1527+
try node_type.getAllTypesWithHandlesArrayList(arena, types_with_handles);
15721528
continue;
15731529
}
1574-
try node_type.getAllTypesWithHandlesArrayList(arena, types_with_handles);
1530+
1531+
if (dot_context.need_ret_type) { // => we need f()'s return type
1532+
node_type = try analyser.resolveReturnType(node_type) orelse continue;
1533+
if (try analyser.resolveUnwrapErrorUnionType(node_type, .payload)) |unwrapped| node_type = unwrapped;
1534+
try node_type.getAllTypesWithHandlesArrayList(arena, types_with_handles);
1535+
continue;
1536+
}
1537+
// don't have the luxury of referencing an `Ast.full.Call`
1538+
// check if the first symbol is a `T` or an instance_of_T
1539+
const additional_index: usize = blk: {
1540+
// `loc` points to offsets within `handle`, not `node_type.decl.handle`
1541+
const field_access_slice = handle.tree.source[loc.start..loc.end];
1542+
if (field_access_slice[0] == '@') break :blk 0; // assume `@import("..").some.Other{.}`
1543+
var symbol_iter = std.mem.tokenizeScalar(u8, field_access_slice, '.');
1544+
const first_symbol = symbol_iter.next() orelse continue;
1545+
const symbol_decl = try analyser.lookupSymbolGlobal(handle, first_symbol, loc.start) orelse continue;
1546+
const symbol_type = try symbol_decl.resolveType(analyser) orelse continue;
1547+
if (!symbol_type.is_type_val) { // then => instance_of_T
1548+
if (try analyser.hasSelfParam(node_type)) break :blk 1;
1549+
}
1550+
break :blk 0; // is `T`, no SelfParam
1551+
};
1552+
const fn_node_handle = node_type.data.other; // this assumes that function types can only be Ast nodes
1553+
const param_decl: Analyser.Declaration.Param = .{
1554+
.param_index = @truncate(dot_context.fn_arg_index + additional_index),
1555+
.func = fn_node_handle.node,
1556+
};
1557+
const param = param_decl.get(fn_node_handle.handle.tree) orelse continue;
1558+
1559+
if (param.type_expr == 0) continue;
1560+
const param_rcts = try collectContainerNodes(
1561+
builder,
1562+
fn_node_handle.handle,
1563+
offsets.nodeToLoc(fn_node_handle.handle.tree, param.type_expr).end,
1564+
dot_context,
1565+
);
1566+
for (param_rcts) |prct| try types_with_handles.append(arena, prct);
15751567
}
15761568
}
15771569

0 commit comments

Comments
 (0)