[sgen] Reenable gc-altstack test
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Dynamic / Utils / TypeUtils.cs
1 /* ****************************************************************************
2  *
3  * Copyright (c) Microsoft Corporation. 
4  *
5  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
6  * copy of the license can be found in the License.html file at the root of this distribution. If 
7  * you cannot locate the  Apache License, Version 2.0, please send an email to 
8  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
9  * by the terms of the Apache License, Version 2.0.
10  *
11  * You must not remove this notice, or any other, from this software.
12  *
13  *
14  * ***************************************************************************/
15
16 #if FEATURE_CORE_DLR
17 using System.Linq.Expressions;
18 #else
19 using Microsoft.Scripting.Ast;
20 #endif
21
22 using System;
23 using System.Reflection;
24 using System.Dynamic;
25 using Microsoft.Scripting.Generation;
26 using Microsoft.Scripting.Runtime;
27
28 namespace Microsoft.Scripting.Utils {
29     public static class TypeUtils {
30         public static bool IsNested(this Type t) {
31             return t.DeclaringType != null;
32         }
33
34         // keep in sync with System.Core version
35         internal static Type GetNonNullableType(Type type) {
36             if (IsNullableType(type)) {
37                 return type.GetGenericArguments()[0];
38             }
39             return type;
40         }
41
42         // keep in sync with System.Core version
43         internal static bool IsNullableType(Type type) {
44             return type.IsGenericType() && type.GetGenericTypeDefinition() == typeof(Nullable<>);
45         }
46
47         // keep in sync with System.Core version
48         internal static bool IsBool(Type type) {
49             return GetNonNullableType(type) == typeof(bool);
50         }
51
52         // keep in sync with System.Core version
53         internal static bool IsNumeric(Type type) {
54             type = GetNonNullableType(type);
55             if (!type.IsEnum()) {
56                 return IsNumeric(type.GetTypeCode());
57             }
58             return false;
59         }
60
61         internal static bool IsNumeric(TypeCode typeCode) {
62             switch (typeCode) {
63                 case TypeCode.Char:
64                 case TypeCode.SByte:
65                 case TypeCode.Byte:
66                 case TypeCode.Int16:
67                 case TypeCode.Int32:
68                 case TypeCode.Int64:
69                 case TypeCode.Double:
70                 case TypeCode.Single:
71                 case TypeCode.UInt16:
72                 case TypeCode.UInt32:
73                 case TypeCode.UInt64:
74                     return true;
75             }
76             return false;
77         }
78
79         // keep in sync with System.Core version
80         internal static bool IsArithmetic(Type type) {
81             type = GetNonNullableType(type);
82             if (!type.IsEnum()) {
83                 switch (type.GetTypeCode()) {
84                     case TypeCode.Int16:
85                     case TypeCode.Int32:
86                     case TypeCode.Int64:
87                     case TypeCode.Double:
88                     case TypeCode.Single:
89                     case TypeCode.UInt16:
90                     case TypeCode.UInt32:
91                     case TypeCode.UInt64:
92                         return true;
93                 }
94             }
95             return false;
96         }
97
98         // keep in sync with System.Core version
99         internal static bool IsUnsignedInt(Type type) {
100             type = GetNonNullableType(type);
101             if (!type.IsEnum()) {
102                 switch (type.GetTypeCode()) {
103                     case TypeCode.UInt16:
104                     case TypeCode.UInt32:
105                     case TypeCode.UInt64:
106                         return true;
107                 }
108             }
109             return false;
110         }
111
112         // keep in sync with System.Core version
113         internal static bool IsIntegerOrBool(Type type) {
114             type = GetNonNullableType(type);
115             if (!type.IsEnum()) {
116                 switch (type.GetTypeCode()) {
117                     case TypeCode.Int64:
118                     case TypeCode.Int32:
119                     case TypeCode.Int16:
120                     case TypeCode.UInt64:
121                     case TypeCode.UInt32:
122                     case TypeCode.UInt16:
123                     case TypeCode.Boolean:
124                     case TypeCode.SByte:
125                     case TypeCode.Byte:
126                         return true;
127                 }
128             }
129             return false;
130         }
131
132         internal static bool CanAssign(Type to, Expression from) {
133             if (CanAssign(to, from.Type)) return true;
134
135             if (to.IsValueType() && 
136                 to.IsGenericType() && 
137                 to.GetGenericTypeDefinition() == typeof(Nullable<>) && 
138                 ConstantCheck.Check(from, null)) {
139                 return true;
140             }
141
142             return false;
143         }
144
145         internal static bool CanAssign(Type to, Type from) {
146             if (to == from) {
147                 return true;
148             }
149             // Reference types
150             if (!to.IsValueType() && !from.IsValueType()) {
151                 if (to.IsAssignableFrom(from)) {
152                     return true;
153                 }
154                 // Arrays can be assigned if they have same rank and assignable element types.
155                 if (to.IsArray && from.IsArray &&
156                     to.GetArrayRank() == from.GetArrayRank() &&
157                     CanAssign(to.GetElementType(), from.GetElementType())) {
158                     return true;
159                 }
160             } 
161
162             return false;
163         }
164
165         internal static bool IsGeneric(Type type) {
166             return type.ContainsGenericParameters() || type.IsGenericTypeDefinition();
167         }
168
169         internal static bool CanCompareToNull(Type type) {
170             // This is a bit too conservative.
171             return !type.IsValueType();
172         }
173
174         /// <summary>
175         /// Returns a numerical code of the size of a type.  All types get both a horizontal
176         /// and vertical code.  Types that are lower in both dimensions have implicit conversions
177         /// to types that are higher in both dimensions.
178         /// </summary>
179         internal static bool GetNumericConversionOrder(TypeCode code, out int x, out int y) {
180             // implicit conversions:
181             //     0     1     2     3     4
182             // 0:       U1 -> U2 -> U4 -> U8
183             //          |     |     |
184             //          v     v     v
185             // 1: I1 -> I2 -> I4 -> I8
186             //          |     |     
187             //          v     v     
188             // 2:       R4 -> R8
189
190             switch (code) {
191                 case TypeCode.Byte: x = 0; y = 0; break;
192                 case TypeCode.UInt16: x = 1; y = 0; break;
193                 case TypeCode.UInt32: x = 2; y = 0; break;
194                 case TypeCode.UInt64: x = 3; y = 0; break;
195
196                 case TypeCode.SByte: x = 0; y = 1; break;
197                 case TypeCode.Int16: x = 1; y = 1; break;
198                 case TypeCode.Int32: x = 2; y = 1; break;
199                 case TypeCode.Int64: x = 3; y = 1; break;
200
201                 case TypeCode.Single: x = 1; y = 2; break;
202                 case TypeCode.Double: x = 2; y = 2; break;
203
204                 default:
205                     x = y = 0;
206                     return false;
207             }
208             return true;
209         }
210
211         internal static bool IsImplicitlyConvertible(int fromX, int fromY, int toX, int toY) {
212             return fromX <= toX && fromY <= toY;
213         }
214
215         internal static bool HasBuiltinEquality(Type left, Type right) {
216             // Reference type can be compared to interfaces
217             if (left.IsInterface() && !right.IsValueType() ||
218                 right.IsInterface() && !left.IsValueType()) {
219                 return true;
220             }
221
222             // Reference types compare if they are assignable
223             if (!left.IsValueType() && !right.IsValueType()) {
224                 if (CanAssign(left, right) || CanAssign(right, left)) {
225                     return true;
226                 }
227             }
228
229             // Nullable<T> vs null
230             if (NullVsNullable(left, right) || NullVsNullable(right, left)) {
231                 return true;
232             }
233
234             if (left != right) {
235                 return false;
236             }
237
238             if (left == typeof(bool) || IsNumeric(left) || left.IsEnum()) {
239                 return true;
240             }
241
242             return false;
243         }
244
245         private static bool NullVsNullable(Type left, Type right) {
246             return IsNullableType(left) && right == typeof(DynamicNull);
247         }
248
249         // keep in sync with System.Core version
250         internal static bool AreEquivalent(Type t1, Type t2) {
251 #if FEATURE_TYPE_EQUIVALENCE
252             return t1 == t2 || t1.IsEquivalentTo(t2);
253 #else
254             return t1 == t2;
255 #endif
256         }
257
258         // keep in sync with System.Core version
259         internal static bool AreReferenceAssignable(Type dest, Type src) {
260             // WARNING: This actually implements "Is this identity assignable and/or reference assignable?"
261             if (dest == src) {
262                 return true;
263             }
264             if (!dest.IsValueType() && !src.IsValueType() && AreAssignable(dest, src)) {
265                 return true;
266             }
267             return false;
268         }
269
270         // keep in sync with System.Core version
271         internal static bool AreAssignable(Type dest, Type src) {
272             if (dest == src) {
273                 return true;
274             }
275             if (dest.IsAssignableFrom(src)) {
276                 return true;
277             }
278             if (dest.IsArray && src.IsArray && dest.GetArrayRank() == src.GetArrayRank() && AreReferenceAssignable(dest.GetElementType(), src.GetElementType())) {
279                 return true;
280             }
281             if (src.IsArray && dest.IsGenericType() &&
282                 (dest.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IEnumerable<>)
283                 || dest.GetGenericTypeDefinition() == typeof(System.Collections.Generic.IList<>)
284                 || dest.GetGenericTypeDefinition() == typeof(System.Collections.Generic.ICollection<>))
285                 && dest.GetGenericArguments()[0] == src.GetElementType()) {
286                 return true;
287             }
288             return false;
289         }
290
291         // keep in sync with System.Core version
292         internal static Type GetConstantType(Type type) {
293             // If it's a visible type, we're done
294             if (type.IsVisible()) {
295                 return type;
296             }
297
298             // Get the visible base type
299             Type bt = type;
300             do {
301                 bt = bt.GetBaseType();
302             } while (!bt.IsVisible());
303
304             // If it's one of the known reflection types,
305             // return the known type.
306             if (bt == typeof(Type) ||
307                 bt == typeof(ConstructorInfo) ||
308                 bt == typeof(EventInfo) ||
309                 bt == typeof(FieldInfo) ||
310                 bt == typeof(MethodInfo) ||
311                 bt == typeof(PropertyInfo)) {
312                 return bt;
313             }
314
315             // else return the original type
316             return type;
317         }
318
319         internal static bool IsConvertible(Type type) {
320             type = GetNonNullableType(type);
321             if (type.IsEnum()) {
322                 return true;
323             }
324             switch (type.GetTypeCode()) {
325                 case TypeCode.Boolean:
326                 case TypeCode.Byte:
327                 case TypeCode.SByte:
328                 case TypeCode.Int16:
329                 case TypeCode.Int32:
330                 case TypeCode.Int64:
331                 case TypeCode.UInt16:
332                 case TypeCode.UInt32:
333                 case TypeCode.UInt64:
334                 case TypeCode.Single:
335                 case TypeCode.Double:
336                 case TypeCode.Char:
337                     return true;
338                 default:
339                     return false;
340             }
341         }
342
343         internal static bool IsFloatingPoint(Type type) {
344             type = GetNonNullableType(type);
345             switch (type.GetTypeCode()) {
346                 case TypeCode.Single:
347                 case TypeCode.Double:
348                     return true;
349                 default:
350                     return false;
351             }
352         }
353
354 #if FEATURE_COM
355         public static readonly Type ComObjectType = typeof(object).Assembly.GetType("System.__ComObject");
356
357         public static bool IsComObjectType(Type/*!*/ type) {
358             return ComObjectType.IsAssignableFrom(type);
359         }
360
361         // we can't use System.Runtime.InteropServices.Marshal.IsComObject(obj) since it doesn't work in partial trust
362         public static bool IsComObject(object obj) {
363             return obj != null && IsComObjectType(obj.GetType());
364         }
365 #else
366         public static bool IsComObjectType(Type/*!*/ type) {
367             return false;
368         }
369
370         public static bool IsComObject(object obj) {
371             return false;
372         }
373 #endif
374     }
375 }