Improve error message when we try to unify two wildcards

Closes #1931
This commit is contained in:
ayazhafiz 2021-11-21 01:42:24 -05:00
parent 8f1878bc42
commit 817bb22f9e
3 changed files with 86 additions and 16 deletions

View file

@ -4,7 +4,7 @@ use roc_collections::all::{MutMap, MutSet};
use roc_module::ident::{Lowercase, TagName};
use roc_module::symbol::{Interns, ModuleId, Symbol};
static WILDCARD: &str = "*";
pub static WILDCARD: &str = "*";
static EMPTY_RECORD: &str = "{}";
static EMPTY_TAG_UNION: &str = "[]";

View file

@ -5,7 +5,7 @@ use roc_module::ident::{Ident, IdentStr, Lowercase, TagName};
use roc_module::symbol::Symbol;
use roc_region::all::{Located, Region};
use roc_solve::solve;
use roc_types::pretty_print::Parens;
use roc_types::pretty_print::{Parens, WILDCARD};
use roc_types::types::{Category, ErrorType, PatternCategory, Reason, RecordField, TypeExt};
use std::path::PathBuf;
@ -355,18 +355,44 @@ fn to_expr_report<'b>(
TypedBody { .. } => "The body is".into(),
};
let comparison = type_comparison(
let i_am_seeing = add_category(alloc, alloc.text(it_is), &category);
// TODO: can comparisons between wildcards happen outside the context of an annotation?
let comparison = if is_wildcards_comparison(&found, &expected_type) {
alloc.stack(vec![
i_am_seeing,
alloc.type_block(to_doc(alloc, Parens::Unnecessary, found)),
alloc.concat(vec![
alloc.reflow("But the type annotation on "),
on_name_text,
alloc.reflow(" says it should be a "),
alloc.type_str(WILDCARD),
alloc.reflow(" too! This tells me that the type is connected in a way that doesn't require a wildcard."),
]),
alloc.concat(vec![
alloc.reflow("Since the type has to be the same in both places, the type can be more specific than "),
alloc.type_str(WILDCARD),
alloc.reflow(". You can change the "),
alloc.type_str(WILDCARD),
alloc.reflow(" to a named type variable like "),
alloc.type_variable("a".into()),
alloc.reflow(" to reflect the connection.")
]),
])
} else {
type_comparison(
alloc,
found,
expected_type,
add_category(alloc, alloc.text(it_is), &category),
i_am_seeing,
alloc.concat(vec![
alloc.text("But the type annotation"),
on_name_text,
alloc.text(" says it should be:"),
]),
None,
);
)
};
Report {
title: "TYPE MISMATCH".to_string(),
@ -891,6 +917,14 @@ fn to_expr_report<'b>(
}
}
fn is_wildcards_comparison(type1: &ErrorType, type2: &ErrorType) -> bool {
use ErrorType::*;
match (type1, type2) {
(RigidVar(v1), RigidVar(v2)) if v1.as_str() == WILDCARD && v2.as_str() == WILDCARD => true,
_ => false,
}
}
fn count_arguments(tipe: &ErrorType) -> usize {
use ErrorType::*;

View file

@ -6761,8 +6761,44 @@ I need all branches in an `if` to have the same type!
Tip: Your type annotation uses `a` and `b` as separate type variables.
Your code seems to be saying they are the same though. Maybe they
should be the same your type annotation? Maybe your code uses them in
a weird way?
should be the same in your type annotation? Maybe your code uses them
in a weird way?
"#
),
)
}
fn error_wildcards_are_related() {
report_problem_as(
indoc!(
r#"
f : * -> *
f = \x -> x
f
"#
),
indoc!(
r#"
TYPE MISMATCH
Something is off with the body of the `f` definition:
1 f : * -> *
2 f = \x -> x
^
This `x` value is a:
*
But the type annotation on on `f` says it should be a * too! This tells
me that the type is connected in a way that doesn't require a
wildcard.
Since the type has to be the same in both places, the type can be more
specific than *. You can change the * to a named type variable like `a`
to reflect the connection.
"#
),
)