diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md index e7d1bd2e1bf..58769fd111e 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md @@ -17,6 +17,8 @@ ### Added +* Added warning FS3882 when a function or delegate value is used as an interpolated string argument. ([PR #19289](https://github.com/dotnet/fsharp/pull/19289)) + ### Changed * Centralized product TFM (Target Framework Moniker) into MSBuild props file `eng/TargetFrameworks.props`. Changing the target framework now only requires editing one file, and it integrates with MSBuild's `--getProperty` for scripts. diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index 62dd231d664..4c455ab35d7 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -1,5 +1,7 @@ ### Added +* Warn (FS3882) when a function or delegate value is used as an interpolated string argument, since it will be formatted via `ToString` rather than being applied. ([PR #19289](https://github.com/dotnet/fsharp/pull/19289)) + ### Fixed ### Changed \ No newline at end of file diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 3d93b2c526d..6c15df8f024 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -7466,6 +7466,15 @@ and TcFormatStringExpr cenv (overallTy: OverallTy) env m tpenv (fmtString: strin ) /// Check an interpolated string expression +and [] warnForFunctionValuesInFillExprs (g: TcGlobals) argTys synFillExprs = + match argTys, synFillExprs with + | argTy :: restTys, (synFillExpr: SynExpr) :: restExprs -> + if isFunTy g argTy || isDelegateTy g argTy then + warning (Error(FSComp.SR.tcFunctionValueUsedAsInterpolatedStringArg (), synFillExpr.Range)) + + warnForFunctionValuesInFillExprs g restTys restExprs + | _ -> () + and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: SynInterpolatedStringPart list) = let g = cenv.g @@ -7615,6 +7624,9 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn // Type check the expressions filling the holes let fillExprs, tpenv = TcExprsNoFlexes cenv env m tpenv argTys synFillExprs + if g.langVersion.SupportsFeature LanguageFeature.WarnWhenFunctionValueUsedAsInterpolatedStringArg then + warnForFunctionValuesInFillExprs g argTys synFillExprs + // Take all interpolated string parts and typed fill expressions // and convert them to typed expressions that can be used as args to System.String.Concat // return an empty list if there are some format specifiers that make lowering to not applicable @@ -7684,6 +7696,9 @@ and TcInterpolatedStringExpr cenv (overallTy: OverallTy) env m tpenv (parts: Syn // Type check the expressions filling the holes let fillExprs, tpenv = TcExprsNoFlexes cenv env m tpenv argTys synFillExprs + if g.langVersion.SupportsFeature LanguageFeature.WarnWhenFunctionValueUsedAsInterpolatedStringArg then + warnForFunctionValuesInFillExprs g argTys synFillExprs + let fillExprsBoxed = (argTys, fillExprs) ||> List.map2 (mkCallBox g m) let dotnetFormatStringExpr = mkString g m dotnetFormatString diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index b39bf210809..e082feb5a1e 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1803,5 +1803,7 @@ featureAllowLetOrUseBangTypeAnnotationWithoutParens,"Allow let! and use! type an 3878,tcAttributeIsNotValidForUnionCaseWithFields,"This attribute is not valid for use on union cases with fields." 3879,xmlDocNotFirstOnLine,"XML documentation comments should be the first non-whitespace text on a line." featureReturnFromFinal,"Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder." +featureWarnWhenFunctionValueUsedAsInterpolatedStringArg,"Warn when a function value is used as an interpolated string argument" 3880,optsLangVersionOutOfSupport,"Language version '%s' is out of support. The last .NET SDK supporting it is available at https://dotnet.microsoft.com/en-us/download/dotnet/%s" -3881,optsUnrecognizedLanguageFeature,"Unrecognized language feature name: '%s'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'." \ No newline at end of file +3881,optsUnrecognizedLanguageFeature,"Unrecognized language feature name: '%s'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'." +3882,tcFunctionValueUsedAsInterpolatedStringArg,"This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments." \ No newline at end of file diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 9fb00722263..c4a5daa83dd 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -104,6 +104,7 @@ type LanguageFeature = | ErrorOnInvalidDeclsInTypeDefinitions | AllowTypedLetUseAndBang | ReturnFromFinal + | WarnWhenFunctionValueUsedAsInterpolatedStringArg /// LanguageVersion management type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) = @@ -245,6 +246,7 @@ type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) // F# 11.0 // Put stabilized features here for F# 11.0 previews via .NET SDK preview channels + LanguageFeature.WarnWhenFunctionValueUsedAsInterpolatedStringArg, languageVersion110 // Difference between languageVersion110 and preview - 11.0 gets turned on automatically by picking a preview .NET 11 SDK // previewVersion is only when "preview" is specified explicitly in project files and users also need a preview SDK @@ -440,6 +442,8 @@ type LanguageVersion(versionText, ?disabledFeaturesArray: LanguageFeature array) | LanguageFeature.ErrorOnInvalidDeclsInTypeDefinitions -> FSComp.SR.featureErrorOnInvalidDeclsInTypeDefinitions () | LanguageFeature.AllowTypedLetUseAndBang -> FSComp.SR.featureAllowLetOrUseBangTypeAnnotationWithoutParens () | LanguageFeature.ReturnFromFinal -> FSComp.SR.featureReturnFromFinal () + | LanguageFeature.WarnWhenFunctionValueUsedAsInterpolatedStringArg -> + FSComp.SR.featureWarnWhenFunctionValueUsedAsInterpolatedStringArg () /// Get a version string associated with the given feature. static member GetFeatureVersionString feature = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 09cb4273571..2f57e9b0b2b 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -95,6 +95,7 @@ type LanguageFeature = | ErrorOnInvalidDeclsInTypeDefinitions | AllowTypedLetUseAndBang | ReturnFromFinal + | WarnWhenFunctionValueUsedAsInterpolatedStringArg /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/Service/FSharpProjectSnapshot.fs b/src/Compiler/Service/FSharpProjectSnapshot.fs index e385cfda204..73bc8597430 100644 --- a/src/Compiler/Service/FSharpProjectSnapshot.fs +++ b/src/Compiler/Service/FSharpProjectSnapshot.fs @@ -101,7 +101,7 @@ type FSharpFileSnapshot(FileName: string, Version: string, GetSource: unit -> Ta task { match! f fileName |> Async.StartAsTask with | Some source -> return SourceTextNew.ofISourceText source - | None -> return failwith $"Couldn't get source for file {f}" + | None -> return failwith $"Couldn't get source for file {fileName}" } ) diff --git a/src/Compiler/Utilities/DependencyGraph.fs b/src/Compiler/Utilities/DependencyGraph.fs index f36e8ac29d4..c3870e66b58 100644 --- a/src/Compiler/Utilities/DependencyGraph.fs +++ b/src/Compiler/Utilities/DependencyGraph.fs @@ -329,7 +329,7 @@ type GraphExtensions = static member Unpack(node: 'NodeValue, unpacker) = match unpacker node with | Some value -> value - | None -> failwith $"Expected {unpacker} but got: {node}" + | None -> failwith $"Expected unpacker to match but got: {node}" [] static member UnpackOne(dependencies: 'NodeValue seq, unpacker: 'NodeValue -> 'UnpackedDependency option) = @@ -337,14 +337,14 @@ type GraphExtensions = |> Seq.tryExactlyOne |> Option.bind unpacker |> Option.defaultWith (fun () -> - failwith $"Expected exactly one dependency matching {unpacker} but got: %A{dependencies |> Seq.toArray}") + failwith $"Expected exactly one dependency matching unpacker but got: %A{dependencies |> Seq.toArray}") [] static member UnpackMany(dependencies: 'NodeValue seq, unpacker) = let results = dependencies |> Seq.choose unpacker if dependencies |> Seq.length <> (results |> Seq.length) then - failwith $"Expected all dependencies to match {unpacker} but got: %A{dependencies |> Seq.toArray}" + failwith $"Expected all dependencies to match unpacker but got: %A{dependencies |> Seq.toArray}" results @@ -361,7 +361,7 @@ type GraphExtensions = | None, None -> extras.Add dependency |> ignore match oneResult with - | None -> failwith $"Expected exactly one dependency matching {oneUnpacker} but didn't find any" + | None -> failwith $"Expected exactly one dependency matching oneUnpacker but didn't find any" | Some head -> if extras.Count > 0 then failwith $"Found extra dependencies: %A{extras.ToArray()}" diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 85dbf4dd95c..47f00246d3a 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type Sdílení podkladových polí v rozlišeném sjednocení [<Struct>] za předpokladu, že mají stejný název a typ @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Nerozpoznaná hodnota {0} pro parametr --langversion; seznam možností zobrazíte zadáním --langversion:? diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 370e248e1d6..49393a98488 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type Teilen sie zugrunde liegende Felder in einen [<Struct>]-diskriminierten Union, solange sie denselben Namen und Typ aufweisen. @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Unbekannter Wert "{0}" für "--langversion". Verwenden Sie "--langversion:?", um die vollständige Liste anzuzeigen. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index c760506b835..5a5852ad173 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type Compartir campos subyacentes en una unión discriminada [<Struct>] siempre y cuando tengan el mismo nombre y tipo @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Valor no reconocido "{0}" para --langversion, use --langversion:? para una lista completa diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 94935d998ff..acf333f1ab2 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type Partager les champs sous-jacents dans une union discriminée [<Struct>] tant qu’ils ont le même nom et le même type @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Valeur non reconnue '{0}' pour --langversion use --langversion:? pour la liste complète diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index e83cb026ed3..7835e6d2472 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type Condividi i campi sottostanti in un'unione discriminata di [<Struct>] purché abbiano lo stesso nome e tipo @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Valore '{0}' non riconosciuto per --langversion. Per l'elenco completo usare --langversion:? diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 9888850c875..daea914e7ad 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type 名前と型が同じである限り、[<Struct>] 判別可能な共用体で基になるフィールドを共有する @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list --langversion の値 '{0}' が認識されません。完全なリストについては、--langversion:? を使用してください diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 433af22b44b..41f81d8ff68 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type 이름과 형식이 같으면 [<Struct>] 구분된 공용 구조체에서 기본 필드 공유 @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list 전체 목록에 대한 --langversion use --langversion:?의 인식할 수 없는 값 '{0}'입니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 8d167f8c5c4..bd570d212db 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type Udostępnij pola źródłowe w unii rozłącznej [<Struct>], o ile mają taką samą nazwę i ten sam typ @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Nierozpoznana wartość „{0}” dla parametru –langversion; podaj parametr –langversion:?, aby uzyskać pełną listę diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 872af8ca069..7ac4656907f 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type Compartilhar campos subjacentes em uma união discriminada [<Struct>], desde que tenham o mesmo nome e tipo @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Valor não reconhecido '{0}' para --langversion use --langversion:? para a lista completa diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 940bcf5df31..47ae941c039 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type Совместное использование базовых полей в дискриминируемом объединении [<Struct>], если они имеют одинаковое имя и тип. @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list Не удалось распознать значение "{0}" для параметра --langversion. Для получения полного списка допустимых значений выполните команду use --langversion:? diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 28576ca243d..9cc384e53c5 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type Aynı ada ve türe sahip oldukları sürece temel alınan alanları [<Struct>] ayırt edici birleşim biçiminde paylaşın @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list --langversion için '{0}' değeri tanınmıyor. Tam liste için --langversion:? kullanın diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 6c459b3f33c..d57d65524e4 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type 只要它们具有相同的名称和类型,即可在 [<Struct>] 中共享基础字段 @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list --langversion 的值“{0}”无法识别,使用 --langversion:? 获取完整列表。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 296ef8fa7de..d4fb703248d 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -607,6 +607,11 @@ Support for ReturnFromFinal/YieldFromFinal in computation expressions to enable tailcall optimization when available on the builder. + + Warn when a function value is used as an interpolated string argument + Warn when a function value is used as an interpolated string argument + + Share underlying fields in a [<Struct>] discriminated union as long as they have same name and type 只要 [<Struct>] 具有相同名稱和類型,就以強制聯集共用基礎欄位 @@ -1082,6 +1087,11 @@ Unrecognized language feature name: '{0}'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'. + + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments. + + Unrecognized value '{0}' for --langversion use --langversion:? for complete list 對 --langversion 為無法識別的值 '{0}',對完整清單使用 --langversion:? diff --git a/tests/FSharp.Compiler.ComponentTests/Language/InterpolatedStringsTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/InterpolatedStringsTests.fs index e7c18f0d679..0f7a2523aeb 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/InterpolatedStringsTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/InterpolatedStringsTests.fs @@ -181,4 +181,162 @@ printfn "%%s" (System.Globalization.CultureInfo "en-US" |> x.ToString) """ |> compileExeAndRun |> shouldSucceed - |> withStdOutContains "abcde" \ No newline at end of file + |> withStdOutContains "abcde" + + [] + let ``Warn when lambda is used as interpolated string argument`` () = + Fsx """ +let f = fun x -> x + 1 +let s = $"{f}" + """ + |> withLangVersionPreview + |> compile + |> shouldFail + |> withSingleDiagnostic (Warning 3882, Line 3, Col 12, Line 3, Col 13, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + + [] + let ``Warn when underscore dot shorthand is used as interpolated string argument`` () = + Fsx """ +type R = { Name: string } +let r = { Name = "hello" } +let s = $"{_.Name}" : string + """ + |> withLangVersionPreview + |> compile + |> shouldFail + |> withSingleDiagnostic (Warning 3882, Line 4, Col 12, Line 4, Col 18, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + + [] + let ``Warn when partially applied function is used as interpolated string argument`` () = + Fsx """ +let add x y = x + y +let s = $"{add 1}" + """ + |> withLangVersionPreview + |> compile + |> shouldFail + |> withSingleDiagnostic (Warning 3882, Line 3, Col 12, Line 3, Col 17, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + + [] + let ``Warn when named function is used as interpolated string argument`` () = + Fsx """ +let myFunc (x: int) = string x +let s = $"result: {myFunc}" + """ + |> withLangVersionPreview + |> compile + |> shouldFail + |> withSingleDiagnostic (Warning 3882, Line 3, Col 20, Line 3, Col 26, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + + [] + let ``No warn when non-function value is used as interpolated string argument`` () = + Fsx """ +let x = 42 +let s1 = $"{x}" +let s2 = $"{System.DateTime.Now}" + """ + |> withLangVersionPreview + |> compile + |> shouldSucceed + + [] + let ``No warn when function is applied in interpolated string argument`` () = + Fsx """ +let f x = x + 1 +let s = $"{f 42}" + """ + |> withLangVersionPreview + |> compile + |> shouldSucceed + + [] + let ``No warn for function value in interpolated string with older language version`` () = + Fsx """ +let f = fun x -> x + 1 +let s = $"{f}" + """ + |> withLangVersion10 + |> compile + |> shouldSucceed + + [] + let ``Warn when multiple function values are used in interpolated string`` () = + Fsx """ +let f x = x + 1 +let g x = x * 2 +let s = $"{f} and {g}" + """ + |> withLangVersionPreview + |> compile + |> shouldFail + |> withDiagnostics [ + (Warning 3882, Line 4, Col 12, Line 4, Col 13, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + (Warning 3882, Line 4, Col 20, Line 4, Col 21, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + ] + + [] + let ``Warn for function value in FormattableString interpolated string`` () = + Fsx """ +let f x = x + 1 +let s : System.FormattableString = $"{f}" + """ + |> withLangVersionPreview + |> compile + |> shouldFail + |> withSingleDiagnostic (Warning 3882, Line 3, Col 39, Line 3, Col 40, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + + [] + let ``Warn for function value with format specifier in interpolated string`` () = + Fsx """ +let f x = x + 1 +let s = $"{f:N2}" + """ + |> withLangVersionPreview + |> compile + |> shouldFail + |> withDiagnostics [ + (Warning 3882, Line 3, Col 12, Line 3, Col 13, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + ] + + [] + let ``Warn can be suppressed with nowarn`` () = + Fsx """ +#nowarn "3882" +let f x = x + 1 +let s = $"{f}" + """ + |> withLangVersionPreview + |> compile + |> shouldSucceed + + [] + let ``Warn when System.Action delegate is used as interpolated string argument`` () = + Fsx """ +let a = System.Action(fun () -> ()) +let s = $"{a}" + """ + |> withLangVersionPreview + |> compile + |> shouldFail + |> withSingleDiagnostic (Warning 3882, Line 3, Col 12, Line 3, Col 13, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + + [] + let ``Warn when System.Func delegate is used as interpolated string argument`` () = + Fsx """ +let f = System.Func(fun x -> string x) +let s = $"{f}" + """ + |> withLangVersionPreview + |> compile + |> shouldFail + |> withSingleDiagnostic (Warning 3882, Line 3, Col 12, Line 3, Col 13, "This expression is a function value. When used in an interpolated string it will be formatted using its 'ToString' method, which is likely not the intended behavior. Consider applying the function to its arguments.") + + [] + let ``No warn when delegate is invoked in interpolated string argument`` () = + Fsx """ +let f = System.Func(fun x -> string x) +let s = $"{f.Invoke(42)}" + """ + |> withLangVersionPreview + |> compile + |> shouldSucceed \ No newline at end of file