metamodel: fix MMType::is_valid for indirect 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_valid do return _base_type.is_valid
377 redef meth is_nullable: Bool do return true
378 redef meth as_notnull do return _base_type
379 redef meth as_nullable do return self
380 init(t: MMType) do _base_type = t
381
382 redef meth module do return _base_type.module
383
384 redef meth local_class do return _base_type.local_class
385
386 redef meth <(t)
387 do
388 return t isa MMNullableType and _base_type < t.as_notnull
389 end
390
391 redef meth to_s
392 do
393 return "nullable {_base_type}"
394 end
395
396 redef meth is_supertype(t)
397 do
398 return _base_type.is_supertype(t)
399 end
400
401 redef meth for_module(mod)
402 do
403 return _base_type.for_module(mod).as_nullable
404 end
405
406 redef meth adapt_to(recv)
407 do
408 return _base_type.adapt_to(recv).as_nullable
409 end
410
411 redef meth upcast_for(c)
412 do
413 return _base_type.upcast_for(c)
414 end
415
416 redef meth not_for_self
417 do
418 return _base_type.not_for_self.as_nullable
419 end
420 end
421
422 class MMTypeClass
423 special MMType
424 redef readable attr _local_class: MMLocalClass
425 redef meth module do return _local_class.module end
426 redef meth <(t) do return t != null and t.is_supertype(self)
427
428 redef meth to_s
429 do
430 return _local_class.to_s
431 end
432
433 redef meth upcast_for(c)
434 do
435 assert _local_class != null
436 assert c != null
437
438 var t: MMType = self
439 if _local_class != c then
440 t = _local_class.ancestor(c)
441 end
442 assert t != null
443 return t
444 end
445
446 init(c : MMLocalClass)
447 do
448 _local_class = c
449 end
450 end
451
452 class MMTypeSimpleClass
453 special MMTypeClass
454 redef meth is_supertype(t)
455 do
456 return t.local_class.cshe <= _local_class
457 end
458
459 redef meth for_module(mod)
460 do
461 var t: MMType = self
462 if module != mod then
463 t = _local_class.for_module(mod).get_type
464 end
465 assert t != null
466 return t
467 end
468
469 redef meth adapt_to(recv) do return self
470
471 init(c: MMLocalClass)
472 do
473 super(c)
474 end
475 end
476
477 # The type of null
478 class MMTypeNone
479 special MMType
480 redef readable attr _module: MMModule
481 redef meth is_nullable: Bool do return true
482 redef meth <(t) do return t isa MMTypeNone or t isa MMNullableType
483 redef meth to_s do return "null"
484 redef meth is_supertype(t) do return false
485 redef meth local_class do abort
486 redef meth upcast_for(c) do abort
487 redef meth as_nullable do return self
488 redef meth as_notnull do abort
489
490 private init(m: MMModule) do _module = m
491 end
492
493 redef class MMModule
494 # The type of null
495 readable attr _type_none: MMTypeNone = new MMTypeNone(self)
496 end