Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Disallow calling abstract methods directly on interfaces #17021

Merged
merged 17 commits into from
Apr 16, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,4 +1,5 @@
### Fixed

Various parenthesization API fixes. ([PR #16977](https://github.com/dotnet/fsharp/pull/16977))
* Disallow calling abstract methods directly on interfaces. ([PR #17021](https://github.com/dotnet/fsharp/pull/17021))
edgarfgp marked this conversation as resolved.
Show resolved Hide resolved
* 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))
20 changes: 17 additions & 3 deletions src/Compiler/Checking/ConstraintSolver.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2942,10 +2942,24 @@ 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 ->
// Don't want to make available via completion, as it will lead to the compile time error e.g. not usable if it's non-virtual
None, ErrorD (Error (FSComp.SR.chkStaticAbstractInterfaceMembers(), 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"
edgarfgp marked this conversation as resolved.
Show resolved Hide resolved
3866,chkStaticAbstractInterfaceMembers,"A static abstract interface member can be accessed only on a type parameter."
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 interface member can be accessed only on a type parameter.")

[<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 # AssemblyVersion01.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 interface member can be accessed only on a type parameter.")
(Error 3866, Line 13, Col 82, Line 13, Col 126, "A static abstract interface member can be accessed only on a type parameter.")
(Error 3866, Line 15, Col 82, Line 15, Col 129, "A static abstract interface member can be accessed only on a type parameter.")
]
Loading