fix self-recursive alias case

This commit is contained in:
Folkert 2020-04-14 01:33:02 +02:00
parent 19761a5d44
commit 18c6c37c04
3 changed files with 104 additions and 37 deletions

View file

@ -17,7 +17,7 @@ const CYCLE_LN: &str = ["| ", "│ "][!IS_WINDOWS as usize];
const CYCLE_MID: &str = ["| |", "│ ↓"][!IS_WINDOWS as usize];
const CYCLE_END: &str = ["+-<---+", "└─────┘"][!IS_WINDOWS as usize];
fn cycle<'b>(
pub fn cycle<'b>(
alloc: &'b RocDocAllocator<'b>,
indent: usize,
name: RocDocBuilder<'b>,
@ -402,35 +402,13 @@ pub fn can_problem<'b>(
},
),
Problem::CyclicAlias(symbol, region, others) => {
if others.is_empty() {
todo!("cyclic alias")
} else {
alloc.stack(vec![
alloc
.reflow("The ")
.append(alloc.symbol_unqualified(symbol))
.append(alloc.reflow(" alias is recursive in an invalid way:")),
alloc.region(region),
alloc
.reflow("The ")
.append(alloc.symbol_unqualified(symbol))
.append(alloc.reflow(
" alias depends on itself through the following chain of definitions:",
)),
cycle(
alloc,
4,
alloc.symbol_unqualified(symbol),
others
.into_iter()
.map(|other| alloc.symbol_unqualified(other))
.collect::<Vec<_>>(),
),
alloc.reflow(
"Recursion in aliases is only allowed if recursion happens behind a tag.",
),
])
}
let (doc, title) = crate::type_error::cyclic_alias(alloc, symbol, region, others);
return Report {
filename,
title,
doc,
};
}
Problem::PhantomTypeArgument {
alias,
@ -466,7 +444,7 @@ pub fn can_problem<'b>(
record_region,
} => alloc.stack(vec![
alloc.concat(vec![
alloc.reflow("This annotation defines the "),
alloc.reflow("This record type defines the "),
alloc.record_field(field_name),
alloc.reflow(" field twice!"),
]),
@ -479,7 +457,7 @@ pub fn can_problem<'b>(
tag_region,
} => alloc.stack(vec![
alloc.concat(vec![
alloc.reflow("This annotation defines the "),
alloc.reflow("This tag union type defines the "),
alloc.tag_name(tag_name),
alloc.reflow(" tag twice!"),
]),
@ -500,7 +478,7 @@ fn not_found<'b>(
alloc: &'b RocDocAllocator<'b>,
region: roc_region::all::Region,
name: &str,
thing: &str,
thing: &'b str,
options: MutSet<Box<str>>,
) -> RocDocBuilder<'b> {
use crate::type_error::suggest;
@ -532,7 +510,12 @@ fn not_found<'b>(
};
alloc.stack(vec![
alloc.string(format!("I cannot find a `{}` {}", name, thing)),
alloc.concat(vec![
alloc.reflow("I cannot find a `"),
alloc.string(name.to_string()),
alloc.reflow("` "),
alloc.reflow(thing),
]),
alloc.region(region),
to_details(default_no, default_yes),
])

View file

@ -74,12 +74,66 @@ pub fn type_problem<'b>(
doc,
}
}
CyclicAlias(symbol, region, others) => {
let (doc, title) = cyclic_alias(alloc, symbol, region, others);
Report {
filename,
title,
doc,
}
}
other => panic!("unhandled bad type: {:?}", other),
}
}
}
}
pub fn cyclic_alias<'b>(
alloc: &'b RocDocAllocator<'b>,
symbol: Symbol,
region: roc_region::all::Region,
others: Vec<Symbol>,
) -> (RocDocBuilder<'b>, String) {
let doc = if others.is_empty() {
alloc.stack(vec![
alloc
.reflow("The ")
.append(alloc.symbol_unqualified(symbol))
.append(alloc.reflow(" alias is self-recursive in an invalid way:")),
alloc.region(region),
alloc.reflow("Recursion in aliases is only allowed if recursion happens behind a tag."),
])
} else {
alloc.stack(vec![
alloc
.reflow("The ")
.append(alloc.symbol_unqualified(symbol))
.append(alloc.reflow(" alias is recursive in an invalid way:")),
alloc.region(region),
alloc
.reflow("The ")
.append(alloc.symbol_unqualified(symbol))
.append(alloc.reflow(
" alias depends on itself through the following chain of definitions:",
)),
crate::report::cycle(
alloc,
4,
alloc.symbol_unqualified(symbol),
others
.into_iter()
.map(|other| alloc.symbol_unqualified(other))
.collect::<Vec<_>>(),
),
alloc.reflow("Recursion in aliases is only allowed if recursion happens behind a tag."),
])
};
(doc, "CYCLIC ALIAS".to_string())
}
#[allow(clippy::too_many_arguments)]
fn report_mismatch<'b>(
alloc: &'b RocDocAllocator<'b>,

View file

@ -2274,7 +2274,7 @@ mod test_reporting {
// should not report Bar as unused!
indoc!(
r#"
-- SYNTAX PROBLEM --------------------------------------------------------------
-- CYCLIC ALIAS ----------------------------------------------------------------
The `Bar` alias is recursive in an invalid way:
@ -2307,6 +2307,36 @@ mod test_reporting {
)
}
#[test]
fn self_recursive_alias() {
report_problem_as(
indoc!(
r#"
Foo : { x : Foo }
f : Foo
f = 3
f
"#
),
// should not report Bar as unused!
indoc!(
r#"
-- CYCLIC ALIAS ----------------------------------------------------------------
The `Foo` alias is self-recursive in an invalid way:
1 Foo : { x : Foo }
^^^
Recursion in aliases is only allowed if recursion happens behind a
tag.
"#
),
)
}
#[test]
fn record_duplicate_field_same_type() {
report_problem_as(
@ -2368,7 +2398,7 @@ mod test_reporting {
r#"
-- SYNTAX PROBLEM --------------------------------------------------------------
This annotation defines the `.foo` field twice!
This record type defines the `.foo` field twice!
1 a : { foo : Int, bar : Float, foo : Str }
^^^^^^^^^
@ -2394,7 +2424,7 @@ mod test_reporting {
r#"
-- SYNTAX PROBLEM --------------------------------------------------------------
This annotation defines the `Foo` tag twice!
This tag union type defines the `Foo` tag twice!
1 a : [ Foo Int, Bar Float, Foo Str ]
^^^^^^^