Try to recover from invalid attribute. Fixes #8590
[mono.git] / mcs / mcs / delegate.cs
index cd355eb53ae8a6cd0767075336e5921cf36ba600..a73c9f68c75cb81a94973da5046804f9d6c7163e 100644 (file)
@@ -436,12 +436,14 @@ namespace Mono.CSharp {
                protected MethodSpec constructor_method;
                protected MethodGroupExpr method_group;
 
+               public bool AllowSpecialMethodsInvocation { get; set; }
+
                public override bool ContainsEmitWithAwait ()
                {
                        return false;
                }
 
-               public static Arguments CreateDelegateMethodArguments (AParametersCollection pd, TypeSpec[] types, Location loc)
+               public static Arguments CreateDelegateMethodArguments (ResolveContext rc, AParametersCollection pd, TypeSpec[] types, Location loc)
                {
                        Arguments delegate_arguments = new Arguments (pd.Count);
                        for (int i = 0; i < pd.Count; ++i) {
@@ -458,7 +460,11 @@ namespace Mono.CSharp {
                                        break;
                                }
 
-                               delegate_arguments.Add (new Argument (new TypeExpression (types [i], loc), atype_modifier));
+                               var ptype = types[i];
+                               if (ptype.BuiltinType == BuiltinTypeSpec.Type.Dynamic)
+                                       ptype = rc.BuiltinTypes.Object;
+
+                               delegate_arguments.Add (new Argument (new TypeExpression (ptype, loc), atype_modifier));
                        }
 
                        return delegate_arguments;
@@ -494,7 +500,7 @@ namespace Mono.CSharp {
 
                        var invoke_method = Delegate.GetInvokeMethod (type);
 
-                       Arguments arguments = CreateDelegateMethodArguments (invoke_method.Parameters, invoke_method.Parameters.Types, loc);
+                       Arguments arguments = CreateDelegateMethodArguments (ec, invoke_method.Parameters, invoke_method.Parameters.Types, loc);
                        method_group = method_group.OverloadResolve (ec, ref arguments, this, OverloadResolver.Restrictions.CovariantDelegate);
                        if (method_group == null)
                                return null;
@@ -507,7 +513,8 @@ namespace Mono.CSharp {
                                return null;
                        }               
                        
-                       Invocation.IsSpecialMethodInvocation (ec, delegate_method, loc);
+                       if (!AllowSpecialMethodsInvocation)
+                               Invocation.IsSpecialMethodInvocation (ec, delegate_method, loc);
 
                        ExtensionMethodGroupExpr emg = method_group as ExtensionMethodGroupExpr;
                        if (emg != null) {
@@ -602,7 +609,7 @@ namespace Mono.CSharp {
 
                        var invoke = Delegate.GetInvokeMethod (target_type);
 
-                       Arguments arguments = CreateDelegateMethodArguments (invoke.Parameters, invoke.Parameters.Types, mg.Location);
+                       Arguments arguments = CreateDelegateMethodArguments (ec, invoke.Parameters, invoke.Parameters.Types, mg.Location);
                        return mg.OverloadResolve (ec, ref arguments, null, OverloadResolver.Restrictions.CovariantDelegate | OverloadResolver.Restrictions.ProbingOnly) != null;
                }
 
@@ -638,18 +645,92 @@ namespace Mono.CSharp {
        //
        public class ImplicitDelegateCreation : DelegateCreation
        {
-               ImplicitDelegateCreation (TypeSpec t, MethodGroupExpr mg, Location l)
+               Field mg_cache;
+
+               public ImplicitDelegateCreation (TypeSpec delegateType, MethodGroupExpr mg, Location loc)
                {
-                       type = t;
+                       type = delegateType;
                        this.method_group = mg;
-                       loc = l;
+                       this.loc = loc;
+               }
+
+               //
+               // Returns true when type is MVAR or has MVAR reference
+               //
+               static bool ContainsMethodTypeParameter (TypeSpec type)
+               {
+                       var tps = type as TypeParameterSpec;
+                       if (tps != null)
+                               return tps.IsMethodOwned;
+
+                       var ec = type as ElementTypeSpec;
+                       if (ec != null)
+                               return ContainsMethodTypeParameter (ec.Element);
+
+                       foreach (var t in type.TypeArguments) {
+                               if (ContainsMethodTypeParameter (t)) {
+                                       return true;
+                               }
+                       }
+
+                       return false;
                }
 
-               static public Expression Create (ResolveContext ec, MethodGroupExpr mge,
-                                                TypeSpec target_type, Location loc)
+               protected override Expression DoResolve (ResolveContext ec)
                {
-                       ImplicitDelegateCreation d = new ImplicitDelegateCreation (target_type, mge, loc);
-                       return d.DoResolve (ec);
+                       var expr = base.DoResolve (ec);
+                       if (expr == null)
+                               return null;
+
+                       if (ec.IsInProbingMode)
+                               return expr;
+
+                       //
+                       // Cache any static delegate creation
+                       //
+                       if (method_group.InstanceExpression != null)
+                               return expr;
+
+                       //
+                       // Cannot easily cache types with MVAR
+                       //
+                       if (ContainsMethodTypeParameter (type))
+                               return expr;
+
+                       if (ContainsMethodTypeParameter (method_group.BestCandidate.DeclaringType))
+                               return expr;
+
+                       //
+                       // Create type level cache for a delegate instance
+                       //
+                       var parent = ec.CurrentMemberDefinition.Parent.PartialContainer;
+                       int id = parent.MethodGroupsCounter++;
+
+                       mg_cache = new Field (parent, new TypeExpression (type, loc),
+                               Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
+                               new MemberName (CompilerGeneratedContainer.MakeName (null, "f", "mg$cache", id), loc), null);
+                       mg_cache.Define ();
+                       parent.AddField (mg_cache);
+
+                       return expr;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       Label l_initialized = ec.DefineLabel ();
+
+                       if (mg_cache != null) {
+                               ec.Emit (OpCodes.Ldsfld, mg_cache.Spec);
+                               ec.Emit (OpCodes.Brtrue_S, l_initialized);
+                       }
+
+                       base.Emit (ec);
+
+                       if (mg_cache != null) {
+                               ec.Emit (OpCodes.Stsfld, mg_cache.Spec);
+                               ec.MarkLabel (l_initialized);
+                               ec.Emit (OpCodes.Ldsfld, mg_cache.Spec);
+                       }
                }
        }