Skip to content

Commit

Permalink
Disallow calling abstract methods directly on interfaces (#17021) (#1…
Browse files Browse the repository at this point in the history
…7053)

* Disallow calling abstract methods directly on interfaces

* More tests

* IWSAMs are not supported by NET472

* Update src/Compiler/Checking/ConstraintSolver.fs



* fix typos

* looking for the right check

* Add comments

* move release notes

* Add a new error number and message

* Update docs/release-notes/.FSharp.Compiler.Service/8.0.400.md



* Update docs/release-notes/.FSharp.Compiler.Service/8.0.400.md



* Improve error message

---------

Co-authored-by: Edgar Gonzalez <edgar.gonzalez@fundourselves.com>
Co-authored-by: Tomas Grosup <tomasgrosup@microsoft.com>
Co-authored-by: Brian Rourke Boll <brianrourkeboll@users.noreply.github.com>
  • Loading branch information
4 people authored Apr 16, 2024
1 parent 0a35514 commit d11b46f
Show file tree
Hide file tree
Showing 18 changed files with 160 additions and 6 deletions.
3 changes: 2 additions & 1 deletion docs/release-notes/.FSharp.Compiler.Service/8.0.400.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### Fixed

* Various parenthesization API fixes. ([PR #16977](https://github.com/dotnet/fsharp/pull/16977))
* 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))
* Various parenthesization API fixes. ([PR #16977](https://github.com/dotnet/fsharp/pull/16977))
* Fix bug in optimization of for-loops over integral ranges with steps and units of measure. ([Issue #17025](https://github.com/dotnet/fsharp/issues/17025), [PR #17040](https://github.com/dotnet/fsharp/pull/17040))
* Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013))
19 changes: 16 additions & 3 deletions src/Compiler/Checking/ConstraintSolver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2942,10 +2942,23 @@ and ResolveOverloading
let candidates = calledMethGroup |> List.filter (fun cmeth -> cmeth.IsCandidate(m, ad))

let calledMethOpt, errors, calledMethTrace =

match calledMethGroup, candidates with
| _, [calledMeth] when not isOpConversion ->
Some calledMeth, CompleteD, NoTrace
| _, [calledMeth] when not isOpConversion ->
// See what candidates we have based on static/virtual/abstract

// If false then is a static method call directly on an interface e.g.
// IParsable.Parse(...)
// IAdditionOperators.(+)
// This is not allowed as Parse and (+) method are static abstract
let isStaticConstrainedCall =
match calledMeth.OptionalStaticType with
| Some ttype -> isTyparTy g ttype
| None -> false

match calledMeth.Method with
| ILMeth(ilMethInfo= ilMethInfo) when not isStaticConstrainedCall && ilMethInfo.IsStatic && ilMethInfo.IsAbstract ->
None, ErrorD (Error (FSComp.SR.chkStaticAbstractInterfaceMembers(ilMethInfo.ILName), m)), NoTrace
| _ -> Some calledMeth, CompleteD, NoTrace

| [], _ when not isOpConversion ->
None, ErrorD (Error (FSComp.SR.csMethodNotFound(methodName), m)), NoTrace
Expand Down
3 changes: 2 additions & 1 deletion src/Compiler/FSComp.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1745,4 +1745,5 @@ featureReuseSameFieldsInStructUnions,"Share underlying fields in a [<Struct>] di
3862,parsStaticMemberImcompleteSyntax,"Incomplete declaration of a static construct. Use 'static let','static do','static member' or 'static val' for declaration."
3863,parsExpectingField,"Expecting record field"
3864,tooManyMethodsInDotNetTypeWritingAssembly,"The type '%s' has too many methods. Found: '%d', maximum: '%d'"
3865,parsOnlySimplePatternsAreAllowedInConstructors,"Only simple patterns are allowed in primary constructors"
3865,parsOnlySimplePatternsAreAllowedInConstructors,"Only simple patterns are allowed in primary constructors"
3866,chkStaticAbstractInterfaceMembers,"A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.%s)."
5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ko.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.pl.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.pt-BR.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.ru.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.tr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.zh-Hans.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions src/Compiler/xlf/FSComp.txt.zh-Hant.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#nowarn "64"
open System
open System.Numerics

module ConstrainedCall =
let ``'T.op_Addition``<'T & #IAdditionOperators<'T, 'T, 'T>> x y = 'T.op_Addition (x, y)
let ``'T.(+)``<'T & #IAdditionOperators<'T, 'T, 'T>> x y = 'T.(+) (x, y)
let ``'T.op_CheckedAddition``<'T & #IAdditionOperators<'T, 'T, 'T>> x y = 'T.op_CheckedAddition (x, y)
let ``'T.Parse``<'T & #IParsable<'T>> x = 'T.Parse (x, null)

module InterfaceCall =
let ``IAdditionOperators.op_Addition`` x y = IAdditionOperators.op_Addition (x, y)
let ``IAdditionOperators.(+)`` x y = IAdditionOperators.(+) (x, y)
let ``IAdditionOperators.op_CheckedAddition`` x y = IAdditionOperators.op_CheckedAddition (x, y)
let ``IParsable.Parse``<'T & #IParsable<'T>> x : 'T = IParsable.Parse (x, null)

Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ module TypesAndTypeConstraints_IWSAMsAndSRTPs =
|> asExe
|> withLangVersion70
|> withReferences [typesModule]

let verifyCompile compilation =
compilation
|> asExe
|> withOptions ["--nowarn:988"]
|> compile

let verifyCompileAndRun compilation =
compilation
|> asExe
|> withOptions ["--nowarn:988"]
|> compileAndRun

[<Fact>]
let ``Srtp call Zero property returns valid result`` () =
Expand Down Expand Up @@ -1183,4 +1195,50 @@ let execute = IPrintable.Say("hello")
|> withOptions [ "--nowarn:3536" ; "--nowarn:3535" ]
|> withLangVersion80
|> typecheck
|> shouldSucceed
|> shouldSucceed

[<FactForNETCOREAPP>]
let ``Accessing to IWSAM(System.Numerics non virtual) produces a compilation error`` () =
Fsx """
open System.Numerics

IAdditionOperators.op_Addition (3, 6)
"""
|> withOptions [ "--nowarn:3536" ; "--nowarn:3535" ]
|> withLangVersion80
|> compile
|> shouldFail
|> withSingleDiagnostic (Error 3866, Line 4, Col 1, Line 4, Col 38, "A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.op_Addition).")

[<FactForNETCOREAPP>]
let ``Accessing to IWSAM(System.Numerics virtual member) compiles and runs`` () =
Fsx """
open System.Numerics

let res = IAdditionOperators.op_CheckedAddition (3, 6)

printf "%A" res"""
|> withOptions [ "--nowarn:3536" ; "--nowarn:3535" ]
|> withLangVersion80
|> asExe
|> compile
|> shouldSucceed
|> run
|> verifyOutput "9"

#if !NETCOREAPP
[<Theory(Skip = "IWSAMs are not supported by NET472.")>]
#else
// SOURCE=ConstrainedAndInterfaceCalls.fs # ConstrainedAndInterfaceCalls.fs
[<Theory; Directory(__SOURCE_DIRECTORY__, Includes=[|"ConstrainedAndInterfaceCalls.fs"|])>]
#endif
let ``ConstrainedAndInterfaceCalls.fs`` compilation =
compilation
|> withOptions [ "--nowarn:3536" ; "--nowarn:3535" ]
|> verifyCompile
|> shouldFail
|> withDiagnostics [
(Error 3866, Line 12, Col 82, Line 12, Col 126, "A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.op_Addition).")
(Error 3866, Line 13, Col 82, Line 13, Col 126, "A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.op_Addition).")
(Error 3866, Line 15, Col 82, Line 15, Col 129, "A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.Parse).")
]

0 comments on commit d11b46f

Please sign in to comment.