Skip to content

Commit 1d892dd

Browse files
github-actions[bot]vzarytovskiiT-Grodsyme
authored
[release/dev17.4] F# 7 fixes (#14322)
* WIP: Fix for calling init-only setter via srtp call + allow calling special-named functions via srtp * Fix 14097 Co-authored-by: Vlad Zarytovskii <[email protected]> Co-authored-by: Tomas Grosup <[email protected]> Co-authored-by: Don Syme <[email protected]>
1 parent f90ab57 commit 1d892dd

File tree

5 files changed

+148
-14
lines changed

5 files changed

+148
-14
lines changed

src/Compiler/Checking/CheckExpressions.fs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8534,7 +8534,12 @@ and TcTraitItemThen (cenv: cenv) overallTy env objOpt traitInfo tpenv mItem dela
85348534
applicableExpr, exprTy
85358535
| _ ->
85368536
let vs, ves = argTys |> List.mapi (fun i ty -> mkCompGenLocal mItem ("arg" + string i) ty) |> List.unzip
8537-
let traitCall = Expr.Op (TOp.TraitCall traitInfo, [], objArgs@ves, mItem)
8537+
// Account for a unit mismtach in logical v. compiled arguments
8538+
let compiledArgExprs =
8539+
match argTys, traitInfo.GetCompiledArgumentTypes() with
8540+
| [_], [] -> []
8541+
| _ -> ves
8542+
let traitCall = Expr.Op (TOp.TraitCall traitInfo, [], objArgs@compiledArgExprs, mItem)
85388543
let v, body = MultiLambdaToTupledLambda g vs traitCall
85398544
let expr = mkLambda mItem v (body, retTy)
85408545
let exprTy = tyOfExpr g expr

src/Compiler/TypedTree/TcGlobals.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1830,12 +1830,12 @@ type TcGlobals(
18301830
let info = makeOtherIntrinsicValRef (fslib_MFOperators_nleref, "atan2", None, Some "Atan2", [vara; varb], ([[varaTy]; [varaTy]], varbTy))
18311831
let tyargs = [aty;bty]
18321832
Some (info, tyargs, argExprs)
1833-
| "get_Zero", _, Some aty, [_] ->
1833+
| "get_Zero", _, Some aty, ([] | [_]) ->
18341834
// Call LanguagePrimitives.GenericZero
18351835
let info = makeOtherIntrinsicValRef (fslib_MFLanguagePrimitives_nleref, "GenericZero", None, None, [vara], ([], varaTy))
18361836
let tyargs = [aty]
18371837
Some (info, tyargs, [])
1838-
| "get_One", _, Some aty, [_] ->
1838+
| "get_One", _, Some aty, ([] | [_]) ->
18391839
// Call LanguagePrimitives.GenericOne
18401840
let info = makeOtherIntrinsicValRef (fslib_MFLanguagePrimitives_nleref, "GenericOne", None, None, [vara], ([], varaTy))
18411841
let tyargs = [aty]

tests/FSharp.Compiler.ComponentTests/Conformance/TypesAndTypeConstraints/IWSAMsAndSRTPs/IWSAMsAndSRTPsTests.fs

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,38 @@ let setupCompilation compilation =
1919
|> withReferences [typesModule]
2020

2121

22+
[<Fact>]
23+
let ``Srtp call Zero property returns valid result`` () =
24+
Fsx """
25+
let inline zero<'T when 'T: (static member Zero: 'T)> = 'T.Zero
26+
let result = zero<int>
27+
if result <> 0 then failwith $"Something's wrong: {result}"
28+
"""
29+
|> runFsi
30+
|> shouldSucceed
31+
32+
[<Fact>]
33+
let ``Srtp call to custom property returns valid result`` () =
34+
FSharp """
35+
module Foo
36+
type Foo =
37+
static member Bar = 1
38+
39+
type HasBar<'T when 'T: (static member Bar: int)> = 'T
40+
41+
let inline bar<'T when HasBar<'T>> =
42+
'T.Bar
43+
44+
[<EntryPoint>]
45+
let main _ =
46+
let result = bar<Foo>
47+
if result <> 0 then
48+
failwith $"Unexpected result: {result}"
49+
0
50+
"""
51+
|> asExe
52+
|> compileAndRun
53+
2254
#if !NETCOREAPP
2355
[<Theory(Skip = "IWSAMs are not supported by NET472.")>]
2456
#else
@@ -775,7 +807,11 @@ module ``Active patterns`` =
775807

776808
module ``Suppression of System Numerics interfaces on unitized types`` =
777809

778-
[<Fact(Skip = "Solution needs to be updated to .NET 7")>]
810+
#if !NETCOREAPP
811+
[<Fact(Skip = "IWSAMs are not supported by NET472.")>]
812+
#else
813+
[<Fact>]
814+
#endif
779815
let Baseline () =
780816
Fsx """
781817
open System.Numerics
@@ -785,16 +821,19 @@ module ``Suppression of System Numerics interfaces on unitized types`` =
785821
|> compile
786822
|> shouldSucceed
787823

788-
[<Theory(Skip = "Solution needs to be updated to .NET 7")>]
824+
#if !NETCOREAPP
825+
[<Theory(Skip = "IWSAMs are not supported by NET472.")>]
826+
#else
827+
[<Theory>]
789828
[<InlineData("IAdditionOperators", 3)>]
790829
[<InlineData("IAdditiveIdentity", 2)>]
791830
[<InlineData("IBinaryFloatingPointIeee754", 1)>]
792831
[<InlineData("IBinaryNumber", 1)>]
793832
[<InlineData("IBitwiseOperators", 3)>]
794-
[<InlineData("IComparisonOperators", 2)>]
833+
[<InlineData("IComparisonOperators", 3)>]
795834
[<InlineData("IDecrementOperators", 1)>]
796835
[<InlineData("IDivisionOperators", 3)>]
797-
[<InlineData("IEqualityOperators", 2)>]
836+
[<InlineData("IEqualityOperators", 3)>]
798837
[<InlineData("IExponentialFunctions", 1)>]
799838
[<InlineData("IFloatingPoint", 1)>]
800839
[<InlineData("IFloatingPointIeee754", 1)>]
@@ -814,6 +853,7 @@ module ``Suppression of System Numerics interfaces on unitized types`` =
814853
[<InlineData("ITrigonometricFunctions", 1)>]
815854
[<InlineData("IUnaryNegationOperators", 2)>]
816855
[<InlineData("IUnaryPlusOperators", 2)>]
856+
#endif
817857
let ``Unitized type shouldn't be compatible with System.Numerics.I*`` name paramCount =
818858
let typeParams = Seq.replicate paramCount "'T" |> String.concat ","
819859
let genericType = $"{name}<{typeParams}>"

tests/FSharp.Compiler.ComponentTests/Conformance/TypesAndTypeConstraints/IWSAMsAndSRTPs/testFiles/CheckNewSyntax.fs

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,31 @@ module CheckNewSyntax =
44

55
type MyType() =
66
static member val StaticProperty = 0 with get, set
7-
static member StaticMethod x = x + 5
7+
static member StaticMethod0 () = 5
8+
static member StaticMethod1 x = x + 5
9+
static member StaticMethod2 (x, y) = x + y + 5
810
member val Length = 0 with get, set
911
member _.Item with get x = "Hello"
10-
member _.InstanceMethod x = x + 5
12+
member _.InstanceMethod0 () = 5
13+
member _.InstanceMethod1 x = x + 5
14+
member _.InstanceMethod2 (x, y) = x + y + 5
1115

1216
// Check that "property" and "get_ method" constraints are considered logically equivalent
1317
let inline f_StaticProperty<'T when 'T : (static member StaticProperty: int) >() : int = 'T.StaticProperty
1418

15-
let inline f_StaticMethod<'T when 'T : (static member StaticMethod: int -> int) >() : int = 'T.StaticMethod(3)
19+
let inline f_StaticMethod0<'T when 'T : (static member StaticMethod0: unit -> int) >() : int = 'T.StaticMethod0()
20+
21+
let inline f_StaticMethod1<'T when 'T : (static member StaticMethod1: int -> int) >() : int = 'T.StaticMethod1(3)
22+
23+
let inline f_StaticMethod2<'T when 'T : (static member StaticMethod2: int * int -> int) >() : int = 'T.StaticMethod2(3, 3)
1624

1725
let inline f_set_StaticProperty<'T when 'T : (static member StaticProperty: int with set) >() = 'T.set_StaticProperty(3)
1826

19-
let inline f_InstanceMethod<'T when 'T : (member InstanceMethod: int -> int) >(x: 'T) : int = x.InstanceMethod(3)
27+
let inline f_InstanceMethod0<'T when 'T : (member InstanceMethod0: unit -> int) >(x: 'T) : int = x.InstanceMethod0()
28+
29+
let inline f_InstanceMethod1<'T when 'T : (member InstanceMethod1: int -> int) >(x: 'T) : int = x.InstanceMethod1(3)
30+
31+
let inline f_InstanceMethod2<'T when 'T : (member InstanceMethod2: int * int -> int) >(x: 'T) : int = x.InstanceMethod2(3, 3)
2032

2133
let inline f_Length<'T when 'T : (member Length: int) >(x: 'T) = x.Length
2234

@@ -33,7 +45,13 @@ module CheckNewSyntax =
3345
//let inline f_set_Length2<'T when 'T : (member Length: int with set) >(x: 'T) = x.Length <- 3
3446
//let inline f_Item2<'T when 'T : (member Item: int -> string with get) >(x: 'T) = x[3]
3547

36-
if f_StaticMethod<MyType>() <> 8 then
48+
if f_StaticMethod0<MyType>() <> 5 then
49+
failwith "Unexpected result"
50+
51+
if f_StaticMethod1<MyType>() <> 8 then
52+
failwith "Unexpected result"
53+
54+
if f_StaticMethod2<MyType>() <> 11 then
3755
failwith "Unexpected result"
3856

3957
if f_set_StaticProperty<MyType>() <> () then
@@ -47,7 +65,13 @@ module CheckNewSyntax =
4765
if f_Length(myInstance) <> 0 then
4866
failwith "Unexpected result"
4967

50-
if f_InstanceMethod(myInstance) <> 8 then
68+
if f_InstanceMethod0(myInstance) <> 5 then
69+
failwith "Unexpected result"
70+
71+
if f_InstanceMethod1(myInstance) <> 8 then
72+
failwith "Unexpected result"
73+
74+
if f_InstanceMethod2(myInstance) <> 11 then
5175
failwith "Unexpected result"
5276

5377
if f_set_Length(myInstance) <> () then

tests/FSharp.Compiler.ComponentTests/Interop/RequiredAndInitOnlyProperties.fs

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,14 @@ open System
88

99
module ``Required and init-only properties`` =
1010

11+
let csharpRecord =
12+
CSharp """
13+
namespace RequiredAndInitOnlyProperties
14+
{
15+
public record Recd();
16+
17+
}""" |> withCSharpLanguageVersion CSharpLanguageVersion.Preview |> withName "csLib"
18+
1119
let csharpBaseClass =
1220
CSharp """
1321
namespace RequiredAndInitOnlyProperties
@@ -228,7 +236,7 @@ let main _ =
228236
Error 810, Line 9, Col 5, Line 9, Col 21, "Cannot call 'set_GetInit' - a setter for init-only property, please use object initialization instead. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization"
229237
]
230238

231-
#if !NETCOREAPP
239+
#if !NETCOREAPP
232240
[<Fact(Skip = "NET472 is unsupported runtime for this kind of test.")>]
233241
#else
234242
[<Fact>]
@@ -259,6 +267,63 @@ let main _ =
259267
Error 810, Line 9, Col 38, Line 9, Col 40, "Init-only property 'GetInit' cannot be set outside the initialization code. See https://aka.ms/fsharp-assigning-values-to-properties-at-initialization"
260268
]
261269

270+
#if !NETCOREAPP
271+
[<Fact(Skip = "IWSAMs are not supported by NET472.")>]
272+
#else
273+
[<Fact>]
274+
#endif
275+
let ``F# can change init-only property via SRTP`` () =
276+
277+
let csharpLib = csharpBaseClass
278+
279+
let fsharpSource =
280+
"""
281+
open System
282+
open RequiredAndInitOnlyProperties
283+
284+
let inline setGetInit<'T when 'T : (member set_GetInit: int -> unit)> (a: 'T) (x: int) = a.set_GetInit(x)
285+
286+
[<EntryPoint>]
287+
let main _ =
288+
let raio = RAIO()
289+
setGetInit raio 111
290+
0
291+
"""
292+
FSharp fsharpSource
293+
|> asExe
294+
|> withLangVersion70
295+
|> withReferences [csharpLib]
296+
|> compile
297+
|> shouldSucceed
298+
299+
#if !NETCOREAPP
300+
[<Fact(Skip = "IWSAMs are not supported by NET472.")>]
301+
#else
302+
[<Fact>]
303+
#endif
304+
let ``F# can call special-named methods via SRTP`` () =
305+
306+
let csharpLib = csharpRecord
307+
308+
let fsharpSource =
309+
"""
310+
open System
311+
open RequiredAndInitOnlyProperties
312+
313+
let inline clone<'T when 'T : (member ``<Clone>$``: unit -> 'T)> (a: 'T) = a.``<Clone>$``()
314+
315+
[<EntryPoint>]
316+
let main _ =
317+
let recd = Recd()
318+
let _ = clone recd
319+
0
320+
"""
321+
FSharp fsharpSource
322+
|> asExe
323+
|> withLangVersion70
324+
|> withReferences [csharpLib]
325+
|> compile
326+
|> shouldSucceed
262327

263328
#if !NETCOREAPP
264329
[<Fact(Skip = "NET472 is unsupported runtime for this kind of test.")>]

0 commit comments

Comments
 (0)