Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Makes dictionary argument exclusion logic in Tactic plugin more robust #508

Merged
merged 9 commits into from
Nov 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 25 additions & 7 deletions plugins/tactics/src/Ide/Plugin/Tactic/CodeGen.hs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import GHC.SourceGen.Binds
import GHC.SourceGen.Expr
import GHC.SourceGen.Overloaded
import GHC.SourceGen.Pat
import Ide.Plugin.Tactic.GHC
import Ide.Plugin.Tactic.Judgements
import Ide.Plugin.Tactic.Machinery
import Ide.Plugin.Tactic.Naming
Expand Down Expand Up @@ -120,13 +121,30 @@ unzipTrace l =


-- | Essentially same as 'dataConInstOrigArgTys' in GHC,
-- but we need some tweaks in GHC >= 8.8.
-- Since old 'dataConInstArgTys' seems working with >= 8.8,
-- we just filter out non-class types in the result.
dataConInstOrigArgTys' :: DataCon -> [Type] -> [Type]
dataConInstOrigArgTys' con ty =
let tys0 = dataConInstArgTys con ty
in filter (maybe True (not . isClassTyCon) . tyConAppTyCon_maybe) tys0
-- but only accepts universally quantified types as the second arguments
-- and automatically introduces existentials.
--
-- NOTE: The behaviour depends on GHC's 'dataConInstOrigArgTys'.
-- We need some tweaks if the compiler changes the implementation.
dataConInstOrigArgTys'
:: DataCon
-- ^ 'DataCon'structor
-> [Type]
-- ^ /Universally/ quantified type arguments to a result type.
-- It /MUST NOT/ contain any dictionaries, coercion and existentials.
--
-- For example, for @MkMyGADT :: b -> MyGADT a c@, we
-- must pass @[a, c]@ as this argument but not @b@, as @b@ is an existential.
-> [Type]
-- ^ Types of arguments to the DataCon with returned type is instantiated with the second argument.
dataConInstOrigArgTys' con uniTys =
let exvars = dataConExTys con
in dataConInstOrigArgTys con $
uniTys ++ fmap mkTyVarTy exvars
-- Rationale: At least in GHC <= 8.10, 'dataConInstOrigArgTys'
-- unifies the second argument with DataCon's universals followed by existentials.
-- If the definition of 'dataConInstOrigArgTys' changes,
-- this place must be changed accordingly.

------------------------------------------------------------------------------
-- | Combinator for performing case splitting, and running sub-rules on the
Expand Down
8 changes: 7 additions & 1 deletion plugins/tactics/src/Ide/Plugin/Tactic/GHC.hs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import Control.Monad.State
import qualified Data.Map as M
import Data.Maybe (isJust)
import Data.Traversable
import qualified DataCon as DataCon
import Development.IDE.GHC.Compat
import Generics.SYB (mkT, everywhere)
import Ide.Plugin.Tactic.Types
Expand All @@ -20,7 +21,6 @@ import TysWiredIn (intTyCon, floatTyCon, doubleTyCon, charTyCon)
import Unique
import Var


tcTyVar_maybe :: Type -> Maybe Var
tcTyVar_maybe ty | Just ty' <- tcView ty = tcTyVar_maybe ty'
tcTyVar_maybe (CastTy ty _) = tcTyVar_maybe ty -- look through casts, as
Expand Down Expand Up @@ -148,3 +148,9 @@ getPatName (fromPatCompat -> p0) =
#endif
_ -> Nothing

dataConExTys :: DataCon -> [TyCoVar]
#if __GLASGOW_HASKELL__ >= 808
dataConExTys = DataCon.dataConExTyCoVars
#else
dataConExTys = DataCon.dataConExTyVars
#endif
1 change: 1 addition & 0 deletions test/functional/Tactic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ tests = testGroup
, goldenTest "GoldenSwap.hs" 2 8 Auto ""
, goldenTest "GoldenFmapTree.hs" 4 11 Auto ""
, goldenTest "GoldenGADTDestruct.hs" 7 17 Destruct "gadt"
, goldenTest "GoldenGADTDestructCoercion.hs" 8 17 Destruct "gadt"
, goldenTest "GoldenGADTAuto.hs" 7 13 Auto ""
, goldenTest "GoldenSwapMany.hs" 2 12 Auto ""
, goldenTest "GoldenBigTuple.hs" 4 12 Auto ""
Expand Down
8 changes: 8 additions & 0 deletions test/testdata/tactic/GoldenGADTDestructCoercion.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
module GoldenGADTDestruct where
data E a b where
E :: forall a b. (b ~ a, Ord a) => b -> E a [a]

ctxGADT :: E a b -> String
ctxGADT gadt = _decons
8 changes: 8 additions & 0 deletions test/testdata/tactic/GoldenGADTDestructCoercion.hs.expected
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE GADTs #-}
module GoldenGADTDestruct where
data E a b where
E :: forall a b. (b ~ a, Ord a) => b -> E a [a]

ctxGADT :: E a b -> String
ctxGADT gadt = (case gadt of { (E b) -> _ })