Merge pull request #601 from knocte/sock_improvements
[mono.git] / mcs / mcs / async.cs
index 6de09f01b1a9d83ff4a899f8cff922549a19e19d..6997d7ca85042729b61b8a0204ee01dc54ae584a 100644 (file)
@@ -123,13 +123,15 @@ namespace Mono.CSharp
 
        public class AwaitStatement : YieldStatement<AsyncInitializer>
        {
-               sealed class AwaitableMemberAccess : MemberAccess
+               public sealed class AwaitableMemberAccess : MemberAccess
                {
                        public AwaitableMemberAccess (Expression expr)
                                : base (expr, "GetAwaiter")
                        {
                        }
 
+                       public bool ProbingMode { get; set; }
+
                        protected override void Error_TypeDoesNotContainDefinition (ResolveContext rc, TypeSpec type, string name)
                        {
                                Error_OperatorCannotBeApplied (rc, type);
@@ -137,6 +139,9 @@ namespace Mono.CSharp
 
                        protected override void Error_OperatorCannotBeApplied (ResolveContext rc, TypeSpec type)
                        {
+                               if (ProbingMode)
+                                       return;
+
                                var invocation = LeftExpression as Invocation;
                                if (invocation != null && invocation.MethodGroup != null && (invocation.MethodGroup.BestCandidate.Modifiers & Modifiers.ASYNC) != 0) {
                                        rc.Report.Error (4008, loc, "Cannot await void method `{0}'. Consider changing method return type to `Task'",
@@ -163,8 +168,7 @@ namespace Mono.CSharp
                }
 
                Field awaiter;
-               PropertySpec is_completed;
-               MethodSpec get_result;
+               AwaiterDefinition awaiter_definition;
                TypeSpec type;
                TypeSpec result_type;
 
@@ -177,7 +181,7 @@ namespace Mono.CSharp
 
                bool IsDynamic {
                        get {
-                               return is_completed == null;
+                               return awaiter_definition == null;
                        }
                }
 
@@ -205,12 +209,12 @@ namespace Mono.CSharp
                        if (IsDynamic) {
                                var rc = new ResolveContext (ec.MemberContext);
                                return new Invocation (new MemberAccess (fe_awaiter, "GetResult"), new Arguments (0)).Resolve (rc);
-                       } else {
-                               var mg_result = MethodGroupExpr.CreatePredefined (get_result, fe_awaiter.Type, loc);
-                               mg_result.InstanceExpression = fe_awaiter;
-
-                               return new GetResultInvocation (mg_result, new Arguments (0));
                        }
+                       
+                       var mg_result = MethodGroupExpr.CreatePredefined (awaiter_definition.GetResult, fe_awaiter.Type, loc);
+                       mg_result.InstanceExpression = fe_awaiter;
+
+                       return new GetResultInvocation (mg_result, new Arguments (0));
                }
 
                public void EmitPrologue (EmitContext ec)
@@ -241,7 +245,7 @@ namespace Mono.CSharp
                                dargs.Add (new Argument (completed_expr));
                                completed_expr = new DynamicConversion (ec.Module.Compiler.BuiltinTypes.Bool, 0, dargs, loc).Resolve (rc);
                        } else {
-                               var pe = PropertyExpr.CreatePredefined (is_completed, loc);
+                               var pe = PropertyExpr.CreatePredefined (awaiter_definition.IsCompleted, loc);
                                pe.InstanceExpression = fe_awaiter;
                                completed_expr = pe;
                        }
@@ -303,9 +307,8 @@ namespace Mono.CSharp
                        if (!base.Resolve (bc))
                                return false;
 
-                       Arguments args = new Arguments (0);
-
                        type = expr.Type;
+                       Arguments args = new Arguments (0);
 
                        //
                        // The await expression is of dynamic type
@@ -337,44 +340,22 @@ namespace Mono.CSharp
                        }
 
                        var awaiter_type = ama.Type;
-                       expr = ama;
-
-                       //
-                       // Predefined: bool IsCompleted { get; } 
-                       //
-                       is_completed = MemberCache.FindMember (awaiter_type, MemberFilter.Property ("IsCompleted", bc.Module.Compiler.BuiltinTypes.Bool),
-                               BindingRestriction.InstanceOnly) as PropertySpec;
 
-                       if (is_completed == null || !is_completed.HasGet) {
-                               Error_WrongAwaiterPattern (bc, awaiter_type);
-                               return false;
-                       }
-
-                       //
-                       // Predefined: GetResult ()
-                       //
-                       // The method return type is also result type of await expression
-                       //
-                       get_result = MemberCache.FindMember (awaiter_type, MemberFilter.Method ("GetResult", 0,
-                               ParametersCompiled.EmptyReadOnlyParameters, null),
-                               BindingRestriction.InstanceOnly) as MethodSpec;
+                       awaiter_definition = bc.Module.GetAwaiter (awaiter_type);
 
-                       if (get_result == null) {
+                       if (!awaiter_definition.IsValidPattern) {
                                Error_WrongAwaiterPattern (bc, awaiter_type);
                                return false;
                        }
 
-                       //
-                       // Predefined: INotifyCompletion.OnCompleted (System.Action)
-                       //
-                       var nc = bc.Module.PredefinedTypes.INotifyCompletion;
-                       if (nc.Define () && !awaiter_type.ImplementsInterface (nc.TypeSpec, false)) {
+                       if (!awaiter_definition.INotifyCompletion) {
                                bc.Report.Error (4027, loc, "The awaiter type `{0}' must implement interface `{1}'",
-                                       awaiter_type.GetSignatureForError (), nc.GetSignatureForError ());
+                                       awaiter_type.GetSignatureForError (), bc.Module.PredefinedTypes.INotifyCompletion.GetSignatureForError ());
                                return false;
                        }
 
-                       result_type = get_result.ReturnType;
+                       expr = ama;
+                       result_type = awaiter_definition.GetResult.ReturnType;
 
                        return true;
                }
@@ -397,6 +378,10 @@ namespace Mono.CSharp
                        }
                }
 
+               public TypeSpec DelegateType {
+                       get; set;
+               }
+
                public override bool IsIterator {
                        get {
                                return false;