//
// property.cs: Property based 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
// Copyright 2011 Xamarin Inc
//

using System;
using System.Collections.Generic;
using System.Text;
using Mono.CompilerServices.SymbolWriter;

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

#if STATIC
using IKVM.Reflection;
using IKVM.Reflection.Emit;
#else
using System.Reflection;
using System.Reflection.Emit;
#endif

namespace Mono.CSharp
{
	// It is used as a base class for all property based members
	// This includes properties, indexers, and events
	public abstract class PropertyBasedMember : InterfaceMemberBase
	{
		protected PropertyBasedMember (TypeDefinition parent, FullNamedExpression type, Modifiers mod, Modifiers allowed_mod, MemberName name, Attributes attrs)
			: base (parent, type, mod, allowed_mod, name, attrs)
		{
		}

		protected void CheckReservedNameConflict (string prefix, MethodSpec accessor)
		{
			string name;
			AParametersCollection parameters;
			if (accessor != null) {
				name = accessor.Name;
				parameters = accessor.Parameters;
			} else {
				name = prefix + ShortName;
				if (IsExplicitImpl)
					name = MemberName.Left + "." + name;

				if (this is Indexer) {
					parameters = ((Indexer) this).ParameterInfo;
					if (prefix[0] == 's') {
						var data = new IParameterData[parameters.Count + 1];
						Array.Copy (parameters.FixedParameters, data, data.Length - 1);
						data[data.Length - 1] = new ParameterData ("value", Parameter.Modifier.NONE);
						var types = new TypeSpec[data.Length];
						Array.Copy (parameters.Types, types, data.Length - 1);
						types[data.Length - 1] = member_type;

						parameters = new ParametersImported (data, types, false);
					}
				} else {
					if (prefix[0] == 's')
						parameters = ParametersCompiled.CreateFullyResolved (new[] { member_type });
					else
						parameters = ParametersCompiled.EmptyReadOnlyParameters;
				}
			}

			var conflict = MemberCache.FindMember (Parent.Definition,
				new MemberFilter (name, 0, MemberKind.Method, parameters, null),
				BindingRestriction.DeclaredOnly | BindingRestriction.NoAccessors);

			if (conflict != null) {
				Report.SymbolRelatedToPreviousError (conflict);
				Report.Error (82, Location, "A member `{0}' is already reserved", conflict.GetSignatureForError ());
			}
		}

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

			if (!MemberType.IsCLSCompliant ()) {
				Report.Warning (3003, 1, Location, "Type of `{0}' is not CLS-compliant",
					GetSignatureForError ());
			}
			return true;
		}

	}

	public class PropertySpec : MemberSpec, IInterfaceMemberSpec
	{
		PropertyInfo info;
		TypeSpec memberType;
		MethodSpec set, get;

		public PropertySpec (MemberKind kind, TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, PropertyInfo info, Modifiers modifiers)
			: base (kind, declaringType, definition, modifiers)
		{
			this.info = info;
			this.memberType = memberType;
		}

		#region Properties

		public MethodSpec Get {
			get {
				return get;
			}
			set {
				get = value;
				get.IsAccessor = true;
			}
		}

		public MethodSpec Set { 
			get {
				return set;
			}
			set {
				set = value;
				set.IsAccessor = true;
			}
		}

		public bool HasDifferentAccessibility {
			get {
				return HasGet && HasSet && 
					(Get.Modifiers & Modifiers.AccessibilityMask) != (Set.Modifiers & Modifiers.AccessibilityMask);
			}
		}

		public bool HasGet {
			get {
				return Get != null;
			}
		}

		public bool HasSet {
			get {
				return Set != null;
			}
		}

		public PropertyInfo MetaInfo {
			get {
				if ((state & StateFlags.PendingMetaInflate) != 0)
					throw new NotSupportedException ();

				return info;
			}
		}

		public TypeSpec MemberType {
			get {
				return memberType;
			}
		}

		#endregion

		public override MemberSpec InflateMember (TypeParameterInflator inflator)
		{
			var ps = (PropertySpec) base.InflateMember (inflator);
			ps.memberType = inflator.Inflate (memberType);
			return ps;
		}

		public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
		{
			return memberType.ResolveMissingDependencies (this);
		}
	}

	//
	// Properties and Indexers both generate PropertyBuilders, we use this to share 
	// their common bits.
	//
	abstract public class PropertyBase : PropertyBasedMember {

		public class GetMethod : PropertyMethod
		{
			static readonly string[] attribute_targets = new string [] { "method", "return" };

			internal const string Prefix = "get_";

			public GetMethod (PropertyBase method, Modifiers modifiers, Attributes attrs, Location loc)
				: base (method, Prefix, modifiers, attrs, loc)
			{
			}

			public override void Define (TypeContainer parent)
			{
				base.Define (parent);

				Spec = new MethodSpec (MemberKind.Method, parent.PartialContainer.Definition, this, ReturnType, ParameterInfo, ModFlags);

				method_data = new MethodData (method, ModFlags, flags, this);

				method_data.Define (parent.PartialContainer, method.GetFullName (MemberName));
			}

			public override TypeSpec ReturnType {
				get {
					return method.MemberType;
				}
			}

			public override ParametersCompiled ParameterInfo {
				get {
					return ParametersCompiled.EmptyReadOnlyParameters;
				}
			}

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

		public class SetMethod : PropertyMethod {

			static readonly string[] attribute_targets = new string[] { "method", "param", "return" };

			internal const string Prefix = "set_";

			protected ParametersCompiled parameters;

			public SetMethod (PropertyBase method, Modifiers modifiers, ParametersCompiled parameters, Attributes attrs, Location loc)
				: base (method, Prefix, modifiers, attrs, loc)
			{
				this.parameters = parameters;
			}

			protected override void ApplyToExtraTarget (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
			{
				if (a.Target == AttributeTargets.Parameter) {
					parameters[parameters.Count - 1].ApplyAttributeBuilder (a, ctor, cdata, pa);
					return;
				}

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

			public override ParametersCompiled ParameterInfo {
			    get {
			        return parameters;
			    }
			}

			public override void Define (TypeContainer parent)
			{
				parameters.Resolve (this);
				
				base.Define (parent);

				Spec = new MethodSpec (MemberKind.Method, parent.PartialContainer.Definition, this, ReturnType, ParameterInfo, ModFlags);

				method_data = new MethodData (method, ModFlags, flags, this);

				method_data.Define (parent.PartialContainer, method.GetFullName (MemberName));
			}

			public override TypeSpec ReturnType {
				get {
					return Parent.Compiler.BuiltinTypes.Void;
				}
			}

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

		static readonly string[] attribute_targets = new string[] { "property" };

		public abstract class PropertyMethod : AbstractPropertyEventMethod
		{
			const Modifiers AllowedModifiers =
				Modifiers.PUBLIC |
				Modifiers.PROTECTED |
				Modifiers.INTERNAL |
				Modifiers.PRIVATE;
		
			protected readonly PropertyBase method;
			protected MethodAttributes flags;

			public PropertyMethod (PropertyBase method, string prefix, Modifiers modifiers, Attributes attrs, Location loc)
				: base (method, prefix, attrs, loc)
			{
				this.method = method;
				this.ModFlags = ModifiersExtensions.Check (AllowedModifiers, modifiers, 0, loc, Report);
				this.ModFlags |= (method.ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE));
			}

			public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
			{
				if (a.Type == pa.MethodImpl) {
					method.is_external_implementation = a.IsInternalCall ();
				}

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

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

			public override bool IsClsComplianceRequired ()
			{
				return method.IsClsComplianceRequired ();
			}

			public virtual void Define (TypeContainer parent)
			{
				var container = parent.PartialContainer;

				//
				// Check for custom access modifier
				//
				if ((ModFlags & Modifiers.AccessibilityMask) == 0) {
					ModFlags |= method.ModFlags;
					flags = method.flags;
				} else {
					CheckModifiers (ModFlags);
					ModFlags |= (method.ModFlags & (~Modifiers.AccessibilityMask));
					ModFlags |= Modifiers.PROPERTY_CUSTOM;

					if (container.Kind == MemberKind.Interface) {
						Report.Error (275, Location, "`{0}': accessibility modifiers may not be used on accessors in an interface",
							GetSignatureForError ());
					} else if ((ModFlags & Modifiers.PRIVATE) != 0) {
						if ((method.ModFlags & Modifiers.ABSTRACT) != 0) {
							Report.Error (442, Location, "`{0}': abstract properties cannot have private accessors", GetSignatureForError ());
						}

						ModFlags &= ~Modifiers.VIRTUAL;
					}

					flags = ModifiersExtensions.MethodAttr (ModFlags) | MethodAttributes.SpecialName;
				}

				CheckAbstractAndExtern (block != null);
				CheckProtectedModifier ();

				if (block != null) {
					if (block.IsIterator)
						Iterator.CreateIterator (this, Parent.PartialContainer, ModFlags);

					if (Compiler.Settings.WriteMetadataOnly)
						block = null;
				}
			}

			public bool HasCustomAccessModifier {
				get {
					return (ModFlags & Modifiers.PROPERTY_CUSTOM) != 0;
				}
			}

			public PropertyBase Property {
				get {
					return method;
				}
			}

			public override ObsoleteAttribute GetAttributeObsolete ()
			{
				return method.GetAttributeObsolete ();
			}

			public override string GetSignatureForError()
			{
				return method.GetSignatureForError () + "." + prefix.Substring (0, 3);
			}

			void CheckModifiers (Modifiers modflags)
			{
				if (!ModifiersExtensions.IsRestrictedModifier (modflags & Modifiers.AccessibilityMask, method.ModFlags & Modifiers.AccessibilityMask)) {
					Report.Error (273, Location,
						"The accessibility modifier of the `{0}' accessor must be more restrictive than the modifier of the property or indexer `{1}'",
						GetSignatureForError (), method.GetSignatureForError ());
				}
			}
		}

		PropertyMethod get, set, first;
		PropertyBuilder PropertyBuilder;

		protected PropertyBase (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, Modifiers allowed_mod, MemberName name, Attributes attrs)
			: base (parent, type, mod_flags, allowed_mod, name, attrs)
		{
		}

		#region Properties

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

		public PropertyMethod AccessorFirst {
			get {
				return first;
			}
		}

		public PropertyMethod AccessorSecond {
			get {
				return first == get ? set : get;
			}
		}

		public override Variance ExpectedMemberTypeVariance {
			get {
				return (get != null && set != null) ?
					Variance.None : set == null ?
					Variance.Covariant :
					Variance.Contravariant;
			}
		}

		public PropertyMethod Get {
			get {
				return get;
			}
			set {
				get = value;
				if (first == null)
					first = value;

				Parent.AddNameToContainer (get, get.MemberName.Basename);
			}
		}

		public PropertyMethod Set {
			get {
				return set;
			}
			set {
				set = value;
				if (first == null)
					first = value;

				Parent.AddNameToContainer (set, set.MemberName.Basename);
			}
		}

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

		#endregion

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			if (a.HasSecurityAttribute) {
				a.Error_InvalidSecurityParent ();
				return;
			}

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

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

		void CheckMissingAccessor (MemberKind kind, ParametersCompiled parameters, bool get)
		{
			if (IsExplicitImpl) {
				MemberFilter filter;
				if (kind == MemberKind.Indexer)
					filter = new MemberFilter (MemberCache.IndexerNameAlias, 0, kind, parameters, null);
				else
					filter = new MemberFilter (MemberName.Name, 0, kind, null, null);

				var implementing = MemberCache.FindMember (InterfaceType, filter, BindingRestriction.DeclaredOnly) as PropertySpec;

				if (implementing == null)
					return;

				var accessor = get ? implementing.Get : implementing.Set;
				if (accessor != null) {
					Report.SymbolRelatedToPreviousError (accessor);
					Report.Error (551, Location, "Explicit interface implementation `{0}' is missing accessor `{1}'",
						GetSignatureForError (), accessor.GetSignatureForError ());
				}
			}
		}

		protected override bool CheckOverrideAgainstBase (MemberSpec base_member)
		{
			var ok = base.CheckOverrideAgainstBase (base_member);

			//
			// Check base property accessors conflict
			//
			var base_prop = (PropertySpec) base_member;
			if (Get == null) {
				if ((ModFlags & Modifiers.SEALED) != 0 && base_prop.HasGet && !base_prop.Get.IsAccessible (this)) {
					// TODO: Should be different error code but csc uses for some reason same
					Report.SymbolRelatedToPreviousError (base_prop);
					Report.Error (545, Location,
						"`{0}': cannot override because `{1}' does not have accessible get accessor",
						GetSignatureForError (), base_prop.GetSignatureForError ());
					ok = false;
				}
			} else {
				if (!base_prop.HasGet) {
					if (ok) {
						Report.SymbolRelatedToPreviousError (base_prop);
						Report.Error (545, Get.Location,
							"`{0}': cannot override because `{1}' does not have an overridable get accessor",
							Get.GetSignatureForError (), base_prop.GetSignatureForError ());
						ok = false;
					}
				} else if (Get.HasCustomAccessModifier || base_prop.HasDifferentAccessibility) {
					if (!base_prop.Get.IsAccessible (this)) {
						// Same as csc but it should be different error code
						Report.Error (115, Get.Location, "`{0}' is marked as an override but no accessible `get' accessor found to override",
							GetSignatureForError ());
						ok = false;
					} else if (!CheckAccessModifiers (Get, base_prop.Get)) {
						Error_CannotChangeAccessModifiers (Get, base_prop.Get);
						ok = false;
					}
				}
			}

			if (Set == null) {
				if (base_prop.HasSet) {
					if ((ModFlags & Modifiers.SEALED) != 0 && !base_prop.Set.IsAccessible (this)) {
						// TODO: Should be different error code but csc uses for some reason same
						Report.SymbolRelatedToPreviousError (base_prop);
						Report.Error (546, Location,
							"`{0}': cannot override because `{1}' does not have accessible set accessor",
							GetSignatureForError (), base_prop.GetSignatureForError ());
						ok = false;
					}

					if ((ModFlags & Modifiers.AutoProperty) != 0) {
						Report.Error (8080, Location, "`{0}': Auto-implemented properties must override all accessors of the overridden property",
							GetSignatureForError ());
						ok = false;
					}
				}
			} else {
				if (!base_prop.HasSet) {
					if (ok) {
						Report.SymbolRelatedToPreviousError (base_prop);
						Report.Error (546, Set.Location,
							"`{0}': cannot override because `{1}' does not have an overridable set accessor",
							Set.GetSignatureForError (), base_prop.GetSignatureForError ());
						ok = false;
					}
				} else if (Set.HasCustomAccessModifier || base_prop.HasDifferentAccessibility) {
					if (!base_prop.Set.IsAccessible (this)) {
						// Same as csc but it should be different error code
						Report.Error (115, Set.Location, "`{0}' is marked as an override but no accessible `set' accessor found to override",
							GetSignatureForError ());
						ok = false;
					} else if (!CheckAccessModifiers (Set, base_prop.Set)) {
						Error_CannotChangeAccessModifiers (Set, base_prop.Set);
						ok = false;
					}
				}
			}

			if ((Set == null || !Set.HasCustomAccessModifier) && (Get == null || !Get.HasCustomAccessModifier)) {
				if (!CheckAccessModifiers (this, base_prop)) {
					Error_CannotChangeAccessModifiers (this, base_prop);
					ok = false;
				}
			}

			return ok;
		}

		protected override void DoMemberTypeDependentChecks ()
		{
			base.DoMemberTypeDependentChecks ();

			IsTypePermitted ();

			if (MemberType.IsStatic)
				Error_StaticReturnType ();
		}

		protected override void DoMemberTypeIndependentChecks ()
		{
			base.DoMemberTypeIndependentChecks ();

			//
			// Accessors modifiers check
			//
			if (AccessorSecond != null) {
				if ((Get.ModFlags & Modifiers.AccessibilityMask) != 0 && (Set.ModFlags & Modifiers.AccessibilityMask) != 0) {
					Report.Error (274, Location, "`{0}': Cannot specify accessibility modifiers for both accessors of the property or indexer",
						GetSignatureForError ());
				}
			} else if ((ModFlags & Modifiers.OVERRIDE) == 0 && 
				((Get == null && (Set.ModFlags & Modifiers.AccessibilityMask) != 0) || (Set == null && (Get.ModFlags & Modifiers.AccessibilityMask) != 0))) {
				Report.Error (276, Location, 
					      "`{0}': accessibility modifiers on accessors may only be used if the property or indexer has both a get and a set accessor",
					      GetSignatureForError ());
			}
		}

		protected bool DefineAccessors ()
		{
			first.Define (Parent);
			if (AccessorSecond != null)
				AccessorSecond.Define (Parent);

			return true;
		}

		protected void DefineBuilders (MemberKind kind, ParametersCompiled parameters)
		{
			PropertyBuilder = Parent.TypeBuilder.DefineProperty (
				GetFullName (MemberName), PropertyAttributes.None,
#if !BOOTSTRAP_BASIC	// Requires trunk version mscorlib
				IsStatic ? 0 : CallingConventions.HasThis,
#endif
				MemberType.GetMetaInfo (), null, null,
				parameters.GetMetaInfo (), null, null);

			PropertySpec spec;
			if (kind == MemberKind.Indexer)
				spec = new IndexerSpec (Parent.Definition, this, MemberType, parameters, PropertyBuilder, ModFlags);
			else
				spec = new PropertySpec (kind, Parent.Definition, this, MemberType, PropertyBuilder, ModFlags);

			if (Get != null) {
				spec.Get = Get.Spec;
				Parent.MemberCache.AddMember (this, Get.Spec.Name, Get.Spec);
			} else {
				CheckMissingAccessor (kind, parameters, true);
			}

			if (Set != null) {
				spec.Set = Set.Spec;
				Parent.MemberCache.AddMember (this, Set.Spec.Name, Set.Spec);
			} else {
				CheckMissingAccessor (kind, parameters, false);
			}

			Parent.MemberCache.AddMember (this, PropertyBuilder.Name, spec);
		}

		public override void Emit ()
		{
			CheckReservedNameConflict (GetMethod.Prefix, get == null ? null : get.Spec);
			CheckReservedNameConflict (SetMethod.Prefix, set == null ? null : set.Spec);

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

			if (member_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
				Module.PredefinedAttributes.Dynamic.EmitAttribute (PropertyBuilder);
			} else if (member_type.HasDynamicElement) {
				Module.PredefinedAttributes.Dynamic.EmitAttribute (PropertyBuilder, member_type, Location);
			}

			if (member_type.HasNamedTupleElement) {
				Module.PredefinedAttributes.TupleElementNames.EmitAttribute (PropertyBuilder, member_type, Location);
			}

			ConstraintChecker.Check (this, member_type, type_expr.Location);

			first.Emit (Parent);
			if (AccessorSecond != null)
				AccessorSecond.Emit (Parent);

			base.Emit ();
		}

		public override bool IsUsed {
			get {
				if (IsExplicitImpl)
					return true;

				return Get.IsUsed | Set.IsUsed;
			}
		}

		public override void PrepareEmit ()
		{
			AccessorFirst.PrepareEmit ();
			if (AccessorSecond != null)
				AccessorSecond.PrepareEmit ();

			if (get != null) {
				var method = Get.Spec.GetMetaInfo () as MethodBuilder;
				if (method != null)
					PropertyBuilder.SetGetMethod (method);
			}

			if (set != null) {
				var method = Set.Spec.GetMetaInfo () as MethodBuilder;
				if (method != null)
					PropertyBuilder.SetSetMethod (method);
			}
		}

		protected override void SetMemberName (MemberName new_name)
		{
			base.SetMemberName (new_name);

			if (Get != null)
				Get.UpdateName (this);

			if (Set != null)
				Set.UpdateName (this);
		}

		public override void WriteDebugSymbol (MonoSymbolFile file)
		{
			if (get != null)
				get.WriteDebugSymbol (file);

			if (set != null)
				set.WriteDebugSymbol (file);
		}

		//
		//   Represents header string for documentation comment.
		//
		public override string DocCommentHeader {
			get { return "P:"; }
		}
	}
			
	public class Property : PropertyBase
	{
		public sealed class BackingFieldDeclaration : Field
		{
			readonly Property property;
			const Modifiers DefaultModifiers = Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.PRIVATE | Modifiers.DEBUGGER_HIDDEN;

			public BackingFieldDeclaration (Property p, bool readOnly)
				: base (p.Parent, p.type_expr, DefaultModifiers | (p.ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)),
				new MemberName ("<" + p.GetFullName (p.MemberName) + ">k__BackingField", p.Location), null)
			{
				this.property = p;
				if (readOnly)
					ModFlags |= Modifiers.READONLY;
			}

			public Property OriginalProperty {
				get {
					return property;
				}
			}

			public override string GetSignatureForError ()
			{
				return property.GetSignatureForError ();
			}
		}

		static readonly string[] attribute_target_auto = new string[] { "property", "field" };

		public Property (TypeDefinition parent, FullNamedExpression type, Modifiers mod,
				 MemberName name, Attributes attrs)
			: base (parent, type, mod,
				parent.PartialContainer.Kind == MemberKind.Interface ? AllowedModifiersInterface :
				parent.PartialContainer.Kind == MemberKind.Struct ? AllowedModifiersStruct :
				AllowedModifiersClass,
				name, attrs)
		{
		}

		public BackingFieldDeclaration BackingField { get; private set; }

		public Expression Initializer { get; set; }

		public override void Accept (StructuralVisitor visitor)
		{
			visitor.Visit (this);
		}

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			if (a.Target == AttributeTargets.Field) {
				BackingField.ApplyAttributeBuilder (a, ctor, cdata, pa);
				return;
			}

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

		void CreateAutomaticProperty ()
		{
			// Create backing field
			BackingField = new BackingFieldDeclaration (this, Initializer == null && Set == null);
			if (!BackingField.Define ())
				return;

			if (Initializer != null) {
				BackingField.Initializer = Initializer;
				Parent.RegisterFieldForInitialization (BackingField, new FieldInitializer (BackingField, Initializer, Location));
				BackingField.ModFlags |= Modifiers.READONLY;
			}

			Parent.PartialContainer.Members.Add (BackingField);

			FieldExpr fe = new FieldExpr (BackingField, Location);
			if ((BackingField.ModFlags & Modifiers.STATIC) == 0) {
				fe.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location);
				Parent.PartialContainer.HasInstanceField = true;
			}

			//
			// Create get block but we careful with location to
			// emit only single sequence point per accessor. This allow
			// to set a breakpoint on it even with no user code
			//
			Get.Block = new ToplevelBlock (Compiler, ParametersCompiled.EmptyReadOnlyParameters, Location.Null);
			Return r = new Return (fe, Get.Location);
			Get.Block.AddStatement (r);
			Get.ModFlags |= Modifiers.COMPILER_GENERATED;

			// Create set block
			if (Set != null) {
				Set.Block = new ToplevelBlock (Compiler, Set.ParameterInfo, Location.Null);
				Assign a = new SimpleAssign (fe, new SimpleName ("value", Location.Null), Location.Null);
				Set.Block.AddStatement (new StatementExpression (a, Set.Location));
				Set.ModFlags |= Modifiers.COMPILER_GENERATED;
			}
		}

		public override bool Define ()
		{
			if (!base.Define ())
				return false;

			flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName;

			bool auto = AccessorFirst.Block == null && (AccessorSecond == null || AccessorSecond.Block == null) &&
				(ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) == 0;

			if (Initializer != null) {
				if (!auto)
					Report.Error (8050, Location, "`{0}': Only auto-implemented properties can have initializers",
						GetSignatureForError ());

				if (IsInterface)
					Report.Error (8052, Location, "`{0}': Properties inside interfaces cannot have initializers",
						GetSignatureForError ());

				if (Compiler.Settings.Version < LanguageVersion.V_6)
					Report.FeatureIsNotAvailable (Compiler, Location, "auto-implemented property initializer");
			}

			if (auto) {
				ModFlags |= Modifiers.AutoProperty;
				if (Get == null) {
					Report.Error (8051, Location, "Auto-implemented property `{0}' must have get accessor",
						GetSignatureForError ());
					return false;
				}

				if (MemberType.Kind == MemberKind.ByRef) {
					Report.Error (8145, Location, "Auto-implemented property `{0}' cannot return by reference",
						GetSignatureForError ());
					return false;
				}

				if ((Parent.PartialContainer.ModFlags & Modifiers.READONLY) != 0 && Set != null && !IsStatic) {
					Report.Error (8341, Location, "Auto-implemented instance property `{0}' in readonly structs must be readonly",
						GetSignatureForError ());
				}

				if (Compiler.Settings.Version < LanguageVersion.V_3 && Initializer == null)
					Report.FeatureIsNotAvailable (Compiler, Location, "auto-implemented properties");

				CreateAutomaticProperty ();
			}

			if (!DefineAccessors ())
				return false;

			if (AccessorSecond == null) {
				PropertyMethod pm;
				if (AccessorFirst is GetMethod)
					pm = new SetMethod (this, 0, ParametersCompiled.EmptyReadOnlyParameters, null, Location);
				else
					pm = new GetMethod (this, 0, null, Location);

				Parent.AddNameToContainer (pm, pm.MemberName.Basename);
			}

			if (!CheckBase ())
				return false;

			DefineBuilders (MemberKind.Property, ParametersCompiled.EmptyReadOnlyParameters);
			return true;
		}

		public override void Emit ()
		{
			if ((AccessorFirst.ModFlags & (Modifiers.STATIC | Modifiers.AutoProperty)) == Modifiers.AutoProperty && Parent.PartialContainer.HasExplicitLayout) {
				Report.Error (842, Location,
					"Automatically implemented property `{0}' cannot be used inside a type with an explicit StructLayout attribute",
					GetSignatureForError ());
			}

			base.Emit ();
		}

		public override string[] ValidAttributeTargets {
			get {
				return Get != null && ((Get.ModFlags & Modifiers.COMPILER_GENERATED) != 0) ?
					attribute_target_auto : base.ValidAttributeTargets;
			}
		}
	}

	/// <summary>
	/// For case when event is declared like property (with add and remove accessors).
	/// </summary>
	public class EventProperty: Event {
		public abstract class AEventPropertyAccessor : AEventAccessor
		{
			protected AEventPropertyAccessor (EventProperty method, string prefix, Attributes attrs, Location loc)
				: base (method, prefix, attrs, loc)
			{
			}

			public override void Define (TypeContainer ds)
			{
				CheckAbstractAndExtern (block != null);
				base.Define (ds);
			}
			
			public override string GetSignatureForError ()
			{
				return method.GetSignatureForError () + "." + prefix.Substring (0, prefix.Length - 1);
			}
		}

		public sealed class AddDelegateMethod: AEventPropertyAccessor
		{
			public AddDelegateMethod (EventProperty method, Attributes attrs, Location loc)
				: base (method, AddPrefix, attrs, loc)
			{
			}
		}

		public sealed class RemoveDelegateMethod: AEventPropertyAccessor
		{
			public RemoveDelegateMethod (EventProperty method, Attributes attrs, Location loc)
				: base (method, RemovePrefix, attrs, loc)
			{
			}
		}

		static readonly string[] attribute_targets = new string [] { "event" };

		public EventProperty (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
			: base (parent, type, mod_flags, name, attrs)
		{
		}

		public override void Accept (StructuralVisitor visitor)
		{
			visitor.Visit (this);
		}
		
		public override bool Define()
		{
			if (!base.Define ())
				return false;

			SetIsUsed ();
			return true;
		}

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

	/// <summary>
	/// Event is declared like field.
	/// </summary>
	public class EventField : Event
	{
		abstract class EventFieldAccessor : AEventAccessor
		{
			protected EventFieldAccessor (EventField method, string prefix)
				: base (method, prefix, null, method.Location)
			{
			}

			protected abstract MethodSpec GetOperation (Location loc);

			public override void Emit (TypeDefinition parent)
			{
				if ((method.ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) == 0 && !Compiler.Settings.WriteMetadataOnly) {
					block = new ToplevelBlock (Compiler, ParameterInfo, Location) {
						IsCompilerGenerated = true
					};
					FabricateBodyStatement ();
				}

				base.Emit (parent);
			}

			void FabricateBodyStatement ()
			{
				//
				// Delegate obj1 = backing_field
				// do {
				//   Delegate obj2 = obj1;
				//   obj1 = Interlocked.CompareExchange (ref backing_field, Delegate.Combine|Remove(obj2, value), obj1);
				// } while ((object)obj1 != (object)obj2)
				//

				var field_info = ((EventField) method).backing_field;
				FieldExpr f_expr = new FieldExpr (field_info, Location);
				if (!IsStatic)
					f_expr.InstanceExpression = new CompilerGeneratedThis (Parent.CurrentType, Location);

				var obj1 = LocalVariable.CreateCompilerGenerated (field_info.MemberType, block, Location);
				var obj2 = LocalVariable.CreateCompilerGenerated (field_info.MemberType, block, Location);

				block.AddStatement (new StatementExpression (new SimpleAssign (new LocalVariableReference (obj1, Location), f_expr)));

				var cond = new BooleanExpression (new Binary (Binary.Operator.Inequality,
					new Cast (new TypeExpression (Module.Compiler.BuiltinTypes.Object, Location), new LocalVariableReference (obj1, Location), Location),
					new Cast (new TypeExpression (Module.Compiler.BuiltinTypes.Object, Location), new LocalVariableReference (obj2, Location), Location)));

				var body = new ExplicitBlock (block, Location, Location);
				block.AddStatement (new Do (body, cond, Location, Location));

				body.AddStatement (new StatementExpression (
					new SimpleAssign (new LocalVariableReference (obj2, Location), new LocalVariableReference (obj1, Location))));

				var args_oper = new Arguments (2);
				args_oper.Add (new Argument (new LocalVariableReference (obj2, Location)));
				args_oper.Add (new Argument (block.GetParameterReference (0, Location)));

				var op_method = GetOperation (Location);

				var args = new Arguments (3);
				args.Add (new Argument (f_expr, Argument.AType.Ref));
				args.Add (new Argument (new Cast (
					new TypeExpression (field_info.MemberType, Location),
					new Invocation (MethodGroupExpr.CreatePredefined (op_method, op_method.DeclaringType, Location), args_oper),
					Location)));
				args.Add (new Argument (new LocalVariableReference (obj1, Location)));

				var cas = Module.PredefinedMembers.InterlockedCompareExchange_T.Get ();
				if (cas == null) {
					if (Module.PredefinedMembers.MonitorEnter_v4.Get () != null || Module.PredefinedMembers.MonitorEnter.Get () != null) {
						// Workaround for cripled (e.g. microframework) mscorlib without CompareExchange
						body.AddStatement (new Lock (
							block.GetParameterReference (0, Location),
							new StatementExpression (new SimpleAssign (
								f_expr, args [1].Expr, Location), Location), Location));
					} else {
						Module.PredefinedMembers.InterlockedCompareExchange_T.Resolve (Location);
					}
				} else {
					body.AddStatement (new StatementExpression (new SimpleAssign (
						new LocalVariableReference (obj1, Location),
						new Invocation (MethodGroupExpr.CreatePredefined (cas, cas.DeclaringType, Location), args))));
				}
			}
		}

		sealed class AddDelegateMethod: EventFieldAccessor
		{
			public AddDelegateMethod (EventField method):
				base (method, AddPrefix)
			{
			}

			protected override MethodSpec GetOperation (Location loc)
			{
				return Module.PredefinedMembers.DelegateCombine.Resolve (loc);
			}
		}

		sealed class RemoveDelegateMethod: EventFieldAccessor
		{
			public RemoveDelegateMethod (EventField method):
				base (method, RemovePrefix)
			{
			}

			protected override MethodSpec GetOperation (Location loc)
			{
				return Module.PredefinedMembers.DelegateRemove.Resolve (loc);
			}
		}


		static readonly string[] attribute_targets = new string [] { "event", "field", "method" };
		static readonly string[] attribute_targets_interface = new string[] { "event", "method" };

		Expression initializer;
		Field backing_field;
		List<FieldDeclarator> declarators;

		public EventField (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
			: base (parent, type, mod_flags, name, attrs)
		{
			Add = new AddDelegateMethod (this);
			Remove = new RemoveDelegateMethod (this);
		}

		#region Properties

		public List<FieldDeclarator> Declarators {
			get {
				return this.declarators;
			}
		}

		bool HasBackingField {
			get {
				return !IsInterface && (ModFlags & Modifiers.ABSTRACT) == 0;
			}
		}

		public Expression Initializer {
			get {
				return initializer;
			}
			set {
				initializer = value;
			}
		}

		public override string[] ValidAttributeTargets {
			get {
				return HasBackingField ? attribute_targets : attribute_targets_interface;
			}
		}

		#endregion

		
		public override void Accept (StructuralVisitor visitor)
		{
			visitor.Visit (this);
		}

		public void AddDeclarator (FieldDeclarator declarator)
		{
			if (declarators == null)
				declarators = new List<FieldDeclarator> (2);

			declarators.Add (declarator);

			Parent.AddNameToContainer (this, declarator.Name.Value);
		}

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			if (a.Target == AttributeTargets.Field) {
				backing_field.ApplyAttributeBuilder (a, ctor, cdata, pa);
				return;
			}

			if (a.Target == AttributeTargets.Method) {
				int errors = Report.Errors;
				Add.ApplyAttributeBuilder (a, ctor, cdata, pa);
				if (errors == Report.Errors)
					Remove.ApplyAttributeBuilder (a, ctor, cdata, pa);
				return;
			}

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

		protected override void DoMemberTypeIndependentChecks ()
		{
			if ((Parent.PartialContainer.ModFlags & Modifiers.READONLY) != 0 && (ModFlags & Modifiers.STATIC) == 0) {
				Report.Error (8342, Location, "`{0}': Field-like instance events are not allowed in readonly structs",
					GetSignatureForError ());
			}

			base.DoMemberTypeIndependentChecks ();
		}

		public override bool Define()
		{
			var mod_flags_src = ModFlags;

			if (!base.Define ())
				return false;

			if (declarators != null) {
				if ((mod_flags_src & Modifiers.DEFAULT_ACCESS_MODIFIER) != 0)
					mod_flags_src &= ~(Modifiers.AccessibilityMask | Modifiers.DEFAULT_ACCESS_MODIFIER);

				var t = new TypeExpression (MemberType, TypeExpression.Location);
				foreach (var d in declarators) {
					var ef = new EventField (Parent, t, mod_flags_src, new MemberName (d.Name.Value, d.Name.Location), OptAttributes);

					if (d.Initializer != null)
						ef.initializer = d.Initializer;

					ef.Define ();
					Parent.PartialContainer.Members.Add (ef);
				}
			}

			if (!HasBackingField) {
				SetIsUsed ();
				return true;
			}

			backing_field = new Field (Parent,
				new TypeExpression (MemberType, Location),
				Modifiers.BACKING_FIELD | Modifiers.COMPILER_GENERATED | Modifiers.DEBUGGER_HIDDEN | Modifiers.PRIVATE | (ModFlags & (Modifiers.STATIC | Modifiers.UNSAFE)),
				MemberName, null);

			Parent.PartialContainer.Members.Add (backing_field);
			backing_field.Initializer = Initializer;

			// Call define because we passed fields definition
			backing_field.Define ();

			// Set backing field for event fields
			spec.BackingField = backing_field.Spec;

			return true;
		}
	}

	public abstract class Event : PropertyBasedMember
	{
		public abstract class AEventAccessor : AbstractPropertyEventMethod
		{
			protected readonly Event method;
			readonly ParametersCompiled parameters;

			static readonly string[] attribute_targets = new string [] { "method", "param", "return" };

			public const string AddPrefix = "add_";
			public const string RemovePrefix = "remove_";

			protected AEventAccessor (Event method, string prefix, Attributes attrs, Location loc)
				: base (method, prefix, attrs, loc)
			{
				this.method = method;
				this.ModFlags = method.ModFlags;
				this.parameters = ParametersCompiled.CreateImplicitParameter (method.TypeExpression, loc);
			}

			public bool IsInterfaceImplementation {
				get { return method_data.implementing != null; }
			}

			public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
			{
				if (a.Type == pa.MethodImpl) {
					method.is_external_implementation = a.IsInternalCall ();
				}

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

			protected override void ApplyToExtraTarget (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
			{
				if (a.Target == AttributeTargets.Parameter) {
					parameters[0].ApplyAttributeBuilder (a, ctor, cdata, pa);
					return;
				}

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

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

			public override bool IsClsComplianceRequired ()
			{
				return method.IsClsComplianceRequired ();
			}

			public virtual void Define (TypeContainer parent)
			{
				// Fill in already resolved event type to speed things up and
				// avoid confusing duplicate errors
				((Parameter) parameters.FixedParameters[0]).Type = method.member_type;
				parameters.Types = new TypeSpec[] { method.member_type };

				method_data = new MethodData (method, method.ModFlags,
					method.flags | MethodAttributes.HideBySig | MethodAttributes.SpecialName, this);

				if (!method_data.Define (parent.PartialContainer, method.GetFullName (MemberName)))
					return;

				if (Compiler.Settings.WriteMetadataOnly)
					block = null;

				Spec = new MethodSpec (MemberKind.Method, parent.PartialContainer.Definition, this, ReturnType, ParameterInfo, method.ModFlags);
				Spec.IsAccessor = true;
			}

			public override TypeSpec ReturnType {
				get {
					return Parent.Compiler.BuiltinTypes.Void;
				}
			}

			public override ObsoleteAttribute GetAttributeObsolete ()
			{
				return method.GetAttributeObsolete ();
			}

			public MethodData MethodData {
				get {
					return method_data;
				}
			}

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

			public override ParametersCompiled ParameterInfo {
				get {
					return parameters;
				}
			}
		}

		AEventAccessor add, remove;
		EventBuilder EventBuilder;
		protected EventSpec spec;

		protected Event (TypeDefinition parent, FullNamedExpression type, Modifiers mod_flags, MemberName name, Attributes attrs)
			: base (parent, type, mod_flags,
				parent.PartialContainer.Kind == MemberKind.Interface ? AllowedModifiersInterface :
				parent.PartialContainer.Kind == MemberKind.Struct ? AllowedModifiersStruct :
				AllowedModifiersClass,
				name, attrs)
		{
		}

		#region Properties

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

		public AEventAccessor Add {
			get {
				return this.add;
			}
			set {
				add = value;
				Parent.AddNameToContainer (value, value.MemberName.Basename);
			}
		}

		public override Variance ExpectedMemberTypeVariance {
			get {
				return Variance.Contravariant;
			}
		}

		public AEventAccessor Remove {
			get {
				return this.remove;
			}
			set {
				remove = value;
				Parent.AddNameToContainer (value, value.MemberName.Basename);
			}
		}
		#endregion

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			if ((a.HasSecurityAttribute)) {
				a.Error_InvalidSecurityParent ();
				return;
			}

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

		protected override bool CheckOverrideAgainstBase (MemberSpec base_member)
		{
			var ok = base.CheckOverrideAgainstBase (base_member);

			if (!CheckAccessModifiers (this, base_member)) {
				Error_CannotChangeAccessModifiers (this, base_member);
				ok = false;
			}

			return ok;
		}

		public override bool Define ()
		{
			if (!base.Define ())
				return false;

			if (!MemberType.IsDelegate) {
				Report.Error (66, Location, "`{0}': event must be of a delegate type", GetSignatureForError ());
			}

			if (!CheckBase ())
				return false;

			//
			// Now define the accessors
			//
			add.Define (Parent);
			remove.Define (Parent);

			EventBuilder = Parent.TypeBuilder.DefineEvent (GetFullName (MemberName), EventAttributes.None, MemberType.GetMetaInfo ());

			spec = new EventSpec (Parent.Definition, this, MemberType, ModFlags, Add.Spec, remove.Spec);

			Parent.MemberCache.AddMember (this, GetFullName (MemberName), spec);
			Parent.MemberCache.AddMember (this, Add.Spec.Name, Add.Spec);
			Parent.MemberCache.AddMember (this, Remove.Spec.Name, remove.Spec);

			return true;
		}

		public override void Emit ()
		{
			CheckReservedNameConflict (null, add.Spec);
			CheckReservedNameConflict (null, remove.Spec);

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

			ConstraintChecker.Check (this, member_type, type_expr.Location);

			Add.Emit (Parent);
			Remove.Emit (Parent);

			base.Emit ();
		}

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

			add.PrepareEmit ();
			remove.PrepareEmit ();

			EventBuilder.SetAddOnMethod (add.MethodData.MethodBuilder);
			EventBuilder.SetRemoveOnMethod (remove.MethodData.MethodBuilder);
		}

		public override void WriteDebugSymbol (MonoSymbolFile file)
		{
			add.WriteDebugSymbol (file);
			remove.WriteDebugSymbol (file);
		}

		//
		//   Represents header string for documentation comment.
		//
		public override string DocCommentHeader {
			get { return "E:"; }
		}
	}

	public class EventSpec : MemberSpec, IInterfaceMemberSpec
	{
		MethodSpec add, remove;
		FieldSpec backing_field;

		public EventSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec eventType, Modifiers modifiers, MethodSpec add, MethodSpec remove)
			: base (MemberKind.Event, declaringType, definition, modifiers)
		{
			this.AccessorAdd = add;
			this.AccessorRemove = remove;
			this.MemberType = eventType;
		}

		#region Properties

		public MethodSpec AccessorAdd { 
			get {
				return add;
			}
			set {
				add = value;
			}
		}

		public MethodSpec AccessorRemove {
			get {
				return remove;
			}
			set {
				remove = value;
			}
		}

		public FieldSpec BackingField {
			get {
				return backing_field;
			}
			set {
				backing_field = value;
			}
		}

		public TypeSpec MemberType { get; private set; }

		#endregion

		public override MemberSpec InflateMember (TypeParameterInflator inflator)
		{
			var es = (EventSpec) base.InflateMember (inflator);
			es.MemberType = inflator.Inflate (MemberType);

			if (backing_field != null)
				es.backing_field = (FieldSpec) backing_field.InflateMember (inflator);

			return es;
		}

		public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
		{
			return MemberType.ResolveMissingDependencies (this);
		}
	}
 
	public class Indexer : PropertyBase, IParametersMember
	{
		public class GetIndexerMethod : GetMethod, IParametersMember
		{
			ParametersCompiled parameters;

			public GetIndexerMethod (PropertyBase property, Modifiers modifiers, ParametersCompiled parameters, Attributes attrs, Location loc)
				: base (property, modifiers, attrs, loc)
			{
				this.parameters = parameters;
			}

			public override void Define (TypeContainer parent)
			{
				// Disable reporting, parameters are resolved twice
				Report.DisableReporting ();
				try {
					parameters.Resolve (this);
				} finally {
					Report.EnableReporting ();
				}

				base.Define (parent);
			}

			public override ParametersCompiled ParameterInfo {
				get {
					return parameters;
				}
			}

			#region IParametersMember Members

			AParametersCollection IParametersMember.Parameters {
				get {
					return parameters;
				}
			}

			TypeSpec IInterfaceMemberSpec.MemberType {
				get {
					return ReturnType;
				}
			}

			#endregion
		}

		public class SetIndexerMethod : SetMethod, IParametersMember
		{
			public SetIndexerMethod (PropertyBase property, Modifiers modifiers, ParametersCompiled parameters, Attributes attrs, Location loc)
				: base (property, modifiers, parameters, attrs, loc)
			{
			}

			#region IParametersMember Members

			AParametersCollection IParametersMember.Parameters {
				get {
					return parameters;
				}
			}

			TypeSpec IInterfaceMemberSpec.MemberType {
				get {
					return ReturnType;
				}
			}

			#endregion
		}

		const Modifiers AllowedModifiers =
			Modifiers.NEW |
			Modifiers.PUBLIC |
			Modifiers.PROTECTED |
			Modifiers.INTERNAL |
			Modifiers.PRIVATE |
			Modifiers.VIRTUAL |
			Modifiers.SEALED |
			Modifiers.OVERRIDE |
			Modifiers.UNSAFE |
			Modifiers.EXTERN |
			Modifiers.ABSTRACT;

		const Modifiers AllowedInterfaceModifiers =
			Modifiers.NEW;

		readonly ParametersCompiled parameters;

		public Indexer (TypeDefinition parent, FullNamedExpression type, MemberName name, Modifiers mod, ParametersCompiled parameters, Attributes attrs)
			: base (parent, type, mod,
				parent.PartialContainer.Kind == MemberKind.Interface ? AllowedInterfaceModifiers : AllowedModifiers,
				name, attrs)
		{
			this.parameters = parameters;
		}

		#region Properties

		AParametersCollection IParametersMember.Parameters {
			get {
				return parameters;
			}
		}

		public ParametersCompiled ParameterInfo {
			get {
				return parameters;
			}
		}

		#endregion

		
		public override void Accept (StructuralVisitor visitor)
		{
			visitor.Visit (this);
		}

		public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
		{
			if (a.Type == pa.IndexerName) {
				// Attribute was copied to container
				return;
			}

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

		protected override bool CheckForDuplications ()
		{
			return Parent.MemberCache.CheckExistingMembersOverloads (this, parameters);
		}
		
		public override bool Define ()
		{
			if (!base.Define ())
				return false;

			if (!DefineParameters (parameters))
				return false;

			if (OptAttributes != null) {
				Attribute indexer_attr = OptAttributes.Search (Module.PredefinedAttributes.IndexerName);
				if (indexer_attr != null) {
					var compiling = indexer_attr.Type.MemberDefinition as TypeContainer;
					if (compiling != null)
						compiling.Define ();

					if (IsExplicitImpl) {
						Report.Error (415, indexer_attr.Location,
							"The `{0}' attribute is valid only on an indexer that is not an explicit interface member declaration",
							indexer_attr.Type.GetSignatureForError ());
					} else if ((ModFlags & Modifiers.OVERRIDE) != 0) {
						Report.Error (609, indexer_attr.Location,
							"Cannot set the `IndexerName' attribute on an indexer marked override");
					} else {
						string name = indexer_attr.GetIndexerAttributeValue ();

						if (!string.IsNullOrEmpty (name)) {
							SetMemberName (new MemberName (MemberName.Left, name, Location));
						}
					}
				}
			}

			if (InterfaceType != null) {
				string base_IndexerName = InterfaceType.MemberDefinition.GetAttributeDefaultMember ();
				if (base_IndexerName != ShortName) {
					SetMemberName (new MemberName (MemberName.Left, base_IndexerName, new TypeExpression (InterfaceType, Location), Location));
				}
			}

			Parent.AddNameToContainer (this, MemberName.Basename);

			flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName;
			
			if (!DefineAccessors ())
				return false;

			if (!CheckBase ())
				return false;

			DefineBuilders (MemberKind.Indexer, parameters);
			return true;
		}

		public override bool EnableOverloadChecks (MemberCore overload)
		{
			if (overload is Indexer) {
				caching_flags |= Flags.MethodOverloadsExist;
				return true;
			}

			return base.EnableOverloadChecks (overload);
		}

		public override void Emit ()
		{
			parameters.CheckConstraints (this);

			base.Emit ();
		}

		public override string GetSignatureForError ()
		{
			StringBuilder sb = new StringBuilder (Parent.GetSignatureForError ());
			if (MemberName.ExplicitInterface != null) {
				sb.Append (".");
				sb.Append (MemberName.ExplicitInterface.GetSignatureForError ());
			}

			sb.Append (".this");
			sb.Append (parameters.GetSignatureForError ("[", "]", parameters.Count));
			return sb.ToString ();
		}

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

		public override void PrepareEmit ()
		{
			base.PrepareEmit ();
			parameters.ResolveDefaultValues (this);
		}

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

			parameters.VerifyClsCompliance (this);
			return true;
		}
	}

	public class IndexerSpec : PropertySpec, IParametersMember
	{
		AParametersCollection parameters;

		public IndexerSpec (TypeSpec declaringType, IMemberDefinition definition, TypeSpec memberType, AParametersCollection parameters, PropertyInfo info, Modifiers modifiers)
			: base (MemberKind.Indexer, declaringType, definition, memberType, info, modifiers)
		{
			this.parameters = parameters;
		}

		#region Properties
		public AParametersCollection Parameters {
			get {
				return parameters;
			}
		}
		#endregion

		public static ParametersImported CreateParametersFromSetter (MethodSpec setter, int set_param_count)
		{
			//
			// Creates indexer parameters based on setter method parameters (the last parameter has to be removed)
			//
			var data = new IParameterData [set_param_count];
			var types = new TypeSpec [set_param_count];
			Array.Copy (setter.Parameters.FixedParameters, data, set_param_count);
			Array.Copy (setter.Parameters.Types, types, set_param_count);
			return new ParametersImported (data, types, setter.Parameters.HasParams);
		}

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

		public override string GetSignatureForError ()
		{
			return DeclaringType.GetSignatureForError () + ".this" + parameters.GetSignatureForError ("[", "]", parameters.Count);
		}

		public override MemberSpec InflateMember (TypeParameterInflator inflator)
		{
			var spec = (IndexerSpec) base.InflateMember (inflator);
			spec.parameters = parameters.Inflate (inflator);
			return spec;
		}

		public override List<MissingTypeSpecReference> ResolveMissingDependencies (MemberSpec caller)
		{
			var missing = base.ResolveMissingDependencies (caller);

			foreach (var pt in parameters.Types) {
				var m = pt.GetMissingDependencies (caller);
				if (m == null)
					continue;

				if (missing == null)
					missing = new List<MissingTypeSpecReference> ();

				missing.AddRange (m);
			}

			return missing;
		}
	}
}
