Skip to content

Commit

Permalink
Fix termination crash due to empty permutation (#3081)
Browse files Browse the repository at this point in the history
- Fixes #3064
  • Loading branch information
janmasrovira authored Oct 2, 2024
1 parent a192654 commit 137b6d8
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -131,37 +131,48 @@ recursiveBehaviour re =
(re ^. reflexiveEdgeFun)
(map callMatrixDiag (toList $ re ^. reflexiveEdgeMatrices))

type SparseMatrix = [[Indexed SizeRel]]

findOrder :: RecursiveBehaviour -> Maybe LexOrder
findOrder rb = LexOrder <$> listToMaybe (mapMaybe (isLexOrder >=> nonEmpty) allPerms)
where
b0 :: [[SizeRel]]
b0 = rb ^. recursiveBehaviourMatrix

indexed = map (zip [0 :: Int ..] . take minLength) b0
indexed = map (indexFrom 0 . take minLength) b0
where
minLength = minimum (map length b0)

startB :: SparseMatrix
startB = removeUselessColumns indexed

-- removes columns that don't have at least one ≺ in them
removeUselessColumns :: [[(Int, SizeRel)]] -> [[(Int, SizeRel)]]
removeUselessColumns = transpose . filter (any (isLess . snd)) . transpose
-- removes columns that don't have at least one ≺ in them because we know
-- they'll never contribute to finding a decreasing lex order
removeUselessColumns :: SparseMatrix -> SparseMatrix
removeUselessColumns = transpose . filter (any (isLess . getRel)) . transpose

getIx :: Indexed SizeRel -> Int
getIx = (^. indexedIx)

getRel :: Indexed SizeRel -> SizeRel
getRel = (^. indexedThing)

isLexOrder :: [Int] -> Maybe [Int]
isLexOrder = go startB
where
go :: [[(Int, SizeRel)]] -> [Int] -> Maybe [Int]
go :: SparseMatrix -> [Int] -> Maybe [Int]
go [] _ = Just []
go b perm = case perm of
[] -> error "The permutation should have one element at least!"
(p0 : ptail)
| Just r <- find (isLess . snd . (!! p0)) b,
all (notNothing . snd . (!! p0)) b,
[] -> Nothing
p0 : ptail
| Just r <- find (isLess . getRel . (!! p0)) b,
all (notNothing . getRel . (!! p0)) b,
Just perm' <- go (b' p0) (map pred ptail) ->
Just (fst (r !! p0) : perm')
Just (getIx (r !! p0) : perm')
| otherwise -> Nothing
where
b' i = map r' (filter (not . isLess . snd . (!! i)) b)
b' :: Int -> SparseMatrix
b' i = map r' (filter (not . isLess . getRel . (!! i)) b)
where
r' r = case splitAt i r of
(x, y) -> x ++ drop 1 y
Expand Down
6 changes: 5 additions & 1 deletion test/Typecheck/Positive.hs
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,11 @@ tests =
posTest
"Default argument with trait in signature"
$(mkRelDir ".")
$(mkRelFile "issue2994.juvix")
$(mkRelFile "issue2994.juvix"),
posTest
"Termination crash because of empty permutation"
$(mkRelDir ".")
$(mkRelFile "issue3064.juvix")
]
<> [ compilationTest t | t <- Compilation.tests
]
35 changes: 35 additions & 0 deletions tests/positive/issue3064.juvix
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
module issue3064;

import Stdlib.Prelude open;

type Expression :=
-- Put both of these into a Const type
| Const Nat
| Str String
| Var String
| Lam String Expression
| App Expression Expression;

axiom undefined : {A : Type} -> A;

Environment : Type := List (Pair String Expression) ;

type Return :=
| RNatural Nat
| RString String;

terminating eval (env : Environment) : Expression -> Maybe Return
| (Const x) := RNatural x |> just
| (Str str) := RString str |> just
| (App f x) := eval-lookup env f x
| (Var var) := lookup-var env var >>= eval env
| _ := undefined;

eval-lookup (env : Environment) (f : Expression) (x : Expression) : Maybe Return :=
let recursive : _ -- Expression -> Return
| (Lam variable body) := eval ((variable , x) :: env) body
| _ := undefined;
in recursive f;

lookup-var (env : Environment) (to-lookup : String) : Maybe Expression
:= (snd <$> find \{ x := fst x == to-lookup } env);

0 comments on commit 137b6d8

Please sign in to comment.