
#12972: Missed specialisation opportunity with phantom type class parameter? -------------------------------------+------------------------------------- Reporter: mpickering | Owner: Type: bug | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.0.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by danharaj): We discovered this while analyzing a moderately large production system based on `reflex` and `reflex-dom` compiled with ghcjs. Web applications that use this framework rely heavily on specialization in order to be performant when run in a browser. One feature of `reflex-dom` is a javascript FFI facility built to allow uniform interaction with either ghcjs's low-level JS FFI or a native JS engine (such as WebKit) when built with ghc. This type class is the user interface for this feature: {{{#!hs class (Monad m, MonadIO (JSM m), MonadFix (JSM m), MonadJS x (JSM m)) => HasJS x m | m -> x where type JSM m :: * -> * liftJS :: JSM m a -> m a }}} The `x` parameter is important. There are situations where a program will manage multiple Javascript execution contexts. In general, references cannot be shared between execution contexts. So this is a slightly more elaborate version of the phantom type parameter used by the `ST` monad. The `x` parameter is used by the implementation of the FFI to tag various JS datastructures so that they cannot be intermixed: It guarantees this aspect of semantic correctness. Unfortunately, using this FFI via `HasJS` prevents automatic specialization because even though the dictionary for `HasJS` need not depend on `x` in an essential way, GHC seems unable to automatically create a specialized version of a polymorphic declaration that is constrained by `HasJS` and marked `INLINABLE`. I believe this is because, according to the documentation in the `Specialise` module, the invariant of the specialiser for generated specialisations is that "no specialised version is overloaded" and GHC cannot deduce that the overloading caused by `x` is benign. The workaround was to create an escape hatch that allowed the user to specify a concrete dummy type for `x` at the top-level, namely `()`. This allowed GHC to specialize all of their code which led to significant performance gains. This isn't the best situation: a user had to abandon type discipline ensuring semantic correctness in order to avoid unacceptable performance overhead. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/12972#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler