Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

D-assignment should return a tuple instead of void #13115

Merged
merged 12 commits into from
Aug 18, 2016
Merged

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Aug 12, 2016

With this change, var t = (x, y) = (1, 2); is now allowed and t is a tuple.
This works with long tuples and nested deconstruction as well.

In the process, I had to include the fix for the evaluation order. The new order is:

  1. Evaluate all the LHS variables for side-effects
  2. Evaluate all the RHS elements (with conversions for tuple literals)
    • If the RHS is a tuple literal (even if it has a natural type), it gets a type by conversion to a "merged tuple type"
  3. Do all deconstructions
  4. Apply Conversions
  5. Assign converted values to LHS variables
  6. Produce a tuple with the converted values (that construction of ValueTuple is not emitted unless it is consumed, as we require the construction of ValueTuple to be side-effect-free)

As a result of this change, you need to reference the ValueTuple library whenever using deconstructions.

Also, you can see that more locals are created to store the outputs of conversions at step (4). I think we should be able to optimize in some more cases.

Fixes #12635 (return type) and #12400 (evaluation order).

FYI for @MadsTorgersen regarding evaluation order.

// receiver for first Deconstruct step
var boundRHS = rhsPlaceholder ?? BindValue(right, diagnostics, BindValueKind.RValue);

boundRHS = FixTupleLiteral(checkedVariables, boundRHS, node, right, diagnostics);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: we now fix tuple literal whether they have a type or not.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the right-hand-side is already given the final type?


In reply to: 74643437 [](ancestors = 74643437)

@jcouv
Copy link
Member Author

jcouv commented Aug 12, 2016

@dotnet/roslyn-compiler This is now ready for review. Thanks

@@ -1765,6 +1767,21 @@ private void EmitObjectCreationExpression(BoundObjectCreationExpression expressi
}
}

private bool ConstructorNotSideEffecting(BoundObjectCreationExpression expression)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider passing constructor symbol rather than BoundObjectCreationExpression.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@cston
Copy link
Member

cston commented Aug 15, 2016

LGTM

@@ -1743,11 +1743,13 @@ private void EmitObjectCreationExpression(BoundObjectCreationExpression expressi
}
else
{
if (!used &&
expression.Constructor.OriginalDefinition == _module.Compilation.GetSpecialTypeMember(SpecialMember.System_Nullable_T__ctor))
if (!used && ConstructorNotSideEffecting(expression.Constructor))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ConstructorNotSideEffecting(constructor)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

@jcouv
Copy link
Member Author

jcouv commented Aug 16, 2016

@dotnet/roslyn-compiler A second review would be appreciated. Thanks!

@gafter gafter self-assigned this Aug 16, 2016
@gafter
Copy link
Member

gafter commented Aug 16, 2016

Reviewing now. When you commit can you please squash commits whose log message aren't descriptive?

var compilation = _module.Compilation;

return originalDef == compilation.GetSpecialTypeMember(SpecialMember.System_Nullable_T__ctor) ||
originalDef == compilation.GetWellKnownTypeMember(WellKnownMember.System_ValueTuple_T1__ctor) ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd put the check for System_ValueTuple_T1_ as the last one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are many checks here that would typically fail. Is it possible to make a cheap easy-out check, like for the name of the type, before doing all the tuple checks?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@jcouv
Copy link
Member Author

jcouv commented Aug 17, 2016

@gafter (mispelled earlier) Let me know if you have any other feedback.

@jcouv
Copy link
Member Author

jcouv commented Aug 18, 2016

@gafter @VSadov I'm waiting on one of you to sign-off. Thanks

@agocke
Copy link
Member

agocke commented Aug 18, 2016

LGTM

@jcouv
Copy link
Member Author

jcouv commented Aug 18, 2016

🎉 Thanks for the review!
I'll go ahead with merging.

@jcouv jcouv merged commit f75c7ef into dotnet:master Aug 18, 2016
@jcouv jcouv deleted the return-type branch August 18, 2016 21:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Deconstruction-assignment should return a tuple type
6 participants