rzk 0.9.2 → 0.10.0
raw patch · 39 files changed
+8691/−6793 lines, 39 filesdep +free-foildep +kind-genericsdep +kind-generics-thPVP ok
version bump matches the API change (PVP)
Dependencies added: free-foil, kind-generics, kind-generics-th, transformers
API changes (from Hackage documentation)
- Free.Scoped: AnnF :: ann typedTerm -> term scope typedTerm -> AnnF (ann :: Type -> Type) (term :: Type -> Type -> Type) scope typedTerm
- Free.Scoped: Free :: t (Scope (FS t) a) (FS t a) -> FS (t :: Type -> Type -> Type) a
- Free.Scoped: InL :: f scope term -> Sum (f :: Type -> Type -> Type) (g :: Type -> Type -> Type) scope term
- Free.Scoped: InR :: g scope term -> Sum (f :: Type -> Type -> Type) (g :: Type -> Type -> Type) scope term
- Free.Scoped: Pure :: a -> FS (t :: Type -> Type -> Type) a
- Free.Scoped: S :: var -> Inc var
- Free.Scoped: Z :: Inc var
- Free.Scoped: [annF] :: AnnF (ann :: Type -> Type) (term :: Type -> Type -> Type) scope typedTerm -> ann typedTerm
- Free.Scoped: [termF] :: AnnF (ann :: Type -> Type) (term :: Type -> Type -> Type) scope typedTerm -> term scope typedTerm
- Free.Scoped: abstract :: (Eq a, Functor f) => a -> f a -> f (Inc a)
- Free.Scoped: data AnnF (ann :: Type -> Type) (term :: Type -> Type -> Type) scope typedTerm
- Free.Scoped: data Empty scope term
- Free.Scoped: data FS (t :: Type -> Type -> Type) a
- Free.Scoped: data Inc var
- Free.Scoped: data Sum (f :: Type -> Type -> Type) (g :: Type -> Type -> Type) scope term
- Free.Scoped: instance (Data.Bifoldable.Bifoldable f, Data.Bifoldable.Bifoldable g) => Data.Bifoldable.Bifoldable (Free.Scoped.Sum f g)
- Free.Scoped: instance (Data.Bifunctor.Bifunctor f, Data.Bifunctor.Bifunctor g) => Data.Bifunctor.Bifunctor (Free.Scoped.Sum f g)
- Free.Scoped: instance (Data.Bitraversable.Bitraversable f, Data.Bitraversable.Bitraversable g) => Data.Bitraversable.Bitraversable (Free.Scoped.Sum f g)
- Free.Scoped: instance (Data.Foldable.Foldable (f scope), Data.Foldable.Foldable (g scope)) => Data.Foldable.Foldable (Free.Scoped.Sum f g scope)
- Free.Scoped: instance (Data.Traversable.Traversable (f scope), Data.Traversable.Traversable (g scope)) => Data.Traversable.Traversable (Free.Scoped.Sum f g scope)
- Free.Scoped: instance (Data.Traversable.Traversable ann, Data.Bitraversable.Bitraversable term) => Data.Bitraversable.Bitraversable (Free.Scoped.AnnF ann term)
- Free.Scoped: instance (GHC.Base.Functor (f scope), GHC.Base.Functor (g scope)) => GHC.Base.Functor (Free.Scoped.Sum f g scope)
- Free.Scoped: instance (GHC.Base.Functor ann, Data.Bifunctor.Bifunctor term) => Data.Bifunctor.Bifunctor (Free.Scoped.AnnF ann term)
- Free.Scoped: instance (GHC.Base.Functor ann, GHC.Base.Functor (term scope)) => GHC.Base.Functor (Free.Scoped.AnnF ann term scope)
- Free.Scoped: instance (GHC.Classes.Eq a, forall x y. (GHC.Classes.Eq x, GHC.Classes.Eq y) => GHC.Classes.Eq (t x y)) => GHC.Classes.Eq (Free.Scoped.FS t a)
- Free.Scoped: instance (GHC.Show.Show (ann typedTerm), GHC.Show.Show (term scope typedTerm)) => GHC.Show.Show (Free.Scoped.AnnF ann term scope typedTerm)
- Free.Scoped: instance Data.Bifoldable.Bifoldable Free.Scoped.Empty
- Free.Scoped: instance Data.Bifoldable.Bifoldable t => Data.Foldable.Foldable (Free.Scoped.FS t)
- Free.Scoped: instance Data.Bifoldable.Bifoldable term => Data.Bifoldable.Bifoldable (Free.Scoped.AnnF ann term)
- Free.Scoped: instance Data.Bifunctor.Bifunctor Free.Scoped.Empty
- Free.Scoped: instance Data.Bifunctor.Bifunctor t => GHC.Base.Applicative (Free.Scoped.FS t)
- Free.Scoped: instance Data.Bifunctor.Bifunctor t => GHC.Base.Functor (Free.Scoped.FS t)
- Free.Scoped: instance Data.Bifunctor.Bifunctor t => GHC.Base.Monad (Free.Scoped.FS t)
- Free.Scoped: instance Data.Bitraversable.Bitraversable Free.Scoped.Empty
- Free.Scoped: instance Data.Bitraversable.Bitraversable t => Data.Traversable.Traversable (Free.Scoped.FS t)
- Free.Scoped: instance Data.Foldable.Foldable (Free.Scoped.Empty scope)
- Free.Scoped: instance Data.Foldable.Foldable Free.Scoped.Inc
- Free.Scoped: instance Data.Traversable.Traversable (Free.Scoped.Empty scope)
- Free.Scoped: instance Data.Traversable.Traversable Free.Scoped.Inc
- Free.Scoped: instance GHC.Base.Functor (Free.Scoped.Empty scope)
- Free.Scoped: instance GHC.Base.Functor Free.Scoped.Inc
- Free.Scoped: instance GHC.Classes.Eq (term scope typedTerm) => GHC.Classes.Eq (Free.Scoped.AnnF ann term scope typedTerm)
- Free.Scoped: instance GHC.Classes.Eq var => GHC.Classes.Eq (Free.Scoped.Inc var)
- Free.Scoped: instance GHC.Generics.Generic (Free.Scoped.Sum f g scope term)
- Free.Scoped: instance GHC.Show.Show var => GHC.Show.Show (Free.Scoped.Inc var)
- Free.Scoped: instantiate :: Monad f => f a -> f (Inc a) -> f a
- Free.Scoped: pattern ExtE :: forall ext (t :: Type -> Type -> Type) a. ext (Scope (FS (t :+: ext)) a) (FS (t :+: ext) a) -> FS (t :+: ext) a
- Free.Scoped: substitute :: forall (t :: Type -> Type -> Type) a. Bifunctor t => FS t a -> Scope (FS t) a -> FS t a
- Free.Scoped: transFS :: Bifunctor term => (forall s t. () => term s t -> term' s t) -> FS term a -> FS term' a
- Free.Scoped: type (:+:) = Sum
- Free.Scoped: type Scope (term :: Type -> Type) var = term Inc var
- Free.Scoped: untyped :: forall (ann :: Type -> Type) (term :: Type -> Type -> Type) a. (Functor ann, Bifunctor term) => FS (AnnF ann term) a -> FS term a
- Free.Scoped.TH: makeCompletePragma :: [Con] -> Q [Dec]
- Free.Scoped.TH: makeCompletePragmaE :: [Con] -> Q [Dec]
- Free.Scoped.TH: makeCompletePragmaT :: [Con] -> Q [Dec]
- Free.Scoped.TH: makeCompletePragmaTE :: [Con] -> Q [Dec]
- Free.Scoped.TH: makePatternEFor :: Con -> Q [Dec]
- Free.Scoped.TH: makePatternFor :: Con -> Q [Dec]
- Free.Scoped.TH: makePatternTEFor :: Con -> Q [Dec]
- Free.Scoped.TH: makePatternTFor :: Con -> Q [Dec]
- Free.Scoped.TH: makePatternsAll :: Name -> Q [Dec]
- Free.Scoped.TH: mkConP :: Name -> [Pat] -> Pat
- Language.Rzk.Free.Syntax: AppF :: term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: BinderPair :: Binder -> Binder -> Binder
- Language.Rzk.Free.Syntax: BinderUnit :: Binder
- Language.Rzk.Free.Syntax: BinderVar :: Maybe VarIdent -> Binder
- Language.Rzk.Free.Syntax: Cube2F :: TermF scope term
- Language.Rzk.Free.Syntax: Cube2_0F :: TermF scope term
- Language.Rzk.Free.Syntax: Cube2_1F :: TermF scope term
- Language.Rzk.Free.Syntax: CubeFlipF :: term -> TermF scope term
- Language.Rzk.Free.Syntax: CubeIF :: TermF scope term
- Language.Rzk.Free.Syntax: CubeI_0F :: TermF scope term
- Language.Rzk.Free.Syntax: CubeI_1F :: TermF scope term
- Language.Rzk.Free.Syntax: CubeProductF :: term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: CubeUnflipF :: term -> TermF scope term
- Language.Rzk.Free.Syntax: CubeUnitF :: TermF scope term
- Language.Rzk.Free.Syntax: CubeUnitStarF :: TermF scope term
- Language.Rzk.Free.Syntax: FirstF :: term -> TermF scope term
- Language.Rzk.Free.Syntax: Flat :: TModality
- Language.Rzk.Free.Syntax: HoleF :: Maybe VarIdent -> TermF scope term
- Language.Rzk.Free.Syntax: Id :: TModality
- Language.Rzk.Free.Syntax: IdJF :: term -> term -> term -> term -> term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: LambdaF :: Binder -> Maybe (TModality, term, Maybe scope) -> scope -> TermF scope term
- Language.Rzk.Free.Syntax: LetF :: Binder -> Maybe term -> term -> scope -> TermF scope term
- Language.Rzk.Free.Syntax: LetModF :: Binder -> TModality -> TModality -> Maybe term -> term -> scope -> TermF scope term
- Language.Rzk.Free.Syntax: ModAppF :: TModality -> term -> TermF scope term
- Language.Rzk.Free.Syntax: ModExtractF :: TModality -> TModality -> term -> TermF scope term
- Language.Rzk.Free.Syntax: Op :: TModality
- Language.Rzk.Free.Syntax: PFst :: Proj
- Language.Rzk.Free.Syntax: PSnd :: Proj
- Language.Rzk.Free.Syntax: PairF :: term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: RecBottomF :: TermF scope term
- Language.Rzk.Free.Syntax: RecOrF :: [(term, term)] -> TermF scope term
- Language.Rzk.Free.Syntax: ReflF :: Maybe (term, Maybe term) -> TermF scope term
- Language.Rzk.Free.Syntax: RzkPosition :: Maybe FilePath -> BNFC'Position -> RzkPosition
- Language.Rzk.Free.Syntax: SecondF :: term -> TermF scope term
- Language.Rzk.Free.Syntax: Sharp :: TModality
- Language.Rzk.Free.Syntax: TopeAndF :: term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: TopeBottomF :: TermF scope term
- Language.Rzk.Free.Syntax: TopeEQF :: term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: TopeInvF :: term -> TermF scope term
- Language.Rzk.Free.Syntax: TopeLEQF :: term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: TopeOrF :: term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: TopeTopF :: TermF scope term
- Language.Rzk.Free.Syntax: TopeUninvF :: term -> TermF scope term
- Language.Rzk.Free.Syntax: Type :: term -> Type term
- Language.Rzk.Free.Syntax: TypeAscF :: term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: TypeFunF :: Binder -> TModality -> term -> Maybe scope -> scope -> TermF scope term
- Language.Rzk.Free.Syntax: TypeIdF :: term -> Maybe term -> term -> TermF scope term
- Language.Rzk.Free.Syntax: TypeInfo :: term -> Maybe term -> Maybe term -> TypeInfo term
- Language.Rzk.Free.Syntax: TypeModalF :: TModality -> term -> TermF scope term
- Language.Rzk.Free.Syntax: TypeRestrictedF :: term -> [(term, term)] -> TermF scope term
- Language.Rzk.Free.Syntax: TypeSigmaF :: Binder -> TModality -> term -> scope -> TermF scope term
- Language.Rzk.Free.Syntax: TypeUnitF :: TermF scope term
- Language.Rzk.Free.Syntax: UnitF :: TermF scope term
- Language.Rzk.Free.Syntax: UniverseCubeF :: TermF scope term
- Language.Rzk.Free.Syntax: UniverseF :: TermF scope term
- Language.Rzk.Free.Syntax: UniverseTopeF :: TermF scope term
- Language.Rzk.Free.Syntax: VarIdent :: VarIdent' RzkPosition -> VarIdent
- Language.Rzk.Free.Syntax: [getType] :: Type term -> term
- Language.Rzk.Free.Syntax: [getVarIdent] :: VarIdent -> VarIdent' RzkPosition
- Language.Rzk.Free.Syntax: [infoNF] :: TypeInfo term -> Maybe term
- Language.Rzk.Free.Syntax: [infoType] :: TypeInfo term -> term
- Language.Rzk.Free.Syntax: [infoWHNF] :: TypeInfo term -> Maybe term
- Language.Rzk.Free.Syntax: [rzkFilePath] :: RzkPosition -> Maybe FilePath
- Language.Rzk.Free.Syntax: [rzkLineCol] :: RzkPosition -> BNFC'Position
- Language.Rzk.Free.Syntax: binderDisplayName :: Binder -> VarIdent
- Language.Rzk.Free.Syntax: binderIsCompound :: Binder -> Bool
- Language.Rzk.Free.Syntax: binderLeaves :: Binder -> [VarIdent]
- Language.Rzk.Free.Syntax: binderName :: Binder -> Maybe VarIdent
- Language.Rzk.Free.Syntax: binderPaths :: Binder -> [([Proj], VarIdent)]
- Language.Rzk.Free.Syntax: binderToPattern :: Binder -> Pattern
- Language.Rzk.Free.Syntax: binderToTerm :: Binder -> Term VarIdent
- Language.Rzk.Free.Syntax: data Binder
- Language.Rzk.Free.Syntax: data Proj
- Language.Rzk.Free.Syntax: data RzkPosition
- Language.Rzk.Free.Syntax: data TModality
- Language.Rzk.Free.Syntax: data TermF scope term
- Language.Rzk.Free.Syntax: data TypeInfo term
- Language.Rzk.Free.Syntax: defaultVarIdents :: [VarIdent]
- Language.Rzk.Free.Syntax: desugarTuple :: t -> [Pattern' t] -> Pattern' t -> Pattern' t -> Pattern' t
- Language.Rzk.Free.Syntax: flattenBinderApp :: Term -> [Term]
- Language.Rzk.Free.Syntax: foldBinderProjections :: Eq a => [(a, [([Proj], a)])] -> Term a -> Term a
- Language.Rzk.Free.Syntax: foldBinderProjectionsT :: Eq a => [(a, [([Proj], a)])] -> TermT a -> TermT a
- Language.Rzk.Free.Syntax: freeVars :: Term a -> [a]
- Language.Rzk.Free.Syntax: freeVarsT :: Eq a => (a -> TermT a) -> TermT a -> [a]
- Language.Rzk.Free.Syntax: freshenBinderLeaves :: [VarIdent] -> Binder -> Binder
- Language.Rzk.Free.Syntax: fromMod :: TModality -> Modality
- Language.Rzk.Free.Syntax: fromScope' :: VarIdent -> [VarIdent] -> [VarIdent] -> Scope Term VarIdent -> Term
- Language.Rzk.Free.Syntax: fromScopeBinder' :: Binder -> VarIdent -> [VarIdent] -> [VarIdent] -> Scope Term VarIdent -> Term
- Language.Rzk.Free.Syntax: fromTModalityToModalColon :: TModality -> ModalColon
- Language.Rzk.Free.Syntax: fromTerm' :: Term' -> Term
- Language.Rzk.Free.Syntax: fromTermWith' :: [VarIdent] -> [VarIdent] -> Term' -> Term
- Language.Rzk.Free.Syntax: fromVarIdent :: VarIdent -> VarIdent
- Language.Rzk.Free.Syntax: holeIdentToken :: Maybe VarIdent -> Text
- Language.Rzk.Free.Syntax: holeName :: Text -> Maybe VarIdent
- Language.Rzk.Free.Syntax: incIndex :: Text -> Text
- Language.Rzk.Free.Syntax: incVarIdentIndex :: VarIdent -> VarIdent
- Language.Rzk.Free.Syntax: instance (GHC.Classes.Eq term, GHC.Classes.Eq scope) => GHC.Classes.Eq (Language.Rzk.Free.Syntax.TermF scope term)
- Language.Rzk.Free.Syntax: instance Data.Bifoldable.Bifoldable Language.Rzk.Free.Syntax.TermF
- Language.Rzk.Free.Syntax: instance Data.Bifunctor.Bifunctor Language.Rzk.Free.Syntax.TermF
- Language.Rzk.Free.Syntax: instance Data.Bitraversable.Bitraversable Language.Rzk.Free.Syntax.TermF
- Language.Rzk.Free.Syntax: instance Data.Foldable.Foldable (Language.Rzk.Free.Syntax.TermF scope)
- Language.Rzk.Free.Syntax: instance Data.Foldable.Foldable Language.Rzk.Free.Syntax.Type
- Language.Rzk.Free.Syntax: instance Data.Foldable.Foldable Language.Rzk.Free.Syntax.TypeInfo
- Language.Rzk.Free.Syntax: instance Data.String.IsString Language.Rzk.Free.Syntax.Term'
- Language.Rzk.Free.Syntax: instance Data.String.IsString Language.Rzk.Free.Syntax.VarIdent
- Language.Rzk.Free.Syntax: instance Data.Traversable.Traversable (Language.Rzk.Free.Syntax.TermF scope)
- Language.Rzk.Free.Syntax: instance Data.Traversable.Traversable Language.Rzk.Free.Syntax.Type
- Language.Rzk.Free.Syntax: instance Data.Traversable.Traversable Language.Rzk.Free.Syntax.TypeInfo
- Language.Rzk.Free.Syntax: instance GHC.Base.Functor (Language.Rzk.Free.Syntax.TermF scope)
- Language.Rzk.Free.Syntax: instance GHC.Base.Functor Language.Rzk.Free.Syntax.Type
- Language.Rzk.Free.Syntax: instance GHC.Base.Functor Language.Rzk.Free.Syntax.TypeInfo
- Language.Rzk.Free.Syntax: instance GHC.Classes.Eq Language.Rzk.Free.Syntax.Binder
- Language.Rzk.Free.Syntax: instance GHC.Classes.Eq Language.Rzk.Free.Syntax.Proj
- Language.Rzk.Free.Syntax: instance GHC.Classes.Eq Language.Rzk.Free.Syntax.TModality
- Language.Rzk.Free.Syntax: instance GHC.Classes.Eq Language.Rzk.Free.Syntax.VarIdent
- Language.Rzk.Free.Syntax: instance GHC.Classes.Eq term => GHC.Classes.Eq (Language.Rzk.Free.Syntax.Type term)
- Language.Rzk.Free.Syntax: instance GHC.Classes.Eq term => GHC.Classes.Eq (Language.Rzk.Free.Syntax.TypeInfo term)
- Language.Rzk.Free.Syntax: instance GHC.Show.Show Language.Rzk.Free.Syntax.TModality
- Language.Rzk.Free.Syntax: instance GHC.Show.Show Language.Rzk.Free.Syntax.Term'
- Language.Rzk.Free.Syntax: instance GHC.Show.Show Language.Rzk.Free.Syntax.TermT'
- Language.Rzk.Free.Syntax: instance GHC.Show.Show Language.Rzk.Free.Syntax.VarIdent
- Language.Rzk.Free.Syntax: invalidateWHNF :: TermT var -> TermT var
- Language.Rzk.Free.Syntax: modCompToMods :: ModComp -> (TModality, TModality)
- Language.Rzk.Free.Syntax: modalColonModality :: ModalColon -> Modality
- Language.Rzk.Free.Syntax: modalColonToTModality :: ModalColon -> TModality
- Language.Rzk.Free.Syntax: modsToModComp :: TModality -> TModality -> ModComp
- Language.Rzk.Free.Syntax: newtype Type term
- Language.Rzk.Free.Syntax: newtype VarIdent
- Language.Rzk.Free.Syntax: partialFreeVarsT :: TermT a -> [a]
- Language.Rzk.Free.Syntax: pattern App :: FS TermF a -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern AppE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern AppT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern AppTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Cube2 :: FS TermF a
- Language.Rzk.Free.Syntax: pattern Cube2E :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern Cube2T :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern Cube2TE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Cube2_0 :: FS TermF a
- Language.Rzk.Free.Syntax: pattern Cube2_0E :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern Cube2_0T :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern Cube2_0TE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Cube2_1 :: FS TermF a
- Language.Rzk.Free.Syntax: pattern Cube2_1E :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern Cube2_1T :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern Cube2_1TE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern CubeFlip :: FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern CubeFlipE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern CubeFlipT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern CubeFlipTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern CubeI :: FS TermF a
- Language.Rzk.Free.Syntax: pattern CubeIE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern CubeIT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern CubeITE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern CubeI_0 :: FS TermF a
- Language.Rzk.Free.Syntax: pattern CubeI_0E :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern CubeI_0T :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern CubeI_0TE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern CubeI_1 :: FS TermF a
- Language.Rzk.Free.Syntax: pattern CubeI_1E :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern CubeI_1T :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern CubeI_1TE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern CubeProduct :: FS TermF a -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern CubeProductE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern CubeProductT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern CubeProductTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern CubeUnflip :: FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern CubeUnflipE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern CubeUnflipT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern CubeUnflipTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern CubeUnit :: FS TermF a
- Language.Rzk.Free.Syntax: pattern CubeUnitE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern CubeUnitStar :: FS TermF a
- Language.Rzk.Free.Syntax: pattern CubeUnitStarE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern CubeUnitStarT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern CubeUnitStarTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern CubeUnitT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern CubeUnitTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern First :: FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern FirstE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern FirstT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern FirstTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Hole :: Maybe VarIdent -> FS TermF a
- Language.Rzk.Free.Syntax: pattern HoleE :: forall {g :: Type -> Type -> Type} {a}. Maybe VarIdent -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern HoleT :: ann (FS (AnnF ann TermF) a) -> Maybe VarIdent -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern HoleTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> Maybe VarIdent -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern IdJ :: FS TermF a -> FS TermF a -> FS TermF a -> FS TermF a -> FS TermF a -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern IdJE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern IdJT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern IdJTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Lambda :: Binder -> Maybe (TModality, FS TermF a, Maybe (Scope (FS TermF) a)) -> Scope (FS TermF) a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern LambdaE :: forall {g :: Type -> Type -> Type} {a}. Binder -> Maybe (TModality, FS (Sum TermF g) a, Maybe (Scope (FS (Sum TermF g)) a)) -> Scope (FS (Sum TermF g)) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern LambdaT :: ann (FS (AnnF ann TermF) a) -> Binder -> Maybe (TModality, FS (AnnF ann TermF) a, Maybe (Scope (FS (AnnF ann TermF)) a)) -> Scope (FS (AnnF ann TermF)) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern LambdaTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> Binder -> Maybe (TModality, FS (Sum (AnnF ann TermF) g) a, Maybe (Scope (FS (Sum (AnnF ann TermF) g)) a)) -> Scope (FS (Sum (AnnF ann TermF) g)) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Let :: Binder -> Maybe (FS TermF a) -> FS TermF a -> Scope (FS TermF) a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern LetE :: forall {g :: Type -> Type -> Type} {a}. Binder -> Maybe (FS (Sum TermF g) a) -> FS (Sum TermF g) a -> Scope (FS (Sum TermF g)) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern LetMod :: Binder -> TModality -> TModality -> Maybe (FS TermF a) -> FS TermF a -> Scope (FS TermF) a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern LetModE :: forall {g :: Type -> Type -> Type} {a}. Binder -> TModality -> TModality -> Maybe (FS (Sum TermF g) a) -> FS (Sum TermF g) a -> Scope (FS (Sum TermF g)) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern LetModT :: ann (FS (AnnF ann TermF) a) -> Binder -> TModality -> TModality -> Maybe (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> Scope (FS (AnnF ann TermF)) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern LetModTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> Binder -> TModality -> TModality -> Maybe (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> Scope (FS (Sum (AnnF ann TermF) g)) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern LetT :: ann (FS (AnnF ann TermF) a) -> Binder -> Maybe (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> Scope (FS (AnnF ann TermF)) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern LetTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> Binder -> Maybe (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> Scope (FS (Sum (AnnF ann TermF) g)) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern ModApp :: TModality -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern ModAppE :: forall {g :: Type -> Type -> Type} {a}. TModality -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern ModAppT :: ann (FS (AnnF ann TermF) a) -> TModality -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern ModAppTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> TModality -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern ModExtract :: TModality -> TModality -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern ModExtractE :: forall {g :: Type -> Type -> Type} {a}. TModality -> TModality -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern ModExtractT :: ann (FS (AnnF ann TermF) a) -> TModality -> TModality -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern ModExtractTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> TModality -> TModality -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Pair :: FS TermF a -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern PairE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern PairT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern PairTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern RecBottom :: FS TermF a
- Language.Rzk.Free.Syntax: pattern RecBottomE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern RecBottomT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern RecBottomTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern RecOr :: [(FS TermF a, FS TermF a)] -> FS TermF a
- Language.Rzk.Free.Syntax: pattern RecOrE :: forall {g :: Type -> Type -> Type} {a}. [(FS (Sum TermF g) a, FS (Sum TermF g) a)] -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern RecOrT :: ann (FS (AnnF ann TermF) a) -> [(FS (AnnF ann TermF) a, FS (AnnF ann TermF) a)] -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern RecOrTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> [(FS (Sum (AnnF ann TermF) g) a, FS (Sum (AnnF ann TermF) g) a)] -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Refl :: Maybe (FS TermF a, Maybe (FS TermF a)) -> FS TermF a
- Language.Rzk.Free.Syntax: pattern ReflE :: forall {g :: Type -> Type -> Type} {a}. Maybe (FS (Sum TermF g) a, Maybe (FS (Sum TermF g) a)) -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern ReflT :: ann (FS (AnnF ann TermF) a) -> Maybe (FS (AnnF ann TermF) a, Maybe (FS (AnnF ann TermF) a)) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern ReflTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> Maybe (FS (Sum (AnnF ann TermF) g) a, Maybe (FS (Sum (AnnF ann TermF) g) a)) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Second :: FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern SecondE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern SecondT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern SecondTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TopeAnd :: FS TermF a -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TopeAndE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TopeAndT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TopeAndTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TopeBottom :: FS TermF a
- Language.Rzk.Free.Syntax: pattern TopeBottomE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TopeBottomT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TopeBottomTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TopeEQ :: FS TermF a -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TopeEQE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TopeEQT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TopeEQTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TopeInv :: FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TopeInvE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TopeInvT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TopeInvTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TopeLEQ :: FS TermF a -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TopeLEQE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TopeLEQT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TopeLEQTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TopeOr :: FS TermF a -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TopeOrE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TopeOrT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TopeOrTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TopeTop :: FS TermF a
- Language.Rzk.Free.Syntax: pattern TopeTopE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TopeTopT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TopeTopTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TopeUninv :: FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TopeUninvE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TopeUninvT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TopeUninvTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TypeAsc :: FS TermF a -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TypeAscE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TypeAscT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TypeAscTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TypeFun :: Binder -> TModality -> FS TermF a -> Maybe (Scope (FS TermF) a) -> Scope (FS TermF) a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TypeFunE :: forall {g :: Type -> Type -> Type} {a}. Binder -> TModality -> FS (Sum TermF g) a -> Maybe (Scope (FS (Sum TermF g)) a) -> Scope (FS (Sum TermF g)) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TypeFunT :: ann (FS (AnnF ann TermF) a) -> Binder -> TModality -> FS (AnnF ann TermF) a -> Maybe (Scope (FS (AnnF ann TermF)) a) -> Scope (FS (AnnF ann TermF)) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TypeFunTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> Binder -> TModality -> FS (Sum (AnnF ann TermF) g) a -> Maybe (Scope (FS (Sum (AnnF ann TermF) g)) a) -> Scope (FS (Sum (AnnF ann TermF) g)) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TypeId :: FS TermF a -> Maybe (FS TermF a) -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TypeIdE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> Maybe (FS (Sum TermF g) a) -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TypeIdT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> Maybe (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TypeIdTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> Maybe (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TypeModal :: TModality -> FS TermF a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TypeModalE :: forall {g :: Type -> Type -> Type} {a}. TModality -> FS (Sum TermF g) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TypeModalT :: ann (FS (AnnF ann TermF) a) -> TModality -> FS (AnnF ann TermF) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TypeModalTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> TModality -> FS (Sum (AnnF ann TermF) g) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TypeRestricted :: FS TermF a -> [(FS TermF a, FS TermF a)] -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TypeRestrictedE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a -> [(FS (Sum TermF g) a, FS (Sum TermF g) a)] -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TypeRestrictedT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a -> [(FS (AnnF ann TermF) a, FS (AnnF ann TermF) a)] -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TypeRestrictedTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a -> [(FS (Sum (AnnF ann TermF) g) a, FS (Sum (AnnF ann TermF) g) a)] -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TypeSigma :: Binder -> TModality -> FS TermF a -> Scope (FS TermF) a -> FS TermF a
- Language.Rzk.Free.Syntax: pattern TypeSigmaE :: forall {g :: Type -> Type -> Type} {a}. Binder -> TModality -> FS (Sum TermF g) a -> Scope (FS (Sum TermF g)) a -> FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TypeSigmaT :: ann (FS (AnnF ann TermF) a) -> Binder -> TModality -> FS (AnnF ann TermF) a -> Scope (FS (AnnF ann TermF)) a -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TypeSigmaTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> Binder -> TModality -> FS (Sum (AnnF ann TermF) g) a -> Scope (FS (Sum (AnnF ann TermF) g)) a -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern TypeUnit :: FS TermF a
- Language.Rzk.Free.Syntax: pattern TypeUnitE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern TypeUnitT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern TypeUnitTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Unit :: FS TermF a
- Language.Rzk.Free.Syntax: pattern UnitE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern UnitT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern UnitTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern Universe :: FS TermF a
- Language.Rzk.Free.Syntax: pattern UniverseCube :: FS TermF a
- Language.Rzk.Free.Syntax: pattern UniverseCubeE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern UniverseCubeT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern UniverseCubeTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern UniverseE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern UniverseT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern UniverseTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: pattern UniverseTope :: FS TermF a
- Language.Rzk.Free.Syntax: pattern UniverseTopeE :: forall {g :: Type -> Type -> Type} {a}. FS (Sum TermF g) a
- Language.Rzk.Free.Syntax: pattern UniverseTopeT :: ann (FS (AnnF ann TermF) a) -> FS (AnnF ann TermF) a
- Language.Rzk.Free.Syntax: pattern UniverseTopeTE :: forall {ann} {g :: Type -> Type -> Type} {a}. ann (FS (Sum (AnnF ann TermF) g) a) -> FS (Sum (AnnF ann TermF) g) a
- Language.Rzk.Free.Syntax: patternToTerm :: Pattern -> Term
- Language.Rzk.Free.Syntax: ppRzkPosition :: RzkPosition -> String
- Language.Rzk.Free.Syntax: ppVarIdentWithLocation :: VarIdent -> String
- Language.Rzk.Free.Syntax: projChain :: Term a -> Maybe ([Proj], a)
- Language.Rzk.Free.Syntax: projChainT :: TermT a -> Maybe ([Proj], a)
- Language.Rzk.Free.Syntax: refreshVar :: [VarIdent] -> VarIdent -> VarIdent
- Language.Rzk.Free.Syntax: restorePatternVars :: [(VarIdent, Binder)] -> Term VarIdent -> Term VarIdent
- Language.Rzk.Free.Syntax: sigmaParamToTypeSigma :: BNFC'Position -> SigmaParam -> Term -> Term
- Language.Rzk.Free.Syntax: substituteT :: TermT var -> Scope TermT var -> TermT var
- Language.Rzk.Free.Syntax: termIsNF :: TermT var -> TermT var
- Language.Rzk.Free.Syntax: termIsWHNF :: TermT var -> TermT var
- Language.Rzk.Free.Syntax: toModality :: Modality -> TModality
- Language.Rzk.Free.Syntax: toScope :: VarIdent -> (VarIdent -> Term a) -> Term -> Scope Term a
- Language.Rzk.Free.Syntax: toScopePattern :: Pattern -> (VarIdent -> Term a) -> Term -> Scope Term a
- Language.Rzk.Free.Syntax: toTerm :: (VarIdent -> Term a) -> Term -> Term a
- Language.Rzk.Free.Syntax: toTerm' :: Term -> Term'
- Language.Rzk.Free.Syntax: type Term = FS TermF
- Language.Rzk.Free.Syntax: type Term' = Term VarIdent
- Language.Rzk.Free.Syntax: type TermT = FS AnnF TypeInfo TermF
- Language.Rzk.Free.Syntax: type TermT' = TermT VarIdent
- Language.Rzk.Free.Syntax: unsafeTermToPattern :: Term -> Pattern
- Language.Rzk.Free.Syntax: unusedScope :: Scope Term var -> Term var
- Language.Rzk.Free.Syntax: varIdent :: VarIdent -> VarIdent
- Language.Rzk.Free.Syntax: varIdentAt :: Maybe FilePath -> VarIdent -> VarIdent
- Rzk.TypeCheck: ActionCheckCoherence :: (TermT var, TermT var) -> (TermT var, TermT var) -> Action var
- Rzk.TypeCheck: ActionCheckLetValue :: Maybe VarIdent -> Action var
- Rzk.TypeCheck: ActionCloseSection :: Maybe SectionName -> Action var
- Rzk.TypeCheck: ActionContextEntailedBy :: [TermT var] -> TermT var -> Action var
- Rzk.TypeCheck: ActionContextEntails :: [TermT var] -> TermT var -> Action var
- Rzk.TypeCheck: ActionContextEntailsUnion :: [TermT var] -> [TermT var] -> Action var
- Rzk.TypeCheck: ActionInfer :: Term var -> Action var
- Rzk.TypeCheck: ActionNF :: TermT var -> Action var
- Rzk.TypeCheck: ActionTypeCheck :: Term var -> TermT var -> Action var
- Rzk.TypeCheck: ActionUnify :: TermT var -> TermT var -> TermT var -> Action var
- Rzk.TypeCheck: ActionUnifyTerms :: TermT var -> TermT var -> Action var
- Rzk.TypeCheck: ActionWHNF :: TermT var -> Action var
- Rzk.TypeCheck: BinderNames :: (var -> VarIdent) -> [(VarIdent, [([Proj], VarIdent)])] -> [(VarIdent, Binder)] -> BinderNames var
- Rzk.TypeCheck: BottomUp :: OutputDirection
- Rzk.TypeCheck: Branching :: ElimCost
- Rzk.TypeCheck: Camera :: Point3D a -> a -> a -> a -> a -> Camera a
- Rzk.TypeCheck: Context :: [ScopeInfo var] -> [GlobalScopeInfo var] -> (VarIdent -> var) -> [ModalTope var] -> [ModalTope var] -> [ModalTope var] -> [[ModalTope var]] -> Maybe Bool -> CachedSaturation var -> [Action var] -> Maybe Command -> Maybe LocationInfo -> Verbosity -> Covariance -> Maybe RenderBackend -> Bool -> Bool -> Bool -> [VarIdent] -> Context var
- Rzk.TypeCheck: Contravariant :: Covariance
- Rzk.TypeCheck: Covariant :: Covariance
- Rzk.TypeCheck: CubeCoords2D :: [(Point3D a, Point2D b)] -> [(Edge3D a, (Point2D b, Point2D b))] -> [(Face3D a, (Point2D b, Point2D b, Point2D b))] -> [(Volume3D a, (Point2D b, Point2D b, Point2D b, Point2D b))] -> CubeCoords2D a b
- Rzk.TypeCheck: Debug :: Verbosity
- Rzk.TypeCheck: Decl :: var -> TermT var -> Maybe (TermT var) -> Bool -> [var] -> Maybe LocationInfo -> Decl var
- Rzk.TypeCheck: GlobalScopeInfo :: Maybe SectionName -> [(var, VarInfo VarIdent)] -> GlobalScopeInfo var
- Rzk.TypeCheck: HoleEntry :: VarIdent -> Term' -> HoleEntry
- Rzk.TypeCheck: HoleInfo :: Maybe VarIdent -> Term' -> Maybe (VarIdent, Term') -> [HoleEntry] -> [HoleEntry] -> [Term'] -> [Term'] -> [Term'] -> Maybe String -> Maybe LocationInfo -> HoleInfo
- Rzk.TypeCheck: Invariant :: Covariance
- Rzk.TypeCheck: LocationInfo :: Maybe FilePath -> Maybe Int -> LocationInfo
- Rzk.TypeCheck: Matrix3D :: a -> a -> a -> a -> a -> a -> a -> a -> a -> Matrix3D a
- Rzk.TypeCheck: Matrix4D :: a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> Matrix4D a
- Rzk.TypeCheck: ModalTope :: TModality -> TModality -> TermT var -> ModalTope var
- Rzk.TypeCheck: Normal :: Verbosity
- Rzk.TypeCheck: PlainTypeError :: TypeErrorInContext var -> TypeErrorInScopedContext var
- Rzk.TypeCheck: RenderLaTeX :: RenderBackend
- Rzk.TypeCheck: RenderObjectData :: String -> String -> String -> RenderObjectData
- Rzk.TypeCheck: RenderSVG :: RenderBackend
- Rzk.TypeCheck: SaturationCached :: Maybe [[ModalTope var]] -> CachedSaturation var
- Rzk.TypeCheck: SaturationUncached :: CachedSaturation var
- Rzk.TypeCheck: ScopeInfo :: Maybe SectionName -> [(var, VarInfo var)] -> ScopeInfo var
- Rzk.TypeCheck: ScopedTypeError :: Maybe VarIdent -> TypeErrorInScopedContext (Inc var) -> TypeErrorInScopedContext var
- Rzk.TypeCheck: ShapeView :: Term' -> Term' -> BinderTypeView
- Rzk.TypeCheck: Silent :: Verbosity
- Rzk.TypeCheck: SpineStep :: ElimCost
- Rzk.TypeCheck: TopDown :: OutputDirection
- Rzk.TypeCheck: TypeErrorCannotInferBareLambda :: Term var -> TypeError var
- Rzk.TypeCheck: TypeErrorCannotInferBareRefl :: Term var -> TypeError var
- Rzk.TypeCheck: TypeErrorCannotInferHole :: Term var -> TypeError var
- Rzk.TypeCheck: TypeErrorDuplicateTopLevel :: [VarIdent] -> VarIdent -> TypeError var
- Rzk.TypeCheck: TypeErrorImplicitAssumption :: (var, TermT var) -> var -> TypeError var
- Rzk.TypeCheck: TypeErrorInContext :: TypeError var -> Context var -> TypeErrorInContext var
- Rzk.TypeCheck: TypeErrorInvalidArgumentType :: Term var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorModalityMismatch :: TModality -> TModality -> Term var -> TypeError var
- Rzk.TypeCheck: TypeErrorNotFunction :: TermT var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorNotModal :: Term var -> TModality -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorNotPair :: TermT var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorNotTypeInModal :: TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorOther :: String -> TypeError var
- Rzk.TypeCheck: TypeErrorTopeContextDisjoint :: TermT var -> [TermT var] -> TypeError var
- Rzk.TypeCheck: TypeErrorTopeNotSatisfied :: [TermT var] -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorTopesNotEquivalent :: TermT var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorUnaccessibleVar :: var -> TModality -> TModality -> TypeError var
- Rzk.TypeCheck: TypeErrorUndefined :: var -> TypeError var
- Rzk.TypeCheck: TypeErrorUnexpectedLambda :: Term var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorUnexpectedPair :: Term var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorUnexpectedRefl :: Term var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorUnify :: TermT var -> TermT var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorUnifyTerms :: TermT var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorUnsolvedHole :: Maybe VarIdent -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeErrorUnusedUsedVariables :: [var] -> var -> TypeError var
- Rzk.TypeCheck: TypeErrorUnusedVariable :: var -> TermT var -> TypeError var
- Rzk.TypeCheck: TypeView :: Term' -> BinderTypeView
- Rzk.TypeCheck: VarInfo :: TermT var -> Maybe (TermT var) -> TModality -> TModality -> Binder -> Bool -> Bool -> [var] -> Maybe LocationInfo -> VarInfo var
- Rzk.TypeCheck: Vector3D :: a -> a -> a -> Vector3D a
- Rzk.TypeCheck: Vector4D :: a -> a -> a -> a -> Vector4D a
- Rzk.TypeCheck: [actionStack] :: Context var -> [Action var]
- Rzk.TypeCheck: [binderNameOf] :: BinderNames var -> var -> VarIdent
- Rzk.TypeCheck: [binderNamePats] :: BinderNames var -> [(VarIdent, Binder)]
- Rzk.TypeCheck: [binderNameProjs] :: BinderNames var -> [(VarIdent, [([Proj], VarIdent)])]
- Rzk.TypeCheck: [cameraAngleX] :: Camera a -> a
- Rzk.TypeCheck: [cameraAngleY] :: Camera a -> a
- Rzk.TypeCheck: [cameraAspectRatio] :: Camera a -> a
- Rzk.TypeCheck: [cameraFoV] :: Camera a -> a
- Rzk.TypeCheck: [cameraPos] :: Camera a -> Point3D a
- Rzk.TypeCheck: [covariance] :: Context var -> Covariance
- Rzk.TypeCheck: [currentCommand] :: Context var -> Maybe Command
- Rzk.TypeCheck: [declIsAssumption] :: Decl var -> Bool
- Rzk.TypeCheck: [declLocation] :: Decl var -> Maybe LocationInfo
- Rzk.TypeCheck: [declName] :: Decl var -> var
- Rzk.TypeCheck: [declType] :: Decl var -> TermT var
- Rzk.TypeCheck: [declUsedVars] :: Decl var -> [var]
- Rzk.TypeCheck: [declValue] :: Decl var -> Maybe (TermT var)
- Rzk.TypeCheck: [deferHoleMismatches] :: Context var -> Bool
- Rzk.TypeCheck: [edges] :: CubeCoords2D a b -> [(Edge3D a, (Point2D b, Point2D b))]
- Rzk.TypeCheck: [faces] :: CubeCoords2D a b -> [(Face3D a, (Point2D b, Point2D b, Point2D b))]
- Rzk.TypeCheck: [globalEmbed] :: Context var -> VarIdent -> var
- Rzk.TypeCheck: [globalScopes] :: Context var -> [GlobalScopeInfo var]
- Rzk.TypeCheck: [gscopeName] :: GlobalScopeInfo var -> Maybe SectionName
- Rzk.TypeCheck: [gscopeVars] :: GlobalScopeInfo var -> [(var, VarInfo VarIdent)]
- Rzk.TypeCheck: [hintLemmas] :: Context var -> [VarIdent]
- Rzk.TypeCheck: [holeCandidates] :: HoleInfo -> [Term']
- Rzk.TypeCheck: [holeCubeVars] :: HoleInfo -> [HoleEntry]
- Rzk.TypeCheck: [holeDiagram] :: HoleInfo -> Maybe String
- Rzk.TypeCheck: [holeEntryName] :: HoleEntry -> VarIdent
- Rzk.TypeCheck: [holeEntryType] :: HoleEntry -> Term'
- Rzk.TypeCheck: [holeGoalShape] :: HoleInfo -> Maybe (VarIdent, Term')
- Rzk.TypeCheck: [holeGoal] :: HoleInfo -> Term'
- Rzk.TypeCheck: [holeIntroductions] :: HoleInfo -> [Term']
- Rzk.TypeCheck: [holeLocation] :: HoleInfo -> Maybe LocationInfo
- Rzk.TypeCheck: [holeName] :: HoleInfo -> Maybe VarIdent
- Rzk.TypeCheck: [holeTermVars] :: HoleInfo -> [HoleEntry]
- Rzk.TypeCheck: [holeTopes] :: HoleInfo -> [Term']
- Rzk.TypeCheck: [holesAreErrors] :: Context var -> Bool
- Rzk.TypeCheck: [localDiscreteTopes] :: Context var -> [ModalTope var]
- Rzk.TypeCheck: [localScopes] :: Context var -> [ScopeInfo var]
- Rzk.TypeCheck: [localTopesEntailBottom] :: Context var -> Maybe Bool
- Rzk.TypeCheck: [localTopesNFUnion] :: Context var -> [[ModalTope var]]
- Rzk.TypeCheck: [localTopesNF] :: Context var -> [ModalTope var]
- Rzk.TypeCheck: [localTopesSaturated] :: Context var -> CachedSaturation var
- Rzk.TypeCheck: [localTopes] :: Context var -> [ModalTope var]
- Rzk.TypeCheck: [locationFilePath] :: LocationInfo -> Maybe FilePath
- Rzk.TypeCheck: [locationLine] :: LocationInfo -> Maybe Int
- Rzk.TypeCheck: [location] :: Context var -> Maybe LocationInfo
- Rzk.TypeCheck: [modAccum] :: VarInfo var -> TModality
- Rzk.TypeCheck: [renderBackend] :: Context var -> Maybe RenderBackend
- Rzk.TypeCheck: [renderHideTerm] :: Context var -> Bool
- Rzk.TypeCheck: [renderObjectDataColor] :: RenderObjectData -> String
- Rzk.TypeCheck: [renderObjectDataFullLabel] :: RenderObjectData -> String
- Rzk.TypeCheck: [renderObjectDataLabel] :: RenderObjectData -> String
- Rzk.TypeCheck: [scopeName] :: ScopeInfo var -> Maybe SectionName
- Rzk.TypeCheck: [scopeVars] :: ScopeInfo var -> [(var, VarInfo var)]
- Rzk.TypeCheck: [tModAccum] :: ModalTope var -> TModality
- Rzk.TypeCheck: [tModVar] :: ModalTope var -> TModality
- Rzk.TypeCheck: [tTope] :: ModalTope var -> TermT var
- Rzk.TypeCheck: [typeErrorContext] :: TypeErrorInContext var -> Context var
- Rzk.TypeCheck: [typeErrorError] :: TypeErrorInContext var -> TypeError var
- Rzk.TypeCheck: [varDeclaredAssumptions] :: VarInfo var -> [var]
- Rzk.TypeCheck: [varIsAssumption] :: VarInfo var -> Bool
- Rzk.TypeCheck: [varIsTopLevel] :: VarInfo var -> Bool
- Rzk.TypeCheck: [varLocation] :: VarInfo var -> Maybe LocationInfo
- Rzk.TypeCheck: [varModality] :: VarInfo var -> TModality
- Rzk.TypeCheck: [varOrig] :: VarInfo var -> Binder
- Rzk.TypeCheck: [varType] :: VarInfo var -> TermT var
- Rzk.TypeCheck: [varValue] :: VarInfo var -> Maybe (TermT var)
- Rzk.TypeCheck: [verbosity] :: Context var -> Verbosity
- Rzk.TypeCheck: [vertices] :: CubeCoords2D a b -> [(Point3D a, Point2D b)]
- Rzk.TypeCheck: [volumes] :: CubeCoords2D a b -> [(Volume3D a, (Point2D b, Point2D b, Point2D b, Point2D b))]
- Rzk.TypeCheck: abstractAssumption :: Eq var => (var, VarInfo var) -> Decl var -> Decl var
- Rzk.TypeCheck: accessibleTopes :: [ModalTope var] -> [TermT var]
- Rzk.TypeCheck: addModalityToScope :: TModality -> ScopeInfo var -> ScopeInfo var
- Rzk.TypeCheck: addParamDecls :: [ParamDecl] -> Term -> Term
- Rzk.TypeCheck: addParams :: [Param] -> Term -> Term
- Rzk.TypeCheck: addVarInCurrentGlobalScope :: VarIdent -> VarInfo VarIdent -> Context VarIdent -> Context VarIdent
- Rzk.TypeCheck: addVarInCurrentScope :: var -> VarInfo var -> Context var -> Context var
- Rzk.TypeCheck: addVarToScope :: var -> VarInfo var -> ScopeInfo var -> ScopeInfo var
- Rzk.TypeCheck: allEliminationsInto :: Eq var => TermT var -> TermT var -> TypeCheck var [TermT var]
- Rzk.TypeCheck: allIntroductionsOf :: Eq var => TermT var -> [VarIdent] -> TypeCheck var [TermT var]
- Rzk.TypeCheck: allM :: Monad m => (a -> m Bool) -> [a] -> m Bool
- Rzk.TypeCheck: allTopePoints :: Eq var => TermT var -> [TermT var]
- Rzk.TypeCheck: allowHoles :: Context var -> Context var
- Rzk.TypeCheck: appT :: TermT var -> TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: applyModality :: TModality -> Context var -> Context var
- Rzk.TypeCheck: applyModalityToGlobalScopes :: TModality -> [GlobalScopeInfo var] -> [GlobalScopeInfo var]
- Rzk.TypeCheck: applyModalityToScopes :: TModality -> [ScopeInfo var] -> [ScopeInfo var]
- Rzk.TypeCheck: applyModalityToTopes :: TModality -> [ModalTope var] -> [ModalTope var]
- Rzk.TypeCheck: askCurrentGlobalScope :: TypeCheck VarIdent (ScopeInfo VarIdent)
- Rzk.TypeCheck: askCurrentScope :: TypeCheck var (ScopeInfo var)
- Rzk.TypeCheck: availableTopes :: Context var -> [TermT var]
- Rzk.TypeCheck: availableTopesNF :: Context var -> [TermT var]
- Rzk.TypeCheck: binderProjMap :: (var -> VarIdent) -> [(var, Binder)] -> [(VarIdent, [([Proj], VarIdent)])]
- Rzk.TypeCheck: binderTypeEntriesM :: Eq var => BinderNames var -> Binder -> TermT var -> TypeCheck var [(VarIdent, BinderTypeView)]
- Rzk.TypeCheck: binderTypesInScopeOf :: [Decl'] -> [Decl'] -> [(VarIdent, BinderTypeView)]
- Rzk.TypeCheck: binderTypesOfTermM :: Eq var => BinderNames var -> TermT var -> TypeCheck var [(VarIdent, BinderTypeView)]
- Rzk.TypeCheck: block :: OutputDirection -> [String] -> String
- Rzk.TypeCheck: checkCoherence :: Eq var => (TermT var, TermT var) -> (TermT var, TermT var) -> TypeCheck var ()
- Rzk.TypeCheck: checkDefinedVar :: VarIdent -> TypeCheck VarIdent ()
- Rzk.TypeCheck: checkEntails :: Eq var => TermT var -> TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: checkHoleAgainstShape :: Eq var => Maybe VarIdent -> Binder -> TermT var -> TermT (Inc var) -> TypeCheck var (TermT var)
- Rzk.TypeCheck: checkNameShadowing :: VarIdent -> TypeCheck var ()
- Rzk.TypeCheck: checkRecOrAgainst :: Eq var => TermT var -> [(Term var, Term var)] -> TypeCheck var (TermT var)
- Rzk.TypeCheck: checkTopLevelDuplicate :: VarIdent -> TypeCheck var ()
- Rzk.TypeCheck: checkTope :: Eq var => TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: checkTopeAgainstContext :: Eq var => String -> TermT var -> TypeCheck var ()
- Rzk.TypeCheck: checkTopeEntails :: Eq var => TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: class ModeTheory m
- Rzk.TypeCheck: closeScope :: Binder -> WriterT [HoleInfo] (Except (TypeErrorInScopedContext (Inc var))) b -> TypeCheck var b
- Rzk.TypeCheck: coe :: ModeTheory m => m -> m -> Bool
- Rzk.TypeCheck: collectScopeDecls :: Eq var => Bool -> [TypeErrorInScopedContext var] -> [(var, VarInfo var)] -> [(var, VarInfo var)] -> TypeCheck var ([Decl var], [TypeErrorInScopedContext var])
- Rzk.TypeCheck: comp :: ModeTheory m => m -> m -> m
- Rzk.TypeCheck: componentWiseEQT :: Int -> TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: containsHole :: TermT var -> Bool
- Rzk.TypeCheck: contextBinders :: Context VarIdent -> ([(VarIdent, Binder)], [(VarIdent, [([Proj], VarIdent)])])
- Rzk.TypeCheck: contextEntails :: Eq var => TermT var -> TypeCheck var ()
- Rzk.TypeCheck: contextEntailsBottom :: Eq var => TypeCheck var Bool
- Rzk.TypeCheck: contextEntailsUnion :: Eq var => [TermT var] -> TypeCheck var ()
- Rzk.TypeCheck: countCommands :: Integral a => [Command] -> a
- Rzk.TypeCheck: coverageHolds :: Eq var => [TermT var] -> TypeCheck var Bool
- Rzk.TypeCheck: cube2T :: TermT var
- Rzk.TypeCheck: cube2_0T :: TermT var
- Rzk.TypeCheck: cube2_1T :: TermT var
- Rzk.TypeCheck: cube2powerT :: Int -> TermT var
- Rzk.TypeCheck: cubeFlipT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: cubeIT :: TermT var
- Rzk.TypeCheck: cubeI_0T :: TermT var
- Rzk.TypeCheck: cubeI_1T :: TermT var
- Rzk.TypeCheck: cubeProductT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: cubeSubTopes :: [(ShapeId, TermT (Inc var))]
- Rzk.TypeCheck: cubeT :: TermT var
- Rzk.TypeCheck: cubeUnflipT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: cubeUnitStarT :: TermT var
- Rzk.TypeCheck: cubeUnitT :: TermT var
- Rzk.TypeCheck: data Action var
- Rzk.TypeCheck: data BinderNames var
- Rzk.TypeCheck: data BinderTypeView
- Rzk.TypeCheck: data CachedSaturation var
- Rzk.TypeCheck: data Camera a
- Rzk.TypeCheck: data Context var
- Rzk.TypeCheck: data Covariance
- Rzk.TypeCheck: data CubeCoords2D a b
- Rzk.TypeCheck: data Decl var
- Rzk.TypeCheck: data ElimCost
- Rzk.TypeCheck: data GlobalScopeInfo var
- Rzk.TypeCheck: data HoleEntry
- Rzk.TypeCheck: data HoleInfo
- Rzk.TypeCheck: data LocationInfo
- Rzk.TypeCheck: data Matrix3D a
- Rzk.TypeCheck: data Matrix4D a
- Rzk.TypeCheck: data ModalTope var
- Rzk.TypeCheck: data OutputDirection
- Rzk.TypeCheck: data RenderBackend
- Rzk.TypeCheck: data RenderObjectData
- Rzk.TypeCheck: data ScopeInfo var
- Rzk.TypeCheck: data TypeError var
- Rzk.TypeCheck: data TypeErrorInContext var
- Rzk.TypeCheck: data TypeErrorInScopedContext var
- Rzk.TypeCheck: data VarInfo var
- Rzk.TypeCheck: data Vector3D a
- Rzk.TypeCheck: data Vector4D a
- Rzk.TypeCheck: data Verbosity
- Rzk.TypeCheck: declBinderTypes :: Decl' -> TypeCheck VarIdent [(VarIdent, BinderTypeView)]
- Rzk.TypeCheck: defaultCamera :: Floating a => Camera a
- Rzk.TypeCheck: defaultTypeCheck :: TypeCheck VarIdent a -> Either (TypeErrorInScopedContext VarIdent) a
- Rzk.TypeCheck: defaultTypeCheckWithHoles :: TypeCheck VarIdent a -> Either (TypeErrorInScopedContext VarIdent) (a, [HoleInfo])
- Rzk.TypeCheck: defaultTypeCheckWithHoles' :: Context var -> TypeCheck var a -> Either (TypeErrorInScopedContext var) (a, [HoleInfo])
- Rzk.TypeCheck: destructuringBinder :: Binder -> TermT var -> Binder
- Rzk.TypeCheck: doesShadowName :: VarIdent -> TypeCheck var [VarIdent]
- Rzk.TypeCheck: eliminatorsOf :: Eq var => TermT var -> TypeCheck var [(ElimCost, TermT var -> TermT var)]
- Rzk.TypeCheck: emptyContext :: Context VarIdent
- Rzk.TypeCheck: emptyContextUnseeded :: Context VarIdent
- Rzk.TypeCheck: emptyTopeContext :: [ModalTope var]
- Rzk.TypeCheck: endSection :: [TypeErrorInScopedContext VarIdent] -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent])
- Rzk.TypeCheck: endpointsAgree :: Eq var => TermT var -> TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: entailContextM :: Eq var => TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: entailM :: Eq var => [ModalTope var] -> TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: entailSaturatedM :: Eq var => [[ModalTope var]] -> TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: entailTraceM :: Eq var => [ModalTope var] -> TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: enterModality :: Eq var => TModality -> TypeCheck var b -> TypeCheck var b
- Rzk.TypeCheck: enterScope :: Eq var => Binder -> TModality -> TermT var -> TypeCheck (Inc var) b -> TypeCheck var b
- Rzk.TypeCheck: enterScopeContext :: Binder -> TModality -> TermT var -> Maybe (TermT var) -> Context var -> Context (Inc var)
- Rzk.TypeCheck: enterScopeMaybe :: Eq var => Binder -> TModality -> TermT var -> Maybe (TermT var) -> TypeCheck (Inc var) b -> TypeCheck var b
- Rzk.TypeCheck: enterScopeWithBind :: Eq var => Binder -> TModality -> TermT var -> TermT var -> TypeCheck (Inc var) b -> TypeCheck var b
- Rzk.TypeCheck: etaExpand :: Eq var => TermT var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: etaMatch :: Eq var => Maybe (TermT var) -> TermT var -> TermT var -> TypeCheck var (TermT var, TermT var)
- Rzk.TypeCheck: filterAccessible :: [ModalTope var] -> [ModalTope var]
- Rzk.TypeCheck: filterInaccessible :: [ModalTope var] -> [ModalTope var]
- Rzk.TypeCheck: firstT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: fitsInto :: Eq var => TermT var -> TermT var -> TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: freeVarsT_ :: Eq var => TermT var -> TypeCheck var [var]
- Rzk.TypeCheck: freshBinders :: Eq var => (var -> VarIdent) -> [(var, VarIdent)] -> [(var, Binder)] -> [(var, Binder)]
- Rzk.TypeCheck: fromAffine :: Fractional a => Vector4D a -> (Point2D a, a)
- Rzk.TypeCheck: fromTypeError :: TypeError var -> TypeCheck var (TypeErrorInScopedContext var)
- Rzk.TypeCheck: generateTopes :: Eq var => [TermT var] -> [TermT var] -> [TermT var]
- Rzk.TypeCheck: generateTopesForModalCubeVarsM :: TypeCheck var [ModalTope var]
- Rzk.TypeCheck: generateTopesForPointsM :: Eq var => [TermT var] -> TypeCheck var [TermT var]
- Rzk.TypeCheck: hideTermData :: Bool -> String -> RenderObjectData -> RenderObjectData
- Rzk.TypeCheck: hidingTerm :: TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: idJT :: TermT var -> TermT var -> TermT var -> TermT var -> TermT var -> TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: iden :: ModeTheory m => m
- Rzk.TypeCheck: inAllSubContexts :: Eq var => TypeCheck var () -> TypeCheck var () -> TypeCheck var ()
- Rzk.TypeCheck: inCubeLayer :: Eq var => TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: inTopeLayer :: Eq var => TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: infer :: Eq var => Term var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: inferAs :: Eq var => TermT var -> Term var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: inferStandalone :: Term VarIdent -> Either (TypeErrorInScopedContext VarIdent) (TermT VarIdent)
- Rzk.TypeCheck: infoOfVar :: Eq var => (VarInfo var -> a) -> var -> TypeCheck var a
- Rzk.TypeCheck: insertExplicitAssumptionFor :: Eq var => var -> (var, VarInfo var) -> TermT var -> TermT var
- Rzk.TypeCheck: insertExplicitAssumptionFor' :: Eq var => var -> (var, VarInfo var) -> VarInfo var -> VarInfo var
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.Action
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.CachedSaturation
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.Context
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.GlobalScopeInfo
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.ModalTope
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.ScopeInfo
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.TypeError
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.TypeErrorInContext
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.TypeErrorInScopedContext
- Rzk.TypeCheck: instance Data.Foldable.Foldable Rzk.TypeCheck.VarInfo
- Rzk.TypeCheck: instance Data.String.IsString Language.Rzk.Free.Syntax.TermT'
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.Action
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.CachedSaturation
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.Context
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.GlobalScopeInfo
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.ModalTope
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.ScopeInfo
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.TypeError
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.TypeErrorInContext
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.TypeErrorInScopedContext
- Rzk.TypeCheck: instance GHC.Base.Functor Rzk.TypeCheck.VarInfo
- Rzk.TypeCheck: instance GHC.Classes.Eq Rzk.TypeCheck.ElimCost
- Rzk.TypeCheck: instance GHC.Classes.Eq Rzk.TypeCheck.HoleEntry
- Rzk.TypeCheck: instance GHC.Classes.Eq Rzk.TypeCheck.HoleInfo
- Rzk.TypeCheck: instance GHC.Classes.Eq Rzk.TypeCheck.LocationInfo
- Rzk.TypeCheck: instance GHC.Classes.Eq Rzk.TypeCheck.OutputDirection
- Rzk.TypeCheck: instance GHC.Classes.Eq Rzk.TypeCheck.Verbosity
- Rzk.TypeCheck: instance GHC.Classes.Eq var => GHC.Classes.Eq (Rzk.TypeCheck.Decl var)
- Rzk.TypeCheck: instance GHC.Classes.Eq var => GHC.Classes.Eq (Rzk.TypeCheck.ModalTope var)
- Rzk.TypeCheck: instance GHC.Classes.Ord Rzk.TypeCheck.Verbosity
- Rzk.TypeCheck: instance GHC.Show.Show Rzk.TypeCheck.ElimCost
- Rzk.TypeCheck: instance GHC.Show.Show Rzk.TypeCheck.HoleEntry
- Rzk.TypeCheck: instance GHC.Show.Show Rzk.TypeCheck.HoleInfo
- Rzk.TypeCheck: instance GHC.Show.Show Rzk.TypeCheck.LocationInfo
- Rzk.TypeCheck: instance Rzk.TypeCheck.ModeTheory Language.Rzk.Free.Syntax.TModality
- Rzk.TypeCheck: isAccessible :: ModalTope var -> Bool
- Rzk.TypeCheck: isCubeOrTopeType :: TermT var -> Bool
- Rzk.TypeCheck: isCubeType :: TermT var -> Bool
- Rzk.TypeCheck: isHoleT :: TermT var -> Bool
- Rzk.TypeCheck: isRA :: ModeTheory m => m -> Bool
- Rzk.TypeCheck: isTopLevelVar :: Eq var => var -> TypeCheck var Bool
- Rzk.TypeCheck: issueTypeError :: TypeError var -> TypeCheck var a
- Rzk.TypeCheck: issueWarning :: String -> TypeCheck var ()
- Rzk.TypeCheck: lambdaT :: TermT var -> Binder -> Maybe (TModality, TermT var, Maybe (Scope TermT var)) -> Scope TermT var -> TermT var
- Rzk.TypeCheck: letModT :: TermT var -> Binder -> TModality -> TModality -> Maybe (TermT var) -> TermT var -> Scope TermT var -> TermT var
- Rzk.TypeCheck: letT :: TermT var -> Binder -> Maybe (TermT var) -> TermT var -> Scope TermT var -> TermT var
- Rzk.TypeCheck: limitLength :: Int -> String -> String
- Rzk.TypeCheck: localDecl :: Decl VarIdent -> TypeCheck VarIdent a -> TypeCheck VarIdent a
- Rzk.TypeCheck: localDeclPrepared :: Decl VarIdent -> TypeCheck VarIdent a -> TypeCheck VarIdent a
- Rzk.TypeCheck: localDecls :: [Decl VarIdent] -> TypeCheck VarIdent a -> TypeCheck VarIdent a
- Rzk.TypeCheck: localDeclsPrepared :: [Decl VarIdent] -> TypeCheck VarIdent a -> TypeCheck VarIdent a
- Rzk.TypeCheck: localHideTerm :: Bool -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: localRenderBackend :: Maybe RenderBackend -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: localTope :: Eq var => TermT var -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: localVerbosity :: Verbosity -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: locksOfVar :: Eq var => var -> TypeCheck var TModality
- Rzk.TypeCheck: lookupVarInfo :: Eq var => var -> Context var -> Maybe (VarInfo var)
- Rzk.TypeCheck: makeAssumptionExplicit :: Eq var => (var, VarInfo var) -> [(var, VarInfo var)] -> TypeCheck var (Bool, [(var, VarInfo var)])
- Rzk.TypeCheck: matrix3Dto4D :: Num a => Matrix3D a -> Matrix4D a
- Rzk.TypeCheck: matrixVectorMult4D :: Num a => Matrix4D a -> Vector4D a -> Vector4D a
- Rzk.TypeCheck: maxEliminationDepth :: Int
- Rzk.TypeCheck: memoWHNF :: TermT var -> TermT var
- Rzk.TypeCheck: memoizeWHNF :: Eq var => TermT var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: modAppT :: TermT var -> TModality -> TermT var -> TermT var
- Rzk.TypeCheck: modExtractT :: TermT var -> TModality -> TModality -> TermT var -> TermT var
- Rzk.TypeCheck: modalityOfVar :: Eq var => var -> TypeCheck var TModality
- Rzk.TypeCheck: namedBlock :: OutputDirection -> String -> [String] -> String
- Rzk.TypeCheck: nfT :: Eq var => TermT var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: nfTope :: Eq var => TermT var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: nubTermT :: Eq a => [a] -> [a]
- Rzk.TypeCheck: pairT :: TermT var -> TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: panicImpossible :: String -> a
- Rzk.TypeCheck: paramToParamDecl :: Param -> TypeCheck var [ParamDecl]
- Rzk.TypeCheck: partitionAccessible :: [ModalTope var] -> ([ModalTope var], [ModalTope var])
- Rzk.TypeCheck: performing :: Eq var => Action var -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: plainTope :: TermT var -> ModalTope var
- Rzk.TypeCheck: point3Dto2D :: Floating a => Camera a -> a -> Point3D a -> (Point2D a, a)
- Rzk.TypeCheck: ppAction :: [(VarIdent, Binder)] -> Int -> Action' -> String
- Rzk.TypeCheck: ppContext' :: OutputDirection -> Context VarIdent -> String
- Rzk.TypeCheck: ppFoldT :: [(VarIdent, Binder)] -> TermT' -> String
- Rzk.TypeCheck: ppFoldU :: [(VarIdent, Binder)] -> Term' -> String
- Rzk.TypeCheck: ppModality :: TModality -> String
- Rzk.TypeCheck: ppSomeAction :: Eq var => [(var, Maybe VarIdent)] -> Int -> Action var -> String
- Rzk.TypeCheck: ppTermInContext :: Eq var => TermT var -> TypeCheck var String
- Rzk.TypeCheck: ppTypeError' :: [(VarIdent, Binder)] -> TypeError' -> String
- Rzk.TypeCheck: ppTypeErrorInContext :: OutputDirection -> TypeErrorInContext VarIdent -> String
- Rzk.TypeCheck: ppTypeErrorInScopedContext' :: OutputDirection -> TypeErrorInScopedContext VarIdent -> String
- Rzk.TypeCheck: ppTypeErrorInScopedContextWith' :: OutputDirection -> [VarIdent] -> [VarIdent] -> TypeErrorInScopedContext VarIdent -> String
- Rzk.TypeCheck: project2D :: Floating a => Camera a -> Matrix4D a
- Rzk.TypeCheck: pruneVacuousFaces :: Eq var => TermT var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: recBottomCandidates :: Eq var => TypeCheck var [TermT var]
- Rzk.TypeCheck: recBottomT :: TermT var
- Rzk.TypeCheck: recOrCandidates :: Eq var => TermT var -> TypeCheck var [TermT var]
- Rzk.TypeCheck: recOrT :: TermT var -> [(TermT var, TermT var)] -> TermT var
- Rzk.TypeCheck: recordHole :: Eq var => Maybe VarIdent -> TermT var -> TypeCheck var ()
- Rzk.TypeCheck: recordHoleShape :: Eq var => Maybe VarIdent -> TermT var -> Maybe (Binder, TermT (Inc var)) -> TypeCheck var ()
- Rzk.TypeCheck: reflT :: TermT var -> Maybe (TermT var, Maybe (TermT var)) -> TermT var
- Rzk.TypeCheck: renderBinderType :: BinderNames var -> TermT var -> Term'
- Rzk.TypeCheck: renderCube :: (Floating a, Show a) => Camera a -> a -> (String -> Maybe RenderObjectData) -> String
- Rzk.TypeCheck: renderForSVG :: Eq var => String -> Int -> TermT var -> TermT var -> TypeCheck var String
- Rzk.TypeCheck: renderForSubShapeSVG :: Eq var => String -> Int -> [var] -> var -> TermT var -> TermT var -> TermT var -> TypeCheck var String
- Rzk.TypeCheck: renderGoalCellSVG :: Eq var => TermT var -> TypeCheck var (Maybe String)
- Rzk.TypeCheck: renderObjectsFor :: Eq var => String -> Int -> TermT var -> TermT var -> TypeCheck var [(ShapeId, RenderObjectData)]
- Rzk.TypeCheck: renderObjectsInSubShapeFor :: Eq var => String -> Int -> [var] -> var -> TermT var -> TermT var -> TermT var -> TypeCheck var [(ShapeId, RenderObjectData)]
- Rzk.TypeCheck: renderTermSVG :: Eq var => TermT var -> TypeCheck var (Maybe String)
- Rzk.TypeCheck: renderTermSVG' :: Eq var => TermT var -> TypeCheck var (Maybe String)
- Rzk.TypeCheck: renderTermSVGFor :: Eq var => String -> Int -> (Maybe (TermT var, TermT var), [var]) -> TermT var -> TypeCheck var (Maybe String)
- Rzk.TypeCheck: rotateX :: Floating a => a -> Matrix3D a
- Rzk.TypeCheck: rotateY :: Floating a => a -> Matrix3D a
- Rzk.TypeCheck: rotateZ :: Floating a => a -> Matrix3D a
- Rzk.TypeCheck: saturateBottom :: Eq var => [ModalTope var] -> [ModalTope var]
- Rzk.TypeCheck: saturateForEntailment :: Eq var => [ModalTope var] -> TypeCheck var [[ModalTope var]]
- Rzk.TypeCheck: saturateInv :: Eq var => [ModalTope var] -> TypeCheck var [ModalTope var]
- Rzk.TypeCheck: saturateTopes :: Eq var => [TermT var] -> [ModalTope var] -> [ModalTope var]
- Rzk.TypeCheck: saturateWith :: (a -> [a] -> Bool) -> ([a] -> [a] -> [a]) -> [a] -> [a]
- Rzk.TypeCheck: scopeNames :: Context var -> [VarIdent]
- Rzk.TypeCheck: scopeToDecls :: Eq var => [TypeErrorInScopedContext var] -> ScopeInfo var -> TypeCheck var ([Decl var], [TypeErrorInScopedContext var])
- Rzk.TypeCheck: secondT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: setOption :: String -> String -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: setVariance :: Covariance -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: simplifyLHS :: Eq var => [ModalTope var] -> [ModalTope var]
- Rzk.TypeCheck: simplifyLHSwithDisjunctions :: Eq var => [ModalTope var] -> [[ModalTope var]]
- Rzk.TypeCheck: solveRHS :: Eq var => [TermT var] -> TermT var -> Bool
- Rzk.TypeCheck: solveRHSM :: Eq var => [ModalTope var] -> TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: splitSectionCommands :: SectionName -> [Command] -> TypeCheck var ([Command], [Command])
- Rzk.TypeCheck: splitViewM :: Eq var => TermT var -> TypeCheck var (Maybe (TermT var))
- Rzk.TypeCheck: splits :: [a] -> [([a], [a])]
- Rzk.TypeCheck: startSection :: Maybe SectionName -> TypeCheck VarIdent a -> TypeCheck VarIdent a
- Rzk.TypeCheck: stripTypeRestrictions :: TermT var -> TermT var
- Rzk.TypeCheck: structuralHoleUnify :: Context var -> Context var
- Rzk.TypeCheck: subPoints :: TermT var -> [TermT var]
- Rzk.TypeCheck: subTopes2 :: Int -> TermT var -> [(ShapeId, TermT var)]
- Rzk.TypeCheck: switchVariance :: TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: topLevelBinderNames :: BinderNames VarIdent
- Rzk.TypeCheck: topeAndT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: topeBottomT :: TermT var
- Rzk.TypeCheck: topeEQT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: topeInvT :: TermT var -> TermT var
- Rzk.TypeCheck: topeLEQT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: topeOrT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: topePoints :: TermT var -> [TermT var]
- Rzk.TypeCheck: topeT :: TermT var
- Rzk.TypeCheck: topeTopT :: TermT var
- Rzk.TypeCheck: topeUninvT :: TermT var -> TermT var
- Rzk.TypeCheck: topesEquiv :: Eq var => TermT var -> TermT var -> TypeCheck var Bool
- Rzk.TypeCheck: trace' :: Verbosity -> Verbosity -> String -> a -> a
- Rzk.TypeCheck: traceAction' :: Int -> Action' -> a -> a
- Rzk.TypeCheck: traceStartAndFinish :: Show a => String -> a -> a
- Rzk.TypeCheck: traceTypeCheck :: Verbosity -> String -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: tryRestriction :: Eq var => TermT var -> TypeCheck var (Maybe (TermT var))
- Rzk.TypeCheck: type Action' = Action VarIdent
- Rzk.TypeCheck: type Decl' = Decl VarIdent
- Rzk.TypeCheck: type Edge3D a = (Point3D a, Point3D a)
- Rzk.TypeCheck: type Face3D a = (Point3D a, Point3D a, Point3D a)
- Rzk.TypeCheck: type Point2D a = (a, a)
- Rzk.TypeCheck: type Point3D a = (a, a, a)
- Rzk.TypeCheck: type PointId = String
- Rzk.TypeCheck: type ShapeId = [PointId]
- Rzk.TypeCheck: type TypeCheck var = ReaderT Context var WriterT [HoleInfo] Except TypeErrorInScopedContext var
- Rzk.TypeCheck: type TypeError' = TypeError VarIdent
- Rzk.TypeCheck: type Volume3D a = (Point3D a, Point3D a, Point3D a, Point3D a)
- Rzk.TypeCheck: typeAscT :: TermT var -> TermT var -> TermT var
- Rzk.TypeCheck: typeFunT :: Binder -> TModality -> TermT var -> Maybe (Scope TermT var) -> Scope TermT var -> TermT var
- Rzk.TypeCheck: typeIdT :: TermT var -> Maybe (TermT var) -> TermT var -> TermT var
- Rzk.TypeCheck: typeModalT :: TermT var -> TModality -> TermT var -> TermT var
- Rzk.TypeCheck: typeOf :: Eq var => TermT var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: typeOfUncomputed :: Eq var => TermT var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: typeOfVar :: Eq var => var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: typeRestrictedT :: TermT var -> [(TermT var, TermT var)] -> TermT var
- Rzk.TypeCheck: typeSigmaT :: Binder -> TModality -> TermT var -> Scope TermT var -> TermT var
- Rzk.TypeCheck: typeUnitT :: TermT var
- Rzk.TypeCheck: typecheck :: Eq var => Term var -> TermT var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: typecheckModule :: Maybe FilePath -> Module -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent])
- Rzk.TypeCheck: typecheckModuleWithLocation :: (FilePath, Module) -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent])
- Rzk.TypeCheck: typecheckModules :: [Module] -> TypeCheck VarIdent [Decl']
- Rzk.TypeCheck: typecheckModulesWithHoles :: [(FilePath, Module)] -> Either (TypeErrorInScopedContext VarIdent) ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent], [HoleInfo])
- Rzk.TypeCheck: typecheckModulesWithHolesAndLemmas :: [VarIdent] -> [(FilePath, Module)] -> Either (TypeErrorInScopedContext VarIdent) ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent], [HoleInfo])
- Rzk.TypeCheck: typecheckModulesWithLocation :: [(FilePath, Module)] -> TypeCheck VarIdent [(FilePath, [Decl'])]
- Rzk.TypeCheck: typecheckModulesWithLocation' :: [(FilePath, Module)] -> TypeCheck VarIdent ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent])
- Rzk.TypeCheck: typecheckModulesWithLocationIncremental :: [(FilePath, [Decl'])] -> [(FilePath, Module)] -> TypeCheck VarIdent ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent])
- Rzk.TypeCheck: underBinder :: Binder -> BinderNames var -> BinderNames (Inc var)
- Rzk.TypeCheck: unify :: Eq var => Maybe (TermT var) -> TermT var -> TermT var -> TypeCheck var ()
- Rzk.TypeCheck: unifyInCurrentContext :: Eq var => Maybe (TermT var) -> TermT var -> TermT var -> TypeCheck var ()
- Rzk.TypeCheck: unifyTerms :: Eq var => TermT var -> TermT var -> TypeCheck var ()
- Rzk.TypeCheck: unifyTopes :: Eq var => TermT var -> TermT var -> TypeCheck var ()
- Rzk.TypeCheck: unifyTypes :: Eq var => TermT var -> TermT var -> TermT var -> TypeCheck var ()
- Rzk.TypeCheck: unifyViaDecompose :: Eq var => TermT var -> TermT var -> TypeCheck var ()
- Rzk.TypeCheck: unitT :: TermT var
- Rzk.TypeCheck: universeT :: TermT var
- Rzk.TypeCheck: unsafeInferStandalone' :: Term' -> TermT'
- Rzk.TypeCheck: unsafeTraceAction' :: Int -> Action var -> a -> a
- Rzk.TypeCheck: unsafeTypeCheck' :: TypeCheck VarIdent a -> a
- Rzk.TypeCheck: unsetOption :: String -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: valueOfVar :: Eq var => var -> TypeCheck var (Maybe (TermT var))
- Rzk.TypeCheck: varBinders :: Context var -> [(var, Binder)]
- Rzk.TypeCheck: varInfos :: Context var -> [(var, VarInfo var)]
- Rzk.TypeCheck: varOrigs :: Context var -> [(var, Maybe VarIdent)]
- Rzk.TypeCheck: varTypes :: Context var -> [(var, TermT var)]
- Rzk.TypeCheck: varValues :: Context var -> [(var, Maybe (TermT var))]
- Rzk.TypeCheck: verticesFrom :: [TermT var] -> [(ShapeId, TermT var)]
- Rzk.TypeCheck: viewRotateX :: Floating a => Camera a -> Matrix4D a
- Rzk.TypeCheck: viewRotateY :: Floating a => Camera a -> Matrix4D a
- Rzk.TypeCheck: viewTranslate :: Num a => Camera a -> Matrix4D a
- Rzk.TypeCheck: whnfT :: Eq var => TermT var -> TypeCheck var (TermT var)
- Rzk.TypeCheck: withCommand :: Command -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent]) -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent])
- Rzk.TypeCheck: withHintLemmas :: [VarIdent] -> Context var -> Context var
- Rzk.TypeCheck: withLocation :: LocationInfo -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: withPartialDecls :: TypeCheck VarIdent ([Decl'], [err]) -> TypeCheck VarIdent ([Decl'], [err]) -> TypeCheck VarIdent ([Decl'], [err])
- Rzk.TypeCheck: withRefreshedTopes :: Eq var => (Context var -> Context var) -> TypeCheck var a -> TypeCheck var a
- Rzk.TypeCheck: withSection :: Maybe SectionName -> TypeCheck VarIdent ([Decl VarIdent], [TypeErrorInScopedContext VarIdent]) -> TypeCheck VarIdent ([Decl VarIdent], [TypeErrorInScopedContext VarIdent]) -> TypeCheck VarIdent ([Decl VarIdent], [TypeErrorInScopedContext VarIdent])
+ Language.Rzk.Foil.Convert: bindings :: forall (n :: S). Pattern -> Term n -> [(VarIdent, Term n)]
+ Language.Rzk.Foil.Convert: collectVarIdents :: Data a => a -> [VarIdent]
+ Language.Rzk.Foil.Convert: nubOrd :: Ord a => [a] -> [a]
+ Language.Rzk.Foil.Convert: toScopedAnon :: forall (n :: S). Distinct n => Scope n -> Env n -> Term -> ScopedAST NameBinder TermSig n
+ Language.Rzk.Foil.Convert: toScopedPattern :: forall (n :: S). Distinct n => Scope n -> Pattern -> Env n -> Term -> ScopedAST NameBinder TermSig n
+ Language.Rzk.Foil.Convert: toTerm :: forall (n :: S). Distinct n => Scope n -> Env n -> Term -> Term n
+ Language.Rzk.Foil.Convert: toTermClosed :: Term -> Term 'VoidS
+ Language.Rzk.Foil.Convert: type Env (n :: S) = VarIdent -> Term n
+ Language.Rzk.Foil.Convert: withOpenTerm :: Term -> (forall (n :: S). Distinct n => Scope n -> NameMap n Display -> Term n -> r) -> r
+ Language.Rzk.Foil.Names: BinderPair :: Binder -> Binder -> Binder
+ Language.Rzk.Foil.Names: BinderUnit :: Binder
+ Language.Rzk.Foil.Names: BinderVar :: Maybe VarIdent -> Binder
+ Language.Rzk.Foil.Names: Flat :: TModality
+ Language.Rzk.Foil.Names: Id :: TModality
+ Language.Rzk.Foil.Names: Op :: TModality
+ Language.Rzk.Foil.Names: PFst :: Proj
+ Language.Rzk.Foil.Names: PSnd :: Proj
+ Language.Rzk.Foil.Names: RzkPosition :: Maybe FilePath -> BNFC'Position -> RzkPosition
+ Language.Rzk.Foil.Names: Sharp :: TModality
+ Language.Rzk.Foil.Names: TypeInfo :: term -> Maybe term -> Maybe term -> TypeInfo term
+ Language.Rzk.Foil.Names: VarIdent :: VarIdent' RzkPosition -> VarIdent
+ Language.Rzk.Foil.Names: [getVarIdent] :: VarIdent -> VarIdent' RzkPosition
+ Language.Rzk.Foil.Names: [infoNF] :: TypeInfo term -> Maybe term
+ Language.Rzk.Foil.Names: [infoType] :: TypeInfo term -> term
+ Language.Rzk.Foil.Names: [infoWHNF] :: TypeInfo term -> Maybe term
+ Language.Rzk.Foil.Names: [rzkFilePath] :: RzkPosition -> Maybe FilePath
+ Language.Rzk.Foil.Names: [rzkLineCol] :: RzkPosition -> BNFC'Position
+ Language.Rzk.Foil.Names: binderDisplayName :: Binder -> VarIdent
+ Language.Rzk.Foil.Names: binderIsCompound :: Binder -> Bool
+ Language.Rzk.Foil.Names: binderLeaves :: Binder -> [VarIdent]
+ Language.Rzk.Foil.Names: binderName :: Binder -> Maybe VarIdent
+ Language.Rzk.Foil.Names: binderPaths :: Binder -> [([Proj], VarIdent)]
+ Language.Rzk.Foil.Names: binderToPattern :: Binder -> Pattern
+ Language.Rzk.Foil.Names: data Binder
+ Language.Rzk.Foil.Names: data Proj
+ Language.Rzk.Foil.Names: data RzkPosition
+ Language.Rzk.Foil.Names: data TModality
+ Language.Rzk.Foil.Names: data TypeInfo term
+ Language.Rzk.Foil.Names: defaultVarIdents :: [VarIdent]
+ Language.Rzk.Foil.Names: desugarTuple :: BNFC'Position -> [Pattern] -> Pattern -> Pattern -> Pattern
+ Language.Rzk.Foil.Names: flattenBinderApp :: Term -> [Term]
+ Language.Rzk.Foil.Names: freshenBinderLeaves :: [VarIdent] -> Binder -> Binder
+ Language.Rzk.Foil.Names: fromMod :: TModality -> Modality
+ Language.Rzk.Foil.Names: fromTModalityToModalColon :: TModality -> ModalColon
+ Language.Rzk.Foil.Names: fromVarIdent :: VarIdent -> VarIdent
+ Language.Rzk.Foil.Names: holeIdentToken :: Maybe VarIdent -> Text
+ Language.Rzk.Foil.Names: holeName :: Text -> Maybe VarIdent
+ Language.Rzk.Foil.Names: incIndex :: Text -> Text
+ Language.Rzk.Foil.Names: incVarIdentIndex :: VarIdent -> VarIdent
+ Language.Rzk.Foil.Names: instance Data.Foldable.Foldable Language.Rzk.Foil.Names.TypeInfo
+ Language.Rzk.Foil.Names: instance Data.String.IsString Language.Rzk.Foil.Names.VarIdent
+ Language.Rzk.Foil.Names: instance Data.Traversable.Traversable Language.Rzk.Foil.Names.TypeInfo
+ Language.Rzk.Foil.Names: instance GHC.Base.Functor Language.Rzk.Foil.Names.TypeInfo
+ Language.Rzk.Foil.Names: instance GHC.Classes.Eq Language.Rzk.Foil.Names.Binder
+ Language.Rzk.Foil.Names: instance GHC.Classes.Eq Language.Rzk.Foil.Names.Proj
+ Language.Rzk.Foil.Names: instance GHC.Classes.Eq Language.Rzk.Foil.Names.TModality
+ Language.Rzk.Foil.Names: instance GHC.Classes.Eq Language.Rzk.Foil.Names.VarIdent
+ Language.Rzk.Foil.Names: instance GHC.Classes.Ord Language.Rzk.Foil.Names.VarIdent
+ Language.Rzk.Foil.Names: instance GHC.Show.Show Language.Rzk.Foil.Names.TModality
+ Language.Rzk.Foil.Names: instance GHC.Show.Show Language.Rzk.Foil.Names.VarIdent
+ Language.Rzk.Foil.Names: markUnresolved :: VarIdent -> VarIdent
+ Language.Rzk.Foil.Names: modCompToMods :: ModComp -> (TModality, TModality)
+ Language.Rzk.Foil.Names: modalColonModality :: ModalColon -> Modality
+ Language.Rzk.Foil.Names: modalColonToTModality :: ModalColon -> TModality
+ Language.Rzk.Foil.Names: modsToModComp :: TModality -> TModality -> ModComp
+ Language.Rzk.Foil.Names: newtype VarIdent
+ Language.Rzk.Foil.Names: patternToTerm :: Pattern -> Term
+ Language.Rzk.Foil.Names: ppRzkPosition :: RzkPosition -> String
+ Language.Rzk.Foil.Names: ppVarIdentWithLocation :: VarIdent -> String
+ Language.Rzk.Foil.Names: refreshVar :: [VarIdent] -> VarIdent -> VarIdent
+ Language.Rzk.Foil.Names: refreshVarIn :: Set VarIdent -> VarIdent -> VarIdent
+ Language.Rzk.Foil.Names: sigmaParamToTypeSigma :: BNFC'Position -> SigmaParam -> Term -> Term
+ Language.Rzk.Foil.Names: toBinder :: Pattern -> Binder
+ Language.Rzk.Foil.Names: toModality :: Modality -> TModality
+ Language.Rzk.Foil.Names: type Display = (VarIdent, Binder)
+ Language.Rzk.Foil.Names: unmarkUnresolved :: VarIdent -> Maybe VarIdent
+ Language.Rzk.Foil.Names: unsafeTermToPattern :: Term -> Pattern
+ Language.Rzk.Foil.Names: varIdent :: VarIdent -> VarIdent
+ Language.Rzk.Foil.Names: varIdentAt :: Maybe FilePath -> VarIdent -> VarIdent
+ Language.Rzk.Foil.Print: fromTerm :: forall (n :: S). [VarIdent] -> [VarIdent] -> NameMap n Display -> Term n -> Term
+ Language.Rzk.Foil.Print: fromTermClosed :: Term 'VoidS -> Term
+ Language.Rzk.Foil.Print: nameIdsOf :: forall (l :: S). Term l -> [Int]
+ Language.Rzk.Foil.Print: scopeUsesItsBinder :: forall (n :: S). ScopedAST NameBinder TermSig n -> Bool
+ Language.Rzk.Foil.Syntax: AppF :: term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: Cube2F :: TermSig scope term
+ Language.Rzk.Foil.Syntax: Cube2_0F :: TermSig scope term
+ Language.Rzk.Foil.Syntax: Cube2_1F :: TermSig scope term
+ Language.Rzk.Foil.Syntax: CubeFlipF :: term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: CubeIF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: CubeI_0F :: TermSig scope term
+ Language.Rzk.Foil.Syntax: CubeI_1F :: TermSig scope term
+ Language.Rzk.Foil.Syntax: CubeProductF :: term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: CubeUnflipF :: term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: CubeUnitF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: CubeUnitStarF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: FirstF :: term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: HoleF :: Maybe VarIdent -> TermSig scope term
+ Language.Rzk.Foil.Syntax: IdJF :: term -> term -> term -> term -> term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: LambdaF :: Binder -> Maybe (LambdaParam scope term) -> scope -> TermSig scope term
+ Language.Rzk.Foil.Syntax: LambdaParam :: TModality -> term -> Maybe scope -> LambdaParam scope term
+ Language.Rzk.Foil.Syntax: LetF :: Binder -> Maybe term -> term -> scope -> TermSig scope term
+ Language.Rzk.Foil.Syntax: LetModF :: Binder -> TModality -> TModality -> Maybe term -> term -> scope -> TermSig scope term
+ Language.Rzk.Foil.Syntax: ModAppF :: TModality -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: ModExtractF :: TModality -> TModality -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: PairF :: term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: RecBottomF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: RecOrF :: [(term, term)] -> TermSig scope term
+ Language.Rzk.Foil.Syntax: ReflF :: Maybe (term, Maybe term) -> TermSig scope term
+ Language.Rzk.Foil.Syntax: SecondF :: term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TopeAndF :: term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TopeBottomF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: TopeEQF :: term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TopeInvF :: term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TopeLEQF :: term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TopeOrF :: term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TopeTopF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: TopeUninvF :: term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TypeAscF :: term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TypeFunF :: Binder -> TModality -> term -> Maybe scope -> scope -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TypeIdF :: term -> Maybe term -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TypeModalF :: TModality -> term -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TypeRestrictedF :: term -> [(term, term)] -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TypeSigmaF :: Binder -> TModality -> term -> scope -> TermSig scope term
+ Language.Rzk.Foil.Syntax: TypeUnitF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: UnitF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: UniverseCubeF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: UniverseF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: UniverseTopeF :: TermSig scope term
+ Language.Rzk.Foil.Syntax: abstractName :: forall (n :: S) r. Distinct n => Scope n -> Name n -> TermT n -> (forall (l :: S). DExt n l => NameBinder n l -> TermT l -> r) -> r
+ Language.Rzk.Foil.Syntax: alphaEqT :: forall (n :: S). Distinct n => Scope n -> TermT n -> TermT n -> Bool
+ Language.Rzk.Foil.Syntax: appT :: forall (n :: S). TermT n -> TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: containsHole :: forall (n :: S). TermT n -> Bool
+ Language.Rzk.Foil.Syntax: cube2T :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: cube2_0T :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: cube2_1T :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: cubeFlipT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: cubeIT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: cubeI_0T :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: cubeI_1T :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: cubeProductT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: cubeT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: cubeUnflipT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: cubeUnitStarT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: cubeUnitT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: data LambdaParam scope term
+ Language.Rzk.Foil.Syntax: data TermSig scope term
+ Language.Rzk.Foil.Syntax: elemT :: forall (n :: S). Distinct n => TermT n -> [TermT n] -> Bool
+ Language.Rzk.Foil.Syntax: eqT :: forall (n :: S). Distinct n => TermT n -> TermT n -> Bool
+ Language.Rzk.Foil.Syntax: firstT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: freeVarsOfTerm :: forall (n :: S). Term n -> [Name n]
+ Language.Rzk.Foil.Syntax: freeVarsOfTermT :: forall (n :: S). TermT n -> [Name n]
+ Language.Rzk.Foil.Syntax: holeNamesOf :: forall (n :: S). Term n -> [Maybe VarIdent]
+ Language.Rzk.Foil.Syntax: holeT :: forall (n :: S). TermT n -> Maybe VarIdent -> TermT n
+ Language.Rzk.Foil.Syntax: idJT :: forall (n :: S). TermT n -> TermT n -> TermT n -> TermT n -> TermT n -> TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: instance (GHC.Classes.Eq term, GHC.Classes.Eq scope) => GHC.Classes.Eq (Language.Rzk.Foil.Syntax.LambdaParam scope term)
+ Language.Rzk.Foil.Syntax: instance (GHC.Classes.Eq term, GHC.Classes.Eq scope) => GHC.Classes.Eq (Language.Rzk.Foil.Syntax.TermSig scope term)
+ Language.Rzk.Foil.Syntax: instance Data.Bifoldable.Bifoldable Language.Rzk.Foil.Syntax.LambdaParam
+ Language.Rzk.Foil.Syntax: instance Data.Bifoldable.Bifoldable Language.Rzk.Foil.Syntax.TermSig
+ Language.Rzk.Foil.Syntax: instance Data.Bifunctor.Bifunctor Language.Rzk.Foil.Syntax.LambdaParam
+ Language.Rzk.Foil.Syntax: instance Data.Bifunctor.Bifunctor Language.Rzk.Foil.Syntax.TermSig
+ Language.Rzk.Foil.Syntax: instance Data.Bitraversable.Bitraversable Language.Rzk.Foil.Syntax.LambdaParam
+ Language.Rzk.Foil.Syntax: instance Data.Bitraversable.Bitraversable Language.Rzk.Foil.Syntax.TermSig
+ Language.Rzk.Foil.Syntax: instance Data.Foldable.Foldable (Language.Rzk.Foil.Syntax.LambdaParam scope)
+ Language.Rzk.Foil.Syntax: instance Data.Foldable.Foldable (Language.Rzk.Foil.Syntax.TermSig scope)
+ Language.Rzk.Foil.Syntax: instance Data.Traversable.Traversable (Language.Rzk.Foil.Syntax.LambdaParam scope)
+ Language.Rzk.Foil.Syntax: instance Data.Traversable.Traversable (Language.Rzk.Foil.Syntax.TermSig scope)
+ Language.Rzk.Foil.Syntax: instance Data.ZipMatchK.Generic.ZipMatchK (GHC.Maybe.Maybe Language.Rzk.Foil.Names.VarIdent)
+ Language.Rzk.Foil.Syntax: instance Data.ZipMatchK.Generic.ZipMatchK Language.Rzk.Foil.Names.Binder
+ Language.Rzk.Foil.Syntax: instance Data.ZipMatchK.Generic.ZipMatchK Language.Rzk.Foil.Names.TModality
+ Language.Rzk.Foil.Syntax: instance Data.ZipMatchK.Generic.ZipMatchK Language.Rzk.Foil.Names.TypeInfo
+ Language.Rzk.Foil.Syntax: instance Data.ZipMatchK.Generic.ZipMatchK Language.Rzk.Foil.Names.VarIdent
+ Language.Rzk.Foil.Syntax: instance Data.ZipMatchK.Generic.ZipMatchK Language.Rzk.Foil.Syntax.LambdaParam
+ Language.Rzk.Foil.Syntax: instance Data.ZipMatchK.Generic.ZipMatchK Language.Rzk.Foil.Syntax.TermSig
+ Language.Rzk.Foil.Syntax: instance GHC.Base.Functor (Language.Rzk.Foil.Syntax.LambdaParam scope)
+ Language.Rzk.Foil.Syntax: instance GHC.Base.Functor (Language.Rzk.Foil.Syntax.TermSig scope)
+ Language.Rzk.Foil.Syntax: instance GHC.Generics.Generic (Language.Rzk.Foil.Syntax.LambdaParam scope term)
+ Language.Rzk.Foil.Syntax: instance GHC.Generics.Generic (Language.Rzk.Foil.Syntax.TermSig scope term)
+ Language.Rzk.Foil.Syntax: instance Generics.Kind.GenericK (Language.Rzk.Foil.Syntax.LambdaParam scope term)
+ Language.Rzk.Foil.Syntax: instance Generics.Kind.GenericK (Language.Rzk.Foil.Syntax.LambdaParam scope)
+ Language.Rzk.Foil.Syntax: instance Generics.Kind.GenericK (Language.Rzk.Foil.Syntax.TermSig scope term)
+ Language.Rzk.Foil.Syntax: instance Generics.Kind.GenericK (Language.Rzk.Foil.Syntax.TermSig scope)
+ Language.Rzk.Foil.Syntax: instance Generics.Kind.GenericK Language.Rzk.Foil.Syntax.LambdaParam
+ Language.Rzk.Foil.Syntax: instance Generics.Kind.GenericK Language.Rzk.Foil.Syntax.TermSig
+ Language.Rzk.Foil.Syntax: instantiateT :: forall (n :: S). Distinct n => Scope n -> ScopedTermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: instantiateUntyped :: forall (n :: S). Distinct n => Scope n -> ScopedTerm n -> Term n -> Term n
+ Language.Rzk.Foil.Syntax: isHoleT :: forall (n :: S). TermT n -> Bool
+ Language.Rzk.Foil.Syntax: lambdaT :: forall (n :: S). TermT n -> Binder -> Maybe (LambdaParam (ScopedTermT n) (TermT n)) -> ScopedTermT n -> TermT n
+ Language.Rzk.Foil.Syntax: letModT :: forall (n :: S). TermT n -> Binder -> TModality -> TModality -> Maybe (TermT n) -> TermT n -> ScopedTermT n -> TermT n
+ Language.Rzk.Foil.Syntax: letT :: forall (n :: S). TermT n -> Binder -> Maybe (TermT n) -> TermT n -> ScopedTermT n -> TermT n
+ Language.Rzk.Foil.Syntax: modAppT :: forall (n :: S). TermT n -> TModality -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: modExtractT :: forall (n :: S). TermT n -> TModality -> TModality -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: notElemT :: forall (n :: S). Distinct n => TermT n -> [TermT n] -> Bool
+ Language.Rzk.Foil.Syntax: nubT :: forall (n :: S). Distinct n => [TermT n] -> [TermT n]
+ Language.Rzk.Foil.Syntax: openWith :: forall (sig :: Type -> Type -> Type) (n :: S) (l :: S). (Bifunctor sig, DExt n l) => Scope l -> Name l -> ScopedAST NameBinder sig n -> AST NameBinder sig l
+ Language.Rzk.Foil.Syntax: pairT :: forall (n :: S). TermT n -> TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: pattern App :: AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern AppT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Cube2 :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern Cube2T :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Cube2_0 :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern Cube2_0T :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Cube2_1 :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern Cube2_1T :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern CubeFlip :: AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern CubeFlipT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern CubeI :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern CubeIT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern CubeI_0 :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern CubeI_0T :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern CubeI_1 :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern CubeI_1T :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern CubeProduct :: AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern CubeProductT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern CubeUnflip :: AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern CubeUnflipT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern CubeUnit :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern CubeUnitStar :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern CubeUnitStarT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern CubeUnitT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern First :: AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern FirstT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Hole :: Maybe VarIdent -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern HoleT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> Maybe VarIdent -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern IdJ :: AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern IdJT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Lambda :: Binder -> Maybe (LambdaParam (ScopedAST binder TermSig n) (AST binder TermSig n)) -> ScopedAST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern LambdaT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> Binder -> Maybe (LambdaParam (ScopedAST binder (AnnSig ann TermSig) n) (AST binder (AnnSig ann TermSig) n)) -> ScopedAST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Let :: Binder -> Maybe (AST binder TermSig n) -> AST binder TermSig n -> ScopedAST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern LetMod :: Binder -> TModality -> TModality -> Maybe (AST binder TermSig n) -> AST binder TermSig n -> ScopedAST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern LetModT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> Binder -> TModality -> TModality -> Maybe (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> ScopedAST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern LetT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> Binder -> Maybe (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> ScopedAST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern ModApp :: TModality -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern ModAppT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> TModality -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern ModExtract :: TModality -> TModality -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern ModExtractT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> TModality -> TModality -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Pair :: AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern PairT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern RecBottom :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern RecBottomT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern RecOr :: [(AST binder TermSig n, AST binder TermSig n)] -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern RecOrT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> [(AST binder (AnnSig ann TermSig) n, AST binder (AnnSig ann TermSig) n)] -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Refl :: Maybe (AST binder TermSig n, Maybe (AST binder TermSig n)) -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern ReflT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> Maybe (AST binder (AnnSig ann TermSig) n, Maybe (AST binder (AnnSig ann TermSig) n)) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Second :: AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern SecondT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TopeAnd :: AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TopeAndT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TopeBottom :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TopeBottomT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TopeEQ :: AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TopeEQT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TopeInv :: AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TopeInvT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TopeLEQ :: AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TopeLEQT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TopeOr :: AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TopeOrT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TopeTop :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TopeTopT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TopeUninv :: AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TopeUninvT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TypeAsc :: AST binder TermSig n -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TypeAscT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TypeFun :: Binder -> TModality -> AST binder TermSig n -> Maybe (ScopedAST binder TermSig n) -> ScopedAST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TypeFunT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> Binder -> TModality -> AST binder (AnnSig ann TermSig) n -> Maybe (ScopedAST binder (AnnSig ann TermSig) n) -> ScopedAST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TypeId :: AST binder TermSig n -> Maybe (AST binder TermSig n) -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TypeIdT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> Maybe (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TypeModal :: TModality -> AST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TypeModalT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> TModality -> AST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TypeRestricted :: AST binder TermSig n -> [(AST binder TermSig n, AST binder TermSig n)] -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TypeRestrictedT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n -> [(AST binder (AnnSig ann TermSig) n, AST binder (AnnSig ann TermSig) n)] -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TypeSigma :: Binder -> TModality -> AST binder TermSig n -> ScopedAST binder TermSig n -> AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TypeSigmaT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> Binder -> TModality -> AST binder (AnnSig ann TermSig) n -> ScopedAST binder (AnnSig ann TermSig) n -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern TypeUnit :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern TypeUnitT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Unit :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern UnitT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern Universe :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern UniverseCube :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern UniverseCubeT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern UniverseT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: pattern UniverseTope :: AST binder TermSig n
+ Language.Rzk.Foil.Syntax: pattern UniverseTopeT :: forall {binder} {ann} {n}. ann (AST binder (AnnSig ann TermSig) n) -> AST binder (AnnSig ann TermSig) n
+ Language.Rzk.Foil.Syntax: recBottomT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: recOrT :: forall (n :: S). TermT n -> [(TermT n, TermT n)] -> TermT n
+ Language.Rzk.Foil.Syntax: reflT :: forall (n :: S). TermT n -> Maybe (TermT n, Maybe (TermT n)) -> TermT n
+ Language.Rzk.Foil.Syntax: secondT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: substituteName :: forall (n :: S). Distinct n => Scope n -> Name n -> TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: substituteT :: forall (o :: S) (i :: S). Distinct o => Scope o -> Substitution TermT i o -> TermT i -> TermT o
+ Language.Rzk.Foil.Syntax: termIsNF :: forall (n :: S). TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: termIsWHNF :: forall (n :: S). TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: topeAndT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: topeBottomT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: topeEQT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: topeInfo :: forall (n :: S). TermT n -> TypeInfo (TermT n)
+ Language.Rzk.Foil.Syntax: topeInvT :: forall (n :: S). TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: topeLEQT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: topeOrT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: topeT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: topeTopT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: topeUninvT :: forall (n :: S). TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: type ScopedTerm = ScopedAST NameBinder TermSig
+ Language.Rzk.Foil.Syntax: type ScopedTermT = ScopedAST NameBinder AnnSig TypeInfo TermSig
+ Language.Rzk.Foil.Syntax: type Term = AST NameBinder TermSig
+ Language.Rzk.Foil.Syntax: type TermT = AST NameBinder AnnSig TypeInfo TermSig
+ Language.Rzk.Foil.Syntax: typeAscT :: forall (n :: S). TermT n -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: typeFunT :: forall (n :: S). Binder -> TModality -> TermT n -> Maybe (ScopedTermT n) -> ScopedTermT n -> TermT n
+ Language.Rzk.Foil.Syntax: typeIdT :: forall (n :: S). TermT n -> Maybe (TermT n) -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: typeInfoOf :: forall (n :: S). TermT n -> Maybe (TypeInfo (TermT n))
+ Language.Rzk.Foil.Syntax: typeModalT :: forall (n :: S). TermT n -> TModality -> TermT n -> TermT n
+ Language.Rzk.Foil.Syntax: typeRestrictedT :: forall (n :: S). TermT n -> [(TermT n, TermT n)] -> TermT n
+ Language.Rzk.Foil.Syntax: typeSigmaT :: forall (n :: S). Binder -> TModality -> TermT n -> ScopedTermT n -> TermT n
+ Language.Rzk.Foil.Syntax: typeUnitT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: unitT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: universeT :: forall (n :: S). TermT n
+ Language.Rzk.Foil.Syntax: untyped :: forall (n :: S). TermT n -> Term n
+ Language.Rzk.Foil.Syntax: valueInfo :: forall (n :: S). TermT n -> TermT n -> TypeInfo (TermT n)
+ Language.Rzk.Foil.Syntax: withScopedT :: forall (sig :: Type -> Type -> Type) (n :: S) r. (Bifunctor sig, Distinct n) => Scope n -> ScopedAST NameBinder sig n -> (forall (l :: S). DExt n l => NameBinder n l -> AST NameBinder sig l -> r) -> r
+ Language.Rzk.Foil.Syntax: withScopedT2 :: forall (n :: S) r. Distinct n => Scope n -> ScopedTermT n -> ScopedTermT n -> (forall (l :: S). DExt n l => NameBinder n l -> TermT l -> TermT l -> r) -> r
+ Language.Rzk.VSCode.Env: [cachedModuleChecked] :: RzkCachedModule -> Checked
+ Rzk.Render.Geometry: Camera :: Point3D a -> a -> a -> a -> a -> Camera a
+ Rzk.Render.Geometry: CubeCoords2D :: [(Point3D a, Point2D b)] -> [(Edge3D a, (Point2D b, Point2D b))] -> [(Face3D a, (Point2D b, Point2D b, Point2D b))] -> [(Volume3D a, (Point2D b, Point2D b, Point2D b, Point2D b))] -> CubeCoords2D a b
+ Rzk.Render.Geometry: Matrix3D :: a -> a -> a -> a -> a -> a -> a -> a -> a -> Matrix3D a
+ Rzk.Render.Geometry: Matrix4D :: a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> a -> Matrix4D a
+ Rzk.Render.Geometry: RenderObjectData :: String -> String -> String -> RenderObjectData
+ Rzk.Render.Geometry: Vector3D :: a -> a -> a -> Vector3D a
+ Rzk.Render.Geometry: Vector4D :: a -> a -> a -> a -> Vector4D a
+ Rzk.Render.Geometry: [cameraAngleX] :: Camera a -> a
+ Rzk.Render.Geometry: [cameraAngleY] :: Camera a -> a
+ Rzk.Render.Geometry: [cameraAspectRatio] :: Camera a -> a
+ Rzk.Render.Geometry: [cameraFoV] :: Camera a -> a
+ Rzk.Render.Geometry: [cameraPos] :: Camera a -> Point3D a
+ Rzk.Render.Geometry: [edges] :: CubeCoords2D a b -> [(Edge3D a, (Point2D b, Point2D b))]
+ Rzk.Render.Geometry: [faces] :: CubeCoords2D a b -> [(Face3D a, (Point2D b, Point2D b, Point2D b))]
+ Rzk.Render.Geometry: [renderObjectDataColor] :: RenderObjectData -> String
+ Rzk.Render.Geometry: [renderObjectDataFullLabel] :: RenderObjectData -> String
+ Rzk.Render.Geometry: [renderObjectDataLabel] :: RenderObjectData -> String
+ Rzk.Render.Geometry: [vertices] :: CubeCoords2D a b -> [(Point3D a, Point2D b)]
+ Rzk.Render.Geometry: [volumes] :: CubeCoords2D a b -> [(Volume3D a, (Point2D b, Point2D b, Point2D b, Point2D b))]
+ Rzk.Render.Geometry: data Camera a
+ Rzk.Render.Geometry: data CubeCoords2D a b
+ Rzk.Render.Geometry: data Matrix3D a
+ Rzk.Render.Geometry: data Matrix4D a
+ Rzk.Render.Geometry: data RenderObjectData
+ Rzk.Render.Geometry: data Vector3D a
+ Rzk.Render.Geometry: data Vector4D a
+ Rzk.Render.Geometry: defaultCamera :: Floating a => Camera a
+ Rzk.Render.Geometry: fromAffine :: Fractional a => Vector4D a -> (Point2D a, a)
+ Rzk.Render.Geometry: hideTermData :: Bool -> String -> RenderObjectData -> RenderObjectData
+ Rzk.Render.Geometry: limitLength :: Int -> String -> String
+ Rzk.Render.Geometry: matrix3Dto4D :: Num a => Matrix3D a -> Matrix4D a
+ Rzk.Render.Geometry: matrixVectorMult4D :: Num a => Matrix4D a -> Vector4D a -> Vector4D a
+ Rzk.Render.Geometry: point3Dto2D :: Floating a => Camera a -> a -> Point3D a -> (Point2D a, a)
+ Rzk.Render.Geometry: project2D :: Floating a => Camera a -> Matrix4D a
+ Rzk.Render.Geometry: renderCube :: (Floating a, Show a) => Camera a -> a -> (String -> Maybe RenderObjectData) -> String
+ Rzk.Render.Geometry: rotateX :: Floating a => a -> Matrix3D a
+ Rzk.Render.Geometry: rotateY :: Floating a => a -> Matrix3D a
+ Rzk.Render.Geometry: rotateZ :: Floating a => a -> Matrix3D a
+ Rzk.Render.Geometry: type Edge3D a = (Point3D a, Point3D a)
+ Rzk.Render.Geometry: type Face3D a = (Point3D a, Point3D a, Point3D a)
+ Rzk.Render.Geometry: type Point2D a = (a, a)
+ Rzk.Render.Geometry: type Point3D a = (a, a, a)
+ Rzk.Render.Geometry: type PointId = String
+ Rzk.Render.Geometry: type ShapeId = [PointId]
+ Rzk.Render.Geometry: type Volume3D a = (Point3D a, Point3D a, Point3D a, Point3D a)
+ Rzk.Render.Geometry: viewRotateX :: Floating a => Camera a -> Matrix4D a
+ Rzk.Render.Geometry: viewRotateY :: Floating a => Camera a -> Matrix4D a
+ Rzk.Render.Geometry: viewTranslate :: Num a => Camera a -> Matrix4D a
+ Rzk.TypeCheck.BinderTypes: ShapeView :: Rendered -> Rendered -> BinderTypeView
+ Rzk.TypeCheck.BinderTypes: TypeView :: Rendered -> BinderTypeView
+ Rzk.TypeCheck.BinderTypes: binderTypeEntries :: forall (n :: S). Distinct n => Binder -> TermT n -> TypeCheck n [(VarIdent, BinderTypeView)]
+ Rzk.TypeCheck.BinderTypes: binderTypesOfFile :: Checked -> FilePath -> [(VarIdent, BinderTypeView)]
+ Rzk.TypeCheck.BinderTypes: binderTypesOfTerm :: forall (n :: S). Distinct n => TermT n -> TypeCheck n [(VarIdent, BinderTypeView)]
+ Rzk.TypeCheck.BinderTypes: data BinderTypeView
+ Rzk.TypeCheck.BinderTypes: declBinderTypes :: forall (n :: S). Distinct n => Decl n -> TypeCheck n [(VarIdent, BinderTypeView)]
+ Rzk.TypeCheck.BinderTypes: instance GHC.Classes.Eq Rzk.TypeCheck.BinderTypes.BinderTypeView
+ Rzk.TypeCheck.BinderTypes: instance GHC.Show.Show Rzk.TypeCheck.BinderTypes.BinderTypeView
+ Rzk.TypeCheck.BinderTypes: memoWHNF :: forall (n :: S). TermT n -> TermT n
+ Rzk.TypeCheck.BinderTypes: renderHere :: forall (n :: S). TermT n -> TypeCheck n Rendered
+ Rzk.TypeCheck.BinderTypes: splitViewM :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (Maybe (TermT n))
+ Rzk.TypeCheck.Context: ActionCheckCoherence :: (TermT n, TermT n) -> (TermT n, TermT n) -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionCheckLetValue :: Maybe VarIdent -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionCloseSection :: Maybe SectionName -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionContextEntailedBy :: [TermT n] -> TermT n -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionContextEntails :: [TermT n] -> TermT n -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionContextEntailsUnion :: [TermT n] -> [TermT n] -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionInfer :: Term n -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionNF :: TermT n -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionTypeCheck :: Term n -> TermT n -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionUnify :: TermT n -> TermT n -> TermT n -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionUnifyTerms :: TermT n -> TermT n -> Action (n :: S)
+ Rzk.TypeCheck.Context: ActionWHNF :: TermT n -> Action (n :: S)
+ Rzk.TypeCheck.Context: Context :: Scope n -> NameMap n (VarInfo n) -> Map VarIdent (Name n) -> [Name n] -> [SectionInfo n] -> [ModalTope n] -> [ModalTope n] -> [ModalTope n] -> [[ModalTope n]] -> Maybe Bool -> CachedSaturation n -> Map VarIdent [VarIdent] -> [Action n] -> Int -> Maybe Command -> Maybe LocationInfo -> Verbosity -> Covariance -> Maybe RenderBackend -> Bool -> Bool -> Bool -> [VarIdent] -> Bool -> Context (n :: S)
+ Rzk.TypeCheck.Context: Contravariant :: Covariance
+ Rzk.TypeCheck.Context: Covariant :: Covariance
+ Rzk.TypeCheck.Context: Debug :: Verbosity
+ Rzk.TypeCheck.Context: Invariant :: Covariance
+ Rzk.TypeCheck.Context: LocationInfo :: Maybe FilePath -> Maybe Int -> LocationInfo
+ Rzk.TypeCheck.Context: ModalTope :: TModality -> TModality -> TermT n -> ModalTope (n :: S)
+ Rzk.TypeCheck.Context: Normal :: Verbosity
+ Rzk.TypeCheck.Context: RenderLaTeX :: RenderBackend
+ Rzk.TypeCheck.Context: RenderSVG :: RenderBackend
+ Rzk.TypeCheck.Context: SaturationCached :: Maybe [[ModalTope n]] -> CachedSaturation (n :: S)
+ Rzk.TypeCheck.Context: SaturationUncached :: CachedSaturation (n :: S)
+ Rzk.TypeCheck.Context: SectionInfo :: Maybe SectionName -> [Name n] -> SectionInfo (n :: S)
+ Rzk.TypeCheck.Context: Silent :: Verbosity
+ Rzk.TypeCheck.Context: VarInfo :: TermT n -> Maybe (TermT n) -> TModality -> TModality -> Binder -> Bool -> Bool -> [Name n] -> Maybe LocationInfo -> VarInfo (n :: S)
+ Rzk.TypeCheck.Context: [ctxActionStackDepth] :: Context (n :: S) -> Int
+ Rzk.TypeCheck.Context: [ctxActionStack] :: Context (n :: S) -> [Action n]
+ Rzk.TypeCheck.Context: [ctxBound] :: Context (n :: S) -> [Name n]
+ Rzk.TypeCheck.Context: [ctxCovariance] :: Context (n :: S) -> Covariance
+ Rzk.TypeCheck.Context: [ctxCurrentCommand] :: Context (n :: S) -> Maybe Command
+ Rzk.TypeCheck.Context: [ctxDeferHoleMismatches] :: Context (n :: S) -> Bool
+ Rzk.TypeCheck.Context: [ctxDiscreteTopes] :: Context (n :: S) -> [ModalTope n]
+ Rzk.TypeCheck.Context: [ctxHintLemmas] :: Context (n :: S) -> [VarIdent]
+ Rzk.TypeCheck.Context: [ctxHolesAreErrors] :: Context (n :: S) -> Bool
+ Rzk.TypeCheck.Context: [ctxLocation] :: Context (n :: S) -> Maybe LocationInfo
+ Rzk.TypeCheck.Context: [ctxNamed] :: Context (n :: S) -> Map VarIdent (Name n)
+ Rzk.TypeCheck.Context: [ctxRenderBackend] :: Context (n :: S) -> Maybe RenderBackend
+ Rzk.TypeCheck.Context: [ctxRenderHideTerm] :: Context (n :: S) -> Bool
+ Rzk.TypeCheck.Context: [ctxScope] :: Context (n :: S) -> Scope n
+ Rzk.TypeCheck.Context: [ctxSections] :: Context (n :: S) -> [SectionInfo n]
+ Rzk.TypeCheck.Context: [ctxShadow] :: Context (n :: S) -> Map VarIdent [VarIdent]
+ Rzk.TypeCheck.Context: [ctxTopesEntailBottom] :: Context (n :: S) -> Maybe Bool
+ Rzk.TypeCheck.Context: [ctxTopesNFUnion] :: Context (n :: S) -> [[ModalTope n]]
+ Rzk.TypeCheck.Context: [ctxTopesNF] :: Context (n :: S) -> [ModalTope n]
+ Rzk.TypeCheck.Context: [ctxTopesSaturated] :: Context (n :: S) -> CachedSaturation n
+ Rzk.TypeCheck.Context: [ctxTopes] :: Context (n :: S) -> [ModalTope n]
+ Rzk.TypeCheck.Context: [ctxVars] :: Context (n :: S) -> NameMap n (VarInfo n)
+ Rzk.TypeCheck.Context: [ctxVerbosity] :: Context (n :: S) -> Verbosity
+ Rzk.TypeCheck.Context: [ctxWarnOverhang] :: Context (n :: S) -> Bool
+ Rzk.TypeCheck.Context: [locationFilePath] :: LocationInfo -> Maybe FilePath
+ Rzk.TypeCheck.Context: [locationLine] :: LocationInfo -> Maybe Int
+ Rzk.TypeCheck.Context: [sectionEntries] :: SectionInfo (n :: S) -> [Name n]
+ Rzk.TypeCheck.Context: [sectionName] :: SectionInfo (n :: S) -> Maybe SectionName
+ Rzk.TypeCheck.Context: [tModAccum] :: ModalTope (n :: S) -> TModality
+ Rzk.TypeCheck.Context: [tModVar] :: ModalTope (n :: S) -> TModality
+ Rzk.TypeCheck.Context: [tTope] :: ModalTope (n :: S) -> TermT n
+ Rzk.TypeCheck.Context: [varDeclaredAssumptions] :: VarInfo (n :: S) -> [Name n]
+ Rzk.TypeCheck.Context: [varIsAssumption] :: VarInfo (n :: S) -> Bool
+ Rzk.TypeCheck.Context: [varIsTopLevel] :: VarInfo (n :: S) -> Bool
+ Rzk.TypeCheck.Context: [varLocation] :: VarInfo (n :: S) -> Maybe LocationInfo
+ Rzk.TypeCheck.Context: [varModAccum] :: VarInfo (n :: S) -> TModality
+ Rzk.TypeCheck.Context: [varModality] :: VarInfo (n :: S) -> TModality
+ Rzk.TypeCheck.Context: [varOrig] :: VarInfo (n :: S) -> Binder
+ Rzk.TypeCheck.Context: [varType] :: VarInfo (n :: S) -> TermT n
+ Rzk.TypeCheck.Context: [varValue] :: VarInfo (n :: S) -> Maybe (TermT n)
+ Rzk.TypeCheck.Context: accessibleTopes :: forall (n :: S). [ModalTope n] -> [TermT n]
+ Rzk.TypeCheck.Context: addBinderNames :: Binder -> Map VarIdent [VarIdent] -> Map VarIdent [VarIdent]
+ Rzk.TypeCheck.Context: allowHoles :: forall (n :: S). Context n -> Context n
+ Rzk.TypeCheck.Context: applyModality :: forall (n :: S). TModality -> Context n -> Context n
+ Rzk.TypeCheck.Context: availableTopes :: forall (n :: S). Context n -> [TermT n]
+ Rzk.TypeCheck.Context: availableTopesNF :: forall (n :: S). Context n -> [TermT n]
+ Rzk.TypeCheck.Context: binderOfName :: forall (n :: S). Name n -> Context n -> Binder
+ Rzk.TypeCheck.Context: class ModeTheory m
+ Rzk.TypeCheck.Context: coe :: ModeTheory m => m -> m -> Bool
+ Rzk.TypeCheck.Context: comp :: ModeTheory m => m -> m -> m
+ Rzk.TypeCheck.Context: data Action (n :: S)
+ Rzk.TypeCheck.Context: data CachedSaturation (n :: S)
+ Rzk.TypeCheck.Context: data Context (n :: S)
+ Rzk.TypeCheck.Context: data Covariance
+ Rzk.TypeCheck.Context: data LocationInfo
+ Rzk.TypeCheck.Context: data ModalTope (n :: S)
+ Rzk.TypeCheck.Context: data RenderBackend
+ Rzk.TypeCheck.Context: data SectionInfo (n :: S)
+ Rzk.TypeCheck.Context: data VarInfo (n :: S)
+ Rzk.TypeCheck.Context: data Verbosity
+ Rzk.TypeCheck.Context: emptyContext :: Context 'VoidS
+ Rzk.TypeCheck.Context: emptyTopeContext :: forall (n :: S). [ModalTope n]
+ Rzk.TypeCheck.Context: enterBinder :: forall (n :: S) (l :: S). DExt n l => NameBinder n l -> VarInfo n -> [ModalTope l] -> Context n -> Context l
+ Rzk.TypeCheck.Context: filterAccessible :: forall (n :: S). [ModalTope n] -> [ModalTope n]
+ Rzk.TypeCheck.Context: iden :: ModeTheory m => m
+ Rzk.TypeCheck.Context: insertVarInfo :: forall (n :: S). Name n -> VarInfo n -> Context n -> Context n
+ Rzk.TypeCheck.Context: instance Control.Monad.Foil.Internal.Sinkable Rzk.TypeCheck.Context.ModalTope
+ Rzk.TypeCheck.Context: instance Control.Monad.Foil.Internal.Sinkable Rzk.TypeCheck.Context.VarInfo
+ Rzk.TypeCheck.Context: instance GHC.Classes.Eq Rzk.TypeCheck.Context.LocationInfo
+ Rzk.TypeCheck.Context: instance GHC.Classes.Eq Rzk.TypeCheck.Context.Verbosity
+ Rzk.TypeCheck.Context: instance GHC.Classes.Ord Rzk.TypeCheck.Context.Verbosity
+ Rzk.TypeCheck.Context: instance GHC.Show.Show Rzk.TypeCheck.Context.LocationInfo
+ Rzk.TypeCheck.Context: instance Rzk.TypeCheck.Context.ModeTheory Language.Rzk.Foil.Names.TModality
+ Rzk.TypeCheck.Context: isAccessible :: forall (n :: S). ModalTope n -> Bool
+ Rzk.TypeCheck.Context: isRA :: ModeTheory m => m -> Bool
+ Rzk.TypeCheck.Context: lookupNamed :: forall (n :: S). VarIdent -> Context n -> Maybe (Name n)
+ Rzk.TypeCheck.Context: lookupVarInfo :: forall (n :: S). Name n -> Context n -> VarInfo n
+ Rzk.TypeCheck.Context: mapNameMap :: forall a b (n :: S). (a -> b) -> NameMap n a -> NameMap n b
+ Rzk.TypeCheck.Context: plainTope :: forall (n :: S). TermT n -> ModalTope n
+ Rzk.TypeCheck.Context: shadowedBy :: forall (n :: S). VarIdent -> Context n -> [VarIdent]
+ Rzk.TypeCheck.Context: sinkContextUnchecked :: forall (n :: S) (l :: S). DExt n l => Context n -> Context l
+ Rzk.TypeCheck.Context: sinkNamed :: forall (n :: S) (l :: S). DExt n l => Map VarIdent (Name n) -> Map VarIdent (Name l)
+ Rzk.TypeCheck.Context: sinkNames :: forall (n :: S) (l :: S). DExt n l => [Name n] -> [Name l]
+ Rzk.TypeCheck.Context: sinkTopes :: forall (n :: S) (l :: S). DExt n l => [ModalTope n] -> [ModalTope l]
+ Rzk.TypeCheck.Context: sinkVars :: forall (n :: S) (l :: S). DExt n l => NameMap n (VarInfo n) -> NameMap n (VarInfo l)
+ Rzk.TypeCheck.Context: structuralHoleUnify :: forall (n :: S). Context n -> Context n
+ Rzk.TypeCheck.Context: varInfos :: forall (n :: S). Context n -> [VarInfo n]
+ Rzk.TypeCheck.Context: varsInScope :: forall (n :: S). Context n -> [(Name n, VarInfo n)]
+ Rzk.TypeCheck.Context: withFreshBinder :: forall (n :: S) r. Distinct n => Context n -> VarInfo n -> (forall (l :: S). DExt n l => NameBinder n l -> Context l -> r) -> r
+ Rzk.TypeCheck.Context: withHintLemmas :: forall (n :: S). [VarIdent] -> Context n -> Context n
+ Rzk.TypeCheck.Decl: Decl :: VarIdent -> Name n -> TermT n -> Maybe (TermT n) -> Bool -> [Name n] -> Maybe LocationInfo -> Decl (n :: S)
+ Rzk.TypeCheck.Decl: DeclView :: VarIdent -> Rendered -> Bool -> Maybe LocationInfo -> DeclView
+ Rzk.TypeCheck.Decl: [Checked] :: forall (n :: S). Distinct n => Context n -> [(FilePath, [Decl n])] -> [TypeErrorInScopedContext] -> Checked
+ Rzk.TypeCheck.Decl: [declIsAssumption] :: Decl (n :: S) -> Bool
+ Rzk.TypeCheck.Decl: [declLocation] :: Decl (n :: S) -> Maybe LocationInfo
+ Rzk.TypeCheck.Decl: [declNameOf] :: Decl (n :: S) -> Name n
+ Rzk.TypeCheck.Decl: [declName] :: Decl (n :: S) -> VarIdent
+ Rzk.TypeCheck.Decl: [declType] :: Decl (n :: S) -> TermT n
+ Rzk.TypeCheck.Decl: [declUsedVars] :: Decl (n :: S) -> [Name n]
+ Rzk.TypeCheck.Decl: [declValue] :: Decl (n :: S) -> Maybe (TermT n)
+ Rzk.TypeCheck.Decl: [declViewIsAssumption] :: DeclView -> Bool
+ Rzk.TypeCheck.Decl: [declViewLocation] :: DeclView -> Maybe LocationInfo
+ Rzk.TypeCheck.Decl: [declViewName] :: DeclView -> VarIdent
+ Rzk.TypeCheck.Decl: [declViewType] :: DeclView -> Rendered
+ Rzk.TypeCheck.Decl: abstractOver :: forall (n :: S). Distinct n => Scope n -> Name n -> VarInfo n -> VarInfo n -> VarInfo n
+ Rzk.TypeCheck.Decl: addParamDecls :: [ParamDecl] -> Term -> Term
+ Rzk.TypeCheck.Decl: addParams :: [Param] -> Term -> Term
+ Rzk.TypeCheck.Decl: applyToAssumption :: forall (n :: S). Distinct n => Scope n -> Name n -> (Name n, VarInfo n) -> VarInfo n -> VarInfo n
+ Rzk.TypeCheck.Decl: assume :: forall (n :: S) r. Distinct n => [VarIdent] -> TermT n -> (forall (l :: S). (DExt n l, Distinct l) => [Decl l] -> TypeCheck l r) -> TypeCheck n r
+ Rzk.TypeCheck.Decl: checkCommands :: forall (n :: S) r. Distinct n => Maybe FilePath -> Integer -> Integer -> [Command] -> (forall (l :: S). (DExt n l, Distinct l) => [Decl l] -> [TypeErrorInScopedContext] -> TypeCheck l r) -> TypeCheck n r
+ Rzk.TypeCheck.Decl: checkDefined :: forall (n :: S). Distinct n => VarIdent -> TypeCheck n (Name n)
+ Rzk.TypeCheck.Decl: checkModule :: forall (n :: S) r. Distinct n => Maybe FilePath -> Module -> (forall (l :: S). (DExt n l, Distinct l) => [Decl l] -> [TypeErrorInScopedContext] -> TypeCheck l r) -> TypeCheck n r
+ Rzk.TypeCheck.Decl: checkModuleWithLocation :: forall (n :: S) r. Distinct n => (FilePath, Module) -> (forall (l :: S). (DExt n l, Distinct l) => [Decl l] -> [TypeErrorInScopedContext] -> TypeCheck l r) -> TypeCheck n r
+ Rzk.TypeCheck.Decl: checkModules :: forall (n :: S) r. Distinct n => [(FilePath, Module)] -> (forall (l :: S). (DExt n l, Distinct l) => [(FilePath, [Decl l])] -> [TypeErrorInScopedContext] -> TypeCheck l r) -> TypeCheck n r
+ Rzk.TypeCheck.Decl: checkedErrors :: Checked -> [TypeErrorInScopedContext]
+ Rzk.TypeCheck.Decl: checkedModules :: [(FilePath, Module)] -> Context 'VoidS -> Either TypeErrorInScopedContext (Checked, [HoleInfo])
+ Rzk.TypeCheck.Decl: collectSectionDecls :: forall (n :: S). Distinct n => Bool -> [TypeErrorInScopedContext] -> [(Name n, VarInfo n)] -> [(Name n, VarInfo n)] -> TypeCheck n ([(Name n, VarInfo n)], [TypeErrorInScopedContext])
+ Rzk.TypeCheck.Decl: countCommands :: Integral a => [Command] -> a
+ Rzk.TypeCheck.Decl: data Checked
+ Rzk.TypeCheck.Decl: data Decl (n :: S)
+ Rzk.TypeCheck.Decl: data DeclView
+ Rzk.TypeCheck.Decl: declViews :: Checked -> [(FilePath, [DeclView])]
+ Rzk.TypeCheck.Decl: elaborate :: forall (n :: S). Distinct n => Term -> TypeCheck n (Term n)
+ Rzk.TypeCheck.Decl: emptyChecked :: Checked
+ Rzk.TypeCheck.Decl: endSection :: forall (n :: S). Distinct n => [TypeErrorInScopedContext] -> TypeCheck n ([Decl n], [TypeErrorInScopedContext], Context n)
+ Rzk.TypeCheck.Decl: instance GHC.Classes.Eq Rzk.TypeCheck.Decl.DeclView
+ Rzk.TypeCheck.Decl: instance GHC.Show.Show Rzk.TypeCheck.Decl.DeclView
+ Rzk.TypeCheck.Decl: makeAssumptionExplicit :: forall (n :: S). Distinct n => (Name n, VarInfo n) -> [(Name n, VarInfo n)] -> TypeCheck n (Bool, [(Name n, VarInfo n)])
+ Rzk.TypeCheck.Decl: paramToParamDecl :: forall (n :: S). Distinct n => Param -> TypeCheck n [ParamDecl]
+ Rzk.TypeCheck.Decl: recheckFrom :: Checked -> [(FilePath, Module)] -> Either TypeErrorInScopedContext (Checked, [HoleInfo])
+ Rzk.TypeCheck.Decl: recordInSection :: forall (n :: S). Name n -> Context n -> Context n
+ Rzk.TypeCheck.Decl: setOption :: forall (n :: S) a. Distinct n => String -> String -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Decl: sinkDecl :: forall (n :: S) (l :: S). DExt n l => Decl n -> Decl l
+ Rzk.TypeCheck.Decl: splitSectionCommands :: forall (n :: S). Distinct n => SectionName -> [Command] -> TypeCheck n ([Command], [Command])
+ Rzk.TypeCheck.Decl: startSection :: forall (n :: S) a. Maybe SectionName -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Decl: typeErrorHere :: forall (n :: S). Distinct n => TypeError n -> TypeCheck n TypeErrorInScopedContext
+ Rzk.TypeCheck.Decl: typecheckModules :: [(FilePath, Module)] -> Either TypeErrorInScopedContext Checked
+ Rzk.TypeCheck.Decl: typecheckModulesWithHoles :: [(FilePath, Module)] -> Either TypeErrorInScopedContext (Checked, [HoleInfo])
+ Rzk.TypeCheck.Decl: typecheckModulesWithHolesAndLemmas :: [VarIdent] -> [(FilePath, Module)] -> Either TypeErrorInScopedContext (Checked, [HoleInfo])
+ Rzk.TypeCheck.Decl: unsetOption :: forall (n :: S) a. Distinct n => String -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Decl: withCommand :: forall (n :: S) r. Command -> ([Decl n] -> [TypeErrorInScopedContext] -> TypeCheck n r) -> TypeCheck n r -> TypeCheck n r
+ Rzk.TypeCheck.Decl: withSection :: forall (n :: S) r. Distinct n => Maybe SectionName -> Integer -> [Command] -> Maybe FilePath -> Integer -> (forall (l :: S). (DExt n l, Distinct l) => [Decl l] -> [TypeErrorInScopedContext] -> TypeCheck l r) -> TypeCheck n r
+ Rzk.TypeCheck.Decl: withTopLevel :: forall (n :: S) r. Distinct n => VarIdent -> TermT n -> Maybe (TermT n) -> Bool -> [Name n] -> (forall (l :: S). (DExt n l, Distinct l) => NameBinder n l -> Decl l -> TypeCheck l r) -> TypeCheck n r
+ Rzk.TypeCheck.Display: Naming :: NameMap n Display -> [VarIdent] -> [VarIdent] -> Naming (n :: S)
+ Rzk.TypeCheck.Display: Rendered :: Term -> Rendered
+ Rzk.TypeCheck.Display: [getRendered] :: Rendered -> Term
+ Rzk.TypeCheck.Display: [namingOf] :: Naming (n :: S) -> NameMap n Display
+ Rzk.TypeCheck.Display: [namingSupply] :: Naming (n :: S) -> [VarIdent]
+ Rzk.TypeCheck.Display: [namingUsed] :: Naming (n :: S) -> [VarIdent]
+ Rzk.TypeCheck.Display: data Naming (n :: S)
+ Rzk.TypeCheck.Display: displayOf :: forall (n :: S). Naming n -> Name n -> Display
+ Rzk.TypeCheck.Display: instance GHC.Classes.Eq Rzk.TypeCheck.Display.Rendered
+ Rzk.TypeCheck.Display: instance GHC.Show.Show Rzk.TypeCheck.Display.Rendered
+ Rzk.TypeCheck.Display: namingOfContext :: forall (n :: S). Context n -> Naming n
+ Rzk.TypeCheck.Display: newtype Rendered
+ Rzk.TypeCheck.Display: panicImpossible :: String -> a
+ Rzk.TypeCheck.Display: ppName :: forall (n :: S). Naming n -> Name n -> String
+ Rzk.TypeCheck.Display: ppTerm :: forall (n :: S). Naming n -> Term n -> String
+ Rzk.TypeCheck.Display: ppTermT :: forall (n :: S). Naming n -> TermT n -> String
+ Rzk.TypeCheck.Display: renderTerm :: forall (n :: S). Naming n -> Term n -> Rendered
+ Rzk.TypeCheck.Error: BottomUp :: OutputDirection
+ Rzk.TypeCheck.Error: TopDown :: OutputDirection
+ Rzk.TypeCheck.Error: TypeErrorCannotInferBareLambda :: Term n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorCannotInferBareRefl :: Term n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorCannotInferHole :: Term n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorDuplicateTopLevel :: [VarIdent] -> VarIdent -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorImplicitAssumption :: (Name n, TermT n) -> Name n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorInvalidArgumentType :: Term n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorModalityMismatch :: TModality -> TModality -> Term n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorNotFunction :: TermT n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorNotModal :: Term n -> TModality -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorNotPair :: TermT n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorNotTypeInModal :: TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorOther :: String -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorTopeContextDisjoint :: TermT n -> [TermT n] -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorTopeNotSatisfied :: [TermT n] -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorTopesNotEquivalent :: TermT n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUnaccessibleVar :: Name n -> TModality -> TModality -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUndefined :: VarIdent -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUnexpectedLambda :: Term n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUnexpectedPair :: Term n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUnexpectedRefl :: Term n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUnify :: TermT n -> TermT n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUnifyTerms :: TermT n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUnsolvedHole :: Maybe VarIdent -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUnusedUsedVariables :: [Name n] -> Name n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: TypeErrorUnusedVariable :: Name n -> TermT n -> TypeError (n :: S)
+ Rzk.TypeCheck.Error: [TypeErrorInScopedContext] :: forall (n :: S). Distinct n => Context n -> TypeError n -> TypeErrorInScopedContext
+ Rzk.TypeCheck.Error: block :: OutputDirection -> [String] -> String
+ Rzk.TypeCheck.Error: data OutputDirection
+ Rzk.TypeCheck.Error: data TypeError (n :: S)
+ Rzk.TypeCheck.Error: data TypeErrorInScopedContext
+ Rzk.TypeCheck.Error: instance GHC.Classes.Eq Rzk.TypeCheck.Error.OutputDirection
+ Rzk.TypeCheck.Error: namedBlock :: OutputDirection -> String -> [String] -> String
+ Rzk.TypeCheck.Error: ppAction :: forall (n :: S). Naming n -> Int -> Action n -> String
+ Rzk.TypeCheck.Error: ppContext :: forall (n :: S). OutputDirection -> Context n -> String
+ Rzk.TypeCheck.Error: ppModality :: TModality -> String
+ Rzk.TypeCheck.Error: ppTypeError :: forall (n :: S). Naming n -> TypeError n -> String
+ Rzk.TypeCheck.Error: ppTypeErrorInScopedContext :: OutputDirection -> TypeErrorInScopedContext -> String
+ Rzk.TypeCheck.Eval: allM :: Monad m => (a -> m Bool) -> [a] -> m Bool
+ Rzk.TypeCheck.Eval: allTopePoints :: forall (n :: S). Distinct n => TermT n -> [TermT n]
+ Rzk.TypeCheck.Eval: applyModalityToTopes :: forall (n :: S). TModality -> [ModalTope n] -> [ModalTope n]
+ Rzk.TypeCheck.Eval: applyNeutral :: forall (n :: S). Distinct n => Scope n -> TermT n -> [(TypeInfo (TermT n), TermT n)] -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: applySpine :: forall (n :: S). Distinct n => Scope n -> TermT n -> [(TypeInfo (TermT n), TermT n)] -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: applyWhnfFun :: forall (n :: S). Distinct n => TypeInfo (TermT n) -> TermT n -> TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: binderInfo :: forall (n :: S). Binder -> TModality -> TermT n -> Maybe (TermT n) -> Maybe LocationInfo -> VarInfo n
+ Rzk.TypeCheck.Eval: checkDefinedVar :: forall (n :: S). Distinct n => VarIdent -> TypeCheck n ()
+ Rzk.TypeCheck.Eval: checkEntails :: forall (n :: S). Distinct n => TermT n -> TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: checkTope :: forall (n :: S). Distinct n => TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: checkTopeAgainstContext :: forall (n :: S). Distinct n => String -> TermT n -> TypeCheck n ()
+ Rzk.TypeCheck.Eval: checkTopeEntails :: forall (n :: S). Distinct n => TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: checkUnder :: forall (n :: S) a. Distinct n => Binder -> TModality -> TermT n -> ScopedTerm n -> (forall (l :: S). (DExt n l, Distinct l) => NameBinder n l -> Term l -> TypeCheck l a) -> TypeCheck n a
+ Rzk.TypeCheck.Eval: checkUnderWith :: forall (n :: S) a. Distinct n => Binder -> TModality -> TermT n -> Maybe (TermT n) -> ScopedTerm n -> (forall (l :: S). (DExt n l, Distinct l) => NameBinder n l -> Term l -> TypeCheck l a) -> TypeCheck n a
+ Rzk.TypeCheck.Eval: collectAppSpine :: forall (n :: S). TermT n -> (TermT n, [(TypeInfo (TermT n), TermT n)])
+ Rzk.TypeCheck.Eval: constScope :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (ScopedTermT n)
+ Rzk.TypeCheck.Eval: contextEntails :: forall (n :: S). Distinct n => TermT n -> TypeCheck n ()
+ Rzk.TypeCheck.Eval: contextEntailsBottom :: forall (n :: S). Distinct n => TypeCheck n Bool
+ Rzk.TypeCheck.Eval: contextEntailsUnion :: forall (n :: S). Distinct n => [TermT n] -> TypeCheck n ()
+ Rzk.TypeCheck.Eval: discreteAxiomOf :: forall (n :: S) (l :: S). Distinct n => TModality -> TermT n -> NameBinder n l -> TypeCheck n [ModalTope l]
+ Rzk.TypeCheck.Eval: elaborateUnder :: forall (n :: S). Distinct n => Binder -> TModality -> TermT n -> Maybe (TermT n) -> ScopedTerm n -> (forall (l :: S). (DExt n l, Distinct l) => NameBinder n l -> Term l -> TypeCheck l (TermT l)) -> TypeCheck n (ScopedTermT n)
+ Rzk.TypeCheck.Eval: elemModalTope :: forall (n :: S). Distinct n => ModalTope n -> [ModalTope n] -> Bool
+ Rzk.TypeCheck.Eval: elemName :: forall (n :: S). Name n -> [Name n] -> Bool
+ Rzk.TypeCheck.Eval: entailContextM :: forall (n :: S). Distinct n => TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: entailM :: forall (n :: S). Distinct n => [ModalTope n] -> TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: entailSaturatedM :: forall (n :: S). Distinct n => [[ModalTope n]] -> TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: enterModality :: forall (n :: S) b. Distinct n => TModality -> TypeCheck n b -> TypeCheck n b
+ Rzk.TypeCheck.Eval: eqModalTope :: forall (n :: S). Distinct n => ModalTope n -> ModalTope n -> Bool
+ Rzk.TypeCheck.Eval: etaExpand :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: etaMatch :: forall (n :: S). Distinct n => Maybe (TermT n) -> TermT n -> TermT n -> TypeCheck n (TermT n, TermT n)
+ Rzk.TypeCheck.Eval: firstMatching :: forall (n :: S). Distinct n => [(TermT n, TermT n)] -> TypeCheck n (Maybe (TermT n))
+ Rzk.TypeCheck.Eval: freeVarsDeep :: forall (n :: S). TermT n -> TypeCheck n [Name n]
+ Rzk.TypeCheck.Eval: generateTopes :: forall (n :: S). Distinct n => [TermT n] -> [TermT n] -> [TermT n]
+ Rzk.TypeCheck.Eval: generateTopesForPointsM :: forall (n :: S). Distinct n => [TermT n] -> TypeCheck n [TermT n]
+ Rzk.TypeCheck.Eval: inAllSubContexts :: forall (n :: S). Distinct n => TypeCheck n () -> TypeCheck n () -> TypeCheck n ()
+ Rzk.TypeCheck.Eval: inCubeLayer :: forall (n :: S). Distinct n => TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: inScope :: forall (sig :: Type -> Type -> Type) (n :: S) a. (Bifunctor sig, Distinct n) => Binder -> TModality -> TermT n -> ScopedAST NameBinder sig n -> (forall (l :: S). (DExt n l, Distinct l) => AST NameBinder sig l -> TypeCheck l a) -> TypeCheck n a
+ Rzk.TypeCheck.Eval: inScopeWith :: forall (sig :: Type -> Type -> Type) (n :: S) a. (Bifunctor sig, Distinct n) => Binder -> TModality -> TermT n -> Maybe (TermT n) -> ScopedAST NameBinder sig n -> (forall (l :: S). (DExt n l, Distinct l) => AST NameBinder sig l -> TypeCheck l a) -> TypeCheck n a
+ Rzk.TypeCheck.Eval: inTopeLayer :: forall (n :: S). Distinct n => TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: infoOfVar :: forall (n :: S) a. (VarInfo n -> a) -> Name n -> TypeCheck n a
+ Rzk.TypeCheck.Eval: instantiate :: forall (n :: S). Distinct n => ScopedTermT n -> TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: isTopLevelVar :: forall (n :: S). Name n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: localTope :: forall (n :: S) a. Distinct n => TermT n -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Eval: locksOfVar :: forall (n :: S). Name n -> TypeCheck n TModality
+ Rzk.TypeCheck.Eval: memoizeWHNF :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: modalityOfVar :: forall (n :: S). Name n -> TypeCheck n TModality
+ Rzk.TypeCheck.Eval: nfT :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: nfTope :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: notElemName :: forall (n :: S). Name n -> [Name n] -> Bool
+ Rzk.TypeCheck.Eval: nubModalTopes :: forall (n :: S). Distinct n => [ModalTope n] -> [ModalTope n]
+ Rzk.TypeCheck.Eval: nubNames :: forall (n :: S). [Name n] -> [Name n]
+ Rzk.TypeCheck.Eval: openScoped :: forall (sig :: Type -> Type -> Type) (n :: S) (l :: S). (Bifunctor sig, DExt n l) => NameBinder n l -> ScopedAST NameBinder sig n -> TypeCheck l (AST NameBinder sig l)
+ Rzk.TypeCheck.Eval: partitionAccessible :: forall (n :: S). [ModalTope n] -> ([ModalTope n], [ModalTope n])
+ Rzk.TypeCheck.Eval: peelLambdas :: forall (i :: S) (n :: S). Distinct n => Scope n -> Substitution TermT i n -> TermT i -> [(TypeInfo (TermT n), TermT n)] -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: saturateBottom :: forall (n :: S). Distinct n => [ModalTope n] -> [ModalTope n]
+ Rzk.TypeCheck.Eval: saturateForEntailment :: forall (n :: S). Distinct n => [ModalTope n] -> TypeCheck n [[ModalTope n]]
+ Rzk.TypeCheck.Eval: saturateInv :: forall (n :: S). Distinct n => [ModalTope n] -> TypeCheck n [ModalTope n]
+ Rzk.TypeCheck.Eval: saturateTopes :: forall (n :: S). Distinct n => [ModalTope n] -> [ModalTope n]
+ Rzk.TypeCheck.Eval: saturateWith :: (a -> [a] -> Bool) -> ([a] -> [a] -> [a]) -> [a] -> [a]
+ Rzk.TypeCheck.Eval: simplifyLHSwithDisjunctions :: forall (n :: S). Distinct n => [ModalTope n] -> [[ModalTope n]]
+ Rzk.TypeCheck.Eval: solveRHS :: forall (n :: S). Distinct n => [TermT n] -> TermT n -> Bool
+ Rzk.TypeCheck.Eval: solveRHSM :: forall (n :: S). Distinct n => [ModalTope n] -> TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: stripTypeRestrictions :: forall (n :: S). TermT n -> TermT n
+ Rzk.TypeCheck.Eval: subPoints :: forall (n :: S). TermT n -> [TermT n]
+ Rzk.TypeCheck.Eval: topePoints :: forall (n :: S). TermT n -> [TermT n]
+ Rzk.TypeCheck.Eval: topesEquiv :: forall (n :: S). Distinct n => TermT n -> TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Eval: tryRestriction :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (Maybe (TermT n))
+ Rzk.TypeCheck.Eval: typeOf :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: typeOfUncomputed :: forall (n :: S). TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: typeOfVar :: forall (n :: S). Name n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: underBinder :: forall (n :: S) (l :: S) a. (Distinct n, DExt n l) => NameBinder n l -> Binder -> TModality -> TermT n -> Maybe (TermT n) -> TypeCheck l a -> TypeCheck n a
+ Rzk.TypeCheck.Eval: underScope :: forall (n :: S). Distinct n => Binder -> TModality -> TermT n -> Maybe (TermT n) -> ScopedTermT n -> (forall (l :: S). (DExt n l, Distinct l) => TermT l -> TypeCheck l (TermT l)) -> TypeCheck n (ScopedTermT n)
+ Rzk.TypeCheck.Eval: underScope2 :: forall (n :: S). Distinct n => Binder -> TModality -> TermT n -> ScopedTermT n -> ScopedTermT n -> (forall (l :: S). (DExt n l, Distinct l) => TermT l -> TermT l -> TypeCheck l (TermT l, TermT l)) -> TypeCheck n (ScopedTermT n, ScopedTermT n)
+ Rzk.TypeCheck.Eval: valueOfVar :: forall (n :: S). Name n -> TypeCheck n (Maybe (TermT n))
+ Rzk.TypeCheck.Eval: whnfT :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Eval: withBinder :: forall (n :: S) a. Distinct n => Binder -> TModality -> TermT n -> (forall (l :: S). (DExt n l, Distinct l) => NameBinder n l -> TypeCheck l a) -> TypeCheck n a
+ Rzk.TypeCheck.Eval: withFreshIn :: forall (n :: S) r. Distinct n => Scope n -> (forall (l :: S). (DExt n l, Distinct l) => NameBinder n l -> r) -> r
+ Rzk.TypeCheck.Eval: withRefreshedTopes :: forall (n :: S) a. Distinct n => (Context n -> Context n) -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Judgements: Branching :: ElimCost
+ Rzk.TypeCheck.Judgements: SpineStep :: ElimCost
+ Rzk.TypeCheck.Judgements: allEliminationsInto :: forall (n :: S). Distinct n => TermT n -> TermT n -> TypeCheck n [TermT n]
+ Rzk.TypeCheck.Judgements: allIntroductionsOf :: forall (n :: S). Distinct n => TermT n -> [VarIdent] -> TypeCheck n [TermT n]
+ Rzk.TypeCheck.Judgements: checkHoleAgainstShape :: forall (n :: S). Distinct n => Maybe VarIdent -> Binder -> TermT n -> ScopedTermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Judgements: checkNameShadowing :: forall (n :: S). VarIdent -> TypeCheck n ()
+ Rzk.TypeCheck.Judgements: checkRecOrAgainst :: forall (n :: S). Distinct n => TermT n -> [(Term n, Term n)] -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Judgements: checkTopLevelDuplicate :: forall (n :: S). Distinct n => VarIdent -> TypeCheck n ()
+ Rzk.TypeCheck.Judgements: closedScope :: forall (n :: S). Distinct n => Scope n -> (forall (l :: S). () => TermT l) -> ScopedTermT n
+ Rzk.TypeCheck.Judgements: coverageHolds :: forall (n :: S). Distinct n => [TermT n] -> TypeCheck n Bool
+ Rzk.TypeCheck.Judgements: data ElimCost
+ Rzk.TypeCheck.Judgements: destructuringBinder :: forall (n :: S). Binder -> TermT n -> Binder
+ Rzk.TypeCheck.Judgements: doesShadowName :: forall (n :: S). VarIdent -> TypeCheck n [VarIdent]
+ Rzk.TypeCheck.Judgements: eliminatorsOf :: forall (n :: S). Distinct n => TermT n -> TypeCheck n [(ElimCost, TermT n -> TypeCheck n (TermT n))]
+ Rzk.TypeCheck.Judgements: endpointsAgree :: forall (n :: S). Distinct n => TermT n -> TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Judgements: fitsInto :: forall (n :: S). Distinct n => TermT n -> TermT n -> TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Judgements: infer :: forall (n :: S). Distinct n => Term n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Judgements: inferAs :: forall (n :: S). Distinct n => TermT n -> Term n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Judgements: instance GHC.Classes.Eq Rzk.TypeCheck.Judgements.ElimCost
+ Rzk.TypeCheck.Judgements: instance GHC.Show.Show Rzk.TypeCheck.Judgements.ElimCost
+ Rzk.TypeCheck.Judgements: isCubeOrTopeType :: forall (n :: S). TermT n -> Bool
+ Rzk.TypeCheck.Judgements: isCubeType :: forall (n :: S). TermT n -> Bool
+ Rzk.TypeCheck.Judgements: lemmaHypotheses :: forall (n :: S). Context n -> [(Name n, VarInfo n)]
+ Rzk.TypeCheck.Judgements: localHypotheses :: forall (n :: S). Context n -> [(Name n, VarInfo n)]
+ Rzk.TypeCheck.Judgements: maxEliminationDepth :: Int
+ Rzk.TypeCheck.Judgements: mkHole :: forall (n :: S). TermT n -> TermT n
+ Rzk.TypeCheck.Judgements: motiveOf :: forall (n :: S). Distinct n => Scope n -> TermT n -> TermT n -> TermT n
+ Rzk.TypeCheck.Judgements: motiveType :: forall (n :: S). Distinct n => TermT n -> TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Judgements: pruneVacuousFaces :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Judgements: recBottomCandidates :: forall (n :: S). Distinct n => TypeCheck n [TermT n]
+ Rzk.TypeCheck.Judgements: recOrCandidates :: forall (n :: S). Distinct n => TermT n -> TypeCheck n [TermT n]
+ Rzk.TypeCheck.Judgements: recordHole :: forall (n :: S). Distinct n => Maybe VarIdent -> TermT n -> TypeCheck n ()
+ Rzk.TypeCheck.Judgements: recordHoleShape :: forall (n :: S). Distinct n => Maybe VarIdent -> TermT n -> Maybe (Binder, ScopedTermT n) -> TypeCheck n ()
+ Rzk.TypeCheck.Judgements: typecheck :: forall (n :: S). Distinct n => Term n -> TermT n -> TypeCheck n (TermT n)
+ Rzk.TypeCheck.Monad: HoleEntry :: VarIdent -> Rendered -> HoleEntry
+ Rzk.TypeCheck.Monad: HoleInfo :: Maybe VarIdent -> Rendered -> Maybe (VarIdent, Rendered) -> [HoleEntry] -> [HoleEntry] -> [Rendered] -> [Rendered] -> [Rendered] -> Maybe String -> Maybe LocationInfo -> HoleInfo
+ Rzk.TypeCheck.Monad: [holeCandidates] :: HoleInfo -> [Rendered]
+ Rzk.TypeCheck.Monad: [holeCubeVars] :: HoleInfo -> [HoleEntry]
+ Rzk.TypeCheck.Monad: [holeDiagram] :: HoleInfo -> Maybe String
+ Rzk.TypeCheck.Monad: [holeEntryName] :: HoleEntry -> VarIdent
+ Rzk.TypeCheck.Monad: [holeEntryType] :: HoleEntry -> Rendered
+ Rzk.TypeCheck.Monad: [holeGoalShape] :: HoleInfo -> Maybe (VarIdent, Rendered)
+ Rzk.TypeCheck.Monad: [holeGoal] :: HoleInfo -> Rendered
+ Rzk.TypeCheck.Monad: [holeIntroductions] :: HoleInfo -> [Rendered]
+ Rzk.TypeCheck.Monad: [holeLocation] :: HoleInfo -> Maybe LocationInfo
+ Rzk.TypeCheck.Monad: [holeName] :: HoleInfo -> Maybe VarIdent
+ Rzk.TypeCheck.Monad: [holeTermVars] :: HoleInfo -> [HoleEntry]
+ Rzk.TypeCheck.Monad: [holeTopes] :: HoleInfo -> [Rendered]
+ Rzk.TypeCheck.Monad: data HoleEntry
+ Rzk.TypeCheck.Monad: data HoleInfo
+ Rzk.TypeCheck.Monad: hidingTerm :: forall (n :: S) a. TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: inContext :: forall (l :: S) a (n :: S). Context l -> TypeCheck l a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: instance GHC.Classes.Eq Rzk.TypeCheck.Monad.HoleEntry
+ Rzk.TypeCheck.Monad: instance GHC.Classes.Eq Rzk.TypeCheck.Monad.HoleInfo
+ Rzk.TypeCheck.Monad: instance GHC.Show.Show Rzk.TypeCheck.Monad.HoleEntry
+ Rzk.TypeCheck.Monad: instance GHC.Show.Show Rzk.TypeCheck.Monad.HoleInfo
+ Rzk.TypeCheck.Monad: issueTypeError :: forall (n :: S) a. Distinct n => TypeError n -> TypeCheck n a
+ Rzk.TypeCheck.Monad: issueWarning :: forall (n :: S). String -> TypeCheck n ()
+ Rzk.TypeCheck.Monad: localHideTerm :: forall (n :: S) a. Bool -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: localRenderBackend :: forall (n :: S) a. Maybe RenderBackend -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: localVerbosity :: forall (n :: S) a. Verbosity -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: localWarnOverhang :: forall (n :: S) a. Bool -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: maxActionStackDepth :: Int
+ Rzk.TypeCheck.Monad: performing :: forall (n :: S) a. Distinct n => Action n -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: recordHoleInfo :: forall (n :: S). HoleInfo -> TypeCheck n ()
+ Rzk.TypeCheck.Monad: runTypeCheck :: TypeCheck 'VoidS a -> Either TypeErrorInScopedContext a
+ Rzk.TypeCheck.Monad: runTypeCheckIn :: forall (n :: S) a. Context n -> TypeCheck n a -> Either TypeErrorInScopedContext a
+ Rzk.TypeCheck.Monad: setVariance :: forall (n :: S) a. Covariance -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: switchVariance :: forall (n :: S) a. TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: trace' :: Verbosity -> Verbosity -> String -> a -> a
+ Rzk.TypeCheck.Monad: traceTypeCheck :: forall (n :: S) a. Verbosity -> String -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.Monad: type TypeCheck (n :: S) = ReaderT Context n WriterT [HoleInfo] Except TypeErrorInScopedContext
+ Rzk.TypeCheck.Monad: withLocation :: forall (n :: S) a. LocationInfo -> TypeCheck n a -> TypeCheck n a
+ Rzk.TypeCheck.NbE: instance GHC.Classes.Eq Rzk.TypeCheck.NbE.AbortReason
+ Rzk.TypeCheck.NbE: instance GHC.Classes.Ord Rzk.TypeCheck.NbE.AbortReason
+ Rzk.TypeCheck.NbE: instance GHC.Enum.Bounded Rzk.TypeCheck.NbE.AbortReason
+ Rzk.TypeCheck.NbE: instance GHC.Enum.Enum Rzk.TypeCheck.NbE.AbortReason
+ Rzk.TypeCheck.NbE: instance GHC.Show.Show Rzk.TypeCheck.NbE.AbortReason
+ Rzk.TypeCheck.NbE: nbeConvertible :: forall (n :: S). TermT n -> TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Render: componentWiseEQT :: forall (n :: S). Int -> TermT n -> TermT n -> TermT n
+ Rzk.TypeCheck.Render: cube2powerT :: forall (n :: S). Int -> TermT n
+ Rzk.TypeCheck.Render: dimOf :: forall (n :: S). TermT n -> Maybe Int
+ Rzk.TypeCheck.Render: drawCube :: Int -> [(String, RenderObjectData)] -> String
+ Rzk.TypeCheck.Render: inScopeMaybeTope :: forall (n :: S) a. Distinct n => Binder -> TModality -> TermT n -> Maybe (ScopedTermT n) -> (forall (l :: S). (DExt n l, Distinct l) => NameBinder n l -> TypeCheck l a) -> TypeCheck n a
+ Rzk.TypeCheck.Render: isAnonymous :: forall (n :: S). Name n -> TypeCheck n Bool
+ Rzk.TypeCheck.Render: maxRenderDim :: Int
+ Rzk.TypeCheck.Render: ppInContext :: forall (n :: S). TermT n -> TypeCheck n String
+ Rzk.TypeCheck.Render: renderApplied :: forall (n :: S) (l :: S). DExt n l => NameBinder n l -> TermT n -> TermT n -> ScopedTermT n -> TypeCheck l (Maybe String)
+ Rzk.TypeCheck.Render: renderForSVG :: forall (n :: S). Distinct n => String -> Int -> TermT n -> TermT n -> TypeCheck n String
+ Rzk.TypeCheck.Render: renderForSubShapeSVG :: forall (n :: S). Distinct n => String -> Int -> [Name n] -> Name n -> TermT n -> TermT n -> TermT n -> TypeCheck n String
+ Rzk.TypeCheck.Render: renderGoalCellSVG :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (Maybe String)
+ Rzk.TypeCheck.Render: renderObjectsFor :: forall (n :: S). Distinct n => String -> Int -> TermT n -> TermT n -> TypeCheck n [(ShapeId, RenderObjectData)]
+ Rzk.TypeCheck.Render: renderObjectsInSubShapeFor :: forall (n :: S). Distinct n => String -> Int -> [Name n] -> Name n -> TermT n -> TermT n -> TermT n -> TypeCheck n [(ShapeId, RenderObjectData)]
+ Rzk.TypeCheck.Render: renderTermSVG :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (Maybe String)
+ Rzk.TypeCheck.Render: renderTermSVG' :: forall (n :: S). Distinct n => TermT n -> TypeCheck n (Maybe String)
+ Rzk.TypeCheck.Render: renderTermSVGFor :: forall (n :: S). Distinct n => String -> Int -> (Maybe (TermT n, TermT n), [Name n]) -> TermT n -> TypeCheck n (Maybe String)
+ Rzk.TypeCheck.Render: splits :: [a] -> [([a], [a])]
+ Rzk.TypeCheck.Render: subTopes2 :: forall (n :: S). Int -> TermT n -> [(ShapeId, TermT n)]
+ Rzk.TypeCheck.Render: verticesFrom :: forall (n :: S). [TermT n] -> [(ShapeId, TermT n)]
+ Rzk.TypeCheck.Unify: alphaEq :: forall (n :: S). Distinct n => TermT n -> TermT n -> TypeCheck n Bool
+ Rzk.TypeCheck.Unify: checkCoherence :: forall (n :: S). Distinct n => (TermT n, TermT n) -> (TermT n, TermT n) -> TypeCheck n ()
+ Rzk.TypeCheck.Unify: inScope2 :: forall (n :: S) a. Distinct n => Binder -> TModality -> TermT n -> ScopedTermT n -> ScopedTermT n -> (forall (l :: S). (DExt n l, Distinct l) => NameBinder n l -> TermT l -> TermT l -> TypeCheck l a) -> TypeCheck n a
+ Rzk.TypeCheck.Unify: unify :: forall (n :: S). Distinct n => Maybe (TermT n) -> TermT n -> TermT n -> TypeCheck n ()
+ Rzk.TypeCheck.Unify: unifyInCurrentContext :: forall (n :: S). Distinct n => Maybe (TermT n) -> TermT n -> TermT n -> TypeCheck n ()
+ Rzk.TypeCheck.Unify: unifyTerms :: forall (n :: S). Distinct n => TermT n -> TermT n -> TypeCheck n ()
+ Rzk.TypeCheck.Unify: unifyTopes :: forall (n :: S). Distinct n => TermT n -> TermT n -> TypeCheck n ()
+ Rzk.TypeCheck.Unify: unifyTypes :: forall (n :: S). Distinct n => TermT n -> TermT n -> TermT n -> TypeCheck n ()
+ Rzk.TypeCheck.Unify: unifyViaDecompose :: forall (n :: S). Distinct n => TermT n -> TermT n -> TypeCheck n ()
- Language.Rzk.VSCode.Env: RzkCachedModule :: [Decl'] -> [TypeErrorInScopedContext VarIdent] -> RzkCachedModule
+ Language.Rzk.VSCode.Env: RzkCachedModule :: Checked -> [DeclView] -> [TypeErrorInScopedContext] -> RzkCachedModule
- Language.Rzk.VSCode.Env: [cachedModuleDecls] :: RzkCachedModule -> [Decl']
+ Language.Rzk.VSCode.Env: [cachedModuleDecls] :: RzkCachedModule -> [DeclView]
- Language.Rzk.VSCode.Env: [cachedModuleErrors] :: RzkCachedModule -> [TypeErrorInScopedContext VarIdent]
+ Language.Rzk.VSCode.Env: [cachedModuleErrors] :: RzkCachedModule -> [TypeErrorInScopedContext]
- Rzk.Diagnostic: diagnoseTypeError :: OutputDirection -> TypeErrorInScopedContext VarIdent -> Diagnostic
+ Rzk.Diagnostic: diagnoseTypeError :: OutputDirection -> TypeErrorInScopedContext -> Diagnostic
- Rzk.Diagnostic: locationOfTypeError :: TypeErrorInScopedContext var -> Maybe LocationInfo
+ Rzk.Diagnostic: locationOfTypeError :: TypeErrorInScopedContext -> Maybe LocationInfo
- Rzk.Diagnostic: typeErrorTag :: TypeError var -> String
+ Rzk.Diagnostic: typeErrorTag :: forall (n :: S). TypeError n -> String
- Rzk.Diagnostic: typeErrorTagInScopedContext :: TypeErrorInScopedContext var -> String
+ Rzk.Diagnostic: typeErrorTagInScopedContext :: TypeErrorInScopedContext -> String
Files
- ChangeLog.md +22/−0
- app/Main.hs +5/−5
- rzk.cabal +45/−6
- src/Free/Scoped.hs +0/−123
- src/Free/Scoped/TH.hs +0/−120
- src/Language/Rzk/Foil/Convert.hs +356/−0
- src/Language/Rzk/Foil/Names.hs +352/−0
- src/Language/Rzk/Foil/Print.hs +246/−0
- src/Language/Rzk/Foil/Syntax.hs +750/−0
- src/Language/Rzk/Free/Syntax.hs +0/−885
- src/Language/Rzk/VSCode/Env.hs +15/−4
- src/Language/Rzk/VSCode/Handlers.hs +50/−42
- src/Language/Rzk/VSCode/ReferenceIndex.hs +34/−20
- src/Rzk/Diagnostic.hs +12/−15
- src/Rzk/Main.hs +2/−2
- src/Rzk/Render/Geometry.hs +274/−0
- src/Rzk/TypeCheck.hs +25/−5507
- src/Rzk/TypeCheck/BinderTypes.hs +213/−0
- src/Rzk/TypeCheck/Context.hs +476/−0
- src/Rzk/TypeCheck/Decl.hs +735/−0
- src/Rzk/TypeCheck/Display.hs +149/−0
- src/Rzk/TypeCheck/Error.hs +385/−0
- src/Rzk/TypeCheck/Eval.hs +1615/−0
- src/Rzk/TypeCheck/Judgements.hs +1185/−0
- src/Rzk/TypeCheck/Monad.hs +177/−0
- src/Rzk/TypeCheck/NbE.hs +297/−0
- src/Rzk/TypeCheck/Render.hs +429/−0
- src/Rzk/TypeCheck/Unify.hs +469/−0
- test/Rzk/BinderTypesSpec.hs +9/−10
- test/Rzk/DiagnosticSpec.hs +3/−3
- test/Rzk/FoilCoreSpec.hs +212/−0
- test/Rzk/HolesSpec.hs +9/−8
- test/Rzk/TypeCheckSpec.hs +46/−43
- test/typecheck/cases/happy-nbe-church-conversion.expect.yaml +4/−0
- test/typecheck/cases/happy-nbe-church-conversion.rzk +41/−0
- test/typecheck/cases/happy-set-option-warn-overhang.expect.yaml +4/−0
- test/typecheck/cases/happy-set-option-warn-overhang.rzk +16/−0
- test/typecheck/cases/ill-nbe-church-unequal.expect.yaml +5/−0
- test/typecheck/cases/ill-nbe-church-unequal.rzk +24/−0
ChangeLog.md view
@@ -6,6 +6,28 @@ and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/). +## v0.10.0 — 2026-07-15++This release replaces the typechecker's internal term representation and makes checking roughly nine times faster. There are no surface-language changes; for users the release is a performance release, plus one new option. For packagers and library users it is a major version: the library API is reorganised, **GHC 9.8 or newer is now required** to build rzk, and the GHCJS-built browser playground is not rebuilt for this release (see below).++Changed:++- **The core representation moved to free-foil** (see [#289](https://github.com/rzk-lang/rzk/pull/289), [#292](https://github.com/rzk-lang/rzk/pull/292)). The typechecker now uses [free-foil](https://github.com/fizruk/free-foil) scope-safe names (integer identifiers with type-level scope indexing) instead of the previous well-scoped de Bruijn representation, whose depth-relative variables made every comparison walk successor chains. The library module layout is reorganised accordingly (`Language.Rzk.Foil.*`, `Rzk.TypeCheck.*`), which is what makes this a major version under the PVP. This raises the compiler floor: **building rzk now requires GHC ≥ 9.8**. The surface language, CLI, and LSP behaviour are unchanged.++- **The browser playground cannot be built from this release** (a consequence of the free-foil migration). The playground is compiled with GHCJS from miso's pinned 2019-era package set, which does not carry free-foil, so the GHCJS lane no longer builds and the playground is not rebuilt or redeployed for v0.10.0; the deployed playground remains the v0.9.2 one. The library itself builds under the GHC WebAssembly backend (the `wasm` CI lane), and the planned replacement is a Miso playground on that backend rather than packaging free-foil for GHCJS.++- **The overhang hint is now opt-in** (see [#295](https://github.com/rzk-lang/rzk/pull/295)). The non-fatal hint that a restriction face or `#!rzk recOR` guard overhangs the local tope context required a solver query per face just to decide whether to print; it is now off by default and enabled with `#!rzk #set-option "warn-overhang" = "yes"`. A face *disjoint* from the context is still a hard error.++Performance:++- A full check of the sHoTT corpus goes from ~13.4 s (v0.9.2) to **~1.5 s**, and maximum residency from 2.1 GB to **233 MB**. The pieces, each measured separately:++ - The free-foil representation itself removes the dominant cost of v0.9.2, variable comparison along de Bruijn successor chains (see [#289](https://github.com/rzk-lang/rzk/pull/289)).+ - The runtime is configured with a 64 MB nursery (`-A64m`), letting the checker's short-lived allocation die young: GC time drops by two thirds (see [#290](https://github.com/rzk-lang/rzk/pull/290)).+ - Beta reduction is spine-batched: a curried application peels the head's lambda chain into a single substitution instead of one per argument, which alone cut wall time by 28% and halved peak residency at its merge point (see [#291](https://github.com/rzk-lang/rzk/pull/291)).+ - **Conversion checking gets a normalisation-by-evaluation fast path** (see [#293](https://github.com/rzk-lang/rzk/pull/293)). Both sides of a comparison are evaluated call-by-need into a value domain with closures and compared structurally; anything context-sensitive falls back to the ordinary unification unchanged, so the fast path cannot change what typechecks. Besides its share of the sHoTT win, this repairs a cliff on computation-heavy code: checking `#!rzk cmul c16 c16 = cadd c128 c128` for Church numerals took 177 seconds (and unbalanced variants did not finish); it now checks in 0.05 seconds.+ - The hole-recording channel uses the CPS writer, removing an allocation on every bind of the typechecking monad (see [#294](https://github.com/rzk-lang/rzk/pull/294)); the judgement stack tracks its depth instead of measuring it (see [#288](https://github.com/rzk-lang/rzk/pull/288)).+ ## v0.9.2 — 2026-07-13 Added:
app/Main.hs view
@@ -75,7 +75,7 @@ putStrLn "An error occurred when typechecking!" putStrLn $ unlines [ "Type Error:"- , ppTypeErrorInScopedContext' BottomUp err+ , ppTypeErrorInScopedContext BottomUp err ] if jsonFlag -- Machine-readable mode: emit every diagnostic (type errors as errors,@@ -84,21 +84,21 @@ then do let diagnostics = case typecheckModulesWithHoles modules of Left err -> [diagnoseTypeError BottomUp err]- Right (_decls, errors, holes) ->+ Right (Checked _ctx _decls errors, holes) -> map (diagnoseTypeError BottomUp) errors ++ map diagnoseHole holes BL8.putStrLn (encode diagnostics) when (any ((== SeverityError) . diagnosticSeverity) diagnostics) exitFailure else if allowHolesFlag then case typecheckModulesWithHoles modules of Left err -> reportError err >> exitFailure- Right (_decls, errors, holes) -> do+ Right (Checked _ctx _decls errors, holes) -> do forM_ holes (putStr . ppHoleInfo) case errors of [] -> putStrLn ("Everything is ok! (" <> show (length holes) <> " hole(s))") _ -> do forM_ errors reportError; exitFailure- else case defaultTypeCheck (typecheckModulesWithLocation modules) of+ else case typecheckModules modules of Left err -> reportError err >> exitFailure- Right _decls -> putStrLn "Everything is ok!"+ Right _checked -> putStrLn "Everything is ok!" Lsp -> #ifdef LSP_ENABLED
rzk.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack name: rzk-version: 0.9.2+version: 0.10.0 synopsis: An experimental proof assistant for synthetic ∞-categories description: Please see the README on GitHub at <https://github.com/rzk-lang/rzk#readme> category: Dependent Types@@ -32,12 +32,14 @@ test/typecheck/cases/happy-modal-tope-unwrap.rzk test/typecheck/cases/happy-modal-topes.rzk test/typecheck/cases/happy-multivar-binder.rzk+ test/typecheck/cases/happy-nbe-church-conversion.rzk test/typecheck/cases/happy-op-hom-to-hom.rzk test/typecheck/cases/happy-recbot-term-wellformed.rzk test/typecheck/cases/happy-recor-guard-exceeds-context.rzk test/typecheck/cases/happy-recor-split-simplex-overhang.rzk test/typecheck/cases/happy-refl-path.rzk test/typecheck/cases/happy-restrict-face-not-contained.rzk+ test/typecheck/cases/happy-set-option-warn-overhang.rzk test/typecheck/cases/happy-shott-simplicial-subcomplexes.rzk test/typecheck/cases/happy-subtype-variance-pi-shape-domain.rzk test/typecheck/cases/happy-subtype-variance-restriction-faces.rzk@@ -77,6 +79,7 @@ test/typecheck/cases/ill-modal-sharp-under-flat.rzk test/typecheck/cases/ill-modal-sharp-under-op.rzk test/typecheck/cases/ill-modal-tope-cross-modality.rzk+ test/typecheck/cases/ill-nbe-church-unequal.rzk test/typecheck/cases/ill-not-function.rzk test/typecheck/cases/ill-not-pair-first-unit.rzk test/typecheck/cases/ill-not-pair-second-unit.rzk@@ -142,12 +145,14 @@ test/typecheck/cases/happy-modal-tope-unwrap.expect.yaml test/typecheck/cases/happy-modal-topes.expect.yaml test/typecheck/cases/happy-multivar-binder.expect.yaml+ test/typecheck/cases/happy-nbe-church-conversion.expect.yaml test/typecheck/cases/happy-op-hom-to-hom.expect.yaml test/typecheck/cases/happy-recbot-term-wellformed.expect.yaml test/typecheck/cases/happy-recor-guard-exceeds-context.expect.yaml test/typecheck/cases/happy-recor-split-simplex-overhang.expect.yaml test/typecheck/cases/happy-refl-path.expect.yaml test/typecheck/cases/happy-restrict-face-not-contained.expect.yaml+ test/typecheck/cases/happy-set-option-warn-overhang.expect.yaml test/typecheck/cases/happy-shott-simplicial-subcomplexes.expect.yaml test/typecheck/cases/happy-subtype-variance-pi-shape-domain.expect.yaml test/typecheck/cases/happy-subtype-variance-restriction-faces.expect.yaml@@ -187,6 +192,7 @@ test/typecheck/cases/ill-modal-sharp-under-flat.expect.yaml test/typecheck/cases/ill-modal-sharp-under-op.expect.yaml test/typecheck/cases/ill-modal-tope-cross-modality.expect.yaml+ test/typecheck/cases/ill-nbe-church-unequal.expect.yaml test/typecheck/cases/ill-not-function.expect.yaml test/typecheck/cases/ill-not-pair-first-unit.expect.yaml test/typecheck/cases/ill-not-pair-second-unit.expect.yaml@@ -255,9 +261,10 @@ library exposed-modules:- Free.Scoped- Free.Scoped.TH- Language.Rzk.Free.Syntax+ Language.Rzk.Foil.Convert+ Language.Rzk.Foil.Names+ Language.Rzk.Foil.Print+ Language.Rzk.Foil.Syntax Language.Rzk.Syntax Language.Rzk.Syntax.Abs Language.Rzk.Syntax.Layout@@ -269,7 +276,19 @@ Rzk.Format Rzk.Main Rzk.Project.Config+ Rzk.Render.Geometry Rzk.TypeCheck+ Rzk.TypeCheck.BinderTypes+ Rzk.TypeCheck.Context+ Rzk.TypeCheck.Decl+ Rzk.TypeCheck.Display+ Rzk.TypeCheck.Error+ Rzk.TypeCheck.Eval+ Rzk.TypeCheck.Judgements+ Rzk.TypeCheck.Monad+ Rzk.TypeCheck.NbE+ Rzk.TypeCheck.Render+ Rzk.TypeCheck.Unify other-modules: Paths_rzk autogen-modules:@@ -286,10 +305,15 @@ , base >=4.7 && <5 , bifunctors >=5.5.3 && <6 , bytestring >=0.10.8.2 && <1+ , containers >=0.6 && <1 , directory >=1.2.7.0 && <2+ , free-foil >=0.3.2 && <0.4+ , kind-generics >=0.5 && <1+ , kind-generics-th >=0.2 && <1 , mtl >=2.2.2 && <3 , template-haskell >=2.14.0.0 && <3 , text >=1.2.3.1 && <3+ , transformers >=0.5 && <1 , yaml >=0.11.0.0 && <1 default-language: Haskell2010 if flag(lsp) && !impl(ghcjs)@@ -307,7 +331,6 @@ aeson >=2.0.0.0 && <3 , async >=2.2 && <3 , co-log-core >=0.3.2.0 && <1- , containers >=0.6 && <1 , data-default-class >=0.1.2.0 && <1 , filepath >=1.4.100.0 && <2 , lens >=5.0.1 && <6@@ -326,7 +349,7 @@ app default-extensions: DeriveDataTypeable- ghc-options: -Wall -Wcompat -Widentities -Werror=missing-fields -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -optP-Wno-nonportable-include-path -threaded -rtsopts -with-rtsopts=-N+ ghc-options: -Wall -Wcompat -Widentities -Werror=missing-fields -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints -optP-Wno-nonportable-include-path -threaded -rtsopts "-with-rtsopts=-N -A64m" build-depends: Glob >=0.9.3 && <1 , aeson >=1.4 && <3@@ -334,11 +357,16 @@ , base >=4.7 && <5 , bifunctors >=5.5.3 && <6 , bytestring >=0.10.8.2 && <1+ , containers >=0.6 && <1 , directory >=1.2.7.0 && <2+ , free-foil >=0.3.2 && <0.4+ , kind-generics >=0.5 && <1+ , kind-generics-th >=0.2 && <1 , mtl >=2.2.2 && <3 , rzk , template-haskell >=2.14.0.0 && <3 , text >=1.2.3.1 && <3+ , transformers >=0.5 && <1 , yaml >=0.11.0.0 && <1 default-language: Haskell2010 if flag(lsp) && !impl(ghcjs)@@ -364,12 +392,17 @@ , base >=4.11.0.0 && <5.0 , bifunctors >=5.5.3 && <6 , bytestring >=0.10.8.2 && <1+ , containers >=0.6 && <1 , directory >=1.2.7.0 && <2 , doctest-parallel >=0.3 && <1+ , free-foil >=0.3.2 && <0.4+ , kind-generics >=0.5 && <1+ , kind-generics-th >=0.2 && <1 , mtl >=2.2.2 && <3 , rzk , template-haskell >=2.14.0.0 && <3 , text >=1.2.3.1 && <3+ , transformers >=0.5 && <1 , yaml >=0.11.0.0 && <1 default-language: Haskell2010 if flag(lsp) && !impl(ghcjs)@@ -381,6 +414,7 @@ other-modules: Rzk.BinderTypesSpec Rzk.DiagnosticSpec+ Rzk.FoilCoreSpec Rzk.FormatSpec Rzk.HolesSpec Rzk.RefIndexSpec@@ -403,14 +437,19 @@ , base >=4.7 && <5 , bifunctors >=5.5.3 && <6 , bytestring >=0.10.8.2 && <1+ , containers >=0.6 && <1 , directory >=1.2.7.0 && <2 , filepath >=1.4 && <2+ , free-foil >=0.3.2 && <0.4 , hspec >=2.7 && <3 , hspec-discover >=2.7 && <3+ , kind-generics >=0.5 && <1+ , kind-generics-th >=0.2 && <1 , mtl >=2.2.2 && <3 , rzk , template-haskell >=2.14.0.0 && <3 , text >=1.2.3.1 && <3+ , transformers >=0.5 && <1 , yaml >=0.11.0.0 && <1 default-language: Haskell2010 if flag(lsp) && !impl(ghcjs)
− src/Free/Scoped.hs
@@ -1,123 +0,0 @@-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE QuantifiedConstraints #-}-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE StandaloneDeriving #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeOperators #-}-{-# LANGUAGE UndecidableInstances #-}-module Free.Scoped where--import Control.Monad (ap)-import Data.Bifoldable-import Data.Bifunctor-import Data.Bifunctor.TH-import Data.Bitraversable-import Data.Function (on)-import qualified GHC.Generics as GHC--data Inc var = Z | S var- deriving (Eq, Show, Functor, Foldable, Traversable)--type Scope term var = term (Inc var)--instantiate :: Monad f => f a -> f (Inc a) -> f a-instantiate e f = f >>= g- where- g Z = e- g (S x) = return x--abstract :: (Eq a, Functor f) => a -> f a -> f (Inc a)-abstract x e = k <$> e- where- k y | x == y = Z- | otherwise = S y--data FS t a- = Pure a- | Free (t (Scope (FS t) a) (FS t a))--deriving instance (Eq a, forall x y. (Eq x, Eq y) => Eq (t x y)) => Eq (FS t a)--instance Bifunctor t => Functor (FS t) where- fmap f (Pure x) = Pure (f x)- fmap f (Free t) = Free- (bimap (fmap (fmap f)) (fmap f) t)--instance Bifoldable t => Foldable (FS t) where- foldMap f (Pure x) = f x- foldMap f (Free t) = bifoldMap (foldMap (foldMap f)) (foldMap f) t--instance Bitraversable t => Traversable (FS t) where- traverse f (Pure x) = Pure <$> f x- traverse f (Free t) = Free <$>- bitraverse (traverse (traverse f)) (traverse f) t--instance Bifunctor t => Applicative (FS t) where- pure = Pure- (<*>) = ap--instance Bifunctor t => Monad (FS t) where- return = pure- Pure x >>= f = f x- Free t >>= f = Free- (bimap ((>>= traverse f)) (>>= f) t)--data Sum f g scope term- = InL (f scope term)- | InR (g scope term)- deriving (Functor, Foldable, Traversable, GHC.Generic)-deriveBifunctor ''Sum-deriveBifoldable ''Sum-deriveBitraversable ''Sum--type (:+:) = Sum--data Empty scope term- deriving (Functor, Foldable, Traversable)-deriveBifunctor ''Empty-deriveBifoldable ''Empty-deriveBitraversable ''Empty--data AnnF ann term scope typedTerm = AnnF- { annF :: ann typedTerm- , termF :: term scope typedTerm- } deriving (Show, Functor)---- | Important: does not compare the `annF` component!-instance Eq (term scope typedTerm) => Eq (AnnF ann term scope typedTerm) where- (==) = (==) `on` termF--instance (Functor ann, Bifunctor term) => Bifunctor (AnnF ann term) where- bimap f g (AnnF t x) = AnnF (fmap g t) (bimap f g x)---- | Important: does not fold over the 'annF' component!-instance Bifoldable term => Bifoldable (AnnF ann term) where- bifoldMap f g (AnnF _ty x) = {- g ty <> -} bifoldMap f g x--instance (Traversable ann, Bitraversable term) => Bitraversable (AnnF ann term) where- bitraverse f g (AnnF t x) = AnnF <$> traverse g t <*> bitraverse f g x--transFS- :: (Bifunctor term)- => (forall s t. term s t -> term' s t)- -> FS term a -> FS term' a-transFS phi = \case- Pure x -> Pure x- Free t -> Free (phi (bimap (transFS phi) (transFS phi) t))--untyped :: (Functor ann, Bifunctor term) => FS (AnnF ann term) a -> FS term a-untyped = transFS termF--pattern ExtE :: ext (Scope (FS (t :+: ext)) a) (FS (t :+: ext) a) -> FS (t :+: ext) a-pattern ExtE t = Free (InR t)--substitute :: Bifunctor t => FS t a -> Scope (FS t) a -> FS t a-substitute t = (>>= f)- where- f Z = t- f (S y) = Pure y
− src/Free/Scoped/TH.hs
@@ -1,120 +0,0 @@-{-# LANGUAGE CPP #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE TemplateHaskell #-}-module Free.Scoped.TH where--import Control.Monad (replicateM)-import Free.Scoped-import Language.Haskell.TH--mkConP :: Name -> [Pat] -> Pat-#if __GLASGOW_HASKELL__ >= 902-mkConP name pats = ConP name [] pats-#else-mkConP name pats = ConP name pats-#endif--makePatternsAll :: Name -> Q [Dec]-makePatternsAll ty = do- TyConI tyCon <- reify ty- case tyCon of- DataD _ _ _ _ cs _ -> concat <$> do- xs <- mapM makePatternFor cs- xs' <- makeCompletePragma cs- ys <- mapM makePatternEFor cs- ys' <- makeCompletePragmaE cs- zs <- mapM makePatternTFor cs- zs' <- makeCompletePragmaT cs- ws <- mapM makePatternTEFor cs- ws' <- makeCompletePragmaTE cs- return (xs ++ [xs'] ++ ys ++ [ys'] ++ zs ++ [zs'] ++ ws ++ [ws'])-- _ -> fail "Can only make patterns for data types."---makeCompletePragma :: [Con] -> Q [Dec]-makeCompletePragma cs = do- DataConI varName _ _ <- reify 'Pure- let names = [mkName (removeF (nameBase name)) | NormalC name _ <- cs]- return [PragmaD (CompleteP (varName : names) Nothing)]- where- removeF s = take (length s - 1) s--makeCompletePragmaE :: [Con] -> Q [Dec]-makeCompletePragmaE cs = do- DataConI varName _ _ <- reify 'Pure- PatSynI extName _ <- reify 'ExtE- let names = [mkName (removeF (nameBase name)) | NormalC name _ <- cs]- return [PragmaD (CompleteP (varName : extName : names) Nothing)]- where- removeF s = take (length s - 1) s <> "E"--makeCompletePragmaT :: [Con] -> Q [Dec]-makeCompletePragmaT cs = do- DataConI varName _ _ <- reify 'Pure- let names = [mkName (removeF (nameBase name)) | NormalC name _ <- cs]- return [PragmaD (CompleteP (varName : names) Nothing)]- where- removeF s = take (length s - 1) s <> "T"--makeCompletePragmaTE :: [Con] -> Q [Dec]-makeCompletePragmaTE cs = do- DataConI varName _ _ <- reify 'Pure- let names = [mkName (removeF (nameBase name)) | NormalC name _ <- cs]- return [PragmaD (CompleteP (varName : names) Nothing)]- where- removeF s = take (length s - 1) s <> "TE"--makePatternFor :: Con -> Q [Dec]-makePatternFor = \case- NormalC name xs -> do- args <- replicateM (length xs) (newName "x")- let patName = mkName (removeF (nameBase name))- patArgs = PrefixPatSyn args- dir = ImplBidir- pat <- [p| Free $(pure (mkConP name (VarP <$> args))) |]- return [PatSynD patName patArgs dir pat]- _ -> fail "Can only make patterns for NormalC constructors"- where- removeF s = take (length s - 1) s--makePatternEFor :: Con -> Q [Dec]-makePatternEFor = \case- NormalC name xs -> do- args <- replicateM (length xs) (newName "x")- let patName = mkName (removeF (nameBase name))- patArgs = PrefixPatSyn args- dir = ImplBidir- pat <- [p| Free (InL $(pure (mkConP name (VarP <$> args)))) |]- return [PatSynD patName patArgs dir pat]- _ -> fail "Can only make patterns for NormalC constructors"- where- removeF s = take (length s - 1) s <> "E"--makePatternTFor :: Con -> Q [Dec]-makePatternTFor = \case- NormalC name xs -> do- t <- newName "type_"- args <- replicateM (length xs) (newName "x")- let patName = mkName (removeF (nameBase name))- patArgs = PrefixPatSyn (t : args)- dir = ImplBidir- pat <- [p| Free (AnnF $(pure (VarP t)) $(pure (mkConP name (VarP <$> args)))) |]- return [PatSynD patName patArgs dir pat]- _ -> fail "Can only make patterns for NormalC constructors"- where- removeF s = take (length s - 1) s <> "T"--makePatternTEFor :: Con -> Q [Dec]-makePatternTEFor = \case- NormalC name xs -> do- t <- newName "type_"- args <- replicateM (length xs) (newName "x")- let patName = mkName (removeF (nameBase name))- patArgs = PrefixPatSyn (t : args)- dir = ImplBidir- pat <- [p| Free (InL (AnnF $(pure (VarP t)) $(pure (mkConP name (VarP <$> args))))) |]- return [PatSynD patName patArgs dir pat]- _ -> fail "Can only make patterns for NormalC constructors"- where- removeF s = take (length s - 1) s <> "TE"
+ src/Language/Rzk/Foil/Convert.hs view
@@ -0,0 +1,356 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Surface syntax to the free-foil core.+--+-- A transcription of @toTerm@ from "Language.Rzk.Foil.Names", with the variable+-- handling replaced. The environment is still a function from a surface+-- identifier to a term, as before; what changes is what happens at a binder:+--+-- * a binder is a fresh 'Foil.NameBinder' rather than the de Bruijn @Z@;+-- * the environment is carried into the binder's scope with 'Foil.sink', which+-- is a coercion, where the old representation shifted every entry with+-- @S \<$\>@ and so rebuilt every term it held.+--+-- A pattern binder still binds exactly /one/ variable, as before: the components+-- of @\\ (t , s) -> …@ are projections of it, and 'Binder' records the names so+-- they can be shown back to the user.+module Language.Rzk.Foil.Convert where++import Control.Monad.Foil (Distinct, NameBinder, NameMap, Scope)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Foil.Internal (NameMap (..))+import Control.Monad.Free.Foil (AST (..), ScopedAST (..))+import Data.Data (Data, cast, gmapQ)+import Data.Functor (void)+import qualified Data.IntMap as IntMap+import Data.Map (Map)+import qualified Data.Map as Map+import qualified Data.Set as Set+import Debug.Trace (trace) -- FIXME: use proper mechanisms for warnings++import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), Display, TModality (..),+ VarIdent, holeName, toBinder, varIdent)+import qualified Language.Rzk.Foil.Names as Free+import qualified Language.Rzk.Syntax as Rzk++-- | The environment: what a surface identifier stands for in the current scope.+-- A pattern binder maps its leaves to projections of the single variable it+-- binds, which is why this is a map to /terms/ and not to names.+type Env n = VarIdent -> Term n++-- | Translate a closed surface term.+toTermClosed :: Rzk.Term -> Term Foil.VoidS+toTermClosed = toTerm Foil.emptyScope unbound+ where+ unbound x = error ("undefined variable: " <> show x)++-- | Enter a pattern binder: bind one fresh name, map the pattern's leaves to+-- projections of it, and carry the rest of the environment in with 'Foil.sink'.+toScopedPattern+ :: Distinct n+ => Scope n -> Rzk.Pattern -> Env n -> Rzk.Term -> ScopedAST NameBinder TermSig n+toScopedPattern scope pat env body =+ Foil.withFresh scope $ \binder ->+ let scope' = Foil.extendScope binder scope+ bound = bindings pat (Var (Foil.nameOf binder))+ env' x = case lookup x bound of+ Just t -> t+ Nothing -> Foil.sink (env x) -- O(1): the old representation shifted every node+ in ScopedAST binder (toTerm scope' env' body)++-- | Enter an anonymous binder (a non-dependent function type binds nothing).+toScopedAnon+ :: Distinct n+ => Scope n -> Env n -> Rzk.Term -> ScopedAST NameBinder TermSig n+toScopedAnon scope env body =+ Foil.withFresh scope $ \binder ->+ let scope' = Foil.extendScope binder scope+ in ScopedAST binder (toTerm scope' (Foil.sink . env) body)++-- | What each leaf of a pattern stands for: a projection chain over the single+-- variable the pattern binds.+bindings :: Rzk.Pattern -> Term n -> [(VarIdent, Term n)]+bindings (Rzk.PatternUnit _loc) _ = []+bindings (Rzk.PatternVar _loc (Rzk.VarIdent _ "_")) _ = []+bindings (Rzk.PatternVar _loc x) t = [(varIdent x, t)]+bindings (Rzk.PatternPair _loc l r) t = bindings l (First t) <> bindings r (Second t)+bindings (Rzk.PatternTuple loc p1 p2 ps) t =+ bindings (Free.desugarTuple loc (reverse ps) p2 p1) t++toTerm :: forall n. Distinct n => Scope n -> Env n -> Rzk.Term -> Term n+toTerm scope env = go+ where+ -- Desugar a deprecated notation, telling the user what to write instead.+ deprecated t t' = trace msg (go t')+ where+ msg = unlines+ [ "[DEPRECATED]:" <> ppBNFC'Position (Rzk.hasPosition t)+ , "the following notation is deprecated and will be removed from future version of rzk:"+ , " " <> Rzk.printTree t+ , "instead consider using the following notation:"+ , " " <> Rzk.printTree t'+ ]++ ppBNFC'Position Nothing = ""+ ppBNFC'Position (Just (line_, col)) = " at line " <> show line_ <> " column " <> show col++ -- A notation that is fine, but that a simpler one says as well.+ lint orig suggestion = trace $ unlines+ [ "[HINT]:" <> ppBNFC'Position (Rzk.hasPosition orig) <> " consider replacing"+ , " " <> Rzk.printTree orig+ , "with the following"+ , " " <> Rzk.printTree suggestion+ ]++ go :: Rzk.Term -> Term n+ go = \case+ -- ASCII aliases and deprecations are desugared exactly as before.+ t@(Rzk.RecOrDeprecated loc psi phi a_psi a_phi) -> deprecated t+ (Rzk.RecOr loc [Rzk.Restriction loc psi a_psi, Rzk.Restriction loc phi a_phi])+ t@(Rzk.TypeExtensionDeprecated loc shape type_) -> deprecated t+ (Rzk.TypeFun loc shape type_)+ t@(Rzk.TypeFun loc (Rzk.ParamTermTypeDeprecated loc' pat type_) ret) -> deprecated t+ (Rzk.TypeFun loc (Rzk.ParamTermType loc' (Free.patternToTerm pat) type_) ret)+ t@(Rzk.TypeFun loc (Rzk.ParamVarShapeDeprecated loc' pat cube tope) ret) -> deprecated t+ (Rzk.TypeFun loc (Rzk.ParamTermShape loc' (Free.patternToTerm pat) cube tope) ret)+ t@(Rzk.Lambda loc (Rzk.ParamPatternShapeDeprecated loc' pat cube tope : params) body) -> deprecated t+ (Rzk.Lambda loc (Rzk.ParamPatternShape loc' [pat] cube tope : params) body)++ Rzk.ASCII_CubeUnitStar loc -> go (Rzk.CubeUnitStar loc)+ Rzk.ASCII_Cube2_0 loc -> go (Rzk.Cube2_0 loc)+ Rzk.ASCII_Cube2_1 loc -> go (Rzk.Cube2_1 loc)+ Rzk.ASCII_TopeTop loc -> go (Rzk.TopeTop loc)+ Rzk.ASCII_TopeBottom loc -> go (Rzk.TopeBottom loc)+ Rzk.ASCII_TopeEQ loc l r -> go (Rzk.TopeEQ loc l r)+ Rzk.ASCII_TopeLEQ loc l r -> go (Rzk.TopeLEQ loc l r)+ Rzk.ASCII_TopeAnd loc l r -> go (Rzk.TopeAnd loc l r)+ Rzk.ASCII_TopeOr loc l r -> go (Rzk.TopeOr loc l r)+ Rzk.ASCII_TypeFun loc param ret -> go (Rzk.TypeFun loc param ret)+ Rzk.ASCII_TypeSigma loc pat ty ret -> go (Rzk.TypeSigma loc pat ty ret)+ Rzk.ASCII_TypeSigmaTuple loc p ps tN -> go (Rzk.TypeSigmaTuple loc p ps tN)+ Rzk.ASCII_Lambda loc pat ret -> go (Rzk.Lambda loc pat ret)+ Rzk.ASCII_TypeExtensionDeprecated loc shape type_ ->+ go (Rzk.TypeExtensionDeprecated loc shape type_)+ Rzk.ASCII_First loc term -> go (Rzk.First loc term)+ Rzk.ASCII_Second loc term -> go (Rzk.Second loc term)+ Rzk.ASCII_CubeI loc -> go (Rzk.CubeI loc)+ Rzk.ASCII_CubeI_0 loc -> go (Rzk.CubeI_0 loc)+ Rzk.ASCII_CubeI_1 loc -> go (Rzk.CubeI_1 loc)++ Rzk.Var _loc x -> env (varIdent x)+ Rzk.Universe _loc -> Universe+ Rzk.UniverseCube _loc -> UniverseCube+ Rzk.UniverseTope _loc -> UniverseTope+ Rzk.CubeUnit _loc -> CubeUnit+ Rzk.CubeUnitStar _loc -> CubeUnitStar+ Rzk.Cube2 _loc -> Cube2+ Rzk.Cube2_0 _loc -> Cube2_0+ Rzk.Cube2_1 _loc -> Cube2_1+ Rzk.CubeI _loc -> CubeI+ Rzk.CubeI_0 _loc -> CubeI_0+ Rzk.CubeI_1 _loc -> CubeI_1+ Rzk.CubeProduct _loc l r -> CubeProduct (go l) (go r)+ Rzk.TopeTop _loc -> TopeTop+ Rzk.TopeBottom _loc -> TopeBottom+ Rzk.TopeEQ _loc l r -> TopeEQ (go l) (go r)+ Rzk.TopeLEQ _loc l r -> TopeLEQ (go l) (go r)+ Rzk.TopeAnd _loc l r -> TopeAnd (go l) (go r)+ Rzk.TopeOr _loc l r -> TopeOr (go l) (go r)+ Rzk.TopeInv _loc t -> TopeInv (go t)+ Rzk.TopeUninv _loc t -> TopeUninv (go t)+ Rzk.CubeFlip _loc t -> CubeFlip (go t)+ Rzk.CubeUnflip _loc t -> CubeUnflip (go t)+ Rzk.RecBottom _loc -> RecBottom+ Rzk.RecOr _loc rs -> RecOr (map restriction rs)+ Rzk.TypeId _loc x tA y -> TypeId (go x) (Just (go tA)) (go y)+ Rzk.TypeIdSimple _loc x y -> TypeId (go x) Nothing (go y)+ Rzk.TypeUnit _loc -> TypeUnit+ Rzk.Unit _loc -> Unit+ Rzk.App _loc f x -> App (go f) (go x)+ Rzk.Pair _loc l r -> Pair (go l) (go r)+ Rzk.Tuple loc p1 p2 (p : ps) -> go (Rzk.Tuple loc (Rzk.Pair loc p1 p2) p ps)+ Rzk.Tuple loc p1 p2 [] -> go (Rzk.Pair loc p1 p2)+ Rzk.First _loc term -> First (go term)+ Rzk.Second _loc term -> Second (go term)+ Rzk.Refl _loc -> Refl Nothing+ Rzk.ReflTerm _loc term -> Refl (Just (go term, Nothing))+ Rzk.ReflTermType _loc x tA -> Refl (Just (go x, Just (go tA)))+ Rzk.IdJ _loc a b c d e f -> IdJ (go a) (go b) (go c) (go d) (go e) (go f)+ Rzk.TypeAsc _loc x t -> TypeAsc (go x) (go t)++ -- A binder may name several variables sharing a type, e.g. @(x y : A)@,+ -- which parses as an application spine; desugar into nested one-variable+ -- binders, as before.+ Rzk.TypeFun loc (Rzk.ParamTermType loc' patTerm arg) ret+ | _ : _ : _ <- vars ->+ go (foldr (\v -> Rzk.TypeFun loc (Rzk.ParamTermType loc' v arg)) ret vars)+ where vars = Free.flattenBinderApp patTerm+ Rzk.TypeFun loc (Rzk.ParamTermModalType loc' patTerm mc ty) ret+ | _ : _ : _ <- vars ->+ go (foldr (\v -> Rzk.TypeFun loc (Rzk.ParamTermModalType loc' v mc ty)) ret vars)+ where vars = Free.flattenBinderApp patTerm++ Rzk.TypeFun _loc (Rzk.ParamTermModalType _loc' patTerm mc ty) ret ->+ let pat = Free.unsafeTermToPattern patTerm+ md = Free.modalColonToTModality mc+ in TypeFun (toBinder pat) md (go ty) Nothing (toScopedPattern scope pat env ret)+ Rzk.TypeFun _loc (Rzk.ParamTermModalShape _loc' patTerm mc cube tope) ret ->+ let pat = Free.unsafeTermToPattern patTerm+ md = Free.modalColonToTModality mc+ in TypeFun (toBinder pat) md (go cube)+ (Just (toScopedPattern scope pat env tope))+ (toScopedPattern scope pat env ret)+ Rzk.TypeFun _loc (Rzk.ParamTermType _ patTerm arg) ret ->+ let pat = Free.unsafeTermToPattern patTerm+ in TypeFun (toBinder pat) Id (go arg) Nothing (toScopedPattern scope pat env ret)+ t@(Rzk.TypeFun loc (Rzk.ParamTermShape loc' patTerm cube tope) ret) ->+ let lint' = case tope of+ -- a shape whose tope is a predicate applied to exactly the binder+ -- is the type of that predicate, and says so more directly+ Rzk.App _loc fun arg | void arg == void patTerm ->+ lint t (Rzk.TypeFun loc (Rzk.ParamTermType loc' patTerm fun) ret)+ _ -> id+ pat = Free.unsafeTermToPattern patTerm+ in lint' $ TypeFun (toBinder pat) Id (go cube)+ (Just (toScopedPattern scope pat env tope))+ (toScopedPattern scope pat env ret)+ Rzk.TypeFun _loc (Rzk.ParamType _ arg) ret ->+ TypeFun (BinderVar Nothing) Id (go arg) Nothing (toScopedAnon scope env ret)++ Rzk.TypeSigma _loc pat tA tB ->+ TypeSigma (toBinder pat) Id (go tA) (toScopedPattern scope pat env tB)+ Rzk.TypeSigmaModal _loc pat mc ty body ->+ TypeSigma (toBinder pat) (Free.modalColonToTModality mc) (go ty)+ (toScopedPattern scope pat env body)+ Rzk.TypeSigmaTuple loc (Rzk.SigmaParamModal _loc' pat mc ty) rest body ->+ let tailSigma = case rest of+ [] -> body+ [sp] -> Free.sigmaParamToTypeSigma loc sp body+ (sp:sps) -> Rzk.TypeSigmaTuple loc sp sps body+ in TypeSigma (toBinder pat) (Free.modalColonToTModality mc) (go ty)+ (toScopedPattern scope pat env tailSigma)+ Rzk.TypeSigmaTuple loc (Rzk.SigmaParam _ patA tA) (mp@Rzk.SigmaParamModal{} : rest) body ->+ go (Rzk.TypeSigma loc patA tA (case rest of+ [] -> Free.sigmaParamToTypeSigma loc mp body+ _ -> Rzk.TypeSigmaTuple loc mp rest body))+ Rzk.TypeSigmaTuple loc (Rzk.SigmaParam _ patA tA) (Rzk.SigmaParam _ patB tB : ps) tN ->+ go (Rzk.TypeSigmaTuple loc (Rzk.SigmaParam loc patX tX) ps tN)+ where+ patX = Rzk.PatternPair loc patA patB+ tX = Rzk.TypeSigma loc patA tA tB+ Rzk.TypeSigmaTuple loc (Rzk.SigmaParam _ pat tA) [] tB -> go (Rzk.TypeSigma loc pat tA tB)++ Rzk.Lambda loc (Rzk.ParamPatternModalType _ [] _mc _ty : params) body ->+ go (Rzk.Lambda loc params body)+ Rzk.Lambda loc (Rzk.ParamPatternModalType loc' (pat:pats) mc ty : params) body ->+ Lambda (toBinder pat) (Just (LambdaParam (Free.modalColonToTModality mc) (go ty) Nothing))+ (toScopedPattern scope pat env+ (Rzk.Lambda loc (if null pats then params else Rzk.ParamPatternModalType loc' pats mc ty : params) body))+ Rzk.Lambda loc (Rzk.ParamPatternModalShape _ [] _mc _cube _tope : params) body ->+ go (Rzk.Lambda loc params body)+ Rzk.Lambda loc (Rzk.ParamPatternModalShape loc' (pat:pats) mc cube tope : params) body ->+ Lambda (toBinder pat)+ (Just (LambdaParam (Free.modalColonToTModality mc) (go cube)+ (Just (toScopedPattern scope pat env tope))))+ (toScopedPattern scope pat env+ (Rzk.Lambda loc (if null pats then params else Rzk.ParamPatternModalShape loc' pats mc cube tope : params) body))+ Rzk.Lambda _loc [] body -> go body+ Rzk.Lambda loc (Rzk.ParamPattern _ pat : params) body ->+ Lambda (toBinder pat) Nothing+ (toScopedPattern scope pat env (Rzk.Lambda loc params body))+ Rzk.Lambda loc (Rzk.ParamPatternType _ [] _ty : params) body ->+ go (Rzk.Lambda loc params body)+ Rzk.Lambda loc (Rzk.ParamPatternType loc' (pat:pats) ty : params) body ->+ Lambda (toBinder pat) (Just (LambdaParam Id (go ty) Nothing))+ (toScopedPattern scope pat env+ (Rzk.Lambda loc (Rzk.ParamPatternType loc' pats ty : params) body))+ Rzk.Lambda loc (Rzk.ParamPatternShape _ [] _cube _tope : params) body ->+ go (Rzk.Lambda loc params body)+ t@(Rzk.Lambda loc (Rzk.ParamPatternShape loc' (pat:pats) cube tope : params) body) ->+ let lint' = case tope of+ Rzk.App _loc fun arg+ | null pats && void arg == void (Free.patternToTerm pat) ->+ lint t (Rzk.Lambda loc (Rzk.ParamPatternType loc' [pat] fun : params) body)+ _ -> id+ in lint' $ Lambda (toBinder pat)+ (Just (LambdaParam Id (go cube) (Just (toScopedPattern scope pat env tope))))+ (toScopedPattern scope pat env+ (Rzk.Lambda loc (Rzk.ParamPatternShape loc' pats cube tope : params) body))++ Rzk.Let _loc (Rzk.BindPattern _ pat) val expr ->+ Let (toBinder pat) Nothing (go val) (toScopedPattern scope pat env expr)+ Rzk.Let _loc (Rzk.BindPatternType _ pat ty) val expr ->+ Let (toBinder pat) (Just (go ty)) (go val) (toScopedPattern scope pat env expr)++ Rzk.TypeRestricted _loc ty rs -> TypeRestricted (go ty) (map restriction rs)+ Rzk.Hole _loc (Rzk.HoleIdent _ (Rzk.HoleIdentToken tok)) -> Hole (holeName tok)+ Rzk.ModApp _loc md body -> ModApp (Free.toModality md) (go body)+ Rzk.ModType _loc md ty -> TypeModal (Free.toModality md) (go ty)+ Rzk.ModExtract{} -> error "$extract$ is an internal term and cannot appear in source"+ Rzk.LetMod _loc comp (Rzk.BindPattern _ pat) val body ->+ let (app, inn) = Free.modCompToMods comp+ in LetMod (toBinder pat) app inn Nothing (go val)+ (toScopedPattern scope pat env body)+ Rzk.LetMod _loc comp (Rzk.BindPatternType _ pat ty) val body ->+ let (app, inn) = Free.modCompToMods comp+ in LetMod (toBinder pat) app inn (Just (go ty)) (go val)+ (toScopedPattern scope pat env body)++ restriction = \case+ Rzk.Restriction _loc tope term -> (go tope, go term)+ Rzk.ASCII_Restriction _loc tope term -> (go tope, go term)++-- * Open terms++-- | Elaborate a surface term whose free identifiers are not known in advance.+--+-- Each identifier occurring anywhere in the term gets a name in a fresh scope, so+-- an /open/ term (the annotation of a binder, say, taken out of its context) can be+-- put into the core, transformed, and printed back with the names it came in with.+-- The reference index needs this: it splits the annotation of a pair binder through+-- the core, and has no typing context to hand.+withOpenTerm+ :: forall r. Rzk.Term+ -> (forall n. Distinct n+ => Foil.Scope n -> NameMap n Display -> Term n -> r)+ -> r+withOpenTerm term k = go Foil.emptyScope [] Map.empty idents+ where+ idents = nubOrd (map varIdent (collectVarIdents term))++ go :: forall n. Distinct n+ => Foil.Scope n -> [(VarIdent, Foil.Name n)] -> Map VarIdent Display+ -> [VarIdent] -> r+ go scope bound names [] =+ k scope (namesOf bound names) (toTerm scope (envOf bound) term)+ go scope bound names (x : xs) =+ Foil.withFresh scope $ \binder ->+ let scope' = Foil.extendScope binder scope+ bound' = (x, Foil.nameOf binder) : map (fmap Foil.sink) bound+ in go scope' bound' (Map.insert x (x, BinderVar (Just x)) names) xs++ envOf bound x = case lookup x bound of+ Just v -> Var v+ -- unreachable: every identifier occurring in the term was given a name above+ Nothing -> error ("withOpenTerm: uncollected identifier " <> show x)++ namesOf bound names = NameMap $ IntMap.fromList+ [ (Foil.nameId v, display)+ | (x, v) <- bound+ , Just display <- [Map.lookup x names]+ ]++-- | Every identifier occurring in a piece of surface syntax, bound or free.+collectVarIdents :: Data a => a -> [Rzk.VarIdent]+collectVarIdents x =+ maybe [] (:[]) (cast x) ++ concat (gmapQ collectVarIdents x)++nubOrd :: Ord a => [a] -> [a]+nubOrd = Set.toList . Set.fromList
+ src/Language/Rzk/Foil/Names.hs view
@@ -0,0 +1,352 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++-- | Surface names, binders and modalities.+--+-- These are what the checker shows the user, and they are independent of how a+-- term represents its variables: a 'VarIdent' is a surface identifier (with the+-- position of its defining occurrence), and a 'Binder' records the /names/ a binder+-- introduces — including a pair pattern, which still binds exactly one variable+-- whose components are projections of it.+module Language.Rzk.Foil.Names where++import Data.Char (chr, ord)+import Data.Coerce (coerce)+import Data.List (intercalate)+import Data.Maybe (fromMaybe)+import Data.String (IsString (..))+import Data.Set (Set)+import qualified Data.Set as Set+import qualified Data.Text as T++import qualified Language.Rzk.Syntax as Rzk++-- | An identifier that is not in scope becomes a hole under a /marked/ name.+--+-- A free-foil term refers to a variable by name, and an unresolved identifier has+-- none — so the term cannot represent it. Elaboration marks it instead, and the+-- checker reports it when it reaches it, which is what keeps the error where the+-- identifier was used (inside the binders and topes it was written under) rather+-- than at the top of the declaration.+--+-- The marker cannot be mistaken for a hole the user wrote: the grammar forbids @#@+-- in an identifier.+markUnresolved :: VarIdent -> VarIdent+markUnresolved x = fromString ('#' : show x)++unmarkUnresolved :: VarIdent -> Maybe VarIdent+unmarkUnresolved x = case show x of+ '#' : name -> Just (fromString name)+ _ -> Nothing++-- | What a bound name is shown as: the display name standing for the variable+-- itself, and the (freshened) binder, which gives the pattern to print and the+-- component names to fold projections back to.+type Display = (VarIdent, Binder)++-- | The annotation on every node of a typed term: its type, plus its memoised weak+-- head and normal forms.+data TypeInfo term = TypeInfo+ { infoType :: term+ , infoWHNF :: Maybe term+ , infoNF :: Maybe term+ } deriving (Functor, Foldable, Traversable)++data RzkPosition = RzkPosition+ { rzkFilePath :: Maybe FilePath+ , rzkLineCol :: Rzk.BNFC'Position+ }++ppRzkPosition :: RzkPosition -> String+ppRzkPosition RzkPosition{..} = intercalate ":" $ concat+ [ [fromMaybe "<stdin>" rzkFilePath]+ , foldMap (\(row, col) -> map show [row, col]) rzkLineCol]++newtype VarIdent = VarIdent { getVarIdent :: Rzk.VarIdent' RzkPosition }++instance Show VarIdent where+ show = Rzk.printTree . getVarIdent++-- | Identifiers are equal when they are spelled the same, whatever their source+-- positions.+--+-- Written out rather than @(==) \`on\` (void . getVarIdent)@, which allocated a+-- position-free copy of the whole syntax node and compared that: identifier+-- equality is on the hot path (every name lookup, every refreshing of a display+-- name, every match of two terms that mention a hole), and profiling put it at 6%+-- of the checker's time.+instance Eq VarIdent where+ VarIdent (Rzk.VarIdent _ x) == VarIdent (Rzk.VarIdent _ y) = x == y++-- | Identifiers are ordered by name, ignoring the source position, so that the+-- order agrees with 'Eq'. Only used to key identifiers in a set or a map.+instance Ord VarIdent where+ compare (VarIdent (Rzk.VarIdent _ x)) (VarIdent (Rzk.VarIdent _ y)) = compare x y++instance IsString VarIdent where+ fromString s = VarIdent (Rzk.VarIdent (RzkPosition Nothing Nothing) (fromString s))++ppVarIdentWithLocation :: VarIdent -> String+ppVarIdentWithLocation (VarIdent var@(Rzk.VarIdent pos _ident)) =+ Rzk.printTree var <> " (" <> ppRzkPosition pos <> ")"++varIdent :: Rzk.VarIdent -> VarIdent+varIdent = varIdentAt Nothing++varIdentAt :: Maybe FilePath -> Rzk.VarIdent -> VarIdent+varIdentAt path (Rzk.VarIdent pos ident) = VarIdent (Rzk.VarIdent (RzkPosition path pos) ident)++fromVarIdent :: VarIdent -> Rzk.VarIdent+fromVarIdent (VarIdent (Rzk.VarIdent (RzkPosition _file pos) ident)) = Rzk.VarIdent pos ident++-- | The display name of a hole from its surface token text. The token includes+-- the leading @?@; an anonymous hole (bare @?@) has no name.+holeName :: T.Text -> Maybe VarIdent+holeName tok =+ case T.drop 1 tok of+ name | T.null name -> Nothing+ | otherwise -> Just (fromString (T.unpack name))++-- | The surface token text (including the leading @?@) for a hole name.+holeIdentToken :: Maybe VarIdent -> T.Text+holeIdentToken Nothing = "?"+holeIdentToken (Just x) = "?" <> T.pack (show x)++-- | The name(s) a binder introduces. A binder may name a single (possibly+-- anonymous) variable, or destructure a pair\/tuple via a pattern. The pattern+-- structure is kept around purely so that goals, holes and error messages can+-- show the user's original names (e.g. @t@ and @s@ for @\\ (t , s) -> …@)+-- instead of projections of a fresh variable (e.g. @π₁ x₄@ and @π₂ x₄@).+--+-- Operationally a pair pattern still binds a /single/ variable; the components+-- are projections of it (see 'toScopePattern'). 'Binder' only records the names+-- so they can be restored when rendering.+data Binder+ = BinderVar (Maybe VarIdent) -- ^ a single variable (@Nothing@ for @_@)+ | BinderPair Binder Binder -- ^ a pair pattern @(l , r)@+ | BinderUnit -- ^ the unit pattern @unit@+ deriving (Eq)++-- | The single name of a binder, if it binds exactly one named variable.+-- A pair\/unit pattern has no single name, so this is 'Nothing' for them.+-- Used wherever the old @Maybe VarIdent@ binder name is still sufficient.+binderName :: Binder -> Maybe VarIdent+binderName (BinderVar mname) = mname+binderName _ = Nothing++data TModality = Sharp | Flat | Op | Id deriving (Eq, Show)++toModality :: Rzk.Modality -> TModality+toModality Rzk.Sharp{} = Sharp+toModality Rzk.ASCII_Sharp{} = Sharp+toModality Rzk.Flat{} = Flat+toModality Rzk.ASCII_Flat{} = Flat+toModality Rzk.Op{} = Op+toModality Rzk.ASCII_Op{} = Op+toModality Rzk.Id{} = Id++modCompToMods :: Rzk.ModComp -> (TModality, TModality)+modCompToMods (Rzk.Single _ m) = (Id, toModality m)+modCompToMods (Rzk.Comp _ ext inn) = (toModality ext, toModality inn)++fromMod :: TModality -> Rzk.Modality+fromMod Sharp = Rzk.Sharp Nothing+fromMod Flat = Rzk.Flat Nothing+fromMod Op = Rzk.Op Nothing+fromMod Id = Rzk.Id Nothing++modsToModComp :: TModality -> TModality -> Rzk.ModComp+modsToModComp Id inn = Rzk.Single Nothing (fromMod inn)+modsToModComp ext inn = Rzk.Comp Nothing (fromMod ext) (fromMod inn)+++-- | A tuple pattern is sugar for nested pairs.+desugarTuple :: Rzk.BNFC'Position -> [Rzk.Pattern] -> Rzk.Pattern -> Rzk.Pattern -> Rzk.Pattern+desugarTuple loc ps p2 p1 =+ case ps of+ [] -> Rzk.PatternPair loc p1 p2+ pLast : ps' -> Rzk.PatternPair loc (desugarTuple loc ps' p2 p1) pLast+++toBinder :: Rzk.Pattern -> Binder+toBinder (Rzk.PatternVar _loc (Rzk.VarIdent _ "_")) = BinderVar Nothing+toBinder (Rzk.PatternVar _loc x) = BinderVar (Just (varIdent x))+toBinder (Rzk.PatternUnit _loc) = BinderUnit+toBinder (Rzk.PatternPair _loc l r) = BinderPair (toBinder l) (toBinder r)+toBinder (Rzk.PatternTuple loc p1 p2 ps) = toBinder (desugarTuple loc (reverse ps) p2 p1)++patternToTerm :: Rzk.Pattern -> Rzk.Term+patternToTerm = ptt+ where+ ptt = \case+ Rzk.PatternVar loc x -> Rzk.Var loc x+ Rzk.PatternPair loc l r -> Rzk.Pair loc (ptt l) (ptt r)+ Rzk.PatternUnit loc -> Rzk.Unit loc+ Rzk.PatternTuple loc p1 p2 ps -> patternToTerm (desugarTuple loc (reverse ps) p2 p1)+++modalColonModality :: Rzk.ModalColon -> Rzk.Modality+modalColonModality = \case+ Rzk.ModalColonFlat loc -> Rzk.Flat loc+ Rzk.ModalColonSharp loc -> Rzk.Sharp loc+ Rzk.ModalColonOp loc -> Rzk.Op loc+ Rzk.ModalColonId loc -> Rzk.Id loc+ Rzk.ASCII_ModalColonFlat loc -> Rzk.Flat loc+ Rzk.ASCII_ModalColonSharp loc -> Rzk.Sharp loc+ Rzk.ASCII_ModalColonOp loc -> Rzk.Op loc++modalColonToTModality :: Rzk.ModalColon -> TModality+modalColonToTModality = toModality . modalColonModality++fromTModalityToModalColon :: TModality -> Rzk.ModalColon+fromTModalityToModalColon = \case+ Sharp -> Rzk.ModalColonSharp Nothing+ Flat -> Rzk.ModalColonFlat Nothing+ Op -> Rzk.ModalColonOp Nothing+ Id -> Rzk.ModalColonId Nothing++-- | Split a binder term into the individual variables it names. A multi-variable+-- binder like @(x y : A)@ is parsed as the application spine @x y@; this returns+-- @[x, y]@ so each can become its own nested binder. A single binder term (a+-- variable, a pair pattern, …) is returned unchanged as a singleton.+flattenBinderApp :: Rzk.Term -> [Rzk.Term]+flattenBinderApp = \case+ Rzk.App _loc f x -> flattenBinderApp f ++ [x]+ t -> [t]++unsafeTermToPattern :: Rzk.Term -> Rzk.Pattern+unsafeTermToPattern = ttp+ where+ ttp = \case+ Rzk.Unit loc -> Rzk.PatternUnit loc+ Rzk.Var loc x -> Rzk.PatternVar loc x+ Rzk.Pair loc l r -> Rzk.PatternPair loc (ttp l) (ttp r)+ Rzk.Tuple loc t1 t2 ts -> Rzk.PatternTuple loc (ttp t1) (ttp t2) (map ttp ts)+ term -> error ("ERROR: expected a pattern but got\n " ++ Rzk.printTree term)++sigmaParamToTypeSigma :: Rzk.BNFC'Position -> Rzk.SigmaParam -> Rzk.Term -> Rzk.Term+sigmaParamToTypeSigma loc sp body = case sp of+ Rzk.SigmaParam _ pat ty -> Rzk.TypeSigma loc pat ty body+ Rzk.SigmaParamModal _ pat mc ty -> Rzk.TypeSigmaModal loc pat mc ty body++-- | A projection step: first (@π₁@) or second (@π₂@) component.+data Proj = PFst | PSnd+ deriving (Eq)++-- | Render a 'Binder' as a surface pattern (used to display the binder itself,+-- e.g. @(t , s)@). Anonymous variables become @_@.+binderToPattern :: Binder -> Rzk.Pattern+binderToPattern (BinderVar Nothing) = Rzk.PatternVar Nothing (fromVarIdent "_")+binderToPattern (BinderVar (Just x)) = Rzk.PatternVar Nothing (fromVarIdent x)+binderToPattern (BinderPair l r) = Rzk.PatternPair Nothing (binderToPattern l) (binderToPattern r)+binderToPattern BinderUnit = Rzk.PatternUnit Nothing++++-- | A 'VarIdent' that prints as the binder's surface pattern, e.g. @(t , s)@.+-- Used to display a pattern binder in a hole's local context as the pattern+-- itself rather than as the underlying single variable.+binderDisplayName :: Binder -> VarIdent+binderDisplayName = fromString . Rzk.printTree . binderToPattern++-- | The named leaves of a binder, each paired with the projection path that+-- reaches it from the bound variable. For example @(t , (a , b))@ yields+-- @[([PFst], t), ([PSnd, PFst], a), ([PSnd, PSnd], b)]@.+binderPaths :: Binder -> [([Proj], VarIdent)]+binderPaths (BinderVar (Just x)) = [([], x)]+binderPaths (BinderVar Nothing) = []+binderPaths BinderUnit = []+binderPaths (BinderPair l r) =+ [ (PFst : p, n) | (p, n) <- binderPaths l ] +++ [ (PSnd : p, n) | (p, n) <- binderPaths r ]++-- | The names appearing in a binder.+binderLeaves :: Binder -> [VarIdent]+binderLeaves = map snd . binderPaths++-- | Does this binder destructure a pair\/tuple (as opposed to naming a single+-- variable or @_@)?+binderIsCompound :: Binder -> Bool+binderIsCompound BinderVar{} = False+binderIsCompound _ = True++-- | Refresh the named leaves of a binder so they avoid the given names (and one+-- another). Anonymous leaves and the unit pattern are left unchanged.+freshenBinderLeaves :: [VarIdent] -> Binder -> Binder+freshenBinderLeaves used = snd . go used+ where+ go u (BinderVar (Just x)) = let x' = refreshVar u x in (x' : u, BinderVar (Just x'))+ go u b@(BinderVar Nothing) = (u, b)+ go u BinderUnit = (u, BinderUnit)+ go u (BinderPair l r) =+ let (u1, l') = go u l+ (u2, r') = go u1 r+ in (u2, BinderPair l' r')++-- | Decompose a chain of projections applied to a variable into the projection+-- path /from the variable outwards/, matching 'binderPaths'. The outermost+-- projection is applied last, so it goes at the /end/ of the path: e.g.+-- @π₂ (π₁ x)@ (select @π₁@ first, then @π₂@) becomes @Just ([PFst, PSnd], x)@.++defaultVarIdents :: [VarIdent]+defaultVarIdents =+ [ fromString name+ | n <- [1 :: Int ..]+ , let name = "x" <> map digitToSub (show n) ]+ where+ digitToSub c = chr ((ord c - ord '0') + ord '₀')++-- $setup+-- >>> :set -XOverloadedStrings+-- >>> import qualified Data.Text as T+-- >>> import qualified Data.Set as Set++-- | Given a list of used variable names in the current context,+-- generate a unique fresh name based on a given one.+--+-- >>> print $ refreshVar ["x", "y", "x₁", "z"] "x"+-- x₂+refreshVar :: [VarIdent] -> VarIdent -> VarIdent+refreshVar vars x+ | x `elem` vars = refreshVar vars (incVarIdentIndex x)+ | otherwise = x++-- | Refresh a name against a /set/ of taken ones.+--+-- The list version above is O(taken) per call, and naming a whole context calls it+-- once per entry, which made reading the naming off a context with every top-level+-- definition of a project in it quadratic.+--+-- >>> print $ refreshVarIn (Set.fromList ["x", "y", "x₁", "z"]) "x"+-- x₂+refreshVarIn :: Set VarIdent -> VarIdent -> VarIdent+refreshVarIn taken x+ | x `Set.member` taken = refreshVarIn taken (incVarIdentIndex x)+ | otherwise = x++incVarIdentIndex :: VarIdent -> VarIdent+incVarIdentIndex (VarIdent (Rzk.VarIdent loc token)) =+ VarIdent (Rzk.VarIdent loc (coerce incIndex token))++-- | Increment the subscript number at the end of the indentifier.+--+-- >>> putStrLn $ T.unpack $ incIndex "x"+-- x₁+-- >>> putStrLn $ T.unpack $ incIndex "x₁₉"+-- x₂₀+incIndex :: T.Text -> T.Text+incIndex s = T.pack $ name <> newIndex+ where+ digitsSub = "₀₁₂₃₄₅₆₇₈₉" :: String+ isDigitSub = (`elem` digitsSub)+ digitFromSub c = chr ((ord c - ord '₀') + ord '0')+ digitToSub c = chr ((ord c - ord '0') + ord '₀')+ (name, index) = break isDigitSub (T.unpack s)+ oldIndexN = read ('0' : map digitFromSub index) :: Int -- FIXME: read+ newIndex = map digitToSub (show (oldIndexN + 1))
+ src/Language/Rzk/Foil/Print.hs view
@@ -0,0 +1,246 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | The free-foil core back to surface syntax.+--+-- A transcription of @fromTermWith'@ from "Language.Rzk.Foil.Names". The+-- structure is the same, and so are the display rules:+--+-- * a binder's user-written name is kept, refreshed only against names already+-- in use; an anonymous binder draws from 'defaultVarIdents';+-- * a pattern binder is shown as the pattern, and projections of the variable+-- it binds are folded back to the component names, so a goal reads+-- @\\ (t , s) -> …@ and not @\\ x -> … π₁ x …@;+-- * an anonymous binder the codomain does not use is not shown at all, so+-- @(x₁ : A) → B@ prints as @A → B@.+--+-- What changes is the bookkeeping: a variable is a 'Foil.Name', so the display+-- names live in a 'Foil.NameMap' keyed by name, rather than being threaded+-- through de Bruijn shifts.+module Language.Rzk.Foil.Print where++import Control.Monad.Foil (NameMap)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Free.Foil (AST (..), ScopedAST (..))+import Data.Bifoldable (bifoldMap)++import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), Display, Proj (..),+ TModality (..),+ VarIdent, binderIsCompound,+ binderLeaves, binderPaths,+ binderToPattern, defaultVarIdents,+ fromTModalityToModalColon,+ fromVarIdent, fromMod, holeIdentToken,+ modsToModComp, patternToTerm,+ refreshVar)+import qualified Language.Rzk.Syntax as Rzk++-- | Print a closed term.+fromTermClosed :: Term Foil.VoidS -> Rzk.Term+fromTermClosed = fromTerm [] defaultVarIdents Foil.emptyNameMap++fromTerm :: forall n. [VarIdent] -> [VarIdent] -> NameMap n Display -> Term n -> Rzk.Term+fromTerm used supply names = go+ where+ loc = Nothing++ goMod :: TModality -> Rzk.Modality+ goMod = fromMod++ -- Enter a binder and print the scopes it binds over.+ --+ -- A Pi-type and a lambda each bind /two/ scopes under one binder (the shape+ -- tope and the body). In the old representation both were indexed by the+ -- same de Bruijn Z; here each 'ScopedAST' carries its own 'NameBinder'. That+ -- is operationally the same (the checker instantiates both with the same+ -- argument), but they must be /shown/ under one name, so each scope's binder+ -- is mapped to the same display name.+ withBinder1 :: Binder -> ScopedTerm n -> ((Binder, Rzk.Term) -> r) -> r+ withBinder1 z s k = withBinder z $ \z' printScope -> k (z', printScope s)++ withBinder2 :: Binder -> ScopedTerm n -> ScopedTerm n -> ((Binder, Rzk.Term, Rzk.Term) -> r) -> r+ withBinder2 z s1 s2 k =+ withBinder z $ \z' printScope -> k (z', printScope s1, printScope s2)++ withBinder+ :: Binder+ -> (Binder -> (ScopedTerm n -> Rzk.Term) -> r)+ -> r+ withBinder z k = k z' printScope+ where+ (z', supply') = freshenBinder used supply z+ x = displayNameOf z' supply'+ supply'' = case z' of+ BinderVar (Just _) -> supply'+ _ -> drop 1 supply'+ used' = x : used <> binderLeaves z'+ printScope (ScopedAST binder body) =+ fromTerm used' supply'' (Foil.addNameBinder binder (x, z') names) body++ -- The name standing for the variable itself. A single-variable binder uses+ -- its own name; a pattern binder needs a placeholder, which is only shown if+ -- the whole point is used (in a shape tope, say), and then it is printed as+ -- the pattern anyway.+ displayNameOf (BinderVar (Just x)) _ = x+ displayNameOf _ (x : _) = x+ displayNameOf _ [] = error "not enough fresh variables!"++ -- Refresh a binder's named leaves against the names already in use; draw+ -- fresh names for anonymous leaves from the remaining supply.+ freshenBinder _ stream (BinderVar Nothing) =+ case stream of+ x : xs -> (BinderVar (Just x), xs)+ _ -> error "not enough fresh variables!"+ freshenBinder used' stream (BinderVar (Just z)) =+ (BinderVar (Just z'), filter (/= z') stream)+ where z' = refreshVar used' z+ freshenBinder _ stream BinderUnit = (BinderUnit, stream)+ freshenBinder used' stream (BinderPair l r) =+ let (l', s1) = freshenBinder used' stream l+ (r', s2) = freshenBinder (used' <> binderLeaves l') s1 r+ in (BinderPair l' r', s2)++ -- A projection chain over a pattern binder's variable is shown as the+ -- component's name: @π₁ x@ is @t@.+ projChain :: Term n -> Maybe ([Proj], Foil.Name n)+ projChain (First t) = fmap (\(ps, x) -> (PFst : ps, x)) (projChain t)+ projChain (Second t) = fmap (\(ps, x) -> (PSnd : ps, x)) (projChain t)+ projChain (Var x) = Just ([], x)+ projChain _ = Nothing++ foldedProjection :: Term n -> Maybe Rzk.Term+ foldedProjection t = do+ (ps, x) <- projChain t+ case ps of+ [] -> Nothing+ _ -> do+ let (_, binder) = Foil.lookupName x names+ leaf <- lookup (reverse ps) (binderPaths binder)+ pure (Rzk.Var loc (fromVarIdent leaf))++ go :: Term n -> Rzk.Term+ go t | Just t' <- foldedProjection t = t'+ go (Var x) =+ case Foil.lookupName x names of+ -- A bare use of a pattern binder's variable (the point itself) reads as+ -- the pattern, not as the placeholder.+ (_, binder) | binderIsCompound binder -> patternToTerm (binderToPattern binder)+ (name, _) -> Rzk.Var loc (fromVarIdent name)++ go Universe = Rzk.Universe loc+ go UniverseCube = Rzk.UniverseCube loc+ go UniverseTope = Rzk.UniverseTope loc+ go CubeUnit = Rzk.CubeUnit loc+ go CubeUnitStar = Rzk.CubeUnitStar loc+ go Cube2 = Rzk.Cube2 loc+ go Cube2_0 = Rzk.Cube2_0 loc+ go Cube2_1 = Rzk.Cube2_1 loc+ go CubeI = Rzk.CubeI loc+ go CubeI_0 = Rzk.CubeI_0 loc+ go CubeI_1 = Rzk.CubeI_1 loc+ go (CubeProduct l r) = Rzk.CubeProduct loc (go l) (go r)+ go (CubeFlip t) = Rzk.CubeFlip loc (go t)+ go (CubeUnflip t) = Rzk.CubeUnflip loc (go t)+ go TopeTop = Rzk.TopeTop loc+ go TopeBottom = Rzk.TopeBottom loc+ go (TopeEQ l r) = Rzk.TopeEQ loc (go l) (go r)+ go (TopeLEQ l r) = Rzk.TopeLEQ loc (go l) (go r)+ go (TopeAnd l r) = Rzk.TopeAnd loc (go l) (go r)+ go (TopeOr l r) = Rzk.TopeOr loc (go l) (go r)+ go (TopeInv t) = Rzk.TopeInv loc (go t)+ go (TopeUninv t) = Rzk.TopeUninv loc (go t)+ go RecBottom = Rzk.RecBottom loc+ go (RecOr rs) = Rzk.RecOr loc [Rzk.Restriction loc (go tope) (go term) | (tope, term) <- rs]+ go (Hole mname) = Rzk.Hole loc (Rzk.HoleIdent loc (Rzk.HoleIdentToken (holeIdentToken mname)))++ -- An anonymous binder the codomain does not use is not shown: @(x₁ : A) → B@+ -- reads better as @A → B@. A user-written name is kept even when unused.+ go (TypeFun z@(BinderVar Nothing) Id arg Nothing ret)+ | not (scopeUsesItsBinder ret) = withBinder1 z ret $ \(_z', ret') ->+ Rzk.TypeFun loc (Rzk.ParamType loc (go arg)) ret'+ go (TypeFun z md arg Nothing ret) = withBinder1 z ret $ \(z', ret') ->+ let pat = patternToTerm (binderToPattern z')+ in case md of+ Id -> Rzk.TypeFun loc (Rzk.ParamTermType loc pat (go arg)) ret'+ _ -> Rzk.TypeFun loc (Rzk.ParamTermModalType loc pat (fromTModalityToModalColon md) (go arg)) ret'+ go (TypeFun z md arg (Just tope) ret) = withBinder2 z tope ret $ \(z', tope', ret') ->+ let pat = patternToTerm (binderToPattern z')+ in case md of+ Id -> Rzk.TypeFun loc (Rzk.ParamTermShape loc pat (go arg) tope') ret'+ _ -> Rzk.TypeFun loc (Rzk.ParamTermModalShape loc pat (fromTModalityToModalColon md) (go arg) tope') ret'++ go (TypeSigma z md a b) = withBinder1 z b $ \(z', b') ->+ case md of+ Id -> Rzk.TypeSigma loc (binderToPattern z') (go a) b'+ _ -> Rzk.TypeSigmaModal loc (binderToPattern z') (fromTModalityToModalColon md) (go a) b'++ go (TypeId l (Just tA) r) = Rzk.TypeId loc (go l) (go tA) (go r)+ go (TypeId l Nothing r) = Rzk.TypeIdSimple loc (go l) (go r)+ go (App l r) = Rzk.App loc (go l) (go r)++ go (Lambda z Nothing body) = withBinder1 z body $ \(z', body') ->+ Rzk.Lambda loc [Rzk.ParamPattern loc (binderToPattern z')] body'+ go (Lambda z (Just (LambdaParam md ty Nothing)) body) = withBinder1 z body $ \(z', body') ->+ let pat = binderToPattern z'+ param = case md of+ Id -> Rzk.ParamPatternType loc [pat] (go ty)+ _ -> Rzk.ParamPatternModalType loc [pat] (fromTModalityToModalColon md) (go ty)+ in Rzk.Lambda loc [param] body'+ go (Lambda z (Just (LambdaParam md cube (Just tope))) body) =+ withBinder2 z tope body $ \(z', tope', body') ->+ let pat = binderToPattern z'+ param = case md of+ Id -> Rzk.ParamPatternShape loc [pat] (go cube) tope'+ _ -> Rzk.ParamPatternModalShape loc [pat] (fromTModalityToModalColon md) (go cube) tope'+ in Rzk.Lambda loc [param] body'++ go (Let z mty val body) = withBinder1 z body $ \(z', body') ->+ let bind = case mty of+ Nothing -> Rzk.BindPattern loc (binderToPattern z')+ Just ty -> Rzk.BindPatternType loc (binderToPattern z') (go ty)+ in Rzk.Let loc bind (go val) body'++ go (Pair l r) = Rzk.Pair loc (go l) (go r)+ go (First t) = Rzk.First loc (go t)+ go (Second t) = Rzk.Second loc (go t)+ go TypeUnit = Rzk.TypeUnit loc+ go Unit = Rzk.Unit loc+ go (Refl Nothing) = Rzk.Refl loc+ go (Refl (Just (t, Nothing))) = Rzk.ReflTerm loc (go t)+ go (Refl (Just (t, Just ty))) = Rzk.ReflTermType loc (go t) (go ty)+ go (IdJ a b c d e f) = Rzk.IdJ loc (go a) (go b) (go c) (go d) (go e) (go f)+ go (TypeAsc l r) = Rzk.TypeAsc loc (go l) (go r)+ go (TypeRestricted ty rs) =+ Rzk.TypeRestricted loc (go ty) [Rzk.Restriction loc (go tope) (go term) | (tope, term) <- rs]+ go (TypeModal m ty) = Rzk.ModType loc (goMod m) (go ty)+ go (ModApp m t) = Rzk.ModApp loc (goMod m) (go t)+ go (ModExtract app inn t) = Rzk.ModExtract loc (Rzk.Comp loc (goMod app) (goMod inn)) (go t)+ go (LetMod z app inn mty val body) = withBinder1 z body $ \(z', body') ->+ let bind = case mty of+ Nothing -> Rzk.BindPattern loc (binderToPattern z')+ Just ty -> Rzk.BindPatternType loc (binderToPattern z') (go ty)+ in Rzk.LetMod loc (modsToModComp app inn) bind (go val) body'++-- | Does a scope actually use the variable it binds?+--+-- Compares name /ids/ rather than names, which sidesteps having to unsink the+-- inner scopes' names back into this one. Ids are unique per binder, so a hit is+-- an occurrence of exactly this binder's variable.+--+-- (free-foil's own @freeVarsOf@ would do, but it is not in the 0.2.0 release --+-- it is one of the unreleased helpers on free-foil's @main@.)+scopeUsesItsBinder :: ScopedAST Foil.NameBinder TermSig n -> Bool+scopeUsesItsBinder (ScopedAST binder body) =+ Foil.nameId (Foil.nameOf binder) `elem` nameIdsOf body++-- | Every name id occurring in a term, bound or free.+nameIdsOf :: Term l -> [Int]+nameIdsOf (Var x) = [Foil.nameId x]+nameIdsOf (Node sig) = bifoldMap goScoped nameIdsOf sig+ where+ goScoped (ScopedAST _binder body) = nameIdsOf body
+ src/Language/Rzk/Foil/Syntax.hs view
@@ -0,0 +1,750 @@+-- The 'ZipMatchK' instances below are orphans: the class is free-foil's and the+-- constant types they cover ('TModality', 'VarIdent', 'Binder') are still the old+-- module's. They come home when the old core goes away.+{-# OPTIONS_GHC -fno-warn-missing-pattern-synonym-signatures -fno-warn-orphans #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveFoldable #-}+{-# LANGUAGE DeriveFunctor #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE DeriveTraversable #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE TypeOperators #-}+{-# LANGUAGE UndecidableInstances #-}++-- | The core syntax on @free-foil@.+--+-- This is the successor of "Language.Rzk.Free.Syntax"'s @TermF@ \/ @TermT@,+-- built on 'Foil.AST' instead of the vendored @Free.Scoped@. It is compiled but+-- not yet consumed: the checker still runs on the old representation, and the+-- two are swapped over in a later stage.+--+-- Three things carry over unchanged, and are imported rather than duplicated:+-- 'VarIdent' (a surface identifier), 'Binder' (the /names/ a binder introduces,+-- including a pair pattern, which still binds exactly one variable), 'TModality',+-- and 'TypeInfo' (a node's type plus its memoised weak head and normal forms).+--+-- What changes is the variable representation. A binder is a 'Foil.NameBinder',+-- a variable is a 'Foil.Name' (an @Int@), and weakening a term into a larger+-- scope is 'Foil.sink', a coercion rather than a traversal of every node.+module Language.Rzk.Foil.Syntax where++import Control.Monad.Foil (NameBinder)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Foil.Internal (Substitution (..),+ unsafeAssertFresh)+import Control.Monad.Free.Foil (AST (..), ScopedAST (..),+ alphaEquiv,+ substitute, unsafeEqAST)+import Data.ZipMatchK (Mappings (..),+ ZipMatchK (..),+ zipMatchViaChooseLeft,+ zipMatchViaEq)+import Control.Monad.Free.Foil.Annotated (AnnSig (..))+import Data.ZipMatchK.TH (deriveZipMatchK)+import Data.Bifoldable (Bifoldable (..))+import Data.Bifunctor (Bifunctor (..))+import Data.Bifunctor.TH (deriveBifoldable,+ deriveBifunctor,+ deriveBitraversable)+import qualified Data.IntMap as IntMap+import Generics.Kind.TH (deriveGenericK)+import qualified GHC.Generics as GHC+import Unsafe.Coerce (unsafeCoerce)++import Language.Rzk.Foil.Names (Binder (..), TModality (..),+ TypeInfo (..), VarIdent)++-- * The signature+--+-- A transliteration of @TermF@: same constructors, same fields, same order. The+-- @scope@ positions are the ones that bind, and there are seven of them across+-- five constructors ('TypeFunF' and 'LambdaF' each carry a tope scope as well as+-- a body scope, under the same binder).++-- | The optional domain annotation of a λ: its modality, its parameter type,+-- and (for a shape) the tope the parameter is restricted by. It was an anonymous+-- triple in the old signature; the generic machinery needs a named type here, and+-- it reads better anyway.+data LambdaParam scope term = LambdaParam TModality term (Maybe scope)+ deriving (Eq, Functor, Foldable, Traversable, GHC.Generic)++data TermSig scope term+ = UniverseF+ | UniverseCubeF+ | UniverseTopeF+ | CubeUnitF+ | CubeUnitStarF+ | Cube2F+ | Cube2_0F+ | Cube2_1F+ | CubeIF+ | CubeI_0F+ | CubeI_1F+ | CubeProductF term term+ | CubeFlipF term+ | CubeUnflipF term+ | TopeTopF+ | TopeBottomF+ | TopeEQF term term+ | TopeLEQF term term+ | TopeAndF term term+ | TopeOrF term term+ | TopeInvF term+ | TopeUninvF term+ | RecBottomF+ | RecOrF [(term, term)]+ | TypeFunF Binder TModality term (Maybe scope) scope+ | TypeSigmaF Binder TModality term scope+ | TypeIdF term (Maybe term) term+ | AppF term term+ | LetF Binder (Maybe term) term scope+ | LambdaF Binder (Maybe (LambdaParam scope term)) scope+ | PairF term term+ | FirstF term+ | SecondF term+ | ReflF (Maybe (term, Maybe term))+ | IdJF term term term term term term+ | UnitF+ | TypeUnitF+ | TypeAscF term term+ | TypeRestrictedF term [(term, term)]+ | TypeModalF TModality term+ | ModAppF TModality term+ | ModExtractF TModality TModality term+ | LetModF Binder TModality TModality (Maybe term) term scope+ | HoleF (Maybe VarIdent)+ deriving (Eq, Functor, Foldable, Traversable, GHC.Generic)++deriveBifunctor ''LambdaParam+deriveBifoldable ''LambdaParam+deriveBitraversable ''LambdaParam+deriveGenericK ''LambdaParam++deriveBifunctor ''TermSig+deriveBifoldable ''TermSig+deriveBitraversable ''TermSig+deriveGenericK ''TermSig++-- | Matching the non-recursive fields of the signature.+--+-- A modality and a hole's name are part of the term: they must agree. A 'Binder'+-- is /not/: it records the names a binder introduces, purely so that goals and+-- error messages can show the user's own names, and two terms that differ only+-- in them are the same term. The old representation compared them (its 'Eq' was+-- derived), so @\ x -> x@ and @\ y -> y@ compared unequal; on the new one they+-- are α-equivalent, as they should be.+instance ZipMatchK TModality where+ zipMatchWithK = zipMatchViaEq++instance ZipMatchK VarIdent where+ zipMatchWithK = zipMatchViaEq++instance ZipMatchK Binder where+ zipMatchWithK = zipMatchViaChooseLeft++-- | A hole's name is a whole field ('HoleF'), so it is matched as a constant+-- rather than through the 'Maybe' functor.+instance ZipMatchK (Maybe VarIdent) where+ zipMatchWithK = zipMatchViaEq++instance ZipMatchK LambdaParam++-- | The node matcher, TH-derived: an explicit instance, so no @Generics.Kind@+-- view is rebuilt per comparison. It drives 'Control.Monad.Free.Foil.alphaEquiv'+-- and 'Control.Monad.Free.Foil.unsafeEqAST', run on every comparison of two+-- terms, which in a dependent checker is most of the work. This replaced a+-- hand-written 44-constructor matcher carried on free-foil 0.2.0 (which had no+-- deriver); the deriver is the point of moving to this free-foil.+deriveZipMatchK ''TermSig+++-- * Annotations+--+-- 'AnnSig' is @Control.Monad.Free.Foil.Annotated@'s: the annotation is a functor+-- of the signature's /term/ parameter, so a node's type is a term in the node's+-- own scope. free-foil provides it with a /derived/ (explicit) 'ZipMatchK', its+-- 'Bifunctor' (recurses into the annotation, for substitution) and its+-- 'Bifoldable' (does not, so a term's free variables exclude those only in its+-- type). All rzk adds is how its own annotation, 'TypeInfo', matches.++-- | The annotation is ignored in matching, so two terms differing only in their+-- types are α-equivalent. The 'ZipMatchK' API makes an annotation holding terms+-- construct its result through the mapping, so it cannot be dropped from the+-- match — but it is made lazy: 'infoType' below is a thunk never forced, because+-- 'AnnSig's 'Bifoldable' does not visit the annotation. So the 30-deep universe+-- tower inside a type is never walked. The memoised forms are dropped (every+-- consumer of the zipped result discards them). This is the annotation-blind+-- pattern from the 'Control.Monad.Free.Foil.Annotated' haddock.+instance ZipMatchK TypeInfo where+ zipMatchWithK (f :^: M0) (TypeInfo t1 _ _) (TypeInfo t2 _ _) =+ Just (TypeInfo (maybe (error "ZipMatchK TypeInfo: annotation forced") id (f t1 t2)) Nothing Nothing)++-- * Terms++-- | An untyped term: the surface syntax, elaborated but without annotations.+type Term = AST NameBinder TermSig++-- | A typed term: every node carries its type. The successor of @TermT@.+type TermT = AST NameBinder (AnnSig TypeInfo TermSig)++-- | A scope: a binder together with the term it binds over.+type ScopedTermT = ScopedAST NameBinder (AnnSig TypeInfo TermSig)++-- | A scope of an untyped term.+type ScopedTerm = ScopedAST NameBinder TermSig++-- | The annotation of a node: its type, and its memoised normal forms. A+-- variable carries none — its type lives in the context.+typeInfoOf :: TermT n -> Maybe (TypeInfo (TermT n))+typeInfoOf (Var _) = Nothing+typeInfoOf (Node (AnnSig info _)) = Just info++-- | Drop every annotation, for printing and for the surface-facing API.+untyped :: TermT n -> Term n+untyped (Var name) = Var name+untyped (Node (AnnSig _ann sig)) = Node (bimap untypedScoped untyped sig)+ where+ untypedScoped (ScopedAST binder body) = ScopedAST binder (untyped body)++-- | Memoise a node's own weak head normal form (the self-referential knot of the+-- old representation, unchanged).+termIsWHNF :: TermT n -> TermT n+termIsWHNF t@Var{} = t+termIsWHNF (Node (AnnSig info sig)) = t'+ where t' = Node (AnnSig info { infoWHNF = Just t' } sig)++termIsNF :: TermT n -> TermT n+termIsNF t@Var{} = t+termIsNF (Node (AnnSig info sig)) = t'+ where t' = Node (AnnSig info { infoWHNF = Just t', infoNF = Just t' } sig)++-- * Equality++-- | Syntactic equality of two terms of the same scope.+--+-- Annotation-blind, as the old derived 'Eq' was, but it also requires the two to+-- bind the same names, so it is /conservative/: two α-equivalent terms whose+-- binders differ are not equal. That is what the tope-context scans want — the+-- terms there come from the same context — and it is cheaper than 'alphaEqT',+-- which walks the scope.+eqT :: Foil.Distinct n => TermT n -> TermT n -> Bool+eqT = unsafeEqAST++-- | α-equivalence: name-blind and annotation-blind. The old representation's 'Eq'+-- compared binder names, so @\\ x -> x@ and @\\ y -> y@ were unequal; they are the+-- same term, and this says so.+alphaEqT :: Foil.Distinct n => Foil.Scope n -> TermT n -> TermT n -> Bool+alphaEqT = alphaEquiv++elemT :: Foil.Distinct n => TermT n -> [TermT n] -> Bool+elemT t = any (eqT t)++notElemT :: Foil.Distinct n => TermT n -> [TermT n] -> Bool+notElemT t = not . elemT t++nubT :: Foil.Distinct n => [TermT n] -> [TermT n]+nubT [] = []+nubT (t : ts) = t : nubT (filter (not . eqT t) ts)++-- * Free variables++-- | The free variables of a term.+--+-- free-foil has @freeVarsOf@ only on its unreleased @main@, so this is written+-- here. A name bound on the way down is dropped from the result, which is what+-- makes the coercion back to the outer scope right.+freeVarsOfTerm :: Term n -> [Foil.Name n]+freeVarsOfTerm (Var x) = [x]+freeVarsOfTerm (Node sig) = bifoldMap freeVarsOfScoped freeVarsOfTerm sig+ where+ freeVarsOfScoped :: ScopedTerm n' -> [Foil.Name n']+ freeVarsOfScoped (ScopedAST binder body) =+ unsafeCoerce+ [ x+ | x <- freeVarsOfTerm body+ , Foil.nameId x /= Foil.nameId (Foil.nameOf binder)+ ]++-- | The free variables of a typed term, not counting those that occur only in the+-- types of its nodes ('Bifoldable' skips the annotation, as it did before).+freeVarsOfTermT :: TermT n -> [Foil.Name n]+freeVarsOfTermT = freeVarsOfTerm . untyped++-- * Holes++isHoleT :: TermT n -> Bool+isHoleT HoleT{} = True+isHoleT _ = False++-- | The name of every hole in a term.+holeNamesOf :: Term n -> [Maybe VarIdent]+holeNamesOf (Hole mname) = [mname]+holeNamesOf (Var _) = []+holeNamesOf (Node sig) = bifoldr (\scoped acc -> holeNamesOfScoped scoped <> acc)+ (\t acc -> holeNamesOf t <> acc) [] sig+ where+ holeNamesOfScoped (ScopedAST _ body) = holeNamesOf body++-- | Does the term contain a hole anywhere (including nested, e.g. @f ?@)?+containsHole :: TermT n -> Bool+containsHole HoleT{} = True+containsHole (Var _) = False+containsHole (Node (AnnSig _ sig)) =+ bifoldr (\scoped acc -> containsHoleScoped scoped || acc) (\t acc -> containsHole t || acc) False sig+ where+ containsHoleScoped (ScopedAST _ body) = containsHole body++-- * Going under a binder, and substituting++-- | Go under the binder of a scoped term.+--+-- The binder is used as it stands when its name is free in the ambient scope,+-- which is the common case and costs nothing. It has to be renamed when the name+-- is taken — sinking a term into a scope that has grown since the term was built+-- can do that — and only then is the body traversed.+withScopedT+ :: (Bifunctor sig, Foil.Distinct n)+ => Foil.Scope n+ -> ScopedAST NameBinder sig n+ -> (forall l. Foil.DExt n l => NameBinder n l -> AST NameBinder sig l -> r)+ -> r+withScopedT scope (ScopedAST binder body) k+ | Foil.member (Foil.nameOf binder) scope =+ Foil.withFresh scope $ \binder' ->+ let scope' = Foil.extendScope binder' scope+ rename = Foil.addRename (Foil.sink Foil.identitySubst) binder (Foil.nameOf binder')+ in k binder' (substitute scope' rename body)+ | otherwise =+ -- The name is fresh here, so the body already /is/ a term of the extended+ -- scope; the coercion says exactly that, and is the same one+ -- 'Foil.withRefreshed' performs on its own fast path.+ unsafeAssertFresh binder $ \binder' -> k binder' (unsafeCoerce body)++-- | Go under two scoped terms that stand for /one/ variable.+--+-- A Π-type and a λ over a shape each carry a tope scope beside the body, under+-- what the user wrote as a single binder. On free-foil each 'ScopedAST' has its+-- own 'NameBinder', so the second is instantiated with the first's name: they+-- behave as two abstractions over one argument, as they did before.+withScopedT2+ :: Foil.Distinct n+ => Foil.Scope n+ -> ScopedTermT n+ -> ScopedTermT n+ -> (forall l. Foil.DExt n l => NameBinder n l -> TermT l -> TermT l -> r)+ -> r+withScopedT2 scope scoped1 scoped2 k =+ withScopedT scope scoped1 $ \binder body1 ->+ k binder body1 (openWith (Foil.extendScope binder scope) (Foil.nameOf binder) scoped2)++-- | Open a scoped term with a name that is already in scope.+--+-- Generic in the signature, so that a λ's (untyped) body and the codomain of the+-- Π it is checked against can be opened under one and the same binder.+openWith+ :: (Bifunctor sig, Foil.DExt n l)+ => Foil.Scope l -> Foil.Name l -> ScopedAST NameBinder sig n -> AST NameBinder sig l+openWith scope name (ScopedAST binder body) =+ substitute scope (Foil.addRename (Foil.sink Foil.identitySubst) binder name) body++-- | Replace a /free/ name by a term.+--+-- A section's assumption is a free name at the top level, and closing the section+-- abstracts it out of the definitions that use it; this is how those definitions+-- are rewritten. free-foil's substitutions are keyed by a binder, so the map is+-- built directly.+substituteName+ :: Foil.Distinct n+ => Foil.Scope n -> Foil.Name n -> TermT n -> TermT n -> TermT n+substituteName scope name value =+ substituteT scope (UnsafeSubstitution (IntMap.singleton (Foil.nameId name) value))++-- | Abstract a free name out of a term: the binder the continuation receives binds+-- what the name stood for.+--+-- The name stays in the scope index (a scope only ever grows), but the term no+-- longer mentions it, which is what makes the resulting Π or λ closed over it.+abstractName+ :: Foil.Distinct n+ => Foil.Scope n+ -> Foil.Name n+ -> TermT n+ -> (forall l. Foil.DExt n l => NameBinder n l -> TermT l -> r)+ -> r+abstractName scope name term k =+ Foil.withFresh scope $ \binder ->+ let scope' = Foil.extendScope binder scope+ term' = substituteName scope' (Foil.sink name) (Var (Foil.nameOf binder))+ (Foil.sink term)+ in k binder term'++-- | Instantiate a scoped term with a term: the successor of @substituteT x scope@.+instantiateT :: Foil.Distinct n => Foil.Scope n -> ScopedTermT n -> TermT n -> TermT n+instantiateT scope (ScopedAST binder body) arg =+ substituteT scope (Foil.addSubst Foil.identitySubst binder arg) body++-- | Instantiate a scoped /untyped/ term. There are no memoised normal forms to+-- invalidate, so this is free-foil's own substitution.+instantiateUntyped :: Foil.Distinct n => Foil.Scope n -> ScopedTerm n -> Term n -> Term n+instantiateUntyped scope (ScopedAST binder body) arg =+ substitute scope (Foil.addSubst Foil.identitySubst binder arg) body++-- | Substitution that invalidates the memoised normal forms of every node it+-- rebuilds, and substitutes into each node's type.+--+-- A renaming ('substitute') keeps the memo, since a renamed term reduces exactly+-- as the original does. A real substitution does not: a variable is in weak head+-- normal form, and what replaces it need not be. This is one traversal, as+-- substituting and invalidating separately was two.+substituteT+ :: Foil.Distinct o+ => Foil.Scope o+ -> Foil.Substitution TermT i o+ -> TermT i+ -> TermT o+substituteT scope subst term = go scope subst term+ where+ go+ :: forall i' o'. Foil.Distinct o'+ => Foil.Scope o' -> Foil.Substitution TermT i' o' -> TermT i' -> TermT o'+ go _ subst' (Var name) = Foil.lookupSubst subst' name+ go scope' subst' (Node (AnnSig info sig)) = Node (AnnSig info' sig')+ where+ info' = TypeInfo+ { infoType = go scope' subst' (infoType info)+ , infoWHNF = Nothing+ , infoNF = Nothing+ }+ sig' = bimap goScoped (go scope' subst') sig++ goScoped (ScopedAST binder body) =+ Foil.withRefreshed scope' (Foil.nameOf binder) $ \binder' ->+ let scope'' = Foil.extendScope binder' scope'+ subst'' = Foil.addRename (Foil.sink subst') binder (Foil.nameOf binder')+ in ScopedAST binder' (go scope'' subst'' body)++-- * Pattern synonyms+--+-- One per constructor, as @makePatternsAll@ generated before. A @scope@ field is+-- a 'ScopedTermT', so going under a binder means matching on 'ScopedAST', which+-- is where the existential scope index appears.++pattern UniverseT info = Node (AnnSig info UniverseF)+pattern UniverseCubeT info = Node (AnnSig info UniverseCubeF)+pattern UniverseTopeT info = Node (AnnSig info UniverseTopeF)+pattern CubeUnitT info = Node (AnnSig info CubeUnitF)+pattern CubeUnitStarT info = Node (AnnSig info CubeUnitStarF)+pattern Cube2T info = Node (AnnSig info Cube2F)+pattern Cube2_0T info = Node (AnnSig info Cube2_0F)+pattern Cube2_1T info = Node (AnnSig info Cube2_1F)+pattern CubeIT info = Node (AnnSig info CubeIF)+pattern CubeI_0T info = Node (AnnSig info CubeI_0F)+pattern CubeI_1T info = Node (AnnSig info CubeI_1F)+pattern CubeProductT info l r = Node (AnnSig info (CubeProductF l r))+pattern CubeFlipT info t = Node (AnnSig info (CubeFlipF t))+pattern CubeUnflipT info t = Node (AnnSig info (CubeUnflipF t))+pattern TopeTopT info = Node (AnnSig info TopeTopF)+pattern TopeBottomT info = Node (AnnSig info TopeBottomF)+pattern TopeEQT info l r = Node (AnnSig info (TopeEQF l r))+pattern TopeLEQT info l r = Node (AnnSig info (TopeLEQF l r))+pattern TopeAndT info l r = Node (AnnSig info (TopeAndF l r))+pattern TopeOrT info l r = Node (AnnSig info (TopeOrF l r))+pattern TopeInvT info t = Node (AnnSig info (TopeInvF t))+pattern TopeUninvT info t = Node (AnnSig info (TopeUninvF t))+pattern RecBottomT info = Node (AnnSig info RecBottomF)+pattern RecOrT info rs = Node (AnnSig info (RecOrF rs))+pattern TypeFunT info orig md param mtope ret = Node (AnnSig info (TypeFunF orig md param mtope ret))+pattern TypeSigmaT info orig md a b = Node (AnnSig info (TypeSigmaF orig md a b))+pattern TypeIdT info a mtA b = Node (AnnSig info (TypeIdF a mtA b))+pattern AppT info f x = Node (AnnSig info (AppF f x))+pattern LetT info orig mparam val body = Node (AnnSig info (LetF orig mparam val body))+pattern LambdaT info orig mparam body = Node (AnnSig info (LambdaF orig mparam body))+pattern PairT info l r = Node (AnnSig info (PairF l r))+pattern FirstT info t = Node (AnnSig info (FirstF t))+pattern SecondT info t = Node (AnnSig info (SecondF t))+pattern ReflT info mx = Node (AnnSig info (ReflF mx))+pattern IdJT info a b c d e f = Node (AnnSig info (IdJF a b c d e f))+pattern UnitT info = Node (AnnSig info UnitF)+pattern TypeUnitT info = Node (AnnSig info TypeUnitF)+pattern TypeAscT info term ty = Node (AnnSig info (TypeAscF term ty))+pattern TypeRestrictedT info ty rs = Node (AnnSig info (TypeRestrictedF ty rs))+pattern TypeModalT info md ty = Node (AnnSig info (TypeModalF md ty))+pattern ModAppT info md t = Node (AnnSig info (ModAppF md t))+pattern ModExtractT info app inn t = Node (AnnSig info (ModExtractF app inn t))+pattern LetModT info orig app inn mparam val body = Node (AnnSig info (LetModF orig app inn mparam val body))+pattern HoleT info mname = Node (AnnSig info (HoleF mname))++{-# COMPLETE Var, UniverseT, UniverseCubeT, UniverseTopeT, CubeUnitT,+ CubeUnitStarT, Cube2T, Cube2_0T, Cube2_1T, CubeIT, CubeI_0T, CubeI_1T,+ CubeProductT, CubeFlipT, CubeUnflipT, TopeTopT, TopeBottomT, TopeEQT, TopeLEQT,+ TopeAndT, TopeOrT, TopeInvT, TopeUninvT, RecBottomT, RecOrT, TypeFunT,+ TypeSigmaT, TypeIdT, AppT, LetT, LambdaT, PairT, FirstT, SecondT, ReflT, IdJT,+ UnitT, TypeUnitT, TypeAscT, TypeRestrictedT, TypeModalT, ModAppT, ModExtractT,+ LetModT, HoleT #-}++-- ** Untyped patterns+--+-- The same constructors on 'Term' (no annotation), for the surface conversions+-- and the printer.++pattern Universe = Node UniverseF+pattern UniverseCube = Node UniverseCubeF+pattern UniverseTope = Node UniverseTopeF+pattern CubeUnit = Node CubeUnitF+pattern CubeUnitStar = Node CubeUnitStarF+pattern Cube2 = Node Cube2F+pattern Cube2_0 = Node Cube2_0F+pattern Cube2_1 = Node Cube2_1F+pattern CubeI = Node CubeIF+pattern CubeI_0 = Node CubeI_0F+pattern CubeI_1 = Node CubeI_1F+pattern CubeProduct l r = Node (CubeProductF l r)+pattern CubeFlip t = Node (CubeFlipF t)+pattern CubeUnflip t = Node (CubeUnflipF t)+pattern TopeTop = Node TopeTopF+pattern TopeBottom = Node TopeBottomF+pattern TopeEQ l r = Node (TopeEQF l r)+pattern TopeLEQ l r = Node (TopeLEQF l r)+pattern TopeAnd l r = Node (TopeAndF l r)+pattern TopeOr l r = Node (TopeOrF l r)+pattern TopeInv t = Node (TopeInvF t)+pattern TopeUninv t = Node (TopeUninvF t)+pattern RecBottom = Node RecBottomF+pattern RecOr rs = Node (RecOrF rs)+pattern TypeFun orig md param mtope ret = Node (TypeFunF orig md param mtope ret)+pattern TypeSigma orig md a b = Node (TypeSigmaF orig md a b)+pattern TypeId a mtA b = Node (TypeIdF a mtA b)+pattern App f x = Node (AppF f x)+pattern Let orig mparam val body = Node (LetF orig mparam val body)+pattern Lambda orig mparam body = Node (LambdaF orig mparam body)+pattern Pair l r = Node (PairF l r)+pattern First t = Node (FirstF t)+pattern Second t = Node (SecondF t)+pattern Refl mx = Node (ReflF mx)+pattern IdJ a b c d e f = Node (IdJF a b c d e f)+pattern Unit = Node UnitF+pattern TypeUnit = Node TypeUnitF+pattern TypeAsc term ty = Node (TypeAscF term ty)+pattern TypeRestricted ty rs = Node (TypeRestrictedF ty rs)+pattern TypeModal md ty = Node (TypeModalF md ty)+pattern ModApp md t = Node (ModAppF md t)+pattern ModExtract app inn t = Node (ModExtractF app inn t)+pattern LetMod orig app inn mparam val body = Node (LetModF orig app inn mparam val body)+pattern Hole mname = Node (HoleF mname)++{-# COMPLETE Var, Universe, UniverseCube, UniverseTope, CubeUnit, CubeUnitStar,+ Cube2, Cube2_0, Cube2_1, CubeI, CubeI_0, CubeI_1, CubeProduct, CubeFlip,+ CubeUnflip, TopeTop, TopeBottom, TopeEQ, TopeLEQ, TopeAnd, TopeOr, TopeInv,+ TopeUninv, RecBottom, RecOr, TypeFun, TypeSigma, TypeId, App, Let, Lambda,+ Pair, First, Second, Refl, IdJ, Unit, TypeUnit, TypeAsc, TypeRestricted,+ TypeModal, ModApp, ModExtract, LetMod, Hole #-}++-- * Closed constants+--+-- They are closed, so they generalise over the scope index: no shifting, no+-- per-scope construction. (The universe is still the 30-deep chain of the old+-- representation, ending in a bottom; making it a real level-polymorphic+-- universe is a separate FIXME.)++universeT :: TermT n+universeT = iterate f (error "going too high up the universe levels") !! 30+ where+ f t = UniverseT TypeInfo { infoType = t, infoWHNF = Just universeT, infoNF = Just universeT }++cubeT :: TermT n+cubeT = UniverseCubeT TypeInfo+ { infoType = universeT, infoWHNF = Just cubeT, infoNF = Just cubeT }++topeT :: TermT n+topeT = UniverseTopeT TypeInfo+ { infoType = universeT, infoWHNF = Just topeT, infoNF = Just topeT }++cubeUnitT :: TermT n+cubeUnitT = CubeUnitT TypeInfo+ { infoType = cubeT, infoWHNF = Just cubeUnitT, infoNF = Just cubeUnitT }++cubeUnitStarT :: TermT n+cubeUnitStarT = CubeUnitStarT TypeInfo+ { infoType = cubeUnitT, infoWHNF = Just cubeUnitStarT, infoNF = Just cubeUnitStarT }++cube2T :: TermT n+cube2T = Cube2T TypeInfo+ { infoType = cubeT, infoWHNF = Just cube2T, infoNF = Just cube2T }++cube2_0T :: TermT n+cube2_0T = Cube2_0T TypeInfo+ { infoType = cube2T, infoWHNF = Just cube2_0T, infoNF = Just cube2_0T }++cube2_1T :: TermT n+cube2_1T = Cube2_1T TypeInfo+ { infoType = cube2T, infoWHNF = Just cube2_1T, infoNF = Just cube2_1T }++cubeIT :: TermT n+cubeIT = CubeIT TypeInfo+ { infoType = cubeT, infoWHNF = Just cubeIT, infoNF = Just cubeIT }++cubeI_0T :: TermT n+cubeI_0T = CubeI_0T TypeInfo+ { infoType = cubeIT, infoWHNF = Just cubeI_0T, infoNF = Just cubeI_0T }++cubeI_1T :: TermT n+cubeI_1T = CubeI_1T TypeInfo+ { infoType = cubeIT, infoWHNF = Just cubeI_1T, infoNF = Just cubeI_1T }++topeTopT :: TermT n+topeTopT = TopeTopT TypeInfo+ { infoType = topeT, infoWHNF = Just topeTopT, infoNF = Just topeTopT }++topeBottomT :: TermT n+topeBottomT = TopeBottomT TypeInfo+ { infoType = topeT, infoWHNF = Just topeBottomT, infoNF = Just topeBottomT }++typeUnitT :: TermT n+typeUnitT = TypeUnitT TypeInfo+ { infoType = universeT, infoWHNF = Just typeUnitT, infoNF = Just typeUnitT }++unitT :: TermT n+unitT = UnitT TypeInfo+ { infoType = typeUnitT, infoWHNF = Just unitT, infoNF = Just unitT }++-- | @recBOT@ is its own type: it inhabits every type in a contradictory context.+recBottomT :: TermT n+recBottomT = RecBottomT TypeInfo+ { infoType = recBottomT, infoWHNF = Just recBottomT, infoNF = Just recBottomT }++-- * Smart constructors+--+-- Each builds the 'TypeInfo' of the node it makes, so the checker never writes a+-- raw @FooT@. A node whose head is already a value ('lambdaT', 'pairT', the type+-- formers) memoises itself as its own WHNF.++-- ** The tope layer++topeEQT :: TermT n -> TermT n -> TermT n+topeEQT l r = TopeEQT (topeInfo topeT) l r++topeLEQT :: TermT n -> TermT n -> TermT n+topeLEQT l r = TopeLEQT (topeInfo topeT) l r++topeOrT :: TermT n -> TermT n -> TermT n+topeOrT l r = TopeOrT (topeInfo topeT) l r++topeAndT :: TermT n -> TermT n -> TermT n+topeAndT l r = TopeAndT (topeInfo topeT) l r++topeInvT :: TermT n -> TermT n+topeInvT t = TopeInvT (topeInfo (typeModalT universeT Op topeT)) t++topeUninvT :: TermT n -> TermT n+topeUninvT t = TopeUninvT (topeInfo topeT) t++-- | An unreduced node of the given type.+topeInfo :: TermT n -> TypeInfo (TermT n)+topeInfo ty = TypeInfo { infoType = ty, infoWHNF = Nothing, infoNF = Nothing }++-- ** Cubes++cubeProductT :: TermT n -> TermT n -> TermT n+cubeProductT l r = CubeProductT (topeInfo cubeT) l r++cubeFlipT :: TermT n -> TermT n -> TermT n+cubeFlipT cubeTy t = CubeFlipT (topeInfo (typeModalT cubeT Op cubeTy)) t++cubeUnflipT :: TermT n -> TermT n -> TermT n+cubeUnflipT cubeTy t = CubeUnflipT (topeInfo cubeTy) t++-- ** Types++typeFunT+ :: Binder -> TModality -> TermT n -> Maybe (ScopedTermT n) -> ScopedTermT n+ -> TermT n+typeFunT orig md cube mtope ret = t+ where t = TypeFunT (valueInfo t universeT) orig md cube mtope ret++typeSigmaT :: Binder -> TModality -> TermT n -> ScopedTermT n -> TermT n+typeSigmaT orig md a b = t+ where t = TypeSigmaT (valueInfo t universeT) orig md a b++typeIdT :: TermT n -> Maybe (TermT n) -> TermT n -> TermT n+typeIdT x tA y = t+ where t = TypeIdT (valueInfo t universeT) x tA y++typeRestrictedT :: TermT n -> [(TermT n, TermT n)] -> TermT n+typeRestrictedT ty rs = TypeRestrictedT (topeInfo universeT) ty rs++typeModalT :: TermT n -> TModality -> TermT n -> TermT n+typeModalT ty md te = TypeModalT (topeInfo ty) md te++typeAscT :: TermT n -> TermT n -> TermT n+typeAscT x ty = TypeAscT (topeInfo ty) x ty++-- | A node that is already a value: it is its own weak head normal form.+valueInfo :: TermT n -> TermT n -> TypeInfo (TermT n)+valueInfo t ty = TypeInfo { infoType = ty, infoWHNF = Just t, infoNF = Nothing }++-- ** Terms++lambdaT+ :: TermT n -> Binder -> Maybe (LambdaParam (ScopedTermT n) (TermT n))+ -> ScopedTermT n -> TermT n+lambdaT ty orig mparam body = t+ where t = LambdaT (valueInfo t ty) orig mparam body++pairT :: TermT n -> TermT n -> TermT n -> TermT n+pairT ty l r = t+ where t = PairT (valueInfo t ty) l r++appT :: TermT n -> TermT n -> TermT n -> TermT n+appT ty f x = AppT (topeInfo ty) f x++firstT :: TermT n -> TermT n -> TermT n+firstT ty arg = FirstT (topeInfo ty) arg++secondT :: TermT n -> TermT n -> TermT n+secondT ty arg = SecondT (topeInfo ty) arg++letT :: TermT n -> Binder -> Maybe (TermT n) -> TermT n -> ScopedTermT n -> TermT n+letT ty orig mparam val body = LetT (topeInfo ty) orig mparam val body++letModT+ :: TermT n -> Binder -> TModality -> TModality -> Maybe (TermT n) -> TermT n+ -> ScopedTermT n -> TermT n+letModT ty orig app inn mparam val body =+ LetModT (topeInfo ty) orig app inn mparam val body++-- | @refl@ normalises to a bare @refl@: its endpoints are recoverable from the+-- type, so they are dropped from the normal form.+reflT :: TermT n -> Maybe (TermT n, Maybe (TermT n)) -> TermT n+reflT ty mx = ReflT info mx+ where+ info = TypeInfo+ { infoType = ty+ , infoWHNF = Just (ReflT info Nothing)+ , infoNF = Just (ReflT info Nothing)+ }++idJT+ :: TermT n -> TermT n -> TermT n -> TermT n -> TermT n -> TermT n -> TermT n+ -> TermT n+idJT ty tA a tC d x p = IdJT (topeInfo ty) tA a tC d x p++recOrT :: TermT n -> [(TermT n, TermT n)] -> TermT n+recOrT ty rs = RecOrT (topeInfo ty) rs++modAppT :: TermT n -> TModality -> TermT n -> TermT n+modAppT ty md term = ModAppT (topeInfo ty) md term++modExtractT :: TermT n -> TModality -> TModality -> TermT n -> TermT n+modExtractT ty app inn term = ModExtractT (topeInfo ty) app inn term++holeT :: TermT n -> Maybe VarIdent -> TermT n+holeT ty mname = HoleT (topeInfo ty) mname
− src/Language/Rzk/Free/Syntax.hs
@@ -1,885 +0,0 @@-{-# OPTIONS_GHC -fno-warn-missing-pattern-synonym-signatures -fno-warn-missing-signatures -fno-warn-type-defaults #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE DeriveTraversable #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE PatternSynonyms #-}-{-# LANGUAGE RecordWildCards #-}-{-# LANGUAGE TemplateHaskell #-}-{-# LANGUAGE TypeSynonymInstances #-}-module Language.Rzk.Free.Syntax where--import Data.Bifunctor (bimap)-import Data.Bifunctor.TH-import Data.Char (chr, ord)-import Data.Coerce-import Data.Function (on)-import Data.Functor (void)-import Data.List (intercalate, nub, (\\))-import Data.Maybe (fromMaybe)-import Data.String-import qualified Data.Text as T--import Free.Scoped-import Free.Scoped.TH---- FIXME: use proper mechanisms for warnings-import Debug.Trace--import qualified Language.Rzk.Syntax as Rzk--data RzkPosition = RzkPosition- { rzkFilePath :: Maybe FilePath- , rzkLineCol :: Rzk.BNFC'Position- }--ppRzkPosition :: RzkPosition -> String-ppRzkPosition RzkPosition{..} = intercalate ":" $ concat- [ [fromMaybe "<stdin>" rzkFilePath]- , foldMap (\(row, col) -> map show [row, col]) rzkLineCol]--newtype VarIdent = VarIdent { getVarIdent :: Rzk.VarIdent' RzkPosition }--instance Show VarIdent where- show = Rzk.printTree . getVarIdent--instance Eq VarIdent where- (==) = (==) `on` (void . getVarIdent)--instance IsString VarIdent where- fromString s = VarIdent (Rzk.VarIdent (RzkPosition Nothing Nothing) (fromString s))--ppVarIdentWithLocation :: VarIdent -> String-ppVarIdentWithLocation (VarIdent var@(Rzk.VarIdent pos _ident)) =- Rzk.printTree var <> " (" <> ppRzkPosition pos <> ")"--varIdent :: Rzk.VarIdent -> VarIdent-varIdent = varIdentAt Nothing--varIdentAt :: Maybe FilePath -> Rzk.VarIdent -> VarIdent-varIdentAt path (Rzk.VarIdent pos ident) = VarIdent (Rzk.VarIdent (RzkPosition path pos) ident)--fromVarIdent :: VarIdent -> Rzk.VarIdent-fromVarIdent (VarIdent (Rzk.VarIdent (RzkPosition _file pos) ident)) = Rzk.VarIdent pos ident---- | The display name of a hole from its surface token text. The token includes--- the leading @?@; an anonymous hole (bare @?@) has no name.-holeName :: T.Text -> Maybe VarIdent-holeName tok =- case T.drop 1 tok of- name | T.null name -> Nothing- | otherwise -> Just (fromString (T.unpack name))---- | The surface token text (including the leading @?@) for a hole name.-holeIdentToken :: Maybe VarIdent -> T.Text-holeIdentToken Nothing = "?"-holeIdentToken (Just x) = "?" <> T.pack (show x)---- | The name(s) a binder introduces. A binder may name a single (possibly--- anonymous) variable, or destructure a pair\/tuple via a pattern. The pattern--- structure is kept around purely so that goals, holes and error messages can--- show the user's original names (e.g. @t@ and @s@ for @\\ (t , s) -> …@)--- instead of projections of a fresh variable (e.g. @π₁ x₄@ and @π₂ x₄@).------ Operationally a pair pattern still binds a /single/ variable; the components--- are projections of it (see 'toScopePattern'). 'Binder' only records the names--- so they can be restored when rendering.-data Binder- = BinderVar (Maybe VarIdent) -- ^ a single variable (@Nothing@ for @_@)- | BinderPair Binder Binder -- ^ a pair pattern @(l , r)@- | BinderUnit -- ^ the unit pattern @unit@- deriving (Eq)---- | The single name of a binder, if it binds exactly one named variable.--- A pair\/unit pattern has no single name, so this is 'Nothing' for them.--- Used wherever the old @Maybe VarIdent@ binder name is still sufficient.-binderName :: Binder -> Maybe VarIdent-binderName (BinderVar mname) = mname-binderName _ = Nothing--data TModality = Sharp | Flat | Op | Id deriving (Eq, Show)--toModality :: Rzk.Modality -> TModality-toModality Rzk.Sharp{} = Sharp-toModality Rzk.ASCII_Sharp{} = Sharp-toModality Rzk.Flat{} = Flat-toModality Rzk.ASCII_Flat{} = Flat-toModality Rzk.Op{} = Op-toModality Rzk.ASCII_Op{} = Op-toModality Rzk.Id{} = Id--modCompToMods :: Rzk.ModComp -> (TModality, TModality)-modCompToMods (Rzk.Single _ m) = (Id, toModality m)-modCompToMods (Rzk.Comp _ ext inn) = (toModality ext, toModality inn)--fromMod :: TModality -> Rzk.Modality-fromMod Sharp = Rzk.Sharp Nothing-fromMod Flat = Rzk.Flat Nothing-fromMod Op = Rzk.Op Nothing-fromMod Id = Rzk.Id Nothing--modsToModComp :: TModality -> TModality -> Rzk.ModComp-modsToModComp Id inn = Rzk.Single Nothing (fromMod inn)-modsToModComp ext inn = Rzk.Comp Nothing (fromMod ext) (fromMod inn)--data TermF scope term- = UniverseF- | UniverseCubeF - | UniverseTopeF- | CubeUnitF- | CubeUnitStarF- | Cube2F- | Cube2_0F- | Cube2_1F- | CubeIF - | CubeI_0F - | CubeI_1F- | CubeProductF term term- | CubeFlipF term- | CubeUnflipF term- | TopeTopF- | TopeBottomF- | TopeEQF term term- | TopeLEQF term term- | TopeAndF term term- | TopeOrF term term- | TopeInvF term - | TopeUninvF term- | RecBottomF- | RecOrF [(term, term)]- | TypeFunF Binder TModality term (Maybe scope) scope- | TypeSigmaF Binder TModality term scope- | TypeIdF term (Maybe term) term- | AppF term term- | LetF Binder (Maybe term) term scope- | LambdaF Binder (Maybe (TModality, term, Maybe scope)) scope- | PairF term term- | FirstF term- | SecondF term- | ReflF (Maybe (term, Maybe term))- | IdJF term term term term term term- | UnitF- | TypeUnitF- | TypeAscF term term- | TypeRestrictedF term [(term, term)]- | TypeModalF TModality term- | ModAppF TModality term- | ModExtractF TModality TModality term- | LetModF Binder TModality TModality (Maybe term) term scope- | HoleF (Maybe VarIdent)- deriving (Eq, Functor, Foldable, Traversable)-deriveBifunctor ''TermF-deriveBifoldable ''TermF-deriveBitraversable ''TermF-makePatternsAll ''TermF -- declare all patterns using Template Haskell--newtype Type term = Type { getType :: term }- deriving (Eq, Functor, Foldable, Traversable)--data TypeInfo term = TypeInfo- { infoType :: term- , infoWHNF :: Maybe term- , infoNF :: Maybe term- } deriving (Eq, Functor, Foldable, Traversable)--type Term = FS TermF-type TermT = FS (AnnF TypeInfo TermF)--termIsWHNF :: TermT var -> TermT var-termIsWHNF t@Pure{} = t-termIsWHNF (Free (AnnF info f)) = t'- where- t' = Free (AnnF info { infoWHNF = Just t' } f)--termIsNF :: TermT var -> TermT var-termIsNF t@Pure{} = t-termIsNF (Free (AnnF info f)) = t'- where- t' = Free (AnnF info { infoWHNF = Just t', infoNF = Just t' } f)--invalidateWHNF :: TermT var -> TermT var-invalidateWHNF = transFS $ \(AnnF info f) ->- AnnF info { infoWHNF = Nothing, infoNF = Nothing } f--substituteT :: TermT var -> Scope TermT var -> TermT var-substituteT x = substitute x . invalidateWHNF--type Term' = Term VarIdent-type TermT' = TermT VarIdent--freeVars :: Term a -> [a]-freeVars = foldMap pure---- FIXME: should be cached in TypeInfo?-partialFreeVarsT :: TermT a -> [a]-partialFreeVarsT (Pure x) = [x]-partialFreeVarsT UniverseT{} = []-partialFreeVarsT term@(Free (AnnF info _)) =- -- FIXME: check correctness (is it ok to use untyped here?)- foldMap (freeVars . untyped) [term, infoType info]---- FIXME: should be cached in TypeInfo?-freeVarsT :: Eq a => (a -> TermT a) -> TermT a -> [a]-freeVarsT typeOfVar t = go [] (partialFreeVarsT t)- where- go vars latest- | null new = vars- | otherwise =- go (new <> vars)- (foldMap (partialFreeVarsT . typeOfVar) new)- where- new = nub latest \\ vars--toTerm' :: Rzk.Term -> Term'-toTerm' = toTerm Pure--toScope :: VarIdent -> (VarIdent -> Term a) -> Rzk.Term -> Scope Term a-toScope x bvars = toTerm $ \z -> if x == z then Pure Z else S <$> bvars z--toScopePattern :: Rzk.Pattern -> (VarIdent -> Term a) -> Rzk.Term -> Scope Term a-toScopePattern pat bvars = toTerm $ \z ->- case lookup z (bindings pat (Pure Z)) of- Just t -> t- Nothing -> S <$> bvars z- where- bindings (Rzk.PatternUnit _loc) _ = []- bindings (Rzk.PatternVar _loc (Rzk.VarIdent _ "_")) _ = []- bindings (Rzk.PatternVar _loc x) t = [(varIdent x, t)]- bindings (Rzk.PatternPair _loc l r) t = bindings l (First t) <> bindings r (Second t)- bindings (Rzk.PatternTuple loc p1 p2 ps) t = bindings (desugarTuple loc (reverse ps) p2 p1) t--desugarTuple loc ps p2 p1 =- case ps of- [] -> Rzk.PatternPair loc p1 p2- pLast : ps' -> Rzk.PatternPair loc (desugarTuple loc ps' p2 p1) pLast--toTerm :: (VarIdent -> Term a) -> Rzk.Term -> Term a-toTerm bvars = go- where- deprecated t t' = trace msg (go t')- where- msg = unlines- [ "[DEPRECATED]:" <> ppBNFC'Position (Rzk.hasPosition t)- , "the following notation is deprecated and will be removed from future version of rzk:"- , " " <> Rzk.printTree t- , "instead consider using the following notation:"- , " " <> Rzk.printTree t'- ]-- ppBNFC'Position Nothing = ""- ppBNFC'Position (Just (line_, col)) = " at line " <> show line_ <> " column " <> show col-- lint orig suggestion = trace $ unlines- [ "[HINT]:" <> ppBNFC'Position (Rzk.hasPosition orig) <> " consider replacing"- , " " <> Rzk.printTree orig- , "with the following"- , " " <> Rzk.printTree suggestion- ]-- go = \case- -- Depracations- t@(Rzk.RecOrDeprecated loc psi phi a_psi a_phi) -> deprecated t- (Rzk.RecOr loc [Rzk.Restriction loc psi a_psi, Rzk.Restriction loc phi a_phi])- t@(Rzk.TypeExtensionDeprecated loc shape type_) -> deprecated t- (Rzk.TypeFun loc shape type_)- t@(Rzk.TypeFun loc (Rzk.ParamTermTypeDeprecated loc' pat type_) ret) -> deprecated t- (Rzk.TypeFun loc (Rzk.ParamTermType loc' (patternToTerm pat) type_) ret)- t@(Rzk.TypeFun loc (Rzk.ParamVarShapeDeprecated loc' pat cube tope) ret) -> deprecated t- (Rzk.TypeFun loc (Rzk.ParamTermShape loc' (patternToTerm pat) cube tope) ret)- t@(Rzk.Lambda loc ((Rzk.ParamPatternShapeDeprecated loc' pat cube tope):params) body) -> deprecated t- (Rzk.Lambda loc ((Rzk.ParamPatternShape loc' [pat] cube tope):params) body)- -- ASCII versions- Rzk.ASCII_CubeUnitStar loc -> go (Rzk.CubeUnitStar loc)- Rzk.ASCII_Cube2_0 loc -> go (Rzk.Cube2_0 loc)- Rzk.ASCII_Cube2_1 loc -> go (Rzk.Cube2_1 loc)- Rzk.ASCII_TopeTop loc -> go (Rzk.TopeTop loc)- Rzk.ASCII_TopeBottom loc -> go (Rzk.TopeBottom loc)- Rzk.ASCII_TopeEQ loc l r -> go (Rzk.TopeEQ loc l r)- Rzk.ASCII_TopeLEQ loc l r -> go (Rzk.TopeLEQ loc l r)- Rzk.ASCII_TopeAnd loc l r -> go (Rzk.TopeAnd loc l r)- Rzk.ASCII_TopeOr loc l r -> go (Rzk.TopeOr loc l r)-- Rzk.ASCII_TypeFun loc param ret -> go (Rzk.TypeFun loc param ret)- Rzk.ASCII_TypeSigma loc pat ty ret -> go (Rzk.TypeSigma loc pat ty ret)- Rzk.ASCII_TypeSigmaTuple loc p ps tN -> go (Rzk.TypeSigmaTuple loc p ps tN)- Rzk.ASCII_Lambda loc pat ret -> go (Rzk.Lambda loc pat ret)- Rzk.ASCII_TypeExtensionDeprecated loc shape type_ -> go (Rzk.TypeExtensionDeprecated loc shape type_)- Rzk.ASCII_First loc term -> go (Rzk.First loc term)- Rzk.ASCII_Second loc term -> go (Rzk.Second loc term)--- Rzk.Var _loc x -> bvars (varIdent x)- Rzk.Universe _loc -> Universe-- Rzk.UniverseCube _loc -> UniverseCube- Rzk.UniverseTope _loc -> UniverseTope- Rzk.CubeUnit _loc -> CubeUnit- Rzk.CubeUnitStar _loc -> CubeUnitStar- Rzk.Cube2 _loc -> Cube2- Rzk.Cube2_0 _loc -> Cube2_0- Rzk.Cube2_1 _loc -> Cube2_1- Rzk.CubeI _loc -> CubeI- Rzk.CubeI_0 _loc -> CubeI_0- Rzk.CubeI_1 _loc -> CubeI_1- Rzk.ASCII_CubeI _loc -> CubeI- Rzk.ASCII_CubeI_0 _loc -> CubeI_0- Rzk.ASCII_CubeI_1 _loc -> CubeI_1- Rzk.CubeProduct _loc l r -> CubeProduct (go l) (go r)- Rzk.TopeTop _loc -> TopeTop- Rzk.TopeBottom _loc -> TopeBottom- Rzk.TopeEQ _loc l r -> TopeEQ (go l) (go r)- Rzk.TopeLEQ _loc l r -> TopeLEQ (go l) (go r)- Rzk.TopeAnd _loc l r -> TopeAnd (go l) (go r)- Rzk.TopeOr _loc l r -> TopeOr (go l) (go r)- Rzk.TopeInv _loc t -> TopeInv (go t)- Rzk.TopeUninv _loc t -> TopeUninv (go t)- Rzk.CubeFlip _loc t -> CubeFlip (go t)- Rzk.CubeUnflip _loc t -> CubeUnflip (go t)- Rzk.RecBottom _loc -> RecBottom- Rzk.RecOr _loc rs -> RecOr $ flip map rs $ \case- Rzk.Restriction _loc tope term -> (go tope, go term)- Rzk.ASCII_Restriction _loc tope term -> (go tope, go term)- Rzk.TypeId _loc x tA y -> TypeId (go x) (Just (go tA)) (go y)- Rzk.TypeIdSimple _loc x y -> TypeId (go x) Nothing (go y)- Rzk.TypeUnit _loc -> TypeUnit- Rzk.Unit _loc -> Unit- Rzk.App _loc f x -> App (go f) (go x)- Rzk.Pair _loc l r -> Pair (go l) (go r)- Rzk.Tuple _loc p1 p2 (p:ps) -> go (Rzk.Tuple _loc (Rzk.Pair _loc p1 p2) p ps)- Rzk.Tuple _loc p1 p2 [] -> go (Rzk.Pair _loc p1 p2)- Rzk.First _loc term -> First (go term)- Rzk.Second _loc term -> Second (go term)- Rzk.Refl _loc -> Refl Nothing- Rzk.ReflTerm _loc term -> Refl (Just (go term, Nothing))- Rzk.ReflTermType _loc x tA -> Refl (Just (go x, Just (go tA)))- Rzk.IdJ _loc a b c d e f -> IdJ (go a) (go b) (go c) (go d) (go e) (go f)- Rzk.TypeAsc _loc x t -> TypeAsc (go x) (go t)- -- A binder may name several variables sharing a type, e.g. (x y : A),- -- which is parsed as the application spine `x y`. Desugar it into nested- -- one-variable binders ((x : A) → (y : A) → …) before translating, so the- -- pattern conversion never sees a juxtaposition. (Shape binders are left- -- alone: their tope refers to the single bound point.)- Rzk.TypeFun loc (Rzk.ParamTermType loc' patTerm arg) ret- | _ : _ : _ <- vars ->- go (foldr (\v -> Rzk.TypeFun loc (Rzk.ParamTermType loc' v arg)) ret vars)- where vars = flattenBinderApp patTerm- Rzk.TypeFun loc (Rzk.ParamTermModalType loc' patTerm mc ty) ret- | _ : _ : _ <- vars ->- go (foldr (\v -> Rzk.TypeFun loc (Rzk.ParamTermModalType loc' v mc ty)) ret vars)- where vars = flattenBinderApp patTerm- Rzk.TypeFun _loc (Rzk.ParamTermModalType _loc' patTerm mc ty) ret ->- let pat = unsafeTermToPattern patTerm- md = modalColonToTModality mc- in TypeFun (toBinder pat) md (go ty) Nothing (toScopePattern pat bvars ret)- Rzk.TypeFun _loc (Rzk.ParamTermModalShape _loc' patTerm mc cube tope) ret ->- let pat = unsafeTermToPattern patTerm- md = modalColonToTModality mc- in TypeFun (toBinder pat) md (go cube) (Just (toScopePattern pat bvars tope)) (toScopePattern pat bvars ret)- Rzk.TypeFun _loc (Rzk.ParamTermType _ patTerm arg) ret ->- let pat = unsafeTermToPattern patTerm- in TypeFun (toBinder pat) Id (go arg) Nothing (toScopePattern pat bvars ret)- t@(Rzk.TypeFun loc (Rzk.ParamTermShape loc' patTerm cube tope) ret) ->- let lint' = case tope of- Rzk.App _loc fun arg | void arg == void patTerm ->- lint t (Rzk.TypeFun loc (Rzk.ParamTermType loc' patTerm fun) ret)- _ -> id- pat = unsafeTermToPattern patTerm- in lint' $ TypeFun (toBinder pat) Id (go cube) (Just (toScopePattern pat bvars tope)) (toScopePattern pat bvars ret)- Rzk.TypeFun _loc (Rzk.ParamType _ arg) ret ->- TypeFun (BinderVar Nothing) Id (go arg) Nothing (toTerm (fmap S <$> bvars) ret)-- Rzk.TypeSigma _loc pat tA tB ->- TypeSigma (toBinder pat) Id (go tA) (toScopePattern pat bvars tB)-- Rzk.TypeSigmaModal _loc pat mc ty body ->- let md = modalColonToTModality mc- in TypeSigma (toBinder pat) md (go ty) (toScopePattern pat bvars body)-- Rzk.TypeSigmaTuple _loc (Rzk.SigmaParamModal _loc' pat mc ty) rest body ->- let md = modalColonToTModality mc- tailSigma = case rest of- [] -> body- [sp] -> sigmaParamToTypeSigma _loc sp body- (sp:sps) -> Rzk.TypeSigmaTuple _loc sp sps body- in TypeSigma (toBinder pat) md (go ty) (toScopePattern pat bvars tailSigma)- Rzk.TypeSigmaTuple _loc (Rzk.SigmaParam _ patA tA) (mp@(Rzk.SigmaParamModal{}) : rest) body ->- go (Rzk.TypeSigma _loc patA tA (case rest of- [] -> sigmaParamToTypeSigma _loc mp body- _ -> Rzk.TypeSigmaTuple _loc mp rest body))- Rzk.TypeSigmaTuple _loc (Rzk.SigmaParam _ patA tA) ((Rzk.SigmaParam _ patB tB) : ps) tN ->- go (Rzk.TypeSigmaTuple _loc (Rzk.SigmaParam _loc patX tX) ps tN)- where- patX = Rzk.PatternPair _loc patA patB- tX = Rzk.TypeSigma _loc patA tA tB- Rzk.TypeSigmaTuple _loc (Rzk.SigmaParam _ pat tA) [] tB -> go (Rzk.TypeSigma _loc pat tA tB)- Rzk.Lambda _loc (Rzk.ParamPatternModalType _ [] _mc _ty : params) body ->- go (Rzk.Lambda _loc params body)- Rzk.Lambda _loc (Rzk.ParamPatternModalType loc' (pat:pats) mc ty : params) body ->- let md = modalColonToTModality mc- in Lambda (toBinder pat) (Just (md, go ty, Nothing))- (toScopePattern pat bvars (Rzk.Lambda _loc (if null pats then params else Rzk.ParamPatternModalType loc' pats mc ty : params) body))- Rzk.Lambda _loc (Rzk.ParamPatternModalShape _ [] _mc _cube _tope : params) body ->- go (Rzk.Lambda _loc params body)- Rzk.Lambda _loc (Rzk.ParamPatternModalShape loc' (pat:pats) mc cube tope : params) body ->- let md = modalColonToTModality mc- in Lambda (toBinder pat) (Just (md, go cube, Just (toScopePattern pat bvars tope)))- (toScopePattern pat bvars (Rzk.Lambda _loc (if null pats then params else Rzk.ParamPatternModalShape loc' pats mc cube tope : params) body))- Rzk.Lambda _loc [] body -> go body- Rzk.Lambda _loc (Rzk.ParamPattern _ pat : params) body ->- Lambda (toBinder pat) Nothing (toScopePattern pat bvars (Rzk.Lambda _loc params body))- Rzk.Lambda _loc (Rzk.ParamPatternType _ [] _ty : params) body ->- go (Rzk.Lambda _loc params body)- Rzk.Lambda _loc (Rzk.ParamPatternType _ (pat:pats) ty : params) body ->- Lambda (toBinder pat) (Just (Id, go ty, Nothing))- (toScopePattern pat bvars (Rzk.Lambda _loc (Rzk.ParamPatternType _loc pats ty : params) body))- Rzk.Lambda _loc (Rzk.ParamPatternShape _ [] _cube _tope : params) body ->- go (Rzk.Lambda _loc params body)- t@(Rzk.Lambda _loc (Rzk.ParamPatternShape _loc' (pat:pats) cube tope : params) body) ->- let lint' = case tope of- Rzk.App _loc fun arg- | null pats && void arg == void (patternToTerm pat) ->- lint t (Rzk.Lambda _loc (Rzk.ParamPatternType _loc' [pat] fun : params) body)- _ -> id- in lint' $ Lambda (toBinder pat) (Just (Id, go cube, Just (toScopePattern pat bvars tope)))- (toScopePattern pat bvars (Rzk.Lambda _loc (Rzk.ParamPatternShape _loc' pats cube tope : params) body))- Rzk.Let _loc (Rzk.BindPattern _ pat) val expr ->- Let (toBinder pat) Nothing (go val) (toScopePattern pat bvars expr)- Rzk.Let _loc (Rzk.BindPatternType _ pat ty) val expr -> - Let (toBinder pat) (Just (go ty)) (go val) (toScopePattern pat bvars expr)- Rzk.TypeRestricted _loc ty rs ->- TypeRestricted (go ty) $ flip map rs $ \case- Rzk.Restriction _loc tope term -> (go tope, go term)- Rzk.ASCII_Restriction _loc tope term -> (go tope, go term)-- Rzk.Hole _loc (Rzk.HoleIdent _ (Rzk.HoleIdentToken tok)) ->- Hole (holeName tok)- Rzk.ModApp _loc md body -> ModApp (toModality md) (go body)- Rzk.ModType _loc md ty -> TypeModal (toModality md) (go ty)- Rzk.ModExtract{} -> error "$extract$ is an internal term and cannot appear in source"- Rzk.LetMod _loc comp (Rzk.BindPattern _ pat) val body ->- let (ext, inn) = modCompToMods comp- in LetMod (toBinder pat) ext inn Nothing (go val) (toScopePattern pat bvars body)- Rzk.LetMod _loc comp (Rzk.BindPatternType _ pat ty) val body ->- let (ext, inn) = modCompToMods comp- in LetMod (toBinder pat) ext inn (Just (go ty)) (go val) (toScopePattern pat bvars body)-- -- Translate a surface pattern into a 'Binder', keeping the pair\/tuple- -- structure so the component names can be restored when rendering.- toBinder (Rzk.PatternVar _loc (Rzk.VarIdent _ "_")) = BinderVar Nothing- toBinder (Rzk.PatternVar _loc x) = BinderVar (Just (varIdent x))- toBinder (Rzk.PatternUnit _loc) = BinderUnit- toBinder (Rzk.PatternPair _loc l r) = BinderPair (toBinder l) (toBinder r)- toBinder (Rzk.PatternTuple loc p1 p2 ps) = toBinder (desugarTuple loc (reverse ps) p2 p1)--patternToTerm :: Rzk.Pattern -> Rzk.Term-patternToTerm = ptt- where- ptt = \case- Rzk.PatternVar loc x -> Rzk.Var loc x- Rzk.PatternPair loc l r -> Rzk.Pair loc (ptt l) (ptt r)- Rzk.PatternUnit loc -> Rzk.Unit loc- Rzk.PatternTuple loc p1 p2 ps -> patternToTerm (desugarTuple loc (reverse ps) p2 p1)---modalColonModality :: Rzk.ModalColon -> Rzk.Modality-modalColonModality = \case- Rzk.ModalColonFlat loc -> Rzk.Flat loc- Rzk.ModalColonSharp loc -> Rzk.Sharp loc- Rzk.ModalColonOp loc -> Rzk.Op loc- Rzk.ModalColonId loc -> Rzk.Id loc- Rzk.ASCII_ModalColonFlat loc -> Rzk.Flat loc- Rzk.ASCII_ModalColonSharp loc -> Rzk.Sharp loc- Rzk.ASCII_ModalColonOp loc -> Rzk.Op loc--modalColonToTModality :: Rzk.ModalColon -> TModality-modalColonToTModality = toModality . modalColonModality--fromTModalityToModalColon :: TModality -> Rzk.ModalColon-fromTModalityToModalColon = \case- Sharp -> Rzk.ModalColonSharp Nothing- Flat -> Rzk.ModalColonFlat Nothing- Op -> Rzk.ModalColonOp Nothing- Id -> Rzk.ModalColonId Nothing---- | Split a binder term into the individual variables it names. A multi-variable--- binder like @(x y : A)@ is parsed as the application spine @x y@; this returns--- @[x, y]@ so each can become its own nested binder. A single binder term (a--- variable, a pair pattern, …) is returned unchanged as a singleton.-flattenBinderApp :: Rzk.Term -> [Rzk.Term]-flattenBinderApp = \case- Rzk.App _loc f x -> flattenBinderApp f ++ [x]- t -> [t]--unsafeTermToPattern :: Rzk.Term -> Rzk.Pattern-unsafeTermToPattern = ttp- where- ttp = \case- Rzk.Unit loc -> Rzk.PatternUnit loc- Rzk.Var loc x -> Rzk.PatternVar loc x- Rzk.Pair loc l r -> Rzk.PatternPair loc (ttp l) (ttp r)- Rzk.Tuple loc t1 t2 ts -> Rzk.PatternTuple loc (ttp t1) (ttp t2) (map ttp ts)- term -> error ("ERROR: expected a pattern but got\n " ++ Rzk.printTree term)--sigmaParamToTypeSigma :: Rzk.BNFC'Position -> Rzk.SigmaParam -> Rzk.Term -> Rzk.Term-sigmaParamToTypeSigma loc sp body = case sp of- Rzk.SigmaParam _ pat ty -> Rzk.TypeSigma loc pat ty body- Rzk.SigmaParamModal _ pat mc ty -> Rzk.TypeSigmaModal loc pat mc ty body---- | A projection step: first (@π₁@) or second (@π₂@) component.-data Proj = PFst | PSnd- deriving (Eq)---- | Render a 'Binder' as a surface pattern (used to display the binder itself,--- e.g. @(t , s)@). Anonymous variables become @_@.-binderToPattern :: Binder -> Rzk.Pattern-binderToPattern (BinderVar Nothing) = Rzk.PatternVar Nothing (fromVarIdent "_")-binderToPattern (BinderVar (Just x)) = Rzk.PatternVar Nothing (fromVarIdent x)-binderToPattern (BinderPair l r) = Rzk.PatternPair Nothing (binderToPattern l) (binderToPattern r)-binderToPattern BinderUnit = Rzk.PatternUnit Nothing---- | A term that prints as the binder's surface pattern, e.g. the point--- @(t , s)@. Used to render a /bare/ occurrence of a pattern binder's variable--- (one not under a projection, e.g. the point in a shape tope @Δ² (t , s)@) as--- the pattern itself rather than the underlying single variable. A--- single-variable binder yields that variable.-binderToTerm :: Binder -> Term VarIdent-binderToTerm (BinderVar Nothing) = Pure (fromString "_")-binderToTerm (BinderVar (Just x)) = Pure x-binderToTerm (BinderPair l r) = Pair (binderToTerm l) (binderToTerm r)-binderToTerm BinderUnit = Unit---- | A 'VarIdent' that prints as the binder's surface pattern, e.g. @(t , s)@.--- Used to display a pattern binder in a hole's local context as the pattern--- itself rather than as the underlying single variable.-binderDisplayName :: Binder -> VarIdent-binderDisplayName = fromString . Rzk.printTree . binderToPattern---- | The named leaves of a binder, each paired with the projection path that--- reaches it from the bound variable. For example @(t , (a , b))@ yields--- @[([PFst], t), ([PSnd, PFst], a), ([PSnd, PSnd], b)]@.-binderPaths :: Binder -> [([Proj], VarIdent)]-binderPaths (BinderVar (Just x)) = [([], x)]-binderPaths (BinderVar Nothing) = []-binderPaths BinderUnit = []-binderPaths (BinderPair l r) =- [ (PFst : p, n) | (p, n) <- binderPaths l ] ++- [ (PSnd : p, n) | (p, n) <- binderPaths r ]---- | The names appearing in a binder.-binderLeaves :: Binder -> [VarIdent]-binderLeaves = map snd . binderPaths---- | Does this binder destructure a pair\/tuple (as opposed to naming a single--- variable or @_@)?-binderIsCompound :: Binder -> Bool-binderIsCompound BinderVar{} = False-binderIsCompound _ = True---- | Refresh the named leaves of a binder so they avoid the given names (and one--- another). Anonymous leaves and the unit pattern are left unchanged.-freshenBinderLeaves :: [VarIdent] -> Binder -> Binder-freshenBinderLeaves used = snd . go used- where- go u (BinderVar (Just x)) = let x' = refreshVar u x in (x' : u, BinderVar (Just x'))- go u b@(BinderVar Nothing) = (u, b)- go u BinderUnit = (u, BinderUnit)- go u (BinderPair l r) =- let (u1, l') = go u l- (u2, r') = go u1 r- in (u2, BinderPair l' r')---- | Decompose a chain of projections applied to a variable into the projection--- path /from the variable outwards/, matching 'binderPaths'. The outermost--- projection is applied last, so it goes at the /end/ of the path: e.g.--- @π₂ (π₁ x)@ (select @π₁@ first, then @π₂@) becomes @Just ([PFst, PSnd], x)@.-projChain :: Term a -> Maybe ([Proj], a)-projChain (First t) = (\(ps, r) -> (ps ++ [PFst], r)) <$> projChain t-projChain (Second t) = (\(ps, r) -> (ps ++ [PSnd], r)) <$> projChain t-projChain (Pure x) = Just ([], x)-projChain _ = Nothing---- | Replace projection chains rooted at a pattern binder with the binder's--- component name. Given a map from a (bound) variable to the named leaves of--- its binder, every @π₁/π₂@ chain that reaches a named leaf is rewritten to--- that name. Ordinary projections (of variables not bound by a pattern, or--- chains that do not reach a named leaf) are left untouched.-foldBinderProjections :: Eq a => [(a, [([Proj], a)])] -> Term a -> Term a-foldBinderProjections m = go- where- go t- | Just (ps, root) <- projChain t- , not (null ps)- , Just leaves <- lookup root m- , Just nm <- lookup ps leaves- = Pure nm- go (Free f) = Free (bimap goScope go f)- go (Pure x) = Pure x- goScope = foldBinderProjections (map liftEntry m)- liftEntry (k, leaves) = (S k, map (fmap S) leaves)---- | Replace bare uses of a pattern binder's variable with the pattern term--- (e.g. a whole point @(t , s)@ rather than the underlying single variable, in--- a tope @Δ² (t , s)@). Given a map from each (already display-named) variable--- to its binder, every free occurrence of a /compound/ binder's variable is--- expanded to its pattern. Complements 'foldBinderProjections', which folds--- /projections/ of such a variable; run this /after/ folding, so projections--- have already become component names and only bare uses remain.-restorePatternVars :: [(VarIdent, Binder)] -> Term VarIdent -> Term VarIdent-restorePatternVars binders = (>>= expand)- where- expand v = case lookup v binders of- Just b | binderIsCompound b -> binderToTerm b- _ -> Pure v---- | Like 'projChain', but for type-annotated terms.-projChainT :: TermT a -> Maybe ([Proj], a)-projChainT (FirstT _ t) = (\(ps, r) -> (ps ++ [PFst], r)) <$> projChainT t-projChainT (SecondT _ t) = (\(ps, r) -> (ps ++ [PSnd], r)) <$> projChainT t-projChainT (Pure x) = Just ([], x)-projChainT _ = Nothing---- | Like 'foldBinderProjections', but for type-annotated terms (e.g. those--- embedded in type errors). The annotation of a folded leaf is dropped, which--- is harmless: the result is only rendered, and a bare variable needs none.-foldBinderProjectionsT :: Eq a => [(a, [([Proj], a)])] -> TermT a -> TermT a-foldBinderProjectionsT m = go- where- go t- | Just (ps, root) <- projChainT t- , not (null ps)- , Just leaves <- lookup root m- , Just nm <- lookup ps leaves- = Pure nm- go (Free (AnnF info f)) = Free (AnnF (fmap go info) (bimap goScope go f))- go (Pure x) = Pure x- goScope = foldBinderProjectionsT (map liftEntry m)- liftEntry (k, leaves) = (S k, map (fmap S) leaves)--fromTerm' :: Term' -> Rzk.Term-fromTerm' t = fromTermWith' vars (defaultVarIdents \\ vars) t- where vars = freeVars t--fromScope' :: VarIdent -> [VarIdent] -> [VarIdent] -> Scope Term VarIdent -> Rzk.Term-fromScope' x used xs = fromTermWith' (x : used) xs . (>>= f)- where- f Z = Pure x- f (S z) = Pure z---- | Drop the binder of a scope that does not use it. The error is--- unreachable when 'Z' is not among the scope's free variables.-unusedScope :: Scope Term var -> Term var-unusedScope scope = scope >>= \case- Z -> error "unusedScope: the bound variable is used"- S z -> Pure z---- | Like 'fromScope'', but additionally restores pattern-binder component names--- inside the scope: projections of the bound variable @x@ are folded back to--- the names recorded in @binder@ (e.g. @π₁ x@ becomes @t@). For a binder that--- names a single variable this is exactly 'fromScope''.-fromScopeBinder' :: Binder -> VarIdent -> [VarIdent] -> [VarIdent] -> Scope Term VarIdent -> Rzk.Term-fromScopeBinder' binder x used xs scope =- fromTermWith' (x : used) xs- (restorePattern (foldBinderProjections [(x, binderPaths binder)] (scope >>= f)))- where- f Z = Pure x- f (S z) = Pure z- -- After projection chains have been folded to their component names, a bare- -- use of a pattern binder's variable (the whole point, e.g. in a shape tope- -- @Δ² (t , s)@) still reads as the placeholder; show it as the pattern.- restorePattern- | binderIsCompound binder = (>>= \v -> if v == x then binderToTerm binder else Pure v)- | otherwise = id--fromTermWith' :: [VarIdent] -> [VarIdent] -> Term' -> Rzk.Term-fromTermWith' used vars = go- where- -- Refresh a binder's named leaves against the names already in use and draw- -- fresh names for anonymous leaves from the remaining supply.- freshenBinder _ stream (BinderVar Nothing) =- case stream of- x:xs -> (BinderVar (Just x), xs)- _ -> error "not enough fresh variables!"- freshenBinder used' stream (BinderVar (Just z)) =- (BinderVar (Just z'), filter (/= z') stream)- where z' = refreshVar used' z- freshenBinder _ stream BinderUnit = (BinderUnit, stream)- freshenBinder used' stream (BinderPair l r) =- let (l', s1) = freshenBinder used' stream l- (r', s2) = freshenBinder (used' ++ binderLeaves l') s1 r- in (BinderPair l' r', s2)-- -- Pick fresh names for a binder. Yields the bound variable's display name- -- (used as the De Bruijn placeholder), the freshened binder (for the- -- displayed pattern and for projection folding), and the remaining supply.- withFreshBinder z f =- case binder' of- BinderVar (Just x) -> f (x, binder', stream)- _ -> case stream of- x:xs -> f (x, binder', xs)- _ -> error "not enough fresh variables!"- where- (binder', stream) = freshenBinder used vars z-- loc = Nothing-- goMod :: TModality -> Rzk.Modality - goMod Sharp = Rzk.Sharp loc- goMod Flat = Rzk.Flat loc - goMod Op = Rzk.Op loc- goMod Id = Rzk.Id loc --- go :: Term' -> Rzk.Term- go = \case- Pure z -> Rzk.Var loc (fromVarIdent z)-- Universe -> Rzk.Universe loc- UniverseCube -> Rzk.UniverseCube loc- UniverseTope -> Rzk.UniverseTope loc- CubeUnit -> Rzk.CubeUnit loc- CubeUnitStar -> Rzk.CubeUnitStar loc- Cube2 -> Rzk.Cube2 loc- Cube2_0 -> Rzk.Cube2_0 loc- Cube2_1 -> Rzk.Cube2_1 loc- CubeI -> Rzk.CubeI loc- CubeI_0 -> Rzk.CubeI_0 loc- CubeI_1 -> Rzk.CubeI_1 loc- CubeProduct l r -> Rzk.CubeProduct loc (go l) (go r)- TopeTop -> Rzk.TopeTop loc- TopeBottom -> Rzk.TopeBottom loc- TopeEQ l r -> Rzk.TopeEQ loc (go l) (go r)- TopeLEQ l r -> Rzk.TopeLEQ loc (go l) (go r)- TopeAnd l r -> Rzk.TopeAnd loc (go l) (go r)- TopeOr l r -> Rzk.TopeOr loc (go l) (go r)- TopeInv t -> Rzk.TopeInv loc (go t)- TopeUninv t -> Rzk.TopeUninv loc (go t)- CubeFlip t -> Rzk.CubeFlip loc (go t)- CubeUnflip t -> Rzk.CubeUnflip loc (go t)- RecBottom -> Rzk.RecBottom loc- RecOr rs -> Rzk.RecOr loc [ Rzk.Restriction loc (go tope) (go term) | (tope, term) <- rs ]-- Hole mname -> Rzk.Hole loc (Rzk.HoleIdent loc (Rzk.HoleIdentToken (holeIdentToken mname)))-- -- An anonymous binder that the return type does not use is not shown:- -- @(x₁ : A) → B@ reads better as @A → B@. A user-written name is kept- -- even when unused.- TypeFun (BinderVar Nothing) Id arg Nothing ret- | Z `notElem` freeVars ret ->- Rzk.TypeFun loc (Rzk.ParamType loc (go arg)) (go (unusedScope ret))- TypeFun z Id arg Nothing ret -> withFreshBinder z $ \(x, z', xs) ->- Rzk.TypeFun loc (Rzk.ParamTermType loc (patternToTerm (binderToPattern z')) (go arg)) (fromScopeBinder' z' x used xs ret)- TypeFun z Id arg (Just tope) ret -> withFreshBinder z $ \(x, z', xs) ->- Rzk.TypeFun loc (Rzk.ParamTermShape loc (patternToTerm (binderToPattern z')) (go arg) (fromScopeBinder' z' x used xs tope)) (fromScopeBinder' z' x used xs ret)- TypeFun z md arg Nothing ret -> withFreshBinder z $ \(x, z', xs) ->- Rzk.TypeFun loc (Rzk.ParamTermModalType loc (patternToTerm (binderToPattern z')) (fromTModalityToModalColon md) (go arg)) (fromScopeBinder' z' x used xs ret)- TypeFun z md arg (Just tope) ret -> withFreshBinder z $ \(x, z', xs) ->- Rzk.TypeFun loc (Rzk.ParamTermModalShape loc (patternToTerm (binderToPattern z')) (fromTModalityToModalColon md) (go arg) (fromScopeBinder' z' x used xs tope)) (fromScopeBinder' z' x used xs ret)-- TypeSigma z Id a b -> withFreshBinder z $ \(x, z', xs) ->- Rzk.TypeSigma loc (binderToPattern z') (go a) (fromScopeBinder' z' x used xs b)- TypeSigma z md a b -> withFreshBinder z $ \(x, z', xs) ->- Rzk.TypeSigmaModal loc (binderToPattern z') (fromTModalityToModalColon md) (go a) (fromScopeBinder' z' x used xs b)- TypeId l (Just tA) r -> Rzk.TypeId loc (go l) (go tA) (go r)- TypeId l Nothing r -> Rzk.TypeIdSimple loc (go l) (go r)- App l r -> Rzk.App loc (go l) (go r)-- Lambda z Nothing scope -> withFreshBinder z $ \(x, z', xs) ->- Rzk.Lambda loc [Rzk.ParamPattern loc (binderToPattern z')] (fromScopeBinder' z' x used xs scope)- Lambda z (Just (Id, ty, Nothing)) scope -> withFreshBinder z $ \(x, z', xs) ->- Rzk.Lambda loc [Rzk.ParamPatternType loc [binderToPattern z'] (go ty)] (fromScopeBinder' z' x used xs scope)- Lambda z (Just (Id, cube, Just tope)) scope -> withFreshBinder z $ \(x, z', xs) ->- Rzk.Lambda loc [Rzk.ParamPatternShape loc [binderToPattern z'] (go cube) (fromScopeBinder' z' x used xs tope)] (fromScopeBinder' z' x used xs scope)- Lambda z (Just (md, ty, Nothing)) scope -> withFreshBinder z $ \(x, z', xs) ->- Rzk.Lambda loc [Rzk.ParamPatternModalType loc [binderToPattern z'] (fromTModalityToModalColon md) (go ty)] (fromScopeBinder' z' x used xs scope)- Lambda z (Just (md, cube, Just tope)) scope -> withFreshBinder z $ \(x, z', xs) ->- Rzk.Lambda loc [Rzk.ParamPatternModalShape loc [binderToPattern z'] (fromTModalityToModalColon md) (go cube) (fromScopeBinder' z' x used xs tope)] (fromScopeBinder' z' x used xs scope)- -- Lambda (Maybe (term, Maybe scope)) scope -> Rzk.Lambda loc (Maybe (term, Maybe scope)) scope- Let z Nothing val scope -> withFreshBinder z $ \(x, z', xs) ->- Rzk.Let loc (Rzk.BindPattern loc (binderToPattern z')) (go val) (fromScopeBinder' z' x used xs scope)- Let z (Just ty) val scope -> withFreshBinder z $ \(x, z', xs) ->- Rzk.Let loc (Rzk.BindPatternType loc (binderToPattern z') (go ty)) (go val) (fromScopeBinder' z' x used xs scope)- Pair l r -> Rzk.Pair loc (go l) (go r)- First term -> Rzk.First loc (go term)- Second term -> Rzk.Second loc (go term)- TypeUnit -> Rzk.TypeUnit loc- Unit -> Rzk.Unit loc- Refl Nothing -> Rzk.Refl loc- Refl (Just (t, Nothing)) -> Rzk.ReflTerm loc (go t)- Refl (Just (t, Just ty)) -> Rzk.ReflTermType loc (go t) (go ty)- IdJ a b c d e f -> Rzk.IdJ loc (go a) (go b) (go c) (go d) (go e) (go f)- TypeAsc l r -> Rzk.TypeAsc loc (go l) (go r)- TypeRestricted ty rs ->- Rzk.TypeRestricted loc (go ty) (map (\(tope, term) -> (Rzk.Restriction loc (go tope) (go term))) rs)- TypeModal m ty -> Rzk.ModType loc (goMod m) (go ty)- ModApp m ty -> Rzk.ModApp loc (goMod m) (go ty)- ModExtract ma mb t -> Rzk.ModExtract loc (Rzk.Comp loc (goMod ma) (goMod mb)) (go t)- LetMod z ext inn Nothing val scope -> withFreshBinder z $ \(x, z', xs) ->- Rzk.LetMod loc (modsToModComp ext inn)- (Rzk.BindPattern loc (binderToPattern z'))- (go val) (fromScopeBinder' z' x used xs scope)- LetMod z ext inn (Just ty) val scope -> withFreshBinder z $ \(x, z', xs) ->- Rzk.LetMod loc (modsToModComp ext inn)- (Rzk.BindPatternType loc (binderToPattern z') (go ty))- (go val) (fromScopeBinder' z' x used xs scope)---defaultVarIdents :: [VarIdent]-defaultVarIdents =- [ fromString name- | n <- [1..]- , let name = "x" <> map digitToSub (show n) ]- where- digitToSub c = chr ((ord c - ord '0') + ord '₀')---- $setup--- >>> :set -XOverloadedStrings--- >>> import qualified Data.Text as T---- | Given a list of used variable names in the current context,--- generate a unique fresh name based on a given one.------ >>> print $ refreshVar ["x", "y", "x₁", "z"] "x"--- x₂-refreshVar :: [VarIdent] -> VarIdent -> VarIdent-refreshVar vars x- | x `elem` vars = refreshVar vars (incVarIdentIndex x)- | otherwise = x--incVarIdentIndex :: VarIdent -> VarIdent-incVarIdentIndex (VarIdent (Rzk.VarIdent loc token)) =- VarIdent (Rzk.VarIdent loc (coerce incIndex token))---- | Increment the subscript number at the end of the indentifier.------ >>> putStrLn $ T.unpack $ incIndex "x"--- x₁--- >>> putStrLn $ T.unpack $ incIndex "x₁₉"--- x₂₀-incIndex :: T.Text -> T.Text-incIndex s = T.pack $ name <> newIndex- where- digitsSub = "₀₁₂₃₄₅₆₇₈₉" :: String- isDigitSub = (`elem` digitsSub)- digitFromSub c = chr ((ord c - ord '₀') + ord '0')- digitToSub c = chr ((ord c - ord '0') + ord '₀')- (name, index) = break isDigitSub (T.unpack s)- oldIndexN = read ('0' : map digitFromSub index) -- FIXME: read- newIndex = map digitToSub (show (oldIndexN + 1))--instance Show Term' where- show = Rzk.printTree . fromTerm'--instance IsString Term' where- fromString = toTerm' . fromRight . Rzk.parseTerm . T.pack- where- fromRight (Left err) = error (T.unpack $ "Parse error: " <> err)- fromRight (Right t) = t--instance Show TermT' where- show var@Pure{} = Rzk.printTree (fromTerm' (untyped var))- show term@(Free (AnnF TypeInfo{..} _)) = termStr <> " : " <> typeStr- where- termStr = Rzk.printTree (fromTerm' (untyped term))- typeStr = Rzk.printTree (fromTerm' (untyped infoType))
src/Language/Rzk/VSCode/Env.hs view
@@ -8,16 +8,27 @@ import qualified Data.Map.Strict as Map import qualified Data.Text as T import Language.LSP.Server-import Language.Rzk.Free.Syntax (VarIdent) import Language.Rzk.Syntax (Module) import qualified Language.Rzk.VSCode.Config as RzkConfig import Language.Rzk.VSCode.Logging import qualified Language.Rzk.VSCode.ReferenceIndex as RefInd-import Rzk.TypeCheck (Decl', TypeErrorInScopedContext)+import Rzk.TypeCheck (Checked, DeclView,+ TypeErrorInScopedContext) +-- | What checking one module produced.+--+-- 'cachedModuleChecked' is the state of the whole run /after/ this module: the+-- top-level scope and every declaration elaborated so far. That is what a resume+-- starts from — a cached elaborated term names the definitions it uses by their+-- foil name, which only means anything in the scope that produced it, so the scope+-- has to be cached with them.+--+-- 'cachedModuleDecls' is the rendered view of this module's own declarations,+-- which is all that completion, symbols and hover need. data RzkCachedModule = RzkCachedModule- { cachedModuleDecls :: [Decl']- , cachedModuleErrors :: [TypeErrorInScopedContext VarIdent]+ { cachedModuleChecked :: Checked+ , cachedModuleDecls :: [DeclView]+ , cachedModuleErrors :: [TypeErrorInScopedContext] } type RzkTypecheckCache = [(FilePath, RzkCachedModule)]
src/Language/Rzk/VSCode/Handlers.hs view
@@ -59,9 +59,8 @@ import System.FilePath.Glob (compile, globDir) import Data.Char (isDigit)-import Language.Rzk.Free.Syntax (RzkPosition (RzkPosition),- VarIdent (getVarIdent),- fromTerm')+import Language.Rzk.Foil.Names (RzkPosition (RzkPosition),+ VarIdent (getVarIdent)) import Language.Rzk.Syntax (Module, Term, Term' (ASCII_TypeFun, TypeFun), VarIdent' (VarIdent),@@ -73,7 +72,6 @@ import Language.Rzk.VSCode.Logging import Language.Rzk.VSCode.Tokenize (mergeTokens, tokenizeModule, tokenizeSyntaxSymbols)-import Free.Scoped (untyped) import qualified Rzk.Diagnostic as Diag import Rzk.Format (format) import Rzk.Project.Config (ProjectConfig (include))@@ -194,15 +192,15 @@ -- continues from there. unless (null parsedModules) $ withProgress "rzk typechecking" Nothing Cancellable $ \reportProgress ->- checkModules reportProgress rootPath cachedModules parsedModules+ checkModulesInProject reportProgress rootPath cachedModules parsedModules where- checkModules+ checkModulesInProject :: (ProgressAmount -> LSP ()) -> FilePath -- ^ Workspace root (for progress messages). -> RzkTypecheckCache -- ^ Cached results for the unchanged prefix. -> [(FilePath, Module)] -- ^ Modified modules, in project order. -> LSP ()- checkModules reportProgress rootPath cache modules = go (0 :: Int) cache modules+ checkModulesInProject reportProgress rootPath cache modules = go (0 :: Int) cache modules where total = length modules @@ -213,9 +211,13 @@ (Just (T.pack (makeRelative rootPath path)))) -- Run in lenient hole mode so holes are collected (and surfaced as -- hints) rather than reported as errors while editing.+ -- Resume from the context of the last module that is still cached: it+ -- /is/ the elaborated prefix, so nothing is replayed or re-elaborated.+ let prefix = case reverse checked of+ (_, entry) : _ -> cachedModuleChecked entry+ [] -> emptyChecked tcResult <- liftIO $ tryTypecheck $ evaluate $- defaultTypeCheckWithHoles $ typecheckModulesWithLocationIncremental- (map (fmap cachedModuleDecls) checked) [(path, module_)]+ recheckFrom prefix [(path, module_)] case tcResult of Left (ex :: SomeException) -> do -- Just a warning to be logged in the "Output" panel and not shown to the user as an error message@@ -223,15 +225,17 @@ logWarning ("Encountered an exception while typechecking:\n" <> tshow ex) publishBlockedDiagnostics rootPath path (map fst rest) Right (Left err) -> do- logError ("An impossible error happened! Please report a bug:\n" <> T.pack (ppTypeErrorInScopedContext' BottomUp err))+ logError ("An impossible error happened! Please report a bug:\n" <> T.pack (ppTypeErrorInScopedContext BottomUp err)) publishModuleDiagnostics path [err] [] -- sort of impossible publishBlockedDiagnostics rootPath path (map fst rest)- Right (Right ((checkedModules, errors), holeInfos)) -> do+ Right (Right (checkedNow, holeInfos)) -> do+ let errors = checkedErrors checkedNow logDebug (T.pack path <> ": " <> tshow (length errors) <> " errors, " <> tshow (length holeInfos) <> " holes")- let decls = fromMaybe [] (lookup path checkedModules)+ let decls = fromMaybe [] (lookup path (declViews checkedNow)) checked' = checked ++- [(path, RzkCachedModule decls (filter ((== path) . filepathOfTypeError) errors))]+ [(path, RzkCachedModule checkedNow decls+ (filter ((== path) . filepathOfTypeError) errors))] cacheTypecheckedModules checked' publishModuleDiagnostics path errors holeInfos -- Stop at the first module with errors, like the batch checker@@ -253,7 +257,7 @@ -- per-source map over the old one, and @partitionBySource []@ has no -- "rzk" key, so the old diagnostics would survive and be re-sent. A -- max count of 0 forces an empty publish to the client, clearing it.- publishModuleDiagnostics :: FilePath -> [TypeErrorInScopedContext VarIdent] -> [HoleInfo] -> LSP ()+ publishModuleDiagnostics :: FilePath -> [TypeErrorInScopedContext] -> [HoleInfo] -> LSP () publishModuleDiagnostics path typeErrors holeInfos = do let errDiagnostics = [ (filepathOfTypeError err, [diagnosticOfTypeError err]) | err <- typeErrors ]@@ -291,12 +295,11 @@ (Just []) -- related information Nothing -- data that is preserved between different calls - filepathOfTypeError :: TypeErrorInScopedContext var -> FilePath- filepathOfTypeError (PlainTypeError err) =- case location (typeErrorContext err) >>= locationFilePath of+ filepathOfTypeError :: TypeErrorInScopedContext -> FilePath+ filepathOfTypeError (TypeErrorInScopedContext ctx _err) =+ case ctxLocation ctx >>= locationFilePath of Just path -> path _ -> error "the impossible happened! Please contact Abdelrahman immediately!!!"- filepathOfTypeError (ScopedTypeError _orig err) = filepathOfTypeError err -- Map a structured library diagnostic to an LSP diagnostic. The range is -- line-level (whole line), reflecting the granularity rzk currently retains.@@ -324,7 +327,7 @@ Diag.SeverityInformation -> DiagnosticSeverity_Information Diag.SeverityHint -> DiagnosticSeverity_Hint - diagnosticOfTypeError :: TypeErrorInScopedContext VarIdent -> Diagnostic+ diagnosticOfTypeError :: TypeErrorInScopedContext -> Diagnostic diagnosticOfTypeError = lspDiagnosticOf . Diag.diagnoseTypeError TopDown diagnosticOfHole :: HoleInfo -> Diagnostic@@ -389,10 +392,10 @@ logDebug ("Sending " <> T.pack (show (length items)) <> " completion items") res $ Right $ InL items where- declsToItems :: FilePath -> (FilePath, [Decl']) -> [CompletionItem]+ declsToItems :: FilePath -> (FilePath, [DeclView]) -> [CompletionItem] declsToItems root (path, decls) = map (declToItem root path) decls- declToItem :: FilePath -> FilePath -> Decl' -> CompletionItem- declToItem rootDir path (Decl name type' _ _ _ _loc) = def+ declToItem :: FilePath -> FilePath -> DeclView -> CompletionItem+ declToItem rootDir path (DeclView name type' _ _loc) = def & label .~ T.pack (printTree $ getVarIdent name) & detail ?~ T.pack (show type')@@ -614,34 +617,36 @@ -- global's type). The surface annotation from the reference index is -- the fallback, e.g. for mid-edit or ill-typed code with no cache. defCol = RefInd.positionCharacter (RefInd.rangeStart (RefInd.locationRange (RefInd.bindingDef binding)))- -- All cached declarations go in scope, so that splitting a pair- -- binder can unfold defined Σ-types from any file of the project.- allDecls = concatMap (cachedModuleDecls . snd) cached+ -- The whole checked project is in scope, so that splitting a pair binder+ -- can unfold defined Σ-types from any file of it.+ binderTypes = case reverse cached of+ (_, entry) : _ -> binderTypesOfFile (cachedModuleChecked entry) file+ [] -> [] elaboratedLocal = lookup (defLine, defCol) [ ((l - 1, c - 1), t)- | (v, t) <- binderTypesInScopeOf allDecls decls+ | (v, t) <- binderTypes , let VarIdent (RzkPosition _path mpos) _ = getVarIdent v , Just (l, c) <- [mpos] ] signature = case elaboratedLocal of- Just (TypeView t) -> formatSignature (T.unpack name) (fromTerm' t)+ Just (TypeView t) -> formatSignature (T.unpack name) (getRendered t) Just (ShapeView c tope) -> T.unpack name ++ " : " ++ show c ++ " | " ++ show tope Nothing -> case find declOnSameLine decls of- Just (Decl _ ty _ _ _ _) -> formatSignature (T.unpack name) (fromTerm' (untyped ty))+ Just d -> formatSignature (T.unpack name) (getRendered (declViewType d)) Nothing -> case RefInd.bindingType binding of Just ann -> T.unpack name ++ " : " ++ T.unpack ann Nothing -> case find declWithName decls of- Just (Decl _ ty _ _ _ _) -> formatSignature (T.unpack name) (fromTerm' (untyped ty))- Nothing -> T.unpack name ++ " : ?"- declWithName (Decl v _ _ _ _ _) =+ Just d -> formatSignature (T.unpack name) (getRendered (declViewType d))+ Nothing -> T.unpack name ++ " : ?"+ declWithName (DeclView v _ _ _) = T.pack (printTree (getVarIdent v)) == name- declOnSameLine d@(Decl _ _ _ _ _ mloc) =+ declOnSameLine d@(DeclView _ _ _ mloc) = declWithName d && (locationLine =<< mloc) == Just (defLine + 1) -- | The printed name of a declaration and the range of its defining -- occurrence, shared by the document and workspace symbol providers.-declNameRange :: Decl' -> (T.Text, Range)-declNameRange (Decl name _ _ _ _ _) = (T.pack (printTree ident), range)+declNameRange :: DeclView -> (T.Text, Range)+declNameRange (DeclView name _ _ _) = (T.pack (printTree ident), range) where ident = getVarIdent name VarIdent pos _ = ident@@ -659,10 +664,10 @@ let decls = maybe [] cachedModuleDecls (lookup currentFile cachedModules) res $ Right $ InR $ InL $ map declToSymbol decls where- declToSymbol :: Decl' -> DocumentSymbol- declToSymbol decl@(Decl _ type' _ _ _ _loc) = DocumentSymbol+ declToSymbol :: DeclView -> DocumentSymbol+ declToSymbol decl@(DeclView _ type' _ _loc) = DocumentSymbol { _name = symbolName- , _detail = Just (T.pack (show (untyped type')))+ , _detail = Just (T.pack (show type')) , _kind = SymbolKind_Function , _tags = Nothing , _deprecated = Nothing@@ -705,15 +710,18 @@ -- | Detects if the given path has changes in its declaration compared to what's in the cache isChanged :: RzkTypecheckCache -> FilePath -> LSP IsChanged isChanged cache path = toIsChanged $ do- let cacheWithoutErrors = map (fmap cachedModuleDecls) cache errors <- maybeToEitherLSP $ cachedModuleErrors <$> lookup path cache cachedDecls <- maybeToEitherLSP $ cachedModuleDecls <$> lookup path cache module' <- toExceptTLifted $ parseModuleFile path+ -- Re-check this file from the context of the prefix before it.+ let prefix = case reverse (takeWhile ((/= path) . fst) cache) of+ (_, entry) : _ -> cachedModuleChecked entry+ [] -> emptyChecked e <- toExceptTLifted $ try @SomeException $ evaluate $- defaultTypeCheck (typecheckModulesWithLocationIncremental (takeWhile ((/= path) . fst) cacheWithoutErrors) [(path, module')])- (checkedModules, errors') <- toExceptT $ return e- decls' <- maybeToEitherLSP $ lookup path checkedModules- return $ if null errors' && null errors && decls' == cachedDecls+ recheckFrom prefix [(path, module')]+ (checkedNow, _holes) <- toExceptT $ return e+ decls' <- maybeToEitherLSP $ lookup path (declViews checkedNow)+ return $ if null (checkedErrors checkedNow) && null errors && decls' == cachedDecls then NotChanged else HasChanged where
src/Language/Rzk/VSCode/ReferenceIndex.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE OverloadedStrings #-} module Language.Rzk.VSCode.ReferenceIndex (@@ -15,13 +16,17 @@ ) where import Control.Applicative ((<|>))-import Data.Bifunctor (bimap) import qualified Data.Map.Strict as Map import Data.Maybe (listToMaybe) import qualified Data.Text as T -import qualified Free.Scoped as Scoped-import qualified Language.Rzk.Free.Syntax as Free+import Language.Rzk.Foil.Convert (withOpenTerm)+import qualified Language.Rzk.Foil.Names as Free+import Language.Rzk.Foil.Print (fromTerm)+import Language.Rzk.Foil.Syntax (Term, instantiateUntyped,+ pattern CubeProduct, pattern First,+ pattern Pair, pattern Second,+ pattern TypeSigma) import qualified Language.Rzk.Syntax as Rzk data Uri = Uri@@ -171,26 +176,35 @@ -- only inherit their cube. splitPairAnn :: Rzk.Term -> BinderAnn -> Maybe (BinderAnn, BinderAnn) splitPairAnn firstComp (AnnShape cube _tope) = splitPairAnn firstComp (AnnType cube)-splitPairAnn firstComp (AnnType ty) = case Free.toTerm' ty of- Free.CubeProduct a b -> Just (fromCore a, fromCore b)- Free.TypeSigma _ _ a scope ->- Just ( fromCore a- , fromCore (reduceProjections (Scoped.substitute (Free.toTerm' firstComp) scope))- )- _ -> Nothing+splitPairAnn firstComp (AnnType ty) =+ -- The annotation is an open term (it mentions whatever is in scope where it was+ -- written), so every identifier in it gets a name, and the names are mapped back+ -- when it is printed.+ withOpenTerm (Rzk.Pair Nothing ty firstComp) $ \scope names paired ->+ case paired of+ Pair ty' first' -> case ty' of+ CubeProduct a b -> Just (render names a, render names b)+ TypeSigma _ _ a scoped ->+ Just ( render names a+ , render names (reduceProjections (instantiateUntyped scope scoped first'))+ )+ _ -> Nothing+ _ -> Nothing where- fromCore = AnnType . Free.fromTerm'+ render names = AnnType . fromTerm [] [] names --- | Reduce projections of literal pairs (π₁ (a, b) → a). A pattern binder--- refers to its components through projections, so substituting a pair for--- it leaves these redexes behind.-reduceProjections :: Scoped.FS Free.TermF a -> Scoped.FS Free.TermF a+-- | Reduce projections of literal pairs (π₁ (a, b) → a). A pattern binder refers to+-- its components through projections, so substituting a pair for it leaves these+-- redexes behind.+reduceProjections :: Term n -> Term n reduceProjections = \case- Scoped.Pure x -> Scoped.Pure x- Scoped.Free f -> case Scoped.Free (bimap reduceProjections reduceProjections f) of- Free.First (Free.Pair a _) -> a- Free.Second (Free.Pair _ b) -> b- t -> t+ First t -> case reduceProjections t of+ Pair a _ -> a+ t' -> First t'+ Second t -> case reduceProjections t of+ Pair _ b -> b+ t' -> Second t'+ t -> t -- | A pattern as the term it matches. patternTerm :: Rzk.Pattern -> Rzk.Term
src/Rzk/Diagnostic.hs view
@@ -15,7 +15,6 @@ import Data.Aeson (ToJSON (..), Value (String), object, (.=)) -import Language.Rzk.Free.Syntax (VarIdent) import Rzk.TypeCheck -- | Diagnostic severity, mirroring the usual LSP levels.@@ -123,7 +122,7 @@ -- | A stable tag for a type error, used as its diagnostic code. Independent of -- the variable type, so it survives the scoped-error unfolding.-typeErrorTag :: TypeError var -> String+typeErrorTag :: TypeError n -> String typeErrorTag = \case TypeErrorOther{} -> "TypeErrorOther" TypeErrorUnify{} -> "TypeErrorUnify"@@ -151,27 +150,25 @@ TypeErrorUnusedUsedVariables{} -> "TypeErrorUnusedUsedVariables" TypeErrorImplicitAssumption{} -> "TypeErrorImplicitAssumption" --- | The tag of a scoped type error (peels the binder layers; the tag does not--- depend on the variable type).-typeErrorTagInScopedContext :: TypeErrorInScopedContext var -> String-typeErrorTagInScopedContext = \case- PlainTypeError e -> typeErrorTag (typeErrorError e)- ScopedTypeError _ e -> typeErrorTagInScopedContext e+-- | The tag of a type error.+--+-- An error carries the context it was raised in, so there are no binder layers to+-- peel: the old representation nested the error one Inc deeper at every binder.+typeErrorTagInScopedContext :: TypeErrorInScopedContext -> String+typeErrorTagInScopedContext (TypeErrorInScopedContext _ctx err) = typeErrorTag err --- | The source location of a scoped type error (the enclosing command's line).-locationOfTypeError :: TypeErrorInScopedContext var -> Maybe LocationInfo-locationOfTypeError = \case- PlainTypeError e -> location (typeErrorContext e)- ScopedTypeError _ e -> locationOfTypeError e+-- | The source location of a type error (the enclosing command's line).+locationOfTypeError :: TypeErrorInScopedContext -> Maybe LocationInfo+locationOfTypeError (TypeErrorInScopedContext ctx _err) = ctxLocation ctx -- | A structured diagnostic for a type error. The message is the usual -- formatted error text; severity is always 'SeverityError'.-diagnoseTypeError :: OutputDirection -> TypeErrorInScopedContext VarIdent -> Diagnostic+diagnoseTypeError :: OutputDirection -> TypeErrorInScopedContext -> Diagnostic diagnoseTypeError dir err = Diagnostic { diagnosticSeverity = SeverityError , diagnosticCode = typeErrorTagInScopedContext err , diagnosticLocation = locationOfTypeError err- , diagnosticMessage = ppTypeErrorInScopedContext' dir err+ , diagnosticMessage = ppTypeErrorInScopedContext dir err , diagnosticHole = Nothing }
src/Rzk/Main.hs view
@@ -93,13 +93,13 @@ typecheckString :: T.Text -> Either T.Text T.Text typecheckString moduleString = do rzkModule <- Rzk.parseModule moduleString- case defaultTypeCheck (typecheckModules [rzkModule]) of+ case typecheckModules [("<stdin>", rzkModule)] of Left err -> Left $ T.unlines [ "An error occurred when typechecking!" , "Rendering type error... (this may take a few seconds)" , T.unlines [ "Type Error:"- , T.pack $ ppTypeErrorInScopedContext' BottomUp err+ , T.pack $ ppTypeErrorInScopedContext BottomUp err ] ] Right _ -> pure "Everything is ok!"
+ src/Rzk/Render/Geometry.hs view
@@ -0,0 +1,274 @@+{-# LANGUAGE RecordWildCards #-}++-- | The geometry behind the SVG rendering of cubes, and nothing else.+--+-- Rzk renders a (sub)shape of a cube as an SVG diagram: the vertices, edges and+-- faces of the unit cube are projected to the plane through a camera, and each+-- of them is labelled with the term that inhabits it. This module holds the part+-- of that story which knows nothing about terms: the projection matrices, the+-- camera, and 'renderCube', which draws a cube given only a function saying what+-- (if anything) to draw on each of its parts.+--+-- Nothing here mentions the type checker, so it is shared by both term+-- representations during the free-foil migration.+module Rzk.Render.Geometry where++import Data.List (intercalate, tails)++-- | The name of a vertex of the unit cube, as a string of coordinates+-- (e.g. @"010"@).+type PointId = String++-- | The name of a subshape of the unit cube: its vertices, in order, joined by+-- dashes (e.g. @"000-011"@ for an edge, @"000"@ for a vertex).+type ShapeId = [PointId]++type Point2D a = (a, a)+type Point3D a = (a, a, a)+type Edge3D a = (Point3D a, Point3D a)+type Face3D a = (Point3D a, Point3D a, Point3D a)+type Volume3D a = (Point3D a, Point3D a, Point3D a, Point3D a)++data CubeCoords2D a b = CubeCoords2D+ { vertices :: [(Point3D a, Point2D b)]+ , edges :: [(Edge3D a, (Point2D b, Point2D b))]+ , faces :: [(Face3D a, (Point2D b, Point2D b, Point2D b))]+ , volumes :: [(Volume3D a, (Point2D b, Point2D b, Point2D b, Point2D b))]+ }++data Matrix3D a = Matrix3D+ a a a+ a a a+ a a a++data Matrix4D a = Matrix4D+ a a a a+ a a a a+ a a a a+ a a a a++data Vector3D a = Vector3D a a a++data Vector4D a = Vector4D a a a a++rotateX :: Floating a => a -> Matrix3D a+rotateX theta = Matrix3D+ 1 0 0+ 0 (cos theta) (- sin theta)+ 0 (sin theta) (cos theta)++rotateY :: Floating a => a -> Matrix3D a+rotateY theta = Matrix3D+ (cos theta) 0 (sin theta)+ 0 1 0+ (- sin theta) 0 (cos theta)++rotateZ :: Floating a => a -> Matrix3D a+rotateZ theta = Matrix3D+ (cos theta) (- sin theta) 0+ (sin theta) (cos theta) 0+ 0 0 1++data Camera a = Camera+ { cameraPos :: Point3D a+ , cameraFoV :: a+ , cameraAspectRatio :: a+ , cameraAngleY :: a+ , cameraAngleX :: a+ }++viewRotateX :: Floating a => Camera a -> Matrix4D a+viewRotateX Camera{..} = matrix3Dto4D (rotateX cameraAngleX)++viewRotateY :: Floating a => Camera a -> Matrix4D a+viewRotateY Camera{..} = matrix3Dto4D (rotateY cameraAngleY)++viewTranslate :: Num a => Camera a -> Matrix4D a+viewTranslate Camera{..} = Matrix4D+ 1 0 0 0+ 0 1 0 0+ 0 0 1 0+ (-x) (-y) (-z) 1+ where+ (x, y, z) = cameraPos++project2D :: Floating a => Camera a -> Matrix4D a+project2D Camera{..} = Matrix4D+ (2 * n / (r - l)) 0 ((r + l) / (r - l)) 0+ 0 (2 * n / (t - b)) ((t + b) / (t - b)) 0+ 0 0 (- (f + n) / (f - n)) (- 2 * f * n / (f - n))+ 0 0 (-1) 0+ where+ n = 1+ f = 2+ r = n * tan (cameraFoV / 2)+ l = -r+ t = r * cameraAspectRatio+ b = -t+++matrixVectorMult4D :: Num a => Matrix4D a -> Vector4D a -> Vector4D a+matrixVectorMult4D+ (Matrix4D+ a1 a2 a3 a4+ b1 b2 b3 b4+ c1 c2 c3 c4+ d1 d2 d3 d4)+ (Vector4D a b c d)+ = Vector4D a' b' c' d'+ where+ a' = sum (zipWith (*) [a1, b1, c1, d1] [a, b, c, d])+ b' = sum (zipWith (*) [a2, b2, c2, d2] [a, b, c, d])+ c' = sum (zipWith (*) [a3, b3, c3, d3] [a, b, c, d])+ d' = sum (zipWith (*) [a4, b4, c4, d4] [a, b, c, d])++matrix3Dto4D :: Num a => Matrix3D a -> Matrix4D a+matrix3Dto4D+ (Matrix3D+ a1 b1 c1+ a2 b2 c2+ a3 b3 c3) = Matrix4D+ a1 b1 c1 0+ a2 b2 c2 0+ a3 b3 c3 0+ 0 0 0 1++fromAffine :: Fractional a => Vector4D a -> (Point2D a, a)+fromAffine (Vector4D a b c d) = ((x, y), zIndex)+ where+ x = a / d+ y = b / d+ zIndex = c / d++point3Dto2D :: Floating a => Camera a -> a -> Point3D a -> (Point2D a, a)+point3Dto2D camera rotY (x, y, z) = fromAffine $+ foldr matrixVectorMult4D (Vector4D x y z 1) $ reverse+ [ matrix3Dto4D (rotateY rotY)+ , viewTranslate camera+ , viewRotateY camera+ , viewRotateX camera+ , project2D camera+ ]++-- | What to draw on one part (vertex, edge or face) of a cube.+data RenderObjectData = RenderObjectData+ { renderObjectDataLabel :: String+ , renderObjectDataFullLabel :: String+ , renderObjectDataColor :: String+ }++limitLength :: Int -> String -> String+limitLength n s+ | length s > n = take (n - 1) s <> "…"+ | otherwise = s++-- | Apply the term-hiding policy to a cell's render data: drop the @\<title\>@+-- (the full term) from every cell, and blank the visible label of a+-- proof-coloured (interior) cell. Boundary cells (coloured otherwise) keep+-- their given labels. A no-op when not hiding.+hideTermData :: Bool -> String -> RenderObjectData -> RenderObjectData+hideTermData False _ d = d+hideTermData True mainColor d+ | renderObjectDataColor d == mainColor =+ d { renderObjectDataLabel = "", renderObjectDataFullLabel = "" }+ | otherwise = d { renderObjectDataFullLabel = "" }++renderCube+ :: (Floating a, Show a)+ => Camera a+ -> a+ -> (String -> Maybe RenderObjectData)+ -> String+renderCube camera rotY renderDataOf' = unlines $ filter (not . null)+ [ "<svg class=\"rzk-render\" viewBox=\"-175 -200 350 375\" width=\"150\" height=\"150\">"+ , intercalate "\n"+ [ " <path d=\"M " <> show x1 <> " " <> show y1+ <> " L " <> show x2 <> " " <> show y2+ <> " L " <> show x3 <> " " <> show y3+ <> " Z\" style=\"fill: " <> renderObjectDataColor <> "; opacity: 0.2\"><title>" <> renderObjectDataFullLabel <> "</title></path>" <> "\n" <>+ " <text x=\"" <> show x <> "\" y=\"" <> show y <> "\" fill=\"" <> renderObjectDataColor <> "\">" <> renderObjectDataLabel <> "</text>"+ | (faceId, (((x1, y1), (x2, y2), (x3, y3)), _)) <- faces+ , Just RenderObjectData{..} <- [renderDataOf faceId]+ , let x = (x1 + x2 + x3) / 3+ , let y = (y1 + y2 + y3) / 3 ]+ , intercalate "\n"+ [ " <polyline points=\"" <> show x1 <> "," <> show y1 <> " " <> show x2 <> "," <> show y2+ <> "\" stroke=\"" <> renderObjectDataColor <> "\" stroke-width=\"3\" marker-end=\"url(#arrow)\"><title>" <> renderObjectDataFullLabel <> "</title></polyline>" <> "\n" <>+ " <text x=\"" <> show x <> "\" y=\"" <> show y <> "\" fill=\"" <> renderObjectDataColor <> "\" stroke=\"white\" stroke-width=\"10\" stroke-opacity=\".8\" paint-order=\"stroke\">" <> renderObjectDataLabel <> "</text>"+ | (edge, (((x1, y1), (x2, y2)), _)) <- edges+ , Just RenderObjectData{..} <- [renderDataOf edge]+ , let x = (x1 + x2) / 2+ , let y = (y1 + y2) / 2 ]+ , intercalate "\n"+ [ " <text x=\"" <> show x <> "\" y=\"" <> show y <> "\" fill=\"" <> renderObjectDataColor <> "\">" <> renderObjectDataLabel <> "</text>"+ | (v, ((x, y), _)) <- vertices+ , Just RenderObjectData{..} <- [renderDataOf v]]+ , "</svg>" ]+ where+ renderDataOf shapeId =+ case renderDataOf' shapeId of+ Nothing -> Nothing+ Just RenderObjectData{..} -> Just RenderObjectData+ -- FIXME: move constants to configurable parameters+ { renderObjectDataLabel = hideWhenLargerThan shapeId 5 renderObjectDataLabel+ , renderObjectDataFullLabel = limitLength 30 renderObjectDataFullLabel+ , .. }++ hideWhenLargerThan shapeId n s+ | null s || length s > n = if '-' `elem` shapeId then "" else "•"+ | otherwise = s++ vertices =+ [ (show x <> show y <> show z, ((500 * x'', 500 * y''), zIndex))+ | x <- [0,1]+ , y <- [0,1]+ , z <- [0,1]+ , let f c = 2 * fromInteger c - 1+ , let x' = f x+ , let y' = f (1-y)+ , let z' = f z+ , let ((x'', y''), zIndex) = point3Dto2D camera rotY (x', y', z') ]++ radius = 20++ mkEdge r (x1, y1) (x2, y2) = ((x1 + dx, y1 + dy), ((x2 - dx), (y2 - dy)))+ where+ d = sqrt ((x2 - x1)^(2 :: Int) + (y2 - y1)^(2 :: Int))+ dx = r * (x2 - x1) / d+ dy = r * (y2 - y1) / d++ scaleAround (cx, cy) s (x, y) = (cx + s * (x - cx), cy + s * (y - cy))++ mkFace (x1, y1) (x2, y2) (x3, y3) = (p1, p2, p3)+ where+ cx = (x1 + x2 + x3) / 3+ cy = (y1 + y2 + y3) / 3+ p1 = scaleAround (cx, cy) 0.85 (x1, y1)+ p2 = scaleAround (cx, cy) 0.85 (x2, y2)+ p3 = scaleAround (cx, cy) 0.85 (x3, y3)++ edges =+ [ (intercalate "-" [fromName, toName], (mkEdge radius from to, 0 :: Int))+ | (fromName, (from, _)) : vs <- tails vertices+ , (toName, (to, _)) <- vs+ , and (zipWith (<=) fromName toName)+ ]++ faces =+ [ (intercalate "-" [name1, name2, name3], (mkFace v1 v2 v3, 0 :: Int))+ | (name1, (v1, _)) : vs <- tails vertices+ , (name2, (v2, _)) : vs' <- tails vs+ , and (zipWith (<=) name1 name2)+ , (name3, (v3, _)) <- vs'+ , and (zipWith (<=) name2 name3)+ ]+++defaultCamera :: Floating a => Camera a+defaultCamera = Camera+ { cameraPos = (0, 7, 10)+ , cameraAngleY = pi+ , cameraAngleX = pi/5+ , cameraFoV = pi/15+ , cameraAspectRatio = 1+ }
src/Rzk/TypeCheck.hs view
@@ -1,5507 +1,25 @@-{-# OPTIONS_GHC -fno-warn-type-defaults -fno-warn-orphans #-}-{-# LANGUAGE DeriveFoldable #-}-{-# LANGUAGE DeriveFunctor #-}-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE LambdaCase #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE RecordWildCards #-}-module Rzk.TypeCheck where--import Control.Applicative ((<|>))-import Control.Monad (forM, forM_, join, unless, when)-import Control.Monad.Except-import Control.Monad.Reader--- An explicit list: a bare 'Control.Monad.Writer' import also re-exports--- 'Data.Monoid' (incl. 'First'/'Last') on some mtl versions, which clashes with--- the 'First'/'Last' term patterns from 'Language.Rzk.Free.Syntax'.-import Control.Monad.Writer (WriterT, censor, runWriterT, tell)-import Data.Bifoldable (bifoldr)-import Data.Bifunctor (first)-import Data.List (intercalate, intersect, nub, partition,- tails, (\\))-import Data.Maybe (catMaybes, fromMaybe, isNothing,- mapMaybe)-import Data.String (IsString (..))-import Data.Tuple (swap)--import Free.Scoped-import Language.Rzk.Free.Syntax-import qualified Language.Rzk.Syntax as Rzk--import Debug.Trace-import Unsafe.Coerce---- $setup--- >>> :set -XOverloadedStrings----- | Parse and 'unsafeInferStandalone''.-instance IsString TermT' where- fromString = unsafeInferStandalone' . fromString--defaultTypeCheck- :: TypeCheck VarIdent a- -> Either (TypeErrorInScopedContext VarIdent) a-defaultTypeCheck = fmap fst . defaultTypeCheckWithHoles' emptyContext---- | Like 'defaultTypeCheck', but runs in lenient hole mode ('allowHoles') and--- also returns the holes recorded during checking (with their goal and context).-defaultTypeCheckWithHoles- :: TypeCheck VarIdent a- -> Either (TypeErrorInScopedContext VarIdent) (a, [HoleInfo])-defaultTypeCheckWithHoles = defaultTypeCheckWithHoles' (allowHoles emptyContext)--defaultTypeCheckWithHoles'- :: Context var- -> TypeCheck var a- -> Either (TypeErrorInScopedContext var) (a, [HoleInfo])-defaultTypeCheckWithHoles' ctx tc =- runExcept (runWriterT (runReaderT tc ctx))---- FIXME: merge with VarInfo-data Decl var = Decl- { declName :: var- , declType :: TermT var- , declValue :: Maybe (TermT var)- , declIsAssumption :: Bool- , declUsedVars :: [var]- , declLocation :: Maybe LocationInfo- } deriving Eq--type Decl' = Decl VarIdent--typecheckModulesWithLocationIncremental- :: [(FilePath, [Decl'])] -- ^ Cached declarations (only those that do not need rechecking).- -> [(FilePath, Rzk.Module)] -- ^ New modules to check- -> TypeCheck VarIdent ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent])-typecheckModulesWithLocationIncremental cached modulesToTypecheck = do- let decls = foldMap snd cached- localDeclsPrepared decls $ do- (checked, errors) <- typecheckModulesWithLocation' modulesToTypecheck- return (cached <> checked, errors)--typecheckModulesWithLocation' :: [(FilePath, Rzk.Module)] -> TypeCheck VarIdent ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent])-typecheckModulesWithLocation' = \case- [] -> return ([], [])- m@(path, _) : ms -> do- (decls, errs) <- typecheckModuleWithLocation m- case errs of- _:_ -> return ([(path, decls)], errs)- _ -> do- localDeclsPrepared decls $ do- (decls', errors) <- typecheckModulesWithLocation' ms- return ((path, decls) : decls', errors)---- | Typecheck modules in lenient hole mode, returning the elaborated--- declarations, any type errors, and the holes recorded (each with its goal and--- local context). This is the structured goal/context query consumed by the--- LSP and the game. Strict callers (the default CLI path, CI) keep using--- 'typecheckModulesWithLocation', where holes are 'TypeErrorUnsolvedHole'.-typecheckModulesWithHoles- :: [(FilePath, Rzk.Module)]- -> Either (TypeErrorInScopedContext VarIdent)- ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent], [HoleInfo])-typecheckModulesWithHoles = typecheckModulesWithHolesAndLemmas []---- | Like 'typecheckModulesWithHoles', but additionally offers the given named--- top-level definitions as hole candidates (each applied to holes when its type--- fits the goal). The game passes a level's allow-list of relevant lemmas so--- they surface as moves; an empty list reproduces 'typecheckModulesWithHoles'.-typecheckModulesWithHolesAndLemmas- :: [VarIdent]- -> [(FilePath, Rzk.Module)]- -> Either (TypeErrorInScopedContext VarIdent)- ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent], [HoleInfo])-typecheckModulesWithHolesAndLemmas lemmas modules =- flatten <$> defaultTypeCheckWithHoles'- (withHintLemmas lemmas (allowHoles emptyContext))- (typecheckModulesWithLocation' modules)- where- flatten ((decls, errs), holes) = (decls, errs, holes)--typecheckModulesWithLocation :: [(FilePath, Rzk.Module)] -> TypeCheck VarIdent [(FilePath, [Decl'])]-typecheckModulesWithLocation = \case- [] -> return []- m@(path, _) : ms -> do- (decls, errs) <- typecheckModuleWithLocation m- case errs of- err : _ -> do- throwError err- [] -> localDeclsPrepared decls $- ((path, decls) :) <$> typecheckModulesWithLocation ms--typecheckModules :: [Rzk.Module] -> TypeCheck VarIdent [Decl']-typecheckModules = \case- [] -> return []- m : ms -> do- (decls, errs) <- typecheckModule Nothing m- case errs of- err : _ -> do- throwError err- _ -> do- localDeclsPrepared decls $- (decls <>) <$> typecheckModules ms--typecheckModuleWithLocation :: (FilePath, Rzk.Module) -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent])-typecheckModuleWithLocation (path, module_) = do- traceTypeCheck Normal ("Checking module from " <> path) $ do- withLocation (LocationInfo { locationFilePath = Just path, locationLine = Nothing }) $- typecheckModule (Just path) module_--countCommands :: Integral a => [Rzk.Command] -> a-countCommands = fromIntegral . length--typecheckModule :: Maybe FilePath -> Rzk.Module -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent])-typecheckModule path (Rzk.Module _moduleLoc _lang commands) =- withSection Nothing (go 1 commands) $ -- FIXME: use module name? or anonymous section?- return ([], [])- where- totalCommands = countCommands commands-- go :: Integer -> [Rzk.Command] -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent])- go _i [] = return ([], [])-- go i (command@(Rzk.CommandUnsetOption _loc optionName) : moreCommands) = do- traceTypeCheck Normal ("[ " <> show i <> " out of " <> show totalCommands <> " ]"- <> " Unsetting option " <> optionName) $ do- withCommand command $ do- unsetOption optionName $- go (i + 1) moreCommands-- go i (command@(Rzk.CommandSetOption _loc optionName optionValue) : moreCommands) = do- traceTypeCheck Normal ("[ " <> show i <> " out of " <> show totalCommands <> " ]"- <> " Setting option " <> optionName <> " = " <> optionValue ) $ do- withCommand command $ do- setOption optionName optionValue $- go (i + 1) moreCommands-- go i (command@(Rzk.CommandDefine _loc name (Rzk.DeclUsedVars _ vars) params ty term) : moreCommands) =- traceTypeCheck Normal ("[ " <> show i <> " out of " <> show totalCommands <> " ]"- <> " Checking #define " <> Rzk.printTree name ) $ do- withCommand command $ do- mapM_ checkDefinedVar (varIdentAt path <$> vars)- paramDecls <- concat <$> mapM paramToParamDecl params- -- Store the elaborated type and term unreduced, but memoise their- -- WHNF on the top node (see 'memoizeWHNF'). Reducing in place would- -- discard or expose a variable occurrence, so the section- -- unused/implicit-assumption checks (run over the stored type and- -- value) would disagree with the term the user wrote; keeping the- -- WHNF cached preserves the original one-shot reduction.- ty' <- memoizeWHNF =<< typecheck (toTerm' (addParamDecls paramDecls ty)) universeT- term' <- memoizeWHNF =<< typecheck (toTerm' (addParams params term)) ty'- loc <- asks location- let decl = Decl (varIdentAt path name) ty' (Just term') False (varIdentAt path <$> vars) loc- fmap (first (decl :)) $- localDeclPrepared decl $ do- Context{..} <- ask- termSVG <-- case renderBackend of- Just RenderSVG -> renderTermSVG (Pure (varIdentAt path name))- Just RenderLaTeX -> issueTypeError $ TypeErrorOther "\"latex\" rendering is not yet supported"- Nothing -> pure Nothing- maybe id trace termSVG $ do- go (i + 1) moreCommands-- go i (command@(Rzk.CommandPostulate _loc name (Rzk.DeclUsedVars _ vars) params ty) : moreCommands) =- traceTypeCheck Normal ("[ " <> show i <> " out of " <> show totalCommands <> " ]"- <> " Checking #postulate " <> Rzk.printTree name) $ do- withCommand command $ do- mapM_ checkDefinedVar (varIdentAt path <$> vars)- paramDecls <- concat <$> mapM paramToParamDecl params- ty' <- memoizeWHNF =<< typecheck (toTerm' (addParamDecls paramDecls ty)) universeT- loc <- asks location- let decl = Decl (varIdentAt path name) ty' Nothing False (varIdentAt path <$> vars) loc- fmap (first (decl :)) $- localDeclPrepared decl $- go (i + 1) moreCommands-- go i (command@(Rzk.CommandCheck _loc term ty) : moreCommands) =- traceTypeCheck Normal ("[ " <> show i <> " out of " <> show totalCommands <> " ]"- <> " Checking " <> Rzk.printTree term <> " : " <> Rzk.printTree ty ) $ do- withCommand command $ do- ty' <- typecheck (toTerm' ty) universeT >>= whnfT- _term' <- typecheck (toTerm' term) ty'- go (i + 1) moreCommands-- go i (Rzk.CommandCompute loc term : moreCommands) =- go i (Rzk.CommandComputeWHNF loc term : moreCommands)-- go i (command@(Rzk.CommandComputeNF _loc term) : moreCommands) =- traceTypeCheck Normal ("[ " <> show i <> " out of " <> show totalCommands <> " ]"- <> " Computing NF for " <> Rzk.printTree term) $ do- withCommand command $ do- term' <- infer (toTerm' term) >>= nfT- traceTypeCheck Normal (" " <> show (untyped term')) $ do- go (i + 1) moreCommands-- go i (command@(Rzk.CommandComputeWHNF _loc term) : moreCommands) =- traceTypeCheck Normal ("[ " <> show i <> " out of " <> show totalCommands <> " ]"- <> " Computing WHNF for " <> Rzk.printTree term) $ do- withCommand command $ do- term' <- infer (toTerm' term) >>= whnfT- traceTypeCheck Normal (" " <> show (untyped term')) $ do- go (i + 1) moreCommands-- go i (command@(Rzk.CommandAssume _loc names ty) : moreCommands) =- traceTypeCheck Normal ("[ " <> show i <> " out of " <> show totalCommands <> " ]"- <> " Checking #assume " <> intercalate " " [ Rzk.printTree name | name <- names ] ) $ do- withCommand command $ do- ty' <- typecheck (toTerm' ty) universeT- loc <- asks location- let decls = [ Decl (varIdentAt path name) ty' Nothing True [] loc | name <- names ]- fmap (first (decls <>)) $- localDeclsPrepared decls $- go (i + 1) moreCommands-- go i (command@(Rzk.CommandSection _loc name) : moreCommands) = do- withCommand command $ do- (sectionCommands, moreCommands') <- splitSectionCommands name moreCommands- withSection (Just name) (go i sectionCommands) $ do- go (i + countCommands sectionCommands) moreCommands'-- go _i (command@(Rzk.CommandSectionEnd _loc endName) : _moreCommands) = do- withCommand command $- issueTypeError $ TypeErrorOther $- "unexpected #end " <> Rzk.printTree endName <> ", no section was declared!"---splitSectionCommands :: Rzk.SectionName -> [Rzk.Command] -> TypeCheck var ([Rzk.Command], [Rzk.Command])-splitSectionCommands name [] =- issueTypeError (TypeErrorOther $ "Section " <> Rzk.printTree name <> " is not closed with an #end")-splitSectionCommands name (Rzk.CommandSection _loc name' : moreCommands) = do- (cs1, cs2) <- splitSectionCommands name' moreCommands- (cs3, cs4) <- splitSectionCommands name cs2- return (cs1 <> cs3, cs4)-splitSectionCommands name (Rzk.CommandSectionEnd _loc endName : moreCommands) = do- when (Rzk.printTree name /= Rzk.printTree endName) $- issueTypeError $ TypeErrorOther $- "unexpected #end " <> Rzk.printTree endName <> ", expecting #end " <> Rzk.printTree name- return ([], moreCommands)-splitSectionCommands name (command : moreCommands) = do- (cs1, cs2) <- splitSectionCommands name moreCommands- return (command : cs1, cs2)--setOption :: String -> String -> TypeCheck var a -> TypeCheck var a-setOption "verbosity" = \case- "debug" -> localVerbosity Debug- "normal" -> localVerbosity Normal- "silent" -> localVerbosity Silent- _ -> const $- issueTypeError $ TypeErrorOther "unknown verbosity level (use \"debug\", \"normal\", or \"silent\")"-setOption "render" = \case- "svg" -> localRenderBackend (Just RenderSVG)- "latex" -> localRenderBackend (Just RenderLaTeX)- "none" -> localRenderBackend Nothing- _ -> const $- issueTypeError $ TypeErrorOther "unknown render backend (use \"svg\", \"latex\", or \"none\")"--- | Render the shape only, hiding the proof term (drop the @\<title\>@--- everywhere and blank interior labels), so a worked term can be shown as the--- cell it builds without giving the term away (see 'renderHideTerm').-setOption "render-hide-term" = \case- "yes" -> localHideTerm True- "no" -> localHideTerm False- _ -> const $- issueTypeError $ TypeErrorOther "unknown value for \"render-hide-term\" (use \"yes\" or \"no\")"-setOption optionName = const $ const $- issueTypeError $ TypeErrorOther ("unknown option " <> show optionName)--unsetOption :: String -> TypeCheck var a -> TypeCheck var a-unsetOption "verbosity" = localVerbosity (verbosity emptyContext)-unsetOption "render" = localRenderBackend (renderBackend emptyContext)-unsetOption "render-hide-term" = localHideTerm (renderHideTerm emptyContext)-unsetOption optionName = const $- issueTypeError $ TypeErrorOther ("unknown option " <> show optionName)--paramToParamDecl :: Rzk.Param -> TypeCheck var [Rzk.ParamDecl]-paramToParamDecl (Rzk.ParamPatternShapeDeprecated loc pat cube tope) = pure- [ Rzk.ParamTermShape loc (patternToTerm pat) cube tope ]-paramToParamDecl (Rzk.ParamPatternShape loc pats cube tope) = pure- [ Rzk.ParamTermShape loc (patternToTerm pat) cube tope | pat <- pats]-paramToParamDecl (Rzk.ParamPatternType loc pats ty) = pure- [ Rzk.ParamTermType loc (patternToTerm pat) ty | pat <- pats ]-paramToParamDecl Rzk.ParamPattern{} = issueTypeError $- TypeErrorOther "untyped pattern in parameters"-paramToParamDecl (Rzk.ParamPatternModalType loc pats mc ty) = pure- [ Rzk.ParamTermModalType loc (patternToTerm pat) mc ty | pat <- pats ]-paramToParamDecl (Rzk.ParamPatternModalShape loc pats mc cube tope) = pure- [ Rzk.ParamTermModalShape loc (patternToTerm pat) mc cube tope | pat <- pats ]--addParamDecls :: [Rzk.ParamDecl] -> Rzk.Term -> Rzk.Term-addParamDecls [] = id-addParamDecls (paramDecl : paramDecls)- = Rzk.TypeFun Nothing paramDecl . addParamDecls paramDecls--addParams :: [Rzk.Param] -> Rzk.Term -> Rzk.Term-addParams [] = id-addParams params = Rzk.Lambda Nothing params--data TypeError var- = TypeErrorOther String- | TypeErrorUnify (TermT var) (TermT var) (TermT var)- | TypeErrorUnifyTerms (TermT var) (TermT var)- | TypeErrorNotPair (TermT var) (TermT var)- | TypeErrorNotModal (Term var) TModality (TermT var)- | TypeErrorModalityMismatch TModality TModality (Term var)- | TypeErrorUnaccessibleVar var TModality TModality- | TypeErrorNotTypeInModal (TermT var)- | TypeErrorNotFunction (TermT var) (TermT var)- | TypeErrorUnexpectedLambda (Term var) (TermT var)- | TypeErrorUnexpectedPair (Term var) (TermT var)- | TypeErrorUnexpectedRefl (Term var) (TermT var)- | TypeErrorCannotInferBareLambda (Term var)- | TypeErrorCannotInferBareRefl (Term var)- | TypeErrorCannotInferHole (Term var)- | TypeErrorUnsolvedHole (Maybe VarIdent) (TermT var)- | TypeErrorUndefined var- | TypeErrorTopeNotSatisfied [TermT var] (TermT var)- | TypeErrorTopeContextDisjoint (TermT var) [TermT var]- | TypeErrorTopesNotEquivalent (TermT var) (TermT var)- | TypeErrorInvalidArgumentType (Term var) (TermT var)- | TypeErrorDuplicateTopLevel [VarIdent] VarIdent- | TypeErrorUnusedVariable var (TermT var)- | TypeErrorUnusedUsedVariables [var] var- | TypeErrorImplicitAssumption (var, TermT var) var- deriving (Functor, Foldable)--data TypeErrorInContext var = TypeErrorInContext- { typeErrorError :: TypeError var- , typeErrorContext :: Context var- } deriving (Functor, Foldable)--data TypeErrorInScopedContext var- = PlainTypeError (TypeErrorInContext var)- | ScopedTypeError (Maybe VarIdent) (TypeErrorInScopedContext (Inc var))- deriving (Functor, Foldable)--type TypeError' = TypeError VarIdent--ppModality :: TModality -> String-ppModality = \case- Flat -> "♭"- Sharp -> "♯"- Op -> "ᵒᵖ"- Id -> "_id"---- | Render a type error, folding pattern-binder projections (e.g. @π₁ x@ back to--- the user's @t@) and showing a bare pattern point as the pattern, using the--- context's freshened binders (see 'contextBinders').-ppTypeError' :: [(VarIdent, Binder)] -> TypeError' -> String-ppTypeError' fbs = \case- TypeErrorOther msg -> msg- TypeErrorUnify term expected actual -> block TopDown- [ "cannot unify expected type"- , " " <> ppU (untyped expected)- , "with actual type"- , " " <> ppU (untyped actual)- , "for term"- , " " <> ppU (untyped term) ]- TypeErrorUnifyTerms expected actual -> block TopDown- [ "cannot unify term"- , " " <> ppU (untyped expected)- , "with term"- , " " <> ppU (untyped actual) ]- TypeErrorNotPair term ty -> block TopDown- [ "expected a cube product or dependent pair"- , "but got type"- , " " <> ppU (untyped ty)- , "for term"- , " " <> ppU (untyped term)- , case ty of- TypeFunT{} -> "\nPerhaps the term is applied to too few arguments?"- _ -> ""- ]- TypeErrorNotModal term m ty -> block TopDown- [ "expected modal type " <> ppModality m <> " ?"- , "but got type"- , " " <> ppU (untyped ty)- , "for term"- , " " <> ppU term- ]- TypeErrorModalityMismatch expected actual term -> block TopDown- [ "modality mismatch"- , " expected " <> ppModality expected- , " but got " <> ppModality actual- , "for term"- , " " <> ppU term- ]- TypeErrorUnaccessibleVar _var varMod locks -> block TopDown- [ "unaccessible var with modality " <> ppModality varMod- , " under locks " <> ppModality locks- ]- TypeErrorNotTypeInModal ty -> block TopDown- [ "expected a type inside modal type"- , "but got"- , " " <> ppU (untyped ty)- ]-- TypeErrorUnexpectedLambda term ty -> block TopDown- [ "unexpected lambda abstraction"- , " " <> ppU term- , "when typechecking against a non-function type"- , " " <> ppTyped ty- ]- TypeErrorUnexpectedPair term ty -> block TopDown- [ "unexpected pair"- , " " <> ppU term- , "when typechecking against a type that is not a product or a dependent sum"- , " " <> ppTyped ty- ]- TypeErrorUnexpectedRefl term ty -> block TopDown- [ "unexpected refl"- , " " <> ppU term- , "when typechecking against a type that is not an identity type"- , " " <> ppTyped ty- ]-- TypeErrorNotFunction term ty -> block TopDown- [ "expected a function or extension type"- , "but got type"- , " " <> ppU (untyped ty)- , "for term"- , " " <> ppU (untyped term)- , case term of- AppT _ty f _x -> "\nPerhaps the term\n " <> ppU (untyped f) <> "\nis applied to too many arguments?"- _ -> ""- ]- TypeErrorCannotInferBareLambda term -> block TopDown- [ "cannot infer the type of the argument"- , "in lambda abstraction"- , " " <> ppU term- ]- TypeErrorCannotInferBareRefl term -> block TopDown- [ "cannot infer the type of term"- , " " <> ppU term- ]- TypeErrorCannotInferHole term -> block TopDown- [ "cannot infer the type of a hole"- , " " <> ppU term- , "a hole is only allowed where its type is already known (checking position)"- ]- TypeErrorUnsolvedHole mname goal -> block TopDown- [ "found an unsolved hole" <> maybe "" (\name -> " ?" <> show name) mname- , "expected type (goal):"- , " " <> ppU (untyped goal)- ]- TypeErrorUndefined var -> block TopDown- [ "undefined variable: " <> show (Pure var :: Term') ]- TypeErrorTopeNotSatisfied topes tope -> block TopDown- [ "local context is not included in (does not entail) the tope"- , " " <> ppU (untyped tope)- , "in local context (normalised)"- , intercalate "\n" (map (" " <>) (map ppTyped topes))] -- FIXME: remove- TypeErrorTopeContextDisjoint tope topes -> block TopDown- [ "the tope"- , " " <> ppU (untyped tope)- , "is disjoint from the local tope context (their conjunction is the empty tope ⊥),"- , "so this restriction face or recOR branch is vacuous everywhere"- , "in local context (normalised)"- , intercalate "\n" (map (" " <>) (map ppTyped topes))]- TypeErrorTopesNotEquivalent expected actual -> block TopDown- [ "expected tope"- , " " <> ppU (untyped expected)- , "but got"- , " " <> ppU (untyped actual) ]-- TypeErrorInvalidArgumentType argType argKind -> block TopDown- [ "invalid function parameter type"- , " " <> ppU argType- , "function parameter can be a cube, a shape, or a type"- , "but given parameter type has type"- , " " <> ppU (untyped argKind)- ]-- TypeErrorDuplicateTopLevel previous lastName -> block TopDown- [ "duplicate top-level definition"- , " " <> ppVarIdentWithLocation lastName- , "previous top-level definitions found at"- , intercalate "\n"- [ " " <> ppVarIdentWithLocation name- | name <- previous ]- ]-- TypeErrorUnusedVariable name type_ -> block TopDown- [ "unused variable"- , " " <> Rzk.printTree (getVarIdent name) <> " : " <> ppU (untyped type_)- ]-- TypeErrorUnusedUsedVariables vars name -> block TopDown- [ "unused variables"- , " " <> intercalate " " (map (Rzk.printTree . getVarIdent) vars)- , "declared as used in definition of"- , " " <> Rzk.printTree (getVarIdent name)- ]-- TypeErrorImplicitAssumption (a, aType) name -> block TopDown- [ "implicit assumption"- , " " <> Rzk.printTree (getVarIdent a) <> " : " <> ppU (untyped aType)- , "used in definition of"- , " " <> Rzk.printTree (getVarIdent name)- ]- where- ppU :: Term' -> String- ppU = ppFoldU fbs- ppTyped :: TermT' -> String- ppTyped = ppFoldT fbs----- | The pattern binders in scope, freshened and keyed by their (current) name,--- together with the projection-folding map derived from them. Both share the--- same freshened component names, so a term's projections and the binder shown--- in the context agree.-contextBinders- :: Context VarIdent- -> ([(VarIdent, Binder)], [(VarIdent, [([Proj], VarIdent)])])-contextBinders ctx = (fbs, binderProjMap id fbs)- where- mapping = [ (v, v) | (v, _) <- varTypes ctx ]- fbs = freshBinders id mapping (varBinders ctx)---- | Render an (untyped) term for an error or diagnostic message, given the--- context's freshened pattern binders: fold a pattern-binder variable's--- projections to their component names, then expand a bare use of the variable--- to the pattern itself (see 'foldBinderProjections' and 'restorePatternVars').--- An empty binder list renders the term as-is.-ppFoldU :: [(VarIdent, Binder)] -> Term' -> String-ppFoldU fbs =- show . restorePatternVars fbs . foldBinderProjections (binderProjMap id fbs)---- | Like 'ppFoldU' for a type-annotated term, shown as @term : type@ with the--- same folding and pattern restoration applied to both halves.-ppFoldT :: [(VarIdent, Binder)] -> TermT' -> String-ppFoldT fbs t0 =- case foldBinderProjectionsT (binderProjMap id fbs) t0 of- t@Pure{} -> r t- t@(Free (AnnF info _)) -> r t <> " : " <> r (infoType info)- where- r :: TermT' -> String- r = show . restorePatternVars fbs . untyped--ppTypeErrorInContext :: OutputDirection -> TypeErrorInContext VarIdent -> String-ppTypeErrorInContext dir TypeErrorInContext{..} = block dir- [ ppTypeError' fbs typeErrorError- , ""- , ppContext' dir typeErrorContext- ]- where- (fbs, _) = contextBinders typeErrorContext--ppTypeErrorInScopedContextWith'- :: OutputDirection- -> [VarIdent]- -> [VarIdent]- -> TypeErrorInScopedContext VarIdent- -> String-ppTypeErrorInScopedContextWith' dir used vars = \case- PlainTypeError err -> ppTypeErrorInContext dir err- ScopedTypeError orig err -> withFresh orig $ \(x, xs) ->- ppTypeErrorInScopedContextWith' dir (x:used) xs $ fmap (g x) err- where- g x Z = x- g _ (S y) = y-- withFresh Nothing f =- case vars of- x:xs -> f (x, xs)- _ -> panicImpossible "not enough fresh variables"- withFresh (Just z) f = f (z', filter (/= z') vars) -- FIXME: very inefficient filter- where- z' = refreshVar used z -- FIXME: inefficient--ppTypeErrorInScopedContext' :: OutputDirection -> TypeErrorInScopedContext VarIdent -> String-ppTypeErrorInScopedContext' dir err =- ppTypeErrorInScopedContextWith' dir vars (defaultVarIdents \\ vars) err- where- vars = nub (foldMap pure err)--issueWarning :: String -> TypeCheck var ()-issueWarning message = do- trace ("Warning: " <> message) $- return ()--fromTypeError :: TypeError var -> TypeCheck var (TypeErrorInScopedContext var)-fromTypeError err = do- context <- ask- return $ PlainTypeError $ TypeErrorInContext- { typeErrorError = err- , typeErrorContext = context- }--issueTypeError :: TypeError var -> TypeCheck var a-issueTypeError err = fromTypeError err >>= throwError--panicImpossible :: String -> a-panicImpossible msg = error $ unlines- [ "PANIC! Impossible happened (" <> msg <> ")!"- , "Please, report a bug at https://github.com/rzk-lang/rzk/issues"- -- TODO: add details and/or instructions how to produce an artifact for reproducing- ]--data Action var- = ActionTypeCheck (Term var) (TermT var)- | ActionUnify (TermT var) (TermT var) (TermT var)- | ActionUnifyTerms (TermT var) (TermT var)- | ActionInfer (Term var)- | ActionContextEntailedBy [TermT var] (TermT var)- | ActionContextEntails [TermT var] (TermT var)- | ActionContextEntailsUnion [TermT var] [TermT var]- | ActionWHNF (TermT var)- | ActionNF (TermT var)- | ActionCheckCoherence (TermT var, TermT var) (TermT var, TermT var)- | ActionCloseSection (Maybe Rzk.SectionName)- | ActionCheckLetValue (Maybe VarIdent)- deriving (Functor, Foldable)--type Action' = Action VarIdent---- | Freshen the compound (pattern) binders in scope so their component names--- avoid the display names already in use and one another. Returns each relevant--- variable paired with its freshened binder. Variables bound to a single name--- are omitted: they need no projection folding and are displayed normally.-freshBinders- :: Eq var- => (var -> VarIdent)- -> [(var, VarIdent)]- -> [(var, Binder)]- -> [(var, Binder)]-freshBinders name mapping binders = go (map (name . fst) mapping) compound- where- compound = [ (v, b) | (v, b) <- binders, binderIsCompound b, v `elem` map fst mapping ]- go _ [] = []- go used ((v, b) : rest) =- let b' = freshenBinderLeaves used b- in (v, b') : go (binderLeaves b' ++ used) rest---- | The projection-folding map for rendering: each pattern-binder variable's--- display name mapped to the projection paths of its component names (e.g.--- @π₁@ ↦ @t@, @π₂@ ↦ @s@). Ordinary projections (of non-pattern variables) are--- left untouched.-binderProjMap :: (var -> VarIdent) -> [(var, Binder)] -> [(VarIdent, [([Proj], VarIdent)])]-binderProjMap name fbs = [ (name v, binderPaths b) | (v, b) <- fbs ]--ppTermInContext :: Eq var => TermT var -> TypeCheck var String-ppTermInContext term = do- vars <- freeVarsT_ term- let mapping = zip vars defaultVarIdents- toRzkVarIdent origs var = fromMaybe "_" $- join (lookup var origs) <|> lookup var mapping- origs <- asks varOrigs- binders <- asks varBinders- let name = toRzkVarIdent origs- fbs = freshBinders name mapping binders- return (show (restorePatternVars [ (name v, b) | (v, b) <- fbs ]- (foldBinderProjections (binderProjMap name fbs)- (untyped (name <$> term)))))---- | Classify a (WHNF) type as a cube, so cube variables (e.g. @t : 2@) are--- shown separately from ordinary term variables in a hole's context.-isCubeType :: TermT var -> Bool-isCubeType = \case- CubeUnitT{} -> True- Cube2T{} -> True- CubeIT{} -> True- CubeProductT{} -> True- UniverseCubeT{} -> True- _ -> False---- | Is a (WHNF) goal type in the cube or tope layer, so a hole of this type is a--- cube point or a tope rather than a term? Used to suppress type-layer-specific--- hole candidates (@recOR@, @recBOT@), which cannot inhabit a cube or a tope.-isCubeOrTopeType :: TermT var -> Bool-isCubeOrTopeType t = isCubeType t || case t of- UniverseTopeT{} -> True- _ -> False---- | Is this term a hole? Holes only exist in lenient mode (see 'allowHoles');--- they are opaque placeholders standing for a term of the expected type.-isHoleT :: TermT var -> Bool-isHoleT HoleT{} = True-isHoleT _ = False---- | Does this term contain a hole anywhere (including nested, e.g. @f ?@)?--- Used to keep unification lenient around incomplete terms: a term with an--- unfilled hole cannot be meaningfully compared, so a unification that would--- otherwise fail is deferred. Evaluated only on the failure path.-containsHole :: TermT var -> Bool-containsHole = \case- HoleT{} -> True- Pure{} -> False- Free (AnnF _ termf) -> bifoldr ((||) . containsHole) ((||) . containsHole) False termf---- | All ways to eliminate a hypothesis into a value usable at a goal. Given a--- @target@ type and a hypothesis /term/ (e.g. @Pure v@ for a context variable),--- return every elimination spine over that term whose type fits the target (or--- a subtype of it). Arguments introduced by application are left as holes for--- the caller to fill later. A value that already fits is returned as-is; a--- function is applied to holes; a Σ-type (or anything that unfolds to one, e.g.--- @is-contr@) is projected, possibly repeatedly — so e.g.--- @first (first (is-segal-A ? ? ? ? ?))@ is discovered.------ The search is driven uniformly by the eliminators a (weak head normal) type--- admits (see 'eliminatorsOf'), so adding a new eliminator extends it without--- touching the search.------ A Π-application is a forced spine step — there is exactly one way to fill an--- argument (with a hole) — so it extends the spine for free and does not spend--- the budget. Only the genuinely branching eliminators (Σ/cube projections and--- @idJ@, flagged by 'eliminatorsOf') count against 'maxEliminationDepth'. The--- bound therefore limits real search depth, not argument count, so a lemma that--- must be applied to many holes is still reached. The free spine terminates--- because each application strips one Π binder off a finite type.-allEliminationsInto- :: Eq var => TermT var -> TermT var -> TypeCheck var [TermT var]-allEliminationsInto target = go maxEliminationDepth- where- go depth term = do- ty <- typeOf term- fits <- fitsInto term ty target- elims <- eliminatorsOf ty- let step (SpineStep, wrap) = go depth (wrap term)- step (Branching, wrap)- | depth <= 0 = pure []- | otherwise = go (depth - 1) (wrap term)- deeper <- concat <$> mapM step elims- pure ([term | fits] <> deeper)---- | How many /branching/ eliminators 'allEliminationsInto' will chain. Forced--- Π-applications are free (see 'allEliminationsInto'), so this bounds only the--- Σ/cube projections and @idJ@ steps, not the argument count of a spine. A--- temporary fixed bound: branching is shallow in the goals seen so far (a few--- projections), and a larger bound mostly adds self-referential spines (a built--- result eliminated again). It should be made configurable once there is more--- evidence of what real goals need.-maxEliminationDepth :: Int-maxEliminationDepth = 7---- | Whether a term of the given (whnf) type may stand where a value of the--- @target@ type is expected: the two types unify under 'structuralHoleUnify',--- so a hole acts as a wildcard leaf but a structural mismatch around it is still--- a mismatch (an under-applied function does not match an extension-type goal,--- but a partial application that genuinely fits an ordinary-function goal does).------ Outer type restrictions are stripped from both sides first: an extension-type--- boundary is satisfied by later refinement, not by the choice of spine, and--- matching against the restricted goal would reject the very spine that--- introduces the holes meant to satisfy it (e.g. @f ?@ at a boundary goal).------ Holes or constraints recorded while probing are discarded, so this is a pure--- yes/no query.-fitsInto :: Eq var => TermT var -> TermT var -> TermT var -> TypeCheck var Bool-fitsInto term ty target = do- ty' <- stripTypeRestrictions <$> whnfT ty- target' <- stripTypeRestrictions <$> whnfT target- censor (const []) $ local structuralHoleUnify- ((unify (Just term) target' ty' >> pure True) `catchError` \_ -> pure False)---- | Whether eliminating a value spends the search budget. A forced--- Π-application is a 'SpineStep' — there is one way to fill the argument (with a--- hole), so 'allEliminationsInto' applies it for free; a 'Branching' eliminator--- (a Σ/cube projection or @idJ@) costs one against 'maxEliminationDepth'.-data ElimCost = SpineStep | Branching- deriving (Eq, Show)---- | The eliminators a value of the given (weak head normal) type admits, each--- as a function wrapping the eliminated term, paired with its 'ElimCost'. A--- Π-type is eliminated by application to a fresh hole (a spine step); a Σ-type--- by either projection; an identity type by path induction (@idJ@), with the--- motive and base case left as holes. The projections and @idJ@ branch.--- Anything else admits no simple eliminator.-eliminatorsOf :: Eq var => TermT var -> TypeCheck var [(ElimCost, TermT var -> TermT var)]-eliminatorsOf ty =- case stripTypeRestrictions ty of- TypeFunT _ty _orig _md param _mtope ret ->- pure [ (SpineStep, \term -> let h = mkHole param in appT (substituteT h ret) term h) ]- TypeSigmaT _ty _orig _md a b ->- pure [ (Branching, \term -> firstT a term)- , (Branching, \term -> secondT (substituteT (firstT a term) b) term) ]- -- A cube point pair (e.g. a pattern-bound @(t , s) : 2 × 2@) projects to its- -- coordinates; rzk renders those projections back as the pattern names.- CubeProductT _ty a b ->- pure [ (Branching, \term -> firstT a term)- , (Branching, \term -> secondT b term) ]- -- A path @p : a =_A x@ is eliminated by path induction. The motive- -- @C : (z : A) → (a =_A z) → U@ is always a function, so we introduce it- -- straight away as @\\ b q → ?@ rather than leaving it a bare hole: the spine- -- @idJ A a (\\ b q → ?) ? x p@ then has type @C x p@, which β-reduces to that- -- inner hole — so J fits any goal (the player fills the motive and the base- -- case @d : C a refl@). The two holes are the motive predicate and the base.- TypeIdT _ty a mtA x -> do- tA <- maybe (typeOf a) pure mtA- let -- the motive predicate body, a type, under the two motive binders- cBody = mkHole universeT- cInner = lambdaT (typeFunT (BinderVar Nothing) Id- (typeIdT (S <$> a) (Just (S <$> tA)) (Pure Z)) Nothing universeT)- (BinderVar (Just (fromString "q"))) Nothing cBody- cType = typeFunT (BinderVar Nothing) Id tA Nothing $- typeFunT (BinderVar Nothing) Id- (typeIdT (S <$> a) (Just (S <$> tA)) (Pure Z)) Nothing universeT- c = lambdaT cType (BinderVar (Just (fromString "b"))) Nothing cInner- dType = appT universeT- (appT (typeFunT (BinderVar Nothing) Id (typeIdT a (Just tA) a) Nothing universeT) c a)- (reflT (typeIdT a (Just tA) a) Nothing)- d = mkHole dType- motiveAt y p = appT universeT- (appT (typeFunT (BinderVar Nothing) Id (typeIdT a (Just tA) y) Nothing universeT) c y) p- pure [ (Branching, \p -> idJT (motiveAt x p) tA a c d x p) ]- _ -> pure []- where- mkHole t = HoleT TypeInfo{ infoType = t, infoWHNF = Nothing, infoNF = Nothing } Nothing---- | The binder for a λ introduced over a domain type. A binder the type already--- gives as a pattern is kept as-is — it carries the user's own names (e.g.--- @(t , s)@). Otherwise an /explicit/ (pre-whnf) Σ-type or product domain is--- destructured into a fresh pair pattern, recursively for products, so that a--- nameless @2 × 2 × 2@ parameter is introduced as @((t1 , t2) , t3)@ rather than--- a single opaque variable. Any other domain keeps its single binder.------ Leaves are named by what they range over: a cube-product component is a point,--- named @t@/@s@-style as @tN@; a Σ component is a term, named @xN@. The names are--- display-only (the body is a hole that does not mention them) and carry a--- shared running index, so every leaf in the pattern is distinct.-destructuringBinder :: Binder -> TermT var -> Binder-destructuringBinder orig param = case orig of- BinderPair{} -> orig -- already a pattern: keep the user's names- _ -> case param of- CubeProductT{} -> fst (go 1 param)- TypeSigmaT{} -> fst (go 1 param)- _ -> orig -- not a product/Σ: leave the binder alone- where- -- a product/Σ becomes a pair; we recurse into a product's components (plain- -- types) but not under a Σ's binder (a scope). A leaf is named by its- -- enclosing constructor: @tN@ under a cube product, @xN@ under a Σ.- go n = \case- CubeProductT _ a b ->- let (l, n') = child "t" n a- (r, n'') = child "t" n' b- in (BinderPair l r, n'')- TypeSigmaT _ _ _md a _b ->- let (l, n') = child "x" n a- in (BinderPair l (BinderVar (Just (leaf "x" n'))), n' + 1)- _ -> (BinderVar (Just (leaf "t" n)), n + 1) -- unreached: go is called on products only- child pfx n = \case- c@CubeProductT{} -> go n c- c@TypeSigmaT{} -> go n c- _ -> (BinderVar (Just (leaf pfx n)), n + 1)- leaf pfx n = fromString (pfx <> show n :: String)---- | All ways to introduce a value /of/ a goal type by its head constructor,--- leaving the constituents as holes. Given a @target@ type, return its--- introduction forms:------ * a Π-type is introduced by a λ-abstraction over a hole body (@\\ x -> ?@);--- the binder is taken from the type, so a pattern domain (e.g. a @Δ²@ point--- @(t , s)@) is introduced as @\\ (t , s) -> ?@;--- * a Σ-type or a cube product by a pair of holes (@(? , ?)@);--- * an identity type by @refl@, but only when its two endpoints already agree--- (otherwise @refl@ would not typecheck);--- * the unit type by @unit@;--- * the tope universe by each tope constructor — @TOP@, @BOT@, @? ≡ ?@,--- @? ≤ ?@, @? ∧ ?@, @? ∨ ?@ — so a shape (a hole of type @TOPE@) can be--- built up by tapping.------ Any other type admits no simple introduction. Unlike 'allEliminationsInto'--- this does not search: a type has at most one introduction form (the tope--- universe is the one exception), read off its (weak head normal) head--- constructor. Outer type restrictions are stripped first, so an extension type--- is introduced by the form of its underlying type (its boundary is met by later--- refinement of the holes, not by the choice of constructor).------ The λ binder of a Π-introduction is freshened against @inScope@ (the names--- already visible at the hole), so introducing over a type whose own definition--- reuses an in-scope name (e.g. @hom@, whose internal binder is @t@) yields--- @\\ t₁ -> ?@ rather than a @t@ that shadows the existing one.-allIntroductionsOf :: Eq var => TermT var -> [VarIdent] -> TypeCheck var [TermT var]-allIntroductionsOf target inScope = do- target' <- stripTypeRestrictions <$> whnfT target- case target' of- TypeFunT _ty orig _md param _mtope ret ->- let binder = freshenBinderLeaves inScope (destructuringBinder orig param)- in pure [ lambdaT target' binder Nothing (mkHole ret) ]- TypeSigmaT _ty _orig _md a b ->- let h = mkHole a in pure [ pairT target' h (mkHole (substituteT h b)) ]- CubeProductT _ty a b ->- pure [ pairT target' (mkHole a) (mkHole b) ]- TypeIdT _ty a _tA b -> do- agree <- endpointsAgree a b- pure [ reflT target' Nothing | agree ]- TypeUnitT{} -> pure [ unitT ]- -- the tope universe: every tope constructor builds a tope, so all are- -- introductions of a shape goal. Point arguments (of ≡, ≤) and tope- -- arguments (of ∧, ∨) are left as holes.- UniverseTopeT{} ->- let point = mkHole (mkHole cubeT) -- a point of an as-yet-unknown cube- tope = mkHole target' -- a tope (its type is the tope universe)- in pure [ topeTopT, topeBottomT- , topeEQT point point, topeLEQT point point- , topeAndT tope tope, topeOrT tope tope ]- _ -> pure []- where- mkHole t = HoleT TypeInfo{ infoType = t, infoWHNF = Nothing, infoNF = Nothing } Nothing---- | Whether the two endpoints of an identity type are definitionally equal, so--- that @refl@ inhabits it. Like 'fitsInto', any holes or constraints recorded--- while probing are discarded, leaving a pure yes\/no query.-endpointsAgree :: Eq var => TermT var -> TermT var -> TypeCheck var Bool-endpointsAgree a b =- censor (const [])- ((unify Nothing a b >> pure True) `catchError` \_ -> pure False)---- | Whether the local tope context is contradictory (entails ⊥). Reads the--- precomputed flag when present, falling back to an entailment check. Used to--- decide whether @recBOT@ (ex falso) is available.-contextEntailsBottom :: Eq var => TypeCheck var Bool-contextEntailsBottom = asks localTopesEntailBottom >>= \case- Just b -> return b- Nothing -> entailContextM topeBottomT---- | Ex falso: in a contradictory tope context @recBOT@ inhabits any type, so it--- is a candidate for every goal there (and only there — elsewhere it would not--- typecheck). Independent of the goal and of the local hypotheses.-recBottomCandidates :: Eq var => TypeCheck var [TermT var]-recBottomCandidates = do- vacuous <- contextEntailsBottom- pure [ recBottomT | vacuous ]---- | Whether the local tope context is covered by the union of the given topes —--- the coverage obligation of @recOR@ (see 'contextEntailsUnion'), but as a pure--- yes\/no query rather than a check that issues an error.-coverageHolds :: Eq var => [TermT var] -> TypeCheck var Bool-coverageHolds topes = do- topesNF <- mapM nfTope topes- entailContextM (foldr topeOrT topeBottomT topesNF)---- | Tope case-split moves: ways to build a value of the goal by @recOR@,--- splitting the proof over a cover of the local tope context. Three sources,--- offered together (the UI ranks and filters):------ * each disjunction @ψ ∨ φ@ already in the context becomes--- @recOR(ψ ↦ ?, φ ↦ ?)@ — its cover is immediate;--- * when the goal is an extension type, its restriction faces are a cover--- candidate @recOR(ψ₁ ↦ ?, …)@, offered only when they actually cover the--- context (so the move typechecks);--- * a generic two-way split @recOR(? ↦ ?, ? ↦ ?)@ with the guards left as--- holes, for an unusual split the player fills in by hand.------ All three are offered only in a setting where a split makes sense — a cube--- variable is in scope, the context has a non-trivial tope, or the goal is a--- restricted type — so an ordinary (tope-free) goal is left alone.-recOrCandidates :: Eq var => TermT var -> TypeCheck var [TermT var]-recOrCandidates goal = do- goalW <- whnfT goal- topes <- asks (filter (/= topeTopT) . availableTopes)- locals <- asks (filter (not . varIsTopLevel . snd) . varInfos)- hasCube <- or <$> mapM (fmap isCubeType . whnfT . varType . snd) locals- let stripped = stripTypeRestrictions goalW- mkRecOr gs = recOrT stripped [ (g, mkHole stripped) | g <- gs ]- fromContext = [ mkRecOr [l, r] | TopeOrT _ l r <- topes ]- faces = case goalW of- TypeRestrictedT _ _ rs -> map fst rs- _ -> []- isRestricted = case goalW of TypeRestrictedT{} -> True; _ -> False- inShape = hasCube || not (null topes) || isRestricted- generic = [ recOrT stripped [ (mkHole topeT, mkHole stripped)- , (mkHole topeT, mkHole stripped) ]- | inShape ]- fromFaces <- if length faces >= 2- then do covered <- coverageHolds faces- pure [ mkRecOr faces | covered ]- else pure []- pure (fromContext <> fromFaces <> generic)- where- mkHole t = HoleT TypeInfo{ infoType = t, infoWHNF = Nothing, infoNF = Nothing } Nothing---- | Record the goal and local context at a hole (lenient mode only). The goal,--- the local hypotheses, and the tope assumptions are all rendered to--- user-facing 'VarIdent' names here — reusing the same resolution as--- 'ppTermInContext' — so the resulting 'HoleInfo' is independent of the De--- Bruijn scope. The global environment is deliberately excluded (only--- @varIsTopLevel == False@ locals are kept), and locals are split into cube--- variables and ordinary term variables.-recordHole :: Eq var => Maybe VarIdent -> TermT var -> TypeCheck var ()-recordHole mname goalTy = recordHoleShape mname goalTy Nothing---- | Record a hole. When the hole is the argument of a shape-restricted function--- its goal is a /shape/: the cube @goalTy@ together with a membership tope. The--- tope is a scope over the shape's bound variable (the third argument carries--- the declared binder name, if any, and the tope); it is rendered under that--- binder so the goal reads @(binder : goalTy | tope)@.-recordHoleShape- :: Eq var- => Maybe VarIdent- -> TermT var- -> Maybe (Binder, TermT (Inc var))- -> TypeCheck var ()-recordHoleShape mname goalTy mshape = do- goal' <- whnfT goalTy- locals <- asks (filter (not . varIsTopLevel . snd) . varInfos)- -- named top-level lemmas the caller allow-listed for hints (see 'hintLemmas').- -- They feed the candidate-elimination loop only — not the local context shown- -- to the user, since they are global definitions, not local hypotheses.- lemmas <- asks hintLemmas- lemmaVars <- asks (filter (\(_, i) -> varIsTopLevel i && maybe False (`elem` lemmas) (binderName (varOrig i))) . varInfos)- cubeFlags <- mapM (fmap isCubeType . whnfT . varType . snd) locals- topes <- asks (filter (/= topeTopT) . availableTopes)- origs <- asks varOrigs- binders <- asks varBinders- loc <- asks location- -- for each local hypothesis (and allow-listed lemma), the elimination spines- -- that land in the goal (arguments left as holes). Probing must not leak holes- -- into the recorded output, hence 'censor'.- candidates <- censor (const []) $ do- elims <- concat <$> mapM (\(v, _) -> allEliminationsInto goalTy (Pure v)) (locals ++ lemmaVars)- -- context-driven moves (independent of the goal's head and the hypotheses):- -- ex falso in a contradictory context, and tope case-splits. recOR and recBOT- -- are term-level eliminators, so they are offered only for a term goal — not- -- when the hole is a cube point or a tope, where they cannot appear.- let termLayer = not (isCubeOrTopeType goal')- recbot <- if termLayer then recBottomCandidates else pure []- recor <- if termLayer then recOrCandidates goalTy else pure []- pure (elims <> recbot <> recor)- let shapeTope = snd <$> mshape- shapeTopeVars = maybe [] (\t -> [ v | S v <- foldr (:) [] t ]) shapeTope- varsList <- concat <$> mapM freeVarsT_ (goal' : map (varType . snd) (locals ++ lemmaVars) ++ topes)- let mapping = zip (nub (varsList ++ shapeTopeVars ++ map fst (locals ++ lemmaVars))) defaultVarIdents- name v = fromMaybe "_" (join (lookup v origs) <|> lookup v mapping)- fbs = freshBinders name mapping binders- render t = restorePatternVars [ (name v, b) | (v, b) <- fbs ]- (foldBinderProjections (binderProjMap name fbs) (untyped (name <$> t)))- -- a pattern binder is shown as its pattern, e.g. (t , s); others by name- entryName v = maybe (name v) binderDisplayName (lookup v fbs)- entries = [ HoleEntry (entryName v) (render (varType info)) | (v, info) <- locals ]- flagged = zip cubeFlags entries- -- binder name for the shape: the declared name if any, else a default- shapeBinder = fromMaybe (fromString "t") (binderName =<< (fst <$> mshape))- nameInc Z = shapeBinder- nameInc (S v) = name v- goalShape = (\t -> (shapeBinder, untyped (nameInc <$> t))) <$> shapeTope- -- names already visible at the hole, which an introduced binder must not- -- shadow: each local hypothesis by its display name, or the leaves of a- -- pattern hypothesis.- inScopeNames = [ nm | (v, _) <- locals- , nm <- maybe [name v] binderLeaves (lookup v fbs) ]- -- the introduction forms for the goal itself (constituents left as holes); the- -- Π binder is freshened against 'inScopeNames' so it does not shadow.- introductions <- censor (const []) (allIntroductionsOf goalTy inScopeNames)- -- the goal cell: an SVG of the shape the hole must inhabit (an arrow, triangle- -- or square), drawn from an abstract inhabitant with the proof term hidden.- -- 'Nothing' when the goal is not a renderable shape.- diagram <- censor (const []) (renderGoalCellSVG goal')- lift $ tell- [ HoleInfo- { holeName = mname- , holeGoal = render goal'- , holeGoalShape = goalShape- , holeTermVars = [ e | (False, e) <- flagged ]- , holeCubeVars = [ e | (True, e) <- flagged ]- , holeTopes = map render topes- , holeCandidates = map render candidates- , holeIntroductions = map render introductions- , holeDiagram = diagram- , holeLocation = loc- } ]---- | Check a hole that appears as the argument of a shape-restricted function,--- whose domain is the cube @cube@ restricted by @tope@ (a scope over the--- domain's bound variable). Mirrors the hole case of 'typecheck', but records--- the shape as the hole's goal so the diagnostic shows @(binder : cube | tope)@.-checkHoleAgainstShape- :: Eq var- => Maybe VarIdent -> Binder -> TermT var -> TermT (Inc var)- -> TypeCheck var (TermT var)-checkHoleAgainstShape mname orig cube tope = do- reject <- asks holesAreErrors- if reject- then issueTypeError (TypeErrorUnsolvedHole mname cube)- else do- recordHoleShape mname cube (Just (orig, tope))- return (HoleT TypeInfo{ infoType = cube, infoWHNF = Nothing, infoNF = Nothing } mname)--ppSomeAction :: Eq var => [(var, Maybe VarIdent)] -> Int -> Action var -> String-ppSomeAction origs n action = ppAction [] n (toRzkVarIdent <$> action)- where- vars = nub (foldMap pure action)- mapping = zip vars defaultVarIdents- toRzkVarIdent var = fromMaybe "_" $- join (lookup var origs) <|> lookup var mapping--ppAction :: [(VarIdent, Binder)] -> Int -> Action' -> String-ppAction fbs n = unlines . map (replicate (2 * n) ' ' <>) . \case- ActionTypeCheck term ty ->- [ "typechecking"- , " " <> ppU term- , "against type"- , " " <> ppU (untyped ty) ]-- ActionUnify term expected actual ->- [ "unifying expected type"- , " " <> ppU (untyped expected)- , "with actual type"- , " " <> ppU (untyped actual)- , "for term"- , " " <> ppU (untyped term) ]-- ActionUnifyTerms expected actual ->- [ "unifying term (expected)"- , " " <> ppTyped expected- , "with term (actual)"- , " " <> ppTyped actual ]-- ActionInfer term ->- [ "inferring type for term"- , " " <> ppU term ]-- ActionContextEntailedBy ctxTopes term ->- [ "checking if local context"- , intercalate "\n" (map ((" " <>) . ppU . untyped) ctxTopes)- , "includes (is entailed by) restriction tope"- , " " <> ppU (untyped term) ]-- ActionContextEntails ctxTopes term ->- [ "checking if local context"- , intercalate "\n" (map ((" " <>) . ppU . untyped) ctxTopes)- , "is included in (entails) the tope"- , " " <> ppU (untyped term) ]-- ActionContextEntailsUnion ctxTopes terms ->- [ "checking if local context"- , intercalate "\n" (map ((" " <>) . ppU . untyped) ctxTopes)- , "is included in (entails) the union of the topes"- , intercalate "\n" (map ((" " <>) . ppU . untyped) terms) ]-- ActionWHNF term ->- [ "computing WHNF for term"- , " " <> ppTyped term ]-- ActionNF term ->- [ "computing normal form for term"- , " " <> ppU (untyped term) ]-- ActionCheckCoherence (ltope, lterm) (rtope, rterm) ->- [ "checking coherence for"- , " " <> ppU (untyped ltope)- , " |-> " <> ppU (untyped lterm)- , "and"- , " " <> ppU (untyped rtope)- , " |-> " <> ppU (untyped rterm) ]-- ActionCloseSection Nothing ->- [ "closing the file"- , "and collecting assumptions (variables)" ]- ActionCloseSection (Just sectionName) ->- [ "closing #section " <> Rzk.printTree sectionName- , "and collecting assumptions (variables)"]-- ActionCheckLetValue orig ->- [ "checking the local definition "- <> maybe "_" (Rzk.printTree . getVarIdent) orig ]- where- ppU :: Term' -> String- ppU = ppFoldU fbs- ppTyped :: TermT' -> String- ppTyped = ppFoldT fbs---traceAction' :: Int -> Action' -> a -> a-traceAction' n action = trace ("[debug]\n" <> ppAction [] n action)--unsafeTraceAction' :: Int -> Action var -> a -> a-unsafeTraceAction' n = traceAction' n . unsafeCoerce--data LocationInfo = LocationInfo- { locationFilePath :: Maybe FilePath- , locationLine :: Maybe Int- } deriving (Eq, Show)--data Verbosity- = Debug- | Normal- | Silent- deriving (Eq, Ord)--trace' :: Verbosity -> Verbosity -> String -> a -> a-trace' msgLevel currentLevel- | currentLevel <= msgLevel = trace- | otherwise = const id--traceTypeCheck :: Verbosity -> String -> TypeCheck var a -> TypeCheck var a-traceTypeCheck msgLevel msg tc = do- Context{..} <- ask- trace' msgLevel verbosity msg tc--localVerbosity :: Verbosity -> TypeCheck var a -> TypeCheck var a-localVerbosity v = local $ \Context{..} -> Context { verbosity = v, .. }--localRenderBackend :: Maybe RenderBackend -> TypeCheck var a -> TypeCheck var a-localRenderBackend v = local $ \Context{..} -> Context { renderBackend = v, .. }---- | Run the enclosed action with the 'renderHideTerm' policy set.-localHideTerm :: Bool -> TypeCheck var a -> TypeCheck var a-localHideTerm v = local $ \ctx -> ctx { renderHideTerm = v }---- | Render the enclosed action with the proof term hidden (see 'renderHideTerm').-hidingTerm :: TypeCheck var a -> TypeCheck var a-hidingTerm = localHideTerm True--data Covariance- = Covariant -- ^ Positive position.- | Contravariant -- ^ Negative position.- | Invariant -- ^ Unknown position.--data RenderBackend- = RenderSVG- | RenderLaTeX--data ScopeInfo var = ScopeInfo- { scopeName :: Maybe Rzk.SectionName- , scopeVars :: [(var, VarInfo var)]- } deriving (Functor, Foldable)---- | A scope of top-level entries (definitions, postulates, section--- assumptions). The payload is pinned at 'VarIdent': shifting the context--- under a binder ('enterScopeContext') maps only the keys and never--- traverses the elaborated terms, which is what made @S <$>@ on the whole--- context account for most of the checker's allocation and residency.--- A payload is embedded into the current scope on lookup via 'globalEmbed'.-data GlobalScopeInfo var = GlobalScopeInfo- { gscopeName :: Maybe Rzk.SectionName- , gscopeVars :: [(var, VarInfo VarIdent)]- } deriving (Functor, Foldable)--addVarToScope :: var -> VarInfo var -> ScopeInfo var -> ScopeInfo var-addVarToScope var info ScopeInfo{..} = ScopeInfo- { scopeVars = (var, info) : scopeVars, .. }--addModalityToScope :: TModality -> ScopeInfo var -> ScopeInfo var-addModalityToScope md ScopeInfo{..} = ScopeInfo- { scopeVars = map (\(var, VarInfo{..}) -> (var, VarInfo{ modAccum = comp modAccum md, ..})) scopeVars, .. }--data VarInfo var = VarInfo- { varType :: TermT var- , varValue :: Maybe (TermT var)- , varModality :: TModality- , modAccum :: TModality- , varOrig :: Binder- , varIsAssumption :: Bool -- FIXME: perhaps, introduce something like decl kind?- , varIsTopLevel :: Bool- , varDeclaredAssumptions :: [var]- , varLocation :: Maybe LocationInfo- } deriving (Functor, Foldable)---class ModeTheory m where- iden :: m- comp :: m -> m -> m- coe :: m -> m -> Bool- isRA :: m -> Bool--instance ModeTheory TModality where- iden = Id-- comp Flat Flat = Flat- comp Flat Sharp = Flat- comp Flat Op = Flat- comp Op Flat = Flat- comp Sharp Sharp = Sharp- comp Sharp Flat = Sharp- comp Sharp Op = Sharp- comp Op Sharp = Sharp- comp Op Op = Id- comp Id m = m- comp m Id = m-- coe Flat Id = True- coe Flat Op = True- coe Id Sharp = True- coe Flat Sharp = True- coe Op Sharp = True- coe a b = a == b-- isRA Sharp = True - isRA Op = True - isRA Id = True- isRA _ = False--data ModalTope var = ModalTope- { tModAccum :: TModality- , tModVar :: TModality- , tTope :: TermT var- } deriving (Functor, Foldable, Eq)---- | The state of the tope-saturation cache in a 'Context'--- (see 'localTopesSaturated' and 'withRefreshedTopes').-data CachedSaturation var- = SaturationUncached- -- ^ No cache was installed for this tope context ('entailContextM'- -- falls back to the per-query pipeline).- | SaturationCached (Maybe [[ModalTope var]])- -- ^ A deferred pipeline run: forced by the first query under this- -- context. 'Nothing' records that the pipeline errored; queries then- -- fall back, so the error surfaces exactly where it would have.- deriving (Functor)---- Deliberately empty: the cache's variables duplicate those of--- 'localTopesNF', and folding a 'Context' (e.g. collecting names when--- printing a scoped error) must not force the deferred pipeline.-instance Foldable CachedSaturation where- foldMap _ _ = mempty--data Context var = Context- { localScopes :: [ScopeInfo var]- -- ^ Binder scopes: variables bound while checking the current- -- declaration. Top-level entries live in 'globalScopes'.- , globalScopes :: [GlobalScopeInfo var]- -- ^ Top-level definitions, postulates and section assumptions, with- -- their payloads pinned at 'VarIdent' (see 'GlobalScopeInfo').- , globalEmbed :: VarIdent -> var- -- ^ The composed injection of top-level names into the current scope- -- (extended by @S .@ at each binder entry; the derived 'Functor'- -- composes it on 'fmap'). Embeds a global payload on lookup.- , localDiscreteTopes :: [ModalTope var]- -- ^ Discreteness axioms for the flat cube variables in scope (a flat- -- point of @2@ or @I@ is an endpoint). Maintained incrementally at- -- binder entry (see 'enterScopeMaybe'), so 'entailM' does not rescan- -- the whole context on every entailment query. A variable's modality- -- is fixed at binding time ('addModalityToScope' only touches- -- 'modAccum'), so entries never need to be revised.- , localTopes :: [ModalTope var]- , localTopesNF :: [ModalTope var]- , localTopesNFUnion :: [[ModalTope var]]- , localTopesEntailBottom :: Maybe Bool- , localTopesSaturated :: CachedSaturation var- -- ^ The saturated alternatives for the context's own tope context- -- ('localTopesNF' plus the discreteness axioms): exactly the- -- preprocessing 'entailM' runs per query, cached at the points where- -- the tope context changes ('localTope', 'enterModality',- -- 'inAllSubContexts', a flat cube binder) via 'withRefreshedTopes'.- -- Ordinary binder entries shift the cached value with the rest of the- -- context, which is sound because saturation commutes with renaming.- , actionStack :: [Action var]- , currentCommand :: Maybe Rzk.Command- , location :: Maybe LocationInfo- , verbosity :: Verbosity- , covariance :: Covariance- , renderBackend :: Maybe RenderBackend- -- | When rendering a diagram, hide the proof term: drop the @\<title\>@- -- (which carries the full term) from every cell and blank the visible label- -- of proof-coloured (interior) cells, keeping the given boundary labels. So- -- a worked term or an abstract inhabitant of a goal type is shown as the- -- shape with its given edges, not the term that fills it.- , renderHideTerm :: Bool- , holesAreErrors :: Bool- -- ^ When 'True' (the default), an unfilled hole is reported as a- -- 'TypeErrorUnsolvedHole'; finished work (and CI) must have no holes. The- -- lenient mode ('allowHoles') instead records each hole's goal and context.- , deferHoleMismatches :: Bool- -- ^ How holes behave during unification, giving three modes overall. With- -- 'holesAreErrors' a hole is rejected outright (strict). Otherwise a hole- -- always unifies as a leaf; this flag then chooses what happens when the- -- /surrounding/ structure disagrees: 'True' (the default) defers — any term- -- containing a hole is accepted, for an in-progress sketch — while 'False'- -- keeps such a mismatch an error, so only a hole standing in a matching- -- structure is accepted ('structuralHoleUnify').- , hintLemmas :: [VarIdent]- -- ^ Named top-level definitions a hole's candidate list may draw on, beyond- -- the local hypotheses (see 'withHintLemmas'). A caller (the game) supplies- -- a small curated allow-list per level; each listed lemma whose type fits- -- the goal is then offered, applied to holes (e.g. @concat ? ? ?@).- } deriving (Functor)---- Hand-written because the 'globalEmbed' function field cannot be folded;--- its image is exactly the keys of 'globalScopes', which are folded.-instance Foldable Context where- foldMap f Context{..} = mconcat- [ foldMap (foldMap f) localScopes- , foldMap (foldMap f) globalScopes- , foldMap (foldMap f) localDiscreteTopes- , foldMap (foldMap f) localTopes- , foldMap (foldMap f) localTopesNF- , foldMap (foldMap (foldMap f)) localTopesNFUnion- -- localTopesSaturated is skipped: its Foldable is deliberately empty- -- (folding must not force the deferred saturation pipeline).- , foldMap (foldMap f) actionStack- ]--addVarInCurrentScope :: var -> VarInfo var -> Context var -> Context var-addVarInCurrentScope var info Context{..} = Context- { localScopes =- case localScopes of- [] -> [ScopeInfo Nothing [(var, info)]]- scope : scopes -> addVarToScope var info scope : scopes- , .. }---- | Add a top-level entry (definition, postulate, section assumption) to the--- current global scope. Only ever happens at the top level, where variables--- are plain 'VarIdent's.-addVarInCurrentGlobalScope :: VarIdent -> VarInfo VarIdent -> Context VarIdent -> Context VarIdent-addVarInCurrentGlobalScope var info Context{..} = Context- { globalScopes =- case globalScopes of- [] -> [GlobalScopeInfo Nothing [(var, info)]]- scope : scopes -> scope { gscopeVars = (var, info) : gscopeVars scope } : scopes- , .. }--applyModalityToScopes :: TModality -> [ScopeInfo var] -> [ScopeInfo var]-applyModalityToScopes md scopes = map (addModalityToScope md) scopes--applyModalityToGlobalScopes :: TModality -> [GlobalScopeInfo var] -> [GlobalScopeInfo var]-applyModalityToGlobalScopes md = map $ \scope -> scope- { gscopeVars = map (fmap (\VarInfo{..} -> VarInfo{ modAccum = comp modAccum md, .. })) (gscopeVars scope) }--applyModalityToTopes :: TModality -> [ModalTope var] -> [ModalTope var]-applyModalityToTopes md topes = map (\ModalTope{..} -> ModalTope{tModAccum = comp tModAccum md, ..}) topes--applyModality :: TModality -> Context var -> Context var-applyModality md Context{..} = Context- { localScopes = applyModalityToScopes md localScopes- , globalScopes = applyModalityToGlobalScopes md globalScopes- , localTopes = applyModalityToTopes md localTopes- , localTopesNF = applyModalityToTopes md localTopesNF- , localTopesNFUnion = map (applyModalityToTopes md) localTopesNFUnion- , localTopesSaturated = SaturationUncached -- accessibility changed; 'enterModality' refreshes- , .. }--emptyTopeContext :: [ModalTope var]-emptyTopeContext =- [ ModalTope Id Id topeTopT- , ModalTope Id Flat topeTopT- , ModalTope Id Op topeTopT- , ModalTope Id Sharp topeTopT- ]--emptyContext :: Context VarIdent-emptyContext = unseeded { localTopesSaturated = SaturationCached sat }- where- -- Seed the saturation cache for the empty tope context, so top-level- -- entailment queries hit the cached path from the start. Deferred, like- -- every other installation (see 'withRefreshedTopes').- sat = case runExcept (runWriterT (runReaderT (saturateForEntailment emptyTopeContext) unseeded)) of- Left _ -> Nothing- Right (s, _) -> Just s- unseeded = emptyContextUnseeded--emptyContextUnseeded :: Context VarIdent-emptyContextUnseeded = Context- { localScopes = [ScopeInfo Nothing []]- , globalScopes = [GlobalScopeInfo Nothing []]- , globalEmbed = id- , localDiscreteTopes = []- , localTopes = emptyTopeContext- , localTopesNF = emptyTopeContext- , localTopesNFUnion = [emptyTopeContext]- , localTopesEntailBottom = Just False- , localTopesSaturated = SaturationUncached- , actionStack = []- , currentCommand = Nothing- , location = Nothing- , verbosity = Normal- , covariance = Covariant- , renderBackend = Nothing- , renderHideTerm = False- , holesAreErrors = True- , deferHoleMismatches = True- , hintLemmas = []- }---- | Switch to lenient hole mode: record each hole's goal and context instead--- of reporting it as an error. Used by the structured goal/context query and--- the @--allow-holes@ CLI mode; the default (strict) mode rejects holes.-allowHoles :: Context var -> Context var-allowHoles ctx = ctx { holesAreErrors = False }---- | Allow a hole's candidate list to draw on the given named top-level--- definitions (in addition to the local hypotheses). The game supplies the--- per-level allow-list; 'recordHoleShape' then offers each listed lemma whose--- type fits the goal, applied to holes. See 'hintLemmas'.-withHintLemmas :: [VarIdent] -> Context var -> Context var-withHintLemmas lemmas ctx = ctx { hintLemmas = lemmas }---- | Within the given action, a hole unifies only as a leaf in an otherwise--- matching structure: a structural mismatch around a hole stays an error rather--- than being deferred (see 'deferHoleMismatches'). Used to ask whether a term--- /could/ have a given type, as opposed to tolerating an in-progress sketch.-structuralHoleUnify :: Context var -> Context var-structuralHoleUnify ctx = ctx { deferHoleMismatches = False }--askCurrentScope :: TypeCheck var (ScopeInfo var)-askCurrentScope = asks localScopes >>= \case- [] -> panicImpossible "no current scope available"- scope : _scopes -> pure scope--isAccessible :: ModalTope var -> Bool-isAccessible mt = coe (tModVar mt) (tModAccum mt)--filterAccessible :: [ModalTope var] -> [ModalTope var]-filterAccessible = filter isAccessible--filterInaccessible :: [ModalTope var] -> [ModalTope var]-filterInaccessible = filter (not . isAccessible)--partitionAccessible :: [ModalTope var] -> ([ModalTope var], [ModalTope var])-partitionAccessible = partition isAccessible--accessibleTopes :: [ModalTope var] -> [TermT var]-accessibleTopes = map tTope . filterAccessible--plainTope :: TermT var -> ModalTope var-plainTope = ModalTope Id Id--availableTopes :: Context var -> [TermT var]-availableTopes ctx = map tTope $ filterAccessible (localTopes ctx)--availableTopesNF :: Context var -> [TermT var]-availableTopesNF ctx = map tTope $ filterAccessible (localTopesNF ctx)---- | All in-scope variables: binder-bound locals first, then the top-level--- entries with their payloads embedded into the current scope. Locals are--- always more recent than the globals, so this matches the pre-split order.-varInfos :: Context var -> [(var, VarInfo var)]-varInfos Context{..} = concatMap scopeVars localScopes- <> [ (v, globalEmbed <$> info)- | (v, info) <- concatMap gscopeVars globalScopes ]---- | Look up one variable's 'VarInfo' by walking the scopes directly. The--- per-variable lookups ('typeOfVar', 'valueOfVar', …) run on every 'typeOf'--- of a variable, so going through a projected association list (as the--- whole-context views below do) allocates a pair per scanned entry on the--- hottest path of the checker. A hit in the global scopes is embedded into--- the current scope ('globalEmbed'); the payload itself is never shifted.-lookupVarInfo :: Eq var => var -> Context var -> Maybe (VarInfo var)-lookupVarInfo x Context{..} = go localScopes- where- go [] = goGlobal globalScopes- go (scope : scopes) =- case lookup x (scopeVars scope) of- Just info -> Just info- Nothing -> go scopes- goGlobal [] = Nothing- goGlobal (scope : scopes) =- case lookup x (gscopeVars scope) of- Just info -> Just (globalEmbed <$> info)- Nothing -> goGlobal scopes--varTypes :: Context var -> [(var, TermT var)]-varTypes = map (fmap varType) . varInfos--varValues :: Context var -> [(var, Maybe (TermT var))]-varValues = map (fmap varValue) . varInfos--varOrigs :: Context var -> [(var, Maybe VarIdent)]-varOrigs = map (fmap (binderName . varOrig)) . varInfos---- | The full binder (pattern) of each in-scope variable, used to restore--- pattern-binder component names (e.g. @t@\/@s@ for @\\ (t , s) -> …@) when--- rendering goals, holes and contexts.-varBinders :: Context var -> [(var, Binder)]-varBinders = map (fmap varOrig) . varInfos--withPartialDecls- :: TypeCheck VarIdent ([Decl'], [err])- -> TypeCheck VarIdent ([Decl'], [err])- -> TypeCheck VarIdent ([Decl'], [err])-withPartialDecls tc next = do- (decls, errs) <- tc- if null errs- then first (decls <>)- <$> localDeclsPrepared decls next- else return (decls, errs)--withSection- :: Maybe Rzk.SectionName- -> TypeCheck VarIdent ([Decl VarIdent], [TypeErrorInScopedContext VarIdent])- -> TypeCheck VarIdent ([Decl VarIdent], [TypeErrorInScopedContext VarIdent])- -> TypeCheck VarIdent ([Decl VarIdent], [TypeErrorInScopedContext VarIdent])-withSection name sectionBody =- withPartialDecls $ startSection name $ do- (decls, errs) <- sectionBody- localDeclsPrepared decls $- performing (ActionCloseSection name) $ do- result <- (Right <$> endSection errs) `catchError` (return . Left)- case result of- Left err -> return ([], errs <> [err])- Right (decls', errs') -> return (decls', errs')- -- (\ decls' -> (decls', errs)) <$> endSection errs--startSection :: Maybe Rzk.SectionName -> TypeCheck VarIdent a -> TypeCheck VarIdent a-startSection name = local $ \Context{..} -> Context- { globalScopes = GlobalScopeInfo { gscopeName = name, gscopeVars = [] } : globalScopes- , .. }---- | The current global scope, as a plain 'ScopeInfo' (at the top level the--- keys and payloads coincide at 'VarIdent').-askCurrentGlobalScope :: TypeCheck VarIdent (ScopeInfo VarIdent)-askCurrentGlobalScope = asks globalScopes >>= \case- [] -> panicImpossible "no current global scope available"- scope : _scopes -> pure ScopeInfo { scopeName = gscopeName scope, scopeVars = gscopeVars scope }--endSection :: [TypeErrorInScopedContext VarIdent] -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent])-endSection errs = askCurrentGlobalScope >>= scopeToDecls errs--scopeToDecls :: Eq var => [TypeErrorInScopedContext var] -> ScopeInfo var -> TypeCheck var ([Decl var], [TypeErrorInScopedContext var])-scopeToDecls errs ScopeInfo{..} = do- -- In lenient (hole-checking) mode an as-yet-unfilled hole may still come to- -- use a declared variable, so we tolerate the unused-variable diagnostics- -- wherever such a hole is present anywhere in the section. This covers both an- -- unused section assumption and an unused 'uses' variable, and crucially a- -- hole-free definition whose body refers to an in-progress (hole-bearing) one:- -- its 'uses' reads as unused only because the referenced definition is- -- incomplete. Strict mode (the default, and CI) keeps reporting both.- lenient <- not <$> asks holesAreErrors- let sectionHasHole = any (maybe False containsHole . varValue . snd) scopeVars- (decls, errs') <- collectScopeDecls (lenient && sectionHasHole) errs [] scopeVars- -- only issue unused variable errors if there were no errors prior in the section- -- when (null errs) $ do- unusedErrors <- forM decls $ \Decl{..} -> do- let unusedUsedVars = declUsedVars `intersect` map fst scopeVars- if null errs && not (null unusedUsedVars) && not (lenient && sectionHasHole)- then do- err <- local (\c -> c { location = declLocation }) $- fromTypeError (TypeErrorUnusedUsedVariables unusedUsedVars declName)- return [err]- else return []- return (decls, errs' <> concat unusedErrors)--insertExplicitAssumptionFor- :: Eq var => var -> (var, VarInfo var) -> TermT var -> TermT var-insertExplicitAssumptionFor a (declName, VarInfo{..}) term =- term >>= \case- y | y == declName -> appT varType (Pure declName) (Pure a)- | otherwise -> Pure y--insertExplicitAssumptionFor'- :: Eq var => var -> (var, VarInfo var) -> VarInfo var -> VarInfo var-insertExplicitAssumptionFor' a decl VarInfo{..}- | varIsAssumption = VarInfo{..}- | otherwise = VarInfo- { varType = insertExplicitAssumptionFor a decl varType- , varValue = insertExplicitAssumptionFor a decl <$> varValue- , varIsAssumption = varIsAssumption- , varIsTopLevel = varIsTopLevel- , varModality = varModality- , modAccum = modAccum- , varOrig = varOrig- , varDeclaredAssumptions = varDeclaredAssumptions- , varLocation = varLocation- }--makeAssumptionExplicit- :: Eq var- => (var, VarInfo var)- -> [(var, VarInfo var)]- -> TypeCheck var (Bool, [(var, VarInfo var)])-makeAssumptionExplicit _ [] = pure (False {- UNUSED -}, [])-makeAssumptionExplicit assumption@(a, aInfo) ((x, xInfo) : xs) = do- varsInType <- freeVarsT_ (varType xInfo)- varsInBody <- concat <$> traverse freeVarsT_ (varValue xInfo)- let xFreeVars = varsInBody <> varsInType- let hasAssumption = a `elem` xFreeVars- xType <- typeOfVar x- xValue <- valueOfVar x- let assumptionInType = a `elem` freeVars (untyped xType)- assumptionInBody = a `elem` foldMap (freeVars . untyped) xValue- implicitAssumption = and- [ hasAssumption- , not (assumptionInType || assumptionInBody)- , a `notElem` varDeclaredAssumptions xInfo ]- if hasAssumption- then do- when implicitAssumption $ do- issueTypeError $ TypeErrorImplicitAssumption (a, varType aInfo) x- (_used, xs'') <- makeAssumptionExplicit (a, aInfo) xs'- return (True {- USED -}, (x, xInfo') : xs'')- else do- (used, xs'') <- makeAssumptionExplicit assumption xs- return (used, (x, xInfo) : xs'')- where- xType' = typeFunT (varOrig aInfo) Id (varType aInfo) Nothing (abstract a (varType xInfo))- xInfo' = VarInfo- { varType = xType'- , varValue = fmap (lambdaT xType' (varOrig aInfo) Nothing . abstract a) (varValue xInfo)- , varIsAssumption = varIsAssumption xInfo- , varIsTopLevel = varIsTopLevel xInfo- , varModality = Id- , modAccum = Id- , varOrig = varOrig xInfo- , varDeclaredAssumptions = varDeclaredAssumptions xInfo \\ [a]- , varLocation = varLocation xInfo- }- xs' = map (fmap (insertExplicitAssumptionFor' a (x, xInfo))) xs--collectScopeDecls :: Eq var => Bool -> [TypeErrorInScopedContext var] -> [(var, VarInfo var)] -> [(var, VarInfo var)] -> TypeCheck var ([Decl var], [TypeErrorInScopedContext var])-collectScopeDecls tolerateUnused errs recentVars (decl@(var, VarInfo{..}) : vars)- | varIsAssumption = do- (used, recentVars') <- makeAssumptionExplicit decl recentVars- -- only issue unused vars error if there were no other errors previously- -- when (null errs) $ do- unusedErr <-- if null errs && not used && not tolerateUnused- then local (\c -> c { location = varLocation }) $- pure <$> fromTypeError (TypeErrorUnusedVariable var varType)- else return []- collectScopeDecls tolerateUnused (errs <> unusedErr) recentVars' vars- | otherwise = do- collectScopeDecls tolerateUnused errs (decl : recentVars) vars-collectScopeDecls _ errs recentVars [] = do- loc <- asks location- return (toDecl loc <$> recentVars, errs)- where- toDecl loc (var, VarInfo{..}) = Decl- { declName = var- , declType = varType- , declValue = varValue- , declIsAssumption = varIsAssumption- , declUsedVars = varDeclaredAssumptions- , declLocation = updatePosition (binderName varOrig >>= fmap fst . Rzk.hasPosition . fromVarIdent) <$> loc -- FIXME- }- updatePosition Nothing l = l- updatePosition (Just lineNo) l = l { locationLine = Just lineNo }--abstractAssumption :: Eq var => (var, VarInfo var) -> Decl var -> Decl var-abstractAssumption (var, VarInfo{..}) Decl{..} = Decl- { declName = declName- , declType = typeFunT varOrig Id varType Nothing (abstract var declType)- , declValue = (\body -> lambdaT newDeclType varOrig Nothing (abstract var body)) <$> declValue- , declIsAssumption = declIsAssumption- , declUsedVars = declUsedVars- , declLocation = declLocation- }- where- newDeclType = typeFunT varOrig Id varType Nothing (abstract var declType)--data OutputDirection = TopDown | BottomUp- deriving (Eq)--block :: OutputDirection -> [String] -> String-block TopDown = intercalate "\n"-block BottomUp = intercalate "\n" . reverse--namedBlock :: OutputDirection -> String -> [String] -> String-namedBlock dir name lines_ = block dir $- name : map indent lines_- where- indent = intercalate "\n" . (map (" " ++)) . lines--ppContext' :: OutputDirection -> Context VarIdent -> String-ppContext' dir ctx@Context{..} = block dir $ dropWhile null- [ block TopDown- [ case location of- _ | dir == TopDown -> "" -- FIXME- Just (LocationInfo (Just path) (Just lineNo)) ->- path <> " (line " <> show lineNo <> "):"- Just (LocationInfo (Just path) _) ->- path <> ":"- _ -> ""- , case currentCommand of- Just (Rzk.CommandDefine _loc name _vars _params _ty _term) ->- " Error occurred when checking\n #define " <> Rzk.printTree name- Just (Rzk.CommandPostulate _loc name _vars _params _ty ) ->- " Error occurred when checking\n #postulate " <> Rzk.printTree name- Just (Rzk.CommandCheck _loc term ty) ->- " Error occurred when checking\n " <> Rzk.printTree term <> " : " <> Rzk.printTree ty- Just (Rzk.CommandCompute _loc term) ->- " Error occurred when computing\n " <> Rzk.printTree term- Just (Rzk.CommandComputeNF _loc term) ->- " Error occurred when computing NF for\n " <> Rzk.printTree term- Just (Rzk.CommandComputeWHNF _loc term) ->- " Error occurred when computing WHNF for\n " <> Rzk.printTree term- Just (Rzk.CommandSetOption _loc optionName _optionValue) ->- " Error occurred when trying to set option\n #set-option " <> show optionName- Just command@Rzk.CommandUnsetOption{} ->- " Error occurred when trying to unset option\n " <> Rzk.printTree command- Just command@Rzk.CommandAssume{} ->- " Error occurred when checking assumption\n " <> Rzk.printTree command- Just (Rzk.CommandSection _loc name) ->- " Error occurred when checking\n #section " <> Rzk.printTree name- Just (Rzk.CommandSectionEnd _loc name) ->- " Error occurred when checking\n #end " <> Rzk.printTree name- Nothing -> " Error occurred outside of any command!"- ]- , ""- , case filter (/= topeTopT) (availableTopes ctx) of- [] -> "Local tope context is unrestricted (⊤)."- localTopes' -> namedBlock TopDown "Local tope context:"- [ " " <> ppU (untyped tope)- | tope <- localTopes' ]- , ""- , block dir- [ "when " <> ppAction fbs 0 action- | action <- actionStack ]- , namedBlock TopDown "Definitions in context:"- [ block dir- [ dispName x <> " : " <> ppU (untyped ty)- | (x, ty) <- reverse (varTypes ctx) ] ]- ]- where- (fbs, _) = contextBinders ctx- ppU = ppFoldU fbs- -- a pattern binder is shown as its pattern, e.g. (t , s); others by name- dispName x = maybe (show (Pure x :: Term')) (show . binderDisplayName) (lookup x fbs)---- | All display names in scope, read off the raw entries: a binder--- ('varOrig') never mentions the scope's variables, so no global payload--- needs embedding. Going through 'varOrigs' here instead embedded every--- global 'VarInfo' once per new top-level name ('checkTopLevelDuplicate'),--- quadratically over a project.-scopeNames :: Context var -> [VarIdent]-scopeNames Context{..} = mapMaybe entryName (concatMap scopeVars localScopes)- <> mapMaybe entryName (concatMap gscopeVars globalScopes)- where- entryName :: (v, VarInfo w) -> Maybe VarIdent- entryName = binderName . varOrig . snd--doesShadowName :: VarIdent -> TypeCheck var [VarIdent]-doesShadowName name = asks (filter (name ==) . scopeNames)--checkTopLevelDuplicate :: VarIdent -> TypeCheck var ()-checkTopLevelDuplicate name = do- doesShadowName name >>= \case- [] -> return ()- collisions -> issueTypeError $- TypeErrorDuplicateTopLevel collisions name--checkNameShadowing :: VarIdent -> TypeCheck var ()-checkNameShadowing name = do- doesShadowName name >>= \case- [] -> return ()- collisions -> issueWarning $- Rzk.printTree (getVarIdent name) <> " shadows an existing definition:"- <> unlines- [ " " <> ppVarIdentWithLocation name- , "previous top-level definitions found at"- , intercalate "\n"- [ " " <> ppVarIdentWithLocation prev | prev <- collisions ] ]--withLocation :: LocationInfo -> TypeCheck var a -> TypeCheck var a-withLocation loc = local $ \Context{..} -> Context { location = Just loc, .. }--withCommand :: Rzk.Command -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent]) -> TypeCheck VarIdent ([Decl'], [TypeErrorInScopedContext VarIdent])-withCommand command tc = local f $ do- result <- (Right <$> tc) `catchError` (return . Left)- case result of- Left err -> return ([], [err])- Right (decls, errs) -> return (decls, errs)- where- f Context{..} = Context- { currentCommand = Just command- , location = updatePosition (Rzk.hasPosition command) <$> location- , .. }- updatePosition pos loc = loc { locationLine = fst <$> pos }--localDecls :: [Decl VarIdent] -> TypeCheck VarIdent a -> TypeCheck VarIdent a-localDecls [] = id-localDecls (decl : decls) = localDecl decl . localDecls decls--localDeclsPrepared :: [Decl VarIdent] -> TypeCheck VarIdent a -> TypeCheck VarIdent a-localDeclsPrepared [] = id-localDeclsPrepared (decl : decls) = localDeclPrepared decl . localDeclsPrepared decls--localDecl :: Decl VarIdent -> TypeCheck VarIdent a -> TypeCheck VarIdent a-localDecl (Decl x ty term isAssumption vars loc) tc = do- ty' <- memoizeWHNF ty- term' <- traverse memoizeWHNF term- localDeclPrepared (Decl x ty' term' isAssumption vars loc) tc--localDeclPrepared :: Decl VarIdent -> TypeCheck VarIdent a -> TypeCheck VarIdent a-localDeclPrepared (Decl x ty term isAssumption vars loc) tc = do- checkTopLevelDuplicate x- local update tc- where- update = addVarInCurrentGlobalScope x VarInfo- { varType = ty- , varValue = term- , varOrig = BinderVar (Just x)- , varModality = Id- , modAccum = Id- , varIsAssumption = isAssumption- , varIsTopLevel = True- , varDeclaredAssumptions = vars- , varLocation = loc- }---- | A binding shown in a hole's local context: the display name and its type,--- already rendered with user-facing 'VarIdent' names (see 'HoleInfo').-data HoleEntry = HoleEntry- { holeEntryName :: VarIdent- , holeEntryType :: Term'- } deriving (Eq, Show)---- | The structured goal and context at a hole, recorded in lenient mode (see--- 'allowHoles'). Everything is rendered to user-facing 'VarIdent' names at--- record time, so 'HoleInfo' is independent of the De Bruijn scope it came--- from. Local hypotheses are split into ordinary term variables and cube--- variables (the cube/tope layer is specific to Rzk); the global environment is--- deliberately excluded — it belongs in a searchable inventory, not the goal--- panel.-data HoleInfo = HoleInfo- { holeName :: Maybe VarIdent -- ^ the @?name@, if the hole was named- , holeGoal :: Term' -- ^ expected type (the goal), kept symbolic- , holeGoalShape :: Maybe (VarIdent, Term')- -- ^ when the goal is a /shape/ (the hole is the argument of a- -- shape-restricted function), the shape's bound variable and its tope: the- -- goal then reads @(binder : holeGoal | tope)@. 'Nothing' for an ordinary- -- goal. (Extension-type goals need no special handling — they are already a- -- restricted type in 'holeGoal'.)- , holeTermVars :: [HoleEntry] -- ^ local hypotheses whose type is not a cube- , holeCubeVars :: [HoleEntry] -- ^ local cube variables (type is a cube)- , holeTopes :: [Term'] -- ^ local tope assumptions (excluding ⊤)- , holeCandidates :: [Term']- -- ^ elimination spines over the local hypotheses whose type fits the goal,- -- with applied arguments left as holes (see 'allEliminationsInto'). Already- -- rendered, like the other fields.- , holeIntroductions :: [Term']- -- ^ introduction forms for the goal type, built from its head constructor- -- with the constituents left as holes (see 'allIntroductionsOf'). Already- -- rendered, like the other fields.- , holeDiagram :: Maybe String- -- ^ an SVG of the goal cell, when the goal is a renderable shape (an arrow,- -- triangle, or square up to dimension 3): the shape with its given boundary- -- edges, drawn from an abstract inhabitant of the goal type with the- -- proof term hidden (see 'renderHideTerm'). 'Nothing' for a non-shape goal.- , holeLocation :: Maybe LocationInfo- } deriving (Eq, Show)--type TypeCheck var =- ReaderT (Context var)- (WriterT [HoleInfo] (Except (TypeErrorInScopedContext var)))--freeVarsT_ :: Eq var => TermT var -> TypeCheck var [var]-freeVarsT_ term = do- ctx <- ask- let typeOfVar' x =- case lookupVarInfo x ctx of- Nothing -> panicImpossible "undefined variable"- Just info -> varType info- return (freeVarsT typeOfVar' term)--traceStartAndFinish :: Show a => String -> a -> a-traceStartAndFinish tag = trace ("start [" <> tag <> "]") .- (\x -> trace ("finish [" <> tag <> "] with " <> show x) x)---- | Monadic 'all' that stops at the first failing element.-allM :: Monad m => (a -> m Bool) -> [a] -> m Bool-allM p = go- where- go [] = return True- go (x:xs) = p x >>= \case- False -> return False- True -> go xs--entailM :: Eq var => [ModalTope var] -> TermT var -> TypeCheck var Bool-entailM modalTopes goal = do- -- genTopes <- generateTopesForPointsM (allTopePoints goal)- topes''' <- saturateForEntailment modalTopes- entailSaturatedM topes''' goal---- | The preprocessing 'entailM' performs before searching: dedup, split off--- context disjunctions, and saturate each alternative. Depends only on the--- given topes (plus the discreteness axioms of the context), not on the goal--- (the points argument of 'saturateTopes' is ignored).-saturateForEntailment :: Eq var => [ModalTope var] -> TypeCheck var [[ModalTope var]]-saturateForEntailment modalTopes = do- discreteAxioms <- generateTopesForModalCubeVarsM- let topes' = nubTermT (modalTopes <> discreteAxioms)- topes'' = simplifyLHSwithDisjunctions topes'- mapM (fmap (saturateTopes [] . saturateBottom) . saturateInv) topes''---- | Search each saturated alternative for the goal; the shared tail of--- 'entailM' and the cached 'entailContextM'.-entailSaturatedM :: Eq var => [[ModalTope var]] -> TermT var -> TypeCheck var Bool-entailSaturatedM topes''' goal = asks verbosity >>= \case- Debug -> do- prettyTopes <- mapM ppTermInContext (map tTope (concat topes'''))- prettyTope <- ppTermInContext goal- traceTypeCheck Debug- ("entail " <> intercalate ", " prettyTopes <> " |- " <> prettyTope) $- allM (`solveRHSM` goal) topes'''- _ -> allM (`solveRHSM` goal) topes'''---- | Entailment against the context's own tope context, using the--- 'localTopesSaturated' cache when one was installed (it is maintained at--- the points where the tope context changes); otherwise fall back to the--- per-query pipeline over 'localTopesNF'. Matching on the payload of--- 'SaturationCached' is what forces the deferred pipeline, so the cost is--- paid at the first query under a context, and never for contexts that are--- never queried.-entailContextM :: Eq var => TermT var -> TypeCheck var Bool-entailContextM goal = asks localTopesSaturated >>= \case- SaturationCached (Just topes''') -> entailSaturatedM topes''' goal- SaturationCached Nothing -> fallback- SaturationUncached -> fallback- where- fallback = asks localTopesNF >>= (`entailM` goal)---- | Install a deferred 'localTopesSaturated' cache for the transformed--- context, and run the action with it. The pipeline's effects (Reader,--- Writer, Except) are discharged purely into a thunk: installation costs--- nothing, holes recorded by the speculative run are discarded, and a--- pipeline error (e.g. a tope guard with a hole in lenient mode, which the--- per-query path would never have evaluated) becomes 'Nothing', so errors--- surface exactly where they did before. Used at every point where the tope--- context changes; ordinary binder entries instead shift the cached value--- with the rest of the context (saturation commutes with renaming).-withRefreshedTopes :: Eq var => (Context var -> Context var) -> TypeCheck var a -> TypeCheck var a-withRefreshedTopes f action = do- ctx' <- asks f- let sat = case runExcept (runWriterT (runReaderT (saturateForEntailment (localTopesNF ctx')) ctx')) of- Left _ -> Nothing- Right (s, _) -> Just s- local (const ctx' { localTopesSaturated = SaturationCached sat }) action---generateTopesForModalCubeVarsM :: TypeCheck var [ModalTope var]-generateTopesForModalCubeVarsM = asks localDiscreteTopes--entailTraceM :: Eq var => [ModalTope var] -> TermT var -> TypeCheck var Bool-entailTraceM modalTopes goal = do- topes' <- mapM ppTermInContext (accessibleTopes modalTopes)- goal' <- ppTermInContext goal- result <- trace ("entail " <> intercalate ", " topes' <> " |- " <> goal') $- modalTopes `entailM` goal- return $ trace (" " <> show result) result--nubTermT :: Eq a => [a] -> [a]-nubTermT [] = []-nubTermT (t:ts) = t : nubTermT (filter (/= t) ts)--saturateTopes :: Eq var => [TermT var] -> [ModalTope var] -> [ModalTope var]-saturateTopes _points topes =- let (accessible, inaccessible) = partitionAccessible topes- saturated = saturateWith- (\mt ts -> mt `elem` ts)- (\new old -> map plainTope $ generateTopes (map tTope new) (map tTope old))- accessible- in saturated <> inaccessible--saturateInv :: Eq var => [ModalTope var] -> TypeCheck var [ModalTope var]-saturateInv modalTopes = do- -- FIXME: this is a workaround; ideally we should regenerate all topes- -- on EVERY modality change in any layer, but that would produce too many;- -- for now we also invert topes that were accessible before the modality shift- let accessible = filterAccessible modalTopes- accessibleById = filter (\mt -> coe (tModVar mt) Id) modalTopes- invResults <- forM (nubTermT (accessible <> accessibleById)) $ \mt -> do- nf <- nfTope $ modExtractT topeT Id Op (topeInvT (tTope mt))- return $ ModalTope (tModAccum mt) Op nf- let accessibleUnderOp = filter (\mt -> coe (tModVar mt) (comp (tModAccum mt) Op)) modalTopes- uninvResults <- forM accessibleUnderOp $ \(ModalTope acc var' phi) -> do- nf <- nfTope $ topeUninvT (modAppT topeT Op phi)- return $ ModalTope (comp acc Op) var' nf- let newTopes = nubTermT (invResults <> uninvResults)- fresh = filter (`notElem` modalTopes) newTopes- return (modalTopes <> fresh)---- | Ex falso for BOT, lifted across modalities.------ A contradiction in the topes that are genuinely available at the identity--- modality entails BOT, and BOT entails @_μ BOT@ for every modality @μ@ by the--- absurd rule (this holds for BOT specifically; a general tope @φ@ does NOT give--- @_μ φ@, which would need the missing unit @id ⇒ μ@). Re-asserting @_μ BOT@ at--- each lock @μ@ where an available tope was hidden lets the contradiction survive--- the lock: e.g. @_b BOT@ is accessible under a @_b@ lock (@coe Flat Flat@), so--- @mod _b recBOT@ in a vacuous context is accepted.------ A tope counts as available at the identity modality when its variable modality--- coerces into @Id@: a @_b@-modal tope qualifies via the counit (@coe Flat Id@),--- but a @_#@-modal one does not (@coe Sharp Id@ is False) — which is exactly why--- @_# BOT@ does not leak to plain BOT (see ill-modal-sharp-bot-not-bot).-saturateBottom :: Eq var => [ModalTope var] -> [ModalTope var]-saturateBottom modalTopes- | null droppedAccums = modalTopes -- nothing hidden by a lock; ordinary saturation suffices- | botDerivable = modalTopes <> fresh- | otherwise = modalTopes- where- idAccessible = filter (\mt -> coe (tModVar mt) Id) modalTopes- droppedAccums = nub [ tModAccum mt | mt <- idAccessible, not (isAccessible mt) ]- saturatedId = saturateWith (\t ts -> t `elem` ts) generateTopes (map tTope idAccessible)- botDerivable = topeBottomT `elem` saturatedId- fresh = [ mt- | acc <- droppedAccums- , let mt = ModalTope acc acc topeBottomT- , mt `notElem` modalTopes ]---- FIXME: cleanup-saturateWith :: (a -> [a] -> Bool) -> ([a] -> [a] -> [a]) -> [a] -> [a]-saturateWith elem' step zs = go (nub' zs) []- where- go lastNew xs- | null new = lastNew- | otherwise = lastNew <> go new xs'- where- xs' = lastNew <> xs- new = filter (not . (`elem'` xs')) (nub' $ step lastNew xs)- nub' [] = []- nub' (x:xs) = x : nub' (filter (not . (`elem'` [x])) xs)--generateTopes :: Eq var => [TermT var] -> [TermT var] -> [TermT var]-generateTopes newTopes oldTopes- | topeBottomT `elem` newTopes = []- | topeEQT cube2_0T cube2_1T `elem` newTopes = [topeBottomT]- | topeEQT cubeI_0T cubeI_1T `elem` newTopes = [topeBottomT]- | length oldTopes > 100 = [] -- FIXME- | otherwise = concat- [ -- symmetry EQ- [ topeEQT y x | TopeEQT _ty x y <- newTopes ]- -- transitivity EQ (1)- , [ topeEQT x z- | TopeEQT _ty x y : newTopes' <- tails newTopes- , TopeEQT _ty y' z <- newTopes' <> oldTopes- , y == y' ]- -- transitivity EQ (2)- , [ topeEQT x z- | TopeEQT _ty y z : newTopes' <- tails newTopes- , TopeEQT _ty x y' <- newTopes' <> oldTopes- , y == y' ]-- -- transitivity LEQ (1)- , [ topeLEQT x z- | TopeLEQT _ty x y : newTopes' <- tails newTopes- , TopeLEQT _ty y' z <- newTopes' <> oldTopes- , y == y' ]- -- transitivity LEQ (2)- , [ topeLEQT x z- | TopeLEQT _ty y z : newTopes' <- tails newTopes- , TopeLEQT _ty x y' <- newTopes' <> oldTopes- , y == y' ]-- -- antisymmetry LEQ- , [ topeEQT x y- | TopeLEQT _ty x y : newTopes' <- tails newTopes- , TopeLEQT _ty y' x' <- newTopes' <> oldTopes- , y == y'- , x == x' ]-- -- FIXME: special case of substitution of EQ- -- transitivity EQ-LEQ (1)- , [ topeLEQT x z- | TopeEQT _ty y z : newTopes' <- tails newTopes- , TopeLEQT _ty x y' <- newTopes' <> oldTopes- , y == y' ]-- -- FIXME: special case of substitution of EQ- -- transitivity EQ-LEQ (2)- , [ topeLEQT x z- | TopeEQT _ty x y : newTopes' <- tails newTopes- , TopeLEQT _ty y' z <- newTopes' <> oldTopes- , y == y' ]-- -- FIXME: special case of substitution of EQ- -- transitivity EQ-LEQ (3)- , [ topeLEQT x z- | TopeLEQT _ty y z : newTopes' <- tails newTopes- , TopeEQT _ty x y' <- newTopes' <> oldTopes- , y == y' ]-- -- FIXME: special case of substitution of EQ- -- transitivity EQ-LEQ (4)- , [ topeLEQT x z- | TopeLEQT _ty x y : newTopes' <- tails newTopes- , TopeEQT _ty y' z <- newTopes' <> oldTopes- , y == y' ]-- -- FIXME: consequence of LEM for LEQ and antisymmetry for LEQ- , [ topeEQT x y | TopeLEQT _ty x y@Cube2_0T{} <- newTopes ]- -- FIXME: consequence of LEM for LEQ and antisymmetry for LEQ- , [ topeEQT x y | TopeLEQT _ty x@Cube2_1T{} y <- newTopes ]- , [ topeEQT x y | TopeLEQT _ty x y@CubeI_0T{} <- newTopes ]- -- FIXME: consequence of LEM for LEQ and antisymmetry for LEQ- , [ topeEQT x y | TopeLEQT _ty x@CubeI_1T{} y <- newTopes ]-- -- subtyping 2 <: II: endpoints and order of 2 lift to II- , [ topeEQT x cubeI_0T | TopeEQT _ty x Cube2_0T{} <- newTopes ]- , [ topeEQT cubeI_0T x | TopeEQT _ty Cube2_0T{} x <- newTopes ]- , [ topeEQT x cubeI_1T | TopeEQT _ty x Cube2_1T{} <- newTopes ]- , [ topeEQT cubeI_1T x | TopeEQT _ty Cube2_1T{} x <- newTopes ]- , [ topeLEQT x cubeI_0T | TopeLEQT _ty x Cube2_0T{} <- newTopes ]- , [ topeLEQT cubeI_0T x | TopeLEQT _ty Cube2_0T{} x <- newTopes ]- , [ topeLEQT x cubeI_1T | TopeLEQT _ty x Cube2_1T{} <- newTopes ]- , [ topeLEQT cubeI_1T x | TopeLEQT _ty Cube2_1T{} x <- newTopes ]- ]--generateTopesForPointsM :: Eq var => [TermT var] -> TypeCheck var [TermT var]-generateTopesForPointsM points = do- let pairs = nub $ concat- [ [ (x, y)- | x : points' <- tails (filter (`notElem` [cube2_0T, cube2_1T, cubeI_0T, cubeI_1T]) points)- , y <- points'- , x /= y ]- ]- stars <- forM points $ \x -> do- xType <- typeOf x- return $ if (xType == cubeUnitT)- then [topeEQT x cubeUnitStarT]- else []- topes <- forM pairs $ \(x, y) -> do- xType <- typeOf x- yType <- typeOf y- return $ if (xType == cube2T) && (yType == cube2T)- then [topeOrT (topeLEQT x y) (topeLEQT y x)]- else []- return (concat (topes ++ stars))--allTopePoints :: Eq var => TermT var -> [TermT var]-allTopePoints = nubTermT . foldMap subPoints . nubTermT . topePoints--topePoints :: TermT var -> [TermT var]-topePoints = \case- TopeTopT{} -> []- TopeBottomT{} -> []- TopeAndT _ l r -> topePoints l <> topePoints r- TopeOrT _ l r -> topePoints l <> topePoints r- TopeEQT _ x y -> [x, y]- TopeLEQT _ x y -> [x, y]- _ -> []--subPoints :: TermT var -> [TermT var]-subPoints = \case- p@(PairT _ x y) -> p : foldMap subPoints [x, y]- p@Pure{} -> [p]- p@(Free (AnnF TypeInfo{..} _))- | Cube2T{} <- infoType -> [p]- | CubeUnitT{} <- infoType -> [p]- _ -> []---- | Simplify the context, including disjunctions. See also 'simplifyLHS'.-simplifyLHSwithDisjunctions :: Eq var => [ModalTope var] -> [[ModalTope var]]-simplifyLHSwithDisjunctions topes = map nubTermT $- case topes of- [] -> [[]]- (ModalTope _ _ TopeTopT{}) : topes' -> simplifyLHSwithDisjunctions topes'- (ModalTope mAcc mVar TopeBottomT{}) : _ -> [[ModalTope mAcc mVar topeBottomT]]- (ModalTope mAcc mVar (TopeAndT _ l r)) : topes' -> simplifyLHSwithDisjunctions ((ModalTope mAcc mVar l) : (ModalTope mAcc mVar r) : topes')-- -- NOTE: it is inefficient to expand disjunctions immediately- (ModalTope mAcc mVar (TopeOrT _ l r)) : topes' -> simplifyLHSwithDisjunctions ((ModalTope mAcc mVar l) : topes') <> simplifyLHSwithDisjunctions ((ModalTope mAcc mVar r) : topes')-- (ModalTope mAcc mVar (TopeEQT _ (PairT _ x y) (PairT _ x' y'))) : topes' ->- simplifyLHSwithDisjunctions (ModalTope mAcc mVar (topeEQT x x') : ModalTope mAcc mVar (topeEQT y y') : topes')- (ModalTope mAcc mVar (TypeModalT _ md inTope)) : topes' ->- simplifyLHSwithDisjunctions ((ModalTope mAcc (comp mVar md) inTope) : topes')- t : topes' -> map (t :) (simplifyLHSwithDisjunctions topes')---- | Simplify the context, except disjunctions. See also 'simplifyLHSwithDisjunctions'.-simplifyLHS :: Eq var => [ModalTope var] -> [ModalTope var]-simplifyLHS topes = nubTermT $- case topes of- [] -> []- (ModalTope _ _ TopeTopT{}) : topes' -> simplifyLHS topes'- (ModalTope _ _ TopeBottomT{}) : _ -> [plainTope topeBottomT]- (ModalTope mAcc mVar (TopeAndT _ l r)) : topes' -> simplifyLHS (ModalTope mAcc mVar l : ModalTope mAcc mVar r : topes')-- -- NOTE: it is inefficient to expand disjunctions immediately- -- (ModalTope mAcc mVar (TopeOrT _ l r)) : topes' -> simplifyLHS (ModalTope mAcc mVar l : topes') <> simplifyLHS (ModalTope mAcc mVar r : topes')-- (ModalTope mAcc mVar (TopeEQT _ (PairT _ x y) (PairT _ x' y'))) : topes' ->- simplifyLHS (ModalTope mAcc mVar (topeEQT x x') : ModalTope mAcc mVar (topeEQT y y') : topes')- (ModalTope mAcc mVar (TypeModalT _ md inTope)) : topes' ->- simplifyLHS (ModalTope mAcc (comp mVar md) inTope : topes')- t : topes' -> t : simplifyLHS topes'--solveRHSM :: Eq var => [ModalTope var] -> TermT var -> TypeCheck var Bool-solveRHSM modalTopes goal =- let topes = accessibleTopes modalTopes- in case goal of- _ | topeBottomT `elem` topes -> return True- TopeTopT{} -> return True- TypeModalT _ty md inTope -> do- let shifted = applyModalityToTopes md modalTopes- resaturated = saturateTopes [] shifted- resaturatedInv <- saturateInv resaturated- solveRHSM resaturatedInv inTope- TopeEQT _ty (PairT _ty1 x y) (PairT _ty2 x' y') ->- solveRHSM modalTopes $ topeAndT- (topeEQT x x')- (topeEQT y y')- TopeEQT _ty (PairT TypeInfo{ infoType = CubeProductT _ cubeI cubeJ } x y) r ->- solveRHSM modalTopes $ topeAndT- (topeEQT x (firstT cubeI r))- (topeEQT y (secondT cubeJ r))- TopeEQT _ty l (PairT TypeInfo{ infoType = CubeProductT _ cubeI cubeJ } x y) ->- solveRHSM modalTopes $ topeAndT- (topeEQT (firstT cubeI l) x)- (topeEQT (secondT cubeJ l) y)- TopeEQT _ty l r- | or- [ l == r- , goal `elem` topes- , topeEQT r l `elem` topes- ] -> return True- TopeEQT _ty l r -> do- lType <- typeOf l- rType <- typeOf r- return $ case (lType, rType) of- (CubeUnitT{}, CubeUnitT{}) -> True- _ -> False- TopeLEQT _ty l r- | l == r -> return True- | solveRHS topes (topeEQT l r) -> return True- | solveRHS topes (topeEQT l cube2_0T) -> return True- | solveRHS topes (topeEQT r cube2_1T) -> return True- TopeAndT _ l r -> solveRHSM modalTopes l >>= \case- False -> return False- True -> solveRHSM modalTopes r- _ | goal `elem` topes -> return True- TopeInvT{} -> do- goal' <- nfTope goal- case goal' of- TopeInvT{} -> return False- _ -> solveRHSM modalTopes goal'- TopeUninvT{} -> do- goal' <- nfTope goal- case goal' of- TopeUninvT{} -> return False- _ -> solveRHSM modalTopes goal'- TopeOrT _ l r -> do- found <- solveRHSM modalTopes l >>= \case- True -> return True- False -> solveRHSM modalTopes r- if found- then return True- else do- lems <- generateTopesForPointsM (allTopePoints goal)- let lems' = [ lem | lem@(TopeOrT _ t1 t2) <- lems, all (`notElem` topes) [t1, t2] ]- (accessible, hidden) = partitionAccessible modalTopes- withTope t = hidden ++ saturateTopes [] (plainTope t : accessible)-- case lems' of- TopeOrT _ t1 t2 : _ ->- solveRHSM (withTope t1) goal >>= \case- False -> return False- True -> solveRHSM (withTope t2) goal- _ -> return False- _ -> return False--solveRHS :: Eq var => [TermT var] -> TermT var -> Bool-solveRHS topes tope =- case tope of- _ | topeBottomT `elem` topes -> True- TopeTopT{} -> True- TopeEQT _ty (PairT _ty1 x y) (PairT _ty2 x' y')- | solveRHS topes (topeEQT x x') && solveRHS topes (topeEQT y y') -> True- TopeEQT _ty (PairT TypeInfo{ infoType = CubeProductT _ cubeI cubeJ } x y) r- | solveRHS topes (topeEQT x (firstT cubeI r)) && solveRHS topes (topeEQT y (secondT cubeJ r)) -> True- TopeEQT _ty l (PairT TypeInfo{ infoType = CubeProductT _ cubeI cubeJ } x y)- | solveRHS topes (topeEQT (firstT cubeI l) x) && solveRHS topes (topeEQT (secondT cubeJ l) y) -> True- TopeEQT _ty l r -> or- [ l == r- , tope `elem` topes- , topeEQT r l `elem` topes- ]- TopeLEQT _ty l r- | l == r -> True- | solveRHS topes (topeEQT l r) -> True- | solveRHS topes (topeEQT l cube2_0T) -> True- | solveRHS topes (topeEQT r cube2_1T) -> True- -- TopeBottomT{} -> solveLHS topes tope- TopeAndT _ l r -> solveRHS topes l && solveRHS topes r- TopeOrT _ l r -> solveRHS topes l || solveRHS topes r- _ -> tope `elem` topes--checkTope :: Eq var => TermT var -> TypeCheck var Bool-checkTope tope = do- ctxTopes <- asks availableTopes- performing (ActionContextEntails ctxTopes tope) $ do- tope' <- nfTope tope- entailContextM tope'--checkTopeEntails :: Eq var => TermT var -> TypeCheck var Bool-checkTopeEntails tope = do- ctxTopes <- asks availableTopes- performing (ActionContextEntailedBy ctxTopes tope) $ do- contextTopes <- asks availableTopesNF- restrictionTope <- nfTope tope- let contextTopesRHS = foldr topeAndT topeTopT contextTopes- [plainTope restrictionTope] `entailM` contextTopesRHS--checkEntails :: Eq var => TermT var -> TermT var -> TypeCheck var Bool-checkEntails l r = do -- FIXME: add action- l' <- nfTope l- r' <- nfTope r- [plainTope l'] `entailM` r'--contextEntails :: Eq var => TermT var -> TypeCheck var ()-contextEntails tope = do- ctxTopes <- asks availableTopes- performing (ActionContextEntails ctxTopes tope) $ do- topeIsEntailed <- checkTope tope- topes' <- asks availableTopesNF- -- When a hole is used in a cube/tope position (e.g. as the argument of a- -- shape-restricted function), the tope being checked mentions the hole and- -- cannot be decided. Treat it as satisfied (defer) rather than failing.- unless (topeIsEntailed || containsHole tope) $- issueTypeError $ TypeErrorTopeNotSatisfied topes' tope--topesEquiv :: Eq var => TermT var -> TermT var -> TypeCheck var Bool-topesEquiv expected actual = performing (ActionUnifyTerms expected actual) $ do- expected' <- nfT expected- actual' <- nfT actual- (&&)- <$> [plainTope expected'] `entailM` actual'- <*> [plainTope actual'] `entailM` expected'---- | Check that the local tope context is included in (entails) the union of--- the given topes. This is the COVERAGE obligation of @recOR@: every point of the--- context must be covered by some branch guard.------ Note that only coverage is required, not equivalence: branch guards may overhang--- the context (e.g. when splitting with an already-defined shape), so we do not--- require @OR(guards) |- context@.-contextEntailsUnion :: Eq var => [TermT var] -> TypeCheck var ()-contextEntailsUnion topes = do- ctxTopes <- asks availableTopes- performing (ActionContextEntailsUnion ctxTopes topes) $ do- contextTopes <- asks localTopesNF- topesNF <- mapM nfTope topes- let unionRHS = foldr topeOrT topeBottomT topesNF- entailContextM unionRHS >>= \case- -- a guard mentioning an (unfilled) hole can't be decided; defer coverage- False | not (any containsHole topesNF) ->- issueTypeError $ TypeErrorTopeNotSatisfied (accessibleTopes contextTopes) unionRHS- _ -> return ()---- | Diagnose a recOR branch guard or restriction face against the local tope--- context. There are three cases, by how the tope relates to the context:------ * DISJOINT — the tope and a consistent context have empty overlap (their--- conjunction is ⊥). The face/branch is then vacuous everywhere, so this is a--- hard error.--- * OVERHANG — the tope is not entailed by the context but still overlaps it.--- This is allowed and often intentional (e.g. splitting or restricting with an--- already-defined shape, whose faces live on the whole cube rather than being--- relativised to the context), so we only emit a non-fatal hint. The hint is--- gated at 'Normal' verbosity, hence silent under 'Silent' (e.g. in tests).--- * CONTAINED — the tope entails the context: nothing to report.-checkTopeAgainstContext :: Eq var => String -> TermT var -> TypeCheck var ()-checkTopeAgainstContext what tope = do- -- a contradictory context is handled elsewhere (recBOT)- ctxEntailsBottom <- contextEntailsBottom- unless ctxEntailsBottom $ do- contextTopes <- asks localTopesNF- let ctxTopes = filter (/= topeTopT) (accessibleTopes contextTopes)- disjoint <- (plainTope tope : contextTopes) `entailM` topeBottomT- -- a face/guard mentioning an (unfilled) hole can't be decided; defer- if disjoint && not (containsHole tope)- then issueTypeError (TypeErrorTopeContextDisjoint tope ctxTopes)- else do- entailed <- checkTopeEntails tope -- tope |- AND(accessible context)- unless entailed $ do- topeStr <- ppTermInContext tope- ctxStrs <- mapM ppTermInContext ctxTopes- traceTypeCheck Normal- (intercalate "\n" $- [ "Warning: " <> what <> " overhangs the local tope context"- , " " <> topeStr- , "is not entailed by the local context (normalised)"- ] <> map (" " <>) ctxStrs)- (return ())--switchVariance :: TypeCheck var a -> TypeCheck var a-switchVariance = local $ \Context{..} -> Context- { covariance = switch covariance, .. }- where- switch Covariant = Contravariant- switch Contravariant = Covariant- switch Invariant = Invariant--setVariance :: Covariance -> TypeCheck var a -> TypeCheck var a-setVariance variance = local $ \Context{..} -> Context- { covariance = variance, .. }--enterScopeContext :: Binder -> TModality -> TermT var -> Maybe (TermT var) -> Context var -> Context (Inc var)-enterScopeContext orig md ty val context =- addVarInCurrentScope Z VarInfo- { varType = S <$> ty- , varValue = fmap (S <$>) val- , varOrig = orig- , varModality = md- , modAccum = Id- , varIsAssumption = False- , varIsTopLevel = False- , varDeclaredAssumptions = []- , varLocation = location context- }- (S <$> context)--enterScopeMaybe :: Eq var => Binder -> TModality -> TermT var -> Maybe (TermT var) -> TypeCheck (Inc var) b -> TypeCheck var b-enterScopeMaybe orig md ty mval action = do- mDiscrete <- case md of- Flat -> whnfT ty >>= \case- Cube2T{} -> pure (Just (topeOrT (topeEQT z cube2_0T) (topeEQT z cube2_1T)))- CubeIT{} -> pure (Just (topeOrT (topeEQT z cubeI_0T) (topeEQT z cubeI_1T)))- _ -> pure Nothing- _ -> pure Nothing- newContext <- asks (enterScopeContext orig md ty mval)- let newContext' = newContext- { localDiscreteTopes = maybe id ((:) . plainTope) mDiscrete (localDiscreteTopes newContext) }- -- A new discreteness axiom changes the saturation input; ordinary- -- binders keep the shifted cache (saturation commutes with renaming).- refresh = maybe id (const (withRefreshedTopes id)) mDiscrete- closeScope orig (runReaderT (refresh action) newContext')- where- z = Pure Z--enterScope :: Eq var => Binder -> TModality -> TermT var -> TypeCheck (Inc var) b -> TypeCheck var b-enterScope orig md ty = enterScopeMaybe orig md ty Nothing--enterScopeWithBind :: Eq var => Binder -> TModality -> TermT var -> TermT var -> TypeCheck (Inc var) b -> TypeCheck var b-enterScopeWithBind orig md ty val = enterScopeMaybe orig md ty (Just val)---- | Run a sub-scope computation and lift it back to the enclosing scope: close--- the error channel one binder with 'ScopedTypeError' (as before), and re-emit--- the holes it recorded. 'HoleInfo' is already rendered to 'VarIdent' names, so--- no De Bruijn re-indexing is needed — only a plain re-'tell'. On a thrown--- error the sub-scope's holes are dropped, which is intended: holes only matter--- on the success path (lenient mode), and strict mode wants the error anyway.-closeScope- :: Binder- -> WriterT [HoleInfo] (Except (TypeErrorInScopedContext (Inc var))) b- -> TypeCheck var b-closeScope orig inner = do- (b, holes) <- lift . lift . withExceptT (ScopedTypeError (binderName orig)) $ runWriterT inner- lift (tell holes)- return b--enterModality :: Eq var => TModality -> TypeCheck var b -> TypeCheck var b-enterModality Id action = action-enterModality md action = do- newContext <- asks (applyModality md)- let newContext' = newContext { localTopesEntailBottom = Nothing }- -- 'applyModality' invalidated the saturation cache (accessibility- -- changed); refresh it under the shifted context.- lift $ runReaderT (withRefreshedTopes id action) newContext'--performing :: Eq var => Action var -> TypeCheck var a -> TypeCheck var a-performing action tc = do- ctx@Context{..} <- ask- unless (length actionStack < 1000) $ -- FIXME: which depth is reasonable? factor out into a parameter- issueTypeError $ TypeErrorOther "maximum depth reached"- traceTypeCheck Debug (ppSomeAction (varOrigs ctx) (length actionStack) action) $- local (const Context { actionStack = action : actionStack, .. }) $ tc--stripTypeRestrictions :: TermT var -> TermT var-stripTypeRestrictions (TypeRestrictedT _ty ty _restriction) = stripTypeRestrictions ty-stripTypeRestrictions t = t---- | Perform at most one \(\eta\)-expansion at the top-level to assist unification.-etaMatch :: Eq var => Maybe (TermT var) -> TermT var -> TermT var -> TypeCheck var (TermT var, TermT var)--- FIXME: double check the next 3 rules-etaMatch _mterm expected@TypeRestrictedT{} actual@TypeRestrictedT{} = pure (expected, actual)-etaMatch mterm expected (TypeRestrictedT _ty ty _rs) = etaMatch mterm expected ty-etaMatch (Just term) expected@TypeRestrictedT{} actual =- etaMatch (Just term) expected (typeRestrictedT actual [(topeTopT, term)])--- --------------------------------------- | Subtyping on interval-etaMatch _mterm CubeIT{} Cube2T{} = pure (cubeIT, cubeIT)--- -------------------------------------etaMatch _mterm expected@LambdaT{} actual@LambdaT{} = pure (expected, actual)-etaMatch _mterm expected@PairT{} actual@PairT{} = pure (expected, actual)-etaMatch _mterm expected@LambdaT{} actual = do- actual' <- etaExpand actual- pure (expected, actual')-etaMatch _mterm expected actual@LambdaT{} = do- expected' <- etaExpand expected- pure (expected', actual)-etaMatch _mterm expected@PairT{} actual = do- actual' <- etaExpand actual- pure (expected, actual')-etaMatch _mterm expected actual@PairT{} = do- expected' <- etaExpand expected- pure (expected', actual)-etaMatch _mterm expected actual = pure (expected, actual)--etaExpand :: Eq var => TermT var -> TypeCheck var (TermT var)-etaExpand term@LambdaT{} = pure term-etaExpand term@PairT{} = pure term-etaExpand term = do- ty <- typeOf term- case stripTypeRestrictions ty of- TypeFunT _ty orig md param mtope ret -> pure $- lambdaT ty orig (Just (md, param, mtope))- (appT ret (S <$> term) (Pure Z))-- TypeSigmaT _ty _orig _md a b -> pure $- pairT ty- (firstT a term)- (secondT (substituteT (firstT a term) b) term)-- CubeProductT _ty a b -> pure $- pairT ty- (firstT a term)- (secondT b term)-- _ -> pure term--inCubeLayer :: Eq var => TermT var -> TypeCheck var Bool-inCubeLayer = \case- RecBottomT{} -> pure False- UniverseT{} -> pure False-- UniverseCubeT{} -> pure True- CubeProductT{} -> pure True- CubeUnitT{} -> pure True- CubeUnitStarT{} -> pure True- Cube2T{} -> pure True- Cube2_0T{} -> pure True- Cube2_1T{} -> pure True-- t -> typeOf t >>= inCubeLayer--inTopeLayer :: Eq var => TermT var -> TypeCheck var Bool-inTopeLayer = \case- RecBottomT{} -> pure False- UniverseT{} -> pure False-- UniverseCubeT{} -> pure True- UniverseTopeT{} -> pure True-- CubeProductT{} -> pure True- CubeUnitT{} -> pure True- CubeUnitStarT{} -> pure True- Cube2T{} -> pure True- Cube2_0T{} -> pure True- Cube2_1T{} -> pure True-- TopeTopT{} -> pure True- TopeBottomT{} -> pure True- TopeAndT{} -> pure True- TopeOrT{} -> pure True- TopeEQT{} -> pure True- TopeLEQT{} -> pure True-- TypeFunT _ty orig md param _mtope ret -> do- enterScope orig md param $ inTopeLayer ret-- t -> typeOfUncomputed t >>= inTopeLayer--tryRestriction :: Eq var => TermT var -> TypeCheck var (Maybe (TermT var))-tryRestriction = \case- TypeRestrictedT _ _ rs -> do- let go [] = pure Nothing- go ((tope, term') : rs') = do- checkTope tope >>= \case- True -> pure (Just term')- False -> go rs'- go rs- _ -> pure Nothing---- | Memoise a term's WHNF on its top node without reducing the term itself.------ The returned term has the same (unreduced) structure, so free-variable and--- @uses@ detection see exactly what the user wrote, while a later 'whnfT' is--- O(1) via the cached 'infoWHNF'. Used when storing a definition's elaborated--- type and value, where an in-place reduction could otherwise discard or--- expose a variable occurrence.-memoizeWHNF :: Eq var => TermT var -> TypeCheck var (TermT var)-memoizeWHNF t@Pure{} = pure t-memoizeWHNF t@(Free (AnnF info f)) = do- w <- whnfT t- pure (Free (AnnF info { infoWHNF = Just w } f))---- | Compute a typed term to its WHNF.------ >>> unsafeTypeCheck' $ whnfT "(\\ (x : Unit) -> x) unit"--- unit : Unit-whnfT :: Eq var => TermT var -> TypeCheck var (TermT var)-whnfT tt = performing (ActionWHNF tt) $ case tt of- -- use cached result if it exists- Free (AnnF info _)- | Just tt' <- infoWHNF info -> pure tt'-- -- universe constants- UniverseT{} -> pure tt- UniverseCubeT{} -> pure tt- UniverseTopeT{} -> pure tt-- -- cube layer (except vars, pairs, and applications)- CubeProductT{} -> nfTope tt- CubeUnitT{} -> pure tt- CubeUnitStarT{} -> pure tt- Cube2T{} -> pure tt- Cube2_0T{} -> pure tt- Cube2_1T{} -> pure tt- CubeIT{} -> pure tt- CubeI_0T{} -> pure tt- CubeI_1T{} -> pure tt- CubeFlipT{} -> nfTope tt- CubeUnflipT{} -> nfTope tt-- -- tope layer (except vars, pairs of points, and applications)- TopeTopT{} -> pure tt- TopeBottomT{} -> pure tt- TopeAndT{} -> nfTope tt- TopeOrT{} -> nfTope tt- TopeEQT{} -> nfTope tt- TopeLEQT{} -> nfTope tt- TopeInvT{} -> nfTope tt- TopeUninvT{} -> nfTope tt-- -- type layer terms that should not be evaluated further- LambdaT{} -> pure tt- PairT{} -> pure tt- ReflT{} -> pure tt- TypeFunT{} -> pure tt- TypeSigmaT{} -> pure tt- TypeIdT{} -> pure tt- TypeModalT{} -> pure tt- RecBottomT{} -> pure tt- TypeUnitT{} -> pure tt- UnitT{} -> pure tt-- -- type ascriptions are ignored, since we already have a typechecked term- TypeAscT _ty term _ty' -> whnfT term-- -- check if we have cube or a tope term (if so, compute NF)- _ -> typeOf tt >>= \case- UniverseCubeT{} -> nfTope tt- UniverseTopeT{} -> nfTope tt-- -- CubeUnitT{} -> pure cubeUnitStarT -- compute an expression of 1 cube to its only point- TypeUnitT{} -> pure unitT -- compute an expression of Unit type to unit- -- FIXME: next line is ad hoc, should be improved!- TypeRestrictedT _info TypeUnitT{} _rs -> pure unitT -- compute an expression of Unit type to unit-- -- check if we have cube point term (if so, compute NF)- typeOf_tt -> typeOf typeOf_tt >>= \case- UniverseCubeT{} -> nfTope tt-- -- now we are in the type layer- _ -> fmap termIsWHNF $ do- tryRestriction typeOf_tt >>= \case- Just tt' -> whnfT tt'- Nothing -> case tt of- -- a hole is opaque: it never reduces, it is already a normal form- HoleT{} -> pure tt- t@(Pure var) ->- valueOfVar var >>= \case- Nothing -> pure t- Just term -> whnfT term-- AppT ty f x ->- whnfT f >>= \case- LambdaT _ty _orig _arg body ->- whnfT (substituteT x body)- f' -> typeOf f' >>= \case- TypeFunT _ty _orig md _param (Just tope) UniverseTopeT{} -> do- x' <- enterModality md $ nfT x- topeAndT- <$> pure (AppT ty f' x')- <*> nfT (substituteT x' tope)- -- FIXME: this seems to be a hack, and will not work in all situations!- -- FIXME: need to check performance of this code thoroughly- -- FIXME: for now, it seems to add ~2x slowdown- TypeFunT info _orig md _param _mtope ret@TypeRestrictedT{}- | TypeRestrictedT{} <- infoType info -> pure (AppT ty f' x)- | otherwise -> do- x' <- enterModality md $ whnfT x- let ret' = substituteT x' ret- tryRestriction ret' >>= \case -- FIXME: too many unnecessary checks?- Nothing -> pure (AppT ty { infoType = ret' } f' x')- Just tt' -> whnfT tt'- _ -> pure (AppT ty f' x)-- LetT _ty _orig _mparam val body ->- whnfT (substituteT val body)- LetModT ty orig app inn mparam val body -> do- (enterModality app $ whnfT val) >>= \case- ModAppT _ md t | md == inn -> do- val' <- enterModality md $ whnfT t- whnfT (substituteT val' body)- b' | isRA inn -> do- bty <- typeOf b' >>= \case- TypeModalT _ _ t -> pure t- _ -> panicImpossible "not modal in letmod"- whnfT (substituteT (modExtractT bty app inn b') body)- _ -> pure (LetModT ty orig app inn mparam val body)- FirstT ty t ->- whnfT t >>= \case- PairT _ l _r -> whnfT l- t' -> pure (FirstT ty t')-- SecondT ty t ->- whnfT t >>= \case- PairT _ _l r -> whnfT r- t' -> pure (SecondT ty t')- ModAppT ty md b -> do- (enterModality md $ whnfT b) >>= \case- ModExtractT _ app inn t | inn == md -> enterModality (comp md app) $ whnfT t- b' -> pure $ ModAppT ty md b'- ModExtractT ty app inn b -> do- (enterModality app $ whnfT b) >>= \case- ModAppT _ md t | inn == md -> enterModality inn $ whnfT t- b' -> pure (ModExtractT ty app inn b')- IdJT ty tA a tC d x p ->- whnfT p >>= \case- ReflT{} -> whnfT d- p' -> pure (IdJT ty tA a tC d x p')-- RecOrT _ty rs -> do- let go [] = pure Nothing- go ((tope, tt') : rs') = do- checkTope tope >>= \case- True -> pure (Just tt')- False -> go rs'- go rs >>= \case- Just tt' -> whnfT tt'- Nothing- | [tt'] <- nubTermT (map snd rs) -> whnfT tt'- | otherwise -> pure tt-- TypeRestrictedT ty type_ rs -> do- rs' <- traverse (\(tope, term) -> (,) <$> nfT tope <*> pure term) rs- case filter ((/= topeBottomT) . fst) rs' of- [] -> whnfT type_ -- get rid of restrictions at BOT- rs'' -> TypeRestrictedT ty <$> whnfT type_ <*> pure rs''--nfTope :: Eq var => TermT var -> TypeCheck var (TermT var)-nfTope tt = performing (ActionNF tt) $ fmap termIsNF $ case tt of- HoleT{} -> pure tt- Pure var ->- valueOfVar var >>= \case- Nothing -> return tt- Just term -> nfTope term-- -- see if normal form is already available- Free (AnnF info _) | Just tt' <- infoNF info -> pure tt'-- -- universe constants- UniverseT{} -> pure tt- UniverseCubeT{} -> pure tt- UniverseTopeT{} -> pure tt-- -- cube layer constants- CubeUnitT{} -> pure tt- CubeUnitStarT{} -> pure tt- Cube2T{} -> pure tt- Cube2_0T{} -> pure tt- Cube2_1T{} -> pure tt- CubeIT{} -> pure tt- CubeI_0T{} -> pure tt- CubeI_1T{} -> pure tt-- -- type layer constants- TypeUnitT{} -> pure tt- UnitT{} -> pure tt-- -- cube layer with computation- CubeProductT _ty l r -> cubeProductT <$> nfTope l <*> nfTope r-- CubeFlipT ty t ->- nfTope t >>= \case- CubeUnflipT _ t' -> pure t'- Cube2_0T{} -> pure (modAppT (typeModalT cubeT Op cube2T) Op cube2_1T)- Cube2_1T{} -> pure (modAppT (typeModalT cubeT Op cube2T) Op cube2_0T)- CubeI_0T{} -> pure (modAppT (typeModalT cubeT Op cubeIT) Op cubeI_1T)- CubeI_1T{} -> pure (modAppT (typeModalT cubeT Op cubeIT) Op cubeI_0T)- t' -> pure (CubeFlipT ty t')-- CubeUnflipT ty t -> - nfTope t >>= \case- CubeFlipT _ t' -> pure t'- ModAppT _ Op Cube2_0T{} -> pure cube2_1T- ModAppT _ Op Cube2_1T{} -> pure cube2_0T- ModAppT _ Op CubeI_0T{} -> pure cubeI_1T- ModAppT _ Op CubeI_1T{} -> pure cubeI_0T- t' -> pure (CubeUnflipT ty t')-- -- tope layer constants- TopeTopT{} -> pure tt- TopeBottomT{} -> pure tt-- -- tope layer with computation- TopeAndT ty l r ->- nfTope l >>= \case- TopeBottomT{} -> pure topeBottomT- l' -> nfTope r >>= \case- TopeBottomT{} -> pure topeBottomT- r' -> pure (TopeAndT ty l' r')-- TopeOrT ty l r -> do- l' <- nfTope l- r' <- nfTope r- case (l', r') of- (TopeBottomT{}, _) -> pure r'- (_, TopeBottomT{}) -> pure l'- _ -> pure (TopeOrT ty l' r')-- TopeEQT ty l r -> TopeEQT ty <$> nfTope l <*> nfTope r- TopeLEQT ty l r -> TopeLEQT ty <$> nfTope l <*> nfTope r-- TopeInvT ty t ->- -- Match And/Or on the *unnormalized* input: nfTope of a shape-restricted- -- App produces a TopeAnd via shape-side-condition propagation, and- -- distributing inv over that synthetic conjunction loops forever because- -- the recursive topeInvT renormalizes the same App back into a TopeAnd.- case t of- TopeTopT _ -> pure $ modAppT topeT Op topeTopT- TopeBottomT _ -> pure $ modAppT topeT Op topeBottomT- TopeLEQT _ x y -> do- xTy <- typeOf x- yTy <- typeOf y- nfTope $- modAppT (typeModalT universeT Op topeT) Op- (topeLEQT- (modExtractT topeT Id Op (cubeFlipT xTy y))- (modExtractT topeT Id Op (cubeFlipT yTy x)))- TopeEQT _ x y -> do- xTy <- typeOf x- yTy <- typeOf y- nfTope $- modAppT (typeModalT universeT Op topeT) Op- (topeEQT- (modExtractT topeT Id Op (cubeFlipT xTy y))- (modExtractT topeT Id Op (cubeFlipT yTy x)))- TopeAndT _ phi psi -> nfTope $- modAppT (typeModalT universeT Op topeT) Op- (topeAndT- (modExtractT topeT Id Op (topeInvT phi))- (modExtractT topeT Id Op (topeInvT psi)))- TopeOrT _ phi psi -> nfTope $- modAppT (typeModalT universeT Op topeT) Op- (topeOrT- (modExtractT topeT Id Op (topeInvT phi))- (modExtractT topeT Id Op (topeInvT psi)))- _ ->- nfTope t >>= \case- TopeTopT _ -> pure topeTopT- TopeBottomT _ -> pure topeBottomT- TopeUninvT _ phi -> pure phi- TopeLEQT _ x y -> do- xTy <- typeOf x- yTy <- typeOf y- nfTope $- modAppT (typeModalT universeT Op topeT) Op- (topeLEQT- (modExtractT topeT Id Op (cubeFlipT xTy y))- (modExtractT topeT Id Op (cubeFlipT yTy x)))- TopeEQT _ x y -> do- xTy <- typeOf x- yTy <- typeOf y- nfTope $- modAppT (typeModalT universeT Op topeT) Op- (topeEQT- (modExtractT topeT Id Op (cubeFlipT xTy y))- (modExtractT topeT Id Op (cubeFlipT yTy x)))- t' -> pure (TopeInvT ty t')-- TopeUninvT ty t ->- case t of- ModAppT _ Op inner -> case inner of- TopeTopT _ -> pure topeTopT- TopeBottomT _ -> pure topeBottomT - TopeAndT _ phi psi ->- nfTope $- (topeAndT- (topeUninvT phi)- (topeUninvT psi))- TopeOrT _ phi psi ->- nfTope $- (topeOrT- (topeUninvT phi)- (topeUninvT psi))- _ ->- nfTope t >>= \case- TopeTopT _ -> pure topeTopT- TopeBottomT _ -> pure topeBottomT- TopeInvT _ phi -> pure phi- ModAppT _ Op inner'' -> case inner'' of- TopeLEQT _ x y -> do- xTy <- typeOf x- yTy <- typeOf y- nfTope $- (topeLEQT- (cubeUnflipT xTy (modAppT (typeModalT cubeT Op xTy) Op y))- (cubeUnflipT yTy (modAppT (typeModalT cubeT Op yTy) Op x)))- TopeEQT _ x y -> do- xTy <- typeOf x- yTy <- typeOf y- nfTope $- (topeEQT- (cubeUnflipT xTy (modAppT (typeModalT cubeT Op xTy) Op y))- (cubeUnflipT yTy (modAppT (typeModalT cubeT Op yTy) Op x)))- inner' ->- pure $- TopeUninvT ty- (modAppT (typeModalT universeT Op topeT) Op inner')- t' ->- pure (TopeUninvT ty t')- _ ->- nfTope t >>= \case- TopeInvT _ phi -> pure phi- t'@(ModAppT _ Op _) -> nfTope (TopeUninvT ty t')- t' -> pure (TopeUninvT ty t')-- -- type ascriptions are ignored, since we already have a typechecked term- TypeAscT _ty term _ty' -> nfTope term-- PairT ty l r -> PairT ty <$> nfTope l <*> nfTope r-- AppT ty f x ->- nfTope f >>= \case- LambdaT _ty _orig _arg body ->- nfTope (substituteT x body)- f' -> typeOfUncomputed f' >>= \case- TypeFunT _ty _orig md _param (Just tope) UniverseTopeT{} -> do- x' <- enterModality md $ nfTope x- topeAndT- <$> pure (AppT ty f' x')- <*> nfTope (substituteT x' tope)- _ -> AppT ty f' <$> nfTope x-- FirstT ty t ->- nfTope t >>= \case- PairT _ty x _y -> pure x- t' -> pure (FirstT ty t')-- SecondT ty t ->- nfTope t >>= \case- PairT _ty _x y -> pure y- t' -> pure (SecondT ty t')-- LambdaT ty orig _mparam body- | TypeFunT _ty _origF md param mtope _ret <- infoType ty ->- -- NOTE: the domain @param@ is left unnormalised: in the tope layer it may- -- be a shape (a function type into TOPE), which nfTope cannot normalise.- LambdaT ty orig (Just (md, param, mtope)) <$> enterScope orig md param (nfTope body)- LambdaT{} -> panicImpossible "lambda with a non-function type in the tope layer"- ModAppT ty md b ->- (enterModality md $ nfTope b) >>= \case- ModExtractT _ _ inn t | inn == md -> pure t- b' -> pure $ ModAppT ty md b'- ModExtractT ty app inn b ->- (enterModality app $ nfTope b) >>= \case- ModAppT _ md t | inn == md -> pure t- b' -> pure $ ModExtractT ty app inn b'- LetModT ty orig app inn mparam val body -> do- (enterModality app $ nfTope val) >>= \case- ModAppT _ md t | md == inn -> do- val' <- return t- nfTope (substituteT val' body)- b' | isRA inn -> do- bty <- typeOf b' >>= \case- TypeModalT _ _ t -> pure t- _ -> panicImpossible "not modal in letmod"- nfTope (substituteT (modExtractT bty app inn b') body)- b' -> do- bty <- typeOf b' >>= \case- TypeModalT _ _ t -> pure t- _ -> panicImpossible "not modal in letmod"- val' <- enterModality app $ nfTope b'- body' <- enterScope orig (comp app inn) bty $ nfTope body- pure (LetModT ty orig app inn mparam val' body')-- TypeModalT ty md inner -> TypeModalT ty md <$> (enterModality md $ nfTope inner)- LetT _ty _orig _mparam val body -> nfTope (substituteT val body)- TypeFunT{} -> panicImpossible "exposed function type in the tope layer"- TypeSigmaT{} -> panicImpossible "dependent sum type in the tope layer"- TypeIdT{} -> panicImpossible "identity type in the tope layer"- ReflT{} -> panicImpossible "refl in the tope layer"- IdJT{} -> panicImpossible "idJ eliminator in the tope layer"- TypeRestrictedT{} -> panicImpossible "extension types in the tope layer"-- -- A recOR/recBOT is a term-level eliminator, never a tope. It should have- -- been rejected before reaching here (see the RecOr case of 'typecheck'); as- -- a safety net for any other path, report a type error rather than panicking.- RecOrT{} -> issueTypeError $ TypeErrorOther "a recOR cannot appear in the tope layer"- RecBottomT{} -> issueTypeError $ TypeErrorOther "a recBOT cannot appear in the tope layer"---- | Compute a typed term to its NF.------ >>> unsafeTypeCheck' $ nfT "(\\ (x : Unit) -> x) unit"--- unit : Unit-nfT :: Eq var => TermT var -> TypeCheck var (TermT var)-nfT tt = performing (ActionNF tt) $ case tt of- -- universe constants- UniverseT{} -> pure tt- UniverseCubeT{} -> pure tt- UniverseTopeT{} -> pure tt-- -- cube layer constants- CubeUnitT{} -> pure tt- CubeUnitStarT{} -> pure tt- Cube2T{} -> pure tt- Cube2_0T{} -> pure tt- Cube2_1T{} -> pure tt- CubeIT{} -> pure tt- CubeI_0T{} -> pure tt- CubeI_1T{} -> pure tt-- -- cube layer with computation- CubeProductT{} -> nfTope tt- CubeFlipT{} -> nfTope tt- CubeUnflipT{} -> nfTope tt-- -- tope layer constants- TopeTopT{} -> pure tt- TopeBottomT{} -> pure tt-- -- tope layer with computation- TopeAndT{} -> nfTope tt- TopeOrT{} -> nfTope tt- TopeEQT{} -> nfTope tt- TopeLEQT{} -> nfTope tt- TopeInvT{} -> nfTope tt- TopeUninvT{} -> nfTope tt-- -- type layer constants- ReflT ty _x -> pure (ReflT ty Nothing)- RecBottomT{} -> pure tt- TypeUnitT{} -> pure tt- UnitT{} -> pure tt-- -- type ascriptions are ignored, since we already have a typechecked term- TypeAscT _ty term _ty' -> nfT term-- -- now we are in the type layer- _ -> do- typeOf tt >>= tryRestriction >>= \case- Just tt' -> nfT tt'- Nothing -> case tt of- -- a hole is opaque: it never reduces, it is already a normal form- HoleT{} -> pure tt- t@(Pure var) ->- valueOfVar var >>= \case- Nothing -> pure t- Just term -> nfT term-- TypeFunT ty orig md param mtope ret -> do- param' <- enterModality md $ nfT param- enterScope orig md param' $ do- mtope' <- traverse nfT mtope- maybe id localTope mtope' $- TypeFunT ty orig md param' mtope' <$> nfT ret- AppT ty f x ->- whnfT f >>= \case- LambdaT _ty _orig _arg body ->- nfT (substituteT x body)- f' -> typeOf f' >>= \case- TypeFunT _ty _orig md _param (Just tope) UniverseTopeT{} -> do- x' <- enterModality md $ nfT x- topeAndT- <$> pure (AppT ty f' x')- <*> nfT (substituteT x' tope)- _ -> AppT ty <$> nfT f' <*> nfT x- LetT _ty _orig _mparam val body ->- nfT (substituteT val body)- LetModT ty orig app inn mparam val body -> do- (enterModality app $ whnfT val) >>= \case- ModAppT _ md t | md == inn -> do- val' <- enterModality md $ nfT t- nfT (substituteT val' body)- b' | isRA inn -> do- bty <- typeOf b' >>= \case- TypeModalT _ _ t -> pure t- _ -> panicImpossible "not modal in letmod"- nfT (substituteT (modExtractT bty app inn b') body)- b' -> do- bty <- typeOf b' >>= \case- TypeModalT _ _ t -> pure t- _ -> panicImpossible "not modal in letmod"- val' <- enterModality app $ nfT b'- body' <- enterScope orig (comp app inn) bty $ nfT body- pure (LetModT ty orig app inn mparam val' body')- LambdaT ty orig _mparam body -> do- case stripTypeRestrictions (infoType ty) of- TypeFunT _ty _orig md param mtope _ret -> do- param' <- enterModality md $ nfT param- enterScope orig md param' $ do- mtope' <- traverse nfT mtope- maybe id localTope mtope' $- LambdaT ty orig (Just (md, param', mtope')) <$> nfT body- _ -> panicImpossible "lambda with a non-function type"--- TypeSigmaT ty orig md a b -> do- a' <- enterModality md $ nfT a- enterScope orig md a' $ do- TypeSigmaT ty orig md a' <$> nfT b- PairT ty l r -> PairT ty <$> nfT l <*> nfT r- FirstT ty t ->- whnfT t >>= \case- PairT _ l _r -> nfT l- t' -> FirstT ty <$> nfT t'- SecondT ty t ->- whnfT t >>= \case- PairT _ _l r -> nfT r- t' -> SecondT ty <$> nfT t'-- TypeIdT ty x _tA y -> TypeIdT ty <$> nfT x <*> pure Nothing <*> nfT y- IdJT ty tA a tC d x p ->- whnfT p >>= \case- ReflT{} -> nfT d- p' -> IdJT ty <$> nfT tA <*> nfT a <*> nfT tC <*> nfT d <*> nfT x <*> nfT p'-- RecOrT _ty rs -> do- let go [] = pure Nothing- go ((tope, tt') : rs') = do- checkTope tope >>= \case- True -> pure (Just tt')- False -> go rs'- go rs >>= \case- Just tt' -> nfT tt'- Nothing- | [tt'] <- nubTermT (map snd rs) -> nfT tt'- | otherwise -> pure tt- TypeModalT ty md b -> do- b' <- enterModality md $ nfT b- pure (TypeModalT ty md b')- ModAppT ty md b -> do- (enterModality md $ whnfT b) >>= \case- ModExtractT _ app inn t | inn == md -> enterModality (comp app inn) $ nfT t- b' -> ModAppT ty md <$> (enterModality md $ nfT b')- ModExtractT ty app inn b -> do- (enterModality app $ whnfT b) >>= \case- ModAppT _ md t | inn == md -> enterModality (comp app inn) $ nfT t- b' -> ModExtractT ty app inn <$> (enterModality app $ nfT b') - TypeRestrictedT ty type_ rs -> do- rs' <- forM rs $ \(tope, term) -> do- nfTope tope >>= \case- TopeBottomT{} -> pure Nothing- tope' -> do- term' <- localTope tope' $- nfT term- return (Just (tope', term'))- case catMaybes rs' of- [] -> nfT type_- rs'' -> TypeRestrictedT ty <$> nfT type_ <*> pure rs''---- | Look up a variable and project one field of its 'VarInfo'; the shared--- shape of the per-variable accessors below.-infoOfVar :: Eq var => (VarInfo var -> a) -> var -> TypeCheck var a-infoOfVar f x = asks (lookupVarInfo x) >>= \case- Nothing -> issueTypeError $ TypeErrorUndefined x- Just info -> return (f info)--checkDefinedVar :: VarIdent -> TypeCheck VarIdent ()-checkDefinedVar = infoOfVar (const ())--valueOfVar :: Eq var => var -> TypeCheck var (Maybe (TermT var))-valueOfVar = infoOfVar varValue--typeOfVar :: Eq var => var -> TypeCheck var (TermT var)-typeOfVar = infoOfVar varType--modalityOfVar :: Eq var => var -> TypeCheck var (TModality)-modalityOfVar = infoOfVar varModality--locksOfVar :: Eq var => var -> TypeCheck var (TModality)-locksOfVar = infoOfVar modAccum--isTopLevelVar :: Eq var => var -> TypeCheck var Bool-isTopLevelVar = infoOfVar varIsTopLevel--typeOfUncomputed :: Eq var => TermT var -> TypeCheck var (TermT var)-typeOfUncomputed = \case- Pure x -> typeOfVar x- Free (AnnF TypeInfo{..} _) -> pure infoType--typeOf :: Eq var => TermT var -> TypeCheck var (TermT var)-typeOf t = typeOfUncomputed t >>= whnfT--unifyTopes :: Eq var => TermT var -> TermT var -> TypeCheck var ()-unifyTopes l r = do- equiv <- (&&)- <$> [plainTope l] `entailM` r- <*> [plainTope r] `entailM` l- unless equiv $- issueTypeError (TypeErrorTopesNotEquivalent l r)--inAllSubContexts :: Eq var => TypeCheck var () -> TypeCheck var () -> TypeCheck var ()-inAllSubContexts handleSingle tc = do- topeSubContexts <- asks localTopesNFUnion- case topeSubContexts of- [] -> panicImpossible "empty set of alternative contexts"- [_] -> handleSingle- _:_:_ -> do- forM_ topeSubContexts $ \topes' -> do- withRefreshedTopes (\Context{..} -> Context- { localTopes = topes'- , localTopesNF = topes'- , localTopesNFUnion = [topes']- , .. }) $- tc--unify :: Eq var => Maybe (TermT var) -> TermT var -> TermT var -> TypeCheck var ()-unify mterm expected actual = performUnification `catchError` \typeError -> do- inAllSubContexts (throwError typeError) performUnification- where- performUnification = unifyInCurrentContext mterm expected actual--unifyViaDecompose :: Eq var => TermT var -> TermT var -> TypeCheck var ()-unifyViaDecompose expected actual | expected == actual = return ()-unifyViaDecompose (AppT _ f x) (AppT _ g y) = do- unify Nothing f g- setVariance Invariant $ unify Nothing x y-unifyViaDecompose _ _ = issueTypeError (TypeErrorOther "cannot decompose")--unifyInCurrentContext :: Eq var => Maybe (TermT var) -> TermT var -> TermT var -> TypeCheck var ()-unifyInCurrentContext mterm expected actual = performing action $ do- inBottom <- contextEntailsBottom- unless inBottom $- unifyViaDecompose expected actual `catchError` \_ -> do -- NOTE: this gives a small, but noticeable speedup- expectedVal <- whnfT expected- actualVal <- whnfT actual- mea <- asks covariance >>= \case- Covariant -> Just <$> etaMatch mterm expectedVal actualVal- Contravariant -> Just . swap <$> etaMatch mterm actualVal expectedVal- Invariant -> traceTypeCheck Debug "invariant" $ do- -- FIXME: inefficient- traceTypeCheck Debug "invariant->covariant" $- setVariance Covariant $ unifyInCurrentContext mterm expectedVal actualVal- traceTypeCheck Debug "invariant->contravariant" $- setVariance Contravariant $ unifyInCurrentContext mterm expectedVal actualVal- return Nothing- case mea of- Nothing -> return ()- -- A hole (lenient mode) stands for a term of the expected type, so it- -- unifies with anything; accept it instead of falling through to the- -- dispatch below (which would panic on an unexpected term).- Just (expected', actual') | isHoleT expected' || isHoleT actual' -> return ()- Just (expected', actual') ->- unless (expected' == actual') $ do -- NOTE: this gives a small, but noticeable speedup- case actual' of- RecBottomT{} -> return ()- RecOrT _ty rs' ->- case expected' of- RecOrT _ty rs -> sequence_ $- checkCoherence <$> rs <*> rs'- _ -> do- forM_ rs' $ \(tope, term) ->- localTope tope $- unifyTerms expected' term- _ -> typeOf expected' >>= typeOf >>= \case- UniverseCubeT{} -> contextEntails (topeEQT expected' actual')- _ -> do- -- A hole stands for a term of the expected type, so a- -- unification that would otherwise fail is deferred when either- -- side still contains an (unfilled) hole — including one nested- -- in a larger term, e.g. @f ?@ checked against an extension-type- -- boundary. The hole may also sit in the tope context rather- -- than the terms: a hole standing for a whole shape point makes- -- the enclosing 'recOR' split over hole-dependent faces, and a- -- branch reduction can drop the hole from the terms while the- -- assumed face (e.g. @π₁ ? ≤ π₂ ?@) still mentions it. Such a- -- branch is only entered because the hole is unfilled, so a- -- mismatch under it is deferred too. 'structuralHoleUnify' turns- -- this off, keeping a structural mismatch around a hole an- -- error. Lazy: only runs on the failure path.- defer <- asks deferHoleMismatches- topeContextHasHole <- asks (any (containsHole . tTope) . localTopes)- let def = unless (expected' == actual') err- holePresent = defer &&- (containsHole expected' || containsHole actual' || topeContextHasHole)- err- | holePresent = return ()- | otherwise =- case mterm of- Nothing -> issueTypeError (TypeErrorUnifyTerms expected' actual')- Just term -> issueTypeError (TypeErrorUnify term expected' actual')- errS- | holePresent = return ()- | otherwise = do- let expectedS = S <$> expected'- actualS = S <$> actual'- case mterm of- Nothing -> issueTypeError (TypeErrorUnifyTerms expectedS actualS)- Just term -> issueTypeError (TypeErrorUnify (S <$> term) expectedS actualS)- case expected' of- Pure{} -> def-- UniverseT{} -> def- UniverseCubeT{} -> def- UniverseTopeT{} -> def-- TypeUnitT{} -> def- UnitT{} -> return () -- Unit always unifies!-- CubeUnitT{} -> def- CubeUnitStarT{} -> def- Cube2T{} -> def- Cube2_0T{} -> def- Cube2_1T{} -> def- CubeIT{} -> def- CubeI_0T{} -> def- CubeI_1T{} -> def- CubeProductT _ l r ->- case actual' of- CubeProductT _ l' r' -> do- unifyTerms l l'- unifyTerms r r'- _ -> err-- PairT _ty l r ->- case actual' of- PairT _ty' l' r' -> do- unifyTerms l l'- unifyTerms r r'-- -- one part of eta-expansion for pairs- -- FIXME: add symmetric version!- _ -> err-- FirstT _ty t ->- case actual' of- FirstT _ty' t' -> unifyTerms t t'- _ -> err-- SecondT _ty t ->- case actual' of- SecondT _ty' t' -> unifyTerms t t'- _ -> err-- TopeTopT{} -> unifyTopes expected' actual'- TopeBottomT{} -> unifyTopes expected' actual'- TopeEQT{} -> unifyTopes expected' actual'- TopeLEQT{} -> unifyTopes expected' actual'- TopeAndT{} -> unifyTopes expected' actual'- TopeOrT{} -> unifyTopes expected' actual'-- RecBottomT{} -> return () -- unifies with anything- RecOrT _ty rs ->- case actual' of- -- ----------------------------------------------- -- IMPORTANT: this pattern matching is redundant,- -- but it is not obvious, so- -- take care when refactoring!- -- ----------------------------------------------- -- RecOrT _ty rs' -> sequence_ $- -- checkCoherence <$> rs <*> rs'- -- ----------------------------------------------- _ -> do- forM_ rs $ \(tope, term) ->- localTope tope $- unifyTerms term actual'-- TypeFunT _ty _orig md cube mtope ret ->- case actual' of- TypeFunT _ty' orig' md' cube' mtope' ret' -> do- when (md /= md') $- issueTypeError (TypeErrorOther $ "modality mismatch in function type: expected " <> show md <> " but got " <> show md')- switchVariance $ -- unifying in the negative position!- unifyTerms cube cube' -- FIXME: unifyCubes- enterScope orig' md cube' $ do- -- The tope checks below are subtyping checks with a fixed- -- direction relative to (subtype, supertype). Which side is- -- the subtype depends on the ambient variance: under- -- Covariant the actual type must be a subtype of the- -- expected one; under Contravariant (inside a domain) the- -- roles are reversed. Invariant is normally handled- -- upstream by running both directions; it is handled here- -- as well for safety.- variance <- asks covariance- case ret' of- UniverseTopeT{} -> do- -- This is the case for tope families (shapes)- --- -- (Λ → TOPE) <: (Δ → TOPE)- -- since if φ : Λ → TOPE- -- then φ ⊢ Δ- --- -- we DO NOT take tope context Φ into account!- expectedTopeNF <- fromMaybe topeTopT <$> traverse nfT mtope- actualTopeNF <- fromMaybe topeTopT <$> traverse nfT mtope'- let subEntailsSuper subNF superNF = do- entails <- [plainTope subNF] `entailM` superNF- unless (entails || containsHole subNF || containsHole superNF) $- issueTypeError (TypeErrorTopeNotSatisfied [subNF] superNF)- case variance of- Covariant -> subEntailsSuper actualTopeNF expectedTopeNF- Contravariant -> subEntailsSuper expectedTopeNF actualTopeNF- Invariant -> do- subEntailsSuper actualTopeNF expectedTopeNF- subEntailsSuper expectedTopeNF actualTopeNF- _ -> do- -- this is the case for Π-types and extension types- --- -- Ξ | Φ | Γ ⊢ {t : I | φ} → A t <: {s : J | ψ} → B s- -- when- -- Ξ | Φ, ψ ⊢ φ- expectedTopeNF <- fromMaybe topeTopT <$> traverse nfT mtope- actualTopeNF <- fromMaybe topeTopT <$> traverse nfT mtope'- let superEntailsSub superNF subNF =- localTope superNF $- contextEntails subNF- case variance of- Covariant -> superEntailsSub expectedTopeNF actualTopeNF- Contravariant -> superEntailsSub actualTopeNF expectedTopeNF- Invariant -> do- superEntailsSub expectedTopeNF actualTopeNF- superEntailsSub actualTopeNF expectedTopeNF- case mterm of- Nothing -> unifyTerms ret ret'- Just term -> unifyTypes (appT ret' (S <$> term) (Pure Z)) ret ret'- _ -> err-- TypeSigmaT _ty _orig md a b ->- case actual' of- TypeSigmaT _ty' orig' md' a' b' -> do- when (md /= md') $- issueTypeError (TypeErrorOther $ "modality mismatch in sigma type: expected " <> show md <> " but got " <> show md')- unify Nothing a a'- enterScope orig' md a' $ unify Nothing b b'- _ -> err-- TypeIdT _ty x tA y ->- case actual' of- TypeIdT _ty' x' tA' y' -> do- -- The underlying types must be compared: without this- -- check the routine equates identity types over- -- different types whenever the endpoints unify,- -- accepting e.g. a free homotopy (a path in the type- -- of functions) where an endpoint-fixing one (a path- -- in a hom-type) is expected. Compared invariantly:- -- subtyping between the underlying types must not- -- leak into equality of identity types over them.- mapM_ (\(t1, t2) -> setVariance Invariant (unify Nothing t1 t2))- ((,) <$> tA <*> tA')- unify Nothing x x'- unify Nothing y y'- _ -> err-- AppT _ty f x ->- case actual' of- AppT _ty' f' x' -> do- unify Nothing f f'- setVariance Invariant $- unify Nothing x x'- _ -> err-- LambdaT ty _orig _mparam body ->- case stripTypeRestrictions (infoType ty) of- TypeFunT _ty _origF md param mtope _ret ->- case actual' of- LambdaT ty' orig' _mparam' body' ->- case stripTypeRestrictions (infoType ty') of- TypeFunT _ty' _origF' md' param' mtope' _ret' -> do- when (md /= md') $- issueTypeError (TypeErrorOther $ "modality mismatch in lambda: expected " <> show md <> " but got " <> show md')- unify Nothing param param' -- we (should) have already checked this in types!- enterScope orig' md param $ do- case (mtope, mtope') of- (Just tope, Just tope') -> do- unify Nothing tope tope' -- we (should) have already checked this in types!- localTope tope $ unify Nothing body body'- (Nothing, Nothing) -> do- unify Nothing body body'- _ -> errS- _ -> err- _ -> err- _ -> err-- LetT{} -> panicImpossible "let at the root of WHNF"- LetModT _ orig app inn _ val body ->- case actual' of- LetModT _ _ app' inn' _ val' body'- | app == app', inn == inn' -> do- unify Nothing val val'- bty <- typeOf val >>= \case- TypeModalT _ _ t -> pure t- _ -> panicImpossible "not modal in letmod"- enterScope orig (comp app inn) bty $- unify Nothing body body'- _ -> err-- ReflT ty _x | TypeIdT _ty x _tA y <- infoType ty ->- case actual' of- ReflT ty' _x' | TypeIdT _ty' x' _tA' y' <- infoType ty' -> do- -- unify Nothing tA tA' -- TODO: do we need this check?- unify Nothing x x'- unify Nothing y y'- _ -> err- ReflT{} -> panicImpossible "refl with a non-identity type!"-- IdJT _ty a b c d e f ->- case actual' of- IdJT _ty' a' b' c' d' e' f' -> do- unify Nothing a a'- unify Nothing b b'- unify Nothing c c'- unify Nothing d d'- unify Nothing e e'- unify Nothing f f'- _ -> err-- TypeAscT{} -> panicImpossible "type ascription at the root of WHNF"-- TypeRestrictedT _ty ty rs ->- case actual' of- TypeRestrictedT _ty' ty' rs' -> do- unify mterm ty ty'- -- The faces of the supertype must be covered by the faces- -- of the subtype (the subtype is at least as specified),- -- with the boundary terms agreeing on overlaps. Which side- -- is the subtype depends on the ambient variance.- variance <- asks covariance- let subCoversSuper subRs superRs = sequence_- [ localTope tope $ do- -- FIXME: can do less entails checks?- contextEntails (foldr topeOrT topeBottomT (map fst subRs))- forM_ subRs $ \(tope', term') -> do- localTope tope' $- unify Nothing term term'- | (tope, term) <- superRs- ]- case variance of- Covariant -> subCoversSuper rs' rs- Contravariant -> subCoversSuper rs rs'- Invariant -> do- subCoversSuper rs' rs- subCoversSuper rs rs'- _ -> err -- FIXME: need better unification for restrictions- TypeModalT _ty m ty ->- case actual' of- TypeModalT _ty' m' ty' -> do- when (m' /= m) $ err- enterModality m $ unify Nothing ty ty'- _ -> err- ModAppT _ty m ty ->- case actual' of- ModAppT _ty' m' ty' -> do- when (m' /= m) $ err- enterModality m $ unify Nothing ty ty'- _ -> err- ModExtractT _ty app inn te ->- case actual' of- ModExtractT _ty' app' inn' te' -> do- when (app' /= app) $ err- when (inn' /= inn) $ err- enterModality app $ unify Nothing te te'- _ -> err- -- defensive: a hole nested anywhere also defers here rather- -- than panicking on an otherwise unexpected shape- _ | holePresent -> return ()- _ -> panicImpossible "unexpected term in UNIFY"-- where- action = case mterm of- Nothing -> ActionUnifyTerms expected actual- Just term -> ActionUnify term expected actual--unifyTypes :: Eq var => TermT var -> TermT var -> TermT var -> TypeCheck var ()-unifyTypes = unify . Just--unifyTerms :: Eq var => TermT var -> TermT var -> TypeCheck var ()-unifyTerms = unify Nothing--localTope :: Eq var => TermT var -> TypeCheck var a -> TypeCheck var a-localTope tope tc = do- Context{..} <- ask- tope' <- nfTope tope- let modalTope' = plainTope tope'- -- A small optimisation to help unify terms faster- let refine = case tope' of- TopeEQT _ x y | x == y -> const tc -- no new information added!- _ | modalTope' `elem` localTopesNF -> const tc -- no new information added!- | otherwise -> id- refine $ do- entailsBottom <- (modalTope' : localTopesNF) `entailM` topeBottomT- withRefreshedTopes (f modalTope' entailsBottom) tc- where- f tope' entailsBottom Context{..} = Context- { localTopes = plainTope tope : localTopes- , localTopesNF = tope' : localTopesNF- , localTopesNFUnion = map nubTermT- [ new <> old- | new <- simplifyLHSwithDisjunctions [tope']- , old <- localTopesNFUnion ]- , localTopesEntailBottom = Just entailsBottom- , .. }--universeT :: TermT var-universeT = iterate f (panicImpossible msg) !! 30- where- msg = "going too high up the universe levels"- f t = UniverseT TypeInfo- { infoType = t- , infoNF = Just universeT- , infoWHNF = Just universeT }--cubeT :: TermT var-cubeT = UniverseCubeT TypeInfo- { infoType = universeT- , infoNF = Just cubeT- , infoWHNF = Just cubeT }--topeT :: TermT var-topeT = UniverseTopeT TypeInfo- { infoType = universeT- , infoNF = Just topeT- , infoWHNF = Just topeT }--topeEQT :: TermT var -> TermT var -> TermT var-topeEQT l r = TopeEQT info l r- where- info = TypeInfo- { infoType = topeT- , infoNF = Nothing- , infoWHNF = Nothing- }--topeLEQT :: TermT var -> TermT var -> TermT var-topeLEQT l r = TopeLEQT info l r- where- info = TypeInfo- { infoType = topeT- , infoNF = Nothing- , infoWHNF = Nothing- }--topeOrT :: TermT var -> TermT var -> TermT var-topeOrT l r = TopeOrT info l r- where- info = TypeInfo- { infoType = topeT- , infoNF = Nothing- , infoWHNF = Nothing- }--topeAndT :: TermT var -> TermT var -> TermT var-topeAndT l r = TopeAndT info l r- where- info = TypeInfo- { infoType = topeT- , infoNF = Nothing- , infoWHNF = Nothing- }--cubeProductT :: TermT var -> TermT var -> TermT var-cubeProductT l r = t- where- t = CubeProductT info l r- info = TypeInfo- { infoType = cubeT- , infoNF = Nothing- , infoWHNF = Nothing- }--cubeUnitT :: TermT var-cubeUnitT = CubeUnitT TypeInfo- { infoType = cubeT- , infoNF = Just cubeUnitT- , infoWHNF = Just cubeUnitT }--cubeUnitStarT :: TermT var-cubeUnitStarT = CubeUnitStarT TypeInfo- { infoType = cubeUnitT- , infoNF = Just cubeUnitStarT- , infoWHNF = Just cubeUnitStarT }--typeUnitT :: TermT var-typeUnitT = TypeUnitT TypeInfo- { infoType = universeT- , infoNF = Just typeUnitT- , infoWHNF = Just typeUnitT }--unitT :: TermT var-unitT = UnitT TypeInfo- { infoType = typeUnitT- , infoNF = Just unitT- , infoWHNF = Just unitT }--cube2T :: TermT var-cube2T = Cube2T TypeInfo- { infoType = cubeT- , infoNF = Just cube2T- , infoWHNF = Just cube2T }--cube2_0T :: TermT var-cube2_0T = Cube2_0T TypeInfo- { infoType = cube2T- , infoNF = Just cube2_0T- , infoWHNF = Just cube2_0T }--cube2_1T :: TermT var-cube2_1T = Cube2_1T TypeInfo- { infoType = cube2T- , infoNF = Just cube2_1T- , infoWHNF = Just cube2_1T }--cubeIT :: TermT var-cubeIT = CubeIT TypeInfo- { infoType = cubeT- , infoNF = Just cubeIT- , infoWHNF = Just cubeIT }--cubeI_0T :: TermT var-cubeI_0T = CubeI_0T TypeInfo- { infoType = cubeIT- , infoNF = Just cubeI_0T- , infoWHNF = Just cubeI_0T }--cubeI_1T :: TermT var-cubeI_1T = CubeI_1T TypeInfo- { infoType = cubeIT- , infoNF = Just cubeI_1T- , infoWHNF = Just cubeI_1T }--cubeFlipT :: TermT var -> TermT var -> TermT var-cubeFlipT cubeTy t = CubeFlipT info t- where- info = TypeInfo- { infoType = typeModalT cubeT Op cubeTy- , infoNF = Nothing- , infoWHNF = Nothing- }--cubeUnflipT :: TermT var -> TermT var -> TermT var-cubeUnflipT cubeTy t = CubeUnflipT info t- where- info = TypeInfo- { infoType = cubeTy- , infoNF = Nothing- , infoWHNF = Nothing- }--topeInvT :: TermT var -> TermT var-topeInvT t = TopeInvT info t- where- info = TypeInfo- { infoType = typeModalT universeT Op topeT- , infoNF = Nothing- , infoWHNF = Nothing- }--topeUninvT :: TermT var -> TermT var-topeUninvT t = TopeUninvT info t- where- info = TypeInfo- { infoType = topeT- , infoNF = Nothing- , infoWHNF = Nothing- }--topeTopT :: TermT var-topeTopT = TopeTopT TypeInfo- { infoType = topeT- , infoNF = Just topeTopT- , infoWHNF = Just topeTopT }--topeBottomT :: TermT var-topeBottomT = TopeBottomT TypeInfo- { infoType = topeT- , infoNF = Just topeBottomT- , infoWHNF = Just topeBottomT }--recBottomT :: TermT var-recBottomT = RecBottomT TypeInfo- { infoType = recBottomT- , infoNF = Just recBottomT- , infoWHNF = Just recBottomT }--typeRestrictedT :: TermT var -> [(TermT var, TermT var)] -> TermT var-typeRestrictedT ty rs = t- where- t = TypeRestrictedT info ty rs- info = TypeInfo- { infoType = universeT- , infoNF = Nothing- , infoWHNF = Nothing- }--lambdaT- :: TermT var- -> Binder- -> Maybe (TModality, TermT var, Maybe (Scope TermT var))- -> Scope TermT var- -> TermT var-lambdaT ty orig mparam body = t- where- t = LambdaT info orig mparam body- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Just t- }---letT :: TermT var -> Binder -> Maybe (TermT var) -> TermT var -> Scope TermT var -> TermT var-letT ty orig mparam val body = t- where- t = LetT info orig mparam val body- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--letModT :: TermT var -> Binder -> TModality -> TModality -> Maybe (TermT var) -> TermT var -> Scope TermT var -> TermT var-letModT ty orig app inn mparam val body = t- where- t = LetModT info orig app inn mparam val body- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--appT :: TermT var -> TermT var -> TermT var -> TermT var-appT ty f x = t- where- t = AppT info f x- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--pairT :: TermT var -> TermT var -> TermT var -> TermT var-pairT ty l r = t- where- t = PairT info l r- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Just t- }--firstT :: TermT var -> TermT var -> TermT var-firstT ty arg = t- where- t = FirstT info arg- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--secondT :: TermT var -> TermT var -> TermT var-secondT ty arg = t- where- t = SecondT info arg- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--reflT- :: TermT var- -> Maybe (TermT var, Maybe (TermT var))- -> TermT var-reflT ty mx = t- where- t = ReflT info mx- info = TypeInfo- { infoType = ty- , infoNF = Just (ReflT info Nothing)- , infoWHNF = Just (ReflT info Nothing)- }--typeFunT- :: Binder- -> TModality- -> TermT var- -> Maybe (Scope TermT var)- -> Scope TermT var- -> TermT var-typeFunT orig md cube mtope ret = t- where- t = TypeFunT info orig md cube mtope ret- info = TypeInfo- { infoType = universeT- , infoNF = Nothing- , infoWHNF = Just t- }--typeSigmaT- :: Binder- -> TModality- -> TermT var- -> Scope TermT var- -> TermT var-typeSigmaT orig md a b = t- where- t = TypeSigmaT info orig md a b- info = TypeInfo- { infoType = universeT- , infoNF = Nothing- , infoWHNF = Just t- }--recOrT- :: TermT var- -> [(TermT var, TermT var)]- -> TermT var-recOrT ty rs = t- where- t = RecOrT info rs- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--typeIdT :: TermT var -> Maybe (TermT var) -> TermT var -> TermT var-typeIdT x tA y = t- where- t = TypeIdT info x tA y- info = TypeInfo- { infoType = universeT- , infoNF = Nothing- , infoWHNF = Just t- }--idJT- :: TermT var- -> TermT var- -> TermT var- -> TermT var- -> TermT var- -> TermT var- -> TermT var- -> TermT var-idJT ty tA a tC d x p = t- where- t = IdJT info tA a tC d x p- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--typeAscT :: TermT var -> TermT var -> TermT var-typeAscT x ty = t- where- t = TypeAscT info x ty- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--typeModalT :: TermT var -> TModality -> TermT var -> TermT var-typeModalT ty md te = t- where- t = TypeModalT info md te- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--modAppT :: TermT var -> TModality -> TermT var -> TermT var-modAppT ty md term = t- where- t = ModAppT info md term- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }--modExtractT :: TermT var -> TModality -> TModality -> TermT var -> TermT var-modExtractT ty app inn term = t- where- t = ModExtractT info app inn term- info = TypeInfo- { infoType = ty- , infoNF = Nothing- , infoWHNF = Nothing- }---- | Check a @recOR@ in checking position against a known expected type: each--- branch is checked against that type under its guard tope, followed by the--- usual pairwise coherence and the coverage obligation. Passing a /restricted/--- type pushes the boundary into every branch, so a branch hole reports the--- faces it must meet (under its tope) instead of the bare underlying type.------ Under a branch guard, the faces belonging to the other (mutually exclusive)--- branches become disjoint from this branch's tope context, so they are pruned--- by 'pruneVacuousFaces' before the branch is checked. Otherwise a face like--- @i ≡ 1₂@ would be reported as vacuous while checking the @i ≡ 0₂@ branch--- against @A [i ≡ 0₂ ↦ a, i ≡ 1₂ ↦ b]@ — which arises in particular with--- flat-discrete cube variables, where @i ≡ 0₂ ∧ i ≡ 1₂@ is provably ⊥.-checkRecOrAgainst :: Eq var => TermT var -> [(Term var, Term var)] -> TypeCheck var (TermT var)-checkRecOrAgainst expected rs = do- rs' <- forM rs $ \(tope, rterm) -> do- tope' <- typecheck tope topeT- checkTopeAgainstContext "recOR branch guard" tope'- localTope tope' $ do- expected' <- pruneVacuousFaces expected- rterm' <- typecheck rterm expected'- return (tope', rterm')- sequence_ [ checkCoherence l r | l:rs'' <- tails rs', r <- rs'' ]- contextEntailsUnion (map fst rs')- return (recOrT expected rs')---- | Drop the restriction faces of an extension type that are vacuous in the--- current tope context (their overlap with the context is the empty tope ⊥). A--- face mentioning an unfilled hole cannot be decided, so it is kept. Non-extension--- types are returned unchanged. Used when descending into a recOR branch, where--- the sibling branches' faces are disjoint from the branch guard.-pruneVacuousFaces :: Eq var => TermT var -> TypeCheck var (TermT var)-pruneVacuousFaces (TypeRestrictedT _info ty rs) = do- contextTopes <- asks localTopesNF- kept <- fmap concat $ forM rs $ \face@(tope, _) -> do- vacuous <- if containsHole tope- then return False- else (plainTope tope : contextTopes) `entailM` topeBottomT- return [ face | not vacuous ]- return $ case kept of- [] -> ty- _ -> typeRestrictedT ty kept-pruneVacuousFaces ty = return ty--typecheck :: Eq var => Term var -> TermT var -> TypeCheck var (TermT var)-typecheck term ty = performing (ActionTypeCheck term ty) $ case term of- -- A hole is checked against a known type (this is checking position): in- -- strict mode it is reported as an unsolved hole; in lenient mode its goal- -- and context are recorded and it is treated as inhabiting the expected type.- Hole mname -> do- reject <- asks holesAreErrors- if reject- then issueTypeError (TypeErrorUnsolvedHole mname ty)- else do- recordHole mname ty- return (HoleT TypeInfo{ infoType = ty, infoWHNF = Nothing, infoNF = Nothing } mname)-- _ -> whnfT ty >>= \case-- RecBottomT{} -> do- -- Even under an absurd tope context (where the expected type collapses to- -- recBOT), the term must still be well-formed in its own right, so that- -- ill-typed bodies are not silently admitted under a false hypothesis. We- -- synthesise its type, discard the result, and keep the recBOT elaboration.- _ <- infer term- return recBottomT-- tr@(TypeRestrictedT _ty ty' rs) -> case term of- -- A recOR against a restricted type: push the restriction into each branch- -- instead of stripping it first, so a branch hole reports the boundary- -- faces it must satisfy under its guard tope, rather than the bare- -- underlying type. Concrete branches still meet the faces, which are- -- checked on each branch's overlap with them (see the general case below).- RecOr branches -> checkRecOrAgainst tr branches- _ -> do- term' <- typecheck term ty'- -- NOTE: restriction faces need not be contained in the local tope context.- -- Each face is checked only on its overlap with the context below, so an- -- overhanging face is harmless (we only hint); a face disjoint from the context- -- is vacuous, however, and is reported as an error by checkTopeAgainstContext.- forM_ rs $ \(tope, rterm) -> do- checkTopeAgainstContext "restriction face" tope- localTope tope $- unifyTerms rterm term'- return term' -- FIXME: correct?-- ty' -> case term of- Lambda orig mparam body ->- case ty' of- TypeFunT _ty _orig' md' param' mtope' ret -> do- case mparam of- Nothing -> return ()- Just (md, param, Nothing) -> do- when (md /= md') $- issueTypeError (TypeErrorModalityMismatch md' md term)- (paramType, mtope) <- do- paramType <- enterModality md $ infer param- typeOf paramType >>= \case- -- an argument can be a shape- TypeFunT _ty _orig _md cube _mtope UniverseTopeT{} -> do- mapM_ checkNameShadowing (binderLeaves orig)- enterScope orig md cube $ do- let tope' = appT topeT (S <$> paramType) (Pure Z) -- eta expand ty'- return (cube, Just tope')- _kind -> return (paramType, Nothing)- unifyTerms param' paramType- mapM_ checkNameShadowing (binderLeaves orig)- enterScope orig md param' $ do- mapM_ (unifyTerms (fromMaybe topeTopT mtope')) mtope- Just (md, param, mtope) -> do- when (md /= md') $- issueTypeError (TypeErrorModalityMismatch md' md term)- param'' <- enterModality md $ typecheck param =<< typeOf param'- unifyTerms param' param''- mapM_ checkNameShadowing (binderLeaves orig)- enterScope orig md param' $ do- mtope'' <- typecheck (fromMaybe TopeTop mtope) topeT- unifyTerms (fromMaybe topeTopT mtope') mtope''-- mapM_ checkNameShadowing (binderLeaves orig)- enterScope orig md' param' $ do- maybe id localTope mtope' $ do- body' <- typecheck body ret- return (lambdaT ty' orig (Just (md', param', mtope')) body')-- _ -> issueTypeError $ TypeErrorUnexpectedLambda term ty- Let orig annot val body -> do- val' <- performing (ActionCheckLetValue (binderName orig)) $ case annot of- Nothing -> infer val- Just bindType -> do- bindType' <- typecheck bindType universeT- typecheck val bindType'- bindTy <- typeOf val'- body' <- enterScopeWithBind orig Id bindTy val' $ do- typecheck body (S <$> ty')- return (letT ty' orig (Just bindTy) val' body')- LetMod orig app inn annot val body -> do- val' <- performing (ActionCheckLetValue (binderName orig)) $ case annot of- Nothing -> enterModality app $ infer val- Just bindType -> do- bindType' <- infer bindType- bindUniv <- typeOf bindType'- enterModality app $ typecheck val (typeModalT bindUniv inn bindType')- bindTy <- typeOf val' >>= \case- o@(TypeModalT _ty md t) ->- if md == inn then- return t- else- issueTypeError $ TypeErrorNotModal (untyped o) inn val'- o -> issueTypeError $ TypeErrorNotModal (untyped o) inn val'- bindVal <- whnfT val' >>= \case- ModAppT _ty _m t -> pure (Just t)- o | isRA inn -> pure (Just (modExtractT bindTy app inn o))- _ -> pure Nothing- body' <- enterScopeMaybe orig (comp app inn) bindTy bindVal $ do- typecheck body (S <$> ty')- return (letModT ty' orig app inn (Just bindTy) val' body')- Pair l r ->- case ty' of- CubeProductT _ty a b -> do- l' <- typecheck l a- r' <- typecheck r b- return (pairT ty' l' r')- TypeSigmaT _ty _orig md a b -> do- l' <- enterModality md $ typecheck l a- r' <- typecheck r (substituteT l' b)- return (pairT ty' l' r')- _ -> issueTypeError $ TypeErrorUnexpectedPair term ty-- Refl mx ->- case ty' of- TypeIdT _ty y _tA z -> do- tA <- typeOf y- forM_ mx $ \(x, mxty) -> do- forM_ mxty $ \xty -> do- xty' <- typecheck xty universeT- unifyTerms tA xty'- x' <- typecheck x tA- unifyTerms x' y >> unifyTerms y x'- unifyTerms x' z >> unifyTerms z x'- when (isNothing mx) $- unifyTerms y z >> unifyTerms z y- return (reflT ty' (Just (y, Just tA)))- _ -> issueTypeError $ TypeErrorUnexpectedRefl term ty- ModExtract{} -> panicImpossible "extract is an internal term and cannot be typechecked"- ModApp md body -> case ty' of- TypeModalT _ty md' tpe -> do- when (md /= md') $ issueTypeError $- TypeErrorModalityMismatch md' md term- body' <- enterModality md $ typecheck body tpe- return $ modAppT ty' md body'- _ -> issueTypeError $ TypeErrorNotModal term md ty'-- -- In checking position the common type is already known, so we push it- -- into every branch instead of inferring each one and unifying. This is- -- what lets a bare hole branch (recOR(φ ↦ ?, …)) be checked against the- -- expected type and recorded, rather than hitting TypeErrorCannotInferHole- -- via the inference rule. The branch-guard, coherence, and coverage- -- obligations mirror the inference rule (see the RecOr case of 'infer').- -- A recOR is a term-level eliminator, not a tope; rejecting it when it is- -- checked against the tope universe (e.g. in another recOR's branch guard)- -- keeps it out of the tope layer, where it would otherwise hit a panic.- RecOr rs -> case ty' of- UniverseTopeT{} -> issueTypeError $- TypeErrorOther "a recOR cannot be used as a tope"- _ -> checkRecOrAgainst ty' rs- -- A neutral term is inferred, then its type unified with the expected- -- one. In lenient (hole-checking) mode a term that still carries an- -- unfilled hole is a work in progress, so a failure of that final- -- unification is tolerated: the holes recorded while inferring the term- -- stand (they were committed before this point), and we accept the term- -- rather than rejecting the whole sketch. The mismatch is typically- -- incidental to the missing pieces — e.g. an extension-type boundary face- -- that only fails to line up because an argument hole sits in the wrong- -- place (`f t` vs `x`), where neither side is itself a hole, so the- -- per-term deferral in 'unifyInCurrentContext' cannot see it. Strict mode- -- (the default, and CI) still rejects the mismatch.- _ -> do- term' <- infer term- inferredType <- typeOf term'- lenient <- not <$> asks holesAreErrors- if lenient && containsHole term'- then unifyTypes term' ty' inferredType `catchError` \_ -> return ()- else unifyTypes term' ty' inferredType- return term'--inferAs :: Eq var => TermT var -> Term var -> TypeCheck var (TermT var)-inferAs expectedKind term = do- term' <- infer term- ty <- typeOf term'- kind <- typeOf ty- unifyTypes ty expectedKind kind- return term'--infer :: Eq var => Term var -> TypeCheck var (TermT var)-infer tt = performing (ActionInfer tt) $ case tt of- Hole _mname -> issueTypeError (TypeErrorCannotInferHole tt)- Pure x -> do- topLevel <- isTopLevelVar x- unless topLevel $ do- varMod <- modalityOfVar x- locks <- locksOfVar x- when (not (coe varMod locks)) $ issueTypeError $ TypeErrorUnaccessibleVar x varMod locks- pure (Pure x)-- Universe -> pure universeT- UniverseCube -> pure cubeT- UniverseTope -> pure topeT-- CubeUnit -> pure cubeUnitT- CubeUnitStar -> pure cubeUnitStarT-- Cube2 -> pure cube2T- Cube2_0 -> pure cube2_0T- Cube2_1 -> pure cube2_1T-- CubeI -> pure cubeIT- CubeI_0 -> pure cubeI_0T- CubeI_1 -> pure cubeI_1T- CubeProduct l r -> do- l' <- typecheck l cubeT- r' <- typecheck r cubeT- return (cubeProductT l' r')-- CubeFlip t -> do- t' <- infer t- typeOf t' >>= \case- CubeIT{} -> pure $ cubeFlipT cubeIT t'- Cube2T{} -> pure $ cubeFlipT cube2T t'- ty -> do- tyStr <- ppTermInContext ty- issueTypeError $ TypeErrorOther $- "flip expects an interval cube (2 or 𝕀); got " <> tyStr- CubeUnflip t -> do- t' <- infer t- typeOf t' >>= \case- TypeModalT _ Op (CubeIT{}) -> pure $ cubeUnflipT cubeIT t'- TypeModalT _ Op (Cube2T{}) -> pure $ cubeUnflipT cube2T t'- ty -> do- tyStr <- ppTermInContext ty- issueTypeError $ TypeErrorOther $- "unflip expects an interval cube (2 or 𝕀) under _op; got " <> tyStr- Pair l r -> do- l' <- infer l- r' <- infer r- lt <- typeOf l'- rt <- typeOf r'- typeOf lt >>= \case- -- Γ ⊢ l ⇒ (I : CUBE)- -- Γ ⊢ r ⇒ (J : CUBE)- -- ———————————————————————————- -- Γ ⊢ (l, r) ⇒ (I × J : CUBE)- UniverseCubeT{} -> return (pairT (cubeProductT lt rt) l' r')- -- Γ ⊢ l ⇒ (A : U)- -- Γ ⊢ r ⇒ (B : U)- -- ———————————————————————————- -- Γ ⊢ (l, r) ⇒ (A × B : U) where A × B = Σ (_ : A), B- _ -> do- -- NOTE: infer as a non-dependent pair!- return (pairT (typeSigmaT (BinderVar Nothing) Id lt (S <$> rt)) l' r')-- First t -> do- t' <- infer t- fmap stripTypeRestrictions (typeOf t') >>= \case- RecBottomT{} -> pure recBottomT -- FIXME: is this ok?- TypeSigmaT _ty _orig _md lt _rt ->- return (firstT lt t')- CubeProductT _ty l _r ->- return (firstT l t')- ty -> issueTypeError $ TypeErrorNotPair t' ty-- Second t -> do- t' <- infer t- fmap stripTypeRestrictions (typeOf t') >>= \case- RecBottomT{} -> pure recBottomT -- FIXME: is this ok?- TypeSigmaT _ty _orig _md lt rt ->- return (secondT (substituteT (firstT lt t') rt) t')- CubeProductT _ty _l r ->- return (secondT r t')- ty -> issueTypeError $ TypeErrorNotPair t' ty-- TypeUnit -> pure typeUnitT- Unit -> pure unitT-- TopeTop -> pure topeTopT- TopeBottom -> pure topeBottomT-- TopeEQ l r -> do- l' <- inferAs cubeT l- lt <- typeOf l'- r' <- typecheck r lt- return (topeEQT l' r')-- TopeLEQ l r -> do- l' <- inferAs cubeT l- r' <- inferAs cubeT r- lTy <- typeOf l'- rTy <- typeOf r'- case (lTy, rTy) of- (Cube2T{}, Cube2T{}) -> return (topeLEQT l' r')- (CubeIT{}, CubeIT{}) -> return (topeLEQT l' r')- (CubeIT{}, Cube2T{}) -> do- r'' <- typecheck r cubeIT- return (topeLEQT l' r'')- (Cube2T{}, CubeIT{}) -> do- l'' <- typecheck l cubeIT- return (topeLEQT l'' r')- _ -> do- lStr <- ppTermInContext lTy- rStr <- ppTermInContext rTy- issueTypeError $ TypeErrorOther $- "the (t ≤ s) tope expects points in interval cubes (2 or 𝕀); got "- <> lStr <> " and " <> rStr-- TopeAnd l r -> do- l' <- typecheck l topeT- r' <- typecheck r topeT- return (topeAndT l' r')-- TopeOr l r -> do- l' <- typecheck l topeT- r' <- typecheck r topeT- return (topeOrT l' r')-- TopeInv t -> do- t' <- typecheck t topeT- return (topeInvT t')-- TopeUninv t -> do- t' <- typecheck t (typeModalT universeT Op topeT )- return (topeUninvT t')-- RecBottom -> do- contextEntails topeBottomT- return recBottomT-- -- Γ ⊢ t ⇒ (T : K)- -- Γ ⊢ K ≡ U- -- —————————————- -- Γ ⊢ t ⇒ T ⇐ U-- RecOr rs -> do- ttts <- forM rs $ \(tope, term) -> do- tope' <- typecheck tope topeT- -- NOTE: branch guards need not be contained in the context. recOR requires- -- only coverage (context |- OR(guards)), enforced by contextEntailsUnion below;- -- a guard may overhang the context (e.g. when splitting with a named shape).- -- checkTopeAgainstContext warns on overhang and errors only if the guard is- -- disjoint from the context (a vacuous branch).- checkTopeAgainstContext "recOR branch guard" tope'- localTope tope' $ do- term' <- inferAs universeT term- ty <- typeOf term'- return (tope', (term', ty))- let rs' = map (fmap fst) ttts- ts = map (fmap snd) ttts- sequence_ [ checkCoherence l r | l:rs'' <- tails rs', r <- rs'' ]- contextEntailsUnion (map fst ttts)- return (recOrT (recOrT universeT ts) rs')-- TypeFun orig md a Nothing b -> do- a' <- enterModality md $ infer a- typeOf a' >>= \case- -- an argument can be a type- UniverseT{} ->- case a' of- -- except if its a TOPE universe- UniverseTopeT{} ->- issueTypeError $ TypeErrorOther "tope params are illegal"- _ -> do- mapM_ checkNameShadowing (binderLeaves orig)- b' <- enterScope orig md a' $ typecheck b universeT- return (typeFunT orig md a' Nothing b')- -- an argument can be a cube- UniverseCubeT{} -> do- mapM_ checkNameShadowing (binderLeaves orig)- b' <- enterScope orig md a' $ typecheck b universeT- return (typeFunT orig md a' Nothing b')- -- an argument can be a shape- TypeFunT _ty _orig _md cube mtope UniverseTopeT{} -> do- mapM_ checkNameShadowing (binderLeaves orig)- enterScope orig md cube $ do- let tope' = appT topeT (S <$> a') (Pure Z) -- eta expand a'- localTope tope' $ do- b' <- typecheck b universeT- case mtope of- Nothing -> return (typeFunT orig md cube (Just tope') b')- Just tope'' -> return (typeFunT orig md cube (Just (topeAndT tope'' tope')) b')- ty -> issueTypeError $ TypeErrorInvalidArgumentType a ty-- TypeFun orig md cube (Just tope) ret -> do- cube' <- enterModality md $ typecheck cube cubeT- mapM_ checkNameShadowing (binderLeaves orig)- enterScope orig md cube' $ do- tope' <- typecheck tope topeT- localTope tope' $ do- ret' <- typecheck ret universeT- return (typeFunT orig md cube' (Just tope') ret')-- TypeSigma orig md a b -> do- a' <- enterModality md $ typecheck a universeT- mapM_ checkNameShadowing (binderLeaves orig)- b' <- enterScope orig md a' $ typecheck b universeT- return (typeSigmaT orig md a' b')-- TypeId x (Just tA) y -> do- tA' <- typecheck tA universeT- x' <- typecheck x tA'- y' <- typecheck y tA'- return (typeIdT x' (Just tA') y')-- TypeId x Nothing y -> do- x' <- inferAs universeT x- tA <- typeOf x'- y' <- typecheck y tA- return (typeIdT x' (Just tA) y')-- App f x -> do- f' <- inferAs universeT f- fmap stripTypeRestrictions (typeOf f') >>= \case- TypeFunT _ty orig md a mtope b -> do- -- A hole argument to a shape-restricted function carries the shape as- -- its goal: record (binder : a | tope) rather than just the cube a.- x' <- enterModality md $ case (x, mtope) of- (Hole mname, Just tope) -> checkHoleAgainstShape mname orig a tope- _ -> typecheck x a- let result = appT (substituteT x' b) f' x'- case b of- UniverseTopeT{} -> do- case mtope of- Nothing -> return result- Just tope -> do- return (topeAndT (substituteT x' tope) result)- _ -> do- mapM_ (contextEntails . substituteT x') mtope -- FIXME: need to check?- return result- ty -> issueTypeError $ TypeErrorNotFunction f' ty-- Lambda _orig Nothing _body -> do- issueTypeError $ TypeErrorCannotInferBareLambda tt- Lambda orig (Just (md, ty, Nothing)) body -> do- ty' <- enterModality md $ infer ty- mtope <- typeOf ty' >>= \case- -- an argument can be a type- UniverseT{} ->- case ty' of- -- except if its a TOPE universe- UniverseTopeT{} ->- issueTypeError $ TypeErrorOther "tope params are illegal"- _ -> return Nothing- -- an argument can be a cube- UniverseCubeT{} -> return Nothing- -- an argument can be a shape- TypeFunT _ty _orig _md cube _mtope UniverseTopeT{} -> do- mapM_ checkNameShadowing (binderLeaves orig)- enterScope orig md cube $ do- let tope' = appT topeT (S <$> ty') (Pure Z) -- eta expand ty'- return (Just tope')- kind -> issueTypeError $ TypeErrorInvalidArgumentType ty kind- mapM_ checkNameShadowing (binderLeaves orig)- enterScope orig md ty' $ do- maybe id localTope mtope $ do- body' <- infer body- ret <- typeOf body'- return (lambdaT (typeFunT orig md ty' mtope ret) orig (Just (md, ty', mtope)) body')- Lambda orig (Just (md, cube, Just tope)) body -> do- cube' <- enterModality md $ typecheck cube cubeT- mapM_ checkNameShadowing (binderLeaves orig)- enterScope orig md cube' $ do- tope' <- infer tope- body' <- localTope tope' $ infer body- ret <- typeOf body'- return (lambdaT (typeFunT orig md cube' (Just tope') ret) orig (Just (md, cube', Just tope')) body')- Let orig annot val body -> do- val' <- performing (ActionCheckLetValue (binderName orig)) $ case annot of- Nothing -> infer val- Just ty -> do- bindTy <- typecheck ty universeT- typecheck val bindTy- bindTy <- typeOf val'- enterScopeWithBind orig Id bindTy val' $ do- body' <- infer body- ret <- typeOf body'- return (letT (substituteT val' ret) orig (Just bindTy) val' body')- LetMod orig app inn annot val body -> do- val' <- performing (ActionCheckLetValue (binderName orig)) $ case annot of- Nothing -> enterModality app $ infer val- Just bindType -> do- bindType' <- infer bindType- bindUniv <- typeOf bindType'- enterModality app $ typecheck val (typeModalT bindUniv inn bindType')- bindTy <- typeOf val' >>= \case- o@(TypeModalT _ty md t) ->- if md == inn then- return t- else- issueTypeError $ TypeErrorNotModal (untyped o) inn val'- o -> issueTypeError $ TypeErrorNotModal (untyped o) inn val'- bindVal <- whnfT val' >>= \case- ModAppT _ty _m t -> pure (Just t)- o | isRA inn -> pure (Just (modExtractT bindTy app inn o))- _ -> pure Nothing- enterScopeMaybe orig (comp app inn) bindTy bindVal $ do- body' <- infer body- ret <- typeOf body'- return (letModT (substituteT val' ret) orig app inn (Just bindTy) val' body')- Refl Nothing -> issueTypeError $ TypeErrorCannotInferBareRefl tt- Refl (Just (x, Nothing)) -> do- x' <- inferAs universeT x- ty <- typeOf x'- return (reflT (typeIdT x' (Just ty) x') (Just (x', Just ty)))- Refl (Just (x, Just ty)) -> do- ty' <- typecheck ty universeT- x' <- typecheck x ty'- return (reflT (typeIdT x' (Just ty') x') (Just (x', Just ty')))-- IdJ tA a tC d x p -> do- tA' <- typecheck tA universeT- a' <- typecheck a tA'- let typeOf_C =- typeFunT (BinderVar Nothing) Id tA' Nothing $- typeFunT (BinderVar Nothing) Id (typeIdT (S <$> a') (Just (S <$> tA')) (Pure Z)) Nothing $- universeT- tC' <- typecheck tC typeOf_C- let typeOf_d =- appT universeT- (appT (typeFunT (BinderVar Nothing) Id (typeIdT a' (Just tA') a') Nothing universeT)- tC' a')- (reflT (typeIdT a' (Just tA') a') Nothing)- d' <- typecheck d typeOf_d- x' <- typecheck x tA'- p' <- typecheck p (typeIdT a' (Just tA') x')- let ret =- appT universeT- (appT (typeFunT (BinderVar Nothing) Id (typeIdT a' (Just tA') x') Nothing universeT)- tC' x')- p'- return (idJT ret tA' a' tC' d' x' p')-- TypeAsc term ty -> do- ty' <- inferAs universeT ty -- this works on types AND cubes- term' <- typecheck term ty'- return (typeAscT term' ty')-- TypeRestricted ty rs -> do- ty' <- typecheck ty universeT- rs' <- forM rs $ \(tope, term) -> do- tope' <- typecheck tope topeT- term' <- localTope tope' $ typecheck term ty'- return (tope', term')- sequence_ [ checkCoherence l r | l:rs'' <- tails rs', r <- rs'' ]- return (typeRestrictedT ty' rs')- TypeModal md ty -> do- ty' <- enterModality md $ infer ty- universeTy <- typeOf ty'- _ <- case universeTy of- UniverseT {} -> pure universeTy- UniverseCubeT {} -> pure universeTy- UniverseTopeT {} -> pure universeTy- _ -> issueTypeError $ TypeErrorNotTypeInModal universeTy- return (typeModalT universeTy md ty')- ModApp md term -> do- term' <- enterModality md $ infer term- ty <- typeOf term'- tyUniv <- typeOf ty- return $ modAppT (typeModalT tyUniv md ty) md term'- ModExtract _ _ _ -> error "untypable $extract$"--checkCoherence- :: Eq var- => (TermT var, TermT var)- -> (TermT var, TermT var)- -> TypeCheck var ()-checkCoherence (ltope, lterm) (rtope, rterm) =- performing (ActionCheckCoherence (ltope, lterm) (rtope, rterm)) $ do- localTope (topeAndT ltope rtope) $ do- ltype <- stripTypeRestrictions <$> typeOf lterm -- FIXME: why strip?- rtype <- stripTypeRestrictions <$> typeOf rterm -- FIXME: why strip?- -- FIXME: do we need to unify types here or is it included in unification of terms?- unifyTerms ltype rtype- unifyTerms lterm rterm--inferStandalone :: Term VarIdent -> Either (TypeErrorInScopedContext VarIdent) (TermT VarIdent)-inferStandalone term = defaultTypeCheck (infer term)--unsafeInferStandalone' :: Term' -> TermT'-unsafeInferStandalone' term = unsafeTypeCheck' (infer term)--unsafeTypeCheck' :: TypeCheck VarIdent a -> a-unsafeTypeCheck' tc =- case defaultTypeCheck tc of- Left err -> error $ ppTypeErrorInScopedContext' BottomUp err- Right result -> result--type PointId = String-type ShapeId = [PointId]--cube2powerT :: Int -> TermT var-cube2powerT 1 = cube2T-cube2powerT dim = cubeProductT (cube2powerT (dim - 1)) cube2T--splits :: [a] -> [([a], [a])]-splits [] = [([], [])]-splits (x:xs) = ([], x:xs) : [ (x : before, after) | (before, after) <- splits xs ]--verticesFrom :: [TermT var] -> [(ShapeId, TermT var)]-verticesFrom ts = combine <$> mapM mk ts- where- mk t = [("0", topeEQT t cube2_0T), ("1", topeEQT t cube2_1T)]- combine xs = ([concat (map fst xs)], foldr1 topeAndT (map snd xs))--subTopes2 :: Int -> TermT var -> [(ShapeId, TermT var)]--- 1-dim-subTopes2 1 t =- [ (words "0", topeEQT t cube2_0T)- , (words "1", topeEQT t cube2_1T)- , (words "0 1", topeTopT) ]--- 2-dim-subTopes2 2 ts =- -- vertices- [ (words "00", topeEQT t cube2_0T `topeAndT` topeEQT s cube2_0T)- , (words "01", topeEQT t cube2_0T `topeAndT` topeEQT s cube2_1T)- , (words "10", topeEQT t cube2_1T `topeAndT` topeEQT s cube2_0T)- , (words "11", topeEQT t cube2_1T `topeAndT` topeEQT s cube2_1T)- -- edges and the diagonal- , (words "00 01", topeEQT t cube2_0T)- , (words "10 11", topeEQT t cube2_1T)- , (words "00 10", topeEQT s cube2_0T)- , (words "01 11", topeEQT s cube2_1T)- , (words "00 11", topeEQT s t)- -- triangles- , (words "00 01 11", topeLEQT t s)- , (words "00 10 11", topeLEQT s t)- ]- where- t = firstT cube2T ts- s = secondT cube2T ts--- 3-dim-subTopes2 3 t =- -- vertices- [ (words "000", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_0T)- , (words "001", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_1T)- , (words "010", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_0T)- , (words "011", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_1T)- , (words "100", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_0T)- , (words "101", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_1T)- , (words "110", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_0T)- , (words "111", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_1T)- -- edges- , (words "000 001", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_0T)- , (words "010 011", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_1T)- , (words "000 010", topeEQT t1 cube2_0T `topeAndT` topeEQT t3 cube2_0T)- , (words "001 011", topeEQT t1 cube2_0T `topeAndT` topeEQT t3 cube2_1T)- , (words "100 101", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_0T)- , (words "110 111", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_1T)- , (words "100 110", topeEQT t1 cube2_1T `topeAndT` topeEQT t3 cube2_0T)- , (words "101 111", topeEQT t1 cube2_1T `topeAndT` topeEQT t3 cube2_1T)- , (words "000 100", topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_0T)- , (words "001 101", topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_1T)- , (words "010 110", topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_0T)- , (words "011 111", topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_1T)- -- face diagonals- , (words "000 011", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 t3)- , (words "100 111", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 t3)- , (words "000 101", topeEQT t2 cube2_0T `topeAndT` topeEQT t1 t3)- , (words "010 111", topeEQT t2 cube2_1T `topeAndT` topeEQT t1 t3)- , (words "000 110", topeEQT t3 cube2_0T `topeAndT` topeEQT t1 t2)- , (words "001 111", topeEQT t3 cube2_1T `topeAndT` topeEQT t1 t2)- -- the long diagonal- , (words "000 111", topeEQT t3 t2 `topeAndT` topeEQT t2 t1)- -- face triangles- , (words "000 001 011", topeEQT t1 cube2_0T `topeAndT` topeLEQT t2 t3)- , (words "000 010 011", topeEQT t1 cube2_0T `topeAndT` topeLEQT t3 t2)- , (words "100 101 111", topeEQT t1 cube2_1T `topeAndT` topeLEQT t2 t3)- , (words "100 110 111", topeEQT t1 cube2_1T `topeAndT` topeLEQT t3 t2)- , (words "000 001 101", topeEQT t2 cube2_0T `topeAndT` topeLEQT t1 t3)- , (words "000 100 101", topeEQT t2 cube2_0T `topeAndT` topeLEQT t3 t1)- , (words "010 011 111", topeEQT t2 cube2_1T `topeAndT` topeLEQT t1 t3)- , (words "010 110 111", topeEQT t2 cube2_1T `topeAndT` topeLEQT t3 t1)- , (words "000 010 110", topeEQT t3 cube2_0T `topeAndT` topeLEQT t1 t2)- , (words "000 100 110", topeEQT t3 cube2_0T `topeAndT` topeLEQT t2 t1)- , (words "001 011 111", topeEQT t3 cube2_1T `topeAndT` topeLEQT t1 t2)- , (words "001 101 111", topeEQT t3 cube2_1T `topeAndT` topeLEQT t2 t1)- -- diagonal triangles- , (words "000 001 111", topeEQT t1 t2 `topeAndT` topeLEQT t2 t3)- , (words "000 010 111", topeEQT t1 t3 `topeAndT` topeLEQT t1 t2)- , (words "000 100 111", topeEQT t2 t3 `topeAndT` topeLEQT t2 t1)- , (words "000 011 111", topeLEQT t1 t2 `topeAndT` topeEQT t2 t3)- , (words "000 101 111", topeLEQT t2 t1 `topeAndT` topeEQT t1 t3)- , (words "000 110 111", topeLEQT t3 t1 `topeAndT` topeEQT t1 t2)- -- tetrahedra- , (words "000 001 011 111", topeLEQT t1 t2 `topeAndT` topeLEQT t2 t3)- , (words "000 010 011 111", topeLEQT t1 t3 `topeAndT` topeLEQT t3 t2)- , (words "000 001 101 111", topeLEQT t2 t1 `topeAndT` topeLEQT t1 t3)- , (words "000 100 101 111", topeLEQT t2 t3 `topeAndT` topeLEQT t3 t1)- , (words "000 010 110 111", topeLEQT t3 t1 `topeAndT` topeLEQT t1 t2)- , (words "000 100 110 111", topeLEQT t3 t2 `topeAndT` topeLEQT t2 t1)- ]- where- t1 = firstT cube2T (firstT (cube2powerT 2) t)- t2 = secondT cube2T (firstT (cube2powerT 2) t)- t3 = secondT cube2T t-subTopes2 dim _ = error (show dim <> " dimensions are not supported")--cubeSubTopes :: [(ShapeId, TermT (Inc var))]-cubeSubTopes = subTopes2 3 (Pure Z)--limitLength :: Int -> String -> String-limitLength n s- | length s > n = take (n - 1) s <> "…"- | otherwise = s---- | Apply the 'renderHideTerm' policy to a cell's render data: drop the--- @\<title\>@ (the full term) from every cell, and blank the visible label of a--- proof-coloured (interior) cell. Boundary cells (coloured otherwise) keep--- their given labels. A no-op when not hiding.-hideTermData :: Bool -> String -> RenderObjectData -> RenderObjectData-hideTermData False _ d = d-hideTermData True mainColor d- | renderObjectDataColor d == mainColor =- d { renderObjectDataLabel = "", renderObjectDataFullLabel = "" }- | otherwise = d { renderObjectDataFullLabel = "" }--renderObjectsFor- :: Eq var- => String- -> Int- -> TermT var- -> TermT var- -> TypeCheck var [(ShapeId, RenderObjectData)]-renderObjectsFor mainColor dim t term = fmap catMaybes $ do- forM (subTopes2 dim t) $ \(shapeId, tope) -> do- checkTopeEntails tope >>= \case- False -> return Nothing- True -> typeOf term >>= \case- UniverseTopeT{} -> localTope term $ checkTopeEntails tope >>= \case- False -> return Nothing- True -> return $ Just (shapeId, RenderObjectData- { renderObjectDataLabel = ""- , renderObjectDataFullLabel = ""- , renderObjectDataColor = "orange" -- FIXME: orange for topes?- })- _ -> do- origs <- asks varOrigs- term' <- localTope tope $ whnfT term- label <-- case term' of- AppT _ (Pure z) arg- | Just (Just "_") <- lookup z origs -> return ""- | null (nub (freeVars (untyped arg)) \\ nub (freeVars (untyped t))) ->- ppTermInContext (Pure z)- _ -> ppTermInContext term'- hide <- asks renderHideTerm- return $ Just (shapeId, hideTermData hide mainColor RenderObjectData- { renderObjectDataLabel = label- , renderObjectDataFullLabel = label- , renderObjectDataColor =- case term' of- Pure{} -> "purple"- AppT _ (Pure x) arg- | Just (Just "_") <- lookup x origs -> mainColor- | null (nub (freeVars (untyped arg)) \\ nub (freeVars (untyped t))) -> "purple"- _ -> mainColor- })--componentWiseEQT :: Int -> TermT var -> TermT var -> TermT var-componentWiseEQT 1 t s = topeEQT t s-componentWiseEQT 2 t s = topeAndT- (componentWiseEQT 1 (firstT cube2T t) (firstT cube2T s))- (componentWiseEQT 1 (secondT cube2T t) (secondT cube2T s))-componentWiseEQT 3 t s = topeAndT- (componentWiseEQT 2 (firstT (cube2powerT 2) t) (firstT (cube2powerT 2) s))- (componentWiseEQT 1 (secondT cube2T t) (secondT cube2T s))-componentWiseEQT dim _ _ = error ("cannot work with " <> show dim <> " dimensions")--renderObjectsInSubShapeFor- :: Eq var- => String- -> Int- -> [var]- -> var- -> TermT var- -> TermT var- -> TermT var- -> TypeCheck var [(ShapeId, RenderObjectData)]-renderObjectsInSubShapeFor mainColor dim sub super retType f x = fmap catMaybes $ do- let reduceContext- = foldr topeOrT topeBottomT- . map (foldr topeAndT topeTopT)- . map (filter (\tope -> all (`notElem` tope) sub))- . map (map tTope)- . map (saturateTopes [])- . simplifyLHSwithDisjunctions- contextTopes <- asks (reduceContext . localTopesNF)- contextTopes' <- localTope (componentWiseEQT dim (Pure super) x) $ asks (reduceContext . localTopesNF)- forM (subTopes2 dim (Pure super)) $ \(shapeId, tope) -> do- checkEntails tope contextTopes >>= \case- False -> return Nothing- True -> do- origs <- asks varOrigs- term <- localTope tope (whnfT (appT retType f (Pure super)))- label <- typeOf term >>= \case- UniverseTopeT{} -> return ""- _ -> do- case term of- AppT _ (Pure z) arg- | Just (Just "_") <- lookup z origs -> return ""- | null (nub (freeVars (untyped arg)) \\ [super]) -> ppTermInContext (Pure z)- _ -> ppTermInContext term- color <- checkEntails tope contextTopes' >>= \case- True -> do- case term of- Pure{} -> return "purple"- AppT _ (Pure z) arg- | Just (Just "_") <- lookup z origs -> return mainColor- | null (nub (freeVars (untyped arg)) \\ [super]) -> return "purple"- _ -> return mainColor- False -> return "gray"- hide <- asks renderHideTerm- return $ Just (shapeId, hideTermData hide mainColor RenderObjectData- { renderObjectDataLabel = label- , renderObjectDataFullLabel = label- , renderObjectDataColor = color- })--renderForSubShapeSVG- :: Eq var- => String- -> Int- -> [var]- -> var- -> TermT var- -> TermT var- -> TermT var- -> TypeCheck var String-renderForSubShapeSVG mainColor dim sub super retType f x = do- objects <- renderObjectsInSubShapeFor mainColor dim sub super retType f x- let objects' = map mk objects- return $ renderCube defaultCamera (if dim > 2 then (pi/7) else 0) $ \obj ->- lookup obj objects'- where- mk (shapeId, renderData) = (intercalate "-" (map fill shapeId), renderData)- fill xs = xs <> replicate (3 - length xs) '1'--renderForSVG :: Eq var => String -> Int -> TermT var -> TermT var -> TypeCheck var String-renderForSVG mainColor dim t term = do- objects <- renderObjectsFor mainColor dim t term- let objects' = map mk objects- return $ renderCube defaultCamera (if dim > 2 then (pi/7) else 0) $ \obj ->- lookup obj objects'- where- mk (shapeId, renderData) = (intercalate "-" (map fill shapeId), renderData)- fill xs = xs <> replicate (3 - length xs) '1'--renderTermSVGFor- :: Eq var- => String -- ^ Main color.- -> Int -- ^ Accumulated dimensions so far (from 0 to 3).- -> (Maybe (TermT var, TermT var), [var]) -- ^ Accumulated point term (and its time).- -> TermT var -- ^ Term to render.- -> TypeCheck var (Maybe String)-renderTermSVGFor mainColor accDim (mp, xs) t = do- t' <- whnfT t- ty <- typeOf t'- case t of -- check unevaluated term- AppT _info f x -> typeOf f >>= \case- TypeFunT _ fOrig md fArg mtopeArg ret | Just dim <- dimOf fArg, dim <= maxDim -> do- enterScope fOrig md fArg $ do- maybe id localTope mtopeArg $ do- Just <$> renderForSubShapeSVG mainColor dim (map S xs) Z ret (S <$> f) (S <$> x) -- FIXME: breaks for 2 * (2 * 2), but works for 2 * 2 * 2 = (2 * 2) * 2- _ -> traverse (\(p', _) -> renderForSVG mainColor accDim p' t') mp- TypeFunT _ _orig' md' _ _ _ | null xs -> enterScope (BinderVar (Just "_")) md' t' $ do- renderTermSVGFor "blue" 0 (Nothing, []) (Pure Z) -- use blue for types-- _ -> case t' of -- check evaluated term- AppT _info f x -> typeOf f >>= \case- TypeFunT _ fOrig md fArg mtopeArg ret | Just dim <- dimOf fArg, dim <= maxDim -> do- enterScope fOrig md fArg $ do- maybe id localTope mtopeArg $ do- Just <$> renderForSubShapeSVG mainColor dim (map S xs) Z ret (S <$> f) (S <$> x) -- FIXME: breaks for 2 * (2 * 2), but works for 2 * 2 * 2 = (2 * 2) * 2- _ -> traverse (\(p', _) -> renderForSVG mainColor accDim p' t') mp- TypeFunT _ _orig' md' _ _ _ | null xs -> enterScope (BinderVar (Just "_")) md' t' $ do- renderTermSVGFor "blue" 0 (Nothing, []) (Pure Z) -- use blue for types-- _ -> case ty of -- check type of the term- TypeFunT _ orig md arg mtope ret- | Just dim <- dimOf arg, accDim + dim <= maxDim -> enterScope orig md arg $ do- maybe id localTope mtope $- renderTermSVGFor mainColor (accDim + dim)- (join' (both (fmap S) <$> mp) (S <$> arg) (Pure Z), Z : map S xs) $- case t' of- LambdaT _ _orig _marg body -> body- _ -> appT ret (S <$> t') (Pure Z)- | null xs -> enterScope orig md arg $ do- maybe id localTope mtope $- renderTermSVGFor mainColor accDim- (both (fmap S) <$> mp, map S xs) $- case t' of- LambdaT _ _orig _marg body -> body- _ -> appT ret (S <$> t') (Pure Z)- _ -> traverse (\(p', _) -> renderForSVG mainColor accDim p' t') mp- where- maxDim = 3-- both f (x, y) = (f x, f y)-- join' Nothing Cube2T{} x = Just (x, cube2T)- join' (Just (p, pt)) Cube2T{} x = Just (p', pt')- where- pt' = cubeProductT pt cube2T- p' = pairT pt' p x- join' p (CubeProductT _ l r) x =- join' (join' p l (firstT l x)) r (secondT r x)- join' _ _ _ = Nothing -- FIXME: error?-- dimOf = \case- Cube2T{} -> Just 1- CubeProductT _ l r -> (+) <$> dimOf l <*> dimOf r- _ -> Nothing--renderTermSVG :: Eq var => TermT var -> TypeCheck var (Maybe String)-renderTermSVG = renderTermSVGFor "red" 0 (Nothing, []) -- use red for terms by default---- | Render the goal /cell/ for a (shape) type: introduce an abstract inhabitant--- and render it with the proof term hidden. Under a boundary tope an abstract--- inhabitant of an extension type reduces to the prescribed face value, so the--- cell shows its given edges with a blank interior — the shape to inhabit, not--- an answer. 'Nothing' for a non-shape type (a 0-cell or a non-cube goal).-renderGoalCellSVG :: Eq var => TermT var -> TypeCheck var (Maybe String)-renderGoalCellSVG ty =- hidingTerm $ enterScope (BinderVar (Just "_")) Id ty $ renderTermSVG' (Pure Z)--renderTermSVG' :: Eq var => TermT var -> TypeCheck var (Maybe String)-renderTermSVG' t = whnfT t >>= \t' -> typeOf t >>= \case- TypeFunT _ orig md arg mtope ret -> enterScope orig md arg $ do- maybe id localTope mtope $ case t' of- LambdaT _ _orig _marg (AppT _info f x) ->- typeOf f >>= \case- TypeFunT _ fOrig md2 fArg mtope2 _ret | Just dim <- dimOf fArg -> do- enterScope fOrig md2 fArg $ do- maybe id localTope mtope2 $ do- Just <$> renderForSubShapeSVG "red" dim [S Z] Z (S <$> ret) (S <$> f) (S <$> x)- _ -> defaultRenderTermSVG t' arg ret- _ -> defaultRenderTermSVG t' arg ret- _t' -> return Nothing- where- dimOf = \case- Cube2T{} -> Just 1- CubeProductT _ l r -> (+) <$> dimOf l <*> dimOf r -- WARNING: breaks for 2 * (2 * 2)- _ -> Nothing-- defaultRenderTermSVG t' arg ret =- case dimOf arg of- Just dim | dim <= 3 ->- Just <$> renderForSVG "red" dim (Pure Z) (appT ret (S <$> t') (Pure Z))- _ -> renderTermSVG' (appT ret (S <$> t') (Pure Z))---type Point2D a = (a, a)-type Point3D a = (a, a, a)-type Edge3D a = (Point3D a, Point3D a)-type Face3D a = (Point3D a, Point3D a, Point3D a)-type Volume3D a = (Point3D a, Point3D a, Point3D a, Point3D a)--data CubeCoords2D a b = CubeCoords2D- { vertices :: [(Point3D a, Point2D b)]- , edges :: [(Edge3D a, (Point2D b, Point2D b))]- , faces :: [(Face3D a, (Point2D b, Point2D b, Point2D b))]- , volumes :: [(Volume3D a, (Point2D b, Point2D b, Point2D b, Point2D b))]- }--data Matrix3D a = Matrix3D- a a a- a a a- a a a--data Matrix4D a = Matrix4D- a a a a- a a a a- a a a a- a a a a--data Vector3D a = Vector3D a a a--data Vector4D a = Vector4D a a a a--rotateX :: Floating a => a -> Matrix3D a-rotateX theta = Matrix3D- 1 0 0- 0 (cos theta) (- sin theta)- 0 (sin theta) (cos theta)--rotateY :: Floating a => a -> Matrix3D a-rotateY theta = Matrix3D- (cos theta) 0 (sin theta)- 0 1 0- (- sin theta) 0 (cos theta)--rotateZ :: Floating a => a -> Matrix3D a-rotateZ theta = Matrix3D- (cos theta) (- sin theta) 0- (sin theta) (cos theta) 0- 0 0 1--data Camera a = Camera- { cameraPos :: Point3D a- , cameraFoV :: a- , cameraAspectRatio :: a- , cameraAngleY :: a- , cameraAngleX :: a- }--viewRotateX :: Floating a => Camera a -> Matrix4D a-viewRotateX Camera{..} = matrix3Dto4D (rotateX cameraAngleX)--viewRotateY :: Floating a => Camera a -> Matrix4D a-viewRotateY Camera{..} = matrix3Dto4D (rotateY cameraAngleY)--viewTranslate :: Num a => Camera a -> Matrix4D a-viewTranslate Camera{..} = Matrix4D- 1 0 0 0- 0 1 0 0- 0 0 1 0- (-x) (-y) (-z) 1- where- (x, y, z) = cameraPos--project2D :: Floating a => Camera a -> Matrix4D a-project2D Camera{..} = Matrix4D- (2 * n / (r - l)) 0 ((r + l) / (r - l)) 0- 0 (2 * n / (t - b)) ((t + b) / (t - b)) 0- 0 0 (- (f + n) / (f - n)) (- 2 * f * n / (f - n))- 0 0 (-1) 0- where- n = 1- f = 2- r = n * tan (cameraFoV / 2)- l = -r- t = r * cameraAspectRatio- b = -t---matrixVectorMult4D :: Num a => Matrix4D a -> Vector4D a -> Vector4D a-matrixVectorMult4D- (Matrix4D- a1 a2 a3 a4- b1 b2 b3 b4- c1 c2 c3 c4- d1 d2 d3 d4)- (Vector4D a b c d)- = Vector4D a' b' c' d'- where- a' = sum (zipWith (*) [a1, b1, c1, d1] [a, b, c, d])- b' = sum (zipWith (*) [a2, b2, c2, d2] [a, b, c, d])- c' = sum (zipWith (*) [a3, b3, c3, d3] [a, b, c, d])- d' = sum (zipWith (*) [a4, b4, c4, d4] [a, b, c, d])--matrix3Dto4D :: Num a => Matrix3D a -> Matrix4D a-matrix3Dto4D- (Matrix3D- a1 b1 c1- a2 b2 c2- a3 b3 c3) = Matrix4D- a1 b1 c1 0- a2 b2 c2 0- a3 b3 c3 0- 0 0 0 1--fromAffine :: Fractional a => Vector4D a -> (Point2D a, a)-fromAffine (Vector4D a b c d) = ((x, y), zIndex)- where- x = a / d- y = b / d- zIndex = c / d--point3Dto2D :: Floating a => Camera a -> a -> Point3D a -> (Point2D a, a)-point3Dto2D camera rotY (x, y, z) = fromAffine $- foldr matrixVectorMult4D (Vector4D x y z 1) $ reverse- [ matrix3Dto4D (rotateY rotY)- , viewTranslate camera- , viewRotateY camera- , viewRotateX camera- , project2D camera- ]--data RenderObjectData = RenderObjectData- { renderObjectDataLabel :: String- , renderObjectDataFullLabel :: String- , renderObjectDataColor :: String- }--renderCube- :: (Floating a, Show a)- => Camera a- -> a- -> (String -> Maybe RenderObjectData)- -> String-renderCube camera rotY renderDataOf' = unlines $ filter (not . null)- [ "<svg class=\"rzk-render\" viewBox=\"-175 -200 350 375\" width=\"150\" height=\"150\">"- , intercalate "\n"- [ " <path d=\"M " <> show x1 <> " " <> show y1- <> " L " <> show x2 <> " " <> show y2- <> " L " <> show x3 <> " " <> show y3- <> " Z\" style=\"fill: " <> renderObjectDataColor <> "; opacity: 0.2\"><title>" <> renderObjectDataFullLabel <> "</title></path>" <> "\n" <>- " <text x=\"" <> show x <> "\" y=\"" <> show y <> "\" fill=\"" <> renderObjectDataColor <> "\">" <> renderObjectDataLabel <> "</text>"- | (faceId, (((x1, y1), (x2, y2), (x3, y3)), _)) <- faces- , Just RenderObjectData{..} <- [renderDataOf faceId]- , let x = (x1 + x2 + x3) / 3- , let y = (y1 + y2 + y3) / 3 ]- , intercalate "\n"- [ " <polyline points=\"" <> show x1 <> "," <> show y1 <> " " <> show x2 <> "," <> show y2- <> "\" stroke=\"" <> renderObjectDataColor <> "\" stroke-width=\"3\" marker-end=\"url(#arrow)\"><title>" <> renderObjectDataFullLabel <> "</title></polyline>" <> "\n" <>- " <text x=\"" <> show x <> "\" y=\"" <> show y <> "\" fill=\"" <> renderObjectDataColor <> "\" stroke=\"white\" stroke-width=\"10\" stroke-opacity=\".8\" paint-order=\"stroke\">" <> renderObjectDataLabel <> "</text>"- | (edge, (((x1, y1), (x2, y2)), _)) <- edges- , Just RenderObjectData{..} <- [renderDataOf edge]- , let x = (x1 + x2) / 2- , let y = (y1 + y2) / 2 ]- , intercalate "\n"- [ " <text x=\"" <> show x <> "\" y=\"" <> show y <> "\" fill=\"" <> renderObjectDataColor <> "\">" <> renderObjectDataLabel <> "</text>"- | (v, ((x, y), _)) <- vertices- , Just RenderObjectData{..} <- [renderDataOf v]]- , "</svg>" ]- where- renderDataOf shapeId =- case renderDataOf' shapeId of- Nothing -> Nothing- Just RenderObjectData{..} -> Just RenderObjectData- -- FIXME: move constants to configurable parameters- { renderObjectDataLabel = hideWhenLargerThan shapeId 5 renderObjectDataLabel- , renderObjectDataFullLabel = limitLength 30 renderObjectDataFullLabel- , .. }-- hideWhenLargerThan shapeId n s- | null s || length s > n = if '-' `elem` shapeId then "" else "•"- | otherwise = s-- vertices =- [ (show x <> show y <> show z, ((500 * x'', 500 * y''), zIndex))- | x <- [0,1]- , y <- [0,1]- , z <- [0,1]- , let f c = 2 * fromInteger c - 1- , let x' = f x- , let y' = f (1-y)- , let z' = f z- , let ((x'', y''), zIndex) = point3Dto2D camera rotY (x', y', z') ]-- radius = 20-- mkEdge r (x1, y1) (x2, y2) = ((x1 + dx, y1 + dy), ((x2 - dx), (y2 - dy)))- where- d = sqrt ((x2 - x1)^2 + (y2 - y1)^2)- dx = r * (x2 - x1) / d- dy = r * (y2 - y1) / d-- scaleAround (cx, cy) s (x, y) = (cx + s * (x - cx), cy + s * (y - cy))-- mkFace (x1, y1) (x2, y2) (x3, y3) = (p1, p2, p3)- where- cx = (x1 + x2 + x3) / 3- cy = (y1 + y2 + y3) / 3- p1 = scaleAround (cx, cy) 0.85 (x1, y1)- p2 = scaleAround (cx, cy) 0.85 (x2, y2)- p3 = scaleAround (cx, cy) 0.85 (x3, y3)-- edges =- [ (intercalate "-" [fromName, toName], (mkEdge radius from to, 0))- | (fromName, (from, _)) : vs <- tails vertices- , (toName, (to, _)) <- vs- , and (zipWith (<=) fromName toName)- ]-- faces =- [ (intercalate "-" [name1, name2, name3], (mkFace v1 v2 v3, 0))- | (name1, (v1, _)) : vs <- tails vertices- , (name2, (v2, _)) : vs' <- tails vs- , and (zipWith (<=) name1 name2)- , (name3, (v3, _)) <- vs'- , and (zipWith (<=) name2 name3)- ]---defaultCamera :: Floating a => Camera a-defaultCamera = Camera- { cameraPos = (0, 7, 10)- , cameraAngleY = pi- , cameraAngleX = pi/5- , cameraFoV = pi/15- , cameraAspectRatio = 1- }---- * Elaborated types of local binders (for LSP hover)---- | Naming environment for rendering types found under binders: how to--- display each variable, plus the pattern binders passed on the way down,--- for projection restoration (as in 'recordHoleShape').-data BinderNames var = BinderNames- { binderNameOf :: var -> VarIdent- , binderNameProjs :: [(VarIdent, [([Proj], VarIdent)])]- , binderNamePats :: [(VarIdent, Binder)]- }--topLevelBinderNames :: BinderNames VarIdent-topLevelBinderNames = BinderNames id [] []--renderBinderType :: BinderNames var -> TermT var -> Term'-renderBinderType names t =- restorePatternVars (binderNamePats names)- (foldBinderProjections (binderNameProjs names) (untyped (binderNameOf names <$> t)))--underBinder :: Binder -> BinderNames var -> BinderNames (Inc var)-underBinder binder names = BinderNames- { binderNameOf = \case- Z -> zName- S v -> binderNameOf names v- , binderNameProjs = case binder of- BinderVar{} -> binderNameProjs names- _ -> (zName, binderPaths binder) : binderNameProjs names- , binderNamePats = case binder of- BinderVar{} -> binderNamePats names- _ -> (zName, binder) : binderNamePats names- }- where- zName = binderDisplayName binder---- | The memoised weak head normal form of a typed term, if present.-memoWHNF :: TermT var -> TermT var-memoWHNF t@(Free (AnnF info _)) = fromMaybe t (infoWHNF info)-memoWHNF t = t----- | The variables a binder introduces, with rendered types. A pair binder--- splits its type along Σ-types and cube products; when the shape is not--- syntactic (e.g. the type is a defined name applied to arguments, as in--- @((η , (ϵ , (α , β))) : has-quasi-diagrammatic-adj A B f u)@), the type is--- put in weak head normal form first, which needs the global declarations in--- scope (see 'binderTypesInScopeOf'). The dependent part is rendered under--- the earlier component's display name, giving @q : B p@.--- | A binder's displayed type: a plain type, or a cube together with a tope--- for shaped binders like @(t : I | φ t)@.-data BinderTypeView- = TypeView Term'- | ShapeView Term' Term'--binderTypeEntriesM :: Eq var => BinderNames var -> Binder -> TermT var -> TypeCheck var [(VarIdent, BinderTypeView)]-binderTypeEntriesM names binder ty = case binder of- BinderUnit -> pure []- BinderVar Nothing -> pure []- BinderVar (Just x) -> pure [(x, TypeView (renderBinderType names ty))]- BinderPair l r -> splitViewM ty >>= \case- Just (TypeSigmaT _ _ md a bscope) -> do- ls <- binderTypeEntriesM names l a- rs <- enterScope l md a (binderTypeEntriesM (underBinder l names) r bscope)- pure (ls ++ rs)- Just (CubeProductT _ a b) ->- (++) <$> binderTypeEntriesM names l a <*> binderTypeEntriesM names r b- _ -> pure [] -- unrecognised shape; the surface annotation is the fallback---- | View a type as a Σ-type or cube product: syntactically or through the--- memoised WHNF if possible, computing the WHNF otherwise. Never throws.-splitViewM :: Eq var => TermT var -> TypeCheck var (Maybe (TermT var))-splitViewM ty = case splitView (memoWHNF ty) of- Just t -> pure (Just t)- Nothing -> (splitView <$> whnfT ty) `catchError` \_ -> pure Nothing- where- splitView t = case stripTypeRestrictions t of- t'@TypeSigmaT{} -> Just t'- t'@CubeProductT{} -> Just t'- _ -> Nothing---- | Elaborated types of the local binders of a typed term, keyed by the--- binder's original identifier (whose position points at its defining--- occurrence). Every node of a typed term carries its type, so even a bare--- lambda's binder is typed, by the domain of the lambda's own Π-type.-binderTypesOfTermM :: Eq var => BinderNames var -> TermT var -> TypeCheck var [(VarIdent, BinderTypeView)]-binderTypesOfTermM names = go- where- go t = case t of- Pure _ -> pure []- LambdaT info binder mparam body -> do- (paramType, paramTope) <- case mparam of- Just (_, ty, mtope) -> pure (Just ty, mtope)- -- A bare lambda: the domain (and shape) of its own Π-type.- Nothing -> case funView (memoWHNF (infoType info)) of- Just (p, mtope) -> pure (Just p, mtope)- Nothing ->- (maybe (Nothing, Nothing) (\(p, mtope) -> (Just p, mtope)) . funView- <$> whnfT (infoType info))- `catchError` \_ -> pure (Nothing, Nothing)- entries <- shapedBinderEntries names binder paramType paramTope- annEntries <- case mparam of- Nothing -> pure []- Just (md, ty, mtope) -> do- tyEntries <- go ty- topeEntries <- maybe (pure []) (enterScope binder md ty . under binder) mtope- pure (tyEntries ++ topeEntries)- let md = maybe Id (\(m, _, _) -> m) mparam- bodyEntries <- enterScope binder md (fromMaybe universeT paramType) (under binder body)- pure (entries ++ annEntries ++ bodyEntries)- TypeFunT _ binder md param mtope ret -> do- entries <- shapedBinderEntries names binder (Just param) mtope- paramEntries <- go param- topeEntries <- maybe (pure []) (enterScope binder md param . under binder) mtope- retEntries <- enterScope binder md param (under binder ret)- pure (entries ++ paramEntries ++ topeEntries ++ retEntries)- TypeSigmaT _ binder md a bscope -> do- entries <- binderTypeEntriesM names binder a- aEntries <- go a- bEntries <- enterScope binder md a (under binder bscope)- pure (entries ++ aEntries ++ bEntries)- LetT _ binder manno value body -> do- let valueType = case value of- Free (AnnF valueInfo _) -> Just (infoType valueInfo)- Pure _ -> manno- entries <- maybe (pure []) (binderTypeEntriesM names binder) valueType- annEntries <- maybe (pure []) go manno- valueEntries <- go value- bodyEntries <- enterScopeWithBind binder Id (fromMaybe universeT valueType) value- (under binder body)- pure (entries ++ annEntries ++ valueEntries ++ bodyEntries)- LetModT _ binder _nu mu manno value body -> do- unwrapped <- case value of- Pure _ -> pure Nothing- Free (AnnF valueInfo _) -> do- let vt = infoType valueInfo- case modalView (memoWHNF vt) of- Just a -> pure (Just a)- Nothing -> (modalView <$> whnfT vt) `catchError` \_ -> pure Nothing- entries <- maybe (pure []) (binderTypeEntriesM names binder) unwrapped- annEntries <- maybe (pure []) go manno- valueEntries <- go value- bodyEntries <- enterScope binder mu (fromMaybe universeT unwrapped) (under binder body)- pure (entries ++ annEntries ++ valueEntries ++ bodyEntries)- Free (AnnF _ f) -> concat <$> mapM go (bifoldr (\_ acc -> acc) (:) [] f)- under binder = binderTypesOfTermM (underBinder binder names)- funView t = case stripTypeRestrictions t of- TypeFunT _ _ _ param mtope _ -> Just (param, mtope)- _ -> Nothing- modalView t = case stripTypeRestrictions t of- TypeModalT _ _ a -> Just a- _ -> Nothing- -- A shaped plain binder shows its cube together with the tope, as it is- -- written: (t : I | φ t). A shaped pair binder splits along the cube,- -- the tope constraining the components jointly (as in the surface tier).- shapedBinderEntries names' binder mty mtope = case (binder, mty, mtope) of- (BinderVar (Just x), Just cube, Just tope) ->- pure [(x, ShapeView (renderBinderType names' cube)- (renderBinderType (underBinder binder names') tope))]- (_, Just ty, _) -> binderTypeEntriesM names' binder ty- _ -> pure []---- | All local binder types of a declaration: Π and Σ binders from the type,--- lambda and let binders from the value.-declBinderTypes :: Decl' -> TypeCheck VarIdent [(VarIdent, BinderTypeView)]-declBinderTypes decl =- (++) <$> binderTypesOfTermM topLevelBinderNames (declType decl)- <*> maybe (pure []) (binderTypesOfTermM topLevelBinderNames) (declValue decl)---- | Elaborated types of the local binders of @fileDecls@, with @globalDecls@--- in scope so that 'whnfT' can unfold definitions when splitting pair--- binders. Pure at the interface: runs the checker silently and returns no--- entries where it fails.-binderTypesInScopeOf :: [Decl'] -> [Decl'] -> [(VarIdent, BinderTypeView)]-binderTypesInScopeOf globalDecls fileDecls =- case defaultTypeCheck action of- Left _ -> []- Right entries -> entries- where- action = localVerbosity Silent $- localDeclsPrepared globalDecls $- concat <$> mapM declBinderTypes fileDecls+-- | The type checker.+--+-- This module is the public face of it: the judgements themselves live in+-- "Rzk.TypeCheck.Judgements", the module driver and the declarations in+-- "Rzk.TypeCheck.Decl", and so on. What used to be one 5,500-line module is now a+-- layer per concern, over the free-foil core in "Language.Rzk.Foil.Syntax".+module Rzk.TypeCheck (+ module Rzk.TypeCheck.Context,+ module Rzk.TypeCheck.Display,+ module Rzk.TypeCheck.Error,+ module Rzk.TypeCheck.Monad,+ module Rzk.TypeCheck.Eval,+ module Rzk.TypeCheck.Judgements,+ module Rzk.TypeCheck.Decl,+ module Rzk.TypeCheck.BinderTypes,+) where++import Rzk.TypeCheck.BinderTypes+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Decl+import Rzk.TypeCheck.Display+import Rzk.TypeCheck.Error+import Rzk.TypeCheck.Eval+import Rzk.TypeCheck.Judgements+import Rzk.TypeCheck.Monad
+ src/Rzk/TypeCheck/BinderTypes.hs view
@@ -0,0 +1,213 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | The elaborated types of a declaration's local binders, for LSP hover.+--+-- Every node of a typed term carries its type, so even a bare λ's binder is typed+-- — by the domain of the λ's own Π-type.+--+-- The old version threaded a @BinderNames@ environment down through the term, to+-- say what each variable it met was called. There is no need: entering a binder+-- puts it in the context, and the context already knows what everything in it is+-- called (see "Rzk.TypeCheck.Display").+module Rzk.TypeCheck.BinderTypes where++import Control.Monad.Except (catchError)+import Control.Monad.Reader (asks)+import Data.Bifoldable (bifoldr)+import Data.Maybe (fromMaybe)++import Control.Monad.Foil (Distinct)+import Control.Monad.Free.Foil (AST (Node, Var))++import Control.Monad.Free.Foil.Annotated (AnnSig (..))+import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), TModality (..),+ TypeInfo (..), VarIdent)+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Decl+import Rzk.TypeCheck.Display+import Rzk.TypeCheck.Eval+import Rzk.TypeCheck.Monad++-- | A binder's displayed type: a plain type, or a cube together with a tope, for a+-- shaped binder like @(t : I | φ t)@.+data BinderTypeView+ = TypeView Rendered+ | ShapeView Rendered Rendered+ deriving (Eq, Show)++-- | Render a term with the names of the context it is in.+renderHere :: TermT n -> TypeCheck n Rendered+renderHere t = do+ naming <- asks namingOfContext+ pure (renderTerm naming (untyped t))++-- | The memoised weak head normal form of a typed term, if present.+memoWHNF :: TermT n -> TermT n+memoWHNF t = fromMaybe t (typeInfoOf t >>= infoWHNF)++-- | The variables a binder introduces, with their rendered types.+--+-- A pair binder splits its type along Σ-types and cube products; when the shape is+-- not syntactic (the type is a defined name applied to arguments, as in+-- @((η , (ϵ , (α , β))) : has-quasi-diagrammatic-adj A B f u)@), the type is put in+-- weak head normal form first, which needs the top-level definitions in scope. The+-- dependent part is rendered under the earlier component's display name, giving+-- @q : B p@.+binderTypeEntries+ :: Distinct n => Binder -> TermT n -> TypeCheck n [(VarIdent, BinderTypeView)]+binderTypeEntries binder ty = case binder of+ BinderUnit -> pure []+ BinderVar Nothing -> pure []+ BinderVar (Just x) -> do+ rendered <- renderHere ty+ pure [(x, TypeView rendered)]+ BinderPair l r -> splitViewM ty >>= \case+ Just (TypeSigmaT _ _ md a bscope) -> do+ ls <- binderTypeEntries l a+ rs <- inScope l md a bscope $ \bBody -> binderTypeEntries r bBody+ pure (ls ++ rs)+ Just (CubeProductT _ a b) ->+ (++) <$> binderTypeEntries l a <*> binderTypeEntries r b+ _ -> pure [] -- unrecognised shape; the surface annotation is the fallback++-- | View a type as a Σ-type or a cube product: syntactically, or through the+-- memoised WHNF if possible, computing the WHNF otherwise. Never throws.+splitViewM :: Distinct n => TermT n -> TypeCheck n (Maybe (TermT n))+splitViewM ty = case splitView (memoWHNF ty) of+ Just t -> pure (Just t)+ Nothing -> (splitView <$> whnfT ty) `catchError` \_ -> pure Nothing+ where+ splitView t = case stripTypeRestrictions t of+ t'@TypeSigmaT{} -> Just t'+ t'@CubeProductT{} -> Just t'+ _ -> Nothing++-- | The elaborated types of the local binders of a typed term, keyed by the+-- binder's original identifier (whose position points at its defining occurrence).+binderTypesOfTerm+ :: Distinct n => TermT n -> TypeCheck n [(VarIdent, BinderTypeView)]+binderTypesOfTerm = go+ where+ go :: Distinct n => TermT n -> TypeCheck n [(VarIdent, BinderTypeView)]+ go t = case t of+ Var _ -> pure []++ LambdaT info binder mparam body -> do+ (paramType, paramTope) <- case mparam of+ Just (LambdaParam _ ty mtope) -> pure (Just ty, mtope)+ -- A bare λ: the domain (and shape) of its own Π-type.+ Nothing -> case funView (memoWHNF (infoType info)) of+ Just (p, mtope) -> pure (Just p, mtope)+ Nothing ->+ (maybe (Nothing, Nothing) (\(p, mtope) -> (Just p, mtope)) . funView+ <$> whnfT (infoType info))+ `catchError` \_ -> pure (Nothing, Nothing)+ entries <- shapedBinderEntries binder paramType paramTope+ let md = maybe Id (\(LambdaParam m _ _) -> m) mparam+ annEntries <- case mparam of+ Nothing -> pure []+ Just (LambdaParam _ ty mtope) -> do+ tyEntries <- go ty+ topeEntries <- case mtope of+ Nothing -> pure []+ Just tope -> inScope binder md ty tope go+ pure (tyEntries ++ topeEntries)+ bodyEntries <-+ inScope binder md (fromMaybe universeT paramType) body go+ pure (entries ++ annEntries ++ bodyEntries)++ TypeFunT _ binder md param mtope ret -> do+ entries <- shapedBinderEntries binder (Just param) mtope+ paramEntries <- go param+ topeEntries <- case mtope of+ Nothing -> pure []+ Just tope -> inScope binder md param tope go+ retEntries <- inScope binder md param ret go+ pure (entries ++ paramEntries ++ topeEntries ++ retEntries)++ TypeSigmaT _ binder md a bscope -> do+ entries <- binderTypeEntries binder a+ aEntries <- go a+ bEntries <- inScope binder md a bscope go+ pure (entries ++ aEntries ++ bEntries)++ LetT _ binder manno value body -> do+ let valueType = case typeInfoOf value of+ Just valueInfo -> Just (infoType valueInfo)+ Nothing -> manno+ entries <- maybe (pure []) (binderTypeEntries binder) valueType+ annEntries <- maybe (pure []) go manno+ valueEntries <- go value+ bodyEntries <- inScopeWith binder Id (fromMaybe universeT valueType) (Just value) body go+ pure (entries ++ annEntries ++ valueEntries ++ bodyEntries)++ LetModT _ binder _nu mu manno value body -> do+ unwrapped <- case typeInfoOf value of+ Nothing -> pure Nothing+ Just valueInfo -> do+ let vt = infoType valueInfo+ case modalView (memoWHNF vt) of+ Just a -> pure (Just a)+ Nothing -> (modalView <$> whnfT vt) `catchError` \_ -> pure Nothing+ entries <- maybe (pure []) (binderTypeEntries binder) unwrapped+ annEntries <- maybe (pure []) go manno+ valueEntries <- go value+ bodyEntries <- inScope binder mu (fromMaybe universeT unwrapped) body go+ pure (entries ++ annEntries ++ valueEntries ++ bodyEntries)++ Node (AnnSig _ f) ->+ concat <$> mapM go (bifoldr (\_ acc -> acc) (:) [] f)++ funView t = case stripTypeRestrictions t of+ TypeFunT _ _ _ param mtope _ -> Just (param, mtope)+ _ -> Nothing+ modalView t = case stripTypeRestrictions t of+ TypeModalT _ _ a -> Just a+ _ -> Nothing++ -- A shaped plain binder shows its cube together with the tope, as it is+ -- written: (t : I | φ t). A shaped pair binder splits along the cube, the tope+ -- constraining the components jointly (as in the surface tier).+ shapedBinderEntries+ :: Distinct n+ => Binder -> Maybe (TermT n) -> Maybe (ScopedTermT n)+ -> TypeCheck n [(VarIdent, BinderTypeView)]+ shapedBinderEntries binder mty mtope = case (binder, mty, mtope) of+ (BinderVar (Just x), Just cube, Just tope) -> do+ cubeR <- renderHere cube+ topeR <- inScope binder Id cube tope renderHere+ pure [(x, ShapeView cubeR topeR)]+ (_, Just ty, _) -> binderTypeEntries binder ty+ _ -> pure []++-- | All the local binder types of a declaration: Π and Σ binders from its type,+-- λ and let binders from its value.+declBinderTypes+ :: Distinct n => Decl n -> TypeCheck n [(VarIdent, BinderTypeView)]+declBinderTypes decl =+ (++) <$> binderTypesOfTerm (declType decl)+ <*> maybe (pure []) binderTypesOfTerm (declValue decl)++-- | The elaborated types of the local binders of one file's declarations, with the+-- rest of the run's declarations in scope so that 'whnfT' can unfold definitions+-- when splitting pair binders.+--+-- Pure at the interface: it runs the checker silently and returns no entries where+-- it fails.+binderTypesOfFile :: Checked -> FilePath -> [(VarIdent, BinderTypeView)]+binderTypesOfFile (Checked ctx decls _errs) path =+ case runTypeCheckIn ctx action of+ Left _ -> []+ Right entries -> entries+ where+ fileDecls = concat [ ds | (p, ds) <- decls, p == path ]+ action = localVerbosity Silent $+ concat <$> mapM declBinderTypes fileDecls
+ src/Rzk/TypeCheck/Context.hs view
@@ -0,0 +1,476 @@+-- The scope-extension evidence on the three sinkers that are coercions+-- ('sinkContextUnchecked', 'sinkVars', 'sinkNamed') is their soundness contract,+-- not an argument they can consume, so GHC calls it redundant. It stays.+{-# OPTIONS_GHC -fno-warn-name-shadowing -fno-warn-redundant-constraints #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | The typing context on free-foil.+--+-- The successor of @Rzk.TypeCheck@'s @Context var@. Two things change, and they+-- are the point of the migration.+--+-- [A variable is a name, and so is a top-level entry.] A free-foil term refers to+-- a variable by 'Foil.Name' (an @Int@), and by nothing else: there is no way to+-- put a 'VarIdent' inside a term. So a top-level definition is a name too, bound+-- in the outermost scope with no binder above it, and the hypotheses — global and+-- local alike — are one 'Foil.NameMap', looked up in constant time. The old+-- context was an association list keyed by a @var@ whose equality walked an+-- @S@-chain; @lookupVarInfo@ alone was 11.5% of the checker's time. The surface+-- name of an entry is resolved through 'ctxNamed'.+--+-- This also gives sections their natural shape. A @#assume@d assumption is an+-- ordinary binder, so the definitions of a section are checked in its scope, and+-- closing the section abstracts the assumption by pairing its binder with the+-- body — no rewrite of the elaborated terms (see @Rzk.TypeCheck.Decl@).+--+-- [Entering a binder rebuilds nothing.] 'enterBinder' extends the scope and+-- sinks the rest of the context by coercion, so it costs O(1) rather than a walk+-- of the context. The old @enterScopeContext@ mapped @S \<$\>@ over the whole+-- context, rebuilding every elaborated term it held; the heap profile showed+-- those forced copies retaining most of the live heap, and @GlobalScopeInfo@ /+-- @globalEmbed@ (PR #277) exist only to keep that shift off the ~1500 top-level+-- entries. All of that machinery is gone.+module Rzk.TypeCheck.Context where++import Control.Monad.Foil (DExt, Distinct, NameBinder,+ NameMap, Scope)+import qualified Control.Monad.Foil as Foil+-- NOTE: free-foil 0.2.0 gives 'NameMap' no 'Functor' instance (it has one on the+-- unreleased main), so 'mapNameMap' goes through the underlying 'IntMap'.+import Control.Monad.Foil.Internal (NameMap (..))+import qualified Data.IntMap as IntMap+import Data.Map (Map)+import qualified Data.Map as Map+import Unsafe.Coerce (unsafeCoerce)++import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), TModality (..),+ VarIdent, binderName)+import qualified Language.Rzk.Syntax as Rzk++-- * The pieces of a context++data Covariance+ = Covariant -- ^ Positive position.+ | Contravariant -- ^ Negative position.+ | Invariant -- ^ Unknown position.++data RenderBackend+ = RenderSVG+ | RenderLaTeX++data Verbosity+ = Debug+ | Normal+ | Silent+ deriving (Eq, Ord)++data LocationInfo = LocationInfo+ { locationFilePath :: Maybe FilePath+ , locationLine :: Maybe Int+ } deriving (Eq, Show)++-- | What is known about a hypothesis, local or top-level.+data VarInfo n = VarInfo+ { varType :: TermT n+ , varValue :: Maybe (TermT n)+ , varModality :: TModality+ , varModAccum :: TModality+ , varOrig :: Binder+ -- ^ the names the binder introduced, for display only+ , varIsAssumption :: Bool -- FIXME: perhaps, introduce something like decl kind?+ , varIsTopLevel :: Bool+ , varDeclaredAssumptions :: [Foil.Name n]+ , varLocation :: Maybe LocationInfo+ }++-- | A tope, together with the modalities under which it is available.+data ModalTope n = ModalTope+ { tModAccum :: TModality+ , tModVar :: TModality+ , tTope :: TermT n+ }++-- | The judgement being performed, for tracing and for the error report.+data Action n+ = ActionTypeCheck (Term n) (TermT n)+ | ActionUnify (TermT n) (TermT n) (TermT n)+ | ActionUnifyTerms (TermT n) (TermT n)+ | ActionInfer (Term n)+ | ActionContextEntailedBy [TermT n] (TermT n)+ | ActionContextEntails [TermT n] (TermT n)+ | ActionContextEntailsUnion [TermT n] [TermT n]+ | ActionWHNF (TermT n)+ | ActionNF (TermT n)+ | ActionCheckCoherence (TermT n, TermT n) (TermT n, TermT n)+ | ActionCloseSection (Maybe Rzk.SectionName)+ | ActionCheckLetValue (Maybe VarIdent)++-- | The state of the tope-saturation cache in a 'Context'+-- (see 'ctxTopesSaturated').+data CachedSaturation n+ = SaturationUncached+ -- ^ No cache was installed for this tope context (entailment falls back to+ -- the per-query pipeline).+ | SaturationCached (Maybe [[ModalTope n]])+ -- ^ A deferred pipeline run: forced by the first query under this context.+ -- 'Nothing' records that the pipeline errored; queries then fall back, so+ -- the error surfaces exactly where it would have.++-- * The context++data Context n = Context+ { ctxScope :: Scope n+ -- ^ Every name in scope: the top-level entries, the section assumptions and+ -- the binders entered on the way here. Substitution and freshness need it.+ , ctxVars :: NameMap n (VarInfo n)+ -- ^ What each name in scope stands for. Total on 'ctxScope', which is what+ -- 'Foil.lookupName' assumes.+ , ctxNamed :: Map VarIdent (Foil.Name n)+ -- ^ The surface name of each top-level entry (and of each named binder), for+ -- resolving an identifier the parser produced.+ , ctxBound :: [Foil.Name n]+ -- ^ Every name in scope, most recently bound first.+ --+ -- The order has to be recorded, not recovered: free-foil refreshes a binder+ -- only when its name clashes, so after a substitution an inner binder may+ -- well carry a /smaller/ id than an outer one (@\\ x2 -> \\ x1 -> …@), and the+ -- ascending order of 'ctxVars' is not the order things were bound in. Display+ -- depends on this: names claim their display name oldest-first, so that an+ -- inner binder is the one refreshed away from an outer name, and not the+ -- other way round.+ , ctxSections :: [SectionInfo n]+ -- ^ The open sections, innermost first. Each records the entries declared in+ -- it, so closing it can turn them into declarations.+ , ctxDiscreteTopes :: [ModalTope n]+ -- ^ Discreteness axioms for the flat cube variables in scope (a flat point of+ -- @2@ or @I@ is an endpoint). Maintained at binder entry, so entailment does+ -- not rescan the context on every query.+ , ctxTopes :: [ModalTope n]+ , ctxTopesNF :: [ModalTope n]+ , ctxTopesNFUnion :: [[ModalTope n]]+ , ctxTopesEntailBottom :: Maybe Bool+ , ctxTopesSaturated :: CachedSaturation n+ -- ^ The saturated alternatives for this tope context, cached at the points+ -- where the tope context changes.+ , ctxShadow :: Map VarIdent [VarIdent]+ -- ^ The identifiers in scope, keyed by their spelling (a 'VarIdent' compares by+ -- spelling and carries the position of its defining occurrence, so the values+ -- are what a shadowing report names).+ --+ -- The check runs at every binder entry, and scanning every name in scope each+ -- time was O(context) per binder — with every top-level definition of a project+ -- in scope, that is most of them.+ , ctxActionStack :: [Action n]+ , ctxActionStackDepth :: Int+ -- ^ The length of 'ctxActionStack', maintained alongside it: measuring the+ -- list on every judgement made each action cost O(depth), and each path+ -- O(depth²).+ , ctxCurrentCommand :: Maybe Rzk.Command+ , ctxLocation :: Maybe LocationInfo+ , ctxVerbosity :: Verbosity+ , ctxCovariance :: Covariance+ , ctxRenderBackend :: Maybe RenderBackend+ , ctxRenderHideTerm :: Bool+ -- ^ When rendering a diagram, hide the proof term: drop the @\<title\>@ (which+ -- carries the full term) from every cell and blank the visible label of+ -- proof-coloured (interior) cells, keeping the given boundary labels.+ , ctxHolesAreErrors :: Bool+ -- ^ When 'True' (the default), an unfilled hole is reported as a+ -- @TypeErrorUnsolvedHole@; finished work (and CI) must have no holes. The+ -- lenient mode ('allowHoles') instead records each hole's goal and context.+ , ctxDeferHoleMismatches :: Bool+ -- ^ How holes behave during unification, giving three modes overall. With+ -- 'ctxHolesAreErrors' a hole is rejected outright (strict). Otherwise a hole+ -- always unifies as a leaf; this flag then chooses what happens when the+ -- /surrounding/ structure disagrees: 'True' (the default) defers — any term+ -- containing a hole is accepted, for an in-progress sketch — while 'False'+ -- keeps such a mismatch an error ('structuralHoleUnify').+ , ctxHintLemmas :: [VarIdent]+ -- ^ Named top-level definitions a hole's candidate list may draw on, beyond+ -- the local hypotheses (see 'withHintLemmas').+ , ctxWarnOverhang :: Bool+ -- ^ When 'True', a restriction face or @recOR@ guard that overhangs the+ -- local tope context (is not entailed by it, while still overlapping it)+ -- is reported with a non-fatal hint. Off by default: deciding the+ -- overhang costs a solver entailment per face and guard, and the overhang+ -- is legitimate (see @happy-restrict-face-not-contained@). Enabled with+ -- @#set-option "warn-overhang" "yes"@. The /disjointness/ error next to+ -- it is unaffected: a vacuous face is always rejected.+ }++-- | An open section: the entries declared in it, newest first.+data SectionInfo n = SectionInfo+ { sectionName :: Maybe Rzk.SectionName+ , sectionEntries :: [Foil.Name n]+ }++emptyContext :: Context Foil.VoidS+emptyContext = Context+ { ctxScope = Foil.emptyScope+ , ctxVars = Foil.emptyNameMap+ , ctxNamed = Map.empty+ , ctxBound = []+ , ctxSections = [SectionInfo Nothing []]+ , ctxDiscreteTopes = []+ , ctxTopes = emptyTopeContext+ , ctxTopesNF = emptyTopeContext+ , ctxTopesNFUnion = [emptyTopeContext]+ , ctxTopesEntailBottom = Just False+ , ctxTopesSaturated = SaturationUncached+ , ctxShadow = Map.empty+ , ctxActionStack = []+ , ctxActionStackDepth = 0+ , ctxCurrentCommand = Nothing+ , ctxLocation = Nothing+ , ctxVerbosity = Normal+ , ctxCovariance = Covariant+ , ctxRenderBackend = Nothing+ , ctxRenderHideTerm = False+ , ctxHolesAreErrors = True+ , ctxDeferHoleMismatches = True+ , ctxHintLemmas = []+ , ctxWarnOverhang = False+ }++-- | The tope context of an empty context: @⊤@ holds under every modality.+emptyTopeContext :: [ModalTope n]+emptyTopeContext =+ [ ModalTope Id Id topeTopT+ , ModalTope Id Flat topeTopT+ , ModalTope Id Op topeTopT+ , ModalTope Id Sharp topeTopT+ ]++-- * Entering a binder+--+-- $sinking+--+-- Everything in a context that mentions the scope is a term, or a container of+-- terms, and so is sinkable: a term whose free names lie in @n@ has its free+-- names in any @l@ that extends @n@. free-foil sinks such a value by coercion+-- (@sink = unsafeCoerce@, sound because @DExt n l@ makes the renaming the+-- identity on raw names; see §3.5 of the Foil paper), and the same argument+-- applies to a whole record of them: renaming every field along the identity is+-- the identity on the representation.+--+-- Two fields are /not/ sinkable, and 'enterBinder' restores both in the same+-- breath, which is why the coercion below is not exported:+--+-- * 'ctxScope' is the set of names /in/ @n@. It has to grow, not coerce —+-- tellingly, free-foil gives 'Foil.Scope' no 'Foil.Sinkable' instance.+-- * 'ctxVars' must stay total on the names in scope ('Foil.lookupName' assumes+-- it), so the new binder's entry has to be added.++-- | Sink a context along a scope extension. Unsound on its own: leaves 'ctxScope'+-- and 'ctxVars' describing the /old/ scope, and the caller must fix both. See the+-- note above; 'enterBinder' is the only caller.+sinkContextUnchecked :: DExt n l => Context n -> Context l+sinkContextUnchecked = unsafeCoerce++-- | Enter the scope of a binder: extend the scope with it, record what it is+-- called and what it stands for, and carry the rest of the context in.+enterBinder+ :: DExt n l+ => NameBinder n l+ -> VarInfo n -- ^ its type, value and modality+ -> [ModalTope l] -- ^ discreteness axioms the binder brings (a flat cube point,+ -- which are about the variable itself, hence at its scope)+ -> Context n+ -> Context l+enterBinder binder info discrete ctx = (sinkContextUnchecked ctx)+ { ctxScope = Foil.extendScope binder (ctxScope ctx)+ , ctxVars = Foil.addNameBinder binder (Foil.sink info) (sinkVars (ctxVars ctx))+ , ctxBound = Foil.nameOf binder : sinkNames (ctxBound ctx)+ , ctxNamed = case binderName (varOrig info) of+ Nothing -> sinkNamed (ctxNamed ctx)+ Just name -> Map.insert name (Foil.nameOf binder) (sinkNamed (ctxNamed ctx))+ , ctxDiscreteTopes = discrete <> sinkTopes (ctxDiscreteTopes ctx)+ , ctxShadow = addBinderNames (varOrig info) (ctxShadow ctx)+ }++-- | Enter a /fresh/ binder: one the checker invents rather than one a term+-- carries (to look under a Π when comparing two of them, say).+withFreshBinder+ :: Distinct n+ => Context n+ -> VarInfo n+ -> (forall l. DExt n l => NameBinder n l -> Context l -> r)+ -> r+withFreshBinder ctx info k =+ Foil.withFresh (ctxScope ctx) $ \binder ->+ k binder (enterBinder binder info [] ctx)++-- | Record the name a binder introduces (if any), for the shadowing check.+addBinderNames :: Binder -> Map VarIdent [VarIdent] -> Map VarIdent [VarIdent]+addBinderNames orig names =+ case binderName orig of+ Nothing -> names+ Just name -> Map.insertWith (<>) name [name] names++-- | The identifiers in scope spelled like this one.+shadowedBy :: VarIdent -> Context n -> [VarIdent]+shadowedBy name ctx = Map.findWithDefault [] name (ctxShadow ctx)++-- * Sinking the parts++instance Foil.Sinkable VarInfo where+ sinkabilityProof rename info = info+ { varType = Foil.sinkabilityProof rename (varType info)+ , varValue = Foil.sinkabilityProof rename <$> varValue info+ , varDeclaredAssumptions = rename <$> varDeclaredAssumptions info+ }++instance Foil.Sinkable ModalTope where+ sinkabilityProof rename tope =+ tope { tTope = Foil.sinkabilityProof rename (tTope tope) }++sinkVars :: DExt n l => NameMap n (VarInfo n) -> NameMap n (VarInfo l)+sinkVars = Foil.sinkContainer++sinkTopes :: DExt n l => [ModalTope n] -> [ModalTope l]+sinkTopes = Foil.sinkContainer++sinkNamed :: DExt n l => Map VarIdent (Foil.Name n) -> Map VarIdent (Foil.Name l)+sinkNamed = Foil.sinkContainer++sinkNames :: DExt n l => [Foil.Name n] -> [Foil.Name l]+sinkNames = Foil.sinkContainer++-- * Lookup++-- | What a name stands for. Total: every name in scope has an entry.+lookupVarInfo :: Foil.Name n -> Context n -> VarInfo n+lookupVarInfo name ctx = Foil.lookupName name (ctxVars ctx)++-- | What every name in scope stands for, in no particular order.+varInfos :: Context n -> [VarInfo n]+varInfos ctx = IntMap.elems m+ where+ NameMap m = ctxVars ctx++-- | Every hypothesis in scope, oldest binding first (see 'ctxBound': the ids+-- themselves do not tell us this).+varsInScope :: Context n -> [(Foil.Name n, VarInfo n)]+varsInScope ctx =+ [ (name, lookupVarInfo name ctx) | name <- reverse (ctxBound ctx) ]++-- | The name a surface identifier resolves to, if any.+lookupNamed :: VarIdent -> Context n -> Maybe (Foil.Name n)+lookupNamed name ctx = Map.lookup name (ctxNamed ctx)++-- | The display binder of a name (the whole pattern, for projection folding).+binderOfName :: Foil.Name n -> Context n -> Binder+binderOfName name = varOrig . lookupVarInfo name++-- * Modalities++class ModeTheory m where+ iden :: m+ comp :: m -> m -> m+ coe :: m -> m -> Bool+ isRA :: m -> Bool++instance ModeTheory TModality where+ iden = Id++ comp Flat Flat = Flat+ comp Flat Sharp = Flat+ comp Flat Op = Flat+ comp Op Flat = Flat+ comp Sharp Sharp = Sharp+ comp Sharp Flat = Sharp+ comp Sharp Op = Sharp+ comp Op Sharp = Sharp+ comp Op Op = Id+ comp Id m = m+ comp m Id = m++ coe Flat Id = True+ coe Flat Op = True+ coe Id Sharp = True+ coe Flat Sharp = True+ coe Op Sharp = True+ coe a b = a == b++ isRA Sharp = True+ isRA Op = True+ isRA Id = True+ isRA _ = False++-- | Accumulate a modality (a lock) over the hypotheses and the topes.+--+-- Note that top-level entries are /not/ touched: a top-level variable is exempt+-- from the accessibility check (see @infer@), so accumulating a modality over+-- them was work with no observable effect. The old context did it to all ~1500+-- of them on every modal binder.+applyModality :: TModality -> Context n -> Context n+applyModality md ctx = ctx+ { ctxVars = mapNameMap addToVar (ctxVars ctx)+ , ctxTopes = map addToTope (ctxTopes ctx)+ , ctxTopesNF = map addToTope (ctxTopesNF ctx)+ , ctxTopesNFUnion = map (map addToTope) (ctxTopesNFUnion ctx)+ , ctxTopesSaturated = SaturationUncached -- accessibility changed+ }+ where+ addToVar info+ | varIsTopLevel info = info+ | otherwise = info { varModAccum = comp (varModAccum info) md }+ addToTope tope = tope { tModAccum = comp (tModAccum tope) md }++-- | Map the values of a name map, keeping its keys.+mapNameMap :: (a -> b) -> NameMap n a -> NameMap n b+mapNameMap f (NameMap m) = NameMap (IntMap.map f m)++-- | Replace what a name stands for.+--+-- Closing a section rewrites the definitions made in it, so that each takes the+-- section's assumptions as explicit parameters; this is how the rewritten entries+-- go back into the context.+insertVarInfo :: Foil.Name n -> VarInfo n -> Context n -> Context n+insertVarInfo name info ctx = ctx { ctxVars = replace (ctxVars ctx) }+ where+ replace (NameMap m) = NameMap (IntMap.insert (Foil.nameId name) info m)++-- * Topes++isAccessible :: ModalTope n -> Bool+isAccessible mt = coe (tModVar mt) (tModAccum mt)++filterAccessible :: [ModalTope n] -> [ModalTope n]+filterAccessible = filter isAccessible++accessibleTopes :: [ModalTope n] -> [TermT n]+accessibleTopes = map tTope . filterAccessible++plainTope :: TermT n -> ModalTope n+plainTope = ModalTope Id Id++availableTopes :: Context n -> [TermT n]+availableTopes = accessibleTopes . ctxTopes++availableTopesNF :: Context n -> [TermT n]+availableTopesNF = accessibleTopes . ctxTopesNF++-- * Hole modes++-- | Switch to lenient hole mode: record each hole's goal and context instead of+-- reporting it as an error.+allowHoles :: Context n -> Context n+allowHoles ctx = ctx { ctxHolesAreErrors = False }++-- | Allow a hole's candidate list to draw on the given named top-level+-- definitions, in addition to the local hypotheses.+withHintLemmas :: [VarIdent] -> Context n -> Context n+withHintLemmas lemmas ctx = ctx { ctxHintLemmas = lemmas }++-- | Within the given action, a hole unifies only as a leaf of an otherwise+-- matching structure: a structural mismatch around a hole stays an error rather+-- than being deferred (see 'ctxDeferHoleMismatches').+structuralHoleUnify :: Context n -> Context n+structuralHoleUnify ctx = ctx { ctxDeferHoleMismatches = False }
+ src/Rzk/TypeCheck/Decl.hs view
@@ -0,0 +1,735 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Declarations, sections, commands, and the public entry points.+--+-- A top-level entry is a name bound in the outermost scope, so the scope /grows/+-- as a module is checked: each @#define@, @#postulate@ and @#assume@ enters a+-- binder and the rest of the module is checked under it. The driver is therefore+-- written in continuation-passing style, and the result is packaged with the scope+-- it was produced in ('Checked').+--+-- That also gives sections their shape. A @#assume@d assumption is an ordinary+-- binder, and closing the section abstracts it out of the definitions that used it+-- (@makeAssumptionExplicit@), rewriting the later definitions to apply them to it.+module Rzk.TypeCheck.Decl where++import Control.Monad (forM, when)+import Control.Monad.Except (catchError, runExcept)+import Control.Monad.Reader (ask, asks, local, runReaderT)+import Control.Monad.Trans.Writer.CPS (runWriterT)+import Data.List (intercalate)+import qualified Data.Map as Map+import Debug.Trace (trace)++import Control.Monad.Foil (DExt, Distinct, NameBinder)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Free.Foil (AST (Var), ScopedAST (..))++import Language.Rzk.Foil.Convert (Env, toTerm)+import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), TModality (..),+ VarIdent, binderName, markUnresolved,+ patternToTerm, varIdentAt)+import qualified Language.Rzk.Syntax as Rzk+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Display+import Rzk.TypeCheck.Error+import Rzk.TypeCheck.Eval+import Rzk.TypeCheck.Judgements+import Rzk.TypeCheck.Monad+import Rzk.TypeCheck.Render++-- * Declarations++-- FIXME: merge with VarInfo+data Decl n = Decl+ { declName :: VarIdent+ -- ^ the surface name, as the user wrote it (with its source position)+ , declNameOf :: Foil.Name n+ -- ^ the name it is bound to in the top-level scope+ , declType :: TermT n+ , declValue :: Maybe (TermT n)+ , declIsAssumption :: Bool+ , declUsedVars :: [Foil.Name n]+ , declLocation :: Maybe LocationInfo+ }++-- | A declaration sinks along a scope extension, by coercion (see the note in+-- "Rzk.TypeCheck.Context").+sinkDecl :: DExt n l => Decl n -> Decl l+sinkDecl decl = decl+ { declNameOf = Foil.sink (declNameOf decl)+ , declType = Foil.sink (declType decl)+ , declValue = Foil.sink <$> declValue decl+ , declUsedVars = Foil.sink <$> declUsedVars decl+ }++-- | What a run of the checker produced: the top-level scope, the declarations in+-- it, and the errors found.+--+-- The scope is existential, and the declarations live in it. Anything that wants+-- to /resume/ from a checked prefix (the LSP's incremental path) keeps the whole+-- package and carries on from that context; anything that only displays them reads+-- them through the context's naming.+data Checked where+ Checked+ :: Distinct n+ => Context n+ -> [(FilePath, [Decl n])]+ -> [TypeErrorInScopedContext]+ -> Checked++-- * Entering a top-level entry++-- | Bind a top-level entry and run the rest of the module under it.+withTopLevel+ :: Distinct n+ => VarIdent -- ^ the surface name+ -> TermT n -- ^ its type+ -> Maybe (TermT n) -- ^ its value, for a definition+ -> Bool -- ^ is it an assumption (a @#assume@)?+ -> [Foil.Name n] -- ^ the variables it declared it uses+ -> (forall l. (DExt n l, Distinct l) => NameBinder n l -> Decl l -> TypeCheck l r)+ -> TypeCheck n r+withTopLevel name ty mval isAssumption usedVars k = do+ checkTopLevelDuplicate name+ ctx <- ask+ Foil.withFresh (ctxScope ctx) $ \binder -> do+ let info = VarInfo+ { varType = ty+ , varValue = mval+ , varModality = Id+ , varModAccum = Id+ , varOrig = BinderVar (Just name)+ , varIsAssumption = isAssumption+ , varIsTopLevel = True+ , varDeclaredAssumptions = usedVars+ , varLocation = ctxLocation ctx+ }+ ctx' = recordInSection (Foil.nameOf binder) (enterBinder binder info [] ctx)+ decl = Decl+ { declName = name+ , declNameOf = Foil.nameOf binder+ , declType = Foil.sink ty+ , declValue = Foil.sink <$> mval+ , declIsAssumption = isAssumption+ , declUsedVars = Foil.sink <$> usedVars+ , declLocation = ctxLocation ctx+ }+ inContext ctx' (k binder decl)++-- | Record a new entry in the innermost open section.+recordInSection :: Foil.Name n -> Context n -> Context n+recordInSection name ctx = ctx+ { ctxSections = case ctxSections ctx of+ [] -> [SectionInfo Nothing [name]]+ s : rest -> s { sectionEntries = name : sectionEntries s } : rest+ }++-- * Sections++startSection :: Maybe Rzk.SectionName -> TypeCheck n a -> TypeCheck n a+startSection name = local $ \ctx -> ctx+ { ctxSections = SectionInfo name [] : ctxSections ctx }++-- | Close a section: abstract each of its assumptions out of the definitions that+-- used it, report the ones that went unused, and take the assumptions back out of+-- scope.+--+-- The definitions stay in scope, with their entries rewritten to take the+-- assumption as an explicit parameter. The assumptions' names stay in the /scope+-- index/ — a scope only ever grows — but they are removed from the surface-name map+-- and from the list of what is in scope, so they can no longer be referred to,+-- shown, or shadowed.+endSection+ :: Distinct n+ => [TypeErrorInScopedContext]+ -> TypeCheck n ([Decl n], [TypeErrorInScopedContext], Context n)+endSection errs = do+ ctx <- ask+ let entries = case ctxSections ctx of+ [] -> []+ s : _ -> sectionEntries s -- newest first+ infos = [ (name, lookupVarInfo name ctx) | name <- entries ]++ -- In lenient (hole-checking) mode an as-yet-unfilled hole may still come to use a+ -- declared variable, so we tolerate the unused-variable diagnostics wherever such+ -- a hole is present anywhere in the section. This covers both an unused section+ -- assumption and an unused 'uses' variable, and crucially a hole-free definition+ -- whose body refers to an in-progress (hole-bearing) one: its 'uses' reads as+ -- unused only because the referenced definition is incomplete. Strict mode (the+ -- default, and CI) keeps reporting both.+ lenient <- not <$> asks ctxHolesAreErrors+ let sectionHasHole = any (maybe False containsHole . varValue . snd) infos+ tolerateUnused = lenient && sectionHasHole++ (kept, errs') <- collectSectionDecls tolerateUnused errs [] infos++ loc <- asks ctxLocation+ let decls = map (toDecl loc) kept+ assumptions = [ name | (name, info) <- infos, varIsAssumption info ]+ isAssumption v = any (sameName v) assumptions+ -- the names the section's assumptions were written with, which leave scope+ assumedNames =+ [ x | (_, info) <- infos, varIsAssumption info+ , Just x <- [binderName (varOrig info)] ]++ -- the definitions of the section are now abstracted over its assumptions+ ctx' = foldr (uncurry insertVarInfo) ctx+ { ctxSections = closeInnermost (ctxSections ctx)+ , ctxBound = filter (not . isAssumption) (ctxBound ctx)+ , ctxNamed = Map.filter (not . isAssumption) (ctxNamed ctx)+ , ctxShadow = foldr Map.delete (ctxShadow ctx) assumedNames+ } kept++ -- The section's definitions outlive it, so the enclosing section adopts+ -- them: closing /that/ one must see them too, and abstract them over its own+ -- assumptions in turn.+ closeInnermost sections = case drop 1 sections of+ [] -> []+ s : rest -> s { sectionEntries = reverse (map fst kept) <> sectionEntries s } : rest++ -- only issue unused-variable errors if there were none before in the section+ unusedErrors <- fmap concat $ forM decls $ \decl -> do+ let unusedUsedVars = [ v | v <- declUsedVars decl, isAssumption v ]+ if null errs && not (null unusedUsedVars) && not tolerateUnused+ then local (\c -> c { ctxLocation = declLocation decl }) $ do+ err <- typeErrorHere (TypeErrorUnusedUsedVariables unusedUsedVars (declNameOf decl))+ return [err]+ else return []++ pure (decls, errs' <> unusedErrors, ctx')+ where+ sameName a b = Foil.nameId a == Foil.nameId b++ toDecl loc (name, info) = Decl+ { declName = case varOrig info of+ BinderVar (Just x) -> x+ _ -> "_"+ , declNameOf = name+ , declType = varType info+ , declValue = varValue info+ , declIsAssumption = varIsAssumption info+ , declUsedVars = varDeclaredAssumptions info+ , declLocation = loc+ }++-- | An error, captured in the current context (rather than thrown).+typeErrorHere :: Distinct n => TypeError n -> TypeCheck n TypeErrorInScopedContext+typeErrorHere err = do+ ctx <- ask+ pure (TypeErrorInScopedContext ctx err)++-- | Turn the section's entries into declarations, abstracting each assumption out+-- of the definitions that follow it.+--+-- The entries come newest first, so the definitions accumulated in @recent@ are+-- exactly those that could have used the assumption currently being processed.+collectSectionDecls+ :: Distinct n+ => Bool -- ^ tolerate unused variables+ -> [TypeErrorInScopedContext]+ -> [(Foil.Name n, VarInfo n)] -- ^ the definitions seen so far (oldest last)+ -> [(Foil.Name n, VarInfo n)] -- ^ the entries still to process (newest first)+ -> TypeCheck n ([(Foil.Name n, VarInfo n)], [TypeErrorInScopedContext])+collectSectionDecls _tolerate errs recent [] = pure (recent, errs)+collectSectionDecls tolerate errs recent (entry@(name, info) : rest)+ | varIsAssumption info = do+ (used, recent') <- makeAssumptionExplicit entry recent+ unusedErr <-+ if null errs && not used && not tolerate+ then local (\c -> c { ctxLocation = varLocation info }) $+ pure <$> typeErrorHere (TypeErrorUnusedVariable name (varType info))+ else return []+ collectSectionDecls tolerate (errs <> unusedErr) recent' rest+ | otherwise =+ collectSectionDecls tolerate errs (entry : recent) rest++-- | Abstract one assumption out of the definitions that come after it.+--+-- A definition that mentions the assumption gains it as an explicit parameter, and+-- every later definition that mentions /that/ definition is rewritten to apply it+-- to the assumption. A definition that mentions it without declaring it in its+-- @uses@ clause is an implicit assumption, and an error.+makeAssumptionExplicit+ :: Distinct n+ => (Foil.Name n, VarInfo n)+ -> [(Foil.Name n, VarInfo n)]+ -> TypeCheck n (Bool, [(Foil.Name n, VarInfo n)])+makeAssumptionExplicit _ [] = pure (False {- UNUSED -}, [])+makeAssumptionExplicit assumption@(a, aInfo) ((x, xInfo) : xs) = do+ scope <- asks ctxScope+ -- Two notions of use, and the difference between them is what 'implicit' means.+ -- The deep one follows the types of the variables the entry mentions, so it sees+ -- a dependency the entry never names; the shallow one is a syntactic occurrence.+ deepVars <- do+ inTy <- freeVarsDeep (varType xInfo)+ inVal <- concat <$> traverse freeVarsDeep (varValue xInfo)+ pure (inTy <> inVal)+ -- The syntactic check reads the declaration as the user wrote it, from the+ -- context — not the entry, which the assumptions abstracted before this one have+ -- already rewritten (and which therefore mentions them).+ written <- asks (lookupVarInfo x)+ let hasAssumption = a `elemName` deepVars+ inTypeSyntactically = a `elemName` freeVarsOfTermT (varType written)+ inBodySyntactically = any (elemName a . freeVarsOfTermT) (varValue written)+ declared = a `elemName` varDeclaredAssumptions xInfo+ -- used, but never written down: neither in the type, nor in the body, nor in+ -- the 'uses' clause+ implicit = and+ [ hasAssumption+ , not (inTypeSyntactically || inBodySyntactically)+ , not declared+ ]+ if hasAssumption+ then do+ when implicit $+ issueTypeError $ TypeErrorImplicitAssumption (a, varType aInfo) x+ let xInfo' = abstractOver scope a aInfo xInfo+ xs' = map (fmap (applyToAssumption scope a (x, xInfo'))) xs+ (_used, xs'') <- makeAssumptionExplicit assumption xs'+ return (True {- USED -}, (x, xInfo') : xs'')+ else do+ (used, xs'') <- makeAssumptionExplicit assumption xs+ return (used, (x, xInfo) : xs'')++-- | Give an entry the assumption as an explicit parameter.+abstractOver+ :: Distinct n+ => Foil.Scope n -> Foil.Name n -> VarInfo n -> VarInfo n -> VarInfo n+abstractOver scope a aInfo info = info+ { varType = newType+ , varValue = fmap abstractValue (varValue info)+ , varModality = Id+ , varModAccum = Id+ , varDeclaredAssumptions =+ filter (\v -> Foil.nameId v /= Foil.nameId a) (varDeclaredAssumptions info)+ }+ where+ orig = varOrig aInfo+ newType =+ abstractName scope a (varType info) $ \binder body ->+ typeFunT orig Id (varType aInfo) Nothing (ScopedAST binder body)+ abstractValue value =+ abstractName scope a value $ \binder body ->+ lambdaT newType orig Nothing (ScopedAST binder body)++-- | Rewrite every use of a definition into an application of it to the assumption+-- it has just been abstracted over.+applyToAssumption+ :: Distinct n+ => Foil.Scope n -> Foil.Name n -> (Foil.Name n, VarInfo n) -> VarInfo n -> VarInfo n+applyToAssumption scope a (defName, defInfo) info+ | varIsAssumption info = info+ | otherwise = info+ { varType = rewrite (varType info)+ , varValue = rewrite <$> varValue info+ }+ where+ applied = appT (varType defInfo) (Var defName) (Var a)+ rewrite = substituteName scope defName applied++-- * Commands++countCommands :: Integral a => [Rzk.Command] -> a+countCommands = fromIntegral . length++setOption :: Distinct n => String -> String -> TypeCheck n a -> TypeCheck n a+setOption "verbosity" = \case+ "debug" -> localVerbosity Debug+ "normal" -> localVerbosity Normal+ "silent" -> localVerbosity Silent+ _ -> const $+ issueTypeError $ TypeErrorOther "unknown verbosity level (use \"debug\", \"normal\", or \"silent\")"+setOption "render" = \case+ "svg" -> localRenderBackend (Just RenderSVG)+ "latex" -> localRenderBackend (Just RenderLaTeX)+ "none" -> localRenderBackend Nothing+ _ -> const $+ issueTypeError $ TypeErrorOther "unknown render backend (use \"svg\", \"latex\", or \"none\")"+-- Render the shape only, hiding the proof term (drop the <title> everywhere and+-- blank interior labels), so a worked term can be shown as the cell it builds+-- without giving the term away.+setOption "render-hide-term" = \case+ "yes" -> localHideTerm True+ "no" -> localHideTerm False+ _ -> const $+ issueTypeError $ TypeErrorOther "unknown value for \"render-hide-term\" (use \"yes\" or \"no\")"+-- The overhang hint costs a solver entailment per restriction face and recOR+-- guard, so it is off by default and opted into per module (or scope).+setOption "warn-overhang" = \case+ "yes" -> localWarnOverhang True+ "no" -> localWarnOverhang False+ _ -> const $+ issueTypeError $ TypeErrorOther "unknown value for \"warn-overhang\" (use \"yes\" or \"no\")"+setOption optionName = const $ const $+ issueTypeError $ TypeErrorOther ("unknown option " <> show optionName)++unsetOption :: Distinct n => String -> TypeCheck n a -> TypeCheck n a+unsetOption "verbosity" = localVerbosity (ctxVerbosity emptyContext)+unsetOption "render" = localRenderBackend (ctxRenderBackend emptyContext)+unsetOption "render-hide-term" = localHideTerm (ctxRenderHideTerm emptyContext)+unsetOption "warn-overhang" = localWarnOverhang (ctxWarnOverhang emptyContext)+unsetOption optionName = const $+ issueTypeError $ TypeErrorOther ("unknown option " <> show optionName)++paramToParamDecl :: Distinct n => Rzk.Param -> TypeCheck n [Rzk.ParamDecl]+paramToParamDecl (Rzk.ParamPatternShapeDeprecated loc pat cube tope) = pure+ [ Rzk.ParamTermShape loc (patternToTerm pat) cube tope ]+paramToParamDecl (Rzk.ParamPatternShape loc pats cube tope) = pure+ [ Rzk.ParamTermShape loc (patternToTerm pat) cube tope | pat <- pats]+paramToParamDecl (Rzk.ParamPatternType loc pats ty) = pure+ [ Rzk.ParamTermType loc (patternToTerm pat) ty | pat <- pats ]+paramToParamDecl Rzk.ParamPattern{} = issueTypeError $+ TypeErrorOther "untyped pattern in parameters"+paramToParamDecl (Rzk.ParamPatternModalType loc pats mc ty) = pure+ [ Rzk.ParamTermModalType loc (patternToTerm pat) mc ty | pat <- pats ]+paramToParamDecl (Rzk.ParamPatternModalShape loc pats mc cube tope) = pure+ [ Rzk.ParamTermModalShape loc (patternToTerm pat) mc cube tope | pat <- pats ]++addParamDecls :: [Rzk.ParamDecl] -> Rzk.Term -> Rzk.Term+addParamDecls [] = id+addParamDecls (paramDecl : paramDecls)+ = Rzk.TypeFun Nothing paramDecl . addParamDecls paramDecls++addParams :: [Rzk.Param] -> Rzk.Term -> Rzk.Term+addParams [] = id+addParams params = Rzk.Lambda Nothing params++-- | Run a command, recording which one it is and where.+--+-- An error raised anywhere in the command (or in the rest of the module, which is+-- checked inside it) is /collected/ rather than thrown: the declarations made+-- before it stand, the error is reported, and the rest of the module is skipped.+-- The strict entry points turn the first collected error back into a thrown one.+withCommand+ :: Rzk.Command+ -> ([Decl n] -> [TypeErrorInScopedContext] -> TypeCheck n r)+ -> TypeCheck n r+ -> TypeCheck n r+withCommand command k action =+ local atCommand (action `catchError` \err -> k [] [err])+ where+ atCommand ctx = ctx+ { ctxCurrentCommand = Just command+ , ctxLocation = updatePosition (Rzk.hasPosition command) <$> ctxLocation ctx+ }+ updatePosition pos loc = loc { locationLine = fst <$> pos }++-- | Elaborate a surface term in the current top-level scope: a free identifier+-- resolves to the top-level entry it names.+elaborate :: forall n. Distinct n => Rzk.Term -> TypeCheck n (Term n)+elaborate term = do+ ctx <- ask+ let env :: Env n+ env name = case lookupNamed name ctx of+ Just v -> Var v+ Nothing -> Hole (Just (markUnresolved name))+ pure (toTerm (ctxScope ctx) env term)++-- | Is a surface identifier defined at the top level?+checkDefined :: Distinct n => VarIdent -> TypeCheck n (Foil.Name n)+checkDefined name = asks (lookupNamed name) >>= \case+ Just v -> pure v+ Nothing -> issueTypeError (TypeErrorUndefined name)++splitSectionCommands+ :: Distinct n+ => Rzk.SectionName -> [Rzk.Command] -> TypeCheck n ([Rzk.Command], [Rzk.Command])+splitSectionCommands name [] =+ issueTypeError (TypeErrorOther $ "Section " <> Rzk.printTree name <> " is not closed with an #end")+splitSectionCommands name (Rzk.CommandSection _loc name' : moreCommands) = do+ (cs1, cs2) <- splitSectionCommands name' moreCommands+ (cs3, cs4) <- splitSectionCommands name cs2+ return (cs1 <> cs3, cs4)+splitSectionCommands name (Rzk.CommandSectionEnd _loc endName : moreCommands) = do+ when (Rzk.printTree name /= Rzk.printTree endName) $+ issueTypeError $ TypeErrorOther $+ "unexpected #end " <> Rzk.printTree endName <> ", expecting #end " <> Rzk.printTree name+ return ([], moreCommands)+splitSectionCommands name (command : moreCommands) = do+ (cs1, cs2) <- splitSectionCommands name moreCommands+ return (command : cs1, cs2)++-- * The module driver++-- | Check a module's commands, extending the scope with each definition.+--+-- The continuation runs in the /final/ scope, with the declarations the module+-- produced (sunk into it) and the errors found.+checkCommands+ :: forall n r. Distinct n+ => Maybe FilePath -> Integer -> Integer -> [Rzk.Command]+ -> (forall l. (DExt n l, Distinct l)+ => [Decl l] -> [TypeErrorInScopedContext] -> TypeCheck l r)+ -> TypeCheck n r+checkCommands path i total commands k = case commands of+ [] -> k [] []++ command@(Rzk.CommandUnsetOption _loc optionName) : more ->+ announce ("Unsetting option " <> optionName) $+ withCommand command k $+ unsetOption optionName $+ checkCommands path (i + 1) total more k++ command@(Rzk.CommandSetOption _loc optionName optionValue) : more ->+ announce ("Setting option " <> optionName <> " = " <> optionValue) $+ withCommand command k $+ setOption optionName optionValue $+ checkCommands path (i + 1) total more k++ command@(Rzk.CommandDefine _loc name (Rzk.DeclUsedVars _ vars) params ty term) : more ->+ announce (" Checking #define " <> Rzk.printTree name) $+ withCommand command k $ do+ used <- mapM (checkDefined . varIdentAt path) vars+ paramDecls <- concat <$> mapM paramToParamDecl params+ -- Store the elaborated type and term unreduced, but memoise their WHNF on+ -- the top node. Reducing in place would discard or expose a variable+ -- occurrence, so the section unused/implicit-assumption checks (run over the+ -- stored type and value) would disagree with the term the user wrote;+ -- keeping the WHNF cached preserves the original one-shot reduction.+ tyTerm <- elaborate (addParamDecls paramDecls ty)+ ty' <- memoizeWHNF =<< typecheck tyTerm universeT+ valTerm <- elaborate (addParams params term)+ term' <- memoizeWHNF =<< typecheck valTerm ty'+ withTopLevel (varIdentAt path name) ty' (Just term') False used $ \binder decl -> do+ backend <- asks ctxRenderBackend+ termSVG <- case backend of+ Just RenderSVG -> renderTermSVG (Var (Foil.nameOf binder))+ Just RenderLaTeX -> issueTypeError $+ TypeErrorOther "\"latex\" rendering is not yet supported"+ Nothing -> pure Nothing+ maybe id trace termSVG $+ checkCommands path (i + 1) total more $ \decls errs ->+ k (sinkDecl decl : decls) errs++ command@(Rzk.CommandPostulate _loc name (Rzk.DeclUsedVars _ vars) params ty) : more ->+ announce (" Checking #postulate " <> Rzk.printTree name) $+ withCommand command k $ do+ used <- mapM (checkDefined . varIdentAt path) vars+ paramDecls <- concat <$> mapM paramToParamDecl params+ tyTerm <- elaborate (addParamDecls paramDecls ty)+ ty' <- memoizeWHNF =<< typecheck tyTerm universeT+ withTopLevel (varIdentAt path name) ty' Nothing False used $ \_binder decl ->+ checkCommands path (i + 1) total more $ \decls errs ->+ k (sinkDecl decl : decls) errs++ command@(Rzk.CommandAssume _loc names ty) : more ->+ announce (" Checking #assume "+ <> intercalate " " [ Rzk.printTree name | name <- names ]) $+ withCommand command k $ do+ tyTerm <- elaborate ty+ ty' <- typecheck tyTerm universeT+ assume (map (varIdentAt path) names) ty' $ \assumed ->+ checkCommands path (i + 1) total more $ \decls errs ->+ k (map sinkDecl assumed <> decls) errs++ command@(Rzk.CommandCheck _loc term ty) : more ->+ announce (" Checking " <> Rzk.printTree term <> " : " <> Rzk.printTree ty) $+ withCommand command k $ do+ tyTerm <- elaborate ty+ ty' <- typecheck tyTerm universeT >>= whnfT+ termTerm <- elaborate term+ _term' <- typecheck termTerm ty'+ checkCommands path (i + 1) total more k++ Rzk.CommandCompute loc term : more ->+ checkCommands path i total (Rzk.CommandComputeWHNF loc term : more) k++ command@(Rzk.CommandComputeNF _loc term) : more ->+ announce (" Computing NF for " <> Rzk.printTree term) $+ withCommand command k $ do+ term' <- elaborate term >>= infer >>= nfT+ shown <- ppInContext term'+ traceTypeCheck Normal (" " <> shown) $+ checkCommands path (i + 1) total more k++ command@(Rzk.CommandComputeWHNF _loc term) : more ->+ announce (" Computing WHNF for " <> Rzk.printTree term) $+ withCommand command k $ do+ term' <- elaborate term >>= infer >>= whnfT+ shown <- ppInContext term'+ traceTypeCheck Normal (" " <> shown) $+ checkCommands path (i + 1) total more k++ command@(Rzk.CommandSection _loc name) : more ->+ withCommand command k $ do+ (sectionCommands, more') <- splitSectionCommands name more+ withSection (Just name) i sectionCommands path total $ \sectionDecls sectionErrs ->+ if null sectionErrs+ then checkCommands path (i + countCommands sectionCommands) total more' $+ \decls errs -> k (map sinkDecl sectionDecls <> decls) errs+ else k sectionDecls sectionErrs++ command@(Rzk.CommandSectionEnd _loc endName) : _more ->+ withCommand command k $+ issueTypeError $ TypeErrorOther $+ "unexpected #end " <> Rzk.printTree endName <> ", no section was declared!"+ where+ announce :: String -> TypeCheck n a -> TypeCheck n a+ announce what =+ traceTypeCheck Normal+ ("[ " <> show i <> " out of " <> show total <> " ]" <> what)++-- | Assume a list of names of the same type, each a top-level entry.+assume+ :: Distinct n+ => [VarIdent] -> TermT n+ -> (forall l. (DExt n l, Distinct l) => [Decl l] -> TypeCheck l r)+ -> TypeCheck n r+assume [] _ty k = k []+assume (name : names) ty k =+ withTopLevel name ty Nothing True [] $ \_binder decl ->+ assume names (Foil.sink ty) $ \decls ->+ k (sinkDecl decl : decls)++-- | Check the commands of a section, then close it.+withSection+ :: forall n r. Distinct n+ => Maybe Rzk.SectionName -> Integer -> [Rzk.Command] -> Maybe FilePath -> Integer+ -> (forall l. (DExt n l, Distinct l)+ => [Decl l] -> [TypeErrorInScopedContext] -> TypeCheck l r)+ -> TypeCheck n r+withSection name i sectionCommands path total k =+ startSection name $+ checkCommands path i total sectionCommands $ \_decls errs ->+ performing (ActionCloseSection name) $ do+ result <- (Right <$> endSection errs) `catchError` (return . Left)+ case result of+ Left err -> k [] (errs <> [err])+ Right (decls', errs', ctx') -> inContext ctx' (k decls' errs')++-- | Check one module.+checkModule+ :: forall n r. Distinct n+ => Maybe FilePath -> Rzk.Module+ -> (forall l. (DExt n l, Distinct l)+ => [Decl l] -> [TypeErrorInScopedContext] -> TypeCheck l r)+ -> TypeCheck n r+checkModule path (Rzk.Module _moduleLoc _lang commands) k =+ -- FIXME: use the module name? or an anonymous section?+ withSection Nothing 1 commands path (countCommands commands) k++checkModuleWithLocation+ :: Distinct n+ => (FilePath, Rzk.Module)+ -> (forall l. (DExt n l, Distinct l)+ => [Decl l] -> [TypeErrorInScopedContext] -> TypeCheck l r)+ -> TypeCheck n r+checkModuleWithLocation (path, module_) k =+ traceTypeCheck Normal ("Checking module from " <> path) $+ withLocation (LocationInfo { locationFilePath = Just path, locationLine = Nothing }) $+ checkModule (Just path) module_ k++-- | Check a list of modules, one after another, in a scope that grows as it goes.+--+-- Checking stops at the first module with an error, as it did before.+checkModules+ :: forall n r. Distinct n+ => [(FilePath, Rzk.Module)]+ -> (forall l. (DExt n l, Distinct l)+ => [(FilePath, [Decl l])] -> [TypeErrorInScopedContext] -> TypeCheck l r)+ -> TypeCheck n r+checkModules [] k = k [] []+checkModules (m@(path, _) : ms) k =+ checkModuleWithLocation m $ \decls errs ->+ case errs of+ _:_ -> k [(path, decls)] errs+ _ -> checkModules ms $ \rest errors ->+ k ((path, map sinkDecl decls) : rest) errors++-- * The public entry points++-- | Check the modules, and package the result with the scope it was checked in.+checkedModules :: [(FilePath, Rzk.Module)] -> Context Foil.VoidS -> Either TypeErrorInScopedContext (Checked, [HoleInfo])+checkedModules modules ctx =+ runExcept $ runWriterT $ flip runReaderT ctx $+ checkModules modules $ \decls errs -> do+ ctx' <- ask+ pure (Checked ctx' decls errs)++-- | Check the modules strictly: an unfilled hole is an error, and the first error+-- stops the run.+typecheckModules+ :: [(FilePath, Rzk.Module)] -> Either TypeErrorInScopedContext Checked+typecheckModules modules = do+ (checked@(Checked _ _ errs), _holes) <- checkedModules modules emptyContext+ case errs of+ err : _ -> Left err+ [] -> Right checked++-- | Check the modules in lenient hole mode, returning the holes recorded (each+-- with its goal and local context). This is the structured goal/context query the+-- LSP and the game consume.+typecheckModulesWithHoles+ :: [(FilePath, Rzk.Module)]+ -> Either TypeErrorInScopedContext (Checked, [HoleInfo])+typecheckModulesWithHoles = typecheckModulesWithHolesAndLemmas []++-- | Like 'typecheckModulesWithHoles', but additionally offers the given named+-- top-level definitions as hole candidates (each applied to holes when its type+-- fits the goal). The game passes a level's allow-list of relevant lemmas so they+-- surface as moves; an empty list reproduces 'typecheckModulesWithHoles'.+typecheckModulesWithHolesAndLemmas+ :: [VarIdent]+ -> [(FilePath, Rzk.Module)]+ -> Either TypeErrorInScopedContext (Checked, [HoleInfo])+typecheckModulesWithHolesAndLemmas lemmas modules =+ checkedModules modules (withHintLemmas lemmas (allowHoles emptyContext))++-- * What a consumer sees++-- | A declaration, rendered: no scope index, and nothing to re-elaborate.+--+-- This is what the LSP shows — a name, a type, a location — and it is all it needs.+-- The elaborated terms stay inside the 'Checked' package, which is what a /resume/+-- needs.+data DeclView = DeclView+ { declViewName :: VarIdent+ , declViewType :: Rendered+ , declViewIsAssumption :: Bool+ , declViewLocation :: Maybe LocationInfo+ } deriving (Eq, Show)++-- | The declarations of a checked run, rendered, grouped by the file they came+-- from.+declViews :: Checked -> [(FilePath, [DeclView])]+declViews (Checked ctx decls _errs) = map (fmap (map view)) decls+ where+ naming = namingOfContext ctx+ view decl = DeclView+ { declViewName = declName decl+ , declViewType = renderTerm naming (untyped (declType decl))+ , declViewIsAssumption = declIsAssumption decl+ , declViewLocation = declLocation decl+ }++-- | Continue checking from a prefix that has already been checked.+--+-- This is the incremental path: the cached context /is/ the elaborated prefix, so+-- nothing is replayed and nothing is re-elaborated.+recheckFrom+ :: Checked+ -> [(FilePath, Rzk.Module)]+ -> Either TypeErrorInScopedContext (Checked, [HoleInfo])+recheckFrom (Checked ctx decls _errs) modules =+ runExcept $ runWriterT $ flip runReaderT ctx $+ checkModules modules $ \newDecls errs -> do+ ctx' <- ask+ pure (Checked ctx' (map (fmap (map sinkDecl)) decls <> newDecls) errs)++-- | The errors of a checked run.+checkedErrors :: Checked -> [TypeErrorInScopedContext]+checkedErrors (Checked _ _ errs) = errs++-- | Nothing checked yet: the empty context, and no declarations.+emptyChecked :: Checked+emptyChecked = Checked emptyContext [] []
+ src/Rzk/TypeCheck/Display.hs view
@@ -0,0 +1,149 @@+{-# LANGUAGE OverloadedStrings #-}++-- | Showing a term to the user.+--+-- A term of the core names its variables by 'Foil.Name' (an @Int@), so anything+-- user-facing — an error, a trace of a judgement, a hole's goal — has to say what+-- each name is /called/. That is a 'Naming': a display name and a display binder+-- per name in scope, plus the supply of fresh names for the binders the printer+-- meets on the way down.+--+-- This replaces the old @var -> VarIdent@ threading (@name@, @nameInc@,+-- @BinderNames@, @ppTermInContext@ — four copies of the same idea), and with it+-- the unwinding loop that rebuilt those names one binder at a time.+module Rzk.TypeCheck.Display where++import Control.Monad.Foil (NameMap)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Foil.Internal (NameMap (..))+import qualified Data.IntMap as IntMap+import Data.List (nub, (\\))+import qualified Data.Set as Set++import Language.Rzk.Foil.Print (fromTerm)+import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), Display,+ TypeInfo (..), VarIdent,+ binderIsCompound, binderLeaves,+ binderToPattern, defaultVarIdents,+ freshenBinderLeaves, fromVarIdent,+ refreshVarIn)+import qualified Language.Rzk.Syntax as Rzk+import Rzk.TypeCheck.Context++-- | What every name in scope is called, and what the printer may call the+-- binders it has yet to meet.+data Naming n = Naming+ { namingOf :: NameMap n Display+ , namingUsed :: [VarIdent]+ -- ^ the display names taken, so a bound binder is refreshed away from them+ , namingSupply :: [VarIdent]+ -- ^ the names left over, for anonymous binders+ }++-- | Read the naming off a context.+--+-- A named binder keeps its name, refreshed only if an outer name has already+-- taken it. An anonymous one draws from the supply. A pattern binder has its+-- component names freshened as a group, so that the pattern shown in the context+-- and the projections folded inside a term agree on them.+--+-- Entries are named oldest binding first (see 'ctxBound'), so an outer binder+-- keeps its name and an inner one is the one refreshed away from it.+namingOfContext :: Context n -> Naming n+namingOfContext ctx = Naming+ { namingOf = NameMap (IntMap.fromList entries)+ , namingUsed = used+ , namingSupply = defaultVarIdents \\ used+ }+ where+ (entries, usedSet) = go Set.empty defaultVarIdents (varsInScope ctx)+ used = Set.toList usedSet++ -- Name the entries in binding order, each avoiding the names already taken.+ -- The taken names are a set: this runs once per entry, and a context can hold+ -- every top-level definition of a project.+ go taken _supply [] = ([], taken)+ go taken supply ((v, info) : rest) =+ case varOrig info of+ BinderVar (Just x) ->+ let x' = refreshVarIn taken x+ in name (x', BinderVar (Just x')) [x'] supply+ BinderVar Nothing ->+ case supply of+ x : supply' -> name (x, BinderVar (Just x)) [x] supply'+ [] -> panicImpossible "not enough fresh variables"+ binder ->+ -- A pattern binder: the variable itself needs a placeholder name (it is+ -- only shown when the whole point is used, and then it prints as the+ -- pattern), and its leaves are freshened together.+ case supply of+ x : supply' ->+ let binder' = freshenBinderLeaves (Set.toList taken) binder+ in name (x, binder') (x : binderLeaves binder') supply'+ [] -> panicImpossible "not enough fresh variables"+ where+ name display claimed supply' =+ let (acc, taken') = go (foldr Set.insert taken claimed) supply' rest+ in ((Foil.nameId v, display) : acc, taken')++-- | A term already rendered for the user, kept as surface syntax rather than a+-- string so that a consumer may still inspect it.+--+-- Its 'Show' prints the surface syntax, which is what the old @Term'@ did, so a+-- rendered goal or candidate reads the same as it always has (@\\ (t, s) → ?@).+newtype Rendered = Rendered { getRendered :: Rzk.Term }++instance Show Rendered where+ show = Rzk.printTree . getRendered++-- | Two rendered terms are equal when they read the same. (The surface AST+-- carries source positions, which a rendered term should not be judged by.)+instance Eq Rendered where+ l == r = show l == show r++-- | A term as surface syntax, with the context's names.+--+-- A binder /inside/ the term is freshened only against the names the term itself+-- mentions — not against everything in scope. A type shows the binder it was+-- written with (@Σ (a : A), B a@), even where the context happens to have an @a@ of+-- its own: the two are different variables, and shadowing is what binders are for.+renderTerm :: Naming n -> Term n -> Rendered+renderTerm naming t = Rendered (fromTerm used supply (namingOf naming) t)+ where+ used = nub $ concat+ [ x : binderLeaves binder+ | v <- freeVarsOfTerm t+ , let (x, binder) = displayOf naming v+ ]+ supply = defaultVarIdents \\ used++-- | A term shown to the user.+ppTerm :: Naming n -> Term n -> String+ppTerm naming = show . renderTerm naming++-- | A typed term shown as @term : type@, as the old @ppFoldT@ did. A variable is+-- shown bare: its type is in the context, not on the node.+ppTermT :: Naming n -> TermT n -> String+ppTermT naming t =+ case typeInfoOf t of+ Nothing -> ppTerm naming (untyped t)+ Just info -> ppTerm naming (untyped t) <> " : " <> ppTerm naming (untyped (infoType info))++-- | What a name is called, and the (freshened) binder it was introduced by.+displayOf :: Naming n -> Foil.Name n -> Display+displayOf naming name = Foil.lookupName name (namingOf naming)++-- | A variable as the user sees it: a pattern binder shows as its pattern+-- (@(t, s)@), anything else by its display name.+ppName :: Naming n -> Foil.Name n -> String+ppName naming name =+ case Foil.lookupName name (namingOf naming) of+ (_, binder) | binderIsCompound binder -> Rzk.printTree (binderToPattern binder)+ (x, _) -> Rzk.printTree (fromVarIdent x)++panicImpossible :: String -> a+panicImpossible msg = error $ unlines+ [ "PANIC! Impossible happened (" <> msg <> ")!"+ , "Please, report a bug at https://github.com/rzk-lang/rzk/issues"+ ]
+ src/Rzk/TypeCheck/Error.hs view
@@ -0,0 +1,385 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++-- | Type errors, and how they are shown.+--+-- An error is captured /at its own scope/: it packages the context it was raised+-- in, existentially, so its scope index does not escape into the error type. The+-- old representation instead nested the error one @Inc@ deeper at every binder+-- (@ScopedTypeError@) and unwound the whole stack at printing time, inventing a+-- name per binder as it went. That unwinding loop, and both of its+-- @FIXME: very inefficient filter@ sites, are gone: the context already knows what+-- everything in scope is called (see "Rzk.TypeCheck.Display").+--+-- The error type is therefore /not/ scope-indexed, which is why entering a binder+-- no longer has to re-index the error channel.+module Rzk.TypeCheck.Error where++import Control.Monad.Foil (Distinct)+import qualified Control.Monad.Foil as Foil+import Data.List (intercalate)++import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (TModality (..), VarIdent, getVarIdent,+ ppVarIdentWithLocation)+import qualified Language.Rzk.Syntax as Rzk+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Display++data TypeError n+ = TypeErrorOther String+ | TypeErrorUnify (TermT n) (TermT n) (TermT n)+ | TypeErrorUnifyTerms (TermT n) (TermT n)+ | TypeErrorNotPair (TermT n) (TermT n)+ | TypeErrorNotModal (Term n) TModality (TermT n)+ | TypeErrorModalityMismatch TModality TModality (Term n)+ | TypeErrorUnaccessibleVar (Foil.Name n) TModality TModality+ | TypeErrorNotTypeInModal (TermT n)+ | TypeErrorNotFunction (TermT n) (TermT n)+ | TypeErrorUnexpectedLambda (Term n) (TermT n)+ | TypeErrorUnexpectedPair (Term n) (TermT n)+ | TypeErrorUnexpectedRefl (Term n) (TermT n)+ | TypeErrorCannotInferBareLambda (Term n)+ | TypeErrorCannotInferBareRefl (Term n)+ | TypeErrorCannotInferHole (Term n)+ | TypeErrorUnsolvedHole (Maybe VarIdent) (TermT n)+ | TypeErrorUndefined VarIdent+ | TypeErrorTopeNotSatisfied [TermT n] (TermT n)+ | TypeErrorTopeContextDisjoint (TermT n) [TermT n]+ | TypeErrorTopesNotEquivalent (TermT n) (TermT n)+ | TypeErrorInvalidArgumentType (Term n) (TermT n)+ | TypeErrorDuplicateTopLevel [VarIdent] VarIdent+ | TypeErrorUnusedVariable (Foil.Name n) (TermT n)+ | TypeErrorUnusedUsedVariables [Foil.Name n] (Foil.Name n)+ | TypeErrorImplicitAssumption (Foil.Name n, TermT n) (Foil.Name n)++-- | An error, together with the context it was raised in.+--+-- The scope index is existential: an error raised under a binder is /already/+-- complete (its context says what its names are called), so it needs nothing+-- from the enclosing scope and can be thrown straight through it.+data TypeErrorInScopedContext where+ TypeErrorInScopedContext+ :: Distinct n => Context n -> TypeError n -> TypeErrorInScopedContext++ppModality :: TModality -> String+ppModality = \case+ Flat -> "♭"+ Sharp -> "♯"+ Op -> "ᵒᵖ"+ Id -> "_id"++-- * Rendering++data OutputDirection = TopDown | BottomUp+ deriving (Eq)++block :: OutputDirection -> [String] -> String+block TopDown = intercalate "\n"+block BottomUp = intercalate "\n" . reverse++namedBlock :: OutputDirection -> String -> [String] -> String+namedBlock dir name lines_ = block dir $+ name : map indent lines_+ where+ indent = intercalate "\n" . map (" " ++) . lines++ppTypeError :: Naming n -> TypeError n -> String+ppTypeError naming = \case+ TypeErrorOther msg -> msg+ TypeErrorUnify term expected actual -> block TopDown+ [ "cannot unify expected type"+ , " " <> ppU (untyped expected)+ , "with actual type"+ , " " <> ppU (untyped actual)+ , "for term"+ , " " <> ppU (untyped term) ]+ TypeErrorUnifyTerms expected actual -> block TopDown+ [ "cannot unify term"+ , " " <> ppU (untyped expected)+ , "with term"+ , " " <> ppU (untyped actual) ]+ TypeErrorNotPair term ty -> block TopDown+ [ "expected a cube product or dependent pair"+ , "but got type"+ , " " <> ppU (untyped ty)+ , "for term"+ , " " <> ppU (untyped term)+ , case ty of+ TypeFunT{} -> "\nPerhaps the term is applied to too few arguments?"+ _ -> ""+ ]+ TypeErrorNotModal term m ty -> block TopDown+ [ "expected modal type " <> ppModality m <> " ?"+ , "but got type"+ , " " <> ppU (untyped ty)+ , "for term"+ , " " <> ppU term+ ]+ TypeErrorModalityMismatch expected actual term -> block TopDown+ [ "modality mismatch"+ , " expected " <> ppModality expected+ , " but got " <> ppModality actual+ , "for term"+ , " " <> ppU term+ ]+ TypeErrorUnaccessibleVar _var varMod locks -> block TopDown+ [ "unaccessible var with modality " <> ppModality varMod+ , " under locks " <> ppModality locks+ ]+ TypeErrorNotTypeInModal ty -> block TopDown+ [ "expected a type inside modal type"+ , "but got"+ , " " <> ppU (untyped ty)+ ]++ TypeErrorUnexpectedLambda term ty -> block TopDown+ [ "unexpected lambda abstraction"+ , " " <> ppU term+ , "when typechecking against a non-function type"+ , " " <> ppTyped ty+ ]+ TypeErrorUnexpectedPair term ty -> block TopDown+ [ "unexpected pair"+ , " " <> ppU term+ , "when typechecking against a type that is not a product or a dependent sum"+ , " " <> ppTyped ty+ ]+ TypeErrorUnexpectedRefl term ty -> block TopDown+ [ "unexpected refl"+ , " " <> ppU term+ , "when typechecking against a type that is not an identity type"+ , " " <> ppTyped ty+ ]++ TypeErrorNotFunction term ty -> block TopDown+ [ "expected a function or extension type"+ , "but got type"+ , " " <> ppU (untyped ty)+ , "for term"+ , " " <> ppU (untyped term)+ , case term of+ AppT _ty f _x -> "\nPerhaps the term\n " <> ppU (untyped f) <> "\nis applied to too many arguments?"+ _ -> ""+ ]+ TypeErrorCannotInferBareLambda term -> block TopDown+ [ "cannot infer the type of the argument"+ , "in lambda abstraction"+ , " " <> ppU term+ ]+ TypeErrorCannotInferBareRefl term -> block TopDown+ [ "cannot infer the type of term"+ , " " <> ppU term+ ]+ TypeErrorCannotInferHole term -> block TopDown+ [ "cannot infer the type of a hole"+ , " " <> ppU term+ , "a hole is only allowed where its type is already known (checking position)"+ ]+ TypeErrorUnsolvedHole mname goal -> block TopDown+ [ "found an unsolved hole" <> maybe "" (\name -> " ?" <> show name) mname+ , "expected type (goal):"+ , " " <> ppU (untyped goal)+ ]+ TypeErrorUndefined var -> block TopDown+ [ "undefined variable: " <> show var ]+ TypeErrorTopeNotSatisfied topes tope -> block TopDown+ [ "local context is not included in (does not entail) the tope"+ , " " <> ppU (untyped tope)+ , "in local context (normalised)"+ , intercalate "\n" (map ((" " <>) . ppTyped) topes)] -- FIXME: remove+ TypeErrorTopeContextDisjoint tope topes -> block TopDown+ [ "the tope"+ , " " <> ppU (untyped tope)+ , "is disjoint from the local tope context (their conjunction is the empty tope ⊥),"+ , "so this restriction face or recOR branch is vacuous everywhere"+ , "in local context (normalised)"+ , intercalate "\n" (map ((" " <>) . ppTyped) topes)]+ TypeErrorTopesNotEquivalent expected actual -> block TopDown+ [ "expected tope"+ , " " <> ppU (untyped expected)+ , "but got"+ , " " <> ppU (untyped actual) ]++ TypeErrorInvalidArgumentType argType argKind -> block TopDown+ [ "invalid function parameter type"+ , " " <> ppU argType+ , "function parameter can be a cube, a shape, or a type"+ , "but given parameter type has type"+ , " " <> ppU (untyped argKind)+ ]++ TypeErrorDuplicateTopLevel previous lastName -> block TopDown+ [ "duplicate top-level definition"+ , " " <> ppVarIdentWithLocation lastName+ , "previous top-level definitions found at"+ , intercalate "\n"+ [ " " <> ppVarIdentWithLocation name+ | name <- previous ]+ ]++ TypeErrorUnusedVariable name type_ -> block TopDown+ [ "unused variable"+ , " " <> ppVar name <> " : " <> ppU (untyped type_)+ ]++ TypeErrorUnusedUsedVariables vars name -> block TopDown+ [ "unused variables"+ , " " <> unwords (map ppVar vars)+ , "declared as used in definition of"+ , " " <> ppVar name+ ]++ TypeErrorImplicitAssumption (a, aType) name -> block TopDown+ [ "implicit assumption"+ , " " <> ppVar a <> " : " <> ppU (untyped aType)+ , "used in definition of"+ , " " <> ppVar name+ ]+ where+ ppU = ppTerm naming+ ppTyped = ppTermT naming+ ppVar = ppName naming++ppAction :: Naming n -> Int -> Action n -> String+ppAction naming n = unlines . map (replicate (2 * n) ' ' <>) . \case+ ActionTypeCheck term ty ->+ [ "typechecking"+ , " " <> ppU term+ , "against type"+ , " " <> ppU (untyped ty) ]++ ActionUnify term expected actual ->+ [ "unifying expected type"+ , " " <> ppU (untyped expected)+ , "with actual type"+ , " " <> ppU (untyped actual)+ , "for term"+ , " " <> ppU (untyped term) ]++ ActionUnifyTerms expected actual ->+ [ "unifying term (expected)"+ , " " <> ppTyped expected+ , "with term (actual)"+ , " " <> ppTyped actual ]++ ActionInfer term ->+ [ "inferring type for term"+ , " " <> ppU term ]++ ActionContextEntailedBy topes term ->+ [ "checking if local context"+ , intercalate "\n" (map ((" " <>) . ppU . untyped) topes)+ , "includes (is entailed by) restriction tope"+ , " " <> ppU (untyped term) ]++ ActionContextEntails topes term ->+ [ "checking if local context"+ , intercalate "\n" (map ((" " <>) . ppU . untyped) topes)+ , "is included in (entails) the tope"+ , " " <> ppU (untyped term) ]++ ActionContextEntailsUnion topes terms ->+ [ "checking if local context"+ , intercalate "\n" (map ((" " <>) . ppU . untyped) topes)+ , "is included in (entails) the union of the topes"+ , intercalate "\n" (map ((" " <>) . ppU . untyped) terms) ]++ ActionWHNF term ->+ [ "computing WHNF for term"+ , " " <> ppTyped term ]++ ActionNF term ->+ [ "computing normal form for term"+ , " " <> ppU (untyped term) ]++ ActionCheckCoherence (ltope, lterm) (rtope, rterm) ->+ [ "checking coherence for"+ , " " <> ppU (untyped ltope)+ , " |-> " <> ppU (untyped lterm)+ , "and"+ , " " <> ppU (untyped rtope)+ , " |-> " <> ppU (untyped rterm) ]++ ActionCloseSection Nothing ->+ [ "closing the file"+ , "and collecting assumptions (variables)" ]+ ActionCloseSection (Just sectionName) ->+ [ "closing #section " <> Rzk.printTree sectionName+ , "and collecting assumptions (variables)"]++ ActionCheckLetValue orig ->+ [ "checking the local definition "+ <> maybe "_" (Rzk.printTree . getVarIdent) orig ]+ where+ ppU = ppTerm naming+ ppTyped = ppTermT naming++-- | The context an error was raised in: where it happened, what was being+-- checked, the tope context, the stack of judgements, and the hypotheses.+ppContext :: OutputDirection -> Context n -> String+ppContext dir ctx@Context{..} = block dir $ dropWhile null+ [ block TopDown+ [ case ctxLocation of+ _ | dir == TopDown -> "" -- FIXME+ Just (LocationInfo (Just path) (Just lineNo)) ->+ path <> " (line " <> show lineNo <> "):"+ Just (LocationInfo (Just path) _) ->+ path <> ":"+ _ -> ""+ , case ctxCurrentCommand of+ Just (Rzk.CommandDefine _loc name _vars _params _ty _term) ->+ " Error occurred when checking\n #define " <> Rzk.printTree name+ Just (Rzk.CommandPostulate _loc name _vars _params _ty ) ->+ " Error occurred when checking\n #postulate " <> Rzk.printTree name+ Just (Rzk.CommandCheck _loc term ty) ->+ " Error occurred when checking\n " <> Rzk.printTree term <> " : " <> Rzk.printTree ty+ Just (Rzk.CommandCompute _loc term) ->+ " Error occurred when computing\n " <> Rzk.printTree term+ Just (Rzk.CommandComputeNF _loc term) ->+ " Error occurred when computing NF for\n " <> Rzk.printTree term+ Just (Rzk.CommandComputeWHNF _loc term) ->+ " Error occurred when computing WHNF for\n " <> Rzk.printTree term+ Just (Rzk.CommandSetOption _loc optionName _optionValue) ->+ " Error occurred when trying to set option\n #set-option " <> show optionName+ Just command@Rzk.CommandUnsetOption{} ->+ " Error occurred when trying to unset option\n " <> Rzk.printTree command+ Just command@Rzk.CommandAssume{} ->+ " Error occurred when checking assumption\n " <> Rzk.printTree command+ Just (Rzk.CommandSection _loc name) ->+ " Error occurred when checking\n #section " <> Rzk.printTree name+ Just (Rzk.CommandSectionEnd _loc name) ->+ " Error occurred when checking\n #end " <> Rzk.printTree name+ Nothing -> " Error occurred outside of any command!"+ ]+ , ""+ , case filter (not . isTopeTop) (availableTopes ctx) of+ [] -> "Local tope context is unrestricted (⊤)."+ topes -> namedBlock TopDown "Local tope context:"+ [ " " <> ppU (untyped tope)+ | tope <- topes ]+ , ""+ , block dir+ [ "when " <> ppAction naming 0 action+ | action <- ctxActionStack ]+ , namedBlock TopDown "Definitions in context:"+ [ block dir+ [ ppName naming name <> " : " <> ppU (untyped (varType info))+ | (name, info) <- reverse (varsInScope ctx) ] ]+ ]+ where+ naming = namingOfContext ctx+ ppU = ppTerm naming+ isTopeTop TopeTopT{} = True+ isTopeTop _ = False++-- | An error, with the context it was raised in.+ppTypeErrorInScopedContext :: OutputDirection -> TypeErrorInScopedContext -> String+ppTypeErrorInScopedContext dir (TypeErrorInScopedContext ctx err) = block dir+ [ ppTypeError (namingOfContext ctx) err+ , ""+ , ppContext dir ctx+ ]
+ src/Rzk/TypeCheck/Eval.hs view
@@ -0,0 +1,1615 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE RecordWildCards #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Entering a scope, evaluation, and the tope solver.+--+-- These three are one recursive knot and cannot be separated:+--+-- * entering a binder needs 'whnfT', to see whether a flat variable is a point+-- of a cube and so brings a discreteness axiom with it;+-- * 'whnfT' strips an extension type's restrictions, which asks the solver+-- whether a face's tope holds ('checkTope');+-- * 'nfT' normalises under a binder and under a tope ('localTope');+-- * and the solver normalises the topes it reasons about ('nfTope').+module Rzk.TypeCheck.Eval where++import Control.Monad (forM, forM_, unless, when)+import Control.Monad.Except (runExcept)+import Control.Monad.Reader (ask, asks, local,+ runReaderT)+import Control.Monad.Trans.Writer.CPS (runWriterT)+import Data.List (intercalate, nub, nubBy,+ tails)+import Data.Maybe (catMaybes)++import Control.Monad.Foil (DExt, Distinct, NameBinder)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Free.Foil (AST (Node, Var),+ ScopedAST (..))+import Data.Bifunctor (Bifunctor)++import Control.Monad.Free.Foil.Annotated (AnnSig (..))+import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), TModality (..),+ TypeInfo (..), VarIdent)+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Display+import Rzk.TypeCheck.Error+import Rzk.TypeCheck.Monad++-- * Variables++-- | Look up a name and project one field of its 'VarInfo'.+infoOfVar :: (VarInfo n -> a) -> Foil.Name n -> TypeCheck n a+infoOfVar f x = asks (f . lookupVarInfo x)++valueOfVar :: Foil.Name n -> TypeCheck n (Maybe (TermT n))+valueOfVar = infoOfVar varValue++typeOfVar :: Foil.Name n -> TypeCheck n (TermT n)+typeOfVar = infoOfVar varType++modalityOfVar :: Foil.Name n -> TypeCheck n TModality+modalityOfVar = infoOfVar varModality++locksOfVar :: Foil.Name n -> TypeCheck n TModality+locksOfVar = infoOfVar varModAccum++isTopLevelVar :: Foil.Name n -> TypeCheck n Bool+isTopLevelVar = infoOfVar varIsTopLevel++-- | Is a surface name defined?+checkDefinedVar :: Distinct n => VarIdent -> TypeCheck n ()+checkDefinedVar name = asks (lookupNamed name) >>= \case+ Nothing -> issueTypeError (TypeErrorUndefined name)+ Just _ -> return ()++typeOfUncomputed :: TermT n -> TypeCheck n (TermT n)+typeOfUncomputed = \case+ Var x -> typeOfVar x+ t -> case typeInfoOf t of+ Just info -> pure (infoType info)+ Nothing -> panicImpossible "a node with no annotation"++typeOf :: Distinct n => TermT n -> TypeCheck n (TermT n)+typeOf t = typeOfUncomputed t >>= whnfT++-- | The free variables of a typed term, including those that occur only in the+-- /types/ of the variables it mentions.+--+-- A definition can depend on a section assumption without naming it: through the+-- type of something else it uses. Closing a section has to see that dependency, and+-- it is exactly what distinguishes an implicit assumption from an explicit one.+freeVarsDeep :: TermT n -> TypeCheck n [Foil.Name n]+freeVarsDeep t = do+ ctx <- ask+ let typeOfName v = varType (lookupVarInfo v ctx)++ -- a node's own free variables, and those of its type+ partial term = case typeInfoOf term of+ Nothing -> freeVarsOfTermT term+ Just info -> freeVarsOfTermT term <> freeVarsOfTermT (infoType info)++ go vars latest+ | null new = vars+ | otherwise = go (new <> vars) (foldMap (partial . typeOfName) new)+ where+ new = filter (`notElemName` vars) (nubNames latest)++ pure (go [] (partial t))++nubNames :: [Foil.Name n] -> [Foil.Name n]+nubNames = nubBy (\a b -> Foil.nameId a == Foil.nameId b)++elemName :: Foil.Name n -> [Foil.Name n] -> Bool+elemName x = any (\y -> Foil.nameId x == Foil.nameId y)++notElemName :: Foil.Name n -> [Foil.Name n] -> Bool+notElemName x = not . elemName x++-- * Substitution, in the monad++-- | Instantiate a scoped term with an argument: the old @substituteT@.+instantiate :: Distinct n => ScopedTermT n -> TermT n -> TypeCheck n (TermT n)+instantiate scoped arg = do+ scope <- asks ctxScope+ pure (instantiateT scope scoped arg)++-- * Entering a binder++-- | The discreteness axiom a flat cube variable brings with it: a flat point of+-- @2@ (or of @I@) is one of the endpoints. Maintained at binder entry so that+-- entailment does not have to rescan the context on every query.+discreteAxiomOf+ :: forall n l. Distinct n+ => TModality -> TermT n -> NameBinder n l -> TypeCheck n [ModalTope l]+discreteAxiomOf Flat ty binder = whnfT ty >>= \case+ Cube2T{} -> pure [endpoints cube2_0T cube2_1T]+ CubeIT{} -> pure [endpoints cubeI_0T cubeI_1T]+ _ -> pure []+ where+ z = Var (Foil.nameOf binder) :: TermT l+ endpoints zero one = plainTope (topeOrT (topeEQT z zero) (topeEQT z one))+discreteAxiomOf _ _ _ = pure []++-- | What a binder adds to the context.+binderInfo+ :: Binder -> TModality -> TermT n -> Maybe (TermT n) -> Maybe LocationInfo+ -> VarInfo n+binderInfo orig md ty mval loc = VarInfo+ { varType = ty+ , varValue = mval+ , varModality = md+ , varModAccum = Id+ , varOrig = orig+ , varIsAssumption = False+ , varIsTopLevel = False+ , varDeclaredAssumptions = []+ , varLocation = loc+ }++-- | Run an action under a binder that has already been chosen.+underBinder+ :: (Distinct n, DExt n l)+ => NameBinder n l -> Binder -> TModality -> TermT n -> Maybe (TermT n)+ -> TypeCheck l a -> TypeCheck n a+underBinder binder orig md ty mval action = do+ ctx <- ask+ discrete <- discreteAxiomOf md ty binder+ let info = binderInfo orig md ty mval (ctxLocation ctx)+ ctx' = enterBinder binder info discrete ctx+ -- A new discreteness axiom changes the saturation input; an ordinary binder+ -- carries the cached value in with the rest of the context (saturation+ -- commutes with renaming).+ inContext ctx' $+ if null discrete then action else withRefreshedTopes id action++-- | Enter a fresh binder (one the checker invents) and run an action whose result+-- says nothing about the new scope.+withBinder+ :: Distinct n+ => Binder -> TModality -> TermT n+ -> (forall l. (DExt n l, Distinct l) => NameBinder n l -> TypeCheck l a)+ -> TypeCheck n a+withBinder orig md ty k = do+ scope <- asks ctxScope+ withFreshIn scope $ \binder ->+ underBinder binder orig md ty Nothing (k binder)++withFreshIn+ :: Distinct n+ => Foil.Scope n+ -> (forall l. (DExt n l, Distinct l) => NameBinder n l -> r)+ -> r+withFreshIn scope k = Foil.withFresh scope k++-- | Open a scoped term under its own binder, run the action on the body, and pack+-- the result back up as a scoped term.+underScope+ :: Distinct n+ => Binder -> TModality -> TermT n -> Maybe (TermT n)+ -> ScopedTermT n+ -> (forall l. (DExt n l, Distinct l) => TermT l -> TypeCheck l (TermT l))+ -> TypeCheck n (ScopedTermT n)+underScope orig md ty mval scoped k = do+ scope <- asks ctxScope+ withScopedT scope scoped $ \binder body ->+ ScopedAST binder <$> underBinder binder orig md ty mval (k body)++-- | Like 'underScope', for a Π (or a λ over a shape), which binds a tope scope+-- beside the body under what the user wrote as one binder.+underScope2+ :: Distinct n+ => Binder -> TModality -> TermT n+ -> ScopedTermT n -> ScopedTermT n+ -> (forall l. (DExt n l, Distinct l) => TermT l -> TermT l -> TypeCheck l (TermT l, TermT l))+ -> TypeCheck n (ScopedTermT n, ScopedTermT n)+underScope2 orig md ty scoped1 scoped2 k = do+ scope <- asks ctxScope+ withScopedT2 scope scoped1 scoped2 $ \binder body1 body2 -> do+ (r1, r2) <- underBinder binder orig md ty Nothing (k body1 body2)+ pure (ScopedAST binder r1, ScopedAST binder r2)++-- | Open a scoped term for a computation whose result says nothing about the new+-- scope (a check, or a rendered string).+inScope+ :: (Bifunctor sig, Distinct n)+ => Binder -> TModality -> TermT n -> ScopedAST NameBinder sig n+ -> (forall l. (DExt n l, Distinct l) => AST NameBinder sig l -> TypeCheck l a)+ -> TypeCheck n a+inScope orig md ty = inScopeWith orig md ty Nothing++-- | Like 'inScope', for a binder that stands for a known value (a @let@).+inScopeWith+ :: (Bifunctor sig, Distinct n)+ => Binder -> TModality -> TermT n -> Maybe (TermT n)+ -> ScopedAST NameBinder sig n+ -> (forall l. (DExt n l, Distinct l) => AST NameBinder sig l -> TypeCheck l a)+ -> TypeCheck n a+inScopeWith orig md ty mval scoped k = do+ scope <- asks ctxScope+ withScopedT scope scoped $ \binder body ->+ underBinder binder orig md ty mval (k body)++-- | Open a scoped term with a binder that has just been entered.+--+-- The scoped term lives in the enclosing scope, and so may be the codomain of the+-- type a λ is being checked against, or the tope of a shape: all of them are+-- opened under the /one/ binder the λ introduces.+openScoped+ :: (Bifunctor sig, DExt n l)+ => NameBinder n l -> ScopedAST NameBinder sig n -> TypeCheck l (AST NameBinder sig l)+openScoped binder scoped = do+ scope <- asks ctxScope+ pure (openWith scope (Foil.nameOf binder) scoped)++-- | A scope that does not use its binder: the codomain of a non-dependent function+-- type, say.+constScope :: Distinct n => TermT n -> TypeCheck n (ScopedTermT n)+constScope t = do+ scope <- asks ctxScope+ pure (Foil.withFresh scope $ \binder -> ScopedAST binder (Foil.sink t))++-- | Enter the binder of an /untyped/ scope — the body of a λ, or of a let, as the+-- user wrote it — and elaborate it into a typed one.+--+-- The binder comes from the term being checked, and the scopes of the /type/ it is+-- checked against are opened under that same binder with 'openScoped'.+elaborateUnder+ :: Distinct n+ => Binder -> TModality -> TermT n -> Maybe (TermT n)+ -> ScopedTerm n+ -> (forall l. (DExt n l, Distinct l)+ => NameBinder n l -> Term l -> TypeCheck l (TermT l))+ -> TypeCheck n (ScopedTermT n)+elaborateUnder orig md ty mval scoped k = do+ scope <- asks ctxScope+ withScopedT scope scoped $ \binder body ->+ ScopedAST binder <$> underBinder binder orig md ty mval (k binder body)++-- | Enter the binder of an untyped scope and run a computation under it.+--+-- The result may not mention the new scope — but a 'ScopedAST' /hides/ its scope,+-- so the continuation can pack whatever it built with the binder it was given and+-- hand back as many scoped terms as it likes. That is how a λ returns its+-- elaborated body, its shape tope and the type it turned out to have, all at once.+checkUnderWith+ :: Distinct n+ => Binder -> TModality -> TermT n -> Maybe (TermT n) -> ScopedTerm n+ -> (forall l. (DExt n l, Distinct l)+ => NameBinder n l -> Term l -> TypeCheck l a)+ -> TypeCheck n a+checkUnderWith orig md ty mval scoped k = do+ scope <- asks ctxScope+ withScopedT scope scoped $ \binder body ->+ underBinder binder orig md ty mval (k binder body)++checkUnder+ :: Distinct n+ => Binder -> TModality -> TermT n -> ScopedTerm n+ -> (forall l. (DExt n l, Distinct l)+ => NameBinder n l -> Term l -> TypeCheck l a)+ -> TypeCheck n a+checkUnder orig md ty = checkUnderWith orig md ty Nothing++-- * Modalities++enterModality :: Distinct n => TModality -> TypeCheck n b -> TypeCheck n b+enterModality Id action = action+enterModality md action = do+ ctx <- asks (applyModality md)+ let ctx' = ctx { ctxTopesEntailBottom = Nothing }+ -- 'applyModality' invalidated the saturation cache (accessibility changed);+ -- refresh it under the shifted context.+ inContext ctx' (withRefreshedTopes id action)++-- * The tope context++-- | Assume a tope for the enclosed action.+localTope :: Distinct n => TermT n -> TypeCheck n a -> TypeCheck n a+localTope tope tc = do+ ctx <- ask'+ tope' <- nfTope tope+ let modalTope' = plainTope tope'+ -- A small optimisation to help unify terms faster.+ let noNewInformation = case tope' of+ TopeEQT _ x y | eqT x y -> True+ _ -> any (eqModalTope modalTope') (ctxTopesNF ctx)+ if noNewInformation+ then tc+ else do+ entailsBottom <- (modalTope' : ctxTopesNF ctx) `entailM` topeBottomT+ withRefreshedTopes (extend modalTope' entailsBottom) tc+ where+ ask' = asks id+ extend tope' entailsBottom ctx = ctx+ { ctxTopes = plainTope tope : ctxTopes ctx+ , ctxTopesNF = tope' : ctxTopesNF ctx+ , ctxTopesNFUnion = map nubModalTopes+ [ new <> old+ | new <- simplifyLHSwithDisjunctions [tope']+ , old <- ctxTopesNFUnion ctx ]+ , ctxTopesEntailBottom = Just entailsBottom+ }++-- | Install a deferred saturation cache for the transformed context, and run the+-- action with it.+--+-- The pipeline's effects are discharged purely into a thunk: installing costs+-- nothing, holes recorded by the speculative run are discarded, and a pipeline+-- error (a tope guard with a hole in lenient mode, say, which the per-query path+-- would never have evaluated) becomes 'Nothing', so errors surface exactly where+-- they did before.+withRefreshedTopes+ :: Distinct n+ => (Context n -> Context n) -> TypeCheck n a -> TypeCheck n a+withRefreshedTopes f action = do+ ctx' <- asks f+ let sat = case runExcept (runWriterT (runReaderT (saturateForEntailment (ctxTopesNF ctx')) ctx')) of+ Left _ -> Nothing+ Right (s, _) -> Just s+ local (const ctx' { ctxTopesSaturated = SaturationCached sat }) action++-- | Run a check in every alternative of a disjunctive tope context.+inAllSubContexts :: Distinct n => TypeCheck n () -> TypeCheck n () -> TypeCheck n ()+inAllSubContexts handleSingle tc = do+ topeSubContexts <- asks ctxTopesNFUnion+ case topeSubContexts of+ [] -> panicImpossible "empty set of alternative contexts"+ [_] -> handleSingle+ _:_:_ ->+ forM_ topeSubContexts $ \topes' ->+ withRefreshedTopes (\ctx -> ctx+ { ctxTopes = topes'+ , ctxTopesNF = topes'+ , ctxTopesNFUnion = [topes']+ }) tc++-- * Equality of topes++eqModalTope :: Distinct n => ModalTope n -> ModalTope n -> Bool+eqModalTope l r = and+ [ tModAccum l == tModAccum r+ , tModVar l == tModVar r+ , eqT (tTope l) (tTope r)+ ]++nubModalTopes :: Distinct n => [ModalTope n] -> [ModalTope n]+nubModalTopes [] = []+nubModalTopes (t : ts) = t : nubModalTopes (filter (not . eqModalTope t) ts)++elemModalTope :: Distinct n => ModalTope n -> [ModalTope n] -> Bool+elemModalTope t = any (eqModalTope t)++-- * Entailment++-- | Monadic 'all' that stops at the first failing element.+allM :: Monad m => (a -> m Bool) -> [a] -> m Bool+allM p = go+ where+ go [] = return True+ go (x:xs) = p x >>= \case+ False -> return False+ True -> go xs++entailM :: Distinct n => [ModalTope n] -> TermT n -> TypeCheck n Bool+entailM modalTopes goal = do+ saturated <- saturateForEntailment modalTopes+ entailSaturatedM saturated goal++-- | The preprocessing 'entailM' does before searching: dedup, split off the+-- context's disjunctions, and saturate each alternative. Depends only on the+-- given topes (plus the discreteness axioms of the context), not on the goal.+saturateForEntailment+ :: Distinct n => [ModalTope n] -> TypeCheck n [[ModalTope n]]+saturateForEntailment modalTopes = do+ discreteAxioms <- asks ctxDiscreteTopes+ let topes' = nubModalTopes (modalTopes <> discreteAxioms)+ topes'' = simplifyLHSwithDisjunctions topes'+ mapM (fmap (saturateTopes . saturateBottom) . saturateInv) topes''++-- | Search each saturated alternative for the goal.+entailSaturatedM+ :: Distinct n => [[ModalTope n]] -> TermT n -> TypeCheck n Bool+entailSaturatedM saturated goal = asks ctxVerbosity >>= \case+ Debug -> do+ naming <- asks namingOfContext+ let prettyTopes = map (ppTerm naming . untyped . tTope) (concat saturated)+ prettyTope = ppTerm naming (untyped goal)+ traceTypeCheck Debug+ ("entail " <> intercalate ", " prettyTopes <> " |- " <> prettyTope) $+ allM (`solveRHSM` goal) saturated+ _ -> allM (`solveRHSM` goal) saturated++-- | Entailment against the context's own tope context, using the cached+-- saturation when one was installed. Matching on the payload of+-- 'SaturationCached' is what forces the deferred pipeline, so the cost is paid at+-- the first query under a context, and never for one that is never queried.+entailContextM :: Distinct n => TermT n -> TypeCheck n Bool+entailContextM goal = asks ctxTopesSaturated >>= \case+ SaturationCached (Just saturated) -> entailSaturatedM saturated goal+ SaturationCached Nothing -> fallback+ SaturationUncached -> fallback+ where+ fallback = asks ctxTopesNF >>= (`entailM` goal)++-- * Saturation++saturateTopes :: Distinct n => [ModalTope n] -> [ModalTope n]+saturateTopes topes = saturated <> inaccessible+ where+ (accessible, inaccessible) = partitionAccessible topes+ saturated = saturateWith+ elemModalTope+ (\new old -> map plainTope (generateTopes (map tTope new) (map tTope old)))+ accessible++saturateInv :: Distinct n => [ModalTope n] -> TypeCheck n [ModalTope n]+saturateInv modalTopes = do+ -- FIXME: this is a workaround; ideally we should regenerate all topes on+ -- EVERY modality change in any layer, but that would produce too many; for+ -- now we also invert topes that were accessible before the modality shift.+ let accessible = filterAccessible modalTopes+ accessibleById = filter (\mt -> coe (tModVar mt) Id) modalTopes+ invResults <- forM (nubModalTopes (accessible <> accessibleById)) $ \mt -> do+ nf <- nfTope $ modExtractT topeT Id Op (topeInvT (tTope mt))+ return $ ModalTope (tModAccum mt) Op nf+ let accessibleUnderOp =+ filter (\mt -> coe (tModVar mt) (comp (tModAccum mt) Op)) modalTopes+ uninvResults <- forM accessibleUnderOp $ \(ModalTope acc var' phi) -> do+ nf <- nfTope $ topeUninvT (modAppT topeT Op phi)+ return $ ModalTope (comp acc Op) var' nf+ let newTopes = nubModalTopes (invResults <> uninvResults)+ fresh = filter (\t -> not (elemModalTope t modalTopes)) newTopes+ return (modalTopes <> fresh)++-- | Ex falso for BOT, lifted across modalities.+--+-- A contradiction in the topes that are genuinely available at the identity+-- modality entails BOT, and BOT entails @_μ BOT@ for every modality @μ@ by the+-- absurd rule (this holds for BOT specifically; a general tope @φ@ does NOT give+-- @_μ φ@, which would need the missing unit @id ⇒ μ@). Re-asserting @_μ BOT@ at+-- each lock @μ@ where an available tope was hidden lets the contradiction survive+-- the lock: @_b BOT@ is accessible under a @_b@ lock (@coe Flat Flat@), so+-- @mod _b recBOT@ in a vacuous context is accepted.+--+-- A tope counts as available at the identity modality when its variable modality+-- coerces into @Id@: a @_b@-modal tope qualifies via the counit (@coe Flat Id@),+-- but a @_#@-modal one does not (@coe Sharp Id@ is False) — which is exactly why+-- @_# BOT@ does not leak to plain BOT.+saturateBottom :: Distinct n => [ModalTope n] -> [ModalTope n]+saturateBottom modalTopes+ | null droppedAccums = modalTopes -- nothing hidden by a lock+ | botDerivable = modalTopes <> fresh+ | otherwise = modalTopes+ where+ idAccessible = filter (\mt -> coe (tModVar mt) Id) modalTopes+ droppedAccums = nub [ tModAccum mt | mt <- idAccessible, not (isAccessible mt) ]+ saturatedId = saturateWith elemT generateTopes (map tTope idAccessible)+ botDerivable = topeBottomT `elemT` saturatedId+ fresh = [ mt+ | acc <- droppedAccums+ , let mt = ModalTope acc acc topeBottomT+ , not (elemModalTope mt modalTopes) ]++-- FIXME: cleanup+saturateWith :: (a -> [a] -> Bool) -> ([a] -> [a] -> [a]) -> [a] -> [a]+saturateWith elem' step zs = go (nub' zs) []+ where+ go lastNew xs+ | null new = lastNew+ | otherwise = lastNew <> go new xs'+ where+ xs' = lastNew <> xs+ new = filter (not . (`elem'` xs')) (nub' $ step lastNew xs)+ nub' [] = []+ nub' (x:xs) = x : nub' (filter (not . (`elem'` [x])) xs)++generateTopes :: Distinct n => [TermT n] -> [TermT n] -> [TermT n]+generateTopes newTopes oldTopes+ | topeBottomT `elemT` newTopes = []+ | topeEQT cube2_0T cube2_1T `elemT` newTopes = [topeBottomT]+ | topeEQT cubeI_0T cubeI_1T `elemT` newTopes = [topeBottomT]+ | length oldTopes > 100 = [] -- FIXME+ | otherwise = concat+ [ -- symmetry EQ+ [ topeEQT y x | TopeEQT _ty x y <- newTopes ]+ -- transitivity EQ (1)+ , [ topeEQT x z+ | TopeEQT _ty x y : newTopes' <- tails newTopes+ , TopeEQT _ty y' z <- newTopes' <> oldTopes+ , eqT y y' ]+ -- transitivity EQ (2)+ , [ topeEQT x z+ | TopeEQT _ty y z : newTopes' <- tails newTopes+ , TopeEQT _ty x y' <- newTopes' <> oldTopes+ , eqT y y' ]++ -- transitivity LEQ (1)+ , [ topeLEQT x z+ | TopeLEQT _ty x y : newTopes' <- tails newTopes+ , TopeLEQT _ty y' z <- newTopes' <> oldTopes+ , eqT y y' ]+ -- transitivity LEQ (2)+ , [ topeLEQT x z+ | TopeLEQT _ty y z : newTopes' <- tails newTopes+ , TopeLEQT _ty x y' <- newTopes' <> oldTopes+ , eqT y y' ]++ -- antisymmetry LEQ+ , [ topeEQT x y+ | TopeLEQT _ty x y : newTopes' <- tails newTopes+ , TopeLEQT _ty y' x' <- newTopes' <> oldTopes+ , eqT y y'+ , eqT x x' ]++ -- FIXME: special case of substitution of EQ+ -- transitivity EQ-LEQ (1)+ , [ topeLEQT x z+ | TopeEQT _ty y z : newTopes' <- tails newTopes+ , TopeLEQT _ty x y' <- newTopes' <> oldTopes+ , eqT y y' ]++ -- transitivity EQ-LEQ (2)+ , [ topeLEQT x z+ | TopeEQT _ty x y : newTopes' <- tails newTopes+ , TopeLEQT _ty y' z <- newTopes' <> oldTopes+ , eqT y y' ]++ -- transitivity EQ-LEQ (3)+ , [ topeLEQT x z+ | TopeLEQT _ty y z : newTopes' <- tails newTopes+ , TopeEQT _ty x y' <- newTopes' <> oldTopes+ , eqT y y' ]++ -- transitivity EQ-LEQ (4)+ , [ topeLEQT x z+ | TopeLEQT _ty x y : newTopes' <- tails newTopes+ , TopeEQT _ty y' z <- newTopes' <> oldTopes+ , eqT y y' ]++ -- FIXME: consequence of LEM for LEQ and antisymmetry for LEQ+ , [ topeEQT x y | TopeLEQT _ty x y@Cube2_0T{} <- newTopes ]+ , [ topeEQT x y | TopeLEQT _ty x@Cube2_1T{} y <- newTopes ]+ , [ topeEQT x y | TopeLEQT _ty x y@CubeI_0T{} <- newTopes ]+ , [ topeEQT x y | TopeLEQT _ty x@CubeI_1T{} y <- newTopes ]++ -- subtyping 2 <: II: endpoints and order of 2 lift to II+ , [ topeEQT x cubeI_0T | TopeEQT _ty x Cube2_0T{} <- newTopes ]+ , [ topeEQT cubeI_0T x | TopeEQT _ty Cube2_0T{} x <- newTopes ]+ , [ topeEQT x cubeI_1T | TopeEQT _ty x Cube2_1T{} <- newTopes ]+ , [ topeEQT cubeI_1T x | TopeEQT _ty Cube2_1T{} x <- newTopes ]+ , [ topeLEQT x cubeI_0T | TopeLEQT _ty x Cube2_0T{} <- newTopes ]+ , [ topeLEQT cubeI_0T x | TopeLEQT _ty Cube2_0T{} x <- newTopes ]+ , [ topeLEQT x cubeI_1T | TopeLEQT _ty x Cube2_1T{} <- newTopes ]+ , [ topeLEQT cubeI_1T x | TopeLEQT _ty Cube2_1T{} x <- newTopes ]+ ]++generateTopesForPointsM :: Distinct n => [TermT n] -> TypeCheck n [TermT n]+generateTopesForPointsM points = do+ let endpoints = [cube2_0T, cube2_1T, cubeI_0T, cubeI_1T]+ pairs = nubPairs $ concat+ [ [ (x, y)+ | x : points' <- tails (filter (\p -> not (p `elemT` endpoints)) points)+ , y <- points'+ , not (eqT x y) ]+ ]+ stars <- forM points $ \x -> do+ xType <- typeOf x+ return $ case xType of+ CubeUnitT{} -> [topeEQT x cubeUnitStarT]+ _ -> []+ topes <- forM pairs $ \(x, y) -> do+ xType <- typeOf x+ yType <- typeOf y+ return $ case (xType, yType) of+ (Cube2T{}, Cube2T{}) -> [topeOrT (topeLEQT x y) (topeLEQT y x)]+ _ -> []+ return (concat (topes ++ stars))+ where+ nubPairs [] = []+ nubPairs (p@(x, y) : ps) =+ p : nubPairs (filter (\(x', y') -> not (eqT x x' && eqT y y')) ps)++allTopePoints :: Distinct n => TermT n -> [TermT n]+allTopePoints = nubT . foldMap subPoints . nubT . topePoints++topePoints :: TermT n -> [TermT n]+topePoints = \case+ TopeTopT{} -> []+ TopeBottomT{} -> []+ TopeAndT _ l r -> topePoints l <> topePoints r+ TopeOrT _ l r -> topePoints l <> topePoints r+ TopeEQT _ x y -> [x, y]+ TopeLEQT _ x y -> [x, y]+ _ -> []++subPoints :: TermT n -> [TermT n]+subPoints = \case+ p@(PairT _ x y) -> p : foldMap subPoints [x, y]+ p@(Var _) -> [p]+ p -> case typeInfoOf p of+ Just TypeInfo{ infoType = CubeUnitT{} } -> [p]+ Just TypeInfo{ infoType = Cube2T{} } -> [p]+ _ -> []++-- * Simplifying the left-hand side++-- | Simplify the context, including disjunctions.+simplifyLHSwithDisjunctions :: Distinct n => [ModalTope n] -> [[ModalTope n]]+simplifyLHSwithDisjunctions topes = map nubModalTopes $+ case topes of+ [] -> [[]]+ ModalTope _ _ TopeTopT{} : topes' -> simplifyLHSwithDisjunctions topes'+ ModalTope mAcc mVar TopeBottomT{} : _ -> [[ModalTope mAcc mVar topeBottomT]]+ ModalTope mAcc mVar (TopeAndT _ l r) : topes' ->+ simplifyLHSwithDisjunctions (ModalTope mAcc mVar l : ModalTope mAcc mVar r : topes')++ -- NOTE: it is inefficient to expand disjunctions immediately+ ModalTope mAcc mVar (TopeOrT _ l r) : topes' ->+ simplifyLHSwithDisjunctions (ModalTope mAcc mVar l : topes')+ <> simplifyLHSwithDisjunctions (ModalTope mAcc mVar r : topes')++ ModalTope mAcc mVar (TopeEQT _ (PairT _ x y) (PairT _ x' y')) : topes' ->+ simplifyLHSwithDisjunctions+ (ModalTope mAcc mVar (topeEQT x x') : ModalTope mAcc mVar (topeEQT y y') : topes')+ ModalTope mAcc mVar (TypeModalT _ md inTope) : topes' ->+ simplifyLHSwithDisjunctions (ModalTope mAcc (comp mVar md) inTope : topes')+ t : topes' -> map (t :) (simplifyLHSwithDisjunctions topes')++-- * Solving the right-hand side++solveRHSM :: Distinct n => [ModalTope n] -> TermT n -> TypeCheck n Bool+solveRHSM modalTopes goal =+ let topes = accessibleTopes modalTopes+ in case goal of+ _ | topeBottomT `elemT` topes -> return True+ TopeTopT{} -> return True+ TypeModalT _ty md inTope -> do+ let shifted = applyModalityToTopes md modalTopes+ resaturated = saturateTopes shifted+ resaturatedInv <- saturateInv resaturated+ solveRHSM resaturatedInv inTope+ TopeEQT _ty (PairT _ty1 x y) (PairT _ty2 x' y') ->+ solveRHSM modalTopes $ topeAndT (topeEQT x x') (topeEQT y y')+ TopeEQT _ty (PairT TypeInfo{ infoType = CubeProductT _ cubeI cubeJ } x y) r ->+ solveRHSM modalTopes $ topeAndT+ (topeEQT x (firstT cubeI r))+ (topeEQT y (secondT cubeJ r))+ TopeEQT _ty l (PairT TypeInfo{ infoType = CubeProductT _ cubeI cubeJ } x y) ->+ solveRHSM modalTopes $ topeAndT+ (topeEQT (firstT cubeI l) x)+ (topeEQT (secondT cubeJ l) y)+ TopeEQT _ty l r+ | or+ [ eqT l r+ , goal `elemT` topes+ , topeEQT r l `elemT` topes+ ] -> return True+ TopeEQT _ty l r -> do+ lType <- typeOf l+ rType <- typeOf r+ return $ case (lType, rType) of+ (CubeUnitT{}, CubeUnitT{}) -> True+ _ -> False+ TopeLEQT _ty l r+ | eqT l r -> return True+ | solveRHS topes (topeEQT l r) -> return True+ | solveRHS topes (topeEQT l cube2_0T) -> return True+ | solveRHS topes (topeEQT r cube2_1T) -> return True+ TopeAndT _ l r -> solveRHSM modalTopes l >>= \case+ False -> return False+ True -> solveRHSM modalTopes r+ _ | goal `elemT` topes -> return True+ TopeInvT{} -> do+ goal' <- nfTope goal+ case goal' of+ TopeInvT{} -> return False+ _ -> solveRHSM modalTopes goal'+ TopeUninvT{} -> do+ goal' <- nfTope goal+ case goal' of+ TopeUninvT{} -> return False+ _ -> solveRHSM modalTopes goal'+ TopeOrT _ l r -> do+ found <- solveRHSM modalTopes l >>= \case+ True -> return True+ False -> solveRHSM modalTopes r+ if found+ then return True+ else do+ lems <- generateTopesForPointsM (allTopePoints goal)+ let lems' = [ lem | lem@(TopeOrT _ t1 t2) <- lems, all (`notElemT` topes) [t1, t2] ]+ (accessible, hidden) = partitionAccessible modalTopes+ withTope t = hidden ++ saturateTopes (plainTope t : accessible)++ case lems' of+ TopeOrT _ t1 t2 : _ ->+ solveRHSM (withTope t1) goal >>= \case+ False -> return False+ True -> solveRHSM (withTope t2) goal+ _ -> return False+ _ -> return False++solveRHS :: Distinct n => [TermT n] -> TermT n -> Bool+solveRHS topes tope =+ case tope of+ _ | topeBottomT `elemT` topes -> True+ TopeTopT{} -> True+ TopeEQT _ty (PairT _ty1 x y) (PairT _ty2 x' y')+ | solveRHS topes (topeEQT x x') && solveRHS topes (topeEQT y y') -> True+ TopeEQT _ty (PairT TypeInfo{ infoType = CubeProductT _ cubeI cubeJ } x y) r+ | solveRHS topes (topeEQT x (firstT cubeI r))+ , solveRHS topes (topeEQT y (secondT cubeJ r)) -> True+ TopeEQT _ty l (PairT TypeInfo{ infoType = CubeProductT _ cubeI cubeJ } x y)+ | solveRHS topes (topeEQT (firstT cubeI l) x)+ , solveRHS topes (topeEQT (secondT cubeJ l) y) -> True+ TopeEQT _ty l r -> or+ [ eqT l r+ , tope `elemT` topes+ , topeEQT r l `elemT` topes+ ]+ TopeLEQT _ty l r+ | eqT l r -> True+ | solveRHS topes (topeEQT l r) -> True+ | solveRHS topes (topeEQT l cube2_0T) -> True+ | solveRHS topes (topeEQT r cube2_1T) -> True+ TopeAndT _ l r -> solveRHS topes l && solveRHS topes r+ TopeOrT _ l r -> solveRHS topes l || solveRHS topes r+ _ -> tope `elemT` topes++-- | Accumulate a modality over a list of topes.+applyModalityToTopes :: TModality -> [ModalTope n] -> [ModalTope n]+applyModalityToTopes md = map (\mt -> mt { tModAccum = comp (tModAccum mt) md })++partitionAccessible :: [ModalTope n] -> ([ModalTope n], [ModalTope n])+partitionAccessible topes = (filter isAccessible topes, filter (not . isAccessible) topes)++-- * The checks the rest of the checker calls++checkTope :: Distinct n => TermT n -> TypeCheck n Bool+checkTope tope = do+ topes <- asks availableTopes+ performing (ActionContextEntails topes tope) $ do+ tope' <- nfTope tope+ entailContextM tope'++checkTopeEntails :: Distinct n => TermT n -> TypeCheck n Bool+checkTopeEntails tope = do+ topes <- asks availableTopes+ performing (ActionContextEntailedBy topes tope) $ do+ contextTopes <- asks availableTopesNF+ restrictionTope <- nfTope tope+ let contextTopesRHS = foldr topeAndT topeTopT contextTopes+ [plainTope restrictionTope] `entailM` contextTopesRHS++checkEntails :: Distinct n => TermT n -> TermT n -> TypeCheck n Bool+checkEntails l r = do -- FIXME: add action+ l' <- nfTope l+ r' <- nfTope r+ [plainTope l'] `entailM` r'++contextEntails :: Distinct n => TermT n -> TypeCheck n ()+contextEntails tope = do+ topes <- asks availableTopes+ performing (ActionContextEntails topes tope) $ do+ topeIsEntailed <- checkTope tope+ topes' <- asks availableTopesNF+ -- When a hole is used in a cube/tope position (as the argument of a+ -- shape-restricted function, say), the tope being checked mentions the hole+ -- and cannot be decided. Treat it as satisfied (defer) rather than failing.+ unless (topeIsEntailed || containsHole tope) $+ issueTypeError $ TypeErrorTopeNotSatisfied topes' tope++-- | Is the local tope context contradictory (does it entail ⊥)?+contextEntailsBottom :: Distinct n => TypeCheck n Bool+contextEntailsBottom = asks ctxTopesEntailBottom >>= \case+ Just entails -> pure entails+ Nothing -> asks ctxTopesNF >>= (`entailM` topeBottomT)++topesEquiv :: Distinct n => TermT n -> TermT n -> TypeCheck n Bool+topesEquiv expected actual = performing (ActionUnifyTerms expected actual) $ do+ expected' <- nfT expected+ actual' <- nfT actual+ (&&)+ <$> [plainTope expected'] `entailM` actual'+ <*> [plainTope actual'] `entailM` expected'++-- | Check that the local tope context is included in (entails) the union of the+-- given topes. This is the COVERAGE obligation of @recOR@: every point of the+-- context must be covered by some branch guard.+--+-- Only coverage is required, not equivalence: branch guards may overhang the+-- context (when splitting with an already-defined shape, say), so we do not+-- require @OR(guards) |- context@.+contextEntailsUnion :: Distinct n => [TermT n] -> TypeCheck n ()+contextEntailsUnion topes = do+ ctxTopes' <- asks availableTopes+ performing (ActionContextEntailsUnion ctxTopes' topes) $ do+ contextTopes <- asks ctxTopesNF+ topesNF <- mapM nfTope topes+ let unionRHS = foldr topeOrT topeBottomT topesNF+ entailContextM unionRHS >>= \case+ -- a guard mentioning an (unfilled) hole can't be decided; defer coverage+ False | not (any containsHole topesNF) ->+ issueTypeError $ TypeErrorTopeNotSatisfied (accessibleTopes contextTopes) unionRHS+ _ -> return ()++-- | Diagnose a @recOR@ branch guard or a restriction face against the local tope+-- context. There are three cases, by how the tope relates to the context:+--+-- * DISJOINT — the tope and a consistent context have empty overlap (their+-- conjunction is ⊥). The face or branch is then vacuous everywhere, so this is+-- a hard error.+-- * OVERHANG — the tope is not entailed by the context but still overlaps it.+-- This is allowed and often intentional (splitting or restricting with an+-- already-defined shape, whose faces live on the whole cube rather than being+-- relativised to the context), so we only emit a non-fatal hint.+-- * CONTAINED — the tope entails the context: nothing to report.+checkTopeAgainstContext :: Distinct n => String -> TermT n -> TypeCheck n ()+checkTopeAgainstContext what tope = do+ -- a contradictory context is handled elsewhere (recBOT)+ ctxEntailsBottom <- contextEntailsBottom+ unless ctxEntailsBottom $ do+ contextTopes <- asks ctxTopesNF+ let topes = filter (not . eqT topeTopT) (accessibleTopes contextTopes)+ disjoint <- (plainTope tope : contextTopes) `entailM` topeBottomT+ -- a face or guard mentioning an (unfilled) hole can't be decided; defer+ if disjoint && not (containsHole tope)+ then issueTypeError (TypeErrorTopeContextDisjoint tope topes)+ else do+ -- The hint below is opt-in (#set-option "warn-overhang"): deciding+ -- whether the tope overhangs costs a solver entailment per face and+ -- guard, and overhang is legitimate.+ warnOverhang <- asks ctxWarnOverhang+ when warnOverhang $ do+ entailed <- checkTopeEntails tope -- tope |- AND(accessible context)+ unless entailed $ do+ naming <- asks namingOfContext+ traceTypeCheck Normal+ (intercalate "\n" $+ [ "Warning: " <> what <> " overhangs the local tope context"+ , " " <> ppTerm naming (untyped tope)+ , "is not entailed by the local context (normalised)"+ ] <> map ((" " <>) . ppTerm naming . untyped) topes)+ (return ())++-- * Restrictions and η++stripTypeRestrictions :: TermT n -> TermT n+stripTypeRestrictions (TypeRestrictedT _ty ty _restriction) = stripTypeRestrictions ty+stripTypeRestrictions t = t++-- | The term a restriction face pins down, when one of the faces holds.+tryRestriction :: Distinct n => TermT n -> TypeCheck n (Maybe (TermT n))+tryRestriction = \case+ TypeRestrictedT _ _ rs -> go rs+ _ -> pure Nothing+ where+ go [] = pure Nothing+ go ((tope, term') : rs') = checkTope tope >>= \case+ True -> pure (Just term')+ False -> go rs'++-- | Perform at most one η-expansion at the top level, to assist unification.+etaMatch+ :: Distinct n+ => Maybe (TermT n) -> TermT n -> TermT n -> TypeCheck n (TermT n, TermT n)+-- FIXME: double check the next 3 rules+etaMatch _mterm expected@TypeRestrictedT{} actual@TypeRestrictedT{} = pure (expected, actual)+etaMatch mterm expected (TypeRestrictedT _ty ty _rs) = etaMatch mterm expected ty+etaMatch (Just term) expected@TypeRestrictedT{} actual =+ etaMatch (Just term) expected (typeRestrictedT actual [(topeTopT, term)])+-- Subtyping on the interval.+etaMatch _mterm CubeIT{} Cube2T{} = pure (cubeIT, cubeIT)+etaMatch _mterm expected@LambdaT{} actual@LambdaT{} = pure (expected, actual)+etaMatch _mterm expected@PairT{} actual@PairT{} = pure (expected, actual)+etaMatch _mterm expected@LambdaT{} actual = do+ actual' <- etaExpand actual+ pure (expected, actual')+etaMatch _mterm expected actual@LambdaT{} = do+ expected' <- etaExpand expected+ pure (expected', actual)+etaMatch _mterm expected@PairT{} actual = do+ actual' <- etaExpand actual+ pure (expected, actual')+etaMatch _mterm expected actual@PairT{} = do+ expected' <- etaExpand expected+ pure (expected', actual)+etaMatch _mterm expected actual = pure (expected, actual)++etaExpand :: Distinct n => TermT n -> TypeCheck n (TermT n)+etaExpand term@LambdaT{} = pure term+etaExpand term@PairT{} = pure term+etaExpand term = do+ ty <- typeOf term+ case stripTypeRestrictions ty of+ TypeFunT _ty orig md param mtope ret -> do+ scope <- asks ctxScope+ pure $ withFreshIn scope $ \binder ->+ let z = Var (Foil.nameOf binder)+ body = appT (openWith (Foil.extendScope binder scope) (Foil.nameOf binder) ret)+ (Foil.sink term) z+ mtope' = fmap (\t -> ScopedAST binder (openWith (Foil.extendScope binder scope) (Foil.nameOf binder) t)) mtope+ in lambdaT ty orig+ (Just (LambdaParam md param mtope'))+ (ScopedAST binder body)++ TypeSigmaT _ty _orig _md a b -> do+ let firstTerm = firstT a term+ bInstantiated <- instantiate b firstTerm+ pure $ pairT ty firstTerm (secondT bInstantiated term)++ CubeProductT _ty a b -> pure $+ pairT ty (firstT a term) (secondT b term)++ _ -> pure term++-- * Layers++inCubeLayer :: Distinct n => TermT n -> TypeCheck n Bool+inCubeLayer = \case+ RecBottomT{} -> pure False+ UniverseT{} -> pure False++ UniverseCubeT{} -> pure True+ CubeProductT{} -> pure True+ CubeUnitT{} -> pure True+ CubeUnitStarT{} -> pure True+ Cube2T{} -> pure True+ Cube2_0T{} -> pure True+ Cube2_1T{} -> pure True++ t -> typeOf t >>= inCubeLayer++inTopeLayer :: Distinct n => TermT n -> TypeCheck n Bool+inTopeLayer = \case+ RecBottomT{} -> pure False+ UniverseT{} -> pure False++ UniverseCubeT{} -> pure True+ UniverseTopeT{} -> pure True++ CubeProductT{} -> pure True+ CubeUnitT{} -> pure True+ CubeUnitStarT{} -> pure True+ Cube2T{} -> pure True+ Cube2_0T{} -> pure True+ Cube2_1T{} -> pure True++ TopeTopT{} -> pure True+ TopeBottomT{} -> pure True+ TopeAndT{} -> pure True+ TopeOrT{} -> pure True+ TopeEQT{} -> pure True+ TopeLEQT{} -> pure True++ TypeFunT _ty orig md param _mtope ret ->+ inScope orig md param ret inTopeLayer++ t -> typeOfUncomputed t >>= inTopeLayer++-- * Weak head normal form++-- | Memoise a term's WHNF on its top node without reducing the term itself.+--+-- The returned term has the same (unreduced) structure, so free-variable and+-- @uses@ detection see exactly what the user wrote, while a later 'whnfT' is O(1)+-- via the cached form. Used when storing a definition's elaborated type and value,+-- where an in-place reduction could otherwise discard or expose a variable+-- occurrence.+memoizeWHNF :: Distinct n => TermT n -> TypeCheck n (TermT n)+memoizeWHNF t@(Var _) = pure t+memoizeWHNF t@(Node (AnnSig info sig)) = do+ w <- whnfT t+ pure (Node (AnnSig info { infoWHNF = Just w } sig))++whnfT :: Distinct n => TermT n -> TypeCheck n (TermT n)+-- A memoised weak head normal form is answered before entering 'performing',+-- which would push an action and rebuild the context just to look a value up. The+-- caches are hit constantly (every 'typeOf' consults one), and the bookkeeping+-- costs more than the answer.+whnfT t | Just info <- typeInfoOf t, Just t' <- infoWHNF info = pure t'+whnfT tt = performing (ActionWHNF tt) $ case tt of+ -- universe constants+ UniverseT{} -> pure tt+ UniverseCubeT{} -> pure tt+ UniverseTopeT{} -> pure tt++ -- cube layer (except vars, pairs, and applications)+ CubeProductT{} -> nfTope tt+ CubeUnitT{} -> pure tt+ CubeUnitStarT{} -> pure tt+ Cube2T{} -> pure tt+ Cube2_0T{} -> pure tt+ Cube2_1T{} -> pure tt+ CubeIT{} -> pure tt+ CubeI_0T{} -> pure tt+ CubeI_1T{} -> pure tt+ CubeFlipT{} -> nfTope tt+ CubeUnflipT{} -> nfTope tt++ -- tope layer (except vars, pairs of points, and applications)+ TopeTopT{} -> pure tt+ TopeBottomT{} -> pure tt+ TopeAndT{} -> nfTope tt+ TopeOrT{} -> nfTope tt+ TopeEQT{} -> nfTope tt+ TopeLEQT{} -> nfTope tt+ TopeInvT{} -> nfTope tt+ TopeUninvT{} -> nfTope tt++ -- type layer terms that should not be evaluated further+ LambdaT{} -> pure tt+ PairT{} -> pure tt+ ReflT{} -> pure tt+ TypeFunT{} -> pure tt+ TypeSigmaT{} -> pure tt+ TypeIdT{} -> pure tt+ TypeModalT{} -> pure tt+ RecBottomT{} -> pure tt+ TypeUnitT{} -> pure tt+ UnitT{} -> pure tt++ -- type ascriptions are ignored, since we already have a typechecked term+ TypeAscT _ty term _ty' -> whnfT term++ -- check if we have a cube or a tope term (if so, compute NF)+ _ -> typeOf tt >>= \case+ UniverseCubeT{} -> nfTope tt+ UniverseTopeT{} -> nfTope tt++ TypeUnitT{} -> pure unitT -- compute an expression of Unit type to unit+ -- FIXME: next line is ad hoc, should be improved!+ TypeRestrictedT _info TypeUnitT{} _rs -> pure unitT++ -- check if we have a cube point term (if so, compute NF)+ typeOf_tt -> typeOf typeOf_tt >>= \case+ UniverseCubeT{} -> nfTope tt++ -- now we are in the type layer+ _ -> fmap termIsWHNF $ do+ tryRestriction typeOf_tt >>= \case+ Just tt' -> whnfT tt'+ Nothing -> case tt of+ -- a hole is opaque: it never reduces, it is already a normal form+ HoleT{} -> pure tt+ t@(Var x) ->+ valueOfVar x >>= \case+ Nothing -> pure t+ Just term -> whnfT term++ AppT{} -> do+ scope <- asks ctxScope+ uncurry (applySpine scope) (collectAppSpine tt)++ LetT _ty _orig _mparam val body ->+ instantiate body val >>= whnfT+ LetModT ty orig app inn mparam val body ->+ (enterModality app $ whnfT val) >>= \case+ ModAppT _ md t | md == inn -> do+ val' <- enterModality md $ whnfT t+ instantiate body val' >>= whnfT+ b' | isRA inn -> do+ bty <- typeOf b' >>= \case+ TypeModalT _ _ t -> pure t+ _ -> panicImpossible "not modal in letmod"+ instantiate body (modExtractT bty app inn b') >>= whnfT+ _ -> pure (LetModT ty orig app inn mparam val body)+ FirstT ty t ->+ whnfT t >>= \case+ PairT _ l _r -> whnfT l+ t' -> pure (FirstT ty t')++ SecondT ty t ->+ whnfT t >>= \case+ PairT _ _l r -> whnfT r+ t' -> pure (SecondT ty t')+ ModAppT ty md b ->+ (enterModality md $ whnfT b) >>= \case+ ModExtractT _ app inn t | inn == md -> enterModality (comp md app) $ whnfT t+ b' -> pure $ ModAppT ty md b'+ ModExtractT ty app inn b ->+ (enterModality app $ whnfT b) >>= \case+ ModAppT _ md t | inn == md -> enterModality inn $ whnfT t+ b' -> pure (ModExtractT ty app inn b')+ IdJT ty tA a tC d x p ->+ whnfT p >>= \case+ ReflT{} -> whnfT d+ p' -> pure (IdJT ty tA a tC d x p')++ RecOrT _ty rs -> do+ firstMatching rs >>= \case+ Just tt' -> whnfT tt'+ Nothing+ | [tt'] <- nubT (map snd rs) -> whnfT tt'+ | otherwise -> pure tt++ TypeRestrictedT ty type_ rs -> do+ rs' <- traverse (\(tope, term) -> (,) <$> nfT tope <*> pure term) rs+ case filter (not . eqT topeBottomT . fst) rs' of+ [] -> whnfT type_ -- get rid of restrictions at BOT+ rs'' -> TypeRestrictedT ty <$> whnfT type_ <*> pure rs''++-- | The branch of a @recOR@ (or the face of a restriction) whose guard holds.+firstMatching :: Distinct n => [(TermT n, TermT n)] -> TypeCheck n (Maybe (TermT n))+firstMatching [] = pure Nothing+firstMatching ((tope, t) : rest) = checkTope tope >>= \case+ True -> pure (Just t)+ False -> firstMatching rest++-- * Application, reducing a whole spine at once+--+-- A curried application @f x y z@ is a left-nested tower of 'AppT'. Reducing it+-- one argument at a time rebuilds the intermediate lambdas — @f x@ produces+-- @\\ y z -> …@ only for the next argument to tear it apart — and each rebuild is+-- a full 'substituteT' traversal (~70% of beta reductions on sHoTT are such+-- spines). Instead, collect the spine, then peel the head's syntactic lambda+-- chain into a /single/ substitution: @\\ a b c -> body@ applied to @x y z@ maps+-- @{a↦x, b↦y, c↦z}@ and substitutes into @body@ once.+--+-- Sound because 'whnfT' of a lambda is the identity — a lambda, its binder+-- shape-restricted or not, is already in weak head normal form — so the+-- intermediate lambdas this skips building would have been returned unchanged,+-- and substitution composes. Beta reduction ignores the binder's domain (the+-- shape restriction is a typing obligation, not enforced during reduction); the+-- tope and modality side-conditions fire only for a /neutral/ function of+-- shape-restricted function type, which is never a lambda. The moment the body+-- is not a syntactic lambda the substitution is applied and control returns to+-- 'whnfT' via 'applySpine'; a neutral head goes to 'applyWhnfFun', unchanged.++-- | The head of an application spine and its arguments, in application order,+-- each paired with the type annotation of its 'AppT' node (needed to rebuild a+-- neutral application).+collectAppSpine :: TermT n -> (TermT n, [(TypeInfo (TermT n), TermT n)])+collectAppSpine = go []+ where+ go acc (AppT ty f x) = go ((ty, x) : acc) f+ go acc h = (h, acc)++-- | Apply a function term to a spine of arguments, reducing.+applySpine+ :: Distinct n+ => Foil.Scope n -> TermT n -> [(TypeInfo (TermT n), TermT n)] -> TypeCheck n (TermT n)+applySpine _ h [] = whnfT h+applySpine scope h pairs = whnfT h >>= \h' -> case h' of+ LambdaT _ _ _ (ScopedAST binder body) | (_, x) : rest <- pairs ->+ peelLambdas scope (Foil.addSubst Foil.identitySubst binder x) body rest+ _ -> applyNeutral scope h' pairs++-- | Peel the head's syntactic lambda chain into one substitution, then reduce.+-- @subst@ maps the binders consumed so far to their arguments; @body@ is the+-- current lambda's body, at the scope those binders extended into.+peelLambdas+ :: forall i n. Distinct n+ => Foil.Scope n -> Foil.Substitution TermT i n -> TermT i+ -> [(TypeInfo (TermT n), TermT n)] -> TypeCheck n (TermT n)+peelLambdas scope subst body pairs = case pairs of+ [] -> whnfT (substituteT scope subst body)+ (_, x) : rest -> case body of+ LambdaT _ _ _ (ScopedAST binder body') ->+ peelLambdas scope (Foil.addSubst subst binder x) body' rest+ _ -> applySpine scope (substituteT scope subst body) pairs++-- | Apply a non-lambda (already WHNF) function to a spine, one argument at a+-- time: this is the type-directed part of application, unchanged from before.+applyNeutral+ :: Distinct n+ => Foil.Scope n -> TermT n -> [(TypeInfo (TermT n), TermT n)] -> TypeCheck n (TermT n)+applyNeutral _ h [] = pure h+applyNeutral scope h ((ty, x) : rest) = do+ r <- applyWhnfFun ty h x+ if null rest then pure r else applySpine scope r rest++-- | Apply a non-lambda function @f'@ (already WHNF) to one argument @x@. A+-- shape-restricted function contributes a tope side-condition; a function whose+-- return type is restricted refines the application's type; everything else is a+-- neutral application. Extracted verbatim from the old single-argument @AppT@ case.+applyWhnfFun :: Distinct n => TypeInfo (TermT n) -> TermT n -> TermT n -> TypeCheck n (TermT n)+applyWhnfFun ty f' x = typeOf f' >>= \case+ TypeFunT _ty _orig md _param (Just tope) (ScopedAST _ UniverseTopeT{}) -> do+ x' <- enterModality md $ nfT x+ sideCondition <- instantiate tope x' >>= nfT+ pure (topeAndT (AppT ty f' x') sideCondition)+ -- FIXME: this seems to be a hack, and will not work in all+ -- situations! FIXME: for now, it seems to add ~2x slowdown+ TypeFunT info _orig md _param _mtope ret@(ScopedAST _ TypeRestrictedT{})+ | TypeRestrictedT{} <- infoType info -> pure (AppT ty f' x)+ | otherwise -> do+ x' <- enterModality md $ whnfT x+ ret' <- instantiate ret x'+ tryRestriction ret' >>= \case -- FIXME: too many unnecessary checks?+ Nothing -> pure (AppT ty { infoType = ret' } f' x')+ Just tt' -> whnfT tt'+ _ -> pure (AppT ty f' x)++-- * Normal form of the tope layer++nfTope :: Distinct n => TermT n -> TypeCheck n (TermT n)+nfTope tt = performing (ActionNF tt) $ fmap termIsNF $ case tt of+ HoleT{} -> pure tt+ Var x ->+ valueOfVar x >>= \case+ Nothing -> return tt+ Just term -> nfTope term++ -- see if a normal form is already available+ _ | Just info <- typeInfoOf tt, Just tt' <- infoNF info -> pure tt'++ -- universe constants+ UniverseT{} -> pure tt+ UniverseCubeT{} -> pure tt+ UniverseTopeT{} -> pure tt++ -- cube layer constants+ CubeUnitT{} -> pure tt+ CubeUnitStarT{} -> pure tt+ Cube2T{} -> pure tt+ Cube2_0T{} -> pure tt+ Cube2_1T{} -> pure tt+ CubeIT{} -> pure tt+ CubeI_0T{} -> pure tt+ CubeI_1T{} -> pure tt++ -- type layer constants+ TypeUnitT{} -> pure tt+ UnitT{} -> pure tt++ -- cube layer with computation+ CubeProductT _ty l r -> cubeProductT <$> nfTope l <*> nfTope r++ CubeFlipT ty t ->+ nfTope t >>= \case+ CubeUnflipT _ t' -> pure t'+ Cube2_0T{} -> pure (modAppT (typeModalT cubeT Op cube2T) Op cube2_1T)+ Cube2_1T{} -> pure (modAppT (typeModalT cubeT Op cube2T) Op cube2_0T)+ CubeI_0T{} -> pure (modAppT (typeModalT cubeT Op cubeIT) Op cubeI_1T)+ CubeI_1T{} -> pure (modAppT (typeModalT cubeT Op cubeIT) Op cubeI_0T)+ t' -> pure (CubeFlipT ty t')++ CubeUnflipT ty t ->+ nfTope t >>= \case+ CubeFlipT _ t' -> pure t'+ ModAppT _ Op Cube2_0T{} -> pure cube2_1T+ ModAppT _ Op Cube2_1T{} -> pure cube2_0T+ ModAppT _ Op CubeI_0T{} -> pure cubeI_1T+ ModAppT _ Op CubeI_1T{} -> pure cubeI_0T+ t' -> pure (CubeUnflipT ty t')++ -- tope layer constants+ TopeTopT{} -> pure tt+ TopeBottomT{} -> pure tt++ -- tope layer with computation+ TopeAndT ty l r ->+ nfTope l >>= \case+ TopeBottomT{} -> pure topeBottomT+ l' -> nfTope r >>= \case+ TopeBottomT{} -> pure topeBottomT+ r' -> pure (TopeAndT ty l' r')++ TopeOrT ty l r -> do+ l' <- nfTope l+ r' <- nfTope r+ case (l', r') of+ (TopeBottomT{}, _) -> pure r'+ (_, TopeBottomT{}) -> pure l'+ _ -> pure (TopeOrT ty l' r')++ TopeEQT ty l r -> TopeEQT ty <$> nfTope l <*> nfTope r+ TopeLEQT ty l r -> TopeLEQT ty <$> nfTope l <*> nfTope r++ TopeInvT ty t ->+ -- Match And/Or on the *unnormalised* input: nfTope of a shape-restricted App+ -- produces a TopeAnd via shape-side-condition propagation, and distributing+ -- inv over that synthetic conjunction loops forever, because the recursive+ -- topeInvT renormalises the same App back into a TopeAnd.+ case t of+ TopeTopT _ -> pure $ modAppT topeT Op topeTopT+ TopeBottomT _ -> pure $ modAppT topeT Op topeBottomT+ TopeLEQT _ x y -> invOf topeLEQT x y+ TopeEQT _ x y -> invOf topeEQT x y+ TopeAndT _ phi psi -> nfTope $+ modAppT (typeModalT universeT Op topeT) Op+ (topeAndT+ (modExtractT topeT Id Op (topeInvT phi))+ (modExtractT topeT Id Op (topeInvT psi)))+ TopeOrT _ phi psi -> nfTope $+ modAppT (typeModalT universeT Op topeT) Op+ (topeOrT+ (modExtractT topeT Id Op (topeInvT phi))+ (modExtractT topeT Id Op (topeInvT psi)))+ _ ->+ nfTope t >>= \case+ TopeTopT _ -> pure topeTopT+ TopeBottomT _ -> pure topeBottomT+ TopeUninvT _ phi -> pure phi+ TopeLEQT _ x y -> invOf topeLEQT x y+ TopeEQT _ x y -> invOf topeEQT x y+ t' -> pure (TopeInvT ty t')+ where+ invOf mk x y = do+ xTy <- typeOf x+ yTy <- typeOf y+ nfTope $+ modAppT (typeModalT universeT Op topeT) Op+ (mk (modExtractT topeT Id Op (cubeFlipT xTy y))+ (modExtractT topeT Id Op (cubeFlipT yTy x)))++ TopeUninvT ty t ->+ case t of+ ModAppT _ Op inner -> case inner of+ TopeTopT _ -> pure topeTopT+ TopeBottomT _ -> pure topeBottomT+ TopeAndT _ phi psi ->+ nfTope (topeAndT (topeUninvT phi) (topeUninvT psi))+ TopeOrT _ phi psi ->+ nfTope (topeOrT (topeUninvT phi) (topeUninvT psi))+ _ ->+ nfTope t >>= \case+ TopeTopT _ -> pure topeTopT+ TopeBottomT _ -> pure topeBottomT+ TopeInvT _ phi -> pure phi+ ModAppT _ Op inner'' -> case inner'' of+ TopeLEQT _ x y -> uninvOf topeLEQT x y+ TopeEQT _ x y -> uninvOf topeEQT x y+ inner' ->+ pure $ TopeUninvT ty+ (modAppT (typeModalT universeT Op topeT) Op inner')+ t' -> pure (TopeUninvT ty t')+ _ ->+ nfTope t >>= \case+ TopeInvT _ phi -> pure phi+ t'@(ModAppT _ Op _) -> nfTope (TopeUninvT ty t')+ t' -> pure (TopeUninvT ty t')+ where+ uninvOf mk x y = do+ xTy <- typeOf x+ yTy <- typeOf y+ nfTope $+ mk (cubeUnflipT xTy (modAppT (typeModalT cubeT Op xTy) Op y))+ (cubeUnflipT yTy (modAppT (typeModalT cubeT Op yTy) Op x))++ -- type ascriptions are ignored, since we already have a typechecked term+ TypeAscT _ty term _ty' -> nfTope term++ PairT ty l r -> PairT ty <$> nfTope l <*> nfTope r++ AppT ty f x ->+ nfTope f >>= \case+ LambdaT _ty _orig _arg body ->+ instantiate body x >>= nfTope+ f' -> typeOfUncomputed f' >>= \case+ TypeFunT _ty _orig md _param (Just tope) (ScopedAST _ UniverseTopeT{}) -> do+ x' <- enterModality md $ nfTope x+ sideCondition <- instantiate tope x' >>= nfTope+ pure (topeAndT (AppT ty f' x') sideCondition)+ _ -> AppT ty f' <$> nfTope x++ FirstT ty t ->+ nfTope t >>= \case+ PairT _ty x _y -> pure x+ t' -> pure (FirstT ty t')++ SecondT ty t ->+ nfTope t >>= \case+ PairT _ty _x y -> pure y+ t' -> pure (SecondT ty t')++ LambdaT ty orig _mparam body+ | TypeFunT _ty _origF md param mtope _ret <- infoType ty -> do+ -- NOTE: the domain @param@ is left unnormalised: in the tope layer it may+ -- be a shape (a function type into TOPE), which nfTope cannot normalise.+ body' <- underScope orig md param Nothing body nfTope+ pure (LambdaT ty orig (Just (LambdaParam md param mtope)) body')+ LambdaT{} -> panicImpossible "lambda with a non-function type in the tope layer"++ ModAppT ty md b ->+ (enterModality md $ nfTope b) >>= \case+ ModExtractT _ _ inn t | inn == md -> pure t+ b' -> pure $ ModAppT ty md b'+ ModExtractT ty app inn b ->+ (enterModality app $ nfTope b) >>= \case+ ModAppT _ md t | inn == md -> pure t+ b' -> pure $ ModExtractT ty app inn b'+ LetModT ty orig app inn mparam val body ->+ (enterModality app $ nfTope val) >>= \case+ ModAppT _ md t | md == inn ->+ instantiate body t >>= nfTope+ b' | isRA inn -> do+ bty <- typeOf b' >>= \case+ TypeModalT _ _ t -> pure t+ _ -> panicImpossible "not modal in letmod"+ instantiate body (modExtractT bty app inn b') >>= nfTope+ b' -> do+ bty <- typeOf b' >>= \case+ TypeModalT _ _ t -> pure t+ _ -> panicImpossible "not modal in letmod"+ val' <- enterModality app $ nfTope b'+ body' <- underScope orig (comp app inn) bty Nothing body nfTope+ pure (LetModT ty orig app inn mparam val' body')++ TypeModalT ty md inner -> TypeModalT ty md <$> (enterModality md $ nfTope inner)+ LetT _ty _orig _mparam val body -> instantiate body val >>= nfTope+ TypeFunT{} -> panicImpossible "exposed function type in the tope layer"+ TypeSigmaT{} -> panicImpossible "dependent sum type in the tope layer"+ TypeIdT{} -> panicImpossible "identity type in the tope layer"+ ReflT{} -> panicImpossible "refl in the tope layer"+ IdJT{} -> panicImpossible "idJ eliminator in the tope layer"+ TypeRestrictedT{} -> panicImpossible "extension types in the tope layer"++ -- A recOR/recBOT is a term-level eliminator, never a tope. It should have been+ -- rejected before reaching here (see the RecOr case of 'typecheck'); as a safety+ -- net for any other path, report a type error rather than panicking.+ RecOrT{} -> issueTypeError $ TypeErrorOther "a recOR cannot appear in the tope layer"+ RecBottomT{} -> issueTypeError $ TypeErrorOther "a recBOT cannot appear in the tope layer"++-- * Normal form++nfT :: Distinct n => TermT n -> TypeCheck n (TermT n)+nfT tt = performing (ActionNF tt) $ case tt of+ -- universe constants+ UniverseT{} -> pure tt+ UniverseCubeT{} -> pure tt+ UniverseTopeT{} -> pure tt++ -- cube layer constants+ CubeUnitT{} -> pure tt+ CubeUnitStarT{} -> pure tt+ Cube2T{} -> pure tt+ Cube2_0T{} -> pure tt+ Cube2_1T{} -> pure tt+ CubeIT{} -> pure tt+ CubeI_0T{} -> pure tt+ CubeI_1T{} -> pure tt++ -- cube layer with computation+ CubeProductT{} -> nfTope tt+ CubeFlipT{} -> nfTope tt+ CubeUnflipT{} -> nfTope tt++ -- tope layer constants+ TopeTopT{} -> pure tt+ TopeBottomT{} -> pure tt++ -- tope layer with computation+ TopeAndT{} -> nfTope tt+ TopeOrT{} -> nfTope tt+ TopeEQT{} -> nfTope tt+ TopeLEQT{} -> nfTope tt+ TopeInvT{} -> nfTope tt+ TopeUninvT{} -> nfTope tt++ -- type layer constants+ ReflT ty _x -> pure (ReflT ty Nothing)+ RecBottomT{} -> pure tt+ TypeUnitT{} -> pure tt+ UnitT{} -> pure tt++ -- type ascriptions are ignored, since we already have a typechecked term+ TypeAscT _ty term _ty' -> nfT term++ -- now we are in the type layer+ _ ->+ typeOf tt >>= tryRestriction >>= \case+ Just tt' -> nfT tt'+ Nothing -> case tt of+ -- a hole is opaque: it never reduces, it is already a normal form+ HoleT{} -> pure tt+ t@(Var x) ->+ valueOfVar x >>= \case+ Nothing -> pure t+ Just term -> nfT term++ TypeFunT ty orig md param mtope ret -> do+ param' <- enterModality md $ nfT param+ case mtope of+ Nothing -> do+ ret' <- underScope orig md param' Nothing ret nfT+ pure (TypeFunT ty orig md param' Nothing ret')+ Just tope -> do+ (tope', ret') <- underScope2 orig md param' tope ret $ \topeBody retBody -> do+ topeNF <- nfT topeBody+ retNF <- localTope topeNF (nfT retBody)+ pure (topeNF, retNF)+ pure (TypeFunT ty orig md param' (Just tope') ret')++ AppT ty f x ->+ whnfT f >>= \case+ LambdaT _ty _orig _arg body ->+ instantiate body x >>= nfT+ f' -> typeOf f' >>= \case+ TypeFunT _ty _orig md _param (Just tope) (ScopedAST _ UniverseTopeT{}) -> do+ x' <- enterModality md $ nfT x+ sideCondition <- instantiate tope x' >>= nfT+ pure (topeAndT (AppT ty f' x') sideCondition)+ _ -> AppT ty <$> nfT f' <*> nfT x+ LetT _ty _orig _mparam val body ->+ instantiate body val >>= nfT+ LetModT ty orig app inn mparam val body ->+ (enterModality app $ whnfT val) >>= \case+ ModAppT _ md t | md == inn -> do+ val' <- enterModality md $ nfT t+ instantiate body val' >>= nfT+ b' | isRA inn -> do+ bty <- typeOf b' >>= \case+ TypeModalT _ _ t -> pure t+ _ -> panicImpossible "not modal in letmod"+ instantiate body (modExtractT bty app inn b') >>= nfT+ b' -> do+ bty <- typeOf b' >>= \case+ TypeModalT _ _ t -> pure t+ _ -> panicImpossible "not modal in letmod"+ val' <- enterModality app $ nfT b'+ body' <- underScope orig (comp app inn) bty Nothing body nfT+ pure (LetModT ty orig app inn mparam val' body')+ LambdaT ty orig _mparam body ->+ case stripTypeRestrictions (infoType ty) of+ TypeFunT _ty _orig md param mtope _ret -> do+ param' <- enterModality md $ nfT param+ case mtope of+ Nothing -> do+ body' <- underScope orig md param' Nothing body nfT+ pure (LambdaT ty orig (Just (LambdaParam md param' Nothing)) body')+ Just tope -> do+ (tope', body') <- underScope2 orig md param' tope body $ \topeBody bodyBody -> do+ topeNF <- nfT topeBody+ bodyNF <- localTope topeNF (nfT bodyBody)+ pure (topeNF, bodyNF)+ pure (LambdaT ty orig (Just (LambdaParam md param' (Just tope'))) body')+ _ -> panicImpossible "lambda with a non-function type"++ TypeSigmaT ty orig md a b -> do+ a' <- enterModality md $ nfT a+ b' <- underScope orig md a' Nothing b nfT+ pure (TypeSigmaT ty orig md a' b')+ PairT ty l r -> PairT ty <$> nfT l <*> nfT r+ FirstT ty t ->+ whnfT t >>= \case+ PairT _ l _r -> nfT l+ t' -> FirstT ty <$> nfT t'+ SecondT ty t ->+ whnfT t >>= \case+ PairT _ _l r -> nfT r+ t' -> SecondT ty <$> nfT t'++ TypeIdT ty x _tA y -> TypeIdT ty <$> nfT x <*> pure Nothing <*> nfT y+ IdJT ty tA a tC d x p ->+ whnfT p >>= \case+ ReflT{} -> nfT d+ p' -> IdJT ty <$> nfT tA <*> nfT a <*> nfT tC <*> nfT d <*> nfT x <*> nfT p'++ RecOrT _ty rs ->+ firstMatching rs >>= \case+ Just tt' -> nfT tt'+ Nothing+ | [tt'] <- nubT (map snd rs) -> nfT tt'+ | otherwise -> pure tt+ TypeModalT ty md b -> do+ b' <- enterModality md $ nfT b+ pure (TypeModalT ty md b')+ ModAppT ty md b ->+ (enterModality md $ whnfT b) >>= \case+ ModExtractT _ app inn t | inn == md -> enterModality (comp app inn) $ nfT t+ b' -> ModAppT ty md <$> (enterModality md $ nfT b')+ ModExtractT ty app inn b ->+ (enterModality app $ whnfT b) >>= \case+ ModAppT _ md t | inn == md -> enterModality (comp app inn) $ nfT t+ b' -> ModExtractT ty app inn <$> (enterModality app $ nfT b')+ TypeRestrictedT ty type_ rs -> do+ rs' <- forM rs $ \(tope, term) ->+ nfTope tope >>= \case+ TopeBottomT{} -> pure Nothing+ tope' -> do+ term' <- localTope tope' (nfT term)+ return (Just (tope', term'))+ case catMaybes rs' of+ [] -> nfT type_+ rs'' -> TypeRestrictedT ty <$> nfT type_ <*> pure rs''
+ src/Rzk/TypeCheck/Judgements.hs view
@@ -0,0 +1,1185 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | The judgements — @typecheck@ and @infer@ — and the hole inventory.+--+-- The two belong together: checking a hole records its goal and context, and+-- recording a hole probes what could fill it, which typechecks and unifies+-- candidate terms.+module Rzk.TypeCheck.Judgements where++import Control.Applicative ((<|>))+import Control.Monad (forM, forM_, unless, when)+import Control.Monad.Except (catchError)+import Control.Monad.Reader (asks, local)+import Control.Monad.Writer.CPS (censor)+import Data.List (intercalate, tails)+import Data.Maybe (fromMaybe, isNothing)+import Data.String (fromString)++import Control.Monad.Foil (Distinct)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Free.Foil (AST (Var), ScopedAST (..))++import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), TModality (..),+ TypeInfo (..), VarIdent,+ binderDisplayName, binderIsCompound,+ binderLeaves, binderName,+ freshenBinderLeaves, getVarIdent,+ ppVarIdentWithLocation,+ unmarkUnresolved)+import qualified Language.Rzk.Syntax as Rzk+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Display+import Rzk.TypeCheck.Error+import Rzk.TypeCheck.Eval+import Rzk.TypeCheck.Monad+import Rzk.TypeCheck.Render+import Rzk.TypeCheck.Unify++-- * Layers of a goal++isCubeType :: TermT n -> Bool+isCubeType = \case+ CubeUnitT{} -> True+ Cube2T{} -> True+ CubeIT{} -> True+ CubeProductT{} -> True+ UniverseCubeT{} -> True+ _ -> False++-- | Is a (WHNF) goal type in the cube or tope layer, so that a hole of this type+-- is a cube point or a tope rather than a term? Used to suppress the+-- type-layer-specific hole candidates (@recOR@, @recBOT@), which cannot inhabit a+-- cube or a tope.+isCubeOrTopeType :: TermT n -> Bool+isCubeOrTopeType t = isCubeType t || case t of+ UniverseTopeT{} -> True+ _ -> False++-- * Shadowing++-- | The names in scope a new one would shadow.+doesShadowName :: VarIdent -> TypeCheck n [VarIdent]+doesShadowName name = asks (shadowedBy name)++checkTopLevelDuplicate :: Distinct n => VarIdent -> TypeCheck n ()+checkTopLevelDuplicate name =+ doesShadowName name >>= \case+ [] -> return ()+ collisions -> issueTypeError $ TypeErrorDuplicateTopLevel collisions name++checkNameShadowing :: VarIdent -> TypeCheck n ()+checkNameShadowing name =+ doesShadowName name >>= \case+ [] -> return ()+ collisions -> issueWarning $+ Rzk.printTree (getVarIdent name) <> " shadows an existing definition:"+ <> unlines+ [ " " <> ppVarIdentWithLocation name+ , "previous top-level definitions found at"+ , intercalate "\n"+ [ " " <> ppVarIdentWithLocation prev | prev <- collisions ] ]++-- * The hole inventory++-- | A fresh hole of the given type.+mkHole :: TermT n -> TermT n+mkHole t = HoleT TypeInfo{ infoType = t, infoWHNF = Nothing, infoNF = Nothing } Nothing++-- | How many /branching/ eliminators 'allEliminationsInto' will chain.+--+-- A forced Π-application is free (see 'allEliminationsInto'), so this bounds only+-- the Σ/cube projections and @idJ@ steps, not the argument count of a spine. A+-- temporary fixed bound: branching is shallow in the goals seen so far (a few+-- projections), and a larger bound mostly adds self-referential spines (a built+-- result eliminated again).+maxEliminationDepth :: Int+maxEliminationDepth = 7++-- | Whether eliminating a value spends the search budget. A forced Π-application+-- is a 'SpineStep' — there is one way to fill the argument (with a hole), so+-- 'allEliminationsInto' applies it for free; a 'Branching' eliminator (a Σ/cube+-- projection or @idJ@) costs one against 'maxEliminationDepth'.+data ElimCost = SpineStep | Branching+ deriving (Eq, Show)++-- | All ways to eliminate a hypothesis into a value usable at a goal.+--+-- Given a @target@ type and a hypothesis /term/, return every elimination spine+-- over that term whose type fits the target (or a subtype of it). Arguments+-- introduced by application are left as holes for the caller to fill later. A+-- value that already fits is returned as-is; a function is applied to holes; a+-- Σ-type (or anything that unfolds to one, e.g. @is-contr@) is projected, possibly+-- repeatedly — so @first (first (is-segal-A ? ? ? ? ?))@ is discovered.+--+-- A Π-application is a forced spine step, so it extends the spine for free and+-- does not spend the budget. Only the genuinely branching eliminators count+-- against 'maxEliminationDepth', so the bound limits real search depth, not+-- argument count, and a lemma that must be applied to many holes is still reached.+allEliminationsInto+ :: Distinct n => TermT n -> TermT n -> TypeCheck n [TermT n]+allEliminationsInto target = go maxEliminationDepth+ where+ go depth term = do+ ty <- typeOf term+ fits <- fitsInto term ty target+ elims <- eliminatorsOf ty+ let step (SpineStep, wrap) = go depth =<< wrap term+ step (Branching, wrap)+ | depth <= 0 = pure []+ | otherwise = go (depth - 1) =<< wrap term+ deeper <- concat <$> mapM step elims+ pure ([term | fits] <> deeper)++-- | Whether a term of the given (whnf) type may stand where a value of the+-- @target@ type is expected: the two types unify under 'structuralHoleUnify', so a+-- hole acts as a wildcard leaf but a structural mismatch around it is still a+-- mismatch (an under-applied function does not match an extension-type goal, but a+-- partial application that genuinely fits an ordinary-function goal does).+--+-- Outer type restrictions are stripped from both sides first: an extension-type+-- boundary is satisfied by later refinement, not by the choice of spine, and+-- matching against the restricted goal would reject the very spine that introduces+-- the holes meant to satisfy it (@f ?@ at a boundary goal, say).+--+-- Holes or constraints recorded while probing are discarded, so this is a pure+-- yes\/no query.+fitsInto :: Distinct n => TermT n -> TermT n -> TermT n -> TypeCheck n Bool+fitsInto term ty target = do+ ty' <- stripTypeRestrictions <$> whnfT ty+ target' <- stripTypeRestrictions <$> whnfT target+ censor (const []) $ local structuralHoleUnify+ ((unify (Just term) target' ty' >> pure True) `catchError` \_ -> pure False)++-- | The eliminators a value of the given (weak head normal) type admits, each as a+-- function wrapping the eliminated term, paired with its 'ElimCost'.+--+-- A Π-type is eliminated by application to a fresh hole (a spine step); a Σ-type by+-- either projection; an identity type by path induction (@idJ@), with the motive+-- and base case left as holes. The projections and @idJ@ branch. Anything else+-- admits no simple eliminator.+eliminatorsOf+ :: Distinct n+ => TermT n -> TypeCheck n [(ElimCost, TermT n -> TypeCheck n (TermT n))]+eliminatorsOf ty =+ case stripTypeRestrictions ty of+ TypeFunT _ty _orig _md param _mtope ret ->+ pure [ (SpineStep, \term -> do+ let h = mkHole param+ retAt <- instantiate ret h+ pure (appT retAt term h)) ]+ TypeSigmaT _ty _orig _md a b ->+ pure [ (Branching, \term -> pure (firstT a term))+ , (Branching, \term -> do+ bAt <- instantiate b (firstT a term)+ pure (secondT bAt term)) ]+ -- A cube point pair (a pattern-bound @(t , s) : 2 × 2@, say) projects to its+ -- coordinates; rzk renders those projections back as the pattern names.+ CubeProductT _ty a b ->+ pure [ (Branching, \term -> pure (firstT a term))+ , (Branching, \term -> pure (secondT b term)) ]+ -- A path @p : a =_A x@ is eliminated by path induction. The motive+ -- @C : (z : A) → (a =_A z) → U@ is always a function, so we introduce it+ -- straight away as @\\ b q → ?@ rather than leaving it a bare hole: the spine+ -- @idJ A a (\\ b q → ?) ? x p@ then has type @C x p@, which β-reduces to that+ -- inner hole — so J fits any goal (the player fills the motive and the base case+ -- @d : C a refl@). The two holes are the motive predicate and the base.+ TypeIdT _ty a mtA x -> do+ tA <- maybe (typeOf a) pure mtA+ scope <- asks ctxScope+ let c = motiveOf scope a tA+ dType = appT universeT+ (appT (typeFunT (BinderVar Nothing) Id (typeIdT a (Just tA) a) Nothing+ (closedScope scope universeT))+ c a)+ (reflT (typeIdT a (Just tA) a) Nothing)+ d = mkHole dType+ motiveAt y p = appT universeT+ (appT (typeFunT (BinderVar Nothing) Id (typeIdT a (Just tA) y) Nothing+ (closedScope scope universeT))+ c y) p+ pure [ (Branching, \p -> pure (idJT (motiveAt x p) tA a c d x p)) ]+ _ -> pure []++-- | A scoped term that does not use its binder.+closedScope :: Distinct n => Foil.Scope n -> (forall l. TermT l) -> ScopedTermT n+closedScope scope t = Foil.withFresh scope $ \binder -> ScopedAST binder t++-- | The motive @\\ b q → ?@ of a path induction: a type in the two motive binders,+-- left as a hole.+motiveOf :: Distinct n => Foil.Scope n -> TermT n -> TermT n -> TermT n+motiveOf scope a tA =+ Foil.withFresh scope $ \bBinder ->+ let scopeB = Foil.extendScope bBinder scope+ b = Var (Foil.nameOf bBinder)+ idTypeAtB = typeIdT (Foil.sink a) (Just (Foil.sink tA)) b+ in Foil.withFresh scopeB $ \qBinder ->+ let cBody = mkHole universeT+ cInner = lambdaT+ (typeFunT (BinderVar Nothing) Id idTypeAtB Nothing+ (ScopedAST qBinder universeT))+ (BinderVar (Just "q")) Nothing+ (ScopedAST qBinder cBody)+ cType = typeFunT (BinderVar Nothing) Id tA Nothing+ (ScopedAST bBinder+ (typeFunT (BinderVar Nothing) Id idTypeAtB Nothing+ (ScopedAST qBinder universeT)))+ in lambdaT cType (BinderVar (Just "b")) Nothing (ScopedAST bBinder cInner)++-- | The binder for a λ introduced over a domain type.+--+-- A binder the type already gives as a pattern is kept as-is — it carries the+-- user's own names (@(t , s)@). Otherwise an /explicit/ (pre-whnf) Σ-type or+-- product domain is destructured into a fresh pair pattern, recursively for+-- products, so that a nameless @2 × 2 × 2@ parameter is introduced as+-- @((t1 , t2) , t3)@ rather than a single opaque variable. Any other domain keeps+-- its single binder.+--+-- Leaves are named by what they range over: a cube-product component is a point,+-- named @tN@; a Σ component is a term, named @xN@. The names are display-only (the+-- body is a hole that does not mention them) and carry a shared running index, so+-- every leaf in the pattern is distinct.+destructuringBinder :: Binder -> TermT n -> Binder+destructuringBinder orig param = case orig of+ BinderPair{} -> orig -- already a pattern: keep the user's names+ _ -> case param of+ CubeProductT{} -> fst (go (1 :: Int) param)+ TypeSigmaT{} -> fst (go (1 :: Int) param)+ _ -> orig -- not a product/Σ: leave the binder alone+ where+ -- a product/Σ becomes a pair; we recurse into a product's components (plain+ -- types) but not under a Σ's binder (a scope). A leaf is named by its enclosing+ -- constructor: @tN@ under a cube product, @xN@ under a Σ.+ go n = \case+ CubeProductT _ a b ->+ let (l, n') = child "t" n a+ (r, n'') = child "t" n' b+ in (BinderPair l r, n'')+ TypeSigmaT _ _ _md a _b ->+ let (l, n') = child "x" n a+ in (BinderPair l (BinderVar (Just (leaf "x" n'))), n' + 1)+ _ -> (BinderVar (Just (leaf "t" n)), n + 1) -- unreached: go is called on products only+ child pfx n = \case+ c@CubeProductT{} -> go n c+ c@TypeSigmaT{} -> go n c+ _ -> (BinderVar (Just (leaf pfx n)), n + 1)+ leaf pfx n = fromString (pfx <> show n :: String)++-- | All ways to introduce a value /of/ a goal type by its head constructor,+-- leaving the constituents as holes:+--+-- * a Π-type is introduced by a λ-abstraction over a hole body (@\\ x -> ?@); the+-- binder is taken from the type, so a pattern domain (a @Δ²@ point @(t , s)@,+-- say) is introduced as @\\ (t , s) -> ?@;+-- * a Σ-type or a cube product by a pair of holes (@(? , ?)@);+-- * an identity type by @refl@, but only when its two endpoints already agree+-- (otherwise @refl@ would not typecheck);+-- * the unit type by @unit@;+-- * the tope universe by each tope constructor — @TOP@, @BOT@, @? ≡ ?@, @? ≤ ?@,+-- @? ∧ ?@, @? ∨ ?@ — so a shape (a hole of type @TOPE@) can be built up by+-- tapping.+--+-- Unlike 'allEliminationsInto' this does not search: a type has at most one+-- introduction form (the tope universe is the one exception), read off its head+-- constructor. Outer restrictions are stripped first, so an extension type is+-- introduced by the form of its underlying type (its boundary is met by later+-- refinement of the holes, not by the choice of constructor).+--+-- The λ binder of a Π-introduction is freshened against the names already visible+-- at the hole, so introducing over a type whose own definition reuses an in-scope+-- name (@hom@, whose internal binder is @t@) yields @\\ t₁ -> ?@ rather than a @t@+-- that shadows the existing one.+allIntroductionsOf+ :: Distinct n => TermT n -> [VarIdent] -> TypeCheck n [TermT n]+allIntroductionsOf target inScopeNames = do+ target' <- stripTypeRestrictions <$> whnfT target+ scope <- asks ctxScope+ case target' of+ TypeFunT _ty orig _md param _mtope ret -> do+ let binder = freshenBinderLeaves inScopeNames (destructuringBinder orig param)+ pure $ Foil.withFresh scope $ \b ->+ let retAt = openWith (Foil.extendScope b scope) (Foil.nameOf b) ret+ in [ lambdaT target' binder Nothing (ScopedAST b (mkHole retAt)) ]+ TypeSigmaT _ty _orig _md a b -> do+ let h = mkHole a+ bAt <- instantiate b h+ pure [ pairT target' h (mkHole bAt) ]+ CubeProductT _ty a b ->+ pure [ pairT target' (mkHole a) (mkHole b) ]+ TypeIdT _ty a _tA b -> do+ agree <- endpointsAgree a b+ pure [ reflT target' Nothing | agree ]+ TypeUnitT{} -> pure [ unitT ]+ -- the tope universe: every tope constructor builds a tope, so all are+ -- introductions of a shape goal. Point arguments (of ≡, ≤) and tope arguments+ -- (of ∧, ∨) are left as holes.+ UniverseTopeT{} ->+ let point = mkHole (mkHole cubeT) -- a point of an as-yet-unknown cube+ tope = mkHole target' -- a tope (its type is the tope universe)+ in pure [ topeTopT, topeBottomT+ , topeEQT point point, topeLEQT point point+ , topeAndT tope tope, topeOrT tope tope ]+ _ -> pure []++-- | Whether the two endpoints of an identity type are definitionally equal, so that+-- @refl@ inhabits it. Like 'fitsInto', any holes or constraints recorded while+-- probing are discarded, leaving a pure yes\/no query.+endpointsAgree :: Distinct n => TermT n -> TermT n -> TypeCheck n Bool+endpointsAgree a b =+ censor (const [])+ ((unify Nothing a b >> pure True) `catchError` \_ -> pure False)++-- | Ex falso: in a contradictory tope context @recBOT@ inhabits any type, so it is a+-- candidate for every goal there (and only there — elsewhere it would not+-- typecheck). Independent of the goal and of the local hypotheses.+recBottomCandidates :: Distinct n => TypeCheck n [TermT n]+recBottomCandidates = do+ vacuous <- contextEntailsBottom+ pure [ recBottomT | vacuous ]++-- | Whether the local tope context is covered by the union of the given topes — the+-- coverage obligation of @recOR@, as a yes\/no query rather than a check that+-- issues an error.+coverageHolds :: Distinct n => [TermT n] -> TypeCheck n Bool+coverageHolds topes = do+ topesNF <- mapM nfTope topes+ entailContextM (foldr topeOrT topeBottomT topesNF)++-- | Tope case-split moves: ways to build a value of the goal by @recOR@, splitting+-- the proof over a cover of the local tope context. Three sources, offered together+-- (the UI ranks and filters):+--+-- * each disjunction @ψ ∨ φ@ already in the context becomes @recOR(ψ ↦ ?, φ ↦ ?)@+-- — its cover is immediate;+-- * when the goal is an extension type, its restriction faces are a cover+-- candidate, offered only when they actually cover the context (so the move+-- typechecks);+-- * a generic two-way split @recOR(? ↦ ?, ? ↦ ?)@ with the guards left as holes,+-- for an unusual split the player fills in by hand.+--+-- All three are offered only where a split makes sense — a cube variable is in+-- scope, the context has a non-trivial tope, or the goal is a restricted type — so+-- an ordinary (tope-free) goal is left alone.+recOrCandidates :: Distinct n => TermT n -> TypeCheck n [TermT n]+recOrCandidates goal = do+ goalW <- whnfT goal+ topes <- asks (filter (not . eqT topeTopT) . availableTopes)+ locals <- asks localHypotheses+ hasCube <- or <$> mapM (fmap isCubeType . whnfT . varType . snd) locals+ let stripped = stripTypeRestrictions goalW+ mkRecOr gs = recOrT stripped [ (g, mkHole stripped) | g <- gs ]+ fromContext = [ mkRecOr [l, r] | TopeOrT _ l r <- topes ]+ faces = case goalW of+ TypeRestrictedT _ _ rs -> map fst rs+ _ -> []+ isRestricted = case goalW of TypeRestrictedT{} -> True; _ -> False+ inShape = hasCube || not (null topes) || isRestricted+ generic = [ recOrT stripped [ (mkHole topeT, mkHole stripped)+ , (mkHole topeT, mkHole stripped) ]+ | inShape ]+ fromFaces <- if length faces >= 2+ then do covered <- coverageHolds faces+ pure [ mkRecOr faces | covered ]+ else pure []+ pure (fromContext <> fromFaces <> generic)++-- | The local hypotheses: everything in scope that is not a top-level entry.+localHypotheses :: Context n -> [(Foil.Name n, VarInfo n)]+localHypotheses = filter (not . varIsTopLevel . snd) . varsInScope++-- | The allow-listed top-level lemmas a hole's candidate list may draw on.+lemmaHypotheses :: Context n -> [(Foil.Name n, VarInfo n)]+lemmaHypotheses ctx =+ [ entry+ | entry@(_, info) <- varsInScope ctx+ , varIsTopLevel info+ , Just name <- [binderName (varOrig info)]+ , name `elem` ctxHintLemmas ctx+ ]++-- | Record the goal and local context at a hole (lenient mode only).+recordHole :: Distinct n => Maybe VarIdent -> TermT n -> TypeCheck n ()+recordHole mname goalTy = recordHoleShape mname goalTy Nothing++-- | Record a hole. When the hole is the argument of a shape-restricted function its+-- goal is a /shape/: the cube @goalTy@ together with a membership tope, which is a+-- scope over the shape's bound variable. It is rendered under that binder, so the+-- goal reads @(binder : goalTy | tope)@.+recordHoleShape+ :: Distinct n+ => Maybe VarIdent+ -> TermT n+ -> Maybe (Binder, ScopedTermT n)+ -> TypeCheck n ()+recordHoleShape mname goalTy mshape = do+ goal' <- whnfT goalTy+ locals <- asks localHypotheses+ -- named top-level lemmas the caller allow-listed for hints. They feed the+ -- candidate-elimination loop only — not the local context shown to the user,+ -- since they are global definitions, not local hypotheses.+ lemmaVars <- asks lemmaHypotheses+ cubeFlags <- mapM (fmap isCubeType . whnfT . varType . snd) locals+ topes <- asks (filter (not . eqT topeTopT) . availableTopes)+ loc <- asks ctxLocation+ naming <- asks namingOfContext++ -- for each local hypothesis (and allow-listed lemma), the elimination spines that+ -- land in the goal (arguments left as holes). Probing must not leak holes into the+ -- recorded output, hence the 'censor'.+ candidates <- censor (const []) $ do+ elims <- concat <$>+ mapM (\(v, _) -> allEliminationsInto goalTy (Var v)) (locals ++ lemmaVars)+ -- context-driven moves (independent of the goal's head and the hypotheses): ex+ -- falso in a contradictory context, and tope case-splits. recOR and recBOT are+ -- term-level eliminators, so they are offered only for a term goal — not when+ -- the hole is a cube point or a tope, where they cannot appear.+ let termLayer = not (isCubeOrTopeType goal')+ recbot <- if termLayer then recBottomCandidates else pure []+ recor <- if termLayer then recOrCandidates goalTy else pure []+ pure (elims <> recbot <> recor)++ let render t = renderTerm naming (untyped t)+ -- a pattern binder is shown as its pattern, e.g. (t , s); others by name+ entryName v = case displayOf naming v of+ (_, binder) | binderIsCompound binder -> binderDisplayName binder+ (x, _) -> x+ entries = [ HoleEntry (entryName v) (render (varType info)) | (v, info) <- locals ]+ flagged = zip cubeFlags entries+ -- names already visible at the hole, which an introduced binder must not+ -- shadow: each local hypothesis by its display name, or the leaves of a+ -- pattern hypothesis.+ inScopeNames =+ [ nm+ | (v, _) <- locals+ , nm <- case displayOf naming v of+ (_, binder) | binderIsCompound binder -> binderLeaves binder+ (x, _) -> [x]+ ]++ -- The goal shape, rendered under the shape's own binder. The name is read back+ -- from the naming rather than assumed: if the declared name is taken (the goal+ -- @(t : 2 × 2 | Δ¹×Δ¹ t)@ under an enclosing @t@), the binder is refreshed, and+ -- the tope must be shown under the /same/ name it is.+ goalShape <- forM mshape $ \(orig, tope) ->+ withBinder (BinderVar (binderName orig <|> Just "t")) Id goal' $ \binder -> do+ topeAt <- openScoped binder tope+ naming' <- asks namingOfContext+ let (shapeBinder, _) = displayOf naming' (Foil.nameOf binder)+ pure (shapeBinder, renderTerm naming' (untyped topeAt))++ -- the introduction forms for the goal itself (constituents left as holes); the Π+ -- binder is freshened against the names in scope so that it does not shadow.+ introductions <- censor (const []) (allIntroductionsOf goalTy inScopeNames)+ -- the goal cell: an SVG of the shape the hole must inhabit (an arrow, triangle or+ -- square), drawn from an abstract inhabitant with the proof term hidden. 'Nothing'+ -- when the goal is not a renderable shape.+ diagram <- censor (const []) (renderGoalCellSVG goal')++ recordHoleInfo HoleInfo+ { holeName = mname+ , holeGoal = render goal'+ , holeGoalShape = goalShape+ , holeTermVars = [ e | (False, e) <- flagged ]+ , holeCubeVars = [ e | (True, e) <- flagged ]+ , holeTopes = map render topes+ , holeCandidates = map render candidates+ , holeIntroductions = map render introductions+ , holeDiagram = diagram+ , holeLocation = loc+ }++-- | Check a hole that appears as the argument of a shape-restricted function, whose+-- domain is the cube @cube@ restricted by @tope@ (a scope over the domain's bound+-- variable). Mirrors the hole case of 'typecheck', but records the shape as the+-- hole's goal so the diagnostic shows @(binder : cube | tope)@.+checkHoleAgainstShape+ :: Distinct n+ => Maybe VarIdent -> Binder -> TermT n -> ScopedTermT n+ -> TypeCheck n (TermT n)+checkHoleAgainstShape mname orig cube tope = do+ reject <- asks ctxHolesAreErrors+ if reject+ then issueTypeError (TypeErrorUnsolvedHole mname cube)+ else do+ recordHoleShape mname cube (Just (orig, tope))+ pure (holeT cube mname)+++-- * Checking++-- | Check a @recOR@ against a known expected type: each branch is checked against+-- it under its own guard, the branches must agree on their overlaps, and together+-- they must cover the context.+checkRecOrAgainst+ :: Distinct n => TermT n -> [(Term n, Term n)] -> TypeCheck n (TermT n)+checkRecOrAgainst expected rs = do+ rs' <- forM rs $ \(tope, rterm) -> do+ tope' <- typecheck tope topeT+ checkTopeAgainstContext "recOR branch guard" tope'+ localTope tope' $ do+ expected' <- pruneVacuousFaces expected+ rterm' <- typecheck rterm expected'+ return (tope', rterm')+ sequence_ [ checkCoherence l r | l:rs'' <- tails rs', r <- rs'' ]+ contextEntailsUnion (map fst rs')+ return (recOrT expected rs')++-- | Drop the restriction faces of an extension type that are vacuous in the current+-- tope context (their overlap with the context is the empty tope ⊥). A face+-- mentioning an unfilled hole cannot be decided, so it is kept. Non-extension types+-- are returned unchanged. Used when descending into a recOR branch, where the+-- sibling branches' faces are disjoint from the branch guard.+pruneVacuousFaces :: Distinct n => TermT n -> TypeCheck n (TermT n)+pruneVacuousFaces (TypeRestrictedT _info ty rs) = do+ contextTopes <- asks ctxTopesNF+ kept <- fmap concat $ forM rs $ \face@(tope, _) -> do+ vacuous <- if containsHole tope+ then return False+ else (plainTope tope : contextTopes) `entailM` topeBottomT+ return [ face | not vacuous ]+ return $ case kept of+ [] -> ty+ _ -> typeRestrictedT ty kept+pruneVacuousFaces ty = return ty++typecheck :: Distinct n => Term n -> TermT n -> TypeCheck n (TermT n)+typecheck term ty = performing (ActionTypeCheck term ty) $ case term of+ -- An identifier that was not in scope: elaboration marked it, and this is where+ -- it is reported, under the binders and topes it was written beneath.+ Hole (Just name) | Just x <- unmarkUnresolved name ->+ issueTypeError (TypeErrorUndefined x)++ -- A hole is checked against a known type (this is checking position): in strict+ -- mode it is reported as an unsolved hole; in lenient mode its goal and context+ -- are recorded and it is treated as inhabiting the expected type.+ Hole mname -> do+ reject <- asks ctxHolesAreErrors+ if reject+ then issueTypeError (TypeErrorUnsolvedHole mname ty)+ else do+ recordHole mname ty+ return (holeT ty mname)++ _ -> whnfT ty >>= \case++ RecBottomT{} -> do+ -- Even under an absurd tope context (where the expected type collapses to+ -- recBOT), the term must still be well-formed in its own right, so that+ -- ill-typed bodies are not silently admitted under a false hypothesis. We+ -- synthesise its type, discard the result, and keep the recBOT elaboration.+ _ <- infer term+ return recBottomT++ tr@(TypeRestrictedT _ty ty' rs) -> case term of+ -- A recOR against a restricted type: push the restriction into each branch+ -- rather than stripping it first, so that a branch hole reports the boundary+ -- faces it must satisfy under its guard tope, and not the bare underlying+ -- type. Concrete branches still meet the faces, which are checked on each+ -- branch's overlap with them (see the general case below).+ RecOr branches -> checkRecOrAgainst tr branches+ _ -> do+ term' <- typecheck term ty'+ -- NOTE: restriction faces need not be contained in the local tope context.+ -- Each face is checked only on its overlap with the context, so an+ -- overhanging face is harmless (we only hint); a face disjoint from the+ -- context is vacuous, however, and is an error.+ forM_ rs $ \(tope, rterm) -> do+ checkTopeAgainstContext "restriction face" tope+ localTope tope $+ unifyTerms rterm term'+ return term' -- FIXME: correct?++ ty' -> case term of+ Lambda orig mparam body ->+ case ty' of+ TypeFunT _ty _orig' md' param' mtope' ret -> do+ -- The λ's own domain annotation, if it wrote one, must agree with the+ -- domain of the type it is checked against.+ case mparam of+ Nothing -> return ()++ Just (LambdaParam md param Nothing) -> do+ when (md /= md') $+ issueTypeError (TypeErrorModalityMismatch md' md term)+ paramType <- enterModality md $ infer param+ -- an argument can be a shape, which is a function into TOPE; the+ -- domain is then its cube, and its tope is the λ's shape tope.+ mcube <- typeOf paramType >>= \case+ TypeFunT _ty _orig _md cube _mtope (ScopedAST _ UniverseTopeT{}) -> do+ mapM_ checkNameShadowing (binderLeaves orig)+ pure (Just cube)+ _kind -> pure Nothing+ unifyTerms param' (fromMaybe paramType mcube)+ mapM_ checkNameShadowing (binderLeaves orig)+ case mcube of+ Nothing -> return ()+ Just _ ->+ withBinder orig md param' $ \binder -> do+ -- eta expand the shape into a tope over the bound variable+ let etaTope = appT topeT (Foil.sink paramType) (Var (Foil.nameOf binder))+ expected <- maybe (pure topeTopT) (openScoped binder) mtope'+ unifyTerms expected etaTope++ Just (LambdaParam md param (Just tope)) -> do+ when (md /= md') $+ issueTypeError (TypeErrorModalityMismatch md' md term)+ param'' <- enterModality md $ typecheck param =<< typeOf param'+ unifyTerms param' param''+ mapM_ checkNameShadowing (binderLeaves orig)+ checkUnder orig md param' tope $ \binder topeTerm -> do+ tope'' <- typecheck topeTerm topeT+ expected <- maybe (pure topeTopT) (openScoped binder) mtope'+ unifyTerms expected tope''++ mapM_ checkNameShadowing (binderLeaves orig)+ body' <- elaborateUnder orig md' param' Nothing body $ \binder bodyTerm -> do+ mtopeIn <- traverse (openScoped binder) mtope'+ maybe id localTope mtopeIn $ do+ retIn <- openScoped binder ret+ typecheck bodyTerm retIn+ return (lambdaT ty' orig (Just (LambdaParam md' param' mtope')) body')++ _ -> issueTypeError $ TypeErrorUnexpectedLambda term ty++ Let orig annot val body -> do+ val' <- performing (ActionCheckLetValue (binderName orig)) $ case annot of+ Nothing -> infer val+ Just bindType -> do+ bindType' <- typecheck bindType universeT+ typecheck val bindType'+ bindTy <- typeOf val'+ body' <- elaborateUnder orig Id bindTy (Just val') body $ \_binder bodyTerm ->+ typecheck bodyTerm (Foil.sink ty')+ return (letT ty' orig (Just bindTy) val' body')++ LetMod orig app inn annot val body -> do+ val' <- performing (ActionCheckLetValue (binderName orig)) $ case annot of+ Nothing -> enterModality app $ infer val+ Just bindType -> do+ bindType' <- infer bindType+ bindUniv <- typeOf bindType'+ enterModality app $ typecheck val (typeModalT bindUniv inn bindType')+ bindTy <- typeOf val' >>= \case+ o@(TypeModalT _ty md t) ->+ if md == inn+ then return t+ else issueTypeError $ TypeErrorNotModal (untyped o) inn val'+ o -> issueTypeError $ TypeErrorNotModal (untyped o) inn val'+ bindVal <- whnfT val' >>= \case+ ModAppT _ty _m t -> pure (Just t)+ o | isRA inn -> pure (Just (modExtractT bindTy app inn o))+ _ -> pure Nothing+ body' <- elaborateUnder orig (comp app inn) bindTy bindVal body $ \_binder bodyTerm ->+ typecheck bodyTerm (Foil.sink ty')+ return (letModT ty' orig app inn (Just bindTy) val' body')++ Pair l r ->+ case ty' of+ CubeProductT _ty a b -> do+ l' <- typecheck l a+ r' <- typecheck r b+ return (pairT ty' l' r')+ TypeSigmaT _ty _orig md a b -> do+ l' <- enterModality md $ typecheck l a+ bAt <- instantiate b l'+ r' <- typecheck r bAt+ return (pairT ty' l' r')+ _ -> issueTypeError $ TypeErrorUnexpectedPair term ty++ Refl mx ->+ case ty' of+ TypeIdT _ty y _tA z -> do+ tA <- typeOf y+ forM_ mx $ \(x, mxty) -> do+ forM_ mxty $ \xty -> do+ xty' <- typecheck xty universeT+ unifyTerms tA xty'+ x' <- typecheck x tA+ unifyTerms x' y >> unifyTerms y x'+ unifyTerms x' z >> unifyTerms z x'+ when (isNothing mx) $+ unifyTerms y z >> unifyTerms z y+ return (reflT ty' (Just (y, Just tA)))+ _ -> issueTypeError $ TypeErrorUnexpectedRefl term ty++ ModExtract{} -> panicImpossible "extract is an internal term and cannot be typechecked"++ ModApp md body -> case ty' of+ TypeModalT _ty md' tpe -> do+ when (md /= md') $ issueTypeError $+ TypeErrorModalityMismatch md' md term+ body' <- enterModality md $ typecheck body tpe+ return $ modAppT ty' md body'+ _ -> issueTypeError $ TypeErrorNotModal term md ty'++ -- In checking position the common type is already known, so we push it into+ -- every branch instead of inferring each one and unifying. This is what lets a+ -- bare hole branch (recOR(φ ↦ ?, …)) be checked against the expected type and+ -- recorded, rather than hitting TypeErrorCannotInferHole via the inference+ -- rule. A recOR is a term-level eliminator, not a tope; rejecting it when it is+ -- checked against the tope universe keeps it out of the tope layer, where it+ -- would otherwise hit a panic.+ RecOr rs -> case ty' of+ UniverseTopeT{} -> issueTypeError $+ TypeErrorOther "a recOR cannot be used as a tope"+ _ -> checkRecOrAgainst ty' rs++ -- A neutral term is inferred, then its type unified with the expected one. In+ -- lenient (hole-checking) mode a term that still carries an unfilled hole is a+ -- work in progress, so a failure of that final unification is tolerated: the+ -- holes recorded while inferring the term stand, and we accept the term rather+ -- than rejecting the whole sketch. The mismatch is typically incidental to the+ -- missing pieces — an extension-type boundary face that only fails to line up+ -- because an argument hole sits in the wrong place (@f t@ vs @x@), where+ -- neither side is itself a hole, so the per-term deferral in unification cannot+ -- see it. Strict mode (the default, and CI) still rejects the mismatch.+ _ -> do+ term' <- infer term+ inferredType <- typeOf term'+ lenient <- not <$> asks ctxHolesAreErrors+ if lenient && containsHole term'+ then unifyTypes term' ty' inferredType `catchError` \_ -> return ()+ else unifyTypes term' ty' inferredType+ return term'++-- * Inference++inferAs :: Distinct n => TermT n -> Term n -> TypeCheck n (TermT n)+inferAs expectedKind term = do+ term' <- infer term+ ty <- typeOf term'+ kind <- typeOf ty+ unifyTypes ty expectedKind kind+ return term'++infer :: Distinct n => Term n -> TypeCheck n (TermT n)+infer tt = performing (ActionInfer tt) $ case tt of+ Hole (Just name) | Just x <- unmarkUnresolved name ->+ issueTypeError (TypeErrorUndefined x)+ Hole _mname -> issueTypeError (TypeErrorCannotInferHole tt)+ Var x -> do+ topLevel <- isTopLevelVar x+ unless topLevel $ do+ varMod <- modalityOfVar x+ locks <- locksOfVar x+ unless (coe varMod locks) $+ issueTypeError $ TypeErrorUnaccessibleVar x varMod locks+ pure (Var x)++ Universe -> pure universeT+ UniverseCube -> pure cubeT+ UniverseTope -> pure topeT++ CubeUnit -> pure cubeUnitT+ CubeUnitStar -> pure cubeUnitStarT++ Cube2 -> pure cube2T+ Cube2_0 -> pure cube2_0T+ Cube2_1 -> pure cube2_1T++ CubeI -> pure cubeIT+ CubeI_0 -> pure cubeI_0T+ CubeI_1 -> pure cubeI_1T+ CubeProduct l r -> do+ l' <- typecheck l cubeT+ r' <- typecheck r cubeT+ return (cubeProductT l' r')++ CubeFlip t -> do+ t' <- infer t+ typeOf t' >>= \case+ CubeIT{} -> pure $ cubeFlipT cubeIT t'+ Cube2T{} -> pure $ cubeFlipT cube2T t'+ ty -> do+ tyStr <- ppInContext ty+ issueTypeError $ TypeErrorOther $+ "flip expects an interval cube (2 or 𝕀); got " <> tyStr+ CubeUnflip t -> do+ t' <- infer t+ typeOf t' >>= \case+ TypeModalT _ Op CubeIT{} -> pure $ cubeUnflipT cubeIT t'+ TypeModalT _ Op Cube2T{} -> pure $ cubeUnflipT cube2T t'+ ty -> do+ tyStr <- ppInContext ty+ issueTypeError $ TypeErrorOther $+ "unflip expects an interval cube (2 or 𝕀) under _op; got " <> tyStr++ Pair l r -> do+ l' <- infer l+ r' <- infer r+ lt <- typeOf l'+ rt <- typeOf r'+ typeOf lt >>= \case+ -- Γ ⊢ l ⇒ (I : CUBE)+ -- Γ ⊢ r ⇒ (J : CUBE)+ -- ———————————————————————————+ -- Γ ⊢ (l, r) ⇒ (I × J : CUBE)+ UniverseCubeT{} -> return (pairT (cubeProductT lt rt) l' r')+ -- Γ ⊢ l ⇒ (A : U)+ -- Γ ⊢ r ⇒ (B : U)+ -- ———————————————————————————+ -- Γ ⊢ (l, r) ⇒ (A × B : U) where A × B = Σ (_ : A), B+ _ -> do+ -- NOTE: infer as a non-dependent pair!+ rtScope <- constScope rt+ return (pairT (typeSigmaT (BinderVar Nothing) Id lt rtScope) l' r')++ First t -> do+ t' <- infer t+ fmap stripTypeRestrictions (typeOf t') >>= \case+ RecBottomT{} -> pure recBottomT -- FIXME: is this ok?+ TypeSigmaT _ty _orig _md lt _rt ->+ return (firstT lt t')+ CubeProductT _ty l _r ->+ return (firstT l t')+ ty -> issueTypeError $ TypeErrorNotPair t' ty++ Second t -> do+ t' <- infer t+ fmap stripTypeRestrictions (typeOf t') >>= \case+ RecBottomT{} -> pure recBottomT -- FIXME: is this ok?+ TypeSigmaT _ty _orig _md lt rt -> do+ rtAt <- instantiate rt (firstT lt t')+ return (secondT rtAt t')+ CubeProductT _ty _l r ->+ return (secondT r t')+ ty -> issueTypeError $ TypeErrorNotPair t' ty++ TypeUnit -> pure typeUnitT+ Unit -> pure unitT++ TopeTop -> pure topeTopT+ TopeBottom -> pure topeBottomT++ TopeEQ l r -> do+ l' <- inferAs cubeT l+ lt <- typeOf l'+ r' <- typecheck r lt+ return (topeEQT l' r')++ TopeLEQ l r -> do+ l' <- inferAs cubeT l+ r' <- inferAs cubeT r+ lTy <- typeOf l'+ rTy <- typeOf r'+ case (lTy, rTy) of+ (Cube2T{}, Cube2T{}) -> return (topeLEQT l' r')+ (CubeIT{}, CubeIT{}) -> return (topeLEQT l' r')+ (CubeIT{}, Cube2T{}) -> do+ r'' <- typecheck r cubeIT+ return (topeLEQT l' r'')+ (Cube2T{}, CubeIT{}) -> do+ l'' <- typecheck l cubeIT+ return (topeLEQT l'' r')+ _ -> do+ lStr <- ppInContext lTy+ rStr <- ppInContext rTy+ issueTypeError $ TypeErrorOther $+ "the (t ≤ s) tope expects points in interval cubes (2 or 𝕀); got "+ <> lStr <> " and " <> rStr++ TopeAnd l r -> do+ l' <- typecheck l topeT+ r' <- typecheck r topeT+ return (topeAndT l' r')++ TopeOr l r -> do+ l' <- typecheck l topeT+ r' <- typecheck r topeT+ return (topeOrT l' r')++ TopeInv t -> do+ t' <- typecheck t topeT+ return (topeInvT t')++ TopeUninv t -> do+ t' <- typecheck t (typeModalT universeT Op topeT)+ return (topeUninvT t')++ RecBottom -> do+ contextEntails topeBottomT+ return recBottomT++ RecOr rs -> do+ ttts <- forM rs $ \(tope, term) -> do+ tope' <- typecheck tope topeT+ -- NOTE: branch guards need not be contained in the context. recOR requires+ -- only coverage (context |- OR(guards)); a guard may overhang the context (when+ -- splitting with a named shape, say). checkTopeAgainstContext warns on overhang+ -- and errors only if the guard is disjoint from the context (a vacuous branch).+ checkTopeAgainstContext "recOR branch guard" tope'+ localTope tope' $ do+ term' <- inferAs universeT term+ ty <- typeOf term'+ return (tope', (term', ty))+ let rs' = map (fmap fst) ttts+ ts = map (fmap snd) ttts+ sequence_ [ checkCoherence l r | l:rs'' <- tails rs', r <- rs'' ]+ contextEntailsUnion (map fst ttts)+ return (recOrT (recOrT universeT ts) rs')++ TypeFun orig md a Nothing b -> do+ a' <- enterModality md $ infer a+ typeOf a' >>= \case+ -- an argument can be a type+ UniverseT{} ->+ case a' of+ -- except if it is the TOPE universe+ UniverseTopeT{} ->+ issueTypeError $ TypeErrorOther "tope params are illegal"+ _ -> do+ mapM_ checkNameShadowing (binderLeaves orig)+ b' <- elaborateUnder orig md a' Nothing b $ \_binder bTerm ->+ typecheck bTerm universeT+ return (typeFunT orig md a' Nothing b')+ -- an argument can be a cube+ UniverseCubeT{} -> do+ mapM_ checkNameShadowing (binderLeaves orig)+ b' <- elaborateUnder orig md a' Nothing b $ \_binder bTerm ->+ typecheck bTerm universeT+ return (typeFunT orig md a' Nothing b')+ -- an argument can be a shape+ TypeFunT _ty _orig _md cube mtope (ScopedAST _ UniverseTopeT{}) -> do+ mapM_ checkNameShadowing (binderLeaves orig)+ (tope', b') <- checkUnder orig md cube b $ \binder bTerm -> do+ -- eta expand a' into a tope over the bound variable+ let etaTope = appT topeT (Foil.sink a') (Var (Foil.nameOf binder))+ tope' <- case mtope of+ Nothing -> pure etaTope+ Just tope'' -> do+ inner <- openScoped binder tope''+ pure (topeAndT inner etaTope)+ bTyped <- localTope etaTope $ typecheck bTerm universeT+ pure (ScopedAST binder tope', ScopedAST binder bTyped)+ return (typeFunT orig md cube (Just tope') b')+ ty -> issueTypeError $ TypeErrorInvalidArgumentType a ty++ TypeFun orig md cube (Just tope) ret -> do+ cube' <- enterModality md $ typecheck cube cubeT+ mapM_ checkNameShadowing (binderLeaves orig)+ (tope', ret') <- checkUnder orig md cube' tope $ \binder topeTerm -> do+ topeTyped <- typecheck topeTerm topeT+ retTerm <- openScoped binder ret+ retTyped <- localTope topeTyped $ typecheck retTerm universeT+ pure (ScopedAST binder topeTyped, ScopedAST binder retTyped)+ return (typeFunT orig md cube' (Just tope') ret')++ TypeSigma orig md a b -> do+ a' <- enterModality md $ typecheck a universeT+ mapM_ checkNameShadowing (binderLeaves orig)+ b' <- elaborateUnder orig md a' Nothing b $ \_binder bTerm ->+ typecheck bTerm universeT+ return (typeSigmaT orig md a' b')++ TypeId x (Just tA) y -> do+ tA' <- typecheck tA universeT+ x' <- typecheck x tA'+ y' <- typecheck y tA'+ return (typeIdT x' (Just tA') y')++ TypeId x Nothing y -> do+ x' <- inferAs universeT x+ tA <- typeOf x'+ y' <- typecheck y tA+ return (typeIdT x' (Just tA) y')++ App f x -> do+ f' <- inferAs universeT f+ fmap stripTypeRestrictions (typeOf f') >>= \case+ TypeFunT _ty orig md a mtope b -> do+ -- A hole argument to a shape-restricted function carries the shape as its+ -- goal: record (binder : a | tope) rather than just the cube a.+ x' <- enterModality md $ case (x, mtope) of+ (Hole mname, Just tope) -> checkHoleAgainstShape mname orig a tope+ _ -> typecheck x a+ bAt <- instantiate b x'+ let result = appT bAt f' x'+ case b of+ ScopedAST _ UniverseTopeT{} ->+ case mtope of+ Nothing -> return result+ Just tope -> do+ topeAt <- instantiate tope x'+ return (topeAndT topeAt result)+ _ -> do+ -- FIXME: need to check?+ forM_ mtope $ \tope -> do+ topeAt <- instantiate tope x'+ contextEntails topeAt+ return result+ ty -> issueTypeError $ TypeErrorNotFunction f' ty++ Lambda _orig Nothing _body ->+ issueTypeError $ TypeErrorCannotInferBareLambda tt++ Lambda orig (Just (LambdaParam md ty Nothing)) body -> do+ ty' <- enterModality md $ infer ty+ mcube <- typeOf ty' >>= \case+ -- an argument can be a type+ UniverseT{} ->+ case ty' of+ -- except if it is the TOPE universe+ UniverseTopeT{} ->+ issueTypeError $ TypeErrorOther "tope params are illegal"+ _ -> return Nothing+ -- an argument can be a cube+ UniverseCubeT{} -> return Nothing+ -- an argument can be a shape+ TypeFunT _ty _orig _md cube _mtope (ScopedAST _ UniverseTopeT{}) -> do+ mapM_ checkNameShadowing (binderLeaves orig)+ return (Just cube)+ kind -> issueTypeError $ TypeErrorInvalidArgumentType ty kind+ mapM_ checkNameShadowing (binderLeaves orig)+ let param = fromMaybe ty' mcube+ case mcube of+ Nothing -> do+ (body', ret) <- checkUnder orig md param body $ \binder bodyTerm -> do+ body' <- infer bodyTerm+ ret <- typeOf body'+ pure (ScopedAST binder body', ScopedAST binder ret)+ return (lambdaT (typeFunT orig md param Nothing ret) orig+ (Just (LambdaParam md param Nothing)) body')+ Just _ -> do+ (tope', body', ret) <- checkUnder orig md param body $ \binder bodyTerm -> do+ -- eta expand the shape into a tope over the bound variable+ let etaTope = appT topeT (Foil.sink ty') (Var (Foil.nameOf binder))+ body' <- localTope etaTope $ infer bodyTerm+ ret <- typeOf body'+ pure (ScopedAST binder etaTope, ScopedAST binder body', ScopedAST binder ret)+ return (lambdaT (typeFunT orig md param (Just tope') ret) orig+ (Just (LambdaParam md param (Just tope'))) body')++ Lambda orig (Just (LambdaParam md cube (Just tope))) body -> do+ cube' <- enterModality md $ typecheck cube cubeT+ mapM_ checkNameShadowing (binderLeaves orig)+ (tope', body', ret) <- checkUnder orig md cube' tope $ \binder topeTerm -> do+ topeTyped <- infer topeTerm+ bodyTerm <- openScoped binder body+ body' <- localTope topeTyped $ infer bodyTerm+ ret <- typeOf body'+ pure (ScopedAST binder topeTyped, ScopedAST binder body', ScopedAST binder ret)+ return (lambdaT (typeFunT orig md cube' (Just tope') ret) orig+ (Just (LambdaParam md cube' (Just tope'))) body')++ Let orig annot val body -> do+ val' <- performing (ActionCheckLetValue (binderName orig)) $ case annot of+ Nothing -> infer val+ Just ty -> do+ bindTy <- typecheck ty universeT+ typecheck val bindTy+ bindTy <- typeOf val'+ (body', ret) <- checkUnderWith orig Id bindTy (Just val') body $ \binder bodyTerm -> do+ body' <- infer bodyTerm+ ret <- typeOf body'+ pure (ScopedAST binder body', ScopedAST binder ret)+ retAt <- instantiate ret val'+ return (letT retAt orig (Just bindTy) val' body')++ LetMod orig app inn annot val body -> do+ val' <- performing (ActionCheckLetValue (binderName orig)) $ case annot of+ Nothing -> enterModality app $ infer val+ Just bindType -> do+ bindType' <- infer bindType+ bindUniv <- typeOf bindType'+ enterModality app $ typecheck val (typeModalT bindUniv inn bindType')+ bindTy <- typeOf val' >>= \case+ o@(TypeModalT _ty md t) ->+ if md == inn+ then return t+ else issueTypeError $ TypeErrorNotModal (untyped o) inn val'+ o -> issueTypeError $ TypeErrorNotModal (untyped o) inn val'+ bindVal <- whnfT val' >>= \case+ ModAppT _ty _m t -> pure (Just t)+ o | isRA inn -> pure (Just (modExtractT bindTy app inn o))+ _ -> pure Nothing+ (body', ret) <- checkUnderWith orig (comp app inn) bindTy bindVal body $ \binder bodyTerm -> do+ body' <- infer bodyTerm+ ret <- typeOf body'+ pure (ScopedAST binder body', ScopedAST binder ret)+ retAt <- instantiate ret val'+ return (letModT retAt orig app inn (Just bindTy) val' body')++ Refl Nothing -> issueTypeError $ TypeErrorCannotInferBareRefl tt+ Refl (Just (x, Nothing)) -> do+ x' <- inferAs universeT x+ ty <- typeOf x'+ return (reflT (typeIdT x' (Just ty) x') (Just (x', Just ty)))+ Refl (Just (x, Just ty)) -> do+ ty' <- typecheck ty universeT+ x' <- typecheck x ty'+ return (reflT (typeIdT x' (Just ty') x') (Just (x', Just ty')))++ IdJ tA a tC d x p -> do+ tA' <- typecheck tA universeT+ a' <- typecheck a tA'+ typeOf_C <- motiveType tA' a'+ tC' <- typecheck tC typeOf_C+ univScope <- constScope universeT+ let typeOf_d =+ appT universeT+ (appT (typeFunT (BinderVar Nothing) Id (typeIdT a' (Just tA') a') Nothing univScope)+ tC' a')+ (reflT (typeIdT a' (Just tA') a') Nothing)+ d' <- typecheck d typeOf_d+ x' <- typecheck x tA'+ p' <- typecheck p (typeIdT a' (Just tA') x')+ let ret =+ appT universeT+ (appT (typeFunT (BinderVar Nothing) Id (typeIdT a' (Just tA') x') Nothing univScope)+ tC' x')+ p'+ return (idJT ret tA' a' tC' d' x' p')++ TypeAsc term ty -> do+ ty' <- inferAs universeT ty -- this works on types AND cubes+ term' <- typecheck term ty'+ return (typeAscT term' ty')++ TypeRestricted ty rs -> do+ ty' <- typecheck ty universeT+ rs' <- forM rs $ \(tope, term) -> do+ tope' <- typecheck tope topeT+ term' <- localTope tope' $ typecheck term ty'+ return (tope', term')+ sequence_ [ checkCoherence l r | l:rs'' <- tails rs', r <- rs'' ]+ return (typeRestrictedT ty' rs')++ TypeModal md ty -> do+ ty' <- enterModality md $ infer ty+ universeTy <- typeOf ty'+ _ <- case universeTy of+ UniverseT{} -> pure universeTy+ UniverseCubeT{} -> pure universeTy+ UniverseTopeT{} -> pure universeTy+ _ -> issueTypeError $ TypeErrorNotTypeInModal universeTy+ return (typeModalT universeTy md ty')++ ModApp md term -> do+ term' <- enterModality md $ infer term+ ty <- typeOf term'+ tyUniv <- typeOf ty+ return $ modAppT (typeModalT tyUniv md ty) md term'++ ModExtract{} -> panicImpossible "extract is an internal term and cannot be inferred"++-- | The type of the motive of a path induction: @(z : A) → (a =_A z) → U@.+motiveType :: Distinct n => TermT n -> TermT n -> TypeCheck n (TermT n)+motiveType tA a = do+ scope <- asks ctxScope+ pure $ Foil.withFresh scope $ \zBinder ->+ let scopeZ = Foil.extendScope zBinder scope+ idType = typeIdT (Foil.sink a) (Just (Foil.sink tA)) (Var (Foil.nameOf zBinder))+ in Foil.withFresh scopeZ $ \pBinder ->+ typeFunT (BinderVar Nothing) Id tA Nothing+ (ScopedAST zBinder+ (typeFunT (BinderVar Nothing) Id idType Nothing+ (ScopedAST pBinder universeT)))
+ src/Rzk/TypeCheck/Monad.hs view
@@ -0,0 +1,177 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}++-- | The checker's monad.+--+-- @TypeCheck n@ is the old @TypeCheck var@ with the scope index in place of the+-- variable type. The error channel, though, is /not/ indexed: an error carries+-- the context it was raised in (see "Rzk.TypeCheck.Error"). That is what makes+-- 'inContext' a one-liner — running a judgement in an inner scope is just running+-- it under a different reader, with nothing to re-index on the way out. The old+-- @closeScope@ had to wrap the error one binder deeper and re-emit the holes.+module Rzk.TypeCheck.Monad where++import Control.Monad (unless)+import Control.Monad.Except (Except, MonadError (throwError),+ runExcept)+import Control.Monad.Reader (ReaderT (..), ask, asks, local)+import Control.Monad.Trans (lift)+import Control.Monad.Trans.Writer.CPS (WriterT, runWriterT)+import Control.Monad.Writer.CPS (tell)+import Debug.Trace (trace)++import Control.Monad.Foil (Distinct)+import qualified Control.Monad.Foil as Foil++import Language.Rzk.Foil.Names (VarIdent)+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Display+import Rzk.TypeCheck.Error++-- | A binding shown in a hole's local context: the display name and its type,+-- already rendered.+data HoleEntry = HoleEntry+ { holeEntryName :: VarIdent+ , holeEntryType :: Rendered+ } deriving (Eq, Show)++-- | The structured goal and context at a hole, recorded in lenient mode (see+-- 'allowHoles'). Everything is rendered to user-facing names at record time, so+-- 'HoleInfo' is independent of the scope it came from. Local hypotheses are split+-- into ordinary term variables and cube variables (the cube/tope layer is+-- specific to Rzk); the global environment is deliberately excluded — it belongs+-- in a searchable inventory, not the goal panel.+data HoleInfo = HoleInfo+ { holeName :: Maybe VarIdent -- ^ the @?name@, if the hole was named+ , holeGoal :: Rendered -- ^ expected type (the goal), kept symbolic+ , holeGoalShape :: Maybe (VarIdent, Rendered)+ -- ^ when the goal is a /shape/ (the hole is the argument of a+ -- shape-restricted function), the shape's bound variable and its tope: the+ -- goal then reads @(binder : holeGoal | tope)@. 'Nothing' for an ordinary+ -- goal. (Extension-type goals need no special handling — they are already a+ -- restricted type in 'holeGoal'.)+ , holeTermVars :: [HoleEntry] -- ^ local hypotheses whose type is not a cube+ , holeCubeVars :: [HoleEntry] -- ^ local cube variables (type is a cube)+ , holeTopes :: [Rendered] -- ^ local tope assumptions (excluding ⊤)+ , holeCandidates :: [Rendered]+ -- ^ elimination spines over the local hypotheses whose type fits the goal,+ -- with applied arguments left as holes. Already rendered, like the rest.+ , holeIntroductions :: [Rendered]+ -- ^ introduction forms for the goal type, built from its head constructor+ -- with the constituents left as holes. Already rendered, like the rest.+ , holeDiagram :: Maybe String+ -- ^ an SVG of the goal cell, when the goal is a renderable shape (an arrow,+ -- triangle, or square up to dimension 3).+ , holeLocation :: Maybe LocationInfo+ } deriving (Eq, Show)++type TypeCheck n =+ ReaderT (Context n)+ (WriterT [HoleInfo] (Except TypeErrorInScopedContext))++-- | Run a judgement in the empty context, discarding the holes it records.+runTypeCheck :: TypeCheck Foil.VoidS a -> Either TypeErrorInScopedContext a+runTypeCheck tc = fst <$> runExcept (runWriterT (runReaderT tc emptyContext))++-- | Run a judgement in a given context, discarding the holes it records.+runTypeCheckIn :: Context n -> TypeCheck n a -> Either TypeErrorInScopedContext a+runTypeCheckIn ctx tc = fst <$> runExcept (runWriterT (runReaderT tc ctx))++-- | Run a judgement in another scope's context.+--+-- The error channel and the hole channel are shared and carry no scope index, so+-- there is nothing to translate: this is 'runReaderT' with the inner scope's+-- context, lifted back. Holes recorded inside are told into the same writer, and+-- an error thrown inside already carries its own context.+inContext :: Context l -> TypeCheck l a -> TypeCheck n a+inContext ctx = lift . flip runReaderT ctx++-- * Errors++-- | Raise a type error, capturing the context it happened in.+issueTypeError :: Distinct n => TypeError n -> TypeCheck n a+issueTypeError err = do+ ctx <- ask+ throwError (TypeErrorInScopedContext ctx err)++issueWarning :: String -> TypeCheck n ()+issueWarning message = trace ("Warning: " <> message) (return ())++-- * Tracing++trace' :: Verbosity -> Verbosity -> String -> a -> a+trace' Silent _ _ = id+trace' Normal Debug _ = id+trace' _ _ msg = trace msg++traceTypeCheck :: Verbosity -> String -> TypeCheck n a -> TypeCheck n a+traceTypeCheck verbosity msg action = do+ configuredVerbosity <- asks ctxVerbosity+ trace' configuredVerbosity verbosity msg action++localVerbosity :: Verbosity -> TypeCheck n a -> TypeCheck n a+localVerbosity verbosity = local $ \ctx -> ctx { ctxVerbosity = verbosity }++localRenderBackend :: Maybe RenderBackend -> TypeCheck n a -> TypeCheck n a+localRenderBackend backend = local $ \ctx -> ctx { ctxRenderBackend = backend }++localHideTerm :: Bool -> TypeCheck n a -> TypeCheck n a+localHideTerm hide = local $ \ctx -> ctx { ctxRenderHideTerm = hide }++localWarnOverhang :: Bool -> TypeCheck n a -> TypeCheck n a+localWarnOverhang warn = local $ \ctx -> ctx { ctxWarnOverhang = warn }++-- | Render the enclosed action with the proof term hidden.+hidingTerm :: TypeCheck n a -> TypeCheck n a+hidingTerm = localHideTerm True++-- * Variance++switchVariance :: TypeCheck n a -> TypeCheck n a+switchVariance = local $ \ctx -> ctx { ctxCovariance = switch (ctxCovariance ctx) }+ where+ switch Covariant = Contravariant+ switch Contravariant = Covariant+ switch Invariant = Invariant++setVariance :: Covariance -> TypeCheck n a -> TypeCheck n a+setVariance variance = local $ \ctx -> ctx { ctxCovariance = variance }++-- * The judgement stack++-- | The depth of nested judgements at which type checking gives up. Well-typed+-- input stays far below it; the cap catches a non-terminating search.+-- FIXME: expose as a parameter (@--max-depth@ and @rzk.yaml@).+maxActionStackDepth :: Int+maxActionStackDepth = 1000++performing :: Distinct n => Action n -> TypeCheck n a -> TypeCheck n a+performing action tc = do+ ctx@Context{..} <- ask+ unless (ctxActionStackDepth < maxActionStackDepth) $+ issueTypeError $ TypeErrorOther "maximum depth reached"+ let ctx' = ctx+ { ctxActionStack = action : ctxActionStack+ , ctxActionStackDepth = ctxActionStackDepth + 1+ }+ -- The trace message is built only when it is actually printed: at normal+ -- verbosity rendering the action's terms on every judgement would cost a+ -- thunk per judgement.+ if ctxVerbosity <= Debug+ then trace (ppAction (namingOfContext ctx) ctxActionStackDepth action) $+ local (const ctx') tc+ else local (const ctx') tc++-- * Holes++recordHoleInfo :: HoleInfo -> TypeCheck n ()+recordHoleInfo info = lift (tell [info])++-- * Locations++withLocation :: LocationInfo -> TypeCheck n a -> TypeCheck n a+withLocation loc = local $ \ctx -> ctx { ctxLocation = Just loc }
+ src/Rzk/TypeCheck/NbE.hs view
@@ -0,0 +1,297 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Normalisation by evaluation, used as an all-or-nothing fast path for+-- conversion checking.+--+-- 'nbeConvertible' evaluates both sides into a value domain with closures+-- (sharing by construction: a definition's value is evaluated once per+-- occurrence, not once per copy, and Haskell's laziness makes the evaluation+-- call-by-need) and compares the values structurally, with one-step η for+-- lambdas and pairs mirroring 'Rzk.TypeCheck.Eval.etaMatch'. It answers only+-- 'True' ("definitely convertible") or 'False' ("do not know") — never a+-- definite inequality — so a caller falls back to the ordinary unification on+-- 'False' and the fast path cannot change what typechecks, only how fast.+--+-- Soundness is a subset argument: 'True' is answered only for terms that are+-- βδ-convertible up to α and the one-step η above, with every construct whose+-- /reduction/ consults the context — @recOR@ guard selection, holes, the+-- modal constructs — evaluating to an opaque 'VAbort' that poisons the+-- comparison into 'False'. Extension types and @recBOT@ are compared+-- structurally (see the note at their 'eval' case): a structurally identical+-- pair of restricted types is also accepted by the ordinary unification,+-- through reflexive coverage and the cross-face coherences already proved at+-- formation. Every 'True' is therefore also a success of the old unification.+--+-- The evaluator is a pure function of the 'Context': 'valueOfVar' is a plain+-- reader-only lookup, and fresh variables for comparing closures are de+-- Bruijn levels ('NLevel'), so the foil scope machinery is never extended and+-- no quote function is needed.+--+-- == Attribution+--+-- None of the underlying techniques are ours. Semantic conversion checking —+-- evaluate both sides into a value domain with closures and compare the+-- values, applying functions to fresh generic values — is the algorithm of+-- Coquand, /An algorithm for type-checking dependent types/ (Science of+-- Computer Programming 26, 1996), the implementation-level core of+-- normalisation by evaluation (Berger and Schwichtenberg, LICS 1991). The+-- concrete implementation shape follows the style popularised by András+-- Kovács' <https://github.com/AndrasKovacs/smalltt smalltt> and+-- <https://github.com/AndrasKovacs/elaboration-zoo elaboration-zoo>:+-- environment machines with closures, de Bruijn levels for fresh variables,+-- and demand-driven definition unfolding (our 'unfoldNeu' — unfold at an+-- elimination or on a comparison mismatch, comparing neutral spines first —+-- is a simplified form of smalltt's glued evaluation). For the fragment this+-- module deliberately aborts on (tope-indexed reduction such as @recOR@),+-- the template is cubical: Sterling and Angiuli, /Normalization for Cubical+-- Type Theory/ (LICS 2021), and its implementation lineage in @cooltt@.+-- What is specific to rzk is only the packaging: the all-or-nothing+-- gating ('True' or do-not-know, never refute), and 'VAbort' poisoning of+-- the context-sensitive fragment so that the fast path stays sound by a+-- subset argument.+module Rzk.TypeCheck.NbE (nbeConvertible) where++import Control.Monad.Reader (asks)+import Data.Bifoldable (bifoldMap)+import Data.Bifunctor (bimap)+import qualified Data.IntMap as IntMap+import Data.Monoid (All (..))+import Data.ZipMatchK (zipMatch2)+import Unsafe.Coerce (unsafeCoerce)++import Control.Monad.Foil (NameBinder)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Free.Foil (AST (Node, Var),+ ScopedAST (..))+import Control.Monad.Free.Foil.Annotated (AnnSig (..))++import Language.Rzk.Foil.Syntax+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Monad++-- * The value domain++data Val n+ = VLam (Closure n)+ -- ^ A lambda: its body under the environment it was evaluated in.+ | VNeutral (Neu n)+ -- ^ A stuck elimination spine over a variable.+ | VCon (TermSig (Closure n) (Val n))+ -- ^ Any other node, its term fields evaluated and its scoped fields+ -- closed over the environment. Covers constructors (pairs, @refl@),+ -- types (Π, Σ, identity, universes) and the cube/tope operators, which+ -- are compared structurally only (reflexivity is entailment).+ | VAbort AbortReason+ -- ^ A construct outside the context-insensitive fragment. Poisons the+ -- comparison: 'conv' answers 'False' the moment it meets one. The+ -- reason records which construct, for diagnostics.++-- | Why evaluation gave up: which context-sensitive construct was met.+data AbortReason+ = AbortHole+ | AbortRecOr+ | AbortModal+ | AbortStuckElim+ -- ^ An elimination of a non-canonical, non-neutral value (an abort+ -- propagating through an application, projection or @idJ@).+ deriving (Eq, Ord, Show, Enum, Bounded)++data Neu n+ = NVar (Foil.Name n)+ -- ^ An ambient variable (its definition, if any, is unfolded on demand+ -- by 'unfoldNeu').+ | NLevel Int+ -- ^ A fresh variable minted while comparing closures.+ | NApp (Neu n) (Val n)+ | NFirst (Neu n)+ | NSecond (Neu n)+ | NIdJ (Val n) (Val n) (Val n) (Val n) (Val n) (Neu n)++-- | A scoped term closed over its environment. The environment maps the raw+-- ids of the binders passed on the way down to values; a missing id belongs+-- to the ambient scope @n@ (the same invariant 'peelLambdas' relies on for+-- its substitution).+--+-- One binder, not @NameBinders i l@: every scope field of every 'TermSig'+-- constructor is a unary 'ScopedAST' (even a pair-pattern lambda binds one+-- variable operationally), so a multi-binder closure would have nothing to+-- be built from without peeling syntactic lambda chains in 'eval'. Peeling+-- (the eval/apply arity optimisation of Marlow and Peyton Jones' fast+-- curry) does not pay here the way spine-batching paid at the term level:+-- an intermediate 'VLam' costs one closure and one persistent+-- 'IntMap.insert', not a 'substituteT' traversal, and η-comparison and+-- partial application want one-argument-at-a-time semantics anyway.+data Closure n where+ Closure :: Env n -> NameBinder i l -> TermT l -> Closure n++-- | Lazy on purpose: forcing an entry would evaluate it, and evaluation is+-- call-by-need.+type Env n = IntMap.IntMap (Val n)++-- * Evaluation++eval :: forall i n. Context n -> Env n -> TermT i -> Val n+eval ctx env = \case+ Var x -> case IntMap.lookup (Foil.nameId x) env of+ Just v -> v+ -- An env miss is an ambient name; kept neutral here, unfolded on demand.+ Nothing -> VNeutral (NVar (unsafeCoerce x))++ AppT _ty f x -> applyVal ctx (eval ctx env f) (eval ctx env x)+ LambdaT _ty _orig _mparam (ScopedAST binder body) ->+ VLam (Closure env binder body)+ LetT _ty _orig _mparam val (ScopedAST binder body) ->+ eval ctx (IntMap.insert (Foil.nameId (Foil.nameOf binder)) (eval ctx env val) env) body+ FirstT _ty t -> projVal ctx NFirst fstOf (eval ctx env t)+ SecondT _ty t -> projVal ctx NSecond sndOf (eval ctx env t)+ TypeAscT _ty term _ty' -> eval ctx env term+ IdJT _ty tA a tC d x p ->+ let vd = eval ctx env d+ in case forceVal ctx (eval ctx env p) of+ VCon ReflF{} -> vd+ VNeutral np -> VNeutral+ (NIdJ (eval ctx env tA) (eval ctx env a) (eval ctx env tC)+ vd (eval ctx env x) np)+ VAbort r -> VAbort r+ _ -> VAbort AbortStuckElim++ -- The context-sensitive fragment. A @recOR@ reduces by deciding its guards+ -- against the tope context, and a hole defers by design, so both abort. The+ -- modal constructs reduce under 'enterModality', which eval does not track.+ --+ -- An extension type ('TypeRestrictedT') and @recBOT@ do /not/ abort: they+ -- fall through to the generic constructor case below and are compared+ -- structurally. For two restricted types with structurally identical+ -- underlying types and face lists this is sound: the ordinary unification+ -- proves the same pair by reflexive coverage (each face entails the+ -- disjunction containing itself) and by re-checking the cross-face+ -- coherences that were already proved when the type was formed (entailment+ -- is monotone in the tope context). Two @recBOT@s unify unconditionally.+ HoleT{} -> VAbort AbortHole+ RecOrT{} -> VAbort AbortRecOr+ TypeModalT{} -> VAbort AbortModal+ ModAppT{} -> VAbort AbortModal+ ModExtractT{} -> VAbort AbortModal+ LetModT{} -> VAbort AbortModal++ -- everything else is a plain constructor: evaluate the fields+ Node (AnnSig _info sig) ->+ VCon (bimap (\(ScopedAST binder body) -> Closure env binder body) (eval ctx env) sig)+ where+ fstOf l _r = l+ sndOf _l r = r++-- | β, and δ at the head of an elimination, exactly where 'whnfT' unfolds.+applyVal :: Context n -> Val n -> Val n -> Val n+applyVal ctx f v = case f of+ VLam closure -> applyClosure ctx closure v+ VNeutral neu -> case unfoldNeu ctx neu of+ Just f' -> applyVal ctx f' v+ Nothing -> VNeutral (NApp neu v)+ VAbort r -> VAbort r+ _ -> VAbort AbortStuckElim++applyClosure :: Context n -> Closure n -> Val n -> Val n+applyClosure ctx (Closure env binder body) v =+ eval ctx (IntMap.insert (Foil.nameId (Foil.nameOf binder)) v env) body++-- | Project from a pair value, or stay neutral.+projVal+ :: Context n+ -> (Neu n -> Neu n) -> (Val n -> Val n -> Val n)+ -> Val n -> Val n+projVal ctx neu pick v = case forceVal ctx v of+ VCon (PairF l r) -> pick l r+ VNeutral n -> VNeutral (neu n)+ VAbort r -> VAbort r+ _ -> VAbort AbortStuckElim++-- | Unfold a neutral's head definition once (replaying the spine), if it has one.+-- A top-level definition's value is cached (see 'cachedDefVal'); a local value+-- (rare at the head of a neutral) is evaluated in place.+unfoldNeu :: Context n -> Neu n -> Maybe (Val n)+unfoldNeu ctx = \case+ NVar x -> eval ctx IntMap.empty <$> varValue (lookupVarInfo x ctx)+ NLevel _ -> Nothing+ NApp n v -> (\f -> applyVal ctx f v) <$> unfoldNeu ctx n+ NFirst n -> projVal ctx NFirst (\l _ -> l) <$> unfoldNeu ctx n+ NSecond n -> projVal ctx NSecond (\_ r -> r) <$> unfoldNeu ctx n+ NIdJ tA a tC d x n ->+ (\vp -> case forceVal ctx vp of+ VCon ReflF{} -> d+ VNeutral np -> VNeutral (NIdJ tA a tC d x np)+ VAbort r -> VAbort r+ _ -> VAbort AbortStuckElim)+ <$> unfoldNeu ctx n++-- | Unfold definitions at the head until the value is canonical or truly stuck.+forceVal :: Context n -> Val n -> Val n+forceVal ctx (VNeutral n) | Just v <- unfoldNeu ctx n = forceVal ctx v+forceVal _ v = v++-- * Conversion++-- | 'False' means "do not know", never a definite inequality.+conv :: Context n -> Int -> Val n -> Val n -> Bool+conv ctx lvl l r = case (forceVal ctx l, forceVal ctx r) of+ (VAbort _, _) -> False+ (_, VAbort _) -> False++ (VLam c1, VLam c2) ->+ conv ctx (lvl + 1) (applyClosure ctx c1 (freshV lvl)) (applyClosure ctx c2 (freshV lvl))+ -- one-step η for lambdas, as in 'etaMatch'+ (VLam c1, v2) ->+ conv ctx (lvl + 1) (applyClosure ctx c1 (freshV lvl)) (applyVal ctx v2 (freshV lvl))+ (v1, VLam c2) ->+ conv ctx (lvl + 1) (applyVal ctx v1 (freshV lvl)) (applyClosure ctx c2 (freshV lvl))++ -- one-step η for pairs+ (VCon (PairF a b), VNeutral n) ->+ conv ctx lvl a (VNeutral (NFirst n)) && conv ctx lvl b (VNeutral (NSecond n))+ (VNeutral n, VCon (PairF a b)) ->+ conv ctx lvl (VNeutral (NFirst n)) a && conv ctx lvl (VNeutral (NSecond n)) b++ (VCon s1, VCon s2) -> case zipMatch2 s1 s2 of+ Nothing -> False+ Just s -> getAll (bifoldMap+ (All . uncurry (convClosure ctx lvl))+ (All . uncurry (conv ctx lvl))+ s)++ (VNeutral n1, VNeutral n2) -> convNeu ctx lvl n1 n2+ _ -> False+ where+ freshV = VNeutral . NLevel++convClosure :: Context n -> Int -> Closure n -> Closure n -> Bool+convClosure ctx lvl c1 c2 =+ conv ctx (lvl + 1) (applyClosure ctx c1 fresh) (applyClosure ctx c2 fresh)+ where+ fresh = VNeutral (NLevel lvl)++convNeu :: Context n -> Int -> Neu n -> Neu n -> Bool+convNeu ctx lvl = go+ where+ go (NVar x) (NVar y) = Foil.nameId x == Foil.nameId y+ go (NLevel i) (NLevel j) = i == j+ go (NApp n v) (NApp n' v') = go n n' && conv ctx lvl v v'+ go (NFirst n) (NFirst n') = go n n'+ go (NSecond n) (NSecond n') = go n n'+ go (NIdJ tA a tC d x n) (NIdJ tA' a' tC' d' x' n') =+ go n n'+ && conv ctx lvl tA tA' && conv ctx lvl a a' && conv ctx lvl tC tC'+ && conv ctx lvl d d' && conv ctx lvl x x'+ go _ _ = False++-- * Entry point++-- | Are the two terms definitely convertible? 'False' means "do not know" —+-- fall back to the ordinary unification.+nbeConvertible :: TermT n -> TermT n -> TypeCheck n Bool+nbeConvertible t1 t2 = asks $ \ctx ->+ conv ctx 0 (eval ctx IntMap.empty t1) (eval ctx IntMap.empty t2)+
+ src/Rzk/TypeCheck/Render.hs view
@@ -0,0 +1,429 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Drawing a term as an SVG diagram of a cube.+--+-- The geometry lives in "Rzk.Render.Geometry"; what is here is the part that+-- knows about terms: which subshape of the cube a tope carves out, which term+-- inhabits each of them, and what to label it with.+module Rzk.TypeCheck.Render where++import Control.Monad (forM)+import Control.Monad.Reader (asks)+import Data.List (intercalate, (\\))+import Data.Maybe (catMaybes)++import Control.Monad.Foil (Distinct)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Free.Foil (AST (Var))++import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), TModality (..),+ binderName)+import Rzk.Render.Geometry+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Display+import Rzk.TypeCheck.Eval+import Rzk.TypeCheck.Monad++-- * The subshapes of a cube++cube2powerT :: Int -> TermT n+cube2powerT 1 = cube2T+cube2powerT dim = cubeProductT (cube2powerT (dim - 1)) cube2T++splits :: [a] -> [([a], [a])]+splits [] = [([], [])]+splits (x:xs) = ([], x:xs) : [ (x : before, after) | (before, after) <- splits xs ]++verticesFrom :: [TermT n] -> [(ShapeId, TermT n)]+verticesFrom ts = combine <$> mapM mk ts+ where+ mk t = [("0", topeEQT t cube2_0T), ("1", topeEQT t cube2_1T)]+ combine xs = ([concat (map fst xs)], foldr1 topeAndT (map snd xs))++subTopes2 :: Int -> TermT n -> [(ShapeId, TermT n)]+-- 1-dim+subTopes2 1 t =+ [ (words "0", topeEQT t cube2_0T)+ , (words "1", topeEQT t cube2_1T)+ , (words "0 1", topeTopT) ]+-- 2-dim+subTopes2 2 ts =+ -- vertices+ [ (words "00", topeEQT t cube2_0T `topeAndT` topeEQT s cube2_0T)+ , (words "01", topeEQT t cube2_0T `topeAndT` topeEQT s cube2_1T)+ , (words "10", topeEQT t cube2_1T `topeAndT` topeEQT s cube2_0T)+ , (words "11", topeEQT t cube2_1T `topeAndT` topeEQT s cube2_1T)+ -- edges and the diagonal+ , (words "00 01", topeEQT t cube2_0T)+ , (words "10 11", topeEQT t cube2_1T)+ , (words "00 10", topeEQT s cube2_0T)+ , (words "01 11", topeEQT s cube2_1T)+ , (words "00 11", topeEQT s t)+ -- triangles+ , (words "00 01 11", topeLEQT t s)+ , (words "00 10 11", topeLEQT s t)+ ]+ where+ t = firstT cube2T ts+ s = secondT cube2T ts+-- 3-dim+subTopes2 3 t =+ -- vertices+ [ (words "000", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_0T)+ , (words "001", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_1T)+ , (words "010", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_0T)+ , (words "011", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_1T)+ , (words "100", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_0T)+ , (words "101", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_1T)+ , (words "110", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_0T)+ , (words "111", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_1T)+ -- edges+ , (words "000 001", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_0T)+ , (words "010 011", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 cube2_1T)+ , (words "000 010", topeEQT t1 cube2_0T `topeAndT` topeEQT t3 cube2_0T)+ , (words "001 011", topeEQT t1 cube2_0T `topeAndT` topeEQT t3 cube2_1T)+ , (words "100 101", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_0T)+ , (words "110 111", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 cube2_1T)+ , (words "100 110", topeEQT t1 cube2_1T `topeAndT` topeEQT t3 cube2_0T)+ , (words "101 111", topeEQT t1 cube2_1T `topeAndT` topeEQT t3 cube2_1T)+ , (words "000 100", topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_0T)+ , (words "001 101", topeEQT t2 cube2_0T `topeAndT` topeEQT t3 cube2_1T)+ , (words "010 110", topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_0T)+ , (words "011 111", topeEQT t2 cube2_1T `topeAndT` topeEQT t3 cube2_1T)+ -- face diagonals+ , (words "000 011", topeEQT t1 cube2_0T `topeAndT` topeEQT t2 t3)+ , (words "100 111", topeEQT t1 cube2_1T `topeAndT` topeEQT t2 t3)+ , (words "000 101", topeEQT t2 cube2_0T `topeAndT` topeEQT t1 t3)+ , (words "010 111", topeEQT t2 cube2_1T `topeAndT` topeEQT t1 t3)+ , (words "000 110", topeEQT t3 cube2_0T `topeAndT` topeEQT t1 t2)+ , (words "001 111", topeEQT t3 cube2_1T `topeAndT` topeEQT t1 t2)+ -- the long diagonal+ , (words "000 111", topeEQT t3 t2 `topeAndT` topeEQT t2 t1)+ -- face triangles+ , (words "000 001 011", topeEQT t1 cube2_0T `topeAndT` topeLEQT t2 t3)+ , (words "000 010 011", topeEQT t1 cube2_0T `topeAndT` topeLEQT t3 t2)+ , (words "100 101 111", topeEQT t1 cube2_1T `topeAndT` topeLEQT t2 t3)+ , (words "100 110 111", topeEQT t1 cube2_1T `topeAndT` topeLEQT t3 t2)+ , (words "000 001 101", topeEQT t2 cube2_0T `topeAndT` topeLEQT t1 t3)+ , (words "000 100 101", topeEQT t2 cube2_0T `topeAndT` topeLEQT t3 t1)+ , (words "010 011 111", topeEQT t2 cube2_1T `topeAndT` topeLEQT t1 t3)+ , (words "010 110 111", topeEQT t2 cube2_1T `topeAndT` topeLEQT t3 t1)+ , (words "000 010 110", topeEQT t3 cube2_0T `topeAndT` topeLEQT t1 t2)+ , (words "000 100 110", topeEQT t3 cube2_0T `topeAndT` topeLEQT t2 t1)+ , (words "001 011 111", topeEQT t3 cube2_1T `topeAndT` topeLEQT t1 t2)+ , (words "001 101 111", topeEQT t3 cube2_1T `topeAndT` topeLEQT t2 t1)+ -- diagonal triangles+ , (words "000 001 111", topeEQT t1 t2 `topeAndT` topeLEQT t2 t3)+ , (words "000 010 111", topeEQT t1 t3 `topeAndT` topeLEQT t1 t2)+ , (words "000 100 111", topeEQT t2 t3 `topeAndT` topeLEQT t2 t1)+ , (words "000 011 111", topeLEQT t1 t2 `topeAndT` topeEQT t2 t3)+ , (words "000 101 111", topeLEQT t2 t1 `topeAndT` topeEQT t1 t3)+ , (words "000 110 111", topeLEQT t3 t1 `topeAndT` topeEQT t1 t2)+ -- tetrahedra+ , (words "000 001 011 111", topeLEQT t1 t2 `topeAndT` topeLEQT t2 t3)+ , (words "000 010 011 111", topeLEQT t1 t3 `topeAndT` topeLEQT t3 t2)+ , (words "000 001 101 111", topeLEQT t2 t1 `topeAndT` topeLEQT t1 t3)+ , (words "000 100 101 111", topeLEQT t2 t3 `topeAndT` topeLEQT t3 t1)+ , (words "000 010 110 111", topeLEQT t3 t1 `topeAndT` topeLEQT t1 t2)+ , (words "000 100 110 111", topeLEQT t3 t2 `topeAndT` topeLEQT t2 t1)+ ]+ where+ t1 = firstT cube2T (firstT (cube2powerT 2) t)+ t2 = secondT cube2T (firstT (cube2powerT 2) t)+ t3 = secondT cube2T t+subTopes2 dim _ = error (show dim <> " dimensions are not supported")++componentWiseEQT :: Int -> TermT n -> TermT n -> TermT n+componentWiseEQT 1 t s = topeEQT t s+componentWiseEQT 2 t s = topeAndT+ (componentWiseEQT 1 (firstT cube2T t) (firstT cube2T s))+ (componentWiseEQT 1 (secondT cube2T t) (secondT cube2T s))+componentWiseEQT 3 t s = topeAndT+ (componentWiseEQT 2 (firstT (cube2powerT 2) t) (firstT (cube2powerT 2) s))+ (componentWiseEQT 1 (secondT cube2T t) (secondT cube2T s))+componentWiseEQT dim _ _ = error ("cannot work with " <> show dim <> " dimensions")+-- * Rendering++-- | Is the variable an anonymous one (written @_@)? Its cells are left+-- unlabelled.+isAnonymous :: Foil.Name n -> TypeCheck n Bool+isAnonymous x = asks ((== Just "_") . binderName . varOrig . lookupVarInfo x)++-- | Render a term in the current context.+ppInContext :: TermT n -> TypeCheck n String+ppInContext t = do+ naming <- asks namingOfContext+ pure (ppTerm naming (untyped t))++renderObjectsFor+ :: Distinct n+ => String -> Int -> TermT n -> TermT n+ -> TypeCheck n [(ShapeId, RenderObjectData)]+renderObjectsFor mainColor dim t term = fmap catMaybes $+ forM (subTopes2 dim t) $ \(shapeId, tope) ->+ checkTopeEntails tope >>= \case+ False -> return Nothing+ True -> typeOf term >>= \case+ UniverseTopeT{} -> localTope term $ checkTopeEntails tope >>= \case+ False -> return Nothing+ True -> return $ Just (shapeId, RenderObjectData+ { renderObjectDataLabel = ""+ , renderObjectDataFullLabel = ""+ , renderObjectDataColor = "orange" -- FIXME: orange for topes?+ })+ _ -> do+ term' <- localTope tope $ whnfT term+ let argIsOfT arg =+ null (freeVarsOfTermT arg \\ freeVarsOfTermT t)+ label <- case term' of+ AppT _ (Var z) arg -> isAnonymous z >>= \case+ True -> return ""+ False+ | argIsOfT arg -> ppInContext (Var z)+ | otherwise -> ppInContext term'+ _ -> ppInContext term'+ color <- case term' of+ Var{} -> return "purple"+ AppT _ (Var x) arg -> isAnonymous x >>= \case+ True -> return mainColor+ False+ | argIsOfT arg -> return "purple"+ | otherwise -> return mainColor+ _ -> return mainColor+ hide <- asks ctxRenderHideTerm+ return $ Just (shapeId, hideTermData hide mainColor RenderObjectData+ { renderObjectDataLabel = label+ , renderObjectDataFullLabel = label+ , renderObjectDataColor = color+ })++renderObjectsInSubShapeFor+ :: Distinct n+ => String -> Int -> [Foil.Name n] -> Foil.Name n+ -> TermT n -> TermT n -> TermT n+ -> TypeCheck n [(ShapeId, RenderObjectData)]+renderObjectsInSubShapeFor mainColor dim sub super retType f x = fmap catMaybes $ do+ let reduceContext+ = foldr topeOrT topeBottomT+ . map (foldr topeAndT topeTopT)+ . map (filter (\tope -> all (`notElem` freeVarsOfTermT tope) sub))+ . map (map tTope)+ . map saturateTopes+ . simplifyLHSwithDisjunctions+ contextTopes <- asks (reduceContext . ctxTopesNF)+ contextTopes' <- localTope (componentWiseEQT dim (Var super) x) $+ asks (reduceContext . ctxTopesNF)+ forM (subTopes2 dim (Var super)) $ \(shapeId, tope) ->+ checkEntails tope contextTopes >>= \case+ False -> return Nothing+ True -> do+ term <- localTope tope (whnfT (appT retType f (Var super)))+ let argIsSuper arg = null (freeVarsOfTermT arg \\ [super])+ label <- typeOf term >>= \case+ UniverseTopeT{} -> return ""+ _ -> case term of+ AppT _ (Var z) arg -> isAnonymous z >>= \case+ True -> return ""+ False+ | argIsSuper arg -> ppInContext (Var z)+ | otherwise -> ppInContext term+ _ -> ppInContext term+ color <- checkEntails tope contextTopes' >>= \case+ True -> case term of+ Var{} -> return "purple"+ AppT _ (Var z) arg -> isAnonymous z >>= \case+ True -> return mainColor+ False+ | argIsSuper arg -> return "purple"+ | otherwise -> return mainColor+ _ -> return mainColor+ False -> return "gray"+ hide <- asks ctxRenderHideTerm+ return $ Just (shapeId, hideTermData hide mainColor RenderObjectData+ { renderObjectDataLabel = label+ , renderObjectDataFullLabel = label+ , renderObjectDataColor = color+ })++renderForSubShapeSVG+ :: Distinct n+ => String -> Int -> [Foil.Name n] -> Foil.Name n+ -> TermT n -> TermT n -> TermT n+ -> TypeCheck n String+renderForSubShapeSVG mainColor dim sub super retType f x = do+ objects <- renderObjectsInSubShapeFor mainColor dim sub super retType f x+ pure (drawCube dim (map mk objects))+ where+ mk (shapeId, renderData) = (intercalate "-" (map fill shapeId), renderData)+ fill xs = xs <> replicate (3 - length xs) '1'++renderForSVG+ :: Distinct n => String -> Int -> TermT n -> TermT n -> TypeCheck n String+renderForSVG mainColor dim t term = do+ objects <- renderObjectsFor mainColor dim t term+ pure (drawCube dim (map mk objects))+ where+ mk (shapeId, renderData) = (intercalate "-" (map fill shapeId), renderData)+ fill xs = xs <> replicate (3 - length xs) '1'++drawCube :: Int -> [(String, RenderObjectData)] -> String+drawCube dim objects =+ renderCube defaultCamera rotation (`lookup` objects)+ where+ rotation :: Double+ rotation = if dim > 2 then pi/7 else 0++-- | The dimension of a cube, if it is a power of the directed interval.+dimOf :: TermT n -> Maybe Int+dimOf = \case+ Cube2T{} -> Just 1+ CubeProductT _ l r -> (+) <$> dimOf l <*> dimOf r+ -- WARNING: breaks for 2 * (2 * 2)+ _ -> Nothing++maxRenderDim :: Int+maxRenderDim = 3++renderTermSVGFor+ :: Distinct n+ => String -- ^ main colour+ -> Int -- ^ dimensions accumulated so far (0 to 3)+ -> (Maybe (TermT n, TermT n), [Foil.Name n]) -- ^ the accumulated point, and its cube+ -> TermT n -- ^ the term to render+ -> TypeCheck n (Maybe String)+renderTermSVGFor mainColor accDim (mp, xs) t = do+ t' <- whnfT t+ ty <- typeOf t'+ case t of -- check the unevaluated term+ AppT _info f x -> renderApp f x+ TypeFunT _ _orig' md' _ _ _+ | null xs -> withBinder (BinderVar (Just "_")) md' t' $ \binder ->+ renderTermSVGFor "blue" 0 (Nothing, []) (Var (Foil.nameOf binder)) -- blue for types++ _ -> case t' of -- check the evaluated term+ AppT _info f x -> renderApp f x+ TypeFunT _ _orig' md' _ _ _+ | null xs -> withBinder (BinderVar (Just "_")) md' t' $ \binder ->+ renderTermSVGFor "blue" 0 (Nothing, []) (Var (Foil.nameOf binder))++ _ -> case ty of -- check the type of the term+ TypeFunT _ orig md arg mtope ret+ | Just dim <- dimOf arg, accDim + dim <= maxRenderDim ->+ underArg orig md arg mtope ret t' (accDim + dim) True+ | null xs ->+ underArg orig md arg mtope ret t' accDim False+ _ -> renderAccumulated t'+ where+ renderAccumulated t' = traverse (\(p', _) -> renderForSVG mainColor accDim p' t') mp++ renderApp f x = typeOf f >>= \case+ TypeFunT _ fOrig md fArg mtopeArg ret+ | Just dim <- dimOf fArg, dim <= maxRenderDim ->+ inScopeMaybeTope fOrig md fArg mtopeArg $ \binder -> do+ ret' <- openScoped binder ret+ -- FIXME: breaks for 2 * (2 * 2), but works for 2 * 2 * 2 = (2 * 2) * 2+ Just <$> renderForSubShapeSVG mainColor dim+ (map Foil.sink xs) (Foil.nameOf binder)+ ret' (Foil.sink f) (Foil.sink x)+ _ -> do+ t' <- whnfT t+ renderAccumulated t'++ -- Go under the domain of a function type, assuming its shape tope if it has+ -- one, and render the body there.+ underArg orig md arg mtope ret t' accDim' extend =+ inScopeMaybeTope orig md arg mtope $ \binder -> do+ let z = Var (Foil.nameOf binder)+ arg' = Foil.sink arg+ body <- case t' of+ LambdaT _ _orig _marg lamBody -> openScoped binder lamBody+ _ -> do+ ret' <- openScoped binder ret+ pure (appT ret' (Foil.sink t') z)+ let mp' | extend = join' (fmap (both Foil.sink) mp) arg' z+ | otherwise = fmap (both Foil.sink) mp+ xs' | extend = Foil.nameOf binder : map Foil.sink xs+ | otherwise = map Foil.sink xs+ renderTermSVGFor mainColor accDim' (mp', xs') body++ both f (x, y) = (f x, f y)++ join' Nothing Cube2T{} x = Just (x, cube2T)+ join' (Just (p, pt)) Cube2T{} x = Just (p', pt')+ where+ pt' = cubeProductT pt cube2T+ p' = pairT pt' p x+ join' p (CubeProductT _ l r) x =+ join' (join' p l (firstT l x)) r (secondT r x)+ join' _ _ _ = Nothing -- FIXME: error?++-- | Enter a binder and assume the shape tope it carries, if any.+inScopeMaybeTope+ :: Distinct n+ => Binder -> TModality -> TermT n -> Maybe (ScopedTermT n)+ -> (forall l. (Foil.DExt n l, Distinct l) => Foil.NameBinder n l -> TypeCheck l a)+ -> TypeCheck n a+inScopeMaybeTope orig md ty mtope k =+ withBinder orig md ty $ \binder ->+ case mtope of+ Nothing -> k binder+ Just tope -> do+ tope' <- openScoped binder tope+ localTope tope' (k binder)++renderTermSVG :: Distinct n => TermT n -> TypeCheck n (Maybe String)+renderTermSVG = renderTermSVGFor "red" 0 (Nothing, []) -- red for terms, by default++-- | Render the goal /cell/ for a (shape) type: introduce an abstract inhabitant+-- and render it with the proof term hidden. Under a boundary tope an abstract+-- inhabitant of an extension type reduces to the prescribed face value, so the+-- cell shows its given edges with a blank interior — the shape to inhabit, not an+-- answer. 'Nothing' for a non-shape type (a 0-cell, or a non-cube goal).+renderGoalCellSVG :: Distinct n => TermT n -> TypeCheck n (Maybe String)+renderGoalCellSVG ty =+ hidingTerm $ withBinder (BinderVar (Just "_")) Id ty $ \binder ->+ renderTermSVG' (Var (Foil.nameOf binder))++renderTermSVG' :: forall n. Distinct n => TermT n -> TypeCheck n (Maybe String)+renderTermSVG' t = whnfT t >>= \t' -> typeOf t >>= \case+ TypeFunT _ orig md arg mtope ret ->+ inScopeMaybeTope orig md arg mtope $ \binder ->+ case t' of+ LambdaT _ _orig _marg lamBody ->+ openScoped binder lamBody >>= \case+ AppT _info f x -> typeOf f >>= \case+ TypeFunT _ fOrig md2 fArg mtope2 _ret+ | Just dim <- dimOf fArg -> do+ ret' <- openScoped binder ret+ inScopeMaybeTope fOrig md2 fArg mtope2 $ \binder2 ->+ Just <$> renderForSubShapeSVG "red" dim+ [Foil.sink (Foil.nameOf binder)] (Foil.nameOf binder2)+ (Foil.sink ret') (Foil.sink f) (Foil.sink x)+ _ -> renderApplied binder t' arg ret+ _ -> renderApplied binder t' arg ret+ _ -> renderApplied binder t' arg ret+ _t' -> return Nothing++-- | Render a term of a function type by applying it to the variable it abstracts+-- over, and drawing that.+renderApplied+ :: Foil.DExt n l+ => Foil.NameBinder n l -> TermT n -> TermT n -> ScopedTermT n+ -> TypeCheck l (Maybe String)+renderApplied binder t' arg ret = do+ ret' <- openScoped binder ret+ let z = Var (Foil.nameOf binder)+ applied = appT ret' (Foil.sink t') z+ case dimOf arg of+ Just dim | dim <= maxRenderDim ->+ Just <$> renderForSVG "red" dim z applied+ _ -> renderTermSVG' applied
+ src/Rzk/TypeCheck/Unify.hs view
@@ -0,0 +1,469 @@+{-# OPTIONS_GHC -fno-warn-name-shadowing #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE GADTs #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE PatternSynonyms #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | Unification, which in rzk is really subtyping: an extension type's faces, a+-- shape's tope and the variance of the position all take part.+module Rzk.TypeCheck.Unify where++import Control.Monad (forM_, unless, when)+import Control.Monad.Except (catchError, throwError)+import Control.Monad.Reader (asks)+import Data.Maybe (fromMaybe)+import Data.Tuple (swap)++import Control.Monad.Foil (DExt, Distinct, NameBinder)+import qualified Control.Monad.Foil as Foil+import Control.Monad.Free.Foil (AST (Var))++import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder, TModality (..),+ TypeInfo (..))+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Display (panicImpossible)+import Rzk.TypeCheck.Error+import Rzk.TypeCheck.Eval+import Rzk.TypeCheck.Monad+import Rzk.TypeCheck.NbE (nbeConvertible)++-- | Open two scoped terms under /one/ binder, so that the two sides of a+-- comparison are compared as functions of the same variable.+inScope2+ :: Distinct n+ => Binder -> TModality -> TermT n+ -> ScopedTermT n -> ScopedTermT n+ -> (forall l. (DExt n l, Distinct l)+ => NameBinder n l -> TermT l -> TermT l -> TypeCheck l a)+ -> TypeCheck n a+inScope2 orig md ty s1 s2 k = do+ scope <- asks ctxScope+ withScopedT2 scope s1 s2 $ \binder body1 body2 ->+ underBinder binder orig md ty Nothing (k binder body1 body2)++-- | α-equivalence in the ambient scope.+alphaEq :: Distinct n => TermT n -> TermT n -> TypeCheck n Bool+alphaEq l r = do+ scope <- asks ctxScope+ pure (alphaEqT scope l r)++unifyTopes :: Distinct n => TermT n -> TermT n -> TypeCheck n ()+unifyTopes l r = do+ equiv <- (&&)+ <$> [plainTope l] `entailM` r+ <*> [plainTope r] `entailM` l+ unless equiv $+ issueTypeError (TypeErrorTopesNotEquivalent l r)++unify+ :: Distinct n+ => Maybe (TermT n) -> TermT n -> TermT n -> TypeCheck n ()+unify mterm expected actual = performUnification `catchError` \typeError -> do+ inAllSubContexts (throwError typeError) performUnification+ where+ performUnification = unifyInCurrentContext mterm expected actual++-- | The syntactic fast path.+--+-- α-equivalence, not the structural equality the old representation used: two+-- terms that differ only in a binder's name are the same term, and saying so here+-- saves the whole unification below.+unifyViaDecompose :: Distinct n => TermT n -> TermT n -> TypeCheck n ()+unifyViaDecompose expected actual = do+ same <- alphaEq expected actual+ if same+ then return ()+ else do+ -- The NbE fast path: a shared-evaluation βδη-conversion check over the+ -- context-insensitive fragment. 'True' is definite (see the module's+ -- soundness note); 'False' only means "do not know", and unification+ -- proceeds unchanged. It must run /before/ the application decomposition+ -- below: decomposing @f x@ against @g y@ compares the arguments pairwise,+ -- which for βδ-equal but structurally different applications creates+ -- false subgoals (e.g. @16 =? 128@ from @16 · 16 =? 128 + 128@) that the+ -- old path then grinds through only to fail and unwind.+ fastPath <- nbeConvertible expected actual+ if fastPath+ then return ()+ else case (expected, actual) of+ (AppT _ f x, AppT _ g y) -> do+ unify Nothing f g+ setVariance Invariant $ unify Nothing x y+ _ -> issueTypeError (TypeErrorOther "cannot decompose")++unifyTypes :: Distinct n => TermT n -> TermT n -> TermT n -> TypeCheck n ()+unifyTypes = unify . Just++unifyTerms :: Distinct n => TermT n -> TermT n -> TypeCheck n ()+unifyTerms = unify Nothing++checkCoherence+ :: Distinct n+ => (TermT n, TermT n) -> (TermT n, TermT n) -> TypeCheck n ()+checkCoherence (ltope, lterm) (rtope, rterm) =+ performing (ActionCheckCoherence (ltope, lterm) (rtope, rterm)) $+ localTope (topeAndT ltope rtope) $ do+ ltype <- stripTypeRestrictions <$> typeOf lterm -- FIXME: why strip?+ rtype <- stripTypeRestrictions <$> typeOf rterm -- FIXME: why strip?+ -- FIXME: do we need to unify types here or is it included in unification of terms?+ unifyTerms ltype rtype+ unifyTerms lterm rterm++unifyInCurrentContext+ :: forall n. Distinct n+ => Maybe (TermT n) -> TermT n -> TermT n -> TypeCheck n ()+unifyInCurrentContext mterm expected actual = performing action $ do+ inBottom <- contextEntailsBottom+ unless inBottom $+ -- NOTE: the decomposition gives a small, but noticeable speedup+ unifyViaDecompose expected actual `catchError` \_ -> do+ expectedVal <- whnfT expected+ actualVal <- whnfT actual+ mea <- asks ctxCovariance >>= \case+ Covariant -> Just <$> etaMatch mterm expectedVal actualVal+ Contravariant -> Just . swap <$> etaMatch mterm actualVal expectedVal+ Invariant -> traceTypeCheck Debug "invariant" $ do+ -- FIXME: inefficient+ traceTypeCheck Debug "invariant->covariant" $+ setVariance Covariant $ unifyInCurrentContext mterm expectedVal actualVal+ traceTypeCheck Debug "invariant->contravariant" $+ setVariance Contravariant $ unifyInCurrentContext mterm expectedVal actualVal+ return Nothing+ case mea of+ Nothing -> return ()+ -- A hole (in lenient mode) stands for a term of the expected type, so it+ -- unifies with anything; accept it rather than falling through to the+ -- dispatch below (which would panic on an unexpected term).+ Just (expected', actual') | isHoleT expected' || isHoleT actual' -> return ()+ Just (expected', actual') -> do+ same <- alphaEq expected' actual'+ unless same $ dispatch expected' actual'+ where+ action = case mterm of+ Nothing -> ActionUnifyTerms expected actual+ Just term -> ActionUnify term expected actual++ dispatch :: TermT n -> TermT n -> TypeCheck n ()+ dispatch expected' actual' =+ case actual' of+ RecBottomT{} -> return ()+ RecOrT _ty rs' ->+ case expected' of+ RecOrT _ty rs -> sequence_ (checkCoherence <$> rs <*> rs')+ _ ->+ forM_ rs' $ \(tope, term) ->+ localTope tope $+ unifyTerms expected' term+ _ -> typeOf expected' >>= typeOf >>= \case+ UniverseCubeT{} -> contextEntails (topeEQT expected' actual')+ _ -> unifyStructurally expected' actual'++ unifyStructurally :: TermT n -> TermT n -> TypeCheck n ()+ unifyStructurally expected' actual' = do+ -- A hole stands for a term of the expected type, so a unification that would+ -- otherwise fail is deferred when either side still contains an (unfilled)+ -- hole — including one nested in a larger term, e.g. @f ?@ checked against an+ -- extension-type boundary. The hole may also sit in the tope context rather+ -- than the terms: a hole standing for a whole shape point makes the enclosing+ -- 'recOR' split over hole-dependent faces, and a branch reduction can drop the+ -- hole from the terms while the assumed face (@π₁ ? ≤ π₂ ?@, say) still+ -- mentions it. Such a branch is only entered because the hole is unfilled, so+ -- a mismatch under it is deferred too. 'structuralHoleUnify' turns this off,+ -- keeping a structural mismatch around a hole an error.+ defer <- asks ctxDeferHoleMismatches+ topeContextHasHole <- asks (any (containsHole . tTope) . ctxTopes)+ let holePresent = defer &&+ (containsHole expected' || containsHole actual' || topeContextHasHole)++ err :: TypeCheck n ()+ err+ | holePresent = return ()+ | otherwise =+ case mterm of+ Nothing -> issueTypeError (TypeErrorUnifyTerms expected' actual')+ Just term -> issueTypeError (TypeErrorUnify term expected' actual')++ -- The same error, raised from inside a binder: the terms are sunk into+ -- the inner scope, which is a coercion. (The old representation had to+ -- shift each of them with @S <$>@.)+ errIn :: DExt n l => TypeCheck l ()+ errIn+ | holePresent = return ()+ | otherwise =+ case mterm of+ Nothing -> issueTypeError+ (TypeErrorUnifyTerms (Foil.sink expected') (Foil.sink actual'))+ Just term -> issueTypeError+ (TypeErrorUnify (Foil.sink term) (Foil.sink expected') (Foil.sink actual'))++ def = do+ same <- alphaEq expected' actual'+ unless same err++ case expected' of+ Var{} -> def++ UniverseT{} -> def+ UniverseCubeT{} -> def+ UniverseTopeT{} -> def++ TypeUnitT{} -> def+ UnitT{} -> return () -- Unit always unifies!++ CubeUnitT{} -> def+ CubeUnitStarT{} -> def+ Cube2T{} -> def+ Cube2_0T{} -> def+ Cube2_1T{} -> def+ CubeIT{} -> def+ CubeI_0T{} -> def+ CubeI_1T{} -> def+ CubeProductT _ l r ->+ case actual' of+ CubeProductT _ l' r' -> do+ unifyTerms l l'+ unifyTerms r r'+ _ -> err++ PairT _ty l r ->+ case actual' of+ PairT _ty' l' r' -> do+ unifyTerms l l'+ unifyTerms r r'+ -- one part of eta-expansion for pairs+ -- FIXME: add symmetric version!+ _ -> err++ FirstT _ty t ->+ case actual' of+ FirstT _ty' t' -> unifyTerms t t'+ _ -> err++ SecondT _ty t ->+ case actual' of+ SecondT _ty' t' -> unifyTerms t t'+ _ -> err++ TopeTopT{} -> unifyTopes expected' actual'+ TopeBottomT{} -> unifyTopes expected' actual'+ TopeEQT{} -> unifyTopes expected' actual'+ TopeLEQT{} -> unifyTopes expected' actual'+ TopeAndT{} -> unifyTopes expected' actual'+ TopeOrT{} -> unifyTopes expected' actual'+ TopeInvT{} -> unifyTopes expected' actual'+ TopeUninvT{} -> unifyTopes expected' actual'++ RecBottomT{} -> return () -- unifies with anything+ RecOrT _ty rs ->+ -- IMPORTANT: matching on actual' here would be redundant, but that is+ -- not obvious; take care when refactoring.+ forM_ rs $ \(tope, term) ->+ localTope tope $+ unifyTerms term actual'++ TypeFunT _ty _orig md cube mtope ret ->+ case actual' of+ TypeFunT _ty' orig' md' cube' mtope' ret' -> do+ when (md /= md') $+ issueTypeError (TypeErrorOther $ "modality mismatch in function type: expected " <> show md <> " but got " <> show md')+ switchVariance $ -- unifying in the negative position!+ unifyTerms cube cube' -- FIXME: unifyCubes+ inScope2 orig' md cube' ret ret' $ \binder retBody retBody' -> do+ -- The tope checks below are subtyping checks with a fixed direction+ -- relative to (subtype, supertype). Which side is the subtype+ -- depends on the ambient variance: under Covariant the actual type+ -- must be a subtype of the expected one; under Contravariant (inside+ -- a domain) the roles are reversed. Invariant is normally handled+ -- upstream by running both directions; it is handled here as well+ -- for safety.+ variance <- asks ctxCovariance+ scope <- asks ctxScope+ let openTope = fmap (openWith scope (Foil.nameOf binder))+ mtopeIn = openTope mtope+ mtopeIn' = openTope mtope'+ case retBody' of+ UniverseTopeT{} -> do+ -- This is the case for tope families (shapes).+ --+ -- (Λ → TOPE) <: (Δ → TOPE) since if φ : Λ → TOPE then φ ⊢ Δ.+ -- We DO NOT take the tope context Φ into account!+ expectedTopeNF <- fromMaybe topeTopT <$> traverse nfT mtopeIn+ actualTopeNF <- fromMaybe topeTopT <$> traverse nfT mtopeIn'+ let subEntailsSuper subNF superNF = do+ entails <- [plainTope subNF] `entailM` superNF+ unless (entails || containsHole subNF || containsHole superNF) $+ issueTypeError (TypeErrorTopeNotSatisfied [subNF] superNF)+ case variance of+ Covariant -> subEntailsSuper actualTopeNF expectedTopeNF+ Contravariant -> subEntailsSuper expectedTopeNF actualTopeNF+ Invariant -> do+ subEntailsSuper actualTopeNF expectedTopeNF+ subEntailsSuper expectedTopeNF actualTopeNF+ _ -> do+ -- this is the case for Π-types and extension types+ --+ -- Ξ | Φ | Γ ⊢ {t : I | φ} → A t <: {s : J | ψ} → B s+ -- when Ξ | Φ, ψ ⊢ φ+ expectedTopeNF <- fromMaybe topeTopT <$> traverse nfT mtopeIn+ actualTopeNF <- fromMaybe topeTopT <$> traverse nfT mtopeIn'+ let superEntailsSub superNF subNF =+ localTope superNF $ contextEntails subNF+ case variance of+ Covariant -> superEntailsSub expectedTopeNF actualTopeNF+ Contravariant -> superEntailsSub actualTopeNF expectedTopeNF+ Invariant -> do+ superEntailsSub expectedTopeNF actualTopeNF+ superEntailsSub actualTopeNF expectedTopeNF+ case mterm of+ Nothing -> unifyTerms retBody retBody'+ Just term ->+ unifyTypes+ (appT retBody' (Foil.sink term) (Var (Foil.nameOf binder)))+ retBody retBody'+ _ -> err++ TypeSigmaT _ty _orig md a b ->+ case actual' of+ TypeSigmaT _ty' orig' md' a' b' -> do+ when (md /= md') $+ issueTypeError (TypeErrorOther $ "modality mismatch in sigma type: expected " <> show md <> " but got " <> show md')+ unify Nothing a a'+ inScope2 orig' md a' b b' $ \_binder bBody bBody' ->+ unify Nothing bBody bBody'+ _ -> err++ TypeIdT _ty x tA y ->+ case actual' of+ TypeIdT _ty' x' tA' y' -> do+ -- The underlying types must be compared: without this check the+ -- routine equates identity types over different types whenever the+ -- endpoints unify, accepting a free homotopy (a path in the type of+ -- functions) where an endpoint-fixing one (a path in a hom-type) is+ -- expected. Compared invariantly: subtyping between the underlying+ -- types must not leak into equality of identity types over them.+ mapM_ (\(t1, t2) -> setVariance Invariant (unify Nothing t1 t2))+ ((,) <$> tA <*> tA')+ unify Nothing x x'+ unify Nothing y y'+ _ -> err++ AppT _ty f x ->+ case actual' of+ AppT _ty' f' x' -> do+ unify Nothing f f'+ setVariance Invariant $+ unify Nothing x x'+ _ -> err++ LambdaT ty _orig _mparam body ->+ case stripTypeRestrictions (infoType ty) of+ TypeFunT _ty _origF md param mtope _ret ->+ case actual' of+ LambdaT ty' orig' _mparam' body' ->+ case stripTypeRestrictions (infoType ty') of+ TypeFunT _ty' _origF' md' param' mtope' _ret' -> do+ when (md /= md') $+ issueTypeError (TypeErrorOther $ "modality mismatch in lambda: expected " <> show md <> " but got " <> show md')+ unify Nothing param param' -- we (should) have already checked this in types!+ inScope2 orig' md param body body' $ \binder bodyIn bodyIn' -> do+ scope <- asks ctxScope+ let openTope = fmap (openWith scope (Foil.nameOf binder))+ case (openTope mtope, openTope mtope') of+ (Just tope, Just tope') -> do+ unify Nothing tope tope' -- we (should) have already checked this in types!+ localTope tope $ unify Nothing bodyIn bodyIn'+ (Nothing, Nothing) ->+ unify Nothing bodyIn bodyIn'+ _ -> errIn+ _ -> err+ _ -> err+ _ -> err++ LetT{} -> panicImpossible "let at the root of WHNF"+ LetModT _ orig app inn _ val body ->+ case actual' of+ LetModT _ _ app' inn' _ val' body'+ | app == app', inn == inn' -> do+ unify Nothing val val'+ bty <- typeOf val >>= \case+ TypeModalT _ _ t -> pure t+ _ -> panicImpossible "not modal in letmod"+ inScope2 orig (comp app inn) bty body body' $ \_binder bodyIn bodyIn' ->+ unify Nothing bodyIn bodyIn'+ _ -> err++ ReflT ty _x | TypeIdT _ty x _tA y <- infoType ty ->+ case actual' of+ ReflT ty' _x' | TypeIdT _ty' x' _tA' y' <- infoType ty' -> do+ unify Nothing x x'+ unify Nothing y y'+ _ -> err+ ReflT{} -> panicImpossible "refl with a non-identity type!"++ IdJT _ty a b c d e f ->+ case actual' of+ IdJT _ty' a' b' c' d' e' f' -> do+ unify Nothing a a'+ unify Nothing b b'+ unify Nothing c c'+ unify Nothing d d'+ unify Nothing e e'+ unify Nothing f f'+ _ -> err++ TypeAscT{} -> panicImpossible "type ascription at the root of WHNF"++ TypeRestrictedT _ty ty rs ->+ case actual' of+ TypeRestrictedT _ty' ty' rs' -> do+ unify mterm ty ty'+ -- The faces of the supertype must be covered by the faces of the+ -- subtype (the subtype is at least as specified), with the boundary+ -- terms agreeing on overlaps. Which side is the subtype depends on the+ -- ambient variance.+ variance <- asks ctxCovariance+ let subCoversSuper subRs superRs = sequence_+ [ localTope tope $ do+ -- FIXME: can do less entails checks?+ contextEntails (foldr topeOrT topeBottomT (map fst subRs))+ forM_ subRs $ \(tope', term') ->+ localTope tope' $+ unify Nothing term term'+ | (tope, term) <- superRs+ ]+ case variance of+ Covariant -> subCoversSuper rs' rs+ Contravariant -> subCoversSuper rs rs'+ Invariant -> do+ subCoversSuper rs' rs+ subCoversSuper rs rs'+ _ -> err -- FIXME: need better unification for restrictions++ TypeModalT _ty m ty ->+ case actual' of+ TypeModalT _ty' m' ty' -> do+ when (m' /= m) err+ enterModality m $ unify Nothing ty ty'+ _ -> err+ ModAppT _ty m ty ->+ case actual' of+ ModAppT _ty' m' ty' -> do+ when (m' /= m) err+ enterModality m $ unify Nothing ty ty'+ _ -> err+ ModExtractT _ty app inn te ->+ case actual' of+ ModExtractT _ty' app' inn' te' -> do+ when (app' /= app) err+ when (inn' /= inn) err+ enterModality app $ unify Nothing te te'+ _ -> err++ -- defensive: a hole nested anywhere also defers here rather than panicking+ -- on an otherwise unexpected shape+ _ | holePresent -> return ()+ _ -> panicImpossible "unexpected term in UNIFY"
test/Rzk/BinderTypesSpec.hs view
@@ -8,7 +8,7 @@ import qualified Data.Text as T -import Language.Rzk.Free.Syntax (RzkPosition (RzkPosition),+import Language.Rzk.Foil.Names (RzkPosition (RzkPosition), getVarIdent) import qualified Language.Rzk.Syntax as Rzk import Language.Rzk.Syntax (VarIdent' (VarIdent))@@ -23,15 +23,14 @@ binderTypesOf src = case Rzk.parseModule src of Left err -> error ("parse error: " <> T.unpack err)- Right m -> case defaultTypeCheck (localVerbosity Silent (typecheckModulesWithLocation [("<test>", m)])) of- Left err -> error ("typecheck threw: " <> ppTypeErrorInScopedContext' BottomUp err)- Right decls ->- let ds = concatMap snd decls- in [ (pos, view t)- | (v, t) <- binderTypesInScopeOf ds ds- , let VarIdent (RzkPosition _ mpos) _ = getVarIdent v- , Just pos <- [mpos]- ]+ Right m -> case typecheckModules [("<test>", m)] of+ Left err -> error ("typecheck threw: " <> ppTypeErrorInScopedContext BottomUp err)+ Right checked ->+ [ (pos, view t)+ | (v, t) <- binderTypesOfFile checked "<test>"+ , let VarIdent (RzkPosition _ mpos) _ = getVarIdent v+ , Just pos <- [mpos]+ ] where view (TypeView t) = show t view (ShapeView c tope) = show c <> " | " <> show tope
test/Rzk/DiagnosticSpec.hs view
@@ -22,9 +22,9 @@ case Rzk.parseModule src of Left err -> error ("parse error: " <> T.unpack err) Right m -> case typecheckModulesWithHoles [("<test>", m)] of- Left err -> [diagnoseTypeError BottomUp err]- Right (_, errors, holes) ->- map (diagnoseTypeError BottomUp) errors ++ map diagnoseHole holes+ Left err -> [diagnoseTypeError BottomUp err]+ Right (checked, holes) ->+ map (diagnoseTypeError BottomUp) (checkedErrors checked) ++ map diagnoseHole holes spec :: Spec spec = do
+ test/Rzk/FoilCoreSpec.hs view
@@ -0,0 +1,212 @@+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ScopedTypeVariables #-}++-- | The free-foil core: the surface conversions, α-equivalence, and the typing+-- context.+--+-- The context tests are the load-bearing ones. Entering a binder sinks the+-- context by coercion (see "Rzk.TypeCheck.Context"), which is sound but unsafe if+-- the argument is ever wrong, so these check the things the argument promises:+-- that an entry stays intact and keeps its meaning however deeply it is sunk.+module Rzk.FoilCoreSpec (spec) where++import qualified Control.Monad.Foil as Foil+import Control.Monad.Free.Foil (AST (Var), ScopedAST (..),+ alphaEquiv)+import qualified Data.Text as T+import Test.Hspec++import Language.Rzk.Foil.Convert (toTermClosed)+import Language.Rzk.Foil.Print (fromTermClosed)+import Language.Rzk.Foil.Syntax+import Language.Rzk.Foil.Names (Binder (..), TModality (..),+ VarIdent, binderName)+import qualified Language.Rzk.Syntax as Rzk+import Rzk.TypeCheck.Context+import Rzk.TypeCheck.Display (namingOfContext, ppName, ppTerm)+import Rzk.TypeCheck.Error (OutputDirection (..),+ ppTypeErrorInScopedContext)+import Rzk.TypeCheck.Eval (nfT, whnfT)+import Rzk.TypeCheck.Judgements (infer, typecheck)+import Rzk.TypeCheck.Monad (runTypeCheck)++-- | Parse a term of the surface syntax, or fail loudly.+parse :: T.Text -> Rzk.Term+parse t =+ case Rzk.parseTerm t of+ Left err -> error ("cannot parse " <> show t <> ": " <> T.unpack err)+ Right term -> term++-- | Parse a closed term into the core.+core :: T.Text -> Term Foil.VoidS+core = toTermClosed . parse++-- | Parse, elaborate to the core, and print back as surface syntax.+roundTrip :: T.Text -> T.Text+roundTrip = T.pack . Rzk.printTree . fromTermClosed . core++-- | Are two closed terms α-equivalent?+equivalent :: T.Text -> T.Text -> Bool+equivalent l r = alphaEquiv Foil.emptyScope (core l) (core r)++-- | A hypothesis of the given type, with no value and no modality.+hypothesis :: VarIdent -> TermT n -> VarInfo n+hypothesis name ty = VarInfo+ { varType = ty+ , varValue = Nothing+ , varModality = Id+ , varModAccum = Id+ , varOrig = BinderVar (Just name)+ , varIsAssumption = False+ , varIsTopLevel = False+ , varDeclaredAssumptions = []+ , varLocation = Nothing+ }++spec :: Spec+spec = do+ -- The terms are closed (a free variable has no name to resolve to in an empty+ -- scope), so each type-level example binds its own A and B.+ describe "surface syntax round-trips through the core" $ do+ let it_roundTrips t expected =+ it (T.unpack t) $ roundTrip t `shouldBe` expected++ it_roundTrips "\\ x -> x" "\\ x → x"+ it_roundTrips "\\ (t, s) -> t" "\\ (t, s) → t"+ it_roundTrips "\\ A -> \\ (x : A) -> x" "\\ A → \\ (x : A) → x"+ it_roundTrips "\\ A -> \\ B -> (x : A) -> B" "\\ A → \\ B → (x : A) → B"+ it_roundTrips "\\ A -> \\ B -> A -> B" "\\ A → \\ B → A → B"+ it_roundTrips "\\ A -> \\ B -> Sigma (x : A), B" "\\ A → \\ B → Σ (x : A), B"+ it_roundTrips "\\ (t, s) -> first (t, s)" "\\ (t, s) → π₁ (t, s)"+ it_roundTrips "\\ A -> \\ (x : A) -> refl_{x : A}" "\\ A → \\ (x : A) → refl_{ x : A }"+ it_roundTrips "\\ t -> \\ s -> t === s" "\\ t → \\ s → t ≡ s"++ describe "α-equivalence ignores binder names" $ do+ it "\\ x -> x is \\ y -> y" $+ equivalent "\\ x -> x" "\\ y -> y" `shouldBe` True++ -- The old representation derived Eq structurally, so it compared the binder+ -- names too and called these two unequal. This is the behaviour change.+ it "\\ x -> \\ y -> x is not \\ x -> \\ y -> y" $+ equivalent "\\ x -> \\ y -> x" "\\ x -> \\ y -> y" `shouldBe` False++ it "a pair pattern binds one variable, and its projections are right" $ do+ equivalent "\\ (t, s) -> t" "\\ (a, b) -> a" `shouldBe` True+ equivalent "\\ (t, s) -> t" "\\ (a, b) -> b" `shouldBe` False++ it "two holes with different names are different terms" $+ equivalent "?a" "?b" `shouldBe` False++ describe "the context" $ do+ it "resolves a name bound three binders up" $ do+ let ctx0 = emptyContext+ withFreshBinder ctx0 (hypothesis "A" universeT) $ \bA ctxA ->+ withFreshBinder ctxA (hypothesis "x" (Var (Foil.nameOf bA))) $ \_bx ctxx ->+ withFreshBinder ctxx (hypothesis "y" cubeT) $ \_by ctxy -> do+ -- 'A' was bound at the outermost scope and has been sunk twice.+ case lookupNamed "A" ctxy of+ Nothing -> expectationFailure "A is not in scope"+ Just nameA -> do+ let info = lookupVarInfo nameA ctxy+ binderName (varOrig info) `shouldBe` Just "A"+ alphaEquiv (ctxScope ctxy) (untyped (varType info)) (untyped universeT)+ `shouldBe` True++ it "keeps a sunk hypothesis pointing at the name it was typed by" $ do+ -- x : A, where A is itself a bound name. After sinking x's entry into a+ -- deeper scope, its type must still be *that* name, not a stale or+ -- renamed one: this is what the coercion in 'enterBinder' promises.+ withFreshBinder emptyContext (hypothesis "A" universeT) $ \bA ctxA -> do+ let nameA = Foil.nameOf bA+ withFreshBinder ctxA (hypothesis "x" (Var nameA)) $ \_bx ctxx ->+ withFreshBinder ctxx (hypothesis "y" cubeT) $ \_by ctxy ->+ case lookupNamed "x" ctxy of+ Nothing -> expectationFailure "x is not in scope"+ Just nameX -> do+ let info = lookupVarInfo nameX ctxy+ case untyped (varType info) of+ Var name -> Foil.nameId name `shouldBe` Foil.nameId nameA+ _ -> expectationFailure "the type of x is no longer a variable"++ it "lets the outer binder keep its name when an inner one shadows it" $+ -- Display names are claimed oldest binding first (see 'ctxBound'), so the+ -- inner 'x' is the one refreshed. The order cannot be read off the name+ -- ids: free-foil refreshes a binder only on a clash, so after a+ -- substitution an inner binder may carry a smaller id than an outer one.+ withFreshBinder emptyContext (hypothesis "x" universeT) $ \bOuter ctxOuter ->+ withFreshBinder ctxOuter (hypothesis "x" universeT) $ \bInner ctxInner -> do+ let naming = namingOfContext ctxInner+ ppName naming (Foil.sink (Foil.nameOf bOuter)) `shouldBe` "x"+ ppName naming (Foil.nameOf bInner) `shouldNotBe` "x"++ it "records the names in scope for the shadowing check" $+ withFreshBinder emptyContext (hypothesis "A" universeT) $ \_bA ctxA ->+ shadowedBy "A" ctxA `shouldBe` ["A" :: VarIdent]++ describe "evaluation" $ do+ -- The identity on the directed interval, applied to an endpoint. A cube-layer+ -- term, so this drives the whole reduction path: whnfT dispatches on the+ -- layer, nfTope reduces the redex, and the argument is substituted into the+ -- body (invalidating the memo on the way).+ let identityOn2 :: TermT Foil.VoidS+ identityOn2 = Foil.withFresh Foil.emptyScope $ \binder ->+ let t = BinderVar (Just "t")+ ty = typeFunT t Id cube2T Nothing (ScopedAST binder cube2T)+ in lambdaT ty t (Just (LambdaParam Id cube2T Nothing))+ (ScopedAST binder (Var (Foil.nameOf binder)))++ applied = appT cube2T identityOn2 cube2_0T++ it "reduces (\\ t -> t) 0₂ to 0₂" $+ case runTypeCheck (whnfT applied) of+ Left err -> expectationFailure (ppTypeErrorInScopedContext TopDown err)+ Right result ->+ alphaEquiv Foil.emptyScope (untyped result) (untyped cube2_0T)+ `shouldBe` True++ it "does not reduce the unapplied identity" $+ case runTypeCheck (whnfT identityOn2) of+ Left err -> expectationFailure (ppTypeErrorInScopedContext TopDown err)+ Right result ->+ alphaEquiv Foil.emptyScope (untyped result) (untyped cube2_0T)+ `shouldBe` False++ describe "the checker" $ do+ -- Parse, elaborate, infer, normalise, and print back: the whole pipeline of+ -- the new core, end to end.+ let inferAndShow :: T.Text -> Either String String+ inferAndShow t =+ case runTypeCheck (infer (core t) >>= nfT) of+ Left err -> Left (ppTypeErrorInScopedContext TopDown err)+ Right result -> Right (ppTerm (namingOfContext emptyContext) (untyped result))++ checkAndShow :: T.Text -> T.Text -> Either String String+ checkAndShow t ty =+ case runTypeCheck (infer (core ty) >>= typecheck (core t) >>= nfT) of+ Left err -> Left (ppTypeErrorInScopedContext TopDown err)+ Right result -> Right (ppTerm (namingOfContext emptyContext) (untyped result))++ it "infers and evaluates (\\ (x : Unit) -> x) unit" $+ inferAndShow "(\\ (x : Unit) -> x) unit" `shouldBe` Right "unit"++ it "infers a dependent function type" $+ inferAndShow "(A : U) -> A -> A" `shouldBe` Right "(A : U) → A → A"++ it "checks the identity against its type" $+ -- the elaborated lambda carries the domain it was checked against+ checkAndShow "\\ A -> \\ (x : A) -> x" "(A : U) -> A -> A"+ `shouldBe` Right "\\ (A : U) → \\ (x : A) → x"++ it "rejects a term that does not have the expected type" $+ case checkAndShow "\\ A -> \\ (x : A) -> A" "(A : U) -> A -> A" of+ Left err -> err `shouldContain` "cannot unify"+ Right t -> expectationFailure ("expected a type error, got " <> t)++ -- A cube domain with a pair pattern: the binder binds one variable whose+ -- components are projections, and the pattern is shown back.+ it "checks a function from a cube point" $+ checkAndShow "\\ A -> \\ (a : A) -> \\ ((t, s) : 2 * 2) -> a"+ "(A : U) -> (a : A) -> (t : 2 * 2) -> A"+ `shouldBe` Right "\\ (A : U) → \\ (a : A) → \\ ((t, s) : 2 × 2) → a"
test/Rzk/HolesSpec.hs view
@@ -14,7 +14,7 @@ import System.FilePath ((</>)) import qualified Language.Rzk.Syntax as Rzk-import Language.Rzk.Free.Syntax (VarIdent)+import Language.Rzk.Foil.Names (VarIdent) import Rzk.Diagnostic (typeErrorTagInScopedContext) import Rzk.TypeCheck @@ -27,8 +27,8 @@ case Rzk.parseModule src of Left err -> error ("parse error: " <> T.unpack err) Right m -> case typecheckModulesWithHoles [("<test>", m)] of- Left err -> error ("typecheck threw: " <> ppTypeErrorInScopedContext' BottomUp err)- Right (_, _, holes) -> holes+ Left err -> error ("typecheck threw: " <> ppTypeErrorInScopedContext BottomUp err)+ Right (_, holes) -> holes -- | Like 'holesOf', but allow-lists the given named top-level lemmas for the -- candidate hints (see 'withHintLemmas'\/'typecheckModulesWithHolesAndLemmas').@@ -37,8 +37,8 @@ case Rzk.parseModule src of Left err -> error ("parse error: " <> T.unpack err) Right m -> case typecheckModulesWithHolesAndLemmas lemmas [("<test>", m)] of- Left err -> error ("typecheck threw: " <> ppTypeErrorInScopedContext' BottomUp err)- Right (_, _, holes) -> holes+ Left err -> error ("typecheck threw: " <> ppTypeErrorInScopedContext BottomUp err)+ Right (_, holes) -> holes names :: [HoleEntry] -> [String] names = map (show . holeEntryName)@@ -52,7 +52,7 @@ Left err -> error ("parse error: " <> T.unpack err) Right m -> case typecheckModulesWithHoles [("<test>", m)] of Left err -> [typeErrorTagInScopedContext err]- Right (_, errs, _) -> map typeErrorTagInScopedContext errs+ Right (checked, _) -> map typeErrorTagInScopedContext (checkedErrors checked) -- | Like 'holesOf'/'errTagsOf', but reads a module from @test/files/@ (so a -- large example need not be inlined). Honours @RZK_TEST_ROOT@ like the other@@ -64,8 +64,9 @@ case Rzk.parseModule src of Left err -> error ("parse error: " <> T.unpack err) Right m -> case typecheckModulesWithHoles [(name, m)] of- Left err -> error ("typecheck threw: " <> ppTypeErrorInScopedContext' BottomUp err)- Right (_, errs, hs) -> pure (hs, map typeErrorTagInScopedContext errs)+ Left err -> error ("typecheck threw: " <> ppTypeErrorInScopedContext BottomUp err)+ Right (checked, hs) ->+ pure (hs, map typeErrorTagInScopedContext (checkedErrors checked)) spec :: Spec spec = do
test/Rzk/TypeCheckSpec.hs view
@@ -17,20 +17,18 @@ takeFileName) import System.FilePath.Glob (compile, globDir1) -import Language.Rzk.Free.Syntax (VarIdent) import qualified Language.Rzk.Syntax as Rzk-import Rzk.Diagnostic (typeErrorTag)-import Rzk.TypeCheck (Context (..), Decl', LocationInfo (..),- OutputDirection (..), TypeError (..),- TypeErrorInContext (..),- TypeErrorInScopedContext (..),- Verbosity (..), defaultTypeCheck,- localVerbosity, ppTypeErrorInScopedContext',- typecheckModulesWithLocation,- typecheckModulesWithLocation')+import Rzk.Diagnostic (locationOfTypeError,+ typeErrorTagInScopedContext)+import Rzk.TypeCheck (Checked, Context (..),+ LocationInfo (..),+ OutputDirection (..),+ TypeErrorInScopedContext,+ Verbosity (..), checkedErrors,+ checkedModules, emptyContext,+ ppTypeErrorInScopedContext) import Test.Hspec-import Unsafe.Coerce (unsafeCoerce) data Expect = Expect { expectStatus :: String@@ -52,24 +50,19 @@ <*> o .:? "modules" <*> o .:? "api" --- | Strip 'ScopedTypeError' layers; take the leaf 'TypeError'.--- Scoped layers change the type parameter ('Inc'); we only need the constructor name, so 'unsafeCoerce' is used for recursion (same shape at runtime).-peelTypeError :: TypeErrorInScopedContext VarIdent -> TypeError VarIdent-peelTypeError = \case- PlainTypeError e -> typeErrorError e- ScopedTypeError _ e -> peelTypeError (unsafeCoerce e)--errorLine :: TypeErrorInScopedContext VarIdent -> Maybe Int-errorLine = \case- PlainTypeError e ->- location (typeErrorContext e) >>= locationLine- ScopedTypeError _ e -> errorLine (unsafeCoerce e)+-- | The line an error was raised on.+--+-- An error carries the context it was raised in, so there are no binder layers to+-- peel: the old representation nested the error one Inc deeper at every binder, and+-- this had to unsafeCoerce its way back out.+errorLine :: TypeErrorInScopedContext -> Maybe Int+errorLine err = locationOfTypeError err >>= locationLine --- | The constructor name of a type error, used to match @error_tag@ in--- fixtures. This is the library's 'typeErrorTag' (also used for diagnostic--- codes), aliased here so the two cannot drift apart.-typeErrorConstructorName :: TypeError VarIdent -> String-typeErrorConstructorName = typeErrorTag+-- | The constructor name of a type error, used to match @error_tag@ in fixtures.+-- This is the library's own tag (also used for diagnostic codes), so the two cannot+-- drift apart.+typeErrorConstructorName :: TypeErrorInScopedContext -> String+typeErrorConstructorName = typeErrorTagInScopedContext casesRoot :: FilePath casesRoot = "test/typecheck/cases"@@ -104,32 +97,41 @@ Right m -> fmap (fmap ((relPath, m) :)) $ loadModules rest -- | Run the checker with @verbosity = Silent@ so @traceTypeCheck Normal@ does not--- clutter @stack test@ output (CLI keeps default @Normal@ via @emptyContext@).-runStrict :: [(FilePath, Rzk.Module)] -> Either (TypeErrorInScopedContext VarIdent) [(FilePath, [Decl'])]-runStrict = defaultTypeCheck . localVerbosity Silent . typecheckModulesWithLocation+-- clutter @stack test@ output (the CLI keeps the default @Normal@).+silently :: Context n -> Context n+silently ctx = ctx { ctxVerbosity = Silent } -runCollect :: [(FilePath, Rzk.Module)] -> Either (TypeErrorInScopedContext VarIdent) ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent])-runCollect = defaultTypeCheck . localVerbosity Silent . typecheckModulesWithLocation'+-- | Strict: the first error stops the run and is returned.+runStrict :: [(FilePath, Rzk.Module)] -> Either TypeErrorInScopedContext Checked+runStrict ms = case checkedModules ms (silently emptyContext) of+ Left err -> Left err+ Right (checked, _holes) -> case checkedErrors checked of+ err : _ -> Left err+ [] -> Right checked -assertExpect :: String -> Expect -> Either (TypeErrorInScopedContext VarIdent) [(FilePath, [Decl'])] -> IO ()+-- | Collect: every error is returned, and the run continues past them.+runCollect :: [(FilePath, Rzk.Module)] -> Either TypeErrorInScopedContext Checked+runCollect ms = fst <$> checkedModules ms (silently emptyContext)++assertExpect :: String -> Expect -> Either TypeErrorInScopedContext Checked -> IO () assertExpect _label Expect{..} (Right _) | expectStatus /= "ok" = expectationFailure "expected type error (status: error), but typechecking succeeded" assertExpect label Expect{..} (Left err) | expectStatus == "ok" = expectationFailure $ "unexpected type error in " <> label <> ":\n"- <> ppTypeErrorInScopedContext' BottomUp err+ <> ppTypeErrorInScopedContext BottomUp err assertExpect label Expect{..} (Left err) | expectStatus == "error" = do- let tag = typeErrorConstructorName (peelTypeError err)+ let tag = typeErrorConstructorName err case expectErrorTag of Nothing -> expectationFailure "expect.yaml missing error_tag for status: error" Just want | want /= tag -> expectationFailure $ "wrong error constructor in " <> label <> ": wanted " <> want <> ", got " <> tag <> "\nFull message:\n"- <> ppTypeErrorInScopedContext' BottomUp err+ <> ppTypeErrorInScopedContext BottomUp err Just _ -> pure () case expectMessageContains of Nothing -> pure () Just subs -> do- let msg = ppTypeErrorInScopedContext' BottomUp err+ let msg = ppTypeErrorInScopedContext BottomUp err mapM_ (\s -> unless (s `isInfixOf` msg) $ expectationFailure $ "in " <> label <> ", message missing substring " <> show s <> ":\n" <> msg) subs@@ -146,10 +148,11 @@ assertExpect label Expect{expectStatus = st} _ = expectationFailure $ "in " <> label <> ", unknown status " <> show st -assertExpectCollect :: String -> Expect -> Either (TypeErrorInScopedContext VarIdent) ([(FilePath, [Decl'])], [TypeErrorInScopedContext VarIdent]) -> IO ()+assertExpectCollect :: String -> Expect -> Either TypeErrorInScopedContext Checked -> IO () assertExpectCollect _label _ (Left err) =- expectationFailure $ "unexpected fatal error: " <> ppTypeErrorInScopedContext' BottomUp err-assertExpectCollect label Expect{..} (Right (_decls, errs)) = case expectStatus of+ expectationFailure $ "unexpected fatal error: " <> ppTypeErrorInScopedContext BottomUp err+assertExpectCollect label Expect{..} (Right checked) = case checkedErrors checked of+ errs -> case expectStatus of "ok" | not (null errs) -> expectationFailure $ "in " <> label <> ", expected ok but got errors: " <> show (length errs) "ok" -> pure ()@@ -157,7 +160,7 @@ [] -> expectationFailure $ "in " <> label <> ", expected type errors but got none" err : _ -> do- let tag = typeErrorConstructorName (peelTypeError err)+ let tag = typeErrorConstructorName err case expectErrorTag of Nothing -> expectationFailure "expect.yaml missing error_tag for status: error" Just want | want /= tag ->@@ -167,7 +170,7 @@ case expectMessageContains of Nothing -> pure () Just subs -> do- let msg = ppTypeErrorInScopedContext' BottomUp err+ let msg = ppTypeErrorInScopedContext BottomUp err mapM_ (\s -> unless (s `isInfixOf` msg) $ expectationFailure $ "in " <> label <> ", message missing substring " <> show s) subs
+ test/typecheck/cases/happy-nbe-church-conversion.expect.yaml view
@@ -0,0 +1,4 @@+status: ok+regression_for:+ - nbe-conversion-fastpath+ - unifyViaDecompose-false-subgoals
+ test/typecheck/cases/happy-nbe-church-conversion.rzk view
@@ -0,0 +1,41 @@+#lang rzk-1++-- Church numerals: the definitional equalities below hold only after full+-- βδ-normalisation of structurally different applications, which exercises+-- the NbE conversion fast path (Rzk.TypeCheck.NbE). Kept small so that the+-- ordinary unification path also checks this file quickly.++#define CN : U+ := (X : U) → (X → X) → X → X++#define czero : CN+ := \ X s x → x++#define csucc (n : CN) : CN+ := \ X s x → s (n X s x)++#define cadd (m n : CN) : CN+ := \ X s x → m X s (n X s x)++#define cmul (m n : CN) : CN+ := \ X s → m X (n X s)++#define cexp (m n : CN) : CN+ := \ X → n (X → X) (m X)++#define c1 : CN := csucc czero+#define c2 : CN := cadd c1 c1+#define c4 : CN := cadd c2 c2+#define c8 : CN := cadd c4 c4+#define c16 : CN := cadd c8 c8+#define c64 : CN := cadd (cadd c16 c16) (cadd c16 c16)++-- 8 * 8 = 64, mul against an addition chain+#define test-mul : cmul c8 c8 = c64 := refl++-- 2 ^ 4 = 16, exp against a doubling chain+#define test-exp : cexp c2 c4 = c16 := refl++-- endpoints as inline applications (regression: these must not be+-- decomposed into the false subgoal 4 =? 16)+#define test-inline : cmul c4 c4 = cadd c8 c8 := refl
+ test/typecheck/cases/happy-set-option-warn-overhang.expect.yaml view
@@ -0,0 +1,4 @@+status: ok+regression_for:+ - warn-overhang-option+ - checkTopeAgainstContext-opt-in-hint
+ test/typecheck/cases/happy-set-option-warn-overhang.rzk view
@@ -0,0 +1,16 @@+#lang rzk-1++-- The overhang hint is opt-in: deciding whether a restriction face or recOR+-- guard overhangs the local tope context costs a solver entailment per face,+-- so it is off by default and enabled with this option. The definition below+-- overhangs (see happy-restrict-face-not-contained); with the option on it+-- still typechecks — the hint is non-fatal — and the option name must be+-- recognised by #set-option and #unset-option.++#set-option "warn-overhang" = "yes"++#define faceOverhang (t : 2 * 2 | first t === 0_2)+ : Unit [ (first t === 0_2) \/ (second t === 0_2) |-> unit ]+ := unit++#unset-option "warn-overhang"
+ test/typecheck/cases/ill-nbe-church-unequal.expect.yaml view
@@ -0,0 +1,5 @@+status: error+error_tag: TypeErrorUnifyTerms+line: 24+regression_for:+ - nbe-conversion-fastpath
+ test/typecheck/cases/ill-nbe-church-unequal.rzk view
@@ -0,0 +1,24 @@+#lang rzk-1++-- A wrong Church-numeral equation must still be rejected: the NbE fast path+-- (Rzk.TypeCheck.NbE) answers only "definitely convertible" or "do not+-- know", so inequality must surface from the ordinary unification.++#define CN : U+ := (X : U) → (X → X) → X → X++#define czero : CN+ := \ X s x → x++#define csucc (n : CN) : CN+ := \ X s x → s (n X s x)++#define cadd (m n : CN) : CN+ := \ X s x → m X s (n X s x)++#define c1 : CN := csucc czero+#define c2 : CN := cadd c1 c1+#define c4 : CN := cadd c2 c2++-- 2 + 2 is not 2+#define test-wrong : cadd c2 c2 = c2 := refl