Improve error message when shadowing builtin type

Closes #3109
This commit is contained in:
Ayaz Hafiz 2022-09-21 12:54:26 -05:00
parent ae122a0aea
commit 5f117be306
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
5 changed files with 90 additions and 62 deletions

View file

@ -2302,11 +2302,6 @@ fn to_pending_alias_or_opaque<'a>(
opt_derived: Option<&'a Loc<ast::HasAbilities<'a>>>,
kind: AliasKind,
) -> PendingTypeDef<'a> {
let shadow_kind = match kind {
AliasKind::Structural => ShadowKind::Alias,
AliasKind::Opaque => ShadowKind::Opaque,
};
let region = Region::span_across(&name.region, &ann.region);
match scope.introduce_without_shadow_symbol(&Ident::from(name.value), region) {
@ -2361,7 +2356,12 @@ fn to_pending_alias_or_opaque<'a>(
}
}
Err((original_region, loc_shadowed_symbol)) => {
Err((original_sym, original_region, loc_shadowed_symbol)) => {
let shadow_kind = match kind {
AliasKind::Structural => ShadowKind::Alias(original_sym),
AliasKind::Opaque => ShadowKind::Opaque(original_sym),
};
env.problem(Problem::Shadowing {
original_region,
shadow: loc_shadowed_symbol,
@ -2422,11 +2422,11 @@ fn to_pending_type_def<'a>(
.introduce_without_shadow_symbol(&Ident::from(name.value), name.region)
{
Ok(symbol) => Loc::at(name.region, symbol),
Err((original_region, shadowed_symbol)) => {
Err((original_symbol, original_region, shadowed_symbol)) => {
env.problem(Problem::Shadowing {
original_region,
shadow: shadowed_symbol,
kind: ShadowKind::Ability,
kind: ShadowKind::Ability(original_symbol),
});
return PendingTypeDef::AbilityShadows;
}

View file

@ -284,14 +284,14 @@ impl Scope {
&mut self,
ident: &Ident,
region: Region,
) -> Result<Symbol, (Region, Loc<Ident>)> {
) -> Result<Symbol, (Symbol, Region, Loc<Ident>)> {
match self.introduce_help(ident.as_str(), region) {
Err((_, original_region)) => {
Err((symbol, original_region)) => {
let shadow = Loc {
value: ident.clone(),
region,
};
Err((original_region, shadow))
Err((symbol, original_region, shadow))
}
Ok(symbol) => Ok(symbol),
}

View file

@ -22,9 +22,9 @@ pub enum BadPattern {
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum ShadowKind {
Variable,
Alias,
Opaque,
Ability,
Alias(Symbol),
Opaque(Symbol),
Ability(Symbol),
}
/// Problems that can occur in the course of canonicalization.

View file

@ -257,9 +257,11 @@ pub fn can_problem<'b>(
shadow,
kind,
} => {
doc = report_shadowing(alloc, lines, original_region, shadow, kind);
let (res_title, res_doc) =
report_shadowing(alloc, lines, original_region, shadow, kind);
title = DUPLICATE_NAME.to_string();
doc = res_doc;
title = res_title.to_string();
severity = Severity::RuntimeError;
}
Problem::CyclicAlias(symbol, region, others, alias_kind) => {
@ -1371,14 +1373,31 @@ fn report_shadowing<'b>(
original_region: Region,
shadow: Loc<Ident>,
kind: ShadowKind,
) -> RocDocBuilder<'b> {
let what = match kind {
ShadowKind::Variable => "variables",
ShadowKind::Alias => "aliases",
ShadowKind::Opaque => "opaques",
ShadowKind::Ability => "abilities",
) -> (&'static str, RocDocBuilder<'b>) {
let (what, what_plural, is_builtin) = match kind {
ShadowKind::Variable => ("variable", "variables", false),
ShadowKind::Alias(sym) => ("alias", "aliases", sym.is_builtin()),
ShadowKind::Opaque(sym) => ("opaque type", "opaque types", sym.is_builtin()),
ShadowKind::Ability(sym) => ("ability", "abilities", sym.is_builtin()),
};
let doc = if is_builtin {
alloc.stack([
alloc.concat([
alloc.reflow("This "),
alloc.reflow(what),
alloc.reflow(" has the same name as a builtin:"),
]),
alloc.region(lines.convert_region(shadow.region)),
alloc.concat([
alloc.reflow("All builtin "),
alloc.reflow(what_plural),
alloc.reflow(" are in scope by default, so I need this "),
alloc.reflow(what),
alloc.reflow(" to have a different name!"),
]),
])
} else {
alloc.stack([
alloc
.text("The ")
@ -1389,10 +1408,13 @@ fn report_shadowing<'b>(
alloc.region(lines.convert_region(shadow.region)),
alloc.concat([
alloc.reflow("Since these "),
alloc.reflow(what),
alloc.reflow(what_plural),
alloc.reflow(" have the same name, it's easy to use the wrong one on accident. Give one of them a new name."),
]),
])
};
(DUPLICATE_NAME, doc)
}
fn pretty_runtime_error<'b>(
@ -1420,8 +1442,7 @@ fn pretty_runtime_error<'b>(
shadow,
kind,
} => {
doc = report_shadowing(alloc, lines, original_region, shadow, kind);
title = DUPLICATE_NAME;
(title, doc) = report_shadowing(alloc, lines, original_region, shadow, kind);
}
RuntimeError::LookupNotInScope(loc_name, options) => {

View file

@ -6198,18 +6198,13 @@ All branches in an `if` must have the same type!
@r###"
DUPLICATE NAME /code/proj/Main.roc
The `Result` name is first defined here:
1 app "test" provides [main] to "./platform"
But then it's defined a second time here:
This alias has the same name as a builtin:
4 Result a b : [Ok a, Err b]
^^^^^^^^^^^^^^^^^^^^^^^^^^
Since these aliases have the same name, it's easy to use the wrong one
on accident. Give one of them a new name.
All builtin aliases are in scope by default, so I need this alias to
have a different name!
TOO FEW TYPE ARGUMENTS /code/proj/Main.roc
@ -6241,18 +6236,13 @@ All branches in an `if` must have the same type!
@r###"
DUPLICATE NAME /code/proj/Main.roc
The `Result` name is first defined here:
1 app "test" provides [main] to "./platform"
But then it's defined a second time here:
This alias has the same name as a builtin:
4 Result a b : [Ok a, Err b]
^^^^^^^^^^^^^^^^^^^^^^^^^^
Since these aliases have the same name, it's easy to use the wrong one
on accident. Give one of them a new name.
All builtin aliases are in scope by default, so I need this alias to
have a different name!
TOO MANY TYPE ARGUMENTS /code/proj/Main.roc
@ -7435,18 +7425,13 @@ All branches in an `if` must have the same type!
@r###"
DUPLICATE NAME /code/proj/Main.roc
The `Result` name is first defined here:
1 app "test" provides [main] to "./platform"
But then it's defined a second time here:
This alias has the same name as a builtin:
4 Result a b : [Ok a, Err b]
^^^^^^^^^^^^^^^^^^^^^^^^^^
Since these aliases have the same name, it's easy to use the wrong one
on accident. Give one of them a new name.
All builtin aliases are in scope by default, so I need this alias to
have a different name!
"###
);
@ -10710,4 +10695,26 @@ All branches in an `if` must have the same type!
be safely removed!
"###
);
test_report!(
custom_type_conflicts_with_builtin,
indoc!(
r#"
Nat := [ S Nat, Z ]
""
"#
),
@r###"
DUPLICATE NAME /code/proj/Main.roc
This opaque type has the same name as a builtin:
4 Nat := [ S Nat, Z ]
^^^^^^^^^^^^^^^^^^^
All builtin opaque types are in scope by default, so I need this
opaque type to have a different name!
"###
);
}