@@ -5,6 +5,7 @@ module Tix.Typechecker
5 runSeqWriter,
5 runSeqWriter,
@@ -15,13 +16,14 @@ import Control.Monad.Freer.Reader
15import Control.Monad.Freer.State
16import Control.Monad.Freer.State
16import Control.Monad.Freer.Writer
17import Control.Monad.Freer.Writer
17import Data.Act
18import Data.Act
19+import qualified Data.Aeson as A
18import Data.Fix
20import Data.Fix
19import Data.Foldable
21import Data.Foldable
20import Data.Functor
22import Data.Functor
21import Data.Group hiding ((~~))
23import Data.Group hiding ((~~))
24+import qualified Data.HashMap.Strict as HM
22import Data.List.NonEmpty (NonEmpty (..))
25import Data.List.NonEmpty (NonEmpty (..))
23import qualified Data.List.NonEmpty as NE
26import qualified Data.List.NonEmpty as NE
24−import qualified Data.Map.Extra as M
25import Data.Map.Shifted.Strict (ShiftedMap (..))
27import Data.Map.Shifted.Strict (ShiftedMap (..))
26import qualified Data.Map.Shifted.Strict as SM
28import qualified Data.Map.Shifted.Strict as SM
27import Data.Map.Strict (Map)
29import Data.Map.Strict (Map)
@@ -37,9 +39,13 @@ import qualified Data.Set as S
37import Data.Text (Text)
39import Data.Text (Text)
38import qualified Data.Text.Lazy as TL
40import qualified Data.Text.Lazy as TL
39import qualified Data.Text.Lazy.Builder as T
41import qualified Data.Text.Lazy.Builder as T
42+import Data.Text.Prettyprint.Doc as P
43+import Data.Text.Prettyprint.Doc.Render.Text
40import Data.Traversable
44import Data.Traversable
45+import qualified Data.Vector as V
41import Nix.Atoms
46import Nix.Atoms
42import Nix.Expr
47import Nix.Expr
44runConstraintEnv ::
50runConstraintEnv ::
45 Eff (SubstituteEnv : Writer Substitution : Writer Constraint : State (Seq Constraint) : effs) a ->
51 Eff (SubstituteEnv : Writer Substitution : Writer Constraint : State (Seq Constraint) : effs) a ->
@@ -55,9 +61,9 @@ runConstraintEnv =
58−getType :: NExprLoc -> (NType, [(SrcSpan, Errors)], [UnifyingError])
64+getType :: NExprLoc -> (NType, [(SrcSpan, Errors)], [UnifyingError], A.Object)
59getType r =
65getType r =
60− let (((((t, unifying), errs), srcs), subs), _) =
66+ let ((((((t, traceTree), unifying), errs), srcs), subs), _) =
62 . runConstraintEnv
68 . runConstraintEnv
63 . runState @[(TypeVariable, SrcSpan)] []
69 . runState @[(TypeVariable, SrcSpan)] []
@@ -66,8 +72,9 @@ getType r =
66 . runSeqWriter @[UnifyingError]
72 . runSeqWriter @[UnifyingError]
67 . runReader (M.empty :: VariableMap)
73 . runReader (M.empty :: VariableMap)
68 . runFresh
74 . runFresh
69 $ inferGeneral r
76 $ inferGeneral r
70− in (sub subs t, errs, unifying)
77+ in (sub subs t, errs, unifying, traceTree)
72data SubstituteEnv a where
79data SubstituteEnv a where
73 SubstituteEnv :: Substitution -> SubstituteEnv ()
80 SubstituteEnv :: Substitution -> SubstituteEnv ()
@@ -84,6 +91,9 @@ instance Show TypeVariable where
84data Constraint = !NType :~ !NType
91data Constraint = !NType :~ !NType
85 deriving stock (Eq, Ord, Show)
92 deriving stock (Eq, Ord, Show)
94+instance Pretty Constraint where
95+ pretty (x :~ y) = pretty x <+> "~" <+> pretty y
87data DeBrujin = DeBrujin !Int !Int
97data DeBrujin = DeBrujin !Int !Int
88 deriving stock (Show, Eq, Ord)
98 deriving stock (Show, Eq, Ord)
@@ -240,9 +250,32 @@ instance Free NType where
240 free (NAttrSet attrs) = foldMap free . M.elems $ attrs
250 free (NAttrSet attrs) = foldMap free . M.elems $ attrs
241 free (x :-> y) = free x <> free y
251 free (x :-> y) = free x <> free y
253+instance Pretty NType where
254+ pretty (NTypeVariable t) = pretty $ prettyTypeVariable t
255+ pretty (NBrujin (DeBrujin i j)) = "⟦" <> pretty i <+> pretty j <> "⟧"
256+ pretty (NAtomic a) = viaShow a
257+ pretty (x :-> y) = sep [pretty x, "->" <+> pretty y]
258+ pretty (List x) = "[" <> align (pretty x) <> "]"
259+ pretty (NAttrSet x) =
263+ ( sep . zipWith (<+>) ("" : repeat ";")
264+ . map (\(k, v) -> pretty k <+> "=" <+> align (pretty v))
243newtype Substitution = Substitution {unSubstitution :: Map TypeVariable NType}
270newtype Substitution = Substitution {unSubstitution :: Map TypeVariable NType}
244 deriving newtype (Eq, Ord, Show)
271 deriving newtype (Eq, Ord, Show)
273+prettyTypeVariable :: TypeVariable -> TL.Text
274+prettyTypeVariable (TypeVariable n) = "⟦" <> (TL.pack . show) n <> "⟧"
276+prettySubstitution :: Substitution -> A.Value
277+prettySubstitution = A.toJSON . M.mapKeysMonotonic prettyTypeVariable . fmap renderPretty . unSubstitution
246-- | Prefers the left
279-- | Prefers the left
247instance Semigroup Substitution where
280instance Semigroup Substitution where
248 x'@(Substitution x) <> (Substitution y) = Substitution (x <> fmap (sub x') y)
281 x'@(Substitution x) <> (Substitution y) = Substitution (x <> fmap (sub x') y)
@@ -375,7 +408,8 @@ type InferEffs =
375 Writer (SrcSpan, Errors),
408 Writer (SrcSpan, Errors),
376 Reader VariableMap,
409 Reader VariableMap,
377 Writer UnifyingError,
410 Writer UnifyingError,
378− SubstituteEnv
411+ SubstituteEnv,
381type InferM x = forall r. Members InferEffs r => Eff r x
415type InferM x = forall r. Members InferEffs r => Eff r x
@@ -580,15 +614,29 @@ inferBinding bindings = do
580-- (_ : (x, _) : _) -> traceM $ x <> " " <> s <> " \t" <> show a
614-- (_ : (x, _) : _) -> traceM $ x <> " " <> s <> " \t" <> show a
581-- _ -> traceM $ s <> " \t" <> show a
615-- _ -> traceM $ s <> " \t" <> show a
617+renderPretty :: Pretty x => x -> TL.Text
618+renderPretty = renderLazy . layoutPretty defaultLayoutOptions . pretty
620+showExpr :: Fix NExprLocF -> Text
621+showExpr = TL.toStrict . renderLazy . layoutPretty defaultLayoutOptions . P.group . prettyNix . stripAnnotation
583inferGeneral :: NExprLoc -> InferM NType
623inferGeneral :: NExprLoc -> InferM NType
584−inferGeneral x = do
624+inferGeneral x = traceSubtree (showExpr x) $ do
625+ (((t, subs), cs), range) <-
585− (((t, subs), cs), range) <- registerTypeVariables . runConstraintEnv $ infer x
626+ traceSubtree "subexpressions" . registerTypeVariables . runConstraintEnv $ infer x
627+ traceValue "received_type" $ renderPretty t
628+ traceValue "received_substitutions" $ prettySubstitution subs
629+ traceValue "received_constraints" $ fmap renderPretty cs
586 s' <- solveWithPriority range cs
630 s' <- solveWithPriority range cs
631+ traceValue "substitutions_after_solving" $ prettySubstitution s'
587 let s = subs <> s'
632 let s = subs <> s'
588 returnedS = Substitution . M.filterWithKey (\k _ -> k `R.notMember` range) . unSubstitution $ s
633 returnedS = Substitution . M.filterWithKey (\k _ -> k `R.notMember` range) . unSubstitution $ s
634+ traceValue "returned_substitutions" $ prettySubstitution returnedS
589 -- Filter for optimization purposes
635 -- Filter for optimization purposes
590 subEnv returnedS
636 subEnv returnedS
591− return . close range $ sub s t
637+ let retT = close range $ sub s t
638+ traceValue "returned_type" $ renderPretty retT
593expectAttrSet :: Members '[Reader SrcSpan, Writer (SrcSpan, Errors)] r => NType -> Eff r VariableMap
641expectAttrSet :: Members '[Reader SrcSpan, Writer (SrcSpan, Errors)] r => NType -> Eff r VariableMap
594expectAttrSet (NAttrSet x) = return x
642expectAttrSet (NAttrSet x) = return x
@@ -676,3 +724,26 @@ lookupAttrSet path = go (NE.toList path)
676 expectAttrSet x <&> M.lookup p >>= \case
724 expectAttrSet x <&> M.lookup p >>= \case
677 Nothing -> NTypeVariable <$> throwSrcTV (KeyNotPresent p)
725 Nothing -> NTypeVariable <$> throwSrcTV (KeyNotPresent p)
678 Just t -> go ps t
726 Just t -> go ps t
728+data TreeTracer a where
729+ TraceTree :: A.Object -> TreeTracer ()
731+traceValue :: (A.ToJSON v, Member TreeTracer eff) => Text -> v -> Eff eff ()
732+traceValue k v = send $ TraceTree $ k A..= v
734+traceSubtree :: Member TreeTracer eff => Text -> Eff eff a -> Eff eff a
735+traceSubtree k = interpose (\(TraceTree o) -> send $ TraceTree (k A..= o))
737+runTreeTracer :: Eff (TreeTracer ': eff) a -> Eff eff (a, A.Object)
738+runTreeTracer = handleRelayS HM.empty (\s x -> pure (x, s)) $ \s (TraceTree o) k ->
739+ k (HM.unionWith unionToList s o) ()
741+ unionToList :: A.Value -> A.Value -> A.Value
742+ unionToList (A.Array x) (A.Array y) = A.Array $ x <> y
743+ unionToList (A.Array x) y = A.Array $ V.snoc x y
744+ unionToList x (A.Array y) = A.Array $ V.cons x y
745+ unionToList (A.Object x) (A.Object y) = A.Object $ HM.unionWith unionToList x y
746+ unionToList x y = A.Array $ V.fromList [x, y]
748+runNoTreeTracer :: Eff (TreeTracer ': eff) a -> Eff eff a
749+runNoTreeTracer = interpret (\(TraceTree _) -> return ())