From cbfd76380a170bcacb4493f17ba7d176d58a2881 Mon Sep 17 00:00:00 2001 From: Ayaz Hafiz Date: Tue, 19 Apr 2022 13:36:42 -0400 Subject: [PATCH] Improve ability generalization error message --- reporting/src/error/type.rs | 46 +++++++++++++++++++++++++++---- reporting/tests/test_reporting.rs | 9 +++--- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/reporting/src/error/type.rs b/reporting/src/error/type.rs index 0351636408..c1640a9eef 100644 --- a/reporting/src/error/type.rs +++ b/reporting/src/error/type.rs @@ -1767,7 +1767,7 @@ pub enum Problem { FieldsMissing(Vec), TagTypo(TagName, Vec), TagsMissing(Vec), - BadRigidVar(Lowercase, ErrorType), + BadRigidVar(Lowercase, ErrorType, Option), OptionalRequiredMismatch(Lowercase), OpaqueComparedToNonOpaque, } @@ -1872,7 +1872,7 @@ fn diff_is_wildcard_comparison<'b>( ) -> bool { let Comparison { problems, .. } = to_comparison(alloc, actual, expected); match problems.last() { - Some(Problem::BadRigidVar(v1, ErrorType::RigidVar(v2))) => { + Some(Problem::BadRigidVar(v1, ErrorType::RigidVar(v2), None)) => { v1.as_str() == WILDCARD && v2.as_str() == WILDCARD } _ => false, @@ -2143,6 +2143,32 @@ fn to_diff<'b>( same(alloc, parens, type1) } + (RigidVar(x), other) | (other, RigidVar(x)) => { + let (left, left_able) = to_doc(alloc, Parens::InFn, type1); + let (right, right_able) = to_doc(alloc, Parens::InFn, type2); + + Diff { + left, + right, + status: Status::Different(vec![Problem::BadRigidVar(x, other, None)]), + left_able, + right_able, + } + } + + (RigidAbleVar(x, ab), other) | (other, RigidAbleVar(x, ab)) => { + let (left, left_able) = to_doc(alloc, Parens::InFn, type1); + let (right, right_able) = to_doc(alloc, Parens::InFn, type2); + + Diff { + left, + right, + status: Status::Different(vec![Problem::BadRigidVar(x, other, Some(ab))]), + left_able, + right_able, + } + } + (Function(args1, _, ret1), Function(args2, _, ret2)) => { if args1.len() == args2.len() { let mut status = Status::Similar; @@ -2325,7 +2351,6 @@ fn to_diff<'b>( }; let problems = match pair { - (RigidVar(x), other) | (other, RigidVar(x)) => vec![Problem::BadRigidVar(x, other)], (a, b) if (is_int(&a) && is_float(&b)) || (is_float(&a) && is_int(&b)) => { vec![Problem::IntFloat] } @@ -2751,6 +2776,7 @@ fn ext_to_status(ext1: &TypeExt, ext2: &TypeExt) -> Status { Status::Different(vec![Problem::BadRigidVar( x.clone(), ErrorType::RigidVar(y.clone()), + None, )]) } } @@ -3128,15 +3154,25 @@ fn type_problem_to_pretty<'b>( alloc.tip().append(line) } - (BadRigidVar(x, tipe), expectation) => { + (BadRigidVar(x, tipe, opt_ability), expectation) => { use ErrorType::*; let bad_rigid_var = |name: Lowercase, a_thing| { + let kind_of_value = match opt_ability { + Some(ability) => alloc.concat(vec![ + alloc.reflow("any value implementing the "), + alloc.symbol_unqualified(ability), + alloc.reflow(" ability"), + ]), + None => alloc.reflow("any type of value"), + }; alloc .tip() .append(alloc.reflow("The type annotation uses the type variable ")) .append(alloc.type_variable(name)) - .append(alloc.reflow(" to say that this definition can produce any type of value. But in the body I see that it will only produce ")) + .append(alloc.reflow(" to say that this definition can produce ") + .append(kind_of_value) + .append(alloc.reflow(". But in the body I see that it will only produce "))) .append(a_thing) .append(alloc.reflow(" of a single specific type. Maybe change the type annotation to be more specific? Maybe change the code to be more general?")) }; diff --git a/reporting/tests/test_reporting.rs b/reporting/tests/test_reporting.rs index 70f5d5bf2e..6fa7e8c10e 100644 --- a/reporting/tests/test_reporting.rs +++ b/reporting/tests/test_reporting.rs @@ -9864,10 +9864,11 @@ I need all branches in an `if` to have the same type! a | a has Hash - Tip: Type comparisons between an opaque type are only ever equal if - both types are the same opaque type. Did you mean to create an opaque - type by wrapping it? If I have an opaque type Age := U32 I can create - an instance of this opaque type by doing @Age 23. + Tip: The type annotation uses the type variable `a` to say that this + definition can produce any value implementing the `Hash` ability. But in + the body I see that it will only produce a `Id` value of a single + specific type. Maybe change the type annotation to be more specific? + Maybe change the code to be more general? "# ), )