From d11b46f7cdaa90ab5663bf16f7f54349204545a9 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Tue, 16 Apr 2024 09:46:22 -0700 Subject: [PATCH 1/6] Disallow calling abstract methods directly on interfaces (#17021) (#17053) * 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 Co-authored-by: Tomas Grosup Co-authored-by: Brian Rourke Boll --- .../.FSharp.Compiler.Service/8.0.400.md | 3 +- src/Compiler/Checking/ConstraintSolver.fs | 19 +++++- src/Compiler/FSComp.txt | 3 +- 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 ++ .../ConstrainedAndInterfaceCalls.fs | 16 +++++ .../IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs | 60 ++++++++++++++++++- 18 files changed, 160 insertions(+), 6 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/ConstrainedAndInterfaceCalls.fs diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index c18d969fa4c..1a6298e3a48 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -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)) diff --git a/src/Compiler/Checking/ConstraintSolver.fs b/src/Compiler/Checking/ConstraintSolver.fs index 2667ea6ccfc..41c7e26f47e 100644 --- a/src/Compiler/Checking/ConstraintSolver.fs +++ b/src/Compiler/Checking/ConstraintSolver.fs @@ -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 diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index acb3eecc210..e5cabbdc7e3 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1745,4 +1745,5 @@ featureReuseSameFieldsInStructUnions,"Share underlying fields in a [] 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" \ No newline at end of file +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)." \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 4a57c5a229d..a7f9808f488 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -122,6 +122,11 @@ Člen nebo funkce „{0}“ má atribut „TailCallAttribute“, ale nepoužívá se koncovým (tail) rekurzivním způsobem. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. Objektové výrazy nemohou implementovat rozhraní se statickými abstraktními členy ani deklarovat statické členy. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 3875895aed7..534e047744f 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -122,6 +122,11 @@ Der Member oder die Funktion "{0}" weist das Attribut "TailCallAttribute" auf, wird jedoch nicht endrekursiv verwendet. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. Objektausdrücke können keine Schnittstellen mit statischen abstrakten Membern implementieren oder statische Member deklarieren. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 229f3781a88..5d2517d1ca9 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -122,6 +122,11 @@ El miembro o la función “{0}” tiene el atributo “TailCallAttribute”, pero no se usa de forma de recursión de cola. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. Las expresiones de objeto no pueden implementar interfaces con miembros abstractos estáticos ni declarar miembros estáticos. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 5ace1c2dc39..f5c4358314a 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -122,6 +122,11 @@ Le membre ou la fonction « {0} » possède l'attribut « TailCallAttribute », mais n'est pas utilisé de manière récursive. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. Les expressions d’objet ne peuvent pas implémenter des interfaces avec des membres abstraits statiques ou déclarer des membres statiques. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index c5cb0876c15..350f2decb87 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -122,6 +122,11 @@ Il membro o la funzione "{0}" ha l'attributo "TailCallAttribute", ma non è in uso in modo ricorsivo finale. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. Le espressioni di oggetto non possono implementare interfacce con membri astratti statici o dichiarare membri statici. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 04b73c10939..376d3d8d592 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -122,6 +122,11 @@ メンバーまたは関数 '{0}' には 'TailCallAttribute' 属性がありますが、末尾の再帰的な方法では使用されていません。 + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. オブジェクト式は、静的抽象メンバーを持つインターフェイスを実装したり、静的メンバーを宣言したりすることはできません。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index afd1f78ca86..f4a42405fcb 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -122,6 +122,11 @@ 멤버 또는 함수 '{0}'에 'TailCallAttribute' 특성이 있지만 비상 재귀적인 방식으로 사용되고 있지 않습니다. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. 개체 식은 정적 추상 멤버가 있는 인터페이스를 구현하거나 정적 멤버를 선언할 수 없습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 98611ebcc88..f081661bf4e 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -122,6 +122,11 @@ Składowa lub funkcja „{0}” ma atrybut „TailCallAttribute”, ale nie jest używana w sposób cykliczny końca. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. Wyrażenia obiektów nie mogą implementować interfejsów ze statycznymi abstrakcyjnymi elementami członkowskimi ani deklarować statycznych elementów członkowskich. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 9356372d275..b17c0b76d24 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -122,6 +122,11 @@ O membro ou a função "{0}" tem o atributo "TailCallAttribute", mas não está sendo usado de maneira recursiva em cauda. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. Expressões de objeto não podem implementar interfaces com membros abstratos estáticos ou declarar membros estáticos. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 6a08c7ada1a..7f83d96d646 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -122,6 +122,11 @@ Элемент или функция "{0}" содержит атрибут "TailCallAttribute", но не используется в рекурсивном хвостовом режиме. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. Выражения объектов не могут реализовывать интерфейсы со статическими абстрактными членами или объявлять статические члены. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index 7aab43de9c4..f74a800f285 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -122,6 +122,11 @@ Üye veya '{0}' işlevi, 'TailCallAttribute' özniteliğine sahip ancak kuyruk özyinelemeli bir şekilde kullanılmıyor. + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. Nesne ifadeleri, statik soyut üyeler içeren arabirimleri uygulayamaz veya statik üyeleri bildiremez. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 95715bd1b8a..19dae40d40a 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -122,6 +122,11 @@ 成员或函数“{0}”具有 "TailCallAttribute" 属性,但未以尾递归方式使用。 + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. 对象表达式无法实现具有静态抽象成员或声明静态成员的接口。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 5b95c7fe99e..4f332483292 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -122,6 +122,11 @@ 成員或函式 '{0}' 具有 'TailCallAttribute' 屬性,但未以尾遞迴方式使用。 + + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Object expressions cannot implement interfaces with static abstract members or declare static members. 物件運算式無法實作具有靜態抽象成員的介面或宣告靜態成員。 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/ConstrainedAndInterfaceCalls.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/ConstrainedAndInterfaceCalls.fs new file mode 100644 index 00000000000..740eff41812 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/ConstrainedAndInterfaceCalls.fs @@ -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) + diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs index d3d7be2cf36..48c54e2c11e 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs @@ -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 [] let ``Srtp call Zero property returns valid result`` () = @@ -1183,4 +1195,50 @@ let execute = IPrintable.Say("hello") |> withOptions [ "--nowarn:3536" ; "--nowarn:3535" ] |> withLangVersion80 |> typecheck - |> shouldSucceed \ No newline at end of file + |> shouldSucceed + + [] + 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).") + + [] + 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 + [] +#else + // SOURCE=ConstrainedAndInterfaceCalls.fs # 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).") + ] \ No newline at end of file From ade069701fa391f194d1772387255e7a5d32da50 Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Wed, 17 Apr 2024 02:14:53 -0700 Subject: [PATCH 2/6] Merge main to release/dev17.11 (#17056) * Disallow calling abstract methods directly on interfaces (#17021) * Disallow calling abstract methods directly on interfaces * More tests * IWSAMs are not supported by NET472 * Update src/Compiler/Checking/ConstraintSolver.fs Co-authored-by: Tomas Grosup * 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 Co-authored-by: Brian Rourke Boll * Update docs/release-notes/.FSharp.Compiler.Service/8.0.400.md Co-authored-by: Brian Rourke Boll * Improve error message --------- Co-authored-by: Tomas Grosup Co-authored-by: Brian Rourke Boll * Always use `typeEquivAux EraseMeasures` (for integral range optimizations) (#17048) * Always use `typeEquivAux EraseMeasures` * Update release notes * Update baselines --------- Co-authored-by: Petr --------- Co-authored-by: Edgar Gonzalez Co-authored-by: Tomas Grosup Co-authored-by: Brian Rourke Boll Co-authored-by: Petr Co-authored-by: Kevin Ransom (msft) --- .../.FSharp.Compiler.Service/8.0.400.md | 4 +- .../Optimize/LowerComputedCollections.fs | 10 +- src/Compiler/TypedTree/TypedTreeOps.fs | 46 ++-- ...EachRangeStep_UnitsOfMeasure.fs.opt.il.bsl | 217 ++++++++++++------ ...EachRangeStep_UnitsOfMeasure.fs.opt.il.bsl | 217 ++++++++++++------ 5 files changed, 322 insertions(+), 172 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index 1a6298e3a48..7ef8842b72c 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -1,6 +1,6 @@ ### Fixed * 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)) +* 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), [PR #17048](https://github.com/dotnet/fsharp/pull/17048)) * Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013)) diff --git a/src/Compiler/Optimize/LowerComputedCollections.fs b/src/Compiler/Optimize/LowerComputedCollections.fs index 52fabfbca26..5d755daf4b1 100644 --- a/src/Compiler/Optimize/LowerComputedCollections.fs +++ b/src/Compiler/Optimize/LowerComputedCollections.fs @@ -314,7 +314,7 @@ module Array = let arrayTy = mkArrayType g overallElemTy let convToNativeInt ovf expr = - let ty = stripMeasuresFromTy g (tyOfExpr g expr) + let ty = tyOfExpr g expr let conv = match ovf with @@ -322,13 +322,13 @@ module Array = | CheckOvf when isSignedIntegerTy g ty -> AI_conv_ovf DT_I | CheckOvf -> AI_conv_ovf_un DT_I - if typeEquiv g ty g.int64_ty then + if typeEquivAux EraseMeasures g ty g.int64_ty then mkAsmExpr ([conv], [], [expr], [g.nativeint_ty], m) - elif typeEquiv g ty g.nativeint_ty then + elif typeEquivAux EraseMeasures g ty g.nativeint_ty then mkAsmExpr ([conv], [], [mkAsmExpr ([AI_conv DT_I8], [], [expr], [g.int64_ty], m)], [g.nativeint_ty], m) - elif typeEquiv g ty g.uint64_ty then + elif typeEquivAux EraseMeasures g ty g.uint64_ty then mkAsmExpr ([conv], [], [expr], [g.nativeint_ty], m) - elif typeEquiv g ty g.unativeint_ty then + elif typeEquivAux EraseMeasures g ty g.unativeint_ty then mkAsmExpr ([conv], [], [mkAsmExpr ([AI_conv DT_U8], [], [expr], [g.uint64_ty], m)], [g.nativeint_ty], m) else expr diff --git a/src/Compiler/TypedTree/TypedTreeOps.fs b/src/Compiler/TypedTree/TypedTreeOps.fs index 92c1e7355be..cc031de1c1c 100644 --- a/src/Compiler/TypedTree/TypedTreeOps.fs +++ b/src/Compiler/TypedTree/TypedTreeOps.fs @@ -10434,21 +10434,19 @@ let mkRangeCount g m rangeTy rangeExpr start step finish = mkAsmExpr ([AI_clt_un], [], [e1; e2], [g.bool_ty], m) let unsignedEquivalent ty = - if typeEquiv g ty g.int64_ty then g.uint64_ty - elif typeEquiv g ty g.int32_ty then g.uint32_ty - elif typeEquiv g ty g.int16_ty then g.uint16_ty - elif typeEquiv g ty g.sbyte_ty then g.byte_ty + if typeEquivAux EraseMeasures g ty g.int64_ty then g.uint64_ty + elif typeEquivAux EraseMeasures g ty g.int32_ty then g.uint32_ty + elif typeEquivAux EraseMeasures g ty g.int16_ty then g.uint16_ty + elif typeEquivAux EraseMeasures g ty g.sbyte_ty then g.byte_ty else ty /// Find the unsigned type with twice the width of the given type, if available. let nextWidestUnsignedTy ty = - let ty = stripMeasuresFromTy g ty - - if typeEquiv g ty g.int64_ty || typeEquiv g ty g.int32_ty || typeEquiv g ty g.uint32_ty then + if typeEquivAux EraseMeasures g ty g.int64_ty || typeEquivAux EraseMeasures g ty g.int32_ty || typeEquivAux EraseMeasures g ty g.uint32_ty then g.uint64_ty - elif typeEquiv g ty g.int16_ty || typeEquiv g ty g.uint16_ty || typeEquiv g ty g.char_ty then + elif typeEquivAux EraseMeasures g ty g.int16_ty || typeEquivAux EraseMeasures g ty g.uint16_ty || typeEquivAux EraseMeasures g ty g.char_ty then g.uint32_ty - elif typeEquiv g ty g.sbyte_ty || typeEquiv g ty g.byte_ty then + elif typeEquivAux EraseMeasures g ty g.sbyte_ty || typeEquivAux EraseMeasures g ty g.byte_ty then g.uint16_ty else ty @@ -10456,19 +10454,17 @@ let mkRangeCount g m rangeTy rangeExpr start step finish = /// Convert the value to the next-widest unsigned type. /// We do this so that adding one won't result in overflow. let mkWiden e = - let ty = stripMeasuresFromTy g rangeTy - - if typeEquiv g ty g.int32_ty then + if typeEquivAux EraseMeasures g rangeTy g.int32_ty then mkAsmExpr ([AI_conv DT_I8], [], [e], [g.uint64_ty], m) - elif typeEquiv g ty g.uint32_ty then + elif typeEquivAux EraseMeasures g rangeTy g.uint32_ty then mkAsmExpr ([AI_conv DT_U8], [], [e], [g.uint64_ty], m) - elif typeEquiv g ty g.int16_ty then + elif typeEquivAux EraseMeasures g rangeTy g.int16_ty then mkAsmExpr ([AI_conv DT_I4], [], [e], [g.uint32_ty], m) - elif typeEquiv g ty g.uint16_ty || typeEquiv g ty g.char_ty then + elif typeEquivAux EraseMeasures g rangeTy g.uint16_ty || typeEquivAux EraseMeasures g rangeTy g.char_ty then mkAsmExpr ([AI_conv DT_U4], [], [e], [g.uint32_ty], m) - elif typeEquiv g ty g.sbyte_ty then + elif typeEquivAux EraseMeasures g rangeTy g.sbyte_ty then mkAsmExpr ([AI_conv DT_I2], [], [e], [g.uint16_ty], m) - elif typeEquiv g ty g.byte_ty then + elif typeEquivAux EraseMeasures g rangeTy g.byte_ty then mkAsmExpr ([AI_conv DT_U2], [], [e], [g.uint16_ty], m) else e @@ -10481,12 +10477,10 @@ let mkRangeCount g m rangeTy rangeExpr start step finish = /// Whether the total count might not fit in 64 bits. let couldBeTooBig ty = - let underlying = stripMeasuresFromTy g ty - - typeEquiv g underlying g.int64_ty - || typeEquiv g underlying g.uint64_ty - || typeEquiv g underlying g.nativeint_ty - || typeEquiv g underlying g.unativeint_ty + typeEquivAux EraseMeasures g ty g.int64_ty + || typeEquivAux EraseMeasures g ty g.uint64_ty + || typeEquivAux EraseMeasures g ty g.nativeint_ty + || typeEquivAux EraseMeasures g ty g.unativeint_ty /// pseudoCount + 1 let mkAddOne pseudoCount = @@ -10499,16 +10493,14 @@ let mkRangeCount g m rangeTy rangeExpr start step finish = mkAsmExpr ([AI_add], [], [pseudoCount; mkTypedOne g m ty], [ty], m) let mkRuntimeCalc mkThrowIfStepIsZero pseudoCount count = - let underlying = stripMeasuresFromTy g rangeTy - - if typeEquiv g underlying g.int64_ty || typeEquiv g underlying g.uint64_ty then + if typeEquivAux EraseMeasures g rangeTy g.int64_ty || typeEquivAux EraseMeasures g rangeTy g.uint64_ty then RangeCount.PossiblyOversize (fun mkLoopExpr -> mkThrowIfStepIsZero (mkCompGenLetIn m (nameof pseudoCount) (tyOfExpr g pseudoCount) pseudoCount (fun (_, pseudoCount) -> let wouldOvf = mkILAsmCeq g m pseudoCount (Expr.Const (Const.UInt64 UInt64.MaxValue, m, g.uint64_ty)) mkCompGenLetIn m (nameof wouldOvf) g.bool_ty wouldOvf (fun (_, wouldOvf) -> mkLoopExpr count wouldOvf)))) - elif typeEquiv g underlying g.nativeint_ty || typeEquiv g underlying g.unativeint_ty then // We have a nativeint ty whose size we won't know till runtime. + elif typeEquivAux EraseMeasures g rangeTy g.nativeint_ty || typeEquivAux EraseMeasures g rangeTy g.unativeint_ty then // We have a nativeint ty whose size we won't know till runtime. RangeCount.PossiblyOversize (fun mkLoopExpr -> mkThrowIfStepIsZero (mkCompGenLetIn m (nameof pseudoCount) (tyOfExpr g pseudoCount) pseudoCount (fun (_, pseudoCount) -> diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/RealInternalSignatureOff/ForEachRangeStep_UnitsOfMeasure.fs.opt.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/RealInternalSignatureOff/ForEachRangeStep_UnitsOfMeasure.fs.opt.il.bsl index c47ef1b4a90..456b6757b4f 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/RealInternalSignatureOff/ForEachRangeStep_UnitsOfMeasure.fs.opt.il.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/RealInternalSignatureOff/ForEachRangeStep_UnitsOfMeasure.fs.opt.il.bsl @@ -98,7 +98,7 @@ { .maxstack 4 - .locals init (int64 V_0, + .locals init (uint64 V_0, int64 V_1) IL_0000: ldc.i4.0 IL_0001: conv.i8 @@ -132,7 +132,7 @@ { .maxstack 4 - .locals init (int64 V_0, + .locals init (uint64 V_0, int64 V_1) IL_0000: ldc.i4.0 IL_0001: conv.i8 @@ -166,8 +166,8 @@ { .maxstack 4 - .locals init (int64 V_0, - int64 V_1, + .locals init (uint64 V_0, + uint64 V_1, int64 V_2) IL_0000: ldc.i4.s 10 IL_0002: conv.i8 @@ -188,7 +188,7 @@ IL_0012: div.un IL_0013: ldc.i4.1 IL_0014: conv.i8 - IL_0015: add + IL_0015: add.ovf.un IL_0016: nop IL_0017: stloc.0 IL_0018: ldc.i4.0 @@ -221,8 +221,8 @@ { .maxstack 5 - .locals init (int64 V_0, - int64 V_1, + .locals init (uint64 V_0, + uint64 V_1, int64 V_2) IL_0000: ldarg.0 IL_0001: brtrue.s IL_0012 @@ -251,7 +251,7 @@ IL_001c: div.un IL_001d: ldc.i4.1 IL_001e: conv.i8 - IL_001f: add + IL_001f: add.ovf.un IL_0020: nop IL_0021: br.s IL_0026 @@ -289,8 +289,8 @@ { .maxstack 4 - .locals init (int64 V_0, - int64 V_1, + .locals init (uint64 V_0, + uint64 V_1, int64 V_2) IL_0000: ldarg.0 IL_0001: ldc.i4.1 @@ -311,7 +311,7 @@ IL_0010: div.un IL_0011: ldc.i4.1 IL_0012: conv.i8 - IL_0013: add + IL_0013: add.ovf.un IL_0014: nop IL_0015: stloc.0 IL_0016: ldc.i4.0 @@ -349,9 +349,11 @@ 00 00 00 00 ) .maxstack 5 - .locals init (int64 V_0, - int64 V_1, - int64 V_2) + .locals init (uint64 V_0, + bool V_1, + uint64 V_2, + int64 V_3, + uint64 V_4) IL_0000: ldarg.1 IL_0001: brtrue.s IL_000f @@ -369,7 +371,7 @@ IL_0010: ldc.i4.0 IL_0011: conv.i8 IL_0012: ldarg.1 - IL_0013: bge.s IL_0029 + IL_0013: bge.s IL_0026 IL_0015: ldarg.2 IL_0016: ldarg.0 @@ -378,65 +380,142 @@ IL_0019: ldc.i4.0 IL_001a: conv.i8 IL_001b: nop - IL_001c: br.s IL_003f + IL_001c: br.s IL_0039 IL_001e: ldarg.2 IL_001f: ldarg.0 IL_0020: sub IL_0021: ldarg.1 IL_0022: div.un - IL_0023: ldc.i4.1 - IL_0024: conv.i8 - IL_0025: add - IL_0026: nop - IL_0027: br.s IL_003f - - IL_0029: ldarg.0 - IL_002a: ldarg.2 - IL_002b: bge.s IL_0032 - - IL_002d: ldc.i4.0 - IL_002e: conv.i8 - IL_002f: nop - IL_0030: br.s IL_003f - - IL_0032: ldarg.0 - IL_0033: ldarg.2 - IL_0034: sub - IL_0035: ldarg.1 - IL_0036: not - IL_0037: ldc.i4.1 - IL_0038: conv.i8 - IL_0039: add - IL_003a: div.un - IL_003b: ldc.i4.1 + IL_0023: nop + IL_0024: br.s IL_0039 + + IL_0026: ldarg.0 + IL_0027: ldarg.2 + IL_0028: bge.s IL_002f + + IL_002a: ldc.i4.0 + IL_002b: conv.i8 + IL_002c: nop + IL_002d: br.s IL_0039 + + IL_002f: ldarg.0 + IL_0030: ldarg.2 + IL_0031: sub + IL_0032: ldarg.1 + IL_0033: not + IL_0034: ldc.i4.1 + IL_0035: conv.i8 + IL_0036: add + IL_0037: div.un + IL_0038: nop + IL_0039: stloc.0 + IL_003a: ldloc.0 + IL_003b: ldc.i4.m1 IL_003c: conv.i8 - IL_003d: add - IL_003e: nop - IL_003f: stloc.0 - IL_0040: ldc.i4.0 - IL_0041: conv.i8 - IL_0042: stloc.1 - IL_0043: ldarg.0 - IL_0044: stloc.2 - IL_0045: br.s IL_0056 - - IL_0047: ldloc.2 - IL_0048: call void assembly::set_c(int64) - IL_004d: ldloc.2 - IL_004e: ldarg.1 - IL_004f: add - IL_0050: stloc.2 - IL_0051: ldloc.1 - IL_0052: ldc.i4.1 - IL_0053: conv.i8 - IL_0054: add - IL_0055: stloc.1 - IL_0056: ldloc.1 - IL_0057: ldloc.0 - IL_0058: blt.un.s IL_0047 - - IL_005a: ret + IL_003d: bne.un.s IL_0061 + + IL_003f: ldc.i4.1 + IL_0040: stloc.1 + IL_0041: ldc.i4.0 + IL_0042: conv.i8 + IL_0043: stloc.2 + IL_0044: ldarg.0 + IL_0045: stloc.3 + IL_0046: br.s IL_005d + + IL_0048: ldloc.3 + IL_0049: call void assembly::set_c(int64) + IL_004e: ldloc.3 + IL_004f: ldarg.1 + IL_0050: add + IL_0051: stloc.3 + IL_0052: ldloc.2 + IL_0053: ldc.i4.1 + IL_0054: conv.i8 + IL_0055: add + IL_0056: stloc.2 + IL_0057: ldloc.2 + IL_0058: ldc.i4.0 + IL_0059: conv.i8 + IL_005a: cgt.un + IL_005c: stloc.1 + IL_005d: ldloc.1 + IL_005e: brtrue.s IL_0048 + + IL_0060: ret + + IL_0061: ldc.i4.0 + IL_0062: conv.i8 + IL_0063: ldarg.1 + IL_0064: bge.s IL_007a + + IL_0066: ldarg.2 + IL_0067: ldarg.0 + IL_0068: bge.s IL_006f + + IL_006a: ldc.i4.0 + IL_006b: conv.i8 + IL_006c: nop + IL_006d: br.s IL_0090 + + IL_006f: ldarg.2 + IL_0070: ldarg.0 + IL_0071: sub + IL_0072: ldarg.1 + IL_0073: div.un + IL_0074: ldc.i4.1 + IL_0075: conv.i8 + IL_0076: add.ovf.un + IL_0077: nop + IL_0078: br.s IL_0090 + + IL_007a: ldarg.0 + IL_007b: ldarg.2 + IL_007c: bge.s IL_0083 + + IL_007e: ldc.i4.0 + IL_007f: conv.i8 + IL_0080: nop + IL_0081: br.s IL_0090 + + IL_0083: ldarg.0 + IL_0084: ldarg.2 + IL_0085: sub + IL_0086: ldarg.1 + IL_0087: not + IL_0088: ldc.i4.1 + IL_0089: conv.i8 + IL_008a: add + IL_008b: div.un + IL_008c: ldc.i4.1 + IL_008d: conv.i8 + IL_008e: add.ovf.un + IL_008f: nop + IL_0090: stloc.2 + IL_0091: ldc.i4.0 + IL_0092: conv.i8 + IL_0093: stloc.s V_4 + IL_0095: ldarg.0 + IL_0096: stloc.3 + IL_0097: br.s IL_00aa + + IL_0099: ldloc.3 + IL_009a: call void assembly::set_c(int64) + IL_009f: ldloc.3 + IL_00a0: ldarg.1 + IL_00a1: add + IL_00a2: stloc.3 + IL_00a3: ldloc.s V_4 + IL_00a5: ldc.i4.1 + IL_00a6: conv.i8 + IL_00a7: add + IL_00a8: stloc.s V_4 + IL_00aa: ldloc.s V_4 + IL_00ac: ldloc.2 + IL_00ad: blt.un.s IL_0099 + + IL_00af: ret } .method public static void f8(int64 start, @@ -536,7 +615,7 @@ { .maxstack 4 - .locals init (int64 V_0, + .locals init (uint64 V_0, int64 V_1) IL_0000: ldc.i4.0 IL_0001: conv.i8 @@ -570,7 +649,7 @@ { .maxstack 4 - .locals init (int64 V_0, + .locals init (uint64 V_0, int64 V_1) IL_0000: ldc.i4.0 IL_0001: conv.i8 diff --git a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/RealInternalSignatureOn/ForEachRangeStep_UnitsOfMeasure.fs.opt.il.bsl b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/RealInternalSignatureOn/ForEachRangeStep_UnitsOfMeasure.fs.opt.il.bsl index 1776b519709..cacb169018c 100644 --- a/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/RealInternalSignatureOn/ForEachRangeStep_UnitsOfMeasure.fs.opt.il.bsl +++ b/tests/FSharp.Compiler.ComponentTests/EmittedIL/ForLoop/RealInternalSignatureOn/ForEachRangeStep_UnitsOfMeasure.fs.opt.il.bsl @@ -100,7 +100,7 @@ { .maxstack 4 - .locals init (int64 V_0, + .locals init (uint64 V_0, int64 V_1) IL_0000: ldc.i4.0 IL_0001: conv.i8 @@ -134,7 +134,7 @@ { .maxstack 4 - .locals init (int64 V_0, + .locals init (uint64 V_0, int64 V_1) IL_0000: ldc.i4.0 IL_0001: conv.i8 @@ -168,8 +168,8 @@ { .maxstack 4 - .locals init (int64 V_0, - int64 V_1, + .locals init (uint64 V_0, + uint64 V_1, int64 V_2) IL_0000: ldc.i4.s 10 IL_0002: conv.i8 @@ -190,7 +190,7 @@ IL_0012: div.un IL_0013: ldc.i4.1 IL_0014: conv.i8 - IL_0015: add + IL_0015: add.ovf.un IL_0016: nop IL_0017: stloc.0 IL_0018: ldc.i4.0 @@ -223,8 +223,8 @@ { .maxstack 5 - .locals init (int64 V_0, - int64 V_1, + .locals init (uint64 V_0, + uint64 V_1, int64 V_2) IL_0000: ldarg.0 IL_0001: brtrue.s IL_0012 @@ -253,7 +253,7 @@ IL_001c: div.un IL_001d: ldc.i4.1 IL_001e: conv.i8 - IL_001f: add + IL_001f: add.ovf.un IL_0020: nop IL_0021: br.s IL_0026 @@ -291,8 +291,8 @@ { .maxstack 4 - .locals init (int64 V_0, - int64 V_1, + .locals init (uint64 V_0, + uint64 V_1, int64 V_2) IL_0000: ldarg.0 IL_0001: ldc.i4.1 @@ -313,7 +313,7 @@ IL_0010: div.un IL_0011: ldc.i4.1 IL_0012: conv.i8 - IL_0013: add + IL_0013: add.ovf.un IL_0014: nop IL_0015: stloc.0 IL_0016: ldc.i4.0 @@ -351,9 +351,11 @@ 00 00 00 00 ) .maxstack 5 - .locals init (int64 V_0, - int64 V_1, - int64 V_2) + .locals init (uint64 V_0, + bool V_1, + uint64 V_2, + int64 V_3, + uint64 V_4) IL_0000: ldarg.1 IL_0001: brtrue.s IL_000f @@ -371,7 +373,7 @@ IL_0010: ldc.i4.0 IL_0011: conv.i8 IL_0012: ldarg.1 - IL_0013: bge.s IL_0029 + IL_0013: bge.s IL_0026 IL_0015: ldarg.2 IL_0016: ldarg.0 @@ -380,65 +382,142 @@ IL_0019: ldc.i4.0 IL_001a: conv.i8 IL_001b: nop - IL_001c: br.s IL_003f + IL_001c: br.s IL_0039 IL_001e: ldarg.2 IL_001f: ldarg.0 IL_0020: sub IL_0021: ldarg.1 IL_0022: div.un - IL_0023: ldc.i4.1 - IL_0024: conv.i8 - IL_0025: add - IL_0026: nop - IL_0027: br.s IL_003f - - IL_0029: ldarg.0 - IL_002a: ldarg.2 - IL_002b: bge.s IL_0032 - - IL_002d: ldc.i4.0 - IL_002e: conv.i8 - IL_002f: nop - IL_0030: br.s IL_003f - - IL_0032: ldarg.0 - IL_0033: ldarg.2 - IL_0034: sub - IL_0035: ldarg.1 - IL_0036: not - IL_0037: ldc.i4.1 - IL_0038: conv.i8 - IL_0039: add - IL_003a: div.un - IL_003b: ldc.i4.1 + IL_0023: nop + IL_0024: br.s IL_0039 + + IL_0026: ldarg.0 + IL_0027: ldarg.2 + IL_0028: bge.s IL_002f + + IL_002a: ldc.i4.0 + IL_002b: conv.i8 + IL_002c: nop + IL_002d: br.s IL_0039 + + IL_002f: ldarg.0 + IL_0030: ldarg.2 + IL_0031: sub + IL_0032: ldarg.1 + IL_0033: not + IL_0034: ldc.i4.1 + IL_0035: conv.i8 + IL_0036: add + IL_0037: div.un + IL_0038: nop + IL_0039: stloc.0 + IL_003a: ldloc.0 + IL_003b: ldc.i4.m1 IL_003c: conv.i8 - IL_003d: add - IL_003e: nop - IL_003f: stloc.0 - IL_0040: ldc.i4.0 - IL_0041: conv.i8 - IL_0042: stloc.1 - IL_0043: ldarg.0 - IL_0044: stloc.2 - IL_0045: br.s IL_0056 - - IL_0047: ldloc.2 - IL_0048: call void assembly::set_c(int64) - IL_004d: ldloc.2 - IL_004e: ldarg.1 - IL_004f: add - IL_0050: stloc.2 - IL_0051: ldloc.1 - IL_0052: ldc.i4.1 - IL_0053: conv.i8 - IL_0054: add - IL_0055: stloc.1 - IL_0056: ldloc.1 - IL_0057: ldloc.0 - IL_0058: blt.un.s IL_0047 - - IL_005a: ret + IL_003d: bne.un.s IL_0061 + + IL_003f: ldc.i4.1 + IL_0040: stloc.1 + IL_0041: ldc.i4.0 + IL_0042: conv.i8 + IL_0043: stloc.2 + IL_0044: ldarg.0 + IL_0045: stloc.3 + IL_0046: br.s IL_005d + + IL_0048: ldloc.3 + IL_0049: call void assembly::set_c(int64) + IL_004e: ldloc.3 + IL_004f: ldarg.1 + IL_0050: add + IL_0051: stloc.3 + IL_0052: ldloc.2 + IL_0053: ldc.i4.1 + IL_0054: conv.i8 + IL_0055: add + IL_0056: stloc.2 + IL_0057: ldloc.2 + IL_0058: ldc.i4.0 + IL_0059: conv.i8 + IL_005a: cgt.un + IL_005c: stloc.1 + IL_005d: ldloc.1 + IL_005e: brtrue.s IL_0048 + + IL_0060: ret + + IL_0061: ldc.i4.0 + IL_0062: conv.i8 + IL_0063: ldarg.1 + IL_0064: bge.s IL_007a + + IL_0066: ldarg.2 + IL_0067: ldarg.0 + IL_0068: bge.s IL_006f + + IL_006a: ldc.i4.0 + IL_006b: conv.i8 + IL_006c: nop + IL_006d: br.s IL_0090 + + IL_006f: ldarg.2 + IL_0070: ldarg.0 + IL_0071: sub + IL_0072: ldarg.1 + IL_0073: div.un + IL_0074: ldc.i4.1 + IL_0075: conv.i8 + IL_0076: add.ovf.un + IL_0077: nop + IL_0078: br.s IL_0090 + + IL_007a: ldarg.0 + IL_007b: ldarg.2 + IL_007c: bge.s IL_0083 + + IL_007e: ldc.i4.0 + IL_007f: conv.i8 + IL_0080: nop + IL_0081: br.s IL_0090 + + IL_0083: ldarg.0 + IL_0084: ldarg.2 + IL_0085: sub + IL_0086: ldarg.1 + IL_0087: not + IL_0088: ldc.i4.1 + IL_0089: conv.i8 + IL_008a: add + IL_008b: div.un + IL_008c: ldc.i4.1 + IL_008d: conv.i8 + IL_008e: add.ovf.un + IL_008f: nop + IL_0090: stloc.2 + IL_0091: ldc.i4.0 + IL_0092: conv.i8 + IL_0093: stloc.s V_4 + IL_0095: ldarg.0 + IL_0096: stloc.3 + IL_0097: br.s IL_00aa + + IL_0099: ldloc.3 + IL_009a: call void assembly::set_c(int64) + IL_009f: ldloc.3 + IL_00a0: ldarg.1 + IL_00a1: add + IL_00a2: stloc.3 + IL_00a3: ldloc.s V_4 + IL_00a5: ldc.i4.1 + IL_00a6: conv.i8 + IL_00a7: add + IL_00a8: stloc.s V_4 + IL_00aa: ldloc.s V_4 + IL_00ac: ldloc.2 + IL_00ad: blt.un.s IL_0099 + + IL_00af: ret } .method public static void f8(int64 start, @@ -538,7 +617,7 @@ { .maxstack 4 - .locals init (int64 V_0, + .locals init (uint64 V_0, int64 V_1) IL_0000: ldc.i4.0 IL_0001: conv.i8 @@ -572,7 +651,7 @@ { .maxstack 4 - .locals init (int64 V_0, + .locals init (uint64 V_0, int64 V_1) IL_0000: ldc.i4.0 IL_0001: conv.i8 From 6b6bbf08ee8a90c6b231d6b636bf2ebb05b2556c Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Wed, 17 Apr 2024 06:50:27 -0700 Subject: [PATCH 3/6] Merge main to release/dev17.11 (#17059) * Disallow calling abstract methods directly on interfaces (#17021) * Disallow calling abstract methods directly on interfaces * More tests * IWSAMs are not supported by NET472 * Update src/Compiler/Checking/ConstraintSolver.fs Co-authored-by: Tomas Grosup * 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 Co-authored-by: Brian Rourke Boll * Update docs/release-notes/.FSharp.Compiler.Service/8.0.400.md Co-authored-by: Brian Rourke Boll * Improve error message --------- Co-authored-by: Tomas Grosup Co-authored-by: Brian Rourke Boll * Always use `typeEquivAux EraseMeasures` (for integral range optimizations) (#17048) * Always use `typeEquivAux EraseMeasures` * Update release notes * Update baselines --------- Co-authored-by: Petr --------- Co-authored-by: Edgar Gonzalez Co-authored-by: Tomas Grosup Co-authored-by: Brian Rourke Boll Co-authored-by: Petr Co-authored-by: Vlad Zarytovskii From 27efc282d3c1e3abdf8322191e09d0fe466c489e Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Thu, 18 Apr 2024 04:35:27 -0700 Subject: [PATCH 4/6] Merge main to release/dev17.11 (#17064) * Disallow calling abstract methods directly on interfaces (#17021) * Disallow calling abstract methods directly on interfaces * More tests * IWSAMs are not supported by NET472 * Update src/Compiler/Checking/ConstraintSolver.fs Co-authored-by: Tomas Grosup * 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 Co-authored-by: Brian Rourke Boll * Update docs/release-notes/.FSharp.Compiler.Service/8.0.400.md Co-authored-by: Brian Rourke Boll * Improve error message --------- Co-authored-by: Tomas Grosup Co-authored-by: Brian Rourke Boll * Always use `typeEquivAux EraseMeasures` (for integral range optimizations) (#17048) * Always use `typeEquivAux EraseMeasures` * Update release notes * Update baselines --------- Co-authored-by: Petr * Error message that explicitly disallowed static abstract members in classes. (#17055) * WIP * Error message that explicitly disallowed static abstract methods in abstract classes * release notes * SynTypeDefnKind.Class * Fix #16761 (#17047) * Fix #16761 * Fully async version + ignore cancellation on external navigation * Automated command ran: fantomas Co-authored-by: vzarytovskii <1260985+vzarytovskii@users.noreply.github.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --------- Co-authored-by: Edgar Gonzalez Co-authored-by: Tomas Grosup Co-authored-by: Brian Rourke Boll Co-authored-by: Petr Co-authored-by: Vlad Zarytovskii Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Kevin Ransom (msft) --- .../.FSharp.Compiler.Service/8.0.400.md | 1 + src/Compiler/Checking/CheckDeclarations.fs | 35 ++++---- src/Compiler/FSComp.txt | 3 +- 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 ++ .../IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs | 29 ++++++- .../Navigation/GoToDefinition.fs | 86 +++++++++++++++++-- .../Navigation/GoToDefinitionService.fs | 4 +- 19 files changed, 198 insertions(+), 25 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index 7ef8842b72c..b24a17b85fb 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -1,5 +1,6 @@ ### Fixed +* Static abstract method on classes no longer yields internal error. ([Issue #17044](https://github.com/dotnet/fsharp/issues/17044), [PR #17055](https://github.com/dotnet/fsharp/pull/17055)) * 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), [PR #17048](https://github.com/dotnet/fsharp/pull/17048)) diff --git a/src/Compiler/Checking/CheckDeclarations.fs b/src/Compiler/Checking/CheckDeclarations.fs index f1037f7f1bb..30f773f7478 100644 --- a/src/Compiler/Checking/CheckDeclarations.fs +++ b/src/Compiler/Checking/CheckDeclarations.fs @@ -3608,6 +3608,20 @@ module EstablishTypeDefinitionCores = elif not (isClassTy g ty) then errorR(Error(FSComp.SR.tcCannotInheritFromInterfaceType(), m))) + let abstractSlots = + [ for synValSig, memberFlags in slotsigs do + + let (SynValSig(range=m)) = synValSig + + CheckMemberFlags None NewSlotsOK OverridesOK memberFlags m + + let slots = fst (TcAndPublishValSpec (cenv, envinner, containerInfo, ModuleOrMemberBinding, Some memberFlags, tpenv, synValSig)) + // Multiple slots may be returned, e.g. for + // abstract P: int with get, set + + for slot in slots do + yield mkLocalValRef slot ] + let kind = match kind with | SynTypeDefnKind.Struct -> @@ -3632,6 +3646,9 @@ module EstablishTypeDefinitionCores = noCLIMutableAttributeCheck() structLayoutAttributeCheck(not isIncrClass) allowNullLiteralAttributeCheck() + for slot in abstractSlots do + if not slot.IsInstanceMember then + errorR(Error(FSComp.SR.chkStaticAbstractMembersOnClasses(), slot.Range)) TFSharpClass | SynTypeDefnKind.Delegate (ty, arity) -> noCLIMutableAttributeCheck() @@ -3666,21 +3683,7 @@ module EstablishTypeDefinitionCores = | (_, m, baseIdOpt) :: _ -> match baseIdOpt with | None -> Some(ident("base", m)) - | Some id -> Some id - - let abstractSlots = - [ for synValSig, memberFlags in slotsigs do - - let (SynValSig(range=m)) = synValSig - - CheckMemberFlags None NewSlotsOK OverridesOK memberFlags m - - let slots = fst (TcAndPublishValSpec (cenv, envinner, containerInfo, ModuleOrMemberBinding, Some memberFlags, tpenv, synValSig)) - // Multiple slots may be returned, e.g. for - // abstract P: int with get, set - - for slot in slots do - yield mkLocalValRef slot ] + | Some id -> Some id let baseValOpt = MakeAndPublishBaseVal cenv envinner baseIdOpt (superOfTycon g tycon) let safeInitInfo = ComputeInstanceSafeInitInfo cenv envinner thisTyconRef.Range thisTy @@ -4453,7 +4456,7 @@ module TcDeclarations = let slotsigs = members |> List.choose (function SynMemberDefn.AbstractSlot (slotSig = x; flags = y) -> Some(x, y) | _ -> None) - let members,_vals_Inherits_Abstractslots = SplitAutoProps members + let members, _vals_Inherits_Abstractslots = SplitAutoProps members let isConcrete = members |> List.exists (function diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index e5cabbdc7e3..d7dfe371f3e 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1746,4 +1746,5 @@ featureReuseSameFieldsInStructUnions,"Share underlying fields in a [] di 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" -3866,chkStaticAbstractInterfaceMembers,"A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.%s)." \ No newline at end of file +3866,chkStaticAbstractInterfaceMembers,"A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.%s)." +3867,chkStaticAbstractMembersOnClasses,"Classes cannot contain static abstract members." \ No newline at end of file diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index a7f9808f488..1e331ca0c1e 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. Objektové výrazy nemohou implementovat rozhraní se statickými abstraktními členy ani deklarovat statické členy. diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index 534e047744f..cb5bb611c16 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. Objektausdrücke können keine Schnittstellen mit statischen abstrakten Membern implementieren oder statische Member deklarieren. diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index 5d2517d1ca9..5a5520af8d0 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. Las expresiones de objeto no pueden implementar interfaces con miembros abstractos estáticos ni declarar miembros estáticos. diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index f5c4358314a..95f24fd7db2 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. Les expressions d’objet ne peuvent pas implémenter des interfaces avec des membres abstraits statiques ou déclarer des membres statiques. diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 350f2decb87..a4468df7f8e 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. Le espressioni di oggetto non possono implementare interfacce con membri astratti statici o dichiarare membri statici. diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 376d3d8d592..358cf700cf0 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. オブジェクト式は、静的抽象メンバーを持つインターフェイスを実装したり、静的メンバーを宣言したりすることはできません。 diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index f4a42405fcb..5784d4264e1 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. 개체 식은 정적 추상 멤버가 있는 인터페이스를 구현하거나 정적 멤버를 선언할 수 없습니다. diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index f081661bf4e..f2858d49504 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. Wyrażenia obiektów nie mogą implementować interfejsów ze statycznymi abstrakcyjnymi elementami członkowskimi ani deklarować statycznych elementów członkowskich. diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index b17c0b76d24..cdff3ed5b34 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. Expressões de objeto não podem implementar interfaces com membros abstratos estáticos ou declarar membros estáticos. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 7f83d96d646..9d1790e8dc9 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. Выражения объектов не могут реализовывать интерфейсы со статическими абстрактными членами или объявлять статические члены. diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index f74a800f285..b8bdd5e9cc6 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. Nesne ifadeleri, statik soyut üyeler içeren arabirimleri uygulayamaz veya statik üyeleri bildiremez. diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 19dae40d40a..f06487e86bd 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. 对象表达式无法实现具有静态抽象成员或声明静态成员的接口。 diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 4f332483292..f80470220b3 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -127,6 +127,11 @@ A static abstract non-virtual interface member should only be called via type parameter (for example: 'T.{0}). + + Classes cannot contain static abstract members. + Classes cannot contain static abstract members. + + Object expressions cannot implement interfaces with static abstract members or declare static members. 物件運算式無法實作具有靜態抽象成員的介面或宣告靜態成員。 diff --git a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs index 48c54e2c11e..3e971a054b0 100644 --- a/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Conformance/Types/TypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs @@ -1241,4 +1241,31 @@ printf "%A" res""" (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).") - ] \ No newline at end of file + ] + + [] + let ``Error message that explicitly disallows static abstract methods in abstract classes.`` () = + Fsx """ +[] +type A () = + static abstract M : unit -> unit + """ + |> withOptions [ "--nowarn:3536" ; "--nowarn:3535" ] + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 3867, Line 4, Col 21, Line 4, Col 22, "Classes cannot contain static abstract members.") + ] + + [] + let ``Error message that explicitly disallows static abstract methods in classes.`` () = + Fsx """ +type A () = + static abstract M : unit -> unit + """ + |> withOptions [ "--nowarn:3536" ; "--nowarn:3535" ] + |> typecheck + |> shouldFail + |> withDiagnostics [ + (Error 3867, Line 3, Col 21, Line 3, Col 22, "Classes cannot contain static abstract members.") + ] diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs index d10bc4fb138..d2d5ae7b01d 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinition.fs @@ -29,7 +29,7 @@ open System.Text.RegularExpressions open CancellableTasks open Microsoft.VisualStudio.FSharp.Editor.Telemetry open Microsoft.VisualStudio.Telemetry -open System.Collections.Generic +open Microsoft.VisualStudio.Threading module private Symbol = let fullName (root: ISymbol) : string = @@ -565,6 +565,77 @@ type internal GoToDefinition(metadataAsSource: FSharpMetadataAsSourceService) = return this.NavigateToItem(item, cancellationToken) } + member this.NavigateToExternalDeclarationAsync(targetSymbolUse: FSharpSymbolUse, metadataReferences: seq) = + let textOpt = + match targetSymbolUse.Symbol with + | :? FSharpEntity as symbol -> symbol.TryGetMetadataText() |> Option.map (fun text -> text, symbol.DisplayName) + | :? FSharpMemberOrFunctionOrValue as symbol -> + symbol.ApparentEnclosingEntity.TryGetMetadataText() + |> Option.map (fun text -> text, symbol.ApparentEnclosingEntity.DisplayName) + | :? FSharpField as symbol -> + match symbol.DeclaringEntity with + | Some entity -> + let text = entity.TryGetMetadataText() + + match text with + | Some text -> Some(text, entity.DisplayName) + | None -> None + | None -> None + | :? FSharpUnionCase as symbol -> + symbol.DeclaringEntity.TryGetMetadataText() + |> Option.map (fun text -> text, symbol.DisplayName) + | _ -> None + + match textOpt with + | None -> CancellableTask.singleton false + | Some(text, fileName) -> + foregroundCancellableTask { + let! cancellationToken = CancellableTask.getCancellationToken () + do! ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken) + + let tmpProjInfo, tmpDocInfo = + MetadataAsSource.generateTemporaryDocument ( + AssemblyIdentity(targetSymbolUse.Symbol.Assembly.QualifiedName), + fileName, + metadataReferences + ) + + let tmpShownDocOpt = + metadataAsSource.ShowDocument(tmpProjInfo, tmpDocInfo.FilePath, SourceText.From(text.ToString())) + + match tmpShownDocOpt with + | ValueNone -> return false + | ValueSome tmpShownDoc -> + let! _, checkResults = tmpShownDoc.GetFSharpParseAndCheckResultsAsync("NavigateToExternalDeclaration") + + let r = + // This tries to find the best possible location of the target symbol's location in the metadata source. + // We really should rely on symbol equality within FCS instead of doing it here, + // but the generated metadata as source isn't perfect for symbol equality. + let symbols = checkResults.GetAllUsesOfAllSymbolsInFile(cancellationToken) + + symbols + |> Seq.tryFindV (tryFindExternalSymbolUse targetSymbolUse) + |> ValueOption.map (fun x -> x.Range) + + let! span = + cancellableTask { + let! cancellationToken = CancellableTask.getCancellationToken () + + match r with + | ValueNone -> return TextSpan.empty + | ValueSome r -> + let! text = tmpShownDoc.GetTextAsync(cancellationToken) + + match RoslynHelpers.TryFSharpRangeToTextSpan(text, r) with + | ValueSome span -> return span + | _ -> return TextSpan.empty + } + + let navItem = FSharpGoToDefinitionNavigableItem(tmpShownDoc, span) + return this.NavigateToItem(navItem, cancellationToken) + } + member this.NavigateToExternalDeclaration ( targetSymbolUse: FSharpSymbolUse, @@ -706,10 +777,15 @@ type internal FSharpNavigation(metadataAsSource: FSharpMetadataAsSourceService, let gtd = GoToDefinition(metadataAsSource) let! result = gtd.FindDefinitionAtPosition(initialDoc, position) - return - match result with - | ValueSome(FSharpGoToDefinitionResult.NavigableItem(navItem), _) -> ImmutableArray.create navItem - | _ -> ImmutableArray.empty + match result with + | ValueSome(FSharpGoToDefinitionResult.NavigableItem(navItem), _) -> return ImmutableArray.create navItem + | ValueSome(FSharpGoToDefinitionResult.ExternalAssembly(targetSymbolUse, metadataReferences), _) -> + do! + gtd.NavigateToExternalDeclarationAsync(targetSymbolUse, metadataReferences) + |> CancellableTask.ignore + + return ImmutableArray.empty + | _ -> return ImmutableArray.empty } member _.TryGoToDefinition(position, cancellationToken) = diff --git a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs index 3130163b192..a51cf0e6943 100644 --- a/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs +++ b/vsintegration/src/FSharp.Editor/Navigation/GoToDefinitionService.fs @@ -18,13 +18,13 @@ type internal FSharpGoToDefinitionService [] (metadataAsSo interface IFSharpGoToDefinitionService with /// Invoked with Peek Definition. - member _.FindDefinitionsAsync(document: Document, position: int, cancellationToken: CancellationToken) = + member _.FindDefinitionsAsync(document: Document, position: int, _cancellationToken: CancellationToken) = cancellableTask { let navigation = FSharpNavigation(metadataAsSource, document, rangeStartup) let! res = navigation.FindDefinitionsAsync(position) return (res :> IEnumerable<_>) } - |> CancellableTask.start cancellationToken + |> CancellableTask.startWithoutCancellation /// Invoked with Go to Definition. /// Try to navigate to the definiton of the symbol at the symbolRange in the originDocument From 96e6c797fda8040f336eafeb5a30abe3a24e383c Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Mon, 22 Apr 2024 05:02:25 -0700 Subject: [PATCH 5/6] Localized file check-in by OneLocBuild Task: Build definition ID 499: Build ID 2434439 (#17073) --- src/Compiler/xlf/FSStrings.cs.xlf | 2 +- src/Compiler/xlf/FSStrings.de.xlf | 2 +- src/Compiler/xlf/FSStrings.es.xlf | 2 +- src/Compiler/xlf/FSStrings.fr.xlf | 2 +- src/Compiler/xlf/FSStrings.it.xlf | 2 +- src/Compiler/xlf/FSStrings.ja.xlf | 2 +- src/Compiler/xlf/FSStrings.ko.xlf | 2 +- src/Compiler/xlf/FSStrings.pl.xlf | 2 +- src/Compiler/xlf/FSStrings.pt-BR.xlf | 2 +- src/Compiler/xlf/FSStrings.ru.xlf | 2 +- src/Compiler/xlf/FSStrings.tr.xlf | 2 +- src/Compiler/xlf/FSStrings.zh-Hans.xlf | 2 +- src/Compiler/xlf/FSStrings.zh-Hant.xlf | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Compiler/xlf/FSStrings.cs.xlf b/src/Compiler/xlf/FSStrings.cs.xlf index 8fa85e6c640..4ed675a7d46 100644 --- a/src/Compiler/xlf/FSStrings.cs.xlf +++ b/src/Compiler/xlf/FSStrings.cs.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - Tento typ je abstract, protože se neimplementovali někteří abstraktní členové. Pokud je to záměr, pak k typu přidejte atribut [<AbstractClass>]. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.de.xlf b/src/Compiler/xlf/FSStrings.de.xlf index 46c2c4eb4f1..4109711fe52 100644 --- a/src/Compiler/xlf/FSStrings.de.xlf +++ b/src/Compiler/xlf/FSStrings.de.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - Der Typ entspricht „abstract“, da einige abstrakte Member nicht mit einer Implementierung versehen wurden. Wenn dies Ihre Absicht ist, fügen Sie das [<AbstractClass>]-Attribut zu Ihrem Typ hinzu. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.es.xlf b/src/Compiler/xlf/FSStrings.es.xlf index 0009c7dd034..458e6e42fd7 100644 --- a/src/Compiler/xlf/FSStrings.es.xlf +++ b/src/Compiler/xlf/FSStrings.es.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - Este tipo es "abstract" ya que a algunos miembros abstractos no se les ha dado una implementación. Si esto es intencional, agregue el atributo "[<AbstractClass>]" + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.fr.xlf b/src/Compiler/xlf/FSStrings.fr.xlf index 788fbf8d78d..675c87f2c90 100644 --- a/src/Compiler/xlf/FSStrings.fr.xlf +++ b/src/Compiler/xlf/FSStrings.fr.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - Ce type est 'abstract', car des membres abstraits n'ont pas reçu d'implémentation. Si cela est intentionnel, ajoutez l'attribut '[<AbstractClass>]' à votre type. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.it.xlf b/src/Compiler/xlf/FSStrings.it.xlf index 98994f92f88..f0c3c7c502b 100644 --- a/src/Compiler/xlf/FSStrings.it.xlf +++ b/src/Compiler/xlf/FSStrings.it.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - Questo tipo è 'abstract' perché non è stata specificata un'implementazione per alcuni membri astratti. Se questa scelta è intenzionale, aggiungere l'attributo '[<AbstractClass>]' al tipo. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.ja.xlf b/src/Compiler/xlf/FSStrings.ja.xlf index e48f47c0f6f..3a856620ad6 100644 --- a/src/Compiler/xlf/FSStrings.ja.xlf +++ b/src/Compiler/xlf/FSStrings.ja.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - これは 'abstract' 型です。一部の抽象メンバーに実装がありません。意図的な場合には、型に '[<AbstractClass>]' 属性を追加してください。 + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.ko.xlf b/src/Compiler/xlf/FSStrings.ko.xlf index 31481aa4566..fba5c3c71e1 100644 --- a/src/Compiler/xlf/FSStrings.ko.xlf +++ b/src/Compiler/xlf/FSStrings.ko.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - 일부 추상 멤버에 구현이 지정되지 않았으므로 이 형식은 'abstract'입니다. 의도적으로 구현을 지정하지 않은 경우에는 형식에 '[<AbstractClass>]' 특성을 추가하세요. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.pl.xlf b/src/Compiler/xlf/FSStrings.pl.xlf index 8dde95ed7e9..5a7f64fd5eb 100644 --- a/src/Compiler/xlf/FSStrings.pl.xlf +++ b/src/Compiler/xlf/FSStrings.pl.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - Ten typ ma wartość „abstract”, ponieważ niektóre abstrakcyjne składowe nie mają określonej implementacji. Jeśli jest to zamierzone działanie, dodaj atrybut „[<AbstractClass>]” do typu. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.pt-BR.xlf b/src/Compiler/xlf/FSStrings.pt-BR.xlf index 5c17c16072b..17690fc703d 100644 --- a/src/Compiler/xlf/FSStrings.pt-BR.xlf +++ b/src/Compiler/xlf/FSStrings.pt-BR.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - Esse tipo é 'abstrato', pois alguns membros abstratos não receberam uma implementação. Se isso for intencional, adicione o atributo '[<AbstractClass>]' ao seu tipo. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.ru.xlf b/src/Compiler/xlf/FSStrings.ru.xlf index 07467917126..9d6e1832bf7 100644 --- a/src/Compiler/xlf/FSStrings.ru.xlf +++ b/src/Compiler/xlf/FSStrings.ru.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - Этот тип является абстрактным ('abstract'), так как для нескольких абстрактных членов не указана реализация. Если это сделано намеренно, добавьте атрибут '[<AbstractClass>]' к своему типу. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.tr.xlf b/src/Compiler/xlf/FSStrings.tr.xlf index c4123c8a985..37b7c963595 100644 --- a/src/Compiler/xlf/FSStrings.tr.xlf +++ b/src/Compiler/xlf/FSStrings.tr.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - Bazı soyut üyelere bir uygulama verilmediğinden bu bir 'abstract' türdür. Bu bilerek yapıldıysa türünüze '[<AbstractClass>]' özniteliğini ekleyin. + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.zh-Hans.xlf b/src/Compiler/xlf/FSStrings.zh-Hans.xlf index 4af6f427ebd..3ba86d203d8 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hans.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hans.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - 由于未向一些抽象成员提供实现,因此该类型为 "abstract"。如果是故意如此,请向你的类型添加 "[<AbstractClass>]" 属性。 + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. diff --git a/src/Compiler/xlf/FSStrings.zh-Hant.xlf b/src/Compiler/xlf/FSStrings.zh-Hant.xlf index d945cbe3d33..670e7b26117 100644 --- a/src/Compiler/xlf/FSStrings.zh-Hant.xlf +++ b/src/Compiler/xlf/FSStrings.zh-Hant.xlf @@ -249,7 +249,7 @@ Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. - 因為未提供實作給某些抽象成員,所以此類型為 'abstract'。如果這是預期的情況,則請將 '[<AbstractClass>]' 屬性新增到您的類型。 + Non-abstract classes cannot contain abstract members. Either provide a default member implementation or add the '[<AbstractClass>]' attribute to your type. From 9881e3b215a6b0ae64b83ffacac518314ca6a19d Mon Sep 17 00:00:00 2001 From: dotnet bot Date: Tue, 23 Apr 2024 05:14:10 -0700 Subject: [PATCH 6/6] Don't split resumable code (#17076) (#17078) Co-authored-by: Vlad Zarytovskii --- .../.FSharp.Compiler.Service/8.0.400.md | 2 +- src/Compiler/Optimize/Optimizer.fs | 13 ++++- .../Language/StateMachineTests.fs | 55 +++++++++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md index 56eed1f56bc..16ead61175e 100644 --- a/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md +++ b/docs/release-notes/.FSharp.Compiler.Service/8.0.400.md @@ -8,4 +8,4 @@ * Files passed with -embed:relative/path/to/file are not embedded. ([Issue #16768](https://github.com/dotnet/fsharp/pull/17068)) * 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), [PR #17048](https://github.com/dotnet/fsharp/pull/17048)) * Fix calling an overridden virtual static method via the interface ([PR #17013](https://github.com/dotnet/fsharp/pull/17013)) - +* Fix state machines compilation, when big decision trees are involved, by removing code split when resumable code is detected ([PR #17076](https://github.com/dotnet/fsharp/pull/17076)) diff --git a/src/Compiler/Optimize/Optimizer.fs b/src/Compiler/Optimize/Optimizer.fs index fafb8184600..6a26f85ec6f 100644 --- a/src/Compiler/Optimize/Optimizer.fs +++ b/src/Compiler/Optimize/Optimizer.fs @@ -2314,7 +2314,7 @@ let IsILMethodRefSystemStringConcatArray (mref: ILMethodRef) = ilTy.IsNominal && ilTy.TypeRef.Name = "System.String" -> true | _ -> false)) - + let rec IsDebugPipeRightExpr cenv expr = let g = cenv.g match expr with @@ -2329,6 +2329,13 @@ let rec IsDebugPipeRightExpr cenv expr = else false | _ -> false +let inline IsStateMachineExpr g overallExpr = + //printfn "%s" (DebugPrint.showExpr overallExpr) + match overallExpr with + | Expr.App(funcExpr = Expr.Val(valRef = valRef)) -> + isReturnsResumableCodeTy g valRef.TauType + | _ -> false + /// Optimize/analyze an expression let rec OptimizeExpr cenv (env: IncrementalOptimizationEnv) expr = cenv.stackGuard.Guard <| fun () -> @@ -2343,6 +2350,10 @@ let rec OptimizeExpr cenv (env: IncrementalOptimizationEnv) expr = if IsDebugPipeRightExpr cenv expr then OptimizeDebugPipeRights cenv env expr else + let isStateMachineE = IsStateMachineExpr g expr + + let env = { env with disableMethodSplitting = env.disableMethodSplitting || isStateMachineE } + match expr with // treat the common linear cases to avoid stack overflows, using an explicit continuation | LinearOpExpr _ diff --git a/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs b/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs index dd031134f63..c4aed123505 100644 --- a/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs +++ b/tests/FSharp.Compiler.ComponentTests/Language/StateMachineTests.fs @@ -103,6 +103,61 @@ let compute () = for i in 1 .. 100 do compute().Wait () """ + |> withOptimize + |> compileExeAndRun + |> shouldSucceed + + [] // https://github.com/dotnet/fsharp/issues/16068 + let ``Decision tree with 32+ binds with nested expression is not getting splitted and state machine is successfully statically compiles``() = + FSharp """ +module Testing + +let test () = + task { + if true then + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + let c = failwith "" + () + } + +[] +let main _ = + test () |> ignore + printfn "Hello, World!" + 0 +""" + |> ignoreWarnings |> withOptimize |> compileExeAndRun |> shouldSucceed \ No newline at end of file