Skip to content
Open
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

* [JS/TS] Fix `super` call in multi-level generic class hierarchy generating wrong mangled method name (fix #3895)
* [TS] Annotate `System.Collections.Generic.IList<T>` as `MutableArray<T>` (by @MangelMaxime)
* [JS/TS] Fix `ResizeArray` index getter/setter not throwing `IndexOutOfRangeException` when index is out of bounds (fix #3812) (by @MangelMaxime)
* [Beam] Fix unused term warning in try/catch when exception variable is not referenced (by @dbrattli)
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

* [JS/TS] Fix `super` call in multi-level generic class hierarchy generating wrong mangled method name (fix #3895)
* [TS] Annotate `System.Collections.Generic.IList<T>` as `MutableArray<T>` (by @MangelMaxime)
* [JS/TS] Fix `ResizeArray` index getter/setter not throwing `IndexOutOfRangeException` when index is out of bounds (fix #3812) (by @MangelMaxime)
* [Beam] Fix unused term warning in try/catch when exception variable is not referenced (by @dbrattli)
Expand Down
27 changes: 19 additions & 8 deletions src/Fable.Transforms/FSharp2Fable.Util.fs
Original file line number Diff line number Diff line change
Expand Up @@ -2939,7 +2939,7 @@ module Util =
// When calling `super` in an override, it may happen the method is not originally declared
// by the immediate parent, so we need to go through the hierarchy until we find the original declaration
// (this is important to get the correct mangled name)
let entity =
let entity, memb =
match memb.IsOverrideOrExplicitInterfaceImplementation, callInfo.ThisArg with
| true, Some(Fable.Value(Fable.BaseValue _, _)) ->
// Only compare param types for overloads (single curried parameter group)
Expand All @@ -2952,13 +2952,24 @@ module Util =
else
None

entity
|> tryFindBaseEntity (fun ent ->
tryFindAbstractMember com ent memb.CompiledName memb.IsInstanceMember paramTypes
|> Option.isSome
)
|> Option.defaultValue entity
| _ -> entity
let baseEntity =
entity
|> tryFindBaseEntity (fun ent ->
tryFindAbstractMember com ent memb.CompiledName memb.IsInstanceMember paramTypes
|> Option.isSome
)
|> Option.defaultValue entity

// Also find the member from the base entity so the overload hash is computed
// with matching generic parameter names. When 'memb' is an override from a
// subclass with different generic param names than the base entity, the hash
// would be wrong if we use the override member with the base entity. (#3895)
let baseMember =
tryFindAbstractMember com baseEntity memb.CompiledName memb.IsInstanceMember paramTypes
|> Option.defaultValue memb

baseEntity, baseMember
| _ -> entity, memb

callAttachedMember com ctx r typ callInfo entity memb

Expand Down
30 changes: 30 additions & 0 deletions tests/Js/Main/TypeTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,30 @@ type MangledAbstractClass5(v) =
type ConcreteClass1() =
inherit MangledAbstractClass5(2)

// See #3895 - super call with generic class hierarchy uses wrong overload hash
type IGenericAttach3895<'C> =
abstract Attach: 'C -> unit

[<AbstractClass>]
type GenericAttachBase3895<'C>() =
let mutable _baseCallCount = 0
abstract Attach: 'C -> unit
default _.Attach(_owner: 'C) = _baseCallCount <- _baseCallCount + 1
member _.BaseCallCount = _baseCallCount

interface IGenericAttach3895<'C> with
member this.Attach(owner: 'C) = this.Attach(owner)

type GenericAttachMid3895<'Container>() =
inherit GenericAttachBase3895<'Container>()
override this.Attach(owner) =
base.Attach(owner)

type GenericAttachLeaf3895() =
inherit GenericAttachMid3895<string>()
override this.Attach(owner) =
base.Attach(owner)

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
Expand Down Expand Up @@ -1391,6 +1415,12 @@ let tests =
let c = ConcreteClass1()
c.MyMethod(4) |> equal 58

// See #3895 - super call in generic class hierarchy was using wrong mangled name
testCase "Super call works correctly in multi-level generic class hierarchy" <| fun () ->
let obj = GenericAttachLeaf3895()
obj.Attach("hello")
obj.BaseCallCount |> equal 1

// See #3328
testCase "SRTP works with byref" <| fun () ->
let result = doubleIntByRef (TypeWithByRefMember()) 7
Expand Down