[GHC] #13943: Compiler infinite loop with GHC-8.2

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.1 Component: Compiler | Version: 8.2.1-rc3 Keywords: | Operating System: Unknown/Multiple Architecture: | Type of failure: None/Unknown Unknown/Multiple | Test Case: | Blocked By: Blocking: | Related Tickets: Differential Rev(s): | Wiki Page: -------------------------------------+------------------------------------- GHC-8.0.1 compile this module in less than one seconds on my machine. Both GHC-8.2rc2 and GHC-8.2rc3 eat all 8GB of memory and don't show any signs of stopping. -dshow-passes shows this: {{{ [1 of 1] Compiling Data.List.Unrolled ( unrolled.hs, unrolled.o ) *** Parser [Data.List.Unrolled]: !!! Parser [Data.List.Unrolled]: finished in 0.00 milliseconds, allocated 3.434 megabytes *** Renamer/typechecker [Data.List.Unrolled]: }}} and then nothing. Only memory consumption grows. Code: {{{#!hs {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeInType #-} {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE GADTs #-} module Data.List.Unrolled where import GHC.TypeLits -- | Drop @n@ elements from a list class Drop (n :: Nat) where drop :: [a] -> [a] instance {-# OVERLAPPING #-} Drop 0 where drop xs = xs {-# INLINE drop #-} instance {-# OVERLAPPABLE #-} (Drop (n - 1)) => Drop n where drop [] = [] drop (_ : xs) = drop @(n - 1) xs {-# INLINE drop #-} -- | Take @n@ elements from a list class Take (n :: Nat) where take :: [a] -> [a] instance {-# OVERLAPPING #-} Take 0 where take _ = [] {-# INLINE take #-} instance {-# OVERLAPPABLE #-} (Take (n - 1)) => Take n where take [] = [] take (x : xs) = x : take @(n - 1) xs {-# INLINE take #-} -- | Split list at @n@-th element. splitAt :: forall (n :: Nat) a. (Take n, Drop n) => [a] -> ([a], [a]) splitAt xs = (take @n xs, drop @n xs) -- | Split list into chunks of the given length @c@. @n@ is length of the list. class ChunksOf (n :: Nat) (c :: Nat) where chunksOf :: [a] -> [[a]] instance {-# OVERLAPPING #-} ChunksOf 0 0 where chunksOf _ = [] {-# INLINE chunksOf #-} instance {-# OVERLAPPABLE #-} ChunksOf 0 c where chunksOf _ = [] {-# INLINE chunksOf #-} instance {-# OVERLAPPABLE #-} ChunksOf n 0 where chunksOf _ = [] {-# INLINE chunksOf #-} instance {-# OVERLAPPABLE #-} (Take c, Drop c, ChunksOf (n - 1) c) => ChunksOf n c where chunksOf xs = let (l, r) = splitAt @c xs in l : chunksOf @(n - 1) @c r {-# INLINE chunksOf #-} }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.1 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): This behavior started with commit 748b79741652028827b6225c36b8ab55d22bdeb0 (`Use top-level instances to solve superclasses where possible`). -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.1 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by vagarenko): * related: => #12791 Comment: Indeed, if I add `-fno-solve-constant-dicts` flag or turn off optimizations it compiles. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.1 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by mpickering): The problem is that we are repeatedly able to solves constraints of the form `Take (k - 1)` with the dictionary we have for `Take n` which matches any constraint. We loop forever as we track whether we have previously solved precisely the same constraint rather than used the same dictionary before. I am not sure exactly how best to fix this. This code does use `UndecidableInstances` so it is perhaps not entirely our responsibility to ensure termination but it has not yet been ruled how this flag should interact with `UndecidableInstances`. As an aside, you can also write your program like this which avoids overlapping and undecidable instances by making the recursion clear from the types but admittedly, it is not very convenient to write numbers like this. {{{ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE TypeInType #-} {-# LANGUAGE AllowAmbiguousTypes #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE GADTs #-} module Data.List.Unrolled where import GHC.TypeLits data N = Z | S N -- | Drop @n@ elements from a list class Drop (n :: N) where drop :: [a] -> [a] instance Drop Z where drop xs = xs {-# INLINE drop #-} instance (Drop n) => Drop (S n) where drop [] = [] drop (_ : xs) = drop @n xs {-# INLINE drop #-} -- | Take @n@ elements from a list class Take (n :: N) where take :: [a] -> [a] instance Take Z where take _ = [] {-# INLINE take #-} instance (Take n) => Take (S n) where take [] = [] take (x : xs) = x : take @n xs {-# INLINE take #-} -- | Split list at @n@-th element. splitAt :: forall (n :: N) a. (Take n, Drop n) => [a] -> ([a], [a]) splitAt xs = (take @n xs, drop @n xs) -- | Split list into chunks of the given length @c@. @n@ is length of the list. class ChunksOf (n :: N) (c :: N) where chunksOf :: [a] -> [[a]] instance ChunksOf Z c where chunksOf _ = [] {-# INLINE chunksOf #-} instance (Take c, Drop c, ChunksOf n c) => ChunksOf (S n) c where chunksOf xs = let (l, r) = splitAt @c xs in l : chunksOf @n @c r {-# INLINE chunksOf #-} }}} -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:3 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.1 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by danharaj): * cc: dan@… (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:4 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.1 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): mpickering, would this be fixed by preventing this mechanism from selecting overlappable instances? If so, maybe we should require an overlap pragma for any instance that will be overlapped. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:5 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.1 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by dfeuer): * cc: dfeuer (added) -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:6 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.2 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * milestone: 8.2.1 => 8.2.2 Comment: Given that `UndecidableInstances` is in play here I'm going to declare this non-release-critical and punt to 8.2.2 at the earliest. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:7 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: (none) Type: bug | Status: new Priority: high | Milestone: 8.2.2 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): I think it's basically wrong for the specializer to select a top-level instance that might be overlapped by one that's given. However, it would be very sad to lose this important optimization in the overwhelmingly more common no-overlap case. I think the right goal is this: neither the type checker nor the optimizer should have to bend over backwards to worry about overlapping instances in the common case that there aren't any. I believe that we can look at the future in a few stages: ==== Short term ==== When a potential instance is given, don't specialize to a top-level instance if any of the following hold: - The instance is marked `OVERLAPPABLE` or `OVERLAPS`. - The instance is polymorphic, appears in a module declaring `OverlappingInstances`, and is not marked `INCOHERENT`. - There is a visible overlapping instance that might match. This short-term change doesn't fix the problem in all cases, because an instance declared in a module that doesn't mention overlapping can be overlapped in an importing module anyway. So we should probably add an option to avoid specializing to ''any'' non-`INCOHERENT` polymorphic instance when a given could possibly match. ==== Short-medium term ==== Only allow an instance to be overlapped if it's explicitly marked `OVERLAPPABLE` or `OVERLAPS`. This is a breaking change, and people will gripe, but I don't think there's any less-invasive way to make this even ''moderately'' robust. Most of the rest of this comment is about trying to make things robust even in the more complicated context of `GADTs`, `RankNTypes`, and `ConstraintKinds`. Add a `NO_OVERLAP` class declaration pragma to allow users to decree that overlapping instances for a particular class are prohibited. Question: should the pragma be per-class or per-parameter? I think probably per- parameter. Given {{{#!hs class Foo a {-# NO_OVERLAP #-} b }}} a constraint like `Foo Int b` is much better behaved than one like `Foo a b`. ==== Medium-long term ==== Only allow overlapping instances of a class if the definition of that class is explicitly marked with a pragma. There can be two pragmas, distinguishing ''semantically significant'' overlap from ''performance- only'' overlap. A class allowing semantically significant overlap is really for meta-programming only; trying to do anything fancy with it will ultimately lead to headaches. My guess is that only *monomorphic* constraints involving such a class should be allowed to instantiate constraint variables, appear in GADT constructor constraints, or appear in higher-rank types. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:8 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: dfeuer Type: bug | Status: new Priority: high | Milestone: 8.2.3 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by bgamari): * owner: (none) => dfeuer * milestone: 8.2.2 => 8.2.3 -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:9 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: dfeuer Type: bug | Status: new Priority: high | Milestone: 8.2.3 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by dfeuer): Simon PJ, do you think you should comment on where you want to go with this? I've suggested a short-term sort-of-fix above; is that what you want? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:10 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: dfeuer Type: bug | Status: new Priority: high | Milestone: 8.2.3 Component: Compiler | Version: 8.2.1-rc3 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by simonpj): I'm on this. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:11 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2
-------------------------------------+-------------------------------------
Reporter: vagarenko | Owner: dfeuer
Type: bug | Status: new
Priority: high | Milestone: 8.2.3
Component: Compiler | Version: 8.2.1-rc3
Resolution: | Keywords:
Operating System: Unknown/Multiple | Architecture:
| Unknown/Multiple
Type of failure: None/Unknown | Test Case:
Blocked By: | Blocking:
Related Tickets: #12791 | Differential Rev(s):
Wiki Page: |
-------------------------------------+-------------------------------------
Comment (by Simon Peyton Jones

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: dfeuer Type: bug | Status: closed Priority: high | Milestone: 8.2.3 Component: Compiler | Version: 8.2.1-rc3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: | typecheck/should_compile/T13943 Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by simonpj): * status: new => closed * testcase: => typecheck/should_compile/T13943 * resolution: => fixed Comment:
I think it's basically wrong for the specializer to select a top-level instance that might be overlapped by one that's given
Yes; and it doesn't, in fact. There was just an outright bug, as in the commit message above. Simon -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:13 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: dfeuer Type: bug | Status: merge Priority: high | Milestone: 8.2.3 Component: Compiler | Version: 8.2.1-rc3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: | typecheck/should_compile/T13943 Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by simonpj): * status: closed => merge Comment: I think it'd be fine to merge this to any future 8.2 version. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:14 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: dfeuer Type: bug | Status: merge Priority: high | Milestone: 8.2.3 Component: Compiler | Version: 8.2.1-rc3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: | typecheck/should_compile/T13943 Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by George): fixed in 8.4.1 alpha 3 is there going to be an 8.2.3? if not should the milestone be changed? -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:15 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler

#13943: Compiler infinite loop with GHC-8.2 -------------------------------------+------------------------------------- Reporter: vagarenko | Owner: dfeuer Type: bug | Status: closed Priority: high | Milestone: 8.4.1 Component: Compiler | Version: 8.2.1-rc3 Resolution: fixed | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: | typecheck/should_compile/T13943 Blocked By: | Blocking: Related Tickets: #12791 | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Changes (by RyanGlScott): * status: merge => closed * milestone: 8.2.3 => 8.4.1 Comment: Sounds good. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/13943#comment:16 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler
participants (1)
-
GHC