[mcs] Implements C# 7.2 readonly structs
[mono.git] / mcs / mcs / class.cs
index fe79b444e36e6600d1a1b227e831fe5a3d278c1b..9afb32c6fe5677d71cdd7632d08c79a43302e040 100644 (file)
@@ -639,6 +639,15 @@ namespace Mono.CSharp
                        }
                }
 
+               public bool HasInstanceField {
+                       get {
+                               return (caching_flags & Flags.HasInstanceField) != 0;
+                       }
+                       set {
+                               caching_flags |= Flags.HasInstanceField;
+                       }
+               }
+
                // Indicated whether container has StructLayout attribute set Explicit
                public bool HasExplicitLayout {
                        get { return (caching_flags & Flags.HasExplicitLayout) != 0; }
@@ -848,18 +857,22 @@ namespace Mono.CSharp
                        if ((field.ModFlags & Modifiers.STATIC) != 0)
                                return true;
 
-                       var first_field = PartialContainer.first_nonstatic_field;
-                       if (first_field == null) {
+                       if (!PartialContainer.HasInstanceField) {
+                               PartialContainer.HasInstanceField = true;
                                PartialContainer.first_nonstatic_field = field;
                                return true;
                        }
 
-                       if (Kind == MemberKind.Struct && first_field.Parent != field.Parent) {
-                               Report.SymbolRelatedToPreviousError (first_field.Parent);
-                               Report.Warning (282, 3, field.Location,
-                                       "struct instance field `{0}' found in different declaration from instance field `{1}'",
-                                       field.GetSignatureForError (), first_field.GetSignatureForError ());
+                       if (Kind == MemberKind.Struct) {
+                               var first_field = PartialContainer.first_nonstatic_field;
+                               if (first_field.Parent != field.Parent) {
+                                       Report.SymbolRelatedToPreviousError (first_field.Parent);
+                                       Report.Warning (282, 3, field.Location,
+                                               "struct instance field `{0}' found in different declaration from instance field `{1}'",
+                                               field.GetSignatureForError (), first_field.GetSignatureForError ());
+                               }
                        }
+
                        return true;
                }
 
@@ -1299,7 +1312,7 @@ namespace Mono.CSharp
                        //
                        // Sets .size to 1 for structs with no instance fields
                        //
-                       int type_size = Kind == MemberKind.Struct && first_nonstatic_field == null && !(this is StateMachine) ? 1 : 0;
+                       int type_size = Kind == MemberKind.Struct && !HasInstanceField && !(this is StateMachine) ? 1 : 0;
 
                        var parent_def = Parent as TypeDefinition;
                        if (parent_def == null) {
@@ -1805,8 +1818,10 @@ namespace Mono.CSharp
                        this.spec = spec;
                        current_type = null;
                        if (class_partial_parts != null) {
-                               foreach (var part in class_partial_parts)
+                               foreach (var part in class_partial_parts) {
                                        part.spec = spec;
+                                       part.current_type = null;
+                               }
                        }
                }
 
@@ -2156,6 +2171,14 @@ namespace Mono.CSharp
 
                public override void Emit ()
                {
+                       if (Interfaces != null) {
+                               foreach (var iface in Interfaces) {
+                                       if (iface.HasNamedTupleElement) {
+                                               throw new NotImplementedException ("named tuples for .interfaceimpl");
+                                       }
+                               }
+                       }
+
                        if (OptAttributes != null)
                                OptAttributes.Emit ();
 
@@ -2212,6 +2235,10 @@ namespace Mono.CSharp
                                Module.PredefinedAttributes.CompilerGenerated.EmitAttribute (TypeBuilder);
 
 #if STATIC
+                       if (Kind == MemberKind.Struct && !HasStructLayout && HasInstanceField) {
+                               TypeBuilder.__SetLayout (0, 0);
+                       }
+
                        if ((TypeBuilder.Attributes & TypeAttributes.StringFormatMask) == 0 && Module.HasDefaultCharSet)
                                TypeBuilder.__SetAttributes (TypeBuilder.Attributes | Module.DefaultCharSetType);
 #endif
@@ -2882,8 +2909,11 @@ namespace Mono.CSharp
                        if ((ModFlags & Modifiers.METHOD_EXTENSION) != 0)
                                Module.PredefinedAttributes.Extension.EmitAttribute (TypeBuilder);
 
-                       if (base_type != null && base_type.HasDynamicElement) {
-                               Module.PredefinedAttributes.Dynamic.EmitAttribute (TypeBuilder, base_type, Location);
+                       if (base_type != null) {
+                               if (base_type.HasDynamicElement)
+                                       Module.PredefinedAttributes.Dynamic.EmitAttribute (TypeBuilder, base_type, Location);
+                               if (base_type.HasNamedTupleElement)
+                                       Module.PredefinedAttributes.TupleElementNames.EmitAttribute (TypeBuilder, base_type, Location);
                        }
                }
 
@@ -2992,7 +3022,8 @@ namespace Mono.CSharp
                        Modifiers.PROTECTED |
                        Modifiers.INTERNAL  |
                        Modifiers.UNSAFE    |
-                       Modifiers.PRIVATE;
+                       Modifiers.PRIVATE   |
+                       Modifiers.READONLY;
 
                public Struct (TypeContainer parent, MemberName name, Modifiers mod, Attributes attrs)
                        : base (parent, name, attrs, MemberKind.Struct)
@@ -3105,6 +3136,9 @@ namespace Mono.CSharp
 
                public override void Emit ()
                {
+                       if ((ModFlags & Modifiers.READONLY) != 0)
+                               Module.PredefinedAttributes.IsReadOnly.EmitAttribute (TypeBuilder);
+
                        CheckStructCycles ();
 
                        base.Emit ();
@@ -3144,7 +3178,7 @@ namespace Mono.CSharp
                                return false;
                        }
 
-                       if (first_nonstatic_field != null) {
+                       if (HasInstanceField) {
                                requires_delayed_unmanagedtype_check = true;
 
                                foreach (var member in Members) {
@@ -3494,10 +3528,13 @@ namespace Mono.CSharp
                                ok = false;
                        }
 
-                       var base_member_type = ((IInterfaceMemberSpec) base_member).MemberType;
+                       var base_member_type = ((IInterfaceMemberSpec)base_member).MemberType;
                        if (!TypeSpecComparer.Override.IsEqual (MemberType, base_member_type)) {
                                Report.SymbolRelatedToPreviousError (base_member);
-                               if (this is PropertyBasedMember) {
+                               if (((base_member_type.Kind ^ MemberType.Kind) & MemberKind.ByRef) != 0) {
+                                       Report.Error (8148, Location, "`{0}': must {2}return by reference to match overridden member `{1}'",
+                                                     GetSignatureForError (), base_member.GetSignatureForError (), base_member_type.Kind == MemberKind.ByRef ? "" : "not ");
+                               } else if (this is PropertyBasedMember) {
                                        Report.Error (1715, Location, "`{0}': type must be `{1}' to match overridden member `{2}'",
                                                GetSignatureForError (), base_member_type.GetSignatureForError (), base_member.GetSignatureForError ());
                                } else {
@@ -3505,6 +3542,20 @@ namespace Mono.CSharp
                                                GetSignatureForError (), base_member_type.GetSignatureForError (), base_member.GetSignatureForError ());
                                }
                                ok = false;
+                       } else if (!NamedTupleSpec.CheckOverrideName (MemberType, base_member_type)) {
+                               // CSC: Should be different error code
+                               Report.Error (8139, Location, "`{0}': cannot change return type tuple element names when overriding inherited member `{1}'",
+                                                         GetSignatureForError (), base_member.GetSignatureForError ());
+                               ok = false;
+                       }
+
+                       var base_params = base_member as IParametersMember;
+                       if (base_params != null) {
+                               if (!NamedTupleSpec.CheckOverrideName ((IParametersMember)this, base_params)) {
+                                       Report.Error (8139, Location, "`{0}': cannot change tuple element names when overriding inherited member `{1}'",
+                                                                 GetSignatureForError (), base_member.GetSignatureForError ());
+                                       ok = false;
+                               }
                        }
 
                        return ok;