Skip to content

Bad(?) performance on long list #3246

Open
@mtzguido

Description

@mtzguido

I noticed (or remembered... I think we noticed this before) that long list literals take a long time to typecheck. I looked at it and I think the root cause is solving the implicit arguments of Cons.

In a synthetic file like this:

module Slow

(* let cons (x : int) (xs : list int) : list int = Cons x xs *)
let cons (x : 'a) (xs : list 'a) : list 'a = Cons x xs

let init : list int =
    cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <|
    cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <|
    cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <| cons 1 <|
    ....

(though much longer), it takes around 20s to typecheck it. If instead we replace the definition of cons for the commented one, which just works on ints, it takes around 2s. Clearly there's an overhead to using the unifier to solve the types and instantiating the implcits, but 10x seems excessive. I think, but I didn't confirm, that the problem may come from the checking of applications not unifying the expected type as it goes through the arguments.

That is, when we check cons 1 e at expected type int, it must be the case that e <: int. But what I think happens is that we allocate a fresh ?u, check 1 against the expected type ?u, which works (with a deferred problem for int <: ?u, and then we check e against list ?u. This accumulates tons of constraints and they only get solved at the end, which probably requires much more time and memory.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions