[mcs] Initial by ref returns and variables support
authorMarek Safar <marek.safar@gmail.com>
Tue, 19 Sep 2017 13:47:31 +0000 (15:47 +0200)
committerMarek Safar <marek.safar@gmail.com>
Mon, 2 Oct 2017 14:23:04 +0000 (16:23 +0200)
61 files changed:
mcs/errors/cs0131-6.cs [new file with mode: 0644]
mcs/errors/cs0199-2.cs [new file with mode: 0644]
mcs/errors/cs0206-5.cs [new file with mode: 0644]
mcs/errors/cs1503-17.cs [new file with mode: 0644]
mcs/errors/cs1547-13.cs [new file with mode: 0644]
mcs/errors/cs1644-55.cs [new file with mode: 0644]
mcs/errors/cs1715-3.cs [new file with mode: 0644]
mcs/errors/cs1764.cs
mcs/errors/cs8145.cs [new file with mode: 0644]
mcs/errors/cs8146.cs [new file with mode: 0644]
mcs/errors/cs8147-2.cs [new file with mode: 0644]
mcs/errors/cs8147.cs [new file with mode: 0644]
mcs/errors/cs8148-2.cs [new file with mode: 0644]
mcs/errors/cs8148.cs [new file with mode: 0644]
mcs/errors/cs8149-2.cs [new file with mode: 0644]
mcs/errors/cs8149.cs [new file with mode: 0644]
mcs/errors/cs8150.cs [new file with mode: 0644]
mcs/errors/cs8151.cs [new file with mode: 0644]
mcs/errors/cs8152.cs [new file with mode: 0644]
mcs/errors/cs8153.cs [new file with mode: 0644]
mcs/errors/cs8154.cs [new file with mode: 0644]
mcs/errors/cs8155.cs [new file with mode: 0644]
mcs/errors/cs8156-2.cs [new file with mode: 0644]
mcs/errors/cs8156.cs [new file with mode: 0644]
mcs/errors/cs8157.cs [new file with mode: 0644]
mcs/errors/cs8160.cs [new file with mode: 0644]
mcs/errors/cs8161.cs [new file with mode: 0644]
mcs/errors/cs8170-2.cs [new file with mode: 0644]
mcs/errors/cs8170.cs [new file with mode: 0644]
mcs/errors/cs8171.cs [new file with mode: 0644]
mcs/errors/cs8172.cs [new file with mode: 0644]
mcs/errors/cs8173.cs [new file with mode: 0644]
mcs/errors/cs8174.cs [new file with mode: 0644]
mcs/errors/cs8175.cs [new file with mode: 0644]
mcs/errors/cs8176.cs [new file with mode: 0644]
mcs/errors/cs8177.cs [new file with mode: 0644]
mcs/errors/cs8178-2.cs [new file with mode: 0644]
mcs/errors/cs8178.cs [new file with mode: 0644]
mcs/errors/cs8189.cs [new file with mode: 0644]
mcs/errors/known-issues-net_4_x
mcs/mcs/argument.cs
mcs/mcs/class.cs
mcs/mcs/convert.cs
mcs/mcs/cs-parser.jay
mcs/mcs/delegate.cs
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/mcs/generic.cs
mcs/mcs/iterators.cs
mcs/mcs/lambda.cs
mcs/mcs/membercache.cs
mcs/mcs/pending.cs
mcs/mcs/property.cs
mcs/mcs/statement.cs
mcs/mcs/typespec.cs
mcs/tests/test-ref-01.cs [new file with mode: 0644]
mcs/tests/test-ref-02.cs [new file with mode: 0644]
mcs/tests/test-ref-03.cs [new file with mode: 0644]
mcs/tests/test-ref-04.cs [new file with mode: 0644]
mcs/tests/test-ref-05.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_x.xml

diff --git a/mcs/errors/cs0131-6.cs b/mcs/errors/cs0131-6.cs
new file mode 100644 (file)
index 0000000..8af3e93
--- /dev/null
@@ -0,0 +1,15 @@
+// CS0131: The left-hand side of an assignment must be a variable, a property or an indexer
+// Line: 8
+
+class X
+{
+       void Test ()
+       {
+               Foo () = 1;
+       }
+
+       static int Foo ()
+       {
+               return 1;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs0199-2.cs b/mcs/errors/cs0199-2.cs
new file mode 100644 (file)
index 0000000..efad7c8
--- /dev/null
@@ -0,0 +1,12 @@
+// CS0199: A static readonly field `X.f' cannot be passed ref or out (except in a static constructor)
+// Line: 10
+
+class X
+{
+       static readonly int f = 0;
+
+       public static void Main ()
+       {
+               ref int j = ref f;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs0206-5.cs b/mcs/errors/cs0206-5.cs
new file mode 100644 (file)
index 0000000..bd9691f
--- /dev/null
@@ -0,0 +1,12 @@
+// CS0206: A property, indexer or dynamic member access may not be passed as `ref' or `out' parameter
+// Line: 10
+
+class X
+{
+       static int P { get; set; }
+
+       static void Main ()
+       {
+               ref int rl = ref P;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs1503-17.cs b/mcs/errors/cs1503-17.cs
new file mode 100644 (file)
index 0000000..23921ed
--- /dev/null
@@ -0,0 +1,31 @@
+// CS1503: Argument `#1' cannot convert `ref long' expression to type `ref int'
+// Line: 18
+
+using System;
+
+class X
+{
+       long field;
+
+       static void Main ()
+       {
+               var x = new X ();
+               x.Run ();
+       }
+
+       void Run ()
+       {
+               Test (ref Prop);
+       }
+
+       static int Test (ref int y)
+       {
+               return y;
+       }
+
+       ref long Prop {
+               get {
+                       return ref field;
+               }
+       }
+}
diff --git a/mcs/errors/cs1547-13.cs b/mcs/errors/cs1547-13.cs
new file mode 100644 (file)
index 0000000..1b3f8e1
--- /dev/null
@@ -0,0 +1,7 @@
+// CS1547: Keyword `void' cannot be used in this context
+// Line: 6
+
+interface IA
+{
+       ref void Foo ();
+}
diff --git a/mcs/errors/cs1644-55.cs b/mcs/errors/cs1644-55.cs
new file mode 100644 (file)
index 0000000..58384a6
--- /dev/null
@@ -0,0 +1,11 @@
+// CS1644: Feature `byref locals and returns' cannot be used because it is not part of the C# 6.0 language specification
+// Line: 9
+// Compiler options: -langversion:6
+
+class Text
+{
+       static ref long Foo ()
+       {
+               throw new System.NotImplementedException ();
+       }
+}
diff --git a/mcs/errors/cs1715-3.cs b/mcs/errors/cs1715-3.cs
new file mode 100644 (file)
index 0000000..d3cd5da
--- /dev/null
@@ -0,0 +1,16 @@
+// CS1715: `B.Foo': type must be `int' to match overridden member `A.Foo'
+// Line: 11
+
+public abstract class A
+{
+       public abstract ref int Foo { get; }
+}
+
+public class B : A
+{
+       public override ref long Foo {
+               get {
+                       throw null;
+               }
+       }
+}
\ No newline at end of file
index f8a89b25659474ba368650c02a016c41b8197656..a1dd2e36d1591c8f4bd3fdcb8e8dad9daea66c9a 100644 (file)
@@ -1,4 +1,4 @@
-// CS1764: Cannot use fixed local `p' inside an anonymous method, lambda expression or query expression
+// CS1764: Cannot use fixed variable `p' inside an anonymous method, lambda expression or query expression
 // Line: 10
 // Compiler options: -unsafe
 
diff --git a/mcs/errors/cs8145.cs b/mcs/errors/cs8145.cs
new file mode 100644 (file)
index 0000000..cf3c508
--- /dev/null
@@ -0,0 +1,7 @@
+// CS8145: Auto-implemented properties cannot return by reference
+// Line: 6
+
+public class X
+{
+       ref string TestProp { get; }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8146.cs b/mcs/errors/cs8146.cs
new file mode 100644 (file)
index 0000000..758804c
--- /dev/null
@@ -0,0 +1,7 @@
+// CS8146: `X.TestProp': property and indexer which return by reference must have a get accessor
+// Line: 6
+
+public class X
+{
+       ref string TestProp { set; }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8147-2.cs b/mcs/errors/cs8147-2.cs
new file mode 100644 (file)
index 0000000..a4375d2
--- /dev/null
@@ -0,0 +1,14 @@
+// CS8147: `X.this[int]': property and indexer which return by reference cannot have set accessors
+// Line: 6
+
+public class X
+{
+       ref string this [int arg] { 
+               set {
+
+               }
+               get {
+
+               }
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8147.cs b/mcs/errors/cs8147.cs
new file mode 100644 (file)
index 0000000..a006a4d
--- /dev/null
@@ -0,0 +1,14 @@
+// CS8147: `X.TestProp': property and indexer which return by reference cannot have set accessors
+// Line: 6
+
+public class X
+{
+       ref string TestProp { 
+               set {
+
+               }
+               get {
+
+               }
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8148-2.cs b/mcs/errors/cs8148-2.cs
new file mode 100644 (file)
index 0000000..1961026
--- /dev/null
@@ -0,0 +1,16 @@
+// CS8148: `B.Foo': must return by reference to match overridden member `A.Foo'
+// Line: 11
+
+public abstract class A
+{
+       public abstract ref int Foo { get; }
+}
+
+public class B : A
+{
+       public override long Foo {
+               get {
+                       throw null;
+               }
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8148.cs b/mcs/errors/cs8148.cs
new file mode 100644 (file)
index 0000000..1e91789
--- /dev/null
@@ -0,0 +1,15 @@
+// CS8148: `B.Foo()': must not return by reference to match overridden member `A.Foo()'
+// Line: 11
+
+public abstract class A
+{
+       public abstract int Foo ();
+}
+
+public class B : A
+{
+       public override ref int Foo ()
+       {
+
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8149-2.cs b/mcs/errors/cs8149-2.cs
new file mode 100644 (file)
index 0000000..3514769
--- /dev/null
@@ -0,0 +1,14 @@
+// CS8149: By-reference returns can only be used in lambda expressions that return by reference
+// Line: 12
+
+using System;
+
+class A
+{
+       int p;
+       
+       void Test ()
+       {
+               Action a = () => ref p;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8149.cs b/mcs/errors/cs8149.cs
new file mode 100644 (file)
index 0000000..351dd54
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8149: By-reference returns can only be used in methods that return by reference
+// Line: 10
+
+class A
+{
+       int p;
+
+       int Test ()
+       {
+               return ref p;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8150.cs b/mcs/errors/cs8150.cs
new file mode 100644 (file)
index 0000000..fd4ef7a
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8150: By-reference return is required when method returns by reference
+// Line: 10
+
+class A
+{
+       int p;
+
+       ref int Test ()
+       {
+               return p;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8151.cs b/mcs/errors/cs8151.cs
new file mode 100644 (file)
index 0000000..934faef
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8151: The return by reference expression must be of type `string' because this method returns by reference
+// Line: 10
+
+public class X
+{
+       int field;
+
+       ref string TestMethod ()
+       {
+               return ref field;
+       }
+}
diff --git a/mcs/errors/cs8152.cs b/mcs/errors/cs8152.cs
new file mode 100644 (file)
index 0000000..45546ad
--- /dev/null
@@ -0,0 +1,14 @@
+// CS8152: `C' does not implement interface member `IA.Foo()' and the best implementing candidate `C.Foo()' return type `void' does not return by reference
+// Line: 11
+
+interface IA
+{
+       ref char Foo ();
+}
+
+public class C : IA
+{
+       public void Foo ()
+       {
+       }
+}
diff --git a/mcs/errors/cs8153.cs b/mcs/errors/cs8153.cs
new file mode 100644 (file)
index 0000000..d36f110
--- /dev/null
@@ -0,0 +1,24 @@
+// CS8153: An expression tree lambda cannot contain a call to a method, property, or indexer that returns by reference
+// Line: 11
+
+using System;
+using System.Linq.Expressions;
+
+class X
+{
+       void Foo ()
+       {
+               Expression<Func<int>> e = () => Test (ref this[0]);
+       }
+
+       static int Test (ref int y)
+       {
+               return y;
+       }
+
+       ref int this [int y] {
+               get {
+                       throw null;
+               }
+       }
+}
diff --git a/mcs/errors/cs8154.cs b/mcs/errors/cs8154.cs
new file mode 100644 (file)
index 0000000..ed98513
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8154: The body of `TestClass.TestFunction()' cannot be an iterator block because the method returns by reference
+// Line: 10
+
+class TestClass
+{
+    int x;
+
+    ref int TestFunction()
+    {
+        yield return x;
+    }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8155.cs b/mcs/errors/cs8155.cs
new file mode 100644 (file)
index 0000000..45d8b4e
--- /dev/null
@@ -0,0 +1,16 @@
+// CS8155: Lambda expressions that return by reference cannot be converted to expression trees
+// Line: 14
+
+using System.Linq.Expressions;
+
+class TestClass
+{
+    static int x;
+
+    delegate ref int D ();
+
+    static void Main ()
+    {
+        Expression<D> e = () => ref x;
+    }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8156-2.cs b/mcs/errors/cs8156-2.cs
new file mode 100644 (file)
index 0000000..7507ec4
--- /dev/null
@@ -0,0 +1,16 @@
+// CS8156: An expression cannot be used in this context because it may not be returned by reference
+// Line: 8
+
+class X
+{
+       int Prop {
+               get {
+                       return 1;
+               }
+       }
+
+       ref int Test ()
+       {
+               return ref Prop;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8156.cs b/mcs/errors/cs8156.cs
new file mode 100644 (file)
index 0000000..fe3f6b7
--- /dev/null
@@ -0,0 +1,10 @@
+// CS8156: An expression cannot be used in this context because it may not be returned by reference
+// Line: 8
+
+class Test
+{
+       ref int Foo ()
+       {
+               return ref 2;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8157.cs b/mcs/errors/cs8157.cs
new file mode 100644 (file)
index 0000000..35d700f
--- /dev/null
@@ -0,0 +1,13 @@
+// CS8157: Cannot return `r' by reference because it was initialized to a value that cannot be returned by reference
+// Line: 11
+
+struct S
+{
+       int i;
+
+       ref int M ()
+       {
+               ref int r = ref i;
+               return ref r;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8160.cs b/mcs/errors/cs8160.cs
new file mode 100644 (file)
index 0000000..2b4ea42
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8160: A readonly field cannot be returned by reference
+// Line: 10
+
+class X
+{
+       readonly int f = 0;
+
+       ref int Test ()
+       {
+               return ref f;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8161.cs b/mcs/errors/cs8161.cs
new file mode 100644 (file)
index 0000000..0d028a1
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8161: A static readonly field cannot be returned by reference
+// Line: 10
+
+class X
+{
+       static readonly int f;
+
+       static ref int Test ()
+       {
+               return ref f;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8170-2.cs b/mcs/errors/cs8170-2.cs
new file mode 100644 (file)
index 0000000..dbd76a4
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8170:
+// Line: 10
+
+public struct S
+{
+       int f;
+
+       public ref S Foo ()
+       {
+               return ref f;
+       }
+}
diff --git a/mcs/errors/cs8170.cs b/mcs/errors/cs8170.cs
new file mode 100644 (file)
index 0000000..142e1a1
--- /dev/null
@@ -0,0 +1,10 @@
+// CS8170:
+// Line: 8
+
+public struct S
+{
+       public ref S Foo ()
+       {
+               return ref this;
+       }
+}
diff --git a/mcs/errors/cs8171.cs b/mcs/errors/cs8171.cs
new file mode 100644 (file)
index 0000000..36eae2c
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8171: Cannot initialize a by-value variable `l' with a reference expression
+// Line: 10
+
+class Test
+{
+       int field;
+
+       void Foo ()
+       {
+               int l = ref field;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8172.cs b/mcs/errors/cs8172.cs
new file mode 100644 (file)
index 0000000..7ddd383
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8172: Cannot initialize a by-reference variable `j' with a value
+// Line: 10
+
+class X
+{
+       static int f;
+
+       public static void Main ()
+       {
+               ref int j = f;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8173.cs b/mcs/errors/cs8173.cs
new file mode 100644 (file)
index 0000000..7c7d894
--- /dev/null
@@ -0,0 +1,13 @@
+// CS8173: The expression must be of type `long' because it is being assigned by reference
+// Line: 11
+
+public class X
+{
+       int field;
+
+       public static void Main ()
+       {
+               int i = 5;
+               ref long j = ref i;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8174.cs b/mcs/errors/cs8174.cs
new file mode 100644 (file)
index 0000000..888711a
--- /dev/null
@@ -0,0 +1,10 @@
+// CS8174: A declaration of a by-reference variable must have an initializer
+// Line: 8
+
+class X
+{
+       public static void Main ()
+       {
+               ref int j;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8175.cs b/mcs/errors/cs8175.cs
new file mode 100644 (file)
index 0000000..4ef39db
--- /dev/null
@@ -0,0 +1,17 @@
+// CS8175: Cannot use by-reference variable `v' inside an anonymous method, lambda expression, or query expression
+// Line: 14
+
+using System;
+
+public class Test
+{
+       public static void Main()
+       {
+               var arr = new int [1];
+               ref var v = ref arr [0];
+
+               Action a = delegate {
+                       ref var v2 = ref v;
+               };
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8176.cs b/mcs/errors/cs8176.cs
new file mode 100644 (file)
index 0000000..514c0b2
--- /dev/null
@@ -0,0 +1,15 @@
+// CS8176: Iterators cannot use by-reference variables
+// Line: 12
+
+using System.Collections.Generic;
+
+class X
+{
+       int x;
+
+       IEnumerable<int> Test ()
+       {
+               ref int y = ref x;
+               yield break;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8177.cs b/mcs/errors/cs8177.cs
new file mode 100644 (file)
index 0000000..414ece1
--- /dev/null
@@ -0,0 +1,15 @@
+// CS8177: Async methods cannot use by-reference variables
+// Line: 12
+
+using System.Threading.Tasks;
+
+class X
+{
+       int x;
+
+       async Task Test ()
+       {
+               ref int y = ref x;
+               await Task.Yield ();
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8178-2.cs b/mcs/errors/cs8178-2.cs
new file mode 100644 (file)
index 0000000..e61b7d9
--- /dev/null
@@ -0,0 +1,20 @@
+// CS8178: `await' cannot be used in an expression containing a call to `X.this[int]' because it returns by reference
+// Line: 12
+
+using System.Threading.Tasks;
+
+class X
+{
+       int x;
+
+       async Task Test ()
+       {
+               Foo (ref this [await Task.FromResult (1)]);
+       }
+
+       ref int this [int arg] => ref x;
+
+       static void Foo (ref int arg)
+       {
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8178.cs b/mcs/errors/cs8178.cs
new file mode 100644 (file)
index 0000000..6f77962
--- /dev/null
@@ -0,0 +1,24 @@
+// CS8178: `await' cannot be used in an expression containing a call to `X.Wrap(int)' because it returns by reference
+// Line: 12
+
+using System.Threading.Tasks;
+
+class X
+{
+       int x;
+
+       async Task Test ()
+       {
+               Foo (ref Wrap (await Task.FromResult (1))) = 4;
+       }
+
+       ref int Wrap (int arg)
+       {
+               return ref x;
+       }
+
+       static ref int Foo (ref int arg)
+       {
+               return ref arg;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8189.cs b/mcs/errors/cs8189.cs
new file mode 100644 (file)
index 0000000..909ec3b
--- /dev/null
@@ -0,0 +1,17 @@
+// CS8189: By reference return delegate does not match `C.D()' return type
+// Line: 15
+
+class C
+{
+       delegate ref int D ();
+
+       static int M ()
+       {
+               return 1;
+       }
+
+       static void Main ()
+       {
+               D d = new D (M);
+       }
+}
\ No newline at end of file
index 40f81ded9703c88ae78fa849f4db1d028545e0bf..c9ed9317350d471d891e70fc18423b7a99c1bd44 100644 (file)
@@ -22,3 +22,8 @@ cs8129.cs NO ERROR
 cs8141.cs
 cs8141-2.cs
 cs8144.cs
+cs8157.cs NO ERROR
+cs8160.cs
+cs8161.cs
+cs8170.cs NO ERROR
+cs8170-2.cs
index 00fd56d8a64a23743451fc6b829f07abe77f3cec..8421b4dfbfcc766e11af46e124c59be508d68165 100644 (file)
@@ -104,12 +104,17 @@ namespace Mono.CSharp
                        return Clone (Expr.Clone (clonectx));
                }
 
-               public virtual Expression CreateExpressionTree (ResolveContext ec)
+               public virtual Expression CreateExpressionTree (ResolveContext rc)
                {
+                       if (Type.Kind == MemberKind.ByRef) {
+                               rc.Report.Error (8153, Expr.Location, "An expression tree lambda cannot contain a call to a method, property, or indexer that returns by reference");
+                               return null;
+                       }
+
                        if (ArgType == AType.Default)
-                               ec.Report.Error (854, Expr.Location, "An expression tree cannot contain an invocation which uses optional parameter");
+                               rc.Report.Error (854, Expr.Location, "An expression tree cannot contain an invocation which uses optional parameter");
 
-                       return Expr.CreateExpressionTree (ec);
+                       return Expr.CreateExpressionTree (rc);
                }
 
 
@@ -126,12 +131,16 @@ namespace Mono.CSharp
                                return;
                        }
 
+                       if (Expr.Type.Kind == MemberKind.ByRef) {
+                               Expr.Emit (ec);
+                               return;
+                       }
+
                        AddressOp mode = AddressOp.Store;
                        if (ArgType == AType.Ref)
                                mode |= AddressOp.Load;
 
-                       IMemoryLocation ml = (IMemoryLocation) Expr;
-                       ml.AddressOf (ec, mode);
+                       ((IMemoryLocation)Expr).AddressOf (ec, mode);
                }
 
                public Argument EmitToField (EmitContext ec, bool cloneResult)
@@ -421,17 +430,19 @@ namespace Mono.CSharp
                        return all;
                }
 
-               public static Arguments CreateForExpressionTree (ResolveContext ec, Arguments args, params Expression[] e)
+               public static Arguments CreateForExpressionTree (ResolveContext rc, Arguments args, params Expression[] e)
                {
                        Arguments all = new Arguments ((args == null ? 0 : args.Count) + e.Length);
                        for (int i = 0; i < e.Length; ++i) {
-                               if (e [i] != null)
-                                       all.Add (new Argument (e[i]));
+                               var expr = e [i];
+                               if (expr != null) {
+                                       all.Add (new Argument (expr));
+                               }
                        }
 
                        if (args != null) {
                                foreach (Argument a in args.args) {
-                                       Expression tree_arg = a.CreateExpressionTree (ec);
+                                       Expression tree_arg = a.CreateExpressionTree (rc);
                                        if (tree_arg != null)
                                                all.Add (new Argument (tree_arg));
                                }
index 48b1c6921f3c897fe0b8e5780e59fe5f34a514aa..07bf45f12ef73f8e0a8527053f96bb599948793e 100644 (file)
@@ -3527,7 +3527,10 @@ namespace Mono.CSharp
                        var base_member_type = ((IInterfaceMemberSpec)base_member).MemberType;
                        if (!TypeSpecComparer.Override.IsEqual (MemberType, base_member_type)) {
                                Report.SymbolRelatedToPreviousError (base_member);
-                               if (this is PropertyBasedMember) {
+                               if (((base_member_type.Kind ^ MemberType.Kind) & MemberKind.ByRef) != 0) {
+                                       Report.Error (8148, Location, "`{0}': must {2}return by reference to match overridden member `{1}'",
+                                                     GetSignatureForError (), base_member.GetSignatureForError (), base_member_type.Kind == MemberKind.ByRef ? "" : "not ");
+                               } else if (this is PropertyBasedMember) {
                                        Report.Error (1715, Location, "`{0}': type must be `{1}' to match overridden member `{2}'",
                                                GetSignatureForError (), base_member_type.GetSignatureForError (), base_member.GetSignatureForError ());
                                } else {
index 8fe0e2026ca5842fdc286d456bf41a536f79456b..b11477c104394b7bc77075d6e4fa02827797529e 100644 (file)
@@ -1503,6 +1503,11 @@ namespace Mono.CSharp {
                                        return null;
                        }
 
+                       if (expr is ReferenceExpression) {
+                               // Only identify conversion is allowed
+                               return null;
+                       }
+
                        e = ImplicitNumericConversion (expr, expr_type, target_type);
                        if (e != null)
                                return e;
index 5f885a77763b8ccebc07be47fb643c310be926f5..648effd7f1095c7731e5ed6797a6bd3ceb20dd3e 100644 (file)
@@ -1161,7 +1161,7 @@ constant_initializer_expr
 field_declaration
        : opt_attributes
          opt_modifiers
-         member_type IDENTIFIER
+         ref_member_type IDENTIFIER
          {
                lexer.parsing_generic_declaration = false;
 
@@ -1364,10 +1364,29 @@ method_declaration
          }
        ;
 
+ref_member_type
+       : member_type
+         {
+               $$ = $1;
+         }
+       | REF
+         {
+               lexer.parsing_generic_declaration = true;
+         }
+         type
+         {
+               if (lang_version < LanguageVersion.V_7) {
+                       FeatureIsNotAvailable (GetLocation ($1), "byref locals and returns");
+               }
+
+               $$ = new ReferenceTypeExpr ((FullNamedExpression) $3, GetLocation ($1));
+         }
+       ;
+
 method_header
        : opt_attributes
          opt_modifiers
-         member_type
+         ref_member_type
          method_declaration_name OPEN_PARENS
          {
                valid_param_mod = ParameterModifierType.All;
@@ -1452,7 +1471,7 @@ method_header
          }
        | opt_attributes
          opt_modifiers
-         member_type
+         ref_member_type
          modifiers method_declaration_name OPEN_PARENS opt_formal_parameter_list CLOSE_PARENS
          {
                MemberName name = (MemberName) $5;
@@ -1473,7 +1492,7 @@ method_header
          }
        | opt_attributes
          opt_modifiers
-         member_type
+         ref_member_type
          method_declaration_name error
          {
                Error_SyntaxError (yyToken);
@@ -1534,7 +1553,7 @@ expression_block
                ++lexer.parsing_block;
                start_block (GetLocation ($1));
         }
-        expression SEMICOLON
+        lambda_arrow_expression SEMICOLON
         {
                lexer.parsing_block = 0;
                current_block.AddStatement (new ContextualReturn ((Expression) $3));
@@ -1838,7 +1857,7 @@ arglist_modifier
 property_declaration
        : opt_attributes
          opt_modifiers
-         member_type
+         ref_member_type
          member_declaration_name
          {
                lexer.parsing_generic_declaration = false;
@@ -1865,6 +1884,16 @@ property_declaration
 
                if (doc_support)
                        current_property.DocComment = ConsumeStoredComment ();
+
+               if ($3 is ReferenceTypeExpr) {
+                       if (current_property.Get == null) {
+                               report.Error (8146, GetLocation ($4), "`{0}': property and indexer which return by reference must have a get accessor", current_property.GetSignatureForError ());
+                       }
+
+                       if (current_property.Set != null) {
+                               report.Error (8147, GetLocation ($4), "`{0}': property and indexer which return by reference cannot have set accessors", current_property.GetSignatureForError ());
+                       }
+               }
          }
          CLOSE_BRACE
          {
@@ -1877,7 +1906,7 @@ property_declaration
          }
        | opt_attributes
          opt_modifiers
-         member_type
+         ref_member_type
          member_declaration_name
          {
                lexer.parsing_generic_declaration = false;
@@ -1939,7 +1968,7 @@ property_initializer
 
 indexer_declaration
        : opt_attributes opt_modifiers
-         member_type indexer_declaration_name OPEN_BRACKET
+         ref_member_type indexer_declaration_name OPEN_BRACKET
          {
                valid_param_mod = ParameterModifierType.Params | ParameterModifierType.DefaultValue;
          }
@@ -1979,6 +2008,16 @@ indexer_declaration
          
                if (doc_support)
                        current_property.DocComment = ConsumeStoredComment ();
+
+               if ($3 is ReferenceTypeExpr) {
+                       if (current_property.Get == null) {
+                               report.Error (8146, GetLocation ($4), "`{0}': property and indexer which return by reference must have a get accessor", current_property.GetSignatureForError ());
+                       }
+
+                       if (current_property.Set != null) {
+                               report.Error (8147, GetLocation ($4), "`{0}': property and indexer which return by reference cannot have set accessors", current_property.GetSignatureForError ());
+                       }
+               }
                        
                current_property = null;                
          }
@@ -2938,7 +2977,7 @@ delegate_declaration
        : opt_attributes
          opt_modifiers
          DELEGATE
-         member_type type_declaration_name
+         ref_member_type type_declaration_name
          OPEN_PARENS
          {
                valid_param_mod = ParameterModifierType.Ref | ParameterModifierType.Out | ParameterModifierType.Params | ParameterModifierType.DefaultValue;
@@ -5109,7 +5148,7 @@ lambda_expression_body
        : {
                start_block (Location.Null);
          }
-         expression    // All expressions must handle error or current block won't be restored and breaking ast completely
+         lambda_arrow_expression       // All expressions must handle error or current block won't be restored and breaking ast completely
          {
                Block b = end_block (Location.Null);
                b.IsCompilerGenerated = true;
@@ -5129,6 +5168,11 @@ lambda_expression_body
          }
        ;
 
+lambda_arrow_expression
+       : expression
+       | reference_expression
+       ;
+
 expression_or_error
        : expression
        | error
@@ -5939,6 +5983,28 @@ block_variable_declaration
                current_variable = null;
                lbag.AddLocation ($$, GetLocation ($1), GetLocation ($7));
          }
+       | REF variable_type identifier_inside_body
+         {
+               if (lang_version < LanguageVersion.V_7) {
+                       FeatureIsNotAvailable (GetLocation ($1), "byref locals and returns");
+               }
+
+               var lt = (LocatedToken) $3;
+               var li = new LocalVariable (current_block, lt.Value, LocalVariable.Flags.ByRef, lt.Location);
+               current_block.AddLocalName (li);
+               current_variable = new BlockVariable ((FullNamedExpression) $2, li);
+         }
+         opt_local_variable_initializer opt_variable_declarators SEMICOLON
+         {
+               $$ = current_variable;
+               current_variable = null;
+               if ($5 != null) {
+                       lbag.AddLocation ($$, PopLocation (), GetLocation ($7));
+               } else {
+                       report.Error (8174, GetLocation ($3), "A declaration of a by-reference variable must have an initializer");
+                       lbag.AddLocation ($$, GetLocation ($7));
+               }
+         }
        ;
 
 opt_local_variable_initializer
@@ -6047,6 +6113,18 @@ block_variable_initializer
                report.Error (1575, GetLocation ($1), "A stackalloc expression requires [] after type");
                $$ = new StackAlloc ((Expression) $2, null, GetLocation ($1));          
          }
+       | reference_expression
+       ;
+
+reference_expression
+       : REF expression
+         {
+               if (lang_version < LanguageVersion.V_7) {
+                       FeatureIsNotAvailable (GetLocation ($1), "byref locals and returns");
+               }
+
+               $$ = new ReferenceExpression ((Expression) $2, GetLocation ($1));
+         }
        ;
 
 expression_statement
@@ -6522,6 +6600,11 @@ return_statement
                $$ = new Return ((Expression) $2, GetLocation ($1));
                lbag.AddStatement ($$, GetLocation ($3));
          }
+       | RETURN reference_expression SEMICOLON
+         {
+               $$ = new Return ((Expression) $2, GetLocation ($1));
+               lbag.AddStatement ($$, GetLocation ($3));
+         }
        | RETURN expression error
          {
                Error_SyntaxError (yyToken);
index 368bb19c1b165d507f90e877ec40a5b993217093..80eb7e265f1395bec67ce6ba117212b0474a80b5 100644 (file)
@@ -587,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) {
@@ -639,7 +638,7 @@ namespace Mono.CSharp {
                        method_group.FlowAnalysis (fc);
                }
 
-               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 ?
@@ -661,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));
index 9486475305452e2ab5c326d264e3f0954e58a661..490bcfb518e5c4a78535f71c07bc2e6c8dde9ce4 100644 (file)
@@ -303,7 +303,12 @@ namespace Mono.CSharp {
                                return;
 
                        string from_type = type.GetSignatureForError ();
+                       if (type.Kind == MemberKind.ByRef)
+                               from_type = "ref " + from_type;
                        string to_type = target.GetSignatureForError ();
+                       if (target.Kind == MemberKind.ByRef)
+                               to_type = "ref " + to_type;
+
                        if (from_type == to_type) {
                                from_type = type.GetSignatureForErrorIncludingAssemblyName ();
                                to_type = target.GetSignatureForErrorIncludingAssemblyName ();
@@ -559,18 +564,18 @@ namespace Mono.CSharp {
                public Expression ResolveLValue (ResolveContext ec, Expression right_side)
                {
                        int errors = ec.Report.Errors;
-                       bool out_access = right_side == EmptyExpression.OutAccess;
+                       //bool out_access = right_side == EmptyExpression.OutAccess;
 
                        Expression e = DoResolveLValue (ec, right_side);
 
-                       if (e != null && out_access && !(e is IMemoryLocation)) {
+                       //if (e != null && out_access && !(e is IMemoryLocation)) {
                                // FIXME: There's no problem with correctness, the 'Expr = null' handles that.
                                //        Enabling this 'throw' will "only" result in deleting useless code elsewhere,
 
                                //throw new InternalErrorException ("ResolveLValue didn't return an IMemoryLocation: " +
                                //                                e.GetType () + " " + e.GetSignatureForError ());
-                               e = null;
-                       }
+                       //      e = null;
+                       //}
 
                        if (e == null) {
                                if (errors == ec.Report.Errors) {
@@ -5417,6 +5422,11 @@ namespace Mono.CSharp {
                                        if (arg_type == InternalType.VarOutType)
                                                return 0;
 
+                                       var ref_arg_type = arg_type as ReferenceContainer;
+                                       if (ref_arg_type != null) {
+                                               arg_type = ref_arg_type.Element;
+                                       }
+
                                        //
                                        // Do full equality check after quick path
                                        //
@@ -5982,13 +5992,13 @@ namespace Mono.CSharp {
                        int arg_count = args == null ? 0 : args.Count;
 
                        for (; a_idx < arg_count; a_idx++, ++a_pos) {
-                               a = args[a_idx];
+                               a = args [a_idx];
                                if (a == null)
                                        continue;
 
                                if (p_mod != Parameter.Modifier.PARAMS) {
                                        p_mod = cpd.FixedParameters [a_idx].ModFlags;
-                                       pt = ptypes[a_idx];
+                                       pt = ptypes [a_idx];
                                        has_unsafe_arg |= pt.IsPointer;
 
                                        if (p_mod == Parameter.Modifier.PARAMS) {
@@ -6018,6 +6028,14 @@ namespace Mono.CSharp {
                                                continue;
                                        }
 
+                                       var ref_arg_type = arg_type as ReferenceContainer;
+                                       if (ref_arg_type != null) {
+                                               if (ref_arg_type.Element != pt)
+                                                       break;
+
+                                               return true;
+                                       }
+
                                        if (!TypeSpecComparer.IsEqual (arg_type, pt))
                                                break;
                                }
@@ -6525,12 +6543,12 @@ namespace Mono.CSharp {
                                                GetSignatureForError ());
                                }
 
-                               return null;
+                               return ErrorExpression.Instance;
                        }
 
                        if (right_side == EmptyExpression.LValueMemberAccess) {
                                // Already reported as CS1648/CS1650
-                               return null;
+                               return ErrorExpression.Instance;
                        }
 
                        if (right_side == EmptyExpression.LValueMemberOutAccess) {
@@ -6541,7 +6559,7 @@ namespace Mono.CSharp {
                                        rc.Report.Error (1649, loc, "Members of readonly field `{0}' cannot be passed ref or out (except in a constructor)",
                                                GetSignatureForError ());
                                }
-                               return null;
+                               return ErrorExpression.Instance;
                        }
 
                        if (IsStatic) {
@@ -6552,7 +6570,7 @@ namespace Mono.CSharp {
                                        GetSignatureForError ());
                        }
 
-                       return null;
+                       return ErrorExpression.Instance;
                }
 
                public override Expression DoResolveLValue (ResolveContext ec, Expression right_side)
@@ -7341,6 +7359,15 @@ namespace Mono.CSharp {
                                Error_NullPropagatingLValue (rc);
 
                        if (right_side == EmptyExpression.OutAccess) {
+                               if (best_candidate?.MemberType.Kind == MemberKind.ByRef) {
+                                       if (Arguments?.ContainsEmitWithAwait () == true) {
+                                               rc.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
+                                                       GetSignatureForError ());
+                                       }
+
+                                       return this;
+                               }
+
                                // TODO: best_candidate can be null at this point
                                INamedBlockVariable variable = null;
                                if (best_candidate != null && rc.CurrentBlock.ParametersBlock.TopBlock.GetLocalName (best_candidate.Name, rc.CurrentBlock, ref variable) && variable is Linq.RangeVariable) {
index 113ed29910c155493a769098bc9e058a05712a96..3407b9faf884118562ea008f55c838c4b5d885bd 100644 (file)
@@ -6562,18 +6562,19 @@ namespace Mono.CSharp
                                return;
                        }
 
+                       bool dereference = IsRef && !(source is ReferenceExpression);
                        New n_source = source as New;
                        if (n_source != null && n_source.CanEmitOptimizedLocalTarget (ec)) {
                                if (!n_source.Emit (ec, this)) {
                                        if (leave_copy) {
                                                EmitLoad (ec);
-                                               if (IsRef)
+                                               if (dereference)
                                                        ec.EmitLoadFromPtr (type);
                                        }
                                        return;
                                }
                        } else {
-                               if (IsRef)
+                               if (dereference)
                                        EmitLoad (ec);
 
                                source.Emit (ec);
@@ -6581,13 +6582,13 @@ namespace Mono.CSharp
 
                        if (leave_copy) {
                                ec.Emit (OpCodes.Dup);
-                               if (IsRef) {
+                               if (dereference) {
                                        temp = new LocalTemporary (Type);
                                        temp.Store (ec);
                                }
                        }
 
-                       if (IsRef)
+                       if (dereference)
                                ec.EmitStoreFromPtr (type);
                        else
                                Variable.EmitAssign (ec);
@@ -6671,7 +6672,7 @@ namespace Mono.CSharp
                }
 
                public override bool IsRef {
-                       get { return false; }
+                       get { return local_info.IsByRef; }
                }
 
                public override string Name {
@@ -6712,7 +6713,11 @@ namespace Mono.CSharp
                                        AnonymousMethodExpression.Error_AddressOfCapturedVar (ec, this, loc);
                                } else if (local_info.IsFixed) {
                                        ec.Report.Error (1764, loc,
-                                               "Cannot use fixed local `{0}' inside an anonymous method, lambda expression or query expression",
+                                               "Cannot use fixed variable `{0}' inside an anonymous method, lambda expression or query expression",
+                                               GetSignatureForError ());
+                               } else if (local_info.IsByRef) {
+                                       ec.Report.Error (8175, loc,
+                                               "Cannot use by-reference variable `{0}' inside an anonymous method, lambda expression, or query expression",
                                                GetSignatureForError ());
                                }
 
@@ -7134,7 +7139,7 @@ namespace Mono.CSharp
                protected override Expression DoResolve (ResolveContext rc)
                {
                        ResolveConditionalAccessReceiver (rc);
-                       return DoResolveInvocation (rc);
+                       return DoResolveInvocation (rc, null);
                }
 
                public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
@@ -7161,10 +7166,21 @@ namespace Mono.CSharp
                                return res.Resolve (rc);
                        }
 
+                       if (right_side != null) {
+                               if (eclass != ExprClass.Unresolved)
+                                       return this;
+
+                               var res = DoResolveInvocation (rc, right_side);
+                               if (res == null)
+                                       return null;
+
+                               return res;
+                       }
+
                        return base.DoResolveLValue (rc, right_side);
                }
 
-               Expression DoResolveInvocation (ResolveContext ec)
+               Expression DoResolveInvocation (ResolveContext ec, Expression rhs)
                {
                        Expression member_expr;
                        var atn = expr as ATypeNameExpression;
@@ -7260,6 +7276,17 @@ namespace Mono.CSharp
                        IsSpecialMethodInvocation (ec, method, loc);
                        
                        eclass = ExprClass.Value;
+
+                       if (type.Kind == MemberKind.ByRef) {
+                               if (rhs == null && arguments?.ContainsEmitWithAwait () == true) {
+                                       ec.Report.Error (8178, loc, "`await' cannot be used in an expression containing a call to `{0}' because it returns by reference",
+                                               GetSignatureForError ());
+                               }
+
+                               if (rhs != EmptyExpression.OutAccess)
+                                       return ByRefDereference.Create (this).Resolve (ec);
+                       }
+
                        return this;
                }
 
@@ -11591,6 +11618,39 @@ namespace Mono.CSharp
                }
        }
 
+       class ReferenceTypeExpr : TypeExpr
+       {
+               FullNamedExpression element;
+
+               public ReferenceTypeExpr (FullNamedExpression element, Location loc)
+               {
+                       this.element = element;
+                       this.loc = loc;
+               }
+
+               public override TypeSpec ResolveAsType (IMemberContext mc, bool allowUnboundTypeArguments = false)
+               {
+                       type = element.ResolveAsType (mc);
+                       if (type == null)
+                               return null;
+
+                       eclass = ExprClass.Type;
+                       type = ReferenceContainer.MakeType (mc.Module, type);
+
+                       return type;
+               }
+
+               public override string GetSignatureForError ()
+               {
+                       return "ref " + element.GetSignatureForError ();
+               }
+
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
+       }
+
        class FixedBufferPtr : Expression
        {
                readonly Expression array;
@@ -12918,4 +12978,146 @@ namespace Mono.CSharp
                        return Reachability.CreateUnreachable ();
                }
        }
+
+       class ReferenceExpression : CompositeExpression
+       {
+               public ReferenceExpression (Expression expr, Location loc)
+                       : base (expr)
+               {
+                       this.loc = loc;
+               }
+
+               static bool CanBeByRef (Expression expr)
+               {
+                       if (expr is IAssignMethod)
+                               return true;
+
+                       var invocation = expr as Invocation;
+                       if (invocation?.Type.Kind == MemberKind.ByRef)
+                               return true;
+
+                       return false;
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext rc)
+               {
+                       throw new NotSupportedException ("ET");
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       var res = expr.DoResolveLValue (rc, EmptyExpression.OutAccess);
+                       if (res == null || !CanBeByRef (res)) {
+                               if (res?.Type != InternalType.ErrorType)
+                                       rc.Report.Error (8156, expr.Location, "An expression cannot be used in this context because it may not be returned by reference");
+                               return ErrorExpression.Instance;
+                       }
+
+                       type = res.Type;
+                       var type_container = type as ReferenceContainer;
+                       if (type_container != null)
+                               type = type_container.Element;
+
+                       expr = res;
+                       eclass = ExprClass.Value;
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       var ml = expr as IMemoryLocation;
+                       if (ml != null)
+                               ml.AddressOf (ec, AddressOp.LoadStore);
+                       else
+                               expr.Emit (ec);
+               }
+
+               public override void Error_ValueCannotBeConverted (ResolveContext rc, TypeSpec target, bool expl)
+               {
+                       rc.Report.Error (8173, loc, "The expression must be of type `{0}' because it is being assigned by reference", target.GetSignatureForError ());
+               }
+       }
+
+       class ByRefDereference : CompositeExpression, IMemoryLocation, IAssignMethod
+       {
+               bool prepared;
+               LocalTemporary temporary;
+
+               private ByRefDereference (Expression expr)
+                       : base (expr)
+               {
+               }
+
+               public static Expression Create (Expression expr)
+               {
+                       var rc = expr.Type as ReferenceContainer;
+                       if (rc == null)
+                               return expr;
+
+                       return new ByRefDereference (expr) {
+                               type = rc.Element
+                       };
+               }
+
+               public void AddressOf (EmitContext ec, AddressOp mode)
+               {
+                       expr.Emit (ec);
+               }
+
+               public void Emit (EmitContext ec, bool leave_copy)
+               {
+                       Emit (ec);
+                       if (leave_copy) {
+                               ec.Emit (OpCodes.Dup);
+                               temporary = new LocalTemporary (type);
+                               temporary.Store (ec);
+                       }
+               }
+
+               public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool isCompound)
+               {
+                       prepared = isCompound;
+
+                       expr.Emit (ec);
+
+                       if (isCompound)
+                               ec.Emit (OpCodes.Dup);
+                       
+                       source.Emit (ec);
+                       if (leave_copy) {
+                               throw new NotImplementedException ("leave_copy");
+                       }
+                       
+                       ec.EmitStoreFromPtr (type);
+                       
+                       if (temporary != null) {
+                               temporary.Emit (ec);
+                               temporary.Release (ec);
+                       }
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       eclass = ExprClass.Variable;
+                       return this;
+               }
+
+               public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
+               {
+                       return DoResolve (rc);
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       if (!prepared)
+                               base.Emit(ec);
+                       
+                       ec.EmitLoadFromPtr (type);
+               }
+
+               public override object Accept (StructuralVisitor visitor)
+               {
+                       return visitor.Visit (this);
+               }
+       }
 }
index 1efba64ba575caf08f33deae99bafc47c5fc4e3f..625cd0c773f0588fefcd0b3055c1ddbc20d0e44a 100644 (file)
@@ -1543,6 +1543,9 @@ namespace Mono.CSharp {
                                        if (ec is PointerContainer)
                                                return PointerContainer.MakeType (context.Module, et);
 
+                                       if (ec is ReferenceContainer)
+                                               return ReferenceContainer.MakeType (context.Module, et);
+                                       
                                        throw new NotImplementedException ();
                                }
 
index c0ccf129e74a77fd44b33e4c702b9e69412cd1e6..feb10844b8c7f0eac017a4454d3d7bf8a5d426b2 100644 (file)
@@ -1187,11 +1187,15 @@ namespace Mono.CSharp
                                return;
 
                        if (!CheckType (ret, parent, out iterator_type, out is_enumerable)) {
-                               parent.Compiler.Report.Error (1624, method.Location,
-                                             "The body of `{0}' cannot be an iterator block " +
-                                             "because `{1}' is not an iterator interface type",
-                                             method.GetSignatureForError (),
-                                             ret.GetSignatureForError ());
+                               if (ret.Kind == MemberKind.ByRef) {
+                                       parent.Compiler.Report.Error (8154, method.Location,
+                                                         "The body of `{0}' cannot be an iterator block because the method returns by reference",
+                                                         method.GetSignatureForError ());
+                               } else {
+                                       parent.Compiler.Report.Error (1624, method.Location,
+                                                         "The body of `{0}' cannot be an iterator block because `{1}' is not an iterator interface type",
+                                                         method.GetSignatureForError (), ret.GetSignatureForError ());
+                               }
                                return;
                        }
 
index 9c804ceca575e6730e194e54a8bce5735a24cb81..360c5c9463002d0d8e1956573bfcb688702589e4 100644 (file)
@@ -188,6 +188,11 @@ namespace Mono.CSharp {
 
                public override Expression CreateExpressionTree (ResolveContext ec)
                {
+                       if (Expr is ReferenceExpression) {
+                               ec.Report.Error (8155, Expr.Location, "Lambda expressions that return by reference cannot be converted to expression trees");
+                               return null;
+                       }
+
                        return Expr.CreateExpressionTree (ec);
                }
 
@@ -216,6 +221,12 @@ namespace Mono.CSharp {
                                if (Expr == null)
                                        return false;
 
+                               if (Expr is ReferenceExpression) {
+                                       // CSC: should be different error code
+                                       ec.Report.Error (8149, loc, "By-reference returns can only be used in lambda expressions that return by reference");
+                                       return false;
+                               }
+
                                statement = Expr as ExpressionStatement;
                                if (statement == null) {
                                        var reduced = Expr as IReducedExpressionStatement;
index d132c872bafced81c59fd1eaf5bc8fd8245eb9a1..eebf71b844b8e2a51337bf35a1560c7b13d7134f 100644 (file)
@@ -35,6 +35,7 @@ namespace Mono.CSharp {
                Enum            = 1 << 14,
                Interface       = 1 << 15,
                TypeParameter = 1 << 16,
+               ByRef           = 1 << 17,
 
                ArrayType = 1 << 19,
                PointerType = 1 << 20,
index 1de765fb4ac041eb7926c501e0aeb235c98579ad..d95f8f13956d867d0d60df079a4a10e9ebe98c80 100644 (file)
@@ -748,6 +748,11 @@ namespace Mono.CSharp {
                                                                Report.Error (737, container.Location,
                                                                        "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' is not public",
                                                                        container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError ());
+                                                       } else if (mi.ReturnType.Kind == MemberKind.ByRef) {
+                                                               Report.Error (8152, container.Location,
+                                                                       "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' return type `{3}' does not return by reference",
+                                                                       container.GetSignatureForError (), mi.GetSignatureForError (), candidate.GetSignatureForError (),
+                                                                       candidate.ReturnType.GetSignatureForError ());
                                                        } else {
                                                                Report.Error (738, container.Location,
                                                                        "`{0}' does not implement interface member `{1}' and the best implementing candidate `{2}' return type `{3}' does not match interface member return type `{4}'",
index 1dd8a86468eb1ab0f2727a649f67d3273ed6d8cd..3478711470a0fa6d93b668621c5d60392e2fda08 100644 (file)
@@ -879,6 +879,11 @@ namespace Mono.CSharp
                                        return false;
                                }
 
+                               if (MemberType.Kind == MemberKind.ByRef) {
+                                       Report.Error (8145, Location, "Auto-implemented properties cannot return by reference");
+                                       return false;
+                               }
+
                                if (Compiler.Settings.Version < LanguageVersion.V_3 && Initializer == null)
                                        Report.FeatureIsNotAvailable (Compiler, Location, "auto-implemented properties");
 
index 7a379fc172aff0bd375aefb7cdbee386f7e4f0c4..0c02bf0562a271da6811188fd102ecf836f0986a 100644 (file)
@@ -1272,16 +1272,38 @@ namespace Mono.CSharp {
                        if (expr == null)
                                return false;
 
+                       if (expr is ReferenceExpression && block_return_type.Kind != MemberKind.ByRef) {
+                               ec.Report.Error (8149, loc, "By-reference returns can only be used in methods that return by reference");
+                               return false;
+                       }
+
                        if (expr.Type != block_return_type && expr.Type != InternalType.ErrorType) {
-                               expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+                               if (block_return_type.Kind == MemberKind.ByRef) {
+                                       var ref_expr = Expr as ReferenceExpression;
+                                       if (ref_expr == null) {
+                                               ec.Report.Error (8150, loc, "By-reference return is required when method returns by reference");
+                                               return false;
+                                       }
 
-                               if (expr == null) {
-                                       if (am != null && block_return_type == ec.ReturnType) {
-                                               ec.Report.Error (1662, loc,
-                                                       "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
-                                                       am.ContainerType, am.GetSignatureForError ());
+                                       var byref_return = (ReferenceContainer)block_return_type;
+
+                                       if (expr.Type != byref_return.Element) {
+                                               ec.Report.Error (8151, loc, "The return by reference expression must be of type `{0}' because this method returns by reference",
+                                                                                byref_return.GetSignatureForError ());
+                                               return false;
+                                       }
+                               } else {
+
+                                       expr = Convert.ImplicitConversionRequired (ec, expr, block_return_type, loc);
+
+                                       if (expr == null) {
+                                               if (am != null && block_return_type == ec.ReturnType) {
+                                                       ec.Report.Error (1662, loc,
+                                                               "Cannot convert `{0}' to delegate type `{1}' because some of the return types in the block are not implicitly convertible to the delegate return type",
+                                                               am.ContainerType, am.GetSignatureForError ());
+                                               }
+                                               return false;
                                        }
-                                       return false;
                                }
                        }
 
@@ -2185,7 +2207,7 @@ namespace Mono.CSharp {
                                }
 
                                if (type == null) {
-                                       type = type_expr.ResolveAsType (bc);
+                                       type = ResolveTypeExpression (bc);
                                        if (type == null)
                                                return false;
 
@@ -2208,6 +2230,25 @@ namespace Mono.CSharp {
                        }
 
                        if (initializer != null) {
+                               if (li.IsByRef) {
+                                       if (!(initializer is ReferenceExpression)) {
+                                               bc.Report.Error (8172, loc, "Cannot initialize a by-reference variable `{0}' with a value", li.Name);
+                                               return false;
+                                       }
+
+                                       if (bc.CurrentAnonymousMethod is AsyncInitializer) {
+                                               bc.Report.Error (8177, loc, "Async methods cannot use by-reference variables");
+                                       } else if (bc.CurrentIterator != null) {
+                                               bc.Report.Error (8176, loc, "Iterators cannot use by-reference variables");
+                                       }
+
+                               } else {
+                                       if (initializer is ReferenceExpression) {
+                                               bc.Report.Error (8171, loc, "Cannot initialize a by-value variable `{0}' with a reference expression", li.Name);
+                                               return false;
+                                       }
+                               }
+
                                initializer = ResolveInitializer (bc, li, initializer);
                                // li.Variable.DefinitelyAssigned 
                        }
@@ -2237,6 +2278,11 @@ namespace Mono.CSharp {
                        return a.ResolveStatement (bc);
                }
 
+               protected virtual TypeSpec ResolveTypeExpression (BlockContext bc)
+               {
+                       return type_expr.ResolveAsType (bc);
+               }
+
                protected override void DoEmit (EmitContext ec)
                {
                        li.CreateBuilder (ec);
@@ -2364,6 +2410,7 @@ namespace Mono.CSharp {
                        UsingVariable = 1 << 7,
                        IsLocked = 1 << 8,
                        SymbolFileHidden = 1 << 9,
+                       ByRef = 1 << 10,
 
                        ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
                }
@@ -2448,6 +2495,8 @@ namespace Mono.CSharp {
                        }
                }
 
+               public bool IsByRef => (flags & Flags.ByRef) != 0;
+
                public bool IsCompilerGenerated {
                        get {
                                return (flags & Flags.CompilerGenerated) != 0;
@@ -2550,10 +2599,15 @@ namespace Mono.CSharp {
                                throw new InternalErrorException ("Already created variable `{0}'", name);
                        }
 
-                       //
-                       // All fixed variabled are pinned, a slot has to be alocated
-                       //
-                       builder = ec.DeclareLocal (Type, IsFixed);
+                       if (IsByRef) {
+                               builder = ec.DeclareLocal (ReferenceContainer.MakeType (ec.Module, Type), IsFixed);
+                       } else {
+                               //
+                               // All fixed variabled are pinned, a slot has to be alocated
+                               //
+                               builder = ec.DeclareLocal(Type, IsFixed);
+                       }
+
                        if ((flags & Flags.SymbolFileHidden) == 0)
                                ec.DefineLocalVariable (name, builder);
                }
@@ -2602,7 +2656,10 @@ namespace Mono.CSharp {
                        if ((flags & Flags.CompilerGenerated) != 0)
                                CreateBuilder (ec);
 
-                       ec.Emit (OpCodes.Ldloca, builder);
+                       if (IsByRef)
+                               ec.Emit (OpCodes.Ldloc, builder);
+                       else
+                               ec.Emit (OpCodes.Ldloca, builder);
                }
 
                public static string GetCompilerGeneratedName (Block block)
index e6ee60c585a8780e1af95af20b7941356d0a160b..0585dfd667a08d6d7f56cf247831eb915fbb7d49 100644 (file)
@@ -1991,10 +1991,11 @@ namespace Mono.CSharp
                }
        }
 
+       [System.Diagnostics.DebuggerDisplay("{DisplayDebugInfo()}")]
        class ReferenceContainer : ElementTypeSpec
        {
                ReferenceContainer (TypeSpec element)
-                       : base (MemberKind.Class, element, null)        // TODO: Kind.Class is most likely wrong
+                       : base (MemberKind.ByRef, element, null)
                {
                }
 
@@ -2004,6 +2005,11 @@ namespace Mono.CSharp
                        }
                }
 
+               string DisplayDebugInfo()
+               {
+                       return "ref " + GetSignatureForError();
+               }
+
                public override MetaType GetMetaInfo ()
                {
                        if (info == null) {
@@ -2013,8 +2019,16 @@ namespace Mono.CSharp
                        return info;
                }
 
+               public override string GetSignatureForError ()
+               {
+                       return Element.GetSignatureForError ();
+               }
+
                public static ReferenceContainer MakeType (ModuleContainer module, TypeSpec element)
                {
+                       if (element.Kind == MemberKind.ByRef)
+                               throw new ArgumentException ();
+
                        ReferenceContainer pc;
                        if (!module.ReferenceTypesCache.TryGetValue (element, out pc)) {
                                pc = new ReferenceContainer (element);
diff --git a/mcs/tests/test-ref-01.cs b/mcs/tests/test-ref-01.cs
new file mode 100644 (file)
index 0000000..60126a3
--- /dev/null
@@ -0,0 +1,38 @@
+// Compiler options: -unsafe
+
+public unsafe class X
+{
+       int field;
+       int* ufield;
+
+       public static void Main ()
+       {
+               int i = 5;
+               ref int j = ref i;
+
+               var x = new X ();
+               ref var v = ref x.TestMethod ();
+       }
+
+       ref int TestMethod ()
+       {
+               return ref field;
+       }
+
+       ref int TestProperty {
+               get {
+                       return ref field;
+               }
+       }
+
+       ref int this [long arg] {
+               get {
+                       return ref field;
+               }
+       }
+
+       unsafe ref int* Foo ()
+       {
+               return ref ufield;
+       }
+}
\ No newline at end of file
diff --git a/mcs/tests/test-ref-02.cs b/mcs/tests/test-ref-02.cs
new file mode 100644 (file)
index 0000000..9adf471
--- /dev/null
@@ -0,0 +1,35 @@
+using System;
+
+class X
+{
+       int field;
+
+       static void Main ()
+       {
+               var x = new X ();
+               x.Run ();
+       }
+
+       void Run ()
+       {
+               Test (ref this[0]);
+               Test (ref Prop);
+       }
+
+       static int Test (ref int y)
+       {
+               return y;
+       }
+
+       ref int this [int y] {
+               get {
+                       return ref field;
+               }
+       }
+
+       ref int Prop {
+               get {
+                       return ref field;
+               }
+       }
+}
\ No newline at end of file
diff --git a/mcs/tests/test-ref-03.cs b/mcs/tests/test-ref-03.cs
new file mode 100644 (file)
index 0000000..201bd6c
--- /dev/null
@@ -0,0 +1,33 @@
+class X
+{
+       int x;
+
+       static void Main ()
+       {
+               var x = new X ();
+               Foo (ref x.Wrap (1));
+               Foo (ref x.Prop);
+               Foo (ref x[""]);                
+       }
+
+       ref int Wrap (int arg)
+       {
+               return ref x;
+       }
+
+       ref int Prop {
+               get {
+                       return ref x;
+               }
+       }
+
+       ref int this [string arg] {
+               get {
+                       return ref x;
+               }
+       }
+
+       static void Foo (ref int arg)
+       {
+       }
+}
\ No newline at end of file
diff --git a/mcs/tests/test-ref-04.cs b/mcs/tests/test-ref-04.cs
new file mode 100644 (file)
index 0000000..af96f23
--- /dev/null
@@ -0,0 +1,45 @@
+class X
+{
+       int field;
+
+       public static int Main ()
+       {
+               var x = new X ();
+
+               x.field = 5;
+               if (!x.Test1 ())
+                       return 1;
+
+               x.Test2 ();
+
+               if (x.Test3 ()++ != 6)
+                       return 2;
+
+               if (x.field != 7)
+                       return 3;
+
+               return 0;
+       }
+
+       bool Test1 ()
+       {
+               ref var x = ref field;
+               int v = x;
+               ++x;
+
+               return x == 6;
+       }
+
+       void Test2 ()
+       {
+               ref int x = ref field;
+               x.ToString ();
+       }
+
+       ref int Test3 ()
+       {
+               ref int l = ref field;
+               ref int v = ref l;
+               return ref l;
+       }
+}
\ No newline at end of file
diff --git a/mcs/tests/test-ref-05.cs b/mcs/tests/test-ref-05.cs
new file mode 100644 (file)
index 0000000..4848468
--- /dev/null
@@ -0,0 +1,46 @@
+class X
+{
+       static int field;
+
+       public static int Main ()
+       {
+               Test () = 3;
+
+               if (field != (byte) 3)
+                       return 1;
+
+               G<string>.Test (ref field) = 6;
+               if (field != 6)
+                       return 2;
+
+               --Test ();
+               if (field != 5)
+                       return 3;
+
+               Test (ref Test (), ref Test ());
+
+               return 0;
+       }
+
+       static ref int Test ()
+       {
+               return ref field;
+       }
+
+       static void Test<T> (ref T a, ref int b)
+       {
+       }
+
+       static void Test2<T> (ref T arg)
+       {
+               Test (ref arg, ref Test ());
+       }
+}
+
+class G<U>
+{
+       public static ref T Test<T> (ref T arg)
+       {
+               return ref arg;
+       }
+}
\ No newline at end of file
index db5bfbd387c5090a47e7c7e01c8813a6cec6540e..b111a7e3c5a7ecf197d9e44d133978ad86c83303 100644 (file)
       </method>
     </type>
   </test>
+  <test name="test-ref-01.cs">
+    <type name="X">
+      <method name="Void Main()" attrs="150">
+        <size>20</size>
+      </method>
+      <method name="Int32&amp; TestMethod()" attrs="129">
+        <size>15</size>
+      </method>
+      <method name="Int32&amp; get_TestProperty()" attrs="2177">
+        <size>15</size>
+      </method>
+      <method name="Int32&amp; get_Item(Int64)" attrs="2177">
+        <size>15</size>
+      </method>
+      <method name="Int32*&amp; Foo()" attrs="129">
+        <size>15</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
+  <test name="test-ref-02.cs">
+    <type name="X">
+      <method name="Void Main()" attrs="145">
+        <size>14</size>
+      </method>
+      <method name="Void Run()" attrs="129">
+        <size>27</size>
+      </method>
+      <method name="Int32 Test(Int32 ByRef)" attrs="145">
+        <size>11</size>
+      </method>
+      <method name="Int32&amp; get_Item(Int32)" attrs="2177">
+        <size>15</size>
+      </method>
+      <method name="Int32&amp; get_Prop()" attrs="2177">
+        <size>15</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
+  <test name="test-ref-03.cs">
+    <type name="X">
+      <method name="Void Main()" attrs="145">
+        <size>47</size>
+      </method>
+      <method name="Int32&amp; Wrap(Int32)" attrs="129">
+        <size>15</size>
+      </method>
+      <method name="Int32&amp; get_Prop()" attrs="2177">
+        <size>15</size>
+      </method>
+      <method name="Int32&amp; get_Item(System.String)" attrs="2177">
+        <size>15</size>
+      </method>
+      <method name="Void Foo(Int32 ByRef)" attrs="145">
+        <size>2</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
+  <test name="test-ref-04.cs">
+    <type name="X">
+      <method name="Int32 Main()" attrs="150">
+        <size>93</size>
+      </method>
+      <method name="Boolean Test1()" attrs="129">
+        <size>30</size>
+      </method>
+      <method name="Void Test2()" attrs="129">
+        <size>22</size>
+      </method>
+      <method name="Int32&amp; Test3()" attrs="129">
+        <size>19</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
+  <test name="test-ref-05.cs">
+    <type name="X">
+      <method name="Int32 Main()" attrs="150">
+        <size>108</size>
+      </method>
+      <method name="Int32&amp; Test()" attrs="145">
+        <size>14</size>
+      </method>
+      <method name="Void Test[T](T ByRef, Int32 ByRef)" attrs="145">
+        <size>2</size>
+      </method>
+      <method name="Void Test2[T](T ByRef)" attrs="145">
+        <size>13</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+    <type name="G`1[U]">
+      <method name="T&amp; Test[T](T ByRef)" attrs="150">
+        <size>10</size>
+      </method>
+      <method name="Void .ctor()" attrs="6278">
+        <size>7</size>
+      </method>
+    </type>
+  </test>
   <test name="test-static-using-01.cs">
     <type name="A.B.X">
       <method name="Int32 Test()" attrs="150">