More error message improvements

This commit is contained in:
Richard Feldman 2025-08-15 18:16:24 -04:00
parent 9a3bb0face
commit cc597648a0
No known key found for this signature in database
17 changed files with 75 additions and 25 deletions

View file

@ -155,6 +155,23 @@ pub fn unify(self: *Self, a: Var, b: Var) std.mem.Allocator.Error!unifier.Result
); );
} }
pub fn unifyWithAnnotation(self: *Self, a: Var, b: Var) std.mem.Allocator.Error!unifier.Result {
const trace = tracy.trace(@src());
defer trace.end();
return try unifier.unifyWithContext(
self.cir,
self.types,
&self.problems,
&self.snapshots,
&self.unify_scratch,
&self.occurs_scratch,
a,
b,
true, // from_annotation = true
);
}
// instantiate // // instantiate //
const InstantiateRegionBehavior = union(enum) { const InstantiateRegionBehavior = union(enum) {
@ -406,7 +423,7 @@ fn checkDef(self: *Self, def_idx: CIR.Def.Idx) std.mem.Allocator.Error!void {
_ = try self.checkExpr(def.expr); _ = try self.checkExpr(def.expr);
// Unify the expression with its annotation // Unify the expression with its annotation
_ = try self.unify(expr_var, anno_var); _ = try self.unifyWithAnnotation(expr_var, anno_var);
} }
} else { } else {
// Check the expr // Check the expr
@ -1469,7 +1486,7 @@ fn checkLambdaWithAnno(
// Unify against the annotation // Unify against the annotation
const pattern_var = ModuleEnv.varFrom(pattern_idx); const pattern_var = ModuleEnv.varFrom(pattern_idx);
_ = try self.unify(pattern_var, expected_arg); _ = try self.unifyWithAnnotation(pattern_var, expected_arg);
} }
} }
} }
@ -1493,12 +1510,12 @@ fn checkLambdaWithAnno(
// STEP 4: Validate the function body against the annotation return type // STEP 4: Validate the function body against the annotation return type
if (mb_expected_func) |func| { if (mb_expected_func) |func| {
_ = try self.unify(return_var, func.ret); _ = try self.unifyWithAnnotation(return_var, func.ret);
} }
// STEP 5: Validate the entire function against the annotation // STEP 5: Validate the entire function against the annotation
if (mb_expected_var) |expected_var| { if (mb_expected_var) |expected_var| {
_ = try self.unify(fn_var, expected_var); _ = try self.unifyWithAnnotation(fn_var, expected_var);
} }
return is_effectful; return is_effectful;

View file

@ -84,6 +84,8 @@ pub const TypePair = struct {
expected_snapshot: SnapshotContentIdx, expected_snapshot: SnapshotContentIdx,
actual_var: Var, actual_var: Var,
actual_snapshot: SnapshotContentIdx, actual_snapshot: SnapshotContentIdx,
/// True if the expected type comes from a type annotation
from_annotation: bool = false,
}; };
/// More specific details about a particular type mismatch. /// More specific details about a particular type mismatch.
@ -335,7 +337,11 @@ pub const ReportBuilder = struct {
); );
try report.document.addLineBreak(); try report.document.addLineBreak();
try report.document.addText("The type annotation says it should have the type:"); if (types.from_annotation) {
try report.document.addText("The type annotation says it should have the type:");
} else {
try report.document.addText("It is of type:");
}
try report.document.addLineBreak(); try report.document.addLineBreak();
try report.document.addText(" "); try report.document.addText(" ");
try report.document.addAnnotated(owned_actual, .type_variable); try report.document.addAnnotated(owned_actual, .type_variable);

View file

@ -114,13 +114,8 @@ pub const Result = union(enum) {
} }
}; };
/// Unify two type variables /// Unify two type variables with context about whether this is from an annotation
/// pub fn unifyWithContext(
/// This function
/// * Resolves type variables & compresses paths
/// * Compares variable contents for equality
/// * Merges unified variables so 1 is "root" and the other is "redirect"
pub fn unify(
module_env: *ModuleEnv, module_env: *ModuleEnv,
types: *types_mod.Store, types: *types_mod.Store,
problems: *problem_mod.Store, problems: *problem_mod.Store,
@ -129,6 +124,7 @@ pub fn unify(
occurs_scratch: *occurs.Scratch, occurs_scratch: *occurs.Scratch,
a: Var, a: Var,
b: Var, b: Var,
from_annotation: bool,
) std.mem.Allocator.Error!Result { ) std.mem.Allocator.Error!Result {
const trace = tracy.trace(@src()); const trace = tracy.trace(@src());
defer trace.end(); defer trace.end();
@ -153,6 +149,7 @@ pub fn unify(
.expected_snapshot = expected_snapshot, .expected_snapshot = expected_snapshot,
.actual_var = b, .actual_var = b,
.actual_snapshot = actual_snapshot, .actual_snapshot = actual_snapshot,
.from_annotation = from_annotation,
}, },
.detail = null, .detail = null,
} }; } };
@ -287,6 +284,36 @@ pub fn unify(
return .ok; return .ok;
} }
/// Unify two type variables
///
/// This function
/// * Resolves type variables & compresses paths
/// * Compares variable contents for equality
/// * Merges unified variables so 1 is "root" and the other is "redirect"
pub fn unify(
module_env: *ModuleEnv,
types: *types_mod.Store,
problems: *problem_mod.Store,
snapshots: *snapshot_mod.Store,
unify_scratch: *Scratch,
occurs_scratch: *occurs.Scratch,
a: Var,
b: Var,
) std.mem.Allocator.Error!Result {
// Default to not from annotation for backward compatibility
return unifyWithContext(
module_env,
types,
problems,
snapshots,
unify_scratch,
occurs_scratch,
a,
b,
false, // from_annotation = false by default
);
}
/// A temporary unification context used to unify two type variables within a `Store`. /// A temporary unification context used to unify two type variables within a `Store`.
/// ///
/// `Unifier` is created per unification call and: /// `Unifier` is created per unification call and:

View file

@ -18,7 +18,7 @@ This expression is used in an unexpected way:
``` ```
^^^^^^^ ^^^^^^^
The type annotation says it should have the type: It is of type:
_Bool_ _Bool_
But you are trying to use it as: But you are trying to use it as:

View file

@ -875,7 +875,7 @@ This expression is used in an unexpected way:
)crash ke"Unr!" #) )crash ke"Unr!" #)
``` ```
The type annotation says it should have the type: It is of type:
__arg -> _ret_ __arg -> _ret_
But you are trying to use it as: But you are trying to use it as:

View file

@ -961,7 +961,7 @@ This expression is used in an unexpected way:
) )
``` ```
The type annotation says it should have the type: It is of type:
__arg -> _ret_ __arg -> _ret_
But you are trying to use it as: But you are trying to use it as:

View file

@ -912,7 +912,7 @@ This expression is used in an unexpected way:
) )
``` ```
The type annotation says it should have the type: It is of type:
__arg -> _ret_ __arg -> _ret_
But you are trying to use it as: But you are trying to use it as:

View file

@ -26,7 +26,7 @@ string_function = |x| x + 42
``` ```
^ ^
The type annotation says it should have the type: It is of type:
_Str_ _Str_
But you are trying to use it as: But you are trying to use it as:

View file

@ -86,7 +86,7 @@ makeAdder = |x| |y| x + y
``` ```
^ ^
The type annotation says it should have the type: It is of type:
_a_ _a_
But you are trying to use it as: But you are trying to use it as:

View file

@ -26,7 +26,7 @@ addTwoF64 = |x| x + 2.0
``` ```
^ ^
The type annotation says it should have the type: It is of type:
_F64_ _F64_
But you are trying to use it as: But you are trying to use it as:

View file

@ -897,7 +897,7 @@ This expression is used in an unexpected way:
) )
``` ```
The type annotation says it should have the type: It is of type:
__arg -> _ret_ __arg -> _ret_
But you are trying to use it as: But you are trying to use it as:

View file

@ -56,7 +56,7 @@ This expression is used in an unexpected way:
``` ```
^^^^^^^^ ^^^^^^^^
The type annotation says it should have the type: It is of type:
_Num(_size), Num(_size2), Num(_size3) -> Num(_size4), Num(_size5) -> Num(_size6) -> _ret_ _Num(_size), Num(_size2), Num(_size3) -> Num(_size4), Num(_size5) -> Num(_size6) -> _ret_
But you are trying to use it as: But you are trying to use it as:

View file

@ -23,7 +23,7 @@ This expression is used in an unexpected way:
``` ```
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
The type annotation says it should have the type: It is of type:
_Num(_size), Num(_size2) -> _ret_ _Num(_size), Num(_size2) -> _ret_
But you are trying to use it as: But you are trying to use it as:

View file

@ -26,7 +26,7 @@ main = swap(1, 2)
``` ```
^^^^ ^^^^
The type annotation says it should have the type: It is of type:
_Num(_size), Num(_size2) -> _ret_ _Num(_size), Num(_size2) -> _ret_
But you are trying to use it as: But you are trying to use it as:

View file

@ -25,7 +25,7 @@ main! = |_| swapPair(1, 2)
``` ```
^^^^^^^^ ^^^^^^^^
The type annotation says it should have the type: It is of type:
_Num(_size), Num(_size2) -> _ret_ _Num(_size), Num(_size2) -> _ret_
But you are trying to use it as: But you are trying to use it as:

View file

@ -23,7 +23,7 @@ main! = |_| mapList([1,2,3,4,5])
``` ```
^^^^^^^ ^^^^^^^
The type annotation says it should have the type: It is of type:
_List(Num(_size)) -> _ret_ _List(Num(_size)) -> _ret_
But you are trying to use it as: But you are trying to use it as: