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

Supporting complex types in ENC (WAS: ENC for tuples in foreach) #19283

Merged
merged 4 commits into from
May 20, 2017

Conversation

ivanbasov
Copy link
Contributor

@ivanbasov ivanbasov commented May 5, 2017

Customer scenario

On ENC, user changes code near a variable declaration of a complex type, e.g. tuple or array of tuples like

var a = (1, 2);
<breakpoint is here> Console.WriteLine(0);

to

var a = (1, 2);
Console.WriteLine(1);

Expected: the variable has a value defined just above.
Actual: the variable value is reseted. Internally, a new variable is declared within ENC without a match to the existing one.

Bugs this fixes:

Fixes #19303

Workarounds, if any

Risk

Low

Performance impact

Low

Is this a regression from a previous update?

Root cause analysis:

How did we miss it? What tests are we adding to guard against it in the future?

How was the bug found?

Planned

@ivanbasov ivanbasov added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label May 5, 2017
@ivanbasov ivanbasov requested a review from tmat May 5, 2017 00:11
@ivanbasov ivanbasov requested a review from jcouv May 8, 2017 19:03
@@ -8077,5 +8077,403 @@ .maxstack 2
}
");
}

[Fact]
public void ForeachStatement_Reorder()
Copy link
Member

@tmat tmat May 9, 2017

Choose a reason for hiding this comment

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

ForeachStatement_Reorder [](start = 20, length = 24)

You can remove this test. Instead expand ArrayOfTuples to test 2nd generation. #Resolved

Copy link
Member

Choose a reason for hiding this comment

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

Also, add ArrayOfTuple test to VB


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

Copy link
Member

Choose a reason for hiding this comment

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

Actually... let's make the ArrayOfTuples test more interesting and make the type of the variable something like an array of tuples of anonymous types of a List. You can also add more variables of more complex types, including pointers, ref variables, etc.

And rename the test to ComplexTypes, or something like that.


In reply to: 115574092 [](ancestors = 115574092,115573899)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! Fixed


In reply to: 115576722 [](ancestors = 115576722,115574092,115573899)

@ivanbasov ivanbasov added Interactive-EnC and removed PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. labels May 11, 2017
var <N:0>a</N:0> = new { key = ""a"", value = new List<(int, int)>()};
var <N:1>b</N:1> = (number: 5, value: a);
var <N:2>c</N:2> = new[] { b };
IntPtr[] <N:3>d</N:3> = new IntPtr[1];
Copy link
Member

@tmat tmat May 11, 2017

Choose a reason for hiding this comment

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

IntPtr [](start = 8, length = 6)

This is not really a pointer type. IntPtr is just ordinary value type.

You can use the following trick to cover quite a few interesting cases:

class C<T>
{
    public enum E
    {
        A
    }
}


C<(int, dynamic)>.E***[,,] x;

#Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! This is done


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

@tmat
Copy link
Member

tmat commented May 11, 2017

:shipit:

Class C
Sub G()
Dim <N:0>a</N:0> = New With {.Key = ""a"", .Value = New List(Of Tuple(Of Integer, Integer))()}
Dim <N:1>b</N:1> = Tuple.Create(5, a)
Copy link
Member

@tmat tmat May 11, 2017

Choose a reason for hiding this comment

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

Tuple.Create(5, a) [](start = 27, length = 18)

This doesn't create a value tuple. I think VB has syntax for tuples as well. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! Added a test and made similar changes to VB. An existing VB test fails.


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

Dim <N:0>a</N:0> = New With {.Key = ""a"", .Value = New List(Of Tuple(Of Integer, Integer))()}
Dim <N:1>b</N:1> = Tuple.Create(5, a)
Dim <N:2>c</N:2> = {b}
Dim <N:3>d</N:3> = New IntPtr(1)
Copy link
Member

@tmat tmat May 11, 2017

Choose a reason for hiding this comment

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

Dim <N:3>d</N:3> = New IntPtr(1) [](start = 8, length = 32)

VB doesn't have pointers. We can remove this case. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK. Thanks!


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

@ivanbasov
Copy link
Contributor Author

ivanbasov commented May 11, 2017

Thank you for the feedback, @tmat ! I made corresponding changes. As I said, an existing VB test failed after changes in VisualBasicSymbolMatcher.vb #Resolved

@ivanbasov
Copy link
Contributor Author

ivanbasov commented May 11, 2017

E2E tests in VB with tuples, e.g. reordering foreach over tuples work fine #Resolved

@@ -692,6 +692,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
End Function

Public Overrides Function VisitNamedType(type As NamedTypeSymbol) As Symbol
If (type.IsTupleType) Then
Copy link
Member

@tmat tmat May 12, 2017

Choose a reason for hiding this comment

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

( [](start = 19, length = 1)

nit: No parentheses needed in VB #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

thanks!


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

@@ -498,7 +498,7 @@ public override Symbol VisitNamedType(NamedTypeSymbol sourceType)
return null;
}

return TupleTypeSymbol.Create(otherDef, sourceType.TupleElementNames);
return otherDef;
Copy link
Member

@jcouv jcouv May 12, 2017

Choose a reason for hiding this comment

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

Consider adding a comment. #Pending

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I could not find an idea for the comment. It seems like a simplification change. Do you have ideas for the comment?


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

var <N:2>c</N:2> = new[] { b };
int[] <N:3>array</N:3> = { 1, 2, 3 };
ref int <N:4>d</N:4> = ref array[0];
C1<(int, dynamic)>.E***[,,] <N:5>x</N:5> = null;
Copy link
Member

@jcouv jcouv May 12, 2017

Choose a reason for hiding this comment

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

Whoa #Resolved

@jcouv
Copy link
Member

jcouv commented May 12, 2017

The PR title mentions tuples in foreach, but I see no such test in the diff. I'm confused. #Resolved

var diff1 = compilation1.EmitDifference(
generation0,
ImmutableArray.Create(
new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true)));
Copy link
Member

@jcouv jcouv May 12, 2017

Choose a reason for hiding this comment

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

I don't understand what is the edit. Aren't f0 and f1 the same (both use the same source)? #Resolved

Copy link
Member

@tmat tmat May 12, 2017

Choose a reason for hiding this comment

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

There is no edit. The compiler doesn't care about edits, only how nodes that declare variables map to previous syntax. We just want to verify that the local slots are assigned correctly. #Resolved

@@ -692,6 +692,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
End Function

Public Overrides Function VisitNamedType(type As NamedTypeSymbol) As Symbol
If (type.IsTupleType) Then
Copy link
Member

@jcouv jcouv May 12, 2017

Choose a reason for hiding this comment

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

From our discussion, let's figure out why this didn't result in the extra locals (from previous PR and tests) to be optimized away. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

the original question was in #19114

re-reviewing it now


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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have reviewed scenarios mentioned in the discussion from the past code review #19114
There are EditAndContinueTests.cs with tuples in the foreach statement. We attempted to change their names or types.

  1. We still do not have a match for them, i.e. extra locals appear.
  2. We still have a rude edit warning for this situation. This prevents us from run-time errors.
  3. We already covered the situation with support advanced edits of foreach statements within ENC #19154

In reply to: 116639124 [](ancestors = 116639124,116339869)

@ivanbasov ivanbasov changed the title ENC for tuples in foreach Supporting complex types in ENC (WAS: ENC for tuples in foreach) May 16, 2017
@ivanbasov
Copy link
Contributor Author

Thank you! Fixed


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

@@ -769,7 +769,7 @@ public class C
public delegate (int, int) F();
}";
var source1 = @"
public struct C
Copy link
Member

@tmat tmat May 16, 2017

Choose a reason for hiding this comment

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

struct [](start = 7, length = 6)

Why this change? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We should compare class vs. class here not class vs. struct. The change happens in the delegate not in the class/struct.


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

Copy link
Member

Choose a reason for hiding this comment

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

Oh, yes. Sorry I missed that.


In reply to: 116845747 [](ancestors = 116845747,116844195)

@ivanbasov ivanbasov added the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label May 17, 2017
@ivanbasov
Copy link
Contributor Author

ivanbasov commented May 17, 2017

need to resolve merge conflict #Closed

@ivanbasov ivanbasov removed the PR For Personal Review Only The PR doesn’t require anyone other than the developer to review it. label May 17, 2017
@tmat
Copy link
Member

tmat commented May 17, 2017

@dotnet/roslyn-compiler Need 2 reviews please.

@tmat tmat added this to the 15.3 milestone May 17, 2017
@tmat tmat requested review from AlekseyTs and VSadov May 17, 2017 23:24
@@ -317,6 +317,41 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
Return IsSameType(obj, TypeCompareKind.ConsiderEverything)
End Function

Friend Overrides Function Equals(t2 As TypeSymbol, comparison As TypeCompareKind) As Boolean
Copy link
Member

@tmat tmat May 17, 2017

Choose a reason for hiding this comment

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

Equals [](start = 34, length = 6)

Each of these implementations could use some compiler unit tests. Presumably there are some C# tests that can be ported. #Resolved

Copy link
Member

Choose a reason for hiding this comment

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

Specifically, types with custom modifiers.


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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed Symbol changes. Current test coverage should be enough. Thank you!


In reply to: 117133247 [](ancestors = 117133247,117133141)

Return True
End If
End If
End If
Copy link
Member

@tmat tmat May 17, 2017

Choose a reason for hiding this comment

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

No applicable in VB. VB doesn't have Dynamic type. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! Fixed.


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

@AlekseyTs
Copy link
Contributor

AlekseyTs commented May 18, 2017

As we discussed offline, we should switch to using IsSameType extension method, rather than adding new Equals overload. #Closed

@ivanbasov
Copy link
Contributor Author

Thank you! Fixed


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


Return visitedSource = visitedOther
Return visitedSource IsNot Nothing AndAlso visitedSource.IsSameType(visitedOther, TypeCompareKind.IgnoreTupleNames)
Copy link
Contributor

@AlekseyTs AlekseyTs May 19, 2017

Choose a reason for hiding this comment

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

visitedSource.IsSameType(visitedOther, TypeCompareKind.IgnoreTupleNames) [](start = 63, length = 72)

We are checking if visitedSource is Nothing, it looks like we should do the same check for visitedOther. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! Fixed


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

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you!


In reply to: 117552926 [](ancestors = 117552926,117395320)

@AlekseyTs
Copy link
Contributor

AlekseyTs commented May 19, 2017

Done with review pass. #Closed


Return visitedSource = visitedOther
' If both visitedSource And visitedOther are Nothing, return false meaning that the method was not able to verify the equality.
Copy link
Contributor

@AlekseyTs AlekseyTs May 19, 2017

Choose a reason for hiding this comment

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

And [](start = 44, length = 3)

"And" vs "and". #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! Fixed


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

Copy link
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

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

LGTM

@@ -14803,7 +14803,8 @@ options:=TestOptions.DebugExe, additionalRefs:=s_valueTupleRefs)
End Sub

Private Shared Sub AssertTestDisplayString(symbols As ImmutableArray(Of Symbol), ParamArray baseLine As String())
AssertEx.Equal(symbols.Select(Function(s) s.ToTestDisplayString()), baseLine)
' Re-ordering arguments because expected Is usually goes first.
AssertEx.Equal(baseLine, symbols.Select(Function(s) s.ToTestDisplayString()))
Copy link
Member

@cston cston May 19, 2017

Choose a reason for hiding this comment

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

is rather than Is, and perhaps just expected is first. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! Fixed


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

Dim member = compilation1.GetMember(Of FieldSymbol)("C.x")
Dim other = matcher.MapDefinition(member)
' Types must match because just an element name was changed.
Assert.NotNull(other)
Copy link
Member

@cston cston May 19, 2017

Choose a reason for hiding this comment

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

Perhaps Assert.Equal("... signature ...", other.ToTestDisplayString()), here and in other tests below.
#Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good idea! Thank you! Done


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

Dim other = matcher.MapDefinition(member)
' Tuple delegate defines a type. We should be able to match old and new types by name.
Assert.NotNull(other)
End Sub
Copy link
Member

@cston cston May 19, 2017

Choose a reason for hiding this comment

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

Consider testing type changes from non-tuple to tuple and tuple to non-tuple. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you! Added


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

@cston
Copy link
Member

cston commented May 19, 2017

LGTM

@ivanbasov
Copy link
Contributor Author

Tagging @MattGertz or @MeiChin-Tsai for ask mode or escrow approval

@MattGertz
Copy link
Contributor

OK by me. Once Mei-Chin approves, please go ahead & set the label.

@MeiChin-Tsai
Copy link

approved.

@ivanbasov ivanbasov merged commit af16c2a into dotnet:master May 20, 2017
@ivanbasov ivanbasov deleted the enc branch May 20, 2017 00:50
ivanbasov added a commit to ivanbasov/roslyn that referenced this pull request May 22, 2017
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.

Support matching complex types between ENC generations
8 participants