mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-30 15:21:12 +00:00
parent
8f1878bc42
commit
817bb22f9e
3 changed files with 86 additions and 16 deletions
|
@ -4,7 +4,7 @@ use roc_collections::all::{MutMap, MutSet};
|
||||||
use roc_module::ident::{Lowercase, TagName};
|
use roc_module::ident::{Lowercase, TagName};
|
||||||
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
use roc_module::symbol::{Interns, ModuleId, Symbol};
|
||||||
|
|
||||||
static WILDCARD: &str = "*";
|
pub static WILDCARD: &str = "*";
|
||||||
static EMPTY_RECORD: &str = "{}";
|
static EMPTY_RECORD: &str = "{}";
|
||||||
static EMPTY_TAG_UNION: &str = "[]";
|
static EMPTY_TAG_UNION: &str = "[]";
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@ use roc_module::ident::{Ident, IdentStr, Lowercase, TagName};
|
||||||
use roc_module::symbol::Symbol;
|
use roc_module::symbol::Symbol;
|
||||||
use roc_region::all::{Located, Region};
|
use roc_region::all::{Located, Region};
|
||||||
use roc_solve::solve;
|
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 roc_types::types::{Category, ErrorType, PatternCategory, Reason, RecordField, TypeExt};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
@ -355,18 +355,44 @@ fn to_expr_report<'b>(
|
||||||
TypedBody { .. } => "The body is".into(),
|
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,
|
alloc,
|
||||||
found,
|
found,
|
||||||
expected_type,
|
expected_type,
|
||||||
add_category(alloc, alloc.text(it_is), &category),
|
i_am_seeing,
|
||||||
alloc.concat(vec![
|
alloc.concat(vec![
|
||||||
alloc.text("But the type annotation"),
|
alloc.text("But the type annotation"),
|
||||||
on_name_text,
|
on_name_text,
|
||||||
alloc.text(" says it should be:"),
|
alloc.text(" says it should be:"),
|
||||||
]),
|
]),
|
||||||
None,
|
None,
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
Report {
|
Report {
|
||||||
title: "TYPE MISMATCH".to_string(),
|
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 {
|
fn count_arguments(tipe: &ErrorType) -> usize {
|
||||||
use ErrorType::*;
|
use ErrorType::*;
|
||||||
|
|
||||||
|
|
|
@ -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.
|
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
|
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
|
should be the same in your type annotation? Maybe your code uses them
|
||||||
a weird way?
|
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.
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue