From 1c340628f01538596fb8c02e5f85bff8c20c5358 Mon Sep 17 00:00:00 2001 From: kerams Date: Fri, 4 Jun 2021 12:46:36 +0200 Subject: [PATCH 1/4] Optimize interpolated string with no holes --- src/fsharp/CheckExpressions.fs | 42 +++++++++++-------- .../EmittedIL/StringFormatAndInterpolation.fs | 28 +++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + 3 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs diff --git a/src/fsharp/CheckExpressions.fs b/src/fsharp/CheckExpressions.fs index 7487225f33..6c6355b5bd 100644 --- a/src/fsharp/CheckExpressions.fs +++ b/src/fsharp/CheckExpressions.fs @@ -6739,27 +6739,35 @@ and TcInterpolatedStringExpr cenv overallTy env m tpenv (parts: SynInterpolatedS UnifyTypes cenv env m printerTupleTy printerTupleTyRequired - // Type check the expressions filling the holes - let flexes = argTys |> List.map (fun _ -> false) - let fillExprs, tpenv = TcExprs cenv env m tpenv flexes argTys synFillExprs + if List.isEmpty synFillExprs then + let str = mkString g m printfFormatString - let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m) - - let argsExpr = mkArray (g.obj_ty, fillExprsBoxed, m) - let percentATysExpr = - if percentATys.Length = 0 then - mkNull m (mkArrayType g g.system_Type_ty) + if isString then + str, tpenv else - let tyExprs = percentATys |> Array.map (mkCallTypeOf g m) |> Array.toList - mkArray (g.system_Type_ty, tyExprs, m) + mkCallNewFormat cenv.g m printerTy printerArgTy printerResidueTy printerResultTy printerTupleTy str, tpenv + else + // Type check the expressions filling the holes + let flexes = argTys |> List.map (fun _ -> false) + let fillExprs, tpenv = TcExprs cenv env m tpenv flexes argTys synFillExprs - let fmtExpr = MakeMethInfoCall cenv.amap m newFormatMethod [] [mkString g m printfFormatString; argsExpr; percentATysExpr] + let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m) - if isString then - // Make the call to sprintf - mkCall_sprintf g m printerTy fmtExpr [], tpenv - else - fmtExpr, tpenv + let argsExpr = mkArray (g.obj_ty, fillExprsBoxed, m) + let percentATysExpr = + if percentATys.Length = 0 then + mkNull m (mkArrayType g g.system_Type_ty) + else + let tyExprs = percentATys |> Array.map (mkCallTypeOf g m) |> Array.toList + mkArray (g.system_Type_ty, tyExprs, m) + + let fmtExpr = MakeMethInfoCall cenv.amap m newFormatMethod [] [mkString g m printfFormatString; argsExpr; percentATysExpr] + + if isString then + // Make the call to sprintf + mkCall_sprintf g m printerTy fmtExpr [], tpenv + else + fmtExpr, tpenv // The case for $"..." used as type FormattableString or IFormattable | Choice2Of2 createFormattableStringMethod -> diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs new file mode 100644 index 0000000000..dc9c963531 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs @@ -0,0 +1,28 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace FSharp.Compiler.ComponentTests.EmittedIL + +open Xunit +open FSharp.Test.Utilities.Compiler + +module ``StringFormatAndInterpolation`` = + [] + let ``Interpolated string with no holes is reduced to a string or simple format when used in printf``() = + FSharp """ +module StringFormatAndInterpolation + +let stringOnly () = $"no hole" + +let printed () = printf $"printed no hole" + """ + |> compile + |> shouldSucceed + |> verifyIL [""" +IL_0000: ldstr "no hole" +IL_0005: ret""" + """ +IL_0000: ldstr "printed no hole" +IL_0005: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string) +IL_000a: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormat(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4) +IL_000f: pop +IL_0010: ret"""] diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 912181214b..a3ac88c1c9 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -23,6 +23,7 @@ + From 58beb889043cacd1fed5ceeb01087af3f2f6d678 Mon Sep 17 00:00:00 2001 From: kerams Date: Fri, 4 Jun 2021 13:32:11 +0200 Subject: [PATCH 2/4] Fix test --- .../EmittedIL/StringFormatAndInterpolation.fs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs index dc9c963531..7e99e82110 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs @@ -18,11 +18,12 @@ let printed () = printf $"printed no hole" |> compile |> shouldSucceed |> verifyIL [""" -IL_0000: ldstr "no hole" -IL_0005: ret""" - """ IL_0000: ldstr "printed no hole" IL_0005: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string) -IL_000a: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormat(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4) -IL_000f: pop -IL_0010: ret"""] +IL_000a: stloc.0 +IL_000b: call class [netstandard]System.IO.TextWriter [netstandard]System.Console::get_Out() +IL_0010: ldloc.0 +IL_0011: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatToTextWriter(class [runtime]System.IO.TextWriter, + class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4) +IL_0016: pop +IL_0017: ret"""] From 37983fbaaea58d09a05648d7dea790c92dd9e7aa Mon Sep 17 00:00:00 2001 From: kerams Date: Fri, 4 Jun 2021 14:02:16 +0200 Subject: [PATCH 3/4] . --- .../EmittedIL/StringFormatAndInterpolation.fs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs index 7e99e82110..716568cf83 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/StringFormatAndInterpolation.fs @@ -18,6 +18,9 @@ let printed () = printf $"printed no hole" |> compile |> shouldSucceed |> verifyIL [""" +IL_0000: ldstr "no hole" +IL_0005: ret""" + """ IL_0000: ldstr "printed no hole" IL_0005: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5::.ctor(string) IL_000a: stloc.0 From a2653522b7e9a42f87f6866b613e36de8934bbcc Mon Sep 17 00:00:00 2001 From: kerams Date: Tue, 29 Jun 2021 14:00:07 +0200 Subject: [PATCH 4/4] Add interpolated string quotation tests --- tests/fsharp/core/quotes/test.fsx | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/fsharp/core/quotes/test.fsx b/tests/fsharp/core/quotes/test.fsx index 6415c466a6..35d1a057b4 100644 --- a/tests/fsharp/core/quotes/test.fsx +++ b/tests/fsharp/core/quotes/test.fsx @@ -4119,6 +4119,19 @@ module CheckEliminatedConstructs = """IfThenElse (Call (None, op_Equality, [ValueWithName ([||], ts), Value ()]), Value (true), Value (false))""" +module Interpolation = + let interpolatedNoHoleQuoted = <@ $"abc" @> + let actual1 = interpolatedNoHoleQuoted.ToString() + checkStrings "brewbreebrwhat1" actual1 """Value ("abc")""" + + let interpolatedWithLiteralQuoted = <@ $"abc {1} def" @> + let actual2 = interpolatedWithLiteralQuoted.ToString() + checkStrings "brewbreebrwhat2" actual2 + """Call (None, PrintFormatToString, + [NewObject (PrintfFormat`5, Value ("abc %P() def"), + NewArray (Object, Call (None, Box, [Value (1)])), + Value ())])""" + module TestAssemblyAttributes = let attributes = System.Reflection.Assembly.GetExecutingAssembly().GetCustomAttributes(false)