plt/racket — pull request #616 by takikawa (2014-04-11 21:24:18+00:00)
Title: Fix contracts for mutually recursive type aliases

This PR improves contract generation for large recursive type aliases such as those used in the typed GUI wrapper library. In particular, contract generation will not use huge amounts of memory or loop effectively forever on these large types.

I'd like to merge this for v6.0.1 if possible (testing is supposed to start next Tuesday or so).

The high-level design: define the contracts for recursive type aliases in-line in the module, using the same mechanism as `require/typed`. This allows contracts for these type aliases to be indirected through an identifier. You still get the advantage of static-contracts because these contract definitions will go through an optimization pass (though not the recursive contract pruning).

The downside is that since contracts are always generated for mutually recursive type aliases, it's not very pay-as-you-go for recursive type aliases. Even type aliases that are never used for export/import generate a contract. I don't expect this is a huge downside for most code, but it's a significant downside for `typed/racket/gui`.

On the other hand, this defines contracts only once instead of n times for n imports/exports of values with the relevant type.

With this change, the zo file for `typed/racket/gui` is 18MB. I think I can reduce it by making contract generation for class types a bit more clever (I have a fairly simple patch for this somewhere).

Here's an example interaction that doesn't work without this PR:

````
Welcome to Racket v6.0.0.6.
-> (module a typed/racket (require typed/racket/gui) (define bm% bitmap%) (provide bm%))
-> (require 'a)
-> (send (make-object bm% 100 200) save-file 1 2))
; save-file: contract violation
; expected: (or/c String Path Output-Port)
; given: 1
; in: the 2nd argument of ...
````

On current git HEAD the contract generation will use up all of your RAM instead.