-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Conversation
@@ -8077,5 +8077,403 @@ .maxstack 2 | |||
} | |||
"); | |||
} | |||
|
|||
[Fact] | |||
public void ForeachStatement_Reorder() |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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]; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
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) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the feedback, @tmat ! I made corresponding changes. As I said, an existing VB test failed after changes in VisualBasicSymbolMatcher.vb #Resolved |
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -498,7 +498,7 @@ public override Symbol VisitNamedType(NamedTypeSymbol sourceType) | |||
return null; | |||
} | |||
|
|||
return TupleTypeSymbol.Create(otherDef, sourceType.TupleElementNames); | |||
return otherDef; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whoa #Resolved
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))); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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.
- We still do not have a match for them, i.e. extra locals appear.
- We still have a rude edit warning for this situation. This prevents us from run-time errors.
- We already covered the situation with support advanced edits of foreach statements within ENC #19154
In reply to: 116639124 [](ancestors = 116639124,116339869)
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
need to resolve merge conflict #Closed |
@dotnet/roslyn-compiler Need 2 reviews please. |
@@ -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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As we discussed offline, we should switch to using IsSameType extension method, rather than adding new Equals overload. #Closed |
Thank you! Fixed In reply to: 302563607 [](ancestors = 302563607) |
|
||
Return visitedSource = visitedOther | ||
Return visitedSource IsNot Nothing AndAlso visitedSource.IsSameType(visitedOther, TypeCompareKind.IgnoreTupleNames) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this 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())) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM |
Tagging @MattGertz or @MeiChin-Tsai for ask mode or escrow approval |
OK by me. Once Mei-Chin approves, please go ahead & set the label. |
approved. |
Customer scenario
On ENC, user changes code near a variable declaration of a complex type, e.g. tuple or array of tuples like
to
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