Skip to content

Commit

Permalink
Supporting complex types in ENC (dotnet#19283)
Browse files Browse the repository at this point in the history
  • Loading branch information
ivanbasov authored May 20, 2017
1 parent b057348 commit af16c2a
Show file tree
Hide file tree
Showing 9 changed files with 740 additions and 10 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 @@ -3824,5 +3824,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,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
Expand Down Expand Up @@ -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),
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 @@ -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)))
Expand Down Expand Up @@ -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

<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 af16c2a

Please sign in to comment.