haskell-tools-builtin-refactorings 1.0.1.1 → 1.1.0.0
raw patch · 94 files changed
+1354/−320 lines, 94 filesdep +portable-linesdep ~basedep ~ghcdep ~haskell-tools-ast
Dependencies added: portable-lines
Dependency ranges changed: base, ghc, haskell-tools-ast, haskell-tools-backend-ghc, haskell-tools-prettyprint, haskell-tools-refactor, haskell-tools-rewrite, template-haskell
Files
- Language/Haskell/Tools/Refactor/Builtin.hs +3/−3
- Language/Haskell/Tools/Refactor/Builtin/AutoCorrect.hs +17/−13
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers.hs +3/−0
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ArrowsChecker.hs +3/−3
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/BangPatternsChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/CPPChecker.hs +45/−0
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ConstrainedClassMethodsChecker.hs +2/−2
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ConstraintKindsChecker.hs +2/−8
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/DefaultSignaturesChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/DerivingsChecker.hs +17/−15
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ExplicitForAllChecker.hs +2/−2
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ExplicitNamespacesChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/FlexibleContextsChecker.hs +162/−0
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/FlexibleInstancesChecker.hs +9/−7
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/FunctionalDependenciesChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/GADTsChecker.hs +17/−10
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/KindSignaturesChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/LambdaCaseChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/MagicHashChecker.hs +8/−8
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/MultiParamTypeClassesChecker.hs +2/−2
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/MultiWayIfChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/OverloadedStringsChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ParallelListCompChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/PatternSynonymsChecker.hs +2/−2
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/RecordWildCardsChecker.hs +2/−2
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/RecursiveDoChecker.hs +2/−2
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TemplateHaskellChecker.hs +4/−4
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TupleSectionsChecker.hs +3/−3
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TypeFamiliesChecker.hs +66/−40
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TypeOperatorsChecker.hs +10/−7
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TypeSynonymInstancesChecker.hs +3/−2
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/UnboxedTuplesChecker.hs +4/−4
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/UndecidableInstancesChecker.hs +98/−0
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ViewPatternsChecker.hs +1/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/ExtMap.hs +45/−5
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/ExtMonad.hs +69/−13
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Instances/AppSelector.hs +3/−1
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Instances/Checkable.hs +10/−2
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/SupportedExtensions.hs +10/−3
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/TraverseAST.hs +4/−2
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Utils/Debug.hs +0/−40
- Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Utils/GHCHelpers.hs +128/−0
- Language/Haskell/Tools/Refactor/Builtin/ExtractBinding.hs +7/−1
- Language/Haskell/Tools/Refactor/Builtin/FloatOut.hs +5/−1
- Language/Haskell/Tools/Refactor/Builtin/GenerateExports.hs +4/−1
- Language/Haskell/Tools/Refactor/Builtin/GenerateTypeSignature.hs +7/−1
- Language/Haskell/Tools/Refactor/Builtin/GetMatches.hs +2/−4
- Language/Haskell/Tools/Refactor/Builtin/InlineBinding.hs +7/−1
- Language/Haskell/Tools/Refactor/Builtin/OrganizeExtensions.hs +50/−19
- Language/Haskell/Tools/Refactor/Builtin/OrganizeImports.hs +6/−1
- Language/Haskell/Tools/Refactor/Builtin/RenameDefinition.hs +7/−1
- examples/Refactor/GenerateTypeSignature/PolymorphSubMulti_res.hs +1/−1
- examples/Refactor/OrganizeImports/MakeExplicit/ImportThree_res.hs +1/−1
- examples/Refactor/OrganizeImports/MakeExplicit/ImportUnitedCount_res.hs +1/−1
- examples/Refactor/OrganizeImports/NarrowType_res.hs +1/−1
- examples/Refactor/RenameDefinition/ParenName.hs +3/−3
- examples/Refactor/RenameDefinition/ParenName_res.hs +3/−3
- haskell-tools-builtin-refactorings.cabal +35/−30
- test/ExtensionOrganizerTest/AnnotationParser.hs +40/−14
- test/ExtensionOrganizerTest/ConstrainedClassMethodsTest/MixedTyVars.hs +1/−1
- test/ExtensionOrganizerTest/FlexibleContextsTest/Definitions.hs +33/−0
- test/ExtensionOrganizerTest/FlexibleContextsTest/ForAll.hs +11/−0
- test/ExtensionOrganizerTest/FlexibleContextsTest/NestedCtx.hs +11/−0
- test/ExtensionOrganizerTest/FlexibleContextsTest/Synonyms.hs +21/−0
- test/ExtensionOrganizerTest/FlexibleContextsTest/TyFamConstraints.hs +11/−0
- test/ExtensionOrganizerTest/FlexibleContextsTest/TySynConstraints.hs +21/−0
- test/ExtensionOrganizerTest/FlexibleContextsTest/TypeApp.hs +11/−0
- test/ExtensionOrganizerTest/FlexibleContextsTest/VarType.hs +11/−0
- test/ExtensionOrganizerTest/FlexibleContextsTest/WithScopedTyVarsMagic.hs +8/−0
- test/ExtensionOrganizerTest/Main.hs +40/−4
- test/ExtensionOrganizerTest/TypeFamiliesTest/Definitions.hs +4/−1
- test/ExtensionOrganizerTest/TypeFamiliesTest/NestedTypeEqualityContextSynonyms.hs +2/−2
- test/ExtensionOrganizerTest/TypeFamiliesTest/NestedTypeEqualitySynonyms.hs +1/−1
- test/ExtensionOrganizerTest/TypeFamiliesTest/TypeEqualityContext.hs +1/−1
- test/ExtensionOrganizerTest/TypeFamiliesTest/TypeEqualityContextSynonyms.hs +2/−2
- test/ExtensionOrganizerTest/TypeFamiliesTest/TypeEqualityInName.hs +7/−1
- test/ExtensionOrganizerTest/TypeFamiliesTest/TypeEqualitySynonyms.hs +1/−1
- test/ExtensionOrganizerTest/UndecidableInstancesTest/BadTyVars.hs +10/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/Definitions.hs +18/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/GNDForAssociatedTypes.hs +9/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/NoSmallerPred.hs +11/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/SynBadTyVars.hs +10/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/SynNoSmallerPred.hs +14/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTupleConstraint.hs +9/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTyFamBadTyVars.hs +22/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTyFamNestedTyFun.hs +17/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTyFamNoSmaller.hs +19/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTyFunInSuperClass.hs +9/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/TupleConstraint.hs +7/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/TyFamBadTyVars.hs +14/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/TyFamNestedTyFun.hs +14/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/TyFamNoSmaller.hs +14/−0
- test/ExtensionOrganizerTest/UndecidableInstancesTest/TyFunInSuperClass.hs +7/−0
- test/Main.hs +8/−7
Language/Haskell/Tools/Refactor/Builtin.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE FlexibleContexts, MonoLocalBinds #-} +{-# LANGUAGE MonoLocalBinds #-} module Language.Haskell.Tools.Refactor.Builtin ( builtinRefactorings, builtinQueries ) where @@ -8,7 +8,7 @@ import Language.Haskell.Tools.Refactor.Builtin.GenerateExports (generateExportsRefactoring) import Language.Haskell.Tools.Refactor.Builtin.GenerateTypeSignature (generateTypeSignatureRefactoring) import Language.Haskell.Tools.Refactor.Builtin.InlineBinding (inlineBindingRefactoring) -import Language.Haskell.Tools.Refactor.Builtin.OrganizeExtensions (organizeExtensionsRefactoring, projectOrganizeExtensionsRefactoring) +import Language.Haskell.Tools.Refactor.Builtin.OrganizeExtensions (organizeExtensionsRefactoring, projectOrganizeExtensionsRefactoring, highlightExtensionsQuery) import Language.Haskell.Tools.Refactor.Builtin.OrganizeImports (organizeImportsRefactoring, projectOrganizeImportsRefactoring) import Language.Haskell.Tools.Refactor.Builtin.RenameDefinition (renameDefinitionRefactoring) import Language.Haskell.Tools.Refactor.Builtin.GetMatches (getMatchesQuery) @@ -30,4 +30,4 @@ ] builtinQueries :: [QueryChoice] -builtinQueries = [ getMatchesQuery ]+builtinQueries = [ getMatchesQuery, highlightExtensionsQuery ]
Language/Haskell/Tools/Refactor/Builtin/AutoCorrect.hs view
@@ -1,4 +1,8 @@-{-# LANGUAGE FlexibleContexts, MonoLocalBinds, ScopedTypeVariables, TupleSections, ViewPatterns #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE ViewPatterns #-} module Language.Haskell.Tools.Refactor.Builtin.AutoCorrect (autoCorrect, tryItOut, autoCorrectRefactoring) where @@ -6,14 +10,14 @@ import GHC import Type -- import Outputable --- +-- import Control.Monad.State import Control.Reference import Data.List import Data.Maybe --- +-- import Language.Haskell.Tools.Refactor as HT --- +-- import Language.Haskell.Tools.PrettyPrint autoCorrectRefactoring :: RefactoringChoice @@ -46,7 +50,7 @@ if not (isJust (appTypeMatches insts funTy [arg1Ty, arg2Ty])) && isJust (appTypeMatches insts funTy [arg2Ty, arg1Ty]) then put True >> return (exprArg .= a1 $ exprFun&exprArg .= a2 $ e) else return e -reOrderExpr insts e@(InfixApp lhs op rhs) +reOrderExpr insts e@(InfixApp lhs op rhs) = do let funTy = idType $ semanticsId (op ^. operatorName) lhsTy <- lift $ typeExpr lhs rhsTy <- lift $ typeExpr rhs @@ -86,9 +90,9 @@ extractAtoms :: Expr -> Ghc [(GHC.Type, Atom)] extractAtoms e = do lits <- mapM (\l -> (, LiteralA l) <$> literalType l) (e ^? biplateRef) - return $ sortOn (srcSpanStart . atomRange . snd) - $ map (\n -> (idType $ semanticsId (n ^. simpleName), NameA n)) (e ^? biplateRef) - ++ map (\o -> (idType $ semanticsId (o ^. operatorName), OperatorA o)) (e ^? biplateRef) + return $ sortOn (srcSpanStart . atomRange . snd) + $ map (\n -> (idType $ semanticsId (n ^. simpleName), NameA n)) (e ^? biplateRef) + ++ map (\o -> (idType $ semanticsId (o ^. operatorName), OperatorA o)) (e ^? biplateRef) ++ lits atomRange :: Atom -> SrcSpan @@ -116,17 +120,17 @@ where reduceFunctionApp ls i | Just (funT, fun) <- lookup i ls , Just (argT, arg) <- lookup (i+1) ls , Just (subst, resTyp) <- appTypeMatches insts funT [argT] - = Just $ map ((_1 .- substTy subst) . snd) (take i ls) - ++ [(resTyp, mkParen' (mkApp' fun arg))] + = Just $ map ((_1 .- substTy subst) . snd) (take i ls) + ++ [(resTyp, mkParen' (mkApp' fun arg))] ++ map ((_1 .- substTy subst) . snd) (drop (i + 2) ls) reduceFunctionApp _ _ = Nothing - + reduceOperatorApp ls i | Just (opT, Left (OperatorA op)) <- lookup i ls , Just (lArgT, lArg) <- lookup (i-1) ls , Just (rArgT, rArg) <- lookup (i+1) ls , Just (subst, resTyp) <- appTypeMatches insts opT [lArgT, rArgT] - = Just $ map ((_1 .- substTy subst) . snd) (take (i - 1) ls) - ++ [(resTyp, mkParen' (mkInfixApp' lArg op rArg))] + = Just $ map ((_1 .- substTy subst) . snd) (take (i - 1) ls) + ++ [(resTyp, mkParen' (mkInfixApp' lArg op rArg))] ++ map ((_1 .- substTy subst) . snd) (drop (i + 2) ls) reduceOperatorApp _ _ = Nothing
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers.hs view
@@ -6,11 +6,13 @@ import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.BangPatternsChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ConstraintKindsChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ConstrainedClassMethodsChecker as X +import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.CPPChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.DefaultSignaturesChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.DerivingsChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ExplicitForAllChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ExplicitNamespacesChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.FlexibleInstancesChecker as X +import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.FlexibleContextsChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.FunctionalDependenciesChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.GADTsChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.KindSignaturesChecker as X @@ -29,4 +31,5 @@ import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.TypeOperatorsChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.TypeSynonymInstancesChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.UnboxedTuplesChecker as X +import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.UndecidableInstancesChecker as X import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ViewPatternsChecker as X
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ArrowsChecker.hs view
@@ -4,9 +4,9 @@ import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad chkArrowsExpr :: CheckNode Expr --- chkArrowsExpr e@Proc{} = addOccurence Arrows e -chkArrowsExpr e@ArrowApp{} = addOccurence Arrows e +-- chkArrowsExpr e@Proc{} = addEvidence Arrows e +chkArrowsExpr e@ArrowApp{} = addEvidence Arrows e chkArrowsExpr e = return e chkArrowsCmd :: CheckNode Cmd -chkArrowsCmd = addOccurence Arrows +chkArrowsCmd = addEvidence Arrows
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/BangPatternsChecker.hs view
@@ -7,7 +7,7 @@ chkBangPatterns = conditional chkBangPatterns' BangPatterns chkBangPatterns' :: CheckNode Pattern -chkBangPatterns' p@(BangPat _) = addOccurence BangPatterns p +chkBangPatterns' p@(BangPat _) = addEvidence BangPatterns p chkBangPatterns' x = return x {-
+ Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/CPPChecker.hs view
@@ -0,0 +1,45 @@+module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.CPPChecker where + +import GHC hiding (Module) +import StringBuffer + +import Data.List (isSubsequenceOf) +import Data.String (fromString) +import Text.PortableLines.ByteString.Lazy (lines8) + +import Language.Haskell.Tools.PrettyPrint +import Language.Haskell.Tools.Refactor +import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad + +gblChkCPP :: CheckNode Module +gblChkCPP = conditional gblChkCPP' Cpp + +-- TODO (after GHC upgrade): Rewrite this with mgLookupModule +gblChkCPP' :: CheckNode Module +gblChkCPP' m = do + ms <- getModSummary . moduleName . semanticsModule $ m + let cppSrc = preprocessedSrc ms + case ml_hs_file . ms_location $ ms of + Just fp -> do + let lines' = lines8 . fromString + cppSrc' = lines' . rmDefaultIncludes fp $ cppSrc + origSrc = lines' . prettyPrint $ m + when (cppSrc' /= origSrc) (addEvidenceLoc Cpp noSrcSpan) + _ -> addEvidenceLoc Cpp noSrcSpan + return m + +-- CPP inserts a line before and after the default includes, +-- that contain the filepath of the module. +-- We want to remove these lines, and everything between them. +rmDefaultIncludes :: FilePath -> String -> String +rmDefaultIncludes fp = unlines . tail + . dropWhile (not . (fp `isSubsequenceOf`)) + . tail . lines + +-- | Returns the preprocessed source code. +-- If it is not present, it returns an empty string. +preprocessedSrc :: ModSummary -> String +preprocessedSrc = maybe "" strBufToStr . ms_hspp_buf + +strBufToStr :: StringBuffer -> String +strBufToStr sb@(StringBuffer _ len _) = lexemeToString sb len
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ConstrainedClassMethodsChecker.hs view
@@ -22,7 +22,7 @@ mNeedsCCM <- runMaybeT . chkCCMDeclHead' $ dh case mNeedsCCM of Just False -> return dh - _ -> addOccurence ConstrainedClassMethods dh + _ -> addEvidence ConstrainedClassMethods dh -- | Helper function for chkCCMDeclHead. @@ -31,7 +31,7 @@ -- fails <=> Lookup is unsuccesful (either name or type lookup) chkCCMDeclHead' :: DeclHead -> MaybeT ExtMonad Bool chkCCMDeclHead' dh = do - sname <- declHeadSemName dh + sname <- liftMaybe . declHeadSemName $ dh tything <- MaybeT . GHC.lookupName $ sname case tything of GHC.ATyCon tc | GHC.isClassTyCon tc -> liftMaybe . fmap classNeedsCCM . GHC.tyConClass_maybe $ tc
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ConstraintKindsChecker.hs view
@@ -20,12 +20,12 @@ -- Has any constraints of form (x t1 t2) | ctxts <- universeBi rhs :: [Context] , any hasTyVarHeadAsserts ctxts - = addOccurence ConstraintKinds d + = addEvidence ConstraintKinds d -- Right-hand side has kind Constraint | otherwise = do let ty = typeOrKindFromId . declHeadQName $ dh if hasConstraintKind ty || returnsConstraintKind ty - then addOccurence ConstraintKinds d + then addEvidence ConstraintKinds d else return d chkConstraintKindsDecl' d = return d @@ -40,9 +40,3 @@ | Just assertions <- ta ^? innerAsserts & annListElems = any hasAnyTyVarHeads assertions hasAnyTyVarHeads _ = False - -declHeadQName :: DeclHead -> QualifiedName -declHeadQName (NameDeclHead n) = n ^. simpleName -declHeadQName (ParenDeclHead dh) = declHeadQName dh -declHeadQName (DeclHeadApp dh _) = declHeadQName dh -declHeadQName (InfixDeclHead _ op _) = op ^. operatorName
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/DefaultSignaturesChecker.hs view
@@ -4,5 +4,5 @@ import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad chkDefaultSigs :: CheckNode ClassElement -chkDefaultSigs ce@ClsDefaultSig{} = addOccurence DefaultSignatures ce +chkDefaultSigs ce@ClsDefaultSig{} = addEvidence DefaultSignatures ce chkDefaultSigs x = return x
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/DerivingsChecker.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE FlexibleContexts, MultiWayIf, ViewPatterns #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MultiWayIf #-} +{-# LANGUAGE ViewPatterns #-} {- @@ -130,14 +132,14 @@ chkGADTDataDecl :: CheckNode Decl chkGADTDataDecl d@(GADTDataDecl keyw _ _ _ _ derivs) = do - addOccurence_ GADTs d + addEvidence_ GADTs d annList !~ separateByKeyword keyw $ derivs return d chkGADTDataDecl d = return d chkDataInstance :: CheckNode Decl chkDataInstance d@(DataInstance keyw _ _ derivs) = do - addOccurence_ TypeFamilies d + addEvidence_ TypeFamilies d annList !~ separateByKeyword keyw $ derivs return d chkDataInstance d = return d @@ -158,7 +160,7 @@ addExtension :: (MonadState ExtMap m, HasRange node) => GHC.Name -> node -> m node addExtension sname - | Just ext <- whichExtension sname = addOccurence ext + | Just ext <- whichExtension sname = addEvidence ext | otherwise = return addStockExtension :: CheckNode InstanceHead @@ -169,15 +171,15 @@ chkByStrat :: CheckNode InstanceHead -> CheckNode Deriving chkByStrat checker d | Just strat <- getStrategy d = do - addOccurence DerivingStrategies d + addEvidence DerivingStrategies d chkDerivingClause (chkStrat strat) d | otherwise = chkDerivingClause checker d chkStrat :: DeriveStrategy -> CheckNode InstanceHead chkStrat (_element -> UStockStrategy) = addStockExtension -chkStrat (_element -> UNewtypeStrategy) = addOccurence GeneralizedNewtypeDeriving -chkStrat (_element -> UAnyClassStrategy) = addOccurence DeriveAnyClass +chkStrat (_element -> UNewtypeStrategy) = addEvidence GeneralizedNewtypeDeriving +chkStrat (_element -> UAnyClassStrategy) = addEvidence DeriveAnyClass chkDerivingClause :: CheckNode InstanceHead -> CheckNode Deriving chkDerivingClause checker d@(DerivingOne x) = checker x >> return d @@ -195,21 +197,21 @@ chkClassForData :: CheckNode InstanceHead chkClassForData x | Just sname <- nameFromStock x = addExtension sname x - | otherwise = addOccurence DeriveAnyClass x + | otherwise = addEvidence DeriveAnyClass x -- performs check in case no explicit strategy is given chkClassForNewtype :: CheckNode InstanceHead chkClassForNewtype x | Just sname <- nameFromStock x = if | gndNotNeeded sname -> return x - | gndNeeded sname -> addOccurence GeneralizedNewtypeDeriving x + | gndNeeded sname -> addEvidence GeneralizedNewtypeDeriving x | gndNotAllowed sname -> addExtension sname x | otherwise = do gndOn <- isTurnedOn GeneralizedNewtypeDeriving deriveAnyOn <- isTurnedOn DeriveAnyClass - if | gndOn && deriveAnyOn -> addOccurence_ DeriveAnyClass x - | deriveAnyOn -> addOccurence_ DeriveAnyClass x - | gndOn -> addOccurence_ GeneralizedNewtypeDeriving x + if | gndOn && deriveAnyOn -> addEvidence_ DeriveAnyClass x + | deriveAnyOn -> addEvidence_ DeriveAnyClass x + | gndOn -> addEvidence_ GeneralizedNewtypeDeriving x | otherwise -> return () return x @@ -220,12 +222,12 @@ chkStandaloneDeriving :: CheckNode Decl chkStandaloneDeriving d@(Refact.StandaloneDeriving strat _ (decompRule -> (cls,ty))) | Just strat' <- strat = do - addOccurence_ Ext.DerivingStrategies d - addOccurence_ Ext.StandaloneDeriving d + addEvidence_ Ext.DerivingStrategies d + addEvidence_ Ext.StandaloneDeriving d chkStrat strat' cls return d | otherwise = do - addOccurence_ Ext.StandaloneDeriving d + addEvidence_ Ext.StandaloneDeriving d itIsNewType <- isNewtype ty itIsSynNewType <- isSynNewType ty if itIsNewType || itIsSynNewType
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ExplicitForAllChecker.hs view
@@ -11,7 +11,7 @@ where chkType :: CheckNode Type chkType t | UTyForall{} <- t ^. element - = addOccurence ExplicitForAll t + = addEvidence ExplicitForAll t | otherwise = return t chkExplicitForAllConDecl :: CheckNode ConDecl @@ -23,5 +23,5 @@ chkQuantifiedTyVarsWith :: HasRange a => (a -> TyVarList) -> CheckNode a chkQuantifiedTyVarsWith getTyVars conDecl = if (annLength . getTyVars $ conDecl) > 0 - then addOccurence ExplicitForAll conDecl + then addEvidence ExplicitForAll conDecl else return conDecl
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ExplicitNamespacesChecker.hs view
@@ -10,5 +10,5 @@ chkExplicitNamespacesIESpec = conditional chkIESpec ExplicitNamespaces where chkIESpec :: CheckNode IESpec chkIESpec x@(IESpec (AnnJust imod) _ _) - | UImportType <- imod ^. element = addOccurence ExplicitNamespaces x + | UImportType <- imod ^. element = addEvidence ExplicitNamespaces x chkIESpec x = return x
+ Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/FlexibleContextsChecker.hs view
@@ -0,0 +1,162 @@+module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.FlexibleContextsChecker where + +import Kind (returnsConstraintKind) +import TcType (tcSplitNestedSigmaTys, checkValidClsArgs) +import Type hiding (Type(..)) +import PrelNames (eqTyConName, eqTyConKey) +import Unique (hasKey) +import qualified Name as GHC +import qualified GHC + +import Data.List +import Data.Generics.Uniplate.Data() +import Data.Generics.Uniplate.Operations + +import Control.Reference ((^.)) + +import Language.Haskell.Tools.AST +import Language.Haskell.Tools.Refactor +import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad + +gblChkQNamesForFC :: CheckNode Module +gblChkQNamesForFC = conditional gblChkQNamesForFC' FlexibleContexts + +chkFlexibleContexts :: CheckNode Context +chkFlexibleContexts = conditional chkFlexibleContexts' FlexibleContexts + +chkFlexibleContexts' :: CheckNode Context +chkFlexibleContexts' ctx@(Context a) = chkAssertion a >> return ctx + +chkAssertion :: CheckNode Assertion +chkAssertion a@(ClassAssert con annTys) = do + -- If a lookup fails, add MissingInformation FlexibleContexts + let errDefault = addMI FlexibleContexts a >> return False + isClass <- fromMaybeTM errDefault (isClassTyConNameM con) + if not isClass || all hasTyVarHead (annTys ^. annListElems) + then return a + else addEvidence FlexibleContexts a +chkAssertion a@(InfixAssert lhs op rhs) + -- If the constraint is of form a ~ b, then we dont need to check + | Just name <- semanticsName op + , name == eqTyConName + = return a + -- If the constraint has only type variable heads, it doesn't need FlexibleContexts + | hasTyVarHead lhs && hasTyVarHead rhs = return a + -- In any other case, we keep FlexibleContexts + | otherwise = addEvidence FlexibleContexts a +chkAssertion a@(TupleAssert xs) = do + mapM_ chkAssertion xs + return a +chkAssertion a@ImplicitAssert{} = return a + +chkFlexibleContextsDecl :: CheckNode Decl +chkFlexibleContextsDecl = conditional chkFlexibleContextsDecl' FlexibleContexts + +chkFlexibleContextsDecl' :: CheckNode Decl +chkFlexibleContextsDecl' d@(TypeDecl dh rhs) = do + let ty = typeOrKindFromId . declHeadQName $ dh + when (hasConstraintKind ty || returnsConstraintKind ty) + (chkClassesInside rhs) + return d +chkFlexibleContextsDecl' d = return d + +-- | Checks whether all type class applications in a type synonym rhs +-- (that has kind Constraint) have only type variable heads. +-- Returns False if a lookup inside is not succesful. +-- If it isn't applied to a type that has kind Constraint, it may give +-- false positive results. +chkClassesInside :: Type -> ExtMonad () +chkClassesInside (TupleType annTys) = + mapM_ chkClassesInside (annTys ^. annListElems) +chkClassesInside t = maybe (addFC t) f (splitTypeAppMaybe t) + where + addFC :: Type -> ExtMonad () + addFC = addEvidence_ FlexibleContexts + + f :: (GHC.Name, [Type]) -> ExtMonad () + f (n,args) = do + isClass <- isJustT . lookupClass $ n + when (n /= eqTyConName && isClass && any (not . hasTyVarHead) args) + (addFC t) + + -- Separates the type into its head and its arguments. + -- This functions should only be applied to types that have kind Constraint. + splitTypeAppMaybe :: Type -> Maybe (GHC.Name, [Type]) + splitTypeAppMaybe (TypeApp f arg) = do + (f', args) <- splitTypeAppMaybe f + return (f', args ++ [arg]) + splitTypeAppMaybe (InfixTypeApp lhs op rhs) = do + opName <- semanticsName op + return (opName, [lhs,rhs]) + splitTypeAppMaybe (VarType n) = do + sname <- semanticsName n + return (sname, []) + splitTypeAppMaybe (ParenType t) = splitTypeAppMaybe t + splitTypeAppMaybe (KindedType t _) = splitTypeAppMaybe t + splitTypeAppMaybe _ = Nothing + + +chkQNameForFC :: QualifiedName -> ExtMonad Bool +chkQNameForFC name = do + mty <- runMaybeT . lookupTypeFromId $ name + case mty of + Just ty -> do + -- First we get all subtypes of the given type, while expanding all type synonyms, + -- then we remove all implicit predicates, + -- and partition the types into predicate types and theta types. + let expanded = expandTypeSynonyms ty + subTys = universeBi expanded :: [GHC.Type] + (preds, tys) = partition isPredTy . filter (not . isIPPred) $ subTys + + -- We don't need type equalities, so we get rid of them and their children. + -- Then we extract the constraints from the types. + nomEqs = universeBi (filter isNominalEqPred preds) :: [GHC.Type] + preds' = preds \\ nomEqs + thetas = concatMap (snd' . tcSplitNestedSigmaTys) tys + + -- We split each theta type into its class tycon and its arguments. + -- We also filter out tuple constraints + -- (we already have the constraints in it). + xs = mapMaybe getClassPredTys_maybe (thetas ++ preds') + xs' = filter (not . isCTupleClass . fst) xs + + if all (uncurry hasValidClsArgs) xs' then return False + else return True + Nothing -> return False + where + hasValidClsArgs :: GHC.Class -> [GHC.Type] -> Bool + hasValidClsArgs cls args = cls `hasKey` eqTyConKey + || isIPClass cls + || checkValidClsArgs False cls args + + snd' :: (a,b,c) -> b + snd' (_,x,_) = x + + isNominalEqPred :: GHC.Type -> Bool + isNominalEqPred ty + | Just (tc,_) <- splitTyConApp_maybe ty = tc `hasKey` eqTyConKey + | otherwise = False + +gblChkQNamesForFC' :: CheckNode Module +gblChkQNamesForFC' m = do + -- Names appearing on the rhs of bindings are just hints, + -- they don't necessarily require FlexibleContexts. + let allNames = universeBi (m ^. modDecl) :: [QualifiedName] + rhs = universeBi (m ^. modDecl) :: [Rhs] + hints = universeBi rhs :: [QualifiedName] + + -- Separating hints from evidence, + -- and grouping them together based on their GHC.Name + evidence = filter (isJust . semanticsName) (allNames \\ hints) + hints' = filter (isJust . semanticsName) hints + groupedEs = equivalenceGroupsBy semanticsName evidence + groupedHs = equivalenceGroupsBy semanticsName hints' + + -- Checking the representative elements, whether they need FC, + -- if they do, add occurences for every node in their group. + es <- filterM (chkQNameForFC . fst) groupedEs + hs <- filterM (chkQNameForFC . fst) groupedHs + mapM_ (addEvidence FlexibleContexts) (concatMap snd es) + mapM_ (addHint FlexibleContexts) (concatMap snd hs) + + return m
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/FlexibleInstancesChecker.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE FlexibleContexts, GADTs, MultiWayIf #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE MultiWayIf #-} module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.FlexibleInstancesChecker where @@ -48,7 +50,7 @@ mCls <- runMaybeT . lookupClassFromInstance $ ih case mCls of Just cls -> mapM_ (chkTypeArg cls) types >> return ih - Nothing -> addOccurence FlexibleInstances ih + Nothing -> addMI FlexibleInstances ih -- | Checks a type argument of class whether it needs FlexibleInstances -- First checks the structure of the type argument opaquely @@ -56,8 +58,8 @@ -- needs the extension. -- -- Might find false positive occurences for phantom types: --- > type Phatom a b = [a] --- > instance C (Phatnom a a) +-- > type Phantom a b = [a] +-- > instance C (Phantom a a) -- > instance C (Phantom a Int) chkTypeArg :: GHC.Class -> Type -> ExtMonad Type chkTypeArg cls ty = do @@ -65,7 +67,7 @@ maybeTM (return ty) (chkSynonymTypeArg cls) (semanticsTypeSynRhs ty) where chkSynonymTypeArg :: GHC.Class -> GHC.Type -> ExtMonad Type chkSynonymTypeArg cls' ty' - | tyArgNeedsFI cls' ty' = addOccurence FlexibleInstances ty + | tyArgNeedsFI cls' ty' = addEvidence FlexibleInstances ty | otherwise = return ty -- | Checks a type argument of class whether it has only (distinct) type variable arguments. @@ -77,7 +79,7 @@ case isOk of Just isOk -> unless (isOk && length vs == (length . nubBy ((==) `on` (semanticsName . (^. simpleName))) $ vs)) --tyvars are different - (addOccurence_ FlexibleInstances vars) + (addEvidence_ FlexibleInstances vars) Nothing -> error "chkNormalTypeArg: Couldn't look up something" return vars @@ -153,7 +155,7 @@ rmTypeMisc (ParenType x) = x rmTypeMisc x = x --- Decides whether a type argument of a type class constructor need FlexibleInstances +-- Decides whether a type argument of a type class constructor needs FlexibleInstances tyArgNeedsFI :: GHC.Class -> GHC.Type -> Bool tyArgNeedsFI cls arg = not . hasOnlyDistinctTyVars $ tyArg where [tyArg] = GHC.filterOutInvisibleTypes (GHC.classTyCon cls) [arg]
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/FunctionalDependenciesChecker.hs view
@@ -4,4 +4,4 @@ import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad chkFunDeps :: CheckNode FunDepList -chkFunDeps = addOccurence FunctionalDependencies +chkFunDeps = addEvidence FunctionalDependencies
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/GADTsChecker.hs view
@@ -1,6 +1,7 @@+{-# LANGUAGE MultiWayIf #-} + module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.GADTsChecker where -import Data.Maybe (catMaybes, fromMaybe) import Control.Reference ((^.), (&)) import Control.Monad.Trans.Maybe (MaybeT(..)) @@ -20,20 +21,26 @@ chkConDeclForExistentials :: CheckNode ConDecl chkConDeclForExistentials = conditionalAny chkConDeclForExistentials' [GADTs, ExistentialQuantification] --- If all data constructors are vanilla Haskell 98 data constructors, then only GADTSyntax is needed. +-- | Checks whether a GADTs-style constructor declaration requires GADTs. +-- If all data constructors are vanilla Haskell 98 data constructors +-- , then only GADTSyntax is needed. If any constructor's lookup fails +-- , we add MissingInformation. chkGADTsGadtConDecl' :: CheckNode GadtConDecl chkGADTsGadtConDecl' conDecl = do - let conNames = conDecl ^. (gadtConNames & annListElems) + let conNames = conDecl ^. (gadtConNames & annListElems) mres <- mapM (runMaybeT . isVanillaDataConNameM) conNames - if and . catMaybes $ mres - then addOccurence GADTSyntax conDecl - else do addOccurence GADTSyntax conDecl - addRelation (GADTs `lOr` ExistentialQuantification) conDecl + addEvidence_ GADTSyntax conDecl + if | any isNothing mres -> + addRelationMI (GADTs `lOr` ExistentialQuantification) conDecl + | any (not . fromJust) mres -> + addRelation (GADTs `lOr` ExistentialQuantification) conDecl + | otherwise -> return conDecl --- Extracts the name from a ConDecl, and checks whether it is a vanilla --- data constructor. +-- | Extracts the name from a ConDecl, and checks whether it is a vanilla +-- data constructor. Ifthe lookup fails, adds MissingInformation. chkConDeclForExistentials' :: CheckNode ConDecl -chkConDeclForExistentials' conDecl = liftM (fromMaybe conDecl) . runMaybeT $ +chkConDeclForExistentials' conDecl = + fromMaybeTM (addRelationMI (GADTs `lOr` ExistentialQuantification) conDecl) $ case conDecl ^. element of UConDecl _ _ n _ -> chkName n URecordDecl _ _ n _ -> chkName n
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/KindSignaturesChecker.hs view
@@ -5,4 +5,4 @@ chkKindSignaturesKind :: CheckNode Kind chkKindSignaturesKind = conditional chkKind KindSignatures - where chkKind = addOccurence KindSignatures + where chkKind = addEvidence KindSignatures
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/LambdaCaseChecker.hs view
@@ -7,7 +7,7 @@ chkLambdaCase = conditional chkLambdaCase' Ext.LambdaCase chkLambdaCase' :: CheckNode Expr -chkLambdaCase' e@(Refact.LambdaCase _) = addOccurence Ext.LambdaCase e +chkLambdaCase' e@(Refact.LambdaCase _) = addEvidence Ext.LambdaCase e chkLambdaCase' e = return e
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/MagicHashChecker.hs view
@@ -18,23 +18,23 @@ chkMagicHashLiteral' :: CheckNode Literal -chkMagicHashLiteral' l@(PrimIntLit _) = addOccurence MagicHash l -chkMagicHashLiteral' l@(PrimWordLit _) = addOccurence MagicHash l -chkMagicHashLiteral' l@(PrimFloatLit _) = addOccurence MagicHash l -chkMagicHashLiteral' l@(PrimDoubleLit _) = addOccurence MagicHash l -chkMagicHashLiteral' l@(PrimCharLit _) = addOccurence MagicHash l -chkMagicHashLiteral' l@(PrimStringLit _) = addOccurence MagicHash l +chkMagicHashLiteral' l@(PrimIntLit _) = addEvidence MagicHash l +chkMagicHashLiteral' l@(PrimWordLit _) = addEvidence MagicHash l +chkMagicHashLiteral' l@(PrimFloatLit _) = addEvidence MagicHash l +chkMagicHashLiteral' l@(PrimDoubleLit _) = addEvidence MagicHash l +chkMagicHashLiteral' l@(PrimCharLit _) = addEvidence MagicHash l +chkMagicHashLiteral' l@(PrimStringLit _) = addEvidence MagicHash l chkMagicHashLiteral' l = return l chkMagicHashNamePart' :: CheckNode NamePart chkMagicHashNamePart' n@(NamePart name) = - if (last name == '#') then addOccurence MagicHash n + if (last name == '#') then addEvidence MagicHash n else return n -- NOTE: is this really needed? chkMagicHashKind' :: CheckNode Kind -chkMagicHashKind' k@UnboxKind = addOccurence MagicHash k +chkMagicHashKind' k@UnboxKind = addEvidence MagicHash k chkMagicHashKind' k = return k {- Name can be reached from:
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/MultiParamTypeClassesChecker.hs view
@@ -14,10 +14,10 @@ chkMultiParamTypeClassesDecl' :: CheckNode Decl chkMultiParamTypeClassesDecl' cd@(ClassDecl _ dh _ _) | n <- length . collectTyVars $ dh - , n /= 1 = addOccurence MultiParamTypeClasses dh >> return cd + , n /= 1 = addEvidence MultiParamTypeClasses dh >> return cd chkMultiParamTypeClassesDecl' i@(InstanceDecl rule _) | isMultiParamNeeded (rule ^. irHead) - = addOccurence MultiParamTypeClasses rule >> return i + = addEvidence MultiParamTypeClasses rule >> return i chkMultiParamTypeClassesDecl' d = return d
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/MultiWayIfChecker.hs view
@@ -7,5 +7,5 @@ chkMultiWayIfExpr = conditional chkMultiWayIfExpr' MultiWayIf chkMultiWayIfExpr' :: CheckNode Expr -chkMultiWayIfExpr' e@(MultiIf _) = addOccurence MultiWayIf e +chkMultiWayIfExpr' e@(MultiIf _) = addEvidence MultiWayIf e chkMultiWayIfExpr' x = return x
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/OverloadedStringsChecker.hs view
@@ -15,5 +15,5 @@ chkLit lit | UStringLit _ <- lit ^. element , not . GHC.eqType GHC.stringTy $ semanticsLiteralType lit - = addOccurence OverloadedStrings lit + = addEvidence OverloadedStrings lit | otherwise = return lit
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ParallelListCompChecker.hs view
@@ -6,5 +6,5 @@ chkParallelListComp :: CheckNode Expr chkParallelListComp e@(ListComp _ body) - | annLength body > 1 = addOccurence ParallelListComp e + | annLength body > 1 = addEvidence ParallelListComp e chkParallelListComp e = return e
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/PatternSynonymsChecker.hs view
@@ -10,7 +10,7 @@ chkPatternSynonymsSyn = conditional chkPatternSynonymsSyn' PatternSynonyms chkPatternSynonymsSyn' :: CheckNode PatternSynonym -chkPatternSynonymsSyn' = addOccurence PatternSynonyms +chkPatternSynonymsSyn' = addEvidence PatternSynonyms chkPatternSynonymsTypeSig :: CheckNode PatternSignature -chkPatternSynonymsTypeSig = conditional (addOccurence PatternSynonyms) PatternSynonyms +chkPatternSynonymsTypeSig = conditional (addEvidence PatternSynonyms) PatternSynonyms
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/RecordWildCardsChecker.hs view
@@ -7,9 +7,9 @@ -- but we don't really need any contraint. chkRecordWildCardsPatField :: CheckNode PatternField -chkRecordWildCardsPatField p@(FieldWildcardPattern {}) = addOccurence RecordWildCards p +chkRecordWildCardsPatField p@(FieldWildcardPattern {}) = addEvidence RecordWildCards p chkRecordWildCardsPatField p = return p chkRecordWildCardsFieldUpdate :: CheckNode FieldUpdate -chkRecordWildCardsFieldUpdate e@(FieldWildcard {}) = addOccurence RecordWildCards e +chkRecordWildCardsFieldUpdate e@(FieldWildcard {}) = addEvidence RecordWildCards e chkRecordWildCardsFieldUpdate e = return e
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/RecursiveDoChecker.hs view
@@ -4,9 +4,9 @@ import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad chkRecursiveDoExpr :: CheckNode Expr -chkRecursiveDoExpr e@MDo{} = addOccurence RecursiveDo e +chkRecursiveDoExpr e@MDo{} = addEvidence RecursiveDo e chkRecursiveDoExpr e = return e chkRecursiveDoStmt :: CheckNode Stmt -chkRecursiveDoStmt s@RecStmt{} = addOccurence RecursiveDo s +chkRecursiveDoStmt s@RecStmt{} = addEvidence RecursiveDo s chkRecursiveDoStmt s = return s
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TemplateHaskellChecker.hs view
@@ -8,15 +8,15 @@ -- can be reached from: Decl, Type, Expr, Pattern chkTemplateHaskellSplice :: CheckNode Splice -chkTemplateHaskellSplice = addOccurence TemplateHaskell +chkTemplateHaskellSplice = addEvidence TemplateHaskell -- can be reached from: Type, Expr, Pattern chkTemplateHaskellQuasiQuote :: CheckNode QuasiQuote -chkTemplateHaskellQuasiQuote = addOccurence QuasiQuotes +chkTemplateHaskellQuasiQuote = addEvidence QuasiQuotes -- can be reached from: Expr chkTemplateHaskellBracket :: CheckNode Bracket -chkTemplateHaskellBracket = addOccurence TemplateHaskellQuotes +chkTemplateHaskellBracket = addEvidence TemplateHaskellQuotes chkTemplateHaskellhNamePart :: CheckNode NamePart chkTemplateHaskellhNamePart = conditional chkTemplateHaskellNamePart' TemplateHaskellQuotes @@ -25,5 +25,5 @@ -- should be THQuotes OR DataKinds chkTemplateHaskellNamePart' :: CheckNode NamePart chkTemplateHaskellNamePart' n@(NamePart name) = - if (head name == '\'') then addOccurence TemplateHaskellQuotes n + if (head name == '\'') then addEvidence TemplateHaskellQuotes n else return n
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TupleSectionsChecker.hs view
@@ -7,7 +7,7 @@ chkTupleSections = conditional chkTupleSections' TupleSections chkTupleSections' :: CheckNode Expr -chkTupleSections' e@(TupleSection _) = addOccurence TupleSections e -chkTupleSections' e@(UnboxedTupleSection _) = addOccurence TupleSections e - >> addOccurence UnboxedTuples e +chkTupleSections' e@(TupleSection _) = addEvidence TupleSections e +chkTupleSections' e@(UnboxedTupleSection _) = addEvidence TupleSections e + >> addEvidence UnboxedTuples e chkTupleSections' e = return e
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TypeFamiliesChecker.hs view
@@ -3,24 +3,22 @@ import TyCon as GHC (TyCon()) import PrelNames as GHC import Unique as GHC (hasKey) +import Var as GHC (isTyVar, isId) import qualified Type as GHC (expandTypeSynonyms) import Control.Reference ((^.)) -import Control.Monad.Trans.Maybe (MaybeT(..)) -import Data.List (zipWith) -import Data.Maybe (catMaybes) +import Data.List ((\\)) import Data.Generics.Uniplate.Data() import Data.Generics.Uniplate.Operations -import qualified Data.Map.Strict as SMap import Language.Haskell.Tools.Refactor import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad -- | Checks whether any name's corresponding type in the module contains a type equality. -globalChkNamesForTypeEq :: CheckNode Module -globalChkNamesForTypeEq = conditionalAny globalChkNamesForTypeEq' [TypeFamilies, GADTs] +gblChkQNamesForTypeEq :: CheckNode Module +gblChkQNamesForTypeEq = conditionalAny gblChkQNamesForTypeEq' [TypeFamilies, GADTs] -- | Checks an operator for syntactic evidence of a ~ b type equality if TypeFamilies or GADTs is turned on. chkOperatorForTypeEq :: CheckNode Operator @@ -42,24 +40,24 @@ chkTypeFamiliesDecl' :: CheckNode Decl -chkTypeFamiliesDecl' d@TypeFamily{} = addOccurence TypeFamilies d -chkTypeFamiliesDecl' d@DataFamily{} = addOccurence TypeFamilies d -chkTypeFamiliesDecl' d@ClosedTypeFamily{} = addOccurence TypeFamilies d -chkTypeFamiliesDecl' d@TypeInstance{} = addOccurence TypeFamilies d -chkTypeFamiliesDecl' d@DataInstance{} = addOccurence TypeFamilies d -chkTypeFamiliesDecl' d@GadtDataInstance{} = addOccurence TypeFamilies d +chkTypeFamiliesDecl' d@TypeFamily{} = addEvidence TypeFamilies d +chkTypeFamiliesDecl' d@DataFamily{} = addEvidence TypeFamilies d +chkTypeFamiliesDecl' d@ClosedTypeFamily{} = addEvidence TypeFamilies d +chkTypeFamiliesDecl' d@TypeInstance{} = addEvidence TypeFamilies d +chkTypeFamiliesDecl' d@DataInstance{} = addEvidence TypeFamilies d +chkTypeFamiliesDecl' d@GadtDataInstance{} = addEvidence TypeFamilies d chkTypeFamiliesDecl' d = return d chkTypeFamiliesClassElement' :: CheckNode ClassElement -chkTypeFamiliesClassElement' ce@ClassElemTypeFam{} = addOccurence TypeFamilies ce -chkTypeFamiliesClassElement' ce@ClassElemDataFam{} = addOccurence TypeFamilies ce -chkTypeFamiliesClassElement' ce@ClsDefaultType{} = addOccurence TypeFamilies ce +chkTypeFamiliesClassElement' ce@ClassElemTypeFam{} = addEvidence TypeFamilies ce +chkTypeFamiliesClassElement' ce@ClassElemDataFam{} = addEvidence TypeFamilies ce +chkTypeFamiliesClassElement' ce@ClsDefaultType{} = addEvidence TypeFamilies ce chkTypeFamiliesClassElement' ce = return ce chkTypeFamiliesInstBodyDecl' :: CheckNode InstBodyDecl -chkTypeFamiliesInstBodyDecl' b@InstanceTypeFamilyDef{} = addOccurence TypeFamilies b -chkTypeFamiliesInstBodyDecl' b@InstanceDataFamilyDef{} = addOccurence TypeFamilies b -chkTypeFamiliesInstBodyDecl' b@InstanceDataFamilyGADTDef{} = addOccurence TypeFamilies b +chkTypeFamiliesInstBodyDecl' b@InstanceTypeFamilyDef{} = addEvidence TypeFamilies b +chkTypeFamiliesInstBodyDecl' b@InstanceDataFamilyDef{} = addEvidence TypeFamilies b +chkTypeFamiliesInstBodyDecl' b@InstanceDataFamilyGADTDef{} = addEvidence TypeFamilies b chkTypeFamiliesInstBodyDecl' b = return b @@ -70,31 +68,59 @@ = addRelation (TypeFamilies `lOr` GADTs) op | otherwise = return op -chkNameForTyEqn :: CheckNode Name -chkNameForTyEqn name = do - mty <- runMaybeT . lookupTypeFromId $ name - case mty of - Just ty -> do +-- | Checks whether a given name's has a type equality operator in it. +-- If the type lookup fails, it returns Nothing. If given a type variable, +-- it returns False. +chkQNameForTyEqn :: QualifiedName -> MaybeT ExtMonad Bool +chkQNameForTyEqn name = + if not . isId . semanticsId $ name + then return False + else do + ty <- lookupTypeFromId name let ty' = GHC.expandTypeSynonyms ty tycons = universeBi ty' :: [GHC.TyCon] - if any isEqTyCon tycons then addRelation (TypeFamilies `lOr` GADTs) name - else return name - Nothing -> return name + if any isEqTyCon tycons then return True + else return False + where isEqTyCon tc = tc `hasKey` eqTyConKey + || tc `hasKey` heqTyConKey + || tc `hasKey` eqPrimTyConKey + || tc `hasKey` eqReprPrimTyConKey + || tc `hasKey` eqPhantPrimTyConKey - --traceShow (showName name ++ " -- " ++ showOutputable ty') $ +gblChkQNamesForTypeEq' :: CheckNode Module +gblChkQNamesForTypeEq' m = do + -- Names appearing on the rhs of bindings are just hints, + -- they don't necessarily require TypeFamilies. + let allNames = universeBi (m ^. modDecl) :: [QualifiedName] + rhs = universeBi (m ^. modDecl) :: [Rhs] + hints = universeBi rhs :: [QualifiedName] - where isEqTyCon tc = tc `hasKey` eqTyConKey - || tc `hasKey` heqTyConKey - || tc `hasKey` eqPrimTyConKey - || tc `hasKey` eqReprPrimTyConKey - || tc `hasKey` eqPhantPrimTyConKey + -- Separating hints from evidence, + -- and grouping them together based on their GHC.Name + evidence = filter (isJust . semanticsName) (allNames \\ hints) + hints' = filter (isJust . semanticsName) hints + groupedEs = equivalenceGroupsBy semanticsName evidence + groupedHs = equivalenceGroupsBy semanticsName hints' -globalChkNamesForTypeEq' :: CheckNode Module -globalChkNamesForTypeEq' m = do - let origNames = universeBi (m ^. modDecl) :: [Name] - pairedNames = catMaybes . zipWith zf (map semanticsName origNames) $ origNames - uniqueNames = SMap.elems . SMap.fromList . reverse $ pairedNames - mapM_ chkNameForTyEqn uniqueNames + -- names failed at the semanticsName lookup + nmFailedNames = filter (isNothing . semanticsName) allNames + + -- Checking the representative elements, whether they need FC, + -- if they do, add occurences for every node in their group. + -- If chkQNameForTyEqn fails, we add MissingInformation. + let hasTypeEq = fromMaybeT False . chkQNameForTyEqn + failedLookup = isNothingT . chkQNameForTyEqn + + es <- filterM (hasTypeEq . fst) groupedEs + hs <- filterM (hasTypeEq . fst) groupedHs + mapM_ (addRelation (TypeFamilies `lOr` GADTs)) (concatMap snd es) + mapM_ (addRelationHint (TypeFamilies `lOr` GADTs)) (concatMap snd hs) + + mapM_ (addRelationMI (TypeFamilies `lOr` GADTs)) nmFailedNames + + -- NOTE: this would result in many false positive results + -- names failed at the chkQNameForTyEqn (lookupTypeFromId) stage + -- idFailedNames <- filterM failedLookup allNames + -- mapM_ (addRelationMI (TypeFamilies `lOr` GADTs)) idFailedNames + return m - where zf (Just x) y = Just (x,y) - zf _ _ = Nothing
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TypeOperatorsChecker.hs view
@@ -1,13 +1,12 @@ module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.TypeOperatorsChecker where +import PrelNames (eqTyConName) import qualified Name as GHC (nameOccName) import qualified OccName as GHC (isTcOcc, isSymOcc) import Data.Generics.Uniplate.Data() import Data.Generics.Uniplate.Operations -import Control.Monad.Trans.Maybe (MaybeT(..)) - import Language.Haskell.Tools.Refactor import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad @@ -32,22 +31,26 @@ chkTypeOperatorsType' :: CheckNode Type -chkTypeOperatorsType' t@InfixTypeApp{} = addOccurence TypeOperators t +chkTypeOperatorsType' t@(InfixTypeApp _ op _) + | Just name <- semanticsName op + , name == eqTyConName + = return t + | otherwise = addEvidence TypeOperators t chkTypeOperatorsType' t = return t chkTypeOperatorsAssertion' :: CheckNode Assertion -chkTypeOperatorsAssertion' a@InfixAssert{} = addOccurence TypeOperators a +chkTypeOperatorsAssertion' a@InfixAssert{} = addEvidence TypeOperators a chkTypeOperatorsAssertion' a = return a chkTypeOperatorsInstHead' :: CheckNode InstanceHead -chkTypeOperatorsInstHead' ih@InfixInstanceHead{} = addOccurence TypeOperators ih +chkTypeOperatorsInstHead' ih@InfixInstanceHead{} = addEvidence TypeOperators ih chkTypeOperatorsInstHead' ih = return ih chkTypeOperatorsDecl' :: CheckNode Decl chkTypeOperatorsDecl' d = do let dhs = universeBi d :: [DeclHead] anyNeedsTO <- liftM or $ mapM isOperatorM dhs - if anyNeedsTO then addOccurence TypeOperators d + if anyNeedsTO then addEvidence TypeOperators d else return d -- OccName: [Type and class operator definitions] @@ -55,7 +58,7 @@ -- but one that uses an operator OccName. isOperatorM :: DeclHead -> ExtMonad Bool isOperatorM dh = do - mSemName <- runMaybeT . declHeadSemName $ dh + let mSemName = declHeadSemName dh case mSemName of Just semName | occ <- GHC.nameOccName semName
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/TypeSynonymInstancesChecker.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE FlexibleContexts, MonoLocalBinds #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MonoLocalBinds #-} module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.TypeSynonymInstancesChecker ( chkTypeSynonymInstancesDecl, chkInstancesDeclWith, chkInstanceRuleWith, collectTyArgs) where @@ -37,7 +38,7 @@ -- | Checks a type argument of class whether it is a synonym chkTypeArg :: Type -> ExtMonad Type chkTypeArg ty = - maybeTM (return ty) (const . addOccurence TypeSynonymInstances $ ty) (semanticsTypeSynRhs ty) + maybeTM (return ty) (const . addEvidence TypeSynonymInstances $ ty) (semanticsTypeSynRhs ty) -- | Collects the type arguments in an instance declaration -- Type arguments are the the types that the class is being instantiated with
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/UnboxedTuplesChecker.hs view
@@ -14,14 +14,14 @@ chkUnboxedTuplesExpr' :: CheckNode Expr -chkUnboxedTuplesExpr' e@(UnboxedTuple _) = addOccurence UnboxedTuples e -chkUnboxedTuplesExpr' e@(UnboxedTupleSection _) = addOccurence UnboxedTuples e +chkUnboxedTuplesExpr' e@(UnboxedTuple _) = addEvidence UnboxedTuples e +chkUnboxedTuplesExpr' e@(UnboxedTupleSection _) = addEvidence UnboxedTuples e chkUnboxedTuplesExpr' e = return e chkUnboxedTuplesPat' :: CheckNode Pattern -chkUnboxedTuplesPat' p@(UnboxTuplePat _) = addOccurence UnboxedTuples p +chkUnboxedTuplesPat' p@(UnboxTuplePat _) = addEvidence UnboxedTuples p chkUnboxedTuplesPat' p = return p chkUnboxedTuplesType' :: CheckNode Type -chkUnboxedTuplesType' t@(UnboxedTupleType _) = addOccurence UnboxedTuples t +chkUnboxedTuplesType' t@(UnboxedTupleType _) = addEvidence UnboxedTuples t chkUnboxedTuplesType' t = return t
+ Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/UndecidableInstancesChecker.hs view
@@ -0,0 +1,98 @@+module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.UndecidableInstancesChecker where + +import Name +import CoAxiom +import FamInstEnv +import InstEnv +import TcType +import GHC hiding (Module, ClassDecl, ClosedTypeFamily) + +import Data.Maybe (isJust) + +import Control.Reference ((^.)) +import Control.Monad.Trans.Maybe (MaybeT(..)) + +import Language.Haskell.Tools.AST +import Language.Haskell.Tools.Refactor +import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad +import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Utils.GHCHelpers + + +-- | If UndecidableInstances is turned on, +-- it checks whether any type class or type family instances needs +-- UndecidableInstances in the module. +gblChkUndecidableInstances :: CheckNode Module +gblChkUndecidableInstances = conditional gblChkUndecidableInstances' UndecidableInstances + +-- | Checks whether any type class or type family instances needs +-- UndecidableInstances in the module. +gblChkUndecidableInstances' :: CheckNode Module +gblChkUndecidableInstances' m = do + (clsInsts, famInsts) <- getInstances [semanticsModule m] + mapM_ chkClsInst clsInsts + mapM_ chkFamInst famInsts + return m + +-- | If the type class instance requires UndecidableInstances, +-- it adds the occurence with location of the instance. +chkClsInst :: ClsInst -> ExtMonad () +chkClsInst inst = when (clsInstNeedsUD inst) + (addEvidenceLoc UndecidableInstances (getSrcSpan inst)) + +-- | Decides whether a type class instance requires UndecidableInstances. +clsInstNeedsUD :: ClsInst -> Bool +clsInstNeedsUD inst = checkInstTermination args theta + where (_, theta, _, args) = instanceSig inst + +-- | If the type class instance requires UndecidableInstances, +-- it adds the occurence with location of the instance. +chkFamInst :: FamInst -> ExtMonad () +chkFamInst inst = when (famInstNeedsUD inst) + (addEvidenceLoc UndecidableInstances (getSrcSpan inst)) + +-- | Decides whether a family instance requires UndecidableInstances. +-- If it is a data family instance, it does not need the extension. +famInstNeedsUD :: FamInst -> Bool +famInstNeedsUD inst + | isTyFamInst inst + , lhs <- fi_tys inst + , rhs <- tcTyFamInsts . fi_rhs $ inst + = checkFamEq lhs rhs + | otherwise = False + +-- | Checks a declaration whether it needs UndecidableInstances. +-- (If the extension is turned on) +chkUndecidableInstancesDecl :: CheckNode Decl +chkUndecidableInstancesDecl = conditional chkUndecidableInstancesDecl' UndecidableInstances + +-- | Checks a declaration whether it needs UndecidableInstances. +-- If a lookup is not successful, it keeps the extension. +chkUndecidableInstancesDecl' :: CheckNode Decl +chkUndecidableInstancesDecl' d = do + mDecl <- runMaybeT (chkUndecidableInstancesDeclMaybe d) + maybe (addEvidence UndecidableInstances d) return mDecl + +-- | Checks a class declaration whether it has a type function in its context, +-- or a closed type family declaration needs UndecidableInstances. +-- For more information on the family check, see checkFamInstRhs. +-- May fail on lookup. +chkUndecidableInstancesDeclMaybe :: Decl -> MaybeT ExtMonad Decl +chkUndecidableInstancesDeclMaybe d@(ClassDecl mCtx _ _ _) + | isJust (mCtx ^. annMaybe) = do + ctx <- liftMaybe $ mCtx ^. annMaybe + let assert = ctx ^. contextAssertion + names = assertionQNames assert + types <- mapM lookupTypeFromId names + if any hasTyFunHead types then addEvidence UndecidableInstances d + else return d + | otherwise = return d +chkUndecidableInstancesDeclMaybe d@(ClosedTypeFamily dh _ _) = do + tyFam <- lookupClosedTyFam dh + let brs = fromBranches . coAxiomBranches $ tyFam + famEqs = map ((,) <$> coAxBranchLHS <*> tcTyFamInsts . coAxBranchRHS) brs + mapM_ (lift . uncurry chkFamEqM) famEqs >> return d + where + chkFamEqM :: [GHC.Type] -> [(GHC.TyCon, [GHC.Type])] -> ExtMonad () + chkFamEqM lhs rhs = when (checkFamEq lhs rhs) + (addEvidence_ UndecidableInstances d) +chkUndecidableInstancesDeclMaybe d = return d
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Checkers/ViewPatternsChecker.hs view
@@ -7,5 +7,5 @@ chkViewPatterns = conditional chkViewPatterns' ViewPatterns chkViewPatterns' :: CheckNode Pattern -chkViewPatterns' p@(ViewPat _ _) = addOccurence ViewPatterns p +chkViewPatterns' p@(ViewPat _ _) = addEvidence ViewPatterns p chkViewPatterns' p = return p
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/ExtMap.hs view
@@ -1,4 +1,7 @@-{-# LANGUAGE DeriveAnyClass, DeriveGeneric, StandaloneDeriving #-} +{-# LANGUAGE DeriveAnyClass #-} +{-# LANGUAGE DeriveFunctor #-} +{-# LANGUAGE DeriveGeneric #-} +{-# LANGUAGE StandaloneDeriving #-} module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMap ( module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMap @@ -36,8 +39,31 @@ type LogicalRelation a = Formula a -type ExtMap = SMap.Map (LogicalRelation Extension) [SrcSpan] +prettyPrintFormula :: Show a => LogicalRelation a -> String +prettyPrintFormula (Var x) = show x +prettyPrintFormula (x :||: y) = prettyPrintFormula x ++ " OR " ++ prettyPrintFormula y +prettyPrintFormula (x :&&: y) = prettyPrintFormula x ++ " AND " ++ prettyPrintFormula y +prettyPrintFormula (x :++: y) = prettyPrintFormula x ++ " XOR " ++ prettyPrintFormula y +prettyPrintFormula (x :->: y) = prettyPrintFormula x ++ " => " ++ prettyPrintFormula y +prettyPrintFormula (x :<->: y) = prettyPrintFormula x ++ " <=> " ++ prettyPrintFormula y +prettyPrintFormula (All xs) = "All [" ++ (intercalate ", " . map prettyPrintFormula $ xs) ++ "]" +prettyPrintFormula (Some xs) = "Some [" ++ (intercalate ", " . map prettyPrintFormula $ xs) ++ "]" +prettyPrintFormula (None xs) = "None [" ++ (intercalate ", " . map prettyPrintFormula $ xs) ++ "]" +prettyPrintFormula (ExactlyOne xs) = "ExactlyOne [" ++ (intercalate ", " . map prettyPrintFormula $ xs) ++ "]" +prettyPrintFormula (AtMostOne xs) = "AtMostOne [" ++ (intercalate ", " . map prettyPrintFormula $ xs) ++ "]" +prettyPrintFormula (Not x) = "Not " ++ prettyPrintFormula x +prettyPrintFormula Yes = "True" +prettyPrintFormula No = "False" +prettyPrintFormula Let{} = "Let ..." +prettyPrintFormula Bound{} = error "Bound is for internal use only" +data Occurence a = Hint { unOcc :: a } + | Evidence { unOcc :: a } + | MissingInformation { unOcc :: a } + deriving (Show, Eq, Ord, Functor) + +type ExtMap = SMap.Map (LogicalRelation Extension) [Occurence SrcSpan] + lVar :: a -> LogicalRelation a lVar = Var @@ -57,11 +83,23 @@ lAll = All complexity :: Extension -> Int -complexity = length . expandExtension +complexity = length . expandExtension' +-- | Completely expand extension +expandExtension' :: Extension -> [Extension] +expandExtension' e = findFixedPoint (nub . expand) [e] + where expand = concatMap expandExtension + +-- | Terminating variant of Control.Monad.Fix.fix +-- It tries to find the fixpoint of a function with a given starting value. +-- It terminates if a value repeats itself. +findFixedPoint :: Eq a => (a -> a) -> a -> a +findFixedPoint f x = findFix' f (f x) x + where findFix' f cur prev = if cur == prev then cur else findFix' f (f cur) cur + determineExtensions :: SMap.Map (LogicalRelation Extension) v -> [Extension] {- NOTE: - We calculate all the possible extension set that satisfy the logical relation, + We calculate all possible extension sets that satisfy the logical relation, then for each extension we remove all the extensions implied by it, (mergeImplied) finally we select the minimal extension set. @@ -69,6 +107,8 @@ - it contains the least amount of extensions - it contains extension with minimal complexity - it is lexicographically the first one (based on the Ord instance of Extension) + + TODO: Comparing on length might be unnecessary -} determineExtensions x = minimal . map toExts $ solution where solution = solve_all . All . LMap.keys $ x @@ -77,7 +117,7 @@ rmImplied :: Extension -> [Extension] -> [Extension] rmImplied e = flip (\\) implied - where implied = delete e $ expandExtension e + where implied = delete e . expandExtension' $ e mergeImplied :: [Extension] -> [Extension] mergeImplied exts = foldl (flip rmImplied) exts exts
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/ExtMonad.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE FlexibleContexts, MonoLocalBinds, RankNTypes #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE RankNTypes #-} module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.ExtMonad @@ -35,32 +37,86 @@ class Checkable node where check :: CheckNode node -addOccurence' :: (Ord k, HasRange a) => - k -> a -> SMap.Map k [SrcSpan] -> SMap.Map k [SrcSpan] -addOccurence' key node = SMap.insertWith (++) key [getRange node] +addHint' :: (Ord k, HasRange a) => + k -> a -> SMap.Map k [Occurence SrcSpan] -> SMap.Map k [Occurence SrcSpan] +addHint' key node = SMap.insertWith (++) key [Hint (getRange node)] --- TODO: add isTurnedOn check -addOccurence_ :: (MonadState ExtMap m, HasRange node) => - Extension -> node -> m () -addOccurence_ extension element = modify $ addOccurence' (lVar extension) element +addHint_ :: (MonadState ExtMap m, HasRange node) => + Extension -> node -> m () +addHint_ extension element = modify $ addHint' (lVar extension) element -addOccurence :: (MonadState ExtMap m, HasRange node) => - Extension -> node -> m node -addOccurence ext node = addOccurence_ ext node >> return node +addHint :: (MonadState ExtMap m, HasRange node) => + Extension -> node -> m node +addHint ext node = addHint_ ext node >> return node +addRelationHint_ :: (MonadState ExtMap m, HasRange node) => + LogicalRelation Extension -> node -> m () +addRelationHint_ rel element = modify $ addHint' rel element + +addRelationHint :: (MonadState ExtMap m, HasRange node) => + LogicalRelation Extension -> node -> m node +addRelationHint rel node = addRelationHint_ rel node >> return node + + +addMI' :: (Ord k, HasRange a) => + k -> a -> SMap.Map k [Occurence SrcSpan] -> SMap.Map k [Occurence SrcSpan] +addMI' key node = SMap.insertWith (++) key [MissingInformation (getRange node)] + +addMI_ :: (MonadState ExtMap m, HasRange node) => + Extension -> node -> m () +addMI_ extension element = modify $ addMI' (lVar extension) element + +addMI :: (MonadState ExtMap m, HasRange node) => + Extension -> node -> m node +addMI ext node = addMI_ ext node >> return node + +addRelationMI_ :: (MonadState ExtMap m, HasRange node) => + LogicalRelation Extension -> node -> m () +addRelationMI_ rel element = modify $ addMI' rel element + +addRelationMI :: (MonadState ExtMap m, HasRange node) => + LogicalRelation Extension -> node -> m node +addRelationMI rel node = addRelationMI_ rel node >> return node + + +addEvidence' :: (Ord k, HasRange a) => + k -> a -> SMap.Map k [Occurence SrcSpan] -> SMap.Map k [Occurence SrcSpan] +addEvidence' key node = SMap.insertWith (++) key [Evidence (getRange node)] + +addEvidence_ :: (MonadState ExtMap m, HasRange node) => + Extension -> node -> m () +addEvidence_ extension element = modify $ addEvidence' (lVar extension) element + +addEvidence :: (MonadState ExtMap m, HasRange node) => + Extension -> node -> m node +addEvidence ext node = addEvidence_ ext node >> return node + addRelation_ :: (MonadState ExtMap m, HasRange node) => LogicalRelation Extension -> node -> m () -addRelation_ rel element = modify $ addOccurence' rel element +addRelation_ rel element = modify $ addEvidence' rel element addRelation :: (MonadState ExtMap m, HasRange node) => LogicalRelation Extension -> node -> m node addRelation rel node = addRelation_ rel node >> return node + +addEvidenceLoc' :: Ord k => k -> SrcSpan -> SMap.Map k [Occurence SrcSpan] -> SMap.Map k [Occurence SrcSpan] +addEvidenceLoc' k loc = SMap.insertWith (++) k [Evidence loc] + +addEvidenceLoc :: MonadState ExtMap m => Extension -> SrcSpan -> m () +addEvidenceLoc ext loc = modify $ addEvidenceLoc' (lVar ext) loc + +addRelationLoc :: MonadState ExtMap m => LogicalRelation Extension -> SrcSpan -> m () +addRelationLoc rel loc = modify $ addEvidenceLoc' rel loc + isTurnedOn :: Extension -> ExtMonad Bool isTurnedOn ext = do defaults <- ask return $! ext `elem` defaults +isTurnedOff :: Extension -> ExtMonad Bool +isTurnedOff ext = not <$> isTurnedOn ext + conditional :: (node -> ExtMonad node) -> Extension -> node -> @@ -84,7 +140,7 @@ if or bs then checker node else return node conditionalAdd :: HasRange node => Extension -> node -> ExtMonad node -conditionalAdd ext = conditional (addOccurence ext) ext +conditionalAdd ext = conditional (addEvidence ext) ext runExtMonadIO :: ExtMonad a -> IO a runExtMonadIO = runGhc (Just libdir) . runExtMonadGHC
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Instances/AppSelector.hs view
@@ -1,4 +1,5 @@-{-# LANGUAGE DataKinds, TypeFamilies #-} +{-# LANGUAGE DataKinds #-} +{-# LANGUAGE TypeFamilies #-} module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Instances.AppSelector where @@ -37,6 +38,7 @@ HasChecker ConDecl = 'True HasChecker Assertion = 'True HasChecker InstanceHead = 'True + HasChecker Context = 'True HasChecker _ = 'False type instance AppSelector Checkable node = HasChecker node
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Instances/Checkable.hs view
@@ -9,7 +9,10 @@ -- | Global checks instance Checkable Module where - check = globalChkNamesForTypeEq + check = gblChkQNamesForTypeEq + >=> gblChkUndecidableInstances + >=> gblChkQNamesForFC + >=> gblChkCPP instance Checkable Decl where check = chkFlexibleInstancesDecl @@ -19,7 +22,9 @@ >=> chkConstraintKindsDecl >=> chkConstrainedClassMethodsDecl >=> chkTypeSynonymInstancesDecl - >=> chkTypeOperatorsDecl' + >=> chkTypeOperatorsDecl + >=> chkUndecidableInstancesDecl + >=> chkFlexibleContextsDecl instance Checkable Pattern where check = chkBangPatterns @@ -108,3 +113,6 @@ instance Checkable InstanceHead where check = chkTypeOperatorsInstHead + +instance Checkable Context where + check = chkFlexibleContexts
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/SupportedExtensions.hs view
@@ -10,10 +10,13 @@ ++ derivingExtensions ++ typeClassExtensions ++ typeSystemExtensions + ++ thExtensions + ++ [Cpp] + ++ [OverloadedStrings] syntacticExtensions :: [Extension] -syntacticExtensions = [ RecordWildCards, TemplateHaskell, BangPatterns - , PatternSynonyms, TupleSections, LambdaCase, QuasiQuotes +syntacticExtensions = [ RecordWildCards, BangPatterns + , PatternSynonyms, TupleSections, LambdaCase , ViewPatterns, MagicHash, UnboxedTuples , FunctionalDependencies, DefaultSignatures , RecursiveDo, Arrows, ParallelListComp @@ -30,8 +33,12 @@ typeClassExtensions :: [Extension] typeClassExtensions = [ MultiParamTypeClasses, ConstrainedClassMethods , FlexibleInstances, TypeSynonymInstances + , FlexibleContexts ] typeSystemExtensions :: [Extension] typeSystemExtensions = [ TypeFamilies, GADTs, ExistentialQuantification - , ConstraintKinds ] + , ConstraintKinds, UndecidableInstances ] + +thExtensions :: [Extension] +thExtensions = [TemplateHaskell, TemplateHaskellQuotes, QuasiQuotes]
Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/TraverseAST.hs view
@@ -1,4 +1,6 @@-{-# LANGUAGE FlexibleContexts, MonoLocalBinds, RankNTypes, TypeApplications #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TypeApplications #-} module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.TraverseAST @@ -14,5 +16,5 @@ import Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Instances.AppSelector() -traverseModule :: CheckNode UnnamedModule +traverseModule :: CheckNode Module traverseModule = topDownM @Checkable check
− Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Utils/Debug.hs
@@ -1,40 +0,0 @@-{-# LANGUAGE FlexibleInstances #-} - - -module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Utils.Debug - ( module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Utils.Debug - , module Debug.Trace - ) where - -import Data.Maybe (isJust) -import Control.Monad.Trans.Maybe -import Control.Reference ((^.), (&)) - -import Debug.Trace -import qualified Outputable as GHC - -import Language.Haskell.Tools.Refactor - - -debugM :: (Monad m, Show a) => m a -> m a -debugM m = do - x <- m - traceShow x m - -debug :: Show a => a -> a -debug x = traceShow x x - --- | Displays True iff the wrapped value is a Just -debugMaybeT :: Monad m => MaybeT m a -> MaybeT m a -debugMaybeT m = MaybeT $ do - x <- runMaybeT m - traceShow (isJust x) (return x) - -showOutputable :: GHC.Outputable a => a -> String -showOutputable = GHC.showSDocUnsafe . GHC.ppr - -showName :: Name -> String -showName = (^. simpleName & unqualifiedName & simpleNameStr) - -showOp :: Operator -> String -showOp = (^. operatorName & unqualifiedName & simpleNameStr)
+ Language/Haskell/Tools/Refactor/Builtin/ExtensionOrganizer/Utils/GHCHelpers.hs view
@@ -0,0 +1,128 @@+module Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Utils.GHCHelpers where + +import Class +import FamInstEnv (FamFlavor(..),FamInst(..)) +import PrelNames +import TcType hiding (sizeType, sizeTypes) +import TyCoRep +import Type +import Var +import GHC + +import Data.List + +-- This module contains private helper functions from GHC (mostly from TcValidity). +-- There are other similar functions that are accessible through the API, +-- but these ones have slighty different behaviour. + +-- Free variables of a type, retaining repetitions, and expanding synonyms +fvType :: Type -> [TyCoVar] +fvType ty | Just exp_ty <- tcView ty = fvType exp_ty +fvType (TyVarTy tv) = [tv] +fvType (TyConApp _ tys) = fvTypes tys +fvType LitTy{} = [] +fvType (AppTy fun arg) = fvType fun ++ fvType arg +fvType (FunTy arg res) = fvType arg ++ fvType res +fvType (ForAllTy (TvBndr tv _) ty) + = fvType (tyVarKind tv) ++ + filter (/= tv) (fvType ty) +fvType (CastTy ty co) = fvType ty ++ fvCo co +fvType (CoercionTy co) = fvCo co + +fvTypes :: [Type] -> [TyVar] +fvTypes = concatMap fvType + +fvCo :: Coercion -> [TyCoVar] +fvCo (Refl _ ty) = fvType ty +fvCo (TyConAppCo _ _ args) = concatMap fvCo args +fvCo (AppCo co arg) = fvCo co ++ fvCo arg +fvCo (ForAllCo tv h co) = filter (/= tv) (fvCo co) ++ fvCo h +fvCo (FunCo _ co1 co2) = fvCo co1 ++ fvCo co2 +fvCo (CoVarCo v) = [v] +fvCo (AxiomInstCo _ _ args) = concatMap fvCo args +fvCo (UnivCo p _ t1 t2) = fvProv p ++ fvType t1 ++ fvType t2 +fvCo (SymCo co) = fvCo co +fvCo (TransCo co1 co2) = fvCo co1 ++ fvCo co2 +fvCo (NthCo _ co) = fvCo co +fvCo (LRCo _ co) = fvCo co +fvCo (InstCo co arg) = fvCo co ++ fvCo arg +fvCo (CoherenceCo co1 co2) = fvCo co1 ++ fvCo co2 +fvCo (KindCo co) = fvCo co +fvCo (SubCo co) = fvCo co +fvCo (AxiomRuleCo _ cs) = concatMap fvCo cs + +fvProv :: UnivCoProvenance -> [TyCoVar] +fvProv UnsafeCoerceProv = [] +fvProv (PhantomProv co) = fvCo co +fvProv (ProofIrrelProv co) = fvCo co +fvProv (PluginProv _) = [] + +sizeType :: Type -> Int +-- Size of a type: the number of variables and constructors +sizeType ty | Just exp_ty <- tcView ty = sizeType exp_ty +sizeType TyVarTy{} = 1 +sizeType (TyConApp _ tys) = sizeTypes tys + 1 +sizeType LitTy{} = 1 +sizeType (AppTy fun arg) = sizeType fun + sizeType arg +sizeType (FunTy arg res) = sizeType arg + sizeType res + 1 +sizeType (ForAllTy _ ty) = sizeType ty +sizeType (CastTy ty _) = sizeType ty +sizeType (CoercionTy _) = 1 + +sizeTypes :: [Type] -> Int +sizeTypes = sum . map sizeType + + +checkInstTermination :: [TcType] -> ThetaType -> Bool +checkInstTermination tys = checkPreds + where + headFvs = fvTypes tys + headSize = sizeTypes tys + + checkPreds :: [PredType] -> Bool + checkPreds = any check + + check :: PredType -> Bool + check predTy + = case classifyPredType predTy of + EqPred {} -> False + IrredPred {} -> check2 predTy (sizeType predTy) + ClassPred cls tys + | isTerminatingClass cls -> False + | isCTupleClass cls -> checkPreds tys + | otherwise + -> check2 predTy (sizeTypes . filterOutInvisibleTypes (classTyCon cls) $ tys) + + check2 predTy predSize = not (null badTvs) || predSize >= headSize + where badTvs = fvType predTy \\ headFvs + -- Tyvars occurring more often in the context than in the head + +isTerminatingClass :: Class -> Bool +isTerminatingClass cls = isIPClass cls + || cls `hasKey` typeableClassKey + || cls `hasKey` coercibleTyConKey + || cls `hasKey` eqTyConKey + || cls `hasKey` heqTyConKey + + +-- | Checks whether a Type has a type function application in its head. +hasTyFunHead :: Type -> Bool +hasTyFunHead ty = case tcSplitTyConApp_maybe ty of + Just (tc, _) -> isTypeFamilyTyCon tc + Nothing -> False + +-- | Given the lhs type arguments and rhs tycon and its arguments +-- of a type family instance, it determines whether it needs UndecidableInstances. +checkFamEq :: [Type] -> [(TyCon, [Type])] -> Bool +checkFamEq lhsTys = any check + where + size = sizeTypes lhsTys + fvs = fvTypes lhsTys + check (_, tys) + | bad_tvs <- fvTypes tys \\ fvs + = not (all isTyFamFree tys) || not (null bad_tvs) || size <= sizeTypes tys + +isTyFamInst :: FamInst -> Bool +isTyFamInst inst + | SynFamilyInst <- fi_flavor inst = True + | otherwise = False
Language/Haskell/Tools/Refactor/Builtin/ExtractBinding.hs view
@@ -1,4 +1,10 @@-{-# LANGUAGE FlexibleContexts, MonoLocalBinds, MultiWayIf, RankNTypes, ScopedTypeVariables, TypeApplications, ViewPatterns #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE MultiWayIf #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE ViewPatterns #-} module Language.Haskell.Tools.Refactor.Builtin.ExtractBinding (extractBinding', tryItOut, extractBindingRefactoring) where
Language/Haskell/Tools/Refactor/Builtin/FloatOut.hs view
@@ -1,4 +1,8 @@-{-# LANGUAGE FlexibleContexts, LambdaCase, MonoLocalBinds, ScopedTypeVariables, TypeApplications #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} module Language.Haskell.Tools.Refactor.Builtin.FloatOut (floatOut, floatOutRefactoring) where
Language/Haskell/Tools/Refactor/Builtin/GenerateExports.hs view
@@ -1,4 +1,7 @@-{-# LANGUAGE FlexibleContexts, LambdaCase, MonoLocalBinds, TupleSections #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE TupleSections #-} module Language.Haskell.Tools.Refactor.Builtin.GenerateExports (generateExports, generateExportsRefactoring) where
Language/Haskell/Tools/Refactor/Builtin/GenerateTypeSignature.hs view
@@ -1,4 +1,10 @@-{-# LANGUAGE FlexibleContexts, GADTs, RankNTypes, ScopedTypeVariables, TupleSections, TypeApplications, ViewPatterns #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE GADTs #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE ViewPatterns #-} module Language.Haskell.Tools.Refactor.Builtin.GenerateTypeSignature ( generateTypeSignature, generateTypeSignature', tryItOut
Language/Haskell/Tools/Refactor/Builtin/GetMatches.hs view
@@ -2,7 +2,6 @@ import Language.Haskell.Tools.Refactor -import Control.Monad.Writer import Control.Reference import Data.Aeson @@ -16,10 +15,9 @@ getMatchesQuery :: QueryChoice getMatchesQuery = LocationQuery "GetMatches" getMatches -getMatches :: RealSrcSpan -> ModuleDom -> [ModuleDom] -> QueryMonad Value +getMatches :: RealSrcSpan -> ModuleDom -> [ModuleDom] -> QueryMonad QueryValue getMatches sp (_,mod) _ - = case selectedName of [n] -> do ctors <- getCtors $ idType $ semanticsId n - return $ toJSON ctors + = case selectedName of [n] -> fmap (GeneralQuery . toJSON) . getCtors . idType . semanticsId $ n [] -> queryError "No name is selected." _ -> queryError "Multiple names are selected." where
Language/Haskell/Tools/Refactor/Builtin/InlineBinding.hs view
@@ -1,4 +1,10 @@-{-# LANGUAGE FlexibleContexts, LambdaCase, MonoLocalBinds, MultiWayIf, RankNTypes, ScopedTypeVariables, TypeApplications #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE MultiWayIf #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TypeApplications #-} -- | Defines the inline binding refactoring that removes a value binding and replaces all occurences -- with an expression equivalent to the body of the binding.
Language/Haskell/Tools/Refactor/Builtin/OrganizeExtensions.hs view
@@ -1,4 +1,8 @@-{-# LANGUAGE FlexibleContexts, LambdaCase, MonoLocalBinds, RankNTypes, TupleSections #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE RankNTypes #-} +{-# LANGUAGE TupleSections #-} module Language.Haskell.Tools.Refactor.Builtin.OrganizeExtensions @@ -16,11 +20,11 @@ import GHC (Ghc(..)) import Control.Reference -import Data.Char (isAlpha) +import Data.Char (isAlphaNum) import Data.Function (on) import Data.Maybe (mapMaybe) import Data.List -import qualified Data.Map.Strict as SMap (empty) +import qualified Data.Map.Strict as SMap (empty, toList) -- NOTE: When working on the entire AST, we should build a monad, -- that will will avoid unnecessary checks. @@ -28,6 +32,11 @@ -- Pretty easy now. Chcek wheter it is already in the ExtMap. +highlightExtensionsQuery :: QueryChoice +highlightExtensionsQuery = GlobalQuery "HighlightExtensions" extQuery + where extQuery :: ModuleDom -> [ModuleDom] -> QueryMonad QueryValue + extQuery (_,m) _ = lift . fmap MarkerQuery . extensionMarkers $ m + organizeExtensionsRefactoring :: RefactoringChoice organizeExtensionsRefactoring = ModuleRefactoring "OrganizeExtensions" (localRefactoring organizeExtensions) @@ -44,12 +53,18 @@ organizeExtensions :: LocalRefactoring organizeExtensions moduleAST = do exts <- liftGhc $ reduceExtensions moduleAST - let langExts = mkLanguagePragma . map show $ exts + let langExts = map (mkLanguagePragma . pure . serializeExt . show) exts ghcOpts = moduleAST ^? filePragmas & annList & opStr & stringNodeStr ghcOpts' = map (mkOptionsGHC . unwords . filter (isPrefixOf "-") . words) ghcOpts - newPragmas = mkFilePragmas $ langExts:ghcOpts' + offExts = map (mkLanguagePragma . pure) + . sort + . map (("No" ++) . serializeExt . show) + . collectTurnedOffExtensions + $ moduleAST + newPragmas = mkFilePragmas $ offExts ++ langExts ++ ghcOpts' + (filePragmas != newPragmas) -- remove empty {-# LANGUAGE #-} pragmas >=> filePragmas !~ filterListSt (\case LanguagePragma (AnnList []) -> False; _ -> True) @@ -61,20 +76,29 @@ let defaults = map replaceDeprecated . collectDefaultExtensions $ moduleAST expanded = expandExtensions defaults (xs, ys) = partition isSupported expanded - -- we can't say anything about generated code - if TemplateHaskell `notElem` expanded - then do - xs' <- flip execStateT SMap.empty . flip runReaderT xs . traverseModule $ moduleAST - -- Merging is needed because there might be unsopported extensions - -- that are implied by supported extensions (TypeFamilies -> MonoLocalBinds) - return . sortBy (compare `on` show) . nub . mergeImplied $ (determineExtensions xs' ++ ys) - else - return . mergeImplied $ defaults + xs' <- flip execStateT SMap.empty . flip runReaderT xs . traverseModule $ moduleAST + let filteredExts = nub . mergeImplied $ (determineExtensions xs' ++ ys) + if any (`elem` filteredExts) [Cpp, TemplateHaskell, TemplateHaskellQuotes, QuasiQuotes] + -- We can't say anything about generated code + then return . mergeImplied $ defaults + -- Merging is needed because there might be unsopported extensions + -- that are implied by supported extensions (TypeFamilies -> MonoLocalBinds) + else return . sortBy (compare `on` show) $ filteredExts + +-- | Collect the required extensions in a module and returns a markers associated with them +extensionMarkers :: UnnamedModule -> Ghc [Marker] +extensionMarkers = fmap (concatMap toMarkers . SMap.toList) . collectExtensions + where toMarkers (rel, occs) = map (toMarker rel) occs + toMarker rel occ = Marker (unOcc occ) Info (showWithLevel rel occ) + showWithLevel rel occ = (head . words . show $ occ) ++ ": " ++ prettyPrintFormula rel + -- | Collects extensions induced by the source code (with location info) collectExtensions :: UnnamedModule -> Ghc ExtMap collectExtensions = collectExtensionsWith traverseModule + +-- | Collects the required extensions from a module using the given traversal method collectExtensionsWith :: CheckNode UnnamedModule -> UnnamedModule -> Ghc ExtMap collectExtensionsWith trvModule moduleAST = do let expanded = expandExtensions . collectDefaultExtensions $ moduleAST @@ -88,11 +112,18 @@ -- | Collects extensions enabled by default collectDefaultExtensions :: UnnamedModule -> [Extension] collectDefaultExtensions = mapMaybe toExt . getExtensions - where - getExtensions :: UnnamedModule -> [String] - getExtensions = flip (^?) (filePragmas & annList & lpPragmas & annList & langExt) +-- | Collects extensions enabled by default +collectTurnedOffExtensions :: UnnamedModule -> [Extension] +collectTurnedOffExtensions = mapMaybe (toExt . drop 2) + . filter (isPrefixOf "No") + . getExtensions + +-- | Collects the string representation of the extensions in the module +getExtensions :: UnnamedModule -> [String] +getExtensions = flip (^?) (filePragmas & annList & lpPragmas & annList & langExt) + toExt :: String -> Maybe Extension -toExt str = case map fst . reads . canonExt . takeWhile isAlpha $ str of +toExt str = case map fst . reads . canonExt . takeWhile isAlphaNum $ str of e:_ -> Just e - [] -> fail $ "Extension '" ++ takeWhile isAlpha str ++ "' is not known." + [] -> fail $ "Extension '" ++ takeWhile isAlphaNum str ++ "' is not known."
Language/Haskell/Tools/Refactor/Builtin/OrganizeImports.hs view
@@ -1,4 +1,9 @@-{-# LANGUAGE FlexibleContexts, LambdaCase, MonoLocalBinds, ScopedTypeVariables, TupleSections, TypeApplications #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeApplications #-} module Language.Haskell.Tools.Refactor.Builtin.OrganizeImports ( organizeImports, projectOrganizeImports
Language/Haskell/Tools/Refactor/Builtin/RenameDefinition.hs view
@@ -1,4 +1,10 @@-{-# LANGUAGE FlexibleContexts, MonoLocalBinds, MultiWayIf, ScopedTypeVariables, TupleSections, TypeApplications, ViewPatterns #-} +{-# LANGUAGE FlexibleContexts #-} +{-# LANGUAGE MonoLocalBinds #-} +{-# LANGUAGE MultiWayIf #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TupleSections #-} +{-# LANGUAGE TypeApplications #-} +{-# LANGUAGE ViewPatterns #-} module Language.Haskell.Tools.Refactor.Builtin.RenameDefinition (renameDefinition, renameDefinition', renameDefinitionRefactoring) where
examples/Refactor/GenerateTypeSignature/PolymorphSubMulti_res.hs view
@@ -2,5 +2,5 @@ f :: (Num a, Ord a) => a -> a f a = g a where - g :: (Num p, Ord p) => p -> p + g :: (Ord p, Num p) => p -> p g a = if a > 0 then a + 1 else a
examples/Refactor/OrganizeImports/MakeExplicit/ImportThree_res.hs view
@@ -1,5 +1,5 @@ module Refactor.OrganizeImports.MakeExplicit.ImportThree where -import Refactor.OrganizeImports.MakeExplicit.Source (g, e, a) +import Refactor.OrganizeImports.MakeExplicit.Source (a, e, g) x = (a,e,g)
examples/Refactor/OrganizeImports/MakeExplicit/ImportUnitedCount_res.hs view
@@ -1,6 +1,6 @@ module Refactor.OrganizeImports.MakeExplicit.ImportUnitedCount where -import Refactor.OrganizeImports.MakeExplicit.Source (A(..), e, a) +import Refactor.OrganizeImports.MakeExplicit.Source (a, e, A(..)) x = B () y = b x
examples/Refactor/OrganizeImports/NarrowType_res.hs view
@@ -1,6 +1,6 @@ module Refactor.OrganizeImports.NarrowType where -import Control.Monad.State (StateT(..), State) +import Control.Monad.State (State, StateT(..)) type St = State () type StT = StateT () IO
examples/Refactor/RenameDefinition/ParenName.hs view
@@ -1,6 +1,6 @@ module Refactor.RenameDefinition.ParenName where -(<>) :: Int -> Int -> Int -a <> b = a + b +(<->) :: Int -> Int -> Int +a <-> b = a + b -x = (<>) 3 4+x = (<->) 3 4
examples/Refactor/RenameDefinition/ParenName_res.hs view
@@ -1,6 +1,6 @@ module Refactor.RenameDefinition.ParenName where -(<->) :: Int -> Int -> Int -a <-> b = a + b +(<-->) :: Int -> Int -> Int +a <--> b = a + b -x = (<->) 3 4+x = (<-->) 3 4
haskell-tools-builtin-refactorings.cabal view
@@ -1,5 +1,5 @@ name: haskell-tools-builtin-refactorings -version: 1.0.1.1 +version: 1.1.0.0 synopsis: Refactoring Tool for Haskell description: Contains a set of refactorings based on the Haskell-Tools framework to easily transform a Haskell program. For the descriptions of the implemented refactorings, see the homepage. homepage: https://github.com/haskell-tools/haskell-tools @@ -43,6 +43,7 @@ , test/ExtensionOrganizerTest/DerivingsTest/*.hs , test/ExtensionOrganizerTest/ExistentialQuantificationTest/*.hs , test/ExtensionOrganizerTest/ExplicitNamespacesTest/*.hs + , test/ExtensionOrganizerTest/FlexibleContextsTest/*.hs , test/ExtensionOrganizerTest/FlexibleInstancesTest/*.hs , test/ExtensionOrganizerTest/FunctionalDependenciesTest/*.hs , test/ExtensionOrganizerTest/GADTsTest/*.hs @@ -61,6 +62,7 @@ , test/ExtensionOrganizerTest/TupleSectionsTest/*.hs , test/ExtensionOrganizerTest/TypeFamiliesTest/*.hs , test/ExtensionOrganizerTest/TypeOperatorsTest/*.hs + , test/ExtensionOrganizerTest/UndecidableInstancesTest/*.hs , test/ExtensionOrganizerTest/ViewPatternsTest/*.hs library @@ -88,10 +90,12 @@ , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.BangPatternsChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ConstrainedClassMethodsChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ConstraintKindsChecker + , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.CPPChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.DefaultSignaturesChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.DerivingsChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ExplicitForAllChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ExplicitNamespacesChecker + , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.FlexibleContextsChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.FlexibleInstancesChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.FunctionalDependenciesChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.GADTsChecker @@ -111,11 +115,12 @@ , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.TypeOperatorsChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.TypeSynonymInstancesChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.UnboxedTuplesChecker + , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.UndecidableInstancesChecker , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Checkers.ViewPatternsChecker - , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Utils.Debug + , Language.Haskell.Tools.Refactor.Builtin.ExtensionOrganizer.Utils.GHCHelpers - build-depends: base >= 4.10 && < 4.11 + build-depends: base >= 4.11 && < 4.12 , mtl >= 2.2 && < 2.3 , aeson >= 1.0 && < 1.4 , uniplate >= 1.6 && < 1.7 @@ -128,15 +133,15 @@ , references >= 0.3 && < 0.4 , split >= 0.2 && < 0.3 , filepath >= 1.4 && < 1.5 - , template-haskell >= 2.12 && < 2.13 + , template-haskell >= 2.13 && < 2.14 , minisat-solver >= 0.1 && < 0.2 - , ghc >= 8.2 && < 8.3 - , Cabal >= 2.0 && < 2.3 - , haskell-tools-ast >= 1.0 && < 1.1 - , haskell-tools-backend-ghc >= 1.0 && < 1.1 - , haskell-tools-rewrite >= 1.0 && < 1.1 - , haskell-tools-prettyprint >= 1.0 && < 1.1 - , haskell-tools-refactor >= 1.0 && < 1.1 + , ghc >= 8.4 && < 8.5 + , portable-lines >= 0.1 && < 0.2 , Cabal >= 2.0 && < 2.3 + , haskell-tools-ast >= 1.1 && < 1.2 + , haskell-tools-backend-ghc >= 1.1 && < 1.2 + , haskell-tools-rewrite >= 1.1 && < 1.2 + , haskell-tools-prettyprint >= 1.1 && < 1.2 + , haskell-tools-refactor >= 1.1 && < 1.2 default-language: Haskell2010 test-suite haskell-tools-builtin-refactorings-test @@ -144,7 +149,7 @@ ghc-options: -with-rtsopts=-M2g hs-source-dirs: test main-is: Main.hs - build-depends: base >= 4.10 && < 4.11 + build-depends: base >= 4.11 && < 4.12 , tasty >= 0.11 && < 1.1 , tasty-hunit >= 0.9 && < 0.11 , transformers >= 0.5 && < 0.6 @@ -157,15 +162,15 @@ , references >= 0.3 && < 0.4 , split >= 0.2 && < 0.3 , time >= 1.8 && < 1.9 - , template-haskell >= 2.12 && < 2.13 - , ghc >= 8.2 && < 8.3 + , template-haskell >= 2.13 && < 2.14 + , ghc >= 8.4 && < 8.5 , ghc-paths >= 0.1 && < 0.2 , Cabal >= 2.0 && < 2.3 - , haskell-tools-ast >= 1.0 && < 1.1 - , haskell-tools-backend-ghc >= 1.0 && < 1.1 - , haskell-tools-rewrite >= 1.0 && < 1.1 - , haskell-tools-prettyprint >= 1.0 && < 1.1 - , haskell-tools-refactor >= 1.0 && < 1.1 + , haskell-tools-ast >= 1.1 && < 1.2 + , haskell-tools-backend-ghc >= 1.1 && < 1.2 + , haskell-tools-rewrite >= 1.1 && < 1.2 + , haskell-tools-prettyprint >= 1.1 && < 1.2 + , haskell-tools-refactor >= 1.1 && < 1.2 , haskell-tools-builtin-refactorings default-language: Haskell2010 @@ -177,7 +182,7 @@ , ExtensionOrganizerTest.Parser hs-source-dirs: test main-is: ExtensionOrganizerTest/Main.hs - build-depends: base >= 4.10 && < 4.11 + build-depends: base >= 4.11 && < 4.12 , tasty >= 0.11 && < 1.1 , tasty-hunit >= 0.9 && < 0.11 , transformers >= 0.5 && < 0.6 @@ -190,15 +195,15 @@ , references >= 0.3 && < 0.4 , split >= 0.2 && < 0.3 , time >= 1.8 && < 1.9 - , template-haskell >= 2.12 && < 2.13 - , ghc >= 8.2 && < 8.3 + , template-haskell >= 2.13 && < 2.14 + , ghc >= 8.4 && < 8.5 , ghc-paths >= 0.1 && < 0.2 , Cabal >= 2.0 && < 2.3 - , haskell-tools-ast >= 1.0 && < 1.1 - , haskell-tools-backend-ghc >= 1.0 && < 1.1 - , haskell-tools-rewrite >= 1.0 && < 1.1 - , haskell-tools-prettyprint >= 1.0 && < 1.1 - , haskell-tools-refactor >= 1.0 && < 1.1 + , haskell-tools-ast >= 1.1 && < 1.2 + , haskell-tools-backend-ghc >= 1.1 && < 1.2 + , haskell-tools-rewrite >= 1.1 && < 1.2 + , haskell-tools-prettyprint >= 1.1 && < 1.2 + , haskell-tools-refactor >= 1.1 && < 1.2 , haskell-tools-builtin-refactorings default-language: Haskell2010 @@ -210,7 +215,7 @@ -- , ExtensionOrganizerBenchmark.UniPlateTraversal -- hs-source-dirs: benchmark -- main-is: ExtensionOrganizerBenchmark/Main.hs --- build-depends: base >= 4.10 && < 4.11 +-- build-depends: base >= 4.11 && < 4.12 -- , criterion >= 1.2 && < 1.3 -- , silently >= 1.2 && < 1.3 -- , transformers >= 0.5 && < 0.6 @@ -223,8 +228,8 @@ -- , references >= 0.3 && < 0.4 -- , split >= 0.2 && < 0.3 -- , time >= 1.8 && < 1.9 --- , template-haskell >= 2.12 && < 2.13 --- , ghc >= 8.2 && < 8.3 +-- , template-haskell >= 2.13 && < 2.14 +-- , ghc >= 8.4 && < 8.5 -- , ghc-paths >= 0.1 && < 0.2 -- , Cabal >= 2.0 && < 2.3 -- , haskell-tools-ast >= 1.0 && < 1.1
test/ExtensionOrganizerTest/AnnotationParser.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE LambdaCase #-} + module ExtensionOrganizerTest.AnnotationParser -- (getLocalExtensionAnnotations, getGlobalExtensionAnnotations) where @@ -18,21 +20,40 @@ | [] <- getGlobalAnnot s = [] | otherwise = parseGlobalAnnot . getGlobalAnnot $ s -getLocalExtensionAnnotations :: String -> SMap.Map (LogicalRelation Extension) [Int] +-- | Parses a file, collects occurences mapped to extension formulas +-- , transform them into formulas mapped to occurences. +getLocalExtensionAnnotations :: String -> SMap.Map (LogicalRelation Extension) [Occurence Int] getLocalExtensionAnnotations s = foldl f SMap.empty (parseFile s) - where f m (num, exts) = foldl (g num) m exts - g num m' ext = SMap.insertWith (++) ext [num] m' + where f m (occ, exts) = foldl (g occ) m exts + g occ m' ext = SMap.insertWith (++) ext [occ] m' -parseFile :: String -> [(Int, [LogicalRelation Extension])] -- SMap.Map Extension [Int] -parseFile = map parseLine . zip [1..] . lines +parseFile :: String -> [(Occurence Int, [LogicalRelation Extension])] -- SMap.Map Extension [Int] +parseFile = concatMap (separateOccurences . parseLine) . zip [1..] . lines -parseLine :: (Int, String) -> (Int, [LogicalRelation Extension]) +-- | Separates the occurences into hints and evidence. +-- The resulting list will always contain three elements +separateOccurences :: (Int, [Occurence (LogicalRelation Extension)]) -> + [(Occurence Int, [LogicalRelation Extension])] +separateOccurences (ln, occs) = [(Evidence ln, evs'), (Hint ln, hints'), (Hint ln, mis')] + where evs = filter (\case Evidence{} -> True; _ -> False;) occs + hints = filter (\case Hint{} -> True; _ -> False;) occs + mis = filter (\case MissingInformation{} -> True; _ -> False;) occs + + evs' = map fromOcc evs + hints' = map fromOcc hints + mis' = map fromOcc mis + + fromOcc (Evidence x) = x + fromOcc (Hint x) = x + fromOcc (MissingInformation x) = x + +parseLine :: (Int, String) -> (Int, [Occurence (LogicalRelation Extension)]) parseLine (num, line) = (num, parseLocalAnnot . getLocalAnnot $ line) -parseLocalAnnot :: String -> [LogicalRelation Extension] +parseLocalAnnot :: String -> [Occurence (LogicalRelation Extension)] parseLocalAnnot = map parseRelation . prepareAnnot -parseRelation :: String -> LogicalRelation Extension +parseRelation :: String -> Occurence (LogicalRelation Extension) parseRelation = execParser relation parseGlobalAnnot :: String -> [Extension] @@ -71,17 +92,22 @@ crop :: String -> String crop = dropWhile isSpace . reverse . dropWhile isSpace . reverse +relation :: Parser (Occurence (LogicalRelation Extension)) +relation = Hint <$> (token "(" *> relation' <* token ")") + <|> MissingInformation <$> (token "[" *> relation' <* token "]") + <|> Evidence <$> relation' + -- | A relation parser that tries to reduce the left-hand side of operators, -- before applíing the left-recursive rules. -- Also the rules are a bit convoluted in order to respect the precedence -- of the operators -relation :: Parser (LogicalRelation Extension) -relation = primRel +relation' :: Parser (LogicalRelation Extension) +relation' = primRel <|> (:&&:) <$> primRel <*> (token "*" *> primRel) - <|> (:||:) <$> primRel <*> (token "+" *> relation) - <|> (:||:) <$> relation <*> (token "+" *> relation) - <|> (:&&:) <$> relation <*> (token "*" *> relation) - <|> Not <$> (token "~" *> relation) + <|> (:||:) <$> primRel <*> (token "+" *> relation') + <|> (:||:) <$> relation' <*> (token "+" *> relation') + <|> (:&&:) <$> relation' <*> (token "*" *> relation') + <|> Not <$> (token "~" *> relation') where primRel = (lVar . readExt) <$> word <|> Not <$> (token "~" *> primRel)
test/ExtensionOrganizerTest/ConstrainedClassMethodsTest/MixedTyVars.hs view
@@ -5,5 +5,5 @@ import Definitions class C a where - op1 :: D (a, b) => a -> b + op1 :: D (a, b) => a -> b {-* FlexibleContexts, FlexibleContexts *-} op2 :: D b => b -> a
+ test/ExtensionOrganizerTest/FlexibleContextsTest/Definitions.hs view
@@ -0,0 +1,33 @@+{-# LANGUAGE MultiParamTypeClasses, TypeOperators, TypeFamilies, ConstraintKinds, FlexibleContexts, RankNTypes #-} + +module Definitions where + +import GHC.Exts + +data T a = T a + +class C a where + foo :: a -> () + +class a :?: b where + q :: a -> b -> () + +class (a :!: b) c where + e :: a -> b -> c -> () + +type family TF a :: Constraint + +instance C [a] where + foo = const () + +type Ctxt a = C [a] +type FunWCtxt a = Ctxt a => a -> () + +fCtxt :: FunWCtxt a +fCtxt = const () + +fNestedCtxt :: a -> FunWCtxt a -> () +fNestedCtxt x f = f x + + +type SimpleEq a = Eq a
+ test/ExtensionOrganizerTest/FlexibleContextsTest/ForAll.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE ExplicitForAll, FlexibleContexts, TypeOperators #-} + +module ForAll where + +import Definitions + +f :: forall a . C [a] => [a] -> () {-* FlexibleContexts, FlexibleContexts, ExplicitForAll *-} +f = foo {-* FlexibleContexts *-} + +g :: forall a . (C [a], [a] :?: [a]) => [a] -> () {-* FlexibleContexts, FlexibleContexts, FlexibleContexts, ExplicitForAll, TypeOperators *-} +g = foo {-* FlexibleContexts *-}
+ test/ExtensionOrganizerTest/FlexibleContextsTest/NestedCtx.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE RankNTypes, FlexibleContexts, TypeOperators #-} + +module NestedCtx where + +import Definitions + +f :: (C [a] => [a] -> ()) -> () {-* FlexibleContexts, FlexibleContexts *-} +f = undefined {-* FlexibleContexts *-} + +g :: ((C [a], [a] :?: [a]) => [a] -> ()) -> () {-* FlexibleContexts, FlexibleContexts, FlexibleContexts, TypeOperators *-} +g = undefined {-* FlexibleContexts *-}
+ test/ExtensionOrganizerTest/FlexibleContextsTest/Synonyms.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE FlexibleContexts #-} + +module Synonyms where + +import Definitions + +f1 = fCtxt {-* (FlexibleContexts) *-} + +f2 = fNestedCtxt {-* (FlexibleContexts), FlexibleContexts *-} + +f3 :: Ctxt a => a -> () {-* FlexibleContexts, FlexibleContexts *-} +f3 = const () {-* FlexibleContexts *-} + +f4 :: FunWCtxt a {-* FlexibleContexts, FlexibleContexts *-} +f4 = const () {-* FlexibleContexts *-} + +f5 :: SimpleEq a => a -> () +f5 = const () + +f6 :: Eq a => a -> () +f6 = id fCtxt :: FunWCtxt a {-* (FlexibleContexts), (FlexibleContexts) *-}
+ test/ExtensionOrganizerTest/FlexibleContextsTest/TyFamConstraints.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE FlexibleContexts, TypeFamilies #-} + +module TyFamConstraints where + +import Definitions + +f1 :: TF [a] => a -> () +f1 = const () + +f2 :: [a] ~ [Int] => a -> Int {-* TypeFamilies + GADTs, TypeFamilies + GADTs *-} +f2 = id {-* TypeFamilies + GADTs *-}
+ test/ExtensionOrganizerTest/FlexibleContextsTest/TySynConstraints.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE FlexibleContexts, ConstraintKinds, TypeOperators, TypeFamilies, RankNTypes #-} + +module TySynConstraints where + +import GHC.Exts +import Definitions + +type CT1 a = Eq [a] {-* FlexibleContexts, FlexibleContexts, ConstraintKinds *-} +type CT2 a = (Eq [a]) {-* FlexibleContexts, FlexibleContexts, ConstraintKinds *-} +type CT3 a = (Eq a, Ord [a]) {-* FlexibleContexts, FlexibleContexts, ConstraintKinds *-} +type CT4 a = (Eq a, Ord [a]) {-* FlexibleContexts, FlexibleContexts, ConstraintKinds *-} +type CT5 a = a :?: T a {-* FlexibleContexts, FlexibleContexts, ConstraintKinds, TypeOperators *-} +type CT6 a = (a :!: a) (T a) {-* FlexibleContexts, FlexibleContexts, ConstraintKinds, TypeOperators *-} +type CT7 a = Eq [a] => a {-* FlexibleContexts, FlexibleContexts *-} +type CT8 a = (Ctxt a, Ord a) {-* FlexibleContexts, FlexibleContexts, ConstraintKinds *-} + + +type CTTF1 a b = [a] ~ b {-* TypeFamilies + GADTs, TypeFamilies + GADTs, ConstraintKinds *-} +type CTTF2 a = (TF [a], TF (T a), TF a ~ Eq [a]) {-* TypeFamilies + GADTs, TypeFamilies + GADTs, ConstraintKinds *-} + +type CTTyVarHeads (f :: * -> Constraint) a = f a {-* KindSignatures, KindSignatures, KindSignatures, ConstraintKinds *-}
+ test/ExtensionOrganizerTest/FlexibleContextsTest/TypeApp.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE FlexibleContexts, TypeOperators #-} + +module TypeApp where + +import Definitions + +f :: C (T a) => T a -> () {-* FlexibleContexts, FlexibleContexts *-} +f = foo {-* FlexibleContexts *-} + +g :: (C (T a), (T a) :?: (T a)) => T a -> () {-* FlexibleContexts, FlexibleContexts, FlexibleContexts, TypeOperators *-} +g = foo {-* FlexibleContexts *-}
+ test/ExtensionOrganizerTest/FlexibleContextsTest/VarType.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE FlexibleContexts, ExplicitForAll, KindSignatures, TypeOperators #-} + +module VarType where + +import Definitions + +f :: forall (f :: * -> *) a . C (f a) => f a -> () {-* ExplicitForAll, KindSignatures, KindSignatures, KindSignatures *-} +f = foo + +g :: forall (f :: * -> *) a . (C (f a), (f a) :?: a) => f a -> () {-* ExplicitForAll, KindSignatures, KindSignatures, KindSignatures, TypeOperators *-} +g = foo
+ test/ExtensionOrganizerTest/FlexibleContextsTest/WithScopedTyVarsMagic.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE FlexibleContexts, ScopedTypeVariables #-} + +module WithScopedTyVarsMagic where + +import Definitions + +f :: Eq a => a -> () +f = id fCtxt :: C [a] => a -> () {-* (FlexibleContexts), FlexibleContexts *-}
test/ExtensionOrganizerTest/Main.hs view
@@ -55,6 +55,8 @@ , mkTests constrainedClassMethodsTest , mkTests multiWayIfTest , mkTests typeOperatorsTest + , mkTests undecidableInstancesTest + , mkTests flexibleContextsTest ] testRoot = "test/ExtensionOrganizerTest" @@ -67,13 +69,14 @@ type TestName = String type ModuleName = String type Line = Int -type SimpleMap = SMap.Map (LogicalRelation Extension) [Line] +type SimpleMap = SMap.Map (LogicalRelation Extension) [Occurence Line] spanToLine :: SrcSpan -> Line -spanToLine (RealSrcSpan s) = srcSpanEndLine s +spanToLine (RealSrcSpan s) = srcSpanEndLine s +spanToLine (UnhelpfulSpan _) = 0 simplifyExtMap :: ExtMap -> SimpleMap -simplifyExtMap = SMap.map (map spanToLine) +simplifyExtMap = SMap.map (map (fmap spanToLine)) getExtensionsFrom :: FilePath -> ModuleName -> IO SimpleMap getExtensionsFrom dir moduleName = runGhc (Just libdir) $ do @@ -178,7 +181,7 @@ , "InAlt" , "InExpr" , "InMatchLhs" - , "InPatSynRhs" + -- , "InPatSynRhs" , "InPattern" , "InRhsGuard" , "InStmt" @@ -422,4 +425,37 @@ , "NormalClassDecl" , "NormalDataDecl" , "NormalInstance" + ] + +undecidableInstancesTest :: TestSuite +undecidableInstancesTest = (udRoot, udModules) +udRoot = "UndecidableInstancesTest" +udModules = [ "BadTyVars" + , "GNDForAssociatedTypes" + , "NoSmallerPred" + , "SynBadTyVars" + , "SynNoSmallerPred" + , "SynTupleConstraint" + , "SynTyFamBadTyVars" + , "SynTyFamNestedTyFun" + , "SynTyFamNoSmaller" + , "SynTyFunInSuperClass" + , "TupleConstraint" + , "TyFamBadTyVars" + , "TyFamNestedTyFun" + , "TyFamNoSmaller" + , "TyFunInSuperClass" + ] + +flexibleContextsTest :: TestSuite +flexibleContextsTest = (fcRoot, fcModules) +fcRoot = "FlexibleContextsTest" +fcModules = [ "ForAll" + , "NestedCtx" + , "Synonyms" + , "TyFamConstraints" + , "TypeApp" + , "TySynConstraints" + , "VarType" + , "WithScopedTyVarsMagic" ]
test/ExtensionOrganizerTest/TypeFamiliesTest/Definitions.hs view
@@ -17,8 +17,11 @@ type HiddenEqRel a b = EqRel a b type ComplexEqRelType a = - Eq a => a -> a -> (forall c . HiddenEqRel a c => c -> c -> Bool) -> Bool + Eq a => a -> a -> (forall c . HiddenEqRel a c => c -> c -> Bool) -> Bool eqRelName :: EqRel a b => a -> b eqRelName = id + +nestedEqRelName :: a -> (forall a b . EqRel a b => a -> b) -> a +nestedEqRelName x f = f x
test/ExtensionOrganizerTest/TypeFamiliesTest/NestedTypeEqualityContextSynonyms.hs view
@@ -7,7 +7,7 @@ {-@ GADTs @-} f :: HiddenEqRel a b => a -> b {-* TypeFamilies + GADTs, TypeFamilies + GADTs *-} -f = id +f = id {-* TypeFamilies + GADTs *-} g :: ComplexEqRelType a {-* TypeFamilies + GADTs, TypeFamilies + GADTs *-} -g x y h = h x y {-* TypeFamilies + GADTs *-} +g x y h = h x y {-* TypeFamilies + GADTs, TypeFamilies + GADTs, (TypeFamilies + GADTs) *-}
test/ExtensionOrganizerTest/TypeFamiliesTest/NestedTypeEqualitySynonyms.hs view
@@ -6,4 +6,4 @@ {-@ GADTs, ConstraintKinds @-} -type TripleEq a b c = (HiddenEqRel a b, HiddenEqRel b c) {-* TypeFamilies + GADTs, TypeFamilies + GADTs, ConstraintKinds *-} +type TripleEq a b c = (HiddenEqRel a b, HiddenEqRel b c) {-* TypeFamilies + GADTs, TypeFamilies + GADTs, TypeFamilies + GADTs, ConstraintKinds *-}
test/ExtensionOrganizerTest/TypeFamiliesTest/TypeEqualityContext.hs view
@@ -5,4 +5,4 @@ {-@ GADTs @-} f :: a ~ b => a -> b {-* TypeFamilies + GADTs, TypeFamilies + GADTs *-} -f = id +f = id {-* TypeFamilies + GADTs *-}
test/ExtensionOrganizerTest/TypeFamiliesTest/TypeEqualityContextSynonyms.hs view
@@ -7,7 +7,7 @@ {-@ GADTs @-} f :: EqRel a b => a -> b {-* TypeFamilies + GADTs, TypeFamilies + GADTs *-} -f = id +f = id {-* TypeFamilies + GADTs *-} g :: TrfAB a b {-* TypeFamilies + GADTs, TypeFamilies + GADTs *-} -g = id +g = id {-* TypeFamilies + GADTs *-}
test/ExtensionOrganizerTest/TypeFamiliesTest/TypeEqualityInName.hs view
@@ -6,4 +6,10 @@ {-@ GADTs @-} -g = eqRelName {-* TypeFamilies + GADTs *-} +g1 = eqRelName {-* (TypeFamilies + GADTs) *-} + +g2 = nestedEqRelName {-* TypeFamilies + GADTs, (TypeFamilies + GADTs) *-} + +x <+> y = nestedEqRelName {-* TypeFamilies + GADTs, (TypeFamilies + GADTs) *-} + +x <-> y = nestedEqRelName 5 id {-* (TypeFamilies + GADTs) *-}
test/ExtensionOrganizerTest/TypeFamiliesTest/TypeEqualitySynonyms.hs view
@@ -6,4 +6,4 @@ {-@ GADTs, ConstraintKinds @-} -type DoubleEq a b c = (EqRel a b, EqRel b c) {-* TypeFamilies + GADTs, TypeFamilies + GADTs, ConstraintKinds *-} +type DoubleEq a b c = (EqRel a b, EqRel b c) {-* TypeFamilies + GADTs, TypeFamilies + GADTs, TypeFamilies + GADTs, ConstraintKinds *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/BadTyVars.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE UndecidableInstances, FlexibleInstances #-} + +module BadTyVars where + +import Definitions + + +-- NOTE: This instance need FlexibleContexts, but if UndecidableInstances +-- is turned on, it compiles. Watch out for this! +instance C (a,a) => C a {-* UndecidableInstances, FlexibleInstances *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/Definitions.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE TypeFamilies #-} + +module Definitions where + +class C a where + type T a :: * + +class C2 a +class C3 a +class C4 a +class C5 a + +type family T1 a + +type family CT a where + CT a = Eq a + +data D a b = D a b
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/GNDForAssociatedTypes.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE UndecidableInstances, GeneralizedNewtypeDeriving, TypeFamilies #-} + +module GNDForAssociatedTypes where + +class C a where + type T a :: * {-* TypeFamilies, KindSignatures *-} + +newtype Loop = MkLoop Loop + deriving C {-* GeneralizedNewtypeDeriving, UndecidableInstances *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/NoSmallerPred.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE FlexibleInstances, UndecidableInstances, ExplicitForAll #-} + +module NoSmallerPred where + +import Definitions + +instance Eq a => C a {-* UndecidableInstances, FlexibleInstances *-} +-- these definitions need FlexibleContexts, but they compile anyway ... +instance Eq (D [a] b) => C2 (a,b) {-* UndecidableInstances *-} +instance forall a b . Eq (D [a] b) => C3 (a,b) {-* UndecidableInstances *-} +instance Eq (D Int Int) => C4 (Int,Int) {-* UndecidableInstances, FlexibleInstances *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/SynBadTyVars.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE ConstraintKinds, UndecidableInstances, FlexibleInstances, FlexibleContexts #-} + +module SynBadTyVars where + +import Definitions + + +type SynC a = C (a,a) {-* ConstraintKinds, FlexibleContexts, FlexibleContexts *-} + +instance SynC (a,a) => C a {-* UndecidableInstances, FlexibleInstances, FlexibleContexts *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/SynNoSmallerPred.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE ConstraintKinds, FlexibleInstances, FlexibleContexts, UndecidableInstances, ExplicitForAll #-} + +module SynNoSmallerPred where + +import Definitions + +type Syn1 a = Eq a {-* ConstraintKinds *-} +type Syn2 a b = Eq (D [a] b) {-* ConstraintKinds, FlexibleContexts, FlexibleContexts *-} +type Syn3 = Syn2 Int Int {-* ConstraintKinds, FlexibleContexts, FlexibleContexts *-} + +instance Syn1 a => C a {-* UndecidableInstances, FlexibleInstances *-} +instance Syn2 a b => C2 (a,b) {-* UndecidableInstances, FlexibleContexts *-} +instance forall a b . Syn2 a b => C3 (a,b) {-* UndecidableInstances, FlexibleContexts *-} +instance Syn3 => C4 (Int,Int) {-* UndecidableInstances, FlexibleInstances, FlexibleContexts *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTupleConstraint.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE ConstraintKinds, FlexibleInstances, UndecidableInstances #-} + +module SynTupleConstraint where + +import Definitions + +type Syn a = (Ord a, Eq a) {-* ConstraintKinds *-} + +instance Syn a => C a {-* UndecidableInstances, FlexibleInstances *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTyFamBadTyVars.hs view
@@ -0,0 +1,22 @@+{-# LANGUAGE UndecidableInstances, TypeFamilies #-} + +module SynTyFamBadTyVars where + +import Definitions hiding (CT) + +type Syn0 a = [a] +type Syn1 a b = [(a,b)] +type Syn2 a = (a,a) +type Syn3 a b c = (a,b,c) +type Syn4 a = Syn3 a a a +type Syn5 a b = (a,b) + + +type instance T1 (Syn0 a) = T1 (Syn2 a) {-* UndecidableInstances, TypeFamilies *-} + +type family CT a where + CT (Syn1 a b) = CT (Syn2 a) + CT (Syn3 a b c) = CT (Syn4 a) {-* UndecidableInstances, UndecidableInstances, TypeFamilies *-} + +instance C (a,b) where + type T (Syn5 a b) = T (Syn2 a) {-* UndecidableInstances, TypeFamilies *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTyFamNestedTyFun.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE UndecidableInstances, TypeFamilies #-} + +module SynTyFamNestedTyFun where + +import Definitions hiding (CT) + +type Syn1 a = T1 (T1 a) +type Syn2 a = CT (CT a) + +type instance T1 [a] = Syn1 a {-* UndecidableInstances, TypeFamilies *-} + +type family CT a where + CT [[a]] = Syn2 a + CT a = Syn2 a {-* UndecidableInstances, UndecidableInstances, TypeFamilies *-} + +instance C [a] where + type T [a] = Syn1 a {-* UndecidableInstances, TypeFamilies *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTyFamNoSmaller.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE UndecidableInstances, TypeFamilies #-} + +module SynTyFamNoSmaller where + +import Definitions hiding (CT) + +type Syn1 a = T1 a +type Syn2 a = CT [a] +type Syn3 a = CT a +type Syn4 a = T [[a]] + +type instance T1 a = Syn1 a {-* UndecidableInstances, TypeFamilies *-} + +type family CT a where + CT [a] = Syn2 a + CT a = Syn3 a {-* UndecidableInstances, UndecidableInstances, TypeFamilies *-} + +instance C [a] where + type T [a] = Syn4 a {-* UndecidableInstances, TypeFamilies *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/SynTyFunInSuperClass.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE UndecidableInstances, UndecidableSuperClasses, ConstraintKinds #-} + +module SynTyFunInSuperClass where + +import Definitions (CT) + +type Syn a = CT a {-* ConstraintKinds *-} + +class Syn a => C a {-* UndecidableInstances *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/TupleConstraint.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE FlexibleInstances, UndecidableInstances #-} + +module TupleConstraint where + +import Definitions + +instance (Ord a, Eq a) => C a {-* UndecidableInstances, FlexibleInstances *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/TyFamBadTyVars.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE UndecidableInstances, TypeFamilies #-} + +module TyFamBadTyVars where + +import Definitions hiding (CT) + +type instance T1 [a] = T1 (a,a) {-* UndecidableInstances, TypeFamilies *-} + +type family CT a where + CT [(a,b)] = CT (a,a) + CT (a,b,c) = CT (a,a,a) {-* UndecidableInstances, UndecidableInstances, TypeFamilies *-} + +instance C (a,b) where + type T (a,b) = T (a,a) {-* UndecidableInstances, TypeFamilies *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/TyFamNestedTyFun.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE UndecidableInstances, TypeFamilies #-} + +module TyFamNestedTyFun where + +import Definitions hiding (CT) + +type instance T1 [a] = T1 (T1 a) {-* UndecidableInstances, TypeFamilies *-} + +type family CT a where + CT [[a]] = CT (CT a) + CT a = CT (CT a) {-* UndecidableInstances, UndecidableInstances, TypeFamilies *-} + +instance C [a] where + type T [a] = T (T [a]) {-* UndecidableInstances, TypeFamilies *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/TyFamNoSmaller.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE UndecidableInstances, TypeFamilies #-} + +module TyFamNoSmaller where + +import Definitions hiding (CT) + +type instance T1 a = T1 a {-* UndecidableInstances, TypeFamilies *-} + +type family CT a where + CT [a] = CT [a] + CT a = CT a {-* UndecidableInstances, UndecidableInstances, TypeFamilies *-} + +instance C [a] where + type T [a] = T [[a]] {-* UndecidableInstances, TypeFamilies *-}
+ test/ExtensionOrganizerTest/UndecidableInstancesTest/TyFunInSuperClass.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE UndecidableInstances, UndecidableSuperClasses #-} + +module TyFunInSuperClass where + +import Definitions (CT) + +class CT a => C a {-* UndecidableInstances *-}
test/Main.hs view
@@ -1,6 +1,7 @@-{-# LANGUAGE LambdaCase, MonoLocalBinds #-} +{-# LANGUAGE LambdaCase #-} +{-# LANGUAGE MonoLocalBinds #-} - + module Main where import Test.Tasty (TestTree, testGroup, defaultMain) @@ -142,7 +143,7 @@ , ("Refactor.RenameDefinition.AccentName", "3:1-3:2", "á") , ("Refactor.RenameDefinition.QualName", "3:1-3:2", "q") , ("Refactor.RenameDefinition.BacktickName", "3:1-3:2", "g") - , ("Refactor.RenameDefinition.ParenName", "4:3-4:5", "<->") + , ("Refactor.RenameDefinition.ParenName", "4:3-4:5", "<-->") , ("Refactor.RenameDefinition.RecordWildcards", "4:32-4:33", "yy") , ("Refactor.RenameDefinition.RecordPatternSynonyms", "4:16-4:17", "xx") , ("Refactor.RenameDefinition.ClassMember", "7:3-7:4", "q") @@ -277,7 +278,7 @@ wrongMultiModuleTests = [ ("InlineBinding 3:1-3:2", "A", "Refactor" </> "InlineBinding" </> "AppearsInAnother", []) ] - + autoCorrectTests = [ ("Refactor.AutoCorrect.SimpleReParen", "3:5-3:12") , ("Refactor.AutoCorrect.ExternalInstanceReParen", "4:5-4:15") @@ -412,7 +413,7 @@ load LoadAllTargets allMods <- getModuleGraph selectedMod <- getModSummary (GHC.mkModuleName target) - let otherModules = filter (not . (\ms -> ms_mod ms == ms_mod selectedMod && ms_hsc_src ms == ms_hsc_src selectedMod)) allMods + let otherModules = filter (not . (\ms -> ms_mod ms == ms_mod selectedMod && ms_hsc_src ms == ms_hsc_src selectedMod)) (mgModSummaries allMods) targetMod <- parseTyped selectedMod otherMods <- mapM parseTyped otherModules res <- performCommand builtinRefactorings (splitOn " " command) @@ -425,7 +426,7 @@ Left l -> Left l) $ res -type ParsedModule = Ann AST.UModule (Dom RdrName) SrcTemplateStage +type ParsedModule = Ann AST.UModule (Dom GhcPs) SrcTemplateStage parseAST :: ModSummary -> Ghc ParsedModule parseAST modSum = do @@ -439,7 +440,7 @@ (if hasCppExtension then prepareASTCpp else prepareAST) sourceOrigin . placeComments (fst annots) (getNormalComments $ snd annots) <$> (runTrf (fst annots) (getPragmaComments $ snd annots) $ trfModule ms $ pm_parsed_source p) -type RenamedModule = Ann AST.UModule (Dom GHC.Name) SrcTemplateStage +type RenamedModule = Ann AST.UModule (Dom GhcRn) SrcTemplateStage parseRenamed :: ModSummary -> Ghc RenamedModule parseRenamed modSum = do