From af16c2adace0b2d235503000ba7b3aa8fbeb3024 Mon Sep 17 00:00:00 2001 From: Ivan Basov Date: Fri, 19 May 2017 17:50:23 -0700 Subject: [PATCH] Supporting complex types in ENC (#19283) --- .../EditAndContinue/CSharpSymbolMatcher.cs | 8 +- .../EditAndContinue/LocalSlotMappingTests.cs | 199 +++++++++ .../EditAndContinue/SymbolMatcherTests.cs | 4 +- .../VisualBasicSymbolMatcher.vb | 14 +- .../Test/Emit/CodeGen/CodeGenTuples.vb | 5 +- .../EditAndContinueTestBase.vb | 2 + .../EditAndContinue/LocalSlotMappingTests.vb | 120 ++++++ .../EditAndContinue/SymbolMatcherTests.vb | 394 +++++++++++++++++- .../Utilities/Portable/Assert/AssertEx.cs | 4 + 9 files changed, 740 insertions(+), 10 deletions(-) diff --git a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs index 17535195836..b47a2f04b7f 100644 --- a/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs +++ b/src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs @@ -498,7 +498,7 @@ public override Symbol VisitNamedType(NamedTypeSymbol sourceType) return null; } - return TupleTypeSymbol.Create(otherDef, sourceType.TupleElementNames); + return otherDef; } Debug.Assert(sourceType.IsDefinition); @@ -888,6 +888,12 @@ public override Symbol VisitDynamicType(DynamicTypeSymbol symbol) public override Symbol VisitNamedType(NamedTypeSymbol type) { + if (type.IsTupleType) + { + type = type.TupleUnderlyingType; + Debug.Assert(!type.IsTupleType); + } + var originalDef = type.OriginalDefinition; if ((object)originalDef != type) { diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs index b3d188e3346..4b6512a9414 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs @@ -3824,5 +3824,204 @@ .maxstack 2 } ", methodToken: diff1.UpdatedMethods.Single()); } + + [Fact] + public void ComplexTypes() + { + var sourceText = @" +using System; +using System.Collections.Generic; + +class C1 +{ + public enum E + { + A + } +} + +class C +{ + public unsafe static void G() + { + var a = new { key = ""a"", value = new List<(int, int)>()}; + var b = (number: 5, value: a); + var c = new[] { b }; + int[] array = { 1, 2, 3 }; + ref int d = ref array[0]; + C1<(int, dynamic)>.E***[,,] x = null; + } +} +"; + var source0 = MarkedSource(sourceText); + var source1 = MarkedSource(sourceText); + var source2 = MarkedSource(sourceText); + + var compilation0 = CreateStandardCompilation(source0.Tree, options: ComSafeDebugDll.WithAllowUnsafe(true), references: s_valueTupleRefs); + var compilation1 = compilation0.WithSource(source1.Tree); + var compilation2 = compilation1.WithSource(source2.Tree); + + var f0 = compilation0.GetMember("C.G"); + var f1 = compilation1.GetMember("C.G"); + var f2 = compilation2.GetMember("C.G"); + + var v0 = CompileAndVerify(compilation0); + v0.VerifyIL("C.G", @" +{ + // Code size 72 (0x48) + .maxstack 4 + .locals init (<>f__AnonymousType0> V_0, //a + System.ValueTuple value>> V_1, //b + (int number, value> value)[] V_2, //c + int[] V_3, //array + int& V_4, //d + C1<(int, dynamic)>.E***[,,] V_5) //x + IL_0000: nop + IL_0001: ldstr ""a"" + IL_0006: newobj ""System.Collections.Generic.List<(int, int)>..ctor()"" + IL_000b: newobj ""<>f__AnonymousType0>..ctor(string, System.Collections.Generic.List<(int, int)>)"" + IL_0010: stloc.0 + IL_0011: ldloca.s V_1 + IL_0013: ldc.i4.5 + IL_0014: ldloc.0 + IL_0015: call ""System.ValueTuple value>>..ctor(int, value>)"" + IL_001a: ldc.i4.1 + IL_001b: newarr ""System.ValueTuple value>>"" + IL_0020: dup + IL_0021: ldc.i4.0 + IL_0022: ldloc.1 + IL_0023: stelem ""System.ValueTuple value>>"" + IL_0028: stloc.2 + IL_0029: ldc.i4.3 + IL_002a: newarr ""int"" + IL_002f: dup + IL_0030: ldtoken "".__StaticArrayInitTypeSize=12 .E429CCA3F703A39CC5954A6572FEC9086135B34E"" + IL_0035: call ""void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)"" + IL_003a: stloc.3 + IL_003b: ldloc.3 + IL_003c: ldc.i4.0 + IL_003d: ldelema ""int"" + IL_0042: stloc.s V_4 + IL_0044: ldnull + IL_0045: stloc.s V_5 + IL_0047: ret +} +"); + + var md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData); + + var generation0 = EmitBaseline.CreateInitialBaseline(md0, v0.CreateSymReader().GetEncMethodDebugInfo); + var diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables: true))); + + diff1.VerifyIL("C.G", @" +{ + // Code size 73 (0x49) + .maxstack 4 + .locals init (<>f__AnonymousType0> V_0, //a + System.ValueTuple value>> V_1, //b + (int number, value> value)[] V_2, //c + int[] V_3, //array + int& V_4, //d + C1<(int, dynamic)>.E***[,,] V_5) //x + IL_0000: nop + IL_0001: ldstr ""a"" + IL_0006: newobj ""System.Collections.Generic.List<(int, int)>..ctor()"" + IL_000b: newobj ""<>f__AnonymousType0>..ctor(string, System.Collections.Generic.List<(int, int)>)"" + IL_0010: stloc.0 + IL_0011: ldloca.s V_1 + IL_0013: ldc.i4.5 + IL_0014: ldloc.0 + IL_0015: call ""System.ValueTuple value>>..ctor(int, value>)"" + IL_001a: ldc.i4.1 + IL_001b: newarr ""System.ValueTuple value>>"" + IL_0020: dup + IL_0021: ldc.i4.0 + IL_0022: ldloc.1 + IL_0023: stelem ""System.ValueTuple value>>"" + IL_0028: stloc.2 + IL_0029: ldc.i4.3 + IL_002a: newarr ""int"" + IL_002f: dup + IL_0030: ldc.i4.0 + IL_0031: ldc.i4.1 + IL_0032: stelem.i4 + IL_0033: dup + IL_0034: ldc.i4.1 + IL_0035: ldc.i4.2 + IL_0036: stelem.i4 + IL_0037: dup + IL_0038: ldc.i4.2 + IL_0039: ldc.i4.3 + IL_003a: stelem.i4 + IL_003b: stloc.3 + IL_003c: ldloc.3 + IL_003d: ldc.i4.0 + IL_003e: ldelema ""int"" + IL_0043: stloc.s V_4 + IL_0045: ldnull + IL_0046: stloc.s V_5 + IL_0048: ret +} +"); + + var diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create( + new SemanticEdit(SemanticEditKind.Update, f1, f2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables: true))); + + diff2.VerifyIL("C.G", @" +{ + // Code size 73 (0x49) + .maxstack 4 + .locals init (<>f__AnonymousType0> V_0, //a + System.ValueTuple value>> V_1, //b + (int number, value> value)[] V_2, //c + int[] V_3, //array + int& V_4, //d + C1<(int, dynamic)>.E***[,,] V_5) //x + IL_0000: nop + IL_0001: ldstr ""a"" + IL_0006: newobj ""System.Collections.Generic.List<(int, int)>..ctor()"" + IL_000b: newobj ""<>f__AnonymousType0>..ctor(string, System.Collections.Generic.List<(int, int)>)"" + IL_0010: stloc.0 + IL_0011: ldloca.s V_1 + IL_0013: ldc.i4.5 + IL_0014: ldloc.0 + IL_0015: call ""System.ValueTuple value>>..ctor(int, value>)"" + IL_001a: ldc.i4.1 + IL_001b: newarr ""System.ValueTuple value>>"" + IL_0020: dup + IL_0021: ldc.i4.0 + IL_0022: ldloc.1 + IL_0023: stelem ""System.ValueTuple value>>"" + IL_0028: stloc.2 + IL_0029: ldc.i4.3 + IL_002a: newarr ""int"" + IL_002f: dup + IL_0030: ldc.i4.0 + IL_0031: ldc.i4.1 + IL_0032: stelem.i4 + IL_0033: dup + IL_0034: ldc.i4.1 + IL_0035: ldc.i4.2 + IL_0036: stelem.i4 + IL_0037: dup + IL_0038: ldc.i4.2 + IL_0039: ldc.i4.3 + IL_003a: stelem.i4 + IL_003b: stloc.3 + IL_003c: ldloc.3 + IL_003d: ldc.i4.0 + IL_003e: ldelema ""int"" + IL_0043: stloc.s V_4 + IL_0045: ldnull + IL_0046: stloc.s V_5 + IL_0048: ret +} +"); + } } } \ No newline at end of file diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.cs index 304ab38789f..f3fc2f0c44a 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.cs @@ -769,7 +769,7 @@ public class C public delegate (int, int) F(); }"; var source1 = @" -public struct C +public class C { public delegate (int, bool) F(); }"; @@ -799,7 +799,7 @@ public class C public delegate (int, int) F(); }"; var source1 = @" -public struct C +public class C { public delegate (int x, int y) F(); }"; diff --git a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicSymbolMatcher.vb b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicSymbolMatcher.vb index 32e5fa57694..94568398b8a 100644 --- a/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicSymbolMatcher.vb +++ b/src/Compilers/VisualBasic/Portable/Emit/EditAndContinue/VisualBasicSymbolMatcher.vb @@ -402,7 +402,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit Return Nothing End If - Return TupleTypeSymbol.Create(otherDef, type.TupleElementNames) + Return otherDef End If Debug.Assert(type.IsDefinition) @@ -652,10 +652,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Sub Public Overloads Function Equals(source As TypeSymbol, other As TypeSymbol) As Boolean - Dim visitedSource = _matcher.Visit(source) - Dim visitedOther = If(_deepTranslatorOpt IsNot Nothing, _deepTranslatorOpt.Visit(other), other) + Dim visitedSource = DirectCast(_matcher.Visit(source), TypeSymbol) + Dim visitedOther = If(_deepTranslatorOpt IsNot Nothing, DirectCast(_deepTranslatorOpt.Visit(other), TypeSymbol), other) - Return visitedSource = visitedOther + ' If both visitedSource and visitedOther are Nothing, return false meaning that the method was not able to verify the equality. + Return visitedSource IsNot Nothing AndAlso visitedOther IsNot Nothing AndAlso visitedSource.IsSameType(visitedOther, TypeCompareKind.IgnoreTupleNames) End Function End Class End Class @@ -692,6 +693,11 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.Emit End Function Public Overrides Function VisitNamedType(type As NamedTypeSymbol) As Symbol + If type.IsTupleType Then + type = type.TupleUnderlyingType + Debug.Assert(Not type.IsTupleType) + End If + Dim originalDef As NamedTypeSymbol = type.OriginalDefinition If originalDef IsNot type Then Dim translatedTypeArguments = type.GetAllTypeArgumentsWithModifiers().SelectAsArray(Function(t, v) New TypeWithModifiers(DirectCast(v.Visit(t.Type), TypeSymbol), diff --git a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb index 1c860d2db5e..15b70d10ca7 100644 --- a/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb +++ b/src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb @@ -14776,7 +14776,7 @@ options:=TestOptions.DebugExe, additionalRefs:=s_valueTupleRefs) Next For i = 0 To members1.Length - 1 - For j = 0 To members2.Length + For j = 0 To members2.Length - 1 If i <> j Then Assert.NotSame(members1(i), members2(j)) Assert.False(members1(i).Equals(members2(j))) @@ -14824,7 +14824,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 first. + AssertEx.Equal(baseLine, symbols.Select(Function(s) s.ToTestDisplayString())) End Sub diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.vb index ee35f1e63d3..c413edbfa7f 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/EditAndContinueTestBase.vb @@ -21,6 +21,8 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests ' PDB reader can only be accessed from a single thread, so avoid concurrent compilation: Protected Shared ReadOnly ComSafeDebugDll As VisualBasicCompilationOptions = TestOptions.DebugDll.WithConcurrentBuild(False) + Protected Shared ReadOnly ValueTupleRefs As MetadataReference() = {SystemRuntimeFacadeRef, ValueTupleRef} + Friend Shared ReadOnly EmptyLocalsProvider As Func(Of MethodDefinitionHandle, EditAndContinueMethodDebugInformation) = Function(token) Nothing Friend Shared Function Visualize(baseline As ModuleMetadata, ParamArray deltas As PinnedMetadata()) As String diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.vb index dfd38077e76..ebee3522189 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.vb @@ -924,5 +924,125 @@ End Class End Sub + + Public Sub ComplexTypes() + Dim sourceText = " +Imports System +Imports System.Collections.Generic + +Class C + Sub G() + Dim a = New With {.Key = ""a"", .Value = New List(Of Tuple(Of Integer, Integer))()} + Dim b = (5, a) + Dim c = {b} + End Sub +End Class +" + Dim source0 = MarkedSource(sourceText) + Dim source1 = MarkedSource(sourceText) + Dim source2 = MarkedSource(sourceText) + + Dim compilation0 = CreateCompilationWithMscorlib(source0.Tree, options:=ComSafeDebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1.Tree) + Dim compilation2 = compilation1.WithSource(source2.Tree) + + Dim f0 = compilation0.GetMember(Of MethodSymbol)("C.G") + Dim f1 = compilation1.GetMember(Of MethodSymbol)("C.G") + Dim f2 = compilation2.GetMember(Of MethodSymbol)("C.G") + + Dim v0 = CompileAndVerify(compilation0) + v0.VerifyIL("C.G", " +{ + // Code size 42 (0x2a) + .maxstack 4 + .locals init (VB$AnonymousType_0(Of String, System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer))) V_0, //a + System.ValueTuple(Of Integer, ) V_1, //b + (Integer, a As )() V_2) //c + IL_0000: nop + IL_0001: ldstr ""a"" + IL_0006: newobj ""Sub System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer))..ctor()"" + IL_000b: newobj ""Sub VB$AnonymousType_0(Of String, System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer)))..ctor(String, System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer)))"" + IL_0010: stloc.0 + IL_0011: ldloca.s V_1 + IL_0013: ldc.i4.5 + IL_0014: ldloc.0 + IL_0015: call ""Sub System.ValueTuple(Of Integer, )..ctor(Integer, )"" + IL_001a: ldc.i4.1 + IL_001b: newarr ""System.ValueTuple(Of Integer, )"" + IL_0020: dup + IL_0021: ldc.i4.0 + IL_0022: ldloc.1 + IL_0023: stelem ""System.ValueTuple(Of Integer, )"" + IL_0028: stloc.2 + IL_0029: ret +} +") + + Dim md0 = ModuleMetadata.CreateFromImage(v0.EmittedAssemblyData) + + Dim generation0 = EmitBaseline.CreateInitialBaseline(md0, AddressOf v0.CreateSymReader().GetEncMethodDebugInfo) + Dim diff1 = compilation1.EmitDifference( + generation0, + ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f0, f1, GetSyntaxMapFromMarkers(source0, source1), preserveLocalVariables:=True))) + + diff1.VerifyIL("C.G", " +{ + // Code size 42 (0x2a) + .maxstack 4 + .locals init (VB$AnonymousType_0(Of String, System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer))) V_0, //a + System.ValueTuple(Of Integer, ) V_1, //b + (Integer, a As )() V_2) //c + IL_0000: nop + IL_0001: ldstr ""a"" + IL_0006: newobj ""Sub System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer))..ctor()"" + IL_000b: newobj ""Sub VB$AnonymousType_0(Of String, System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer)))..ctor(String, System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer)))"" + IL_0010: stloc.0 + IL_0011: ldloca.s V_1 + IL_0013: ldc.i4.5 + IL_0014: ldloc.0 + IL_0015: call ""Sub System.ValueTuple(Of Integer, )..ctor(Integer, )"" + IL_001a: ldc.i4.1 + IL_001b: newarr ""System.ValueTuple(Of Integer, )"" + IL_0020: dup + IL_0021: ldc.i4.0 + IL_0022: ldloc.1 + IL_0023: stelem ""System.ValueTuple(Of Integer, )"" + IL_0028: stloc.2 + IL_0029: ret +} +") + + Dim diff2 = compilation2.EmitDifference( + diff1.NextGeneration, + ImmutableArray.Create(New SemanticEdit(SemanticEditKind.Update, f1, f2, GetSyntaxMapFromMarkers(source1, source2), preserveLocalVariables:=True))) + + diff2.VerifyIL("C.G", " +{ + // Code size 42 (0x2a) + .maxstack 4 + .locals init (VB$AnonymousType_0(Of String, System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer))) V_0, //a + System.ValueTuple(Of Integer, ) V_1, //b + (Integer, a As )() V_2) //c + IL_0000: nop + IL_0001: ldstr ""a"" + IL_0006: newobj ""Sub System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer))..ctor()"" + IL_000b: newobj ""Sub VB$AnonymousType_0(Of String, System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer)))..ctor(String, System.Collections.Generic.List(Of System.Tuple(Of Integer, Integer)))"" + IL_0010: stloc.0 + IL_0011: ldloca.s V_1 + IL_0013: ldc.i4.5 + IL_0014: ldloc.0 + IL_0015: call ""Sub System.ValueTuple(Of Integer, )..ctor(Integer, )"" + IL_001a: ldc.i4.1 + IL_001b: newarr ""System.ValueTuple(Of Integer, )"" + IL_0020: dup + IL_0021: ldc.i4.0 + IL_0022: ldloc.1 + IL_0023: stelem ""System.ValueTuple(Of Integer, )"" + IL_0028: stloc.2 + IL_0029: ret +} +") + End Sub + End Class End Namespace diff --git a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.vb b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.vb index ca3e62666ef..c25dda32bb5 100644 --- a/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.vb +++ b/src/Compilers/VisualBasic/Test/Emit/Emit/EditAndContinue/SymbolMatcherTests.vb @@ -512,5 +512,397 @@ End Class Assert.Equal("$VB$Local_x1", mappedX1.Name) Assert.Null(mappedX2) End Sub + + + Public Sub TupleField_TypeChange() + Dim source0 = " +Class C +{ + Public x As (a As Integer, b As Integer) +}" + Dim source1 = " +Class C +{ + Public x As (a As Integer, b As Boolean) +}" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of FieldSymbol)("C.x") + Dim other = matcher.MapDefinition(member) + ' If a type changes within a tuple, we do not expect types to match. + Assert.Null(other) + End Sub + + + Public Sub TupleField_NameChange() + + Dim source0 = " +Class C +{ + Public x As (a As Integer, b As Integer) +}" + Dim source1 = " +Class C +{ + Public x As (a As Integer, c As Integer) +}" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of FieldSymbol)("C.x") + Dim other = matcher.MapDefinition(member) + ' Types must match because just an element name was changed. + Dim otherSymbol = DirectCast(other, SourceFieldSymbol) + Assert.NotNull(otherSymbol) + Assert.Equal("C.x As (a As System.Int32, b As System.Int32)", otherSymbol.ToTestDisplayString()) + End Sub + + + Public Sub TupleMethod_TypeToNoTupleChange() + Dim source0 = " +Class C + Public Function X() As (a As Integer, b As Integer) + Return Nothing + End Function +End Class +" + Dim source1 = " +Class C + Public Function X() As Integer() + Return Nothing + End Function +End Class +" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of MethodSymbol)("C.X") + Dim other = matcher.MapDefinition(member) + ' Types should not match: one is tuple and another is not. + Assert.Null(other) + End Sub + + + Public Sub TupleMethod_TypeFromNoTupleChange() + Dim source0 = " +Class C + Public Function X() As Integer() + Return Nothing + End Function +End Class +" + Dim source1 = " +Class C + Public Function X() As (a As Integer, b As Boolean) + Return Nothing + End Function +End Class +" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of MethodSymbol)("C.X") + Dim other = matcher.MapDefinition(member) + ' Types should not match: one is tuple and another is not. + Assert.Null(other) + End Sub + + + Public Sub TupleMethod_TypeChange() + Dim source0 = " +Class C + Public Function X() As (a As Integer, b As Integer) + Return Nothing + End Function +End Class +" + Dim source1 = " +Class C + Public Function X() As (a As Integer, b As Boolean) + Return Nothing + End Function +End Class +" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of MethodSymbol)("C.X") + Dim other = matcher.MapDefinition(member) + ' If a type changes within a tuple, we do not expect types to match. + Assert.Null(other) + End Sub + + + Public Sub TupleMethod_NameChange() + Dim source0 = " +Class C + Public Function X() As (a As Integer, b As Integer) + Return Nothing + End Function +End Class +" + Dim source1 = " +Class C + Public Function X() As (a As Integer, c As Integer) + Return Nothing + End Function +End Class +" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of MethodSymbol)("C.X") + Dim other = matcher.MapDefinition(member) + ' Types must match because just an element name was changed. + Dim otherSymbol = DirectCast(other, SourceMemberMethodSymbol) + Assert.NotNull(otherSymbol) + Assert.Equal("Function C.X() As (a As System.Int32, b As System.Int32)", otherSymbol.ToTestDisplayString()) + End Sub + + + Public Sub TupleProperty_TypeChange() + Dim source0 = " +Class C + Public ReadOnly Property X As (a As Integer, b As Integer) + Get + Return Nothing + End Get + End Property +End Class +" + Dim source1 = " +Class C + Public ReadOnly Property X As (a As Integer, b As Boolean) + Get + Return Nothing + End Get + End Property +End Class +" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of PropertySymbol)("C.X") + Dim other = matcher.MapDefinition(member) + ' If a type changes within a tuple, we do not expect types to match. + Assert.Null(other) + End Sub + + + Public Sub TupleProperty_NameChange() + Dim source0 = " +Class C + Public ReadOnly Property X As (a As Integer, b As Integer) + Get + Return Nothing + End Get + End Property +End Class +" + Dim source1 = " +Class C + Public ReadOnly Property X As (a As Integer, c As Integer) + Get + Return Nothing + End Get + End Property +End Class +" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of PropertySymbol)("C.X") + Dim other = matcher.MapDefinition(member) + ' Types must match because just an element name was changed. + Dim otherSymbol = DirectCast(other, SourcePropertySymbol) + Assert.NotNull(otherSymbol) + Assert.Equal("ReadOnly Property C.X As (a As System.Int32, b As System.Int32)", otherSymbol.ToTestDisplayString()) + End Sub + + + Public Sub TupleStructField_TypeChange() + Dim source0 = " +Public Structure Vector + Public Coordinates As (x As Integer, y As Integer) +End Structure +" + Dim source1 = " +Public Structure Vector + Public Coordinates As (x As Integer, y As Integer, z As Integer) +End Structure +" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of FieldSymbol)("Vector.Coordinates") + Dim other = matcher.MapDefinition(member) + ' If a type changes within a tuple, we do not expect types to match. + Assert.Null(other) + End Sub + + + Public Sub TupleStructField_NameChange() + Dim source0 = " +Public Structure Vector + Public Coordinates As (x As Integer, y As Integer) +End Structure +" + Dim source1 = " +Public Structure Vector + Public Coordinates As (x As Integer, z As Integer) +End Structure +" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:= TestOptions.DebugDll, references:= ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of FieldSymbol)("Vector.Coordinates") + Dim other = matcher.MapDefinition(member) + ' Types must match because just an element name was changed. + Dim otherSymbol = DirectCast(other, SourceFieldSymbol) + Assert.NotNull(otherSymbol) + Assert.Equal("Vector.Coordinates As (x As System.Int32, y As System.Int32)", otherSymbol.ToTestDisplayString()) + End Sub + + + Public Sub TupleDelegate_TypeChange() + Dim source0 = " +Public Class C + Public Delegate Function F() As (Integer, Integer) +End Class +" + Dim source1 = " +Public Class C + Public Delegate Function F() As (Integer, Boolean) +End Class +" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:= TestOptions.DebugDll, references:= ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of SourceNamedTypeSymbol)("C.F") + Dim other = matcher.MapDefinition(member) + ' Tuple delegate defines a type. We should be able to match old and new types by name. + Dim otherSymbol = DirectCast(other, SourceNamedTypeSymbol) + Assert.NotNull(otherSymbol) + Assert.Equal("C.F", otherSymbol.ToTestDisplayString()) + End Sub + + + Public Sub TupleDeletagate_NameChange() + Dim source0 = " +Public Class C + Public Delegate Function F() As (x as Integer, y as Integer) +End Class +" + Dim source1 = " +Public Class C + Public Delegate Function F() As (x as Integer, z as Integer) +End Class" + Dim compilation0 = CreateCompilationWithMscorlib(source0, options:=TestOptions.DebugDll, references:=ValueTupleRefs) + Dim compilation1 = compilation0.WithSource(source1) + + Dim matcher = New VisualBasicSymbolMatcher( + Nothing, + compilation1.SourceAssembly, + New EmitContext(), + compilation0.SourceAssembly, + New EmitContext(), + Nothing) + + Dim member = compilation1.GetMember(Of SourceNamedTypeSymbol)("C.F") + Dim other = matcher.MapDefinition(member) + ' Types must match because just an element name was changed. + Dim otherSymbol = DirectCast(other, SourceNamedTypeSymbol) + Assert.NotNull(otherSymbol) + Assert.Equal("C.F", otherSymbol.ToTestDisplayString()) + End Sub End Class -End Namespace +End Namespace \ No newline at end of file diff --git a/src/Test/Utilities/Portable/Assert/AssertEx.cs b/src/Test/Utilities/Portable/Assert/AssertEx.cs index 6a5d7c038c4..7bfc8aec55e 100644 --- a/src/Test/Utilities/Portable/Assert/AssertEx.cs +++ b/src/Test/Utilities/Portable/Assert/AssertEx.cs @@ -448,6 +448,10 @@ public static string GetAssertMessage(IEnumerable expected, IEnumerable { itemInspector = b => $"0x{b:X2}"; } + else if (expected is IEnumerable) + { + itemInspector = new Func(obj => (obj != null) ? string.Format("\"{0}\"", obj.ToString()) : ""); + } else { itemInspector = new Func(obj => (obj != null) ? obj.ToString() : ""); -- GitLab