Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Allow writing holes which are solved by BRAT #59

Open
wants to merge 40 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
fec6dc4
Add holes(!)
croyzor Nov 8, 2024
3c1f4ec
WIP: Merge better nat solving
croyzor Nov 8, 2024
0f7d13d
Revert `run` namespacing changes
croyzor Nov 8, 2024
a53435b
Add defines
croyzor Nov 26, 2024
fec3263
rename some variables
croyzor Nov 26, 2024
c8cb33f
drive-by: Give everything created with anext a label
croyzor Nov 27, 2024
5b2cb45
Replace define -> instantiate
croyzor Nov 27, 2024
ed531ae
Define targets instead of sources (fixes unified.brat)
croyzor Nov 27, 2024
c48da2c
fix: Dodgy demandSucc logic
croyzor Nov 27, 2024
95a4c2d
Define tgts to respective srcs in invertNatVal
croyzor Nov 27, 2024
37ef790
Allow hopes to be removed from the set
croyzor Nov 27, 2024
7626077
Merge remote-tracking branch 'origin/main' into holes
croyzor Nov 27, 2024
cebc93b
Cleanup Error.hs
croyzor Nov 27, 2024
c6e7c3c
Add golden file for unsolved hope error
croyzor Nov 27, 2024
4e776cc
XFAIL infer.brat because we don't compile `Pow`
croyzor Nov 27, 2024
541f35a
Apply lints
croyzor Nov 27, 2024
8ad05de
Revert "drive-by: Give everything created with anext a label"
croyzor Nov 27, 2024
3fe88aa
Merge remote-tracking branch 'origin/main' into holes
croyzor Nov 28, 2024
0cef0d3
drive-by: Give labels to more `next` calls
croyzor Nov 28, 2024
ef85987
Merge remote-tracking branch 'origin/main' into holes
croyzor Dec 3, 2024
c4ebd8c
[cleanup] Remove News datatype from this PR
croyzor Dec 3, 2024
991e0dc
Update brat/Brat/Checker/Monad.hs
croyzor Dec 3, 2024
f82f25c
refactor: Move Nat building code to Helpers
croyzor Dec 3, 2024
f75ce8c
refactor: Replace mkStaticNum with a call to buildNatVal
croyzor Dec 3, 2024
da08608
Revert changes to FC
croyzor Dec 3, 2024
575474e
Apply suggestions from code review
croyzor Dec 3, 2024
c6555b9
rename HopeSet -> Hopes
croyzor Dec 3, 2024
d077d4c
refactor: Make GHC enforce that Hopes are InPorts
croyzor Dec 3, 2024
741d896
refactor: Curry ANewHope
croyzor Dec 3, 2024
bb431ef
refactor: Expose only a simpler version of typeEq
croyzor Dec 3, 2024
b846a62
cosmetic: Get rid of unused variable
croyzor Dec 3, 2024
8bee0d0
cleanup: Get rid of outdated comments
croyzor Dec 3, 2024
631509e
Don't reexport nat building from SolveHoles
croyzor Dec 3, 2024
5a3ffd8
[broken] New example
croyzor Dec 3, 2024
7286b0c
refactor: Make better use of `toEnd` function
croyzor Dec 3, 2024
787baed
Fill in the missing case for demandSucc
croyzor Dec 3, 2024
ca5df29
fix: Add missing unelab cases
croyzor Dec 6, 2024
837eeed
lint: Redundant brackets
croyzor Dec 6, 2024
722e610
Merge remote-tracking branch 'origin/main' into HEAD
acl-cqc Dec 9, 2024
da57ef6
Merge remote-tracking branch 'origin/main' into HEAD
acl-cqc Dec 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions brat/Brat/Checker.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import Prelude hiding (filter)
import Brat.Checker.Helpers
import Brat.Checker.Monad
import Brat.Checker.Quantity
import Brat.Checker.SolveHoles (typeEq)
import Brat.Checker.SolvePatterns (argProblems, argProblemsWithLeftovers, solve)
import Brat.Checker.Types
import Brat.Constructors
Expand Down Expand Up @@ -659,7 +660,13 @@ check' (Of n e) ((), unders) = case ?my of
(elems, unders, rightUnders) <- getVecs len unders
pure ((tgt, el):elems, (tgt, ty):unders, rightUnders)
getVecs _ unders = pure ([], [], unders)

check' Hope ((), (NamedPort hope _, ty):unders) = case (?my, ty) of
(Braty, Left _k) -> do
fc <- req AskFC
req (ANewHope hope fc)
pure (((), ()), ((), unders))
(Braty, Right _ty) -> typeErr "Can only infer kinded things with !"
(Kerny, _) -> typeErr "Won't infer kernel typed !"
check' tm _ = error $ "check' " ++ show tm


Expand Down Expand Up @@ -1124,13 +1131,27 @@ run :: VEnv
-> Namespace
-> Checking a
-> Either Error (a, ([TypedHole], Store, Graph))
run ve initStore ns m =
run ve initStore ns m = do
let ctx = Ctx { globalVEnv = ve
, store = initStore
-- TODO: fill with default constructors
, constructors = defaultConstructors
, kconstructors = kernelConstructors
, typeConstructors = defaultTypeConstructors
, aliasTable = M.empty
} in
(\(a,ctx,(holes, graph)) -> (a, (holes, store ctx, graph))) <$> handler (localNS ns m) ctx mempty
, hopes = M.empty
}
(a,ctx,(holes, graph)) <- handler (localNS ns m) ctx mempty
let tyMap = typeMap $ store ctx
-- If the `hopes` set has any remaining holes with kind Nat, we need to abort.
-- Even though we didn't need them for typechecking problems, our runtime
-- behaviour depends on the values of the holes, which we can't account for.
case M.toList $ M.filterWithKey (\e _ -> isNatKinded tyMap (InEnd e)) (hopes ctx) of
[] -> pure (a, (holes, store ctx, graph))
-- Just use the FC of the first hole while we don't have the capacity to
-- show multiple error locations
hs@((_,fc):_) -> Left $ Err (Just fc) (RemainingNatHopes (show . fst <$> hs))
where
isNatKinded tyMap e = case tyMap M.! e of
EndType Braty (Left Nat) -> True
_ -> False
151 changes: 104 additions & 47 deletions brat/Brat/Checker/Helpers.hs
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@
-> Checking [(PortName, ty)]
pullPortsSig = pullPorts fst showSig

pullPorts :: forall a ty

Check warning on line 112 in brat/Brat/Checker/Helpers.hs

View workflow job for this annotation

GitHub Actions / build

Unused quantified type variable ‘ty’

Check warning on line 112 in brat/Brat/Checker/Helpers.hs

View workflow job for this annotation

GitHub Actions / build

Unused quantified type variable ‘ty’
. (a -> PortName) -- A way to get a port name for each element
-> ([a] -> String) -- A way to print the list
-> [PortName] -- Things to pull to the front
Expand All @@ -117,7 +117,7 @@
-> Checking [a]
pullPorts toPort showFn to_pull types =
-- the "state" here is the things still available to be pulled
(\(pulled, rest) -> pulled ++ rest) <$> runStateT (mapM pull1Port to_pull) types

Check warning on line 120 in brat/Brat/Checker/Helpers.hs

View workflow job for this annotation

GitHub Actions / hlint

Suggestion in pullPorts in module Brat.Checker.Helpers: Use uncurry ▫︎ Found: "\\ (pulled, rest) -> pulled ++ rest" ▫︎ Perhaps: "uncurry (++)" ▫︎ Note: increases laziness
where
pull1Port :: PortName -> StateT [a] Checking a
pull1Port p = StateT $ \available -> case partition ((== p) . toPort) available of
Expand Down Expand Up @@ -272,58 +272,12 @@
,CTy m Z -- The function type at the end
)
vecLayers my (TVec ty (VNum n)) = do
src <- mkStaticNum n
src <- buildNatVal n
first ((src, n):) <$> vecLayers my ty
vecLayers Braty (VFun Braty cty) = pure ([], cty)
vecLayers Kerny (VFun Kerny cty) = pure ([], cty)
vecLayers my ty = typeErr $ "Expected a " ++ showMode my ++ "function or vector of functions, got " ++ show ty

mkStaticNum :: NumVal (VVar Z) -> Checking Src
mkStaticNum n@(NumValue c gro) = do
(_, [], [(constSrc,_)], _) <- next "const" (Const (Num (fromIntegral c))) (S0, Some (Zy :* S0)) R0 (RPr ("value", TNat) R0)
src <- case gro of
Constant0 -> pure constSrc
StrictMonoFun sm -> do
(_, [(lhs,_),(rhs,_)], [(src,_)], _) <- next "add_const" (ArithNode Add) (S0, Some (Zy :* S0))
(RPr ("lhs", TNat) (RPr ("rhs", TNat) R0))
(RPr ("value", TNat) R0)
smSrc <- mkStrictMono sm
wire (constSrc, TNat, lhs)
wire (smSrc, TNat, rhs)
pure src
defineSrc src (VNum n)
pure src
where
mkStrictMono :: StrictMono (VVar Z) -> Checking Src
mkStrictMono (StrictMono k mono) = do
(_, [], [(constSrc,_)], _) <- next "2^k" (Const (Num (2^k))) (S0, Some (Zy :* S0)) R0 (RPr ("value", TNat) R0)
(_, [(lhs,_),(rhs,_)], [(src,_)], _) <- next "mult_const" (ArithNode Mul) (S0, Some (Zy :* S0))
(RPr ("lhs", TNat) (RPr ("rhs", TNat) R0))
(RPr ("value", TNat) R0)
monoSrc <- mkMono mono
wire (constSrc, TNat, lhs)
wire (monoSrc, TNat, rhs)
pure src

mkMono :: Monotone (VVar Z) -> Checking Src
mkMono (Linear (VPar (ExEnd e))) = pure (NamedPort e "mono")
mkMono (Full sm) = do
(_, [], [(twoSrc,_)], _) <- next "2" (Const (Num 2)) (S0, Some (Zy :* S0)) R0 (RPr ("value", TNat) R0)
(_, [(lhs,_),(rhs,_)], [(powSrc,_)], _) <- next "2^" (ArithNode Pow) (S0, Some (Zy :* S0))
(RPr ("lhs", TNat) (RPr ("rhs", TNat) R0))
(RPr ("value", TNat) R0)
smSrc <- mkStrictMono sm
wire (twoSrc, TNat, lhs)
wire (smSrc, TNat, rhs)

(_, [], [(oneSrc,_)], _) <- next "1" (Const (Num 1)) (S0, Some (Zy :* S0)) R0 (RPr ("value", TNat) R0)
(_, [(lhs,_),(rhs,_)], [(src,_)], _) <- next "n-1" (ArithNode Sub) (S0, Some (Zy :* S0))
(RPr ("lhs", TNat) (RPr ("rhs", TNat) R0))
(RPr ("value", TNat) R0)
wire (powSrc, TNat, lhs)
wire (oneSrc, TNat, rhs)
pure src

vectorise :: forall m. Modey m -> (Src, Val Z) -> Checking (Src, CTy m Z)
vectorise my (src, ty) = do
(layers, cty) <- vecLayers my ty
Expand All @@ -333,7 +287,7 @@
-> (Src, CTy m Z) -- The input to this level of mapfun
-> Checking (Src, CTy m Z)
mkMapFun (lenSrc, len) (valSrc, cty) = do
let weak1 = changeVar (Thinning (ThDrop ThNull))

Check warning on line 290 in brat/Brat/Checker/Helpers.hs

View workflow job for this annotation

GitHub Actions / build

• The Monomorphism Restriction applies to the binding for ‘weak1’

Check warning on line 290 in brat/Brat/Checker/Helpers.hs

View workflow job for this annotation

GitHub Actions / build

• The Monomorphism Restriction applies to the binding for ‘weak1’
vecFun <- vectorisedFun len my cty
(_, [(lenTgt,_), (valTgt, _)], [(vectorSrc, Right (VFun my' cty))], _) <-
next "MapFun" MapFun (S0, Some (Zy :* S0))
Expand Down Expand Up @@ -492,3 +446,106 @@
-- 2^(2^k * upr) + 2^(2^k * upr) * (full(2^(k + k') * mono))
= pure $ NumValue (upl ^ upr) (StrictMonoFun (StrictMono (l * upr) (Full (StrictMono (k + k') mono))))
runArith _ _ _ = Nothing

buildArithOp :: ArithOp -> Checking ((Tgt, Tgt), Src)
buildArithOp op = do
(_, [(lhs,_), (rhs,_)], [(out,_)], _) <- next (show op) (ArithNode op) (S0, Some (Zy :* S0)) (RPr ("lhs", TNat) (RPr ("rhs", TNat) R0)) (RPr ("value", TNat) R0)
pure ((lhs, rhs), out)

buildConst :: SimpleTerm -> Val Z -> Checking Src
buildConst tm ty = do
(_, _, [(out,_)], _) <- next "buildConst" (Const tm) (S0, Some (Zy :* S0)) R0 (RPr ("value", ty) R0)
pure out

buildNum :: Integer -> Checking Src
buildNum n = buildConst (Num (fromIntegral n)) TNat

-- Generate wiring to produce a dynamic instance of the numval argument
-- N.B. In these functions, we wire using Req, rather than the `wire` function
-- because we don't want it to do any extra evaluation.
buildNatVal :: NumVal (VVar Z) -> Checking Src
buildNatVal nv@(NumValue n gro) = case n of
0 -> buildGro gro
n -> do
nDangling <- buildNum n
((lhs,rhs),out) <- buildArithOp Add
src <- buildGro gro
req $ Wire (end nDangling, TNat, end lhs)
req $ Wire (end src, TNat, end rhs)
defineSrc out (VNum (nPlus n (nVar (VPar (toEnd src)))))
pure out
where
buildGro :: Fun00 (VVar Z) -> Checking Src
buildGro Constant0 = buildNum 0
buildGro (StrictMonoFun sm) = buildSM sm

buildSM :: StrictMono (VVar Z) -> Checking Src
buildSM (StrictMono k mono) = do
-- Calculate 2^k as `factor`
two <- buildNum 2
kDangling <- buildNum k
((lhs,rhs),factor) <- buildArithOp Pow
req $ Wire (end two, TNat, end lhs)
req $ Wire (end kDangling, TNat, end rhs)
-- Multiply mono by 2^k
((lhs,rhs),out) <- buildArithOp Mul
monoDangling <- buildMono mono
req $ Wire (end factor, TNat, end lhs)
req $ Wire (end monoDangling, TNat, end rhs)
defineSrc out (VNum (n2PowTimes k (nVar (VPar (toEnd monoDangling)))))
pure out

buildMono :: Monotone (VVar Z) -> Checking Src
buildMono (Linear (VPar (ExEnd e))) = pure $ NamedPort e "numval"
buildMono (Full sm) = do
-- Calculate 2^n as `outPlus1`
two <- buildNum 2
dangling <- buildSM sm
((lhs,rhs),outPlus1) <- buildArithOp Pow
req $ Wire (end two, TNat, end lhs)
req $ Wire (end dangling, TNat, end rhs)
-- Then subtract 1
one <- buildNum 1
((lhs,rhs),out) <- buildArithOp Sub
req $ Wire (end outPlus1, TNat, end lhs)
req $ Wire (end one, TNat, end rhs)
defineSrc out (VNum (nFull (nVar (VPar (toEnd dangling)))))
pure out
buildMono _ = err . InternalError $ "Trying to build a non-closed nat value: " ++ show nv

invertNatVal :: NumVal (VVar Z) -> Checking Tgt
invertNatVal (NumValue up gro) = case up of
0 -> invertGro gro
_ -> do
((lhs,rhs),out) <- buildArithOp Sub
upSrc <- buildNum up
req $ Wire (end upSrc, TNat, end rhs)
tgt <- invertGro gro
req $ Wire (end out, TNat, end tgt)
defineTgt tgt (VNum (nVar (VPar (toEnd out))))
defineTgt lhs (VNum (nPlus up (nVar (VPar (toEnd tgt)))))
pure lhs
where
invertGro Constant0 = error "Invariant violated: the numval arg to invertNatVal should contain a variable"
invertGro (StrictMonoFun sm) = invertSM sm

invertSM (StrictMono k mono) = case k of
0 -> invertMono mono
_ -> do
divisor <- buildNum (2 ^ k)
((lhs,rhs),out) <- buildArithOp Div
tgt <- invertMono mono
req $ Wire (end out, TNat, end tgt)
req $ Wire (end divisor, TNat, end rhs)
defineTgt tgt (VNum (nVar (VPar (toEnd out))))
defineTgt lhs (VNum (n2PowTimes k (nVar (VPar (toEnd tgt)))))
pure lhs

invertMono (Linear (VPar (InEnd e))) = pure (NamedPort e "numval")

Check warning on line 544 in brat/Brat/Checker/Helpers.hs

View workflow job for this annotation

GitHub Actions / build

Pattern match(es) are non-exhaustive

Check warning on line 544 in brat/Brat/Checker/Helpers.hs

View workflow job for this annotation

GitHub Actions / build

Pattern match(es) are non-exhaustive
invertMono (Full sm) = do
(_, [(llufTgt,_)], [(llufSrc,_)], _) <- next "luff" (Prim ("BRAT","lluf")) (S0, Some (Zy :* S0)) (REx ("n", Nat) R0) (REx ("n", Nat) R0)
tgt <- invertSM sm
req $ Wire (end llufSrc, TNat, end tgt)
defineTgt tgt (VNum (nVar (VPar (toEnd llufSrc))))
defineTgt llufTgt (VNum (nFull (nVar (VPar (toEnd tgt)))))
pure llufTgt
16 changes: 16 additions & 0 deletions brat/Brat/Checker/Monad.hs
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,16 @@ data CtxEnv = CtxEnv
, locals :: VEnv
}

type Hopes = M.Map InPort FC

data Context = Ctx { globalVEnv :: VEnv
, store :: Store
, constructors :: ConstructorMap Brat
, kconstructors :: ConstructorMap Kernel
, typeConstructors :: M.Map (Mode, QualName) [(PortName, TypeKind)]
, aliasTable :: M.Map QualName Alias
-- All the ends here should be targets
croyzor marked this conversation as resolved.
Show resolved Hide resolved
, hopes :: Hopes
}

data CheckingSig ty where
Expand Down Expand Up @@ -89,6 +93,9 @@ data CheckingSig ty where
AskVEnv :: CheckingSig CtxEnv
Declare :: End -> Modey m -> BinderType m -> CheckingSig ()
Define :: End -> Val Z -> CheckingSig ()
ANewHope :: InPort -> FC -> CheckingSig ()
AskHopes :: CheckingSig Hopes
RemoveHope :: InPort -> CheckingSig ()

localAlias :: (QualName, Alias) -> Checking v -> Checking v
localAlias _ (Ret v) = Ret v
Expand Down Expand Up @@ -267,6 +274,15 @@ handler (Req s k) ctx g
M.lookup tycon tbl
handler (k args) ctx g

ANewHope e fc -> handler (k ()) (ctx { hopes = M.insert e fc (hopes ctx) }) g

AskHopes -> handler (k (hopes ctx)) ctx g

RemoveHope e -> let hset = hopes ctx in
if M.member e hset
then handler (k ()) (ctx { hopes = M.delete e hset }) g
else Left (dumbErr (InternalError ("Trying to remove Hope not in set: " ++ show e)))

type Checking = Free CheckingSig

instance Semigroup a => Semigroup (Checking a) where
Expand Down
Loading
Loading