[mcs] C# 7 tuple (foundation only).
[mono.git] / mcs / mcs / import.cs
index dbec2c0469f603bce116c228d4a3252b2abc85be..719ba23952cd714f0021ef68335b081af7a94640 100644 (file)
@@ -30,15 +30,18 @@ namespace Mono.CSharp
        public abstract class MetadataImporter
        {
                //
-               // Dynamic types reader with additional logic to reconstruct a dynamic
-               // type using DynamicAttribute values
+               // Types reader with additional logic to reconstruct extra
+               // type information encoded in custom attributes values
                //
-               protected struct DynamicTypeReader
+               protected struct AttributesTypeInfoReader
                {
                        static readonly bool[] single_attribute = { true };
 
-                       public int Position;
-                       bool[] flags;
+                       public int DynamicPosition;
+                       bool[] dynamicFlags;
+
+                       public int TuplePosition;
+                       string[] tupleNames;
 
                        // There is no common type for CustomAttributeData and we cannot
                        // use ICustomAttributeProvider
@@ -47,10 +50,12 @@ namespace Mono.CSharp
                        //
                        // A member provider which can be used to get CustomAttributeData
                        //
-                       public DynamicTypeReader (object provider)
+                       public AttributesTypeInfoReader (object provider)
                        {
-                               Position = 0;
-                               flags = null;
+                               DynamicPosition = 0;
+                               TuplePosition = 0;
+                               dynamicFlags = null;
+                               tupleNames = null;
                                this.provider = provider;
                        }
 
@@ -62,7 +67,7 @@ namespace Mono.CSharp
                                if (provider != null)
                                        ReadAttribute ();
 
-                               return flags != null && Position < flags.Length && flags[Position];
+                               return dynamicFlags != null && DynamicPosition < dynamicFlags.Length && dynamicFlags [DynamicPosition];
                        }
 
                        //
@@ -73,7 +78,34 @@ namespace Mono.CSharp
                                if (provider != null)
                                        ReadAttribute ();
 
-                               return flags != null;
+                               return dynamicFlags != null;
+                       }
+
+                       public bool HasNamedTupleAttribute ()
+                       {
+                               if (provider != null)
+                                       ReadAttribute ();
+
+                               return tupleNames != null;
+                       }
+
+                       public IList<string> GetNamedTupleElements (int length)
+                       {
+                               if (TuplePosition == 0 && length == tupleNames.Length)
+                                       return tupleNames;
+
+                               for (int i = TuplePosition; i < length + TuplePosition; ++i) {
+                                       if (tupleNames [i] != null) {
+                                               var res = new string [length];
+                                               Array.Copy (tupleNames, TuplePosition, res, 0, length);
+                                               return res;
+                                       }
+                               }
+
+                               //
+                               // Current range can be just padding
+                               //
+                               return null;
                        }
 
                        IList<CustomAttributeData> GetCustomAttributes ()
@@ -100,22 +132,40 @@ namespace Mono.CSharp
                                if (cad.Count > 0) {
                                        foreach (var ca in cad) {
                                                var dt = ca.Constructor.DeclaringType;
-                                               if (dt.Name != "DynamicAttribute" || dt.Namespace != CompilerServicesNamespace)
+                                               if (dt.Namespace != CompilerServicesNamespace)
                                                        continue;
 
-                                               if (ca.ConstructorArguments.Count == 0) {
-                                                       flags = single_attribute;
-                                                       break;
-                                               }
+                                               switch (dt.Name) {
+                                               case "DynamicAttribute":
+                                                       if (ca.ConstructorArguments.Count == 0) {
+                                                               dynamicFlags = single_attribute;
+                                                               break;
+                                                       }
 
-                                               var arg_type = ca.ConstructorArguments[0].ArgumentType;
+                                                       var arg_type = ca.ConstructorArguments [0].ArgumentType;
 
-                                               if (arg_type.IsArray && MetaType.GetTypeCode (arg_type.GetElementType ()) == TypeCode.Boolean) {
-                                                       var carg = (IList<CustomAttributeTypedArgument>) ca.ConstructorArguments[0].Value;
-                                                       flags = new bool[carg.Count];
-                                                       for (int i = 0; i < flags.Length; ++i) {
-                                                               if (MetaType.GetTypeCode (carg[i].ArgumentType) == TypeCode.Boolean)
-                                                                       flags[i] = (bool) carg[i].Value;
+                                                       if (arg_type.IsArray && MetaType.GetTypeCode (arg_type.GetElementType ()) == TypeCode.Boolean) {
+                                                               var carg = (IList<CustomAttributeTypedArgument>)ca.ConstructorArguments [0].Value;
+                                                               dynamicFlags = new bool [carg.Count];
+                                                               for (int i = 0; i < dynamicFlags.Length; ++i) {
+                                                                       if (MetaType.GetTypeCode (carg [i].ArgumentType) == TypeCode.Boolean)
+                                                                               dynamicFlags [i] = (bool)carg [i].Value;
+                                                               }
+                                                       }
+
+                                                       break;
+                                               case "TupleElementNamesAttribute":
+                                                       if (ca.ConstructorArguments.Count != 1)
+                                                               break;
+
+                                                       var tuple_arg_type = ca.ConstructorArguments [0].ArgumentType;
+                                                       if (tuple_arg_type.IsArray && MetaType.GetTypeCode (tuple_arg_type.GetElementType ()) == TypeCode.String) {
+                                                               var carg = (IList<CustomAttributeTypedArgument>)ca.ConstructorArguments [0].Value;
+                                                               tupleNames = new string [carg.Count];
+                                                               for (int i = 0; i < tupleNames.Length; ++i) {
+                                                                       if (MetaType.GetTypeCode (carg [i].ArgumentType) == TypeCode.String)
+                                                                               tupleNames [i] = (string)carg [i].Value;
+                                                               }
                                                        }
 
                                                        break;
@@ -195,7 +245,7 @@ namespace Mono.CSharp
                        TypeSpec field_type;
 
                        try {
-                               field_type = ImportType (fi.FieldType, new DynamicTypeReader (fi), declaringType);
+                               field_type = ImportType (fi.FieldType, new AttributesTypeInfoReader (fi), declaringType);
 
                                //
                                // Private field has private type which is not fixed buffer
@@ -275,7 +325,7 @@ namespace Mono.CSharp
                        if (add.Modifiers != remove.Modifiers)
                                throw new NotImplementedException ("Different accessor modifiers " + ei.Name);
 
-                       var event_type = ImportType (ei.EventHandlerType, new DynamicTypeReader (ei), declaringType);
+                       var event_type = ImportType (ei.EventHandlerType, new AttributesTypeInfoReader (ei), declaringType);
                        var definition = new ImportedMemberDefinition (ei, event_type,  this);
                        return new EventSpec (declaringType, definition, event_type, add.Modifiers, add, remove);
                }
@@ -327,15 +377,15 @@ namespace Mono.CSharp
                                var type = tparams[pos];
                                int index = pos - first;
 
-                               tspec[index] = (TypeParameterSpec) CreateType (type, new DynamicTypeReader (), false);
+                               tspec[index] = (TypeParameterSpec) CreateType (type, new AttributesTypeInfoReader (), false);
                        }
 
                        return tspec;
                }
 
-               TypeSpec[] CreateGenericArguments (int first, MetaType[] tparams, DynamicTypeReader dtype)
+               TypeSpec[] CreateGenericArguments (int first, MetaType[] tparams, AttributesTypeInfoReader dtype)
                {
-                       ++dtype.Position;
+                       ++dtype.DynamicPosition;
 
                        var tspec = new TypeSpec [tparams.Length - first];
                        for (int pos = first; pos < tparams.Length; ++pos) {
@@ -345,7 +395,7 @@ namespace Mono.CSharp
                                TypeSpec spec;
                                if (type.HasElementType) {
                                        var element = type.GetElementType ();
-                                       ++dtype.Position;
+                                       ++dtype.DynamicPosition;
                                        spec = ImportType (element, dtype, null);
 
                                        if (!type.IsArray) {
@@ -374,7 +424,7 @@ namespace Mono.CSharp
                                if (spec == null)
                                        return null;
 
-                               ++dtype.Position;
+                               ++dtype.DynamicPosition;
                                tspec[index] = spec;
                        }
 
@@ -415,7 +465,7 @@ namespace Mono.CSharp
                                returnType = module.Compiler.BuiltinTypes.Void;
                        } else {
                                var mi = (MethodInfo)mb;
-                               returnType = ImportType (mi.ReturnType, new DynamicTypeReader (mi.ReturnParameter), declaringType);
+                               returnType = ImportType (mi.ReturnType, new AttributesTypeInfoReader (mi.ReturnParameter), declaringType);
 
                                //
                                // Detect operators and destructors
@@ -545,13 +595,13 @@ namespace Mono.CSharp
                                        // Strip reference wrapping
                                        //
                                        var el = p.ParameterType.GetElementType ();
-                                       types[i] = ImportType (el, new DynamicTypeReader (p), parent);  // TODO: 1-based positio to be csc compatible
+                                       types[i] = ImportType (el, new AttributesTypeInfoReader (p), parent);   // TODO: 1-based positio to be csc compatible
                                } else if (i == 0 && method.IsStatic && (parent.Modifiers & Modifiers.METHOD_EXTENSION) != 0 &&
                                        HasAttribute (CustomAttributeData.GetCustomAttributes (method), "ExtensionAttribute", CompilerServicesNamespace)) {
                                        mod = Parameter.Modifier.This;
-                                       types[i] = ImportType (p.ParameterType, new DynamicTypeReader (p), parent);
+                                       types[i] = ImportType (p.ParameterType, new AttributesTypeInfoReader (p), parent);
                                } else {
-                                       types[i] = ImportType (p.ParameterType, new DynamicTypeReader (p), parent);
+                                       types[i] = ImportType (p.ParameterType, new AttributesTypeInfoReader (p), parent);
 
                                        if (i >= pi.Length - 2 && types[i] is ArrayContainer) {
                                                if (HasAttribute (CustomAttributeData.GetCustomAttributes (p), "ParamArrayAttribute", "System")) {
@@ -734,26 +784,26 @@ namespace Mono.CSharp
 
                public TypeSpec CreateType (MetaType type)
                {
-                       return CreateType (type, new DynamicTypeReader (), true);
+                       return CreateType (type, new AttributesTypeInfoReader (), true);
                }
 
                public TypeSpec CreateNestedType (MetaType type, TypeSpec declaringType)
                {
-                       return CreateType (type, declaringType, new DynamicTypeReader (type), false);
+                       return CreateType (type, declaringType, new AttributesTypeInfoReader (type), false);
                }
 
-               TypeSpec CreateType (MetaType type, DynamicTypeReader dtype, bool canImportBaseType)
+               TypeSpec CreateType (MetaType type, AttributesTypeInfoReader dtype, bool canImportBaseType)
                {
                        TypeSpec declaring_type;
                        if (type.IsNested && !type.IsGenericParameter)
-                               declaring_type = CreateType (type.DeclaringType, new DynamicTypeReader (type.DeclaringType), true);
+                               declaring_type = CreateType (type.DeclaringType, new AttributesTypeInfoReader (type.DeclaringType), true);
                        else
                                declaring_type = null;
 
                        return CreateType (type, declaring_type, dtype, canImportBaseType);
                }
 
-               protected TypeSpec CreateType (MetaType type, TypeSpec declaringType, DynamicTypeReader dtype, bool canImportBaseType)
+               protected TypeSpec CreateType (MetaType type, TypeSpec declaringType, AttributesTypeInfoReader dtype, bool canImportBaseType)
                {
                        TypeSpec spec;
                        if (import_cache.TryGetValue (type, out spec)) {
@@ -796,7 +846,7 @@ namespace Mono.CSharp
                                        return null;
                                if (declaringType == null) {
                                        // Simple case, no nesting
-                                       spec = CreateType (type_def, null, new DynamicTypeReader (), canImportBaseType);
+                                       spec = CreateType (type_def, null, new AttributesTypeInfoReader (), canImportBaseType);
                                        spec = spec.MakeGenericType (module, targs);
                                } else {
                                        //
@@ -851,6 +901,14 @@ namespace Mono.CSharp
                                        }
                                }
 
+                               if (spec.IsTupleType && dtype.HasNamedTupleAttribute ()) {
+                                       var names = dtype.GetNamedTupleElements (spec.Arity);
+                                       if (names != null)
+                                               return NamedTupleSpec.MakeType (module, (InflatedTypeSpec) spec, names);
+
+                                       dtype.TuplePosition += spec.Arity;
+                               }
+
                                // Don't add generic type with dynamic arguments, they can interfere with same type
                                // using object type arguments
                                if (!spec.HasDynamicElement) {
@@ -1071,7 +1129,7 @@ namespace Mono.CSharp
                        else if (type.BaseType != null) {
                                TypeSpec base_type;
                                if (!IsMissingType (type.BaseType) && type.BaseType.IsGenericType)
-                                       base_type = CreateType (type.BaseType, new DynamicTypeReader (type), true);
+                                       base_type = CreateType (type.BaseType, new AttributesTypeInfoReader (type), true);
                                else
                                        base_type = CreateType (type.BaseType);
 
@@ -1100,7 +1158,7 @@ namespace Mono.CSharp
                                if (t.Name[0] == '<')
                                        continue;
 
-                               var it = CreateType (t, null, new DynamicTypeReader (t), true);
+                               var it = CreateType (t, null, new AttributesTypeInfoReader (t), true);
                                if (it == null)
                                        continue;
 
@@ -1192,14 +1250,14 @@ namespace Mono.CSharp
 
                public TypeSpec ImportType (MetaType type)
                {
-                       return ImportType (type, new DynamicTypeReader (type), null);
+                       return ImportType (type, new AttributesTypeInfoReader (type), null);
                }
 
-               TypeSpec ImportType (MetaType type, DynamicTypeReader dtype, TypeSpec currentType)
+               TypeSpec ImportType (MetaType type, AttributesTypeInfoReader dtype, TypeSpec currentType)
                {
                        if (type.HasElementType) {
                                var element = type.GetElementType ();
-                               ++dtype.Position;
+                               ++dtype.DynamicPosition;
                                var spec = ImportType (element, dtype, currentType);
 
                                if (type.IsArray)