packages feed

demangler-1.1.0.0: src/Demangler/PPrint.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-- OPTIONS_GHC -ddump-splices #-}

module Demangler.PPrint () where

import           Data.Char
import           Data.List.NonEmpty ( NonEmpty((:|)) )
import qualified Data.List.NonEmpty as NEL
import           Data.Text ( Text )
import qualified Data.Text as T
import           Text.Sayable

import           Demangler.Context
import           Demangler.Engine
import           Demangler.Structure


#ifdef MIN_VERSION_panic
import           Panic

-- Debug function to cause a Panic with -fdebug builds, or return a placeholder
-- in non-debug mode.  This is usually used for unfinished portions of the
-- output, to provide a useful panic when in development mode but to avoid
-- crashing in normal mode.  Note that the demangling process uses a similar
-- function to fail the parse; here, the parse has completed and we are simply
-- generating output, so we don't have the option to "revert" to the original.
-- Instead, emitting invalid output (without failing) is the most useful
-- operation, since the valid form of that output is not currently
-- known/implemented.
cannotSay :: PanicComponent a => a -> String -> [String] -> b
cannotSay = panic
#else
cannotSay :: a -> String -> [String] -> Saying saytag
cannotSay _ _ rsn = t'"OUTFMT?:{ " &* rsn &- '}'
#endif


data PrefixUQN = PUC Prefix UnqualifiedName
data PrefixCDtor = PCDC Prefix CtorDtor

$(return [])

ctxLst :: forall saytag t a .
          Sayable saytag (WithContext a)
       => Functor t
       => Foldable t
       => t a -> Context -> Saying saytag
ctxLst l c = t'"" &+* wCtx l c

ctxLst' :: Sayable saytag (WithContext a)
        => Functor t
        => Foldable t
        => t a -> Context -> Text -> Saying saytag
ctxLst' l c sep = sep &:* wCtx l c

wCtx :: Functor t => t a -> Context -> t (WithContext a)
wCtx a c = (\b -> WC b c) <$> a


----------------------------------------------------------------------
-- Sayable instances for printing demangled results

instance {-# OVERLAPPING #-}
  ( Sayable "diagnostic" (WithContext Encoding)
  ) => Sayable "diagnostic" Result where
  sayable = \case
    (Original i, c) -> contextStr c i &- t'"{orig}"
    (Encoded e, c) -> sayable @"diagnostic" $ WC e c
    (VendorExtended d i, c) ->
      let (s1,s2) = T.span isAlphaNum $ contextStr c i
      in WC d c &- t'"[clone" &- s1 &+ ']' &+ s2

instance {-# OVERLAPPABLE #-}
  ( Sayable saytag (WithContext Encoding)
  ) => Sayable saytag Result where
  sayable = \case
    (Original i, c) -> sayable @saytag $ contextStr c i
    (Encoded e, c) -> sayable @saytag $ WC e c
    (VendorExtended d i, c) ->
      let (s1,s2) = T.span isAlphaNum $ contextStr c i
      in WC d c &- t'"[clone" &- '.' &+ s1 &+ ']' &+ s2

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''Encoding
  ) => Sayable saytag (WithContext Encoding) where
  sayable (WC n c) =
    case n of
      -- Note: if the function has only a single void argument, print "()"
      -- instead of "(void)"; these are semantically the same, but demangling
      -- emits the former.
      --
      -- Another tricky part is that the FunctionName may contain qualifiers
      -- (esp. "const") but for a function these must be placed at the end,
      -- following the arguments.
      EncFunc f rty (BaseType Void :| []) -> sayFunction c f rty []
      EncFunc f rty t -> sayFunction c f rty $ NEL.toList t
      -- n.b. static functions don't have any visible difference in demangled
      -- form.
      EncStaticFunc f rty (BaseType Void :| []) -> sayFunction c f rty []
      EncStaticFunc f rty t -> sayFunction c f rty $ NEL.toList t
      EncConstStructData nm -> sayable @saytag $ WC nm c
      EncData nm -> sayable @saytag $ WC nm c
      EncSpecial sn -> sayable @saytag $ WC sn c

sayFunction :: Sayable saytag (WithContext Type_)
            => Context -> FunctionName -> Maybe Type_ -> [Type_] -> Saying saytag
sayFunction c fn mbRet args =
  let (nm,q) = cleanFunctionName fn
      part1 = case mbRet of
                Nothing -> WC nm c &+ t'""
                Just rty -> WC rty c &- WC nm c
      part2 = part1 &+ '(' &+ ctxLst args c &+ ')'
  in if null q then part2 else part2 &- ctxLst' q c " "

instance Sayable saytag (WithContext a)
  => Sayable saytag (NonEmpty (WithContext a)) where
  sayable l = t'"" &+* l

instance {-# OVERLAPPABLE #-} Sayable saytag (WithContext a)
  => Sayable saytag (WithContext (NonEmpty a)) where
  sayable (WC l c) = ctxLst l c

cleanFunctionName :: FunctionName -> (Name, [CVQualifier])
cleanFunctionName (FunctionName nm) =
  case nm of
    NameNested (NestedName p u cvq mbrq) ->
      (NameNested $ NestedName p u [] mbrq, cvq)
    NameNested (NestedTemplateName tp ta cvq mbrq) ->
      (NameNested $ NestedTemplateName tp ta [] mbrq, cvq)
    _ -> (nm, [])

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''SpecialName
  ) => Sayable saytag (WithContext SpecialName) where
  sayable (WC n c) =
    case n of
      VirtualTable ty -> t'"vtable for" &- WC ty c
      TemplateParameterObj ta -> t'"template parameter object for" &- WC ta c
      VTT ty -> t'"VTT for" &- WC ty c
      TypeInfo ty -> t'"typeinfo for" &- WC ty c
      TypeInfoName ty -> t'"typeinfo name for" &- WC ty c
      CtorVTable _ -> t'"construction vtable for" &- t'"()"
      Thunk (VirtualOffset _o1 _o2) enc -> t'"virtual thunk to" &- WC enc c
      Thunk (NonVirtualOffset _o1) enc -> t'"non-virtual thunk to" &- WC enc c


instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''FunctionName
  ) => Sayable saytag (WithContext FunctionName) where
  sayable (WC n c) = sayable @saytag $ WC n c


instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''Name
  ) => Sayable saytag (WithContext Name) where
  sayable (WC n c) =
    case n of
      NameNested nn -> sayable @saytag $ WC nn c
      UnscopedName False uqn -> sayable @saytag $ WC uqn c
      UnscopedName True uqn -> t'"std::" &+ WC uqn c
      UnscopedTemplateName nn ta -> WC nn c &+ WC ta c
      LocalName fs fe mbd -> WC fs c  &+ t'"::" &+ WC fe c &? wCtx mbd c -- ??
      StringLitName fs mbd -> WC fs c &? wCtx mbd c -- ??


instance {-# OVERLAPPABLE #-} Sayable saytag (WithContext Coord) where
  sayable (WC i c) = sayable @saytag $ contextStr c i


instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''UnqualifiedName
  ) =>  Sayable saytag (WithContext UnqualifiedName) where
  sayable (WC n c) =
    case n of
      SourceName i [] -> sayable @saytag $ WC i c
      SourceName i tags -> WC i c &+ ctxLst' tags c ""
      OperatorName op [] -> sayable @saytag $ WC op c
      OperatorName op tags -> WC op c &+ ctxLst' tags c ""
      CtorDtorName cd -> sayable @saytag $ WC cd c
      StdSubst subs -> sayable @saytag $ WC subs c
      ModuleNamed mn uqn -> ctxLst' mn c "" &+ WC uqn c

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''SourceName
   ) => Sayable saytag (WithContext SourceName) where
  sayable (WC (SrcName i) c) = sayable @saytag $ contextStr c i


instance {-# OVERLAPPABLE #-}
  ($(sayableConstraints ''PrefixUQN)
  , Sayable saytag (WithContext PrefixCDtor)
  ) =>  Sayable saytag (WithContext PrefixUQN) where
  sayable (WC (PUC p n) c) =
    case n of
      CtorDtorName cd -> sayable @saytag $ WC (PCDC p cd) c
      _ -> sayable @saytag $ WC n c

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''ModuleName
  ) => Sayable saytag (WithContext ModuleName) where
  sayable (WC (ModuleName isP sn) c) =
    if isP
    then WC sn c &+ ':'
    else WC sn c &+ '.'

{- | Use Sayable (Prefix, CtorDtor, Context) instead, since CtorDtor needs to
   reproduce Prefix name. -}
instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''CtorDtor
   ) =>  Sayable saytag (WithContext CtorDtor) where
  sayable (WC n c) =
    case n of
      CompleteCtor -> 'c' &+ '1'
      BaseCtor -> 'c' &+ '2'
      CompleteAllocatingCtor -> 'c' &+ '3'
      CompleteInheritingCtor t -> t'"ci1" &+ WC t c
      BaseInheritingCtor t -> t'"ci2" &+ WC t c
      DeletingDtor -> 'd' &+ '0'
      CompleteDtor -> 'd' &+ '1'
      BaseDtor -> 'd' &+ '2'

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''PrefixCDtor
  ) =>  Sayable saytag (WithContext PrefixCDtor) where
  sayable (WC (PCDC p n) c) =
    let mb'ln = case p of
                  Prefix pfxr -> pfxrLastUQName pfxr
                  _ -> cannot Demangler "sayable"
                       [ "CTORDTOR UNK PFX: " <> show p ]
        pfxrLastUQName = \case
          PrefixUQName unm PrefixEnd -> Just unm
          PrefixUQName unm (PrefixTemplateArgs _ PrefixEnd) -> Just unm
          PrefixUQName _ sp -> pfxrLastUQName sp
          PrefixTemplateArgs _ sp -> pfxrLastUQName sp
          PrefixEnd -> Nothing
    in case mb'ln of
         Just ln ->
           case n of
             CompleteCtor -> sayable @saytag $ WC ln c
             BaseCtor -> sayable @saytag $ WC ln c
             CompleteAllocatingCtor -> sayable @saytag $ WC ln c
             CompleteInheritingCtor t -> sayable @saytag $ WC t c -- ??
             BaseInheritingCtor t -> sayable @saytag $ WC t c -- ??
             DeletingDtor -> '~' &+ WC ln c
             CompleteDtor -> '~' &+ WC ln c
             BaseDtor -> '~' &+ WC ln c
         Nothing -> t'"unk_" &+ WC n c -- unlikely... and will be wrong


instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''Operator
  ) =>  Sayable saytag (WithContext Operator) where
  sayable (WC op c) =
    case lookup op opTable of
      Just (_, o) -> t'"operator" &+ o
      Nothing ->
        case op of
          OpCast ty -> t'"operator" &- WC ty c
          OpString snm -> sayable @saytag $ WC snm c
          OpVendor n snm -> t'"vendor" &- n &- WC snm c
          _ -> cannotSay Demangler "sayable"
               [ "Operator not in opTable or with a specific override:"
               , show op
               ]

instance {-# OVERLAPPABLE #-}
  ($(sayableConstraints ''NestedName)
  , Sayable saytag (WithContext PrefixCDtor)
  ) => Sayable saytag (WithContext NestedName) where
  sayable (WC n c) =
    let qualrefs q r = ctxLst' q c " " &? wCtx r c
    in case n of
      NestedName p (CtorDtorName nm) q r ->
        qualrefs q r &+ WC p c &+ t'"::" &+ WC (PCDC p nm) c
      NestedName EmptyPrefix nm q r -> qualrefs q r &+ WC nm c
      NestedName p nm q r -> qualrefs q r &+ WC p c &+ t'"::" &+ WC nm c
      NestedTemplateName tp ta q r -> qualrefs q r &+ WC tp c &+ WC ta c


instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''Prefix
  ) => Sayable saytag (WithContext Prefix) where
  sayable (WC p c) =
    case p of
      PrefixTemplateParam tp prefixr -> WC tp c &+ WC prefixr c
      PrefixDeclType dt prefixr -> WC dt c &+ WC prefixr c
      PrefixClosure cp -> sayable @saytag $ WC cp c -- ??
      Prefix prefixr -> sayable @saytag $ WC prefixr c

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''PrefixR
  ) => Sayable saytag (WithContext PrefixR) where
  sayable (WC p c) =
    case p of
      PrefixUQName uqn pfr@(PrefixUQName {}) -> WC uqn c &+ t'"::" &+ WC pfr c
      PrefixUQName uqn pfr -> WC uqn c &+ WC pfr c
      PrefixTemplateArgs ta pfr -> WC ta c &+ WC pfr c
      PrefixEnd -> sayable @saytag $ t'""


instance {-# OVERLAPPABLE #-} Sayable saytag (WithContext CVQualifier) where
  sayable (WC q _c) =
    case q of
      Restrict -> sayable @saytag $ t'"restrict"
      Volatile -> sayable @saytag $ t'"volatile"
      Const_ -> sayable @saytag $ t'"const"

instance {-# OVERLAPPABLE #-} Sayable saytag (WithContext RefQualifier) where
  sayable (WC q _c) =
    case q of
      Ref -> sayable @saytag '&'
      RefRef -> sayable @saytag $ t'"&&"

instance {-# OVERLAPPABLE #-}
  ($(sayableConstraints ''TemplatePrefix)
  , Sayable saytag (WithContext PrefixUQN)
  ) => Sayable saytag (WithContext TemplatePrefix) where
  sayable (WC p c) =
    case p of
      GlobalTemplate uqns -> ctxLst' uqns c "::"
      NestedTemplate pr uqns -> WC pr c &+ t'"::"
                                &+ ctxLst' (PUC pr <$> uqns) c "::"
      TemplateTemplateParam tp -> sayable @saytag $ WC tp c


instance {-# OVERLAPPABLE #-}
  (Sayable saytag (WithContext TemplateArg)
  ) => Sayable saytag (WithContext TemplateArgs) where
  sayable (WC args c) = '<' &+ ctxLst args c &+ templateArgsEnd args

-- C++ requires a space between template argument closures to resolve the parsing
-- ambiguity between that and a right shift operation.(e.g. "list<foo<int> >"
-- instead of "list<foo<int>>"
templateArgsEnd :: TemplateArgs -> String
templateArgsEnd args = case NEL.last args of
                        TArgPack targs ->
                          case NEL.nonEmpty targs of
                            Just args' -> templateArgsEnd args'
                            -- Expected to need ellipsis here, but c++filt does
                            -- not emit them.
                            -- Nothing -> "..."
                            Nothing -> ">"
                        TArgType (ClassUnionStructEnum
                                  (NameNested
                                   (NestedTemplateName {}))) -> " >"
                        TArgType (ClassUnionStructEnum
                                  (UnscopedTemplateName {})) -> " >"
                        _ -> ">"

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''TemplateArg
  ) => Sayable saytag (WithContext TemplateArg) where
  sayable (WC p c) =
    case p of
      TArgType ty -> sayable @saytag $ WC ty c
      TArgSimpleExpr ep -> sayable @saytag $ WC ep c
      TArgExpr expr -> sayable @saytag $ WC expr c
      TArgPack tas ->
        -- Expected some ellipses (see
        -- https://en.cppreference.com/w/cpp/language/parameter-pack), but
        -- c++filt does not show them in that manner.
        --
        -- if null tas  then '.' &+ ".."
        -- else (NEL.fromList tas, c) &+ "..."
        --
        -- Do not simply defer to the TemplateArgs sayable because that will
        -- engender another pair of surrounding angle brackets.
        ctxLst tas c

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''Expression
  ) => Sayable saytag (WithContext Expression) where
  sayable (WC e c) =
    case e of
      ExprPack expr -> sayable @saytag $ WC expr c
      ExprTemplateParam tp -> sayable @saytag $ WC tp c
      ExprPrim pe -> sayable @saytag $ WC pe c


instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''ExprPrimary
  ) => Sayable saytag (WithContext ExprPrimary) where
  sayable (WC e c) =
    case e of
      IntLit ty n ->
        -- Normally these are printed with a typecast (e.g. `(type)`) ".
        -- However, C and C++ have some special situations where they can use
        -- special suffixes instead (e.g. `10ul` for unsigned long).  And some
        -- are just wholesale changes.
        case ty of
          BaseType Bool_ -> t'"" &+ if n > 0 then t'"true" else t'"false"
          BaseType bty -> case lookup bty builtinTypeTable of
                            Just (_, cst, sfx) -> if T.null sfx
                                                  then '(' &+ cst &+ ')' &+ n
                                                  else n &+ sfx
                            _ -> '(' &+ WC ty c &+ ')' &+ n
          _ -> '(' &+ WC ty c &+ ')' &+ n
      FloatLit ty n -> '(' &+ WC ty c &+ ')' &+ n
      ComplexFloatLit ty r i -> '(' &+ WC ty c &+ ')' &+ '(' &+ r &+ ',' &- i &+ ')'
      DirectLit ty -> '(' &+ WC ty c &+ t'")NULL"  -- except String?
      NullPtrTemplateArg ty -> '(' &+ WC ty c &+ t'")0"
      ExternalNameLit enc -> sayable @saytag $ WC enc c


instance {-# OVERLAPPABLE #-} Sayable saytag (WithContext ClosurePrefix) where
  sayable (WC _p _c) = cannotSay Demangler "sayable"
                       [ "No Sayable for ClosurePrefix" ]

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''Substitution
  ) => Sayable saytag (WithContext Substitution) where
  sayable (WC p c) =
    case p of
      SubStd -> t'"std" &+ t'""
      SubAlloc -> t'"std" &+ t'"::allocator"
      SubBasicString -> t'"std" &+ t'"::basic_string"
      SubStdType stdTy -> sayable @saytag $ WC stdTy c

instance {-# OVERLAPPABLE #-} Sayable saytag (WithContext StdType) where
  sayable (WC stdTy _c) =
    let ct = t'"std::char_traits<char>" in
    case stdTy of
      BasicStringChar -> t'"std::basic_string<char," &- ct &+ t'", std::allocator<char> >"
      BasicIStream -> t'"std::basic_istream<char," &- ct &- '>'
      BasicOStream -> t'"std::basic_ostream<char," &- ct &- '>'
      BasicIOStream -> t'"std::basic_iostream<char," &- ct &- '>'


-- n.b. LLVM and GNU syntax seems to be [abi:foo][abi:bar], despite the website
-- documentation of [[gnu::abi_tag ("foo", "bar")]]
instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''ABI_Tag
  ) => Sayable saytag (WithContext ABI_Tag) where
  sayable (WC (ABITag p) c) = t'"[abi:" &+ WC p c &+ ']'

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''Type_
 ) => Sayable saytag (WithContext Type_) where
  sayable (WC ty c) =
    case ty of
      BaseType t -> sayable @saytag $ WC t c
      QualifiedType [] [] t -> sayable @saytag $ WC t c
      QualifiedType eqs [] t -> WC t c &+ ctxLst' eqs c " "
      QualifiedType [] cvqs t -> WC t c &- ctxLst' cvqs c " "
      QualifiedType eqs cvqs t -> WC t c &- ctxLst' eqs c " " &- ctxLst' cvqs c " "
      ClassUnionStructEnum n -> sayable @saytag $ WC n c
      ClassStruct n -> sayable @saytag $ WC n c
      Union n -> sayable @saytag $ WC n c
      Enum n -> sayable @saytag $ WC n c
      Function {} -> sayFunctionType ty "" c
      Pointer f@(Function {}) -> sayFunctionType f "(*)" c
      Pointer (ArrayType bnd t) -> WC t c &- t'"(*)" &- '[' &+ WC bnd c &+ ']'
      Pointer t -> WC t c &+ '*'
      LValRef (ArrayType bnd t) -> WC t c &- t'"(&)" &- '[' &+ WC bnd c &+ ']'
      LValRef t -> WC t c &+ '&'
      RValRef t -> WC t c &+ t'"&&"
      ComplexPair t -> WC t c &- t'"complex"
      Imaginary t -> WC t c &- t'"imaginary"
      ArrayType bnd t -> WC t c &+ '[' &+ WC bnd c &+ ']'
      Template tp ta -> WC tp c &- WC ta c -- ??
      Cpp11PackExpansion ts ->
        -- XXX expected some "..." (see
        -- https://en.cppreference.com/w/cpp/language/parameter-pack) but c++filt
        -- does not visibly decorate these.
        ctxLst ts c
      StdType stdTy -> sayable @saytag $ WC stdTy c


sayFunctionType :: Type_ -> Text -> Context -> Saying saytag
sayFunctionType (Function cvqs mb'exc trns isExternC rTy argTys mb'ref) nm c =
  ctxLst' cvqs c " "
  &? wCtx mb'exc c
  &+ WC trns c
  &+ (if isExternC then t'" extern \"C\"" else t'"")
  &+ WC rTy c
  &- nm &+ '('
  &+* (case argTys of
          BaseType Void :| [] -> []
          _ -> wCtx (NEL.toList argTys) c
      )
  &+ ')'
  &? wCtx mb'ref c
sayFunctionType _ _ _ = cannotSay Demangler "sayFunctionType"
                        [ "Called with a type that is not a Function!" ]


instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''ArrayBound
  ) => Sayable saytag (WithContext ArrayBound) where
  sayable (WC n c) =
    case n of
      NoBounds -> sayable @saytag $ t'""
      NumBound i -> sayable @saytag i
      ExprBound e -> sayable @saytag $ WC e c


instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''ExceptionSpec
  ) => Sayable saytag (WithContext ExceptionSpec) where
  sayable (WC exc c) =
    case exc of
      NonThrowing -> sayable @saytag $ t'"noexcept"
      ComputedThrow expr -> t'"throw" &- WC expr c -- ?
      Throwing tys -> t'"throw (" &+ wCtx tys c &+ ')' -- ?

instance {-# OVERLAPPABLE #-} Sayable saytag (WithContext Transaction) where
  sayable (WC trns _c) =
    case trns of
      TransactionSafe -> sayable @saytag $ t'"safe" -- ?
      TransactionUnsafe -> sayable @saytag $ t'""

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''BaseType
  ) => Sayable saytag (WithContext BaseType) where
  sayable (WC t c) =
    case lookup t builtinTypeTable of
      Just (_,s,_) -> sayable @saytag s
      Nothing ->
        case t of
          FloatN n -> t'"std::float" &+ n &+ t'"_t"
          FloatNx n -> t'"std::float" &+ n &+ t'"x_t"
          SBitInt n -> t'"signed _BitInt(" &+ n &+ ')'
          UBitInt n -> t'"unsigned _BitInt(" &+ n &+ ')'
          VendorExtendedType nm mb'ta -> WC nm c &? wCtx mb'ta c
          _ -> cannotSay Demangler "sayable.Basetype"
               [ "Unknown BaseType not listed in the builtinTypeTable"
               , show t
               ]

instance {-# OVERLAPPABLE #-} Sayable saytag (WithContext CallOffset) where
  sayable (WC _co _c) =
    cannotSay Demangler "Sayable CallOffset"
    [ "The CallOffset is for a thunk or covariant return thunk"
    , "and is not expected to be printed."
    ]

instance {-# OVERLAPPABLE #-}
  $(sayableConstraints ''SubsCandidate
  ) => Sayable saytag (WithContext SubsCandidate) where
  sayable (WC cand c) = -- For debug only
    case cand of
      SC_Type t -> t'"SC_Ty" &- WC t c
      SC_UQName True n -> t'"SC_UN" &- t'"std::" &+ WC n c
      SC_UQName _ n -> t'"SC_UN" &- WC n c
      SC_Prefix p -> t'"SC_PR" &- WC p c
      SC_TemplatePrefix tp -> t'"SC_TP" &- WC tp c