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 ();
public static void Reset ()
{
- type_hash = new Dictionary<TypeSpec, TypeInfo> ();
StructInfo.field_type_hash = new Dictionary<TypeSpec, StructInfo> ();
}
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;
}
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;
}
}
//
// 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);
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);
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);
}
}
}
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;
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
};
}
}
+ //
+ // 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];
}
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;
}
}
}