Skip to content

Commit 2a2e347

Browse files
authored
Merge pull request #229 from granule-project/fractional
Fractional permissions for mutable and immutable borrowing
2 parents dfc2314 + f861c0d commit 2a2e347

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1068
-158
lines changed

StdLib/List.gr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import Result
1414
import Maybe
1515
import Bool
1616

17-
data List a where Empty; Next a (List a)
17+
data List a where Empty | Next a (List a)
1818

1919
--- Append two lists
2020
append_list : forall {a : Type} . List a -> List a -> List a

StdLib/Vec.gr

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -128,11 +128,11 @@ uncons
128128
uncons (Cons x xs) = (x,xs)
129129

130130
--- Split a vector at position 'n'
131-
split
131+
splitVec
132132
: forall {a : Type, m n : Nat}
133133
. N n -> (Vec (n + m) a) -> (Vec n a, Vec m a)
134-
split Z xs = (Nil, xs);
135-
split (S n) (Cons x xs) = let (xs', ys') = split n xs in (Cons x xs', ys')
134+
splitVec Z xs = (Nil, xs);
135+
splitVec (S n) (Cons x xs) = let (xs', ys') = splitVec n xs in (Cons x xs', ys')
136136

137137
--- Sum a vector of integers (using `foldr`)
138138
sum

compiler/src/Language/Granule/Compiler/HSCodegen.hs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,15 +134,18 @@ cgType (GrType.TyApp t1 t2) =
134134
t2' <- cgType t2
135135
return $ Hs.TyApp () t1' t2'
136136
cgType (GrType.Star _t t2) = cgType t2
137+
cgType (GrType.Borrow _t t2) = cgType t2
137138
cgType (GrType.TyInt i) = return mkUnit
138139
cgType (GrType.TyRational ri) = return mkUnit
140+
cgType (GrType.TyFraction ri) = return mkUnit
139141
cgType (GrType.TyGrade mt i) = return mkUnit
140142
cgType (GrType.TyInfix t1 t2 t3) = return mkUnit
141143
cgType (GrType.TySet p l_t) = return mkUnit
142144
cgType (GrType.TyCase t l_p_tt) = unsupported "cgType: tycase not implemented"
143145
cgType (GrType.TySig t t2) = unsupported "cgType: tysig not implemented"
144146
cgType (GrType.TyExists _ _ _) = unsupported "cgType: tyexists not implemented"
145147
cgType (GrType.TyForall _ _ _) = unsupported "cgType: tyforall not implemented"
148+
cgType (GrType.TyName _) = unsupported "cgType: tyname not implemented"
146149

147150
isTupleType :: GrType.Type -> Bool
148151
isTupleType (GrType.TyApp (GrType.TyCon id) _) = id == Id "," ","

docs/style.css

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,16 @@ body {
1212
}
1313

1414
.code pre {
15-
white-space: pre-wrap; /* css-3 */
16-
white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
17-
white-space: -pre-wrap; /* Opera 4-6 */
18-
white-space: -o-pre-wrap; /* Opera 7 */
19-
word-wrap: break-word; /* Internet Explorer 5.5+ */
15+
white-space: pre-wrap;
16+
/* css-3 */
17+
white-space: -moz-pre-wrap;
18+
/* Mozilla, since 1999 */
19+
white-space: -pre-wrap;
20+
/* Opera 4-6 */
21+
white-space: -o-pre-wrap;
22+
/* Opera 7 */
23+
word-wrap: break-word;
24+
/* Internet Explorer 5.5+ */
2025
}
2126

2227
.inline {
@@ -65,6 +70,11 @@ body {
6570
color: rgb(194, 2, 50);
6671
}
6772

73+
.perm,
74+
.perm span {
75+
color: rgb(34, 102, 34);
76+
}
77+
6878
#navigator {
6979
width: calc(25vw - 20px - 2 * 20px);
7080
margin: 0px;

examples/effects_nondet.gr

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import List
1010

1111
data Labels = Toss | Drop
1212

13-
-- Operations
13+
-- (Sigma functor) - Signature of operations
1414
data GameOps : Set Labels -> Type -> Type where
1515
FlipCoin : forall {r : Type} . () -> (Bool -> r) [2] -> GameOps {Toss} r;
1616
Fumble : forall {r : Type} . () -> (Void -> r) [0] -> GameOps {Drop} r
@@ -33,7 +33,7 @@ foo = call FlipCoin ()
3333

3434
-- Two coin flips, all good
3535
example1 : (Bool, Bool) <Eff (Set Labels) GameOps {Toss}>
36-
example1 = let
36+
example1 = let -- do x <- ...
3737
x <- call FlipCoin ();
3838
y <- call FlipCoin ()
3939
in pure (x, y)

examples/parallelWithMutation.gr

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import Parallel
2+
import Prelude
3+
import Vec
4+
5+
--- Convert an indexed natural number to an untyped int
6+
natToInt'
7+
: forall {n : Nat}
8+
. N n -> Int
9+
natToInt' Z = 0;
10+
natToInt' (S m) = 1 + natToInt' m
11+
12+
toFloatArray : forall {n : Nat} . Vec n Float -> exists {id : Name} . *(FloatArray id)
13+
toFloatArray v =
14+
let (n', v) = length' v
15+
in unpack <id, arr> = newFloatArray (natToInt' n')
16+
in pack <id, (toFloatArrayAux arr [0] v)> as exists {id : Name} . *(FloatArray id)
17+
18+
toFloatArrayAux : forall {n : Nat, id : Name} . *(FloatArray id) -> Int [n] -> Vec n Float -> *(FloatArray id)
19+
toFloatArrayAux a [n] Nil = a;
20+
toFloatArrayAux a [n] (Cons x xs) =
21+
toFloatArrayAux (writeFloatArray a n x) [n + 1] xs
22+
23+
sumFromTo : forall {id : Name, f : Fraction} . & f (FloatArray id) -> !Int -> !Int -> (Float, & f (FloatArray id))
24+
sumFromTo array [i] [n] =
25+
if i == n
26+
then (0.0, array)
27+
else
28+
let (x, a) = readFloatArray array i;
29+
(y, arr) = sumFromTo a [i+1] [n]
30+
in (x + y, arr)
31+
32+
-- A reference to a droppable value can be written to without violating linearity
33+
writeRef : forall {a : Type, id : Name} . {Dropable a} => a -> & 1 (Ref id a) -> & 1 (Ref id a)
34+
writeRef x r = let
35+
(y, r') = swapRef r x;
36+
() = drop@a y in r'
37+
38+
parSum : forall {id id' : Name} . *(FloatArray id) -> *(Ref id' Float) -> *(Ref id' Float, FloatArray id)
39+
parSum array ref = let
40+
([n], array) : (!Int, *(FloatArray id)) = lengthFloatArray array;
41+
compIn = borrowPull (ref, array)
42+
in flip withBorrow compIn (\compIn ->
43+
44+
let (ref, array) = borrowPush compIn;
45+
(array1, array2) = split array;
46+
47+
-- Compute in parallel
48+
((x, array1), (y, array2)) =
49+
par (\() -> sumFromTo array1 [0] [div n 2])
50+
(\() -> sumFromTo array2 [div n 2] [n]);
51+
52+
-- Update the reference
53+
ref' = writeRef ((x : Float) + y) ref;
54+
compOut = borrowPull (ref', join (array1, array2))
55+
56+
in compOut)
57+
58+
main : Float
59+
main =
60+
unpack <id , arr> = toFloatArray (Cons 10.0 (Cons 20.0 (Cons 30.0 (Cons 40.0 Nil)))) in
61+
unpack <id', ref> = newRef 0.0 in
62+
let
63+
(result, array) = borrowPush (parSum arr ref);
64+
() = deleteFloatArray array
65+
in freezeRef result

examples/simple-clone.gr

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
example : ()
2+
example = unpack <id , a> = newFloatArray 3 in
3+
clone (share a) as x in
4+
unpack <id' , a'> = x in (deleteFloatArray a')

frontend/granule-frontend.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ library
7171
other-modules:
7272
Language.Granule.Checker.CoeffectsTypeConverter
7373
Language.Granule.Checker.Constraints.Compile
74+
Language.Granule.Checker.Constraints.SFrac
7475
Language.Granule.Checker.Constraints.SymbolicGrades
7576
Language.Granule.Checker.Effects
7677
Language.Granule.Checker.Exhaustivity

frontend/src/Language/Granule/Checker/Checker.hs

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,22 @@ checkExpr defs gam pol topLevel tau
663663
else
664664
throw $ TypeError { errLoc = s, tyExpected = TyCon $ mkId "DFloat", tyActual = tau }
665665

666+
-- Clone
667+
-- Pattern match on an applicable of `uniqueBind fun e`
668+
checkExpr defs gam pol topLevel tau
669+
expr@(App s a rf
670+
(App _ _ _
671+
(Val _ _ _ (Var _ (internalName -> "uniqueBind")))
672+
(Val _ _ _ (Abs _ (PVar _ _ _ var) _ body)))
673+
e) = do
674+
debugM "checkExpr[Clone]" (pretty s <> " : " <> pretty tau)
675+
(tau', gam, subst, elab) <- synthExpr defs gam pol expr
676+
-- Check the return types match
677+
(eqT, _, substTy) <- equalTypes s tau tau'
678+
unless eqT $ throw TypeError{ errLoc = s, tyExpected = tau, tyActual = tau' }
679+
substF <- combineSubstitutions s subst substTy
680+
return (gam, subst, elab)
681+
666682
-- Application checking
667683
checkExpr defs gam pol topLevel tau (App s a rf e1 e2) | (usingExtension GradedBase) = do
668684
debugM "checkExpr[App]-gradedBase" (pretty s <> " : " <> pretty tau)
@@ -745,6 +761,15 @@ checkExpr defs gam pol _ ty@(Star demand tau) (Val s _ rf (Nec _ e)) = do
745761
let elaborated = Val s ty rf (Nec tau elaboratedE)
746762
return (gam', subst, elaborated)
747763

764+
checkExpr defs gam pol _ ty@(Borrow demand tau) (Val s _ rf (Ref _ e)) = do
765+
debugM "checkExpr[Borrow]" (pretty s <> " : " <> pretty ty)
766+
767+
-- Checker the expression being borrowed
768+
(gam', subst, elaboratedE) <- checkExpr defs gam pol False tau e
769+
770+
let elaborated = Val s ty rf (Ref tau elaboratedE)
771+
return (gam', subst, elaborated)
772+
748773
-- Check a case expression
749774
checkExpr defs gam pol True tau (Case s _ rf guardExpr cases) = do
750775
debugM "checkExpr[Case]" (pretty s <> " : " <> pretty tau)
@@ -888,8 +913,9 @@ synthExpr :: (?globals :: Globals)
888913

889914
-- Hit an unfilled hole
890915
synthExpr _ ctxt _ (Hole s _ _ _ _) = do
916+
st <- get
891917
debugM "synthExpr[Hole]" (pretty s)
892-
throw $ InvalidHolePosition s
918+
throw $ InvalidHolePosition s ctxt (tyVarContext st)
893919

894920
-- Literals can have their type easily synthesised
895921
synthExpr _ _ _ (Val s _ rf (NumInt n)) = do
@@ -912,6 +938,51 @@ synthExpr _ _ _ (Val s _ rf (StringLiteral c)) = do
912938
let t = TyCon $ mkId "String"
913939
return (t, usedGhostVariableContext, [], Val s t rf (StringLiteral c))
914940

941+
-- Clone
942+
-- Pattern match on an applicable of `uniqueBind fun e`
943+
synthExpr defs gam pol
944+
expr@(App s a rf
945+
(App _ _ _
946+
(Val _ _ _ (Var _ (internalName -> "uniqueBind")))
947+
(Val _ _ _ (Abs _ (PVar _ _ _ var) _ body)))
948+
e) = do
949+
debugM "synthExpr[uniqueBind]" (pretty s <> pretty expr)
950+
-- Infer the type of e (the boxed argument)
951+
(ty, ghostVarCtxt, subst0, elabE) <- synthExpr defs gam pol e
952+
-- Check that ty is actually a boxed type
953+
case ty of
954+
Box r tyA -> do
955+
-- existential type for the cloned var ((exists {id : Name} . *(Rename id a))
956+
idVar <- mkId <$> freshIdentifierBase "id"
957+
let clonedInputTy =
958+
TyExists idVar (TyCon $ mkId "Name")
959+
(Borrow (TyCon $ mkId "Star") (TyApp (TyApp (TyCon $ mkId "Rename") (TyVar idVar)) tyA))
960+
let clonedAssumption = (var, Linear clonedInputTy)
961+
962+
debugM "synthExpr[uniqueBind]body" (pretty clonedAssumption)
963+
-- synthesise the type of the body for the clone
964+
(tyB, ghostVarCtxt', subst1, elabBody) <- synthExpr defs (clonedAssumption : gam) pol body
965+
966+
let contType = FunTy Nothing Nothing (Box r tyA) tyB
967+
let funType = FunTy Nothing Nothing clonedInputTy tyB
968+
let cloneType = FunTy Nothing Nothing contType funType
969+
let elab = App s tyB rf
970+
(App s contType rf (Val s cloneType rf (Var cloneType $ mkId "uniqueBind"))
971+
(Val s funType rf (Abs funType (PVar s clonedInputTy rf var) Nothing elabBody))) elabE
972+
973+
-- Add constraints of `clone`
974+
-- Constraint that 1 : s <= r
975+
(semiring, subst2, _) <- synthKind s r
976+
let constraint = ApproximatedBy s (TyGrade (Just semiring) 1) r semiring
977+
addConstraint constraint
978+
-- Cloneable constraint
979+
otherTypeConstraints <- enforceConstraints s [TyApp (TyCon $ mkId "Cloneable") tyA]
980+
registerWantedTypeConstraints otherTypeConstraints
981+
982+
substFinal <- combineSubstitutions s subst0 subst1
983+
return (tyB, ghostVarCtxt <> (deleteVar var ghostVarCtxt'), substFinal, elab)
984+
_ -> throw TypeError{ errLoc = s, tyExpected = Box (TyVar $ mkId "a") (TyVar $ mkId "b"), tyActual = ty }
985+
915986
-- Secret syntactic weakening
916987
synthExpr defs gam pol
917988
(App s _ _ (Val _ _ _ (Var _ (sourceName -> "weak__"))) v@(Val _ _ _ (Var _ x))) = do
@@ -1195,7 +1266,7 @@ synthExpr defs gam pol (TryCatch s _ rf e1 p mty e2 e3) = do
11951266

11961267
-- Variables
11971268
synthExpr defs gam _ (Val s _ rf (Var _ x)) = do
1198-
debugM "synthExpr[Var]" (pretty s)
1269+
debugM ("synthExpr[Var] - " <> pretty x) (pretty s)
11991270

12001271
-- Try the local context
12011272
case lookup x gam of
@@ -1387,6 +1458,25 @@ synthExpr defs gam pol (Val s _ rf (Nec _ e)) = do
13871458
let elaborated = Val s finalTy rf (Nec t elaboratedE)
13881459
return (finalTy, gam', subst, elaborated)
13891460

1461+
-- Infer type for references
1462+
synthExpr defs gam pol (Val s _ rf (Ref _ e)) = do
1463+
debugM "synthExpr[Ref]" (pretty s)
1464+
1465+
-- Create a fresh kind variable for this permission
1466+
vark <- freshIdentifierBase $ "kref_[" <> pretty (startPos s) <> "]"
1467+
-- remember this new kind variable in the kind environment
1468+
modify (\st -> st { tyVarContext = (mkId vark, (kguarantee, InstanceQ)) : tyVarContext st })
1469+
1470+
-- Create a fresh permission variable for the permission of the borrowed expression
1471+
var <- freshTyVarInContext (mkId $ "ref_[" <> pretty (startPos s) <> "]") (tyVar vark)
1472+
1473+
-- Synth type of necessitated expression
1474+
(t, gam', subst, elaboratedE) <- synthExpr defs gam pol e
1475+
1476+
let finalTy = Borrow (TyVar var) t
1477+
let elaborated = Val s finalTy rf (Ref t elaboratedE)
1478+
return (finalTy, gam', subst, elaborated)
1479+
13901480
-- BinOp
13911481
synthExpr defs gam pol (Binop s _ rf op e1 e2) = do
13921482
debugM "synthExpr[BinOp]" (pretty s)

frontend/src/Language/Granule/Checker/CoeffectsTypeConverter.hs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
{-# LANGUAGE GADTs #-}
22
module Language.Granule.Checker.CoeffectsTypeConverter(includeOnlyGradeVariables, tyVarContextExistential) where
33

4-
import Control.Monad.Except (catchError)
54
import Control.Monad.State.Strict
65
import Data.Maybe(catMaybes, mapMaybe)
76

87
import Language.Granule.Checker.Monad
98
import Language.Granule.Checker.Predicates
10-
import Language.Granule.Checker.Kinding (checkKind)
9+
import Language.Granule.Checker.Kinding (requiresSolver)
1110

1211
import Language.Granule.Context
1312

@@ -22,9 +21,11 @@ includeOnlyGradeVariables :: (?globals :: Globals)
2221
=> Span -> Ctxt (Type, b) -> Checker (Ctxt (Type, b))
2322
includeOnlyGradeVariables s xs = mapM convert xs >>= (return . catMaybes)
2423
where
25-
convert (var, (t, q)) = (do
26-
k <- checkKind s t kcoeffect <|> checkKind s t keffect
27-
return $ Just (var, (t, q))) `catchError` const (return Nothing)
24+
convert (var, (t, q)) = do
25+
reqSolver <- requiresSolver s t
26+
return $ if reqSolver
27+
then Just (var, (t, q))
28+
else Nothing
2829

2930
tyVarContextExistential :: Checker (Ctxt (Type, Quantifier))
3031
tyVarContextExistential = do

0 commit comments

Comments
 (0)