+#region Generics
+ // <remarks>
+ // Tracks the generic parameters.
+ // </remarks>
+ static PtrHashtable builder_to_type_param;
+
+ public static void AddTypeParameter (Type t, TypeParameter tparam)
+ {
+ if (!builder_to_type_param.Contains (t))
+ builder_to_type_param.Add (t, tparam);
+ }
+
+ public static TypeParameter LookupTypeParameter (Type t)
+ {
+ return (TypeParameter) builder_to_type_param [t];
+ }
+
+ // This method always return false for non-generic compiler,
+ // while Type.IsGenericParameter is returned if it is supported.
+ public static bool IsGenericParameter (Type type)
+ {
+#if GMCS_SOURCE
+ return type.IsGenericParameter;
+#else
+ return false;
+#endif
+ }
+
+ public static int GenericParameterPosition (Type type)
+ {
+#if GMCS_SOURCE
+ return type.GenericParameterPosition;
+#else
+ throw new InternalErrorException ("should not be called");
+#endif
+ }
+
+ public static bool IsGenericType (Type type)
+ {
+#if GMCS_SOURCE
+ return type.IsGenericType;
+#else
+ return false;
+#endif
+ }
+
+ public static bool IsGenericTypeDefinition (Type type)
+ {
+#if GMCS_SOURCE
+ return type.IsGenericTypeDefinition;
+#else
+ return false;
+#endif
+ }
+
+ public static bool ContainsGenericParameters (Type type)
+ {
+#if GMCS_SOURCE
+ return type.ContainsGenericParameters;
+#else
+ return false;
+#endif
+ }
+
+ public static FieldInfo GetGenericFieldDefinition (FieldInfo fi)
+ {
+#if GMCS_SOURCE
+ if (fi.DeclaringType.IsGenericTypeDefinition ||
+ !fi.DeclaringType.IsGenericType)
+ return fi;
+
+ Type t = fi.DeclaringType.GetGenericTypeDefinition ();
+ BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
+
+ foreach (FieldInfo f in t.GetFields (bf))
+ if (f.MetadataToken == fi.MetadataToken)
+ return f;
+#endif
+
+ return fi;
+ }
+
+ public static bool IsEqual (Type a, Type b)
+ {
+ if (a.Equals (b))
+ return true;
+
+#if GMCS_SOURCE
+ if (a.IsGenericParameter && b.IsGenericParameter) {
+ if (a.DeclaringMethod != b.DeclaringMethod &&
+ (a.DeclaringMethod == null || b.DeclaringMethod == null))
+ return false;
+ return a.GenericParameterPosition == b.GenericParameterPosition;
+ }
+
+ if (a.IsArray && b.IsArray) {
+ if (a.GetArrayRank () != b.GetArrayRank ())
+ return false;
+ return IsEqual (a.GetElementType (), b.GetElementType ());
+ }
+
+ if (a.IsByRef && b.IsByRef)
+ return IsEqual (a.GetElementType (), b.GetElementType ());
+
+ if (a.IsGenericType && b.IsGenericType) {
+ if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
+ return false;
+
+ Type[] aargs = a.GetGenericArguments ();
+ Type[] bargs = b.GetGenericArguments ();
+
+ if (aargs.Length != bargs.Length)
+ return false;
+
+ for (int i = 0; i < aargs.Length; i++) {
+ if (!IsEqual (aargs [i], bargs [i]))
+ return false;
+ }
+
+ return true;
+ }
+#endif
+
+ return false;
+ }
+
+ public static Type DropGenericTypeArguments (Type t)
+ {
+#if GMCS_SOURCE
+ if (!t.IsGenericType)
+ return t;
+ // Micro-optimization: a generic typebuilder is always a generic type definition
+ if (t is TypeBuilder)
+ return t;
+ return t.GetGenericTypeDefinition ();
+#else
+ return t;
+#endif
+ }
+
+ public static MethodBase DropGenericMethodArguments (MethodBase m)
+ {
+#if GMCS_SOURCE
+ if (m.IsGenericMethodDefinition)
+ return m;
+ if (m.IsGenericMethod)
+ return ((MethodInfo) m).GetGenericMethodDefinition ();
+ if (!m.DeclaringType.IsGenericType)
+ return m;
+
+ Type t = m.DeclaringType.GetGenericTypeDefinition ();
+ BindingFlags bf = BindingFlags.Public | BindingFlags.NonPublic |
+ BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly;
+
+#if MS_COMPATIBLE
+ return m;
+#endif
+
+ if (m is ConstructorInfo) {
+ foreach (ConstructorInfo c in t.GetConstructors (bf))
+ if (c.MetadataToken == m.MetadataToken)
+ return c;
+ } else {
+ foreach (MethodBase mb in t.GetMethods (bf))
+ if (mb.MetadataToken == m.MetadataToken)
+ return mb;
+ }
+#endif
+
+ return m;
+ }
+
+ public static Type[] GetGenericArguments (MethodInfo mi)
+ {
+#if GMCS_SOURCE
+ return mi.GetGenericArguments ();
+#else
+ return Type.EmptyTypes;
+#endif
+ }
+
+ public static Type[] GetTypeArguments (Type t)
+ {
+#if GMCS_SOURCE
+ DeclSpace tc = LookupDeclSpace (t);
+ if (tc != null) {
+ if (!tc.IsGeneric)
+ return Type.EmptyTypes;
+
+ TypeParameter[] tparam = tc.TypeParameters;
+ Type[] ret = new Type [tparam.Length];
+ for (int i = 0; i < tparam.Length; i++) {
+ ret [i] = tparam [i].Type;
+ if (ret [i] == null)
+ throw new InternalErrorException ();
+ }
+
+ return ret;
+ } else
+ return t.GetGenericArguments ();
+#else
+ throw new InternalErrorException ();
+#endif
+ }
+
+ public static bool HasGenericArguments (Type t)
+ {
+ return GetNumberOfTypeArguments (t) > 0;
+ }
+
+ public static int GetNumberOfTypeArguments (Type t)
+ {
+#if GMCS_SOURCE
+ if (t.IsGenericParameter)
+ return 0;
+ DeclSpace tc = LookupDeclSpace (t);
+ if (tc != null)
+ return tc.IsGeneric ? tc.CountTypeParameters : 0;
+ else
+ return t.IsGenericType ? t.GetGenericArguments ().Length : 0;
+#else
+ return 0;
+#endif
+ }
+
+ /// <summary>
+ /// Check whether `type' and `parent' are both instantiations of the same
+ /// generic type. Note that we do not check the type parameters here.
+ /// </summary>
+ public static bool IsInstantiationOfSameGenericType (Type type, Type parent)
+ {
+ int tcount = GetNumberOfTypeArguments (type);
+ int pcount = GetNumberOfTypeArguments (parent);
+
+ if (tcount != pcount)
+ return false;
+
+ type = DropGenericTypeArguments (type);
+ parent = DropGenericTypeArguments (parent);
+
+ return type.Equals (parent);
+ }
+
+ /// <summary>
+ /// Whether `mb' is a generic method definition.
+ /// </summary>
+ public static bool IsGenericMethodDefinition (MethodBase mb)
+ {
+#if GMCS_SOURCE
+ if (mb.DeclaringType is TypeBuilder) {
+ IMethodData method = (IMethodData) builder_to_method [mb];
+ if (method == null)
+ return false;
+
+ return method.GenericMethod != null;
+ }
+
+ return mb.IsGenericMethodDefinition;
+#else
+ return false;
+#endif
+ }
+
+ /// <summary>
+ /// Whether `mb' is a generic method.
+ /// </summary>
+ public static bool IsGenericMethod (MethodBase mb)
+ {
+#if GMCS_SOURCE
+ if (mb.DeclaringType is TypeBuilder) {
+ IMethodData method = (IMethodData) builder_to_method [mb];
+ if (method == null)
+ return false;
+
+ return method.GenericMethod != null;
+ }
+
+ return mb.IsGenericMethod;
+#else
+ return false;
+#endif
+ }
+
+ public static bool IsNullableType (Type t)
+ {
+#if GMCS_SOURCE
+ return generic_nullable_type == DropGenericTypeArguments (t);
+#else
+ return false;
+#endif
+ }
+
+ public static bool IsNullableTypeOf (Type t, Type nullable)
+ {
+#if GMCS_SOURCE
+ if (!IsNullableType (t))
+ return false;
+
+ return GetTypeArguments (t) [0] == nullable;
+#else
+ return false;
+#endif
+ }
+
+ public static bool IsNullableValueType (Type t)
+ {
+#if GMCS_SOURCE
+ if (!IsNullableType (t))
+ return false;
+
+ return GetTypeArguments (t) [0].IsValueType;
+#else
+ return false;
+#endif
+ }
+#endregion