From d2eb1c501fed1eef1447705bbdfd2be3246e53a4 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Tue, 8 Nov 2022 07:23:31 +0100 Subject: [PATCH 1/6] No errors for non virtual members overrides --- src/Compiler/Checking/CheckExpressions.fs | 24 ++- .../ErrorMessages/ClassesTests.fs | 175 ++++++++++++++++++ 2 files changed, 193 insertions(+), 6 deletions(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index ca78dbe444b..efd9fe7eaf8 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -10944,7 +10944,7 @@ and ComputeIsComplete enclosingDeclaredTypars declaredTypars ty = /// Determine if a uniquely-identified-abstract-slot exists for an override member (or interface member implementation) based on the information available /// at the syntactic definition of the member (i.e. prior to type inference). If so, we know the expected signature of the override, and the full slotsig /// it implements. Apply the inferred slotsig. -and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (argsAndRetTy, m, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, _objTy, intfSlotTyOpt, valSynData, memberFlags: SynMemberFlags, attribs) = +and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (baseValOpt: Val option) (argsAndRetTy, m, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, intfSlotTyOpt, valSynData, memberFlags: SynMemberFlags, attribs) = let g = cenv.g let ad = envinner.eAccessRights @@ -10991,7 +10991,20 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (argsAndRetTy, m, | _ -> [] // check that method to override is sealed is located at CheckOverridesAreAllUsedOnce (typrelns.fs) // We hit this case when it is ambiguous which abstract method is being implemented. - + // Chekss if the declaring type inherits from a base class. + // Raises an error if we try to override an non virtual member with the same name in both + match baseValOpt with + | Some ttypeApp -> + match ttypeApp.Type with + | TType_app(tyconRef, _, _) -> + let ilMethods = tyconRef.ILTyconRawMetadata.Methods.AsList() + let nameOpt = ilMethods |> List.tryFind(fun id -> id.Name = memberId.idText) + match nameOpt with + | Some name when not name.IsVirtual -> + errorR(Error(FSComp.SR.tcNoMemberFoundForOverride(), memberId.idRange)) + | _ -> () + | _ -> () + | None -> () // If we determined a unique member then utilize the type information from the slotsig let declaredTypars = @@ -11153,14 +11166,14 @@ and AnalyzeRecursiveStaticMemberOrValDecl CheckForNonAbstractInterface declKind tcref memberFlags id.idRange let isExtrinsic = (declKind = ExtrinsicExtensionBinding) - let tcrefObjTy, enclosingDeclaredTypars, renaming, objTy, _ = FreshenObjectArgType cenv mBinding TyparRigidity.WillBeRigid tcref isExtrinsic declaredTyconTypars + let tcrefObjTy, enclosingDeclaredTypars, renaming, _, _ = FreshenObjectArgType cenv mBinding TyparRigidity.WillBeRigid tcref isExtrinsic declaredTyconTypars let envinner = AddDeclaredTypars CheckForDuplicateTypars enclosingDeclaredTypars envinner let envinner = MakeInnerEnvForTyconRef envinner tcref isExtrinsic let (ExplicitTyparInfo(_, declaredTypars, infer)) = explicitTyparInfo let optInferredImplSlotTys, declaredTypars = - ApplyAbstractSlotInference cenv envinner (ty, mBinding, synTyparDecls, declaredTypars, id, tcrefObjTy, renaming, objTy, intfSlotTyOpt, valSynInfo, memberFlags, bindingAttribs) + ApplyAbstractSlotInference cenv envinner None (ty, mBinding, synTyparDecls, declaredTypars, id, tcrefObjTy, renaming, intfSlotTyOpt, valSynInfo, memberFlags, bindingAttribs) let explicitTyparInfo = ExplicitTyparInfo(declaredTypars, declaredTypars, infer) @@ -11225,7 +11238,6 @@ and AnalyzeRecursiveStaticMemberOrValDecl | _ -> envinner, tpenv, id, None, None, vis, vis2, None, [], None, explicitTyparInfo, bindingRhs, declaredTypars - and AnalyzeRecursiveInstanceMemberDecl (cenv: cenv, envinner: TcEnv, @@ -11284,7 +11296,7 @@ and AnalyzeRecursiveInstanceMemberDecl // at the member signature. If so, we know the type of this member, and the full slotsig // it implements. Apply the inferred slotsig. let optInferredImplSlotTys, declaredTypars = - ApplyAbstractSlotInference cenv envinner (argsAndRetTy, mBinding, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, objTy, intfSlotTyOpt, valSynInfo, memberFlags, bindingAttribs) + ApplyAbstractSlotInference cenv envinner baseValOpt (argsAndRetTy, mBinding, synTyparDecls, declaredTypars, memberId, tcrefObjTy, renaming, intfSlotTyOpt, valSynInfo, memberFlags, bindingAttribs) // Update the ExplicitTyparInfo to reflect the declaredTypars inferred from the abstract slot let explicitTyparInfo = ExplicitTyparInfo(declaredTypars, declaredTypars, infer) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index 621307f4e66..9f5c0d14812 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -121,3 +121,178 @@ type X() = (Error 531, Line 4, Col 5, Line 4, Col 12, "Accessibility modifiers should come immediately prior to the identifier naming a construct") (Error 512, Line 4, Col 13, Line 4, Col 18, "Accessibility modifiers are not permitted on 'do' bindings, but 'Private' was given.") (Error 222, Line 2, Col 1, Line 3, Col 1, "Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule'. Only the last source file of an application may omit such a declaration.")] + + [] + let ``Virtual member was found that corresponds to this override`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public virtual void M2() { } + public virtual void M3() { } + public virtual void M4() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type B() = + inherit A() + override this.M1() = () + override this.M2() = () + override this.M3() = () + override this.M4() = () + member this.M5() = () + """ |> withReferences [CSLib] + app + |> compile + |> shouldSucceed + + [] + let ``Virtual member was not found that corresponds to this override simple base class`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public void M2() { } + public virtual void M3() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type B() = + inherit A() + + override this.M1() = () + override this.M2() = () // error expected + override this.M3() = () + member this.M4() = () + """ |> withReferences [CSLib] + app + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 855, Line 7, Col 19, Line 7, Col 21, "No abstract or interface member was found that corresponds to this override") + ] + + [] + let ``Virtual member was not found that corresponds to this override nested base class`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public virtual void M2() { } + public virtual void M3() { } + public virtual void M4() { } +} + +public class B : A +{ + public override void M1() { } + public void M2() { } + public new void M3() { } + public new virtual void M4() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type C() = + inherit B() + + override this.M1() = () + override this.M2() = () // error expected + override this.M3() = () // error expected + override this.M4() = () + member this.M5() = () + """ |> withReferences [CSLib] + app + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 855, Line 7, Col 19, Line 7, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 8, Col 19, Line 8, Col 21, "No abstract or interface member was found that corresponds to this override") + ] + + [] + let ``Virtual member was not found that corresponds to this override nested base class 2`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public virtual void M2() { } + public virtual void M3() { } + public virtual void M4() { } +} + +public class B : A +{ + public void M2() { } + public new void M3() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type C() = + inherit B() + + override this.M1() = () + override this.M2() = () // error is expected + override this.M3() = () // error is expected + override this.M4() = () + member this.M5() = () + """ |> withReferences [CSLib] + app + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 855, Line 7, Col 19, Line 7, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 8, Col 19, Line 8, Col 21, "No abstract or interface member was found that corresponds to this override") + ] + + [] + let ``Virtual member was not found that corresponds to this override nested base class 3`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public void M2() { } +} + +public class B : A +{ + public virtual void M3() { } + public new void M4() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type C() = + inherit B() + + override this.M1() = () + override this.M2() = () // error is expected + override this.M3() = () + override this.M4() = () // error is expected + member this.M5() = () + """ |> withReferences [CSLib] + app + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 855, Line 7, Col 19, Line 7, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 9, Col 19, Line 9, Col 21, "No abstract or interface member was found that corresponds to this override") + ] \ No newline at end of file From 0b9728e5ddb23efa9a30af2324fd7c2140939ee4 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 10 Nov 2022 17:05:07 +0100 Subject: [PATCH 2/6] Check for isFSharpObjModelTy as we are interested on csharp virtual methods --- src/Compiler/Checking/CheckExpressions.fs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index efd9fe7eaf8..7a86d18ec02 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -10991,11 +10991,11 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (baseValOpt: Val o | _ -> [] // check that method to override is sealed is located at CheckOverridesAreAllUsedOnce (typrelns.fs) // We hit this case when it is ambiguous which abstract method is being implemented. - // Chekss if the declaring type inherits from a base class. + // Checks if the declaring type inherits from a base class andisFSharpObjModelTy // Raises an error if we try to override an non virtual member with the same name in both match baseValOpt with - | Some ttypeApp -> - match ttypeApp.Type with + | Some ttype when not(isFSharpObjModelTy g ttype.Type) -> + match ttype.Type with | TType_app(tyconRef, _, _) -> let ilMethods = tyconRef.ILTyconRawMetadata.Methods.AsList() let nameOpt = ilMethods |> List.tryFind(fun id -> id.Name = memberId.idText) @@ -11004,7 +11004,7 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (baseValOpt: Val o errorR(Error(FSComp.SR.tcNoMemberFoundForOverride(), memberId.idRange)) | _ -> () | _ -> () - | None -> () + | _ -> () // If we determined a unique member then utilize the type information from the slotsig let declaredTypars = From d337d726963ba00d1b0562aa068523b42ad2bcde Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 10 Nov 2022 17:05:19 +0100 Subject: [PATCH 3/6] More testing --- .../ErrorMessages/ClassesTests.fs | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index 9f5c0d14812..81ee9041844 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -120,8 +120,42 @@ type X() = |> withDiagnostics [ (Error 531, Line 4, Col 5, Line 4, Col 12, "Accessibility modifiers should come immediately prior to the identifier naming a construct") (Error 512, Line 4, Col 13, Line 4, Col 18, "Accessibility modifiers are not permitted on 'do' bindings, but 'Private' was given.") - (Error 222, Line 2, Col 1, Line 3, Col 1, "Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule'. Only the last source file of an application may omit such a declaration.")] - + (Error 222, Line 2, Col 1, Line 3, Col 1, "Files in libraries or multiple-file applications must begin with a namespace or module declaration, e.g. 'namespace SomeNamespace.SubNamespace' or 'module SomeNamespace.SomeModule'. Only the last source file of an application may omit such a declaration.") + ] + + [] + let ``Do Cannot Have Visibility Declarations 1``() = + Fsx """ +type A = + abstract member M1: unit -> unit + abstract member M2: unit -> unit + abstract member M3: unit -> unit + abstract member M4: unit -> unit + +type B() = + interface A with + override this.M1() = () + override this.M2() = () // error is expected + override this.M3() = () // error is expected + override this.M4() = () + +type C() = + inherit B() + override this.M1() = () + override this.M2() = () + override this.M3() = () + override this.M4() = () + member this.M5() = () + """ + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 855, Line 17, Col 19, Line 17, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 18, Col 19, Line 18, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 19, Col 19, Line 19, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 20, Col 19, Line 20, Col 21, "No abstract or interface member was found that corresponds to this override") + ] + [] let ``Virtual member was found that corresponds to this override`` () = let CSLib = From 432e25771f54595ec286fef3e4ceeca504a5bc08 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 10 Nov 2022 17:40:01 +0100 Subject: [PATCH 4/6] Add a feature lang preview --- src/Compiler/Checking/CheckExpressions.fs | 27 ++++++++++---------- src/Compiler/FSComp.txt | 1 + src/Compiler/Facilities/LanguageFeatures.fs | 3 +++ src/Compiler/Facilities/LanguageFeatures.fsi | 1 + 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 ++++ 17 files changed, 84 insertions(+), 13 deletions(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 9a76010a1bb..3637c23582c 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -10997,20 +10997,21 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (baseValOpt: Val o | _ -> [] // check that method to override is sealed is located at CheckOverridesAreAllUsedOnce (typrelns.fs) // We hit this case when it is ambiguous which abstract method is being implemented. - // Checks if the declaring type inherits from a base class andisFSharpObjModelTy - // Raises an error if we try to override an non virtual member with the same name in both - match baseValOpt with - | Some ttype when not(isFSharpObjModelTy g ttype.Type) -> - match ttype.Type with - | TType_app(tyconRef, _, _) -> - let ilMethods = tyconRef.ILTyconRawMetadata.Methods.AsList() - let nameOpt = ilMethods |> List.tryFind(fun id -> id.Name = memberId.idText) - match nameOpt with - | Some name when not name.IsVirtual -> - errorR(Error(FSComp.SR.tcNoMemberFoundForOverride(), memberId.idRange)) + if g.langVersion.SupportsFeature(LanguageFeature.ErrorForNonVirtualMembersOverrides) then + // Checks if the declaring type inherits from a base class and is not FSharpObjModelTy + // Raises an error if we try to override an non virtual member with the same name in both + match baseValOpt with + | Some ttype when not(isFSharpObjModelTy g ttype.Type) -> + match ttype.Type with + | TType_app(tyconRef, _, _) -> + let ilMethods = tyconRef.ILTyconRawMetadata.Methods.AsList() + let nameOpt = ilMethods |> List.tryFind(fun id -> id.Name = memberId.idText) + match nameOpt with + | Some name when not name.IsVirtual -> + errorR(Error(FSComp.SR.tcNoMemberFoundForOverride(), memberId.idRange)) + | _ -> () | _ -> () - | _ -> () - | _ -> () + | _ -> () // If we determined a unique member then utilize the type information from the slotsig let declaredTypars = diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 9c9da192081..53cfa341667 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1561,6 +1561,7 @@ featureInitProperties,"support for consuming init properties" featureLowercaseDUWhenRequireQualifiedAccess,"Allow lowercase DU when RequireQualifiedAccess attribute" featureMatchNotAllowedForUnionCaseWithNoData,"Pattern match discard is not allowed for union case that takes no data." featureCSharpExtensionAttributeNotRequired,"Allow implicit Extension attribute on declaring types, modules" +featureErrorForNonVirtualMembersOverrides,"Raises errors for non-virtual members overrides" 3353,fsiInvalidDirective,"Invalid directive '#%s %s'" 3354,tcNotAFunctionButIndexerNamedIndexingNotYetEnabled,"This value supports indexing, e.g. '%s.[index]'. The syntax '%s[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation." 3354,tcNotAFunctionButIndexerIndexingNotYetEnabled,"This expression supports indexing, e.g. 'expr.[index]'. The syntax 'expr[index]' requires /langversion:preview. See https://aka.ms/fsharp-index-notation." diff --git a/src/Compiler/Facilities/LanguageFeatures.fs b/src/Compiler/Facilities/LanguageFeatures.fs index 00ddd74b6c5..14302b05132 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fs +++ b/src/Compiler/Facilities/LanguageFeatures.fs @@ -56,6 +56,7 @@ type LanguageFeature = | SelfTypeConstraints | MatchNotAllowedForUnionCaseWithNoData | CSharpExtensionAttributeNotRequired + | ErrorForNonVirtualMembersOverrides /// LanguageVersion management type LanguageVersion(versionText) = @@ -128,6 +129,7 @@ type LanguageVersion(versionText) = LanguageFeature.FromEndSlicing, previewVersion LanguageFeature.MatchNotAllowedForUnionCaseWithNoData, previewVersion LanguageFeature.CSharpExtensionAttributeNotRequired, previewVersion + LanguageFeature.ErrorForNonVirtualMembersOverrides, previewVersion ] @@ -237,6 +239,7 @@ type LanguageVersion(versionText) = | LanguageFeature.SelfTypeConstraints -> FSComp.SR.featureSelfTypeConstraints () | LanguageFeature.MatchNotAllowedForUnionCaseWithNoData -> FSComp.SR.featureMatchNotAllowedForUnionCaseWithNoData () | LanguageFeature.CSharpExtensionAttributeNotRequired -> FSComp.SR.featureCSharpExtensionAttributeNotRequired () + | LanguageFeature.ErrorForNonVirtualMembersOverrides -> FSComp.SR.featureErrorForNonVirtualMembersOverrides () /// Get a version string associated with the given feature. static member GetFeatureVersionString feature = diff --git a/src/Compiler/Facilities/LanguageFeatures.fsi b/src/Compiler/Facilities/LanguageFeatures.fsi index 1b3d68e8f2a..f471f371b95 100644 --- a/src/Compiler/Facilities/LanguageFeatures.fsi +++ b/src/Compiler/Facilities/LanguageFeatures.fsi @@ -46,6 +46,7 @@ type LanguageFeature = | SelfTypeConstraints | MatchNotAllowedForUnionCaseWithNoData | CSharpExtensionAttributeNotRequired + | ErrorForNonVirtualMembersOverrides /// LanguageVersion management type LanguageVersion = diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 8c4a1300a7f..2afccb1fd40 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -177,6 +177,11 @@ literál float32 bez tečky + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute chyba při zastaralém přístupu konstruktoru s atributem RequireQualifiedAccess diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 688592092e3..b0eec3044bc 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -177,6 +177,11 @@ punktloses float32-Literal + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute Beim veralteten Zugriff auf das Konstrukt mit dem RequireQualifiedAccess-Attribut wird ein Fehler ausgegeben. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index a06daa1f7f1..89d57eacb65 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -177,6 +177,11 @@ literal float32 sin punto + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute error en el acceso en desuso de la construcción con el atributo RequireQualifiedAccess diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index f8a89904bfa..2db2d58f88f 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -177,6 +177,11 @@ littéral float32 sans point + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute donner une erreur sur l’accès déconseillé de la construction avec l’attribut RequireQualifiedAccess diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 37d11b74636..66011450a6b 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -177,6 +177,11 @@ valore letterale float32 senza punti + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute errore durante l'accesso deprecato del costrutto con l'attributo RequireQualifiedAccess diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index c42700c1d18..0ba2173b8fc 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -177,6 +177,11 @@ ドットなしの float32 リテラル + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute RequireQualifiedAccess 属性を持つコンストラクトの非推奨アクセスでエラーが発生しました diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 39e9a33001e..e97d0cf2eb2 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -177,6 +177,11 @@ 점이 없는 float32 리터럴 + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute RequireQualifiedAccess 특성을 사용하여 사용되지 않는 구문 액세스에 대한 오류 제공 diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index e3a61d7dd58..d39b72ca26f 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -177,6 +177,11 @@ bezkropkowy literał float32 + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute wskazywanie błędu w przypadku przestarzałego dostępu do konstrukcji z atrybutem RequireQualifiedAccess diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 78742938012..09d70721f8a 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -177,6 +177,11 @@ literal float32 sem ponto + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute fornecer erro no acesso preterido do constructo com o atributo RequireQualifiedAccess diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 837271832bf..01249439e53 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -177,6 +177,11 @@ литерал float32 без точки + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute выдать ошибку при устаревшем доступе к конструкции с атрибутом RequireQualifiedAccess diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 59d04a3fe94..113d6a42396 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -177,6 +177,11 @@ noktasız float32 sabit değeri + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute RequireQualifiedAccess özniteliğine sahip yapının kullanım dışı erişiminde hata diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index ebcafbf1852..b6a766f9cd5 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -177,6 +177,11 @@ 无点 float32 文本 + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute 对具有 RequireQualifiedAccess 属性的构造进行弃用的访问时出错 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 0606b9b48c4..f404d766e1c 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -177,6 +177,11 @@ 無點號的 float32 常值 + + Raises errors for non-virtual members overrides + Raises errors for non-virtual members overrides + + give error on deprecated access of construct with RequireQualifiedAccess attribute 對具有 RequireQualifiedAccess 屬性的建構的已取代存取發出錯誤 From f6bf000be176abd195744a05930de07599734274 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Thu, 10 Nov 2022 17:40:13 +0100 Subject: [PATCH 5/6] More testing --- .../ErrorMessages/ClassesTests.fs | 225 +++++++++++++++++- 1 file changed, 219 insertions(+), 6 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs index 81ee9041844..eeb3ab1d371 100644 --- a/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/ErrorMessages/ClassesTests.fs @@ -124,7 +124,7 @@ type X() = ] [] - let ``Do Cannot Have Visibility Declarations 1``() = + let ``No abstract or interface member was found that corresponds to this override with lang preview``() = Fsx """ type A = abstract member M1: unit -> unit @@ -147,6 +147,7 @@ type C() = override this.M4() = () member this.M5() = () """ + |> withLangVersionPreview |> compile |> shouldFail |> withDiagnostics [ @@ -157,7 +158,41 @@ type C() = ] [] - let ``Virtual member was found that corresponds to this override`` () = + let ``No abstract or interface member was found that corresponds to this override with lang version70``() = + Fsx """ +type A = + abstract member M1: unit -> unit + abstract member M2: unit -> unit + abstract member M3: unit -> unit + abstract member M4: unit -> unit + +type B() = + interface A with + override this.M1() = () + override this.M2() = () // error is expected + override this.M3() = () // error is expected + override this.M4() = () + +type C() = + inherit B() + override this.M1() = () + override this.M2() = () + override this.M3() = () + override this.M4() = () + member this.M5() = () + """ + |> withLangVersion70 + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 855, Line 17, Col 19, Line 17, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 18, Col 19, Line 18, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 19, Col 19, Line 19, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 20, Col 19, Line 20, Col 21, "No abstract or interface member was found that corresponds to this override") + ] + + [] + let ``Virtual member was found that corresponds to this override with lang version70`` () = let CSLib = CSharp """ public class A @@ -181,11 +216,42 @@ type B() = member this.M5() = () """ |> withReferences [CSLib] app + |> withLangVersion70 |> compile |> shouldSucceed + + [] + let ``Virtual member was found that corresponds to this override with lang preview`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public virtual void M2() { } + public virtual void M3() { } + public virtual void M4() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type B() = + inherit A() + override this.M1() = () + override this.M2() = () + override this.M3() = () + override this.M4() = () + member this.M5() = () + """ |> withReferences [CSLib] + app + |> withLangVersionPreview + |> compile + |> shouldSucceed + [] - let ``Virtual member was not found that corresponds to this override simple base class`` () = + let ``Virtual member was not found that corresponds to this override simple base class with lang version preview`` () = let CSLib = CSharp """ public class A @@ -208,6 +274,38 @@ type B() = member this.M4() = () """ |> withReferences [CSLib] app + |> withLangVersionPreview + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 855, Line 7, Col 19, Line 7, Col 21, "No abstract or interface member was found that corresponds to this override") + ] + + [] + let ``Virtual member was not found that corresponds to this override simple base class with lang version70`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public void M2() { } + public virtual void M3() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type B() = + inherit A() + + override this.M1() = () + override this.M2() = () + override this.M3() = () + member this.M4() = () + """ |> withReferences [CSLib] + app + |> withLangVersion70 |> compile |> shouldFail |> withDiagnostics [ @@ -215,7 +313,7 @@ type B() = ] [] - let ``Virtual member was not found that corresponds to this override nested base class`` () = + let ``Virtual member was not found that corresponds to this override nested base class with lang version preview`` () = let CSLib = CSharp """ public class A @@ -248,15 +346,54 @@ type C() = member this.M5() = () """ |> withReferences [CSLib] app + |> withLangVersionPreview |> compile |> shouldFail |> withDiagnostics [ (Error 855, Line 7, Col 19, Line 7, Col 21, "No abstract or interface member was found that corresponds to this override") (Error 855, Line 8, Col 19, Line 8, Col 21, "No abstract or interface member was found that corresponds to this override") ] + + [] + let ``Virtual member was not found that corresponds to this override nested base class with lang version70`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public virtual void M2() { } + public virtual void M3() { } + public virtual void M4() { } +} + +public class B : A +{ + public override void M1() { } + public void M2() { } + public new void M3() { } + public new virtual void M4() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type C() = + inherit B() + + override this.M1() = () + override this.M2() = () // error expected + override this.M3() = () // error expected + override this.M4() = () + member this.M5() = () + """ |> withReferences [CSLib] + app + |> withLangVersion70 + |> compile + |> shouldSucceed [] - let ``Virtual member was not found that corresponds to this override nested base class 2`` () = + let ``Virtual member was not found that corresponds to this override nested 2 base class with lang preview`` () = let CSLib = CSharp """ public class A @@ -287,6 +424,7 @@ type C() = member this.M5() = () """ |> withReferences [CSLib] app + |> withLangVersionPreview |> compile |> shouldFail |> withDiagnostics [ @@ -295,7 +433,43 @@ type C() = ] [] - let ``Virtual member was not found that corresponds to this override nested base class 3`` () = + let ``Virtual member was not found that corresponds to this override nested 2 base classes with lang version70`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public virtual void M2() { } + public virtual void M3() { } + public virtual void M4() { } +} + +public class B : A +{ + public void M2() { } + public new void M3() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type C() = + inherit B() + + override this.M1() = () + override this.M2() = () // error is expected + override this.M3() = () // error is expected + override this.M4() = () + member this.M5() = () + """ |> withReferences [CSLib] + app + |> withLangVersion70 + |> compile + |> shouldSucceed + + [] + let ``Virtual member was not found that corresponds to this override nested 2 base classes and mixed methods with lang preview`` () = let CSLib = CSharp """ public class A @@ -324,6 +498,45 @@ type C() = member this.M5() = () """ |> withReferences [CSLib] app + |> withLangVersionPreview + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 855, Line 7, Col 19, Line 7, Col 21, "No abstract or interface member was found that corresponds to this override") + (Error 855, Line 9, Col 19, Line 9, Col 21, "No abstract or interface member was found that corresponds to this override") + ] + + [] + let ``Virtual member was not found that corresponds to this override nested 2 base classes and mixed methods with lang version70`` () = + let CSLib = + CSharp """ +public class A +{ + public virtual void M1() { } + public void M2() { } +} + +public class B : A +{ + public virtual void M3() { } + public new void M4() { } +} + """ |> withName "CSLib" + + let app = + FSharp """ +module ClassTests +type C() = + inherit B() + + override this.M1() = () + override this.M2() = () // error is expected + override this.M3() = () + override this.M4() = () // error is expected + member this.M5() = () + """ |> withReferences [CSLib] + app + |> withLangVersion70 |> compile |> shouldFail |> withDiagnostics [ From 8bb88b106595d7a3c9b4619fafa391a71ffc5c23 Mon Sep 17 00:00:00 2001 From: Edgar Gonzalez Date: Fri, 11 Nov 2022 17:38:12 +0100 Subject: [PATCH 6/6] Fix PR comment --- src/Compiler/Checking/CheckExpressions.fs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Compiler/Checking/CheckExpressions.fs b/src/Compiler/Checking/CheckExpressions.fs index 3637c23582c..043502372c2 100644 --- a/src/Compiler/Checking/CheckExpressions.fs +++ b/src/Compiler/Checking/CheckExpressions.fs @@ -11002,7 +11002,7 @@ and ApplyAbstractSlotInference (cenv: cenv) (envinner: TcEnv) (baseValOpt: Val o // Raises an error if we try to override an non virtual member with the same name in both match baseValOpt with | Some ttype when not(isFSharpObjModelTy g ttype.Type) -> - match ttype.Type with + match stripTyEqns g ttype.Type with | TType_app(tyconRef, _, _) -> let ilMethods = tyconRef.ILTyconRawMetadata.Methods.AsList() let nameOpt = ilMethods |> List.tryFind(fun id -> id.Name = memberId.idText)