X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fenum.cs;h=691fcbe6b1291424181587d730f6e8bcda8301a1;hb=25f808006ab037e1c36f844b01268a34c9d40601;hp=0f91e1ccd244cf7ef933758730c52b4d6c42f7f2;hpb=75b15060b976b16ab7673c9a1e9737add1de34ec;p=mono.git diff --git a/mcs/mcs/enum.cs b/mcs/mcs/enum.cs index 0f91e1ccd24..691fcbe6b12 100755 --- a/mcs/mcs/enum.cs +++ b/mcs/mcs/enum.cs @@ -20,25 +20,27 @@ namespace Mono.CSharp { /// Enumeration container /// public class Enum : DeclSpace { - ArrayList ordered_enums; - public readonly string BaseType; - public readonly string EnumName; - int mod_flags; - public TypeBuilder EnumBuilder; + + public Expression BaseType; public Attributes OptAttributes; public Type UnderlyingType; Hashtable member_to_location; + Hashtable member_to_attributes; // // This is for members that have been defined // Hashtable member_to_value; + + // + // This is used to mark members we're currently defining + // + Hashtable in_transit; ArrayList field_builders; - Location loc; public const int AllowedModifiers = Modifiers.NEW | @@ -47,18 +49,18 @@ namespace Mono.CSharp { Modifiers.INTERNAL | Modifiers.PRIVATE; - public Enum (RootContext rc, string type, int mod_flags, string name, Attributes attrs, Location l) - : base (rc, name, l) + public Enum (TypeContainer parent, Expression type, int mod_flags, string name, Attributes attrs, Location l) + : base (parent, name, l) { this.BaseType = type; - this.EnumName = name; - this.mod_flags = Modifiers.Check (AllowedModifiers, mod_flags, Modifiers.PUBLIC); + ModFlags = Modifiers.Check (AllowedModifiers, mod_flags, + IsTopLevel ? Modifiers.INTERNAL : Modifiers.PRIVATE, l); OptAttributes = attrs; - loc = l; ordered_enums = new ArrayList (); member_to_location = new Hashtable (); member_to_value = new Hashtable (); + in_transit = new Hashtable (); field_builders = new ArrayList (); } @@ -66,7 +68,8 @@ namespace Mono.CSharp { /// Adds @name to the enumeration space, with @expr /// being its definition. /// - public AdditionResult AddEnumMember (string name, Expression expr, Location loc) + public AdditionResult AddEnumMember (string name, Expression expr, Location loc, + Attributes opt_attrs) { if (defined_names.Contains (name)) return AdditionResult.NameExists; @@ -75,15 +78,57 @@ namespace Mono.CSharp { ordered_enums.Add (name); member_to_location.Add (name, loc); + + if (member_to_attributes == null) + member_to_attributes = new Hashtable (); + + member_to_attributes.Add (name, opt_attrs); return AdditionResult.Success; } - public void DefineEnum (object parent_builder) + // + // This is used by corlib compilation: we map from our + // type to a type that is consumable by the DefineField + // + Type MapToInternalType (Type t) { - TypeAttributes attr = TypeAttributes.Class | TypeAttributes.Sealed; + if (t == TypeManager.int32_type) + return typeof (int); + if (t == TypeManager.int64_type) + return typeof (long); + if (t == TypeManager.uint32_type) + return typeof (uint); + if (t == TypeManager.uint64_type) + return typeof (ulong); + if (t == TypeManager.float_type) + return typeof (float); + if (t == TypeManager.double_type) + return typeof (double); + if (t == TypeManager.byte_type) + return typeof (byte); + if (t == TypeManager.sbyte_type) + return typeof (sbyte); + if (t == TypeManager.char_type) + return typeof (char); + if (t == TypeManager.short_type) + return typeof (short); + if (t == TypeManager.ushort_type) + return typeof (ushort); + + throw new Exception (); + } + + public override TypeBuilder DefineType () + { + if (TypeBuilder != null) + return TypeBuilder; + + TypeAttributes attr = Modifiers.TypeAttr (ModFlags, IsTopLevel); + + attr |= TypeAttributes.Class | TypeAttributes.Sealed; - UnderlyingType = RootContext.TypeManager.LookupType (BaseType); + UnderlyingType = ResolveType (BaseType, false, Location); if (UnderlyingType != TypeManager.int32_type && UnderlyingType != TypeManager.uint32_type && @@ -95,45 +140,42 @@ namespace Mono.CSharp { UnderlyingType != TypeManager.sbyte_type) { Report.Error (1008, Location, "Type byte, sbyte, short, ushort, int, uint, " + - "long, or ulong expected"); - return; + "long, or ulong expected (got: " + + TypeManager.CSharpName (UnderlyingType) + ")"); + return null; } - if (parent_builder is ModuleBuilder) { - ModuleBuilder builder = (ModuleBuilder) parent_builder; - - if ((ModFlags & Modifiers.PUBLIC) != 0) - attr |= TypeAttributes.Public; - else - attr |= TypeAttributes.NotPublic; - - EnumBuilder = builder.DefineType (EnumName, attr, TypeManager.enum_type); + if (IsTopLevel) { + ModuleBuilder builder = CodeGen.ModuleBuilder; + TypeBuilder = builder.DefineType (Name, attr, TypeManager.enum_type); } else { - TypeBuilder builder = (TypeBuilder) parent_builder; + TypeBuilder builder = Parent.TypeBuilder; - if ((ModFlags & Modifiers.PUBLIC) != 0) - attr |= TypeAttributes.NestedPublic; - else - attr |= TypeAttributes.NestedPrivate; - - EnumBuilder = builder.DefineNestedType (EnumName, attr, TypeManager.enum_type); + TypeBuilder = builder.DefineNestedType ( + Basename, attr, TypeManager.enum_type); } - EnumBuilder.DefineField ("value__", UnderlyingType, - FieldAttributes.Public | FieldAttributes.SpecialName); + // + // Call MapToInternalType for corlib + // + TypeBuilder.DefineField ("value__", UnderlyingType, + FieldAttributes.Public | FieldAttributes.SpecialName + | FieldAttributes.RTSpecialName); - RootContext.TypeManager.AddEnumType (EnumName, EnumBuilder, this); + TypeManager.AddEnumType (Name, TypeBuilder, this); - return; + return TypeBuilder; } - bool IsValidEnumLiteral (Expression e) + bool IsValidEnumConstant (Expression e) { - if (!(e is Literal)) + if (!(e is Constant)) return false; - if (e is IntLiteral || e is UIntLiteral || e is LongLiteral || e is ULongLiteral || e is EnumLiteral) + if (e is IntConstant || e is UIntConstant || e is LongConstant || + e is ByteConstant || e is SByteConstant || e is ShortConstant || + e is UShortConstant || e is ULongConstant || e is EnumConstant) return true; else return false; @@ -202,10 +244,10 @@ namespace Mono.CSharp { return null; } - void error31 (object val, Location loc) + void Error_ConstantValueCannotBeConverted (object val, Location loc) { - if (val is Literal) - Report.Error (31, loc, "Constant value '" + ((Literal) val).AsString () + + if (val is Constant) + Report.Error (31, loc, "Constant value '" + ((Constant) val).AsString () + "' cannot be converted" + " to a " + TypeManager.CSharpName (UnderlyingType)); else @@ -215,6 +257,129 @@ namespace Mono.CSharp { return; } + /// + /// Determines if a standard implicit conversion exists from + /// expr_type to target_type + /// + public static bool ImplicitConversionExists (Type expr_type, Type target_type) + { + expr_type = TypeManager.TypeToCoreType (expr_type); + + if (expr_type == TypeManager.void_type) + return false; + + if (expr_type == target_type) + return true; + + // First numeric conversions + + if (expr_type == TypeManager.sbyte_type){ + // + // From sbyte to short, int, long, float, double. + // + if ((target_type == TypeManager.int32_type) || + (target_type == TypeManager.int64_type) || + (target_type == TypeManager.double_type) || + (target_type == TypeManager.float_type) || + (target_type == TypeManager.short_type) || + (target_type == TypeManager.decimal_type)) + return true; + + } else if (expr_type == TypeManager.byte_type){ + // + // From byte to short, ushort, int, uint, long, ulong, float, double + // + if ((target_type == TypeManager.short_type) || + (target_type == TypeManager.ushort_type) || + (target_type == TypeManager.int32_type) || + (target_type == TypeManager.uint32_type) || + (target_type == TypeManager.uint64_type) || + (target_type == TypeManager.int64_type) || + (target_type == TypeManager.float_type) || + (target_type == TypeManager.double_type) || + (target_type == TypeManager.decimal_type)) + return true; + + } else if (expr_type == TypeManager.short_type){ + // + // From short to int, long, float, double + // + if ((target_type == TypeManager.int32_type) || + (target_type == TypeManager.int64_type) || + (target_type == TypeManager.double_type) || + (target_type == TypeManager.float_type) || + (target_type == TypeManager.decimal_type)) + return true; + + } else if (expr_type == TypeManager.ushort_type){ + // + // From ushort to int, uint, long, ulong, float, double + // + if ((target_type == TypeManager.uint32_type) || + (target_type == TypeManager.uint64_type) || + (target_type == TypeManager.int32_type) || + (target_type == TypeManager.int64_type) || + (target_type == TypeManager.double_type) || + (target_type == TypeManager.float_type) || + (target_type == TypeManager.decimal_type)) + return true; + + } else if (expr_type == TypeManager.int32_type){ + // + // From int to long, float, double + // + if ((target_type == TypeManager.int64_type) || + (target_type == TypeManager.double_type) || + (target_type == TypeManager.float_type) || + (target_type == TypeManager.decimal_type)) + return true; + + } else if (expr_type == TypeManager.uint32_type){ + // + // From uint to long, ulong, float, double + // + if ((target_type == TypeManager.int64_type) || + (target_type == TypeManager.uint64_type) || + (target_type == TypeManager.double_type) || + (target_type == TypeManager.float_type) || + (target_type == TypeManager.decimal_type)) + return true; + + } else if ((expr_type == TypeManager.uint64_type) || + (expr_type == TypeManager.int64_type)) { + // + // From long/ulong to float, double + // + if ((target_type == TypeManager.double_type) || + (target_type == TypeManager.float_type) || + (target_type == TypeManager.decimal_type)) + return true; + + } else if (expr_type == TypeManager.char_type){ + // + // From char to ushort, int, uint, long, ulong, float, double + // + if ((target_type == TypeManager.ushort_type) || + (target_type == TypeManager.int32_type) || + (target_type == TypeManager.uint32_type) || + (target_type == TypeManager.uint64_type) || + (target_type == TypeManager.int64_type) || + (target_type == TypeManager.float_type) || + (target_type == TypeManager.double_type) || + (target_type == TypeManager.decimal_type)) + return true; + + } else if (expr_type == TypeManager.float_type){ + // + // float to double + // + if (target_type == TypeManager.double_type) + return true; + } + + return false; + } + /// /// This is used to lookup the value of an enum member. If the member is undefined, /// it attempts to define it and return its value @@ -222,16 +387,23 @@ namespace Mono.CSharp { public object LookupEnumValue (EmitContext ec, string name, Location loc) { object default_value = null; - Literal l = null; + Constant c = null; default_value = member_to_value [name]; if (default_value != null) return default_value; - if (!defined_names.Contains (name)) { - Report.Error (117, loc, "'"+ EnumName + "' does not contain a definition for '" - + name + "'"); + // + // This may happen if we're calling a method in System.Enum, for instance + // Enum.IsDefined(). + // + if (!defined_names.Contains (name)) + return null; + + if (in_transit.Contains (name)) { + Report.Error (110, loc, "The evaluation of the constant value for `" + + Name + "." + name + "' involves a circular definition."); return null; } @@ -250,46 +422,65 @@ namespace Mono.CSharp { else { for (int i = 0; i < idx; ++i) { string n = (string) ordered_enums [i]; - Location m_loc = (Location) member_to_location [n]; + Location m_loc = (Mono.CSharp.Location) + member_to_location [n]; + in_transit.Add (name, true); default_value = LookupEnumValue (ec, n, m_loc); + in_transit.Remove (name); + if (default_value == null) + return null; } default_value = GetNextDefaultValue (default_value); } } else { + bool old = ec.InEnumContext; + ec.InEnumContext = true; + in_transit.Add (name, true); val = val.Resolve (ec); - - if (val == null) { - Report.Error (-12, loc, "Definition is circular."); + in_transit.Remove (name); + ec.InEnumContext = old; + + if (val == null) return null; - } - - if (IsValidEnumLiteral (val)) { - l = (Literal) val; - default_value = l.GetValue (); + + if (!IsValidEnumConstant (val)) { + Report.Error ( + 1008, loc, + "Type byte, sbyte, short, ushort, int, uint, long, or " + + "ulong expected (have: " + val + ")"); + return null; + } + + c = (Constant) val; + default_value = c.GetValue (); + + if (default_value == null) { + Error_ConstantValueCannotBeConverted (c, loc); + return null; + } + + if (val is EnumConstant){ + Type etype = TypeManager.EnumToUnderlying (c.Type); - if (default_value == null) { - error31 (l, loc); + if (!ImplicitConversionExists (etype, UnderlyingType)){ + Expression.Error_CannotConvertImplicit ( + loc, c.Type, UnderlyingType); return null; } - - } else { - Report.Error (1008, loc, - "Type byte, sbyte, short, ushort, int, uint, long, or ulong expected"); - return null; } } FieldAttributes attr = FieldAttributes.Public | FieldAttributes.Static | FieldAttributes.Literal; - FieldBuilder fb = EnumBuilder.DefineField (name, UnderlyingType, attr); - + FieldBuilder fb = TypeBuilder.DefineField (name, UnderlyingType, attr); + try { - default_value = Convert.ChangeType (default_value, UnderlyingType); + default_value = TypeManager.ChangeType (default_value, UnderlyingType); } catch { - error31 (l, loc); + Error_ConstantValueCannotBeConverted (c, loc); return null; } @@ -297,21 +488,32 @@ namespace Mono.CSharp { field_builders.Add (fb); member_to_value [name] = default_value; - if (!TypeManager.RegisterField (fb, default_value)) + if (!TypeManager.RegisterFieldValue (fb, default_value)) return null; + + // + // Now apply attributes + // + Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name], loc); return default_value; } + + public override bool DefineMembers (TypeContainer parent) + { + return true; + } - public void Populate (TypeContainer tc) + public override bool Define (TypeContainer parent) { // // If there was an error during DefineEnum, return // - if (EnumBuilder == null) - return; + if (TypeBuilder == null) + return false; - EmitContext ec = new EmitContext (tc, Location, null, UnderlyingType, ModFlags); + EmitContext ec = new EmitContext (parent, this, Location, null, + UnderlyingType, ModFlags, false); object default_value = 0; @@ -320,78 +522,63 @@ namespace Mono.CSharp { foreach (string name in ordered_enums) { - - Expression val; - // // Have we already been defined, thanks to some cross-referencing ? // if (member_to_value.Contains (name)) continue; - Location loc = (Location) member_to_location [name]; + Location loc = (Mono.CSharp.Location) member_to_location [name]; if (this [name] != null) { default_value = LookupEnumValue (ec, name, loc); if (default_value == null) - return; + return true; } else { - - FieldBuilder fb = EnumBuilder.DefineField (name, UnderlyingType, attr); + FieldBuilder fb = TypeBuilder.DefineField ( + name, UnderlyingType, attr); if (default_value == null) { Report.Error (543, loc, "Enumerator value for '" + name + "' is too large to " + "fit in its type"); - return; + return false; } try { - default_value = Convert.ChangeType (default_value, UnderlyingType); + default_value = TypeManager.ChangeType (default_value, UnderlyingType); } catch { - error31 (default_value, loc); - return; + Error_ConstantValueCannotBeConverted (default_value, loc); + return false; } - val = Expression.Literalize (default_value, UnderlyingType); - fb.SetConstant (default_value); field_builders.Add (fb); member_to_value [name] = default_value; - if (!TypeManager.RegisterField (fb, default_value)) - return; + if (!TypeManager.RegisterFieldValue (fb, default_value)) + return false; + + // + // Apply attributes on the enum member + // + Attribute.ApplyAttributes (ec, fb, fb, (Attributes) member_to_attributes [name], loc); } default_value = GetNextDefaultValue (default_value); } - if (OptAttributes == null) - return; - - if (OptAttributes.AttributeSections == null) - return; - - foreach (AttributeSection asec in OptAttributes.AttributeSections) { - if (asec.Attributes == null) - continue; - - foreach (Attribute a in asec.Attributes) { - CustomAttributeBuilder cb = a.Resolve (ec); + Attribute.ApplyAttributes (ec, TypeBuilder, this, OptAttributes, Location); - if (cb == null) - continue; - - EnumBuilder.SetCustomAttribute (cb); - } - } + return true; } // - // Hack around System.Reflection as found everywhere else + // IMemberFinder // - public MemberInfo [] FindMembers (MemberTypes mt, BindingFlags bf, MemberFilter filter, object criteria) + public override MemberList FindMembers (MemberTypes mt, BindingFlags bf, + MemberFilter filter, object criteria) { ArrayList members = new ArrayList (); @@ -401,34 +588,21 @@ namespace Mono.CSharp { members.Add (fb); } - int count = members.Count; + return new MemberList (members); + } - if (count > 0) { - MemberInfo [] mi = new MemberInfo [count]; - members.CopyTo (mi, 0); - return mi; + public override MemberCache MemberCache { + get { + return null; } - - return null; } - public void CloseEnum () - { - EnumBuilder.CreateType (); - } - public ArrayList ValueNames { get { return ordered_enums; } } - public int ModFlags { - get { - return mod_flags; - } - } - // indexer public Expression this [string name] { get {