diff --git a/examples/passing/DerivingFunctor.purs b/examples/passing/DerivingFunctor.purs index bd40cac9f2..765564bb91 100644 --- a/examples/passing/DerivingFunctor.purs +++ b/examples/passing/DerivingFunctor.purs @@ -1,6 +1,7 @@ module Main where import Prelude +import Data.Eq (class Eq1) import Control.Monad.Eff.Console (log) import Test.Assert @@ -13,7 +14,7 @@ data M f a | M3 { foo :: Int, bar :: a, baz :: f a } | M4 (MyRecord a) -derive instance eqM :: (Eq (f a), Eq a) => Eq (M f a) +derive instance eqM :: (Eq1 f, Eq a) => Eq (M f a) derive instance functorM :: Functor f => Functor (M f) @@ -24,5 +25,5 @@ main = do assert $ map show (M1 0 :: MA Int) == M1 0 assert $ map show (M2 [0, 1] :: MA Int) == M2 ["0", "1"] assert $ map show (M3 {foo: 0, bar: 1, baz: [2, 3]} :: MA Int) == M3 {foo: 0, bar: "1", baz: ["2", "3"]} - assert $ map show (M4 { myField: 42 }) == M4 { myField: "42" } :: MA String + assert $ map show (M4 { myField: 42 }) == M4 { myField: "42" } :: MA String log "Done" diff --git a/examples/passing/Eq1Deriving.purs b/examples/passing/Eq1Deriving.purs new file mode 100644 index 0000000000..52ff900b8f --- /dev/null +++ b/examples/passing/Eq1Deriving.purs @@ -0,0 +1,12 @@ +module Main where + +import Prelude +import Data.Eq (class Eq1) +import Control.Monad.Eff.Console (log) + +data Product a b = Product a b + +derive instance eqMu :: (Eq a, Eq b) => Eq (Product a b) +derive instance eq1Mu :: Eq a => Eq1 (Product a) + +main = log "Done" diff --git a/examples/passing/Eq1InEqDeriving.purs b/examples/passing/Eq1InEqDeriving.purs new file mode 100644 index 0000000000..a916c87804 --- /dev/null +++ b/examples/passing/Eq1InEqDeriving.purs @@ -0,0 +1,11 @@ +module Main where + +import Prelude +import Data.Eq (class Eq1) +import Control.Monad.Eff.Console (log) + +newtype Mu f = In (f (Mu f)) + +derive instance eqMu :: Eq1 f => Eq (Mu f) + +main = log "Done" diff --git a/examples/passing/Ord1Deriving.purs b/examples/passing/Ord1Deriving.purs new file mode 100644 index 0000000000..88a6394c2b --- /dev/null +++ b/examples/passing/Ord1Deriving.purs @@ -0,0 +1,16 @@ +module Main where + +import Prelude +import Data.Eq (class Eq1) +import Data.Ord (class Ord1) +import Control.Monad.Eff.Console (log) + +data Product a b = Product a b + +derive instance eqMu :: (Eq a, Eq b) => Eq (Product a b) +derive instance eq1Mu :: Eq a => Eq1 (Product a) + +derive instance ordMu :: (Ord a, Ord b) => Ord (Product a b) +derive instance ord1Mu :: Ord a => Ord1 (Product a) + +main = log "Done" diff --git a/examples/passing/Ord1InOrdDeriving.purs b/examples/passing/Ord1InOrdDeriving.purs new file mode 100644 index 0000000000..00ae1ca997 --- /dev/null +++ b/examples/passing/Ord1InOrdDeriving.purs @@ -0,0 +1,13 @@ +module Main where + +import Prelude +import Data.Eq (class Eq1) +import Data.Ord (class Ord1) +import Control.Monad.Eff.Console (log) + +newtype Mu f = In (f (Mu f)) + +derive instance eqMu :: Eq1 f => Eq (Mu f) +derive instance ordMu :: Ord1 f => Ord (Mu f) + +main = log "Done" diff --git a/src/Language/PureScript/Constants.hs b/src/Language/PureScript/Constants.hs index 3703e07bf1..cd5c8902d5 100644 --- a/src/Language/PureScript/Constants.hs +++ b/src/Language/PureScript/Constants.hs @@ -100,6 +100,9 @@ greaterThanOrEq = "greaterThanOrEq" eq :: forall a. (IsString a) => a eq = "eq" +eq1 :: forall a. (IsString a) => a +eq1 = "eq1" + (/=) :: forall a. (IsString a) => a (/=) = "/=" @@ -109,6 +112,9 @@ notEq = "notEq" compare :: forall a. (IsString a) => a compare = "compare" +compare1 :: forall a. (IsString a) => a +compare1 = "compare1" + (&&) :: forall a. (IsString a) => a (&&) = "&&" diff --git a/src/Language/PureScript/Sugar/TypeClasses/Deriving.hs b/src/Language/PureScript/Sugar/TypeClasses/Deriving.hs index 27fcf75393..279785c0f0 100755 --- a/src/Language/PureScript/Sugar/TypeClasses/Deriving.hs +++ b/src/Language/PureScript/Sugar/TypeClasses/Deriving.hs @@ -121,6 +121,13 @@ deriveInstance mn syns _ ds (TypeInstanceDeclaration sa@(ss, _) ch idx nm deps c -> TypeInstanceDeclaration sa ch idx nm deps className tys . ExplicitInstance <$> deriveEq ss mn syns ds tyCon | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys ty _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 1 + | className == Qualified (Just dataEq) (ProperName "Eq1") + = case tys of + [ty] | Just (Qualified mn' _, _) <- unwrapTypeConstructor ty + , mn == fromMaybe mn mn' + -> pure . TypeInstanceDeclaration sa ch idx nm deps className tys . ExplicitInstance $ deriveEq1 ss + | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys ty + _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 1 | className == Qualified (Just dataOrd) (ProperName "Ord") = case tys of [ty] | Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty @@ -128,6 +135,13 @@ deriveInstance mn syns _ ds (TypeInstanceDeclaration sa@(ss, _) ch idx nm deps c -> TypeInstanceDeclaration sa ch idx nm deps className tys . ExplicitInstance <$> deriveOrd ss mn syns ds tyCon | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys ty _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 1 + | className == Qualified (Just dataOrd) (ProperName "Ord1") + = case tys of + [ty] | Just (Qualified mn' _, _) <- unwrapTypeConstructor ty + , mn == fromMaybe mn mn' + -> pure . TypeInstanceDeclaration sa ch idx nm deps className tys . ExplicitInstance $ deriveOrd1 ss + | otherwise -> throwError . errorMessage' ss $ ExpectedTypeConstructor className tys ty + _ -> throwError . errorMessage' ss $ InvalidDerivedInstance className tys 1 | className == Qualified (Just dataFunctor) (ProperName "Functor") = case tys of [ty] | Just (Qualified mn' tyCon, _) <- unwrapTypeConstructor ty @@ -436,6 +450,9 @@ deriveEq ss mn syns ds tyConNm = do preludeEq :: Expr -> Expr -> Expr preludeEq = App . App (Var (Qualified (Just dataEq) (Ident C.eq))) + preludeEq1 :: Expr -> Expr -> Expr + preludeEq1 = App . App (Var (Qualified (Just dataEq) (Ident C.eq1))) + addCatch :: [CaseAlternative] -> [CaseAlternative] addCatch xs | length xs /= 1 = xs ++ [catchAll] @@ -458,12 +475,21 @@ deriveEq ss mn syns ds tyConNm = do conjAll xs = foldl1 preludeConj xs toEqTest :: Expr -> Expr -> Type -> Expr - toEqTest l r ty | Just rec <- objectType ty - , Just fields <- decomposeRec rec = - conjAll - . map (\((Label str), typ) -> toEqTest (Accessor str l) (Accessor str r) typ) - $ fields - toEqTest l r _ = preludeEq l r + toEqTest l r ty + | Just rec <- objectType ty + , Just fields <- decomposeRec rec = + conjAll + . map (\((Label str), typ) -> toEqTest (Accessor str l) (Accessor str r) typ) + $ fields + | isAppliedVar ty = preludeEq1 l r + | otherwise = preludeEq l r + +deriveEq1 :: SourceSpan -> [Declaration] +deriveEq1 ss = + [ ValueDecl (ss, []) (Ident C.eq1) Public [] (unguarded preludeEq)] + where + preludeEq :: Expr + preludeEq = Var (Qualified (Just dataEq) (Ident C.eq)) deriveOrd :: forall m @@ -510,6 +536,9 @@ deriveOrd ss mn syns ds tyConNm = do ordCompare :: Expr -> Expr -> Expr ordCompare = App . App (Var (Qualified (Just dataOrd) (Ident C.compare))) + ordCompare1 :: Expr -> Expr -> Expr + ordCompare1 = App . App (Var (Qualified (Just dataOrd) (Ident C.compare1))) + mkCtorClauses :: ((ProperName 'ConstructorName, [Type]), Bool) -> m [CaseAlternative] mkCtorClauses ((ctorName, tys), isLast) = do identsL <- replicateM (length tys) (freshIdent "l") @@ -547,12 +576,21 @@ deriveOrd ss mn syns ds tyConNm = do ] toOrdering :: Expr -> Expr -> Type -> Expr - toOrdering l r ty | Just rec <- objectType ty - , Just fields <- decomposeRec rec = - appendAll - . map (\((Label str), typ) -> toOrdering (Accessor str l) (Accessor str r) typ) - $ fields - toOrdering l r _ = ordCompare l r + toOrdering l r ty + | Just rec <- objectType ty + , Just fields <- decomposeRec rec = + appendAll + . map (\((Label str), typ) -> toOrdering (Accessor str l) (Accessor str r) typ) + $ fields + | isAppliedVar ty = ordCompare1 l r + | otherwise = ordCompare l r + +deriveOrd1 :: SourceSpan -> [Declaration] +deriveOrd1 ss = + [ ValueDecl (ss, []) (Ident C.compare1) Public [] (unguarded dataOrdCompare)] + where + dataOrdCompare :: Expr + dataOrdCompare = Var (Qualified (Just dataOrd) (Ident C.compare)) deriveNewtype :: forall m @@ -617,6 +655,10 @@ mkVarMn mn = Var . Qualified mn mkVar :: Ident -> Expr mkVar = mkVarMn Nothing +isAppliedVar :: Type -> Bool +isAppliedVar (TypeApp (TypeVar _) _) = True +isAppliedVar _ = False + objectType :: Type -> Maybe Type objectType (TypeApp (TypeConstructor (Qualified (Just (ModuleName [ProperName "Prim"])) (ProperName "Record"))) rec) = Just rec objectType _ = Nothing