diff --git a/src/fsharp/FSharp.Core/prim-types.fs b/src/fsharp/FSharp.Core/prim-types.fs index 6f619b045b3f..0aba6593b02d 100644 --- a/src/fsharp/FSharp.Core/prim-types.fs +++ b/src/fsharp/FSharp.Core/prim-types.fs @@ -4509,7 +4509,10 @@ namespace Microsoft.FSharp.Core [] let inline string (value: 'T) = anyToString "" value - when 'T : string = (# "" value : string #) // force no-op + + when 'T : string = + if value = unsafeDefault<'T> then "" + else (# "" value : string #) // force no-op // Using 'let x = (# ... #) in x.ToString()' leads to better IL, without it, an extra stloc and ldloca.s (get address-of) // gets emitted, which are unnecessary. With it, the extra address-of-variable is not created diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/OperatorsModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/OperatorsModule2.fs index e821b4b88356..3a7cc87778db 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/OperatorsModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/OperatorsModule2.fs @@ -740,6 +740,20 @@ type OperatorsModule2() = [] member _.string() = + + let result = Operators.string null + Assert.AreEqual("", result) + + let nullStr:string = null + let result = Operators.string nullStr + Assert.AreEqual("", result) + + let result = Operators.string null + Assert.AreEqual("", result) + + let result = Operators.string (null:string) + Assert.AreEqual("", result) + // value type let result = Operators.string 100 Assert.AreEqual("100", result)