• Aucun résultat trouvé

Compiler's View of Overloading

Implicit Overloading

4.2.2 Compiler's View of Overloading

We have introduced two new constructs,overloadandinstance. Along with that, we have to process implicit and recursive overloading too. We now give a two step, high level description of the extended type checking and overloading resolution algorithm.

The rst step is to execute the type inference algorithm of chapter 3 to determine the Hindley/Milner types of all expressions in the given program. The only addition is that the type of an explicitly overloaded identier is taken to be its HMT template.

The next step is to recursively traverse the given program bottom up assigning type pred-icates to all identiers. This is the major overloading resolution step and is depicted algo-rithmically in gure 4.3. We process one denitional binding at a time, where a denitional binding is either a function denition or a top-level constant denition or one of overloador

instancedeclarations. The syntax followed is a subset of the complete Id language syntax and is similar to that of Id Kernel language (gure 2.7) without performing some of its simplifying transformations8.

There are certain characteristic properties of our resolution algorithm; we list them below.

1. Literals, e.g., 1,2.718,"abracadabra",'atom etc. can not be overloaded9.

8There are some dierences from (gure 2.7); we have not lifted out the internal function denitions, neither do we need to atten all subexpressions, and we have expanded the top-levelMainblock into a sequence of top-level constant denition bindings. Finally, new denitional bindings corresponding tooverloadandinstance are also handled.9

These literals constitute the base types in our typed semantic domain. Without them, the type structure would be quite uninteresting and overloading them will make the job of the type inference system almost

impos-DefOverloading-Resolution(binding)

casebinding of

`overloadIdentier= HMTo' ) Mark Identieras explicitly overloaded.

Generate its predicate function.

`instanceOverloaded-identier =Instance-identier' )

IfOverloaded-identier is not marked overloaded then error.

elseLet typeof Overloaded-identier= Predicateo . HMTo. Let typeof Instance-identier= Predicatei . HMTi.

S = Unify(HMTo,HMTi). (may fail)

Instance-clause = S(Predicateo).

ifInstance-clause overlaps with a previously generated instance clause then error.

elseGenerate Explicit Overloading Rewrite Rule forInstance-identier.

endif.

endif.

`defFunction-identier parameters=body' )

Recursively process all denitional bindings inside the body in topological order.

Collect all overloading predicates from the body instantiated with their type context.

Resolve the predicates using the current set of Rewrite Rules.

ifthere are no unresolved predicates leftthen Mark Function-identieras non-overloaded.

else if there is an unresolved predicate(Identier? t1 tn) such that some ti is not a type variablethen error.

elseMarkFunction-identier as implicitly overloaded.

Generate Implicit Overloading Rewrite Rule forFunction-identier.

endif.

endif.

`Constant-LHS=body' )

Recursively process all denitional bindings inside the body in topological order.

Collect all overloading predicates from the body instantiated with their type context.

Resolve the predicates using the current set of Rewrite Rules.

ifthere is any unresolved predicate then error.

endcase.

Figure 4.3: Overloading Resolution and Propagation Algorithm.

2. The meaning of an overloaded identier is determined by its declared instances and the context of its use that selects one of those instances. The compiler machinery to do these resolutions consists of a set of rewrite rules, one for each implicitly overloaded identier or a declared instance of an explicitly overloaded identier. These rules are then applied to the type context where the overloaded identier is used in order to generate its appropriate instance. The details of this rewrite mechanism will be presented shortly.

3. An identier can be declared to be explicitly overloaded at the top-level or inside the scope of any block expression. The overload declaration denes that identier for all syntactic purposes. The compiler notes this fact by generating its predicate function and its arity. The scope of overloading is exactly the same as the scope of visibility of that identier10.

4. Aninstancedeclaration is processed within the scope of theoverloaddeclaration of the corresponding overloaded identier and the denitional binding of the instance identier.

The compiler action is rst, to generate a type context for the overloaded identier using the type signature of the instance identier, and then to validate that instance (check for overlap with previous instances) and generate the appropriate rules for its resolution. At the moment, we ag an error if we nd a previous overlapping instance. We will rene this behaviour later on.

5. Only function identiers are allowed to be implicitly overloaded. To be precise, a function identier is implicitly overloaded if there is some use of an overloaded identier within its body that remains unresolved. So, we collect all unresolved uses of overloaded identiers in a block expression and attribute it to to its nearest enclosing function denition identier.

When there is no such enclosing function denition, as in the case of top-level constants, we raise an error condition. The reason for not allowing top-level constants to be implicitly overloaded is essentially pragmatic. As stated earlier, overloading can be viewed as a possible parameterization of semantic meaning of the overloaded identier with contextual information. Thus, an overloaded constant behaves like a function, i.e., it has to be re-evaluated in every context in which the overloading gets resolved. This defeats the very purpose of having a constant, which is supposed to be evaluated only once11. We will

10The scope-analysis phase assigns unique names to all identiers and eectivelyattensthe block structure,

review this point at a later stage.

6. We allow a function identier to be implicitly overloaded only if no contextual information is available to resolve its overloading predicates. We raise an error condition if some overloading predicate has partial contextual information but can not be resolved because there is no declared instance to handle it. This does not aect our resolution mechanism and is done essentially for pragmatic reasons.