@@ -22,15 +22,18 @@ import Data.Map qualified as M
2222import Data.Maybe (catMaybes , mapMaybe , isJust )
2323import Data.List.NonEmpty qualified as NEL
2424import Data.Set qualified as S
25+ import Data.Char qualified
2526import Data.Text (Text )
27+ import Data.Text qualified
2628import Data.Traversable (for )
2729import Language.PureScript.Constants.Prim qualified as C
30+ import Language.PureScript.AST.Declarations.ChainId (mkChainId )
2831import Language.PureScript.Crash (internalError )
2932import Language.PureScript.Environment (DataDeclType (.. ), NameKind (.. ), TypeClassData (.. ), dictTypeName , function , makeTypeClassData , primClasses , primCoerceClasses , primIntClasses , primRowClasses , primRowListClasses , primSymbolClasses , primTypeErrorClasses , tyRecord )
3033import Language.PureScript.Errors hiding (isExported , nonEmpty )
3134import Language.PureScript.Externs (ExternsDeclaration (.. ), ExternsFile (.. ))
3235import Language.PureScript.Label (Label (.. ))
33- import Language.PureScript.Names (pattern ByNullSourcePos , Ident (.. ), ModuleName , Name (.. ), ProperName , ProperNameType (.. ), Qualified (.. ), QualifiedBy (.. ), coerceProperName , freshIdent , qualify , runIdent )
36+ import Language.PureScript.Names (pattern ByNullSourcePos , Ident (.. ), ModuleName , Name (.. ), ProperName , ProperNameType (.. ), Qualified (.. ), QualifiedBy (.. ), coerceProperName , freshIdent , qualify , runIdent , runProperName )
3437import Language.PureScript.PSString (mkString )
3538import Language.PureScript.Sugar.CaseDeclarations (desugarCases )
3639import Language.PureScript.TypeClassDictionaries (superclassName )
@@ -228,6 +231,18 @@ desugarDecl mn exps = go
228231 in
229232 return $ ValueDecl sa name' Private [] [MkUnguarded (TypedValue True dict constrainedTy)]
230233 return (expRef name' className tys, [d, dictDecl])
234+ go (DeriveClauseDeclaration sa tyName tyVars className extraArgs) = do
235+ memberMap <- get
236+ let
237+ classKey = case className of
238+ Qualified (ByModuleName clsMn) cn -> (clsMn, cn)
239+ _ -> (mn, let Qualified _ cn = className in cn)
240+ mClassData = M. lookup classKey memberMap
241+ ss = fst sa
242+ chainId = mkChainId (spanName ss) (spanStart ss)
243+ genName = mkDeriveClauseName className
244+ tyConArgs <- computeInstArgs ss mn tyName tyVars mClassData className extraArgs
245+ go $ TypeInstanceDeclaration sa sa chainId 0 (Left genName) [] className tyConArgs DerivedInstance
231246 go other = return (Nothing , [other])
232247
233248 -- Completes the name generation for type class instances that do not have
@@ -267,6 +282,58 @@ desugarDecl mn exps = go
267282 genSpan :: SourceSpan
268283 genSpan = internalModuleSourceSpan " <generated>"
269284
285+ -- | Compute the full instance type arguments for a derive clause.
286+ --
287+ -- With explicit args containing a wildcard (_), the wildcard is replaced
288+ -- with the bare type constructor:
289+ -- derive (Functor _) => Functor MyType
290+ --
291+ -- Without explicit args, the kind of the class's first parameter
292+ -- determines how many type variables to apply. Generic and Newtype
293+ -- additionally get a wildcard for their computed representation type.
294+ computeInstArgs
295+ :: MonadError MultipleErrors m
296+ => SourceSpan
297+ -> ModuleName
298+ -> ProperName 'TypeName
299+ -> [(Text , Maybe SourceType )]
300+ -> Maybe TypeClassData
301+ -> Qualified (ProperName 'ClassName)
302+ -> [SourceType ]
303+ -> m [SourceType ]
304+ computeInstArgs ss mn tyName tyVars mClassData className extraArgs
305+ | _: _ <- extraArgs = pure $ map substWildcard extraArgs
306+ | otherwise = do
307+ let firstParamKind = do
308+ tcd <- mClassData
309+ (_, k) : _ <- pure (typeClassArguments tcd)
310+ k
311+ kindArity <- case firstParamKind of
312+ Just k -> pure $ kindArrowCount k
313+ Nothing -> throwError . errorMessage' ss $ CannotDerive className []
314+ let numVarsToApply = max 0 (length tyVars - kindArity)
315+ pure [foldl srcTypeApp tyCon (take numVarsToApply tyVarTypes)]
316+ where
317+ tyCon = srcTypeConstructor (Qualified (ByModuleName mn) tyName)
318+ tyVarTypes = map (\ (v, _) -> srcTypeVar v) tyVars
319+ substWildcard (TypeWildcard _ _) = tyCon
320+ substWildcard t = t
321+
322+ -- | Count the number of arrows in a kind.
323+ -- Type returns 0, Type -> Type returns 1, etc.
324+ kindArrowCount :: SourceType -> Int
325+ kindArrowCount (TypeApp _ (TypeApp _ (TypeConstructor _ f) _) rest)
326+ | f == C. Function = 1 + kindArrowCount rest
327+ kindArrowCount _ = 0
328+
329+ -- | Generate a name for a derive clause instance
330+ mkDeriveClauseName :: Qualified (ProperName 'ClassName) -> Text
331+ mkDeriveClauseName (Qualified _ cn) = Data.Char. toLower c `Data.Text.cons` cs
332+ where
333+ (c, cs) = case Data.Text. uncons (runProperName cn) of
334+ Just pair -> pair
335+ Nothing -> internalError " Empty class name"
336+
270337memberToNameAndType :: Declaration -> (Ident , SourceType )
271338memberToNameAndType (TypeDeclaration td) = unwrapTypeDeclaration td
272339memberToNameAndType _ = internalError " Invalid declaration in type class definition"
0 commit comments