A framework for type inference with subtyping

In type systems based on subtyping, type equality is replaced with subtyping, which is a less restrictive relationship. The idea is, if 71 is a subtype of ~2, then a value of type ~1 can be transparently supplied wherever a value of type r~ is expected. Subtyping has been used as a key concept to create formal type systems for object-oriented languages. These systems often require the programs to be annotated with user-supplied type information. Being able to omit this information--or at least part of it-provides the programmer with a greater degree of freedom; hence, the desire arises to do type inference in the presence of subtyping. This issue has been extensively studied in the past few years. Many type systems have been proposed, with varying degrees of richness and complexity. Possible features are the existence of a least type I and a greatest type T, the presence of contravariant type constructors such as +, the existence of union and intersection types, the existence of recursive types, the ability for the user to extend the type language through generative type declarations, etc. Virtually all of these systems hare their type inference algorithms upon the same principle. Each function application node in the program generates a subtyping constraint, which requires that the actual argument’s type be a subtype of the funct,ion parameter’s t,ype. Type inference consists in gathering these constraints and checking that they admit a solution. The type system we present here is quite general. It has a fixed type language, which is the set of regular types formed with I, T and --+. It is not as powerful as that of [4, 51, which has much more general union and intersection types; still, it is general enough to easily support the addition of a wide class of type constructs, such as extensible records and variants. Type inference is done as explained above; determining whether a conjunction of constraints admits a solution is done through a closure computation [7]. In theory, the issue is settled. In practice, however, things only begin here. The number of constraints accumulated by type inference is large (at best, linear in the program size; at worst, exponential, because let constructs duplicate them). This slows down type inference (the closure algorithm takes time cubic in the number of type variables) and makes types illegible (constraints are part of the type information given to the user). Therefore, algorithms are needed to simplify sets of subtyping constraints, without affecting their meaning. In [14], we introduced two such methods. One removed so-called unreachable constraints; the other used heuristics to come up with substitutions which could be applied to the inferred type schemes without lessening their power. Smith and Trifonov [18] refine the former into a concept called garbage collectron. Besides, they describe a process called canonizatzon, which consists in rewriting a type scheme so that each variable has at most one constructed lower (resp. upper) bound. Other substitution methods can be found in [l]. So, at this point, various simplification methods are known, some of which are very effective, such as garbage collection. However, these are not sufficient to obtain an efficient, well-integrated type inference algorithm; several problems remain. First, substitut.ion heuristics are inherently ineficient. Many possibilities have to be tried out, and each t.rv is costly, since it involves proving that the suhstitution”is lrgal. We solve this problem by eliminating heuristics altogether and replacing them with a very efficient minimizatl:on algorithm, a close cousin to the “Hopcroft” algorithm introduced in [9]. Second, although garbage collection, as described by Smith and Trifonov, works well, it does not preserve the closure property. This is a problem, since we would like the type inference algorithm to work with closed constraint sets at all times, so it can do incremental closure computations. We solve it by showing that. if the type inference rules are properly formulated, then no bipolar type variables are generated, which ensures that garbage collection preserves closure. Third, we give a precise formal descript.iou of the canonizatl;orb algorithm, and we combine it with garbage collection, which makes it more efficient. We also show that. a nat.ural generalization of this algorithm can be used, if desired, to eliminate bipolar variables. Fourth and finally, wp draw a distinction between internal and external simplific:ation methods. The former help efficiency, and can be used throughout the type inference process; the latter help readability, and must. be used only when submitting type information to the user. The former conflict with the latter, which is why the distinction is important; trying to achieve cflicienc,y and readability at the same time is a design mistake.