@@ -5,8 +5,10 @@
6module Language.PureScript.TypeChecker.Entailment
6module Language.PureScript.TypeChecker.Entailment
7 ( InstanceContext
7 ( InstanceContext
8 , replaceTypeClassDictionaries
9 , replaceTypeClassDictionaries
9 , newDictionaries
10 , newDictionaries
12import Prelude.Compat
14import Prelude.Compat
@@ -56,7 +58,7 @@ replaceTypeClassDictionaries
56 . (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadSupply m)
58 . (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadSupply m)
59− -> m (Expr, [(Ident, Constraint)])
61+ -> m (Expr, [(Ident, InstanceContext, Constraint)])
60replaceTypeClassDictionaries shouldGeneralize expr = flip evalStateT M.empty $ do
62replaceTypeClassDictionaries shouldGeneralize expr = flip evalStateT M.empty $ do
61 -- Loop, deferring any unsolved constraints, until there are no more
63 -- Loop, deferring any unsolved constraints, until there are no more
62 -- constraints which can be solved, then make a generalization pass.
64 -- constraints which can be solved, then make a generalization pass.
@@ -70,18 +72,18 @@ replaceTypeClassDictionaries shouldGeneralize expr = flip evalStateT M.empty $ d
70 -- This pass solves constraints where possible, deferring constraints if not.
72 -- This pass solves constraints where possible, deferring constraints if not.
71 deferPass :: Expr -> StateT InstanceContext m (Expr, Any)
73 deferPass :: Expr -> StateT InstanceContext m (Expr, Any)
72 deferPass = fmap (second fst) . runWriterT . f where
74 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
74 (_, f, _) = everywhereOnValuesTopDownM return (go True) return
76 (_, f, _) = everywhereOnValuesTopDownM return (go True) return
76 -- This pass generalizes any remaining constraints
78 -- 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)])
78 generalizePass = fmap (second snd) . runWriterT . f where
80 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
80 (_, f, _) = everywhereOnValuesTopDownM return (go False) return
82 (_, f, _) = everywhereOnValuesTopDownM return (go False) return
82− go :: Bool -> Expr -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) Expr
84+ go :: Bool -> Expr -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
83− go deferErrors dict@(TypeClassDictionary _ _ hints) =
85+ go deferErrors (TypeClassDictionary constraint context hints) =
84− rethrow (addHints hints) $ entails shouldGeneralize deferErrors dict
86+ rethrow (addHints hints) $ entails (SolverOptions shouldGeneralize deferErrors) constraint context hints
85 go _ other = return other
87 go _ other = return other
87-- | Three options for how we can handle a constraint, depending on the mode we're in.
89-- | Three options for how we can handle a constraint, depending on the mode we're in.
@@ -93,18 +95,29 @@ data EntailsResult a
93 | Deferred
95 | Deferred
94 -- ^ We couldn't solve this constraint right now, so it has been deferred
96 -- ^ We couldn't solve this constraint right now, so it has been deferred
96−-- |
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?
97−-- Check that the current set of type class dictionaries entail the specified type class goal, and, if so,
106+-- | Check that the current set of type class dictionaries entail the specified type class goal, and, if so,
98-- return a type class dictionary reference.
107-- return a type class dictionary reference.
101 :: forall m
109 :: forall m
102 . (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadSupply m)
110 . (MonadState CheckState m, MonadError MultipleErrors m, MonadWriter MultipleErrors m, MonadSupply m)
103− => Bool
111+ => SolverOptions
104− -> Bool
112+ -- ^ Solver options
105− -> Expr
113+ -> Constraint
114+ -- ^ The constraint to solve
116+ -- ^ The contexts in which to solve the constraint
117+ -> [ErrorMessageHint]
118+ -- ^ Error message hints to apply to any instance errors
106− -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) Expr
119+ -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
107−entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hints) =
120+entails SolverOptions{..} constraint context hints =
108 solve constraint
121 solve constraint
110 forClassName :: InstanceContext -> Qualified (ProperName 'ClassName) -> [Type] -> [TypeClassDictionaryInScope]
123 forClassName :: InstanceContext -> Qualified (ProperName 'ClassName) -> [Type] -> [TypeClassDictionaryInScope]
@@ -123,10 +136,10 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
123 valUndefined :: Expr
136 valUndefined :: Expr
124 valUndefined = Var (Qualified (Just (ModuleName [ProperName C.prim])) (Ident C.undefined))
137 valUndefined = Var (Qualified (Just (ModuleName [ProperName C.prim])) (Ident C.undefined))
126− solve :: Constraint -> WriterT (Any, [(Ident, Constraint)]) (StateT InstanceContext m) Expr
139+ solve :: Constraint -> WriterT (Any, [(Ident, InstanceContext, Constraint)]) (StateT InstanceContext m) Expr
127 solve con = go 0 con
140 solve con = go 0 con
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
130 go work (Constraint className' tys' _) | work > 1000 = throwError . errorMessage $ PossiblyInfiniteInstance className' tys'
143 go work (Constraint className' tys' _) | work > 1000 = throwError . errorMessage $ PossiblyInfiniteInstance className' tys'
131 go work con'@(Constraint className' tys' conInfo) = WriterT . StateT . (withErrorMessageHint (ErrorSolvingConstraint con') .) . runStateT . runWriterT $ do
144 go work con'@(Constraint className' tys' conInfo) = WriterT . StateT . (withErrorMessageHint (ErrorSolvingConstraint con') .) . runStateT . runWriterT $ do
132 -- We might have unified types by solving other constraints, so we need to
145 -- We might have unified types by solving other constraints, so we need to
@@ -179,7 +192,7 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
179 let newContext = mkContext newDicts
192 let newContext = mkContext newDicts
180 modify (combineContexts newContext)
193 modify (combineContexts newContext)
181 -- Mark this constraint for generalization
194 -- Mark this constraint for generalization
182− tell (mempty, [(ident, unsolved)])
195+ tell (mempty, [(ident, context, unsolved)])
183 return (Var qident)
196 return (Var qident)
184 Deferred ->
197 Deferred ->
185 -- Constraint was deferred, just return the dictionary unchanged,
198 -- Constraint was deferred, just return the dictionary unchanged,
@@ -219,10 +232,10 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
220 unique :: [Type] -> [(a, TypeClassDictionaryInScope)] -> m (EntailsResult a)
233 unique :: [Type] -> [(a, TypeClassDictionaryInScope)] -> m (EntailsResult a)
221 unique tyArgs []
234 unique tyArgs []
222− | deferErrors = return Deferred
235+ | solverDeferErrors = return Deferred
223 -- We need a special case for nullary type classes, since we want
236 -- We need a special case for nullary type classes, since we want
224 -- to generalize over Partial constraints.
237 -- 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))
226 | otherwise = throwError . errorMessage $ NoInstanceFound (Constraint className' tyArgs conInfo)
239 | otherwise = throwError . errorMessage $ NoInstanceFound (Constraint className' tyArgs conInfo)
227 unique _ [(a, dict)] = return $ Solved a dict
240 unique _ [(a, dict)] = return $ Solved a dict
228 unique tyArgs tcds
241 unique tyArgs tcds
@@ -250,7 +263,7 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
250 -- Create dictionaries for subgoals which still need to be solved by calling go recursively
263 -- Create dictionaries for subgoals which still need to be solved by calling go recursively
251 -- E.g. the goal (Show a, Show b) => Show (Either a b) can be satisfied if the current type
264 -- E.g. the goal (Show a, Show b) => Show (Either a b) can be satisfied if the current type
252 -- unifies with Either a b, and we can satisfy the subgoals Show a and Show b recursively.
265 -- 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])
254 solveSubgoals _ Nothing = return Nothing
267 solveSubgoals _ Nothing = return Nothing
255 solveSubgoals subst (Just subgoals) =
268 solveSubgoals subst (Just subgoals) =
256 Just <$> traverse (go (work + 1) . mapConstraintArgs (map (replaceAllTypeVars (M.toList subst)))) subgoals
269 Just <$> traverse (go (work + 1) . mapConstraintArgs (map (replaceAllTypeVars (M.toList subst)))) subgoals
@@ -267,7 +280,6 @@ entails shouldGeneralize deferErrors (TypeClassDictionary constraint context hin
267 App (Accessor (C.__superclass_ ++ showQualified runProperName superclassName ++ "_" ++ show index)
280 App (Accessor (C.__superclass_ ++ showQualified runProperName superclassName ++ "_" ++ show index)
269 valUndefined
282 valUndefined
270−entails _ _ _ = internalError "entails: expected TypeClassDictionary"
272-- Check if an instance matches our list of types, allowing for types
284-- Check if an instance matches our list of types, allowing for types
273-- to be solved via functional dependencies. If the types match, we return a
285-- to be solved via functional dependencies. If the types match, we return a