Closed myreen closed 1 year ago
Currently, letrec
transformations happen before type inference, removing such unreachable top-level declarations before inference sees them. I believe we chose this ordering due to a lack of type signature support (#25), which makes it more efficient to untangle letrec
s before attempting to infer their types from scratch. We can reorder inference/transformation provided we prove that the letrec
transformations preserve typing, at a (small?) loss of efficiency until type signatures are supported.
As discussed in a meeting, we have decided to:
letrec
s and convert non-recursive ones into let
s before type inference (as before)letrec
s after type inferenceThis ensures that dead code will still be type-checked, but removed before demands analysis. We will need to prove that deletion of unreachable letrec
s preserves typing. We should also be able to prove that the passes before type inference preserve free variables, so that the parser no longer needs to check for closedness.
65f55650c57cd04e5cd36f0aed2c9e59faf00252 moves both conversion of non-recursive letrec
s and deletion of unreachable letrec
s to after type inference. The pass making letrec
s distinct and the topological sort remain before type inference.
Unfortunately the parser still has to check for closedness (contrary to the comment above): the distinctness pass can delete free variables. Users can still trigger some of the unexpected behaviour by duplicating declarations, e.g. the following is accepted:
foo = <ill-typed>
foo = <well-typed>
main = do
Ret foo
Ret ()
Surprisingly the compiler accepts:
While it rejects the following: