context: //
  // generic.cs: Generics support
  //
  // Authors: Martin Baulig (martin@ximian.com)
  //          Miguel de Icaza (miguel@ximian.com)
  //          Marek Safar (marek.safar@gmail.com)
  //
  // Dual licensed under the terms of the MIT X11 or GNU GPL
  //
  // Copyright 2001, 2002, 2003 Ximian, Inc (http://www.ximian.com)
  // Copyright 2004-2008 Novell, Inc
  //
  using System;
  using System.Collections.Generic;
  using System.Text;
  using System.Linq;
  
  #if STATIC
  using MetaType = IKVM.Reflection.Type;
  using IKVM.Reflection;
  using IKVM.Reflection.Emit;
  #else
  using MetaType = System.Type;
  using System.Reflection;
  using System.Reflection.Emit;
  #endif
  
  namespace Mono.CSharp {
  	public enum Variance
  	{
  		//
  		// Don't add or modify internal values, they are used as -/+ calculation signs
  		//
  		None			= 0,
  		Covariant		= 1,
  		Contravariant	= -1
  	}
  
  	[Flags]
  	public enum SpecialConstraint
  	{
  		None		= 0,
  		Constructor = 1 << 2,
  		Class		= 1 << 3,
  		Struct		= 1 << 4
  	}
  
  	public class SpecialContraintExpr : FullNamedExpression
  	{
  		public SpecialContraintExpr (SpecialConstraint constraint, Location loc)
  		{
  			this.loc = loc;
  			this.Constraint = constraint;
  		}
  
  		public SpecialConstraint Constraint { get; private set; }
  
  		protected override Expression DoResolve (ResolveContext rc)
  		{
  			throw new NotImplementedException ();
  		}
  
  		public override FullNamedExpression ResolveAsTypeOrNamespace (IMemberContext ec)
  		{
  			throw new NotImplementedException ();
  		}
  	}
  
  	//
  	// A set of parsed constraints for a type parameter
  	//
  	public class Constraints
  	{
  		SimpleMemberName tparam;
  		List<FullNamedExpression> constraints;
  		Location loc;
  		bool resolved;
  		bool resolving;
  		
  		public IEnumerable<FullNamedExpression> ConstraintExpressions {
  			get {
  				return constraints;
  			}
  		}
  
  		public Constraints (SimpleMemberName tparam, List<FullNamedExpression> constraints, Location loc)
  		{
  			this.tparam = tparam;
  			this.constraints = constraints;
  			this.loc = loc;
  		}
  
  		#region Properties
  
  		public Location Location {
  			get {
  				return loc;
  			}
  		}
  
  		public SimpleMemberName TypeParameter {
  			get {
  				return tparam;
  			}
  		}
  
  		#endregion
  
  		public static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec, TypeSpec bb, IMemberContext context, Location loc)
  		{
  			if (spec.HasSpecialClass && bb.IsStruct) {
  				context.Module.Compiler.Report.Error (455, loc,
  					"Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
  					spec.Name, "class", bb.GetSignatureForError ());
  
  				return false;
  			}
  
  			return CheckConflictingInheritedConstraint (spec, spec.BaseType, bb, context, loc);
  		}
  
  		static bool CheckConflictingInheritedConstraint (TypeParameterSpec spec, TypeSpec ba, TypeSpec bb, IMemberContext context, Location loc)
  		{
  			if (ba == bb)
  				return true;
  
  			if (TypeSpec.IsBaseClass (ba, bb, false) || TypeSpec.IsBaseClass (bb, ba, false))
  				return true;
  
  			context.Module.Compiler.Report.Error (455, loc,
  				"Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
  				spec.Name, ba.GetSignatureForError (), bb.GetSignatureForError ());
  			return false;
  		}
  
  		public void CheckGenericConstraints (IMemberContext context)
  		{
  			foreach (var c in constraints) {
  				var ge = c as GenericTypeExpr;
  				if (ge != null)
  					ge.CheckConstraints (context);
  			}
  		}
  
  		//
  		// Resolve the constraints types with only possible early checks, return
  		// value `false' is reserved for recursive failure
  		//
  		public bool Resolve (IMemberContext context, TypeParameter tp)
  		{
  			if (resolved)
  				return true;
  
  			if (resolving)
  				return false;
  
  			resolving = true;
  			var spec = tp.Type;
  			List<TypeParameterSpec> tparam_types = null;
  			bool iface_found = false;
  
  			spec.BaseType = context.Module.Compiler.BuiltinTypes.Object;
  
  			for (int i = 0; i < constraints.Count; ++i) {
  				var constraint = constraints[i];
  
  				if (constraint is SpecialContraintExpr) {
  					spec.SpecialConstraint |= ((SpecialContraintExpr) constraint).Constraint;
  					if (spec.HasSpecialStruct)
  						spec.BaseType = context.Module.Compiler.BuiltinTypes.ValueType;
  
  					// Set to null as it does not have a type
  					constraints[i] = null;
  					continue;
  				}
  
  				var type_expr = constraints[i] = constraint.ResolveAsType (context);
  				if (type_expr == null)
  					continue;
  
  				var gexpr = type_expr as GenericTypeExpr;
  				if (gexpr != null && gexpr.HasDynamicArguments ()) {
  					context.Module.Compiler.Report.Error (1968, constraint.Location,
  						"A constraint cannot be the dynamic type `{0}'", gexpr.GetSignatureForError ());
  					continue;
  				}
  
  				var type = type_expr.Type;
  
  				if (!context.CurrentMemberDefinition.IsAccessibleAs (type)) {
  					context.Module.Compiler.Report.SymbolRelatedToPreviousError (type);
  					context.Module.Compiler.Report.Error (703, loc,
  						"Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'",
  						type.GetSignatureForError (), context.GetSignatureForError ());
  				}
  
  				if (type.IsInterface) {
  					if (!spec.AddInterface (type)) {
  						context.Module.Compiler.Report.Error (405, constraint.Location,
  							"Duplicate constraint `{0}' for type parameter `{1}'", type.GetSignatureForError (), tparam.Value);
  					}
  
  					iface_found = true;
  					continue;
  				}
  
  
  				var constraint_tp = type as TypeParameterSpec;
  				if (constraint_tp != null) {
  					if (tparam_types == null) {
  						tparam_types = new List<TypeParameterSpec> (2);
  					} else if (tparam_types.Contains (constraint_tp)) {
  						context.Module.Compiler.Report.Error (405, constraint.Location,
  							"Duplicate constraint `{0}' for type parameter `{1}'", type.GetSignatureForError (), tparam.Value);
  						continue;
  					}
  
  					//
  					// Checks whether each generic method parameter constraint type
  					// is valid with respect to T
  					//
  					if (tp.IsMethodTypeParameter) {
  						TypeManager.CheckTypeVariance (type, Variance.Contravariant, context);
  					}
  
  					var tp_def = constraint_tp.MemberDefinition as TypeParameter;
  					if (tp_def != null && !tp_def.ResolveConstraints (context)) {
  						context.Module.Compiler.Report.Error (454, constraint.Location,
  							"Circular constraint dependency involving `{0}' and `{1}'",
  							constraint_tp.GetSignatureForError (), tp.GetSignatureForError ());
  						continue;
  					}
  
  					//
  					// Checks whether there are no conflicts between type parameter constraints
  					//
  					// class Foo<T, U>
  					//      where T : A
  					//      where U : B, T
  					//
  					// A and B are not convertible and only 1 class constraint is allowed
  					//
  					if (constraint_tp.HasTypeConstraint) {
  						if (spec.HasTypeConstraint || spec.HasSpecialStruct) {
  							if (!CheckConflictingInheritedConstraint (spec, constraint_tp.BaseType, context, constraint.Location))
  								continue;
  						} else {
  							for (int ii = 0; ii < tparam_types.Count; ++ii) {
  								if (!tparam_types[ii].HasTypeConstraint)
  									continue;
  
  								if (!CheckConflictingInheritedConstraint (spec, tparam_types[ii].BaseType, constraint_tp.BaseType, context, constraint.Location))
  									break;
  							}
  						}
  					}
  
  					if (constraint_tp.HasSpecialStruct) {
  						context.Module.Compiler.Report.Error (456, constraint.Location,
  							"Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'",
  							constraint_tp.GetSignatureForError (), tp.GetSignatureForError ());
  						continue;
  					}
  
  					tparam_types.Add (constraint_tp);
  					continue;
  				}
  
  				if (iface_found || spec.HasTypeConstraint) {
  					context.Module.Compiler.Report.Error (406, constraint.Location,
  						"The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list",
  						type.GetSignatureForError ());
  				}
  
  				if (spec.HasSpecialStruct || spec.HasSpecialClass) {
  					context.Module.Compiler.Report.Error (450, type_expr.Location,
  						"`{0}': cannot specify both a constraint class and the `class' or `struct' constraint",
  						type.GetSignatureForError ());
  				}
  
  				switch (type.BuiltinType) {
  				case BuiltinTypeSpec.Type.Array:
  				case BuiltinTypeSpec.Type.Delegate:
  				case BuiltinTypeSpec.Type.MulticastDelegate:
  				case BuiltinTypeSpec.Type.Enum:
  				case BuiltinTypeSpec.Type.ValueType:
  				case BuiltinTypeSpec.Type.Object:
  					context.Module.Compiler.Report.Error (702, constraint.Location,
  						"A constraint cannot be special class `{0}'", type.GetSignatureForError ());
  					continue;
  				case BuiltinTypeSpec.Type.Dynamic:
  					context.Module.Compiler.Report.Error (1967, constraint.Location,
  						"A constraint cannot be the dynamic type");
  					continue;
  				}
  
  				if (type.IsSealed || !type.IsClass) {
  					context.Module.Compiler.Report.Error (701, loc,
  						"`{0}' is not a valid constraint. A constraint must be an interface, a non-sealed class or a type parameter",
  						TypeManager.CSharpName (type));
  					continue;
  				}
  
  				if (type.IsStatic) {
  					context.Module.Compiler.Report.Error (717, constraint.Location,
  						"`{0}' is not a valid constraint. Static classes cannot be used as constraints",
  						type.GetSignatureForError ());
  				}
  
  				spec.BaseType = type;
  			}
  
  			if (tparam_types != null)
  				spec.TypeArguments = tparam_types.ToArray ();
  
  			resolving = false;
  			resolved = true;
  			return true;
  		}
  
  		public void VerifyClsCompliance (Report report)
  		{
  			foreach (var c in constraints)
  			{
  				if (c == null)
  					continue;
  
  				if (!c.Type.IsCLSCompliant ()) {
  					report.SymbolRelatedToPreviousError (c.Type);
  					report.Warning (3024, 1, loc, "Constraint type `{0}' is not CLS-compliant",
  						c.Type.GetSignatureForError ());
  				}
  			}
  		}
  	}
  
  	//
  	// A type parameter for a generic type or generic method definition
  	//
  	public class TypeParameter : MemberCore, ITypeDefinition
  	{
  		static readonly string[] attribute_target = new string [] { "type parameter" };
  		
  		Constraints constraints;
  		GenericTypeParameterBuilder builder;
  		TypeParameterSpec spec;
  
  		public TypeParameter (DeclSpace parent, int index, MemberName name, Constraints constraints, Attributes attrs, Variance variance)
  			: base (parent, name, attrs)
  		{
  			this.constraints = constraints;
  			this.spec = new TypeParameterSpec (null, index, this, SpecialConstraint.None, variance, null);
  		}
  
  		public TypeParameter (TypeParameterSpec spec, DeclSpace parent, TypeSpec parentSpec, MemberName name, Attributes attrs)
  			: base (parent, name, attrs)
  		{
  			this.spec = new TypeParameterSpec (parentSpec, spec.DeclaredPosition, spec.MemberDefinition, spec.SpecialConstraint, spec.Variance, null) {
  				BaseType = spec.BaseType,
  				InterfacesDefined = spec.InterfacesDefined,
  				TypeArguments = spec.TypeArguments
  			};
  		}
  
  		#region Properties
  
  		public override AttributeTargets AttributeTargets {
  			get {
  				return AttributeTargets.GenericParameter;
  			}
  		}
  
  		public IAssemblyDefinition DeclaringAssembly {
  			get	{
  				return Module.DeclaringAssembly;
  			}
  		}
  
  		public override string DocCommentHeader {
  			get {
  				throw new InvalidOperationException (
  					"Unexpected attempt to get doc comment from " + this.GetType ());
  			}
  		}
  
  		public bool IsMethodTypeParameter {
  			get {
  				return spec.IsMethodOwned;
  			}
  		}
  
  		public string Namespace {
  			get {
  				return null;
  			}
  		}
  
  		public TypeParameterSpec Type {
  			get {
  				return spec;
  			}
  		}
  
  		public int TypeParametersCount {
  			get {
  				return 0;
  			}
  		}
  
  		public TypeParameterSpec[] TypeParameters {
  			get {
  				return null;
  			}
  		}
  
  		public override string[] ValidAttributeTargets {
  			get {
  				return attribute_target;
  			}
  		}
  
  		public Variance Variance {
  			get {
  				return spec.Variance;
  			}
  		}
  
  		public Constraints Constraints {
  			get {
  				return this.constraints;
  			}
  		}
  
  		#endregion
  
  		//
  		// This is called for each part of a partial generic type definition.
  		//
  		// If partial type parameters constraints are not null and we don't
  		// already have constraints they become our constraints. If we already
  		// have constraints, we must check that they're the same.
  		//
  		public bool AddPartialConstraints (TypeContainer part, TypeParameter tp)
  		{
  			if (builder == null)
  				throw new InvalidOperationException ();
  
  			var new_constraints = tp.constraints;
  			if (new_constraints == null)
  				return true;
  
  			// TODO: could create spec only
  			//tp.Define (null, -1, part.Definition);
  			tp.spec.DeclaringType = part.Definition;
  			if (!tp.ResolveConstraints (part))
  				return false;
  
  			if (constraints != null)
  				return spec.HasSameConstraintsDefinition (tp.Type);
  
  			// Copy constraint from resolved part to partial container
  			spec.SpecialConstraint = tp.spec.SpecialConstraint;
  			spec.InterfacesDefined = tp.spec.InterfacesDefined;
  			spec.TypeArguments = tp.spec.TypeArguments;
  			spec.BaseType = tp.spec.BaseType;
  			
  			return true;
  		}
  
  		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
  		{
  			builder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
  		}
  
  		public void CheckGenericConstraints ()
  		{
  			if (constraints != null)
  				constraints.CheckGenericConstraints (this);
  		}
  
  		public TypeParameter CreateHoistedCopy (TypeContainer declaringType, TypeSpec declaringSpec)
  		{
  			return new TypeParameter (spec, declaringType, declaringSpec, MemberName, null);
  		}
  
  		public override bool Define ()
  		{
  			return true;
  		}
  
  		//
  		// This is the first method which is called during the resolving
  		// process; we're called immediately after creating the type parameters
  		// with SRE (by calling `DefineGenericParameters()' on the TypeBuilder /
  		// MethodBuilder).
  		//
  		public void Define (GenericTypeParameterBuilder type, TypeSpec declaringType)
  		{
  			if (builder != null)
  				throw new InternalErrorException ();
  
  			this.builder = type;
  			spec.DeclaringType = declaringType;
  			spec.SetMetaInfo (type);
  		}
  
  		public void EmitConstraints (GenericTypeParameterBuilder builder)
  		{
  			var attr = GenericParameterAttributes.None;
  			if (spec.Variance == Variance.Contravariant)
  				attr |= GenericParameterAttributes.Contravariant;
  			else if (spec.Variance == Variance.Covariant)
  				attr |= GenericParameterAttributes.Covariant;
  
  			if (spec.HasSpecialClass)
  				attr |= GenericParameterAttributes.ReferenceTypeConstraint;
  			else if (spec.HasSpecialStruct)
  				attr |= GenericParameterAttributes.NotNullableValueTypeConstraint | GenericParameterAttributes.DefaultConstructorConstraint;
  
  			if (spec.HasSpecialConstructor)
  				attr |= GenericParameterAttributes.DefaultConstructorConstraint;
  
  			if (spec.BaseType.BuiltinType != BuiltinTypeSpec.Type.Object)
  				builder.SetBaseTypeConstraint (spec.BaseType.GetMetaInfo ());
  
  			if (spec.InterfacesDefined != null)
  				builder.SetInterfaceConstraints (spec.InterfacesDefined.Select (l => l.GetMetaInfo ()).ToArray ());
  
  			if (spec.TypeArguments != null)
  				builder.SetInterfaceConstraints (spec.TypeArguments.Select (l => l.GetMetaInfo ()).ToArray ());
  
  			builder.SetGenericParameterAttributes (attr);
  		}
  
  		public override void Emit ()
  		{
  			EmitConstraints (builder);
  
  			if (OptAttributes != null)
  				OptAttributes.Emit ();
  
  			base.Emit ();
  		}
  
  		public void ErrorInvalidVariance (IMemberContext mc, Variance expected)
  		{
  			Report.SymbolRelatedToPreviousError (mc.CurrentMemberDefinition);
  			string input_variance = Variance == Variance.Contravariant ? "contravariant" : "covariant";
  			string gtype_variance;
  			switch (expected) {
  			case Variance.Contravariant: gtype_variance = "contravariantly"; break;
  			case Variance.Covariant: gtype_variance = "covariantly"; break;
  			default: gtype_variance = "invariantly"; break;
  			}
  
  			Delegate d = mc as Delegate;
  			string parameters = d != null ? d.Parameters.GetSignatureForError () : "";
  
  			Report.Error (1961, Location,
  				"The {2} type parameter `{0}' must be {3} valid on `{1}{4}'",
  					GetSignatureForError (), mc.GetSignatureForError (), input_variance, gtype_variance, parameters);
  		}
  
  		public TypeSpec GetAttributeCoClass ()
  		{
  			return null;
  		}
  
  		public string GetAttributeDefaultMember ()
  		{
  			throw new NotSupportedException ();
  		}
  
  		public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
  		{
  			throw new NotSupportedException ();
  		}
  
  		public override string GetSignatureForDocumentation ()
  		{
  			throw new NotImplementedException ();
  		}
  
  		public override string GetSignatureForError ()
  		{
  			return MemberName.Name;
  		}
  
  		bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
  		{
  			return spec.GetEffectiveBase ().MemberDefinition.DeclaringAssembly == assembly;
  		}
  
  		public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
  		{
  			throw new NotSupportedException ("Not supported for compiled definition");
  		}
  
  		//
  		// Resolves all type parameter constraints
  		//
  		public bool ResolveConstraints (IMemberContext context)
  		{
  			if (constraints != null)
  				return constraints.Resolve (context, this);
  
  			if (spec.BaseType == null)
  				spec.BaseType = context.Module.Compiler.BuiltinTypes.Object;
  
  			return true;
  		}
  
  		public static TypeParameter FindTypeParameter (TypeParameter[] tparams, string name)
  		{
  			foreach (var tp in tparams) {
  				if (tp.Name == name)
  					return tp;
  			}
  
  			return null;
  		}
  
  		public override bool IsClsComplianceRequired ()
  		{
  			return false;
  		}
  
  		public new void VerifyClsCompliance ()
  		{
  			if (constraints != null)
  				constraints.VerifyClsCompliance (Report);
  		}
  	}
  
  	[System.Diagnostics.DebuggerDisplay ("{DisplayDebugInfo()}")]
  	public class TypeParameterSpec : TypeSpec
  	{
  		public static readonly new TypeParameterSpec[] EmptyTypes = new TypeParameterSpec[0];
  
  		Variance variance;
  		SpecialConstraint spec;
  		readonly int tp_pos;
  		TypeSpec[] targs;
  		TypeSpec[] ifaces_defined;
  
  		//
  		// Creates type owned type parameter
  		//
  		public TypeParameterSpec (TypeSpec declaringType, int index, ITypeDefinition definition, SpecialConstraint spec, Variance variance, MetaType info)
  			: base (MemberKind.TypeParameter, declaringType, definition, info, Modifiers.PUBLIC)
  		{
  			this.variance = variance;
  			this.spec = spec;
  			state &= ~StateFlags.Obsolete_Undetected;
  			tp_pos = index;
  		}
  
  		//
  		// Creates method owned type parameter
  		//
  		public TypeParameterSpec (int index, ITypeDefinition definition, SpecialConstraint spec, Variance variance, MetaType info)
  			: this (null, index, definition, spec, variance, info)
  		{
  		}
  
  		#region Properties
  
  		public int DeclaredPosition {
  			get {
  				return tp_pos;
  			}
  		}
  
  		public bool HasSpecialConstructor {
  			get {
  				return (spec & SpecialConstraint.Constructor) != 0;
  			}
  		}
  
  		public bool HasSpecialClass {
  			get {
  				return (spec & SpecialConstraint.Class) != 0;
  			}
  		}
  
  		public bool HasSpecialStruct {
  			get {
  				return (spec & SpecialConstraint.Struct) != 0;
  			}
  		}
  
  		public bool HasTypeConstraint {
  			get {
  				var bt = BaseType.BuiltinType;
  				return bt != BuiltinTypeSpec.Type.Object && bt != BuiltinTypeSpec.Type.ValueType;
  			}
  		}
  
  		public override IList<TypeSpec> Interfaces {
  			get {
  				if ((state & StateFlags.InterfacesExpanded) == 0) {
  					if (ifaces != null) {
  						for (int i = 0; i < ifaces.Count; ++i ) {
  							var iface_type = ifaces[i];
  							if (iface_type.Interfaces != null) {
  								if (ifaces_defined == null)
  									ifaces_defined = ifaces.ToArray ();
  
  								for (int ii = 0; ii < iface_type.Interfaces.Count; ++ii) {
  									var ii_iface_type = iface_type.Interfaces [ii];
  
  									AddInterface (ii_iface_type);
  								}
  							}
  						}
  					}
  
  					if (ifaces_defined == null && ifaces != null)
  						ifaces_defined = ifaces.ToArray ();
  
  					state |= StateFlags.InterfacesExpanded;
  				}
  
  				return ifaces;
  			}
  		}
  
  		//
  		// Unexpanded interfaces list
  		//
  		public TypeSpec[] InterfacesDefined {
  			get {
  				if (ifaces_defined == null && ifaces != null)
  					ifaces_defined = ifaces.ToArray ();
  
  				return ifaces_defined;
  			}
  			set {
  				ifaces = ifaces_defined = value;
  			}
  		}
  
  		public bool IsConstrained {
  			get {
  				return spec != SpecialConstraint.None || ifaces != null || targs != null || HasTypeConstraint;
  			}
  		}
  
  		//
  		// Returns whether the type parameter is "known to be a reference type"
  		//
  		public bool IsReferenceType {
  			get {
  				if ((spec & SpecialConstraint.Class) != 0 || HasTypeConstraint)
  					return true;
  
  				if (targs != null) {
  					foreach (var ta in targs) {
  						if (TypeManager.IsReferenceType (ta))
  							return true;
  					}
  				}
  
  				return false;
  			}
  		}
  
  		public bool IsValueType {	// TODO: Do I need this ?
  			get {
  				// TODO MemberCache: probably wrong
  				return HasSpecialStruct;
  			}
  		}
  
  		public override string Name {
  			get {
  				return definition.Name;
  			}
  		}
  
  		public bool IsMethodOwned {
  			get {
  				return DeclaringType == null;
  			}
  		}
  
  		public SpecialConstraint SpecialConstraint {
  			get {
  				return spec;
  			}
  			set {
  				spec = value;
  			}
  		}
  
  		//
  		// Types used to inflate the generic type
  		//
  		public new TypeSpec[] TypeArguments {
  			get {
  				return targs;
  			}
  			set {
  				targs = value;
  			}
  		}
  
  		public Variance Variance {
  			get {
  				return variance;
  			}
  		}
  
  		#endregion
  
  		public void ChangeTypeArgumentToBaseType (int index)
  		{
  			BaseType = targs [index];
  			if (targs.Length == 1) {
  				targs = null;
  			} else {
  				var copy = new TypeSpec[targs.Length - 1];
  				if (index > 0)
  					Array.Copy (targs, copy, index);
  
  				Array.Copy (targs, index + 1, copy, index, targs.Length - index - 1);
  				targs = copy;
  			}
  		}
  
  		public string DisplayDebugInfo ()
  		{
  			var s = GetSignatureForError ();
  			return IsMethodOwned ? s + "!!" : s + "!";
  		}
  
  		//
  		// Finds effective base class
  		//
  		public TypeSpec GetEffectiveBase ()
  		{
  			if (HasSpecialStruct)
  				return BaseType;
  
  			if (BaseType != null && targs == null)
  				return BaseType;
  
  			var types = targs;
  			if (HasTypeConstraint) {
  				Array.Resize (ref types, types.Length + 1);
  				types[types.Length - 1] = BaseType;
  			}
  
  			if (types != null)
  				return Convert.FindMostEncompassedType (types.Select (l => l.BaseType));
  
  			return BaseType;
  		}
  
  		public override string GetSignatureForDocumentation ()
  		{
  			int c = 0;
  			var type = DeclaringType;
  			while (type != null && type.DeclaringType != null) {
  				type = type.DeclaringType;
  				c += type.MemberDefinition.TypeParametersCount;
  			}
  
  			var prefix = IsMethodOwned ? "``" : "`";
  			return prefix + (c + DeclaredPosition);
  		}
  
  		public override string GetSignatureForError ()
  		{
  			return Name;
  		}
  
  		//
  		// Constraints have to match by definition but not position, used by
  		// partial classes or methods
  		//
  		public bool HasSameConstraintsDefinition (TypeParameterSpec other)
  		{
  			if (spec != other.spec)
  				return false;
  
  			if (BaseType != other.BaseType)
  				return false;
  
  			if (!TypeSpecComparer.Override.IsSame (InterfacesDefined, other.InterfacesDefined))
  				return false;
  
  			if (!TypeSpecComparer.Override.IsSame (targs, other.targs))
  				return false;
  
  			return true;
  		}
  
  		//
  		// Constraints have to match by using same set of types, used by
  		// implicit interface implementation
  		//
  		public bool HasSameConstraintsImplementation (TypeParameterSpec other)
  		{
  			if (spec != other.spec)
  				return false;
  
  			//
  			// It can be same base type or inflated type parameter
  			//
  			// interface I<T> { void Foo<U> where U : T; }
  			// class A : I<int> { void Foo<X> where X : int {} }
  			//
  			bool found;
  			if (!TypeSpecComparer.Override.IsEqual (BaseType, other.BaseType)) {
  				if (other.targs == null)
  					return false;
  
  				found = false;
  				foreach (var otarg in other.targs) {
  					if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) {
  						found = true;
  						break;
  					}
  				}
  
  				if (!found)
  					return false;
  			}
  
  			// Check interfaces implementation -> definition
  			if (InterfacesDefined != null) {
  				foreach (var iface in InterfacesDefined) {
  					found = false;
  					if (other.InterfacesDefined != null) {
  						foreach (var oiface in other.InterfacesDefined) {
  							if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
  								found = true;
  								break;
  							}
  						}
  					}
  
  					if (found)
  						continue;
  
  					if (other.targs != null) {
  						foreach (var otarg in other.targs) {
  							if (TypeSpecComparer.Override.IsEqual (BaseType, otarg)) {
  								found = true;
  								break;
  							}
  						}
  					}
  
  					if (!found)
  						return false;
  				}
  			}
  
  			// Check interfaces implementation <- definition
  			if (other.InterfacesDefined != null) {
  				if (InterfacesDefined == null)
  					return false;
  
  				foreach (var oiface in other.InterfacesDefined) {
  					found = false;
  					foreach (var iface in InterfacesDefined) {
  						if (TypeSpecComparer.Override.IsEqual (iface, oiface)) {
  							found = true;
  							break;
  						}
  					}
  
  					if (!found)
  						return false;
  				}
  			}
  
  			// Check type parameters implementation -> definition
  			if (targs != null) {
  				if (other.targs == null)
  					return false;
  
  				foreach (var targ in targs) {
  					found = false;
  					foreach (var otarg in other.targs) {
  						if (TypeSpecComparer.Override.IsEqual (targ, otarg)) {
  							found = true;
  							break;
  						}
  					}
  
  					if (!found)
  						return false;
  				}
  			}
  
  			// Check type parameters implementation <- definition
  			if (other.targs != null) {
  				foreach (var otarg in other.targs) {
  					// Ignore inflated type arguments, were checked above
  					if (!otarg.IsGenericParameter)
  						continue;
  
  					if (targs == null)
  						return false;
  
  					found = false;
  					foreach (var targ in targs) {
  						if (TypeSpecComparer.Override.IsEqual (targ, otarg)) {
  							found = true;
  							break;
  						}
  					}
  
  					if (!found)
  						return false;
  				}				
  			}
  
  			return true;
  		}
  
  		public static TypeParameterSpec[] InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec[] tparams)
  		{
  			return InflateConstraints (tparams, l => l, inflator);
  		}
  
  		public static TypeParameterSpec[] InflateConstraints<T> (TypeParameterSpec[] tparams, Func<T, TypeParameterInflator> inflatorFactory, T arg)
  		{
  			TypeParameterSpec[] constraints = null;
  			TypeParameterInflator? inflator = null;
  
  			for (int i = 0; i < tparams.Length; ++i) {
  				var tp = tparams[i];
  				if (tp.HasTypeConstraint || tp.InterfacesDefined != null || tp.TypeArguments != null) {
  					if (constraints == null) {
  						constraints = new TypeParameterSpec[tparams.Length];
  						Array.Copy (tparams, constraints, constraints.Length);
  					}
  
  					//
  					// Using a factory to avoid possibly expensive inflator build up
  					//
  					if (inflator == null)
  						inflator = inflatorFactory (arg);
  
  					constraints[i] = (TypeParameterSpec) constraints[i].InflateMember (inflator.Value);
  				}
  			}
  
  			if (constraints == null)
  				constraints = tparams;
  
  			return constraints;
  		}
  
  		public void InflateConstraints (TypeParameterInflator inflator, TypeParameterSpec tps)
  		{
  			tps.BaseType = inflator.Inflate (BaseType);
  			if (ifaces != null) {
  				tps.ifaces = new List<TypeSpec> (ifaces.Count);
  				for (int i = 0; i < ifaces.Count; ++i)
  					tps.ifaces.Add (inflator.Inflate (ifaces[i]));
  			}
  
  			if (targs != null) {
  				tps.targs = new TypeSpec[targs.Length];
  				for (int i = 0; i < targs.Length; ++i)
  					tps.targs[i] = inflator.Inflate (targs[i]);
  			}
  		}
  
  		public override MemberSpec InflateMember (TypeParameterInflator inflator)
  		{
  			var tps = (TypeParameterSpec) MemberwiseClone ();
  			InflateConstraints (inflator, tps);
  			return tps;
  		}
  
  		//
  		// Populates type parameter members using type parameter constraints
  		// The trick here is to be called late enough but not too late to
  		// populate member cache with all members from other types
  		//
  		protected override void InitializeMemberCache (bool onlyTypes)
  		{
  
gt: 			cache = new MemberCache ();