metamodel: add nullable static types
[nit.git] / src / metamodel / static_type.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2004-2008 Jean Privat <jean@pryen.org>
4 # Copyright 2006-2008 Floréal Morandat <morandat@lirmm.fr>
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License");
7 # you may not use this file except in compliance with the License.
8 # You may obtain a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS,
14 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 # See the License for the specific language governing permissions and
16 # limitations under the License.
17
18 # Static types and property signatures
19 package static_type
20
21 intrude import abstractmetamodel
22
23 redef class MMLocalClass
24 # Cached result of get_type
25 attr _base_type_cache: MMType
26
27 # Return the type of self for this class
28 meth get_type: MMType
29 do
30 if _base_type_cache == null then _base_type_cache = new MMTypeSimpleClass(self)
31 return _base_type_cache
32 end
33
34 # Register a new ancestor
35 protected meth add_ancestor(a: MMAncestor)
36 do
37 assert not _ancestors.has_key(a.local_class)
38 assert a.local_class != self
39 _ancestors[a.local_class] = a
40 end
41
42 # Array of ancestor that associate each superclass with the corresponding ancestor
43 readable attr _ancestors: Map[MMLocalClass, MMAncestor]
44
45 # The ancestor type for a given superclass
46 meth ancestor(c: MMLocalClass): MMType
47 do
48 return _ancestors[c].stype
49 end
50 end
51
52 redef class MMLocalProperty
53 # The signature of the property (where it is declared)
54 readable writable attr _signature: MMSignature
55
56 attr _signatures_cache: HashMap[MMType, MMSignature] = new HashMap[MMType, MMSignature]
57
58 # Return the adapted signature of self for a receiver of type t
59 meth signature_for(t: MMType): MMSignature do
60 if t == local_class.get_type then return signature
61
62 if _signatures_cache.has_key(t) then return _signatures_cache[t]
63
64 var res = signature.adaptation_to(t)
65 _signatures_cache[t] = res
66 return res
67 end
68 end
69
70 # Signature for local properties
71 class MMSignature
72 # The type of the reveiver
73 readable attr _recv: MMType
74
75 # The parameter types
76 attr _params: Array[MMType]
77
78 # The return type
79 readable attr _return_type: MMType
80
81 # The closure parameters
82 readable attr _closures: Array[MMClosure] = new Array[MMClosure]
83
84 # Number of parameters
85 meth arity: Int
86 do
87 assert _params != null
88 return _params.length
89 end
90
91 # Is self a valid subtype of an other signature
92 meth <(s: MMSignature): Bool
93 do
94 assert s != null
95 if self == s then
96 return true
97 end
98 assert _recv.module == s.recv.module
99 if arity != s.arity or (_return_type == null) != (s.return_type == null) then return false
100 if _return_type != null and not _return_type < s.return_type then
101 return false
102 end
103
104 for i in [0..arity[ do
105 if not s[i] < self[i] then
106 return false
107 end
108 end
109
110 if closures.length != s.closures.length then return false
111 for i in [0..closures.length[ do
112 if not s.closures[i] < closures[i] then return false
113 end
114 return true
115 end
116
117 # The type of the i-th parameter
118 meth [](i: Int): MMType
119 do
120 assert _params.length > i
121 return _params[i]
122 end
123
124 redef meth to_s
125 do
126 var s = new Buffer
127 if _params != null and _params.length > 0 then
128 var tmp: String
129 var a = new Array[String].with_capacity(_params.length)
130 for i in [0.._params.length[ do
131 #var pn = _params_name[i]
132 var p = _params[i]
133 #a.add("{pn}: {p}")
134 a.add(p.to_s)
135 end
136 s.append("({a.join(",")})")
137 end
138 if _return_type != null then
139 s.append(": {_return_type}")
140 end
141 return s.to_s
142 end
143
144 # Adapt the signature to a different receiver
145 meth adaptation_to(r: MMType): MMSignature
146 do
147 if _recv == r then
148 return self
149 end
150 var mod = r.module
151 var p = _params
152 if p != null then
153 p = new Array[MMType]
154 for i in _params do
155 p.add(i.for_module(mod).adapt_to(r))
156 end
157 end
158 var rv = _return_type
159 if rv != null then
160 rv = rv.for_module(mod).adapt_to(r)
161 end
162 var res = new MMSignature(p,rv,r)
163 for clos in _closures do
164 res.closures.add(clos.adaptation_to(r))
165 end
166 return res
167 end
168
169 attr _not_for_self_cache: MMSignature = null
170
171 # Return a type approximation if the reveiver is not self
172 # Useful for virtual types
173 meth not_for_self: MMSignature
174 do
175 var res = _not_for_self_cache
176 if res != null then return res
177
178 var need_for_self = false
179 var p = _params
180 if p != null then
181 p = new Array[MMType]
182 for i in _params do
183 var i2 = i.not_for_self
184 if i != i2 then need_for_self = true
185 p.add(i2)
186 end
187 end
188
189 var rv = _return_type
190 if rv != null then
191 rv = rv.not_for_self
192 if rv != _return_type then need_for_self = true
193 end
194
195 var clos = _closures
196 if clos != null then
197 clos = new Array[MMClosure]
198 for c in _closures do
199 var c2 = c.not_for_self
200 if c2 != c then need_for_self = true
201 clos.add(c2)
202 end
203 end
204
205 if need_for_self then
206 res = new MMSignature(p, rv, _recv)
207 res.closures.add_all(clos)
208 else
209 res = self
210 end
211
212 _not_for_self_cache = res
213 return res
214 end
215
216 init(params: Array[MMType], return_type: MMType, r: MMType)
217 do
218 assert params != null
219 _params = params
220 _return_type = return_type
221 _recv = r
222 end
223 end
224
225 # A closure in a signature
226 class MMClosure
227 # The signature of the closure
228 readable attr _signature: MMSignature
229
230 # Is the closure a brek one
231 # aka is defined with the break keyword thus does not return
232 readable attr _is_break: Bool
233
234 # Is the closure optional?
235 # ie is there a default definition
236 readable attr _is_optional: Bool
237
238 # Adapt the signature to a different receiver
239 meth adaptation_to(r: MMType): MMClosure
240 do
241 return new MMClosure(_signature.adaptation_to(r), _is_break, _is_optional)
242 end
243
244 init(s: MMSignature, is_break: Bool, is_optional: Bool)
245 do
246 _signature = s
247 _is_break = is_break
248 _is_optional = is_optional
249 end
250
251 meth not_for_self: MMClosure
252 do
253 var sig = _signature.not_for_self
254 if sig != _signature then
255 return new MMClosure(sig, _is_break, _is_optional)
256 else
257 return self
258 end
259 end
260
261 meth <(c: MMClosure): Bool
262 do
263 if c.is_optional and not is_optional then return false
264 if not c.is_break and is_break then return false
265 return c.signature < signature
266 end
267 end
268
269 # Inheritance relation between two types
270 abstract class MMAncestor
271 # The inherited type
272 readable writable attr _stype: MMType = null
273
274 # The inheriter (heir) type
275 readable writable attr _inheriter: MMType = null
276
277 meth is_reffinement: Bool do
278 return stype.module != stype.module
279 end
280
281 meth is_specialisation: Bool do
282 return stype.local_class.global != inheriter.local_class.global
283 end
284
285 # The inherited class
286 meth local_class: MMLocalClass is abstract
287
288 redef meth to_s
289 do
290 if stype == null then
291 return local_class.to_s
292 else
293 return stype.to_s
294 end
295 end
296 end
297
298 # A static type
299 # Note that static type a related to a specific module
300 abstract class MMType
301 # The module where self makes sence
302 meth module: MMModule is abstract
303
304 # The local class that self direclty or indirectly refers to
305 meth local_class: MMLocalClass is abstract
306
307 # Is the type a valid one
308 # For instance, circular dependency on formal types is invalid
309 meth is_valid: Bool do return true
310
311 # Is self a valid subtype of t
312 meth <(t : MMType): Bool is abstract
313
314 # Is self a valid supertype of t
315 # This method must be only called within definition of < if
316 # a double dispatch is needed
317 meth is_supertype(t: MMType): Bool is abstract
318
319 # Adapt self to another module
320 meth for_module(mod: MMModule): MMType is abstract
321
322 # Get the type adapted to another receiver type
323 # Useful for formal types
324 meth adapt_to(recv: MMType): MMType is abstract
325
326 # Adapt self to another local class context
327 # Useful for genericity
328 # 'c' Must be a super-class of self
329 # Example:
330 # class A[E]
331 # class B[F] special A[F]
332 # class C[G] special B[String]
333 # class D special C[Float]
334 # 'A[Int]'.upcast_for('A') -> 'A[Int]'
335 # 'A[Int]'.upcast_for('B') -> abort
336 # 'B[Int]'.upcast_for('B') -> 'B[Int]'
337 # 'B[Int]'.upcast_for('A') -> 'A[Int]'
338 # 'B[Int]'.upcast_for('C') -> abort
339 # 'C[Int]'.upcast_for('C') -> 'C[Int]'
340 # 'C[Int]'.upcast_for('B') -> 'B[String]'
341 # 'C[Int]'.upcast_for('A') -> 'A[String]'
342 # 'D'.upcast_for('D') -> 'D'
343 # 'D'.upcast_for('C') -> 'C[Float]'
344 # 'D'.upcast_for('B') -> 'C[String]'
345 # 'D'.upcast_for('A') -> 'A[String]'
346 meth upcast_for(c: MMLocalClass): MMType is abstract
347
348 # Return a type approximation if the reveiver is not self
349 # Useful for virtual types
350 meth not_for_self: MMType do return self
351
352 # The nullable version of self (if needed)
353 attr _as_nullable_cache: MMType = null
354
355 # IS the type can accept null?
356 meth is_nullable: Bool do return false
357
358 # Return the nullable version of the type
359 # Noop if already nullable
360 meth as_nullable: MMType do
361 var cache = _as_nullable_cache
362 if cache != null then return cache
363 var res = new MMNullableType(self)
364 _as_nullable_cache = res
365 return res
366 end
367
368 # Return the not null version of the type
369 # Noop if already not null
370 meth as_notnull: MMType do return self
371 end
372
373 class MMNullableType
374 special MMType
375 attr _base_type: MMType
376 redef meth is_nullable: Bool do return true
377 redef meth as_notnull do return _base_type
378 redef meth as_nullable do return self
379 init(t: MMType) do _base_type = t
380
381 redef meth module do return _base_type.module
382
383 redef meth local_class do return _base_type.local_class
384
385 redef meth <(t)
386 do
387 return t isa MMNullableType and _base_type < t.as_notnull
388 end
389
390 redef meth to_s
391 do
392 return "nullable {_base_type}"
393 end
394
395 redef meth is_supertype(t)
396 do
397 return _base_type.is_supertype(t)
398 end
399
400 redef meth for_module(mod)
401 do
402 return _base_type.for_module(mod).as_nullable
403 end
404
405 redef meth adapt_to(recv)
406 do
407 return _base_type.adapt_to(recv).as_nullable
408 end
409
410 redef meth upcast_for(c)
411 do
412 return _base_type.upcast_for(c)
413 end
414
415 redef meth not_for_self
416 do
417 return _base_type.not_for_self.as_nullable
418 end
419 end
420
421 class MMTypeClass
422 special MMType
423 redef readable attr _local_class: MMLocalClass
424 redef meth module do return _local_class.module end
425 redef meth <(t) do return t != null and t.is_supertype(self)
426
427 redef meth to_s
428 do
429 return _local_class.to_s
430 end
431
432 redef meth upcast_for(c)
433 do
434 assert _local_class != null
435 assert c != null
436
437 var t: MMType = self
438 if _local_class != c then
439 t = _local_class.ancestor(c)
440 end
441 assert t != null
442 return t
443 end
444
445 init(c : MMLocalClass)
446 do
447 _local_class = c
448 end
449 end
450
451 class MMTypeSimpleClass
452 special MMTypeClass
453 redef meth is_supertype(t)
454 do
455 return t.local_class.cshe <= _local_class
456 end
457
458 redef meth for_module(mod)
459 do
460 var t: MMType = self
461 if module != mod then
462 t = _local_class.for_module(mod).get_type
463 end
464 assert t != null
465 return t
466 end
467
468 redef meth adapt_to(recv) do return self
469
470 init(c: MMLocalClass)
471 do
472 super(c)
473 end
474 end
475
476 # The type of null
477 class MMTypeNone
478 special MMType
479 redef readable attr _module: MMModule
480 redef meth is_nullable: Bool do return true
481 redef meth <(t) do return t isa MMTypeNone or t isa MMNullableType
482 redef meth to_s do return "null"
483 redef meth is_supertype(t) do return false
484 redef meth local_class do abort
485 redef meth upcast_for(c) do abort
486 redef meth as_nullable do return self
487 redef meth as_notnull do abort
488
489 private init(m: MMModule) do _module = m
490 end
491
492 redef class MMModule
493 # The type of null
494 readable attr _type_none: MMTypeNone = new MMTypeNone(self)
495 end