Project

General

Profile

root / trunk / compiler / ooasCompiler / src / org / momut / ooas / ast / types / Type.java @ 10

1
/**
2
  *
3
  *                      OOAS Compiler
4
  *
5
  *       Copyright 2015, AIT Austrian Institute of Technology.
6
  * This code is based on the C# Version of the OOAS Compiler, which is
7
  * copyright 2015 by the Institute of Software Technology, Graz University
8
  * of Technology with portions copyright by the AIT Austrian Institute of
9
  * Technology. All rights reserved.
10
  *
11
  * SEE THE "LICENSE" FILE FOR THE TERMS UNDER WHICH THIS FILE IS PROVIDED.
12
  *
13
  * If you modify the file please update the list of contributors below to in-
14
  * clude your name. Please also stick to the coding convention of using TABs
15
  * to do the basic (block-level) indentation and spaces for anything after
16
  * that. (Enable the display of special chars and it should be pretty obvious
17
  * what this means.) Also, remove all trailing whitespace.
18
  *
19
  * Contributors:
20
  *               Willibald Krenn (AIT)
21
  *               Stephan Zimmerer (AIT)
22
  *               Markus Demetz (AIT)
23
  *               Christoph Czurda (AIT)
24
  *
25
  */
26

    
27

    
28
package org.momut.ooas.ast.types;
29

    
30
import java.util.Iterator;
31

    
32
import org.momut.ooas.ast.AstNode;
33
import org.momut.ooas.ast.AstNodeTypeEnum;
34
import org.momut.ooas.ast.IAst;
35
import org.momut.ooas.ast.IAstVisitor;
36
import org.momut.ooas.ast.identifiers.TypeIdentifier;
37
import org.momut.ooas.utils.exceptions.ArgumentException;
38
import org.momut.ooas.utils.exceptions.NotImplementedException;
39
import org.momut.ooas.utils.exceptions.OoasCompilerRuntimeException;
40

    
41
public abstract class Type extends AstNode implements IAst
42
{
43
        private String m_origAnonName;
44
        protected TypeKind m_kind;
45
        protected TypeIdentifier m_identifier;
46
        protected int m_hash;
47
        //    protected long TimeStamp = DateTime.Now.Ticks;
48

    
49

    
50
        public TypeKind kind() { return m_kind; }
51

    
52
        public TypeIdentifier identifier() {
53
                synchronized(this) {
54
                        if (m_identifier == null)
55
                                SetupAnonymousName();
56
                }
57
                return m_identifier;
58
        }
59

    
60
        public boolean isAnonymousType() {
61
                final String anonName = AnonymousName();
62
                if (!m_origAnonName.equals(anonName))
63
                        throw new OoasCompilerRuntimeException("Internal Error: Anonymous Name changed from '%s' to '%s'.", m_origAnonName, anonName);
64
                return anonName.equals(m_identifier.tokenText());
65
        }
66

    
67
        protected Type(TypeKind aKind, TypeIdentifier anIdentifier)
68
        {
69
                m_kind = aKind;
70
                m_identifier = anIdentifier;
71
                m_hash = aKind.toString().hashCode(); //Enum.GetName(typeof(TypeKind), aKind).GetHashCode();
72
        }
73

    
74
        @Override
75
        public String toString()
76
        {
77
                return identifier().tokenText();
78
        }
79

    
80
        public /*virtual*/ String AnonymousName()
81
        {
82
                throw new NotImplementedException();
83
        }
84

    
85

    
86
        public void SetTypeIdentifier(TypeIdentifier anId)
87
        {
88
                m_identifier = anId;
89
        }
90

    
91
        public void SetupAnonymousName()
92
        {
93
                if (m_identifier == null)
94
                {
95
                        final String anonymousName = this.AnonymousName();
96
                        m_identifier = new TypeIdentifier(anonymousName, this, null);
97
                        m_origAnonName = anonymousName;
98
                }
99
        }
100

    
101

    
102
        @Override
103
        public AstNodeTypeEnum nodeType() { return AstNodeTypeEnum.type; }
104

    
105
        @Override
106
        public void Accept(IAstVisitor visitor)
107
        {
108
                throw new NotImplementedException();
109
        }
110

    
111

    
112

    
113
        public boolean IsNumeric()
114
        {
115
                final Object o = this;
116
                return (m_kind == TypeKind.IntType) ||
117
                                (m_kind == TypeKind.FloatType) ||
118
                                (m_kind == TypeKind.EnumeratedType && o instanceof ValuedEnumType);
119
        }
120

    
121
        /**
122
         * returns the number of unique values of the type (2 for bool, etc..)
123
         */
124
        public int valueCount() {
125
                throw new NotImplementedException(); // must be overridden by child
126
        }
127

    
128
        public static String High(Type atype)
129
        {
130
                switch (atype.kind())
131
                {
132
                        case BoolType:
133
                                return "1";
134
                        case EnumeratedType:
135
                                return Integer.toString((((EnumType)atype).listOfEnumSymbols().size() - 1));
136
                        case IntType:
137
                                return Integer.toString(((IntType)atype).rangeHigh());
138
                        case FloatType:
139
                                return Double.toString(((FloatType)atype).high());
140
                        default:
141
                                throw new NotImplementedException();
142
                }
143
        }
144

    
145
        public static String Low(Type atype)
146
        {
147
                switch (atype.kind())
148
                {
149
                        case BoolType:
150
                                return "0";
151
                        case EnumeratedType:
152
                                return "0";
153
                        case IntType:
154
                                return Integer.toString(((IntType)atype).rangeLow());
155
                        case FloatType:
156
                                return Double.toString(((FloatType)atype).low());
157
//                        case TypeKind.QrType:
158
//                                return "0";
159
                        default:
160
                                throw new NotImplementedException();
161
                }
162
        }
163

    
164

    
165
        /// <summary>
166
        ///  Returns a cover for two types (if possible).
167
        ///  note the cover type for two ints, floats, etc. will have max/min values
168
        ///  that reflect the maximum of the two operands.
169
        /// </summary>
170

    
171
        public static Type CoverType(Type type1, Type type2)
172
        {
173
                /*first some sanity checks*/
174
                if (type1 == null)
175
                        throw new ArgumentException("type1 null");
176
                if (type2 == null)
177
                        throw new ArgumentException("type2 null");
178

    
179
                if (type1.kind() == TypeKind.OpaqueType)
180
                        throw new ArgumentException("type1 opaque type");
181
                if (type2.kind() == TypeKind.OpaqueType)
182
                        throw new ArgumentException("type2 opaque type");
183

    
184
                if (type1 == type2)
185
                        return type1;
186
                if (Type.TypeEqual(type1, type2))
187
                        return type1;
188

    
189
                final TypeKind tk1 = type1.kind();
190
                final TypeKind tk2 = type2.kind();
191

    
192

    
193

    
194
                if (tk1 != tk2)
195
                {
196
                        // the only notion we support here is int->float and valenum -> int
197
                        if ((tk1 == TypeKind.IntType || tk2 == TypeKind.IntType)
198
                                        && (tk1 == TypeKind.FloatType || tk2 == TypeKind.FloatType))
199
                        {
200
                                final IntType aInt = tk1 == TypeKind.IntType ? (IntType)type1 : (IntType)type2;
201
                                final FloatType aFloat = tk1 == TypeKind.IntType ? (FloatType)type2 : (FloatType)type1;
202

    
203
                                final double low = aInt.rangeLow() < aFloat.low() ? (double)aInt.rangeLow() : aFloat.low();
204
                                final double high = aInt.rangeHigh() < aFloat.high() ? aFloat.high() : (double)aInt.rangeHigh();
205
                                final double precision = aFloat.precision() > 1 ? 1.0 : aFloat.precision();
206

    
207
                                return new FloatType(low, high, precision, null);
208

    
209
                        }
210
                        else if ((tk1 == TypeKind.IntType || tk2 == TypeKind.IntType)
211
                                        && (tk1 == TypeKind.EnumeratedType || tk2 == TypeKind.EnumeratedType))
212
                        {
213
                                final IntType intt1 = tk1 == TypeKind.IntType ? (IntType)type1 : (IntType)type2;
214
                                final EnumType anEnum = tk1 == TypeKind.IntType ? (EnumType)type2 : (EnumType)type1;
215

    
216
                                if (anEnum instanceof ValuedEnumType)
217
                                {
218
                                        final IntType intt2 = ((ValuedEnumType)anEnum).getIntType();
219
                                        final int low = intt1.rangeLow() < intt2.rangeLow() ? intt1.rangeLow() : intt2.rangeLow();
220
                                        final int high = intt1.rangeHigh() > intt2.rangeHigh() ? intt1.rangeHigh() : intt2.rangeHigh();
221
                                        return new IntType(low, high, null);
222
                                }
223
                                else
224
                                        return null;
225
                        }
226
                        else if (tk1 == TypeKind.Any || tk2 == TypeKind.Any)
227
                        {
228
                                final AnyType freeVar = tk1 == TypeKind.Any ? (AnyType)type1 : (AnyType)type2;
229
                                final Type fixedType = tk1 == TypeKind.Any ? type2 : type1;
230
                                final Type newcover = freeVar.VariableIdentifier().type().kind() == TypeKind.Any
231
                                                ? fixedType : CoverType(fixedType, freeVar.VariableIdentifier().type());
232
                                freeVar.VariableIdentifier().SetType(newcover);
233
                                return newcover;
234
                        }
235
                        else if (tk1 == TypeKind.OoActionSystemType && tk2 == TypeKind.Null)
236
                        {
237
                                return type1;
238
                        }
239
                        else if (tk2 == TypeKind.OoActionSystemType && tk1 == TypeKind.Null)
240
                        {
241
                                return type2;
242
                        }
243

    
244
                        else
245
                                return null;
246
                }
247
                else
248
                {
249
                        switch (tk1)
250
                        {
251
                                case Any:
252
                                        return type1;
253

    
254
                                case IntType:
255
                                        final IntType intt1 = (IntType)type1;
256
                                        final IntType intt2 = (IntType)type2;
257
                                        final int low = intt1.rangeLow() < intt2.rangeLow() ? intt1.rangeLow() : intt2.rangeLow();
258
                                        final int high = intt1.rangeHigh() > intt2.rangeHigh() ? intt1.rangeHigh() : intt2.rangeHigh();
259
                                        return new IntType(low, high, null);
260
                                case BoolType:
261
                                        return type1;
262
                                case FloatType:
263
                                        final FloatType floatt1 = (FloatType)type1;
264
                                        final FloatType floatt2 = (FloatType)type2;
265
                                        final double flow = floatt1.low() < floatt2.low() ? floatt1.low() : floatt2.low();
266
                                        final double fhigh = floatt1.high() > floatt2.high() ? floatt1.high() : floatt2.high();
267
                                        final double fprec = floatt1.precision() < floatt2.precision() ? floatt1.precision() : floatt2.precision();
268
                                        return new FloatType(flow, fhigh, fprec, null);
269
                                case EnumeratedType:
270
                                        return null;
271
                                case ListType:
272
                                        final ListType listt1 = (ListType)type1;
273
                                        final ListType listt2 = (ListType)type2;
274
                                        // empty lists lack type, so take the other one
275
                                        if ((listt1.innerType().kind() == TypeKind.Null) && (listt2.innerType().kind() != TypeKind.Null))
276
                                                return listt2;
277
                                        else if ((listt2.innerType().kind() == TypeKind.Null) && (listt1.innerType().kind() != TypeKind.Null))
278
                                                return listt1;
279
                                        else if (listt1.innerType().kind() == TypeKind.Null && listt2.innerType().kind() == TypeKind.Null)
280
                                                return listt1;
281
                                        else
282
                                        {
283
                                                /**
284
                                                 * A cover type of a list must not change the size of the inner type. Mostly what is
285
                                                 * allowed to change is the list length.
286
                                                 */
287
                                                Type subtype = listt1.innerType();
288
                                                final boolean castAllowed = TypeEqual(listt1.innerType(), listt2.innerType())
289
                                                          || (    (listt1.innerType().kind() == TypeKind.OoActionSystemType)
290
                                                               && (subtype = Type.CoverType(listt1.innerType(), listt2.innerType())) != null);
291
                                                if (castAllowed){
292
                                                        final int maxelems = listt1.maxNumberOfElements() > listt2.maxNumberOfElements()
293
                                                                        ? listt1.maxNumberOfElements()
294
                                                                        : listt2.maxNumberOfElements();
295
                                                        return new ListType(subtype, maxelems, null);
296
                                                } else
297
                                                        return null;
298

    
299
//                                                // The code blow allowed for bit-size changes of the inner type and is considered too
300
//                                                // liberal. If a deep cast is necessary, the user might want to do a fold operation
301
//                                                // instead..
302
//                                                final Type subtype = Type.CoverType(listt1.innerType(), listt2.innerType());
303
//                                                if (subtype != null)
304
//                                                        return new ListType(subtype, maxelems, null);
305
//                                                else
306
//                                                        return null;
307
                                        }
308
                                case MapType:
309
                                        final MapType mapt1 = (MapType)type1;
310
                                        final MapType mapt2 = (MapType)type2;
311
                                        // empty maps lack type, so take the other one.
312
                                        if ((mapt1.fromType().kind() == TypeKind.Null && mapt1.toType().kind() == TypeKind.Null)
313
                                           && (mapt2.fromType().kind() != TypeKind.Null && mapt2.toType().kind() != TypeKind.Null))
314
                                                return mapt2;
315
                                        else if ((mapt2.fromType().kind() == TypeKind.Null && mapt2.toType().kind() == TypeKind.Null)
316
                                           && (mapt1.fromType().kind() != TypeKind.Null && mapt1.toType().kind() != TypeKind.Null))
317
                                                return mapt1;
318
                                        else if ((mapt2.fromType().kind() == TypeKind.Null && mapt2.toType().kind() == TypeKind.Null)
319
                                           && (mapt1.fromType().kind() == TypeKind.Null && mapt1.toType().kind() == TypeKind.Null))
320
                                                return mapt1;
321
                                        else
322
                                        {
323
                                                final Type sub1 = Type.CoverType(mapt1.fromType(), mapt2.fromType());
324
                                                final Type sub2 = Type.CoverType(mapt2.toType(), mapt2.toType());
325
                                                final int maxelems = mapt1.maxNumberOfElements() > mapt2.maxNumberOfElements() ?
326
                                                        mapt1.maxNumberOfElements() : mapt2.maxNumberOfElements();
327
                                                if (sub1 != null && sub2 != null)
328
                                                        return new MapType(sub1, sub2, maxelems, null);
329
                                                else
330
                                                        return null;
331
                                        }
332
                                case TupleType:
333
                                        final TupleType tuplet1 = (TupleType)type1;
334
                                        final TupleType tuplet2 = (TupleType)type2;
335
                                        final TupleType result = new TupleType(null);
336
                                        final Iterator<Type> innert1 = tuplet1.innerTypes().iterator();
337
                                        final Iterator<Type> innert2 = tuplet2.innerTypes().iterator();
338
                                        while (innert1.hasNext())
339
                                        {
340
                                                final Type newinner = Type.CoverType(innert1.next(), innert2.next());
341
                                                if (newinner == null)
342
                                                        return null;
343
                                                result.AddType(newinner);
344
                                        }
345
                                        return result;
346
                                case OoActionSystemType:
347
                                        if (type1.kind() == TypeKind.Null && type2.kind() != TypeKind.Null)
348
                                                return type2;
349
                                        else if (type2.kind() == TypeKind.Null && type1.kind() != TypeKind.Null)
350
                                                return type1;
351
                                        else if (type1.kind() == TypeKind.Null && type2.kind() == TypeKind.Null)
352
                                                return type2;
353
                                        else if (type1 == type2) // ref equals!
354
                                                return type1;
355
                                        else
356
                                                return ClassBaseType((OoActionSystemType)type1, (OoActionSystemType)type2);
357
                                case OpaqueType:
358
                                        assert(false);
359
                                        return null;
360
                                default:
361
                                        throw new NotImplementedException();
362
                        }
363
                }
364
        }
365

    
366
        private static Type ClassBaseType(OoActionSystemType type1, OoActionSystemType type2)
367
        {
368
                // this is rather inefficient.. should be done differently
369
                final OoActionSystemType typea = type1;
370
                final OoActionSystemType typeb = type2;
371
                OoActionSystemType basea = type1;
372
                OoActionSystemType baseb = type2;
373
                while (basea != null)
374
                {
375
                        if (basea == typeb)  // ref equals
376
                                return basea;
377
                        basea = basea.baseType();
378
                }
379
                while (baseb != null)
380
                {
381
                        if (baseb == typea) // ref equals
382
                                return baseb;
383
                        baseb = baseb.baseType();
384
                }
385
                return null;
386
        }
387

    
388
        public static boolean FirstTypeLessRange(Type type1, Type type2)
389
        {
390
                final TypeKind tk1 = type1.kind();
391
                final TypeKind tk2 = type2.kind();
392

    
393
                if (tk1 != tk2)
394
                        throw new ArgumentException("Types need to be equal");
395

    
396
                switch (tk1)
397
                {
398
                        case Any:
399
                                return false;
400
                        case IntType:
401
                                final IntType Int1 = (IntType)type1;
402
                                final IntType Int2 = (IntType)type2;
403
                                return Int1.rangeLow() > Int2.rangeLow() ||
404
                                        Int1.rangeHigh() < Int2.rangeHigh();
405
                        case BoolType:
406
                                return false;
407
                        case FloatType:
408
                                final FloatType Float1 = (FloatType)type1;
409
                                final FloatType Float2 = (FloatType)type2;
410
                                return Float1.low() > Float2.low()
411
                                        || Float1.high() < Float2.high()
412
                                        || Float1.precision() > Float2.precision();
413
                        case EnumeratedType:
414
                                return false;
415
                        case ListType:
416
                                final ListType listt1 = (ListType)type1;
417
                                final ListType listt2 = (ListType)type2;
418
                                return (listt1.maxNumberOfElements() < listt2.maxNumberOfElements()) ||
419
                                        Type.FirstTypeLessRange(listt1.innerType(), listt2.innerType());
420
                        case MapType:
421
                                final MapType mapt1 = (MapType)type1;
422
                                final MapType mapt2 = (MapType)type2;
423
                                return (mapt1.maxNumberOfElements() < mapt2.maxNumberOfElements()) ||
424
                                        Type.FirstTypeLessRange(mapt1.fromType(), mapt2.fromType()) ||
425
                                        Type.FirstTypeLessRange(mapt1.toType(), mapt2.toType());
426
                        case TupleType:
427
                                final TupleType tuplet1 = (TupleType)type1;
428
                                final TupleType tuplet2 = (TupleType)type2;
429
                                if (tuplet1.innerTypes().size() != tuplet2.innerTypes().size())
430
                                        return false;
431
                                final Iterator<Type> innert1 = tuplet1.innerTypes().iterator();
432
                                final Iterator<Type> innert2 = tuplet2.innerTypes().iterator();
433
                                while (innert1.hasNext())
434
                                {
435
                                        if (Type.FirstTypeLessRange(innert1.next(), innert2.next()))
436
                                                return true;
437
                                }
438
                                return false;
439
                        case OoActionSystemType:
440
                                return false;
441
                        case OpaqueType:
442
                                assert(false);
443
                                return false;
444
                        default:
445
                                throw new NotImplementedException();
446
                }
447
        }
448

    
449
        public static boolean TypeEqualByKind(Type type1, Type type2)
450
        {
451
                if ((type1 == null) || (type2 == null))
452
                        return false;
453

    
454
                final TypeKind tk1 = type1.kind();
455
                final TypeKind tk2 = type2.kind();
456

    
457
                // if of different kind, then return false..
458
                if (tk1 != tk2)
459
                        return false;
460

    
461
                // if same kind, make a rigorous check
462
                switch (tk1)
463
                {
464
                        case Any:
465
                                return true;
466

    
467
                        case IntType:
468
                        case BoolType:
469
                        case FloatType:
470
                                return true;
471
                        case EnumeratedType:
472
                                return type1 == type2; // ref equals
473
                        case ListType:
474
                                final ListType listt1 = (ListType)type1;
475
                                final ListType listt2 = (ListType)type2;
476
                                return Type.TypeEqualByKind(listt1.innerType(), listt2.innerType());
477
                        case MapType:
478
                                final MapType mapt1 = (MapType)type1;
479
                                final MapType mapt2 = (MapType)type2;
480
                                return Type.TypeEqualByKind(mapt1.fromType(), mapt2.fromType()) &&
481
                                        Type.TypeEqualByKind(mapt1.toType(), mapt2.toType());
482
                        case TupleType:
483
                                final TupleType tuplet1 = (TupleType)type1;
484
                                final TupleType tuplet2 = (TupleType)type2;
485
                                if (tuplet1.innerTypes().size() != tuplet2.innerTypes().size())
486
                                        return false;
487
                                final Iterator<Type> innert1 = tuplet1.innerTypes().iterator();
488
                                final Iterator<Type> innert2 = tuplet2.innerTypes().iterator();
489
                                while (innert1.hasNext())
490
                                {
491
                                        if (!Type.TypeEqualByKind(innert1.next(), innert2.next()))
492
                                                return false;
493
                                }
494
                                return true;
495
                        case OoActionSystemType:
496
                                return type1 == type2; // ref equ.
497
                        case OpaqueType:
498
                                assert(false);
499
                                return false;
500
                        default:
501
                                throw new NotImplementedException();
502
                }
503
        }
504

    
505

    
506
        public static boolean TypeEqual(Type type1, Type type2)
507
        {
508
                // this will also work with opaque types...
509
                while (type1 instanceof OpaqueType)
510
                        type1 = ((OpaqueType)type1).resolvedType();
511
                while (type2 instanceof OpaqueType)
512
                        type2 = ((OpaqueType)type2).resolvedType();
513

    
514
                if ((type1 == null) || (type2 == null))
515
                        return false;
516

    
517
                final TypeKind tk1 = type1.kind();
518
                final TypeKind tk2 = type2.kind();
519

    
520
                // if of different kind, then return false..
521
                if (tk1 != tk2)
522
                        return false;
523

    
524
                // if same kind, make a rigorous check
525
                switch (tk1)
526
                {
527
                        case IntType:
528
                                final IntType intt1 = (IntType)type1;
529
                                final IntType intt2 = (IntType)type2;
530
                                return intt1.rangeLow() == intt2.rangeLow() &&
531
                                        intt1.rangeHigh() == intt2.rangeHigh();
532
                        case BoolType:
533
                                return true;
534
                        case FloatType:
535
                                final FloatType floatt1 = (FloatType)type1;
536
                                final FloatType floatt2 = (FloatType)type2;
537
                                return floatt1.low() == floatt2.low() &&
538
                                        floatt1.high() == floatt2.high() &&
539
                                        floatt1.precision() == floatt2.precision();
540
                        case EnumeratedType:
541
                                return type1 == type2; // ref equ
542
                        case ListType:
543
                                final ListType listt1 = (ListType)type1;
544
                                final ListType listt2 = (ListType)type2;
545
                                // an empty list can be of any type..
546
                                /*if ((listt1.innerType.kind == TypeKind.Null) || (listt2.innerType.kind == TypeKind.Null))
547
                                        return true;
548
                                else*/
549
                                return Type.TypeEqual(listt1.innerType(), listt2.innerType()) &&
550
                                                listt1.maxNumberOfElements() == listt2.maxNumberOfElements(); // need this because of covertype
551
                        case MapType:
552
                                final MapType mapt1 = (MapType)type1;
553
                                final MapType mapt2 = (MapType)type2;
554
                                return Type.TypeEqual(mapt1.fromType(), mapt2.fromType()) &&
555
                                        Type.TypeEqual(mapt1.toType(), mapt2.toType()) &&
556
                                        mapt1.maxNumberOfElements() == mapt2.maxNumberOfElements(); // need this because of covertype
557
                        case TupleType:
558
                                final TupleType tuplet1 = (TupleType)type1;
559
                                final TupleType tuplet2 = (TupleType)type2;
560
                                if (tuplet1.innerTypes().size() != tuplet2.innerTypes().size())
561
                                        return false;
562
                                final Iterator<Type> innert1 = tuplet1.innerTypes().iterator();
563
                                final Iterator<Type> innert2 = tuplet2.innerTypes().iterator();
564
                                while (innert1.hasNext())
565
                                {
566
                                        if (!Type.TypeEqual(innert1.next(), innert2.next()))
567
                                                return false;
568
                                }
569
                                return true;
570
                        case OoActionSystemType:
571
                                return type1 == type2; // ref equ. // || Covariance((OoActionSystemType)type1, (OoActionSystemType)type2);
572
                        case OpaqueType:
573
                                assert(false);
574
                                return false;
575
                        case Null:
576
                        case Any:
577
                                return true;
578
                        default:
579
                                throw new NotImplementedException();
580
                }
581
        }
582

    
583
        /// <summary>
584
        /// checks if type 2 is a desc. of type 1
585
        /// </summary>
586
        public static boolean Covariance(OoActionSystemType ooActionSystemType, OoActionSystemType ooActionSystemType_2)
587
        {
588
                // check if type 2 is a desc. of type 1
589
                while (ooActionSystemType != ooActionSystemType_2 && ooActionSystemType_2.baseType() != null) // ref equ.
590
                        ooActionSystemType_2 = ooActionSystemType_2.baseType();
591

    
592
                return ooActionSystemType == ooActionSystemType_2; // ref equ.
593
        }
594
}