Skip to content

Commit 998d3ac

Browse files
committed
tweaked assumptions for typeclass validation
1 parent 9d97874 commit 998d3ac

File tree

1 file changed

+9
-29
lines changed
  • lambda-buffers-compiler/src/LambdaBuffers/Compiler/TypeClass

1 file changed

+9
-29
lines changed

lambda-buffers-compiler/src/LambdaBuffers/Compiler/TypeClass/Validate.hs

Lines changed: 9 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,7 @@ module LambdaBuffers.Compiler.TypeClass.Validate (
1212
checkDerive,
1313
) where
1414

15-
import Data.List (foldl')
16-
17-
import Data.Map qualified as M
1815
import Data.Set qualified as S
19-
import Data.Text qualified as T
2016

2117
import LambdaBuffers.Compiler.TypeClass.Rules (
2218
Class,
@@ -29,11 +25,9 @@ import LambdaBuffers.Compiler.ProtoCompat.Types qualified as P (
2925
)
3026
import LambdaBuffers.Compiler.TypeClass.Pat (
3127
Pat (
32-
AppP,
3328
DecP,
3429
Name,
3530
Nil,
36-
Opaque,
3731
ProdP,
3832
RecP,
3933
RefP,
@@ -77,33 +71,21 @@ mkStructuralRules c =
7771
splitInstance :: Instance -> (Constraint, [Constraint])
7872
splitInstance (C c t :<= is) = (C c t, is)
7973

80-
-- utility
74+
{- NOTE: This is *only* a safe thing to do in cases where:
75+
1) The instances have all been kind-checked
76+
2) The instances have been checked for basic condition violations (specifically conditions 1 & 2, see Utils.hs)
77+
3) Steps 1 & 2 were performed IN THAT ORDER
78+
79+
If the above checks have not been performed, a user can short-circuit all of our
80+
typeclass validation by doing something stupid like `instance Foo a => Foo a`
81+
(that's not the only thing that can go wrong, checking for duplicates isn't enough)
82+
-}
8183
assume :: [Constraint] -> [Instance]
8284
assume = map $ \(C c t) -> C c t :<= []
8385

8486
constraintClass :: Constraint -> Class
8587
constraintClass (C c _) = c
8688

87-
{- We presume that all locally defined instances of the forms:
88-
1. instance C Opaque0
89-
2. instance C var => C (Opaque1 var)
90-
Should be interpreted as axioms, and, therefore, are
91-
automagically solved.
92-
-}
93-
assumeLocalOpaqueInstances :: M.Map T.Text Pat -> [Instance] -> [Instance]
94-
assumeLocalOpaqueInstances localTyScope =
95-
foldl'
96-
( \acc i -> case i of
97-
cx@(C _ (RefP Nil (Name t)) :<= []) -> case M.lookup t localTyScope of
98-
Just (DecP _ _ Opaque) -> cx : acc
99-
_ -> acc
100-
cx@(C _ (AppP (RefP Nil (Name t)) _) :<= _) -> case M.lookup t localTyScope of
101-
Just (DecP _ _ Opaque) -> cx : acc
102-
_ -> acc
103-
_ -> acc
104-
)
105-
[]
106-
10789
-- NOTE: Practically this enforces the "must define instances where types are defined"
10890
-- half of Haskell's orphan instances rule. We could relax that in various ways
10991
-- but it would require reworking a lot of the utilities above.
@@ -128,11 +110,9 @@ checkDerive mn mb i = concat <$> (traverse solveRef =<< catchOverlap (solve assu
128110
catchOverlap $ solve assumptions (C cx refOf)
129111
other -> pure [other]
130112

131-
-- TODO(gnumonik): THESE ARE NOT RIGHT. UPDATE TO WORK W/ TyVarP
132113
assumptions =
133114
S.toList . S.fromList $
134115
S.toList inScopeInstances -- the basic set of in-scope instances
135116
<> concatMap (mkStructuralRules . constraintClass) (c : cs) -- structural rules for all in scope classes
136117
<> assume cs -- local assumptions, i.e., the `C a` in `instance C a => C (F a)`
137118
<> S.toList (S.filter (/= i) localInstances) -- all local instances that aren't the one we're trying to check
138-
<> assumeLocalOpaqueInstances localTyDefs (S.toList localInstances) -- all local instances (i.e. ones to be generated) with an opaque body (treat them as assertions/axioms)

0 commit comments

Comments
 (0)