Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/mono.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/mcs
diff options
context:
space:
mode:
authorMarek Safar <marek.safar@gmail.com>2018-01-22 16:59:55 +0300
committerMarek Safar <marek.safar@gmail.com>2018-01-22 21:11:27 +0300
commit51e1e5af325baa566bd6b65dd045e461eb1cef7c (patch)
treeb1135eb60b5e72698c51d0f60cdbb06599f533f3 /mcs
parentb519d42c15e08158ad48824bab4922797a766704 (diff)
[mcs] Implements C# 7 tuples implicit deconstruction
Diffstat (limited to 'mcs')
-rw-r--r--mcs/errors/cs8184.cs10
-rw-r--r--mcs/mcs/cs-parser.jay53
-rw-r--r--mcs/mcs/expression.cs9
-rw-r--r--mcs/mcs/tuples.cs69
-rw-r--r--mcs/tests/test-tuple-09.cs19
-rw-r--r--mcs/tests/ver-il-net_4_x.xml26
6 files changed, 142 insertions, 44 deletions
diff --git a/mcs/errors/cs8184.cs b/mcs/errors/cs8184.cs
new file mode 100644
index 00000000000..19a4685d7bd
--- /dev/null
+++ b/mcs/errors/cs8184.cs
@@ -0,0 +1,10 @@
+// CS8184: A deconstruction cannot mix declarations and expressions on the left-hand-side
+// Line: 8
+
+class X
+{
+ public static void Main ()
+ {
+ (int a, b) = (1, 2);
+ }
+} \ No newline at end of file
diff --git a/mcs/mcs/cs-parser.jay b/mcs/mcs/cs-parser.jay
index e2118a23f0f..4d6fcb44c0d 100644
--- a/mcs/mcs/cs-parser.jay
+++ b/mcs/mcs/cs-parser.jay
@@ -5109,17 +5109,25 @@ assignment_expression
$$ = new CompoundAssign (Binary.Operator.ExclusiveOr, (Expression) $1, (Expression) $3);
lbag.AddLocation ($$, GetLocation ($2));
}
- | OPEN_PARENS_DECONSTRUCT deconstruct_exprs CLOSE_PARENS ASSIGN expression
+ | OPEN_PARENS_DECONSTRUCT deconstruct_assignment CLOSE_PARENS ASSIGN expression
{
if (lang_version < LanguageVersion.V_7)
FeatureIsNotAvailable (GetLocation ($1), "tuples");
- var exprs = (List<Expression>) $2;
+ var exprs = (List<Expression>) $2;
+ $$ = new TupleDeconstruct (exprs, (Expression) $5, GetLocation ($4));
+ }
+ | OPEN_PARENS_DECONSTRUCT deconstruct_declaration CLOSE_PARENS ASSIGN expression
+ {
+ if (lang_version < LanguageVersion.V_7)
+ FeatureIsNotAvailable (GetLocation ($1), "tuples");
+
+ var exprs = (List<BlockVariable>) $2;
$$ = new TupleDeconstruct (exprs, (Expression) $5, GetLocation ($4));
}
;
-deconstruct_exprs
+deconstruct_assignment
: expression COMMA expression
{
$$ = new List<Expression> () {
@@ -5127,7 +5135,7 @@ deconstruct_exprs
(Expression) $3
};
}
- | deconstruct_exprs COMMA expression
+ | deconstruct_assignment COMMA expression
{
var src = (List<Expression>) $1;
src.Add ((Expression) $3);
@@ -5135,6 +5143,43 @@ deconstruct_exprs
}
;
+deconstruct_declaration
+ : variable_type identifier_inside_body
+ {
+ var lt = (LocatedToken) $2;
+ var li = new LocalVariable (current_block, lt.Value, lt.Location);
+ current_block.AddLocalName (li);
+ $$ = new List<BlockVariable> (2) {
+ new BlockVariable ((FullNamedExpression) $1, li)
+ };
+ }
+ | deconstruct_declaration COMMA variable_type identifier_inside_body
+ {
+ var lt = (LocatedToken) $4;
+ var li = new LocalVariable (current_block, lt.Value, lt.Location);
+ current_block.AddLocalName (li);
+
+ var src = (List<BlockVariable>) $1;
+ src.Add (new BlockVariable ((FullNamedExpression) $3, li));
+ $$ = src;
+ }
+ | deconstruct_declaration COMMA identifier_inside_body
+ {
+ var lt = (LocatedToken) $3;
+ var li = new LocalVariable (current_block, lt.Value, lt.Location);
+
+ if (lt.Value != "_") {
+ report.Error (8184, lt.Location, "A deconstruction cannot mix declarations and expressions on the left-hand-side");
+ } else {
+ li.Type = InternalType.Discard;
+ }
+
+ var src = (List<BlockVariable>) $1;
+ src.Add (new BlockVariable (new TypeExpression (li.Type, lt.Location), li));
+ $$ = src;
+ }
+ ;
+
lambda_parameter_list
: lambda_parameter
{
diff --git a/mcs/mcs/expression.cs b/mcs/mcs/expression.cs
index ae01588cc61..518ccc8ef43 100644
--- a/mcs/mcs/expression.cs
+++ b/mcs/mcs/expression.cs
@@ -7210,8 +7210,7 @@ namespace Mono.CSharp
{
var sn = expr as SimpleName;
if (sn != null && sn.Name == "var" && sn.Arity == 0 && arguments?.Count > 1) {
- var targets = new List<Expression> (arguments.Count);
- var variables = new List<LocalVariable> (arguments.Count);
+ var variables = new List<BlockVariable> (arguments.Count);
foreach (var arg in arguments) {
var arg_sn = arg.Expr as SimpleName;
if (arg_sn == null || arg_sn.Arity != 0) {
@@ -7221,12 +7220,10 @@ namespace Mono.CSharp
var lv = new LocalVariable (rc.CurrentBlock, arg_sn.Name, arg.Expr.Location);
rc.CurrentBlock.AddLocalName (lv);
- variables.Add (lv);
-
- targets.Add (new LocalVariableReference (lv, arg_sn.Location));
+ variables.Add (new BlockVariable (new VarExpr (lv.Location), lv));
}
- var res = new TupleDeconstruct (targets, variables, right_side, loc);
+ var res = new TupleDeconstruct (variables, right_side, loc);
return res.Resolve (rc);
}
diff --git a/mcs/mcs/tuples.cs b/mcs/mcs/tuples.cs
index 6497a894876..15a2ca5b0d3 100644
--- a/mcs/mcs/tuples.cs
+++ b/mcs/mcs/tuples.cs
@@ -432,7 +432,7 @@ namespace Mono.CSharp
{
Expression source;
List<Expression> targetExprs;
- List<LocalVariable> variablesToInfer;
+ List<BlockVariable> variables;
Expression instance;
public TupleDeconstruct (List<Expression> targetExprs, Expression source, Location loc)
@@ -442,10 +442,11 @@ namespace Mono.CSharp
this.loc = loc;
}
- public TupleDeconstruct (List<Expression> targetExprs, List<LocalVariable> variables, Expression source, Location loc)
- : this (targetExprs, source, loc)
+ public TupleDeconstruct (List<BlockVariable> variables, Expression source, Location loc)
{
- this.variablesToInfer = variables;
+ this.source = source;
+ this.variables = variables;
+ this.loc = loc;
}
public override Expression CreateExpressionTree (ResolveContext ec)
@@ -469,9 +470,18 @@ namespace Mono.CSharp
var src_type = src.Type;
if (src_type.IsTupleType) {
- if (src_type.Arity != targetExprs.Count) {
+ int target_count;
+
+ if (targetExprs == null) {
+ target_count = variables.Count;
+ targetExprs = new List<Expression> (target_count);
+ } else {
+ target_count = targetExprs.Count;
+ }
+
+ if (src_type.Arity != target_count) {
rc.Report.Error (8132, loc, "Cannot deconstruct a tuple of `{0}' elements into `{1}' variables",
- src_type.Arity.ToString (), targetExprs.Count.ToString ());
+ src_type.Arity.ToString (CultureInfo.InvariantCulture), target_count.ToString (CultureInfo.InvariantCulture));
return null;
}
@@ -482,21 +492,35 @@ namespace Mono.CSharp
instance = expr_variable.CreateReferenceExpression (rc, loc);
}
- for (int i = 0; i < targetExprs.Count; ++i) {
+ for (int i = 0; i < target_count; ++i) {
var tle = src_type.TypeArguments [i];
- var lv = variablesToInfer? [i];
- if (lv != null) {
- if (InternalType.HasNoType (tle)) {
- rc.Report.Error (8130, Location, "Cannot infer the type of implicitly-typed deconstruction variable `{0}'", lv.Name);
- lv.Type = InternalType.ErrorType;
+ if (variables != null) {
+ var variable = variables [i].Variable;
+
+ if (variable.Type == InternalType.Discard) {
+ variables [i] = null;
+ targetExprs.Add (EmptyExpressionStatement.Instance);
continue;
}
- lv.Type = tle;
- lv.PrepareAssignmentAnalysis ((BlockContext) rc);
- }
+ var variable_type = variables [i].TypeExpression;
+
+ targetExprs.Add (new LocalVariableReference (variable, variable.Location));
+ if (variable_type is VarExpr) {
+ if (InternalType.HasNoType (tle)) {
+ rc.Report.Error (8130, Location, "Cannot infer the type of implicitly-typed deconstruction variable `{0}'", variable.Name);
+ tle = InternalType.ErrorType;
+ }
+
+ variable.Type = tle;
+ } else {
+ variable.Type = variable_type.ResolveAsType (rc);
+ }
+
+ variable.PrepareAssignmentAnalysis ((BlockContext)rc);
+ }
var element_src = tupleLiteral == null ? new MemberAccess (instance, NamedTupleSpec.GetElementPropertyName (i)) : tupleLiteral.Elements [i].Expr;
targetExprs [i] = new SimpleAssign (targetExprs [i], element_src).Resolve (rc);
@@ -542,6 +566,12 @@ namespace Mono.CSharp
public override void EmitStatement (EmitContext ec)
{
+ if (variables != null) {
+ foreach (var lv in variables) {
+ lv?.Variable.CreateBuilder (ec);
+ }
+ }
+
if (instance != null)
((ExpressionStatement) source).EmitStatement (ec);
@@ -559,9 +589,6 @@ namespace Mono.CSharp
if (leave_copy)
throw new NotImplementedException ();
- foreach (var lv in variablesToInfer)
- lv.CreateBuilder (ec);
-
EmitStatement (ec);
}
@@ -574,11 +601,11 @@ namespace Mono.CSharp
public void SetGeneratedFieldAssigned (FlowAnalysisContext fc)
{
- if (variablesToInfer == null)
+ if (variables == null)
return;
- foreach (var lv in variablesToInfer)
- fc.SetVariableAssigned (lv.VariableInfo);
+ foreach (var lv in variables)
+ fc.SetVariableAssigned (lv.Variable.VariableInfo);
}
}
} \ No newline at end of file
diff --git a/mcs/tests/test-tuple-09.cs b/mcs/tests/test-tuple-09.cs
new file mode 100644
index 00000000000..3f15cae6cf1
--- /dev/null
+++ b/mcs/tests/test-tuple-09.cs
@@ -0,0 +1,19 @@
+using System;
+
+class TupleDeconstructionDeclaration
+{
+ public static int Main ()
+ {
+ (string s, long l) = GetValues ();
+ (var vs, var vl) = GetValues ();
+ (object o, var vl2) = GetValues ();
+ (string ds, _) = GetValues ();
+
+ return 0;
+ }
+
+ static (string, long) GetValues ()
+ {
+ return ("a", 3);
+ }
+} \ 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 aa3578da455..dbb2e5869e9 100644
--- a/mcs/tests/ver-il-net_4_x.xml
+++ b/mcs/tests/ver-il-net_4_x.xml
@@ -68710,19 +68710,6 @@
</method>
</type>
</test>
- <test name="test-default-03.cs">
- <type name="X">
- <method name="Int32 Main()" attrs="150">
- <size>25</size>
- </method>
- <method name="Byte[] Test(S`1[System.Byte])" attrs="145">
- <size>10</size>
- </method>
- <method name="Void .ctor()" attrs="6278">
- <size>7</size>
- </method>
- </type>
- </test>
<test name="test-dictinit-01.cs">
<type name="Program">
<method name="Int32 Main()" attrs="145">
@@ -73776,6 +73763,19 @@
</method>
</type>
</test>
+ <test name="test-tuple-09.cs">
+ <type name="TupleDeconstructionDeclaration">
+ <method name="Int32 Main()" attrs="150">
+ <size>99</size>
+ </method>
+ <method name="System.ValueTuple`2[System.String,System.Int64] GetValues()" attrs="145">
+ <size>21</size>
+ </method>
+ <method name="Void .ctor()" attrs="6278">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="test-var-01.cs">
<type name="Test">
<method name="Int32 Main()" attrs="150">