[mcs] Implements C# 7.2 readonly structs
[mono.git] / mcs / mcs / attribute.cs
index 8edce969a443819cabe510b5da2804ba4796a2dd..3ff2d68ccb5ad38964c23c0890f4372c9a4406ef 100644 (file)
@@ -258,6 +258,11 @@ namespace Mono.CSharp {
                        Report.Error (1970, loc, "Do not use `{0}' directly. Use `dynamic' keyword instead", GetSignatureForError ());
                }
 
+               public void Error_MisusedTupleAttribute ()
+               {
+                       Report.Error (8138, loc, "Do not use `{0}' directly. Use the tuple syntax instead", GetSignatureForError ());
+               }
+
                void Error_AttributeEmitError (string inner)
                {
                        Report.Error (647, Location, "Error during emitting `{0}' attribute. The reason is `{1}'",
@@ -1125,7 +1130,12 @@ namespace Mono.CSharp {
                                cdata = encoder.ToArray ();
                        }
 
-                       if (!ctor.DeclaringType.IsConditionallyExcluded (context)) {
+                       if (!IsConditionallyExcluded (ctor.DeclaringType)) {
+                               if (Type == predefined.TupleElementNames) {
+                                       Error_MisusedTupleAttribute ();
+                                       return;
+                               }
+
                                try {
                                        foreach (Attributable target in targets)
                                                target.ApplyAttributeBuilder (this, ctor, cdata, predefined);
@@ -1166,6 +1176,18 @@ namespace Mono.CSharp {
                        }
                }
 
+               bool IsConditionallyExcluded (TypeSpec type)
+               {
+                       do {
+                               if (type.IsConditionallyExcluded (context))
+                                       return true;
+
+                               type = type.BaseType;
+                       } while (type != null);
+
+                       return false;
+               }
+
                private Expression GetValue () 
                {
                        if (pos_args == null || pos_args.Count < 1)
@@ -1730,6 +1752,12 @@ namespace Mono.CSharp {
                // New in .NET 4.5
                public readonly PredefinedStateMachineAttribute AsyncStateMachine;
 
+               // New in .NET 4.7
+               public readonly PredefinedTupleElementNamesAttribute TupleElementNames;
+
+               // New in .NET 4.7.1
+               public readonly PredefinedAttribute IsReadOnly;
+
                //
                // Optional types which are used as types and for member lookup
                //
@@ -1809,6 +1837,9 @@ namespace Mono.CSharp {
                        CallerLineNumberAttribute = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CallerLineNumberAttribute");
                        CallerFilePathAttribute = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "CallerFilePathAttribute");
 
+                       TupleElementNames = new PredefinedTupleElementNamesAttribute (module, "System.Runtime.CompilerServices", "TupleElementNamesAttribute");
+                       IsReadOnly = new PredefinedAttribute (module, "System.Runtime.CompilerServices", "IsReadOnlyAttribute");
+
                        // TODO: Should define only attributes which are used for comparison
                        const System.Reflection.BindingFlags all_fields = System.Reflection.BindingFlags.Public |
                                System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly;
@@ -2159,4 +2190,83 @@ namespace Mono.CSharp {
                        return tctor != null;
                }
        }
+
+       public class PredefinedTupleElementNamesAttribute : PredefinedAttribute
+       {
+               MethodSpec tctor;
+
+               public PredefinedTupleElementNamesAttribute (ModuleContainer module, string ns, string name)
+                       : base (module, ns, name)
+               {
+               }
+
+               public void EmitAttribute (FieldBuilder builder, TypeSpec type, Location loc)
+               {
+                       var cab = CreateCustomAttributeBuilder (type, loc);
+                       if (cab != null)
+                               builder.SetCustomAttribute (cab);
+               }
+
+               public void EmitAttribute (ParameterBuilder builder, TypeSpec type, Location loc)
+               {
+                       var cab = CreateCustomAttributeBuilder (type, loc);
+                       if (cab != null)
+                               builder.SetCustomAttribute (cab);
+               }
+
+               public void EmitAttribute (PropertyBuilder builder, TypeSpec type, Location loc)
+               {
+                       var cab = CreateCustomAttributeBuilder (type, loc);
+                       if (cab != null)
+                               builder.SetCustomAttribute (cab);
+               }
+
+               public void EmitAttribute (TypeBuilder builder, TypeSpec type, Location loc)
+               {
+                       var cab = CreateCustomAttributeBuilder (type, loc);
+                       if (cab != null)
+                               builder.SetCustomAttribute (cab);
+               }
+
+               CustomAttributeBuilder CreateCustomAttributeBuilder (TypeSpec type, Location loc)
+               {
+                       if (tctor == null) {
+                               tctor = module.PredefinedMembers.TupleElementNamesAttributeCtor.Resolve (loc);
+                               if (tctor == null)
+                                       return null;
+                       }
+
+                       var names = new List<string> (type.TypeArguments.Length);
+                       BuildStringElements (type, names);
+                       return new CustomAttributeBuilder ((ConstructorInfo)tctor.GetMetaInfo (), new object [] { names.ToArray () });
+               }
+
+               //
+               // Returns an array of names when any element of the type is
+               // tuple with named element. The array is built for top level
+               // type therefore it can contain multiple tuple types
+               //
+               // Example: Func<(int, int), int, (int a, int b)[]>
+               // Output: { null, null, "a", "b" }
+               //
+               static void BuildStringElements (TypeSpec type, List<string> names)
+               {
+                       while (type is ArrayContainer) {
+                               type = ((ArrayContainer)type).Element;
+                       }
+
+                       var nts = type as NamedTupleSpec;
+                       if (nts != null) {
+                               names.AddRange (nts.Elements);
+                       } else {
+                               for (int i = 0; i < type.Arity; ++i) {
+                                       names.Add (null);
+                               }
+                       }
+
+                       foreach (var ta in type.TypeArguments) {
+                               BuildStringElements (ta, names);
+                       }
+               }
+       }
 }