From: Marek Safar Date: Wed, 7 Jun 2017 12:13:52 +0000 (+0200) Subject: [mcs] C#7 out variable declaration X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=mono.git;a=commitdiff_plain;h=44a2d35676fac7c3672de43b72bbf6e05d06b95c [mcs] C#7 out variable declaration --- diff --git a/mcs/errors/cs0128-3.cs b/mcs/errors/cs0128-3.cs new file mode 100644 index 00000000000..380616cc238 --- /dev/null +++ b/mcs/errors/cs0128-3.cs @@ -0,0 +1,16 @@ +// CS0128: A local variable named `x' is already defined in this scope +// Line: 9 + +class X +{ + public static void Main () + { + Foo (out int x); + Foo (out int x); + } + + static void Foo (out int arg) + { + arg = 2; + } +} \ No newline at end of file diff --git a/mcs/errors/cs0815-7.cs b/mcs/errors/cs0815-7.cs deleted file mode 100644 index af3d10f8c6c..00000000000 --- a/mcs/errors/cs0815-7.cs +++ /dev/null @@ -1,16 +0,0 @@ -// CS0815: An implicitly typed local variable declaration cannot be initialized with `void' -// Line: 8 -// Compiler options: -langversion:experimental - -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/cs1503-17.cs b/mcs/errors/cs1503-17.cs deleted file mode 100644 index 07da09dfe29..00000000000 --- a/mcs/errors/cs1503-17.cs +++ /dev/null @@ -1,15 +0,0 @@ -// CS1501: Argument `#1' cannot convert `ref string' expression to type `ref int' -// Line: 8 -// Compiler options: -langversion:experimental - -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/cs1644-47.cs b/mcs/errors/cs1644-47.cs index b756cd7b60c..498b627ead5 100644 --- a/mcs/errors/cs1644-47.cs +++ b/mcs/errors/cs1644-47.cs @@ -1,5 +1,5 @@ -// CS1644: Feature `declaration expression' cannot be used because it is not part of the C# 5.0 language specification -// Line: 12 +// CS1644: Feature `out variable declaration' cannot be used because it is not part of the C# 5.0 language specification +// Line: 9 // Compiler options: -langversion:5 class C diff --git a/mcs/errors/cs8046.cs b/mcs/errors/cs8046.cs deleted file mode 100644 index 3335e29c4b1..00000000000 --- a/mcs/errors/cs8046.cs +++ /dev/null @@ -1,20 +0,0 @@ -// CS8046: An expression tree cannot contain a declaration expression -// Line: 11 -// Compiler options: -langversion:experimental - -using System; -using System.Linq.Expressions; - -class C -{ - static void Main() - { - Expression> 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 deleted file mode 100644 index cd91a4fb3a7..00000000000 --- a/mcs/errors/cs8047.cs +++ /dev/null @@ -1,20 +0,0 @@ -// CS8047: Declaration expression cannot be used in this context -// Line: 8 -// Compiler options: -langversion:experimental - -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 diff --git a/mcs/errors/cs8196-2.cs b/mcs/errors/cs8196-2.cs new file mode 100644 index 00000000000..cf58de30ddc --- /dev/null +++ b/mcs/errors/cs8196-2.cs @@ -0,0 +1,16 @@ +// CS8196: Reference to an implicitly typed out variable `x1' is not permitted in the same argument list +// Line: 8 + +public class C +{ + public static void Main () + { + Test (out var x1, out x1); + } + + static void Test (out int x, out int x2) + { + x = 1; + x2 = 2; + } +} \ No newline at end of file diff --git a/mcs/errors/cs8196.cs b/mcs/errors/cs8196.cs new file mode 100644 index 00000000000..cf58de30ddc --- /dev/null +++ b/mcs/errors/cs8196.cs @@ -0,0 +1,16 @@ +// CS8196: Reference to an implicitly typed out variable `x1' is not permitted in the same argument list +// Line: 8 + +public class C +{ + public static void Main () + { + Test (out var x1, out x1); + } + + static void Test (out int x, out int x2) + { + x = 1; + x2 = 2; + } +} \ No newline at end of file diff --git a/mcs/errors/cs8197.cs b/mcs/errors/cs8197.cs new file mode 100644 index 00000000000..f8538a1fe5b --- /dev/null +++ b/mcs/errors/cs8197.cs @@ -0,0 +1,19 @@ +// CS8197: Cannot infer the type of implicitly-typed out variable `y' +// Line: 9 + +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 diff --git a/mcs/errors/cs8198.cs b/mcs/errors/cs8198.cs new file mode 100644 index 00000000000..267c57ea0a9 --- /dev/null +++ b/mcs/errors/cs8198.cs @@ -0,0 +1,19 @@ +// CS8198: An expression tree cannot contain out variable declaration +// Line: 11 + +using System; +using System.Linq.Expressions; + +class C +{ + static void Main() + { + Expression> 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/cs8200-2.cs b/mcs/errors/cs8200-2.cs new file mode 100644 index 00000000000..d5ad76374e7 --- /dev/null +++ b/mcs/errors/cs8200-2.cs @@ -0,0 +1,13 @@ +// CS8200: Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers +// Line: 6 + +public class C +{ + bool res = Foo (out int arg); + + static bool Foo (out int arg) + { + arg = 2; + return false; + } +} \ No newline at end of file diff --git a/mcs/errors/cs8200-3.cs b/mcs/errors/cs8200-3.cs new file mode 100644 index 00000000000..52c87bf3e9c --- /dev/null +++ b/mcs/errors/cs8200-3.cs @@ -0,0 +1,13 @@ +// CS8200: Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers +// Line: 11 + +public class C +{ + bool Prop { get; } = Foo (out int arg); + + static bool Foo (out int arg) + { + arg = 2; + return false; + } +} \ No newline at end of file diff --git a/mcs/errors/cs8200.cs b/mcs/errors/cs8200.cs new file mode 100644 index 00000000000..e7565e4d4e7 --- /dev/null +++ b/mcs/errors/cs8200.cs @@ -0,0 +1,20 @@ +// CS8200: Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers +// Line: 11 + +public class C +{ + public C (bool value) + { + } + + public C () + : this (Foo (out int arg)) + { + } + + static bool Foo (out int arg) + { + arg = 2; + return false; + } +} \ No newline at end of file diff --git a/mcs/errors/cs8201.cs b/mcs/errors/cs8201.cs new file mode 100644 index 00000000000..7a1141774fa --- /dev/null +++ b/mcs/errors/cs8201.cs @@ -0,0 +1,15 @@ +// CS8201: Out variable and pattern variable declarations are not allowed within a query clause +// Line: 11 + +using System.Linq; + +class Program +{ + public static void Main () + { + var a = "abcdef"; + var res = from x in a from y in M (a, out var z) select x; + } + + public static T M(T x, out T z) => z = x; +} \ No newline at end of file diff --git a/mcs/mcs/argument.cs b/mcs/mcs/argument.cs index a5edeb53cf6..702ace629c3 100644 --- a/mcs/mcs/argument.cs +++ b/mcs/mcs/argument.cs @@ -651,13 +651,35 @@ namespace Mono.CSharp // // Returns dynamic when at least one argument is of dynamic type // - public void Resolve (ResolveContext ec, out bool dynamic) + public void Resolve (ResolveContext rc, out bool dynamic) { dynamic = false; + + List var_locals = null; foreach (Argument a in args) { - a.Resolve (ec); - if (a.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && !a.IsByRef) + a.Resolve (rc); + + if (a.Type.BuiltinType == BuiltinTypeSpec.Type.Dynamic && !a.IsByRef) { dynamic = true; + continue; + } + + if (a.Type == InternalType.VarOutType) { + var de = a.Expr as DeclarationExpression; + if (de != null) { + if (var_locals == null) + var_locals = new List (); + + var_locals.Add (de.Variable); + continue; + } + + var lvr = a.Expr as LocalVariableReference; + if (lvr != null && var_locals != null && var_locals.Contains (lvr.local_info)) { + rc.Report.Error (8196, lvr.Location, "Reference to an implicitly typed out variable `{0}' is not permitted in the same argument list", lvr.Name); + lvr.Type = InternalType.ErrorType; + } + } } } diff --git a/mcs/mcs/context.cs b/mcs/mcs/context.cs index 24bccb69187..b36fc7aeaa1 100644 --- a/mcs/mcs/context.cs +++ b/mcs/mcs/context.cs @@ -113,6 +113,9 @@ namespace Mono.CSharp if (rc.HasSet (ResolveContext.Options.BaseInitializer)) flags |= ResolveContext.Options.BaseInitializer; + + if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) + flags |= ResolveContext.Options.QueryClauseScope; } public ExceptionStatement CurrentTryBlock { get; set; } @@ -196,6 +199,8 @@ namespace Mono.CSharp NameOfScope = 1 << 17, + QueryClauseScope = 1 << 18, + /// /// Indicates the current context is in probing mode, no errors are reported. /// diff --git a/mcs/mcs/cs-parser.jay b/mcs/mcs/cs-parser.jay index 8d36abae8dc..f505da17685 100644 --- a/mcs/mcs/cs-parser.jay +++ b/mcs/mcs/cs-parser.jay @@ -918,11 +918,25 @@ named_argument $$ = new NamedArgument (lt.Value, lt.Location, (Expression) $4, arg_mod); lbag.AddLocation ($$, GetLocation($2)); } + | identifier_inside_body COLON OUT named_argument_expr_or_out_variable_declaration + { + if (lang_version <= LanguageVersion.V_3) + FeatureIsNotAvailable (GetLocation ($1), "named argument"); + + var lt = (LocatedToken) $1; + $$ = new NamedArgument (lt.Value, lt.Location, (Expression) $4, Argument.AType.Out); + lbag.AddLocation ($$, GetLocation($2)); + } + ; named_argument_expr : expression_or_error -// | declaration_expression + ; + +named_argument_expr_or_out_variable_declaration + : expression_or_error + | out_variable_declaration ; opt_named_modifier @@ -931,10 +945,6 @@ opt_named_modifier { $$ = Argument.AType.Ref; } - | OUT - { - $$ = Argument.AType.Out; - } ; opt_class_member_declarations @@ -3722,16 +3732,12 @@ 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 + | OUT out_variable_declaration { $$ = new Argument ((Expression) $2, Argument.AType.Out); } @@ -3747,46 +3753,17 @@ 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 +out_variable_declaration + : variable_type identifier_inside_body { - if (lang_version != LanguageVersion.Experimental) - FeatureIsNotAvailable (GetLocation ($1), "declaration expression"); + if (lang_version < LanguageVersion.V_7) + FeatureIsNotAvailable (GetLocation ($1), "out variable declaration"); 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.Experimental) - 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 diff --git a/mcs/mcs/dynamic.cs b/mcs/mcs/dynamic.cs index 09d78302854..fd4662b2fed 100644 --- a/mcs/mcs/dynamic.cs +++ b/mcs/mcs/dynamic.cs @@ -282,7 +282,7 @@ namespace Mono.CSharp 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"); + rc.Report.Error (8197, arg.Expr.Location, "Cannot infer the type of implicitly-typed out variable `{0}'", ((DeclarationExpression) arg.Expr).Variable.Name); } } diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs index d84214302c3..bb6255ce487 100644 --- a/mcs/mcs/expression.cs +++ b/mcs/mcs/expression.cs @@ -2562,12 +2562,18 @@ namespace Mono.CSharp public override Expression CreateExpressionTree (ResolveContext rc) { - rc.Report.Error (8046, loc, "An expression tree cannot contain a declaration expression"); + rc.Report.Error (8198, loc, "An expression tree cannot contain out variable declaration"); return null; } bool DoResolveCommon (ResolveContext rc) { + if (rc.HasAny (ResolveContext.Options.BaseInitializer | ResolveContext.Options.FieldInitializerScope)) { + rc.Report.Error (8200, loc, "Out variable and pattern variable declarations are not allowed within constructor initializers, field initializers, or property initializers"); + } else if (rc.HasSet (ResolveContext.Options.QueryClauseScope)) { + rc.Report.Error (8201, loc, "Out variable and pattern variable declarations are not allowed within a query clause"); + } + var var_expr = VariableType as VarExpr; if (var_expr != null) { type = InternalType.VarOutType; diff --git a/mcs/mcs/linq.cs b/mcs/mcs/linq.cs index 40c500d365e..68f4b6ff30b 100644 --- a/mcs/mcs/linq.cs +++ b/mcs/mcs/linq.cs @@ -79,10 +79,11 @@ namespace Mono.CSharp.Linq { } - protected override MethodGroupExpr DoResolveOverload (ResolveContext ec) + protected override MethodGroupExpr DoResolveOverload (ResolveContext rc) { - MethodGroupExpr rmg = mg.OverloadResolve (ec, ref arguments, this, OverloadResolver.Restrictions.None); - return rmg; + using (rc.Set (ResolveContext.Options.QueryClauseScope)) { + return mg.OverloadResolve (rc, ref arguments, this, OverloadResolver.Restrictions.None); + } } protected override Expression DoResolveDynamic (ResolveContext ec, Expression memberExpr) diff --git a/mcs/tests/test-decl-expr-01.cs b/mcs/tests/test-decl-expr-01.cs index 9078ff7caaa..880d3344585 100644 --- a/mcs/tests/test-decl-expr-01.cs +++ b/mcs/tests/test-decl-expr-01.cs @@ -1,4 +1,3 @@ -// Compiler options: -langversion:experimental using System; class DeclarationExpression @@ -14,29 +13,13 @@ class DeclarationExpression 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; + Out2 (str: "b", v: out var o5); + if (o5 != 9) + return 7; Console.WriteLine ("ok"); return 0; @@ -53,14 +36,4 @@ class DeclarationExpression v = 9; return true; } - - static void Out3 (out T t) - { - t = default (T); - } - - static void Ref (ref int arg) - { - arg += 5; - } } \ No newline at end of file diff --git a/mcs/tests/test-decl-expr-02.cs b/mcs/tests/test-decl-expr-02.cs index 1c2ce760728..1d1c355e1a7 100644 --- a/mcs/tests/test-decl-expr-02.cs +++ b/mcs/tests/test-decl-expr-02.cs @@ -1,27 +1,11 @@ -// Compiler options: -langversion:experimental +using System; -using static System.Console; - -public class DeclarationExpressions +public class C { - public static void Main() - { - // TODO: - //Test (int value = 5); - //WriteLine (value); - } - - void M2 () + public static void Main () { -// for (int i = 0; int v = 2; ++i) { - -// } - } - static int Test (int x) - { - WriteLine (x); - return x; - } + bool Test1 => int.TryParse ("1", out int x); + int Test2 => int.TryParse ("2", out int x) ? x : 0; } \ No newline at end of file diff --git a/mcs/tests/test-decl-expr-03.cs b/mcs/tests/test-decl-expr-03.cs new file mode 100644 index 00000000000..bc0f01c5f60 --- /dev/null +++ b/mcs/tests/test-decl-expr-03.cs @@ -0,0 +1,15 @@ +using System; +using System.Linq; + +public class C +{ + public static void Main () + { + var a = "abcdef"; + + var t1 = from x in Foo (a, out var q1) select x; + var t2 = from x in a join y in Foo (a, out var q2) on x equals y select x; + } + + public static T Foo (T x, out T z) => z = x; +} \ No newline at end of file diff --git a/mcs/tests/test-decl-expr-04.cs b/mcs/tests/test-decl-expr-04.cs new file mode 100644 index 00000000000..f30c4feefcb --- /dev/null +++ b/mcs/tests/test-decl-expr-04.cs @@ -0,0 +1,18 @@ +public class C +{ + public static void Main () + { + Test2 (Test (out var x1), x1); + } + + static int Test (out int x) + { + x = 1; + return 2; + } + + static int Test2 (int x, int y) + { + return 2; + } +} \ No newline at end of file diff --git a/mcs/tests/ver-il-net_4_x.xml b/mcs/tests/ver-il-net_4_x.xml index a3ef14c1009..e2b6cd90558 100644 --- a/mcs/tests/ver-il-net_4_x.xml +++ b/mcs/tests/ver-il-net_4_x.xml @@ -68400,7 +68400,7 @@ - 223 + 121 13 @@ -68408,28 +68408,63 @@ 14 - - 17 - - - 8 - 7 - + 2 - - 2 + + 20 - + + 32 + + + 7 + + + + + + + 153 + + + 18 + + + 10 + + + 10 + + + 10 + + + 10 + + + 7 + + + + + + 16 + + 13 + + + 10 + 7