From 89e641108e8773e8d5731437a2b944510de52567 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 19 Apr 2024 15:28:57 +0100 Subject: [PATCH] Improve error reporting for abstract members when used in classes (#17063) * Improve error reporting for abstract members when used in classes * Revert "Improve error reporting for abstract members when used in classes" This reverts commit 49f472296a3c805427ad8d1253dfb4d9c04c4342. * Improve error reporting for abstract members when used in classes * Update tests * more tests * update tests * release notes * more tests * Update src/Compiler/FSStrings.resx Co-authored-by: Tomas Grosup * Update error messages * Update src/Compiler/FSStrings.resx Co-authored-by: Petr * Another one --------- Co-authored-by: Tomas Grosup Co-authored-by: Petr --- .../.FSharp.Compiler.Service/8.0.400.md | 1 + src/Compiler/Checking/MethodOverrides.fs | 2 +- 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 +-- .../Basic/Basic.fs | 3 -- .../Types/UnionTypes/UnionStructTypes.fs | 12 +++++++ .../Types/UnionTypes/UnionTypes.fs | 12 +++++++ .../Diagnostics/Records.fs | 13 ++++++- .../ErrorMessages/ClassesTests.fs | 35 ++++++++++++++++++- tests/fsharp/typecheck/sigs/neg44.bsl | 2 +- ...ClassNotImplAllInheritedAbstractSlots01.fs | 2 +- .../E_CallToAbstractMember03.fs | 2 +- .../E_Sealed_Member_Override02.fsx | 2 +- .../ClassTypes/Misc/E_AbstractClass01.fs | 4 +-- .../TypeKindInference/infer_interface003e.fs | 4 +-- 27 files changed, 107 insertions(+), 41 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index 71aa4a0d3ed..56eed1f56bc 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -1,5 +1,6 @@ ### Fixed +* Improve error reporting for abstract members when used in classes. ([PR #17063](https://github.com/dotnet/fsharp/pull/17063)) * Make typechecking of indexed setters with tuples on the right more consistent. ([Issue #16987](https://github.com/dotnet/fsharp/issues/16987), [PR #17017](https://github.com/dotnet/fsharp/pull/17017)) * Static abstract method on classes no longer yields internal error. ([Issue #17044](https://github.com/dotnet/fsharp/issues/17044), [PR #17055](https://github.com/dotnet/fsharp/pull/17055)) * Disallow calling abstract methods directly on interfaces. ([Issue #14012](https://github.com/dotnet/fsharp/issues/14012), [Issue #16299](https://github.com/dotnet/fsharp/issues/16299), [PR #17021](https://github.com/dotnet/fsharp/pull/17021)) diff --git a/src/Compiler/Checking/MethodOverrides.fs b/src/Compiler/Checking/MethodOverrides.fs index b166d7fc07a..7d41026582a 100644 --- a/src/Compiler/Checking/MethodOverrides.fs +++ b/src/Compiler/Checking/MethodOverrides.fs @@ -831,7 +831,7 @@ module DispatchSlotChecking = let allCorrect = CheckDispatchSlotsAreImplemented (denv, infoReader, m, nenv, sink, tcaug.tcaug_abstract, false, reqdTy, dispatchSlots, availPriorOverrides, overrides) // Tell the user to mark the thing abstract if it was missing implementations - if not allCorrect && not tcaug.tcaug_abstract && not (isInterfaceTy g reqdTy) then + if not allCorrect && not tcaug.tcaug_abstract && (isClassTy g reqdTy) then errorR(TypeIsImplicitlyAbstract(m)) let overridesToCheck = diff --git a/src/Compiler/FSStrings.resx b/src/Compiler/FSStrings.resx index d5e19724c80..73ae2901566 100644 --- a/src/Compiler/FSStrings.resx +++ b/src/Compiler/FSStrings.resx @@ -220,7 +220,7 @@ A coercion from the value type \n {0} \nto the type \n {1} \nwill involve boxing. Consider using 'box' instead - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. This construct causes code to be less generic than indicated by its type annotations. The type variable implied by the use of a '#', '_' or other type annotation at or near '{0}' has been constrained to be type '{1}'. diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf index 51770445099..8fa85e6c640 100644 --- a/src/Compiler/xlf/FSStrings.cs.xlf +++ b/src/Compiler/xlf/FSStrings.cs.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - Tento typ je abstract, protože se neimplementovali někteří abstraktní členové. Pokud je to záměr, pak k typu přidejte atribut [<AbstractClass>]. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + Tento typ je abstract, protože se neimplementovali někteří abstraktní členové. Pokud je to záměr, pak k typu přidejte atribut [<AbstractClass>]. diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf index 816fe236526..46c2c4eb4f1 100644 --- a/src/Compiler/xlf/FSStrings.de.xlf +++ b/src/Compiler/xlf/FSStrings.de.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - Der Typ entspricht „abstract“, da einige abstrakte Member nicht mit einer Implementierung versehen wurden. Wenn dies Ihre Absicht ist, fügen Sie das [<AbstractClass>]-Attribut zu Ihrem Typ hinzu. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + Der Typ entspricht „abstract“, da einige abstrakte Member nicht mit einer Implementierung versehen wurden. Wenn dies Ihre Absicht ist, fügen Sie das [<AbstractClass>]-Attribut zu Ihrem Typ hinzu. diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf index 5230e06b774..0009c7dd034 100644 --- a/src/Compiler/xlf/FSStrings.es.xlf +++ b/src/Compiler/xlf/FSStrings.es.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - Este tipo es "abstract" ya que a algunos miembros abstractos no se les ha dado una implementación. Si esto es intencional, agregue el atributo "[<AbstractClass>]" + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + Este tipo es "abstract" ya que a algunos miembros abstractos no se les ha dado una implementación. Si esto es intencional, agregue el atributo "[<AbstractClass>]" diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf index 059408c760b..788fbf8d78d 100644 --- a/src/Compiler/xlf/FSStrings.fr.xlf +++ b/src/Compiler/xlf/FSStrings.fr.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - Ce type est 'abstract', car des membres abstraits n'ont pas reçu d'implémentation. Si cela est intentionnel, ajoutez l'attribut '[<AbstractClass>]' à votre type. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + Ce type est 'abstract', car des membres abstraits n'ont pas reçu d'implémentation. Si cela est intentionnel, ajoutez l'attribut '[<AbstractClass>]' à votre type. diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf index 3e79188ed4b..98994f92f88 100644 --- a/src/Compiler/xlf/FSStrings.it.xlf +++ b/src/Compiler/xlf/FSStrings.it.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - Questo tipo è 'abstract' perché non è stata specificata un'implementazione per alcuni membri astratti. Se questa scelta è intenzionale, aggiungere l'attributo '[<AbstractClass>]' al tipo. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + Questo tipo è 'abstract' perché non è stata specificata un'implementazione per alcuni membri astratti. Se questa scelta è intenzionale, aggiungere l'attributo '[<AbstractClass>]' al tipo. diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf index 7aea227ec19..e48f47c0f6f 100644 --- a/src/Compiler/xlf/FSStrings.ja.xlf +++ b/src/Compiler/xlf/FSStrings.ja.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - これは 'abstract' 型です。一部の抽象メンバーに実装がありません。意図的な場合には、型に '[<AbstractClass>]' 属性を追加してください。 + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + これは 'abstract' 型です。一部の抽象メンバーに実装がありません。意図的な場合には、型に '[<AbstractClass>]' 属性を追加してください。 diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf index 825f5d99b9f..31481aa4566 100644 --- a/src/Compiler/xlf/FSStrings.ko.xlf +++ b/src/Compiler/xlf/FSStrings.ko.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - 일부 추상 멤버에 구현이 지정되지 않았으므로 이 형식은 'abstract'입니다. 의도적으로 구현을 지정하지 않은 경우에는 형식에 '[<AbstractClass>]' 특성을 추가하세요. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + 일부 추상 멤버에 구현이 지정되지 않았으므로 이 형식은 'abstract'입니다. 의도적으로 구현을 지정하지 않은 경우에는 형식에 '[<AbstractClass>]' 특성을 추가하세요. diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf index 0de699e9f96..8dde95ed7e9 100644 --- a/src/Compiler/xlf/FSStrings.pl.xlf +++ b/src/Compiler/xlf/FSStrings.pl.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - Ten typ ma wartość „abstract”, ponieważ niektóre abstrakcyjne składowe nie mają określonej implementacji. Jeśli jest to zamierzone działanie, dodaj atrybut „[<AbstractClass>]” do typu. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + Ten typ ma wartość „abstract”, ponieważ niektóre abstrakcyjne składowe nie mają określonej implementacji. Jeśli jest to zamierzone działanie, dodaj atrybut „[<AbstractClass>]” do typu. diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf index 9f1aaba8b97..5c17c16072b 100644 --- a/src/Compiler/xlf/FSStrings.pt-BR.xlf +++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - Esse tipo é 'abstrato', pois alguns membros abstratos não receberam uma implementação. Se isso for intencional, adicione o atributo '[<AbstractClass>]' ao seu tipo. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + Esse tipo é 'abstrato', pois alguns membros abstratos não receberam uma implementação. Se isso for intencional, adicione o atributo '[<AbstractClass>]' ao seu tipo. diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf index 0da994d81bb..07467917126 100644 --- a/src/Compiler/xlf/FSStrings.ru.xlf +++ b/src/Compiler/xlf/FSStrings.ru.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - Этот тип является абстрактным ('abstract'), так как для нескольких абстрактных членов не указана реализация. Если это сделано намеренно, добавьте атрибут '[<AbstractClass>]' к своему типу. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + Этот тип является абстрактным ('abstract'), так как для нескольких абстрактных членов не указана реализация. Если это сделано намеренно, добавьте атрибут '[<AbstractClass>]' к своему типу. diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf index d7095e4c6f3..c4123c8a985 100644 --- a/src/Compiler/xlf/FSStrings.tr.xlf +++ b/src/Compiler/xlf/FSStrings.tr.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - Bazı soyut üyelere bir uygulama verilmediğinden bu bir 'abstract' türdür. Bu bilerek yapıldıysa türünüze '[<AbstractClass>]' özniteliğini ekleyin. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + Bazı soyut üyelere bir uygulama verilmediğinden bu bir 'abstract' türdür. Bu bilerek yapıldıysa türünüze '[<AbstractClass>]' özniteliğini ekleyin. diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf index 2371bf01202..4af6f427ebd 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - 由于未向一些抽象成员提供实现,因此该类型为 "abstract"。如果是故意如此,请向你的类型添加 "[<AbstractClass>]" 属性。 + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + 由于未向一些抽象成员提供实现,因此该类型为 "abstract"。如果是故意如此,请向你的类型添加 "[<AbstractClass>]" 属性。 diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf index 1cb1d903cf7..d945cbe3d33 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf @@ -248,8 +248,8 @@ - This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[<AbstractClass>]' attribute to your type. - 因為未提供實作給某些抽象成員,所以此類型為 'abstract'。如果這是預期的情況,則請將 '[<AbstractClass>]' 屬性新增到您的類型。 + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. + 因為未提供實作給某些抽象成員,所以此類型為 'abstract'。如果這是預期的情況,則請將 '[<AbstractClass>]' 屬性新增到您的類型。 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/GeneratedEqualityHashingComparison/Basic/Basic.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/GeneratedEqualityHashingComparison/Basic/Basic.fs index 76203d10cda..c3a239e07f0 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/GeneratedEqualityHashingComparison/Basic/Basic.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/GeneratedEqualityHashingComparison/Basic/Basic.fs @@ -62,15 +62,12 @@ module Basic = (Error 344, Line 13, Col 6, Line 13, Col 7, "The struct, record or union type 'R' has an explicit implementation of 'Object.GetHashCode' or 'Object.Equals'. You must apply the 'CustomEquality' attribute to the type") (Warning 345, Line 13, Col 6, Line 13, Col 7, "The struct, record or union type 'R' has an explicit implementation of 'Object.GetHashCode'. Consider implementing a matching override for 'Object.Equals(obj)'") (Error 359, Line 13, Col 6, Line 13, Col 7, "More than one override implements 'GetHashCode: unit -> int'") - (Error 54, Line 13, Col 6, Line 13, Col 7, "This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[]' attribute to your type.") (Error 344, Line 17, Col 6, Line 17, Col 7, "The struct, record or union type 'U' has an explicit implementation of 'Object.GetHashCode' or 'Object.Equals'. You must apply the 'CustomEquality' attribute to the type") (Warning 345, Line 17, Col 6, Line 17, Col 7, "The struct, record or union type 'U' has an explicit implementation of 'Object.GetHashCode'. Consider implementing a matching override for 'Object.Equals(obj)'") (Error 359, Line 17, Col 6, Line 17, Col 7, "More than one override implements 'GetHashCode: unit -> int'") - (Error 54, Line 17, Col 6, Line 17, Col 7, "This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[]' attribute to your type.") (Error 344, Line 21, Col 6, Line 21, Col 7, "The struct, record or union type 'S' has an explicit implementation of 'Object.GetHashCode' or 'Object.Equals'. You must apply the 'CustomEquality' attribute to the type") (Warning 345, Line 21, Col 6, Line 21, Col 7, "The struct, record or union type 'S' has an explicit implementation of 'Object.GetHashCode'. Consider implementing a matching override for 'Object.Equals(obj)'") (Error 359, Line 21, Col 6, Line 21, Col 7, "More than one override implements 'GetHashCode: unit -> int'") - (Error 54, Line 21, Col 6, Line 21, Col 7, "This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[]' attribute to your type.") ] // SOURCE=E_ExceptionsNoComparison.fs SCFLAGS="--test:ErrorRanges" # E_ExceptionsNoComparison.fs diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionStructTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionStructTypes.fs index 630d2c2a838..574f1695d62 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionStructTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionStructTypes.fs @@ -752,6 +752,18 @@ type GenericStructDu<'T> = EmptyFirst | SingleVal of f:'T | DoubleVal of f2:'T * """ |> compile |> shouldSucceed + + [] + let ``Error when declaring an abstract member in union struct type`` () = + Fsx """ +[] +type U = + | A | B + abstract M : unit -> unit + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 912, Line 5, Col 3, Line 5, Col 28, "This declaration element is not permitted in an augmentation") [] let ``Regression 16282 DefaultAugment false on a struct union with fields`` () = diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs index 948ae405822..75ee664d938 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/UnionTypes/UnionTypes.fs @@ -709,3 +709,15 @@ if (sprintf "%%A" ABC.ab) <> "[A; B]" then failwith (sprintf "Failed: printing ' |> asExe |> compileAndRun |> shouldSucceed + + [] + let ``Error when declaring an abstract member in union type`` () = + Fsx """ +type U = + | A | B + abstract M : unit -> unit + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 912, Line 4, Col 3, Line 4, Col 28, "This declaration element is not permitted in an augmentation") + diff --git a/tests/FSharp.Compiler.ComponentTests/Diagnostics/Records.fs b/tests/FSharp.Compiler.ComponentTests/Diagnostics/Records.fs index d617daaee7c..7b6bd70d729 100644 --- a/tests/FSharp.Compiler.ComponentTests/Diagnostics/Records.fs +++ b/tests/FSharp.Compiler.ComponentTests/Diagnostics/Records.fs @@ -111,4 +111,15 @@ type FooImpl = |> asExe |> compile |> shouldFail - |> withSingleDiagnostic (Error 912, Line 9, Col 5, Line 9, Col 36, "This declaration element is not permitted in an augmentation") \ No newline at end of file + |> withSingleDiagnostic (Error 912, Line 9, Col 5, Line 9, Col 36, "This declaration element is not permitted in an augmentation") + +[] +let ``Error when declaring an abstract member in record type`` () = + Fsx """ +type R = + { a : int; b : string } + abstract M : unit -> unit + """ + |> typecheck + |> shouldFail + |> withSingleDiagnostic (Error 912, Line 4, Col 3, Line 4, Col 28, "This declaration element is not permitted in an augmentation") diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index 5d8273748b9..55f4d1cbf1b 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -782,4 +782,37 @@ type FooImpl = static member val X = "" with get, set """ |> typecheck - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + + [] + let ``Error when declaring abstract members on a class, No [] or default implementation`` () = + Fsx """ +type A() = + abstract member M: unit -> unit + """ + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 365, Line 2, Col 6, Line 2, Col 7, "No implementation was given for 'abstract A.M: unit -> unit'") + (Error 54, Line 2, Col 6, Line 2, Col 7, "Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[]' attribute to your type.") + ] + + [] + let ``Not error when declaring abstract members on a class with [] attribute.`` () = + Fsx """ +[] +type A() = + abstract member M: unit -> unit + """ + |> typecheck + |> shouldSucceed + + [] + let ``Not error when declaring abstract members on a class with a default implementation.`` () = + Fsx """ +type A() = + abstract member M: unit -> unit + default this.M() = () + """ + |> typecheck + |> shouldSucceed \ No newline at end of file diff --git a/tests/fsharp/typecheck/sigs/neg44.bsl b/tests/fsharp/typecheck/sigs/neg44.bsl index a8aa1d6ecea..1f69c7d9ff0 100644 --- a/tests/fsharp/typecheck/sigs/neg44.bsl +++ b/tests/fsharp/typecheck/sigs/neg44.bsl @@ -1,4 +1,4 @@ neg44.fs(6,6,6,12): typecheck error FS0365: No implementation was given for 'Type.get_Module() : Module' -neg44.fs(6,6,6,12): typecheck error FS0054: This type is 'abstract' since some abstract members have not been given an implementation. If this is intentional then add the '[]' attribute to your type. +neg44.fs(6,6,6,12): typecheck error FS0054: Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[]' attribute to your type. diff --git a/tests/fsharpqa/Source/Conformance/InferenceProcedures/WellFormednessChecking/E_NonAbstractClassNotImplAllInheritedAbstractSlots01.fs b/tests/fsharpqa/Source/Conformance/InferenceProcedures/WellFormednessChecking/E_NonAbstractClassNotImplAllInheritedAbstractSlots01.fs index fc8085da099..f844bbfda6f 100644 --- a/tests/fsharpqa/Source/Conformance/InferenceProcedures/WellFormednessChecking/E_NonAbstractClassNotImplAllInheritedAbstractSlots01.fs +++ b/tests/fsharpqa/Source/Conformance/InferenceProcedures/WellFormednessChecking/E_NonAbstractClassNotImplAllInheritedAbstractSlots01.fs @@ -1,7 +1,7 @@ // #Regression #Conformance #TypeInference // Regression test for FSHARP1.0:6123 //No implementation was given for 'Derived\.get_Foo\(\) : int'$ -//This type is 'abstract' since some abstract members have not been given an implementation\. If this is intentional then add the '\[\]' attribute to your type\.$ +//Non-abstract classes cannot contain abstract members\. Either provide a default member implementation or add the '\[\]' attribute to your type\.$ type FSDerived() = inherit Derived() diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/AbstractMembers/E_CallToAbstractMember03.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/AbstractMembers/E_CallToAbstractMember03.fs index 277ed73ab9d..18fc7c46d55 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/AbstractMembers/E_CallToAbstractMember03.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/AbstractMembers/E_CallToAbstractMember03.fs @@ -2,7 +2,7 @@ // Regression test for TFS bug Dev10:834160 // This test would fail if we don't set the IsImplemented bit for the abstract slot //No implementation was given for 'abstract B\.M: int -> float'$ -//This type is 'abstract' since some abstract members have not been given an implementation\. If this is intentional then add the '\[\]' attribute to your type\.$ +//Non-abstract classes cannot contain abstract members\. Either provide a default member implementation or add the '\[\]' attribute to your type\.$ [] type B() = abstract M : int -> float diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/MemberDeclarations/E_Sealed_Member_Override02.fsx b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/MemberDeclarations/E_Sealed_Member_Override02.fsx index 08eb1ecdafd..529a497ee4b 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/MemberDeclarations/E_Sealed_Member_Override02.fsx +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/MemberDeclarations/E_Sealed_Member_Override02.fsx @@ -28,5 +28,5 @@ type T4() = //No implementation was given for those members: // 'CSLib5\.B0\.M\(c: char, a: int\) : int' // 'CSLib5\.B0\.N\(c: char, a: int\) : int' -//This type is 'abstract' since some abstract members have not been given an implementation\. If this is intentional then add the '\[\]' attribute to your type\.$ +//Non-abstract classes cannot contain abstract members\. Either provide a default member implementation or add the '\[\]' attribute to your type\.$ //Cannot override inherited member 'CSLib5.B1::M' because it is sealed$ \ No newline at end of file diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_AbstractClass01.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_AbstractClass01.fs index ce38600f850..d4d614ca1c9 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_AbstractClass01.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/ClassTypes/Misc/E_AbstractClass01.fs @@ -3,9 +3,9 @@ // FSB 1272, New-ing a sub class with unimplemented abstract members should not be allowed. -//This type is 'abstract' since some abstract members have not been given an implementation\. If this is intentional then add the '\[\]' attribute to your type +//Non-abstract classes cannot contain abstract members\. Either provide a default member implementation or add the '\[\]' attribute to your type //No implementation was given for 'abstract Foo\.f: int -> int' -//This type is 'abstract' since some abstract members have not been given an implementation\. If this is intentional then add the '\[\]' attribute to your type +//Non-abstract classes cannot contain abstract members\. Either provide a default member implementation or add the '\[\]' attribute to your type //No implementation was given for 'abstract Foo\.f: int -> int' diff --git a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface003e.fs b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface003e.fs index 7240d11d5fa..e56e6266453 100644 --- a/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface003e.fs +++ b/tests/fsharpqa/Source/Conformance/ObjectOrientedTypeDefinitions/TypeKindInference/infer_interface003e.fs @@ -3,9 +3,9 @@ // attribute must match inferred type //No implementation was given for 'abstract TK_I_005\.M: unit -> unit'$ -//This type is 'abstract' since some abstract members have not been given an implementation\. If this is intentional then add the '\[\]' attribute to your type\.$ +//Non-abstract classes cannot contain abstract members\. Either provide a default member implementation or add the '\[\]' attribute to your type\.$ //No implementation was given for 'abstract TK_C_000\.M: int -> int'$ -//This type is 'abstract' since some abstract members have not been given an implementation\. If this is intentional then add the '\[\]' attribute to your type\.$ +//Non-abstract classes cannot contain abstract members\. Either provide a default member implementation or add the '\[\]' attribute to your type\.$ [] type TK_C_000 =