From cc6d5dbdcc2913271ab045df872208da815d5372 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 20 Feb 2026 20:15:05 +0100 Subject: [PATCH 01/39] Reword FS0072 IndeterminateType error message for clarity Replace academic jargon ('indeterminate type', 'program point') with plain language that helps beginners understand what to do. Old: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. New: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. Fixes dotnet/fsharp#13013 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/FSStrings.resx | 2 +- src/Compiler/xlf/FSStrings.cs.xlf | 4 ++-- src/Compiler/xlf/FSStrings.de.xlf | 4 ++-- src/Compiler/xlf/FSStrings.es.xlf | 4 ++-- src/Compiler/xlf/FSStrings.fr.xlf | 4 ++-- src/Compiler/xlf/FSStrings.it.xlf | 4 ++-- src/Compiler/xlf/FSStrings.ja.xlf | 4 ++-- src/Compiler/xlf/FSStrings.ko.xlf | 4 ++-- src/Compiler/xlf/FSStrings.pl.xlf | 4 ++-- src/Compiler/xlf/FSStrings.pt-BR.xlf | 4 ++-- src/Compiler/xlf/FSStrings.ru.xlf | 4 ++-- src/Compiler/xlf/FSStrings.tr.xlf | 4 ++-- src/Compiler/xlf/FSStrings.zh-Hans.xlf | 4 ++-- src/Compiler/xlf/FSStrings.zh-Hant.xlf | 4 ++-- .../ModuleAbbreviations/ModuleAbbreviations.fs | 2 +- .../ByrefSafetyAnalysis/ByrefSafetyAnalysis.fs | 2 +- .../Conformance/Types/RecordTypes/RecordTypes.fs | 4 ++-- .../Conformance/Types/UnionTypes/UnionTypes.fs | 4 ++-- .../Language/DotLambdaTests.fs | 6 +++--- .../Language/ObsoleteAttributeCheckingTests.fs | 2 +- tests/fsharp/typecheck/sigs/neg106.bsl | 10 +++++----- tests/fsharp/typecheck/sigs/neg106.vsbsl | 10 +++++----- tests/fsharp/typecheck/sigs/neg15.bsl | 10 +++++----- tests/fsharp/typecheck/sigs/neg17.bsl | 12 ++++++------ 24 files changed, 58 insertions(+), 58 deletions(-) diff --git a/src/Compiler/FSStrings.resx b/src/Compiler/FSStrings.resx index 9e471249843..41310df3d83 100644 --- a/src/Compiler/FSStrings.resx +++ b/src/Compiler/FSStrings.resx @@ -190,7 +190,7 @@ The type '{0}' expects {1} type argument(s) but is given {2} - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. Duplicate definition of {0} '{1}' diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf index 80fc8d575a2..426179327bd 100644 --- a/src/Compiler/xlf/FSStrings.cs.xlf +++ b/src/Compiler/xlf/FSStrings.cs.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - Definovali jste vyhledávání u objektu neurčitého typu založeného na informacích před tímto místem v programu. Aby se typ objektu omezil, bude možná potřeba přidat před tímto místem v programu poznámku typu. Tím se problém s vyhledáváním pravděpodobně vyřeší. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + Definovali jste vyhledávání u objektu neurčitého typu založeného na informacích před tímto místem v programu. Aby se typ objektu omezil, bude možná potřeba přidat před tímto místem v programu poznámku typu. Tím se problém s vyhledáváním pravděpodobně vyřeší. diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf index cad73cb05c3..02fd2f3ba47 100644 --- a/src/Compiler/xlf/FSStrings.de.xlf +++ b/src/Compiler/xlf/FSStrings.de.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - Lookup für ein Objekt unbestimmten Typs, der auf Informationen vor diesem Programmpunkt basiert. Möglicherweise ist vor diesem Programmpunkt eine Typanmerkung erforderlich, um den Objekttyp einzuschränken. Dadurch kann das Lookup möglicherweise aufgelöst werden. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + Lookup für ein Objekt unbestimmten Typs, der auf Informationen vor diesem Programmpunkt basiert. Möglicherweise ist vor diesem Programmpunkt eine Typanmerkung erforderlich, um den Objekttyp einzuschränken. Dadurch kann das Lookup möglicherweise aufgelöst werden. diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf index e262a1eae44..5b474f48c96 100644 --- a/src/Compiler/xlf/FSStrings.es.xlf +++ b/src/Compiler/xlf/FSStrings.es.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - Búsqueda de un objeto de tipo indeterminado basado en información anterior a este punto del programa. Puede ser necesaria una anotación de tipo anterior a este punto del programa para restringir el tipo del objeto. Esto puede permitir que se resuelva la búsqueda. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + Búsqueda de un objeto de tipo indeterminado basado en información anterior a este punto del programa. Puede ser necesaria una anotación de tipo anterior a este punto del programa para restringir el tipo del objeto. Esto puede permitir que se resuelva la búsqueda. diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf index 0a265c96bea..cb893afd402 100644 --- a/src/Compiler/xlf/FSStrings.fr.xlf +++ b/src/Compiler/xlf/FSStrings.fr.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - Recherche d'un objet de type indéterminé basé sur des informations situées avant ce point du programme. Une annotation de type peut être nécessaire avant ce point du programme pour contraindre le type de l'objet. Cela peut permettre la résolution de la recherche. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + Recherche d'un objet de type indéterminé basé sur des informations situées avant ce point du programme. Une annotation de type peut être nécessaire avant ce point du programme pour contraindre le type de l'objet. Cela peut permettre la résolution de la recherche. diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf index b0ceff4e83a..41c41b92221 100644 --- a/src/Compiler/xlf/FSStrings.it.xlf +++ b/src/Compiler/xlf/FSStrings.it.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - Ricerca in un oggetto di tipo non determinato basato su informazioni che si trovano prima di questo punto del programma. Potrebbe essere necessaria un'annotazione di tipo prima di questo punto del programma per vincolare il tipo dell'oggetto. Questa modifica potrebbe consentire la risoluzione della ricerca. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + Ricerca in un oggetto di tipo non determinato basato su informazioni che si trovano prima di questo punto del programma. Potrebbe essere necessaria un'annotazione di tipo prima di questo punto del programma per vincolare il tipo dell'oggetto. Questa modifica potrebbe consentire la risoluzione della ricerca. diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf index 58439655441..b8bbb2321a5 100644 --- a/src/Compiler/xlf/FSStrings.ja.xlf +++ b/src/Compiler/xlf/FSStrings.ja.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - このプログラムの場所の前方にある情報に基づく不確定の型のオブジェクトに対する参照です。場合によっては、オブジェクトの型を制約する型の注釈がこのプログラムの場所の前に必要です。この操作で参照が解決される可能性があります。 + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + このプログラムの場所の前方にある情報に基づく不確定の型のオブジェクトに対する参照です。場合によっては、オブジェクトの型を制約する型の注釈がこのプログラムの場所の前に必要です。この操作で参照が解決される可能性があります。 diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf index 84886e9c6ca..46cce884f7c 100644 --- a/src/Compiler/xlf/FSStrings.ko.xlf +++ b/src/Compiler/xlf/FSStrings.ko.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - 이 프로그램 지점 전의 정보를 기반으로 하는 확인할 수 없는 형식의 개체를 대상으로 조회를 수행합니다. 개체의 형식을 제한하기 위해 이 프로그램 지점 전에 형식 주석이 필요할 수 있습니다. 이를 통해 조회가 확인될 수도 있습니다. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + 이 프로그램 지점 전의 정보를 기반으로 하는 확인할 수 없는 형식의 개체를 대상으로 조회를 수행합니다. 개체의 형식을 제한하기 위해 이 프로그램 지점 전에 형식 주석이 필요할 수 있습니다. 이를 통해 조회가 확인될 수도 있습니다. diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf index 04e2db874cd..c662402760a 100644 --- a/src/Compiler/xlf/FSStrings.pl.xlf +++ b/src/Compiler/xlf/FSStrings.pl.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - Odnośnik do obiektu nieokreślonego typu na podstawie informacji przed tym punktem programu. Może być wymagana adnotacja typu przed tym punktem programu w celu ograniczenia typu obiektu. Może to umożliwić rozpoznanie odnośnika. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + Odnośnik do obiektu nieokreślonego typu na podstawie informacji przed tym punktem programu. Może być wymagana adnotacja typu przed tym punktem programu w celu ograniczenia typu obiektu. Może to umożliwić rozpoznanie odnośnika. diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf index ecce364bb99..f5bc196602a 100644 --- a/src/Compiler/xlf/FSStrings.pt-BR.xlf +++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - Pesquisa por um objeto de tipo indeterminado baseado em informações anteriores a este ponto do programa. Uma anotação de tipo pode ser necessária antes deste ponto do programa para restringir o tipo do objeto. Isto deverá permitir que a pesquisa seja resolvida. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + Pesquisa por um objeto de tipo indeterminado baseado em informações anteriores a este ponto do programa. Uma anotação de tipo pode ser necessária antes deste ponto do programa para restringir o tipo do objeto. Isto deverá permitir que a pesquisa seja resolvida. diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf index fff4ab3f12d..071963e992d 100644 --- a/src/Compiler/xlf/FSStrings.ru.xlf +++ b/src/Compiler/xlf/FSStrings.ru.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - Поиск объекта неопределенного типа, основанного на информации до данной точки программы. Возможно, перед данной точкой программы потребуется аннотация типа, с целью ограничения типа объекта. Возможно, это позволит разрешить поиск. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + Поиск объекта неопределенного типа, основанного на информации до данной точки программы. Возможно, перед данной точкой программы потребуется аннотация типа, с целью ограничения типа объекта. Возможно, это позволит разрешить поиск. diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf index 69a73dfd9fd..39b66087754 100644 --- a/src/Compiler/xlf/FSStrings.tr.xlf +++ b/src/Compiler/xlf/FSStrings.tr.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - Bu program noktasından önceki bilgilere dayalı olarak belirsiz türdeki nesne araması. Bu program noktasından önce nesnenin türünü kısıtlamak için bir tür ek açıklaması gerekebilir. Bu, aramanın çözümlenmesine izin verebilir. + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + Bu program noktasından önceki bilgilere dayalı olarak belirsiz türdeki nesne araması. Bu program noktasından önce nesnenin türünü kısıtlamak için bir tür ek açıklaması gerekebilir. Bu, aramanın çözümlenmesine izin verebilir. diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf index f2f98d4e788..730fb86a85e 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - 查找基于此程序点之前的信息的不确定类型的对象。在此程序点之前可能需要类型批注来约束对象的类型。这可能允许解析查找。 + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + 查找基于此程序点之前的信息的不确定类型的对象。在此程序点之前可能需要类型批注来约束对象的类型。这可能允许解析查找。 diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf index 571fa7b1446..4a82caa840a 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf @@ -233,8 +233,8 @@ - Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. - 根據這個程式點之前的資訊,查詢是針對不定類型的物件。在這個程式點之前可能需要類型註釋,以限制物件的類型。這樣或許可以讓查詢能夠解析。 + The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. + 根據這個程式點之前的資訊,查詢是針對不定類型的物件。在這個程式點之前可能需要類型註釋,以限制物件的類型。這樣或許可以讓查詢能夠解析。 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ModuleAbbreviations/ModuleAbbreviations.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ModuleAbbreviations/ModuleAbbreviations.fs index 6f457f7c5e4..a2fca4aa81d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ModuleAbbreviations/ModuleAbbreviations.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/ModuleAbbreviations/ModuleAbbreviations.fs @@ -31,7 +31,7 @@ module ModuleAbbreviations = (Error 39, Line 13, Col 15, Line 13, Col 17, "The value, namespace, type or module 'IO' is not defined.") (Error 965, Line 16, Col 1, Line 16, Col 43, "The path 'System.Text.RegularExpressions' is a namespace. A module abbreviation may not abbreviate a namespace.") (Error 39, Line 18, Col 19, Line 18, Col 21, "The namespace or module 'rx' is not defined.") - (Error 72, Line 21, Col 4, Line 21, Col 19, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.") + (Error 72, Line 21, Col 4, Line 21, Col 19, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point.") ] // SOURCE=E_InvalidAbbrevName01.fs SCFLAGS="--test:ErrorRanges" # E_InvalidAbbrevName01.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/InferenceProcedures/ByrefSafetyAnalysis/ByrefSafetyAnalysis.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/InferenceProcedures/ByrefSafetyAnalysis/ByrefSafetyAnalysis.fs index d3fad55a539..40d511a028b 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/InferenceProcedures/ByrefSafetyAnalysis/ByrefSafetyAnalysis.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/InferenceProcedures/ByrefSafetyAnalysis/ByrefSafetyAnalysis.fs @@ -609,7 +609,7 @@ The type 'ByRefKinds.InOut' does not match the type 'ByRefKinds.In'") |> shouldFail |> withDiagnostics [ (Error 39, Line 1, Col 18, Line 1, Col 19, "The type 'S' is not defined.") - (Error 72, Line 1, Col 24, Line 1, Col 27, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.") + (Error 72, Line 1, Col 24, Line 1, Col 27, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point.") ] [] diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/RecordTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/RecordTypes.fs index 61b66c956aa..e5fefa0b7c2 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/RecordTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/RecordTypes/RecordTypes.fs @@ -100,9 +100,9 @@ module RecordTypes = |> shouldFail |> withDiagnostics [ (Error 39, Line 16, Col 15, Line 16, Col 30, "The type 'IStructuralHash' is not defined.") - (Error 72, Line 17, Col 1, Line 17, Col 25, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.") + (Error 72, Line 17, Col 1, Line 17, Col 25, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point.") (Error 39, Line 20, Col 15, Line 20, Col 30, "The type 'IStructuralHash' is not defined.") - (Error 72, Line 21, Col 1, Line 21, Col 25, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.") + (Error 72, Line 21, Col 1, Line 21, Col 25, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point.") ] // SOURCE=E_MutableFields01.fsx SCFLAGS="--test:ErrorRanges" # E_MutableFields01.fsx diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs index aea5429b356..7d5db82abde 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs @@ -172,9 +172,9 @@ module UnionTypes = |> shouldFail |> withDiagnostics [ (Error 39, Line 17, Col 15, Line 17, Col 30, "The type 'IStructuralHash' is not defined.") - (Error 72, Line 18, Col 1, Line 18, Col 25, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.") + (Error 72, Line 18, Col 1, Line 18, Col 25, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point.") (Error 39, Line 21, Col 15, Line 21, Col 30, "The type 'IStructuralHash' is not defined.") - (Error 72, Line 22, Col 1, Line 22, Col 25, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.") + (Error 72, Line 22, Col 1, Line 22, Col 25, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point.") ] //SOURCE=E_FieldNameUsedMulti.fs SCFLAGS="--test:ErrorRanges" # E_FieldNameUsedMulti.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Language/DotLambdaTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/DotLambdaTests.fs index 1907d32fa23..500e03089ca 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/DotLambdaTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/DotLambdaTests.fs @@ -102,7 +102,7 @@ let myFunction (x:MyRecord) = x |> _.DoStuff 1 2 3""" |> shouldFail |> withDiagnostics [ Error 3584, Line 4, Col 36, Line 4, Col 45, "Shorthand lambda syntax is only supported for atomic expressions, such as method, property, field or indexer on the implied '_' argument. For example: 'let f = _.Length'." - Error 72, Line 4, Col 36, Line 4, Col 45, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved." + Error 72, Line 4, Col 36, Line 4, Col 45, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point." ] [] @@ -155,7 +155,7 @@ let ``DotLambda does NOT generalize automatically to a member based SRTP`` () = |> withLangVersion80 |> typecheck |> shouldFail - |> withDiagnostics [(Error 72, Line 1, Col 28, Line 1, Col 47, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.")] + |> withDiagnostics [(Error 72, Line 1, Col 28, Line 1, Col 47, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point.")] [] let ``DotLambda does allow member based SRTP if labelled explicitly`` () = @@ -249,7 +249,7 @@ let ``Regression 16318 typeof dotlambda should fail`` () = |> withLangVersion80 |> typecheck |> shouldFail - |> withDiagnostics [Error 72, Line 1, Col 10, Line 1, Col 18, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved."] + |> withDiagnostics [Error 72, Line 1, Col 10, Line 1, Col 18, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point."] [] let ``Nested anonymous unary function shorthands fails because of ambiguous discard`` () = diff --git a/tests/FSharp.Compiler.ComponentTests/Language/ObsoleteAttributeCheckingTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/ObsoleteAttributeCheckingTests.fs index d9a8bfb28f0..c74309a4138 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/ObsoleteAttributeCheckingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/ObsoleteAttributeCheckingTests.fs @@ -1604,7 +1604,7 @@ let f (x: IFirst) = x.F() |> withDiagnostics [ (Error 101, Line 9, Col 11, Line 9, Col 17, "This construct is deprecated. Use G instead") (Error 101, Line 13, Col 11, Line 13, Col 17, "This construct is deprecated. Use G instead") - (Error 72, Line 13, Col 21, Line 13, Col 24, "Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved.") + (Error 72, Line 13, Col 21, Line 13, Col 24, "The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point.") ] [] diff --git a/tests/fsharp/typecheck/sigs/neg106.bsl b/tests/fsharp/typecheck/sigs/neg106.bsl index feb58523b1f..f25e10e776e 100644 --- a/tests/fsharp/typecheck/sigs/neg106.bsl +++ b/tests/fsharp/typecheck/sigs/neg106.bsl @@ -91,7 +91,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.Out' does not match the type 'ByRefKinds.In' -neg106.fs(102,37,102,40): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(102,37,102,40): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(102,36,102,40): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. @@ -107,7 +107,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.InOut' does not match the type 'ByRefKinds.In' -neg106.fs(112,39,112,42): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(112,39,112,42): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(112,38,112,42): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. @@ -123,7 +123,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.Out' does not match the type 'ByRefKinds.In' -neg106.fs(122,39,122,42): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(122,39,122,42): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(122,38,122,42): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. @@ -139,7 +139,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.InOut' does not match the type 'ByRefKinds.In' -neg106.fs(132,39,132,42): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(132,39,132,42): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(132,38,132,42): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. @@ -155,7 +155,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.Out' does not match the type 'ByRefKinds.In' -neg106.fs(142,39,142,42): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(142,39,142,42): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(142,38,142,42): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. diff --git a/tests/fsharp/typecheck/sigs/neg106.vsbsl b/tests/fsharp/typecheck/sigs/neg106.vsbsl index feb58523b1f..f25e10e776e 100644 --- a/tests/fsharp/typecheck/sigs/neg106.vsbsl +++ b/tests/fsharp/typecheck/sigs/neg106.vsbsl @@ -91,7 +91,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.Out' does not match the type 'ByRefKinds.In' -neg106.fs(102,37,102,40): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(102,37,102,40): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(102,36,102,40): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. @@ -107,7 +107,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.InOut' does not match the type 'ByRefKinds.In' -neg106.fs(112,39,112,42): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(112,39,112,42): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(112,38,112,42): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. @@ -123,7 +123,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.Out' does not match the type 'ByRefKinds.In' -neg106.fs(122,39,122,42): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(122,39,122,42): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(122,38,122,42): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. @@ -139,7 +139,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.InOut' does not match the type 'ByRefKinds.In' -neg106.fs(132,39,132,42): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(132,39,132,42): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(132,38,132,42): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. @@ -155,7 +155,7 @@ but given a 'inref<'T>' The type 'ByRefKinds.Out' does not match the type 'ByRefKinds.In' -neg106.fs(142,39,142,42): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg106.fs(142,39,142,42): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg106.fs(142,38,142,42): typecheck error FS3236: Cannot take the address of the value returned from the expression. Assign the returned value to a let-bound value before taking the address. diff --git a/tests/fsharp/typecheck/sigs/neg15.bsl b/tests/fsharp/typecheck/sigs/neg15.bsl index 3089124970c..e82c0042d11 100644 --- a/tests/fsharp/typecheck/sigs/neg15.bsl +++ b/tests/fsharp/typecheck/sigs/neg15.bsl @@ -21,25 +21,25 @@ neg15.fs(113,17,113,76): typecheck error FS1093: The union cases or fields of th neg15.fs(114,17,114,52): typecheck error FS1092: The type 'PrivateRecordType' is not accessible from this code location -neg15.fs(115,19,115,48): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg15.fs(115,19,115,48): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. -neg15.fs(116,20,116,73): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg15.fs(116,20,116,73): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg15.fs(122,32,122,57): typecheck error FS0039: The value, constructor, namespace or type 'InternalTagOfInternalType' is not defined. Maybe you want one of the following: InternalUnionType InternalRecordType DefaultTagOfInternalType -neg15.fs(128,31,128,61): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg15.fs(128,31,128,61): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg15.fs(135,31,135,56): typecheck error FS0039: The value, constructor, namespace or type 'InternalTagOfInternalType' is not defined. Maybe you want one of the following: InternalUnionType InternalRecordType DefaultTagOfInternalType -neg15.fs(141,30,141,60): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg15.fs(141,30,141,60): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. -neg15.fs(152,20,152,50): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg15.fs(152,20,152,50): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg15.fs(183,1,183,5): typecheck error FS0491: The member or object constructor 'P' is not accessible. Private members may only be accessed from within the declaring type. Protected members may only be accessed from an extending type and cannot be accessed from inner lambda expressions. diff --git a/tests/fsharp/typecheck/sigs/neg17.bsl b/tests/fsharp/typecheck/sigs/neg17.bsl index 673e0b7ec78..d322538b929 100644 --- a/tests/fsharp/typecheck/sigs/neg17.bsl +++ b/tests/fsharp/typecheck/sigs/neg17.bsl @@ -19,24 +19,24 @@ neg17b.fs(15,17,15,52): typecheck error FS1092: The type 'PrivateRecordType' is neg17b.fs(15,17,15,52): typecheck error FS1092: The type 'PrivateRecordType' is not accessible from this code location -neg17b.fs(16,19,16,48): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg17b.fs(16,19,16,48): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. -neg17b.fs(17,19,17,47): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg17b.fs(17,19,17,47): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg17b.fs(21,31,21,77): typecheck error FS0039: The value, constructor, namespace or type 'DefaultTagOfUnionTypeWithPrivateRepresentation' is not defined. Maybe you want one of the following: DefaultTagOfInternalType UnionTypeWithPrivateRepresentation -neg17b.fs(29,31,29,61): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg17b.fs(29,31,29,61): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. -neg17b.fs(30,31,30,84): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg17b.fs(30,31,30,84): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg17b.fs(32,24,32,50): typecheck error FS0039: The type 'RecordTypeWithPrivateField' is not defined in 'Neg17.M'. Maybe you want one of the following: RecordTypeWithPrivateRepresentation -neg17b.fs(43,30,43,60): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg17b.fs(43,30,43,60): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. neg17b.fs(45,23,45,49): typecheck error FS0039: The type 'RecordTypeWithPrivateField' is not defined in 'Neg17.M'. Maybe you want one of the following: RecordTypeWithPrivateRepresentation -neg17b.fs(54,20,54,50): typecheck error FS0072: Lookup on object of indeterminate type based on information prior to this program point. A type annotation may be needed prior to this program point to constrain the type of the object. This may allow the lookup to be resolved. +neg17b.fs(54,20,54,50): typecheck error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point. From b7ada5b192e912a44b38f50c6d4305f6cc8a9a18 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 20 Feb 2026 20:46:05 +0100 Subject: [PATCH 02/39] FS0039: Reword 'does not define field/constructor/member' to clearer phrasing Change error message from: The type 'X' does not define the field, constructor or member 'Y'. to: The type 'X' does not have a field, property, or member named 'Y'. Fixes #13012 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/FSComp.txt | 2 +- src/Compiler/xlf/FSComp.txt.cs.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.de.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.es.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.fr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.it.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ja.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ko.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pl.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ru.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.tr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 4 ++-- .../CompilerService/FSharpWorkspace.fs | 2 +- .../MethodsAndProperties/E_ActivePatternMember01.fs | 2 +- .../MethodsAndProperties/MethodsAndProperties.fs | 4 ++-- .../OptionalArguments/OptionalArguments.fs | 4 ++-- .../ObjectConstruction/E_ObjectConstruction01.fs | 2 +- .../E_InvalidSelfReferentialStructConstructor.fs | 2 +- .../Expressions/SyntacticSugar/E_GetSliceNotDef01.fs | 2 +- .../Expressions/SyntacticSugar/SyntacticSugar.fs | 4 ++-- .../EnumTypes/E_NoValueFieldOnEnum.fs | 2 +- .../InterfaceTypes/E_MultipleInterfaceInheritance.fs | 6 +++--- .../Conformance/Signatures/Signatures.fs | 2 +- .../ErrorMessages/NameResolutionTests.fs | 4 ++-- .../ErrorMessages/SuggestionsTests.fs | 12 ++++++------ .../Import/ImportTests.fs | 2 +- .../Interop/DeeplyNestedCSharpClasses.fs | 6 +++--- .../Language/ComputationExpressionTests.fs | 2 +- .../Language/DiscriminatedUnionTests.fs | 6 +++--- .../E_StructWithNameConflict02.fsi | 2 +- .../Compiler/Language/CustomCollectionTests.fs | 4 ++-- .../Compiler/Language/DefaultInterfaceMemberTests.fs | 6 +++--- .../expressions/syntacticsugar/E_Slices01.bsl | 2 +- ...TypeWithIncorrectNameFromApplyStaticArguments.bsl | 2 +- tests/fsharp/typecheck/sigs/neg04.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg06.bsl | 2 +- tests/fsharp/typecheck/sigs/neg08.bsl | 2 +- tests/fsharp/typecheck/sigs/neg101.bsl | 2 +- tests/fsharp/typecheck/sigs/neg17.bsl | 8 ++++---- tests/fsharp/typecheck/sigs/neg20.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg45.bsl | 2 +- tests/fsharp/typecheck/sigs/neg55.bsl | 2 +- 44 files changed, 80 insertions(+), 80 deletions(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index c1b6736f158..310c3e57176 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -5,7 +5,7 @@ undefinedNameNamespace,"The namespace '%s' is not defined." undefinedNameNamespaceOrModule,"The namespace or module '%s' is not defined." undefinedNameFieldConstructorOrMember,"The field, constructor or member '%s' is not defined." -undefinedNameFieldConstructorOrMemberWhenTypeIsKnown,"The type '%s' does not define the field, constructor or member '%s'." +undefinedNameFieldConstructorOrMemberWhenTypeIsKnown,"The type '%s' does not have a field, property, or member named '%s'." undefinedNameValueConstructorNamespaceOrType,"The value, constructor, namespace or type '%s' is not defined." undefinedNameValueOfConstructor,"The value or constructor '%s' is not defined." undefinedNameValueNamespaceTypeOrModule,"The value, namespace, type or module '%s' is not defined." diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index f8c72037e1e..6c4ddc77dd3 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - Typ {0} nedefinuje pole, konstruktor ani člen {1}. + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index f9271e5b32f..102967b9104 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - Der Typ "{0}" definiert nicht das Feld, den Konstruktor oder den Member "{1}". + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 1989ceb6078..90aa2b88790 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - El tipo "{0}" no define el campo, constructor o miembro "{1}". + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index a707b886f6e..9daee40beee 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - Le type '{0}' ne définit pas le champ, le constructeur ou le membre '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 5bfc10f12a6..42d7c4a9d82 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - Il tipo '{0}' non definisce il campo, il costruttore o il membro '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 1e31efbbe42..f57c8953f3f 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - 型 '{0}' は、フィールド、コンストラクター、またはメンバー '{1}' を定義していません。 + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 4312ec97276..38e8abcd74b 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - '{0}' 형식은 '{1}' 필드, 생성자 또는 멤버를 정의하지 않습니다. + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index bc96b9e1716..9d195e673a0 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - Typ „{0}” nie definiuje pola, konstruktora lub składowej „{1}”. + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 72bc274c921..a0834de610d 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - O tipo '{0}' não define o campo, o construtor ou o membro '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 5ef2a6eef3e..340a6dc6d22 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - Тип "{0}" не определяет поле, конструктор или член "{1}". + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 8db95b959f0..d21a944b388 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - '{0}' türü; alanı, oluşturucuyu veya '{1}' üyesini tanımlamıyor. + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 6eddc15e91d..247bf228d69 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - 类型“{0}”未定义字段、构造函数或成员“{1}”。 + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 61468e74752..14493e8e180 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -1843,8 +1843,8 @@ - The type '{0}' does not define the field, constructor or member '{1}'. - 類型 '{0}' 未定義欄位、建構函式或成員 '{1}'。 + The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not have a field, property, or member named '{1}'. diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs index 3f4b41679ab..3cf97a45dae 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs @@ -441,7 +441,7 @@ let ``Giraffe signature test`` () = let! diag = workspace.Query.GetDiagnosticsForFile(Uri(giraffeSignaturesSampleDir ++ "Program.fs")) Assert.Equal(1, diag.Diagnostics.Length) - Assert.Equal("The type 'IServiceCollection' does not define the field, constructor or member 'AddGiraffe'.", diag.Diagnostics[0].Message) + Assert.Equal("The type 'IServiceCollection' does not have a field, property, or member named 'AddGiraffe'.", diag.Diagnostics[0].Message) } #endif \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/E_ActivePatternMember01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/E_ActivePatternMember01.fs index adf50eef460..3234d86fa03 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/E_ActivePatternMember01.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/E_ActivePatternMember01.fs @@ -2,7 +2,7 @@ // Regression for FSHARP1.0:6168 // Active patterns should not be allowed as members - they don't work , but currently can be defined //This is not a valid name for an active pattern -//The type 'FaaBor' does not define the field, constructor or member 'Foo' +//The type 'FaaBor' does not have a field, property, or member named 'Foo' module M diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/MethodsAndProperties.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/MethodsAndProperties.fs index 44ae4972bc9..0253276fe26 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/MethodsAndProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/MethodsAndProperties.fs @@ -71,7 +71,7 @@ module MemberDefinitions_MethodsAndProperties = |> shouldFail |> withDiagnostics [ (Error 827, Line 10, Col 20, Line 10, Col 29, "'(|Foo|Bar|)' is not a valid method name. Use a 'let' binding instead.") - (Error 39, Line 21, Col 10, Line 21, Col 13, "The type 'FaaBor' does not define the field, constructor or member 'Foo'.") + (Error 39, Line 21, Col 10, Line 21, Col 13, "The type 'FaaBor' does not have a field, property, or member named 'Foo'.") ] // SOURCE=E_ActivePatternMember02.fs SCFLAGS="--test:ErrorRanges" # E_ActivePatternMember02.fs @@ -154,7 +154,7 @@ module MemberDefinitions_MethodsAndProperties = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 39, Line 13, Col 9, Line 13, Col 15, "The type 'Foo' does not define the field, constructor or member 'Item'.") + (Error 39, Line 13, Col 9, Line 13, Col 15, "The type 'Foo' does not have a field, property, or member named 'Item'.") ] // SOURCE=E_OutscopeThisPtr01.fs SCFLAGS="--test:ErrorRanges" # E_OutscopeThisPtr01.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs index 508314ee941..bda47c8a119 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs @@ -73,7 +73,7 @@ module MemberDefinitions_OptionalArguments = |> shouldFail |> withDiagnostics [ (Error 1212, Line 7, Col 22, Line 7, Col 32, "Optional arguments must come at the end of the argument list, after any non-optional arguments") - (Error 39, Line 8, Col 5, Line 8, Col 8, "The type 'Foo' does not define the field, constructor or member 'Bar'.") + (Error 39, Line 8, Col 5, Line 8, Col 8, "The type 'Foo' does not have a field, property, or member named 'Bar'.") ] // SOURCE=E_SanityCheck02.fs @@ -84,7 +84,7 @@ module MemberDefinitions_OptionalArguments = |> shouldFail |> withDiagnostics [ (Error 1212, Line 7, Col 22, Line 7, Col 29, "Optional arguments must come at the end of the argument list, after any non-optional arguments") - (Error 39, Line 8, Col 5, Line 8, Col 8, "The type 'Foo' does not define the field, constructor or member 'Bar'.") + (Error 39, Line 8, Col 5, Line 8, Col 8, "The type 'Foo' does not have a field, property, or member named 'Bar'.") ] // SOURCE=optionalOfOptOptA.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ApplicationExpressions/ObjectConstruction/E_ObjectConstruction01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ApplicationExpressions/ObjectConstruction/E_ObjectConstruction01.fs index cf368bdfbb0..aee8a055f57 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ApplicationExpressions/ObjectConstruction/E_ObjectConstruction01.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ApplicationExpressions/ObjectConstruction/E_ObjectConstruction01.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #ApplicationExpressions #ObjectConstructors // Verify error for inaccessible constructor -//The type 'BitArray' does not define the field, constructor or member 'BitArrayEnumeratorSimple' +//The type 'BitArray' does not have a field, property, or member named 'BitArrayEnumeratorSimple' let y = System.Collections.BitArray.BitArrayEnumeratorSimple () diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/DataExpressions/ObjectExpressions/E_InvalidSelfReferentialStructConstructor.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/DataExpressions/ObjectExpressions/E_InvalidSelfReferentialStructConstructor.fs index 2a74365591c..7f693dae7b0 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/DataExpressions/ObjectExpressions/E_InvalidSelfReferentialStructConstructor.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/DataExpressions/ObjectExpressions/E_InvalidSelfReferentialStructConstructor.fs @@ -3,7 +3,7 @@ //Structs may only bind a 'this' parameter at member declarations$ //This is not a valid object construction expression\. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor\.$ -//The type 'byref<_,_>' does not define the field, constructor or member 'dt' +//The type 'byref<_,_>' does not have a field, property, or member named 'dt' module mod6350 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/E_GetSliceNotDef01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/E_GetSliceNotDef01.fs index c2a12354ad7..24d1875e981 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/E_GetSliceNotDef01.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/E_GetSliceNotDef01.fs @@ -2,7 +2,7 @@ // Verify error if GetSlice is not defined -//The type 'DU' does not define the field, constructor or member 'GetSlice' +//The type 'DU' does not have a field, property, or member named 'GetSlice' type DU = A | B of int | C diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/SyntacticSugar.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/SyntacticSugar.fs index e7a1a9a50e8..0e5731d5cb3 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/SyntacticSugar.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/SyntacticSugar.fs @@ -82,7 +82,7 @@ module SyntacticSugar = |> verifyCompile // SOURCE=E_GetSliceNotDef01.fs - // The type 'DU' does not define the field, constructor or member 'GetSlice' + // The type 'DU' does not have a field, property, or member named 'GetSlice' [] let ``E_GetSliceNotDef01_fs`` compilation = compilation @@ -90,7 +90,7 @@ module SyntacticSugar = |> verifyTypecheck |> shouldFail |> withErrorCode 39 - |> withDiagnosticMessageMatches "The type 'DU' does not define the field, constructor or member 'GetSlice'" + |> withDiagnosticMessageMatches "The type 'DU' does not have a field, property, or member named 'GetSlice'" // SOURCE=E_GetSliceNotDef02.fs // ... diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoValueFieldOnEnum.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoValueFieldOnEnum.fs index a3fb2787598..917c4398046 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoValueFieldOnEnum.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoValueFieldOnEnum.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #ObjectOrientedTypes #Enums // FS1 992: ilreflect error triggered with Enum value__ calls. -//The type 'EnumType' does not define the field, constructor or member 'value__' +//The type 'EnumType' does not have a field, property, or member named 'value__' type EnumType = | A = 1 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/InterfaceTypes/E_MultipleInterfaceInheritance.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/InterfaceTypes/E_MultipleInterfaceInheritance.fs index df1d97e60d0..67bdf79c6a6 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/InterfaceTypes/E_MultipleInterfaceInheritance.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/InterfaceTypes/E_MultipleInterfaceInheritance.fs @@ -60,9 +60,9 @@ if ( {new I_003 with System.Console.WriteLine("I_003.Home failed") res <- false -//The type 'T' does not define the field, constructor or member 'Me' -//The type 'T' does not define the field, constructor or member 'Me' -//The type 'T' does not define the field, constructor or member 'Home' +//The type 'T' does not have a field, property, or member named 'Me' +//The type 'T' does not have a field, property, or member named 'Me' +//The type 'T' does not have a field, property, or member named 'Home' //No implementation was given for those members: //'abstract I_002\.Me: 'a -> int'\. //'abstract I_002\.Me: 'a -> int'\. diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/Signatures.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/Signatures.fs index 1dc0799cb8e..034d016dffa 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/Signatures.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/Signatures.fs @@ -127,7 +127,7 @@ module SignatureConformance = // Regression for Dev11:137942 - structs used to not give errors when member names conflicted with interface members // SOURCE="E_StructWithNameConflict02.fsi E_StructWithNameConflict02.fs" SCFLAGS="--test:ErrorRanges --flaterrors" - // The type 'Foo<_>' does not define the field, constructor or member 'GetEnumerator' + // The type 'Foo<_>' does not have a field, property, or member named 'GetEnumerator' // ... [] let ``E_StructWithNameConflict02 - struct undefined member from signature`` () = diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/NameResolutionTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/NameResolutionTests.fs index fdf1608b9b2..59e4f045ced 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/NameResolutionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/NameResolutionTests.fs @@ -77,7 +77,7 @@ module Lib = |> shouldFail |> withDiagnostics [ (Warning 3566, Line 22, Col 9, Line 22, Col 19, "Multiple type matches were found:\n N.Module1.OtherThing\n N.Module2.Person\nThe type 'N.Module1.OtherThing' was used. Due to the overlapping field names\n Name\nconsider using type annotations or change the order of open statements.") - (Error 39, Line 22, Col 15, Line 22, Col 19, "The type 'OtherThing' does not define the field, constructor or member 'City'.") + (Error 39, Line 22, Col 15, Line 22, Col 19, "The type 'OtherThing' does not have a field, property, or member named 'City'.") ] let multipleRecdTypeChoiceWarningWith2AlternativeSource = """ @@ -123,7 +123,7 @@ module Lib = |> shouldFail |> withDiagnostics [ (Warning 3566, Line 33, Col 9, Line 33, Col 19, "Multiple type matches were found:\n N.Module1.OtherThing\n N.Module2.Person\n N.Module3.Cafe\nThe type 'N.Module1.OtherThing' was used. Due to the overlapping field names\n Name\n Planet\nconsider using type annotations or change the order of open statements.") - (Error 39, Line 33, Col 15, Line 33, Col 19, "The type 'OtherThing' does not define the field, constructor or member 'City'.") + (Error 39, Line 33, Col 15, Line 33, Col 19, "The type 'OtherThing' does not have a field, property, or member named 'City'.") ] let multipleRecdTypeChoiceWarningNotRaisedWithCorrectOpenStmtsOrderingSource = """ diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuggestionsTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuggestionsTests.fs index 0657c6f4ec4..9772dcf5cef 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuggestionsTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuggestionsTests.fs @@ -18,7 +18,7 @@ let x = { Person.Names = "Isaac" } |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 4, Col 18, Line 4, Col 23, - ("The type 'Person' does not define the field, constructor or member 'Names'. Maybe you want one of the following:" + Environment.NewLine + " Name")) + ("The type 'Person' does not have a field, property, or member named 'Names'. Maybe you want one of the following:" + Environment.NewLine + " Name")) [] let ``Suggest Array Module Functions`` () = @@ -77,7 +77,7 @@ let x = N.MyUnion.``My Case2`` |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 9, Col 19, Line 9,Col 31, - ("The type 'MyUnion' does not define the field, constructor or member 'My Case2'. Maybe you want one of the following:" + Environment.NewLine + " Case2" + Environment.NewLine + " ``My Case1``" + Environment.NewLine + " IsMy Case1")) + ("The type 'MyUnion' does not have a field, property, or member named 'My Case2'. Maybe you want one of the following:" + Environment.NewLine + " Case2" + Environment.NewLine + " ``My Case1``" + Environment.NewLine + " IsMy Case1")) [] @@ -120,7 +120,7 @@ module Test2 = |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 9, Col 7, Line 9, Col 14, - ("The type 'D' does not define the field, constructor or member 'Method2'. Maybe you want one of the following:" + Environment.NewLine + " Method1")) + ("The type 'D' does not have a field, property, or member named 'Method2'. Maybe you want one of the following:" + Environment.NewLine + " Method1")) [] let ``Suggest Modules`` () = @@ -158,7 +158,7 @@ let x = r.ello |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 6, Col 11, Line 6, Col 15, - ("The type 'MyRecord' does not define the field, constructor or member 'ello'. Maybe you want one of the following:" + Environment.NewLine + " Hello")) + ("The type 'MyRecord' does not have a field, property, or member named 'ello'. Maybe you want one of the following:" + Environment.NewLine + " Hello")) [] let ``Suggest Record Type for RequireQualifiedAccess Records`` () = @@ -224,7 +224,7 @@ let u = MyUnion.AntherCase |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 6, Col 17, Line 6, Col 27, - ("The type 'MyUnion' does not define the field, constructor or member 'AntherCase'. Maybe you want one of the following:" + Environment.NewLine + " AnotherCase" + Environment.NewLine + " IsAnotherCase")) + ("The type 'MyUnion' does not have a field, property, or member named 'AntherCase'. Maybe you want one of the following:" + Environment.NewLine + " AnotherCase" + Environment.NewLine + " IsAnotherCase")) [] let ``Suggest Union Type for RequireQualifiedAccess Unions`` () = @@ -260,4 +260,4 @@ let x = |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 11, Col 15, Line 11, Col 19, - ("The type 'MyUnion' does not define the field, constructor or member 'Cas1'. Maybe you want one of the following:" + Environment.NewLine + " Case1" + Environment.NewLine + " Case2")) + ("The type 'MyUnion' does not have a field, property, or member named 'Cas1'. Maybe you want one of the following:" + Environment.NewLine + " Case1" + Environment.NewLine + " Case2")) diff --git a/tests/FSharp.Compiler.ComponentTests/Import/ImportTests.fs b/tests/FSharp.Compiler.ComponentTests/Import/ImportTests.fs index f19fcfeac14..e9aec0df6cd 100644 --- a/tests/FSharp.Compiler.ComponentTests/Import/ImportTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Import/ImportTests.fs @@ -554,7 +554,7 @@ type T() = |> withReferences [csLib] |> compile |> shouldFail - |> withErrorCode 39 // "The type does not define the field, constructor or member" + |> withErrorCode 39 // "The type does not have a field, property, or member named" |> ignore // ======================================== diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/DeeplyNestedCSharpClasses.fs b/tests/FSharp.Compiler.ComponentTests/Interop/DeeplyNestedCSharpClasses.fs index cbc02c49727..e682cedc8d7 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/DeeplyNestedCSharpClasses.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/DeeplyNestedCSharpClasses.fs @@ -54,7 +54,7 @@ let loss2 = MyNamespace.OuterClass.InnerClass_.MoreInnerClass.somefunction() / |> withReferences [cslib] |> compile |> shouldFail - |> withSingleDiagnostic (Error 39, Line 2, Col 36, Line 2, Col 47, "The type 'OuterClass' does not define the field, constructor or member 'InnerClass_'.") + |> withSingleDiagnostic (Error 39, Line 2, Col 36, Line 2, Col 47, "The type 'OuterClass' does not have a field, property, or member named 'InnerClass_'.") [] let ``Missing type nested type moreinnerclass generates good message and range`` () = @@ -68,7 +68,7 @@ let loss2 = MyNamespace.OuterClass.InnerClass.MoareInnerClass.somefunction() / |> withReferences [cslib] |> compile |> shouldFail - |> withSingleDiagnostic (Error 39, Line 2, Col 47, Line 2, Col 62, "The type 'InnerClass' does not define the field, constructor or member 'MoareInnerClass'.") + |> withSingleDiagnostic (Error 39, Line 2, Col 47, Line 2, Col 62, "The type 'InnerClass' does not have a field, property, or member named 'MoareInnerClass'.") [] let ``Missing function generates good message and range`` () = @@ -82,5 +82,5 @@ let loss2 = MyNamespace.OuterClass.InnerClass.MoreInnerClass.somefunction_() / |> withReferences [cslib] |> compile |> shouldFail - |> withSingleDiagnostic ((Error 39, Line 2, Col 62, Line 2, Col 75, """The type 'MoreInnerClass' does not define the field, constructor or member 'somefunction_'. Maybe you want one of the following: + |> withSingleDiagnostic ((Error 39, Line 2, Col 62, Line 2, Col 75, """The type 'MoreInnerClass' does not have a field, property, or member named 'somefunction_'. Maybe you want one of the following: somefunction""")) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs index 378879bbfc3..b1ea2b95ec7 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs @@ -175,7 +175,7 @@ let x = lb {1; 2;()} """ |> compile |> shouldFail - |> withSingleDiagnostic (Error 39, Line 10, Col 18, Line 10, Col 20, "The type 'ListBuilder' does not define the field, constructor or member 'Zero'.") + |> withSingleDiagnostic (Error 39, Line 10, Col 18, Line 10, Col 20, "The type 'ListBuilder' does not have a field, property, or member named 'Zero'.") |> ignore [] diff --git a/tests/FSharp.Compiler.ComponentTests/Language/DiscriminatedUnionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/DiscriminatedUnionTests.fs index fe2963643f3..a0ace1631d1 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/DiscriminatedUnionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/DiscriminatedUnionTests.fs @@ -28,7 +28,7 @@ if not foo.IsBar then failwith "Should be Bar" """ |> typecheck |> shouldFail - |> withDiagnostics [Error 39, Line 4, Col 12, Line 4, Col 17, "The type 'Foo' does not define the field, constructor or member 'IsBar'. Maybe you want one of the following: + |> withDiagnostics [Error 39, Line 4, Col 12, Line 4, Col 17, "The type 'Foo' does not have a field, property, or member named 'IsBar'. Maybe you want one of the following: Bar"] [] @@ -136,7 +136,7 @@ let isFoo = foo.IsFoo """ |> typecheck |> shouldFail - |> withErrorMessage "The type 'Foo' does not define the field, constructor or member 'IsFoo'. Maybe you want one of the following: + |> withErrorMessage "The type 'Foo' does not have a field, property, or member named 'IsFoo'. Maybe you want one of the following: Foo" @@ -154,7 +154,7 @@ let x = (PrimaryAssembly.Mscorlib).IsMscorlib |> withLangVersion80 |> typecheck |> shouldFail - |> withErrorMessage "The type 'PrimaryAssembly' does not define the field, constructor or member 'IsMscorlib'. Maybe you want one of the following: + |> withErrorMessage "The type 'PrimaryAssembly' does not have a field, property, or member named 'IsMscorlib'. Maybe you want one of the following: Mscorlib" diff --git a/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/Signatures/SignatureConformance/E_StructWithNameConflict02.fsi b/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/Signatures/SignatureConformance/E_StructWithNameConflict02.fsi index f94ece27d76..0722ca0c353 100644 --- a/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/Signatures/SignatureConformance/E_StructWithNameConflict02.fsi +++ b/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/Signatures/SignatureConformance/E_StructWithNameConflict02.fsi @@ -1,6 +1,6 @@ // #Conformance #Signatures #Structs #Regression // Regression for Dev11:137942, structs used to not give errors on when member names conflicted with interface members -//The type 'Foo<_>' does not define the field, constructor or member 'GetEnumerator' +//The type 'Foo<_>' does not have a field, property, or member named 'GetEnumerator' //Module 'M' contains override Foo\.GetEnumerator : unit -> IEnumerator<'T> but its signature specifies member Foo\.GetEnumerator : unit -> IEnumerator<'T> The compiled names differ module M diff --git a/tests/fsharp/Compiler/Language/CustomCollectionTests.fs b/tests/fsharp/Compiler/Language/CustomCollectionTests.fs index 0d1aa07d5e1..5003f5a2dd1 100644 --- a/tests/fsharp/Compiler/Language/CustomCollectionTests.fs +++ b/tests/fsharp/Compiler/Language/CustomCollectionTests.fs @@ -107,7 +107,7 @@ if a.[^2] <> 12 then failwith "expected 12" FSharpDiagnosticSeverity.Error 39 (9,7,9,9) - "The type 'foo' does not define the field, constructor or member 'GetReverseIndex'." + "The type 'foo' does not have a field, property, or member named 'GetReverseIndex'." [] let ``Custom collection with GetSlice and GetReverseIndex should support reverse index slicing``() = @@ -148,4 +148,4 @@ if a[^2..1] <> 13 then failwith "expected 13" FSharpDiagnosticSeverity.Error 39 (12,6,12,8) - "The type 'foo' does not define the field, constructor or member 'GetReverseIndex'." + "The type 'foo' does not have a field, property, or member named 'GetReverseIndex'." diff --git a/tests/fsharp/Compiler/Language/DefaultInterfaceMemberTests.fs b/tests/fsharp/Compiler/Language/DefaultInterfaceMemberTests.fs index 7e987ef3c5f..2269b2ad9a6 100644 --- a/tests/fsharp/Compiler/Language/DefaultInterfaceMemberTests.fs +++ b/tests/fsharp/Compiler/Language/DefaultInterfaceMemberTests.fs @@ -546,7 +546,7 @@ let f () = Compilation.Create(fsharpSource, Library, options = [|"--langversion:8.0"|], cmplRefs = [csCmpl]) CompilerAssert.CompileWithErrors(fsCmpl, [| - (FSharpDiagnosticSeverity.Error, 39, (16, 10, 16, 23), "The type 'ITest' does not define the field, constructor or member 'DefaultMethod'. Maybe you want one of the following: + (FSharpDiagnosticSeverity.Error, 39, (16, 10, 16, 23), "The type 'ITest' does not have a field, property, or member named 'DefaultMethod'. Maybe you want one of the following: NonDefaultMethod") |]) @@ -3720,7 +3720,7 @@ let f () = Compilation.Create(fsharpSource, Exe, options = [|"--langversion:8.0"|], cmplRefs = [csCmpl]) CompilerAssert.CompileWithErrors(fsCmpl, [| - (FSharpDiagnosticSeverity.Error, 39, (6, 17, 6, 29), "The type 'CSharpClass' does not define the field, constructor or member 'StaticMethod'.") + (FSharpDiagnosticSeverity.Error, 39, (6, 17, 6, 29), "The type 'CSharpClass' does not have a field, property, or member named 'StaticMethod'.") |]) [] @@ -3770,7 +3770,7 @@ let f () = Compilation.Create(fsharpSource, Exe, options = [|"--langversion:8.0"|], cmplRefs = [csCmpl]) CompilerAssert.CompileWithErrors(fsCmpl, [| - (FSharpDiagnosticSeverity.Error, 39, (11, 17, 11, 29), "The type 'FSharpClass' does not define the field, constructor or member 'StaticMethod'.") + (FSharpDiagnosticSeverity.Error, 39, (11, 17, 11, 29), "The type 'FSharpClass' does not have a field, property, or member named 'StaticMethod'.") |]) [] diff --git a/tests/fsharp/conformance/expressions/syntacticsugar/E_Slices01.bsl b/tests/fsharp/conformance/expressions/syntacticsugar/E_Slices01.bsl index 4f092ad8b6c..8bc348bcdb9 100644 --- a/tests/fsharp/conformance/expressions/syntacticsugar/E_Slices01.bsl +++ b/tests/fsharp/conformance/expressions/syntacticsugar/E_Slices01.bsl @@ -31,7 +31,7 @@ Candidates: - member Foo.GetSlice: x1: float option * x2: int option * y: int -> unit - member Foo.GetSlice: x1: int option * x2: int option * y: int -> unit -E_Slices01.fsx(19,9,19,17): typecheck error FS0039: The type 'Foo<_>' does not define the field, constructor or member 'Item'. +E_Slices01.fsx(19,9,19,17): typecheck error FS0039: The type 'Foo<_>' does not have a field, property, or member named 'Item'. E_Slices01.fsx(20,9,20,26): typecheck error FS0503: A member or object constructor 'GetSlice' taking 4 arguments is not accessible from this code location. All accessible versions of method 'GetSlice' take 3 arguments. diff --git a/tests/fsharp/typeProviders/negTests/EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.bsl b/tests/fsharp/typeProviders/negTests/EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.bsl index 67d18357023..7cb4de4b26b 100644 --- a/tests/fsharp/typeProviders/negTests/EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.bsl +++ b/tests/fsharp/typeProviders/negTests/EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.bsl @@ -5,4 +5,4 @@ EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.fsx(6,39,6,14 EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.fsx(8,41,8,58): typecheck error FS0039: The type 'TheGeneratedTypeJ' is not defined. -EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.fsx(8,79,8,96): typecheck error FS0039: The type 'Object' does not define the field, constructor or member 'TheGeneratedTypeJ'. +EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.fsx(8,79,8,96): typecheck error FS0039: The type 'Object' does not have a field, property, or member named 'TheGeneratedTypeJ'. diff --git a/tests/fsharp/typecheck/sigs/neg04.bsl b/tests/fsharp/typecheck/sigs/neg04.bsl index 3bf91043774..194422d7b1b 100644 --- a/tests/fsharp/typecheck/sigs/neg04.bsl +++ b/tests/fsharp/typecheck/sigs/neg04.bsl @@ -11,7 +11,7 @@ neg04.fs(22,8,22,17): typecheck error FS0912: This declaration element is not pe neg04.fs(26,8,26,17): typecheck error FS0912: This declaration element is not permitted in an augmentation -neg04.fs(32,8,32,11): typecheck error FS0039: The type 'Double' does not define the field, constructor or member 'Nan'. Maybe you want one of the following: +neg04.fs(32,8,32,11): typecheck error FS0039: The type 'Double' does not have a field, property, or member named 'Nan'. Maybe you want one of the following: IsNaN neg04.fs(46,69,46,94): typecheck error FS0001: Type mismatch. Expecting a tuple of length 4 of type @@ -64,7 +64,7 @@ but here has type neg04.fs(83,39,83,46): typecheck error FS0752: The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints -neg04.fs(85,47,85,52): typecheck error FS0039: The type 'Int32' does not define the field, constructor or member 'Item'. +neg04.fs(85,47,85,52): typecheck error FS0039: The type 'Int32' does not have a field, property, or member named 'Item'. neg04.fs(87,73,87,78): typecheck error FS0752: The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints diff --git a/tests/fsharp/typecheck/sigs/neg06.bsl b/tests/fsharp/typecheck/sigs/neg06.bsl index 4e28da2b6d7..b0fa7d1450b 100644 --- a/tests/fsharp/typecheck/sigs/neg06.bsl +++ b/tests/fsharp/typecheck/sigs/neg06.bsl @@ -1,5 +1,5 @@ -neg06.fs(3,40,3,45): typecheck error FS0039: The type 'Encoding' does not define the field, constructor or member 'Ascii'. Maybe you want one of the following: +neg06.fs(3,40,3,45): typecheck error FS0039: The type 'Encoding' does not have a field, property, or member named 'Ascii'. Maybe you want one of the following: ASCII neg06.fs(12,6,12,31): typecheck error FS0942: Struct types are always sealed diff --git a/tests/fsharp/typecheck/sigs/neg08.bsl b/tests/fsharp/typecheck/sigs/neg08.bsl index d9215e7c744..d6731b8131e 100644 --- a/tests/fsharp/typecheck/sigs/neg08.bsl +++ b/tests/fsharp/typecheck/sigs/neg08.bsl @@ -19,6 +19,6 @@ neg08.fs(55,7,55,14): typecheck error FS0773: Cannot create an extension of a se neg08.fs(55,7,55,14): typecheck error FS0776: Object construction expressions may only be used to implement constructors in class types -neg08.fs(61,19,61,26): typecheck error FS0039: The type 'Type' does not define the field, constructor or member 'value__'. +neg08.fs(61,19,61,26): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'value__'. neg08.fs(79,5,79,44): typecheck error FS0502: The member or object constructor 'Random' takes 0 type argument(s) but is here given 1. The required signature is 'static member Variable.Random: y: Variable<'a> -> Variable<'a>'. diff --git a/tests/fsharp/typecheck/sigs/neg101.bsl b/tests/fsharp/typecheck/sigs/neg101.bsl index 44a8c10cdd6..f764e86da88 100644 --- a/tests/fsharp/typecheck/sigs/neg101.bsl +++ b/tests/fsharp/typecheck/sigs/neg101.bsl @@ -1,5 +1,5 @@ -neg101.fs(7,11,7,14): typecheck error FS0039: The type 'Int32' does not define the field, constructor or member 'Foo'. +neg101.fs(7,11,7,14): typecheck error FS0039: The type 'Int32' does not have a field, property, or member named 'Foo'. neg101.fs(14,6,14,17): typecheck error FS3220: This method or property is not normally used from F# code, use an explicit tuple pattern for deconstruction instead. diff --git a/tests/fsharp/typecheck/sigs/neg17.bsl b/tests/fsharp/typecheck/sigs/neg17.bsl index d322538b929..730875a22b5 100644 --- a/tests/fsharp/typecheck/sigs/neg17.bsl +++ b/tests/fsharp/typecheck/sigs/neg17.bsl @@ -5,14 +5,14 @@ neg17b.fs(7,17,7,31): typecheck error FS1094: The value 'privateValue' is not ac neg17b.fs(8,18,8,43): typecheck error FS1092: The type 'PrivateUnionType' is not accessible from this code location -neg17b.fs(11,26,11,41): typecheck error FS0039: The type 'Type' does not define the field, constructor or member 'PrivateProperty'. +neg17b.fs(11,26,11,41): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'PrivateProperty'. -neg17b.fs(12,24,12,45): typecheck error FS0039: The type 'Type' does not define the field, constructor or member 'PrivateStaticProperty'. Maybe you want one of the following: +neg17b.fs(12,24,12,45): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'PrivateStaticProperty'. Maybe you want one of the following: InternalStaticProperty -neg17b.fs(13,26,13,39): typecheck error FS0039: The type 'Type' does not define the field, constructor or member 'PrivateMethod'. +neg17b.fs(13,26,13,39): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'PrivateMethod'. -neg17b.fs(14,24,14,43): typecheck error FS0039: The type 'Type' does not define the field, constructor or member 'PrivateStaticMethod'. Maybe you want one of the following: +neg17b.fs(14,24,14,43): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'PrivateStaticMethod'. Maybe you want one of the following: InternalStaticMethod neg17b.fs(15,17,15,52): typecheck error FS1092: The type 'PrivateRecordType' is not accessible from this code location diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 9b965cdbbed..1997770dcd2 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -358,13 +358,13 @@ neg20.fs(373,22,373,41): typecheck error FS1124: Multiple types exist called 'Ov neg20.fs(382,19,382,40): typecheck error FS1124: Multiple types exist called 'OverloadedClassName', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'OverloadedClassName<_>'. -neg20.fs(383,39,383,41): typecheck error FS0039: The type 'OverloadedClassName<_>' does not define the field, constructor or member 'S2'. +neg20.fs(383,39,383,41): typecheck error FS0039: The type 'OverloadedClassName<_>' does not have a field, property, or member named 'S2'. neg20.fs(428,19,428,38): typecheck error FS1133: No constructors are available for the type 'OverloadedClassName<'a,'b>' neg20.fs(430,22,430,41): typecheck error FS1133: No constructors are available for the type 'OverloadedClassName<'a,'b>' -neg20.fs(444,39,444,41): typecheck error FS0039: The type 'OverloadedClassName' does not define the field, constructor or member 'S2'. +neg20.fs(444,39,444,41): typecheck error FS0039: The type 'OverloadedClassName' does not have a field, property, or member named 'S2'. neg20.fs(447,27,447,28): typecheck error FS0001: This expression was expected to have type 'int option' diff --git a/tests/fsharp/typecheck/sigs/neg45.bsl b/tests/fsharp/typecheck/sigs/neg45.bsl index 3ec59a417f6..081352c4167 100644 --- a/tests/fsharp/typecheck/sigs/neg45.bsl +++ b/tests/fsharp/typecheck/sigs/neg45.bsl @@ -13,7 +13,7 @@ neg45.fs(34,27,34,28): typecheck error FS0465: Type inference problem too compli neg45.fs(41,24,41,33): typecheck error FS0827: '(|Foo|Bir|)' is not a valid method name. Use a 'let' binding instead. -neg45.fs(52,14,52,17): typecheck error FS0039: The type 'FooBir' does not define the field, constructor or member 'Foo'. +neg45.fs(52,14,52,17): typecheck error FS0039: The type 'FooBir' does not have a field, property, or member named 'Foo'. neg45.fs(56,19,56,28): typecheck error FS0827: '(|Foo|Bir|)' is not a valid method name. Use a 'let' binding instead. diff --git a/tests/fsharp/typecheck/sigs/neg55.bsl b/tests/fsharp/typecheck/sigs/neg55.bsl index 76f4b6b8c81..4abff92f75b 100644 --- a/tests/fsharp/typecheck/sigs/neg55.bsl +++ b/tests/fsharp/typecheck/sigs/neg55.bsl @@ -1,6 +1,6 @@ neg55.fs(10,5,10,19): typecheck error FS0491: The member or object constructor '.cctor' is not accessible. Private members may only be accessed from within the declaring type. Protected members may only be accessed from an extending type and cannot be accessed from inner lambda expressions. -neg55.fs(19,7,19,16): typecheck error FS0039: The type 'D' does not define the field, constructor or member '.ctor'. +neg55.fs(19,7,19,16): typecheck error FS0039: The type 'D' does not have a field, property, or member named '.ctor'. neg55.fs(24,22,24,31): typecheck error FS3066: Invalid member name. Members may not have name '.ctor' or '.cctor' From 7ef169c6187301b4128d71334571881fec74fbeb Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 20 Feb 2026 21:22:52 +0100 Subject: [PATCH 03/39] Reword FS0597 'successive arguments' error message for clarity Replace the confusing 'Successive arguments should be separated by spaces or tupled' message with a clearer, actionable message that tells the user their argument expression needs parentheses and includes an example. Fixes dotnet/fsharp#6687 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/FSComp.txt | 2 +- src/Compiler/xlf/FSComp.txt.cs.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.de.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.es.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.fr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.it.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ja.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ko.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pl.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ru.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.tr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 4 ++-- tests/fsharp/typecheck/sigs/neg67.bsl | 2 +- tests/fsharp/typecheck/sigs/neg67.vsbsl | 2 +- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 310c3e57176..fa0152bb53f 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -454,7 +454,7 @@ parsConsiderUsingSeparateRecordType,"Consider using a separate record type inste 594,parsIdentifierExpected,"Identifier expected" 595,parsInOrEqualExpected,"'in' or '=' expected" 596,parsArrowUseIsLimited,"The use of '->' in sequence and computation expressions is limited to the form 'for pat in expr -> expr'. Use the syntax 'for ... in ... do ... yield...' to generate elements in more complex sequence expressions." -597,parsSuccessiveArgsShouldBeSpacedOrTupled,"Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized" +597,parsSuccessiveArgsShouldBeSpacedOrTupled,"This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%%s\" (arg.Trim())'." 598,parsUnmatchedBracket,"Unmatched '['" 599,parsMissingQualificationAfterDot,"Missing qualification after '.'" parsParenFormIsForML,"In F# code you may use 'expr.[expr]'. A type annotation may be required to indicate the first expression is an array" diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 6c4ddc77dd3..87cadcceaa5 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - Po sobě jdoucí argumenty by měly být oddělené mezerami nebo by měly být řazenou kolekcí členů a argumenty zahrnující použití funkcí nebo metod by měly být v závorkách. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 102967b9104..f60a0cbde46 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - Aufeinanderfolgende Argumente sollten durch Leerzeichen getrennt oder als Tupel angegeben werden, und Argumente mit Funktions- oder Methodenanwendungen sollten in Klammern gesetzt werden. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 90aa2b88790..1aa0d4a2f7a 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - Argumentos sucesivos deben separarse con espacios u organizarse en tuplas, y los argumentos que implican aplicaciones de función o método deben encerrarse entre paréntesis. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 9daee40beee..97846684fec 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - Les arguments successifs doivent être séparés par des espaces ou être basés sur des tuples. En outre, les arguments impliquant des applications de fonction ou de méthode doivent être mis entre parenthèses + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 42d7c4a9d82..7beaf0f66dc 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - Gli argomenti successivi devono essere separati da spazi o inclusi in tuple, mentre gli argomenti che prevedono applicazioni di metodi o funzioni devono essere racchiusi tra parentesi + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index f57c8953f3f..57df774c724 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - 複数の引数が連続する場合、スペースで区切るかタプル化します。関数またはメソッド アプリケーションに関する引数の場合、かっこで囲む必要があります。 + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 38e8abcd74b..f48c712f978 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - 연속된 인수는 공백으로 구분하거나 튜플해야 하며 함수 또는 메서드 적용과 관련된 인수는 괄호로 묶어야 합니다. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 9d195e673a0..c3a9c5cac8d 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - Kolejne argumenty powinny być oddzielone spacjami lub mieć postać krotek, a argumenty obejmujące aplikacje metody lub funkcji powinny być umieszczone w nawiasach okrągłych + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index a0834de610d..196717f727f 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - Argumentos sucessivos devem ser separados por espaços ou serem tuplas; argumentos envolvendo aplicações de função ou de método devem estar entre parênteses + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 340a6dc6d22..ab87c7054df 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - Последовательные аргументы следует разделять пробелами или включать в кортежи; аргументы, предполагающие применение функции или метода, следует заключать в круглые скобки + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index d21a944b388..0db09e721f3 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - Ardışık bağımsız değişkenler boşluklarla veya grup olarak tanımlayarak ayrılmalı ve işlev veya metot uygulamaları içeren bağımsız değişkenler ayraç içine alınmalıdır + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 247bf228d69..d5e196ee2d6 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - 应使用空格来分隔连续参数或将这些连续参数组成元组,并且应使用括号将涉及函数或方法应用的参数括起来 + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 14493e8e180..0ff4ff12899 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -3998,8 +3998,8 @@ - Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized - 後續引數應該用空格分隔或採用 Tuple 形式,而且涉及函式或方法應用程式的引數應該用括號括住 + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. diff --git a/tests/fsharp/typecheck/sigs/neg67.bsl b/tests/fsharp/typecheck/sigs/neg67.bsl index 8fee8cf3f5d..97eafa4f483 100644 --- a/tests/fsharp/typecheck/sigs/neg67.bsl +++ b/tests/fsharp/typecheck/sigs/neg67.bsl @@ -3,6 +3,6 @@ neg67.fsx(41,36,41,37): parse error FS0010: Incomplete structured construct at o neg67.fsx(41,15,41,16): parse error FS0604: Unmatched '{' -neg67.fsx(42,17,42,34): parse error FS0597: Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized +neg67.fsx(42,17,42,34): parse error FS0597: This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. neg67.fsx(42,35,42,36): parse error FS0010: Unexpected symbol '}' in definition. Expected incomplete structured construct at or before this point or other token. diff --git a/tests/fsharp/typecheck/sigs/neg67.vsbsl b/tests/fsharp/typecheck/sigs/neg67.vsbsl index 6f2922050be..e45f3865c12 100644 --- a/tests/fsharp/typecheck/sigs/neg67.vsbsl +++ b/tests/fsharp/typecheck/sigs/neg67.vsbsl @@ -3,7 +3,7 @@ neg67.fsx(41,36,41,37): parse error FS0010: Incomplete structured construct at o neg67.fsx(41,15,41,16): parse error FS0604: Unmatched '{' -neg67.fsx(42,17,42,34): parse error FS0597: Successive arguments should be separated by spaces or tupled, and arguments involving function or method applications should be parenthesized +neg67.fsx(42,17,42,34): parse error FS0597: This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. neg67.fsx(42,35,42,36): parse error FS0010: Unexpected symbol '}' in definition. Expected incomplete structured construct at or before this point or other token. From a1f43a496c4bd07444fe6b72ba7b9d6f6d697e58 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 20 Feb 2026 21:48:22 +0100 Subject: [PATCH 04/39] FS0670: Suggest 'inline' for type variable escape scope errors Append suggestion text to error FS0670 (tcNotSufficientlyGenericBecauseOfScope): 'Consider adding '\''inline'\'' to the member or function definition.' Fixes #3302 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/FSComp.txt | 2 +- src/Compiler/xlf/FSComp.txt.cs.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.de.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.es.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.fr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.it.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ja.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ko.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pl.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ru.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.tr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 4 ++-- .../Conformance/LexicalAnalysis/SymbolicOperators.fs | 2 +- tests/fsharp/typecheck/sigs/neg08.bsl | 2 +- tests/fsharp/typecheck/sigs/neg37.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg62.bsl | 2 +- tests/fsharp/typecheck/sigs/neg92.bsl | 2 +- 19 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index fa0152bb53f..3c0199eedab 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -524,7 +524,7 @@ tcExpectModuleOrNamespaceParent,"Expected module or namespace parent %s" 667,tcFieldsDoNotDetermineUniqueRecordType,"The field labels and expected type of this record expression or pattern do not uniquely determine a corresponding record type" 668,tcMultipleFieldsInRecord,"The field '%s' appears multiple times in this record expression or pattern" 669,tcUnknownUnion,"Unknown union case" -670,tcNotSufficientlyGenericBecauseOfScope,"This code is not sufficiently generic. The type variable %s could not be generalized because it would escape its scope." +670,tcNotSufficientlyGenericBecauseOfScope,"This code is not sufficiently generic. The type variable %s could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition." 671,tcPropertyRequiresExplicitTypeParameters,"A property cannot have explicit type parameters. Consider using a method instead." 672,tcConstructorCannotHaveTypeParameters,"A constructor cannot have explicit type parameters. Consider using a static construction method instead." 673,tcInstanceMemberRequiresTarget,"This instance member needs a parameter to represent the object being invoked. Make the member static or use the notation 'member x.Member(args) = ...'." diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 87cadcceaa5..63ebaea84cb 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - Tento kód není dostatečně obecný. Proměnná typu {0} se nedá zobecnit, protože by se tak dostala mimo svůj definiční obor. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + Tento kód není dostatečně obecný. Proměnná typu {0} se nedá zobecnit, protože by se tak dostala mimo svůj definiční obor. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index f60a0cbde46..5857e284135 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - Dieser Code ist nicht generisch genug. Die Typvariable "{0}" konnte nicht generalisiert werden, weil sie sonst aus dem Bereich fallen würde. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + Dieser Code ist nicht generisch genug. Die Typvariable "{0}" konnte nicht generalisiert werden, weil sie sonst aus dem Bereich fallen würde. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 1aa0d4a2f7a..eccdbd2ee6a 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - Este código no es lo suficientemente genérico. La variable de tipo {0} no se pudo generalizar porque escaparía de su ámbito. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + Este código no es lo suficientemente genérico. La variable de tipo {0} no se pudo generalizar porque escaparía de su ámbito. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 97846684fec..3237039d25f 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - Ce code n'est pas suffisamment générique. Impossible de généraliser la variable de type {0}, car elle sort de sa portée. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + Ce code n'est pas suffisamment générique. Impossible de généraliser la variable de type {0}, car elle sort de sa portée. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 7beaf0f66dc..2f17cd3934a 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - Questo codice non è sufficientemente generico. Non è stato possibile generalizzare la variabile di tipo {0} perché non sarebbe compresa nel relativo ambito. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + Questo codice non è sufficientemente generico. Non è stato possibile generalizzare la variabile di tipo {0} perché non sarebbe compresa nel relativo ambito. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 57df774c724..25ef4a7202d 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - このコードの総称性が十分ではありません。スコープが回避されるため、型変数 {0} をジェネリック化することはできません。 + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + このコードの総称性が十分ではありません。スコープが回避されるため、型変数 {0} をジェネリック化することはできません。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index f48c712f978..3078435c512 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - 이 코드는 충분히 일반적이지 않습니다. 형식 변수 {0}을(를) 일반화하면 범위를 벗어나게 되므로 일반화할 수 없습니다. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + 이 코드는 충분히 일반적이지 않습니다. 형식 변수 {0}을(를) 일반화하면 범위를 벗어나게 되므로 일반화할 수 없습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index c3a9c5cac8d..1815f946c64 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - Ten kod nie jest wystarczająco ogólny. Nie można uogólnić zmiennej typu {0}, ponieważ wykroczy ona poza swój zakres. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + Ten kod nie jest wystarczająco ogólny. Nie można uogólnić zmiennej typu {0}, ponieważ wykroczy ona poza swój zakres. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 196717f727f..7b0a5e1a81f 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - Este código não é suficientemente genérico. A variável de tipo {0} não pode ser gerada porque ela escaparia de seu escopo. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + Este código não é suficientemente genérico. A variável de tipo {0} não pode ser gerada porque ela escaparia de seu escopo. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index ab87c7054df..afba154805f 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - Этот код является недостаточно базовым Переменная типа {0} не может быть обобщена, так как тогда она выйдет за пределы области. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + Этот код является недостаточно базовым Переменная типа {0} не может быть обобщена, так как тогда она выйдет за пределы области. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 0db09e721f3..ebc60ef194e 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - Bu kod yeterince genel değil. Tür değişkeni {0}, kapsamını kaçıracağı için genelleştirilemedi. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + Bu kod yeterince genel değil. Tür değişkeni {0}, kapsamını kaçıracağı için genelleştirilemedi. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index d5e196ee2d6..f8e485fb25c 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - 此代码的通用程度不够。未能对类型变量 {0} 进行一般化,因为它会超出其范围。 + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + 此代码的通用程度不够。未能对类型变量 {0} 进行一般化,因为它会超出其范围。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 0ff4ff12899..797b6f44d35 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -4328,8 +4328,8 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. - 這個程式碼的一般程度不足。無法一般化類型變數 {0},因為它會逸出其範圍。 + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + 這個程式碼的一般程度不足。無法一般化類型變數 {0},因為它會逸出其範圍。 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs index b0d76a9bcd4..eb317b44eec 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs @@ -66,7 +66,7 @@ let a6 = TestType.(+++)((fun (x : string) -> 18), tt0)""" |> compile |> shouldFail |> withErrorCode 0670 - |> withDiagnosticMessageMatches " 'a\) could not be generalized because it would escape its scope" + |> withDiagnosticMessageMatches " 'a\) could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition." |> ignore // This test was automatically generated (moved from FSharpQA suite - Conformance/LexicalAnalysis/SymbolicOperators) diff --git a/tests/fsharp/typecheck/sigs/neg08.bsl b/tests/fsharp/typecheck/sigs/neg08.bsl index d6731b8131e..ebba5c4149a 100644 --- a/tests/fsharp/typecheck/sigs/neg08.bsl +++ b/tests/fsharp/typecheck/sigs/neg08.bsl @@ -3,7 +3,7 @@ neg08.fs(7,24,7,55): typecheck error FS0033: The type 'System.Collections.Generi neg08.fs(9,24,9,67): typecheck error FS0033: The type 'System.Collections.Generic.List<_>' expects 1 type argument(s) but is given 2 -neg08.fs(16,8,16,10): typecheck error FS0670: This code is not sufficiently generic. The type variable 'b could not be generalized because it would escape its scope. +neg08.fs(16,8,16,10): typecheck error FS0670: This code is not sufficiently generic. The type variable 'b could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. neg08.fs(21,1,21,28): typecheck error FS0919: Exception abbreviations must refer to existing exceptions or F# types deriving from System.Exception diff --git a/tests/fsharp/typecheck/sigs/neg37.bsl b/tests/fsharp/typecheck/sigs/neg37.bsl index 88bd2f32dba..e3bbe3464a6 100644 --- a/tests/fsharp/typecheck/sigs/neg37.bsl +++ b/tests/fsharp/typecheck/sigs/neg37.bsl @@ -1,9 +1,9 @@ -neg37.fs(7,19,7,22): typecheck error FS0670: This code is not sufficiently generic. The type variable 'T could not be generalized because it would escape its scope. +neg37.fs(7,19,7,22): typecheck error FS0670: This code is not sufficiently generic. The type variable 'T could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. neg37.fs(19,33,19,40): typecheck error FS1125: The instantiation of the generic type 'CCC' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, e.g. 'CCC<_>'. -neg37.fs(19,19,19,22): typecheck error FS0670: This code is not sufficiently generic. The type variable 'T could not be generalized because it would escape its scope. +neg37.fs(19,19,19,22): typecheck error FS0670: This code is not sufficiently generic. The type variable 'T could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. neg37.fs(24,10,24,11): typecheck error FS0071: Type constraint mismatch when applying the default type 'IEvent<'T>' for a type inference variable. The type 'IEvent<'T>' is not compatible with the type 'System.IComparable<'T>' Consider adding further type constraints diff --git a/tests/fsharp/typecheck/sigs/neg62.bsl b/tests/fsharp/typecheck/sigs/neg62.bsl index 0632741def0..d000ea280e1 100644 --- a/tests/fsharp/typecheck/sigs/neg62.bsl +++ b/tests/fsharp/typecheck/sigs/neg62.bsl @@ -19,7 +19,7 @@ neg62.fs(50,5,50,34): typecheck error FS0901: Structs cannot contain value defin neg62.fs(54,31,54,34): typecheck error FS3135: To indicate that this property can be set, use 'member val PropertyName = expr with get,set'. -neg62.fs(69,24,69,30): typecheck error FS0670: This code is not sufficiently generic. The type variable 'S could not be generalized because it would escape its scope. +neg62.fs(69,24,69,30): typecheck error FS0670: This code is not sufficiently generic. The type variable 'S could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. neg62.fs(75,5,75,28): typecheck error FS3151: This member, function or value declaration may not be declared 'inline' diff --git a/tests/fsharp/typecheck/sigs/neg92.bsl b/tests/fsharp/typecheck/sigs/neg92.bsl index 997be061e03..b28b78b9815 100644 --- a/tests/fsharp/typecheck/sigs/neg92.bsl +++ b/tests/fsharp/typecheck/sigs/neg92.bsl @@ -1,4 +1,4 @@ neg92.fs(10,19,10,20): typecheck error FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'T has been constrained to be type ''U'. -neg92.fs(9,9,9,17): typecheck error FS0670: This code is not sufficiently generic. The type variable 'U could not be generalized because it would escape its scope. +neg92.fs(9,9,9,17): typecheck error FS0670: This code is not sufficiently generic. The type variable 'U could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. From 572fa4f6a9301f4f825ec06c52f9069b5f01f702 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 20 Feb 2026 22:13:50 +0100 Subject: [PATCH 05/39] Append 'operator not in scope' hint to csExpectTypeWithOperatorButGivenFunction When SRTP resolution fails with a function type, the error now suggests the operator may not be in scope and advises checking module/namespace opens. Fixes dotnet/fsharp#2828 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/FSComp.txt | 2 +- src/Compiler/xlf/FSComp.txt.cs.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.de.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.es.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.fr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.it.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ja.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ko.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pl.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ru.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.tr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 4 ++-- 14 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 3c0199eedab..32bc5235843 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -310,7 +310,7 @@ csTypeCannotBeResolvedAtCompileTime,"The declared type parameter '%s' cannot be 465,csTypeInferenceMaxDepth,"Type inference problem too complicated (maximum iteration depth reached). Consider adding further type annotations." csExpectedArguments,"Expected arguments to an instance member" csIndexArgumentMismatch,"This indexer expects %d arguments but is here given %d" -csExpectTypeWithOperatorButGivenFunction,"Expecting a type supporting the operator '%s' but given a function type. You may be missing an argument to a function." +csExpectTypeWithOperatorButGivenFunction,"Expecting a type supporting the operator '%s' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace." 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'" diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 63ebaea84cb..16227939a2a 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - Očekává se typ podporující operátor {0}, ale předává se typ funkce. Možná, že u funkce chybí argument. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Očekává se typ podporující operátor {0}, ale předává se typ funkce. Možná, že u funkce chybí argument. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 5857e284135..c7446b1869a 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - Ein unterstützender Typ für den Operator "{0}" wurde erwartet, aber ein Funktionstyp wurde empfangen. Möglicherweise fehlt ein Argument für eine Funktion. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Ein unterstützender Typ für den Operator "{0}" wurde erwartet, aber ein Funktionstyp wurde empfangen. Möglicherweise fehlt ein Argument für eine Funktion. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index eccdbd2ee6a..fd238192378 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - Se espera un tipo que admita el operador '{0}', pero se ha proporcionado un tipo de función. Quizá falta un argumento en una función. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Se espera un tipo que admita el operador '{0}', pero se ha proporcionado un tipo de función. Quizá falta un argumento en una función. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 3237039d25f..c658f1f7cdf 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - Un type prenant en charge l'opérateur '{0}' est attendu mais un type de fonction a été reçu. Il manque peut-être un argument à une fonction. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Un type prenant en charge l'opérateur '{0}' est attendu mais un type de fonction a été reçu. Il manque peut-être un argument à une fonction. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 2f17cd3934a..0dd8ed43039 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - È previsto un tipo che supporti l'operatore '{0}', tuttavia è specificato un tipo di funzione. Probabilmente manca un argomento in una funzione. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + È previsto un tipo che supporti l'operatore '{0}', tuttavia è specificato un tipo di funzione. Probabilmente manca un argomento in una funzione. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 25ef4a7202d..846531f630b 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - 演算子 '{0}' をサポートし、特定の関数型である型が必要です。関数に対する引数が足りない可能性があります。 + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + 演算子 '{0}' をサポートし、特定の関数型である型が必要です。関数に対する引数が足りない可能性があります。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 3078435c512..3987a5f0ab2 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - '{0}' 연산자를 지원하는 형식이 필요하지만 함수 형식이 지정되었습니다. 함수에 대한 인수가 없을 수 있습니다. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + '{0}' 연산자를 지원하는 형식이 필요하지만 함수 형식이 지정되었습니다. 함수에 대한 인수가 없을 수 있습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 1815f946c64..d60e25c392b 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - Oczekiwany jest typ obsługujący operator „{0}”, ale podano typ funkcji. Być może brakuje argumentu funkcji. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Oczekiwany jest typ obsługujący operator „{0}”, ale podano typ funkcji. Być może brakuje argumentu funkcji. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 7b0a5e1a81f..15945fcddfe 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - Um tipo que suporte o operador '{0}' era esperado, mas um tipo de função foi recebido. Pode estar faltando um argumento para alguma função. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Um tipo que suporte o operador '{0}' era esperado, mas um tipo de função foi recebido. Pode estar faltando um argumento para alguma função. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index afba154805f..1114ffde580 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - Требуется тип, поддерживающий оператор "{0}", однако задан тип функции. Возможно, отсутствует аргумент функции. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Требуется тип, поддерживающий оператор "{0}", однако задан тип функции. Возможно, отсутствует аргумент функции. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index ebc60ef194e..438d99412f5 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - '{0}' işlecini destekleyen bir tür bekleniyor ancak bir işlev türü verildi. Bir işlevde bağımsız değişkeniniz eksik olabilir. + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + '{0}' işlecini destekleyen bir tür bekleniyor ancak bir işlev türü verildi. Bir işlevde bağımsız değişkeniniz eksik olabilir. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index f8e485fb25c..71b3783cd31 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - 应为支持运算符“{0}”的类型,但给定的是函数类型。可能缺少函数的参数。 + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + 应为支持运算符“{0}”的类型,但给定的是函数类型。可能缺少函数的参数。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 797b6f44d35..8c105131f06 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -3343,8 +3343,8 @@ - Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function. - 必須是支援運算子 '{0}' 的類型,但提供的卻是函式類型。您可能遺漏函式的引數。 + Expecting a type supporting the operator '{0}' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + 必須是支援運算子 '{0}' 的類型,但提供的卻是函式類型。您可能遺漏函式的引數。 From 0af93203f65dd330ad71b1eba6e328db92982994 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 20 Feb 2026 22:30:45 +0100 Subject: [PATCH 06/39] FS0247: Improve namespace/module collision error message Change the error message from: 'A namespace and a module named X both occur in two parts of this assembly' to: 'The name X is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict.' Updated FSComp.txt, all 13 xlf localization files, and test baselines. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/FSComp.txt | 2 +- src/Compiler/xlf/FSComp.txt.cs.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.de.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.es.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.fr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.it.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ja.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ko.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pl.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ru.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.tr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 4 ++-- .../NamespacesFragmentsAndImplementationFiles.fs | 2 +- .../basic/E_NamespaceModuleCollision01.fs | 2 +- 16 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 32bc5235843..77be59d3cca 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -80,7 +80,7 @@ pickleErrorReadingWritingMetadata,"Error reading/writing metadata for the F# com 245,tastTypeOrModuleNotConcrete,"The type/module '%s' is not a concrete module or type" tastTypeHasAssemblyCodeRepresentation,"The type '%s' has an inline assembly code representation" 246,optsUnrecognizedLanguageVersion,"Unrecognized value '%s' for --langversion use --langversion:? for complete list" -247,tastNamespaceAndModuleWithSameNameInAssembly,"A namespace and a module named '%s' both occur in two parts of this assembly" +247,tastNamespaceAndModuleWithSameNameInAssembly,"The name '%s' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict." 248,tastTwoModulesWithSameNameInAssembly,"Two modules named '%s' occur in two parts of this assembly" 249,tastDuplicateTypeDefinitionInAssembly,"Two type definitions named '%s' occur in namespace '%s' in two parts of this assembly" 250,tastConflictingModuleAndTypeDefinitionInAssembly,"A module and a type definition named '%s' occur in namespace '%s' in two parts of this assembly" diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 16227939a2a..bd48b3966fa 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - Obor názvů a modul s názvem {0} se oba vyskytují ve dvou částech tohoto sestavení. + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + Obor názvů a modul s názvem {0} se oba vyskytují ve dvou částech tohoto sestavení. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index c7446b1869a..ba3e03e310b 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - Ein Namespace und ein Modul namens "{0}" sind beide in zwei Teilen dieser Assembly vorhanden. + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + Ein Namespace und ein Modul namens "{0}" sind beide in zwei Teilen dieser Assembly vorhanden. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index fd238192378..ea738234473 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - Hay un espacio de nombres y un módulo con el nombre '{0}' en dos partes de este ensamblado. + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + Hay un espacio de nombres y un módulo con el nombre '{0}' en dos partes de este ensamblado. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index c658f1f7cdf..400a8b131be 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - Un espace de noms et un module nommés tous les deux '{0}' sont présents dans deux parties de cet assembly + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + Un espace de noms et un module nommés tous les deux '{0}' sont présents dans deux parties de cet assembly diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 0dd8ed43039..6347725a6f8 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - In due parti di questo assembly sono presenti uno spazio dei nomi e un modulo entrambi denominati '{0}' + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + In due parti di questo assembly sono presenti uno spazio dei nomi e un modulo entrambi denominati '{0}' diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 846531f630b..7622410e0eb 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - '{0}' という名前空間とモジュールの両方がこのアセンブリの 2 か所で発生しています + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + '{0}' という名前空間とモジュールの両方がこのアセンブリの 2 か所で発生しています diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 3987a5f0ab2..5b1eb716ced 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - 이 어셈블리의 두 부분에서 '{0}'(이)라는 네임스페이스와 모듈이 모두 발생합니다. + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + 이 어셈블리의 두 부분에서 '{0}'(이)라는 네임스페이스와 모듈이 모두 발생합니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index d60e25c392b..a282192ded9 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - Przestrzeń nazw i moduł o nazwie „{0}” występują w dwóch częściach tego zestawu + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + Przestrzeń nazw i moduł o nazwie „{0}” występują w dwóch częściach tego zestawu diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 15945fcddfe..25f07a4de41 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - Um namespace e um módulo chamado '{0}' ocorrem em duas partes deste assembly + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + Um namespace e um módulo chamado '{0}' ocorrem em duas partes deste assembly diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 1114ffde580..17ef31c19d8 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - Пространство имен и модуль с именем "{0}" одновременно встречаются в двух частях этой сборки + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + Пространство имен и модуль с именем "{0}" одновременно встречаются в двух частях этой сборки diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 438d99412f5..94b4506cb9d 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - Bir ad alanı ve '{0}' adlı modülün ikisi birden bu bütünleştirilmiş kodun iki yerinde geçiyor + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + Bir ad alanı ve '{0}' adlı modülün ikisi birden bu bütünleştirilmiş kodun iki yerinde geçiyor diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 71b3783cd31..7c29aea214d 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - 名称均为“{0}”的一个命名空间和一个模块同时出现在此程序集的两个部分中 + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + 名称均为“{0}”的一个命名空间和一个模块同时出现在此程序集的两个部分中 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 8c105131f06..23a589e29ab 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -2238,8 +2238,8 @@ - A namespace and a module named '{0}' both occur in two parts of this assembly - 名稱為 '{0}' 的命名空間和模組都出現在這個組件的兩個部分中 + The name '{0}' is used as both a namespace and a module in this assembly. Rename one of them to avoid the conflict. + 名稱為 '{0}' 的命名空間和模組都出現在這個組件的兩個部分中 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/ImplementationFilesAndSignatureFiles/NamespacesFragmentsAndImplementationFiles.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/ImplementationFilesAndSignatureFiles/NamespacesFragmentsAndImplementationFiles.fs index 5fd8d547a10..c1030e030d1 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/ImplementationFilesAndSignatureFiles/NamespacesFragmentsAndImplementationFiles.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/ImplementationFilesAndSignatureFiles/NamespacesFragmentsAndImplementationFiles.fs @@ -136,7 +136,7 @@ module NamespacesBasic = |> compile |> shouldFail |> withErrorCode 0247 - |> withDiagnosticMessageMatches "A namespace and a module named" + |> withDiagnosticMessageMatches "The name 'A\.B' is used as both a namespace and a module in this assembly" |> ignore // SOURCE="LastFileExeCanBeAnona.fs LastFileExeCanBeAnonb.fs" diff --git a/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/ImplementationFilesAndSignatureFiles/NamespacesFragmentsAndImplementationFiles/basic/E_NamespaceModuleCollision01.fs b/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/ImplementationFilesAndSignatureFiles/NamespacesFragmentsAndImplementationFiles/basic/E_NamespaceModuleCollision01.fs index ba8984f01c8..40a7a256114 100644 --- a/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/ImplementationFilesAndSignatureFiles/NamespacesFragmentsAndImplementationFiles/basic/E_NamespaceModuleCollision01.fs +++ b/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/ImplementationFilesAndSignatureFiles/NamespacesFragmentsAndImplementationFiles/basic/E_NamespaceModuleCollision01.fs @@ -1,5 +1,5 @@ // #Regression #Conformance #SignatureFiles #Namespaces -//A namespace and a module named 'A\.B' both occur in two parts of this assembly +//The name 'A\.B' is used as both a namespace and a module in this assembly\. Rename one of them to avoid the conflict\. namespace A From b3f29032813dfc496ce58aac7050d0f0ba4be529 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sat, 21 Feb 2026 00:20:32 +0100 Subject: [PATCH 07/39] FS0003: Show concrete type in 'not a function' error message Pass exprTy (the expression's actual type) instead of overallTy.Commit (the expected result type) to the NotAFunction exception. This ensures the error message shows the concrete type of the value being applied, not an unsolved type variable. Use isTyparTy instead of string heuristic for type variable detection. Add targeted tests for int, string, bool, record, and tuple types. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 6 +-- src/Compiler/Driver/CompilerDiagnostics.fs | 6 ++- src/Compiler/FSComp.txt | 1 + src/Compiler/xlf/FSComp.txt.cs.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.de.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.es.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.fr.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.it.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.ja.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.ko.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.pl.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.ru.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.tr.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 9 +++- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 9 +++- .../NamedArguments/NamedArguments.fs | 2 +- .../PrecedenceAndOperators.fs | 4 +- .../ComputationExpressions.fs | 6 +-- .../ErrorMessages/TypeMismatchTests.fs | 41 +++++++++++++++++++ .../Shadowing/E_NoChangeForEvent.fsx.err.bsl | 4 +- tests/fsharp/typecheck/sigs/neg104.vsbsl | 2 +- tests/fsharp/typecheck/sigs/neg111.bsl | 2 +- tests/fsharp/typecheck/sigs/neg118.bsl | 12 +++--- tests/fsharp/typecheck/sigs/neg123.bsl | 2 +- tests/fsharp/typecheck/sigs/neg135.vsbsl | 4 +- tests/fsharp/typecheck/sigs/neg66.vsbsl | 2 +- tests/fsharp/typecheck/sigs/neg67.vsbsl | 2 +- 28 files changed, 161 insertions(+), 52 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index cd305725396..2921de02b33 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -8410,13 +8410,13 @@ and Propagate (cenv: cenv) (overallTy: OverallTy) (env: TcEnv) tpenv (expr: Appl let old = not (g.langVersion.SupportsFeature LanguageFeature.IndexerNotationWithoutDot) error (NotAFunctionButIndexer(denv, overallTy.Commit, vName, mExpr, mArg, old)) else - error (NotAFunction(denv, overallTy.Commit, mExpr, mArg)) + error (NotAFunction(denv, exprTy, mExpr, mArg)) // f x (where 'f' is not a function) | _ -> // 'delayed' is about to be dropped on the floor, first do rudimentary checking to get name resolutions in its body RecordNameAndTypeResolutionsDelayed cenv env tpenv delayed - error (NotAFunction(denv, overallTy.Commit, mExpr, mArg)) + error (NotAFunction(denv, exprTy, mExpr, mArg)) propagate false delayed expr.Range exprTy @@ -8735,7 +8735,7 @@ and TcApplicationThen (cenv: cenv) (overallTy: OverallTy) env tpenv mExprAndArg TcDelayed cenv overallTy env tpenv mExprAndArg (MakeApplicableExprNoFlex cenv bodyOfCompExpr) (tyOfExpr g bodyOfCompExpr) ExprAtomicFlag.NonAtomic delayed | _ -> - error (NotAFunction(denv, overallTy.Commit, mLeftExpr, mArg)) + error (NotAFunction(denv, exprTy, mLeftExpr, mArg)) //------------------------------------------------------------------------- // TcLongIdentThen: Typecheck "A.B.C.E.F ... " constructs diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index 1da09301ff5..6959a6c7df0 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -1009,11 +1009,13 @@ type Exception with | Some name -> os.AppendString(FSComp.SR.notAFunctionButMaybeIndexerWithName2 name) | _ -> os.AppendString(FSComp.SR.notAFunctionButMaybeIndexer2 ()) - | NotAFunction(_, _, _, marg) -> + | NotAFunction(denv, ty, _, marg) -> if marg.StartColumn = 0 then os.AppendString(FSComp.SR.notAFunctionButMaybeDeclaration ()) - else + elif isTyparTy denv.g ty then os.AppendString(FSComp.SR.notAFunction ()) + else + os.AppendString(FSComp.SR.notAFunctionWithType (NicePrint.prettyStringOfTy denv ty)) | TyconBadArgs(_, tcref, d, _) -> let exp = tcref.TyparsNoRange.Length diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 77be59d3cca..efc9e333928 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1482,6 +1482,7 @@ keywordDescriptionUntypedQuotation,"Delimits a untyped code quotation." 3216,itemNotFoundInTypeDuringDynamicCodeGen,"%s '%s' not found in type '%s' from assembly '%s'. A possible cause may be a version incompatibility. You may need to explicitly reference the correct version of this assembly to allow all referenced components to use the correct version." descriptionWordIs,"is" notAFunction,"This value is not a function and cannot be applied." +notAFunctionWithType,"This value is not a function and cannot be applied. It has type '%s', which does not accept arguments." notAFunctionButMaybeIndexerWithName,"This value is not a function and cannot be applied. Did you intend to access the indexer via '%s.[index]'?" notAFunctionButMaybeIndexer,"This expression is not a function and cannot be applied. Did you intend to access the indexer via 'expr.[index]'?" notAFunctionButMaybeIndexerWithName2,"This value is not a function and cannot be applied. Did you intend to access the indexer via '%s[index]'?" diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index bd48b3966fa..cd6f0b5f582 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ Tato hodnota není funkcí a nedá se použít. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? Tato hodnota není funkcí a nedá se použít. Nechtěli jste získat k indexeru přístup přes {0}.[index]? diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index ba3e03e310b..52395a3ddc8 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ Dieser Wert ist keine Funktion und kann nicht angewendet werden. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? Dieser Wert ist keine Funktion und kann nicht angewendet werden. Wollten Sie auf den Indexer über "{0}.[index]" zugreifen? diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index ea738234473..671901f391b 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ Este valor no es una función y no se puede aplicar. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? Este valor no es una función y no se puede aplicar. ¿Quería tener acceso al indexador a través de "{0}.[index]"? diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 400a8b131be..678c5453122 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ Cette valeur n'est pas une fonction et ne peut pas être appliquée. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? Cette valeur n'est pas une fonction et ne peut pas être appliquée. Souhaitiez-vous accéder à l'indexeur via « {0}.[index] » ? diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 6347725a6f8..25d499f950b 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ Questo valore non è una funzione e non può essere applicato. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? Questo valore non è una funzione e non può essere applicato. Si intendeva accedere all'indicizzatore tramite la sintassi '{0}.[index]'? diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 7622410e0eb..b55ad346ce0 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ この値は関数ではないため、適用できません。 + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? この値は関数ではないため、適用できません。{0}.[index] によってインデクサーにアクセスしようとしましたか? diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 5b1eb716ced..5479af2d7a4 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ 이 값은 함수가 아니며 적용할 수 없습니다. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? 이 값은 함수가 아니며 적용할 수 없습니다. '{0}.[index]'를 통해 인덱서에 액세스하려고 했습니까? diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index a282192ded9..0895d775d1f 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ Ta wartość nie jest funkcją i nie można jej zastosować. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? To wyrażenie nie jest funkcją i nie można go zastosować. Spróbuj uzyskać dostęp do indeksatora za pośrednictwem wyrażenia „{0}.[index]”? diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 25f07a4de41..11ac22d6959 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ Este valor não é uma função e não pode ser aplicado. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? Esse valor não é uma função e não pode ser aplicado. Você pretendia acessar o indexador por meio do '{0}.[index]'? diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 17ef31c19d8..f2dfdc3fb94 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ Это значение не является функцией, и применить его невозможно. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? Это значение не является функцией, и применить его невозможно. Вы хотели обратиться к индексатору с помощью "{0}.[index]"? diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 94b4506cb9d..86fb544b9c7 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ Bu değer, bir işlev değil ve uygulanamaz. + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? Bu değer, bir işlev değil ve uygulanamaz. Dizin oluşturucuya bunun yerine “{0}.[index]” üzerinden erişmeye mi çalışıyordunuz? diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 7c29aea214d..85e85187369 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ 此值不是一个函数,无法应用。 + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? 此值不是一个函数,无法应用。是否曾打算通过 '{0}.[index]' 访问索引器? diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 23a589e29ab..8414c5316b1 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -3998,8 +3998,8 @@ - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. - This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn "%s" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. + This argument expression needs parentheses. Expressions involving function or method calls must be parenthesized when passed as arguments, e.g. 'printfn \"%s\" (arg.Trim())'. @@ -8672,6 +8672,11 @@ 此值不是函式,無法套用。 + + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + This value is not a function and cannot be applied. It has type '{0}', which does not accept arguments. + + This value is not a function and cannot be applied. Did you intend to access the indexer via '{0}.[index]'? 此值並非函式,因而無法套用。您要用 '{0}.[index]' 存取索引子嗎? diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/NamedArguments/NamedArguments.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/NamedArguments/NamedArguments.fs index 21176ac005c..508a54b09f9 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/NamedArguments/NamedArguments.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/NamedArguments/NamedArguments.fs @@ -82,7 +82,7 @@ module MemberDefinitions_NamedArguments = |> withDiagnostics [ (Error 39, Line 8, Col 47, Line 8, Col 51, "The value or constructor 'arg1' is not defined.") (Error 39, Line 8, Col 54, Line 8, Col 58, "The value or constructor 'arg2' is not defined.") - (Error 3, Line 12, Col 1, Line 12, Col 8, "This value is not a function and cannot be applied.") + (Error 3, Line 12, Col 1, Line 12, Col 8, "This value is not a function and cannot be applied. It has type '(int * int)', which does not accept arguments.") ] // SOURCE=genericNamedParams.fs # genericNamedParams.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/PrecedenceAndOperators/PrecedenceAndOperators.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/PrecedenceAndOperators/PrecedenceAndOperators.fs index b6f0d7982ae..2e07f846a34 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/PrecedenceAndOperators/PrecedenceAndOperators.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/PrecedenceAndOperators/PrecedenceAndOperators.fs @@ -44,8 +44,8 @@ module PrecedenceAndOperators = |> compile |> shouldFail |> withDiagnostics [ - (Error 3, Line 14, Col 11, Line 14, Col 20, "This value is not a function and cannot be applied.") - (Error 3, Line 15, Col 12, Line 15, Col 21, "This value is not a function and cannot be applied.") + (Error 3, Line 14, Col 11, Line 14, Col 20, "This value is not a function and cannot be applied. It has type 'int list', which does not accept arguments.") + (Error 3, Line 15, Col 12, Line 15, Col 21, "This value is not a function and cannot be applied. It has type 'int list', which does not accept arguments.") ] // SOURCE=E_Negation01.fs SCFLAGS="--test:ErrorRanges -a" # E_Negation01.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs index 8e340726963..612973e8e27 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ComputationExpressions/ComputationExpressions.fs @@ -66,7 +66,7 @@ module EmptyBodied = |> compile |> shouldFail |> withErrorCode 3 - |> withErrorMessage "This value is not a function and cannot be applied." + |> withErrorMessage "This value is not a function and cannot be applied. It has type 'AsyncBuilder', which does not accept arguments." [] let ``task { } does not compile`` () = @@ -80,7 +80,7 @@ module EmptyBodied = |> compile |> shouldFail |> withErrorCode 3 - |> withErrorMessage "This value is not a function and cannot be applied." + |> withErrorMessage "This value is not a function and cannot be applied. It has type 'TaskBuilder', which does not accept arguments." [] let ``builder { } does not compile`` () = @@ -99,7 +99,7 @@ module EmptyBodied = |> compile |> shouldFail |> withErrorCode 3 - |> withErrorMessage "This value is not a function and cannot be applied." + |> withErrorMessage "This value is not a function and cannot be applied. It has type 'Builder', which does not accept arguments." [] let ``builder { () } and no Zero: FS0708`` () = diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs index d645f4d5a92..e96ba41087c 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs @@ -370,3 +370,44 @@ let main args = (Error 1, Line 8, Col 25, Line 8, Col 37, "The tuples have differing lengths of 3 and 2") ] + module ``Not a function`` = + + [] + [] + [] + [] + [] + let ``Value applied as function shows concrete type`` (valueDef: string) (varName: string) (expectedType: string) = + FSharp + $""" +{valueDef} +let y = {varName} 10 + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic + (Error 3, + Line 3, + Col 9, + Line 3, + Col 10, + $"This value is not a function and cannot be applied. It has type '{expectedType}', which does not accept arguments.") + + [] + let ``Record value applied as function shows type`` () = + FSharp + """ +type MyRecord = { Name: string } +let r = { Name = "hello" } +let y = r 10 + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic + (Error 3, + Line 4, + Col 9, + Line 4, + Col 10, + "This value is not a function and cannot be applied. It has type 'MyRecord', which does not accept arguments.") + diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_NoChangeForEvent.fsx.err.bsl b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_NoChangeForEvent.fsx.err.bsl index e022666431a..5a3d39e8aee 100644 --- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_NoChangeForEvent.fsx.err.bsl +++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_NoChangeForEvent.fsx.err.bsl @@ -1,3 +1,3 @@ E_NoChangeForEvent.fsx (9,9)-(9,30) typecheck warning It is recommended that objects supporting the IDisposable interface are created using the syntax 'new Type(args)', rather than 'Type(args)' or 'Type' as a function value representing the constructor, to indicate that resources may be owned by the generated value -E_NoChangeForEvent.fsx (10,1)-(10,11) typecheck error This value is not a function and cannot be applied. -E_NoChangeForEvent.fsx (18,1)-(18,11) typecheck error This value is not a function and cannot be applied. \ No newline at end of file +E_NoChangeForEvent.fsx (10,1)-(10,11) typecheck error This value is not a function and cannot be applied. It has type 'IEvent', which does not accept arguments. +E_NoChangeForEvent.fsx (18,1)-(18,11) typecheck error This value is not a function and cannot be applied. It has type 'IEvent', which does not accept arguments. \ No newline at end of file diff --git a/tests/fsharp/typecheck/sigs/neg104.vsbsl b/tests/fsharp/typecheck/sigs/neg104.vsbsl index ab4a928249b..4b0ba6d74a8 100644 --- a/tests/fsharp/typecheck/sigs/neg104.vsbsl +++ b/tests/fsharp/typecheck/sigs/neg104.vsbsl @@ -23,7 +23,7 @@ neg104.fs(8,9,8,15): typecheck error FS0750: This construct may only be used wit neg104.fs(10,9,10,15): typecheck error FS0750: This construct may only be used within computation expressions -neg104.fs(13,21,13,26): typecheck error FS0003: This value is not a function and cannot be applied. +neg104.fs(13,21,13,26): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'AsyncBuilder', which does not accept arguments. neg104.fs(20,9,20,15): typecheck error FS0025: Incomplete pattern matches on this expression. diff --git a/tests/fsharp/typecheck/sigs/neg111.bsl b/tests/fsharp/typecheck/sigs/neg111.bsl index 9ad833b8054..c323655fd89 100644 --- a/tests/fsharp/typecheck/sigs/neg111.bsl +++ b/tests/fsharp/typecheck/sigs/neg111.bsl @@ -6,4 +6,4 @@ neg111.fs(3,624,3,629): typecheck error FS0039: The value or constructor 'fail2' failwith failwithf -neg111.fs(5,538,5,540): typecheck error FS0003: This value is not a function and cannot be applied. +neg111.fs(5,538,5,540): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'unit', which does not accept arguments. diff --git a/tests/fsharp/typecheck/sigs/neg118.bsl b/tests/fsharp/typecheck/sigs/neg118.bsl index 7b70803cc6c..b3552cb686b 100644 --- a/tests/fsharp/typecheck/sigs/neg118.bsl +++ b/tests/fsharp/typecheck/sigs/neg118.bsl @@ -1,12 +1,12 @@ -neg118.fs(18,21,18,37): typecheck error FS0003: This value is not a function and cannot be applied. +neg118.fs(18,21,18,37): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'int', which does not accept arguments. -neg118.fs(19,21,19,37): typecheck error FS0003: This value is not a function and cannot be applied. +neg118.fs(19,21,19,37): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'int', which does not accept arguments. -neg118.fs(20,21,20,39): typecheck error FS0003: This value is not a function and cannot be applied. +neg118.fs(20,21,20,39): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'decimal', which does not accept arguments. -neg118.fs(21,21,21,41): typecheck error FS0003: This value is not a function and cannot be applied. +neg118.fs(21,21,21,41): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'string', which does not accept arguments. -neg118.fs(22,21,22,39): typecheck error FS0003: This value is not a function and cannot be applied. +neg118.fs(22,21,22,39): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'float', which does not accept arguments. -neg118.fs(25,51,25,67): typecheck error FS0003: This value is not a function and cannot be applied. +neg118.fs(25,51,25,67): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'int', which does not accept arguments. diff --git a/tests/fsharp/typecheck/sigs/neg123.bsl b/tests/fsharp/typecheck/sigs/neg123.bsl index a944f087500..9d865364c12 100644 --- a/tests/fsharp/typecheck/sigs/neg123.bsl +++ b/tests/fsharp/typecheck/sigs/neg123.bsl @@ -1,2 +1,2 @@ -neg123.fs(19,18,19,27): typecheck error FS0003: This value is not a function and cannot be applied. +neg123.fs(19,18,19,27): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'unit', which does not accept arguments. diff --git a/tests/fsharp/typecheck/sigs/neg135.vsbsl b/tests/fsharp/typecheck/sigs/neg135.vsbsl index e3d34411d0c..03ec06fd560 100644 --- a/tests/fsharp/typecheck/sigs/neg135.vsbsl +++ b/tests/fsharp/typecheck/sigs/neg135.vsbsl @@ -3,6 +3,6 @@ neg135.fs(6,1,6,2): parse error FS0010: Unexpected symbol '}' in expression neg135.fs(4,5,4,11): parse error FS3122: Missing 'do' in 'while' expression. Expected 'while do '. -neg135.fs(4,12,4,17): typecheck error FS0003: This value is not a function and cannot be applied. +neg135.fs(4,12,4,17): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'AsyncBuilder', which does not accept arguments. -neg135.fs(4,12,4,17): typecheck error FS0003: This value is not a function and cannot be applied. +neg135.fs(4,12,4,17): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'AsyncBuilder', which does not accept arguments. diff --git a/tests/fsharp/typecheck/sigs/neg66.vsbsl b/tests/fsharp/typecheck/sigs/neg66.vsbsl index 0c27ea51528..e65fa3bd7da 100644 --- a/tests/fsharp/typecheck/sigs/neg66.vsbsl +++ b/tests/fsharp/typecheck/sigs/neg66.vsbsl @@ -1,4 +1,4 @@ neg66.fsx(43,4,43,5): parse error FS0010: Unexpected symbol ')' in definition. Expected incomplete structured construct at or before this point or other token. -neg66.fsx(30,1,38,33): typecheck error FS0003: This value is not a function and cannot be applied. +neg66.fsx(30,1,38,33): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'unit', which does not accept arguments. diff --git a/tests/fsharp/typecheck/sigs/neg67.vsbsl b/tests/fsharp/typecheck/sigs/neg67.vsbsl index e45f3865c12..f865a4b3d09 100644 --- a/tests/fsharp/typecheck/sigs/neg67.vsbsl +++ b/tests/fsharp/typecheck/sigs/neg67.vsbsl @@ -13,4 +13,4 @@ is not compatible with type 'unit' -neg67.fsx(30,1,41,37): typecheck error FS0003: This value is not a function and cannot be applied. +neg67.fsx(30,1,41,37): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'unit', which does not accept arguments. From b5c792c8912a8b6259f7d9366224ea60a6493b0e Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sat, 21 Feb 2026 01:46:20 +0100 Subject: [PATCH 08/39] FS3082: List available static parameters in error message When a type provider is used with a wrong static parameter name, the error now lists available parameter names (capped at 5) to help the user identify the correct name. Fixes dotnet/fsharp#11445 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Checking/Expressions/CheckExpressions.fs | 8 +++++++- src/Compiler/FSComp.txt | 2 +- src/Compiler/xlf/FSComp.txt.cs.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.de.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.es.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.fr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.it.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ja.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ko.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pl.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.ru.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.tr.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 4 ++-- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 4 ++-- tests/FSharp.Compiler.Service.Tests/EditorTests.fs | 2 +- 16 files changed, 35 insertions(+), 29 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 2921de02b33..9933129a2fd 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -4995,7 +4995,13 @@ and CrackStaticConstantArgs (cenv: cenv) env tpenv (staticParameters: Tainted Array.exists (fun sp -> n.idText = sp.PUntaint((fun sp -> sp.Name), n.idRange)) then error (Error(FSComp.SR.etStaticParameterAlreadyHasValue n.idText, n.idRange)) else - error (Error(FSComp.SR.etNoStaticParameterWithName n.idText, n.idRange)) + let availableNames = + staticParameters + |> Array.map (fun sp -> sp.PUntaint((fun sp -> sp.Name), n.idRange)) + |> Array.truncate 5 + |> String.concat ", " + + error (Error(FSComp.SR.etNoStaticParameterWithName (n.idText, availableNames), n.idRange)) | [_] -> () | _ -> error (Error(FSComp.SR.etMultipleStaticParameterWithName n.idText, n.idRange)) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index efc9e333928..dec06fef1f4 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1236,7 +1236,7 @@ invalidFullNameForProvidedType,"invalid full name for provided type" 3078,tcMissingCustomOperation,"A custom query operation for '%s' is required but not specified" 3080,etBadUnnamedStaticArgs,"Named static arguments must come after all unnamed static arguments" 3081,etStaticParameterRequiresAValue,"The static parameter '%s' of the provided type or method '%s' requires a value. Static parameters to type providers may be optionally specified using named arguments, e.g. '%s<%s=...>'." -3082,etNoStaticParameterWithName,"No static parameter exists with name '%s'" +3082,etNoStaticParameterWithName,"No static parameter exists with name '%s'. Available parameters: %s." 3083,etStaticParameterAlreadyHasValue,"The static parameter '%s' has already been given a value" 3084,etMultipleStaticParameterWithName,"Multiple static parameters exist with name '%s'" 3085,tcCustomOperationMayNotBeUsedInConjunctionWithNonSimpleLetBindings,"A custom operation may not be used in conjunction with a non-value or recursive 'let' binding in another part of this computation expression" diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index cd6f0b5f582..251245548bc 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - Neexistuje žádný statický parametr s názvem {0}. + No static parameter exists with name '{0}'. Available parameters: {1}. + Neexistuje žádný statický parametr s názvem {0}. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 52395a3ddc8..34347e241d3 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - Es sind keine statische Parameter mit dem Namen '{0}' vorhanden. + No static parameter exists with name '{0}'. Available parameters: {1}. + Es sind keine statische Parameter mit dem Namen '{0}' vorhanden. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 671901f391b..5ef879e9e15 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - No existe ningún parámetro estático con el nombre '{0}'. + No static parameter exists with name '{0}'. Available parameters: {1}. + No existe ningún parámetro estático con el nombre '{0}'. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 678c5453122..e15826b60e8 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - Il n'existe aucun paramètre statique nommé '{0}' + No static parameter exists with name '{0}'. Available parameters: {1}. + Il n'existe aucun paramètre statique nommé '{0}' diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 25d499f950b..b1617822dfc 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - Non sono presenti parametri statici denominati '{0}' + No static parameter exists with name '{0}'. Available parameters: {1}. + Non sono presenti parametri statici denominati '{0}' diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index b55ad346ce0..cf5e8a72ba5 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - '{0}' という名前の静的パラメーターがありません + No static parameter exists with name '{0}'. Available parameters: {1}. + '{0}' という名前の静的パラメーターがありません diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 5479af2d7a4..4255024b558 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - 이름이 '{0}'인 정적 매개 변수가 없습니다. + No static parameter exists with name '{0}'. Available parameters: {1}. + 이름이 '{0}'인 정적 매개 변수가 없습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 0895d775d1f..217d9609954 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - Nie istnieje parametr statyczny o nazwie „{0}” + No static parameter exists with name '{0}'. Available parameters: {1}. + Nie istnieje parametr statyczny o nazwie „{0}” diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 11ac22d6959..b0d40bedeb5 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - Não existe um parâmetro estático com o nome '{0}' + No static parameter exists with name '{0}'. Available parameters: {1}. + Não existe um parâmetro estático com o nome '{0}' diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index f2dfdc3fb94..0d5e4b865ad 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - Имя "{0}" не имеет статических параметров + No static parameter exists with name '{0}'. Available parameters: {1}. + Имя "{0}" не имеет статических параметров diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 86fb544b9c7..e63f0e1d8ea 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - '{0}' adında hiç statik parametre yok + No static parameter exists with name '{0}'. Available parameters: {1}. + '{0}' adında hiç statik parametre yok diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 85e85187369..03474d84fde 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - 不存在名称为“{0}”的静态参数 + No static parameter exists with name '{0}'. Available parameters: {1}. + 不存在名称为“{0}”的静态参数 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 8414c5316b1..2b45dddfd15 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -7598,8 +7598,8 @@ - No static parameter exists with name '{0}' - 沒有名稱為 '{0}' 的靜態參數 + No static parameter exists with name '{0}'. Available parameters: {1}. + 沒有名稱為 '{0}' 的靜態參數 diff --git a/tests/FSharp.Compiler.Service.Tests/EditorTests.fs b/tests/FSharp.Compiler.Service.Tests/EditorTests.fs index 6ce135326fc..44be1a5cfef 100644 --- a/tests/FSharp.Compiler.Service.Tests/EditorTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/EditorTests.fs @@ -1690,7 +1690,7 @@ let ``Test TPProject errors`` () = (11, 8, 11, 35, "The static parameter 'pattern1' of the provided type or method 'IsMatch' requires a value. Static parameters to type providers may be optionally specified using named arguments, e.g. 'IsMatch'."); (12, 8, 12, 41, "The static parameter 'pattern1' of the provided type or method 'IsMatch' requires a value. Static parameters to type providers may be optionally specified using named arguments, e.g. 'IsMatch'."); (14, 46, 14, 50, "This expression was expected to have type 'string' but here has type 'unit' "); - (15, 33, 15, 38, "No static parameter exists with name ''"); + (15, 33, 15, 38, "No static parameter exists with name ''. Available parameters: pattern1."); (16, 40, 16, 50, "This expression was expected to have type 'string' but here has type 'unit' ")] let internal extractToolTipText (ToolTipText(els)) = From 611b32bde544cf96f233a619a6c5d62d5de30131 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sat, 21 Feb 2026 04:33:55 +0100 Subject: [PATCH 09/39] FS0025: Add context-aware hint for incomplete match in for-loops When a for-loop uses a constant pattern (e.g., 'for 0 in 1..10'), the incomplete match warning now includes the hint: 'Did you use a constant where a loop variable was expected?' The hint only applies to constant patterns in for-loops, not to DU destructuring patterns like 'for Some x in ...' or regular match expressions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 28 +++++++++++++++++ .../Checking/PatternMatchCompilation.fs | 6 ++-- .../Checking/PatternMatchCompilation.fsi | 2 +- src/Compiler/Driver/CompilerDiagnostics.fs | 8 +++-- src/Compiler/FSStrings.resx | 3 ++ src/Compiler/xlf/FSStrings.cs.xlf | 5 +++ src/Compiler/xlf/FSStrings.de.xlf | 5 +++ src/Compiler/xlf/FSStrings.es.xlf | 5 +++ src/Compiler/xlf/FSStrings.fr.xlf | 5 +++ src/Compiler/xlf/FSStrings.it.xlf | 5 +++ src/Compiler/xlf/FSStrings.ja.xlf | 5 +++ src/Compiler/xlf/FSStrings.ko.xlf | 5 +++ src/Compiler/xlf/FSStrings.pl.xlf | 5 +++ src/Compiler/xlf/FSStrings.pt-BR.xlf | 5 +++ src/Compiler/xlf/FSStrings.ru.xlf | 5 +++ src/Compiler/xlf/FSStrings.tr.xlf | 5 +++ src/Compiler/xlf/FSStrings.zh-Hans.xlf | 5 +++ src/Compiler/xlf/FSStrings.zh-Hant.xlf | 5 +++ .../SequenceIteration/SequenceIteration.fs | 2 +- .../PatternMatching/Expression/Expression.fs | 31 +++++++++++++++++++ tests/fsharp/typecheck/sigs/neg06.bsl | 2 +- 21 files changed, 139 insertions(+), 8 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 9933129a2fd..ad933cc7197 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -8243,6 +8243,34 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s // Add the pattern match compilation let bodyExpr = let valsDefinedByMatching = ListSet.remove valEq elemVar vspecs + + let isConstantPattern = + match synPat with + | SynPat.Const _ + | SynPat.Paren(SynPat.Const _, _) -> true + | _ -> false + + use _diagnostics = + if isConstantPattern then + UseTransformedDiagnosticsLogger(fun oldLogger -> + { new DiagnosticsLogger("forLoopPatternMatch") with + member _.DiagnosticSink(diagnostic) = + let diagnostic = + match diagnostic.Exception with + | MatchIncomplete(isComp, cexOpt, m, _) -> + { diagnostic with Exception = MatchIncomplete(isComp, cexOpt, m, true) } + | _ -> diagnostic + + oldLogger.DiagnosticSink(diagnostic) + + member _.ErrorCount = oldLogger.ErrorCount + member _.CheckForRealErrorsIgnoringWarnings = oldLogger.CheckForRealErrorsIgnoringWarnings + }) + else + { new System.IDisposable with + member _.Dispose() = () + } + CompilePatternForMatch cenv env synEnumExpr.Range pat.Range false IgnoreWithWarning (elemVar, [], None) [MatchClause(pat, None, TTarget(valsDefinedByMatching, bodyExpr, None), mIn)] diff --git a/src/Compiler/Checking/PatternMatchCompilation.fs b/src/Compiler/Checking/PatternMatchCompilation.fs index 8bfb6d5d469..1ce5b694280 100644 --- a/src/Compiler/Checking/PatternMatchCompilation.fs +++ b/src/Compiler/Checking/PatternMatchCompilation.fs @@ -24,7 +24,7 @@ open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TypeRelations open type System.MemoryExtensions -exception MatchIncomplete of bool * (string * bool) option * range +exception MatchIncomplete of bool * (string * bool) option * range * bool exception RuleNeverMatched of range exception EnumMatchIncomplete of bool * (string * bool) option * range @@ -1016,10 +1016,10 @@ let CompilePatternBasic warning (EnumMatchIncomplete(ignoreWithWarning, Some(text, failingWhenClause), mMatch)) warningsGenerated.Add CounterExampleType.EnumCoversKnown | Some(text, failingWhenClause, CounterExampleType.WithoutEnum) when not(warningsGenerated.Contains(CounterExampleType.WithoutEnum)) -> - warning (MatchIncomplete(ignoreWithWarning, Some(text, failingWhenClause), mMatch)) + warning (MatchIncomplete(ignoreWithWarning, Some(text, failingWhenClause), mMatch, false)) warningsGenerated.Add CounterExampleType.WithoutEnum | None when not(warningsGenerated.Contains(CounterExampleType.WithoutEnum)) -> - warning (MatchIncomplete(ignoreWithWarning, None, mMatch)) + warning (MatchIncomplete(ignoreWithWarning, None, mMatch, false)) warningsGenerated.Add CounterExampleType.WithoutEnum | _ -> () | _ -> diff --git a/src/Compiler/Checking/PatternMatchCompilation.fsi b/src/Compiler/Checking/PatternMatchCompilation.fsi index b4d68aa320c..26dab1aa71a 100644 --- a/src/Compiler/Checking/PatternMatchCompilation.fsi +++ b/src/Compiler/Checking/PatternMatchCompilation.fsi @@ -71,7 +71,7 @@ val internal CompilePattern: TType -> DecisionTree * DecisionTreeTarget list -exception internal MatchIncomplete of bool * (string * bool) option * range +exception internal MatchIncomplete of bool * (string * bool) option * range * bool exception internal RuleNeverMatched of range diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index 6959a6c7df0..e80fa9b9076 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -125,7 +125,7 @@ type Exception with | InternalException(_, _, m) | InterfaceNotRevealed(_, _, m) | WrappedError(_, m) - | PatternMatchCompilation.MatchIncomplete(_, _, m) + | PatternMatchCompilation.MatchIncomplete(_, _, m, _) | PatternMatchCompilation.EnumMatchIncomplete(_, _, m) | PatternMatchCompilation.RuleNeverMatched m | ValNotMutable(_, _, m) @@ -564,6 +564,7 @@ module OldStyleMessages = let MatchIncomplete2E () = Message("MatchIncomplete2", "%s") let MatchIncomplete3E () = Message("MatchIncomplete3", "%s") let MatchIncomplete4E () = Message("MatchIncomplete4", "") + let MatchIncompleteForLoopE () = Message("MatchIncompleteForLoop", "") let RuleNeverMatchedE () = Message("RuleNeverMatched", "") let EnumMatchIncomplete1E () = Message("EnumMatchIncomplete1", "") let ValNotMutableE () = Message("ValNotMutable", "%s") @@ -1779,9 +1780,12 @@ type Exception with | WrappedError(e, _) -> e.Output(os, suggestNames) - | PatternMatchCompilation.MatchIncomplete(isComp, cexOpt, _) -> + | PatternMatchCompilation.MatchIncomplete(isComp, cexOpt, _, isForLoop) -> os.AppendString(MatchIncomplete1E().Format) + if isForLoop then + os.AppendString(MatchIncompleteForLoopE().Format) + match cexOpt with | None -> () | Some(cex, false) -> os.AppendString(MatchIncomplete2E().Format cex) diff --git a/src/Compiler/FSStrings.resx b/src/Compiler/FSStrings.resx index 41310df3d83..320dca5f32f 100644 --- a/src/Compiler/FSStrings.resx +++ b/src/Compiler/FSStrings.resx @@ -1017,6 +1017,9 @@ Unmatched elements will be ignored. + + Did you use a constant where a loop variable was expected? + Enums may take values outside known cases. diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf index 426179327bd..93943662dfe 100644 --- a/src/Compiler/xlf/FSStrings.cs.xlf +++ b/src/Compiler/xlf/FSStrings.cs.xlf @@ -1557,6 +1557,11 @@ Nespárované prvky se budou ignorovat. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. Výčty můžou získávat hodnoty mimo známé případy. diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf index 02fd2f3ba47..fc4a578186c 100644 --- a/src/Compiler/xlf/FSStrings.de.xlf +++ b/src/Compiler/xlf/FSStrings.de.xlf @@ -1557,6 +1557,11 @@ Nicht zugeordnete Elemente werden ignoriert. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. Enumerationen können Werte außerhalb bekannter Fälle verwenden. diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf index 5b474f48c96..28c04a238df 100644 --- a/src/Compiler/xlf/FSStrings.es.xlf +++ b/src/Compiler/xlf/FSStrings.es.xlf @@ -1557,6 +1557,11 @@ Los elementos que no coinciden se omitirán. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. Las enumeraciones pueden tomar valores fuera de las clases conocidas. diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf index cb893afd402..e6e9007f24d 100644 --- a/src/Compiler/xlf/FSStrings.fr.xlf +++ b/src/Compiler/xlf/FSStrings.fr.xlf @@ -1557,6 +1557,11 @@ Les éléments non appariés seront ignorés. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. Les enums peuvent accepter des valeurs en dehors des cas connus. diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf index 41c41b92221..74d0abed4f3 100644 --- a/src/Compiler/xlf/FSStrings.it.xlf +++ b/src/Compiler/xlf/FSStrings.it.xlf @@ -1557,6 +1557,11 @@ Gli elementi senza corrispondenza verranno ignorati. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. Le enumerazioni possono accettare valori esterni a casi noti. diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf index b8bbb2321a5..857ec487e51 100644 --- a/src/Compiler/xlf/FSStrings.ja.xlf +++ b/src/Compiler/xlf/FSStrings.ja.xlf @@ -1557,6 +1557,11 @@ 一致しない要素は無視されます。 + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. 列挙型は既知のケースの外の値を使用する可能性があります。 diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf index 46cce884f7c..c3f14ebc003 100644 --- a/src/Compiler/xlf/FSStrings.ko.xlf +++ b/src/Compiler/xlf/FSStrings.ko.xlf @@ -1557,6 +1557,11 @@ 일치하지 않는 요소는 무시됩니다. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. 열거형이 알려진 사례를 벗어난 값을 사용할 수 있습니다. diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf index c662402760a..255b78b901b 100644 --- a/src/Compiler/xlf/FSStrings.pl.xlf +++ b/src/Compiler/xlf/FSStrings.pl.xlf @@ -1557,6 +1557,11 @@ Niedopasowane elementy zostaną zignorowane. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. Wyliczenia mogą przyjmować wartości spoza znanych przypadków. diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf index f5bc196602a..7ba237be562 100644 --- a/src/Compiler/xlf/FSStrings.pt-BR.xlf +++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf @@ -1557,6 +1557,11 @@ Elementos incompatíveis serão ignorados. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. As enumerações pode usar valores fora de casos conhecidos. diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf index 071963e992d..ba7ddf0e871 100644 --- a/src/Compiler/xlf/FSStrings.ru.xlf +++ b/src/Compiler/xlf/FSStrings.ru.xlf @@ -1557,6 +1557,11 @@ Элементы без соответствий будут проигнорированы. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. Перечисления могут принимать значения, выходящие за пределы известных случаев. diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf index 39b66087754..6b851d2ba27 100644 --- a/src/Compiler/xlf/FSStrings.tr.xlf +++ b/src/Compiler/xlf/FSStrings.tr.xlf @@ -1557,6 +1557,11 @@ Eşleşmeyen öğeler yok sayılacak. + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. Numaralandırmalar, bilinen durumlar dışından değerler alabilir. diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf index 730fb86a85e..d10869456ce 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf @@ -1557,6 +1557,11 @@ 将忽略不匹配的元素。 + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. 枚举可能使用已知用例外的值。 diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf index 4a82caa840a..117c4e3b897 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf @@ -1557,6 +1557,11 @@ 無對應的項目將會被忽略。 + + Did you use a constant where a loop variable was expected? + Did you use a constant where a loop variable was expected? + + Enums may take values outside known cases. 列舉可能會採用來自已知案例之外的值。 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/SequenceIteration/SequenceIteration.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/SequenceIteration/SequenceIteration.fs index 322ea5be52b..5df179c09ac 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/SequenceIteration/SequenceIteration.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/SequenceIteration/SequenceIteration.fs @@ -22,7 +22,7 @@ module SequenceIteration = (Warning 25, Line 10, Col 5, Line 10, Col 11, "Incomplete pattern matches on this expression. For example, the value 'None' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") (Warning 25, Line 13, Col 5, Line 13, Col 11, "Incomplete pattern matches on this expression. For example, the value 'None' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") (Warning 25, Line 15, Col 5, Line 15, Col 11, "Incomplete pattern matches on this expression. For example, the value 'Some (0)' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") - (Warning 25, Line 17, Col 5, Line 17, Col 6, "Incomplete pattern matches on this expression. For example, the value '0' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") + (Warning 25, Line 17, Col 5, Line 17, Col 6, "Incomplete pattern matches on this expression. Did you use a constant where a loop variable was expected? For example, the value '0' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") (Warning 25, Line 22, Col 9, Line 22, Col 17, "Incomplete pattern matches on this expression. For example, the value 'None' may indicate a case not covered by the pattern(s).") (Warning 25, Line 27, Col 20, Line 27, Col 28, "Incomplete pattern matches on this expression. For example, the value 'None' may indicate a case not covered by the pattern(s).") ] diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/PatternMatching/Expression/Expression.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/PatternMatching/Expression/Expression.fs index fc9ed2de733..9d04bf40f80 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/PatternMatching/Expression/Expression.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/PatternMatching/Expression/Expression.fs @@ -141,3 +141,34 @@ module Expression = |> withOptions ["--test:ErrorRanges"] |> typecheck |> shouldSucceed + + [] + let ``MatchIncomplete for-loop with constant pattern includes hint`` () = + FSharp """ +for 0 in 1..10 do + () + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 25, Line 2, Col 5, Line 2, Col 6, "Incomplete pattern matches on this expression. Did you use a constant where a loop variable was expected? For example, the value '1' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") + + [] + let ``MatchIncomplete for-loop with parenthesized constant pattern includes hint`` () = + FSharp """ +for (0) in 1..10 do + () + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 25, Line 2, Col 6, Line 2, Col 7, "Incomplete pattern matches on this expression. Did you use a constant where a loop variable was expected? For example, the value '1' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") + + [] + let ``MatchIncomplete regular match does not include for-loop hint`` () = + FSharp """ +let f x = + match x with + | 0 -> 0 + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 25, Line 3, Col 11, Line 3, Col 12, "Incomplete pattern matches on this expression. For example, the value '1' may indicate a case not covered by the pattern(s).") diff --git a/tests/fsharp/typecheck/sigs/neg06.bsl b/tests/fsharp/typecheck/sigs/neg06.bsl index b0fa7d1450b..9d4e4fdafd8 100644 --- a/tests/fsharp/typecheck/sigs/neg06.bsl +++ b/tests/fsharp/typecheck/sigs/neg06.bsl @@ -116,4 +116,4 @@ Candidates: - static member C.M1: x: int -> int - static member C.M1: x: string -> int -neg06.fs(398,13,398,14): typecheck error FS0025: Incomplete pattern matches on this expression. For example, the value '0' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored. +neg06.fs(398,13,398,14): typecheck error FS0025: Incomplete pattern matches on this expression. Did you use a constant where a loop variable was expected? For example, the value '0' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored. From 00a34c03e549f8bdc878ad7a4d2bad07fbaa196d Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sat, 21 Feb 2026 05:20:19 +0100 Subject: [PATCH 10/39] Type mismatch errors say 'is a tuple of type' when actual type is a tuple When a type mismatch involves a tuple as the actual type, the error message now says 'is a tuple of type' instead of 'but here has type', making it clearer for beginners that the * syntax represents a tuple. Fixes dotnet/fsharp#11234 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Driver/CompilerDiagnostics.fs | 22 +++++++++++++++---- src/Compiler/FSStrings.resx | 6 +++++ src/Compiler/xlf/FSStrings.cs.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.de.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.es.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.fr.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.it.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.ja.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.ko.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.pl.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.pt-BR.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.ru.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.tr.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.zh-Hans.xlf | 10 +++++++++ src/Compiler/xlf/FSStrings.zh-Hant.xlf | 10 +++++++++ .../ErrorMessages/ConstructorTests.fs | 2 +- .../ErrorMessages/TypeMismatchTests.fs | 20 +++++++++++++++++ .../PatternMatchCompilationTests.fs | 4 ++-- 18 files changed, 177 insertions(+), 7 deletions(-) diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index e80fa9b9076..fd501f76a93 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -449,7 +449,9 @@ module OldStyleMessages = let ConstraintSolverTypesNotInEqualityRelation2E () = Message("ConstraintSolverTypesNotInEqualityRelation2", "%s%s") let ConstraintSolverTypesNotInSubsumptionRelationE () = Message("ConstraintSolverTypesNotInSubsumptionRelation", "%s%s%s") let ErrorFromAddingTypeEquation1E () = Message("ErrorFromAddingTypeEquation1", "%s%s%s") + let ErrorFromAddingTypeEquation1TupleE () = Message("ErrorFromAddingTypeEquation1Tuple", "%s%s%s") let ErrorFromAddingTypeEquation2E () = Message("ErrorFromAddingTypeEquation2", "%s%s%s") + let ErrorFromAddingTypeEquation2TupleE () = Message("ErrorFromAddingTypeEquation2Tuple", "%s%s%s") let ErrorFromAddingTypeEquationTuplesE () = Message("ErrorFromAddingTypeEquationTuples", "%d%s%d%s%s") let ErrorFromApplyingDefault1E () = Message("ErrorFromApplyingDefault1", "%s") let ErrorFromApplyingDefault2E () = Message("ErrorFromApplyingDefault2", "") @@ -765,17 +767,24 @@ type Exception with | ErrorFromAddingTypeEquation(g, denv, ty1, ty2, ConstraintSolverTypesNotInEqualityRelation(_, ty1b, ty2b, m, _, contextInfo), _) when typeEquiv g ty1 ty1b && typeEquiv g ty2 ty2b -> + let isActualTuple = isAnyTupleTy g ty2 let ty1, ty2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2 + let typeEquation1E = + if isActualTuple then + ErrorFromAddingTypeEquation1TupleE + else + ErrorFromAddingTypeEquation1E + OutputTypesNotInEqualityRelationContextInfo contextInfo ty1 ty2 m os (fun contextInfo -> match contextInfo with | ContextInfo.TupleInRecordFields -> - os.AppendString(ErrorFromAddingTypeEquation1E().Format ty2 ty1 tpcs) + os.AppendString(typeEquation1E().Format ty2 ty1 tpcs) os.AppendString(Environment.NewLine + FSComp.SR.commaInsteadOfSemicolonInRecord ()) | _ when ty2 = "bool" && ty1.EndsWithOrdinal(" ref") -> - os.AppendString(ErrorFromAddingTypeEquation1E().Format ty2 ty1 tpcs) + os.AppendString(typeEquation1E().Format ty2 ty1 tpcs) os.AppendString(Environment.NewLine + FSComp.SR.derefInsteadOfNot ()) - | _ -> os.AppendString(ErrorFromAddingTypeEquation1E().Format ty2 ty1 tpcs)) + | _ -> os.AppendString(typeEquation1E().Format ty2 ty1 tpcs)) | ErrorFromAddingTypeEquation(_, _, _, _, (ConstraintSolverTypesNotInEqualityRelation(_, _, _, _, _, contextInfo) as e), _) when (match contextInfo with @@ -813,12 +822,17 @@ type Exception with os.AppendString(SeeAlsoE().Format(stringOfRange m1)) | ErrorFromAddingTypeEquation(g, denv, ty1, ty2, e, _) -> + let isActualTuple = isAnyTupleTy g ty2 + let e = if not (typeEquiv g ty1 ty2) then let ty1, ty2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2 if ty1 <> ty2 + tpcs then - os.AppendString(ErrorFromAddingTypeEquation2E().Format ty1 ty2 tpcs) + if isActualTuple then + os.AppendString(ErrorFromAddingTypeEquation2TupleE().Format ty1 ty2 tpcs) + else + os.AppendString(ErrorFromAddingTypeEquation2E().Format ty1 ty2 tpcs) e diff --git a/src/Compiler/FSStrings.resx b/src/Compiler/FSStrings.resx index 320dca5f32f..2783a569fdb 100644 --- a/src/Compiler/FSStrings.resx +++ b/src/Compiler/FSStrings.resx @@ -153,9 +153,15 @@ This expression was expected to have type\n '{1}' \nbut here has type\n '{0}' {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type constraint mismatch when applying the default type '{0}' for a type inference variable. diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf index 93943662dfe..30003ecc155 100644 --- a/src/Compiler/xlf/FSStrings.cs.xlf +++ b/src/Compiler/xlf/FSStrings.cs.xlf @@ -172,6 +172,16 @@ U tohoto výrazu se očekával typ\n {1}, \nale tady je typu\n {0} {2}. + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n Neshoda v typu. Očekávaný typ je \n {0}, \nale předávaný je\n {1} {2}.\n diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf index fc4a578186c..b04b50a630d 100644 --- a/src/Compiler/xlf/FSStrings.de.xlf +++ b/src/Compiler/xlf/FSStrings.de.xlf @@ -172,6 +172,16 @@ Dieser Ausdruck sollte den folgenden Typ aufweisen:\n "{1}" \nEr ist jedoch vom folgenden Typ:\n "{0}" {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n Typenkonflikt. Erwartet:\n "{0}" \nErhalten:\n "{1}" {2}\n diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf index 28c04a238df..de6c7a3e4ca 100644 --- a/src/Compiler/xlf/FSStrings.es.xlf +++ b/src/Compiler/xlf/FSStrings.es.xlf @@ -172,6 +172,16 @@ Se esperaba que esta expresión tuviera el tipo\n '{1}' \npero aquí tiene el tipo\n '{0}' {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n No coinciden los tipos. Se esperaba\n '{0}' \npero se dio\n '{1}' {2}\n diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf index e6e9007f24d..d01331484cb 100644 --- a/src/Compiler/xlf/FSStrings.fr.xlf +++ b/src/Compiler/xlf/FSStrings.fr.xlf @@ -172,6 +172,16 @@ Cette expression était censée avoir le type\n {1} \nmais elle a ici le type\n {0} {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n Incompatibilité de type. Attente de\n {0} \nmais obtention de\n {1} {2}\n diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf index 74d0abed4f3..4721867dc6b 100644 --- a/src/Compiler/xlf/FSStrings.it.xlf +++ b/src/Compiler/xlf/FSStrings.it.xlf @@ -172,6 +172,16 @@ Il tipo previsto di questa espressione è\n '{1}' \nma quello effettivo è\n '{0}' {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n Tipo non corrispondente. Il tipo previsto è\n '{0}' \nma quello specificato è\n '{1}' {2}\n diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf index 857ec487e51..d9d94d47fae 100644 --- a/src/Compiler/xlf/FSStrings.ja.xlf +++ b/src/Compiler/xlf/FSStrings.ja.xlf @@ -172,6 +172,16 @@ この式に必要な型は\n '{1}' \nですが、ここでは次の型が指定されています\n '{0}' {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n 型が一致しません。\n '{0}' \nという指定が必要ですが、\n '{1}' {2}\nが指定されました。 diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf index c3f14ebc003..be61bd88fcb 100644 --- a/src/Compiler/xlf/FSStrings.ko.xlf +++ b/src/Compiler/xlf/FSStrings.ko.xlf @@ -172,6 +172,16 @@ 이 식에는\n '{1}' 형식이 필요하지만 \n여기에서는\n '{0}' 형식이 지정되었습니다. {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n 형식이 일치하지 않습니다.\n '{0}'이(가) \n필요하지만\n '{1}'이(가) 지정되었습니다. {2}\n diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf index 255b78b901b..f3c19eb815b 100644 --- a/src/Compiler/xlf/FSStrings.pl.xlf +++ b/src/Compiler/xlf/FSStrings.pl.xlf @@ -172,6 +172,16 @@ Oczekiwany typ tego wyrażenia:\n „{1}” \nTyp w tym miejscu:\n „{0}” {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n Niezgodność typów. Oczekiwany typ:\n „{0}” \nOtrzymany typ:\n „{1}” {2}\n diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf index 7ba237be562..40fb1f2305f 100644 --- a/src/Compiler/xlf/FSStrings.pt-BR.xlf +++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf @@ -172,6 +172,16 @@ Esperava-se que esta expressão tivesse o tipo\n '{1}' \n, mas aqui ela tem o tipo\n '{0}' {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n Tipos incompatíveis. Esperando um\n '{0}' \n, mas foi fornecido um\n '{1}' {2}\n diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf index ba7ddf0e871..95ae50b60fd 100644 --- a/src/Compiler/xlf/FSStrings.ru.xlf +++ b/src/Compiler/xlf/FSStrings.ru.xlf @@ -172,6 +172,16 @@ В данном выражении требовалось наличие типа\n "{1}" \n, но получен тип\n "{0}" {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n Несоответствие типов. Требуется \n "{0}" \n, но получен\n "{1}" {2}\n diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf index 6b851d2ba27..9da12dfe721 100644 --- a/src/Compiler/xlf/FSStrings.tr.xlf +++ b/src/Compiler/xlf/FSStrings.tr.xlf @@ -172,6 +172,16 @@ Bu ifadenin\n '{1}' \ntüründe olması bekleniyordu ancak buradaki tür\n '{0}' {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n Tür uyumsuzluğu. Beklenen şuydu:\n '{0}' \nancak şu sağlandı:\n '{1}' {2}\n diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf index d10869456ce..c9fda977784 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf @@ -172,6 +172,16 @@ 此表达式应具有类型\n “{1}” \n而此处具有类型\n “{0}” {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n 类型不匹配。应为\n “{0}” \n而给定的是\n “{1}” {2}\n diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf index 117c4e3b897..a199691702d 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf @@ -172,6 +172,16 @@ 這個運算式必須為類型\n '{1}' \n但此處卻是類型\n '{0}' {2} + + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + This expression was expected to have type\n '{1}' \nbut is a tuple of type\n '{0}' {2} + + + + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + Type mismatch. Expecting a\n '{0}' \nbut given a tuple of type\n '{1}' {2}\n + + Type mismatch. Expecting a\n '{0}' \nbut given a\n '{1}' {2}\n 類型不符。必須是\n '{0}' \n但指定的是\n '{1}' {2}\n diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConstructorTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConstructorTests.fs index a08e1cdcaed..6ef494d9042 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConstructorTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ConstructorTests.fs @@ -32,7 +32,7 @@ let x = { Name = "Isaac", Age = 21, City = "London" } |> withDiagnostics [ (Error 39, Line 3, Col 27, Line 3, Col 30, "The value or constructor 'Age' is not defined.") (Error 39, Line 3, Col 37, Line 3, Col 41, "The value or constructor 'City' is not defined.") - (Error 1, Line 3, Col 18, Line 3, Col 52, "This expression was expected to have type\n 'string' \nbut here has type\n 'string * bool * bool' ") + (Error 1, Line 3, Col 18, Line 3, Col 52, "This expression was expected to have type\n 'string' \nbut is a tuple of type\n 'string * bool * bool' ") (Error 764, Line 3, Col 9, Line 3, Col 54, "No assignment given for field 'Age' of type 'Test.Person'")] [] diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs index e96ba41087c..193717a16a9 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs @@ -411,3 +411,23 @@ let y = r 10 Col 10, "This value is not a function and cannot be applied. It has type 'MyRecord', which does not accept arguments.") + [] + let ``Tuple actual type says 'is a tuple of type'``() = + FSharp """ +let f (x: int) (y: int) : string = x, y + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 1, Line 2, Col 36, Line 2, Col 40, + "This expression was expected to have type\n 'string' \nbut is a tuple of type\n 'int * int' ") + + [] + let ``Non-tuple actual type says 'but here has type'``() = + FSharp """ +let f (x: int) : string = x + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 1, Line 2, Col 27, Line 2, Col 28, + "This expression was expected to have type\n 'string' \nbut here has type\n 'int' ") + diff --git a/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs b/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs index 0c77c11b9d0..f3c31f000da 100644 --- a/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/PatternMatchCompilationTests.fs @@ -82,7 +82,7 @@ match A with """ assertHasSymbolUsages ["x"; "y"] checkResults dumpDiagnostics checkResults |> shouldEqual [ - "(7,5--7,12): This expression was expected to have type 'int' but here has type ''a * 'b * 'c'"; + "(7,5--7,12): This expression was expected to have type 'int' but is a tuple of type ''a * 'b * 'c'"; "(6,6--6,7): Incomplete pattern matches on this expression." ] @@ -955,7 +955,7 @@ Some "" |> eq // No more type checks after the above line? """ assertHasSymbolUsages (Set.toList validSet) checkResults dumpDiagnostics checkResults |> shouldEqual [ - "(27,2--27,14): This expression was expected to have type 'objnull' but here has type 'struct ('a * 'b)'"; + "(27,2--27,14): This expression was expected to have type 'objnull' but is a tuple of type 'struct ('a * 'b)'"; "(52,2--52,13): This expression was expected to have type 'objnull' but here has type 'AAA'"; "(26,6--26,24): Incomplete pattern matches on this expression. For example, the value '``some-other-subtype``' may indicate a case not covered by the pattern(s)."; "(24,6--24,12): Incomplete pattern matches on this expression. For example, the value '``some-other-subtype``' may indicate a case not covered by the pattern(s)."; From ac665668e2cc70e9ec05d8a3d190301b6c1d77cc Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sat, 21 Feb 2026 07:01:39 +0100 Subject: [PATCH 11/39] Add specific error for let!/use! at end of CE Fixes dotnet/fsharp#6717 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/FSComp.txt | 3 +- src/Compiler/pars.fsy | 22 +++++++ src/Compiler/xlf/FSComp.txt.cs.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.de.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.es.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.fr.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.it.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.ja.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.ko.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.pl.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.ru.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.tr.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 7 ++- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 7 ++- .../Language/ComputationExpressionTests.fs | 59 +++++++++++++++++++ 16 files changed, 161 insertions(+), 14 deletions(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index dec06fef1f4..fb9881637c5 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1807,4 +1807,5 @@ featureReturnFromFinal,"Support for ReturnFromFinal/YieldFromFinal in computatio featureMethodOverloadsCache,"Support for caching method overload resolution results for improved compilation performance." featureImplicitDIMCoverage,"Implicit dispatch slot coverage for default interface member implementations" 3880,optsLangVersionOutOfSupport,"Language version '%s' is out of support. The last .NET SDK supporting it is available at https://dotnet.microsoft.com/en-us/download/dotnet/%s" -3881,optsUnrecognizedLanguageFeature,"Unrecognized language feature name: '%s'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'." \ No newline at end of file +3881,optsUnrecognizedLanguageFeature,"Unrecognized language feature name: '%s'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'." +3882,parsLetBangCannotBeLastInCE,"'%s' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression." \ No newline at end of file diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 37eb245265d..5d6708131b8 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -4575,6 +4575,8 @@ declExpr: if isInline then errorR(Error(FSComp.SR.parsInvalidDeclarationSyntax(), rhs parseState 2)) if isMutable then errorR(Error(FSComp.SR.parsInvalidDeclarationSyntax(), rhs parseState 2)) + errorR(Error(FSComp.SR.parsLetBangCannotBeLastInCE($1 + "!"), rhs parseState 1)) + let mKeyword = rhs parseState 1 let keyword = if $1 = "let" then SynLeadingKeyword.LetBang mKeyword else SynLeadingKeyword.UseBang mKeyword let mEquals = Some(rhs parseState 3) @@ -4587,6 +4589,26 @@ declExpr: // Use ImplicitZero as the continuation expression for error recovery mkLetBangExpression(mIn, mAll, SynExpr.ImplicitZero m, (pat, returnInfo, $4, [], keyword, mEquals, isUse)) } + | OBINDER ceBindingCore EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders error %prec expr_let + { // Error recovery for let!/use! as the final expression in a computation expression + let pat, mPat, isInline, isMutable, returnInfo = $2 + + if isInline then errorR(Error(FSComp.SR.parsInvalidDeclarationSyntax(), rhs parseState 2)) + if isMutable then errorR(Error(FSComp.SR.parsInvalidDeclarationSyntax(), rhs parseState 2)) + + errorR(Error(FSComp.SR.parsLetBangCannotBeLastInCE($1 + "!"), rhs parseState 1)) + + let mKeyword = rhs parseState 1 + let keyword = if $1 = "let" then SynLeadingKeyword.LetBang mKeyword else SynLeadingKeyword.UseBang mKeyword + let mEquals = Some(rhs parseState 3) + let mAll = unionRanges mKeyword (rhs parseState 8) + let m = $4.Range.EndRange + let _, mIn, _ = $5 + + let isUse = ($1 = "use") + + mkLetBangExpression(mIn, mAll, SynExpr.ImplicitZero m, (pat, returnInfo, $4, $7, keyword, mEquals, isUse)) } + | DO_BANG typedSequentialExpr IN opt_OBLOCKSEP typedSequentialExprBlock %prec expr_let { let spBind = DebugPointAtBinding.NoneAtDo let trivia: SynExprDoBangTrivia = { DoBangKeyword = rhs parseState 1 } diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 251245548bc..145d83e7c02 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - Neexistuje žádný statický parametr s názvem {0}. + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ Rozšíření správce závislostí {0} nešlo načíst. Zpráva: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 34347e241d3..e5b678e73a8 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - Es sind keine statische Parameter mit dem Namen '{0}' vorhanden. + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ Die Abhängigkeits-Manager-Erweiterung "{0}" konnte nicht geladen werden. Meldung: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 5ef879e9e15..c518e8ea248 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - No existe ningún parámetro estático con el nombre '{0}'. + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ No se pudo cargar la extensión del administrador de dependencias {0}. Mensaje: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index e15826b60e8..4cfbc23d0b6 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - Il n'existe aucun paramètre statique nommé '{0}' + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ Impossible de charger l'extension du gestionnaire de dépendances {0}. Message : {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index b1617822dfc..dbd7e6d6a48 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - Non sono presenti parametri statici denominati '{0}' + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ Non è stato possibile caricare l'estensione {0} di gestione delle dipendenze. Messaggio: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index cf5e8a72ba5..f9e73277c01 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - '{0}' という名前の静的パラメーターがありません + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ 依存関係マネージャーの拡張機能 {0} を読み込むことができませんでした。メッセージ: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 4255024b558..809a37ac101 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - 이름이 '{0}'인 정적 매개 변수가 없습니다. + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ 종속성 관리자 확장 {0}을(를) 로드할 수 없습니다. 메시지: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 217d9609954..aef42e3ca00 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - Nie istnieje parametr statyczny o nazwie „{0}” + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ Nie można załadować rozszerzenia menedżera zależności {0}. Komunikat: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index b0d40bedeb5..607bc565233 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - Não existe um parâmetro estático com o nome '{0}' + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ Não foi possível carregar a extensão do gerenciador de dependências {0}. Mensagem: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 0d5e4b865ad..a0a3af66594 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - Имя "{0}" не имеет статических параметров + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ Не удалось загрузить расширение диспетчера зависимостей {0}. Сообщение: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index e63f0e1d8ea..701c6acc444 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - '{0}' adında hiç statik parametre yok + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ {0} bağımlılık yöneticisi uzantısı yüklenemedi. İleti: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 03474d84fde..f0c58364b68 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - 不存在名称为“{0}”的静态参数 + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ 无法加载依赖项管理器扩展 {0}。消息: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 2b45dddfd15..6f1889819f1 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -7599,7 +7599,7 @@ No static parameter exists with name '{0}'. Available parameters: {1}. - 沒有名稱為 '{0}' 的靜態參數 + No static parameter exists with name '{0}'. Available parameters: {1}. @@ -8932,6 +8932,11 @@ 無法載入相依性管理員延伸模組 {0}。訊息: {1} + + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs index b1ea2b95ec7..1b3a1b7ad5c 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs @@ -2323,3 +2323,62 @@ let result = query { for x in data1 do join (y, name) in data2 on (x = y); selec |> shouldFail |> withSingleDiagnostic (Warning 1182, Line line1, Col col1, Line line2, Col col2, msg) |> ignore + + [] + let ``let! at end of computation expression gives specific error``() = + FSharp """ +module ComputationExpressionTests +let foo() = + async { + let! result = async { return 0 } + } + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 10, Line 6, Col 5, Line 6, Col 6, "Unexpected symbol '}' in expression") + (Error 3882, Line 5, Col 9, Line 5, Col 13, "'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") + ] + + [] + let ``use! at end of computation expression gives specific error``() = + FSharp """ +module ComputationExpressionTests +let foo() = + async { + use! result = async { return null : System.IDisposable } + } + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 10, Line 6, Col 5, Line 6, Col 6, "Unexpected symbol '}' in expression") + (Error 3882, Line 5, Col 9, Line 5, Col 13, "'use!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") + ] + + [] + let ``let! and! at end of computation expression gives specific error``() = + FSharp """ +module ComputationExpressionTests + +type Builder() = + member _.Bind(x, f) = f x + member _.MergeSources(x, y) = (x, y) + member _.BindReturn(x, f) = f x + member _.Return(x) = x + member _.Zero() = () + +let builder = Builder() + +let foo() = + builder { + let! x = 1 + and! y = 2 + } + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 10, Line 17, Col 5, Line 17, Col 6, "Unexpected symbol '}' in expression") + (Error 3882, Line 15, Col 9, Line 15, Col 13, "'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") + ] From 9222e8ebdb4be1ad8f7483a377ed96ffdb53635c Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sat, 21 Feb 2026 08:28:43 +0100 Subject: [PATCH 12/39] Improve error for elif chain without final else branch When an if/elif chain is missing the final else branch, the compiler now produces the same quality error message as for a simple if without else: 'This if expression is missing an else branch...' instead of the generic type mismatch error. The fix detects elif chains missing a final else at two levels: - At the outer if level, using a recursive elifChainMissingElse helper - At the inner elif level, when the context is ElseBranchResult and synElseExprOpt is None, setting OmittedElseBranch with the correct range to match the UnifyTypes error location. Fixes dotnet/fsharp#6873 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 11 ++++++++ .../ErrorMessages/MissingElseBranch.fs | 27 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index ad933cc7197..c56c84781e1 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -10741,6 +10741,13 @@ and CheckRecursiveBindingIds binds = if nm <> "" && not (hashOfBinds.Add nm) then error(Duplicate("value", nm, m)) +/// Returns true if the expression is an elif chain that ends without a final 'else' branch. +and elifChainMissingElse = + function + | SynExpr.IfThenElse(elseExpr = None) -> true + | SynExpr.IfThenElse(elseExpr = Some elseExpr) -> elifChainMissingElse elseExpr + | _ -> false + /// Process a sequence of sequentials mixed with iterated lets "let ... in let ... in ..." in a tail recursive way /// This avoids stack overflow on really large "let" and "letrec" lists and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synExpr cont = @@ -10788,10 +10795,14 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synExpr cont = let thenExpr, tpenv = let env = match env.eContextInfo with + | ContextInfo.ElseBranchResult _ when Option.isNone synElseExprOpt -> + { env with eContextInfo = ContextInfo.OmittedElseBranch m } | ContextInfo.ElseBranchResult _ -> { env with eContextInfo = ContextInfo.ElseBranchResult synThenExpr.Range } | _ -> match synElseExprOpt with | None -> { env with eContextInfo = ContextInfo.OmittedElseBranch synThenExpr.Range } + | Some elseExpr when elifChainMissingElse elseExpr -> + { env with eContextInfo = ContextInfo.OmittedElseBranch synThenExpr.Range } | _ -> { env with eContextInfo = ContextInfo.IfExpression synThenExpr.Range } if not isRecovery && Option.isNone synElseExprOpt then diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/MissingElseBranch.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/MissingElseBranch.fs index 23f43914260..7a906b49946 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/MissingElseBranch.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/MissingElseBranch.fs @@ -44,3 +44,30 @@ let y = |> shouldFail |> withSingleDiagnostic (Error 1, Line 4, Col 20, Line 4, Col 26, "This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'string'.") + + [] + let ``Fail if else branch is missing in elif chain``() = + FSharp """ +let x = 10 +let y = + if x > 10 then "test" + elif x > 2 then "blah" + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 1, Line 5, Col 4, Line 5, Col 26, + "This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'string'.") + + [] + let ``Fail if else branch is missing in nested elif chain``() = + FSharp """ +let x = 10 +let y = + if x > 10 then "test" + elif x > 5 then "middle" + elif x > 2 then "blah" + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 1, Line 6, Col 4, Line 6, Col 26, + "This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'string'.") From 4c0a17517fb24936b82fb582b2d2d29d1eb93720 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sat, 21 Feb 2026 09:17:51 +0100 Subject: [PATCH 13/39] Add warning 3883 for comma vs semicolon confusion in list literals When a list literal contains exactly one tuple element (e.g. [1, 2, 3]), emit warning FS3883 suggesting the use of semicolons instead of commas. Parenthesized tuples [(1, 2, 3)] do not trigger the warning. Fixes dotnet/fsharp#1120 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 5 ++ 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 ++ .../ErrorMessages/CommaSemicolonListTests.fs | 83 +++++++++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + 17 files changed, 156 insertions(+), 1 deletion(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index c56c84781e1..dcd42e3e48d 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -6257,6 +6257,11 @@ and TcExprTuple (cenv: cenv) overallTy env tpenv (isExplicitStruct, args, m) = and TcExprArrayOrList (cenv: cenv) overallTy env tpenv (isArray, args, m) = let g = cenv.g + match isArray, args with + | false, [ SynExpr.Tuple(_, _, _, _) ] -> + warning (Error(FSComp.SR.tcListLiteralWithSingleTupleElement (), m)) + | _ -> () + CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) let argTy = NewInferenceType g let actualTy = if isArray then mkArrayType g argTy else mkListTy g argTy diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index fb9881637c5..5a9d0d8140f 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1808,4 +1808,5 @@ featureMethodOverloadsCache,"Support for caching method overload resolution resu featureImplicitDIMCoverage,"Implicit dispatch slot coverage for default interface member implementations" 3880,optsLangVersionOutOfSupport,"Language version '%s' is out of support. The last .NET SDK supporting it is available at https://dotnet.microsoft.com/en-us/download/dotnet/%s" 3881,optsUnrecognizedLanguageFeature,"Unrecognized language feature name: '%s'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'." -3882,parsLetBangCannotBeLastInCE,"'%s' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression." \ No newline at end of file +3882,parsLetBangCannotBeLastInCE,"'%s' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression." +3883,tcListLiteralWithSingleTupleElement,"This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?" \ 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 145d83e7c02..8fdd1e50583 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index e5b678e73a8..d1a027738c1 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index c518e8ea248..4205eaf6bc9 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 4cfbc23d0b6..6efba8b40cb 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index dbd7e6d6a48..54ba8a01c42 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index f9e73277c01..204ab0110df 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 809a37ac101..6ef1fa76bfe 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index aef42e3ca00..21d3adcb606 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 607bc565233..b5dd43d8560 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index a0a3af66594..59b868a4fbb 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 701c6acc444..64d62b4b37d 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index f0c58364b68..ced5ab31ee7 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 6f1889819f1..cc21f520588 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -8937,6 +8937,11 @@ '{0}' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. + + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements? + + \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs new file mode 100644 index 00000000000..df354ab1bae --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs @@ -0,0 +1,83 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace ErrorMessages + +open Xunit +open FSharp.Test.Compiler + +module ``Comma vs semicolon in list`` = + + [] + let ``Warn on single tuple in list literal``() = + FSharp """ +let x = [1, 2, 3] + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 3883, Line 2, Col 9, Line 2, Col 18, + "This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?") + + [] + let ``No warning on semicolon-separated list``() = + FSharp """ +let x = [1; 2; 3] + """ + |> typecheck + |> shouldSucceed + |> withDiagnostics [] + + [] + let ``No warning on parenthesized tuple in list``() = + FSharp """ +let x = [(1, 2, 3)] + """ + |> typecheck + |> shouldSucceed + |> withDiagnostics [] + + [] + let ``No warning on multi-element list of tuples``() = + FSharp """ +let x = [1, 2; 3, 4] + """ + |> typecheck + |> shouldSucceed + |> withDiagnostics [] + + [] + let ``No warning on array with tuple``() = + FSharp """ +let x = [| 1, 2, 3 |] + """ + |> typecheck + |> shouldSucceed + |> withDiagnostics [] + + [] + let ``Warn on two-element tuple in list``() = + FSharp """ +let x = [1, 2] + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Warning 3883, Line 2, Col 9, Line 2, Col 15, + "This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?") + + [] + let ``Warning is suppressible via nowarn``() = + FSharp """ +#nowarn "3883" +let x = [1, 2, 3] + """ + |> typecheck + |> shouldSucceed + |> withDiagnostics [] + + [] + let ``No warning on empty list``() = + FSharp """ +let x: int list = [] + """ + |> typecheck + |> shouldSucceed + |> withDiagnostics [] diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index fd02dace6e1..d743eacb29e 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -289,6 +289,7 @@ + From 164db13bd0e951ebc1eda0f501b68e703a665026 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sat, 21 Feb 2026 10:09:37 +0100 Subject: [PATCH 14/39] Fix warning 3883 to exclude struct tuples in list literals Change SynExpr.Tuple(_, _, _, _) to SynExpr.Tuple(false, _, _, _) so that [struct(1, 2, 3)] does not trigger a false positive warning. Add test for struct tuple case. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Checking/Expressions/CheckExpressions.fs | 2 +- .../ErrorMessages/CommaSemicolonListTests.fs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index dcd42e3e48d..3f025a3ea07 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -6258,7 +6258,7 @@ and TcExprArrayOrList (cenv: cenv) overallTy env tpenv (isArray, args, m) = let g = cenv.g match isArray, args with - | false, [ SynExpr.Tuple(_, _, _, _) ] -> + | false, [ SynExpr.Tuple(false, _, _, _) ] -> warning (Error(FSComp.SR.tcListLiteralWithSingleTupleElement (), m)) | _ -> () diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs index df354ab1bae..fbced051094 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs @@ -73,6 +73,15 @@ let x = [1, 2, 3] |> shouldSucceed |> withDiagnostics [] + [] + let ``No warning on struct tuple in list``() = + FSharp """ +let x = [struct(1, 2, 3)] + """ + |> typecheck + |> shouldSucceed + |> withDiagnostics [] + [] let ``No warning on empty list``() = FSharp """ From 343581882534b42a5a5a0cabb507f75e35331faf Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 25 Feb 2026 09:48:07 +0100 Subject: [PATCH 15/39] Add test for SRTP operator scope hint in error message Add a component test that asserts the csExpectTypeWithOperatorButGivenFunction error message includes the 'operator may not be in scope' hint text added for dotnet/fsharp#2828. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ErrorMessages/OperatorTests.fs | 19 +++++++++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + 2 files changed, 20 insertions(+) create mode 100644 tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs new file mode 100644 index 00000000000..9c44888a222 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs @@ -0,0 +1,19 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace ErrorMessages + +open Xunit +open FSharp.Test.Compiler + +module ``Operator Errors`` = + + [] + let ``SRTP operator scope hint is shown when function type given``() = + FSharp """ +let inline add (x: ^a) (y: ^a) = x + y +let result = add id id + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 1, Line 3, Col 18, Line 3, Col 20, + "Expecting a type supporting the operator '+' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace.") diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index d743eacb29e..6dbd4d9408a 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -289,6 +289,7 @@ + From b101368541898c042627185f3a5b586c820b00b1 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 25 Feb 2026 10:41:50 +0100 Subject: [PATCH 16/39] Add test for ErrorFromAddingTypeEquation2Tuple diagnostic path The catch-all arm in CompilerDiagnostics.fs (ErrorFromAddingTypeEquation2Tuple) was untested. This test uses a recursive function producing a tuple that triggers the ConstraintSolverInfiniteTypes inner error, which falls through to the catch-all arm and verifies the 'but given a tuple of type' message. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ErrorMessages/TypeMismatchTests.fs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs index 193717a16a9..33195b1187c 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs @@ -421,6 +421,20 @@ let f (x: int) (y: int) : string = x, y |> withSingleDiagnostic (Error 1, Line 2, Col 36, Line 2, Col 40, "This expression was expected to have type\n 'string' \nbut is a tuple of type\n 'int * int' ") + [] + let ``Catch-all tuple type says 'but given a tuple of type'``() = + FSharp """ +let rec f () = f (), f () + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 1, Line 2, Col 16, Line 2, Col 20, + "Type mismatch. Expecting a\n ''a' \nbut given a tuple of type\n ''a * 'b' \nThe types ''a' and ''a * 'b' cannot be unified.") + (Error 1, Line 2, Col 22, Line 2, Col 26, + "Type mismatch. Expecting a\n ''a' \nbut given a tuple of type\n ''b * 'a' \nThe types ''a' and ''b * 'a' cannot be unified.") + ] + [] let ``Non-tuple actual type says 'but here has type'``() = FSharp """ From 5f2b98225224f6733d9c88110278ecd76b2e4da6 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 25 Feb 2026 11:23:36 +0100 Subject: [PATCH 17/39] Document MatchIncomplete 4th bool and add inline comments Add doc comments to MatchIncomplete exception in .fsi and .fs explaining all 4 fields including the isForLoopBinding flag. Add inline comment (* isForLoopBinding: *) at the call site in CheckExpressions.fs and a block comment explaining why the DiagnosticsLogger interception exists. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Checking/Expressions/CheckExpressions.fs | 5 ++++- src/Compiler/Checking/PatternMatchCompilation.fs | 2 ++ src/Compiler/Checking/PatternMatchCompilation.fsi | 4 ++++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 3f025a3ea07..36ed8c00c5e 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -8255,6 +8255,8 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s | SynPat.Paren(SynPat.Const _, _) -> true | _ -> false + // Intercept MatchIncomplete diagnostics to mark them as originating from a for-loop binding, + // which adds a context-specific hint in the error message (e.g., "consider using a wildcard pattern"). use _diagnostics = if isConstantPattern then UseTransformedDiagnosticsLogger(fun oldLogger -> @@ -8263,7 +8265,8 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s let diagnostic = match diagnostic.Exception with | MatchIncomplete(isComp, cexOpt, m, _) -> - { diagnostic with Exception = MatchIncomplete(isComp, cexOpt, m, true) } + { diagnostic with + Exception = MatchIncomplete(isComp, cexOpt, m, (* isForLoopBinding: *) true) } | _ -> diagnostic oldLogger.DiagnosticSink(diagnostic) diff --git a/src/Compiler/Checking/PatternMatchCompilation.fs b/src/Compiler/Checking/PatternMatchCompilation.fs index 1ce5b694280..e9639c3311c 100644 --- a/src/Compiler/Checking/PatternMatchCompilation.fs +++ b/src/Compiler/Checking/PatternMatchCompilation.fs @@ -24,6 +24,8 @@ open FSharp.Compiler.TypedTreeOps open FSharp.Compiler.TypeRelations open type System.MemoryExtensions +/// Exception raised when a pattern match is incomplete. +/// Fields: isComputationExpression * (counterExample * isShownAsFieldPattern) option * range * isForLoopBinding exception MatchIncomplete of bool * (string * bool) option * range * bool exception RuleNeverMatched of range exception EnumMatchIncomplete of bool * (string * bool) option * range diff --git a/src/Compiler/Checking/PatternMatchCompilation.fsi b/src/Compiler/Checking/PatternMatchCompilation.fsi index 26dab1aa71a..8dbf3fd1adb 100644 --- a/src/Compiler/Checking/PatternMatchCompilation.fsi +++ b/src/Compiler/Checking/PatternMatchCompilation.fsi @@ -71,6 +71,10 @@ val internal CompilePattern: TType -> DecisionTree * DecisionTreeTarget list +/// Exception raised when a pattern match is incomplete. +/// Fields: isComputationExpression * (counterExample * isShownAsFieldPattern) option * range * isForLoopBinding +/// The isForLoopBinding flag indicates the match originated from a for-loop pattern (e.g., `for 1 in xs`), +/// which changes the diagnostic hint to suggest using a wildcard pattern. exception internal MatchIncomplete of bool * (string * bool) option * range * bool exception internal RuleNeverMatched of range From 8f4a0a2e9b2c360595d267906f6ef3411507ddbc Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 25 Feb 2026 11:56:59 +0100 Subject: [PATCH 18/39] Deduplicate tuple detection in CompilerDiagnostics.fs Extract typeEquationMessage helper to replace duplicated isAnyTupleTy branching at both ErrorFromAddingTypeEquation match arms. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/Driver/CompilerDiagnostics.fs | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index fd501f76a93..f7626531e9e 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -660,6 +660,8 @@ type Exception with member exn.Output(os: StringBuilder, suggestNames) = + let typeEquationMessage g ty2 normalE tupleE = if isAnyTupleTy g ty2 then tupleE else normalE + match exn with // TODO: this is now unused...? | ConstraintSolverTupleDiffLengths(_, _, tl1, tl2, m, m2) -> @@ -767,14 +769,10 @@ type Exception with | ErrorFromAddingTypeEquation(g, denv, ty1, ty2, ConstraintSolverTypesNotInEqualityRelation(_, ty1b, ty2b, m, _, contextInfo), _) when typeEquiv g ty1 ty1b && typeEquiv g ty2 ty2b -> - let isActualTuple = isAnyTupleTy g ty2 - let ty1, ty2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2 - let typeEquation1E = - if isActualTuple then - ErrorFromAddingTypeEquation1TupleE - else - ErrorFromAddingTypeEquation1E + typeEquationMessage g ty2 ErrorFromAddingTypeEquation1E ErrorFromAddingTypeEquation1TupleE + + let ty1, ty2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2 OutputTypesNotInEqualityRelationContextInfo contextInfo ty1 ty2 m os (fun contextInfo -> match contextInfo with @@ -822,17 +820,15 @@ type Exception with os.AppendString(SeeAlsoE().Format(stringOfRange m1)) | ErrorFromAddingTypeEquation(g, denv, ty1, ty2, e, _) -> - let isActualTuple = isAnyTupleTy g ty2 + let typeEquation2E = + typeEquationMessage g ty2 ErrorFromAddingTypeEquation2E ErrorFromAddingTypeEquation2TupleE let e = if not (typeEquiv g ty1 ty2) then let ty1, ty2, tpcs = NicePrint.minimalStringsOfTwoTypes denv ty1 ty2 if ty1 <> ty2 + tpcs then - if isActualTuple then - os.AppendString(ErrorFromAddingTypeEquation2TupleE().Format ty1 ty2 tpcs) - else - os.AppendString(ErrorFromAddingTypeEquation2E().Format ty1 ty2 tpcs) + os.AppendString(typeEquation2E().Format ty1 ty2 tpcs) e From 0882c782331c6f8b5ad8008c6d9cb8be1e61cb54 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 25 Feb 2026 12:26:49 +0100 Subject: [PATCH 19/39] Flatten nested match in TcLinearExprs IfThenElse context selection Replace nested match-within-match on env.eContextInfo and synElseExprOpt with a single tuple match containing 5 flat arms. No behavioral change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 36ed8c00c5e..113b9b0fb8d 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -10802,16 +10802,13 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synExpr cont = let env = { env with eIsControlFlow = true } let thenExpr, tpenv = let env = - match env.eContextInfo with - | ContextInfo.ElseBranchResult _ when Option.isNone synElseExprOpt -> - { env with eContextInfo = ContextInfo.OmittedElseBranch m } - | ContextInfo.ElseBranchResult _ -> { env with eContextInfo = ContextInfo.ElseBranchResult synThenExpr.Range } - | _ -> - match synElseExprOpt with - | None -> { env with eContextInfo = ContextInfo.OmittedElseBranch synThenExpr.Range } - | Some elseExpr when elifChainMissingElse elseExpr -> - { env with eContextInfo = ContextInfo.OmittedElseBranch synThenExpr.Range } - | _ -> { env with eContextInfo = ContextInfo.IfExpression synThenExpr.Range } + match env.eContextInfo, synElseExprOpt with + | ContextInfo.ElseBranchResult _, None -> { env with eContextInfo = ContextInfo.OmittedElseBranch m } + | ContextInfo.ElseBranchResult _, _ -> { env with eContextInfo = ContextInfo.ElseBranchResult synThenExpr.Range } + | _, None -> { env with eContextInfo = ContextInfo.OmittedElseBranch synThenExpr.Range } + | _, Some elseExpr when elifChainMissingElse elseExpr -> + { env with eContextInfo = ContextInfo.OmittedElseBranch synThenExpr.Range } + | _ -> { env with eContextInfo = ContextInfo.IfExpression synThenExpr.Range } if not isRecovery && Option.isNone synElseExprOpt then UnifyTypes cenv env m g.unit_ty overallTy.Commit From ea316d88e4c72f9b57dc98609cd5d42df3b8005c Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 25 Feb 2026 12:55:32 +0100 Subject: [PATCH 20/39] Add test for isTyparTy fallback in NotAFunction handler Exercise the branch in CompilerDiagnostics.fs where the type of the value being applied is a type variable (isTyparTy), which falls back to the plain 'not a function' message without displaying the type. Uses a struct-constrained type parameter to prevent unification with a function type, ensuring the NotAFunction error is raised with the type still being a type variable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ErrorMessages/TypeMismatchTests.fs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs index 33195b1187c..e13cce92a95 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs @@ -411,6 +411,22 @@ let y = r 10 Col 10, "This value is not a function and cannot be applied. It has type 'MyRecord', which does not accept arguments.") + [] + let ``Generic value applied as function shows plain error`` () = + FSharp + """ +let f<'a when 'a : struct> (x: 'a) = x 10 + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic + (Error 3, + Line 2, + Col 38, + Line 2, + Col 39, + "This value is not a function and cannot be applied.") + [] let ``Tuple actual type says 'is a tuple of type'``() = FSharp """ From ebdc5f6ec18d81418bdb10f895fb65a6372eaad6 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 25 Feb 2026 13:28:30 +0100 Subject: [PATCH 21/39] Add positive tests for elif chain missing-else detection Add three new tests to verify elif chains compile cleanly: - Elif chain with final else (string return) - Unit-returning elif chain without else - Deep elif chain (4 branches) with final else Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ErrorMessages/MissingElseBranch.fs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/MissingElseBranch.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/MissingElseBranch.fs index 7a906b49946..72a0a19db68 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/MissingElseBranch.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/MissingElseBranch.fs @@ -71,3 +71,39 @@ let y = |> shouldFail |> withSingleDiagnostic (Error 1, Line 6, Col 4, Line 6, Col 26, "This 'if' expression is missing an 'else' branch. Because 'if' is an expression, and not a statement, add an 'else' branch which also returns a value of type 'string'.") + + [] + let ``Elif chain with final else compiles cleanly``() = + FSharp """ +let x = 10 +let y = + if x > 10 then "a" + elif x > 5 then "b" + else "c" + """ + |> typecheck + |> shouldSucceed + + [] + let ``Unit-returning elif chain without else compiles cleanly``() = + FSharp """ +let x = 10 +if x > 10 then printfn "a" +elif x > 5 then printfn "b" + """ + |> typecheck + |> shouldSucceed + + [] + let ``Deep elif chain with final else compiles cleanly``() = + FSharp """ +let x = 10 +let y = + if x > 10 then "a" + elif x > 8 then "b" + elif x > 5 then "c" + elif x > 2 then "d" + else "e" + """ + |> typecheck + |> shouldSucceed From 020e0588f5016743bf770b5462ddfc42cb4e3447 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 25 Feb 2026 13:54:16 +0100 Subject: [PATCH 22/39] Extract and test static parameter name truncation logic Extract formatAvailableNames helper from CrackStaticConstantArgs for diagnostic formatting of static parameter names truncated to 5 entries. Add 5 unit tests covering empty, single, fewer than 5, exactly 5, and more than 5 names. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 7 ++-- .../Checking/Expressions/CheckExpressions.fsi | 3 ++ .../StaticParameterFormattingTests.fs | 36 +++++++++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + 4 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 113b9b0fb8d..c18b8791593 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -4091,6 +4091,10 @@ type ImplicitlyBoundTyparsAllowed = | NewTyparsOK | NoNewTypars +/// Formats a list of names for display in diagnostics, truncating to at most 5 entries. +let formatAvailableNames (names: string array) = + names |> Array.truncate 5 |> String.concat ", " + //------------------------------------------------------------------------- // Checking types and type constraints //------------------------------------------------------------------------- @@ -4998,8 +5002,7 @@ and CrackStaticConstantArgs (cenv: cenv) env tpenv (staticParameters: Tainted Array.map (fun sp -> sp.PUntaint((fun sp -> sp.Name), n.idRange)) - |> Array.truncate 5 - |> String.concat ", " + |> formatAvailableNames error (Error(FSComp.SR.etNoStaticParameterWithName (n.idText, availableNames), n.idRange)) | [_] -> () diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fsi b/src/Compiler/Checking/Expressions/CheckExpressions.fsi index 9e3014896c8..d8905081763 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fsi +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fsi @@ -135,6 +135,9 @@ type ImplicitlyBoundTyparsAllowed = | NewTyparsOK | NoNewTypars +/// Formats a list of names for display in diagnostics, truncating to at most 5 entries. +val formatAvailableNames: names: string array -> string + //------------------------------------------------------------------------- // The rest are all helpers needed for declaration checking (CheckDeclarations.fs) //------------------------------------------------------------------------- diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs new file mode 100644 index 00000000000..e920d8db9e8 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs @@ -0,0 +1,36 @@ +namespace ErrorMessages + +open Xunit +open FSharp.Compiler.CheckExpressions + +module ``Static parameter formatting`` = + + [] + let ``formatAvailableNames truncates at 5`` () = + let names = [| "A"; "B"; "C"; "D"; "E"; "F"; "G" |] + let result = formatAvailableNames names + Assert.Equal("A, B, C, D, E", result) + + [] + let ``formatAvailableNames with fewer than 5`` () = + let names = [| "X"; "Y" |] + let result = formatAvailableNames names + Assert.Equal("X, Y", result) + + [] + let ``formatAvailableNames with exactly 5`` () = + let names = [| "A"; "B"; "C"; "D"; "E" |] + let result = formatAvailableNames names + Assert.Equal("A, B, C, D, E", result) + + [] + let ``formatAvailableNames with empty`` () = + let names = [||] + let result = formatAvailableNames names + Assert.Equal("", result) + + [] + let ``formatAvailableNames with single name`` () = + let names = [| "OnlyOne" |] + let result = formatAvailableNames names + Assert.Equal("OnlyOne", result) diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 6dbd4d9408a..dbcef643423 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -307,6 +307,7 @@ + From 0b7fd5e07732168ddc72700268549a5798980a94 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Wed, 25 Feb 2026 15:33:33 +0100 Subject: [PATCH 23/39] Add missing copyright header to StaticParameterFormattingTests.fs Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../ErrorMessages/StaticParameterFormattingTests.fs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs index e920d8db9e8..9961bd1b65c 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs @@ -1,3 +1,5 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + namespace ErrorMessages open Xunit From 9ff63e06c93bac487547db9df445eee1611caf46 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 26 Feb 2026 12:12:16 +0100 Subject: [PATCH 24/39] Address review council findings: quality and test improvements - Extract markForLoopMatchIncomplete helper to reduce nesting in TcForEachExpr - Add inline comments for NotAFunction vs NotAFunctionButIndexer type asymmetry - Add inline comments for OmittedElseBranch range choices in elif context - Add operator scope hint to csExpectTypeWithOperatorButGivenTuple for consistency - Make formatAvailableNames internal (val internal in .fsi) - Add cross-reference comments for sibling parser error-recovery rules - Add component tests for FS0597 (successive arguments) - Update neg60.bsl baseline for tuple operator hint Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 38 +++++++++++-------- .../Checking/Expressions/CheckExpressions.fsi | 2 +- src/Compiler/FSComp.txt | 2 +- src/Compiler/pars.fsy | 12 +++--- src/Compiler/xlf/FSComp.txt.cs.xlf | 4 +- src/Compiler/xlf/FSComp.txt.de.xlf | 4 +- src/Compiler/xlf/FSComp.txt.es.xlf | 4 +- src/Compiler/xlf/FSComp.txt.fr.xlf | 4 +- src/Compiler/xlf/FSComp.txt.it.xlf | 4 +- src/Compiler/xlf/FSComp.txt.ja.xlf | 4 +- src/Compiler/xlf/FSComp.txt.ko.xlf | 4 +- src/Compiler/xlf/FSComp.txt.pl.xlf | 4 +- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 4 +- src/Compiler/xlf/FSComp.txt.ru.xlf | 4 +- src/Compiler/xlf/FSComp.txt.tr.xlf | 4 +- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 4 +- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 4 +- .../ErrorMessages/SuccessiveArgTests.fs | 29 ++++++++++++++ .../FSharp.Compiler.ComponentTests.fsproj | 1 + tests/fsharp/typecheck/sigs/neg60.bsl | 4 +- 20 files changed, 88 insertions(+), 52 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuccessiveArgTests.fs diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index c18b8791593..f9243451bdd 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -8259,24 +8259,26 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s | _ -> false // Intercept MatchIncomplete diagnostics to mark them as originating from a for-loop binding, - // which adds a context-specific hint in the error message (e.g., "consider using a wildcard pattern"). + // which adds a context-specific hint in the error message (e.g., "Did you use a constant where a loop variable was expected?"). + let markForLoopMatchIncomplete (oldLogger: DiagnosticsLogger) = + { new DiagnosticsLogger("forLoopPatternMatch") with + member _.DiagnosticSink(diagnostic) = + let diagnostic = + match diagnostic.Exception with + | MatchIncomplete(isComp, cexOpt, m, _) -> + { diagnostic with + Exception = MatchIncomplete(isComp, cexOpt, m, (* isForLoopBinding: *) true) } + | _ -> diagnostic + + oldLogger.DiagnosticSink(diagnostic) + + member _.ErrorCount = oldLogger.ErrorCount + member _.CheckForRealErrorsIgnoringWarnings = oldLogger.CheckForRealErrorsIgnoringWarnings + } + use _diagnostics = if isConstantPattern then - UseTransformedDiagnosticsLogger(fun oldLogger -> - { new DiagnosticsLogger("forLoopPatternMatch") with - member _.DiagnosticSink(diagnostic) = - let diagnostic = - match diagnostic.Exception with - | MatchIncomplete(isComp, cexOpt, m, _) -> - { diagnostic with - Exception = MatchIncomplete(isComp, cexOpt, m, (* isForLoopBinding: *) true) } - | _ -> diagnostic - - oldLogger.DiagnosticSink(diagnostic) - - member _.ErrorCount = oldLogger.ErrorCount - member _.CheckForRealErrorsIgnoringWarnings = oldLogger.CheckForRealErrorsIgnoringWarnings - }) + UseTransformedDiagnosticsLogger(markForLoopMatchIncomplete) else { new System.IDisposable with member _.Dispose() = () @@ -8453,8 +8455,10 @@ and Propagate (cenv: cenv) (overallTy: OverallTy) (env: TcEnv) tpenv (expr: Appl else if IsIndexerType g cenv.amap expr.Type then let old = not (g.langVersion.SupportsFeature LanguageFeature.IndexerNotationWithoutDot) + // NotAFunctionButIndexer uses overallTy (expected type) for the indexer suggestion message. error (NotAFunctionButIndexer(denv, overallTy.Commit, vName, mExpr, mArg, old)) else + // NotAFunction uses exprTy (actual type) to show "has type X, which does not accept arguments". error (NotAFunction(denv, exprTy, mExpr, mArg)) // f x (where 'f' is not a function) @@ -10806,8 +10810,10 @@ and TcLinearExprs bodyChecker cenv env overallTy tpenv isCompExpr synExpr cont = let thenExpr, tpenv = let env = match env.eContextInfo, synElseExprOpt with + // Inside an elif chain with no final else: use full elif range (m) so the error points at the whole elif. | ContextInfo.ElseBranchResult _, None -> { env with eContextInfo = ContextInfo.OmittedElseBranch m } | ContextInfo.ElseBranchResult _, _ -> { env with eContextInfo = ContextInfo.ElseBranchResult synThenExpr.Range } + // Top-level if with no else: use then-branch range. | _, None -> { env with eContextInfo = ContextInfo.OmittedElseBranch synThenExpr.Range } | _, Some elseExpr when elifChainMissingElse elseExpr -> { env with eContextInfo = ContextInfo.OmittedElseBranch synThenExpr.Range } diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fsi b/src/Compiler/Checking/Expressions/CheckExpressions.fsi index d8905081763..d8f801c7c5c 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fsi +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fsi @@ -136,7 +136,7 @@ type ImplicitlyBoundTyparsAllowed = | NoNewTypars /// Formats a list of names for display in diagnostics, truncating to at most 5 entries. -val formatAvailableNames: names: string array -> string +val internal formatAvailableNames: names: string array -> string //------------------------------------------------------------------------- // The rest are all helpers needed for declaration checking (CheckDeclarations.fs) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 5a9d0d8140f..c451fceaf87 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -311,7 +311,7 @@ csTypeCannotBeResolvedAtCompileTime,"The declared type parameter '%s' cannot be csExpectedArguments,"Expected arguments to an instance member" csIndexArgumentMismatch,"This indexer expects %d arguments but is here given %d" csExpectTypeWithOperatorButGivenFunction,"Expecting a type supporting the operator '%s' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace." -csExpectTypeWithOperatorButGivenTuple,"Expecting a type supporting the operator '%s' but given a tuple type" +csExpectTypeWithOperatorButGivenTuple,"Expecting a type supporting the operator '%s' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace." 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'" diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 5d6708131b8..d2d51f454b2 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -4566,12 +4566,12 @@ declExpr: mkLetBangExpression(mIn, m, $8, (pat, returnInfo, $4, $7, keyword, mEquals, isUse)) } + // NOTE: The two OBINDER error-recovery rules below are siblings that must be kept in sync. + // They differ only in: (1) presence of moreBinders ($7 vs []), (2) rhs parseState offset (7 vs 8). | OBINDER ceBindingCore EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP error %prec expr_let - { // Error recovery for incomplete let!/use! bindings - // Allows intellisense to work when writing incomplete computation expressions + { // Error recovery for incomplete let!/use! bindings (without and! clauses) let pat, mPat, isInline, isMutable, returnInfo = $2 - // Error checking for invalid modifiers if isInline then errorR(Error(FSComp.SR.parsInvalidDeclarationSyntax(), rhs parseState 2)) if isMutable then errorR(Error(FSComp.SR.parsInvalidDeclarationSyntax(), rhs parseState 2)) @@ -4581,16 +4581,16 @@ declExpr: let keyword = if $1 = "let" then SynLeadingKeyword.LetBang mKeyword else SynLeadingKeyword.UseBang mKeyword let mEquals = Some(rhs parseState 3) let mAll = unionRanges mKeyword (rhs parseState 7) - let m = $4.Range.EndRange // zero-width range + let m = $4.Range.EndRange let _, mIn, _ = $5 let isUse = ($1 = "use") - // Use ImplicitZero as the continuation expression for error recovery mkLetBangExpression(mIn, mAll, SynExpr.ImplicitZero m, (pat, returnInfo, $4, [], keyword, mEquals, isUse)) } + // NOTE: Sibling of the rule above — keep in sync. Handles the case with and! (moreBinders) clauses. | OBINDER ceBindingCore EQUALS typedSequentialExprBlock hardwhiteDefnBindingsTerminator opt_OBLOCKSEP moreBinders error %prec expr_let - { // Error recovery for let!/use! as the final expression in a computation expression + { // Error recovery for incomplete let!/use! bindings (with and! clauses) let pat, mPat, isInline, isMutable, returnInfo = $2 if isInline then errorR(Error(FSComp.SR.parsInvalidDeclarationSyntax(), rhs parseState 2)) diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 8fdd1e50583..5232d9ae106 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - Očekává se typ podporující operátor {0}, ale předává se typ řazené kolekce členů. + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Očekává se typ podporující operátor {0}, ale předává se typ řazené kolekce členů. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index d1a027738c1..bb13af38bbb 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - Ein unterstützender Typ für den Operator '{0}' wurde erwartet, aber ein Tupeltyp wurde empfangen + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Ein unterstützender Typ für den Operator '{0}' wurde erwartet, aber ein Tupeltyp wurde empfangen diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 4205eaf6bc9..991e8de81ef 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - Se espera un tipo que admita el operador '{0}', pero se ha proporcionado un tipo de tupla. + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Se espera un tipo que admita el operador '{0}', pero se ha proporcionado un tipo de tupla. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 6efba8b40cb..3da655c6ac8 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - Un type prenant en charge l'opérateur '{0}' est attendu, mais un type tuple a été reçu + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Un type prenant en charge l'opérateur '{0}' est attendu, mais un type tuple a été reçu diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 54ba8a01c42..b62fc22c123 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - È previsto un tipo che supporti l'operatore '{0}', tuttavia è specificato un tipo di tuple + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + È previsto un tipo che supporti l'operatore '{0}', tuttavia è specificato un tipo di tuple diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 204ab0110df..a43d7bab47e 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - 演算子 '{0}' をサポートする型が必要ですが、タプル型が指定されました + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + 演算子 '{0}' をサポートする型が必要ですが、タプル型が指定されました diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 6ef1fa76bfe..00fde3d8ca7 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - '{0}' 연산자를 지원하는 형식이 필요한데 튜플 형식을 지정했습니다. + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + '{0}' 연산자를 지원하는 형식이 필요한데 튜플 형식을 지정했습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 21d3adcb606..0a2adaff95a 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - Oczekiwany jest typ obsługujący operator „{0}”, ale podano typ krotki + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Oczekiwany jest typ obsługujący operator „{0}”, ale podano typ krotki diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index b5dd43d8560..57b7affdfbf 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - Um tipo que suporte o operador '{0}' era esperado, mas um tipo de tupla foi recebido. + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Um tipo que suporte o operador '{0}' era esperado, mas um tipo de tupla foi recebido. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 59b868a4fbb..06b9c05fe8b 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - Ожидался тип, поддерживающий оператор "{0}", однако указан кортежный тип + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Ожидался тип, поддерживающий оператор "{0}", однако указан кортежный тип diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 64d62b4b37d..7b75e214154 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - '{0}' işlecini destekleyen bir tür bekleniyor ancak bir demet türü verildi. + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + '{0}' işlecini destekleyen bir tür bekleniyor ancak bir demet türü verildi. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index ced5ab31ee7..b6e61a8f312 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - 需要一个支持运算符“{0}”的类型,但提供的是元组类型 + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + 需要一个支持运算符“{0}”的类型,但提供的是元组类型 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index cc21f520588..8abb909edcd 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -3348,8 +3348,8 @@ - Expecting a type supporting the operator '{0}' but given a tuple type - 必須是支援運算子 '{0}' 的型別,但指定的是元組型別 + Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + 必須是支援運算子 '{0}' 的型別,但指定的是元組型別 diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuccessiveArgTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuccessiveArgTests.fs new file mode 100644 index 00000000000..0251eedcee2 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuccessiveArgTests.fs @@ -0,0 +1,29 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace ErrorMessages + +open Xunit +open FSharp.Test.Compiler + +module ``Successive arguments`` = + + [] + let ``Method call as argument needs parentheses``() = + FSharp """ +let f x y = x + y +let g() = 1 +let r = f g() 2 + """ + |> typecheck + |> shouldFail + |> withErrorCode 597 + + [] + let ``Constructor call as argument needs parentheses``() = + FSharp """ +let f (x: obj) (y: int) = x +let r = f System.Object() 2 + """ + |> typecheck + |> shouldFail + |> withErrorCode 597 diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index dbcef643423..6d06ebb2335 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -307,6 +307,7 @@ + diff --git a/tests/fsharp/typecheck/sigs/neg60.bsl b/tests/fsharp/typecheck/sigs/neg60.bsl index 06ee5dbc874..3e6786b96e7 100644 --- a/tests/fsharp/typecheck/sigs/neg60.bsl +++ b/tests/fsharp/typecheck/sigs/neg60.bsl @@ -16,9 +16,9 @@ neg60.fs(79,18,79,21): typecheck error FS0001: The type ''a * 'b' does not match neg60.fs(79,15,79,16): typecheck error FS0043: The type ''a * 'b' does not match the type 'int' -neg60.fs(80,22,80,25): typecheck error FS0001: Expecting a type supporting the operator '+' but given a tuple type +neg60.fs(80,22,80,25): typecheck error FS0001: Expecting a type supporting the operator '+' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. -neg60.fs(80,19,80,20): typecheck error FS0043: Expecting a type supporting the operator '+' but given a tuple type +neg60.fs(80,19,80,20): typecheck error FS0043: Expecting a type supporting the operator '+' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. neg60.fs(81,22,81,34): typecheck error FS0002: This function takes too many arguments, or is used in a context where a function is not expected From a9e6b468eebdd07c9196d6088902329ebb36c72a Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 26 Feb 2026 15:12:55 +0100 Subject: [PATCH 25/39] Add release notes for diagnostic message improvements and MatchIncomplete API change Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/10.0.300.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md index 42b0b781a2f..7fff6f6ed15 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md @@ -32,6 +32,6 @@ * Centralized product TFM (Target Framework Moniker) into MSBuild props file `eng/TargetFrameworks.props`. Changing the target framework now only requires editing one file, and it integrates with MSBuild's `--getProperty` for scripts. * Overload resolution results are now cached, providing compile time improvements for code with repeated method calls. ([Issue #18807](https://github.com/dotnet/fsharp/issues/18807)) * Symbols: safer qualified name getting ([PR #19298](https://github.com/dotnet/fsharp/pull/19298)) - +* Improved diagnostic messages for FS0003, FS0025, FS0039, FS0072, FS0247, FS0597, FS0670, FS3082, and type mismatch errors involving tuples. Added new warnings FS3882 (let!/use! at end of computation expression) and FS3883 (comma vs semicolon confusion in list literals). Added elif-chain detection for missing else branch errors, context-aware hints for incomplete matches in for-loops, and operator scope hints for SRTP errors. ### Breaking Changes From d79918fee5296d5e92f4974b5c1e620908488552 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 26 Feb 2026 17:10:25 +0100 Subject: [PATCH 26/39] Address review council: ellipsis on truncation, info-level W3883, thread isForLoopBinding - formatAvailableNames: append '...' when list is truncated beyond 5 - Warning 3883 (comma vs semicolon in lists): downgrade from warning to informationalWarning to reduce false positive impact - Remove diagnostic interception pattern (markForLoopMatchIncomplete): thread isForLoopBinding through CompilePattern call chain instead of post-hoc exception rewriting via DiagnosticsLogger wrapper Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 36 ++++--------------- .../Expressions/CheckExpressionsOps.fs | 4 +++ .../Checking/PatternMatchCompilation.fs | 15 ++++---- .../Checking/PatternMatchCompilation.fsi | 2 ++ 4 files changed, 20 insertions(+), 37 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index f9243451bdd..24b0452956f 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -4093,7 +4093,9 @@ type ImplicitlyBoundTyparsAllowed = /// Formats a list of names for display in diagnostics, truncating to at most 5 entries. let formatAvailableNames (names: string array) = - names |> Array.truncate 5 |> String.concat ", " + let truncated = names |> Array.truncate 5 + let result = truncated |> String.concat ", " + if names.Length > 5 then result + ", ..." else result //------------------------------------------------------------------------- // Checking types and type constraints @@ -6262,7 +6264,7 @@ and TcExprArrayOrList (cenv: cenv) overallTy env tpenv (isArray, args, m) = match isArray, args with | false, [ SynExpr.Tuple(false, _, _, _) ] -> - warning (Error(FSComp.SR.tcListLiteralWithSingleTupleElement (), m)) + informationalWarning (Error(FSComp.SR.tcListLiteralWithSingleTupleElement (), m)) | _ -> () CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.AccessRights) @@ -8258,34 +8260,8 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s | SynPat.Paren(SynPat.Const _, _) -> true | _ -> false - // Intercept MatchIncomplete diagnostics to mark them as originating from a for-loop binding, - // which adds a context-specific hint in the error message (e.g., "Did you use a constant where a loop variable was expected?"). - let markForLoopMatchIncomplete (oldLogger: DiagnosticsLogger) = - { new DiagnosticsLogger("forLoopPatternMatch") with - member _.DiagnosticSink(diagnostic) = - let diagnostic = - match diagnostic.Exception with - | MatchIncomplete(isComp, cexOpt, m, _) -> - { diagnostic with - Exception = MatchIncomplete(isComp, cexOpt, m, (* isForLoopBinding: *) true) } - | _ -> diagnostic - - oldLogger.DiagnosticSink(diagnostic) - - member _.ErrorCount = oldLogger.ErrorCount - member _.CheckForRealErrorsIgnoringWarnings = oldLogger.CheckForRealErrorsIgnoringWarnings - } - - use _diagnostics = - if isConstantPattern then - UseTransformedDiagnosticsLogger(markForLoopMatchIncomplete) - else - { new System.IDisposable with - member _.Dispose() = () - } - CompilePatternForMatch - cenv env synEnumExpr.Range pat.Range false IgnoreWithWarning (elemVar, [], None) + cenv env synEnumExpr.Range pat.Range false IgnoreWithWarning isConstantPattern (elemVar, [], None) [MatchClause(pat, None, TTarget(valsDefinedByMatching, bodyExpr, None), mIn)] enumElemTy overallTy.Commit @@ -11827,7 +11803,7 @@ and TcLetBinding (cenv: cenv) isUse env containerInfo declKind tpenv (synBinds, let mkPatBind (bodyExpr, bodyExprTy) = let valsDefinedByMatching = ListSet.remove valEq patternInputTmp allValsDefinedByPattern let clauses = [MatchClause(checkedPat2, None, TTarget(valsDefinedByMatching, bodyExpr, None), m)] - let matchExpr = CompilePatternForMatch cenv env m m true ThrowIncompleteMatchException (patternInputTmp, generalizedTypars, Some rhsExpr) clauses tauTy bodyExprTy + let matchExpr = CompilePatternForMatch cenv env m m true ThrowIncompleteMatchException false (patternInputTmp, generalizedTypars, Some rhsExpr) clauses tauTy bodyExprTy let matchExpr = if declKind.IsConvertToLinearBindings then diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index 0fe8e296b81..15181f0dde3 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -78,6 +78,7 @@ let CompilePatternForMatch mMatch warnOnUnused actionOnFailure + isForLoopBinding (inputVal, generalizedTypars, inputExprOpt) clauses inputTy @@ -96,6 +97,7 @@ let CompilePatternForMatch mMatch warnOnUnused actionOnFailure + isForLoopBinding (inputVal, generalizedTypars, inputExprOpt) clauses inputTy @@ -119,6 +121,7 @@ let CompilePatternForMatchClauses (cenv: TcFileState) env mExpr mMatch warnOnUnu mMatch warnOnUnused actionOnFailure + false (asVal, generalizedTypars, None) [ MatchClause(pat1, None, TTarget(vs2, targetExpr, None), m2) ] inputTy @@ -136,6 +139,7 @@ let CompilePatternForMatchClauses (cenv: TcFileState) env mExpr mMatch warnOnUnu mMatch warnOnUnused actionOnFailure + false (matchValueTmp, [], inputExprOpt) tclauses inputTy diff --git a/src/Compiler/Checking/PatternMatchCompilation.fs b/src/Compiler/Checking/PatternMatchCompilation.fs index e9639c3311c..851afec8ecf 100644 --- a/src/Compiler/Checking/PatternMatchCompilation.fs +++ b/src/Compiler/Checking/PatternMatchCompilation.fs @@ -991,6 +991,7 @@ let CompilePatternBasic warnOnUnused warnOnIncomplete actionOnFailure + isForLoopBinding (origInputVal, origInputValTypars, _origInputExprOpt: Expr option) (clauses: MatchClause list) inputTy @@ -1018,10 +1019,10 @@ let CompilePatternBasic warning (EnumMatchIncomplete(ignoreWithWarning, Some(text, failingWhenClause), mMatch)) warningsGenerated.Add CounterExampleType.EnumCoversKnown | Some(text, failingWhenClause, CounterExampleType.WithoutEnum) when not(warningsGenerated.Contains(CounterExampleType.WithoutEnum)) -> - warning (MatchIncomplete(ignoreWithWarning, Some(text, failingWhenClause), mMatch, false)) + warning (MatchIncomplete(ignoreWithWarning, Some(text, failingWhenClause), mMatch, isForLoopBinding)) warningsGenerated.Add CounterExampleType.WithoutEnum | None when not(warningsGenerated.Contains(CounterExampleType.WithoutEnum)) -> - warning (MatchIncomplete(ignoreWithWarning, None, mMatch, false)) + warning (MatchIncomplete(ignoreWithWarning, None, mMatch, isForLoopBinding)) warningsGenerated.Add CounterExampleType.WithoutEnum | _ -> () | _ -> @@ -1708,7 +1709,7 @@ let isProblematicClause (clause: MatchClause) = let ips = investigationPoints clause.Pattern ips.Length > 0 && Span.exists id (ips.AsSpan (0, ips.Length - 1)) -let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) (clausesL: MatchClause list) inputTy resultTy = +let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) (clausesL: MatchClause list) inputTy resultTy = match clausesL with | _ when List.exists isProblematicClause clausesL -> @@ -1716,7 +1717,7 @@ let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused a let warnOnUnused = false // we can't turn this on since we're pretending all partials fail in order to control the complexity of this. let warnOnIncomplete = true let clausesPretendAllPartialFail = clausesL |> List.collect (fun (MatchClause(p, whenOpt, tg, m)) -> [MatchClause(erasePartialPatterns p, whenOpt, tg, m)]) - let _ = CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) clausesPretendAllPartialFail inputTy resultTy + let _ = CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) clausesPretendAllPartialFail inputTy resultTy let warnOnIncomplete = false // Partial and when clauses cause major code explosion if treated naively @@ -1724,7 +1725,7 @@ let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused a let rec atMostOneProblematicClauseAtATime clauses = match List.takeUntil isProblematicClause clauses with | l, [] -> - CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) l inputTy resultTy + CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) l inputTy resultTy | l, h :: t -> // Add the problematic clause. doGroupWithAtMostOneProblematic (l @ [h]) t @@ -1739,10 +1740,10 @@ let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused a // Make the clause that represents the remaining cases of the pattern match let clauseForRestOfMatch = MatchClause(TPat_wild mMatch, None, TTarget(List.empty, expr, None), mMatch) - CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) (group @ [clauseForRestOfMatch]) inputTy resultTy + CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) (group @ [clauseForRestOfMatch]) inputTy resultTy atMostOneProblematicClauseAtATime clausesL | _ -> - CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused true actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) clausesL inputTy resultTy + CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused true actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) clausesL inputTy resultTy diff --git a/src/Compiler/Checking/PatternMatchCompilation.fsi b/src/Compiler/Checking/PatternMatchCompilation.fsi index 8dbf3fd1adb..7fdd3029323 100644 --- a/src/Compiler/Checking/PatternMatchCompilation.fsi +++ b/src/Compiler/Checking/PatternMatchCompilation.fsi @@ -62,6 +62,8 @@ val internal CompilePattern: // warn on unused? bool -> ActionOnFailure -> + // is this a for-loop binding pattern? + bool -> Val * Typars * Expr option -> // input type-checked syntax of pattern matching MatchClause list -> From 54ffd94170c967b9e3ab9dfbfac271e74d0416c3 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 27 Feb 2026 14:58:19 +0100 Subject: [PATCH 27/39] Fix review findings: test assertions, trailing newline, tuple alias test - FS3883 tests: Warning -> Information (intentionally info-level) - formatAvailableNames test: update expected value to include ellipsis - FSComp.txt: add trailing newline - Add negative test: type alias for tuple still says 'is a tuple of type' Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/FSComp.txt | 2 +- .../ErrorMessages/CommaSemicolonListTests.fs | 4 ++-- .../ErrorMessages/StaticParameterFormattingTests.fs | 2 +- .../ErrorMessages/TypeMismatchTests.fs | 11 +++++++++++ 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index c451fceaf87..16e45eacdc2 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1809,4 +1809,4 @@ featureImplicitDIMCoverage,"Implicit dispatch slot coverage for default interfac 3880,optsLangVersionOutOfSupport,"Language version '%s' is out of support. The last .NET SDK supporting it is available at https://dotnet.microsoft.com/en-us/download/dotnet/%s" 3881,optsUnrecognizedLanguageFeature,"Unrecognized language feature name: '%s'. Use a valid feature name such as 'NameOf' or 'StringInterpolation'." 3882,parsLetBangCannotBeLastInCE,"'%s' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression." -3883,tcListLiteralWithSingleTupleElement,"This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?" \ No newline at end of file +3883,tcListLiteralWithSingleTupleElement,"This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?" diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs index fbced051094..e1d625524d2 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs @@ -14,7 +14,7 @@ let x = [1, 2, 3] """ |> typecheck |> shouldFail - |> withSingleDiagnostic (Warning 3883, Line 2, Col 9, Line 2, Col 18, + |> withSingleDiagnostic (Information 3883, Line 2, Col 9, Line 2, Col 18, "This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?") [] @@ -60,7 +60,7 @@ let x = [1, 2] """ |> typecheck |> shouldFail - |> withSingleDiagnostic (Warning 3883, Line 2, Col 9, Line 2, Col 15, + |> withSingleDiagnostic (Information 3883, Line 2, Col 9, Line 2, Col 15, "This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?") [] diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs index 9961bd1b65c..80377680c8e 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/StaticParameterFormattingTests.fs @@ -11,7 +11,7 @@ module ``Static parameter formatting`` = let ``formatAvailableNames truncates at 5`` () = let names = [| "A"; "B"; "C"; "D"; "E"; "F"; "G" |] let result = formatAvailableNames names - Assert.Equal("A, B, C, D, E", result) + Assert.Equal("A, B, C, D, E, ...", result) [] let ``formatAvailableNames with fewer than 5`` () = diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs index e13cce92a95..2569b3867c6 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs @@ -461,3 +461,14 @@ let f (x: int) : string = x |> withSingleDiagnostic (Error 1, Line 2, Col 27, Line 2, Col 28, "This expression was expected to have type\n 'string' \nbut here has type\n 'int' ") + [] + let ``Type alias for tuple still says 'is a tuple of type'``() = + FSharp """ +type Pair = int * int +let f (x: Pair) : string = x + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 1, Line 3, Col 28, Line 3, Col 29, + "This expression was expected to have type\n 'string' \nbut is a tuple of type\n 'Pair' ") + From 3445a5da8b18cebdd3d934e8adba82b32af8ddb6 Mon Sep 17 00:00:00 2001 From: test Date: Fri, 27 Feb 2026 17:09:56 +0100 Subject: [PATCH 28/39] Fix dead code --- src/Compiler/Checking/Expressions/CheckExpressions.fs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 24b0452956f..9aadf32706e 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -6020,7 +6020,13 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE CallExprHasTypeSink cenv.tcSink (m, env.NameEnv, overallTy.Commit, env.eAccessRights) cenv.TcArrayOrListComputedExpression cenv env overallTy tpenv (isArray, comp) m - | SynExpr.LetOrUse _ -> + | SynExpr.LetOrUse letOrUse -> + match letOrUse with + | { Bindings = SynBinding(trivia = { LeadingKeyword = leadingKeyword }) :: _ } + when letOrUse.IsBang -> + errorR(Error(FSComp.SR.tcConstructRequiresComputationExpression(), leadingKeyword.Range)) + | _ -> () + TcLinearExprs (TcExprThatCanBeCtorBody cenv) cenv env overallTy tpenv false synExpr id | SynExpr.TryWith (synBodyExpr, synWithClauses, mTryToLast, spTry, spWith, trivia) -> @@ -6128,8 +6134,6 @@ and TcExprUndelayed (cenv: cenv) (overallTy: OverallTy) env tpenv (synExpr: SynE | SynExpr.MatchBang (trivia = { MatchBangKeyword = m }) | SynExpr.WhileBang (range = m) -> error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), m)) - | LetOrUse({ Bindings = [ SynBinding(trivia = { LeadingKeyword = leadingKeyword }) ]}, true, _) -> - error(Error(FSComp.SR.tcConstructRequiresComputationExpression(), leadingKeyword.Range)) | SynExpr.IndexFromEnd (rightExpr, m) -> errorR(Error(FSComp.SR.tcTraitInvocationShouldUseTick(), m)) @@ -9323,7 +9327,6 @@ and TcImplicitOpItemThen (cenv: cenv) overallTy env id sln tpenv mItem delayed = | SynExpr.YieldOrReturn _ | SynExpr.YieldOrReturnFrom _ | SynExpr.MatchBang _ - | LetOrUse(_, true, _) | SynExpr.DoBang _ | SynExpr.WhileBang _ | SynExpr.TraitCall _ From 4289f45c1a65dfb96925629f3e0270a764c8b647 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 27 Feb 2026 20:17:06 +0100 Subject: [PATCH 29/39] Address review council: iterative elif walk, typed constant patterns, test coverage - Convert elifChainMissingElse from recursive to iterative while-loop to avoid theoretical stack overflow on deep elif chains - Expand isConstantPattern to handle SynPat.Typed(SynPat.Const) and SynPat.Paren(SynPat.Typed(SynPat.Const)) for typed for-loop constants - Add SRTP tuple operator scope hint test (csExpectTypeWithOperatorButGivenTuple) - Add struct tuple type mismatch test verifying 'is a tuple of type' phrasing Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 23 ++++++++++++++----- .../ErrorMessages/OperatorTests.fs | 10 ++++++++ .../ErrorMessages/TypeMismatchTests.fs | 9 ++++++++ .../Language/ComputationExpressionTests.fs | 14 +++++++++++ 4 files changed, 50 insertions(+), 6 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 9aadf32706e..d6e74adeada 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -8261,7 +8261,9 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s let isConstantPattern = match synPat with | SynPat.Const _ - | SynPat.Paren(SynPat.Const _, _) -> true + | SynPat.Paren(SynPat.Const _, _) + | SynPat.Typed(SynPat.Const _, _, _) + | SynPat.Paren(SynPat.Typed(SynPat.Const _, _, _), _) -> true | _ -> false CompilePatternForMatch @@ -10736,11 +10738,20 @@ and CheckRecursiveBindingIds binds = error(Duplicate("value", nm, m)) /// Returns true if the expression is an elif chain that ends without a final 'else' branch. -and elifChainMissingElse = - function - | SynExpr.IfThenElse(elseExpr = None) -> true - | SynExpr.IfThenElse(elseExpr = Some elseExpr) -> elifChainMissingElse elseExpr - | _ -> false +and elifChainMissingElse expr = + let mutable current = expr + let mutable cont = true + let mutable result = false + + while cont do + match current with + | SynExpr.IfThenElse(elseExpr = None) -> + result <- true + cont <- false + | SynExpr.IfThenElse(elseExpr = Some elseExpr) -> current <- elseExpr + | _ -> cont <- false + + result /// Process a sequence of sequentials mixed with iterated lets "let ... in let ... in ..." in a tail recursive way /// This avoids stack overflow on really large "let" and "letrec" lists diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs index 9c44888a222..b02cf16307d 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs @@ -17,3 +17,13 @@ let result = add id id |> shouldFail |> withSingleDiagnostic (Error 1, Line 3, Col 18, Line 3, Col 20, "Expecting a type supporting the operator '+' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace.") + + [] + let ``SRTP operator scope hint is shown when tuple type given``() = + FSharp """ +let inline add (x: ^a) (y: ^a) = x + y +let result = add (1, 2) (3, 4) + """ + |> typecheck + |> shouldFail + |> withDiagnosticMessageMatches "Expecting a type supporting the operator '\+' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope." diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs index 2569b3867c6..337a49d5352 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/TypeMismatchTests.fs @@ -472,3 +472,12 @@ let f (x: Pair) : string = x |> withSingleDiagnostic (Error 1, Line 3, Col 28, Line 3, Col 29, "This expression was expected to have type\n 'string' \nbut is a tuple of type\n 'Pair' ") + [] + let ``Struct tuple actual type says 'is a tuple of type'``() = + FSharp """ +let f () : string = struct(1, 2) + """ + |> typecheck + |> shouldFail + |> withDiagnosticMessageMatches "but is a tuple of type" + diff --git a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs index 1b3a1b7ad5c..f68ab2b4825 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs @@ -2382,3 +2382,17 @@ let foo() = (Error 10, Line 17, Col 5, Line 17, Col 6, "Unexpected symbol '}' in expression") (Error 3882, Line 15, Col 9, Line 15, Col 13, "'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") ] + + [] + let ``match! at end of computation expression is allowed``() = + FSharp """ +module ComputationExpressionTests +let foo() = + async { + match! async { return 0 } with + | 0 -> return 1 + | _ -> return 2 + } + """ + |> typecheck + |> shouldSucceed From 95cf5bbf5379a017a9a6bcd0b969d715fc62b295 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Sat, 28 Feb 2026 12:03:50 +0100 Subject: [PATCH 30/39] Improve diagnostic wording: tuple operator hint, FS0670 inline advice, restore constructor in FS0039 - csExpectTypeWithOperatorButGivenTuple: Replace copy-pasted 'missing argument to a function' hint with tuple-specific guidance about unintended commas creating tuples - FS0670: Broaden 'Consider adding inline' to also suggest type annotations and converting values to functions (inline is wrong for value restriction and mutable capture cases) - FS0039: Restore 'constructor' in the message so DU case typos like Shape.Circl hint that union cases exist Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/FSComp.txt | 6 +++--- src/Compiler/xlf/FSComp.txt.cs.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.de.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.es.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.fr.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.it.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.ja.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.ko.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.pl.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.ru.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.tr.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 6 +++--- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 6 +++--- .../CompilerService/FSharpWorkspace.fs | 2 +- .../MethodsAndProperties/E_ActivePatternMember01.fs | 2 +- .../MethodsAndProperties/MethodsAndProperties.fs | 4 ++-- .../OptionalArguments/OptionalArguments.fs | 4 ++-- .../ObjectConstruction/E_ObjectConstruction01.fs | 2 +- .../E_InvalidSelfReferentialStructConstructor.fs | 2 +- .../Expressions/SyntacticSugar/E_GetSliceNotDef01.fs | 2 +- .../Expressions/SyntacticSugar/SyntacticSugar.fs | 4 ++-- .../Conformance/LexicalAnalysis/SymbolicOperators.fs | 2 +- .../EnumTypes/E_NoValueFieldOnEnum.fs | 2 +- .../InterfaceTypes/E_MultipleInterfaceInheritance.fs | 6 +++--- .../Conformance/Signatures/Signatures.fs | 2 +- .../ErrorMessages/NameResolutionTests.fs | 4 ++-- .../ErrorMessages/OperatorTests.fs | 2 +- .../ErrorMessages/SuggestionsTests.fs | 12 ++++++------ .../Import/ImportTests.fs | 2 +- .../Interop/DeeplyNestedCSharpClasses.fs | 6 +++--- .../Language/ComputationExpressionTests.fs | 2 +- .../Language/DiscriminatedUnionTests.fs | 6 +++--- .../E_StructWithNameConflict02.fsi | 2 +- .../Compiler/Language/CustomCollectionTests.fs | 4 ++-- .../Compiler/Language/DefaultInterfaceMemberTests.fs | 6 +++--- .../expressions/syntacticsugar/E_Slices01.bsl | 2 +- ...TypeWithIncorrectNameFromApplyStaticArguments.bsl | 2 +- tests/fsharp/typecheck/sigs/neg04.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg06.bsl | 2 +- tests/fsharp/typecheck/sigs/neg08.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg101.bsl | 2 +- tests/fsharp/typecheck/sigs/neg17.bsl | 8 ++++---- tests/fsharp/typecheck/sigs/neg20.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg37.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg45.bsl | 2 +- tests/fsharp/typecheck/sigs/neg55.bsl | 2 +- tests/fsharp/typecheck/sigs/neg60.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg62.bsl | 2 +- tests/fsharp/typecheck/sigs/neg92.bsl | 2 +- 50 files changed, 104 insertions(+), 104 deletions(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 16e45eacdc2..5858d67c311 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -5,7 +5,7 @@ undefinedNameNamespace,"The namespace '%s' is not defined." undefinedNameNamespaceOrModule,"The namespace or module '%s' is not defined." undefinedNameFieldConstructorOrMember,"The field, constructor or member '%s' is not defined." -undefinedNameFieldConstructorOrMemberWhenTypeIsKnown,"The type '%s' does not have a field, property, or member named '%s'." +undefinedNameFieldConstructorOrMemberWhenTypeIsKnown,"The type '%s' does not define a field, constructor, or member named '%s'." undefinedNameValueConstructorNamespaceOrType,"The value, constructor, namespace or type '%s' is not defined." undefinedNameValueOfConstructor,"The value or constructor '%s' is not defined." undefinedNameValueNamespaceTypeOrModule,"The value, namespace, type or module '%s' is not defined." @@ -311,7 +311,7 @@ csTypeCannotBeResolvedAtCompileTime,"The declared type parameter '%s' cannot be csExpectedArguments,"Expected arguments to an instance member" csIndexArgumentMismatch,"This indexer expects %d arguments but is here given %d" csExpectTypeWithOperatorButGivenFunction,"Expecting a type supporting the operator '%s' but given a function type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace." -csExpectTypeWithOperatorButGivenTuple,"Expecting a type supporting the operator '%s' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace." +csExpectTypeWithOperatorButGivenTuple,"Operator '%s' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace." 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'" @@ -524,7 +524,7 @@ tcExpectModuleOrNamespaceParent,"Expected module or namespace parent %s" 667,tcFieldsDoNotDetermineUniqueRecordType,"The field labels and expected type of this record expression or pattern do not uniquely determine a corresponding record type" 668,tcMultipleFieldsInRecord,"The field '%s' appears multiple times in this record expression or pattern" 669,tcUnknownUnion,"Unknown union case" -670,tcNotSufficientlyGenericBecauseOfScope,"This code is not sufficiently generic. The type variable %s could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition." +670,tcNotSufficientlyGenericBecauseOfScope,"This code is not sufficiently generic. The type variable %s could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'." 671,tcPropertyRequiresExplicitTypeParameters,"A property cannot have explicit type parameters. Consider using a method instead." 672,tcConstructorCannotHaveTypeParameters,"A constructor cannot have explicit type parameters. Consider using a static construction method instead." 673,tcInstanceMemberRequiresTarget,"This instance member needs a parameter to represent the object being invoked. Make the member static or use the notation 'member x.Member(args) = ...'." diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 5232d9ae106..abcc454281f 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. Očekává se typ podporující operátor {0}, ale předává se typ řazené kolekce členů. @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. Tento kód není dostatečně obecný. Proměnná typu {0} se nedá zobecnit, protože by se tak dostala mimo svůj definiční obor. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index bb13af38bbb..e786319ba02 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. Ein unterstützender Typ für den Operator '{0}' wurde erwartet, aber ein Tupeltyp wurde empfangen @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. Dieser Code ist nicht generisch genug. Die Typvariable "{0}" konnte nicht generalisiert werden, weil sie sonst aus dem Bereich fallen würde. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 991e8de81ef..2d47dc1aea0 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. Se espera un tipo que admita el operador '{0}', pero se ha proporcionado un tipo de tupla. @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. Este código no es lo suficientemente genérico. La variable de tipo {0} no se pudo generalizar porque escaparía de su ámbito. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 3da655c6ac8..97c32519a51 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. Un type prenant en charge l'opérateur '{0}' est attendu, mais un type tuple a été reçu @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. Ce code n'est pas suffisamment générique. Impossible de généraliser la variable de type {0}, car elle sort de sa portée. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index b62fc22c123..78bedf2fc54 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. È previsto un tipo che supporti l'operatore '{0}', tuttavia è specificato un tipo di tuple @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. Questo codice non è sufficientemente generico. Non è stato possibile generalizzare la variabile di tipo {0} perché non sarebbe compresa nel relativo ambito. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index a43d7bab47e..958de8241dd 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. 演算子 '{0}' をサポートする型が必要ですが、タプル型が指定されました @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. このコードの総称性が十分ではありません。スコープが回避されるため、型変数 {0} をジェネリック化することはできません。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 00fde3d8ca7..63bc282534a 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. '{0}' 연산자를 지원하는 형식이 필요한데 튜플 형식을 지정했습니다. @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. 이 코드는 충분히 일반적이지 않습니다. 형식 변수 {0}을(를) 일반화하면 범위를 벗어나게 되므로 일반화할 수 없습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 0a2adaff95a..9d31cdffad2 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. Oczekiwany jest typ obsługujący operator „{0}”, ale podano typ krotki @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. Ten kod nie jest wystarczająco ogólny. Nie można uogólnić zmiennej typu {0}, ponieważ wykroczy ona poza swój zakres. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 57b7affdfbf..85f70e4cd9a 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. Um tipo que suporte o operador '{0}' era esperado, mas um tipo de tupla foi recebido. @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. Este código não é suficientemente genérico. A variável de tipo {0} não pode ser gerada porque ela escaparia de seu escopo. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 06b9c05fe8b..76769efea97 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. Ожидался тип, поддерживающий оператор "{0}", однако указан кортежный тип @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. Этот код является недостаточно базовым Переменная типа {0} не может быть обобщена, так как тогда она выйдет за пределы области. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 7b75e214154..171ea112b88 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. '{0}' işlecini destekleyen bir tür bekleniyor ancak bir demet türü verildi. @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. Bu kod yeterince genel değil. Tür değişkeni {0}, kapsamını kaçıracağı için genelleştirilemedi. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index b6e61a8f312..af5eade7968 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. 需要一个支持运算符“{0}”的类型,但提供的是元组类型 @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. 此代码的通用程度不够。未能对类型变量 {0} 进行一般化,因为它会超出其范围。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 8abb909edcd..940457be07e 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -1843,7 +1843,7 @@ - The type '{0}' does not have a field, property, or member named '{1}'. + The type '{0}' does not define a field, constructor, or member named '{1}'. The type '{0}' does not have a field, property, or member named '{1}'. @@ -3348,7 +3348,7 @@ - Expecting a type supporting the operator '{0}' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. + Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. 必須是支援運算子 '{0}' 的型別,但指定的是元組型別 @@ -4328,7 +4328,7 @@ - This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. + This code is not sufficiently generic. The type variable {0} could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. 這個程式碼的一般程度不足。無法一般化類型變數 {0},因為它會逸出其範圍。 diff --git a/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs b/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs index 3cf97a45dae..b9252abdfb4 100644 --- a/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs +++ b/tests/FSharp.Compiler.ComponentTests/CompilerService/FSharpWorkspace.fs @@ -441,7 +441,7 @@ let ``Giraffe signature test`` () = let! diag = workspace.Query.GetDiagnosticsForFile(Uri(giraffeSignaturesSampleDir ++ "Program.fs")) Assert.Equal(1, diag.Diagnostics.Length) - Assert.Equal("The type 'IServiceCollection' does not have a field, property, or member named 'AddGiraffe'.", diag.Diagnostics[0].Message) + Assert.Equal("The type 'IServiceCollection' does not define a field, constructor, or member named 'AddGiraffe'.", diag.Diagnostics[0].Message) } #endif \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/E_ActivePatternMember01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/E_ActivePatternMember01.fs index 3234d86fa03..6ecd74a0536 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/E_ActivePatternMember01.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/E_ActivePatternMember01.fs @@ -2,7 +2,7 @@ // Regression for FSHARP1.0:6168 // Active patterns should not be allowed as members - they don't work , but currently can be defined //This is not a valid name for an active pattern -//The type 'FaaBor' does not have a field, property, or member named 'Foo' +//The type 'FaaBor' does not define a field, constructor, or member named 'Foo' module M diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/MethodsAndProperties.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/MethodsAndProperties.fs index 0253276fe26..659ea3b2a52 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/MethodsAndProperties.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/MethodsAndProperties/MethodsAndProperties.fs @@ -71,7 +71,7 @@ module MemberDefinitions_MethodsAndProperties = |> shouldFail |> withDiagnostics [ (Error 827, Line 10, Col 20, Line 10, Col 29, "'(|Foo|Bar|)' is not a valid method name. Use a 'let' binding instead.") - (Error 39, Line 21, Col 10, Line 21, Col 13, "The type 'FaaBor' does not have a field, property, or member named 'Foo'.") + (Error 39, Line 21, Col 10, Line 21, Col 13, "The type 'FaaBor' does not define a field, constructor, or member named 'Foo'.") ] // SOURCE=E_ActivePatternMember02.fs SCFLAGS="--test:ErrorRanges" # E_ActivePatternMember02.fs @@ -154,7 +154,7 @@ module MemberDefinitions_MethodsAndProperties = |> verifyCompile |> shouldFail |> withDiagnostics [ - (Error 39, Line 13, Col 9, Line 13, Col 15, "The type 'Foo' does not have a field, property, or member named 'Item'.") + (Error 39, Line 13, Col 9, Line 13, Col 15, "The type 'Foo' does not define a field, constructor, or member named 'Item'.") ] // SOURCE=E_OutscopeThisPtr01.fs SCFLAGS="--test:ErrorRanges" # E_OutscopeThisPtr01.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs index bda47c8a119..48b27ecb666 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OptionalArguments/OptionalArguments.fs @@ -73,7 +73,7 @@ module MemberDefinitions_OptionalArguments = |> shouldFail |> withDiagnostics [ (Error 1212, Line 7, Col 22, Line 7, Col 32, "Optional arguments must come at the end of the argument list, after any non-optional arguments") - (Error 39, Line 8, Col 5, Line 8, Col 8, "The type 'Foo' does not have a field, property, or member named 'Bar'.") + (Error 39, Line 8, Col 5, Line 8, Col 8, "The type 'Foo' does not define a field, constructor, or member named 'Bar'.") ] // SOURCE=E_SanityCheck02.fs @@ -84,7 +84,7 @@ module MemberDefinitions_OptionalArguments = |> shouldFail |> withDiagnostics [ (Error 1212, Line 7, Col 22, Line 7, Col 29, "Optional arguments must come at the end of the argument list, after any non-optional arguments") - (Error 39, Line 8, Col 5, Line 8, Col 8, "The type 'Foo' does not have a field, property, or member named 'Bar'.") + (Error 39, Line 8, Col 5, Line 8, Col 8, "The type 'Foo' does not define a field, constructor, or member named 'Bar'.") ] // SOURCE=optionalOfOptOptA.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ApplicationExpressions/ObjectConstruction/E_ObjectConstruction01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ApplicationExpressions/ObjectConstruction/E_ObjectConstruction01.fs index aee8a055f57..3f10b356341 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ApplicationExpressions/ObjectConstruction/E_ObjectConstruction01.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ApplicationExpressions/ObjectConstruction/E_ObjectConstruction01.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #ApplicationExpressions #ObjectConstructors // Verify error for inaccessible constructor -//The type 'BitArray' does not have a field, property, or member named 'BitArrayEnumeratorSimple' +//The type 'BitArray' does not define a field, constructor, or member named 'BitArrayEnumeratorSimple' let y = System.Collections.BitArray.BitArrayEnumeratorSimple () diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/DataExpressions/ObjectExpressions/E_InvalidSelfReferentialStructConstructor.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/DataExpressions/ObjectExpressions/E_InvalidSelfReferentialStructConstructor.fs index 7f693dae7b0..1d9bc7038ef 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/DataExpressions/ObjectExpressions/E_InvalidSelfReferentialStructConstructor.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/DataExpressions/ObjectExpressions/E_InvalidSelfReferentialStructConstructor.fs @@ -3,7 +3,7 @@ //Structs may only bind a 'this' parameter at member declarations$ //This is not a valid object construction expression\. Explicit object constructors must either call an alternate constructor or initialize all fields of the object and specify a call to a super class constructor\.$ -//The type 'byref<_,_>' does not have a field, property, or member named 'dt' +//The type 'byref<_,_>' does not define a field, constructor, or member named 'dt' module mod6350 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/E_GetSliceNotDef01.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/E_GetSliceNotDef01.fs index 24d1875e981..a91d573ba81 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/E_GetSliceNotDef01.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/E_GetSliceNotDef01.fs @@ -2,7 +2,7 @@ // Verify error if GetSlice is not defined -//The type 'DU' does not have a field, property, or member named 'GetSlice' +//The type 'DU' does not define a field, constructor, or member named 'GetSlice' type DU = A | B of int | C diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/SyntacticSugar.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/SyntacticSugar.fs index 0e5731d5cb3..561144c981d 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/SyntacticSugar.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/SyntacticSugar/SyntacticSugar.fs @@ -82,7 +82,7 @@ module SyntacticSugar = |> verifyCompile // SOURCE=E_GetSliceNotDef01.fs - // The type 'DU' does not have a field, property, or member named 'GetSlice' + // The type 'DU' does not define a field, constructor, or member named 'GetSlice' [] let ``E_GetSliceNotDef01_fs`` compilation = compilation @@ -90,7 +90,7 @@ module SyntacticSugar = |> verifyTypecheck |> shouldFail |> withErrorCode 39 - |> withDiagnosticMessageMatches "The type 'DU' does not have a field, property, or member named 'GetSlice'" + |> withDiagnosticMessageMatches "The type 'DU' does not define a field, constructor, or member named 'GetSlice'" // SOURCE=E_GetSliceNotDef02.fs // ... diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs index eb317b44eec..27ec6b14d4c 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalAnalysis/SymbolicOperators.fs @@ -66,7 +66,7 @@ let a6 = TestType.(+++)((fun (x : string) -> 18), tt0)""" |> compile |> shouldFail |> withErrorCode 0670 - |> withDiagnosticMessageMatches " 'a\) could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition." + |> withDiagnosticMessageMatches " 'a\) could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'." |> ignore // This test was automatically generated (moved from FSharpQA suite - Conformance/LexicalAnalysis/SymbolicOperators) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoValueFieldOnEnum.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoValueFieldOnEnum.fs index 917c4398046..17588c344e6 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoValueFieldOnEnum.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/EnumTypes/E_NoValueFieldOnEnum.fs @@ -1,6 +1,6 @@ // #Regression #Conformance #ObjectOrientedTypes #Enums // FS1 992: ilreflect error triggered with Enum value__ calls. -//The type 'EnumType' does not have a field, property, or member named 'value__' +//The type 'EnumType' does not define a field, constructor, or member named 'value__' type EnumType = | A = 1 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/InterfaceTypes/E_MultipleInterfaceInheritance.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/InterfaceTypes/E_MultipleInterfaceInheritance.fs index 67bdf79c6a6..112b8894e1f 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/InterfaceTypes/E_MultipleInterfaceInheritance.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/ObjectOrientedTypeDefinitions/InterfaceTypes/E_MultipleInterfaceInheritance.fs @@ -60,9 +60,9 @@ if ( {new I_003 with System.Console.WriteLine("I_003.Home failed") res <- false -//The type 'T' does not have a field, property, or member named 'Me' -//The type 'T' does not have a field, property, or member named 'Me' -//The type 'T' does not have a field, property, or member named 'Home' +//The type 'T' does not define a field, constructor, or member named 'Me' +//The type 'T' does not define a field, constructor, or member named 'Me' +//The type 'T' does not define a field, constructor, or member named 'Home' //No implementation was given for those members: //'abstract I_002\.Me: 'a -> int'\. //'abstract I_002\.Me: 'a -> int'\. diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/Signatures.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/Signatures.fs index 034d016dffa..62fc70a6810 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/Signatures.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Signatures/Signatures.fs @@ -127,7 +127,7 @@ module SignatureConformance = // Regression for Dev11:137942 - structs used to not give errors when member names conflicted with interface members // SOURCE="E_StructWithNameConflict02.fsi E_StructWithNameConflict02.fs" SCFLAGS="--test:ErrorRanges --flaterrors" - // The type 'Foo<_>' does not have a field, property, or member named 'GetEnumerator' + // The type 'Foo<_>' does not define a field, constructor, or member named 'GetEnumerator' // ... [] let ``E_StructWithNameConflict02 - struct undefined member from signature`` () = diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/NameResolutionTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/NameResolutionTests.fs index 59e4f045ced..a1175f09b0d 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/NameResolutionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/NameResolutionTests.fs @@ -77,7 +77,7 @@ module Lib = |> shouldFail |> withDiagnostics [ (Warning 3566, Line 22, Col 9, Line 22, Col 19, "Multiple type matches were found:\n N.Module1.OtherThing\n N.Module2.Person\nThe type 'N.Module1.OtherThing' was used. Due to the overlapping field names\n Name\nconsider using type annotations or change the order of open statements.") - (Error 39, Line 22, Col 15, Line 22, Col 19, "The type 'OtherThing' does not have a field, property, or member named 'City'.") + (Error 39, Line 22, Col 15, Line 22, Col 19, "The type 'OtherThing' does not define a field, constructor, or member named 'City'.") ] let multipleRecdTypeChoiceWarningWith2AlternativeSource = """ @@ -123,7 +123,7 @@ module Lib = |> shouldFail |> withDiagnostics [ (Warning 3566, Line 33, Col 9, Line 33, Col 19, "Multiple type matches were found:\n N.Module1.OtherThing\n N.Module2.Person\n N.Module3.Cafe\nThe type 'N.Module1.OtherThing' was used. Due to the overlapping field names\n Name\n Planet\nconsider using type annotations or change the order of open statements.") - (Error 39, Line 33, Col 15, Line 33, Col 19, "The type 'OtherThing' does not have a field, property, or member named 'City'.") + (Error 39, Line 33, Col 15, Line 33, Col 19, "The type 'OtherThing' does not define a field, constructor, or member named 'City'.") ] let multipleRecdTypeChoiceWarningNotRaisedWithCorrectOpenStmtsOrderingSource = """ diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs index b02cf16307d..dfbc555fe1b 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs @@ -26,4 +26,4 @@ let result = add (1, 2) (3, 4) """ |> typecheck |> shouldFail - |> withDiagnosticMessageMatches "Expecting a type supporting the operator '\+' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope." + |> withDiagnosticMessageMatches "Operator '\+' cannot be applied to a tuple type. You may be missing an argument to a function, or the operator may not be in scope." diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuggestionsTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuggestionsTests.fs index 9772dcf5cef..9ccad763718 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuggestionsTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/SuggestionsTests.fs @@ -18,7 +18,7 @@ let x = { Person.Names = "Isaac" } |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 4, Col 18, Line 4, Col 23, - ("The type 'Person' does not have a field, property, or member named 'Names'. Maybe you want one of the following:" + Environment.NewLine + " Name")) + ("The type 'Person' does not define a field, constructor, or member named 'Names'. Maybe you want one of the following:" + Environment.NewLine + " Name")) [] let ``Suggest Array Module Functions`` () = @@ -77,7 +77,7 @@ let x = N.MyUnion.``My Case2`` |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 9, Col 19, Line 9,Col 31, - ("The type 'MyUnion' does not have a field, property, or member named 'My Case2'. Maybe you want one of the following:" + Environment.NewLine + " Case2" + Environment.NewLine + " ``My Case1``" + Environment.NewLine + " IsMy Case1")) + ("The type 'MyUnion' does not define a field, constructor, or member named 'My Case2'. Maybe you want one of the following:" + Environment.NewLine + " Case2" + Environment.NewLine + " ``My Case1``" + Environment.NewLine + " IsMy Case1")) [] @@ -120,7 +120,7 @@ module Test2 = |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 9, Col 7, Line 9, Col 14, - ("The type 'D' does not have a field, property, or member named 'Method2'. Maybe you want one of the following:" + Environment.NewLine + " Method1")) + ("The type 'D' does not define a field, constructor, or member named 'Method2'. Maybe you want one of the following:" + Environment.NewLine + " Method1")) [] let ``Suggest Modules`` () = @@ -158,7 +158,7 @@ let x = r.ello |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 6, Col 11, Line 6, Col 15, - ("The type 'MyRecord' does not have a field, property, or member named 'ello'. Maybe you want one of the following:" + Environment.NewLine + " Hello")) + ("The type 'MyRecord' does not define a field, constructor, or member named 'ello'. Maybe you want one of the following:" + Environment.NewLine + " Hello")) [] let ``Suggest Record Type for RequireQualifiedAccess Records`` () = @@ -224,7 +224,7 @@ let u = MyUnion.AntherCase |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 6, Col 17, Line 6, Col 27, - ("The type 'MyUnion' does not have a field, property, or member named 'AntherCase'. Maybe you want one of the following:" + Environment.NewLine + " AnotherCase" + Environment.NewLine + " IsAnotherCase")) + ("The type 'MyUnion' does not define a field, constructor, or member named 'AntherCase'. Maybe you want one of the following:" + Environment.NewLine + " AnotherCase" + Environment.NewLine + " IsAnotherCase")) [] let ``Suggest Union Type for RequireQualifiedAccess Unions`` () = @@ -260,4 +260,4 @@ let x = |> typecheck |> shouldFail |> withSingleDiagnostic (Error 39, Line 11, Col 15, Line 11, Col 19, - ("The type 'MyUnion' does not have a field, property, or member named 'Cas1'. Maybe you want one of the following:" + Environment.NewLine + " Case1" + Environment.NewLine + " Case2")) + ("The type 'MyUnion' does not define a field, constructor, or member named 'Cas1'. Maybe you want one of the following:" + Environment.NewLine + " Case1" + Environment.NewLine + " Case2")) diff --git a/tests/FSharp.Compiler.ComponentTests/Import/ImportTests.fs b/tests/FSharp.Compiler.ComponentTests/Import/ImportTests.fs index e9aec0df6cd..8c61bc082a0 100644 --- a/tests/FSharp.Compiler.ComponentTests/Import/ImportTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Import/ImportTests.fs @@ -554,7 +554,7 @@ type T() = |> withReferences [csLib] |> compile |> shouldFail - |> withErrorCode 39 // "The type does not have a field, property, or member named" + |> withErrorCode 39 // "The type does not define a field, constructor, or member named" |> ignore // ======================================== diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/DeeplyNestedCSharpClasses.fs b/tests/FSharp.Compiler.ComponentTests/Interop/DeeplyNestedCSharpClasses.fs index e682cedc8d7..e88c3acae81 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/DeeplyNestedCSharpClasses.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/DeeplyNestedCSharpClasses.fs @@ -54,7 +54,7 @@ let loss2 = MyNamespace.OuterClass.InnerClass_.MoreInnerClass.somefunction() / |> withReferences [cslib] |> compile |> shouldFail - |> withSingleDiagnostic (Error 39, Line 2, Col 36, Line 2, Col 47, "The type 'OuterClass' does not have a field, property, or member named 'InnerClass_'.") + |> withSingleDiagnostic (Error 39, Line 2, Col 36, Line 2, Col 47, "The type 'OuterClass' does not define a field, constructor, or member named 'InnerClass_'.") [] let ``Missing type nested type moreinnerclass generates good message and range`` () = @@ -68,7 +68,7 @@ let loss2 = MyNamespace.OuterClass.InnerClass.MoareInnerClass.somefunction() / |> withReferences [cslib] |> compile |> shouldFail - |> withSingleDiagnostic (Error 39, Line 2, Col 47, Line 2, Col 62, "The type 'InnerClass' does not have a field, property, or member named 'MoareInnerClass'.") + |> withSingleDiagnostic (Error 39, Line 2, Col 47, Line 2, Col 62, "The type 'InnerClass' does not define a field, constructor, or member named 'MoareInnerClass'.") [] let ``Missing function generates good message and range`` () = @@ -82,5 +82,5 @@ let loss2 = MyNamespace.OuterClass.InnerClass.MoreInnerClass.somefunction_() / |> withReferences [cslib] |> compile |> shouldFail - |> withSingleDiagnostic ((Error 39, Line 2, Col 62, Line 2, Col 75, """The type 'MoreInnerClass' does not have a field, property, or member named 'somefunction_'. Maybe you want one of the following: + |> withSingleDiagnostic ((Error 39, Line 2, Col 62, Line 2, Col 75, """The type 'MoreInnerClass' does not define a field, constructor, or member named 'somefunction_'. Maybe you want one of the following: somefunction""")) diff --git a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs index f68ab2b4825..800427ea2bd 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs @@ -175,7 +175,7 @@ let x = lb {1; 2;()} """ |> compile |> shouldFail - |> withSingleDiagnostic (Error 39, Line 10, Col 18, Line 10, Col 20, "The type 'ListBuilder' does not have a field, property, or member named 'Zero'.") + |> withSingleDiagnostic (Error 39, Line 10, Col 18, Line 10, Col 20, "The type 'ListBuilder' does not define a field, constructor, or member named 'Zero'.") |> ignore [] diff --git a/tests/FSharp.Compiler.ComponentTests/Language/DiscriminatedUnionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/DiscriminatedUnionTests.fs index a0ace1631d1..ed4c2b7bb33 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/DiscriminatedUnionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/DiscriminatedUnionTests.fs @@ -28,7 +28,7 @@ if not foo.IsBar then failwith "Should be Bar" """ |> typecheck |> shouldFail - |> withDiagnostics [Error 39, Line 4, Col 12, Line 4, Col 17, "The type 'Foo' does not have a field, property, or member named 'IsBar'. Maybe you want one of the following: + |> withDiagnostics [Error 39, Line 4, Col 12, Line 4, Col 17, "The type 'Foo' does not define a field, constructor, or member named 'IsBar'. Maybe you want one of the following: Bar"] [] @@ -136,7 +136,7 @@ let isFoo = foo.IsFoo """ |> typecheck |> shouldFail - |> withErrorMessage "The type 'Foo' does not have a field, property, or member named 'IsFoo'. Maybe you want one of the following: + |> withErrorMessage "The type 'Foo' does not define a field, constructor, or member named 'IsFoo'. Maybe you want one of the following: Foo" @@ -154,7 +154,7 @@ let x = (PrimaryAssembly.Mscorlib).IsMscorlib |> withLangVersion80 |> typecheck |> shouldFail - |> withErrorMessage "The type 'PrimaryAssembly' does not have a field, property, or member named 'IsMscorlib'. Maybe you want one of the following: + |> withErrorMessage "The type 'PrimaryAssembly' does not define a field, constructor, or member named 'IsMscorlib'. Maybe you want one of the following: Mscorlib" diff --git a/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/Signatures/SignatureConformance/E_StructWithNameConflict02.fsi b/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/Signatures/SignatureConformance/E_StructWithNameConflict02.fsi index 0722ca0c353..4f3c6feb429 100644 --- a/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/Signatures/SignatureConformance/E_StructWithNameConflict02.fsi +++ b/tests/FSharp.Compiler.ComponentTests/resources/tests/Conformance/Signatures/SignatureConformance/E_StructWithNameConflict02.fsi @@ -1,6 +1,6 @@ // #Conformance #Signatures #Structs #Regression // Regression for Dev11:137942, structs used to not give errors on when member names conflicted with interface members -//The type 'Foo<_>' does not have a field, property, or member named 'GetEnumerator' +//The type 'Foo<_>' does not define a field, constructor, or member named 'GetEnumerator' //Module 'M' contains override Foo\.GetEnumerator : unit -> IEnumerator<'T> but its signature specifies member Foo\.GetEnumerator : unit -> IEnumerator<'T> The compiled names differ module M diff --git a/tests/fsharp/Compiler/Language/CustomCollectionTests.fs b/tests/fsharp/Compiler/Language/CustomCollectionTests.fs index 5003f5a2dd1..2c935b77e53 100644 --- a/tests/fsharp/Compiler/Language/CustomCollectionTests.fs +++ b/tests/fsharp/Compiler/Language/CustomCollectionTests.fs @@ -107,7 +107,7 @@ if a.[^2] <> 12 then failwith "expected 12" FSharpDiagnosticSeverity.Error 39 (9,7,9,9) - "The type 'foo' does not have a field, property, or member named 'GetReverseIndex'." + "The type 'foo' does not define a field, constructor, or member named 'GetReverseIndex'." [] let ``Custom collection with GetSlice and GetReverseIndex should support reverse index slicing``() = @@ -148,4 +148,4 @@ if a[^2..1] <> 13 then failwith "expected 13" FSharpDiagnosticSeverity.Error 39 (12,6,12,8) - "The type 'foo' does not have a field, property, or member named 'GetReverseIndex'." + "The type 'foo' does not define a field, constructor, or member named 'GetReverseIndex'." diff --git a/tests/fsharp/Compiler/Language/DefaultInterfaceMemberTests.fs b/tests/fsharp/Compiler/Language/DefaultInterfaceMemberTests.fs index 2269b2ad9a6..d6a667b6156 100644 --- a/tests/fsharp/Compiler/Language/DefaultInterfaceMemberTests.fs +++ b/tests/fsharp/Compiler/Language/DefaultInterfaceMemberTests.fs @@ -546,7 +546,7 @@ let f () = Compilation.Create(fsharpSource, Library, options = [|"--langversion:8.0"|], cmplRefs = [csCmpl]) CompilerAssert.CompileWithErrors(fsCmpl, [| - (FSharpDiagnosticSeverity.Error, 39, (16, 10, 16, 23), "The type 'ITest' does not have a field, property, or member named 'DefaultMethod'. Maybe you want one of the following: + (FSharpDiagnosticSeverity.Error, 39, (16, 10, 16, 23), "The type 'ITest' does not define a field, constructor, or member named 'DefaultMethod'. Maybe you want one of the following: NonDefaultMethod") |]) @@ -3720,7 +3720,7 @@ let f () = Compilation.Create(fsharpSource, Exe, options = [|"--langversion:8.0"|], cmplRefs = [csCmpl]) CompilerAssert.CompileWithErrors(fsCmpl, [| - (FSharpDiagnosticSeverity.Error, 39, (6, 17, 6, 29), "The type 'CSharpClass' does not have a field, property, or member named 'StaticMethod'.") + (FSharpDiagnosticSeverity.Error, 39, (6, 17, 6, 29), "The type 'CSharpClass' does not define a field, constructor, or member named 'StaticMethod'.") |]) [] @@ -3770,7 +3770,7 @@ let f () = Compilation.Create(fsharpSource, Exe, options = [|"--langversion:8.0"|], cmplRefs = [csCmpl]) CompilerAssert.CompileWithErrors(fsCmpl, [| - (FSharpDiagnosticSeverity.Error, 39, (11, 17, 11, 29), "The type 'FSharpClass' does not have a field, property, or member named 'StaticMethod'.") + (FSharpDiagnosticSeverity.Error, 39, (11, 17, 11, 29), "The type 'FSharpClass' does not define a field, constructor, or member named 'StaticMethod'.") |]) [] diff --git a/tests/fsharp/conformance/expressions/syntacticsugar/E_Slices01.bsl b/tests/fsharp/conformance/expressions/syntacticsugar/E_Slices01.bsl index 8bc348bcdb9..6cb4c4dde0b 100644 --- a/tests/fsharp/conformance/expressions/syntacticsugar/E_Slices01.bsl +++ b/tests/fsharp/conformance/expressions/syntacticsugar/E_Slices01.bsl @@ -31,7 +31,7 @@ Candidates: - member Foo.GetSlice: x1: float option * x2: int option * y: int -> unit - member Foo.GetSlice: x1: int option * x2: int option * y: int -> unit -E_Slices01.fsx(19,9,19,17): typecheck error FS0039: The type 'Foo<_>' does not have a field, property, or member named 'Item'. +E_Slices01.fsx(19,9,19,17): typecheck error FS0039: The type 'Foo<_>' does not define a field, constructor, or member named 'Item'. E_Slices01.fsx(20,9,20,26): typecheck error FS0503: A member or object constructor 'GetSlice' taking 4 arguments is not accessible from this code location. All accessible versions of method 'GetSlice' take 3 arguments. diff --git a/tests/fsharp/typeProviders/negTests/EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.bsl b/tests/fsharp/typeProviders/negTests/EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.bsl index 7cb4de4b26b..2d01bbd1c4f 100644 --- a/tests/fsharp/typeProviders/negTests/EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.bsl +++ b/tests/fsharp/typeProviders/negTests/EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.bsl @@ -5,4 +5,4 @@ EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.fsx(6,39,6,14 EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.fsx(8,41,8,58): typecheck error FS0039: The type 'TheGeneratedTypeJ' is not defined. -EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.fsx(8,79,8,96): typecheck error FS0039: The type 'Object' does not have a field, property, or member named 'TheGeneratedTypeJ'. +EVIL_PROVIDER_ReturnsTypeWithIncorrectNameFromApplyStaticArguments.fsx(8,79,8,96): typecheck error FS0039: The type 'Object' does not define a field, constructor, or member named 'TheGeneratedTypeJ'. diff --git a/tests/fsharp/typecheck/sigs/neg04.bsl b/tests/fsharp/typecheck/sigs/neg04.bsl index 194422d7b1b..119c1ef38cf 100644 --- a/tests/fsharp/typecheck/sigs/neg04.bsl +++ b/tests/fsharp/typecheck/sigs/neg04.bsl @@ -11,7 +11,7 @@ neg04.fs(22,8,22,17): typecheck error FS0912: This declaration element is not pe neg04.fs(26,8,26,17): typecheck error FS0912: This declaration element is not permitted in an augmentation -neg04.fs(32,8,32,11): typecheck error FS0039: The type 'Double' does not have a field, property, or member named 'Nan'. Maybe you want one of the following: +neg04.fs(32,8,32,11): typecheck error FS0039: The type 'Double' does not define a field, constructor, or member named 'Nan'. Maybe you want one of the following: IsNaN neg04.fs(46,69,46,94): typecheck error FS0001: Type mismatch. Expecting a tuple of length 4 of type @@ -64,7 +64,7 @@ but here has type neg04.fs(83,39,83,46): typecheck error FS0752: The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints -neg04.fs(85,47,85,52): typecheck error FS0039: The type 'Int32' does not have a field, property, or member named 'Item'. +neg04.fs(85,47,85,52): typecheck error FS0039: The type 'Int32' does not define a field, constructor, or member named 'Item'. neg04.fs(87,73,87,78): typecheck error FS0752: The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints diff --git a/tests/fsharp/typecheck/sigs/neg06.bsl b/tests/fsharp/typecheck/sigs/neg06.bsl index 9d4e4fdafd8..1a0546e8fd4 100644 --- a/tests/fsharp/typecheck/sigs/neg06.bsl +++ b/tests/fsharp/typecheck/sigs/neg06.bsl @@ -1,5 +1,5 @@ -neg06.fs(3,40,3,45): typecheck error FS0039: The type 'Encoding' does not have a field, property, or member named 'Ascii'. Maybe you want one of the following: +neg06.fs(3,40,3,45): typecheck error FS0039: The type 'Encoding' does not define a field, constructor, or member named 'Ascii'. Maybe you want one of the following: ASCII neg06.fs(12,6,12,31): typecheck error FS0942: Struct types are always sealed diff --git a/tests/fsharp/typecheck/sigs/neg08.bsl b/tests/fsharp/typecheck/sigs/neg08.bsl index ebba5c4149a..0a632b731c3 100644 --- a/tests/fsharp/typecheck/sigs/neg08.bsl +++ b/tests/fsharp/typecheck/sigs/neg08.bsl @@ -3,7 +3,7 @@ neg08.fs(7,24,7,55): typecheck error FS0033: The type 'System.Collections.Generi neg08.fs(9,24,9,67): typecheck error FS0033: The type 'System.Collections.Generic.List<_>' expects 1 type argument(s) but is given 2 -neg08.fs(16,8,16,10): typecheck error FS0670: This code is not sufficiently generic. The type variable 'b could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. +neg08.fs(16,8,16,10): typecheck error FS0670: This code is not sufficiently generic. The type variable 'b could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. neg08.fs(21,1,21,28): typecheck error FS0919: Exception abbreviations must refer to existing exceptions or F# types deriving from System.Exception @@ -19,6 +19,6 @@ neg08.fs(55,7,55,14): typecheck error FS0773: Cannot create an extension of a se neg08.fs(55,7,55,14): typecheck error FS0776: Object construction expressions may only be used to implement constructors in class types -neg08.fs(61,19,61,26): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'value__'. +neg08.fs(61,19,61,26): typecheck error FS0039: The type 'Type' does not define a field, constructor, or member named 'value__'. neg08.fs(79,5,79,44): typecheck error FS0502: The member or object constructor 'Random' takes 0 type argument(s) but is here given 1. The required signature is 'static member Variable.Random: y: Variable<'a> -> Variable<'a>'. diff --git a/tests/fsharp/typecheck/sigs/neg101.bsl b/tests/fsharp/typecheck/sigs/neg101.bsl index f764e86da88..8efa169c8e1 100644 --- a/tests/fsharp/typecheck/sigs/neg101.bsl +++ b/tests/fsharp/typecheck/sigs/neg101.bsl @@ -1,5 +1,5 @@ -neg101.fs(7,11,7,14): typecheck error FS0039: The type 'Int32' does not have a field, property, or member named 'Foo'. +neg101.fs(7,11,7,14): typecheck error FS0039: The type 'Int32' does not define a field, constructor, or member named 'Foo'. neg101.fs(14,6,14,17): typecheck error FS3220: This method or property is not normally used from F# code, use an explicit tuple pattern for deconstruction instead. diff --git a/tests/fsharp/typecheck/sigs/neg17.bsl b/tests/fsharp/typecheck/sigs/neg17.bsl index 730875a22b5..c09ddb99bb8 100644 --- a/tests/fsharp/typecheck/sigs/neg17.bsl +++ b/tests/fsharp/typecheck/sigs/neg17.bsl @@ -5,14 +5,14 @@ neg17b.fs(7,17,7,31): typecheck error FS1094: The value 'privateValue' is not ac neg17b.fs(8,18,8,43): typecheck error FS1092: The type 'PrivateUnionType' is not accessible from this code location -neg17b.fs(11,26,11,41): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'PrivateProperty'. +neg17b.fs(11,26,11,41): typecheck error FS0039: The type 'Type' does not define a field, constructor, or member named 'PrivateProperty'. -neg17b.fs(12,24,12,45): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'PrivateStaticProperty'. Maybe you want one of the following: +neg17b.fs(12,24,12,45): typecheck error FS0039: The type 'Type' does not define a field, constructor, or member named 'PrivateStaticProperty'. Maybe you want one of the following: InternalStaticProperty -neg17b.fs(13,26,13,39): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'PrivateMethod'. +neg17b.fs(13,26,13,39): typecheck error FS0039: The type 'Type' does not define a field, constructor, or member named 'PrivateMethod'. -neg17b.fs(14,24,14,43): typecheck error FS0039: The type 'Type' does not have a field, property, or member named 'PrivateStaticMethod'. Maybe you want one of the following: +neg17b.fs(14,24,14,43): typecheck error FS0039: The type 'Type' does not define a field, constructor, or member named 'PrivateStaticMethod'. Maybe you want one of the following: InternalStaticMethod neg17b.fs(15,17,15,52): typecheck error FS1092: The type 'PrivateRecordType' is not accessible from this code location diff --git a/tests/fsharp/typecheck/sigs/neg20.bsl b/tests/fsharp/typecheck/sigs/neg20.bsl index 1997770dcd2..6e5923f6116 100644 --- a/tests/fsharp/typecheck/sigs/neg20.bsl +++ b/tests/fsharp/typecheck/sigs/neg20.bsl @@ -358,13 +358,13 @@ neg20.fs(373,22,373,41): typecheck error FS1124: Multiple types exist called 'Ov neg20.fs(382,19,382,40): typecheck error FS1124: Multiple types exist called 'OverloadedClassName', taking different numbers of generic parameters. Provide a type instantiation to disambiguate the type resolution, e.g. 'OverloadedClassName<_>'. -neg20.fs(383,39,383,41): typecheck error FS0039: The type 'OverloadedClassName<_>' does not have a field, property, or member named 'S2'. +neg20.fs(383,39,383,41): typecheck error FS0039: The type 'OverloadedClassName<_>' does not define a field, constructor, or member named 'S2'. neg20.fs(428,19,428,38): typecheck error FS1133: No constructors are available for the type 'OverloadedClassName<'a,'b>' neg20.fs(430,22,430,41): typecheck error FS1133: No constructors are available for the type 'OverloadedClassName<'a,'b>' -neg20.fs(444,39,444,41): typecheck error FS0039: The type 'OverloadedClassName' does not have a field, property, or member named 'S2'. +neg20.fs(444,39,444,41): typecheck error FS0039: The type 'OverloadedClassName' does not define a field, constructor, or member named 'S2'. neg20.fs(447,27,447,28): typecheck error FS0001: This expression was expected to have type 'int option' diff --git a/tests/fsharp/typecheck/sigs/neg37.bsl b/tests/fsharp/typecheck/sigs/neg37.bsl index e3bbe3464a6..a1b1a6b2804 100644 --- a/tests/fsharp/typecheck/sigs/neg37.bsl +++ b/tests/fsharp/typecheck/sigs/neg37.bsl @@ -1,9 +1,9 @@ -neg37.fs(7,19,7,22): typecheck error FS0670: This code is not sufficiently generic. The type variable 'T could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. +neg37.fs(7,19,7,22): typecheck error FS0670: This code is not sufficiently generic. The type variable 'T could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. neg37.fs(19,33,19,40): typecheck error FS1125: The instantiation of the generic type 'CCC' is missing and can't be inferred from the arguments or return type of this member. Consider providing a type instantiation when accessing this type, e.g. 'CCC<_>'. -neg37.fs(19,19,19,22): typecheck error FS0670: This code is not sufficiently generic. The type variable 'T could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. +neg37.fs(19,19,19,22): typecheck error FS0670: This code is not sufficiently generic. The type variable 'T could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. neg37.fs(24,10,24,11): typecheck error FS0071: Type constraint mismatch when applying the default type 'IEvent<'T>' for a type inference variable. The type 'IEvent<'T>' is not compatible with the type 'System.IComparable<'T>' Consider adding further type constraints diff --git a/tests/fsharp/typecheck/sigs/neg45.bsl b/tests/fsharp/typecheck/sigs/neg45.bsl index 081352c4167..18de4770ac8 100644 --- a/tests/fsharp/typecheck/sigs/neg45.bsl +++ b/tests/fsharp/typecheck/sigs/neg45.bsl @@ -13,7 +13,7 @@ neg45.fs(34,27,34,28): typecheck error FS0465: Type inference problem too compli neg45.fs(41,24,41,33): typecheck error FS0827: '(|Foo|Bir|)' is not a valid method name. Use a 'let' binding instead. -neg45.fs(52,14,52,17): typecheck error FS0039: The type 'FooBir' does not have a field, property, or member named 'Foo'. +neg45.fs(52,14,52,17): typecheck error FS0039: The type 'FooBir' does not define a field, constructor, or member named 'Foo'. neg45.fs(56,19,56,28): typecheck error FS0827: '(|Foo|Bir|)' is not a valid method name. Use a 'let' binding instead. diff --git a/tests/fsharp/typecheck/sigs/neg55.bsl b/tests/fsharp/typecheck/sigs/neg55.bsl index 4abff92f75b..eaeeec743d0 100644 --- a/tests/fsharp/typecheck/sigs/neg55.bsl +++ b/tests/fsharp/typecheck/sigs/neg55.bsl @@ -1,6 +1,6 @@ neg55.fs(10,5,10,19): typecheck error FS0491: The member or object constructor '.cctor' is not accessible. Private members may only be accessed from within the declaring type. Protected members may only be accessed from an extending type and cannot be accessed from inner lambda expressions. -neg55.fs(19,7,19,16): typecheck error FS0039: The type 'D' does not have a field, property, or member named '.ctor'. +neg55.fs(19,7,19,16): typecheck error FS0039: The type 'D' does not define a field, constructor, or member named '.ctor'. neg55.fs(24,22,24,31): typecheck error FS3066: Invalid member name. Members may not have name '.ctor' or '.cctor' diff --git a/tests/fsharp/typecheck/sigs/neg60.bsl b/tests/fsharp/typecheck/sigs/neg60.bsl index 3e6786b96e7..68db2892038 100644 --- a/tests/fsharp/typecheck/sigs/neg60.bsl +++ b/tests/fsharp/typecheck/sigs/neg60.bsl @@ -16,9 +16,9 @@ neg60.fs(79,18,79,21): typecheck error FS0001: The type ''a * 'b' does not match neg60.fs(79,15,79,16): typecheck error FS0043: The type ''a * 'b' does not match the type 'int' -neg60.fs(80,22,80,25): typecheck error FS0001: Expecting a type supporting the operator '+' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. +neg60.fs(80,22,80,25): typecheck error FS0001: Operator '+' cannot be applied to a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. -neg60.fs(80,19,80,20): typecheck error FS0043: Expecting a type supporting the operator '+' but given a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. +neg60.fs(80,19,80,20): typecheck error FS0043: Operator '+' cannot be applied to a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. neg60.fs(81,22,81,34): typecheck error FS0002: This function takes too many arguments, or is used in a context where a function is not expected diff --git a/tests/fsharp/typecheck/sigs/neg62.bsl b/tests/fsharp/typecheck/sigs/neg62.bsl index d000ea280e1..3fabf9bcc5c 100644 --- a/tests/fsharp/typecheck/sigs/neg62.bsl +++ b/tests/fsharp/typecheck/sigs/neg62.bsl @@ -19,7 +19,7 @@ neg62.fs(50,5,50,34): typecheck error FS0901: Structs cannot contain value defin neg62.fs(54,31,54,34): typecheck error FS3135: To indicate that this property can be set, use 'member val PropertyName = expr with get,set'. -neg62.fs(69,24,69,30): typecheck error FS0670: This code is not sufficiently generic. The type variable 'S could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. +neg62.fs(69,24,69,30): typecheck error FS0670: This code is not sufficiently generic. The type variable 'S could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. neg62.fs(75,5,75,28): typecheck error FS3151: This member, function or value declaration may not be declared 'inline' diff --git a/tests/fsharp/typecheck/sigs/neg92.bsl b/tests/fsharp/typecheck/sigs/neg92.bsl index b28b78b9815..21946534ef8 100644 --- a/tests/fsharp/typecheck/sigs/neg92.bsl +++ b/tests/fsharp/typecheck/sigs/neg92.bsl @@ -1,4 +1,4 @@ neg92.fs(10,19,10,20): typecheck error FS0064: This construct causes code to be less generic than indicated by the type annotations. The type variable 'T has been constrained to be type ''U'. -neg92.fs(9,9,9,17): typecheck error FS0670: This code is not sufficiently generic. The type variable 'U could not be generalized because it would escape its scope. Consider adding 'inline' to the member or function definition. +neg92.fs(9,9,9,17): typecheck error FS0670: This code is not sufficiently generic. The type variable 'U could not be generalized because it would escape its scope. Consider adding a type annotation, converting the value to a function, or making the definition 'inline'. From 7b1a4472a9339dae4afd07a3291a6f71d6e7f220 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 2 Mar 2026 17:46:14 +0100 Subject: [PATCH 31/39] tests --- .../ErrorMessages/OperatorTests.fs | 2 +- tests/fsharp/typecheck/sigs/neg60.bsl | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs index dfbc555fe1b..3602fce04bb 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/OperatorTests.fs @@ -26,4 +26,4 @@ let result = add (1, 2) (3, 4) """ |> typecheck |> shouldFail - |> withDiagnosticMessageMatches "Operator '\+' cannot be applied to a tuple type. You may be missing an argument to a function, or the operator may not be in scope." + |> withDiagnosticMessageMatches "Operator '\+' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope." diff --git a/tests/fsharp/typecheck/sigs/neg60.bsl b/tests/fsharp/typecheck/sigs/neg60.bsl index 68db2892038..fb46313e958 100644 --- a/tests/fsharp/typecheck/sigs/neg60.bsl +++ b/tests/fsharp/typecheck/sigs/neg60.bsl @@ -16,9 +16,9 @@ neg60.fs(79,18,79,21): typecheck error FS0001: The type ''a * 'b' does not match neg60.fs(79,15,79,16): typecheck error FS0043: The type ''a * 'b' does not match the type 'int' -neg60.fs(80,22,80,25): typecheck error FS0001: Operator '+' cannot be applied to a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. +neg60.fs(80,22,80,25): typecheck error FS0001: Operator '+' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. -neg60.fs(80,19,80,20): typecheck error FS0043: Operator '+' cannot be applied to a tuple type. You may be missing an argument to a function, or the operator may not be in scope. Check that you have opened the correct module or namespace. +neg60.fs(80,19,80,20): typecheck error FS0043: Operator '+' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. neg60.fs(81,22,81,34): typecheck error FS0002: This function takes too many arguments, or is used in a context where a function is not expected From 17fb9836e73cd63e525bccff5f24aa4b7dbf125e Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Mon, 2 Mar 2026 18:01:28 +0100 Subject: [PATCH 32/39] =?UTF-8?q?Renumber=20FS3882=E2=86=92FS3884,=20FS388?= =?UTF-8?q?3=E2=86=92FS3885=20after=20merge;=20fix=20hint=20ordering=20in?= =?UTF-8?q?=20MatchIncomplete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Main took 3882/3883 for #elif preprocessor directive, renumber our diagnostics to avoid collision - Move for-loop hint after counter-example in MatchIncomplete so the message flows naturally: example first, then hint, then ignore note - Update all test assertions and release notes for new error codes Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/10.0.300.md | 2 +- src/Compiler/Driver/CompilerDiagnostics.fs | 6 +++--- .../Conformance/PatternMatching/Expression/Expression.fs | 4 ++-- .../ErrorMessages/CommaSemicolonListTests.fs | 6 +++--- .../Language/ComputationExpressionTests.fs | 6 +++--- tests/fsharp/typecheck/sigs/neg06.bsl | 2 +- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md index 5357e111899..1d485b7f079 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md @@ -36,6 +36,6 @@ * Centralized product TFM (Target Framework Moniker) into MSBuild props file `eng/TargetFrameworks.props`. Changing the target framework now only requires editing one file, and it integrates with MSBuild's `--getProperty` for scripts. * Overload resolution results are now cached, providing compile time improvements for code with repeated method calls. ([Issue #18807](https://github.com/dotnet/fsharp/issues/18807)) * Symbols: safer qualified name getting ([PR #19298](https://github.com/dotnet/fsharp/pull/19298)) -* Improved diagnostic messages for FS0003, FS0025, FS0039, FS0072, FS0247, FS0597, FS0670, FS3082, and type mismatch errors involving tuples. Added new warnings FS3882 (let!/use! at end of computation expression) and FS3883 (comma vs semicolon confusion in list literals). Added elif-chain detection for missing else branch errors, context-aware hints for incomplete matches in for-loops, and operator scope hints for SRTP errors. +* Improved diagnostic messages for FS0003, FS0025, FS0039, FS0072, FS0247, FS0597, FS0670, FS3082, and type mismatch errors involving tuples. Added new warnings FS3884 (let!/use! at end of computation expression) and FS3885 (comma vs semicolon confusion in list literals). Added elif-chain detection for missing else branch errors, context-aware hints for incomplete matches in for-loops, and operator scope hints for SRTP errors. ### Breaking Changes diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index ce34de30a64..25795c32b9e 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -1794,14 +1794,14 @@ type Exception with | PatternMatchCompilation.MatchIncomplete(isComp, cexOpt, _, isForLoop) -> os.AppendString(MatchIncomplete1E().Format) - if isForLoop then - os.AppendString(MatchIncompleteForLoopE().Format) - match cexOpt with | None -> () | Some(cex, false) -> os.AppendString(MatchIncomplete2E().Format cex) | Some(cex, true) -> os.AppendString(MatchIncomplete3E().Format cex) + if isForLoop then + os.AppendString(MatchIncompleteForLoopE().Format) + if isComp then os.AppendString(MatchIncomplete4E().Format) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/PatternMatching/Expression/Expression.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/PatternMatching/Expression/Expression.fs index 9d04bf40f80..7aba44ae432 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/PatternMatching/Expression/Expression.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/PatternMatching/Expression/Expression.fs @@ -150,7 +150,7 @@ for 0 in 1..10 do """ |> typecheck |> shouldFail - |> withSingleDiagnostic (Warning 25, Line 2, Col 5, Line 2, Col 6, "Incomplete pattern matches on this expression. Did you use a constant where a loop variable was expected? For example, the value '1' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") + |> withSingleDiagnostic (Warning 25, Line 2, Col 5, Line 2, Col 6, "Incomplete pattern matches on this expression. For example, the value '1' may indicate a case not covered by the pattern(s). Did you use a constant where a loop variable was expected? Unmatched elements will be ignored.") [] let ``MatchIncomplete for-loop with parenthesized constant pattern includes hint`` () = @@ -160,7 +160,7 @@ for (0) in 1..10 do """ |> typecheck |> shouldFail - |> withSingleDiagnostic (Warning 25, Line 2, Col 6, Line 2, Col 7, "Incomplete pattern matches on this expression. Did you use a constant where a loop variable was expected? For example, the value '1' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") + |> withSingleDiagnostic (Warning 25, Line 2, Col 6, Line 2, Col 7, "Incomplete pattern matches on this expression. For example, the value '1' may indicate a case not covered by the pattern(s). Did you use a constant where a loop variable was expected? Unmatched elements will be ignored.") [] let ``MatchIncomplete regular match does not include for-loop hint`` () = diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs index e1d625524d2..e851052d184 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/CommaSemicolonListTests.fs @@ -14,7 +14,7 @@ let x = [1, 2, 3] """ |> typecheck |> shouldFail - |> withSingleDiagnostic (Information 3883, Line 2, Col 9, Line 2, Col 18, + |> withSingleDiagnostic (Information 3885, Line 2, Col 9, Line 2, Col 18, "This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?") [] @@ -60,13 +60,13 @@ let x = [1, 2] """ |> typecheck |> shouldFail - |> withSingleDiagnostic (Information 3883, Line 2, Col 9, Line 2, Col 15, + |> withSingleDiagnostic (Information 3885, Line 2, Col 9, Line 2, Col 15, "This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?") [] let ``Warning is suppressible via nowarn``() = FSharp """ -#nowarn "3883" +#nowarn "3885" let x = [1, 2, 3] """ |> typecheck diff --git a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs index 800427ea2bd..56b7b288331 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/ComputationExpressionTests.fs @@ -2337,7 +2337,7 @@ let foo() = |> shouldFail |> withDiagnostics [ (Error 10, Line 6, Col 5, Line 6, Col 6, "Unexpected symbol '}' in expression") - (Error 3882, Line 5, Col 9, Line 5, Col 13, "'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") + (Error 3884, Line 5, Col 9, Line 5, Col 13, "'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") ] [] @@ -2353,7 +2353,7 @@ let foo() = |> shouldFail |> withDiagnostics [ (Error 10, Line 6, Col 5, Line 6, Col 6, "Unexpected symbol '}' in expression") - (Error 3882, Line 5, Col 9, Line 5, Col 13, "'use!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") + (Error 3884, Line 5, Col 9, Line 5, Col 13, "'use!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") ] [] @@ -2380,7 +2380,7 @@ let foo() = |> shouldFail |> withDiagnostics [ (Error 10, Line 17, Col 5, Line 17, Col 6, "Unexpected symbol '}' in expression") - (Error 3882, Line 15, Col 9, Line 15, Col 13, "'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") + (Error 3884, Line 15, Col 9, Line 15, Col 13, "'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.") ] [] diff --git a/tests/fsharp/typecheck/sigs/neg06.bsl b/tests/fsharp/typecheck/sigs/neg06.bsl index 1a0546e8fd4..aac7fe5403b 100644 --- a/tests/fsharp/typecheck/sigs/neg06.bsl +++ b/tests/fsharp/typecheck/sigs/neg06.bsl @@ -116,4 +116,4 @@ Candidates: - static member C.M1: x: int -> int - static member C.M1: x: string -> int -neg06.fs(398,13,398,14): typecheck error FS0025: Incomplete pattern matches on this expression. Did you use a constant where a loop variable was expected? For example, the value '0' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored. +neg06.fs(398,13,398,14): typecheck error FS0025: Incomplete pattern matches on this expression. For example, the value '0' may indicate a case not covered by the pattern(s). Did you use a constant where a loop variable was expected? Unmatched elements will be ignored. From 6495e53140ec109ad1046b6f911457b972b242a2 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 3 Mar 2026 16:19:39 +0100 Subject: [PATCH 33/39] Address council review: fix stale test, simplify elifChainMissingElse MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix SequenceIteration test assertion: hint order was stale after reordering (counter-example before for-loop hint) - Replace 14-line mutable while-loop elifChainMissingElse with 4-line recursive match — elif chains are syntactically shallow Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 17 ++++------------- .../SequenceIteration/SequenceIteration.fs | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index bd256b74fd9..6e2faad405b 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -10740,19 +10740,10 @@ and CheckRecursiveBindingIds binds = /// Returns true if the expression is an elif chain that ends without a final 'else' branch. and elifChainMissingElse expr = - let mutable current = expr - let mutable cont = true - let mutable result = false - - while cont do - match current with - | SynExpr.IfThenElse(elseExpr = None) -> - result <- true - cont <- false - | SynExpr.IfThenElse(elseExpr = Some elseExpr) -> current <- elseExpr - | _ -> cont <- false - - result + match expr with + | SynExpr.IfThenElse(elseExpr = None) -> true + | SynExpr.IfThenElse(elseExpr = Some elseExpr) -> elifChainMissingElse elseExpr + | _ -> false /// Process a sequence of sequentials mixed with iterated lets "let ... in let ... in ..." in a tail recursive way /// This avoids stack overflow on really large "let" and "letrec" lists diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/SequenceIteration/SequenceIteration.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/SequenceIteration/SequenceIteration.fs index 5df179c09ac..cef9f9b4abb 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/SequenceIteration/SequenceIteration.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Expressions/ControlFlowExpressions/SequenceIteration/SequenceIteration.fs @@ -22,7 +22,7 @@ module SequenceIteration = (Warning 25, Line 10, Col 5, Line 10, Col 11, "Incomplete pattern matches on this expression. For example, the value 'None' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") (Warning 25, Line 13, Col 5, Line 13, Col 11, "Incomplete pattern matches on this expression. For example, the value 'None' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") (Warning 25, Line 15, Col 5, Line 15, Col 11, "Incomplete pattern matches on this expression. For example, the value 'Some (0)' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") - (Warning 25, Line 17, Col 5, Line 17, Col 6, "Incomplete pattern matches on this expression. Did you use a constant where a loop variable was expected? For example, the value '0' may indicate a case not covered by the pattern(s). Unmatched elements will be ignored.") + (Warning 25, Line 17, Col 5, Line 17, Col 6, "Incomplete pattern matches on this expression. For example, the value '0' may indicate a case not covered by the pattern(s). Did you use a constant where a loop variable was expected? Unmatched elements will be ignored.") (Warning 25, Line 22, Col 9, Line 22, Col 17, "Incomplete pattern matches on this expression. For example, the value 'None' may indicate a case not covered by the pattern(s).") (Warning 25, Line 27, Col 20, Line 27, Col 28, "Incomplete pattern matches on this expression. For example, the value 'None' may indicate a case not covered by the pattern(s).") ] From f883edb68483b380cac6661c54b7ad293be884a3 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Thu, 5 Mar 2026 14:04:24 +0100 Subject: [PATCH 34/39] Refactor FS0025 for-loop hint: replace bool threading with DiagnosticsLogger interceptor Replace the isForLoopBinding bool threaded through CompilePattern pipeline (4 function signatures, 7 call sites, MatchIncomplete exception type change) with a DiagnosticsLogger interceptor at the single call site in TcForEachExpr. - Revert MatchIncomplete to original 3 fields (bool * option * range) - Add MatchIncompleteForLoopHint wrapper exception - Use UseTransformedDiagnosticsLogger to intercept MatchIncomplete warnings from CompilePatternForMatch and wrap them when isConstantPattern is true - Handle wrapper in CompilerDiagnostics.fs for range, error number, formatting The diagnostic output is identical. The constant-pattern detection stays where the context lives (TcForEachExpr), and the pattern match pipeline remains oblivious to for-loop concerns. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../Checking/Expressions/CheckExpressions.fs | 32 +++++++++++++++---- .../Expressions/CheckExpressionsOps.fs | 4 --- .../Checking/PatternMatchCompilation.fs | 23 +++++++------ .../Checking/PatternMatchCompilation.fsi | 11 +++---- src/Compiler/Driver/CompilerDiagnostics.fs | 20 +++++++++--- 5 files changed, 60 insertions(+), 30 deletions(-) diff --git a/src/Compiler/Checking/Expressions/CheckExpressions.fs b/src/Compiler/Checking/Expressions/CheckExpressions.fs index 6e2faad405b..fac0b1b432f 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressions.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressions.fs @@ -8267,11 +8267,31 @@ and TcForEachExpr cenv overallTy env tpenv (seqExprOnly, isFromSource, synPat, s | SynPat.Paren(SynPat.Typed(SynPat.Const _, _, _), _) -> true | _ -> false - CompilePatternForMatch - cenv env synEnumExpr.Range pat.Range false IgnoreWithWarning isConstantPattern (elemVar, [], None) - [MatchClause(pat, None, TTarget(valsDefinedByMatching, bodyExpr, None), mIn)] - enumElemTy - overallTy.Commit + let compileMatch () = + CompilePatternForMatch + cenv env synEnumExpr.Range pat.Range false IgnoreWithWarning (elemVar, [], None) + [MatchClause(pat, None, TTarget(valsDefinedByMatching, bodyExpr, None), mIn)] + enumElemTy + overallTy.Commit + + if isConstantPattern then + use _ = + UseTransformedDiagnosticsLogger(fun oldLogger -> + { new DiagnosticsLogger("forLoopConstantHint") with + member _.DiagnosticSink(diagnostic) = + match diagnostic.Exception with + | MatchIncomplete _ -> + oldLogger.DiagnosticSink( + { diagnostic with + Exception = MatchIncompleteForLoopHint(diagnostic.Exception) }) + | _ -> oldLogger.DiagnosticSink(diagnostic) + + member _.ErrorCount = oldLogger.ErrorCount + }) + + compileMatch () + else + compileMatch () // Apply the fixup to bind the elemVar if needed let bodyExpr = bodyExprFixup elemVar bodyExpr @@ -11809,7 +11829,7 @@ and TcLetBinding (cenv: cenv) isUse env containerInfo declKind tpenv (synBinds, let mkPatBind (bodyExpr, bodyExprTy) = let valsDefinedByMatching = ListSet.remove valEq patternInputTmp allValsDefinedByPattern let clauses = [MatchClause(checkedPat2, None, TTarget(valsDefinedByMatching, bodyExpr, None), m)] - let matchExpr = CompilePatternForMatch cenv env m m true ThrowIncompleteMatchException false (patternInputTmp, generalizedTypars, Some rhsExpr) clauses tauTy bodyExprTy + let matchExpr = CompilePatternForMatch cenv env m m true ThrowIncompleteMatchException (patternInputTmp, generalizedTypars, Some rhsExpr) clauses tauTy bodyExprTy let matchExpr = if declKind.IsConvertToLinearBindings then diff --git a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs index 15181f0dde3..0fe8e296b81 100644 --- a/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs +++ b/src/Compiler/Checking/Expressions/CheckExpressionsOps.fs @@ -78,7 +78,6 @@ let CompilePatternForMatch mMatch warnOnUnused actionOnFailure - isForLoopBinding (inputVal, generalizedTypars, inputExprOpt) clauses inputTy @@ -97,7 +96,6 @@ let CompilePatternForMatch mMatch warnOnUnused actionOnFailure - isForLoopBinding (inputVal, generalizedTypars, inputExprOpt) clauses inputTy @@ -121,7 +119,6 @@ let CompilePatternForMatchClauses (cenv: TcFileState) env mExpr mMatch warnOnUnu mMatch warnOnUnused actionOnFailure - false (asVal, generalizedTypars, None) [ MatchClause(pat1, None, TTarget(vs2, targetExpr, None), m2) ] inputTy @@ -139,7 +136,6 @@ let CompilePatternForMatchClauses (cenv: TcFileState) env mExpr mMatch warnOnUnu mMatch warnOnUnused actionOnFailure - false (matchValueTmp, [], inputExprOpt) tclauses inputTy diff --git a/src/Compiler/Checking/PatternMatchCompilation.fs b/src/Compiler/Checking/PatternMatchCompilation.fs index 851afec8ecf..4128b8cf5f4 100644 --- a/src/Compiler/Checking/PatternMatchCompilation.fs +++ b/src/Compiler/Checking/PatternMatchCompilation.fs @@ -25,8 +25,12 @@ open FSharp.Compiler.TypeRelations open type System.MemoryExtensions /// Exception raised when a pattern match is incomplete. -/// Fields: isComputationExpression * (counterExample * isShownAsFieldPattern) option * range * isForLoopBinding -exception MatchIncomplete of bool * (string * bool) option * range * bool +/// Fields: isComputationExpression * (counterExample * isShownAsFieldPattern) option * range +exception MatchIncomplete of bool * (string * bool) option * range + +/// Wrapper that adds a for-loop hint to an existing MatchIncomplete diagnostic. +exception MatchIncompleteForLoopHint of exn + exception RuleNeverMatched of range exception EnumMatchIncomplete of bool * (string * bool) option * range @@ -991,7 +995,6 @@ let CompilePatternBasic warnOnUnused warnOnIncomplete actionOnFailure - isForLoopBinding (origInputVal, origInputValTypars, _origInputExprOpt: Expr option) (clauses: MatchClause list) inputTy @@ -1019,10 +1022,10 @@ let CompilePatternBasic warning (EnumMatchIncomplete(ignoreWithWarning, Some(text, failingWhenClause), mMatch)) warningsGenerated.Add CounterExampleType.EnumCoversKnown | Some(text, failingWhenClause, CounterExampleType.WithoutEnum) when not(warningsGenerated.Contains(CounterExampleType.WithoutEnum)) -> - warning (MatchIncomplete(ignoreWithWarning, Some(text, failingWhenClause), mMatch, isForLoopBinding)) + warning (MatchIncomplete(ignoreWithWarning, Some(text, failingWhenClause), mMatch)) warningsGenerated.Add CounterExampleType.WithoutEnum | None when not(warningsGenerated.Contains(CounterExampleType.WithoutEnum)) -> - warning (MatchIncomplete(ignoreWithWarning, None, mMatch, isForLoopBinding)) + warning (MatchIncomplete(ignoreWithWarning, None, mMatch)) warningsGenerated.Add CounterExampleType.WithoutEnum | _ -> () | _ -> @@ -1709,7 +1712,7 @@ let isProblematicClause (clause: MatchClause) = let ips = investigationPoints clause.Pattern ips.Length > 0 && Span.exists id (ips.AsSpan (0, ips.Length - 1)) -let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) (clausesL: MatchClause list) inputTy resultTy = +let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) (clausesL: MatchClause list) inputTy resultTy = match clausesL with | _ when List.exists isProblematicClause clausesL -> @@ -1717,7 +1720,7 @@ let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused a let warnOnUnused = false // we can't turn this on since we're pretending all partials fail in order to control the complexity of this. let warnOnIncomplete = true let clausesPretendAllPartialFail = clausesL |> List.collect (fun (MatchClause(p, whenOpt, tg, m)) -> [MatchClause(erasePartialPatterns p, whenOpt, tg, m)]) - let _ = CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) clausesPretendAllPartialFail inputTy resultTy + let _ = CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) clausesPretendAllPartialFail inputTy resultTy let warnOnIncomplete = false // Partial and when clauses cause major code explosion if treated naively @@ -1725,7 +1728,7 @@ let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused a let rec atMostOneProblematicClauseAtATime clauses = match List.takeUntil isProblematicClause clauses with | l, [] -> - CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) l inputTy resultTy + CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) l inputTy resultTy | l, h :: t -> // Add the problematic clause. doGroupWithAtMostOneProblematic (l @ [h]) t @@ -1740,10 +1743,10 @@ let rec CompilePattern g denv amap tcVal infoReader mExpr mMatch warnOnUnused a // Make the clause that represents the remaining cases of the pattern match let clauseForRestOfMatch = MatchClause(TPat_wild mMatch, None, TTarget(List.empty, expr, None), mMatch) - CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) (group @ [clauseForRestOfMatch]) inputTy resultTy + CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused warnOnIncomplete actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) (group @ [clauseForRestOfMatch]) inputTy resultTy atMostOneProblematicClauseAtATime clausesL | _ -> - CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused true actionOnFailure isForLoopBinding (origInputVal, origInputValTypars, origInputExprOpt) clausesL inputTy resultTy + CompilePatternBasic g denv amap tcVal infoReader mExpr mMatch warnOnUnused true actionOnFailure (origInputVal, origInputValTypars, origInputExprOpt) clausesL inputTy resultTy diff --git a/src/Compiler/Checking/PatternMatchCompilation.fsi b/src/Compiler/Checking/PatternMatchCompilation.fsi index 7fdd3029323..de9ab0fe318 100644 --- a/src/Compiler/Checking/PatternMatchCompilation.fsi +++ b/src/Compiler/Checking/PatternMatchCompilation.fsi @@ -62,8 +62,6 @@ val internal CompilePattern: // warn on unused? bool -> ActionOnFailure -> - // is this a for-loop binding pattern? - bool -> Val * Typars * Expr option -> // input type-checked syntax of pattern matching MatchClause list -> @@ -74,10 +72,11 @@ val internal CompilePattern: DecisionTree * DecisionTreeTarget list /// Exception raised when a pattern match is incomplete. -/// Fields: isComputationExpression * (counterExample * isShownAsFieldPattern) option * range * isForLoopBinding -/// The isForLoopBinding flag indicates the match originated from a for-loop pattern (e.g., `for 1 in xs`), -/// which changes the diagnostic hint to suggest using a wildcard pattern. -exception internal MatchIncomplete of bool * (string * bool) option * range * bool +/// Fields: isComputationExpression * (counterExample * isShownAsFieldPattern) option * range +exception internal MatchIncomplete of bool * (string * bool) option * range + +/// Wrapper that adds a for-loop hint to an existing MatchIncomplete diagnostic. +exception internal MatchIncompleteForLoopHint of exn exception internal RuleNeverMatched of range diff --git a/src/Compiler/Driver/CompilerDiagnostics.fs b/src/Compiler/Driver/CompilerDiagnostics.fs index 25795c32b9e..377e329bd87 100644 --- a/src/Compiler/Driver/CompilerDiagnostics.fs +++ b/src/Compiler/Driver/CompilerDiagnostics.fs @@ -125,7 +125,8 @@ type Exception with | InternalException(_, _, m) | InterfaceNotRevealed(_, _, m) | WrappedError(_, m) - | PatternMatchCompilation.MatchIncomplete(_, _, m, _) + | PatternMatchCompilation.MatchIncomplete(_, _, m) + | PatternMatchCompilation.MatchIncompleteForLoopHint(PatternMatchCompilation.MatchIncomplete(_, _, m)) | PatternMatchCompilation.EnumMatchIncomplete(_, _, m) | PatternMatchCompilation.RuleNeverMatched m | ValNotMutable(_, _, m) @@ -238,6 +239,7 @@ type Exception with | NameClash _ -> 23 // 24 cannot be reused | PatternMatchCompilation.MatchIncomplete _ -> 25 + | PatternMatchCompilation.MatchIncompleteForLoopHint _ -> 25 | PatternMatchCompilation.RuleNeverMatched _ -> 26 | ValNotMutable _ -> 27 @@ -1791,7 +1793,7 @@ type Exception with | WrappedError(e, _) -> e.Output(os, suggestNames) - | PatternMatchCompilation.MatchIncomplete(isComp, cexOpt, _, isForLoop) -> + | PatternMatchCompilation.MatchIncomplete(isComp, cexOpt, _) -> os.AppendString(MatchIncomplete1E().Format) match cexOpt with @@ -1799,8 +1801,18 @@ type Exception with | Some(cex, false) -> os.AppendString(MatchIncomplete2E().Format cex) | Some(cex, true) -> os.AppendString(MatchIncomplete3E().Format cex) - if isForLoop then - os.AppendString(MatchIncompleteForLoopE().Format) + if isComp then + os.AppendString(MatchIncomplete4E().Format) + + | PatternMatchCompilation.MatchIncompleteForLoopHint(PatternMatchCompilation.MatchIncomplete(isComp, cexOpt, _)) -> + os.AppendString(MatchIncomplete1E().Format) + + match cexOpt with + | None -> () + | Some(cex, false) -> os.AppendString(MatchIncomplete2E().Format cex) + | Some(cex, true) -> os.AppendString(MatchIncomplete3E().Format cex) + + os.AppendString(MatchIncompleteForLoopE().Format) if isComp then os.AppendString(MatchIncomplete4E().Format) From 5514168993af90b40d755edc7a93226b7d09d9cf Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 6 Mar 2026 18:54:49 +0100 Subject: [PATCH 35/39] Move release notes to 11.0.100, remove from 10.0.300 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- docs/release-notes/.FSharp.Compiler.Service/10.0.300.md | 2 +- docs/release-notes/.FSharp.Compiler.Service/11.0.100.md | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 docs/release-notes/.FSharp.Compiler.Service/11.0.100.md diff --git a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md index 5b0b83a46a5..7c6e8a886e1 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md +++ b/docs/release-notes/.FSharp.Compiler.Service/10.0.300.md @@ -37,6 +37,6 @@ * Centralized product TFM (Target Framework Moniker) into MSBuild props file `eng/TargetFrameworks.props`. Changing the target framework now only requires editing one file, and it integrates with MSBuild's `--getProperty` for scripts. * Overload resolution results are now cached, providing compile time improvements for code with repeated method calls. ([Issue #18807](https://github.com/dotnet/fsharp/issues/18807)) * Symbols: safer qualified name getting ([PR #19298](https://github.com/dotnet/fsharp/pull/19298)) -* Improved diagnostic messages for FS0003, FS0025, FS0039, FS0072, FS0247, FS0597, FS0670, FS3082, and type mismatch errors involving tuples. Added new warnings FS3884 (let!/use! at end of computation expression) and FS3885 (comma vs semicolon confusion in list literals). Added elif-chain detection for missing else branch errors, context-aware hints for incomplete matches in for-loops, and operator scope hints for SRTP errors. + ### Breaking Changes diff --git a/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md new file mode 100644 index 00000000000..505e290dd76 --- /dev/null +++ b/docs/release-notes/.FSharp.Compiler.Service/11.0.100.md @@ -0,0 +1,9 @@ +### Fixed + +### Added + +### Changed + +* Improvements in error and warning messages. ([PR #19398](https://github.com/dotnet/fsharp/pull/19398)) + +### Breaking Changes From 21eb9759040307661f5706db2ce74b1c1d36418b Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 6 Mar 2026 21:56:15 +0100 Subject: [PATCH 36/39] Fix invalid XLF state attribute causing all CI failures Change state="needs-review" to state="new" in all 13 XLF files for the csExpectTypeWithOperatorButGivenTuple trans-unit. "needs-review" is not a valid XLIFF 1.2 state value. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- src/Compiler/xlf/FSComp.txt.cs.xlf | 2 +- src/Compiler/xlf/FSComp.txt.de.xlf | 2 +- src/Compiler/xlf/FSComp.txt.es.xlf | 2 +- src/Compiler/xlf/FSComp.txt.fr.xlf | 2 +- src/Compiler/xlf/FSComp.txt.it.xlf | 2 +- src/Compiler/xlf/FSComp.txt.ja.xlf | 2 +- src/Compiler/xlf/FSComp.txt.ko.xlf | 2 +- src/Compiler/xlf/FSComp.txt.pl.xlf | 2 +- src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 2 +- src/Compiler/xlf/FSComp.txt.ru.xlf | 2 +- src/Compiler/xlf/FSComp.txt.tr.xlf | 2 +- src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 2 +- src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 7263a236753..e20fc176483 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - Očekává se typ podporující operátor {0}, ale předává se typ řazené kolekce členů. + Očekává se typ podporující operátor {0}, ale předává se typ řazené kolekce členů. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 3c3d32e894f..90dc1afc630 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - Ein unterstützender Typ für den Operator '{0}' wurde erwartet, aber ein Tupeltyp wurde empfangen + Ein unterstützender Typ für den Operator '{0}' wurde erwartet, aber ein Tupeltyp wurde empfangen diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index bbd306a51d4..e9391956d33 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - Se espera un tipo que admita el operador '{0}', pero se ha proporcionado un tipo de tupla. + Se espera un tipo que admita el operador '{0}', pero se ha proporcionado un tipo de tupla. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 059dca39308..5dee74c332e 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - Un type prenant en charge l'opérateur '{0}' est attendu, mais un type tuple a été reçu + Un type prenant en charge l'opérateur '{0}' est attendu, mais un type tuple a été reçu diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 9f10faba18f..fc49252a516 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - È previsto un tipo che supporti l'operatore '{0}', tuttavia è specificato un tipo di tuple + È previsto un tipo che supporti l'operatore '{0}', tuttavia è specificato un tipo di tuple diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index ee73e95faae..e22ed69fb57 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - 演算子 '{0}' をサポートする型が必要ですが、タプル型が指定されました + 演算子 '{0}' をサポートする型が必要ですが、タプル型が指定されました diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index ab61c0e4356..961fd4233c2 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - '{0}' 연산자를 지원하는 형식이 필요한데 튜플 형식을 지정했습니다. + '{0}' 연산자를 지원하는 형식이 필요한데 튜플 형식을 지정했습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index d08ba3af5a6..18b8bc3049e 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - Oczekiwany jest typ obsługujący operator „{0}”, ale podano typ krotki + Oczekiwany jest typ obsługujący operator „{0}”, ale podano typ krotki diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index d028b4bddb1..86df9963f4f 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - Um tipo que suporte o operador '{0}' era esperado, mas um tipo de tupla foi recebido. + Um tipo que suporte o operador '{0}' era esperado, mas um tipo de tupla foi recebido. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 3e8231cb58e..f84e8dd6739 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - Ожидался тип, поддерживающий оператор "{0}", однако указан кортежный тип + Ожидался тип, поддерживающий оператор "{0}", однако указан кортежный тип diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index a69cbd8c716..f0634eebe1e 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - '{0}' işlecini destekleyen bir tür bekleniyor ancak bir demet türü verildi. + '{0}' işlecini destekleyen bir tür bekleniyor ancak bir demet türü verildi. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index a1dd34d337d..e2c67189922 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - 需要一个支持运算符“{0}”的类型,但提供的是元组类型 + 需要一个支持运算符“{0}”的类型,但提供的是元组类型 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index b2901093395..675d77a38fc 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -3374,7 +3374,7 @@ Operator '{0}' cannot be applied to a tuple type. You may have an unintended extra comma creating a tuple, or the operator may not be in scope. Check that you have opened the correct module or namespace. - 必須是支援運算子 '{0}' 的型別,但指定的是元組型別 + 必須是支援運算子 '{0}' 的型別,但指定的是元組型別 From 033a7c79d5b6b8ef9870bfcf7f432666164d0b84 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Tue, 10 Mar 2026 17:33:24 +0100 Subject: [PATCH 37/39] Fix CI: update tests for new diagnostic messages - Suppress warning 3886 (tcListLiteralWithSingleTupleElement) in tests that legitimately use single-tuple list expressions [a, b] (StateMachineTests, InferenceForLambdaArgs, AgedLookup, RelaxWhitespace2, ExprTests Project1) - Update PropertyShadowing baselines for 'but is a tuple of type' message variant (ErrorFromAddingTypeEquation1Tuple) - Update DocumentDiagnosticAnalyzerTests for notAFunctionWithType message that now includes the type name - Update SyntaxTree ParseFile baselines to include new parsLetBangCannotBeLastInCE (3885) diagnostic - Update AndBang CE test to expect both error 10 and error 3885 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../OverloadingMembers/OverloadingMembers.fs | 1 + .../LexicalFiltering/OffsideExceptions/OffsideExceptions.fs | 3 ++- .../RealInternalSignature/ClassTypeInitialization.fs | 1 + .../Language/StateMachineTests.fs | 1 + ...CannotShadowIndexedPropertyWithExtensionMethod.fsx.err.bsl | 2 +- ...E_CannotShadowIndexedPropertyWithTypeExtension.fsx.err.bsl | 2 +- tests/FSharp.Compiler.Service.Tests/ExprTests.fs | 4 ++-- .../Conformance/DataExpressions/ComputationExpressions.fs | 3 ++- tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs.bsl | 1 + tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs.bsl | 1 + tests/service/data/SyntaxTree/SynType/Typed LetBang 17.fs.bsl | 1 + tests/service/data/SyntaxTree/SynType/Typed LetBang 18.fs.bsl | 1 + .../data/SyntaxTree/SynType/Typed LetBang AndBang 15.fs.bsl | 1 + tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs.bsl | 1 + tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs.bsl | 1 + .../FSharp.Editor.Tests/DocumentDiagnosticAnalyzerTests.fs | 4 ++-- 16 files changed, 20 insertions(+), 8 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OverloadingMembers/OverloadingMembers.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OverloadingMembers/OverloadingMembers.fs index c15706a3e3c..e98999930b6 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OverloadingMembers/OverloadingMembers.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/BasicGrammarElements/MemberDefinitions/OverloadingMembers/OverloadingMembers.fs @@ -128,6 +128,7 @@ module MemberDefinitions_OverloadingMembers = [] let ``InferenceForLambdaArgs_fs`` compilation = compilation + |> withOptions [ "--nowarn:3886" ] |> verifyCompileAndRun |> shouldSucceed diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/OffsideExceptions.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/OffsideExceptions.fs index 03730240066..8153a9e44bc 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/OffsideExceptions.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/LexicalFiltering/OffsideExceptions/OffsideExceptions.fs @@ -27,7 +27,7 @@ module OffsideExceptions = |> getCompilation |> asFsx |> withLangVersion80 - |> withOptions ["--nowarn:25"] // Incomplete pattern matches on this expression. + |> withOptions ["--nowarn:25"; "--nowarn:3886"] // Incomplete pattern matches on this expression. |> typecheck |> shouldSucceed |> ignore @@ -38,6 +38,7 @@ module OffsideExceptions = |> getCompilation |> asFsx |> withLangVersion80 + |> withOptions ["--nowarn:3886"] |> typecheck |> verifyBaseline diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeInitialization.fs b/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeInitialization.fs index 981b2e5d95a..33ebc04f71d 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeInitialization.fs +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/RealInternalSignature/ClassTypeInitialization.fs @@ -778,6 +778,7 @@ type internal AgedLookup<'Token, 'Key, 'Value when 'Value: not struct>(keepStron |> asLibrary |> withRealInternalSignature realSig |> withOptimization optimize + |> withOptions [ "--nowarn:3886" ] |> compile |> shouldSucceed |> verifyPEFileWithSystemDlls diff --git a/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs index f7d2ebb906c..91877d4d338 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs @@ -243,6 +243,7 @@ let test = task { () } """ + |> withOptions [ "--nowarn:3886" ] |> compile |> verifyIL [ ".override [runtime]System.Runtime.CompilerServices.IAsyncStateMachine::MoveNext" ] diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_CannotShadowIndexedPropertyWithExtensionMethod.fsx.err.bsl b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_CannotShadowIndexedPropertyWithExtensionMethod.fsx.err.bsl index a7537411869..31d98f56d21 100644 --- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_CannotShadowIndexedPropertyWithExtensionMethod.fsx.err.bsl +++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_CannotShadowIndexedPropertyWithExtensionMethod.fsx.err.bsl @@ -1,4 +1,4 @@ E_CannotShadowIndexedPropertyWithExtensionMethod.fsx (23,5)-(23,8) typecheck error This expression was expected to have type 'int' -but here has type +but is a tuple of type 'int * int' \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_CannotShadowIndexedPropertyWithTypeExtension.fsx.err.bsl b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_CannotShadowIndexedPropertyWithTypeExtension.fsx.err.bsl index ec65c7a754b..23fd58d3384 100644 --- a/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_CannotShadowIndexedPropertyWithTypeExtension.fsx.err.bsl +++ b/tests/FSharp.Compiler.ComponentTests/TypeChecks/Shadowing/E_CannotShadowIndexedPropertyWithTypeExtension.fsx.err.bsl @@ -1,4 +1,4 @@ E_CannotShadowIndexedPropertyWithTypeExtension.fsx (20,5)-(20,8) typecheck error This expression was expected to have type 'int' -but here has type +but is a tuple of type 'int * int' \ No newline at end of file diff --git a/tests/FSharp.Compiler.Service.Tests/ExprTests.fs b/tests/FSharp.Compiler.Service.Tests/ExprTests.fs index f628870119a..e2cb6787ebd 100644 --- a/tests/FSharp.Compiler.Service.Tests/ExprTests.fs +++ b/tests/FSharp.Compiler.Service.Tests/ExprTests.fs @@ -661,7 +661,7 @@ let test{0}ToStringOperator (e1:{1}) = string e1 /// This test is run in unison with its optimized counterpart below [] let ``Test Unoptimized Declarations Project1`` () = - let options = Project1.createOptionsWithArgs [ "--langversion:preview" ] + let options = Project1.createOptionsWithArgs [ "--langversion:preview"; "--nowarn:3886" ] let exprChecker = FSharpChecker.Create(keepAssemblyContents=true, useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let wholeProjectResults = exprChecker.ParseAndCheckProject(options) |> Async.RunImmediate @@ -799,7 +799,7 @@ let ``Test Unoptimized Declarations Project1`` () = [] let ``Test Optimized Declarations Project1`` () = - let options = Project1.createOptionsWithArgs [ "--langversion:preview" ] + let options = Project1.createOptionsWithArgs [ "--langversion:preview"; "--nowarn:3886" ] let exprChecker = FSharpChecker.Create(keepAssemblyContents=true, useTransparentCompiler=CompilerAssertHelpers.UseTransparentCompiler) let wholeProjectResults = exprChecker.ParseAndCheckProject(options) |> Async.RunImmediate diff --git a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs index 09c378ba67a..f90de327250 100644 --- a/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs +++ b/tests/fsharp/Compiler/Conformance/DataExpressions/ComputationExpressions.fs @@ -646,7 +646,8 @@ let _ = and! y = Trace 2 } """ - [|(FSharpDiagnosticSeverity.Error, 10, (8, 5, 8, 6), "Unexpected symbol '}' in expression")|] + [|(FSharpDiagnosticSeverity.Error, 10, (8, 5, 8, 6), "Unexpected symbol '}' in expression") + (FSharpDiagnosticSeverity.Error, 3885, (6, 9, 6, 13), "'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression.")|] [] let ``AndBang TraceApplicative conditional return`` () = diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs.bsl index c83def28fd5..79dcf26f244 100644 --- a/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs.bsl +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 05.fs.bsl @@ -72,3 +72,4 @@ ImplFile CodeComments = [] }, set [])) (3,0)-(3,33) parse error Incomplete structured construct at or before this point in expression +(3,0)-(3,4) parse error 'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs.bsl index 7ead12b4fe7..c3216411b4c 100644 --- a/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs.bsl +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 06.fs.bsl @@ -70,3 +70,4 @@ ImplFile CodeComments = [] }, set [])) (3,0)-(3,33) parse error Incomplete structured construct at or before this point in expression +(3,0)-(3,4) parse error 'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 17.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 17.fs.bsl index 05b7904bbfe..10285a69804 100644 --- a/tests/service/data/SyntaxTree/SynType/Typed LetBang 17.fs.bsl +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 17.fs.bsl @@ -68,3 +68,4 @@ ImplFile CodeComments = [] }, set [])) (5,0)-(5,42) parse error Incomplete structured construct at or before this point in expression +(5,0)-(5,4) parse error 'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang 18.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang 18.fs.bsl index f91a64c545e..4b24e167434 100644 --- a/tests/service/data/SyntaxTree/SynType/Typed LetBang 18.fs.bsl +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang 18.fs.bsl @@ -71,3 +71,4 @@ ImplFile CodeComments = [] }, set [])) (5,0)-(5,40) parse error Incomplete structured construct at or before this point in expression +(5,0)-(5,4) parse error 'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. diff --git a/tests/service/data/SyntaxTree/SynType/Typed LetBang AndBang 15.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed LetBang AndBang 15.fs.bsl index a78918b83c4..52815797a5e 100644 --- a/tests/service/data/SyntaxTree/SynType/Typed LetBang AndBang 15.fs.bsl +++ b/tests/service/data/SyntaxTree/SynType/Typed LetBang AndBang 15.fs.bsl @@ -64,3 +64,4 @@ ImplFile CodeComments = [] }, set [])) (5,15)-(5,16) parse error Unexpected symbol ',' in expression. Expected '=' or other token. +(4,4)-(4,8) parse error 'let!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs.bsl index 90ab130d7a1..1d66a9d611b 100644 --- a/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs.bsl +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 03.fs.bsl @@ -72,3 +72,4 @@ ImplFile CodeComments = [] }, set [])) (4,0)-(4,33) parse error Incomplete structured construct at or before this point in expression +(4,0)-(4,4) parse error 'use!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. diff --git a/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs.bsl b/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs.bsl index 65c4a779fc4..dd8a4b67468 100644 --- a/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs.bsl +++ b/tests/service/data/SyntaxTree/SynType/Typed UseBang 04.fs.bsl @@ -70,3 +70,4 @@ ImplFile CodeComments = [] }, set [])) (4,0)-(4,33) parse error Incomplete structured construct at or before this point in expression +(4,0)-(4,4) parse error 'use!' cannot be the final expression in a computation expression. Finish with 'return', 'return!', or a simple expression. diff --git a/vsintegration/tests/FSharp.Editor.Tests/DocumentDiagnosticAnalyzerTests.fs b/vsintegration/tests/FSharp.Editor.Tests/DocumentDiagnosticAnalyzerTests.fs index 51efbb4fcf2..8f2843f8a76 100644 --- a/vsintegration/tests/FSharp.Editor.Tests/DocumentDiagnosticAnalyzerTests.fs +++ b/vsintegration/tests/FSharp.Editor.Tests/DocumentDiagnosticAnalyzerTests.fs @@ -362,7 +362,7 @@ let x = 3 let y = (*start*)x(*end*) 4 let arr = [| 1; 2; 3 |] """, - expectedMessage = "This value is not a function and cannot be applied." + expectedMessage = "This value is not a function and cannot be applied. It has type 'int', which does not accept arguments." ) [] @@ -373,7 +373,7 @@ let arr = [| 1; 2; 3 |] let f x = x + 1 let r = (*start*)f 3(*end*) 4 """, - expectedMessage = "This value is not a function and cannot be applied." + expectedMessage = "This value is not a function and cannot be applied. It has type 'int', which does not accept arguments." ) [] From 0ea798f2e965f1d8ed353a80606ae30c8e17f447 Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 13 Mar 2026 15:53:42 +0100 Subject: [PATCH 38/39] Fix CI: correct test baselines for diagnostic message changes - neg118.bsl/neg123.bsl: SRTP type parameters use isTyparTy path, so FS0003 message has no type suffix (revert incorrect update) - neg135.vsbsl: async { return true } has type Async, not AsyncBuilder - neg04.bsl: tuple type (int * int) uses 'but is a tuple of type' wording Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- tests/fsharp/typecheck/sigs/neg04.bsl | 2 +- tests/fsharp/typecheck/sigs/neg118.bsl | 12 ++++++------ tests/fsharp/typecheck/sigs/neg123.bsl | 4 ++-- tests/fsharp/typecheck/sigs/neg135.vsbsl | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/fsharp/typecheck/sigs/neg04.bsl b/tests/fsharp/typecheck/sigs/neg04.bsl index 119c1ef38cf..824aacb8869 100644 --- a/tests/fsharp/typecheck/sigs/neg04.bsl +++ b/tests/fsharp/typecheck/sigs/neg04.bsl @@ -59,7 +59,7 @@ neg04.fs(76,10,76,12): typecheck error FS0663: This type parameter has been used neg04.fs(81,58,81,61): typecheck error FS0001: This expression was expected to have type 'int' -but here has type +but is a tuple of type 'int * int' neg04.fs(83,39,83,46): typecheck error FS0752: The operator 'expr.[idx]' has been used on an object of indeterminate type based on information prior to this program point. Consider adding further type constraints diff --git a/tests/fsharp/typecheck/sigs/neg118.bsl b/tests/fsharp/typecheck/sigs/neg118.bsl index b3552cb686b..7b70803cc6c 100644 --- a/tests/fsharp/typecheck/sigs/neg118.bsl +++ b/tests/fsharp/typecheck/sigs/neg118.bsl @@ -1,12 +1,12 @@ -neg118.fs(18,21,18,37): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'int', which does not accept arguments. +neg118.fs(18,21,18,37): typecheck error FS0003: This value is not a function and cannot be applied. -neg118.fs(19,21,19,37): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'int', which does not accept arguments. +neg118.fs(19,21,19,37): typecheck error FS0003: This value is not a function and cannot be applied. -neg118.fs(20,21,20,39): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'decimal', which does not accept arguments. +neg118.fs(20,21,20,39): typecheck error FS0003: This value is not a function and cannot be applied. -neg118.fs(21,21,21,41): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'string', which does not accept arguments. +neg118.fs(21,21,21,41): typecheck error FS0003: This value is not a function and cannot be applied. -neg118.fs(22,21,22,39): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'float', which does not accept arguments. +neg118.fs(22,21,22,39): typecheck error FS0003: This value is not a function and cannot be applied. -neg118.fs(25,51,25,67): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'int', which does not accept arguments. +neg118.fs(25,51,25,67): typecheck error FS0003: This value is not a function and cannot be applied. diff --git a/tests/fsharp/typecheck/sigs/neg123.bsl b/tests/fsharp/typecheck/sigs/neg123.bsl index 9d865364c12..3964ae9865a 100644 --- a/tests/fsharp/typecheck/sigs/neg123.bsl +++ b/tests/fsharp/typecheck/sigs/neg123.bsl @@ -1,2 +1,2 @@ - -neg123.fs(19,18,19,27): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'unit', which does not accept arguments. + +neg123.fs(19,18,19,27): typecheck error FS0003: This value is not a function and cannot be applied. diff --git a/tests/fsharp/typecheck/sigs/neg135.vsbsl b/tests/fsharp/typecheck/sigs/neg135.vsbsl index 03ec06fd560..96083778399 100644 --- a/tests/fsharp/typecheck/sigs/neg135.vsbsl +++ b/tests/fsharp/typecheck/sigs/neg135.vsbsl @@ -3,6 +3,6 @@ neg135.fs(6,1,6,2): parse error FS0010: Unexpected symbol '}' in expression neg135.fs(4,5,4,11): parse error FS3122: Missing 'do' in 'while' expression. Expected 'while do '. -neg135.fs(4,12,4,17): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'AsyncBuilder', which does not accept arguments. +neg135.fs(4,12,4,17): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'Async', which does not accept arguments. -neg135.fs(4,12,4,17): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'AsyncBuilder', which does not accept arguments. +neg135.fs(4,12,4,17): typecheck error FS0003: This value is not a function and cannot be applied. It has type 'Async', which does not accept arguments. From 2a8524ef070d0e8d58c5ad300110dd201b74e08e Mon Sep 17 00:00:00 2001 From: Tomas Grosup Date: Fri, 13 Mar 2026 18:00:18 +0100 Subject: [PATCH 39/39] Remove accidentally committed .copilot-pid file Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .copilot-pid | 1 - 1 file changed, 1 deletion(-) delete mode 100644 .copilot-pid diff --git a/.copilot-pid b/.copilot-pid deleted file mode 100644 index 90adf1ca96c..00000000000 --- a/.copilot-pid +++ /dev/null @@ -1 +0,0 @@ -50088 \ No newline at end of file