-
Notifications
You must be signed in to change notification settings - Fork 0
/
OCL_Typing.thy
1576 lines (1335 loc) · 82.9 KB
/
OCL_Typing.thy
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
(* Title: Safe OCL
Author: Denis Nikiforov, March 2019
Maintainer: Denis Nikiforov <denis.nikif at gmail.com>
License: LGPL
*)
chapter \<open>Typing\<close>
theory OCL_Typing
imports OCL_Object_Model OCL_Type_Helpers "HOL-Library.Transitive_Closure_Table"
begin
text \<open>
The following rules are more restrictive than rules given in
the OCL specification. This allows one to identify more errors
in expressions. However, these restrictions may be revised if necessary.
Perhaps some of them could be separated and should cause warnings
instead of errors.\<close>
(*** Operations Typing ******************************************************)
section \<open>Operations Typing\<close>
text \<open>
A strict operation is an operation that is defined for invalid source and
arguments and returns an invalid value if any of its source or arguments
is invalid.
A non-strict operation is an operation that either is not defined for
invalid source and arguments or returns a valid value for invalid source
or arguments.
A null-safe operation is an operation that is defined for a nullable
source.
All metaclass and type operations are non-strict, because neither
source nor argument types can be invalid. For these operations we
define rules for errorable types explicitly.
Most of the other operations are strict by default. The typing rules
for errorable source and arguments are defined implicitly. The only
exclusion from this rule is the following non-strict operations:\<close>
inductive non_strict_op :: "op \<Rightarrow> bool" where
"non_strict_op OclIsUndefinedOp"
| "non_strict_op OclIsInvalidOp"
| "non_strict_op AndOp"
| "non_strict_op OrOp"
| "non_strict_op XorOp"
| "non_strict_op ImpliesOp"
abbreviation "strict_op op \<equiv> \<not> non_strict_op op"
subsection \<open>Metaclass Operations\<close>
text \<open>
All basic types in the theory are either nullable or non-nullable.
For example, instead of @{text Boolean} type we have two types:
@{text "Boolean[1]"} and @{text "Boolean[?]"}.
The @{text "allInstances()"} operation is extended accordingly:\<close>
text \<open>
\<^verbatim>\<open>Boolean[1].allInstances() = Set{true, false}
Boolean[?].allInstances() = Set{true, false, null}\<close>\<close>
inductive mataop_type where
"finite_type\<^sub>N \<tau> \<Longrightarrow>
mataop_type (ErrorFree \<tau>) AllInstancesOp (Set \<tau>)[1]"
subsection \<open>Type Operations\<close>
text \<open>
At first we decided to allow casting only to subtypes.
However sometimes it is necessary to cast expressions to supertypes,
for example, to access overridden attributes of a supertype.
So we allow casting to subtypes and supertypes.
Casting to other types is meaningless and prohibited.\<close>
text \<open>
According to the Section 7.4.7 of the OCL specification
@{text "oclAsType()"} can be applied to collections as well as
to single values. I guess we can allow @{text "oclIsTypeOf()"}
and @{text "oclIsKindOf()"} for collections too.\<close>
text \<open>
Please take a note that the following expressions are prohibited,
because they always return true or false:\<close>
text \<open>
\<^verbatim>\<open>1.oclIsKindOf(OclAny[?])
1.oclIsKindOf(String[1])\<close>\<close>
text \<open>
Please take a note that:\<close>
text \<open>
\<^verbatim>\<open>Set{1,2,null,'abc'}->selectByKind(Integer[1]) = Set{1,2}
Set{1,2,null,'abc'}->selectByKind(Integer[?]) = Set{1,2,null}\<close>\<close>
text \<open>
The following expressions are prohibited, because they always
returns either the same or empty collections:\<close>
text \<open>
\<^verbatim>\<open>Set{1,2,null,'abc'}->selectByKind(OclAny[?])
Set{1,2,null,'abc'}->selectByKind(Collection(Boolean[1]))\<close>\<close>
inductive typeop_type where
"\<tau> < \<sigma> \<Longrightarrow>
typeop_type DotCall OclAsTypeOp \<tau> \<sigma> \<sigma>"
| "\<sigma> < \<tau> \<Longrightarrow>
typeop_type DotCall OclAsTypeOp \<tau> \<sigma> \<sigma>\<lbrakk>.!\<rbrakk>"
| "\<sigma> < \<tau>[1] \<Longrightarrow>
typeop_type DotCall OclIsTypeOfOp \<tau>[1] \<sigma> Boolean[1]"
| "\<sigma> < \<tau>[?] \<Longrightarrow>
typeop_type DotCall OclIsTypeOfOp \<tau>[?] \<sigma> Boolean[1!]"
| "\<sigma> < \<tau>[1!] \<Longrightarrow>
typeop_type DotCall OclIsTypeOfOp \<tau>[1!] \<sigma> Boolean[1!]"
| "\<sigma> < \<tau>[?!] \<Longrightarrow>
typeop_type DotCall OclIsTypeOfOp \<tau>[?!] \<sigma> Boolean[1!]"
| "\<sigma> < \<tau>[1] \<Longrightarrow>
typeop_type DotCall OclIsKindOfOp \<tau>[1] \<sigma> Boolean[1]"
| "\<sigma> < \<tau>[?] \<Longrightarrow>
typeop_type DotCall OclIsKindOfOp \<tau>[?] \<sigma> Boolean[1!]"
| "\<sigma> < \<tau>[1!] \<Longrightarrow>
typeop_type DotCall OclIsKindOfOp \<tau>[1!] \<sigma> Boolean[1!]"
| "\<sigma> < \<tau>[?!] \<Longrightarrow>
typeop_type DotCall OclIsKindOfOp \<tau>[?!] \<sigma> Boolean[1!]"
| "\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<rho>)[1] \<Longrightarrow> \<sigma> < \<rho> \<Longrightarrow>
\<upsilon> \<hookleftarrow> Collection\<^bsub>k\<^esub>(\<sigma>)[1] \<Longrightarrow>
typeop_type ArrowCall SelectByKindOp \<tau> \<sigma> \<upsilon>"
| "\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<rho>)[1!] \<Longrightarrow> \<sigma> < \<rho> \<Longrightarrow>
\<upsilon> \<hookleftarrow> Collection\<^bsub>k\<^esub>(\<sigma>)[1!] \<Longrightarrow>
typeop_type ArrowCall SelectByKindOp \<tau> \<sigma> \<upsilon>"
| "\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<rho>)[1] \<Longrightarrow> \<sigma> < \<rho> \<Longrightarrow>
\<upsilon> \<hookleftarrow> Collection\<^bsub>k\<^esub>(\<sigma>)[1] \<Longrightarrow>
typeop_type ArrowCall SelectByTypeOp \<tau> \<sigma> \<upsilon>"
| "\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<rho>)[1!] \<Longrightarrow> \<sigma> < \<rho> \<Longrightarrow>
\<upsilon> \<hookleftarrow> Collection\<^bsub>k\<^esub>(\<sigma>)[1!] \<Longrightarrow>
typeop_type ArrowCall SelectByTypeOp \<tau> \<sigma> \<upsilon>"
subsection \<open>OclAny Operations\<close>
text \<open>
The OCL specification defines @{text "toString()"} operation
only for boolean and numeric types. However, I guess it is a good
idea to define it once for all types. The OCL specification does not
state that the operation can return @{text invalid} for a null
boolean value. Let us suppose that it returns a "null" string.
However, I guess that the operation should be strict and
return @{text invalid} for an invalid value.\<close>
inductive any_unop_type where
"\<tau> \<hookrightarrow> NonIterable(\<sigma>[1]) \<Longrightarrow>
any_unop_type OclAsSetOp \<tau> (Set \<sigma>[\<^bold>1])[1]"
| "\<tau> \<hookrightarrow> NonIterable(\<sigma>[?]) \<Longrightarrow>
any_unop_type OclAsSetOp \<tau> (Set \<sigma>[\<^bold>1])[1]"
| "\<tau> \<hookrightarrow> ObjectType(\<C>)[_] \<Longrightarrow>
any_unop_type OclIsNewOp \<tau> Boolean[1]"
| "any_unop_type OclIsUndefinedOp \<tau>[?] Boolean[1]"
| "any_unop_type OclIsUndefinedOp \<tau>[1!] Boolean[1]"
| "any_unop_type OclIsUndefinedOp \<tau>[?!] Boolean[1]"
| "any_unop_type OclIsInvalidOp \<tau>[1!] Boolean[1]"
| "any_unop_type OclIsInvalidOp \<tau>[?!] Boolean[1]"
| "any_unop_type ToStringOp \<tau> String[1]"
text \<open>
It makes sense to compare values only with compatible types.\<close>
(* We have to specify the predicate type explicitly to let
a generated code work *)
inductive any_binop_type
:: "any_binop \<Rightarrow> ('a :: order) type\<^sub>N\<^sub>E \<Rightarrow> 'a type\<^sub>N\<^sub>E \<Rightarrow> 'a type\<^sub>N\<^sub>E \<Rightarrow> bool" where
"\<tau> \<le> \<sigma> \<or> \<sigma> < \<tau> \<Longrightarrow>
any_binop_type EqualOp \<tau> \<sigma> Boolean[1]"
| "\<tau> \<le> \<sigma> \<or> \<sigma> < \<tau> \<Longrightarrow>
any_binop_type NotEqualOp \<tau> \<sigma> Boolean[1]"
subsection \<open>Boolean Operations\<close>
text \<open>
Please take a note that:\<close>
text \<open>
\<^verbatim>\<open>true or false : Boolean[1]
true and null : Boolean[?]
null and null : OclVoid[?]\<close>\<close>
inductive boolean_unop_type where
"\<tau> \<le> Boolean[?!] \<Longrightarrow>
boolean_unop_type NotOp \<tau> \<tau>"
inductive boolean_binop_type where
"\<tau> \<squnion> \<sigma> = \<rho> \<Longrightarrow> \<rho> \<le> Boolean[?!] \<Longrightarrow>
boolean_binop_type AndOp \<tau> \<sigma> \<rho>"
| "\<tau> \<squnion> \<sigma> = \<rho> \<Longrightarrow> \<rho> \<le> Boolean[?!] \<Longrightarrow>
boolean_binop_type OrOp \<tau> \<sigma> \<rho>"
| "\<tau> \<squnion> \<sigma> = \<rho> \<Longrightarrow> \<rho> \<le> Boolean[?!] \<Longrightarrow>
boolean_binop_type XorOp \<tau> \<sigma> \<rho>"
| "\<tau> \<squnion> \<sigma> = \<rho> \<Longrightarrow> \<rho> \<le> Boolean[?!] \<Longrightarrow>
boolean_binop_type ImpliesOp \<tau> \<sigma> \<rho>"
subsection \<open>Numeric Operations\<close>
text \<open>
The expression @{text "1 + null"} is not well-typed.
Nullable numeric values should be converted to non-nullable ones.
This is a significant difference from the OCL specification.\<close>
text \<open>
Please take a note that @{text "floor()"} and @{text "round()"}
operations are undefined for the @{text "Integer"} type.
The @{text "Integer"} type is not inherited from the @{text "Real"}
type, it is just a subtype.\<close>
text \<open>
The @{text "oclAsType(Integer)"} operation is not well-typed,
because the @{text "UnlimitedNatural"} type is not a subtype
of the @{text "Integer"} type. So the @{text "toInteger()"}
operation should be used instead.\<close>
inductive numeric_unop_type where
"numeric_unop_type UMinusOp Real[1] Real[1]"
| "numeric_unop_type UMinusOp Integer[1] Integer[1]"
| "numeric_unop_type AbsOp Real[1] Real[1]"
| "numeric_unop_type AbsOp Integer[1] Integer[1]"
| "numeric_unop_type FloorOp Real[1] Integer[1]"
| "numeric_unop_type RoundOp Real[1] Integer[1]"
| "numeric_unop_type numeric_unop.ToIntegerOp UnlimitedNatural[1] Integer[1!]"
inductive numeric_binop_type where
"\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type PlusOp \<tau> \<sigma> (\<tau> \<squnion> \<sigma>)"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type PlusOp \<tau> \<sigma> UnlimitedNatural[1!]"
| "\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type MinusOp \<tau> \<sigma> (\<tau> \<squnion> \<sigma>)"
| "\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type MultOp \<tau> \<sigma> (\<tau> \<squnion> \<sigma>)"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type MultOp \<tau> \<sigma> UnlimitedNatural[1!]"
| "\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type DivideOp \<tau> \<sigma> Real[1!]"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type DivideOp \<tau> \<sigma> Real[1!]"
| "\<tau> = Integer[1] \<Longrightarrow> \<sigma> = Integer[1] \<Longrightarrow>
numeric_binop_type DivOp \<tau> \<sigma> Integer[1!]"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type DivOp \<tau> \<sigma> UnlimitedNatural[1!]"
| "\<tau> = Integer[1] \<Longrightarrow> \<sigma> = Integer[1] \<Longrightarrow>
numeric_binop_type ModOp \<tau> \<sigma> Integer[1!]"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type ModOp \<tau> \<sigma> UnlimitedNatural[1!]"
| "\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type NumericMaxOp \<tau> \<sigma> (\<tau> \<squnion> \<sigma>)"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type NumericMaxOp \<tau> \<sigma> UnlimitedNatural[1]"
| "\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type NumericMinOp \<tau> \<sigma> (\<tau> \<squnion> \<sigma>)"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type NumericMinOp \<tau> \<sigma> UnlimitedNatural[1]"
| "\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type NumericLessOp \<tau> \<sigma> Boolean[1]"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type NumericLessOp \<tau> \<sigma> Boolean[1]"
| "\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type NumericLessEqOp \<tau> \<sigma> Boolean[1]"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type NumericLessEqOp \<tau> \<sigma> Boolean[1]"
| "\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type NumericGreaterOp \<tau> \<sigma> Boolean[1]"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type NumericGreaterOp \<tau> \<sigma> Boolean[1]"
| "\<tau> = Integer[1]\<midarrow>Real[1] \<Longrightarrow> \<sigma> = Integer[1]\<midarrow>Real[1] \<Longrightarrow>
numeric_binop_type NumericGreaterEqOp \<tau> \<sigma> Boolean[1]"
| "\<tau> = UnlimitedNatural[1] \<Longrightarrow> \<sigma> = UnlimitedNatural[1] \<Longrightarrow>
numeric_binop_type NumericGreaterEqOp \<tau> \<sigma> Boolean[1]"
subsection \<open>String Operations\<close>
inductive string_unop_type where
"string_unop_type StringSizeOp String[1] Integer[1]"
| "string_unop_type CharactersOp String[1] (Sequence String[\<^bold>1])[1]"
| "string_unop_type ToUpperCaseOp String[1] String[1]"
| "string_unop_type ToLowerCaseOp String[1] String[1]"
| "string_unop_type ToBooleanOp String[1] Boolean[1!]"
| "string_unop_type ToRealOp String[1] Real[1!]"
| "string_unop_type ToIntegerOp String[1] Integer[1!]"
inductive string_binop_type where
"string_binop_type ConcatOp String[1] String[1] String[1]"
| "string_binop_type EqualsIgnoreCaseOp String[1] String[1] Boolean[1]"
| "string_binop_type StringLessOp String[1] String[1] Boolean[1]"
| "string_binop_type StringLessEqOp String[1] String[1] Boolean[1]"
| "string_binop_type StringGreaterOp String[1] String[1] Boolean[1]"
| "string_binop_type StringGreaterEqOp String[1] String[1] Boolean[1]"
| "string_binop_type StringIndexOfOp String[1] String[1] Integer[1]"
| "string_binop_type StringAtOp String[1] Integer[1] String[1!]"
inductive string_ternop_type where
"string_ternop_type SubstringOp String[1] Integer[1] Integer[1] String[1!]"
subsection \<open>Iterable Operations\<close>
text \<open>
Please take a note, that @{text "flatten()"} preserves a collection kind.\<close>
abbreviation "max_op_defined \<tau> \<equiv>
(\<tau> = Real[1] \<or> \<tau> = Integer[1] \<or> \<tau> = UnlimitedNatural[1] \<or>
operation_defined \<tau> STR ''max'' [\<tau>])"
abbreviation "min_op_defined \<tau> \<equiv>
(\<tau> = Real[1] \<or> \<tau> = Integer[1] \<or> \<tau> = UnlimitedNatural[1] \<or>
operation_defined \<tau> STR ''min'' [\<tau>])"
abbreviation "sum_op_defined \<tau> \<equiv>
(\<tau> = Real[1] \<or> \<tau> = Integer[1] \<or> \<tau> = UnlimitedNatural[1] \<or>
operation_defined \<tau> STR ''+'' [\<tau>])"
inductive comparable_type\<^sub>T where
"comparable_type\<^sub>T Real"
| "comparable_type\<^sub>T Integer"
| "comparable_type\<^sub>T UnlimitedNatural"
| "comparable_type\<^sub>T String"
inductive comparable_type\<^sub>N where
"comparable_type\<^sub>T \<tau> \<Longrightarrow>
comparable_type\<^sub>N (Required \<tau>) False"
| "comparable_type\<^sub>T \<tau> \<Longrightarrow>
comparable_type\<^sub>N (Optional \<tau>) True"
inductive comparable_type where
"comparable_type\<^sub>N \<tau> n \<Longrightarrow>
comparable_type (ErrorFree \<tau>) n"
| "comparable_type\<^sub>N \<tau> n \<Longrightarrow>
comparable_type (Errorable \<tau>) n"
inductive iterable_unop_type where
"\<tau> \<hookrightarrow> Iterable(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type SizeOp \<tau> Integer[1]"
| "\<tau> \<hookrightarrow> Iterable(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type IsEmptyOp \<tau> Boolean[1]"
| "\<tau> \<hookrightarrow> Iterable(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type NotEmptyOp \<tau> Boolean[1]"
| "\<tau> \<hookrightarrow> Collection(\<sigma>)[1] \<Longrightarrow> max_op_defined \<sigma> \<Longrightarrow>
iterable_unop_type MaxOp \<tau> \<sigma>"
| "\<tau> \<hookrightarrow> Collection(\<sigma>)[1] \<Longrightarrow> min_op_defined \<sigma> \<Longrightarrow>
iterable_unop_type MinOp \<tau> \<sigma>"
| "\<tau> \<hookrightarrow> Collection(\<sigma>)[1] \<Longrightarrow> sum_op_defined \<sigma> \<Longrightarrow>
iterable_unop_type SumOp \<tau> \<sigma>"
| "\<tau> \<hookrightarrow> Collection(\<sigma>)[1] \<Longrightarrow>
\<rho> \<hookleftarrow> Set(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type AsSetOp \<tau> \<rho>"
| "\<tau> \<hookrightarrow> Collection(\<sigma>)[1] \<Longrightarrow>
\<rho> \<hookleftarrow> OrderedSet(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type AsOrderedSetOp \<tau> \<rho>"
| "\<tau> \<hookrightarrow> Collection(\<sigma>)[1] \<Longrightarrow>
\<rho> \<hookleftarrow> Bag(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type AsBagOp \<tau> \<rho>"
| "\<tau> \<hookrightarrow> Collection(\<sigma>)[1] \<Longrightarrow>
\<rho> \<hookleftarrow> Sequence(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type AsSequenceOp \<tau> \<rho>"
| "\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<sigma>)[1] \<Longrightarrow>
to_single_type \<sigma> \<rho> \<Longrightarrow>
\<upsilon> \<hookleftarrow> Collection\<^bsub>k\<^esub>(\<rho>)[1] \<Longrightarrow>
iterable_unop_type FlattenOp \<tau> \<upsilon>"
| "\<tau> \<hookrightarrow> OrderedCollection(\<sigma>[1])[1] \<Longrightarrow>
iterable_unop_type FirstOp \<tau> \<sigma>[1!]"
| "\<tau> \<hookrightarrow> OrderedCollection(\<sigma>[?])[1] \<Longrightarrow>
iterable_unop_type FirstOp \<tau> \<sigma>[?!]"
| "\<tau> \<hookrightarrow> OrderedCollection(\<sigma>[1])[1] \<Longrightarrow>
iterable_unop_type LastOp \<tau> \<sigma>[1!]"
| "\<tau> \<hookrightarrow> OrderedCollection(\<sigma>[?])[1] \<Longrightarrow>
iterable_unop_type LastOp \<tau> \<sigma>[?!]"
| "\<tau> \<hookrightarrow> OrderedCollection(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type ReverseOp \<tau> \<tau>"
| "\<tau> \<hookrightarrow> Map(\<sigma>, \<rho>)[1] \<Longrightarrow>
\<upsilon> \<hookleftarrow> Set(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type KeysOp \<tau> \<upsilon>"
| "\<tau> \<hookrightarrow> Map(\<sigma>, \<rho>)[1] \<Longrightarrow>
\<upsilon> \<hookleftarrow> Bag(\<sigma>)[1] \<Longrightarrow>
iterable_unop_type ValuesOp \<tau> \<upsilon>"
text \<open>
Please take a note that if both arguments are collections,
then an element type of the resulting collection is a super type
of element types of orginal collections. However for single-valued
operations (@{text "append()"}, @{text "insertAt()"}, ...)
this behavior looks undesirable. So we restrict such arguments
to have a subtype of the collection element type.\<close>
text \<open>
Please take a note that we allow the following expressions:\<close>
text \<open>
\<^verbatim>\<open>let nullable_value : Integer[?] = null in
Sequence{1..3}->inculdes(nullable_value) and
Sequence{1..3}->inculdes(null) and
Sequence{1..3}->inculdesAll(Set{1,null})\<close>\<close>
text \<open>
The OCL specification defines @{text "including()"} and
@{text "excluding()"} operations for the @{text Sequence} type
but does not define them for the @{text OrderedSet} type.
We define them for all collection types.
It is a good idea to prohibit including of values that
do not conform to a collection element type.
However we do not restrict it.
At first we defined the following typing rules for the
@{text "excluding()"} operation:
{\isacharbar}\ {\isachardoublequoteopen}element{\isacharunderscore}type\ {\isasymtau}\ {\isasymrho}\ {\isasymLongrightarrow}\ {\isasymsigma}\ {\isasymle}\ {\isasymrho}\ {\isasymLongrightarrow}\ {\isasymsigma}\ {\isasymnoteq}\ OclVoid{\isacharbrackleft}{\isacharquery}{\isacharbrackright}\ {\isasymLongrightarrow}\isanewline
\ \ \ collection{\isacharunderscore}binop{\isacharunderscore}type\ ExcludingOp\ {\isasymtau}\ {\isasymsigma}\ {\isasymtau}{\isachardoublequoteclose}\isanewline
{\isacharbar}\ {\isachardoublequoteopen}element{\isacharunderscore}type\ {\isasymtau}\ {\isasymrho}\ {\isasymLongrightarrow}\ {\isasymsigma}\ {\isasymle}\ {\isasymrho}\ {\isasymLongrightarrow}\ {\isasymsigma}\ {\isacharequal}\ OclVoid{\isacharbrackleft}{\isacharquery}{\isacharbrackright}\ {\isasymLongrightarrow}\isanewline
\ \ \ update{\isacharunderscore}element{\isacharunderscore}type\ {\isasymtau}\ {\isacharparenleft}to{\isacharunderscore}required{\isacharunderscore}type\ {\isasymrho}{\isacharparenright}\ {\isasymupsilon}\ {\isasymLongrightarrow}\isanewline
\ \ \ collection{\isacharunderscore}binop{\isacharunderscore}type\ ExcludingOp\ {\isasymtau}\ {\isasymsigma}\ {\isasymupsilon}{\isachardoublequoteclose}\isanewline
This operation could play a special role in a definition
of safe navigation operations:\<close>
text \<open>
\<^verbatim>\<open>Sequence{1,2,null}->exculding(null) : Integer[1]\<close>\<close>
text \<open>
However it is more natural to use a @{text "selectByKind(T[1])"}
operation instead.\<close>
(* TODO: Написать про разницу including и append *)
notation unwrap_errorable_type ("\<lfloor>_\<rfloor>\<^sub>E")
inductive iterable_binop_type where
"\<tau> \<hookrightarrow> Collection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<le> \<rho>[??] \<Longrightarrow>
iterable_binop_type CountOp \<tau> \<sigma> Integer[1]"
| "\<tau> \<hookrightarrow> Iterable(\<rho>)[1] \<Longrightarrow>
\<sigma> \<le> \<rho>[??] \<Longrightarrow>
iterable_binop_type IncludesOp \<tau> \<sigma> Boolean[1]"
| "\<tau> \<hookrightarrow> Iterable(\<rho>)[1] \<Longrightarrow>
\<sigma> \<le> \<rho>[??] \<Longrightarrow>
iterable_binop_type ExcludesOp \<tau> \<sigma> Boolean[1]"
| "\<tau> \<hookrightarrow> Map(\<rho>, \<upsilon>)[1] \<Longrightarrow> \<sigma> \<le> \<upsilon>[??] \<Longrightarrow>
iterable_binop_type IncludesValueOp \<tau> \<sigma> Boolean[1]"
| "\<tau> \<hookrightarrow> Map(\<rho>, \<upsilon>)[1] \<Longrightarrow> \<sigma> \<le> \<upsilon>[??] \<Longrightarrow>
iterable_binop_type ExcludesValueOp \<tau> \<sigma> Boolean[1]"
| "\<tau> \<hookrightarrow> Iterable(\<rho>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> Collection(\<upsilon>)[1] \<Longrightarrow>
\<upsilon> \<le> \<rho>[??] \<Longrightarrow>
iterable_binop_type IncludesAllOp \<tau> \<sigma> Boolean[1]"
| "\<tau> \<hookrightarrow> Iterable(\<rho>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> Collection(\<upsilon>)[1] \<Longrightarrow>
\<upsilon> \<le> \<rho>[??] \<Longrightarrow>
iterable_binop_type ExcludesAllOp \<tau> \<sigma> Boolean[1]"
| "\<tau> \<hookrightarrow> Map(\<rho>, \<upsilon>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> Map(\<phi>, \<psi>)[1] \<Longrightarrow>
\<phi> \<le> \<rho>[??] \<Longrightarrow>
\<psi> \<le> \<upsilon>[??] \<Longrightarrow>
iterable_binop_type IncludesMapOp \<tau> \<sigma> Boolean[1]"
| "\<tau> \<hookrightarrow> Map(\<rho>, \<upsilon>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> Map(\<phi>, \<psi>)[1] \<Longrightarrow>
\<phi> \<le> \<rho>[??] \<Longrightarrow>
\<psi> \<le> \<upsilon>[??] \<Longrightarrow>
iterable_binop_type ExcludesMapOp \<tau> \<sigma> Boolean[1]"
| "\<tau> \<hookrightarrow> Collection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> Collection(\<upsilon>)[1] \<Longrightarrow>
iterable_binop_type ProductOp \<tau> \<sigma>
(Set (Tuple(STR ''first'' : \<lfloor>\<rho>\<rfloor>\<^sub>E, STR ''second'' : \<lfloor>\<upsilon>\<rfloor>\<^sub>E))[\<^bold>1])[1]"
| "iterable_binop_type UnionOp (Set \<tau>)[1] (Set \<sigma>)[1] (Set (\<tau> \<squnion> \<sigma>))[1]"
| "iterable_binop_type UnionOp (Set \<tau>)[1] (Bag \<sigma>)[1] (Bag (\<tau> \<squnion> \<sigma>))[1]"
| "iterable_binop_type UnionOp (Bag \<tau>)[1] (Set \<sigma>)[1] (Bag (\<tau> \<squnion> \<sigma>))[1]"
| "iterable_binop_type UnionOp (Bag \<tau>)[1] (Bag \<sigma>)[1] (Bag (\<tau> \<squnion> \<sigma>))[1]"
| "iterable_binop_type IntersectionOp (Set \<tau>)[1] (Set \<sigma>)[1] (Set (\<tau> \<squnion> \<sigma>))[1]"
| "iterable_binop_type IntersectionOp (Set \<tau>)[1] (Bag \<sigma>)[1] (Set (\<tau> \<squnion> \<sigma>))[1]"
| "iterable_binop_type IntersectionOp (Bag \<tau>)[1] (Set \<sigma>)[1] (Set (\<tau> \<squnion> \<sigma>))[1]"
| "iterable_binop_type IntersectionOp (Bag \<tau>)[1] (Bag \<sigma>)[1] (Bag (\<tau> \<squnion> \<sigma>))[1]"
| "\<tau> \<le> \<sigma> \<or> \<sigma> \<le> \<tau> \<Longrightarrow>
iterable_binop_type SetMinusOp (Set \<tau>)[1] (Set \<sigma>)[1] (Set \<tau>)[1]"
| "iterable_binop_type SymmetricDifferenceOp (Set \<tau>)[1] (Set \<sigma>)[1] (Set (\<tau> \<squnion> \<sigma>))[1]"
| "\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<rho>)[1] \<Longrightarrow>
\<phi> \<hookleftarrow> Collection\<^bsub>k\<^esub>(\<rho> \<squnion> \<sigma>)[1] \<Longrightarrow>
iterable_binop_type IncludingOp \<tau> \<sigma> \<phi>"
| "\<tau> \<hookrightarrow> Collection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<le> \<rho> \<Longrightarrow>
iterable_binop_type ExcludingOp \<tau> \<sigma> \<tau>"
| "\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<rho>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> Collection(\<upsilon>)[1] \<Longrightarrow>
\<phi> \<hookleftarrow> Collection\<^bsub>k\<^esub>(\<rho> \<squnion> \<upsilon>)[1] \<Longrightarrow>
iterable_binop_type IncludingAllOp \<tau> \<sigma> \<phi>"
| "\<tau> \<hookrightarrow> Collection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> Collection(\<upsilon>)[1] \<Longrightarrow>
\<upsilon> \<le> \<rho> \<Longrightarrow>
iterable_binop_type ExcludingAllOp \<tau> \<sigma> \<tau>"
| "\<tau> \<hookrightarrow> Map(\<rho>, \<upsilon>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> Map(\<rho>', \<upsilon>')[1] \<Longrightarrow>
\<phi> \<hookleftarrow> Map(\<rho> \<squnion> \<rho>', \<upsilon> \<squnion> \<upsilon>')[1] \<Longrightarrow>
iterable_binop_type IncludingMapOp \<tau> \<sigma> \<phi>"
| "\<tau> \<hookrightarrow> Map(\<rho>, \<upsilon>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> Map(\<rho>', \<upsilon>')[1] \<Longrightarrow>
\<rho>' \<le> \<rho> \<Longrightarrow>
\<upsilon>' \<le> \<upsilon> \<Longrightarrow>
iterable_binop_type ExcludingMapOp \<tau> \<sigma> \<tau>"
| "\<tau> \<hookrightarrow> OrderedCollection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<le> \<rho> \<Longrightarrow>
iterable_binop_type AppendOp \<tau> \<sigma> \<tau>"
| "\<tau> \<hookrightarrow> OrderedCollection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<le> \<rho> \<Longrightarrow>
iterable_binop_type PrependOp \<tau> \<sigma> \<tau>"
| "\<tau> \<hookrightarrow> OrderedCollection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> OrderedCollection(\<upsilon>)[1] \<Longrightarrow>
\<upsilon> \<le> \<rho> \<Longrightarrow>
iterable_binop_type AppendAllOp \<tau> \<sigma> \<tau>"
| "\<tau> \<hookrightarrow> OrderedCollection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<hookrightarrow> OrderedCollection(\<upsilon>)[1] \<Longrightarrow>
\<upsilon> \<le> \<rho> \<Longrightarrow>
iterable_binop_type PrependAllOp \<tau> \<sigma> \<tau>"
| "\<tau> \<hookrightarrow> OrderedCollection(\<sigma>[1])[1] \<Longrightarrow>
iterable_binop_type AtOp \<tau> Integer[1] \<sigma>[1!]"
| "\<tau> \<hookrightarrow> OrderedCollection(\<sigma>[?])[1] \<Longrightarrow>
iterable_binop_type AtOp \<tau> Integer[1] \<sigma>[?!]"
| "\<tau> \<hookrightarrow> Map(\<rho>, \<upsilon>[1])[1] \<Longrightarrow>
\<sigma> \<le> \<rho>[??] \<Longrightarrow>
iterable_binop_type AtOp \<tau> \<sigma> \<upsilon>[1!]"
| "\<tau> \<hookrightarrow> Map(\<rho>, \<upsilon>[?])[1] \<Longrightarrow>
\<sigma> \<le> \<rho>[??] \<Longrightarrow>
iterable_binop_type AtOp \<tau> \<sigma> \<upsilon>[?!]"
| "\<tau> \<hookrightarrow> OrderedCollection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<le> \<rho> \<Longrightarrow>
iterable_binop_type IndexOfOp \<tau> \<sigma> Integer[1]"
inductive iterable_ternop_type where
"\<tau>[1] \<hookrightarrow> OrderedCollection(\<rho>)[1] \<Longrightarrow>
\<sigma> \<le> \<rho> \<Longrightarrow>
iterable_ternop_type InsertAtOp \<tau>[1] Integer[1] \<sigma> \<tau>[1!]"
| "\<tau>[1] \<hookrightarrow> OrderedSet(\<sigma>)[1] \<Longrightarrow>
iterable_ternop_type SubOrderedSetOp \<tau>[1] Integer[1] Integer[1] \<tau>[1!]"
| "\<tau>[1] \<hookrightarrow> Sequence(\<sigma>)[1] \<Longrightarrow>
iterable_ternop_type SubSequenceOp \<tau>[1] Integer[1] Integer[1] \<tau>[1!]"
| "\<tau> \<hookrightarrow> Map(\<upsilon>, \<phi>)[1] \<Longrightarrow>
\<sigma> \<le> \<upsilon> \<Longrightarrow>
\<rho> \<le> \<phi> \<Longrightarrow>
iterable_ternop_type IncludesPairOp \<tau> \<sigma> \<rho> Boolean[1]"
| "\<tau> \<hookrightarrow> Map(\<upsilon>, \<phi>)[1] \<Longrightarrow>
\<sigma> \<le> \<upsilon> \<Longrightarrow>
\<rho> \<le> \<phi> \<Longrightarrow>
iterable_ternop_type ExcludesPairOp \<tau> \<sigma> \<rho> Boolean[1]"
| "\<tau> \<hookrightarrow> Map(\<upsilon>, \<phi>)[1] \<Longrightarrow>
\<psi> \<hookleftarrow> Map(\<upsilon> \<squnion> \<sigma>, \<phi> \<squnion> \<rho>)[1] \<Longrightarrow>
iterable_ternop_type IncludingPairOp \<tau> \<sigma> \<rho> \<psi>"
| "\<tau> \<hookrightarrow> Map(\<upsilon>, \<phi>)[1] \<Longrightarrow>
\<sigma> \<le> \<upsilon> \<Longrightarrow>
\<rho> \<le> \<phi> \<Longrightarrow>
iterable_ternop_type ExcludingPairOp \<tau> \<sigma> \<rho> \<tau>"
subsection \<open>Iterations\<close>
inductive iteration_type where
"n \<le> (1 :: nat) \<Longrightarrow>
\<rho> \<le> Boolean[?] \<Longrightarrow>
iteration_type AnyIter n \<tau> \<sigma>[1] \<rho> \<sigma>[1!]"
| "n \<le> (1 :: nat) \<Longrightarrow>
\<rho> \<le> Boolean[?] \<Longrightarrow>
iteration_type AnyIter n \<tau> \<sigma>[?] \<rho> \<sigma>[?!]"
| "n \<le> 1 \<Longrightarrow>
\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<sigma>)[1.] \<Longrightarrow>
\<rho> \<hookrightarrow> Collection(\<phi>)[1.] \<Longrightarrow>
\<phi> \<le> \<sigma> \<Longrightarrow>
\<upsilon> \<hookleftarrow> UniqueCollection\<^bsub>k\<^esub>(\<sigma>)[1] \<Longrightarrow>
iteration_type ClosureIter n \<tau> \<sigma> \<rho> \<upsilon>"
| "n \<le> 1 \<Longrightarrow>
to_single_type \<rho> \<rho>' \<Longrightarrow>
\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<sigma>)[1.] \<Longrightarrow>
\<upsilon> \<hookleftarrow> NonUniqueCollection\<^bsub>k\<^esub>(\<rho>')[1] \<Longrightarrow>
iteration_type CollectIter n \<tau> \<sigma> \<rho> \<upsilon>"
| "n \<le> 1 \<Longrightarrow>
to_single_type \<rho> \<rho>' \<Longrightarrow>
\<tau> \<hookrightarrow> Map(\<sigma>, _)[1.] \<Longrightarrow>
\<upsilon> \<hookleftarrow> Bag(\<rho>')[1] \<Longrightarrow>
iteration_type CollectIter n \<tau> \<sigma> \<rho> \<upsilon>"
| "n \<le> 1 \<Longrightarrow>
\<upsilon> \<hookleftarrow> Map(\<sigma>, \<rho>)[1] \<Longrightarrow>
iteration_type CollectByIter n \<tau> \<sigma> \<rho> \<upsilon>"
| "n \<le> 1 \<Longrightarrow>
\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<sigma>)[1.] \<Longrightarrow>
\<upsilon> \<hookleftarrow> NonUniqueCollection\<^bsub>k\<^esub>(\<rho>)[1] \<Longrightarrow>
iteration_type CollectNestedIter n \<tau> \<sigma> \<rho> \<upsilon>"
| "n \<le> 1 \<Longrightarrow>
\<tau> \<hookrightarrow> Map(\<upsilon>, _)[1.] \<Longrightarrow>
\<phi> \<hookleftarrow> Map(\<upsilon>, \<rho>)[1] \<Longrightarrow>
iteration_type CollectNestedIter n \<tau> \<sigma> \<rho> \<phi>"
| "n \<le> 2 \<Longrightarrow>
\<rho> \<le> Boolean[?!] \<Longrightarrow>
iteration_type ExistsIter n \<tau> \<sigma> \<rho> \<rho>"
| "n \<le> 2 \<Longrightarrow>
\<rho> \<le> Boolean[?!] \<Longrightarrow>
iteration_type ForAllIter n \<tau> \<sigma> \<rho> \<rho>"
| "n \<le> 1 \<Longrightarrow>
\<rho> \<le> Boolean[?!] \<Longrightarrow>
iteration_type OneIter n \<tau> \<sigma> \<rho> Boolean[1]"
| "n \<le> 1 \<Longrightarrow>
iteration_type IsUniqueIter n \<tau> \<sigma> \<rho> Boolean[1]"
| "n \<le> 1 \<Longrightarrow>
\<rho> \<le> Boolean[?!] \<Longrightarrow>
iteration_type SelectIter n \<tau> \<sigma> \<rho> \<tau>"
| "n \<le> 1 \<Longrightarrow>
\<rho> \<le> Boolean[?!] \<Longrightarrow>
iteration_type RejectIter n \<tau> \<sigma> \<rho> \<tau>"
| "n \<le> 1 \<Longrightarrow>
\<tau> \<hookrightarrow> Collection\<^bsub>k\<^esub>(\<sigma>)[1.] \<Longrightarrow>
\<upsilon> \<hookleftarrow> OrderedCollection\<^bsub>k\<^esub>(\<sigma>)[1] \<Longrightarrow>
iteration_type SortedByIter n \<tau> \<sigma> \<rho> \<upsilon>"
subsection \<open>Coercions\<close>
inductive unop_type where
"any_unop_type op \<tau> \<sigma> \<Longrightarrow>
unop_type (Inl op) DotCall \<tau> \<sigma>"
| "boolean_unop_type op \<tau> \<sigma> \<Longrightarrow>
unop_type (Inr (Inl op)) DotCall \<tau> \<sigma>"
| "numeric_unop_type op \<tau> \<sigma> \<Longrightarrow>
unop_type (Inr (Inr (Inl op))) DotCall \<tau> \<sigma>"
| "string_unop_type op \<tau> \<sigma> \<Longrightarrow>
unop_type (Inr (Inr (Inr (Inl op)))) DotCall \<tau> \<sigma>"
| "iterable_unop_type op \<tau> \<sigma> \<Longrightarrow>
unop_type (Inr (Inr (Inr (Inr op)))) ArrowCall \<tau> \<sigma>"
inductive binop_type where
"any_binop_type op \<tau> \<sigma> \<rho> \<Longrightarrow>
binop_type (Inl op) DotCall \<tau> \<sigma> \<rho>"
| "boolean_binop_type op \<tau> \<sigma> \<rho> \<Longrightarrow>
binop_type (Inr (Inl op)) DotCall \<tau> \<sigma> \<rho>"
| "numeric_binop_type op \<tau> \<sigma> \<rho> \<Longrightarrow>
binop_type (Inr (Inr (Inl op))) DotCall \<tau> \<sigma> \<rho>"
| "string_binop_type op \<tau> \<sigma> \<rho> \<Longrightarrow>
binop_type (Inr (Inr (Inr (Inl op)))) DotCall \<tau> \<sigma> \<rho>"
| "iterable_binop_type op \<tau> \<sigma> \<rho> \<Longrightarrow>
binop_type (Inr (Inr (Inr (Inr op)))) ArrowCall \<tau> \<sigma> \<rho>"
inductive ternop_type where
"string_ternop_type op \<tau> \<sigma> \<rho> \<upsilon> \<Longrightarrow>
ternop_type (Inl op) DotCall \<tau> \<sigma> \<rho> \<upsilon>"
| "iterable_ternop_type op \<tau> \<sigma> \<rho> \<upsilon> \<Longrightarrow>
ternop_type (Inr op) ArrowCall \<tau> \<sigma> \<rho> \<upsilon>"
definition "op_result_type_is_errorable op \<pi> \<equiv>
strict_op op \<and> fBex \<pi> errorable_type"
inductive op_type where
"unop_type op k \<tau>\<lbrakk>.\<rbrakk> \<upsilon> \<Longrightarrow>
op_result_type_is_errorable (Inl op) {|\<tau>|} \<Longrightarrow>
op_type (Inl op) k \<tau> [] \<upsilon>\<lbrakk>.!\<rbrakk>"
| "unop_type op k \<tau> \<upsilon> \<Longrightarrow>
\<not> op_result_type_is_errorable (Inl op) {|\<tau>|} \<Longrightarrow>
op_type (Inl op) k \<tau> [] \<upsilon>"
| "binop_type op k \<tau>\<lbrakk>.\<rbrakk> \<sigma>\<lbrakk>.\<rbrakk> \<upsilon> \<Longrightarrow>
op_result_type_is_errorable (Inr (Inl op)) {|\<tau>, \<sigma>|} \<Longrightarrow>
op_type (Inr (Inl op)) k \<tau> [\<sigma>] \<upsilon>\<lbrakk>.!\<rbrakk>"
| "binop_type op k \<tau> \<sigma> \<upsilon> \<Longrightarrow>
\<not> op_result_type_is_errorable (Inr (Inl op)) {|\<tau>, \<sigma>|} \<Longrightarrow>
op_type (Inr (Inl op)) k \<tau> [\<sigma>] \<upsilon>"
| "ternop_type op k \<tau>\<lbrakk>.\<rbrakk> \<sigma>\<lbrakk>.\<rbrakk> \<rho>\<lbrakk>.\<rbrakk> \<upsilon> \<Longrightarrow>
op_result_type_is_errorable (Inr (Inr (Inl op))) {|\<tau>, \<sigma>, \<rho>|} \<Longrightarrow>
op_type (Inr (Inr (Inl op))) k \<tau> [\<sigma>, \<rho>] \<upsilon>\<lbrakk>.!\<rbrakk>"
| "ternop_type op k \<tau> \<sigma> \<rho> \<upsilon> \<Longrightarrow>
\<not> op_result_type_is_errorable (Inr (Inr (Inl op))) {|\<tau>, \<sigma>, \<rho>|} \<Longrightarrow>
op_type (Inr (Inr (Inl op))) k \<tau> [\<sigma>, \<rho>] \<upsilon>"
| "operation \<tau> op \<pi> oper \<Longrightarrow>
op_type (Inr (Inr (Inr op))) DotCall \<tau> \<pi> (oper_type oper)"
(*code_pred [show_modes] op_type .*)
(*** Simplification Rules ***************************************************)
subsection \<open>Simplification Rules\<close>
inductive_simps op_type_alt_simps:
"mataop_type \<tau> op \<sigma>"
"typeop_type k op \<tau> \<sigma> \<rho>"
"op_type op k \<tau> \<pi> \<sigma>"
"unop_type op k \<tau> \<sigma>"
"binop_type op k \<tau> \<sigma> \<rho>"
"ternop_type op k \<tau> \<sigma> \<rho> \<upsilon>"
"any_unop_type op \<tau> \<sigma>"
"boolean_unop_type op \<tau> \<sigma>"
"numeric_unop_type op \<tau> \<sigma>"
"string_unop_type op \<tau> \<sigma>"
"iterable_unop_type op \<tau> \<sigma>"
"any_binop_type op \<tau> \<sigma> \<rho>"
"boolean_binop_type op \<tau> \<sigma> \<rho>"
"numeric_binop_type op \<tau> \<sigma> \<rho>"
"string_binop_type op \<tau> \<sigma> \<rho>"
"iterable_binop_type op \<tau> \<sigma> \<rho>"
"string_ternop_type op \<tau> \<sigma> \<rho> \<upsilon>"
"iterable_ternop_type op \<tau> \<sigma> \<rho> \<upsilon>"
(*** Determinism ************************************************************)
(*code_pred [show_modes] op_type .*)
subsection \<open>Determinism\<close>
lemma mataop_type_det:
"mataop_type \<tau> op \<sigma> \<Longrightarrow>
mataop_type \<tau> op \<rho> \<Longrightarrow> \<sigma> = \<rho>"
by (auto simp: mataop_type.simps)
lemma typeop_type_det:
"typeop_type op k \<tau> \<sigma> \<rho>\<^sub>1 \<Longrightarrow>
typeop_type op k \<tau> \<sigma> \<rho>\<^sub>2 \<Longrightarrow> \<rho>\<^sub>1 = \<rho>\<^sub>2"
apply (erule typeop_type.cases; simp add: typeop_type.simps)
apply auto[1]
apply auto[1]
using collection_type_det collection_type'_det by blast+
lemma any_unop_type_det:
"any_unop_type op \<tau> \<sigma>\<^sub>1 \<Longrightarrow>
any_unop_type op \<tau> \<sigma>\<^sub>2 \<Longrightarrow> \<sigma>\<^sub>1 = \<sigma>\<^sub>2"
by (erule any_unop_type.cases;
simp add: any_unop_type.simps any_type_template'.simps any_type.simps)
lemma boolean_unop_type_det:
"boolean_unop_type op \<tau> \<sigma>\<^sub>1 \<Longrightarrow>
boolean_unop_type op \<tau> \<sigma>\<^sub>2 \<Longrightarrow> \<sigma>\<^sub>1 = \<sigma>\<^sub>2"
by (erule boolean_unop_type.cases; simp add: boolean_unop_type.simps)
lemma numeric_unop_type_det:
"numeric_unop_type op \<tau> \<sigma>\<^sub>1 \<Longrightarrow>
numeric_unop_type op \<tau> \<sigma>\<^sub>2 \<Longrightarrow> \<sigma>\<^sub>1 = \<sigma>\<^sub>2"
by (erule numeric_unop_type.cases; auto simp add: numeric_unop_type.simps)
lemma string_unop_type_det:
"string_unop_type op \<tau> \<sigma>\<^sub>1 \<Longrightarrow>
string_unop_type op \<tau> \<sigma>\<^sub>2 \<Longrightarrow> \<sigma>\<^sub>1 = \<sigma>\<^sub>2"
by (erule string_unop_type.cases; simp add: string_unop_type.simps)
lemma iterable_unop_type_det:
"iterable_unop_type op \<tau> \<sigma>\<^sub>1 \<Longrightarrow>
iterable_unop_type op \<tau> \<sigma>\<^sub>2 \<Longrightarrow> \<sigma>\<^sub>1 = \<sigma>\<^sub>2"
apply (erule iterable_unop_type.cases; simp add: iterable_unop_type.simps)
using collection_type'_det any_collection_type_det apply blast+
using collection_type_det collection_type'_det to_single_type_det apply blast+
using any_ordered_collection_type_det apply blast+
using collection_type'_det map_type_det by blast+
lemma unop_type_det:
"unop_type op k \<tau> \<sigma>\<^sub>1 \<Longrightarrow>
unop_type op k \<tau> \<sigma>\<^sub>2 \<Longrightarrow> \<sigma>\<^sub>1 = \<sigma>\<^sub>2"
by (erule unop_type.cases;
simp add: unop_type.simps any_unop_type_det
boolean_unop_type_det numeric_unop_type_det
string_unop_type_det iterable_unop_type_det)
lemma any_binop_type_det:
"any_binop_type op \<tau> \<sigma> \<rho>\<^sub>1 \<Longrightarrow>
any_binop_type op \<tau> \<sigma> \<rho>\<^sub>2 \<Longrightarrow> \<rho>\<^sub>1 = \<rho>\<^sub>2"
by (erule any_binop_type.cases; auto simp add: any_binop_type.simps)
lemma boolean_binop_type_det:
"boolean_binop_type op \<tau> \<sigma> \<rho>\<^sub>1 \<Longrightarrow>
boolean_binop_type op \<tau> \<sigma> \<rho>\<^sub>2 \<Longrightarrow> \<rho>\<^sub>1 = \<rho>\<^sub>2"
by (erule boolean_binop_type.cases; simp add: boolean_binop_type.simps)
lemma numeric_binop_type_det:
"numeric_binop_type op \<tau> \<sigma> \<rho>\<^sub>1 \<Longrightarrow>
numeric_binop_type op \<tau> \<sigma> \<rho>\<^sub>2 \<Longrightarrow> \<rho>\<^sub>1 = \<rho>\<^sub>2"
by (erule numeric_binop_type.cases;
auto simp add: numeric_binop_type.simps split: if_splits)
lemma string_binop_type_det:
"string_binop_type op \<tau> \<sigma> \<rho>\<^sub>1 \<Longrightarrow>
string_binop_type op \<tau> \<sigma> \<rho>\<^sub>2 \<Longrightarrow> \<rho>\<^sub>1 = \<rho>\<^sub>2"
by (erule string_binop_type.cases; simp add: string_binop_type.simps)
lemma iterable_binop_type_det:
"iterable_binop_type op \<tau> \<sigma> \<rho>\<^sub>1 \<Longrightarrow>
iterable_binop_type op \<tau> \<sigma> \<rho>\<^sub>2 \<Longrightarrow> \<rho>\<^sub>1 = \<rho>\<^sub>2"
apply (erule iterable_binop_type.cases; simp add: iterable_binop_type.simps)
using any_collection_type_det apply blast
using collection_type'_det collection_type_det apply blast
apply (metis any_collection_type_det collection_type'_det collection_type_det)
apply (metis map_type'_det map_type_det)
using any_ordered_collection_type_and_map_type_distinct
any_ordered_collection_type_det apply blast
using any_ordered_collection_type_and_map_type_distinct any_ordered_collection_type_det apply blast
apply (metis any_ordered_collection_type_and_map_type_distinct errorable.inject(1) map_type_det)
using any_ordered_collection_type_and_map_type_distinct map_type_det by blast
lemma binop_type_det:
"binop_type op k \<tau> \<sigma> \<rho>\<^sub>1 \<Longrightarrow>
binop_type op k \<tau> \<sigma> \<rho>\<^sub>2 \<Longrightarrow> \<rho>\<^sub>1 = \<rho>\<^sub>2"
by (erule binop_type.cases;
simp add: binop_type.simps any_binop_type_det
boolean_binop_type_det numeric_binop_type_det
string_binop_type_det iterable_binop_type_det)
lemma string_ternop_type_det:
"string_ternop_type op \<tau> \<sigma> \<rho> \<upsilon>\<^sub>1 \<Longrightarrow>
string_ternop_type op \<tau> \<sigma> \<rho> \<upsilon>\<^sub>2 \<Longrightarrow> \<upsilon>\<^sub>1 = \<upsilon>\<^sub>2"
by (erule string_ternop_type.cases; simp add: string_ternop_type.simps)
lemma iterable_ternop_type_det:
"iterable_ternop_type op \<tau> \<sigma> \<rho> \<upsilon>\<^sub>1 \<Longrightarrow>
iterable_ternop_type op \<tau> \<sigma> \<rho> \<upsilon>\<^sub>2 \<Longrightarrow> \<upsilon>\<^sub>1 = \<upsilon>\<^sub>2"
apply (erule iterable_ternop_type.cases; simp add: iterable_ternop_type.simps)
using map_type_det map_type'_det by blast
lemma ternop_type_det:
"ternop_type op k \<tau> \<sigma> \<rho> \<upsilon>\<^sub>1 \<Longrightarrow>
ternop_type op k \<tau> \<sigma> \<rho> \<upsilon>\<^sub>2 \<Longrightarrow> \<upsilon>\<^sub>1 = \<upsilon>\<^sub>2"
by (erule ternop_type.cases;
simp add: ternop_type.simps string_ternop_type_det iterable_ternop_type_det)
lemma op_type_det:
"op_type op k \<tau> \<pi> \<sigma> \<Longrightarrow>
op_type op k \<tau> \<pi> \<rho> \<Longrightarrow> \<sigma> = \<rho>"
apply (erule op_type.cases; simp add: op_type.simps)
using unop_type_det binop_type_det ternop_type_det apply blast+
using operation_det by blast
lemma collection_type_template_det:
"collection_type_template \<tau> k\<^sub>1 \<sigma>\<^sub>1 n\<^sub>1 \<Longrightarrow>
collection_type_template \<tau> k\<^sub>2 \<sigma>\<^sub>2 n\<^sub>2 \<Longrightarrow> k\<^sub>1 = k\<^sub>2 \<and> \<sigma>\<^sub>1 = \<sigma>\<^sub>2 \<and> n\<^sub>1 = n\<^sub>2"
apply (simp add: collection_type_template.simps)
using collection_type_det by blast
lemma any_collection_type_and_map_type_distinct':
"collection_type_template \<tau> k \<sigma> n\<^sub>1 \<Longrightarrow> map_type_template \<tau> \<rho> \<upsilon> n\<^sub>2 \<Longrightarrow> False"
by (auto simp: collection_type_template.simps collection_type.simps
collection_type\<^sub>N.simps collection_type\<^sub>T.simps
map_type_template.simps
map_type.simps map_type\<^sub>N.simps map_type\<^sub>T.simps)
lemma iteration_type_det:
"iteration_type iter n \<tau> \<sigma> \<rho> \<upsilon> \<Longrightarrow>
iteration_type iter n \<tau> \<sigma> \<rho> \<phi> \<Longrightarrow> \<upsilon> = \<phi>"
apply (erule iteration_type.cases; simp add: iteration_type.simps)
using collection_type_template_det unique_collection_type'_det apply blast
apply (metis any_collection_type_and_map_type_distinct' collection_type_template_det non_unique_collection_type'_det to_single_type_det)
using any_collection_type_and_map_type_distinct' collection_type'_det to_single_type_det apply blast
using map_type'_det apply blast
using any_collection_type_and_map_type_distinct' collection_type_template_det non_unique_collection_type'_det apply blast
using any_collection_type_and_map_type_distinct' map_type'_det map_type_template_det apply blast
using collection_type_template_det ordered_collection_type'_det by blast
(*** Expressions Typing *****************************************************)
section \<open>Expressions Typing\<close>
text \<open>
The following typing rules are preliminary. The final rules are given at
the end of the next chapter.\<close>
definition "iterators its \<tau> \<equiv>
fmap_of_list (map (\<lambda>it. (fst it, \<tau>)) its)"
definition "coiterators its \<tau> \<equiv>
fmap_of_list (map (\<lambda>it. (the (snd it), \<tau>)) (filter (\<lambda>it. snd it \<noteq> None) its))"
inductive typing :: "('a :: ocl_object_model) type\<^sub>N\<^sub>E env \<Rightarrow> 'a expr \<Rightarrow> 'a type\<^sub>N\<^sub>E \<Rightarrow> bool"
("(1_/ \<turnstile>\<^sub>E/ (_ :/ _))" [51,51,51] 50)
and collection_part_typing ("(1_/ \<turnstile>\<^sub>C/ (_ :/ _))" [51,51,51] 50)
and iterator_typing ("(1_/ \<turnstile>\<^sub>I/ (_ :/ _))" [51,51,51] 50)
and expr_list_typing ("(1_/ \<turnstile>\<^sub>L/ (_ :/ _))" [51,51,51] 50) where
\<comment> \<open>Primitive Literals\<close>
NullLiteralT:
"\<Gamma> \<turnstile>\<^sub>E NullLiteral : OclVoid[?]"
|BooleanLiteralT:
"\<Gamma> \<turnstile>\<^sub>E BooleanLiteral c : Boolean[1]"
|RealLiteralT:
"\<Gamma> \<turnstile>\<^sub>E RealLiteral c : Real[1]"
|IntegerLiteralT:
"\<Gamma> \<turnstile>\<^sub>E IntegerLiteral c : Integer[1]"
|UnlimitedNaturalLiteralT:
"\<Gamma> \<turnstile>\<^sub>E UnlimitedNaturalLiteral c : UnlimitedNatural[1]"
|StringLiteralT:
"\<Gamma> \<turnstile>\<^sub>E StringLiteral c : String[1]"
|EnumLiteralT:
"has_literal enm lit \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E EnumLiteral enm lit : (Enum enm)[1]"
\<comment> \<open>Tuple Literals\<close>
|TupleLiteralNilT:
"\<Gamma> \<turnstile>\<^sub>E TupleLiteral [] : (Tuple fmempty)[1]"
|TupleLiteralConsT:
"\<Gamma> \<turnstile>\<^sub>E tuple_literal_element_expr el : \<tau> \<Longrightarrow>
tuple_literal_element_type el = Some \<sigma> \<Longrightarrow>
\<tau> \<le> \<sigma> \<Longrightarrow>
\<rho> \<hookleftarrow> Tuple([tuple_literal_element_name el \<mapsto>\<^sub>f \<sigma>])[1] \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E TupleLiteral elems : \<upsilon> \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E TupleLiteral (el # elems) : \<rho> \<squnion> \<upsilon>"
\<comment> \<open>Collection Literals\<close>
|CollectionLiteralNilT:
"k \<noteq> CollectionKind \<Longrightarrow>
\<sigma> \<hookleftarrow> Collection\<^bsub>k\<^esub>(OclVoid[1])[1] \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E CollectionLiteral k [] : \<sigma>"
|CollectionLiteralConsT:
"k \<noteq> CollectionKind \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>C x : \<tau> \<Longrightarrow>
\<sigma> \<hookleftarrow> Collection\<^bsub>k\<^esub>(\<tau>)[1] \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E CollectionLiteral k xs : \<rho> \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E CollectionLiteral k (x # xs) : \<sigma> \<squnion> \<rho>"
|CollectionPartItemT:
"\<Gamma> \<turnstile>\<^sub>E a : \<tau> \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>C CollectionItem a : \<tau>"
|CollectionPartRangeT:
"\<Gamma> \<turnstile>\<^sub>E a : Integer[1] \<Longrightarrow> \<Gamma> \<turnstile>\<^sub>E b : Integer[1] \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>C CollectionRange a b : Integer[1]"
|LowerErrorableCollectionPartRangeT:
"\<Gamma> \<turnstile>\<^sub>E a : Integer[1!] \<Longrightarrow> \<Gamma> \<turnstile>\<^sub>E b : Integer[1] \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>C CollectionRange a b : Integer[1!]"
|UpperErrorableCollectionPartRangeT:
"\<Gamma> \<turnstile>\<^sub>E a : Integer[1] \<Longrightarrow> \<Gamma> \<turnstile>\<^sub>E b : Integer[1!] \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>C CollectionRange a b : Integer[1!]"
|ErrorableCollectionPartRangeT:
"\<Gamma> \<turnstile>\<^sub>E a : Integer[1!] \<Longrightarrow> \<Gamma> \<turnstile>\<^sub>E b : Integer[1!] \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>C CollectionRange a b : Integer[1!]"
\<comment> \<open>Map Literals\<close>
|MapNilT:
"\<tau> \<hookleftarrow> Map(OclVoid[1], OclVoid[1])[1] \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E MapLiteral [] : \<tau>"
|MapConsT:
"\<Gamma> \<turnstile>\<^sub>E map_literal_element_key x : \<tau> \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E map_literal_element_value x : \<sigma> \<Longrightarrow>
\<rho> \<hookleftarrow> Map(\<tau>, \<sigma>)[1] \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E MapLiteral xs : \<upsilon> \<Longrightarrow>
\<Gamma> \<turnstile>\<^sub>E MapLiteral (x # xs) : \<rho> \<squnion> \<upsilon>"
\<comment> \<open>Misc Expressions\<close>
|LetT: