1 /* ****************************************************************************
3 * Copyright (c) Microsoft Corporation.
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.
11 * You must not remove this notice, or any other, from this software.
14 * ***************************************************************************/
17 using System.Linq.Expressions;
19 using Microsoft.Scripting.Ast;
23 using System.Reflection;
25 using Microsoft.Scripting.Generation;
26 using Microsoft.Scripting.Runtime;
28 namespace Microsoft.Scripting.Utils {
29 public static class TypeUtils {
30 public static bool IsNested(this Type t) {
31 return t.DeclaringType != null;
34 // keep in sync with System.Core version
35 internal static Type GetNonNullableType(Type type) {
36 if (IsNullableType(type)) {
37 return type.GetGenericArguments()[0];
42 // keep in sync with System.Core version
43 internal static bool IsNullableType(Type type) {
44 return type.IsGenericType() && type.GetGenericTypeDefinition() == typeof(Nullable<>);
47 // keep in sync with System.Core version
48 internal static bool IsBool(Type type) {
49 return GetNonNullableType(type) == typeof(bool);
52 // keep in sync with System.Core version
53 internal static bool IsNumeric(Type type) {
54 type = GetNonNullableType(type);
56 return IsNumeric(type.GetTypeCode());
61 internal static bool IsNumeric(TypeCode typeCode) {
79 // keep in sync with System.Core version
80 internal static bool IsArithmetic(Type type) {
81 type = GetNonNullableType(type);
83 switch (type.GetTypeCode()) {
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:
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()) {
120 case TypeCode.UInt64:
121 case TypeCode.UInt32:
122 case TypeCode.UInt16:
123 case TypeCode.Boolean:
132 internal static bool CanAssign(Type to, Expression from) {
133 if (CanAssign(to, from.Type)) return true;
135 if (to.IsValueType() &&
136 to.IsGenericType() &&
137 to.GetGenericTypeDefinition() == typeof(Nullable<>) &&
138 ConstantCheck.Check(from, null)) {
145 internal static bool CanAssign(Type to, Type from) {
150 if (!to.IsValueType() && !from.IsValueType()) {
151 if (to.IsAssignableFrom(from)) {
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())) {
165 internal static bool IsGeneric(Type type) {
166 return type.ContainsGenericParameters() || type.IsGenericTypeDefinition();
169 internal static bool CanCompareToNull(Type type) {
170 // This is a bit too conservative.
171 return !type.IsValueType();
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.
179 internal static bool GetNumericConversionOrder(TypeCode code, out int x, out int y) {
180 // implicit conversions:
182 // 0: U1 -> U2 -> U4 -> U8
185 // 1: I1 -> I2 -> I4 -> I8
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;
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;
201 case TypeCode.Single: x = 1; y = 2; break;
202 case TypeCode.Double: x = 2; y = 2; break;
211 internal static bool IsImplicitlyConvertible(int fromX, int fromY, int toX, int toY) {
212 return fromX <= toX && fromY <= toY;
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()) {
222 // Reference types compare if they are assignable
223 if (!left.IsValueType() && !right.IsValueType()) {
224 if (CanAssign(left, right) || CanAssign(right, left)) {
229 // Nullable<T> vs null
230 if (NullVsNullable(left, right) || NullVsNullable(right, left)) {
238 if (left == typeof(bool) || IsNumeric(left) || left.IsEnum()) {
245 private static bool NullVsNullable(Type left, Type right) {
246 return IsNullableType(left) && right == typeof(DynamicNull);
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);
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?"
264 if (!dest.IsValueType() && !src.IsValueType() && AreAssignable(dest, src)) {
270 // keep in sync with System.Core version
271 internal static bool AreAssignable(Type dest, Type src) {
275 if (dest.IsAssignableFrom(src)) {
278 if (dest.IsArray && src.IsArray && dest.GetArrayRank() == src.GetArrayRank() && AreReferenceAssignable(dest.GetElementType(), src.GetElementType())) {
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()) {
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()) {
298 // Get the visible base type
301 bt = bt.GetBaseType();
302 } while (!bt.IsVisible());
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)) {
315 // else return the original type
319 internal static bool IsConvertible(Type type) {
320 type = GetNonNullableType(type);
324 switch (type.GetTypeCode()) {
325 case TypeCode.Boolean:
331 case TypeCode.UInt16:
332 case TypeCode.UInt32:
333 case TypeCode.UInt64:
334 case TypeCode.Single:
335 case TypeCode.Double:
343 internal static bool IsFloatingPoint(Type type) {
344 type = GetNonNullableType(type);
345 switch (type.GetTypeCode()) {
346 case TypeCode.Single:
347 case TypeCode.Double:
355 public static readonly Type ComObjectType = typeof(object).Assembly.GetType("System.__ComObject");
357 public static bool IsComObjectType(Type/*!*/ type) {
358 return ComObjectType.IsAssignableFrom(type);
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());
366 public static bool IsComObjectType(Type/*!*/ type) {
370 public static bool IsComObject(object obj) {