Browse Source

Fix #888: [3.0 Preview 1] F# code decompiles to ... unoptimal C#

pull/1243/head
Siegfried Pammer 7 years ago
parent
commit
e6fa143ef1
  1. 20
      ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
  2. 112
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs
  3. 109
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs

20
ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs

@ -118,15 +118,17 @@ namespace ICSharpCode.Decompiler.Tests
Run(); Run();
} }
[Test, Ignore("?")] [Test]
public void FSharpLoops_Debug() public void FSharpLoops_Debug()
{ {
CopyFSharpCoreDll();
Run(settings: new DecompilerSettings { RemoveDeadCode = true }); Run(settings: new DecompilerSettings { RemoveDeadCode = true });
} }
[Test, Ignore("?")] [Test]
public void FSharpLoops_Release() public void FSharpLoops_Release()
{ {
CopyFSharpCoreDll();
Run(settings: new DecompilerSettings { RemoveDeadCode = true }); Run(settings: new DecompilerSettings { RemoveDeadCode = true });
} }
@ -140,5 +142,19 @@ namespace ICSharpCode.Decompiler.Tests
CodeAssert.FilesAreEqual(csFile, decompiled); CodeAssert.FilesAreEqual(csFile, decompiled);
} }
static readonly object copyLock = new object();
static void CopyFSharpCoreDll()
{
lock (copyLock) {
if (File.Exists(Path.Combine(TestCasePath, "FSharp.Core.dll")))
return;
string fsharpCoreDll = Path.Combine(TestCasePath, "..\\..\\..\\ILSpy-tests\\FSharp\\FSharp.Core.dll");
if (!File.Exists(fsharpCoreDll))
Assert.Ignore("Ignored because of missing ILSpy-tests repo. Must be checked out separately from https://github.com/icsharpcode/ILSpy-tests!");
File.Copy(fsharpCoreDll, Path.Combine(TestCasePath, "FSharp.Core.dll"));
}
}
} }
} }

112
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Debug.cs

@ -18,91 +18,84 @@ using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
[assembly: FSharpInterfaceDataVersion(2, 0, 0)] [assembly: FSharpInterfaceDataVersion(2, 0, 0)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: AssemblyTitle("ConsoleApplication1")] [assembly: AssemblyTitle("ConsoleApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication1")] [assembly: AssemblyProduct("ConsoleApplication1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: Guid("e0674ff5-5e8f-4d4e-a88f-e447192454c7")] [assembly: Guid("e0674ff5-5e8f-4d4e-a88f-e447192454c7")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations)]
[assembly: AssemblyVersion("1.0.0.0")]
[CompilationMapping(SourceConstructFlags.Module)] [CompilationMapping(SourceConstructFlags.Module)]
public static class Program public static class Program
{ {
[Serializable] [Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
[CompilationMapping(SourceConstructFlags.Closure)] [CompilationMapping(SourceConstructFlags.Closure)]
internal sealed class disposable@3 : IDisposable internal sealed class disposable_00403 : IDisposable
{ {
public disposable@3() public disposable_00403()
{ {
((object)this)..ctor(); ((object)this)._002Ector();
} }
private void System-IDisposable-Dispose() private void System_002DIDisposable_002DDispose()
{ {
} }
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
//ILSpy generated this explicit interface implementation from .override directive in System-IDisposable-Dispose //ILSpy generated this explicit interface implementation from .override directive in System-IDisposable-Dispose
this.System-IDisposable-Dispose(); this.System_002DIDisposable_002DDispose();
} }
} }
[Serializable] [Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
[CompilationMapping(SourceConstructFlags.Closure)] [CompilationMapping(SourceConstructFlags.Closure)]
internal sealed class getSeq@5 : GeneratedSequenceBase<int> internal sealed class getSeq_00405 : GeneratedSequenceBase<int>
{ {
[DebuggerNonUserCode]
[DebuggerBrowsable(DebuggerBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated] [CompilerGenerated]
[DebuggerNonUserCode]
public int pc = pc; public int pc = pc;
[DebuggerNonUserCode]
[DebuggerBrowsable(DebuggerBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated] [CompilerGenerated]
[DebuggerNonUserCode]
public int current = current; public int current = current;
public getSeq@5(int pc, int current) public getSeq_00405(int pc, int current)
{ {
} }
public override int GenerateNext(ref IEnumerable<int> next) public override int GenerateNext(ref IEnumerable<int> next)
{ {
switch (this.pc) switch (pc) {
{
default: default:
this.pc = 1; pc = 1;
this.current = 1; current = 1;
return 1; return 1;
case 1: case 1:
this.pc = 2; pc = 2;
break; break;
case 2: case 2:
break; break;
} }
this.current = 0; current = 0;
return 0; return 0;
} }
public override void Close() public override void Close()
{ {
this.pc = 2; pc = 2;
} }
public override bool get_CheckClose() public override bool get_CheckClose()
{ {
switch (this.pc) switch (pc) {
{
default: default:
return false; return false;
case 0: case 0:
@ -111,29 +104,29 @@ public static class Program
} }
} }
[CompilerGenerated]
[DebuggerNonUserCode] [DebuggerNonUserCode]
[CompilerGenerated]
public override int get_LastGenerated() public override int get_LastGenerated()
{ {
return this.current; return current;
} }
[CompilerGenerated]
[DebuggerNonUserCode] [DebuggerNonUserCode]
[CompilerGenerated]
public override IEnumerator<int> GetFreshEnumerator() public override IEnumerator<int> GetFreshEnumerator()
{ {
return new getSeq@5(0, 0); return new getSeq_00405(0, 0);
} }
} }
public static IDisposable disposable() public static IDisposable disposable()
{ {
return new disposable@3(); return new disposable_00403();
} }
public static IEnumerable<int> getSeq() public static IEnumerable<int> getSeq()
{ {
return new getSeq@5(0, 0); return new getSeq_00405(0, 0);
} }
public static FSharpList<int> getList() public static FSharpList<int> getList()
@ -143,8 +136,7 @@ public static class Program
public static int[] getArray() public static int[] getArray()
{ {
return new int[1] return new int[1] {
{
1 1
}; };
} }
@ -152,56 +144,40 @@ public static class Program
[EntryPoint] [EntryPoint]
public static int main(string[] argv) public static int main(string[] argv)
{ {
IDisposable disposable = default(IDisposable); IDisposable disposable;
using (Program.disposable()) using (Program.disposable()) {
{
Console.WriteLine("Hello 1"); Console.WriteLine("Hello 1");
disposable = Program.disposable(); disposable = Program.disposable();
} }
using (disposable) using (disposable) {
{ IEnumerable<int> seq = getSeq();
IEnumerable<int> seq = Program.getSeq(); foreach (int item in seq) {
using (IEnumerator<int> enumerator = seq.GetEnumerator()) Console.WriteLine(item);
{
while (true)
{
if (!enumerator.MoveNext())
break;
int k = enumerator.Current;
Console.WriteLine(k);
}
} }
FSharpList<int> fSharpList = Program.getList(); FSharpList<int> fSharpList = getList();
FSharpList<int> tailOrNull = fSharpList.TailOrNull; for (FSharpList<int> tailOrNull = fSharpList.TailOrNull; tailOrNull != null; tailOrNull = fSharpList.TailOrNull) {
while (true) int headOrDefault = fSharpList.HeadOrDefault;
{ Console.WriteLine(headOrDefault);
if (tailOrNull == null)
break;
int j = fSharpList.HeadOrDefault;
Console.WriteLine(j);
fSharpList = tailOrNull; fSharpList = tailOrNull;
tailOrNull = fSharpList.TailOrNull;
} }
int[] array = Program.getArray(); int[] array = getArray();
for (int l = 0; l < array.Length; l++) foreach (int value in array) {
{ Console.WriteLine(value);
int i = array[l];
Console.WriteLine(i);
} }
return 0; return 0;
} }
} }
} }
namespace <StartupCode$ConsoleApplication1> namespace _003CStartupCode_0024ConsoleApplication1_003E
{ {
internal static class $Program internal static class _0024Program
{ {
} }
internal static class $AssemblyInfo internal static class _0024AssemblyInfo
{ {
} }
} }
namespace <StartupCode$ConsoleApplication1>.$.NETFramework,Version=v4.6.1 namespace _003CStartupCode_0024ConsoleApplication1_003E._0024.NETFramework_002CVersion_003Dv4._6._1
{ {
internal static class AssemblyAttributes internal static class AssemblyAttributes
{ {

109
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/FSharpLoops_Release.cs

@ -18,91 +18,84 @@ using System.Runtime.InteropServices;
using System.Runtime.Versioning; using System.Runtime.Versioning;
[assembly: FSharpInterfaceDataVersion(2, 0, 0)] [assembly: FSharpInterfaceDataVersion(2, 0, 0)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: AssemblyTitle("ConsoleApplication1")] [assembly: AssemblyTitle("ConsoleApplication1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")] [assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ConsoleApplication1")] [assembly: AssemblyProduct("ConsoleApplication1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.6.1", FrameworkDisplayName = ".NET Framework 4.6.1")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCopyright("Copyright © 2017")] [assembly: AssemblyCopyright("Copyright © 2017")]
[assembly: AssemblyTrademark("")] [assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")] [assembly: AssemblyCulture("")]
[assembly: ComVisible(false)] [assembly: ComVisible(false)]
[assembly: Guid("e0674ff5-5e8f-4d4e-a88f-e447192454c7")] [assembly: Guid("e0674ff5-5e8f-4d4e-a88f-e447192454c7")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.None)]
[assembly: AssemblyVersion("1.0.0.0")]
[CompilationMapping(SourceConstructFlags.Module)] [CompilationMapping(SourceConstructFlags.Module)]
public static class Program public static class Program
{ {
[Serializable] [Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
[CompilationMapping(SourceConstructFlags.Closure)] [CompilationMapping(SourceConstructFlags.Closure)]
internal sealed class disposable@3 : IDisposable internal sealed class disposable_00403 : IDisposable
{ {
public disposable@3() public disposable_00403()
{ {
((object)this)..ctor(); ((object)this)._002Ector();
} }
private void System-IDisposable-Dispose() private void System_002DIDisposable_002DDispose()
{ {
} }
void IDisposable.Dispose() void IDisposable.Dispose()
{ {
//ILSpy generated this explicit interface implementation from .override directive in System-IDisposable-Dispose //ILSpy generated this explicit interface implementation from .override directive in System-IDisposable-Dispose
this.System-IDisposable-Dispose(); this.System_002DIDisposable_002DDispose();
} }
} }
[Serializable] [Serializable]
[StructLayout(LayoutKind.Auto, CharSet = CharSet.Auto)]
[CompilationMapping(SourceConstructFlags.Closure)] [CompilationMapping(SourceConstructFlags.Closure)]
internal sealed class getSeq@5 : GeneratedSequenceBase<int> internal sealed class getSeq_00405 : GeneratedSequenceBase<int>
{ {
[DebuggerNonUserCode]
[DebuggerBrowsable(DebuggerBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated] [CompilerGenerated]
[DebuggerNonUserCode]
public int pc = pc; public int pc = pc;
[DebuggerNonUserCode]
[DebuggerBrowsable(DebuggerBrowsableState.Never)] [DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated] [CompilerGenerated]
[DebuggerNonUserCode]
public int current = current; public int current = current;
public getSeq@5(int pc, int current) public getSeq_00405(int pc, int current)
{ {
} }
public override int GenerateNext(ref IEnumerable<int> next) public override int GenerateNext(ref IEnumerable<int> next)
{ {
switch (this.pc) switch (pc) {
{
default: default:
this.pc = 1; pc = 1;
this.current = 1; current = 1;
return 1; return 1;
case 1: case 1:
this.pc = 2; pc = 2;
break; break;
case 2: case 2:
break; break;
} }
this.current = 0; current = 0;
return 0; return 0;
} }
public override void Close() public override void Close()
{ {
this.pc = 2; pc = 2;
} }
public override bool get_CheckClose() public override bool get_CheckClose()
{ {
switch (this.pc) switch (pc) {
{
default: default:
return false; return false;
case 0: case 0:
@ -111,29 +104,29 @@ public static class Program
} }
} }
[CompilerGenerated]
[DebuggerNonUserCode] [DebuggerNonUserCode]
[CompilerGenerated]
public override int get_LastGenerated() public override int get_LastGenerated()
{ {
return this.current; return current;
} }
[CompilerGenerated]
[DebuggerNonUserCode] [DebuggerNonUserCode]
[CompilerGenerated]
public override IEnumerator<int> GetFreshEnumerator() public override IEnumerator<int> GetFreshEnumerator()
{ {
return new getSeq@5(0, 0); return new getSeq_00405(0, 0);
} }
} }
public static IDisposable disposable() public static IDisposable disposable()
{ {
return new disposable@3(); return new disposable_00403();
} }
public static IEnumerable<int> getSeq() public static IEnumerable<int> getSeq()
{ {
return new getSeq@5(0, 0); return new getSeq_00405(0, 0);
} }
public static FSharpList<int> getList() public static FSharpList<int> getList()
@ -143,8 +136,7 @@ public static class Program
public static int[] getArray() public static int[] getArray()
{ {
return new int[1] return new int[1] {
{
1 1
}; };
} }
@ -152,57 +144,42 @@ public static class Program
[EntryPoint] [EntryPoint]
public static int main(string[] argv) public static int main(string[] argv)
{ {
IDisposable disposable = default(IDisposable); IDisposable disposable;
using (Program.disposable()) using (Program.disposable()) {
{
Console.WriteLine("Hello 1"); Console.WriteLine("Hello 1");
disposable = Program.disposable(); disposable = Program.disposable();
} }
using (disposable) using (disposable) {
{ IEnumerable<int> seq = getSeq();
IEnumerable<int> seq = Program.getSeq(); foreach (int item in seq) {
using (IEnumerator<int> enumerator = seq.GetEnumerator()) Console.WriteLine(item);
{
while (true)
{
if (!enumerator.MoveNext())
break;
Console.WriteLine(enumerator.Current);
}
} }
FSharpList<int> fSharpList = FSharpList<int>.Cons(1, FSharpList<int>.Empty); FSharpList<int> fSharpList = FSharpList<int>.Cons(1, FSharpList<int>.Empty);
FSharpList<int> tailOrNull = fSharpList.TailOrNull; for (FSharpList<int> tailOrNull = fSharpList.TailOrNull; tailOrNull != null; tailOrNull = fSharpList.TailOrNull) {
while (true) int headOrDefault = fSharpList.HeadOrDefault;
{ Console.WriteLine(headOrDefault);
if (tailOrNull == null)
break;
int j = fSharpList.HeadOrDefault;
Console.WriteLine(j);
fSharpList = tailOrNull; fSharpList = tailOrNull;
tailOrNull = fSharpList.TailOrNull;
} }
int[] array = new int[1] int[] array = new int[1] {
{
1 1
}; };
for (int j = 0; j < array.Length; j++) for (int headOrDefault = 0; headOrDefault < array.Length; headOrDefault++) {
{ Console.WriteLine(array[headOrDefault]);
Console.WriteLine(array[j]);
} }
return 0; return 0;
} }
} }
} }
namespace <StartupCode$ConsoleApplication1> namespace _003CStartupCode_0024ConsoleApplication1_003E
{ {
internal static class $Program internal static class _0024Program
{ {
} }
internal static class $AssemblyInfo internal static class _0024AssemblyInfo
{ {
} }
} }
namespace <StartupCode$ConsoleApplication1>.$.NETFramework,Version=v4.6.1 namespace _003CStartupCode_0024ConsoleApplication1_003E._0024.NETFramework_002CVersion_003Dv4._6._1
{ {
internal static class AssemblyAttributes internal static class AssemblyAttributes
{ {

Loading…
Cancel
Save