Provide warning for defs that are used only in (mutual) recursion

This patch provides errors for defs that are used only in
possibly-mutual recursion, and are not reachable outside of their
recursive closures. For example:

```
test_report!(
    mutual_recursion_not_reached_nested,
    indoc!(
        r#"
        app "test" provides [main] to "./platform"

        main =
            f = \{} -> if Bool.true then "" else g {}
            g = \{} -> if Bool.true then "" else f {}
            ""
        "#
    ),
@r###"
── DEFINITIONs ONLY USED IN RECURSION ──────────────────── /code/proj/Main.roc ─

These 2 definitions are only used in mutual recursion with themselves:

4│>      f = \{} -> if Bool.true then "" else g {}
5│>      g = \{} -> if Bool.true then "" else f {}

If you don't intend to use or export any of them, they should all be
removed!
"###
);
```
This commit is contained in:
Ayaz Hafiz 2022-12-01 18:26:01 -06:00
parent 1beb00f490
commit 0a807dc43e
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
8 changed files with 262 additions and 15 deletions

View file

@ -40,6 +40,7 @@ pub enum Problem {
/// Second symbol is the name of the argument that is unused
UnusedArgument(Symbol, bool, Symbol, Region),
UnusedBranchDef(Symbol, Region),
DefsOnlyUsedInRecursion(usize, Region),
PrecedenceProblem(PrecedenceProblem),
// Example: (5 = 1 + 2) is an unsupported pattern in an assignment; Int patterns aren't allowed in assignments!
UnsupportedPattern(BadPattern, Region),
@ -333,7 +334,8 @@ impl Problem {
| Problem::BadTypeArguments { region, .. }
| Problem::UnnecessaryOutputWildcard { region }
| Problem::OverAppliedCrash { region }
| Problem::UnappliedCrash { region } => Some(*region),
| Problem::UnappliedCrash { region }
| Problem::DefsOnlyUsedInRecursion(_, region) => Some(*region),
Problem::RuntimeError(RuntimeError::CircularDef(cycle_entries))
| Problem::BadRecursion(cycle_entries) => {
cycle_entries.first().map(|entry| entry.expr_region)