Skip to content

GitLab

  • Menu
Projects Groups Snippets
  • Help
    • Help
    • Support
    • Community forum
    • Submit feedback
  • Sign in / Register
  • GHC GHC
  • Project information
    • Project information
    • Activity
    • Labels
    • Members
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Locked Files
  • Issues 4,870
    • Issues 4,870
    • List
    • Boards
    • Service Desk
    • Milestones
    • Iterations
  • Merge requests 453
    • Merge requests 453
  • CI/CD
    • CI/CD
    • Pipelines
    • Jobs
    • Schedules
    • Test Cases
  • Deployments
    • Deployments
    • Releases
  • Analytics
    • Analytics
    • Value stream
    • CI/CD
    • Code review
    • Insights
    • Issue
    • Repository
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Activity
  • Graph
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
Collapse sidebar
  • Glasgow Haskell Compiler
  • GHCGHC
  • Issues
  • #19974
Closed
Open
Created Jun 10, 2021 by sheaf@sheafMaintainer

Non-terminating substitution with derived constraints

@rae reports the following issue, introduced by the removal of flattening variables (8bb52d91).

{-# LANGUAGE TypeFamilies, FunctionalDependencies, FlexibleInstances,
             FlexibleContexts, ScopedTypeVariables #-}

module Bug where

type family F a
class C a b | a -> b where
  meth :: a -> b -> ()

g :: forall a b. (F b ~ F a) => a -> b -> ()
g x y = const () (meth True x, meth False y, [undefined :: F a, True])
    * Reduction stack overflow; size = 201
      When simplifying the following type: F a
      Use -freduction-depth=0 to disable this check
      (any upper bound you could choose might fail unpredictably with
       minor updates to GHC, so disabling the check is recommended if
       you're sure that type checking should terminate)
    * In the expression: undefined :: F a
      In the expression: [undefined :: F a, True]
      In the second argument of `const', namely
        `(meth True x, meth False y, [undefined :: F a, True])'
   |
11 | g x y = const () (meth True x, meth False y, [undefined :: F a, True])
   |                                               ^^^^^^^^^^^^^^^^

The problem is that we end up with inerts:

[G] co {0} :: F b[sk:1] ~# F a[sk:1] (CEqCan)
[D] _ {0}:: a[sk:1] ~# b[sk:1] (CEqCan)

and work item

[D] _ {0}:: F a[sk:1] ~# Bool (CEqCan)

This causes a loop as the substitution associated to the inert set is not terminating, rewriting F a to F b (using the Derived) then back to F a (using the Given).


Note that a similar situation can happen if we allow Wanteds to rewrite Wanteds (see test case T3440):

 type family Fam a :: Type

 data GADT :: Type -> Type where
   GADT :: a -> Fam a -> GADT (Fam a)

 unwrap :: GADT (Fam a) -> (a, Fam a)
 unwrap (GADT x y) = (x, y)

In that case we end up with inert set

[G] F b[sk:1] ~# F a[sk:1] (CEqCan)
[W] a[sk:1] ~# b[sk:1] (CEqCan)

which causes the same loop when trying to rewrite another wanted involving a or b.

Edited Jun 30, 2021 by sheaf
To upload designs, you'll need to enable LFS and have an admin enable hashed storage. More information
Assignee
Assign to
Time tracking