Click here to Skip to main content
15,885,871 members
Articles / Containers / Virtual Machine

Hacking the Mono C# Compiler.

Rate me:
Please Sign up or sign in to vote.
5.00/5 (12 votes)
9 Oct 2010CPOL7 min read 56.3K   1.5K   41  
Describes how to dump information from the C# parse tree
//
// 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.Reflection;
using System.Reflection.Emit;
using System.Globalization;
using System.Collections;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;
	
namespace Mono.CSharp {

	/// <summary>
	///   Abstract base class for type parameter constraints.
	///   The type parameter can come from a generic type definition or from reflection.
	/// </summary>
	public abstract class GenericConstraints {
		public abstract string TypeParameter {
			get;
		}

		public abstract GenericParameterAttributes Attributes {
			get;
		}

		public bool HasConstructorConstraint {
			get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
		}

		public bool HasReferenceTypeConstraint {
			get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
		}

		public bool HasValueTypeConstraint {
			get { return (Attributes & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0; }
		}

		public virtual bool HasClassConstraint {
			get { return ClassConstraint != null; }
		}

		public abstract Type ClassConstraint {
			get;
		}

		public abstract Type[] InterfaceConstraints {
			get;
		}

		public abstract Type EffectiveBaseClass {
			get;
		}

		// <summary>
		//   Returns whether the type parameter is "known to be a reference type".
		// </summary>
		public virtual bool IsReferenceType {
			get {
				if (HasReferenceTypeConstraint)
					return true;
				if (HasValueTypeConstraint)
					return false;

				if (ClassConstraint != null) {
					if (ClassConstraint.IsValueType)
						return false;

					if (ClassConstraint != TypeManager.object_type)
						return true;
				}

				foreach (Type t in InterfaceConstraints) {
					if (!t.IsGenericParameter)
						continue;

					GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
					if ((gc != null) && gc.IsReferenceType)
						return true;
				}

				return false;
			}
		}

		// <summary>
		//   Returns whether the type parameter is "known to be a value type".
		// </summary>
		public virtual bool IsValueType {
			get {
				if (HasValueTypeConstraint)
					return true;
				if (HasReferenceTypeConstraint)
					return false;

				if (ClassConstraint != null) {
					if (!TypeManager.IsValueType (ClassConstraint))
						return false;

					if (ClassConstraint != TypeManager.value_type)
						return true;
				}

				foreach (Type t in InterfaceConstraints) {
					if (!t.IsGenericParameter)
						continue;

					GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
					if ((gc != null) && gc.IsValueType)
						return true;
				}

				return false;
			}
		}
	}

	public class ReflectionConstraints : GenericConstraints
	{
		GenericParameterAttributes attrs;
		Type base_type;
		Type class_constraint;
		Type[] iface_constraints;
		string name;

		public static GenericConstraints GetConstraints (Type t)
		{
			Type[] constraints = t.GetGenericParameterConstraints ();
			GenericParameterAttributes attrs = t.GenericParameterAttributes;
			if (constraints.Length == 0 && attrs == GenericParameterAttributes.None)
				return null;
			return new ReflectionConstraints (t.Name, constraints, attrs);
		}

		private ReflectionConstraints (string name, Type[] constraints, GenericParameterAttributes attrs)
		{
			this.name = name;
			this.attrs = attrs;

			int interface_constraints_pos = 0;
			if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0) {
				base_type = TypeManager.value_type;
				interface_constraints_pos = 1;
			} else if ((attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0) {
				if (constraints.Length > 0 && constraints[0].IsClass) {
					class_constraint = base_type = constraints[0];
					interface_constraints_pos = 1;
				} else {
					base_type = TypeManager.object_type;
				}
			} else {
				base_type = TypeManager.object_type;
			}

			if (constraints.Length > interface_constraints_pos) {
				if (interface_constraints_pos == 0) {
					iface_constraints = constraints;
				} else {
					iface_constraints = new Type[constraints.Length - interface_constraints_pos];
					Array.Copy (constraints, interface_constraints_pos, iface_constraints, 0, iface_constraints.Length);
				}
			} else {
				iface_constraints = Type.EmptyTypes;
			}
		}

		public override string TypeParameter
		{
			get { return name; }
		}

		public override GenericParameterAttributes Attributes
		{
			get { return attrs; }
		}

		public override Type ClassConstraint
		{
			get { return class_constraint; }
		}

		public override Type EffectiveBaseClass
		{
			get { return base_type; }
		}

		public override Type[] InterfaceConstraints
		{
			get { return iface_constraints; }
		}
	}

	public enum Variance
	{
		//
		// Don't add or modify internal values, they are used as -/+ calculation signs
		//
		None			= 0,
		Covariant		= 1,
		Contravariant	= -1
	}

	public enum SpecialConstraint
	{
		Constructor,
		ReferenceType,
		ValueType
	}

	/// <summary>
	///   Tracks the constraints for a type parameter from a generic type definition.
	/// </summary>
	public class Constraints : GenericConstraints {
		string name;
		ArrayList constraints;
		Location loc;
		
		//
		// name is the identifier, constraints is an arraylist of
		// Expressions (with types) or `true' for the constructor constraint.
		// 
		public Constraints (string name, ArrayList constraints,
				    Location loc)
		{
			this.name = name;
			this.constraints = constraints;
			this.loc = loc;
		}

		public override string TypeParameter {
			get {
				return name;
			}
		}

		public Constraints Clone ()
		{
			return new Constraints (name, constraints, loc);
		}

		GenericParameterAttributes attrs;
		TypeExpr class_constraint;
		ArrayList iface_constraints;
		ArrayList type_param_constraints;
		int num_constraints;
		Type class_constraint_type;
		Type[] iface_constraint_types;
		Type effective_base_type;
		bool resolved;
		bool resolved_types;

		/// <summary>
		///   Resolve the constraints - but only resolve things into Expression's, not
		///   into actual types.
		/// </summary>
		public bool Resolve (MemberCore ec, TypeParameter tp, Report Report)
		{
			if (resolved)
				return true;

			if (ec == null)
				return false;

			iface_constraints = new ArrayList (2);	// TODO: Too expensive allocation
			type_param_constraints = new ArrayList ();

			foreach (object obj in constraints) {
				if (HasConstructorConstraint) {
					Report.Error (401, loc,
						      "The new() constraint must be the last constraint specified");
					return false;
				}

				if (obj is SpecialConstraint) {
					SpecialConstraint sc = (SpecialConstraint) obj;

					if (sc == SpecialConstraint.Constructor) {
						if (!HasValueTypeConstraint) {
							attrs |= GenericParameterAttributes.DefaultConstructorConstraint;
							continue;
						}

						Report.Error (451, loc, "The `new()' constraint " +
							"cannot be used with the `struct' constraint");
						return false;
					}

					if ((num_constraints > 0) || HasReferenceTypeConstraint || HasValueTypeConstraint) {
						Report.Error (449, loc, "The `class' or `struct' " +
							      "constraint must be the first constraint specified");
						return false;
					}

					if (sc == SpecialConstraint.ReferenceType)
						attrs |= GenericParameterAttributes.ReferenceTypeConstraint;
					else
						attrs |= GenericParameterAttributes.NotNullableValueTypeConstraint;
					continue;
				}

				int errors = Report.Errors;
				FullNamedExpression fn = ((Expression) obj).ResolveAsTypeStep (ec, false);

				if (fn == null) {
					if (errors != Report.Errors)
						return false;

					NamespaceEntry.Error_NamespaceNotFound (loc, ((Expression)obj).GetSignatureForError (), Report);
					return false;
				}

				TypeExpr expr;
				GenericTypeExpr cexpr = fn as GenericTypeExpr;
				if (cexpr != null) {
					expr = cexpr.ResolveAsBaseTerminal (ec, false);
				} else
					expr = ((Expression) obj).ResolveAsTypeTerminal (ec, false);

				if ((expr == null) || (expr.Type == null))
					return false;

				if (!ec.IsAccessibleAs (fn.Type)) {
					Report.SymbolRelatedToPreviousError (fn.Type);
					Report.Error (703, loc,
						"Inconsistent accessibility: constraint type `{0}' is less accessible than `{1}'",
						fn.GetSignatureForError (), ec.GetSignatureForError ());
					return false;
				}

				if (TypeManager.IsGenericParameter (expr.Type))
					type_param_constraints.Add (expr);
				else if (expr.IsInterface)
					iface_constraints.Add (expr);
				else if (class_constraint != null || iface_constraints.Count != 0) {
					Report.Error (406, loc,
						"The class type constraint `{0}' must be listed before any other constraints. Consider moving type constraint to the beginning of the constraint list",
						expr.GetSignatureForError ());
					return false;
				} else if (HasReferenceTypeConstraint || HasValueTypeConstraint) {
					Report.Error (450, loc, "`{0}': cannot specify both " +
						      "a constraint class and the `class' " +
						      "or `struct' constraint", expr.GetSignatureForError ());
					return false;
				} else
					class_constraint = expr;


				//
				// Checks whether each generic method parameter constraint type
				// is valid with respect to T
				//
				if (tp != null && tp.Type.DeclaringMethod != null) {
					TypeManager.CheckTypeVariance (expr.Type, Variance.Contravariant, ec as MemberCore);
				}

				num_constraints++;
			}

			ArrayList list = new ArrayList ();
			foreach (TypeExpr iface_constraint in iface_constraints) {
				foreach (Type type in list) {
					if (!type.Equals (iface_constraint.Type))
						continue;

					Report.Error (405, loc,
						      "Duplicate constraint `{0}' for type " +
						      "parameter `{1}'.", iface_constraint.GetSignatureForError (),
						      name);
					return false;
				}

				list.Add (iface_constraint.Type);
			}

			foreach (TypeExpr expr in type_param_constraints) {
				foreach (Type type in list) {
					if (!type.Equals (expr.Type))
						continue;

					Report.Error (405, loc,
						      "Duplicate constraint `{0}' for type " +
						      "parameter `{1}'.", expr.GetSignatureForError (), name);
					return false;
				}

				list.Add (expr.Type);
			}

			iface_constraint_types = new Type [list.Count];
			list.CopyTo (iface_constraint_types, 0);

			if (class_constraint != null) {
				class_constraint_type = class_constraint.Type;
				if (class_constraint_type == null)
					return false;

				if (class_constraint_type.IsSealed) {
					if (class_constraint_type.IsAbstract)
					{
						Report.Error (717, loc, "`{0}' is not a valid constraint. Static classes cannot be used as constraints",
							TypeManager.CSharpName (class_constraint_type));
					}
					else
					{
						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(class_constraint_type));
					}
					return false;
				}

				if ((class_constraint_type == TypeManager.array_type) ||
				    (class_constraint_type == TypeManager.delegate_type) ||
				    (class_constraint_type == TypeManager.enum_type) ||
				    (class_constraint_type == TypeManager.value_type) ||
				    (class_constraint_type == TypeManager.object_type) ||
					class_constraint_type == TypeManager.multicast_delegate_type) {
					Report.Error (702, loc,
							  "A constraint cannot be special class `{0}'",
						      TypeManager.CSharpName (class_constraint_type));
					return false;
				}

				if (TypeManager.IsDynamicType (class_constraint_type)) {
					Report.Error (1967, loc, "A constraint cannot be the dynamic type");
					return false;
				}
			}

			if (class_constraint_type != null)
				effective_base_type = class_constraint_type;
			else if (HasValueTypeConstraint)
				effective_base_type = TypeManager.value_type;
			else
				effective_base_type = TypeManager.object_type;

			if ((attrs & GenericParameterAttributes.NotNullableValueTypeConstraint) != 0)
				attrs |= GenericParameterAttributes.DefaultConstructorConstraint;

			resolved = true;
			return true;
		}

		bool CheckTypeParameterConstraints (Type tparam, ref TypeExpr prevConstraint, ArrayList seen, Report Report)
		{
			seen.Add (tparam);

			Constraints constraints = TypeManager.LookupTypeParameter (tparam).Constraints;
			if (constraints == null)
				return true;

			if (constraints.HasValueTypeConstraint) {
				Report.Error (456, loc,
					"Type parameter `{0}' has the `struct' constraint, so it cannot be used as a constraint for `{1}'",
					tparam.Name, name);
				return false;
			}

			//
			//  Checks whether there are no conflicts between type parameter constraints
			//
			//   class Foo<T, U>
			//      where T : A
			//      where U : A, B	// A and B are not convertible
			//
			if (constraints.HasClassConstraint) {
				if (prevConstraint != null) {
					Type t2 = constraints.ClassConstraint;
					TypeExpr e2 = constraints.class_constraint;

					if (!Convert.ImplicitReferenceConversionExists (prevConstraint, t2) &&
						!Convert.ImplicitReferenceConversionExists (e2, prevConstraint.Type)) {
						Report.Error (455, loc,
							"Type parameter `{0}' inherits conflicting constraints `{1}' and `{2}'",
							name, TypeManager.CSharpName (prevConstraint.Type), TypeManager.CSharpName (t2));
						return false;
					}
				}

				prevConstraint = constraints.class_constraint;
			}

			if (constraints.type_param_constraints == null)
				return true;

			foreach (TypeExpr expr in constraints.type_param_constraints) {
				if (seen.Contains (expr.Type)) {
					Report.Error (454, loc, "Circular constraint " +
						      "dependency involving `{0}' and `{1}'",
						      tparam.Name, expr.GetSignatureForError ());
					return false;
				}

				if (!CheckTypeParameterConstraints (expr.Type, ref prevConstraint, seen, Report))
					return false;
			}

			return true;
		}

		/// <summary>
		///   Resolve the constraints into actual types.
		/// </summary>
		public bool ResolveTypes (IMemberContext ec, Report r)
		{
			if (resolved_types)
				return true;

			resolved_types = true;

			foreach (object obj in constraints) {
				GenericTypeExpr cexpr = obj as GenericTypeExpr;
				if (cexpr == null)
					continue;

				if (!cexpr.CheckConstraints (ec))
					return false;
			}

			if (type_param_constraints.Count != 0) {
				ArrayList seen = new ArrayList ();
				TypeExpr prev_constraint = class_constraint;
				foreach (TypeExpr expr in type_param_constraints) {
					if (!CheckTypeParameterConstraints (expr.Type, ref prev_constraint, seen, r))
						return false;
					seen.Clear ();
				}
			}

			for (int i = 0; i < iface_constraints.Count; ++i) {
				TypeExpr iface_constraint = (TypeExpr) iface_constraints [i];
				iface_constraint = iface_constraint.ResolveAsTypeTerminal (ec, false);
				if (iface_constraint == null)
					return false;
				iface_constraints [i] = iface_constraint;
			}

			if (class_constraint != null) {
				class_constraint = class_constraint.ResolveAsTypeTerminal (ec, false);
				if (class_constraint == null)
					return false;
			}

			return true;
		}

		public override GenericParameterAttributes Attributes {
			get { return attrs; }
		}

		public override bool HasClassConstraint {
			get { return class_constraint != null; }
		}

		public override Type ClassConstraint {
			get { return class_constraint_type; }
		}

		public override Type[] InterfaceConstraints {
			get { return iface_constraint_types; }
		}

		public override Type EffectiveBaseClass {
			get { return effective_base_type; }
		}

		public bool IsSubclassOf (Type t)
		{
			if ((class_constraint_type != null) &&
			    class_constraint_type.IsSubclassOf (t))
				return true;

			if (iface_constraint_types == null)
				return false;

			foreach (Type iface in iface_constraint_types) {
				if (TypeManager.IsSubclassOf (iface, t))
					return true;
			}

			return false;
		}

		public Location Location {
			get {
				return loc;
			}
		}

		/// <summary>
		///   This is used when we're implementing a generic interface method.
		///   Each method type parameter in implementing method must have the same
		///   constraints than the corresponding type parameter in the interface
		///   method.  To do that, we're called on each of the implementing method's
		///   type parameters.
		/// </summary>
		public bool AreEqual (GenericConstraints gc)
		{
			if (gc.Attributes != attrs)
				return false;

			if (HasClassConstraint != gc.HasClassConstraint)
				return false;
			if (HasClassConstraint && !TypeManager.IsEqual (gc.ClassConstraint, ClassConstraint))
				return false;

			int gc_icount = gc.InterfaceConstraints != null ?
				gc.InterfaceConstraints.Length : 0;
			int icount = InterfaceConstraints != null ?
				InterfaceConstraints.Length : 0;

			if (gc_icount != icount)
				return false;

			for (int i = 0; i < gc.InterfaceConstraints.Length; ++i) {
				Type iface = gc.InterfaceConstraints [i];
				if (iface.IsGenericType)
					iface = iface.GetGenericTypeDefinition ();
				
				bool ok = false;
				for (int ii = 0; ii < InterfaceConstraints.Length; ii++) {
					Type check = InterfaceConstraints [ii];
					if (check.IsGenericType)
						check = check.GetGenericTypeDefinition ();
					
					if (TypeManager.IsEqual (iface, check)) {
						ok = true;
						break;
					}
				}

				if (!ok)
					return false;
			}

			return true;
		}

		public void VerifyClsCompliance (Report r)
		{
			if (class_constraint_type != null && !AttributeTester.IsClsCompliant (class_constraint_type))
				Warning_ConstrainIsNotClsCompliant (class_constraint_type, class_constraint.Location, r);

			if (iface_constraint_types != null) {
				for (int i = 0; i < iface_constraint_types.Length; ++i) {
					if (!AttributeTester.IsClsCompliant (iface_constraint_types [i]))
						Warning_ConstrainIsNotClsCompliant (iface_constraint_types [i],
							((TypeExpr)iface_constraints [i]).Location, r);
				}
			}
		}

		void Warning_ConstrainIsNotClsCompliant (Type t, Location loc, Report Report)
		{
			Report.SymbolRelatedToPreviousError (t);
			Report.Warning (3024, 1, loc, "Constraint type `{0}' is not CLS-compliant",
				TypeManager.CSharpName (t));
		}
	}

	/// <summary>
	///   A type parameter from a generic type definition.
	/// </summary>
	public class TypeParameter : MemberCore, IMemberContainer
	{
		static readonly string[] attribute_target = new string [] { "type parameter" };
		
		DeclSpace decl;
		GenericConstraints gc;
		Constraints constraints;
		GenericTypeParameterBuilder type;
		MemberCache member_cache;
		Variance variance;

        public override IEnumerable<IVisitable> GetChildren(object context)
        {
           return Visitable.Container().Single("decl", decl); 
        }

		public TypeParameter (DeclSpace parent, DeclSpace decl, string name,
				      Constraints constraints, Attributes attrs, Variance variance, Location loc)
			: base (parent, new MemberName (name, loc), attrs)
		{
			this.decl = decl;
			this.constraints = constraints;
			this.variance = variance;
		}

		public GenericConstraints GenericConstraints {
			get { return gc != null ? gc : constraints; }
		}

		public Constraints Constraints {
			get { return constraints; }
		}

		public DeclSpace DeclSpace {
			get { return decl; }
		}

		public Variance Variance {
			get { return variance; }
		}

		public Type Type {
			get { return type; }
		}

		/// <summary>
		///   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).
		///
		///   We're either called from TypeContainer.DefineType() or from
		///   GenericMethod.Define() (called from Method.Define()).
		/// </summary>
		public void Define (GenericTypeParameterBuilder type)
		{
			if (this.type != null)
				throw new InvalidOperationException ();

			this.type = type;
			TypeManager.AddTypeParameter (type, this);
		}

		public void ErrorInvalidVariance (IMemberContext mc, Variance expected)
		{
// TODO:	Report.SymbolRelatedToPreviousError (mc);
			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);
		}

		/// <summary>
		///   This is the second method which is called during the resolving
		///   process - in case of class type parameters, we're called from
		///   TypeContainer.ResolveType() - after it resolved the class'es
		///   base class and interfaces. For method type parameters, we're
		///   called immediately after Define().
		///
		///   We're just resolving the constraints into expressions here, we
		///   don't resolve them into actual types.
		///
		///   Note that in the special case of partial generic classes, we may be
		///   called _before_ Define() and we may also be called multiple types.
		/// </summary>
		public bool Resolve (DeclSpace ds)
		{
			if (constraints != null) {
				if (!constraints.Resolve (ds, this, Report)) {
					constraints = null;
					return false;
				}
			}

			return true;
		}

		/// <summary>
		///   This is the third method which is called during the resolving
		///   process.  We're called immediately after calling DefineConstraints()
		///   on all of the current class'es type parameters.
		///
		///   Our job is to resolve the constraints to actual types.
		///
		///   Note that we may have circular dependencies on type parameters - this
		///   is why Resolve() and ResolveType() are separate.
		/// </summary>
		public bool ResolveType (IMemberContext ec)
		{
			if (constraints != null) {
				if (!constraints.ResolveTypes (ec, Report)) {
					constraints = null;
					return false;
				}
			}

			return true;
		}

		/// <summary>
		///   This is the fourth and last method which is called during the resolving
		///   process.  We're called after everything is fully resolved and actually
		///   register the constraints with SRE and the TypeManager.
		/// </summary>
		public bool DefineType (IMemberContext ec)
		{
			return DefineType (ec, null, null, false);
		}

		/// <summary>
		///   This is the fith and last method which is called during the resolving
		///   process.  We're called after everything is fully resolved and actually
		///   register the constraints with SRE and the TypeManager.
		///
		///   The `builder', `implementing' and `is_override' arguments are only
		///   applicable to method type parameters.
		/// </summary>
		public bool DefineType (IMemberContext ec, MethodBuilder builder,
					MethodInfo implementing, bool is_override)
		{
			if (!ResolveType (ec))
				return false;

			if (implementing != null) {
				if (is_override && (constraints != null)) {
					Report.Error (460, Location,
						"`{0}': Cannot specify constraints for overrides or explicit interface implementation methods",
						TypeManager.CSharpSignature (builder));
					return false;
				}

				MethodBase mb = TypeManager.DropGenericMethodArguments (implementing);

				int pos = type.GenericParameterPosition;
				Type mparam = mb.GetGenericArguments () [pos];
				GenericConstraints temp_gc = ReflectionConstraints.GetConstraints (mparam);

				if (temp_gc != null)
					gc = new InflatedConstraints (temp_gc, implementing.DeclaringType);
				else if (constraints != null)
					gc = new InflatedConstraints (constraints, implementing.DeclaringType);

				bool ok = true;
				if (constraints != null) {
					if (temp_gc == null)
						ok = false;
					else if (!constraints.AreEqual (gc))
						ok = false;
				} else {
					if (!is_override && (temp_gc != null))
						ok = false;
				}

				if (!ok) {
					Report.SymbolRelatedToPreviousError (implementing);

					Report.Error (
						425, Location, "The constraints for type " +
						"parameter `{0}' of method `{1}' must match " +
						"the constraints for type parameter `{2}' " +
						"of interface method `{3}'. Consider using " +
						"an explicit interface implementation instead",
						Name, TypeManager.CSharpSignature (builder),
						TypeManager.CSharpName (mparam), TypeManager.CSharpSignature (mb));
					return false;
				}
			} else if (DeclSpace is CompilerGeneratedClass) {
				TypeParameter[] tparams = DeclSpace.TypeParameters;
				Type[] types = new Type [tparams.Length];
				for (int i = 0; i < tparams.Length; i++)
					types [i] = tparams [i].Type;

				if (constraints != null)
					gc = new InflatedConstraints (constraints, types);
			} else {
				gc = (GenericConstraints) constraints;
			}

			SetConstraints (type);
			return true;
		}

		public static TypeParameter FindTypeParameter (TypeParameter[] tparams, string name)
		{
			foreach (var tp in tparams) {
				if (tp.Name == name)
					return tp;
			}

			return null;
		}

		public void SetConstraints (GenericTypeParameterBuilder type)
		{
			GenericParameterAttributes attr = GenericParameterAttributes.None;
			if (variance == Variance.Contravariant)
				attr |= GenericParameterAttributes.Contravariant;
			else if (variance == Variance.Covariant)
				attr |= GenericParameterAttributes.Covariant;

			if (gc != null) {
				if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
					type.SetBaseTypeConstraint (gc.EffectiveBaseClass);

				attr |= gc.Attributes;
				type.SetInterfaceConstraints (gc.InterfaceConstraints);
				TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
			}
			
			type.SetGenericParameterAttributes (attr);
		}

		/// <summary>
		///   This is called for each part of a partial generic type definition.
		///
		///   If `new_constraints' is 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.
		///   con
		/// </summary>
		public bool UpdateConstraints (MemberCore ec, Constraints new_constraints)
		{
			if (type == null)
				throw new InvalidOperationException ();

			if (new_constraints == null)
				return true;

			if (!new_constraints.Resolve (ec, this, Report))
				return false;
			if (!new_constraints.ResolveTypes (ec, Report))
				return false;

			if (constraints != null) 
				return constraints.AreEqual (new_constraints);

			constraints = new_constraints;
			return true;
		}

		public override void Emit ()
		{
			if (OptAttributes != null)
				OptAttributes.Emit ();

			base.Emit ();
		}

		public override string DocCommentHeader {
			get {
				throw new InvalidOperationException (
					"Unexpected attempt to get doc comment from " + this.GetType () + ".");
			}
		}

		//
		// MemberContainer
		//

		public override bool Define ()
		{
			return true;
		}

		public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb, PredefinedAttributes pa)
		{
			type.SetCustomAttribute (cb);
		}

		public override AttributeTargets AttributeTargets {
			get {
				return AttributeTargets.GenericParameter;
			}
		}

		public override string[] ValidAttributeTargets {
			get {
				return attribute_target;
			}
		}

		//
		// IMemberContainer
		//

		string IMemberContainer.Name {
			get { return Name; }
		}

		MemberCache IMemberContainer.BaseCache {
			get {
				if (gc == null)
					return null;

				if (gc.EffectiveBaseClass.BaseType == null)
					return null;

				return TypeManager.LookupMemberCache (gc.EffectiveBaseClass.BaseType);
			}
		}

		bool IMemberContainer.IsInterface {
			get { return false; }
		}

		MemberList IMemberContainer.GetMembers (MemberTypes mt, BindingFlags bf)
		{
			throw new NotSupportedException ();
		}

		public MemberCache MemberCache {
			get {
				if (member_cache != null)
					return member_cache;

				if (gc == null)
					return null;

				Type[] ifaces = TypeManager.ExpandInterfaces (gc.InterfaceConstraints);
				member_cache = new MemberCache (this, gc.EffectiveBaseClass, ifaces);

				return member_cache;
			}
		}

		public MemberList FindMembers (MemberTypes mt, BindingFlags bf,
					       MemberFilter filter, object criteria)
		{
			if (gc == null)
				return MemberList.Empty;

			ArrayList members = new ArrayList ();

			if (gc.HasClassConstraint) {
				MemberList list = TypeManager.FindMembers (
					gc.ClassConstraint, mt, bf, filter, criteria);

				members.AddRange (list);
			}

			Type[] ifaces = TypeManager.ExpandInterfaces (gc.InterfaceConstraints);
			foreach (Type t in ifaces) {
				MemberList list = TypeManager.FindMembers (
					t, mt, bf, filter, criteria);

				members.AddRange (list);
			}

			return new MemberList (members);
		}

		public bool IsSubclassOf (Type t)
		{
			if (type.Equals (t))
				return true;

			if (constraints != null)
				return constraints.IsSubclassOf (t);

			return false;
		}

		public void InflateConstraints (Type declaring)
		{
			if (constraints != null)
				gc = new InflatedConstraints (constraints, declaring);
		}
		
		public override bool IsClsComplianceRequired ()
		{
			return false;
		}

		protected class InflatedConstraints : GenericConstraints
		{
			GenericConstraints gc;
			Type base_type;
			Type class_constraint;
			Type[] iface_constraints;
			Type[] dargs;

			public InflatedConstraints (GenericConstraints gc, Type declaring)
				: this (gc, TypeManager.GetTypeArguments (declaring))
			{ }

			public InflatedConstraints (GenericConstraints gc, Type[] dargs)
			{
				this.gc = gc;
				this.dargs = dargs;

				ArrayList list = new ArrayList ();
				if (gc.HasClassConstraint)
					list.Add (inflate (gc.ClassConstraint));
				foreach (Type iface in gc.InterfaceConstraints)
					list.Add (inflate (iface));

				bool has_class_constr = false;
				if (list.Count > 0) {
					Type first = (Type) list [0];
					has_class_constr = !first.IsGenericParameter && !first.IsInterface;
				}

				if ((list.Count > 0) && has_class_constr) {
					class_constraint = (Type) list [0];
					iface_constraints = new Type [list.Count - 1];
					list.CopyTo (1, iface_constraints, 0, list.Count - 1);
				} else {
					iface_constraints = new Type [list.Count];
					list.CopyTo (iface_constraints, 0);
				}

				if (HasValueTypeConstraint)
					base_type = TypeManager.value_type;
				else if (class_constraint != null)
					base_type = class_constraint;
				else
					base_type = TypeManager.object_type;
			}

			Type inflate (Type t)
			{
				if (t == null)
					return null;
				if (t.IsGenericParameter)
					return t.GenericParameterPosition < dargs.Length ? dargs [t.GenericParameterPosition] : t;
				if (t.IsGenericType) {
					Type[] args = t.GetGenericArguments ();
					Type[] inflated = new Type [args.Length];

					for (int i = 0; i < args.Length; i++)
						inflated [i] = inflate (args [i]);

					t = t.GetGenericTypeDefinition ();
					t = t.MakeGenericType (inflated);
				}

				return t;
			}

			public override string TypeParameter {
				get { return gc.TypeParameter; }
			}

			public override GenericParameterAttributes Attributes {
				get { return gc.Attributes; }
			}

			public override Type ClassConstraint {
				get { return class_constraint; }
			}

			public override Type EffectiveBaseClass {
				get { return base_type; }
			}

			public override Type[] InterfaceConstraints {
				get { return iface_constraints; }
			}
		}
	}

	/// <summary>
	///   A TypeExpr which already resolved to a type parameter.
	/// </summary>
	public class TypeParameterExpr : TypeExpr {
		

		public TypeParameterExpr (TypeParameter type_parameter, Location loc)
		{
			this.type = type_parameter.Type;
			this.eclass = ExprClass.TypeParameter;
			this.loc = loc;
		}

        public override IEnumerable<IVisitable> GetChildrenX(object context)
        {
            return Visitable.Container();
        }

        public override string GetNameX()
        {
            return null;
        }

		protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
		{
			throw new NotSupportedException ();
		}

		public override FullNamedExpression ResolveAsTypeStep (IMemberContext ec, bool silent)
		{
			return this;
		}

		public override bool IsInterface {
			get { return false; }
		}

		public override bool CheckAccessLevel (IMemberContext ds)
		{
			return true;
		}
	}

	//
	// Tracks the type arguments when instantiating a generic type. It's used
	// by both type arguments and type parameters
	//
	public class TypeArguments {
		ArrayList args;
		Type[] atypes;

        public ArrayList GetArgs(){
            //if (args == null)
            //    return new ArrayList();
            return args;
        }
		
		public TypeArguments ()
		{
			args = new ArrayList ();
		}

		public TypeArguments (params FullNamedExpression[] types)
		{
			this.args = new ArrayList (types);
		}

		public void Add (FullNamedExpression type)
		{
			args.Add (type);
		}

		public void Add (TypeArguments new_args)
		{
			args.AddRange (new_args.args);
		}

		// TODO: Should be deleted
		public TypeParameterName[] GetDeclarations ()
		{
			return (TypeParameterName[]) args.ToArray (typeof (TypeParameterName));
		}

		/// <summary>
		///   We may only be used after Resolve() is called and return the fully
		///   resolved types.
		/// </summary>
		public Type[] Arguments {
			get {
				return atypes;
			}
		}

		public int Count {
			get {
				return args.Count;
			}
		}

		public string GetSignatureForError()
		{
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < Count; ++i)
			{
				Expression expr = (Expression)args [i];
				sb.Append(expr.GetSignatureForError());
				if (i + 1 < Count)
					sb.Append(',');
			}
			return sb.ToString();
		}

		/// <summary>
		///   Resolve the type arguments.
		/// </summary>
		public bool Resolve (IMemberContext ec)
		{
			if (atypes != null)
				return atypes.Length != 0;

			int count = args.Count;
			bool ok = true;

			atypes = new Type [count];

			for (int i = 0; i < count; i++){
				TypeExpr te = ((FullNamedExpression) args[i]).ResolveAsTypeTerminal (ec, false);
				if (te == null) {
					ok = false;
					continue;
				}

				atypes[i] = te.Type;

				if (te.Type.IsSealed && te.Type.IsAbstract) {
					ec.Compiler.Report.Error (718, te.Location, "`{0}': static classes cannot be used as generic arguments",
						te.GetSignatureForError ());
					ok = false;
				}

				if (te.Type.IsPointer || TypeManager.IsSpecialType (te.Type)) {
					ec.Compiler.Report.Error (306, te.Location,
						"The type `{0}' may not be used as a type argument",
						te.GetSignatureForError ());
					ok = false;
				}
			}

			if (!ok)
				atypes = Type.EmptyTypes;

			return ok;
		}

		public TypeArguments Clone ()
		{
			TypeArguments copy = new TypeArguments ();
			foreach (Expression ta in args)
				copy.args.Add (ta);

			return copy;
		}
	}

	public class TypeParameterName : SimpleName
	{
		Attributes attributes;
		Variance variance;

		public TypeParameterName (string name, Attributes attrs, Location loc)
			: this (name, attrs, Variance.None, loc)
		{
		}

		public TypeParameterName (string name, Attributes attrs, Variance variance, Location loc)
			: base (name, loc)
		{
			attributes = attrs;
			this.variance = variance;
		}

		public Attributes OptAttributes {
			get {
				return attributes;
			}
		}

		public Variance Variance {
			get {
				return variance;
			}
		}
	}

	/// <summary>
	///   A reference expression to generic type
	/// </summary>	
	class GenericTypeExpr : TypeExpr
	{
		TypeArguments args;
		Type[] gen_params;	// TODO: Waiting for constrains check cleanup
		Type open_type;

		//
		// Should be carefully used only with defined generic containers. Type parameters
		// can be used as type arguments in this case.
		//
		// TODO: This could be GenericTypeExpr specialization
		//
		public GenericTypeExpr (DeclSpace gType, Location l)
		{
			open_type = gType.TypeBuilder.GetGenericTypeDefinition ();

			args = new TypeArguments ();
			foreach (TypeParameter type_param in gType.TypeParameters)
				args.Add (new TypeParameterExpr (type_param, l));

			this.loc = l;
		}

		/// <summary>
		///   Instantiate the generic type `t' with the type arguments `args'.
		///   Use this constructor if you already know the fully resolved
		///   generic type.
		/// </summary>		
		public GenericTypeExpr (Type t, TypeArguments args, Location l)
		{
			open_type = t.GetGenericTypeDefinition ();

			loc = l;
			this.args = args;
		}

		public TypeArguments TypeArguments {
			get { return args; }
		}

        public override IEnumerable<IVisitable> GetChildrenX(object context)
        {
            return Visitable.Container();
        }

        public override string GetNameX()
        {
            return null;
        }

		public override string GetSignatureForError ()
		{
			return TypeManager.CSharpName (type);
		}

		protected override TypeExpr DoResolveAsTypeStep (IMemberContext ec)
		{
			if (eclass != ExprClass.Invalid)
				return this;

			eclass = ExprClass.Type;

			if (!args.Resolve (ec))
				return null;

			gen_params = open_type.GetGenericArguments ();
			Type[] atypes = args.Arguments;
			
			if (atypes.Length != gen_params.Length) {
				Namespace.Error_InvalidNumberOfTypeArguments (open_type, loc);
				return null;
			}

			//
			// Now bind the parameters
			//
			type = open_type.MakeGenericType (atypes);
			return this;
		}

		/// <summary>
		///   Check the constraints; we're called from ResolveAsTypeTerminal()
		///   after fully resolving the constructed type.
		/// </summary>
		public bool CheckConstraints (IMemberContext ec)
		{
			return ConstraintChecker.CheckConstraints (ec, open_type, gen_params, args.Arguments, loc);
		}
	
		public override bool CheckAccessLevel (IMemberContext mc)
		{
			return mc.CurrentTypeDefinition.CheckAccessLevel (open_type);
		}

		public override bool IsClass {
			get { return open_type.IsClass; }
		}

		public override bool IsValueType {
			get { return TypeManager.IsStruct (open_type); }
		}

		public override bool IsInterface {
			get { return open_type.IsInterface; }
		}

		public override bool IsSealed {
			get { return open_type.IsSealed; }
		}

		public override bool Equals (object obj)
		{
			GenericTypeExpr cobj = obj as GenericTypeExpr;
			if (cobj == null)
				return false;

			if ((type == null) || (cobj.type == null))
				return false;

			return type == cobj.type;
		}

		public override int GetHashCode ()
		{
			return base.GetHashCode ();
		}
	}

	public abstract class ConstraintChecker
	{
		protected readonly Type[] gen_params;
		protected readonly Type[] atypes;
		protected readonly Location loc;
		protected Report Report;

		protected ConstraintChecker (Type[] gen_params, Type[] atypes, Location loc, Report r)
		{
			this.gen_params = gen_params;
			this.atypes = atypes;
			this.loc = loc;
			this.Report = r;
		}

		/// <summary>
		///   Check the constraints; we're called from ResolveAsTypeTerminal()
		///   after fully resolving the constructed type.
		/// </summary>
		public bool CheckConstraints (IMemberContext ec)
		{
			for (int i = 0; i < gen_params.Length; i++) {
				if (!CheckConstraints (ec, i))
					return false;
			}

			return true;
		}

		protected bool CheckConstraints (IMemberContext ec, int index)
		{
			Type atype = atypes [index];
			Type ptype = gen_params [index];

			if (atype == ptype)
				return true;

			Expression aexpr = new EmptyExpression (atype);

			GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype);
			if (gc == null)
				return true;

			bool is_class, is_struct;
			if (atype.IsGenericParameter) {
				GenericConstraints agc = TypeManager.GetTypeParameterConstraints (atype);
				if (agc != null) {
					if (agc is Constraints) {
						// FIXME: No constraints can be resolved here, we are in
						// completely wrong/different context. This path is hit
						// when resolving base type of unresolved generic type
						// with constraints. We are waiting with CheckConsttraints
						// after type-definition but not in this case
						if (!((Constraints) agc).Resolve (null, null, Report))
							return true;
					}
					is_class = agc.IsReferenceType;
					is_struct = agc.IsValueType;
				} else {
					is_class = is_struct = false;
				}
			} else {
				is_class = TypeManager.IsReferenceType (atype);
				is_struct = TypeManager.IsValueType (atype) && !TypeManager.IsNullableType (atype);
			}

			//
			// First, check the `class' and `struct' constraints.
			//
			if (gc.HasReferenceTypeConstraint && !is_class) {
				Report.Error (452, loc, "The type `{0}' must be " +
					      "a reference type in order to use it " +
					      "as type parameter `{1}' in the " +
					      "generic type or method `{2}'.",
					      TypeManager.CSharpName (atype),
					      TypeManager.CSharpName (ptype),
					      GetSignatureForError ());
				return false;
			} else if (gc.HasValueTypeConstraint && !is_struct) {
				Report.Error (453, loc, "The type `{0}' must be a " +
					      "non-nullable value type in order to use it " +
					      "as type parameter `{1}' in the " +
					      "generic type or method `{2}'.",
					      TypeManager.CSharpName (atype),
					      TypeManager.CSharpName (ptype),
					      GetSignatureForError ());
				return false;
			}

			//
			// The class constraint comes next.
			//
			if (gc.HasClassConstraint) {
				if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint))
					return false;
			}

			//
			// Now, check the interface constraints.
			//
			if (gc.InterfaceConstraints != null) {
				foreach (Type it in gc.InterfaceConstraints) {
					if (!CheckConstraint (ec, ptype, aexpr, it))
						return false;
				}
			}

			//
			// Finally, check the constructor constraint.
			//

			if (!gc.HasConstructorConstraint)
				return true;

			if (TypeManager.IsValueType (atype))
				return true;

			if (HasDefaultConstructor (atype))
				return true;

			Report_SymbolRelatedToPreviousError ();
			Report.SymbolRelatedToPreviousError (atype);
			Report.Error (310, loc, "The type `{0}' must have a public " +
				      "parameterless constructor in order to use it " +
				      "as parameter `{1}' in the generic type or " +
				      "method `{2}'",
				      TypeManager.CSharpName (atype),
				      TypeManager.CSharpName (ptype),
				      GetSignatureForError ());
			return false;
		}

		protected bool CheckConstraint (IMemberContext ec, Type ptype, Expression expr,
						Type ctype)
		{
			//
			// All this is needed because we don't have
			// real inflated type hierarchy
			//
			if (TypeManager.HasGenericArguments (ctype)) {
				Type[] types = TypeManager.GetTypeArguments (ctype);

				TypeArguments new_args = new TypeArguments ();

				for (int i = 0; i < types.Length; i++) {
					Type t = TypeManager.TypeToCoreType (types [i]);

					if (t.IsGenericParameter) {
						int pos = t.GenericParameterPosition;
						if (t.DeclaringMethod == null && this is MethodConstraintChecker) {
							Type parent = ((MethodConstraintChecker) this).declaring_type;
							t = parent.GetGenericArguments ()[pos];
						} else {
							t = atypes [pos];
						}
					}
					new_args.Add (new TypeExpression (t, loc));
				}

				TypeExpr ct = new GenericTypeExpr (ctype, new_args, loc);
				if (ct.ResolveAsTypeStep (ec, false) == null)
					return false;
				ctype = ct.Type;
			} else if (ctype.IsGenericParameter) {
				int pos = ctype.GenericParameterPosition;
				if (ctype.DeclaringMethod == null) {
					// FIXME: Implement
					return true;
				} else {				
					ctype = atypes [pos];
				}
			}

			if (Convert.ImplicitStandardConversionExists (expr, ctype))
				return true;

			Report_SymbolRelatedToPreviousError ();
			Report.SymbolRelatedToPreviousError (expr.Type);

			if (TypeManager.IsNullableType (expr.Type) && ctype.IsInterface) {
				Report.Error (313, loc,
					"The type `{0}' cannot be used as type parameter `{1}' in the generic type or method `{2}'. " +
					"The nullable type `{0}' never satisfies interface constraint of type `{3}'",
					TypeManager.CSharpName (expr.Type), TypeManager.CSharpName (ptype),
					GetSignatureForError (), TypeManager.CSharpName (ctype));
			} else {
				Report.Error (309, loc,
					"The type `{0}' must be convertible to `{1}' in order to " +
					"use it as parameter `{2}' in the generic type or method `{3}'",
					TypeManager.CSharpName (expr.Type), TypeManager.CSharpName (ctype),
					TypeManager.CSharpName (ptype), GetSignatureForError ());
			}
			return false;
		}

		static bool HasDefaultConstructor (Type atype)
		{
			TypeParameter tparam = TypeManager.LookupTypeParameter (atype);
			if (tparam != null) {
				if (tparam.GenericConstraints == null)
					return false;
						
				return tparam.GenericConstraints.HasConstructorConstraint || 
					tparam.GenericConstraints.HasValueTypeConstraint;
			}
		
			if (atype.IsAbstract)
				return false;

		again:
			atype = TypeManager.DropGenericTypeArguments (atype);
			if (atype is TypeBuilder) {
				TypeContainer tc = TypeManager.LookupTypeContainer (atype);
				if (tc.InstanceConstructors == null) {
					atype = atype.BaseType;
					goto again;
				}

				foreach (Constructor c in tc.InstanceConstructors) {
					if ((c.ModFlags & Modifiers.PUBLIC) == 0)
						continue;
					if ((c.Parameters.FixedParameters != null) &&
					    (c.Parameters.FixedParameters.Length != 0))
						continue;
					if (c.Parameters.HasArglist || c.Parameters.HasParams)
						continue;

					return true;
				}
			}

			MemberInfo [] list = TypeManager.MemberLookup (null, null, atype, MemberTypes.Constructor,
				BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly,
				ConstructorInfo.ConstructorName, null);

			if (list == null)
				return false;

			foreach (MethodBase mb in list) {
				AParametersCollection pd = TypeManager.GetParameterData (mb);
				if (pd.Count == 0)
					return true;
			}

			return false;
		}

		protected abstract string GetSignatureForError ();
		protected abstract void Report_SymbolRelatedToPreviousError ();

		public static bool CheckConstraints (IMemberContext ec, MethodBase definition,
						     MethodBase instantiated, Location loc)
		{
			MethodConstraintChecker checker = new MethodConstraintChecker (
				definition, instantiated.DeclaringType, definition.GetGenericArguments (),
				instantiated.GetGenericArguments (), loc, ec.Compiler.Report);

			return checker.CheckConstraints (ec);
		}

		public static bool CheckConstraints (IMemberContext ec, Type gt, Type[] gen_params,
						     Type[] atypes, Location loc)
		{
			TypeConstraintChecker checker = new TypeConstraintChecker (
				gt, gen_params, atypes, loc, ec.Compiler.Report);

			return checker.CheckConstraints (ec);
		}

		protected class MethodConstraintChecker : ConstraintChecker
		{
			MethodBase definition;
			public Type declaring_type;

			public MethodConstraintChecker (MethodBase definition, Type declaringType, Type[] gen_params,
							Type[] atypes, Location loc, Report r)
				: base (gen_params, atypes, loc, r)
			{
				this.declaring_type = declaringType;
				this.definition = definition;
			}

			protected override string GetSignatureForError ()
			{
				return TypeManager.CSharpSignature (definition);
			}

			protected override void Report_SymbolRelatedToPreviousError ()
			{
				Report.SymbolRelatedToPreviousError (definition);
			}
		}

		protected class TypeConstraintChecker : ConstraintChecker
		{
			Type gt;

			public TypeConstraintChecker (Type gt, Type[] gen_params, Type[] atypes,
						      Location loc, Report r)
				: base (gen_params, atypes, loc, r)
			{
				this.gt = gt;
			}

			protected override string GetSignatureForError ()
			{
				return TypeManager.CSharpName (gt);
			}

			protected override void Report_SymbolRelatedToPreviousError ()
			{
				Report.SymbolRelatedToPreviousError (gt);
			}
		}
	}

	/// <summary>
	///   A generic method definition.
	/// </summary>
	public class GenericMethod : DeclSpace
	{
		FullNamedExpression return_type;
		ParametersCompiled parameters;

		public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name,
				      FullNamedExpression return_type, ParametersCompiled parameters)
			: base (ns, parent, name, null)
		{
			this.return_type = return_type;
			this.parameters = parameters;
		}

		public override TypeContainer CurrentTypeDefinition {
			get {
				return Parent.CurrentTypeDefinition;
			}
		}

		public override TypeParameter[] CurrentTypeParameters {
			get {
				return base.type_params;
			}
		}

		public override TypeBuilder DefineType ()
		{
			throw new Exception ();
		}

		public override bool Define ()
		{
			for (int i = 0; i < TypeParameters.Length; i++)
				if (!TypeParameters [i].Resolve (this))
					return false;

			return true;
		}

		/// <summary>
		///   Define and resolve the type parameters.
		///   We're called from Method.Define().
		/// </summary>
		public bool Define (MethodOrOperator m)
		{
			TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations ();
			string[] snames = new string [names.Length];
			for (int i = 0; i < names.Length; i++) {
				string type_argument_name = names[i].Name;
				int idx = parameters.GetParameterIndexByName (type_argument_name);
				if (idx >= 0) {
					Block b = m.Block;
					if (b == null)
						b = new Block (null);

					b.Error_AlreadyDeclaredTypeParameter (Report, parameters [i].Location,
						type_argument_name, "method parameter");
				}
				
				snames[i] = type_argument_name;
			}

			GenericTypeParameterBuilder[] gen_params = m.MethodBuilder.DefineGenericParameters (snames);
			for (int i = 0; i < TypeParameters.Length; i++)
				TypeParameters [i].Define (gen_params [i]);

			if (!Define ())
				return false;

			for (int i = 0; i < TypeParameters.Length; i++) {
				if (!TypeParameters [i].ResolveType (this))
					return false;
			}

			return true;
		}

		/// <summary>
		///   We're called from MethodData.Define() after creating the MethodBuilder.
		/// </summary>
		public bool DefineType (IMemberContext ec, MethodBuilder mb,
					MethodInfo implementing, bool is_override)
		{
			for (int i = 0; i < TypeParameters.Length; i++)
				if (!TypeParameters [i].DefineType (
					    ec, mb, implementing, is_override))
					return false;

			bool ok = parameters.Resolve (ec);

			if ((return_type != null) && (return_type.ResolveAsTypeTerminal (ec, false) == null))
				ok = false;

			return ok;
		}

		public void EmitAttributes ()
		{
			for (int i = 0; i < TypeParameters.Length; i++)
				TypeParameters [i].Emit ();

			if (OptAttributes != null)
				OptAttributes.Emit ();
		}

		public override MemberList FindMembers (MemberTypes mt, BindingFlags bf,
							MemberFilter filter, object criteria)
		{
			throw new Exception ();
		}

		public override string GetSignatureForError ()
		{
			return base.GetSignatureForError () + parameters.GetSignatureForError ();
		}

		public override MemberCache MemberCache {
			get {
				return null;
			}
		}

		public override AttributeTargets AttributeTargets {
			get {
				return AttributeTargets.Method | AttributeTargets.ReturnValue;
			}
		}

		public override string DocCommentHeader {
			get { return "M:"; }
		}

		public new void VerifyClsCompliance ()
		{
			foreach (TypeParameter tp in TypeParameters) {
				if (tp.Constraints == null)
					continue;

				tp.Constraints.VerifyClsCompliance (Report);
			}
		}
	}

	public partial class TypeManager
	{
		static public Type activator_type;
	
		public static TypeContainer LookupGenericTypeContainer (Type t)
		{
			t = DropGenericTypeArguments (t);
			return LookupTypeContainer (t);
		}

		public static Variance GetTypeParameterVariance (Type type)
		{
			TypeParameter tparam = LookupTypeParameter (type);
			if (tparam != null)
				return tparam.Variance;

			switch (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) {
			case GenericParameterAttributes.Covariant:
				return Variance.Covariant;
			case GenericParameterAttributes.Contravariant:
				return Variance.Contravariant;
			default:
				return Variance.None;
			}
		}

		public static Variance CheckTypeVariance (Type t, Variance expected, IMemberContext member)
		{
			TypeParameter tp = LookupTypeParameter (t);
			if (tp != null) {
				Variance v = tp.Variance;
				if (expected == Variance.None && v != expected ||
					expected == Variance.Covariant && v == Variance.Contravariant ||
					expected == Variance.Contravariant && v == Variance.Covariant)
					tp.ErrorInvalidVariance (member, expected);

				return expected;
			}

			if (t.IsGenericType) {
				Type[] targs_definition = GetTypeArguments (DropGenericTypeArguments (t));
				Type[] targs = GetTypeArguments (t);
				for (int i = 0; i < targs_definition.Length; ++i) {
					Variance v = GetTypeParameterVariance (targs_definition[i]);
					CheckTypeVariance (targs[i], (Variance) ((int)v * (int)expected), member);
				}

				return expected;
			}

			if (t.IsArray)
				return CheckTypeVariance (GetElementType (t), expected, member);

			return Variance.None;
		}

		public static bool IsVariantOf (Type type1, Type type2)
		{
			if (!type1.IsGenericType || !type2.IsGenericType)
				return false;

			Type generic_target_type = DropGenericTypeArguments (type2);
			if (DropGenericTypeArguments (type1) != generic_target_type)
				return false;

			Type[] t1 = GetTypeArguments (type1);
			Type[] t2 = GetTypeArguments (type2);
			Type[] targs_definition = GetTypeArguments (generic_target_type);
			for (int i = 0; i < targs_definition.Length; ++i) {
				Variance v = GetTypeParameterVariance (targs_definition [i]);
				if (v == Variance.None) {
					if (t1[i] == t2[i])
						continue;
					return false;
				}

				if (v == Variance.Covariant) {
					if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t1 [i]), t2 [i]))
						return false;
				} else if (!Convert.ImplicitReferenceConversionExists (new EmptyExpression (t2[i]), t1[i])) {
					return false;
				}
			}

			return true;
		}

		/// <summary>
		///   Check whether `a' and `b' may become equal generic types.
		///   The algorithm to do that is a little bit complicated.
		/// </summary>
		public static bool MayBecomeEqualGenericTypes (Type a, Type b, Type[] class_inferred,
							       Type[] method_inferred)
		{
			if (a.IsGenericParameter) {
				//
				// If a is an array of a's type, they may never
				// become equal.
				//
				while (b.IsArray) {
					b = GetElementType (b);
					if (a.Equals (b))
						return false;
				}

				//
				// If b is a generic parameter or an actual type,
				// they may become equal:
				//
				//    class X<T,U> : I<T>, I<U>
				//    class X<T> : I<T>, I<float>
				// 
				if (b.IsGenericParameter || !b.IsGenericType) {
					int pos = a.GenericParameterPosition;
					Type[] args = a.DeclaringMethod != null ? method_inferred : class_inferred;
					if (args [pos] == null) {
						args [pos] = b;
						return true;
					}

					return args [pos] == a;
				}

				//
				// We're now comparing a type parameter with a
				// generic instance.  They may become equal unless
				// the type parameter appears anywhere in the
				// generic instance:
				//
				//    class X<T,U> : I<T>, I<X<U>>
				//        -> error because you could instanciate it as
				//           X<X<int>,int>
				//
				//    class X<T> : I<T>, I<X<T>> -> ok
				//

				Type[] bargs = GetTypeArguments (b);
				for (int i = 0; i < bargs.Length; i++) {
					if (a.Equals (bargs [i]))
						return false;
				}

				return true;
			}

			if (b.IsGenericParameter)
				return MayBecomeEqualGenericTypes (b, a, class_inferred, method_inferred);

			//
			// At this point, neither a nor b are a type parameter.
			//
			// If one of them is a generic instance, let
			// MayBecomeEqualGenericInstances() compare them (if the
			// other one is not a generic instance, they can never
			// become equal).
			//

			if (a.IsGenericType || b.IsGenericType)
				return MayBecomeEqualGenericInstances (a, b, class_inferred, method_inferred);

			//
			// If both of them are arrays.
			//

			if (a.IsArray && b.IsArray) {
				if (a.GetArrayRank () != b.GetArrayRank ())
					return false;
			
				a = GetElementType (a);
				b = GetElementType (b);

				return MayBecomeEqualGenericTypes (a, b, class_inferred, method_inferred);
			}

			//
			// Ok, two ordinary types.
			//

			return a.Equals (b);
		}

		//
		// Checks whether two generic instances may become equal for some
		// particular instantiation (26.3.1).
		//
		public static bool MayBecomeEqualGenericInstances (Type a, Type b,
								   Type[] class_inferred,
								   Type[] method_inferred)
		{
			if (!a.IsGenericType || !b.IsGenericType)
				return false;
			if (a.GetGenericTypeDefinition () != b.GetGenericTypeDefinition ())
				return false;

			return MayBecomeEqualGenericInstances (
				GetTypeArguments (a), GetTypeArguments (b), class_inferred, method_inferred);
		}

		public static bool MayBecomeEqualGenericInstances (Type[] aargs, Type[] bargs,
								   Type[] class_inferred,
								   Type[] method_inferred)
		{
			if (aargs.Length != bargs.Length)
				return false;

			for (int i = 0; i < aargs.Length; i++) {
				if (!MayBecomeEqualGenericTypes (aargs [i], bargs [i], class_inferred, method_inferred))
					return false;
			}

			return true;
		}

		/// <summary>
		///   Type inference.  Try to infer the type arguments from `method',
		///   which is invoked with the arguments `arguments'.  This is used
		///   when resolving an Invocation or a DelegateInvocation and the user
		///   did not explicitly specify type arguments.
		/// </summary>
		public static int InferTypeArguments (ResolveContext ec, Arguments arguments, ref MethodBase method)
		{
			ATypeInference ti = ATypeInference.CreateInstance (arguments);
			Type[] i_args = ti.InferMethodArguments (ec, method);
			if (i_args == null)
				return ti.InferenceScore;

			if (i_args.Length == 0)
				return 0;

			method = ((MethodInfo) method).MakeGenericMethod (i_args);
			return 0;
		}

/*
		public static bool InferTypeArguments (ResolveContext ec, AParametersCollection param, ref MethodBase method)
		{
			if (!TypeManager.IsGenericMethod (method))
				return true;

			ATypeInference ti = ATypeInference.CreateInstance (DelegateCreation.CreateDelegateMethodArguments (param, Location.Null));
			Type[] i_args = ti.InferDelegateArguments (ec, method);
			if (i_args == null)
				return false;

			method = ((MethodInfo) method).MakeGenericMethod (i_args);
			return true;
		}
*/
	}

	abstract class ATypeInference
	{
		protected readonly Arguments arguments;
		protected readonly int arg_count;

		protected ATypeInference (Arguments arguments)
		{
			this.arguments = arguments;
			if (arguments != null)
				arg_count = arguments.Count;
		}

		public static ATypeInference CreateInstance (Arguments arguments)
		{
			return new TypeInference (arguments);
		}

		public virtual int InferenceScore {
			get {
				return int.MaxValue;
			}
		}

		public abstract Type[] InferMethodArguments (ResolveContext ec, MethodBase method);
//		public abstract Type[] InferDelegateArguments (ResolveContext ec, MethodBase method);
	}

	//
	// Implements C# type inference
	//
	class TypeInference : ATypeInference
	{
		//
		// Tracks successful rate of type inference
		//
		int score = int.MaxValue;

		public TypeInference (Arguments arguments)
			: base (arguments)
		{
		}

		public override int InferenceScore {
			get {
				return score;
			}
		}

/*
		public override Type[] InferDelegateArguments (ResolveContext ec, MethodBase method)
		{
			AParametersCollection pd = TypeManager.GetParameterData (method);
			if (arg_count != pd.Count)
				return null;

			Type[] d_gargs = method.GetGenericArguments ();
			TypeInferenceContext context = new TypeInferenceContext (d_gargs);

			// A lower-bound inference is made from each argument type Uj of D
			// to the corresponding parameter type Tj of M
			for (int i = 0; i < arg_count; ++i) {
				Type t = pd.Types [i];
				if (!t.IsGenericParameter)
					continue;

				context.LowerBoundInference (arguments [i].Expr.Type, t);
			}

			if (!context.FixAllTypes (ec))
				return null;

			return context.InferredTypeArguments;
		}
*/
		public override Type[] InferMethodArguments (ResolveContext ec, MethodBase method)
		{
			Type[] method_generic_args = method.GetGenericArguments ();
			TypeInferenceContext context = new TypeInferenceContext (method_generic_args);
			if (!context.UnfixedVariableExists)
				return Type.EmptyTypes;

			AParametersCollection pd = TypeManager.GetParameterData (method);
			if (!InferInPhases (ec, context, pd))
				return null;

			return context.InferredTypeArguments;
		}

		//
		// Implements method type arguments inference
		//
		bool InferInPhases (ResolveContext ec, TypeInferenceContext tic, AParametersCollection methodParameters)
		{
			int params_arguments_start;
			if (methodParameters.HasParams) {
				params_arguments_start = methodParameters.Count - 1;
			} else {
				params_arguments_start = arg_count;
			}

			Type [] ptypes = methodParameters.Types;
			
			//
			// The first inference phase
			//
			Type method_parameter = null;
			for (int i = 0; i < arg_count; i++) {
				Argument a = arguments [i];
				if (a == null)
					continue;
				
				if (i < params_arguments_start) {
					method_parameter = methodParameters.Types [i];
				} else if (i == params_arguments_start) {
					if (arg_count == params_arguments_start + 1 && TypeManager.HasElementType (a.Type))
						method_parameter = methodParameters.Types [params_arguments_start];
					else
						method_parameter = TypeManager.GetElementType (methodParameters.Types [params_arguments_start]);

					ptypes = (Type[]) ptypes.Clone ();
					ptypes [i] = method_parameter;
				}

				//
				// When a lambda expression, an anonymous method
				// is used an explicit argument type inference takes a place
				//
				AnonymousMethodExpression am = a.Expr as AnonymousMethodExpression;
				if (am != null) {
					if (am.ExplicitTypeInference (ec, tic, method_parameter))
						--score; 
					continue;
				}

				if (a.IsByRef) {
					score -= tic.ExactInference (a.Type, method_parameter);
					continue;
				}

				if (a.Expr.Type == TypeManager.null_type)
					continue;

				if (TypeManager.IsValueType (method_parameter)) {
					score -= tic.LowerBoundInference (a.Type, method_parameter);
					continue;
				}

				//
				// Otherwise an output type inference is made
				//
				score -= tic.OutputTypeInference (ec, a.Expr, method_parameter);
			}

			//
			// Part of the second phase but because it happens only once
			// we don't need to call it in cycle
			//
			bool fixed_any = false;
			if (!tic.FixIndependentTypeArguments (ec, ptypes, ref fixed_any))
				return false;

			return DoSecondPhase (ec, tic, ptypes, !fixed_any);
		}

		bool DoSecondPhase (ResolveContext ec, TypeInferenceContext tic, Type[] methodParameters, bool fixDependent)
		{
			bool fixed_any = false;
			if (fixDependent && !tic.FixDependentTypes (ec, ref fixed_any))
				return false;

			// If no further unfixed type variables exist, type inference succeeds
			if (!tic.UnfixedVariableExists)
				return true;

			if (!fixed_any && fixDependent)
				return false;
			
			// For all arguments where the corresponding argument output types
			// contain unfixed type variables but the input types do not,
			// an output type inference is made
			for (int i = 0; i < arg_count; i++) {
				
				// Align params arguments
				Type t_i = methodParameters [i >= methodParameters.Length ? methodParameters.Length - 1: i];
				
				if (!TypeManager.IsDelegateType (t_i)) {
					if (TypeManager.DropGenericTypeArguments (t_i) != TypeManager.expression_type)
						continue;

					t_i = t_i.GetGenericArguments () [0];
				}

				MethodInfo mi = Delegate.GetInvokeMethod (ec.Compiler, t_i, t_i);
				Type rtype = mi.ReturnType;

#if MS_COMPATIBLE
				// Blablabla, because reflection does not work with dynamic types
				Type[] g_args = t_i.GetGenericArguments ();
				rtype = g_args[rtype.GenericParameterPosition];
#endif

				if (tic.IsReturnTypeNonDependent (ec, mi, rtype))
					score -= tic.OutputTypeInference (ec, arguments [i].Expr, t_i);
			}


			return DoSecondPhase (ec, tic, methodParameters, true);
		}
	}

	public class TypeInferenceContext
	{
		enum BoundKind
		{
			Exact	= 0,
			Lower	= 1,
			Upper	= 2
		}

		class BoundInfo
		{
			public readonly Type Type;
			public readonly BoundKind Kind;

			public BoundInfo (Type type, BoundKind kind)
			{
				this.Type = type;
				this.Kind = kind;
			}
			
			public override int GetHashCode ()
			{
				return Type.GetHashCode ();
			}

			public override bool Equals (object obj)
			{
				BoundInfo a = (BoundInfo) obj;
				return Type == a.Type && Kind == a.Kind;
			}
		}

		readonly Type[] unfixed_types;
		readonly Type[] fixed_types;
		readonly ArrayList[] bounds;
		bool failed;
		
		public TypeInferenceContext (Type[] typeArguments)
		{
			if (typeArguments.Length == 0)
				throw new ArgumentException ("Empty generic arguments");

			fixed_types = new Type [typeArguments.Length];
			for (int i = 0; i < typeArguments.Length; ++i) {
				if (typeArguments [i].IsGenericParameter) {
					if (bounds == null) {
						bounds = new ArrayList [typeArguments.Length];
						unfixed_types = new Type [typeArguments.Length];
					}
					unfixed_types [i] = typeArguments [i];
				} else {
					fixed_types [i] = typeArguments [i];
				}
			}
		}

		// 
		// Used together with AddCommonTypeBound fo implement
		// 7.4.2.13 Finding the best common type of a set of expressions
		//
		public TypeInferenceContext ()
		{
			fixed_types = new Type [1];
			unfixed_types = new Type [1];
			unfixed_types[0] = InternalType.Arglist; // it can be any internal type
			bounds = new ArrayList [1];
		}

		public Type[] InferredTypeArguments {
			get {
				return fixed_types;
			}
		}

		public void AddCommonTypeBound (Type type)
		{
			AddToBounds (new BoundInfo (type, BoundKind.Lower), 0);
		}

		void AddToBounds (BoundInfo bound, int index)
		{
			//
			// Some types cannot be used as type arguments
			//
			if (bound.Type == TypeManager.void_type || bound.Type.IsPointer)
				return;

			ArrayList a = bounds [index];
			if (a == null) {
				a = new ArrayList ();
				bounds [index] = a;
			} else {
				if (a.Contains (bound))
					return;
			}

			//
			// SPEC: does not cover type inference using constraints
			//
			//if (TypeManager.IsGenericParameter (t)) {
			//    GenericConstraints constraints = TypeManager.GetTypeParameterConstraints (t);
			//    if (constraints != null) {
			//        //if (constraints.EffectiveBaseClass != null)
			//        //	t = constraints.EffectiveBaseClass;
			//    }
			//}
			a.Add (bound);
		}
		
		bool AllTypesAreFixed (Type[] types)
		{
			foreach (Type t in types) {
				if (t.IsGenericParameter) {
					if (!IsFixed (t))
						return false;
					continue;
				}

				if (t.IsGenericType)
					return AllTypesAreFixed (t.GetGenericArguments ());
			}
			
			return true;
		}		

		//
		// 26.3.3.8 Exact Inference
		//
		public int ExactInference (Type u, Type v)
		{
			// If V is an array type
			if (v.IsArray) {
				if (!u.IsArray)
					return 0;

				if (u.GetArrayRank () != v.GetArrayRank ())
					return 0;

				return ExactInference (TypeManager.GetElementType (u), TypeManager.GetElementType (v));
			}

			// If V is constructed type and U is constructed type
			if (v.IsGenericType && !v.IsGenericTypeDefinition) {
				if (!u.IsGenericType)
					return 0;

				Type [] ga_u = u.GetGenericArguments ();
				Type [] ga_v = v.GetGenericArguments ();
				if (ga_u.Length != ga_v.Length)
					return 0;

				int score = 0;
				for (int i = 0; i < ga_u.Length; ++i)
					score += ExactInference (ga_u [i], ga_v [i]);

				return score > 0 ? 1 : 0;
			}

			// If V is one of the unfixed type arguments
			int pos = IsUnfixed (v);
			if (pos == -1)
				return 0;

			AddToBounds (new BoundInfo (u, BoundKind.Exact), pos);
			return 1;
		}

		public bool FixAllTypes (ResolveContext ec)
		{
			for (int i = 0; i < unfixed_types.Length; ++i) {
				if (!FixType (ec, i))
					return false;
			}
			return true;
		}

		//
		// All unfixed type variables Xi are fixed for which all of the following hold:
		// a, There is at least one type variable Xj that depends on Xi
		// b, Xi has a non-empty set of bounds
		// 
		public bool FixDependentTypes (ResolveContext ec, ref bool fixed_any)
		{
			for (int i = 0; i < unfixed_types.Length; ++i) {
				if (unfixed_types[i] == null)
					continue;

				if (bounds[i] == null)
					continue;

				if (!FixType (ec, i))
					return false;
				
				fixed_any = true;
			}

			return true;
		}

		//
		// All unfixed type variables Xi which depend on no Xj are fixed
		//
		public bool FixIndependentTypeArguments (ResolveContext ec, Type[] methodParameters, ref bool fixed_any)
		{
			ArrayList types_to_fix = new ArrayList (unfixed_types);
			for (int i = 0; i < methodParameters.Length; ++i) {
				Type t = methodParameters[i];

				if (!TypeManager.IsDelegateType (t)) {
					if (TypeManager.DropGenericTypeArguments (t) != TypeManager.expression_type)
						continue;

					t = t.GetGenericArguments () [0];
				}

				if (t.IsGenericParameter)
					continue;

				MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, t, t);
				Type rtype = invoke.ReturnType;
				if (!rtype.IsGenericParameter && !rtype.IsGenericType)
					continue;

#if MS_COMPATIBLE
				// Blablabla, because reflection does not work with dynamic types
				if (rtype.IsGenericParameter) {
					Type [] g_args = t.GetGenericArguments ();
					rtype = g_args [rtype.GenericParameterPosition];
				}
#endif
				// Remove dependent types, they cannot be fixed yet
				RemoveDependentTypes (types_to_fix, rtype);
			}

			foreach (Type t in types_to_fix) {
				if (t == null)
					continue;

				int idx = IsUnfixed (t);
				if (idx >= 0 && !FixType (ec, idx)) {
					return false;
				}
			}

			fixed_any = types_to_fix.Count > 0;
			return true;
		}

		//
		// 26.3.3.10 Fixing
		//
		public bool FixType (ResolveContext ec, int i)
		{
			// It's already fixed
			if (unfixed_types[i] == null)
				throw new InternalErrorException ("Type argument has been already fixed");

			if (failed)
				return false;

			ArrayList candidates = (ArrayList)bounds [i];
			if (candidates == null)
				return false;

			if (candidates.Count == 1) {
				unfixed_types[i] = null;
				Type t = ((BoundInfo) candidates[0]).Type;
				if (t == TypeManager.null_type)
					return false;

				fixed_types [i] = t;
				return true;
			}

			//
			// Determines a unique type from which there is
			// a standard implicit conversion to all the other
			// candidate types.
			//
			Type best_candidate = null;
			int cii;
			int candidates_count = candidates.Count;
			for (int ci = 0; ci < candidates_count; ++ci) {
				BoundInfo bound = (BoundInfo)candidates [ci];
				for (cii = 0; cii < candidates_count; ++cii) {
					if (cii == ci)
						continue;

					BoundInfo cbound = (BoundInfo) candidates[cii];
					
					// Same type parameters with different bounds
					if (cbound.Type == bound.Type) {
						if (bound.Kind != BoundKind.Exact)
							bound = cbound;

						continue;
					}

					if (bound.Kind == BoundKind.Exact || cbound.Kind == BoundKind.Exact) {
						if (cbound.Kind != BoundKind.Exact) {
							if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) {
								break;
							}

							continue;
						}
						
						if (bound.Kind != BoundKind.Exact) {
							if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
								break;
							}

							bound = cbound;
							continue;
						}
						
						break;
					}

					if (bound.Kind == BoundKind.Lower) {
						if (!Convert.ImplicitConversionExists (ec, new TypeExpression (cbound.Type, Location.Null), bound.Type)) {
							break;
						}
					} else {
						if (!Convert.ImplicitConversionExists (ec, new TypeExpression (bound.Type, Location.Null), cbound.Type)) {
							break;
						}
					}
				}

				if (cii != candidates_count)
					continue;

				if (best_candidate != null && best_candidate != bound.Type)
					return false;

				best_candidate = bound.Type;
			}

			if (best_candidate == null)
				return false;

			unfixed_types[i] = null;
			fixed_types[i] = best_candidate;
			return true;
		}
		
		//
		// Uses inferred types to inflate delegate type argument
		//
		public Type InflateGenericArgument (Type parameter)
		{
			if (parameter.IsGenericParameter) {
				//
				// Inflate method generic argument (MVAR) only
				//
				if (parameter.DeclaringMethod == null)
					return parameter;

				return fixed_types [parameter.GenericParameterPosition];
			}

			if (parameter.IsGenericType) {
				Type [] parameter_targs = parameter.GetGenericArguments ();
				for (int ii = 0; ii < parameter_targs.Length; ++ii) {
					parameter_targs [ii] = InflateGenericArgument (parameter_targs [ii]);
				}
				return parameter.GetGenericTypeDefinition ().MakeGenericType (parameter_targs);
			}

			return parameter;
		}
		
		//
		// Tests whether all delegate input arguments are fixed and generic output type
		// requires output type inference 
		//
		public bool IsReturnTypeNonDependent (ResolveContext ec, MethodInfo invoke, Type returnType)
		{
			if (returnType.IsGenericParameter) {
				if (IsFixed (returnType))
				    return false;
			} else if (returnType.IsGenericType) {
				if (TypeManager.IsDelegateType (returnType)) {
					invoke = Delegate.GetInvokeMethod (ec.Compiler, returnType, returnType);
					return IsReturnTypeNonDependent (ec, invoke, invoke.ReturnType);
				}
					
				Type[] g_args = returnType.GetGenericArguments ();
				
				// At least one unfixed return type has to exist 
				if (AllTypesAreFixed (g_args))
					return false;
			} else {
				return false;
			}

			// All generic input arguments have to be fixed
			AParametersCollection d_parameters = TypeManager.GetParameterData (invoke);
			return AllTypesAreFixed (d_parameters.Types);
		}
		
		bool IsFixed (Type type)
		{
			return IsUnfixed (type) == -1;
		}		

		int IsUnfixed (Type type)
		{
			if (!type.IsGenericParameter)
				return -1;

			//return unfixed_types[type.GenericParameterPosition] != null;
			for (int i = 0; i < unfixed_types.Length; ++i) {
				if (unfixed_types [i] == type)
					return i;
			}

			return -1;
		}

		//
		// 26.3.3.9 Lower-bound Inference
		//
		public int LowerBoundInference (Type u, Type v)
		{
			return LowerBoundInference (u, v, false);
		}

		//
		// Lower-bound (false) or Upper-bound (true) inference based on inversed argument
		//
		int LowerBoundInference (Type u, Type v, bool inversed)
		{
			// If V is one of the unfixed type arguments
			int pos = IsUnfixed (v);
			if (pos != -1) {
				AddToBounds (new BoundInfo (u, inversed ? BoundKind.Upper : BoundKind.Lower), pos);
				return 1;
			}			

			// If U is an array type
			if (u.IsArray) {
				int u_dim = u.GetArrayRank ();
				Type v_i;
				Type u_i = TypeManager.GetElementType (u);

				if (v.IsArray) {
					if (u_dim != v.GetArrayRank ())
						return 0;

					v_i = TypeManager.GetElementType (v);

					if (TypeManager.IsValueType (u_i))
						return ExactInference (u_i, v_i);

					return LowerBoundInference (u_i, v_i, inversed);
				}

				if (u_dim != 1)
					return 0;

				if (v.IsGenericType) {
					Type g_v = v.GetGenericTypeDefinition ();
					if ((g_v != TypeManager.generic_ilist_type) && (g_v != TypeManager.generic_icollection_type) &&
						(g_v != TypeManager.generic_ienumerable_type))
						return 0;

					v_i = TypeManager.TypeToCoreType (TypeManager.GetTypeArguments (v) [0]);
					if (TypeManager.IsValueType (u_i))
						return ExactInference (u_i, v_i);

					return LowerBoundInference (u_i, v_i);
				}
			} else if (v.IsGenericType && !v.IsGenericTypeDefinition) {
				//
				// if V is a constructed type C<V1..Vk> and there is a unique type C<U1..Uk>
				// such that U is identical to, inherits from (directly or indirectly),
				// or implements (directly or indirectly) C<U1..Uk>
				//
				ArrayList u_candidates = new ArrayList ();
				if (u.IsGenericType)
					u_candidates.Add (u);

				for (Type t = u.BaseType; t != null; t = t.BaseType) {
					if (t.IsGenericType && !t.IsGenericTypeDefinition)
						u_candidates.Add (t);
				}

				// TODO: Implement GetGenericInterfaces only and remove
				// the if from foreach
				u_candidates.AddRange (TypeManager.GetInterfaces (u));

				Type open_v = v.GetGenericTypeDefinition ();
				Type [] unique_candidate_targs = null;
				Type [] ga_v = v.GetGenericArguments ();			
				foreach (Type u_candidate in u_candidates) {
					if (!u_candidate.IsGenericType || u_candidate.IsGenericTypeDefinition)
						continue;

					if (TypeManager.DropGenericTypeArguments (u_candidate) != open_v)
						continue;

					//
					// The unique set of types U1..Uk means that if we have an interface I<T>,
					// class U : I<int>, I<long> then no type inference is made when inferring
					// type I<T> by applying type U because T could be int or long
					//
					if (unique_candidate_targs != null) {
						Type[] second_unique_candidate_targs = u_candidate.GetGenericArguments ();
						if (TypeManager.IsEqual (unique_candidate_targs, second_unique_candidate_targs)) {
							unique_candidate_targs = second_unique_candidate_targs;
							continue;
						}

						//
						// This should always cause type inference failure
						//
						failed = true;
						return 1;
					}

					unique_candidate_targs = u_candidate.GetGenericArguments ();
				}

				if (unique_candidate_targs != null) {
					Type[] ga_open_v = open_v.GetGenericArguments ();
					int score = 0;
					for (int i = 0; i < unique_candidate_targs.Length; ++i) {
						Variance variance = TypeManager.GetTypeParameterVariance (ga_open_v [i]);

						Type u_i = unique_candidate_targs [i];
						if (variance == Variance.None || TypeManager.IsValueType (u_i)) {
							if (ExactInference (u_i, ga_v [i]) == 0)
								++score;
						} else {
							bool upper_bound = (variance == Variance.Contravariant && !inversed) ||
								(variance == Variance.Covariant && inversed);

							if (LowerBoundInference (u_i, ga_v [i], upper_bound) == 0)
								++score;
						}
					}
					return score;
				}
			}

			return 0;
		}

		//
		// 26.3.3.6 Output Type Inference
		//
		public int OutputTypeInference (ResolveContext ec, Expression e, Type t)
		{
			// If e is a lambda or anonymous method with inferred return type
			AnonymousMethodExpression ame = e as AnonymousMethodExpression;
			if (ame != null) {
				Type rt = ame.InferReturnType (ec, this, t);
				MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, t, t);

				if (rt == null) {
					AParametersCollection pd = TypeManager.GetParameterData (invoke);
					return ame.Parameters.Count == pd.Count ? 1 : 0;
				}

				Type rtype = invoke.ReturnType;
#if MS_COMPATIBLE
				// Blablabla, because reflection does not work with dynamic types
				Type [] g_args = t.GetGenericArguments ();
				rtype = g_args [rtype.GenericParameterPosition];
#endif
				return LowerBoundInference (rt, rtype) + 1;
			}

			//
			// if E is a method group and T is a delegate type or expression tree type
			// return type Tb with parameter types T1..Tk and return type Tb, and overload
			// resolution of E with the types T1..Tk yields a single method with return type U,
			// then a lower-bound inference is made from U for Tb.
			//
			if (e is MethodGroupExpr) {
				// TODO: Or expression tree
				if (!TypeManager.IsDelegateType (t))
					return 0;

				MethodInfo invoke = Delegate.GetInvokeMethod (ec.Compiler, t, t);
				Type rtype = invoke.ReturnType;
#if MS_COMPATIBLE
				// Blablabla, because reflection does not work with dynamic types
				Type [] g_args = t.GetGenericArguments ();
				rtype = g_args [rtype.GenericParameterPosition];
#endif

				if (!TypeManager.IsGenericType (rtype))
					return 0;

				MethodGroupExpr mg = (MethodGroupExpr) e;
				Arguments args = DelegateCreation.CreateDelegateMethodArguments (TypeManager.GetParameterData (invoke), e.Location);
				mg = mg.OverloadResolve (ec, ref args, true, e.Location);
				if (mg == null)
					return 0;

				// TODO: What should happen when return type is of generic type ?
				throw new NotImplementedException ();
//				return LowerBoundInference (null, rtype) + 1;
			}

			//
			// if e is an expression with type U, then
			// a lower-bound inference is made from U for T
			//
			return LowerBoundInference (e.Type, t) * 2;
		}

		void RemoveDependentTypes (ArrayList types, Type returnType)
		{
			int idx = IsUnfixed (returnType);
			if (idx >= 0) {
				types [idx] = null;
				return;
			}

			if (returnType.IsGenericType) {
				foreach (Type t in returnType.GetGenericArguments ()) {
					RemoveDependentTypes (types, t);
				}
			}
		}

		public bool UnfixedVariableExists {
			get {
				if (unfixed_types == null)
					return false;

				foreach (Type ut in unfixed_types)
					if (ut != null)
						return true;
				return false;
			}
		}
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions