提交 9c7ab597 编写于 作者: T TomasMatousek

Static lambdas in generic methods are emitted on per-method display class....

Static lambdas in generic methods are emitted on per-method display class. Include method ordinal into its name to make it unique.

     The previous change to synthesized name numbering introduced a regression - if two generic methods of the same arity contained static lambdas the resulting assembly had duplicate type names. This change addresses that case.
 (changeset 1391470)
上级 65c17605
......@@ -703,7 +703,7 @@
<Compile Include="Symbols\Synthesized\SynthesizedStaticConstructor.cs" />
<Compile Include="Symbols\Synthesized\SynthesizedStringHashFunctionSymbol.cs" />
<Compile Include="Symbols\Synthesized\SynthesizedSubmissionConstructor.cs" />
<Compile Include="Symbols\Synthesized\SynthesizedTypeParameterSymbol.cs" />
<Compile Include="Symbols\Synthesized\SynthesizedSubstitutedTypeParameterSymbol.cs" />
<Compile Include="Symbols\Synthesized\TypeSubstitutedLocalSymbol.cs" />
<Compile Include="Symbols\TypedConstantExtensions.cs" />
<Compile Include="Symbols\TypeMap.cs" />
......
......@@ -21,8 +21,8 @@ internal sealed class LambdaFrame : SynthesizedContainer, ISynthesizedMethodBody
private readonly FieldSymbol singletonCache;
internal readonly CSharpSyntaxNode ScopeSyntaxOpt;
internal LambdaFrame(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, MethodSymbol topLevelMethod, int overloadOrdinal, CSharpSyntaxNode scopeSyntax, int scopeOrdinal, bool isStatic)
: base(MakeName(slotAllocatorOpt, overloadOrdinal, scopeOrdinal, isStatic), topLevelMethod)
internal LambdaFrame(VariableSlotAllocator slotAllocatorOpt, TypeCompilationState compilationState, MethodSymbol topLevelMethod, int methodOrdinal, CSharpSyntaxNode scopeSyntax, int scopeOrdinal, bool isStatic)
: base(MakeName(slotAllocatorOpt, methodOrdinal, scopeOrdinal, isStatic), topLevelMethod)
{
this.topLevelMethod = topLevelMethod;
this.constructor = new LambdaFrameConstructor(this);
......@@ -45,13 +45,18 @@ internal LambdaFrame(VariableSlotAllocator slotAllocatorOpt, TypeCompilationStat
private static string MakeName(VariableSlotAllocator slotAllocatorOpt, int methodOrdinal, int scopeOrdinal, bool isStatic)
{
// TODO: slotAllocatorOpt?.GetPrevious()
if (isStatic)
{
return GeneratedNames.MakeStaticLambdaDisplayClassName();
// Display class is shared among static non-generic lambdas, method ordinal is -1.
// Generic display classes don't share lambdas and need to include the ordinal to avoid duplicate names.
Debug.Assert(methodOrdinal >= -1);
return GeneratedNames.MakeStaticLambdaDisplayClassName(methodOrdinal);
}
return // TODO: slotAllocatorOpt?.GetPrevious() ??
GeneratedNames.MakeLambdaDisplayClassName(methodOrdinal, scopeOrdinal);
Debug.Assert(methodOrdinal >= 0);
return GeneratedNames.MakeLambdaDisplayClassName(methodOrdinal, scopeOrdinal);
}
[Conditional("DEBUG")]
......
......@@ -328,7 +328,7 @@ private LambdaFrame GetStaticFrame(DiagnosticBag diagnostics, BoundNode lambda)
// therefore could have no syntax.
CSharpSyntaxNode syntax = lambda.Syntax;
this.lazyStaticLambdaFrame = new LambdaFrame(slotAllocatorOpt, CompilationState, topLevelMethod, topLevelMethodOrdinal, syntax, scopeOrdinal: -1, isStatic: true);
this.lazyStaticLambdaFrame = new LambdaFrame(slotAllocatorOpt, CompilationState, topLevelMethod, isNonGeneric ? -1 : topLevelMethodOrdinal, syntax, scopeOrdinal: -1, isStatic: true);
// nongeneric static lambdas can share the frame
if (isNonGeneric)
......@@ -907,20 +907,22 @@ private BoundNode RewriteLambdaConversion(BoundLambda node)
NamedTypeSymbol translatedLambdaContainer;
BoundNode lambdaScope = null;
LambdaFrame containerAsFrame;
ClosureKind closureKind;
if (analysis.lambdaScopes.TryGetValue(node.Symbol, out lambdaScope))
{
translatedLambdaContainer = frames[lambdaScope];
translatedLambdaContainer = containerAsFrame = frames[lambdaScope];
closureKind = ClosureKind.General;
}
else if (analysis.capturedVariablesByLambda[node.Symbol].Count == 0)
{
translatedLambdaContainer = GetStaticFrame(Diagnostics, node);
translatedLambdaContainer = containerAsFrame = GetStaticFrame(Diagnostics, node);
closureKind = ClosureKind.Static;
}
else
{
containerAsFrame = null;
translatedLambdaContainer = topLevelMethod.ContainingType;
closureKind = ClosureKind.ThisOnly;
}
......@@ -964,7 +966,7 @@ private BoundNode RewriteLambdaConversion(BoundLambda node)
framePointers.TryGetValue(translatedLambdaContainer, out innermostFramePointer);
}
if (translatedLambdaContainer.OriginalDefinition is LambdaFrame)
if ((object)containerAsFrame != null)
{
currentTypeParameters = translatedLambdaContainer.TypeParameters;
currentLambdaBodyTypeMap = ((LambdaFrame)translatedLambdaContainer).TypeMap;
......@@ -990,7 +992,6 @@ private BoundNode RewriteLambdaConversion(BoundLambda node)
addedStatements = oldAddedStatements;
// Rewrite the lambda expression (and the enclosing anonymous method conversion) as a delegate creation expression
var containerAsFrame = translatedLambdaContainer as LambdaFrame;
NamedTypeSymbol constructedFrame = (object)containerAsFrame != null ?
translatedLambdaContainer.ConstructIfGeneric(StaticCast<TypeSymbol>.From(currentTypeParameters)) :
translatedLambdaContainer;
......
......@@ -107,14 +107,14 @@ private ImmutableArray<ParameterSymbol> MakeParameters()
var parameters = this.BaseMethodParameters;
foreach (var p in parameters)
{
builder.Add(new SynthesizedParameterSymbol(this, this.TypeMap.SubstituteType(((ParameterSymbol)p.OriginalDefinition).Type), ordinal++, p.RefKind, p.Name));
builder.Add(new SynthesizedParameterSymbol(this, this.TypeMap.SubstituteType(p.OriginalDefinition.Type), ordinal++, p.RefKind, p.Name));
}
return builder.ToImmutableAndFree();
}
public sealed override TypeSymbol ReturnType
{
get { return this.TypeMap.SubstituteType(((MethodSymbol)this.BaseMethod.OriginalDefinition).ReturnType); }
get { return this.TypeMap.SubstituteType(this.BaseMethod.OriginalDefinition.ReturnType); }
}
public sealed override bool IsVararg
......
......@@ -4,9 +4,6 @@
using System.Collections.Immutable;
using System.Globalization;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
......
......@@ -42,9 +42,10 @@ internal static string MakeIteratorFinallyMethodName(int iteratorState)
return "<>m__Finally" + GetString(Math.Abs(iteratorState + 2));
}
internal static string MakeStaticLambdaDisplayClassName()
internal static string MakeStaticLambdaDisplayClassName(int methodOrdinal)
{
return "<>c";
const string prefix = "<>c";
return (methodOrdinal >= 0) ? prefix + GetString(methodOrdinal) : prefix;
}
internal static string MakeLambdaDisplayClassName(int methodOrdinal, int scopeOrdinal)
......
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
/// <summary>
/// A type parameter for a synthesized class or method.
/// </summary>
internal sealed class SynthesizedTypeParameterSymbol : SubstitutedTypeParameterSymbol
internal sealed class SynthesizedSubstitutedTypeParameterSymbol : SubstitutedTypeParameterSymbol
{
public SynthesizedTypeParameterSymbol(Symbol owner, TypeMap map, TypeParameterSymbol substitutedFrom)
public SynthesizedSubstitutedTypeParameterSymbol(Symbol owner, TypeMap map, TypeParameterSymbol substitutedFrom)
: base(owner, map, substitutedFrom)
{
}
......
......@@ -103,7 +103,7 @@ private TypeMap WithAlphaRename(ImmutableArray<TypeParameterSymbol> oldTypeParam
foreach (var tp in oldTypeParameters)
{
var newTp = synthesized ?
new SynthesizedTypeParameterSymbol(newOwner, result, tp) :
new SynthesizedSubstitutedTypeParameterSymbol(newOwner, result, tp) :
new SubstitutedTypeParameterSymbol(newOwner, result, tp);
result.Mapping.Add(tp, newTp);
newTypeParametersBuilder.Add(newTp);
......@@ -122,7 +122,7 @@ internal TypeMap WithAlphaRename(NamedTypeSymbol oldOwner, NamedTypeSymbol newOw
internal TypeMap WithAlphaRename(MethodSymbol oldOwner, Symbol newOwner, out ImmutableArray<TypeParameterSymbol> newTypeParameters)
{
Debug.Assert(oldOwner.ConstructedFrom == oldOwner);
return WithAlphaRename(((MethodSymbol)oldOwner.OriginalDefinition).TypeParameters, newOwner, out newTypeParameters);
return WithAlphaRename(oldOwner.OriginalDefinition.TypeParameters, newOwner, out newTypeParameters);
}
private static SmallDictionary<TypeParameterSymbol, TypeSymbol> ConstructMapping(ImmutableArray<TypeParameterSymbol> from, ImmutableArray<TypeSymbol> to)
......
......@@ -756,5 +756,61 @@ public static async void M()
IL_019c: ldflda ""System.Runtime.CompilerServices.AsyncVoidMethodBuilder Test.<M>d__3.<>t__builder""
", actual);
}
[Fact]
public void ManySynthesizedNames()
{
string source = @"
using System;
using System.Threading.Tasks;
public class C
{
public async Task F()
{
var a1 = await Task.FromResult(default(Tuple<char, char, char>));
var a2 = await Task.FromResult(default(Tuple<char, char, byte>));
var a3 = await Task.FromResult(default(Tuple<char, byte, char>));
var a4 = await Task.FromResult(default(Tuple<char, byte, byte>));
var a5 = await Task.FromResult(default(Tuple<byte, char, char>));
var a6 = await Task.FromResult(default(Tuple<byte, char, byte>));
var a7 = await Task.FromResult(default(Tuple<byte, byte, char>));
var a8 = await Task.FromResult(default(Tuple<byte, byte, byte>));
var b1 = await Task.FromResult(default(Tuple<int, int, int>));
var b2 = await Task.FromResult(default(Tuple<int, int, long>));
var b3 = await Task.FromResult(default(Tuple<int, long, int>));
var b4 = await Task.FromResult(default(Tuple<int, long, long>));
var b5 = await Task.FromResult(default(Tuple<long, int, int>));
var b6 = await Task.FromResult(default(Tuple<long, int, long>));
var b7 = await Task.FromResult(default(Tuple<long, long, int>));
var b8 = await Task.FromResult(default(Tuple<long, long, long>));
}
}";
CompileAndVerify(source, additionalRefs: AsyncRefs, options: TestOptions.ReleaseDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: module =>
{
AssertEx.Equal(new[]
{
"<>1__state",
"<>t__builder",
"<>u__1",
"<>u__2",
"<>u__3",
"<>u__4",
"<>u__5",
"<>u__6",
"<>u__7",
"<>u__8",
"<>u__9",
"<>u__10",
"<>u__11",
"<>u__12",
"<>u__13",
"<>u__14",
"<>u__15",
"<>u__16",
}, module.GetFieldNames("C.<F>d__0"));
});
}
}
}
// Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Test.Utilities;
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
......@@ -937,7 +939,7 @@ static void Main()
}
}";
var verifier = CompileAndVerify(source, expectedOutput: "pass");
verifier.VerifyIL("Program.<>c<T>.<F>b__1_0", @"
verifier.VerifyIL("Program.<>c1<T>.<F>b__1_0", @"
{
// Code size 67 (0x43)
.maxstack 2
......@@ -3831,6 +3833,165 @@ static C()
CompileAndVerify(source);
}
[Fact]
public void GenericStaticFrames()
{
string source = @"
using System;
public class C
{
public static void F<TF>()
{
var f = new Func<TF>(() => default(TF));
}
public static void G<TG>()
{
var f = new Func<TG>(() => default(TG));
}
public static void F<TF1, TF2>()
{
var f = new Func<TF1, TF2>(a => default(TF2));
}
public static void G<TG1, TG2>()
{
var f = new Func<TG1, TG2>(a => default(TG2));
}
}";
CompileAndVerify(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: m =>
{
var c = m.GlobalNamespace.GetMember<NamedTypeSymbol>("C");
AssertEx.Equal(new[]
{
"C.<>c0<TF>",
"C.<>c1<TG>",
"C.<>c2<TF1, TF2>",
"C.<>c3<TG1, TG2>"
}, c.GetMembers().Where(member => member.Kind == SymbolKind.NamedType).Select(member => member.ToString()));
var c0 = c.GetMember<NamedTypeSymbol>("<>c0");
AssertEx.SetEqual(new[]
{
"C.<>c0<TF>.<>9",
"C.<>c0<TF>.<>9__0_0",
"C.<>c0<TF>.<>c0()",
"C.<>c0<TF>.<>c0()",
"C.<>c0<TF>.<F>b__0_0()",
}, c0.GetMembers().Select(member => member.ToString()));
var c1 = c.GetMember<NamedTypeSymbol>("<>c1");
AssertEx.SetEqual(new[]
{
"C.<>c1<TG>.<>9",
"C.<>c1<TG>.<>9__1_0",
"C.<>c1<TG>.<>c1()",
"C.<>c1<TG>.<>c1()",
"C.<>c1<TG>.<G>b__1_0()",
}, c1.GetMembers().Select(member => member.ToString()));
var c2 = c.GetMember<NamedTypeSymbol>("<>c2");
AssertEx.SetEqual(new[]
{
"C.<>c2<TF1, TF2>.<>9",
"C.<>c2<TF1, TF2>.<>9__2_0",
"C.<>c2<TF1, TF2>.<>c2()",
"C.<>c2<TF1, TF2>.<>c2()",
"C.<>c2<TF1, TF2>.<F>b__2_0(TF1)",
}, c2.GetMembers().Select(member => member.ToString()));
var c3 = c.GetMember<NamedTypeSymbol>("<>c3");
AssertEx.SetEqual(new[]
{
"C.<>c3<TG1, TG2>.<>9",
"C.<>c3<TG1, TG2>.<>9__3_0",
"C.<>c3<TG1, TG2>.<>c3()",
"C.<>c3<TG1, TG2>.<>c3()",
"C.<>c3<TG1, TG2>.<G>b__3_0(TG1)",
}, c3.GetMembers().Select(member => member.ToString()));
});
}
[Fact]
public void GenericStaticFramesWithConstraints()
{
string source = @"
using System;
public class C
{
public static void F<TF>() where TF : class
{
var f = new Func<TF>(() => default(TF));
}
public static void G<TG>() where TG : struct
{
var f = new Func<TG>(() => default(TG));
}
}";
CompileAndVerify(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: m =>
{
var c = m.GlobalNamespace.GetMember<NamedTypeSymbol>("C");
AssertEx.Equal(new[]
{
"C.<>c0<TF>",
"C.<>c1<TG>",
}, c.GetMembers().Where(member => member.Kind == SymbolKind.NamedType).Select(member => member.ToString()));
});
}
[Fact]
public void GenericInstance()
{
string source = @"
using System;
public class C
{
public void F<TF>()
{
var f = new Func<TF>(() => { this.F(); return default(TF); });
}
public void G<TG>()
{
var f = new Func<TG>(() => { this.F(); return default(TG); });
}
public void F<TF1, TF2>()
{
var f = new Func<TF1, TF2>(a => { this.F(); return default(TF2); });
}
public void G<TG1, TG2>()
{
var f = new Func<TG1, TG2>(a => { this.F(); return default(TG2); });
}
private void F() {}
}";
CompileAndVerify(source, options: TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator: m =>
{
var c = m.GlobalNamespace.GetMember<NamedTypeSymbol>("C");
AssertEx.SetEqual(new[]
{
"C.F<TF>()",
"C.G<TG>()",
"C.F<TF1, TF2>()",
"C.G<TG1, TG2>()",
"C.F()",
"C.C()",
"C.<F>b__0_0<TF>()",
"C.<G>b__1_0<TG>()",
"C.<F>b__2_0<TF1, TF2>(TF1)",
"C.<G>b__3_0<TG1, TG2>(TG1)",
}, c.GetMembers().Select(member => member.ToString()));
});
}
#region "Regressions"
[WorkItem(539439, "DevDiv")]
......
' Copyright (c) Microsoft Open Technologies, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Roslyn.Test.Utilities
Imports Microsoft.CodeAnalysis.VisualBasic
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Namespace Microsoft.CodeAnalysis.VisualBasic.UnitTests
......@@ -3464,6 +3465,139 @@ end Module
</file>
</compilation>, expectedOutput:="hello")
End Sub
<Fact>
Public Sub GenericStaticFrames()
Dim source =
<compilation>
<file name="a.vb">
Imports System
Public Class C
Shared Sub F(Of TF)()
Dim f = New Func(Of TF)(Function() Nothing)
End Sub
Shared Sub G(Of TG)()
Dim f = New Func(Of TG)(Function() Nothing)
End Sub
Shared Sub F(Of TF1, TF2)()
Dim f = New Func(Of TF1, TF2)(Function(a) Nothing)
End Sub
Shared Sub G(Of TG1, TG2)()
Dim f = New Func(Of TG1, TG2)(Function(a) Nothing)
End Sub
End Class
</file>
</compilation>
CompileAndVerify(source, options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator:=
Sub(m)
Dim c = m.GlobalNamespace.GetMember(Of NamedTypeSymbol)("C")
AssertEx.Equal({
"C._Closure$__1(Of $CLS0)",
"C._Closure$__4(Of $CLS0)",
"C._Closure$__7(Of $CLS0, $CLS1)",
"C._Closure$__10(Of $CLS0, $CLS1)"
}, c.GetMembers().Where(Function(member) member.Kind = SymbolKind.NamedType).Select(Function(member) member.ToString()))
Dim c0 = c.GetMember(Of NamedTypeSymbol)("_Closure$__1")
AssertEx.SetEqual({
"Public Shared ReadOnly $I As C._Closure$__1(Of $CLS0)",
"Public Shared _ClosureCache$__3 As System.Func(Of $CLS0)",
"Public Sub New()",
"Private Shared Sub New()",
"Friend Function _Lambda$__2() As $CLS0"
}, c0.GetMembers().Select(Function(member) member.ToString()))
Dim c1 = c.GetMember(Of NamedTypeSymbol)("_Closure$__4")
AssertEx.SetEqual({
"Public Shared ReadOnly $I As C._Closure$__4(Of $CLS0)",
"Public Shared _ClosureCache$__6 As System.Func(Of $CLS0)",
"Public Sub New()",
"Private Shared Sub New()",
"Friend Function _Lambda$__5() As $CLS0"
}, c1.GetMembers().Select(Function(member) member.ToString()))
Dim c2 = c.GetMember(Of NamedTypeSymbol)("_Closure$__7")
AssertEx.SetEqual({
"Public Shared ReadOnly $I As C._Closure$__7(Of $CLS0, $CLS1)",
"Public Shared _ClosureCache$__9 As System.Func(Of $CLS0, $CLS1)",
"Public Sub New()",
"Private Shared Sub New()",
"Friend Function _Lambda$__8(a As $CLS0) As $CLS1"
}, c2.GetMembers().Select(Function(member) member.ToString()))
Dim c3 = c.GetMember(Of NamedTypeSymbol)("_Closure$__10")
AssertEx.SetEqual({
"Public Shared ReadOnly $I As C._Closure$__10(Of $CLS0, $CLS1)",
"Public Shared _ClosureCache$__12 As System.Func(Of $CLS0, $CLS1)",
"Public Sub New()",
"Private Shared Sub New()",
"Friend Function _Lambda$__11(a As $CLS0) As $CLS1"
}, c3.GetMembers().Select(Function(member) member.ToString()))
End Sub)
End Sub
<Fact>
Public Sub GenericInstance()
Dim source =
<compilation>
<file name="a.vb">
Imports System
Public Class C
Sub F(Of TF)()
Dim f = New Func(Of TF)(Function()
Me.F()
Return Nothing
End Function)
End Sub
Sub G(Of TG)()
Dim f = New Func(Of TG)(Function()
Me.F()
Return Nothing
End Function)
End Sub
Sub F(Of TF1, TF2)()
Dim f = New Func(Of TF1, TF2)(Function(a)
Me.F()
Return Nothing
End Function)
End Sub
Sub G(Of TG1, TG2)()
Dim f = New Func(Of TG1, TG2)(Function(a)
Me.F()
Return Nothing
End Function)
End Sub
Sub F()
End Sub
End Class
</file>
</compilation>
CompileAndVerify(source, options:=TestOptions.DebugDll.WithMetadataImportOptions(MetadataImportOptions.All), symbolValidator:=
Sub(m)
Dim c = m.GlobalNamespace.GetMember(Of NamedTypeSymbol)("C")
AssertEx.SetEqual({
"Public Sub New()",
"Public Sub F(Of TF)()",
"Public Sub G(Of TG)()",
"Public Sub F(Of TF1, TF2)()",
"Public Sub G(Of TG1, TG2)()",
"Public Sub F()",
"Private Function _Lambda$__1(Of $CLS0)() As $CLS0",
"Private Function _Lambda$__2(Of $CLS0)() As $CLS0",
"Private Function _Lambda$__3(Of $CLS0, $CLS1)(a As $CLS0) As $CLS1",
"Private Function _Lambda$__4(Of $CLS0, $CLS1)(a As $CLS0) As $CLS1"
}, c.GetMembers().Select(Function(member) member.ToString()))
End Sub)
End Sub
End Class
End Namespace
......@@ -244,7 +244,7 @@ private static bool SequenceEqual<T>(IEnumerable<T> expected, IEnumerable<T> act
return true;
}
public static void SetEqual<T>(IEnumerable<T> expected, IEnumerable<T> actual, IEqualityComparer<T> comparer = null, string message = null, string itemSeparator = ", ")
public static void SetEqual<T>(IEnumerable<T> expected, IEnumerable<T> actual, IEqualityComparer<T> comparer = null, string message = null, string itemSeparator = "\r\n")
{
var expectedSet = new HashSet<T>(expected, comparer);
var result = expected.Count() == actual.Count() && expectedSet.SetEquals(actual);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册