From d487cb6300a5644f8f8e579d153f1425cee7a77d Mon Sep 17 00:00:00 2001 From: Jared Ramirez Date: Sun, 26 Oct 2025 16:15:28 -0400 Subject: [PATCH] Improve error message for rigid vars --- src/check/Check.zig | 32 ++++++++++++++++++-------------- src/check/problem.zig | 19 ++++++++++++++++--- 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/src/check/Check.zig b/src/check/Check.zig index 6127941390..a4414a6416 100644 --- a/src/check/Check.zig +++ b/src/check/Check.zig @@ -99,8 +99,8 @@ bool_var: Var, deferred_static_dispatch_constraints: DeferredConstraintCheck.SafeList, /// Used when looking up static dispatch functions static_dispatch_method_name_buf: std.ArrayList(u8), -/// Map representation of Idet -> Var, user in checking static dispatch constraints -static_dispatch_constraints_map: std.AutoHashMap(Ident.Idx, Var), +/// Map representation of Ident -> Var, used in checking static dispatch constraints +ident_to_var_map: std.AutoHashMap(Ident.Idx, Var), /// A map of rigid variables that we build up during a branch of type checking const FreeVar = struct { ident: base.Ident.Idx, var_: Var }; @@ -161,7 +161,7 @@ pub fn init( .bool_var = undefined, // Will be initialized in copyBuiltinTypes() .deferred_static_dispatch_constraints = try DeferredConstraintCheck.SafeList.initCapacity(gpa, 128), .static_dispatch_method_name_buf = try std.ArrayList(u8).initCapacity(gpa, 32), - .static_dispatch_constraints_map = std.AutoHashMap(Ident.Idx, Var).init(gpa), + .ident_to_var_map = std.AutoHashMap(Ident.Idx, Var).init(gpa), }; } @@ -186,7 +186,7 @@ pub fn deinit(self: *Self) void { self.constraint_origins.deinit(); self.deferred_static_dispatch_constraints.deinit(self.gpa); self.static_dispatch_method_name_buf.deinit(self.gpa); - self.static_dispatch_constraints_map.deinit(); + self.ident_to_var_map.deinit(); } /// Assert that type vars and regions in sync @@ -3774,16 +3774,16 @@ fn checkDeferredStaticDispatchConstraints(self: *Self) std.mem.Allocator.Error!v try self.reportConstraintError( deferred_constraint.var_, constraint, - .missing_method, + .{ .missing_method = .rigid }, ); continue; } // Build a map of constraints the rigid has - self.static_dispatch_constraints_map.clearRetainingCapacity(); - try self.static_dispatch_constraints_map.ensureUnusedCapacity(@intCast(rigid_constraints.len)); + self.ident_to_var_map.clearRetainingCapacity(); + try self.ident_to_var_map.ensureUnusedCapacity(@intCast(rigid_constraints.len)); for (rigid_constraints) |rigid_constraint| { - self.static_dispatch_constraints_map.putAssumeCapacity(rigid_constraint.fn_name, rigid_constraint.fn_var); + self.ident_to_var_map.putAssumeCapacity(rigid_constraint.fn_name, rigid_constraint.fn_var); } // Iterate over the constraints @@ -3795,7 +3795,7 @@ fn checkDeferredStaticDispatchConstraints(self: *Self) std.mem.Allocator.Error!v const resolved_func = mb_resolved_func.?; // Then, lookup the inferred constraint in the actual list of rigid constraints - if (self.static_dispatch_constraints_map.get(constraint.fn_name)) |rigid_var| { + if (self.ident_to_var_map.get(constraint.fn_name)) |rigid_var| { // Unify the actual function var against the inferred var // // TODO: For better error messages, we should check if these @@ -3810,7 +3810,7 @@ fn checkDeferredStaticDispatchConstraints(self: *Self) std.mem.Allocator.Error!v try self.reportConstraintError( deferred_constraint.var_, constraint, - .missing_method, + .{ .missing_method = .nominal }, ); continue; } @@ -3877,7 +3877,7 @@ fn checkDeferredStaticDispatchConstraints(self: *Self) std.mem.Allocator.Error!v try self.reportConstraintError( deferred_constraint.var_, constraint, - .missing_method, + .{ .missing_method = .nominal }, ); continue; }; @@ -3890,7 +3890,7 @@ fn checkDeferredStaticDispatchConstraints(self: *Self) std.mem.Allocator.Error!v try self.reportConstraintError( deferred_constraint.var_, constraint, - .missing_method, + .{ .missing_method = .nominal }, ); continue; }; @@ -3946,15 +3946,19 @@ fn reportConstraintError( self: *Self, dispatcher_var: Var, constraint: StaticDispatchConstraint, - kind: enum { missing_method, not_nominal }, + kind: union(enum) { + missing_method: problem.DispatcherDoesNotImplMethod.DispatcherType, + not_nominal, + }, ) !void { const snapshot = try self.snapshots.deepCopyVar(self.types, dispatcher_var); const constraint_problem = switch (kind) { - .missing_method => problem.Problem{ .static_dispach = .{ + .missing_method => |dispatcher_type| problem.Problem{ .static_dispach = .{ .dispatcher_does_not_impl_method = .{ .dispatcher_var = dispatcher_var, .dispatcher_snapshot = snapshot, + .dispatcher_type = dispatcher_type, .fn_var = constraint.fn_var, .method_name = constraint.fn_name, }, diff --git a/src/check/problem.zig b/src/check/problem.zig index 39ca342088..bab4d8c346 100644 --- a/src/check/problem.zig +++ b/src/check/problem.zig @@ -222,8 +222,12 @@ pub const DispatcherNotNominal = struct { pub const DispatcherDoesNotImplMethod = struct { dispatcher_var: Var, dispatcher_snapshot: SnapshotContentIdx, + dispatcher_type: DispatcherType, fn_var: Var, method_name: Ident.Idx, + + /// Type of the dispatcher + pub const DispatcherType = enum { nominal, rigid }; }; // bug // @@ -1695,9 +1699,18 @@ pub const ReportBuilder = struct { try report.document.addLineBreak(); try report.document.addLineBreak(); try report.document.addAnnotated("Hint:", .emphasized); - try report.document.addReflowingText(" Did you forget to define "); - try report.document.addAnnotated(method_name_str, .emphasized); - try report.document.addReflowingText(" in the type's method block?"); + switch (data.dispatcher_type) { + .nominal => { + try report.document.addReflowingText(" Did you forget to define "); + try report.document.addAnnotated(method_name_str, .emphasized); + try report.document.addReflowingText(" in the type's method block?"); + }, + .rigid => { + try report.document.addReflowingText(" Did you forget to specify "); + try report.document.addAnnotated(method_name_str, .emphasized); + try report.document.addReflowingText(" in the type annotation?"); + }, + } return report; }