0c0df556007f8eee3fb81746fe5910452509acf2
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Metadata / TypeSemantics.cs
1 //---------------------------------------------------------------------
2 // <copyright file="TypeSemantics.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9
10 using System.Collections.Generic;
11 using System.Data.Common;
12 using System.Linq;
13 using System.Diagnostics;
14 using objectModel = System.Collections.ObjectModel;
15
16 namespace System.Data.Metadata.Edm
17 {
18     /// <summary>
19     /// Provides type semantics service, type operations and type predicates for the EDM type system.
20     /// </summary>
21     /// <remarks>
22     /// For detailed functional specification, see "The EDP Type System.docx" and "edm.spec.doc".
23     /// Notes:
24     /// 1) The notion of 'type' for the sake of type operation semantics is based on TypeUsage, i.e., EdmType *plus* facets.
25     /// 
26     /// 2) EDM built-in primitive types are defined by the EDM Provider Manifest.
27     /// 
28     /// 3) SubType and Promotable are similar notions however subtyping is stricter than promotability. Subtyping is used for mapping 
29     ///    validation while Promotability is used in query, update expression static type validation.
30     /// </remarks>
31     internal static class TypeSemantics
32     {
33         #region Fields
34         //
35         // cache commom super type closure
36         //
37         static private objectModel.ReadOnlyCollection<PrimitiveType>[,] _commonTypeClosure;
38         #endregion
39
40         //
41         // 'Public' Interface
42         //
43         #region 'Public' Interface
44
45         /// <summary>
46         /// Determines whether two types are exactly equal.
47         /// For row types, this INCLUDES property names as well as property types.
48         /// </summary>
49         /// <param name="type1">The first type to compare.</param>
50         /// <param name="type2">The second type to compare.</param>
51         /// <returns>If the two types are structurally equal, <c>true</c>; otherwise <c>false</c>.</returns>
52         internal static bool IsEqual(TypeUsage type1, TypeUsage type2)
53         {
54             return CompareTypes(type1, type2, false /*equivalenceOnly*/);
55         }
56
57         /// <summary>
58         /// Determines if the two types are structurally equivalent.
59         /// </summary>
60         /// <param name="fromType"></param>
61         /// <param name="toType"></param>
62         /// <remarks>
63         /// Equivalence for nomimal types is based on lexical identity and structural equivalence for structural types.
64         /// Structural equivalence for row types is based only on equivalence of property types, property names are ignored.
65         /// </remarks>
66         /// <returns>true if equivalent, false otherwise</returns>
67         internal static bool IsStructurallyEqual(TypeUsage fromType, TypeUsage toType)
68         {
69             return CompareTypes(fromType, toType, true /*equivalenceOnly*/);
70         }
71
72         /// <summary>
73         /// determines if two types are equivalent or if fromType is promotable to toType 
74         /// </summary>
75         /// <param name="fromType"></param>
76         /// <param name="toType"></param>
77         /// <returns>true if fromType equivalent or promotable to toType, false otherwise</returns>
78         internal static bool IsStructurallyEqualOrPromotableTo(TypeUsage fromType, TypeUsage toType)
79         {
80             return IsStructurallyEqual(fromType, toType) ||
81                    IsPromotableTo(fromType, toType);
82         }
83
84         /// <summary>
85         /// determines if two types are equivalent or if fromType is promotable to toType 
86         /// </summary>
87         /// <param name="fromType"></param>
88         /// <param name="toType"></param>
89         /// <returns>true if fromType equivalent or promotable to toType, false otherwise</returns>
90         internal static bool IsStructurallyEqualOrPromotableTo(EdmType fromType, EdmType toType)
91         {
92             return IsStructurallyEqualOrPromotableTo(TypeUsage.Create(fromType), TypeUsage.Create(toType));
93         }
94
95         /// <summary>
96         /// determines if subType is equal to or a sub-type of superType.
97         /// </summary>
98         /// <param name="subType"></param>
99         /// <param name="superType"></param>
100         /// <returns>true if subType is equal to or a sub-type of superType, false otherwise</returns>
101         internal static bool IsSubTypeOf(TypeUsage subType, TypeUsage superType)
102         {
103             Debug.Assert(subType != null, "subType must not be NULL");
104             Debug.Assert(superType != null, "superType must not be NULL");
105
106             if (subType.EdmEquals(superType))
107             {
108                 return true;
109             }
110
111             if (Helper.IsPrimitiveType(subType.EdmType) && Helper.IsPrimitiveType(superType.EdmType))
112             {
113                 return IsPrimitiveTypeSubTypeOf(subType, superType);
114             }
115
116             return subType.IsSubtypeOf(superType);
117         }
118
119         /// <summary>
120         /// determines if subType EdmType is a sub-type of superType EdmType.
121         /// </summary>
122         /// <param name="subEdmType"></param>
123         /// <param name="superEdmType"></param>
124         /// <returns>true if subType is a sub-type of superType, false otherwise</returns>
125         internal static bool IsSubTypeOf(EdmType subEdmType, EdmType superEdmType)
126         {
127             return subEdmType.IsSubtypeOf(superEdmType);
128         }
129
130         /// <summary>
131         /// Determines if fromType is promotable to toType.
132         /// </summary>
133         /// <param name="fromType"></param>
134         /// <param name="toType"></param>
135         /// <returns>true if fromType is promotable to toType, false otherwise</returns>
136         internal static bool IsPromotableTo(TypeUsage fromType, TypeUsage toType)
137         {
138             Debug.Assert(fromType != null, "fromType must not be NULL");
139             Debug.Assert(toType != null, "toType must not be NULL");
140
141             if (toType.EdmType.EdmEquals(fromType.EdmType))
142             {
143                 return true;
144             }
145
146             if (Helper.IsPrimitiveType(fromType.EdmType) && Helper.IsPrimitiveType(toType.EdmType))
147             {
148                 return IsPrimitiveTypePromotableTo(fromType,
149                                                    toType);
150             }
151             else if (Helper.IsCollectionType(fromType.EdmType) && Helper.IsCollectionType(toType.EdmType))
152             {
153                 return IsPromotableTo(TypeHelpers.GetElementTypeUsage(fromType),
154                                       TypeHelpers.GetElementTypeUsage(toType));
155             }
156             else if (Helper.IsEntityTypeBase(fromType.EdmType) && Helper.IsEntityTypeBase(toType.EdmType))
157             {
158                 return fromType.EdmType.IsSubtypeOf(toType.EdmType);
159             }
160             else if (Helper.IsRefType(fromType.EdmType) && Helper.IsRefType(toType.EdmType))
161             {
162                 return IsPromotableTo(TypeHelpers.GetElementTypeUsage(fromType),
163                                       TypeHelpers.GetElementTypeUsage(toType));
164             }
165             else if (Helper.IsRowType(fromType.EdmType) && Helper.IsRowType(toType.EdmType))
166             {
167                 return IsPromotableTo((RowType)fromType.EdmType,
168                                       (RowType)toType.EdmType);
169             }
170
171             return false;
172         }
173
174         /// <summary>
175         /// Flattens composite transient type down to nominal type leafs.
176         /// </summary>
177         internal static IEnumerable<TypeUsage> FlattenType(TypeUsage type)
178         {
179             Func<TypeUsage, bool> isLeaf = t => !Helper.IsTransientType(t.EdmType);
180
181             Func<TypeUsage, IEnumerable<TypeUsage>> getImmediateSubNodes = 
182                 t =>
183                 {
184                     if (Helper.IsCollectionType(t.EdmType) || Helper.IsRefType(t.EdmType))
185                     {
186                         return new[] { TypeHelpers.GetElementTypeUsage(t) };
187                     }
188                     else if (Helper.IsRowType(t.EdmType))
189                     {
190                         return ((RowType)t.EdmType).Properties.Select(p => p.TypeUsage);
191                     }
192                     else
193                     {
194                         Debug.Fail("cannot enumerate subnodes of a leaf node");
195                         return new TypeUsage[] { };
196                     }
197                 };
198
199             return Common.Utils.Helpers.GetLeafNodes<TypeUsage>(type, isLeaf, getImmediateSubNodes);
200         }
201
202         /// <summary>
203         /// determines if fromType can be casted to toType.
204         /// </summary>
205         /// <param name="fromType">Type to cast from.</param>
206         /// <param name="toType">Type to cast to.</param>
207         /// <returns><c>true</c> if <paramref name="fromType"/> can be casted to <paramref name="toType" />; <c>false</c> otherwise.</returns>
208         /// <remarks>
209         /// Cast rules:
210         /// - primitive types can be casted to other primitive types
211         /// - primitive types can be casted to enum types
212         /// - enum types can be casted to primitive types
213         /// - enum types cannot be casted to other enum types except for casting to the same type
214         /// </remarks>
215         internal static bool IsCastAllowed(TypeUsage fromType, TypeUsage toType)
216         {
217             Debug.Assert(fromType != null, "fromType != null");
218             Debug.Assert(toType != null, "toType != null");
219
220             return
221                 (Helper.IsPrimitiveType(fromType.EdmType) && Helper.IsPrimitiveType(toType.EdmType)) ||
222                 (Helper.IsPrimitiveType(fromType.EdmType) && Helper.IsEnumType(toType.EdmType)) ||
223                 (Helper.IsEnumType(fromType.EdmType) && Helper.IsPrimitiveType(toType.EdmType)) ||
224                 (Helper.IsEnumType(fromType.EdmType) && Helper.IsEnumType(toType.EdmType) && fromType.EdmType.Equals(toType.EdmType));
225         }
226
227         /// <summary>
228         /// Determines if a common super type (LUB) exists between type1 and type2.
229         /// </summary>
230         /// <param name="type1"></param>
231         /// <param name="type2"></param>
232         /// <param name="commonType"></param>
233         /// <returns>
234         /// true if a common super type between type1 and type2 exists and out commonType represents the common super type.
235         /// false otherwise along with commonType as null
236         /// </returns>
237         internal static bool TryGetCommonType(TypeUsage type1, TypeUsage type2, out TypeUsage commonType)
238         {
239             Debug.Assert(type1 != null, "type1 must not be NULL");
240             Debug.Assert(type2 != null, "type2 must not be NULL");
241
242             commonType = null;
243
244             if (type1.EdmEquals(type2))
245             {
246                 commonType = ForgetConstraints(type2);
247                 return true;
248             }
249
250             if (Helper.IsPrimitiveType(type1.EdmType) && Helper.IsPrimitiveType(type2.EdmType))
251             {
252                 return TryGetCommonPrimitiveType(type1, type2, out commonType);
253             }
254
255             EdmType commonEdmType;
256             if (TryGetCommonType(type1.EdmType, type2.EdmType, out commonEdmType))
257             {
258                 commonType = ForgetConstraints(TypeUsage.Create(commonEdmType));
259                 return true;
260             }
261
262             commonType = null;
263             return false;
264         }
265
266         /// <summary>
267         /// Gets a Common super-type of type1 and type2 if one exists. null otherwise.
268         /// </summary>
269         /// <param name="type1"></param>
270         /// <param name="type2"></param>
271         /// <returns></returns>
272         internal static TypeUsage GetCommonType(TypeUsage type1, TypeUsage type2)
273         {
274             TypeUsage commonType = null;
275             if (TypeSemantics.TryGetCommonType(type1, type2, out commonType))
276             {
277                 return commonType;
278             }
279             return null;
280         }
281
282         /// <summary>
283         /// determines if an EdmFunction is an aggregate function
284         /// </summary>
285         /// <param name="function"></param>
286         /// <returns></returns>
287         internal static bool IsAggregateFunction(EdmFunction function)
288         {
289             return function.AggregateAttribute;
290         }
291
292         /// <summary>
293         /// determines if fromType can be cast to toType. this operation is valid only
294         /// if fromtype and totype are polimorphic types.
295         /// </summary>
296         /// <param name="fromType"></param>
297         /// <param name="toType"></param>
298         /// <returns></returns>
299         internal static bool IsValidPolymorphicCast(TypeUsage fromType, TypeUsage toType)
300         {
301             if (!IsPolymorphicType(fromType) || !IsPolymorphicType(toType))
302             {
303                 return false;
304             }
305             return (IsStructurallyEqual(fromType, toType) || IsSubTypeOf(fromType, toType) || IsSubTypeOf(toType, fromType));
306         }
307
308         /// <summary>
309         /// determines if fromEdmType can be cast to toEdmType. this operation is valid only
310         /// if fromtype and totype are polimorphic types.
311         /// </summary>
312         /// <param name="fromType"></param>
313         /// <param name="toType"></param>
314         /// <returns></returns>
315         internal static bool IsValidPolymorphicCast(EdmType fromEdmType, EdmType toEdmType)
316         {
317             return IsValidPolymorphicCast(TypeUsage.Create(fromEdmType), TypeUsage.Create(toEdmType));
318         }
319
320         /// <summary>
321         /// Determines if the <param ref="type" /> is a structural nominal type, i.e., EntityType or ComplexType
322         /// </summary>
323         /// <param name="type">Type to be checked.</param>
324         /// <returns><c>true</c> if the <param ref="type" /> is a nominal type. <c>false</c> otherwise.</returns>
325         static internal bool IsNominalType(TypeUsage type)
326         {
327             Debug.Assert(!IsEnumerationType(type), "Implicit cast/Softcast is not allowed for enums so we should never see enum type here.");
328
329             return IsEntityType(type) || IsComplexType(type);
330         }
331
332         /// <summary>
333         /// determines if type is a collection type.
334         /// </summary>
335         /// <param name="type"></param>
336         /// <returns></returns>
337         internal static bool IsCollectionType(TypeUsage type)
338         {
339             return Helper.IsCollectionType(type.EdmType);
340         }
341
342         /// <summary>
343         /// determines if type is a complex type.
344         /// </summary>
345         /// <param name="type"></param>
346         /// <returns></returns>
347         internal static bool IsComplexType(TypeUsage type)
348         {
349             return (BuiltInTypeKind.ComplexType == type.EdmType.BuiltInTypeKind);
350         }
351
352         /// <summary>
353         /// determines if type is an EntityType
354         /// </summary>
355         /// <param name="type"></param>
356         /// <returns></returns>
357         internal static bool IsEntityType(TypeUsage type)
358         {
359             return Helper.IsEntityType(type.EdmType);
360         }
361
362         /// <summary>
363         /// determines if type is a Relationship Type.
364         /// </summary>
365         /// <param name="type"></param>
366         /// <returns></returns>
367         internal static bool IsRelationshipType(TypeUsage type)
368         {
369             return (BuiltInTypeKind.AssociationType == type.EdmType.BuiltInTypeKind);
370         }
371
372         /// <summary>
373         /// determines if type is of EnumerationType.
374         /// </summary>
375         /// <param name="type"></param>
376         /// <returns></returns>
377         internal static bool IsEnumerationType(TypeUsage type)
378         {
379             Debug.Assert(type != null, "type != null");
380
381             return Helper.IsEnumType(type.EdmType);
382         }
383
384         /// <summary>
385         /// determines if <paramref name="type"/> is primitive or enumeration type
386         /// </summary>
387         /// <param name="type">Type to verify.</param>
388         /// <returns><c>true</c> if <paramref name="type"/> is primitive or enumeration type. <c>false</c> otherwise.</returns>
389         internal static bool IsScalarType(TypeUsage type)
390         {
391             return IsScalarType(type.EdmType);
392         }
393
394         /// <summary>
395         /// determines if <paramref name="type"/> is primitive or enumeration type
396         /// </summary>
397         /// <param name="type">Type to verify.</param>
398         /// <returns><c>true</c> if <paramref name="type"/> is primitive or enumeration type. <c>false</c> otherwise.</returns>
399         internal static bool IsScalarType(EdmType type)
400         {
401             Debug.Assert(type != null, "type != null");
402
403             return Helper.IsPrimitiveType(type) || Helper.IsEnumType(type);
404         }
405
406         /// <summary>
407         /// Determines if type is a numeric type, i.e., is one of:
408         /// Byte, Int16, Int32, Int64, Decimal, Single or Double
409         /// </summary>
410         /// <param name="type"></param>
411         /// <returns></returns>
412         internal static bool IsNumericType(TypeUsage type)
413         {
414             return (IsIntegerNumericType(type) || IsFixedPointNumericType(type) || IsFloatPointNumericType(type));
415         }
416
417         /// <summary>
418         /// Determines if type is an integer numeric type, i.e., is one of: Byte, Int16, Int32, Int64
419         /// </summary>
420         /// <param name="type"></param>
421         /// <returns></returns>
422         internal static bool IsIntegerNumericType(TypeUsage type)
423         {
424             PrimitiveTypeKind typeKind;
425             if (TypeHelpers.TryGetPrimitiveTypeKind(type, out typeKind))
426             {
427                 switch (typeKind)
428                 {
429                     case PrimitiveTypeKind.Byte:
430                     case PrimitiveTypeKind.Int16:
431                     case PrimitiveTypeKind.Int32:
432                     case PrimitiveTypeKind.Int64:
433                     case PrimitiveTypeKind.SByte:
434                         return true;
435
436                     default:
437                         return false;
438                 }
439             }
440             return false;
441         }
442
443         /// <summary>
444         /// Determines if type is an fixed point numeric type, i.e., is one of: Decimal
445         /// </summary>
446         /// <param name="type"></param>
447         /// <returns></returns>
448         internal static bool IsFixedPointNumericType(TypeUsage type)
449         {
450             PrimitiveTypeKind typeKind;
451             if (TypeHelpers.TryGetPrimitiveTypeKind(type, out typeKind))
452             {
453                 return (typeKind == PrimitiveTypeKind.Decimal);
454             }
455
456             return false;
457         }
458
459         /// <summary>
460         /// Determines if type is an float point numeric type, i.e., is one of: Single or Double.
461         /// </summary>
462         /// <param name="type"></param>
463         /// <returns></returns>
464         internal static bool IsFloatPointNumericType(TypeUsage type)
465         {
466             PrimitiveTypeKind typeKind;
467             if (TypeHelpers.TryGetPrimitiveTypeKind(type, out typeKind))
468             {
469                 return (typeKind == PrimitiveTypeKind.Double || typeKind == PrimitiveTypeKind.Single);
470             }
471             return false;
472         }
473
474         /// <summary>
475         /// Determines if type is an unsigned integer numeric type, i.e., is Byte
476         /// </summary>
477         /// <param name="type"></param>
478         /// <returns></returns>
479         internal static bool IsUnsignedNumericType(TypeUsage type)
480         {
481             PrimitiveTypeKind typeKind;
482             if (TypeHelpers.TryGetPrimitiveTypeKind(type, out typeKind))
483             {
484                 switch (typeKind)
485                 {
486                     case PrimitiveTypeKind.Byte:
487                         return true;
488
489                     default:
490                         return false;
491                 }
492             }
493             return false;
494         }
495
496         /// <summary>
497         /// determines if type is a polimorphic type, ie, EntityType or ComplexType.
498         /// </summary>
499         /// <param name="type"></param>
500         /// <returns></returns>
501         internal static bool IsPolymorphicType(TypeUsage type)
502         {
503             return (IsEntityType(type) || IsComplexType(type));
504         }
505
506         /// <summary>
507         /// determines if type is of Boolean Kind
508         /// </summary>
509         /// <param name="type"></param>
510         /// <returns></returns>
511         internal static bool IsBooleanType(TypeUsage type)
512         {
513             return TypeSemantics.IsPrimitiveType(type, PrimitiveTypeKind.Boolean);
514         }
515
516         /// <summary>
517         /// determines if type is a primitive/scalar type.
518         /// </summary>
519         /// <param name="type"></param>
520         /// <returns></returns>
521         internal static bool IsPrimitiveType(TypeUsage type)
522         {
523             return Helper.IsPrimitiveType(type.EdmType);
524         }
525
526         /// <summary>
527         /// determines if type is a primitive type of given primitiveTypeKind
528         /// </summary>
529         /// <param name="type"></param>
530         /// <param name="primitiveType"></param>
531         /// <returns></returns>
532         internal static bool IsPrimitiveType(TypeUsage type, PrimitiveTypeKind primitiveTypeKind)
533         {
534             PrimitiveTypeKind typeKind;
535             if (TypeHelpers.TryGetPrimitiveTypeKind(type, out typeKind))
536             {
537                 return (typeKind == primitiveTypeKind);
538             }
539             return false;
540         }
541
542         /// <summary>
543         /// determines if type is a RowType
544         /// </summary>
545         /// <param name="type"></param>
546         /// <returns></returns>
547         internal static bool IsRowType(TypeUsage type)
548         {
549             return Helper.IsRowType(type.EdmType);
550         }
551
552         /// <summary>
553         /// determines if type is a ReferenceType
554         /// </summary>
555         /// <param name="type"></param>
556         /// <returns></returns>
557         internal static bool IsReferenceType(TypeUsage type)
558         {
559             return Helper.IsRefType(type.EdmType);
560         }
561
562         /// <summary>
563         /// determines if type is a spatial type
564         /// </summary>
565         /// <param name="type"></param>
566         /// <returns></returns>
567         internal static bool IsSpatialType(TypeUsage type)
568         {
569             return Helper.IsSpatialType(type);
570         }
571
572         /// <summary>
573         /// determines if type is a strong spatial type (i.e., a spatial type, but not one of the two spatial union types)
574         /// </summary>
575         /// <param name="type"></param>
576         /// <returns></returns>
577         internal static bool IsStrongSpatialType(TypeUsage type)
578         {
579             return IsPrimitiveType(type) && Helper.IsStrongSpatialTypeKind(((PrimitiveType)type.EdmType).PrimitiveTypeKind);
580         }
581
582         /// <summary>
583         /// determines if type is a structural type, ie, EntityType, ComplexType, RowType or ReferenceType.
584         /// </summary>
585         /// <param name="type"></param>
586         /// <returns></returns>
587         internal static bool IsStructuralType(TypeUsage type)
588         {
589             return Helper.IsStructuralType(type.EdmType);
590         }
591
592         /// <summary>
593         /// determines if edmMember is part of the key of it's defining type.
594         /// </summary>
595         /// <param name="member"></param>
596         /// <returns></returns>
597         internal static bool IsPartOfKey(EdmMember edmMember)
598         {
599             if (Helper.IsRelationshipEndMember(edmMember))
600             {
601                 return ((RelationshipType)edmMember.DeclaringType).KeyMembers.Contains(edmMember);
602             }
603
604             if (!Helper.IsEdmProperty(edmMember))
605             {
606                 return false;
607             }
608
609             if (Helper.IsEntityTypeBase(edmMember.DeclaringType))
610             {
611                 return ((EntityTypeBase)edmMember.DeclaringType).KeyMembers.Contains(edmMember);
612             }
613
614             return false;
615         }
616
617         /// <summary>
618         /// determines if type is Nullable.
619         /// </summary>
620         /// <param name="type"></param>
621         /// <returns></returns>
622         internal static bool IsNullable(TypeUsage type)
623         {
624             Facet nullableFacet;
625             if (type.Facets.TryGetValue(EdmProviderManifest.NullableFacetName, false, out nullableFacet))
626             {
627                 return (bool)nullableFacet.Value;
628             }
629             return true;
630         }
631
632         /// <summary>
633         /// determines if edmMember is Nullable.
634         /// </summary>
635         /// <param name="edmMember"></param>
636         /// <returns></returns>
637         internal static bool IsNullable(EdmMember edmMember)
638         {
639             return IsNullable(edmMember.TypeUsage);
640         }
641
642         /// <summary>
643         /// determines if given type is equal-comparable.
644         /// </summary>
645         /// <param name="type"></param>
646         /// <returns>true if equal-comparable, false otherwise</returns>
647         internal static bool IsEqualComparable(TypeUsage type)
648         {
649             return IsEqualComparable(type.EdmType);
650         }
651
652         /// <summary>
653         /// Determines if type1 is equal-comparable to type2.
654         /// in order for type1 and type2 to be equal-comparable, they must be
655         /// individualy equal-comparable and have a common super-type.
656         /// </summary>
657         /// <param name="type1">an instance of a TypeUsage</param>
658         /// <param name="type2">an instance of a TypeUsage</param>
659         /// <returns><c>true</c> if type1 and type2 are equal-comparable, <c>false</c> otherwise</returns>
660         internal static bool IsEqualComparableTo(TypeUsage type1, TypeUsage type2)
661         {
662             if (IsEqualComparable(type1) && IsEqualComparable(type2))
663             {
664                 return HasCommonType(type1, type2);
665             }
666             return false;
667         }
668
669         /// <summary>
670         /// Determines if given type is order-comparable
671         /// </summary>
672         /// <param name="typeUsage"></param>
673         /// <returns></returns>
674         internal static bool IsOrderComparable(TypeUsage type)
675         {
676             Debug.Assert(null != type, "type must not be null");
677             return IsOrderComparable(type.EdmType);
678         }
679
680         /// Determines if type1 is order-comparable to type2.
681         /// in order for type1 and type2 to be order-comparable, they must be
682         /// individualy order-comparable and have a common super-type.
683         /// </summary>
684         /// <param name="type1">an instance of a TypeUsage</param>
685         /// <param name="type2">an instance of a TypeUsage</param>
686         /// <returns><c>true</c> if type1 and type2 are order-comparable, <c>false</c> otherwise</returns>
687         internal static bool IsOrderComparableTo(TypeUsage type1, TypeUsage type2)
688         {
689             if (IsOrderComparable(type1) && IsOrderComparable(type2))
690             {
691                 return HasCommonType(type1, type2);
692             }
693             return false;
694         }
695
696         /// <summary>
697         /// Removes facets that are not type constraints.
698         /// </summary>
699         /// <param name="type"></param>
700         /// <returns></returns>
701         internal static TypeUsage ForgetConstraints(TypeUsage type)
702         {
703             if (Helper.IsPrimitiveType(type.EdmType))
704             {
705                 return EdmProviderManifest.Instance.ForgetScalarConstraints(type);
706             }
707             return type;
708         }
709
710         [System.Diagnostics.Conditional("DEBUG")]
711         static internal void AssertTypeInvariant(string message, Func<bool> assertPredicate)
712         {
713             System.Diagnostics.Debug.Assert(assertPredicate(),
714                                             "Type invariant check FAILED\n" + message);
715         }
716         #endregion // Internal interface
717
718         //
719         // Private Interface
720         //
721         #region Private Interface
722
723         #region Subtyping
724         private static bool IsPrimitiveTypeSubTypeOf(TypeUsage fromType, TypeUsage toType)
725         {
726             Debug.Assert(fromType != null, "fromType must not be null");
727             Debug.Assert(Helper.IsPrimitiveType(fromType.EdmType), "fromType must be primitive type");
728             Debug.Assert(toType != null, "toType must not be null");
729             Debug.Assert(Helper.IsPrimitiveType(toType.EdmType), "toType must be primitive type");
730
731             if (!IsSubTypeOf((PrimitiveType)fromType.EdmType, (PrimitiveType)toType.EdmType))
732             {
733                 return false;
734             }
735
736             return true;
737         }
738
739         private static bool IsSubTypeOf(PrimitiveType subPrimitiveType, PrimitiveType superPrimitiveType)
740         {
741             if (object.ReferenceEquals(subPrimitiveType, superPrimitiveType))
742             {
743                 return true;
744             }
745
746             if (Helper.AreSameSpatialUnionType(subPrimitiveType, superPrimitiveType))
747             {
748                 return true;
749             }
750
751             objectModel.ReadOnlyCollection<PrimitiveType> superTypes = EdmProviderManifest.Instance.GetPromotionTypes(subPrimitiveType);
752
753             return (-1 != superTypes.IndexOf(superPrimitiveType));
754         }
755
756         #endregion // Subtyping
757
758         #region Promotability
759         private static bool IsPromotableTo(RowType fromRowType, RowType toRowType)
760         {
761             Debug.Assert(fromRowType != null && toRowType != null);
762
763             if (fromRowType.Properties.Count != toRowType.Properties.Count)
764             {
765                 return false;
766             }
767
768             for (int i = 0; i < fromRowType.Properties.Count; i++)
769             {
770                 if (!IsPromotableTo(fromRowType.Properties[i].TypeUsage, toRowType.Properties[i].TypeUsage))
771                 {
772                     return false;
773                 }
774             }
775
776             return true;
777         }
778
779         private static bool IsPrimitiveTypePromotableTo(TypeUsage fromType, TypeUsage toType)
780         {
781             Debug.Assert(fromType != null, "fromType must not be null");
782             Debug.Assert(Helper.IsPrimitiveType(fromType.EdmType), "fromType must be primitive type");
783             Debug.Assert(toType != null, "toType must not be null");
784             Debug.Assert(Helper.IsPrimitiveType(toType.EdmType), "toType must be primitive type");
785
786             if (!IsSubTypeOf((PrimitiveType)fromType.EdmType, (PrimitiveType)toType.EdmType))
787             {
788                 return false;
789             }
790
791             return true;
792         }
793
794         #endregion // promotability
795
796         #region Common Super-Type
797         private static bool TryGetCommonType(EdmType edmType1, EdmType edmType2, out EdmType commonEdmType)
798         {
799             Debug.Assert(edmType1 != null && edmType2 != null);
800
801             if (edmType2 == edmType1)
802             {
803                 commonEdmType = edmType1;
804                 return true;
805             }
806
807             if (Helper.IsPrimitiveType(edmType1) && Helper.IsPrimitiveType(edmType2))
808             {
809                 return TryGetCommonType((PrimitiveType)edmType1,
810                                                  (PrimitiveType)edmType2,
811                                                  out commonEdmType);
812             }
813
814             else if (Helper.IsCollectionType(edmType1) && Helper.IsCollectionType(edmType2))
815             {
816                 return TryGetCommonType((CollectionType)edmType1,
817                                                   (CollectionType)edmType2,
818                                                   out commonEdmType);
819             }
820
821             else if (Helper.IsEntityTypeBase(edmType1) && Helper.IsEntityTypeBase(edmType2))
822             {
823                 return TryGetCommonBaseType(edmType1,
824                                             edmType2,
825                                             out commonEdmType);
826             }
827
828             else if (Helper.IsRefType(edmType1) && Helper.IsRefType(edmType2))
829             {
830                 return TryGetCommonType((RefType)edmType1,
831                                            (RefType)edmType2,
832                                            out commonEdmType);
833             }
834
835             else if (Helper.IsRowType(edmType1) && Helper.IsRowType(edmType2))
836             {
837                 return TryGetCommonType((RowType)edmType1,
838                                            (RowType)edmType2,
839                                            out commonEdmType);
840             }
841             else
842             {
843                 commonEdmType = null;
844                 return false;
845             }
846         }
847
848         private static bool TryGetCommonPrimitiveType(TypeUsage type1, TypeUsage type2, out TypeUsage commonType)
849         {
850             Debug.Assert(type1 != null, "type1 must not be null");
851             Debug.Assert(Helper.IsPrimitiveType(type1.EdmType), "type1 must be primitive type");
852             Debug.Assert(type2 != null, "type2 must not be null");
853             Debug.Assert(Helper.IsPrimitiveType(type2.EdmType), "type2 must be primitive type");
854
855             commonType = null;
856
857             if (IsPromotableTo(type1, type2))
858             {
859                 commonType = ForgetConstraints(type2);
860                 return true;
861             }
862
863             if (IsPromotableTo(type2, type1))
864             {
865                 commonType = ForgetConstraints(type1);
866                 return true;
867             }
868
869             objectModel.ReadOnlyCollection<PrimitiveType> superTypes = GetPrimitiveCommonSuperTypes((PrimitiveType)type1.EdmType,
870                                                                                                     (PrimitiveType)type2.EdmType);
871             if (superTypes.Count == 0)
872             {
873                 return false;
874             }
875
876             commonType = TypeUsage.CreateDefaultTypeUsage(superTypes[0]);
877             return null != commonType;
878         }
879
880         private static bool TryGetCommonType(PrimitiveType primitiveType1, PrimitiveType primitiveType2, out EdmType commonType)
881         {
882             commonType = null;
883
884             if (IsSubTypeOf(primitiveType1, primitiveType2))
885             {
886                 commonType = primitiveType2;
887                 return true;
888             }
889
890             if (IsSubTypeOf(primitiveType2, primitiveType1))
891             {
892                 commonType = primitiveType1;
893                 return true;
894             }
895
896             objectModel.ReadOnlyCollection<PrimitiveType> superTypes = GetPrimitiveCommonSuperTypes(primitiveType1, primitiveType2);
897             if (superTypes.Count > 0)
898             {
899                 commonType = superTypes[0];
900                 return true;
901             }
902
903             return false;
904         }
905
906         private static bool TryGetCommonType(CollectionType collectionType1, CollectionType collectionType2, out EdmType commonType)
907         {
908             TypeUsage commonTypeUsage = null;
909             if (!TryGetCommonType(collectionType1.TypeUsage, collectionType2.TypeUsage, out commonTypeUsage))
910             {
911                 commonType = null;
912                 return false;
913             }
914
915             commonType = new CollectionType(commonTypeUsage);
916             return true;
917         }
918
919         private static bool TryGetCommonType(RefType refType1, RefType reftype2, out EdmType commonType)
920         {
921             Debug.Assert(refType1.ElementType != null && reftype2.ElementType != null);
922
923             if (!TryGetCommonType(refType1.ElementType, reftype2.ElementType, out commonType))
924             {
925                 return false;
926             }
927
928             commonType = new RefType((EntityType)commonType);
929             return true;
930         }
931
932         private static bool TryGetCommonType(RowType rowType1, RowType rowType2, out EdmType commonRowType)
933         {
934             if (rowType1.Properties.Count != rowType2.Properties.Count ||
935                 rowType1.InitializerMetadata != rowType2.InitializerMetadata)
936             {
937                 commonRowType = null;
938                 return false;
939             }
940
941             // find a common type for every property
942             List<EdmProperty> commonProperties = new List<EdmProperty>();
943             for (int i = 0; i < rowType1.Properties.Count; i++)
944             {
945                 TypeUsage columnCommonTypeUsage;
946                 if (!TryGetCommonType(rowType1.Properties[i].TypeUsage, rowType2.Properties[i].TypeUsage, out columnCommonTypeUsage))
947                 {
948                     commonRowType = null;
949                     return false;
950                 }
951
952                 commonProperties.Add(new EdmProperty(rowType1.Properties[i].Name, columnCommonTypeUsage));
953             }
954
955             commonRowType = new RowType(commonProperties, rowType1.InitializerMetadata);
956             return true;
957         }
958
959         private static bool TryGetCommonBaseType(EdmType type1, EdmType type2, out EdmType commonBaseType)
960         {
961             // put all the other base types in a dictionary
962             Dictionary<EdmType, byte> otherBaseTypes = new Dictionary<EdmType, byte>();
963             for (EdmType ancestor = type2; ancestor != null; ancestor = ancestor.BaseType)
964             {
965                 otherBaseTypes.Add(ancestor, 0);
966             }
967
968             // walk up the ancestor chain, and see if any of them are 
969             // common to the otherTypes ancestors
970             for (EdmType ancestor = type1; ancestor != null; ancestor = ancestor.BaseType)
971             {
972
973                 if (otherBaseTypes.ContainsKey(ancestor))
974                 {
975                     commonBaseType = ancestor;
976                     return true;
977                 }
978             }
979
980             commonBaseType = null;
981             return false;
982         }
983
984         private static bool HasCommonType(TypeUsage type1, TypeUsage type2)
985         {
986             return (null != TypeHelpers.GetCommonTypeUsage(type1, type2));
987         }
988         #endregion // common super-type helpers
989
990         #region Comparability
991         /// <summary>
992         /// Determines if the given edmType is equal comparable. Consult "EntitySql Language Specification", 
993         /// section 7 - Comparison and Dependent Operations for details.
994         /// </summary>
995         /// <param name="edmType">an instance of an EdmType</param>
996         /// <returns>true if edmType is equal-comparable, false otherwise</returns>
997         private static bool IsEqualComparable(EdmType edmType)
998         {
999             if (Helper.IsPrimitiveType(edmType) || Helper.IsRefType(edmType) || Helper.IsEntityType(edmType) || Helper.IsEnumType(edmType))
1000             {
1001                 return true;
1002             }
1003             else if (Helper.IsRowType(edmType))
1004             {
1005                 RowType rowType = (RowType)edmType;
1006                 foreach (EdmProperty rowProperty in rowType.Properties)
1007                 {
1008                     if (!IsEqualComparable(rowProperty.TypeUsage))
1009                     {
1010                         return false;
1011                     }
1012                 }
1013                 return true;
1014             }
1015             return false;
1016         }
1017
1018         /// Determines if the given edmType is order comparable. Consult "EntitySql Language Specification", 
1019         /// section 7 - Comparison and Dependent Operations for details.
1020         /// </summary>
1021         /// <param name="edmType">an instance of an EdmType</param>
1022         /// <returns>true if edmType is order-comparable, false otherwise</returns>
1023         private static bool IsOrderComparable(EdmType edmType)
1024         {
1025             // only primitive and enum types are assumed to be order-comparable though they 
1026             // may still fail during runtime depending on the provider specific behavior
1027             return Helper.IsScalarType(edmType);
1028         }
1029         #endregion
1030
1031         #region Private Helpers
1032
1033         private static bool CompareTypes(TypeUsage fromType, TypeUsage toType, bool equivalenceOnly)
1034         {
1035             Debug.Assert(fromType != null && toType != null);
1036
1037             // If the type usages are the same reference, they are equal.
1038             if (object.ReferenceEquals(fromType, toType))
1039             {
1040                 return true;
1041             }
1042
1043             if (fromType.EdmType.BuiltInTypeKind != toType.EdmType.BuiltInTypeKind)
1044             {
1045                 return false;
1046             }
1047
1048             //
1049             // Ensure structural evaluation for Collection, Ref and Row types
1050             //
1051             if (fromType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType)
1052             {
1053                 // Collection Type: Just compare the Element types
1054                 return CompareTypes(((CollectionType)fromType.EdmType).TypeUsage,
1055                                                 ((CollectionType)toType.EdmType).TypeUsage,
1056                                                 equivalenceOnly);
1057             }
1058             else if (fromType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType)
1059             {
1060                 // Both are Reference Types, so compare the referenced Entity types
1061                 return ((RefType)fromType.EdmType).ElementType.EdmEquals(((RefType)toType.EdmType).ElementType);
1062             }
1063             else if (fromType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RowType)
1064             {
1065                 // Row Types
1066                 RowType fromRow = (RowType)fromType.EdmType;
1067                 RowType toRow = (RowType)toType.EdmType;
1068                 // Both are RowTypes, so compare the structure.
1069                 // The number of properties must be the same.
1070                 if (fromRow.Properties.Count != toRow.Properties.Count)
1071                 {
1072                     return false;
1073                 }
1074
1075                 // Compare properties. For an equivalence comparison, only
1076                 // property types must match, otherwise names and types must match.
1077                 for (int idx = 0; idx < fromRow.Properties.Count; idx++)
1078                 {
1079                     EdmProperty fromProp = fromRow.Properties[idx];
1080                     EdmProperty toProp = toRow.Properties[idx];
1081
1082                     if (!equivalenceOnly && (fromProp.Name != toProp.Name))
1083                     {
1084                         return false;
1085                     }
1086
1087                     if (!CompareTypes(fromProp.TypeUsage, toProp.TypeUsage, equivalenceOnly))
1088                     {
1089                         return false;
1090                     }
1091                 }
1092
1093                 return true;
1094             }
1095
1096             //
1097             // compare non-transient type usages - simply compare the edm types instead
1098             //
1099             return fromType.EdmType.EdmEquals(toType.EdmType);
1100         }
1101
1102         /// <summary>
1103         /// Computes the closure of common super types of the set of predefined edm primitive types
1104         /// This is done only once and cached as opposed to previous implementation that was computing
1105         /// this for every new pair of types.
1106         /// </summary>
1107         private static void ComputeCommonTypeClosure()
1108         {
1109             if (null != _commonTypeClosure)
1110             {
1111                 return;
1112             }
1113
1114             objectModel.ReadOnlyCollection<PrimitiveType>[,] commonTypeClosure = new objectModel.ReadOnlyCollection<PrimitiveType>[EdmConstants.NumPrimitiveTypes, EdmConstants.NumPrimitiveTypes];
1115             for (int i = 0; i < EdmConstants.NumPrimitiveTypes; i++)
1116             {
1117                 commonTypeClosure[i, i] = Helper.EmptyPrimitiveTypeReadOnlyCollection;
1118             }
1119
1120             objectModel.ReadOnlyCollection<PrimitiveType> primitiveTypes = EdmProviderManifest.Instance.GetStoreTypes();
1121
1122             for (int i = 0; i < EdmConstants.NumPrimitiveTypes; i++)
1123             {
1124                 for (int j = 0; j < i; j++)
1125                 {
1126                     commonTypeClosure[i, j] = Intersect(EdmProviderManifest.Instance.GetPromotionTypes(primitiveTypes[i]),
1127                                                         EdmProviderManifest.Instance.GetPromotionTypes(primitiveTypes[j]));
1128
1129                     commonTypeClosure[j, i] = commonTypeClosure[i, j];
1130                 }
1131             }
1132
1133             TypeSemantics.AssertTypeInvariant("Common Type closure is incorrect",
1134                                                 delegate()
1135                                                 {
1136                                                     for (int i = 0; i < EdmConstants.NumPrimitiveTypes; i++)
1137                                                     {
1138                                                         for (int j = 0; j < EdmConstants.NumPrimitiveTypes; j++)
1139                                                         {
1140                                                             if (commonTypeClosure[i, j] != commonTypeClosure[j, i])
1141                                                                 return false;
1142                                                             if (i == j && commonTypeClosure[i, j].Count != 0)
1143                                                                 return false;
1144                                                         }
1145                                                     }
1146                                                     return true;
1147                                                 });
1148
1149             System.Threading.Interlocked.CompareExchange<objectModel.ReadOnlyCollection<PrimitiveType>[,]>(ref _commonTypeClosure, commonTypeClosure, null);
1150         }
1151
1152         /// <summary>
1153         /// returns the intersection of types.
1154         /// </summary>
1155         /// <param name="types1"></param>
1156         /// <param name="types2"></param>
1157         /// <returns></returns>
1158         private static objectModel.ReadOnlyCollection<PrimitiveType> Intersect(IList<PrimitiveType> types1, IList<PrimitiveType> types2)
1159         {
1160             List<PrimitiveType> commonTypes = new List<PrimitiveType>();
1161             for (int i = 0; i < types1.Count; i++)
1162             {
1163                 if (types2.Contains(types1[i]))
1164                 {
1165                     commonTypes.Add(types1[i]);
1166                 }
1167             }
1168
1169             if (0 == commonTypes.Count)
1170             {
1171                 return Helper.EmptyPrimitiveTypeReadOnlyCollection;
1172             }
1173
1174             return new objectModel.ReadOnlyCollection<PrimitiveType>(commonTypes);
1175         }
1176
1177         /// <summary>
1178         /// Returns the list of common super types of two primitive types.
1179         /// </summary>
1180         /// <param name="primitiveType1"></param>
1181         /// <param name="primitiveType2"></param>
1182         /// <returns></returns>
1183         private static objectModel.ReadOnlyCollection<PrimitiveType> GetPrimitiveCommonSuperTypes(PrimitiveType primitiveType1, PrimitiveType primitiveType2)
1184         {
1185             ComputeCommonTypeClosure();
1186             return _commonTypeClosure[(int)primitiveType1.PrimitiveTypeKind, (int)primitiveType2.PrimitiveTypeKind];
1187         }
1188         #endregion // Private Helpers
1189
1190         #endregion // Private interface
1191     }
1192 }