Implement await for new expressions
authorMarek Safar <marek.safar@gmail.com>
Wed, 13 Jul 2011 16:25:06 +0000 (17:25 +0100)
committerMarek Safar <marek.safar@gmail.com>
Wed, 13 Jul 2011 16:25:06 +0000 (17:25 +0100)
mcs/mcs/codegen.cs
mcs/mcs/expression.cs
mcs/tests/test-async-13.cs
mcs/tests/test-async-15.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_0.xml

index a03c6d0a9f249fc0540399108313d43fd9ec390b..2d085f8aec62068c71cebc819c7eff8780d413f5 100644 (file)
@@ -1082,6 +1082,7 @@ namespace Mono.CSharp
                        }
 
                        OpCode call_op;
+                       LocalTemporary lt = null;
 
                        if (method.IsStatic) {
                                call_op = OpCodes.Call;
@@ -1102,7 +1103,7 @@ namespace Mono.CSharp
                                        if (DuplicateArguments) {
                                                ec.Emit (OpCodes.Dup);
                                                if (Arguments != null && Arguments.Count != 0) {
-                                                       var lt = new LocalTemporary (instance_on_stack_type);
+                                                       lt = new LocalTemporary (instance_on_stack_type);
                                                        lt.Store (ec);
                                                        instance_copy = lt;
                                                }
@@ -1116,7 +1117,6 @@ namespace Mono.CSharp
                                        if (instance_copy != null) {
                                                EmitCallInstance (ec, instance_copy, method.DeclaringType, call_op);
 
-                                               var lt = instance_copy as LocalTemporary;
                                                if (lt != null)
                                                        lt.Release (ec);
                                        }
index 71149b0834b1c5ae518602ae16b842e144db4c36..7c71ca3829d06d53c680d5b280f555a3eab53047 100644 (file)
@@ -5389,6 +5389,11 @@ namespace Mono.CSharp
                        return null;
                }
 
+               public override bool ContainsEmitWithAwait ()
+               {
+                       return arguments != null && arguments.ContainsEmitWithAwait ();
+               }
+
                //
                // Checks whether the type is an interface that has the
                // [ComImport, CoClass] attributes and must be treated
@@ -5590,9 +5595,13 @@ namespace Mono.CSharp
                        } else if (vr != null && vr.IsRef) {
                                vr.EmitLoad (ec);
                        }
-                       
-                       if (arguments != null)
+
+                       if (arguments != null) {
+                               if ((arguments.Count > (this is NewInitialize ? 0 : 1)) && arguments.ContainsEmitWithAwait ())
+                                       arguments = arguments.Emit (ec, false, true);
+
                                arguments.Emit (ec);
+                       }
 
                        if (is_value_type) {
                                if (method == null) {
@@ -8248,18 +8257,6 @@ namespace Mono.CSharp
                        }
                }
 
-               public void EmitNew (EmitContext ec, New source, bool leave_copy)
-               {
-                       if (!source.Emit (ec, this)) {
-                               if (leave_copy)
-                                       throw new NotImplementedException ();
-
-                               return;
-                       }
-
-                       throw new NotImplementedException ();
-               }
-
                public override Expression EmitToField (EmitContext ec)
                {
                        //
@@ -9313,6 +9310,16 @@ namespace Mono.CSharp
                                t.initializers.Add (e.Clone (clonectx));
                }
 
+               public override bool ContainsEmitWithAwait ()
+               {
+                       foreach (var e in initializers) {
+                               if (e.ContainsEmitWithAwait ())
+                                       return true;
+                       }
+
+                       return false;
+               }
+
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
                        var expr_initializers = new ArrayInitializer (initializers.Count, loc);
@@ -9445,6 +9452,11 @@ namespace Mono.CSharp
                                e.Emit (ec);
                        }
 
+                       public override Expression EmitToField (EmitContext ec)
+                       {
+                               return (Expression) new_instance.instance;
+                       }
+
                        #region IMemoryLocation Members
 
                        public void AddressOf (EmitContext ec, AddressOp mode)
@@ -9464,16 +9476,6 @@ namespace Mono.CSharp
                        this.initializers = initializers;
                }
 
-               protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
-               {
-                       instance = base.EmitAddressOf (ec, Mode);
-
-                       if (!initializers.IsEmpty)
-                               initializers.Emit (ec);
-
-                       return instance;
-               }
-
                protected override void CloneTo (CloneContext clonectx, Expression t)
                {
                        base.CloneTo (clonectx, t);
@@ -9482,6 +9484,11 @@ namespace Mono.CSharp
                        target.initializers = (CollectionOrObjectInitializers) initializers.Clone (clonectx);
                }
 
+               public override bool ContainsEmitWithAwait ()
+               {
+                       return base.ContainsEmitWithAwait () || initializers.ContainsEmitWithAwait ();
+               }
+
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
                        Arguments args = new Arguments (2);
@@ -9514,11 +9521,14 @@ namespace Mono.CSharp
                        if (initializers.IsEmpty)
                                return left_on_stack;
 
-                       LocalTemporary temp = target as LocalTemporary;
-                       if (temp == null) {
+                       LocalTemporary temp = null;
+
+                       instance = target as LocalTemporary;
+
+                       if (instance == null) {
                                if (!left_on_stack) {
                                        VariableReference vr = target as VariableReference;
-                                       
+
                                        // FIXME: This still does not work correctly for pre-set variables
                                        if (vr != null && vr.IsRef)
                                                target.AddressOf (ec, AddressOp.Load);
@@ -9527,22 +9537,40 @@ namespace Mono.CSharp
                                        left_on_stack = true;
                                }
 
-                               temp = new LocalTemporary (type);
+                               if (initializers.ContainsEmitWithAwait ()) {
+                                       instance = new EmptyExpression (Type).EmitToField (ec) as IMemoryLocation;
+                               } else {
+                                       temp = new LocalTemporary (type);
+                                       instance = temp;
+                               }
                        }
 
-                       instance = temp;
-                       if (left_on_stack)
+                       if (left_on_stack && temp != null)
                                temp.Store (ec);
 
                        initializers.Emit (ec);
 
                        if (left_on_stack) {
-                               temp.Emit (ec);
-                               temp.Release (ec);
+                               if (temp != null) {
+                                       temp.Emit (ec);
+                                       temp.Release (ec);
+                               } else {
+                                       ((Expression) instance).Emit (ec);
+                               }
                        }
 
                        return left_on_stack;
                }
+
+               protected override IMemoryLocation EmitAddressOf (EmitContext ec, AddressOp Mode)
+               {
+                       instance = base.EmitAddressOf (ec, Mode);
+
+                       if (!initializers.IsEmpty)
+                               initializers.Emit (ec);
+
+                       return instance;
+               }
        }
 
        public class NewAnonymousType : New
index 0d78a3e6fc6ccdd97216e29b36162585b4bf9ce3..52cfb934d4302eba5ed2bc57d0d3461a519f1033 100644 (file)
@@ -10,6 +10,11 @@ struct S
 {
        public int Value;
        
+       public S (int a1, string a2)
+       {
+               Value = a1;
+       }
+       
        public void SetValue (int value)
        {
                Value = value;
@@ -23,12 +28,21 @@ enum E
 
 class Base
 {
-       protected int field_int;
+       public int field_int;
        protected int field_this;
        protected int property_this_counter;
        
        public event Action Event;
        
+       public Base ()
+       {
+       }
+       
+       public Base (int arg, int arg2)
+       {
+               field_int = arg;
+       }
+       
        public bool PropertyBool {
                get {
                        return true;
@@ -332,6 +346,71 @@ class Tester : Base
                return res == 1;
        }
        
+       async Task<bool> NewTest_1 ()
+       {
+               int value = 9;
+               var b = new Base (value, await Task.Factory.StartNew (() => 33));
+               return b.field_int == 9;
+       }
+       
+       async Task<bool> NewTest_2 ()
+       {
+               var s = new S (await Task.Factory.StartNew (() => 77), await Task.Factory.StartNew (() => "b"));
+               return s.Value == 77;
+       }
+       
+       async Task<int> NewInitTest_1 ()
+       {
+               int value = 9;
+               
+               var b = new Base (value, await Task.Factory.StartNew (() => 33)) { };
+               if (b.field_int != 9)
+                       return 1;
+               
+               b = new Base (value, await Task.Factory.StartNew (() => 11)) {
+                       field_int = await Task.Factory.StartNew (() => 12),
+                       PropertyInt = await Task.Factory.StartNew (() => 13)
+               };
+               
+               if (b.field_int != 25)
+                       return 2;
+               
+               b = new Base () {
+                       field_int = await Task.Factory.StartNew (() => 12),
+                       PropertyInt = await Task.Factory.StartNew (() => 13)
+               };
+
+               if (b.field_int != 25)
+                       return 3;
+               
+               return 0;
+       }
+       
+       async Task<int> NewInitTest_2 ()
+       {
+               int value = 9;
+               
+               var s = new S (value, await Task.Factory.StartNew (() => "x")) { };
+               if (s.Value != 9)
+                       return 1;
+               
+               s = new S (value, await Task.Factory.StartNew (() => "y")) {
+                       Value = await Task.Factory.StartNew (() => 12)
+               };
+
+               if (s.Value != 12)
+                       return 2;
+               
+               s = new S () {
+                       Value = await Task.Factory.StartNew (() => 13)
+               };
+               
+               if (s.Value != 13)
+                       return 3;
+               
+               return 0;
+       }
+
        async Task<bool> NewArrayInitTest_1 ()
        {
                var a = new int[await Task.Factory.StartNew (() => 5)];
diff --git a/mcs/tests/test-async-15.cs b/mcs/tests/test-async-15.cs
new file mode 100644 (file)
index 0000000..ae56f39
--- /dev/null
@@ -0,0 +1,57 @@
+// Compiler options: -langversion:future
+
+using System;
+using System.Threading.Tasks;
+using System.Threading;
+
+interface IFoo
+{
+       int Value { get; set; }
+}
+
+struct S : IFoo
+{
+       public S (int a1, string a2)
+               : this ()
+       {
+               Value = a1;
+       }
+       
+       public int Value { get; set; }
+       
+       public void SetValue (int value)
+       {
+               Value = value;
+       }
+}
+
+class Tester
+{
+       async Task<T> NewInitTestGen<T> () where T : struct, IFoo
+       {
+               int value = 9;
+               
+               var s = new T () {
+                       Value = await Task.Factory.StartNew (() => 13)
+               };
+               
+               if (s.Value != 13)
+                       return new T ();
+               
+               return s;
+       }
+       
+       public static int Main ()
+       {
+               var t = new Tester().NewInitTestGen<S> ();
+               
+               if (!Task.WaitAll (new[] { t }, 1000)) {
+                       return 1;
+               }
+               
+               if (t.Result.Value != 13)
+                       return 2;
+               
+               return 0;
+       }
+}
index 28a667eb8ef6e21c0ae2bc71fa29959d4885969b..61291fe551a86ab78d2ecc61efad8373020bcc0f 100644 (file)
     </type>
     <type name="Tester+&lt;&gt;c__async1A">
       <method name="Void MoveNext()">
-        <size>212</size>
+        <size>230</size>
       </method>
       <method name="Void .ctor()">
         <size>36</size>
     </type>
     <type name="Tester+&lt;&gt;c__async1A">
       <method name="Int32 &lt;&gt;m__37()">
-        <size>2</size>
+        <size>3</size>
       </method>
     </type>
     <type name="Tester+&lt;&gt;c__async1B">
         <size>334</size>
       </method>
       <method name="Int32 &lt;&gt;m__38()">
-        <size>2</size>
-      </method>
-      <method name="Int32 &lt;&gt;m__39()">
-        <size>2</size>
+        <size>3</size>
       </method>
       <method name="Void .ctor()">
         <size>36</size>
     </type>
     <type name="Tester+&lt;&gt;c__async1C">
       <method name="Void MoveNext()">
-        <size>232</size>
-      </method>
-      <method name="Byte &lt;&gt;m__3A()">
-        <size>2</size>
+        <size>1009</size>
       </method>
       <method name="Void .ctor()">
         <size>36</size>
     </type>
     <type name="Tester+&lt;&gt;c__async1D">
       <method name="Void MoveNext()">
-        <size>420</size>
+        <size>738</size>
       </method>
-      <method name="UInt16 &lt;&gt;m__3B()">
-        <size>2</size>
+      <method name="Void .ctor()">
+        <size>36</size>
       </method>
-      <method name="UInt16 &lt;&gt;m__3C()">
-        <size>2</size>
+    </type>
+    <type name="Tester+&lt;&gt;c__async1E">
+      <method name="Void MoveNext()">
+        <size>212</size>
       </method>
       <method name="Void .ctor()">
         <size>36</size>
       </method>
     </type>
-    <type name="Tester+&lt;&gt;c__async1E">
+    <type name="Tester+&lt;&gt;c__async1F">
       <method name="Void MoveNext()">
-        <size>250</size>
+        <size>334</size>
       </method>
-      <method name="S &lt;&gt;m__3D()">
-        <size>18</size>
+      <method name="Void .ctor()">
+        <size>36</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async20">
+      <method name="Void MoveNext()">
+        <size>232</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>36</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async21">
+      <method name="Void MoveNext()">
+        <size>420</size>
       </method>
       <method name="Void .ctor()">
         <size>36</size>
       </method>
     </type>
+    <type name="Tester+&lt;&gt;c__async22">
+      <method name="Void MoveNext()">
+        <size>250</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>36</size>
+      </method>
+    </type>
+    <type name="S">
+      <method name="Void .ctor(Int32, String)">
+        <size>8</size>
+      </method>
+    </type>
+    <type name="Base">
+      <method name="Void .ctor(Int32, Int32)">
+        <size>14</size>
+      </method>
+    </type>
+    <type name="Tester">
+      <method name="System.Threading.Tasks.Task`1[System.Boolean] NewTest_1()">
+        <size>27</size>
+      </method>
+      <method name="System.Threading.Tasks.Task`1[System.Boolean] NewTest_2()">
+        <size>27</size>
+      </method>
+      <method name="System.Threading.Tasks.Task`1[System.Int32] NewInitTest_1()">
+        <size>27</size>
+      </method>
+      <method name="System.Threading.Tasks.Task`1[System.Int32] NewInitTest_2()">
+        <size>27</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async1B">
+      <method name="System.String &lt;&gt;m__39()">
+        <size>6</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async1C">
+      <method name="Int32 &lt;&gt;m__3A()">
+        <size>3</size>
+      </method>
+      <method name="Int32 &lt;&gt;m__3B()">
+        <size>3</size>
+      </method>
+      <method name="Int32 &lt;&gt;m__3C()">
+        <size>3</size>
+      </method>
+      <method name="Int32 &lt;&gt;m__3D()">
+        <size>3</size>
+      </method>
+      <method name="Int32 &lt;&gt;m__3E()">
+        <size>3</size>
+      </method>
+      <method name="Int32 &lt;&gt;m__3F()">
+        <size>3</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async1D">
+      <method name="System.String &lt;&gt;m__40()">
+        <size>6</size>
+      </method>
+      <method name="System.String &lt;&gt;m__41()">
+        <size>6</size>
+      </method>
+      <method name="Int32 &lt;&gt;m__42()">
+        <size>3</size>
+      </method>
+      <method name="Int32 &lt;&gt;m__43()">
+        <size>3</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async1E">
+      <method name="Int32 &lt;&gt;m__44()">
+        <size>2</size>
+      </method>
+    </type>
     <type name="Tester+&lt;&gt;c__async1F">
+      <method name="Int32 &lt;&gt;m__45()">
+        <size>2</size>
+      </method>
+      <method name="Int32 &lt;&gt;m__46()">
+        <size>2</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async20">
+      <method name="Byte &lt;&gt;m__47()">
+        <size>2</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async21">
+      <method name="UInt16 &lt;&gt;m__48()">
+        <size>2</size>
+      </method>
+      <method name="UInt16 &lt;&gt;m__49()">
+        <size>2</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async22">
+      <method name="S &lt;&gt;m__4A()">
+        <size>18</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async23">
       <method name="Void MoveNext()">
         <size>201</size>
       </method>
-      <method name="Int32 &lt;&gt;m__3E()">
+      <method name="Int32 &lt;&gt;m__4B()">
         <size>2</size>
       </method>
       <method name="Void .ctor()">
         <size>36</size>
       </method>
     </type>
-    <type name="Tester+&lt;&gt;c__async20">
+    <type name="Tester+&lt;&gt;c__async24">
       <method name="Void MoveNext()">
         <size>272</size>
       </method>
-      <method name="Int32 &lt;&gt;m__3F()">
+      <method name="Int32 &lt;&gt;m__4C()">
         <size>2</size>
       </method>
       <method name="Void .ctor()">
         <size>36</size>
       </method>
     </type>
-    <type name="Tester+&lt;&gt;c__async21">
+    <type name="Tester+&lt;&gt;c__async25">
       <method name="Void MoveNext()">
         <size>636</size>
       </method>
-      <method name="Int32 &lt;&gt;m__40()">
+      <method name="Int32 &lt;&gt;m__4D()">
         <size>3</size>
       </method>
-      <method name="Int32 &lt;&gt;m__41()">
+      <method name="Int32 &lt;&gt;m__4E()">
         <size>2</size>
       </method>
-      <method name="Int32 &lt;&gt;m__42()">
+      <method name="Int32 &lt;&gt;m__4F()">
         <size>2</size>
       </method>
       <method name="Void .ctor()">
         <size>36</size>
       </method>
     </type>
-    <type name="Tester+&lt;&gt;c__async22">
+    <type name="Tester+&lt;&gt;c__async26">
       <method name="Void MoveNext()">
         <size>441</size>
       </method>
-      <method name="System.String &lt;&gt;m__43()">
+      <method name="System.String &lt;&gt;m__50()">
         <size>6</size>
       </method>
-      <method name="System.String &lt;&gt;m__44()">
+      <method name="System.String &lt;&gt;m__51()">
         <size>6</size>
       </method>
-      <method name="System.String &lt;&gt;m__45()">
+      <method name="System.String &lt;&gt;m__52()">
         <size>2</size>
       </method>
       <method name="Void .ctor()">
       </method>
     </type>
   </test>
+  <test name="test-async-15.cs">
+    <type name="S">
+      <method name="Int32 get_Value()">
+        <size>7</size>
+      </method>
+      <method name="Void set_Value(Int32)">
+        <size>8</size>
+      </method>
+      <method name="Void SetValue(Int32)">
+        <size>8</size>
+      </method>
+      <method name="Void .ctor(Int32, String)">
+        <size>8</size>
+      </method>
+    </type>
+    <type name="Tester">
+      <method name="System.Threading.Tasks.Task`1[T] NewInitTestGen[T]()">
+        <size>27</size>
+      </method>
+      <method name="Int32 Main()">
+        <size>63</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="Tester+&lt;&gt;c__async0`1[T]">
+      <method name="Void MoveNext()">
+        <size>272</size>
+      </method>
+      <method name="Int32 &lt;&gt;m__0()">
+        <size>3</size>
+      </method>
+      <method name="Void .ctor()">
+        <size>36</size>
+      </method>
+    </type>
+  </test>
   <test name="test-cls-00.cs">
     <type name="CLSCLass_6">
       <method name="Void .ctor()">