10
10
{-# LANGUAGE OverloadedStrings #-}
11
11
{-# LANGUAGE PartialTypeSignatures #-}
12
12
{-# LANGUAGE PatternSynonyms #-}
13
+ {-# LANGUAGE PolyKinds #-}
13
14
{-# LANGUAGE QuantifiedConstraints #-}
14
15
{-# LANGUAGE RankNTypes #-}
15
16
{-# LANGUAGE ScopedTypeVariables #-}
23
24
{-# OPTIONS_GHC -Wno-orphans #-}
24
25
{-# OPTIONS_GHC -Wno-redundant-constraints #-}
25
26
26
- -- The pattern completeness checker is much weaker before ghc-9.0. Rather than introducing redundant
27
- -- cases and turning off the overlap check in newer ghc versions we disable the check for old
28
- -- versions.
29
- #if __GLASGOW_HASKELL__ < 900
30
- {-# OPTIONS_GHC -Wno-incomplete-patterns #-}
31
- #endif
32
-
33
27
module Constrained.Spec.SumProd (
34
28
IsNormalType ,
29
+ ProdAsListComputes ,
35
30
caseOn ,
36
31
branch ,
37
32
branchW ,
@@ -133,6 +128,7 @@ import Constrained.TheKnot (
133
128
prodSnd_ ,
134
129
prod_ ,
135
130
)
131
+ import Constrained.TypeErrors
136
132
import Data.Typeable (Typeable )
137
133
import GHC.TypeLits (Symbol )
138
134
import GHC.TypeNats
@@ -250,20 +246,43 @@ type family ResultType t where
250
246
ResultType (a -> b ) = ResultType b
251
247
ResultType a = a
252
248
253
- type IsNormalType a = (Cases a ~ '[a ], Args a ~ '[a ], IsProd a , CountCases a ~ 1 )
249
+ type IsNormalType a =
250
+ ( AssertComputes
251
+ (Cases a )
252
+ ( Text " Failed to compute Cases in a use of IsNormalType for "
253
+ :$$: ShowType a
254
+ :<>: Text " , are you missing an IsNormalType constraint?"
255
+ )
256
+ , Cases a ~ '[a ]
257
+ , AssertComputes
258
+ (Args a )
259
+ ( Text " Failed to compute Args in a use of IsNormalType for "
260
+ :<>: ShowType a
261
+ :<>: Text " , are you missing an IsNormalType constraint?"
262
+ )
263
+ , Args a ~ '[a ]
264
+ , IsProd a
265
+ , CountCases a ~ 1
266
+ )
254
267
255
268
type family Cases t where
256
269
Cases (Sum a b ) = a : Cases b
257
270
Cases a = '[a ]
258
271
259
272
type IsProductType a =
260
273
( HasSimpleRep a
274
+ , AssertComputes
275
+ (Cases (SimpleRep a ))
276
+ ( Text " Failed to compute Cases in a use of IsProductType for "
277
+ :$$: ShowType a
278
+ :<>: Text " , are you missing an IsProductType constraint?"
279
+ )
261
280
, Cases (SimpleRep a ) ~ '[SimpleRep a ]
262
281
, SimpleRep a ~ SumOver (Cases (SimpleRep a ))
263
282
, IsProd (SimpleRep a )
264
283
, HasSpec (SimpleRep a )
265
284
, TypeSpec a ~ TypeSpec (SimpleRep a )
266
- , All HasSpec (ProductAsList a )
285
+ , All HasSpec (Args ( SimpleRep a ) )
267
286
)
268
287
269
288
type ProductAsList a = Args (SimpleRep a )
@@ -472,15 +491,45 @@ branchW ::
472
491
branchW w body =
473
492
Weighted (Just w) (bind (buildBranch @ p body . toArgs @ a ))
474
493
494
+ -- | ProdAsListComputes is here to make sure that in situations like this:
495
+ --
496
+ -- > type family Foobar k
497
+ -- >
498
+ -- > ex :: HasSpec (Foobar k) => Specification (Int, Foobar k)
499
+ -- > ex = constrained $ \ p -> match p $ \ i _ -> (i ==. 10)
500
+ --
501
+ -- Where you're trying to work with an unevaluated type family in constraints.
502
+ -- You get reasonable type errors prompting you to add the @IsNormalType (Foobar k)@ constraint
503
+ -- like this:
504
+ --
505
+ -- > • Type list computation is stuck on
506
+ -- > Args (Foobar k)
507
+ -- > Have you considered adding an IsNormalType or ProdAsListComputes constraint?
508
+ -- > • In the first argument of ‘($)’, namely ‘match p’
509
+ -- > In the expression: match p $ \ i _ -> (i ==. 10)
510
+ -- > In the second argument of ‘($)’, namely
511
+ -- > ‘\ p -> match p $ \ i _ -> (i ==. 10)’
512
+ -- > |
513
+ -- > 503 | ex = constrained $ \ p -> match p $ \ i _ -> (i ==. 10)
514
+ -- > | ^^^^^
515
+ --
516
+ -- Which should help you come to the conclusion that you need to do something
517
+ -- like this for everything to compile:
518
+ --
519
+ -- > ex :: (HasSpec (Foobar k), IsNormalType (Foobar k)) => Specification (Int, Foobar k)
520
+ type ProdAsListComputes a =
521
+ AssertSpineComputes
522
+ (Text " Have you considered adding an IsNormalType or ProdAsListComputes constraint?" )
523
+ (ProductAsList a )
524
+
475
525
match ::
476
526
forall p a .
477
527
( IsProductType a
478
528
, IsPred p
479
529
, GenericRequires a
530
+ , ProdAsListComputes a
480
531
) =>
481
- Term a ->
482
- FunTy (MapList Term (ProductAsList a )) p ->
483
- Pred
532
+ Term a -> FunTy (MapList Term (ProductAsList a )) p -> Pred
484
533
match p m = caseOn p (branch @ p m)
485
534
486
535
-- NOTE: `ResultType r ~ Term a` is NOT a redundant constraint,
@@ -536,11 +585,13 @@ forAll' ::
536
585
, All HasSpec (Args (SimpleRep a ))
537
586
, IsPred p
538
587
, IsProd (SimpleRep a )
588
+ , IsProductType a
539
589
, HasSpec a
540
590
, GenericRequires a
591
+ , ProdAsListComputes a
541
592
) =>
542
593
Term t ->
543
- FunTy (MapList Term (Args ( SimpleRep a ) )) p ->
594
+ FunTy (MapList Term (ProductAsList a )) p ->
544
595
Pred
545
596
forAll' xs f = forAll xs $ \ x -> match @ p x f
546
597
@@ -554,10 +605,12 @@ constrained' ::
554
605
, All HasSpec (Args (SimpleRep a ))
555
606
, IsProd (SimpleRep a )
556
607
, HasSpec a
608
+ , IsProductType a
557
609
, IsPred p
558
610
, GenericRequires a
611
+ , ProdAsListComputes a
559
612
) =>
560
- FunTy (MapList Term (Args ( SimpleRep a ) )) p ->
613
+ FunTy (MapList Term (ProductAsList a )) p ->
561
614
Specification a
562
615
constrained' f = constrained $ \ x -> match @ p x f
563
616
@@ -572,12 +625,15 @@ reify' ::
572
625
, IsProd (SimpleRep b )
573
626
, HasSpec a
574
627
, HasSpec b
628
+ , IsProductType b
629
+ , IsProd a
575
630
, IsPred p
576
631
, GenericRequires b
632
+ , ProdAsListComputes b
577
633
) =>
578
634
Term a ->
579
635
(a -> b ) ->
580
- FunTy (MapList Term (Args ( SimpleRep b ) )) p ->
636
+ FunTy (MapList Term (ProductAsList b )) p ->
581
637
Pred
582
638
reify' a r f = reify a r $ \ x -> match @ p x f
583
639
0 commit comments