Implement partial generic methods
[mono.git] / mcs / mcs / method.cs
index 343670bd83c6a94185c86ac9cb31b0f17b871717..22f73d5cef7570a2234b427249c7e3fd85f4a37c 100644 (file)
@@ -188,7 +188,7 @@ namespace Mono.CSharp {
                }
        }
 
-       public interface IGenericMethodDefinition : IMemberDefinition
+       public interface IGenericMethodDefinition : IMethodDefinition
        {
                TypeParameterSpec[] TypeParameters { get; }
                int TypeParametersCount { get; }
@@ -198,18 +198,17 @@ namespace Mono.CSharp {
 
        public sealed class MethodSpec : MemberSpec, IParametersMember
        {
-               MethodBase metaInfo, inflatedMetaInfo;
+               MethodBase inflatedMetaInfo;
                AParametersCollection parameters;
                TypeSpec returnType;
 
                TypeSpec[] targs;
                TypeParameterSpec[] constraints;
 
-               public MethodSpec (MemberKind kind, TypeSpec declaringType, IMemberDefinition details, TypeSpec returnType,
-                       MethodBase info, AParametersCollection parameters, Modifiers modifiers)
+               public MethodSpec (MemberKind kind, TypeSpec declaringType, IMethodDefinition details, TypeSpec returnType,
+                       AParametersCollection parameters, Modifiers modifiers)
                        : base (kind, declaringType, details, modifiers)
                {
-                       this.metaInfo = info;
                        this.parameters = parameters;
                        this.returnType = returnType;
                }
@@ -237,6 +236,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               public new IMethodDefinition MemberDefinition {
+                       get {
+                               return (IMethodDefinition) definition;
+                       }
+               }
+
                public IGenericMethodDefinition GenericDefinition {
                        get {
                                return (IGenericMethodDefinition) definition;
@@ -322,21 +327,21 @@ namespace Mono.CSharp {
 
                                        if (DeclaringType.IsTypeBuilder) {
                                                if (IsConstructor)
-                                                       inflatedMetaInfo = TypeBuilder.GetConstructor (dt_meta, (ConstructorInfo) metaInfo);
+                                                       inflatedMetaInfo = TypeBuilder.GetConstructor (dt_meta, (ConstructorInfo) MemberDefinition.Metadata);
                                                else
-                                                       inflatedMetaInfo = TypeBuilder.GetMethod (dt_meta, (MethodInfo) metaInfo);
+                                                       inflatedMetaInfo = TypeBuilder.GetMethod (dt_meta, (MethodInfo) MemberDefinition.Metadata);
                                        } else {
 #if STATIC
                                                // it should not be reached
                                                throw new NotImplementedException ();
 #else
-                                               inflatedMetaInfo = MethodInfo.GetMethodFromHandle (metaInfo.MethodHandle, dt_meta.TypeHandle);
+                                               inflatedMetaInfo = MethodInfo.GetMethodFromHandle (MemberDefinition.Metadata.MethodHandle, dt_meta.TypeHandle);
 #endif
                                        }
 
                                        state &= ~StateFlags.PendingMetaInflate;
                                } else {
-                                       inflatedMetaInfo = metaInfo;
+                                       inflatedMetaInfo = MemberDefinition.Metadata;
                                }
                        }
 
@@ -518,19 +523,10 @@ namespace Mono.CSharp {
 
                        return missing;                 
                }
-
-               public void SetMetaInfo (MethodInfo info)
-               {
-                       if (this.metaInfo != null)
-                               throw new InternalErrorException ("MetaInfo reset");
-
-                       this.metaInfo = info;
-               }
        }
 
-       public abstract class MethodOrOperator : MethodCore, IMethodData
+       public abstract class MethodOrOperator : MethodCore, IMethodData, IMethodDefinition
        {
-               public MethodBuilder MethodBuilder;
                ReturnParameter return_attributes;
                SecurityType declarative_security;
                protected MethodData MethodData;
@@ -583,6 +579,19 @@ namespace Mono.CSharp {
                        }
                }
 
+               MethodBase IMethodDefinition.Metadata {
+                       get {
+                               return MethodData.MethodBuilder;
+                       }
+               }
+
+               // TODO: Remove and use MethodData abstraction
+               public MethodBuilder MethodBuilder {
+                       get {
+                               return MethodData.MethodBuilder;
+                       }
+               }
+
                protected override bool CheckForDuplications ()
                {
                        return Parent.MemberCache.CheckExistingMembersOverloads (this, parameters);
@@ -609,41 +618,34 @@ namespace Mono.CSharp {
                        else
                                kind = MemberKind.Method;
 
+                       string explicit_name;
+
                        if (IsPartialDefinition) {
                                caching_flags &= ~Flags.Excluded_Undetected;
                                caching_flags |= Flags.Excluded;
 
                                // Add to member cache only when a partial method implementation has not been found yet
-                               if ((caching_flags & Flags.PartialDefinitionExists) == 0) {
-//                                     MethodBase mb = new PartialMethodDefinitionInfo (this);
+                               if ((caching_flags & Flags.PartialDefinitionExists) != 0)
+                                       return true;
 
-                                       spec = new MethodSpec (kind, Parent.Definition, this, ReturnType, null, parameters, ModFlags);
-                                       if (MemberName.Arity > 0) {
-                                               spec.IsGeneric = true;
+                               if (IsExplicitImpl)
+                                       return true;
 
-                                               // TODO: Have to move DefineMethod after Define (ideally to Emit)
-                                               throw new NotImplementedException ("Generic partial methods");
-                                       }
+                               explicit_name = null;
+                       } else {
+                               MethodData = new MethodData (this, ModFlags, flags, this, base_method);
 
-                                       Parent.MemberCache.AddMember (spec);
-                               }
+                               if (!MethodData.Define (Parent.PartialContainer, GetFullName (MemberName)))
+                                       return false;
 
-                               return true;
+                               explicit_name = MethodData.MetadataName;
                        }
 
-                       MethodData = new MethodData (
-                               this, ModFlags, flags, this, MethodBuilder, base_method);
-
-                       if (!MethodData.Define (Parent.PartialContainer, GetFullName (MemberName)))
-                               return false;
-                                       
-                       MethodBuilder = MethodData.MethodBuilder;
-
-                       spec = new MethodSpec (kind, Parent.Definition, this, ReturnType, MethodBuilder, parameters, ModFlags);
+                       spec = new MethodSpec (kind, Parent.Definition, this, ReturnType, parameters, ModFlags);
                        if (MemberName.Arity > 0)
                                spec.IsGeneric = true;
-                       
-                       Parent.MemberCache.AddMember (this, MethodBuilder.Name, spec);
+
+                       Parent.MemberCache.AddMember (this, explicit_name, spec);
 
                        return true;
                }
@@ -798,6 +800,33 @@ namespace Mono.CSharp {
 
                #endregion
 
+               public virtual void PrepareEmit ()
+               {
+                       var mb = MethodData.DefineMethodBuilder (Parent);
+
+                       if (CurrentTypeParameters != null) {
+                               string[] gnames = new string[CurrentTypeParameters.Count];
+                               for (int i = 0; i < gnames.Length; ++i) {
+                                       gnames[i] = CurrentTypeParameters[i].Name;
+                               }
+
+                               var gen_params = MethodBuilder.DefineGenericParameters (gnames);
+
+                               for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
+                                       var tp = CurrentTypeParameters[i];
+
+                                       tp.Define (gen_params[i]);
+                               }
+                       }
+
+                       //
+                       // Generic method has been already defined to resolve method parameters
+                       // correctly when they use type parameters
+                       //
+                       mb.SetParameters (parameters.GetMetaInfo ());
+                       mb.SetReturnType (ReturnType.GetMetaInfo ());
+               }
+
                public override void WriteDebugSymbol (MonoSymbolFile file)
                {
                        if (MethodData != null)
@@ -844,7 +873,7 @@ namespace Mono.CSharp {
                        }
                }
 
-#endregion
+               #endregion
 
                public override void Accept (StructuralVisitor visitor)
                {
@@ -972,10 +1001,9 @@ namespace Mono.CSharp {
                void CreateTypeParameters ()
                {
                        var tparams = MemberName.TypeParameters;
-                       string[] snames = new string[MemberName.Arity];
                        var parent_tparams = Parent.TypeParametersAll;
 
-                       for (int i = 0; i < snames.Length; i++) {
+                       for (int i = 0; i < MemberName.Arity; i++) {
                                string type_argument_name = tparams[i].MemberName.Name;
 
                                if (block == null) {
@@ -1000,12 +1028,9 @@ namespace Mono.CSharp {
                                                tparams[i].WarningParentNameConflict (tp);
                                        }
                                }
-
-                               snames[i] = type_argument_name;
                        }
 
-                       GenericTypeParameterBuilder[] gen_params = MethodBuilder.DefineGenericParameters (snames);
-                       tparams.Define (gen_params, null, 0, Parent);
+                       tparams.Create (null, 0, Parent);
                }
 
                protected virtual void DefineTypeParameters ()
@@ -1171,9 +1196,6 @@ namespace Mono.CSharp {
                                        "Introducing `Finalize' method can interfere with destructor invocation. Did you intend to declare a destructor?");
                        }
 
-                       if (partialMethodImplementation != null && IsPartialDefinition)
-                               MethodBuilder = partialMethodImplementation.MethodBuilder;
-
                        if (Compiler.Settings.StdLib && ReturnType.IsSpecialRuntimeType) {
                                Error1599 (Location, ReturnType, Report);
                                return false;
@@ -1272,6 +1294,22 @@ namespace Mono.CSharp {
                        return true;
                }
 
+               public override void PrepareEmit ()
+               {
+                       if (IsPartialDefinition) {
+                               //
+                               // Use partial method implementation builder for partial method declaration attributes
+                               //
+                               if (partialMethodImplementation != null) {
+                                       MethodData = partialMethodImplementation.MethodData;
+                               }
+
+                               return;
+                       }
+
+                       base.PrepareEmit ();
+               }
+
                //
                // Emits the code
                // 
@@ -1279,11 +1317,8 @@ namespace Mono.CSharp {
                {
                        try {
                                if (IsPartialDefinition) {
-                                       //
-                                       // Use partial method implementation builder for partial method declaration attributes
-                                       //
-                                       if (partialMethodImplementation != null) {
-                                               MethodBuilder = partialMethodImplementation.MethodBuilder;
+                                       if (partialMethodImplementation != null && CurrentTypeParameters != null) {
+                                               CurrentTypeParameters.CheckPartialConstraints (partialMethodImplementation);
                                        }
 
                                        return;
@@ -1297,11 +1332,15 @@ namespace Mono.CSharp {
                                if (CurrentTypeParameters != null) {
                                        for (int i = 0; i < CurrentTypeParameters.Count; ++i) {
                                                var tp = CurrentTypeParameters [i];
+
                                                tp.CheckGenericConstraints (false);
                                                tp.Emit ();
                                        }
                                }
 
+                               if (IsExplicitImpl)
+                                       MethodData.DefineOverride (Parent);
+
                                if (block != null && block.StateMachine is AsyncTaskStorey) {
                                        var psm = Module.PredefinedAttributes.AsyncStateMachine;
                                        
@@ -1312,10 +1351,8 @@ namespace Mono.CSharp {
                                        Module.PredefinedAttributes.Extension.EmitAttribute (MethodBuilder);
 
                                base.Emit ();
-                       } catch {
-                               Console.WriteLine ("Internal compiler error at {0}: exception caught while emitting {1}",
-                                                  Location, MethodBuilder);
-                               throw;
+                       } catch (Exception e) {
+                               throw new InternalErrorException (this, e);
                        }
                }
 
@@ -1335,7 +1372,6 @@ namespace Mono.CSharp {
                protected override bool ResolveMemberType ()
                {
                        if (CurrentTypeParameters != null) {
-                               MethodBuilder = Parent.TypeBuilder.DefineMethod (GetFullName (MemberName), flags);
                                CreateTypeParameters ();
                        }
 
@@ -1485,7 +1521,7 @@ namespace Mono.CSharp {
                }
        }
        
-       public class Constructor : MethodCore, IMethodData
+       public class Constructor : MethodCore, IMethodData, IMethodDefinition
        {
                public ConstructorBuilder ConstructorBuilder;
                public ConstructorInitializer Initializer;
@@ -1533,6 +1569,13 @@ namespace Mono.CSharp {
                    }
                }
 
+               
+               MethodBase IMethodDefinition.Metadata {
+                       get {
+                               return ConstructorBuilder;
+                       }
+               }
+
                //
                // Returns true if this is a default constructor
                //
@@ -1620,7 +1663,7 @@ namespace Mono.CSharp {
                                ca, CallingConventions,
                                parameters.GetMetaInfo ());
 
-                       spec = new MethodSpec (MemberKind.Constructor, Parent.Definition, this, Compiler.BuiltinTypes.Void, ConstructorBuilder, parameters, ModFlags);
+                       spec = new MethodSpec (MemberKind.Constructor, Parent.Definition, this, Compiler.BuiltinTypes.Void, parameters, ModFlags);
                        
                        Parent.MemberCache.AddMember (spec);
                        
@@ -1828,10 +1871,6 @@ namespace Mono.CSharp {
        //
        public class MethodData
        {
-#if !STATIC
-               static FieldInfo methodbuilder_attrs_field;
-#endif
-
                public readonly IMethodData method;
 
                //
@@ -1848,6 +1887,7 @@ namespace Mono.CSharp {
                protected TypeSpec declaring_type;
                protected MethodSpec parent_method;
                SourceMethodBuilder debug_builder;
+               string full_name;
 
                MethodBuilder builder;
                public MethodBuilder MethodBuilder {
@@ -1862,6 +1902,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               public string MetadataName {
+                       get {
+                               return full_name;
+                       }
+               }
+
                public MethodData (InterfaceMemberBase member,
                                   Modifiers modifiers, MethodAttributes flags, IMethodData method)
                {
@@ -1874,11 +1920,10 @@ namespace Mono.CSharp {
 
                public MethodData (InterfaceMemberBase member,
                                   Modifiers modifiers, MethodAttributes flags, 
-                                  IMethodData method, MethodBuilder builder,
+                                  IMethodData method,
                                   MethodSpec parent_method)
                        : this (member, modifiers, flags, method)
                {
-                       this.builder = builder;
                        this.parent_method = parent_method;
                }
 
@@ -2033,58 +2078,45 @@ namespace Mono.CSharp {
                                        method_full_name = implementing.MemberDefinition.Name;
                        }
 
-                       DefineMethodBuilder (container, method_full_name, method.ParameterInfo);
+                       full_name = method_full_name;
+                       declaring_type = container.Definition;
 
-                       if (builder == null)
-                               return false;
+                       return true;
+               }
 
-//                     if (container.CurrentType != null)
-//                             declaring_type = container.CurrentType;
-//                     else
-                               declaring_type = container.Definition;
+               public void DefineOverride (TypeDefinition container)
+               {
+                       if (implementing == null)
+                               return;
 
-                       if (implementing != null && member.IsExplicitImpl) {
-                               container.TypeBuilder.DefineMethodOverride (builder, (MethodInfo) implementing.GetMetaInfo ());
-                       }
+                       if (!member.IsExplicitImpl)
+                               return;
 
-                       return true;
+                       container.TypeBuilder.DefineMethodOverride (builder, (MethodInfo) implementing.GetMetaInfo ());
                }
 
-
-               /// <summary>
-               /// Create the MethodBuilder for the method 
-               /// </summary>
-               void DefineMethodBuilder (TypeDefinition container, string method_name, ParametersCompiled param)
+               //
+               // Creates partial MethodBuilder for the method when has generic parameters used
+               // as arguments or return type
+               //
+               public MethodBuilder DefineMethodBuilder (TypeDefinition container)
                {
-                       var return_type = method.ReturnType.GetMetaInfo ();
-                       var p_types = param.GetMetaInfo ();
+                       if (builder != null)
+                               throw new InternalErrorException ();
 
-                       if (builder == null) {
-                               builder = container.TypeBuilder.DefineMethod (
-                                       method_name, flags, method.CallingConventions,
-                                       return_type, p_types);
-                               return;
-                       }
+                       builder = container.TypeBuilder.DefineMethod (full_name, flags, method.CallingConventions);
+                       return builder;
+               }
 
-                       //
-                       // Generic method has been already defined to resolve method parameters
-                       // correctly when they use type parameters
-                       //
-                       builder.SetParameters (p_types);
-                       builder.SetReturnType (return_type);
-                       if (builder.Attributes != flags) {
-#if STATIC
-                               builder.__SetAttributes (flags);
-#else
-                               try {
-                                       if (methodbuilder_attrs_field == null)
-                                               methodbuilder_attrs_field = typeof (MethodBuilder).GetField ("attrs", BindingFlags.NonPublic | BindingFlags.Instance);
-                                       methodbuilder_attrs_field.SetValue (builder, flags);
-                               } catch {
-                                       container.Compiler.Report.RuntimeMissingSupport (method.Location, "Generic method MethodAttributes");
-                               }
-#endif
-                       }
+               //
+               // Creates full MethodBuilder for the method 
+               //
+               public MethodBuilder DefineMethodBuilder (TypeDefinition container, ParametersCompiled param)
+               {
+                       DefineMethodBuilder (container);
+                       builder.SetReturnType (method.ReturnType.GetMetaInfo ());
+                       builder.SetParameters (param.GetMetaInfo ());
+                       return builder;
                }
 
                //
@@ -2092,6 +2124,8 @@ namespace Mono.CSharp {
                // 
                public void Emit (TypeDefinition parent)
                {
+                       DefineOverride (parent);
+
                        var mc = (IMemberContext) method;
 
                        method.ParameterInfo.ApplyAttributes (mc, MethodBuilder);
@@ -2226,7 +2260,7 @@ namespace Mono.CSharp {
 
        // Ooouh Martin, templates are missing here.
        // When it will be possible move here a lot of child code and template method type.
-       public abstract class AbstractPropertyEventMethod : MemberCore, IMethodData {
+       public abstract class AbstractPropertyEventMethod : MemberCore, IMethodData, IMethodDefinition {
                protected MethodData method_data;
                protected ToplevelBlock block;
                protected SecurityType declarative_security;
@@ -2292,6 +2326,12 @@ namespace Mono.CSharp {
                        }
                }
 
+               MethodBase IMethodDefinition.Metadata {
+                       get {
+                               return method_data.MethodBuilder;
+                       }
+               }
+
                public abstract ParametersCompiled ParameterInfo { get ; }
                public abstract TypeSpec ReturnType { get; }