start removing implicit properties
[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 MMType
95 # TODO: IS this useful?
96 meth is_generic: Bool is abstract
97 end
98
99 redef class MMTypeFormal
100 redef meth is_generic do return _bound.is_generic
101 end
102
103 redef class MMTypeSimpleClass
104 redef meth is_generic do return false
105 end
106
107 class MMTypeGeneric
108 special MMTypeClass
109 # Formal arguments
110 readable attr _params: Array[MMType]
111 attr _props: Map[MMGlobalProperty, MMLocalProperty] = new HashMap[MMGlobalProperty, MMLocalProperty]
112
113 redef meth is_generic do return true
114
115 redef meth is_supertype(t)
116 do
117 if t.local_class.cshe <= _local_class then
118 var u = t.upcast_for(_local_class)
119 if u isa MMTypeGeneric then
120 return is_subtype(u) # and u.is_subtype(self) # Strong typing is too strong
121 end
122 end
123 return false
124 end
125
126 redef meth upcast_for(c)
127 do
128 var t = super
129 if t != self then
130 t = t.adapt_to(self)
131 end
132 return t
133 end
134
135 redef meth for_module(mod)
136 do
137 var t: MMType = self
138 if module != mod then
139 var parms = new Array[MMType]
140 for p in _params do
141 parms.add(p.for_module(mod))
142 end
143 var b = _local_class.for_module(mod)
144 t = b.get_instantiate_type(parms)
145 end
146 assert t != null
147 return t
148 end
149
150 redef meth adapt_to(r)
151 do
152 var rv = new Array[MMType]
153 for i in _params do
154 rv.add(i.adapt_to(r))
155 end
156 var l = _local_class.get_instantiate_type(rv)
157 return l
158 end
159
160 private meth params_equals(t: Array[MMType]): Bool
161 do
162 if t.length != _params.length then
163 return false
164 end
165 for i in [0..t.length[ do
166 assert _params[i] != null
167 assert t[i] != null
168 if _params[i] != t[i] then
169 return false
170 end
171 end
172 return true
173 end
174
175 redef meth select_property(g)
176 do
177 if g == null then
178 return null
179 end
180 if not _props.has_key(g) then
181 assert _local_class != null
182 var p = _local_class[g]
183 if p != null then
184 #var p2 = p.adapt_property(self)
185 #_props[g] = p2
186 #return p2
187 return p
188 else
189 assert false
190 end
191 end
192 return _props[g]
193 end
194
195 redef meth to_s
196 do
197 return "{super}[{_params.join(", ")}]"
198 end
199
200 # Is self a subtype of t?
201 # Require that t.local_class = self.local_class
202 private meth is_subtype(t: MMTypeGeneric) : Bool
203 do
204 for i in [0.._params.length[
205 do
206 if not t.params[i] < _params[i] then
207 return false
208 end
209 end
210 return true
211 end
212
213 init(c: MMLocalClass, p: Array[MMType])
214 do
215 super(c)
216 _params = p
217 end
218 end
219
220 class MMTypeFormalParameter
221 special MMTypeFormal
222 # The class where self is defined
223 readable attr _def_class: MMLocalClass
224
225 # The position is self in def_class
226 readable attr _position: Int
227
228 redef meth module do return _def_class.module
229
230 redef meth for_module(mod)
231 do
232 var t: MMType = self
233 if module != mod then
234 t = mod[_def_class.global].get_formal(position)
235 end
236 assert t != null
237 return t
238 end
239
240 redef meth upcast_for(c) do return self
241
242 meth bound=(t: MMType)
243 do
244 assert _bound == null
245 _bound = t
246 end
247
248 redef meth adapt_to(r)
249 do
250 r = r.direct_type
251 var old_r = r.upcast_for(def_class)
252 #if not old_r isa MMTypeGeneric then
253 # print "adapt {self}'{def_class}'{self.module} to {r}'{r.module}"
254 # print " old_r = {old_r}'{old_r.module}"
255 #end
256 assert old_r isa MMTypeGeneric
257 var reduct = old_r.params[position]
258 assert reduct != null
259 return reduct
260 end
261
262 init with_bound(n: Symbol, p: Int, intro: MMLocalClass, b: MMType)
263 do
264 init(n,p,intro)
265 _bound = b
266 end
267
268 init(n: Symbol, p: Int, intro: MMLocalClass)
269 do
270 assert n != null
271 _name = n
272 _position = p
273 _def_class = intro
274 end
275 end
276
277 redef class MMTypeNone
278 redef meth is_generic do return false
279 redef meth for_module(mod) do return self
280 redef meth adapt_to(r) do return self
281 end