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

Refactoring on inferred tuple names and anonymous type members (VB) #18930

Merged
merged 5 commits into from
Apr 27, 2017

Conversation

jcouv
Copy link
Member

@jcouv jcouv commented Apr 23, 2017

Same change as #18726, but for VB.
There are some minor differences: (1) the syntax for anonymous types is a bit different in VB, (2) the identifier comparisons are case-insensitive, and (3) there is no deconstruction in VB.

Note that there is an existing issue with the semantic model on the name of tuple elements in VB (#16697). For instance, in (i:=i, 2), both i's are treated as references to the local called i.
So some InlineTemporary tests are skipped for now.

@@ -1827,7 +1827,7 @@ Class C
Const {|Rename:V|} As Integer = 5
Console.WriteLine(V)
#End ExternalSource
End Sub
End Sub
Copy link
Member Author

@jcouv jcouv Apr 23, 2017

Choose a reason for hiding this comment

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

Note: This change occurred when I moved complify earlier in the IntroduceVariable logic. I didn't investigate in details.

@@ -392,5 +393,50 @@ where NodeMatchesExpression(originalSemanticModel, currentSemanticModel, syntaxF
.Where(p => p.ContainingSymbol.IsAnonymousFunction());
return anonymousMethodParameters;
}

protected static async Task<(SemanticDocument newSemanticDocument, ISet<TExpressionSyntax> newMatches)> ComplexifyParentingStatements(
Copy link
Member Author

@jcouv jcouv Apr 23, 2017

Choose a reason for hiding this comment

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

Note: I pulled this method up from the C# derived class. The only change is that ExpressionSyntax was made generic, using TExpressionSyntax. #Resolved

Copy link
Member

@CyrusNajmabadi CyrusNajmabadi Apr 26, 2017

Choose a reason for hiding this comment

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

nice! #Resolved


Dim oldOutermostBlock = container
If oldOutermostBlock.IsSingleLineExecutableBlock() Then
oldOutermostBlock = oldOutermostBlock.Parent
End If

Dim matches = FindMatches(document, expression, document, oldOutermostBlock, allOccurrences, cancellationToken)

Dim complexified = Await ComplexifyParentingStatements(document, matches, cancellationToken).ConfigureAwait(False)
Copy link
Member Author

@jcouv jcouv Apr 23, 2017

Choose a reason for hiding this comment

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

Note: Before the change, the complexification was happening after the local was introduced. But that is too late, as we need the original syntax to make names explicit in tuples and anonymous types.
The new flow mirrors the C# implementation of IntroduceVariable. #Resolved

Copy link
Member

@DustinCampbell DustinCampbell Apr 26, 2017

Choose a reason for hiding this comment

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

I don't recall why this was done this way in VB. However, matching the flow of C# makes sense to me. #Resolved

@jcouv jcouv self-assigned this Apr 23, 2017
@jcouv
Copy link
Member Author

jcouv commented Apr 24, 2017

@CyrusNajmabadi I'm thinking about what is required to merge the inferred tuple names branch back into master. The crash with IntroduceVariable is probably the biggest issue, but it's also not new.
I'm wondering if I could mitigate the issue until the larger issue with semantic model on tuple element names in VB is fixed. Maybe blocking the refactoring or putting a special case (the name of a tuple element doesn't contain expressions to be extracted into variables)?

@CyrusNajmabadi
Copy link
Member

Sorry, i'm not sure what this is referring to:

The crash with IntroduceVariable is probably the biggest issue

@jcouv
Copy link
Member Author

jcouv commented Apr 24, 2017

@CyrusNajmabadi More context:
A number of IntroduceVariable tests that I added in this PR are skipped. IntroduceVariable looks for the expression to extract (let's say i) and replaces it with the parenthesized local (let's say (local)), whenever i is found and matches what you're trying to extract.
The problem is that the semantic model for tuple element names is busted. So the symbol for i in (i:=1, 2) is found to be a local of the same name (assuming it exists). So the rewriter will attempt to produce ((local):=1, 2) which does not fit the syntax model (crash).

@CyrusNajmabadi
Copy link
Member

So the rewriter will attempt to produce ((local):=1, 2) which does not fit the syntax model (crash).

Can you just fix that?

@jcouv
Copy link
Member Author

jcouv commented Apr 24, 2017

I should be able to. The only concern is that such fix will become irrelevant once the semantic model is fixed.
I'll give it a shot. Thanks

@jcouv jcouv added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Apr 24, 2017
@jcouv jcouv removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label Apr 24, 2017
@jcouv
Copy link
Member Author

jcouv commented Apr 24, 2017

@CyrusNajmabadi That worked. I was debating to put a comment to remove that VisitNameColonEquals method once the semantic model is fixed, but I think that special case is reasonable to leave permanently.

@DustinCampbell @dotnet/roslyn-ide This PR is ready for review. You will find it very similar to the last one (for C#). Thanks!

@jcouv
Copy link
Member Author

jcouv commented Apr 25, 2017

@DustinCampbell @dotnet/roslyn-ide This PR is ready for review. Thanks.
I'm aiming to merge the tuple-names feature branch back into master on Thursday.

Sub Main()
Dim a = 1
Dim t = {|Rename:GetT|}(a)
System.Console.Write(t.a)
Copy link
Member

@DustinCampbell DustinCampbell Apr 26, 2017

Choose a reason for hiding this comment

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

Does this code compile, since the tuple returned by GetT does not have a as a member? #Resolved

Copy link
Member Author

@jcouv jcouv Apr 26, 2017

Choose a reason for hiding this comment

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

It won't compile. The refactoring uses VB 15.3 feature, but the project is only VB 15.
My understanding is there is a broader issue to allow making refactorings sensitive to language version. #Resolved


Dim oldOutermostBlock = container
If oldOutermostBlock.IsSingleLineExecutableBlock() Then
oldOutermostBlock = oldOutermostBlock.Parent
End If

Dim matches = FindMatches(document, expression, document, oldOutermostBlock, allOccurrences, cancellationToken)

Dim complexified = Await ComplexifyParentingStatements(document, matches, cancellationToken).ConfigureAwait(False)
Copy link
Member

@DustinCampbell DustinCampbell Apr 26, 2017

Choose a reason for hiding this comment

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

I don't recall why this was done this way in VB. However, matching the flow of C# makes sense to me. #Resolved

@@ -122,7 +139,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Simplification
Return newToken
End Function

Protected Function SimplifyExpression(Of TExpression As ExpressionSyntax)(
Protected Function SimplifyExpression(Of TExpression As SyntaxNode)(
Copy link
Member

Choose a reason for hiding this comment

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

Why was this necessary? It seems a bit weird given the method name, the type parameter name, and the parameter name, expression.

Copy link
Member Author

Choose a reason for hiding this comment

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

See corresponding C# implementation of SimplifyExpression. Notice that TExpression is constrained to SyntaxNode.

Specifically, the new Reducer (VisualBasicInferredMemberNameReducer.Rewriter) needs to simplify a SimpleArgumentSyntax (for tuples) and a NamedFieldInitializerSyntax (for anonymous types). Copied relevant code below:

     Public Overrides Function VisitSimpleArgument(node As SimpleArgumentSyntax) As SyntaxNode
                CancellationToken.ThrowIfCancellationRequested()

                Dim newNode = MyBase.VisitSimpleArgument(node)

                If node.IsParentKind(SyntaxKind.TupleExpression) Then
                    Return SimplifyExpression(
                        node,
                        newNode:=newNode,
                        simplifier:=AddressOf SimplifyTupleName)
                End If

                Return newNode
            End Function

            Public Overrides Function VisitNamedFieldInitializer(node As NamedFieldInitializerSyntax) As SyntaxNode
                Dim newNode = MyBase.VisitNamedFieldInitializer(node)

                Return SimplifyExpression(
                    node,
                    newNode:=newNode,
                    simplifier:=AddressOf SimplifyNamedFieldInitializer)
            End Function

        End Class

Copy link
Member

Choose a reason for hiding this comment

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

Then we really need to change the name. SimplifyExpression means to me that it will be getting an expression. I have no problem with you calling this SimplifyExpressionOrSimpleArgumentOrFieldInitializer. Or just having three helpers that each handle a single type.

@jcouv
Copy link
Member Author

jcouv commented Apr 26, 2017

Thanks @DustinCampbell Do I need to get a second review?

@DustinCampbell
Copy link
Member

I'm good with it. @CyrusNajmabadi, did you want to take a look?

If node.IsParentKind(SyntaxKind.SimpleArgument) AndAlso
node.Parent.IsParentKind(SyntaxKind.TupleExpression) Then

Return node
Copy link
Member

@CyrusNajmabadi CyrusNajmabadi Apr 26, 2017

Choose a reason for hiding this comment

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

this needs documentation as to why you are explicitly not changing anything in this situatoin. #Resolved

Return node.Parent
End If

Return Nothing
Copy link
Member

@CyrusNajmabadi CyrusNajmabadi Apr 26, 2017

Choose a reason for hiding this comment

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

this whole method needs commenting to explain what's going on. #Resolved

Copy link
Member Author

@jcouv jcouv Apr 26, 2017

Choose a reason for hiding this comment

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

So, for this one, I'm not really sure. I'll talk to Dustin. #Resolved

Copy link
Member Author

Choose a reason for hiding this comment

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

Removed this method.


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

newNode:=newNode,
simplifier:=AddressOf SimplifyNamedFieldInitializer)
End Function

Copy link
Member

Choose a reason for hiding this comment

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

nit: in general, i do not like extraneous newline between the 'end' statements of VB constructs.

) As SimpleArgumentSyntax

If node.NameColonEquals Is Nothing OrElse Not node.IsParentKind(SyntaxKind.TupleExpression) Then
Return node
Copy link
Member

Choose a reason for hiding this comment

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

needs comments.

@jcouv
Copy link
Member Author

jcouv commented Apr 26, 2017

@dotnet/roslyn-compiler This is the corresponding change for VB to public API change I made last week. It adds TryGetInferredMemberName and IsReservedTupleElementName.

@jcouv jcouv force-pushed the tuple-names-refactoring branch from 74122f5 to 47987fb Compare April 26, 2017 20:53
@jcouv jcouv force-pushed the tuple-names-refactoring branch from 47987fb to 304b908 Compare April 26, 2017 23:16
Copy link
Member

@jasonmalinowski jasonmalinowski left a comment

Choose a reason for hiding this comment

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

Did we get tests for renaming the field being captured by a tuple creation? We've (still 😦) blocked that for anonymous types and a few other places (@dpoeschl knows more), and we might have problems here too.

<Extension>
Public Function TryGetInferredMemberName(expression As ExpressionSyntax) As String
Dim ignore As XmlNameSyntax = Nothing
Dim nameToken As SyntaxToken = expression.ExtractAnonymousTypeMemberName(ignore)
Copy link
Member

Choose a reason for hiding this comment

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

This will null ref is expression is null.

Copy link
Member Author

Choose a reason for hiding this comment

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

Added a null check for safety.

@@ -1171,5 +1172,17 @@ Namespace Microsoft.CodeAnalysis.VisualBasic

Return False
End Function

''' <summary>
''' Checks whether the element name Is reserved.
Copy link
Member

Choose a reason for hiding this comment

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

Not sure why "Is" is capitalized.

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy and paste from C#, then VB auto-formatting. I'll fix.

Namespace System
Structure ValueTuple(Of T1, T2)
End Structure
End Namespace", TestOptions.Regular.WithLanguageVersion(LanguageVersion.VisualBasic15))
Copy link
Member

Choose a reason for hiding this comment

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

Why aren't we testing with 15.3 then? To be clear, you're OK doing a blanket upgrade of TestOptions.Regular to something higher.

Copy link
Member Author

Choose a reason for hiding this comment

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

See TestTupleWithInferredNames above. It uses VB15.3.

node.Parent.IsParentKind(SyntaxKind.TupleExpression) Then

' Temporaries should not be inlined in the name portion of a named tuple element
' This special case should be removed once https://github.com/dotnet/roslyn/issues/16697 is fixed
Copy link
Member

Choose a reason for hiding this comment

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

Is fixing #16697 on the docket for this work?

Copy link
Member Author

Choose a reason for hiding this comment

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

No

@jasonmalinowski
Copy link
Member

@jcouv, @VSadov, @rchande: you might want to take a look at the integration test failures here in this run. It might be flaky results, but might also indicate some new issues in the branch?

@VSadov
Copy link
Member

VSadov commented Apr 27, 2017

BasicReferenceHighlighting.Highlighting failed in both Debug and Release so could be related to the changes.
Other failures are more likely to be just flaky tests

''' Checks whether the element name is reserved.
'''
''' For example:
''' "Item3" is reserved (at certain positions).
Copy link
Member

Choose a reason for hiding this comment

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

What does at certain positions refer to? It looks like "Item3" will always return True.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'll update the comment. This refers to previous shape of the API (which was returning a position).

<InlineData("M()", "M")>
<InlineData("x.M()", "M")>
<InlineData("TypeOf(x)", Nothing)>
<InlineData("GetType(x)", Nothing)>
Copy link
Member

@cston cston Apr 27, 2017

Choose a reason for hiding this comment

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

Perhaps test: "Me", "[Me]", "x.Me", "x!y", "-x", "M()()", "New C()"

<InlineData("GetHashCode", True)>
<InlineData("item1", True)>
<InlineData("item10", True)>
<InlineData("Alice", False)>
Copy link
Member

Choose a reason for hiding this comment

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

"Item01"

@cston
Copy link
Member

cston commented Apr 27, 2017

Compiler changes LGTM

@jaredpar
Copy link
Member

APi changes look good.

@jcouv jcouv merged commit 3069ba1 into dotnet:features/tuple-names Apr 27, 2017
@jcouv jcouv deleted the tuple-names-refactoring branch April 27, 2017 15:50
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.

8 participants