Merge pull request #606 from sesef/master
[mono.git] / mcs / mcs / async.cs
index 47ae75708707c7a4c2382dd7a420ad715df79453..7742126beda0353d680e283e1c258d2b7f58a024 100644 (file)
@@ -7,7 +7,7 @@
 // Dual licensed under the terms of the MIT X11 or GNU GPL
 //
 // Copyright 2011 Novell, Inc.
-// Copyright 2011 Xamarin Inc.
+// Copyright 2011-2012 Xamarin Inc.
 //
 
 using System;
@@ -16,8 +16,10 @@ using System.Linq;
 using System.Collections;
 
 #if STATIC
+using IKVM.Reflection;
 using IKVM.Reflection.Emit;
 #else
+using System.Reflection;
 using System.Reflection.Emit;
 #endif
 
@@ -121,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);
@@ -135,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'",
@@ -161,8 +168,7 @@ namespace Mono.CSharp
                }
 
                Field awaiter;
-               PropertySpec is_completed;
-               MethodSpec get_result;
+               AwaiterDefinition awaiter_definition;
                TypeSpec type;
                TypeSpec result_type;
 
@@ -175,7 +181,7 @@ namespace Mono.CSharp
 
                bool IsDynamic {
                        get {
-                               return is_completed == null;
+                               return awaiter_definition == null;
                        }
                }
 
@@ -203,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)
@@ -239,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;
                        }
@@ -301,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
@@ -335,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;
                }
@@ -486,6 +469,12 @@ namespace Mono.CSharp
                        }
                }
 
+               protected override TypeAttributes TypeAttr {
+                       get {
+                               return base.TypeAttr & ~TypeAttributes.SequentialLayout;
+                       }
+               }
+
                #endregion
 
                public Field AddAwaiter (TypeSpec type, Location loc)