Skip to content

Commit afc8779

Browse files
authored
Exclude superclass-generated names in class placeholders (#4902)
* Exclude superclass-generated names in class placeholders Superclasses generate bindings in typeclasses as well. When determining which bindings to create placeholders for, these superclass-generated names need to be excluded. At the time of writing, this corresponds to the `mkSuperDictAuxOcc` function in Occurrence.hs in GHC, see the subsection on `Making system names` for the relevant bit. * Reference GHC issue in superclass binder check
1 parent 32a7d2f commit afc8779

4 files changed

Lines changed: 48 additions & 2 deletions

File tree

plugins/hls-class-plugin/src/Ide/Plugin/Class/Utils.hs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ module Ide.Plugin.Class.Utils where
44

55
import Control.Monad.IO.Class (MonadIO, liftIO)
66
import Control.Monad.Trans.Except
7-
import Data.Char (isAlpha)
7+
import Data.Char (isAlpha, isDigit)
88
import Data.List (isPrefixOf)
99
import Data.String (IsString)
1010
import qualified Data.Text as T
@@ -22,8 +22,20 @@ import Language.LSP.Protocol.Types
2222
bindingPrefix :: IsString s => s
2323
bindingPrefix = "$c"
2424

25+
-- | Superclasses generate bindings in typeclasses as well.
26+
--
27+
-- When determining which bindings to create placeholders for, these
28+
-- superclass-generated names need to be excluded.
29+
-- TODO: This function should be replaced by an equivalent one from GHC:
30+
-- https://gitlab.haskell.org/ghc/ghc/-/issues/27195
31+
isSuperClassesBindingPrefix :: String -> Bool
32+
isSuperClassesBindingPrefix ('$' : 'c' : 'p' : n : _) | isDigit n = True
33+
isSuperClassesBindingPrefix _ = False
34+
2535
isBindingName :: Name -> Bool
26-
isBindingName name = isPrefixOf bindingPrefix $ occNameString $ nameOccName name
36+
isBindingName name =
37+
let bindingName = occNameString $ nameOccName name
38+
in isPrefixOf bindingPrefix bindingName && not (isSuperClassesBindingPrefix bindingName)
2739

2840
-- | Check if some `HasSrcSpan` value in the given range
2941
inRange :: Range -> SrcSpan -> Bool

plugins/hls-class-plugin/test/Main.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ codeActionTests = testGroup
7272
goldenWithClass "Creates a placeholder for '<>'" "T8" "diamond" $
7373
getActionByTitle "Add placeholders for '<>'"
7474
]
75+
, goldenWithClass "Creates a placeholder for type classes with super classes" "T9" "" $
76+
getActionByTitle "Add placeholders for all missing methods"
7577
, goldenWithClass "Don't insert pragma with GHC2021" "InsertWithGHC2021Enabled" "" $
7678
getActionByTitle "Add placeholders for '==' with signature(s)"
7779
, goldenWithClass "Insert pragma if not exist" "InsertWithoutPragma" "" $
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module T9 where
2+
3+
class A a where
4+
a :: a
5+
6+
instance A Int where
7+
a = 1
8+
9+
class (A a) => B a where
10+
{-# MINIMAL b1 #-}
11+
b1 :: a
12+
b2 :: a
13+
b2 = b1
14+
15+
instance B Int where
16+
b1 = _
17+
b2 = _
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
module T9 where
2+
3+
class A a where
4+
a :: a
5+
6+
instance A Int where
7+
a = 1
8+
9+
class (A a) => B a where
10+
{-# MINIMAL b1 #-}
11+
b1 :: a
12+
b2 :: a
13+
b2 = b1
14+
15+
instance B Int where

0 commit comments

Comments
 (0)