1
+ {-# OPTIONS_GHC -Wno-redundant-constraints #-}
2
+
1
3
module LambdaBuffers.Compiler.KindCheck (
2
4
-- * Kindchecking functions.
3
5
check ,
@@ -11,9 +13,10 @@ module LambdaBuffers.Compiler.KindCheck (
11
13
12
14
import Control.Lens (view , (&) , (.~) , (^.) )
13
15
import Control.Monad (void )
14
- import Control.Monad.Freer (Eff , Members , reinterpret , run )
16
+ import Control.Monad.Freer (Eff , Member , Members , interpret , reinterpret , run )
15
17
import Control.Monad.Freer.Error (Error , runError , throwError )
16
18
import Control.Monad.Freer.Reader (Reader , ask , runReader )
19
+ import Control.Monad.Freer.State (State , evalState , get , modify )
17
20
import Control.Monad.Freer.TH (makeEffect )
18
21
import Data.Foldable (traverse_ )
19
22
import Data.List.NonEmpty (NonEmpty ((:|) ), uncons , (<|) )
@@ -36,51 +39,12 @@ import LambdaBuffers.Compiler.KindCheck.Inference qualified as I
36
39
import LambdaBuffers.Compiler.KindCheck.Type (Type (App ))
37
40
import LambdaBuffers.Compiler.KindCheck.Variable (Variable (ForeignRef , LocalRef ))
38
41
import LambdaBuffers.Compiler.ProtoCompat (kind2ProtoKind )
39
- import LambdaBuffers.Compiler.ProtoCompat.Types qualified as P (
40
- ClassDef ,
41
- CompilerError (.. ),
42
- CompilerInput ,
43
- Constructor ,
44
- Field ,
45
- ForeignRef ,
46
- InstanceClause ,
47
- Kind ,
48
- KindCheckError (
49
- InconsistentTypeError ,
50
- IncorrectApplicationError ,
51
- RecursiveKindError ,
52
- UnboundTermError
53
- ),
54
- KindRefType (KType ),
55
- KindType (KindArrow , KindRef ),
56
- LocalRef ,
57
- Module ,
58
- ModuleName ,
59
- Product (.. ),
60
- Record ,
61
- SourceInfo (SourceInfo ),
62
- SourcePosition (SourcePosition ),
63
- Sum ,
64
- Tuple ,
65
- Ty (.. ),
66
- TyAbs ,
67
- TyApp ,
68
- TyArg ,
69
- TyBody (.. ),
70
- TyDef (TyDef ),
71
- TyName ,
72
- TyRef (.. ),
73
- TyVar ,
74
- VarName (VarName ),
75
- )
42
+ import LambdaBuffers.Compiler.ProtoCompat.Types qualified as P
76
43
import LambdaBuffers.Compiler.ProtoCompat.Types qualified as PT
77
44
78
45
--------------------------------------------------------------------------------
79
46
-- Types
80
47
81
- -- FIXME(cstml) - We should add the following tests:
82
- -- - double declaration of a type
83
-
84
48
-- | Kind Check failure types.
85
49
type CompilerErr = P. CompilerError
86
50
@@ -121,20 +85,27 @@ makeEffect ''KindCheck
121
85
122
86
--------------------------------------------------------------------------------
123
87
124
- runCheck :: Eff (Check ': '[] ) a -> Either CompilerErr a
88
+ -- | The Check effect runner.
89
+ runCheck :: Eff '[Check , Err ] a -> Either CompilerErr a
125
90
runCheck = run . runError . runKindCheck . localStrategy . moduleStrategy . globalStrategy
126
91
127
- -- | Run the check - return the validated context or the failure.
92
+ {- | Run the check - return the validated context or the failure. The main API
93
+ function of the library.
94
+ -}
128
95
check :: P. CompilerInput -> PT. CompilerOutput
129
96
check = fmap (const PT. CompilerResult ) . runCheck . kCheck
130
97
131
- -- | Run the check - drop the result if it succeeds.
98
+ -- | Run the check - drop the result if it succeeds - useful for testing .
132
99
check_ :: P. CompilerInput -> Either CompilerErr ()
133
100
check_ = void . runCheck . kCheck
134
101
135
102
--------------------------------------------------------------------------------
136
103
137
- type Transform x y = forall effs {a }. Eff (x ': effs ) a -> Eff (y ': effs ) a
104
+ {- | A transformation (in the context of the Kind Checker) is a mapping from one
105
+ Effect to another. All effects can fial via the `Err` effect - which is
106
+ essentially the Kind Check failure.
107
+ -}
108
+ type Transform x y = forall effs {a }. Member Err effs = > Eff (x ': effs ) a -> Eff (y ': effs ) a
138
109
139
110
-- Transformation strategies
140
111
globalStrategy :: Transform Check GlobalCheck
@@ -146,7 +117,7 @@ globalStrategy = reinterpret $ \case
146
117
147
118
moduleStrategy :: Transform GlobalCheck ModuleCheck
148
119
moduleStrategy = reinterpret $ \ case
149
- CreateContext ci -> resolveCreateContext ci
120
+ CreateContext ci -> evalState ( mempty @ ( M. Map Variable P. TyDef )) . resolveCreateContext $ ci
150
121
ValidateModule cx md -> do
151
122
traverse_ (kCTypeDefinition (module2ModuleName md) cx) (md ^. # typeDefs)
152
123
traverse_ (kCClassInstance cx) (md ^. # instances)
@@ -159,14 +130,14 @@ localStrategy = reinterpret $ \case
159
130
KCClassInstance _ctx _instClause -> pure () -- "FIXME(cstml)"
160
131
KCClass _ctx _classDef -> pure () -- "FIXME(cstml)"
161
132
162
- runKindCheck :: Eff '[ KindCheck ] a -> Eff '[ Err ] a
163
- runKindCheck = reinterpret $ \ case
133
+ runKindCheck :: forall effs { a } . Member Err effs => Eff ( KindCheck ' : effs ) a -> Eff effs a
134
+ runKindCheck = interpret $ \ case
164
135
KindFromTyDef moduleName tydef -> runReader moduleName (tyDef2Type tydef)
165
136
-- TyDefToTypes moduleName tydef -> runReader moduleName (tyDef2Types tydef)
166
137
InferTypeKind _modName tyDef ctx ty -> either (handleErr tyDef) pure $ infer ctx ty
167
138
CheckKindConsistency mname def ctx k -> runReader mname $ resolveKindConsistency def ctx k
168
139
where
169
- handleErr :: forall a . P. TyDef -> InferErr -> Eff '[ Err ] a
140
+ handleErr :: forall { b } . P. TyDef -> InferErr -> Eff effs b
170
141
handleErr td = \ case
171
142
InferUnboundTermErr uA ->
172
143
throwError . P. CompKindCheckError $ P. UnboundTermError (tyDef2TyName td) (var2VarName uA)
@@ -208,15 +179,65 @@ resolveKindConsistency tydef _ctx inferredKind = do
208
179
throwError . P. CompKindCheckError $
209
180
P. InconsistentTypeError n (kind2ProtoKind i) (kind2ProtoKind d)
210
181
211
- resolveCreateContext :: forall effs . P. CompilerInput -> Eff effs Context
212
- resolveCreateContext ci = mconcat <$> traverse module2Context (ci ^. # modules)
213
-
214
182
tyDef2TyName :: P. TyDef -> P. TyName
215
183
tyDef2TyName (P. TyDef n _ _) = n
216
184
217
- module2Context :: forall effs . P. Module -> Eff effs Context
218
- module2Context m = mconcat <$> traverse (tyDef2Context (moduleName2ModName (m ^. # moduleName))) (m ^. # typeDefs)
185
+ --------------------------------------------------------------------------------
186
+ -- Context Creation
219
187
188
+ {- | Resolver function for the context creation - it fails if two identical
189
+ declarations are found.
190
+ -}
191
+ resolveCreateContext ::
192
+ forall effs .
193
+ Member (State (M. Map Variable P. TyDef )) effs =>
194
+ Member Err effs =>
195
+ P. CompilerInput ->
196
+ Eff effs Context
197
+ resolveCreateContext ci = do
198
+ ctxs <- traverse module2Context (ci ^. # modules)
199
+ pure $ mconcat ctxs
200
+
201
+ module2Context ::
202
+ forall effs .
203
+ Member (State (M. Map Variable P. TyDef )) effs =>
204
+ Member Err effs =>
205
+ P. Module ->
206
+ Eff effs Context
207
+ module2Context m = do
208
+ let typeDefinitions = m ^. # typeDefs
209
+ ctxs <- runReader (m ^. # moduleName) $ do
210
+ traverse (tyDef2Context (moduleName2ModName (m ^. # moduleName))) typeDefinitions
211
+ pure $ mconcat ctxs
212
+
213
+ -- | Creates a Context entry from one type definition.
214
+ tyDef2Context ::
215
+ forall effs .
216
+ Member (Reader P. ModuleName ) effs =>
217
+ Member (State (M. Map Variable P. TyDef )) effs =>
218
+ Member Err effs =>
219
+ ModName ->
220
+ P. TyDef ->
221
+ Eff effs Context
222
+ tyDef2Context curModName tyDef = do
223
+ r@ (v, _) <- tyDef2NameAndKind curModName tyDef
224
+ associateName v tyDef
225
+ pure $ mempty & context .~ uncurry M. singleton r
226
+ where
227
+ -- Ads the name to our map - we can use its SourceLocation in the case of a
228
+ -- double use. If it's already in our map - that means we've double declared it.
229
+ associateName :: Variable -> P. TyDef -> Eff effs ()
230
+ associateName v curTyDef = do
231
+ modName <- ask
232
+ maps <- get @ (M. Map Variable P. TyDef )
233
+ case maps M. !? v of
234
+ Just otherTyDef ->
235
+ throwError . PT. CompKindCheckError $ PT. MultipleTyDefError modName [otherTyDef, curTyDef]
236
+ Nothing -> modify (M. insert v curTyDef)
237
+
238
+ {- | Converts the Proto Module name to a local modname - dropping the
239
+ information.
240
+ -}
220
241
moduleName2ModName :: P. ModuleName -> ModName
221
242
moduleName2ModName mName = (\ p -> p ^. # name) <$> mName ^. # parts
222
243
@@ -227,11 +248,6 @@ tyDef2NameAndKind curModName tyDef = do
227
248
let k = tyAbsLHS2Kind (tyDef ^. # tyAbs)
228
249
pure (name, k)
229
250
230
- tyDef2Context :: forall effs . ModName -> P. TyDef -> Eff effs Context
231
- tyDef2Context curModName tyDef = do
232
- r <- tyDef2NameAndKind curModName tyDef
233
- pure $ mempty & context .~ uncurry M. singleton r
234
-
235
251
tyAbsLHS2Kind :: P. TyAbs -> Kind
236
252
tyAbsLHS2Kind tyAbs = foldWithArrow $ pKind2Type . (\ x -> x ^. # argKind) <$> (tyAbs ^. # tyArgs)
237
253
0 commit comments