Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/Fable.Cli/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

* [TS/Python] Fix invalid `this` argument type in structs (#4453) (by @ncave)
* [JS/TS] Fix `N` format specifier (`ToString("N0")`, `String.Format("{0:N0}", ...)`) producing a trailing dot when precision is 0 (fix #2582) (by @MangelMaxime)
* [JS/TS] Fix `C0` and `P0` format specifiers producing trailing dot (e.g., `"¤1,000."` → `"¤1,000"`) (by @MangelMaxime)
* [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)
Expand Down
1 change: 1 addition & 0 deletions src/Fable.Compiler/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

* [TS/Python] Fix invalid `this` argument type in structs (#4453) (by @ncave)
* [JS/TS] Fix `N` format specifier (`ToString("N0")`, `String.Format("{0:N0}", ...)`) producing a trailing dot when precision is 0 (fix #2582) (by @MangelMaxime)
* [JS/TS] Fix `C0` and `P0` format specifiers producing trailing dot (e.g., `"¤1,000."` → `"¤1,000"`) (by @MangelMaxime)
* [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)
Expand Down
12 changes: 10 additions & 2 deletions src/Fable.Transforms/Fable2Babel.fs
Original file line number Diff line number Diff line change
Expand Up @@ -628,6 +628,14 @@ module Annotation =
| Replacements.Util.Builtin kind -> makeBuiltinTypeAnnotation com ctx typ kind
| Fable.DeclaredType(entRef, genArgs) -> com.GetEntity(entRef) |> makeEntityTypeAnnotation com ctx genArgs

let makeArgTypeAnnotation (com: IBabelCompiler) ctx (id: Fable.Ident) =
if com.IsTypeScript then
match id.Type, id with
| Replacements.Util.IsByRefType com typ, id when id.IsThisArgument -> makeTypeAnnotation com ctx typ |> Some
| _ -> makeTypeAnnotation com ctx id.Type |> Some
else
None

let makeTypeAnnotationIfTypeScript (com: IBabelCompiler) ctx typ expr =
if com.IsTypeScript then
match typ, expr with
Expand Down Expand Up @@ -3322,7 +3330,7 @@ but thanks to the optimisation done below we get
let args' =
List.zip args tc.Args
|> List.map (fun (id, tcArg) ->
let ta = makeTypeAnnotationIfTypeScript com ctx id.Type None
let ta = makeArgTypeAnnotation com ctx id

Parameter.parameter (tcArg, ?typeAnnotation = ta)
)
Expand All @@ -3348,7 +3356,7 @@ but thanks to the optimisation done below we get
| _ ->
args
|> List.map (fun a ->
let ta = makeTypeAnnotationIfTypeScript com ctx a.Type None
let ta = makeArgTypeAnnotation com ctx a
Parameter.parameter (a.Name, ?typeAnnotation = ta)
),
body
Expand Down
6 changes: 6 additions & 0 deletions src/Fable.Transforms/Python/Fable2Python.Annotation.fs
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,12 @@ let makeBuiltinTypeAnnotation com ctx typ repeatedGenerics kind =
fableModuleAnnotation com ctx "choice" name resolved, stmts
| _ -> stdlibModuleTypeHint com ctx "typing" "Any" [] repeatedGenerics

let makeArgTypeAnnotation com ctx repeatedGenerics (id: Fable.Ident) =
match id.Type, id with
| Replacements.Util.IsByRefType com typ, id when id.IsThisArgument ->
typeAnnotation com ctx (Some repeatedGenerics) typ
| _ -> typeAnnotation com ctx (Some repeatedGenerics) id.Type

let transformFunctionWithAnnotations
(com: IPythonCompiler)
ctx
Expand Down
13 changes: 5 additions & 8 deletions src/Fable.Transforms/Python/Fable2Python.Transforms.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3083,12 +3083,10 @@ let transformFunction
// Replace args, see NamedTailCallOpportunity constructor
let args' =
List.zip args tc.Args
|> List.map (fun (_id, { Arg = Identifier tcArg }) ->
let id = com.GetIdentifier(ctx, tcArg)

let ta, _ = Annotation.typeAnnotation com ctx (Some repeatedGenerics) _id.Type

Arg.arg (id, annotation = ta)
|> List.map (fun (id, { Arg = Identifier tcArg }) ->
let id2 = com.GetIdentifier(ctx, tcArg)
let ta, _ = Annotation.makeArgTypeAnnotation com ctx repeatedGenerics id
Arg.arg (id2, annotation = ta)
)

let varDecls =
Expand Down Expand Up @@ -3119,8 +3117,7 @@ let transformFunction
let args' =
args
|> List.map (fun id ->
let ta, _ = Annotation.typeAnnotation com ctx (Some repeatedGenerics) id.Type

let ta, _ = Annotation.makeArgTypeAnnotation com ctx repeatedGenerics id
Arg.arg (ident com ctx id, annotation = ta)
)

Expand Down
13 changes: 13 additions & 0 deletions tests/Beam/TypeTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ type ValueType1<'T>(value: 'T) =
type ValueType2(i: int, j: int) =
member x.Value = i + j

[<Struct>]
type ValueTypeR =
val mutable X: float
new(x: float) = { X = x }
member this.IsEmpty() = this.X < 0.0

[<Struct>]
type StructUnion = Value of string

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

[<Fact>]
let ``test Struct with mutable fields works`` () =
let x = ValueTypeR(-10.0)
x.X |> equal -10.0
x.IsEmpty() |> equal true

[<Fact>]
let ``test Custom F# exceptions work`` () =
try
Expand Down Expand Up @@ -732,6 +744,7 @@ let ``test Type abbreviation works`` () =
// let mutable t2 = ValueType3()
// t2.X |> equal 0


// Test types for generic parameter static member resolution
type TestTypeA =
static member GetValue() = "A"
Expand Down
11 changes: 11 additions & 0 deletions tests/Dart/src/TypeTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@ open Util
// val mutable public X : int
// end

// [<Struct>]
// type ValueTypeR =
// val mutable X: float
// new(x: float) = { X = x }
// member this.IsEmpty() = this.X < 0.0

// [<Struct>]
// type StructUnion = Value of string

Expand Down Expand Up @@ -1083,6 +1089,11 @@ let tests() =
// t1 |> equal t2
// (compare t1 t2) |> equal 0

// testCase "Struct with mutable fields works" <| fun () ->
// let x = ValueTypeR(-10.0)
// x.X |> equal -10.0
// x.IsEmpty() |> equal true

// testCase "copying struct records works" <| fun () -> // See #3371
// let simple : SimpleRecord = { A = ""; B = "B" }
// let simpleRecord = { simple with A = "A" }
Expand Down
12 changes: 11 additions & 1 deletion tests/Js/Main/TypeTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -261,13 +261,18 @@ type ValueType2(i: int, j: int) =
member x.Value = i + j

#if !FABLE_COMPILER_TYPESCRIPT
[<Struct>]
type ValueType3 =
struct
val mutable public X : int
end
#endif

[<Struct>]
type ValueTypeR =
val mutable X: float
new(x: float) = { X = x }
member this.IsEmpty() = this.X < 0.0

[<Struct>]
type StructUnion = Value of string

Expand Down Expand Up @@ -1303,6 +1308,11 @@ let tests =
(compare t1 t2) |> equal 0
#endif

testCase "Struct with mutable fields works" <| fun () ->
let x = ValueTypeR(-10.0)
x.X |> equal -10.0
x.IsEmpty() |> equal true

testCase "copying struct records works" <| fun () -> // See #3371
let simple : SimpleRecord = { A = ""; B = "B" }
let simpleRecord = { simple with A = "A" }
Expand Down
12 changes: 12 additions & 0 deletions tests/Python/TestType.fs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,12 @@
val mutable public X: int
end

[<Struct>]
type ValueTypeR =
val mutable X: float
new(x: float) = { X = x }
member this.IsEmpty() = this.X < 0.0

[<Struct>]
type StructUnion = Value of string

Expand Down Expand Up @@ -586,7 +592,7 @@

type IndexedProps(v: int) =
let mutable v = v
member _.Item with get (v2: int) = v + v2 and set v2 (s: string) = v <- v2 + int s

Check warning on line 595 in tests/Python/TestType.fs

View workflow job for this annotation

GitHub Actions / build-python (ubuntu-latest, 3.14)

An indexed property's getter and setter must have the same type. Property 'Item' has getter of type 'int' but setter of type 'string'.

Check warning on line 595 in tests/Python/TestType.fs

View workflow job for this annotation

GitHub Actions / build-python (ubuntu-latest, 3.12)

An indexed property's getter and setter must have the same type. Property 'Item' has getter of type 'int' but setter of type 'string'.

Check warning on line 595 in tests/Python/TestType.fs

View workflow job for this annotation

GitHub Actions / build-python (ubuntu-latest, 3.13)

An indexed property's getter and setter must have the same type. Property 'Item' has getter of type 'int' but setter of type 'string'.

Check warning on line 595 in tests/Python/TestType.fs

View workflow job for this annotation

GitHub Actions / build-python (windows-latest, 3.13)

An indexed property's getter and setter must have the same type. Property 'Item' has getter of type 'int' but setter of type 'string'.

Check warning on line 595 in tests/Python/TestType.fs

View workflow job for this annotation

GitHub Actions / build-python (windows-latest, 3.14)

An indexed property's getter and setter must have the same type. Property 'Item' has getter of type 'int' but setter of type 'string'.

Check warning on line 595 in tests/Python/TestType.fs

View workflow job for this annotation

GitHub Actions / build-python (windows-latest, 3.12)

An indexed property's getter and setter must have the same type. Property 'Item' has getter of type 'int' but setter of type 'string'.
member _.Item with get (v2: float) = float v + v2 / 2.

[<Interface>]
Expand Down Expand Up @@ -1246,6 +1252,12 @@

(compare t1 t2) |> equal 0

[<Fact>]
let ``test Struct with mutable fields works`` () =
let x = ValueTypeR(-10.0)
x.X |> equal -10.0
x.IsEmpty() |> equal true

[<Fact>]
let ``test Custom F# exceptions work`` () =
try
Expand Down
12 changes: 12 additions & 0 deletions tests/Rust/tests/src/TypeTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,12 @@
val mutable public X : int
end

[<Struct>]
type ValueTypeR =
val mutable X: float
new(x: float) = { X = x }
member this.IsEmpty() = this.X < 0.0

[<Struct>]
type StructUnion = Value of string

Expand Down Expand Up @@ -507,7 +513,7 @@

type IndexedProps(v: int) =
let mutable v = v
member _.Item with get (v2: int) = v + v2 and set v2 (s: string) = v <- v2 + int s

Check warning on line 516 in tests/Rust/tests/src/TypeTests.fs

View workflow job for this annotation

GitHub Actions / build-rust (no_std)

An indexed property's getter and setter must have the same type. Property 'Item' has getter of type 'int' but setter of type 'string'.

Check warning on line 516 in tests/Rust/tests/src/TypeTests.fs

View workflow job for this annotation

GitHub Actions / build-rust (default)

An indexed property's getter and setter must have the same type. Property 'Item' has getter of type 'int' but setter of type 'string'.

Check warning on line 516 in tests/Rust/tests/src/TypeTests.fs

View workflow job for this annotation

GitHub Actions / build-rust (threaded)

An indexed property's getter and setter must have the same type. Property 'Item' has getter of type 'int' but setter of type 'string'.
member _.Item with get (v2: float) = float v + v2 / 2.

[<Interface>]
Expand Down Expand Up @@ -1120,6 +1126,12 @@
t1 |> equal t2
(compare t1 t2) |> equal 0

[<Fact>]
let ``Struct with mutable fields works`` () =
let x = ValueTypeR(-10.0)
x.X |> equal -10.0
x.IsEmpty() |> equal true

[<Fact>]
let ``Unchecked.defaultof works for fields on nested structs`` () =
let top = TopLevelStruct()
Expand Down
Loading