Commit | Line | Data |
---|---|---|
7f918cf1 CE |
1 | (* Copyright (C) 2017 Matthew Fluet. |
2 | * Copyright (C) 1999-2008 Henry Cejtin, Matthew Fluet, Suresh | |
3 | * Jagannathan, and Stephen Weeks. | |
4 | * Copyright (C) 1997-2000 NEC Research Institute. | |
5 | * | |
6 | * MLton is released under a BSD-style license. | |
7 | * See the file MLton-LICENSE for details. | |
8 | *) | |
9 | ||
10 | functor HashType (S: HASH_TYPE_STRUCTS): HASH_TYPE = | |
11 | struct | |
12 | ||
13 | open S | |
14 | ||
15 | structure Type = | |
16 | struct | |
17 | datatype t = | |
18 | T of { | |
19 | hash: Word.t, | |
20 | plist: PropertyList.t, | |
21 | tree: tree | |
22 | } | |
23 | and tree = | |
24 | Var of Tyvar.t | |
25 | | Con of Tycon.t * t vector | |
26 | ||
27 | local | |
28 | fun make f (T r) = f r | |
29 | in | |
30 | val hash = make #hash | |
31 | val plist = make #plist | |
32 | val tree = make #tree | |
33 | end | |
34 | ||
35 | local | |
36 | open Layout | |
37 | in | |
38 | val rec layoutTree = | |
39 | fn Var a => Tyvar.layout a | |
40 | | Con (c, ts) => | |
41 | seq [Tycon.layout c, | |
42 | Vector.layout (layoutTree o tree) ts] | |
43 | end | |
44 | ||
45 | structure Dest = | |
46 | struct | |
47 | datatype dest = datatype tree | |
48 | val dest = tree | |
49 | end | |
50 | open Dest | |
51 | ||
52 | fun deConOpt t = | |
53 | case dest t of | |
54 | Con x => SOME x | |
55 | | _ => NONE | |
56 | ||
57 | fun makeHom {con, var} = | |
58 | let | |
59 | val {get, destroy, ...} = | |
60 | Property.destGet | |
61 | (plist, | |
62 | Property.initRec | |
63 | (fn (t, get) => | |
64 | case dest t of | |
65 | Var a => var (t, a) | |
66 | | Con (c, ts) => con (t, c, Vector.map (ts, get)))) | |
67 | in {hom = get, destroy = destroy} | |
68 | end | |
69 | ||
70 | fun hom {ty, var, con} = | |
71 | let | |
72 | val {hom, destroy} = makeHom {var = var o #2, | |
73 | con = fn (_, c, xs) => con (c, xs)} | |
74 | val res = hom ty | |
75 | val _ = destroy () | |
76 | in res | |
77 | end | |
78 | ||
79 | fun makeMonoHom {con} = | |
80 | makeHom {var = fn _ => Error.bug "HashType.Type.makeMonoHom: type variable", | |
81 | con = con} | |
82 | ||
83 | fun equals (t, t'): bool = PropertyList.equals (plist t, plist t') | |
84 | ||
85 | fun layoutPretty (ty: t): Layout.t = | |
86 | #1 (hom {con = fn (c, ts) => (Tycon.layoutAppPretty | |
87 | (c, ts, {layoutPretty = Tycon.layout})), | |
88 | ty = ty, | |
89 | var = fn a => LayoutPretty.simple (Tyvar.layout a)}) | |
90 | ||
91 | fun layout (ty: t): Layout.t = | |
92 | hom {con = Tycon.layoutApp, | |
93 | ty = ty, | |
94 | var = Tyvar.layout} | |
95 | ||
96 | local | |
97 | val same: tree * tree -> bool = | |
98 | fn (Var a, Var a') => Tyvar.equals (a, a') | |
99 | | (Con (c, ts), Con (c', ts')) => | |
100 | Tycon.equals (c, c') | |
101 | andalso Vector.equals (ts, ts', equals) | |
102 | | _ => false | |
103 | val same = | |
104 | Trace.trace2 ("HashType.Type.same", layoutTree, layoutTree, Bool.layout) | |
105 | same | |
106 | val table: t HashSet.t = HashSet.new {hash = hash} | |
107 | in | |
108 | fun lookup (hash, tr) = | |
109 | HashSet.lookupOrInsert (table, hash, | |
110 | fn t => same (tr, tree t), | |
111 | fn () => T {hash = hash, | |
112 | plist = PropertyList.new (), | |
113 | tree = tr}) | |
114 | ||
115 | fun stats () = | |
116 | let open Layout | |
117 | in align [seq [str "num types in hash table = ", | |
118 | Int.layout (HashSet.size table)], | |
119 | Control.sizeMessage ("types hash table", table)] | |
120 | end | |
121 | end | |
122 | ||
123 | fun var a = lookup (Tyvar.hash a, Var a) | |
124 | ||
125 | local | |
126 | val generator: Word.t = 0wx5555 | |
127 | in | |
128 | fun con (c, ts) = | |
129 | lookup (Vector.fold (ts, Tycon.hash c, fn (t, w) => | |
130 | Word.xorb (w * generator, hash t)), | |
131 | Con (c, ts)) | |
132 | val con = Trace.trace2 ("HashType.Type.con", | |
133 | Tycon.layout, | |
134 | Vector.layout layout, | |
135 | layout) con | |
136 | end | |
137 | end | |
138 | structure Ops = TypeOps (structure Tycon = Tycon | |
139 | open Type) | |
140 | open Type Ops | |
141 | ||
142 | val string = word8Vector | |
143 | ||
144 | fun ofConst c = | |
145 | let | |
146 | datatype z = datatype Const.t | |
147 | in | |
148 | case c of | |
149 | IntInf _ => intInf | |
150 | | Null => cpointer | |
151 | | Real r => real (RealX.size r) | |
152 | | Word w => word (WordX.size w) | |
153 | | WordVector v => vector (word (WordXVector.elementSize v)) | |
154 | end | |
155 | ||
156 | fun isUnit t = | |
157 | case dest t of | |
158 | Con (c, ts) => Vector.isEmpty ts andalso Tycon.equals (c, Tycon.tuple) | |
159 | | _ => false | |
160 | ||
161 | fun substitute (ty, v) = | |
162 | if Vector.isEmpty v | |
163 | then ty (* This optimization is important so that monotypes | |
164 | * are not substituted inside of. | |
165 | *) | |
166 | else | |
167 | hom {ty = ty, | |
168 | var = fn a => (case Vector.peek (v, fn (a', _) => | |
169 | Tyvar.equals (a, a')) of | |
170 | NONE => var a | |
171 | | SOME (_, ty) => ty), | |
172 | con = con} | |
173 | ||
174 | val substitute = | |
175 | Trace.trace2 | |
176 | ("HashType.substitute", | |
177 | layout, | |
178 | Vector.layout (Layout.tuple2 (Tyvar.layout, Type.layout)), | |
179 | layout) | |
180 | substitute | |
181 | ||
182 | (* fun equalss (ts: t list): t option = | |
183 | * case ts of | |
184 | * t :: ts => | |
185 | * let fun loop [] = SOME t | |
186 | * | loop (t' :: ts) = if equals (t, t') then loop ts else NONE | |
187 | * in loop ts | |
188 | * end | |
189 | * | [] => Error.bug "HashType.equals" | |
190 | *) | |
191 | ||
192 | local | |
193 | val out = Out.error | |
194 | val print = Out.outputc out | |
195 | exception TypeError | |
196 | in | |
197 | fun error (msg, lay) = | |
198 | (print (concat ["Type error: ", msg, "\n"]) | |
199 | ; Layout.output (lay, out) | |
200 | ; print "\n" | |
201 | ; raise TypeError) | |
202 | end | |
203 | ||
204 | fun tycon t = | |
205 | case dest t of | |
206 | Con (c, _) => c | |
207 | | _ => Error.bug "HashType.tycon: type variable" | |
208 | ||
209 | fun containsTycon (ty, tycon) = | |
210 | hom {ty = ty, | |
211 | var = fn _ => false, | |
212 | con = fn (tycon', bs) => (Tycon.equals (tycon, tycon') | |
213 | orelse Vector.exists (bs, fn b => b))} | |
214 | ||
215 | fun checkPrimApp {args, prim, result, targs}: bool = | |
216 | Prim.checkApp (prim, | |
217 | {args = args, | |
218 | result = result, | |
219 | targs = targs, | |
220 | typeOps = {array = array, | |
221 | arrow = arrow, | |
222 | bool = bool, | |
223 | cpointer = cpointer, | |
224 | equals = equals, | |
225 | exn = exn, | |
226 | intInf = intInf, | |
227 | real = real, | |
228 | reff = reff, | |
229 | thread = thread, | |
230 | unit = unit, | |
231 | vector = vector, | |
232 | weak = weak, | |
233 | word = word}}) | |
234 | end |