1 |
indexing |
2 |
description: "Descritpion of an actual generical 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 GEN_TYPE_A |
9 |
|
10 |
inherit |
11 |
CL_TYPE_A |
12 |
rename |
13 |
make as cl_make |
14 |
redefine |
15 |
generics, valid_generic, parent_type, dump, ext_append_to, |
16 |
has_like, has_like_argument, is_loose, duplicate, type_i, good_generics, |
17 |
error_generics, check_constraints, has_formal_generic, instantiated_in, |
18 |
has_expanded, is_valid, expanded_deferred, valid_expanded_creation, |
19 |
same_as, format, is_equivalent, |
20 |
deep_actual_type, instantiation_in, |
21 |
actual_argument_type, update_dependance, hash_code, |
22 |
is_full_named_type, process, evaluated_type_in_descendant |
23 |
end |
24 |
|
25 |
create |
26 |
make |
27 |
|
28 |
feature {NONE} -- Initialization |
29 |
|
30 |
make (a_class_id: INTEGER; g: like generics) is |
31 |
-- Create Current with `g' types as generic parameter. |
32 |
require |
33 |
valid_class_id: a_class_id > 0 |
34 |
has_generics: g /= Void |
35 |
do |
36 |
generics := g |
37 |
class_id := a_class_id |
38 |
ensure |
39 |
generics_set: generics = g |
40 |
class_id_set: class_id = a_class_id |
41 |
end |
42 |
|
43 |
feature -- Visitor |
44 |
|
45 |
process (v: TYPE_A_VISITOR) is |
46 |
-- Process current element. |
47 |
do |
48 |
v.process_gen_type_a (Current) |
49 |
end |
50 |
|
51 |
feature -- Property |
52 |
|
53 |
generics: ARRAY [TYPE_A] |
54 |
-- Actual generical parameter |
55 |
|
56 |
is_covariant (a_generic_position: INTEGER): BOOLEAN |
57 |
-- Is generic at `a_generic_position' marked as covariant? |
58 |
do |
59 |
if covariance_flags /= Void then |
60 |
Result := covariance_flags [a_generic_position] |
61 |
end |
62 |
|
63 |
end |
64 |
|
65 |
feature -- Comparison |
66 |
|
67 |
is_equivalent (other: like Current): BOOLEAN is |
68 |
-- Is `other' equivalent to the current object ? |
69 |
local |
70 |
i, nb: INTEGER |
71 |
other_generics: like generics |
72 |
do |
73 |
Result := Precursor {CL_TYPE_A} (other) |
74 |
if Result then |
75 |
from |
76 |
i := 1 |
77 |
nb := generics.count |
78 |
other_generics := other.generics |
79 |
Result := nb = other_generics.count |
80 |
until |
81 |
i > nb or else not Result |
82 |
loop |
83 |
Result := equivalent (generics.item (i), |
84 |
other_generics.item (i)) |
85 |
i := i + 1 |
86 |
end |
87 |
end |
88 |
end |
89 |
|
90 |
feature -- Access |
91 |
|
92 |
same_as (other: TYPE_A): BOOLEAN is |
93 |
-- Is the current type the same as `other' ? |
94 |
local |
95 |
other_gen_type: like Current |
96 |
i, nb: INTEGER |
97 |
other_generics: like generics |
98 |
do |
99 |
other_gen_type ?= other |
100 |
if |
101 |
other_gen_type /= Void |
102 |
and then other_gen_type.class_id = class_id |
103 |
and then is_expanded = other_gen_type.is_expanded |
104 |
and then is_separate = other_gen_type.is_separate |
105 |
then |
106 |
from |
107 |
i := 1 |
108 |
nb := generics.count |
109 |
other_generics := other_gen_type.generics |
110 |
Result := nb = other_generics.count |
111 |
until |
112 |
i > nb or else not Result |
113 |
loop |
114 |
Result := generics.item (i).same_as (other_generics.item (i)) |
115 |
i := i + 1 |
116 |
end |
117 |
end |
118 |
end |
119 |
|
120 |
hash_code: INTEGER is |
121 |
-- Hash code value |
122 |
local |
123 |
i, nb: INTEGER |
124 |
l_cl_type_a: CL_TYPE_A |
125 |
do |
126 |
Result := class_id |
127 |
from |
128 |
i := 1 |
129 |
nb := generics.count |
130 |
until |
131 |
i > nb |
132 |
loop |
133 |
l_cl_type_a ?= generics.item (i) |
134 |
if l_cl_type_a /= Void then |
135 |
Result := Result + l_cl_type_a.hash_code |
136 |
end |
137 |
i := i + 1 |
138 |
end |
139 |
-- Clear sign if it becomes negative |
140 |
Result := 0x7FFFFFFF & Result |
141 |
end |
142 |
|
143 |
feature -- Output |
144 |
|
145 |
dump: STRING is |
146 |
-- Dumped trace |
147 |
local |
148 |
i, count: INTEGER |
149 |
do |
150 |
Result := Precursor {CL_TYPE_A} |
151 |
|
152 |
count := generics.count |
153 |
|
154 |
-- TUPLE may have zero generic parameters |
155 |
|
156 |
if count > 0 then |
157 |
Result.append (" [") |
158 |
from |
159 |
i := 1 |
160 |
until |
161 |
i > count |
162 |
loop |
163 |
Result.append (generics.item (i).dump) |
164 |
if i /= count then |
165 |
Result.append (", ") |
166 |
end |
167 |
i := i + 1 |
168 |
end |
169 |
Result.append ("]") |
170 |
end |
171 |
end |
172 |
|
173 |
ext_append_to (st: TEXT_FORMATTER; c: CLASS_C) is |
174 |
local |
175 |
i, count: INTEGER |
176 |
do |
177 |
-- Append classname "TUPLE" |
178 |
Precursor {CL_TYPE_A} (st, c) |
179 |
|
180 |
count := generics.count |
181 |
-- TUPLE may have zero generic parameters |
182 |
if count > 0 then |
183 |
st.add_space |
184 |
st.process_symbol_text (ti_L_bracket) |
185 |
from |
186 |
i := 1 |
187 |
until |
188 |
i > count |
189 |
loop |
190 |
generics.item (i).ext_append_to (st, c) |
191 |
if i /= count then |
192 |
st.process_symbol_text (ti_Comma) |
193 |
st.add_space |
194 |
end |
195 |
i := i + 1 |
196 |
end |
197 |
st.process_symbol_text (ti_R_bracket) |
198 |
end |
199 |
end |
200 |
|
201 |
feature {COMPILER_EXPORTER} -- Primitives |
202 |
|
203 |
generate_error_from_creation_constraint_list (a_context_class: CLASS_C; a_context_feature: FEATURE_I; a_location_as: LOCATION_AS) |
204 |
-- Generated a VTCG7 error if there are any constraint errors. |
205 |
-- Otherwise it does nothing. |
206 |
require |
207 |
not_constraint_error_list_is_void: constraint_error_list /= Void |
208 |
local |
209 |
l_vtcg7: VTCG7 |
210 |
do |
211 |
if not constraint_error_list.is_empty then |
212 |
-- The feature listed in the creation constraint have |
213 |
-- not been declared in the constraint class. |
214 |
create l_vtcg7 |
215 |
l_vtcg7.set_location (a_location_as) |
216 |
l_vtcg7.set_class (a_context_class) |
217 |
l_vtcg7.set_error_list (constraint_error_list) |
218 |
l_vtcg7.set_parent_type (Current) |
219 |
if a_context_feature /= Void then |
220 |
l_vtcg7.set_feature (a_context_feature) |
221 |
end |
222 |
Error_handler.insert_error (l_vtcg7) |
223 |
end |
224 |
end |
225 |
|
226 |
update_dependance (feat_depend: FEATURE_DEPENDANCE) is |
227 |
-- Update dependency for Dead Code Removal |
228 |
local |
229 |
i, count: INTEGER |
230 |
do |
231 |
from |
232 |
i := 1 |
233 |
count := generics.count |
234 |
until |
235 |
i > count |
236 |
loop |
237 |
generics.item (i).update_dependance (feat_depend) |
238 |
i := i + 1 |
239 |
end |
240 |
end |
241 |
|
242 |
set_generics (g: like generics) is |
243 |
-- Assign `g' to `generics'. |
244 |
require |
245 |
g_not_void: g /= Void |
246 |
do |
247 |
generics := g |
248 |
ensure |
249 |
generics_set: generics = g |
250 |
end |
251 |
|
252 |
set_covariance_flags (a_flags: like covariance_flags) is |
253 |
-- Assign `a_flags' to `covariance_flags'. |
254 |
require |
255 |
a_flags_not_void: a_flags /= Void |
256 |
do |
257 |
covariance_flags := a_flags |
258 |
ensure |
259 |
covariance_flags_set: covariance_flags = a_flags |
260 |
end |
261 |
|
262 |
has_expanded: BOOLEAN is |
263 |
-- Are some expanded type in the current generic declaration ? |
264 |
local |
265 |
i, count: INTEGER |
266 |
do |
267 |
from |
268 |
Result := is_expanded |
269 |
i := 1 |
270 |
count := generics.count |
271 |
until |
272 |
i > count or else Result |
273 |
loop |
274 |
Result := generics.item (i).has_expanded |
275 |
i := i + 1 |
276 |
end |
277 |
end |
278 |
|
279 |
is_valid: BOOLEAN is |
280 |
local |
281 |
i, count: INTEGER |
282 |
do |
283 |
from |
284 |
Result := Precursor {CL_TYPE_A} |
285 |
i := 1 |
286 |
count := generics.count |
287 |
until |
288 |
i > count or else not Result |
289 |
loop |
290 |
Result := generics.item (i).is_valid |
291 |
i := i + 1 |
292 |
end |
293 |
end |
294 |
|
295 |
is_full_named_type: BOOLEAN is |
296 |
-- Is Current a fully named type? |
297 |
local |
298 |
i, count: INTEGER |
299 |
do |
300 |
from |
301 |
i := 1 |
302 |
count := generics.count |
303 |
until |
304 |
i > count or else Result |
305 |
loop |
306 |
Result := generics.item (i).is_full_named_type |
307 |
i := i + 1 |
308 |
end |
309 |
end |
310 |
|
311 |
has_formal_generic: BOOLEAN is |
312 |
-- Has type a formal generic parameter? |
313 |
local |
314 |
i, count: INTEGER |
315 |
do |
316 |
from |
317 |
i := 1 |
318 |
count := generics.count |
319 |
until |
320 |
i > count or else Result |
321 |
loop |
322 |
Result := generics.item (i).has_formal_generic |
323 |
i := i + 1 |
324 |
end |
325 |
end |
326 |
|
327 |
is_loose: BOOLEAN is |
328 |
-- Does type depend on formal generic parameters and/or anchors? |
329 |
local |
330 |
g: like generics |
331 |
i: INTEGER |
332 |
do |
333 |
from |
334 |
g := generics |
335 |
i := g.count |
336 |
until |
337 |
i <= 0 or else Result |
338 |
loop |
339 |
Result := g.item (i).is_loose |
340 |
i := i - 1 |
341 |
end |
342 |
end |
343 |
|
344 |
type_i: GEN_TYPE_I is |
345 |
-- Meta generic interpretation of the generic type |
346 |
local |
347 |
i, count: INTEGER |
348 |
meta_generic: META_GENERIC |
349 |
true_generics: ARRAY [TYPE_I] |
350 |
gt:TYPE_A |
351 |
do |
352 |
from |
353 |
i := 1 |
354 |
count := generics.count |
355 |
create meta_generic.make (count) |
356 |
create true_generics.make (1, count) |
357 |
until |
358 |
i > count |
359 |
loop |
360 |
gt := generics.item (i) |
361 |
meta_generic.put (gt.meta_type, i) |
362 |
true_generics.put (gt.type_i, i) |
363 |
i := i + 1 |
364 |
end |
365 |
|
366 |
create Result.make (class_id, meta_generic, true_generics) |
367 |
Result.set_mark (declaration_mark) |
368 |
end |
369 |
|
370 |
deep_actual_type: like Current is |
371 |
-- Actual type of Current; recursive version for generics |
372 |
local |
373 |
i: INTEGER |
374 |
new_generics: like generics |
375 |
do |
376 |
if not has_like then |
377 |
Result := Current |
378 |
else |
379 |
from |
380 |
i := generics.count |
381 |
create new_generics.make (1, i) |
382 |
until |
383 |
i <= 0 |
384 |
loop |
385 |
new_generics.put (generics.item (i).deep_actual_type, i) |
386 |
i := i - 1 |
387 |
end |
388 |
Result := twin |
389 |
Result.set_generics (new_generics) |
390 |
end |
391 |
end |
392 |
|
393 |
actual_argument_type (a_arg_types: ARRAY [TYPE_A]): like Current is |
394 |
local |
395 |
i, count: INTEGER |
396 |
new_generics: like generics |
397 |
do |
398 |
if not has_like then |
399 |
Result := Current |
400 |
else |
401 |
from |
402 |
i := 1 |
403 |
count := generics.count |
404 |
create new_generics.make (1, count) |
405 |
until |
406 |
i > count |
407 |
loop |
408 |
new_generics.put (generics.item (i).actual_argument_type (a_arg_types), i) |
409 |
i := i + 1 |
410 |
end |
411 |
Result := twin |
412 |
Result.set_generics (new_generics) |
413 |
Result.set_mark (declaration_mark) |
414 |
end |
415 |
end |
416 |
|
417 |
instantiation_in (type: TYPE_A; written_id: INTEGER): GEN_TYPE_A is |
418 |
-- TODO: new comment |
419 |
local |
420 |
i: INTEGER |
421 |
old_generics: like generics |
422 |
new_generics: like generics |
423 |
old_type: TYPE_A |
424 |
new_type: TYPE_A |
425 |
do |
426 |
Result := Current |
427 |
from |
428 |
old_generics := Result.generics |
429 |
i := old_generics.count |
430 |
until |
431 |
i <= 0 |
432 |
loop |
433 |
old_type := old_generics.item (i) |
434 |
new_type := old_type.instantiation_in (type, written_id) |
435 |
if new_type /= old_type then |
436 |
-- Record a new type of a generic parameter. |
437 |
if new_generics = Void then |
438 |
-- Avoid modifying original type descriptor. |
439 |
Result := Result.duplicate |
440 |
new_generics := Result.generics |
441 |
end |
442 |
new_generics.put (new_type, i) |
443 |
end |
444 |
i := i - 1 |
445 |
end |
446 |
end |
447 |
|
448 |
instantiated_in (class_type: TYPE_A): TYPE_A is |
449 |
-- Instantiation of Current in the context of `class_type' |
450 |
-- assuming that Current is written in the associated class |
451 |
-- of `class_type'. |
452 |
local |
453 |
i, count: INTEGER |
454 |
new_generics: like generics |
455 |
do |
456 |
from |
457 |
Result := duplicate |
458 |
i := 1 |
459 |
count := generics.count |
460 |
new_generics := Result.generics |
461 |
until |
462 |
i > count |
463 |
loop |
464 |
new_generics.put |
465 |
(generics.item (i).instantiated_in (class_type), i) |
466 |
i := i + 1 |
467 |
end |
468 |
end |
469 |
|
470 |
evaluated_type_in_descendant (a_ancestor, a_descendant: CLASS_C; a_feature: FEATURE_I): like Current is |
471 |
local |
472 |
i, nb: INTEGER |
473 |
new_generics: like generics |
474 |
do |
475 |
if a_ancestor /= a_descendant then |
476 |
if is_loose then |
477 |
from |
478 |
nb := generics.count |
479 |
create new_generics.make (1, nb) |
480 |
i := 1 |
481 |
until |
482 |
i > nb |
483 |
loop |
484 |
new_generics.put ( |
485 |
generics.item (i).evaluated_type_in_descendant (a_ancestor, a_descendant, a_feature), |
486 |
i) |
487 |
i := i + 1 |
488 |
end |
489 |
Result := twin |
490 |
Result.set_generics (new_generics) |
491 |
else |
492 |
Result := Current |
493 |
end |
494 |
else |
495 |
Result := Current |
496 |
end |
497 |
end |
498 |
|
499 |
valid_generic (type: CL_TYPE_A): BOOLEAN is |
500 |
-- Check generic parameters |
501 |
local |
502 |
i, count: INTEGER |
503 |
gen_type: GEN_TYPE_A |
504 |
gen_type_generics: like generics |
505 |
do |
506 |
if class_id = type.class_id then |
507 |
gen_type ?= type |
508 |
if gen_type /= Void then |
509 |
from |
510 |
i := 1 |
511 |
gen_type_generics := gen_type.generics |
512 |
count := generics.count |
513 |
Result := count = gen_type_generics.count |
514 |
until |
515 |
i > count or else not Result |
516 |
loop |
517 |
Result := gen_type_generics.item (i).conform_to (generics.item (i)) |
518 |
if Result and then not is_covariant (i) and then not equivalent (gen_type_generics.item (i).conformance_type, generics.item (i).conformance_type) then |
519 |
-- It is not a covariant generic, and the types differ. This is a conformance mismatch |
520 |
conformance_check.cat_result := False |
521 |
end |
522 |
i := i + 1 |
523 |
end |
524 |
end |
525 |
else |
526 |
-- `type' is a descendant type of Current: so we |
527 |
-- have to check the current generic parameters |
528 |
Result := type.generic_conform_to (Current) |
529 |
end |
530 |
end |
531 |
|
532 |
parent_type (parent: CL_TYPE_A): TYPE_A is |
533 |
-- Parent actual type in the current context |
534 |
do |
535 |
Result := instantiate (parent.duplicate) |
536 |
end |
537 |
|
538 |
instantiate (type: TYPE_A): TYPE_A is |
539 |
-- Instantiates `type'. Given that `type' may hold |
540 |
-- some formal generics, instantiate them with the |
541 |
-- generics from Current. |
542 |
require |
543 |
good_argument: type /= Void |
544 |
local |
545 |
i, count: INTEGER |
546 |
gen_type: GEN_TYPE_A |
547 |
gen_type_generics: like generics |
548 |
formal_type: FORMAL_A |
549 |
l_like_type: LIKE_TYPE_A |
550 |
do |
551 |
formal_type ?= type |
552 |
if formal_type /= Void then |
553 |
-- Instantiation of a formal generic |
554 |
Result := generics.item (formal_type.position).actual_type |
555 |
elseif type.is_like then |
556 |
-- We do not want to loose the fact that it is an anchor |
557 |
-- as otherwise we would break eweasel test exec206, but we |
558 |
-- still need to adapt its actual_type to the current context |
559 |
-- otherwise we would break valid168. |
560 |
l_like_type ?= type |
561 |
check |
562 |
l_like_type_not_void: l_like_type /= Void |
563 |
end |
564 |
l_like_type.set_actual_type (instantiate (l_like_type.conformance_type)) |
565 |
Result := l_like_type |
566 |
elseif type.has_generics then |
567 |
-- Instantiation of the generic parameter of `type' |
568 |
gen_type ?= type |
569 |
Result := gen_type.duplicate |
570 |
from |
571 |
i := 1 |
572 |
gen_type_generics := Result.generics |
573 |
count := gen_type_generics.count |
574 |
until |
575 |
i > count |
576 |
loop |
577 |
gen_type_generics.put |
578 |
(instantiate (gen_type_generics.item (i)), i) |
579 |
i := i + 1 |
580 |
end |
581 |
else |
582 |
Result := type |
583 |
end |
584 |
end |
585 |
|
586 |
has_like: BOOLEAN is |
587 |
-- Has the type anchored type in its definition ? |
588 |
local |
589 |
i, count: INTEGER |
590 |
do |
591 |
from |
592 |
i := 1 |
593 |
count := generics.count |
594 |
until |
595 |
i > count or else Result |
596 |
loop |
597 |
Result := generics.item (i).has_like |
598 |
i := i + 1 |
599 |
end |
600 |
end |
601 |
|
602 |
has_like_argument: BOOLEAN is |
603 |
-- Has the type like argument in its definition? |
604 |
local |
605 |
i, count: INTEGER |
606 |
do |
607 |
from |
608 |
i := 1 |
609 |
count := generics.count |
610 |
until |
611 |
i > count or else Result |
612 |
loop |
613 |
Result := generics.item (i).has_like_argument |
614 |
i := i + 1 |
615 |
end |
616 |
end |
617 |
|
618 |
duplicate: like Current is |
619 |
-- Duplication |
620 |
local |
621 |
i, count: INTEGER |
622 |
duplicate_generics: like generics |
623 |
do |
624 |
from |
625 |
i := 1 |
626 |
count := generics.count |
627 |
create duplicate_generics.make (1, count) |
628 |
until |
629 |
i > count |
630 |
loop |
631 |
duplicate_generics.put (generics.item (i).duplicate, i) |
632 |
i := i + 1 |
633 |
end |
634 |
Result := twin |
635 |
Result.set_generics (duplicate_generics) |
636 |
if covariance_flags /= Void then |
637 |
Result.set_covariance_flags (covariance_flags.twin) |
638 |
end |
639 |
end |
640 |
|
641 |
good_generics: BOOLEAN is |
642 |
-- Has the base class exactly the same number of generic |
643 |
-- parameters in its formal generic declarations? |
644 |
local |
645 |
base_generics: EIFFEL_LIST [FORMAL_DEC_AS] |
646 |
i, generic_count: INTEGER |
647 |
do |
648 |
base_generics := associated_class.generics |
649 |
if base_generics /= Void then |
650 |
generic_count := base_generics.count |
651 |
Result := generic_count = generics.count |
652 |
from |
653 |
i := 1 |
654 |
until |
655 |
i > generic_count or else not Result |
656 |
loop |
657 |
Result := generics.item (i).good_generics |
658 |
i := i + 1 |
659 |
end |
660 |
end |
661 |
end |
662 |
|
663 |
error_generics: VTUG is |
664 |
-- Returns the first error regarding the number of generic parameters |
665 |
-- compared to the formal generic declarations. |
666 |
--| Recursion is done to find all errors. |
667 |
local |
668 |
base_generics: EIFFEL_LIST [FORMAL_DEC_AS] |
669 |
i, generic_count: INTEGER |
670 |
do |
671 |
base_generics := associated_class.generics |
672 |
if base_generics /= Void then |
673 |
generic_count := base_generics.count |
674 |
if (generic_count = generics.count) then |
675 |
from |
676 |
i := 1 |
677 |
until |
678 |
i > generic_count or else (Result /= Void) |
679 |
loop |
680 |
if not generics.item (i).good_generics then |
681 |
Result := generics.item (i).error_generics |
682 |
end |
683 |
i := i + 1 |
684 |
end |
685 |
end |
686 |
end |
687 |
if Result = Void then |
688 |
if base_generics = Void then |
689 |
create {VTUG1} Result |
690 |
else |
691 |
create {VTUG2} Result |
692 |
end |
693 |
Result.set_type (Current) |
694 |
Result.set_base_class (associated_class) |
695 |
end |
696 |
end |
697 |
|
698 |
check_constraints (a_type_context: CLASS_C; a_context_feature: FEATURE_I; a_check_creation_readiness: BOOLEAN) is |
699 |
-- Check the constrained genericity validity rule |
700 |
--| We check for all generic parameters whether they fullfill their constraints: |
701 |
--| * conformance to all the constraining types |
702 |
--| * providing creations routines to meet all creation constraints |
703 |
local |
704 |
i, l_count: INTEGER |
705 |
l_class: CLASS_C |
706 |
l_constraints: TYPE_SET_A |
707 |
l_constraint_item: TYPE_A |
708 |
l_formal_constraint: FORMAL_A |
709 |
l_generic_constraint: GEN_TYPE_A |
710 |
l_generic_parameters: ARRAY[TYPE_A] |
711 |
l_formal_generic_parameter: FORMAL_A |
712 |
l_generic_parameter: TYPE_A |
713 |
l_conform: BOOLEAN |
714 |
l_formal_dec_as: FORMAL_CONSTRAINT_AS |
715 |
l_check_creation_readiness: BOOLEAN |
716 |
do |
717 |
l_conform := True |
718 |
l_class := associated_class |
719 |
l_generic_parameters := generics |
720 |
|
721 |
-- Check all actual generic parameters against their constraining types. |
722 |
from |
723 |
l_count := l_generic_parameters.count |
724 |
i := 1 |
725 |
until |
726 |
i > l_count or not l_conform |
727 |
loop |
728 |
l_generic_parameter := l_generic_parameters.item(i) |
729 |
l_constraints := l_class.constraints(i) |
730 |
from |
731 |
l_constraints.start |
732 |
until |
733 |
l_constraints.after |
734 |
loop |
735 |
l_constraint_item := l_constraints.item.type |
736 |
if l_constraint_item.is_formal then |
737 |
l_formal_constraint ?= l_constraint_item |
738 |
check l_formal_constraint /= Void end |
739 |
-- Replace the formal with its 'instantiation' of the current generic derivation. |
740 |
--| `l_constraint_item' can indeed still be a formal, but now has to be resolved by using `a_type_context' |
741 |
l_constraint_item := l_generic_parameters.item(l_formal_constraint.position) |
742 |
elseif l_constraint_item.has_generics and then not l_constraint_item.generics.is_empty then |
743 |
-- We substitude all occurences of formals in the constraint with the instantiation of the corresponding formal in our generic derivation. |
744 |
l_generic_constraint ?= l_constraint_item.deep_twin |
745 |
l_generic_constraint.substitute (l_generic_parameters) |
746 |
l_constraint_item := l_generic_constraint |
747 |
end |
748 |
--| Knowing that formals (FORMAL_A) just take of their "layers" and fall back to their constraints and ask and ask again until they match. |
749 |
--| Example: [G -> H, H -> I, I -> J] Question: Is G conform to J? Answer of `conform_to' is yes. |
750 |
--| Knowing that there is no recursion in such a case: X -> LIST[X] because either the input really matches LIST and then we _have_ to continue or then it does not and we stop. |
751 |
if l_generic_parameter.conformance_type.conform_to (l_constraint_item) then |
752 |
-- Everything is fine, we conform |
753 |
else |
754 |
-- We do not conform, insert an error for this type. |
755 |
l_conform := False |
756 |
generate_constraint_error (Current, l_generic_parameter, l_constraint_item, i, Void) |
757 |
end |
758 |
|
759 |
l_constraints.forth |
760 |
end |
761 |
if l_conform then |
762 |
-- Check now for the validity of the creation constraint clause if |
763 |
-- there is one which can be checked, i.e. when `to_check' conforms |
764 |
-- to `constraint_type'. |
765 |
l_formal_dec_as ?= associated_class.generics.i_th (i) |
766 |
check l_formal_dec_as_not_void: l_formal_dec_as /= Void end |
767 |
if l_formal_dec_as.has_creation_constraint and (system.check_generic_creation_constraint and a_check_creation_readiness) then |
768 |
-- If we are not in degree 3 (i.e. 4), we cannot have a |
769 |
-- complete check since if we are currently checking an attribute |
770 |
-- of TEST declared as A [TOTO], maybe TOTO has not yet been recompiled? |
771 |
-- So we store all the needed information and we will do a check at the |
772 |
-- end of the degree 4 (look at PASS2 for the code which does the checking). |
773 |
l_formal_generic_parameter ?= l_generic_parameter.conformance_type |
774 |
-- We have a creation constraint so in case a check was requested we have to continue checking it. |
775 |
l_check_creation_readiness := a_check_creation_readiness |
776 |
if System.in_pass3 then |
777 |
creation_constraint_check ( |
778 |
l_formal_dec_as, l_constraints, a_type_context, |
779 |
l_generic_parameter, i, l_formal_generic_parameter) |
780 |
else |
781 |
add_future_checking (a_type_context, |
782 |
agent delayed_creation_constraint_check (a_type_context, a_context_feature, |
783 |
l_generic_parameter, l_constraints, l_formal_dec_as, i, l_formal_generic_parameter)) |
784 |
end |
785 |
else |
786 |
-- We do not have a creation constraint, so stop checking for it. |
787 |
l_check_creation_readiness := False |
788 |
end |
789 |
end |
790 |
if l_generic_parameter.has_generics then |
791 |
-- Recursion |
792 |
l_generic_parameter.check_constraints (a_type_context, a_context_feature, l_check_creation_readiness) |
793 |
end |
794 |
|
795 |
i := i + 1 |
796 |
end |
797 |
end |
798 |
|
799 |
substitute (new_generics: ARRAY [TYPE_A]) is |
800 |
-- Take the arguments from `new_generics' to create an |
801 |
-- effective representation of the current GEN_TYPE |
802 |
require |
803 |
new_generics_not_void: new_generics /= Void |
804 |
local |
805 |
i, count, pos: INTEGER |
806 |
constraint_type: TYPE_A |
807 |
formal_type: FORMAL_A |
808 |
gen_type: GEN_TYPE_A |
809 |
do |
810 |
from |
811 |
i := 1 |
812 |
count := generics.count |
813 |
until |
814 |
i > count |
815 |
loop |
816 |
constraint_type := generics.item (i) |
817 |
|
818 |
if constraint_type.is_formal then |
819 |
formal_type ?= constraint_type |
820 |
pos := formal_type.position |
821 |
generics.force (new_generics.item (pos), i) |
822 |
elseif constraint_type.generics /= Void then |
823 |
gen_type ?= constraint_type |
824 |
gen_type.substitute (new_generics) |
825 |
end |
826 |
i := i + 1 |
827 |
end |
828 |
end |
829 |
|
830 |
delayed_creation_constraint_check ( |
831 |
context_class: CLASS_C; |
832 |
a_context_feature: FEATURE_I; |
833 |
to_check: TYPE_A |
834 |
constraint_type: TYPE_SET_A |
835 |
formal_dec_as: FORMAL_CONSTRAINT_AS |
836 |
i: INTEGER; |
837 |
formal_type: FORMAL_A) is |
838 |
-- Check that declaration of generic class is conform to |
839 |
-- defined creation constraint in delayed mode. |
840 |
require |
841 |
formal_dec_as_not_void: formal_dec_as /= Void |
842 |
creation_constraint_exists: formal_dec_as.has_creation_constraint |
843 |
to_check_is_formal_implies_formal_type_not_void: to_check.conformance_type.is_formal implies formal_type /= Void |
844 |
do |
845 |
reset_constraint_error_list |
846 |
-- We assume that we only get checks if the class is valid. |
847 |
-- However, if contracts are disabled we catch the error also with the following if-statement. |
848 |
check is_valid: is_valid end |
849 |
if is_valid and then context_class.is_valid and then to_check /= Void and then to_check.is_valid then |
850 |
creation_constraint_check (formal_dec_as, constraint_type, context_class, to_check, i, formal_type) |
851 |
generate_error_from_creation_constraint_list (context_class, a_context_feature, formal_dec_as.start_location ) |
852 |
end |
853 |
end |
854 |
|
855 |
creation_constraint_check ( |
856 |
formal_dec_as: FORMAL_CONSTRAINT_AS |
857 |
a_constraint_types: TYPE_SET_A; |
858 |
context_class: CLASS_C; |
859 |
to_check: TYPE_A; |
860 |
i: INTEGER; |
861 |
formal_type: FORMAL_A) is |
862 |
-- Check that declaration of generic class is conform to |
863 |
-- defined creation constraint. |
864 |
require |
865 |
formal_dec_as_not_void: formal_dec_as /= Void |
866 |
creation_constraint_exists: formal_dec_as.has_creation_constraint |
867 |
is_valid: is_valid |
868 |
local |
869 |
formal_type_dec_as: FORMAL_CONSTRAINT_AS |
870 |
formal_crc_list, crc_list: LINKED_LIST [TUPLE [type_item: RENAMED_TYPE_A [TYPE_A]; feature_item: FEATURE_I]]; |
871 |
creators_table: HASH_TABLE [EXPORT_I, STRING] |
872 |
matched: BOOLEAN |
873 |
feat_tbl: FEATURE_TABLE |
874 |
class_c: CLASS_C |
875 |
other_feature_i, feature_i: FEATURE_I |
876 |
l_unmatched_features: LIST [FEATURE_I] |
877 |
do |
878 |
|
879 |
-- If there is a creation constraint we are facing two different cases: |
880 |
-- * case 1: the declaration is using a real type `to_check', we check that |
881 |
-- the creation procedures listed in the constraint are indeed |
882 |
-- creation procedures of `to_check'. |
883 |
-- * case 2: the declaration is using a formal type. Let's take an example and |
884 |
-- I will explain what we need to do: |
885 |
-- we have: |
886 |
-- A[G -> C create make_1, make_2,..., make_n end] |
887 |
-- B [H, K -> MY_C create my_make_1, my_make_2,...my_make_m end] |
888 |
-- MY_C inherits from C |
889 |
-- In B, we have `a: A[K]', which is valid if: |
890 |
-- * MY_C conforms to C (already established here) |
891 |
-- * m >= n |
892 |
-- * for each `make_i' where 1 <= i <= n, there is a `j' (1 <= j <= m) |
893 |
-- where `my_make_k' is a redefined/renamed version of `make_i'. |
894 |
crc_list := formal_dec_as.constraint_creation_list (associated_class) |
895 |
if formal_type = Void then |
896 |
-- We're in the case of a class type. |
897 |
|
898 |
-- If it is a deferred class and the actual derivation uses like current |
899 |
-- we move the duty to check the creation constraint to the full class check to check |
900 |
-- the descendants of this deferred class, which can never be instantiated direclty. |
901 |
-- See bug#12464 and test#valid208/test#valid209 for more information. |
902 |
if to_check.is_like_current and context_class.is_deferred then |
903 |
-- We simply accept it. |
904 |
else |
905 |
|
906 |
if to_check.has_associated_class then |
907 |
-- `to_check' may not have an associated class if it represents NONE type, for |
908 |
-- example in PROCEDURE [ANY, NONE], we will check NONE against |
909 |
-- constraint of PROCEDURE which is `TUPLE create default_create end'. |
910 |
class_c := to_check.associated_class |
911 |
creators_table := class_c.creators |
912 |
end |
913 |
|
914 |
-- A creation procedure has to be specified, so if none is |
915 |
-- specified or if there is no creation procedure in the class |
916 |
-- corresponding to `to_check', this is not valid. |
917 |
if |
918 |
creators_table /= Void and then not creators_table.is_empty |
919 |
then |
920 |
from |
921 |
crc_list.start |
922 |
feat_tbl := class_c.feature_table |
923 |
until |
924 |
crc_list.after |
925 |
loop |
926 |
-- Let's take one of the creation procedure defined in the constraint. |
927 |
feature_i := crc_list.item.feature_item |
928 |
|
929 |
-- Take the redefined/renamed version of the previous version in the |
930 |
-- descendant class `to_check'/`class_c'. |
931 |
other_feature_i := feat_tbl.feature_of_rout_id (feature_i.rout_id_set.first) |
932 |
|
933 |
-- Test if we found the specified feature name among the creation |
934 |
-- procedures of `class_c' and that it is exported to Current, since it |
935 |
-- it is Current that will create instances of the generic parameter. |
936 |
creators_table.search (other_feature_i.feature_name) |
937 |
if |
938 |
not creators_table.found or else |
939 |
not creators_table.found_item.valid_for (associated_class) |
940 |
then |
941 |
if l_unmatched_features = Void then |
942 |
create {LINKED_LIST[FEATURE_I]} l_unmatched_features.make |
943 |
end |
944 |
l_unmatched_features.extend (feature_i) |
945 |
end |
946 |
crc_list.forth |
947 |
end |
948 |
else |
949 |
-- The class type does not have a creation clause: |
950 |
-- May be we are handling a case where the constraint only specfies |
951 |
-- `default_create', so let's check that the constraint defines |
952 |
-- `default_create' as creation procedure and that `creators_table' |
953 |
-- is Void (as empty means there is no way to create an instance of this |
954 |
-- class). |
955 |
-- At last we check that this class is not deferred. |
956 |
if |
957 |
creators_table = Void and then |
958 |
(crc_list.count = 1 and then formal_dec_as.has_default_create) |
959 |
then |
960 |
-- Ok, no error: We have no create clause which makes `default_create' available |
961 |
-- and the constraint demands only `default_create' |
962 |
|
963 |
-- But maybe it is a deferred class? |
964 |
if class_c /= Void and then class_c.is_deferred then |
965 |
if l_unmatched_features = Void then |
966 |
create {LINKED_LIST[FEATURE_I]} l_unmatched_features.make |
967 |
end |
968 |
l_unmatched_features.extend (crc_list.first.feature_item) |
969 |
end |
970 |
else |
971 |
-- Generate list of features not matching constraint. |
972 |
from |
973 |
create {LINKED_LIST[FEATURE_I]} l_unmatched_features.make |
974 |
crc_list.start |
975 |
until |
976 |
crc_list.after |
977 |
loop |
978 |
-- If `creators_table' is not Void, it simply means we have an empty creation routine |
979 |
-- and therefore all the creation constraints are not met. |
980 |
-- If it is Void, then `{ANY}.default_create' is a valid creation routine, in that |
981 |
-- case we should not list `default_create' has not beeing met if listed in the creation |
982 |
-- constraint. |
983 |
feature_i := crc_list.item.feature_item |
984 |
if creators_table /= Void or else not feature_i.rout_id_set.has (system.default_create_id) then |
985 |
l_unmatched_features.extend (feature_i) |
986 |
end |
987 |
crc_list.forth |
988 |
end |
989 |
end |
990 |
end |
991 |
-- We have an error if we have unmatched features. |
992 |
if l_unmatched_features /= Void then |
993 |
generate_constraint_error (Current, to_check, a_constraint_types, i, l_unmatched_features) |
994 |
end |
995 |
end |
996 |
else |
997 |
-- Check if there is a creation constraint clause |
998 |
formal_type_dec_as ?= context_class.generics.i_th (formal_type.position) |
999 |
if formal_type_dec_as /= Void and then formal_type_dec_as.has_creation_constraint then |
1000 |
-- Check if we have m >= n as specified above. |
1001 |
formal_crc_list := formal_type_dec_as.constraint_creation_list (context_class) |
1002 |
if formal_crc_list.count >= crc_list.count then |
1003 |
from |
1004 |
crc_list.start |
1005 |
matched := True |
1006 |
until |
1007 |
crc_list.after |
1008 |
loop |
1009 |
feature_i := crc_list.item.feature_item |
1010 |
-- Check that all the creation procedures defined in the creation |
1011 |
-- constraint clause `crc_list' are indeed present under a |
1012 |
-- redefined/renamed version in the creation constraint clause |
1013 |
from |
1014 |
matched := False |
1015 |
formal_crc_list.start |
1016 |
until |
1017 |
matched or else formal_crc_list.after |
1018 |
loop |
1019 |
matched := formal_crc_list.item.feature_item.rout_id_set.has ( |
1020 |
feature_i.rout_id_set.first) |
1021 |
formal_crc_list.forth |
1022 |
end |
1023 |
-- If not matched save the feature to report a proper error. |
1024 |
if not matched then |
1025 |
if l_unmatched_features = Void then |
1026 |
create {LINKED_LIST[FEATURE_I]} l_unmatched_features.make |
1027 |
end |
1028 |
l_unmatched_features.extend (feature_i) |
1029 |
end |
1030 |
crc_list.forth |
1031 |
end |
1032 |
else |
1033 |
matched := False |
1034 |
end |
1035 |
else |
1036 |
matched := False |
1037 |
end |
1038 |
|
1039 |
if not matched then |
1040 |
generate_constraint_error (Current, formal_type,a_constraint_types, i, l_unmatched_features) |
1041 |
end |
1042 |
end |
1043 |
end |
1044 |
|
1045 |
expanded_deferred: BOOLEAN is |
1046 |
-- Are the expanded class types present in the current generic |
1047 |
-- type not based on deferred classes ? |
1048 |
local |
1049 |
i, nb: INTEGER |
1050 |
gen_param: TYPE_A |
1051 |
do |
1052 |
from |
1053 |
Result := Precursor {CL_TYPE_A} |
1054 |
i := 1 |
1055 |
nb := generics.count |
1056 |
until |
1057 |
i > nb or else Result |
1058 |
loop |
1059 |
gen_param := generics.item (i) |
1060 |
if gen_param.has_expanded then |
1061 |
Result := gen_param.expanded_deferred |
1062 |
end |
1063 |
i := i + 1 |
1064 |
end |
1065 |
end |
1066 |
|
1067 |
valid_expanded_creation (a_class: CLASS_C): BOOLEAN is |
1068 |
-- Is the expanded type has an associated class with one |
1069 |
-- creation routine with no arguments only ? |
1070 |
local |
1071 |
i, nb: INTEGER |
1072 |
gen_param: TYPE_A |
1073 |
do |
1074 |
from |
1075 |
Result := Precursor {CL_TYPE_A} (a_class) |
1076 |
i := 1 |
1077 |
nb := generics.count |
1078 |
until |
1079 |
i > nb or else not Result |
1080 |
loop |
1081 |
gen_param := generics.item (i) |
1082 |
if gen_param.has_expanded then |
1083 |
Result := gen_param.valid_expanded_creation (a_class) |
1084 |
end |
1085 |
i := i + 1 |
1086 |
end |
1087 |
end |
1088 |
|
1089 |
format (ctxt: TEXT_FORMATTER_DECORATOR) is |
1090 |
local |
1091 |
i, count: INTEGER |
1092 |
do |
1093 |
ctxt.put_classi (associated_class.lace_class) |
1094 |
count := generics.count |
1095 |
|
1096 |
-- TUPLE may have zero generic parameters |
1097 |
if count > 0 then |
1098 |
ctxt.put_space |
1099 |
ctxt.process_symbol_text (ti_L_bracket) |
1100 |
from |
1101 |
i := 1 |
1102 |
until |
1103 |
i > count |
1104 |
loop |
1105 |
generics.item (i).format (ctxt) |
1106 |
if i /= count then |
1107 |
ctxt.process_symbol_text (ti_Comma) |
1108 |
ctxt.put_space |
1109 |
end |
1110 |
i := i + 1 |
1111 |
end |
1112 |
ctxt.process_symbol_text (ti_R_bracket) |
1113 |
end |
1114 |
end |
1115 |
|
1116 |
feature {NONE} -- Implementation |
1117 |
|
1118 |
covariance_flags: PACKED_BOOLEANS |
1119 |
-- Stores whether a generic at a certain position is marked covariant or not. |
1120 |
|
1121 |
invariant |
1122 |
|
1123 |
-- A generic class always has generic parameters |
1124 |
generics_not_void: generics /= Void |
1125 |
|
1126 |
indexing |
1127 |
copyright: "Copyright (c) 1984-2006, Eiffel Software" |
1128 |
license: "GPL version 2 (see http://www.eiffel.com/licensing/gpl.txt)" |
1129 |
licensing_options: "http://www.eiffel.com/licensing" |
1130 |
copying: "[ |
1131 |
This file is part of Eiffel Software's Eiffel Development Environment. |
1132 |
|
1133 |
Eiffel Software's Eiffel Development Environment is free |
1134 |
software; you can redistribute it and/or modify it under |
1135 |
the terms of the GNU General Public License as published |
1136 |
by the Free Software Foundation, version 2 of the License |
1137 |
(available at the URL listed under "license" above). |
1138 |
|
1139 |
Eiffel Software's Eiffel Development Environment is |
1140 |
distributed in the hope that it will be useful, but |
1141 |
WITHOUT ANY WARRANTY; without even the implied warranty |
1142 |
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
1143 |
See the GNU General Public License for more details. |
1144 |
|
1145 |
You should have received a copy of the GNU General Public |
1146 |
License along with Eiffel Software's Eiffel Development |
1147 |
Environment; if not, write to the Free Software Foundation, |
1148 |
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
1149 |
]" |
1150 |
source: "[ |
1151 |
Eiffel Software |
1152 |
356 Storke Road, Goleta, CA 93117 USA |
1153 |
Telephone 805-685-1006, Fax 805-685-6869 |
1154 |
Website http://www.eiffel.com |
1155 |
Customer support http://support.eiffel.com |
1156 |
]" |
1157 |
|
1158 |
end -- class GEN_TYPE_A |
1159 |
|