public static TypeReference MakeGenericType (this TypeReference self, params TypeReference [] arguments)
		{
			if (self.GenericParameters.Count != arguments.Length)
				throw new ArgumentException ();

			var instance = new GenericInstanceType (self);
			foreach (var argument in arguments)
				instance.GenericArguments.Add (argument);

			return instance;
		}
		TypeReference ImportTypeSpecification (TypeReference type, IGenericContext context)
		{
			switch (type.etype) {
			case ElementType.SzArray:
				var vector = (ArrayType) type;
				return new ArrayType (ImportType (vector.ElementType, context));
			case ElementType.Ptr:
				var pointer = (PointerType) type;
				return new PointerType (ImportType (pointer.ElementType, context));
			case ElementType.ByRef:
				var byref = (ByReferenceType) type;
				return new ByReferenceType (ImportType (byref.ElementType, context));
			case ElementType.Pinned:
				var pinned = (PinnedType) type;
				return new PinnedType (ImportType (pinned.ElementType, context));
			case ElementType.Sentinel:
				var sentinel = (SentinelType) type;
				return new SentinelType (ImportType (sentinel.ElementType, context));
			case ElementType.CModOpt:
				var modopt = (OptionalModifierType) type;
				return new OptionalModifierType (
					ImportType (modopt.ModifierType, context),
					ImportType (modopt.ElementType, context));
			case ElementType.CModReqD:
				var modreq = (RequiredModifierType) type;
				return new RequiredModifierType (
					ImportType (modreq.ModifierType, context),
					ImportType (modreq.ElementType, context));
			case ElementType.Array:
				var array = (ArrayType) type;
				return new ArrayType (ImportType (array.ElementType, context), array.Dimensions);
			case ElementType.GenericInst:
				var instance = (GenericInstanceType) type;
				var element_type = ImportType (instance.ElementType, context);
				var imported_instance = new GenericInstanceType (element_type);

				var arguments = instance.GenericArguments;
				var imported_arguments = imported_instance.GenericArguments;

				for (int i = 0; i < arguments.Count; i++)
					imported_arguments.Add (ImportType (arguments [i], context));

				return imported_instance;
			case ElementType.Var:
				if (context == null || context.Type == null)
					throw new InvalidOperationException ();

				return ((TypeReference) context.Type).GetElementType ().GenericParameters [((GenericParameter) type).Position];
			case ElementType.MVar:
				if (context == null || context.Method == null)
					throw new InvalidOperationException ();

				return context.Method.GenericParameters [((GenericParameter) type).Position];
			}

			throw new NotSupportedException (type.etype.ToString ());
		}
		public static TypeReference SubstituteTypeArgs(TypeReference type, MemberReference member)
		{
			if (type is TypeSpecification) {
				ArrayType arrayType = type as ArrayType;
				if (arrayType != null) {
					TypeReference elementType = SubstituteTypeArgs(arrayType.ElementType, member);
					if (elementType != arrayType.ElementType) {
						return new ArrayType(elementType, arrayType.Dimensions);
					} else {
						return type;
					}
				}
				ByReferenceType refType = type as ByReferenceType;
				if (refType != null) {
					TypeReference elementType = SubstituteTypeArgs(refType.ElementType, member);
					return elementType != refType.ElementType ? new ByReferenceType(elementType) : type;
				}
				GenericInstanceType giType = type as GenericInstanceType;
				if (giType != null) {
					GenericInstanceType newType = new GenericInstanceType(giType.ElementType);
					bool isChanged = false;
					for (int i = 0; i < giType.GenericArguments.Count; i++) {
						newType.GenericArguments.Add(SubstituteTypeArgs(giType.GenericArguments[i], member));
						isChanged |= newType.GenericArguments[i] != giType.GenericArguments[i];
					}
					return isChanged ? newType : type;
				}
				OptionalModifierType optmodType = type as OptionalModifierType;
				if (optmodType != null) {
					TypeReference elementType = SubstituteTypeArgs(optmodType.ElementType, member);
					return elementType != optmodType.ElementType ? new OptionalModifierType(optmodType.ModifierType, elementType) : type;
				}
				RequiredModifierType reqmodType = type as RequiredModifierType;
				if (reqmodType != null) {
					TypeReference elementType = SubstituteTypeArgs(reqmodType.ElementType, member);
					return elementType != reqmodType.ElementType ? new RequiredModifierType(reqmodType.ModifierType, elementType) : type;
				}
				PointerType ptrType = type as PointerType;
				if (ptrType != null) {
					TypeReference elementType = SubstituteTypeArgs(ptrType.ElementType, member);
					return elementType != ptrType.ElementType ? new PointerType(elementType) : type;
				}
			}
			GenericParameter gp = type as GenericParameter;
			if (gp != null) {
				if (gp.Owner.GenericParameterType == GenericParameterType.Method) {
					return ((GenericInstanceMethod)member).GenericArguments[gp.Position];
				} else {
					if (member.DeclaringType is ArrayType) {
						return ((ArrayType)member.DeclaringType).ElementType;
					} else {
						return ((GenericInstanceType)member.DeclaringType).GenericArguments[gp.Position];
					}
				}
			}
			return type;
		}
		TypeReference ImportGenericInstance (Type type, IGenericContext context)
		{
			var element_type = ImportType (type.GetGenericTypeDefinition (), context, ImportGenericKind.Definition);
			var instance = new GenericInstanceType (element_type);
			var arguments = type.GetGenericArguments ();
			var instance_arguments = instance.GenericArguments;

			for (int i = 0; i < arguments.Length; i++)
				instance_arguments.Add (ImportType (arguments [i], context ?? element_type));

			return instance;
		}
		static bool AreSame (GenericInstanceType a, GenericInstanceType b)
		{
			if (a.GenericArguments.Count != b.GenericArguments.Count)
				return false;

			for (int i = 0; i < a.GenericArguments.Count; i++)
				if (!AreSame (a.GenericArguments [i], b.GenericArguments [i]))
					return false;

			return true;
		}