]>
Commit | Line | Data |
---|---|---|
85aaf69f SL |
1 | # Type inference engine |
2 | ||
3 | This is loosely based on standard HM-type inference, but with an | |
4 | extension to try and accommodate subtyping. There is nothing | |
5 | principled about this extension; it's sound---I hope!---but it's a | |
6 | heuristic, ultimately, and does not guarantee that it finds a valid | |
7 | typing even if one exists (in fact, there are known scenarios where it | |
8 | fails, some of which may eventually become problematic). | |
9 | ||
10 | ## Key idea | |
11 | ||
12 | The main change is that each type variable T is associated with a | |
13 | lower-bound L and an upper-bound U. L and U begin as bottom and top, | |
14 | respectively, but gradually narrow in response to new constraints | |
15 | being introduced. When a variable is finally resolved to a concrete | |
16 | type, it can (theoretically) select any type that is a supertype of L | |
17 | and a subtype of U. | |
18 | ||
19 | There are several critical invariants which we maintain: | |
20 | ||
21 | - the upper-bound of a variable only becomes lower and the lower-bound | |
22 | only becomes higher over time; | |
23 | - the lower-bound L is always a subtype of the upper bound U; | |
24 | - the lower-bound L and upper-bound U never refer to other type variables, | |
25 | but only to types (though those types may contain type variables). | |
26 | ||
27 | > An aside: if the terms upper- and lower-bound confuse you, think of | |
28 | > "supertype" and "subtype". The upper-bound is a "supertype" | |
29 | > (super=upper in Latin, or something like that anyway) and the lower-bound | |
30 | > is a "subtype" (sub=lower in Latin). I find it helps to visualize | |
31 | > a simple class hierarchy, like Java minus interfaces and | |
32 | > primitive types. The class Object is at the root (top) and other | |
33 | > types lie in between. The bottom type is then the Null type. | |
34 | > So the tree looks like: | |
35 | > | |
36 | > ```text | |
37 | > Object | |
38 | > / \ | |
39 | > String Other | |
40 | > \ / | |
41 | > (null) | |
42 | > ``` | |
43 | > | |
44 | > So the upper bound type is the "supertype" and the lower bound is the | |
45 | > "subtype" (also, super and sub mean upper and lower in Latin, or something | |
46 | > like that anyway). | |
47 | ||
48 | ## Satisfying constraints | |
49 | ||
50 | At a primitive level, there is only one form of constraint that the | |
51 | inference understands: a subtype relation. So the outside world can | |
52 | say "make type A a subtype of type B". If there are variables | |
53 | involved, the inferencer will adjust their upper- and lower-bounds as | |
54 | needed to ensure that this relation is satisfied. (We also allow "make | |
55 | type A equal to type B", but this is translated into "A <: B" and "B | |
56 | <: A") | |
57 | ||
58 | As stated above, we always maintain the invariant that type bounds | |
59 | never refer to other variables. This keeps the inference relatively | |
60 | simple, avoiding the scenario of having a kind of graph where we have | |
61 | to pump constraints along and reach a fixed point, but it does impose | |
62 | some heuristics in the case where the user is relating two type | |
63 | variables A <: B. | |
64 | ||
65 | Combining two variables such that variable A will forever be a subtype | |
66 | of variable B is the trickiest part of the algorithm because there is | |
67 | often no right choice---that is, the right choice will depend on | |
68 | future constraints which we do not yet know. The problem comes about | |
69 | because both A and B have bounds that can be adjusted in the future. | |
70 | Let's look at some of the cases that can come up. | |
71 | ||
72 | Imagine, to start, the best case, where both A and B have an upper and | |
73 | lower bound (that is, the bounds are not top nor bot respectively). In | |
74 | that case, if we're lucky, A.ub <: B.lb, and so we know that whatever | |
75 | A and B should become, they will forever have the desired subtyping | |
76 | relation. We can just leave things as they are. | |
77 | ||
78 | ### Option 1: Unify | |
79 | ||
80 | However, suppose that A.ub is *not* a subtype of B.lb. In | |
81 | that case, we must make a decision. One option is to unify A | |
82 | and B so that they are one variable whose bounds are: | |
83 | ||
84 | UB = GLB(A.ub, B.ub) | |
85 | LB = LUB(A.lb, B.lb) | |
86 | ||
87 | (Note that we will have to verify that LB <: UB; if it does not, the | |
88 | types are not intersecting and there is an error) In that case, A <: B | |
89 | holds trivially because A==B. However, we have now lost some | |
90 | flexibility, because perhaps the user intended for A and B to end up | |
91 | as different types and not the same type. | |
92 | ||
93 | Pictorally, what this does is to take two distinct variables with | |
94 | (hopefully not completely) distinct type ranges and produce one with | |
95 | the intersection. | |
96 | ||
97 | ```text | |
98 | B.ub B.ub | |
99 | /\ / | |
100 | A.ub / \ A.ub / | |
101 | / \ / \ \ / | |
102 | / X \ UB | |
103 | / / \ \ / \ | |
104 | / / / \ / / | |
105 | \ \ / / \ / | |
106 | \ X / LB | |
107 | \ / \ / / \ | |
108 | \ / \ / / \ | |
109 | A.lb B.lb A.lb B.lb | |
110 | ``` | |
111 | ||
112 | ||
113 | ### Option 2: Relate UB/LB | |
114 | ||
115 | Another option is to keep A and B as distinct variables but set their | |
116 | bounds in such a way that, whatever happens, we know that A <: B will hold. | |
117 | This can be achieved by ensuring that A.ub <: B.lb. In practice there | |
118 | are two ways to do that, depicted pictorially here: | |
119 | ||
120 | ```text | |
121 | Before Option #1 Option #2 | |
122 | ||
123 | B.ub B.ub B.ub | |
124 | /\ / \ / \ | |
125 | A.ub / \ A.ub /(B')\ A.ub /(B')\ | |
126 | / \ / \ \ / / \ / / | |
127 | / X \ __UB____/ UB / | |
128 | / / \ \ / | | / | |
129 | / / / \ / | | / | |
130 | \ \ / / /(A')| | / | |
131 | \ X / / LB ______LB/ | |
132 | \ / \ / / / \ / (A')/ \ | |
133 | \ / \ / \ / \ \ / \ | |
134 | A.lb B.lb A.lb B.lb A.lb B.lb | |
135 | ``` | |
136 | ||
137 | In these diagrams, UB and LB are defined as before. As you can see, | |
138 | the new ranges `A'` and `B'` are quite different from the range that | |
139 | would be produced by unifying the variables. | |
140 | ||
141 | ### What we do now | |
142 | ||
143 | Our current technique is to *try* (transactionally) to relate the | |
144 | existing bounds of A and B, if there are any (i.e., if `UB(A) != top | |
145 | && LB(B) != bot`). If that succeeds, we're done. If it fails, then | |
146 | we merge A and B into same variable. | |
147 | ||
148 | This is not clearly the correct course. For example, if `UB(A) != | |
149 | top` but `LB(B) == bot`, we could conceivably set `LB(B)` to `UB(A)` | |
150 | and leave the variables unmerged. This is sometimes the better | |
151 | course, it depends on the program. | |
152 | ||
153 | The main case which fails today that I would like to support is: | |
154 | ||
155 | ```text | |
156 | fn foo<T>(x: T, y: T) { ... } | |
157 | ||
158 | fn bar() { | |
159 | let x: @mut int = @mut 3; | |
160 | let y: @int = @3; | |
161 | foo(x, y); | |
162 | } | |
163 | ``` | |
164 | ||
165 | In principle, the inferencer ought to find that the parameter `T` to | |
166 | `foo(x, y)` is `@const int`. Today, however, it does not; this is | |
167 | because the type variable `T` is merged with the type variable for | |
168 | `X`, and thus inherits its UB/LB of `@mut int`. This leaves no | |
169 | flexibility for `T` to later adjust to accommodate `@int`. | |
170 | ||
171 | ### What to do when not all bounds are present | |
172 | ||
173 | In the prior discussion we assumed that A.ub was not top and B.lb was | |
174 | not bot. Unfortunately this is rarely the case. Often type variables | |
175 | have "lopsided" bounds. For example, if a variable in the program has | |
176 | been initialized but has not been used, then its corresponding type | |
177 | variable will have a lower bound but no upper bound. When that | |
178 | variable is then used, we would like to know its upper bound---but we | |
179 | don't have one! In this case we'll do different things depending on | |
180 | how the variable is being used. | |
181 | ||
182 | ## Transactional support | |
183 | ||
184 | Whenever we adjust merge variables or adjust their bounds, we always | |
185 | keep a record of the old value. This allows the changes to be undone. | |
186 | ||
187 | ## Regions | |
188 | ||
189 | I've only talked about type variables here, but region variables | |
190 | follow the same principle. They have upper- and lower-bounds. A | |
191 | region A is a subregion of a region B if A being valid implies that B | |
192 | is valid. This basically corresponds to the block nesting structure: | |
193 | the regions for outer block scopes are superregions of those for inner | |
194 | block scopes. | |
195 | ||
196 | ## Integral and floating-point type variables | |
197 | ||
198 | There is a third variety of type variable that we use only for | |
199 | inferring the types of unsuffixed integer literals. Integral type | |
200 | variables differ from general-purpose type variables in that there's | |
201 | no subtyping relationship among the various integral types, so instead | |
202 | of associating each variable with an upper and lower bound, we just | |
203 | use simple unification. Each integer variable is associated with at | |
204 | most one integer type. Floating point types are handled similarly to | |
205 | integral types. | |
206 | ||
207 | ## GLB/LUB | |
208 | ||
209 | Computing the greatest-lower-bound and least-upper-bound of two | |
210 | types/regions is generally straightforward except when type variables | |
211 | are involved. In that case, we follow a similar "try to use the bounds | |
212 | when possible but otherwise merge the variables" strategy. In other | |
213 | words, `GLB(A, B)` where `A` and `B` are variables will often result | |
214 | in `A` and `B` being merged and the result being `A`. | |
215 | ||
216 | ## Type coercion | |
217 | ||
218 | We have a notion of assignability which differs somewhat from | |
219 | subtyping; in particular it may cause region borrowing to occur. See | |
220 | the big comment later in this file on Type Coercion for specifics. | |
221 | ||
222 | ### In conclusion | |
223 | ||
224 | I showed you three ways to relate `A` and `B`. There are also more, | |
225 | of course, though I'm not sure if there are any more sensible options. | |
226 | The main point is that there are various options, each of which | |
227 | produce a distinct range of types for `A` and `B`. Depending on what | |
228 | the correct values for A and B are, one of these options will be the | |
229 | right choice: but of course we don't know the right values for A and B | |
230 | yet, that's what we're trying to find! In our code, we opt to unify | |
231 | (Option #1). | |
232 | ||
233 | # Implementation details | |
234 | ||
235 | We make use of a trait-like implementation strategy to consolidate | |
236 | duplicated code between subtypes, GLB, and LUB computations. See the | |
237 | section on "Type Combining" below for details. |