@@ -0,0 +1,92 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE MultiParamTypeClasses #-}
6+{-# LANGUAGE NoMonomorphismRestriction #-}
7+{-# LANGUAGE PolyKinds #-}
8+{-# LANGUAGE Rank2Types #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE TypeApplications #-}
11+{-# LANGUAGE TypeFamilies #-}
12+{-# LANGUAGE TypeOperators #-}
13+{-# LANGUAGE UndecidableInstances #-}
14+
15+-----------------------------------------------------------------------------
16+-- |
17+-- Module : Data.Generics.Product.Internal.Subtype
18+-- Copyright : (C) 2017 Csongor Kiss
19+-- License : BSD3
20+-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
21+-- Stability : experimental
22+-- Portability : non-portable
23+--
24+-- Structural subtype relationships between product types.
25+--
26+-----------------------------------------------------------------------------
27+
28+module Data.Generics.Product.Internal.Subtype
29+ ( GUpcast (..)
30+ , GSmash (..)
31+ ) where
32+
33+import Data.Generics.Internal.Families
34+import Data.Generics.Internal.Lens
35+import Data.Generics.Product.Internal.Fields
36+
37+import Data.Kind (Type)
38+import GHC.Generics
39+
40+--------------------------------------------------------------------------------
41+-- * Generic upcasting
42+
43+class GUpcast (sub :: Type -> Type) (sup :: Type -> Type) where
44+ gupcast :: sub p -> sup p
45+
46+instance (GUpcast sub a, GUpcast sub b) => GUpcast sub (a :*: b) where
47+ gupcast rep = gupcast rep :*: gupcast rep
48+
49+instance
50+ GHasField field sub t
51+ => GUpcast sub (S1 ('MetaSel ('Just field) p f b) (Rec0 t)) where
52+
53+ gupcast r = M1 (K1 (r ^. gfield @field))
54+
55+instance GUpcast sub sup => GUpcast sub (C1 c sup) where
56+ gupcast = M1 . gupcast
57+
58+instance GUpcast sub sup => GUpcast sub (D1 c sup) where
59+ gupcast = M1 . gupcast
60+
61+--------------------------------------------------------------------------------
62+-- * Generic smashing
63+
64+class GSmash sub sup where
65+ gsmash :: sup p -> sub p -> sub p
66+
67+instance (GSmash a sup, GSmash b sup) => GSmash (a :*: b) sup where
68+ gsmash rep (a :*: b) = gsmash rep a :*: gsmash rep b
69+
70+instance
71+ ( leaf ~ (S1 ('MetaSel ('Just field) p f b) t)
72+ , GSmashLeaf leaf sup (HasTotalFieldP field sup)
73+ ) => GSmash (S1 ('MetaSel ('Just field) p f b) t) sup where
74+
75+ gsmash = gsmashLeaf @_ @_ @(HasTotalFieldP field sup)
76+
77+instance GSmash sub sup => GSmash (C1 c sub) sup where
78+ gsmash sup (M1 sub) = M1 (gsmash sup sub)
79+
80+instance GSmash sub sup => GSmash (D1 c sub) sup where
81+ gsmash sup (M1 sub) = M1 (gsmash sup sub)
82+
83+class GSmashLeaf sub sup (w :: Bool) where
84+ gsmashLeaf :: sup p -> sub p -> sub p
85+
86+instance
87+ GHasField field sup t
88+ => GSmashLeaf (S1 ('MetaSel ('Just field) p f b) (Rec0 t)) sup 'True where
89+ gsmashLeaf sup _ = M1 (K1 (sup ^. gfield @field))
90+
91+instance GSmashLeaf (S1 ('MetaSel ('Just field) p f b) (Rec0 t)) sup 'False where
92+ gsmashLeaf _ = id