Skip to content

Commit

Permalink
Fix type resolution for MyTaggedUnion.value
Browse files Browse the repository at this point in the history
  • Loading branch information
FnControlOption committed Jul 17, 2023
1 parent 92dc4f3 commit 6ae797f
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 5 deletions.
83 changes: 81 additions & 2 deletions src/analysis.zig
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,9 @@ pub fn resolveVarDeclAlias(analyser: *Analyser, node_handle: NodeWithHandle) err
if (!resolved.type.is_type_val) return null;

const rhs = datas[node_handle.node].rhs;
break :blk try analyser.lookupSymbolContainer(resolved, tree.tokenSlice(rhs));
break :blk try analyser.lookupSymbolContainerAdvanced(resolved, tree.tokenSlice(rhs), .{
.allow_container_fields = false,
});
},
.global_var_decl,
.local_var_decl,
Expand Down Expand Up @@ -598,7 +600,7 @@ fn resolveUnwrapErrorUnionType(analyser: *Analyser, rhs: TypeWithHandle, side: E
.left => null,
.right => t.*,
},
.primitive, .slice, .pointer, .multi_pointer, .array_index, .@"comptime", .either => return null,
else => return null,
};

if (rhs.handle.tree.nodes.items(.tag)[rhs_node] == .error_union) {
Expand All @@ -615,6 +617,49 @@ fn resolveUnwrapErrorUnionType(analyser: *Analyser, rhs: TypeWithHandle, side: E
return null;
}

fn resolveUnwrapUnionTagType(analyser: *Analyser, type_handle: TypeWithHandle) !?TypeWithHandle {
if (!type_handle.type.is_type_val)
return null;

const node = switch (type_handle.type.data) {
.other => |n| n,
else => return null,
};

if (node == 0)
return null;

const handle = type_handle.handle;
const tree = handle.tree;
const token_tags = tree.tokens.items(.tag);

var buf: [2]Ast.Node.Index = undefined;
const container_decl = tree.fullContainerDecl(&buf, node) orelse
return null;

if (token_tags[container_decl.ast.main_token] != .keyword_union)
return null;

if (container_decl.ast.enum_token != null) {
const union_type_ptr = try analyser.arena.allocator().create(TypeWithHandle);
union_type_ptr.* = type_handle;
return TypeWithHandle{
.type = .{ .data = .{ .union_tag = union_type_ptr }, .is_type_val = false },
.handle = handle,
};
}

if (container_decl.ast.arg != 0) {
const tag_type = (try analyser.resolveTypeOfNode(.{
.node = container_decl.ast.arg,
.handle = handle,
})) orelse return null;
return tag_type.instanceTypeVal();
}

return null;
}

/// Resolves the child type of a deref type
fn resolveDerefType(analyser: *Analyser, deref: TypeWithHandle) !?TypeWithHandle {
const deref_node = switch (deref.type.data) {
Expand Down Expand Up @@ -1212,6 +1257,9 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e
.handle = handle,
})) orelse return null;

if (try analyser.resolveUnwrapUnionTagType(lhs)) |tag_type|
return tag_type;

// If we are accessing a pointer type, remove one pointerness level :)
const left_type = (try analyser.resolveDerefType(lhs)) orelse lhs;

Expand Down Expand Up @@ -1483,14 +1531,38 @@ pub const Type = struct {
};

data: union(enum) {
/// Type of `foo` in `&foo`
pointer: *TypeWithHandle,

/// Element type of `slice` in `slice.ptr`
multi_pointer: *TypeWithHandle,

/// Element type of `array` in `array[x..y]`
slice: *TypeWithHandle,

/// Return type of `fn foo() !Foo`
error_union: *TypeWithHandle,

/// `Foo` in `Foo.bar` where `Foo = union(enum) { bar }`
union_tag: *TypeWithHandle,

/// - Container type: `struct {}`, `enum {}`, `union {}`, `opaque {}`, `error {}`
/// - Pointer type: `*Foo`, `[]Foo`, `?Foo`
/// - Error type: `Foo || Bar`, `Foo!Bar`
/// - Function: `fn () Foo`, `fn foo() Foo`
/// - Literal: `"foo"`, `'x'`, `42`, `.foo`, `error.Foo`
/// - Primitive value: `true`, `false`, `null`, `undefined`
other: Ast.Node.Index,

/// Primitive type: `u8`, `bool`, `type`, etc.
primitive: []const u8,

/// Branching types
either: []const EitherEntry,

// TODO: Unused?
array_index,

@"comptime": struct {
interpreter: *ComptimeInterpreter,
value: ComptimeInterpreter.Value,
Expand All @@ -1516,6 +1588,7 @@ pub const TypeWithHandle = struct {
.multi_pointer,
.slice,
.error_union,
.union_tag,
=> |t| hashTypeWithHandle(hasher, t.*),
.other => |idx| hasher.update(&std.mem.toBytes(idx)),
.primitive => |name| hasher.update(name),
Expand Down Expand Up @@ -1554,6 +1627,7 @@ pub const TypeWithHandle = struct {
.multi_pointer,
.slice,
.error_union,
.union_tag,
=> |a_type, name| {
const b_type = @field(b.type.data, @tagName(name));
if (!self.eql(a_type.*, b_type.*)) return false;
Expand Down Expand Up @@ -4153,6 +4227,11 @@ fn addReferencedTypes(
return try std.fmt.allocPrint(allocator, "!{s}", .{rhs_str orelse return null});
},

.union_tag => |t| {
const union_type_str = try analyser.addReferencedTypes(t.*, ReferencedType.Collector.init(referenced_types));
return try std.fmt.allocPrint(allocator, "@typeInfo({s}).Union.tag_type.?", .{union_type_str orelse return null});
},

.other => |p| switch (node_tags[p]) {
.root => {
const path = URI.parse(allocator, handle.uri) catch |err| switch (err) {
Expand Down
4 changes: 1 addition & 3 deletions src/features/completions.zig
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ fn typeToCompletion(
});
}
},
.error_union => {},
.multi_pointer => {},
.pointer => |t| {
if (server.config.operator_completions) {
try list.append(arena, .{
Expand All @@ -74,7 +72,6 @@ fn typeToCompletion(
null,
either_descriptor,
),
.primitive, .array_index => {},
.@"comptime" => |co| try analyser_completions.dotCompletions(
arena,
list,
Expand All @@ -87,6 +84,7 @@ fn typeToCompletion(
for (bruh) |a|
try typeToCompletion(server, analyser, arena, list, .{ .original = a.type_with_handle }, orig_handle, a.descriptor);
},
else => {},
}
}

Expand Down

0 comments on commit 6ae797f

Please sign in to comment.