@@ -19,7 +19,7 @@ import Control.Monad.State
19import Control.Monad.Supply.Class (MonadSupply(..))
19import Control.Monad.Supply.Class (MonadSupply(..))
20import Control.Monad.Writer
20import Control.Monad.Writer
22−import Data.Foldable (for_)
22+import Data.Foldable (for_, fold, toList)
23import Data.Function (on)
23import Data.Function (on)
24import Data.List (minimumBy, nub)
24import Data.List (minimumBy, nub)
25import Data.Maybe (fromMaybe, maybeToList, mapMaybe)
25import Data.Maybe (fromMaybe, maybeToList, mapMaybe)
@@ -37,11 +37,26 @@ import Language.PureScript.TypeClassDictionaries
37import Language.PureScript.Types
37import Language.PureScript.Types
38import qualified Language.PureScript.Constants as C
38import qualified Language.PureScript.Constants as C
40+-- | Describes what sort of dictionary to generate for type class instances
42+ = NamedInstance (Qualified Ident)
43+ -- ^ An existing named instance
44+ | IsSymbolInstance String
45+ -- ^ Computed instance of the IsSymbol type class for a given Symbol literal
48+-- | Extract the identifier of a named instance
49+namedInstanceIdentifier :: Evidence -> Maybe (Qualified Ident)
50+namedInstanceIdentifier (NamedInstance i) = Just i
51+namedInstanceIdentifier _ = Nothing
53+-- | Description of a type class dictionary with instance evidence
54+type TypeClassDict = TypeClassDictionaryInScope Evidence
40-- | The 'InstanceContext' tracks those constraints which can be satisfied.
56-- | The 'InstanceContext' tracks those constraints which can be satisfied.
41type InstanceContext = M.Map (Maybe ModuleName)
57type InstanceContext = M.Map (Maybe ModuleName)
42 (M.Map (Qualified (ProperName 'ClassName))
58 (M.Map (Qualified (ProperName 'ClassName))
43− (M.Map (Qualified Ident)
59+ (M.Map (Qualified Ident) NamedDict))
44− TypeClassDictionaryInScope))
46-- | A type substitution which makes an instance head match a list of types.
61-- | A type substitution which makes an instance head match a list of types.
@@ -88,7 +103,7 @@ replaceTypeClassDictionaries shouldGeneralize expr = flip evalStateT M.empty $ d
89-- | Three options for how we can handle a constraint, depending on the mode we're in.
104-- | Three options for how we can handle a constraint, depending on the mode we're in.
90data EntailsResult a
105data EntailsResult a
91− = Solved a TypeClassDictionaryInScope
106+ = Solved a TypeClassDict
92 -- ^ We solved this constraint
107 -- ^ We solved this constraint
93 | Unsolved Constraint
108 | Unsolved Constraint
94 -- ^ We couldn't solve this constraint right now, it will be generalized
109 -- ^ We couldn't solve this constraint right now, it will be generalized
@@ -120,7 +135,8 @@ entails
120entails SolverOptions{..} constraint context hints =
135entails SolverOptions{..} constraint context hints =
121 solve constraint
136 solve constraint
123− forClassName :: InstanceContext -> Qualified (ProperName 'ClassName) -> [Type] -> [TypeClassDictionaryInScope]
138+ forClassName :: InstanceContext -> Qualified (ProperName 'ClassName) -> [Type] -> [TypeClassDict]
139+ forClassName _ C.IsSymbol [TypeLevelString sym] = [TypeClassDictionaryInScope (IsSymbolInstance sym) [] C.IsSymbol [TypeLevelString sym] Nothing]
124 forClassName ctx cn@(Qualified (Just mn) _) tys = concatMap (findDicts ctx cn) (nub (Nothing : Just mn : map Just (mapMaybe ctorModules tys)))
140 forClassName ctx cn@(Qualified (Just mn) _) tys = concatMap (findDicts ctx cn) (nub (Nothing : Just mn : map Just (mapMaybe ctorModules tys)))
125 forClassName _ _ _ = internalError "forClassName: expected qualified class name"
141 forClassName _ _ _ = internalError "forClassName: expected qualified class name"
@@ -130,8 +146,8 @@ entails SolverOptions{..} constraint context hints =
130 ctorModules (TypeApp ty _) = ctorModules ty
146 ctorModules (TypeApp ty _) = ctorModules ty
131 ctorModules _ = Nothing
147 ctorModules _ = Nothing
133− findDicts :: InstanceContext -> Qualified (ProperName 'ClassName) -> Maybe ModuleName -> [TypeClassDictionaryInScope]
149+ findDicts :: InstanceContext -> Qualified (ProperName 'ClassName) -> Maybe ModuleName -> [TypeClassDict]
134− findDicts ctx cn = maybe [] M.elems . (>>= M.lookup cn) . flip M.lookup ctx
150+ findDicts ctx cn = fmap (fmap NamedInstance) . maybe [] M.elems . (>>= M.lookup cn) . flip M.lookup ctx
136 valUndefined :: Expr
152 valUndefined :: Expr
137 valUndefined = Var (Qualified (Just (ModuleName [ProperName C.prim])) (Ident C.undefined))
153 valUndefined = Var (Qualified (Just (ModuleName [ProperName C.prim])) (Ident C.undefined))
@@ -181,7 +197,7 @@ entails SolverOptions{..} constraint context hints =
181 -- Solve any necessary subgoals
197 -- Solve any necessary subgoals
182 args <- solveSubgoals subst'' (tcdDependencies tcd)
198 args <- solveSubgoals subst'' (tcdDependencies tcd)
183 let match = foldr (\(superclassName, index) dict -> subclassDictionaryValue dict superclassName index)
199 let match = foldr (\(superclassName, index) dict -> subclassDictionaryValue dict superclassName index)
184− (mkDictionary (tcdName tcd) args)
200+ (mkDictionary (tcdValue tcd) args)
185 (tcdPath tcd)
201 (tcdPath tcd)
186 return match
202 return match
187 Unsolved unsolved -> do
203 Unsolved unsolved -> do
@@ -213,7 +229,7 @@ entails SolverOptions{..} constraint context hints =
213 -- fresh type variables. This function extends a substitution with fresh type variables
229 -- fresh type variables. This function extends a substitution with fresh type variables
214 -- as necessary, based on the types in the instance head.
230 -- as necessary, based on the types in the instance head.
215 withFreshTypes
231 withFreshTypes
216− :: TypeClassDictionaryInScope
232+ :: TypeClassDict
217 -> Matching Type
233 -> Matching Type
218 -> m (Matching Type)
234 -> m (Matching Type)
219 withFreshTypes TypeClassDictionaryInScope{..} subst = do
235 withFreshTypes TypeClassDictionaryInScope{..} subst = do
@@ -232,7 +248,7 @@ entails SolverOptions{..} constraint context hints =
232 t <- freshType
248 t <- freshType
233 return (s, t)
249 return (s, t)
235− unique :: [Type] -> [(a, TypeClassDictionaryInScope)] -> m (EntailsResult a)
251+ unique :: [Type] -> [(a, TypeClassDict)] -> m (EntailsResult a)
236 unique tyArgs []
252 unique tyArgs []
237 | solverDeferErrors = return Deferred
253 | solverDeferErrors = return Deferred
238 -- We need a special case for nullary type classes, since we want
254 -- We need a special case for nullary type classes, since we want
@@ -242,7 +258,7 @@ entails SolverOptions{..} constraint context hints =
242 unique _ [(a, dict)] = return $ Solved a dict
258 unique _ [(a, dict)] = return $ Solved a dict
243 unique tyArgs tcds
259 unique tyArgs tcds
244 | pairwiseAny overlapping (map snd tcds) = do
260 | pairwiseAny overlapping (map snd tcds) = do
245− tell . errorMessage $ OverlappingInstances className' tyArgs (map (tcdName . snd) tcds)
261+ tell . errorMessage $ OverlappingInstances className' tyArgs (tcds >>= (toList . namedInstanceIdentifier . tcdValue . snd))
246 return $ uncurry Solved (head tcds)
262 return $ uncurry Solved (head tcds)
247 | otherwise = return $ uncurry Solved (minimumBy (compare `on` length . tcdPath . snd) tcds)
263 | otherwise = return $ uncurry Solved (minimumBy (compare `on` length . tcdPath . snd) tcds)
@@ -255,12 +271,12 @@ entails SolverOptions{..} constraint context hints =
256 -- Dictionaries which are subclass dictionaries cannot overlap, since otherwise the overlap would have
272 -- Dictionaries which are subclass dictionaries cannot overlap, since otherwise the overlap would have
257 -- been caught when constructing superclass dictionaries.
273 -- been caught when constructing superclass dictionaries.
258− overlapping :: TypeClassDictionaryInScope -> TypeClassDictionaryInScope -> Bool
274+ overlapping :: TypeClassDict -> TypeClassDict -> Bool
259 overlapping TypeClassDictionaryInScope{ tcdPath = _ : _ } _ = False
275 overlapping TypeClassDictionaryInScope{ tcdPath = _ : _ } _ = False
260 overlapping _ TypeClassDictionaryInScope{ tcdPath = _ : _ } = False
276 overlapping _ TypeClassDictionaryInScope{ tcdPath = _ : _ } = False
261 overlapping TypeClassDictionaryInScope{ tcdDependencies = Nothing } _ = False
277 overlapping TypeClassDictionaryInScope{ tcdDependencies = Nothing } _ = False
262 overlapping _ TypeClassDictionaryInScope{ tcdDependencies = Nothing } = False
278 overlapping _ TypeClassDictionaryInScope{ tcdDependencies = Nothing } = False
263− overlapping tcd1 tcd2 = tcdName tcd1 /= tcdName tcd2
279+ overlapping tcd1 tcd2 = tcdValue tcd1 /= tcdValue tcd2
265 -- Create dictionaries for subgoals which still need to be solved by calling go recursively
281 -- Create dictionaries for subgoals which still need to be solved by calling go recursively
266 -- E.g. the goal (Show a, Show b) => Show (Either a b) can be satisfied if the current type
282 -- E.g. the goal (Show a, Show b) => Show (Either a b) can be satisfied if the current type
@@ -271,10 +287,11 @@ entails SolverOptions{..} constraint context hints =
271 Just <$> traverse (go (work + 1) . mapConstraintArgs (map (replaceAllTypeVars (M.toList subst)))) subgoals
287 Just <$> traverse (go (work + 1) . mapConstraintArgs (map (replaceAllTypeVars (M.toList subst)))) subgoals
273 -- Make a dictionary from subgoal dictionaries by applying the correct function
289 -- Make a dictionary from subgoal dictionaries by applying the correct function
274− mkDictionary :: Qualified Ident -> Maybe [Expr] -> Expr
290+ mkDictionary :: Evidence -> Maybe [Expr] -> Expr
275− mkDictionary fnName Nothing = Var fnName
291+ mkDictionary (NamedInstance n) args = foldl App (Var n) (fold args)
276− mkDictionary fnName (Just []) = Var fnName
292+ mkDictionary (IsSymbolInstance sym) _ = TypeClassDictionaryConstructorApp C.IsSymbol (Literal (ObjectLiteral fields)) where
277− mkDictionary fnName (Just dicts) = foldl App (Var fnName) dicts
293+ fields = [ ("reflectSymbol", Abs (Left (Ident C.__unused)) (Literal (StringLiteral sym)))
279 -- Turn a DictionaryValue into a Expr
296 -- Turn a DictionaryValue into a Expr
280 subclassDictionaryValue :: Expr -> Qualified (ProperName a) -> Integer -> Expr
297 subclassDictionaryValue :: Expr -> Qualified (ProperName a) -> Integer -> Expr
@@ -286,7 +303,7 @@ entails SolverOptions{..} constraint context hints =
286-- Check if an instance matches our list of types, allowing for types
303-- Check if an instance matches our list of types, allowing for types
287-- to be solved via functional dependencies. If the types match, we return a
304-- to be solved via functional dependencies. If the types match, we return a
288-- substitution which makes them match. If not, we return 'Nothing'.
305-- substitution which makes them match. If not, we return 'Nothing'.
289−matches :: [FunctionalDependency] -> TypeClassDictionaryInScope -> [Type] -> Maybe (Matching [Type])
306+matches :: [FunctionalDependency] -> TypeClassDict -> [Type] -> Maybe (Matching [Type])
290matches deps TypeClassDictionaryInScope{..} tys = do
307matches deps TypeClassDictionaryInScope{..} tys = do
291 -- First, find those types which match exactly
308 -- First, find those types which match exactly
292 let matched = zipWith typeHeadsAreEqual tys tcdInstanceTypes
309 let matched = zipWith typeHeadsAreEqual tys tcdInstanceTypes
@@ -402,7 +419,7 @@ newDictionaries
402 => [(Qualified (ProperName 'ClassName), Integer)]
419 => [(Qualified (ProperName 'ClassName), Integer)]
403 -> Qualified Ident
420 -> Qualified Ident
404 -> Constraint
421 -> Constraint
405− -> m [TypeClassDictionaryInScope]
422+ -> m [NamedDict]
406newDictionaries path name (Constraint className instanceTy _) = do
423newDictionaries path name (Constraint className instanceTy _) = do
407 tcs <- gets (typeClasses . checkEnv)
424 tcs <- gets (typeClasses . checkEnv)
408 let TypeClassData{..} = fromMaybe (internalError "newDictionaries: type class lookup failed") $ M.lookup className tcs
425 let TypeClassData{..} = fromMaybe (internalError "newDictionaries: type class lookup failed") $ M.lookup className tcs
@@ -416,9 +433,9 @@ newDictionaries path name (Constraint className instanceTy _) = do
416 instantiateSuperclass :: [String] -> [Type] -> [Type] -> [Type]
433 instantiateSuperclass :: [String] -> [Type] -> [Type] -> [Type]
417 instantiateSuperclass args supArgs tys = map (replaceAllTypeVars (zip args tys)) supArgs
434 instantiateSuperclass args supArgs tys = map (replaceAllTypeVars (zip args tys)) supArgs
419−mkContext :: [TypeClassDictionaryInScope] -> InstanceContext
436+mkContext :: [NamedDict] -> InstanceContext
420mkContext = foldr combineContexts M.empty . map fromDict where
437mkContext = foldr combineContexts M.empty . map fromDict where
421− fromDict d = M.singleton Nothing (M.singleton (tcdClassName d) (M.singleton (tcdName d) d))
438+ fromDict d = M.singleton Nothing (M.singleton (tcdClassName d) (M.singleton (tcdValue d) d))
423-- | Check all pairs of values in a list match a predicate
440-- | Check all pairs of values in a list match a predicate
424pairwiseAll :: (a -> a -> Bool) -> [a] -> Bool
441pairwiseAll :: (a -> a -> Bool) -> [a] -> Bool