@@ -5,8 +5,10 @@
55--
66module Language.PureScript.TypeChecker.Entailment
77 ( InstanceContext
8+ , SolverOptions(..)
89 , replaceTypeClassDictionaries
910 , newDictionaries
11+ , entails
1012 ) where
1113
1214import Prelude.Compat
@@ -56,7 +58,7 @@ replaceTypeClassDictionaries
5658 . (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadSupply m)
5759 => Bool
5860 -> Expr
59− -> m (Expr, [(Ident, Constraint)])
61+ -> m (Expr, [(Ident, InstanceContext, Constraint)])
6062replaceTypeClassDictionaries shouldGeneralize expr = flip evalStateT M.empty $ do
6163 -- Loop, deferring any unsolved constraints, until there are no more
6264 -- constraints which can be solved, then make a generalization pass.
@@ -70,18 +72,18 @@ replaceTypeClassDictionaries shouldGeneralize expr = flip evalStateT M.empty $ d
7072 -- This pass solves constraints where possible, deferring constraints if not.
7173 deferPass :: Expr -> StateT InstanceContext m (Expr, Any)
7274 deferPass = fmap (second fst) . runWriterT . f where
73− f :: Expr -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) Expr
75+ f :: Expr -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
7476 (_, f, _) = everywhereOnValuesTopDownM return (go True) return
7577
7678 -- This pass generalizes any remaining constraints
77− generalizePass :: Expr -> StateT InstanceContext m (Expr, [(Ident, Constraint)])
79+ generalizePass :: Expr -> StateT InstanceContext m (Expr, [(Ident, InstanceContext, Constraint)])
7880 generalizePass = fmap (second snd) . runWriterT . f where
79− f :: Expr -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) Expr
81+ f :: Expr -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
8082 (_, f, _) = everywhereOnValuesTopDownM return (go False) return
8183
82− go :: Bool -> Expr -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) Expr
83− go deferErrors dict@(TypeClassDictionary _ _ hints) =
84− rethrow (addHints hints) $ entails shouldGeneralize deferErrors dict
84+ go :: Bool -> Expr -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
85+ go deferErrors (TypeClassDictionary constraint context hints) =
86+ rethrow (addHints hints) $ entails (SolverOptions shouldGeneralize deferErrors) constraint context hints
8587 go _ other = return other
8688
8789-- | Three options for how we can handle a constraint, depending on the mode we're in.
@@ -93,18 +95,29 @@ data EntailsResult a
9395 | Deferred
9496 -- ^ We couldn't solve this constraint right now, so it has been deferred
9597
96−-- |
97−-- Check that the current set of type class dictionaries entail the specified type class goal, and, if so,
98+-- | Options for the constraint solver
99+data SolverOptions = SolverOptions
100+ { solverShouldGeneralize :: Bool
101+ -- ^ Should the solver be allowed to generalize over unsolved constraints?
102+ , solverDeferErrors :: Bool
103+ -- ^ Should the solver be allowed to defer errors by skipping constraints?
104+ }
105+
106+-- | Check that the current set of type class dictionaries entail the specified type class goal, and, if so,
98107-- return a type class dictionary reference.
99−--
100108entails
101109 :: forall m
102110 . (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadSupply m)
103− => Bool
104− -> Bool
105− -> Expr
106− -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) Expr
107−entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hints) =
111+ => SolverOptions
112+ -- ^ Solver options
113+ -> Constraint
114+ -- ^ The constraint to solve
115+ -> InstanceContext
116+ -- ^ The contexts in which to solve the constraint
117+ -> [ErrorMessageHint]
118+ -- ^ Error message hints to apply to any instance errors
119+ -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
120+entails SolverOptions{..} constraint context hints =
108121 solve constraint
109122 where
110123 forClassName :: InstanceContext -> Qualified (ProperName 'ClassName) -> [Type] -> [TypeClassDictionaryInScope]
@@ -123,10 +136,10 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
123136 valUndefined :: Expr
124137 valUndefined = Var (Qualified (Just (ModuleName [ProperName C.prim])) (Ident C.undefined))
125138
126− solve :: Constraint -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) Expr
139+ solve :: Constraint -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
127140 solve con = go 0 con
128141 where
129− go :: Int -> Constraint -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) Expr
142+ go :: Int -> Constraint -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
130143 go work (Constraint className' tys' _) | work > 1000 = throwError . errorMessage $ PossiblyInfiniteInstance className' tys'
131144 go work con'@(Constraint className' tys' conInfo) = WriterT . StateT . (withErrorMessageHint (ErrorSolvingConstraint con') .) . runStateT . runWriterT $ do
132145 -- We might have unified types by solving other constraints, so we need to
@@ -179,7 +192,7 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
179192 let newContext = mkContext newDicts
180193 modify (combineContexts newContext)
181194 -- Mark this constraint for generalization
182− tell (mempty, [(ident, unsolved)])
195+ tell (mempty, [(ident, context, unsolved)])
183196 return (Var qident)
184197 Deferred ->
185198 -- Constraint was deferred, just return the dictionary unchanged,
@@ -219,10 +232,10 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
219232
220233 unique :: [Type] -> [(a, TypeClassDictionaryInScope)] -> m (EntailsResult a)
221234 unique tyArgs []
222− | deferErrors = return Deferred
235+ | solverDeferErrors = return Deferred
223236 -- We need a special case for nullary type classes, since we want
224237 -- to generalize over Partial constraints.
225− | shouldGeneralize && (null tyArgs || any canBeGeneralized tyArgs) = return (Unsolved (Constraint className' tyArgs conInfo))
238+ | solverShouldGeneralize && (null tyArgs || any canBeGeneralized tyArgs) = return (Unsolved (Constraint className' tyArgs conInfo))
226239 | otherwise = throwError . errorMessage $ NoInstanceFound (Constraint className' tyArgs conInfo)
227240 unique _ [(a, dict)] = return $ Solved a dict
228241 unique tyArgs tcds
@@ -250,7 +263,7 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
250263 -- Create dictionaries for subgoals which still need to be solved by calling go recursively
251264 -- E.g. the goal (Show a, Show b) => Show (Either a b) can be satisfied if the current type
252265 -- unifies with Either a b, and we can satisfy the subgoals Show a and Show b recursively.
253− solveSubgoals :: Matching Type -> Maybe [Constraint] -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) (Maybe [Expr])
266+ solveSubgoals :: Matching Type -> Maybe [Constraint] -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) (Maybe [Expr])
254267 solveSubgoals _ Nothing = return Nothing
255268 solveSubgoals subst (Just subgoals) =
256269 Just <$> traverse (go (work + 1) . mapConstraintArgs (map (replaceAllTypeVars (M.toList subst)))) subgoals
@@ -267,7 +280,6 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
267280 App (Accessor (C.__superclass_ ++ showQualified runProperName superclassName ++ "_" ++ show index)
268281 dict)
269282 valUndefined
270−entails _ _ _ = internalError "entails: expected TypeClassDictionary"
271283
272284-- Check if an instance matches our list of types, allowing for types
273285-- to be solved via functional dependencies. If the types match, we return a