Skip to content

Commit 6ac09ec

Browse files
committed
Lint: Node pattern match uses subtype instead of type equality.
1 parent 27cd500 commit 6ac09ec

File tree

3 files changed

+42
-26
lines changed

3 files changed

+42
-26
lines changed

grin/src/Grin/Lint.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,7 @@ lint warningKinds mTypeEnv exp@(Program exts _) =
318318
lhsType <- normalizeType <$> extract leftExp
319319
pure $ do -- Lint
320320
-- NOTE: This can still give false positive errors, because bottom-up typing can only approximate the result of HPT.
321-
when (sameType expectedPatType lhsType == Just False) $ do
321+
when (subType expectedPatType lhsType == Just False) $ do
322322
warning Semantics $ [beforeMsg $ unwords
323323
["Invalid pattern match for", plainShow lpat ++ "." , "Expected pattern of type:", plainShow expectedPatType ++ ",", "but got:", plainShow lhsType]]
324324

grin/src/Grin/TypeEnv.hs

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ import Data.Map (Map)
1111
import Data.Set (Set)
1212
import Data.Vector (Vector)
1313
import qualified Data.Map as Map
14-
import qualified Data.Set as Set (fromList, toList)
15-
import qualified Data.Vector as Vector (fromList, toList, map)
14+
import qualified Data.Set as Set
15+
import qualified Data.Vector as Vector
1616
import Data.Bifunctor (bimap)
1717
import Data.Monoid
1818
import Data.Maybe (fromMaybe)
@@ -181,6 +181,29 @@ sameType (T_SimpleType T_UnspecifiedLocation) _ = Nothing
181181
sameType _ (T_SimpleType T_UnspecifiedLocation) = Nothing
182182
sameType t1 t2 = Just $ t1 == t2
183183

184+
subType :: Type -> Type -> Maybe Bool
185+
subType (T_SimpleType T_Dead) _ = Nothing
186+
subType _ (T_SimpleType T_Dead) = Nothing
187+
subType (T_SimpleType T_UnspecifiedLocation) _ = Nothing
188+
subType _ (T_SimpleType T_UnspecifiedLocation) = Nothing
189+
subType (T_SimpleType st1) (T_SimpleType st2) = Just $ simpleSubType st1 st2
190+
subType (T_NodeSet t1) (T_NodeSet t2) = do -- t1 <: t2
191+
let ks1 = Map.keysSet t1
192+
let ks2 = Map.keysSet t2
193+
let subset = ks1 `Set.isSubsetOf` ks2
194+
pure $ subset && and [ Vector.length v1 == Vector.length v2
195+
&& (Vector.all id (Vector.zipWith simpleSubType v1 v2))
196+
| (t,v1) <- Map.toList t1
197+
, Just v2 <- pure $ Map.lookup t t2
198+
]
199+
subType _ _ = Nothing
200+
201+
simpleSubType :: SimpleType -> SimpleType -> Bool
202+
simpleSubType T_UnspecifiedLocation (T_Location l) = True
203+
simpleSubType (T_Location ls1) (T_Location ls2) =
204+
(Set.fromList ls1) `Set.isSubsetOf` (Set.fromList ls2)
205+
simpleSubType t1 t2 = t1 == t2
206+
184207
ptrLocations :: TypeEnv -> Name -> [Loc]
185208
ptrLocations te p = case variableType te p of
186209
T_SimpleType (T_Location locs) -> locs

grin/test/LintSpec.hs

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -224,45 +224,38 @@ spec = do
224224
let (_, errors) = lint allWarnings (Just typeEnv) program
225225
lintErrors errors `shouldBe` ["Invalid pattern match for (CInt x). Expected pattern of type: {CInt[T_Dead]}, but got: {CFloat[T_Float]}"]
226226

227-
it "disregards variable patterns" $ do
227+
it "doesn't alert over-approximated binds" $ do
228228
let program = [prog|
229229
main =
230-
n0 <- pure (CInt 0)
231-
n1 <- case n0 of
232-
(CInt c0) -> pure n0
233-
(CFloat c1) ->
234-
a0 <- pure (CFloat 2.0)
235-
pure a0
230+
i <- pure (CInt 1)
231+
f <- pure (CFloat 1.0)
232+
l <- store i
233+
update l f
234+
v <- fetch l
235+
(CFloat f2) <- pure v
236236
pure ()
237237
|]
238238
let typeEnv = inferTypeEnv program
239239
let (_, errors) = lint allWarnings (Just typeEnv) program
240240
lintErrors errors `shouldBe` []
241241

242-
-- NOTE: Bottom-up typing can only approximate the result of HPT.
243-
it "can give false positive errors" $ do
242+
it "disregards variable patterns" $ do
244243
let program = [prog|
245244
main =
246-
n0 <- case 0 of
247-
0 ->
248-
n1 <- pure (CInt 0)
249-
pure n1
250-
1 ->
251-
n2 <- pure (CFloat 0.0)
252-
pure n2
253-
(CInt x) <- case n0 of
245+
n0 <- pure (CInt 0)
246+
n1 <- case n0 of
254247
(CInt c0) -> pure n0
255248
(CFloat c1) ->
256-
a0 <- pure (CInt 0)
249+
a0 <- pure (CFloat 2.0)
257250
pure a0
258251
pure ()
259252
|]
260253
let typeEnv = inferTypeEnv program
261254
let (_, errors) = lint allWarnings (Just typeEnv) program
262-
lintErrors errors `shouldBe` ["Invalid pattern match for (CInt x). Expected pattern of type: {CInt[T_Int64]}, but got: {CFloat[T_Float],CInt[T_Int64]}"]
255+
lintErrors errors `shouldBe` []
263256

264257
describe "Producer lint" $ do
265-
it "finds nodes in single return statment" $ do
258+
it "finds nodes in single return statement" $ do
266259
let program = [prog|
267260
grinMain =
268261
pure (CInt 5)
@@ -271,7 +264,7 @@ spec = do
271264
let (_, errors) = lint allWarnings (Just typeEnv) program
272265
lintErrors errors `shouldBe` ["Last return expressions can only return non-node values: pure (CInt 5)"]
273266

274-
it "finds nodes in last return statment" $ do
267+
it "finds nodes in last return statement" $ do
275268
let program = [prog|
276269
grinMain =
277270
n <- pure (CInt 0)
@@ -281,7 +274,7 @@ spec = do
281274
let (_, errors) = lint allWarnings (Just typeEnv) program
282275
lintErrors errors `shouldBe` ["Last return expressions can only return non-node values: pure (CInt 5)"]
283276

284-
it "finds nodes in single return statment in case alternative" $ do
277+
it "finds nodes in single return statement in case alternative" $ do
285278
let program = [prog|
286279
grinMain =
287280
case 0 of
@@ -291,7 +284,7 @@ spec = do
291284
let (_, errors) = lint allWarnings (Just typeEnv) program
292285
lintErrors errors `shouldBe` ["Last return expressions can only return non-node values: pure (CInt 5)"]
293286

294-
it "finds nodes in last return statment in case alternative" $ do
287+
it "finds nodes in last return statement in case alternative" $ do
295288
let program = [prog|
296289
grinMain =
297290
case 0 of

0 commit comments

Comments
 (0)