Skip to content

Commit d3f59a7

Browse files
Fix resolved type of pointer to const identifier
1 parent ea6c052 commit d3f59a7

File tree

3 files changed

+110
-37
lines changed

3 files changed

+110
-37
lines changed

src/analysis.zig

+88-34
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ ip: *InternPool,
3232
// nested scopes with comptime bindings
3333
bound_type_params: BoundTypeParams = .{},
3434
resolved_callsites: std.AutoHashMapUnmanaged(Declaration.Param, ?Type) = .empty,
35-
resolved_nodes: std.HashMapUnmanaged(NodeWithUri, ?Type, NodeWithUri.Context, std.hash_map.default_max_load_percentage) = .empty,
35+
resolved_nodes: std.HashMapUnmanaged(NodeWithUri, ?Binding, NodeWithUri.Context, std.hash_map.default_max_load_percentage) = .empty,
3636
/// used to detect recursion
3737
use_trail: NodeSet = .empty,
3838
collect_callsite_references: bool,
@@ -893,13 +893,13 @@ pub fn resolveOrelseType(analyser: *Analyser, lhs: Type, rhs: Type) error{OutOfM
893893
};
894894
}
895895

896-
pub fn resolveAddressOf(analyser: *Analyser, ty: Type) error{OutOfMemory}!?Type {
896+
pub fn resolveAddressOf(analyser: *Analyser, is_const: bool, ty: Type) error{OutOfMemory}!Type {
897897
return .{
898898
.data = .{
899899
.pointer = .{
900900
.size = .one,
901901
.sentinel = .none,
902-
.is_const = false,
902+
.is_const = is_const,
903903
.elem_ty = try analyser.allocType(ty.typeOf(analyser)),
904904
},
905905
},
@@ -1515,13 +1515,23 @@ const FindBreaks = struct {
15151515
/// Resolves the type of an Ast Node.
15161516
/// Returns `null` if the type could not be resolved.
15171517
pub fn resolveTypeOfNode(analyser: *Analyser, node_handle: NodeWithHandle) error{OutOfMemory}!?Type {
1518+
const binding = try analyser.resolveBindingOfNode(node_handle) orelse return null;
1519+
return binding.type;
1520+
}
1521+
1522+
fn resolveTypeOfNodeInternal(analyser: *Analyser, node_handle: NodeWithHandle) error{OutOfMemory}!?Type {
1523+
const binding = try analyser.resolveBindingOfNodeInternal(node_handle) orelse return null;
1524+
return binding.type;
1525+
}
1526+
1527+
pub fn resolveBindingOfNode(analyser: *Analyser, node_handle: NodeWithHandle) error{OutOfMemory}!?Binding {
15181528
const tracy_zone = tracy.trace(@src());
15191529
defer tracy_zone.end();
15201530

1521-
return analyser.resolveTypeOfNodeInternal(node_handle);
1531+
return analyser.resolveBindingOfNodeInternal(node_handle);
15221532
}
15231533

1524-
fn resolveTypeOfNodeInternal(analyser: *Analyser, node_handle: NodeWithHandle) error{OutOfMemory}!?Type {
1534+
fn resolveBindingOfNodeInternal(analyser: *Analyser, node_handle: NodeWithHandle) error{OutOfMemory}!?Binding {
15251535
const node_with_uri: NodeWithUri = .{
15261536
.node = node_handle.node,
15271537
.uri = node_handle.handle.uri,
@@ -1533,12 +1543,12 @@ fn resolveTypeOfNodeInternal(analyser: *Analyser, node_handle: NodeWithHandle) e
15331543
// we insert null before resolving the type so that a recursive definition doesn't result in an infinite loop
15341544
gop.value_ptr.* = null;
15351545

1536-
const ty = try analyser.resolveTypeOfNodeUncached(node_handle);
1537-
if (ty != null) {
1538-
analyser.resolved_nodes.getPtr(node_with_uri).?.* = ty;
1546+
const binding = try analyser.resolveBindingOfNodeUncached(node_handle);
1547+
if (binding != null) {
1548+
analyser.resolved_nodes.getPtr(node_with_uri).?.* = binding;
15391549
}
15401550

1541-
return ty;
1551+
return binding;
15421552
}
15431553

15441554
fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) error{OutOfMemory}!?Type {
@@ -1576,23 +1586,6 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e
15761586

15771587
return fallback_type;
15781588
},
1579-
.identifier => {
1580-
const name_token = ast.identifierTokenFromIdentifierNode(tree, node) orelse return null;
1581-
const name = offsets.identifierTokenToNameSlice(tree, name_token);
1582-
1583-
const is_escaped_identifier = tree.source[tree.tokenStart(name_token)] == '@';
1584-
if (!is_escaped_identifier) {
1585-
if (std.mem.eql(u8, name, "_")) return null;
1586-
if (try analyser.resolvePrimitive(name)) |primitive| {
1587-
return Type.fromIP(analyser, analyser.ip.typeOf(primitive), primitive);
1588-
}
1589-
}
1590-
if (analyser.bound_type_params.resolve(name)) |t| {
1591-
return t.*;
1592-
}
1593-
const child = try analyser.lookupSymbolGlobal(handle, name, tree.tokenStart(name_token)) orelse return null;
1594-
return try child.resolveType(analyser);
1595-
},
15961589
.call,
15971590
.call_comma,
15981591
.async_call,
@@ -1809,14 +1802,6 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e
18091802

18101803
return try analyser.resolveUnwrapErrorUnionType(base_type, .payload);
18111804
},
1812-
.address_of => {
1813-
const base_type = try analyser.resolveTypeOfNodeInternal(.{
1814-
.node = tree.nodeData(node).node,
1815-
.handle = handle,
1816-
}) orelse return null;
1817-
1818-
return try analyser.resolveAddressOf(base_type);
1819-
},
18201805
.field_access => {
18211806
const lhs_node, const field_name = tree.nodeData(node_handle.node).node_and_token;
18221807

@@ -2620,10 +2605,79 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) e
26202605
.asm_output,
26212606
.asm_input,
26222607
=> {},
2608+
2609+
// TODO: port remaining nodes to resolveBindingOfNodeUncached
2610+
.identifier,
2611+
.address_of,
2612+
=> {
2613+
const binding = try analyser.resolveBindingOfNodeUncached(node_handle) orelse return null;
2614+
return binding.type;
2615+
},
26232616
}
26242617
return null;
26252618
}
26262619

2620+
fn resolveBindingOfNodeUncached(analyser: *Analyser, node_handle: NodeWithHandle) error{OutOfMemory}!?Binding {
2621+
const node = node_handle.node;
2622+
const handle = node_handle.handle;
2623+
const tree = handle.tree;
2624+
2625+
switch (tree.nodeTag(node)) {
2626+
.identifier => {
2627+
const name_token = ast.identifierTokenFromIdentifierNode(tree, node) orelse return null;
2628+
const name = offsets.identifierTokenToNameSlice(tree, name_token);
2629+
2630+
const is_escaped_identifier = tree.source[tree.tokenStart(name_token)] == '@';
2631+
if (!is_escaped_identifier) {
2632+
if (std.mem.eql(u8, name, "_")) return null;
2633+
if (try analyser.resolvePrimitive(name)) |primitive| {
2634+
return .{
2635+
.type = Type.fromIP(analyser, analyser.ip.typeOf(primitive), primitive),
2636+
.is_const = true,
2637+
};
2638+
}
2639+
}
2640+
2641+
if (analyser.bound_type_params.resolve(name)) |t| {
2642+
return .{
2643+
.type = t.*,
2644+
.is_const = true,
2645+
};
2646+
}
2647+
2648+
const child = try analyser.lookupSymbolGlobal(handle, name, tree.tokenStart(name_token)) orelse return null;
2649+
const child_ty = try child.resolveType(analyser) orelse return null;
2650+
return .{
2651+
.type = child_ty,
2652+
.is_const = child.isConst(),
2653+
};
2654+
},
2655+
2656+
.address_of => {
2657+
const base_binding = try analyser.resolveBindingOfNodeInternal(.{
2658+
.node = tree.nodeData(node).node,
2659+
.handle = handle,
2660+
}) orelse return null;
2661+
2662+
return .{
2663+
.type = try analyser.resolveAddressOf(base_binding.is_const, base_binding.type),
2664+
.is_const = true,
2665+
};
2666+
},
2667+
2668+
// TODO: port remaining nodes to resolveBindingOfNodeUncached
2669+
else => return .{
2670+
.type = try analyser.resolveTypeOfNodeUncached(node_handle) orelse return null,
2671+
.is_const = false,
2672+
},
2673+
}
2674+
}
2675+
2676+
pub const Binding = struct {
2677+
type: Type,
2678+
is_const: bool,
2679+
};
2680+
26272681
/// Represents a resolved Zig type.
26282682
/// This is the return type of `resolveTypeOfNode`.
26292683
pub const Type = struct {

tests/analysis/address_of.zig

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
const StructType = struct {
2+
foo: i32,
3+
};
4+
5+
const some_struct: StructType = .{ .foo = 1 };
6+
7+
var mutable_struct: StructType = .{ .foo = 1 };
8+
9+
const some_struct_pointer = &some_struct;
10+
// ^^^^^^^^^^^^^^^^^^^ (*const StructType)()
11+
12+
const mutable_struct_pointer = &mutable_struct;
13+
// ^^^^^^^^^^^^^^^^^^^^^^ (*StructType)()
14+
15+
const some_struct_pointer_pointer = &&some_struct;
16+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^ (*const *const StructType)()
17+
18+
const mutable_struct_pointer_pointer = &&mutable_struct;
19+
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (*const *StructType)()

tests/lsp_features/inlay_hints.zig

+3-3
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ test "var decl" {
247247
, .{ .kind = .Type });
248248
try testInlayHints(
249249
\\const foo: *[]const u8 = &"Bar";
250-
\\const baz<**[]const u8> = &foo;
250+
\\const baz<*const *[]const u8> = &foo;
251251
, .{ .kind = .Type });
252252
try testInlayHints(
253253
\\const Foo<type> = struct { bar: u32 };
@@ -256,7 +256,7 @@ test "var decl" {
256256
\\ const baz: ?Foo = Foo{ .bar<u32> = 42 };
257257
\\ if (baz) |b<Foo>| {
258258
\\ const d: Error!?Foo = b;
259-
\\ const e<*error{e}!?Foo> = &d;
259+
\\ const e<*const error{e}!?Foo> = &d;
260260
\\ const f<Foo> = (try e.*).?;
261261
\\ _ = f;
262262
\\ }
@@ -355,7 +355,7 @@ test "function alias" {
355355
\\) u32 {
356356
\\ return alpha;
357357
\\}
358-
\\const bar<*fn (comptime alpha: u32) u32> = &foo;
358+
\\const bar<*const fn (comptime alpha: u32) u32> = &foo;
359359
, .{ .kind = .Type });
360360
}
361361

0 commit comments

Comments
 (0)