Skip to content

Type aliases twice as slow to compile as closed type families.

Hello guys! This bug is awkard at last to me. So I notiiced today, that using type aliases in my code takes twice as long to copile than using closed type families with just single member. So to be most precise - when I replace the following line:

type XQ1 m a = Targets (Match m a)

with

type family XQ1 m a where XQ1 m a = Targets (Match m a)

the compilation time drops from 15s to 7s (this type alias is heavily used across the application). I think it could be somehow related to the famous #8095 bug, but I can of course be wrong here.

Unfortunetally the codebase is pretty big and its not so easy to make a minimal example, but I'll try to work on it during the upcoming weekend (please notify me if that would not be necessary).

And some statistics from -dshow-passes:

When using type alias:

*** Parser:
*** Renamer/typechecker:
*** Desugar:
Result size of Desugar (after optimization)
  = {terms: 10,303, types: 66,949, coercions: 16,383,834}
*** Simplifier:
Result size of Simplifier iteration=1
  = {terms: 10,722, types: 75,391, coercions: 16,507,338}
Result size of Simplifier iteration=2
  = {terms: 10,550, types: 74,437, coercions: 16,504,770}
Result size of Simplifier iteration=3
  = {terms: 10,543, types: 74,347, coercions: 16,504,734}
Result size of Simplifier
  = {terms: 10,543, types: 74,347, coercions: 16,504,630}
*** Tidy Core:
Result size of Tidy Core
  = {terms: 10,846, types: 75,522, coercions: 16,504,729}
*** CorePrep:
Result size of CorePrep
  = {terms: 14,823, types: 96,430, coercions: 16,504,729}
*** ByteCodeGen:
Upsweep completely successful.
*** Deleting temp files:
Warning: deleting non-existent /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64965_0/ghc_95.c
Warning: deleting non-existent /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64965_0/ghc_94.o
Ok, modules loaded: Prologue, Type.Bool, Type.Container, Type.List, Type.Set, Data.Cata, Type.Promotion, Data.Bits.Mask, Control.Monad.State.Dependent, Control.Monad.Poly, Control.Applicative.Poly, Type.Regex, Type.Either, Data.Reprx, Data.Impossible, Type.Cache.TH, Main, Control.Lens.Utils, Control.Lens.Wrapped.Utils, Data.Text.CodeBuilder, Data.Text.CodeBuilder.Tok, Data.Text.CodeBuilder.Builder, Data.Text.CodeBuilder.Doc, Data.Binary.Instances.Missing, Data.Default.Instances.Missing, Data.String.Class, Data.Text.Class, Data.Convert, Data.Layer, Data.Container.Class, Data.Container.List, Data.Functor.Utils, Type.Operators, Type.Show, Type.Wrapped, Data.Container.Opts, Data.Container.Poly, Data.Convert.Base, Data.Convert.Instances, Data.Convert.Instances.Map, Data.Convert.Instances.Num, Data.Convert.Instances.Text, Data.Convert.Instances.TH, Data.Convert.Bound, Data.Bits.Base.
*** Parser:
*** Desugar:
*** Simplify:
*** CorePrep:
*** ByteCodeGen:
...

and with type families:

*** Parser:
*** Renamer/typechecker:
*** Desugar:
Result size of Desugar (after optimization)
  = {terms: 10,303, types: 67,609, coercions: 162,249}
*** Simplifier:
Result size of Simplifier iteration=1
  = {terms: 10,722, types: 75,721, coercions: 323,027}
Result size of Simplifier iteration=2
  = {terms: 10,550, types: 74,767, coercions: 320,473}
Result size of Simplifier iteration=3
  = {terms: 10,543, types: 74,677, coercions: 320,437}
Result size of Simplifier
  = {terms: 10,543, types: 74,677, coercions: 320,333}
*** Tidy Core:
Result size of Tidy Core
  = {terms: 10,846, types: 75,852, coercions: 320,432}
*** CorePrep:
Result size of CorePrep
  = {terms: 14,823, types: 96,760, coercions: 320,432}
*** ByteCodeGen:
Upsweep completely successful.
*** Deleting temp files:
Warning: deleting non-existent /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64863_0/ghc_95.c
Warning: deleting non-existent /var/folders/y9/km24zv3d4yl711mwv85vwljc0000gp/T/ghc64863_0/ghc_94.o
Ok, modules loaded: Prologue, Type.Bool, Type.Container, Type.List, Type.Set, Data.Cata, Type.Promotion, Data.Bits.Mask, Control.Monad.State.Dependent, Control.Monad.Poly, Control.Applicative.Poly, Type.Regex, Type.Either, Data.Reprx, Data.Impossible, Type.Cache.TH, Main, Control.Lens.Utils, Control.Lens.Wrapped.Utils, Data.Text.CodeBuilder, Data.Text.CodeBuilder.Tok, Data.Text.CodeBuilder.Builder, Data.Text.CodeBuilder.Doc, Data.Binary.Instances.Missing, Data.Default.Instances.Missing, Data.String.Class, Data.Text.Class, Data.Convert, Data.Layer, Data.Container.Class, Data.Container.List, Data.Functor.Utils, Type.Operators, Type.Show, Type.Wrapped, Data.Container.Opts, Data.Container.Poly, Data.Convert.Base, Data.Convert.Instances, Data.Convert.Instances.Map, Data.Convert.Instances.Num, Data.Convert.Instances.Text, Data.Convert.Instances.TH, Data.Convert.Bound, Data.Bits.Base.
*** Parser:
*** Desugar:
*** Simplify:
*** CorePrep:
*** ByteCodeGen:
...

As we can see the type aliase (used in one single place (!)) produces (100 x) more coertions than type families: 16,383,834 vs 162,249. This is really interesting thing and it seems related to the linked bug above.

Edited by danilo2
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information