Merge pull request #1952 from esdrubal/proc_name
[mono.git] / mcs / mcs / flowanalysis.cs
index 4878341e3f8dee692015971435ab9ca9c17d35e4..267879c043b75ef8dc40f3df4f150503cd69317c 100644 (file)
@@ -59,10 +59,9 @@ namespace Mono.CSharp
                public TypeInfo[] SubStructInfo;
 
                readonly StructInfo struct_info;
-               private static Dictionary<TypeSpec, TypeInfo> type_hash;
 
                static readonly TypeInfo simple_type = new TypeInfo (1);
-               
+
                static TypeInfo ()
                {
                        Reset ();
@@ -70,7 +69,6 @@ namespace Mono.CSharp
                
                public static void Reset ()
                {
-                       type_hash = new Dictionary<TypeSpec, TypeInfo> ();
                        StructInfo.field_type_hash = new Dictionary<TypeSpec, StructInfo> ();
                }
 
@@ -105,23 +103,34 @@ namespace Mono.CSharp
                        return struct_info.GetStructField (name);
                }
 
-               public static TypeInfo GetTypeInfo (TypeSpec type)
+               public static TypeInfo GetTypeInfo (TypeSpec type, IMemberContext context)
                {
                        if (!type.IsStruct)
                                return simple_type;
 
                        TypeInfo info;
-                       if (type_hash.TryGetValue (type, out info))
-                               return info;
+                       Dictionary<TypeSpec, TypeInfo> type_hash;
+                       if (type.BuiltinType > 0) {
+                               // Don't cache built-in types, they are null in most cases except for
+                               // corlib compilation when we need to distinguish between declaration
+                               // and referencing
+                               type_hash = null;
+                       } else {
+                               type_hash = context.Module.TypeInfoCache;
+                               if (type_hash.TryGetValue (type, out info))
+                                       return info;
+                       }
 
-                       var struct_info = StructInfo.GetStructInfo (type);
+                       var struct_info = StructInfo.GetStructInfo (type, context);
                        if (struct_info != null) {
                                info = new TypeInfo (struct_info, 0);
                        } else {
                                info = simple_type;
                        }
 
-                       type_hash.Add (type, info);
+                       if (type_hash != null)
+                               type_hash.Add (type, info);
+
                        return info;
                }
 
@@ -139,15 +148,22 @@ namespace Mono.CSharp
                                var field = struct_info.Fields[i];
 
                                if (!fc.IsStructFieldDefinitelyAssigned (vi, field.Name)) {
-                                       if (field.MemberDefinition is Property.BackingField) {
+                                       var bf = field.MemberDefinition as Property.BackingFieldDeclaration;
+                                       if (bf != null) {
+                                               if (bf.Initializer != null)
+                                                       continue;
+
                                                fc.Report.Error (843, loc,
                                                        "An automatically implemented property `{0}' must be fully assigned before control leaves the constructor. Consider calling the default struct contructor from a constructor initializer",
                                                        field.GetSignatureForError ());
-                                       } else {
-                                               fc.Report.Error (171, loc,
-                                                       "Field `{0}' must be fully assigned before control leaves the constructor",
-                                                       field.GetSignatureForError ());
+
+                                               ok = false;
+                                               continue;
                                        }
+
+                                       fc.Report.Error (171, loc,
+                                               "Field `{0}' must be fully assigned before control leaves the constructor",
+                                               field.GetSignatureForError ());
                                        ok = false;
                                }
                        }
@@ -177,11 +193,11 @@ namespace Mono.CSharp
                        //
                        // We only need one instance per type
                        //
-                       StructInfo (TypeSpec type)
+                       StructInfo (TypeSpec type, IMemberContext context)
                        {
                                field_type_hash.Add (type, this);
 
-                               fields = MemberCache.GetAllFieldsForDefiniteAssignment (type);
+                               fields = MemberCache.GetAllFieldsForDefiniteAssignment (type, context);
 
                                struct_field_hash = new Dictionary<string, TypeInfo> ();
                                field_hash = new Dictionary<string, int> (fields.Count);
@@ -195,7 +211,7 @@ namespace Mono.CSharp
                                        var field = fields [i];
 
                                        if (field.MemberType.IsStruct)
-                                               sinfo [i] = GetStructInfo (field.MemberType);
+                                               sinfo [i] = GetStructInfo (field.MemberType, context);
 
                                        if (sinfo [i] == null)
                                                field_hash.Add (field.Name, ++Length);
@@ -253,16 +269,16 @@ namespace Mono.CSharp
                                return null;
                        }
 
-                       public static StructInfo GetStructInfo (TypeSpec type)
+                       public static StructInfo GetStructInfo (TypeSpec type, IMemberContext context)
                        {
-                               if (type.BuiltinType > 0)
+                               if (type.BuiltinType > 0 && type != context.CurrentType)
                                        return null;
 
                                StructInfo info;
                                if (field_type_hash.TryGetValue (type, out info))
                                        return info;
 
-                               return new StructInfo (type);
+                               return new StructInfo (type, context);
                        }
                }
        }
@@ -298,11 +314,11 @@ namespace Mono.CSharp
 
                VariableInfo[] sub_info;
 
-               VariableInfo (string name, TypeSpec type, int offset)
+               VariableInfo (string name, TypeSpec type, int offset, IMemberContext context)
                {
                        this.Name = name;
                        this.Offset = offset;
-                       this.TypeInfo = TypeInfo.GetTypeInfo (type);
+                       this.TypeInfo = TypeInfo.GetTypeInfo (type, context);
 
                        Length = TypeInfo.TotalLength;
 
@@ -336,14 +352,14 @@ namespace Mono.CSharp
 
                public static VariableInfo Create (BlockContext bc, LocalVariable variable)
                {
-                       var info = new VariableInfo (variable.Name, variable.Type, bc.AssignmentInfoOffset);
+                       var info = new VariableInfo (variable.Name, variable.Type, bc.AssignmentInfoOffset, bc);
                        bc.AssignmentInfoOffset += info.Length;
                        return info;
                }
 
                public static VariableInfo Create (BlockContext bc, Parameter parameter)
                {
-                       var info = new VariableInfo (parameter.Name, parameter.Type, bc.AssignmentInfoOffset) {
+                       var info = new VariableInfo (parameter.Name, parameter.Type, bc.AssignmentInfoOffset, bc) {
                                IsParameter = true
                        };
 
@@ -503,54 +519,91 @@ namespace Mono.CSharp
                }
        }
 
+       //
+       // Special version of bit array. Many operations can be simplified because
+       // we are always dealing with arrays of same sizes
+       //
        public class DefiniteAssignmentBitSet
        {
-               // Make it
-               // int bits;
-               // int int[] bits_extended; // when bits overflows
+               const uint copy_on_write_flag = 1u << 31;
 
-               System.Collections.BitArray bits;
-               bool copy_on_write;
+               uint bits;
 
-               public DefiniteAssignmentBitSet ()
-               {
-                       bits = new System.Collections.BitArray (4096); // TODO:
-               }
+               // Used when bits overflows
+               int[] large_bits;
 
-               public DefiniteAssignmentBitSet (DefiniteAssignmentBitSet source)
-               {
-                       bits = source.bits;
+               public static readonly DefiniteAssignmentBitSet Empty = new DefiniteAssignmentBitSet (0);
 
-                       copy_on_write = true;
+               public DefiniteAssignmentBitSet (int length)
+               {
+                       if (length > 31)
+                               large_bits = new int[(length + 31) / 32];
                }
 
-               private DefiniteAssignmentBitSet (System.Collections.BitArray bits)
+               public DefiniteAssignmentBitSet (DefiniteAssignmentBitSet source)
                {
-                       this.bits = bits;
+                       if (source.large_bits != null) {
+                               large_bits = source.large_bits;
+                               bits = source.bits | copy_on_write_flag;
+                       } else {
+                               bits = source.bits & ~copy_on_write_flag;
+                       }
                }
 
                public static DefiniteAssignmentBitSet operator & (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
                {
-                       if (a.bits == b.bits)
+                       if (IsEqual (a, b))
                                return a;
 
-                       return new DefiniteAssignmentBitSet (a.bits.And (b.bits));
+                       DefiniteAssignmentBitSet res;
+                       if (a.large_bits == null) {
+                               res = new DefiniteAssignmentBitSet (a);
+                               res.bits &= (b.bits & ~copy_on_write_flag);
+                               return res;
+                       }
+
+                       res = new DefiniteAssignmentBitSet (a);
+                       res.Clone ();
+                       var dest = res.large_bits;
+                       var src = b.large_bits;
+                       for (int i = 0; i < dest.Length; ++i) {
+                               dest[i] &= src[i];
+                       }
+
+                       return res;
                }
 
                public static DefiniteAssignmentBitSet operator | (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
                {
-                       if (a.bits == b.bits)
+                       if (IsEqual (a, b))
                                return a;
 
-                       return new DefiniteAssignmentBitSet (a.bits.Or (b.bits));
+                       DefiniteAssignmentBitSet res;
+                       if (a.large_bits == null) {
+                               res = new DefiniteAssignmentBitSet (a);
+                               res.bits |= b.bits;
+                               res.bits &= ~copy_on_write_flag;
+                               return res;
+                       }
+
+                       res = new DefiniteAssignmentBitSet (a);
+                       res.Clone ();
+                       var dest = res.large_bits;
+                       var src = b.large_bits;
+
+                       for (int i = 0; i < dest.Length; ++i) {
+                               dest[i] |= src[i];
+                       }
+
+                       return res;
                }
 
                public static DefiniteAssignmentBitSet And (List<DefiniteAssignmentBitSet> das)
                {
                        if (das.Count == 0)
-                               return new DefiniteAssignmentBitSet ();
+                               throw new ArgumentException ("Empty das");
 
-                       DefiniteAssignmentBitSet res = das [0];
+                       DefiniteAssignmentBitSet res = das[0];
                        for (int i = 1; i < das.Count; ++i) {
                                res &= das[i];
                        }
@@ -558,34 +611,99 @@ namespace Mono.CSharp
                        return res;
                }
 
+               bool CopyOnWrite {
+                       get {
+                               return (bits & copy_on_write_flag) != 0;
+                       }
+               }
+
+               int Length {
+                       get {
+                               return large_bits == null ? 31 : large_bits.Length * 32;
+                       }
+               }
+
                public void Set (int index)
                {
-                       if (copy_on_write && !bits[index])
+                       if (CopyOnWrite && !this[index])
                                Clone ();
 
-                       bits[index] = true;
+                       SetBit (index);
                }
 
                public void Set (int index, int length)
                {
                        for (int i = 0; i < length; ++i) {
-                               if (copy_on_write && !bits[index + i])
+                               if (CopyOnWrite && !this[index + i])
                                        Clone ();
 
-                               bits[index + i] = true;
+                               SetBit (index + i);
                        }
-               }
+               }
 
-               public bool this [int index] {
+               public bool this[int index] {
                        get {
-                               return bits [index];
+                               return GetBit (index);
+                       }
+               }
+
+               public override string ToString ()
+               {
+                       var length = Length;
+                       StringBuilder sb = new StringBuilder (length);
+                       for (int i = 0; i < length; ++i) {
+                               sb.Append (this[i] ? '1' : '0');
                        }
+
+                       return sb.ToString ();
                }
 
                void Clone ()
                {
-                       bits = new System.Collections.BitArray (bits);
-                       copy_on_write = false;
+                       large_bits = (int[]) large_bits.Clone ();
+               }
+
+               bool GetBit (int index)
+               {
+                       return large_bits == null ?
+                               (bits & (1 << index)) != 0 :
+                               (large_bits[index >> 5] & (1 << (index & 31))) != 0;
+               }
+
+               void SetBit (int index)
+               {
+                       if (large_bits == null)
+                               bits = (uint) ((int) bits | (1 << index));
+                       else
+                               large_bits[index >> 5] |= (1 << (index & 31));
+               }
+
+               static bool IsEqual (DefiniteAssignmentBitSet a, DefiniteAssignmentBitSet b)
+               {
+                       if (a.large_bits == null)
+                               return (a.bits & ~copy_on_write_flag) == (b.bits & ~copy_on_write_flag);
+
+                       for (int i = 0; i < a.large_bits.Length; ++i) {
+                               if (a.large_bits[i] != b.large_bits[i])
+                                       return false;
+                       }
+
+                       return true;
+               }
+
+               public static bool IsIncluded (DefiniteAssignmentBitSet set, DefiniteAssignmentBitSet test)
+               {
+                       var set_bits = set.large_bits;
+                       if (set_bits == null)
+                               return (set.bits & test.bits & ~copy_on_write_flag) == (set.bits & ~copy_on_write_flag);
+
+                       var test_bits = test.large_bits;
+                       for (int i = 0; i < set_bits.Length; ++i) {
+                               if ((set_bits[i] & test_bits[i]) != set_bits[i])
+                                       return false;
+                       }
+
+                       return true;
                }
        }
 }