Move property selectors from types to local classes
[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
112 redef meth is_generic do return true
113
114 redef meth is_supertype(t)
115 do
116 if t.local_class.cshe <= _local_class then
117 var u = t.upcast_for(_local_class)
118 if u isa MMTypeGeneric then
119 return is_subtype(u) # and u.is_subtype(self) # Strong typing is too strong
120 end
121 end
122 return false
123 end
124
125 redef meth upcast_for(c)
126 do
127 var t = super
128 if t != self then
129 t = t.adapt_to(self)
130 end
131 return t
132 end
133
134 redef meth for_module(mod)
135 do
136 var t: MMType = self
137 if module != mod then
138 var parms = new Array[MMType]
139 for p in _params do
140 parms.add(p.for_module(mod))
141 end
142 var b = _local_class.for_module(mod)
143 t = b.get_instantiate_type(parms)
144 end
145 assert t != null
146 return t
147 end
148
149 redef meth adapt_to(r)
150 do
151 var rv = new Array[MMType]
152 for i in _params do
153 rv.add(i.adapt_to(r))
154 end
155 var l = _local_class.get_instantiate_type(rv)
156 return l
157 end
158
159 private meth params_equals(t: Array[MMType]): Bool
160 do
161 if t.length != _params.length then
162 return false
163 end
164 for i in [0..t.length[ do
165 assert _params[i] != null
166 assert t[i] != null
167 if _params[i] != t[i] then
168 return false
169 end
170 end
171 return true
172 end
173
174 redef meth to_s
175 do
176 return "{super}[{_params.join(", ")}]"
177 end
178
179 # Is self a subtype of t?
180 # Require that t.local_class = self.local_class
181 private meth is_subtype(t: MMTypeGeneric) : Bool
182 do
183 for i in [0.._params.length[
184 do
185 if not t.params[i] < _params[i] then
186 return false
187 end
188 end
189 return true
190 end
191
192 init(c: MMLocalClass, p: Array[MMType])
193 do
194 super(c)
195 _params = p
196 end
197 end
198
199 class MMTypeFormalParameter
200 special MMTypeFormal
201 # The class where self is defined
202 readable attr _def_class: MMLocalClass
203
204 # The position is self in def_class
205 readable attr _position: Int
206
207 redef meth module do return _def_class.module
208
209 redef meth for_module(mod)
210 do
211 var t: MMType = self
212 if module != mod then
213 t = mod[_def_class.global].get_formal(position)
214 end
215 assert t != null
216 return t
217 end
218
219 redef meth upcast_for(c) do return self
220
221 meth bound=(t: MMType)
222 do
223 assert _bound == null
224 _bound = t
225 end
226
227 redef meth adapt_to(r)
228 do
229 r = r.direct_type
230 var old_r = r.upcast_for(def_class)
231 #if not old_r isa MMTypeGeneric then
232 # print "adapt {self}'{def_class}'{self.module} to {r}'{r.module}"
233 # print " old_r = {old_r}'{old_r.module}"
234 #end
235 assert old_r isa MMTypeGeneric
236 var reduct = old_r.params[position]
237 assert reduct != null
238 return reduct
239 end
240
241 init with_bound(n: Symbol, p: Int, intro: MMLocalClass, b: MMType)
242 do
243 init(n,p,intro)
244 _bound = b
245 end
246
247 init(n: Symbol, p: Int, intro: MMLocalClass)
248 do
249 assert n != null
250 _name = n
251 _position = p
252 _def_class = intro
253 end
254 end
255
256 redef class MMTypeNone
257 redef meth is_generic do return false
258 redef meth for_module(mod) do return self
259 redef meth adapt_to(r) do return self
260 end