fable-compiler / Fable

F# to JavaScript, TypeScript, Python, Rust and Dart Compiler
http://fable.io/
MIT License
2.89k stars 295 forks source link

[Python] '<' not supported between instances of 'dict' and 'dict' #3869

Open PawelStadnicki opened 1 month ago

PawelStadnicki commented 1 month ago

Description

Code that uses Map.tryFind compiles fine to Python, but I'm getting '<' not supported between instances of 'dict' and 'dict' when running. My python version is 3.12.4.

I found that "In Python 3, dictionaries are no longer orderable together with many other types"

I can see a lot of tests in the repo for the Map module but the keys are pretty much plain numbers there and I have DU's.

Does it mean I cannot use complex types as keys? The same code works fine when compiled to js.

Related information

PawelStadnicki commented 1 month ago

hmm, after some further research I can see that the problem only happens with anonymous records in keys

MangelMaxime commented 1 month ago

For reference, are you saying that there is a bug when doing something like this?

let myMap =
    Map.ofList [
        {| Key = "1"|}, "Value 1"
        {| Key = "2"|}, "Value 2"
    ]

let value1 = Map.tryFind {| Key = "1"|} myMap
dbrattli commented 1 month ago

I cannot reproduce so it would be great with a minimal repro. I also cannot make that example fail @MangelMaxime. Does it fail on your machine? This might be related to #3771

MangelMaxime commented 1 month ago

@dbrattli I didn't try my example.

My goal was to confirm with @PawelStadnicki if this was the code that caused problem to him. My message was unclear sorry.

@PawelStadnicki Could you please provide a reproduction code?

PawelStadnicki commented 1 month ago

Hi @MangelMaxime @dbrattli

Sample provided by Maxime works, it fails when we add some (nested) AR's.

Here is my reproduction code:

type Item<'c> =
  { Content: 'c }

type Named = { Name : string; Id: int }

let test = testList "service" [
    testCase "Map" <| fun _ ->
        let items = [3 .. 17] |> List.map ( fun i -> { Content = {| Id = i; Name = $"Name:{i}" |} })

        let m = items |> List.map (fun a -> a, a) |> Map.ofList
        let value = m |> Map.tryFind items.Head

        Expect.isTrue (value.Value.Content.Id = 3) ""
]

This results in:

image

while for js and F# targets it works.

However, when I switch from anonymuous to Named type, it satisfies py as well:

fails:

let items = [3 .. 17] |> List.map ( fun i -> { Content = {| Id = i; Name = $"Name:{i}" |} })

works:

let items = [3 .. 17] |> List.map ( fun i -> { Content = { Id = i; Name = $"Name:{i}" } })

What is interesting: when I have anonymous types everywhere, for both the outer and the Content field, it works:

let items = [3 .. 17] |> List.map ( fun i -> {| Content = {| Id = i; Name = $"Name:{i}" |} |})

So it looks like only the inner anonymous field makes troubles.