Ticket #5759 (closed bug: fixed)

Opened 18 months ago

Last modified 18 months ago

Infinite recursion while deriving type

Reported by: Bogdan Owned by:
Priority: normal Milestone:
Component: Compiler Version: 7.0.4
Keywords: Cc:
Operating System: Unknown/Multiple Architecture: Unknown/Multiple
Type of failure: GHC rejects valid program Difficulty: Unknown
Test Case: typecheck/should_run/T5759 Blocked By:
Blocking: Related Tickets:

Description (last modified by simonpj) (diff)

The following code:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, OverlappingInstances,
    UndecidableInstances, FunctionalDependencies #-}

class Container a b | a -> b where
    make :: b -> a

data Cont a = Cont a deriving (Show, Eq)

instance Container (Cont a) a where
    make x = Cont x

instance (Container a b, Show a, Eq a, Num b) => Num a where
    fromInteger x = make (fromInteger x)

d = fromInteger 3 :: Cont Integer

main = do
    print d

produces compilation error:

    Context reduction stack overflow; size = 21
    Use -fcontext-stack=N to increase stack size to N
      $dNum :: Num b19
      [skipped]
      $dNum :: Num b0
    In the first argument of `make', namely `(fromInteger x)'
    In the expression: make (fromInteger x)
    In an equation for `fromInteger':
        fromInteger x = make (fromInteger x)

Why I think this should work: my understanding is that in line fromInteger x = make (fromInteger x) compiler should take into account that

  1. the signature for make is make :: b -> a,
  2. type b is known at the moment of creating instance (because a == Cont Integer, which is an instance of Container (Cont Integer) Integer),

and cast fromInteger x to type b and pass it to make. This seems to be fixed in 7.2.2 (where this code compiles and displays Cont 3), although I did not manage to find any related entry in the changelog.

If one replaces the block instance (Container a b, ... with

class NumEquiv a where
    fromInt :: Integer -> a

instance NumEquiv Integer where
    fromInt = id

instance (Container a b, NumEquiv b) => NumEquiv a where
    fromInt x = make (fromInt x)

(which is the same as the initial code, the only difference being that the target typeclass --- NumEquiv --- is defined locally in the code), the code compiles successfully even on 7.0.4.

Change History

Changed 18 months ago by simonpj

  • difficulty set to Unknown
  • description modified (diff)

Changed 18 months ago by simonpj

  • status changed from new to closed
  • testcase set to typecheck/should_run/T5759
  • resolution set to fixed

Thank you. I think I agree. And happily it works in 7.2 and 7.4. So I'll add the example to the test suite and close the bug as fixed.

Simon

Note: See TracTickets for help on using tickets.