Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | TypeChecking |
2 | ============ | |
3 | ||
4 | MLton's type checker follows the <:DefinitionOfStandardML:Definition> | |
5 | closely, so you may find differences between MLton and other SML | |
6 | compilers that do not follow the Definition so closely. In | |
7 | particular, SML/NJ has many deviations from the Definition -- please | |
8 | see <:SMLNJDeviations:> for those that we are aware of. | |
9 | ||
10 | In some respects MLton's type checker is more powerful than other SML | |
11 | compilers, so there are programs that MLton accepts that are rejected | |
12 | by some other SML compilers. These kinds of programs fall into a few | |
13 | simple categories. | |
14 | ||
15 | * MLton resolves flexible record patterns using a larger context than | |
16 | many other SML compilers. For example, MLton accepts the | |
17 | following. | |
18 | + | |
19 | [source,sml] | |
20 | ---- | |
21 | fun f {x, ...} = x | |
22 | val _ = f {x = 13, y = "foo"} | |
23 | ---- | |
24 | ||
25 | * MLton uses as large a context as possible to resolve the type of | |
26 | variables constrained by the value restriction to be monotypes. For | |
27 | example, MLton accepts the following. | |
28 | + | |
29 | [source,sml] | |
30 | ---- | |
31 | structure S: | |
32 | sig | |
33 | val f: int -> int | |
34 | end = | |
35 | struct | |
36 | val f = (fn x => x) (fn y => y) | |
37 | end | |
38 | ---- | |
39 | ||
40 | ||
41 | == Type error messages == | |
42 | ||
43 | To aid in the understanding of type errors, MLton's type checker | |
44 | displays type errors differently than other SML compilers. In | |
45 | particular, when two types are different, it is important for the | |
46 | programmer to easily understand why they are different. So, MLton | |
47 | displays only the differences between two types that don't match, | |
48 | using underscores for the parts that match. For example, if a | |
49 | function expects `real * int` but gets `real * real`, the type error | |
50 | message would look like | |
51 | ||
52 | ---- | |
53 | expects: _ * [int] | |
54 | but got: _ * [real] | |
55 | ---- | |
56 | ||
57 | As another aid to spotting differences, MLton places brackets `[]` | |
58 | around the parts of the types that don't match. A common situation is | |
59 | when a function receives a different number of arguments than it | |
60 | expects, in which case you might see an error like | |
61 | ||
62 | ---- | |
63 | expects: [int * real] | |
64 | but got: [int * real * string] | |
65 | ---- | |
66 | ||
67 | The brackets make it easy to see that the problem is that the tuples | |
68 | have different numbers of components -- not that the components don't | |
69 | match. Contrast that with a case where a function receives the right | |
70 | number of arguments, but in the wrong order, in which case you might | |
71 | see an error like | |
72 | ||
73 | ---- | |
74 | expects: [int] * [real] | |
75 | but got: [real] * [int] | |
76 | ---- | |
77 | ||
78 | Here the brackets make it easy to see that the components do not match. | |
79 | ||
80 | We appreciate feedback on any type error messages that you find | |
81 | confusing, or suggestions you may have for improvements to error | |
82 | messages. | |
83 | ||
84 | ||
85 | == The shortest/most-recent rule for type names == | |
86 | ||
87 | In a type error message, MLton often has a number of choices in | |
88 | deciding what name to use for a type. For example, in the following | |
89 | type-incorrect program | |
90 | ||
91 | [source,sml] | |
92 | ---- | |
93 | type t = int | |
94 | fun f (x: t) = x | |
95 | val _ = f "foo" | |
96 | ---- | |
97 | ||
98 | MLton reports the error message | |
99 | ||
100 | ---- | |
101 | Error: z.sml 3.9-3.15. | |
102 | Function applied to incorrect argument. | |
103 | expects: [t] | |
104 | but got: [string] | |
105 | in: f "foo" | |
106 | ---- | |
107 | ||
108 | MLton could have reported `expects: [int]` instead of `expects: [t]`. | |
109 | However, MLton uses the shortest/most-recent rule in order to decide | |
110 | what type name to display. This rule means that, at the point of the | |
111 | error, MLton first looks for the shortest name for a type in terms of | |
112 | number of structure identifiers (e.g. `foobar` is shorter than `A.t`). | |
113 | Next, if there are multiple names of the same length, then MLton uses | |
114 | the most recently defined name. It is this tiebreaker that causes | |
115 | MLton to prefer `t` to `int` in the above example. | |
116 | ||
117 | In signature matching, most recently defined is not taken to include | |
118 | all of the definitions introduced by the structure (since the matching | |
119 | takes place outside the structure and before it is defined). For | |
120 | example, in the following type-incorrect program | |
121 | ||
122 | [source,sml] | |
123 | ---- | |
124 | structure S: | |
125 | sig | |
126 | val x: int | |
127 | end = | |
128 | struct | |
129 | type t = int | |
130 | val x = "foo" | |
131 | end | |
132 | ---- | |
133 | ||
134 | MLton reports the error message | |
135 | ||
136 | ---- | |
137 | Error: z.sml 2.4-4.6. | |
138 | Variable in structure disagrees with signature (type): x. | |
139 | structure: val x: [string] | |
140 | defn at: z.sml 7.11-7.11 | |
141 | signature: val x: [int] | |
142 | spec at: z.sml 3.11-3.11 | |
143 | ---- | |
144 | ||
145 | If there is a type that only exists inside the structure being | |
146 | matched, then the prefix `_str.` is used. For example, in the | |
147 | following type-incorrect program | |
148 | ||
149 | [source,sml] | |
150 | ---- | |
151 | structure S: | |
152 | sig | |
153 | val x: int | |
154 | end = | |
155 | struct | |
156 | datatype t = T | |
157 | val x = T | |
158 | end | |
159 | ---- | |
160 | ||
161 | MLton reports the error message | |
162 | ||
163 | ---- | |
164 | Error: z.sml 2.4-4.6. | |
165 | Variable in structure disagrees with signature (type): x. | |
166 | structure: val x: [_str.t] | |
167 | defn at: z.sml 7.11-7.11 | |
168 | signature: val x: [int] | |
169 | spec at: z.sml 3.11-3.11 | |
170 | ---- | |
171 | ||
172 | in which the `[_str.t]` refers to the type defined in the structure. |