From e9576a2b21b33b5f0b7ad2f140ec901e58054035 Mon Sep 17 00:00:00 2001 From: "Kevin Ransom (msft)" Date: Thu, 14 Dec 2023 12:25:31 -0800 Subject: [PATCH 01/10] merge (#16427) --- .../.FSharp.Compiler.Service/8.0.200.md | 1 + src/Compiler/AbstractIL/ilwrite.fs | 20 ++++++-- src/Compiler/FSComp.txt | 3 +- 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 ++ .../EmittedIL/VeryLargeClasses.fs | 50 +++++++++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + tests/FSharp.Test.Utilities/CompilerAssert.fs | 2 +- tests/FSharp.Test.Utilities/TestFramework.fs | 5 +- tests/service/ScriptOptionsTests.fs | 4 +- 21 files changed, 141 insertions(+), 10 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/EmittedIL/VeryLargeClasses.fs diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md index f77a4a7613f..09463d94484 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md @@ -2,6 +2,7 @@ * Miscellaneous fixes to parentheses analysis. ([PR #16262](https://github.com/dotnet/fsharp/pull/16262), [PR #16391](https://github.com/dotnet/fsharp/pull/16391), [PR #16370](https://github.com/dotnet/fsharp/pull/16370), [PR #16395](https://github.com/dotnet/fsharp/pull/16395)) * Correctly handle assembly imports with public key token of 0 length. ([Issue #16359](https://github.com/dotnet/fsharp/issues/16359), [PR #16363](https://github.com/dotnet/fsharp/pull/16363)) +* Fix #16398 - The dotnet framework has a limit of ~64K methods in a single class. Introduce a compile-time error if any class has over approx 64K methods in generated IL ### Added * Raise a new error when interfaces with auto properties are implemented on constructor-less types. ([PR #16352](https://github.com/dotnet/fsharp/pull/16352)) diff --git a/src/Compiler/AbstractIL/ilwrite.fs b/src/Compiler/AbstractIL/ilwrite.fs index 5c007513153..f41c8aaa08d 100644 --- a/src/Compiler/AbstractIL/ilwrite.fs +++ b/src/Compiler/AbstractIL/ilwrite.fs @@ -50,6 +50,13 @@ let emitBytesViaBuffer f = use bb = ByteBuffer.Create EmitBytesViaBufferCapacity /// Alignment and padding let align alignment n = ((n + alignment - 1) / alignment) * alignment + +/// Maximum number of methods in a dotnet type +/// This differs from the spec and file formats slightly which suggests 0xfffe is the maximum +/// this value was identified empirically. +[] +let maximumMethodsPerDotNetType = 0xfff0 + //--------------------------------------------------------------------- // Concrete token representations etc. used in PE files //--------------------------------------------------------------------- @@ -672,8 +679,14 @@ let GetTypeNameAsElemPair cenv n = //===================================================================== let rec GenTypeDefPass1 enc cenv (tdef: ILTypeDef) = - ignore (cenv.typeDefs.AddUniqueEntry "type index" (fun (TdKey (_, n)) -> n) (TdKey (enc, tdef.Name))) - GenTypeDefsPass1 (enc@[tdef.Name]) cenv (tdef.NestedTypes.AsList()) + ignore (cenv.typeDefs.AddUniqueEntry "type index" (fun (TdKey (_, n)) -> n) (TdKey (enc, tdef.Name))) + + // Verify that the typedef contains fewer than maximumMethodsPerDotNetType + let count = tdef.Methods.AsArray().Length + if count > maximumMethodsPerDotNetType then + errorR(Error(FSComp.SR.tooManyMethodsInDotNetTypeWritingAssembly (tdef.Name, count, maximumMethodsPerDotNetType), rangeStartup)) + + GenTypeDefsPass1 (enc@[tdef.Name]) cenv (tdef.NestedTypes.AsList()) and GenTypeDefsPass1 enc cenv tdefs = List.iter (GenTypeDefPass1 enc cenv) tdefs @@ -682,7 +695,8 @@ and GenTypeDefsPass1 enc cenv tdefs = List.iter (GenTypeDefPass1 enc cenv) tdefs //===================================================================== let rec GetIdxForTypeDef cenv key = - try cenv.typeDefs.GetTableEntry key + try + cenv.typeDefs.GetTableEntry key with :? KeyNotFoundException -> let (TdKey (enc, n) ) = key diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index d0fad76ab36..46fd02464da 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1738,4 +1738,5 @@ featureReuseSameFieldsInStructUnions,"Share underlying fields in a [] di 3860,chkStaticMembersOnObjectExpressions,"Object expressions cannot implement interfaces with static abstract members or declare static members." 3861,chkTailCallAttrOnNonRec,"The TailCall attribute should only be applied to recursive functions." 3862,parsStaticMemberImcompleteSyntax,"Incomplete declaration of a static construct. Use 'static let','static do','static member' or 'static val' for declaration." -3863,parsExpectingField,"Expecting record field" \ No newline at end of file +3863,parsExpectingField,"Expecting record field" +3864,tooManyMethodsInDotNetTypeWritingAssembly,"The type '%s' has too many methods. Found: '%d', maximum: '%d'" \ 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 07cccc56186..20ffb4de64a 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -1457,6 +1457,11 @@ Deklarování \"interfaces with static abstract methods\" (rozhraní se statickými abstraktními metodami) je pokročilá funkce. Pokyny najdete v https://aka.ms/fsharp-iwsams. Toto upozornění můžete zakázat pomocí #nowarn \"3535\" nebo '--nowarn:3535'. + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. Člen rozhraní {0} nemá nejvíce specifickou implementaci. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index d9def2b9c6a..6844c4ebe7b 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -1457,6 +1457,11 @@ Das Deklarieren von \"Schnittstellen mit statischen abstrakten Methoden\" ist ein erweitertes Feature. Anleitungen finden Sie unter https://aka.ms/fsharp-iwsams. Sie können diese Warnung deaktivieren, indem Sie „#nowarn \"3535\"“ or „--nowarn:3535“ verwenden. + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. Der Schnittstellenmember "{0}" weist keine spezifischste Implementierung auf. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 6a6959dc583..797d8231cfd 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -1457,6 +1457,11 @@ Declarar \"interfaces con métodos abstractos estáticos\" es una característica avanzada. Consulte https://aka.ms/fsharp-iwsams para obtener instrucciones. Puede deshabilitar esta advertencia con "#nowarn \"3535\"" o "--nowarn:3535". + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. El miembro de interfaz "{0}" no tiene una implementación más específica. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 8bf1b97e9bc..c3a07f32303 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -1457,6 +1457,11 @@ La déclaration de \"interfaces with static abstract methods\" est une fonctionnalité avancée. Consultez https://aka.ms/fsharp-iwsams pour obtenir de l’aide. Vous pouvez désactiver cet avertissement à l’aide de '#nowarn \"3535\"' or '--nowarn:3535'. + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. Le membre d'interface '{0}' n'a pas l'implémentation la plus spécifique. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 135dbc86cf4..1bbd6f3a48e 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -1457,6 +1457,11 @@ La dichiarazione di \"interfaces with static abstract methods\" è una funzionalità avanzata. Per indicazioni, vedere https://aka.ms/fsharp-iwsams. È possibile disabilitare questo avviso usando '#nowarn \"3535\"' o '--nowarn:3535'. + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. Il membro di interfaccia '{0}' non contiene un'implementazione più specifica. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index c4e1d71a82f..254548c4d61 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -1457,6 +1457,11 @@ \"interfaces with static abstract method\" の宣言は高度な機能です。ガイダンスについては https://aka.ms/fsharp-iwsams を参照してください。この警告は、'#nowarn \"3535\"' または '--nowarn:3535' を使用して無効にできます。 + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. インターフェイス メンバー '{0}' には最も固有な実装がありません。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 4751ad79ebc..f9fbab289f2 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -1457,6 +1457,11 @@ \"interfaces with static abstract methods\"를 선언하는 것은 고급 기능입니다. 지침은 https://aka.ms/fsharp-iwsams를 참조하세요. '#nowarn \"3535\"' 또는 '--nowarn:3535'를 사용하여 이 경고를 비활성화할 수 있습니다. + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. 인터페이스 멤버 '{0}'에 가장 한정적인 구현이 없습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 81d62979a4e..075f8c0cc06 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -1457,6 +1457,11 @@ Deklarowanie \"interfejsów ze statycznymi metodami abstrakcyjnymi\" jest funkcją zaawansowaną. Aby uzyskać wskazówki, zobacz https://aka.ms/fsharp-iwsams. To ostrzeżenie można wyłączyć przy użyciu polecenia „#nowarn \"3535\"" lub "--nowarn:3535”. + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. Składowa interfejsu „{0}” nie ma najbardziej specyficznej implementacji. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 8cdbcdb29c4..2fc380b9748 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -1457,6 +1457,11 @@ Declarando \"interfaces com métodos abstratos estáticos\" é um recurso avançado. Consulte https://aka.ms/fsharp-iwsams para obter diretrizes. Você pode desabilitar esse aviso usando '#nowarn \"3535\"' ou '--nowarn:3535'. + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. O membro de interface '{0}' não tem uma implementação mais específica. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 1319210fbc9..85f28ad43be 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -1457,6 +1457,11 @@ Объявление \"интерфейсов со статическими абстрактными методами\" является расширенной функцией. См. руководство на https://aka.ms/fsharp-iwsams. Это предупреждение можно отключить с помощью используя "#nowarn \"3535\"" or "--nowarn:3535". + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. Элемент интерфейса "{0}" не имеет наиболее конкретной реализации. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index d9143a0db5d..843ad544e09 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -1457,6 +1457,11 @@ \"interfaces with static abstract methods\" bildirimi gelişmiş bir özelliktir. Rehber için bkz. https://aka.ms/fsharp-iwsams. '#nowarn \"3535\"' veya '--nowarn:3535'. kullanarak bu uyarıyı devre dışı bırakabilirsiniz. + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. '{0}' arabirim üyesinin en belirgin uygulaması yok. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index c62c1e73f6c..9c5c4fc8857 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -1457,6 +1457,11 @@ 声明“使用静态抽象方法的接口”是一项高级功能。有关指南,请参阅 https://aka.ms/fsharp-iwsams。可以使用 "#nowarn \"3535\"' 或 '--nowarn:3535' 禁用此警告。 + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. 接口成员“{0}”没有最具体的实现。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 5f66fcae4ea..6992ddfd8b6 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -1457,6 +1457,11 @@ 使用「靜態抽象方法宣告介面」是進階的功能。請參閱 https://aka.ms/fsharp-iwsams 以尋求指引。您可以使用 '#nowarn \"3535\"' 或 '--nowarn:3535' 來停用此警告。 + + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + The type '{0}' has too many methods. Found: '{1}', maximum: '{2}' + + Interface member '{0}' does not have a most specific implementation. 介面成員 '{0}' 沒有最具體的實作。 diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/VeryLargeClasses.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/VeryLargeClasses.fs new file mode 100644 index 00000000000..f8924fca551 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/VeryLargeClasses.fs @@ -0,0 +1,50 @@ +namespace EmittedIL + +open Microsoft.FSharp.Core +open Xunit +open FSharp.Test.Compiler + +module VeryLargeClasses = + + let classWithManyMethods n = + let methods = + let mutable source = "" + for i = 0 to n - 1 do + source <- source + $""" + static member Method%05x{i}() = () """ + source + + FSharp + $""" + namespace VeryLargeClassesTestcases + + type Type1 ={methods} + """ + + [] + let ``More than 64K Methods -- should fail`` () = + classWithManyMethods (1024 * 64 + 1) + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 3864, Line 1, Col 1, Line 1, Col 1, "The type 'VeryLargeClassesTestcases.Type1' has too many methods. Found: '65537', maximum: '65520'") + ] + + [] + let ``Exactly (0xfff0) Methods -- should succeed`` () = + FSharp + """ +module MyMain +open System +open System.Reflection +do printfn $"location: {typeof.Assembly.Location}" +let asm = Assembly.LoadFrom(typeof.Assembly.Location) +printfn $"asm: {asm}" +let types = asm.GetTypes() +printfn "length: {types.Length}" +""" + |> withReferences [ classWithManyMethods 0xfff0 |> asLibrary ] + |> asExe + |> compileAndRun + |> shouldSucceed + diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 70221cde693..a46a34a1160 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -124,6 +124,7 @@ + diff --git a/tests/FSharp.Test.Utilities/CompilerAssert.fs b/tests/FSharp.Test.Utilities/CompilerAssert.fs index 1dcbcb846ff..b5e12d8cd5a 100644 --- a/tests/FSharp.Test.Utilities/CompilerAssert.fs +++ b/tests/FSharp.Test.Utilities/CompilerAssert.fs @@ -386,7 +386,7 @@ module rec CompilerAssertHelpers = let name = match nameOpt with | Some name -> name - | _ -> tryCreateTemporaryFileName() + | _ -> tryCreateTemporaryFileNameInDirectory(outputDirectory) let outputFilePath = Path.ChangeExtension (Path.Combine(outputDirectory.FullName, name), if isExe then ".exe" else ".dll") disposals.Add(disposeFile outputFilePath) diff --git a/tests/FSharp.Test.Utilities/TestFramework.fs b/tests/FSharp.Test.Utilities/TestFramework.fs index e5af95432b0..f7ec7f48001 100644 --- a/tests/FSharp.Test.Utilities/TestFramework.fs +++ b/tests/FSharp.Test.Utilities/TestFramework.fs @@ -28,12 +28,11 @@ let tryCreateTemporaryFileName () = filePath // Create a temporaryFileName -- newGuid is random --- there is no point validating the file alread exists because: threading and Path.ChangeExtension() is commonly used after this API -let tryCreateTemporaryFileNameInDirectory (directory) = +let tryCreateTemporaryFileNameInDirectory (directory: DirectoryInfo) = let fileName = ("Temp-" + Guid.NewGuid().ToString() + ".tmp").Replace('-', '_') - let filePath = Path.Combine(directory, fileName) + let filePath = Path.Combine(directory.FullName, fileName) filePath - [] module Commands = diff --git a/tests/service/ScriptOptionsTests.fs b/tests/service/ScriptOptionsTests.fs index 6b692543572..4cdeaa5c3c2 100644 --- a/tests/service/ScriptOptionsTests.fs +++ b/tests/service/ScriptOptionsTests.fs @@ -50,9 +50,9 @@ let ``can generate options for different frameworks regardless of execution envi [] [] let ``can resolve nuget packages to right target framework for different frameworks regardless of execution environment``(flags) = - let path = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location) + let path = DirectoryInfo(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location)) let file = tryCreateTemporaryFileNameInDirectory(path) + ".fsx" - let scriptFullPath = Path.Combine(path, file) + let scriptFullPath = Path.Combine(path.FullName, file) let scriptSource = """ #r "nuget: FSharp.Data, 3.3.3" open System From 54cfe95755000d5b5c3fb474a32a55b6b90e9d09 Mon Sep 17 00:00:00 2001 From: dawe Date: Fri, 15 Dec 2023 14:28:16 +0100 Subject: [PATCH 02/10] =?UTF-8?q?Using=20Ordinal=20is=20both=20faster=20an?= =?UTF-8?q?d=20more=20correct=20as=20our=20intent=20is=20to=20do=20?= =?UTF-8?q?=E2=80=A6=20(#16439)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Using Ordinal is both faster and more correct as our intent is to do symbolic compares. * format code * use extension methods --- src/Compiler/Checking/CheckFormatStrings.fs | 4 ++-- src/Compiler/Checking/ConstraintSolver.fs | 2 +- src/Compiler/Checking/MethodCalls.fs | 2 +- src/Compiler/Checking/NicePrint.fs | 2 +- src/Compiler/Checking/SignatureHash.fs | 2 +- src/Compiler/Checking/infos.fs | 2 +- src/Compiler/CodeGen/IlxGen.fs | 2 +- src/Compiler/DependencyManager/DependencyProvider.fs | 2 +- .../DependencyManager/NativeDllResolveHandler.fs | 3 ++- src/Compiler/Driver/FxResolver.fs | 8 ++++---- src/Compiler/Facilities/prim-lexing.fs | 3 ++- src/Compiler/Interactive/fsi.fs | 2 +- src/Compiler/Optimize/LowerStateMachines.fs | 4 ++-- src/Compiler/Optimize/Optimizer.fs | 6 +++--- src/Compiler/Service/FSharpCheckerResults.fs | 2 +- src/Compiler/Service/SemanticClassification.fs | 2 +- src/Compiler/Service/ServiceAnalysis.fs | 2 +- src/Compiler/SyntaxTree/SyntaxTreeOps.fs | 5 ++++- src/Compiler/TypedTree/TcGlobals.fs | 2 +- src/Compiler/TypedTree/TypedTreeOps.fs | 2 +- src/Compiler/Utilities/PathMap.fs | 7 ++++--- src/Compiler/Utilities/illib.fs | 9 +++++++++ src/Compiler/Utilities/illib.fsi | 6 ++++++ src/Compiler/Utilities/sformat.fs | 4 ++-- 24 files changed, 53 insertions(+), 32 deletions(-) diff --git a/src/Compiler/Checking/CheckFormatStrings.fs b/src/Compiler/Checking/CheckFormatStrings.fs index 7eb4c0355e2..ec8b4ae2b91 100644 --- a/src/Compiler/Checking/CheckFormatStrings.fs +++ b/src/Compiler/Checking/CheckFormatStrings.fs @@ -59,7 +59,7 @@ let escapeDotnetFormatString str = [] let (|PrefixedBy|_|) (prefix: string) (str: string) = - if str.StartsWith prefix then + if str.StartsWithOrdinal(prefix) then ValueSome prefix.Length else ValueNone @@ -371,7 +371,7 @@ let parseFormatStringInternal // type checker. They should always have '(...)' after for format string. let requireAndSkipInterpolationHoleFormat i = if i < len && fmt[i] = '(' then - let i2 = fmt.IndexOf(")", i+1) + let i2 = fmt.IndexOfOrdinal(")", i+1) if i2 = -1 then failwith (FSComp.SR.forFormatInvalidForInterpolated3()) else diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 3c0f68c2859..6bc57f606ca 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -1713,7 +1713,7 @@ and SolveMemberConstraint (csenv: ConstraintSolverEnv) ignoreUnresolvedOverload None let anonRecdPropSearch = - let isGetProp = nm.StartsWith "get_" + let isGetProp = nm.StartsWithOrdinal("get_") if not isRigid && isGetProp && memFlags.IsInstance then let propName = nm[4..] let props = diff --git a/src/Compiler/Checking/MethodCalls.fs b/src/Compiler/Checking/MethodCalls.fs index 4878c66511c..5aed55cba08 100644 --- a/src/Compiler/Checking/MethodCalls.fs +++ b/src/Compiler/Checking/MethodCalls.fs @@ -538,7 +538,7 @@ type CalledMeth<'T> // Detect the special case where an indexer setter using param aray takes 'value' argument after ParamArray arguments let isIndexerSetter = match pinfoOpt with - | Some pinfo when pinfo.HasSetter && minfo.LogicalName.StartsWith "set_" && (List.concat fullCurriedCalledArgs).Length >= 2 -> true + | Some pinfo when pinfo.HasSetter && minfo.LogicalName.StartsWithOrdinal("set_") && (List.concat fullCurriedCalledArgs).Length >= 2 -> true | _ -> false let argSetInfos = diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs index b37ecf518d2..dfb5a8f20a1 100644 --- a/src/Compiler/Checking/NicePrint.fs +++ b/src/Compiler/Checking/NicePrint.fs @@ -55,7 +55,7 @@ module internal PrintUtilities = let comment str = wordL (tagText (sprintf "(* %s *)" str)) - let isDiscard (name: string) = name.StartsWith("_") + let isDiscard (name: string) = name.StartsWithOrdinal("_") let ensureFloat (s: string) = if String.forall (fun c -> Char.IsDigit c || c = '-') s then diff --git a/src/Compiler/Checking/SignatureHash.fs b/src/Compiler/Checking/SignatureHash.fs index 77a9ede4145..156f64c5bdf 100644 --- a/src/Compiler/Checking/SignatureHash.fs +++ b/src/Compiler/Checking/SignatureHash.fs @@ -476,7 +476,7 @@ let calculateHashOfImpliedSignature g observer (expr: ModuleOrNamespaceContents) let rec hashModuleOrNameSpaceBinding (monb: ModuleOrNamespaceBinding) = match monb with - | ModuleOrNamespaceBinding.Binding b when b.Var.LogicalName.StartsWith("doval@") -> 0 + | ModuleOrNamespaceBinding.Binding b when b.Var.LogicalName.StartsWithOrdinal("doval@") -> 0 | ModuleOrNamespaceBinding.Binding b -> HashTastMemberOrVals.hashValOrMemberNoInst (g, observer) (mkLocalValRef b.Var) | ModuleOrNamespaceBinding.Module(moduleInfo, contents) -> hashSingleModuleOrNameSpaceIncludingName (moduleInfo, contents) diff --git a/src/Compiler/Checking/infos.fs b/src/Compiler/Checking/infos.fs index 56bb6d953c8..d7fd858d957 100644 --- a/src/Compiler/Checking/infos.fs +++ b/src/Compiler/Checking/infos.fs @@ -812,7 +812,7 @@ type MethInfo = member x.IsUnionCaseTester = let tcref = x.ApparentEnclosingTyconRef tcref.IsUnionTycon && - x.LogicalName.StartsWith("get_Is") && + x.LogicalName.StartsWithOrdinal("get_Is") && match x.ArbitraryValRef with | Some v -> v.IsImplied | None -> false diff --git a/src/Compiler/CodeGen/IlxGen.fs b/src/Compiler/CodeGen/IlxGen.fs index b8577aa4cdf..d1d3c9f85c8 100644 --- a/src/Compiler/CodeGen/IlxGen.fs +++ b/src/Compiler/CodeGen/IlxGen.fs @@ -2695,7 +2695,7 @@ let CodeGenThen (cenv: cenv) mgbuf (entryPointInfo, methodName, eenv, alreadyUse match selfArgOpt with | Some selfArg when selfArg.LogicalName <> "this" - && not (selfArg.LogicalName.StartsWith("_")) + && not (selfArg.LogicalName.StartsWithOrdinal("_")) && not cenv.options.localOptimizationsEnabled -> let ilTy = selfArg.Type |> GenType cenv m eenv.tyenv diff --git a/src/Compiler/DependencyManager/DependencyProvider.fs b/src/Compiler/DependencyManager/DependencyProvider.fs index 329dd9bd299..858cf84fc1a 100644 --- a/src/Compiler/DependencyManager/DependencyProvider.fs +++ b/src/Compiler/DependencyManager/DependencyProvider.fs @@ -612,7 +612,7 @@ type DependencyProvider let managers = RegisteredDependencyManagers compilerTools (Option.ofString outputDir) reportError - match managers |> Seq.tryFind (fun kv -> path.StartsWith(kv.Value.Key + ":")) with + match managers |> Seq.tryFind (fun kv -> path.StartsWithOrdinal(kv.Value.Key + ":")) with | None -> let err, msg = this.CreatePackageManagerUnknownError(compilerTools, outputDir, path.Split(':').[0], reportError) diff --git a/src/Compiler/DependencyManager/NativeDllResolveHandler.fs b/src/Compiler/DependencyManager/NativeDllResolveHandler.fs index 12aa28c48cc..8a3161a89d8 100644 --- a/src/Compiler/DependencyManager/NativeDllResolveHandler.fs +++ b/src/Compiler/DependencyManager/NativeDllResolveHandler.fs @@ -8,6 +8,7 @@ open System.IO open System.Reflection open System.Runtime.InteropServices open Internal.Utilities +open Internal.Utilities.Library open Internal.Utilities.FSharpEnvironment open FSharp.Compiler.IO @@ -88,7 +89,7 @@ type internal NativeDllResolveHandlerCoreClr(nativeProbingRoots: NativeResolutio let isRooted = Path.IsPathRooted name let useSuffix s = - not (name.Contains(s + ".") || name.EndsWith(s)) // linux devs often append version # to libraries I.e mydll.so.5.3.2 + not (name.Contains(s + ".") || name.EndsWithOrdinal(s)) // linux devs often append version # to libraries I.e mydll.so.5.3.2 let usePrefix = name.IndexOf(Path.DirectorySeparatorChar) = -1 // If name has directory information no add no prefix diff --git a/src/Compiler/Driver/FxResolver.fs b/src/Compiler/Driver/FxResolver.fs index 6f8643c30a1..42681600f88 100644 --- a/src/Compiler/Driver/FxResolver.fs +++ b/src/Compiler/Driver/FxResolver.fs @@ -238,7 +238,7 @@ type internal FxResolver dotnetConfig.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) + pattern.Length - let endPos = dotnetConfig.IndexOf("\"", startPos) + let endPos = dotnetConfig.IndexOfOrdinal("\"", startPos) let ver = dotnetConfig[startPos .. endPos - 1] let path = @@ -364,7 +364,7 @@ type internal FxResolver let implDir, warnings = getImplementationAssemblyDir () let version = DirectoryInfo(implDir).Name - if version.StartsWith("x") then + if version.StartsWithOrdinal("x") then // Is running on the desktop (None, None), warnings else @@ -403,7 +403,7 @@ type internal FxResolver | ".NET", "Core" when arr.Length >= 3 -> Some("netcoreapp" + (getTfmNumber arr[2])) | ".NET", "Framework" when arr.Length >= 3 -> - if arr[2].StartsWith("4.8") then + if arr[2].StartsWithOrdinal("4.8") then Some "net48" else Some "net472" @@ -560,7 +560,7 @@ type internal FxResolver dotnetConfig.IndexOf(pattern, StringComparison.OrdinalIgnoreCase) + pattern.Length - let endPos = dotnetConfig.IndexOf("\"", startPos) + let endPos = dotnetConfig.IndexOfOrdinal("\"", startPos) let tfm = dotnetConfig[startPos .. endPos - 1] tfm with _ -> diff --git a/src/Compiler/Facilities/prim-lexing.fs b/src/Compiler/Facilities/prim-lexing.fs index 4aa1d3a79e5..5951c8338e4 100644 --- a/src/Compiler/Facilities/prim-lexing.fs +++ b/src/Compiler/Facilities/prim-lexing.fs @@ -6,6 +6,7 @@ namespace FSharp.Compiler.Text open System open System.IO +open Internal.Utilities.Library type ISourceText = @@ -97,7 +98,7 @@ type StringText(str: string) = if lastIndex <= startIndex || lastIndex >= str.Length then invalidArg "target" "Too big." - str.IndexOf(target, startIndex, target.Length) <> -1 + str.IndexOfOrdinal(target, startIndex, target.Length) <> -1 member _.Length = str.Length diff --git a/src/Compiler/Interactive/fsi.fs b/src/Compiler/Interactive/fsi.fs index 924ea6c02e3..ca0e2335064 100644 --- a/src/Compiler/Interactive/fsi.fs +++ b/src/Compiler/Interactive/fsi.fs @@ -1526,7 +1526,7 @@ let ConvReflectionTypeToILTypeRef (reflectionTy: Type) = let scoref = ILScopeRef.Assembly aref let fullName = reflectionTy.FullName - let index = fullName.IndexOf("[") + let index = fullName.IndexOfOrdinal("[") let fullName = if index = -1 then diff --git a/src/Compiler/Optimize/LowerStateMachines.fs b/src/Compiler/Optimize/LowerStateMachines.fs index 7c4835b3460..ef578e86064 100644 --- a/src/Compiler/Optimize/LowerStateMachines.fs +++ b/src/Compiler/Optimize/LowerStateMachines.fs @@ -114,7 +114,7 @@ let isExpandVar g (v: Val) = let isStateMachineBindingVar g (v: Val) = isExpandVar g v || (let nm = v.LogicalName - (nm.StartsWith "builder@" || v.IsMemberThisVal) && + (nm.StartsWithOrdinal("builder@") || v.IsMemberThisVal) && not v.IsCompiledAsTopLevel) type env = @@ -833,7 +833,7 @@ type LowerStateMachine(g: TcGlobals) = |> Result.Ok elif bind.Var.IsCompiledAsTopLevel || not (resBody.resumableVars.FreeLocals.Contains(bind.Var)) || - bind.Var.LogicalName.StartsWith stackVarPrefix then + bind.Var.LogicalName.StartsWithOrdinal(stackVarPrefix) then if sm_verbose then printfn "LetExpr (non-control-flow, rewrite rhs, RepresentBindingAsTopLevelOrLocal)" RepresentBindingAsTopLevelOrLocal bind resBody m |> Result.Ok diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs index a1e01d4a58d..e1eaddef8a8 100644 --- a/src/Compiler/Optimize/Optimizer.fs +++ b/src/Compiler/Optimize/Optimizer.fs @@ -1534,11 +1534,11 @@ let ValueOfExpr expr = let IsMutableStructuralBindingForTupleElement (vref: ValRef) = vref.IsCompilerGenerated && - vref.LogicalName.EndsWith suffixForTupleElementAssignmentTarget + vref.LogicalName.EndsWithOrdinal suffixForTupleElementAssignmentTarget let IsMutableForOutArg (vref: ValRef) = vref.IsCompilerGenerated && - vref.LogicalName.StartsWith(outArgCompilerGeneratedName) + vref.LogicalName.StartsWithOrdinal(outArgCompilerGeneratedName) let IsKnownOnlyMutableBeforeUse (vref: ValRef) = IsMutableStructuralBindingForTupleElement vref || @@ -1672,7 +1672,7 @@ let TryEliminateBinding cenv _env bind e2 _m = not vspec1.IsCompilerGenerated then None elif vspec1.IsFixed then None - elif vspec1.LogicalName.StartsWith stackVarPrefix || + elif vspec1.LogicalName.StartsWithOrdinal stackVarPrefix || vspec1.LogicalName.Contains suffixForVariablesThatMayNotBeEliminated then None else diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 80a31221270..2391f26655f 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -1909,7 +1909,7 @@ type internal TypeCheckInfo | Some(_, lines) -> let lines = lines - |> List.filter (fun line -> not (line.StartsWith("//")) && not (String.IsNullOrEmpty line)) + |> List.filter (fun line -> not (line.StartsWithOrdinal("//")) && not (String.IsNullOrEmpty line)) ToolTipText.ToolTipText [ diff --git a/src/Compiler/Service/SemanticClassification.fs b/src/Compiler/Service/SemanticClassification.fs index 3697d781373..75516028fdf 100644 --- a/src/Compiler/Service/SemanticClassification.fs +++ b/src/Compiler/Service/SemanticClassification.fs @@ -75,7 +75,7 @@ module TcResolutionsExtensions = && protectAssemblyExplorationNoReraise false false (fun () -> ExistsHeadTypeInEntireHierarchy g amap range0 ty g.tcref_System_IDisposable) - let isDiscard (str: string) = str.StartsWith("_") + let isDiscard (str: string) = str.StartsWithOrdinal("_") let isValRefDisposable g amap (vref: ValRef) = not (isDiscard vref.DisplayName) diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index 5d47bab60c9..6be35d42ecb 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -439,7 +439,7 @@ module UnusedDeclarations = su.IsFromDefinition && su.Symbol.DeclarationLocation.IsSome && (isScript || su.IsPrivateToFile) - && not (su.Symbol.DisplayName.StartsWith "_") + && not (su.Symbol.DisplayName.StartsWithOrdinal "_") && isPotentiallyUnusedDeclaration su.Symbol then Some(su, usages.Contains su.Symbol.DeclarationLocation.Value) diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs index 4f259854614..d44395dbcc1 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs @@ -409,7 +409,10 @@ let opNameQMark = CompileOpName qmark let mkSynOperator (opm: range) (oper: string) = let trivia = - if oper.StartsWith("~") && ((opm.EndColumn - opm.StartColumn) = (oper.Length - 1)) then + if + oper.StartsWithOrdinal("~") + && ((opm.EndColumn - opm.StartColumn) = (oper.Length - 1)) + then // PREFIX_OP token where the ~ was actually absent IdentTrivia.OriginalNotation(string (oper.[1..])) else diff --git a/src/Compiler/TypedTree/TcGlobals.fs b/src/Compiler/TypedTree/TcGlobals.fs index fa90f06ed55..0bbee0c3e55 100644 --- a/src/Compiler/TypedTree/TcGlobals.fs +++ b/src/Compiler/TypedTree/TcGlobals.fs @@ -1882,7 +1882,7 @@ type TcGlobals( let memberName = let nm = t.MemberLogicalName let coreName = - if nm.StartsWith "op_" then nm[3..] + if nm.StartsWithOrdinal "op_" then nm[3..] elif nm = "get_Zero" then "GenericZero" elif nm = "get_One" then "GenericOne" else nm diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index d9ecfe0ca96..519a076a41e 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -10417,7 +10417,7 @@ let (|SequentialResumableCode|_|) (g: TcGlobals) expr = Some (e1, e2, m, (fun e1 e2 -> Expr.Sequential(e1, e2, NormalSeq, m))) // let __stack_step = e1 in e2 - | Expr.Let(bind, e2, m, _) when bind.Var.CompiledName(g.CompilerGlobalState).StartsWith(stackVarPrefix) -> + | Expr.Let(bind, e2, m, _) when bind.Var.CompiledName(g.CompilerGlobalState).StartsWithOrdinal(stackVarPrefix) -> Some (bind.Expr, e2, m, (fun e1 e2 -> mkLet bind.DebugPoint m bind.Var e1 e2)) | _ -> None diff --git a/src/Compiler/Utilities/PathMap.fs b/src/Compiler/Utilities/PathMap.fs index f11edef6a82..50319ea7079 100644 --- a/src/Compiler/Utilities/PathMap.fs +++ b/src/Compiler/Utilities/PathMap.fs @@ -6,6 +6,7 @@ namespace Internal.Utilities open System open System.IO +open Internal.Utilities.Library open FSharp.Compiler.IO type PathMap = PathMap of Map @@ -22,7 +23,7 @@ module internal PathMap = let normalSrc = FileSystem.GetFullPathShim src let oldPrefix = - if normalSrc.EndsWith dirSepStr then + if normalSrc.EndsWithOrdinal dirSepStr then normalSrc else normalSrc + dirSepStr @@ -41,7 +42,7 @@ module internal PathMap = // oldPrefix always ends with a path separator, so there's no need // to check if it was a partial match // e.g. for the map /goo=/bar and file name /goooo - if filePath.StartsWith(oldPrefix, StringComparison.Ordinal) then + if filePath.StartsWithOrdinal oldPrefix then let replacement = replacementPrefix + filePath.Substring(oldPrefix.Length - 1) // Normalize the path separators if used uniformly in the replacement @@ -60,7 +61,7 @@ module internal PathMap = |> Option.defaultValue filePath let applyDir pathMap (dirName: string) : string = - if dirName.EndsWith dirSepStr then + if dirName.EndsWithOrdinal dirSepStr then apply pathMap dirName else let mapped = apply pathMap (dirName + dirSepStr) diff --git a/src/Compiler/Utilities/illib.fs b/src/Compiler/Utilities/illib.fs index 1206b390443..fca3cd54605 100644 --- a/src/Compiler/Utilities/illib.fs +++ b/src/Compiler/Utilities/illib.fs @@ -124,6 +124,15 @@ module internal PervasiveAutoOpens = member inline x.EndsWithOrdinalIgnoreCase value = x.EndsWith(value, StringComparison.OrdinalIgnoreCase) + member inline x.IndexOfOrdinal value = + x.IndexOf(value, StringComparison.Ordinal) + + member inline x.IndexOfOrdinal(value, startIndex) = + x.IndexOf(value, startIndex, StringComparison.Ordinal) + + member inline x.IndexOfOrdinal(value, startIndex, count) = + x.IndexOf(value, startIndex, count, StringComparison.Ordinal) + /// Get an initialization hole let getHole (r: _ ref) = match r.Value with diff --git a/src/Compiler/Utilities/illib.fsi b/src/Compiler/Utilities/illib.fsi index fa2f1416d9c..a9ee48c4be9 100644 --- a/src/Compiler/Utilities/illib.fsi +++ b/src/Compiler/Utilities/illib.fsi @@ -79,6 +79,12 @@ module internal PervasiveAutoOpens = member inline EndsWithOrdinalIgnoreCase: value: string -> bool + member inline IndexOfOrdinal: value: string -> int + + member inline IndexOfOrdinal: value: string * startIndex: int -> int + + member inline IndexOfOrdinal: value: string * startIndex: int * count: int -> int + type Async with /// Runs the computation synchronously, always starting on the current thread. diff --git a/src/Compiler/Utilities/sformat.fs b/src/Compiler/Utilities/sformat.fs index c9158fc8a36..2a11d4fee98 100644 --- a/src/Compiler/Utilities/sformat.fs +++ b/src/Compiler/Utilities/sformat.fs @@ -285,7 +285,7 @@ module Layout = #if COMPILER let rec endsWithL (text: string) layout = match layout with - | Leaf(_, s, _) -> s.Text.EndsWith(text) + | Leaf(_, s, _) -> s.Text.EndsWith(text, StringComparison.Ordinal) | Node(_, r, _) -> endsWithL text r | Attr(_, _, l) -> endsWithL text l | ObjLeaf _ -> false @@ -512,7 +512,7 @@ module ReflectUtils = FSharpValue.GetTupleFields obj |> Array.mapi (fun i v -> (v, tyArgs[i])) let tupleType = - if reprty.Name.StartsWith "ValueTuple" then + if reprty.Name.StartsWith("ValueTuple", StringComparison.Ordinal) then TupleType.Value else TupleType.Reference From b21983195649b26a05e581b61d0e0fc17e7f432f Mon Sep 17 00:00:00 2001 From: Florian Verdonck Date: Fri, 15 Dec 2023 17:49:23 +0100 Subject: [PATCH 03/10] More release note entries (#16438) * Add additional release note entries. --- .../.FSharp.Compiler.Service/8.0.200.md | 8 +++- docs/release-notes/.Language/preview.md | 7 ++- docs/release-notes/.aux/Common.fsx | 3 +- docs/running-documentation-locally.md | 46 +++++++++++++++++++ 4 files changed, 61 insertions(+), 3 deletions(-) create mode 100644 docs/running-documentation-locally.md diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md index 09463d94484..5bc700796d6 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md @@ -2,8 +2,14 @@ * Miscellaneous fixes to parentheses analysis. ([PR #16262](https://github.com/dotnet/fsharp/pull/16262), [PR #16391](https://github.com/dotnet/fsharp/pull/16391), [PR #16370](https://github.com/dotnet/fsharp/pull/16370), [PR #16395](https://github.com/dotnet/fsharp/pull/16395)) * Correctly handle assembly imports with public key token of 0 length. ([Issue #16359](https://github.com/dotnet/fsharp/issues/16359), [PR #16363](https://github.com/dotnet/fsharp/pull/16363)) -* Fix #16398 - The dotnet framework has a limit of ~64K methods in a single class. Introduce a compile-time error if any class has over approx 64K methods in generated IL +* Range of [SynField](../reference/fsharp-compiler-syntax-synfield.html) ([PR #16357](https://github.com/dotnet/fsharp/pull/16357)) +* Limit a type to 65K methods, introduce a compile-time error if any class has over approx 64K methods in generated IL. ([Issue #16398](https://github.com/dotnet/fsharp/issues/16398), [#PR 16427](https://github.com/dotnet/fsharp/pull/16427)) ### Added * Raise a new error when interfaces with auto properties are implemented on constructor-less types. ([PR #16352](https://github.com/dotnet/fsharp/pull/16352)) * Allow usage of `[]` with older `FSharp.Core` package versions. ([PR #16373](https://github.com/dotnet/fsharp/pull/16373)) +* Parser recovers on unfinished `as` patterns. ([PR #16404](https://github.com/dotnet/fsharp/pull/16404)) +* Allow type-checking of unfinished object expressions. ([PR #16413](https://github.com/dotnet/fsharp/pull/16413)) +* Parser recovers on unfinished enum case declarations. ([PR #16401](https://github.com/dotnet/fsharp/pull/16401)) +* Parser recovers on unfinished record declarations. ([PR #16357](https://github.com/dotnet/fsharp/pull/16357)) +* `MutableKeyword` to [SynFieldTrivia](../reference/fsharp-compiler-syntaxtrivia-synfieldtrivia.html) ([PR #16357](https://github.com/dotnet/fsharp/pull/16357)) diff --git a/docs/release-notes/.Language/preview.md b/docs/release-notes/.Language/preview.md index 177436a2b43..0fce580b51e 100644 --- a/docs/release-notes/.Language/preview.md +++ b/docs/release-notes/.Language/preview.md @@ -1,4 +1,9 @@ ### Added * Better generic unmanaged structs handling. ([Language suggestion #692](https://github.com/fsharp/fslang-suggestions/issues/692), [PR #12154](https://github.com/dotnet/fsharp/pull/12154)) -* Bidirectional F#/C# interop for 'unmanaged' constraint. ([PR #12154](https://github.com/dotnet/fsharp/pull/12154)) \ No newline at end of file +* Bidirectional F#/C# interop for 'unmanaged' constraint. ([PR #12154](https://github.com/dotnet/fsharp/pull/12154)) +* Make `.Is*` discriminated union properties visible. ([Language suggestion #222](https://github.com/fsharp/fslang-suggestions/issues/222), [PR #16341](https://github.com/dotnet/fsharp/pull/16341)) + +### Fixed + +* Allow extension methods without type attribute work for types from imported assemblies. ([PR #16368](https://github.com/dotnet/fsharp/pull/16368)) diff --git a/docs/release-notes/.aux/Common.fsx b/docs/release-notes/.aux/Common.fsx index ec9bd35101c..a64026d2934 100644 --- a/docs/release-notes/.aux/Common.fsx +++ b/docs/release-notes/.aux/Common.fsx @@ -1,4 +1,5 @@ -#r "nuget: Markdig, 0.33.0" +#i "nuget: https://api.nuget.org/v3/index.json" +#r "nuget: Markdig, 0.33.0" #r "nuget: FsHttp, 12.1.0" open System.IO diff --git a/docs/running-documentation-locally.md b/docs/running-documentation-locally.md new file mode 100644 index 00000000000..ebecfd583b7 --- /dev/null +++ b/docs/running-documentation-locally.md @@ -0,0 +1,46 @@ +--- +title: Running the documentation locally +category: Compiler Internals +categoryindex: 200 +index: 999 +--- +# Running the documentation locally + +The source of this documentation website is hosted on https://github.com/fsharp/fsharp-compiler-docs. +You can follow this guide to see the results of your document changes rendered in the browser. + +## Setup + +`fsharp/fsharp-compiler-docs` will clone the `dotnet/fsharp` repository first to generate the documentation. +You can however, easily run the documentation locally and modify the `docs` from `dotnet/fsharp`. + +* Clone `fsharp/fsharp-compiler-docs` at the same level as your local `dotnet/fsharp` repository: + + + git clone https://github.com/fsharp/fsharp-compiler-docs.git + + +* Restore the `FSharp.Compiler.Service` project in `fsharp-compiler-docs`: + + + cd fsharp-compiler-docs/FSharp.Compiler.Service + dotnet restore + + +* Restore the local tools in `fsharp-compiler-docs`: + + + cd .. + dotnet tool restore + + +* Run the documentation tool using your `dotnet/fsharp` fork as input. + + + dotnet fsdocs watch --eval --sourcefolder ../fsharp/ --input ../fsharp/docs/ + + +## Release notes caveat + +The release notes pages from `docs/release-notes` are composed from the MarkDown files in subfolders. +Changing any of these files, won't regenerate the served webpage. Only the changes to the `.fsx` will trigger the tool. This is a known limitation. From fd642a9aef5b5b4617e2e890187ba7642d2f13a9 Mon Sep 17 00:00:00 2001 From: Brian Rourke Boll Date: Fri, 15 Dec 2023 11:49:43 -0500 Subject: [PATCH 04/10] Parens: Keep parens for non-identical infix operator pairs with same precedence (#16372) * Keep parens for non-ident. op pairs with same prec * Keep parens in cases like `f <| (g << h)`, `x + (y ++ z)`, etc. * Keep parens around "relational" ops even when same * The order of operations in `x > (y < z)` or `x <> (y <> z)` is not necessarily immediately obvious, and there are built-in operators in this class like `<|` for which the associativity of the underlying operation depends on the types of the operands. * Add entry to FCS release notes --- .../.FSharp.Compiler.Service/8.0.200.md | 2 +- src/Compiler/Service/ServiceAnalysis.fs | 291 +++++++----------- .../RemoveUnnecessaryParenthesesTests.fs | 26 +- 3 files changed, 134 insertions(+), 185 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md index 5bc700796d6..3eb14e5457c 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.200.md @@ -1,6 +1,6 @@ ### Fixed -* Miscellaneous fixes to parentheses analysis. ([PR #16262](https://github.com/dotnet/fsharp/pull/16262), [PR #16391](https://github.com/dotnet/fsharp/pull/16391), [PR #16370](https://github.com/dotnet/fsharp/pull/16370), [PR #16395](https://github.com/dotnet/fsharp/pull/16395)) +* Miscellaneous fixes to parentheses analysis. ([PR #16262](https://github.com/dotnet/fsharp/pull/16262), [PR #16391](https://github.com/dotnet/fsharp/pull/16391), [PR #16370](https://github.com/dotnet/fsharp/pull/16370), [PR #16395](https://github.com/dotnet/fsharp/pull/16395), [PR #16372](https://github.com/dotnet/fsharp/pull/16372)) * Correctly handle assembly imports with public key token of 0 length. ([Issue #16359](https://github.com/dotnet/fsharp/issues/16359), [PR #16363](https://github.com/dotnet/fsharp/pull/16363)) * Range of [SynField](../reference/fsharp-compiler-syntax-synfield.html) ([PR #16357](https://github.com/dotnet/fsharp/pull/16357)) * Limit a type to 65K methods, introduce a compile-time error if any class has over approx 64K methods in generated IL. ([Issue #16398](https://github.com/dotnet/fsharp/issues/16398), [#PR 16427](https://github.com/dotnet/fsharp/pull/16427)) diff --git a/src/Compiler/Service/ServiceAnalysis.fs b/src/Compiler/Service/ServiceAnalysis.fs index 6be35d42ecb..16d9f953681 100644 --- a/src/Compiler/Service/ServiceAnalysis.fs +++ b/src/Compiler/Service/ServiceAnalysis.fs @@ -462,14 +462,67 @@ module UnnecessaryParentheses = let (|Ident|) (ident: Ident) = ident.idText - /// Represents an expression's precedence, or, - /// for a few few types of expression whose exact - /// kind can be significant, the expression's exact kind. + /// Represents a symbolic infix operator with the precedence of *, /, or %. + /// All instances of this type are considered equal. + [] + type MulDivMod = + | Mul + | Div + | Mod + + member _.CompareTo(_other: MulDivMod) = 0 + override this.Equals obj = this.CompareTo(unbox obj) = 0 + override _.GetHashCode() = 0 + + interface IComparable with + member this.CompareTo obj = this.CompareTo(unbox obj) + + /// Represents a symbolic infix operator with the precedence of + or -. + /// All instances of this type are considered equal. + [] + type AddSub = + | Add + | Sub + + member _.CompareTo(_other: AddSub) = 0 + override this.Equals obj = this.CompareTo(unbox obj) = 0 + override _.GetHashCode() = 0 + + interface IComparable with + member this.CompareTo obj = this.CompareTo(unbox obj) + + /// Holds a symbolic operator's original notation. + /// Equality is based on the contents of the string. + /// Comparison always returns 0. + [] + type OriginalNotation = + | OriginalNotation of string + + member _.CompareTo(_other: OriginalNotation) = 0 + + override this.Equals obj = + match this, obj with + | OriginalNotation this, (:? OriginalNotation as OriginalNotation other) -> String.Equals(this, other, StringComparison.Ordinal) + | _ -> false + + override this.GetHashCode() = + match this with + | OriginalNotation notation -> notation.GetHashCode() + + interface IComparable with + member this.CompareTo obj = this.CompareTo(unbox obj) + + /// Represents an expression's precedence. + /// Comparison is based only on the precedence case. + /// Equality considers the embedded original notation, if any. + /// + /// For example: + /// + /// compare (AddSub (Add, OriginalNotation "+")) (AddSub (Add, OriginalNotation "++")) = 0 /// - /// Use Precedence.sameKind to determine whether two expressions - /// have the same kind. Use Precedence.compare to compare two - /// expressions' precedence. Avoid using relational operators or the - /// built-in compare function on this type. + /// but + /// + /// AddSub (Add, OriginalNotation "+") <> AddSub (Add, OriginalNotation "++") type Precedence = /// yield, yield!, return, return! | Low @@ -487,46 +540,22 @@ module UnnecessaryParentheses = /// /// Refers to the exact operators or and ||. /// Instances with leading dots or question marks or trailing characters are parsed as Bar instead. - | BarBar + | BarBar of OriginalNotation /// &, && /// /// Refers to the exact operators & and &&. /// Instances with leading dots or question marks or trailing characters are parsed as Amp instead. - | AmpAmp - - /// :?> - | Downcast - - /// :> - | Upcast + | AmpAmp of OriginalNotation - /// =… - | Eq + /// :>, :?> + | UpcastDowncast - /// |… - | Bar + /// =…, |…, &…, $…, >…, <…, !=… + | Relational of OriginalNotation - /// &… - | Amp - - /// $… - | Dollar - - /// >… - | Greater - - /// <… - | Less - - /// !=… - | BangEq - - /// ^… - | Hat - - /// @… - | At + /// ^…, @… + | HatAt /// :: | Cons @@ -534,20 +563,11 @@ module UnnecessaryParentheses = /// :? | TypeTest - /// -… - | Sub - - /// +… - | Add - - /// %… - | Mod + /// +…, -… + | AddSub of AddSub * OriginalNotation - /// /… - | Div - - /// *… - | Mul + /// *…, /…, %… + | MulDivMod of MulDivMod * OriginalNotation /// **… | Exp @@ -564,85 +584,6 @@ module UnnecessaryParentheses = // x.y | Dot - module Precedence = - /// Returns true only if the two expressions are of the - /// exact same kind. E.g., Add = Add and Sub = Sub, - /// but Add <> Sub, even though their precedence compares equally. - let sameKind prec1 prec2 = prec1 = prec2 - - /// Compares two expressions' precedence. - let compare prec1 prec2 = - match prec1, prec2 with - | Dot, Dot -> 0 - | Dot, _ -> 1 - | _, Dot -> -1 - - | High, High -> 0 - | High, _ -> 1 - | _, High -> -1 - - | Apply, Apply -> 0 - | Apply, _ -> 1 - | _, Apply -> -1 - - | UnaryPrefix, UnaryPrefix -> 0 - | UnaryPrefix, _ -> 1 - | _, UnaryPrefix -> -1 - - | Exp, Exp -> 0 - | Exp, _ -> 1 - | _, Exp -> -1 - - | (Mod | Div | Mul), (Mod | Div | Mul) -> 0 - | (Mod | Div | Mul), _ -> 1 - | _, (Mod | Div | Mul) -> -1 - - | (Sub | Add), (Sub | Add) -> 0 - | (Sub | Add), _ -> 1 - | _, (Sub | Add) -> -1 - - | TypeTest, TypeTest -> 0 - | TypeTest, _ -> 1 - | _, TypeTest -> -1 - - | Cons, Cons -> 0 - | Cons, _ -> 1 - | _, Cons -> -1 - - | (Hat | At), (Hat | At) -> 0 - | (Hat | At), _ -> 1 - | _, (Hat | At) -> -1 - - | (Eq | Bar | Amp | Dollar | Greater | Less | BangEq), (Eq | Bar | Amp | Dollar | Greater | Less | BangEq) -> 0 - | (Eq | Bar | Amp | Dollar | Greater | Less | BangEq), _ -> 1 - | _, (Eq | Bar | Amp | Dollar | Greater | Less | BangEq) -> -1 - - | (Downcast | Upcast), (Downcast | Upcast) -> 0 - | (Downcast | Upcast), _ -> 1 - | _, (Downcast | Upcast) -> -1 - - | AmpAmp, AmpAmp -> 0 - | AmpAmp, _ -> 1 - | _, AmpAmp -> -1 - - | BarBar, BarBar -> 0 - | BarBar, _ -> 1 - | _, BarBar -> -1 - - | Comma, Comma -> 0 - | Comma, _ -> 1 - | _, Comma -> -1 - - | ColonEquals, ColonEquals -> 0 - | ColonEquals, _ -> 1 - | _, ColonEquals -> -1 - - | Set, Set -> 0 - | Set, _ -> 1 - | _, Set -> -1 - - | Low, Low -> 0 - /// Associativity/association. type Assoc = /// Non-associative or no association. @@ -661,26 +602,15 @@ module UnnecessaryParentheses = | Set -> Non | ColonEquals -> Right | Comma -> Non - | BarBar -> Left - | AmpAmp -> Left - | Upcast - | Downcast -> Right - | Eq - | Bar - | Amp - | Dollar - | Greater - | Less - | BangEq -> Left - | At - | Hat -> Right + | BarBar _ -> Left + | AmpAmp _ -> Left + | UpcastDowncast -> Right + | Relational _ -> Left + | HatAt -> Right | Cons -> Right | TypeTest -> Non - | Add - | Sub -> Left - | Mul - | Div - | Mod -> Left + | AddSub _ -> Left + | MulDivMod _ -> Left | Exp -> Right | UnaryPrefix -> Left | Apply -> Left @@ -783,26 +713,30 @@ module UnnecessaryParentheses = match trimmed[0], originalNotation with | _, ":=" -> ValueSome ColonEquals - | _, ("||" | "or") -> ValueSome BarBar - | _, ("&" | "&&") -> ValueSome AmpAmp - | '|', _ -> ValueSome Bar - | '&', _ -> ValueSome Amp - | '<', _ -> ValueSome Less - | '>', _ -> ValueSome Greater - | '=', _ -> ValueSome Eq - | '$', _ -> ValueSome Dollar - | '!', _ when trimmed.Length > 1 && trimmed[1] = '=' -> ValueSome BangEq - | '^', _ -> ValueSome Hat - | '@', _ -> ValueSome At + | _, ("||" | "or") -> ValueSome(BarBar(OriginalNotation originalNotation)) + | _, ("&" | "&&") -> ValueSome(AmpAmp(OriginalNotation originalNotation)) + | '|', _ + | '&', _ + | '<', _ + | '>', _ + | '=', _ + | '$', _ -> ValueSome(Relational(OriginalNotation originalNotation)) + | '!', _ when trimmed.Length > 1 && trimmed[1] = '=' -> ValueSome(Relational(OriginalNotation originalNotation)) + | '^', _ + | '@', _ -> ValueSome HatAt | _, "::" -> ValueSome Cons - | '+', _ -> ValueSome Add - | '-', _ -> ValueSome Sub - | '/', _ -> ValueSome Div - | '%', _ -> ValueSome Mod + | '+', _ -> ValueSome(AddSub(Add, OriginalNotation originalNotation)) + | '-', _ -> ValueSome(AddSub(Sub, OriginalNotation originalNotation)) + | '/', _ -> ValueSome(MulDivMod(Div, OriginalNotation originalNotation)) + | '%', _ -> ValueSome(MulDivMod(Mod, OriginalNotation originalNotation)) | '*', _ when trimmed.Length > 1 && trimmed[1] = '*' -> ValueSome Exp - | '*', _ -> ValueSome Mul + | '*', _ -> ValueSome(MulDivMod(Mul, OriginalNotation originalNotation)) | _ -> ValueNone + [] + let (|Contains|_|) (c: char) (s: string) = + if s.IndexOf c >= 0 then ValueSome Contains else ValueNone + /// Any expressions in which the removal of parens would /// lead to something like the following that would be /// confused by the parser with a type parameter application: @@ -815,9 +749,9 @@ module UnnecessaryParentheses = match synExpr with | SynExpr.Paren(expr = ConfusableWithTypeApp) | SynExpr.App(funcExpr = ConfusableWithTypeApp) - | SynExpr.App(isInfix = true; funcExpr = FuncExpr.SymbolicOperator(SymbolPrec Greater); argExpr = ConfusableWithTypeApp) -> + | SynExpr.App(isInfix = true; funcExpr = FuncExpr.SymbolicOperator(Contains '>'); argExpr = ConfusableWithTypeApp) -> ValueSome ConfusableWithTypeApp - | SynExpr.App(isInfix = true; funcExpr = funcExpr & FuncExpr.SymbolicOperator(SymbolPrec Less); argExpr = argExpr) when + | SynExpr.App(isInfix = true; funcExpr = funcExpr & FuncExpr.SymbolicOperator(Contains '<'); argExpr = argExpr) when argExpr.Range.IsAdjacentTo funcExpr.Range -> ValueSome ConfusableWithTypeApp @@ -843,8 +777,8 @@ module UnnecessaryParentheses = | SynExpr.App(funcExpr = SynExpr.App(isInfix = true; funcExpr = FuncExpr.SymbolicOperator(SymbolPrec prec))) -> ValueSome(prec, Right) | SynExpr.App(isInfix = true; funcExpr = FuncExpr.SymbolicOperator(SymbolPrec prec)) -> ValueSome(prec, Left) - | SynExpr.Upcast _ -> ValueSome(Upcast, Left) - | SynExpr.Downcast _ -> ValueSome(Downcast, Left) + | SynExpr.Upcast _ + | SynExpr.Downcast _ -> ValueSome(UpcastDowncast, Left) | SynExpr.TypeTest _ -> ValueSome(TypeTest, Left) | _ -> ValueNone @@ -1228,11 +1162,11 @@ module UnnecessaryParentheses = // // o.M((x = y)) // o.N((x = y), z) - | SynExpr.Paren(expr = SynExpr.Paren(expr = InfixApp(Eq, _))), + | SynExpr.Paren(expr = SynExpr.Paren(expr = InfixApp(Relational(OriginalNotation "="), _))), SyntaxNode.SynExpr(SynExpr.App(funcExpr = SynExpr.LongIdent _)) :: _ - | SynExpr.Paren(expr = InfixApp(Eq, _)), + | SynExpr.Paren(expr = InfixApp(Relational(OriginalNotation "="), _)), SyntaxNode.SynExpr(SynExpr.Paren _) :: SyntaxNode.SynExpr(SynExpr.App(funcExpr = SynExpr.LongIdent _)) :: _ - | SynExpr.Paren(expr = InfixApp(Eq, _)), + | SynExpr.Paren(expr = InfixApp(Relational(OriginalNotation "="), _)), SyntaxNode.SynExpr(SynExpr.Tuple(isStruct = false)) :: SyntaxNode.SynExpr(SynExpr.Paren _) :: SyntaxNode.SynExpr(SynExpr.App( funcExpr = SynExpr.LongIdent _)) :: _ -> ValueNone @@ -1378,7 +1312,7 @@ module UnnecessaryParentheses = | OuterBinaryExpr inner (outerPrecedence, side), InnerBinaryExpr innerPrecedence -> let ambiguous = - match Precedence.compare outerPrecedence innerPrecedence with + match compare outerPrecedence innerPrecedence with | 0 -> match side, Assoc.ofPrecedence innerPrecedence with | Non, _ @@ -1387,11 +1321,12 @@ module UnnecessaryParentheses = | Right, Right | Left, Left -> false | Right, Left -> - not (Precedence.sameKind outerPrecedence innerPrecedence) - || match innerPrecedence with - | Div - | Mod - | Sub -> true + outerPrecedence <> innerPrecedence + || match outerPrecedence, innerPrecedence with + | _, MulDivMod(Div, _) + | _, MulDivMod(Mod, _) + | _, AddSub(Sub, _) -> true + | Relational _, Relational _ -> true | _ -> false | c -> c > 0 diff --git a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs index c190db6fc2d..69d6456e378 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/CodeFixes/RemoveUnnecessaryParenthesesTests.fs @@ -1079,7 +1079,7 @@ in x |> id " - "x |> (id |> fun x -> x)", "x |> id |> fun x -> x" + "x |> (id |> fun x -> x)", "x |> (id |> fun x -> x)" "x |> (id <| fun x -> x)", "x |> (id <| fun x -> x)" "id <| (fun x -> x)", "id <| fun x -> x" "id <| (fun x -> x) |> id", "id <| (fun x -> x) |> id" @@ -1121,6 +1121,10 @@ in x "id (-(-x))", "id -(-x)" "id -(-x)", "id -(-x)" + "f <| (g << h)", "f <| (g << h)" + "x <> (y <> z)", "x <> (y <> z)" + "x > (y > z)", "x > (y > z)" + " let f x y = 0 f ((+) x y) z @@ -1426,6 +1430,12 @@ let _ = (2 + 2) { return 5 } /// (x λ y) ρ z | OuterRight of l: string * r: string + /// Indicates whether both operators are the same exact symbolic operator. + member this.Identical = + match this with + | OuterLeft(l, r) + | OuterRight(l, r) -> l = r + override this.ToString() = match this with | OuterLeft(l, r) -> $"x {l} (y {r} z)" @@ -1474,11 +1484,11 @@ let _ = (2 + 2) { return 5 } | OuterLeft((":?" | ":>" | ":?>"), _) -> invalidPairing | OuterLeft(_, "**op") -> fixable pair | OuterLeft("**op", _) -> unfixable pair - | OuterLeft("*op", "*op") -> fixable pair + | OuterLeft("*op", "*op") -> if pair.Identical then fixable pair else unfixable pair | OuterLeft(("%op" | "/op" | "*op"), ("%op" | "/op" | "*op")) -> unfixable pair | OuterLeft(_, ("%op" | "/op" | "*op")) -> fixable pair | OuterLeft(("%op" | "/op" | "*op"), _) -> unfixable pair - | OuterLeft("+op", "+op") -> fixable pair + | OuterLeft("+op", "+op") -> if pair.Identical then fixable pair else unfixable pair | OuterLeft(("-op" | "+op"), ("-op" | "+op")) -> unfixable pair | OuterLeft(_, ("-op" | "+op")) -> fixable pair | OuterLeft(("-op" | "+op"), _) -> unfixable pair @@ -1487,14 +1497,15 @@ let _ = (2 + 2) { return 5 } | OuterLeft("::", _) -> unfixable pair | OuterLeft(_, ("^op" | "@op")) -> fixable pair | OuterLeft(("^op" | "@op"), _) -> unfixable pair - | OuterLeft(l & ("=op" | "|op" | "&op" | "$" | ">op" | "op" | " - if l = r then fixable pair else unfixable pair + | OuterLeft(("=op" | "|op" | "&op" | "$" | ">op" | "op" | " unfixable pair | OuterLeft(_, ("=op" | "|op" | "&op" | "$" | ">op" | " fixable pair | OuterLeft(("=op" | "|op" | "&op" | "$" | ">op" | " unfixable pair | OuterLeft(_, (":>" | ":?>")) -> fixable pair + | OuterLeft(("&" | "&&"), ("&" | "&&")) -> if pair.Identical then fixable pair else unfixable pair | OuterLeft(_, ("&" | "&&")) -> fixable pair | OuterLeft(("&" | "&&"), _) -> unfixable pair + | OuterLeft(("||" | "or"), ("||" | "or")) -> if pair.Identical then fixable pair else unfixable pair | OuterLeft(_, ("||" | "or")) -> fixable pair | OuterLeft(("||" | "or"), _) -> unfixable pair | OuterLeft(":=", ":=") -> fixable pair @@ -1527,11 +1538,14 @@ let _ = (2 + 2) { return 5 } let operators = [ "**" + "***" "*" + "*." "/" "%" "-" "+" + "++" ":?" "::" "^^^" From 311360de0a5cc576a8e2689814273140686f1959 Mon Sep 17 00:00:00 2001 From: Hadrian Tang Date: Mon, 18 Dec 2023 21:27:19 +0800 Subject: [PATCH 05/10] Improve value restriction error message #1103 (#15877) * Improve value restriction error message #1103 * Update the error message * Update message * Update tests * Update error message * Update messages * Add line back * Update error messages * Update E_ValueRestriction01.fs * Update messages * Update messages * Update messages * Does this work? * hmm * Update function message * Escape () * Update tests * Update messages * Update CompilerDiagnostics.fs * Update CompilerDiagnostics.fs --------- Co-authored-by: Petr --- src/Compiler/Checking/CheckDeclarations.fs | 2 +- src/Compiler/Checking/CheckExpressions.fs | 2 +- src/Compiler/Checking/CheckExpressions.fsi | 2 +- src/Compiler/Driver/CompilerDiagnostics.fs | 70 +++++-------------- src/Compiler/FSStrings.resx | 17 ++--- src/Compiler/xlf/FSStrings.cs.xlf | 35 +++------- src/Compiler/xlf/FSStrings.de.xlf | 35 +++------- src/Compiler/xlf/FSStrings.es.xlf | 35 +++------- src/Compiler/xlf/FSStrings.fr.xlf | 35 +++------- src/Compiler/xlf/FSStrings.it.xlf | 35 +++------- src/Compiler/xlf/FSStrings.ja.xlf | 35 +++------- src/Compiler/xlf/FSStrings.ko.xlf | 35 +++------- src/Compiler/xlf/FSStrings.pl.xlf | 35 +++------- src/Compiler/xlf/FSStrings.pt-BR.xlf | 35 +++------- src/Compiler/xlf/FSStrings.ru.xlf | 35 +++------- src/Compiler/xlf/FSStrings.tr.xlf | 35 +++------- src/Compiler/xlf/FSStrings.zh-Hans.xlf | 35 +++------- src/Compiler/xlf/FSStrings.zh-Hant.xlf | 35 +++------- .../E_NotMemberOrFunction01.fsx | 2 +- .../Language/SequenceExpressionTests.fs | 3 +- tests/fsharp/typecheck/sigs/neg119b.bsl | 13 +++- .../ExpressionQuotations/Baselines/E_Cast.fs | 3 +- .../ConstraintSolving/E_ValueRestriction01.fs | 17 +++-- .../E_GenInterfaceWGenMethods01.fs | 2 +- .../E_NotMemberOrFunction01.fsx | 4 +- .../W_NonGenVarInValueRestrictionWarning.fs | 4 +- 26 files changed, 183 insertions(+), 413 deletions(-) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index 0a860cef0ec..ef9a56204a0 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -5577,7 +5577,7 @@ let CheckValueRestriction denvAtEnd infoReader rootSigOpt implFileTypePriorToSig // for example FSharp 1.0 3661. (match v.ValReprInfo with None -> true | Some tvi -> tvi.HasNoArgs)) then match ftyvs with - | tp :: _ -> errorR (ValueRestriction(denvAtEnd, infoReader, false, v, tp, v.Range)) + | tp :: _ -> errorR (ValueRestriction(denvAtEnd, infoReader, v, tp, v.Range)) | _ -> () mty.ModuleAndNamespaceDefinitions |> List.iter (fun v -> check v.ModuleOrNamespaceType) try check implFileTypePriorToSig with RecoverableException e -> errorRecovery e m diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 6f169d474a8..98138270658 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -94,7 +94,7 @@ exception UnionPatternsBindDifferentNames of range exception VarBoundTwice of Ident -exception ValueRestriction of DisplayEnv * InfoReader * bool * Val * Typar * range +exception ValueRestriction of DisplayEnv * InfoReader * Val * Typar * range exception ValNotMutable of DisplayEnv * ValRef * range diff --git a/src/Compiler/Checking/CheckExpressions.fsi b/src/Compiler/Checking/CheckExpressions.fsi index 16a759c2e3d..3f1e8d78b97 100644 --- a/src/Compiler/Checking/CheckExpressions.fsi +++ b/src/Compiler/Checking/CheckExpressions.fsi @@ -75,7 +75,7 @@ exception UnionPatternsBindDifferentNames of range exception VarBoundTwice of Ident -exception ValueRestriction of DisplayEnv * InfoReader * bool * Val * Typar * range +exception ValueRestriction of DisplayEnv * InfoReader * Val * Typar * range exception ValNotMutable of DisplayEnv * ValRef * range diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index 71d24223e14..3327aa0a635 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -145,7 +145,7 @@ type Exception with | IntfImplInIntrinsicAugmentation m | OverrideInExtrinsicAugmentation m | IntfImplInExtrinsicAugmentation m - | ValueRestriction(_, _, _, _, _, m) + | ValueRestriction(_, _, _, _, m) | LetRecUnsound(_, _, m) | ObsoleteError(_, m) | ObsoleteWarning(_, m) @@ -579,11 +579,8 @@ module OldStyleMessages = let DeprecatedE () = Message("Deprecated", "%s") let LibraryUseOnlyE () = Message("LibraryUseOnly", "") let MissingFieldsE () = Message("MissingFields", "%s") - let ValueRestriction1E () = Message("ValueRestriction1", "%s%s%s") - let ValueRestriction2E () = Message("ValueRestriction2", "%s%s%s") - let ValueRestriction3E () = Message("ValueRestriction3", "%s") - let ValueRestriction4E () = Message("ValueRestriction4", "%s%s%s") - let ValueRestriction5E () = Message("ValueRestriction5", "%s%s%s") + let ValueRestrictionFunctionE () = Message("ValueRestrictionFunction", "%s%s%s") + let ValueRestrictionE () = Message("ValueRestriction", "%s%s%s") let RecoverableParseErrorE () = Message("RecoverableParseError", "") let ReservedKeywordE () = Message("ReservedKeyword", "%s") let IndentationProblemE () = Message("IndentationProblem", "%s") @@ -1760,7 +1757,7 @@ type Exception with | MissingFields(sl, _) -> os.AppendString(MissingFieldsE().Format(String.concat "," sl + ".")) - | ValueRestriction(denv, infoReader, hasSig, v, _, _) -> + | ValueRestriction(denv, infoReader, v, _, _) -> let denv = { denv with showInferenceTyparAnnotations = true @@ -1768,55 +1765,22 @@ type Exception with let tau = v.TauType - if hasSig then - if isFunTy denv.g tau && (arityOfVal v).HasNoArgs then - let msg = - ValueRestriction1E().Format - v.DisplayName - (NicePrint.stringOfQualifiedValOrMember denv infoReader (mkLocalValRef v)) - v.DisplayName + if isFunTy denv.g tau && (arityOfVal v).HasNoArgs then + let msg = + ValueRestrictionFunctionE().Format + v.DisplayName + (NicePrint.stringOfQualifiedValOrMember denv infoReader (mkLocalValRef v)) + v.DisplayName - os.AppendString msg - else - let msg = - ValueRestriction2E().Format - v.DisplayName - (NicePrint.stringOfQualifiedValOrMember denv infoReader (mkLocalValRef v)) - v.DisplayName - - os.AppendString msg + os.AppendString msg else - match v.MemberInfo with - | Some membInfo when - (match membInfo.MemberFlags.MemberKind with - | SynMemberKind.PropertyGet - | SynMemberKind.PropertySet - | SynMemberKind.Constructor -> true // can't infer extra polymorphism - // can infer extra polymorphism - | _ -> false) - -> - let msg = - ValueRestriction3E() - .Format(NicePrint.stringOfQualifiedValOrMember denv infoReader (mkLocalValRef v)) - - os.AppendString msg - | _ -> - if isFunTy denv.g tau && (arityOfVal v).HasNoArgs then - let msg = - ValueRestriction4E().Format - v.DisplayName - (NicePrint.stringOfQualifiedValOrMember denv infoReader (mkLocalValRef v)) - v.DisplayName - - os.AppendString msg - else - let msg = - ValueRestriction5E().Format - v.DisplayName - (NicePrint.stringOfQualifiedValOrMember denv infoReader (mkLocalValRef v)) - v.DisplayName + let msg = + ValueRestrictionE().Format + v.DisplayName + (NicePrint.stringOfQualifiedValOrMember denv infoReader (mkLocalValRef v)) + v.DisplayName - os.AppendString msg + os.AppendString msg | Parsing.RecoverableParseError -> os.AppendString(RecoverableParseErrorE().Format) diff --git a/src/Compiler/FSStrings.resx b/src/Compiler/FSStrings.resx index 251f626c63e..e24b4737742 100644 --- a/src/Compiler/FSStrings.resx +++ b/src/Compiler/FSStrings.resx @@ -1029,20 +1029,11 @@ The following fields require values: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. syntax error diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf index 318ea1464ff..c2142422521 100644 --- a/src/Compiler/xlf/FSStrings.cs.xlf +++ b/src/Compiler/xlf/FSStrings.cs.xlf @@ -202,6 +202,16 @@ Pole {0} a {1} jsou odlišného typu. + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern {0} má v tomto vzoru dvě vazby. @@ -1532,31 +1542,6 @@ Následující pole vyžadují hodnoty: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Omezení hodnoty. Hodnota {0} je obecného typu\n {1}. \nBuď změňte argumenty pro {2} na explicitní, nebo (pokud hodnota nemá být obecná) přidejte poznámku typu. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Omezení hodnoty. Hodnota {0} je obecného typu\n {1}. \nZměňte {2} na funkci s explicitními argumenty nebo (pokud hodnota nemá být obecná) přidejte poznámku typu. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - Omezení hodnoty. Tento člen se odvodil jako člen obecného typu\n {0}. \nKonstruktory a metody getter nebo setter vlastnosti nemůžou být obecnější než nadřazený typ. Přidejte poznámku typu, abyste přesně určili, které typy se mají zahrnout. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Omezení hodnoty. Hodnota {0} se odvodila jako hodnota obecného typu\n {1}. \nBuď změňte argumenty pro {2} na explicitní, nebo (pokud hodnota nemá být obecná) přidejte poznámku typu. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Omezení hodnoty. Hodnota {0} se odvodila jako hodnota obecného typu\n {1}. \nDefinujte {2} jako jednoduchý datový výraz, změňte ji na funkci s explicitními argumenty nebo (pokud hodnota nemá být obecná) přidejte poznámku typu. - - syntax error chyba syntaxe diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf index 430b308631e..9e138b1f06a 100644 --- a/src/Compiler/xlf/FSStrings.de.xlf +++ b/src/Compiler/xlf/FSStrings.de.xlf @@ -202,6 +202,16 @@ Die Felder "{0}" und "{1}" stammen aus unterschiedlichen Typen. + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern {0} ist in diesem Muster doppelt gebunden. @@ -1532,31 +1542,6 @@ Für die folgenden Felder sind Werte erforderlich: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Werteinschränkung. Der Wert "{0}" hat den generischen Typ\n {1} \nLegen Sie die Argumente für "{2}" entweder als explizit fest, oder fügen Sie eine Typanmerkung hinzu, wenn der Typ nicht generisch sein soll. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Werteinschränkung. Der Wert "{0}" hat den generischen Typ\n {1} \nDefinieren Sie "{2}" entweder als Funktion mit expliziten Argumenten, oder fügen Sie eine Typanmerkung hinzu, wenn der Typ nicht generisch sein soll. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - Werteinschränkung. Dieser Member wurde per Rückschluss abgeleitet als generischer Typ\n {0} \nKonstruktoren und Eigenschaftengetter/-setter dürfen nicht generischer sein als der einschließende Typ. Fügen Sie eine Typanmerkung hinzu, um die genauen Typen anzugeben. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Werteinschränkung. Der Wert "{0}" wurde per Rückschluss abgeleitet als generischer Typ\n {1} \nLegen Sie die Argumente für "{2}" entweder als explizit fest, oder fügen Sie eine Typanmerkung hinzu, wenn der Typ nicht generisch sein soll. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Werteinschränkung. Der Wert "{0}" wurde per Rückschluss abgeleitet als generischer Typ\n {1} \nDefinieren Sie "{2}" entweder als einfachen Ausdruck oder als Funktion mit expliziten Argumenten, oder fügen Sie eine Typanmerkung hinzu, wenn der Typ nicht generisch sein soll. - - syntax error Syntaxfehler diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf index 9a94fe0bfca..21ce23e4a4c 100644 --- a/src/Compiler/xlf/FSStrings.es.xlf +++ b/src/Compiler/xlf/FSStrings.es.xlf @@ -202,6 +202,16 @@ Los campos '{0}' y '{1}' son de tipos diferentes. + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern '{0}' está enlazado dos veces en este patrón @@ -1532,31 +1542,6 @@ Los campos siguientes requieren valores: {0}. - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Restricción de valor. El valor '{0}' tiene el tipo genérico\n {1} \nConvierta los argumentos de '{2}' en explícitos o, si su intención no es que sea genérico, agregue una anotación de tipo. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Restricción de valor. El valor '{0}' tiene el tipo genérico\n {1} \nConvierta '{2}' en una función con argumentos explícitos o, si su intención no es que sea genérico, agregue una anotación de tipo. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - Restricción de valor. Se ha inferido que este miembro tiene el tipo genérico\n {0} \nLos constructores y los captadores y establecedores de propiedades no pueden ser más genéricos que el tipo envolvente. Agregue una anotación de tipo para indicar los tipos exactos implicados. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Restricción de valor. Se ha inferido que el valor '{0}' tiene el tipo genérico\n {1} \nConvierta los argumentos de '{2}' en explícitos o, si su intención no es que sea genérico, agregue una anotación de tipo. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Restricción de valor. Se ha inferido que el valor '{0}' tiene el tipo genérico\n {1} \nDefina '{2}' como un término de datos simple, conviértalo en una función con argumentos explícitos o, si su intención no es que sea genérico, agregue una anotación de tipo. - - syntax error error de sintaxis diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf index 0d5bfd687ae..b60d006b516 100644 --- a/src/Compiler/xlf/FSStrings.fr.xlf +++ b/src/Compiler/xlf/FSStrings.fr.xlf @@ -202,6 +202,16 @@ Les champs '{0}' et '{1}' sont de types différents + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern '{0}' est lié à deux reprises dans ce modèle @@ -1532,31 +1542,6 @@ Les champs suivants requièrent des valeurs : {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Restriction de valeur. La valeur '{0}' a le type générique\n {1} \nRendez les arguments de '{2}' explicites ou, si votre but n'est pas d'utiliser un type générique, ajoutez une annotation de type. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Restriction de valeur. La valeur '{0}' a le type générique\n {1} \nChangez '{2}' en fonction avec des arguments explicites ou, si votre but n'est pas d'utiliser un type générique, ajoutez une annotation de type. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - Restriction de valeur. Il a été déduit que ce membre avait un type générique\n {0} \nLes constructeurs, ainsi que les méthodes getter/setter d'une propriété ne peuvent pas être plus génériques que le type englobant. Ajoutez une annotation de type pour indiquer les types exacts impliqués. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Restriction de valeur. Il a été déduit que la valeur '{0}' avait le type générique\n {1} \nRendez les arguments de '{2}' explicites ou, si votre but n'est pas d'utiliser un type générique, ajoutez une annotation de type. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Restriction de valeur. Il a été déduit que la valeur '{0}' avait le type générique\n {1} \nDéfinissez '{2}' en tant que terme de données simple, faites-en une fonction avec des arguments explicites ou, si votre but n'est pas d'utiliser un type générique, ajoutez une annotation de type. - - syntax error erreur de syntaxe diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf index 465456a085d..11a10d7e283 100644 --- a/src/Compiler/xlf/FSStrings.it.xlf +++ b/src/Compiler/xlf/FSStrings.it.xlf @@ -202,6 +202,16 @@ I campi '{0}' e '{1}' sono di tipi diversi + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern '{0}' è associato due volte in questo criterio @@ -1532,31 +1542,6 @@ Immissione valori obbligatoria per i campi seguenti: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Limitazione valore. Il valore '{0}' ha il tipo generico\n {1} \nRendere gli argomenti di '{2}' espliciti oppure, se non si intende renderlo generico, aggiungere un'annotazione di tipo. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Limitazione valore. Il valore '{0}' ha il tipo generico\n {1} \nRendere '{2}' una funzione con argomenti espliciti oppure, se non si intende renderlo generico, aggiungere un'annotazione di tipo. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - Restrizione relativa ai valori. È stato dedotto che il membro ha il tipo generico\n {0} \nI getter/setter di proprietà e i costruttori non possono essere più generici del tipo di inclusione. Aggiungere un'annotazione di tipo per indicare i tipi esatti previsti. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Limitazione valore. È stato dedotto che il valore '{0}' ha il tipo generico\n {1} \nRendere gli argomenti di '{2}' espliciti, oppure se non si intende renderlo generico, aggiungere un'annotazione di tipo. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Limitazione valore. È stato dedotto che il valore '{0}' ha il tipo generico\n {1} \nDefinire '{2}' come termine di dati semplice, renderlo una funzione con argomenti espliciti oppure, se non si intende renderlo generico, aggiungere un'annotazione di tipo. - - syntax error errore di sintassi diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf index c895e7a6a1e..8bd7b3bf676 100644 --- a/src/Compiler/xlf/FSStrings.ja.xlf +++ b/src/Compiler/xlf/FSStrings.ja.xlf @@ -202,6 +202,16 @@ フィールド '{0}' と '{1}' は異なる型です + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern このパターンで '{0}' が 2 回バインドされています @@ -1532,31 +1542,6 @@ 次のフィールドには値が必要です: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - 値の制限。値 '{0}' は次のジェネリック型です。\n {1} \n明示的に引数を '{2}' にするか、ジェネリックにする意図がない場合は型の注釈を追加してください。 - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - 値の制限。値 '{0}' は次のジェネリック型です。\n {1} \n明示的な引数を使用して '{2}' を関数にするか、ジェネリックにする意図がない場合は型の注釈を追加してください。 - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - 値の制限。このメンバーは次のジェネリック型を持つと推論されました。\n {0} \nコンストラクターとプロパティのゲッター/セッターは、それを囲む型よりも総称性を高くすることができません。関係する正確な型を示すために、型の注釈を追加してください。 - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - 値の制限。値 '{0}' は次のジェネリック型を持つと推論されました。\n {1} \n明示的に引数を '{2}' にするか、ジェネリックにする意図がない場合は型の注釈を追加してください。 - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - 値の制限。値 '{0}' は次のジェネリック型を持つと推論されました。\n {1} \n単純なデータ用語として '{2}' を定義するか、明示的な引数を使用して関数にするか、ジェネリックにする意図がない場合は型の注釈を追加してください。 - - syntax error 構文エラーです diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf index 82dbc42e072..809f65182e8 100644 --- a/src/Compiler/xlf/FSStrings.ko.xlf +++ b/src/Compiler/xlf/FSStrings.ko.xlf @@ -202,6 +202,16 @@ {0}' 필드와 '{1}' 필드의 소스 형식이 서로 다릅니다. + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern '{0}'은(는) 이 패턴에서 두 번 바인딩되었습니다. @@ -1532,31 +1542,6 @@ 다음 필드에는 값이 필요합니다. {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - 값 제한이 있습니다. 값 '{0}'에 제네릭 형식\n {1}이(가) 있습니다. \n'{2}'에 대한 인수를 명시적으로 만들거나, 제네릭 요소로 만들지 않으려는 경우 형식 주석을 추가하세요. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - 값 제한이 있습니다. 값 '{0}'에 제네릭 형식\n {1}이(가) 있습니다. \n'{2}'을(를) 명시적 인수가 포함된 함수로 만들거나, 제네릭 요소로 만들지 않으려는 경우 형식 주석을 추가하세요. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - 값 제한이 있습니다. 이 멤버는 제네릭 형식\n {0}을(를) 가지는 것으로 유추되었습니다. \n생성자 및 속성 getter/setter는 바깥쪽 형식보다 일반적일 수 없습니다. 형식 주석을 추가하여 관련 형식을 정확히 나타내세요. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - 값 제한이 있습니다. 값 '{0}'은(는) 제네릭 형식\n {1}을(를) 가지는 것으로 유추되었습니다. \n'{2}'에 대한 인수를 명시적으로 만들거나, 제네릭 요소로 만들지 않으려는 경우 형식 주석을 추가하세요. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - 값 제한이 있습니다. 값 '{0}'은(는) 제네릭 형식\n {1}을(를) 가지는 것으로 유추되었습니다. \n'{2}'을(를) 단순 데이터 용어로 정의하거나, 명시적 인수가 포함된 함수로 만들거나, 제네릭 요소로 만들지 않으려는 경우 형식 주석을 추가하세요. - - syntax error 구문 오류입니다. diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf index e2bc31e3fb9..7f0fd4fe660 100644 --- a/src/Compiler/xlf/FSStrings.pl.xlf +++ b/src/Compiler/xlf/FSStrings.pl.xlf @@ -202,6 +202,16 @@ Pola „{0}” i „{1}” są polami różnego typu + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern Zmienna „{0}” została powiązana dwa razy w tym wzorcu @@ -1532,31 +1542,6 @@ Następujące pola wymagają wartości: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Ograniczenie wartości. Wartość „{0}” jest wartością typu ogólnego\n {1} \nOkreśl argumenty elementu „{2}” jako jawne lub dodaj adnotację typu, jeśli nie chcesz, aby wartość była ogólna. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Ograniczenie wartości. Wartość „{0}” jest wartością typu ogólnego\n {1} \nUstaw element „{2}” jako funkcję z jawnymi argumentami lub dodaj adnotację typu, jeśli nie chcesz, aby wartość była ogólna. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - Ograniczenie wartości. Wywnioskowano, że ten element członkowski jest elementem typu ogólnego\n {0} \nKonstruktory i metody pobierające/ustawiające właściwości nie mogą być bardziej ogólne niż typ otaczający. Dodaj adnotację typu, aby dokładnie wskazać uwzględnione typy. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Ograniczenie wartości. Wywnioskowano, że wartość „{0}” jest wartością typu ogólnego\n {1} \nOkreśl argumenty elementu „{2}” jako jawne lub dodaj adnotację typu, jeśli nie chcesz, aby wartość była ogólna. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Ograniczenie wartości. Wywnioskowano, że wartość „{0}” jest wartością typu ogólnego\n {1} \nZdefiniuj element „{2}” jako prosty termin danych, określ go jako funkcję z jawnymi argumentami lub dodaj adnotację typu, jeśli nie chcesz, aby wartość była ogólna. - - syntax error błąd składni diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf index b4d1f7ba70d..68884d303f8 100644 --- a/src/Compiler/xlf/FSStrings.pt-BR.xlf +++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf @@ -202,6 +202,16 @@ Os campos '{0}' e '{1}' são de tipos diferentes + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern '{0}' é associado duas vezes neste padrão @@ -1532,31 +1542,6 @@ Os campos a seguir requerem valores: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Restrição de valor. O valor '{0}' tem um tipo genérico\n {1} \nTorne os argumentos '{2}' explícitos ou, se sua intenção não for deixá-los genéricos, adicione uma anotação de tipo. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Restrição de valor. O valor '{0}' tem um tipo genérico\n {1} \nInsira '{2}' em uma função com argumentos explícitos ou, se você não desejar que ele seja genérico, adicione uma anotação de tipo. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - Restrição de valor. Este membro foi inferido para ter um tipo genérico\n {0} \nConstrutores e getters/setters de propriedade não podem ser mais genéricos que o tipo de delimitador. Adicione uma anotação de tipo para indicar os tipos exatos envolvidos. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Restrição de valor. O valor '{0}' foi inferido para ter um tipo genérico\n {1} \nTorne os argumentos '{2}' explícitos ou, se sua intenção não for deixá-los genéricos, adicione uma anotação de tipo. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Restrição de valor. O valor '{0}' foi inferido para ter um tipo genérico\n {1} \nDefina '{2}' como um termo de dado simples e torne-o uma função com argumentos explícitos ou, se sua intenção for deixá-los genéricos, adicione uma anotação de tipo. - - syntax error erro de sintaxe diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf index 5149ef4d9f0..e4183664a10 100644 --- a/src/Compiler/xlf/FSStrings.ru.xlf +++ b/src/Compiler/xlf/FSStrings.ru.xlf @@ -202,6 +202,16 @@ Поля "{0}" и "{1}" принадлежат различным типам + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern {0} в данном шаблоне привязан дважды @@ -1532,31 +1542,6 @@ Для следующих полей требуются значения: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Ограничение значения. Значение "{0}" имеет универсальный тип\n {1} \nЛибо сделайте аргументы для "{2}" явными либо (если универсальный тип не требуется) добавьте аннотацию типа. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Ограничение значения. Значение "{0}" имеет универсальный тип\n {1} \nЛибо сделайте "{2}" функцией с явными аргументами, либо (если универсальный тип не требуется) добавьте аннотацию типа. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - Ограничение значения. Данный выведенный элемент должен иметь универсальный тип\n {0} \nМетоды получения или задания свойств и конструкторов не могут быть более универсальными, чем вмещающий тип. Добавьте аннотацию типа, чтобы точно обозначить затрагиваемые типы. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Ограничение значения. Выведенное значение "{0}" должно иметь универсальный тип\n {1} \nЛибо сделайте аргументы для "{2}" явными, либо (если универсальный тип не требуется) добавьте аннотацию типа. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Ограничение значения. Выведенное значение "{0}" должно иметь универсальный тип\n {1} \nЛибо определите "{2}" как простой член данных, либо сделайте его функцией с явными аргументами, либо (если универсальный тип не требуется) добавьте аннотацию типа. - - syntax error синтаксическая ошибка diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf index dde4f9ee022..fd472f37780 100644 --- a/src/Compiler/xlf/FSStrings.tr.xlf +++ b/src/Compiler/xlf/FSStrings.tr.xlf @@ -202,6 +202,16 @@ {0}' ve '{1}' alanları farklı türlerde + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern '{0}' bu desende iki kez bağlandı @@ -1532,31 +1542,6 @@ Aşağıdaki alanlar için değerler gerekiyor: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Değer kısıtlaması. '{0}' değerinin genel türü:\n {1} \nYa '{2}' bağımsız değişkenlerini açık yapın ya da genel olmasını istemiyorsanız bir tür ek açıklaması ekleyin. - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Değer kısıtlaması. '{0}' değerinin genel türü:\n {1} \nYa açık bağımsız değişkenlerle '{2}' için işlev dönüşümü yapın ya da genel olmasını istemiyorsanız bir tür ek açıklaması ekleyin. - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - Değer kısıtlaması. Bu üyenin şu genel türü olduğu çıkarıldı\n {0} \nOluşturucular ve özellik alıcıları/ayarlayıcıları kapsayan türden daha genel olamaz. Söz konusu türleri tam olarak belirtmek için bir tür ek açıklaması ekleyin. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - Değer kısıtlaması. '{0}' değerinin şu genel türü olduğu çıkarıldı:\n {1} \nYa '{2}' bağımsız değişkenlerini açık yapın ya da genel olmasını istemiyorsanız bir tür ek açıklaması ekleyin. - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - Değer kısıtlaması. '{0}' değerinin şu genel türü olduğu çıkarıldı:\n {1} \nYa '{2}' tanımını basit veri terimi olarak yaparak onu açık bağımsız değişkenlerle bir işlev yapın ya da genel olmasını istemiyorsanız bir tür ek açıklaması ekleyin. - - syntax error sözdizimi hatası diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf index 89e54bb26c5..fa324741415 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf @@ -202,6 +202,16 @@ 字段“{0}”和“{1}”来自不同的类型 + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern “{0}”在此模式中绑定了两次 @@ -1532,31 +1542,6 @@ 以下字段需要值: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - 值限制。值“{0}”具有泛型类型\n {1} \n使“{2}”的参数成为显式参数,或添加类型批注(如果您不希望它是泛型的)。 - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - 值限制。值“{0}”具有泛型类型\n {1} \n使“{2}”成为具有显式参数的函数,或添加类型批注(如果您不希望它是泛型的)。 - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - 值限制。已推理出此成员具有泛型类型\n {0} \n构造函数和属性 Getter/Setter 不能比封闭类型更通用。 添加类型批注以指示涉及到的确切类型。 - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - 值限制。已推理出值“{0}”具有泛型类型\n {1} \n使“{2}”的参数成为显式参数,或添加类型批注(如果您不希望它是泛型的)。 - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - 值限制。已推理出值“{0}”具有泛型类型\n {1} \n将“{2}”定义为简单的数据条目,使其成为具有显式参数的函数,或添加类型批注(如果您不希望它是泛型的)。 - - syntax error 语法错误 diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf index 71c045b02fa..db72d0a3ee7 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf @@ -202,6 +202,16 @@ 欄位 '{0}' 和 '{1}' 來自不同類型 + + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic type\n {1}\nHowever, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following:\n- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"\n- Add an explicit type annotation like "let x : int"\n- Use the value as a non-generic type in later code for type inference like "do x"\nor if you still want type-dependent results, you can define '{2}' as a function instead by doing either:\n- Add a unit parameter like "let x()"\n- Write explicit type parameters like "let x<'a>".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + + + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + Value restriction: The value '{0}' has an inferred generic function type\n {1}\nHowever, values cannot have generic type variables like '_a in "let f: '_a". You should define '{2}' as a function instead by doing one of the following:\n- Add an explicit parameter that is applied instead of using a partial application "let f param"\n- Add a unit parameter like "let f()"\n- Write explicit type parameters like "let f<'a>"\nor if you do not intend for it to be generic, either:\n- Add an explicit type annotation like "let f : obj -> obj"\n- Apply arguments of non-generic types to the function value in later code for type inference like "do f()".\nThis error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. + + '{0}' is bound twice in this pattern '{0}' 在這個模式中繫結兩次 @@ -1532,31 +1542,6 @@ 下列欄位需要值: {0} - - Value restriction. The value '{0}' has generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - 值限制。值 '{0}' 具有泛型類型\n {1} \n請將 '{2}' 的引數設為明確的,或者如果不想將它設為泛型,請加入類型註釋。 - - - - Value restriction. The value '{0}' has generic type\n {1} \nEither make '{2}' into a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - 值限制。值 '{0}' 具有泛型類型\n {1} \n請將 '{2}' 設為具有明確引數的函式,或者如果不想將它設為泛型,請加入類型註釋。 - - - - Value restriction. This member has been inferred to have generic type\n {0} \nConstructors and property getters/setters cannot be more generic than the enclosing type. Add a type annotation to indicate the exact types involved. - 值限制。這個成員已被推斷為具有泛型類型\n {0} \n建構函式和屬性 getter/setter 不能比封入類型更為泛型。請加入類型註釋,以指示涉及的確切類型。 - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither make the arguments to '{2}' explicit or, if you do not intend for it to be generic, add a type annotation. - 值限制。值 '{0}' 已被推斷為具有泛型類型\n {1} \n請將 '{2}' 的引數設為明確的,或者如果不想將它設為泛型,請加入類型註釋。 - - - - Value restriction. The value '{0}' has been inferred to have generic type\n {1} \nEither define '{2}' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. - 值限制。值 '{0}' 已被推斷為具有泛型類型\n {1} \n請將 '{2}' 定義為簡單資料項、將它設為具有明確引數的函式,或者如果不想將它設為泛型,請加入類型註釋。 - - syntax error 語法錯誤 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ValueRestriction/E_NotMemberOrFunction01.fsx b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ValueRestriction/E_NotMemberOrFunction01.fsx index 182fb04be48..5cb7755a083 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ValueRestriction/E_NotMemberOrFunction01.fsx +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ValueRestriction/E_NotMemberOrFunction01.fsx @@ -1,6 +1,6 @@ // #Conformance #ObjectOrientedTypes #Classes #TypeInference #ValueRestriction -//Value restriction\. The value 'x1' has been inferred to have generic type. val x1: \('_a -> unit\) .Either make the arguments to 'x1' explicit or, if you do not intend for it to be generic, add a type annotation\.$ +//Value restriction: The value 'x1' has an inferred generic function type val x1: \('_a -> unit\)However, values cannot have generic type variables like '_a in "let f: '_a". You should define 'x1' as a function instead by doing one of the following:- Add an explicit parameter that is applied instead of using a partial application "let f param"- Add a unit parameter like "let f\(\)"- Write explicit type parameters like "let f<'a>"or if you do not intend for it to be generic, either:- Add an explicit type annotation like "let f : obj -> obj"- Apply arguments of non-generic types to the function value in later code for type inference like "do f\(\)"\.This error is because a let binding without parameters defines a value, not a function\. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results\.$ // We expect a value restriction here. The inferred signature is: // val x1: (?1 -> unit) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs index 2f90f8963c6..982ae0c820b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/SequenceExpressionTests.fs @@ -440,5 +440,6 @@ let typedSeq = |> typecheck |> shouldFail |> withErrorCode 30 - |> withDiagnosticMessageMatches "Value restriction. The value 'typedSeq' has been inferred to have generic type" + |> withDiagnosticMessageMatches "Value restriction: The value 'typedSeq' has an inferred generic type" + |> withDiagnosticMessageMatches "val typedSeq: '_a seq" \ No newline at end of file diff --git a/tests/fsharp/typecheck/sigs/neg119b.bsl b/tests/fsharp/typecheck/sigs/neg119b.bsl index e5edc502670..7a445f3ea7f 100644 --- a/tests/fsharp/typecheck/sigs/neg119b.bsl +++ b/tests/fsharp/typecheck/sigs/neg119b.bsl @@ -1,4 +1,11 @@ -neg119b.fs(40,9,40,17): typecheck error FS0030: Value restriction. The value 'res2n3n4' has been inferred to have generic type - val res2n3n4: ^_a when (^_b or Applicatives.ZipList or ^_a) : (static member (<*>) : ^_b * Applicatives.ZipList -> ^_a) and (^_c or obj or ^_b) : (static member (<*>) : ^_c * obj -> ^_b) and (Applicatives.Ap or ^_c) : (static member Return: ^_c * Applicatives.Ap -> ((int -> int -> int) -> ^_c)) -Either define 'res2n3n4' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation. +neg119b.fs(40,9,40,17): typecheck error FS0030: Value restriction: The value 'res2n3n4' has an inferred generic type + val res2n3n4: ^_a when (^_b or Applicatives.ZipList or ^_a) : (static member (<*>) : ^_b * Applicatives.ZipList -> ^_a) and (^_c or obj or ^_b) : (static member (<*>) : ^_c * obj -> ^_b) and (Applicatives.Ap or ^_c) : (static member Return: ^_c * Applicatives.Ap -> ((int -> int -> int) -> ^_c)) +However, values cannot have generic type variables like '_a in "let x: '_a". You can do one of the following: +- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1" +- Add an explicit type annotation like "let x : int" +- Use the value as a non-generic type in later code for type inference like "do x" +or if you still want type-dependent results, you can define 'res2n3n4' as a function instead by doing either: +- Add a unit parameter like "let x()" +- Write explicit type parameters like "let x<'a>". +This error is because a let binding without parameters defines a value, not a function. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results. diff --git a/tests/fsharpqa/Source/Conformance/Expressions/ExpressionQuotations/Baselines/E_Cast.fs b/tests/fsharpqa/Source/Conformance/Expressions/ExpressionQuotations/Baselines/E_Cast.fs index fdfeed0171e..bd3772bf30c 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/ExpressionQuotations/Baselines/E_Cast.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/ExpressionQuotations/Baselines/E_Cast.fs @@ -1,7 +1,6 @@ // #Regression #Conformance #Quotations // Verify type annotation is required for casting quotes -//Value restriction\. The value 'tq' has been inferred to have generic type. val tq: Expr<'_a> .Either define 'tq' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation\.$ -// +//Value restriction: The value 'tq' has an inferred generic type val tq: Expr<'_a>However, values cannot have generic type variables like '_a in "let x: '_a"\. You can do one of the following:- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"- Add an explicit type annotation like "let x : int"- Use the value as a non-generic type in later code for type inference like "do x"or if you still want type-dependent results, you can define 'tq' as a function instead by doing either:- Add a unit parameter like "let x\(\)"- Write explicit type parameters like "let x<'a>".This error is because a let binding without parameters defines a value, not a function\. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results\.$ open Microsoft.FSharp.Quotations diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_ValueRestriction01.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_ValueRestriction01.fs index d66cc047dc4..cf485b37d8c 100644 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_ValueRestriction01.fs +++ b/tests/fsharpqa/Source/Conformance/InferenceProcedures/ConstraintSolving/E_ValueRestriction01.fs @@ -3,13 +3,16 @@ // Verify error associated with open type variable -(* -error FS0030: Value restriction. The value 'x' has been inferred to have generic type - val x : '_a list ref -Either define 'x' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type constraint. -*) -//Value restriction. The value - +//Value restriction: The value 'x' has an inferred generic type +// val x: '_a list ref +//However, values cannot have generic type variables like '_a in "let x: '_a"\. You can do one of the following: +//- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1" +//- Add an explicit type annotation like "let x : int" +//- Use the value as a non-generic type in later code for type inference like "do x" +//or if you still want type-dependent results, you can define 'x' as a function instead by doing either: +//- Add a unit parameter like "let x()" +//- Write explicit type parameters like "let x<'a>"\. +//This error is because a let binding without parameters defines a value, not a function\. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results\.$ let x = ref [] exit 1 diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/DispatchSlotInference/E_GenInterfaceWGenMethods01.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/DispatchSlotInference/E_GenInterfaceWGenMethods01.fs index 5d87e71957e..8a65831546e 100644 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/DispatchSlotInference/E_GenInterfaceWGenMethods01.fs +++ b/tests/fsharpqa/Source/Conformance/InferenceProcedures/DispatchSlotInference/E_GenInterfaceWGenMethods01.fs @@ -1,7 +1,7 @@ // #Regression #Conformance #TypeInference // FSHARP1.0:1445. See also FSHARP1.0:4721 // Failure when generating code for generic interface with generic method -//Value restriction\. The value 'result' has been inferred to have generic type. val result: '_a array when '_a: equality and '_a: null .Either define 'result' as a simple data term, make it a function with explicit arguments or, if you do not intend for it to be generic, add a type annotation\.$ +//Value restriction: The value 'result' has an inferred generic type val result: '_a array when '_a: equality and '_a: nullHowever, values cannot have generic type variables like '_a in "let x: '_a"\. You can do one of the following:- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"- Add an explicit type annotation like "let x : int"- Use the value as a non-generic type in later code for type inference like "do x"or if you still want type-dependent results, you can define 'result' as a function instead by doing either:- Add a unit parameter like "let x\(\)"- Write explicit type parameters like "let x<'a>".This error is because a let binding without parameters defines a value, not a function\. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results\.$ type 'a IFoo = interface abstract DoStuff<'b> : 'a -> 'b array end diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/ValueRestriction/E_NotMemberOrFunction01.fsx b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/ValueRestriction/E_NotMemberOrFunction01.fsx index 182fb04be48..a33da54e3f9 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/ValueRestriction/E_NotMemberOrFunction01.fsx +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/ValueRestriction/E_NotMemberOrFunction01.fsx @@ -1,6 +1,6 @@ // #Conformance #ObjectOrientedTypes #Classes #TypeInference #ValueRestriction -//Value restriction\. The value 'x1' has been inferred to have generic type. val x1: \('_a -> unit\) .Either make the arguments to 'x1' explicit or, if you do not intend for it to be generic, add a type annotation\.$ +//Value restriction: The value 'x1' has an inferred generic function type val x1: \('_a -> unit\)However, values cannot have generic type variables like '_a in "let f: '_a". You should define 'x1' as a function instead by doing one of the following:- Add an explicit parameter that is applied instead of using a partial application "let f param"- Add a unit parameter like "let f\(\)"- Write explicit type parameters like "let f<'a>"or if you do not intend for it to be generic, either:- Add an explicit type annotation like "let f : obj -> obj"- Apply arguments of non-generic types to the function value in later code for type inference like "do f\(\)"\.This error is because a let binding without parameters defines a value, not a function\. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results\.$ // We expect a value restriction here. The inferred signature is: // val x1: (?1 -> unit) @@ -8,4 +8,4 @@ // variable could have feasibly be genrealized at 'x1' (c.f. the case above, where it // was generalized). let f1 (x:obj) = () -let x1 = ((); f1) \ No newline at end of file +let x1 = ((); f1) diff --git a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Diagnostics/W_NonGenVarInValueRestrictionWarning.fs b/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Diagnostics/W_NonGenVarInValueRestrictionWarning.fs index 12ca2be2ce8..6552aa57379 100644 --- a/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Diagnostics/W_NonGenVarInValueRestrictionWarning.fs +++ b/tests/fsharpqa/Source/Conformance/UnitsOfMeasure/Diagnostics/W_NonGenVarInValueRestrictionWarning.fs @@ -1,7 +1,7 @@ // #Regression #Conformance #UnitsOfMeasure #Diagnostics // Regression test for FSHARP1.0:4969 // Non-generalized unit-of-measure variables should display with "_" in value restriction warning -//.+val x: float<'_u> list ref -//.+val y: '_a list ref +//Value restriction: The value 'x' has an inferred generic type val x: float<'_u> list refHowever, values cannot have generic type variables like '_a in "let x: '_a"\. You can do one of the following:- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"- Add an explicit type annotation like "let x : int"- Use the value as a non-generic type in later code for type inference like "do x"or if you still want type-dependent results, you can define 'x' as a function instead by doing either:- Add a unit parameter like "let x\(\)"- Write explicit type parameters like "let x<'a>".This error is because a let binding without parameters defines a value, not a function\. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results\. +//Value restriction: The value 'y' has an inferred generic type val y: '_a list refHowever, values cannot have generic type variables like '_a in "let x: '_a"\. You can do one of the following:- Define it as a simple data term like an integer literal, a string literal or a union case like "let x = 1"- Add an explicit type annotation like "let x : int"- Use the value as a non-generic type in later code for type inference like "do x"or if you still want type-dependent results, you can define 'y' as a function instead by doing either:- Add a unit parameter like "let x\(\)"- Write explicit type parameters like "let x<'a>".This error is because a let binding without parameters defines a value, not a function\. Values cannot be generic because reading a value is assumed to result in the same everywhere but generic type parameters may invalidate this assumption by enabling type-dependent results\.$ let x = ref ([] : float<_> list) let y = ref ([] : _ list) From dd809e812addcdcd2615d920f4ab90c514f39779 Mon Sep 17 00:00:00 2001 From: Vlad Zarytovskii Date: Tue, 19 Dec 2023 15:37:19 +0100 Subject: [PATCH 06/10] Disabling 2 tests: running for too long, causing CI timeouts --- .../EmittedIL/VeryLargeClasses.fs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/VeryLargeClasses.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/VeryLargeClasses.fs index f8924fca551..8819cf27cdc 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/VeryLargeClasses.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/VeryLargeClasses.fs @@ -21,7 +21,7 @@ module VeryLargeClasses = type Type1 ={methods} """ - [] + [] let ``More than 64K Methods -- should fail`` () = classWithManyMethods (1024 * 64 + 1) |> compile @@ -30,7 +30,7 @@ module VeryLargeClasses = (Error 3864, Line 1, Col 1, Line 1, Col 1, "The type 'VeryLargeClassesTestcases.Type1' has too many methods. Found: '65537', maximum: '65520'") ] - [] + [] let ``Exactly (0xfff0) Methods -- should succeed`` () = FSharp """ From 75ff9a5bf57c3bed3cea70ecdeccf0e3822299aa Mon Sep 17 00:00:00 2001 From: SebastianAtWork Date: Tue, 19 Dec 2023 20:35:49 +0100 Subject: [PATCH 07/10] AddExplicitReturnType refactoring (#16077) --- .../src/FSharp.Editor/FSharp.Editor.fsproj | 1 + .../src/FSharp.Editor/FSharp.Editor.resx | 3 + .../FSharp.Editor/Refactor/AddReturnType.fs | 118 +++++ .../FSharp.Editor/xlf/FSharp.Editor.cs.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.de.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.es.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.fr.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.it.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.ja.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.ko.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.pl.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.ru.xlf | 5 + .../FSharp.Editor/xlf/FSharp.Editor.tr.xlf | 5 + .../xlf/FSharp.Editor.zh-Hans.xlf | 5 + .../xlf/FSharp.Editor.zh-Hant.xlf | 5 + .../FSharp.Editor.Tests.fsproj | 3 + .../Helpers/RoslynHelpers.fs | 5 + .../Refactors/AddReturnTypeTests.fs | 452 ++++++++++++++++++ .../Refactors/RefactorTestFramework.fs | 89 ++++ 20 files changed, 736 insertions(+) create mode 100644 vsintegration/src/FSharp.Editor/Refactor/AddReturnType.fs create mode 100644 vsintegration/tests/FSharp.Editor.Tests/Refactors/AddReturnTypeTests.fs create mode 100644 vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj index 60e86c9eb96..37bb02d43d2 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.fsproj @@ -99,6 +99,7 @@ + diff --git a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx index 41b80965895..ef5f05b3d24 100644 --- a/vsintegration/src/FSharp.Editor/FSharp.Editor.resx +++ b/vsintegration/src/FSharp.Editor/FSharp.Editor.resx @@ -353,6 +353,9 @@ Use live (unsaved) buffers for analysis Convert C# 'using' to F# 'open' + + Add return type annotation + Remove unnecessary parentheses diff --git a/vsintegration/src/FSharp.Editor/Refactor/AddReturnType.fs b/vsintegration/src/FSharp.Editor/Refactor/AddReturnType.fs new file mode 100644 index 00000000000..b3c586b445e --- /dev/null +++ b/vsintegration/src/FSharp.Editor/Refactor/AddReturnType.fs @@ -0,0 +1,118 @@ +namespace Microsoft.VisualStudio.FSharp.Editor + +open System.Composition +open FSharp.Compiler.CodeAnalysis +open FSharp.Compiler.Symbols +open FSharp.Compiler.Text + +open Microsoft.CodeAnalysis.Text +open Microsoft.CodeAnalysis.CodeRefactorings +open Microsoft.CodeAnalysis.CodeActions +open CancellableTasks + +[] +type internal AddReturnType [] () = + inherit CodeRefactoringProvider() + + static member isValidMethodWithoutTypeAnnotation + (symbolUse: FSharpSymbolUse) + (parseFileResults: FSharpParseFileResults) + (funcOrValue: FSharpMemberOrFunctionOrValue) + = + let typeAnnotationRange = + parseFileResults.TryRangeOfReturnTypeHint(symbolUse.Range.Start, false) + + let res = + funcOrValue.CompiledName = funcOrValue.DisplayName + && funcOrValue.IsFunction + && not (parseFileResults.IsBindingALambdaAtPosition symbolUse.Range.Start) + && not (funcOrValue.ReturnParameter.Type.IsUnresolved) + && not (parseFileResults.IsTypeAnnotationGivenAtPosition symbolUse.Range.Start) + && not typeAnnotationRange.IsNone + + match (res, typeAnnotationRange) with + | (true, Some tr) -> Some(funcOrValue, tr) + | (_, _) -> None + + static member refactor + (context: CodeRefactoringContext) + (memberFunc: FSharpMemberOrFunctionOrValue, typeRange: Range, symbolUse: FSharpSymbolUse) + = + let title = SR.AddReturnTypeAnnotation() + + let getChangedText (sourceText: SourceText) = + let returnType = memberFunc.ReturnParameter.Type + + let inferredType = + let res = returnType.Format symbolUse.DisplayContext + + if returnType.HasTypeDefinition then + res + else + $"({res})".Replace(" ", "") + + let textSpan = RoslynHelpers.FSharpRangeToTextSpan(sourceText, typeRange) + let textChange = TextChange(textSpan, $": {inferredType} ") + sourceText.WithChanges(textChange) + + let codeActionFunc = + cancellableTask { + let! cancellationToken = CancellableTask.getCancellationToken () + let! sourceText = context.Document.GetTextAsync(cancellationToken) + let changedText = getChangedText sourceText + + let newDocument = context.Document.WithText(changedText) + return newDocument + } + + let codeAction = CodeAction.Create(title, codeActionFunc, title) + + do context.RegisterRefactoring(codeAction) + + static member ofFSharpMemberOrFunctionOrValue(symbol: FSharpSymbol) = + match symbol with + | :? FSharpMemberOrFunctionOrValue as v -> Some v + | _ -> None + + override _.ComputeRefactoringsAsync context = + cancellableTask { + let document = context.Document + let position = context.Span.Start + let! sourceText = document.GetTextAsync() + let textLine = sourceText.Lines.GetLineFromPosition position + let textLinePos = sourceText.Lines.GetLinePosition position + let fcsTextLineNumber = Line.fromZ textLinePos.Line + + let! lexerSymbol = + document.TryFindFSharpLexerSymbolAsync(position, SymbolLookupKind.Greedy, false, false, nameof (AddReturnType)) + + let! (parseFileResults, checkFileResults) = document.GetFSharpParseAndCheckResultsAsync(nameof (AddReturnType)) + + let symbolUseOpt = + lexerSymbol + |> Option.bind (fun lexer -> + checkFileResults.GetSymbolUseAtLocation( + fcsTextLineNumber, + lexer.Ident.idRange.EndColumn, + textLine.ToString(), + lexer.FullIsland + )) + + let memberFuncOpt = + symbolUseOpt + |> Option.bind (fun sym -> sym.Symbol |> AddReturnType.ofFSharpMemberOrFunctionOrValue) + + match (symbolUseOpt, memberFuncOpt) with + | (Some symbolUse, Some memberFunc) -> + let isValidMethod = + memberFunc + |> AddReturnType.isValidMethodWithoutTypeAnnotation symbolUse parseFileResults + + match isValidMethod with + | Some(memberFunc, typeRange) -> do AddReturnType.refactor context (memberFunc, typeRange, symbolUse) + | None -> () + | _ -> () + + return () + } + |> CancellableTask.startAsTask context.CancellationToken diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf index 7f90ad6a126..b4ad96704a9 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.cs.xlf @@ -22,6 +22,11 @@ Přidejte klíčové slovo new. + + Add return type annotation + Add return type annotation + + Add type annotation Přidat anotaci typu diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf index 5e5261ef993..7796b6a2fe9 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.de.xlf @@ -22,6 +22,11 @@ Schlüsselwort "new" hinzufügen + + Add return type annotation + Add return type annotation + + Add type annotation Typanmerkung hinzufügen diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf index f130a461216..c8c15573014 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.es.xlf @@ -22,6 +22,11 @@ Agregar "nueva" palabra clave + + Add return type annotation + Add return type annotation + + Add type annotation Agregar una anotación de tipo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf index a3bc317a6af..c0076a1473e 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.fr.xlf @@ -22,6 +22,11 @@ Ajouter le mot clé 'new' + + Add return type annotation + Add return type annotation + + Add type annotation Ajouter une annotation de type diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf index 45fbdd6637c..fc95d16b038 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.it.xlf @@ -22,6 +22,11 @@ Aggiungi la parola chiave 'new' + + Add return type annotation + Add return type annotation + + Add type annotation Aggiungere l'annotazione di tipo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf index 09a35c432c9..74d787d914b 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ja.xlf @@ -22,6 +22,11 @@ 'new' キーワードを追加する + + Add return type annotation + Add return type annotation + + Add type annotation 型の注釈の追加 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf index 32499ff0771..816da89d7d7 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ko.xlf @@ -22,6 +22,11 @@ 'new' 키워드 추가 + + Add return type annotation + Add return type annotation + + Add type annotation 형식 주석 추가 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf index 589adf994b9..f0645a7a1b3 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pl.xlf @@ -22,6 +22,11 @@ Dodaj słowo kluczowe „new” + + Add return type annotation + Add return type annotation + + Add type annotation Dodaj adnotację typu diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf index 8234f5190c7..7c05c537e39 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.pt-BR.xlf @@ -22,6 +22,11 @@ Adicionar a palavra-chave 'new' + + Add return type annotation + Add return type annotation + + Add type annotation Adicionar uma anotação de tipo diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf index d6447a61572..53d05e963f3 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.ru.xlf @@ -22,6 +22,11 @@ Добавить ключевое слово "new" + + Add return type annotation + Add return type annotation + + Add type annotation Добавить заметку типа diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf index 56c3ca4e2d4..d8047f179af 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.tr.xlf @@ -22,6 +22,11 @@ 'new' anahtar sözcüğünü ekleme + + Add return type annotation + Add return type annotation + + Add type annotation Tür ek açıklaması ekle diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf index 80d8c8362cc..7f0aeefc86f 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hans.xlf @@ -22,6 +22,11 @@ 添加“新”关键字 + + Add return type annotation + Add return type annotation + + Add type annotation 添加类型注释 diff --git a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf index 31b2ea7cec2..8e5de2d10a5 100644 --- a/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf +++ b/vsintegration/src/FSharp.Editor/xlf/FSharp.Editor.zh-Hant.xlf @@ -22,6 +22,11 @@ 新增 'new' 關鍵字 + + Add return type annotation + Add return type annotation + + Add type annotation 新增型別註解 diff --git a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj index 77ce57f27e0..a180accc43f 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj +++ b/vsintegration/tests/FSharp.Editor.Tests/FSharp.Editor.Tests.fsproj @@ -12,6 +12,7 @@ + @@ -71,6 +72,8 @@ + + diff --git a/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs b/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs index a0853ed83b9..ca113f72bf3 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/Helpers/RoslynHelpers.fs @@ -304,6 +304,11 @@ type RoslynTestHelpers private () = let document = project.Documents |> Seq.exactlyOne document + static member GetLastDocument(solution: Solution) = + let project = solution.Projects |> Seq.exactlyOne + let document = project.Documents |> Seq.last + document + static member CreateSolution(syntheticProject: SyntheticProject) = let checker = syntheticProject.SaveAndCheck() diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddReturnTypeTests.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddReturnTypeTests.fs new file mode 100644 index 00000000000..5b81fb996da --- /dev/null +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/AddReturnTypeTests.fs @@ -0,0 +1,452 @@ +module FSharp.Editor.Tests.Refactors.AddReturnTypeTests + +open Microsoft.VisualStudio.FSharp.Editor +open Xunit +open FSharp.Editor.Tests.Refactors.RefactorTestFramework +open FSharp.Test.ProjectGeneration +open FSharp.Editor.Tests.Helpers + +[] +[] +[] +[] +[] +let ``Refactor should not trigger`` (shouldNotTrigger: string) = + let symbolName = "sum" + + let code = + $""" +let sum a b {shouldNotTrigger}= a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let actions = tryGetRefactoringActions code spanStart context (new AddReturnType()) + + do Assert.Empty(actions) + +[] +let ``Refactor should not trigger on values`` () = + let symbolName = "example2" + + let code = + """ +let example2 = 42 // value + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let actions = tryGetRefactoringActions code spanStart context (new AddReturnType()) + + do Assert.Empty(actions) + +[] +let ``Refactor should not trigger on member values`` () = + let symbolName = "SomeProp" + + let code = + """ +type Example3() = + member _.SomeProp = 42 // property + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let actions = tryGetRefactoringActions code spanStart context (new AddReturnType()) + + do Assert.Empty(actions) + +[] +let ``Correctly infer int as return type`` () = + let symbolName = "sum" + + let code = + """ +let sum a b = a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +let sum a b : int = a + b + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Correctly infer on next line arguments`` () = + let symbolName = "sum" + + let code = + """ +let sum + x y = + x + y + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +let sum + x y : int = + x + y + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Should not throw exception when binding another method`` () = + let symbolName = "addThings" + + let code = + """ +let add (x:int) (y:int) = (float(x + y)) + 0.1 +let addThings = add + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +let add (x:int) (y:int) = (float(x + y)) + 0.1 +let addThings : (int->int->float) = add + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Handle parantheses on the arguments`` () = + let symbolName = "sum" + + let code = + """ +let sum (a:float) (b:float) = a + b + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + """ +let sum (a:float) (b:float) : float = a + b + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Infer on rec method`` () = + let symbolName = "fib" + + let code = + $""" +let rec fib n = + if n < 2 then 1 + else fib (n - 1) + fib (n - 2) + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +let rec fib n : int = + if n < 2 then 1 + else fib (n - 1) + fib (n - 2) + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Infer with function parameter method`` () = + let symbolName = "apply1" + + let code = + $""" +let apply1 (transform: int -> int) y = transform y + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +let apply1 (transform: int -> int) y : int = transform y + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Infer on member function`` () = + let symbolName = "SomeMethod" + + let code = + $""" +type SomeType(factor0: int) = + let factor = factor0 + member this.SomeMethod(a, b, c) = (a + b + c) * factor + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +type SomeType(factor0: int) = + let factor = factor0 + member this.SomeMethod(a, b, c) : int = (a + b + c) * factor + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Binding another function doesnt crash`` () = + let symbolName = "getNow" + + let code = + $""" +let getNow() = + System.DateTime.Now + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +let getNow() : System.DateTime = + System.DateTime.Now + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Handle already existing opens for DateTime`` () = + let symbolName = "getNow" + + let code = + $""" +open System + +let getNow() = + DateTime.Now + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +open System + +let getNow() : DateTime = + DateTime.Now + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Binding linq function doesnt crash`` () = + let symbolName = "skip1" + + let code = + $""" +let skip1 elements = + System.Linq.Enumerable.Skip(elements, 1) + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +let skip1 elements : System.Collections.Generic.IEnumerable<'a> = + System.Linq.Enumerable.Skip(elements, 1) + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Handle already existing opens on Linq`` () = + let symbolName = "skip1" + + let code = + $""" +open System + +let skip1 elements = + Linq.Enumerable.Skip(elements, 1) + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +open System + +let skip1 elements : Collections.Generic.IEnumerable<'a> = + Linq.Enumerable.Skip(elements, 1) + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Handle already existing opens on Enumerable`` () = + let symbolName = "skip1" + + let code = + $""" +open System +open System.Linq + +let skip1 elements = + Enumerable.Skip(elements, 1) + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + $""" +open System +open System.Linq + +let skip1 elements : Collections.Generic.IEnumerable<'a> = + Enumerable.Skip(elements, 1) + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Correctly infer custom type that is declared earlier in file`` () = + let symbolName = "sum" + + let code = + """ +type MyType = { Value: int } +let sum a b = {Value=a+b} + """ + + use context = TestContext.CreateWithCode code + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + """ +type MyType = { Value: int } +let sum a b : MyType = {Value=a+b} + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode, resultText.ToString()) + +[] +let ``Correctly infer custom type that is declared earlier in project`` () = + let symbolName = "sum" + + let myModule = + """ +module ModuleFirst +type MyType = { Value: int } + """ + + let code = + """ +module ModuleSecond + +open ModuleFirst + +let sum a b = {Value=a+b} + """ + + let project = + { SyntheticProject.Create( + { sourceFile "First" [] with + Source = myModule + }, + { sourceFile "Second" [ "First" ] with + Source = code + } + ) with + AutoAddModules = false + } + + let solution, _ = RoslynTestHelpers.CreateSolution project + let context = new TestContext(solution) + + let spanStart = code.IndexOf symbolName + + let newDoc = tryRefactor code spanStart context (new AddReturnType()) + + let expectedCode = + """ +module ModuleSecond + +open ModuleFirst + +let sum a b : MyType = {Value=a+b} + """ + + let resultText = newDoc.GetTextAsync() |> GetTaskResult + Assert.Equal(expectedCode.Trim(' ', '\r', '\n'), resultText.ToString().Trim(' ', '\r', '\n')) diff --git a/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs new file mode 100644 index 00000000000..849da8c84ec --- /dev/null +++ b/vsintegration/tests/FSharp.Editor.Tests/Refactors/RefactorTestFramework.fs @@ -0,0 +1,89 @@ +module FSharp.Editor.Tests.Refactors.RefactorTestFramework + +open System +open System.Linq +open System.Collections.Generic + +open Microsoft.CodeAnalysis +open Microsoft.CodeAnalysis.Text +open Microsoft.VisualStudio.FSharp.Editor.CancellableTasks + +open FSharp.Editor.Tests.Helpers +open Microsoft.CodeAnalysis.CodeRefactorings +open Microsoft.CodeAnalysis.CodeActions +open System.Threading + +let GetTaskResult (task: Tasks.Task<'T>) = task.GetAwaiter().GetResult() + +type TestContext(Solution: Solution) = + let mutable _solution = Solution + member _.CancellationToken = CancellationToken.None + + member _.Solution + with set value = _solution <- value + and get () = _solution + + interface IDisposable with + member _.Dispose() = Solution.Workspace.Dispose() + + static member CreateWithCode(code: string) = + let solution = RoslynTestHelpers.CreateSolution(code) + new TestContext(solution) + + static member CreateWithCodeAndDependency (code: string) (codeForPreviousFile: string) = + let mutable solution = RoslynTestHelpers.CreateSolution(codeForPreviousFile) + + let firstProject = solution.Projects.First() + solution <- solution.AddDocument(DocumentId.CreateNewId(firstProject.Id), "test2.fs", code, filePath = "C:\\test2.fs") + + new TestContext(solution) + +let tryRefactor (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = + cancellableTask { + let mutable action: CodeAction = null + let existingDocument = RoslynTestHelpers.GetLastDocument context.Solution + + context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) + + let document = RoslynTestHelpers.GetLastDocument context.Solution + + let mutable workspace = context.Solution.Workspace + + let refactoringContext = + CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> action <- a), context.CancellationToken) + + do! refactorProvider.ComputeRefactoringsAsync refactoringContext + + let! operations = action.GetOperationsAsync context.CancellationToken + + for operation in operations do + let codeChangeOperation = operation :?> ApplyChangesOperation + codeChangeOperation.Apply(workspace, context.CancellationToken) + context.Solution <- codeChangeOperation.ChangedSolution + () + + let newDocument = context.Solution.GetDocument(document.Id) + return newDocument + + } + |> CancellableTask.startWithoutCancellation + |> GetTaskResult + +let tryGetRefactoringActions (code: string) (cursorPosition) (context: TestContext) (refactorProvider: 'T :> CodeRefactoringProvider) = + cancellableTask { + let refactoringActions = new List() + let existingDocument = RoslynTestHelpers.GetLastDocument context.Solution + + context.Solution <- context.Solution.WithDocumentText(existingDocument.Id, SourceText.From(code)) + + let document = RoslynTestHelpers.GetLastDocument context.Solution + + let refactoringContext = + CodeRefactoringContext(document, TextSpan(cursorPosition, 1), (fun a -> refactoringActions.Add a), context.CancellationToken) + + do! refactorProvider.ComputeRefactoringsAsync refactoringContext + + return refactoringActions + } + |> CancellableTask.startWithoutCancellation + |> fun task -> task.Result From 1df143300c889a3a1f6fb72a27a81842bd2b7859 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Tue, 19 Dec 2023 21:40:59 +0100 Subject: [PATCH 08/10] Name resolution: resolve interfaces in expressions (#15660) * Name resolution: don't create fake items for interfaces * More experiments * Tweak nameof * Update baselines * Record special occurrence kind * Add tests * Fantomas * Cleanup * Rename --- src/Compiler/Checking/CheckExpressions.fs | 66 +++++++------ src/Compiler/Checking/NameResolution.fs | 97 +++++++++++-------- src/Compiler/Checking/NameResolution.fsi | 4 +- src/Compiler/Service/FSharpCheckerResults.fs | 5 +- src/Compiler/Service/ItemKey.fs | 1 - .../Service/SemanticClassification.fs | 2 - .../Service/ServiceDeclarationLists.fs | 22 +---- src/Compiler/Symbols/SymbolHelpers.fs | 13 +-- src/Compiler/Symbols/Symbols.fs | 1 - tests/fsharp/typecheck/sigs/neg06.bsl | 16 +-- .../E_InvalidRecursiveGeneric01.fs | 2 +- .../E_InvalidRecursiveGeneric02.fs | 2 +- .../StructTypes/E_StructConstruction03.fs | 4 +- tests/service/Symbols.fs | 26 +++++ 14 files changed, 139 insertions(+), 122 deletions(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 98138270658..cf1b9bce32a 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -7011,31 +7011,34 @@ and TcObjectExpr (cenv: cenv) env tpenv (objTy, realObjTy, argopt, binds, extraI TcRecordConstruction cenv objTy true env tpenv None objTy fldsList mWholeExpr else - let item = ForceRaise (ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mObjTy ad objTy) + let ctorCall, baseIdOpt, tpenv = + if isInterfaceTy g objTy then + match argopt with + | None -> + BuildObjCtorCall g mWholeExpr, None, tpenv + | Some _ -> + error(Error(FSComp.SR.tcConstructorForInterfacesDoNotTakeArguments(), mNewExpr)) + else + let item = ForceRaise (ResolveObjectConstructor cenv.nameResolver env.DisplayEnv mObjTy ad objTy) - if isFSharpObjModelTy g objTy && GetCtorShapeCounter env = 1 then - error(Error(FSComp.SR.tcObjectsMustBeInitializedWithObjectExpression(), mNewExpr)) + if isFSharpObjModelTy g objTy && GetCtorShapeCounter env = 1 then + error(Error(FSComp.SR.tcObjectsMustBeInitializedWithObjectExpression(), mNewExpr)) - let ctorCall, baseIdOpt, tpenv = - match item, argopt with - | Item.CtorGroup(methodName, minfos), Some (arg, baseIdOpt) -> - let meths = minfos |> List.map (fun minfo -> minfo, None) - let afterResolution = ForNewConstructors cenv.tcSink env mObjTy methodName minfos - let ad = env.AccessRights - - let expr, tpenv = TcMethodApplicationThen cenv env (MustEqual objTy) None tpenv None [] mWholeExpr mObjTy methodName ad PossiblyMutates false meths afterResolution CtorValUsedAsSuperInit [arg] ExprAtomicFlag.Atomic None [] - // The 'base' value is always bound - let baseIdOpt = (match baseIdOpt with None -> Some(ident("base", mObjTy)) | Some id -> Some id) - expr, baseIdOpt, tpenv - | Item.FakeInterfaceCtor intfTy, None -> - UnifyTypes cenv env mWholeExpr objTy intfTy - let expr = BuildObjCtorCall g mWholeExpr - expr, None, tpenv - | Item.FakeInterfaceCtor _, Some _ -> - error(Error(FSComp.SR.tcConstructorForInterfacesDoNotTakeArguments(), mNewExpr)) - | Item.CtorGroup _, None -> - error(Error(FSComp.SR.tcConstructorRequiresArguments(), mNewExpr)) - | _ -> error(Error(FSComp.SR.tcNewRequiresObjectConstructor(), mNewExpr)) + match item, argopt with + | Item.CtorGroup(methodName, minfos), Some (arg, baseIdOpt) -> + let meths = minfos |> List.map (fun minfo -> minfo, None) + let afterResolution = ForNewConstructors cenv.tcSink env mObjTy methodName minfos + let ad = env.AccessRights + + let expr, tpenv = TcMethodApplicationThen cenv env (MustEqual objTy) None tpenv None [] mWholeExpr mObjTy methodName ad PossiblyMutates false meths afterResolution CtorValUsedAsSuperInit [arg] ExprAtomicFlag.Atomic None [] + // The 'base' value is always bound + let baseIdOpt = (match baseIdOpt with None -> Some(ident("base", mObjTy)) | Some id -> Some id) + expr, baseIdOpt, tpenv + + | Item.CtorGroup _, None -> + error(Error(FSComp.SR.tcConstructorRequiresArguments(), mNewExpr)) + + | _ -> error(Error(FSComp.SR.tcNewRequiresObjectConstructor(), mNewExpr)) let baseValOpt = MakeAndPublishBaseVal cenv env baseIdOpt objTy let env = Option.foldBack (AddLocalVal g cenv.tcSink mNewExpr) baseValOpt env @@ -8141,8 +8144,11 @@ and TcNameOfExpr (cenv: cenv) env tpenv (synArg: SynExpr) = when (match item with | Item.DelegateCtor _ - | Item.CtorGroup _ - | Item.FakeInterfaceCtor _ -> false + | Item.CtorGroup _ -> false + | Item.Types _ when delayed.IsEmpty -> + match delayed with + | [] | [DelayedTypeApp _] -> false + | _ -> true | _ -> true) -> let overallTy = match overallTyOpt with None -> MustEqual (NewInferenceType g) | Some t -> t let _, _ = TcItemThen cenv overallTy env tpenv res None delayed @@ -8374,9 +8380,6 @@ and TcItemThen (cenv: cenv) (overallTy: OverallTy) env tpenv (tinstEnclosing, it | Item.CtorGroup(nm, minfos) -> TcCtorItemThen cenv overallTy env item nm minfos tinstEnclosing tpenv mItem afterResolution delayed - | Item.FakeInterfaceCtor _ -> - error(Error(FSComp.SR.tcInvalidUseOfInterfaceType(), mItem)) - | Item.ImplicitOp(id, sln) -> TcImplicitOpItemThen cenv overallTy env id sln tpenv mItem delayed @@ -8614,7 +8617,10 @@ and TcTypeItemThen (cenv: cenv) overallTy env nm ty tpenv mItem tinstEnclosing d // In this case the type is not generic, and indeed we should never have returned Item.Types. // That's because ResolveTypeNamesToCtors should have been set at the original // call to ResolveLongIdentAsExprAndComputeRange - error(Error(FSComp.SR.tcInvalidUseOfTypeName(), mItem)) + if isInterfaceTy g ty then + error(Error(FSComp.SR.tcInvalidUseOfInterfaceType(), mItem)) + else + error(Error(FSComp.SR.tcInvalidUseOfTypeName(), mItem)) and TcMethodItemThen (cenv: cenv) overallTy env item methodName minfos tpenv mItem afterResolution staticTyOpt delayed = let ad = env.eAccessRights @@ -9305,7 +9311,7 @@ and TcLookupItemThen cenv overallTy env tpenv mObjExpr objExpr objExprTy delayed | Item.Trait traitInfo -> TcTraitItemThen cenv overallTy env (Some objExpr) traitInfo tpenv mItem delayed - | Item.FakeInterfaceCtor _ | Item.DelegateCtor _ -> error (Error (FSComp.SR.tcConstructorsCannotBeFirstClassValues(), mItem)) + | Item.DelegateCtor _ -> error (Error (FSComp.SR.tcConstructorsCannotBeFirstClassValues(), mItem)) // These items are not expected here - they can't be the result of a instance member dot-lookup "expr.Ident" | Item.ActivePatternResult _ diff --git a/src/Compiler/Checking/NameResolution.fs b/src/Compiler/Checking/NameResolution.fs index 7b660d3d21d..5afdada9b05 100644 --- a/src/Compiler/Checking/NameResolution.fs +++ b/src/Compiler/Checking/NameResolution.fs @@ -201,9 +201,6 @@ type Item = /// Represents the resolution of a name to a constructor | CtorGroup of string * MethInfo list - /// Represents the resolution of a name to the fake constructor simulated for an interface type. - | FakeInterfaceCtor of TType - /// Represents the resolution of a name to a delegate | DelegateCtor of TType @@ -276,8 +273,7 @@ type Item = | ValueSome tcref -> tcref.DisplayNameCore | _ -> nm |> DemangleGenericTypeName - | Item.CtorGroup(nm, _) -> nm |> DemangleGenericTypeName - | Item.FakeInterfaceCtor ty + | Item.CtorGroup(nm, _) -> nm |> DemangleGenericTypeName | Item.DelegateCtor ty -> match ty with | AbbrevOrAppTy tcref -> tcref.DisplayNameCore @@ -1713,6 +1709,8 @@ type ItemOccurence = | RelatedText /// This is a usage of a module or namespace name in open statement | Open + /// Not permitted item uses like interface names used as expressions + | InvalidUse type FormatStringCheckContext = { SourceText: ISourceText @@ -1786,8 +1784,7 @@ let (|EntityUse|_|) (item: Item) = | Item.UnqualifiedType (tcref :: _) -> Some tcref | Item.ExnCase tcref -> Some tcref | Item.Types(_, [AbbrevOrAppTy tcref]) - | Item.DelegateCtor(AbbrevOrAppTy tcref) - | Item.FakeInterfaceCtor(AbbrevOrAppTy tcref) -> Some tcref + | Item.DelegateCtor(AbbrevOrAppTy tcref) -> Some tcref | Item.CtorGroup(_, ctor :: _) -> match ctor.ApparentEnclosingType with | AbbrevOrAppTy tcref -> Some tcref @@ -2229,7 +2226,6 @@ let CheckAllTyparsInferrable amap m item = | Item.Trait _ | Item.CtorGroup _ - | Item.FakeInterfaceCtor _ | Item.DelegateCtor _ | Item.Types _ | Item.ModuleOrNamespaces _ @@ -2470,7 +2466,8 @@ let private ResolveObjectConstructorPrim (ncenv: NameResolver) edenv resInfo m a else let ctorInfos = GetIntrinsicConstructorInfosOfType ncenv.InfoReader m ty if isNil ctorInfos && isInterfaceTy g ty then - success (resInfo, Item.FakeInterfaceCtor ty) + let tcref = tcrefOfAppTy g ty + success (resInfo, Item.Types(tcref.DisplayName, [ty])) else let defaultStructCtorInfo = if (not (ctorInfos |> List.exists (fun x -> x.IsNullary)) && @@ -3070,33 +3067,49 @@ let rec ResolveExprLongIdentPrim sink (ncenv: NameResolver) first fullyQualified match AtMostOneResult m innerSearch with | Result _ as res -> res | _ -> - let failingCase = - match typeError with - | Some e -> raze e - | _ -> - let suggestNamesAndTypes (addToBuffer: string -> unit) = - for e in nenv.eUnqualifiedItems do - if canSuggestThisItem e.Value then - addToBuffer e.Value.DisplayName - - for e in nenv.TyconsByDemangledNameAndArity fullyQualified do - if IsEntityAccessible ncenv.amap m ad e.Value then - addToBuffer e.Value.DisplayName - - for kv in nenv.ModulesAndNamespaces fullyQualified do - for modref in kv.Value do - if IsEntityAccessible ncenv.amap m ad modref then - addToBuffer modref.DisplayName - - // check if the user forgot to use qualified access - for e in nenv.eTyconsByDemangledNameAndArity do - let hasRequireQualifiedAccessAttribute = HasFSharpAttribute ncenv.g ncenv.g.attrib_RequireQualifiedAccessAttribute e.Value.Attribs - if hasRequireQualifiedAccessAttribute then - if e.Value.IsUnionTycon && e.Value.UnionCasesArray |> Array.exists (fun c -> c.LogicalName = id.idText) then - addToBuffer (e.Value.DisplayName + "." + id.idText) - - raze (UndefinedName(0, FSComp.SR.undefinedNameValueOfConstructor, id, suggestNamesAndTypes)) - failingCase + + match typeError with + | Some e -> raze e + | _ -> + + let tyconSearch () = + let tcrefs = LookupTypeNameInEnvNoArity fullyQualified id.idText nenv + if isNil tcrefs then NoResultsOrUsefulErrors else + + let tcrefs = ResolveUnqualifiedTyconRefs nenv tcrefs + let typeNameResInfo = TypeNameResolutionInfo.ResolveToTypeRefs typeNameResInfo.StaticArgsInfo + CheckForTypeLegitimacyAndMultipleGenericTypeAmbiguities (tcrefs, typeNameResInfo, PermitDirectReferenceToGeneratedType.No, unionRanges m id.idRange) + |> CollectResults success + + match tyconSearch () with + | Result ((resInfo, tcref) :: _) -> + let item = Item.Types(id.idText, [ generalizedTyconRef ncenv.g tcref ]) + success (resInfo, item) + | _ -> + + let suggestNamesAndTypes (addToBuffer: string -> unit) = + for e in nenv.eUnqualifiedItems do + if canSuggestThisItem e.Value then + addToBuffer e.Value.DisplayName + + for e in nenv.TyconsByDemangledNameAndArity fullyQualified do + if IsEntityAccessible ncenv.amap m ad e.Value then + addToBuffer e.Value.DisplayName + + for kv in nenv.ModulesAndNamespaces fullyQualified do + for modref in kv.Value do + if IsEntityAccessible ncenv.amap m ad modref then + addToBuffer modref.DisplayName + + // check if the user forgot to use qualified access + for e in nenv.eTyconsByDemangledNameAndArity do + let hasRequireQualifiedAccessAttribute = HasFSharpAttribute ncenv.g ncenv.g.attrib_RequireQualifiedAccessAttribute e.Value.Attribs + if hasRequireQualifiedAccessAttribute then + if e.Value.IsUnionTycon && e.Value.UnionCasesArray |> Array.exists (fun c -> c.LogicalName = id.idText) then + addToBuffer (e.Value.DisplayName + "." + id.idText) + + raze (UndefinedName(0, FSComp.SR.undefinedNameValueOfConstructor, id, suggestNamesAndTypes)) + match res with | Exception e -> raze e | Result (resInfo, item) -> @@ -3997,6 +4010,11 @@ let NeedsWorkAfterResolution namedItem = | Item.ActivePatternCase apref -> not (List.isEmpty apref.ActivePatternVal.Typars) | _ -> false +let isWrongItemInExpr item = + match item with + | Item.Types _ -> true + | _ -> false + /// Specifies additional work to do after an item has been processed further in type checking. [] type AfterResolution = @@ -4059,6 +4077,11 @@ let ResolveLongIdentAsExprAndComputeRange (sink: TcResultsSink) (ncenv: NameReso | Some _ -> if NeedsWorkAfterResolution item then AfterResolution.RecordResolution(None, (fun tpinst -> callSink(item, tpinst)), callSinkWithSpecificOverload, (fun () -> callSink (item, emptyTyparInst))) + + elif isWrongItemInExpr item then + CallNameResolutionSink sink (itemRange, nenv, item, emptyTyparInst, ItemOccurence.InvalidUse, ad) + AfterResolution.DoNothing + else callSink (item, emptyTyparInst) AfterResolution.DoNothing @@ -4500,7 +4523,6 @@ let InfosForTyconConstructors (ncenv: NameResolver) m ad (tcref: TyconRef) = match ResolveObjectConstructor ncenv (DisplayEnv.Empty g) m ad ty with | Result item -> match item with - | Item.FakeInterfaceCtor _ -> None | Item.CtorGroup(nm, ctorInfos) -> let ctors = ctorInfos @@ -5301,7 +5323,6 @@ let rec GetCompletionForItem (ncenv: NameResolver) (nenv: NameResolutionEnv) m a | _ -> () | Item.DelegateCtor _ - | Item.FakeInterfaceCtor _ | Item.CtorGroup _ | Item.UnqualifiedType _ -> for tcref in nenv.TyconsByDemangledNameAndArity(OpenQualified).Values do diff --git a/src/Compiler/Checking/NameResolution.fsi b/src/Compiler/Checking/NameResolution.fsi index 3ba5113b004..43cfdd12d5c 100755 --- a/src/Compiler/Checking/NameResolution.fsi +++ b/src/Compiler/Checking/NameResolution.fsi @@ -94,9 +94,6 @@ type Item = /// Represents the resolution of a name to a constructor | CtorGroup of string * MethInfo list - /// Represents the resolution of a name to the fake constructor simulated for an interface type. - | FakeInterfaceCtor of TType - /// Represents the resolution of a name to a delegate | DelegateCtor of TType @@ -385,6 +382,7 @@ type internal ItemOccurence = | Implemented | RelatedText | Open + | InvalidUse /// Check for equality, up to signature matching val ItemsAreEffectivelyEqual: TcGlobals -> Item -> Item -> bool diff --git a/src/Compiler/Service/FSharpCheckerResults.fs b/src/Compiler/Service/FSharpCheckerResults.fs index 2391f26655f..37ae0083298 100644 --- a/src/Compiler/Service/FSharpCheckerResults.fs +++ b/src/Compiler/Service/FSharpCheckerResults.fs @@ -483,6 +483,8 @@ type internal TypeCheckInfo // // If we're looking for members using a residue, we'd expect only // a single item (pick the first one) and we need the residue (which may be "") + | CNR(_, ItemOccurence.InvalidUse, _, _, _, _) :: _, _ -> NameResResult.Empty + | CNR(Item.Types(_, ty :: _), _, denv, nenv, ad, m) :: _, Some _ -> let targets = ResolveCompletionTargets.All(ConstraintSolver.IsApplicableMethApprox g amap m) @@ -891,7 +893,6 @@ type internal TypeCheckInfo let CompletionItem (ty: TyconRef voption) (assemblySymbol: AssemblySymbol voption) (item: ItemWithInst) = let kind = match item.Item with - | Item.FakeInterfaceCtor _ | Item.DelegateCtor _ | Item.CtorGroup _ -> CompletionItemKind.Method false | Item.MethodGroup(_, minfos, _) -> @@ -1802,7 +1803,6 @@ type internal TypeCheckInfo match d.Item with | Item.Types(_, AbbrevOrAppTy tcref :: _) -> 1 + tcref.TyparsNoRange.Length // Put delegate ctors after types, sorted by #typars. RemoveDuplicateItems will remove FakeInterfaceCtor and DelegateCtor if an earlier type is also reported with this name - | Item.FakeInterfaceCtor(AbbrevOrAppTy tcref) | Item.DelegateCtor(AbbrevOrAppTy tcref) -> 1000 + tcref.TyparsNoRange.Length // Put type ctors after types, sorted by #typars. RemoveDuplicateItems will remove DefaultStructCtors if a type is also reported with this name | Item.CtorGroup(_, cinfo :: _) -> 1000 + 10 * cinfo.DeclaringTyconRef.TyparsNoRange.Length @@ -1822,7 +1822,6 @@ type internal TypeCheckInfo | Item.Types(_, AbbrevOrAppTy tcref :: _) | Item.ExnCase tcref -> tcref.LogicalName | Item.UnqualifiedType(tcref :: _) - | Item.FakeInterfaceCtor(AbbrevOrAppTy tcref) | Item.DelegateCtor(AbbrevOrAppTy tcref) -> tcref.CompiledName | Item.CtorGroup(_, cinfo :: _) -> cinfo.ApparentEnclosingTyconRef.CompiledName | _ -> d.Item.DisplayName) diff --git a/src/Compiler/Service/ItemKey.fs b/src/Compiler/Service/ItemKey.fs index daf6a28f544..7a904a235ed 100644 --- a/src/Compiler/Service/ItemKey.fs +++ b/src/Compiler/Service/ItemKey.fs @@ -562,7 +562,6 @@ and [] ItemKeyStoreBuilder(tcGlobals: TcGlobals) = // We should consider writing ItemKey for each of these | Item.OtherName _ -> () - | Item.FakeInterfaceCtor _ -> () | Item.CustomOperation _ -> () | Item.CustomBuilder _ -> () | Item.ImplicitOp _ -> () diff --git a/src/Compiler/Service/SemanticClassification.fs b/src/Compiler/Service/SemanticClassification.fs index 75516028fdf..6ebbb3c8ae0 100644 --- a/src/Compiler/Service/SemanticClassification.fs +++ b/src/Compiler/Service/SemanticClassification.fs @@ -287,8 +287,6 @@ module TcResolutionsExtensions = | Item.DelegateCtor _, _, m -> add m SemanticClassificationType.ConstructorForReferenceType - | Item.FakeInterfaceCtor _, _, m -> add m SemanticClassificationType.ConstructorForReferenceType - | Item.MethodGroup(_, minfos, _), _, m -> match minfos with | [] -> add m SemanticClassificationType.Method diff --git a/src/Compiler/Service/ServiceDeclarationLists.fs b/src/Compiler/Service/ServiceDeclarationLists.fs index 1b955ead042..14b506bff86 100644 --- a/src/Compiler/Service/ServiceDeclarationLists.fs +++ b/src/Compiler/Service/ServiceDeclarationLists.fs @@ -358,19 +358,7 @@ module DeclarationListHelpers = | Item.CtorGroup(_, minfos) | Item.MethodGroup(_, minfos, _) -> FormatOverloadsToList infoReader m denv item minfos symbol width - - // The 'fake' zero-argument constructors of .NET interfaces. - // This ideally should never appear in intellisense, but we do get here in repros like: - // type IFoo = abstract F : int - // type II = IFoo // remove 'type II = ' and quickly hover over IFoo before it gets squiggled for 'invalid use of interface type' - // and in that case we'll just show the interface type name. - | Item.FakeInterfaceCtor ty -> - let ty, _ = PrettyTypes.PrettifyType g ty - let layout = NicePrint.layoutTyconRef denv (tcrefOfAppTy g ty) - let layout = PrintUtilities.squashToWidth width layout - let layout = toArray layout - ToolTipElement.Single(layout, xml, ?symbol = symbol) - + // The 'fake' representation of constructors of .NET delegate types | Item.DelegateCtor delTy -> let delTy, _cxs = PrettyTypes.PrettifyType g delTy @@ -848,10 +836,6 @@ module internal DescriptionListsImpl = let _prettyTyparInst, prettyRetTyL = NicePrint.prettyLayoutOfUncurriedSig denv item.TyparInstantiation [] retTy [], prettyRetTyL // no parameter data available for binary operators like 'zip', 'join' and 'groupJoin' since they use bespoke syntax - | Item.FakeInterfaceCtor ty -> - let _prettyTyparInst, prettyRetTyL = NicePrint.prettyLayoutOfUncurriedSig denv item.TyparInstantiation [] ty - [], prettyRetTyL - | Item.DelegateCtor delTy -> let (SigOfFunctionForDelegate(_, _, _, delFuncTy)) = GetSigOfFunctionForDelegate infoReader delTy m AccessibleFromSomewhere @@ -940,7 +924,6 @@ module internal DescriptionListsImpl = | Item.Property _ -> FSharpGlyph.Property | Item.CtorGroup _ | Item.DelegateCtor _ - | Item.FakeInterfaceCtor _ | Item.CustomOperation _ -> FSharpGlyph.Method | Item.MethodGroup (_, minfos, _) when minfos |> List.forall (fun minfo -> minfo.IsExtensionMember) -> FSharpGlyph.ExtensionMethod | Item.MethodGroup _ -> FSharpGlyph.Method @@ -986,7 +969,6 @@ module internal DescriptionListsImpl = | Item.CtorGroup(nm, cinfos) -> List.map (fun minfo -> Item.CtorGroup(nm, [minfo])) cinfos | Item.Trait traitInfo -> if traitInfo.GetLogicalArgumentTypes(g).IsEmpty then [] else [item] - | Item.FakeInterfaceCtor _ | Item.DelegateCtor _ -> [item] | Item.NewDef _ | Item.ILField _ -> [] @@ -1107,9 +1089,9 @@ type DeclarationListInfo(declarations: DeclarationListItem[], isForType: bool, i items |> List.map (fun x -> match x.Item with + | Item.Types (_, TType_app(tcref, _, _) :: _) when isInterfaceTyconRef tcref -> { x with MinorPriority = 1000 + tcref.TyparsNoRange.Length } | Item.Types (_, TType_app(tcref, _, _) :: _) -> { x with MinorPriority = 1 + tcref.TyparsNoRange.Length } // Put delegate ctors after types, sorted by #typars. RemoveDuplicateItems will remove FakeInterfaceCtor and DelegateCtor if an earlier type is also reported with this name - | Item.FakeInterfaceCtor (TType_app(tcref, _, _)) | Item.DelegateCtor (TType_app(tcref, _, _)) -> { x with MinorPriority = 1000 + tcref.TyparsNoRange.Length } // Put type ctors after types, sorted by #typars. RemoveDuplicateItems will remove DefaultStructCtors if a type is also reported with this name | Item.CtorGroup (_, cinfo :: _) -> { x with MinorPriority = 1000 + 10 * cinfo.DeclaringTyconRef.TyparsNoRange.Length } diff --git a/src/Compiler/Symbols/SymbolHelpers.fs b/src/Compiler/Symbols/SymbolHelpers.fs index fda64a95282..3c669d7a64c 100644 --- a/src/Compiler/Symbols/SymbolHelpers.fs +++ b/src/Compiler/Symbols/SymbolHelpers.fs @@ -118,8 +118,7 @@ module internal SymbolHelpers = | Item.ImplicitOp (_, {contents = Some(TraitConstraintSln.FSMethSln(vref=vref))}) -> Some vref.Range | Item.ImplicitOp _ -> None | Item.UnqualifiedType tcrefs -> tcrefs |> List.tryPick (rangeOfEntityRef preferFlag >> Some) - | Item.DelegateCtor ty - | Item.FakeInterfaceCtor ty -> ty |> tryNiceEntityRefOfTyOption |> Option.map (rangeOfEntityRef preferFlag) + | Item.DelegateCtor ty -> ty |> tryNiceEntityRefOfTyOption |> Option.map (rangeOfEntityRef preferFlag) | Item.NewDef _ -> None // Provided type definitions do not have a useful F# CCU for the purposes of goto-definition. @@ -190,7 +189,6 @@ module internal SymbolHelpers = | Item.Types(_, tys) -> tys |> List.tryPick (tryNiceEntityRefOfTyOption >> Option.bind computeCcuOfTyconRef) - | Item.FakeInterfaceCtor(ty) | Item.DelegateCtor(ty) -> ty |> tryNiceEntityRefOfTyOption |> Option.bind computeCcuOfTyconRef @@ -283,7 +281,6 @@ module internal SymbolHelpers = | Item.ILField finfo -> mkXmlComment (GetXmlDocSigOfILFieldInfo infoReader m finfo) - | Item.FakeInterfaceCtor ty | Item.DelegateCtor ty | Item.Types(_, ty :: _) -> match ty with @@ -363,7 +360,6 @@ module internal SymbolHelpers = match item with | Item.DelegateCtor ty | Item.CtorGroup(_, [DefaultStructCtor(_, ty)]) - | Item.FakeInterfaceCtor ty | Item.Types(_, [ty]) -> Some ty | _ -> None @@ -398,7 +394,6 @@ module internal SymbolHelpers = | Item.ActivePatternResult _ | Item.AnonRecdField _ | Item.OtherName _ - | Item.FakeInterfaceCtor _ | Item.ImplicitOp _ | Item.NewDef _ | Item.UnionCaseField _ @@ -504,7 +499,6 @@ module internal SymbolHelpers = | Item.ActivePatternResult _ | Item.AnonRecdField _ | Item.OtherName _ - | Item.FakeInterfaceCtor _ | Item.ImplicitOp _ | Item.NewDef _ | Item.UnionCaseField _ @@ -571,7 +565,6 @@ module internal SymbolHelpers = | Item.MethodGroup(_, _, Some minfo) -> buildString (fun os -> NicePrint.outputTyconRef denv os minfo.DeclaringTyconRef; bprintf os ".%s" minfo.DisplayName) | Item.MethodGroup(_, minfo :: _, _) -> buildString (fun os -> NicePrint.outputTyconRef denv os minfo.DeclaringTyconRef; bprintf os ".%s" minfo.DisplayName) | Item.UnqualifiedType (tcref :: _) -> buildString (fun os -> NicePrint.outputTyconRef denv os tcref) - | Item.FakeInterfaceCtor ty | Item.DelegateCtor ty | Item.Types(_, ty :: _) -> match tryTcrefOfAppTy g ty with @@ -716,7 +709,6 @@ module internal SymbolHelpers = | Item.ActivePatternResult _ | Item.NewDef _ | Item.ILField _ - | Item.FakeInterfaceCtor _ | Item.DelegateCtor _ -> //| _ -> GetXmlCommentForItemAux None infoReader m item @@ -848,7 +840,6 @@ module internal SymbolHelpers = #endif | Item.Types(_, AppTy g (tcref, _) :: _) | Item.DelegateCtor(AppTy g (tcref, _)) - | Item.FakeInterfaceCtor(AppTy g (tcref, _)) | Item.UnqualifiedType (tcref :: _) | Item.ExnCase tcref -> // strip off any abbreviation @@ -859,7 +850,6 @@ module internal SymbolHelpers = // Pathological cases of the above | Item.Types _ | Item.DelegateCtor _ - | Item.FakeInterfaceCtor _ | Item.UnqualifiedType [] -> None @@ -958,7 +948,6 @@ module internal SymbolHelpers = minfos |> List.map (fun minfo -> { Item = Item.MethodGroup(nm, [minfo], orig); TyparInstantiation = item.TyparInstantiation }) | Item.CtorGroup(nm, cinfos) -> cinfos |> List.map (fun minfo -> { Item = Item.CtorGroup(nm, [minfo]); TyparInstantiation = item.TyparInstantiation }) - | Item.FakeInterfaceCtor _ | Item.DelegateCtor _ -> [item] | Item.NewDef _ | Item.ILField _ -> [] diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index e405ded53e5..5caf1bc1245 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -331,7 +331,6 @@ type FSharpSymbol(cenv: SymbolEnv, item: unit -> Item, access: FSharpSymbol -> C // TODO: the following don't currently return any interesting subtype | Item.ImplicitOp _ | Item.ILField _ - | Item.FakeInterfaceCtor _ | Item.NewDef _ -> dflt() // These cases cover unreachable cases | Item.CustomOperation (_, _, None) diff --git a/tests/fsharp/typecheck/sigs/neg06.bsl b/tests/fsharp/typecheck/sigs/neg06.bsl index cc7fc113cfc..54b3c5d84e5 100644 --- a/tests/fsharp/typecheck/sigs/neg06.bsl +++ b/tests/fsharp/typecheck/sigs/neg06.bsl @@ -94,27 +94,27 @@ neg06.fs(128,53,128,61): typecheck error FS0043: A type parameter is missing a c neg06.fs(141,10,141,18): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation -neg06.fs(148,13,148,21): typecheck error FS0039: The value or constructor 'BadType1' is not defined. +neg06.fs(148,13,148,21): typecheck error FS0800: Invalid use of a type name neg06.fs(150,10,150,18): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation -neg06.fs(157,13,157,21): typecheck error FS0039: The value or constructor 'BadType2' is not defined. +neg06.fs(157,13,157,21): typecheck error FS0800: Invalid use of a type name neg06.fs(159,10,159,18): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation -neg06.fs(166,13,166,21): typecheck error FS0039: The value or constructor 'BadType3' is not defined. +neg06.fs(166,13,166,21): typecheck error FS0800: Invalid use of a type name neg06.fs(195,10,195,18): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation -neg06.fs(203,13,203,21): typecheck error FS0039: The value or constructor 'BadType1' is not defined. +neg06.fs(203,13,203,21): typecheck error FS0800: Invalid use of a type name neg06.fs(205,10,205,18): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation -neg06.fs(213,13,213,21): typecheck error FS0039: The value or constructor 'BadType2' is not defined. +neg06.fs(213,13,213,21): typecheck error FS0800: Invalid use of a type name neg06.fs(215,10,215,18): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation -neg06.fs(223,13,223,21): typecheck error FS0039: The value or constructor 'BadType3' is not defined. +neg06.fs(223,13,223,21): typecheck error FS0800: Invalid use of a type name neg06.fs(300,10,300,12): typecheck error FS0009: Uses of this construct may result in the generation of unverifiable .NET IL code. This warning can be disabled using '--nowarn:9' or '#nowarn "9"'. @@ -130,11 +130,11 @@ neg06.fs(320,10,320,12): typecheck error FS0937: Only structs and classes withou neg06.fs(326,10,326,18): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation -neg06.fs(335,13,335,21): typecheck error FS0039: The value or constructor 'BadType4' is not defined. +neg06.fs(335,13,335,21): typecheck error FS0800: Invalid use of a type name neg06.fs(340,10,340,18): typecheck error FS0954: This type definition involves an immediate cyclic reference through a struct field or inheritance relation -neg06.fs(350,13,350,21): typecheck error FS0039: The value or constructor 'BadType4' is not defined. +neg06.fs(350,13,350,21): typecheck error FS0800: Invalid use of a type name neg06.fs(375,9,375,10): typecheck error FS1197: The parameter 'x' was inferred to have byref type. Parameters of byref type must be given an explicit type annotation, e.g. 'x1: byref'. When used, a byref parameter is implicitly dereferenced. diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_InvalidRecursiveGeneric01.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_InvalidRecursiveGeneric01.fs index 2d426f6244f..9324d3e4902 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_InvalidRecursiveGeneric01.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_InvalidRecursiveGeneric01.fs @@ -3,7 +3,7 @@ // Regression for FSB 3417 //This type definition involves an immediate cyclic reference through a struct field or inheritance relation -//The value or constructor 'BadType4' is not defined +//Invalid use of a type name type BadType4 = struct diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_InvalidRecursiveGeneric02.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_InvalidRecursiveGeneric02.fs index 21854ced87a..f90ab777f41 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_InvalidRecursiveGeneric02.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_InvalidRecursiveGeneric02.fs @@ -3,7 +3,7 @@ // Regression for FSB 3417 //This type definition involves an immediate cyclic reference through a struct field or inheritance relation -//The value or constructor 'BadType4' is not defined +//Invalid use of a type name type BadType4 = struct diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructConstruction03.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructConstruction03.fs index de295146093..0ee07b3415e 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructConstruction03.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/StructTypes/E_StructConstruction03.fs @@ -2,8 +2,8 @@ // Regression test for FSHARP1.0:3143 //This type definition involves an immediate cyclic reference through a struct field or inheritance relation$ //This declaration element is not permitted in an augmentation$ -//The value or constructor 'S' is not defined -//The value or constructor 'S' is not defined +//Invalid use of a type name +//Invalid use of a type name type S(x:S) = struct end diff --git a/tests/service/Symbols.fs b/tests/service/Symbols.fs index c52865d8804..acbc02f6c98 100644 --- a/tests/service/Symbols.fs +++ b/tests/service/Symbols.fs @@ -301,6 +301,32 @@ type E = Ns1.Ns2.T | _ -> Assert.Fail (sprintf "Couldn't get entity: %s" symbolName)) + [] + let ``Interface 01`` () = + let _, checkResults = getParseAndCheckResults """ +open System + +IDisposable +""" + findSymbolUseByName "IDisposable" checkResults |> ignore + + [] + let ``Interface 02`` () = + let _, checkResults = getParseAndCheckResults """ +System.IDisposable +""" + findSymbolUseByName "IDisposable" checkResults |> ignore + + [] + let ``Interface 03`` () = + let _, checkResults = getParseAndCheckResults """ +open System + +{ new IDisposable with } +""" + findSymbolUseByName "IDisposable" checkResults |> ignore + + [] let ``FSharpType.Format can use prefix representations`` () = let _, checkResults = getParseAndCheckResults """ From 73970cb343fc6706dbf94f568be478220814727b Mon Sep 17 00:00:00 2001 From: Martin <29605222+Martin521@users.noreply.github.com> Date: Wed, 20 Dec 2023 01:00:14 +0100 Subject: [PATCH 09/10] Fix for #83 (improve constraint error message) (#16304) --- src/Compiler/Checking/CheckExpressions.fs | 7 ++-- src/Compiler/Checking/ConstraintSolver.fs | 35 +++++++++------- src/Compiler/Checking/FindUnsolved.fs | 2 +- src/Compiler/Checking/NicePrint.fs | 2 +- src/Compiler/Checking/PostInferenceChecks.fs | 12 +++--- src/Compiler/Driver/CompilerImports.fs | 23 +++++++++++ src/Compiler/FSComp.txt | 1 + src/Compiler/Symbols/Exprs.fs | 8 ++-- src/Compiler/Symbols/Symbols.fs | 12 +++--- src/Compiler/TypedTree/TypedTree.fs | 38 ++++++++++++------ src/Compiler/TypedTree/TypedTree.fsi | 8 +++- src/Compiler/TypedTree/TypedTreeOps.fs | 18 ++++----- src/Compiler/TypedTree/TypedTreePickle.fs | 4 +- 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 +++ .../ConstraintSolver/MemberConstraints.fs | 40 +++++++++++++++++++ .../Libraries/Core/Operators/AbsTests.fs | 14 +++---- .../Libraries/Core/Operators/SignTests.fs | 8 ++-- tests/fsharp/typecheck/sigs/neg61.bsl | 2 +- .../EnumTypes/E_NoMethodsOnEnums01.fs | 5 +-- 31 files changed, 228 insertions(+), 76 deletions(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index cf1b9bce32a..f182c98ac85 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -4076,7 +4076,8 @@ and TcConstraintWhereTyparSupportsMember cenv env newOk tpenv synSupportTys synM let g = cenv.g let traitInfo, tpenv = TcPseudoMemberSpec cenv newOk env synSupportTys tpenv synMemberSig m match traitInfo with - | TTrait(objTys, ".ctor", memberFlags, argTys, returnTy, _) when memberFlags.MemberKind = SynMemberKind.Constructor -> + | TTrait(tys=objTys; memberName=".ctor"; memberFlags=memberFlags; objAndArgTys=argTys; returnTyOpt=returnTy) + when memberFlags.MemberKind = SynMemberKind.Constructor -> match objTys, argTys with | [ty], [] when typeEquiv g ty (GetFSharpViewOfReturnType g returnTy) -> AddCxTypeMustSupportDefaultCtor env.DisplayEnv cenv.css m NoTrace ty @@ -4125,7 +4126,7 @@ and TcPseudoMemberSpec cenv newOk env synTypes tpenv synMemberSig m = let item = Item.OtherName (Some id, memberConstraintTy, None, None, id.idRange) CallNameResolutionSink cenv.tcSink (id.idRange, env.NameEnv, item, emptyTyparInst, ItemOccurence.Use, env.AccessRights) - TTrait(tys, logicalCompiledName, memberFlags, argTys, returnTy, ref None), tpenv + TTrait(tys, logicalCompiledName, memberFlags, argTys, returnTy, ref None, ref None), tpenv | _ -> error(Error(FSComp.SR.tcInvalidConstraint(), m)) @@ -8813,7 +8814,7 @@ and TcImplicitOpItemThen (cenv: cenv) overallTy env id sln tpenv mItem delayed = let memberFlags = StaticMemberFlags SynMemberKind.Member let logicalCompiledName = ComputeLogicalName id memberFlags - let traitInfo = TTrait(argTys, logicalCompiledName, memberFlags, argTys, Some retTy, sln) + let traitInfo = TTrait(argTys, logicalCompiledName, memberFlags, argTys, Some retTy, ref None, sln) let expr = Expr.Op (TOp.TraitCall traitInfo, [], ves, mItem) let expr = mkLambdas g mItem [] vs (expr, retTy) diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 6bc57f606ca..c30ca0cdc66 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -1394,7 +1394,7 @@ and SolveDimensionlessNumericType (csenv: ConstraintSolverEnv) ndeep m2 trace ty /// /// 2. Some additional solutions are forced prior to generalization (permitWeakResolution= Yes or YesDuringCodeGen). See above and SolveMemberConstraint (csenv: ConstraintSolverEnv) ignoreUnresolvedOverload permitWeakResolution ndeep m2 trace traitInfo : OperationResult = trackErrors { - let (TTrait(supportTys, nm, memFlags, traitObjAndArgTys, retTy, sln)) = traitInfo + let (TTrait(supportTys, nm, memFlags, traitObjAndArgTys, retTy, source, sln)) = traitInfo // Do not re-solve if already solved if sln.Value.IsSome then return true else @@ -1411,8 +1411,8 @@ and SolveMemberConstraint (csenv: ConstraintSolverEnv) ignoreUnresolvedOverload let supportTys = ListSet.setify (typeAEquiv g aenv) supportTys // Rebuild the trait info after removing duplicates - let traitInfo = TTrait(supportTys, nm, memFlags, traitObjAndArgTys, retTy, sln) - let retTy = GetFSharpViewOfReturnType g retTy + let traitInfo = traitInfo.WithSupportTypes supportTys + let retTy = GetFSharpViewOfReturnType g retTy // Assert the object type if the constraint is for an instance member if memFlags.IsInstance then @@ -1754,8 +1754,17 @@ and SolveMemberConstraint (csenv: ConstraintSolverEnv) ignoreUnresolvedOverload if List.isSingleton supportTys then FSComp.SR.csTypeDoesNotSupportOperatorNullable(tyString, opName) else FSComp.SR.csTypesDoNotSupportOperatorNullable(tyString, opName) | _ -> - if List.isSingleton supportTys then FSComp.SR.csTypeDoesNotSupportOperator(tyString, opName) - else FSComp.SR.csTypesDoNotSupportOperator(tyString, opName) + match supportTys, source.Value with + | [_], Some s when s.StartsWith("Operators.") -> + let opSource = s[10..] + if opSource = nm then FSComp.SR.csTypeDoesNotSupportOperator(tyString, opName) + else FSComp.SR.csTypeDoesNotSupportOperator(tyString, opSource) + | [_], Some s -> + FSComp.SR.csFunctionDoesNotSupportType(s, tyString, nm) + | [_], _ + -> FSComp.SR.csTypeDoesNotSupportOperator(tyString, opName) + | _, _ + -> FSComp.SR.csTypesDoNotSupportOperator(tyString, opName) return! ErrorD(ConstraintSolverError(err, m, m2)) | _ -> @@ -1928,7 +1937,6 @@ and TransactMemberConstraintSolution traitInfo (trace: OptionalTrace) sln = /// Only consider overload resolution if canonicalizing or all the types are now nominal. /// That is, don't perform resolution if more nominal information may influence the set of available overloads and GetRelevantMethodsForTrait (csenv: ConstraintSolverEnv) (permitWeakResolution: PermitWeakResolution) nm traitInfo : (TType * MethInfo) list = - let (TTrait(_, _, memFlags, _, _, _)) = traitInfo let results = if permitWeakResolution.Permit || MemberConstraintSupportIsReadyForDeterminingOverloads csenv traitInfo then let m = csenv.m @@ -1938,7 +1946,7 @@ and GetRelevantMethodsForTrait (csenv: ConstraintSolverEnv) (permitWeakResolutio let minfos = [ for (supportTy, nominalTy) in nominalTys do let infos = - match memFlags.MemberKind with + match traitInfo.MemberFlags.MemberKind with | SynMemberKind.Constructor -> GetIntrinsicConstructorInfosOfType csenv.SolverState.InfoReader m nominalTy | _ -> @@ -1962,8 +1970,7 @@ and GetRelevantMethodsForTrait (csenv: ConstraintSolverEnv) (permitWeakResolutio // The trait name "op_Explicit" also covers "op_Implicit", so look for that one too. if nm = "op_Explicit" then - let (TTrait(supportTys, _, memFlags, argTys, retTy, soln)) = traitInfo - let traitInfo2 = TTrait(supportTys, "op_Implicit", memFlags, argTys, retTy, soln) + let traitInfo2 = traitInfo.WithMemberName "op_Implicit" results @ GetRelevantMethodsForTrait csenv permitWeakResolution "op_Implicit" traitInfo2 else results @@ -2020,7 +2027,7 @@ and SupportTypeOfMemberConstraintIsSolved (csenv: ConstraintSolverEnv) (traitInf /// Get all the unsolved typars (statically resolved or not) relevant to the member constraint and GetFreeTyparsOfMemberConstraint (csenv: ConstraintSolverEnv) traitInfo = - let (TTrait(supportTys, _, _, argTys, retTy, _)) = traitInfo + let (TTrait(tys=supportTys; objAndArgTys=argTys; returnTyOpt=retTy)) = traitInfo freeInTypesLeftToRightSkippingConstraints csenv.g (supportTys @ argTys @ Option.toList retTy) and MemberConstraintIsReadyForWeakResolution csenv traitInfo = @@ -2104,8 +2111,8 @@ and AddMemberConstraint (csenv: ConstraintSolverEnv) ndeep m2 (trace: OptionalTr and TraitsAreRelated (csenv: ConstraintSolverEnv) retry traitInfo1 traitInfo2 = let g = csenv.g - let (TTrait(tys1, nm1, memFlags1, argTys1, _, _)) = traitInfo1 - let (TTrait(tys2, nm2, memFlags2, argTys2, _, _)) = traitInfo2 + let (TTrait(tys=tys1; memberName=nm1; memberFlags=memFlags1; objAndArgTys=argTys1)) = traitInfo1 + let (TTrait(tys=tys2; memberName=nm2; memberFlags=memFlags2; objAndArgTys=argTys2)) = traitInfo2 memFlags1.IsInstance = memFlags2.IsInstance && nm1 = nm2 && // Multiple op_Explicit and op_Implicit constraints can exist for the same type variable. @@ -2130,8 +2137,8 @@ and EnforceConstraintConsistency (csenv: ConstraintSolverEnv) ndeep m2 trace ret match tpc1, tpc2 with | TyparConstraint.MayResolveMember(traitInfo1, _), TyparConstraint.MayResolveMember(traitInfo2, _) when TraitsAreRelated csenv retry traitInfo1 traitInfo2 -> - let (TTrait(tys1, _, _, argTys1, rty1, _)) = traitInfo1 - let (TTrait(tys2, _, _, argTys2, rty2, _)) = traitInfo2 + let (TTrait(tys=tys1; objAndArgTys=argTys1; returnTyOpt=rty1)) = traitInfo1 + let (TTrait(tys=tys2; objAndArgTys=argTys2; returnTyOpt=rty2)) = traitInfo2 if retry then match tys1, tys2 with | [ty1], [ty2] -> do! SolveTypeEqualsTypeKeepAbbrevs csenv ndeep m2 trace ty1 ty2 diff --git a/src/Compiler/Checking/FindUnsolved.fs b/src/Compiler/Checking/FindUnsolved.fs index cfc34649ae5..10eb7ab672c 100644 --- a/src/Compiler/Checking/FindUnsolved.fs +++ b/src/Compiler/Checking/FindUnsolved.fs @@ -167,7 +167,7 @@ and accOp cenv env (op, tyargs, args, m) = | _ -> () /// Walk a trait call, collecting type variables -and accTraitInfo cenv env (mFallback : range) (TTrait(tys, _nm, _, argTys, retTy, _sln)) = +and accTraitInfo cenv env (mFallback : range) (TTrait(tys=tys; objAndArgTys=argTys; returnTyOpt=retTy)) = argTys |> accTypeInst cenv env mFallback retTy |> Option.iter (accTy cenv env mFallback) tys |> List.iter (accTy cenv env mFallback) diff --git a/src/Compiler/Checking/NicePrint.fs b/src/Compiler/Checking/NicePrint.fs index dfb5a8f20a1..985d3fbe22b 100644 --- a/src/Compiler/Checking/NicePrint.fs +++ b/src/Compiler/Checking/NicePrint.fs @@ -823,7 +823,7 @@ module PrintTypes = and layoutTraitWithInfo denv env traitInfo = let g = denv.g - let (TTrait(tys, _, memFlags, _, _, _)) = traitInfo + let (TTrait(tys=tys;memberFlags=memFlags)) = traitInfo let nm = traitInfo.MemberDisplayNameCore let nameL = ConvertValLogicalNameToDisplayLayout false (tagMember >> wordL) nm if denv.shortConstraints then diff --git a/src/Compiler/Checking/PostInferenceChecks.fs b/src/Compiler/Checking/PostInferenceChecks.fs index c60fb146d54..e9dee56e748 100644 --- a/src/Compiler/Checking/PostInferenceChecks.fs +++ b/src/Compiler/Checking/PostInferenceChecks.fs @@ -346,7 +346,7 @@ let rec CheckTypeDeep (cenv: cenv) (visitTy, visitTyconRefOpt, visitAppTyOpt, vi | TType_var (tp, _) when tp.Solution.IsSome -> for cx in tp.Constraints do match cx with - | TyparConstraint.MayResolveMember(TTrait(_, _, _, _, _, soln), _) -> + | TyparConstraint.MayResolveMember(TTrait(solution=soln), _) -> match visitTraitSolutionOpt, soln.Value with | Some visitTraitSolution, Some sln -> visitTraitSolution sln | _ -> () @@ -432,11 +432,11 @@ and CheckTypeConstraintDeep cenv f g env x = | TyparConstraint.IsReferenceType _ | TyparConstraint.RequiresDefaultConstructor _ -> () -and CheckTraitInfoDeep cenv (_, _, _, visitTraitSolutionOpt, _ as f) g env (TTrait(tys, _, _, argTys, retTy, soln)) = - CheckTypesDeep cenv f g env tys - CheckTypesDeep cenv f g env argTys - Option.iter (CheckTypeDeep cenv f g env true ) retTy - match visitTraitSolutionOpt, soln.Value with +and CheckTraitInfoDeep cenv (_, _, _, visitTraitSolutionOpt, _ as f) g env traitInfo = + CheckTypesDeep cenv f g env traitInfo.SupportTypes + CheckTypesDeep cenv f g env traitInfo.CompiledObjectAndArgumentTypes + Option.iter (CheckTypeDeep cenv f g env true ) traitInfo.CompiledReturnType + match visitTraitSolutionOpt, traitInfo.Solution with | Some visitTraitSolution, Some sln -> visitTraitSolution sln | _ -> () diff --git a/src/Compiler/Driver/CompilerImports.fs b/src/Compiler/Driver/CompilerImports.fs index e828863c3a8..d8d9ccd9866 100644 --- a/src/Compiler/Driver/CompilerImports.fs +++ b/src/Compiler/Driver/CompilerImports.fs @@ -377,6 +377,26 @@ let IsExe fileName = let ext = Path.GetExtension fileName String.Compare(ext, ".exe", StringComparison.OrdinalIgnoreCase) = 0 +let addConstraintSources(ia: ImportedAssembly) = + let contents = ia.FSharpViewOfMetadata.Contents + let addCxsToMember name (v: Val) = + for typar in fst v.GeneralizedType do + for cx in typar.Constraints do + match cx with + | TyparConstraint.MayResolveMember(TTrait(source=source), _) -> + source.Value <- Some name + | _ -> () + let rec addCxsToModule name (m: ModuleOrNamespaceType) = + for e in m.ModuleAndNamespaceDefinitions do + if e.IsModuleOrNamespace then + let mname = + if String.length name > 0 then name + "." + e.DisplayName + elif e.IsModule then e.DisplayName + else "" + addCxsToModule mname e.ModuleOrNamespaceType + for memb in m.AllValsAndMembers do addCxsToMember (name + "." + memb.LogicalName) memb + addCxsToModule "" contents.ModuleOrNamespaceType + type TcConfig with member tcConfig.TryResolveLibWithDirectories(r: AssemblyReference) = @@ -2233,6 +2253,9 @@ and [] TcImports let _dllinfos, phase2s = results |> Array.choose id |> List.ofArray |> List.unzip fixupOrphanCcus () let ccuinfos = List.collect (fun phase2 -> phase2 ()) phase2s + if importsBase.IsSome then + importsBase.Value.CcuTable.Values |> Seq.iter addConstraintSources + ccuTable.Values |> Seq.iter addConstraintSources return ccuinfos } diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 46fd02464da..b17d5877ad9 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -315,6 +315,7 @@ csExpectTypeWithOperatorButGivenFunction,"Expecting a type supporting the operat csExpectTypeWithOperatorButGivenTuple,"Expecting a type supporting the operator '%s' but given a tuple type" csTypesDoNotSupportOperator,"None of the types '%s' support the operator '%s'" csTypeDoesNotSupportOperator,"The type '%s' does not support the operator '%s'" +csFunctionDoesNotSupportType,"'%s' does not support the type '%s', because the latter lacks the required (real or built-in) member '%s'" csTypesDoNotSupportOperatorNullable,"None of the types '%s' support the operator '%s'. Consider opening the module 'Microsoft.FSharp.Linq.NullableOperators'." csTypeDoesNotSupportOperatorNullable,"The type '%s' does not support the operator '%s'. Consider opening the module 'Microsoft.FSharp.Linq.NullableOperators'." csTypeDoesNotSupportConversion,"The type '%s' does not support a conversion to the type '%s'" diff --git a/src/Compiler/Symbols/Exprs.fs b/src/Compiler/Symbols/Exprs.fs index 3aa8f1cbe5e..4d0b994f35b 100644 --- a/src/Compiler/Symbols/Exprs.fs +++ b/src/Compiler/Symbols/Exprs.fs @@ -899,12 +899,12 @@ module FSharpExprConvert = let typR = ConvType cenv (mkAppTy tycr tyargs) E.UnionCaseTag(ConvExpr cenv env arg1, typR) - | TOp.TraitCall (TTrait(tys, nm, memFlags, argTys, _retTy, _solution)), _, _ -> - let tysR = ConvTypes cenv tys + | TOp.TraitCall traitInfo, _, _ -> + let tysR = ConvTypes cenv traitInfo.SupportTypes let tyargsR = ConvTypes cenv tyargs - let argTysR = ConvTypes cenv argTys + let argTysR = ConvTypes cenv traitInfo.CompiledObjectAndArgumentTypes let argsR = ConvExprs cenv env args - E.TraitCall(tysR, nm, memFlags, argTysR, tyargsR, argsR) + E.TraitCall(tysR, traitInfo.MemberLogicalName, traitInfo.MemberFlags, argTysR, tyargsR, argsR) | TOp.RefAddrGet readonly, [ty], [e] -> let replExpr = mkRecdFieldGetAddrViaExprAddr(readonly, e, mkRefCellContentsRef g, [ty], m) diff --git a/src/Compiler/Symbols/Symbols.fs b/src/Compiler/Symbols/Symbols.fs index 5caf1bc1245..6319af1089c 100644 --- a/src/Compiler/Symbols/Symbols.fs +++ b/src/Compiler/Symbols/Symbols.fs @@ -1460,18 +1460,18 @@ type FSharpGenericParameterMemberConstraint(cenv, info: TraitConstraintInfo) = (fun () -> Item.Trait(info)), (fun _ _ _ad -> true)) - let (TTrait(tys, nm, flags, atys, retTy, _)) = info member _.MemberSources = - tys |> List.map (fun ty -> FSharpType(cenv, ty)) |> makeReadOnlyCollection + info.SupportTypes |> List.map (fun ty -> FSharpType(cenv, ty)) |> makeReadOnlyCollection - member _.MemberName = nm + member _.MemberName = info.MemberLogicalName - member _.MemberIsStatic = not flags.IsInstance + member _.MemberIsStatic = not info.MemberFlags.IsInstance - member _.MemberArgumentTypes = atys |> List.map (fun ty -> FSharpType(cenv, ty)) |> makeReadOnlyCollection + member _.MemberArgumentTypes = + info.CompiledObjectAndArgumentTypes |> List.map (fun ty -> FSharpType(cenv, ty)) |> makeReadOnlyCollection member _.MemberReturnType = - match retTy with + match info.CompiledReturnType with | None -> FSharpType(cenv, cenv.g.unit_ty) | Some ty -> FSharpType(cenv, ty) override x.ToString() = "" diff --git a/src/Compiler/TypedTree/TypedTree.fs b/src/Compiler/TypedTree/TypedTree.fs index a0665d32212..2109361291e 100644 --- a/src/Compiler/TypedTree/TypedTree.fs +++ b/src/Compiler/TypedTree/TypedTree.fs @@ -2454,29 +2454,41 @@ type TraitWitnessInfo = type TraitConstraintInfo = /// Indicates the signature of a member constraint. Contains a mutable solution cell - /// to store the inferred solution of the constraint. - | TTrait of tys: TTypes * memberName: string * memberFlags: SynMemberFlags * objAndArgTys: TTypes * returnTyOpt: TType option * solution: TraitConstraintSln option ref + /// to store the inferred solution of the constraint. And a mutable source cell to store + /// the name of the type or member that defined the constraint. + | TTrait of + tys: TTypes * + memberName: string * + memberFlags: SynMemberFlags * + objAndArgTys: TTypes * + returnTyOpt: TType option * + source: string option ref * + solution: TraitConstraintSln option ref /// Get the types that may provide solutions for the traits - member x.SupportTypes = (let (TTrait(tys, _, _, _, _, _)) = x in tys) + member x.SupportTypes = (let (TTrait(tys = tys)) = x in tys) /// Get the logical member name associated with the member constraint. - member x.MemberLogicalName = (let (TTrait(_, nm, _, _, _, _)) = x in nm) + member x.MemberLogicalName = (let (TTrait(memberName = nm)) = x in nm) /// Get the member flags associated with the member constraint. - member x.MemberFlags = (let (TTrait(_, _, flags, _, _, _)) = x in flags) - - member x.CompiledObjectAndArgumentTypes = (let (TTrait(_, _, _, objAndArgTys, _, _)) = x in objAndArgTys) - - member x.WithMemberKind(kind) = (let (TTrait(a, b, c, d, e, f)) = x in TTrait(a, b, { c with MemberKind=kind }, d, e, f)) + member x.MemberFlags = (let (TTrait(memberFlags = flags)) = x in flags) + member x.CompiledObjectAndArgumentTypes = (let (TTrait(objAndArgTys = objAndArgTys)) = x in objAndArgTys) + /// Get the optional return type recorded in the member constraint. - member x.CompiledReturnType = (let (TTrait(_, _, _, _, retTy, _)) = x in retTy) - + member x.CompiledReturnType = (let (TTrait(returnTyOpt = retTy)) = x in retTy) + /// Get or set the solution of the member constraint during inference member x.Solution - with get() = (let (TTrait(_, _, _, _, _, sln)) = x in sln.Value) - and set v = (let (TTrait(_, _, _, _, _, sln)) = x in sln.Value <- v) + with get() = (let (TTrait(solution = sln)) = x in sln.Value) + and set v = (let (TTrait(solution = sln)) = x in sln.Value <- v) + + member x.WithMemberKind(kind) = (let (TTrait(a, b, c, d, e, f, g)) = x in TTrait(a, b, { c with MemberKind=kind }, d, e, f, g)) + + member x.WithSupportTypes(tys) = (let (TTrait(_, b, c, d, e, f, g)) = x in TTrait(tys, b, c, d, e, f, g)) + + member x.WithMemberName(name) = (let (TTrait(a, _, c, d, e, f, g)) = x in TTrait(a, name, c, d, e, f, g)) [] member x.DebugText = x.ToString() diff --git a/src/Compiler/TypedTree/TypedTree.fsi b/src/Compiler/TypedTree/TypedTree.fsi index 61674b35fa1..3eb47b5eb47 100644 --- a/src/Compiler/TypedTree/TypedTree.fsi +++ b/src/Compiler/TypedTree/TypedTree.fsi @@ -1678,13 +1678,15 @@ type TraitWitnessInfo = type TraitConstraintInfo = /// Indicates the signature of a member constraint. Contains a mutable solution cell - /// to store the inferred solution of the constraint. + /// to store the inferred solution of the constraint. And a mutable source cell to store + /// the name of the type or member that defined the constraint. | TTrait of tys: TTypes * memberName: string * memberFlags: Syntax.SynMemberFlags * objAndArgTys: TTypes * returnTyOpt: TType option * + source: string option ref * solution: TraitConstraintSln option ref override ToString: unit -> string @@ -1719,6 +1721,10 @@ type TraitConstraintInfo = /// the extension property MemberDisplayNameCore member WithMemberKind: SynMemberKind -> TraitConstraintInfo + member WithSupportTypes: TTypes -> TraitConstraintInfo + + member WithMemberName: string -> TraitConstraintInfo + /// Represents the solution of a member constraint during inference. [] type TraitConstraintSln = diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index 519a076a41e..8616a7e43fa 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -262,7 +262,7 @@ and remapTyparConstraintsAux tyenv cs = | TyparConstraint.IsReferenceType _ | TyparConstraint.RequiresDefaultConstructor _ -> Some x) -and remapTraitInfo tyenv (TTrait(tys, nm, flags, argTys, retTy, slnCell)) = +and remapTraitInfo tyenv (TTrait(tys, nm, flags, argTys, retTy, source, slnCell)) = let slnCell = match slnCell.Value with | None -> None @@ -298,7 +298,7 @@ and remapTraitInfo tyenv (TTrait(tys, nm, flags, argTys, retTy, slnCell)) = // in the same way as types let newSlnCell = ref slnCell - TTrait(tysR, nm, flags, argTysR, retTyR, newSlnCell) + TTrait(tysR, nm, flags, argTysR, retTyR, source, newSlnCell) and bindTypars tps tyargs tpinst = match tps with @@ -961,8 +961,8 @@ type TypeEquivEnv with TypeEquivEnv.Empty.BindEquivTypars tps1 tps2 let rec traitsAEquivAux erasureFlag g aenv traitInfo1 traitInfo2 = - let (TTrait(tys1, nm, mf1, argTys, retTy, _)) = traitInfo1 - let (TTrait(tys2, nm2, mf2, argTys2, retTy2, _)) = traitInfo2 + let (TTrait(tys1, nm, mf1, argTys, retTy, _, _)) = traitInfo1 + let (TTrait(tys2, nm2, mf2, argTys2, retTy2, _, _)) = traitInfo2 mf1.IsInstance = mf2.IsInstance && nm = nm2 && ListSet.equals (typeAEquivAux erasureFlag g aenv) tys1 tys2 && @@ -2291,7 +2291,7 @@ and accFreeInTyparConstraint opts tpc acc = | TyparConstraint.IsUnmanaged _ | TyparConstraint.RequiresDefaultConstructor _ -> acc -and accFreeInTrait opts (TTrait(tys, _, _, argTys, retTy, sln)) acc = +and accFreeInTrait opts (TTrait(tys, _, _, argTys, retTy, _, sln)) acc = Option.foldBack (accFreeInTraitSln opts) sln.Value (accFreeInTypes opts tys (accFreeInTypes opts argTys @@ -2426,7 +2426,7 @@ and accFreeInTyparConstraintLeftToRight g cxFlag thruFlag acc tpc = | TyparConstraint.IsReferenceType _ | TyparConstraint.RequiresDefaultConstructor _ -> acc -and accFreeInTraitLeftToRight g cxFlag thruFlag acc (TTrait(tys, _, _, argTys, retTy, _)) = +and accFreeInTraitLeftToRight g cxFlag thruFlag acc (TTrait(tys, _, _, argTys, retTy, _, _)) = let acc = accFreeInTypesLeftToRight g cxFlag thruFlag acc tys let acc = accFreeInTypesLeftToRight g cxFlag thruFlag acc argTys let acc = Option.fold (accFreeInTypeLeftToRight g cxFlag thruFlag) acc retTy @@ -2633,7 +2633,7 @@ type TraitConstraintInfo with /// Get the key associated with the member constraint. member traitInfo.GetWitnessInfo() = - let (TTrait(tys, nm, memFlags, objAndArgTys, rty, _)) = traitInfo + let (TTrait(tys, nm, memFlags, objAndArgTys, rty, _, _)) = traitInfo TraitWitnessInfo(tys, nm, memFlags, objAndArgTys, rty) /// Get information about the trait constraints for a set of typars. @@ -4033,7 +4033,7 @@ module DebugPrint = and auxTraitL env (ttrait: TraitConstraintInfo) = #if DEBUG - let (TTrait(tys, nm, memFlags, argTys, retTy, _)) = ttrait + let (TTrait(tys, nm, memFlags, argTys, retTy, _, _)) = ttrait match global_g with | None -> wordL (tagText "") | Some g -> @@ -5366,7 +5366,7 @@ and accFreeInOp opts op acc = | TOp.Reraise -> accUsesRethrow true acc - | TOp.TraitCall (TTrait(tys, _, _, argTys, retTy, sln)) -> + | TOp.TraitCall (TTrait(tys, _, _, argTys, retTy, _, sln)) -> Option.foldBack (accFreeVarsInTraitSln opts) sln.Value (accFreeVarsInTys opts tys (accFreeVarsInTys opts argTys diff --git a/src/Compiler/TypedTree/TypedTreePickle.fs b/src/Compiler/TypedTree/TypedTreePickle.fs index b5b738f8ada..f2fd9887772 100644 --- a/src/Compiler/TypedTree/TypedTreePickle.fs +++ b/src/Compiler/TypedTree/TypedTreePickle.fs @@ -1437,7 +1437,7 @@ let p_trait_sln sln st = p_byte 7 st; p_tup4 p_ty (p_vref "trait") p_tys p_ty (a, b, c, d) st -let p_trait (TTrait(a, b, c, d, e, f)) st = +let p_trait (TTrait(a, b, c, d, e, _, f)) st = p_tup6 p_tys p_string p_MemberFlags p_tys (p_option p_ty) (p_option p_trait_sln) (a, b, c, d, e, f.Value) st let u_anonInfo_data st = @@ -1477,7 +1477,7 @@ let u_trait_sln st = let u_trait st = let a, b, c, d, e, f = u_tup6 u_tys u_string u_MemberFlags u_tys (u_option u_ty) (u_option u_trait_sln) st - TTrait (a, b, c, d, e, ref f) + TTrait (a, b, c, d, e, ref None, ref f) let p_rational q st = p_int32 (GetNumerator q) st; p_int32 (GetDenominator q) st diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 20ffb4de64a..fc48c028ba1 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -147,6 +147,11 @@ Dostupná přetížení:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. Obecná konstrukce vyžaduje, aby byl parametr obecného typu známý jako typ struct nebo reference. Zvažte možnost přidat anotaci typu. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 6844c4ebe7b..b5a49454df9 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -147,6 +147,11 @@ Verfügbare Überladungen:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. Für ein generisches Konstrukt muss ein generischer Typparameter als Struktur- oder Verweistyp bekannt sein. Erwägen Sie das Hinzufügen einer Typanmerkung. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 797d8231cfd..4dc6a6713cd 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -147,6 +147,11 @@ Sobrecargas disponibles:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. Una construcción genérica requiere que un parámetro de tipo genérico se conozca como tipo de referencia o estructura. Puede agregar una anotación de tipo. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index c3a07f32303..538b800e29d 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -147,6 +147,11 @@ Surcharges disponibles :\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. L'utilisation d'une construction générique est possible uniquement si un paramètre de type générique est connu en tant que type struct ou type référence. Ajoutez une annotation de type. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 1bbd6f3a48e..b5c3ac2c8f3 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -147,6 +147,11 @@ Overload disponibili:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. Un costrutto generico richiede che un parametro di tipo generico sia noto come tipo riferimento o struct. Provare ad aggiungere un'annotazione di tipo. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 254548c4d61..7943618317f 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -147,6 +147,11 @@ 使用可能なオーバーロード:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. ジェネリック コンストラクトでは、ジェネリック型パラメーターが構造体または参照型として認識されている必要があります。型の注釈の追加を検討してください。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index f9fbab289f2..4c2816c22ab 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -147,6 +147,11 @@ 사용 가능한 오버로드:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. 제네릭 구문을 사용하려면 구조체 또는 참조 형식의 제네릭 형식 매개 변수가 필요합니다. 형식 주석을 추가하세요. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 075f8c0cc06..4db14e63e73 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -147,6 +147,11 @@ Dostępne przeciążenia:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. Konstrukcja ogólna wymaga, aby parametr typu ogólnego był znany jako struktura lub typ referencyjny. Rozważ dodanie adnotacji typu. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 2fc380b9748..3bf88631e2a 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -147,6 +147,11 @@ Sobrecargas disponíveis:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. Um constructo genérico exige que um parâmetro de tipo genérico seja conhecido como um tipo de referência ou struct. Considere adicionar uma anotação de tipo. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 85f28ad43be..a2e84f55e72 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -147,6 +147,11 @@ Доступные перегрузки:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. В универсальной конструкции требуется использовать параметр универсального типа, известный как структура или ссылочный тип. Рекомендуется добавить заметку с типом. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 843ad544e09..b0f5750e193 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -147,6 +147,11 @@ Kullanılabilir aşırı yüklemeler:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. Genel yapı, genel bir tür parametresinin yapı veya başvuru türü olarak bilinmesini gerektirir. Tür ek açıklaması eklemeyi düşünün. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 9c5c4fc8857..39b2583dbf5 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -147,6 +147,11 @@ 可用重载:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. 泛型构造要求泛型类型参数被视为结构或引用类型。请考虑添加类型注释。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 6992ddfd8b6..c55ca762564 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -147,6 +147,11 @@ 可用的多載:\n{0} + + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + '{0}' does not support the type '{1}', because the latter lacks the required (real or built-in) member '{2}' + + A generic construct requires that a generic type parameter be known as a struct or reference type. Consider adding a type annotation. 泛型建構要求泛型型別參數必須指定為結構或參考型別。請考慮新增型別註解。 diff --git a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs index 3bb1770b411..b3c33031acb 100644 --- a/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs +++ b/tests/FSharp.Compiler.ComponentTests/ConstraintSolver/MemberConstraints.fs @@ -74,3 +74,43 @@ type DataItem< ^input> with """ |> compile |> shouldSucceed + + [] + let ``Indirect constraint by operator`` () = + FSharp """ +List.average [42] |> ignore +""" + |> typecheck + |> shouldFail + |> withSingleDiagnostic + (Error 1, Line 2, Col 15, Line 2, Col 17, "'List.average' does not support the type 'int', because the latter lacks the required (real or built-in) member 'DivideByInt'") + + [] + let ``Direct constraint by named (pseudo) operator`` () = + FSharp """ +abs -1u |> ignore +""" + |> typecheck + |> shouldFail + |> withSingleDiagnostic + (Error 1, Line 2, Col 6, Line 2, Col 8, "The type 'uint32' does not support the operator 'abs'") + + [] + let ``Direct constraint by simple operator`` () = + FSharp """ +"" >>> 1 |> ignore +""" + |> typecheck + |> shouldFail + |> withSingleDiagnostic + (Error 1, Line 2, Col 1, Line 2, Col 3, "The type 'string' does not support the operator '>>>'") + + [] + let ``Direct constraint by pseudo operator`` () = + FSharp """ +ignore ["1" .. "42"] +""" + |> typecheck + |> shouldFail + |> withSingleDiagnostic + (Error 1, Line 2, Col 9, Line 2, Col 12, "The type 'string' does not support the operator 'op_Range'") diff --git a/tests/fsharp/Compiler/Libraries/Core/Operators/AbsTests.fs b/tests/fsharp/Compiler/Libraries/Core/Operators/AbsTests.fs index ca2f753de4e..a6e07ba38e4 100644 --- a/tests/fsharp/Compiler/Libraries/Core/Operators/AbsTests.fs +++ b/tests/fsharp/Compiler/Libraries/Core/Operators/AbsTests.fs @@ -29,7 +29,7 @@ abs -1uy |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 9) - "The type 'byte' does not support the operator 'Abs'" + "The type 'byte' does not support the operator 'abs'" [] let ``Abs of uint16``() = @@ -40,7 +40,7 @@ abs -1us |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 9) - "The type 'uint16' does not support the operator 'Abs'" + "The type 'uint16' does not support the operator 'abs'" [] let ``Abs of uint32``() = @@ -51,7 +51,7 @@ abs -1ul |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 9) - "The type 'uint32' does not support the operator 'Abs'" + "The type 'uint32' does not support the operator 'abs'" CompilerAssert.TypeCheckSingleError """ @@ -60,7 +60,7 @@ abs -1u |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 8) - "The type 'uint32' does not support the operator 'Abs'" + "The type 'uint32' does not support the operator 'abs'" [] let ``Abs of unativeint``() = @@ -71,7 +71,7 @@ abs -1un |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 9) - "The type 'unativeint' does not support the operator 'Abs'" + "The type 'unativeint' does not support the operator 'abs'" [] let ``Abs of uint64``() = @@ -82,7 +82,7 @@ abs -1uL |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 9) - "The type 'uint64' does not support the operator 'Abs'" + "The type 'uint64' does not support the operator 'abs'" CompilerAssert.TypeCheckSingleError """ @@ -91,4 +91,4 @@ abs -1UL |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 9) - "The type 'uint64' does not support the operator 'Abs'" \ No newline at end of file + "The type 'uint64' does not support the operator 'abs'" \ No newline at end of file diff --git a/tests/fsharp/Compiler/Libraries/Core/Operators/SignTests.fs b/tests/fsharp/Compiler/Libraries/Core/Operators/SignTests.fs index 2c67b1d1b8d..ca3edf8b377 100644 --- a/tests/fsharp/Compiler/Libraries/Core/Operators/SignTests.fs +++ b/tests/fsharp/Compiler/Libraries/Core/Operators/SignTests.fs @@ -45,7 +45,7 @@ sign 0uy |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 9) - "The type 'byte' does not support the operator 'get_Sign'" + "The type 'byte' does not support the operator 'sign'" [] let ``Sign of uint16``() = @@ -56,7 +56,7 @@ sign 0us |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 9) - "The type 'uint16' does not support the operator 'get_Sign'" + "The type 'uint16' does not support the operator 'sign'" [] let ``Sign of uint32``() = @@ -67,7 +67,7 @@ sign 0u |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 8) - "The type 'uint32' does not support the operator 'get_Sign'" + "The type 'uint32' does not support the operator 'sign'" [] let ``Sign of uint64``() = @@ -78,4 +78,4 @@ sign 0uL |> ignore FSharpDiagnosticSeverity.Error 1 (2, 6, 2, 9) - "The type 'uint64' does not support the operator 'get_Sign'" \ No newline at end of file + "The type 'uint64' does not support the operator 'sign'" \ No newline at end of file diff --git a/tests/fsharp/typecheck/sigs/neg61.bsl b/tests/fsharp/typecheck/sigs/neg61.bsl index b1ba15a77ad..e0b2fb5eafb 100644 --- a/tests/fsharp/typecheck/sigs/neg61.bsl +++ b/tests/fsharp/typecheck/sigs/neg61.bsl @@ -71,7 +71,7 @@ neg61.fs(111,13,111,24): typecheck error FS3144: 'return' and 'return!' may not neg61.fs(114,13,114,21): typecheck error FS3145: This is not a known query operator. Query operators are identifiers such as 'select', 'where', 'sortBy', 'thenBy', 'groupBy', 'groupValBy', 'join', 'groupJoin', 'sumBy' and 'averageBy', defined using corresponding methods on the 'QueryBuilder' type. -neg61.fs(114,22,114,23): typecheck error FS0001: The type 'int' does not support the operator 'Truncate' +neg61.fs(114,22,114,23): typecheck error FS0001: The type 'int' does not support the operator 'truncate' neg61.fs(133,17,133,20): typecheck error FS3147: This 'let' definition may not be used in a query. Only simple value definitions may be used in queries. diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoMethodsOnEnums01.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoMethodsOnEnums01.fs index b4e05661698..dca7226146d 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoMethodsOnEnums01.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoMethodsOnEnums01.fs @@ -1,6 +1,5 @@ // #Regression #Conformance #ObjectOrientedTypes #Enums -//Enumerations cannot have members$ -//The type 'Season' does not support the operator 'get_One'$ +//Enumerations cannot have members$ type Season = Spring=0 | Summer=1 | Autumn=2 | Winter=3 with @@ -8,5 +7,3 @@ type Season = Spring=0 | Summer=1 | Autumn=2 | Winter=3 let starti = Enum.to_int start let stopi = Enum.to_int stop { for i in starti .. stopi -> Enum.of_int i } - -printfn "%A" [Season.Spring .. Season.Autumn] From 99514c0fafa1f4a9ddf63e0439ec8804d87276eb Mon Sep 17 00:00:00 2001 From: Dan Fuchs <330402+fajpunk@users.noreply.github.com> Date: Wed, 20 Dec 2023 05:48:02 -0600 Subject: [PATCH 10/10] typo in foldBack summary (#16453) --- src/FSharp.Core/result.fsi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/FSharp.Core/result.fsi b/src/FSharp.Core/result.fsi index a5b7a5cb37a..c10226ab6ba 100644 --- a/src/FSharp.Core/result.fsi +++ b/src/FSharp.Core/result.fsi @@ -166,7 +166,7 @@ module Result = val inline fold<'T, 'Error, 'State> : folder: ('State -> 'T -> 'State) -> state: 'State -> result: Result<'T, 'Error> -> 'State - /// fold f inp s evaluates to match inp with Error _ -> s | Ok x -> f x s. + /// foldBack f inp s evaluates to match inp with Error _ -> s | Ok x -> f x s. /// /// A function to update the state data when given a value from an result. /// The input result.