From 84634257ec9f419a9454e028378b7d07899ee930 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 27 Sep 2024 11:09:27 +0200 Subject: [PATCH 1/4] string operator always returning nonNull --- src/FSharp.Core/prim-types.fs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/FSharp.Core/prim-types.fs b/src/FSharp.Core/prim-types.fs index e1f093e13eb..7c5f12f764d 100644 --- a/src/FSharp.Core/prim-types.fs +++ b/src/FSharp.Core/prim-types.fs @@ -890,11 +890,16 @@ namespace Microsoft.FSharp.Core for m = 0 to len4 - 1 do SetArray4D dst (src1+i) (src2+j) (src3+k) (src4+m) (GetArray4D src i j k m) + let inline defaultIfNull (defaultStr:string) x = + match x with + | null -> defaultStr + | nonNullString -> nonNullString + let inline anyToString nullStr x = match box x with - | :? IFormattable as f -> f.ToString(null, CultureInfo.InvariantCulture) + | :? IFormattable as f -> defaultIfNull nullStr (f.ToString(null, CultureInfo.InvariantCulture)) | null -> nullStr - | _ -> x.ToString() + | _ -> defaultIfNull nullStr (x.ToString()) let anyToStringShowingNull x = anyToString "null" x @@ -5200,8 +5205,8 @@ namespace Microsoft.FSharp.Core when 'T : Guid = let x = (# "" value : Guid #) in x.ToString(null, CultureInfo.InvariantCulture) when 'T struct = match box value with - | :? IFormattable as f -> f.ToString(null, CultureInfo.InvariantCulture) - | _ -> value.ToString() + | :? IFormattable as f -> defaultIfNull "" (f.ToString(null, CultureInfo.InvariantCulture)) + | _ -> defaultIfNull "" (value.ToString()) // other common mscorlib reference types when 'T : StringBuilder = @@ -5210,7 +5215,7 @@ namespace Microsoft.FSharp.Core when 'T : IFormattable = if value = unsafeDefault<'T> then "" - else let x = (# "" value : IFormattable #) in x.ToString(null, CultureInfo.InvariantCulture) + else let x = (# "" value : IFormattable #) in defaultIfNull "" (x.ToString(null, CultureInfo.InvariantCulture)) [] [] From da41d3b0b29f61029a19afb969718a86448fd8fe Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 15 Oct 2024 11:19:52 +0200 Subject: [PATCH 2/4] release notes --- docs/release-notes/.FSharp.Core/9.0.200.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 docs/release-notes/.FSharp.Core/9.0.200.md diff --git a/docs/release-notes/.FSharp.Core/9.0.200.md b/docs/release-notes/.FSharp.Core/9.0.200.md new file mode 100644 index 00000000000..c53ccabe7e3 --- /dev/null +++ b/docs/release-notes/.FSharp.Core/9.0.200.md @@ -0,0 +1,8 @@ +### Fixed + +### Added + +### Changed +* String function changed to guarantee a non-nullable string return type ([PR #17809](https://github.com/dotnet/fsharp/pull/17809)) + +### Breaking Changes \ No newline at end of file From 09039d35330536868141ad7de57471b5452f1f3b Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 7 Nov 2024 11:38:23 +0100 Subject: [PATCH 3/4] Update docs/release-notes/.FSharp.Core/9.0.200.md Co-authored-by: Petr Pokorny --- docs/release-notes/.FSharp.Core/9.0.200.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Core/9.0.200.md b/docs/release-notes/.FSharp.Core/9.0.200.md index 6a586306233..2ea077abe4b 100644 --- a/docs/release-notes/.FSharp.Core/9.0.200.md +++ b/docs/release-notes/.FSharp.Core/9.0.200.md @@ -5,7 +5,8 @@ ### Added ### Changed -* String function changed to guarantee a non-nullable string return type ([PR #17809](https://github.com/dotnet/fsharp/pull/17809)) +* String function changed to guarantee a non-null string return type ([PR #17809](https://github.com/dotnet/fsharp/pull/17809)) + ### Breaking Changes From 4b43621d6c635560ae7e3142b8ea555e37eb60a4 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 7 Nov 2024 12:21:44 +0100 Subject: [PATCH 4/4] tests added --- .../FSharp.Core/OperatorsModule2.fs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/FSharp.Core.UnitTests/FSharp.Core/OperatorsModule2.fs b/tests/FSharp.Core.UnitTests/FSharp.Core/OperatorsModule2.fs index 57647ead9ed..f2dc93d9ee9 100644 --- a/tests/FSharp.Core.UnitTests/FSharp.Core/OperatorsModule2.fs +++ b/tests/FSharp.Core.UnitTests/FSharp.Core/OperatorsModule2.fs @@ -872,6 +872,15 @@ type OperatorsModule2() = let result = Operators.string 123.456M Assert.AreEqual("123.456", result) + let result = Operators.string { new obj () with override _.ToString () = null } + Assert.AreEqual("", result) + + let result = Operators.string { new obj () with override _.ToString () = Operators.string null } + Assert.AreEqual("", result) + + let result = Operators.string { new IFormattable with override _.ToString (_, _) = null } + Assert.AreEqual("", result) + // Following tests ensure that InvariantCulture is used if type implements IFormattable // safe current culture, then switch culture