dotnet / dotnet/fsharp

Implicit boxing produces extraneous closure

Open
#12,546 1 comment 0 reactions 0 assignees View on GitHub
Area-Compiler-CodeGen Feature Improvement
Dominant language
F#
Stars
4.3k
Forks
876
Avg merge
4d 11h
Merged PRs (30d)
131

Description

**Repro steps**

Minimized repro ([sharplab](https://sharplab.io/#v2:DYLgZgzgPgtg9gEwK7AKYAIBic4FgBQBaALumDugBRwBGI6tAVgJToC86NcAHpWEgDsqrALQA+BjQB0AFTgBlYgCcAlgIDmlZqxAB+CZUErS49BGVr1zAkVSl1cLezIUARAAsVrgkA==)):

```fsharp
module Foo

let foo (ob: obj) = box(fun () -> ob.ToString()) :?> (unit -> string)

let go() = foo "hi"
```

**Expected behavior**

A single closure should be allocated.

**Actual behavior**

A second, extraneous closure is allocated that simply wraps the first. Here is the decompiled C# for that closure from sharplab:

```csharp
[Serializable]
internal sealed class go@5 : FSharpFunc
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
[CompilerGenerated]
[DebuggerNonUserCode]
public FSharpFunc clo1;

[CompilerGenerated]
[DebuggerNonUserCode]
internal go@5(FSharpFunc clo1)
{
this.clo1 = clo1;
}

public override string Invoke(Unit arg10)
{
return clo1.Invoke(arg10);
}
}
```

**Known workarounds**

Explicitly boxing the argument doesn't produce the extra closure ([sharplab](https://sharplab.io/#v2:DYLgZgzgPgtg9gEwK7AKYAIBic4FgBQBaALumDugBRwBGI6tAVgJToC86NcAHpWEgDsqrALQA+BjQB0AFTgBlYgCcAlgIDmlZqxAB+CZUErS49BGVr1zAkVSl1cLezI5KXbugBEACxWfmQA=)):

```fsharp
module Foo

let foo (ob: obj) = box(fun () -> ob.ToString()) :?> (unit -> string)

let go() = foo(box "hi")
```

**Related information**

Provide any related information (optional):

* Operating system
* .NET Runtime kind (.NET Core, .NET Framework, Mono)
* Editing Tools (e.g. Visual Studio Version, Visual Studio)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.