[mcs] Initial by ref returns and variables support
[mono.git] / mcs / mcs / delegate.cs
index 56fb8d6d43cf8f7f936f162408d63f139d06c034..80eb7e265f1395bec67ce6ba117212b0474a80b5 100644 (file)
@@ -101,9 +101,7 @@ namespace Mono.CSharp {
                public override void ApplyAttributeBuilder (Attribute a, MethodSpec ctor, byte[] cdata, PredefinedAttributes pa)
                {
                        if (a.Target == AttributeTargets.ReturnValue) {
-                               if (return_attributes == null)
-                                       return_attributes = new ReturnParameter (this, InvokeBuilder.MethodBuilder, Location);
-
+                               CreateReturnBuilder ();
                                return_attributes.ApplyAttributeBuilder (a, ctor, cdata, pa);
                                return;
                        }
@@ -122,6 +120,11 @@ namespace Mono.CSharp {
                        }
                }
 
+               ReturnParameter CreateReturnBuilder ()
+               {
+                       return return_attributes ?? (return_attributes = new ReturnParameter (this, InvokeBuilder.MethodBuilder, Location));
+               }
+
                protected override bool DoDefineMembers ()
                {
                        var builtin_types = Compiler.BuiltinTypes;
@@ -308,6 +311,8 @@ namespace Mono.CSharp {
 
                        InvokeBuilder.PrepareEmit ();
                        if (BeginInvokeBuilder != null) {
+                               BeginInvokeBuilder.TypeExpression = null;
+                               EndInvokeBuilder.TypeExpression = null;
                                BeginInvokeBuilder.PrepareEmit ();
                                EndInvokeBuilder.PrepareEmit ();
                        }
@@ -327,13 +332,16 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       if (ReturnType.Type != null) {
-                               if (ReturnType.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
-                                       return_attributes = new ReturnParameter (this, InvokeBuilder.MethodBuilder, Location);
-                                       Module.PredefinedAttributes.Dynamic.EmitAttribute (return_attributes.Builder);
-                               } else if (ReturnType.Type.HasDynamicElement) {
-                                       return_attributes = new ReturnParameter (this, InvokeBuilder.MethodBuilder, Location);
-                                       Module.PredefinedAttributes.Dynamic.EmitAttribute (return_attributes.Builder, ReturnType.Type, Location);
+                       var rtype = ReturnType.Type;
+                       if (rtype != null) {
+                               if (rtype.BuiltinType == BuiltinTypeSpec.Type.Dynamic) {
+                                       Module.PredefinedAttributes.Dynamic.EmitAttribute (CreateReturnBuilder ().Builder);
+                               } else if (rtype.HasDynamicElement) {
+                                       Module.PredefinedAttributes.Dynamic.EmitAttribute (CreateReturnBuilder ().Builder, rtype, Location);
+                               }
+
+                               if (rtype.HasNamedTupleElement) {
+                                       Module.PredefinedAttributes.TupleElementNames.EmitAttribute (CreateReturnBuilder ().Builder, rtype, Location);
                                }
 
                                ConstraintChecker.Check (this, ReturnType.Type, ReturnType.Location);
@@ -457,7 +465,6 @@ namespace Mono.CSharp {
        //
        public abstract class DelegateCreation : Expression, OverloadResolver.IErrorHandler
        {
-               bool conditional_access_receiver;
                protected MethodSpec constructor_method;
                protected MethodGroupExpr method_group;
 
@@ -498,9 +505,7 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
-                       MemberAccess ma = new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "Delegate", loc), "CreateDelegate", loc);
-
-                       Arguments args = new Arguments (3);
+                       Arguments args = new Arguments (2);
                        args.Add (new Argument (new TypeOf (type, loc)));
 
                        if (method_group.InstanceExpression == null)
@@ -508,7 +513,21 @@ namespace Mono.CSharp {
                        else
                                args.Add (new Argument (method_group.InstanceExpression));
 
-                       args.Add (new Argument (method_group.CreateExpressionTree (ec)));
+                       Expression ma;
+                       var create_v45 = ec.Module.PredefinedMembers.MethodInfoCreateDelegate.Get ();
+                       if (create_v45 != null) {
+                               //
+                               // .NET 4.5 has better API but it produces different instance than Delegate::CreateDelegate
+                               // and because csc uses this enhancement we have to as well to be fully compatible
+                               //
+                               var mg = MethodGroupExpr.CreatePredefined (create_v45, create_v45.DeclaringType, loc);
+                               mg.InstanceExpression = method_group.CreateExpressionTree (ec);
+                               ma = mg;
+                       } else {
+                               ma = new MemberAccess (new MemberAccess (new QualifiedAliasMember ("global", "System", loc), "Delegate", loc), "CreateDelegate", loc);
+                               args.Add (new Argument (method_group.CreateExpressionTree (ec)));
+                       }
+
                        Expression e = new Invocation (ma, args).Resolve (ec);
                        if (e == null)
                                return null;
@@ -520,25 +539,25 @@ namespace Mono.CSharp {
                        return e.CreateExpressionTree (ec);
                }
 
+               void ResolveConditionalAccessReceiver (ResolveContext rc)
+               {
+                       // LAMESPEC: Not sure why this is explicitly disallowed with very odd error message
+                       if (!rc.HasSet (ResolveContext.Options.DontSetConditionalAccessReceiver) && method_group.HasConditionalAccess ()) {
+                               Error_OperatorCannotBeApplied (rc, loc, "?", method_group.Type);
+                       }
+               }
+
                protected override Expression DoResolve (ResolveContext ec)
                {
                        constructor_method = Delegate.GetConstructor (type);
 
                        var invoke_method = Delegate.GetInvokeMethod (type);
 
-                       if (!ec.HasSet (ResolveContext.Options.ConditionalAccessReceiver)) {
-                               if (method_group.HasConditionalAccess ()) {
-                                       conditional_access_receiver = true;
-                                       ec.Set (ResolveContext.Options.ConditionalAccessReceiver);
-                               }
-                       }
+                       ResolveConditionalAccessReceiver (ec);
 
                        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 (conditional_access_receiver)
-                               ec.With (ResolveContext.Options.ConditionalAccessReceiver, false);
-
                        if (method_group == null)
                                return null;
 
@@ -568,8 +587,7 @@ namespace Mono.CSharp {
                                rt = ec.BuiltinTypes.Object;
 
                        if (!Delegate.IsTypeCovariant (ec, rt, invoke_method.ReturnType)) {
-                               Expression ret_expr = new TypeExpression (delegate_method.ReturnType, loc);
-                               Error_ConversionFailed (ec, delegate_method, ret_expr);
+                               Error_ConversionFailed (ec, delegate_method, delegate_method.ReturnType);
                        }
 
                        if (method_group.IsConditionallyExcluded) {
@@ -594,9 +612,6 @@ namespace Mono.CSharp {
                
                public override void Emit (EmitContext ec)
                {
-                       if (conditional_access_receiver)
-                               ec.ConditionalAccess = new ConditionalAccessContext (type, ec.DefineLabel ());
-
                        if (method_group.InstanceExpression == null) {
                                ec.EmitNull ();
                        } else {
@@ -615,21 +630,15 @@ namespace Mono.CSharp {
                        }
 
                        ec.Emit (OpCodes.Newobj, constructor_method);
-
-                       if (conditional_access_receiver)
-                               ec.CloseConditionalAccess (null);
                }
 
                public override void FlowAnalysis (FlowAnalysisContext fc)
                {
                        base.FlowAnalysis (fc);
                        method_group.FlowAnalysis (fc);
-
-                       if (conditional_access_receiver)
-                               fc.ConditionalAccessEnd ();
                }
 
-               void Error_ConversionFailed (ResolveContext ec, MethodSpec method, Expression return_type)
+               void Error_ConversionFailed (ResolveContext ec, MethodSpec method, TypeSpec return_type)
                {
                        var invoke_method = Delegate.GetInvokeMethod (type);
                        string member_name = method_group.InstanceExpression != null ?
@@ -651,6 +660,12 @@ namespace Mono.CSharp {
                                return;
                        }
 
+                       if (invoke_method.ReturnType.Kind == MemberKind.ByRef) {
+                               ec.Report.Error (8189, loc, "By reference return delegate does not match `{0}' return type",
+                                       Delegate.FullDelegateDesc (invoke_method));
+                               return;
+                       }
+
                        ec.Report.Error (407, loc, "A method or delegate `{0} {1}' return type does not match delegate `{2} {3}' return type",
                                return_type.GetSignatureForError (), member_name,
                                invoke_method.ReturnType.GetSignatureForError (), Delegate.FullDelegateDesc (invoke_method));