diff --git a/src/fsharp/FSComp.txt b/src/fsharp/FSComp.txt index 5bbff5d3ffa..7ca7ce14e80 100644 --- a/src/fsharp/FSComp.txt +++ b/src/fsharp/FSComp.txt @@ -588,7 +588,8 @@ 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" +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 c8cfc054800..fd8a876b6c0 100755 --- a/src/fsharp/TypeChecker.fs +++ b/src/fsharp/TypeChecker.fs @@ -6202,14 +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 - | [] -> errorR(Error(FSComp.SR.tcNoAbstractOrVirtualMemberFound(bindName),mBinding)) + | [] -> + 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 + + 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 ca631ed99f7..ba47d7e2529 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 5950ee0ed00..41badad221f 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 00000000000..36275ff0e92 --- /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/NoMatchingAbstractMethodWithSameName.fs b/tests/fsharpqa/Source/Warnings/NoMatchingAbstractMethodWithSameName.fs new file mode 100644 index 00000000000..a59f863a774 --- /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 89651c646aa..54b35516a04 100644 --- a/tests/fsharpqa/Source/Warnings/env.lst +++ b/tests/fsharpqa/Source/Warnings/env.lst @@ -5,6 +5,8 @@ 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 SOURCE=UpcastInsteadOfDowncast.fs # UpcastInsteadOfDowncast.fs