//
// class.cs: Class and Struct handlers
//
// Authors: Miguel de Icaza (miguel@gnu.org)
//          Martin Baulig (martin@ximian.com)
//          Marek Safar (marek.safar@seznam.cz)
//
// 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.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Linq;

#if NET_2_1
using XmlElement = System.Object;
#endif

#if STATIC
using SecurityType = System.Collections.Generic.List<IKVM.Reflection.Emit.CustomAttributeBuilder>;
using IKVM.Reflection;
using IKVM.Reflection.Emit;
#else
using SecurityType = System.Collections.Generic.Dictionary<System.Security.Permissions.SecurityAction, System.Security.PermissionSet>;
using System.Reflection;
using System.Reflection.Emit;
#endif

namespace Mono.CSharp {

	/// <summary>
	///   This is the base class for structs and classes.  
	/// </summary>
	public abstract class TypeContainer : DeclSpace, ITypeDefinition
	{
		//
		// Different context is needed when resolving type container base
		// types. Type names come from the parent scope but type parameter
		// names from the container scope.
		//
		public struct BaseContext : IMemberContext
		{
			TypeContainer tc;

			public BaseContext (TypeContainer tc)
			{
				this.tc = tc;
			}

			#region IMemberContext Members

			public CompilerContext Compiler {
				get { return tc.Compiler; }
			}

			public TypeSpec CurrentType {
				get { return tc.Parent.CurrentType; }
			}

			public TypeParameter[] CurrentTypeParameters {
				get { return tc.PartialContainer.CurrentTypeParameters; }
			}

			public MemberCore CurrentMemberDefinition {
				get { return tc; }
			}

			public bool HasUnresolvedConstraints {
				get { return true; }
			}

			public bool IsObsolete {
				get { return tc.IsObsolete; }
			}

			public bool IsUnsafe {
				get { return tc.IsUnsafe; }
			}

			public bool IsStatic {
				get { return tc.IsStatic; }
			}

			public ModuleContainer Module {
				get { return tc.Module; }
			}

			public string GetSignatureForError ()
			{
				return tc.GetSignatureForError ();
			}

			public IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
			{
				return null;
			}

			public FullNamedExpression LookupNamespaceAlias (string name)
			{
				return tc.Parent.LookupNamespaceAlias (name);
			}

			public FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
			{
				if (arity == 0) {
					TypeParameter[] tp = CurrentTypeParameters;
					if (tp != null) {
						TypeParameter t = TypeParameter.FindTypeParameter (tp, name);
						if (t != null)
							return new TypeParameterExpr (t, loc);
					}
				}

				return tc.Parent.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
			}

			#endregion
		}

		[Flags]
		enum CachedMethods
		{
			Equals				= 1,
			GetHashCode			= 1 << 1,
			HasStaticFieldInitializer	= 1 << 2
		}


		// Whether this is a struct, class or interface
		public readonly MemberKind Kind;

		// Holds a list of classes and structures
		protected List<TypeContainer> types;

		List<MemberCore> ordered_explicit_member_list;
		List<MemberCore> ordered_member_list;

		// Holds the list of properties
		List<MemberCore> properties;

		// Holds the list of constructors
		protected List<Constructor> instance_constructors;

		// Holds the list of fields
		protected List<FieldBase> fields;

		// Holds a list of fields that have initializers
		protected List<FieldInitializer> initialized_fields;

		// Holds a list of static fields that have initializers
		protected List<FieldInitializer> initialized_static_fields;

		// Holds the list of constants
		protected List<MemberCore> constants;

		// Holds the methods.
		List<MemberCore> methods;

		// Holds the events
		protected List<MemberCore> events;

		// Holds the indexers
		List<MemberCore> indexers;

		// Holds the operators
		List<MemberCore> operators;

		// Holds the compiler generated classes
		protected List<CompilerGeneratedClass> compiler_generated;

		Dictionary<MethodSpec, Method> hoisted_base_call_proxies;

		Dictionary<string, FullNamedExpression> Cache = new Dictionary<string, FullNamedExpression> ();

		//
		// Pointers to the default constructor and the default static constructor
		//
		protected Constructor default_constructor;
		protected Constructor default_static_constructor;

		//
		// Points to the first non-static field added to the container.
		//
		// This is an arbitrary choice.  We are interested in looking at _some_ non-static field,
		// and the first one's as good as any.
		//
		FieldBase first_nonstatic_field;

		//
		// This one is computed after we can distinguish interfaces
		// from classes from the arraylist `type_bases' 
		//
		protected TypeSpec base_type;
		protected TypeExpr base_type_expr;
		protected TypeExpr[] iface_exprs;

		protected List<FullNamedExpression> type_bases;

		bool members_defined;
		bool members_defined_ok;
		bool type_defined;

		TypeContainer InTransit;

		GenericTypeParameterBuilder[] all_tp_builders;

		public const string DefaultIndexerName = "Item";

		private bool seen_normal_indexers = false;
		private string indexer_name = DefaultIndexerName;
		protected bool requires_delayed_unmanagedtype_check;
		bool error;

		private CachedMethods cached_method;

		protected TypeSpec spec;
		TypeSpec current_type;

		List<TypeContainer> partial_parts;

		public int DynamicSitesCounter;

		/// <remarks>
		///  The pending methods that need to be implemented
		//   (interfaces or abstract methods)
		/// </remarks>
		PendingImplementation pending;

		public TypeContainer (NamespaceEntry ns, DeclSpace parent, MemberName name,
				      Attributes attrs, MemberKind kind)
			: base (ns, parent, name, attrs)
		{
			if (parent != null && parent.NamespaceEntry != ns)
				throw new InternalErrorException ("A nested type should be in the same NamespaceEntry as its enclosing class");

			this.Kind = kind;
			this.PartialContainer = this;
		}

		#region Properties

		public override TypeSpec CurrentType {
			get {
				if (current_type == null) {
					if (IsGeneric) {
						//
						// Switch to inflated version as it's used by all expressions
						//
						var targs = CurrentTypeParameters == null ? TypeSpec.EmptyTypes : CurrentTypeParameters.Select (l => l.Type).ToArray ();
						current_type = spec.MakeGenericType (targs);
					} else {
						current_type = spec;
					}
				}

				return current_type;
			}
		}

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

		int CurrentTypeParametersStartIndex {
			get {
				int total = all_tp_builders.Length;
				if (CurrentTypeParameters != null) {
					return total - CurrentTypeParameters.Length;
				}
				return total;
			}
		}

		public virtual AssemblyDefinition DeclaringAssembly {
			get {
				return Module.DeclaringAssembly;
			}
		}

		IAssemblyDefinition ITypeDefinition.DeclaringAssembly {
			get {
				return Module.DeclaringAssembly;
			}
		}

		public TypeSpec Definition {
			get {
				return spec;
			}
		}

		public bool HasMembersDefined {
			get {
				return members_defined;
			}
		}

		#endregion

		public bool AddMember (MemberCore symbol)
		{
			return AddToContainer (symbol, symbol.MemberName.Basename);
		}

		public bool AddMember (MemberCore symbol, string name)
		{
			return AddToContainer (symbol, name);
		}

		protected virtual bool AddMemberType (TypeContainer ds)
		{
			return AddToContainer (ds, ds.Basename);
		}

		protected virtual void RemoveMemberType (DeclSpace ds)
		{
			RemoveFromContainer (ds.Basename);
		}

		public void AddConstant (Const constant)
		{
			if (!AddMember (constant))
				return;

			if (constants == null)
				constants = new List<MemberCore> ();
			
			constants.Add (constant);
		}

		public TypeContainer AddTypeContainer (TypeContainer tc)
		{
			if (!AddMemberType (tc))
				return tc;

			if (types == null)
				types = new List<TypeContainer> ();

			types.Add (tc);
			return tc;
		}

		public virtual TypeContainer AddPartial (TypeContainer next_part)
		{
			return AddPartial (next_part, next_part.Basename);
		}

		protected TypeContainer AddPartial (TypeContainer next_part, string name)
		{
			next_part.ModFlags |= Modifiers.PARTIAL;
			TypeContainer tc = GetDefinition (name) as TypeContainer;
			if (tc == null)
				return AddTypeContainer (next_part);

			if ((tc.ModFlags & Modifiers.PARTIAL) == 0) {
				Report.SymbolRelatedToPreviousError (next_part);
				Error_MissingPartialModifier (tc);
			}

			if (tc.Kind != next_part.Kind) {
				Report.SymbolRelatedToPreviousError (tc);
				Report.Error (261, next_part.Location,
					"Partial declarations of `{0}' must be all classes, all structs or all interfaces",
					next_part.GetSignatureForError ());
			}

			if ((tc.ModFlags & Modifiers.AccessibilityMask) != (next_part.ModFlags & Modifiers.AccessibilityMask) &&
				((tc.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) == 0 &&
				 (next_part.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) == 0)) {
				Report.SymbolRelatedToPreviousError (tc);
				Report.Error (262, next_part.Location,
					"Partial declarations of `{0}' have conflicting accessibility modifiers",
					next_part.GetSignatureForError ());
			}

			if (tc.partial_parts == null)
				tc.partial_parts = new List<TypeContainer> (1);

			if ((next_part.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) != 0) {
				tc.ModFlags |= next_part.ModFlags & ~(Modifiers.DEFAULT_ACCESS_MODIFER | Modifiers.AccessibilityMask);
			} else if ((tc.ModFlags & Modifiers.DEFAULT_ACCESS_MODIFER) != 0) {
				tc.ModFlags &= ~(Modifiers.DEFAULT_ACCESS_MODIFER | Modifiers.AccessibilityMask);
				tc.ModFlags |= next_part.ModFlags;
			} else {
				tc.ModFlags |= next_part.ModFlags;
			}

			tc.spec.Modifiers = tc.ModFlags;

			if (next_part.attributes != null) {
				if (tc.attributes == null)
					tc.attributes = next_part.attributes;
				else
					tc.attributes.AddAttributes (next_part.attributes.Attrs);
			}

			next_part.PartialContainer = tc;
			tc.partial_parts.Add (next_part);
			return tc;
		}

		public virtual void RemoveTypeContainer (TypeContainer next_part)
		{
			if (types != null)
				types.Remove (next_part);
			RemoveMemberType (next_part);
		}
		
		public virtual TypeSpec AddDelegate (Delegate d)
		{
			AddTypeContainer (d);
			return null;
		}

		private void AddMemberToList (MemberCore mc, List<MemberCore> alist, bool isexplicit)
		{
			if (ordered_explicit_member_list == null)  {
				ordered_explicit_member_list = new List<MemberCore> ();
				ordered_member_list = new List<MemberCore> ();
			}

			if (isexplicit) {
				if (Kind == MemberKind.Interface) {
					Report.Error (541, mc.Location,
						"`{0}': explicit interface declaration can only be declared in a class or struct",
						mc.GetSignatureForError ());
				}

				ordered_explicit_member_list.Add (mc);
				alist.Insert (0, mc);
			} else {
				ordered_member_list.Add (mc);
				alist.Add (mc);
			}

		}
		
		public void AddMethod (MethodOrOperator method)
		{
			if (!AddToContainer (method, method.MemberName.Basename))
				return;
			
			if (methods == null)
				methods = new List<MemberCore> ();

			if (method.MemberName.Left != null) 
				AddMemberToList (method, methods, true);
			else 
				AddMemberToList (method, methods, false);
		}

		public void AddConstructor (Constructor c)
		{
			bool is_static = (c.ModFlags & Modifiers.STATIC) != 0;
			if (!AddToContainer (c, is_static ? Constructor.ConstructorName : Constructor.TypeConstructorName))
				return;
			
			if (is_static && c.ParameterInfo.IsEmpty){
				if (default_static_constructor != null) {
				    Report.SymbolRelatedToPreviousError (default_static_constructor);
					Report.Error (111, c.Location,
						"A member `{0}' is already defined. Rename this member or use different parameter types",
						c.GetSignatureForError ());
				    return;
				}

				default_static_constructor = c;
			} else {
				if (c.ParameterInfo.IsEmpty)
					default_constructor = c;
				
				if (instance_constructors == null)
					instance_constructors = new List<Constructor> ();
				
				instance_constructors.Add (c);
			}
		}

		public bool AddField (FieldBase field)
		{
			if (!AddMember (field))
				return false;

			if (fields == null)
				fields = new List<FieldBase> ();

			fields.Add (field);

			if ((field.ModFlags & Modifiers.STATIC) != 0)
				return true;

			if (first_nonstatic_field == null) {
				first_nonstatic_field = field;
				return true;
			}

			if (Kind == MemberKind.Struct && first_nonstatic_field.Parent != field.Parent) {
				Report.SymbolRelatedToPreviousError (first_nonstatic_field.Parent);
				Report.Warning (282, 3, field.Location,
					"struct instance field `{0}' found in different declaration from instance field `{1}'",
					field.GetSignatureForError (), first_nonstatic_field.GetSignatureForError ());
			}
			return true;
		}

		public void AddProperty (Property prop)
		{
			if (!AddMember (prop))
				return;

			if (properties == null)
				properties = new List<MemberCore> ();

			if (prop.MemberName.Left != null)
				AddMemberToList (prop, properties, true);
			else 
				AddMemberToList (prop, properties, false);
		}

		public void AddEvent (Event e)
		{
			if (!AddMember (e))
				return;

			if (events == null)
				events = new List<MemberCore> ();

			events.Add (e);
		}

		/// <summary>
		/// Indexer has special handling in constrast to other AddXXX because the name can be driven by IndexerNameAttribute
		/// </summary>
		public void AddIndexer (Indexer i)
		{
			if (indexers == null)
				indexers = new List<MemberCore> ();

			if (i.IsExplicitImpl)
				AddMemberToList (i, indexers, true);
			else 
				AddMemberToList (i, indexers, false);
		}

		public void AddOperator (Operator op)
		{
			if (!AddMember (op))
				return;

			if (operators == null)
				operators = new List<MemberCore> ();

			operators.Add (op);
		}

		public void AddCompilerGeneratedClass (CompilerGeneratedClass c)
		{
			Report.Debug (64, "ADD COMPILER GENERATED CLASS", this, c);

			if (compiler_generated == null)
				compiler_generated = new List<CompilerGeneratedClass> ();

			compiler_generated.Add (c);
		}

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			if (a.Type == pa.DefaultMember) {
				if (Indexers != null) {
					Report.Error (646, a.Location, "Cannot specify the `DefaultMember' attribute on type containing an indexer");
					return;
				}
			}

			if (a.Type == pa.Required) {
				Report.Error (1608, a.Location, "The RequiredAttribute attribute is not permitted on C# types");
				return;
			}

			TypeBuilder.SetCustomAttribute ((ConstructorInfo) ctor.GetMetaInfo (), cdata);
		} 

		public override AttributeTargets AttributeTargets {
			get {
				throw new NotSupportedException ();
			}
		}

		public IList<TypeContainer> Types {
			get {
				return types;
			}
		}

		public IList<MemberCore> Methods {
			get {
				return methods;
			}
		}

		public IList<MemberCore> Constants {
			get {
				return constants;
			}
		}

		public TypeSpec BaseType {
			get {
				return spec.BaseType;
			}
		}

		public IList<FieldBase> Fields {
			get {
				return fields;
			}
		}

		public IList<Constructor> InstanceConstructors {
			get {
				return instance_constructors;
			}
		}

		public IList<MemberCore> Properties {
			get {
				return properties;
			}
		}

		public IList<MemberCore> Events {
			get {
				return events;
			}
		}
		
		public IList<MemberCore> Indexers {
			get {
				return indexers;
			}
		}

		public IList<MemberCore> Operators {
			get {
				return operators;
			}
		}

		protected override TypeAttributes TypeAttr {
			get {
				return ModifiersExtensions.TypeAttr (ModFlags, IsTopLevel) | base.TypeAttr;
			}
		}

		public int TypeParametersCount {
			get {
				return MemberName.Arity;
			}
		}

		TypeParameterSpec[] ITypeDefinition.TypeParameters {
			get {
				// TODO MemberCache: this is going to hurt
				return PartialContainer.type_params.Select (l => l.Type).ToArray ();
			}
		}

		public string GetAttributeDefaultMember ()
		{
			return indexers == null ? DefaultIndexerName : indexer_name;
		}

		public bool IsComImport {
			get {
				if (OptAttributes == null)
					return false;

				return OptAttributes.Contains (Module.PredefinedAttributes.ComImport);
			}
		}

		string ITypeDefinition.Namespace {
			get {
				return NamespaceEntry.NS.MemberName.GetSignatureForError ();
			}
		}

		public virtual void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression)
		{
			if ((field.ModFlags & Modifiers.STATIC) != 0){
				if (initialized_static_fields == null) {
					PartialContainer.HasStaticFieldInitializer = true;
					initialized_static_fields = new List<FieldInitializer> (4);
				}

				initialized_static_fields.Add (expression);
			} else {
				if (initialized_fields == null)
					initialized_fields = new List<FieldInitializer> (4);

				initialized_fields.Add (expression);
			}
		}

		public void ResolveFieldInitializers (BlockContext ec)
		{
			if (partial_parts != null) {
				foreach (TypeContainer part in partial_parts) {
					part.DoResolveFieldInitializers (ec);
				}
			}
			DoResolveFieldInitializers (ec);
		}

		void DoResolveFieldInitializers (BlockContext ec)
		{
			if (ec.IsStatic) {
				if (initialized_static_fields == null)
					return;

				bool has_complex_initializer = !RootContext.Optimize;
				int i;
				ExpressionStatement [] init = new ExpressionStatement [initialized_static_fields.Count];
				for (i = 0; i < initialized_static_fields.Count; ++i) {
					FieldInitializer fi = initialized_static_fields [i];
					ExpressionStatement s = fi.ResolveStatement (ec);
					if (s == null) {
						s = EmptyExpressionStatement.Instance;
					} else if (fi.IsComplexInitializer) {
						has_complex_initializer |= true;
					}

					init [i] = s;
				}

				for (i = 0; i < initialized_static_fields.Count; ++i) {
					FieldInitializer fi = initialized_static_fields [i];
					//
					// Need special check to not optimize code like this
					// static int a = b = 5;
					// static int b = 0;
					//
					if (!has_complex_initializer && fi.IsDefaultInitializer)
						continue;

					ec.CurrentBlock.AddScopeStatement (new StatementExpression (init [i]));
				}

				return;
			}

			if (initialized_fields == null)
				return;

			for (int i = 0; i < initialized_fields.Count; ++i) {
				FieldInitializer fi = initialized_fields [i];
				ExpressionStatement s = fi.ResolveStatement (ec);
				if (s == null)
					continue;

				//
				// Field is re-initialized to its default value => removed
				//
				if (fi.IsDefaultInitializer && RootContext.Optimize)
					continue;

				ec.CurrentBlock.AddScopeStatement (new StatementExpression (s));
			}
		}

		public override string DocComment {
			get {
				return comment;
			}
			set {
				if (value == null)
					return;

				comment += value;
			}
		}

		public PendingImplementation PendingImplementations {
			get { return pending; }
		}

		public TypeSpec GetAttributeCoClass ()
		{
			if (OptAttributes == null)
				return null;

			Attribute a = OptAttributes.Search (Module.PredefinedAttributes.CoClass);
			if (a == null)
				return null;

			return a.GetCoClassAttributeValue ();
		}

		public AttributeUsageAttribute GetAttributeUsage (PredefinedAttribute pa)
		{
			Attribute a = null;
			if (OptAttributes != null) {
				a = OptAttributes.Search (pa);
			}

			if (a == null)
				return null;

			return a.GetAttributeUsageAttribute ();
		}

		public virtual void AddBasesForPart (DeclSpace part, List<FullNamedExpression> bases)
		{
			// FIXME: get rid of partial_parts and store lists of bases of each part here
			// assumed, not verified: 'part' is in 'partial_parts' 
			((TypeContainer) part).type_bases = bases;
		}

		/// <summary>
		///   This function computes the Base class and also the
		///   list of interfaces that the class or struct @c implements.
		///   
		///   The return value is an array (might be null) of
		///   interfaces implemented (as Types).
		///   
		///   The @base_class argument is set to the base object or null
		///   if this is `System.Object'. 
		/// </summary>
		protected virtual TypeExpr[] ResolveBaseTypes (out TypeExpr base_class)
		{
			base_class = null;
			if (type_bases == null)
				return null;

			int count = type_bases.Count;
			TypeExpr [] ifaces = null;
			var base_context = new BaseContext (this);
			for (int i = 0, j = 0; i < count; i++){
				FullNamedExpression fne = type_bases [i];

				TypeExpr fne_resolved = fne.ResolveAsTypeTerminal (base_context, false);
				if (fne_resolved == null)
					continue;

				if (i == 0 && Kind == MemberKind.Class && !fne_resolved.Type.IsInterface) {
					if (fne_resolved.Type == InternalType.Dynamic) {
						Report.Error (1965, Location, "Class `{0}' cannot derive from the dynamic type",
							GetSignatureForError ());

						continue;
					}
					
					base_type = fne_resolved.Type;
					base_class = fne_resolved;
					continue;
				}

				if (ifaces == null)
					ifaces = new TypeExpr [count - i];

				if (fne_resolved.Type.IsInterface) {
					for (int ii = 0; ii < j; ++ii) {
						if (fne_resolved.Type == ifaces [ii].Type) {
							Report.Error (528, Location, "`{0}' is already listed in interface list",
								fne_resolved.GetSignatureForError ());
							break;
						}
					}

					if (Kind == MemberKind.Interface && !IsAccessibleAs (fne_resolved.Type)) {
						Report.Error (61, fne.Location,
							"Inconsistent accessibility: base interface `{0}' is less accessible than interface `{1}'",
							fne_resolved.GetSignatureForError (), GetSignatureForError ());
					}
				} else {
					Report.SymbolRelatedToPreviousError (fne_resolved.Type);
					if (Kind != MemberKind.Class) {
						Report.Error (527, fne.Location, "Type `{0}' in interface list is not an interface", fne_resolved.GetSignatureForError ());
					} else if (base_class != null)
						Report.Error (1721, fne.Location, "`{0}': Classes cannot have multiple base classes (`{1}' and `{2}')",
							GetSignatureForError (), base_class.GetSignatureForError (), fne_resolved.GetSignatureForError ());
					else {
						Report.Error (1722, fne.Location, "`{0}': Base class `{1}' must be specified as first",
							GetSignatureForError (), fne_resolved.GetSignatureForError ());
					}
				}

				ifaces [j++] = fne_resolved;
			}

			return ifaces;
		}

		TypeExpr[] GetNormalPartialBases ()
		{
			var ifaces = new List<TypeExpr> (0);
			if (iface_exprs != null)
				ifaces.AddRange (iface_exprs);

			foreach (TypeContainer part in partial_parts) {
				TypeExpr new_base_class;
				TypeExpr[] new_ifaces = part.ResolveBaseTypes (out new_base_class);
				if (new_base_class != null) {
					if (base_type_expr != null && new_base_class.Type != base_type) {
						Report.SymbolRelatedToPreviousError (new_base_class.Location, "");
						Report.Error (263, part.Location,
							"Partial declarations of `{0}' must not specify different base classes",
							part.GetSignatureForError ());
					} else {
						base_type_expr = new_base_class;
						base_type = base_type_expr.Type;
					}
				}

				if (new_ifaces == null)
					continue;

				foreach (TypeExpr iface in new_ifaces) {
					if (ifaces.Contains (iface))
						continue;

					ifaces.Add (iface);
				}
			}

			if (ifaces.Count == 0)
				return null;

			return ifaces.ToArray ();
		}

		//
		// Checks that some operators come in pairs:
		//  == and !=
		// > and <
		// >= and <=
		// true and false
		//
		// They are matched based on the return type and the argument types
		//
		void CheckPairedOperators ()
		{
			bool has_equality_or_inequality = false;
			var operators = this.operators.ToArray ();
			bool[] has_pair = new bool[operators.Length];

			for (int i = 0; i < operators.Length; ++i) {
				if (operators[i] == null)
					continue;

				Operator o_a = (Operator) operators[i];
				Operator.OpType o_type = o_a.OperatorType;
				if (o_type == Operator.OpType.Equality || o_type == Operator.OpType.Inequality)
					has_equality_or_inequality = true;

				Operator.OpType matching_type = o_a.GetMatchingOperator ();
				if (matching_type == Operator.OpType.TOP) {
					operators[i] = null;
					continue;
				}

				for (int ii = 0; ii < operators.Length; ++ii) {
					Operator o_b = (Operator) operators[ii];
					if (o_b == null || o_b.OperatorType != matching_type)
						continue;

					if (!TypeSpecComparer.IsEqual (o_a.ReturnType, o_b.ReturnType))
						continue;

					if (!TypeSpecComparer.Equals (o_a.ParameterTypes, o_b.ParameterTypes))
						continue;

					operators[i] = null;

					//
					// Used to ignore duplicate user conversions
					//
					has_pair[ii] = true;
				}
			}

			for (int i = 0; i < operators.Length; ++i) {
				if (operators[i] == null || has_pair[i])
					continue;

				Operator o = (Operator) operators [i];
				Report.Error (216, o.Location,
					"The operator `{0}' requires a matching operator `{1}' to also be defined",
					o.GetSignatureForError (), Operator.GetName (o.GetMatchingOperator ()));
			}

			if (has_equality_or_inequality) {
				if (Methods == null || !HasEquals)
					Report.Warning (660, 2, Location, "`{0}' defines operator == or operator != but does not override Object.Equals(object o)",
						GetSignatureForError ());

				if (Methods == null || !HasGetHashCode)
					Report.Warning (661, 2, Location, "`{0}' defines operator == or operator != but does not override Object.GetHashCode()",
						GetSignatureForError ());
			}
		}
	
		bool CreateTypeBuilder ()
		{
			//
			// Sets .size to 1 for structs with no instance fields
			//
			int type_size = Kind == MemberKind.Struct && first_nonstatic_field == null ? 1 : 0;

			if (IsTopLevel) {
				// TODO: Completely wrong
				if (Module.GlobalRootNamespace.IsNamespace (Name)) {
					Report.Error (519, Location, "`{0}' clashes with a predefined namespace", Name);
				}

				TypeBuilder = Module.CreateBuilder (Name, TypeAttr, type_size);
			} else {
				TypeBuilder = Parent.TypeBuilder.DefineNestedType (Basename, TypeAttr, null, type_size);
			}

			spec.SetMetaInfo (TypeBuilder);
			spec.MemberCache = new MemberCache (this);
			spec.DeclaringType = Parent.CurrentType;

			if (!IsTopLevel)
				Parent.MemberCache.AddMember (spec);

			if (IsGeneric) {
				string[] param_names = new string[TypeParameters.Length];
				for (int i = 0; i < TypeParameters.Length; i++)
					param_names [i] = TypeParameters[i].Name;

				all_tp_builders = TypeBuilder.DefineGenericParameters (param_names);

				int offset = CurrentTypeParametersStartIndex;
				for (int i = offset; i < all_tp_builders.Length; i++) {
					CurrentTypeParameters [i - offset].Define (all_tp_builders [i], spec);
				}
			}

			return true;
		}

		//
		// Creates a proxy base method call inside this container for hoisted base member calls
		//
		public MethodSpec CreateHoistedBaseCallProxy (ResolveContext rc, MethodSpec method)
		{
			Method proxy_method;

			//
			// One proxy per base method is enough
			//
			if (hoisted_base_call_proxies == null) {
				hoisted_base_call_proxies = new Dictionary<MethodSpec, Method> ();
				proxy_method = null;
			} else {
				hoisted_base_call_proxies.TryGetValue (method, out proxy_method);
			}

			if (proxy_method == null) {
				string name = CompilerGeneratedClass.MakeName (method.Name, null, "BaseCallProxy", hoisted_base_call_proxies.Count);
				var base_parameters = new Parameter[method.Parameters.Count];
				for (int i = 0; i < base_parameters.Length; ++i) {
					var base_param = method.Parameters.FixedParameters[i];
					base_parameters[i] = new Parameter (new TypeExpression (method.Parameters.Types[i], Location),
						base_param.Name, base_param.ModFlags, null, Location);
					base_parameters[i].Resolve (this, i);
				}

				var cloned_params = ParametersCompiled.CreateFullyResolved (base_parameters, method.Parameters.Types);
				if (method.Parameters.HasArglist) {
					cloned_params.FixedParameters[0] = new Parameter (null, "__arglist", Parameter.Modifier.NONE, null, Location);
					cloned_params.Types[0] = Module.PredefinedTypes.RuntimeArgumentHandle.Resolve (Location);
				}

				GenericMethod generic_method;
				MemberName member_name;
				TypeArguments targs = null;
				if (method.IsGeneric) {
					//
					// Copy all base generic method type parameters info
					//
					var hoisted_tparams = method.GenericDefinition.TypeParameters;
					var type_params = new TypeParameter[hoisted_tparams.Length];
					targs = new TypeArguments ();
					targs.Arguments = new TypeSpec[type_params.Length];
					for (int i = 0; i < type_params.Length; ++i) {
						var tp = hoisted_tparams[i];
						targs.Add (new TypeParameterName (tp.Name, null, Location));
						targs.Arguments[i] = tp;
						type_params[i] = new TypeParameter (tp, null, null, new MemberName (tp.Name), null);
					}

					member_name = new MemberName (name, targs, Location);
					generic_method = new GenericMethod (NamespaceEntry, this, member_name, type_params,
						new TypeExpression (method.ReturnType, Location), cloned_params);
				} else {
					member_name = new MemberName (name);
					generic_method = null;
				}

				// Compiler generated proxy
				proxy_method = new Method (this, generic_method, new TypeExpression (method.ReturnType, Location),
					Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN,
					member_name, cloned_params, null);

				var block = new ToplevelBlock (Compiler, proxy_method.ParameterInfo, Location);

				var mg = MethodGroupExpr.CreatePredefined (method, method.DeclaringType, Location);
				mg.InstanceExpression = new BaseThis (method.DeclaringType, Location);
				if (targs != null)
					mg.SetTypeArguments (rc, targs);

				// Get all the method parameters and pass them as arguments
				var real_base_call = new Invocation (mg, block.GetAllParametersArguments ());
				Statement statement;
				if (method.ReturnType == TypeManager.void_type)
					statement = new StatementExpression (real_base_call);
				else
					statement = new Return (real_base_call, Location);

				block.AddStatement (statement);
				proxy_method.Block = block;

				methods.Add (proxy_method);
				proxy_method.Define ();

				hoisted_base_call_proxies.Add (method, proxy_method);
			}

			return proxy_method.Spec;
		}

		bool DefineBaseTypes ()
		{
			iface_exprs = ResolveBaseTypes (out base_type_expr);
			if (partial_parts != null) {
				iface_exprs = GetNormalPartialBases ();
			}

			var cycle = CheckRecursiveDefinition (this);
			if (cycle != null) {
				Report.SymbolRelatedToPreviousError (cycle);
				if (this is Interface) {
					Report.Error (529, Location,
						"Inherited interface `{0}' causes a cycle in the interface hierarchy of `{1}'",
					    GetSignatureForError (), cycle.GetSignatureForError ());

					iface_exprs = null;
				} else {
					Report.Error (146, Location,
						"Circular base class dependency involving `{0}' and `{1}'",
						GetSignatureForError (), cycle.GetSignatureForError ());

					base_type = null;
				}
			}

			if (iface_exprs != null) {
				foreach (TypeExpr iface in iface_exprs) {
					// Prevents a crash, the interface might not have been resolved: 442144
					if (iface == null)
						continue;
					
					var iface_type = iface.Type;

					if (!spec.AddInterface (iface_type))
						continue;

					if (iface_type.IsGeneric && spec.Interfaces != null) {
						foreach (var prev_iface in iface_exprs) {
							if (prev_iface == iface)
								break;

							if (!TypeSpecComparer.Unify.IsEqual (iface_type, prev_iface.Type))
								continue;

							Report.Error (695, Location,
								"`{0}' cannot implement both `{1}' and `{2}' because they may unify for some type parameter substitutions",
								GetSignatureForError (), prev_iface.GetSignatureForError (), iface_type.GetSignatureForError ());
						}
					}

					TypeBuilder.AddInterfaceImplementation (iface_type.GetMetaInfo ());

					// Ensure the base is always setup
					var compiled_iface = iface_type.MemberDefinition as Interface;
					if (compiled_iface != null) {
						// TODO: Need DefineBaseType only
						compiled_iface.DefineType ();
					}

					if (iface_type.Interfaces != null) {
						var base_ifaces = new List<TypeSpec> (iface_type.Interfaces);
						for (int i = 0; i < base_ifaces.Count; ++i) {
							var ii_iface_type = base_ifaces[i];
							if (spec.AddInterface (ii_iface_type)) {
								TypeBuilder.AddInterfaceImplementation (ii_iface_type.GetMetaInfo ());

								if (ii_iface_type.Interfaces != null)
									base_ifaces.AddRange (ii_iface_type.Interfaces);
							}
						}
					}
				}
			}

			if (Kind == MemberKind.Interface) {
				spec.BaseType = TypeManager.object_type;
				return true;
			}

			if (base_type != null) {
				spec.BaseType = base_type;

				// Set base type after type creation
				TypeBuilder.SetParent (base_type.GetMetaInfo ());
			}

			return true;
		}

		public virtual void DefineConstants ()
		{
			if (constants != null) {
				foreach (Const c in constants) {
					c.DefineValue ();
				}
			}

			if (instance_constructors != null) {
				foreach (MethodCore m in instance_constructors) {
					var p = m.ParameterInfo;
					if (!p.IsEmpty) {
						p.ResolveDefaultValues (m);
					}
				}
			}

			if (methods != null) {
				foreach (MethodCore m in methods) {
					var p = m.ParameterInfo;
					if (!p.IsEmpty) {
						p.ResolveDefaultValues (m);
					}
				}
			}

			if (indexers != null) {
				foreach (Indexer i in indexers) {
					i.ParameterInfo.ResolveDefaultValues (i);
				}
			}

			if (types != null) {
				foreach (var t in types)
					t.DefineConstants ();
			}
		}

		//
		// Defines the type in the appropriate ModuleBuilder or TypeBuilder.
		//
		public bool CreateType ()
		{
			if (TypeBuilder != null)
				return !error;

			if (error)
				return false;

			if (!CreateTypeBuilder ()) {
				error = true;
				return false;
			}

			if (partial_parts != null) {
				foreach (TypeContainer part in partial_parts) {
					part.spec = spec;
					part.current_type = current_type;
					part.TypeBuilder = TypeBuilder;
				}
			}

			if (Types != null) {
				foreach (TypeContainer tc in Types) {
					tc.CreateType ();
				}
			}

			return true;
		}

		public override void DefineType ()
		{
			if (error)
				return;
			if (type_defined)
				return;

			type_defined = true;

			if (!DefineBaseTypes ()) {
				error = true;
				return;
			}

			if (!DefineNestedTypes ()) {
				error = true;
				return;
			}
		}

		public override void SetParameterInfo (List<Constraints> constraints_list)
		{
			base.SetParameterInfo (constraints_list);

			if (PartialContainer.CurrentTypeParameters == null || PartialContainer == this)
				return;

			TypeParameter[] tc_names = PartialContainer.CurrentTypeParameters;
			for (int i = 0; i < tc_names.Length; ++i) {
				if (tc_names [i].Name != type_params [i].Name) {
					Report.SymbolRelatedToPreviousError (PartialContainer.Location, "");
					Report.Error (264, Location, "Partial declarations of `{0}' must have the same type parameter names in the same order",
						GetSignatureForError ());
					break;
				}

				if (tc_names [i].Variance != type_params [i].Variance) {
					Report.SymbolRelatedToPreviousError (PartialContainer.Location, "");
					Report.Error (1067, Location, "Partial declarations of `{0}' must have the same type parameter variance modifiers",
						GetSignatureForError ());
					break;
				}
			}
		}

		//
		// Replaces normal spec with predefined one when compiling corlib
		// and this type container defines predefined type
		//
		public void SetPredefinedSpec (BuildinTypeSpec spec)
		{
			this.spec = spec;
		}

		void UpdateTypeParameterConstraints (TypeContainer part)
		{
			TypeParameter[] current_params = type_params;
			for (int i = 0; i < current_params.Length; i++) {
				if (current_params [i].AddPartialConstraints (part, part.type_params [i]))
					continue;

				Report.SymbolRelatedToPreviousError (Location, "");
				Report.Error (265, part.Location,
					"Partial declarations of `{0}' have inconsistent constraints for type parameter `{1}'",
					GetSignatureForError (), current_params [i].GetSignatureForError ());
			}
		}

		public bool ResolveTypeParameters ()
		{
			if (!DoResolveTypeParameters ())
				return false;

			if (types != null) {
				foreach (var type in types)
					if (!type.ResolveTypeParameters ())
						return false;
			}

			if (compiler_generated != null) {
				foreach (CompilerGeneratedClass c in compiler_generated)
					if (!c.ResolveTypeParameters ())
						return false;
			}

			return true;
		}

		protected virtual bool DoResolveTypeParameters ()
		{
			if (CurrentTypeParameters == null)
				return true;

			if (PartialContainer != this)
				throw new InternalErrorException ();

			var base_context = new BaseContext (this);
			foreach (TypeParameter type_param in CurrentTypeParameters) {
				if (!type_param.ResolveConstraints (base_context)) {
					error = true;
					return false;
				}
			}

			if (partial_parts != null) {
				foreach (TypeContainer part in partial_parts)
					UpdateTypeParameterConstraints (part);
			}

			return true;
		}

		protected virtual bool DefineNestedTypes ()
		{
			if (Types != null) {
				foreach (TypeContainer tc in Types)
					tc.DefineType ();
			}

			return true;
		}

		TypeSpec CheckRecursiveDefinition (TypeContainer tc)
		{
			if (InTransit != null)
				return spec;

			InTransit = tc;

			if (base_type_expr != null) {
				var ptc = base_type.MemberDefinition as TypeContainer;
				if (ptc != null && ptc.CheckRecursiveDefinition (this) != null)
					return base_type;
			}

			if (iface_exprs != null) {
				foreach (TypeExpr iface in iface_exprs) {
					// the interface might not have been resolved, prevents a crash, see #442144
					if (iface == null)
						continue;
					var ptc = iface.Type.MemberDefinition as Interface;
					if (ptc != null && ptc.CheckRecursiveDefinition (this) != null)
						return iface.Type;
				}
			}

			if (!IsTopLevel && Parent.PartialContainer.CheckRecursiveDefinition (this) != null)
				return spec;

			InTransit = null;
			return null;
		}

		/// <summary>
		///   Populates our TypeBuilder with fields and methods
		/// </summary>
		public sealed override bool Define ()
		{
			if (members_defined)
				return members_defined_ok;

			members_defined_ok = DoDefineMembers ();
			members_defined = true;

			if (types != null) {
				foreach (var nested in types)
					nested.Define ();
			}

			return members_defined_ok;
		}

		protected virtual bool DoDefineMembers ()
		{
			if (iface_exprs != null) {
				foreach (TypeExpr iface in iface_exprs) {
					if (iface == null)
						continue;

					var iface_type = iface.Type;

					// Ensure the base is always setup
					var compiled_iface = iface_type.MemberDefinition as Interface;
					if (compiled_iface != null)
						compiled_iface.Define ();

					if (Kind == MemberKind.Interface)
						MemberCache.AddInterface (iface_type);

					ObsoleteAttribute oa = iface_type.GetAttributeObsolete ();
					if (oa != null && !IsObsolete)
						AttributeTester.Report_ObsoleteMessage (oa, iface.GetSignatureForError (), Location, Report);

					GenericTypeExpr ct = iface as GenericTypeExpr;
					if (ct != null) {
						// TODO: passing `this' is wrong, should be base type iface instead
						TypeManager.CheckTypeVariance (ct.Type, Variance.Covariant, this);

						ct.CheckConstraints (this);

						if (ct.HasDynamicArguments () && !IsCompilerGenerated) {
							Report.Error (1966, iface.Location,
								"`{0}': cannot implement a dynamic interface `{1}'",
								GetSignatureForError (), iface.GetSignatureForError ());
							return false;
						}
					}
				}
			}

			if (base_type != null) {
				ObsoleteAttribute obsolete_attr = base_type.GetAttributeObsolete ();
				if (obsolete_attr != null && !IsObsolete)
					AttributeTester.Report_ObsoleteMessage (obsolete_attr, base_type.GetSignatureForError (), Location, Report);

				var ct = base_type_expr as GenericTypeExpr;
				if (ct != null)
					ct.CheckConstraints (this);

				if (base_type.Interfaces != null) {
					foreach (var iface in base_type.Interfaces)
						spec.AddInterface (iface);
				}

				var baseContainer = base_type.MemberDefinition as ClassOrStruct;
				if (baseContainer != null) {
					baseContainer.Define ();

					//
					// It can trigger define of this type (for generic types only)
					//
					if (HasMembersDefined)
						return true;
				}
			}

			if (type_params != null) {
				foreach (var tp in type_params) {
					tp.CheckGenericConstraints ();
				}
			}

			DefineContainerMembers (constants);
			DefineContainerMembers (fields);

			if (Kind == MemberKind.Struct || Kind == MemberKind.Class) {
				pending = PendingImplementation.GetPendingImplementations (this);

				if (requires_delayed_unmanagedtype_check) {
					requires_delayed_unmanagedtype_check = false;
					foreach (FieldBase f in fields) {
						if (f.MemberType != null && f.MemberType.IsPointer)
							TypeManager.VerifyUnmanaged (Compiler, f.MemberType, f.Location);
					}
				}
			}
		
			//
			// Constructors are not in the defined_names array
			//
			DefineContainerMembers (instance_constructors);
		
			DefineContainerMembers (events);
			DefineContainerMembers (ordered_explicit_member_list);
			DefineContainerMembers (ordered_member_list);

			if (operators != null) {
				DefineContainerMembers (operators);
				CheckPairedOperators ();
			}

			ComputeIndexerName();
			CheckEqualsAndGetHashCode();

			return true;
		}

		protected virtual void DefineContainerMembers (System.Collections.IList mcal) // IList<MemberCore>
		{
			if (mcal != null) {
				for (int i = 0; i < mcal.Count; ++i) {
					MemberCore mc = (MemberCore) mcal[i];
					try {
						mc.Define ();
					} catch (Exception e) {
						throw new InternalErrorException (mc, e);
					}
				}
			}
		}
		
		protected virtual void ComputeIndexerName ()
		{
			if (indexers == null)
				return;

			string class_indexer_name = null;

			//
			// If there's both an explicit and an implicit interface implementation, the
			// explicit one actually implements the interface while the other one is just
			// a normal indexer.  See bug #37714.
			//

			// Invariant maintained by AddIndexer(): All explicit interface indexers precede normal indexers
			foreach (Indexer i in indexers) {
				if (i.InterfaceType != null) {
					if (seen_normal_indexers)
						throw new Exception ("Internal Error: 'Indexers' array not sorted properly.");
					continue;
				}

				seen_normal_indexers = true;

				if (class_indexer_name == null) {
					class_indexer_name = i.ShortName;
					continue;
				}

				if (i.ShortName != class_indexer_name)
					Report.Error (668, i.Location, "Two indexers have different names; the IndexerName attribute must be used with the same name on every indexer within a type");
			}

			if (class_indexer_name != null)
				indexer_name = class_indexer_name;
		}

		void EmitIndexerName ()
		{
			if (!seen_normal_indexers)
				return;

			PredefinedAttribute pa = Module.PredefinedAttributes.DefaultMember;
			if (pa.Constructor == null &&
				!pa.ResolveConstructor (Location, TypeManager.string_type))
				return;

			var encoder = new AttributeEncoder ();
			encoder.Encode (GetAttributeDefaultMember ());
			encoder.EncodeEmptyNamedArguments ();

			pa.EmitAttribute (TypeBuilder, encoder);
		}

		protected virtual void CheckEqualsAndGetHashCode ()
		{
			if (methods == null)
				return;

			if (HasEquals && !HasGetHashCode) {
				Report.Warning (659, 3, this.Location, "`{0}' overrides Object.Equals(object) but does not override Object.GetHashCode()", this.GetSignatureForError ());
			}
		}

		// Indicated whether container has StructLayout attribute set Explicit
		public bool HasExplicitLayout {
			get { return (caching_flags & Flags.HasExplicitLayout) != 0; }
			set { caching_flags |= Flags.HasExplicitLayout; }
		}

		public bool HasStructLayout {
			get { return (caching_flags & Flags.HasStructLayout) != 0; }
			set { caching_flags |= Flags.HasStructLayout; }
		}

		public MemberCache MemberCache {
			get {
				return spec.MemberCache;
			}
		}

		void CheckMemberUsage (List<MemberCore> al, string member_type)
		{
			if (al == null)
				return;

			foreach (MemberCore mc in al) {
				if ((mc.ModFlags & Modifiers.AccessibilityMask) != Modifiers.PRIVATE)
					continue;

				if (!mc.IsUsed && (mc.caching_flags & Flags.Excluded) == 0) {
					Report.Warning (169, 3, mc.Location, "The private {0} `{1}' is never used", member_type, mc.GetSignatureForError ());
				}
			}
		}

		public virtual void VerifyMembers ()
		{
			//
			// Check for internal or private fields that were never assigned
			//
			if (Report.WarningLevel >= 3) {
				if (RootContext.EnhancedWarnings) {
					CheckMemberUsage (properties, "property");
					CheckMemberUsage (methods, "method");
					CheckMemberUsage (constants, "constant");
				}

				if (fields != null){
					bool is_type_exposed = Kind == MemberKind.Struct || IsExposedFromAssembly ();
					foreach (FieldBase f in fields) {
						if ((f.ModFlags & Modifiers.AccessibilityMask) != Modifiers.PRIVATE) {
							if (is_type_exposed)
								continue;

							f.SetIsUsed ();
						}				
						
						if (!f.IsUsed){
							if ((f.caching_flags & Flags.IsAssigned) == 0)
								Report.Warning (169, 3, f.Location, "The private field `{0}' is never used", f.GetSignatureForError ());
							else {
								Report.Warning (414, 3, f.Location, "The private field `{0}' is assigned but its value is never used",
									f.GetSignatureForError ());
							}
							continue;
						}
						
						//
						// Only report 649 on level 4
						//
						if (Report.WarningLevel < 4)
							continue;
						
						if ((f.caching_flags & Flags.IsAssigned) != 0)
							continue;

						//
						// Don't be pendatic over serializable attributes
						//
						if (f.OptAttributes != null || PartialContainer.HasStructLayout)
							continue;
						
						Constant c = New.Constantify (f.MemberType, f.Location);
						Report.Warning (649, 4, f.Location, "Field `{0}' is never assigned to, and will always have its default value `{1}'",
							f.GetSignatureForError (), c == null ? "null" : c.AsString ());
					}
				}
			}
		}

		public override void Emit ()
		{
			if (!IsTopLevel) {
				MemberSpec candidate;
				var conflict_symbol = MemberCache.FindBaseMember (this, out candidate);
				if (conflict_symbol == null && candidate == null) {
					if ((ModFlags & Modifiers.NEW) != 0)
						Report.Warning (109, 4, Location, "The member `{0}' does not hide an inherited member. The new keyword is not required",
							GetSignatureForError ());
				} else {
					if ((ModFlags & Modifiers.NEW) == 0) {
						if (candidate == null)
							candidate = conflict_symbol;

						Report.SymbolRelatedToPreviousError (candidate);
						Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
							GetSignatureForError (), candidate.GetSignatureForError ());
					}
				}
			}

			if (all_tp_builders != null) {
				int current_starts_index = CurrentTypeParametersStartIndex;
				for (int i = 0; i < all_tp_builders.Length; i++) {
					if (i < current_starts_index) {
						TypeParameters[i].EmitConstraints (all_tp_builders [i]);
					} else {
						CurrentTypeParameters [i - current_starts_index].Emit ();
					}
				}
			}

			if ((ModFlags & Modifiers.COMPILER_GENERATED) != 0 && !Parent.IsCompilerGenerated)
				Module.PredefinedAttributes.CompilerGenerated.EmitAttribute (TypeBuilder);

			base.Emit ();
		}

		// TODO: move to ClassOrStruct
		void EmitConstructors ()
		{
			if (instance_constructors == null)
				return;

			if (spec.IsAttribute && IsExposedFromAssembly () && RootContext.VerifyClsCompliance && IsClsComplianceRequired ()) {
				bool has_compliant_args = false;

				foreach (Constructor c in instance_constructors) {
					try {
						c.Emit ();
					}
					catch (Exception e) {
						throw new InternalErrorException (c, e);
					}

					if (has_compliant_args)
						continue;

					has_compliant_args = c.HasCompliantArgs;
				}
				if (!has_compliant_args)
					Report.Warning (3015, 1, Location, "`{0}' has no accessible constructors which use only CLS-compliant types", GetSignatureForError ());
			} else {
				foreach (Constructor c in instance_constructors) {
					try {
						c.Emit ();
					}
					catch (Exception e) {
						throw new InternalErrorException (c, e);
					}
				}
			}
		}

		/// <summary>
		///   Emits the code, this step is performed after all
		///   the types, enumerations, constructors
		/// </summary>
		public virtual void EmitType ()
		{
			if (OptAttributes != null)
				OptAttributes.Emit ();

			Emit ();

			EmitConstructors ();

			if (constants != null)
				foreach (Const con in constants)
					con.Emit ();

			if (default_static_constructor != null)
				default_static_constructor.Emit ();
			
			if (operators != null)
				foreach (Operator o in operators)
					o.Emit ();

			if (properties != null)
				foreach (Property p in properties)
					p.Emit ();

			if (indexers != null) {
				foreach (Indexer indx in indexers)
					indx.Emit ();
				EmitIndexerName ();
			}

			if (events != null){
				foreach (Event e in Events)
					e.Emit ();
			}

			if (methods != null) {
				for (int i = 0; i < methods.Count; ++i)
					((MethodOrOperator) methods [i]).Emit ();
			}
			
			if (fields != null)
				foreach (FieldBase f in fields)
					f.Emit ();

			if (types != null) {
				foreach (TypeContainer t in types)
					t.EmitType ();
			}

			if (pending != null)
				pending.VerifyPendingMethods (Report);

			if (Report.Errors > 0)
				return;

			if (compiler_generated != null) {
				for (int i = 0; i < compiler_generated.Count; ++i)
					compiler_generated [i].EmitType ();
			}
		}

		public virtual void CloseType ()
		{
			if ((caching_flags & Flags.CloseTypeCreated) != 0)
				return;

			// Close base type container first to avoid TypeLoadException
			if (spec.BaseType != null) {
				var btype = spec.BaseType.MemberDefinition as TypeContainer;
				if (btype != null) {
					btype.CloseType ();

					if ((caching_flags & Flags.CloseTypeCreated) != 0)
						return;
				}
			}

			try {
				caching_flags |= Flags.CloseTypeCreated;
				TypeBuilder.CreateType ();
			} catch (TypeLoadException){
				//
				// This is fine, the code still created the type
				//
//				Report.Warning (-20, "Exception while creating class: " + TypeBuilder.Name);
//				Console.WriteLine (e.Message);
			} catch (Exception e) {
				throw new InternalErrorException (this, e);
			}
			
			if (Types != null){
				foreach (TypeContainer tc in Types)
					tc.CloseType ();
			}

			if (compiler_generated != null)
				foreach (CompilerGeneratedClass c in compiler_generated)
					c.CloseType ();
			
			types = null;
			fields = null;
			initialized_fields = null;
			initialized_static_fields = null;
			constants = null;
			ordered_explicit_member_list = null;
			ordered_member_list = null;
			methods = null;
			events = null;
			indexers = null;
			operators = null;
			compiler_generated = null;
			default_constructor = null;
			default_static_constructor = null;
			type_bases = null;
			OptAttributes = null;
		}

		//
		// Performs the validation on a Method's modifiers (properties have
		// the same properties).
		//
		// TODO: Why is it not done at parse stage ?
		//
		public bool MethodModifiersValid (MemberCore mc)
		{
			const Modifiers vao = (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE);
			const Modifiers nv = (Modifiers.NEW | Modifiers.VIRTUAL);
			bool ok = true;
			var flags = mc.ModFlags;
			
			//
			// At most one of static, virtual or override
			//
			if ((flags & Modifiers.STATIC) != 0){
				if ((flags & vao) != 0){
					Report.Error (112, mc.Location, "A static member `{0}' cannot be marked as override, virtual or abstract",
						mc.GetSignatureForError ());
					ok = false;
				}
			}

			if ((flags & Modifiers.OVERRIDE) != 0 && (flags & nv) != 0){
				Report.Error (113, mc.Location, "A member `{0}' marked as override cannot be marked as new or virtual",
					mc.GetSignatureForError ());
				ok = false;
			}

			//
			// If the declaration includes the abstract modifier, then the
			// declaration does not include static, virtual or extern
			//
			if ((flags & Modifiers.ABSTRACT) != 0){
				if ((flags & Modifiers.EXTERN) != 0){
					Report.Error (
						180, mc.Location, "`{0}' cannot be both extern and abstract", mc.GetSignatureForError ());
					ok = false;
				}

				if ((flags & Modifiers.SEALED) != 0) {
					Report.Error (502, mc.Location, "`{0}' cannot be both abstract and sealed", mc.GetSignatureForError ());
					ok = false;
				}

				if ((flags & Modifiers.VIRTUAL) != 0){
					Report.Error (503, mc.Location, "The abstract method `{0}' cannot be marked virtual", mc.GetSignatureForError ());
					ok = false;
				}

				if ((ModFlags & Modifiers.ABSTRACT) == 0){
					Report.SymbolRelatedToPreviousError (this);
					Report.Error (513, mc.Location, "`{0}' is abstract but it is declared in the non-abstract class `{1}'",
						mc.GetSignatureForError (), GetSignatureForError ());
					ok = false;
				}
			}

			if ((flags & Modifiers.PRIVATE) != 0){
				if ((flags & vao) != 0){
					Report.Error (621, mc.Location, "`{0}': virtual or abstract members cannot be private", mc.GetSignatureForError ());
					ok = false;
				}
			}

			if ((flags & Modifiers.SEALED) != 0){
				if ((flags & Modifiers.OVERRIDE) == 0){
					Report.Error (238, mc.Location, "`{0}' cannot be sealed because it is not an override", mc.GetSignatureForError ());
					ok = false;
				}
			}

			return ok;
		}

		public Constructor DefaultStaticConstructor {
			get { return default_static_constructor; }
		}

		protected override bool VerifyClsCompliance ()
		{
			if (!base.VerifyClsCompliance ())
				return false;

			// Check this name against other containers
			NamespaceEntry.NS.VerifyClsCompliance ();

			// Check all container names for user classes
			if (Kind != MemberKind.Delegate)
				MemberCache.VerifyClsCompliance (Definition, Report);

			if (BaseType != null && !BaseType.IsCLSCompliant ()) {
				Report.Warning (3009, 1, Location, "`{0}': base type `{1}' is not CLS-compliant",
					GetSignatureForError (), BaseType.GetSignatureForError ());
			}
			return true;
		}

		/// <summary>
		///   Performs checks for an explicit interface implementation.  First it
		///   checks whether the `interface_type' is a base inteface implementation.
		///   Then it checks whether `name' exists in the interface type.
		/// </summary>
		public bool VerifyImplements (InterfaceMemberBase mb)
		{
			var ifaces = spec.Interfaces;
			if (ifaces != null) {
				foreach (TypeSpec t in ifaces){
					if (t == mb.InterfaceType)
						return true;
				}
			}
			
			Report.SymbolRelatedToPreviousError (mb.InterfaceType);
			Report.Error (540, mb.Location, "`{0}': containing type does not implement interface `{1}'",
				mb.GetSignatureForError (), TypeManager.CSharpName (mb.InterfaceType));
			return false;
		}

		//
		// Used for visiblity checks to tests whether this definition shares
		// base type baseType, it does member-definition search
		//
		public bool IsBaseTypeDefinition (TypeSpec baseType)
		{
			// RootContext check
			if (TypeBuilder == null)
				return false;

			var type = spec;
			do {
				if (type.MemberDefinition == baseType.MemberDefinition)
					return true;

				type = type.BaseType;
			} while (type != null);

			return false;
		}

		bool ITypeDefinition.IsInternalAsPublic (IAssemblyDefinition assembly)
		{
			return Module.DeclaringAssembly == assembly;
		}

		public void LoadMembers (TypeSpec declaringType, bool onlyTypes, ref MemberCache cache)
		{
			throw new NotSupportedException ("Not supported for compiled definition " + GetSignatureForError ());
		}

		//
		// Public function used to locate types.
		//
		// Set 'ignore_cs0104' to true if you want to ignore cs0104 errors.
		//
		// Returns: Type or null if they type can not be found.
		//
		public override FullNamedExpression LookupNamespaceOrType (string name, int arity, Location loc, bool ignore_cs0104)
		{
			FullNamedExpression e;
			if (arity == 0 && Cache.TryGetValue (name, out e))
				return e;

			e = null;
			int errors = Report.Errors;

			if (arity == 0) {
				TypeParameter[] tp = CurrentTypeParameters;
				if (tp != null) {
					TypeParameter tparam = TypeParameter.FindTypeParameter (tp, name);
					if (tparam != null)
						e = new TypeParameterExpr (tparam, Location.Null);
				}
			}

			if (e == null) {
				TypeSpec t = LookupNestedTypeInHierarchy (name, arity);

				if (t != null)
					e = new TypeExpression (t, Location.Null);
				else if (Parent != null) {
					e = Parent.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
				} else
					e = NamespaceEntry.LookupNamespaceOrType (name, arity, loc, ignore_cs0104);
			}

			// TODO MemberCache: How to cache arity stuff ?
			if (errors == Report.Errors && arity == 0)
				Cache[name] = e;

			return e;
		}

		TypeSpec LookupNestedTypeInHierarchy (string name, int arity)
		{
			// TODO: GenericMethod only
			if (PartialContainer == null)
				return null;

			// Has any nested type
			// Does not work, because base type can have
			//if (PartialContainer.Types == null)
			//	return null;

			var container = PartialContainer.CurrentType;

			// Is not Root container
			if (container == null)
				return null;

			var t = MemberCache.FindNestedType (container, name, arity);
			if (t == null)
				return null;

			// FIXME: Breaks error reporting
			if (!t.IsAccessible (CurrentType))
				return null;

			return t;
		}

		public void Mark_HasEquals ()
		{
			cached_method |= CachedMethods.Equals;
		}

		public void Mark_HasGetHashCode ()
		{
			cached_method |= CachedMethods.GetHashCode;
		}

		/// <summary>
		/// Method container contains Equals method
		/// </summary>
		public bool HasEquals {
			get {
				return (cached_method & CachedMethods.Equals) != 0;
			}
		}
 
		/// <summary>
		/// Method container contains GetHashCode method
		/// </summary>
		public bool HasGetHashCode {
			get {
				return (cached_method & CachedMethods.GetHashCode) != 0;
			}
		}

		public bool HasStaticFieldInitializer {
			get {
				return (cached_method & CachedMethods.HasStaticFieldInitializer) != 0;
			}
			set {
				if (value)
					cached_method |= CachedMethods.HasStaticFieldInitializer;
				else
					cached_method &= ~CachedMethods.HasStaticFieldInitializer;
			}
		}

		//
		// Generates xml doc comments (if any), and if required,
		// handle warning report.
		//
		internal override void GenerateDocComment (DeclSpace ds)
		{
			DocUtil.GenerateTypeDocComment (this, ds, Report);
		}

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

	public abstract class ClassOrStruct : TypeContainer
	{
		SecurityType declarative_security;

		public ClassOrStruct (NamespaceEntry ns, DeclSpace parent,
				      MemberName name, Attributes attrs, MemberKind kind)
			: base (ns, parent, name, attrs, kind)
		{
		}

		protected override bool AddToContainer (MemberCore symbol, string name)
		{
			if (!(symbol is Constructor) && symbol.MemberName.Name == MemberName.Name) {
				if (symbol is TypeParameter) {
					Report.Error (694, symbol.Location,
						"Type parameter `{0}' has same name as containing type, or method",
						symbol.GetSignatureForError ());
					return false;
				}
			
				InterfaceMemberBase imb = symbol as InterfaceMemberBase;
				if (imb == null || !imb.IsExplicitImpl) {
					Report.SymbolRelatedToPreviousError (this);
					Report.Error (542, symbol.Location, "`{0}': member names cannot be the same as their enclosing type",
						symbol.GetSignatureForError ());
					return false;
				}
			}

			return base.AddToContainer (symbol, name);
		}

		public override void VerifyMembers ()
		{
			base.VerifyMembers ();

			if ((events != null) && Report.WarningLevel >= 3) {
				foreach (Event e in events){
					// Note: The event can be assigned from same class only, so we can report
					// this warning for all accessibility modes
					if ((e.caching_flags & Flags.IsUsed) == 0)
						Report.Warning (67, 3, e.Location, "The event `{0}' is never used", e.GetSignatureForError ());
				}
			}

			if (types != null) {
				foreach (var t in types)
					t.VerifyMembers ();
			}
		}

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			if (a.IsValidSecurityAttribute ()) {
				a.ExtractSecurityPermissionSet (ctor, ref declarative_security);
				return;
			}

			if (a.Type == pa.StructLayout) {
				PartialContainer.HasStructLayout = true;
				if (a.IsExplicitLayoutKind ())
					PartialContainer.HasExplicitLayout = true;
			}

			if (a.Type == pa.Dynamic) {
				a.Error_MisusedDynamicAttribute ();
				return;
			}

			base.ApplyAttributeBuilder (a, ctor, cdata, pa);
		}

		/// <summary>
		/// Defines the default constructors 
		/// </summary>
		protected void DefineDefaultConstructor (bool is_static)
		{
			// The default instance constructor is public
			// If the class is abstract, the default constructor is protected
			// The default static constructor is private

			Modifiers mods;
			if (is_static) {
				mods = Modifiers.STATIC | Modifiers.PRIVATE;
			} else {
				mods = ((ModFlags & Modifiers.ABSTRACT) != 0) ? Modifiers.PROTECTED : Modifiers.PUBLIC;
			}

			Constructor c = new Constructor (this, MemberName.Name, mods,
				null, ParametersCompiled.EmptyReadOnlyParameters,
				new GeneratedBaseInitializer (Location),
				Location);
			
			AddConstructor (c);
			c.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location);
		}

		protected override bool DoDefineMembers ()
		{
			CheckProtectedModifier ();

			base.DoDefineMembers ();

			if (default_static_constructor != null)
				default_static_constructor.Define ();

			return true;
		}

		public override void Emit ()
		{
			if (default_static_constructor == null && PartialContainer.HasStaticFieldInitializer) {
				DefineDefaultConstructor (true);
				default_static_constructor.Define ();
			}

			base.Emit ();

			if (declarative_security != null) {
				foreach (var de in declarative_security) {
#if STATIC
					TypeBuilder.__AddDeclarativeSecurity (de);
#else
					TypeBuilder.AddDeclarativeSecurity (de.Key, de.Value);
#endif
				}
			}
		}

		public override IList<MethodSpec> LookupExtensionMethod (TypeSpec extensionType, string name, int arity, ref NamespaceEntry scope)
		{
			DeclSpace top_level = Parent;
			if (top_level != null) {
				while (top_level.Parent != null)
					top_level = top_level.Parent;

				var candidates = NamespaceEntry.NS.LookupExtensionMethod (extensionType, this, name, arity);
				if (candidates != null) {
					scope = NamespaceEntry;
					return candidates;
				}
			}

			return NamespaceEntry.LookupExtensionMethod (extensionType, name, arity, ref scope);
		}

		protected override TypeAttributes TypeAttr {
			get {
				if (default_static_constructor == null)
					return base.TypeAttr | TypeAttributes.BeforeFieldInit;

				return base.TypeAttr;
			}
		}
	}


	// TODO: should be sealed
	public class Class : ClassOrStruct {
		const Modifiers AllowedModifiers =
			Modifiers.NEW |
			Modifiers.PUBLIC |
			Modifiers.PROTECTED |
			Modifiers.INTERNAL |
			Modifiers.PRIVATE |
			Modifiers.ABSTRACT |
			Modifiers.SEALED |
			Modifiers.STATIC |
			Modifiers.UNSAFE;

		public const TypeAttributes StaticClassAttribute = TypeAttributes.Abstract | TypeAttributes.Sealed;

		public Class (NamespaceEntry ns, DeclSpace parent, MemberName name, Modifiers mod,
			      Attributes attrs)
			: base (ns, parent, name, attrs, MemberKind.Class)
		{
			var accmods = (Parent == null || Parent.Parent == null) ? Modifiers.INTERNAL : Modifiers.PRIVATE;
			this.ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod, accmods, Location, Report);
			spec = new TypeSpec (Kind, null, this, null, ModFlags);

			if (IsStatic && RootContext.Version == LanguageVersion.ISO_1) {
				Report.FeatureIsNotAvailable (Location, "static classes");
			}
		}

		public override void AddBasesForPart (DeclSpace part, List<FullNamedExpression> bases)
		{
			if (part.Name == "System.Object")
				Report.Error (537, part.Location,
					"The class System.Object cannot have a base class or implement an interface.");
			base.AddBasesForPart (part, bases);
		}

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			if (a.Type == pa.AttributeUsage) {
				if (!BaseType.IsAttribute && spec != TypeManager.attribute_type) {
					Report.Error (641, a.Location, "Attribute `{0}' is only valid on classes derived from System.Attribute", a.GetSignatureForError ());
				}
			}

			if (a.Type == pa.Conditional && !BaseType.IsAttribute) {
				Report.Error (1689, a.Location, "Attribute `System.Diagnostics.ConditionalAttribute' is only valid on methods or attribute classes");
				return;
			}

			if (a.Type == pa.ComImport && !attributes.Contains (pa.Guid)) {
				a.Error_MissingGuidAttribute ();
				return;
			}

			if (a.Type == pa.Extension) {
				a.Error_MisusedExtensionAttribute ();
				return;
			}

			if (a.Type.IsConditionallyExcluded (Location))
				return;

			base.ApplyAttributeBuilder (a, ctor, cdata, pa);
		}

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

		protected override void DefineContainerMembers (System.Collections.IList list)
		{
			if (list == null)
				return;

			if (!IsStatic) {
				base.DefineContainerMembers (list);
				return;
			}

			foreach (MemberCore m in list) {
				if (m is Operator) {
					Report.Error (715, m.Location, "`{0}': Static classes cannot contain user-defined operators", m.GetSignatureForError ());
					continue;
				}

				if (m is Destructor) {
					Report.Error (711, m.Location, "`{0}': Static classes cannot contain destructor", GetSignatureForError ());
					continue;
				}

				if (m is Indexer) {
					Report.Error (720, m.Location, "`{0}': cannot declare indexers in a static class", m.GetSignatureForError ());
					continue;
				}

				if ((m.ModFlags & Modifiers.STATIC) != 0 || m is Enum || m is Delegate)
					continue;

				if (m is Constructor) {
					Report.Error (710, m.Location, "`{0}': Static classes cannot have instance constructors", GetSignatureForError ());
					continue;
				}

				Method method = m as Method;
				if (method != null && method.ParameterInfo.HasExtensionMethodType) {
					Report.Error (1105, m.Location, "`{0}': Extension methods must be declared static", m.GetSignatureForError ());
					continue;
				}

				Report.Error (708, m.Location, "`{0}': cannot declare instance members in a static class", m.GetSignatureForError ());
			}

			base.DefineContainerMembers (list);
		}

		protected override bool DoDefineMembers ()
		{
			if ((ModFlags & Modifiers.ABSTRACT) == Modifiers.ABSTRACT && (ModFlags & (Modifiers.SEALED | Modifiers.STATIC)) != 0) {
				Report.Error (418, Location, "`{0}': an abstract class cannot be sealed or static", GetSignatureForError ());
			}

			if ((ModFlags & (Modifiers.SEALED | Modifiers.STATIC)) == (Modifiers.SEALED | Modifiers.STATIC)) {
				Report.Error (441, Location, "`{0}': a class cannot be both static and sealed", GetSignatureForError ());
			}

			if (InstanceConstructors == null && !IsStatic)
				DefineDefaultConstructor (false);

			return base.DoDefineMembers ();
		}

		public override void Emit ()
		{
			base.Emit ();

			if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
				Module.PredefinedAttributes.Extension.EmitAttribute (TypeBuilder);

			if (base_type != null && base_type.HasDynamicElement) {
				Module.PredefinedAttributes.Dynamic.EmitAttribute (TypeBuilder, base_type, Location);
			}
		}

		protected override TypeExpr[] ResolveBaseTypes (out TypeExpr base_class)
		{
			TypeExpr[] ifaces = base.ResolveBaseTypes (out base_class);

			if (base_class == null) {
				if (spec != TypeManager.object_type)
					base_type = TypeManager.object_type;
			} else {
				if (base_type.IsGenericParameter){
					Report.Error (689, base_class.Location, "`{0}': Cannot derive from type parameter `{1}'",
						GetSignatureForError (), base_type.GetSignatureForError ());
				} else if (IsGeneric && base_type.IsAttribute) {
					Report.Error (698, base_class.Location,
						"A generic type cannot derive from `{0}' because it is an attribute class",
						base_class.GetSignatureForError ());
				} else if (base_type.IsStatic) {
					Report.SymbolRelatedToPreviousError (base_class.Type);
					Report.Error (709, Location, "`{0}': Cannot derive from static class `{1}'",
						GetSignatureForError (), base_type.GetSignatureForError ());
				} else if (base_type.IsSealed) {
					Report.SymbolRelatedToPreviousError (base_class.Type);
					Report.Error (509, Location, "`{0}': cannot derive from sealed type `{1}'",
						GetSignatureForError (), base_type.GetSignatureForError ());
				} else if (PartialContainer.IsStatic && base_class.Type != TypeManager.object_type) {
					Report.Error (713, Location, "Static class `{0}' cannot derive from type `{1}'. Static classes must derive from object",
						GetSignatureForError (), base_class.GetSignatureForError ());
				}

				if (base_type is BuildinTypeSpec && !(spec is BuildinTypeSpec) &&
					(base_type == TypeManager.enum_type || base_type == TypeManager.value_type || base_type == TypeManager.multicast_delegate_type ||
					base_type == TypeManager.delegate_type || base_type == TypeManager.array_type)) {
					Report.Error (644, Location, "`{0}' cannot derive from special class `{1}'",
						GetSignatureForError (), base_type.GetSignatureForError ());

					base_type = TypeManager.object_type;
				}

				if (!IsAccessibleAs (base_type)) {
					Report.SymbolRelatedToPreviousError (base_type);
					Report.Error (60, Location, "Inconsistent accessibility: base class `{0}' is less accessible than class `{1}'",
						base_type.GetSignatureForError (), GetSignatureForError ());
				}
			}

			if (PartialContainer.IsStatic && ifaces != null) {
				foreach (TypeExpr t in ifaces)
					Report.SymbolRelatedToPreviousError (t.Type);
				Report.Error (714, Location, "Static class `{0}' cannot implement interfaces", GetSignatureForError ());
			}

			return ifaces;
		}

		/// Search for at least one defined condition in ConditionalAttribute of attribute class
		/// Valid only for attribute classes.
		public override string[] ConditionalConditions ()
		{
			if ((caching_flags & (Flags.Excluded_Undetected | Flags.Excluded)) == 0)
				return null;

			caching_flags &= ~Flags.Excluded_Undetected;

			if (OptAttributes == null)
				return null;

			Attribute[] attrs = OptAttributes.SearchMulti (Module.PredefinedAttributes.Conditional);
			if (attrs == null)
				return null;

			string[] conditions = new string[attrs.Length];
			for (int i = 0; i < conditions.Length; ++i)
				conditions[i] = attrs[i].GetConditionalAttributeValue ();

			caching_flags |= Flags.Excluded;
			return conditions;
		}

		//
		// FIXME: How do we deal with the user specifying a different
		// layout?
		//
		protected override TypeAttributes TypeAttr {
			get {
				TypeAttributes ta = base.TypeAttr | TypeAttributes.AutoLayout | TypeAttributes.Class;
				if (IsStatic)
					ta |= StaticClassAttribute;
				return ta;
			}
		}
	}

	public sealed class Struct : ClassOrStruct {

		bool is_unmanaged, has_unmanaged_check_done;
		bool InTransit;

		// <summary>
		//   Modifiers allowed in a struct declaration
		// </summary>
		const Modifiers AllowedModifiers =
			Modifiers.NEW       |
			Modifiers.PUBLIC    |
			Modifiers.PROTECTED |
			Modifiers.INTERNAL  |
			Modifiers.UNSAFE    |
			Modifiers.PRIVATE;

		public Struct (NamespaceEntry ns, DeclSpace parent, MemberName name,
			       Modifiers mod, Attributes attrs)
			: base (ns, parent, name, attrs, MemberKind.Struct)
		{
			var accmods = parent.Parent == null ? Modifiers.INTERNAL : Modifiers.PRIVATE;			
			this.ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod, accmods, Location, Report) | Modifiers.SEALED ;
			spec = new TypeSpec (Kind, null, this, null, ModFlags);
		}

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

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			base.ApplyAttributeBuilder (a, ctor, cdata, pa);

			//
			// When struct constains fixed fixed and struct layout has explicitly
			// set CharSet, its value has to be propagated to compiler generated
			// fixed types
			//
			if (a.Type == pa.StructLayout && Fields != null) {
				var value = a.GetNamedValue ("CharSet");
				if (value == null)
					return;

				for (int i = 0; i < Fields.Count; ++i) {
					FixedField ff = Fields [i] as FixedField;
					if (ff == null)
						continue;

					ff.CharSet = (CharSet) System.Enum.Parse (typeof (CharSet), value.GetValue ().ToString ());
				}
			}
		}

		bool CheckStructCycles (Struct s)
		{
			if (s.Fields == null)
				return true;

			if (s.InTransit)
				return false;

			s.InTransit = true;
			foreach (FieldBase field in s.Fields) {
				TypeSpec ftype = field.Spec.MemberType;
				if (!ftype.IsStruct)
					continue;

				if (ftype is BuildinTypeSpec)
					continue;

				foreach (var targ in ftype.TypeArguments) {
					if (!CheckFieldTypeCycle (targ)) {
						Report.Error (523, field.Location,
							"Struct member `{0}' of type `{1}' causes a cycle in the struct layout",
							field.GetSignatureForError (), ftype.GetSignatureForError ());
						break;
					}
				}

				if ((field.IsStatic && (!ftype.IsGeneric || ftype == CurrentType)))
					continue;

				if (!CheckFieldTypeCycle (ftype)) {
					Report.Error (523, field.Location,
						"Struct member `{0}' of type `{1}' causes a cycle in the struct layout",
						field.GetSignatureForError (), ftype.GetSignatureForError ());
					break;
				}
			}

			s.InTransit = false;
			return true;
		}

		bool CheckFieldTypeCycle (TypeSpec ts)
		{
			var fts = ts.MemberDefinition as Struct;
			if (fts == null)
				return true;

			return CheckStructCycles (fts);
		}

		public override void Emit ()
		{
			CheckStructCycles (this);

			base.Emit ();
		}

		public override bool IsUnmanagedType ()
		{
			if (fields == null)
				return true;

			if (has_unmanaged_check_done)
				return is_unmanaged;

			if (requires_delayed_unmanagedtype_check)
				return true;

			requires_delayed_unmanagedtype_check = true;

			foreach (FieldBase f in fields) {
				if (f.IsStatic)
					continue;

				// It can happen when recursive unmanaged types are defined
				// struct S { S* s; }
				TypeSpec mt = f.MemberType;
				if (mt == null) {
					return true;
				}

				while (mt.IsPointer)
					mt = TypeManager.GetElementType (mt);

				if (mt.IsGenericOrParentIsGeneric || mt.IsGenericParameter) {
					has_unmanaged_check_done = true;
					return false;
				}

				if (TypeManager.IsUnmanagedType (mt))
					continue;

				has_unmanaged_check_done = true;
				return false;
			}

			has_unmanaged_check_done = true;
			is_unmanaged = true;
			return true;
		}

		protected override TypeExpr[] ResolveBaseTypes (out TypeExpr base_class)
		{
			TypeExpr[] ifaces = base.ResolveBaseTypes (out base_class);
			base_type = TypeManager.value_type;
			return ifaces;
		}

		protected override TypeAttributes TypeAttr {
			get {
				const TypeAttributes DefaultTypeAttributes =
					TypeAttributes.SequentialLayout |
					TypeAttributes.Sealed;

				return base.TypeAttr | DefaultTypeAttributes;
			}
		}

		public override void RegisterFieldForInitialization (MemberCore field, FieldInitializer expression)
		{
			if ((field.ModFlags & Modifiers.STATIC) == 0) {
				Report.Error (573, field.Location, "`{0}': Structs cannot have instance field initializers",
					field.GetSignatureForError ());
				return;
			}
			base.RegisterFieldForInitialization (field, expression);
		}

	}

	/// <summary>
	///   Interfaces
	/// </summary>
	public sealed class Interface : TypeContainer {

		/// <summary>
		///   Modifiers allowed in a class declaration
		/// </summary>
		public const Modifiers AllowedModifiers =
			Modifiers.NEW       |
			Modifiers.PUBLIC    |
			Modifiers.PROTECTED |
			Modifiers.INTERNAL  |
		 	Modifiers.UNSAFE    |
			Modifiers.PRIVATE;

		public Interface (NamespaceEntry ns, DeclSpace parent, MemberName name, Modifiers mod,
				  Attributes attrs)
			: base (ns, parent, name, attrs, MemberKind.Interface)
		{
			var accmods = parent.Parent == null ? Modifiers.INTERNAL : Modifiers.PRIVATE;

			this.ModFlags = ModifiersExtensions.Check (AllowedModifiers, mod, accmods, name.Location, Report);
			spec = new TypeSpec (Kind, null, this, null, ModFlags);
		}

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			if (a.Type == pa.ComImport && !attributes.Contains (pa.Guid)) {
				a.Error_MissingGuidAttribute ();
				return;
			}

			base.ApplyAttributeBuilder (a, ctor, cdata, pa);
		}


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

		protected override TypeAttributes TypeAttr {
			get {
				const TypeAttributes DefaultTypeAttributes =
					TypeAttributes.AutoLayout |
					TypeAttributes.Abstract |
					TypeAttributes.Interface;

				return base.TypeAttr | DefaultTypeAttributes;
			}
		}

		protected override bool VerifyClsCompliance ()
		{
			if (!base.VerifyClsCompliance ())
				return false;

			if (iface_exprs != null) {
				foreach (var iface in iface_exprs) {
					if (iface.Type.IsCLSCompliant ())
						continue;

					Report.SymbolRelatedToPreviousError (iface.Type);
					Report.Warning (3027, 1, Location, "`{0}' is not CLS-compliant because base interface `{1}' is not CLS-compliant",
						GetSignatureForError (), TypeManager.CSharpName (iface.Type));
				}
			}

			return true;
		}
	}

	public abstract class InterfaceMemberBase : MemberBase
	{
		//
		// Common modifiers allowed in a class declaration
		//
		protected const Modifiers AllowedModifiersClass =
			Modifiers.NEW |
			Modifiers.PUBLIC |
			Modifiers.PROTECTED |
			Modifiers.INTERNAL |
			Modifiers.PRIVATE |
			Modifiers.STATIC |
			Modifiers.VIRTUAL |
			Modifiers.SEALED |
			Modifiers.OVERRIDE |
			Modifiers.ABSTRACT |
			Modifiers.UNSAFE |
			Modifiers.EXTERN;

		//
		// Common modifiers allowed in a struct declaration
		//
		protected const Modifiers AllowedModifiersStruct =
			Modifiers.NEW |
			Modifiers.PUBLIC |
			Modifiers.PROTECTED |
			Modifiers.INTERNAL |
			Modifiers.PRIVATE |
			Modifiers.STATIC |
			Modifiers.OVERRIDE |
			Modifiers.UNSAFE |
			Modifiers.EXTERN;

		//
		// Common modifiers allowed in a interface declaration
		//
		protected const Modifiers AllowedModifiersInterface =
			Modifiers.NEW |
			Modifiers.UNSAFE;

		//
		// Whether this is an interface member.
		//
		public bool IsInterface;

		//
		// If true, this is an explicit interface implementation
		//
		public bool IsExplicitImpl;

		protected bool is_external_implementation;

		//
		// The interface type we are explicitly implementing
		//
		public TypeSpec InterfaceType;

		//
		// The method we're overriding if this is an override method.
		//
		protected MethodSpec base_method;

		readonly Modifiers explicit_mod_flags;
		public MethodAttributes flags;

		public InterfaceMemberBase (DeclSpace parent, GenericMethod generic,
				   FullNamedExpression type, Modifiers mod, Modifiers allowed_mod,
				   MemberName name, Attributes attrs)
			: base (parent, generic, type, mod, allowed_mod, Modifiers.PRIVATE,
				name, attrs)
		{
			IsInterface = parent.PartialContainer.Kind == MemberKind.Interface;
			IsExplicitImpl = (MemberName.Left != null);
			explicit_mod_flags = mod;
		}
		
		protected override bool CheckBase ()
		{
			if (!base.CheckBase ())
				return false;

			if ((caching_flags & Flags.MethodOverloadsExist) != 0)
				CheckForDuplications ();
			
			if (IsExplicitImpl)
				return true;

			// For System.Object only
			if (Parent.BaseType == null)
				return true;

			MemberSpec candidate;
			var base_member = FindBaseMember (out candidate);

			if ((ModFlags & Modifiers.OVERRIDE) != 0) {
				if (base_member == null) {
					if (candidate == null) {
						if (this is Method && ((Method)this).ParameterInfo.IsEmpty && MemberName.Name == Destructor.MetadataName && MemberName.Arity == 0) {
							Report.Error (249, Location, "Do not override `{0}'. Use destructor syntax instead",
								"object.Finalize()");
						} else {
							Report.Error (115, Location, "`{0}' is marked as an override but no suitable {1} found to override",
								GetSignatureForError (), SimpleName.GetMemberType (this));
						}
					} else {
						Report.SymbolRelatedToPreviousError (candidate);
						if (this is Event)
							Report.Error (72, Location, "`{0}': cannot override because `{1}' is not an event",
								GetSignatureForError (), TypeManager.GetFullNameSignature (candidate));
						else if (this is PropertyBase)
							Report.Error (544, Location, "`{0}': cannot override because `{1}' is not a property",
								GetSignatureForError (), TypeManager.GetFullNameSignature (candidate));
						else
							Report.Error (505, Location, "`{0}': cannot override because `{1}' is not a method",
								GetSignatureForError (), TypeManager.GetFullNameSignature (candidate));
					}

					return false;
				}

				if (!CheckOverrideAgainstBase (base_member))
					return false;

				ObsoleteAttribute oa = base_member.GetAttributeObsolete ();
				if (oa != null) {
					if (OptAttributes == null || !OptAttributes.Contains (Module.PredefinedAttributes.Obsolete)) {
						Report.SymbolRelatedToPreviousError (base_member);
						Report.Warning (672, 1, Location, "Member `{0}' overrides obsolete member `{1}'. Add the Obsolete attribute to `{0}'",
							GetSignatureForError (), TypeManager.GetFullNameSignature (base_member));
					}
				} else {
					if (OptAttributes != null && OptAttributes.Contains (Module.PredefinedAttributes.Obsolete)) {
						Report.SymbolRelatedToPreviousError (base_member);
						Report.Warning (809, 1, Location, "Obsolete member `{0}' overrides non-obsolete member `{1}'",
							GetSignatureForError (), TypeManager.GetFullNameSignature (base_member));
					}
				}

				base_method = base_member as MethodSpec;
				return true;
			}

			if (base_member == null && candidate != null && (!(candidate is IParametersMember) || !(this is IParametersMember)))
				base_member = candidate;

			if (base_member == null) {
				if ((ModFlags & Modifiers.NEW) != 0) {
					if (base_member == null) {
						Report.Warning (109, 4, Location, "The member `{0}' does not hide an inherited member. The new keyword is not required",
							GetSignatureForError ());
					}
				}
			} else {
				if ((ModFlags & Modifiers.NEW) == 0) {
					ModFlags |= Modifiers.NEW;
					if (!IsCompilerGenerated) {
						Report.SymbolRelatedToPreviousError (base_member);
						if (!IsInterface && (base_member.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) != 0) {
							Report.Warning (114, 2, Location, "`{0}' hides inherited member `{1}'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword",
								GetSignatureForError (), base_member.GetSignatureForError ());
						} else {
							Report.Warning (108, 2, Location, "`{0}' hides inherited member `{1}'. Use the new keyword if hiding was intended",
								GetSignatureForError (), base_member.GetSignatureForError ());
						}
					}
				}

				if (!IsInterface && base_member.IsAbstract && candidate == null) {
					Report.SymbolRelatedToPreviousError (base_member);
					Report.Error (533, Location, "`{0}' hides inherited abstract member `{1}'",
						GetSignatureForError (), base_member.GetSignatureForError ());
				}
			}

			return true;
		}

		protected virtual bool CheckForDuplications ()
		{
			return Parent.MemberCache.CheckExistingMembersOverloads (this, ParametersCompiled.EmptyReadOnlyParameters);
		}

		//
		// Performs various checks on the MethodInfo `mb' regarding the modifier flags
		// that have been defined.
		//
		protected virtual bool CheckOverrideAgainstBase (MemberSpec base_member)
		{
			bool ok = true;

			if ((base_member.Modifiers & (Modifiers.ABSTRACT | Modifiers.VIRTUAL | Modifiers.OVERRIDE)) == 0) {
				Report.SymbolRelatedToPreviousError (base_member);
				Report.Error (506, Location,
					"`{0}': cannot override inherited member `{1}' because it is not marked virtual, abstract or override",
					 GetSignatureForError (), TypeManager.CSharpSignature (base_member));
				ok = false;
			}

			// Now we check that the overriden method is not final	
			if ((base_member.Modifiers & Modifiers.SEALED) != 0) {
				Report.SymbolRelatedToPreviousError (base_member);
				Report.Error (239, Location, "`{0}': cannot override inherited member `{1}' because it is sealed",
							  GetSignatureForError (), TypeManager.CSharpSignature (base_member));
				ok = false;
			}

			var base_member_type = ((IInterfaceMemberSpec) base_member).MemberType;
			if (!TypeSpecComparer.Override.IsEqual (MemberType, base_member_type)) {
				Report.SymbolRelatedToPreviousError (base_member);
				if (this is PropertyBasedMember) {
					Report.Error (1715, Location, "`{0}': type must be `{1}' to match overridden member `{2}'",
						GetSignatureForError (), TypeManager.CSharpName (base_member_type), TypeManager.CSharpSignature (base_member));
				} else {
					Report.Error (508, Location, "`{0}': return type must be `{1}' to match overridden member `{2}'",
						GetSignatureForError (), TypeManager.CSharpName (base_member_type), TypeManager.CSharpSignature (base_member));
				}
				ok = false;
			}

			return ok;
		}

		protected static bool CheckAccessModifiers (MemberCore this_member, MemberSpec base_member)
		{
			var thisp = this_member.ModFlags & Modifiers.AccessibilityMask;
			var base_classp = base_member.Modifiers & Modifiers.AccessibilityMask;

			if ((base_classp & (Modifiers.PROTECTED | Modifiers.INTERNAL)) == (Modifiers.PROTECTED | Modifiers.INTERNAL)) {
				//
				// It must be at least "protected"
				//
				if ((thisp & Modifiers.PROTECTED) == 0) {
					return false;
				}

				//
				// when overriding protected internal, the method can be declared
				// protected internal only within the same assembly or assembly
				// which has InternalsVisibleTo
				//
				if ((thisp & Modifiers.INTERNAL) != 0) {
					return base_member.DeclaringType.MemberDefinition.IsInternalAsPublic (this_member.Module.DeclaringAssembly);
				}

				//
				// protected overriding protected internal inside same assembly
				// requires internal modifier as well
				//
				if (base_member.DeclaringType.MemberDefinition.IsInternalAsPublic (this_member.Module.DeclaringAssembly)) {
					return false;
				}

				return true;
			}

			return thisp == base_classp;
		}

		public override bool Define ()
		{
			if (IsInterface) {
				ModFlags = Modifiers.PUBLIC | Modifiers.ABSTRACT |
					Modifiers.VIRTUAL | (ModFlags & (Modifiers.UNSAFE | Modifiers.NEW));

				flags = MethodAttributes.Public |
					MethodAttributes.Abstract |
					MethodAttributes.HideBySig |
					MethodAttributes.NewSlot |
					MethodAttributes.Virtual;
			} else {
				Parent.PartialContainer.MethodModifiersValid (this);

				flags = ModifiersExtensions.MethodAttr (ModFlags);
			}

			if (IsExplicitImpl) {
				TypeExpr iface_texpr = MemberName.Left.GetTypeExpression ().ResolveAsTypeTerminal (Parent, false);
				if (iface_texpr == null)
					return false;

				if ((ModFlags & Modifiers.PARTIAL) != 0) {
					Report.Error (754, Location, "A partial method `{0}' cannot explicitly implement an interface",
						GetSignatureForError ());
				}

				InterfaceType = iface_texpr.Type;

				if (!InterfaceType.IsInterface) {
					Report.SymbolRelatedToPreviousError (InterfaceType);
					Report.Error (538, Location, "The type `{0}' in explicit interface declaration is not an interface",
						TypeManager.CSharpName (InterfaceType));
				} else {
					Parent.PartialContainer.VerifyImplements (this);
				}

				ModifiersExtensions.Check (Modifiers.AllowedExplicitImplFlags, explicit_mod_flags, 0, Location, Report);
			}

			return base.Define ();
		}

		protected bool DefineParameters (ParametersCompiled parameters)
		{
			if (!parameters.Resolve (this))
				return false;

			bool error = false;
			for (int i = 0; i < parameters.Count; ++i) {
				Parameter p = parameters [i];

				if (p.HasDefaultValue && (IsExplicitImpl || this is Operator || (this is Indexer && parameters.Count == 1)))
					p.Warning_UselessOptionalParameter (Report);

				if (p.CheckAccessibility (this))
					continue;

				TypeSpec t = parameters.Types [i];
				Report.SymbolRelatedToPreviousError (t);
				if (this is Indexer)
					Report.Error (55, Location,
						      "Inconsistent accessibility: parameter type `{0}' is less accessible than indexer `{1}'",
						      TypeManager.CSharpName (t), GetSignatureForError ());
				else if (this is Operator)
					Report.Error (57, Location,
						      "Inconsistent accessibility: parameter type `{0}' is less accessible than operator `{1}'",
						      TypeManager.CSharpName (t), GetSignatureForError ());
				else
					Report.Error (51, Location,
						"Inconsistent accessibility: parameter type `{0}' is less accessible than method `{1}'",
						TypeManager.CSharpName (t), GetSignatureForError ());
				error = true;
			}
			return !error;
		}

		public override void Emit()
		{
			// for extern static method must be specified either DllImport attribute or MethodImplAttribute.
			// We are more strict than csc and report this as an error because SRE does not allow emit that
			if ((ModFlags & Modifiers.EXTERN) != 0 && !is_external_implementation) {
				if (this is Constructor) {
					Report.Error (824, Location,
						"Constructor `{0}' is marked `external' but has no external implementation specified", GetSignatureForError ());
				} else {
					Report.Error (626, Location,
						"`{0}' is marked as an external but has no DllImport attribute. Consider adding a DllImport attribute to specify the external implementation",
						GetSignatureForError ());
				}
			}

			base.Emit ();
		}

		public override bool EnableOverloadChecks (MemberCore overload)
		{
			//
			// Two members can differ in their explicit interface
			// type parameter only
			//
			InterfaceMemberBase imb = overload as InterfaceMemberBase;
			if (imb != null && imb.IsExplicitImpl) {
				if (IsExplicitImpl) {
					caching_flags |= Flags.MethodOverloadsExist;
				}
				return true;
			}

			return IsExplicitImpl;
		}

		protected void Error_CannotChangeAccessModifiers (MemberCore member, MemberSpec base_member)
		{
			var base_modifiers = base_member.Modifiers;

			// Remove internal modifier from types which are not internally accessible
			if ((base_modifiers & Modifiers.AccessibilityMask) == (Modifiers.PROTECTED | Modifiers.INTERNAL) &&
				!base_member.DeclaringType.MemberDefinition.IsInternalAsPublic (member.Module.DeclaringAssembly))
				base_modifiers = Modifiers.PROTECTED;

			Report.SymbolRelatedToPreviousError (base_member);
			Report.Error (507, member.Location,
				"`{0}': cannot change access modifiers when overriding `{1}' inherited member `{2}'",
				member.GetSignatureForError (),
				ModifiersExtensions.AccessibilityName (base_modifiers),
				base_member.GetSignatureForError ());
		}

		protected void Error_StaticReturnType ()
		{
			Report.Error (722, Location,
				"`{0}': static types cannot be used as return types",
				MemberType.GetSignatureForError ());
		}

		/// <summary>
		/// Gets base method and its return type
		/// </summary>
		protected virtual MemberSpec FindBaseMember (out MemberSpec bestCandidate)
		{
			return MemberCache.FindBaseMember (this, out bestCandidate);
		}

		//
		// The "short" name of this property / indexer / event.  This is the
		// name without the explicit interface.
		//
		public string ShortName {
			get { return MemberName.Name; }
			set { SetMemberName (new MemberName (MemberName.Left, value, Location)); }
		}
		
		//
		// Returns full metadata method name
		//
		public string GetFullName (MemberName name)
		{
			return GetFullName (name.Name);
		}

		public string GetFullName (string name)
		{
			if (!IsExplicitImpl)
				return name;

			//
			// When dealing with explicit members a full interface type
			// name is added to member name to avoid possible name conflicts
			//
			// We use CSharpName which gets us full name with benefit of
			// replacing predefined names which saves some space and name
			// is still unique
			//
			return TypeManager.CSharpName (InterfaceType) + "." + name;
		}

		protected override bool VerifyClsCompliance ()
		{
			if (!base.VerifyClsCompliance ()) {
				return false;
			}

			if (GenericMethod != null)
				GenericMethod.VerifyClsCompliance ();

			return true;
		}

		public override bool IsUsed 
		{
			get { return IsExplicitImpl || base.IsUsed; }
		}

	}

	public abstract class MemberBase : MemberCore
	{
		protected FullNamedExpression type_expr;
		protected TypeSpec member_type;

		public readonly DeclSpace ds;
		public readonly GenericMethod GenericMethod;

		protected MemberBase (DeclSpace parent, GenericMethod generic,
				      FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, Modifiers def_mod,
				      MemberName name, Attributes attrs)
			: base (parent, name, attrs)
		{
			this.ds = generic != null ? generic : (DeclSpace) parent;
			this.type_expr = type;
			ModFlags = ModifiersExtensions.Check (allowed_mod, mod, def_mod, Location, Report);
			GenericMethod = generic;
			if (GenericMethod != null)
				GenericMethod.ModFlags = ModFlags;
		}

		#region Properties

		public TypeSpec MemberType {
			get {
				return member_type;
			}
		}

		public FullNamedExpression TypeExpression {
			get {
				return type_expr;
			}
		}

		#endregion

		//
		// Main member define entry
		//
		public override bool Define ()
		{
			DoMemberTypeIndependentChecks ();

			//
			// Returns false only when type resolution failed
			//
			if (!ResolveMemberType ())
				return false;

			DoMemberTypeDependentChecks ();
			return true;
		}

		//
		// Any type_name independent checks
		//
		protected virtual void DoMemberTypeIndependentChecks ()
		{
			if ((Parent.ModFlags & Modifiers.SEALED) != 0 &&
				(ModFlags & (Modifiers.VIRTUAL | Modifiers.ABSTRACT)) != 0) {
				Report.Error (549, Location, "New virtual member `{0}' is declared in a sealed class `{1}'",
					GetSignatureForError (), Parent.GetSignatureForError ());
			}
		}

		//
		// Any type_name dependent checks
		//
		protected virtual void DoMemberTypeDependentChecks ()
		{
			// verify accessibility
			if (!IsAccessibleAs (MemberType)) {
				Report.SymbolRelatedToPreviousError (MemberType);
				if (this is Property)
					Report.Error (53, Location,
						      "Inconsistent accessibility: property type `" +
						      TypeManager.CSharpName (MemberType) + "' is less " +
						      "accessible than property `" + GetSignatureForError () + "'");
				else if (this is Indexer)
					Report.Error (54, Location,
						      "Inconsistent accessibility: indexer return type `" +
						      TypeManager.CSharpName (MemberType) + "' is less " +
						      "accessible than indexer `" + GetSignatureForError () + "'");
				else if (this is MethodCore) {
					if (this is Operator)
						Report.Error (56, Location,
							      "Inconsistent accessibility: return type `" +
							      TypeManager.CSharpName (MemberType) + "' is less " +
							      "accessible than operator `" + GetSignatureForError () + "'");
					else
						Report.Error (50, Location,
							      "Inconsistent accessibility: return type `" +
							      TypeManager.CSharpName (MemberType) + "' is less " +
							      "accessible than method `" + GetSignatureForError () + "'");
				} else {
					Report.Error (52, Location,
						      "Inconsistent accessibility: field type `" +
						      TypeManager.CSharpName (MemberType) + "' is less " +
						      "accessible than field `" + GetSignatureForError () + "'");
				}
			}

			Variance variance = this is Event ? Variance.Contravariant : Variance.Covariant;
			TypeManager.CheckTypeVariance (MemberType, variance, this);
		}

		protected bool IsTypePermitted ()
		{
			if (TypeManager.IsSpecialType (MemberType)) {
				Report.Error (610, Location, "Field or property cannot be of type `{0}'", TypeManager.CSharpName (MemberType));
				return false;
			}
			return true;
		}

		protected virtual bool CheckBase ()
		{
			CheckProtectedModifier ();

			return true;
		}

		protected virtual bool ResolveMemberType ()
		{
			if (member_type != null)
				throw new InternalErrorException ("Multi-resolve");

			TypeExpr te = type_expr.ResolveAsTypeTerminal (this, false);
			if (te == null)
				return false;
			
			//
			// Replace original type name, error reporting can use fully resolved name
			//
			type_expr = te;

			member_type = te.Type;
			return true;
		}
	}
}

