-- | "Selfification" (c.f. TILT) is the process of adding to the current scope
-- a type variable of singleton kind (ie, a module variable standing
-- for a module expression) such that the module variable is given its principal
-- kind (exposes maximal sharing).
selfifySignature :: Path -> Signature -> TC SelfSig
selfifySignature pmod msig_ =
  case msig_ of
    UnitSig -> return UnitSelfSig
    ValueSig fld ty msig -> do
      let qvar = QVar pmod fld
      selfSig <- selfifySignature pmod msig
      return $ ValueSelfSig qvar ty selfSig
    TypeSig fld bnd ->
      U.lunbind bnd $ \((tyId, U.unembed -> tsd), msig) -> do
      let p = TypePath pmod fld
          -- replace the local Con (IdP tyId) way of refering to
          -- this definition in the rest of the signature by
          -- the full projection from the model path.  Also replace the
          -- type constructors
          tcon = TCGlobal p
          substVCons = selfifyTypeSigDecl p tsd
          substTyCon = [(tyId, tcon)]
          tsd' = U.substs substTyCon $ U.substs substVCons tsd
          msig' = U.substs substTyCon $ U.substs substVCons msig
      selfSig <- extendTypeSigDeclCtx tcon tsd $ selfifySignature pmod msig'
      return $ TypeSelfSig p tsd' selfSig
    SubmoduleSig fld bnd ->
      U.lunbind bnd $ \((modId, U.unembed -> modTy), msig) -> do
        let p = ProjP pmod fld
        mtnf <- whnfModuleType modTy <??@ ("while selfifying signature of " <> formatErr pmod)
        case mtnf of
         (SigMTNF (SigV subSig ModuleMK)) -> do
           subSelfSig <- selfifySignature p subSig
           let msig' = U.subst modId p msig
           selfSig' <- extendModuleCtx subSelfSig $ selfifySignature pmod msig'
           return $ SubmoduleSelfSig p subSelfSig selfSig'
         (SigMTNF (SigV _ ModelMK)) -> do
           let msig' = U.subst modId p msig
           selfSig' <- selfifySignature pmod msig'
           return $ GenerativeSelfSig p mtnf selfSig'
         (FunMTNF {}) -> do
           let msig' = U.subst modId p msig
           selfSig' <- selfifySignature pmod msig'
           return $ GenerativeSelfSig p mtnf selfSig'
selfifySignature :: Path -> Signature -> TC SelfSig
selfifySignature pmod msig_ =
  case msig_ of
    UnitSig -> return UnitSelfSig
    ValueSig fld ty msig -> do
      let qvar = QVar pmod fld
      selfSig <- selfifySignature pmod msig
      return $ ValueSelfSig qvar ty selfSig
    TypeSig fld bnd ->
      U.lunbind bnd $ \((tyId, U.unembed -> tsd), msig) -> do
      let p = TypePath pmod fld
          -- replace the local Con (IdP tyId) way of refering to
          -- this definition in the rest of the signature by
          -- the full projection from the model path.  Also replace the
          -- type constructors
          tcon = TCGlobal p
          substVCons = selfifyTypeSigDecl p tsd
          substTyCon = [(tyId, tcon)]
          tsd' = U.substs substTyCon $ U.substs substVCons tsd
          msig' = U.substs substTyCon $ U.substs substVCons msig
      selfSig <- extendTypeSigDeclCtx tcon tsd $ selfifySignature pmod msig'
      return $ TypeSelfSig p tsd' selfSig
    SubmoduleSig fld bnd ->
      U.lunbind bnd $ \((modId, U.unembed -> modTy), msig) -> do
        let p = ProjP pmod fld
        mtnf <- whnfModuleType modTy <??@ ("while selfifying signature of " <> formatErr pmod)
        case mtnf of
         (SigMTNF (SigV subSig ModuleMK)) -> do
           subSelfSig <- selfifySignature p subSig
           let msig' = U.subst modId p msig
           selfSig' <- extendModuleCtx subSelfSig $ selfifySignature pmod msig'
           return $ SubmoduleSelfSig p subSelfSig selfSig'
         (SigMTNF (SigV _ ModelMK)) -> do
           let msig' = U.subst modId p msig
           selfSig' <- selfifySignature pmod msig'
           return $ GenerativeSelfSig p mtnf selfSig'
         (FunMTNF {}) -> do
           let msig' = U.subst modId p msig
           selfSig' <- selfifySignature pmod msig'
           return $ GenerativeSelfSig p mtnf selfSig'
selfifySignature pmod msig_ =
  case msig_ of
    UnitSig -> return UnitSelfSig
    ValueSig fld ty msig -> do
      let qvar = QVar pmod fld
      selfSig <- selfifySignature pmod msig
      return $ ValueSelfSig qvar ty selfSig
    TypeSig fld bnd ->
      U.lunbind bnd $ \((tyId, U.unembed -> tsd), msig) -> do
      let p = TypePath pmod fld
          -- replace the local Con (IdP tyId) way of refering to
          -- this definition in the rest of the signature by
          -- the full projection from the model path.  Also replace the
          -- type constructors
          tcon = TCGlobal p
          substVCons = selfifyTypeSigDecl p tsd
          substTyCon = [(tyId, tcon)]
          tsd' = U.substs substTyCon $ U.substs substVCons tsd
          msig' = U.substs substTyCon $ U.substs substVCons msig
      selfSig <- extendTypeSigDeclCtx tcon tsd $ selfifySignature pmod msig'
      return $ TypeSelfSig p tsd' selfSig
    SubmoduleSig fld bnd ->
      U.lunbind bnd $ \((modId, U.unembed -> modTy), msig) -> do
        let p = ProjP pmod fld
        mtnf <- whnfModuleType modTy <??@ ("while selfifying signature of " <> formatErr pmod)
        case mtnf of
         (SigMTNF (SigV subSig ModuleMK)) -> do
           subSelfSig <- selfifySignature p subSig
           let msig' = U.subst modId p msig
           selfSig' <- extendModuleCtx subSelfSig $ selfifySignature pmod msig'
           return $ SubmoduleSelfSig p subSelfSig selfSig'
         (SigMTNF (SigV _ ModelMK)) -> do
           let msig' = U.subst modId p msig
           selfSig' <- selfifySignature pmod msig'
           return $ GenerativeSelfSig p mtnf selfSig'
         (FunMTNF {}) -> do
           let msig' = U.subst modId p msig
           selfSig' <- selfifySignature pmod msig'
           return $ GenerativeSelfSig p mtnf selfSig'