From 3156f1a55daa849190233ffc7db6428fa8eb5fb6 Mon Sep 17 00:00:00 2001 From: psfinaki Date: Tue, 6 Aug 2024 15:02:46 +0200 Subject: [PATCH 1/2] C# params interop tests --- .../FSharp.Compiler.ComponentTests.fsproj | 2 + .../Interop/ParamArray.fs | 74 ++++++++++++ .../Interop/ParamArrayMigrated.fs | 110 ++++++++++++++++++ tests/FSharp.Test.Utilities/Compiler.fs | 3 + .../Source/Misc/ConsumeParamArray.fsscript | 56 --------- .../Source/Misc/E_ConsumeParamArray.fsscript | 35 ------ tests/fsharpqa/Source/Misc/ParamArray.cs | 33 ------ tests/fsharpqa/Source/Misc/env.lst | 3 - 8 files changed, 189 insertions(+), 127 deletions(-) create mode 100644 tests/FSharp.Compiler.ComponentTests/Interop/ParamArray.fs create mode 100644 tests/FSharp.Compiler.ComponentTests/Interop/ParamArrayMigrated.fs delete mode 100644 tests/fsharpqa/Source/Misc/ConsumeParamArray.fsscript delete mode 100644 tests/fsharpqa/Source/Misc/E_ConsumeParamArray.fsscript delete mode 100644 tests/fsharpqa/Source/Misc/ParamArray.cs diff --git a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj index 3cbbe3ef3c5..0509d424f8b 100644 --- a/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj +++ b/tests/FSharp.Compiler.ComponentTests/FSharp.Compiler.ComponentTests.fsproj @@ -250,6 +250,8 @@ + + diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/ParamArray.fs b/tests/FSharp.Compiler.ComponentTests/Interop/ParamArray.fs new file mode 100644 index 00000000000..e9c6a6705a4 --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Interop/ParamArray.fs @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Interop + +open Xunit +open FSharp.Test +open FSharp.Test.Compiler + +module ParamArray = + + [] + let ``C# 13 params enhancements`` () = + let csharp = + CSharp """ +using System; +using System.Collections.Generic; + +namespace CSharpAssembly; + +public class CS13ParamArray +{ + public static void WriteNames(params string[] names) + => Console.WriteLine("First: " + string.Join(" + ", names)); + + public static void WriteNames(params List names) + => Console.WriteLine("Second: " + string.Join(" + ", names)); + + public static void WriteNames(params IEnumerable names) + => Console.WriteLine("Third: " + string.Join(" + ", names)); +}""" + |> withCSharpLanguageVersionPreview + + FSharp """ +open System.Collections.Generic; +open CSharpAssembly + +CS13ParamArray.WriteNames("Petr", "Jana") +CS13ParamArray.WriteNames(List["Petr"; "Jana"]) +CS13ParamArray.WriteNames(["Petr"; "Jana"]) +""" + |> withReferences [csharp] + |> compileExeAndRun + |> shouldSucceed + |> withStdOutContainsAllInOrder [ + "First: Petr + Jana" + "Second: Petr + Jana" + "Third: Petr + Jana" + ] + + [] + let ``C# 13 params enhancements - ReadOnlySpan`` () = + let csharp = + CSharp """ +using System; + +namespace CSharpAssembly; + +public class CS13ParamArray +{ + public static void WriteNames(params ReadOnlySpan names) + => Console.WriteLine(string.Join(" + ", names)); +}""" + |> withCSharpLanguageVersionPreview + + FSharp """ +open System +open CSharpAssembly + +CS13ParamArray.WriteNames(ReadOnlySpan([|"Petr"; "Jana"|])) +""" + |> withReferences [csharp] + |> compileExeAndRun + |> shouldSucceed + |> withStdOutContainsAllInOrder [ "Petr + Jana" ] diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/ParamArrayMigrated.fs b/tests/FSharp.Compiler.ComponentTests/Interop/ParamArrayMigrated.fs new file mode 100644 index 00000000000..c5a0fd0796a --- /dev/null +++ b/tests/FSharp.Compiler.ComponentTests/Interop/ParamArrayMigrated.fs @@ -0,0 +1,110 @@ +// Copyright (c) Microsoft Corporation. All Rights Reserved. See License.txt in the project root for license information. + +namespace Interop + +open Xunit +open FSharp.Test.Compiler + +module ParamArrayMigrated = + + let csharp = + CSharp """ +using System; + +namespace CSharpAssembly +{ + [AttributeUsage(AttributeTargets.All)] + public class AttributeWithParamArray : Attribute + { + public object[] Parameters; + + public AttributeWithParamArray(params object[] x) + { + + Parameters = x; + } + } + + public class CSParamArray + { + public static int Method(params int[] allArgs) + { + int total = 0; + foreach (int i in allArgs) + total += i; + + return total; + } + + public static int Method(params T[] args) + { + return args.Length; + } + } +}""" + + [] + let ``Valid params call`` () = + FSharp """ +open System +open CSharpAssembly + +// Apply the attribute +[ obj) |])>] +type Foo() = + [ obj); ("bar" :> obj) |])>] + override this.ToString() = "Stuff" + +let callCSGenericMethod (a: 't[]) = CSParamArray.Method(a) + +[] +do + let getTestAttribute (t : Type) = + let tyAttributes = t.GetCustomAttributes(false) + let attrib = tyAttributes |> Array.find (fun attrib -> match attrib with :? AttributeWithParamArray -> true | _ -> false) + (attrib :?> AttributeWithParamArray) + + let tyFoo = typeof + let testAtt = getTestAttribute tyFoo + if testAtt.Parameters <> [| (0 :> obj) |] then + failwith "Attribute parameters not as expected" + + let directCallWorks = + CSParamArray.Method(9, 8, 7) + CSParamArray.Method(1, 2) + CSParamArray.Method() = (9 + 8 + 7) + (1 + 2) + if not directCallWorks then + failwith "Calling C# param array method gave unexpected result" + + let callParamArray (x : int array) = CSParamArray.Method(x) + let asArrayCallWorks = (callParamArray [| 9; 8; 7 |]) = (9 + 8 + 7) + if not asArrayCallWorks then + failwith "Calling C# param array method, passing args as an array, gave unexpected result" + + if callCSGenericMethod [|"1";"2";"3"|] <> 3 then + failwith "Calling C# generic param array method gave unexpected result" + + if CSParamArray.Method("1", "2", "3") <> CSParamArray.Method([|"1"; "2"; "3"|]) then + failwith "Calling C# generic param array in normal and expanded method gave unexpected result" +""" + |> withReferences [csharp] + |> compileExeAndRun + |> shouldSucceed + + [] + let ``Invalid params call`` () = + FSharp """ +open CSharpAssembly + +[] +type Foo() = + override this.ToString() = "Stuff" +""" + |> withReferences [csharp] + |> asExe + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 13, Line 4, Col 29, Line 4, Col 37, + "The static coercion from type\n int \nto \n 'a \n involves an indeterminate type based on information prior to this program point. Static coercions are not allowed on some types. Further type annotations are needed.") + (Error 267, Line 4, Col 29, Line 4, Col 37, + "This is not a valid constant expression or custom attribute value") + ] diff --git a/tests/FSharp.Test.Utilities/Compiler.fs b/tests/FSharp.Test.Utilities/Compiler.fs index 9fb050b09df..1edd5ef5488 100644 --- a/tests/FSharp.Test.Utilities/Compiler.fs +++ b/tests/FSharp.Test.Utilities/Compiler.fs @@ -585,6 +585,9 @@ module rec Compiler = | CS cs -> CS { cs with LangVersion = ver } | _ -> failwith "Only supported in C#" + let withCSharpLanguageVersionPreview = + withCSharpLanguageVersion CSharpLanguageVersion.Preview + let withOutputType (outputType : CompileOutput) (cUnit: CompilationUnit) : CompilationUnit = match cUnit with | FS x -> FS { x with OutputType = outputType } diff --git a/tests/fsharpqa/Source/Misc/ConsumeParamArray.fsscript b/tests/fsharpqa/Source/Misc/ConsumeParamArray.fsscript deleted file mode 100644 index 188c6459f38..00000000000 --- a/tests/fsharpqa/Source/Misc/ConsumeParamArray.fsscript +++ /dev/null @@ -1,56 +0,0 @@ -// #Regression #Misc -#light - -// Test that F# can consume C# param arrays. (Can't use variable number of arguments, rather -// arguments will just be exposed as taking an array.) -// FSB 1105, params attributes not supported -// This is also regression test for FSHARP1.0:3817 -open System - -#r "ParamArray.dll" -open CSharpAssembly - -// Apply the attribute -[ obj) |])>] -type Foo() = - [ obj); ("bar" :> obj) |])>] - override this.ToString() = "Stuff" - -let callCSGenericMethod (a: 't[]) = CSParamArray.Method(a) - -[] -do - let getTestAttribute (t : Type) = - let tyAttributes = t.GetCustomAttributes(false) - let attrib = tyAttributes |> Array.find (fun attrib -> match attrib with :? AttributeWithParamArray -> true | _ -> false) - (attrib :?> AttributeWithParamArray) - - let tyFoo = typeof - let testAtt = getTestAttribute tyFoo - if testAtt.Parameters <> [| (0 :> obj) |] then - printfn "Attribute parameters not as expected" - exit 1 - - let directCallWorks = - CSParamArray.Method(9, 8, 7) + CSParamArray.Method(1, 2) + CSParamArray.Method() = (9 + 8 + 7) + (1 + 2) - if not directCallWorks then - printfn "Calling C# param array method gave unexpected result" - exit 1 - - let callParamArray (x : int array) = CSParamArray.Method(x) - let asArrayCallWorks = (callParamArray [| 9; 8; 7 |]) = (9 + 8 + 7) - if not asArrayCallWorks then - printfn "Calling C# param array method, passing args as an array, gave unexpected result" - exit 1 - - if callCSGenericMethod [|"1";"2";"3"|] <> 3 then - printfn "Calling C# generic param array method gave unexpected result" - exit 1 - - if CSParamArray.Method("1", "2", "3") <> CSParamArray.Method([|"1"; "2"; "3"|]) then - printfn "Calling C# generic param array in normal and expanded method gave unexpected result" - exit 1 - - exit 0 - - \ No newline at end of file diff --git a/tests/fsharpqa/Source/Misc/E_ConsumeParamArray.fsscript b/tests/fsharpqa/Source/Misc/E_ConsumeParamArray.fsscript deleted file mode 100644 index 8e6a7a1473d..00000000000 --- a/tests/fsharpqa/Source/Misc/E_ConsumeParamArray.fsscript +++ /dev/null @@ -1,35 +0,0 @@ -// #Regression #Misc -#light - -// This test used to be the regression test for FSHARP1.0:1105. -// This code is expected to fail compilation, yet it was able to detect FSHARP1.0:3817 -// so I am promoting it to negative testcases. -//The static coercion from type -open System - -#r "ParamArray.dll" -open CSharpAssembly - -// Apply the attribute -[] -type Foo() = - [] - override this.ToString() = "Stuff" - -[] -do - let testPassed = - let getTestAttribute (t : Type) = - let tyAttributes = t.GetCustomAttributes(false) - let attrib = tyAttributes |> Array.find (fun attrib -> match attrib with :? AttributeWithParamArray -> true | _ -> false) - (attrib :?> AttributeWithParamArray) - - let tyFoo = typeof - let testAtt = getTestAttribute tyFoo - if testAtt.Parameters <> [|upcast 0|] then - false - else - true - - if not testPassed then exit 1 - exit 0 diff --git a/tests/fsharpqa/Source/Misc/ParamArray.cs b/tests/fsharpqa/Source/Misc/ParamArray.cs deleted file mode 100644 index 6c7ae6108d7..00000000000 --- a/tests/fsharpqa/Source/Misc/ParamArray.cs +++ /dev/null @@ -1,33 +0,0 @@ -using System; - -namespace CSharpAssembly -{ - [AttributeUsage(AttributeTargets.All)] - public class AttributeWithParamArray : Attribute - { - public object[] Parameters; - - public AttributeWithParamArray(params object[] x) - { - - Parameters = x; - } - } - - public class CSParamArray - { - public static int Method(params int[] allArgs) - { - int total = 0; - foreach (int i in allArgs) - total += i; - - return total; - } - - public static int Method(params T[] args) - { - return args.Length; - } - } -} \ No newline at end of file diff --git a/tests/fsharpqa/Source/Misc/env.lst b/tests/fsharpqa/Source/Misc/env.lst index b2b236cb7f5..ada01d097f1 100644 --- a/tests/fsharpqa/Source/Misc/env.lst +++ b/tests/fsharpqa/Source/Misc/env.lst @@ -1,6 +1,3 @@ - PRECMD="\$CSC_PIPE /target:library ParamArray.cs" SOURCE=ConsumeParamArray.fsscript # ConsumeParamArray.fsscript - PRECMD="\$CSC_PIPE /target:library ParamArray.cs" SOURCE=E_ConsumeParamArray.fsscript # E_ConsumeParamArray.fsscript - SOURCE=E_productioncoverage01.fs # E_productioncoverage01.fs SOURCE=E_productioncoverage02.fs # E_productioncoverage02.fs SOURCE=E_productioncoverage03.fs SCFLAGS="--test:ErrorRanges" # E_productioncoverage03.fs From adf92c2071f21c5dfac040b1c09527a70db11e33 Mon Sep 17 00:00:00 2001 From: psfinaki Date: Wed, 7 Aug 2024 13:09:53 +0200 Subject: [PATCH 2/2] One more test --- .../Interop/ParamArray.fs | 33 +++++++++++++++++++ .../Interop/ParamArrayMigrated.fs | 4 +-- 2 files changed, 35 insertions(+), 2 deletions(-) diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/ParamArray.fs b/tests/FSharp.Compiler.ComponentTests/Interop/ParamArray.fs index e9c6a6705a4..3864857d969 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/ParamArray.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/ParamArray.fs @@ -72,3 +72,36 @@ CS13ParamArray.WriteNames(ReadOnlySpan([|"Petr"; "Jana"|])) |> compileExeAndRun |> shouldSucceed |> withStdOutContainsAllInOrder [ "Petr + Jana" ] + + [] + let ``C# 13 params enhancements - error when no matching overload is available`` () = + let csharp = + CSharp """ +using System; +using System.Collections.Generic; + +namespace CSharpAssembly; + +public class CS13ParamArray +{ + public static void WriteNames(params List names) + => Console.WriteLine("Second: " + string.Join(" + ", names)); + + public static void WriteNames(params IEnumerable names) + => Console.WriteLine("Third: " + string.Join(" + ", names)); +}""" + |> withCSharpLanguageVersionPreview + + FSharp """ +open CSharpAssembly + +CS13ParamArray.WriteNames("Petr", "Jana") +""" + |> withReferences [csharp] + |> asExe + |> compile + |> shouldFail + |> withDiagnostics [ + (Error 503, Line 4, Col 1, Line 4, Col 42, + "A member or object constructor 'WriteNames' taking 2 arguments is not accessible from this code location. All accessible versions of method 'WriteNames' take 1 arguments.") + ] \ No newline at end of file diff --git a/tests/FSharp.Compiler.ComponentTests/Interop/ParamArrayMigrated.fs b/tests/FSharp.Compiler.ComponentTests/Interop/ParamArrayMigrated.fs index c5a0fd0796a..0906682d6d6 100644 --- a/tests/FSharp.Compiler.ComponentTests/Interop/ParamArrayMigrated.fs +++ b/tests/FSharp.Compiler.ComponentTests/Interop/ParamArrayMigrated.fs @@ -104,7 +104,7 @@ type Foo() = |> shouldFail |> withDiagnostics [ (Error 13, Line 4, Col 29, Line 4, Col 37, - "The static coercion from type\n int \nto \n 'a \n involves an indeterminate type based on information prior to this program point. Static coercions are not allowed on some types. Further type annotations are needed.") + "The static coercion from type\n int \nto \n 'a \n involves an indeterminate type based on information prior to this program point. Static coercions are not allowed on some types. Further type annotations are needed.") (Error 267, Line 4, Col 29, Line 4, Col 37, - "This is not a valid constant expression or custom attribute value") + "This is not a valid constant expression or custom attribute value") ]