Merge pull request #118 from alexnask/master
Differentiate between values of a type and type values
This commit is contained in:
commit
5ddebe8ffc
382
src/analysis.zig
382
src/analysis.zig
@ -232,19 +232,22 @@ fn resolveVarDeclAliasInternal(
|
|||||||
if (!std.mem.eql(u8, handle.tree.tokenSlice(builtin_call.builtin_token), "@import"))
|
if (!std.mem.eql(u8, handle.tree.tokenSlice(builtin_call.builtin_token), "@import"))
|
||||||
return null;
|
return null;
|
||||||
const inner_node = (try resolveTypeOfNode(store, arena, .{ .node = infix_op.lhs, .handle = handle })) orelse return null;
|
const inner_node = (try resolveTypeOfNode(store, arena, .{ .node = infix_op.lhs, .handle = handle })) orelse return null;
|
||||||
std.debug.assert(inner_node.node.id == .Root);
|
std.debug.assert(inner_node.type.data.other.id == .Root);
|
||||||
break :block inner_node;
|
break :block NodeWithHandle{ .node = inner_node.type.data.other, .handle = inner_node.handle };
|
||||||
} else if (try resolveVarDeclAliasInternal(store, arena, .{ .node = infix_op.lhs, .handle = handle }, false)) |decl_handle| block: {
|
} else if (try resolveVarDeclAliasInternal(store, arena, .{ .node = infix_op.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, arena, .{ .node = decl_handle.decl.ast_node, .handle = decl_handle.handle })) orelse return null;
|
const resolved = (try resolveTypeOfNode(store, arena, .{ .node = decl_handle.decl.ast_node, .handle = decl_handle.handle })) orelse return null;
|
||||||
if (resolved.node.id != .ContainerDecl and resolved.node.id != .Root) return null;
|
const resolved_node = switch (resolved.type.data) {
|
||||||
break :block resolved;
|
.other => |n| n,
|
||||||
|
else => return null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (resolved_node.id != .ContainerDecl and resolved_node.id != .Root) return null;
|
||||||
|
break :block NodeWithHandle{ .node = resolved_node, .handle = resolved.handle };
|
||||||
} else return null;
|
} else return null;
|
||||||
|
|
||||||
if (try lookupSymbolContainer(store, arena, container_node, handle.tree.tokenSlice(infix_op.rhs.firstToken()), false)) |inner_decl| {
|
if (try lookupSymbolContainer(store, arena, container_node, handle.tree.tokenSlice(infix_op.rhs.firstToken()), false)) |inner_decl| {
|
||||||
if (root) return inner_decl;
|
if (root) return inner_decl;
|
||||||
|
|
||||||
// if (!root and !isContainerDecl(inner_decl)) return null;
|
|
||||||
return inner_decl;
|
return inner_decl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -263,6 +266,7 @@ pub fn resolveVarDeclAlias(store: *DocumentStore, arena: *std.heap.ArenaAllocato
|
|||||||
|
|
||||||
if (decl.cast(ast.Node.VarDecl)) |var_decl| {
|
if (decl.cast(ast.Node.VarDecl)) |var_decl| {
|
||||||
if (var_decl.init_node == null) return null;
|
if (var_decl.init_node == null) return null;
|
||||||
|
if (handle.tree.token_ids[var_decl.mut_token] != .Keyword_const) return null;
|
||||||
|
|
||||||
const base_expr = var_decl.init_node.?;
|
const base_expr = var_decl.init_node.?;
|
||||||
if (base_expr.cast(ast.Node.InfixOp)) |infix_op| {
|
if (base_expr.cast(ast.Node.InfixOp)) |infix_op| {
|
||||||
@ -328,7 +332,7 @@ fn resolveReturnType(
|
|||||||
fn_decl: *ast.Node.FnProto,
|
fn_decl: *ast.Node.FnProto,
|
||||||
handle: *DocumentStore.Handle,
|
handle: *DocumentStore.Handle,
|
||||||
bound_type_params: *BoundTypeParams,
|
bound_type_params: *BoundTypeParams,
|
||||||
) !?NodeWithHandle {
|
) !?TypeWithHandle {
|
||||||
if (isTypeFunction(handle.tree, fn_decl) and fn_decl.body_node != null) {
|
if (isTypeFunction(handle.tree, fn_decl) and fn_decl.body_node != 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
|
||||||
// a container declaration, we will return that declaration.
|
// a container declaration, we will return that declaration.
|
||||||
@ -349,12 +353,16 @@ fn resolveReturnType(
|
|||||||
.node = return_type,
|
.node = return_type,
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
}, bound_type_params)) orelse return null;
|
}, bound_type_params)) orelse return null;
|
||||||
break :block NodeWithHandle{ .node = try makeErrorUnionType(arena, child_type.node), .handle = child_type.handle };
|
const child_type_node = switch (child_type.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => return null,
|
||||||
|
};
|
||||||
|
break :block TypeWithHandle{ .type = .{ .data = .{ .error_union = child_type_node }, .is_type_val = false }, .handle = child_type.handle };
|
||||||
},
|
},
|
||||||
.Explicit => |return_type| try resolveTypeOfNodeInternal(store, arena, .{
|
.Explicit => |return_type| ((try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = return_type,
|
.node = return_type,
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
}, bound_type_params),
|
}, bound_type_params)) orelse return null).instanceTypeVal(),
|
||||||
.Invalid => null,
|
.Invalid => null,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -363,15 +371,20 @@ fn resolveReturnType(
|
|||||||
fn resolveUnwrapOptionalType(
|
fn resolveUnwrapOptionalType(
|
||||||
store: *DocumentStore,
|
store: *DocumentStore,
|
||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
opt: NodeWithHandle,
|
opt: TypeWithHandle,
|
||||||
bound_type_params: *BoundTypeParams,
|
bound_type_params: *BoundTypeParams,
|
||||||
) !?NodeWithHandle {
|
) !?TypeWithHandle {
|
||||||
if (opt.node.cast(ast.Node.PrefixOp)) |prefix_op| {
|
const opt_node = switch (opt.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => return null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (opt_node.cast(ast.Node.PrefixOp)) |prefix_op| {
|
||||||
if (prefix_op.op == .OptionalType) {
|
if (prefix_op.op == .OptionalType) {
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{
|
return ((try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = prefix_op.rhs,
|
.node = prefix_op.rhs,
|
||||||
.handle = opt.handle,
|
.handle = opt.handle,
|
||||||
}, bound_type_params);
|
}, bound_type_params)) orelse return null).instanceTypeVal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,15 +394,24 @@ fn resolveUnwrapOptionalType(
|
|||||||
fn resolveUnwrapErrorType(
|
fn resolveUnwrapErrorType(
|
||||||
store: *DocumentStore,
|
store: *DocumentStore,
|
||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
rhs: NodeWithHandle,
|
rhs: TypeWithHandle,
|
||||||
bound_type_params: *BoundTypeParams,
|
bound_type_params: *BoundTypeParams,
|
||||||
) !?NodeWithHandle {
|
) !?TypeWithHandle {
|
||||||
if (rhs.node.cast(ast.Node.InfixOp)) |infix_op| {
|
const rhs_node = switch (rhs.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
.error_union => |n| return TypeWithHandle{
|
||||||
|
.type = .{ .data = .{ .other = n }, .is_type_val = rhs.type.is_type_val },
|
||||||
|
.handle = rhs.handle,
|
||||||
|
},
|
||||||
|
.slice => return null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (rhs_node.cast(ast.Node.InfixOp)) |infix_op| {
|
||||||
if (infix_op.op == .ErrorUnion) {
|
if (infix_op.op == .ErrorUnion) {
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{
|
return ((try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = infix_op.rhs,
|
.node = infix_op.rhs,
|
||||||
.handle = rhs.handle,
|
.handle = rhs.handle,
|
||||||
}, bound_type_params);
|
}, bound_type_params)) orelse return null).instanceTypeVal();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -400,17 +422,24 @@ fn resolveUnwrapErrorType(
|
|||||||
fn resolveDerefType(
|
fn resolveDerefType(
|
||||||
store: *DocumentStore,
|
store: *DocumentStore,
|
||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
deref: NodeWithHandle,
|
deref: TypeWithHandle,
|
||||||
bound_type_params: *BoundTypeParams,
|
bound_type_params: *BoundTypeParams,
|
||||||
) !?NodeWithHandle {
|
) !?TypeWithHandle {
|
||||||
if (deref.node.cast(ast.Node.PrefixOp)) |pop| {
|
const deref_node = switch (deref.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => return null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (deref_node.cast(ast.Node.PrefixOp)) |pop| {
|
||||||
if (pop.op == .PtrType) {
|
if (pop.op == .PtrType) {
|
||||||
const op_token_id = deref.handle.tree.token_ids[pop.op_token];
|
const op_token_id = deref.handle.tree.token_ids[pop.op_token];
|
||||||
switch (op_token_id) {
|
switch (op_token_id) {
|
||||||
.Asterisk => return try resolveTypeOfNodeInternal(store, arena, .{
|
.Asterisk => {
|
||||||
|
return ((try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = pop.rhs,
|
.node = pop.rhs,
|
||||||
.handle = deref.handle,
|
.handle = deref.handle,
|
||||||
}, bound_type_params),
|
}, bound_type_params)) orelse return null).instanceTypeVal();
|
||||||
|
},
|
||||||
.LBracket, .AsteriskAsterisk => return null,
|
.LBracket, .AsteriskAsterisk => return null,
|
||||||
else => unreachable,
|
else => unreachable,
|
||||||
}
|
}
|
||||||
@ -419,74 +448,49 @@ fn resolveDerefType(
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn makeErrorUnionType(arena: *std.heap.ArenaAllocator, child_type: *ast.Node) !*ast.Node {
|
|
||||||
// TODO: Better values for fields, better way to do this?
|
|
||||||
var error_union_type = try arena.allocator.create(ast.Node.InfixOp);
|
|
||||||
error_union_type.* = .{
|
|
||||||
.op_token = child_type.firstToken(),
|
|
||||||
.op = .ErrorUnion,
|
|
||||||
.lhs = child_type, // This is a dummy value
|
|
||||||
.rhs = child_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
return &error_union_type.base;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn makeSliceType(arena: *std.heap.ArenaAllocator, child_type: *ast.Node) !*ast.Node {
|
|
||||||
// TODO: Better values for fields, better way to do this?
|
|
||||||
var slice_type = try arena.allocator.create(ast.Node.PrefixOp);
|
|
||||||
slice_type.* = .{
|
|
||||||
.op_token = child_type.firstToken(),
|
|
||||||
.op = .{
|
|
||||||
.SliceType = .{
|
|
||||||
.allowzero_token = null,
|
|
||||||
.align_info = null,
|
|
||||||
.const_token = null,
|
|
||||||
.volatile_token = null,
|
|
||||||
.sentinel = null,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
.rhs = child_type,
|
|
||||||
};
|
|
||||||
|
|
||||||
return &slice_type.base;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resolves bracket access type (both slicing and array access)
|
/// Resolves bracket access type (both slicing and array access)
|
||||||
fn resolveBracketAccessType(
|
fn resolveBracketAccessType(
|
||||||
store: *DocumentStore,
|
store: *DocumentStore,
|
||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
lhs: NodeWithHandle,
|
lhs: TypeWithHandle,
|
||||||
rhs: enum { Single, Range },
|
rhs: enum { Single, Range },
|
||||||
bound_type_params: *BoundTypeParams,
|
bound_type_params: *BoundTypeParams,
|
||||||
) !?NodeWithHandle {
|
) !?TypeWithHandle {
|
||||||
if (lhs.node.cast(ast.Node.PrefixOp)) |pop| {
|
const lhs_node = switch (lhs.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => return null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (lhs_node.cast(ast.Node.PrefixOp)) |pop| {
|
||||||
switch (pop.op) {
|
switch (pop.op) {
|
||||||
.SliceType => {
|
.SliceType => {
|
||||||
if (rhs == .Single)
|
if (rhs == .Single)
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{
|
return ((try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = pop.rhs,
|
.node = pop.rhs,
|
||||||
.handle = lhs.handle,
|
.handle = lhs.handle,
|
||||||
}, bound_type_params);
|
}, bound_type_params)) orelse return null).instanceTypeVal();
|
||||||
return lhs;
|
return lhs;
|
||||||
},
|
},
|
||||||
.ArrayType => {
|
.ArrayType => {
|
||||||
if (rhs == .Single)
|
if (rhs == .Single)
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{
|
return ((try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = pop.rhs,
|
.node = pop.rhs,
|
||||||
.handle = lhs.handle,
|
.handle = lhs.handle,
|
||||||
}, bound_type_params);
|
}, bound_type_params)) orelse return null).instanceTypeVal();
|
||||||
return NodeWithHandle{ .node = try makeSliceType(arena, pop.rhs), .handle = lhs.handle };
|
return TypeWithHandle{
|
||||||
|
.type = .{ .data = .{ .slice = pop.rhs }, .is_type_val = false },
|
||||||
|
.handle = lhs.handle,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
.PtrType => {
|
.PtrType => {
|
||||||
if (pop.rhs.cast(std.zig.ast.Node.PrefixOp)) |child_pop| {
|
if (pop.rhs.cast(std.zig.ast.Node.PrefixOp)) |child_pop| {
|
||||||
switch (child_pop.op) {
|
switch (child_pop.op) {
|
||||||
.ArrayType => {
|
.ArrayType => {
|
||||||
if (rhs == .Single) {
|
if (rhs == .Single) {
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{
|
return ((try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = child_pop.rhs,
|
.node = child_pop.rhs,
|
||||||
.handle = lhs.handle,
|
.handle = lhs.handle,
|
||||||
}, bound_type_params);
|
}, bound_type_params)) orelse return null).instanceTypeVal();
|
||||||
}
|
}
|
||||||
return lhs;
|
return lhs;
|
||||||
},
|
},
|
||||||
@ -504,13 +508,13 @@ fn resolveBracketAccessType(
|
|||||||
fn resolveFieldAccessLhsType(
|
fn resolveFieldAccessLhsType(
|
||||||
store: *DocumentStore,
|
store: *DocumentStore,
|
||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
lhs: NodeWithHandle,
|
lhs: TypeWithHandle,
|
||||||
bound_type_params: *BoundTypeParams,
|
bound_type_params: *BoundTypeParams,
|
||||||
) !NodeWithHandle {
|
) !TypeWithHandle {
|
||||||
return (try resolveDerefType(store, arena, lhs, bound_type_params)) orelse lhs;
|
return (try resolveDerefType(store, arena, lhs, bound_type_params)) orelse lhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BoundTypeParams = std.AutoHashMap(*const ast.Node.FnProto.ParamDecl, NodeWithHandle);
|
const BoundTypeParams = std.AutoHashMap(*const ast.Node.FnProto.ParamDecl, TypeWithHandle);
|
||||||
|
|
||||||
/// Resolves the type of a node
|
/// Resolves the type of a node
|
||||||
fn resolveTypeOfNodeInternal(
|
fn resolveTypeOfNodeInternal(
|
||||||
@ -518,14 +522,23 @@ fn resolveTypeOfNodeInternal(
|
|||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
node_handle: NodeWithHandle,
|
node_handle: NodeWithHandle,
|
||||||
bound_type_params: *BoundTypeParams,
|
bound_type_params: *BoundTypeParams,
|
||||||
) error{OutOfMemory}!?NodeWithHandle {
|
) error{OutOfMemory}!?TypeWithHandle {
|
||||||
const node = node_handle.node;
|
const node = node_handle.node;
|
||||||
const handle = node_handle.handle;
|
const handle = node_handle.handle;
|
||||||
|
|
||||||
switch (node.id) {
|
switch (node.id) {
|
||||||
.VarDecl => {
|
.VarDecl => {
|
||||||
const vari = node.cast(ast.Node.VarDecl).?;
|
const vari = node.cast(ast.Node.VarDecl).?;
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{ .node = vari.type_node orelse vari.init_node.?, .handle = handle }, bound_type_params);
|
if (vari.type_node) |type_node| block: {
|
||||||
|
return ((try resolveTypeOfNodeInternal(
|
||||||
|
store,
|
||||||
|
arena,
|
||||||
|
.{ .node = vari.type_node orelse break :block, .handle = handle },
|
||||||
|
bound_type_params,
|
||||||
|
)) orelse break :block).instanceTypeVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
return try resolveTypeOfNodeInternal(store, arena, .{ .node = vari.init_node.?, .handle = handle }, bound_type_params);
|
||||||
},
|
},
|
||||||
.Identifier => {
|
.Identifier => {
|
||||||
if (try lookupSymbolGlobal(store, arena, handle, handle.tree.getNodeSource(node), handle.tree.token_locs[node.firstToken()].start)) |child| {
|
if (try lookupSymbolGlobal(store, arena, handle, handle.tree.getNodeSource(node), handle.tree.token_locs[node.firstToken()].start)) |child| {
|
||||||
@ -535,13 +548,28 @@ fn resolveTypeOfNodeInternal(
|
|||||||
},
|
},
|
||||||
.ContainerField => {
|
.ContainerField => {
|
||||||
const field = node.cast(ast.Node.ContainerField).?;
|
const field = node.cast(ast.Node.ContainerField).?;
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{ .node = field.type_expr orelse return null, .handle = handle }, bound_type_params);
|
return ((try resolveTypeOfNodeInternal(
|
||||||
|
store,
|
||||||
|
arena,
|
||||||
|
.{ .node = field.type_expr orelse return null, .handle = handle },
|
||||||
|
bound_type_params,
|
||||||
|
)) orelse return null).instanceTypeVal();
|
||||||
},
|
},
|
||||||
.Call => {
|
.Call => {
|
||||||
const call = node.cast(ast.Node.Call).?;
|
const call = node.cast(ast.Node.Call).?;
|
||||||
|
const decl = (try resolveTypeOfNodeInternal(
|
||||||
|
store,
|
||||||
|
arena,
|
||||||
|
.{ .node = call.lhs, .handle = handle },
|
||||||
|
bound_type_params,
|
||||||
|
)) orelse return null;
|
||||||
|
|
||||||
const decl = (try resolveTypeOfNodeInternal(store, arena, .{ .node = call.lhs, .handle = handle }, bound_type_params)) orelse return null;
|
if (decl.type.is_type_val) return null;
|
||||||
if (decl.node.cast(ast.Node.FnProto)) |fn_decl| {
|
const decl_node = switch (decl.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => return null,
|
||||||
|
};
|
||||||
|
if (decl_node.cast(ast.Node.FnProto)) |fn_decl| {
|
||||||
var has_self_param: u8 = 0;
|
var has_self_param: u8 = 0;
|
||||||
if (call.lhs.cast(ast.Node.InfixOp)) |lhs_infix_op| {
|
if (call.lhs.cast(ast.Node.InfixOp)) |lhs_infix_op| {
|
||||||
if (lhs_infix_op.op == .Period) {
|
if (lhs_infix_op.op == .Period) {
|
||||||
@ -565,13 +593,14 @@ fn resolveTypeOfNodeInternal(
|
|||||||
.node = call.paramsConst()[param_idx - has_self_param],
|
.node = call.paramsConst()[param_idx - has_self_param],
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
}, bound_type_params)) orelse continue;
|
}, bound_type_params)) orelse continue;
|
||||||
|
if (!call_param_type.type.is_type_val) continue;
|
||||||
|
|
||||||
_ = try bound_type_params.put(decl_param, call_param_type);
|
_ = try bound_type_params.put(decl_param, call_param_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
return try resolveReturnType(store, arena, fn_decl, decl.handle, bound_type_params);
|
return try resolveReturnType(store, arena, fn_decl, decl.handle, bound_type_params);
|
||||||
}
|
}
|
||||||
return decl;
|
return null;
|
||||||
},
|
},
|
||||||
.GroupedExpression => {
|
.GroupedExpression => {
|
||||||
const grouped = node.cast(ast.Node.GroupedExpression).?;
|
const grouped = node.cast(ast.Node.GroupedExpression).?;
|
||||||
@ -579,7 +608,12 @@ fn resolveTypeOfNodeInternal(
|
|||||||
},
|
},
|
||||||
.StructInitializer => {
|
.StructInitializer => {
|
||||||
const struct_init = node.cast(ast.Node.StructInitializer).?;
|
const struct_init = node.cast(ast.Node.StructInitializer).?;
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{ .node = struct_init.lhs, .handle = handle }, bound_type_params);
|
return ((try resolveTypeOfNodeInternal(
|
||||||
|
store,
|
||||||
|
arena,
|
||||||
|
.{ .node = struct_init.lhs, .handle = handle },
|
||||||
|
bound_type_params,
|
||||||
|
)) orelse return null).instanceTypeVal();
|
||||||
},
|
},
|
||||||
.ErrorSetDecl => {
|
.ErrorSetDecl => {
|
||||||
const set = node.cast(ast.Node.ErrorSetDecl).?;
|
const set = node.cast(ast.Node.ErrorSetDecl).?;
|
||||||
@ -587,7 +621,7 @@ fn resolveTypeOfNodeInternal(
|
|||||||
while (set.iterate(i)) |decl| : (i += 1) {
|
while (set.iterate(i)) |decl| : (i += 1) {
|
||||||
try store.error_completions.add(handle.tree, decl);
|
try store.error_completions.add(handle.tree, decl);
|
||||||
}
|
}
|
||||||
return node_handle;
|
return TypeWithHandle.typeVal(node_handle);
|
||||||
},
|
},
|
||||||
.SuffixOp => {
|
.SuffixOp => {
|
||||||
const suffix_op = node.cast(ast.Node.SuffixOp).?;
|
const suffix_op = node.cast(ast.Node.SuffixOp).?;
|
||||||
@ -619,7 +653,18 @@ fn resolveTypeOfNodeInternal(
|
|||||||
bound_type_params,
|
bound_type_params,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (try lookupSymbolContainer(store, arena, left_type, rhs_str, true)) |child| {
|
const left_type_node = switch (left_type.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => return null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (try lookupSymbolContainer(
|
||||||
|
store,
|
||||||
|
arena,
|
||||||
|
.{ .node = left_type_node, .handle = left_type.handle },
|
||||||
|
rhs_str,
|
||||||
|
!left_type.type.is_type_val,
|
||||||
|
)) |child| {
|
||||||
return try child.resolveType(store, arena, bound_type_params);
|
return try child.resolveType(store, arena, bound_type_params);
|
||||||
} else return null;
|
} else return null;
|
||||||
},
|
},
|
||||||
@ -637,7 +682,7 @@ fn resolveTypeOfNodeInternal(
|
|||||||
}, bound_type_params)) orelse return null;
|
}, bound_type_params)) orelse return null;
|
||||||
return try resolveUnwrapErrorType(store, arena, left_type, bound_type_params);
|
return try resolveUnwrapErrorType(store, arena, left_type, bound_type_params);
|
||||||
},
|
},
|
||||||
.ErrorUnion => return node_handle,
|
.ErrorUnion => return TypeWithHandle.typeVal(node_handle),
|
||||||
else => return null,
|
else => return null,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -648,7 +693,7 @@ fn resolveTypeOfNodeInternal(
|
|||||||
.ArrayType,
|
.ArrayType,
|
||||||
.OptionalType,
|
.OptionalType,
|
||||||
.PtrType,
|
.PtrType,
|
||||||
=> return node_handle,
|
=> return TypeWithHandle.typeVal(node_handle),
|
||||||
.Try => {
|
.Try => {
|
||||||
const rhs_type = (try resolveTypeOfNodeInternal(store, arena, .{
|
const rhs_type = (try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = prefix_op.rhs,
|
.node = prefix_op.rhs,
|
||||||
@ -682,10 +727,24 @@ fn resolveTypeOfNodeInternal(
|
|||||||
});
|
});
|
||||||
if (cast_map.has(call_name)) {
|
if (cast_map.has(call_name)) {
|
||||||
if (builtin_call.params_len < 1) return null;
|
if (builtin_call.params_len < 1) return null;
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{
|
return ((try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
.node = builtin_call.paramsConst()[0],
|
.node = builtin_call.paramsConst()[0],
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
}, bound_type_params);
|
}, bound_type_params)) orelse return null).instanceTypeVal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Almost the same as the above, return a type value though.
|
||||||
|
// TODO Do peer type resolution, we just keep the first for now.
|
||||||
|
if (std.mem.eql(u8, call_name, "@TypeOf")) {
|
||||||
|
if (builtin_call.params_len < 1) return null;
|
||||||
|
var resolved_type = (try resolveTypeOfNodeInternal(store, arena, .{
|
||||||
|
.node = builtin_call.paramsConst()[0],
|
||||||
|
.handle = handle,
|
||||||
|
}, bound_type_params)) orelse return null;
|
||||||
|
|
||||||
|
if (resolved_type.type.is_type_val) return null;
|
||||||
|
resolved_type.type.is_type_val = true;
|
||||||
|
return resolved_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!std.mem.eql(u8, call_name, "@import")) return null;
|
if (!std.mem.eql(u8, call_name, "@import")) return null;
|
||||||
@ -700,14 +759,14 @@ fn resolveTypeOfNodeInternal(
|
|||||||
return null;
|
return null;
|
||||||
}) orelse return null;
|
}) orelse return null;
|
||||||
|
|
||||||
return NodeWithHandle{ .node = &new_handle.tree.root_node.base, .handle = new_handle };
|
return TypeWithHandle.typeVal(.{ .node = &new_handle.tree.root_node.base, .handle = new_handle });
|
||||||
},
|
},
|
||||||
.ContainerDecl => {
|
.ContainerDecl => {
|
||||||
const container = node.cast(ast.Node.ContainerDecl).?;
|
const container = node.cast(ast.Node.ContainerDecl).?;
|
||||||
const kind = handle.tree.token_ids[container.kind_token];
|
const kind = handle.tree.token_ids[container.kind_token];
|
||||||
|
|
||||||
if (kind == .Keyword_struct or (kind == .Keyword_union and container.init_arg_expr == .None)) {
|
if (kind == .Keyword_struct or (kind == .Keyword_union and container.init_arg_expr == .None)) {
|
||||||
return node_handle;
|
return TypeWithHandle.typeVal(node_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
@ -715,15 +774,63 @@ fn resolveTypeOfNodeInternal(
|
|||||||
if (decl.id != .ContainerField) continue;
|
if (decl.id != .ContainerField) continue;
|
||||||
try store.enum_completions.add(handle.tree, decl);
|
try store.enum_completions.add(handle.tree, decl);
|
||||||
}
|
}
|
||||||
return node_handle;
|
return TypeWithHandle.typeVal(node_handle);
|
||||||
|
},
|
||||||
|
.FnProto => {
|
||||||
|
// This is a function type
|
||||||
|
if (node.cast(ast.Node.FnProto).?.name_token == null) {
|
||||||
|
return TypeWithHandle.typeVal(node_handle);
|
||||||
|
}
|
||||||
|
return TypeWithHandle{
|
||||||
|
.type = .{ .data = .{ .other = node }, .is_type_val = false },
|
||||||
|
.handle = handle,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
.MultilineStringLiteral, .StringLiteral => return TypeWithHandle{
|
||||||
|
.type = .{ .data = .{ .other = node }, .is_type_val = false },
|
||||||
|
.handle = handle,
|
||||||
},
|
},
|
||||||
.MultilineStringLiteral, .StringLiteral, .FnProto => return node_handle,
|
|
||||||
else => std.debug.warn("Type resolution case not implemented; {}\n", .{node.id}),
|
else => std.debug.warn("Type resolution case not implemented; {}\n", .{node.id}),
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn resolveTypeOfNode(store: *DocumentStore, arena: *std.heap.ArenaAllocator, node_handle: NodeWithHandle) error{OutOfMemory}!?NodeWithHandle {
|
// TODO Reorganize this file, perhaps split into a couple as well
|
||||||
|
// TODO Make this better, nested levels of type vals
|
||||||
|
pub const Type = struct {
|
||||||
|
data: union(enum) {
|
||||||
|
slice: *ast.Node,
|
||||||
|
error_union: *ast.Node,
|
||||||
|
other: *ast.Node,
|
||||||
|
},
|
||||||
|
/// If true, the type `type`, the attached data is the value of the type value.
|
||||||
|
is_type_val: bool,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const TypeWithHandle = struct {
|
||||||
|
type: Type,
|
||||||
|
handle: *DocumentStore.Handle,
|
||||||
|
|
||||||
|
fn typeVal(node_handle: NodeWithHandle) TypeWithHandle {
|
||||||
|
return .{
|
||||||
|
.type = .{
|
||||||
|
.data = .{ .other = node_handle.node },
|
||||||
|
.is_type_val = true,
|
||||||
|
},
|
||||||
|
.handle = node_handle.handle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instanceTypeVal(self: TypeWithHandle) ?TypeWithHandle {
|
||||||
|
if (!self.type.is_type_val) return null;
|
||||||
|
return TypeWithHandle{
|
||||||
|
.type = .{ .data = self.type.data, .is_type_val = false },
|
||||||
|
.handle = self.handle,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn resolveTypeOfNode(store: *DocumentStore, arena: *std.heap.ArenaAllocator, node_handle: NodeWithHandle) error{OutOfMemory}!?TypeWithHandle {
|
||||||
var bound_type_params = BoundTypeParams.init(&arena.allocator);
|
var bound_type_params = BoundTypeParams.init(&arena.allocator);
|
||||||
return resolveTypeOfNodeInternal(store, arena, node_handle, &bound_type_params);
|
return resolveTypeOfNodeInternal(store, arena, node_handle, &bound_type_params);
|
||||||
}
|
}
|
||||||
@ -773,17 +880,17 @@ pub const NodeWithHandle = struct {
|
|||||||
handle: *DocumentStore.Handle,
|
handle: *DocumentStore.Handle,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn getFieldAccessTypeNode(
|
pub fn getFieldAccessType(
|
||||||
store: *DocumentStore,
|
store: *DocumentStore,
|
||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
handle: *DocumentStore.Handle,
|
handle: *DocumentStore.Handle,
|
||||||
source_index: usize,
|
source_index: usize,
|
||||||
tokenizer: *std.zig.Tokenizer,
|
tokenizer: *std.zig.Tokenizer,
|
||||||
) !?NodeWithHandle {
|
) !?TypeWithHandle {
|
||||||
var current_node = NodeWithHandle{
|
var current_type = TypeWithHandle.typeVal(.{
|
||||||
.node = &handle.tree.root_node.base,
|
.node = &handle.tree.root_node.base,
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
};
|
});
|
||||||
|
|
||||||
// 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.
|
||||||
var bound_type_params = BoundTypeParams.init(&arena.allocator);
|
var bound_type_params = BoundTypeParams.init(&arena.allocator);
|
||||||
@ -791,27 +898,38 @@ pub fn getFieldAccessTypeNode(
|
|||||||
while (true) {
|
while (true) {
|
||||||
const tok = tokenizer.next();
|
const tok = tokenizer.next();
|
||||||
switch (tok.id) {
|
switch (tok.id) {
|
||||||
.Eof => return try resolveFieldAccessLhsType(store, arena, current_node, &bound_type_params),
|
.Eof => return try resolveFieldAccessLhsType(store, arena, current_type, &bound_type_params),
|
||||||
.Identifier => {
|
.Identifier => {
|
||||||
if (try lookupSymbolGlobal(store, arena, current_node.handle, tokenizer.buffer[tok.loc.start..tok.loc.end], source_index)) |child| {
|
if (try lookupSymbolGlobal(store, arena, current_type.handle, tokenizer.buffer[tok.loc.start..tok.loc.end], source_index)) |child| {
|
||||||
current_node = (try child.resolveType(store, arena, &bound_type_params)) orelse return null;
|
current_type = (try child.resolveType(store, arena, &bound_type_params)) orelse return null;
|
||||||
} else return null;
|
} else return null;
|
||||||
},
|
},
|
||||||
.Period => {
|
.Period => {
|
||||||
const after_period = tokenizer.next();
|
const after_period = tokenizer.next();
|
||||||
switch (after_period.id) {
|
switch (after_period.id) {
|
||||||
.Eof => return try resolveFieldAccessLhsType(store, arena, current_node, &bound_type_params),
|
.Eof => return try resolveFieldAccessLhsType(store, arena, current_type, &bound_type_params),
|
||||||
.Identifier => {
|
.Identifier => {
|
||||||
if (after_period.loc.end == tokenizer.buffer.len)
|
if (after_period.loc.end == tokenizer.buffer.len)
|
||||||
return try resolveFieldAccessLhsType(store, arena, current_node, &bound_type_params);
|
return try resolveFieldAccessLhsType(store, arena, current_type, &bound_type_params);
|
||||||
|
|
||||||
current_node = try resolveFieldAccessLhsType(store, arena, current_node, &bound_type_params);
|
current_type = try resolveFieldAccessLhsType(store, arena, current_type, &bound_type_params);
|
||||||
if (try lookupSymbolContainer(store, arena, current_node, tokenizer.buffer[after_period.loc.start..after_period.loc.end], true)) |child| {
|
const current_type_node = switch (current_type.type.data) {
|
||||||
current_node = (try child.resolveType(store, arena, &bound_type_params)) orelse return null;
|
.other => |n| n,
|
||||||
|
else => return null,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (try lookupSymbolContainer(
|
||||||
|
store,
|
||||||
|
arena,
|
||||||
|
.{ .node = current_type_node, .handle = current_type.handle },
|
||||||
|
tokenizer.buffer[after_period.loc.start..after_period.loc.end],
|
||||||
|
!current_type.type.is_type_val,
|
||||||
|
)) |child| {
|
||||||
|
current_type = (try child.resolveType(store, arena, &bound_type_params)) orelse return null;
|
||||||
} else return null;
|
} else return null;
|
||||||
},
|
},
|
||||||
.QuestionMark => {
|
.QuestionMark => {
|
||||||
current_node = (try resolveUnwrapOptionalType(store, arena, current_node, &bound_type_params)) orelse return null;
|
current_type = (try resolveUnwrapOptionalType(store, arena, current_type, &bound_type_params)) orelse return null;
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
std.debug.warn("Unrecognized token {} after period.\n", .{after_period.id});
|
std.debug.warn("Unrecognized token {} after period.\n", .{after_period.id});
|
||||||
@ -820,14 +938,19 @@ pub fn getFieldAccessTypeNode(
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
.PeriodAsterisk => {
|
.PeriodAsterisk => {
|
||||||
current_node = (try resolveDerefType(store, arena, current_node, &bound_type_params)) orelse return null;
|
current_type = (try resolveDerefType(store, arena, current_type, &bound_type_params)) orelse return null;
|
||||||
},
|
},
|
||||||
.LParen => {
|
.LParen => {
|
||||||
switch (current_node.node.id) {
|
const current_type_node = switch (current_type.type.data) {
|
||||||
.FnProto => {
|
.other => |n| n,
|
||||||
const func = current_node.node.cast(ast.Node.FnProto).?;
|
else => return null,
|
||||||
if (try resolveReturnType(store, arena, func, current_node.handle, &bound_type_params)) |ret| {
|
};
|
||||||
current_node = ret;
|
|
||||||
|
// Can't call a function type, we need a function type instance.
|
||||||
|
if (current_type.type.is_type_val) return null;
|
||||||
|
if (current_type_node.cast(ast.Node.FnProto)) |func| {
|
||||||
|
if (try resolveReturnType(store, arena, func, current_type.handle, &bound_type_params)) |ret| {
|
||||||
|
current_type = ret;
|
||||||
// Skip to the right paren
|
// Skip to the right paren
|
||||||
var paren_count: usize = 1;
|
var paren_count: usize = 1;
|
||||||
var next = tokenizer.next();
|
var next = tokenizer.next();
|
||||||
@ -840,9 +963,7 @@ pub fn getFieldAccessTypeNode(
|
|||||||
}
|
}
|
||||||
} else return null;
|
} else return null;
|
||||||
} else return null;
|
} else return null;
|
||||||
},
|
} else return null;
|
||||||
else => {},
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
.LBracket => {
|
.LBracket => {
|
||||||
var brack_count: usize = 1;
|
var brack_count: usize = 1;
|
||||||
@ -859,7 +980,7 @@ pub fn getFieldAccessTypeNode(
|
|||||||
}
|
}
|
||||||
} else return null;
|
} else return null;
|
||||||
|
|
||||||
current_node = (try resolveBracketAccessType(store, arena, current_node, if (is_range) .Range else .Single, &bound_type_params)) orelse return null;
|
current_type = (try resolveBracketAccessType(store, arena, current_type, if (is_range) .Range else .Single, &bound_type_params)) orelse return null;
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
std.debug.warn("Unimplemented token: {}\n", .{tok.id});
|
std.debug.warn("Unimplemented token: {}\n", .{tok.id});
|
||||||
@ -868,7 +989,7 @@ pub fn getFieldAccessTypeNode(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return try resolveFieldAccessLhsType(store, arena, current_node, &bound_type_params);
|
return try resolveFieldAccessLhsType(store, arena, current_type, &bound_type_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn isNodePublic(tree: *ast.Tree, node: *ast.Node) bool {
|
pub fn isNodePublic(tree: *ast.Tree, node: *ast.Node) bool {
|
||||||
@ -1053,6 +1174,8 @@ pub fn documentPositionContext(allocator: *std.mem.Allocator, document: types.Te
|
|||||||
.Keyword_break, .Keyword_continue => curr_ctx.ctx = .pre_label,
|
.Keyword_break, .Keyword_continue => curr_ctx.ctx = .pre_label,
|
||||||
.Colon => if (curr_ctx.ctx == .pre_label) {
|
.Colon => if (curr_ctx.ctx == .pre_label) {
|
||||||
curr_ctx.ctx = .label;
|
curr_ctx.ctx = .label;
|
||||||
|
} else {
|
||||||
|
curr_ctx.ctx = .empty;
|
||||||
},
|
},
|
||||||
.QuestionMark => switch (curr_ctx.ctx) {
|
.QuestionMark => switch (curr_ctx.ctx) {
|
||||||
.field_access => {},
|
.field_access => {},
|
||||||
@ -1215,7 +1338,7 @@ pub const DeclWithHandle = struct {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveType(self: DeclWithHandle, store: *DocumentStore, arena: *std.heap.ArenaAllocator, bound_type_params: *BoundTypeParams) !?NodeWithHandle {
|
fn resolveType(self: DeclWithHandle, store: *DocumentStore, arena: *std.heap.ArenaAllocator, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
|
||||||
return switch (self.decl.*) {
|
return switch (self.decl.*) {
|
||||||
.ast_node => |node| try resolveTypeOfNodeInternal(store, arena, .{ .node = node, .handle = self.handle }, bound_type_params),
|
.ast_node => |node| try resolveTypeOfNodeInternal(store, arena, .{ .node = node, .handle = self.handle }, bound_type_params),
|
||||||
.param_decl => |param_decl| switch (param_decl.param_type) {
|
.param_decl => |param_decl| switch (param_decl.param_type) {
|
||||||
@ -1227,7 +1350,12 @@ pub const DeclWithHandle = struct {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return try resolveTypeOfNodeInternal(store, arena, .{ .node = type_node, .handle = self.handle }, bound_type_params);
|
return ((try resolveTypeOfNodeInternal(
|
||||||
|
store,
|
||||||
|
arena,
|
||||||
|
.{ .node = type_node, .handle = self.handle },
|
||||||
|
bound_type_params,
|
||||||
|
)) orelse return null).instanceTypeVal();
|
||||||
},
|
},
|
||||||
else => null,
|
else => null,
|
||||||
},
|
},
|
||||||
@ -1304,7 +1432,11 @@ pub fn iterateSymbolsContainer(
|
|||||||
for (container_scope.uses) |use| {
|
for (container_scope.uses) |use| {
|
||||||
if (handle != orig_handle and use.visib_token == null) continue;
|
if (handle != orig_handle and use.visib_token == null) continue;
|
||||||
const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = use.expr, .handle = handle })) orelse continue;
|
const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = use.expr, .handle = handle })) orelse continue;
|
||||||
try iterateSymbolsContainer(store, arena, use_expr, orig_handle, callback, context, false);
|
const use_expr_node = switch (use_expr.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
try iterateSymbolsContainer(store, arena, .{ .node = use_expr_node, .handle = use_expr.handle }, orig_handle, callback, context, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1351,7 +1483,11 @@ pub fn iterateSymbolsGlobal(
|
|||||||
|
|
||||||
for (scope.uses) |use| {
|
for (scope.uses) |use| {
|
||||||
const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = use.expr, .handle = handle })) orelse continue;
|
const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = use.expr, .handle = handle })) orelse continue;
|
||||||
try iterateSymbolsContainer(store, arena, use_expr, handle, callback, context, false);
|
const use_expr_node = switch (use_expr.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
try iterateSymbolsContainer(store, arena, .{ .node = use_expr_node, .handle = use_expr.handle }, handle, callback, context, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1359,9 +1495,9 @@ pub fn iterateSymbolsGlobal(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn innermostContainer(handle: *DocumentStore.Handle, source_index: usize) NodeWithHandle {
|
pub fn innermostContainer(handle: *DocumentStore.Handle, source_index: usize) TypeWithHandle {
|
||||||
var current = handle.document_scope.scopes[0].data.container;
|
var current = handle.document_scope.scopes[0].data.container;
|
||||||
if (handle.document_scope.scopes.len == 1) return .{ .node = current, .handle = handle };
|
if (handle.document_scope.scopes.len == 1) return TypeWithHandle.typeVal(.{ .node = current, .handle = handle });
|
||||||
|
|
||||||
for (handle.document_scope.scopes[1..]) |scope| {
|
for (handle.document_scope.scopes[1..]) |scope| {
|
||||||
if (source_index >= scope.range.start and source_index < scope.range.end) {
|
if (source_index >= scope.range.start and source_index < scope.range.end) {
|
||||||
@ -1372,7 +1508,7 @@ pub fn innermostContainer(handle: *DocumentStore.Handle, source_index: usize) No
|
|||||||
}
|
}
|
||||||
if (scope.range.start > source_index) break;
|
if (scope.range.start > source_index) break;
|
||||||
}
|
}
|
||||||
return .{ .node = current, .handle = handle };
|
return TypeWithHandle.typeVal(.{ .node = current, .handle = handle });
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolveUse(
|
fn resolveUse(
|
||||||
@ -1384,7 +1520,11 @@ fn resolveUse(
|
|||||||
) error{OutOfMemory}!?DeclWithHandle {
|
) error{OutOfMemory}!?DeclWithHandle {
|
||||||
for (uses) |use| {
|
for (uses) |use| {
|
||||||
const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = use.expr, .handle = handle })) orelse continue;
|
const use_expr = (try resolveTypeOfNode(store, arena, .{ .node = use.expr, .handle = handle })) orelse continue;
|
||||||
if (try lookupSymbolContainer(store, arena, use_expr, symbol, false)) |candidate| {
|
const use_expr_node = switch (use_expr.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => continue,
|
||||||
|
};
|
||||||
|
if (try lookupSymbolContainer(store, arena, .{ .node = use_expr_node, .handle = use_expr.handle }, symbol, false)) |candidate| {
|
||||||
if (candidate.handle != handle and !candidate.isPublic()) {
|
if (candidate.handle != handle and !candidate.isPublic()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
70
src/main.zig
70
src/main.zig
@ -202,11 +202,44 @@ fn publishDiagnostics(handle: DocumentStore.Handle, config: Config) !void {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn typeToCompletion(
|
||||||
|
arena: *std.heap.ArenaAllocator,
|
||||||
|
list: *std.ArrayList(types.CompletionItem),
|
||||||
|
type_handle: analysis.TypeWithHandle,
|
||||||
|
orig_handle: *DocumentStore.Handle,
|
||||||
|
config: Config,
|
||||||
|
) error{OutOfMemory}!void {
|
||||||
|
switch (type_handle.type.data) {
|
||||||
|
.slice => {
|
||||||
|
if (!type_handle.type.is_type_val) {
|
||||||
|
try list.append(.{
|
||||||
|
.label = "len",
|
||||||
|
.kind = .Field,
|
||||||
|
});
|
||||||
|
try list.append(.{
|
||||||
|
.label = "ptr",
|
||||||
|
.kind = .Field,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.error_union => {},
|
||||||
|
.other => |n| try nodeToCompletion(
|
||||||
|
arena,
|
||||||
|
list,
|
||||||
|
.{ .node = n, .handle = type_handle.handle },
|
||||||
|
orig_handle,
|
||||||
|
type_handle.type.is_type_val,
|
||||||
|
config,
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn nodeToCompletion(
|
fn nodeToCompletion(
|
||||||
arena: *std.heap.ArenaAllocator,
|
arena: *std.heap.ArenaAllocator,
|
||||||
list: *std.ArrayList(types.CompletionItem),
|
list: *std.ArrayList(types.CompletionItem),
|
||||||
node_handle: analysis.NodeWithHandle,
|
node_handle: analysis.NodeWithHandle,
|
||||||
orig_handle: *DocumentStore.Handle,
|
orig_handle: *DocumentStore.Handle,
|
||||||
|
is_type_val: bool,
|
||||||
config: Config,
|
config: Config,
|
||||||
) error{OutOfMemory}!void {
|
) error{OutOfMemory}!void {
|
||||||
const node = node_handle.node;
|
const node = node_handle.node;
|
||||||
@ -226,31 +259,36 @@ fn nodeToCompletion(
|
|||||||
else
|
else
|
||||||
null;
|
null;
|
||||||
|
|
||||||
switch (node.id) {
|
if (node.id == .ErrorSetDecl or node.id == .Root or node.id == .ContainerDecl) {
|
||||||
.ErrorSetDecl, .Root, .ContainerDecl => {
|
|
||||||
const context = DeclToCompletionContext{
|
const context = DeclToCompletionContext{
|
||||||
.completions = list,
|
.completions = list,
|
||||||
.config = &config,
|
.config = &config,
|
||||||
.arena = arena,
|
.arena = arena,
|
||||||
.orig_handle = orig_handle,
|
.orig_handle = orig_handle,
|
||||||
};
|
};
|
||||||
try analysis.iterateSymbolsContainer(&document_store, arena, node_handle, orig_handle, declToCompletion, context, true);
|
try analysis.iterateSymbolsContainer(&document_store, arena, node_handle, orig_handle, declToCompletion, context, !is_type_val);
|
||||||
},
|
}
|
||||||
|
|
||||||
|
if (is_type_val) return;
|
||||||
|
|
||||||
|
switch (node.id) {
|
||||||
.FnProto => {
|
.FnProto => {
|
||||||
const func = node.cast(std.zig.ast.Node.FnProto).?;
|
const func = node.cast(std.zig.ast.Node.FnProto).?;
|
||||||
if (func.name_token) |name_token| {
|
if (func.name_token) |name_token| {
|
||||||
const use_snippets = config.enable_snippets and client_capabilities.supports_snippets;
|
const use_snippets = config.enable_snippets and client_capabilities.supports_snippets;
|
||||||
|
|
||||||
const insert_text = if (use_snippets) blk: {
|
const insert_text = if (use_snippets) blk: {
|
||||||
|
// TODO Also check if we are dot accessing from a type val and dont skip in that case.
|
||||||
const skip_self_param = if (func.params_len > 0) param_check: {
|
const skip_self_param = if (func.params_len > 0) param_check: {
|
||||||
const in_container = analysis.innermostContainer(handle, handle.tree.token_locs[func.firstToken()].start);
|
const in_container = analysis.innermostContainer(handle, handle.tree.token_locs[func.firstToken()].start);
|
||||||
|
|
||||||
switch (func.paramsConst()[0].param_type) {
|
switch (func.paramsConst()[0].param_type) {
|
||||||
.type_expr => |type_node| {
|
.type_expr => |type_node| {
|
||||||
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
if (try analysis.resolveTypeOfNode(&document_store, arena, .{
|
||||||
.node = type_node,
|
.node = type_node,
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
})) |resolved_type| {
|
})) |resolved_type| {
|
||||||
if (in_container.node == resolved_type.node)
|
if (std.meta.eql(in_container, resolved_type))
|
||||||
break :param_check true;
|
break :param_check true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -260,7 +298,7 @@ fn nodeToCompletion(
|
|||||||
.node = prefix_op.rhs,
|
.node = prefix_op.rhs,
|
||||||
.handle = handle,
|
.handle = handle,
|
||||||
})) |resolved_prefix_op| {
|
})) |resolved_prefix_op| {
|
||||||
if (in_container.node == resolved_prefix_op.node)
|
if (std.meta.eql(in_container, resolved_prefix_op))
|
||||||
break :param_check true;
|
break :param_check true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -548,8 +586,18 @@ fn getSymbolFieldAccess(
|
|||||||
const line = try handle.document.getLine(@intCast(usize, position.line));
|
const line = try handle.document.getLine(@intCast(usize, position.line));
|
||||||
var tokenizer = std.zig.Tokenizer.init(line[range.start..range.end]);
|
var tokenizer = std.zig.Tokenizer.init(line[range.start..range.end]);
|
||||||
|
|
||||||
if (try analysis.getFieldAccessTypeNode(&document_store, arena, handle, pos_index, &tokenizer)) |container_handle| {
|
if (try analysis.getFieldAccessType(&document_store, arena, handle, pos_index, &tokenizer)) |container_handle| {
|
||||||
return try analysis.lookupSymbolContainer(&document_store, arena, container_handle, name, true);
|
const container_handle_node = switch (container_handle.type.data) {
|
||||||
|
.other => |n| n,
|
||||||
|
else => return null,
|
||||||
|
};
|
||||||
|
return try analysis.lookupSymbolContainer(
|
||||||
|
&document_store,
|
||||||
|
arena,
|
||||||
|
.{ .node = container_handle_node, .handle = container_handle.handle },
|
||||||
|
name,
|
||||||
|
true,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -621,7 +669,7 @@ fn declToCompletion(context: DeclToCompletionContext, decl_handle: analysis.Decl
|
|||||||
const tree = decl_handle.handle.tree;
|
const tree = decl_handle.handle.tree;
|
||||||
|
|
||||||
switch (decl_handle.decl.*) {
|
switch (decl_handle.decl.*) {
|
||||||
.ast_node => |node| try nodeToCompletion(context.arena, context.completions, .{ .node = node, .handle = decl_handle.handle }, context.orig_handle, context.config.*),
|
.ast_node => |node| try nodeToCompletion(context.arena, context.completions, .{ .node = node, .handle = decl_handle.handle }, context.orig_handle, false, context.config.*),
|
||||||
.param_decl => |param| {
|
.param_decl => |param| {
|
||||||
const doc_kind: types.MarkupKind = if (client_capabilities.completion_doc_supports_md) .Markdown else .PlainText;
|
const doc_kind: types.MarkupKind = if (client_capabilities.completion_doc_supports_md) .Markdown else .PlainText;
|
||||||
const doc = if (param.doc_comments) |doc_comments|
|
const doc = if (param.doc_comments) |doc_comments|
|
||||||
@ -728,8 +776,8 @@ fn completeFieldAccess(id: types.RequestId, handle: *DocumentStore.Handle, posit
|
|||||||
var tokenizer = std.zig.Tokenizer.init(line[range.start..range.end]);
|
var tokenizer = std.zig.Tokenizer.init(line[range.start..range.end]);
|
||||||
|
|
||||||
const pos_index = try handle.document.positionToIndex(position);
|
const pos_index = try handle.document.positionToIndex(position);
|
||||||
if (try analysis.getFieldAccessTypeNode(&document_store, &arena, handle, pos_index, &tokenizer)) |node| {
|
if (try analysis.getFieldAccessType(&document_store, &arena, handle, pos_index, &tokenizer)) |node| {
|
||||||
try nodeToCompletion(&arena, &completions, node, handle, config);
|
try typeToCompletion(&arena, &completions, node, handle, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
try send(types.Response{
|
try send(types.Response{
|
||||||
|
Loading…
Reference in New Issue
Block a user