From bfbc3e9822dd05f7dbf8711c0699f95127208398 Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Tue, 31 May 2016 15:54:16 +0200 Subject: [PATCH 1/2] Suggest a function to implement --- src/fsharp/FSComp.txt | 2 +- src/fsharp/TypeChecker.fs | 8 +++++++- .../NoMatchingAbstractMethodWithSameName.fs | 14 ++++++++++++++ tests/fsharpqa/Source/Warnings/env.lst | 1 + 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 5bbff5d3ff..1ff34fb9e6 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -588,7 +588,7 @@ tcExpressionWithIfRequiresParenthesis,"This list or array expression includes an 764,tcFieldRequiresAssignment,"No assignment given for field '%s' of type '%s'" 765,tcExtraneousFieldsGivenValues,"Extraneous fields have been given values" 766,tcObjectExpressionsCanOnlyOverrideAbstractOrVirtual,"Only overrides of abstract and virtual members may be specified in object expressions" -767,tcNoAbstractOrVirtualMemberFound,"The member '%s' does not correspond to any abstract or virtual method available to override or implement" +767,tcNoAbstractOrVirtualMemberFound,"The member '%s' does not correspond to any abstract or virtual method available to override or implement.%s" 768,tcArgumentArityMismatch,"The member '%s' does not accept the correct number of arguments, %d arguments are expected" 769,tcArgumentArityMismatchOneOverload,"The member '%s' does not accept the correct number of arguments. One overload accepts %d arguments." 770,tcSimpleMethodNameRequired,"A simple method name is required here" diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index c8cfc05480..4599cd304a 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -6209,7 +6209,13 @@ and FreshenObjExprAbstractSlot cenv (_env: TcEnv) implty virtNameAndArityPairs ( let absSlotsByName = List.filter (fst >> fst >> (=) bindName) virtNameAndArityPairs match absSlotsByName with - | [] -> errorR(Error(FSComp.SR.tcNoAbstractOrVirtualMemberFound(bindName),mBinding)) + | [] -> + let predictions = + virtNameAndArityPairs + |> List.map (fst >> fst) + |> ErrorResolutionHints.FilterPredictions bindName + + errorR(Error(FSComp.SR.tcNoAbstractOrVirtualMemberFound(bindName, ErrorResolutionHints.FormatPredictions predictions),mBinding)) | [(_,absSlot:MethInfo)] -> errorR(Error(FSComp.SR.tcArgumentArityMismatch(bindName, (List.sum absSlot.NumArgs)),mBinding)) | (_,absSlot:MethInfo) :: _ -> errorR(Error(FSComp.SR.tcArgumentArityMismatchOneOverload(bindName, (List.sum absSlot.NumArgs)),mBinding)) diff --git a/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs b/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs new file mode 100644 index 0000000000..a59f863a77 --- /dev/null +++ b/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs @@ -0,0 +1,14 @@ +// #Warnings +//The member 'Function' does not correspond to any abstract or virtual method available to override or implement. +//MyFunction + +type IInterface = + abstract MyFunction : int32 * int32 -> unit + abstract SomeOtherFunction : int32 * int32 -> unit + +let x = + { new IInterface with + member this.Function (i, j) = () + } + +exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/env.lst b/tests/fsharpqa/Source/Warnings/env.lst index 89651c646a..ac2d8543e5 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -5,6 +5,7 @@ SOURCE=CommaInRecCtor.fs # CommaInRecCtor.fs SOURCE=ValidCommaInRecCtor.fs # ValidCommaInRecCtor.fs SOURCE=ElseBranchHasWrongType.fs # ElseBranchHasWrongType.fs + SOURCE=NoMatchingAbstractMethodWithSameName.fs # NoMatchingAbstractMethodWithSameName.fs SOURCE=MissingExpressionAfterLet.fs # MissingExpressionAfterLet.fs SOURCE=AssignmentOnImmutable.fs # AssignmentOnImmutable.fs SOURCE=UpcastInsteadOfDowncast.fs # UpcastInsteadOfDowncast.fs From 3e7ddeeffe6e454d5107e291151a73aa4e741b4f Mon Sep 17 00:00:00 2001 From: Steffen Forkmann Date: Thu, 2 Jun 2016 12:33:39 +0200 Subject: [PATCH 2/2] If the member is not abstract then give better error --- src/fsharp/FSComp.txt | 1 + src/fsharp/TypeChecker.fs | 14 +++++++++++--- tests/fsharp/typecheck/sigs/neg10.bsl | 12 +++++++++++- .../ObjectExpressions/E_MembersMustBeVirtual01.fs | 2 +- .../MatchingMethodWithSameNameIsNotAbstract.fs | 14 ++++++++++++++ tests/fsharpqa/Source/Warnings/env.lst | 1 + 6 files changed, 39 insertions(+), 5 deletions(-) create mode 100644 tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 1ff34fb9e6..7ca7ce14e8 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -589,6 +589,7 @@ tcExpressionWithIfRequiresParenthesis,"This list or array expression includes an 765,tcExtraneousFieldsGivenValues,"Extraneous fields have been given values" 766,tcObjectExpressionsCanOnlyOverrideAbstractOrVirtual,"Only overrides of abstract and virtual members may be specified in object expressions" 767,tcNoAbstractOrVirtualMemberFound,"The member '%s' does not correspond to any abstract or virtual method available to override or implement.%s" +767,tcMemberFoundIsNotAbstractOrVirtual,"The type %s contains the member '%s' but it is not a virtual or abstract method that is available to override or implement.%s" 768,tcArgumentArityMismatch,"The member '%s' does not accept the correct number of arguments, %d arguments are expected" 769,tcArgumentArityMismatchOneOverload,"The member '%s' does not accept the correct number of arguments. One overload accepts %d arguments." 770,tcSimpleMethodNameRequired,"A simple method name is required here" diff --git a/src/fsharp/TypeChecker.fs b/src/fsharp/TypeChecker.fs index 4599cd304a..fd8a876b6c 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -6202,20 +6202,28 @@ and GetNameAndArityOfObjExprBinding _cenv _env b = lookPat pat -and FreshenObjExprAbstractSlot cenv (_env: TcEnv) implty virtNameAndArityPairs (bind,bindAttribs,bindName,absSlots:(_ * MethInfo) list) = +and FreshenObjExprAbstractSlot cenv (_env: TcEnv) (implty:TType) virtNameAndArityPairs (bind,bindAttribs,bindName,absSlots:(_ * MethInfo) list) = let (NormalizedBinding (_,_,_,_,_,_,synTyparDecls,_,_,_,mBinding,_)) = bind match absSlots with | [] when not (CompileAsEvent cenv.g bindAttribs) -> let absSlotsByName = List.filter (fst >> fst >> (=) bindName) virtNameAndArityPairs match absSlotsByName with - | [] -> + | [] -> + let tcref = tcrefOfAppTy cenv.g implty + let containsNonAbstractMemberWithSameName = + tcref.MembersOfFSharpTyconByName + |> Seq.exists (fun kv -> kv.Value |> List.exists (fun valRef -> valRef.DisplayName = bindName)) + let predictions = virtNameAndArityPairs |> List.map (fst >> fst) |> ErrorResolutionHints.FilterPredictions bindName - errorR(Error(FSComp.SR.tcNoAbstractOrVirtualMemberFound(bindName, ErrorResolutionHints.FormatPredictions predictions),mBinding)) + if containsNonAbstractMemberWithSameName then + errorR(Error(FSComp.SR.tcMemberFoundIsNotAbstractOrVirtual(tcref.DisplayName, bindName, ErrorResolutionHints.FormatPredictions predictions),mBinding)) + else + errorR(Error(FSComp.SR.tcNoAbstractOrVirtualMemberFound(bindName, ErrorResolutionHints.FormatPredictions predictions),mBinding)) | [(_,absSlot:MethInfo)] -> errorR(Error(FSComp.SR.tcArgumentArityMismatch(bindName, (List.sum absSlot.NumArgs)),mBinding)) | (_,absSlot:MethInfo) :: _ -> errorR(Error(FSComp.SR.tcArgumentArityMismatchOneOverload(bindName, (List.sum absSlot.NumArgs)),mBinding)) diff --git a/tests/fsharp/typecheck/sigs/neg10.bsl b/tests/fsharp/typecheck/sigs/neg10.bsl index ca631ed99f..ba47d7e252 100644 --- a/tests/fsharp/typecheck/sigs/neg10.bsl +++ b/tests/fsharp/typecheck/sigs/neg10.bsl @@ -69,7 +69,17 @@ neg10.fs(174,9,175,20): typecheck error FS0951: Literal enumerations must have t neg10.fs(180,10,180,11): typecheck error FS0866: Interfaces cannot contain definitions of object constructors -neg10.fs(193,39,193,46): typecheck error FS0767: The member 'MyX' does not correspond to any abstract or virtual method available to override or implement +neg10.fs(193,39,193,46): typecheck error FS0767: The type Foo contains the member 'MyX' but it is not a virtual or abstract method that is available to override or implement. + +Maybe you want one of the following: + + Equals + + ToString + + Finalize + + GetHashCode neg10.fs(193,41,193,44): typecheck error FS0017: The member 'MyX : unit -> int' does not have the correct type to override any given virtual method diff --git a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/ObjectExpressions/E_MembersMustBeVirtual01.fs b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/ObjectExpressions/E_MembersMustBeVirtual01.fs index 5950ee0ed0..41badad221 100644 --- a/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/ObjectExpressions/E_MembersMustBeVirtual01.fs +++ b/tests/fsharpqa/Source/Conformance/Expressions/DataExpressions/ObjectExpressions/E_MembersMustBeVirtual01.fs @@ -1,7 +1,7 @@ // #Regression #Conformance #DataExpressions #ObjectConstructors // FSB 1683, dispatch slot checking in object expression manages to match non-virtual member -//The member 'MyX' does not correspond to any abstract or virtual method available to override or implement$ +//The type Foo contains the member 'MyX' but it is not a virtual or abstract method that is available to override or implement. //The member 'MyX : unit -> int' does not have the correct type to override any given virtual method$ //At least one override did not correctly implement its corresponding abstract member$ diff --git a/tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs b/tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs new file mode 100644 index 0000000000..36275ff0e9 --- /dev/null +++ b/tests/fsharpqa/Source/Warnings/MatchingMethodWithSameNameIsNotAbstract.fs @@ -0,0 +1,14 @@ +// #Warnings +//The type Foo contains the member 'MyX' but it is not a virtual or abstract method that is available to override or implement. +//ToString + +type Foo(x : int) = + member v.MyX() = x + +let foo = + { new Foo(3) + with + member v.MyX() = 4 } + + +exit 0 \ No newline at end of file diff --git a/tests/fsharpqa/Source/Warnings/env.lst b/tests/fsharpqa/Source/Warnings/env.lst index ac2d8543e5..54b35516a0 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -5,6 +5,7 @@ SOURCE=CommaInRecCtor.fs # CommaInRecCtor.fs SOURCE=ValidCommaInRecCtor.fs # ValidCommaInRecCtor.fs SOURCE=ElseBranchHasWrongType.fs # ElseBranchHasWrongType.fs + SOURCE=MatchingMethodWithSameNameIsNotAbstract.fs # MatchingMethodWithSameNameIsNotAbstract.fs SOURCE=NoMatchingAbstractMethodWithSameName.fs # NoMatchingAbstractMethodWithSameName.fs SOURCE=MissingExpressionAfterLet.fs # MissingExpressionAfterLet.fs SOURCE=AssignmentOnImmutable.fs # AssignmentOnImmutable.fs