Skip to content

Commit

Permalink
Align mcs's tuple deconstruction behavior with csc
Browse files Browse the repository at this point in the history
Before the code
(a, b) = (b, a);
was the equivalent of
a = b;
b = a;

now, it evaluates it to so something like
tmp1 = a;
tmp2 = b;
a = tmp2;
b = tmp1;

Signed-off-by: Bijan Tabatabai <bijan311@yahoo.com>
  • Loading branch information
BijanT authored and marek-safar committed Jun 5, 2019
1 parent 644bfc9 commit a3de030
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 5 deletions.
63 changes: 58 additions & 5 deletions mcs/mcs/tuples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,7 @@ class TupleDeconstruct : ExpressionStatement, IAssignMethod
{
Expression source;
List<Expression> targetExprs;
List<Expression> tempExprs;
List<BlockVariable> variables;
Expression instance;

Expand All @@ -455,13 +456,17 @@ public TupleDeconstruct (List<Expression> targetExprs, Expression source, Locati
this.source = source;
this.targetExprs = targetExprs;
this.loc = loc;

tempExprs = new List<Expression> ();
}

public TupleDeconstruct (List<BlockVariable> variables, Expression source, Location loc)
{
this.source = source;
this.variables = variables;
this.loc = loc;

tempExprs = new List<Expression> ();
}

public override Expression CreateExpressionTree (ResolveContext ec)
Expand Down Expand Up @@ -507,6 +512,15 @@ protected override Expression DoResolve (ResolveContext rc)
instance = expr_variable.CreateReferenceExpression (rc, loc);
}

var element_srcs = new List<Expression> ();
var src_names = new List<string> ();
for (int i = 0; i < target_count; ++i) {
var element_src = tupleLiteral == null ? new MemberAccess (instance, NamedTupleSpec.GetElementPropertyName (i)) : tupleLiteral.Elements [i].Expr;
element_srcs.Add (element_src);
if (element_src is VariableReference)
src_names.Add ((element_src as VariableReference)?.Name);
}

for (int i = 0; i < target_count; ++i) {
var tle = src_type.TypeArguments [i];

Expand Down Expand Up @@ -537,8 +551,17 @@ protected override Expression DoResolve (ResolveContext 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);
var element_target = (targetExprs [i] as SimpleName)?.LookupNameExpression (rc, MemberLookupRestrictions.None);

if (element_target != null && src_names.Contains ((element_target as VariableReference)?.Name)) {
var tempType = element_target.Resolve (rc).Type;

var temp = new LocalTemporary (tempType);
tempExprs.Add (new SimpleAssign (temp, element_srcs [i]).Resolve (rc));
targetExprs [i] = new SimpleAssign (targetExprs [i], temp).Resolve (rc);
} else {
targetExprs [i] = new SimpleAssign (targetExprs [i], element_srcs [i]).Resolve (rc);
}
}

eclass = ExprClass.Value;
Expand Down Expand Up @@ -572,9 +595,24 @@ public override void Emit (EmitContext ec)
if (instance != null)
((ExpressionStatement)source).EmitStatement (ec);

foreach (ExpressionStatement expr in targetExprs)
foreach (ExpressionStatement expr in tempExprs) {
var temp = (expr as Assign)?.Target as LocalTemporary;
if (temp == null)
continue;

temp.AddressOf (ec, AddressOp.LoadStore);
ec.Emit (OpCodes.Initobj, temp.Type);
expr.Emit (ec);
}

foreach (ExpressionStatement expr in targetExprs) {
expr.Emit (ec);

var temp = (expr as Assign)?.Source as LocalTemporary;
if (temp != null)
temp.Release (ec);
}

var ctor = MemberCache.FindMember (type, MemberFilter.Constructor (null), BindingRestriction.DeclaredOnly | BindingRestriction.InstanceOnly) as MethodSpec;
ec.Emit (OpCodes.Newobj, ctor);
}
Expand All @@ -589,9 +627,24 @@ public override void EmitStatement (EmitContext ec)

if (instance != null)
((ExpressionStatement) source).EmitStatement (ec);

foreach (ExpressionStatement expr in targetExprs)

foreach (ExpressionStatement expr in tempExprs) {
var temp = (expr as Assign)?.Target as LocalTemporary;
if (temp == null)
continue;

temp.AddressOf (ec, AddressOp.LoadStore);
ec.Emit (OpCodes.Initobj, temp.Type);
expr.EmitStatement (ec);
}

foreach (ExpressionStatement expr in targetExprs) {
expr.EmitStatement (ec);

var temp = (expr as Assign)?.Source as LocalTemporary;
if (temp != null)
temp.Release (ec);
}
}

public void Emit (EmitContext ec, bool leave_copy)
Expand Down
20 changes: 20 additions & 0 deletions mcs/tests/test-tuple-11.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
using System;

class Program
{
public static int Main ()
{
int x = 1;
int y = 2;

(x, y) = (y, x);

if (x != 2)
return 1;

if (y != 1)
return 2;

return 0;
}
}
10 changes: 10 additions & 0 deletions mcs/tests/ver-il-net_4_x.xml
Original file line number Diff line number Diff line change
Expand Up @@ -74502,6 +74502,16 @@
</method>
</type>
</test>
<test name="test-tuple-11.cs">
<type name="Program">
<method name="Int32 Main()" attrs="150">
<size>70</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">
Expand Down

0 comments on commit a3de030

Please sign in to comment.