Skip to content

Commit

Permalink
symbol matcher tuples support in C# and VB
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanbasov committed May 18, 2017
1 parent 1e444cf commit 8bb6f85
Show file tree
Hide file tree
Showing 9 changed files with 668 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -498,7 +498,7 @@ public override Symbol VisitNamedType(NamedTypeSymbol sourceType)
return null;
}

return TupleTypeSymbol.Create(otherDef, sourceType.TupleElementNames);
return otherDef;
}

Debug.Assert(sourceType.IsDefinition);
Expand Down Expand Up @@ -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)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3525,5 +3525,204 @@ .locals init ([unchanged] V_0,
}
", methodToken: diff1.UpdatedMethods.Single());
}

[Fact]
public void ComplexTypes()
{
var sourceText = @"
using System;
using System.Collections.Generic;
class C1<T>
{
public enum E
{
A
}
}
class C
{
public unsafe static void G()
{
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 };
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;
}
}
";
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<MethodSymbol>("C.G");
var f1 = compilation1.GetMember<MethodSymbol>("C.G");
var f2 = compilation2.GetMember<MethodSymbol>("C.G");

var v0 = CompileAndVerify(compilation0);
v0.VerifyIL("C.G", @"
{
// Code size 72 (0x48)
.maxstack 4
.locals init (<>f__AnonymousType0<string, System.Collections.Generic.List<(int, int)>> V_0, //a
System.ValueTuple<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>> V_1, //b
(int number, <anonymous type: string key, System.Collections.Generic.List<(int, int)> 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<string, System.Collections.Generic.List<(int, int)>>..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<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>>..ctor(int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>)""
IL_001a: ldc.i4.1
IL_001b: newarr ""System.ValueTuple<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>>""
IL_0020: dup
IL_0021: ldc.i4.0
IL_0022: ldloc.1
IL_0023: stelem ""System.ValueTuple<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>>""
IL_0028: stloc.2
IL_0029: ldc.i4.3
IL_002a: newarr ""int""
IL_002f: dup
IL_0030: ldtoken ""<PrivateImplementationDetails>.__StaticArrayInitTypeSize=12 <PrivateImplementationDetails>.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<string, System.Collections.Generic.List<(int, int)>> V_0, //a
System.ValueTuple<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>> V_1, //b
(int number, <anonymous type: string key, System.Collections.Generic.List<(int, int)> 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<string, System.Collections.Generic.List<(int, int)>>..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<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>>..ctor(int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>)""
IL_001a: ldc.i4.1
IL_001b: newarr ""System.ValueTuple<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>>""
IL_0020: dup
IL_0021: ldc.i4.0
IL_0022: ldloc.1
IL_0023: stelem ""System.ValueTuple<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> 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<string, System.Collections.Generic.List<(int, int)>> V_0, //a
System.ValueTuple<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>> V_1, //b
(int number, <anonymous type: string key, System.Collections.Generic.List<(int, int)> 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<string, System.Collections.Generic.List<(int, int)>>..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<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>>..ctor(int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>)""
IL_001a: ldc.i4.1
IL_001b: newarr ""System.ValueTuple<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> value>>""
IL_0020: dup
IL_0021: ldc.i4.0
IL_0022: ldloc.1
IL_0023: stelem ""System.ValueTuple<int, <anonymous type: string key, System.Collections.Generic.List<(int, int)> 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
}
");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}";
Expand Down Expand Up @@ -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();
}";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -652,10 +652,10 @@ 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
Return visitedSource IsNot Nothing AndAlso visitedSource.IsSameType(visitedOther, TypeCompareKind.IgnoreTupleNames)
End Function
End Class
End Class
Expand Down Expand Up @@ -692,6 +692,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),
Expand Down
5 changes: 3 additions & 2 deletions src/Compilers/VisualBasic/Test/Emit/CodeGen/CodeGenTuples.vb
Original file line number Diff line number Diff line change
Expand Up @@ -14755,7 +14755,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)))
Expand Down Expand Up @@ -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()))
End Sub

<Fact>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading

0 comments on commit 8bb6f85

Please sign in to comment.