mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-29 06:44:46 +00:00
fix self-recursive alias case
This commit is contained in:
parent
19761a5d44
commit
18c6c37c04
3 changed files with 104 additions and 37 deletions
|
@ -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),
|
||||
])
|
||||
|
|
|
@ -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>,
|
||||
|
|
|
@ -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 ]
|
||||
┆ ^^^^^^^
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue