Skip to content

Commit

Permalink
Fix #450, check conjunctiveness when splitting
Browse files Browse the repository at this point in the history
Before this commit, there was a bug when checking of whether an unpack was
allowed that lead to code like `let read Get, linear Set = consume Cell`
compiling. This is now fixed so that all types in an unpack needs to be
separated by a conjunction in the capability being unpacked, unless all
the types can safely be (at least locally) aliased.

A known bug is that we also need to check that the modes are preserved
for all types in an upcast, meaning that the `read Get` above should
also be `linear` (assuming `Get` and `Set` are conjunctive in `Cell`).
  • Loading branch information
EliasC committed May 27, 2016
1 parent 72b2be7 commit 9989f4d
Show file tree
Hide file tree
Showing 3 changed files with 33 additions and 3 deletions.
6 changes: 3 additions & 3 deletions src/types/Typechecker/Typechecker.hs
Original file line number Diff line number Diff line change
Expand Up @@ -616,9 +616,9 @@ instance Checkable Expr where
Var{varName} -> (varName, eType)}
localBindings = map extractBindings eVars
varTypes = map snd localBindings
linearTypes <- filterM isLinearType varTypes
when (length linearTypes > 1) $
checkConjunction eType linearTypes
allAliasable <- allM isAliasableType varTypes
unless (allAliasable || length varTypes == 1) $
checkConjunction eType varTypes
(locals, eDecls) <-
local (extendEnvironment localBindings) $
typecheckDecls decls'
Expand Down
25 changes: 25 additions & 0 deletions src/types/Typechecker/Util.hs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module Typechecker.Util(TypecheckM
,CapturecheckM
,whenM
,anyM
,allM
,unlessM
,tcError
,tcWarning
Expand All @@ -24,6 +25,7 @@ module Typechecker.Util(TypecheckM
,isSubordinateType
,isEncapsulatedType
,isThreadType
,isAliasableType
,checkConjunction
) where

Expand Down Expand Up @@ -424,6 +426,23 @@ isThreadType ty
anyM isThreadType (getArgTypes ty)
| otherwise = return $ isThreadRefType ty

isUnsafeType :: Type -> TypecheckM Bool
isUnsafeType ty
| isPassiveClassType ty = do
capability <- findCapability ty
isUnsafeType capability
| otherwise = return $
any isUnsafeRefType $ typeComponents ty

isAliasableType :: Type -> TypecheckM Bool
isAliasableType ty =
anyM (\f -> f ty)
[return . isSafeType
,isThreadType
,isSubordinateType
,isUnsafeType
]

checkConjunction :: Type -> [Type] -> TypecheckM ()
checkConjunction source sinks
| isCompositeType source = do
Expand All @@ -432,6 +451,12 @@ checkConjunction source sinks
(sinks \\ [ty]) ty) sinks
| isPassiveClassType source = do
cap <- findCapability source
when (isIncapability cap) $
tcError $ "Cannot unpack empty capability of class '" ++
show source ++ "'"
when (source `elem` sinks) $
tcError $ "Unpacking of " ++ Ty.showWithKind cap ++
" cannot be inferred. Try adding type annotations"
checkConjunction cap sinks
| otherwise =
return ()
Expand Down
5 changes: 5 additions & 0 deletions src/types/Types.hs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ module Types(
,isThreadRefType
,isReadRefType
,isSubordinateRefType
,isUnsafeRefType
,makeStackbound
,isStackboundType
) where
Expand Down Expand Up @@ -619,6 +620,10 @@ isSubordinateRefType ty
| Just Subordinate <- getMode ty = True
| otherwise = False

isUnsafeRefType ty
| Just Unsafe <- getMode ty = True
| otherwise = False

isCapabilityType Type{inner = CapabilityType{}} = True
isCapabilityType Type{inner = TraitType{}} = True
isCapabilityType Type{inner = EmptyCapability{}} = True
Expand Down

0 comments on commit 9989f4d

Please sign in to comment.