X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fclass.cs;h=b851ffec290552c2af646ae706bfc50f7fce1428;hb=5697a97b9870b44d6dab7bec66577fa3ec815ee0;hp=dd3ddeb618886dd017ef902ea8ec8ac4cdaba01b;hpb=33d2fc699a7c72ed3816e40cedea573e95a14b31;p=mono.git diff --git a/mcs/gmcs/class.cs b/mcs/gmcs/class.cs index dd3ddeb6188..b851ffec290 100755 --- a/mcs/gmcs/class.cs +++ b/mcs/gmcs/class.cs @@ -3,6 +3,7 @@ // // Authors: Miguel de Icaza (miguel@gnu.org) // Martin Baulig (martin@gnome.org) +// Marek Safar (marek.safar@seznam.cz) // // Licensed under the terms of the GNU GPL // @@ -30,61 +31,392 @@ // #define CACHE using System; +using System.Text; using System.Collections; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +using Mono.CompilerServices.SymbolWriter; namespace Mono.CSharp { + public enum Kind { + Root, + Struct, + Class, + Interface + } + /// /// This is the base class for structs and classes. /// - public class TypeContainer : DeclSpace, IMemberContainer { + public abstract class TypeContainer : DeclSpace, IMemberContainer { + + public class MemberCoreArrayList: ArrayList + { + /// + /// Defines the MemberCore objects that are in this array + /// + public virtual void DefineContainerMembers () + { + foreach (MemberCore mc in this) { + mc.Define (); + } + } + + public virtual void Emit () + { + foreach (MemberCore mc in this) + mc.Emit (); + } + } + + public class MethodArrayList: MemberCoreArrayList + { + [Flags] + enum CachedMethods { + Equals = 1, + GetHashCode = 1 << 1 + } + + CachedMethods cached_method; + TypeContainer container; + + public MethodArrayList (TypeContainer container) + { + this.container = container; + } + + /// + /// Method container contains Equals method + /// + public bool HasEquals { + set { + cached_method |= CachedMethods.Equals; + } + + get { + return (cached_method & CachedMethods.Equals) != 0; + } + } + + /// + /// Method container contains GetHashCode method + /// + public bool HasGetHashCode { + set { + cached_method |= CachedMethods.GetHashCode; + } + + get { + return (cached_method & CachedMethods.GetHashCode) != 0; + } + } + + public override void DefineContainerMembers () + { + base.DefineContainerMembers (); + + if ((RootContext.WarningLevel >= 3) && HasEquals && !HasGetHashCode) { + Report.Warning (659, container.Location, "'{0}' overrides Object.Equals(object) but does not override Object.GetHashCode()", container.GetSignatureForError ()); + } + } + + } + + public sealed class IndexerArrayList: MemberCoreArrayList + { + /// + /// The indexer name for this container + /// + public string IndexerName = DefaultIndexerName; + + bool seen_normal_indexers = false; + + TypeContainer container; + + public IndexerArrayList (TypeContainer container) + { + this.container = container; + } + + /// + /// Defines the indexers, and also verifies that the IndexerNameAttribute in the + /// class is consistent. Either it is `Item' or it is the name defined by all the + /// indexers with the `IndexerName' attribute. + /// + /// Turns out that the IndexerNameAttribute is applied to each indexer, + /// but it is never emitted, instead a DefaultMember attribute is attached + /// to the class. + /// + public override void DefineContainerMembers() + { + base.DefineContainerMembers (); + + 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 this) { + 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) + IndexerName = class_indexer_name; + } + + public override void Emit () + { + base.Emit (); + + if (!seen_normal_indexers) + return; + + CustomAttributeBuilder cb = new CustomAttributeBuilder (TypeManager.default_member_ctor, new string [] { IndexerName }); + container.TypeBuilder.SetCustomAttribute (cb); + } + } + + public class OperatorArrayList: MemberCoreArrayList + { + TypeContainer container; + + public OperatorArrayList (TypeContainer container) + { + this.container = container; + } + + // + // Operator pair checking + // + class OperatorEntry + { + public int flags; + public Type ret_type; + public Type type1, type2; + public Operator op; + public Operator.OpType ot; + + public OperatorEntry (int f, Operator o) + { + flags = f; + + ret_type = o.OperatorMethod.ReturnType; + Type [] pt = o.OperatorMethod.ParameterTypes; + type1 = pt [0]; + type2 = pt [1]; + op = o; + ot = o.OperatorType; + } + + public override int GetHashCode () + { + return ret_type.GetHashCode (); + } + + public override bool Equals (object o) + { + OperatorEntry other = (OperatorEntry) o; + + if (other.ret_type != ret_type) + return false; + if (other.type1 != type1) + return false; + if (other.type2 != type2) + return false; + return true; + } + } + + // + // 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 () + { + Hashtable pairs = new Hashtable (null, null); + Operator true_op = null; + Operator false_op = null; + bool has_equality_or_inequality = false; + + // Register all the operators we care about. + foreach (Operator op in this){ + int reg = 0; + + switch (op.OperatorType){ + case Operator.OpType.Equality: + reg = 1; + has_equality_or_inequality = true; + break; + case Operator.OpType.Inequality: + reg = 2; + has_equality_or_inequality = true; + break; + + case Operator.OpType.True: + true_op = op; + break; + case Operator.OpType.False: + false_op = op; + break; + + case Operator.OpType.GreaterThan: + reg = 1; break; + case Operator.OpType.LessThan: + reg = 2; break; + + case Operator.OpType.GreaterThanOrEqual: + reg = 1; break; + case Operator.OpType.LessThanOrEqual: + reg = 2; break; + } + if (reg == 0) + continue; + + OperatorEntry oe = new OperatorEntry (reg, op); + + object o = pairs [oe]; + if (o == null) + pairs [oe] = oe; + else { + oe = (OperatorEntry) o; + oe.flags |= reg; + } + } + + if (true_op != null){ + if (false_op == null) + Report.Error (216, true_op.Location, "operator true requires a matching operator false"); + } else if (false_op != null) + Report.Error (216, false_op.Location, "operator false requires a matching operator true"); + + // + // Look for the mistakes. + // + foreach (DictionaryEntry de in pairs){ + OperatorEntry oe = (OperatorEntry) de.Key; + + if (oe.flags == 3) + continue; + + string s = ""; + switch (oe.ot){ + case Operator.OpType.Equality: + s = "!="; + break; + case Operator.OpType.Inequality: + s = "=="; + break; + case Operator.OpType.GreaterThan: + s = "<"; + break; + case Operator.OpType.LessThan: + s = ">"; + break; + case Operator.OpType.GreaterThanOrEqual: + s = "<="; + break; + case Operator.OpType.LessThanOrEqual: + s = ">="; + break; + } + Report.Error (216, oe.op.Location, + "The operator `" + oe.op + "' requires a matching operator `" + s + "' to also be defined"); + } + + if (has_equality_or_inequality && (RootContext.WarningLevel > 2)) { + if (container.Methods == null || !container.Methods.HasEquals) + Report.Warning (660, container.Location, "'{0}' defines operator == or operator != but does not override Object.Equals(object o)", container.GetSignatureForError ()); + + if (container.Methods == null || !container.Methods.HasGetHashCode) + Report.Warning (661, container.Location, "'{0}' defines operator == or operator != but does not override Object.GetHashCode()", container.GetSignatureForError ()); + } + } + + public override void DefineContainerMembers () + { + base.DefineContainerMembers (); + CheckPairedOperators (); + } + } + + + // Whether this is a struct, class or interface + public readonly Kind Kind; + // Holds a list of classes and structures ArrayList types; // Holds the list of properties - ArrayList properties; + MemberCoreArrayList properties; // Holds the list of enumerations - ArrayList enums; + MemberCoreArrayList enums; // Holds the list of delegates - ArrayList delegates; + MemberCoreArrayList delegates; // Holds the list of constructors - ArrayList instance_constructors; + protected MemberCoreArrayList instance_constructors; // Holds the list of fields - ArrayList fields; + MemberCoreArrayList fields; // Holds a list of fields that have initializers - ArrayList initialized_fields; + protected ArrayList initialized_fields; // Holds a list of static fields that have initializers - ArrayList initialized_static_fields; + protected ArrayList initialized_static_fields; // Holds the list of constants - ArrayList constants; + MemberCoreArrayList constants; // Holds the list of - ArrayList interfaces; + MemberCoreArrayList interfaces; - // Holds order in which interfaces must be closed - ArrayList interface_order; - // Holds the methods. - ArrayList methods; + MethodArrayList methods; // Holds the events - ArrayList events; + MemberCoreArrayList events; // Holds the indexers - ArrayList indexers; + IndexerArrayList indexers; // Holds the operators - ArrayList operators; + MemberCoreArrayList operators; + + // Holds the iterators + ArrayList iterators; + + // Holds the parts of a partial class; + ArrayList parts; // The emit context for toplevel objects. EmitContext ec; @@ -92,13 +424,8 @@ namespace Mono.CSharp { // // Pointers to the default constructor and the default static constructor // - Constructor default_constructor; - Constructor default_static_constructor; - - // - // Whether we have seen a static constructor for this class or not - // - public bool UserDefinedStaticConstructor = false; + protected Constructor default_constructor; + protected Constructor default_static_constructor; // // Whether we have at least one non-static field @@ -109,208 +436,156 @@ namespace Mono.CSharp { // This one is computed after we can distinguish interfaces // from classes from the arraylist `type_bases' // - string base_class_name; + string base_class_name; + TypeExpr parent_type; ArrayList type_bases; bool members_defined; bool members_defined_ok; - // Information in the case we are an attribute type - - public AttributeTargets Targets = AttributeTargets.All; - public bool AllowMultiple = false; - public bool Inherited; - // The interfaces we implement. - TypeExpr [] ifaces; + protected Type[] ifaces; + protected Type ptype; // The parent member container and our member cache IMemberContainer parent_container; MemberCache member_cache; - // - // The indexer name for this class - // - public string IndexerName; + public const string DefaultIndexerName = "Item"; Type GenericType; - public TypeContainer (): - this (null, null, MemberName.Null, null, new Location (-1)) { - } - - public TypeContainer (NamespaceEntry ns, TypeContainer parent, - MemberName name, Attributes attrs, Location l) + public TypeContainer (NamespaceEntry ns, TypeContainer parent, MemberName name, + Attributes attrs, Kind kind, Location l) : base (ns, parent, name, attrs, l) { + this.Kind = kind; + types = new ArrayList (); base_class_name = null; } - public AdditionResult AddConstant (Const constant) + public bool AddToMemberContainer (MemberCore symbol, bool is_method) + { + return AddToContainer (symbol, is_method, String.Concat (Name, '.', symbol.Name), symbol.Name); + } + + bool AddToTypeContainer (DeclSpace ds) { - AdditionResult res; - string basename = constant.Name; - string fullname = Name + "." + basename; + return AddToContainer (ds, false, ds.Name, ds.Basename); + } + + public void AddConstant (Const constant) + { + if (!AddToMemberContainer (constant, false)) + return; - if ((res = IsValid (basename, fullname)) != AdditionResult.Success) - return res; - if (constants == null) - constants = new ArrayList (); + constants = new MemberCoreArrayList (); constants.Add (constant); - DefineName (fullname, constant); - - return AdditionResult.Success; } - public AdditionResult AddEnum (Mono.CSharp.Enum e) + public void AddEnum (Mono.CSharp.Enum e) { - AdditionResult res; - - if ((res = IsValid (e.Basename, e.Name)) != AdditionResult.Success) - return res; + if (!AddToTypeContainer (e)) + return; if (enums == null) - enums = new ArrayList (); + enums = new MemberCoreArrayList (); enums.Add (e); - DefineName (e.Name, e); - - return AdditionResult.Success; } - public AdditionResult AddClass (Class c) + public void AddClassOrStruct (TypeContainer c) { - AdditionResult res; - string name = c.Basename; - - if ((res = IsValid (name, c.Name)) != AdditionResult.Success) - return res; + if (!AddToTypeContainer (c)) + return; - DefineName (c.Name, c); types.Add (c); - - return AdditionResult.Success; - } - - public AdditionResult AddStruct (Struct s) - { - AdditionResult res; - string name = s.Basename; - - if ((res = IsValid (name, s.Name)) != AdditionResult.Success) - return res; - - DefineName (s.Name, s); - types.Add (s); - - return AdditionResult.Success; } - public AdditionResult AddDelegate (Delegate d) + public void AddDelegate (Delegate d) { - AdditionResult res; - string name = d.Basename; - - if ((res = IsValid (name, d.Name)) != AdditionResult.Success) - return res; + if (!AddToTypeContainer (d)) + return; if (delegates == null) - delegates = new ArrayList (); + delegates = new MemberCoreArrayList (); - DefineName (d.Name, d); delegates.Add (d); - - return AdditionResult.Success; } - public AdditionResult AddMethod (Method method) + public void AddMethod (Method method) { - string basename = method.Name; - string fullname = Name + "." + basename; - - Object value = defined_names [fullname]; - - if (value != null && (!(value is Method))) - return AdditionResult.NameExists; - - if (basename == Basename) - return AdditionResult.EnclosingClash; + if (!AddToMemberContainer (method, true)) + return; if (methods == null) - methods = new ArrayList (); + methods = new MethodArrayList (this); if (method.Name.IndexOf ('.') != -1) methods.Insert (0, method); else methods.Add (method); - - if (value == null) - DefineName (fullname, method); - - return AdditionResult.Success; } - public AdditionResult AddConstructor (Constructor c) + public void AddConstructor (Constructor c) { - if (c.Name != Basename) - return AdditionResult.NotAConstructor; + if (c.Name != Basename) { + Report.Error (1520, Location, "Class, struct, or interface method must have a return type"); + } bool is_static = (c.ModFlags & Modifiers.STATIC) != 0; if (is_static){ - UserDefinedStaticConstructor = true; - if (default_static_constructor != null) - return AdditionResult.MethodExists; + if (default_static_constructor != null) { + Report.SymbolRelatedToPreviousError (default_static_constructor); + Report.Error (111, c.Location, "Type '{0}' already defines a member " + + "called '{1}' with the same parameter types", Name, c.Name); + return; + } default_static_constructor = c; } else { if (c.IsDefault ()){ - if (default_constructor != null) - return AdditionResult.MethodExists; + if (default_constructor != null) { + Report.SymbolRelatedToPreviousError (default_constructor); + Report.Error (111, c.Location, "Type '{0}' already defines a member " + + "called '{1}' with the same parameter types", Name, c.Name); + return; + } default_constructor = c; } if (instance_constructors == null) - instance_constructors = new ArrayList (); + instance_constructors = new MemberCoreArrayList (); instance_constructors.Add (c); } - - return AdditionResult.Success; } - public AdditionResult AddInterface (Interface iface) + public void AddInterface (TypeContainer iface) { - AdditionResult res; - string name = iface.Basename; - - if ((res = IsValid (name, iface.Name)) != AdditionResult.Success) - return res; - - if (interfaces == null) - interfaces = new ArrayList (); + if (!AddToTypeContainer (iface)) + return; + + if (interfaces == null) { + interfaces = new MemberCoreArrayList (); + } + interfaces.Add (iface); - DefineName (iface.Name, iface); - - return AdditionResult.Success; } - public AdditionResult AddField (Field field) + public void AddField (Field field) { - AdditionResult res; - string basename = field.Name; - string fullname = Name + "." + basename; + if (!AddToMemberContainer (field, false)) + return; - if ((res = IsValid (basename, fullname)) != AdditionResult.Success) - return res; - if (fields == null) - fields = new ArrayList (); + fields = new MemberCoreArrayList (); fields.Add (field); @@ -331,112 +606,115 @@ namespace Mono.CSharp { if ((field.ModFlags & Modifiers.STATIC) == 0) have_nonstatic_fields = true; - - DefineName (fullname, field); - return AdditionResult.Success; } - public AdditionResult AddProperty (Property prop) + public void AddProperty (Property prop) { - AdditionResult res; - - if ((res = AddProperty (prop, prop.Name)) != AdditionResult.Success) - return res; - - if (prop.Get != null) { - if ((res = AddProperty (prop, "get_" + prop.Name)) != AdditionResult.Success) - return res; - } - - if (prop.Set != null) { - if ((res = AddProperty (prop, "set_" + prop.Name)) != AdditionResult.Success) - return res; - } + if (!AddToMemberContainer (prop, false) || + !AddToMemberContainer (prop.Get, true) || !AddToMemberContainer (prop.Set, true)) + return; if (properties == null) - properties = new ArrayList (); + properties = new MemberCoreArrayList (); if (prop.Name.IndexOf ('.') != -1) properties.Insert (0, prop); else properties.Add (prop); - - return AdditionResult.Success; } - AdditionResult AddProperty (Property prop, string basename) + public void AddEvent (Event e) { - AdditionResult res; - string fullname = Name + "." + basename; - - if ((res = IsValid (basename, fullname)) != AdditionResult.Success) - return res; - - DefineName (fullname, prop); - - return AdditionResult.Success; - } + if (!AddToMemberContainer (e, false)) + return; - public AdditionResult AddEvent (Event e) - { - AdditionResult res; - string basename = e.Name; - string fullname = Name + "." + basename; + if (e is EventProperty) { + if (!AddToMemberContainer (e.Add, true)) + return; - if ((res = IsValid (basename, fullname)) != AdditionResult.Success) - return res; + if (!AddToMemberContainer (e.Remove, true)) + return; + } if (events == null) - events = new ArrayList (); - - events.Add (e); - DefineName (fullname, e); + events = new MemberCoreArrayList (); - return AdditionResult.Success; + events.Add (e); } + /// + /// Indexer has special handling in constrast to other AddXXX because the name can be driven by IndexerNameAttribute + /// public void AddIndexer (Indexer i) { if (indexers == null) - indexers = new ArrayList (); + indexers = new IndexerArrayList (this); - if (i.InterfaceType != null) + if (i.IsExplicitImpl) indexers.Insert (0, i); else indexers.Add (i); } - public AdditionResult AddOperator (Operator op) + public void AddOperator (Operator op) { + if (!AddToMemberContainer (op, true)) + return; + if (operators == null) - operators = new ArrayList (); + operators = new OperatorArrayList (this); operators.Add (op); + } - string basename = op.Name; - string fullname = Name + "." + basename; - if (!defined_names.Contains (fullname)) - { - DefineName (fullname, op); - } - return AdditionResult.Success; + public void AddIterator (Iterator i) + { + if (iterators == null) + iterators = new ArrayList (); + + iterators.Add (i); } - public void RegisterOrder (Interface iface) + public void AddType (TypeContainer tc) { - if (interface_order == null) - interface_order = new ArrayList (); + types.Add (tc); + } + + public void AddPart (ClassPart part) + { + if (parts == null) + parts = new ArrayList (); - interface_order.Add (iface); + parts.Add (part); } - + + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + { + if (a.Type == TypeManager.default_member_type) { + if (Indexers != null) { + Report.Error (646, a.Location, + "Cannot specify the DefaultMember attribute on" + + " a type containing an indexer"); + return; + } + } + + base.ApplyAttributeBuilder (a, cb); + } + + public override AttributeTargets AttributeTargets { + get { + throw new NotSupportedException (); + } + } + public ArrayList Types { get { return types; } } - public ArrayList Methods { + public MethodArrayList Methods { get { return methods; } @@ -453,6 +731,12 @@ namespace Mono.CSharp { return interfaces; } } + + public ArrayList Iterators { + get { + return iterators; + } + } public string Base { get { @@ -474,10 +758,6 @@ namespace Mono.CSharp { get { return fields; } - - set { - fields = value; - } } public ArrayList InstanceConstructors { @@ -522,12 +802,24 @@ namespace Mono.CSharp { } } + public ArrayList Parts { + get { + return parts; + } + } + public virtual TypeAttributes TypeAttr { get { return Modifiers.TypeAttr (ModFlags, this); } } + public string IndexerName { + get { + return indexers == null ? DefaultIndexerName : indexers.IndexerName; + } + } + // // Emits the instance field initializers // @@ -555,6 +847,8 @@ namespace Mono.CSharp { Location l = f.Location; FieldExpr fe = new FieldExpr (f.FieldBuilder, l); fe.InstanceExpression = instance_expr; + fe.IsFieldInitializer = true; + ExpressionStatement a = new Assign (fe, e, l); a = a.ResolveStatement (ec); @@ -570,7 +864,7 @@ namespace Mono.CSharp { // // Defines the default constructors // - void DefineDefaultConstructor (bool is_static) + protected void DefineDefaultConstructor (bool is_static) { Constructor c; @@ -596,121 +890,182 @@ namespace Mono.CSharp { } - public void ReportStructInitializedInstanceError () - { - string n = TypeBuilder.FullName; - - foreach (Field f in initialized_fields){ - Report.Error ( - 573, Location, - "`" + n + "." + f.Name + "': can not have " + - "instance field initializers in structs"); - } - } - /// - /// The pending methods that need to be implemented (interfaces or abstract methods) + /// The pending methods that need to be implemented + // (interfaces or abstract methods) /// public PendingImplementation Pending; - /// - /// 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 @parent argument is set to the parent object or null - /// if this is `System.Object'. - /// - TypeExpr [] GetClassBases (bool is_class, bool is_iface, - out TypeExpr parent, out bool error) - { - ArrayList bases = Bases; - int count; - int start, j, i; + public abstract void Register (); - error = false; + public abstract PendingImplementation GetPendingImplementations (); - if (is_class || is_iface) - parent = null; - else - parent = TypeManager.system_valuetype_expr; + TypeExpr[] GetPartialBases (out TypeExpr parent, out bool error) + { + ArrayList ifaces = new ArrayList (); - if (bases == null){ - if (is_class){ - if (RootContext.StdLib) - parent = TypeManager.system_object_expr; - else if (Name != "System.Object") - parent = TypeManager.system_object_expr; - } else { - // - // If we are compiling our runtime, - // and we are defining ValueType, then our - // parent is `System.Object'. - // - if (!RootContext.StdLib && Name == "System.ValueType") - parent = TypeManager.system_object_expr; + parent = null; + Location parent_loc = Location.Null; + + foreach (ClassPart part in parts) { + TypeExpr new_parent; + TypeExpr[] new_ifaces; + + new_ifaces = part.GetClassBases (out new_parent, out error); + if (error) + return null; + + if ((parent != null) && (new_parent != null) && + !parent.Equals (new_parent)) { + Report.Error (263, part.Location, + "Partial declarations of `{0}' must " + + "not specify different base classes", + Name); + + if (!Location.IsNull (parent_loc)) + Report.LocationOfPreviousError (parent_loc); + + error = true; + return null; } - return null; + if ((parent == null) && (new_parent != null)) { + parent = new_parent; + parent_loc = part.Location; + } + + if (new_ifaces == null) + continue; + + foreach (TypeExpr iface in new_ifaces) { + bool found = false; + foreach (TypeExpr old_iface in ifaces) { + if (old_iface.Equals (iface)) { + found = true; + break; + } + } + + if (!found) + ifaces.Add (iface); + } } - // - // Bases should be null if there are no bases at all - // - count = bases.Count; + error = false; + + TypeExpr[] retval = new TypeExpr [ifaces.Count]; + ifaces.CopyTo (retval, 0); + return retval; + } + + TypeExpr[] GetNormalBases (out TypeExpr parent, out bool error) + { + parent = null; + + int count = Bases.Count; + int start, i, j; - if (is_class){ - TypeExpr name = ResolveTypeExpr ((Expression) bases [0], false, Location); + if (Kind == Kind.Class){ + TypeExpr name = ResolveTypeExpr ( + (Expression) Bases [0], false, Location); if (name == null){ error = true; return null; } - if (name is TypeParameterExpr){ + if (name.IsClass){ + parent = name; + start = 1; + } else { + start = 0; + } + } else { + start = 0; + } + + TypeExpr [] ifaces = new TypeExpr [count-start]; + + for (i = start, j = 0; i < count; i++, j++){ + Expression name = (Expression) Bases [i]; + TypeExpr resolved = ResolveTypeExpr (name, false, Location); + if (resolved == null) { + error = true; + return null; + } + + ifaces [j] = resolved; + } + + error = false; + return ifaces; + } + + /// + /// 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 @parent argument is set to the parent object or null + /// if this is `System.Object'. + /// + TypeExpr [] GetClassBases (out TypeExpr parent, out bool error) + { + ArrayList bases = Bases; + int start, j, i; + + error = false; + + TypeExpr[] ifaces; + + if (parts != null) + ifaces = GetPartialBases (out parent, out error); + else if (Bases == null){ + parent = null; + return null; + } else + ifaces = GetNormalBases (out parent, out error); + + if (error) + return null; + + if ((parent != null) && (Kind == Kind.Class)){ + if (parent is TypeParameterExpr){ Report.Error ( - 689, name.Location, + 689, parent.Location, "Type parameter `{0}' can not be used as a " + - "base class or interface", name.Name); + "base class or interface", parent.Name); error = true; return null; } - if (IsGeneric && name.IsAttribute){ + if (IsGeneric && parent.IsAttribute){ Report.Error ( - 698, name.Location, + 698, parent.Location, "A generic type cannot derive from `{0}' " + - "because it is an attribute class", name.Name); + "because it is an attribute class", + parent.Name); error = true; return null; } - if (name.IsClass){ - parent = name; - start = 1; - } else { - parent = TypeManager.system_object_expr; - start = 0; - } - if (name.IsSealed){ - string detail = ""; - - if (name.IsValueType) - detail = " (a class can not inherit from a struct/enum)"; - - Report.Error (509, "class `"+ Name + - "': Cannot inherit from sealed class `"+ - name.Name + "'" + detail); + if (parent.IsSealed){ error = true; + Report.SymbolRelatedToPreviousError (parent.Type); + if (parent.Type.IsAbstract) { + Report.Error (709, Location, "'{0}': Cannot derive from static class", GetSignatureForError ()); + } else { + Report.Error (509, Location, "'{0}': Cannot derive from sealed class", GetSignatureForError ()); + } return null; } if (!parent.CanInheritFrom ()){ Report.Error (644, Location, "`{0}' cannot inherit from special class `{1}'", - Name, parent.Name); + Name, parent_type.Name); error = true; return null; } @@ -718,62 +1073,62 @@ namespace Mono.CSharp { if (!parent.AsAccessible (this, ModFlags)) Report.Error (60, Location, "Inconsistent accessibility: base class `" + - name.Name + "' is less accessible than class `" + + parent.Name + "' is less accessible than class `" + Name + "'"); - - } else { - start = 0; } if (parent != null) base_class_name = parent.Name; - TypeExpr [] ifaces = new TypeExpr [count-start]; + if (ifaces == null) + return null; - for (i = start, j = 0; i < count; i++, j++){ - Expression name = (Expression) bases [i]; - TypeExpr resolved = ResolveTypeExpr (name, false, Location); + int count = ifaces != null ? ifaces.Length : 0; - if (resolved == null) - return null; - - bases [i] = resolved; + for (i = 0; i < count; i++) { + TypeExpr iface = (TypeExpr) ifaces [i]; - if (is_class == false && !resolved.IsInterface){ - Report.Error (527, "In Struct `" + Name + "', type `"+ - name +"' is not an interface"); + if ((Kind != Kind.Class) && !iface.IsInterface){ + string what = Kind == Kind.Struct ? + "Struct" : "Interface"; + + Report.Error (527, Location, + "In {0} `{1}', type `{2}' is not "+ + "an interface", what, Name, iface.Name); error = true; return null; } - - if (resolved.IsClass) { + + if (iface.IsClass) { if (parent != null){ - Report.Error (527, "In Class `" + Name + "', type `"+ - name+"' is not an interface"); + Report.Error (527, Location, + "In Class `{0}', `{1}' is not " + + "an interface", Name, iface.Name); error = true; return null; } } - - for (int x = 0; x < j; x++) { - if (resolved.Equals (ifaces [x])) { - Report.Error (528, "`" + name + "' is already listed in interface list"); + + for (int x = 0; x < i; x++) { + if (iface.Equals (ifaces [x])) { + Report.Error (528, Location, + "`{0}' is already listed in " + + "interface list", iface.Name); error = true; return null; } } - if (is_iface && - !resolved.AsAccessible (Parent, ModFlags)) + if ((Kind == Kind.Interface) && + !iface.AsAccessible (Parent, ModFlags)) Report.Error (61, Location, - "Inconsistent accessibility: base interface `" + - name + "' is less accessible than interface `" + - Name + "'"); - - ifaces [j] = resolved; + "Inconsistent accessibility: base " + + "interface `{0}' is less accessible " + + "than interface `{1}'", iface.Name, + Name); } - return TypeManager.ExpandInterfaces (ifaces); + return ifaces; } bool CheckGenericInterfaces (Type[] ifaces) @@ -813,110 +1168,130 @@ namespace Mono.CSharp { public override TypeBuilder DefineType () { TypeExpr parent; - bool is_class, is_iface; - - if (TypeBuilder != null) - return TypeBuilder; if (error) return null; - - if (InTransit) { - Report.Error (146, Location, "Class definition is circular: `{0}'", Name); - error = true; - return null; - } - - InTransit = true; - if (this is Interface) { - is_iface = true; - is_class = false; - } else { - is_iface = false; - if (this is Class) - is_class = true; - else - is_class = false; - } + if (TypeBuilder != null) + return TypeBuilder; ec = new EmitContext (this, Mono.CSharp.Location.Null, null, null, ModFlags); - ifaces = GetClassBases (is_class, is_iface, out parent, out error); - - if (error) - return null; + TypeAttributes type_attributes = TypeAttr; - if (IsGeneric) { - foreach (TypeParameter type_param in TypeParameters) - if (!type_param.Resolve (this)) { + try { + if (IsTopLevel){ + if (TypeManager.NamespaceClash (Name, Location)) { error = true; return null; } - } - - if (!is_class && TypeManager.value_type == null) - throw new Exception (); - - TypeAttributes type_attributes = TypeAttr; - - Type ptype; - ConstructedType constructed = parent as ConstructedType; - if ((constructed == null) && (parent != null)) - ptype = parent.ResolveType (ec); - else - ptype = null; - if (IsTopLevel){ - if (TypeManager.NamespaceClash (Name, Location)) { - error = true; - return null; - } + ModuleBuilder builder = CodeGen.Module.Builder; + TypeBuilder = builder.DefineType ( + Name, type_attributes, null, null); + } else { + TypeBuilder builder; + if (Parent.TypeBuilder != null) + builder = Parent.TypeBuilder; + else + builder = Parent.DefineType (); - ModuleBuilder builder = CodeGen.Module.Builder; - TypeBuilder = builder.DefineType ( - Name, type_attributes, ptype, null); + if (builder == null) { + error = true; + return null; + } - } else { - TypeBuilder builder = Parent.DefineType (); - if (builder == null) { - error = true; - return null; + TypeBuilder = builder.DefineNestedType ( + MemberName.Basename, type_attributes, + null, null); } - - TypeBuilder = builder.DefineNestedType ( - Basename, type_attributes, ptype, null); + } + catch (ArgumentException) { + Report.RuntimeMissingSupport ("static classes"); + return null; } - TypeManager.AddUserType (Name, TypeBuilder, this, ifaces); + TypeManager.AddUserType (Name, TypeBuilder, this); if (IsGeneric) { + foreach (TypeParameter type_param in TypeParameters) { + if (!type_param.Resolve (this)) { + error = true; + return null; + } + } + CurrentType = new ConstructedType ( Name, TypeParameters, Location); + string[] param_names = new string [TypeParameters.Length]; + for (int i = 0; i < TypeParameters.Length; i++) + param_names [i] = TypeParameters [i].Name; + + GenericTypeParameterBuilder[] gen_params; + + gen_params = TypeBuilder.DefineGenericParameters (param_names); + + for (int i = 0; i < gen_params.Length; i++) + TypeParameters [i].Define (gen_params [i]); + } + + if (IsGeneric) { foreach (TypeParameter type_param in TypeParameters) - type_param.Define (TypeBuilder); + if (!type_param.DefineType (ec)) { + error = true; + return null; + } + } + + if ((Kind == Kind.Struct) && TypeManager.value_type == null) + throw new Exception (); + + TypeExpr[] iface_exprs = GetClassBases (out parent_type, out error); + if (error) + return null; + + if (parent_type == null) { + if (Kind == Kind.Class){ + if (RootContext.StdLib) + parent_type = TypeManager.system_object_expr; + else if (Name != "System.Object") + parent_type = TypeManager.system_object_expr; + } else if (Kind == Kind.Struct){ + // + // If we are compiling our runtime, + // and we are defining ValueType, then our + // parent is `System.Object'. + // + if (!RootContext.StdLib && Name == "System.ValueType") + parent_type = TypeManager.system_object_expr; + else if (Kind == Kind.Struct) + parent_type = TypeManager.system_valuetype_expr; + } } + ConstructedType constructed = parent_type as ConstructedType; + if ((constructed == null) && (parent_type != null)) + ptype = parent_type.ResolveType (ec); + else + ptype = null; + if (constructed != null) { ptype = constructed.ResolveType (ec); if (ptype == null) { error = true; return null; } - - TypeBuilder.SetParent (ptype); } - if (IsGeneric) { - foreach (TypeParameter type_param in TypeParameters) - if (!type_param.DefineType (ec, TypeBuilder)) - error = true; - - if (error) - return null; + if (!CheckRecursiveDefinition ()) { + error = true; + return null; } + if (ptype != null) + TypeBuilder.SetParent (ptype); + // // Structs with no fields need to have at least one byte. // The right thing would be to set the PackingSize in a DefineType @@ -924,30 +1299,36 @@ namespace Mono.CSharp { // be specified. // - if (!is_class && !is_iface && !have_nonstatic_fields){ + if ((Kind == Kind.Struct) && !have_nonstatic_fields){ TypeBuilder.DefineField ("$PRIVATE$", TypeManager.byte_type, FieldAttributes.Private); } // add interfaces that were not added at type creation - if (ifaces != null) { - Type[] itypes = new Type [ifaces.Length]; - for (int i = 0; i < ifaces.Length; i++) { - itypes [i] = ifaces [i].ResolveType (ec); - if (itypes [i] == null) - error = true; + if (iface_exprs != null) { + ifaces = TypeManager.ExpandInterfaces (ec, iface_exprs); + if (ifaces == null) { + error = true; + return null; } - if (error) - return null; + foreach (Type itype in ifaces) + TypeBuilder.AddInterfaceImplementation (itype); - if (!CheckGenericInterfaces (itypes)) { + if (!CheckGenericInterfaces (ifaces)) { error = true; return null; } - for (int i = 0; i < ifaces.Length; i++) - TypeBuilder.AddInterfaceImplementation (itypes [i]); + TypeManager.RegisterBuilder (TypeBuilder, ifaces); + } + + if (IsGeneric) { + foreach (TypeParameter type_param in TypeParameters) + if (!type_param.CheckDependencies (ec)) { + error = true; + return null; + } } // @@ -955,171 +1336,79 @@ namespace Mono.CSharp { // ec.ContainerType = TypeBuilder; - if ((parent != null) && parent.IsAttribute) { + if ((parent_type != null) && parent_type.IsAttribute) { RootContext.RegisterAttribute (this); - TypeManager.RegisterAttrType (TypeBuilder, this); - } else + } else if (!(this is Iterator)) RootContext.RegisterOrder (this); - + + if (!DefineNestedTypes ()) { + error = true; + return null; + } + + return TypeBuilder; + } + + protected virtual bool DefineNestedTypes () + { if (Interfaces != null) { - foreach (Interface iface in Interfaces) - if (iface.DefineType () == null) { - error = true; - return null; - } + foreach (TypeContainer iface in Interfaces) + if (iface.DefineType () == null) + return false; } if (Types != null) { foreach (TypeContainer tc in Types) - if (tc.DefineType () == null) { - error = true; - return null; - } + if (tc.DefineType () == null) + return false; } if (Delegates != null) { foreach (Delegate d in Delegates) - if (d.DefineType () == null) { - error = true; - return null; - } + if (d.DefineType () == null) + return false; } if (Enums != null) { foreach (Enum en in Enums) - if (en.DefineType () == null) { - error = true; - return null; - } + if (en.DefineType () == null) + return false; } - InTransit = false; - return TypeBuilder; - } + if (Parts != null) { + foreach (ClassPart part in Parts) { + part.TypeBuilder = TypeBuilder; + part.parent_type = parent_type; + } + } + return true; + } - /// - /// Defines the MemberCore objects that are in the `list' Arraylist - /// - /// The `defined_names' array contains a list of members defined in - /// a base class - /// - static ArrayList remove_list = new ArrayList (); - void DefineMembers (ArrayList list, MemberInfo [] defined_names) + protected bool CheckRecursiveDefinition () { - int idx; - - remove_list.Clear (); - - foreach (MemberCore mc in list){ - - if (defined_names != null) - idx = Array.BinarySearch (defined_names, mc.Name, mif_compare); - else - idx = -1; - - if (idx < 0){ - if (RootContext.WarningLevel >= 4){ - if ((mc.ModFlags & Modifiers.NEW) != 0) - Warning_KeywordNewNotRequired (mc.Location, mc); - } - } else if (mc is MethodCore) - ((MethodCore) mc).OverridesSomething = true; - - if (!mc.Define (this)){ - remove_list.Add (mc); - continue; - } - - if (idx < 0) - continue; - - MemberInfo match = defined_names [idx]; - - if (match is PropertyInfo && ((mc.ModFlags & Modifiers.OVERRIDE) != 0)) - continue; - - // - // If we are both methods, let the method resolution emit warnings - // - if (match is MethodBase && mc is MethodCore) - continue; - - if ((mc.ModFlags & Modifiers.NEW) == 0) { - if (mc is Event) { - if (!(match is EventInfo)) { - Error_EventCanOnlyOverrideEvent (mc.Location, defined_names [idx]); - return; - } - - if ((mc.ModFlags & Modifiers.OVERRIDE) != 0) - continue; - } - - Warning_KeywordNewRequired (mc.Location, defined_names [idx]); - } + if (InTransit) { + Report.Error (146, Location, + "Class definition is circular: `{0}'", + GetSignatureForError ()); + error = true; + return false; } - - foreach (object o in remove_list) - list.Remove (o); - - remove_list.Clear (); - } - // - // Defines the indexers, and also verifies that the IndexerNameAttribute in the - // class is consisten. Either it is `Item' or it is the name defined by all the - // indexers with the `IndexerName' attribute. - // - // Turns out that the IndexerNameAttribute is applied to each indexer, - // but it is never emitted, instead a DefaultName attribute is attached - // to the class. - // - void DefineIndexers () - { - string class_indexer_name = null; + InTransit = true; - // - // 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. - // + Type parent = ptype; + if (parent != null) { + if (parent.IsGenericInstance) + parent = parent.GetGenericTypeDefinition (); - ArrayList list = new ArrayList (); - foreach (Indexer i in Indexers){ - if (i.MemberName.TypeName != null) - list.Add (i); - } - foreach (Indexer i in Indexers){ - if (i.MemberName.TypeName == null) - list.Add (i); + TypeContainer ptc = TypeManager.LookupTypeContainer (parent); + if ((ptc != null) && !ptc.CheckRecursiveDefinition ()) + return false; } - foreach (Indexer i in list){ - string name; - - i.Define (this); - - name = i.IndexerName; - - if (i.InterfaceType != null) - continue; - - if (class_indexer_name == null){ - class_indexer_name = name; - continue; - } - - if (name == class_indexer_name) - continue; - - Report.Error ( - 668, "Two indexers have different names, " + - " you should use the same name for all your indexers"); - } - if (class_indexer_name == null) - class_indexer_name = "Item"; - IndexerName = class_indexer_name; + InTransit = false; + return true; } static void Error_KeywordNotAllowed (Location loc) @@ -1143,73 +1432,47 @@ namespace Mono.CSharp { bool DoDefineMembers () { - MemberInfo [] defined_names = null; - // // We need to be able to use the member cache while we are checking/defining // -#if CACHE if (TypeBuilder.BaseType != null) parent_container = TypeManager.LookupMemberContainer (TypeBuilder.BaseType); -#endif - - if (interface_order != null){ - foreach (Interface iface in interface_order) - if ((iface.ModFlags & Modifiers.NEW) == 0) - iface.DefineMembers (this); - else - Error_KeywordNotAllowed (iface.Location); - } - - if (RootContext.WarningLevel > 1){ - Type ptype; - // - // This code throws an exception in the comparer - // I guess the string is not an object? - // - ptype = TypeBuilder.BaseType; - if (ptype != null){ - defined_names = (MemberInfo []) FindMembers ( - ptype, MemberTypes.All & ~MemberTypes.Constructor, - BindingFlags.Public | BindingFlags.Instance | - BindingFlags.Static, null, null); - - Array.Sort (defined_names, mif_compare); + // TODO: + //if (TypeBuilder.IsInterface) { + // parent_container = TypeManager.LookupInterfaceContainer (base_inteface_types); + //} + + if (IsTopLevel) { + if ((ModFlags & Modifiers.NEW) != 0) + Error_KeywordNotAllowed (Location); + } else { + // HACK: missing implemenation + // This is not fully functional. Better way how to handle this is to have recursive definition of containers + // instead of flat as we have now. + // Now we are not able to check inner attribute class because its parent had not been defined. + + // TODO: remove this if + if (Parent.MemberCache != null) { + MemberInfo conflict_symbol = Parent.MemberCache.FindMemberWithSameName (Basename, false, TypeBuilder); + if (conflict_symbol == null) { + if ((RootContext.WarningLevel >= 4) && ((ModFlags & Modifiers.NEW) != 0)) + Report.Warning (109, Location, "The member '{0}' does not hide an inherited member. The new keyword is not required", GetSignatureForError ()); + } else { + if ((ModFlags & Modifiers.NEW) == 0) { + Report.SymbolRelatedToPreviousError (conflict_symbol); + Report.Warning (108, Location, "The keyword new is required on '{0}' because it hides inherited member", GetSignatureForError ()); + } + } } } - Class pclass = Parent as Class; - if (pclass != null) { - string pname = null; - TypeExpr ptype = null; - Type t = pclass.TypeBuilder.BaseType; - while ((t != null) && (ptype == null)) { - pname = t.FullName + "." + Basename; - ptype = RootContext.LookupType (this, pname, true, Location.Null); - t = t.BaseType; - } - - if ((ModFlags & Modifiers.NEW) != 0) { - if (ptype == null) - Report.Warning (109, Location, "The member '" + Name + "' does not hide an " + - "inherited member. The keyword new is not required."); - } else if (ptype != null) { - Report.Warning (108, Location, "The keyword new is required on `" + - Name + "' because it hides inherited member '" + - pname + "'."); - } - } else if ((ModFlags & Modifiers.NEW) != 0) - Error_KeywordNotAllowed (Location); - - if (constants != null) - DefineMembers (constants, defined_names); - - if (fields != null) - DefineMembers (fields, defined_names); + DefineContainerMembers (constants); + DefineContainerMembers (fields); - if (this is Class){ - if (instance_constructors == null){ + if ((Kind == Kind.Class) && !(this is ClassPart) && !(this is StaticClass)){ + if ((instance_constructors == null) && + !(this is StaticClass)) { if (default_constructor == null) DefineDefaultConstructor (false); } @@ -1219,7 +1482,7 @@ namespace Mono.CSharp { DefineDefaultConstructor (true); } - if (this is Struct){ + if (Kind == Kind.Struct){ // // Structs can not have initialized instance // fields @@ -1232,43 +1495,30 @@ namespace Mono.CSharp { ReportStructInitializedInstanceError (); } - if (!(this is Interface)) - Pending = PendingImplementation.GetPendingImplementations (this); + Pending = GetPendingImplementations (); + + if (parts != null) { + foreach (ClassPart part in parts) { + if (!part.DefineMembers (this)) + return false; + } + } // // Constructors are not in the defined_names array // - if (instance_constructors != null) - DefineMembers (instance_constructors, null); - - if (default_static_constructor != null) - default_static_constructor.Define (this); - - if (methods != null) - DefineMembers (methods, defined_names); - - if (properties != null) - DefineMembers (properties, defined_names); - - if (events != null) - DefineMembers (events, defined_names); + DefineContainerMembers (instance_constructors); - if (indexers != null) { - DefineIndexers (); - } else - IndexerName = "Item"; - - if (operators != null){ - DefineMembers (operators, null); - - CheckPairedOperators (); - } + if (default_static_constructor != null) + default_static_constructor.Define (); - if (enums != null) - DefineMembers (enums, defined_names); - - if (delegates != null) - DefineMembers (delegates, defined_names); + DefineContainerMembers (properties); + DefineContainerMembers (events); + DefineContainerMembers (indexers); + DefineContainerMembers (methods); + DefineContainerMembers (operators); + DefineContainerMembers (enums); + DefineContainerMembers (delegates); if (CurrentType != null) { GenericType = CurrentType.ResolveType (ec); @@ -1278,24 +1528,65 @@ namespace Mono.CSharp { #if CACHE + if (!(this is ClassPart)) member_cache = new MemberCache (this); #endif - + if (parts != null) { + foreach (ClassPart part in parts) + part.member_cache = member_cache; + } + + if (iterators != null) { + foreach (Iterator iterator in iterators) { + if (iterator.DefineType () == null) + return false; + } + + foreach (Iterator iterator in iterators) { + if (!iterator.DefineMembers (this)) + return false; + } + } + return true; } - public override bool Define (TypeContainer container) + void ReportStructInitializedInstanceError () + { + string n = TypeBuilder.FullName; + + foreach (Field f in initialized_fields){ + Report.Error ( + 573, Location, + "`" + n + "." + f.Name + "': can not have " + + "instance field initializers in structs"); + } + } + + protected virtual void DefineContainerMembers (MemberCoreArrayList mcal) { - if (interface_order != null){ - foreach (Interface iface in interface_order) - if ((iface.ModFlags & Modifiers.NEW) == 0) - iface.Define (this); + if (mcal != null) + mcal.DefineContainerMembers (); + } + + public override bool Define () + { + if (parts != null) { + foreach (ClassPart part in parts) { + if (!part.Define ()) + return false; + } } return true; } + public MemberInfo FindMemberWithSameName (string name, bool ignore_methods) + { + return ParentContainer.MemberCache.FindMemberWithSameName (name, ignore_methods, null); + } + /// /// This function is based by a delegate to the FindMembers routine /// @@ -1311,15 +1602,9 @@ namespace Mono.CSharp { static MemberFilter accepting_filter; - /// - /// A member comparission method based on name only - /// - static IComparer mif_compare; - static TypeContainer () { accepting_filter = new MemberFilter (AlwaysAccept); - mif_compare = new MemberInfoCompare (); } public MethodInfo[] GetMethods () @@ -1382,9 +1667,9 @@ namespace Mono.CSharp { } } - MethodInfo[] methods = new MethodInfo [members.Count]; - members.CopyTo (methods, 0); - return methods; + MethodInfo[] retMethods = new MethodInfo [members.Count]; + members.CopyTo (retMethods, 0); + return retMethods; } /// @@ -1706,7 +1991,7 @@ namespace Mono.CSharp { if (interfaces != null) { int len = interfaces.Count; for (int i = 0; i < len; i++) { - Interface iface = (Interface) interfaces [i]; + TypeContainer iface = (TypeContainer) interfaces [i]; if ((iface.ModFlags & modflags) == 0) continue; @@ -1754,7 +2039,8 @@ namespace Mono.CSharp { // // Lookup members in parent if requested. // - if (((bf & BindingFlags.DeclaredOnly) == 0) && (TypeBuilder.BaseType != null)) { + if ((bf & BindingFlags.DeclaredOnly) == 0) { + if (TypeBuilder.BaseType != null) { MemberList list = FindMembers (TypeBuilder.BaseType, mt, bf, filter, criteria); if (list.Count > 0) { if (members == null) @@ -1763,6 +2049,8 @@ namespace Mono.CSharp { members.AddRange (list); } } + + } Timer.StopTimer (TimerType.TcFindMembers); @@ -1806,58 +2094,12 @@ namespace Mono.CSharp { { if (constants != null) foreach (Const con in constants) - con.Emit (this); + con.Emit (); return; } - /// - /// Emits the code, this step is performed after all - /// the types, enumerations, constructors - /// - public void Emit () + protected virtual void VerifyMembers (EmitContext ec) { - if (instance_constructors != null) - foreach (Constructor c in instance_constructors) - c.Emit (this); - - if (default_static_constructor != null) - default_static_constructor.Emit (this); - - if (methods != null) - foreach (Method m in methods) - m.Emit (this); - - if (operators != null) - foreach (Operator o in operators) - o.Emit (this); - - if (properties != null) - foreach (Property p in properties) - p.Emit (this); - - if (indexers != null){ - foreach (Indexer ix in indexers) - ix.Emit (this); - - CustomAttributeBuilder cb = EmitDefaultMemberAttr (); - TypeBuilder.SetCustomAttribute (cb); - } - - if (fields != null) - foreach (Field f in fields) - f.Emit (this); - - if (events != null){ - foreach (Event e in Events) - e.Emit (this); - } - - if (Pending != null) - if (Pending.VerifyPendingMethods ()) - return; - - Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes); - // // Check for internal or private fields that were never assigned // @@ -1868,9 +2110,7 @@ namespace Mono.CSharp { continue; if ((f.status & Field.Status.USED) == 0){ - Report.Warning ( - 169, f.Location, "Private field " + - MakeName (f.Name) + " is never used"); + Report.Warning (169, f.Location, "The private field '{0}' is never used", f.GetSignatureForError ()); continue; } @@ -1883,58 +2123,117 @@ namespace Mono.CSharp { if ((f.status & Field.Status.ASSIGNED) != 0) continue; - Report.Warning ( - 649, f.Location, - "Field " + MakeName (f.Name) + " is never assigned " + - " to and will always have its default value"); + Report.Warning (649, f.Location, "Field '{0}' is never assigned to, and will always have its default value '{1}'", f.GetSignatureForError (), ""); } } - if (events != null){ + if ((events != null) && (RootContext.WarningLevel >= 3)) { foreach (Event e in events){ if (e.status == 0) - Report.Warning (67, "The event " + MakeName (e.Name) + " is never used"); + Report.Warning (67, e.Location, "The event '{0}' is never used", e.GetSignatureForError ()); } } } - -// if (types != null) -// foreach (TypeContainer tc in types) -// tc.Emit (); } - - CustomAttributeBuilder EmitDefaultMemberAttr () + + /// + /// Emits the code, this step is performed after all + /// the types, enumerations, constructors + /// + public void EmitType () { - EmitContext ec = new EmitContext (this, Location, null, null, ModFlags); + if (OptAttributes != null) + OptAttributes.Emit (ec, this); + + Emit (); + + if (instance_constructors != null) { + if (TypeBuilder.IsSubclassOf (TypeManager.attribute_type) && RootContext.VerifyClsCompliance && IsClsCompliaceRequired (this)) { + bool has_compliant_args = false; + + foreach (Constructor c in instance_constructors) { + c.Emit (); + + if (has_compliant_args) + continue; - Expression ml = Expression.MemberLookup (ec, TypeManager.default_member_type, - ".ctor", MemberTypes.Constructor, - BindingFlags.Public | BindingFlags.Instance, - Location.Null); + has_compliant_args = c.HasCompliantArgs; + } + if (!has_compliant_args) + Report.Error (3015, Location, "'{0}' has no accessible constructors which use only CLS-compliant types", GetSignatureForError ()); + } else { + foreach (Constructor c in instance_constructors) + c.Emit (); + } + } + + if (default_static_constructor != null) + default_static_constructor.Emit (); - MethodGroupExpr mg = (MethodGroupExpr) ml; + if (methods != null) + foreach (Method m in methods) + m.Emit (); - MethodBase constructor = mg.Methods [0]; + if (operators != null) + foreach (Operator o in operators) + o.Emit (); - string [] vals = { IndexerName }; + if (properties != null) + foreach (Property p in properties) + p.Emit (); - CustomAttributeBuilder cb = null; - try { - cb = new CustomAttributeBuilder ((ConstructorInfo) constructor, vals); - } catch { - Report.Warning (-100, "Can not set the indexer default member attribute"); + if (indexers != null){ + indexers.Emit (); } + + if (fields != null) + foreach (Field f in fields) + f.Emit (); - return cb; - } + if (events != null){ + foreach (Event e in Events) + e.Emit (); + } + + if (delegates != null) { + foreach (Delegate d in Delegates) { + d.Emit (); + } + } + + if (enums != null) { + foreach (Enum e in enums) { + e.Emit (); + } + } + + if (parts != null) { + foreach (ClassPart part in parts) + part.EmitType (); + } + + if ((Pending != null) && !(this is ClassPart)) + if (Pending.VerifyPendingMethods ()) + return; + VerifyMembers (ec); + + if (iterators != null) + foreach (Iterator iterator in iterators) + iterator.EmitType (); + +// if (types != null) +// foreach (TypeContainer tc in types) +// tc.Emit (); + } + public override void CloseType () { - if (Created) + if ((caching_flags & Flags.CloseTypeCreated) != 0) return; - + try { - Created = true; + caching_flags |= Flags.CloseTypeCreated; TypeBuilder.CreateType (); } catch (TypeLoadException){ // @@ -1951,24 +2250,23 @@ namespace Mono.CSharp { foreach (Enum en in Enums) en.CloseType (); - if (interface_order != null){ - foreach (Interface iface in interface_order) - iface.CloseType (); - } - if (Types != null){ foreach (TypeContainer tc in Types) - if (tc is Struct) + if (tc.Kind == Kind.Struct) tc.CloseType (); foreach (TypeContainer tc in Types) - if (!(tc is Struct)) + if (tc.Kind != Kind.Struct) tc.CloseType (); } if (Delegates != null) foreach (Delegate d in Delegates) d.CloseType (); + + if (Iterators != null) + foreach (Iterator i in Iterators) + i.CloseType (); types = null; properties = null; @@ -1979,11 +2277,11 @@ namespace Mono.CSharp { initialized_static_fields = null; constants = null; interfaces = null; - interface_order = null; methods = null; events = null; indexers = null; operators = null; + iterators = null; ec = null; default_constructor = null; default_static_constructor = null; @@ -1994,38 +2292,12 @@ namespace Mono.CSharp { member_cache = null; } + // TODO: make it obsolete and use GetSignatureForError public string MakeName (string n) { return "`" + Name + "." + n + "'"; } - public void Warning_KeywordNewRequired (Location l, MemberInfo mi) - { - Report.Warning ( - 108, l, "The keyword new is required on " + - MakeName (mi.Name) + " because it hides `" + - mi.ReflectedType.Name + "." + mi.Name + "'"); - } - - public void Warning_KeywordNewNotRequired (Location l, MemberCore mc) - { - Report.Warning ( - 109, l, "The member " + MakeName (mc.Name) + " does not hide an " + - "inherited member, the keyword new is not required"); - } - - public void Error_EventCanOnlyOverrideEvent (Location l, MemberInfo mi) - { - Report.Error ( - 72, l, MakeName (mi.Name) + " : cannot override; `" + - mi.ReflectedType.Name + "." + mi.Name + "' is not an event"); - } - - public static int CheckMember (string name, MemberInfo mi, int ModFlags) - { - return 0; - } - // // Performs the validation on a Method's modifiers (properties have // the same properties). @@ -2049,7 +2321,7 @@ namespace Mono.CSharp { } } - if (this is Struct){ + if (Kind == Kind.Struct){ if ((flags & va) != 0){ Modifiers.Error_InvalidModifier (loc, "virtual or abstract"); ok = false; @@ -2110,27 +2382,83 @@ namespace Mono.CSharp { return ok; } - Hashtable builder_and_args; - - public bool RegisterMethod (MethodBuilder mb, InternalParameters ip, Type [] args) + public bool UserDefinedStaticConstructor { + get { + return default_static_constructor != null; + } + } + + protected override bool VerifyClsCompliance (DeclSpace ds) { - if (builder_and_args == null) - builder_and_args = new Hashtable (); + if (!base.VerifyClsCompliance (ds)) + return false; + + VerifyClsName (); + + // parent_container is null for System.Object + if (parent_container != null && !AttributeTester.IsClsCompliant (parent_container.Type)) { + Report.Error (3009, Location, "'{0}': base type '{1}' is not CLS-compliant", GetSignatureForError (), TypeManager.CSharpName (parent_container.Type)); + } return true; } + + /// + /// Checks whether container name is CLS Compliant + /// + void VerifyClsName () + { + Hashtable parent_members = parent_container == null ? + new Hashtable () : + parent_container.MemberCache.GetPublicMembers (); + Hashtable this_members = new Hashtable (); + + foreach (DictionaryEntry entry in defined_names) { + MemberCore mc = (MemberCore)entry.Value; + if (!mc.IsClsCompliaceRequired (this)) + continue; + + string name = (string)entry.Key; + string basename = name.Substring (name.LastIndexOf ('.') + 1); + + string lcase = basename.ToLower (System.Globalization.CultureInfo.InvariantCulture); + object found = parent_members [lcase]; + if (found == null) { + found = this_members [lcase]; + if (found == null) { + this_members.Add (lcase, mc); + continue; + } + } + + if ((mc.ModFlags & Modifiers.OVERRIDE) != 0) + continue; + + if (found is MemberInfo) { + if (basename == ((MemberInfo)found).Name) + continue; + Report.SymbolRelatedToPreviousError ((MemberInfo)found); + } else { + Report.SymbolRelatedToPreviousError ((MemberCore) found); + } + Report.Error (3005, mc.Location, "Identifier '{0}' differing only in case is not CLS-compliant", mc.GetSignatureForError ()); + } + } + + /// /// 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. /// - public bool VerifyImplements (Type interface_type, string full, string name, Location loc) + public virtual bool VerifyImplements (Type interface_type, string full, + string name, Location loc) { bool found = false; if (ifaces != null){ - foreach (TypeExpr t in ifaces){ - if (t.Type == interface_type){ + foreach (Type t in ifaces){ + if (t == interface_type){ found = true; break; } @@ -2145,6 +2473,18 @@ namespace Mono.CSharp { return true; } + protected override void VerifyObsoleteAttribute() + { + CheckUsageOfObsoleteAttribute (TypeBuilder.BaseType); + + if (ifaces == null) + return; + + foreach (Type iface in ifaces) { + CheckUsageOfObsoleteAttribute (iface); + } + } + // // IMemberContainer // @@ -2161,12 +2501,6 @@ namespace Mono.CSharp { } } - IMemberContainer IMemberContainer.Parent { - get { - return parent_container; - } - } - MemberCache IMemberContainer.MemberCache { get { return member_cache; @@ -2175,7 +2509,7 @@ namespace Mono.CSharp { bool IMemberContainer.IsInterface { get { - return this is Interface; + return Kind == Kind.Interface; } } @@ -2190,181 +2524,329 @@ namespace Mono.CSharp { return FindMembers (mt, new_bf, null, null); } - // - // Operator pair checking - // + public virtual IMemberContainer ParentContainer { + get { + return parent_container; + } + } + + } - class OperatorEntry { - public int flags; - public Type ret_type; - public Type type1, type2; - public Operator op; - public Operator.OpType ot; - - public OperatorEntry (int f, Operator o) - { - flags = f; + public class PartialContainer : TypeContainer { + + public readonly Namespace Namespace; + public readonly int OriginalModFlags; + public readonly int AllowedModifiers; + public readonly TypeAttributes DefaultTypeAttributes; + + static PartialContainer Create (NamespaceEntry ns, TypeContainer parent, + MemberName name, int mod_flags, Kind kind, + Location loc) + { + PartialContainer pc; + string full_name = name.GetName (true); + DeclSpace ds = (DeclSpace) RootContext.Tree.Decls [full_name]; + if (ds != null) { + pc = ds as PartialContainer; + + if (pc == null) { + Report.Error ( + 260, ds.Location, "Missing partial modifier " + + "on declaration of type `{0}'; another " + + "partial implementation of this type exists", + name); + + Report.LocationOfPreviousError (loc); + return null; + } + + if (pc.Kind != kind) { + Report.Error ( + 261, loc, "Partial declarations of `{0}' " + + "must be all classes, all structs or " + + "all interfaces", name); + return null; + } + + if (pc.OriginalModFlags != mod_flags) { + Report.Error ( + 262, loc, "Partial declarations of `{0}' " + + "have conflicting accessibility modifiers", + name); + return null; + } - ret_type = o.OperatorMethod.GetReturnType (); - Type [] pt = o.OperatorMethod.ParameterTypes; - type1 = pt [0]; - type2 = pt [1]; - op = o; - ot = o.OperatorType; + return pc; } - public override int GetHashCode () - { - return ret_type.GetHashCode (); + pc = new PartialContainer (ns, parent, name, mod_flags, kind, loc); + RootContext.Tree.RecordDecl (full_name, pc); + parent.AddType (pc); + pc.Register (); + return pc; + } + + public static ClassPart CreatePart (NamespaceEntry ns, TypeContainer parent, + MemberName name, int mod, Attributes attrs, + Kind kind, Location loc) + { + PartialContainer pc = Create (ns, parent, name, mod, kind, loc); + if (pc == null) { + // An error occured; create a dummy container, but don't + // register it. + pc = new PartialContainer (ns, parent, name, mod, kind, loc); } - public override bool Equals (object o) - { - OperatorEntry other = (OperatorEntry) o; + ClassPart part = new ClassPart (ns, pc, mod, attrs, kind, loc); + pc.AddPart (part); + return part; + } - if (other.ret_type != ret_type) - return false; - if (other.type1 != type1) - return false; - if (other.type2 != type2) - return false; - return true; + protected PartialContainer (NamespaceEntry ns, TypeContainer parent, + MemberName name, int mod, Kind kind, Location l) + : base (ns, parent, name, null, kind, l) + { + this.Namespace = ns.NS; + + switch (kind) { + case Kind.Class: + AllowedModifiers = Class.AllowedModifiers; + DefaultTypeAttributes = Class.DefaultTypeAttributes; + break; + + case Kind.Struct: + AllowedModifiers = Struct.AllowedModifiers; + DefaultTypeAttributes = Struct.DefaultTypeAttributes; + break; + + case Kind.Interface: + AllowedModifiers = Interface.AllowedModifiers; + DefaultTypeAttributes = Interface.DefaultTypeAttributes; + break; + + default: + throw new InvalidOperationException (); + } + + int accmods; + if (parent.Parent == null) + accmods = Modifiers.INTERNAL; + else + accmods = Modifiers.PRIVATE; + + this.ModFlags = Modifiers.Check (AllowedModifiers, mod, accmods, l); + this.OriginalModFlags = mod; + } + + public override void Register () + { + if (Kind == Kind.Interface) + Parent.AddInterface (this); + else if (Kind == Kind.Class || Kind == Kind.Struct) + Parent.AddClassOrStruct (this); + else + throw new InvalidOperationException (); + } + + public override PendingImplementation GetPendingImplementations () + { + return PendingImplementation.GetPendingImplementations (this); + } + + public ClassPart AddPart (NamespaceEntry ns, int mod, Attributes attrs, + Location l) + { + ClassPart part = new ClassPart (ns, this, mod, attrs, Kind, l); + AddPart (part); + return part; + } + + public override TypeAttributes TypeAttr { + get { + return base.TypeAttr | DefaultTypeAttributes; } } - - // - // 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 () + } + + public class ClassPart : TypeContainer, IMemberContainer { + public readonly PartialContainer PartialContainer; + public readonly bool IsPartial; + + public ClassPart (NamespaceEntry ns, PartialContainer parent, + int mod, Attributes attrs, Kind kind, Location l) + : base (ns, parent.Parent, parent.MemberName, attrs, kind, l) { - Hashtable pairs = new Hashtable (null, null); - Operator true_op = null; - Operator false_op = null; - bool has_equality_or_inequality = false; - - // Register all the operators we care about. - foreach (Operator op in operators){ - int reg = 0; - - switch (op.OperatorType){ - case Operator.OpType.Equality: - reg = 1; - has_equality_or_inequality = true; - break; - case Operator.OpType.Inequality: - reg = 2; - has_equality_or_inequality = true; - break; + this.PartialContainer = parent; + this.IsPartial = true; - case Operator.OpType.True: - true_op = op; - break; - case Operator.OpType.False: - false_op = op; - break; - - case Operator.OpType.GreaterThan: - reg = 1; break; - case Operator.OpType.LessThan: - reg = 2; break; - - case Operator.OpType.GreaterThanOrEqual: - reg = 1; break; - case Operator.OpType.LessThanOrEqual: - reg = 2; break; - } - if (reg == 0) - continue; + int accmods; + if (parent.Parent == null) + accmods = Modifiers.INTERNAL; + else + accmods = Modifiers.PRIVATE; + + this.ModFlags = Modifiers.Check ( + parent.AllowedModifiers, mod, accmods, l); + } + + public override void Register () + { + } + + public override PendingImplementation GetPendingImplementations () + { + return PartialContainer.Pending; + } + + public override bool VerifyImplements (Type interface_type, string full, + string name, Location loc) + { + return PartialContainer.VerifyImplements ( + interface_type, full, name, loc); + } - OperatorEntry oe = new OperatorEntry (reg, op); + public override IMemberContainer ParentContainer { + get { + return PartialContainer.ParentContainer; + } + } + } + + public abstract class ClassOrStruct : TypeContainer { + bool hasExplicitLayout = false; + + public ClassOrStruct (NamespaceEntry ns, TypeContainer parent, + MemberName name, Attributes attrs, Kind kind, + Location l) + : base (ns, parent, name, attrs, kind, l) + { + } - object o = pairs [oe]; - if (o == null) - pairs [oe] = oe; - else { - oe = (OperatorEntry) o; - oe.flags |= reg; + public override PendingImplementation GetPendingImplementations () + { + return PendingImplementation.GetPendingImplementations (this); + } + + protected override void VerifyMembers (EmitContext ec) + { + if (Fields != null) { + foreach (Field f in Fields) { + if ((f.ModFlags & Modifiers.STATIC) != 0) + continue; + if (hasExplicitLayout) { + if (f.OptAttributes == null + || !f.OptAttributes.Contains (TypeManager.field_offset_attribute_type, ec)) { + Report.Error (625, f.Location, + "Instance field of type marked with" + + " StructLayout(LayoutKind.Explicit) must have a" + + " FieldOffset attribute."); + } + } + else { + if (f.OptAttributes != null + && f.OptAttributes.Contains (TypeManager.field_offset_attribute_type, ec)) { + Report.Error (636, f.Location, + "The FieldOffset attribute can only be placed on members of " + + "types marked with the StructLayout(LayoutKind.Explicit)"); + } + } } } + base.VerifyMembers (ec); + } - if (true_op != null){ - if (false_op == null) - Report.Error (216, true_op.Location, "operator true requires a matching operator false"); - } else if (false_op != null) - Report.Error (216, false_op.Location, "operator false requires a matching operator true"); - - // - // Look for the mistakes. - // - foreach (DictionaryEntry de in pairs){ - OperatorEntry oe = (OperatorEntry) de.Key; + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + { + if (a.Type == TypeManager.struct_layout_attribute_type + && (LayoutKind) a.GetPositionalValue (0) == LayoutKind.Explicit) + hasExplicitLayout = true; + + base.ApplyAttributeBuilder (a, cb); + } + + public override void Register () + { + Parent.AddClassOrStruct (this); + } + } + + /// + /// Class handles static classes declaration + /// + public sealed class StaticClass: Class { + public StaticClass (NamespaceEntry ns, TypeContainer parent, MemberName name, int mod, + Attributes attrs, Location l) + : base (ns, parent, name, mod & ~Modifiers.STATIC, attrs, l) + { + if (RootContext.Version == LanguageVersion.ISO_1) { + Report.FeatureIsNotStandardized (l, "static classes"); + Environment.Exit (1); + } + } + + protected override void DefineContainerMembers (MemberCoreArrayList list) + { + if (list == null) + return; - if (oe.flags == 3) + foreach (MemberCore m in list) { + if (m is Operator) { + Report.Error (715, m.Location, "'{0}': static classes cannot contain user-defined operators", m.GetSignatureForError (this)); continue; + } - string s = ""; - switch (oe.ot){ - case Operator.OpType.Equality: - s = "!="; - break; - case Operator.OpType.Inequality: - s = "=="; - break; - case Operator.OpType.GreaterThan: - s = "<"; - break; - case Operator.OpType.LessThan: - s = ">"; - break; - case Operator.OpType.GreaterThanOrEqual: - s = "<="; - break; - case Operator.OpType.LessThanOrEqual: - s = ">="; - break; + if ((m.ModFlags & Modifiers.STATIC) != 0) + continue; + + if (m is Constructor) { + Report.Error (710, m.Location, "'{0}': Static classes cannot have instance constructors", GetSignatureForError ()); + continue; + } + + if (m is Destructor) { + Report.Error (711, m.Location, "'{0}': Static class cannot contain destructor", GetSignatureForError ()); + continue; } - Report.Error (216, oe.op.Location, - "The operator `" + oe.op + "' requires a matching operator `" + s + "' to also be defined"); + Report.Error (708, m.Location, "'{0}': cannot declare instance members in a static class", m.GetSignatureForError (this)); } - if ((has_equality_or_inequality) && (RootContext.WarningLevel >= 2)) { - MethodSignature equals_ms = new MethodSignature ( - "Equals", TypeManager.bool_type, new Type [] { TypeManager.object_type }); - MethodSignature hash_ms = new MethodSignature ( - "GetHashCode", TypeManager.int32_type, new Type [0]); + base.DefineContainerMembers (list); + } + + public override TypeBuilder DefineType() + { + TypeBuilder tb = base.DefineType (); + if (tb == null) + return null; - MemberList equals_ml = FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance | - BindingFlags.DeclaredOnly, MethodSignature.method_signature_filter, - equals_ms); - MemberList hash_ml = FindMembers (MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance | - BindingFlags.DeclaredOnly, MethodSignature.method_signature_filter, - hash_ms); + if ((ptype != null) && (ptype != TypeManager.object_type)) { + Report.Error ( + 713, Location, + "Static class '{0}' cannot derive from type '{1}'. " + + "Static classes must derive from object", + GetSignatureForError (), ptype); + return null; + } - bool equals_ok = false; - if ((equals_ml != null) && (equals_ml.Count == 1)) - equals_ok = equals_ml [0].DeclaringType == TypeBuilder; - bool hash_ok = false; - if ((hash_ml != null) && (hash_ml.Count == 1)) - hash_ok = hash_ml [0].DeclaringType == TypeBuilder; + if (ifaces != null) { + foreach (Type t in ifaces) + Report.SymbolRelatedToPreviousError (t); + Report.Error ( + 714, Location, + "'{0}': static classes cannot implement interfaces", + GetSignatureForError ()); + } + return tb; + } - if (!equals_ok) - Report.Warning (660, Location, "`" + Name + "' defines operator == or operator != but does " + - "not override Object.Equals (object o)"); - if (!hash_ok) - Report.Warning (661, Location, "`" + Name + "' defines operator == or operator != but does " + - "not override Object.GetHashCode ()"); + public override TypeAttributes TypeAttr { + get { + return base.TypeAttr | TypeAttributes.Abstract | TypeAttributes.Sealed; } } - } - public class Class : TypeContainer { + public class Class : ClassOrStruct { // // Modifiers allowed in a class declaration // @@ -2378,9 +2860,12 @@ namespace Mono.CSharp { Modifiers.SEALED | Modifiers.UNSAFE; - public Class (NamespaceEntry ns, TypeContainer parent, MemberName name, - int mod, Attributes attrs, Location l) - : base (ns, parent, name, attrs, l) + // Information in the case we are an attribute type + AttributeUsageAttribute attribute_usage; + + public Class (NamespaceEntry ns, TypeContainer parent, MemberName name, int mod, + Attributes attrs, Location l) + : base (ns, parent, name, attrs, Kind.Class, l) { int accmods; @@ -2390,20 +2875,54 @@ namespace Mono.CSharp { accmods = Modifiers.PRIVATE; this.ModFlags = Modifiers.Check (AllowedModifiers, mod, accmods, l); + if ((ModFlags & (Modifiers.ABSTRACT | Modifiers.SEALED)) == (Modifiers.ABSTRACT | Modifiers.SEALED)) { + Report.Error (502, Location, "'{0}' cannot be both abstract and sealed", GetSignatureForError ()); + } + + attribute_usage = new AttributeUsageAttribute (AttributeTargets.All); + } + + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Class; + } + } + + public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb) + { + if (a.UsageAttribute != null) { + if (ptype != TypeManager.attribute_type && + !ptype.IsSubclassOf (TypeManager.attribute_type) && + TypeBuilder.FullName != "System.Attribute") { + Report.Error (641, a.Location, "Attribute '{0}' is only valid on classes derived from System.Attribute", a.Name); + } + attribute_usage = a.UsageAttribute; + } + + base.ApplyAttributeBuilder (a, cb); + } + + public AttributeUsageAttribute AttributeUsage { + get { + return attribute_usage; + } } + public const TypeAttributes DefaultTypeAttributes = + TypeAttributes.AutoLayout | TypeAttributes.Class; + // // FIXME: How do we deal with the user specifying a different // layout? // public override TypeAttributes TypeAttr { get { - return base.TypeAttr | TypeAttributes.AutoLayout | TypeAttributes.Class; + return base.TypeAttr | DefaultTypeAttributes; } } } - public class Struct : TypeContainer { + public class Struct : ClassOrStruct { // // Modifiers allowed in a struct declaration // @@ -2417,7 +2936,7 @@ namespace Mono.CSharp { public Struct (NamespaceEntry ns, TypeContainer parent, MemberName name, int mod, Attributes attrs, Location l) - : base (ns, parent, name, attrs, l) + : base (ns, parent, name, attrs, Kind.Struct, l) { int accmods; @@ -2431,6 +2950,17 @@ namespace Mono.CSharp { this.ModFlags |= Modifiers.SEALED; } + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Struct; + } + } + + public const TypeAttributes DefaultTypeAttributes = + TypeAttributes.SequentialLayout | + TypeAttributes.Sealed | + TypeAttributes.BeforeFieldInit; + // // FIXME: Allow the user to specify a different set of attributes // in some cases (Sealed for example is mandatory for a class, @@ -2438,10 +2968,7 @@ namespace Mono.CSharp { // public override TypeAttributes TypeAttr { get { - return base.TypeAttr | - TypeAttributes.SequentialLayout | - TypeAttributes.Sealed | - TypeAttributes.BeforeFieldInit; + return base.TypeAttr | DefaultTypeAttributes; } } } @@ -2463,7 +2990,7 @@ namespace Mono.CSharp { public Interface (NamespaceEntry ns, TypeContainer parent, MemberName name, int mod, Attributes attrs, Location l) - : base (ns, parent, name, attrs, l) + : base (ns, parent, name, attrs, Kind.Interface, l) { int accmods; @@ -2475,20 +3002,39 @@ namespace Mono.CSharp { this.ModFlags = Modifiers.Check (AllowedModifiers, mod, accmods, l); } - public override TypeAttributes TypeAttr { + public override void Register () + { + Parent.AddInterface (this); + } + + public override PendingImplementation GetPendingImplementations () + { + return null; + } + + public override AttributeTargets AttributeTargets { get { - return base.TypeAttr | + return AttributeTargets.Interface; + } + } + + public const TypeAttributes DefaultTypeAttributes = TypeAttributes.AutoLayout | TypeAttributes.Abstract | TypeAttributes.Interface; + + public override TypeAttributes TypeAttr { + get { + return base.TypeAttr | DefaultTypeAttributes; } } } public abstract class MethodCore : MemberBase { public readonly Parameters Parameters; + public readonly GenericMethod GenericMethod; + public readonly DeclSpace ds; protected Block block; - protected DeclSpace ds; // // Parameters, cached for semantic analysis. @@ -2496,22 +3042,31 @@ namespace Mono.CSharp { protected InternalParameters parameter_info; protected Type [] parameter_types; - // - // This is set from TypeContainer.DefineMembers if this method overrides something. - // - public bool OverridesSomething; - // Whether this is an operator method. public bool IsOperator; - public MethodCore (DeclSpace ds, Expression type, int mod, int allowed_mod, - bool is_interface, MemberName name, Attributes attrs, - Parameters parameters, Location loc) - : base (type, mod, allowed_mod, Modifiers.PRIVATE, name, attrs, loc) + // + // The method we're overriding if this is an override method. + // + protected MethodInfo parent_method = null; + + static string[] attribute_targets = new string [] { "method", "return" }; + + public MethodCore (TypeContainer parent, GenericMethod generic, + Expression type, int mod, int allowed_mod, bool is_iface, + MemberName name, Attributes attrs, Parameters parameters, + Location loc) + : base (parent, type, mod, allowed_mod, Modifiers.PRIVATE, name, + attrs, loc) { Parameters = parameters; - IsInterface = is_interface; - this.ds = ds; + IsInterface = is_iface; + this.GenericMethod = generic; + + if (generic != null) + ds = generic; + else + ds = parent; } // @@ -2540,30 +3095,257 @@ namespace Mono.CSharp { } } - protected virtual bool DoDefineParameters () + protected override bool CheckBase () { - // Check if arguments were correct - parameter_types = Parameters.GetParameterInfo (ds); - if ((parameter_types == null) || !CheckParameters (ds, parameter_types)) + if (!base.CheckBase ()) + return false; + + // Check whether arguments were correct. + if (!DoDefineParameters ()) return false; - parameter_info = new InternalParameters (ds, Parameters); - - Parameter array_param = Parameters.ArrayParameter; - if ((array_param != null) && - (!array_param.ParameterType.IsArray || - (array_param.ParameterType.GetArrayRank () != 1))) { - Report.Error (225, Location, "params parameter has to be a single dimensional array"); + if ((caching_flags & Flags.TestMethodDuplication) != 0 && !CheckForDuplications ()) return false; + + if (IsExplicitImpl) + return true; + + // Is null for System.Object while compiling corlib and base interfaces + if (Parent.ParentContainer == null) { + if ((RootContext.WarningLevel >= 4) && ((ModFlags & Modifiers.NEW) != 0)) { + Report.Warning (109, Location, "The member '{0}' does not hide an inherited member. The new keyword is not required", GetSignatureForError (Parent)); + } + return true; } - return true; - } + Type parent_ret_type = null; + parent_method = FindOutParentMethod (Parent, ref parent_ret_type); - void error_425 (Type old, Type t, string name) - { - Report.Error (425, Location, - "The constraints of type parameter `{0}' " + + // method is override + if (parent_method != null) { + + if (!CheckMethodAgainstBase ()) + return false; + + if ((ModFlags & Modifiers.NEW) == 0) { + if (!MemberType.Equals (TypeManager.TypeToCoreType (parent_ret_type))) { + Report.SymbolRelatedToPreviousError (parent_method); + Report.Error (508, Location, GetSignatureForError (Parent) + ": cannot " + + "change return type when overriding inherited member"); + return false; + } + } + + if (RootContext.WarningLevel > 2) { + if (Name == "Equals" && parameter_types.Length == 1 && parameter_types [0] == TypeManager.object_type) + Parent.Methods.HasEquals = true; + else if (Name == "GetHashCode" && parameter_types.Length == 0) + Parent.Methods.HasGetHashCode = true; + } + + ObsoleteAttribute oa = AttributeTester.GetMethodObsoleteAttribute (parent_method); + if (oa != null) { + EmitContext ec = new EmitContext (this.Parent, this.Parent, Location, null, null, ModFlags, false); + if (OptAttributes == null || !OptAttributes.Contains (TypeManager.obsolete_attribute_type, ec)) { + Report.SymbolRelatedToPreviousError (parent_method); + Report.Warning (672, 1, Location, "Member '{0}' overrides obsolete member. Add the Obsolete attribute to '{0}'", GetSignatureForError (Parent)); + } + } + return true; + } + + if ((ModFlags & Modifiers.OVERRIDE) != 0) { + Report.Error (115, Location, "'{0}': no suitable methods found to override", GetSignatureForError (Parent)); + return false; + } + + MemberInfo conflict_symbol = Parent.FindMemberWithSameName (Name, !(this is Property)); + if (conflict_symbol == null) { + if ((RootContext.WarningLevel >= 4) && ((ModFlags & Modifiers.NEW) != 0)) { + Report.Warning (109, Location, "The member '{0}' does not hide an inherited member. The new keyword is not required", GetSignatureForError (Parent)); + } + return true; + } + + if ((ModFlags & Modifiers.NEW) == 0) { + if (this is Method && conflict_symbol is MethodBase) + return true; + + Report.SymbolRelatedToPreviousError (conflict_symbol); + Report.Warning (108, Location, "The keyword new is required on '{0}' because it hides inherited member", GetSignatureForError (Parent)); + } + + return true; + } + + + // + // Performs various checks on the MethodInfo `mb' regarding the modifier flags + // that have been defined. + // + // `name' is the user visible name for reporting errors (this is used to + // provide the right name regarding method names and properties) + // + bool CheckMethodAgainstBase () + { + bool ok = true; + + // TODO: replace with GetSignatureForError + string name = parent_method.DeclaringType.Name + "." + parent_method.Name; + + if ((ModFlags & Modifiers.OVERRIDE) != 0){ + if (!(parent_method.IsAbstract || parent_method.IsVirtual)){ + Report.Error ( + 506, Location, Parent.MakeName (Name) + + ": cannot override inherited member `" + + name + "' because it is not " + + "virtual, abstract or override"); + ok = false; + } + + // Now we check that the overriden method is not final + + if (parent_method.IsFinal) { + // This happens when implementing interface methods. + if (parent_method.IsHideBySig && parent_method.IsVirtual) { + Report.Error ( + 506, Location, Parent.MakeName (Name) + + ": cannot override inherited member `" + + name + "' because it is not " + + "virtual, abstract or override"); + } else + Report.Error (239, Location, Parent.MakeName (Name) + " : cannot " + + "override inherited member `" + name + + "' because it is sealed."); + ok = false; + } + // + // Check that the permissions are not being changed + // + MethodAttributes thisp = flags & MethodAttributes.MemberAccessMask; + MethodAttributes parentp = parent_method.Attributes & MethodAttributes.MemberAccessMask; + + // + // special case for "protected internal" + // + + if ((parentp & MethodAttributes.FamORAssem) == MethodAttributes.FamORAssem){ + // + // when overriding protected internal, the method can be declared + // protected internal only within the same assembly + // + + if ((thisp & MethodAttributes.FamORAssem) == MethodAttributes.FamORAssem){ + if (Parent.TypeBuilder.Assembly != parent_method.DeclaringType.Assembly){ + // + // assemblies differ - report an error + // + + Error_CannotChangeAccessModifiers (Parent, parent_method, name); + ok = false; + } else if (thisp != parentp) { + // + // same assembly, but other attributes differ - report an error + // + + Error_CannotChangeAccessModifiers (Parent, parent_method, name); + ok = false; + }; + } else if ((thisp & MethodAttributes.Family) != MethodAttributes.Family) { + // + // if it's not "protected internal", it must be "protected" + // + + Error_CannotChangeAccessModifiers (Parent, parent_method, name); + ok = false; + } else if (Parent.TypeBuilder.Assembly == parent_method.DeclaringType.Assembly) { + // + // protected within the same assembly - an error + // + Error_CannotChangeAccessModifiers (Parent, parent_method, name); + ok = false; + } else if ((thisp & ~(MethodAttributes.Family | MethodAttributes.FamORAssem)) != + (parentp & ~(MethodAttributes.Family | MethodAttributes.FamORAssem))) { + // + // protected ok, but other attributes differ - report an error + // + Error_CannotChangeAccessModifiers (Parent, parent_method, name); + ok = false; + } + } else { + if (thisp != parentp){ + Error_CannotChangeAccessModifiers (Parent, parent_method, name); + ok = false; + } + } + } + + if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0 && Name != "Finalize") { + ModFlags |= Modifiers.NEW; + Report.SymbolRelatedToPreviousError (parent_method); + if (!IsInterface && (parent_method.IsVirtual || parent_method.IsAbstract)) { + if (RootContext.WarningLevel >= 2) + Report.Warning (114, Location, "'{0}' hides inherited member '{1}'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword", GetSignatureForError (Parent), parent_method); + } else + Report.Warning (108, Location, "The keyword new is required on '{0}' because it hides inherited member", GetSignatureForError (Parent)); + } + + return ok; + } + + void Error_CannotChangeAccessModifiers (TypeContainer parent, MethodInfo parent_method, string name) + { + // + // FIXME: report the old/new permissions? + // + Report.Error ( + 507, Location, parent.MakeName (Name) + + ": can't change the access modifiers when overriding inherited " + + "member `" + name + "'"); + } + + protected static string Error722 { + get { + return "'{0}': static types cannot be used as return types"; + } + } + + /// + /// For custom member duplication search in a container + /// + protected abstract bool CheckForDuplications (); + + /// + /// Gets parent method and its return type + /// + protected abstract MethodInfo FindOutParentMethod (TypeContainer container, ref Type parent_ret_type); + + protected virtual bool DoDefineParameters () + { + // Check if arguments were correct + parameter_types = Parameters.GetParameterInfo (ds); + if ((parameter_types == null) || + !CheckParameters (ds, parameter_types)) + return false; + + TypeParameter[] tparam = ds.IsGeneric ? ds.TypeParameters : null; + parameter_info = new InternalParameters (ds, Parameters, tparam); + + Parameter array_param = Parameters.ArrayParameter; + if ((array_param != null) && + (!array_param.ParameterType.IsArray || + (array_param.ParameterType.GetArrayRank () != 1))) { + Report.Error (225, Location, "params parameter has to be a single dimensional array"); + return false; + } + + return true; + } + + void error_425 (Type old, Type t, string name) + { + Report.Error (425, Location, + "The constraints of type parameter `{0}' " + "of method `{1}' must match the constraints for " + "type parameter `{2}' of method `{3}'", TypeManager.CSharpName (old), Name, @@ -2594,8 +3376,19 @@ namespace Mono.CSharp { return false; } - Type[] oct = ogc.Types; - Type[] ct = gc.Types; + if (ogc.HasClassConstraint != gc.HasClassConstraint) { + error_425 (ot, t, name); + return false; + } + + if (ogc.HasClassConstraint && + !ogc.ClassConstraint.Equals (gc.ClassConstraint)) { + error_425 (ot, t, name); + return false; + } + + Type[] oct = ogc.InterfaceConstraints; + Type[] ct = gc.InterfaceConstraints; if (oct.Length != ct.Length) { error_425 (ot, t, name); @@ -2612,9 +3405,38 @@ namespace Mono.CSharp { return true; } - protected bool IsDuplicateImplementation (TypeContainer tc, MethodCore method) + public override string[] ValidAttributeTargets { + get { + return attribute_targets; + } + } + + protected override bool VerifyClsCompliance (DeclSpace ds) + { + if (!base.VerifyClsCompliance (ds)) { + if ((ModFlags & Modifiers.ABSTRACT) != 0 && IsExposedFromAssembly (ds) && ds.IsClsCompliaceRequired (ds)) { + Report.Error (3011, Location, "'{0}': only CLS-compliant members can be abstract", GetSignatureForError ()); + } + return false; + } + + if (Parameters.HasArglist) { + Report.Error (3000, Location, "Methods with variable arguments are not CLS-compliant"); + } + + if (!AttributeTester.IsClsCompliant (MemberType)) { + Report.Error (3002, Location, "Return type of '{0}' is not CLS-compliant", GetSignatureForError ()); + } + + AttributeTester.AreParametersCompliant (Parameters.FixedParameters, Location); + + return true; + } + + protected bool IsDuplicateImplementation (MethodCore method) { - if ((method == this) || (method.Name != Name)) + if ((method == this) || + (method.MemberName.GetTypeName () != MemberName.GetTypeName ())) return false; Type[] param_types = method.ParameterTypes; @@ -2624,167 +3446,161 @@ namespace Mono.CSharp { if (param_types.Length != ParameterTypes.Length) return false; + int type_params = 0; + if (GenericMethod != null) + type_params = GenericMethod.CountTypeParameters; + + int m_type_params = 0; + if (method.GenericMethod != null) + m_type_params = method.GenericMethod.CountTypeParameters; + + if (type_params != m_type_params) + return false; + bool equal = true; bool may_unify; - Type[] infered_types = new Type [param_types.Length]; + Type[] infered_types; + if (type_params > 0) + infered_types = new Type [type_params]; + else + infered_types = null; + may_unify = Invocation.InferTypeArguments ( param_types, ParameterTypes, ref infered_types); if (!may_unify) { - infered_types = new Type [param_types.Length]; + if (type_params > 0) + infered_types = new Type [type_params]; + else + infered_types = null; + may_unify = Invocation.InferTypeArguments ( ParameterTypes, param_types, ref infered_types); } for (int i = 0; i < param_types.Length; i++) { - Type a = param_types [i]; - Type b = ParameterTypes [i]; + if (param_types [i] != ParameterTypes [i]) + equal = false; + } - if (a != b) + // TODO: make operator compatible with MethodCore to avoid this + if (this is Operator && method is Operator) { + if (MemberType != method.MemberType) equal = false; } if (equal) { - Report.Error (111, Location, - "Class `{0}' already defines a member called " + - "`{1}' with the same parameter types", - tc.Name, Name); + // + // Try to report 663: method only differs on out/ref + // + ParameterData info = ParameterInfo; + ParameterData other_info = method.ParameterInfo; + for (int i = 0; i < info.Count; i++){ + if (info.ParameterModifier (i) != other_info.ParameterModifier (i)){ + Report.Error (663, Location, + "Overload method only differs " + + "in parameter modifier"); + return false; + } + } + + Report.SymbolRelatedToPreviousError (method); + Report.Error (111, Location, "Type '{0}' already defines a member called '{1}' with the same parameter types", Parent.Name, Name); return true; } else if (may_unify) { Report.Error (408, Location, "`{0}' cannot define overload members that " + "may unify for some type parameter substitutions", - tc.Name); + Parent.Name); return true; } return false; } - public CallingConventions GetCallingConvention (bool is_class) + protected override void VerifyObsoleteAttribute() { - CallingConventions cc = 0; - - cc = Parameters.GetCallingConvention (); + base.VerifyObsoleteAttribute (); - if (is_class) - if ((ModFlags & Modifiers.STATIC) == 0) - cc |= CallingConventions.HasThis; + if (parameter_types == null) + return; - // FIXME: How is `ExplicitThis' used in C#? - - return cc; + foreach (Type type in parameter_types) { + CheckUsageOfObsoleteAttribute (type); + } } + } - // - // The method's attributes are passed in because we need to extract - // the "return:" attribute from there to apply on the return type - // - static public void LabelParameters (EmitContext ec, - MethodBase builder, - Parameters parameters, - Attributes method_attrs, - Location loc) + public class SourceMethod : ISourceMethod + { + TypeContainer container; + MethodBase builder; + + protected SourceMethod (TypeContainer container, MethodBase builder, + ISourceFile file, Location start, Location end) { - // - // Define each type attribute (in/out/ref) and - // the argument names. - // - Parameter [] p = parameters.FixedParameters; - int i = 0; + this.container = container; + this.builder = builder; - MethodBuilder mb = null; - ConstructorBuilder cb = null; - - if (builder is MethodBuilder) - mb = (MethodBuilder) builder; - else - cb = (ConstructorBuilder) builder; + CodeGen.SymbolWriter.OpenMethod ( + file, this, start.Row, 0, end.Row, 0); + } - if (p != null){ - for (i = 0; i < p.Length; i++) { - ParameterBuilder pb; - ParameterAttributes par_attr = p [i].Attributes; - - if (mb == null) - pb = cb.DefineParameter ( - i + 1, par_attr, p [i].Name); - else - pb = mb.DefineParameter ( - i + 1, par_attr, p [i].Name); - - Attributes attr = p [i].OptAttributes; - if (attr != null){ - Attribute.ApplyAttributes (ec, pb, pb, attr); - - if (par_attr == ParameterAttributes.Out){ - if (attr.Contains (TypeManager.in_attribute_type)) - Report.Error (36, loc, - "Can not use [In] attribute on out parameter"); - } - } - } - } + public string Name { + get { return builder.Name; } + } - if (parameters.ArrayParameter != null){ - ParameterBuilder pb; - Parameter array_param = parameters.ArrayParameter; + public int NamespaceID { + get { return container.NamespaceEntry.SymbolFileID; } + } - if (mb == null) - pb = cb.DefineParameter ( - i + 1, array_param.Attributes, - array_param.Name); + public int Token { + get { + if (builder is MethodBuilder) + return ((MethodBuilder) builder).GetToken ().Token; + else if (builder is ConstructorBuilder) + return ((ConstructorBuilder) builder).GetToken ().Token; else - pb = mb.DefineParameter ( - i + 1, array_param.Attributes, - array_param.Name); - - CustomAttributeBuilder a = new CustomAttributeBuilder ( - TypeManager.cons_param_array_attribute, new object [0]); - - pb.SetCustomAttribute (a); + throw new NotSupportedException (); } + } - // - // And now for the return type attribute decoration - // - ParameterBuilder ret_pb; - Attributes ret_attrs = null; - - if (mb == null || method_attrs == null) - return; + public void CloseMethod () + { + if (CodeGen.SymbolWriter != null) + CodeGen.SymbolWriter.CloseMethod (); + } - foreach (AttributeSection asec in method_attrs.AttributeSections) { + public static SourceMethod Create (TypeContainer parent, + MethodBase builder, Block block) + { + if (CodeGen.SymbolWriter == null) + return null; + if (block == null) + return null; - if (asec.Target != "return") - continue; + Location start_loc = block.StartLocation; + if (Location.IsNull (start_loc)) + return null; - if (ret_attrs == null) - ret_attrs = new Attributes (asec); - else - ret_attrs.AddAttributeSection (asec); - } + Location end_loc = block.EndLocation; + if (Location.IsNull (end_loc)) + return null; - if (ret_attrs != null) { - try { - ret_pb = mb.DefineParameter (0, ParameterAttributes.None, ""); - Attribute.ApplyAttributes (ec, ret_pb, ret_pb, ret_attrs); + ISourceFile file = start_loc.SourceFile; + if (file == null) + return null; - } catch (ArgumentOutOfRangeException) { - Report.Warning ( - -24, loc, - ".NET SDK 1.0 does not permit setting custom attributes" + - " on the return type of a method"); - } - } + return new SourceMethod ( + parent, builder, file, start_loc, end_loc); } } - public class Method : MethodCore, IIteratorContainer { + public class Method : MethodCore, IIteratorContainer, IMethodData { public MethodBuilder MethodBuilder; public MethodData MethodData; - public readonly GenericMethod GenericMethod; + ReturnParameter return_attributes; /// /// Modifiers allowed in a class declaration @@ -2805,40 +3621,57 @@ namespace Mono.CSharp { Modifiers.EXTERN; const int AllowedInterfaceModifiers = - Modifiers.NEW; + Modifiers.NEW | Modifiers.UNSAFE; // // return_type can be "null" for VOID values. // - public Method (DeclSpace ds, Expression return_type, int mod, bool is_iface, + public Method (TypeContainer parent, GenericMethod generic, + Expression return_type, int mod, bool is_iface, MemberName name, Parameters parameters, Attributes attrs, Location l) - : base (ds, return_type, mod, + : base (parent, generic, return_type, mod, is_iface ? AllowedInterfaceModifiers : AllowedModifiers, is_iface, name, attrs, parameters, l) { } - // - // return_type can be "null" for VOID values. - // - public Method (GenericMethod generic, Expression return_type, int mod, - bool is_iface, MemberName name, Parameters parameters, - Attributes attrs, Location l) - : this ((DeclSpace) generic, return_type, mod, is_iface, name, - parameters, attrs, l) + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Method; + } + } + + public override string GetSignatureForError() { - GenericMethod = generic; + if (MethodBuilder == null) { + return GetSignatureForError (Parent); + } + return TypeManager.CSharpSignature (MethodBuilder); } - // - // Returns the `System.Type' for the ReturnType of this - // function. Provides a nice cache. (used between semantic analysis - // and actual code generation - // - public Type GetReturnType () + /// + /// Use this method when MethodBuilder is null + /// + public override string GetSignatureForError (TypeContainer tc) { - return MemberType; + // TODO: get params from somewhere + if (parameter_info == null) + return base.GetSignatureForError (tc); + + // TODO: move to parameters + System.Text.StringBuilder args = new System.Text.StringBuilder (); + if (parameter_info.Parameters.FixedParameters != null) { + for (int i = 0; i < parameter_info.Parameters.FixedParameters.Length; ++i) { + Parameter p = parameter_info.Parameters.FixedParameters [i]; + args.Append (p.GetSignatureForError ()); + + if (i < parameter_info.Parameters.FixedParameters.Length - 1) + args.Append (','); + } + } + + return String.Concat (base.GetSignatureForError (tc), "(", args.ToString (), ")"); } void DuplicateEntryPoint (MethodInfo b, Location location) @@ -2850,14 +3683,6 @@ namespace Mono.CSharp { TypeManager.CSharpSignature(b) + "'"); } - void Report28 (MethodInfo b) - { - Report.Warning ( - 28, Location, - "`" + TypeManager.CSharpSignature(b) + - "' has the wrong signature to be an entry point"); - } - public bool IsEntryPoint (MethodBuilder b, InternalParameters pinfo) { if (b.ReturnType != TypeManager.void_type && @@ -2880,87 +3705,105 @@ namespace Mono.CSharp { return false; } - // - // Checks our base implementation if any - // - protected override bool CheckBase (TypeContainer container) + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) { - base.CheckBase (container); - - // Check whether arguments were correct. - if (!DoDefineParameters ()) - return false; + if (a.Target == AttributeTargets.ReturnValue) { + if (return_attributes == null) + return_attributes = new ReturnParameter (MethodBuilder, Location); - MethodSignature ms = new MethodSignature (Name, null, ParameterTypes); - if (IsOperator) { - flags |= MethodAttributes.SpecialName | MethodAttributes.HideBySig; - } else { - // - // Check in our class for dups - // - ArrayList ar = container.Methods; - if (ar != null) { - int arLen = ar.Count; - - for (int i = 0; i < arLen; i++) { - Method m = (Method) ar [i]; - if (IsDuplicateImplementation (container, m)) - return false; - } + return_attributes.ApplyAttributeBuilder (a, cb); + return; + } + + if (a.Type == TypeManager.methodimpl_attr_type && a.IsInternalCall) { + MethodBuilder.SetImplementationFlags (MethodImplAttributes.InternalCall | MethodImplAttributes.Runtime); + } + + if (a.Type == TypeManager.dllimport_type) { + const int extern_static = Modifiers.EXTERN | Modifiers.STATIC; + if ((ModFlags & extern_static) != extern_static) { + Report.Error (601, a.Location, "The DllImport attribute must be specified on a method marked `static' and `extern'"); } + + return; } + if (a.Type == TypeManager.conditional_attribute_type) { + if (IsOperator || IsExplicitImpl) { + Report.Error (577, Location, "Conditional not valid on '{0}' because it is a destructor, operator, or explicit interface implementation", GetSignatureForError ()); + return; + } - // - // Verify if the parent has a type with the same name, and then - // check whether we have to create a new slot for it or not. - // - Type ptype = container.TypeBuilder.BaseType; + if (ReturnType != TypeManager.void_type) { + Report.Error (578, Location, "Conditional not valid on '{0}' because its return new ErrorData ( type is not void", GetSignatureForError ()); + return; + } - // ptype is only null for System.Object while compiling corlib. - if (ptype != null) { - - // - // Explicit implementations do not have `parent' methods, however, - // the member cache stores them there. Without this check, we get - // an incorrect warning in corlib. - // - if (! IsExplicitImpl) { - parent_method = (MethodInfo)((IMemberContainer)container).Parent.MemberCache.FindMemberToOverride ( - container.TypeBuilder, Name, ParameterTypes, false); + if ((ModFlags & Modifiers.OVERRIDE) != 0) { + Report.Error (243, Location, "Conditional not valid on '{0}' because it is an override method", GetSignatureForError ()); + return; } - - if (parent_method != null) { - string name = parent_method.DeclaringType.Name + "." + - parent_method.Name; - if (!CheckMethodAgainstBase (container, flags, parent_method, name)) - return false; + if (IsInterface) { + Report.Error (582, Location, "Conditional not valid on interface members"); + return; + } - if ((ModFlags & Modifiers.NEW) == 0) { - Type parent_ret = TypeManager.TypeToCoreType ( - parent_method.ReturnType); + if (MethodData.IsImplementing) { + Report.Error (629, Location, "Conditional member '{0}' cannot implement interface member", GetSignatureForError ()); + return; + } - if (!parent_ret.Equals (MemberType)) { - Report.Error ( - 508, Location, container.MakeName (Name) + ": cannot " + - "change return type when overriding " + - "inherited member " + name); - return false; - } + for (int i = 0; i < parameter_info.Count; ++i) { + if ((parameter_info.ParameterModifier (i) & Parameter.Modifier.OUT) != 0) { + Report.Error (685, Location, "Conditional method '{0}' cannot have an out parameter", GetSignatureForError ()); + return; } - } else { - if (!OverridesSomething && ((ModFlags & Modifiers.NEW) != 0)) - WarningNotHiding (container); + } + } - if ((ModFlags & Modifiers.OVERRIDE) != 0){ - Report.Error (115, Location, - container.MakeName (Name) + - " no suitable methods found to override"); - } + MethodBuilder.SetCustomAttribute (cb); + } + + protected override bool CheckForDuplications () + { + ArrayList ar = Parent.Methods; + if (ar != null) { + int arLen = ar.Count; + + for (int i = 0; i < arLen; i++) { + Method m = (Method) ar [i]; + if (IsDuplicateImplementation (m)) + return false; + } + } + + ar = Parent.Properties; + if (ar != null) { + for (int i = 0; i < ar.Count; ++i) { + PropertyBase pb = (PropertyBase) ar [i]; + if (pb.AreAccessorsDuplicateImplementation (this)) + return false; + } + } + + ar = Parent.Indexers; + if (ar != null) { + for (int i = 0; i < ar.Count; ++i) { + PropertyBase pb = (PropertyBase) ar [i]; + if (pb.AreAccessorsDuplicateImplementation (this)) + return false; } - } else if ((ModFlags & Modifiers.NEW) != 0) - WarningNotHiding (container); + } + + ar = Parent.Events; + if (ar != null) { + for (int i = 0; i < ar.Count; ++i) { + Event ev = (Event) ar [i]; + if (ev.AreAccessorsDuplicateImplementation (this)) + return false; + } + } return true; } @@ -2968,47 +3811,46 @@ namespace Mono.CSharp { // // Creates the type // - public override bool Define (TypeContainer container) + public override bool Define () { - DeclSpace decl; + if (!DoDefineBase ()) + return false; + MethodBuilder mb = null; if (GenericMethod != null) { - mb = container.TypeBuilder.DefineGenericMethod (Name, flags); - if (!GenericMethod.Define (container, mb)) + string mname = MemberName.GetMethodName (); + mb = Parent.TypeBuilder.DefineGenericMethod (mname, flags); + if (!GenericMethod.Define (mb)) return false; - decl = GenericMethod; - } else - decl = container; + } - if (!DoDefine (decl, container)) + if (!DoDefine (ds)) return false; - if (!CheckBase (container)) + if (!CheckBase ()) return false; - CallingConventions cc = GetCallingConvention (container is Class); + if (IsOperator) + flags |= MethodAttributes.SpecialName | MethodAttributes.HideBySig; - MethodData = new MethodData (ds, this, null, MemberType, - ParameterTypes, ParameterInfo, cc, - OptAttributes, ModFlags, flags, true, - mb, GenericMethod); + MethodData = new MethodData (this, ParameterInfo, ModFlags, flags, + this, mb, GenericMethod); - if (!MethodData.Define (container)) + if (!MethodData.Define (Parent)) return false; // // Setup iterator if we are one // if ((ModFlags & Modifiers.METHOD_YIELDS) != 0){ - IteratorHandler ih = new IteratorHandler ( - Name, container, MemberType, - ParameterTypes, ParameterInfo, - ModFlags, Location); + Iterator iterator = new Iterator ( + Parent, Name, MemberType, ParameterTypes, + ParameterInfo, ModFlags, block, Location); - Block new_block = ih.Setup (block); - if (new_block == null) + if (!iterator.DefineIterator ()) return false; - block = new_block; + + block = iterator.Block; } MethodBuilder = MethodData.MethodBuilder; @@ -3019,10 +3861,10 @@ namespace Mono.CSharp { if (Name == "Main" && ((ModFlags & Modifiers.STATIC) != 0) && RootContext.NeedsEntryPoint && (RootContext.MainClass == null || - RootContext.MainClass == container.TypeBuilder.FullName)){ + RootContext.MainClass == Parent.TypeBuilder.FullName)){ if (IsEntryPoint (MethodBuilder, ParameterInfo)) { if (RootContext.EntryPoint == null) { - if (container.IsGeneric){ + if (Parent.IsGeneric){ Report.Error (-201, Location, "Entry point can not be defined in a generic class"); } @@ -3033,32 +3875,167 @@ namespace Mono.CSharp { DuplicateEntryPoint (RootContext.EntryPoint, RootContext.EntryPointLocation); DuplicateEntryPoint (MethodBuilder, Location); } - } else - Report28(MethodBuilder); + } else { + if (RootContext.WarningLevel >= 4) + Report.Warning (28, Location, "'{0}' has the wrong signature to be an entry point", TypeManager.CSharpSignature(MethodBuilder) ); + } + } + + if (MemberType.IsAbstract && MemberType.IsSealed) { + Report.Error (722, Location, Error722, TypeManager.CSharpName (MemberType)); + return false; + } + + return true; + } + + // + // Emits the code + // + public override void Emit () + { + MethodData.Emit (Parent, this); + base.Emit (); + Block = null; + MethodData = null; + } + + protected override MethodInfo FindOutParentMethod (TypeContainer container, ref Type parent_ret_type) + { + MethodInfo mi = (MethodInfo) container.ParentContainer.MemberCache.FindMemberToOverride ( + container.TypeBuilder, Name, ParameterTypes, false); + + if (mi == null) + return null; + + parent_ret_type = mi.ReturnType; + return mi; + } + + protected override bool VerifyClsCompliance(DeclSpace ds) + { + if (!base.VerifyClsCompliance (ds)) + return false; + + if (parameter_types.Length > 0) { + ArrayList al = (ArrayList)ds.MemberCache.Members [Name]; + if (al.Count > 1) + ds.MemberCache.VerifyClsParameterConflict (al, this, MethodBuilder); + } + + return true; + } + + + void IIteratorContainer.SetYields () + { + ModFlags |= Modifiers.METHOD_YIELDS; + } + + #region IMethodData Members + + public CallingConventions CallingConventions { + get { + CallingConventions cc = Parameters.GetCallingConvention (); + if (Parameters.HasArglist) + block.HasVarargs = true; + + if (!IsInterface) + if ((ModFlags & Modifiers.STATIC) == 0) + cc |= CallingConventions.HasThis; + + // FIXME: How is `ExplicitThis' used in C#? + + return cc; + } + } + + public Type ReturnType { + get { + return MemberType; + } + } + + public MemberName MethodName { + get { + return MemberName; + } + } + + public new Location Location { + get { + return base.Location; + } + } + + public EmitContext CreateEmitContext (TypeContainer tc, ILGenerator ig) + { + return new EmitContext ( + tc, ds, Location, ig, ReturnType, ModFlags, false); + } + + public ObsoleteAttribute GetObsoleteAttribute () + { + return GetObsoleteAttribute (ds); + } + + /// + /// Returns true if method has conditional attribute and the conditions is not defined (method is excluded). + /// + public bool IsExcluded (EmitContext ec) + { + if ((caching_flags & Flags.Excluded_Undetected) == 0) + return (caching_flags & Flags.Excluded) != 0; + + caching_flags &= ~Flags.Excluded_Undetected; + + if (parent_method == null) { + if (OptAttributes == null) + return false; + + Attribute[] attrs = OptAttributes.SearchMulti (TypeManager.conditional_attribute_type, ec); + + if (attrs == null) + return false; + + foreach (Attribute a in attrs) { + string condition = a.GetConditionalAttributeValue (ds); + if (RootContext.AllDefines.Contains (condition)) + return false; + } + + caching_flags |= Flags.Excluded; + return true; } - return true; - } + IMethodData md = TypeManager.GetMethod (parent_method); + if (md == null) { + if (AttributeTester.IsConditionalMethodExcluded (parent_method)) { + caching_flags |= Flags.Excluded; + return true; + } + return false; + } - // - // Emits the code - // - public void Emit (TypeContainer container) - { - MethodData.Emit (container, Block, this); - Block = null; - MethodData = null; + if (md.IsExcluded (ec)) { + caching_flags |= Flags.Excluded; + return true; + } + return false; } - void IIteratorContainer.SetYields () - { - ModFlags |= Modifiers.METHOD_YIELDS; + GenericMethod IMethodData.GenericMethod { + get { + return GenericMethod; + } } + + #endregion } public abstract class ConstructorInitializer { ArrayList argument_list; - ConstructorInfo parent_constructor; + protected ConstructorInfo parent_constructor; Parameters parameters; Location loc; @@ -3105,14 +4082,24 @@ namespace Mono.CSharp { t = ec.ContainerType; parent_constructor_group = Expression.MemberLookup ( - ec, t, null, t, ".ctor", 0, - MemberTypes.Constructor, + ec, t, ".ctor", MemberTypes.Constructor, BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly, loc); if (parent_constructor_group == null){ - Report.Error (1501, loc, - "Can not find a constructor for this argument list"); + parent_constructor_group = Expression.MemberLookup ( + ec, t, ".ctor", MemberTypes.Constructor, + BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly, + loc); + + if (parent_constructor_group != null) + Report.Error ( + 112, loc, "`{0}.{1}' is inaccessible due to " + + "its protection level", t.FullName, t.Name); + else + Report.Error ( + 1501, loc, "Can not find a constructor for " + + "this argument list"); return false; } @@ -3127,7 +4114,7 @@ namespace Mono.CSharp { } if (parent_constructor == caller_builder){ - Report.Error (515, String.Format ("Constructor `{0}' can not call itself", TypeManager.CSharpSignature (caller_builder))); + Report.Error (516, String.Format ("Constructor `{0}' can not call itself", TypeManager.CSharpSignature (caller_builder))); return false; } @@ -3144,6 +4131,66 @@ namespace Mono.CSharp { Invocation.EmitCall (ec, true, false, ec.GetThis (loc), parent_constructor, argument_list, loc); } } + + /// + /// Method search for base ctor. (We do not cache it). + /// + Constructor GetOverloadedConstructor (TypeContainer tc) + { + if (tc.InstanceConstructors == null) + return null; + + foreach (Constructor c in tc.InstanceConstructors) { + if (Arguments == null) { + if (c.ParameterTypes.Length == 0) + return c; + + continue; + } + + bool ok = true; + + int count = c.ParameterInfo.Count; + if ((count > 0) && + c.ParameterInfo.ParameterModifier (count - 1) == Parameter.Modifier.PARAMS) { + for (int i = 0; i < count-1; i++) + if (c.ParameterTypes [i] != ((Argument)Arguments [i]).Type) { + ok = false; + break; + } + } else { + if (c.ParameterTypes.Length != Arguments.Count) + continue; + + for (int i = 0; i < Arguments.Count; ++i) + if (c.ParameterTypes [i] != ((Argument)Arguments [i]).Type) { + ok = false; + break; + } + } + + if (!ok) + continue; + + return c; + } + + return null; + } + + //TODO: implement caching when it will be necessary + public virtual void CheckObsoleteAttribute (TypeContainer tc, Location loc) + { + Constructor ctor = GetOverloadedConstructor (tc); + if (ctor == null) + return; + + ObsoleteAttribute oa = ctor.GetObsoleteAttribute (tc); + if (oa == null) + return; + + AttributeTester.Report_ObsoleteMessage (oa, ctor.GetSignatureForError (), loc); + } } public class ConstructorBaseInitializer : ConstructorInitializer { @@ -3151,6 +4198,24 @@ namespace Mono.CSharp { base (argument_list, pars, l) { } + + public override void CheckObsoleteAttribute(TypeContainer tc, Location loc) { + if (parent_constructor == null) + return; + + TypeContainer type_ds = TypeManager.LookupTypeContainer (tc.TypeBuilder.BaseType); + if (type_ds == null) { + ObsoleteAttribute oa = AttributeTester.GetMemberObsoleteAttribute (parent_constructor); + + if (oa != null) + AttributeTester.Report_ObsoleteMessage (oa, TypeManager.CSharpSignature (parent_constructor), loc); + + return; + } + + base.CheckObsoleteAttribute (type_ds, loc); + } + } public class ConstructorThisInitializer : ConstructorInitializer { @@ -3160,7 +4225,7 @@ namespace Mono.CSharp { } } - public class Constructor : MethodCore { + public class Constructor : MethodCore, IMethodData { public ConstructorBuilder ConstructorBuilder; public ConstructorInitializer Initializer; @@ -3176,18 +4241,40 @@ namespace Mono.CSharp { Modifiers.EXTERN | Modifiers.PRIVATE; + bool has_compliant_args = false; // // The spec claims that static is not permitted, but // my very own code has static constructors. // - public Constructor (DeclSpace ds, string name, int mod, Parameters args, + public Constructor (TypeContainer ds, string name, int mod, Parameters args, ConstructorInitializer init, Location l) - : base (ds, null, mod, AllowedModifiers, false, + : base (ds, null, null, mod, AllowedModifiers, false, new MemberName (name), null, args, l) { Initializer = init; } + public override string GetSignatureForError() + { + if (ConstructorBuilder == null) + return GetSignatureForError (Parent); + + return TypeManager.CSharpSignature (ConstructorBuilder); + } + + public bool HasCompliantArgs { + get { + return has_compliant_args; + } + } + + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Constructor; + } + } + + // // Returns true if this is a default constructor // @@ -3204,45 +4291,64 @@ namespace Mono.CSharp { (Initializer.Arguments == null); } - protected override bool CheckBase (TypeContainer container) + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + { + ConstructorBuilder.SetCustomAttribute (cb); + } + + protected override bool CheckForDuplications () { - base.CheckBase (container); + ArrayList ar = Parent.InstanceConstructors; + if (ar != null) { + int arLen = ar.Count; + + for (int i = 0; i < arLen; i++) { + Constructor m = (Constructor) ar [i]; + if (IsDuplicateImplementation (m)) + return false; + } + } + return true; + } + protected override bool CheckBase () + { // Check whether arguments were correct. if (!DoDefineParameters ()) return false; + // TODO: skip the rest for generated ctor if ((ModFlags & Modifiers.STATIC) != 0) return true; - if (container is Struct && ParameterTypes.Length == 0) { + if (!CheckForDuplications ()) + return false; + + if (Parent.Kind == Kind.Struct) { + if (ParameterTypes.Length == 0) { Report.Error (568, Location, "Structs can not contain explicit parameterless " + "constructors"); return false; } - // - // Check in our class for dups - // - ArrayList ar = container.InstanceConstructors; - if (ar != null) { - int arLen = ar.Count; - - for (int i = 0; i < arLen; i++) { - Constructor m = (Constructor) ar [i]; - if (IsDuplicateImplementation (container, m)) + if ((ModFlags & Modifiers.PROTECTED) != 0) { + Report.Error (666, Location, "Protected member in struct declaration"); return false; } } + if ((RootContext.WarningLevel >= 4) && ((Parent.ModFlags & Modifiers.SEALED) != 0 && (ModFlags & Modifiers.PROTECTED) != 0)) { + Report.Warning (628, Location, "'{0}': new protected member declared in sealed class", GetSignatureForError (Parent)); + } + return true; } // // Creates the ConstructorBuilder // - public override bool Define (TypeContainer container) + public override bool Define () { MethodAttributes ca = (MethodAttributes.RTSpecialName | MethodAttributes.SpecialName); @@ -3268,15 +4374,18 @@ namespace Mono.CSharp { } // Check if arguments were correct. - if (!CheckBase (container)) + if (!CheckBase ()) return false; - ConstructorBuilder = container.TypeBuilder.DefineConstructor ( - ca, GetCallingConvention (container is Class), ParameterTypes); + ConstructorBuilder = Parent.TypeBuilder.DefineConstructor ( + ca, CallingConventions, + ParameterTypes); if ((ModFlags & Modifiers.UNSAFE) != 0) ConstructorBuilder.InitLocals = false; + TypeManager.AddMethod (ConstructorBuilder, this); + // // HACK because System.Reflection.Emit is lame // @@ -3288,10 +4397,9 @@ namespace Mono.CSharp { // // Emits the code // - public void Emit (TypeContainer container) + public override void Emit () { - ILGenerator ig = ConstructorBuilder.GetILGenerator (); - EmitContext ec = new EmitContext (container, Location, ig, null, ModFlags, true); + EmitContext ec = CreateEmitContext (null, null); // // extern methods have no bodies @@ -3313,7 +4421,7 @@ namespace Mono.CSharp { } if ((ModFlags & Modifiers.STATIC) == 0){ - if (container is Class && Initializer == null) + if (Parent.Kind == Kind.Class && Initializer == null) Initializer = new ConstructorBaseInitializer ( null, Parameters.EmptyReadOnlyParameters, Location); @@ -3328,25 +4436,15 @@ namespace Mono.CSharp { ec.IsStatic = false; } - MethodCore.LabelParameters (ec, ConstructorBuilder, - Parameters, OptAttributes, Location); + Parameters.LabelParameters (ec, ConstructorBuilder, Location); - SymbolWriter sw = CodeGen.SymbolWriter; - bool generate_debugging = false; - - if ((sw != null) && (block != null) && - !Location.IsNull (Location) && - !Location.IsNull (block.EndLocation) && - (Location.SymbolDocument != null)) { - sw.OpenMethod (container, ConstructorBuilder, Location, block.EndLocation); - - generate_debugging = true; - } + SourceMethod source = SourceMethod.Create ( + Parent, ConstructorBuilder, block); // // Classes can have base initializers and instance field initializers. // - if (container is Class){ + if (Parent.Kind == Kind.Class){ if ((ModFlags & Modifiers.STATIC) == 0){ // @@ -3354,45 +4452,158 @@ namespace Mono.CSharp { // do not emit field initializers, they are initialized in the other constructor // if (!(Initializer != null && Initializer is ConstructorThisInitializer)) - container.EmitFieldInitializers (ec); + Parent.EmitFieldInitializers (ec); } } - if (Initializer != null) + if (Initializer != null) { + Initializer.CheckObsoleteAttribute (Parent, Location); Initializer.Emit (ec); + } if ((ModFlags & Modifiers.STATIC) != 0) - container.EmitFieldInitializers (ec); + Parent.EmitFieldInitializers (ec); - Attribute.ApplyAttributes (ec, ConstructorBuilder, this, OptAttributes); + if (OptAttributes != null) + OptAttributes.Emit (ec, this); // If this is a non-static `struct' constructor and doesn't have any // initializer, it must initialize all of the struct's fields. - if ((container is Struct) && ((ModFlags & Modifiers.STATIC) == 0) && (Initializer == null)) - Block.AddThisVariable (container, Location); + if ((Parent.Kind == Kind.Struct) && + ((ModFlags & Modifiers.STATIC) == 0) && (Initializer == null)) + Block.AddThisVariable (Parent, Location); ec.EmitTopBlock (block, ParameterInfo, Location); - if (generate_debugging) - sw.CloseMethod (); + if (source != null) + source.CloseMethod (); + + base.Emit (); block = null; } + + // Is never override + protected override MethodInfo FindOutParentMethod (TypeContainer container, ref Type parent_ret_type) + { + return null; + } + + protected override bool VerifyClsCompliance (DeclSpace ds) + { + if (!base.VerifyClsCompliance (ds) || !IsExposedFromAssembly (ds)) { + return false; + } + + if (parameter_types.Length > 0) { + ArrayList al = (ArrayList)ds.MemberCache.Members [".ctor"]; + if (al.Count > 3) + ds.MemberCache.VerifyClsParameterConflict (al, this, ConstructorBuilder); + + if (ds.TypeBuilder.IsSubclassOf (TypeManager.attribute_type)) { + foreach (Type param in parameter_types) { + if (param.IsArray) { + return true; + } + } + } + } + has_compliant_args = true; + return true; + } + + #region IMethodData Members + + public System.Reflection.CallingConventions CallingConventions { + get { + CallingConventions cc = Parameters.GetCallingConvention (); + + if (Parent.Kind == Kind.Class) + if ((ModFlags & Modifiers.STATIC) == 0) + cc |= CallingConventions.HasThis; + + // FIXME: How is `ExplicitThis' used in C#? + + return cc; + } + } + + public new Location Location { + get { + return base.Location; + } + } + + public MemberName MethodName { + get { + return MemberName; + } + } + + public Type ReturnType { + get { + return MemberType; + } + } + + public EmitContext CreateEmitContext (TypeContainer tc, ILGenerator ig) + { + ILGenerator ig_ = ConstructorBuilder.GetILGenerator (); + return new EmitContext (Parent, Location, ig_, null, ModFlags, true); + } + + public ObsoleteAttribute GetObsoleteAttribute () + { + return null; + } + + public bool IsExcluded(EmitContext ec) + { + return false; + } + + GenericMethod IMethodData.GenericMethod { + get { + return null; + } + } + + #endregion + } + + /// + /// Interface for MethodData class. Holds links to parent members to avoid member duplication. + /// + public interface IMethodData + { + CallingConventions CallingConventions { get; } + Location Location { get; } + MemberName MethodName { get; } + Type[] ParameterTypes { get; } + Type ReturnType { get; } + GenericMethod GenericMethod { get; } + + Attributes OptAttributes { get; } + Block Block { get; } + + EmitContext CreateEmitContext (TypeContainer tc, ILGenerator ig); + ObsoleteAttribute GetObsoleteAttribute (); + string GetSignatureForError (TypeContainer tc); + bool IsExcluded (EmitContext ec); + bool IsClsCompliaceRequired (DeclSpace ds); } // // Encapsulates most of the Method's state // public class MethodData { + + readonly IMethodData method; + // // The return type of this method // - public readonly Type ReturnType; - public readonly Type[] ParameterTypes; public readonly GenericMethod GenericMethod; public readonly InternalParameters ParameterInfo; - public readonly CallingConventions CallingConventions; - public readonly Attributes OptAttributes; - public readonly Location Location; // // Are we implementing an interface ? @@ -3402,17 +4613,11 @@ namespace Mono.CSharp { // // Protected data. // - protected DeclSpace ds; protected MemberBase member; protected int modifiers; protected MethodAttributes flags; - protected bool is_method; - protected string accessor_name; protected Type declaring_type; - // - // It can either hold a string with the condition, or an arraylist of conditions. - object conditionals; EmitContext ec; MethodBuilder builder = null; @@ -3428,252 +4633,75 @@ namespace Mono.CSharp { } } - public MethodData (DeclSpace ds, MemberBase member, string name, Type return_type, - Type [] parameter_types, InternalParameters parameters, - CallingConventions cc, Attributes opt_attrs, - int modifiers, MethodAttributes flags, bool is_method) + public MethodData (MemberBase member, InternalParameters parameters, + int modifiers, MethodAttributes flags, IMethodData method) { - this.ds = ds; this.member = member; - this.accessor_name = name; - this.ReturnType = return_type; - this.ParameterTypes = parameter_types; this.ParameterInfo = parameters; - this.CallingConventions = cc; - this.OptAttributes = opt_attrs; this.modifiers = modifiers; this.flags = flags; - this.is_method = is_method; - this.Location = member.Location; - this.conditionals = null; - } - - public MethodData (DeclSpace ds, MemberBase member, string name, Type return_type, - Type [] parameter_types, InternalParameters parameters, - CallingConventions cc, Attributes opt_attrs, - int modifiers, MethodAttributes flags, bool is_method, - MethodBuilder builder, GenericMethod generic) - : this (ds, member, name, return_type, parameter_types, parameters, - cc, opt_attrs, modifiers, flags, is_method) - { - this.builder = builder; - this.GenericMethod = generic; - } - - // - // Attributes. - // - Attribute dllimport_attribute = null; - string obsolete = null; - bool obsolete_error = false; - - public virtual bool ApplyAttributes (Attributes opt_attrs, bool is_method) - { - if ((opt_attrs == null) || (opt_attrs.AttributeSections == null)) - return true; - - foreach (AttributeSection asec in opt_attrs.AttributeSections) { - if (asec.Attributes == null) - continue; - - foreach (Attribute a in asec.Attributes) { - if (a.Name == "Conditional") { - if (!ApplyConditionalAttribute (a)) - return false; - } else if (a.Name == "Obsolete") { - if (!ApplyObsoleteAttribute (a)) - return false; - } else if (a.Name.IndexOf ("DllImport") != -1) { - if (!is_method) { - a.Type = TypeManager.dllimport_type; - Attribute.Error_AttributeNotValidForElement (a, Location); - return false; - } - if (!ApplyDllImportAttribute (a)) - return false; - } - } - } - - return true; - } - - // - // Applies the `DllImport' attribute to the method. - // - protected virtual bool ApplyDllImportAttribute (Attribute a) - { - const int extern_static = Modifiers.EXTERN | Modifiers.STATIC; - if ((modifiers & extern_static) != extern_static) { - Report.Error (601, Location, - "The DllImport attribute must be specified on a method " + - "marked `static' and `extern'."); - return false; - } - - flags |= MethodAttributes.PinvokeImpl; - dllimport_attribute = a; - return true; - } - - // - // Applies the `Obsolete' attribute to the method. - // - protected virtual bool ApplyObsoleteAttribute (Attribute a) - { - if (obsolete != null) { - Report.Error (579, Location, "Duplicate `Obsolete' attribute"); - return false; - } - - obsolete = a.Obsolete_GetObsoleteMessage (out obsolete_error); - return obsolete != null; - } - - // - // Applies the `Conditional' attribute to the method. - // - protected virtual bool ApplyConditionalAttribute (Attribute a) - { - // The Conditional attribute is only valid on methods. - if (!is_method) { - Attribute.Error_AttributeNotValidForElement (a, Location); - return false; - } - string condition = a.Conditional_GetConditionName (); - - if (condition == null) - return false; - - if (ReturnType != TypeManager.void_type) { - Report.Error (578, Location, - "Conditional not valid on `" + member.Name + "' " + - "because its return type is not void"); - return false; - } - - if ((modifiers & Modifiers.OVERRIDE) != 0) { - Report.Error (243, Location, - "Conditional not valid on `" + member.Name + "' " + - "because it is an override method"); - return false; - } - - if (member.IsExplicitImpl) { - Report.Error (577, Location, - "Conditional not valid on `" + member.Name + "' " + - "because it is an explicit interface implementation"); - return false; - } - - if (IsImplementing) { - Report.Error (623, Location, - "Conditional not valid on `" + member.Name + "' " + - "because it is an interface method"); - return false; - } - - // - // The likelyhood that the conditional will be more than 1 is very slim - // - if (conditionals == null) - conditionals = condition; - else if (conditionals is string){ - string s = (string) conditionals; - conditionals = new ArrayList (); - ((ArrayList)conditionals).Add (s); - } else - ((ArrayList)conditionals).Add (condition); - - return true; + this.method = method; } - - // - // Checks whether this method should be ignored due to its Conditional attributes. - // - bool ShouldIgnore (Location loc) - { - // When we're overriding a virtual method, we implicitly inherit the - // Conditional attributes from our parent. - if (member.ParentMethod != null) { - TypeManager.MethodFlags flags = TypeManager.GetMethodFlags ( - member.ParentMethod, loc); - - if ((flags & TypeManager.MethodFlags.ShouldIgnore) != 0) - return true; - } - - if (conditionals != null){ - if (conditionals is string){ - if (RootContext.AllDefines [conditionals] == null) - return true; - } else { - foreach (string condition in (ArrayList) conditionals) - if (RootContext.AllDefines [condition] == null) - return true; - } - } - return false; + + public MethodData (MemberBase member, InternalParameters parameters, + int modifiers, MethodAttributes flags, + IMethodData method, MethodBuilder builder, + GenericMethod generic) + : this (member, parameters, modifiers, flags, method) + { + this.builder = builder; + this.GenericMethod = generic; } - // - // Returns the TypeManager.MethodFlags for this method. - // This emits an error 619 / warning 618 if the method is obsolete. - // In the former case, TypeManager.MethodFlags.IsObsoleteError is returned. - // - public virtual TypeManager.MethodFlags GetMethodFlags (Location loc) + static string RemoveArity (string name) { - TypeManager.MethodFlags flags = 0; + int start = 0; + StringBuilder sb = new StringBuilder (); + while (start < name.Length) { + int pos = name.IndexOf ('`', start); + if (pos < 0) { + sb.Append (name.Substring (start)); + break; + } - if (obsolete != null) { - if (obsolete_error) { - Report.Error (619, loc, "Method `" + member.Name + - "' is obsolete: `" + obsolete + "'"); - return TypeManager.MethodFlags.IsObsoleteError; - } else - Report.Warning (618, loc, "Method `" + member.Name + - "' is obsolete: `" + obsolete + "'"); + sb.Append (name.Substring (start, pos-start)); - flags |= TypeManager.MethodFlags.IsObsolete; - } + pos++; + while ((pos < name.Length) && Char.IsNumber (name [pos])) + pos++; - if (ShouldIgnore (loc)) - flags |= TypeManager.MethodFlags.ShouldIgnore; + start = pos; + } - return flags; + return sb.ToString (); } - public virtual bool Define (TypeContainer container) + public bool Define (TypeContainer container) { MethodInfo implementing = null; - string method_name, name, prefix; - - if (OptAttributes != null) - if (!ApplyAttributes (OptAttributes, is_method)) - return false; + string prefix; if (member.IsExplicitImpl) - prefix = member.InterfaceType.FullName + "."; + prefix = RemoveArity (member.InterfaceType.FullName) + "."; else prefix = ""; - if (accessor_name != null) - name = accessor_name + "_" + member.ShortName; - else - name = member.ShortName; - method_name = prefix + name; + string name = method.MethodName.Name; + string method_name = prefix + name; + + Type[] ParameterTypes = method.ParameterTypes; if (container.Pending != null){ if (member is Indexer) implementing = container.Pending.IsInterfaceIndexer ( - member.InterfaceType, ReturnType, ParameterTypes); + member.InterfaceType, method.ReturnType, ParameterTypes); else implementing = container.Pending.IsInterfaceMethod ( - member.InterfaceType, name, ReturnType, ParameterTypes); + member.InterfaceType, name, method.ReturnType, ParameterTypes); if (member.InterfaceType != null && implementing == null){ - Report.Error (539, Location, "'{0}' in explicit interface declaration is not an interface", method_name); + Report.Error (539, method.Location, "'{0}' in explicit interface declaration is not an interface", method_name); return false; } } @@ -3692,7 +4720,7 @@ namespace Mono.CSharp { // if (member.IsExplicitImpl){ if ((modifiers & (Modifiers.PUBLIC | Modifiers.ABSTRACT | Modifiers.VIRTUAL)) != 0){ - Modifiers.Error_InvalidModifier (Location, "public, virtual or abstract"); + Modifiers.Error_InvalidModifier (method.Location, "public, virtual or abstract"); implementing = null; } } else if ((flags & MethodAttributes.MemberAccessMask) != MethodAttributes.Public){ @@ -3718,7 +4746,7 @@ namespace Mono.CSharp { // if ((modifiers & Modifiers.STATIC) != 0){ implementing = null; - Modifiers.Error_InvalidModifier (Location, "static"); + Modifiers.Error_InvalidModifier (method.Location, "static"); } } @@ -3742,48 +4770,16 @@ namespace Mono.CSharp { if ((modifiers & (Modifiers.VIRTUAL | Modifiers.ABSTRACT | Modifiers.OVERRIDE)) == 0) flags |= MethodAttributes.Final; - // Get the method name from the explicit interface. - if (member.InterfaceType != null) { - name = implementing.Name; - method_name = prefix + name; - } - IsImplementing = true; } - ec = new EmitContext ( - container, ds, Location, null, ReturnType, modifiers, false); + EmitContext ec = method.CreateEmitContext (container, null); - // - // Create the MethodBuilder for the method - // - if ((flags & MethodAttributes.PinvokeImpl) != 0) { - if ((modifiers & Modifiers.STATIC) == 0) { - Report.Error (601, Location, - "The DllImport attribute must be specified on " + - "a method marked 'static' and 'extern'."); - return false; - } - builder = dllimport_attribute.DefinePInvokeMethod ( - ec, container.TypeBuilder, method_name, flags, - ReturnType, ParameterTypes); - } else if (builder == null) - builder = container.TypeBuilder.DefineMethod ( - method_name, flags, CallingConventions, - ReturnType, ParameterTypes); - else - builder.SetGenericMethodSignature ( - flags, CallingConventions, - ReturnType, ParameterTypes); + DefineMethodBuilder (ec, container, method_name, ParameterTypes); if (builder == null) return false; - if (GenericMethod != null) { - if (!GenericMethod.DefineType (ec, builder)) - return false; - } - if (container.CurrentType != null) declaring_type = container.CurrentType.ResolveType (ec); else @@ -3798,11 +4794,11 @@ namespace Mono.CSharp { // if (member is Indexer) { container.Pending.ImplementIndexer ( - member.InterfaceType, builder, ReturnType, - ParameterTypes, true); + member.InterfaceType, builder, method.ReturnType, + ParameterTypes, member.IsExplicitImpl); } else container.Pending.ImplementMethod ( - member.InterfaceType, name, ReturnType, + member.InterfaceType, name, method.ReturnType, ParameterTypes, member.IsExplicitImpl); if (member.IsExplicitImpl) @@ -3811,73 +4807,104 @@ namespace Mono.CSharp { } - if (!TypeManager.RegisterMethod (builder, ParameterInfo, ParameterTypes)) { - Report.Error (111, Location, - "Class `" + container.Name + - "' already contains a definition with the " + - "same return value and parameter types as the " + - "'get' method of property `" + member.Name + "'"); - return false; - } + TypeManager.RegisterMethod (builder, ParameterInfo, ParameterTypes); + TypeManager.AddMethod (builder, method); + + if (GenericMethod != null) { + bool is_override = member.IsExplicitImpl | + ((modifiers & Modifiers.OVERRIDE) != 0); + + is_override &= IsImplementing; - TypeManager.AddMethod (builder, this); + if (!GenericMethod.DefineType ( + ec, builder, implementing, is_override)) + return false; + } return true; } + /// + /// Create the MethodBuilder for the method + /// + void DefineMethodBuilder (EmitContext ec, TypeContainer container, string method_name, Type[] ParameterTypes) + { + const int extern_static = Modifiers.EXTERN | Modifiers.STATIC; + + if ((modifiers & extern_static) == extern_static) { + + if (method.OptAttributes != null) { + Attribute dllimport_attribute = method.OptAttributes.Search (TypeManager.dllimport_type, ec); + if (dllimport_attribute != null) { + flags |= MethodAttributes.PinvokeImpl; + builder = dllimport_attribute.DefinePInvokeMethod ( + ec, container.TypeBuilder, method_name, flags, + method.ReturnType, ParameterTypes); + + return; + } + } + + // for extern static method must be specified either DllImport attribute or MethodImplAttribute. + // We are more strict than Microsoft and report CS0626 like error + if (method.OptAttributes == null || + !method.OptAttributes.Contains (TypeManager.methodimpl_attr_type, ec)) { + Report.Error (626, method.Location, "Method, operator, or accessor '{0}' is marked external and has no attributes on it. Consider adding a DllImport attribute to specify the external implementation", method.GetSignatureForError (container)); + return; + } + } + + if (builder == null) + builder = container.TypeBuilder.DefineMethod ( + method_name, flags, method.CallingConventions, + method.ReturnType, ParameterTypes); + else + builder.SetGenericMethodSignature ( + flags, method.CallingConventions, + method.ReturnType, ParameterTypes); + } + // // Emits the code // - public virtual void Emit (TypeContainer container, Block block, object kind) + public void Emit (TypeContainer container, Attributable kind) { - ILGenerator ig; EmitContext ec; - if ((flags & MethodAttributes.PinvokeImpl) == 0) - ig = builder.GetILGenerator (); + ec = method.CreateEmitContext (container, builder.GetILGenerator ()); else - ig = null; + ec = method.CreateEmitContext (container, null); - ec = new EmitContext (container, ds, Location, ig, ReturnType, modifiers, false); + Location loc = method.Location; + Attributes OptAttributes = method.OptAttributes; if (OptAttributes != null) - Attribute.ApplyAttributes (ec, builder, kind, OptAttributes); + OptAttributes.Emit (ec, kind); if (member is MethodCore) - MethodCore.LabelParameters (ec, MethodBuilder, - ((MethodCore) member).Parameters, - OptAttributes, - Location); + ((MethodCore) member).Parameters.LabelParameters (ec, MethodBuilder, loc); - SymbolWriter sw = CodeGen.SymbolWriter; + Block block = method.Block; // // abstract or extern methods have no bodies // if ((modifiers & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0){ - if (block == null) { - if ((sw != null) && ((modifiers & Modifiers.EXTERN) != 0) && - !Location.IsNull (Location) && - (Location.SymbolDocument != null)) { - sw.OpenMethod (container, MethodBuilder, Location, Location); - sw.CloseMethod (); - } - + if (block == null) return; - } // // abstract or extern methods have no bodies. // if ((modifiers & Modifiers.ABSTRACT) != 0) Report.Error ( - 500, Location, "Abstract method `" + + 500, method.Location, "Abstract method `" + TypeManager.CSharpSignature (builder) + "' can not have a body"); if ((modifiers & Modifiers.EXTERN) != 0) Report.Error ( - 179, Location, "External method `" + + 179, method.Location, "External method `" + TypeManager.CSharpSignature (builder) + "' can not have a body"); @@ -3889,35 +4916,28 @@ namespace Mono.CSharp { // if (block == null) { Report.Error ( - 501, Location, "Method `" + + 501, method.Location, "Method `" + TypeManager.CSharpSignature (builder) + "' must declare a body since it is not marked " + "abstract or extern"); return; } + SourceMethod source = SourceMethod.Create ( + container, MethodBuilder, method.Block); + // // Handle destructors specially // // FIXME: This code generates buggy code // - if ((sw != null) && !Location.IsNull (Location) && - !Location.IsNull (block.EndLocation) && - (Location.SymbolDocument != null)) { - sw.OpenMethod (container, MethodBuilder, Location, block.EndLocation); - - if (member is Destructor) - EmitDestructor (ec, block); - else - ec.EmitTopBlock (block, ParameterInfo, Location); + if (member is Destructor) + EmitDestructor (ec, block); + else + ec.EmitTopBlock (block, ParameterInfo, loc); - sw.CloseMethod (); - } else { - if (member is Destructor) - EmitDestructor (ec, block); - else - ec.EmitTopBlock (block, ParameterInfo, Location); - } + if (source != null) + source.CloseMethod (); } void EmitDestructor (EmitContext ec, Block block) @@ -3931,7 +4951,7 @@ namespace Mono.CSharp { ig.BeginExceptionBlock (); ec.ReturnLabel = finish; ec.HasReturnLabel = true; - ec.EmitTopBlock (block, null, Location); + ec.EmitTopBlock (block, null, method.Location); // ig.MarkLabel (finish); ig.BeginFinallyBlock (); @@ -3939,7 +4959,7 @@ namespace Mono.CSharp { if (ec.ContainerType.BaseType != null) { Expression member_lookup = Expression.MemberLookup ( ec, ec.ContainerType.BaseType, null, ec.ContainerType.BaseType, - "Finalize", 0, MemberTypes.Method, Expression.AllBindingFlags, Location); + "Finalize", MemberTypes.Method, Expression.AllBindingFlags, method.Location); if (member_lookup != null){ MethodGroupExpr parent_destructor = ((MethodGroupExpr) member_lookup); @@ -3957,18 +4977,27 @@ namespace Mono.CSharp { public class Destructor : Method { - public Destructor (DeclSpace ds, Expression return_type, int mod, string name, + public Destructor (TypeContainer ds, Expression return_type, int mod, string name, Parameters parameters, Attributes attrs, Location l) - : base (ds, return_type, mod, false, new MemberName (name), + : base (ds, null, return_type, mod, false, new MemberName (name), parameters, attrs, l) { } + public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb) + { + if (a.Type == TypeManager.conditional_attribute_type) { + Report.Error (577, Location, "Conditional not valid on '{0}' because it is a destructor, operator, or explicit interface implementation", GetSignatureForError ()); + return; + } + + base.ApplyAttributeBuilder (a, cb); + } } abstract public class MemberBase : MemberCore { public Expression Type; - protected MethodAttributes flags; + public MethodAttributes flags; protected readonly int explicit_mod_flags; @@ -3991,7 +5020,7 @@ namespace Mono.CSharp { // // The name of the interface we are explicitly implementing // - public Expression ExplicitInterfaceName = null; + public MemberName ExplicitInterfaceName = null; // // Whether this is an interface member. @@ -4003,205 +5032,58 @@ namespace Mono.CSharp { // public Type InterfaceType = null; - // - // The method we're overriding if this is an override method. - // - protected MethodInfo parent_method = null; - public MethodInfo ParentMethod { - get { - return parent_method; - } - } - // // The constructor is only exposed to our children // - protected MemberBase (Expression type, int mod, int allowed_mod, int def_mod, - MemberName name, Attributes attrs, Location loc) - : base (name, attrs, loc) + protected MemberBase (TypeContainer parent, Expression type, int mod, + int allowed_mod, int def_mod, MemberName name, + Attributes attrs, Location loc) + : base (parent, name, attrs, loc) { explicit_mod_flags = mod; Type = type; ModFlags = Modifiers.Check (allowed_mod, mod, def_mod, loc); - } - - protected virtual bool CheckBase (TypeContainer container) - { - if ((container is Struct) || (RootContext.WarningLevel > 3)){ - if ((ModFlags & Modifiers.PROTECTED) != 0 && (container.ModFlags & Modifiers.SEALED) != 0){ - if (container is Struct){ - Report.Error (666, Location, "Protected member in struct declaration"); - return false; - } else - Report.Warning (628, Location, "Member " + container.MakeName (Name) + " protected in sealed class"); - } - } - return true; - } - - protected void WarningNotHiding (TypeContainer parent) - { - Report.Warning ( - 109, Location, - "The member " + parent.MakeName (Name) + " does not hide an " + - "inherited member. The keyword new is not required"); - - } - void Error_CannotChangeAccessModifiers (TypeContainer parent, MethodInfo parent_method, - string name) - { - // - // FIXME: report the old/new permissions? - // - Report.Error ( - 507, Location, parent.MakeName (Name) + - ": can't change the access modifiers when overriding inherited " + - "member `" + name + "'"); + // Check for explicit interface implementation + if (MemberName.Left != null) { + ExplicitInterfaceName = MemberName.Left; + ShortName = MemberName.Name; + IsExplicitImpl = true; + } else + ShortName = Name; } - protected abstract bool CheckGenericOverride (MethodInfo method, string name); - - // - // Performs various checks on the MethodInfo `mb' regarding the modifier flags - // that have been defined. - // - // `name' is the user visible name for reporting errors (this is used to - // provide the right name regarding method names and properties) - // - protected bool CheckMethodAgainstBase (TypeContainer parent, MethodAttributes my_attrs, - MethodInfo mb, string name) + protected virtual bool CheckBase () { - bool ok = true; - - if ((ModFlags & Modifiers.OVERRIDE) != 0){ - if (!(mb.IsAbstract || mb.IsVirtual)){ - Report.Error ( - 506, Location, parent.MakeName (Name) + - ": cannot override inherited member `" + - name + "' because it is not " + - "virtual, abstract or override"); - ok = false; - } - - // Now we check that the overriden method is not final - - if (mb.IsFinal) { - // This happens when implementing interface methods. - if (mb.IsHideBySig && mb.IsVirtual) { - Report.Error ( - 506, Location, parent.MakeName (Name) + - ": cannot override inherited member `" + - name + "' because it is not " + - "virtual, abstract or override"); - } else - Report.Error (239, Location, parent.MakeName (Name) + " : cannot " + - "override inherited member `" + name + - "' because it is sealed."); - ok = false; - } - - // - // Check that the constraints match when overriding a - // generic method. - // - - if (!CheckGenericOverride (mb, name)) - ok = false; - - // - // Check that the permissions are not being changed - // - MethodAttributes thisp = my_attrs & MethodAttributes.MemberAccessMask; - MethodAttributes parentp = mb.Attributes & MethodAttributes.MemberAccessMask; - - // - // special case for "protected internal" - // - - if ((parentp & MethodAttributes.FamORAssem) == MethodAttributes.FamORAssem){ - // - // when overriding protected internal, the method can be declared - // protected internal only within the same assembly - // - - if ((thisp & MethodAttributes.FamORAssem) == MethodAttributes.FamORAssem){ - if (parent.TypeBuilder.Assembly != mb.DeclaringType.Assembly){ - // - // assemblies differ - report an error - // - - Error_CannotChangeAccessModifiers (parent, mb, name); - ok = false; - } else if (thisp != parentp) { - // - // same assembly, but other attributes differ - report an error - // - - Error_CannotChangeAccessModifiers (parent, mb, name); - ok = false; - }; - } else if ((thisp & MethodAttributes.Family) != MethodAttributes.Family) { - // - // if it's not "protected internal", it must be "protected" - // - - Error_CannotChangeAccessModifiers (parent, mb, name); - ok = false; - } else if (parent.TypeBuilder.Assembly == mb.DeclaringType.Assembly) { - // - // protected within the same assembly - an error - // - Error_CannotChangeAccessModifiers (parent, mb, name); - ok = false; - } else if ((thisp & ~(MethodAttributes.Family | MethodAttributes.FamORAssem)) != - (parentp & ~(MethodAttributes.Family | MethodAttributes.FamORAssem))) { - // - // protected ok, but other attributes differ - report an error - // - Error_CannotChangeAccessModifiers (parent, mb, name); - ok = false; - } - } else { - if (thisp != parentp){ - Error_CannotChangeAccessModifiers (parent, mb, name); - ok = false; - } - } + if ((ModFlags & Modifiers.PROTECTED) != 0 && Parent.Kind == Kind.Struct) { + Report.Error (666, Location, "Protected member in struct declaration"); + return false; } - if (mb.IsVirtual || mb.IsAbstract){ - if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0){ - if (Name != "Finalize"){ - Report.Warning ( - 114, 2, Location, parent.MakeName (Name) + - " hides inherited member `" + name + - "'. To make the current member override that " + - "implementation, add the override keyword, " + - "otherwise use the new keyword"); - ModFlags |= Modifiers.NEW; - } - } - } else { - if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0){ - if (Name != "Finalize"){ - Report.Warning ( - 108, 1, Location, "The keyword new is required on " + - parent.MakeName (Name) + " because it hides " + - "inherited member `" + name + "'"); - ModFlags |= Modifiers.NEW; - } - } + if ((RootContext.WarningLevel >= 4) && + ((Parent.ModFlags & Modifiers.SEALED) != 0) && + ((ModFlags & Modifiers.PROTECTED) != 0) && + ((ModFlags & Modifiers.OVERRIDE) == 0) && (Name != "Finalize")) { + Report.Warning (628, Location, "'{0}': new protected member declared in sealed class", GetSignatureForError (Parent)); } - return ok; + return true; } + protected abstract bool CheckGenericOverride (MethodInfo method, string name); + protected virtual bool CheckParameters (DeclSpace ds, Type [] parameters) { bool error = false; foreach (Type partype in parameters){ + if (partype == TypeManager.void_type) { + Report.Error ( + 1547, Location, "Keyword 'void' cannot " + + "be used in this context"); + return false; + } + if (partype.IsPointer){ if (!UnsafeOK (ds)) error = true; @@ -4233,15 +5115,15 @@ namespace Mono.CSharp { return !error; } - protected virtual bool DoDefine (DeclSpace decl, TypeContainer container) + protected virtual bool DoDefineBase () { if (Name == null) - Name = "this"; + throw new InternalErrorException (); if (IsInterface) { ModFlags = Modifiers.PUBLIC | Modifiers.ABSTRACT | - Modifiers.VIRTUAL; + Modifiers.VIRTUAL | (ModFlags & Modifiers.UNSAFE) | (ModFlags & Modifiers.NEW); flags = MethodAttributes.Public | MethodAttributes.Abstract | @@ -4249,18 +5131,23 @@ namespace Mono.CSharp { MethodAttributes.NewSlot | MethodAttributes.Virtual; } else { - if (!container.MethodModifiersValid (ModFlags, Name, Location)) - return false; + if (!Parent.MethodModifiersValid (ModFlags, Name, Location)) + return false; - flags = Modifiers.MethodAttr (ModFlags); + flags = Modifiers.MethodAttr (ModFlags); } + return true; + } + + protected virtual bool DoDefine (DeclSpace decl) + { // Lookup Type, verify validity MemberType = decl.ResolveType (Type, false, Location); if (MemberType == null) return false; - if ((container.ModFlags & Modifiers.SEALED) != 0){ + if ((Parent.ModFlags & Modifiers.SEALED) != 0){ if ((ModFlags & (Modifiers.VIRTUAL|Modifiers.ABSTRACT)) != 0){ Report.Error (549, Location, "Virtual method can not be contained in sealed class"); return false; @@ -4268,7 +5155,7 @@ namespace Mono.CSharp { } // verify accessibility - if (!container.AsAccessible (MemberType, ModFlags)) { + if (!Parent.AsAccessible (MemberType, ModFlags)) { if (this is Property) Report.Error (53, Location, "Inconsistent accessibility: property type `" + @@ -4298,21 +5185,12 @@ namespace Mono.CSharp { return false; } - if (MemberType.IsPointer && !UnsafeOK (container)) + if (MemberType.IsPointer && !UnsafeOK (Parent)) return false; - - // - // Check for explicit interface implementation - // - if (MemberName.TypeName != null) { - ExplicitInterfaceName = MemberName.TypeName.GetTypeExpression (Location); - ShortName = MemberName.Name; - } else - ShortName = Name; - if (ExplicitInterfaceName != null) { - InterfaceType = container.ResolveType ( - ExplicitInterfaceName, false, Location); + if (IsExplicitImpl) { + InterfaceType = Parent.ResolveType ( + ExplicitInterfaceName.GetTypeExpression (Location), false, Location); if (InterfaceType == null) return false; @@ -4321,20 +5199,44 @@ namespace Mono.CSharp { return false; } - // Compute the full name that we need to export. - Name = InterfaceType.FullName + "." + ShortName; - - if (!container.VerifyImplements (InterfaceType, ShortName, Name, Location)) + if (!Parent.VerifyImplements (InterfaceType, ShortName, Name, Location)) return false; Modifiers.Check (Modifiers.AllowedExplicitImplFlags, explicit_mod_flags, 0, Location); - - IsExplicitImpl = true; - } else - IsExplicitImpl = false; + } return true; } + + /// + /// The name of the member can be changed during definition (see IndexerName attribute) + /// + protected virtual void UpdateMemberName () + { + MemberName.Name = ShortName; + } + + public override string GetSignatureForError (TypeContainer tc) + { + return String.Concat (tc.Name, '.', base.GetSignatureForError (tc)); + } + + protected override bool VerifyClsCompliance(DeclSpace ds) + { + if (base.VerifyClsCompliance (ds)) { + return true; + } + + if (IsInterface && HasClsCompliantAttribute && ds.IsClsCompliaceRequired (ds)) { + Report.Error (3010, Location, "'{0}': CLS-compliant interfaces must have only CLS-compliant members", GetSignatureForError ()); + } + return false; + } + + protected override void VerifyObsoleteAttribute() + { + CheckUsageOfObsoleteAttribute (MemberType); + } } // @@ -4348,14 +5250,45 @@ namespace Mono.CSharp { [Flags] public enum Status : byte { ASSIGNED = 1, USED = 2 } + static string[] attribute_targets = new string [] { "field" }; + + /// + /// Symbol with same name in parent class/struct + /// + public MemberInfo conflict_symbol; + // // The constructor is only exposed to our children // - protected FieldBase (Expression type, int mod, int allowed_mod, MemberName name, - object init, Attributes attrs, Location loc) - : base (type, mod, allowed_mod, Modifiers.PRIVATE, name, attrs, loc) + protected FieldBase (TypeContainer parent, Expression type, int mod, + int allowed_mod, MemberName name, object init, + Attributes attrs, Location loc) + : base (parent, type, mod, allowed_mod, Modifiers.PRIVATE, + name, attrs, loc) + { + this.init = init; + } + + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Field; + } + } + + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) { - this.init = init; + if (a.Type == TypeManager.marshal_as_attr_type) { + UnmanagedMarshal marshal = a.GetMarshal (); + if (marshal != null) { + FieldBuilder.SetMarshal (marshal); + return; + } + Report.Warning (-24, a.Location, "The Microsoft Runtime cannot set this marshal info. Please use the Mono runtime instead."); + return; + } + + + FieldBuilder.SetCustomAttribute (cb); } // @@ -4401,6 +5334,80 @@ namespace Mono.CSharp { return init_expr; } + protected override bool CheckBase () + { + if (!base.CheckBase ()) + return false; + + // TODO: Implement + if (IsInterface) + return true; + + conflict_symbol = Parent.FindMemberWithSameName (Name, false); + if (conflict_symbol == null) { + if ((RootContext.WarningLevel >= 4) && ((ModFlags & Modifiers.NEW) != 0)) { + Report.Warning (109, Location, "The member '{0}' does not hide an inherited member. The new keyword is not required", GetSignatureForError (Parent)); + } + return true; + } + + if ((ModFlags & (Modifiers.NEW | Modifiers.OVERRIDE)) == 0) { + Report.SymbolRelatedToPreviousError (conflict_symbol); + Report.Warning (108, Location, "The keyword new is required on '{0}' because it hides inherited member", GetSignatureForError (Parent)); + } + + return true; + } + + protected override bool DoDefine (DeclSpace ds) + { + if (!base.DoDefine (ds)) + return false; + + if (MemberType == TypeManager.void_type) { + Report.Error (1547, Location, + "Keyword 'void' cannot be used in this context"); + return false; + } + + if (MemberType == TypeManager.arg_iterator_type || MemberType == TypeManager.typed_reference_type) { + Report.Error (610, Location, "Field or property cannot be of type '{0}'", TypeManager.CSharpName (MemberType)); + return false; + } + + return true; + } + + public override string GetSignatureForError () + { + if (FieldBuilder == null) { + return base.GetSignatureForError (Parent); + } + return TypeManager.GetFullNameSignature (FieldBuilder); + } + + public override string[] ValidAttributeTargets { + get { + return attribute_targets; + } + } + + protected override bool VerifyClsCompliance (DeclSpace ds) + { + if (!base.VerifyClsCompliance (ds)) + return false; + + if (FieldBuilder == null) { + return true; + } + + if (!AttributeTester.IsClsCompliant (FieldBuilder.FieldType)) { + Report.Error (3003, Location, "Type of '{0}' is not CLS-compliant", GetSignatureForError ()); + } + return true; + } + + public void SetAssigned () { status |= Status.ASSIGNED; @@ -4425,35 +5432,35 @@ namespace Mono.CSharp { Modifiers.UNSAFE | Modifiers.READONLY; - public Field (Expression type, int mod, string name, Object expr_or_array_init, - Attributes attrs, Location loc) - : base (type, mod, AllowedModifiers, new MemberName (name), + public Field (TypeContainer parent, Expression type, int mod, string name, + Object expr_or_array_init, Attributes attrs, Location loc) + : base (parent, type, mod, AllowedModifiers, new MemberName (name), expr_or_array_init, attrs, loc) { } - public override bool Define (TypeContainer container) + public override bool Define () { - Type t = container.ResolveType (Type, false, Location); - - if (t == null) + MemberType = Parent.ResolveType (Type, false, Location); + + if (MemberType == null) return false; - CheckBase (container); + CheckBase (); - if (!container.AsAccessible (t, ModFlags)) { + if (!Parent.AsAccessible (MemberType, ModFlags)) { Report.Error (52, Location, "Inconsistent accessibility: field type `" + - TypeManager.CSharpName (t) + "' is less " + + TypeManager.CSharpName (MemberType) + "' is less " + "accessible than field `" + Name + "'"); return false; } - if (t.IsPointer && !UnsafeOK (container)) + if (MemberType.IsPointer && !UnsafeOK (Parent)) return false; if (RootContext.WarningLevel > 1){ - Type ptype = container.TypeBuilder.BaseType; + Type ptype = Parent.TypeBuilder.BaseType; // ptype is only null for System.Object while compiling corlib. if (ptype != null){ @@ -4466,23 +5473,24 @@ namespace Mono.CSharp { } if ((ModFlags & Modifiers.VOLATILE) != 0){ - if (!t.IsClass){ - Type vt = t; + if (!MemberType.IsClass){ + Type vt = MemberType; if (TypeManager.IsEnumType (vt)) - vt = TypeManager.EnumToUnderlying (t); + vt = TypeManager.EnumToUnderlying (MemberType); if (!((vt == TypeManager.bool_type) || (vt == TypeManager.sbyte_type) || (vt == TypeManager.byte_type) || - (vt == TypeManager.short_type) || + (vt == TypeManager.short_type) || (vt == TypeManager.ushort_type) || - (vt == TypeManager.int32_type) || + (vt == TypeManager.int32_type) || (vt == TypeManager.uint32_type) || - (vt == TypeManager.char_type) || - (vt == TypeManager.float_type))){ + (vt == TypeManager.char_type) || + (vt == TypeManager.float_type) || + (!vt.IsValueType))){ Report.Error ( - 677, Location, container.MakeName (Name) + + 677, Location, Parent.MakeName (Name) + " A volatile field can not be of type `" + TypeManager.CSharpName (vt) + "'"); return false; @@ -4499,18 +5507,18 @@ namespace Mono.CSharp { FieldAttributes fa = Modifiers.FieldAttr (ModFlags); - if (container is Struct && + if (Parent.Kind == Kind.Struct && ((fa & FieldAttributes.Static) == 0) && - t == container.TypeBuilder && - !TypeManager.IsBuiltinType (t)){ - Report.Error (523, Location, "Struct member `" + container.Name + "." + Name + + MemberType == Parent.TypeBuilder && + !TypeManager.IsBuiltinType (MemberType)){ + Report.Error (523, Location, "Struct member `" + Parent.Name + "." + Name + "' causes a cycle in the structure layout"); return false; } try { - FieldBuilder = container.TypeBuilder.DefineField ( - Name, t, Modifiers.FieldAttr (ModFlags)); + FieldBuilder = Parent.TypeBuilder.DefineField ( + Name, MemberType, Modifiers.FieldAttr (ModFlags)); TypeManager.RegisterFieldBase (FieldBuilder, this); } @@ -4522,205 +5530,520 @@ namespace Mono.CSharp { return true; } - public void Emit (TypeContainer tc) - { - EmitContext ec = new EmitContext (tc, Location, null, - FieldBuilder.FieldType, ModFlags); + public override void Emit () + { + if (OptAttributes != null) { + EmitContext ec = new EmitContext ( + Parent, Location, null, FieldBuilder.FieldType, + ModFlags); + OptAttributes.Emit (ec, this); + } + + base.Emit (); + } + } + + // + // `set' and `get' accessors are represented with an Accessor. + // + public class Accessor { + // + // Null if the accessor is empty, or a Block if not + // + public Block Block; + public Attributes Attributes; + public Location Location; + + public Accessor (Block b, Attributes attrs, Location loc) + { + Block = b; + Attributes = attrs; + Location = loc; + } + } + + + // Ooouh Martin, templates are missing here. + // When it will be possible move here a lot of child code and template method type. + public abstract class AbstractPropertyEventMethod: MemberCore, IMethodData { + protected MethodData method_data; + protected Block block; + + // The accessor are created event if they are not wanted. + // But we need them because their names are reserved. + // Field says whether accessor will be emited or not + public readonly bool IsDummy; + + protected readonly string prefix; + + ReturnParameter return_attributes; + + public AbstractPropertyEventMethod (MemberBase member, string prefix) + : base (null, SetupName (prefix, member), null, member.Location) + { + this.prefix = prefix; + IsDummy = true; + } + + public AbstractPropertyEventMethod (MemberBase member, Accessor accessor, + string prefix) + : base (null, SetupName (prefix, member), + accessor.Attributes, accessor.Location) + { + this.prefix = prefix; + this.block = accessor.Block; + } + + static MemberName SetupName (string prefix, MemberBase member) + { + MemberName name = member.MemberName.Clone (); + name.Name = prefix + member.ShortName; + return name; + } + + public void UpdateName (MemberBase member) + { + MemberName.Name = prefix + member.ShortName; + } + + #region IMethodData Members + + public Block Block { + get { + return block; + } + + set { + block = value; + } + } + + public CallingConventions CallingConventions { + get { + return CallingConventions.Standard; + } + } + + public bool IsExcluded (EmitContext ec) + { + return false; + } + + GenericMethod IMethodData.GenericMethod { + get { + return null; + } + } + + public MemberName MethodName { + get { + return MemberName; + } + } + + public abstract ObsoleteAttribute GetObsoleteAttribute (); + public abstract Type[] ParameterTypes { get; } + public abstract Type ReturnType { get; } + public abstract EmitContext CreateEmitContext(TypeContainer tc, ILGenerator ig); + + #endregion + + public override void ApplyAttributeBuilder(Attribute a, CustomAttributeBuilder cb) + { + if (a.Type == TypeManager.cls_compliant_attribute_type || a.Type == TypeManager.obsolete_attribute_type || + a.Type == TypeManager.conditional_attribute_type) { + Report.Error (1667, a.Location, "'{0}' is not valid on property or event accessors. It is valid on '{1}' declarations only", TypeManager.CSharpName (a.Type), a.GetValidTargets ()); + return; + } + + if (a.Target == AttributeTargets.Method) { + method_data.MethodBuilder.SetCustomAttribute (cb); + return; + } + + if (a.Target == AttributeTargets.ReturnValue) { + if (return_attributes == null) + return_attributes = new ReturnParameter (method_data.MethodBuilder, Location); + + return_attributes.ApplyAttributeBuilder (a, cb); + return; + } + + ApplyToExtraTarget (a, cb); + } + + virtual protected void ApplyToExtraTarget (Attribute a, CustomAttributeBuilder cb) + { + System.Diagnostics.Debug.Fail ("You forgot to define special attribute target handling"); + } + + public override bool Define() + { + return false; + } + + public virtual void Emit (TypeContainer container) + { + method_data.Emit (container, this); + block = null; + } + + public override bool IsClsCompliaceRequired(DeclSpace ds) + { + return false; + } + + public bool IsDuplicateImplementation (MethodCore method) + { + if (Name != method.Name) + return false; + + Type[] param_types = method.ParameterTypes; + + if (param_types.Length != ParameterTypes.Length) + return false; + + for (int i = 0; i < param_types.Length; i++) + if (param_types [i] != ParameterTypes [i]) + return false; + + Report.SymbolRelatedToPreviousError (method); + Report.Error (111, Location, "Type '{0}' already defines a member called '{1}' with " + + "the same parameter types", Parent.Name, Name); + return true; + } + + public new Location Location { + get { + return base.Location; + } + } + + protected override void VerifyObsoleteAttribute() + { + } + + } + + // + // Properties and Indexers both generate PropertyBuilders, we use this to share + // their common bits. + // + abstract public class PropertyBase : MethodCore { + + public class GetMethod: PropertyMethod + { + static string[] attribute_targets = new string [] { "method", "return" }; + + public GetMethod (MethodCore method): + base (method, "get_") + { + } + + public GetMethod (MethodCore method, Accessor accessor): + base (method, accessor, "get_") + { + } + + public override MethodBuilder Define(TypeContainer container) + { + method_data = new MethodData (method, method.ParameterInfo, method.ModFlags, method.flags, this); + + if (!method_data.Define (container)) + return null; + + return method_data.MethodBuilder; + } + + public override string GetSignatureForError (TypeContainer tc) + { + return String.Concat (base.GetSignatureForError (tc), ".get"); + } + + public override Type ReturnType { + get { + return method.MemberType; + } + } + + public override string[] ValidAttributeTargets { + get { + return attribute_targets; + } + } + } + + public class SetMethod: PropertyMethod { + + static string[] attribute_targets = new string [] { "method", "param", "return" }; + ImplicitParameter param_attr; + + public SetMethod (MethodCore method): + base (method, "set_") + { + } + + public SetMethod (MethodCore method, Accessor accessor): + base (method, accessor, "set_") + { + } + + protected override void ApplyToExtraTarget(Attribute a, CustomAttributeBuilder cb) + { + if (a.Target == AttributeTargets.Parameter) { + if (param_attr == null) + param_attr = new ImplicitParameter (method_data.MethodBuilder); + + param_attr.ApplyAttributeBuilder (a, cb); + return; + } + + base.ApplyAttributeBuilder (a, cb); + } + + protected virtual InternalParameters GetParameterInfo (TypeContainer container) + { + Parameter [] parms = new Parameter [1]; + parms [0] = new Parameter (method.Type, "value", Parameter.Modifier.NONE, null); + return new InternalParameters ( + container, new Parameters (parms, null, method.Location)); + } + + public override MethodBuilder Define(TypeContainer container) + { + method_data = new MethodData (method, GetParameterInfo (container), method.ModFlags, method.flags, this); + + if (!method_data.Define (container)) + return null; + + return method_data.MethodBuilder; + } + + public override string GetSignatureForError (TypeContainer tc) + { + return String.Concat (base.GetSignatureForError (tc), ".set"); + } + + public override Type[] ParameterTypes { + get { + return new Type[] { method.MemberType }; + } + } + + public override Type ReturnType { + get { + return TypeManager.void_type; + } + } + + public override string[] ValidAttributeTargets { + get { + return attribute_targets; + } + } + } + + static string[] attribute_targets = new string [] { "property" }; + + public abstract class PropertyMethod: AbstractPropertyEventMethod { + protected readonly MethodCore method; + + public PropertyMethod (MethodCore method, string prefix) + : base (method, prefix) + { + this.method = method; + } + + public PropertyMethod (MethodCore method, Accessor accessor, string prefix) + : base (method, accessor, prefix) + { + this.method = method; + } + + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Method; + } + } + + public override bool IsClsCompliaceRequired(DeclSpace ds) + { + return method.IsClsCompliaceRequired (ds); + } + + public InternalParameters ParameterInfo + { + get { + return method_data.ParameterInfo; + } + } + + public abstract MethodBuilder Define (TypeContainer container); + + public override Type[] ParameterTypes { + get { + return TypeManager.NoTypes; + } + } + + public override EmitContext CreateEmitContext (TypeContainer tc, + ILGenerator ig) + { + return new EmitContext ( + tc, method.ds, method.Location, ig, ReturnType, + method.ModFlags, false); + } - Attribute.ApplyAttributes (ec, FieldBuilder, this, OptAttributes); - } - } + public override ObsoleteAttribute GetObsoleteAttribute () + { + return method.GetObsoleteAttribute (method.ds); + } - // - // `set' and `get' accessors are represented with an Accessor. - // - public class Accessor { - // - // Null if the accessor is empty, or a Block if not - // - public Block Block; - public Attributes OptAttributes; - - public Accessor (Block b, Attributes attrs) - { - Block = b; - OptAttributes = attrs; + public override string GetSignatureForError (TypeContainer tc) + { + return String.Concat (tc.Name, '.', method.Name); + } } - } - // - // Properties and Indexers both generate PropertyBuilders, we use this to share - // their common bits. - // - abstract public class PropertyBase : MethodCore { - public Accessor Get, Set; + public PropertyMethod Get, Set; public PropertyBuilder PropertyBuilder; public MethodBuilder GetBuilder, SetBuilder; - public MethodData GetData, SetData; protected EmitContext ec; - public PropertyBase (DeclSpace ds, Expression type, int mod_flags, + public PropertyBase (TypeContainer parent, Expression type, int mod_flags, int allowed_mod, bool is_iface, MemberName name, Parameters parameters, Attributes attrs, - Accessor get_block, Accessor set_block, Location loc) - : base (ds, type, mod_flags, allowed_mod, is_iface, name, + : base (parent, null, type, mod_flags, allowed_mod, is_iface, name, attrs, parameters, loc) { - Get = get_block; - Set = set_block; } - protected override bool DoDefine (DeclSpace decl, TypeContainer container) + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) { - if (!base.DoDefine (decl, container)) + PropertyBuilder.SetCustomAttribute (cb); + } + + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Property; + } + } + + protected override bool DoDefine (DeclSpace decl) + { + if (!base.DoDefine (decl)) + return false; + + if (MemberType == TypeManager.arg_iterator_type || MemberType == TypeManager.typed_reference_type) { + Report.Error (610, Location, "Field or property cannot be of type '{0}'", TypeManager.CSharpName (MemberType)); return false; + } - ec = new EmitContext (container, Location, null, MemberType, ModFlags); + if (MemberType.IsAbstract && MemberType.IsSealed) { + Report.Error (722, Location, Error722, TypeManager.CSharpName (MemberType)); + return false; + } + ec = new EmitContext (Parent, Location, null, MemberType, ModFlags); return true; } - // - // Checks our base implementation if any - // - protected override bool CheckBase (TypeContainer container) + public override string GetSignatureForError() { - base.CheckBase (container); - - // Check whether arguments were correct. - if (!DoDefineParameters ()) - return false; + if (PropertyBuilder == null) + return GetSignatureForError (Parent); - if (IsExplicitImpl) - return true; + return TypeManager.CSharpSignature (PropertyBuilder, false); + } - // - // Check in our class for dups - // - ArrayList ar = container.Properties; + + protected override bool CheckForDuplications () + { + ArrayList ar = Parent.Indexers; + if (ar != null) { + int arLen = ar.Count; + + for (int i = 0; i < arLen; i++) { + Indexer m = (Indexer) ar [i]; + if (IsDuplicateImplementation (m)) + return false; + } + } + + ar = Parent.Properties; if (ar != null) { int arLen = ar.Count; for (int i = 0; i < arLen; i++) { Property m = (Property) ar [i]; - if (IsDuplicateImplementation (container, m)) + if (IsDuplicateImplementation (m)) return false; } } - if (IsInterface) - return true; + return true; + } - string report_name; - MethodSignature ms, base_ms; - if (this is Indexer) { - string name, base_name; + protected override MethodInfo FindOutParentMethod (TypeContainer container, ref Type parent_ret_type) + { + PropertyInfo parent_property = container.ParentContainer.MemberCache.FindMemberToOverride ( + container.TypeBuilder, Name, ParameterTypes, true) as PropertyInfo; - report_name = "this"; - name = TypeManager.IndexerPropertyName (container.TypeBuilder); - ms = new MethodSignature (name, null, ParameterTypes); - base_name = TypeManager.IndexerPropertyName (container.TypeBuilder.BaseType); - base_ms = new MethodSignature (base_name, null, ParameterTypes); - } else { - report_name = Name; - ms = base_ms = new MethodSignature (Name, null, ParameterTypes); - } + if (parent_property == null) + return null; - // - // Verify if the parent has a type with the same name, and then - // check whether we have to create a new slot for it or not. - // - Type ptype = container.TypeBuilder.BaseType; + parent_ret_type = parent_property.PropertyType; - // ptype is only null for System.Object while compiling corlib. - if (ptype == null) { - if ((ModFlags & Modifiers.NEW) != 0) - WarningNotHiding (container); + MethodInfo temp_m; + temp_m = parent_property.GetGetMethod (true); + if (temp_m != null) + return temp_m; - return true; - } + System.Diagnostics.Debug.Assert (parent_property.GetSetMethod (true) != null, "Internal error property without get/set"); + return parent_property.GetSetMethod (true); + } - PropertyInfo parent_property = null; - + public override void Emit () + { // - // Explicit implementations do not have `parent' methods, however, - // the member cache stores them there. Without this check, we get - // an incorrect warning in corlib. + // The PropertyBuilder can be null for explicit implementations, in that + // case, we do not actually emit the ".property", so there is nowhere to + // put the attribute // - if (! IsExplicitImpl) { - parent_property = (PropertyInfo) ((IMemberContainer)container).Parent.MemberCache.FindMemberToOverride ( - container.TypeBuilder, Name, ParameterTypes, true); - } - - if (parent_property != null) { - string name = parent_property.DeclaringType.Name + "." + - parent_property.Name; + if (PropertyBuilder != null && OptAttributes != null) + OptAttributes.Emit (ec, this); - MethodInfo get, set, parent_method; - get = parent_property.GetGetMethod (true); - set = parent_property.GetSetMethod (true); - - if (get != null) - parent_method = get; - else if (set != null) - parent_method = set; - else - throw new Exception ("Internal error!"); + if (!Get.IsDummy) + Get.Emit (Parent); - if (!CheckMethodAgainstBase (container, flags, parent_method, name)) - return false; + if (!Set.IsDummy) + Set.Emit (Parent); - if ((ModFlags & Modifiers.NEW) == 0) { - Type parent_type = TypeManager.TypeToCoreType ( - parent_property.PropertyType); + base.Emit (); + } - if (parent_type != MemberType) { - Report.Error ( - 508, Location, container.MakeName (Name) + ": cannot " + - "change return type when overriding " + - "inherited member " + name); - return false; - } - } - } else { - if ((ModFlags & Modifiers.NEW) != 0) - WarningNotHiding (container); - - if ((ModFlags & Modifiers.OVERRIDE) != 0){ - if (this is Indexer) - Report.Error (115, Location, - container.MakeName (Name) + - " no suitable indexers found to override"); - else - Report.Error (115, Location, - container.MakeName (Name) + - " no suitable properties found to override"); - return false; - } - } - return true; + /// + /// Tests whether accessors are not in collision with some method (CS0111) + /// + public bool AreAccessorsDuplicateImplementation (MethodCore mc) + { + return Get.IsDuplicateImplementation (mc) || Set.IsDuplicateImplementation (mc); } - public void Emit (TypeContainer tc) + protected override void UpdateMemberName () { - // - // The PropertyBuilder can be null for explicit implementations, in that - // case, we do not actually emit the ".property", so there is nowhere to - // put the attribute - // - if (PropertyBuilder != null) - Attribute.ApplyAttributes (ec, PropertyBuilder, this, OptAttributes); + base.UpdateMemberName (); + + Get.UpdateName (this); + Set.UpdateName (this); + } - if (GetData != null) { - GetData.Emit (tc, Get.Block, Get); - Get.Block = null; - } - if (SetData != null) { - SetData.Emit (tc, Set.Block, Set); - Set.Block = null; + public override string[] ValidAttributeTargets { + get { + return attribute_targets; } } } @@ -4744,73 +6067,64 @@ namespace Mono.CSharp { const int AllowedInterfaceModifiers = Modifiers.NEW; - public Property (DeclSpace ds, Expression type, int mod_flags, bool is_iface, - MemberName name, Attributes attrs, Accessor get_block, - Accessor set_block, Location loc) - : base (ds, type, mod_flags, + public Property (TypeContainer parent, Expression type, int mod_flags, + bool is_iface, MemberName name, Attributes attrs, + Accessor get_block, Accessor set_block, Location loc) + : base (parent, type, mod_flags, is_iface ? AllowedInterfaceModifiers : AllowedModifiers, is_iface, name, Parameters.EmptyReadOnlyParameters, attrs, - get_block, set_block, loc) + loc) { + if (get_block == null) + Get = new GetMethod (this); + else + Get = new GetMethod (this, get_block); + + if (set_block == null) + Set = new SetMethod (this); + else + Set = new SetMethod (this, set_block); } - public override bool Define (TypeContainer container) + public override bool Define () { - if (!DoDefine (container, container)) + if (!DoDefineBase ()) return false; - if (!CheckBase (container)) + if (!DoDefine (Parent)) return false; - flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName; + if (!CheckBase ()) + return false; - if (Get != null) { - Type [] parameters = TypeManager.NoTypes; + flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName; - InternalParameters ip = new InternalParameters ( - container, Parameters.EmptyReadOnlyParameters); + if (!Get.IsDummy) { - GetData = new MethodData (container, this, "get", MemberType, - parameters, ip, CallingConventions.Standard, - Get.OptAttributes, ModFlags, flags, false); + GetBuilder = Get.Define (Parent); + if (GetBuilder == null) + return false; // // Setup iterator if we are one // if ((ModFlags & Modifiers.METHOD_YIELDS) != 0){ - IteratorHandler ih = new IteratorHandler ( - "get", container, MemberType, - parameters, ip, ModFlags, Location); + Iterator iterator = new Iterator ( + Parent, "get", MemberType, + TypeManager.NoTypes, Get.ParameterInfo, + ModFlags, Get.Block, Location); - Block new_block = ih.Setup (block); - if (new_block == null) + if (!iterator.DefineIterator ()) return false; - block = new_block; + Get.Block = iterator.Block; } - - if (!GetData.Define (container)) - return false; - - GetBuilder = GetData.MethodBuilder; } - if (Set != null) { - Type [] parameters = new Type [1]; - parameters [0] = MemberType; - - Parameter [] parms = new Parameter [1]; - parms [0] = new Parameter (Type, "value", Parameter.Modifier.NONE, null); - InternalParameters ip = new InternalParameters ( - container, new Parameters (parms, null, Location)); - - SetData = new MethodData (container, this, "set", TypeManager.void_type, - parameters, ip, CallingConventions.Standard, - Set.OptAttributes, ModFlags, flags, false); - - if (!SetData.Define (container)) + if (!Set.IsDummy) { + SetBuilder = Set.Define (Parent); + if (SetBuilder == null) return false; - SetBuilder = SetData.MethodBuilder; SetBuilder.DefineParameter (1, ParameterAttributes.None, "value"); } @@ -4822,26 +6136,16 @@ namespace Mono.CSharp { PropertyAttributes.SpecialName; if (!IsExplicitImpl){ - PropertyBuilder = container.TypeBuilder.DefineProperty ( + PropertyBuilder = Parent.TypeBuilder.DefineProperty ( Name, prop_attr, MemberType, null); - if (Get != null) + if (!Get.IsDummy) PropertyBuilder.SetGetMethod (GetBuilder); - if (Set != null) + if (!Set.IsDummy) PropertyBuilder.SetSetMethod (SetBuilder); - // - // HACK for the reasons exposed above - // - if (!TypeManager.RegisterProperty (PropertyBuilder, GetBuilder, SetBuilder)) { - Report.Error ( - 111, Location, - "Class `" + container.Name + - "' already contains a definition for the property `" + - Name + "'"); - return false; - } + TypeManager.RegisterProperty (PropertyBuilder, GetBuilder, SetBuilder); } return true; } @@ -4959,44 +6263,276 @@ namespace Mono.CSharp { return true; } - public override EventAttributes Attributes { - get { - return attributes; + public override EventAttributes Attributes { + get { + return attributes; + } + } + + public override string Name { + get { + return name; + } + } + + public override Type DeclaringType { + get { + return declaring_type; + } + } + + public override Type ReflectedType { + get { + return reflected_type; + } + } + + public Type EventType { + get { + return event_type; + } + } + + public void SetUsed () + { + if (my_event != null) + my_event.status = (FieldBase.Status.ASSIGNED | FieldBase.Status.USED); + } + } + + /// + /// For case when event is declared like property (with add and remove accessors). + /// + public class EventProperty: Event { + + static string[] attribute_targets = new string [] { "event", "property" }; + + public EventProperty (TypeContainer parent, Expression type, int mod_flags, + bool is_iface, MemberName name, Object init, + Attributes attrs, Accessor add, Accessor remove, + Location loc) + : base (parent, type, mod_flags, is_iface, name, init, attrs, loc) + { + Add = new AddDelegateMethod (this, add); + Remove = new RemoveDelegateMethod (this, remove); + } + + public override string[] ValidAttributeTargets { + get { + return attribute_targets; + } + } + } + + /// + /// Event is declared like field. + /// + public class EventField: Event { + + static string[] attribute_targets = new string [] { "event", "field", "method" }; + + public EventField (TypeContainer parent, Expression type, int mod_flags, + bool is_iface, MemberName name, Object init, + Attributes attrs, Location loc) + : base (parent, type, mod_flags, is_iface, name, init, attrs, loc) + { + Add = new AddDelegateMethod (this); + Remove = new RemoveDelegateMethod (this); + } + + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + { + if (a.Target == AttributeTargets.Field) { + FieldBuilder.SetCustomAttribute (cb); + return; + } + + if (a.Target == AttributeTargets.Method) { + AddBuilder.SetCustomAttribute (cb); + RemoveBuilder.SetCustomAttribute (cb); + return; + } + + base.ApplyAttributeBuilder (a, cb); + } + + public override string[] ValidAttributeTargets { + get { + return attribute_targets; + } + } + } + + public abstract class Event : FieldBase { + + protected sealed class AddDelegateMethod: DelegateMethod + { + + public AddDelegateMethod (Event method): + base (method, "add_") + { + } + + public AddDelegateMethod (Event method, Accessor accessor): + base (method, accessor, "add_") + { + } + + protected override MethodInfo DelegateMethodInfo { + get { + return TypeManager.delegate_combine_delegate_delegate; + } + } + + } + + protected sealed class RemoveDelegateMethod: DelegateMethod + { + public RemoveDelegateMethod (Event method): + base (method, "remove_") + { + } + + public RemoveDelegateMethod (Event method, Accessor accessor): + base (method, accessor, "remove_") + { + } + + protected override MethodInfo DelegateMethodInfo { + get { + return TypeManager.delegate_remove_delegate_delegate; + } + } + + } + + public abstract class DelegateMethod: AbstractPropertyEventMethod + { + protected readonly Event method; + ImplicitParameter param_attr; + + static string[] attribute_targets = new string [] { "method", "param", "return" }; + + public DelegateMethod (Event method, string prefix) + : base (method, prefix) + { + this.method = method; + } + + public DelegateMethod (Event method, Accessor accessor, string prefix) + : base (method, accessor, prefix) + { + this.method = method; + } + + protected override void ApplyToExtraTarget(Attribute a, CustomAttributeBuilder cb) + { + if (a.Target == AttributeTargets.Parameter) { + if (param_attr == null) + param_attr = new ImplicitParameter (method_data.MethodBuilder); + + param_attr.ApplyAttributeBuilder (a, cb); + return; + } + + base.ApplyAttributeBuilder (a, cb); + } + + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Method; + } + } + + public override bool IsClsCompliaceRequired(DeclSpace ds) + { + return method.IsClsCompliaceRequired (ds); + } + + public MethodBuilder Define (TypeContainer container, InternalParameters ip) + { + method_data = new MethodData (method, ip, method.ModFlags, + method.flags | MethodAttributes.HideBySig | MethodAttributes.SpecialName, this); + + if (!method_data.Define (container)) + return null; + + MethodBuilder mb = method_data.MethodBuilder; + mb.DefineParameter (1, ParameterAttributes.None, "value"); + return mb; + } + + + public override void Emit (TypeContainer tc) + { + if (block != null) { + base.Emit (tc); + return; + } + + ILGenerator ig = method_data.MethodBuilder.GetILGenerator (); + EmitContext ec = CreateEmitContext (tc, ig); + FieldInfo field_info = (FieldInfo)method.FieldBuilder; + + method_data.MethodBuilder.SetImplementationFlags (MethodImplAttributes.Synchronized); + if ((method.ModFlags & Modifiers.STATIC) != 0) { + ig.Emit (OpCodes.Ldsfld, field_info); + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Call, DelegateMethodInfo); + ig.Emit (OpCodes.Castclass, method.MemberType); + ig.Emit (OpCodes.Stsfld, field_info); + } else { + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Ldfld, field_info); + ig.Emit (OpCodes.Ldarg_1); + ig.Emit (OpCodes.Call, DelegateMethodInfo); + ig.Emit (OpCodes.Castclass, method.MemberType); + ig.Emit (OpCodes.Stfld, field_info); + } + ig.Emit (OpCodes.Ret); + } + + protected abstract MethodInfo DelegateMethodInfo { get; } + + public override Type[] ParameterTypes { + get { + return new Type[] { method.MemberType }; + } } - } - public override string Name { - get { - return name; + public override Type ReturnType { + get { + return TypeManager.void_type; + } } - } - public override Type DeclaringType { - get { - return declaring_type; + public override EmitContext CreateEmitContext (TypeContainer tc, + ILGenerator ig) + { + return new EmitContext ( + tc, method.Parent, Location, ig, ReturnType, + method.ModFlags, false); } - } - public override Type ReflectedType { - get { - return reflected_type; + public override string GetSignatureForError (TypeContainer tc) + { + return String.Concat (tc.Name, '.', method.Name); } - } - public Type EventType { - get { - return event_type; + public override ObsoleteAttribute GetObsoleteAttribute () + { + return method.GetObsoleteAttribute (method.Parent); + } + + public override string[] ValidAttributeTargets { + get { + return attribute_targets; + } } } - - public void SetUsed () - { - if (my_event != null) - my_event.status = (FieldBase.Status.ASSIGNED | FieldBase.Status.USED); - } - } - - public class Event : FieldBase { + + const int AllowedModifiers = Modifiers.NEW | Modifiers.PUBLIC | @@ -5013,87 +6549,88 @@ namespace Mono.CSharp { const int AllowedInterfaceModifiers = Modifiers.NEW; - public readonly Accessor Add; - public readonly Accessor Remove; + public DelegateMethod Add, Remove; public MyEventBuilder EventBuilder; - public MethodBuilder AddBuilder, RemoveBuilder; + MethodData AddData, RemoveData; - public Event (Expression type, int mod_flags, bool is_iface, MemberName name, - Object init, Attributes attrs, Accessor add, Accessor remove, + public Event (TypeContainer parent, Expression type, int mod_flags, + bool is_iface, MemberName name, Object init, Attributes attrs, Location loc) - : base (type, mod_flags, + : base (parent, type, mod_flags, is_iface ? AllowedInterfaceModifiers : AllowedModifiers, name, init, attrs, loc) { - Add = add; - Remove = remove; IsInterface = is_iface; } - public override bool Define (TypeContainer container) + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) + { + EventBuilder.SetCustomAttribute (cb); + } + + public bool AreAccessorsDuplicateImplementation (MethodCore mc) + { + return Add.IsDuplicateImplementation (mc) || Remove.IsDuplicateImplementation (mc); + } + + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Event; + } + } + + public override bool Define () { - EventAttributes e_attr = EventAttributes.RTSpecialName | EventAttributes.SpecialName; - MethodAttributes m_attr = MethodAttributes.HideBySig | MethodAttributes.SpecialName + EventAttributes e_attr; + e_attr = EventAttributes.None; ; - if (!DoDefine (container, container)) + if (!DoDefineBase ()) + return false; + + if (!DoDefine (Parent)) return false; if (init != null && ((ModFlags & Modifiers.ABSTRACT) != 0)){ - Report.Error (74, Location, "'" + container.Name + "." + Name + + Report.Error (74, Location, "'" + Parent.Name + "." + Name + "': abstract event can not have an initializer"); return false; } if (!TypeManager.IsDelegateType (MemberType)) { - Report.Error (66, Location, "'" + container.Name + "." + Name + + Report.Error (66, Location, "'" + Parent.Name + "." + Name + "' : event must be of a delegate type"); return false; } - Type [] parameter_types = new Type [1]; - parameter_types [0] = MemberType; - Parameter [] parms = new Parameter [1]; parms [0] = new Parameter (Type, "value", Parameter.Modifier.NONE, null); InternalParameters ip = new InternalParameters ( - container, new Parameters (parms, null, Location)); + Parent, new Parameters (parms, null, Location)); - if (!CheckBase (container)) + if (!CheckBase ()) return false; // // Now define the accessors // - AddData = new MethodData (container, this, "add", TypeManager.void_type, - parameter_types, ip, CallingConventions.Standard, - (Add != null) ? Add.OptAttributes : null, - ModFlags, flags | m_attr, false); - if (!AddData.Define (container)) + AddBuilder = Add.Define (Parent, ip); + if (AddBuilder == null) return false; - AddBuilder = AddData.MethodBuilder; - AddBuilder.DefineParameter (1, ParameterAttributes.None, "value"); - - RemoveData = new MethodData (container, this, "remove", TypeManager.void_type, - parameter_types, ip, CallingConventions.Standard, - (Remove != null) ? Remove.OptAttributes : null, - ModFlags, flags | m_attr, false); - - if (!RemoveData.Define (container)) + RemoveBuilder = Remove.Define (Parent, ip); + if (RemoveBuilder == null) return false; - RemoveBuilder = RemoveData.MethodBuilder; - RemoveBuilder.DefineParameter (1, ParameterAttributes.None, "value"); - if (!IsExplicitImpl){ EventBuilder = new MyEventBuilder (this, - container.TypeBuilder, Name, e_attr, MemberType); + Parent.TypeBuilder, Name, e_attr, MemberType); - if (Add == null && Remove == null) { - FieldBuilder = container.TypeBuilder.DefineField ( + if (Add.Block == null && Remove.Block == null && + !IsInterface) { + FieldBuilder = Parent.TypeBuilder.DefineField ( Name, MemberType, FieldAttributes.Private | ((ModFlags & Modifiers.STATIC) != 0 ? FieldAttributes.Static : 0)); TypeManager.RegisterPrivateFieldOfEvent ( @@ -5104,85 +6641,133 @@ namespace Mono.CSharp { EventBuilder.SetAddOnMethod (AddBuilder); EventBuilder.SetRemoveOnMethod (RemoveBuilder); - if (!TypeManager.RegisterEvent (EventBuilder, AddBuilder, RemoveBuilder)) { - Report.Error (111, Location, - "Class `" + container.Name + - "' already contains a definition for the event `" + - Name + "'"); - return false; - } + TypeManager.RegisterEvent (EventBuilder, AddBuilder, RemoveBuilder); } return true; } - void EmitDefaultMethod (EmitContext ec, bool is_add) + protected override bool CheckBase () + { + if (!base.CheckBase ()) + return false; + + if (conflict_symbol != null && (ModFlags & Modifiers.NEW) == 0) { + if (!(conflict_symbol is EventInfo)) { + Report.SymbolRelatedToPreviousError (conflict_symbol); + Report.Error (72, Location, "Event '{0}' can override only event", GetSignatureForError (Parent)); + return false; + } + } + + return true; + } + + public override void Emit () { - ILGenerator ig = ec.ig; - MethodInfo method = null; - - if (is_add) - method = TypeManager.delegate_combine_delegate_delegate; - else - method = TypeManager.delegate_remove_delegate_delegate; - - if ((ModFlags & Modifiers.STATIC) != 0) { - ig.Emit (OpCodes.Ldsfld, (FieldInfo) FieldBuilder); - ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Call, method); - ig.Emit (OpCodes.Castclass, MemberType); - ig.Emit (OpCodes.Stsfld, (FieldInfo) FieldBuilder); - } else { - ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Ldarg_0); - ig.Emit (OpCodes.Ldfld, (FieldInfo) FieldBuilder); - ig.Emit (OpCodes.Ldarg_1); - ig.Emit (OpCodes.Call, method); - ig.Emit (OpCodes.Castclass, MemberType); - ig.Emit (OpCodes.Stfld, (FieldInfo) FieldBuilder); + if (OptAttributes != null) { + EmitContext ec = new EmitContext ( + Parent, Location, null, MemberType, ModFlags); + OptAttributes.Emit (ec, this); } - ig.Emit (OpCodes.Ret); + + if (!IsInterface) { + Add.Emit (Parent); + Remove.Emit (Parent); + } + + base.Emit (); } - public void Emit (TypeContainer tc) + public override string GetSignatureForError () { - EmitContext ec; + if (EventBuilder == null) + return base.GetSignatureForError (Parent); + + return TypeManager.GetFullNameSignature (EventBuilder); + } + } - ec = new EmitContext (tc, Location, null, MemberType, ModFlags); - Attribute.ApplyAttributes (ec, EventBuilder, this, OptAttributes); + + public class Indexer : PropertyBase { - if (Add != null) { - AddData.Emit (tc, Add.Block, Add); - Add.Block = null; - } else { - ILGenerator ig = AddData.MethodBuilder.GetILGenerator (); - ec = new EmitContext (tc, Location, ig, TypeManager.void_type, ModFlags); - EmitDefaultMethod (ec, true); + class GetIndexerMethod: GetMethod + { + public GetIndexerMethod (MethodCore method): + base (method) + { } - if (Remove != null) { - RemoveData.Emit (tc, Remove.Block, Remove); - Remove.Block = null; - } else { - ILGenerator ig = RemoveData.MethodBuilder.GetILGenerator (); - ec = new EmitContext (tc, Location, ig, TypeManager.void_type, ModFlags); - EmitDefaultMethod (ec, false); + public GetIndexerMethod (MethodCore method, Accessor accessor): + base (method, accessor) + { + } + + public override Type[] ParameterTypes { + get { + return method.ParameterTypes; + } } } - - } - // - // FIXME: This does not handle: - // - // int INTERFACENAME [ args ] - // Does not - // - // Only: - // - // int this [ args ] - - public class Indexer : PropertyBase { + class SetIndexerMethod: SetMethod + { + readonly Parameters parameters; + + public SetIndexerMethod (MethodCore method): + base (method) + { + } + + public SetIndexerMethod (MethodCore method, Parameters parameters, Accessor accessor): + base (method, accessor) + { + this.parameters = parameters; + } + + public override Type[] ParameterTypes { + get { + int top = method.ParameterTypes.Length; + Type [] set_pars = new Type [top + 1]; + method.ParameterTypes.CopyTo (set_pars, 0); + set_pars [top] = method.MemberType; + return set_pars; + } + } + + protected override InternalParameters GetParameterInfo (TypeContainer container) + { + Parameter [] fixed_parms = parameters.FixedParameters; + + if (fixed_parms == null){ + throw new Exception ("We currently do not support only array arguments in an indexer at: " + method.Location); + // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG + // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG + // + // Here is the problem: the `value' parameter has + // to come *after* the array parameter in the declaration + // like this: + // X (object [] x, Type value) + // .param [0] + // + // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG + // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG + + } + + Parameter [] tmp = new Parameter [fixed_parms.Length + 1]; + + fixed_parms.CopyTo (tmp, 0); + tmp [fixed_parms.Length] = new Parameter ( + method.Type, "value", Parameter.Modifier.NONE, null); + + Parameters set_formal_params = new Parameters (tmp, null, method.Location); + + return new InternalParameters (container, set_formal_params); + } + + } + const int AllowedModifiers = Modifiers.NEW | @@ -5200,110 +6785,88 @@ namespace Mono.CSharp { const int AllowedInterfaceModifiers = Modifiers.NEW; - public string IndexerName; - public string InterfaceIndexerName; - // // Are we implementing an interface ? // - public Indexer (DeclSpace ds, Expression type, int mod_flags, bool is_iface, - MemberName name, Parameters parameters, Attributes attrs, + public Indexer (TypeContainer parent, Expression type, MemberName name, int mod, + bool is_iface, Parameters parameters, Attributes attrs, Accessor get_block, Accessor set_block, Location loc) - : base (ds, type, mod_flags, + : base (parent, type, mod, is_iface ? AllowedInterfaceModifiers : AllowedModifiers, - is_iface, name, parameters, attrs, get_block, set_block, loc) + is_iface, name, parameters, attrs, loc) { + if (get_block == null) + Get = new GetIndexerMethod (this); + else + Get = new GetIndexerMethod (this, get_block); + + if (set_block == null) + Set = new SetIndexerMethod (this); + else + Set = new SetIndexerMethod (this, parameters, set_block); } - public override bool Define (TypeContainer container) + public override bool Define () { PropertyAttributes prop_attr = PropertyAttributes.RTSpecialName | PropertyAttributes.SpecialName; - if (!DoDefine (container, container)) + if (!DoDefineBase ()) return false; - IndexerName = Attribute.ScanForIndexerName (ec, OptAttributes); - if (IndexerName == null) - IndexerName = "Item"; - else if (IsExplicitImpl) - Report.Error (592, Location, - "Attribute 'IndexerName' is not valid on this declaration " + - "type. It is valid on `property' declarations only."); + if (!DoDefine (Parent)) + return false; - ShortName = IndexerName; - if (IsExplicitImpl) { - InterfaceIndexerName = TypeManager.IndexerPropertyName (InterfaceType); - Name = InterfaceType.FullName + "." + IndexerName; - } else { - InterfaceIndexerName = IndexerName; - Name = ShortName; + if (OptAttributes != null) { + Attribute indexer_attr = OptAttributes.GetIndexerNameAttribute (ec); + if (indexer_attr != null) { + ShortName = indexer_attr.GetIndexerAttributeValue (ec); + + if (IsExplicitImpl) { + Report.Error (415, indexer_attr.Location, "The 'IndexerName' attribute is valid only on an indexer that is not an explicit interface member declaration"); + return false; + } + + if ((ModFlags & Modifiers.OVERRIDE) != 0) { + Report.Error (609, indexer_attr.Location, "Cannot set the 'IndexerName' attribute on an indexer marked override"); + return false; + } + + if (!Tokenizer.IsValidIdentifier (ShortName)) { + Report.Error (633, indexer_attr.Location, "The argument to the 'IndexerName' attribute must be a valid identifier"); + return false; + } + + UpdateMemberName (); + } } - if (!CheckNameCollision (container)) + if (InterfaceType != null) { + string parent_IndexerName = TypeManager.IndexerPropertyName (InterfaceType); + if (parent_IndexerName != Name) + ShortName = parent_IndexerName; + UpdateMemberName (); + } + + if (!Parent.AddToMemberContainer (this, true) || + !Parent.AddToMemberContainer (Get, true) || !Parent.AddToMemberContainer (Set, true)) return false; - if (!CheckBase (container)) + if (!CheckBase ()) return false; flags |= MethodAttributes.HideBySig | MethodAttributes.SpecialName; - if (Get != null){ - InternalParameters ip = new InternalParameters (container, Parameters); - - GetData = new MethodData (container, this, "get", MemberType, - ParameterTypes, ip, CallingConventions.Standard, - Get.OptAttributes, ModFlags, flags, false); - - if (!GetData.Define (container)) + if (!Get.IsDummy){ + GetBuilder = Get.Define (Parent); + if (GetBuilder == null) return false; - - GetBuilder = GetData.MethodBuilder; } - if (Set != null){ - int top = ParameterTypes.Length; - Type [] set_pars = new Type [top + 1]; - ParameterTypes.CopyTo (set_pars, 0); - set_pars [top] = MemberType; - - Parameter [] fixed_parms = Parameters.FixedParameters; - - if (fixed_parms == null){ - throw new Exception ("We currently do not support only array arguments in an indexer at: " + Location); - // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG - // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG - // - // Here is the problem: the `value' parameter has - // to come *after* the array parameter in the declaration - // like this: - // X (object [] x, Type value) - // .param [0] - // - // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG - // BUG BUG BUG BUG BUG BUG BUG BUG BUG BUG - - } - - Parameter [] tmp = new Parameter [fixed_parms.Length + 1]; - - - fixed_parms.CopyTo (tmp, 0); - tmp [fixed_parms.Length] = new Parameter ( - Type, "value", Parameter.Modifier.NONE, null); - - Parameters set_formal_params = new Parameters (tmp, null, Location); - - InternalParameters ip = new InternalParameters (container, set_formal_params); - - SetData = new MethodData (container, this, "set", TypeManager.void_type, - set_pars, ip, CallingConventions.Standard, - Set.OptAttributes, ModFlags, flags, false); - - if (!SetData.Define (container)) + if (!Set.IsDummy){ + SetBuilder = Set.Define (Parent); + if (SetBuilder == null) return false; - - SetBuilder = SetData.MethodBuilder; } // @@ -5311,19 +6874,24 @@ namespace Mono.CSharp { // Parameter [] p = Parameters.FixedParameters; if (p != null) { + if ((p [0].ModFlags & Parameter.Modifier.ISBYREF) != 0) { + Report.Error (631, Location, "ref and out are not valid in this context"); + return false; + } + int i; for (i = 0; i < p.Length; ++i) { - if (Get != null) + if (!Get.IsDummy) GetBuilder.DefineParameter ( i + 1, p [i].Attributes, p [i].Name); - if (Set != null) + if (!Set.IsDummy) SetBuilder.DefineParameter ( i + 1, p [i].Attributes, p [i].Name); } - if (Set != null) + if (!Set.IsDummy) SetBuilder.DefineParameter ( i + 1, ParameterAttributes.None, "value"); @@ -5342,13 +6910,13 @@ namespace Mono.CSharp { // explicit interface implementation. // if (!IsExplicitImpl) { - PropertyBuilder = container.TypeBuilder.DefineProperty ( - IndexerName, prop_attr, MemberType, ParameterTypes); + PropertyBuilder = Parent.TypeBuilder.DefineProperty ( + ShortName, prop_attr, MemberType, ParameterTypes); - if (GetData != null) + if (!Get.IsDummy) PropertyBuilder.SetGetMethod (GetBuilder); - if (SetData != null) + if (!Set.IsDummy) PropertyBuilder.SetSetMethod (SetBuilder); TypeManager.RegisterIndexer (PropertyBuilder, GetBuilder, SetBuilder, @@ -5358,52 +6926,21 @@ namespace Mono.CSharp { return true; } - bool CheckNameCollision (TypeContainer container) { - switch (VerifyName (container)){ - case DeclSpace.AdditionResult.NameExists: - Report.Error (102, Location, "The container '{0}' already contains a definition for '{1}'", container.GetSignatureForError (), Name); - return false; - - case DeclSpace.AdditionResult.Success: - return true; - } - throw new NotImplementedException (); - } - - DeclSpace.AdditionResult VerifyName (TypeContainer container) { - if (!AddIndexer (container, container.Name + "." + Name)) - return DeclSpace.AdditionResult.NameExists; - - if (Get != null) { - if (!AddIndexer (container, container.Name + ".get_" + Name)) - return DeclSpace.AdditionResult.NameExists; - } - - if (Set != null) { - if (!AddIndexer (container, container.Name + ".set_" + Name)) - return DeclSpace.AdditionResult.NameExists; - } - return DeclSpace.AdditionResult.Success; - } - - bool AddIndexer (TypeContainer container, string fullname) + public override string GetSignatureForError () { - object value = container.GetDefinition (fullname); - - if (value != null) { - return value.GetType () != GetType () ? false : true; - } + if (PropertyBuilder == null) + return GetSignatureForError (Parent); - container.DefineName (fullname, this); - return true; + return TypeManager.CSharpSignature (PropertyBuilder, true); } - public override string GetSignatureForError () { - return TypeManager.CSharpSignature (PropertyBuilder, true); + public override string GetSignatureForError(TypeContainer tc) + { + return String.Concat (tc.Name, ".this[", Parameters.FixedParameters [0].TypeName.ToString (), ']'); } } - public class Operator : MemberBase, IIteratorContainer { + public class Operator : MethodCore, IIteratorContainer { const int AllowedModifiers = Modifiers.PUBLIC | @@ -5454,36 +6991,31 @@ namespace Mono.CSharp { }; public readonly OpType OperatorType; - public readonly Expression ReturnType; - public readonly Expression FirstArgType, SecondArgType; - public readonly string FirstArgName, SecondArgName; - public Block Block; public MethodBuilder OperatorMethodBuilder; - public string MethodName; public Method OperatorMethod; - public Operator (OpType type, Expression ret_type, int mod_flags, - Expression arg1type, string arg1name, - Expression arg2type, string arg2name, + static string[] attribute_targets = new string [] { "method", "return" }; + + public Operator (TypeContainer parent, OpType type, Expression ret_type, + int mod_flags, Parameters parameters, Block block, Attributes attrs, Location loc) - : base (ret_type, mod_flags, AllowedModifiers, Modifiers.PUBLIC, - MemberName.Null, attrs, loc) + : base (parent, null, ret_type, mod_flags, AllowedModifiers, false, + new MemberName ("op_" + type), attrs, parameters, loc) { OperatorType = type; - Name = "op_" + OperatorType; - ReturnType = ret_type; - FirstArgType = arg1type; - FirstArgName = arg1name; - SecondArgType = arg2type; - SecondArgName = arg2name; Block = block; } - string Prototype (TypeContainer container) + public override void ApplyAttributeBuilder (Attribute a, CustomAttributeBuilder cb) { - return container.Name + ".operator " + OperatorType + " (" + FirstArgType + "," + - SecondArgType + ")"; + OperatorMethod.ApplyAttributeBuilder (a, cb); + } + + public override AttributeTargets AttributeTargets { + get { + return AttributeTargets.Method; + } } protected override bool CheckGenericOverride (MethodInfo method, string name) @@ -5491,50 +7023,68 @@ namespace Mono.CSharp { return true; } - public override bool Define (TypeContainer container) + protected override bool CheckForDuplications() { - int length = 1; - MethodName = "op_" + OperatorType; - - if (SecondArgType != null) - length = 2; - - Parameter [] param_list = new Parameter [length]; + ArrayList ar = Parent.Operators; + if (ar != null) { + int arLen = ar.Count; + + for (int i = 0; i < arLen; i++) { + Operator o = (Operator) ar [i]; + if (IsDuplicateImplementation (o)) + return false; + } + } + + ar = Parent.Methods; + if (ar != null) { + int arLen = ar.Count; + + for (int i = 0; i < arLen; i++) { + Method m = (Method) ar [i]; + if (IsDuplicateImplementation (m)) + return false; + } + } + + return true; + } + public override bool Define () + { if ((ModFlags & RequiredModifiers) != RequiredModifiers){ Report.Error ( 558, Location, "User defined operators `" + - Prototype (container) + + GetSignatureForError (Parent) + "' must be declared static and public"); return false; } - param_list[0] = new Parameter (FirstArgType, FirstArgName, - Parameter.Modifier.NONE, null); - if (SecondArgType != null) - param_list[1] = new Parameter (SecondArgType, SecondArgName, - Parameter.Modifier.NONE, null); - + if (!DoDefine (ds)) + return false; + OperatorMethod = new Method ( - container, ReturnType, ModFlags, false, - new MemberName (MethodName), - new Parameters (param_list, null, Location), - OptAttributes, Location); + Parent, null, Type, ModFlags, false, MemberName, + Parameters, OptAttributes, Location); OperatorMethod.Block = Block; OperatorMethod.IsOperator = true; - OperatorMethod.Define (container); + OperatorMethod.flags |= MethodAttributes.SpecialName | MethodAttributes.HideBySig; + OperatorMethod.Define (); if (OperatorMethod.MethodBuilder == null) return false; OperatorMethodBuilder = OperatorMethod.MethodBuilder; - Type [] param_types = OperatorMethod.ParameterTypes; + parameter_types = OperatorMethod.ParameterTypes; Type declaring_type = OperatorMethod.MethodData.DeclaringType; - Type return_type = OperatorMethod.GetReturnType (); - Type first_arg_type = param_types [0]; + Type return_type = OperatorMethod.ReturnType; + Type first_arg_type = parameter_types [0]; + + if (!CheckBase ()) + return false; // Rules for conversion operators @@ -5573,15 +7123,21 @@ namespace Mono.CSharp { return false; } - if (first_arg_type.IsSubclassOf (return_type) || - return_type.IsSubclassOf (first_arg_type)){ - Report.Error ( - -10, Location, - "User-defined conversion cannot convert between types " + - "that derive from each other"); + if (first_arg_type.IsSubclassOf (return_type) + || return_type.IsSubclassOf (first_arg_type)){ + if (declaring_type.IsSubclassOf (return_type)) { + Report.Error (553, Location, "'{0}' : user defined conversion to/from base class", GetSignatureForError ()); + return false; + } + Report.Error (554, Location, "'{0}' : user defined conversion to/from derived class", GetSignatureForError ()); return false; } - } else if (SecondArgType == null) { + } else if (OperatorType == OpType.LeftShift || OperatorType == OpType.RightShift) { + if (first_arg_type != declaring_type || parameter_types [1] != TypeManager.int32_type) { + Report.Error (564, Location, "Overloaded shift operator must have the type of the first operand be the containing type, and the type of the second operand must be int"); + return false; + } + } else if (Parameters.FixedParameters.Length == 1) { // Checks for Unary operators if (first_arg_type != declaring_type){ @@ -5617,7 +7173,7 @@ namespace Mono.CSharp { // Checks for Binary operators if (first_arg_type != declaring_type && - param_types [1] != declaring_type){ + parameter_types [1] != declaring_type){ Report.Error ( 563, Location, "One of the parameters of a binary operator must " + @@ -5629,7 +7185,7 @@ namespace Mono.CSharp { return true; } - public void Emit (TypeContainer container) + public override void Emit () { // // abstract or extern methods have no bodies @@ -5637,10 +7193,16 @@ namespace Mono.CSharp { if ((ModFlags & (Modifiers.ABSTRACT | Modifiers.EXTERN)) != 0) return; - OperatorMethod.Emit (container); + OperatorMethod.Emit (); Block = null; } + // Operator cannot be override + protected override MethodInfo FindOutParentMethod (TypeContainer container, ref Type parent_ret_type) + { + return null; + } + public static string GetName (OpType ot) { switch (ot){ @@ -5699,13 +7261,34 @@ namespace Mono.CSharp { default: return ""; } } + + public override string GetSignatureForError (TypeContainer tc) + { + StringBuilder sb = new StringBuilder (); + sb.AppendFormat ("{0}.operator {1} {2}({3}", tc.Name, GetName (OperatorType), Type.ToString (), Parameters.FixedParameters [0].GetSignatureForError ()); + + if (Parameters.FixedParameters.Length > 1) { + sb.Append (","); + sb.Append (Parameters.FixedParameters [1].GetSignatureForError ()); + } + sb.Append (")"); + return sb.ToString (); + } + + public override string GetSignatureForError () + { + return ToString (); + } public override string ToString () { - Type return_type = OperatorMethod.GetReturnType(); + if (OperatorMethod == null) + return Name; + + Type return_type = OperatorMethod.ReturnType; Type [] param_types = OperatorMethod.ParameterTypes; - if (SecondArgType == null) + if (Parameters.FixedParameters.Length == 1) return String.Format ( "{0} operator {1}({2})", TypeManager.CSharpName (return_type), @@ -5719,6 +7302,12 @@ namespace Mono.CSharp { param_types [0], param_types [1]); } + public override string[] ValidAttributeTargets { + get { + return attribute_targets; + } + } + public void SetYields () { ModFlags |= Modifiers.METHOD_YIELDS;