Skip to content

Commit 142afe4

Browse files
authored
[TS/Python] Fix invalid this argument type in structs (#4453) (#4454)
1 parent 326c3b1 commit 142afe4

10 files changed

Lines changed: 82 additions & 11 deletions

File tree

src/Fable.Cli/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Fixed
1111

12+
* [TS/Python] Fix invalid `this` argument type in structs (#4453) (by @ncave)
1213
* [JS/TS] Fix `N` format specifier (`ToString("N0")`, `String.Format("{0:N0}", ...)`) producing a trailing dot when precision is 0 (fix #2582) (by @MangelMaxime)
1314
* [JS/TS] Fix `C0` and `P0` format specifiers producing trailing dot (e.g., `"¤1,000."``"¤1,000"`) (by @MangelMaxime)
1415
* [All] Fix captured side-effect-free values (e.g. empty ResizeArray) being incorrectly inlined into object expression getters in release mode, causing a new instance to be created on each getter call (fixes #3779) (by @MangelMaxime)

src/Fable.Compiler/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Fixed
1111

12+
* [TS/Python] Fix invalid `this` argument type in structs (#4453) (by @ncave)
1213
* [JS/TS] Fix `N` format specifier (`ToString("N0")`, `String.Format("{0:N0}", ...)`) producing a trailing dot when precision is 0 (fix #2582) (by @MangelMaxime)
1314
* [JS/TS] Fix `C0` and `P0` format specifiers producing trailing dot (e.g., `"¤1,000."``"¤1,000"`) (by @MangelMaxime)
1415
* [All] Fix captured side-effect-free values (e.g. empty ResizeArray) being incorrectly inlined into object expression getters in release mode, causing a new instance to be created on each getter call (fixes #3779) (by @MangelMaxime)

src/Fable.Transforms/Fable2Babel.fs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,14 @@ module Annotation =
628628
| Replacements.Util.Builtin kind -> makeBuiltinTypeAnnotation com ctx typ kind
629629
| Fable.DeclaredType(entRef, genArgs) -> com.GetEntity(entRef) |> makeEntityTypeAnnotation com ctx genArgs
630630

631+
let makeArgTypeAnnotation (com: IBabelCompiler) ctx (id: Fable.Ident) =
632+
if com.IsTypeScript then
633+
match id.Type, id with
634+
| Replacements.Util.IsByRefType com typ, id when id.IsThisArgument -> makeTypeAnnotation com ctx typ |> Some
635+
| _ -> makeTypeAnnotation com ctx id.Type |> Some
636+
else
637+
None
638+
631639
let makeTypeAnnotationIfTypeScript (com: IBabelCompiler) ctx typ expr =
632640
if com.IsTypeScript then
633641
match typ, expr with
@@ -3322,7 +3330,7 @@ but thanks to the optimisation done below we get
33223330
let args' =
33233331
List.zip args tc.Args
33243332
|> List.map (fun (id, tcArg) ->
3325-
let ta = makeTypeAnnotationIfTypeScript com ctx id.Type None
3333+
let ta = makeArgTypeAnnotation com ctx id
33263334

33273335
Parameter.parameter (tcArg, ?typeAnnotation = ta)
33283336
)
@@ -3348,7 +3356,7 @@ but thanks to the optimisation done below we get
33483356
| _ ->
33493357
args
33503358
|> List.map (fun a ->
3351-
let ta = makeTypeAnnotationIfTypeScript com ctx a.Type None
3359+
let ta = makeArgTypeAnnotation com ctx a
33523360
Parameter.parameter (a.Name, ?typeAnnotation = ta)
33533361
),
33543362
body

src/Fable.Transforms/Python/Fable2Python.Annotation.fs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,12 @@ let makeBuiltinTypeAnnotation com ctx typ repeatedGenerics kind =
754754
fableModuleAnnotation com ctx "choice" name resolved, stmts
755755
| _ -> stdlibModuleTypeHint com ctx "typing" "Any" [] repeatedGenerics
756756

757+
let makeArgTypeAnnotation com ctx repeatedGenerics (id: Fable.Ident) =
758+
match id.Type, id with
759+
| Replacements.Util.IsByRefType com typ, id when id.IsThisArgument ->
760+
typeAnnotation com ctx (Some repeatedGenerics) typ
761+
| _ -> typeAnnotation com ctx (Some repeatedGenerics) id.Type
762+
757763
let transformFunctionWithAnnotations
758764
(com: IPythonCompiler)
759765
ctx

src/Fable.Transforms/Python/Fable2Python.Transforms.fs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3083,12 +3083,10 @@ let transformFunction
30833083
// Replace args, see NamedTailCallOpportunity constructor
30843084
let args' =
30853085
List.zip args tc.Args
3086-
|> List.map (fun (_id, { Arg = Identifier tcArg }) ->
3087-
let id = com.GetIdentifier(ctx, tcArg)
3088-
3089-
let ta, _ = Annotation.typeAnnotation com ctx (Some repeatedGenerics) _id.Type
3090-
3091-
Arg.arg (id, annotation = ta)
3086+
|> List.map (fun (id, { Arg = Identifier tcArg }) ->
3087+
let id2 = com.GetIdentifier(ctx, tcArg)
3088+
let ta, _ = Annotation.makeArgTypeAnnotation com ctx repeatedGenerics id
3089+
Arg.arg (id2, annotation = ta)
30923090
)
30933091

30943092
let varDecls =
@@ -3119,8 +3117,7 @@ let transformFunction
31193117
let args' =
31203118
args
31213119
|> List.map (fun id ->
3122-
let ta, _ = Annotation.typeAnnotation com ctx (Some repeatedGenerics) id.Type
3123-
3120+
let ta, _ = Annotation.makeArgTypeAnnotation com ctx repeatedGenerics id
31243121
Arg.arg (ident com ctx id, annotation = ta)
31253122
)
31263123

tests/Beam/TypeTests.fs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ type ValueType1<'T>(value: 'T) =
4343
type ValueType2(i: int, j: int) =
4444
member x.Value = i + j
4545

46+
[<Struct>]
47+
type ValueTypeR =
48+
val mutable X: float
49+
new(x: float) = { X = x }
50+
member this.IsEmpty() = this.X < 0.0
51+
4652
[<Struct>]
4753
type StructUnion = Value of string
4854

@@ -645,6 +651,12 @@ let ``test Other Value Types work`` () =
645651
let p = Point2D(2.)
646652
p.Y |> equal 2.
647653

654+
[<Fact>]
655+
let ``test Struct with mutable fields works`` () =
656+
let x = ValueTypeR(-10.0)
657+
x.X |> equal -10.0
658+
x.IsEmpty() |> equal true
659+
648660
[<Fact>]
649661
let ``test Custom F# exceptions work`` () =
650662
try
@@ -732,6 +744,7 @@ let ``test Type abbreviation works`` () =
732744
// let mutable t2 = ValueType3()
733745
// t2.X |> equal 0
734746

747+
735748
// Test types for generic parameter static member resolution
736749
type TestTypeA =
737750
static member GetValue() = "A"

tests/Dart/src/TypeTests.fs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,12 @@ open Util
264264
// val mutable public X : int
265265
// end
266266

267+
// [<Struct>]
268+
// type ValueTypeR =
269+
// val mutable X: float
270+
// new(x: float) = { X = x }
271+
// member this.IsEmpty() = this.X < 0.0
272+
267273
// [<Struct>]
268274
// type StructUnion = Value of string
269275

@@ -1083,6 +1089,11 @@ let tests() =
10831089
// t1 |> equal t2
10841090
// (compare t1 t2) |> equal 0
10851091

1092+
// testCase "Struct with mutable fields works" <| fun () ->
1093+
// let x = ValueTypeR(-10.0)
1094+
// x.X |> equal -10.0
1095+
// x.IsEmpty() |> equal true
1096+
10861097
// testCase "copying struct records works" <| fun () -> // See #3371
10871098
// let simple : SimpleRecord = { A = ""; B = "B" }
10881099
// let simpleRecord = { simple with A = "A" }

tests/Js/Main/TypeTests.fs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,13 +261,18 @@ type ValueType2(i: int, j: int) =
261261
member x.Value = i + j
262262

263263
#if !FABLE_COMPILER_TYPESCRIPT
264-
[<Struct>]
265264
type ValueType3 =
266265
struct
267266
val mutable public X : int
268267
end
269268
#endif
270269

270+
[<Struct>]
271+
type ValueTypeR =
272+
val mutable X: float
273+
new(x: float) = { X = x }
274+
member this.IsEmpty() = this.X < 0.0
275+
271276
[<Struct>]
272277
type StructUnion = Value of string
273278

@@ -1303,6 +1308,11 @@ let tests =
13031308
(compare t1 t2) |> equal 0
13041309
#endif
13051310

1311+
testCase "Struct with mutable fields works" <| fun () ->
1312+
let x = ValueTypeR(-10.0)
1313+
x.X |> equal -10.0
1314+
x.IsEmpty() |> equal true
1315+
13061316
testCase "copying struct records works" <| fun () -> // See #3371
13071317
let simple : SimpleRecord = { A = ""; B = "B" }
13081318
let simpleRecord = { simple with A = "A" }

tests/Python/TestType.fs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,12 @@ type ValueType3 =
298298
val mutable public X: int
299299
end
300300

301+
[<Struct>]
302+
type ValueTypeR =
303+
val mutable X: float
304+
new(x: float) = { X = x }
305+
member this.IsEmpty() = this.X < 0.0
306+
301307
[<Struct>]
302308
type StructUnion = Value of string
303309

@@ -1246,6 +1252,12 @@ let ``test struct without explicit ctor works`` () =
12461252

12471253
(compare t1 t2) |> equal 0
12481254

1255+
[<Fact>]
1256+
let ``test Struct with mutable fields works`` () =
1257+
let x = ValueTypeR(-10.0)
1258+
x.X |> equal -10.0
1259+
x.IsEmpty() |> equal true
1260+
12491261
[<Fact>]
12501262
let ``test Custom F# exceptions work`` () =
12511263
try

tests/Rust/tests/src/TypeTests.fs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,12 @@ type ValueType3 =
264264
val mutable public X : int
265265
end
266266

267+
[<Struct>]
268+
type ValueTypeR =
269+
val mutable X: float
270+
new(x: float) = { X = x }
271+
member this.IsEmpty() = this.X < 0.0
272+
267273
[<Struct>]
268274
type StructUnion = Value of string
269275

@@ -1120,6 +1126,12 @@ let ``struct without explicit ctor works`` () =
11201126
t1 |> equal t2
11211127
(compare t1 t2) |> equal 0
11221128

1129+
[<Fact>]
1130+
let ``Struct with mutable fields works`` () =
1131+
let x = ValueTypeR(-10.0)
1132+
x.X |> equal -10.0
1133+
x.IsEmpty() |> equal true
1134+
11231135
[<Fact>]
11241136
let ``Unchecked.defaultof works for fields on nested structs`` () =
11251137
let top = TopLevelStruct()

0 commit comments

Comments
 (0)