Skip to content

Inline function resolves static member call on second generic parameter ('b) using the implementation of the first ('a) #4093

@Programmerino

Description

@Programmerino

Environment:

  • Fable Version: Fable REPL (4.23.0 as of writing)
  • Target: JavaScript

Description:
When using an inline function with multiple generic type parameters ('a, 'b) that are both constrained by a static member requirement (e.g., static member getString), calling the static member explicitly on the second type parameter ('b.getString) inside the function body incorrectly resolves to the implementation provided by the first type parameter ('a).

REPL Link:
https://fable.io/repl/#?code=C4TwDgpgBAwg9gOwM7AE4EMCWDgB4DkwUA7gBYQJSEBcUAFCusJgMZQC2E7ARhKlAHMIwAMppsA2ilQSoAWgB8UaRICUSgLxVgAKB2hIUAIJQNOqBagAfYwDV0AG3OXGzNpx59BwsTIQD6AH0pcX9VEL8ArQAiI2i9A2gAIVNnCxsk+ydLZWAmVg4uXn4hUVCAumDcyPDq2Rik+L0HYShsB2xoUpEIFkQAEwAVcAhfCQJ0ABoqbhJySnhkNCwcCaV0BH7YRGkVvHxuBSU6WpV-VJyDgDpu8qhopoB6R6gRUjgAVwct3igk6e4HyIYD8wCQxgAhDpur0BsNIGN-LgjNMkgoTtYlCDsMAAGaUaIAUjiQA&html=Q&css=Q

F# Code:

// Define a constraint alias requiring a static member
type Constraint<'t when 't: (static member getString: string -> string)> = 't

// Define two types implementing the static member
type A =
    | AVal
    static member getString (_: string): string = "A"

type B =
    | BVal
    static member getString (_: string): string = "B"

// Inline function constrained by both types
let inline getSecondTypeString<'a, 'b when Constraint<'a> and Constraint<'b>> (): string =
    // Explicitly call the static member on the second type parameter 'b
    'b.getString ""

// Call the function specifying A and B
// Expected: Should call B.getString "" and print "B"
// Actual: Prints "A"
getSecondTypeString<A, B>() |> printfn "%A"

Generated JavaScript:

The relevant part of the generated JavaScript shows that the call is hardcoded to A_getString_Z721C83C5, which is the implementation for type A, instead of B_getString_Z721C83C5.

// ... (Type definitions for A and B) ...

// Implementation for A.getString
export function A_getString_Z721C83C5(_arg) {
    return "A";
}

// ...

// Implementation for B.getString
export function B_getString_Z721C83C5(_arg) {
    return "B";
}

// The call site for getSecondTypeString<A, B>()
(function () {
    // Incorrectly calls A's implementation
    const arg_1 = A_getString_Z721C83C5("");
    toConsole(printf("%A"))(arg_1);
})();

Expected Behavior:
The code getSecondTypeString<A, B>() should execute 'b.getString "", which resolves to B.getString "". The program should therefore print "B".

Actual Behavior:
The code getSecondTypeString<A, B>() incorrectly executes the static member implementation associated with the first type parameter ('a), resulting in a call equivalent to A.getString "". The program prints "A". The generated JavaScript confirms that the call is resolved to A_getString_Z721C83C5 at compile time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions