From 937651605a217b3b3940fb1783996981e2972741 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:45:26 -0700 Subject: [PATCH 1/4] Avoid using interned value when resolving negation --- src/analysis.zig | 6 +++++- tests/analysis/integer_literal.zig | 9 +++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/analysis.zig b/src/analysis.zig index 45919db68..b97799530 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -2709,7 +2709,11 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error .bit_not, .negation, .negation_wrap, - => return try analyser.resolveTypeOfNodeInternal(.of(tree.nodeData(node).node, handle)), + => { + const ty = try analyser.resolveTypeOfNodeInternal(.of(tree.nodeData(node).node, handle)) orelse return null; + if (ty.is_type_val) return null; + return ty.withoutIPIndex(analyser); + }, .multiline_string_literal => { const start, const end = tree.nodeData(node).token_and_token; diff --git a/tests/analysis/integer_literal.zig b/tests/analysis/integer_literal.zig index 8aa6591cc..638bd9ccc 100644 --- a/tests/analysis/integer_literal.zig +++ b/tests/analysis/integer_literal.zig @@ -22,6 +22,15 @@ const comptime_shl = 2 << 3; const one_plus_one = 1 + 1; // ^^^^^^^^^^^^ (comptime_int)((unknown value)) TODO this should be `2` +const negation_one = -1; +// ^^^^^^^^^^^^ (comptime_int)((unknown value)) TODO this should be `-1` + +const negation_wrap_one = -%1; +// ^^^^^^^^^^^^^^^^^ (comptime_int)((unknown value)) TODO this should be `-1` + +const bit_not_one = ~1; +// ^^^^^^^^^^^ (comptime_int)((unknown value)) + const const_u8: u8 = 42; // ^^^^^^^^ (u8)((unknown value)) TODO this should be `42` From 57a229da7ac11277fc35ae031c48fda0e886fca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:58:32 -0700 Subject: [PATCH 2/4] Avoid using interned value when resolving variable --- src/analysis.zig | 6 +++++- tests/analysis/variable.zig | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/analysis.zig b/src/analysis.zig index b97799530..de2648c2f 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -1968,6 +1968,7 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error .aligned_var_decl, => { const var_decl = tree.fullVarDecl(node).?; + const mut_token_tag = tree.tokenTag(var_decl.ast.mut_token); var fallback_type: ?Type = null; if (var_decl.ast.type_node.unwrap()) |type_node| blk: { @@ -1983,7 +1984,10 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error } if (var_decl.ast.init_node.unwrap()) |init_node| blk: { - return try analyser.resolveTypeOfNodeInternal(.of(init_node, handle)) orelse break :blk; + const ty = try analyser.resolveTypeOfNodeInternal(.of(init_node, handle)) orelse break :blk; + if (mut_token_tag == .keyword_var) + return ty.withoutIPIndex(analyser); + return ty; } return fallback_type; diff --git a/tests/analysis/variable.zig b/tests/analysis/variable.zig index 04c2b62c2..c0bbbe7c0 100644 --- a/tests/analysis/variable.zig +++ b/tests/analysis/variable.zig @@ -1,3 +1,6 @@ const variable addrspace(.generic) linksection(.{}) = 0; // ^^^^^^^^ (AddressSpace)() // ^ ([]const u8)() + +var bool_var = true; +// ^^^^^^^^ (bool)((unknown value)) From f884ccf359c831c7d26adfa133658c519b4333ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:54:19 -0700 Subject: [PATCH 3/4] Resolve `@as` call as interned value if possible --- src/analyser/InternPool.zig | 11 ++++++++++ src/analysis.zig | 34 +++++++++++++++++++++++++++++- tests/analysis/integer_literal.zig | 2 +- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/analyser/InternPool.zig b/src/analyser/InternPool.zig index 0ddc0c837..ba6bb2298 100644 --- a/src/analyser/InternPool.zig +++ b/src/analyser/InternPool.zig @@ -3155,6 +3155,17 @@ pub fn isType(ip: *InternPool, ty: Index) bool { }; } +pub fn isUndefined(ip: *InternPool, index: Index) bool { + switch (index) { + .undefined_value => return true, + else => { + ip.lock.lockSharedUncancelable(ip.io); + defer ip.lock.unlockShared(ip.io); + return ip.items.items(.tag)[@intFromEnum(index)] == .undefined_value; + }, + } +} + pub fn isUnknown(ip: *InternPool, index: Index) bool { switch (index) { .unknown_type, .unknown_unknown => return true, diff --git a/src/analysis.zig b/src/analysis.zig index de2648c2f..0ef62dd96 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -1425,6 +1425,28 @@ fn resolveOptionalIPValue( return try analyser.resolveInternPoolValue(.of(node, handle)) orelse .unknown_unknown; } +fn resolveCoercedIPValue( + analyser: *Analyser, + ip_ty: InternPool.Index, + options: ResolveOptions, +) Error!?InternPool.Index { + if (!analyser.ip.isType(ip_ty)) return null; + const ty = try analyser.resolveTypeOfNode(options) orelse return null; + const ip_index = ty.ipIndex() orelse return null; + if (analyser.ip.isUndefined(ip_index)) return null; + + var arena_allocator: std.heap.ArenaAllocator = .init(analyser.gpa); + defer arena_allocator.deinit(); + const arena = arena_allocator.allocator(); + + var err_msg: ErrorMsg = undefined; + const new_index = try analyser.ip.coerce(arena, ip_ty, ip_index, builtin.target, &err_msg); + + if (new_index == .none) return null; + if (analyser.ip.isUnknown(new_index)) return null; + return new_index; +} + fn resolveInternPoolValue(analyser: *Analyser, options: ResolveOptions) Error!?InternPool.Index { const old_resolve_number_literal_values = analyser.resolve_number_literal_values; analyser.resolve_number_literal_values = true; @@ -2279,7 +2301,17 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error if (params.len != 0) return null; return options.container_type orelse try analyser.innermostContainer(handle, tree.tokenStart(tree.firstToken(node))); }, - .as, + .as => { + if (params.len < 1) return null; + const ty = (try analyser.resolveTypeOfNodeInternal(.of(params[0], handle))) orelse return null; + num: { + if (params.len < 2) break :num; + const ip_ty = ty.ipIndex() orelse break :num; + const ip_index = try analyser.resolveCoercedIPValue(ip_ty, .of(params[1], handle)) orelse break :num; + return Type.fromIP(analyser, analyser.ip.typeOf(ip_index), ip_index); + } + return try ty.instanceTypeVal(analyser); + }, .atomic_load, .atomic_rmw, .@"extern", diff --git a/tests/analysis/integer_literal.zig b/tests/analysis/integer_literal.zig index 638bd9ccc..d2726c8ce 100644 --- a/tests/analysis/integer_literal.zig +++ b/tests/analysis/integer_literal.zig @@ -38,7 +38,7 @@ var var_u8: u8 = 42; // ^^^^^^ (u8)((unknown value)) const as_u8 = @as(u8, 42); -// ^^^^^ (u8)((unknown value)) TODO this should be `42` +// ^^^^^ (u8)(42) const as_u8_too_big = @as(u8, 256); // ^^^^^^^^^^^^^ (u8)((unknown value)) From 094caef6b68f5b1befe366e7c34fa0d8e5b33452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Thu, 12 Mar 2026 21:59:50 -0700 Subject: [PATCH 4/4] Resolve `const` declaration as interned value if possible --- src/analysis.zig | 6 ++++++ tests/analysis/integer_literal.zig | 2 +- tests/lsp_features/hover.zig | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/analysis.zig b/src/analysis.zig index 0ef62dd96..accd779a7 100644 --- a/src/analysis.zig +++ b/src/analysis.zig @@ -2002,6 +2002,12 @@ fn resolveTypeOfNodeUncached(analyser: *Analyser, options: ResolveOptions) Error fallback_type = .unknown_type; break :blk; } + if (mut_token_tag == .keyword_const) num: { + const init_node = var_decl.ast.init_node.unwrap() orelse break :num; + const ip_ty = decl_type.ipIndex() orelse break :num; + const ip_index = try analyser.resolveCoercedIPValue(ip_ty, .of(init_node, handle)) orelse break :num; + return Type.fromIP(analyser, analyser.ip.typeOf(ip_index), ip_index); + } return try decl_type.instanceTypeVal(analyser); } diff --git a/tests/analysis/integer_literal.zig b/tests/analysis/integer_literal.zig index d2726c8ce..eeeee77a9 100644 --- a/tests/analysis/integer_literal.zig +++ b/tests/analysis/integer_literal.zig @@ -32,7 +32,7 @@ const bit_not_one = ~1; // ^^^^^^^^^^^ (comptime_int)((unknown value)) const const_u8: u8 = 42; -// ^^^^^^^^ (u8)((unknown value)) TODO this should be `42` +// ^^^^^^^^ (u8)(42) var var_u8: u8 = 42; // ^^^^^^ (u8)((unknown value)) diff --git a/tests/lsp_features/hover.zig b/tests/lsp_features/hover.zig index 7ddc34764..68e1c1c1e 100644 --- a/tests/lsp_features/hover.zig +++ b/tests/lsp_features/hover.zig @@ -1097,7 +1097,7 @@ test "alias with different type" { \\const bar: ?i32 = foo; , \\const foo: i32 = 1 - \\(?i32) + \\(?i32 = 1) , .{ .markup_kind = .plaintext }); }