First NIT release and new clean mercurial repository
[nit.git] / src / metamodel / genericity.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 # Generic classes, generic types and generic formal parameters
19 package genericity
20
21 intrude import type_formal
22 intrude import inheritance
23
24 redef class MMLocalClass
25 # The pos-th formal type parameter
26 meth get_formal(pos: Int): MMTypeFormalParameter
27 do
28 return formals_types[pos]
29 end
30
31 # Register a new formal type
32 # Called in order during the building of the class
33 meth register_formal(f: MMTypeFormalParameter)
34 do
35 assert f.def_class == self
36 assert f.position == _formals_types.length
37 _formals_types.add(f)
38 end
39
40 # All the insanciated types of the class
41 attr _types: Array[MMTypeGeneric] = new Array[MMTypeGeneric]
42
43 # Instanciate a type from the generic class
44 meth get_instantiate_type(t: Array[MMType]): MMType
45 do
46 for g in _types do
47 if g.params_equals(t) then return g
48 end
49 var g = new MMTypeGeneric(self, t)
50 _types.add(g)
51 return g
52 end
53
54 # The formal types of the class
55 attr _formals_types: Array[MMTypeFormalParameter] = new Array[MMTypeFormalParameter]
56
57 # Return the definition formal types for the class
58 # Import them from the intro class if needed
59 private meth formals_types: Array[MMTypeFormalParameter]
60 do
61 if _formals_types.is_empty then
62 assert not self isa MMConcreteClass
63 # Because of F-genericity, the import is done in two pass
64 # First, get the formal types untyped so that one can recurcively call formals_types
65 for i in [0..arity[ do
66 var oft = global.intro.get_formal(i)
67 var ft = new MMTypeFormalParameter(oft.name, i, self)
68 register_formal(ft)
69 end
70 # Second, assign the bound to the formal type
71 for i in [0..arity[ do
72 var oft = global.intro.get_formal(i)
73 var ft = _formals_types[i]
74 ft.bound = oft.bound.for_module(module)
75 end
76 end
77 return _formals_types
78 end
79
80 redef meth get_type
81 do
82 if _base_type_cache == null and is_generic then
83 _base_type_cache = get_instantiate_type(formals_types)
84 return _base_type_cache
85 else
86 return super
87 end
88 end
89
90 # Is the class a generic one?
91 meth is_generic: Bool do return arity > 0
92 end
93
94 redef class MMSignature
95 # Adapt the signature to a different receiver
96 meth adaptation_to(r: MMType): MMSignature
97 do
98 if _recv == r then
99 return self
100 end
101 var mod = r.module
102 var p = _params
103 if p != null then
104 p = new Array[MMType]
105 for i in _params do
106 p.add(i.for_module(mod).adapt_to(r))
107 end
108 end
109 var rv = _return_type
110 if rv != null then
111 rv = rv.for_module(mod).adapt_to(r)
112 end
113 return new MMSignature(p,rv,r)
114 end
115 end
116
117 redef class MMLocalProperty
118 # The receiver type if the signature is unknown (aka lazily computed)
119 attr _recv_alone: MMType
120
121 meth recv: MMType
122 do
123 assert signature != null
124 return signature.recv
125 end
126
127 meth recv=(rec: MMType)
128 do
129 assert rec != null
130 # print("setting recv for {self} {rec} {_recv == null}")
131 assert _signature_cache == null
132 _recv_alone = rec
133 end
134
135 redef meth signature
136 do
137 var sig = _signature_cache
138 if sig != null then
139 return sig
140 end
141 if self isa MMConcreteProperty then
142 return null
143 end
144 var sp = _super_prop
145 #assert self != sp
146 var impl = _concrete_property
147 if sp == null then # superprop ?
148 # print("building signature for {self}:{self.object_id} and type {_recv}")
149 _signature_cache = impl.signature
150 assert _signature_cache != null
151 else
152 # print("adapting signature for {self}:{self.object_id} and type {_recv}")
153 assert sp.signature != null
154 assert _recv_alone != null
155 #_signature = sp.signature
156 _signature_cache = sp.signature.adaptation_to(_recv_alone)
157 end
158 assert _signature_cache != null
159 # print("finally recv is {_recv} for {self}:{self.object_id} and sig is {_signature.recv}")
160 return _signature_cache
161 end
162
163 # Adapt the property to a different receiver
164 # TODO: Merge with inheritance stuff
165 meth adapt_property(t: MMType): MMLocalProperty
166 do
167 assert t != null
168 var recv = local_class.get_type
169 if t == recv then
170 return self
171 else
172 return inherit_to(t)
173 end
174 end
175
176 redef meth inherit_from(s, t) # for the super bugs
177 do
178 super
179 _recv_alone = t
180 end
181 end
182
183 redef class MMType
184 # TODO: IS this useful?
185 meth is_generic: Bool is abstract
186 end
187
188 redef class MMTypeFormal
189 redef meth is_generic do return _bound.is_generic
190 end
191
192 redef class MMTypeSimpleClass
193 redef meth is_generic do return false
194 end
195
196 class MMTypeGeneric
197 special MMTypeClass
198 # Formal arguments
199 readable attr _params: Array[MMType]
200 attr _props: Map[MMGlobalProperty, MMLocalProperty] = new HashMap[MMGlobalProperty, MMLocalProperty]
201
202 redef meth is_generic do return true
203
204 redef meth is_supertype(t)
205 do
206 if t.local_class.cshe <= _local_class then
207 var u = t.upcast_for(_local_class)
208 if u isa MMTypeGeneric then
209 return is_subtype(u) # and u.is_subtype(self) # Strong typing is too strong
210 end
211 end
212 return false
213 end
214
215 redef meth upcast_for(c)
216 do
217 var t = super
218 if t != self then
219 t = t.adapt_to(self)
220 end
221 return t
222 end
223
224 redef meth for_module(mod)
225 do
226 var t: MMType = self
227 if module != mod then
228 var parms = new Array[MMType]
229 for p in _params do
230 parms.add(p.for_module(mod))
231 end
232 var b = _local_class.for_module(mod)
233 t = b.get_instantiate_type(parms)
234 end
235 assert t != null
236 return t
237 end
238
239 redef meth adapt_to(r)
240 do
241 var rv = new Array[MMType]
242 for i in _params do
243 rv.add(i.adapt_to(r))
244 end
245 var l = _local_class.get_instantiate_type(rv)
246 return l
247 end
248
249 private meth params_equals(t: Array[MMType]): Bool
250 do
251 if t.length != _params.length then
252 return false
253 end
254 for i in [0..t.length[ do
255 assert _params[i] != null
256 assert t[i] != null
257 if _params[i] != t[i] then
258 return false
259 end
260 end
261 return true
262 end
263
264 redef meth select_property(g)
265 do
266 if g == null then
267 return null
268 end
269 if not _props.has_key(g) then
270 assert _local_class != null
271 var p = _local_class[g]
272 if p != null then
273 var p2 = p.adapt_property(self)
274 _props[g] = p2
275 return p2
276 else
277 assert false
278 end
279 end
280 return _props[g]
281 end
282
283 redef meth to_s
284 do
285 return "{super}[{_params.join(", ")}]"
286 end
287
288 # Is self a subtype of t?
289 # Require that t.local_class = self.local_class
290 private meth is_subtype(t: MMTypeGeneric) : Bool
291 do
292 for i in [0.._params.length[
293 do
294 if not t.params[i] < _params[i] then
295 return false
296 end
297 end
298 return true
299 end
300
301 init(c: MMLocalClass, p: Array[MMType])
302 do
303 super(c)
304 _params = p
305 end
306 end
307
308 class MMTypeFormalParameter
309 special MMTypeFormal
310 # The class where self is defined
311 readable attr _def_class: MMLocalClass
312
313 # The position is self in def_class
314 readable attr _position: Int
315
316 redef meth module do return _def_class.module
317
318 redef meth for_module(mod)
319 do
320 var t: MMType = self
321 if module != mod then
322 t = mod[_def_class.global].get_formal(position)
323 end
324 assert t != null
325 return t
326 end
327
328 redef meth upcast_for(c) do return self
329
330 meth bound=(t: MMType)
331 do
332 assert _bound == null
333 _bound = t
334 end
335
336 redef meth adapt_to(r)
337 do
338 var old_r = r.upcast_for(def_class)
339 #print "adapt {self} for ({old_r} -> {r})"
340 assert old_r isa MMTypeGeneric
341 var reduct = old_r.params[position]
342 assert reduct != null
343 return reduct
344 end
345
346 init with_bound(n: Symbol, p: Int, intro: MMLocalClass, b: MMType)
347 do
348 init(n,p,intro)
349 _bound = b
350 end
351
352 init(n: Symbol, p: Int, intro: MMLocalClass)
353 do
354 assert n != null
355 _name = n
356 _position = p
357 _def_class = intro
358 end
359 end
360
361 redef class MMTypeNone
362 redef meth is_generic do return false
363 redef meth for_module(mod) do return self
364 redef meth adapt_to(r) do return self
365 end