Type resolving fixes

This commit is contained in:
Luuk de Gram 2021-02-28 21:57:15 +01:00
parent 96fcac89a4
commit b651a79380
No known key found for this signature in database
GPG Key ID: A002B174963DBB7D

View File

@ -132,7 +132,7 @@ pub fn getFunctionSnippet(allocator: *std.mem.Allocator, tree: ast.Tree, func: *
if (curr_token == end_token and is_comma) continue; if (curr_token == end_token and is_comma) continue;
try buffer.appendSlice(tree.tokenSlice(curr_token)); try buffer.appendSlice(tree.tokenSlice(curr_token));
if (is_comma or tag == .Keyword_const) try buffer.append(' '); if (is_comma or tag == .keyword_const) try buffer.append(' ');
} }
} }
try buffer.append('}'); try buffer.append('}');
@ -240,7 +240,7 @@ fn getDeclName(tree: ast.Tree, node: ast.Node.Index) ?[]const u8 {
fn isContainerDecl(decl_handle: DeclWithHandle) bool { fn isContainerDecl(decl_handle: DeclWithHandle) bool {
return switch (decl_handle.decl.*) { return switch (decl_handle.decl.*) {
.ast_node => |inner_node| inner_node.tag == .ContainerDecl or inner_node.tag == .Root, .ast_node => |inner_node| isContainer(decl_handle.handle.tree.nodes.items(.tag)[inner_node]) or inner_node == 0,
else => false, else => false,
}; };
} }
@ -370,21 +370,18 @@ fn resolveUnwrapOptionalType(
arena: *std.heap.ArenaAllocator, arena: *std.heap.ArenaAllocator,
opt: TypeWithHandle, opt: TypeWithHandle,
bound_type_params: *BoundTypeParams, bound_type_params: *BoundTypeParams,
tree: ast.Tree,
) !?TypeWithHandle { ) !?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_node.cast(ast.Node.SimplePrefixOp)) |prefix_op| { if (opt.handle.tree.nodes.items(.tag)[opt_node] == .optional_type) {
if (opt_node.tag == .OptionalType) {
return ((try resolveTypeOfNodeInternal(store, arena, .{ return ((try resolveTypeOfNodeInternal(store, arena, .{
.node = prefix_op.rhs, .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();
} }
}
return null; return null;
} }
@ -403,15 +400,12 @@ fn resolveUnwrapErrorType(
}, },
.primitive, .slice, .pointer => return null, .primitive, .slice, .pointer => return null,
}; };
if (rhs.handle.tree.nodes.items(.tag)[rhs_node] == .error_union) {
if (rhs_node.cast(ast.Node.SimpleInfixOp)) |infix_op| {
if (rhs_node.tag == .ErrorUnion) {
return ((try resolveTypeOfNodeInternal(store, arena, .{ return ((try resolveTypeOfNodeInternal(store, arena, .{
.node = infix_op.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();
} }
}
return null; return null;
} }
@ -470,32 +464,27 @@ fn resolveBracketAccessType(
else => return null, else => return null,
}; };
if (lhs_node.castTag(.SliceType)) |slice_type| { const tags = lhs.handle.tree.nodes.items(.tag);
const tag = tags[lhs_node];
const data = lhs.handle.tree.nodes.items(.data)[lhs_node];
if (tag == .array_type or tag == .array_type_sentinel) {
if (rhs == .Single) if (rhs == .Single)
return ((try resolveTypeOfNodeInternal(store, arena, .{ return ((try resolveTypeOfNodeInternal(store, arena, .{
.node = slice_type.rhs, .node = data.rhs,
.handle = lhs.handle,
}, bound_type_params)) orelse return null).instanceTypeVal();
return lhs;
} else if (lhs_node.castTag(.ArrayType)) |array_type| {
if (rhs == .Single)
return ((try resolveTypeOfNodeInternal(store, arena, .{
.node = array_type.rhs,
.handle = lhs.handle, .handle = lhs.handle,
}, bound_type_params)) orelse return null).instanceTypeVal(); }, bound_type_params)) orelse return null).instanceTypeVal();
return TypeWithHandle{ return TypeWithHandle{
.type = .{ .data = .{ .slice = array_type.rhs }, .is_type_val = false }, .type = .{ .data = .{ .slice = data.rhs }, .is_type_val = false },
.handle = lhs.handle, .handle = lhs.handle,
}; };
} else if (lhs_node.castTag(.PtrType)) |ptr_type| { } else if (isPtrType(tree, lhs_node)) {
if (ptr_type.rhs.castTag(.ArrayType)) |child_arr| { if (tags[data.rhs] == .array_type or tags[data.rhs] == .array_type_sentinel) {
if (rhs == .Single) { if (rhs == .Single) {
return ((try resolveTypeOfNodeInternal(store, arena, .{ return ((try resolveTypeOfNodeInternal(store, arena, .{
.node = child_arr.rhs, .node = lhs.handle.tree.nodes.items(.data)[data.rhs].rhs,
.handle = lhs.handle, .handle = lhs.handle,
}, bound_type_params)) orelse return null).instanceTypeVal(); }, bound_type_params)) orelse return null).instanceTypeVal();
} }
return lhs;
} }
} }
@ -931,28 +920,26 @@ pub const TypeWithHandle = struct {
fn isRoot(self: TypeWithHandle) bool { fn isRoot(self: TypeWithHandle) bool {
switch (self.type.data) { switch (self.type.data) {
.other => |n| return n.tag == .Root, // root is always index 0
.other => |n| return n == 0,
else => return false, else => return false,
} }
} }
fn isContainer(self: TypeWithHandle, container_kind_tok: std.zig.Token.Id) bool { fn isContainer(self: TypeWithHandle, container_kind_tok: std.zig.Token.Tag, tree: ast.Tree) bool {
const main_tokens = tree.nodes.items(.main_token);
const tags = tree.tokens.items(.tag);
switch (self.type.data) { switch (self.type.data) {
.other => |n| { .other => |n| return tags[main_tokens[n]] == container_kind_tok,
if (n.castTag(.ContainerDecl)) |cont| {
return self.handle.tree.token_ids[cont.kind_token] == container_kind_tok;
}
return false;
},
else => return false, else => return false,
} }
} }
pub fn isStructType(self: TypeWithHandle) bool { pub fn isStructType(self: TypeWithHandle, tree: ast.Tree) bool {
return self.isContainer(.Keyword_struct) or self.isRoot(); return self.isContainer(.keyword_struct, tree) or self.isRoot();
} }
pub fn isNamespace(self: TypeWithHandle) bool { pub fn isNamespace(self: TypeWithHandle, tree: ast.Tree) bool {
if (!self.isStructType()) return false; if (!self.isStructType()) return false;
var idx: usize = 0; var idx: usize = 0;
while (self.type.data.other.iterate(idx)) |child| : (idx += 1) { while (self.type.data.other.iterate(idx)) |child| : (idx += 1) {
@ -962,46 +949,56 @@ pub const TypeWithHandle = struct {
return true; return true;
} }
pub fn isEnumType(self: TypeWithHandle) bool { pub fn isEnumType(self: TypeWithHandle, tree: ast.Tree) bool {
return self.isContainer(.Keyword_enum); return self.isContainer(.keyword_enum, tree);
} }
pub fn isUnionType(self: TypeWithHandle) bool { pub fn isUnionType(self: TypeWithHandle, tree: ast.Tree) bool {
return self.isContainer(.Keyword_union); return self.isContainer(.keyword_union, tree);
} }
pub fn isOpaqueType(self: TypeWithHandle) bool { pub fn isOpaqueType(self: TypeWithHandle, tree: ast.Tree) bool {
return self.isContainer(.Keyword_opaque); return self.isContainer(.keyword_opaque, tree);
} }
pub fn isTypeFunc(self: TypeWithHandle) bool { pub fn isTypeFunc(self: TypeWithHandle, tree: ast.Tree) bool {
var buf: [1]ast.Node.Index = undefined;
switch (self.type.data) { switch (self.type.data) {
.other => |n| { .other => |n| return switch (tree.nodes.items(.tag)[n]) {
if (n.castTag(.FnProto)) |fn_proto| { .fn_proto => isTypeFunction(tree, tree.fnProto(n)),
return isTypeFunction(self.handle.tree, fn_proto); .fn_proto_multi => isTypeFunction(tree, tree.fnProtoMulti(n)),
} .fn_proto_one => isTypeFunction(tree, tree.fnProtoOne(&buf, n)),
return false; .fn_proto_simple => isTypeFunction(tree, tree.fnProtoSimple(&buf, n)),
else => false,
}, },
else => return false, else => return false,
} }
} }
pub fn isGenericFunc(self: TypeWithHandle) bool { pub fn isGenericFunc(self: TypeWithHandle, tree: ast.Tree) bool {
var buf: [1]ast.Node.Index = undefined;
switch (self.type.data) { switch (self.type.data) {
.other => |n| { .other => |n| return switch (tree.nodes.items(.tag)[n]) {
if (n.castTag(.FnProto)) |fn_proto| { .fn_proto => isGenericFunction(tree, tree.fnProto(n)),
return isGenericFunction(self.handle.tree, fn_proto); .fn_proto_multi => isGenericFunction(tree, tree.fnProtoMulti(n)),
} .fn_proto_one => isGenericFunction(tree, tree.fnProtoOne(&buf, n)),
return false; .fn_proto_simple => isGenericFunction(tree, tree.fnProtoSimple(&buf, n)),
else => false,
}, },
else => return false, else => return false,
} }
} }
pub fn isFunc(self: TypeWithHandle) bool { pub fn isFunc(self: TypeWithHandle, tree: ast.Tree) bool {
const tags = tree.nodes.items(.tag);
switch (self.type.data) { switch (self.type.data) {
.other => |n| { .other => |n| return switch (tags[n]) {
return n.tag == .FnProto; .fn_proto,
.fn_proto_multi,
.fn_proto_one,
.fn_proto_simple,
=> true,
else => false,
}, },
else => return false, else => return false,
} }
@ -1100,7 +1097,7 @@ pub fn getFieldAccessType(
}, },
.period => { .period => {
const after_period = tokenizer.next(); const after_period = tokenizer.next();
switch (after_period.id) { switch (after_period.tag) {
.Eof => return FieldAccessReturn{ .Eof => return FieldAccessReturn{
.original = current_type, .original = current_type,
.unwrapped = try resolveDerefType(store, arena, current_type, &bound_type_params), .unwrapped = try resolveDerefType(store, arena, current_type, &bound_type_params),
@ -1133,7 +1130,7 @@ pub fn getFieldAccessType(
current_type = (try resolveUnwrapOptionalType(store, arena, current_type, &bound_type_params)) orelse return null; current_type = (try resolveUnwrapOptionalType(store, arena, current_type, &bound_type_params)) orelse return null;
}, },
else => { else => {
log.debug("Unrecognized token {} after period.", .{after_period.id}); log.debug("Unrecognized token {} after period.", .{after_period.tag});
return null; return null;
}, },
} }
@ -1155,11 +1152,11 @@ pub fn getFieldAccessType(
// 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();
while (next.id != .Eof) : (next = tokenizer.next()) { while (next.tag != .Eof) : (next = tokenizer.next()) {
if (next.id == .RParen) { if (next.tag == .RParen) {
paren_count -= 1; paren_count -= 1;
if (paren_count == 0) break; if (paren_count == 0) break;
} else if (next.id == .LParen) { } else if (next.tag == .LParen) {
paren_count += 1; paren_count += 1;
} }
} else return null; } else return null;
@ -1170,13 +1167,13 @@ pub fn getFieldAccessType(
var brack_count: usize = 1; var brack_count: usize = 1;
var next = tokenizer.next(); var next = tokenizer.next();
var is_range = false; var is_range = false;
while (next.id != .Eof) : (next = tokenizer.next()) { while (next.tag != .Eof) : (next = tokenizer.next()) {
if (next.id == .RBracket) { if (next.tag == .RBracket) {
brack_count -= 1; brack_count -= 1;
if (brack_count == 0) break; if (brack_count == 0) break;
} else if (next.id == .LBracket) { } else if (next.tag == .LBracket) {
brack_count += 1; brack_count += 1;
} else if (next.id == .Ellipsis2 and brack_count == 1) { } else if (next.tag == .Ellipsis2 and brack_count == 1) {
is_range = true; is_range = true;
} }
} else return null; } else return null;
@ -1664,10 +1661,10 @@ pub const Declaration = union(enum) {
name: ast.TokenIndex, name: ast.TokenIndex,
condition: ast.Node.Index, condition: ast.Node.Index,
}, },
array_payload: struct { // array_payload: struct {
identifier: *ast.Node, // identifier: *ast.Node,
array_expr: ast.full.ArrayType, // array_expr: ast.full.ArrayType,
}, // },
switch_payload: struct { switch_payload: struct {
node: ast.TokenIndex, node: ast.TokenIndex,
switch_expr: ast.Node.Index, switch_expr: ast.Node.Index,
@ -1686,7 +1683,7 @@ pub const DeclWithHandle = struct {
.ast_node => |n| getDeclNameToken(tree, n).?, .ast_node => |n| getDeclNameToken(tree, n).?,
.param_decl => |p| p.name_token.?, .param_decl => |p| p.name_token.?,
.pointer_payload => |pp| pp.node.value_symbol.firstToken(), .pointer_payload => |pp| pp.node.value_symbol.firstToken(),
.array_payload => |ap| ap.identifier.firstToken(), // .array_payload => |ap| ap.identifier.firstToken(),
.switch_payload => |sp| sp.node.value_symbol.firstToken(), .switch_payload => |sp| sp.node.value_symbol.firstToken(),
.label_decl => |ld| ld.firstToken(), .label_decl => |ld| ld.firstToken(),
}; };
@ -1705,31 +1702,31 @@ pub const DeclWithHandle = struct {
} }
pub fn resolveType(self: DeclWithHandle, store: *DocumentStore, arena: *std.heap.ArenaAllocator, bound_type_params: *BoundTypeParams) !?TypeWithHandle { pub fn resolveType(self: DeclWithHandle, store: *DocumentStore, arena: *std.heap.ArenaAllocator, bound_type_params: *BoundTypeParams) !?TypeWithHandle {
const tree = self.handle.tree;
const node_tags = tree.nodes.items(.tag);
const main_tokens = tree.nodes.items(.main_token);
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| {
.type_expr => |type_node| { if (typeIsType(self.handle.tree, param_decl.type_expr)) {
if (typeIsType(self.handle.tree, type_node)) {
var bound_param_it = bound_type_params.iterator(); var bound_param_it = bound_type_params.iterator();
while (bound_param_it.next()) |entry| { while (bound_param_it.next()) |entry| {
if (entry.key == param_decl) return entry.value; if (entry.key == param_decl) return entry.value;
} }
return null; return null;
} else if (type_node.castTag(.Identifier)) |type_ident| { } else if (node_tags[param_decl.type_expr] == .identifier) {
if (param_decl.name_token) |name_tok| { if (param_decl.name_token) |name_tok| {
if (std.mem.eql(u8, self.handle.tree.tokenSlice(type_ident.firstToken()), self.handle.tree.tokenSlice(name_tok))) if (std.mem.eql(u8, tree.tokenSlice(tree.firstToken(param_decl.type_expr)), tree.tokenSlice(name_tok)))
return null; return null;
} }
} }
return ((try resolveTypeOfNodeInternal( return ((try resolveTypeOfNodeInternal(
store, store,
arena, arena,
.{ .node = type_node, .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();
}, },
else => null,
},
.pointer_payload => |pay| try resolveUnwrapOptionalType( .pointer_payload => |pay| try resolveUnwrapOptionalType(
store, store,
arena, arena,
@ -1739,16 +1736,16 @@ pub const DeclWithHandle = struct {
}, 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(
store, // store,
arena, // arena,
(try resolveTypeOfNodeInternal(store, arena, .{ // (try resolveTypeOfNodeInternal(store, arena, .{
.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,
.Single, // .Single,
bound_type_params, // bound_type_params,
), // ),
.label_decl => return null, .label_decl => return null,
.switch_payload => |pay| { .switch_payload => |pay| {
if (pay.items.len == 0) return null; if (pay.items.len == 0) return null;
@ -1757,20 +1754,20 @@ pub const DeclWithHandle = struct {
.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;
if (!switch_expr_type.isUnionType()) if (!switch_expr_type.isUnionType(tree))
return null; return null;
if (pay.items[0].castTag(.EnumLiteral)) |enum_lit| { if (node_tags[pay.items[0]] == .enum_literal) {
const scope = findContainerScope(.{ .node = switch_expr_type.type.data.other, .handle = switch_expr_type.handle }) orelse return null; const scope = findContainerScope(.{ .node = switch_expr_type.type.data.other, .handle = switch_expr_type.handle }) orelse return null;
if (scope.decls.getEntry(self.handle.tree.tokenSlice(enum_lit.name))) |candidate| { if (scope.decls.getEntry(self.handle.tree.tokenSlice(main_tokens[pay.items[0]]))) |candidate| {
switch (candidate.value) { switch (candidate.value) {
.ast_node => |node| { .ast_node => |node| {
if (node.castTag(.ContainerField)) |container_field| { if (containerField(tree, node)) |container_field| {
if (container_field.type_expr) |type_expr| { if (container_field.ast.type_expr != 0) {
return ((try resolveTypeOfNodeInternal( return ((try resolveTypeOfNodeInternal(
store, store,
arena, arena,
.{ .node = type_expr, .handle = switch_expr_type.handle }, .{ .node = container_field.ast.type_expr, .handle = switch_expr_type.handle },
bound_type_params, bound_type_params,
)) orelse return null).instanceTypeVal(); )) orelse return null).instanceTypeVal();
} }
@ -1787,6 +1784,15 @@ pub const DeclWithHandle = struct {
} }
}; };
fn containerField(tree: ast.Tree, node: ast.Node.Index) ?ast.full.ContainerField {
return switch (tree.nodes.items(.tag)[node]) {
.container_field => tree.containerField(node),
.container_field_init => tree.containerFieldInit(node),
.container_field_align => tree.containerFieldAlign(node),
else => null,
};
}
fn findContainerScope(container_handle: NodeWithHandle) ?*Scope { fn findContainerScope(container_handle: NodeWithHandle) ?*Scope {
const container = container_handle.node; const container = container_handle.node;
const handle = container_handle.handle; const handle = container_handle.handle;