[mcs] declaration expression after ref/out argument
authorMarek Safar <marek.safar@gmail.com>
Mon, 22 Sep 2014 15:26:55 +0000 (17:26 +0200)
committerMarek Safar <marek.safar@gmail.com>
Mon, 22 Sep 2014 15:30:34 +0000 (17:30 +0200)
17 files changed:
mcs/errors/cs0411-24.cs [new file with mode: 0644]
mcs/errors/cs0815-7.cs [new file with mode: 0644]
mcs/errors/cs0841-5.cs [new file with mode: 0644]
mcs/errors/cs1501-18.cs
mcs/errors/cs1503-17.cs [new file with mode: 0644]
mcs/errors/cs1615-3.cs [new file with mode: 0644]
mcs/errors/cs1644-47.cs [new file with mode: 0644]
mcs/errors/cs8046.cs [new file with mode: 0644]
mcs/errors/cs8047.cs [new file with mode: 0644]
mcs/mcs/cs-parser.jay
mcs/mcs/dynamic.cs
mcs/mcs/ecore.cs
mcs/mcs/expression.cs
mcs/mcs/generic.cs
mcs/mcs/typespec.cs
mcs/tests/test-decl-expr-01.cs [new file with mode: 0644]
mcs/tests/ver-il-net_4_5.xml

diff --git a/mcs/errors/cs0411-24.cs b/mcs/errors/cs0411-24.cs
new file mode 100644 (file)
index 0000000..1462cba
--- /dev/null
@@ -0,0 +1,15 @@
+// CS0411: The type arguments for method `C.Foo<T>(out T)' cannot be inferred from the usage. Try specifying the type arguments explicitly
+// Line: 8
+
+public class C
+{
+       public static void Main ()
+       {
+               Foo (out var y);
+       }
+
+       static void Foo<T> (out T t)
+       {
+               t = default (T);
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs0815-7.cs b/mcs/errors/cs0815-7.cs
new file mode 100644 (file)
index 0000000..ae41a72
--- /dev/null
@@ -0,0 +1,15 @@
+// CS0815: An implicitly typed local variable declaration cannot be initialized with `void'
+// Line: 8
+
+class X
+{
+       public static void Main ()
+       {
+               Foo (out var x = Main ());
+       }
+
+       static void Foo (out int i)
+       {
+               i = 0;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs0841-5.cs b/mcs/errors/cs0841-5.cs
new file mode 100644 (file)
index 0000000..798b335
--- /dev/null
@@ -0,0 +1,15 @@
+// CS0841: A local variable `x' cannot be used before it is declared
+// Line: 8
+
+class X
+{
+       public static void Main ()
+       {
+               Foo (x, out var x);
+       }
+
+       static void Foo (int arg, out int value)
+       {
+               value = 3;
+       }
+}
\ No newline at end of file
index 6f445564e948e0982cf82234f6818456485db5f8..b22ab55c406ba3e8ce2ba31e308169a788297f37 100644 (file)
@@ -1,5 +1,5 @@
 // CS1501: No overload for method `Bar' takes `2' arguments
-// Line: 25
+// Line: 19
 
 using System;
 
@@ -13,14 +13,6 @@ class T
        {
        }
 
-       static void Mismatch (string s)
-       {
-       }
-
-       public static void Main ()
-       {
-       }
-
        void Bar ()
        {
                Foo (arg: 1, a: () => {
diff --git a/mcs/errors/cs1503-17.cs b/mcs/errors/cs1503-17.cs
new file mode 100644 (file)
index 0000000..26766c0
--- /dev/null
@@ -0,0 +1,14 @@
+// CS1501: Argument `#1' cannot convert `ref string' expression to type `ref int'
+// Line: 8
+
+class C
+{
+       public static void Main ()
+       {
+               Foo (ref var x = "");
+       }
+
+       static void Foo (ref int i)
+       {
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs1615-3.cs b/mcs/errors/cs1615-3.cs
new file mode 100644 (file)
index 0000000..c64fb7f
--- /dev/null
@@ -0,0 +1,18 @@
+// CS1615: Argument `#1' does not require `out' modifier. Consider removing `out' modifier
+// Line: 8
+
+public class C
+{
+       public static void Main ()
+       {
+               Foo (out var y);
+       }
+
+       static void Foo (int x)
+       {
+       }
+
+       static void Foo (string x)
+       {
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs1644-47.cs b/mcs/errors/cs1644-47.cs
new file mode 100644 (file)
index 0000000..b756cd7
--- /dev/null
@@ -0,0 +1,11 @@
+// CS1644: Feature `declaration expression' cannot be used because it is not part of the C# 5.0 language specification
+// Line: 12
+// Compiler options: -langversion:5
+
+class C
+{
+       public static void Main ()
+       {
+               int.TryParse ("0", out var v);
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8046.cs b/mcs/errors/cs8046.cs
new file mode 100644 (file)
index 0000000..f8b9ad5
--- /dev/null
@@ -0,0 +1,19 @@
+// CS8046: An expression tree cannot contain a declaration expression
+// Line: 11
+
+using System;
+using System.Linq.Expressions;
+
+class C
+{
+       static void Main()
+       {
+               Expression<Func<bool>> e = () => Out (out int x);
+       }
+
+       static bool Out (out int value)
+       {
+               value = 3;
+               return true;
+       }
+}
\ No newline at end of file
diff --git a/mcs/errors/cs8047.cs b/mcs/errors/cs8047.cs
new file mode 100644 (file)
index 0000000..7171d56
--- /dev/null
@@ -0,0 +1,19 @@
+// CS8047: Declaration expression cannot be used in this context
+// Line: 8
+
+public class C
+{
+       public static void Main ()
+       {
+               dynamic target = 3;
+               var x = new Test (target, out var y);
+       }
+}
+
+class Test
+{
+       public Test (int x, out int y)
+       {
+               y = 0;
+       }
+}
\ No newline at end of file
index d90cc01eb21ce3212b1e8258110d93cb96ecfba3..2db083886ca5e52b8b2d756ec25477f33400cac2 100644 (file)
@@ -871,7 +871,7 @@ named_attribute_argument
        ;
        
 named_argument
-       : identifier_inside_body COLON opt_named_modifier expression_or_error
+       : identifier_inside_body COLON opt_named_modifier named_argument_expr
          {
                if (lang_version <= LanguageVersion.V_3)
                        FeatureIsNotAvailable (GetLocation ($1), "named argument");
@@ -884,6 +884,11 @@ named_argument
                lbag.AddLocation ($$, GetLocation($2));
          }
        ;
+
+named_argument_expr
+       : expression_or_error
+       | declaration_expression
+       ;
        
 opt_named_modifier
        : /* empty */   { $$ = null; }
@@ -3606,11 +3611,19 @@ non_simple_argument
                $$ = new Argument ((Expression) $2, Argument.AType.Ref);
                lbag.AddLocation ($$, GetLocation ($1));
          }
+       | REF declaration_expression
+         {
+               $$ = new Argument ((Expression) $2, Argument.AType.Ref);
+         }
        | OUT variable_reference 
          { 
                $$ = new Argument ((Expression) $2, Argument.AType.Out);
                lbag.AddLocation ($$, GetLocation ($1));
          }
+       | OUT declaration_expression
+         {
+               $$ = new Argument ((Expression) $2, Argument.AType.Out);
+         }
        | ARGLIST OPEN_PARENS argument_list CLOSE_PARENS
          {
                $$ = new Argument (new Arglist ((Arguments) $3, GetLocation ($1)));
@@ -3623,6 +3636,48 @@ non_simple_argument
          }       
        ;
 
+declaration_expression
+       : OPEN_PARENS declaration_expression CLOSE_PARENS
+         {
+               $$ = new ParenthesizedExpression ((Expression) $2, GetLocation ($1));
+               lbag.AddLocation ($$, GetLocation ($1), GetLocation ($3));
+         }
+/*
+       | CHECKED open_parens_any declaration_expression CLOSE_PARENS
+         {
+               $$ = new CheckedExpr ((Expression) $3, GetLocation ($1));
+               lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4));
+         }
+       | UNCHECKED open_parens_any declaration_expression CLOSE_PARENS
+         {
+               $$ = new UnCheckedExpr ((Expression) $3, GetLocation ($1));
+               lbag.AddLocation ($$, GetLocation ($2), GetLocation ($4));
+         }
+*/
+       | variable_type identifier_inside_body
+         {
+               if (lang_version < LanguageVersion.V_6)
+                       FeatureIsNotAvailable (GetLocation ($1), "declaration expression");
+
+               var lt = (LocatedToken) $2;
+               var lv = new LocalVariable (current_block, lt.Value, lt.Location);
+               current_block.AddLocalName (lv);
+               $$ = new DeclarationExpression ((FullNamedExpression) $1, lv);
+         }
+       | variable_type identifier_inside_body ASSIGN expression
+         {
+               if (lang_version < LanguageVersion.V_6)
+                       FeatureIsNotAvailable (GetLocation ($1), "declaration expression");
+
+               var lt = (LocatedToken) $2;
+               var lv = new LocalVariable (current_block, lt.Value, lt.Location);
+               current_block.AddLocalName (lv);
+               $$ = new DeclarationExpression ((FullNamedExpression) $1, lv) {
+                       Initializer = (Expression) $4
+               };
+         }
+       ;
+
 variable_reference
        : expression
        ;
index 5604a3fcdc9da79542c44c435c840d12e6ac504f..8a9a0c87de2eb00488f65b94a1ea4b0ec348405d 100644 (file)
@@ -289,6 +289,13 @@ namespace Mono.CSharp
 
                protected bool DoResolveCore (ResolveContext rc)
                {
+                       foreach (var arg in arguments) {
+                               if (arg.Type == InternalType.VarOutType) {
+                                       // Should be special error message about dynamic dispatch
+                                       rc.Report.Error (8047, arg.Expr.Location, "Declaration expression cannot be used in this context");
+                               }
+                       }
+
                        if (rc.CurrentTypeParameters != null && rc.CurrentTypeParameters[0].IsMethodTypeParameter)
                                context_mvars = rc.CurrentTypeParameters;
 
index 94f4bcb129b7bcea307f2f37d452a3f14bbb6a50..7c2537c8bc7b8cdd386cacf6ad18349d7d3bbed9 100644 (file)
@@ -5144,31 +5144,36 @@ namespace Mono.CSharp {
                        // is used and argument is not of dynamic type
                        //
                        if (((argument.Modifier | param_mod) & Parameter.Modifier.RefOutMask) != 0) {
-                               if (argument.Type != parameter) {
+                               var arg_type = argument.Type;
+
+                               if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
+                                       //
+                                       // Using dynamic for ref/out parameter can still succeed at runtime
+                                       //
+                                       if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
+                                               return -1;
+
+                                       return 1;
+                               }
+
+                               if (arg_type != parameter) {
+                                       if (arg_type == InternalType.VarOutType)
+                                               return 0;
+
                                        //
                                        // Do full equality check after quick path
                                        //
-                                       if (!TypeSpecComparer.IsEqual (argument.Type, parameter)) {
+                                       if (!TypeSpecComparer.IsEqual (arg_type, parameter)) {
                                                //
                                                // Using dynamic for ref/out parameter can still succeed at runtime
                                                //
-                                               if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
+                                               if (arg_type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
                                                        return -1;
 
                                                return 2;
                                        }
                                }
 
-                               if ((argument.Modifier & Parameter.Modifier.RefOutMask) != (param_mod & Parameter.Modifier.RefOutMask)) {
-                                       //
-                                       // Using dynamic for ref/out parameter can still succeed at runtime
-                                       //
-                                       if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (argument.Modifier & Parameter.Modifier.RefOutMask) == 0 && (restrictions & Restrictions.CovariantDelegate) == 0)
-                                               return -1;
-
-                                       return 1;
-                               }
-
                        } else {
                                if (argument.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && (restrictions & Restrictions.CovariantDelegate) == 0)
                                        return -1;
@@ -5741,10 +5746,20 @@ namespace Mono.CSharp {
                                        if ((a.Modifier & Parameter.Modifier.RefOutMask) != (p_mod & Parameter.Modifier.RefOutMask))
                                                break;
 
-                                       if (a.Expr.Type == pt || TypeSpecComparer.IsEqual (a.Expr.Type, pt))
+                                       var arg_type = a.Type;
+                                       if (arg_type == pt)
                                                continue;
 
-                                       break;
+                                       if (arg_type == InternalType.VarOutType) {
+                                               //
+                                               // Set underlying variable type based on parameter type
+                                               //
+                                               ((DeclarationExpression)a.Expr).Variable.Type = pt;
+                                               continue;
+                                       }
+
+                                       if (!TypeSpecComparer.IsEqual (arg_type, pt))
+                                               break;
                                }
 
                                NamedArgument na = a as NamedArgument;
@@ -5816,6 +5831,20 @@ namespace Mono.CSharp {
                        }
 
                        if (a_idx != arg_count) {
+                               //
+                               // Convert all var out argument to error type for less confusing error reporting
+                               // when no matching overload is found
+                               //
+                               for (; a_idx < arg_count; a_idx++) {
+                                       var arg = args [a_idx];
+                                       if (arg == null)
+                                               continue;
+
+                                       if (arg.Type == InternalType.VarOutType) {
+                                               ((DeclarationExpression)arg.Expr).Variable.Type = InternalType.ErrorType;
+                                       }
+                               }
+
                                ReportArgumentMismatch (ec, a_pos, member, a, pd, pt);
                                return false;
                        }
index 1d6a082094c58c2e7a8c4781bc3d48a150ef6cc0..c784f62d1c1506055b58f9a284b7c5affb94dfb2 100644 (file)
@@ -2493,6 +2493,96 @@ namespace Mono.CSharp
                        return expr;
                }
        }
+
+       public class DeclarationExpression : Expression, IMemoryLocation
+       {
+               LocalVariableReference lvr;
+
+               public DeclarationExpression (FullNamedExpression variableType, LocalVariable variable)
+               {
+                       VariableType = variableType;
+                       Variable = variable;
+                       this.loc = variable.Location;
+               }
+
+               public LocalVariable Variable { get; set; }
+               public Expression Initializer { get; set; }
+               public FullNamedExpression VariableType { get; set; }
+
+               public void AddressOf (EmitContext ec, AddressOp mode)
+               {
+                       Variable.CreateBuilder (ec);
+
+                       if (Initializer != null) {
+                               lvr.EmitAssign (ec, Initializer, false, false);
+                       }
+
+                       lvr.AddressOf (ec, mode);
+               }
+
+               protected override void CloneTo (CloneContext clonectx, Expression t)
+               {
+                       var target = (DeclarationExpression) t;
+
+                       target.VariableType = (FullNamedExpression) VariableType.Clone (clonectx);
+
+                       if (Initializer != null)
+                               target.Initializer = Initializer.Clone (clonectx);
+               }
+
+               public override Expression CreateExpressionTree (ResolveContext rc)
+               {
+                       rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression");
+                       return null;
+               }
+
+               bool DoResolveCommon (ResolveContext rc)
+               {
+                       var var_expr = VariableType as VarExpr;
+                       if (var_expr != null) {
+                               type = InternalType.VarOutType;
+                       } else {
+                               type = VariableType.ResolveAsType (rc);
+                               if (type == null)
+                                       return false;
+                       }
+
+                       if (Initializer != null) {
+                               Initializer = Initializer.Resolve (rc);
+
+                               if (var_expr != null && Initializer != null && var_expr.InferType (rc, Initializer)) {
+                                       type = var_expr.Type;
+                               }
+                       }
+
+                       Variable.Type = type;
+                       lvr = new LocalVariableReference (Variable, loc);
+
+                       eclass = ExprClass.Variable;
+                       return true;
+               }
+
+               protected override Expression DoResolve (ResolveContext rc)
+               {
+                       if (DoResolveCommon (rc))
+                               lvr.Resolve (rc);
+
+                       return this;
+               }
+
+               public override Expression DoResolveLValue (ResolveContext rc, Expression right_side)
+               {
+                       if (lvr == null && DoResolveCommon (rc))
+                               lvr.ResolveLValue (rc, right_side);
+
+                       return this;
+               }
+
+               public override void Emit (EmitContext ec)
+               {
+                       throw new NotImplementedException ();
+               }
+       }
        
        //
        // C# 2.0 Default value expression
@@ -6472,6 +6562,9 @@ namespace Mono.CSharp
 
                void DoResolveBase (ResolveContext ec)
                {
+                       eclass = ExprClass.Variable;
+                       type = local_info.Type;
+
                        //
                        // If we are referencing a variable from the external block
                        // flag it for capturing
@@ -6490,9 +6583,6 @@ namespace Mono.CSharp
                                        storey.CaptureLocalVariable (ec, local_info);
                                }
                        }
-
-                       eclass = ExprClass.Variable;
-                       type = local_info.Type;
                }
 
                protected override Expression DoResolve (ResolveContext ec)
@@ -6500,6 +6590,14 @@ namespace Mono.CSharp
                        local_info.SetIsUsed ();
 
                        DoResolveBase (ec);
+
+                       if (local_info.Type == InternalType.VarOutType) {
+                               ec.Report.Error (8048, loc, "Cannot use uninitialized variable `{0}'",
+                                       GetSignatureForError ());
+
+                               type = InternalType.ErrorType;
+                       }
+
                        return this;
                }
 
index f9fc75256672721674a1c90acde43dc9fa827289..17dc329cee0bfb4a192a53397a3c60f07e3c31f9 100644 (file)
@@ -3008,7 +3008,7 @@ namespace Mono.CSharp {
                        // Some types cannot be used as type arguments
                        //
                        if ((bound.Type.Kind == MemberKind.Void && !voidAllowed) || bound.Type.IsPointer || bound.Type.IsSpecialRuntimeType ||
-                               bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod)
+                               bound.Type == InternalType.MethodGroup || bound.Type == InternalType.AnonymousMethod || bound.Type == InternalType.VarOutType)
                                return;
 
                        var a = bounds [index];
index a33159d8478bdb6100faa7ba75f376290c667a5c..6b42112f9ed1ae938c96aea045222e19f29405fd 100644 (file)
@@ -1446,6 +1446,7 @@ namespace Mono.CSharp
                public static readonly InternalType FakeInternalType = new InternalType ("<fake$type>");
                public static readonly InternalType Namespace = new InternalType ("<namespace>");
                public static readonly InternalType ErrorType = new InternalType ("<error>");
+               public static readonly InternalType VarOutType = new InternalType ("var out");
 
                readonly string name;
 
diff --git a/mcs/tests/test-decl-expr-01.cs b/mcs/tests/test-decl-expr-01.cs
new file mode 100644 (file)
index 0000000..15e781d
--- /dev/null
@@ -0,0 +1,65 @@
+using System;
+
+class DeclarationExpression
+{
+       public static int Main ()
+       {
+               Out (out int o);
+               if (o != 3)
+                       return 1;
+
+               if (Out (out int o1)) {
+                       if (o1 != 3)
+                               return 2;
+               }
+
+               Out (out int o2 = 2);
+               if (o2 != 3)
+                       return 3;
+
+               Out (out var o3);
+               if (o3 != 3)
+                       return 4;
+
+               Ref (ref int r = 2);
+               if (r != 7)
+                       return 5;
+
+               Ref (ref ((var r2 = 3)));
+               if (r2 != 8)
+                       return 6;
+
+               Out2 (str: "b", v: out var o5);
+               if (o5 != 9)
+                       return 7;
+
+               Out3 (out var o6 = 9m);
+               if (o6.GetType () != typeof (decimal))
+                       return 8;
+
+               Console.WriteLine ("ok");
+               return 0;
+       }
+
+       static bool Out (out int value)
+       {
+               value = 3;
+               return true;
+       }
+
+       static bool Out2 (out int v, string str)
+       {
+               v = 9;
+               return true;
+       }
+
+       static void Out3<T> (out T t)
+       {
+               t = default (T);
+       }
+
+       static void Ref (ref int arg)
+       {
+               arg += 5;
+       }
+}
\ No newline at end of file
index d6569ccdbefa1404e8b71cda71620f00af23aeee..45d8c130549bbad8f4cf02a42e7a7807eae1633f 100644 (file)
       </method>\r
     </type>\r
   </test>\r
+  <test name="test-decl-expr-01.cs">\r
+    <type name="DeclarationExpression">\r
+      <method name="Int32 Main()" attrs="150">\r
+        <size>252</size>\r
+      </method>\r
+      <method name="Boolean Out(Int32 ByRef)" attrs="145">\r
+        <size>13</size>\r
+      </method>\r
+      <method name="Boolean Out2(Int32 ByRef, System.String)" attrs="145">\r
+        <size>14</size>\r
+      </method>\r
+      <method name="Void Out3[T](T ByRef)" attrs="145">\r
+        <size>17</size>\r
+      </method>\r
+      <method name="Void Ref(Int32 ByRef)" attrs="145">\r
+        <size>8</size>\r
+      </method>\r
+      <method name="Void .ctor()" attrs="6278">\r
+        <size>7</size>\r
+      </method>\r
+    </type>\r
+  </test>\r
   <test name="test-dictinit-01.cs">\r
     <type name="Program">\r
       <method name="Int32 Main()" attrs="145">\r