1 |
indexing |
2 |
description: "Descripion of a formal generic type" |
3 |
legal: "See notice at end of class." |
4 |
status: "See notice at end of class." |
5 |
date: "$Date$" |
6 |
revision: "$Revision$" |
7 |
|
8 |
class FORMAL_A |
9 |
|
10 |
inherit |
11 |
NAMED_TYPE_A |
12 |
redefine |
13 |
is_formal, |
14 |
instantiation_in, |
15 |
has_formal_generic, |
16 |
is_loose, |
17 |
instantiated_in, |
18 |
evaluated_type_in_descendant, |
19 |
same_as, |
20 |
format, |
21 |
is_full_named_type, |
22 |
convert_to, |
23 |
check_const_gen_conformance, |
24 |
is_reference, |
25 |
is_expanded, |
26 |
is_monomorph |
27 |
end |
28 |
|
29 |
REFACTORING_HELPER |
30 |
create |
31 |
make |
32 |
|
33 |
feature {NONE} -- Initialization |
34 |
|
35 |
make (is_ref: like is_reference; is_exp: like is_expanded; i: like position) is |
36 |
-- Initialize new instance of FORMAL_A which is garanteed to |
37 |
-- be instantiated as a reference type if `is_ref'. |
38 |
do |
39 |
is_reference := is_ref |
40 |
is_expanded := is_exp |
41 |
position := i |
42 |
ensure |
43 |
is_reference_set: is_reference = is_ref |
44 |
is_expanded_set: is_expanded = is_exp |
45 |
position_set: position = i |
46 |
end |
47 |
|
48 |
feature -- Visitor |
49 |
|
50 |
process (v: TYPE_A_VISITOR) is |
51 |
-- Process current element. |
52 |
do |
53 |
v.process_formal_a (Current) |
54 |
end |
55 |
|
56 |
feature -- Property |
57 |
|
58 |
is_formal: BOOLEAN is True |
59 |
-- Is the current actual type a formal generic type ? |
60 |
|
61 |
is_multi_constrained (a_context_class: CLASS_C): BOOLEAN is |
62 |
-- Is Current a multi constraint formal relative to current context class? |
63 |
-- |
64 |
-- `a_context_class': Used to resolve formals to their constraints. |
65 |
require |
66 |
a_context_class_not_void: a_context_class /= Void |
67 |
a_context_class_valid: a_context_class.is_generic and then a_context_class.is_valid_formal_position (position) |
68 |
local |
69 |
l_generics: EIFFEL_LIST[FORMAL_DEC_AS] |
70 |
do |
71 |
l_generics := a_context_class.generics |
72 |
Result := l_generics.i_th (position).is_multi_constrained (l_generics) |
73 |
end |
74 |
|
75 |
is_full_named_type: BOOLEAN is True |
76 |
-- Current is a named type. |
77 |
|
78 |
is_reference: BOOLEAN |
79 |
-- Is current constrained to be always a reference? |
80 |
|
81 |
is_expanded: BOOLEAN |
82 |
-- Is current constrained to be always an expanded? |
83 |
|
84 |
is_monomorph: BOOLEAN |
85 |
-- Is curren type a monomorph? |
86 |
|
87 |
hash_code: INTEGER is |
88 |
-- |
89 |
do |
90 |
Result := position |
91 |
end |
92 |
|
93 |
is_single_constraint_without_renaming (a_context_class: CLASS_C): BOOLEAN |
94 |
-- Is current type a formal type which is single constrained and the constraint has not a feature renaming? |
95 |
-- |
96 |
-- `a_context_class' is the context class where the type occurs in. |
97 |
--| G -> A -> True |
98 |
--| G -> A rename a as b end -> False |
99 |
--| G -> {A, B} -> False |
100 |
--| This means there is exactly one constraint class which can be directly used without applying a feature renaming. |
101 |
local |
102 |
l_generics: EIFFEL_LIST[FORMAL_DEC_AS] |
103 |
do |
104 |
l_generics := a_context_class.generics |
105 |
check l_generics_not_void: l_generics /= Void end |
106 |
Result := l_generics.i_th (position).is_single_constraint_without_renaming (l_generics) |
107 |
end |
108 |
|
109 |
feature -- Comparison |
110 |
|
111 |
is_equivalent (other: like Current): BOOLEAN is |
112 |
-- Is `other' equivalent to the current object ? |
113 |
do |
114 |
Result := position = other.position and then |
115 |
is_reference = other.is_reference and then |
116 |
is_expanded = other.is_expanded |
117 |
end |
118 |
|
119 |
feature -- Access |
120 |
|
121 |
constrained_type (a_context_class: CLASS_C): TYPE_A |
122 |
-- Constraint of Current. |
123 |
require |
124 |
a_context_class_attached: a_context_class /= Void |
125 |
not_multi_constraint: not is_multi_constrained (a_context_class) |
126 |
do |
127 |
Result := a_context_class.constrained_type (position) |
128 |
ensure |
129 |
Result_not_void: Result /= Void |
130 |
Result_is_named_but_not_formal: (Result.is_none or Result.is_named_type) and not Result.is_formal |
131 |
end |
132 |
|
133 |
constrained_types (a_context_class: CLASS_C): TYPE_SET_A |
134 |
-- Constrained types of Current. |
135 |
-- |
136 |
-- `a_context_class' is the context class where the formal occurs in. |
137 |
--| It is a list of class types which constraint the current Formal. |
138 |
require |
139 |
a_context_class_attached: a_context_class /= Void |
140 |
do |
141 |
Result := a_context_class.constrained_types (position) |
142 |
ensure |
143 |
Result_not_void_and_not_empty: Result /= Void and not Result.is_empty |
144 |
end |
145 |
|
146 |
constrained_type_if_possible (a_context_class: CLASS_C): TYPE_A |
147 |
-- Constraint of Current. |
148 |
require |
149 |
a_context_class_attached: a_context_class /= Void |
150 |
not_multi_constraint: not is_multi_constrained (a_context_class) |
151 |
local |
152 |
l_formal_type: FORMAL_A |
153 |
do |
154 |
from |
155 |
-- Unfold the chain of formal generics |
156 |
Result := Current |
157 |
until |
158 |
Result = Void or else not Result.is_formal |
159 |
loop |
160 |
l_formal_type ?= Result |
161 |
Result := a_context_class.constraint_if_possible (l_formal_type.position) |
162 |
end |
163 |
end |
164 |
|
165 |
constrained_types_if_possible (a_context_class: CLASS_C): TYPE_SET_A |
166 |
-- Constraint of Current. |
167 |
require |
168 |
a_context_class_attached: a_context_class /= Void |
169 |
do |
170 |
Result := constraints (a_context_class).constraining_types (a_context_class) |
171 |
end |
172 |
|
173 |
constraint (a_context_class: CLASS_C): TYPE_A is |
174 |
-- Constraint type of `Current'. |
175 |
--| Return excatly what is written. For a formal like G -> H we return H. |
176 |
--| If you want to resolve formal chains use `constrained_type'. |
177 |
--| If there are several formals in the type set we merge the results. |
178 |
require |
179 |
a_a_context_classt_not_void: a_context_class /= Void |
180 |
do |
181 |
Result := a_context_class.constraint (position) |
182 |
ensure |
183 |
Result_sane: Result /= Void |
184 |
end |
185 |
|
186 |
|
187 |
constraints (a_context_class: CLASS_C): TYPE_SET_A is |
188 |
-- Constraint types of `Current'. |
189 |
--| Return excatly what is written. For a formal like G -> {H,STRING} we return {H, STRING}. |
190 |
--| If there are several formals in the type set we merge the results. |
191 |
--| If you want to get rid of recursive formals call `constraining_types' on the resulting TYPE_SET_A. |
192 |
require |
193 |
a_a_context_classt_not_void: a_context_class /= Void |
194 |
do |
195 |
Result := a_context_class.constraints (position) |
196 |
ensure |
197 |
Result_sane: Result /= Void and then not Result.is_empty |
198 |
end |
199 |
|
200 |
constraints_if_possible (a_context_class: CLASS_C): TYPE_SET_A is |
201 |
-- Constraint types of `Current'. |
202 |
--| Return excatly what is written. For a formal like G -> {H,STRING} we return {H, STRING}. |
203 |
--| If there are several formals in the type set we merge the results. |
204 |
require |
205 |
a_a_context_classt_not_void: a_context_class /= Void |
206 |
do |
207 |
Result := a_context_class.constraints_if_possible (position) |
208 |
ensure |
209 |
Result_sane: Result /= Void |
210 |
end |
211 |
|
212 |
same_as (other: TYPE_A): BOOLEAN is |
213 |
-- Is `other' the same as Current ? |
214 |
local |
215 |
other_formal: FORMAL_A |
216 |
do |
217 |
other_formal ?= other |
218 |
if other_formal /= Void then |
219 |
Result := is_equivalent (other_formal) |
220 |
end |
221 |
end |
222 |
|
223 |
associated_class: CLASS_C is |
224 |
do |
225 |
-- No associated class |
226 |
end |
227 |
|
228 |
position: INTEGER |
229 |
-- Position of the formal parameter in the |
230 |
-- generic class declaration |
231 |
|
232 |
feature -- Output |
233 |
|
234 |
dump: STRING is |
235 |
-- Dumped trace |
236 |
do |
237 |
create Result.make (3) |
238 |
Result.append ("G#") |
239 |
Result.append_integer (position) |
240 |
end |
241 |
|
242 |
ext_append_to (st: TEXT_FORMATTER; c: CLASS_C) is |
243 |
local |
244 |
s: STRING |
245 |
l_class: CLASS_AS |
246 |
do |
247 |
if c /= Void then |
248 |
l_class := c.ast |
249 |
if l_class.generics /= Void and then l_class.generics.valid_index (position) then |
250 |
s := l_class.generics.i_th (position).name.name.as_upper |
251 |
st.process_generic_text (s) |
252 |
else |
253 |
-- We are in case where actual generic position does not match |
254 |
-- any generics in written class of `f'. E.g: A [H, G] inherits |
255 |
-- from B [G], therefore in B, `G' at position 2 does not make sense. |
256 |
--| FIXME: Manu 05/29/2002: we cannot let this happen, the reason is |
257 |
-- due to bad initialization of `f' in wrong class. |
258 |
st.add (Ti_generic_index) |
259 |
st.add_int (position) |
260 |
end |
261 |
else |
262 |
st.add (Ti_generic_index) |
263 |
st.add_int (position) |
264 |
end |
265 |
end |
266 |
|
267 |
feature {COMPILER_EXPORTER} -- Type checking |
268 |
|
269 |
check_const_gen_conformance (a_gen_type: GEN_TYPE_A; a_target_type: TYPE_A; a_class: CLASS_C; i: INTEGER) is |
270 |
-- Is `Current' a valid generic parameter at position `i' of `gen_type'? |
271 |
-- For formal generic parameter, we do check that their constraint |
272 |
-- conforms to `a_target_type'. |
273 |
local |
274 |
l_is_ref, l_is_exp: BOOLEAN |
275 |
do |
276 |
-- We simply consider conformance as if current formal |
277 |
-- was constrained to be a reference type, it enables us |
278 |
-- to accept the following code: |
279 |
-- class B [G -> STRING] |
280 |
-- class A [G -> STRING, H -> B [G]] |
281 |
l_is_ref := is_reference |
282 |
l_is_exp := is_expanded |
283 |
is_reference := True |
284 |
is_expanded := False |
285 |
Precursor {NAMED_TYPE_A} (a_gen_type, a_target_type, a_class, i) |
286 |
is_reference := l_is_ref |
287 |
is_expanded := l_is_exp |
288 |
|
289 |
-- Note that even if the constraint is not valid, e.g. |
290 |
-- class B [reference G -> STRING] |
291 |
-- class A [expanded G -> STRING, H -> B [G]] |
292 |
-- we do not trigger an error. This is ok, because an |
293 |
-- error will be triggered when trying to write a generic |
294 |
-- derivation of A as none is possible. |
295 |
end |
296 |
|
297 |
feature {COMPILER_EXPORTER} |
298 |
|
299 |
has_formal_generic: BOOLEAN is |
300 |
-- Does the current actual type have formal generic type ? |
301 |
do |
302 |
Result := True |
303 |
end |
304 |
|
305 |
is_loose: BOOLEAN is True |
306 |
-- Does type depend on formal generic parameters and/or anchors? |
307 |
|
308 |
conform_to (other: TYPE_A): BOOLEAN is |
309 |
-- Does Current conform to `other'? |
310 |
local |
311 |
l_constraints: TYPE_SET_A |
312 |
do |
313 |
Result := same_as (other.conformance_type) |
314 |
if not Result then |
315 |
-- We do not treat the case `is_expanded' as if it is an |
316 |
-- expanded then it does not conform to anything but itself |
317 |
-- so this is automatically taken care by `same_as' above. |
318 |
if not is_expanded then |
319 |
-- Check conformance of constrained generic type to `other'. |
320 |
fixme ("As soon as conform_to takes a context class as an argument, do no longer use System.current_class but the argument.") |
321 |
check |
322 |
has_generics: System.current_class.generics /= Void |
323 |
count_ok: System.current_class.generics.count >= position |
324 |
end |
325 |
-- Get the actual type for the formal generic parameter |
326 |
l_constraints := System.current_class.constraints_if_possible (position) |
327 |
Result := l_constraints.constraining_types (system.current_class).conform_to_type (other) |
328 |
end |
329 |
end |
330 |
end |
331 |
|
332 |
convert_to (a_context_class: CLASS_C; a_target_type: TYPE_A): BOOLEAN is |
333 |
-- Does current convert to `a_target_type' in `a_context_class'? |
334 |
-- Update `last_conversion_info' of AST_CONTEXT. |
335 |
local |
336 |
l_checker: CONVERTIBILITY_CHECKER |
337 |
do |
338 |
-- Check conformance of constained generic type |
339 |
-- to `other' |
340 |
check |
341 |
has_generics: System.current_class.generics /= Void |
342 |
count_ok: System.current_class.generics.count >= position |
343 |
end |
344 |
|
345 |
create l_checker |
346 |
l_checker.check_formal_conversion (System.current_class, Current, a_target_type) |
347 |
Result := l_checker.last_conversion_check_successful |
348 |
if Result then |
349 |
context.set_last_conversion_info (l_checker.last_conversion_info) |
350 |
else |
351 |
context.set_last_conversion_info (Void) |
352 |
end |
353 |
end |
354 |
|
355 |
instantiation_in (type: TYPE_A; written_id: INTEGER): TYPE_A is |
356 |
-- Instantiation of Current in the context of `class_type', |
357 |
-- assuming that Current is written in class of id `written_id'. |
358 |
local |
359 |
class_type: CL_TYPE_A |
360 |
do |
361 |
class_type ?= type |
362 |
if class_type /= Void then |
363 |
Result := class_type.instantiation_of (Current, written_id) |
364 |
else |
365 |
Result := Current |
366 |
end |
367 |
end |
368 |
|
369 |
instantiated_in (class_type: TYPE_A): TYPE_A is |
370 |
-- Instantiation of Current in the context of `class_type' |
371 |
-- assuming that Current is written in the associated class |
372 |
-- of `class_type'. |
373 |
do |
374 |
Result := class_type.generics.item (position) |
375 |
end |
376 |
|
377 |
evaluated_type_in_descendant (a_ancestor, a_descendant: CLASS_C; a_feature: FEATURE_I): TYPE_A is |
378 |
local |
379 |
l_feat: TYPE_FEATURE_I |
380 |
do |
381 |
-- Get associated feature in parent. |
382 |
l_feat := a_ancestor.formal_at_position (position) |
383 |
-- Get associated feature in descendant. |
384 |
l_feat := a_descendant.generic_features.item (l_feat.rout_id_set.first) |
385 |
check l_feat_not_void: l_feat /= Void end |
386 |
Result := l_feat.type.actual_type |
387 |
end |
388 |
|
389 |
type_i: FORMAL_I is |
390 |
-- C type |
391 |
do |
392 |
create Result.make (is_reference, is_expanded, position) |
393 |
end |
394 |
|
395 |
create_info: CREATE_FORMAL_TYPE is |
396 |
-- Create formal type info. |
397 |
do |
398 |
create Result.make (type_i) |
399 |
end |
400 |
|
401 |
format (ctxt: TEXT_FORMATTER_DECORATOR) is |
402 |
-- reconstitute text |
403 |
do |
404 |
ctxt.process_generic_text (ctxt.formal_name (position)) |
405 |
end |
406 |
|
407 |
indexing |
408 |
copyright: "Copyright (c) 1984-2006, Eiffel Software" |
409 |
license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)" |
410 |
licensing_options: "http://www.eiffel.com/licensing" |
411 |
copying: "[ |
412 |
This file is part of Eiffel Software's Eiffel Development Environment. |
413 |
|
414 |
Eiffel Software's Eiffel Development Environment is free |
415 |
software; you can redistribute it and/or modify it under |
416 |
the terms of the GNU General Public License as published |
417 |
by the Free Software Foundation, version 2 of the License |
418 |
(available at the URL listed under "license" above). |
419 |
|
420 |
Eiffel Software's Eiffel Development Environment is |
421 |
distributed in the hope that it will be useful, but |
422 |
WITHOUT ANY WARRANTY; without even the implied warranty |
423 |
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
424 |
See the GNU General Public License for more details. |
425 |
|
426 |
You should have received a copy of the GNU General Public |
427 |
License along with Eiffel Software's Eiffel Development |
428 |
Environment; if not, write to the Free Software Foundation, |
429 |
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
430 |
]" |
431 |
source: "[ |
432 |
Eiffel Software |
433 |
356 Storke Road, Goleta, CA 93117 USA |
434 |
Telephone 805-685-1006, Fax 805-685-6869 |
435 |
Website http://www.eiffel.com |
436 |
Customer support http://support.eiffel.com |
437 |
]" |
438 |
|
439 |
end -- class FORMAL_A |