Record all nested recursive structures an entry in the layout cache contains

If an entry in the layout cache contains recursive structures, the entry
is not reusable if the recursive structure is currently in the "seen"
set. The example elucidated in the source code is as follows:

Suppose we are constructing the layout of

```
[A, B (List r)] as r
```

and we have already constructed and cached the layout of `List r`, which would
be

```
List (Recursive [Unit, List RecursivePointer])
```

If we use the cached entry of `List r`, we would end up with the layout

```
Recursive [Unit, (List (Recursive [Unit, List RecursivePointer]))]
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cached layout for `List r`
```

but this is not correct; the canonical layout of `[A, B (List r)] as r` is

```
Recursive [Unit, (List RecursivePointer)]
```

However, the current implementation only preserves this behavior for
structures that contain one recursive structure under them. In practice,
there can be structures that contain multiple recursive structures under
them, and we must be sure to record all those structures in the
layout-cache.
This commit is contained in:
Ayaz Hafiz 2023-03-30 18:15:35 -05:00
parent a003451c1f
commit 247913dc20
No known key found for this signature in database
GPG key ID: 0E2A37416A25EF58
3 changed files with 145 additions and 47 deletions

View file

@ -2859,3 +2859,33 @@ fn issue_4759() {
"#
)
}
#[mono_test]
fn layout_cache_structure_with_multiple_recursive_structures() {
indoc!(
r#"
app "test" provides [main] to "./platform"
Chain : [
End,
Link Chain,
]
LinkedList : [Nil, Cons { first : Chain, rest : LinkedList }]
main =
base : LinkedList
base = Nil
walker : LinkedList, Chain -> LinkedList
walker = \rest, first -> Cons { first, rest }
list : List Chain
list = []
r = List.walk list base walker
r
"#
)
}