|
24 | 24 | {-# LANGUAGE UndecidableSuperClasses #-} |
25 | 25 | {-# LANGUAGE ViewPatterns #-} |
26 | 26 | -- Show Evidence |
27 | | -{-# OPTIONS_GHC -Wno-orphans #-} |
| 27 | +{-# OPTIONS_GHC -Wno-orphans -Wno-unticked-promoted-constructors #-} |
28 | 28 |
|
29 | 29 | -- | This module contains the most basic parts the implementation. Essentially |
30 | 30 | -- everything to define Specification, HasSpec, HasSimpleRep, Term, Pred, and the Syntax, |
@@ -71,6 +71,7 @@ import Constrained.List ( |
71 | 71 | pattern ListCtx, |
72 | 72 | pattern NilCtx, |
73 | 73 | ) |
| 74 | +import Constrained.TypeErrors |
74 | 75 |
|
75 | 76 | import Control.Monad.Writer ( |
76 | 77 | Writer, |
@@ -383,7 +384,66 @@ typeSpec ts = TypeSpec ts mempty |
383 | 384 | -- Don't be afraid of all the methods. Most have default implementations. |
384 | 385 | -- ================================================================= |
385 | 386 |
|
386 | | -class (Typeable a, Eq a, Show a, Show (TypeSpec a), Typeable (TypeSpec a)) => HasSpec a where |
| 387 | +type GenericallyInstantiated a = |
| 388 | + ( AssertComputes |
| 389 | + (SimpleRep a) |
| 390 | + ( Text "Trying to use a generic instantiation of " |
| 391 | + :<>: ShowType a |
| 392 | + :<>: Text ", likely in a HasSpec instance." |
| 393 | + :$$: Text |
| 394 | + "However, the type has no definition of SimpleRep, likely because of a missing instance of HasSimpleRep." |
| 395 | + ) |
| 396 | + , HasSimpleRep a |
| 397 | + , HasSpec (SimpleRep a) |
| 398 | + , TypeSpec a ~ TypeSpec (SimpleRep a) |
| 399 | + ) |
| 400 | + |
| 401 | +type TypeSpecEqShow a = |
| 402 | + ( AssertComputes |
| 403 | + (TypeSpec a) |
| 404 | + ( Text "Can't compute " |
| 405 | + :<>: ShowType (TypeSpec a) |
| 406 | + :$$: Text "Either because of a missing definition of TypeSpec or a missing instance of HasSimpleRep." |
| 407 | + ) |
| 408 | + , Show (TypeSpec a) |
| 409 | + , Typeable (TypeSpec a) |
| 410 | + ) |
| 411 | + |
| 412 | +{- NOTE: type errors in constrained-generators |
| 413 | + It's easy to make a mistake like this: |
| 414 | + data Bad = Bad | Worse deriving (Eq, Show) |
| 415 | + instance HasSpec Bad |
| 416 | + Missing that this requires an instance of HasSimpleRep for Bad to work. |
| 417 | + The two `AssertComputes` uses above are here to give you better error messages when you make this mistake, |
| 418 | + e.g. giving you something like this: |
| 419 | + src/Constrained/Examples/Basic.hs:327:10: error: [GHC-64725] |
| 420 | + • Can't compute TypeSpec (SimpleRep Bad) |
| 421 | + Either because of a missing definition of TypeSpec or a missing instance of HasSimpleRep. |
| 422 | + • In the instance declaration for ‘HasSpec Bad’ |
| 423 | + | |
| 424 | + 327 | instance HasSpec Bad |
| 425 | + | ^^^^^^^^^^^ |
| 426 | +
|
| 427 | + src/Constrained/Examples/Basic.hs:327:10: error: [GHC-64725] |
| 428 | + • Trying to use a generic instantiation of Bad, likely in a HasSpec instance. |
| 429 | + However, the type has no definition of SimpleRep, likely because of a missing instance of HasSimpleRep. |
| 430 | + • In the expression: Constrained.Base.$dmemptySpec @(Bad) |
| 431 | + In an equation for ‘emptySpec’: |
| 432 | + emptySpec = Constrained.Base.$dmemptySpec @(Bad) |
| 433 | + In the instance declaration for ‘HasSpec Bad’ |
| 434 | + | |
| 435 | + 327 | instance HasSpec Bad |
| 436 | + | ^^^^^^^^^^^ |
| 437 | +-} |
| 438 | + |
| 439 | +class |
| 440 | + ( Typeable a |
| 441 | + , Eq a |
| 442 | + , Show a |
| 443 | + , TypeSpecEqShow a |
| 444 | + ) => |
| 445 | + HasSpec a |
| 446 | + where |
387 | 447 | -- | The `TypeSpec a` is the type-specific `Specification a`. |
388 | 448 | type TypeSpec a |
389 | 449 |
|
@@ -489,63 +549,45 @@ class (Typeable a, Eq a, Show a, Show (TypeSpec a), Typeable (TypeSpec a)) => Ha |
489 | 549 | a` using `fromSimpleRepSpec`. |
490 | 550 | -} |
491 | 551 |
|
492 | | - default emptySpec :: |
493 | | - (HasSpec (SimpleRep a), TypeSpec a ~ TypeSpec (SimpleRep a)) => TypeSpec a |
| 552 | + default emptySpec :: GenericallyInstantiated a => TypeSpec a |
494 | 553 | emptySpec = emptySpec @(SimpleRep a) |
495 | 554 |
|
496 | 555 | default combineSpec :: |
497 | | - ( HasSimpleRep a |
498 | | - , HasSpec (SimpleRep a) |
499 | | - , TypeSpec a ~ TypeSpec (SimpleRep a) |
500 | | - ) => |
| 556 | + GenericallyInstantiated a => |
501 | 557 | TypeSpec a -> |
502 | 558 | TypeSpec a -> |
503 | 559 | Specification a |
504 | 560 | combineSpec s s' = fromSimpleRepSpec $ combineSpec @(SimpleRep a) s s' |
505 | 561 |
|
506 | 562 | default genFromTypeSpec :: |
507 | | - ( HasSimpleRep a |
508 | | - , HasSpec (SimpleRep a) |
509 | | - , TypeSpec a ~ TypeSpec (SimpleRep a) |
510 | | - ) => |
511 | | - (HasCallStack, MonadGenError m) => |
| 563 | + (GenericallyInstantiated a, HasCallStack, MonadGenError m) => |
512 | 564 | TypeSpec a -> |
513 | 565 | GenT m a |
514 | 566 | genFromTypeSpec s = fromSimpleRep <$> genFromTypeSpec s |
515 | 567 |
|
516 | 568 | default conformsTo :: |
517 | | - ( HasSimpleRep a |
518 | | - , HasSpec (SimpleRep a) |
519 | | - , TypeSpec a ~ TypeSpec (SimpleRep a) |
520 | | - ) => |
521 | | - HasCallStack => |
| 569 | + (GenericallyInstantiated a, HasCallStack) => |
522 | 570 | a -> |
523 | 571 | TypeSpec a -> |
524 | 572 | Bool |
525 | 573 | a `conformsTo` s = conformsTo (toSimpleRep a) s |
526 | 574 |
|
527 | 575 | default toPreds :: |
528 | | - ( HasSpec (SimpleRep a) |
529 | | - , TypeSpec a ~ TypeSpec (SimpleRep a) |
530 | | - , HasSimpleRep a |
531 | | - ) => |
| 576 | + GenericallyInstantiated a => |
532 | 577 | Term a -> |
533 | 578 | TypeSpec a -> |
534 | 579 | Pred |
535 | 580 | toPreds v s = toPreds (toGeneric_ v) s |
536 | 581 |
|
537 | 582 | default shrinkWithTypeSpec :: |
538 | | - ( HasSpec (SimpleRep a) |
539 | | - , TypeSpec a ~ TypeSpec (SimpleRep a) |
540 | | - , HasSimpleRep a |
541 | | - ) => |
| 583 | + GenericallyInstantiated a => |
542 | 584 | TypeSpec a -> |
543 | 585 | a -> |
544 | 586 | [a] |
545 | 587 | shrinkWithTypeSpec spec a = map fromSimpleRep $ shrinkWithTypeSpec spec (toSimpleRep a) |
546 | 588 |
|
547 | 589 | default cardinalTypeSpec :: |
548 | | - (HasSpec (SimpleRep a), TypeSpec a ~ TypeSpec (SimpleRep a)) => |
| 590 | + GenericallyInstantiated a => |
549 | 591 | TypeSpec a -> |
550 | 592 | Specification Integer |
551 | 593 | cardinalTypeSpec = cardinalTypeSpec @(SimpleRep a) |
|
0 commit comments