packages feed

ghc-typelits-natnormalise-0.9.6: tests/ShouldError.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE QuasiQuotes #-}

module ShouldError (tests) where

import Data.String.Interpolate (i)
import ShouldError.Tasty (assertCompileError)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.HUnit (testCase)

tests :: TestTree
tests = testGroup "ShouldError"
    [ test1
    , test2
    , test3
    , test4
    , test5
    , test6
    , test7
    , test8
    , test9
    , test10
    , test11
    , testIssue126
    , inequalityTests
    ]

preamble :: String
preamble = [i|
import Data.Kind (Constraint)
import Data.Proxy
import GHC.TypeLits
|] <> "\n"

source1 :: String
source1 = preamble <> [i|
test :: Proxy (x + 1) -> Proxy (2 + x)
test = id
|]

expected1 :: [String]
expected1 =
#if __GLASGOW_HASKELL__ >= 914
  ["Expected: Proxy (2 + x)"
  ,"  Actual: Proxy (x + 1)"
  ]
#elif __GLASGOW_HASKELL__ >= 900
  ["Expected: Proxy (x + 1) -> Proxy (2 + x)"
  ,"  Actual: Proxy (x + 1) -> Proxy (x + 1)"
  ]
#else
  ["Expected type: Proxy (x + 1) -> Proxy (2 + x)"
  ,"Actual type: Proxy (2 + x) -> Proxy (2 + x)"
  ]
#endif

test1 :: TestTree
test1 = testCase "x + 1 /~ 2 + x" $ assertCompileError source1 expected1

source2 :: String
source2 = preamble <> [i|
type family GCD (x :: Nat) (y :: Nat) :: Nat
type instance GCD 6 8 = 2
type instance GCD 9 6 = 3

test :: Proxy (GCD 6 8 + x) -> Proxy (x + GCD 9 6)
test = id
|]

expected2 :: [String]
expected2 =
#if __GLASGOW_HASKELL__ >= 914
  ["Expected: Proxy (x + GCD 9 6)"
  ,"  Actual: Proxy (2 + x)"
  ]
#elif __GLASGOW_HASKELL__ >= 900
  ["Expected: Proxy (GCD 6 8 + x) -> Proxy (x + GCD 9 6)"
  ,"  Actual: Proxy (2 + x) -> Proxy (2 + x)"
  ]
#else
  ["Expected type: Proxy (GCD 6 8 + x) -> Proxy (x + GCD 9 6)"
  ,"Actual type: Proxy (x + 3) -> Proxy (x + 3)"
  ]
#endif

test2 :: TestTree
test2 = testCase "GCD 6 8 + x /~ x + GCD 9 6" $ assertCompileError source2 expected2

source3 :: String
source3 = preamble <> [i|
proxyFun :: Proxy (x + x + x) -> ()
proxyFun = const ()

test :: Proxy 8 -> ()
test = proxyFun
|]

expected3 :: [String]
expected3 =
#if __GLASGOW_HASKELL__ >= 914
  ["Expected: Proxy ((x0 + x0) + x0)"
  ,"  Actual: Proxy 8"
  ]
#elif __GLASGOW_HASKELL__ >= 900
  ["Expected: Proxy 8 -> ()"
  ,"  Actual: Proxy ((x0 + x0) + x0) -> ()"
  ]
#else
  ["Expected type: Proxy 8 -> ()"
  ,"Actual type: Proxy ((x0 + x0) + x0) -> ()"
  ]
#endif

test3 :: TestTree
test3 = testCase "Unify \"x + x + x\" with \"8\"" $ assertCompileError source3 expected3

source4 :: String
source4 = preamble <> [i|
proxyFun :: Proxy ((2*y)+4) -> ()
proxyFun = const ()

test :: Proxy 2 -> ()
test = proxyFun
|]

expected4 :: [String]
expected4 =
#if __GLASGOW_HASKELL__ >= 914
  ["Expected: Proxy ((2 * y0) + 4)"
  ,"  Actual: Proxy 2"
  ]
#elif __GLASGOW_HASKELL__ >= 900
  ["Expected: Proxy 2 -> ()"
  ,"  Actual: Proxy ((2 * y0) + 4) -> ()"
  ]
#else
  ["Expected type: Proxy 2 -> ()"
  ,"Actual type: Proxy ((2 * y0) + 4) -> ()"
  ]
#endif

test4 :: TestTree
test4 = testCase "Unify \"(2*x)+4\" with \"2\"" $ assertCompileError source4 expected4

source5 :: String
source5 = preamble <> [i|
proxyFun :: Proxy ((2*y)+4) -> ()
proxyFun = const ()

test :: Proxy 7 -> ()
test = proxyFun
|]

expected5 :: [String]
expected5 =
#if __GLASGOW_HASKELL__ >= 914
  ["Expected: Proxy ((2 * y"
  ,"Actual: Proxy 7"
  ]
#elif __GLASGOW_HASKELL__ >= 900
  ["Expected: Proxy 7 -> ()"
  ,"Actual: Proxy ((2 * y"
  ]
#else
  ["Expected type: Proxy 7 -> ()"
  ,"Actual type: Proxy ((2 * y"
  ]
#endif

test5 :: TestTree
test5 = testCase "Unify \"(2*x)+4\" with \"7\"" $ assertCompileError source5 expected5

source6 :: String
source6 = preamble <> [i|
proxyFun :: Proxy (2^k) -> Proxy (2^k)
proxyFun = const Proxy

test :: Proxy 7
test = proxyFun (Proxy :: Proxy 7)
|]

expected6 :: [String]
expected6 =
#if __GLASGOW_HASKELL__ >= 902
  ["Expected: Proxy 7"
  ,"  Actual: Proxy (2 ^ k0)"
  ]
#elif __GLASGOW_HASKELL__ >= 900
  ["Expected: Proxy (2 ^ k0)"
  ,"  Actual: Proxy 7"
  ]
#else
  ["Expected type: Proxy (2 ^ k0)"
  ,"Actual type: Proxy 7"
  ]
#endif

test6 :: TestTree
test6 = testCase "Unify \"2^k\" with \"7\"" $ assertCompileError source6 expected6

source7 :: String
source7 = preamble <> [i|
test :: Proxy x -> Proxy (y + x)
test = id
|]

expected7 :: [String]
expected7 =
#if __GLASGOW_HASKELL__ >= 914
  ["Expected: Proxy (y + x)"
  ,"  Actual: Proxy x"
  ]
#elif __GLASGOW_HASKELL__ >= 900
  ["Expected: Proxy x -> Proxy (y + x)"
  ,"  Actual: Proxy x -> Proxy x"
  ]
#else
  ["Expected type: Proxy x -> Proxy (y + x)"
  ,"Actual type: Proxy x -> Proxy x"
  ]
#endif

test7 :: TestTree
test7 = testCase "x /~ y + x" $ assertCompileError source7 expected7

source8 :: String
source8 = preamble <> [i|
type family CLog (b :: Nat) (x :: Nat) :: Nat
type instance CLog 2 2 = 1

test :: (CLog 2 (2 ^ n) ~ n, (1 <=? n) ~ True) => Proxy n -> Proxy (n+d)
test = id
|]

expected8 :: [String]
expected8 =
#if __GLASGOW_HASKELL__ >= 914
  ["Expected: Proxy (n + d)"
  ,"  Actual: Proxy n"
  ]
#elif __GLASGOW_HASKELL__ >= 900
  ["Expected: Proxy n -> Proxy (n + d)"
  ,"  Actual: Proxy n -> Proxy n"
  ]
#else
  ["Expected type: Proxy n -> Proxy (n + d)"
  ,"Actual type: Proxy n -> Proxy n"
  ]
#endif

test8 :: TestTree
test8 = testCase "(CLog 2 (2 ^ n) ~ n, (1 <=? n) ~ True) => n /~ n + d" $
  assertCompileError source8 expected8

source9 :: String
source9 = preamble <> [i|
data Fin (n :: Nat) where
  FZ :: Fin (n + 1)
  FS :: Fin n -> Fin (n + 1)

test :: forall n . Integer -> Fin n
test n = case n of
  0 -> FZ
  x -> FS (test @(n-1) (x-1))
|]

expected9 :: [String]
expected9 =
#if __GLASGOW_HASKELL__ >= 904
  ["Cannot satisfy: 1 <= n"]
#elif __GLASGOW_HASKELL__ >= 902
  [ "Couldn't match type Data.Type.Ord.OrdCond"
  , "(CmpNat 1 n) True True False"
  , "with True"
  ]
#else
  [ "Couldn't match type 1 <=? n with True" ]
#endif

test9 :: TestTree
test9 = testCase "(n - 1) + 1 ~ n implies (1 <= n)" $ assertCompileError source9 expected9

source10 :: String
source10 = preamble <> [i|
type family Drop (n :: Nat) (xs :: [Nat]) :: [Nat] where
  Drop 0 xs = xs
  Drop n (x ': xs) = Drop (n-1) xs
  Drop n '[] = '[]

test :: Proxy ns -> Proxy (Drop 1 ns) -> Proxy (Drop 2 ns)
test _ px = px
|]

expected10 :: [String]
expected10 =
#if __GLASGOW_HASKELL__ >= 811
  [ "Couldn't match type: Drop 1 ns"
  , "               with: Drop 2 ns"
  , "Expected: Proxy (Drop 2 ns)"
  , "  Actual: Proxy (Drop 1 ns)"
  , "Drop is a non-injective type family"
  ]
#else
  [ "Couldn't match type Drop 1 ns with Drop 2 ns"
  , "Expected type: Proxy (Drop 2 ns)"
  , "  Actual type: Proxy (Drop 1 ns)"
  , "Drop is a non-injective type family"
  ]
#endif

test10 :: TestTree
test10 = testCase "Do not unify in non-injective positions" $ assertCompileError source10 expected10

source11 :: String
source11 = preamble <> [i|
test :: Proxy a -> Proxy b -> Proxy ((2 * a) + b) -> Proxy 5
test _ _ = id
|]

expected11 :: [String]
expected11 =
#if __GLASGOW_HASKELL__ >= 914
  ["Expected: Proxy 5"
  ,"  Actual: Proxy ((2 * a) + b)"
  ]
#elif __GLASGOW_HASKELL__ >= 900
  ["Expected: Proxy ((2 * a) + b) -> Proxy 5"
  ,"  Actual: Proxy 5 -> Proxy 5"
  ]
#else
  ["Expected type: Proxy ((2 * a) + b) -> Proxy 5"
  ,"Actual type: Proxy 5 -> Proxy 5"
  ]
#endif

test11 :: TestTree
test11 = testCase "Do not rewrite constraint to itself" $ assertCompileError source11 expected11

-- ((3 * (n - 1)) + 1) simplifies to (3 * n - 2), so
-- the equality would require b0 ~ -2, which is impossible at kind Nat.
sourceIssue126 :: String
sourceIssue126 = preamble <> [i|
data Index (n :: Nat) = Index

truncateB :: Index (a + b) -> Index a
truncateB = undefined

mul :: Index 4 -> Index n -> Index ((3 * (n - 1)) + 1)
mul _ _ = Index

zeroExtendTimesThree :: (1 <= n) => Index n -> Index (n * 3)
zeroExtendTimesThree = truncateB . (mul Index)
|]

expectedIssue126 :: [String]
expectedIssue126 =
#if __GLASGOW_HASKELL__ >= 906
  [ "Could not deduce ((n * 3) + b0) ~ ((3 * (n - 1)) + 1)"
#elif __GLASGOW_HASKELL__ >= 904
  [ "Could not deduce (((n * 3) + b0) ~ ((3 * (n - 1)) + 1))"
#elif __GLASGOW_HASKELL__ >= 902
  [ "Could not deduce: ((n * 3) + b0) ~ ((3 * (n - 1)) + 1)"
#else
  [ "Could not deduce: ((3 * (n - 1)) + 1) ~ ((n * 3) + b0)"
#endif
  , "from the context: 1 <= n"
  ]



testIssue126 :: TestTree
testIssue126 =
  testCase "Issue 126 regression reproducer" $
    assertCompileError sourceIssue126 expectedIssue126

proxyInEqDef :: String
proxyInEqDef =
#if __GLASGOW_HASKELL__ >= 904
  [i|
proxyInEq :: ((a <= b) ~ (() :: Constraint)) => Proxy (a :: Nat) -> Proxy b -> ()
proxyInEq _ _ = ()
|]
#else
  [i|
proxyInEq :: (a <= b) => Proxy (a :: Nat) -> Proxy b -> ()
proxyInEq _ _ = ()
|]
#endif

proxyInEq'Def :: String
proxyInEq'Def = [i|
proxyInEq' :: ((a <=? b) ~ 'False) => Proxy (a :: Nat) -> Proxy b -> ()
proxyInEq' _ _ = ()
|]

source12 :: String
source12 = preamble <> proxyInEqDef <> proxyInEq'Def <> [i|
test :: Proxy (a + 1) -> Proxy a -> ()
test = proxyInEq
|]

expected12 :: [String]
expected12 =
#if __GLASGOW_HASKELL__ >= 904
  ["Cannot satisfy: a + 1 <= a"]
#elif __GLASGOW_HASKELL__ >= 902
  [ "Couldn't match type Data.Type.Ord.OrdCond"
  , "(CmpNat (a + 1) a) True True False"
  , "with True"
  ]
#else
  [ "Couldn't match type (a + 1) <=? a with True" ]
#endif

test12 :: TestTree
test12 = testCase "a+1 <= a" $ assertCompileError source12 expected12

source13 :: String
source13 = preamble <> proxyInEqDef <> proxyInEq'Def <> [i|
test :: Proxy (a :: Nat) -> Proxy (a + 2) -> ()
test = proxyInEq'
|]

expected13 :: [String]
expected13 =
#if __GLASGOW_HASKELL__ >= 902
  [ "Data.Type.Ord.OrdCond"
  , "(CmpNat a (a + 2)) True True False"
  , "with False"
  ]
#else
  [ "Couldn't match type a <=? (a + 2) with False" ]
#endif

test13 :: TestTree
test13 = testCase "(a <=? a+1) ~ False" $ assertCompileError source13 expected13

source14 :: String
source14 = preamble <> proxyInEqDef <> proxyInEq'Def <> [i|
test :: Proxy (a :: Nat) -> Proxy a -> ()
test = proxyInEq'
|]

expected14 :: [String]
expected14 = [ "Couldn't match type True with False" ]

test14 :: TestTree
test14 = testCase "(a <=? a) ~ False" $ assertCompileError source14 expected14

source15 :: String
source15 = preamble <> proxyInEqDef <> proxyInEq'Def <> [i|
test :: Proxy (a + b) -> Proxy (a + c) -> ()
test = proxyInEq
|]

expected15 :: [String]
expected15 =
#if __GLASGOW_HASKELL__ >= 904
  ["Cannot satisfy: a + b <= a + c"]
#elif __GLASGOW_HASKELL__ >= 902
  [ "Couldn't match type Data.Type.Ord.OrdCond"
  , "(CmpNat (a + b) (a + c)) True True False"
  , "with True"
  ]
#else
  [ "Couldn't match type (a + b) <=? (a + c) with True" ]
#endif

test15 :: TestTree
test15 = testCase "() => (a+b <= a+c)" $ assertCompileError source15 expected15

source16 :: String
source16 = preamble <> proxyInEqDef <> proxyInEq'Def <> [i|
test :: Proxy (4*a) -> Proxy (2*a) -> ()
test = proxyInEq
|]

expected16 :: [String]
expected16 =
#if __GLASGOW_HASKELL__ >= 904
  ["Cannot satisfy: 4 * a <= 2 * a"]
#elif __GLASGOW_HASKELL__ >= 902
  [ "Couldn't match type Data.Type.Ord.OrdCond"
  , "(CmpNat (4 * a) (2 * a)) True True False"
  , "with True"
  ]
#else
  [ "Couldn't match type (4 * a) <=? (2 * a) with True" ]
#endif

test16 :: TestTree
test16 = testCase "4a <= 2a" $ assertCompileError source16 expected16

source17 :: String
source17 = preamble <> proxyInEqDef <> proxyInEq'Def <> [i|
test :: Proxy (2*a) -> Proxy (4*a) -> ()
test = proxyInEq'
|]

expected17 :: [String]
expected17 =
#if __GLASGOW_HASKELL__ >= 902
  [ "Data.Type.Ord.OrdCond"
  , "(CmpNat (2 * a) (4 * a)) True True False"
  , "with False"
  ]
#else
  [ "Couldn't match type (2 * a) <=? (4 * a) with False" ]
#endif

test17 :: TestTree
test17 = testCase "2a <=? 4a ~ False" $ assertCompileError source17 expected17

source18 :: String
source18 = preamble <> [i|
data Boo (n :: Nat) = Boo

test :: Show (Boo n) => Proxy n -> Boo (n - 1 + 1) -> String
test = const show
|]

expected18 :: [String]
expected18 = expected9

test18 :: TestTree
test18 = testCase "Show (Boo n) => Show (Boo (n - 1 + 1))" $ assertCompileError source18 expected18

test19fDef :: String
test19fDef =
#if __GLASGOW_HASKELL__ >= 904
  [i|
test19f :: ((1 <= n) ~ (() :: Constraint)) => Proxy n -> Proxy n
test19f = id
|]
#else
  [i|
test19f :: (1 <= n) => Proxy n -> Proxy n
test19f = id
|]
#endif

source19 :: String
source19 = preamble <> test19fDef <> [i|
test :: (1 <= m, m <= rp) => Proxy m -> Proxy rp -> Proxy (rp - m) -> Proxy (rp - m)
test _ _ = test19f
|]

expected19 :: [String]
expected19 =
#if __GLASGOW_HASKELL__ >= 904
  [ "Cannot satisfy: 1 <= rp - m" ]
#elif __GLASGOW_HASKELL__ >= 902
  [ "Could not deduce: Data.Type.Ord.OrdCond"
  , "(CmpNat 1 (rp - m)) True True False"
  , "~ True"
  ]
#else
  [ "Could not deduce: (1 <=? (rp - m)) ~ True" ]
#endif

test19 :: TestTree
test19 = testCase "1 <= m, m <= rp implies 1 <= rp - m" $ assertCompileError source19 expected19

source20 :: String
source20 = preamble <> proxyInEqDef <> [i|
test :: Proxy 1 -> Proxy (m ^ 2) -> ()
test = proxyInEq
|]

expected20 :: [String]
expected20 =
#if __GLASGOW_HASKELL__ >= 904
  ["Cannot satisfy: 1 <= m ^ 2"]
#elif __GLASGOW_HASKELL__ >= 902
  [ "Couldn't match type Data.Type.Ord.OrdCond"
  , "(CmpNat 1 (m ^ 2)) True True False"
  , "with True"
  ]
#else
  [ "Couldn't match type 1 <=? (m ^ 2) with True" ]
#endif

test20 :: TestTree
test20 = testCase "Vacuously: 1 <= m ^ 2 ~ True" $ assertCompileError source20 expected20

inequalityTests :: TestTree
inequalityTests = testGroup "Inequality"
  [ test12
  , test13
  , test14
  , test15
  , test16
  , test17
  , test18
  , test19
  , test20
  ]