Default RuntimeRep variables unless -fprint-explicit-runtime-reps
authorBen Gamari <bgamari.foss@gmail.com>
Thu, 24 Mar 2016 10:39:59 +0000 (11:39 +0100)
committerBen Gamari <ben@smart-cactus.org>
Thu, 24 Mar 2016 11:29:42 +0000 (12:29 +0100)
Summary:
Addresses #11549 by defaulting `RuntimeRep` variables to `PtrRepLifted`
and adding a new compiler flag `-fprint-explicit-runtime-reps` to
disable this behavior.

This is just a guess at the right way to go about this. If it's
wrong-beyond-any-hope just say so.

Test Plan: Working on a testcase

Reviewers: goldfire, austin

Subscribers: simonpj, thomie

Differential Revision: https://phabricator.haskell.org/D1961

GHC Trac Issues: #11549

compiler/main/DynFlags.hs
compiler/prelude/TysWiredIn.hs-boot
compiler/types/TyCoRep.hs
docs/users_guide/using.rst
testsuite/tests/dependent/ghci/T11549.script [new file with mode: 0644]
testsuite/tests/dependent/ghci/T11549.stdout [new file with mode: 0644]
testsuite/tests/dependent/ghci/all.T [new file with mode: 0644]
testsuite/tests/dependent/should_fail/TypeSkolEscape.stderr
testsuite/tests/ghci/scripts/T7627.stdout
utils/mkUserGuidePart/Options/Verbosity.hs

index c800979..f14a36f 100644 (file)
@@ -387,6 +387,7 @@ data GeneralFlag
    | Opt_PrintExplicitForalls
    | Opt_PrintExplicitKinds
    | Opt_PrintExplicitCoercions
+   | Opt_PrintExplicitRuntimeReps
    | Opt_PrintEqualityRelations
    | Opt_PrintUnicodeSyntax
    | Opt_PrintExpandedSynonyms
@@ -3353,6 +3354,7 @@ fFlagsDeps = [
   flagSpec "print-explicit-foralls"           Opt_PrintExplicitForalls,
   flagSpec "print-explicit-kinds"             Opt_PrintExplicitKinds,
   flagSpec "print-explicit-coercions"         Opt_PrintExplicitCoercions,
+  flagSpec "print-explicit-runtime-reps"      Opt_PrintExplicitRuntimeReps,
   flagSpec "print-equality-relations"         Opt_PrintEqualityRelations,
   flagSpec "print-unicode-syntax"             Opt_PrintUnicodeSyntax,
   flagSpec "print-expanded-synonyms"          Opt_PrintExpandedSynonyms,
index 7216d26..0c8ed7e 100644 (file)
@@ -13,6 +13,7 @@ constraintKind :: Kind
 
 runtimeRepTyCon, vecCountTyCon, vecElemTyCon :: TyCon
 runtimeRepTy :: Type
+ptrRepLiftedTy :: Type
 
 ptrRepUnliftedDataConTyCon, vecRepDataConTyCon :: TyCon
 
index 5b54e6b..9686531 100644 (file)
@@ -135,6 +135,7 @@ import {-# SOURCE #-} Type( isPredTy, isCoercionTy, mkAppTy
 
 import {-# SOURCE #-} Coercion
 import {-# SOURCE #-} ConLike ( ConLike(..) )
+import {-# SOURCE #-} TysWiredIn ( ptrRepLiftedTy )
 
 -- friends:
 import Var
@@ -2377,9 +2378,90 @@ maybeParen ctxt_prec inner_prec pretty
   | otherwise              = parens pretty
 
 ------------------
+
+{-
+Note [Defaulting RuntimeRep variables]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+RuntimeRep variables are considered by many (most?) users to be little more than
+syntactic noise. When the notion was introduced there was a signficant and
+understandable push-back from those with pedagogy in mind, which argued that
+RuntimeRep variables would throw a wrench into nearly any teach approach since
+they appear in even the lowly ($) function's type,
+
+    ($) :: forall (w :: RuntimeRep) a (b :: TYPE w). (a -> b) -> a -> b
+
+which is significantly less readable than its non RuntimeRep-polymorphic type of
+
+    ($) :: (a -> b) -> a -> b
+
+Moreover, unboxed types don't appear all that often in run-of-the-mill Haskell
+programs, so it makes little sense to make all users pay this syntactic
+overhead.
+
+For this reason it was decided that we would hide RuntimeRep variables for now
+(see #11549). We do this by defaulting all type variables of kind RuntimeRep to
+PtrLiftedRep. This is done in a pass right before pretty-printing
+(defaultRuntimeRepVars, controlled by -fprint-explicit-runtime-reps)
+-}
+
+-- | Default 'RuntimeRep' variables to 'LiftedPtr'. e.g.
+--
+-- @
+-- ($) :: forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r).
+--        (a -> b) -> a -> b
+-- @
+--
+-- turns in to,
+--
+-- @ ($) :: forall a (b :: *). (a -> b) -> a -> b @
+--
+-- We do this to prevent RuntimeRep variables from incurring a significant
+-- syntactic overhead in otherwise simple type signatures (e.g. ($)). See
+-- Note [Defaulting RuntimeRep variables] and #11549 for further discussion.
+--
+defaultRuntimeRepVars :: Type -> Type
+defaultRuntimeRepVars = defaultRuntimeRepVars' emptyVarSet
+
+defaultRuntimeRepVars' :: TyVarSet  -- ^ the binders which we should default
+                       -> Type -> Type
+-- TODO: Eventually we should just eliminate the Type pretty-printer
+-- entirely and simply use IfaceType; this task is tracked as #11660.
+defaultRuntimeRepVars' subs (ForAllTy (Named var vis) ty)
+  | isRuntimeRepVar var                        =
+    let subs' = extendVarSet subs var
+    in defaultRuntimeRepVars' subs' ty
+  | otherwise                                  =
+    let var' = var { varType = defaultRuntimeRepVars' subs (varType var) }
+    in ForAllTy (Named var' vis) (defaultRuntimeRepVars' subs ty)
+
+defaultRuntimeRepVars' subs (ForAllTy (Anon kind) ty) =
+    ForAllTy (Anon $ defaultRuntimeRepVars' subs kind)
+             (defaultRuntimeRepVars' subs ty)
+
+defaultRuntimeRepVars' subs (TyVarTy var)
+  | var `elemVarSet` subs                      = ptrRepLiftedTy
+
+defaultRuntimeRepVars' subs (TyConApp tc args) =
+    TyConApp tc $ map (defaultRuntimeRepVars' subs) args
+
+defaultRuntimeRepVars' subs (AppTy x y)        =
+    defaultRuntimeRepVars' subs x `AppTy` defaultRuntimeRepVars' subs y
+
+defaultRuntimeRepVars' subs (CastTy ty co)     =
+    CastTy (defaultRuntimeRepVars' subs ty) co
+
+defaultRuntimeRepVars' _    other              = other
+
+eliminateRuntimeRep :: (Type -> SDoc) -> Type -> SDoc
+eliminateRuntimeRep f ty = sdocWithDynFlags $ \dflags ->
+    if gopt Opt_PrintExplicitRuntimeReps dflags
+      then f ty
+      else f (defaultRuntimeRepVars ty)
+
 pprType, pprParendType :: Type -> SDoc
-pprType       ty = ppr_type TopPrec ty
-pprParendType ty = ppr_type TyConPrec ty
+pprType       ty = eliminateRuntimeRep (ppr_type TopPrec) ty
+pprParendType ty = eliminateRuntimeRep (ppr_type TyConPrec) ty
 
 pprTyLit :: TyLit -> SDoc
 pprTyLit = ppr_tylit TopPrec
@@ -2540,7 +2622,8 @@ ppr_fun_tail (ForAllTy (Anon ty1) ty2)
 ppr_fun_tail other_ty = [ppr_type TopPrec other_ty]
 
 pprSigmaType :: Type -> SDoc
-pprSigmaType ty = sdocWithDynFlags $ \dflags -> ppr_sigma_type dflags False ty
+pprSigmaType ty = sdocWithDynFlags $ \dflags ->
+    eliminateRuntimeRep (ppr_sigma_type dflags False) ty
 
 pprUserForAll :: [TyBinder] -> SDoc
 -- Print a user-level forall; see Note [When to print foralls]
index bcd641f..3d3ef34 100644 (file)
@@ -684,6 +684,22 @@ messages and in GHCi:
         ghci> :t MkT
         MkT :: forall (k :: BOX) (a :: k). T k a
 
+.. ghc-flag:: -fprint-explicit-runtime-reps
+
+    When :ghc-flag:`-fprint-explicit-runtime-reps` is enabled, GHC prints
+    ``RuntimeRep`` type variables for runtime-representation-polymorphic types.
+    Otherwise GHC will default these to ``PtrRepLifted``. For example,
+
+    .. code-block:: none
+
+        ghci> :t ($)
+        ($) :: (a -> b) -> a -> b
+        ghci> :set -fprint-explicit-runtime-reps
+        ghci> :t ($)
+        ($)
+          :: forall (r :: GHC.Types.RuntimeRep) a (b :: TYPE r).
+             (a -> b) -> a -> b
+
 .. ghc-flag:: -fprint-explicit-coercions
 
     Using :ghc-flag:`-fprint-explicit-coercions` makes GHC print coercions in
diff --git a/testsuite/tests/dependent/ghci/T11549.script b/testsuite/tests/dependent/ghci/T11549.script
new file mode 100644 (file)
index 0000000..5f8c500
--- /dev/null
@@ -0,0 +1,14 @@
+:set -XTypeInType
+import GHC.Exts
+
+putStrLn "-fno-print-explicit-runtime-reps"
+:set -fno-print-explicit-runtime-reps
+:ty ($)
+:kind TYPE
+:ty error
+
+putStrLn "\n-fprint-explicit-runtime-reps"
+:set -fprint-explicit-runtime-reps
+:ty ($)
+:kind TYPE
+:ty error
diff --git a/testsuite/tests/dependent/ghci/T11549.stdout b/testsuite/tests/dependent/ghci/T11549.stdout
new file mode 100644 (file)
index 0000000..c8449ba
--- /dev/null
@@ -0,0 +1,12 @@
+-fno-print-explicit-runtime-reps
+($) :: (a -> b) -> a -> b
+TYPE :: RuntimeRep -> *
+error :: GHC.Stack.Types.HasCallStack => [Char] -> a
+
+-fprint-explicit-runtime-reps
+($) :: forall (r :: RuntimeRep) a (b :: TYPE r). (a -> b) -> a -> b
+TYPE :: RuntimeRep -> *
+error
+  :: forall (r :: RuntimeRep) (a :: TYPE r).
+     GHC.Stack.Types.HasCallStack =>
+     [Char] -> a
diff --git a/testsuite/tests/dependent/ghci/all.T b/testsuite/tests/dependent/ghci/all.T
new file mode 100644 (file)
index 0000000..6d9332a
--- /dev/null
@@ -0,0 +1,3 @@
+test('T11549',
+     normal,
+     ghci_script, ['T11549.script'])
index a4ce1e4..963dcbb 100644 (file)
@@ -2,6 +2,6 @@
 TypeSkolEscape.hs:8:1: error:
     • Quantified type's kind mentions quantified type variable
       (skolem escape)
-           type: forall (v1 :: RuntimeRep) (a1 :: TYPE v1). a1
+           type: forall a1. a1
         of kind: TYPE v
     • In the type synonym declaration for ‘Bad’
index ee6dfa4..81a360f 100644 (file)
@@ -28,12 +28,6 @@ instance (Monoid a, Monoid b) => Monoid (a, b)
 data (#,#) (c :: TYPE a) (d :: TYPE b) = (#,#) c d
        -- Defined in ‘GHC.Prim’
 (,) :: a -> b -> (a, b)
-(#,#)
-  :: forall (a :: GHC.Types.RuntimeRep) (b :: GHC.Types.RuntimeRep) (c :: TYPE
-                                                                            a) (d :: TYPE b).
-     c -> d -> (# c, d #)
+(#,#) :: c -> d -> (# c, d #)
 (  ,  ) :: a -> b -> (a, b)
-(#  ,  #)
-  :: forall (a :: GHC.Types.RuntimeRep) (b :: GHC.Types.RuntimeRep) (c :: TYPE
-                                                                            a) (d :: TYPE b).
-     c -> d -> (# c, d #)
+(#  ,  #) :: c -> d -> (# c, d #)
index 8d5ed1a..5aefd22 100644 (file)
@@ -33,6 +33,13 @@ verbosityOptions =
          , flagType = DynamicFlag
          , flagReverse = "-fno-print-explicit-kinds"
          }
+  , flag { flagName = "-fprint-explicit-runtime-reps"
+         , flagDescription =
+           "Print ``RuntimeRep`` variables in types which are "++
+           "runtime-representation polymorphic."
+         , flagType = DynamicFlag
+         , flagReverse = "-fno-print-explicit-runtime-reps"
+         }
   , flag { flagName = "-fprint-unicode-syntax"
          , flagDescription =
            "Use unicode syntax when printing expressions, types and kinds. " ++