From f57d1e35be919bbe859d7f612892a4c6cf639c65 Mon Sep 17 00:00:00 2001 From: Andrii Kurdiumov Date: Fri, 4 Aug 2023 11:07:30 +0600 Subject: [PATCH] Add warning for interpolated strings where type is not given By default warning is off. https://github.com/fsharp/fslang-suggestions/issues/1285#issuecomment-1660296244 --- src/Compiler/Checking/CheckFormatStrings.fs | 2 + src/Compiler/Driver/CompilerDiagnostics.fs | 3 +- src/Compiler/FSComp.txt | 1 + src/Compiler/xlf/FSComp.txt.cs.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.de.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.es.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.fr.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.it.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.ja.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.ko.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.pl.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.ru.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.tr.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 5 +++ src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 5 +++ .../TypedInterpolatedStringsTests.fs | 38 +++++++++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + 18 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypedInterpolatedStringsTests.fs diff --git a/src/Compiler/Checking/CheckFormatStrings.fs b/src/Compiler/Checking/CheckFormatStrings.fs index ea15e196fbd..ec52131c0f5 100644 --- a/src/Compiler/Checking/CheckFormatStrings.fs +++ b/src/Compiler/Checking/CheckFormatStrings.fs @@ -458,6 +458,8 @@ let parseFormatStringInternal // residue of hole "...{n}..." in interpolated strings become %P(...) | 'P' when isInterpolated -> + let (code, message) = FSComp.SR.alwaysUseTypedStringInterpolation() + warning(DiagnosticWithText(code, message, m)) checkOtherFlags ch let i = requireAndSkipInterpolationHoleFormat (i+1) // Note, the fragCol doesn't advance at all as these are magically inserted. diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index ee8949ba1ca..46548c6a0de 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -377,13 +377,14 @@ type PhasedDiagnostic with | 1182 -> false // chkUnusedValue - off by default | 3180 -> false // abImplicitHeapAllocation - off by default | 3186 -> false // pickleMissingDefinition - off by default - | 3366 -> false //tcIndexNotationDeprecated - currently off by default + | 3366 -> false // tcIndexNotationDeprecated - currently off by default | 3517 -> false // optFailedToInlineSuggestedValue - off by default | 3388 -> false // tcSubsumptionImplicitConversionUsed - off by default | 3389 -> false // tcBuiltInImplicitConversionUsed - off by default | 3390 -> false // xmlDocBadlyFormed - off by default | 3395 -> false // tcImplicitConversionUsedForMethodArg - off by default | 3559 -> false // typrelNeverRefinedAwayFromTop - off by default + | 3579 -> false // alwaysUseTypedStringInterpolation - off by default | _ -> match x.Exception with | DiagnosticEnabledWithLanguageFeature (_, _, _, enabled) -> enabled diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index dfbda7e7b67..ffb8dc30cde 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1721,3 +1721,4 @@ featureAccessorFunctionShorthand,"underscore dot shorthand for accessor only fun 3577,tcOverrideUsesMultipleArgumentsInsteadOfTuple,"This override takes a tuple instead of multiple arguments. Try to add an additional layer of parentheses at the method definition (e.g. 'member _.Foo((x, y))'), or remove parentheses at the abstract method declaration (e.g. 'abstract member Foo: 'a * 'b -> 'c')." featureUnmanagedConstraintCsharpInterop,"Interop between C#'s and F#'s unmanaged generic constraint (emit additional modreq)" 3578,chkCopyUpdateSyntaxInAnonRecords,"This expression is an anonymous record, use {{|...|}} instead of {{...}}." +3579,alwaysUseTypedStringInterpolation,"Prefer to use typed interpolated strings over untyped one." \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 2ff15cd7a6b..2eb14d28ba4 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n Všechny prvky pole musí být implicitně převoditelné na typ prvního elementu, což je řazená kolekce členů o délce {0} typu\n {1} \nTento element je řazená kolekce členů o délce {2} typu\n {3} \n diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 08236b18246..4da0cbd6d19 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n Alle Elemente eines Arrays müssen implizit in den Typ des ersten Elements konvertiert werden. Hierbei handelt es sich um ein Tupel der Länge {0} vom Typ\n {1} \nDieses Element ist ein Tupel der Länge {2} vom Typ\n {3}. \n diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index fd837db386c..570e8bba9e9 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n Todos los elementos de una matriz deben convertirse implícitamente en el tipo del primer elemento, que aquí es una tupla de longitud {0} de tipo\n {1} \nEste elemento es una tupla de longitud {2} de tipo\n {3} \n diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 1587b7f10e0..53a1c041925 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n Tous les éléments d’un tableau doivent être implicitement convertibles en type du premier élément, qui est ici un tuple de longueur {0} de type\n {1} \nCet élément est un tuple de longueur {2} de type\n {3} \n diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index bb92fad9b00..f5f06615715 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n Tutti gli elementi di una matrice devono essere convertibili in modo implicito nel tipo del primo elemento, che qui è una tupla di lunghezza {0} di tipo\n {1} \nQuesto elemento è una tupla di lunghezza {2} di tipo\n {3} \n diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index c59b5a2abf4..e255b82cebc 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n 配列のすべての要素は、最初の要素の型に暗黙的に変換できる必要があります。これは、型の長さ {0} のタプルです\n {1} \nこの要素は、型の長さ {2} のタプルです\n {3} \n diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 782b1fe4b22..051afa592d8 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n 배열의 모든 요소는 첫 번째 요소의 형식으로 암시적으로 변환할 수 있어야 합니다. 여기서는 형식이 \n {1}이고 길이가 {0}인 튜플입니다. \n이 요소는 형식이 \n {3}이고 길이가 {2}인 튜플입니다. \n diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 26e1c6498bc..23c9550605b 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n Wszystkie elementy tablicy muszą być niejawnie konwertowalne na typ pierwszego elementu, który w tym miejscu jest krotką o długości {0} typu\n {1} \nTen element jest krotką o długości {2} typu\n {3} \n diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index afe6de384ca..f4d655cd9de 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n Todos os elementos de uma matriz devem ser implicitamente conversíveis ao tipo do primeiro elemento, que aqui é uma tupla de comprimento {0} do tipo\n {1} \nEste elemento é uma tupla de comprimento {2} do tipo\n {3} \n diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index a6b7ccdcfd6..91036312db2 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n Все элементы массива должны поддерживать неявное преобразование в тип первого элемента, который здесь является кортежем длиной {0} типа\n {1} \nЭтот элемент является кортежем длиной {2} типа\n {3} \n diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index f2b50c00ba5..ddf07370ab1 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n Bir dizinin tüm öğeleri örtük olarak ilk öğenin türüne dönüştürülebilir olmalıdır. Burada ilk öğe {0} uzunluğunda türü\n {1} \nolan bir demet. Bu öğe ise {2} uzunluğunda türü\n {3} \nolan bir demet. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 1f63fdbae98..a0b71a3bdde 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n 数组的所有元素必须可隐式转换为第一个元素的类型,这是一个长度为 {0} 的类型的元组\n {1} \n此元素是长度为 {2} 类型的元组\n {3} \n diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 5771d206cfd..90976b61fed 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -2,6 +2,11 @@ + + Prefer to use typed interpolated strings over untyped one. + Prefer to use typed interpolated strings over untyped one. + + All elements of an array must be implicitly convertible to the type of the first element, which here is a tuple of length {0} of type\n {1} \nThis element is a tuple of length {2} of type\n {3} \n 陣列的所有元素必須以隱含方式轉換成第一個元素的類型,這是類型為\n {1} \n的元組長度 {0}此元素是類型為\n {3} \n的元組長度{2} diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypedInterpolatedStringsTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypedInterpolatedStringsTests.fs new file mode 100644 index 00000000000..c3d41587ac0 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypedInterpolatedStringsTests.fs @@ -0,0 +1,38 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace ErrorMessages + +open Xunit +open FSharp.Test.Compiler + +module ``Typed interpolated strings`` = + + [] + let ``Untyped interpolated strings produce warning``() = + FSharp """ +let hello = "Hello World" +printf $"{hello}" + """ + |> withWarnOn 3579 + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 3579, Line 3, Col 8, Line 3, Col 18, "Prefer to use typed interpolated strings over untyped one.") + + [] + let ``Do not warn on untyped interpolated strings by default``() = + FSharp """ +let hello = "Hello World" +printf $"{hello}" + """ + |> typecheck + |> shouldSucceed + + [] + let ``Typed interpolated strings over interpolated one``() = + FSharp """ +let hello = "Hello World" +printf $"%s{hello}" + """ + |> withWarnOn 3579 + |> typecheck + |> shouldSucceed diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index ef20cb82400..af09e1f3879 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -143,6 +143,7 @@ +