Skip to content

Infinite type inference loop - no manual fix possible #90

@anmolitor

Description

@anmolitor

Hi,
first off: thanks for the incredible work on this tool.
I wanted to use it to generate some boilerplate maps for non-comparable types and ran into problems:

--ELM CODEGEN WARNING-----------------------------------------------------------
In the generated file: MapIdDict.elm

    When trying to figure out the type for insert, I ran into an issue
    
    Infinite type inference loop!  Whoops.  This is an issue with elm-codegen.  If you can report this to the elm-codegen repo, that would be appreciated!
    
    I'm not as smart as the Elm compiler :/, but we're good friends.  I especially get confused when there are a lot of type aliases.
    If you need to, try using Elm.withType to tell me what the type should be!


    generated/MapIdDict.elm was generated!
    However, there was a warning.

For simplicity, I simplified my code to not use any of my custom types but Int instead:

module Generate exposing (main)

{-| -}

import Elm
import Elm.Annotation as Type
import Elm.Case
import Gen.CodeGen.Generate as Generate
import Gen.ManualDict


main : Program {} () ()
main =
    Generate.run
        [ genDict
            { dictTypeName = "MapIdDict"
            , keyType = Type.int
            , comparableType = Type.int
            , toComparable = Basics.identity
            }
        ]


type alias DictConfig =
    { dictTypeName : String
    , keyType : Type.Annotation
    , comparableType : Type.Annotation
    , toComparable : Elm.Expression -> Elm.Expression
    }


genDict : DictConfig -> Elm.File
genDict config =
    let
        v =
            Type.var "v"

        dictAnn =
            Gen.ManualDict.annotation_.dict config.comparableType
                config.keyType
                v

        customAnn =
            Type.namedWith [] config.dictTypeName [ v ]

        wrap dict =
            Elm.apply (Elm.val config.dictTypeName) [ dict ]

        unwrap f dict =
            Elm.Case.custom dict
                (Type.named [] config.dictTypeName)
                [ Elm.Case.branch1 config.dictTypeName
                    ( "dict"
                    , Gen.ManualDict.annotation_.dict
                        config.comparableType
                        config.keyType
                        (Type.var "v")
                    )
                    f
                ]

        withWrap f = unwrap f >> wrap         
    in
    Elm.file [ config.dictTypeName ]
        [ Elm.customTypeWith config.dictTypeName
            [ "v" ]
            [ Elm.variantWith config.dictTypeName [ dictAnn ] ]
        , wrap Gen.ManualDict.empty |> Elm.withType customAnn |> Elm.declaration "empty"
        , Elm.fn3 ( "k", Just config.keyType )
            ( "v", Just v )
            ( "dict"
            , Just customAnn
            )
            (\key value -> withWrap (Gen.ManualDict.insert config.toComparable key value))
            |> Elm.withType (Type.function [ config.keyType, v, customAnn ] customAnn)
            |> Elm.declaration "insert"
        ]

The generated file looks like this:

module MapIdDict exposing (..)

import ManualDict


type MapIdDict v
    = MapIdDict (ManualDict.Dict Int Int v)


empty : MapIdDict v
empty =
    MapIdDict ManualDict.empty


insert k v dict =
    MapIdDict
        (case dict of
             MapIdDict dict0 ->
                 ManualDict.insert (\insertUnpack -> insertUnpack) k v dict0
        )

Note the missing annotation on insert. Even though I specified types on all parameters and the function itself,
the issue persists. The code itself is fine, the Elm compiler correctly infers the type.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions