packages feed

hls-tactics-plugin 1.1.0.0 → 1.2.0.0

raw patch · 265 files changed

+3704/−1126 lines, 265 filesdep +hls-graphdep +hyphenationdep +megaparsecdep −shakedep ~extradep ~ghcidenew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: hls-graph, hyphenation, megaparsec, parser-combinators, prettyprinter

Dependencies removed: shake

Dependency ranges changed: extra, ghcide

API changes (from Hackage documentation)

- Wingman.FeatureSet: FeatureDestructAll :: Feature
- Wingman.FeatureSet: FeatureKnownMonoid :: Feature
- Wingman.FeatureSet: FeatureRefineHole :: Feature
- Wingman.FeatureSet: FeatureUseDataCon :: Feature
- Wingman.FeatureSet: allFeatures :: FeatureSet
- Wingman.FeatureSet: data Feature
- Wingman.FeatureSet: defaultFeatures :: FeatureSet
- Wingman.FeatureSet: hasFeature :: Feature -> FeatureSet -> Bool
- Wingman.FeatureSet: instance GHC.Classes.Eq Wingman.FeatureSet.Feature
- Wingman.FeatureSet: instance GHC.Classes.Ord Wingman.FeatureSet.Feature
- Wingman.FeatureSet: instance GHC.Enum.Bounded Wingman.FeatureSet.Feature
- Wingman.FeatureSet: instance GHC.Enum.Enum Wingman.FeatureSet.Feature
- Wingman.FeatureSet: instance GHC.Read.Read Wingman.FeatureSet.Feature
- Wingman.FeatureSet: instance GHC.Show.Show Wingman.FeatureSet.Feature
- Wingman.FeatureSet: parseFeatureSet :: Text -> FeatureSet
- Wingman.FeatureSet: prettyFeatureSet :: FeatureSet -> String
- Wingman.FeatureSet: type FeatureSet = Set Feature
- Wingman.KnownStrategies: featureGuard :: Feature -> TacticsM a -> TacticsM a
- Wingman.LanguageServer: getFeatureSet :: MonadLsp Config m => PluginId -> m FeatureSet
- Wingman.Types: [cfg_feature_set] :: Config -> FeatureSet
- Wingman.Types: [ctxFeatureSet] :: Context -> FeatureSet
+ Ide.Plugin.Tactic: BeginMetaprogram :: TacticCommand
+ Ide.Plugin.Tactic: DestructPun :: TacticCommand
+ Ide.Plugin.Tactic: RunMetaprogram :: TacticCommand
+ Wingman.CodeGen: destructionFor :: Hypothesis a -> Type -> Maybe [LMatch GhcPs (LHsExpr GhcPs)]
+ Wingman.CodeGen: letForEach :: (OccName -> OccName) -> (HyInfo CType -> TacticsM ()) -> Hypothesis CType -> Judgement -> RuleM (Synthesized (LHsExpr GhcPs))
+ Wingman.Context: locallyDefinedMethods :: TcGblEnv -> [Id]
+ Wingman.EmptyCase: codeLensProvider :: PluginMethodHandler IdeState TextDocumentCodeLens
+ Wingman.EmptyCase: emptyCaseLensCommandId :: CommandId
+ Wingman.EmptyCase: emptyCaseQ :: GenericQ [(SrcSpan, HsExpr GhcTc)]
+ Wingman.EmptyCase: emptyCaseScrutinees :: IdeState -> NormalizedFilePath -> MaybeT IO [(Tracked 'Current RealSrcSpan, Type)]
+ Wingman.EmptyCase: fromMaybeT :: Functor m => a -> MaybeT m a -> m a
+ Wingman.EmptyCase: graftMatchGroup :: SrcSpan -> Located [LMatch GhcPs (LHsExpr GhcPs)] -> Graft (Either String) ParsedSource
+ Wingman.EmptyCase: hush :: Either e a -> Maybe a
+ Wingman.EmptyCase: mkEmptyCaseLensDesc :: Type -> Text
+ Wingman.EmptyCase: workspaceEditHandler :: CommandFunction IdeState WorkspaceEdit
+ Wingman.GHC: expandTyFam :: Context -> Type -> Type
+ Wingman.GHC: mkFunTys' :: [Type] -> Type -> Type
+ Wingman.GHC: normalizeType :: Context -> Type -> Type
+ Wingman.GHC: pattern SingleLet :: IdP GhcPs -> [Pat GhcPs] -> HsExpr GhcPs -> HsExpr GhcPs -> HsExpr GhcPs
+ Wingman.GHC: typeCheck :: HscEnv -> TcGblEnv -> HsExpr GhcTc -> IO (Maybe Type)
+ Wingman.Judgements: hyFilter :: (HyInfo a -> Bool) -> Hypothesis a -> Hypothesis a
+ Wingman.Judgements: hySingleton :: OccName -> Hypothesis ()
+ Wingman.Judgements: normalizeHypothesis :: Functor f => Context -> f CType -> f CType
+ Wingman.Judgements: normalizeJudgement :: Functor f => Context -> f CType -> f CType
+ Wingman.Judgements: userHypothesis :: [(OccName, a)] -> Hypothesis a
+ Wingman.Judgements.SYB: metaprogramQ :: SrcSpan -> GenericQ [(SrcSpan, Text)]
+ Wingman.Judgements.Theta: instance GHC.Generics.Generic Wingman.Judgements.Theta.Evidence
+ Wingman.LanguageServer: annotateMetaprograms :: Data a => a -> Transform a
+ Wingman.LanguageServer: getAllMetaprograms :: Data a => a -> [String]
+ Wingman.LanguageServer: getMetaprogramAtSpan :: Tracked age SrcSpan -> Tracked age TcGblEnv -> Maybe Text
+ Wingman.LanguageServer: getParserState :: IdeState -> NormalizedFilePath -> Context -> MaybeT IO ParserContext
+ Wingman.LanguageServer: holeSortFor :: Maybe Text -> HoleSort
+ Wingman.LanguageServer: mkWorkspaceEdits :: DynFlags -> ClientCapabilities -> Uri -> Annotated ParsedSource -> Graft (Either String) ParsedSource -> Either UserFacingMessage WorkspaceEdit
+ Wingman.LanguageServer.Metaprogram: hoverProvider :: PluginMethodHandler IdeState TextDocumentHover
+ Wingman.LanguageServer.TacticProviders: [tpd_hole_sort] :: TacticProviderData -> HoleSort
+ Wingman.LanguageServer.TacticProviders: useNameFromHypothesis :: (HyInfo CType -> TacticsM a) -> OccName -> TacticsM a
+ Wingman.Machinery: createImportedHyInfo :: OccName -> CType -> HyInfo CType
+ Wingman.Machinery: exact :: HsExpr GhcPs -> TacticsM ()
+ Wingman.Machinery: getOccNameType :: HscEnv -> OccEnv [GlobalRdrElt] -> Module -> OccName -> IO (Maybe Type)
+ Wingman.Machinery: lookupNameInContext :: MonadReader Context m => OccName -> m (Maybe CType)
+ Wingman.Machinery: tacticToRule :: Judgement -> TacticsM () -> Rule
+ Wingman.Machinery: useNameFromContext :: (HyInfo CType -> TacticsM a) -> OccName -> TacticsM a
+ Wingman.Machinery: useNameFromHypothesis :: (HyInfo CType -> TacticsM a) -> OccName -> TacticsM a
+ Wingman.Metaprogramming.Lexer: ParserContext :: HscEnv -> OccEnv [GlobalRdrElt] -> Module -> Context -> ParserContext
+ Wingman.Metaprogramming.Lexer: [ps_context] :: ParserContext -> Context
+ Wingman.Metaprogramming.Lexer: [ps_hscEnv] :: ParserContext -> HscEnv
+ Wingman.Metaprogramming.Lexer: [ps_module] :: ParserContext -> Module
+ Wingman.Metaprogramming.Lexer: [ps_occEnv] :: ParserContext -> OccEnv [GlobalRdrElt]
+ Wingman.Metaprogramming.Lexer: blockComment :: Parser ()
+ Wingman.Metaprogramming.Lexer: braces :: Parser a -> Parser a
+ Wingman.Metaprogramming.Lexer: brackets :: Parser a -> Parser a
+ Wingman.Metaprogramming.Lexer: data ParserContext
+ Wingman.Metaprogramming.Lexer: ichar :: Parser Char
+ Wingman.Metaprogramming.Lexer: identifier :: Text -> Parser ()
+ Wingman.Metaprogramming.Lexer: keyword :: Text -> Parser ()
+ Wingman.Metaprogramming.Lexer: lexeme :: Parser a -> Parser a
+ Wingman.Metaprogramming.Lexer: lineComment :: Parser ()
+ Wingman.Metaprogramming.Lexer: name :: Parser Text
+ Wingman.Metaprogramming.Lexer: parens :: Parser a -> Parser a
+ Wingman.Metaprogramming.Lexer: sc :: Parser ()
+ Wingman.Metaprogramming.Lexer: symbol :: Text -> Parser Text
+ Wingman.Metaprogramming.Lexer: symbol_ :: Text -> Parser ()
+ Wingman.Metaprogramming.Lexer: type Parser = ParsecT Void Text (ReaderT ParserContext IO)
+ Wingman.Metaprogramming.Lexer: variable :: Parser OccName
+ Wingman.Metaprogramming.Parser: attempt_it :: Context -> Judgement -> String -> ReaderT ParserContext IO (Either String String)
+ Wingman.Metaprogramming.Parser: bindOne :: TacticsM a -> TacticsM a -> TacticsM a
+ Wingman.Metaprogramming.Parser: commands :: [SomeMetaprogramCommand]
+ Wingman.Metaprogramming.Parser: getOccTy :: OccName -> Parser Type
+ Wingman.Metaprogramming.Parser: nullary :: Text -> TacticsM () -> Parser (TacticsM ())
+ Wingman.Metaprogramming.Parser: oneTactic :: Parser (TacticsM ())
+ Wingman.Metaprogramming.Parser: operators :: [[Operator Parser (TacticsM ())]]
+ Wingman.Metaprogramming.Parser: parseMetaprogram :: Text -> ReaderT ParserContext IO (TacticsM ())
+ Wingman.Metaprogramming.Parser: tactic :: Parser (TacticsM ())
+ Wingman.Metaprogramming.Parser: tacticProgram :: Parser (TacticsM ())
+ Wingman.Metaprogramming.Parser: unary_occ :: Text -> (OccName -> TacticsM ()) -> Parser (TacticsM ())
+ Wingman.Metaprogramming.Parser: unary_occM :: Text -> (OccName -> Parser (TacticsM ())) -> Parser (TacticsM ())
+ Wingman.Metaprogramming.Parser: variadic_occ :: Text -> ([OccName] -> TacticsM ()) -> Parser (TacticsM ())
+ Wingman.Metaprogramming.Parser: wrapError :: String -> String
+ Wingman.Metaprogramming.Parser: writeDocumentation :: IO ()
+ Wingman.Metaprogramming.Parser.Documentation: Deterministic :: Determinism
+ Wingman.Metaprogramming.Parser.Documentation: EHI :: Var -> ExampleType -> ExampleHyInfo
+ Wingman.Metaprogramming.Parser.Documentation: Example :: Maybe Text -> [Var] -> [ExampleHyInfo] -> Maybe ExampleType -> Text -> Example
+ Wingman.Metaprogramming.Parser.Documentation: ExampleType :: Text -> ExampleType
+ Wingman.Metaprogramming.Parser.Documentation: MC :: Text -> Syntax a -> Determinism -> Text -> a -> [Example] -> MetaprogramCommand a
+ Wingman.Metaprogramming.Parser.Documentation: Nondeterministic :: Determinism
+ Wingman.Metaprogramming.Parser.Documentation: Var :: Text -> Var
+ Wingman.Metaprogramming.Parser.Documentation: [Bind] :: Count a -> Syntax (a -> Parser (TacticsM ()))
+ Wingman.Metaprogramming.Parser.Documentation: [Many] :: Count [OccName]
+ Wingman.Metaprogramming.Parser.Documentation: [Nullary] :: Syntax (Parser (TacticsM ()))
+ Wingman.Metaprogramming.Parser.Documentation: [One] :: Count OccName
+ Wingman.Metaprogramming.Parser.Documentation: [Ref] :: Count a -> Syntax (a -> Parser (TacticsM ()))
+ Wingman.Metaprogramming.Parser.Documentation: [SMC] :: MetaprogramCommand a -> SomeMetaprogramCommand
+ Wingman.Metaprogramming.Parser.Documentation: [ehi_name] :: ExampleHyInfo -> Var
+ Wingman.Metaprogramming.Parser.Documentation: [ehi_type] :: ExampleHyInfo -> ExampleType
+ Wingman.Metaprogramming.Parser.Documentation: [ex_args] :: Example -> [Var]
+ Wingman.Metaprogramming.Parser.Documentation: [ex_ctx] :: Example -> Maybe Text
+ Wingman.Metaprogramming.Parser.Documentation: [ex_goal] :: Example -> Maybe ExampleType
+ Wingman.Metaprogramming.Parser.Documentation: [ex_hyp] :: Example -> [ExampleHyInfo]
+ Wingman.Metaprogramming.Parser.Documentation: [ex_result] :: Example -> Text
+ Wingman.Metaprogramming.Parser.Documentation: [getExampleType] :: ExampleType -> Text
+ Wingman.Metaprogramming.Parser.Documentation: [getVar] :: Var -> Text
+ Wingman.Metaprogramming.Parser.Documentation: [mpc_description] :: MetaprogramCommand a -> Text
+ Wingman.Metaprogramming.Parser.Documentation: [mpc_det] :: MetaprogramCommand a -> Determinism
+ Wingman.Metaprogramming.Parser.Documentation: [mpc_examples] :: MetaprogramCommand a -> [Example]
+ Wingman.Metaprogramming.Parser.Documentation: [mpc_name] :: MetaprogramCommand a -> Text
+ Wingman.Metaprogramming.Parser.Documentation: [mpc_syntax] :: MetaprogramCommand a -> Syntax a
+ Wingman.Metaprogramming.Parser.Documentation: [mpc_tactic] :: MetaprogramCommand a -> a
+ Wingman.Metaprogramming.Parser.Documentation: codeFence :: Doc a -> Doc a
+ Wingman.Metaprogramming.Parser.Documentation: command :: Text -> Determinism -> Syntax a -> Text -> a -> [Example] -> SomeMetaprogramCommand
+ Wingman.Metaprogramming.Parser.Documentation: data Count a
+ Wingman.Metaprogramming.Parser.Documentation: data Determinism
+ Wingman.Metaprogramming.Parser.Documentation: data Example
+ Wingman.Metaprogramming.Parser.Documentation: data ExampleHyInfo
+ Wingman.Metaprogramming.Parser.Documentation: data MetaprogramCommand a
+ Wingman.Metaprogramming.Parser.Documentation: data SomeMetaprogramCommand
+ Wingman.Metaprogramming.Parser.Documentation: data Syntax a
+ Wingman.Metaprogramming.Parser.Documentation: instance Data.String.IsString Wingman.Metaprogramming.Parser.Documentation.ExampleType
+ Wingman.Metaprogramming.Parser.Documentation: instance Data.String.IsString Wingman.Metaprogramming.Parser.Documentation.Var
+ Wingman.Metaprogramming.Parser.Documentation: instance Prettyprinter.Internal.Pretty Wingman.Metaprogramming.Parser.Documentation.ExampleType
+ Wingman.Metaprogramming.Parser.Documentation: instance Prettyprinter.Internal.Pretty Wingman.Metaprogramming.Parser.Documentation.Var
+ Wingman.Metaprogramming.Parser.Documentation: makeMPParser :: MetaprogramCommand a -> Parser (TacticsM ())
+ Wingman.Metaprogramming.Parser.Documentation: makeParser :: [SomeMetaprogramCommand] -> Parser (TacticsM ())
+ Wingman.Metaprogramming.Parser.Documentation: mappendIfNotNull :: [a] -> a -> [a]
+ Wingman.Metaprogramming.Parser.Documentation: newtype ExampleType
+ Wingman.Metaprogramming.Parser.Documentation: newtype Var
+ Wingman.Metaprogramming.Parser.Documentation: prettyCommand :: MetaprogramCommand a -> Doc b
+ Wingman.Metaprogramming.Parser.Documentation: prettyCount :: Count a -> Doc b
+ Wingman.Metaprogramming.Parser.Documentation: prettyDeterminism :: Determinism -> Doc b
+ Wingman.Metaprogramming.Parser.Documentation: prettyExample :: Text -> Example -> Doc a
+ Wingman.Metaprogramming.Parser.Documentation: prettyHyInfo :: ExampleHyInfo -> Doc a
+ Wingman.Metaprogramming.Parser.Documentation: prettyReadme :: [SomeMetaprogramCommand] -> String
+ Wingman.Metaprogramming.Parser.Documentation: prettySyntax :: Syntax a -> Doc b
+ Wingman.Metaprogramming.ProofState: Goal :: Ann
+ Wingman.Metaprogramming.ProofState: Hypoth :: Ann
+ Wingman.Metaprogramming.ProofState: Status :: Ann
+ Wingman.Metaprogramming.ProofState: count :: Doc Ann -> Int -> Doc Ann
+ Wingman.Metaprogramming.ProofState: countFinished :: Doc Ann -> Doc Ann -> Int -> Doc Ann
+ Wingman.Metaprogramming.ProofState: data Ann
+ Wingman.Metaprogramming.ProofState: forceMarkdownNewlines :: String -> String
+ Wingman.Metaprogramming.ProofState: instance GHC.Classes.Eq Wingman.Metaprogramming.ProofState.Ann
+ Wingman.Metaprogramming.ProofState: instance GHC.Classes.Ord Wingman.Metaprogramming.ProofState.Ann
+ Wingman.Metaprogramming.ProofState: instance GHC.Enum.Bounded Wingman.Metaprogramming.ProofState.Ann
+ Wingman.Metaprogramming.ProofState: instance GHC.Enum.Enum Wingman.Metaprogramming.ProofState.Ann
+ Wingman.Metaprogramming.ProofState: instance GHC.Show.Show Wingman.Metaprogramming.ProofState.Ann
+ Wingman.Metaprogramming.ProofState: layout :: Doc Ann -> String
+ Wingman.Metaprogramming.ProofState: prettyHyInfo :: HyInfo CType -> Doc Ann
+ Wingman.Metaprogramming.ProofState: prettyHypothesis :: Hypothesis CType -> Doc Ann
+ Wingman.Metaprogramming.ProofState: prettySubgoal :: Judgement -> Doc Ann
+ Wingman.Metaprogramming.ProofState: prettyType :: CType -> Doc Ann
+ Wingman.Metaprogramming.ProofState: proofState :: RunTacticResults -> Doc Ann
+ Wingman.Metaprogramming.ProofState: renderAnn :: Ann -> Text
+ Wingman.Metaprogramming.ProofState: renderSimplyDecorated :: Monoid out => (Text -> out) -> (ann -> out) -> (ann -> out) -> SimpleDocStream ann -> out
+ Wingman.Metaprogramming.ProofState: renderUnann :: Ann -> Text
+ Wingman.Metaprogramming.ProofState: textSpaces :: Int -> Text
+ Wingman.Naming: Continuation :: Purpose
+ Wingman.Naming: Function :: [Type] -> Type -> Purpose
+ Wingman.Naming: Integral :: Purpose
+ Wingman.Naming: List :: Type -> Purpose
+ Wingman.Naming: Maybe :: Type -> Purpose
+ Wingman.Naming: Number :: Purpose
+ Wingman.Naming: Predicate :: Purpose
+ Wingman.Naming: String :: Purpose
+ Wingman.Naming: TyConned :: TyCon -> [Type] -> Purpose
+ Wingman.Naming: TyVarred :: TyVar -> [Type] -> Purpose
+ Wingman.Naming: camelTerms :: String -> [String]
+ Wingman.Naming: data Purpose
+ Wingman.Naming: functionNames :: [String]
+ Wingman.Naming: getPurposes :: Type -> [Purpose]
+ Wingman.Naming: getStem :: String -> String
+ Wingman.Naming: mkNumericSuffix :: Set OccName -> String -> String
+ Wingman.Naming: pattern IsFunction :: [Type] -> Type -> Type
+ Wingman.Naming: pattern IsList :: Type -> Type
+ Wingman.Naming: pattern IsMaybe :: Type -> Type
+ Wingman.Naming: pattern IsPredicate :: Type
+ Wingman.Naming: pattern IsString :: Type
+ Wingman.Naming: pattern IsTyConned :: TyCon -> [Type] -> Type
+ Wingman.Naming: pattern IsTyVarred :: TyVar -> [Type] -> Type
+ Wingman.Naming: purposeToName :: Purpose -> [String]
+ Wingman.Naming: stem :: String -> String
+ Wingman.Naming: with :: Monoid a => Bool -> a -> a
+ Wingman.Plugin: BeginMetaprogram :: TacticCommand
+ Wingman.Plugin: DestructPun :: TacticCommand
+ Wingman.Plugin: RunMetaprogram :: TacticCommand
+ Wingman.StaticPlugin: metaprogramHoleName :: OccName
+ Wingman.StaticPlugin: pattern MetaprogramSyntax :: FastString -> HsExpr GhcPs
+ Wingman.StaticPlugin: pattern WingmanMetaprogram :: FastString -> HsExpr p
+ Wingman.StaticPlugin: staticPlugin :: DynFlagsModifications
+ Wingman.Tactics: application :: TacticsM ()
+ Wingman.Tactics: applyByType :: Type -> TacticsM ()
+ Wingman.Tactics: cata :: HyInfo CType -> TacticsM ()
+ Wingman.Tactics: collapse :: TacticsM ()
+ Wingman.Tactics: destructPun :: HyInfo CType -> TacticsM ()
+ Wingman.Tactics: hyDiff :: TacticsM () -> TacticsM (Hypothesis CType)
+ Wingman.Tactics: intros' :: Maybe [OccName] -> TacticsM ()
+ Wingman.Tactics: metaprogram :: TacticsM ()
+ Wingman.Tactics: nary :: Int -> TacticsM ()
+ Wingman.Tactics: obvious :: TacticsM ()
+ Wingman.Tactics: self :: TacticsM ()
+ Wingman.Tactics: sorry :: TacticsM ()
+ Wingman.Types: BeginMetaprogram :: TacticCommand
+ Wingman.Types: DestructPun :: TacticCommand
+ Wingman.Types: Hole :: HoleSort
+ Wingman.Types: HoleJudgment :: Tracked 'Current Range -> Judgement -> Context -> DynFlags -> HoleSort -> HoleJudgment
+ Wingman.Types: ImportPrv :: Provenance
+ Wingman.Types: Metaprogram :: Text -> HoleSort
+ Wingman.Types: RunMetaprogram :: TacticCommand
+ Wingman.Types: TacticPanic :: String -> TacticError
+ Wingman.Types: [cfg_auto_gas] :: Config -> Int
+ Wingman.Types: [ctxConfig] :: Context -> Config
+ Wingman.Types: [ctxFamInstEnvs] :: Context -> FamInstEnvs
+ Wingman.Types: [hj_ctx] :: HoleJudgment -> Context
+ Wingman.Types: [hj_dflags] :: HoleJudgment -> DynFlags
+ Wingman.Types: [hj_hole_sort] :: HoleJudgment -> HoleSort
+ Wingman.Types: [hj_jdg] :: HoleJudgment -> Judgement
+ Wingman.Types: [hj_range] :: HoleJudgment -> Tracked 'Current Range
+ Wingman.Types: [rtr_subgoals] :: RunTacticResults -> [Judgement]
+ Wingman.Types: data HoleJudgment
+ Wingman.Types: data HoleSort
+ Wingman.Types: emptyConfig :: Config
+ Wingman.Types: instance GHC.Classes.Eq Wingman.Types.Config
+ Wingman.Types: instance GHC.Classes.Eq Wingman.Types.HoleSort
+ Wingman.Types: instance GHC.Classes.Ord Wingman.Types.Config
+ Wingman.Types: instance GHC.Classes.Ord Wingman.Types.HoleSort
+ Wingman.Types: instance GHC.Show.Show (GHC.Hs.Expr.HsExpr GHC.Hs.Extension.GhcTc)
+ Wingman.Types: instance GHC.Show.Show Wingman.Types.Config
+ Wingman.Types: instance GHC.Show.Show Wingman.Types.HoleSort
- Wingman.CodeGen: destruct' :: (ConLike -> Judgement -> Rule) -> HyInfo CType -> Judgement -> Rule
+ Wingman.CodeGen: destruct' :: Bool -> (ConLike -> Judgement -> Rule) -> HyInfo CType -> Judgement -> Rule
- Wingman.CodeGen: destructLambdaCase' :: (ConLike -> Judgement -> Rule) -> Judgement -> Rule
+ Wingman.CodeGen: destructLambdaCase' :: Bool -> (ConLike -> Judgement -> Rule) -> Judgement -> Rule
- Wingman.CodeGen: destructMatches :: (ConLike -> Judgement -> Rule) -> Maybe OccName -> CType -> Judgement -> RuleM (Synthesized [RawMatch])
+ Wingman.CodeGen: destructMatches :: Bool -> (ConLike -> Judgement -> Rule) -> Maybe OccName -> CType -> Judgement -> RuleM (Synthesized [RawMatch])
- Wingman.CodeGen: mkDestructPat :: ConLike -> [OccName] -> Pat GhcPs
+ Wingman.CodeGen: mkDestructPat :: Maybe (Set OccName) -> ConLike -> [OccName] -> ([OccName], Pat GhcPs)
- Wingman.Context: mkContext :: FeatureSet -> [(OccName, CType)] -> TcGblEnv -> ExternalPackageState -> KnownThings -> [Evidence] -> Context
+ Wingman.Context: mkContext :: Config -> [(OccName, CType)] -> TcGblEnv -> ExternalPackageState -> KnownThings -> [Evidence] -> Context
- Wingman.Judgements: introduce :: Hypothesis a -> Judgement' a -> Judgement' a
+ Wingman.Judgements: introduce :: Context -> Hypothesis CType -> Judgement' CType -> Judgement' CType
- Wingman.Judgements: mkFirstJudgement :: Hypothesis CType -> Bool -> Type -> Judgement' CType
+ Wingman.Judgements: mkFirstJudgement :: Context -> Hypothesis CType -> Bool -> Type -> Judgement' CType
- Wingman.Judgements.Theta: evidenceToSubst :: Evidence -> TacticState -> TacticState
+ Wingman.Judgements.Theta: evidenceToSubst :: [Evidence] -> TacticState -> TacticState
- Wingman.LanguageServer: judgementForHole :: IdeState -> NormalizedFilePath -> Tracked 'Current Range -> FeatureSet -> MaybeT IO (Tracked 'Current Range, Judgement, Context, DynFlags)
+ Wingman.LanguageServer: judgementForHole :: IdeState -> NormalizedFilePath -> Tracked 'Current Range -> Config -> MaybeT IO HoleJudgment
- Wingman.LanguageServer: mkJudgementAndContext :: FeatureSet -> Type -> TrackedStale Bindings -> Tracked 'Current RealSrcSpan -> TrackedStale TcGblEnv -> ExternalPackageState -> KnownThings -> Maybe (Judgement, Context)
+ Wingman.LanguageServer: mkJudgementAndContext :: Config -> Type -> TrackedStale Bindings -> Tracked 'Current RealSrcSpan -> TrackedStale TcGblEnv -> ExternalPackageState -> KnownThings -> Maybe (Judgement, Context)
- Wingman.LanguageServer: properties :: Properties '[ 'PropertyKey "hole_severity" ('TEnum (Maybe DiagnosticSeverity)), 'PropertyKey "max_use_ctor_actions" 'TInteger, 'PropertyKey "features" 'TString, 'PropertyKey "timeout_duration" 'TInteger]
+ Wingman.LanguageServer: properties :: Properties '[ 'PropertyKey "hole_severity" ('TEnum (Maybe DiagnosticSeverity)), 'PropertyKey "max_use_ctor_actions" 'TInteger, 'PropertyKey "timeout_duration" 'TInteger, 'PropertyKey "auto_gas" 'TInteger]
- Wingman.LanguageServer: runCurrentIde :: forall a r. (r ~ RuleResult a, Eq a, Hashable a, Binary a, Show a, Typeable a, NFData a, Show r, Typeable r, NFData r) => IdeState -> NormalizedFilePath -> a -> MaybeT IO (Tracked 'Current r)
+ Wingman.LanguageServer: runCurrentIde :: forall a r. (r ~ RuleResult a, Eq a, Hashable a, Binary a, Show a, Typeable a, NFData a, Show r, Typeable r, NFData r) => String -> IdeState -> NormalizedFilePath -> a -> MaybeT IO (Tracked 'Current r)
- Wingman.LanguageServer: runIde :: IdeState -> Action a -> IO a
+ Wingman.LanguageServer: runIde :: String -> String -> IdeState -> Action a -> IO a
- Wingman.LanguageServer: runStaleIde :: forall a r. (r ~ RuleResult a, Eq a, Hashable a, Binary a, Show a, Typeable a, NFData a, Show r, Typeable r, NFData r) => IdeState -> NormalizedFilePath -> a -> MaybeT IO (TrackedStale r)
+ Wingman.LanguageServer: runStaleIde :: forall a r. (r ~ RuleResult a, Eq a, Hashable a, Binary a, Show a, Typeable a, NFData a, Show r, Typeable r, NFData r) => String -> IdeState -> NormalizedFilePath -> a -> MaybeT IO (TrackedStale r)
- Wingman.LanguageServer: unsafeRunStaleIde :: forall a r. (r ~ RuleResult a, Eq a, Hashable a, Binary a, Show a, Typeable a, NFData a, Show r, Typeable r, NFData r) => IdeState -> NormalizedFilePath -> a -> MaybeT IO r
+ Wingman.LanguageServer: unsafeRunStaleIde :: forall a r. (r ~ RuleResult a, Eq a, Hashable a, Binary a, Show a, Typeable a, NFData a, Show r, Typeable r, NFData r) => String -> IdeState -> NormalizedFilePath -> a -> MaybeT IO r
- Wingman.LanguageServer.TacticProviders: TacticProviderData :: DynFlags -> Config -> PluginId -> Uri -> Tracked 'Current Range -> Judgement -> TacticProviderData
+ Wingman.LanguageServer.TacticProviders: TacticProviderData :: DynFlags -> Config -> PluginId -> Uri -> Tracked 'Current Range -> Judgement -> HoleSort -> TacticProviderData
- Wingman.LanguageServer.TacticProviders: commandTactic :: TacticCommand -> OccName -> TacticsM ()
+ Wingman.LanguageServer.TacticProviders: commandTactic :: ParserContext -> TacticCommand -> Text -> IO (TacticsM ())
- Wingman.Naming: mkManyGoodNames :: (Traversable t, Monad m) => Set OccName -> t Type -> m (t OccName)
+ Wingman.Naming: mkManyGoodNames :: Traversable t => Set OccName -> t Type -> t OccName
- Wingman.Naming: mkTyName :: Type -> String
+ Wingman.Naming: mkTyName :: Type -> [String]
- Wingman.Types: Config :: FeatureSet -> Int -> Int -> Config
+ Wingman.Types: Config :: Int -> Int -> Int -> Config
- Wingman.Types: Context :: [(OccName, CType)] -> [(OccName, CType)] -> FeatureSet -> KnownThings -> InstEnvs -> Set CType -> Context
+ Wingman.Types: Context :: [(OccName, CType)] -> [(OccName, CType)] -> Config -> KnownThings -> InstEnvs -> FamInstEnvs -> Set CType -> Context
- Wingman.Types: RunTacticResults :: Trace -> LHsExpr GhcPs -> [Synthesized (LHsExpr GhcPs)] -> Judgement -> Context -> RunTacticResults
+ Wingman.Types: RunTacticResults :: Trace -> LHsExpr GhcPs -> [Judgement] -> [Synthesized (LHsExpr GhcPs)] -> Judgement -> Context -> RunTacticResults

Files

README.md view
@@ -56,8 +56,6 @@ " <leader>d to perform a pattern match, <leader>n to fill a hole nnoremap <silent> <leader>d  :<C-u>set operatorfunc=<SID>WingmanDestruct<CR>g@l nnoremap <silent> <leader>n  :<C-u>set operatorfunc=<SID>WingmanFillHole<CR>g@l--" beta only nnoremap <silent> <leader>r  :<C-u>set operatorfunc=<SID>WingmanRefine<CR>g@l nnoremap <silent> <leader>c  :<C-u>set operatorfunc=<SID>WingmanUseCtor<CR>g@l nnoremap <silent> <leader>a  :<C-u>set operatorfunc=<SID>WingmanDestructAll<CR>g@l
hls-tactics-plugin.cabal view
@@ -1,7 +1,7 @@ cabal-version:      2.4 category:           Development name:               hls-tactics-plugin-version:            1.1.0.0+version:            1.2.0.0 synopsis:           Wingman plugin for Haskell Language Server description:        Please see README.md author:             Sandy Maguire, Reed Mullanix@@ -15,7 +15,6 @@ extra-source-files:   README.md   test/golden/*.cabal-  test/golden/*.expected   test/golden/*.hs   test/golden/*.yaml @@ -34,7 +33,7 @@     Wingman.CodeGen.Utils     Wingman.Context     Wingman.Debug-    Wingman.FeatureSet+    Wingman.EmptyCase     Wingman.GHC     Wingman.Judgements     Wingman.Judgements.SYB@@ -42,12 +41,18 @@     Wingman.KnownStrategies     Wingman.KnownStrategies.QuickCheck     Wingman.LanguageServer+    Wingman.LanguageServer.Metaprogram     Wingman.LanguageServer.TacticProviders     Wingman.Machinery+    Wingman.Metaprogramming.Lexer+    Wingman.Metaprogramming.Parser+    Wingman.Metaprogramming.Parser.Documentation+    Wingman.Metaprogramming.ProofState     Wingman.Naming     Wingman.Plugin     Wingman.Range     Wingman.Simplify+    Wingman.StaticPlugin     Wingman.Tactics     Wingman.Types @@ -72,14 +77,18 @@     , ghc-boot-th     , ghc-exactprint     , ghc-source-gen-    , ghcide                ^>=1.2+    , ghcide                ^>=1.4+    , hls-graph     , hls-plugin-api        ^>=1.1+    , hyphenation     , lens     , lsp+    , megaparsec            ^>=9     , mtl+    , parser-combinators+    , prettyprinter     , refinery              ^>=0.3     , retrie                >=0.1.1.0-    , shake     , syb     , text     , transformers@@ -117,10 +126,13 @@     AutoTupleSpec     CodeAction.AutoSpec     CodeAction.DestructAllSpec+    CodeAction.DestructPunSpec     CodeAction.DestructSpec     CodeAction.IntrosSpec     CodeAction.RefineSpec+    CodeAction.RunMetaprogramSpec     CodeAction.UseDataConSpec+    CodeLens.EmptyCaseSpec     ProviderSpec     Spec     UnificationSpec@@ -141,7 +153,7 @@     , ghcide     , hls-plugin-api     , hls-tactics-plugin-    , hls-test-utils  ^>= 1.0+    , hls-test-utils      ^>=1.0     , hspec     , hspec-expectations     , lens
src/Wingman/Auto.hs view
@@ -1,5 +1,7 @@+ module Wingman.Auto where +import           Control.Monad.Reader.Class (asks) import           Control.Monad.State (gets) import qualified Data.Set as S import           Refinery.Tactic@@ -17,13 +19,14 @@ auto = do   jdg <- goal   skolems <- gets ts_skolems+  gas <- asks $ cfg_auto_gas . ctxConfig   current <- getCurrentDefinitions   traceMX "goal" jdg   traceMX "ctx" current   traceMX "skolems" skolems   commit knownStrategies     . tracing "auto"-    . localTactic (auto' 4)+    . localTactic (auto' gas)     . disallowing RecursiveCall     . S.fromList     $ fmap fst current
src/Wingman/CaseSplit.hs view
@@ -56,9 +56,17 @@ ------------------------------------------------------------------------------ -- | Replace a 'VarPat' with the given @'Pat' GhcPs@. rewriteVarPat :: Data a => RdrName -> Pat GhcPs -> a -> a-rewriteVarPat name rep = everywhere $ mkT $ \case-  VarPat _ (L _ var) | eqRdrName name var -> rep-  (x :: Pat GhcPs)                        -> x+rewriteVarPat name rep = everywhere $+  mkT (\case+    VarPat _ (L _ var) | eqRdrName name var -> rep+    (x :: Pat GhcPs)                        -> x+      )+  `extT` \case+    HsRecField lbl _ True+      | eqRdrName name $ unLoc $ rdrNameFieldOcc $ unLoc lbl+          -> HsRecField lbl (toPatCompat rep) False+    (x :: HsRecField' (FieldOcc GhcPs) (PatCompat GhcPs)) -> x+   ------------------------------------------------------------------------------
src/Wingman/CodeGen.hs view
@@ -1,7 +1,8 @@-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE OverloadedLabels #-}-{-# LANGUAGE TupleSections    #-}-{-# LANGUAGE TypeApplications #-}+{-# LANGUAGE FlexibleContexts  #-}+{-# LANGUAGE OverloadedLabels  #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TupleSections     #-}+{-# LANGUAGE TypeApplications  #-}  module Wingman.CodeGen   ( module Wingman.CodeGen@@ -12,21 +13,24 @@ import           ConLike import           Control.Lens ((%~), (<>~), (&)) import           Control.Monad.Except+import           Control.Monad.Reader (ask) import           Control.Monad.State import           Data.Bool (bool)+import           Data.Functor ((<&>)) import           Data.Generics.Labels () import           Data.List-import           Data.Monoid (Endo(..)) import qualified Data.Set as S import           Data.Traversable import           DataCon import           Development.IDE.GHC.Compat import           GHC.Exts+import           GHC.SourceGen (occNameToStr) import           GHC.SourceGen.Binds import           GHC.SourceGen.Expr import           GHC.SourceGen.Overloaded import           GHC.SourceGen.Pat-import           GhcPlugins (isSymOcc)+import           GhcPlugins (isSymOcc, mkVarOccFS)+import           OccName (occName) import           PatSyn import           Type hiding (Var) import           Wingman.CodeGen.Utils@@ -39,7 +43,8 @@   destructMatches-    :: (ConLike -> Judgement -> Rule)+    :: Bool+    -> (ConLike -> Judgement -> Rule)        -- ^ How to construct each match     -> Maybe OccName        -- ^ Scrutinee@@ -47,49 +52,106 @@        -- ^ Type being destructed     -> Judgement     -> RuleM (Synthesized [RawMatch])-destructMatches f scrut t jdg = do+-- TODO(sandy): In an ideal world, this would be the same codepath as+-- 'destructionFor'. Make sure to change that if you ever change this.+destructMatches use_field_puns f scrut t jdg = do   let hy = jEntireHypothesis jdg       g  = jGoal jdg-  case splitTyConApp_maybe $ unCType t of+  case tacticsGetDataCons $ unCType t of     Nothing -> throwError $ GoalMismatch "destruct" g-    Just (tc, apps) -> do-      let dcs = tyConDataCons tc-      case dcs of-        [] -> throwError $ GoalMismatch "destruct" g-        _ -> fmap unzipTrace $ for dcs $ \dc -> do-          let con = RealDataCon dc-              ev = concatMap mkEvidence $ dataConInstArgTys dc apps-              -- We explicitly do not need to add the method hypothesis to-              -- #syn_scoped-              method_hy = foldMap evidenceToHypothesis ev-              args = conLikeInstOrigArgTys' con apps-          modify $ appEndo $ foldMap (Endo . evidenceToSubst) ev-          subst <- gets ts_unifier-          names <- mkManyGoodNames (hyNamesInScope hy) args-          let hy' = patternHypothesis scrut con jdg-                  $ zip names-                  $ coerce args-              j = fmap (CType . substTyAddInScope subst . unCType)-                $ introduce hy'-                $ introduce method_hy-                $ withNewGoal g jdg-          ext <- f con j-          pure $ ext-            & #syn_trace %~ rose ("match " <> show dc <> " {" <> intercalate ", " (fmap show names) <> "}")-                          . pure-            & #syn_scoped <>~ hy'-            & #syn_val     %~ match [mkDestructPat con names] . unLoc+    Just (dcs, apps) ->+      fmap unzipTrace $ for dcs $ \dc -> do+        let con = RealDataCon dc+            ev = concatMap mkEvidence $ dataConInstArgTys dc apps+            -- We explicitly do not need to add the method hypothesis to+            -- #syn_scoped+            method_hy = foldMap evidenceToHypothesis ev+            args = conLikeInstOrigArgTys' con apps+        modify $ evidenceToSubst ev+        subst <- gets ts_unifier+        ctx <- ask +        let names_in_scope = hyNamesInScope hy+            names = mkManyGoodNames (hyNamesInScope hy) args+            (names', destructed) =+              mkDestructPat (bool Nothing (Just names_in_scope) use_field_puns) con names +        let hy' = patternHypothesis scrut con jdg+                $ zip names'+                $ coerce args+            j = fmap (CType . substTyAddInScope subst . unCType)+              $ introduce ctx hy'+              $ introduce ctx method_hy+              $ withNewGoal g jdg+        ext <- f con j+        pure $ ext+          & #syn_trace %~ rose ("match " <> show dc <> " {" <> intercalate ", " (fmap show names') <> "}")+                        . pure+          & #syn_scoped <>~ hy'+          & #syn_val %~ match [destructed] . unLoc++ ------------------------------------------------------------------------------+-- | Generate just the 'Match'es for a case split on a specific type.+destructionFor :: Hypothesis a -> Type -> Maybe [LMatch GhcPs (LHsExpr GhcPs)]+-- TODO(sandy): In an ideal world, this would be the same codepath as+-- 'destructMatches'. Make sure to change that if you ever change this.+destructionFor hy t = do+  case tacticsGetDataCons t of+    Nothing -> Nothing+    Just ([], _) -> Nothing+    Just (dcs, apps) -> do+      for dcs $ \dc -> do+        let con   = RealDataCon dc+            args  = conLikeInstOrigArgTys' con apps+            names = mkManyGoodNames (hyNamesInScope hy) args+        pure+          . noLoc+          . Match+              noExtField+              CaseAlt+              [toPatCompat $ snd $ mkDestructPat Nothing con names]+          . GRHSs noExtField (pure $ noLoc $ GRHS noExtField [] $ noLoc $ var "_")+          . noLoc+          $ EmptyLocalBinds noExtField++++------------------------------------------------------------------------------ -- | Produces a pattern for a data con and the names of its fields.-mkDestructPat :: ConLike -> [OccName] -> Pat GhcPs-mkDestructPat con names+mkDestructPat :: Maybe (S.Set OccName) -> ConLike -> [OccName] -> ([OccName], Pat GhcPs)+mkDestructPat already_in_scope con names   | RealDataCon dcon <- con   , isTupleDataCon dcon =-      tuple pat_args+      (names, tuple pat_args)+  | fields@(_:_) <- zip (conLikeFieldLabels con) names+  , Just in_scope <- already_in_scope =+      let (names', rec_fields) =+            unzip $ fields <&> \(label, name) -> do+              let label_occ = mkVarOccFS $ flLabel label+              case S.member label_occ in_scope of+                -- We have a shadow, so use the generated name instead+                True ->+                  (name,) $ noLoc $+                    HsRecField+                      (noLoc $ mkFieldOcc $ noLoc $ Unqual label_occ)+                      (noLoc $ bvar' name)+                      False+                -- No shadow, safe to use a pun+                False ->+                  (label_occ,) $ noLoc $+                    HsRecField+                      (noLoc $ mkFieldOcc $ noLoc $ Unqual label_occ)+                      (noLoc $ bvar' label_occ)+                      True++        in (names', )+         $ ConPatIn (noLoc $ Unqual $ occName $ conLikeName con)+         $ RecCon+         $ HsRecFields rec_fields+         $ Nothing   | otherwise =-      infixifyPatIfNecessary con $+      (names, ) $ infixifyPatIfNecessary con $         conP           (coerceName $ conLikeName con)           pat_args@@ -151,12 +213,13 @@ -- | Combinator for performing case splitting, and running sub-rules on the -- resulting matches. -destruct' :: (ConLike -> Judgement -> Rule) -> HyInfo CType -> Judgement -> Rule-destruct' f hi jdg = do+destruct' :: Bool -> (ConLike -> Judgement -> Rule) -> HyInfo CType -> Judgement -> Rule+destruct' use_field_puns f hi jdg = do   when (isDestructBlacklisted jdg) $ throwError NoApplicableTactic   let term = hi_name hi   ext       <- destructMatches+           use_field_puns            f            (Just term)            (hi_type hi)@@ -170,14 +233,14 @@ ------------------------------------------------------------------------------ -- | Combinator for performign case splitting, and running sub-rules on the -- resulting matches.-destructLambdaCase' :: (ConLike -> Judgement -> Rule) -> Judgement -> Rule-destructLambdaCase' f jdg = do+destructLambdaCase' :: Bool -> (ConLike -> Judgement -> Rule) -> Judgement -> Rule+destructLambdaCase' use_field_puns f jdg = do   when (isDestructBlacklisted jdg) $ throwError NoApplicableTactic   let g  = jGoal jdg   case splitFunTy_maybe (unCType g) of     Just (arg, _) | isAlgType arg ->       fmap (fmap noLoc lambdaCase) <$>-        destructMatches f Nothing (CType arg) jdg+        destructMatches use_field_puns f Nothing (CType arg) jdg     _ -> throwError $ GoalMismatch "destructLambdaCase'" g  @@ -190,7 +253,22 @@     -> [Type]             -- ^ Type arguments for the data con     -> RuleM (Synthesized (LHsExpr GhcPs)) buildDataCon should_blacklist jdg dc tyapps = do-  let args = conLikeInstOrigArgTys' dc tyapps+  args <- case dc of+    RealDataCon dc' -> do+      let (skolems', theta, args) = dataConInstSig dc' tyapps+      modify $ \ts ->+        evidenceToSubst (foldMap mkEvidence theta) ts+          & #ts_skolems <>~ S.fromList skolems'+      pure args+    _ ->+      -- If we have a 'PatSyn', we can't continue, since there is no+      -- 'dataConInstSig' equivalent for 'PatSyn's. I don't think this is+      -- a fundamental problem, but I don't know enough about the GHC internals+      -- to implement it myself.+      --+      -- Fortunately, this isn't an issue in practice, since 'PatSyn's are+      -- never in the hypothesis.+      throwError $ TacticPanic "Can't build Pattern constructors yet"   ext       <- fmap unzipTrace        $ traverse ( \(arg, n) ->@@ -212,4 +290,29 @@   | isSymOcc occ   = noLoc $ foldl' (@@) (op lhs (coerceName occ) rhs) more mkApply occ args = noLoc $ foldl' (@@) (var' occ) args+++------------------------------------------------------------------------------+-- | Run a tactic over each term in the given 'Hypothesis', binding the results+-- of each in a let expression.+letForEach+    :: (OccName -> OccName)           -- ^ How to name bound variables+    -> (HyInfo CType -> TacticsM ())  -- ^ The tactic to run+    -> Hypothesis CType               -- ^ Terms to generate bindings for+    -> Judgement                      -- ^ The goal of original hole+    -> RuleM (Synthesized (LHsExpr GhcPs))+letForEach rename solve (unHypothesis -> hy) jdg = do+  case hy of+    [] -> newSubgoal jdg+    _ -> do+      ctx <- ask+      let g = jGoal jdg+      terms <- fmap sequenceA $ for hy $ \hi -> do+        let name = rename $ hi_name hi+        res <- tacticToRule jdg $ solve hi+        pure $ fmap ((name,) . unLoc) res+      let hy' = fmap (g <$) $ syn_val terms+          matches = fmap (fmap (\(occ, expr) -> valBind (occNameToStr occ) expr)) terms+      g <- fmap (fmap unLoc) $ newSubgoal $ introduce ctx (userHypothesis hy') jdg+      pure $ fmap noLoc $ let' <$> matches <*> g 
src/Wingman/CodeGen/Utils.hs view
@@ -5,7 +5,7 @@ import DataCon import Development.IDE.GHC.Compat import GHC.Exts-import GHC.SourceGen (RdrNameStr, recordConE, string)+import GHC.SourceGen (RdrNameStr (UnqualStr), recordConE, string) import GHC.SourceGen.Overloaded import GhcPlugins (nilDataCon, charTy, eqType) import Name@@ -43,7 +43,7 @@   coerceName :: HasOccName a => a -> RdrNameStr-coerceName = fromString . occNameString . occName+coerceName = UnqualStr . fromString . occNameString . occName   ------------------------------------------------------------------------------
src/Wingman/Context.hs view
@@ -3,45 +3,60 @@ import           Bag import           Control.Arrow import           Control.Monad.Reader+import           Data.Coerce (coerce) import           Data.Foldable.Extra (allM)-import           Data.Maybe (fromMaybe, isJust)+import           Data.Maybe (fromMaybe, isJust, mapMaybe) import qualified Data.Set as S import           Development.IDE.GHC.Compat-import           GhcPlugins (ExternalPackageState (eps_inst_env), piResultTys)+import           GhcPlugins (ExternalPackageState (eps_inst_env), piResultTys, eps_fam_inst_env) import           InstEnv (lookupInstEnv, InstEnvs(..), is_dfun) import           OccName import           TcRnTypes import           TcType (tcSplitTyConApp, tcSplitPhiTy) import           TysPrim (alphaTys)-import           Wingman.FeatureSet (FeatureSet)+import           Wingman.GHC (normalizeType) import           Wingman.Judgements.Theta import           Wingman.Types   mkContext-    :: FeatureSet+    :: Config     -> [(OccName, CType)]     -> TcGblEnv     -> ExternalPackageState     -> KnownThings     -> [Evidence]     -> Context-mkContext features locals tcg eps kt ev = Context-  { ctxDefiningFuncs = locals-  , ctxModuleFuncs = fmap splitId-                   . (getFunBindId =<<)-                   . fmap unLoc-                   . bagToList-                   $ tcg_binds tcg-  , ctxFeatureSet = features-  , ctxInstEnvs =-      InstEnvs-        (eps_inst_env eps)-        (tcg_inst_env tcg)-        (tcVisibleOrphanMods tcg)-  , ctxKnownThings = kt-  , ctxTheta = evidenceToThetaType ev-  }+mkContext cfg locals tcg eps kt ev = fix $ \ctx ->+  Context+    { ctxDefiningFuncs+        = fmap (second $ coerce $ normalizeType ctx) locals+    , ctxModuleFuncs+        = fmap (second (coerce $ normalizeType ctx) . splitId)+        . mappend (locallyDefinedMethods tcg)+        . (getFunBindId =<<)+        . fmap unLoc+        . bagToList+        $ tcg_binds tcg+    , ctxConfig = cfg+    , ctxFamInstEnvs =+        (eps_fam_inst_env eps, tcg_fam_inst_env tcg)+    , ctxInstEnvs =+        InstEnvs+          (eps_inst_env eps)+          (tcg_inst_env tcg)+          (tcVisibleOrphanMods tcg)+    , ctxKnownThings = kt+    , ctxTheta = evidenceToThetaType ev+    }+++locallyDefinedMethods :: TcGblEnv -> [Id]+locallyDefinedMethods+  = foldMap classMethods+  . mapMaybe tyConClass_maybe+  . tcg_tcs+   splitId :: Id -> (OccName, CType)
+ src/Wingman/EmptyCase.hs view
@@ -0,0 +1,160 @@+{-# LANGUAGE OverloadedStrings #-}++{-# LANGUAGE NoMonoLocalBinds  #-}++module Wingman.EmptyCase where++import           Control.Applicative (empty)+import           Control.Monad+import           Control.Monad.Except (runExcept)+import           Control.Monad.Trans+import           Control.Monad.Trans.Maybe+import           Data.Aeson+import           Data.Generics.Aliases (mkQ, GenericQ)+import           Data.Generics.Schemes (everything)+import           Data.Maybe+import           Data.Monoid+import qualified Data.Text as T+import           Data.Traversable+import           Development.IDE (hscEnv)+import           Development.IDE (realSrcSpanToRange)+import           Development.IDE.Core.RuleTypes+import           Development.IDE.Core.Shake (IdeState (..))+import           Development.IDE.Core.UseStale+import           Development.IDE.GHC.Compat+import           Development.IDE.GHC.ExactPrint+import           Development.IDE.Spans.LocalBindings (getLocalScope)+import           Ide.Types+import           Language.LSP.Server+import           Language.LSP.Types+import           OccName+import           Prelude hiding (span)+import           Prelude hiding (span)+import           TcRnTypes (tcg_binds)+import           Wingman.CodeGen (destructionFor)+import           Wingman.GHC+import           Wingman.Judgements+import           Wingman.LanguageServer+import           Wingman.Types+++------------------------------------------------------------------------------+-- | The 'CommandId' for the empty case completion.+emptyCaseLensCommandId :: CommandId+emptyCaseLensCommandId = CommandId "wingman.emptyCase"+++------------------------------------------------------------------------------+-- | A command function that just applies a 'WorkspaceEdit'.+workspaceEditHandler :: CommandFunction IdeState WorkspaceEdit+workspaceEditHandler _ideState wedit = do+  _ <- sendRequest SWorkspaceApplyEdit (ApplyWorkspaceEditParams Nothing wedit) (\_ -> pure ())+  return $ Right Null+++------------------------------------------------------------------------------+-- | Provide the "empty case completion" code lens+codeLensProvider :: PluginMethodHandler IdeState TextDocumentCodeLens+codeLensProvider state plId (CodeLensParams _ _ (TextDocumentIdentifier uri))+  | Just nfp <- uriToNormalizedFilePath $ toNormalizedUri uri = do+      let stale a = runStaleIde "codeLensProvider" state nfp a++      cfg <- getTacticConfig plId+      ccs <- getClientCapabilities+      liftIO $ fromMaybeT (Right $ List []) $ do+        dflags <- getIdeDynflags state nfp+        TrackedStale pm _ <- stale GetAnnotatedParsedSource+        TrackedStale binds bind_map <- stale GetBindings+        holes <- emptyCaseScrutinees state nfp++        fmap (Right . List) $ for holes $ \(ss, ty) -> do+          binds_ss <- liftMaybe $ mapAgeFrom bind_map ss+          let bindings = getLocalScope (unTrack binds) $ unTrack binds_ss+              range = realSrcSpanToRange $ unTrack ss+          matches <-+            liftMaybe $+              destructionFor+                (foldMap (hySingleton . occName . fst) bindings)+                ty+          edits <- liftMaybe $ hush $+                mkWorkspaceEdits dflags ccs uri (unTrack pm) $+                  graftMatchGroup (RealSrcSpan $ unTrack ss) $+                    noLoc matches++          pure $+            CodeLens range+              (Just+                $ mkLspCommand+                    plId+                    emptyCaseLensCommandId+                    (mkEmptyCaseLensDesc ty)+                $ Just $ pure $ toJSON $ edits+              )+              Nothing+codeLensProvider _ _ _ = pure $ Right $ List []+++------------------------------------------------------------------------------+-- | The description for the empty case lens.+mkEmptyCaseLensDesc :: Type -> T.Text+mkEmptyCaseLensDesc ty =+  "Wingman: Complete case constructors (" <> T.pack (unsafeRender ty) <> ")"+++------------------------------------------------------------------------------+-- | Silence an error.+hush :: Either e a -> Maybe a+hush (Left _) = Nothing+hush (Right a) = Just a+++------------------------------------------------------------------------------+-- | Graft a 'RunTacticResults' into the correct place in an AST. Correctly+-- deals with top-level holes, in which we might need to fiddle with the+-- 'Match's that bind variables.+graftMatchGroup+    :: SrcSpan+    -> Located [LMatch GhcPs (LHsExpr GhcPs)]+    -> Graft (Either String) ParsedSource+graftMatchGroup ss l =+  hoistGraft (runExcept . runExceptString) $ graftExprWithM ss $ \case+    L span (HsCase ext scrut mg@_) -> do+      pure $ Just $ L span $ HsCase ext scrut $ mg { mg_alts = l }+    (_ :: LHsExpr GhcPs) -> pure Nothing+++fromMaybeT :: Functor m => a -> MaybeT m a -> m a+fromMaybeT def = fmap (fromMaybe def) . runMaybeT+++------------------------------------------------------------------------------+-- | Find the last typechecked module, and find the most specific span, as well+-- as the judgement at the given range.+emptyCaseScrutinees+    :: IdeState+    -> NormalizedFilePath+    -> MaybeT IO [(Tracked 'Current RealSrcSpan, Type)]+emptyCaseScrutinees state nfp = do+    let stale a = runStaleIde "emptyCaseScrutinees" state nfp a++    TrackedStale tcg tcg_map <- fmap (fmap tmrTypechecked) $ stale TypeCheck+    let tcg' = unTrack tcg+    hscenv <- stale GhcSessionDeps++    let scrutinees = traverse (emptyCaseQ . tcg_binds) tcg+    for scrutinees $ \aged@(unTrack -> (ss, scrutinee)) -> do+      ty <- MaybeT $ typeCheck (hscEnv $ untrackedStaleValue hscenv) tcg' scrutinee+      case ss of+        RealSrcSpan r   -> do+          rss' <- liftMaybe $ mapAgeTo tcg_map $ unsafeCopyAge aged r+          pure (rss', ty)+        UnhelpfulSpan _ -> empty+++------------------------------------------------------------------------------+-- | Get the 'SrcSpan' and scrutinee of every empty case.+emptyCaseQ :: GenericQ [(SrcSpan, HsExpr GhcTc)]+emptyCaseQ = everything (<>) $ mkQ mempty $ \case+  L new_span (Case scrutinee []) -> pure (new_span, scrutinee)+  (_ :: LHsExpr GhcTc) -> mempty+
− src/Wingman/FeatureSet.hs
@@ -1,94 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Wingman.FeatureSet-  ( Feature (..)-  , FeatureSet-  , hasFeature-  , defaultFeatures-  , allFeatures-  , parseFeatureSet-  , prettyFeatureSet-  ) where--import           Data.List  (intercalate)-import           Data.Maybe (listToMaybe, mapMaybe)-import           Data.Set   (Set)-import qualified Data.Set   as S-import qualified Data.Text  as T------------------------------------------------------------------------------------ | All the available features. A 'FeatureSet' describes the ones currently--- available to the user.-data Feature-  = FeatureDestructAll-  | FeatureUseDataCon-  | FeatureRefineHole-  | FeatureKnownMonoid-  deriving (Eq, Ord, Show, Read, Enum, Bounded)------------------------------------------------------------------------------------ | A collection of enabled features.-type FeatureSet = Set Feature------------------------------------------------------------------------------------ | Parse a feature set.-parseFeatureSet :: T.Text -> FeatureSet-parseFeatureSet-  = mappend defaultFeatures-  . S.fromList-  . mapMaybe (readMaybe . mappend featurePrefix . rot13 . T.unpack)-  . T.split (== '/')------------------------------------------------------------------------------------ | Features that are globally enabled for all users.-defaultFeatures :: FeatureSet-defaultFeatures = S.fromList-  [-  ]------------------------------------------------------------------------------------ | All available features.-allFeatures :: FeatureSet-allFeatures = S.fromList $ enumFromTo minBound maxBound------------------------------------------------------------------------------------ | Pretty print a feature set.-prettyFeatureSet :: FeatureSet -> String-prettyFeatureSet-  = intercalate "/"-  . fmap (rot13 . drop (length featurePrefix) . show)-  . S.toList------------------------------------------------------------------------------------ | Is a given 'Feature' currently enabled?-hasFeature :: Feature -> FeatureSet -> Bool-hasFeature = S.member------------------------------------------------------------------------------------ | Like 'read', but not partial.-readMaybe :: Read a => String -> Maybe a-readMaybe = fmap fst . listToMaybe . reads---featurePrefix :: String-featurePrefix = "Feature"---rot13 :: String -> String-rot13 = fmap (toEnum . rot13int . fromEnum)---rot13int :: Integral a => a -> a-rot13int x-  | (fromIntegral x :: Word) - 97 < 26 = 97 + rem (x - 84) 26-  | (fromIntegral x :: Word) - 65 < 26 = 65 + rem (x - 52) 26-  | otherwise   = x-
src/Wingman/GHC.hs view
@@ -3,10 +3,12 @@  module Wingman.GHC where +import           Bag (bagToList) import           ConLike import           Control.Applicative (empty) import           Control.Monad.State import           Control.Monad.Trans.Maybe (MaybeT(..))+import           CoreUtils (exprType) import           Data.Function (on) import           Data.Functor ((<&>)) import           Data.List (isPrefixOf)@@ -18,10 +20,14 @@ import           DataCon import           Development.IDE (HscEnvEq (hscEnv)) import           Development.IDE.Core.Compile (lookupName)-import           Development.IDE.GHC.Compat+import           Development.IDE.GHC.Compat hiding (exprType)+import           DsExpr (dsExpr)+import           DsMonad (initDs)+import           FamInst (tcLookupDataFamInst_maybe)+import           FamInstEnv (normaliseType) import           GHC.SourceGen (lambda) import           Generics.SYB (Data, everything, everywhere, listify, mkQ, mkT)-import           GhcPlugins (extractModule, GlobalRdrElt (gre_name))+import           GhcPlugins (extractModule, GlobalRdrElt (gre_name), Role (Nominal)) import           OccName import           TcRnMonad import           TcType@@ -70,7 +76,7 @@ -- context. tacticsSplitFunTy :: Type -> ([TyVar], ThetaType, [Type], Type) tacticsSplitFunTy t-  = let (vars, theta, t') = tcSplitSigmaTy t+  = let (vars, theta, t') = tcSplitNestedSigmaTys t         (args, res) = tcSplitFunTys t'      in (vars, theta, args, res) @@ -193,6 +199,15 @@         }  +pattern SingleLet :: IdP GhcPs -> [Pat GhcPs] -> HsExpr GhcPs -> HsExpr GhcPs -> HsExpr GhcPs+pattern SingleLet bind pats val expr <-+  HsLet _+    (L _ (HsValBinds _+      (ValBinds _ (bagToList ->+        [(L _ (FunBind _ (L _ bind) (MG _ (L _ [L _ (AMatch _ pats val)]) _) _ _))]) _)))+    (L _ expr)++ ------------------------------------------------------------------------------ -- | A pattern over the otherwise (extremely) messy AST for lambdas. pattern Lambda :: [Pat GhcPs] -> HsExpr GhcPs -> HsExpr GhcPs@@ -341,6 +356,43 @@         Just tt -> liftMaybe $ f tt         _ -> empty + liftMaybe :: Monad m => Maybe a -> MaybeT m a liftMaybe a = MaybeT $ pure a+++------------------------------------------------------------------------------+-- | Get the type of an @HsExpr GhcTc@. This is slow and you should prefer to+-- not use it, but sometimes it can't be helped.+typeCheck :: HscEnv -> TcGblEnv -> HsExpr GhcTc -> IO (Maybe Type)+typeCheck hscenv tcg = fmap snd . initDs hscenv tcg . fmap exprType . dsExpr+++mkFunTys' :: [Type] -> Type -> Type+mkFunTys' =+#if __GLASGOW_HASKELL__ <= 808+  mkFunTys+#else+  mkVisFunTys+#endif+++------------------------------------------------------------------------------+-- | Expand type and data families+normalizeType :: Context -> Type -> Type+normalizeType ctx ty =+  let ty' = expandTyFam ctx ty+   in case tcSplitTyConApp_maybe ty' of+        Just (tc, tys) ->+          -- try to expand any data families+          case tcLookupDataFamInst_maybe (ctxFamInstEnvs ctx) tc tys of+            Just (dtc, dtys, _) -> mkAppTys (mkTyConTy dtc) dtys+            Nothing -> ty'+        Nothing -> ty'++------------------------------------------------------------------------------+-- | Expand type families+expandTyFam :: Context -> Type -> Type+expandTyFam ctx = snd . normaliseType  (ctxFamInstEnvs ctx) Nominal+ 
src/Wingman/Judgements.hs view
@@ -17,7 +17,7 @@ import           OccName import           SrcLoc import           Type-import           Wingman.GHC (algebraicTyCon)+import           Wingman.GHC (algebraicTyCon, normalizeType) import           Wingman.Types  @@ -40,6 +40,13 @@       | otherwise = Nothing  +------------------------------------------------------------------------------+-- | Build a trivial hypothesis containing only a single name. The corresponding+-- HyInfo has no provenance or type.+hySingleton :: OccName -> Hypothesis ()+hySingleton n = Hypothesis . pure $ HyInfo n UserPrv ()++ blacklistingDestruct :: Judgement -> Judgement blacklistingDestruct =   field @"_jBlacklistDestruct" .~ True@@ -62,11 +69,19 @@ withNewGoal t = field @"_jGoal" .~ t  -introduce :: Hypothesis a -> Judgement' a -> Judgement' a+normalizeHypothesis :: Functor f => Context -> f CType -> f CType+normalizeHypothesis = fmap . coerce . normalizeType++normalizeJudgement :: Functor f => Context -> f CType -> f CType+normalizeJudgement = normalizeHypothesis+++introduce :: Context -> Hypothesis CType -> Judgement' CType -> Judgement' CType -- NOTE(sandy): It's important that we put the new hypothesis terms first, -- since 'jAcceptableDestructTargets' will never destruct a pattern that occurs -- after a previously-destructed term.-introduce hy = field @"_jHypothesis" %~ mappend hy+introduce ctx hy =+  field @"_jHypothesis" %~ mappend (normalizeHypothesis ctx hy)   ------------------------------------------------------------------------------@@ -101,6 +116,12 @@   ------------------------------------------------------------------------------+-- | Introduce a binding in a recursive context.+userHypothesis :: [(OccName, a)] -> Hypothesis a+userHypothesis = introduceHypothesis $ const $ const UserPrv+++------------------------------------------------------------------------------ -- | Check whether any of the given occnames are an ancestor of the term. hasPositionalAncestry     :: Foldable t@@ -222,6 +243,7 @@ provAncestryOf (ClassMethodPrv _) = mempty provAncestryOf UserPrv = mempty provAncestryOf RecursivePrv = mempty+provAncestryOf ImportPrv = mempty provAncestryOf (DisallowedPrv _ p2) = provAncestryOf p2  @@ -295,6 +317,12 @@   ------------------------------------------------------------------------------+-- | Filter elements from the hypothesis+hyFilter :: (HyInfo a -> Bool) -> Hypothesis a -> Hypothesis a+hyFilter f  = Hypothesis . filter f . unHypothesis+++------------------------------------------------------------------------------ -- | Given a judgment, return the hypotheses that are acceptable to destruct. -- -- We use the ordering of the hypothesis for this purpose. Since new bindings@@ -373,17 +401,20 @@   mkFirstJudgement-    :: Hypothesis CType+    :: Context+    -> Hypothesis CType     -> Bool  -- ^ are we in the top level rhs hole?     -> Type     -> Judgement' CType-mkFirstJudgement hy top goal = Judgement-  { _jHypothesis        = hy-  , _jBlacklistDestruct = False-  , _jWhitelistSplit    = True-  , _jIsTopHole         = top-  , _jGoal              = CType goal-  }+mkFirstJudgement ctx hy top goal =+  normalizeJudgement ctx $+    Judgement+      { _jHypothesis        = hy+      , _jBlacklistDestruct = False+      , _jWhitelistSplit    = True+      , _jIsTopHole         = top+      , _jGoal              = CType goal+      }   ------------------------------------------------------------------------------
src/Wingman/Judgements/SYB.hs view
@@ -4,12 +4,15 @@ -- | Custom SYB traversals module Wingman.Judgements.SYB where -import Data.Foldable (foldl')-import Data.Generics hiding (typeRep)-import Development.IDE.GHC.Compat-import GHC.Exts (Any)-import Type.Reflection-import Unsafe.Coerce (unsafeCoerce)+import           Data.Foldable (foldl')+import           Data.Generics hiding (typeRep)+import qualified Data.Text as T+import           Development.IDE.GHC.Compat+import           GHC.Exts (Any)+import           GhcPlugins (unpackFS)+import           Type.Reflection+import           Unsafe.Coerce (unsafeCoerce)+import           Wingman.StaticPlugin (pattern WingmanMetaprogram)   ------------------------------------------------------------------------------@@ -80,4 +83,10 @@             Just HRefl -> True             Nothing    -> False         _ -> False+++metaprogramQ :: SrcSpan -> GenericQ [(SrcSpan, T.Text)]+metaprogramQ ss = everythingContaining ss $ mkQ mempty $ \case+  L new_span (WingmanMetaprogram program) -> pure (new_span, T.pack $ unpackFS $ program)+  (_ :: LHsExpr GhcTc) -> mempty 
src/Wingman/Judgements/Theta.hs view
@@ -12,13 +12,16 @@  import           Class (classTyVars) import           Control.Applicative (empty)+import           Control.Lens (preview) import           Data.Maybe (fromMaybe, mapMaybe, maybeToList)+import           Data.Generics.Sum (_Ctor) import           Data.Set (Set) import qualified Data.Set as S import           Development.IDE.Core.UseStale import           Development.IDE.GHC.Compat-import           Generics.SYB hiding (tyConName, empty)-import           GhcPlugins (mkVarOcc, splitTyConApp_maybe, getTyVar_maybe, zipTvSubst)+import           Generics.SYB hiding (tyConName, empty, Generic)+import           GHC.Generics+import           GhcPlugins (mkVarOcc, splitTyConApp_maybe, getTyVar_maybe, zipTvSubst, unionTCvSubst, emptyTCvSubst, TCvSubst) #if __GLASGOW_HASKELL__ > 806 import           GhcPlugins (eqTyCon) #else@@ -40,7 +43,7 @@   = EqualityOfTypes Type Type     -- | We have an instance in scope   | HasInstance PredType-  deriving (Show)+  deriving (Show, Generic)   ------------------------------------------------------------------------------@@ -75,21 +78,46 @@   . unTrack  ---------------------------------------------------------------------------------- | Update our knowledge of which types are equal.-evidenceToSubst :: Evidence -> TacticState -> TacticState-evidenceToSubst (EqualityOfTypes a b) ts =+mkSubst :: Set TyVar -> Type -> Type -> TCvSubst+mkSubst skolems a b =   let tyvars = S.fromList $ mapMaybe getTyVar_maybe [a, b]       -- If we can unify our skolems, at least one is no longer a skolem.       -- Removing them from this set ensures we can get a subtitution between       -- the two. But it's okay to leave them in 'ts_skolems' in general, since       -- they won't exist after running this substitution.-      skolems = ts_skolems ts S.\\ tyvars+      skolems' = skolems S.\\ tyvars    in-  case tryUnifyUnivarsButNotSkolems skolems (CType a) (CType b) of-    Just subst -> updateSubst subst ts-    Nothing -> ts-evidenceToSubst HasInstance{} ts = ts+  case tryUnifyUnivarsButNotSkolems skolems' (CType a) (CType b) of+    Just subst -> subst+    Nothing -> emptyTCvSubst+++substPair :: TCvSubst -> (Type, Type) -> (Type, Type)+substPair subst (ty, ty') = (substTy subst ty, substTy subst ty')+++------------------------------------------------------------------------------+-- | Construct a substitution given a list of types that are equal to one+-- another. This is more subtle than it seems, since there might be several+-- equalities for the same type. We must be careful to push the accumulating+-- substitution through each pair of types before adding their equalities.+allEvidenceToSubst :: Set TyVar -> [(Type, Type)] -> TCvSubst+allEvidenceToSubst _ [] = emptyTCvSubst+allEvidenceToSubst skolems ((a, b) : evs) =+  let subst = mkSubst skolems a b+   in unionTCvSubst subst+    $ allEvidenceToSubst skolems+    $ fmap (substPair subst) evs++------------------------------------------------------------------------------+-- | Update our knowledge of which types are equal.+evidenceToSubst :: [Evidence] -> TacticState -> TacticState+evidenceToSubst evs ts =+  updateSubst+    (allEvidenceToSubst (ts_skolems ts)+      $ mapMaybe (preview $ _Ctor @"EqualityOfTypes")+      $ evs)+    ts   ------------------------------------------------------------------------------
src/Wingman/KnownStrategies.hs view
@@ -1,18 +1,17 @@ module Wingman.KnownStrategies where +import Control.Applicative (empty) import Control.Monad.Error.Class+import Control.Monad.Reader.Class (asks)+import Data.Foldable (for_) import OccName (mkVarOcc) import Refinery.Tactic import Wingman.Context (getCurrentDefinitions, getKnownInstance)+import Wingman.Judgements (jGoal) import Wingman.KnownStrategies.QuickCheck (deriveArbitrary) import Wingman.Machinery (tracing) import Wingman.Tactics import Wingman.Types-import Wingman.Judgements (jGoal)-import Data.Foldable (for_)-import Wingman.FeatureSet-import Control.Applicative (empty)-import Control.Monad.Reader.Class (asks)   knownStrategies :: TacticsM ()@@ -20,19 +19,9 @@   [ known "fmap" deriveFmap   , known "mempty" deriveMempty   , known "arbitrary" deriveArbitrary-  , featureGuard FeatureKnownMonoid $ known "<>" deriveMappend-  , featureGuard FeatureKnownMonoid $ known "mappend" deriveMappend+  , known "<>" deriveMappend+  , known "mappend" deriveMappend   ]------------------------------------------------------------------------------------ | Guard a tactic behind a feature.-featureGuard :: Feature -> TacticsM a -> TacticsM a-featureGuard feat t = do-  fs <- asks ctxFeatureSet-  case hasFeature feat fs of-    True -> t-    False -> empty   known :: String -> TacticsM () -> TacticsM ()
src/Wingman/LanguageServer.hs view
@@ -1,28 +1,33 @@ {-# LANGUAGE CPP               #-} {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RankNTypes        #-}+{-# LANGUAGE TupleSections     #-} {-# LANGUAGE TypeFamilies      #-} +{-# LANGUAGE NoMonoLocalBinds  #-}+ module Wingman.LanguageServer where  import           ConLike-import           Control.Arrow+import           Control.Arrow ((***)) import           Control.Monad-import           Control.Monad.State (State, get, put, evalState)+import           Control.Monad.IO.Class+import           Control.Monad.RWS+import           Control.Monad.State (State, evalState) import           Control.Monad.Trans.Maybe+import           Data.Bifunctor (first) import           Data.Coerce import           Data.Functor ((<&>))-import           Data.Generics.Aliases (mkQ)-import           Data.Generics.Schemes (everything)+import           Data.Functor.Identity (runIdentity) import qualified Data.HashMap.Strict as Map import           Data.IORef (readIORef) import qualified Data.Map as M import           Data.Maybe-import           Data.Monoid import           Data.Set (Set) import qualified Data.Set as S import qualified Data.Text as T import           Data.Traversable-import           Development.IDE (getFilesOfInterest, ShowDiagnostic (ShowDiag), srcSpanToRange)+import           Development.IDE (getFilesOfInterestUntracked, ShowDiagnostic (ShowDiag), srcSpanToRange) import           Development.IDE (hscEnv) import           Development.IDE.Core.RuleTypes import           Development.IDE.Core.Rules (usePropertyAction)@@ -30,31 +35,39 @@ import           Development.IDE.Core.Shake (IdeState (..), uses, define, use) import qualified Development.IDE.Core.Shake as IDE import           Development.IDE.Core.UseStale-import           Development.IDE.GHC.Compat+import           Development.IDE.GHC.Compat hiding (parseExpr) import           Development.IDE.GHC.Error (realSrcSpanToRange)+import           Development.IDE.GHC.ExactPrint+import           Development.IDE.Graph (Action, RuleResult, Rules, action)+import           Development.IDE.Graph.Classes (Binary, Hashable, NFData) import           Development.IDE.Spans.LocalBindings (Bindings, getDefiningBindings)-import           Development.Shake (Action, RuleResult, Rules, action)-import           Development.Shake.Classes (Typeable, Binary, Hashable, NFData) import qualified FastString import           GHC.Generics (Generic)-import           GhcPlugins (tupleDataCon, consDataCon, substTyAddInScope, ExternalPackageState, HscEnv (hsc_EPS), liftIO)+import           Generics.SYB hiding (Generic)+import           GhcPlugins (extractModule)+import           GhcPlugins (tupleDataCon, consDataCon, substTyAddInScope, ExternalPackageState, HscEnv (hsc_EPS), unpackFS) import qualified Ide.Plugin.Config as Plugin import           Ide.Plugin.Properties import           Ide.PluginUtils (usePropertyLsp) import           Ide.Types (PluginId)+import           Language.Haskell.GHC.ExactPrint (Transform)+import           Language.Haskell.GHC.ExactPrint (modifyAnnsT, addAnnotationsForPretty) import           Language.LSP.Server (MonadLsp, sendNotification) import           Language.LSP.Types+import           Language.LSP.Types.Capabilities import           OccName import           Prelude hiding (span)+import           Retrie (transformA) import           SrcLoc (containsSpan)-import           TcRnTypes (tcg_binds, TcGblEnv)+import           TcRnTypes (tcg_binds, TcGblEnv (tcg_rdr_env)) import           Wingman.Context-import           Wingman.FeatureSet import           Wingman.GHC import           Wingman.Judgements-import           Wingman.Judgements.SYB (everythingContaining)+import           Wingman.Judgements.SYB (everythingContaining, metaprogramQ) import           Wingman.Judgements.Theta+import           Wingman.Metaprogramming.Lexer (ParserContext(..)) import           Wingman.Range+import           Wingman.StaticPlugin (pattern WingmanMetaprogram, pattern MetaprogramSyntax) import           Wingman.Types  @@ -68,8 +81,8 @@ tcCommandName = T.pack . show  -runIde :: IdeState -> Action a -> IO a-runIde state = runAction "tactic" state+runIde :: String -> String -> IdeState -> Action a -> IO a+runIde herald action state = runAction ("Wingman." <> herald <> "." <> action) state   runCurrentIde@@ -78,11 +91,13 @@        , Eq a , Hashable a , Binary a , Show a , Typeable a , NFData a        , Show r, Typeable r, NFData r        )-    => IdeState+    => String+    -> IdeState     -> NormalizedFilePath     -> a     -> MaybeT IO (Tracked 'Current r)-runCurrentIde state nfp a = MaybeT $ fmap (fmap unsafeMkCurrent) $ runIde state $ use a nfp+runCurrentIde herald state nfp a =+  MaybeT $ fmap (fmap unsafeMkCurrent) $ runIde herald (show a) state $ use a nfp   runStaleIde@@ -91,11 +106,13 @@        , Eq a , Hashable a , Binary a , Show a , Typeable a , NFData a        , Show r, Typeable r, NFData r        )-    => IdeState+    => String+    -> IdeState     -> NormalizedFilePath     -> a     -> MaybeT IO (TrackedStale r)-runStaleIde state nfp a = MaybeT $ runIde state $ useWithStale a nfp+runStaleIde herald state nfp a =+  MaybeT $ runIde herald (show a) state $ useWithStale a nfp   unsafeRunStaleIde@@ -104,12 +121,13 @@        , Eq a , Hashable a , Binary a , Show a , Typeable a , NFData a        , Show r, Typeable r, NFData r        )-    => IdeState+    => String+    -> IdeState     -> NormalizedFilePath     -> a     -> MaybeT IO r-unsafeRunStaleIde state nfp a = do-  (r, _) <- MaybeT $ runIde state $ IDE.useWithStale a nfp+unsafeRunStaleIde herald state nfp a = do+  (r, _) <- MaybeT $ runIde herald (show a) state $ IDE.useWithStale a nfp   pure r  @@ -118,14 +136,14 @@ properties :: Properties   '[ 'PropertyKey "hole_severity" ('TEnum (Maybe DiagnosticSeverity))    , 'PropertyKey "max_use_ctor_actions" 'TInteger-   , 'PropertyKey "features" 'TString    , 'PropertyKey "timeout_duration" 'TInteger+   , 'PropertyKey "auto_gas" 'TInteger    ] properties = emptyProperties+  & defineIntegerProperty #auto_gas+    "The depth of the search tree when performing \"Attempt to fill hole\". Bigger values will be able to derive more solutions, but will take exponentially more time." 4   & defineIntegerProperty #timeout_duration     "The timeout for Wingman actions, in seconds" 2-  & defineStringProperty #features-    "Feature set used by Wingman" ""   & defineIntegerProperty #max_use_ctor_actions     "Maximum number of `Use constructor <x>` code actions that can appear" 5   & defineEnumProperty #hole_severity@@ -143,14 +161,9 @@ getTacticConfig :: MonadLsp Plugin.Config m => PluginId -> m Config getTacticConfig pId =   Config-    <$> (parseFeatureSet <$> usePropertyLsp #features pId properties)-    <*> usePropertyLsp #max_use_ctor_actions pId properties+    <$> usePropertyLsp #max_use_ctor_actions pId properties     <*> usePropertyLsp #timeout_duration pId properties----------------------------------------------------------------------------------- | Get the current feature set from the plugin config.-getFeatureSet :: MonadLsp Plugin.Config m => PluginId -> m FeatureSet-getFeatureSet  = fmap cfg_feature_set . getTacticConfig+    <*> usePropertyLsp #auto_gas pId properties   getIdeDynflags@@ -160,10 +173,15 @@ getIdeDynflags state nfp = do   -- Ok to use the stale 'ModIface', since all we need is its 'DynFlags'   -- which don't change very often.-  msr <- unsafeRunStaleIde state nfp GetModSummaryWithoutTimestamps+  msr <- unsafeRunStaleIde "getIdeDynflags" state nfp GetModSummaryWithoutTimestamps   pure $ ms_hspp_opts $ msrModSummary msr +getAllMetaprograms :: Data a => a -> [String]+getAllMetaprograms = everything (<>) $ mkQ mempty $ \case+  WingmanMetaprogram fs -> [ unpackFS fs ]+  (_ :: HsExpr GhcTc)  -> mempty + ------------------------------------------------------------------------------ -- | Find the last typechecked module, and find the most specific span, as well -- as the judgement at the given range.@@ -171,21 +189,27 @@     :: IdeState     -> NormalizedFilePath     -> Tracked 'Current Range-    -> FeatureSet-    -> MaybeT IO (Tracked 'Current Range, Judgement, Context, DynFlags)-judgementForHole state nfp range features = do-  TrackedStale asts amapping  <- runStaleIde state nfp GetHieAst+    -> Config+    -> MaybeT IO HoleJudgment+judgementForHole state nfp range cfg = do+  let stale a = runStaleIde "judgementForHole" state nfp a++  TrackedStale asts amapping  <- stale GetHieAst   case unTrack asts of     HAR _ _  _ _ (HieFromDisk _) -> fail "Need a fresh hie file"     HAR _ (unsafeCopyAge asts -> hf) _ _ HieFresh -> do       range' <- liftMaybe $ mapAgeFrom amapping range-      binds <- runStaleIde state nfp GetBindings-      tcg <- fmap (fmap tmrTypechecked)-           $ runStaleIde state nfp TypeCheck-      hscenv <- runStaleIde state nfp GhcSessionDeps+      binds <- stale GetBindings+      tcg@(TrackedStale tcg_t tcg_map)+          <- fmap (fmap tmrTypechecked)+           $ stale TypeCheck +      hscenv <- stale GhcSessionDeps+       (rss, g) <- liftMaybe $ getSpanAndTypeAtHole range' hf+       new_rss <- liftMaybe $ mapAgeTo amapping rss+      tcg_rss <- liftMaybe $ mapAgeFrom tcg_map new_rss        -- KnownThings is just the instances in scope. There are no ranges       -- involved, so it's not crucial to track ages.@@ -193,14 +217,25 @@       eps <- liftIO $ readIORef $ hsc_EPS $ hscEnv henv       kt <- knownThings (untrackedStaleValue tcg) henv -      (jdg, ctx) <- liftMaybe $ mkJudgementAndContext features g binds new_rss tcg eps kt+      (jdg, ctx) <- liftMaybe $ mkJudgementAndContext cfg g binds new_rss tcg eps kt+      let mp = getMetaprogramAtSpan (fmap RealSrcSpan tcg_rss) tcg_t        dflags <- getIdeDynflags state nfp-      pure (fmap realSrcSpanToRange new_rss, jdg, ctx, dflags)+      pure $ HoleJudgment+        { hj_range = fmap realSrcSpanToRange new_rss+        , hj_jdg = jdg+        , hj_ctx = ctx+        , hj_dflags = dflags+        , hj_hole_sort = holeSortFor mp+        }  +holeSortFor :: Maybe T.Text -> HoleSort+holeSortFor = maybe Hole Metaprogram++ mkJudgementAndContext-    :: FeatureSet+    :: Config     -> Type     -> TrackedStale Bindings     -> Tracked 'Current RealSrcSpan@@ -208,12 +243,12 @@     -> ExternalPackageState     -> KnownThings     -> Maybe (Judgement, Context)-mkJudgementAndContext features g (TrackedStale binds bmap) rss (TrackedStale tcg tcgmap) eps kt = do+mkJudgementAndContext cfg g (TrackedStale binds bmap) rss (TrackedStale tcg tcgmap) eps kt = do   binds_rss <- mapAgeFrom bmap rss   tcg_rss <- mapAgeFrom tcgmap rss    let tcs = fmap tcg_binds tcg-      ctx = mkContext features+      ctx = mkContext cfg               (mapMaybe (sequenceA . (occName *** coerce))                 $ unTrack                 $ getDefiningBindings <$> binds <*> binds_rss)@@ -227,10 +262,12 @@                $ hypothesisFromBindings binds_rss binds       evidence = getEvidenceAtHole (fmap RealSrcSpan tcg_rss) tcs       cls_hy = foldMap evidenceToHypothesis evidence-      subst = ts_unifier $ appEndo (foldMap (Endo . evidenceToSubst) evidence) defaultTacticState+      subst = ts_unifier $ evidenceToSubst evidence defaultTacticState   pure $     ( disallowing AlreadyDestructed already_destructed-    $ fmap (CType . substTyAddInScope subst . unCType) $ mkFirstJudgement+    $ fmap (CType . substTyAddInScope subst . unCType) $+        mkFirstJudgement+          ctx           (local_hy <> cls_hy)           (isRhsHole tcg_rss tcs)           g@@ -267,8 +304,12 @@         ty <- listToMaybe $ nodeType info         guard $ ("HsUnboundVar","HsExpr") `S.member` nodeAnnotations info         -- Ensure we're actually looking at a hole here-        guard $ all (either (const False) $ isHole . occName)-          $ M.keysSet $ nodeIdentifiers info+        occ <- (either (const Nothing) (Just . occName) =<<)+             . listToMaybe+             . S.toList+             . M.keysSet+             $ nodeIdentifiers info+        guard $ isHole occ         pure (unsafeCopyAge r $ nodeSpan ast', ty)  @@ -500,7 +541,7 @@               )    action $ do-    files <- getFilesOfInterest+    files <- getFilesOfInterestUntracked     void $ uses WriteDiagnostics $ Map.keys files  @@ -513,4 +554,69 @@     "Hole"     (Just $ List [DtUnnecessary])     Nothing+++------------------------------------------------------------------------------+-- | Transform a 'Graft' over the AST into a 'WorkspaceEdit'.+mkWorkspaceEdits+    :: DynFlags+    -> ClientCapabilities+    -> Uri+    -> Annotated ParsedSource+    -> Graft (Either String) ParsedSource+    -> Either UserFacingMessage WorkspaceEdit+mkWorkspaceEdits dflags ccs uri pm g = do+  let pm' = runIdentity $ transformA pm annotateMetaprograms+  let response = transform dflags ccs uri g pm'+   in first (InfrastructureError . T.pack) response+++------------------------------------------------------------------------------+-- | Add ExactPrint annotations to every metaprogram in the source tree.+-- Usually the ExactPrint module can do this for us, but we've enabled+-- QuasiQuotes, so the round-trip print/parse journey will crash.+annotateMetaprograms :: Data a => a -> Transform a+annotateMetaprograms = everywhereM $ mkM $ \case+  L ss (WingmanMetaprogram mp) -> do+    let x = L ss $ MetaprogramSyntax mp+    let anns = addAnnotationsForPretty [] x mempty+    modifyAnnsT $ mappend anns+    pure x+  (x :: LHsExpr GhcPs) -> pure x+++------------------------------------------------------------------------------+-- | Find the source of a tactic metaprogram at the given span.+getMetaprogramAtSpan+    :: Tracked age SrcSpan+    -> Tracked age TcGblEnv+    -> Maybe T.Text+getMetaprogramAtSpan (unTrack -> ss)+  = fmap snd+  . listToMaybe+  . metaprogramQ ss+  . tcg_binds+  . unTrack+++------------------------------------------------------------------------------+-- | The metaprogram parser needs the ability to lookup terms from the module+-- and imports. The 'ParserContext' contains everything we need to find that+-- stuff.+getParserState+    :: IdeState+    -> NormalizedFilePath+    -> Context+    -> MaybeT IO ParserContext+getParserState state nfp ctx = do+  let stale a = runStaleIde "getParserState" state nfp a++  TrackedStale (unTrack -> tcmod) _  <- stale TypeCheck+  TrackedStale (unTrack -> hscenv) _ <- stale GhcSessionDeps++  let tcgblenv = tmrTypechecked tcmod+      modul = extractModule tcgblenv+      rdrenv = tcg_rdr_env tcgblenv++  pure $ ParserContext (hscEnv hscenv) rdrenv modul ctx 
+ src/Wingman/LanguageServer/Metaprogram.hs view
@@ -0,0 +1,89 @@+{-# LANGUAGE DuplicateRecordFields #-}+{-# LANGUAGE OverloadedStrings     #-}++{-# LANGUAGE NoMonoLocalBinds  #-}+{-# LANGUAGE RankNTypes #-}++module Wingman.LanguageServer.Metaprogram+  ( hoverProvider+  ) where++import           Control.Applicative (empty)+import           Control.Monad+import           Control.Monad.Reader (runReaderT)+import           Control.Monad.Trans+import           Control.Monad.Trans.Maybe+import           Data.List (find)+import           Data.Maybe+import qualified Data.Text as T+import           Data.Traversable+import           Development.IDE (positionToRealSrcLoc)+import           Development.IDE (realSrcSpanToRange)+import           Development.IDE.Core.RuleTypes+import           Development.IDE.Core.Shake (IdeState (..))+import           Development.IDE.Core.UseStale+import           Development.IDE.GHC.Compat+import           GhcPlugins (containsSpan, realSrcLocSpan)+import           Ide.Types+import           Language.LSP.Types+import           Prelude hiding (span)+import           Prelude hiding (span)+import           TcRnTypes (tcg_binds)+import           Wingman.GHC+import           Wingman.Judgements.SYB (metaprogramQ)+import           Wingman.LanguageServer+import           Wingman.Metaprogramming.Parser (attempt_it)+import           Wingman.Types+++------------------------------------------------------------------------------+-- | Provide the "empty case completion" code lens+hoverProvider :: PluginMethodHandler IdeState TextDocumentHover+hoverProvider state plId (HoverParams (TextDocumentIdentifier uri) (unsafeMkCurrent -> pos) _)+  | Just nfp <- uriToNormalizedFilePath $ toNormalizedUri uri = do+      let loc = fmap (realSrcLocSpan . positionToRealSrcLoc nfp) pos++      cfg <- getTacticConfig plId+      liftIO $ fromMaybeT (Right Nothing) $ do+        holes <- getMetaprogramsAtSpan state nfp $ RealSrcSpan $ unTrack loc++        fmap (Right . Just) $+          case (find (flip containsSpan (unTrack loc) . unTrack . fst) holes) of+            Just (trss, program) -> do+              let tr_range = fmap realSrcSpanToRange trss+              HoleJudgment{hj_jdg=jdg, hj_ctx=ctx} <- judgementForHole state nfp tr_range cfg+              ps <- getParserState state nfp ctx+              z <- liftIO $ flip runReaderT ps $ attempt_it ctx jdg $ T.unpack program+              pure $ Hover+                { _contents = HoverContents+                            $ MarkupContent MkMarkdown+                            $ either T.pack T.pack z+                , _range = Just $ unTrack tr_range+                }+            Nothing -> empty+hoverProvider _ _ _ = pure $ Right Nothing+++fromMaybeT :: Functor m => a -> MaybeT m a -> m a+fromMaybeT def = fmap (fromMaybe def) . runMaybeT+++getMetaprogramsAtSpan+    :: IdeState+    -> NormalizedFilePath+    -> SrcSpan+    -> MaybeT IO [(Tracked 'Current RealSrcSpan, T.Text)]+getMetaprogramsAtSpan state nfp ss = do+    let stale a = runStaleIde "getMetaprogramsAtSpan" state nfp a++    TrackedStale tcg tcg_map <- fmap (fmap tmrTypechecked) $ stale TypeCheck++    let scrutinees = traverse (metaprogramQ ss . tcg_binds) tcg+    for scrutinees $ \aged@(unTrack -> (ss, program)) -> do+      case ss of+        RealSrcSpan r   -> do+          rss' <- liftMaybe $ mapAgeTo tcg_map $ unsafeCopyAge aged r+          pure (rss', program)+        UnhelpfulSpan _ -> empty++
src/Wingman/LanguageServer/TacticProviders.hs view
@@ -1,3 +1,4 @@+{-# LANGUAGE CPP               #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE RecordWildCards   #-} @@ -7,14 +8,14 @@   , tcCommandId   , TacticParams (..)   , TacticProviderData (..)+  , useNameFromHypothesis   ) where  import           Control.Monad-import           Control.Monad.Error.Class (MonadError (throwError))+import           Control.Monad.Reader (runReaderT) import           Data.Aeson import           Data.Bool (bool) import           Data.Coerce-import qualified Data.Map as M import           Data.Maybe import           Data.Monoid import qualified Data.Text as T@@ -29,27 +30,31 @@ import           Language.LSP.Types import           OccName import           Prelude hiding (span)-import           Refinery.Tactic (goal) import           Wingman.Auto-import           Wingman.FeatureSet import           Wingman.GHC import           Wingman.Judgements+import           Wingman.Machinery (useNameFromHypothesis)+import           Wingman.Metaprogramming.Lexer (ParserContext)+import           Wingman.Metaprogramming.Parser (parseMetaprogram) import           Wingman.Tactics import           Wingman.Types   ------------------------------------------------------------------------------ -- | A mapping from tactic commands to actual tactics for refinery.-commandTactic :: TacticCommand -> OccName -> TacticsM ()-commandTactic Auto                   = const auto-commandTactic Intros                 = const intros-commandTactic Destruct               = useNameFromHypothesis destruct-commandTactic Homomorphism           = useNameFromHypothesis homo-commandTactic DestructLambdaCase     = const destructLambdaCase-commandTactic HomomorphismLambdaCase = const homoLambdaCase-commandTactic DestructAll            = const destructAll-commandTactic UseDataCon             = userSplit-commandTactic Refine                 = const refine+commandTactic :: ParserContext -> TacticCommand -> T.Text -> IO (TacticsM ())+commandTactic _ Auto                   = pure . const auto+commandTactic _ Intros                 = pure . const intros+commandTactic _ Destruct               = pure . useNameFromHypothesis destruct . mkVarOcc . T.unpack+commandTactic _ DestructPun            = pure . useNameFromHypothesis destructPun . mkVarOcc . T.unpack+commandTactic _ Homomorphism           = pure . useNameFromHypothesis homo . mkVarOcc . T.unpack+commandTactic _ DestructLambdaCase     = pure . const destructLambdaCase+commandTactic _ HomomorphismLambdaCase = pure . const homoLambdaCase+commandTactic _ DestructAll            = pure . const destructAll+commandTactic _ UseDataCon             = pure . userSplit . mkVarOcc . T.unpack+commandTactic _ Refine                 = pure . const refine+commandTactic _ BeginMetaprogram       = pure . const metaprogram+commandTactic c RunMetaprogram         = flip runReaderT c . parseMetaprogram   ------------------------------------------------------------------------------@@ -58,12 +63,15 @@ tacticKind Auto                   = "fillHole" tacticKind Intros                 = "introduceLambda" tacticKind Destruct               = "caseSplit"+tacticKind DestructPun            = "caseSplitPun" tacticKind Homomorphism           = "homomorphicCaseSplit" tacticKind DestructLambdaCase     = "lambdaCase" tacticKind HomomorphismLambdaCase = "homomorphicLambdaCase" tacticKind DestructAll            = "splitFuncArgs" tacticKind UseDataCon             = "useConstructor" tacticKind Refine                 = "refine"+tacticKind BeginMetaprogram       = "beginMetaprogram"+tacticKind RunMetaprogram         = "runMetaprogram"   ------------------------------------------------------------------------------@@ -73,12 +81,15 @@ tacticPreferred Auto                   = True tacticPreferred Intros                 = True tacticPreferred Destruct               = True+tacticPreferred DestructPun            = False tacticPreferred Homomorphism           = False tacticPreferred DestructLambdaCase     = False tacticPreferred HomomorphismLambdaCase = False tacticPreferred DestructAll            = True tacticPreferred UseDataCon             = True tacticPreferred Refine                 = True+tacticPreferred BeginMetaprogram       = False+tacticPreferred RunMetaprogram         = True   mkTacticKind :: TacticCommand -> CodeActionKind@@ -90,49 +101,77 @@ -- | Mapping from tactic commands to their contextual providers. See 'provide', -- 'filterGoalType' and 'filterBindingType' for the nitty gritty. commandProvider :: TacticCommand -> TacticProvider-commandProvider Auto  = provide Auto ""+commandProvider Auto  =+  requireHoleSort (== Hole) $+  provide Auto "" commandProvider Intros =+  requireHoleSort (== Hole) $   filterGoalType isFunction $     provide Intros "" commandProvider Destruct =+  requireHoleSort (== Hole) $   filterBindingType destructFilter $ \occ _ ->     provide Destruct $ T.pack $ occNameString occ+commandProvider DestructPun =+  requireHoleSort (== Hole) $+    filterBindingType destructPunFilter $ \occ _ ->+      provide DestructPun $ T.pack $ occNameString occ commandProvider Homomorphism =+  requireHoleSort (== Hole) $   filterBindingType homoFilter $ \occ _ ->     provide Homomorphism $ T.pack $ occNameString occ commandProvider DestructLambdaCase =+  requireHoleSort (== Hole) $   requireExtension LambdaCase $     filterGoalType (isJust . lambdaCaseable) $       provide DestructLambdaCase "" commandProvider HomomorphismLambdaCase =+  requireHoleSort (== Hole) $   requireExtension LambdaCase $     filterGoalType ((== Just True) . lambdaCaseable) $       provide HomomorphismLambdaCase "" commandProvider DestructAll =-  requireFeature FeatureDestructAll $+  requireHoleSort (== Hole) $     withJudgement $ \jdg ->       case _jIsTopHole jdg && jHasBoundArgs jdg of         True  -> provide DestructAll ""         False -> mempty commandProvider UseDataCon =+  requireHoleSort (== Hole) $   withConfig $ \cfg ->-    requireFeature FeatureUseDataCon $-      filterTypeProjection-          ( guardLength (<= cfg_max_use_ctor_actions cfg)-          . fromMaybe []-          . fmap fst-          . tacticsGetDataCons-          ) $ \dcon ->-        provide UseDataCon-          . T.pack-          . occNameString-          . occName-          $ dataConName dcon+    filterTypeProjection+        ( guardLength (<= cfg_max_use_ctor_actions cfg)+        . fromMaybe []+        . fmap fst+        . tacticsGetDataCons+        ) $ \dcon ->+      provide UseDataCon+        . T.pack+        . occNameString+        . occName+        $ dataConName dcon commandProvider Refine =-  requireFeature FeatureRefineHole $+  requireHoleSort (== Hole) $     provide Refine ""+commandProvider BeginMetaprogram =+  requireGHC88OrHigher $+  requireHoleSort (== Hole) $+    provide BeginMetaprogram ""+commandProvider RunMetaprogram =+  requireGHC88OrHigher $+  withMetaprogram $ \mp ->+    provide RunMetaprogram mp  +requireGHC88OrHigher :: TacticProvider -> TacticProvider+requireGHC88OrHigher tp tpd =+#if __GLASGOW_HASKELL__ >= 808+  tp tpd+#else+  mempty+#endif++ ------------------------------------------------------------------------------ -- | Return an empty list if the given predicate doesn't hold over the length guardLength :: (Int -> Bool) -> [a] -> [a]@@ -146,6 +185,7 @@      = TacticProviderData     -> IO [Command |? CodeAction] + data TacticProviderData = TacticProviderData   { tpd_dflags :: DynFlags   , tpd_config :: Config@@ -153,6 +193,7 @@   , tpd_uri    :: Uri   , tpd_range  :: Tracked 'Current Range   , tpd_jdg    :: Judgement+  , tpd_hole_sort :: HoleSort   }  @@ -165,16 +206,19 @@   deriving anyclass (ToJSON, FromJSON)  ---------------------------------------------------------------------------------- | Restrict a 'TacticProvider', making sure it appears only when the given--- 'Feature' is in the feature set.-requireFeature :: Feature -> TacticProvider -> TacticProvider-requireFeature f tp tpd =-  case hasFeature f $ cfg_feature_set $ tpd_config tpd of+requireHoleSort :: (HoleSort -> Bool) -> TacticProvider -> TacticProvider+requireHoleSort p tp tpd =+  case p $ tpd_hole_sort tpd of     True  -> tp tpd     False -> pure [] +withMetaprogram :: (T.Text -> TacticProvider) -> TacticProvider+withMetaprogram tp tpd =+  case tpd_hole_sort tpd of+    Metaprogram mp -> tp mp tpd+    _ -> pure [] + ------------------------------------------------------------------------------ -- | Restrict a 'TacticProvider', making sure it appears only when the given -- predicate holds for the goal.@@ -238,19 +282,7 @@ withConfig tp tpd = tp (tpd_config tpd) tpd  - --------------------------------------------------------------------------------- | Lift a function over 'HyInfo's to one that takes an 'OccName' and tries to--- look it up in the hypothesis.-useNameFromHypothesis :: (HyInfo CType -> TacticsM a) -> OccName -> TacticsM a-useNameFromHypothesis f name = do-  hy <- jHypothesis <$> goal-  case M.lookup name $ hyByName hy of-    Just hi -> f hi-    Nothing -> throwError $ NotInScope name--------------------------------------------------------------------------------- -- | Terminal constructor for providing context-sensitive tactics. Tactics -- given by 'provide' are always available. provide :: TacticCommand -> T.Text -> TacticProvider@@ -293,4 +325,13 @@ destructFilter :: Type -> Type -> Bool destructFilter _ (algebraicTyCon -> Just _) = True destructFilter _ _                          = False+++------------------------------------------------------------------------------+-- | We should show destruct punning for bindings only when those bindings have+-- usual algebraic types, and when any of their data constructors are records.+destructPunFilter :: Type -> Type -> Bool+destructPunFilter _ (algebraicTyCon -> Just tc) =+  any (not . null . dataConFieldLabels) $ tyConDataCons tc+destructPunFilter _ _                          = False 
src/Wingman/Machinery.hs view
@@ -3,11 +3,12 @@ module Wingman.Machinery where  import           Class (Class (classTyVars))+import           Control.Applicative (empty) import           Control.Lens ((<>~)) import           Control.Monad.Error.Class import           Control.Monad.Reader import           Control.Monad.State.Class (gets, modify)-import           Control.Monad.State.Strict (StateT (..))+import           Control.Monad.State.Strict (StateT (..), execStateT) import           Data.Bool (bool) import           Data.Coerce import           Data.Either@@ -22,13 +23,15 @@ import           Data.Ord (Down (..), comparing) import           Data.Set (Set) import qualified Data.Set as S+import           Development.IDE.Core.Compile (lookupName) import           Development.IDE.GHC.Compat-import           OccName (HasOccName (occName))+import           GhcPlugins (GlobalRdrElt (gre_name), lookupOccEnv, varType)+import           OccName (HasOccName (occName), OccEnv) import           Refinery.ProofState import           Refinery.Tactic import           Refinery.Tactic.Internal import           TcType-import           Type+import           Type (tyCoVarsOfTypeWellScoped, splitTyConApp_maybe) import           Unify import           Wingman.Judgements import           Wingman.Simplify (simplify)@@ -46,12 +49,19 @@     :: Judgement     -> Rule newSubgoal j = do-    unifier <- gets ts_unifier-    subgoal-      $ substJdg unifier-      $ unsetIsTopHole j+  ctx <- ask+  unifier <- gets ts_unifier+  subgoal+    $ normalizeJudgement ctx+    $ substJdg unifier+    $ unsetIsTopHole+    $ normalizeJudgement ctx j  +tacticToRule :: Judgement -> TacticsM () -> Rule+tacticToRule jdg (TacticT tt) = RuleT $ flip execStateT jdg tt >>= flip Subgoal Axiom++ ------------------------------------------------------------------------------ -- | Attempt to generate a term of the right type using in-scope bindings, and -- a given tactic.@@ -82,11 +92,12 @@               flip sortBy solns $ comparing $ \(ext, (_, holes)) ->                 Down $ scoreSolution ext jdg holes         case sorted of-          ((syn, _) : _) ->+          ((syn, (_, subgoals)) : _) ->             Right $               RunTacticResults-                { rtr_trace = syn_trace syn-                , rtr_extract = simplify $ syn_val syn+                { rtr_trace    = syn_trace syn+                , rtr_extract  = simplify $ syn_val syn+                , rtr_subgoals = subgoals                 , rtr_other_solns = reverse . fmap fst $ sorted                 , rtr_jdg = jdg                 , rtr_ctx = ctx@@ -297,4 +308,69 @@     => TacticT jdg ext err s m ()     -> TacticT jdg ext err s m () try' t = commit t $ pure ()+++------------------------------------------------------------------------------+-- | Sorry leaves a hole in its extract+exact :: HsExpr GhcPs -> TacticsM ()+exact = rule . const . pure . pure . noLoc++------------------------------------------------------------------------------+-- | Lift a function over 'HyInfo's to one that takes an 'OccName' and tries to+-- look it up in the hypothesis.+useNameFromHypothesis :: (HyInfo CType -> TacticsM a) -> OccName -> TacticsM a+useNameFromHypothesis f name = do+  hy <- jHypothesis <$> goal+  case M.lookup name $ hyByName hy of+    Just hi -> f hi+    Nothing -> throwError $ NotInScope name++------------------------------------------------------------------------------+-- | Lift a function over 'HyInfo's to one that takes an 'OccName' and tries to+-- look it up in the hypothesis.+useNameFromContext :: (HyInfo CType -> TacticsM a) -> OccName -> TacticsM a+useNameFromContext f name = do+  lookupNameInContext name >>= \case+    Just ty -> f $ createImportedHyInfo name ty+    Nothing -> throwError $ NotInScope name+++------------------------------------------------------------------------------+-- | Find the type of an 'OccName' that is defined in the current module.+lookupNameInContext :: MonadReader Context m => OccName -> m (Maybe CType)+lookupNameInContext name = do+  ctx <- asks ctxModuleFuncs+  pure $ case find ((== name) . fst) ctx of+    Just (_, ty) -> pure ty+    Nothing      -> empty+++------------------------------------------------------------------------------+-- | Build a 'HyInfo' for an imported term.+createImportedHyInfo :: OccName -> CType -> HyInfo CType+createImportedHyInfo on ty = HyInfo+  { hi_name = on+  , hi_provenance = ImportPrv+  , hi_type = ty+  }+++------------------------------------------------------------------------------+-- | Lookup the type of any 'OccName' that was imported. Necessarily done in+-- IO, so we only expose this functionality to the parser. Internal Haskell+-- code that wants to lookup terms should do it via 'KnownThings'.+getOccNameType+    :: HscEnv+    -> OccEnv [GlobalRdrElt]+    -> Module+    -> OccName+    -> IO (Maybe Type)+getOccNameType hscenv rdrenv modul occ =+  case lookupOccEnv rdrenv occ of+    Just (elt : _) -> do+      mvar <- lookupName hscenv modul $ gre_name elt+      pure $ case mvar of+        Just (AnId v) -> pure $ varType v+        _ -> Nothing+    _ -> pure Nothing 
+ src/Wingman/Metaprogramming/Lexer.hs view
@@ -0,0 +1,85 @@+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications  #-}++module Wingman.Metaprogramming.Lexer where++import           Control.Applicative+import           Control.Monad+import           Control.Monad.Reader (ReaderT)+import           Data.Text (Text)+import qualified Data.Text as T+import           Data.Void+import           Development.IDE.GHC.Compat (HscEnv, Module)+import           GhcPlugins (GlobalRdrElt)+import           Name+import qualified Text.Megaparsec as P+import qualified Text.Megaparsec.Char as P+import qualified Text.Megaparsec.Char.Lexer as L+import Wingman.Types (Context)+++------------------------------------------------------------------------------+-- | Everything we need in order to call 'Wingman.Machinery.getOccNameType'.+data ParserContext = ParserContext+  { ps_hscEnv :: HscEnv+  , ps_occEnv :: OccEnv [GlobalRdrElt]+  , ps_module :: Module+  , ps_context :: Context+  }++type Parser = P.ParsecT Void Text (ReaderT ParserContext IO)++++lineComment :: Parser ()+lineComment = L.skipLineComment "--"++blockComment :: Parser ()+blockComment = L.skipBlockComment "{-" "-}"++sc :: Parser ()+sc = L.space P.space1 lineComment blockComment++ichar :: Parser Char+ichar = P.alphaNumChar <|> P.char '_' <|> P.char '\''++lexeme :: Parser a -> Parser a+lexeme = L.lexeme sc++symbol :: Text -> Parser Text+symbol = L.symbol sc++symbol_ :: Text -> Parser ()+symbol_ = void . symbol++brackets :: Parser a -> Parser a+brackets = P.between (symbol "[") (symbol "]")++braces :: Parser a -> Parser a+braces = P.between (symbol "{") (symbol "}")++parens :: Parser a -> Parser a+parens = P.between (symbol "(") (symbol ")")++identifier :: Text -> Parser ()+identifier i = lexeme (P.string i *> P.notFollowedBy ichar)++-- FIXME [Reed M. 2020-10-18] Check to see if the variables are in the reserved list+variable :: Parser OccName+variable = lexeme $ do+    c <- P.alphaNumChar+    cs <- P.many ichar+    pure $ mkVarOcc (c:cs)++-- FIXME [Reed M. 2020-10-18] Check to see if the variables are in the reserved list+name :: Parser Text+name = lexeme $ do+    c <- P.alphaNumChar+    cs <- P.many (ichar <|> P.char '-')+    pure $ T.pack (c:cs)++keyword :: Text -> Parser ()+keyword = identifier+
+ src/Wingman/Metaprogramming/Parser.hs view
@@ -0,0 +1,434 @@+{-# LANGUAGE DataKinds         #-}+{-# LANGUAGE LambdaCase        #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE TypeApplications  #-}++module Wingman.Metaprogramming.Parser where++import qualified Control.Monad.Combinators.Expr as P+import qualified Control.Monad.Error.Class as E+import           Control.Monad.Reader (ReaderT, ask, MonadIO (liftIO), asks)+import           Data.Functor+import           Data.Maybe (listToMaybe)+import qualified Data.Text as T+import           GhcPlugins (occNameString)+import qualified Refinery.Tactic as R+import qualified Text.Megaparsec as P+import           Wingman.Auto+import           Wingman.Context (getCurrentDefinitions)+import           Wingman.Machinery (useNameFromHypothesis, getOccNameType, createImportedHyInfo, useNameFromContext, lookupNameInContext)+import           Wingman.Metaprogramming.Lexer+import           Wingman.Metaprogramming.Parser.Documentation+import           Wingman.Metaprogramming.ProofState (proofState, layout)+import           Wingman.Tactics+import           Wingman.Types+++nullary :: T.Text -> TacticsM () -> Parser (TacticsM ())+nullary name tac = identifier name $> tac+++unary_occ :: T.Text -> (OccName -> TacticsM ()) -> Parser (TacticsM ())+unary_occ name tac = tac <$> (identifier name *> variable)+++------------------------------------------------------------------------------+-- | Like 'unary_occ', but runs directly in the 'Parser' monad.+unary_occM :: T.Text -> (OccName -> Parser (TacticsM ())) -> Parser (TacticsM ())+unary_occM name tac = tac =<< (identifier name *> variable)+++variadic_occ :: T.Text -> ([OccName] -> TacticsM ()) -> Parser (TacticsM ())+variadic_occ name tac = tac <$> (identifier name *> P.many variable)+++commands :: [SomeMetaprogramCommand]+commands =+  [ command "assumption" Nondeterministic Nullary+      "Use any term in the hypothesis that can unify with the current goal."+      (pure assumption)+      [ Example+          Nothing+          []+          [EHI "some_a_val" "a"]+          (Just "a")+          "some_a_val"+      ]++  , command "assume" Deterministic (Ref One)+      "Use the given term from the hypothesis, unifying it with the current goal"+      (pure . assume)+      [ Example+          Nothing+          ["some_a_val"]+          [EHI "some_a_val" "a"]+          (Just "a")+          "some_a_val"+      ]++  , command "intros" Deterministic (Bind Many)+      ( mconcat+          [ "Construct a lambda expression, using the specific names if given, "+          , "generating unique names otherwise. When no arguments are given, "+          , "all of the function arguments will be bound; otherwise, this "+          , "tactic will bind only enough to saturate the given names. Extra "+          , "names are ignored."+          ])+      (pure . \case+        []    -> intros+        names -> intros' $ Just names+      )+      [ Example+          Nothing+          []+          []+          (Just "a -> b -> c -> d")+          "\\a b c -> (_ :: d)"+      , Example+          Nothing+          ["aye"]+          []+          (Just "a -> b -> c -> d")+          "\\aye -> (_ :: b -> c -> d)"+      , Example+          Nothing+          ["x", "y", "z", "w"]+          []+          (Just "a -> b -> c -> d")+          "\\x y z -> (_ :: d)"+      ]++  , command "intro" Deterministic (Bind One)+      "Construct a lambda expression, binding an argument with the given name."+      (pure . intros' . Just . pure)+      [ Example+          Nothing+          ["aye"]+          []+          (Just "a -> b -> c -> d")+          "\\aye -> (_ :: b -> c -> d)"+      ]++  , command "destruct_all" Deterministic Nullary+      "Pattern match on every function paramater, in original binding order."+      (pure destructAll)+      [ Example+          (Just "Assume `a` and `b` were bound via `f a b = _`.")+          []+          [EHI "a" "Bool", EHI "b" "Maybe Int"]+          Nothing $+          T.pack $ init $ unlines+            [ "case a of"+            , "  False -> case b of"+            , "    Nothing -> _"+            , "    Just i -> _"+            , "  True -> case b of"+            , "    Nothing -> _"+            , "    Just i -> _"+            ]+      ]++  , command "destruct" Deterministic (Ref One)+      "Pattern match on the argument."+      (pure . useNameFromHypothesis destruct)+      [ Example+          Nothing+          ["a"]+          [EHI "a" "Bool"]+          Nothing $+          T.pack $ init $ unlines+            [ "case a of"+            , "  False -> _"+            , "  True -> _"+            ]+      ]++  , command "homo" Deterministic (Ref One)+      ( mconcat+        [ "Pattern match on the argument, and fill the resulting hole in with "+        , "the same data constructor."+        ])+      (pure . useNameFromHypothesis homo)+      [ Example+          (Just $ mconcat+            [ "Only applicable when the type constructor of the argument is "+            , "the same as that of the hole."+            ])+          ["e"]+          [EHI "e" "Either a b"]+          (Just "Either x y") $+          T.pack $ init $ unlines+            [ "case e of"+            , "  Left a -> Left (_ :: x)"+            , "  Right b -> Right (_ :: y)"+            ]+      ]++  , command "application" Nondeterministic Nullary+      "Apply any function in the hypothesis that returns the correct type."+      (pure application)+      [ Example+          Nothing+          []+          [EHI "f" "a -> b"]+          (Just "b")+          "f (_ :: a)"+      ]++  , command "apply" Deterministic (Ref One)+      "Apply the given function from *local* scope."+      (pure . useNameFromHypothesis apply)+      [ Example+          Nothing+          ["f"]+          [EHI "f" "a -> b"]+          (Just "b")+          "f (_ :: a)"+      ]++  , command "split" Nondeterministic Nullary+      "Produce a data constructor for the current goal."+      (pure split)+      [ Example+          Nothing+          []+          []+          (Just "Either a b")+          "Right (_ :: b)"+      ]++  , command "ctor" Deterministic (Ref One)+      "Use the given data cosntructor."+      (pure . userSplit)+      [ Example+          Nothing+          ["Just"]+          []+          (Just "Maybe a")+          "Just (_ :: a)"+      ]++  , command "obvious" Nondeterministic Nullary+      "Produce a nullary data constructor for the current goal."+      (pure obvious)+      [ Example+          Nothing+          []+          []+          (Just "[a]")+          "[]"+      ]++  , command "auto" Nondeterministic Nullary+      ( mconcat+          [ "Repeatedly attempt to split, destruct, apply functions, and "+          , "recurse in an attempt to fill the hole."+          ])+      (pure auto)+      [ Example+          Nothing+          []+          [EHI "f" "a -> b", EHI "g" "b -> c"]+          (Just "a -> c")+          "g . f"+      ]++  , command "sorry" Deterministic Nullary+      "\"Solve\" the goal by leaving a hole."+      (pure sorry)+      [ Example+          Nothing+          []+          []+          (Just "b")+          "_ :: b"+      ]++  , command "unary" Deterministic Nullary+      ( mconcat+        [ "Produce a hole for a single-parameter function, as well as a hole for "+        , "its argument. The argument holes are completely unconstrained, and "+        , "will be solved before the function."+        ])+      (pure $ nary 1)+      [ Example+          (Just $ mconcat+            [ "In the example below, the variable `a` is free, and will unify "+            , "to the resulting extract from any subsequent tactic."+            ])+          []+          []+          (Just "Int")+          "(_2 :: a -> Int) (_1 :: a)"+      ]++  , command "binary" Deterministic Nullary+      ( mconcat+        [ "Produce a hole for a two-parameter function, as well as holes for "+        , "its arguments. The argument holes have the same type but are "+        , "otherwise unconstrained, and will be solved before the function."+        ])+      (pure $ nary 2)+      [ Example+          (Just $ mconcat+            [ "In the example below, the variable `a` is free, and will unify "+            , "to the resulting extract from any subsequent tactic."+            ])+          []+          []+          (Just "Int")+          "(_3 :: a -> a -> Int) (_1 :: a) (_2 :: a)"+      ]++  , command "recursion" Deterministic Nullary+      "Fill the current hole with a call to the defining function."+      ( pure $+          fmap listToMaybe getCurrentDefinitions >>= \case+            Just (self, _) -> useNameFromContext apply self+            Nothing -> E.throwError $ TacticPanic "no defining function"+      )+      [ Example+          (Just "In the context of `foo (a :: Int) (b :: b) = _`:")+          []+          []+          Nothing+          "foo (_ :: Int) (_ :: b)"+      ]++  , command "use" Deterministic (Ref One)+      "Apply the given function from *module* scope."+      ( \occ -> do+          ctx <- asks ps_context+          ty <- case lookupNameInContext occ ctx of+            Just ty -> pure ty+            Nothing -> CType <$> getOccTy occ+          pure $ apply $ createImportedHyInfo occ ty+      )+      [ Example+          (Just "`import Data.Char (isSpace)`")+          ["isSpace"]+          []+          (Just "Bool")+          "isSpace (_ :: Char)"+      ]++  , command "cata" Deterministic (Ref One)+      "Destruct the given term, recursing on every resulting binding."+      (pure . useNameFromHypothesis cata)+      [ Example+          (Just "Assume we're called in the context of a function `f.`")+          ["x"]+          [EHI "x" "(a, a)"]+          Nothing $+          T.pack $ init $ unlines+            [ "case x of"+            , "  (a1, a2) ->"+            , "    let a1_c = f a1"+            , "        a2_c = f a2"+            , "     in _"+            ]+      ]++  , command "collapse" Deterministic Nullary+      "Collapse every term in scope with the same type as the goal."+      (pure collapse)+      [ Example+          Nothing+          []+          [ EHI "a1" "a"+          , EHI "a2" "a"+          , EHI "a3" "a"+          ]+          (Just "a")+          "(_ :: a -> a -> a -> a) a1 a2 a3"+      ]++  ]++++oneTactic :: Parser (TacticsM ())+oneTactic =+  P.choice+    [ parens tactic+    , makeParser commands+    ]+++tactic :: Parser (TacticsM ())+tactic = flip P.makeExprParser operators oneTactic++bindOne :: TacticsM a -> TacticsM a -> TacticsM a+bindOne t t1 = t R.<@> [t1]++operators :: [[P.Operator Parser (TacticsM ())]]+operators =+    [ [ P.Prefix (symbol "*"   $> R.many_) ]+    , [ P.Prefix (symbol "try" $> R.try) ]+    , [ P.InfixR (symbol "|"   $> (R.<%>) )]+    , [ P.InfixL (symbol ";"   $> (>>))+      , P.InfixL (symbol ","   $> bindOne)+      ]+    ]+++tacticProgram :: Parser (TacticsM ())+tacticProgram = do+  sc+  r <- tactic P.<|> pure (pure ())+  P.eof+  pure r+++wrapError :: String -> String+wrapError err = "```\n" <> err <> "\n```\n"+++------------------------------------------------------------------------------+-- | Attempt to run a metaprogram tactic, returning the proof state, or the+-- errors.+attempt_it+    :: Context+    -> Judgement+    -> String+    -> ReaderT ParserContext IO (Either String String)+attempt_it ctx jdg program =+  P.runParserT tacticProgram "<splice>" (T.pack program) <&> \case+      Left peb -> Left $ wrapError $ P.errorBundlePretty peb+      Right tt -> do+        case runTactic+              ctx+              jdg+              tt+          of+            Left tes -> Left $ wrapError $ show tes+            Right rtr -> Right $ layout $ proofState rtr+++parseMetaprogram :: T.Text -> ReaderT ParserContext IO (TacticsM ())+parseMetaprogram+    = fmap (either (const $ pure ()) id)+    . P.runParserT tacticProgram "<splice>"+++------------------------------------------------------------------------------+-- | Like 'getOccNameType', but runs in the 'Parser' monad.+getOccTy :: OccName -> Parser Type+getOccTy occ = do+  ParserContext hscenv rdrenv modul _ <- ask+  mty <- liftIO $ getOccNameType hscenv rdrenv modul occ+  maybe (fail $ occNameString occ <> " is not in scope") pure mty+++------------------------------------------------------------------------------+-- | Automatically generate the metaprogram command reference.+writeDocumentation :: IO ()+writeDocumentation =+  writeFile "plugins/hls-tactics-plugin/COMMANDS.md" $+    unlines+      [ "# Wingman Metaprogram Command Reference"+      , ""+      , prettyReadme commands+      ]+
+ src/Wingman/Metaprogramming/Parser/Documentation.hs view
@@ -0,0 +1,228 @@+{-# LANGUAGE OverloadedStrings #-}++module Wingman.Metaprogramming.Parser.Documentation where++import           Data.Functor ((<&>))+import           Data.List (sortOn)+import           Data.String (IsString)+import           Data.Text (Text)+import           Data.Text.Prettyprint.Doc+import           Data.Text.Prettyprint.Doc.Render.String (renderString)+import           GhcPlugins (OccName)+import qualified Text.Megaparsec as P+import           Wingman.Metaprogramming.Lexer (Parser, identifier, variable)+import           Wingman.Types (TacticsM)+++------------------------------------------------------------------------------+-- | Is a tactic deterministic or not?+data Determinism+  = Deterministic+  | Nondeterministic++prettyDeterminism :: Determinism -> Doc b+prettyDeterminism Deterministic = "deterministic"+prettyDeterminism Nondeterministic = "non-deterministic"+++------------------------------------------------------------------------------+-- | How many arguments does the tactic take?+data Count a where+  One  :: Count OccName+  Many :: Count [OccName]++prettyCount :: Count a -> Doc b+prettyCount One  = "single"+prettyCount Many = "varadic"+++------------------------------------------------------------------------------+-- | What sorts of arguments does the tactic take? Currently there is no+-- distincion between 'Ref' and 'Bind', other than documentation.+--+-- The type index here is used for the shape of the function the parser should+-- take.+data Syntax a where+  Nullary :: Syntax (Parser (TacticsM ()))+  Ref     :: Count a -> Syntax (a -> Parser (TacticsM ()))+  Bind    :: Count a -> Syntax (a -> Parser (TacticsM ()))++prettySyntax :: Syntax a -> Doc b+prettySyntax Nullary   = "none"+prettySyntax (Ref co)  = prettyCount co <+> "reference"+prettySyntax (Bind co) = prettyCount co <+> "binding"+++------------------------------------------------------------------------------+-- | An example for the documentation.+data Example = Example+  { ex_ctx    :: Maybe Text         -- ^ Specific context information about when the tactic is applicable+  , ex_args   :: [Var]              -- ^ Arguments the tactic was called with+  , ex_hyp    :: [ExampleHyInfo]    -- ^ The hypothesis+  , ex_goal   :: Maybe ExampleType  -- ^ Current goal. Nothing indicates it's uninteresting.+  , ex_result :: Text               -- ^ Resulting extract.+  }+++------------------------------------------------------------------------------+-- | An example 'HyInfo'.+data ExampleHyInfo = EHI+  { ehi_name :: Var          -- ^ Name of the variable+  , ehi_type :: ExampleType  -- ^ Type of the variable+  }+++------------------------------------------------------------------------------+-- | A variable+newtype Var = Var+  { getVar :: Text+  }+  deriving newtype (IsString, Pretty)+++------------------------------------------------------------------------------+-- | A type+newtype ExampleType = ExampleType+  { getExampleType :: Text+  }+  deriving newtype (IsString, Pretty)+++------------------------------------------------------------------------------+-- | A command to expose to the parser+data MetaprogramCommand a = MC+  { mpc_name        :: Text         -- ^ Name of the command. This is the token necessary to run the command.+  , mpc_syntax      :: Syntax a     -- ^ The command's arguments+  , mpc_det         :: Determinism  -- ^ Determinism of the command+  , mpc_description :: Text         -- ^ User-facing description+  , mpc_tactic      :: a            -- ^ Tactic to run+  , mpc_examples    :: [Example]    -- ^ Collection of documentation examples+  }++------------------------------------------------------------------------------+-- | Existentialize the pain away+data SomeMetaprogramCommand where+  SMC :: MetaprogramCommand a -> SomeMetaprogramCommand+++------------------------------------------------------------------------------+-- | Run the 'Parser' of a 'MetaprogramCommand'+makeMPParser :: MetaprogramCommand a -> Parser (TacticsM ())+makeMPParser (MC name Nullary _ _ tactic _) = do+  identifier name+  tactic+makeMPParser (MC name (Ref One) _ _ tactic _) = do+  identifier name+  variable >>= tactic+makeMPParser (MC name (Ref Many) _ _ tactic _) = do+  identifier name+  P.many variable >>= tactic+makeMPParser (MC name (Bind One) _ _ tactic _) = do+  identifier name+  variable >>= tactic+makeMPParser (MC name (Bind Many) _ _ tactic _) = do+  identifier name+  P.many variable >>= tactic+++------------------------------------------------------------------------------+-- | Compile a collection of metaprogram commands into a parser.+makeParser :: [SomeMetaprogramCommand] -> Parser (TacticsM ())+makeParser ps = P.choice $ ps <&> \(SMC mp) -> makeMPParser mp+++------------------------------------------------------------------------------+-- | Pretty print a command.+prettyCommand :: MetaprogramCommand a -> Doc b+prettyCommand (MC name syn det desc _ exs) = vsep+  [ "##" <+> pretty name+  , mempty+  , "arguments:" <+> prettySyntax syn <> ".  "+  , prettyDeterminism det <> "."+  , mempty+  , ">" <+> align (pretty desc)+  , mempty+  , vsep $ fmap (prettyExample name) exs+  ]+++------------------------------------------------------------------------------+-- | Pretty print a hypothesis.+prettyHyInfo :: ExampleHyInfo -> Doc a+prettyHyInfo hi = pretty (ehi_name hi) <+> "::" <+> pretty (ehi_type hi)+++------------------------------------------------------------------------------+-- | Append the given term only if the first argument has elements.+mappendIfNotNull :: [a] -> a -> [a]+mappendIfNotNull [] _ = []+mappendIfNotNull as a = as <> [a]+++------------------------------------------------------------------------------+-- | Pretty print an example.+prettyExample :: Text -> Example -> Doc a+prettyExample name (Example m_txt args hys goal res) =+  align $ vsep+    [ mempty+    , "### Example"+    , maybe mempty ((line <>) . (<> line) . (">" <+>) . align . pretty) m_txt+    , "Given:"+    , mempty+    , codeFence $ vsep+        $ mappendIfNotNull (fmap prettyHyInfo hys) mempty+           <> [ "_" <+> maybe mempty (("::" <+>). pretty) goal+              ]+    , mempty+    , hsep+        [ "running "+        , enclose "`" "`" $ pretty name <> hsep (mempty : fmap pretty args)+        , "will produce:"+        ]+    , mempty+    , codeFence $ align $ pretty res+    ]+++------------------------------------------------------------------------------+-- | Make a haskell code fence.+codeFence :: Doc a -> Doc a+codeFence d = align $ vsep+  [ "```haskell"+  , d+  , "```"+  ]+++------------------------------------------------------------------------------+-- | Render all of the commands.+prettyReadme :: [SomeMetaprogramCommand] -> String+prettyReadme+  = renderString+  . layoutPretty defaultLayoutOptions+  . vsep+  . fmap (\case SMC c -> prettyCommand c)+  . sortOn (\case SMC c -> mpc_name c)++++------------------------------------------------------------------------------+-- | Helper function to build a 'SomeMetaprogramCommand'.+command+    :: Text+    -> Determinism+    -> Syntax a+    -> Text+    -> a+    -> [Example]+    -> SomeMetaprogramCommand+command txt det syn txt' a exs = SMC $+  MC+    { mpc_name        = txt+    , mpc_det         = det+    , mpc_syntax      = syn+    , mpc_description = txt'+    , mpc_tactic      = a+    , mpc_examples    = exs+    }+
+ src/Wingman/Metaprogramming/ProofState.hs view
@@ -0,0 +1,113 @@+{-# LANGUAGE NamedFieldPuns    #-}+{-# LANGUAGE OverloadedStrings #-}++module Wingman.Metaprogramming.ProofState where++import           Data.Bool (bool)+import           Data.Functor ((<&>))+import qualified Data.Text as T+import           Data.Text.Prettyprint.Doc+import           Data.Text.Prettyprint.Doc.Render.Util.Panic+import           Language.LSP.Types (sectionSeparator)+import           Wingman.Judgements (jHypothesis)+import           Wingman.Types++renderSimplyDecorated+    :: Monoid out+    => (T.Text -> out) -- ^ Render plain 'Text'+    -> (ann -> out)  -- ^ How to render an annotation+    -> (ann -> out)  -- ^ How to render the removed annotation+    -> SimpleDocStream ann+    -> out+renderSimplyDecorated text push pop = go []+  where+    go _        SFail               = panicUncaughtFail+    go []       SEmpty              = mempty+    go (_:_)    SEmpty              = panicInputNotFullyConsumed+    go st       (SChar c rest)      = text (T.singleton c) <> go st rest+    go st       (SText _l t rest)   = text t <> go st rest+    go st       (SLine i rest)      =+      text (T.singleton '\n') <> text (textSpaces i) <> go st rest+    go st       (SAnnPush ann rest) = push ann <> go (ann : st) rest+    go (ann:st) (SAnnPop rest)      = pop ann <> go st rest+    go []       SAnnPop{}           = panicUnpairedPop+{-# INLINE renderSimplyDecorated #-}+++data Ann+  = Goal+  | Hypoth+  | Status+  deriving (Eq, Ord, Show, Enum, Bounded)++forceMarkdownNewlines :: String -> String+forceMarkdownNewlines = unlines . fmap (<> "  ") . lines++layout :: Doc Ann -> String+layout+  = forceMarkdownNewlines+  . T.unpack+  . renderSimplyDecorated id+    renderAnn+    renderUnann+  . layoutPretty (LayoutOptions $ AvailablePerLine 80 0.6)++renderAnn :: Ann -> T.Text+renderAnn Goal = "<span style='color:#ef4026;'>"+renderAnn Hypoth = "```haskell\n"+renderAnn Status = "<span style='color:#6495ED;'>"++renderUnann :: Ann -> T.Text+renderUnann Goal = "</span>"+renderUnann Hypoth = "\n```\n"+renderUnann Status = "</span>"++proofState :: RunTacticResults -> Doc Ann+proofState RunTacticResults{rtr_subgoals} =+  vsep+    $ ( annotate Status+      . countFinished "goals accomplished 🎉" "goal"+      $ length rtr_subgoals+      )+    : pretty sectionSeparator+    : fmap prettySubgoal rtr_subgoals+++prettySubgoal :: Judgement -> Doc Ann+prettySubgoal jdg =+  vsep $+    [ mempty | has_hy] <>+    [ annotate Hypoth $ prettyHypothesis hy | has_hy] <>+    [ "⊢" <+> annotate Goal (prettyType (_jGoal jdg))+    , pretty sectionSeparator+    ]+  where+    hy = jHypothesis jdg+    has_hy = not $ null $ unHypothesis hy+++prettyHypothesis :: Hypothesis CType -> Doc Ann+prettyHypothesis hy =+  vsep $ unHypothesis hy <&> \hi ->+    prettyHyInfo hi++prettyHyInfo :: HyInfo CType -> Doc Ann+prettyHyInfo hi = viaShow (hi_name hi) <+> "::" <+> prettyType (hi_type hi)+++prettyType :: CType -> Doc Ann+prettyType (CType ty) = viaShow ty+++countFinished :: Doc Ann -> Doc Ann -> Int -> Doc Ann+countFinished finished _ 0 = finished+countFinished _ thing n    = count thing n++count :: Doc Ann -> Int -> Doc Ann+count thing n =+  pretty n <+> thing <> bool "" "s" (n /= 1)++textSpaces :: Int -> T.Text+textSpaces n = T.replicate n $ T.singleton ' '++
src/Wingman/Naming.hs view
@@ -1,61 +1,207 @@ module Wingman.Naming where +import           Control.Arrow import           Control.Monad.State.Strict+import           Data.Aeson (camelTo2) import           Data.Bool (bool) import           Data.Char+import           Data.List (isPrefixOf)+import           Data.List.Extra (split) import           Data.Map (Map) import qualified Data.Map as M+import           Data.Maybe (listToMaybe, fromMaybe)+import           Data.Monoid import           Data.Set (Set) import qualified Data.Set as S import           Data.Traversable+import           GhcPlugins (charTy, maybeTyCon) import           Name import           TcType+import           Text.Hyphenation (hyphenate, english_US) import           TyCon import           Type-import           TysWiredIn (listTyCon, pairTyCon, unitTyCon)+import           TysWiredIn (listTyCon, unitTyCon)+import           Wingman.GHC (tcTyVar_maybe)   --------------------------------------------------------------------------------- | Use type information to create a reasonable name.-mkTyName :: Type -> String--- eg. mkTyName (a -> B) = "fab"-mkTyName (tcSplitFunTys -> ([a@(isFunTy -> False)], b))-  = "f" ++ mkTyName a ++ mkTyName b--- eg. mkTyName (a -> b -> C) = "f_C"-mkTyName (tcSplitFunTys -> (_:_, b))-  = "f_" ++ mkTyName b--- eg. mkTyName (Either A B) = "eab"-mkTyName (splitTyConApp_maybe -> Just (c, args))-  = mkTyConName c ++ foldMap mkTyName args--- eg. mkTyName (f a) = "fa"-mkTyName (tcSplitAppTys -> (t, args@(_:_)))-  = mkTyName t ++ foldMap mkTyName args--- eg. mkTyName a = "a"-mkTyName (getTyVar_maybe -> Just tv)-  = occNameString $ occName tv--- eg. mkTyName (forall x. y) = "y"-mkTyName (tcSplitSigmaTy -> (_:_, _, t))-  = mkTyName t-mkTyName _ = "x"+-- | A classification of a variable, for which we have specific naming rules.+-- A variable can have multiple purposes simultaneously.+data Purpose+  = Function [Type] Type+  | Predicate+  | Continuation+  | Integral+  | Number+  | String+  | List Type+  | Maybe Type+  | TyConned TyCon [Type]+    -- ^ Something of the form @TC a b c@+  | TyVarred TyVar [Type]+    -- ^ Something of the form @m a b c@ +pattern IsPredicate :: Type+pattern IsPredicate <-+  (tcSplitFunTys -> ([isFunTy -> False], isBoolTy -> True)) +pattern IsFunction :: [Type] -> Type -> Type+pattern IsFunction args res <-+  (tcSplitFunTys -> (args@(_:_), res))++pattern IsString :: Type+pattern IsString <-+  (splitTyConApp_maybe -> Just ((== listTyCon) -> True, [eqType charTy -> True]))++pattern IsMaybe :: Type -> Type+pattern IsMaybe a <-+  (splitTyConApp_maybe -> Just ((== maybeTyCon) -> True, [a]))++pattern IsList :: Type -> Type+pattern IsList a <-+  (splitTyConApp_maybe -> Just ((== listTyCon) -> True, [a]))++pattern IsTyConned :: TyCon -> [Type] -> Type+pattern IsTyConned tc args <-+  (splitTyConApp_maybe -> Just (id &&& isSymOcc . getOccName -> (tc, False), args))++pattern IsTyVarred :: TyVar -> [Type] -> Type+pattern IsTyVarred v args <-+  (tcSplitAppTys -> (tcTyVar_maybe -> Just v, args))++ ------------------------------------------------------------------------------+-- | Get the 'Purpose's of a type. A type can have multiple purposes+-- simultaneously, so the order of purposes in this function corresponds to the+-- precedence of that naming rule. Which means, eg, that if a type is both+-- a 'Predicate' and a 'Function', we should prefer to use the predicate naming+-- rules, since they come first.+getPurposes :: Type -> [Purpose]+getPurposes ty = mconcat+  [ [ Predicate         | IsPredicate         <- [ty] ]+  , [ Function args res | IsFunction args res <- [ty] ]+  , with (isIntegerTy ty) [ Integral, Number          ]+  , with (isIntTy ty)     [ Integral, Number          ]+  , [ Number            | isFloatingTy ty             ]+  , [ String            | isStringTy ty               ]+  , [ Maybe a           | IsMaybe a           <- [ty] ]+  , [ List a            | IsList a            <- [ty] ]+  , [ TyVarred v args   | IsTyVarred v args   <- [ty] ]+  , [ TyConned tc args  | IsTyConned tc args  <- [ty]+                        , not (isTupleTyCon tc)+                        , tc /= listTyCon             ]+  ]+++------------------------------------------------------------------------------+-- | Return 'mempty' if the give bool is false.+with :: Monoid a => Bool -> a -> a+with False _ = mempty+with True a = a+++------------------------------------------------------------------------------+-- | Names we can give functions+functionNames :: [String]+functionNames = ["f", "g", "h"]+++------------------------------------------------------------------------------+-- | Get a ranked ordering of names for a given purpose.+purposeToName :: Purpose -> [String]+purposeToName (Function args res)+  | Just tv_args <- traverse tcTyVar_maybe $ args <> pure res+  = fmap (<> foldMap (occNameString . occName) tv_args) functionNames+purposeToName (Function _ _) = functionNames+purposeToName Predicate = pure "p"+purposeToName Continuation = pure "k"+purposeToName Integral = ["n", "i", "j"]+purposeToName Number = ["x", "y", "z", "w"]+purposeToName String = ["s", "str"]+purposeToName (List t) = fmap (<> "s") $ purposeToName =<< getPurposes t+purposeToName (Maybe t) = fmap ("m_" <>) $ purposeToName =<< getPurposes t+purposeToName (TyVarred tv args)+  | Just tv_args <- traverse tcTyVar_maybe args+  = pure $ foldMap (occNameString . occName) $ tv : tv_args+purposeToName (TyVarred tv _) = pure $ occNameString $ occName tv+purposeToName (TyConned tc args@(_:_))+  | Just tv_args <- traverse tcTyVar_maybe args+  = [ mkTyConName tc+      -- We insert primes to everything later, but it gets the lowest+      -- precedence. Here we'd like to prefer it over the more specific type+      -- name.+    , mkTyConName tc <> "'"+    , mconcat+      [ mkTyConName tc+      , bool mempty "_" $ length (mkTyConName tc) > 1+      , foldMap (occNameString . occName) tv_args+      ]+    ]+purposeToName (TyConned tc _)+  = pure+  $ mkTyConName tc+++mkTyName :: Type -> [String]+mkTyName = purposeToName <=< getPurposes+++------------------------------------------------------------------------------ -- | Get a good name for a type constructor. mkTyConName :: TyCon -> String mkTyConName tc-  | tc == listTyCon = "l_"-  | tc == pairTyCon = "p_"-  | tc == unitTyCon = "unit"-  | otherwise+  | tc == unitTyCon = "u"+  | isSymOcc occ       = take 1       . fmap toLower       . filterReplace isSymbol      's'       . filterReplace isPunctuation 'p'-      . occNameString-      $ getOccName tc+      $ name+  | camels@(_:_:_) <- camelTerms name+      = foldMap (fmap toLower . take 1) camels+  | otherwise+      = getStem+      $ fmap toLower+      $ name+  where+    occ = getOccName tc+    name = occNameString occ   ------------------------------------------------------------------------------+-- | Split a string into its camel case components.+camelTerms :: String -> [String]+camelTerms = split (== '@') . camelTo2 '@'+++------------------------------------------------------------------------------+-- | A stem of a string is either a special-case shortened form, or a shortened+-- first syllable. If the string is one syllable, we take the full word if it's+-- short, or just the first two characters if it's long. Otherwise, just take+-- the first syllable.+--+-- NOTE: There's no rhyme or reason here, I just experimented until I got+-- results that were reasonably consistent with the names I would give things.+getStem :: String -> String+getStem str =+  let s = stem str+   in case (s == str, length str) of+        (False, _)             -> s+        (True, (<= 3) -> True) -> str+        _                      -> take 2 str++------------------------------------------------------------------------------+-- | Get a special-case stem, or, failing that, give back the first syllable.+stem :: String -> String+stem "char" = "c"+stem "function" = "func"+stem "bool" = "b"+stem "either" = "e"+stem "text" = "txt"+stem s = join $ take 1 $ hyphenate english_US s+++------------------------------------------------------------------------------ -- | Maybe replace an element in the list if the predicate matches filterReplace :: (a -> Bool) -> a -> [a] -> [a] filterReplace f r = fmap (\a -> bool a r $ f a)@@ -67,22 +213,34 @@     :: Set OccName  -- ^ Bindings in scope; used to ensure we don't shadow anything     -> Type       -- ^ The type to produce a name for     -> OccName-mkGoodName in_scope t =-  let tn = mkTyName t-   in mkVarOcc $ case S.member (mkVarOcc tn) in_scope of-        True  -> tn ++ show (length in_scope)-        False -> tn+mkGoodName in_scope (mkTyName -> tn)+  = mkVarOcc+  . fromMaybe (mkNumericSuffix in_scope $ fromMaybe "x" $ listToMaybe tn)+  . getFirst+  . foldMap (\n -> bool (pure n) mempty $ check n)+  $ tn <> fmap (<> "'") tn+  where+    check n = S.member (mkVarOcc n) in_scope   ------------------------------------------------------------------------------+-- | Given a desired name, compute a new name for it based on how many names in+-- scope conflict with it. Eg, if we want to name something @x@, but already+-- have @x@, @x'@ and @x2@ in scope, we will give back @x3@.+mkNumericSuffix :: Set OccName -> String -> String+mkNumericSuffix s nm =+  mappend nm . show . length . filter (isPrefixOf nm . occNameString) $ S.toList s+++------------------------------------------------------------------------------ -- | Like 'mkGoodName' but creates several apart names. mkManyGoodNames-  :: (Traversable t, Monad m)+  :: (Traversable t)   => Set OccName   -> t Type-  -> m (t OccName)+  -> t OccName mkManyGoodNames in_scope args =-  flip evalStateT in_scope $ for args $ \at -> do+  flip evalState in_scope $ for args $ \at -> do     in_scope <- get     let n = mkGoodName in_scope at     modify $ S.insert n
src/Wingman/Plugin.hs view
@@ -1,4 +1,5 @@ {-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE RecordWildCards #-}  -- | A plugin that uses tactics to synthesize code module Wingman.Plugin@@ -12,7 +13,6 @@ import           Control.Monad.Trans import           Control.Monad.Trans.Maybe import           Data.Aeson-import           Data.Bifunctor (first) import           Data.Data import           Data.Foldable (for_) import           Data.Maybe@@ -21,6 +21,7 @@ import           Development.IDE.Core.UseStale (Tracked, TrackedStale(..), unTrack, mapAgeFrom, unsafeMkCurrent) import           Development.IDE.GHC.Compat import           Development.IDE.GHC.ExactPrint+import           Generics.SYB.GHC import           Ide.Types import           Language.LSP.Server import           Language.LSP.Types@@ -29,29 +30,44 @@ import           Prelude hiding (span) import           System.Timeout import           Wingman.CaseSplit+import           Wingman.EmptyCase import           Wingman.GHC import           Wingman.LanguageServer+import           Wingman.LanguageServer.Metaprogram (hoverProvider) import           Wingman.LanguageServer.TacticProviders import           Wingman.Machinery (scoreSolution) import           Wingman.Range+import           Wingman.StaticPlugin import           Wingman.Tactics import           Wingman.Types+import Wingman.Metaprogramming.Lexer (ParserContext)   descriptor :: PluginId -> PluginDescriptor IdeState descriptor plId = (defaultPluginDescriptor plId)   { pluginCommands-      = fmap (\tc ->-          PluginCommand-            (tcCommandId tc)-            (tacticDesc $ tcCommandName tc)-            (tacticCmd (commandTactic tc) plId))-            [minBound .. maxBound]-  , pluginHandlers =-      mkPluginHandler STextDocumentCodeAction codeActionProvider+      = mconcat+          [ fmap (\tc ->+              PluginCommand+                (tcCommandId tc)+                (tacticDesc $ tcCommandName tc)+                (tacticCmd (flip commandTactic tc) plId))+                [minBound .. maxBound]+          , pure $+              PluginCommand+              emptyCaseLensCommandId+              "Complete the empty case"+              workspaceEditHandler+          ]+  , pluginHandlers = mconcat+      [ mkPluginHandler STextDocumentCodeAction codeActionProvider+      , mkPluginHandler STextDocumentCodeLens codeLensProvider+      , mkPluginHandler STextDocumentHover hoverProvider+      ]   , pluginRules = wingmanRules plId-  , pluginCustomConfig =-      mkCustomConfig properties+  , pluginConfigDescriptor =+      defaultConfigDescriptor {configCustomConfig = mkCustomConfig properties}+  , pluginModifyDynflags = staticPlugin   }  @@ -60,16 +76,17 @@   | Just nfp <- uriToNormalizedFilePath $ toNormalizedUri uri = do       cfg <- getTacticConfig plId       liftIO $ fromMaybeT (Right $ List []) $ do-        (_, jdg, _, dflags) <- judgementForHole state nfp range $ cfg_feature_set cfg+        HoleJudgment{..} <- judgementForHole state nfp range cfg         actions <- lift $           -- This foldMap is over the function monoid.           foldMap commandProvider [minBound .. maxBound] $ TacticProviderData-            { tpd_dflags = dflags+            { tpd_dflags = hj_dflags             , tpd_config = cfg             , tpd_plid   = plId             , tpd_uri    = uri             , tpd_range  = range-            , tpd_jdg    = jdg+            , tpd_jdg    = hj_jdg+            , tpd_hole_sort = hj_hole_sort             }         pure $ Right $ List actions codeActionProvider _ _ _ = pure $ Right $ List []@@ -84,26 +101,34 @@   pure $ Left $ mkErr InternalError $ T.pack $ show ufm  -tacticCmd :: (OccName -> TacticsM ()) -> PluginId -> CommandFunction IdeState TacticParams+tacticCmd+    :: (ParserContext -> T.Text -> IO (TacticsM ()))+    -> PluginId+    -> CommandFunction IdeState TacticParams tacticCmd tac pId state (TacticParams uri range var_name)   | Just nfp <- uriToNormalizedFilePath $ toNormalizedUri uri = do-      features <- getFeatureSet pId+      let stale a = runStaleIde "tacticCmd" state nfp a+       ccs <- getClientCapabilities       cfg <- getTacticConfig pId       res <- liftIO $ runMaybeT $ do-        (range', jdg, ctx, dflags) <- judgementForHole state nfp range features-        let span = fmap (rangeToRealSrcSpan (fromNormalizedFilePath nfp)) range'-        TrackedStale pm pmmap <- runStaleIde state nfp GetAnnotatedParsedSource+        HoleJudgment{..} <- judgementForHole state nfp range cfg+        let span = fmap (rangeToRealSrcSpan (fromNormalizedFilePath nfp)) hj_range+        TrackedStale pm pmmap <- stale GetAnnotatedParsedSource         pm_span <- liftMaybe $ mapAgeFrom pmmap span+        pc <- getParserState state nfp hj_ctx+        t <- liftIO $ tac pc var_name          timingOut (cfg_timeout_seconds cfg * seconds) $ join $-          case runTactic ctx jdg $ tac $ mkVarOcc $ T.unpack var_name of-            Left _ -> Left TacticErrors+          case runTactic hj_ctx hj_jdg t of+            Left errs ->  do+              traceMX "errs" errs+              Left TacticErrors             Right rtr ->               case rtr_extract rtr of                 L _ (HsVar _ (L _ rdr)) | isHole (occName rdr) ->                   Left NothingToDo-                _ -> pure $ mkWorkspaceEdits pm_span dflags ccs uri pm rtr+                _ -> pure $ mkTacticResultEdits pm_span hj_dflags ccs uri pm rtr        case res of         Nothing -> do@@ -140,7 +165,7 @@ ------------------------------------------------------------------------------ -- | Turn a 'RunTacticResults' into concrete edits to make in the source -- document.-mkWorkspaceEdits+mkTacticResultEdits     :: Tracked age RealSrcSpan     -> DynFlags     -> ClientCapabilities@@ -148,14 +173,12 @@     -> Tracked age (Annotated ParsedSource)     -> RunTacticResults     -> Either UserFacingMessage WorkspaceEdit-mkWorkspaceEdits (unTrack -> span) dflags ccs uri (unTrack -> pm) rtr = do+mkTacticResultEdits (unTrack -> span) dflags ccs uri (unTrack -> pm) rtr = do   for_ (rtr_other_solns rtr) $ \soln -> do     traceMX "other solution" $ syn_val soln     traceMX "with score" $ scoreSolution soln (rtr_jdg rtr) []   traceMX "solution" $ rtr_extract rtr-  let g = graftHole (RealSrcSpan span) rtr-      response = transform dflags ccs uri g pm-   in first (InfrastructureError . T.pack) response+  mkWorkspaceEdits dflags ccs uri pm $ graftHole (RealSrcSpan span) rtr   ------------------------------------------------------------------------------@@ -209,8 +232,4 @@           pure alts         _ -> lift $ Left "annotateDecl didn't produce a funbind" graftDecl _ _ _ _ x = pure $ pure x---fromMaybeT :: Functor m => a -> MaybeT m a -> m a-fromMaybeT def = fmap (fromMaybe def) . runMaybeT 
src/Wingman/Simplify.hs view
@@ -11,7 +11,7 @@ import GHC.SourceGen (var) import GHC.SourceGen.Expr (lambda) import Wingman.CodeGen.Utils-import Wingman.GHC (containsHsVar, fromPatCompat)+import Wingman.GHC (containsHsVar, fromPatCompat, pattern SingleLet)   ------------------------------------------------------------------------------@@ -30,6 +30,7 @@     Lambda pats body = lambda pats body  + ------------------------------------------------------------------------------ -- | Simlify an expression. simplify :: LHsExpr GhcPs -> LHsExpr GhcPs@@ -41,6 +42,7 @@     [ simplifyEtaReduce     , simplifyRemoveParens     , simplifyCompose+    , simplifySingleLet     ])  @@ -66,6 +68,13 @@         -- We can only perform this simplifiation if @pat@ is otherwise unused.       , not (containsHsVar pat f) ->     Lambda pats f+  x -> x++------------------------------------------------------------------------------+-- | Eliminates the unnecessary binding in @let a = b in a@+simplifySingleLet :: GenericT+simplifySingleLet = mkT $ \case+  SingleLet bind [] val (HsVar _ (L _ a)) | a == bind -> val   x -> x  
+ src/Wingman/StaticPlugin.hs view
@@ -0,0 +1,96 @@+{-# LANGUAGE CPP #-}++module Wingman.StaticPlugin+  ( staticPlugin+  , metaprogramHoleName+  , pattern WingmanMetaprogram+  , pattern MetaprogramSyntax+  ) where++import Data.Data+import Development.IDE.GHC.Compat+import GHC.LanguageExtensions.Type (Extension(EmptyCase, QuasiQuotes))+import Generics.SYB+import GhcPlugins hiding ((<>))+import Ide.Types+++staticPlugin :: DynFlagsModifications+staticPlugin = mempty+  { dynFlagsModifyGlobal =+      \df -> allowEmptyCaseButWithWarning+           $ df+#if __GLASGOW_HASKELL__ >= 808+             { staticPlugins = staticPlugins df <> [metaprogrammingPlugin] }+  , dynFlagsModifyParser = enableQuasiQuotes+#endif+  }+++pattern MetaprogramSourceText :: SourceText+pattern MetaprogramSourceText = SourceText "wingman-meta-program"++++pattern WingmanMetaprogram :: FastString -> HsExpr p+pattern WingmanMetaprogram mp+  <- HsSCC _ MetaprogramSourceText (StringLiteral NoSourceText mp)+      (L _ ( HsVar _ _))+++enableQuasiQuotes :: DynFlags -> DynFlags+enableQuasiQuotes = flip xopt_set QuasiQuotes+++-- | Wingman wants to support destructing of empty cases, but these are a parse+-- error by default. So we want to enable 'EmptyCase', but then that leads to+-- silent errors without 'Opt_WarnIncompletePatterns'.+allowEmptyCaseButWithWarning :: DynFlags -> DynFlags+allowEmptyCaseButWithWarning =+  flip xopt_set EmptyCase . flip wopt_set Opt_WarnIncompletePatterns+++#if __GLASGOW_HASKELL__ >= 808+metaprogrammingPlugin :: StaticPlugin+metaprogrammingPlugin =+    StaticPlugin $ PluginWithArgs (defaultPlugin { parsedResultAction = worker })  []+  where+    worker :: [CommandLineOption] -> ModSummary -> HsParsedModule -> Hsc HsParsedModule+    worker _ _ pm = pure $ pm { hpm_module = addMetaprogrammingSyntax $ hpm_module pm }+#endif++metaprogramHoleName :: OccName+metaprogramHoleName = mkVarOcc "_$metaprogram"+++mkMetaprogram :: SrcSpan -> FastString -> HsExpr GhcPs+mkMetaprogram ss mp =+  HsSCC noExtField MetaprogramSourceText (StringLiteral NoSourceText mp)+    $ L ss+    $ HsVar noExtField+    $ L ss+    $ mkRdrUnqual+    $ metaprogramHoleName+++addMetaprogrammingSyntax :: Data a => a -> a+addMetaprogrammingSyntax =+  everywhere $ mkT $ \case+    L ss (MetaprogramSyntax mp) ->+      L ss $ mkMetaprogram ss mp+    (x :: LHsExpr GhcPs) -> x+++pattern MetaprogramSyntax :: FastString -> HsExpr GhcPs+pattern MetaprogramSyntax mp <-+    HsSpliceE _ (HsQuasiQuote _ _ (occNameString . rdrNameOcc -> "wingman") _ mp)+  where+    MetaprogramSyntax mp =+      HsSpliceE noExtField $+        HsQuasiQuote+          noExtField+          (mkRdrUnqual $ mkVarOcc "splice")+          (mkRdrUnqual $ mkVarOcc "wingman")+          noSrcSpan+          mp+
src/Wingman/Tactics.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE OverloadedStrings #-}+ module Wingman.Tactics   ( module Wingman.Tactics   , runTactic@@ -9,7 +11,8 @@ import           Control.Monad (unless) import           Control.Monad.Except (throwError) import           Control.Monad.Reader.Class (MonadReader (ask))-import           Control.Monad.State.Strict (StateT(..), runStateT)+import           Control.Monad.State.Strict (StateT(..), runStateT, gets)+import           Data.Bool (bool) import           Data.Foldable import           Data.Functor ((<&>)) import           Data.Generics.Labels ()@@ -21,18 +24,22 @@ import           DataCon import           Development.IDE.GHC.Compat import           GHC.Exts+import           GHC.SourceGen ((@@)) import           GHC.SourceGen.Expr import           Name (occNameString, occName)+import           OccName (mkVarOcc) import           Refinery.Tactic import           Refinery.Tactic.Internal import           TcType import           Type hiding (Var)+import           TysPrim (betaTy, alphaTy, betaTyVar, alphaTyVar) import           Wingman.CodeGen import           Wingman.Context import           Wingman.GHC import           Wingman.Judgements import           Wingman.Machinery import           Wingman.Naming+import           Wingman.StaticPlugin (pattern MetaprogramSyntax) import           Wingman.Types  @@ -76,7 +83,8 @@       unless (any (flip M.member pat_vals) $ syn_used_vals ext) empty      let hy' = recursiveHypothesis defs-    localTactic (apply $ HyInfo name RecursivePrv ty) (introduce hy')+    ctx <- ask+    localTactic (apply $ HyInfo name RecursivePrv ty) (introduce ctx hy')       <@> fmap (localTactic assumption . filterPosition name) [0..]  @@ -93,17 +101,26 @@ ------------------------------------------------------------------------------ -- | Introduce a lambda binding every variable. intros :: TacticsM ()-intros = rule $ \jdg -> do+intros = intros' Nothing++------------------------------------------------------------------------------+-- | Introduce a lambda binding every variable.+intros'+    :: Maybe [OccName]  -- ^ When 'Nothing', generate a new name for every+                        -- variable. Otherwise, only bind the variables named.+    -> TacticsM ()+intros' names = rule $ \jdg -> do   let g  = jGoal jdg-  ctx <- ask-  case tcSplitFunTys $ unCType g of-    ([], _) -> throwError $ GoalMismatch "intros" g-    (as, b) -> do-      vs <- mkManyGoodNames (hyNamesInScope $ jEntireHypothesis jdg) as-      let top_hole = isTopHole ctx jdg+  case tacticsSplitFunTy $ unCType g of+    (_, _, [], _) -> throwError $ GoalMismatch "intros" g+    (_, _, as, b) -> do+      ctx <- ask+      let vs = fromMaybe (mkManyGoodNames (hyNamesInScope $ jEntireHypothesis jdg) as) names+          num_args = length vs+          top_hole = isTopHole ctx jdg           hy' = lambdaHypothesis top_hole $ zip vs $ coerce as-          jdg' = introduce hy'-               $ withNewGoal (CType b) jdg+          jdg' = introduce ctx hy'+               $ withNewGoal (CType $ mkFunTys' (drop num_args as) b) jdg       ext <- newSubgoal jdg'       pure $         ext@@ -142,9 +159,9 @@       ty = unCType $ hi_type hi    attemptWhen-      (rule $ destruct' (\dc jdg ->+      (rule $ destruct' False (\dc jdg ->         buildDataCon False jdg dc $ snd $ splitAppTys g) hi)-      (rule $ destruct' (const subgoal) hi)+      (rule $ destruct' False (const newSubgoal) hi)     $ case (splitTyConApp_maybe g, splitTyConApp_maybe ty) of         (Just (gtc, _), Just (tytc, _)) -> gtc == tytc         _ -> False@@ -154,20 +171,28 @@ -- | Case split, and leave holes in the matches. destruct :: HyInfo CType -> TacticsM () destruct hi = requireConcreteHole $ tracing "destruct(user)" $-  rule $ destruct' (const subgoal) hi+  rule $ destruct' False (const newSubgoal) hi   ------------------------------------------------------------------------------+-- | Case split, and leave holes in the matches. Performs record punning.+destructPun :: HyInfo CType -> TacticsM ()+destructPun hi = requireConcreteHole $ tracing "destructPun(user)" $+  rule $ destruct' True (const newSubgoal) hi+++------------------------------------------------------------------------------ -- | Case split, using the same data constructor in the matches. homo :: HyInfo CType -> TacticsM ()-homo = requireConcreteHole . tracing "homo" . rule . destruct' (\dc jdg ->+homo = requireConcreteHole . tracing "homo" . rule . destruct' False (\dc jdg ->   buildDataCon False jdg dc $ snd $ splitAppTys $ unCType $ jGoal jdg)   ------------------------------------------------------------------------------ -- | LambdaCase split, and leave holes in the matches. destructLambdaCase :: TacticsM ()-destructLambdaCase = tracing "destructLambdaCase" $ rule $ destructLambdaCase' (const subgoal)+destructLambdaCase =+  tracing "destructLambdaCase" $ rule $ destructLambdaCase' False (const newSubgoal)   ------------------------------------------------------------------------------@@ -175,7 +200,7 @@ homoLambdaCase :: TacticsM () homoLambdaCase =   tracing "homoLambdaCase" $-    rule $ destructLambdaCase' $ \dc jdg ->+    rule $ destructLambdaCase' False $ \dc jdg ->       buildDataCon False jdg dc         . snd         . splitAppTys@@ -184,7 +209,7 @@   apply :: HyInfo CType -> TacticsM ()-apply hi = requireConcreteHole $ tracing ("apply' " <> show (hi_name hi)) $ do+apply hi = tracing ("apply' " <> show (hi_name hi)) $ do   jdg <- goal   let g  = jGoal jdg       ty = unCType $ hi_type hi@@ -205,7 +230,10 @@         & #syn_used_vals %~ S.insert func         & #syn_val       %~ mkApply func . fmap unLoc +application :: TacticsM ()+application = overFunctions apply + ------------------------------------------------------------------------------ -- | Choose between each of the goal's data constructors. split :: TacticsM ()@@ -247,8 +275,26 @@       splitDataCon dc     _ -> throwError $ GoalMismatch "splitSingle" g +------------------------------------------------------------------------------+-- | Like 'split', but prunes any data constructors which have holes.+obvious :: TacticsM ()+obvious = tracing "obvious" $ do+  pruning split $ bool (Just NoProgress) Nothing . null + ------------------------------------------------------------------------------+-- | Sorry leaves a hole in its extract+sorry :: TacticsM ()+sorry = exact $ var' $ mkVarOcc "_"+++------------------------------------------------------------------------------+-- | Sorry leaves a hole in its extract+metaprogram :: TacticsM ()+metaprogram = exact $ MetaprogramSyntax ""+++------------------------------------------------------------------------------ -- | Allow the given tactic to proceed if and only if it introduces holes that -- have a different goal than current goal. requireNewHoles :: TacticsM () -> TacticsM ()@@ -290,7 +336,7 @@ destructAll = do   jdg <- goal   let args = fmap fst-           $ sortOn (Down . snd)+           $ sortOn snd            $ mapMaybe (\(hi, prov) ->               case prov of                 TopLevelArgPrv _ idx _ -> pure (hi, idx)@@ -300,7 +346,9 @@            $ filter (isAlgType . unCType . hi_type)            $ unHypothesis            $ jHypothesis jdg-  for_ args destruct+  for_ args $ \arg -> do+    subst <- gets ts_unifier+    destruct $ fmap (coerce substTy subst) arg  -------------------------------------------------------------------------------- -- | User-facing tactic to implement "Use constructor <x>"@@ -338,10 +386,7 @@   refine :: TacticsM ()-refine = do-  try' intros-  try' splitSingle-  try' intros+refine = intros <%> splitSingle   auto' :: Int -> TacticsM ()@@ -351,7 +396,7 @@   try intros   choice     [ overFunctions $ \fname -> do-        apply fname+        requireConcreteHole $ apply fname         loop     , overAlgebraicTerms $ \aname -> do         destructAuto aname@@ -394,4 +439,75 @@       True  -> apply hi       False -> empty ++------------------------------------------------------------------------------+-- | Make a function application where the function being applied itself is+-- a hole.+applyByType :: Type -> TacticsM ()+applyByType ty = tracing ("applyByType " <> show ty) $ do+  jdg <- goal+  let g  = jGoal jdg+  ty' <- freshTyvars ty+  let (_, _, args, ret) = tacticsSplitFunTy ty'+  rule $ \jdg -> do+    unify g (CType ret)+    ext+        <- fmap unzipTrace+        $ traverse ( newSubgoal+                    . blacklistingDestruct+                    . flip withNewGoal jdg+                    . CType+                    ) args+    app <- newSubgoal . blacklistingDestruct $ withNewGoal (CType ty) jdg+    pure $+      fmap noLoc $+        foldl' (@@)+          <$> fmap unLoc app+          <*> fmap (fmap unLoc) ext+++------------------------------------------------------------------------------+-- | Make an n-ary function call of the form+-- @(_ :: forall a b. a -> a -> b) _ _@.+nary :: Int -> TacticsM ()+nary n =+  applyByType $+    mkInvForAllTys [alphaTyVar, betaTyVar] $+      mkFunTys' (replicate n alphaTy) betaTy++self :: TacticsM ()+self =+  fmap listToMaybe getCurrentDefinitions >>= \case+    Just (self, _) -> useNameFromContext apply self+    Nothing -> throwError $ TacticPanic "no defining function"+++cata :: HyInfo CType -> TacticsM ()+cata hi = do+  diff <- hyDiff $ destruct hi+  rule $+    letForEach+      (mkVarOcc . flip mappend "_c" . occNameString)+      (\hi -> self >> commit (apply hi) assumption)+      diff++collapse :: TacticsM ()+collapse = do+  g <- goal+  let terms = unHypothesis $ hyFilter ((jGoal g ==) . hi_type) $ jLocalHypothesis g+  case terms of+    [hi] -> assume $ hi_name hi+    _    -> nary (length terms) <@> fmap (assume . hi_name) terms+++------------------------------------------------------------------------------+-- | Determine the difference in hypothesis due to running a tactic. Also, it+-- runs the tactic.+hyDiff :: TacticsM () -> TacticsM (Hypothesis CType)+hyDiff m = do+  g <- unHypothesis . jEntireHypothesis <$> goal+  let g_len = length g+  m+  g' <- unHypothesis . jEntireHypothesis <$> goal+  pure $ Hypothesis $ take (length g' - g_len) g' 
src/Wingman/Types.hs view
@@ -26,8 +26,11 @@ import           Data.Text (Text) import qualified Data.Text as T import           Data.Tree+import           Development.IDE (Range)+import           Development.IDE.Core.UseStale import           Development.IDE.GHC.Compat hiding (Node) import           Development.IDE.GHC.Orphans ()+import           FamInstEnv (FamInstEnvs) import           GHC.Generics import           GHC.SourceGen (var) import           InstEnv (InstEnvs(..))@@ -38,7 +41,6 @@ import           UniqSupply (takeUniqFromSupply, mkSplitUniqSupply, UniqSupply) import           Unique (nonDetCmpUnique, Uniquable, getUnique, Unique) import           Wingman.Debug-import           Wingman.FeatureSet   ------------------------------------------------------------------------------@@ -49,12 +51,15 @@   = Auto   | Intros   | Destruct+  | DestructPun   | Homomorphism   | DestructLambdaCase   | HomomorphismLambdaCase   | DestructAll   | UseDataCon   | Refine+  | BeginMetaprogram+  | RunMetaprogram   deriving (Eq, Ord, Show, Enum, Bounded)  -- | Generate a title for the command.@@ -64,22 +69,33 @@     go Auto _                   = "Attempt to fill hole"     go Intros _                 = "Introduce lambda"     go Destruct var             = "Case split on " <> var+    go DestructPun var          = "Split on " <> var <> " with NamedFieldPuns"     go Homomorphism var         = "Homomorphic case split on " <> var     go DestructLambdaCase _     = "Lambda case split"     go HomomorphismLambdaCase _ = "Homomorphic lambda case split"     go DestructAll _            = "Split all function arguments"     go UseDataCon dcon          = "Use constructor " <> dcon     go Refine _                 = "Refine hole"+    go BeginMetaprogram _       = "Use custom tactic block"+    go RunMetaprogram _         = "Run custom tactic"   ------------------------------------------------------------------------------ -- | Plugin configuration for tactics data Config = Config-  { cfg_feature_set          :: FeatureSet-  , cfg_max_use_ctor_actions :: Int+  { cfg_max_use_ctor_actions :: Int   , cfg_timeout_seconds      :: Int+  , cfg_auto_gas             :: Int   }+  deriving (Eq, Ord, Show) +emptyConfig :: Config+emptyConfig = Config+  { cfg_max_use_ctor_actions = 5+  , cfg_timeout_seconds = 2+  , cfg_auto_gas = 4+  }+ ------------------------------------------------------------------------------ -- | A wrapper around 'Type' which supports equality and ordering. newtype CType = CType { unCType :: Type }@@ -117,6 +133,9 @@ instance Show (HsExpr GhcPs) where   show  = unsafeRender +instance Show (HsExpr GhcTc) where+  show  = unsafeRender+ instance Show (HsDecl GhcPs) where   show  = unsafeRender @@ -191,6 +210,8 @@       (Uniquely Class)     -- ^ Class     -- | A binding explicitly written by the user.   | UserPrv+    -- | A binding explicitly imported by the user.+  | ImportPrv     -- | The recursive hypothesis. Present only in the context of the recursion     -- tactic.   | RecursivePrv@@ -305,6 +326,7 @@   | UnhelpfulSplit OccName   | TooPolymorphic   | NotInScope OccName+  | TacticPanic String   deriving stock (Eq)  instance Show TacticError where@@ -343,6 +365,8 @@       "The tactic isn't applicable because the goal is too polymorphic"     show (NotInScope name) =       "Tried to do something with the out of scope name " <> show name+    show (TacticPanic err) =+      "PANIC: " <> err   ------------------------------------------------------------------------------@@ -393,9 +417,10 @@     -- ^ The functions currently being defined   , ctxModuleFuncs   :: [(OccName, CType)]     -- ^ Everything defined in the current module-  , ctxFeatureSet    :: FeatureSet+  , ctxConfig        :: Config   , ctxKnownThings   :: KnownThings   , ctxInstEnvs      :: InstEnvs+  , ctxFamInstEnvs   :: FamInstEnvs   , ctxTheta         :: Set CType   } @@ -404,7 +429,7 @@     [ "Context "     , showsPrec 10 ctxDefiningFuncs ""     , showsPrec 10 ctxModuleFuncs ""-    , showsPrec 10 ctxFeatureSet ""+    , showsPrec 10 ctxConfig ""     , showsPrec 10 ctxTheta ""     ] @@ -424,8 +449,9 @@   = Context       { ctxDefiningFuncs = mempty       , ctxModuleFuncs = mempty-      , ctxFeatureSet = mempty+      , ctxConfig = emptyConfig       , ctxKnownThings = error "empty known things from emptyContext"+      , ctxFamInstEnvs = mempty       , ctxInstEnvs = InstEnvs mempty mempty mempty       , ctxTheta = mempty       }@@ -461,6 +487,7 @@ data RunTacticResults = RunTacticResults   { rtr_trace       :: Trace   , rtr_extract     :: LHsExpr GhcPs+  , rtr_subgoals    :: [Judgement]   , rtr_other_solns :: [Synthesized (LHsExpr GhcPs)]   , rtr_jdg         :: Judgement   , rtr_ctx         :: Context@@ -486,4 +513,16 @@   show TimedOut                = "Wingman timed out while trying to find a solution"   show NothingToDo             = "Nothing to do"   show (InfrastructureError t) = "Internal error: " <> T.unpack t+++data HoleSort = Hole | Metaprogram T.Text+  deriving (Eq, Ord, Show)++data HoleJudgment = HoleJudgment+  { hj_range     :: Tracked 'Current Range+  , hj_jdg       :: Judgement+  , hj_ctx       :: Context+  , hj_dflags    :: DynFlags+  , hj_hole_sort :: HoleSort+  } 
test/AutoTupleSpec.hs view
@@ -36,6 +36,7 @@           runTactic             emptyContext             (mkFirstJudgement+              emptyContext               (Hypothesis $ pure $ HyInfo (mkVarOcc "x") UserPrv $ CType in_type)               True               out_type)
test/CodeAction/AutoSpec.hs view
@@ -1,16 +1,10 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE ScopedTypeVariables   #-}-{-# LANGUAGE TypeOperators         #-}-{-# LANGUAGE ViewPatterns          #-}+{-# LANGUAGE OverloadedStrings #-}  module CodeAction.AutoSpec where  import Wingman.Types import Test.Hspec import Utils-import Wingman.FeatureSet (allFeatures)   spec :: Spec@@ -19,72 +13,75 @@       autoTestNoWhitespace = goldenTestNoWhitespace Auto ""    describe "golden" $ do-    autoTest 11  8 "AutoSplitGADT.hs"-    autoTest  2 11 "GoldenEitherAuto.hs"-    autoTest  4 12 "GoldenJoinCont.hs"-    autoTest  3 11 "GoldenIdentityFunctor.hs"-    autoTest  7 11 "GoldenIdTypeFam.hs"-    autoTest  2 15 "GoldenEitherHomomorphic.hs"-    autoTest  2  8 "GoldenNote.hs"-    autoTest  2 12 "GoldenPureList.hs"-    autoTest  2 12 "GoldenListFmap.hs"-    autoTest  2 13 "GoldenFromMaybe.hs"-    autoTest  2 10 "GoldenFoldr.hs"-    autoTest  2  8 "GoldenSwap.hs"-    autoTest  4 11 "GoldenFmapTree.hs"-    autoTest  7 13 "GoldenGADTAuto.hs"-    autoTest  2 12 "GoldenSwapMany.hs"-    autoTest  4 12 "GoldenBigTuple.hs"-    autoTest  2 10 "GoldenShow.hs"-    autoTest  2 15 "GoldenShowCompose.hs"-    autoTest  2  8 "GoldenShowMapChar.hs"-    autoTest  7  8 "GoldenSuperclass.hs"-    autoTest  2 12 "GoldenSafeHead.hs"-    autoTest  2 12 "FmapBoth.hs"-    autoTest  7  8 "RecordCon.hs"-    autoTest  6  8 "NewtypeRecord.hs"-    autoTest  2 14 "FmapJoin.hs"-    autoTest  2  9 "Fgmap.hs"-    autoTest  4 19 "FmapJoinInLet.hs"-    autoTest  9 12 "AutoEndo.hs"-    autoTest  2 16 "AutoEmptyString.hs"-    autoTest  7 35 "AutoPatSynUse.hs"-    autoTest  2 28 "AutoZip.hs"-    autoTest  2 17 "AutoInfixApply.hs"-    autoTest  2 19 "AutoInfixApplyMany.hs"-    autoTest  2 25 "AutoInfixInfix.hs"+    autoTest 11  8 "AutoSplitGADT"+    autoTest  2 11 "GoldenEitherAuto"+    autoTest  4 12 "GoldenJoinCont"+    autoTest  3 11 "GoldenIdentityFunctor"+    autoTest  7 11 "GoldenIdTypeFam"+    autoTest  2 15 "GoldenEitherHomomorphic"+    autoTest  2  8 "GoldenNote"+    autoTest  2 12 "GoldenPureList"+    autoTest  2 12 "GoldenListFmap"+    autoTest  2 13 "GoldenFromMaybe"+    autoTest  2 10 "GoldenFoldr"+    autoTest  2  8 "GoldenSwap"+    autoTest  4 11 "GoldenFmapTree"+    autoTest  7 13 "GoldenGADTAuto"+    autoTest  2 12 "GoldenSwapMany"+    autoTest  4 12 "GoldenBigTuple"+    autoTest  2 10 "GoldenShow"+    autoTest  2 15 "GoldenShowCompose"+    autoTest  2  8 "GoldenShowMapChar"+    autoTest  7  8 "GoldenSuperclass"+    autoTest  2 12 "GoldenSafeHead"+    autoTest  2 12 "FmapBoth"+    autoTest  7  8 "RecordCon"+    autoTest  6  8 "NewtypeRecord"+    autoTest  2 14 "FmapJoin"+    autoTest  2  9 "Fgmap"+    autoTest  4 19 "FmapJoinInLet"+    autoTest  9 12 "AutoEndo"+    autoTest  2 16 "AutoEmptyString"+    autoTest  7 35 "AutoPatSynUse"+    autoTest  2 28 "AutoZip"+    autoTest  2 17 "AutoInfixApply"+    autoTest  2 19 "AutoInfixApplyMany"+    autoTest  2 25 "AutoInfixInfix"      failing "flaky in CI" $-      autoTest 2 11 "GoldenApplicativeThen.hs"+      autoTest 2 11 "GoldenApplicativeThen"      failing "not enough auto gas" $-      autoTest 5 18 "GoldenFish.hs"+      autoTest 5 18 "GoldenFish"    describe "theta" $ do-    autoTest 12 10 "AutoThetaFix.hs"-    autoTest  7 20 "AutoThetaRankN.hs"-    autoTest  6 10 "AutoThetaGADT.hs"-    autoTest  6  8 "AutoThetaGADTDestruct.hs"-    autoTest  4  8 "AutoThetaEqCtx.hs"-    autoTest  6 10 "AutoThetaEqGADT.hs"-    autoTest  6  8 "AutoThetaEqGADTDestruct.hs"-    autoTest  6 10 "AutoThetaRefl.hs"-    autoTest  6  8 "AutoThetaReflDestruct.hs"+    autoTest 12 10 "AutoThetaFix"+    autoTest  7 20 "AutoThetaRankN"+    autoTest  6 10 "AutoThetaGADT"+    autoTest  6  8 "AutoThetaGADTDestruct"+    autoTest  4  8 "AutoThetaEqCtx"+    autoTest  6 10 "AutoThetaEqGADT"+    autoTest  6  8 "AutoThetaEqGADTDestruct"+    autoTest  6 10 "AutoThetaRefl"+    autoTest  6  8 "AutoThetaReflDestruct"+    autoTest 19 30 "AutoThetaMultipleUnification"+    autoTest 16  9 "AutoThetaSplitUnification"    describe "known" $ do-    autoTest 25 13 "GoldenArbitrary.hs"+    autoTest 25 13 "GoldenArbitrary"     autoTestNoWhitespace-              6 10 "KnownBigSemigroup.hs"-    autoTest  4 10 "KnownThetaSemigroup.hs"-    autoTest  6 10 "KnownCounterfactualSemigroup.hs"-    autoTest 10 10 "KnownModuleInstanceSemigroup.hs"-    autoTest  4 22 "KnownDestructedSemigroup.hs"-    autoTest  4 10 "KnownMissingSemigroup.hs"-    autoTest  7 12 "KnownMonoid.hs"-    autoTest  7 12 "KnownPolyMonoid.hs"-    autoTest  7 12 "KnownMissingMonoid.hs"+              6 10 "KnownBigSemigroup"+    autoTest  4 10 "KnownThetaSemigroup"+    autoTest  6 10 "KnownCounterfactualSemigroup"+    autoTest 10 10 "KnownModuleInstanceSemigroup"+    autoTest  4 22 "KnownDestructedSemigroup"+    autoTest  4 10 "KnownMissingSemigroup"+    autoTest  7 12 "KnownMonoid"+    autoTest  7 12 "KnownPolyMonoid"+    autoTest  7 12 "KnownMissingMonoid"     describe "messages" $ do-    mkShowMessageTest allFeatures Auto "" 2 8 "MessageForallA.hs" TacticErrors+    mkShowMessageTest Auto "" 2 8 "MessageForallA" TacticErrors+    mkShowMessageTest Auto "" 7 8 "MessageCantUnify" TacticErrors 
test/CodeAction/DestructAllSpec.hs view
@@ -1,9 +1,4 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE ScopedTypeVariables   #-}-{-# LANGUAGE TypeOperators         #-}-{-# LANGUAGE ViewPatterns          #-}+{-# LANGUAGE OverloadedStrings #-}  module CodeAction.DestructAllSpec where @@ -18,25 +13,26 @@   describe "provider" $ do     mkTest       "Requires args on lhs of ="-      "DestructAllProvider.hs" 3 21+      "DestructAllProvider" 3 21       [ (not, DestructAll, "")       ]     mkTest       "Can't be a non-top-hole"-      "DestructAllProvider.hs" 8 19+      "DestructAllProvider" 8 19       [ (not, DestructAll, "")       , (id, Destruct, "a")       , (id, Destruct, "b")       ]     mkTest       "Provides a destruct all otherwise"-      "DestructAllProvider.hs" 12 22+      "DestructAllProvider" 12 22       [ (id, DestructAll, "")       ]    describe "golden" $ do-    destructAllTest 2 11 "DestructAllAnd.hs"-    destructAllTest 4 23 "DestructAllMany.hs"-    destructAllTest 2 18 "DestructAllNonVarTopMatch.hs"-    destructAllTest 2 18 "DestructAllFunc.hs"+    destructAllTest 2 11 "DestructAllAnd"+    destructAllTest 4 23 "DestructAllMany"+    destructAllTest 2 18 "DestructAllNonVarTopMatch"+    destructAllTest 2 18 "DestructAllFunc"+    destructAllTest 19 18 "DestructAllGADTEvidence" 
+ test/CodeAction/DestructPunSpec.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE OverloadedStrings #-}++module CodeAction.DestructPunSpec where++import Wingman.Types+import Test.Hspec+import Utils+++spec :: Spec+spec = do+  let destructTest = goldenTest DestructPun++  describe "golden" $ do+    destructTest "x"  4  9 "PunSimple"+    destructTest "x"  6 10 "PunMany"+    destructTest "x" 11 11 "PunGADT"+    destructTest "x" 17 11 "PunManyGADT"+    destructTest "x"  4 12 "PunShadowing"+
test/CodeAction/DestructSpec.hs view
@@ -1,9 +1,4 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE ScopedTypeVariables   #-}-{-# LANGUAGE TypeOperators         #-}-{-# LANGUAGE ViewPatterns          #-}+{-# LANGUAGE OverloadedStrings #-}  module CodeAction.DestructSpec where @@ -17,21 +12,26 @@   let destructTest = goldenTest Destruct    describe "golden" $ do-    destructTest "gadt" 7 17 "GoldenGADTDestruct.hs"-    destructTest "gadt" 8 17 "GoldenGADTDestructCoercion.hs"-    destructTest "a"    7 25 "SplitPattern.hs"+    destructTest "gadt"  7 17 "GoldenGADTDestruct"+    destructTest "gadt"  8 17 "GoldenGADTDestructCoercion"+    destructTest "a"     7 25 "SplitPattern"+    destructTest "a"     6 18 "DestructPun"+    destructTest "fp"   31 14 "DestructCthulhu"+    destructTest "b"     7 10 "DestructTyFam"+    destructTest "b"     7 10 "DestructDataFam"+    destructTest "b"    17 10 "DestructTyToDataFam"    describe "layout" $ do-    destructTest "b"  4  3 "LayoutBind.hs"-    destructTest "b"  2 15 "LayoutDollarApp.hs"-    destructTest "b"  2 18 "LayoutOpApp.hs"-    destructTest "b"  2 14 "LayoutLam.hs"-    destructTest "x" 11 15 "LayoutSplitWhere.hs"-    destructTest "x"  3 12 "LayoutSplitClass.hs"-    destructTest "b"  3  9 "LayoutSplitGuard.hs"-    destructTest "b"  4 13 "LayoutSplitLet.hs"-    destructTest "a"  4  7 "LayoutSplitIn.hs"-    destructTest "a"  4 31 "LayoutSplitViewPat.hs"-    destructTest "a"  7 17 "LayoutSplitPattern.hs"-    destructTest "a"  8 26 "LayoutSplitPatSyn.hs"+    destructTest "b"  4  3 "LayoutBind"+    destructTest "b"  2 15 "LayoutDollarApp"+    destructTest "b"  2 18 "LayoutOpApp"+    destructTest "b"  2 14 "LayoutLam"+    destructTest "x" 11 15 "LayoutSplitWhere"+    destructTest "x"  3 12 "LayoutSplitClass"+    destructTest "b"  3  9 "LayoutSplitGuard"+    destructTest "b"  4 13 "LayoutSplitLet"+    destructTest "a"  4  7 "LayoutSplitIn"+    destructTest "a"  4 31 "LayoutSplitViewPat"+    destructTest "a"  7 17 "LayoutSplitPattern"+    destructTest "a"  8 26 "LayoutSplitPatSyn" 
test/CodeAction/IntrosSpec.hs view
@@ -1,9 +1,4 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE ScopedTypeVariables   #-}-{-# LANGUAGE TypeOperators         #-}-{-# LANGUAGE ViewPatterns          #-}+{-# LANGUAGE OverloadedStrings #-}  module CodeAction.IntrosSpec where @@ -17,5 +12,8 @@   let introsTest = goldenTest Intros ""    describe "golden" $ do-    introsTest 2 8 "GoldenIntros.hs"+    introsTest 2 8 "GoldenIntros"++  describe "layout" $ do+    introsTest 4 24 "LayoutRec" 
test/CodeAction/RefineSpec.hs view
@@ -1,16 +1,10 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE ScopedTypeVariables   #-}-{-# LANGUAGE TypeOperators         #-}-{-# LANGUAGE ViewPatterns          #-}+{-# LANGUAGE OverloadedStrings #-}  module CodeAction.RefineSpec where  import Wingman.Types import Test.Hspec import Utils-import Wingman.FeatureSet (allFeatures)   spec :: Spec@@ -18,11 +12,11 @@   let refineTest = goldenTest Refine ""    describe "golden" $ do-    refineTest 2 8 "RefineIntro.hs"-    refineTest 2 8 "RefineCon.hs"-    refineTest 4 8 "RefineReader.hs"-    refineTest 8 8 "RefineGADT.hs"+    refineTest  2  8 "RefineIntro"+    refineTest  2  8 "RefineCon"+    refineTest  4 10 "RefineReader"+    refineTest  8 10 "RefineGADT"    describe "messages" $ do-    mkShowMessageTest allFeatures Refine "" 2 8 "MessageForallA.hs" NothingToDo+    mkShowMessageTest Refine "" 2 8 "MessageForallA" TacticErrors 
+ test/CodeAction/RunMetaprogramSpec.hs view
@@ -0,0 +1,36 @@+{-# LANGUAGE CPP               #-}+{-# LANGUAGE OverloadedStrings #-}++module CodeAction.RunMetaprogramSpec where++import  Utils+import  Test.Hspec+import  Wingman.Types+++spec :: Spec+spec = do+  let metaTest l c f =+#if __GLASGOW_HASKELL__ >= 808+        goldenTest RunMetaprogram "" l c f+#else+        pure ()+#endif++#if __GLASGOW_HASKELL__ >= 808+  describe "beginMetaprogram" $ do+    goldenTest BeginMetaprogram ""  1  7 "MetaBegin"+#endif++  describe "golden" $ do+    metaTest  6 11 "MetaMaybeAp"+    metaTest  2 32 "MetaBindOne"+    metaTest  2 32 "MetaBindAll"+    metaTest  2 13 "MetaTry"+    metaTest  2 74 "MetaChoice"+    metaTest  5 40 "MetaUseImport"+    metaTest  6 31 "MetaUseLocal"+    metaTest 11 11 "MetaUseMethod"+    metaTest  9 38 "MetaCataCollapse"+    metaTest  7 16 "MetaCataCollapseUnary"+
test/CodeAction/UseDataConSpec.hs view
@@ -1,9 +1,4 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE ScopedTypeVariables   #-}-{-# LANGUAGE TypeOperators         #-}-{-# LANGUAGE ViewPatterns          #-}+{-# LANGUAGE OverloadedStrings #-}  module CodeAction.UseDataConSpec where @@ -20,7 +15,7 @@   describe "provider" $ do     mkTest       "Suggests all data cons for Either"-      "ConProviders.hs" 5 6+      "ConProviders" 5 6       [ (id, UseDataCon, "Left")       , (id, UseDataCon, "Right")       , (not, UseDataCon, ":")@@ -29,19 +24,19 @@       ]     mkTest       "Suggests no data cons for big types"-      "ConProviders.hs" 11 17 $ do+      "ConProviders" 11 17 $ do         c <- [1 :: Int .. 10]         pure $ (not, UseDataCon, T.pack $ show c)     mkTest       "Suggests only matching data cons for GADT"-      "ConProviders.hs" 20 12+      "ConProviders" 20 12       [ (id, UseDataCon, "IntGADT")       , (id, UseDataCon, "VarGADT")       , (not, UseDataCon, "BoolGADT")       ]    describe "golden" $ do-    useTest "(,)"   2 8 "UseConPair.hs"-    useTest "Left"  2 8 "UseConLeft.hs"-    useTest "Right" 2 8 "UseConRight.hs"+    useTest "(,)"   2 8 "UseConPair"+    useTest "Left"  2 8 "UseConLeft"+    useTest "Right" 2 8 "UseConRight" 
+ test/CodeLens/EmptyCaseSpec.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE OverloadedStrings #-}++module CodeLens.EmptyCaseSpec where++import Test.Hspec+import Utils+++spec :: Spec+spec = do+  let test = mkCodeLensTest++  describe "golden" $ do+    test "EmptyCaseADT"+    test "EmptyCaseShadow"+    test "EmptyCaseParens"+    test "EmptyCaseNested"+    test "EmptyCaseApply"+    test "EmptyCaseGADT"+
test/ProviderSpec.hs view
@@ -1,9 +1,4 @@-{-# LANGUAGE DataKinds             #-}-{-# LANGUAGE DuplicateRecordFields #-}-{-# LANGUAGE OverloadedStrings     #-}-{-# LANGUAGE ScopedTypeVariables   #-}-{-# LANGUAGE TypeOperators         #-}-{-# LANGUAGE ViewPatterns          #-}+{-# LANGUAGE OverloadedStrings #-}  module ProviderSpec where @@ -16,57 +11,58 @@ spec = do   mkTest     "Produces intros code action"-    "T1.hs" 2 14+    "T1" 2 14     [ (id, Intros, "")     ]   mkTest     "Produces destruct and homomorphism code actions"-    "T2.hs" 2 21+    "T2" 2 21     [ (id, Destruct, "eab")     , (id, Homomorphism, "eab")+    , (not, DestructPun, "eab")     ]   mkTest     "Won't suggest homomorphism on the wrong type"-    "T2.hs" 8 8+    "T2" 8 8     [ (not, Homomorphism, "global")     ]   mkTest     "Won't suggest intros on the wrong type"-    "T2.hs" 8 8+    "T2" 8 8     [ (not, Intros, "")     ]   mkTest     "Produces (homomorphic) lambdacase code actions"-    "T3.hs" 4 24+    "T3" 4 24     [ (id, HomomorphismLambdaCase, "")     , (id, DestructLambdaCase, "")     ]   mkTest     "Produces lambdacase code actions"-    "T3.hs" 7 13+    "T3" 7 13     [ (id, DestructLambdaCase, "")     ]   mkTest     "Doesn't suggest lambdacase without -XLambdaCase"-    "T2.hs" 11 25+    "T2" 11 25     [ (not, DestructLambdaCase, "")     ]    mkTest     "Doesn't suggest destruct if already destructed"-    "ProvideAlreadyDestructed.hs" 6 18+    "ProvideAlreadyDestructed" 6 18     [ (not, Destruct, "x")     ]    mkTest     "...but does suggest destruct if destructed in a different branch"-    "ProvideAlreadyDestructed.hs" 9 7+    "ProvideAlreadyDestructed" 9 7     [ (id, Destruct, "x")     ]    mkTest     "Doesn't suggest destruct on class methods"-    "ProvideLocalHyOnly.hs" 2 12+    "ProvideLocalHyOnly" 2 12     [ (not, Destruct, "mempty")     ] 
test/Utils.hs view
@@ -9,7 +9,7 @@  import           Control.DeepSeq (deepseq) import qualified Control.Exception as E-import           Control.Lens hiding (failing, (<.>), (.=))+import           Control.Lens hiding (List, failing, (<.>), (.=)) import           Control.Monad (unless) import           Control.Monad.IO.Class import           Data.Aeson@@ -29,11 +29,10 @@ import           Test.Hls import           Test.Hspec import           Test.Hspec.Formatters (FailureReason(ExpectedButGot))-import           Test.Tasty.HUnit (Assertion, HUnitFailure(..))-import           Wingman.FeatureSet (FeatureSet, allFeatures, prettyFeatureSet) import           Wingman.LanguageServer (mkShowMessageParams) import           Wingman.Types + plugin :: PluginDescriptor IdeState plugin = Tactic.descriptor "tactics" @@ -61,7 +60,7 @@ mkTest     :: Foldable t     => String  -- ^ The test name-    -> FilePath  -- ^ The file to load+    -> FilePath  -- ^ The file name stem (without extension) to load     -> Int  -- ^ Cursor line     -> Int  -- ^ Cursor columnn     -> t ( Bool -> Bool   -- Use 'not' for actions that shouldnt be present@@ -71,8 +70,7 @@     -> SpecWith (Arg Bool) mkTest name fp line col ts = it name $ do   runSessionWithServer plugin tacticPath $ do-    setFeatureSet allFeatures-    doc <- openDoc fp "haskell"+    doc <- openDoc (fp <.> "hs") "haskell"     _ <- waitForDiagnostics     actions <- getCodeActions doc $ pointRange line col     let titles = mapMaybe codeActionTitle actions@@ -82,36 +80,19 @@         (title `elem` titles) `shouldSatisfy` f  -setFeatureSet :: FeatureSet -> Session ()-setFeatureSet features = do-  let unObject (Object obj) = obj-      unObject _            = undefined-      def_config = def :: Plugin.Config-      config =-        def_config-          { Plugin.plugins = M.fromList [("tactics",-              def { Plugin.plcConfig = unObject $ object ["features" .= prettyFeatureSet features] }-          )] <> Plugin.plugins def_config } -  sendNotification SWorkspaceDidChangeConfiguration $-    DidChangeConfigurationParams $-      toJSON config-- mkGoldenTest     :: (Text -> Text -> Assertion)-    -> FeatureSet     -> TacticCommand     -> Text     -> Int     -> Int     -> FilePath     -> SpecWith ()-mkGoldenTest eq features tc occ line col input =+mkGoldenTest eq tc occ line col input =   it (input <> " (golden)") $ do     runSessionWithServer plugin tacticPath $ do-      setFeatureSet features-      doc <- openDoc input "haskell"+      doc <- openDoc (input <.> "hs") "haskell"       _ <- waitForDiagnostics       actions <- getCodeActions doc $ pointRange line col       Just (InR CodeAction {_command = Just c})@@ -119,27 +100,54 @@       executeCommand c       _resp <- skipManyTill anyMessage (message SWorkspaceApplyEdit)       edited <- documentContents doc-      let expected_name = input <.> "expected"+      let expected_name = input <.> "expected" <.> "hs"       -- Write golden tests if they don't already exist       liftIO $ (doesFileExist expected_name >>=) $ flip unless $ do         T.writeFile expected_name edited       expected <- liftIO $ T.readFile expected_name       liftIO $ edited `eq` expected ++mkCodeLensTest+    :: FilePath+    -> SpecWith ()+mkCodeLensTest input =+  it (input <> " (golden)") $ do+    runSessionWithServer plugin tacticPath $ do+      doc <- openDoc (input <.> "hs") "haskell"+      _ <- waitForDiagnostics+      lenses <- fmap (reverse . filter isWingmanLens) $ getCodeLenses doc+      for_ lenses $ \(CodeLens _ (Just cmd) _) ->+        executeCommand cmd+      _resp <- skipManyTill anyMessage (message SWorkspaceApplyEdit)+      edited <- documentContents doc+      let expected_name = input <.> "expected" <.> "hs"+      -- Write golden tests if they don't already exist+      liftIO $ (doesFileExist expected_name >>=) $ flip unless $ do+        T.writeFile expected_name edited+      expected <- liftIO $ T.readFile expected_name+      liftIO $ edited `shouldBe` expected++++isWingmanLens :: CodeLens -> Bool+isWingmanLens (CodeLens _ (Just (Command _ cmd _)) _)+    = T.isInfixOf ":tactics:" cmd+isWingmanLens _ = False++ mkShowMessageTest-    :: FeatureSet-    -> TacticCommand+    :: TacticCommand     -> Text     -> Int     -> Int     -> FilePath     -> UserFacingMessage     -> SpecWith ()-mkShowMessageTest features tc occ line col input ufm =+mkShowMessageTest tc occ line col input ufm =   it (input <> " (golden)") $ do     runSessionWithServer plugin tacticPath $ do-      setFeatureSet features-      doc <- openDoc input "haskell"+      doc <- openDoc (input <.> "hs") "haskell"       _ <- waitForDiagnostics       actions <- getCodeActions doc $ pointRange line col       Just (InR CodeAction {_command = Just c})@@ -150,10 +158,10 @@   goldenTest :: TacticCommand -> Text -> Int -> Int -> FilePath -> SpecWith ()-goldenTest = mkGoldenTest shouldBe allFeatures+goldenTest = mkGoldenTest shouldBe  goldenTestNoWhitespace :: TacticCommand -> Text -> Int -> Int -> FilePath -> SpecWith ()-goldenTestNoWhitespace = mkGoldenTest shouldBeIgnoringSpaces allFeatures+goldenTestNoWhitespace = mkGoldenTest shouldBeIgnoringSpaces   shouldBeIgnoringSpaces :: Text -> Text -> Assertion
+ test/golden/AutoEmptyString.expected.hs view
@@ -0,0 +1,2 @@+empty_string :: String+empty_string = ""
− test/golden/AutoEmptyString.hs.expected
@@ -1,2 +0,0 @@-empty_string :: String-empty_string = ""
+ test/golden/AutoEndo.expected.hs view
@@ -0,0 +1,11 @@+data Synthesized b a = Synthesized+  { syn_trace :: b+  , syn_val   :: a+  }+  deriving (Eq, Show)+++mapTrace :: (b -> b) -> Synthesized b a -> Synthesized b a+mapTrace fbb (Synthesized b a)+  = Synthesized {syn_trace = fbb b, syn_val = a}+
− test/golden/AutoEndo.hs.expected
@@ -1,11 +0,0 @@-data Synthesized b a = Synthesized-  { syn_trace :: b-  , syn_val   :: a-  }-  deriving (Eq, Show)---mapTrace :: (b -> b) -> Synthesized b a -> Synthesized b a-mapTrace fbb (Synthesized b a)-  = Synthesized {syn_trace = fbb b, syn_val = a}-
+ test/golden/AutoInfixApply.expected.hs view
@@ -0,0 +1,3 @@+test :: (a -> b -> c) -> a -> (a -> b) -> c+test (/:) a f = a /: f a+
− test/golden/AutoInfixApply.hs.expected
@@ -1,3 +0,0 @@-test :: (a -> b -> c) -> a -> (a -> b) -> c-test (/:) a f = a /: f a-
+ test/golden/AutoInfixApplyMany.expected.hs view
@@ -0,0 +1,3 @@+test :: (a -> b -> x -> c) -> a -> (a -> b) -> x -> c+test (/:) a f x = (a /: f a) x+
− test/golden/AutoInfixApplyMany.hs.expected
@@ -1,3 +0,0 @@-test :: (a -> b -> x -> c) -> a -> (a -> b) -> x -> c-test (/:) a f x = (a /: f a) x-
+ test/golden/AutoInfixInfix.expected.hs view
@@ -0,0 +1,2 @@+test :: (a -> b -> c) -> (c -> d -> e) -> a -> (a -> b) -> d -> e+test (/:) (-->) a f x = (a /: f a) --> x
− test/golden/AutoInfixInfix.hs.expected
@@ -1,2 +0,0 @@-test :: (a -> b -> c) -> (c -> d -> e) -> a -> (a -> b) -> d -> e-test (/:) (-->) a f x = (a /: f a) --> x
+ test/golden/AutoPatSynUse.expected.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE PatternSynonyms #-}++pattern JustSingleton :: a -> Maybe [a]+pattern JustSingleton a <- Just [a]++amIASingleton :: Maybe [a] -> Maybe a+amIASingleton (JustSingleton a) = Just a+
− test/golden/AutoPatSynUse.hs.expected
@@ -1,8 +0,0 @@-{-# LANGUAGE PatternSynonyms #-}--pattern JustSingleton :: a -> Maybe [a]-pattern JustSingleton a <- Just [a]--amIASingleton :: Maybe [a] -> Maybe a-amIASingleton (JustSingleton a) = Just a-
+ test/golden/AutoSplitGADT.expected.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE GADTs #-}++data GADT b a where+  GBool :: b -> GADT b Bool+  GInt :: GADT b Int++-- wingman would prefer to use GBool since then it can use its argument. But+-- that won't unify with GADT Int, so it is forced to pick GInt and ignore the+-- argument.+test :: b -> GADT b Int+test _ = GInt+
− test/golden/AutoSplitGADT.hs.expected
@@ -1,12 +0,0 @@-{-# LANGUAGE GADTs #-}--data GADT b a where-  GBool :: b -> GADT b Bool-  GInt :: GADT b Int---- wingman would prefer to use GBool since then it can use its argument. But--- that won't unify with GADT Int, so it is forced to pick GInt and ignore the--- argument.-test :: b -> GADT b Int-test _ = GInt-
+ test/golden/AutoThetaEqCtx.expected.hs view
@@ -0,0 +1,5 @@+{-# LANGUAGE GADTs #-}++fun2 :: (a ~ b) => a -> b+fun2 = id -- id+
− test/golden/AutoThetaEqCtx.hs.expected
@@ -1,5 +0,0 @@-{-# LANGUAGE GADTs #-}--fun2 :: (a ~ b) => a -> b-fun2 = id -- id-
+ test/golden/AutoThetaEqGADT.expected.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE GADTs #-}++data Y a b = a ~ b => Y++fun3 :: Y a b -> a -> b+fun3 Y = id+
− test/golden/AutoThetaEqGADT.hs.expected
@@ -1,7 +0,0 @@-{-# LANGUAGE GADTs #-}--data Y a b = a ~ b => Y--fun3 :: Y a b -> a -> b-fun3 Y = id-
+ test/golden/AutoThetaEqGADTDestruct.expected.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE GADTs #-}++data Y a b = a ~ b => Y++fun3 :: Y a b -> a -> b+fun3 Y a = a++
− test/golden/AutoThetaEqGADTDestruct.hs.expected
@@ -1,8 +0,0 @@-{-# LANGUAGE GADTs #-}--data Y a b = a ~ b => Y--fun3 :: Y a b -> a -> b-fun3 Y a = a--
+ test/golden/AutoThetaFix.expected.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE UndecidableInstances #-}++data Fix f a = Fix (f (Fix f a))++instance ( Functor f+           -- FIXME(sandy): Unfortunately, the recursion tactic fails to fire+           -- on this case. By explicitly adding the @Functor (Fix f)@+           -- dictionary, we can get Wingman to generate the right definition.+         , Functor (Fix f)+         ) => Functor (Fix f) where+  fmap fab (Fix f) = Fix (fmap (fmap fab) f)+
− test/golden/AutoThetaFix.hs.expected
@@ -1,13 +0,0 @@-{-# LANGUAGE FlexibleContexts     #-}-{-# LANGUAGE UndecidableInstances #-}--data Fix f a = Fix (f (Fix f a))--instance ( Functor f-           -- FIXME(sandy): Unfortunately, the recursion tactic fails to fire-           -- on this case. By explicitly adding the @Functor (Fix f)@-           -- dictionary, we can get Wingman to generate the right definition.-         , Functor (Fix f)-         ) => Functor (Fix f) where-  fmap fab (Fix fffa) = Fix (fmap (fmap fab) fffa)-
+ test/golden/AutoThetaGADT.expected.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE GADTs #-}++data X f = Monad f => X++fun1 :: X f -> a -> f a+fun1 X = pure+
− test/golden/AutoThetaGADT.hs.expected
@@ -1,7 +0,0 @@-{-# LANGUAGE GADTs #-}--data X f = Monad f => X--fun1 :: X f -> a -> f a-fun1 X = pure-
+ test/golden/AutoThetaGADTDestruct.expected.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE GADTs #-}++data X f = Monad f => X++fun1 :: X f -> a -> f a+fun1 X a = pure a+
− test/golden/AutoThetaGADTDestruct.hs.expected
@@ -1,7 +0,0 @@-{-# LANGUAGE GADTs #-}--data X f = Monad f => X--fun1 :: X f -> a -> f a-fun1 X a = pure a-
+ test/golden/AutoThetaMultipleUnification.expected.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE DataKinds      #-}+{-# LANGUAGE GADTs          #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators  #-}++import Data.Kind++data Nat = Z | S Nat++data HList (ls :: [Type]) where+  HNil :: HList '[]+  HCons :: t -> HList ts -> HList (t ': ts)++data ElemAt (n :: Nat) t (ts :: [Type]) where+  AtZ :: ElemAt 'Z t (t ': ts)+  AtS :: ElemAt k t ts -> ElemAt ('S k) t (u ': ts)++lookMeUp :: ElemAt i ty tys -> HList tys -> ty+lookMeUp AtZ (HCons t _) = t+lookMeUp (AtS ea') (HCons t hl') = _+
+ test/golden/AutoThetaMultipleUnification.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE DataKinds      #-}+{-# LANGUAGE GADTs          #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators  #-}++import Data.Kind++data Nat = Z | S Nat++data HList (ls :: [Type]) where+  HNil :: HList '[]+  HCons :: t -> HList ts -> HList (t ': ts)++data ElemAt (n :: Nat) t (ts :: [Type]) where+  AtZ :: ElemAt 'Z t (t ': ts)+  AtS :: ElemAt k t ts -> ElemAt ('S k) t (u ': ts)++lookMeUp :: ElemAt i ty tys -> HList tys -> ty+lookMeUp AtZ (HCons t hl') = _+lookMeUp (AtS ea') (HCons t hl') = _+
+ test/golden/AutoThetaRankN.expected.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE RankNTypes #-}++showMe :: (forall x. Show x => x -> String) -> Int -> String+showMe f = f++showedYou :: Int -> String+showedYou = showMe show+
− test/golden/AutoThetaRankN.hs.expected
@@ -1,8 +0,0 @@-{-# LANGUAGE RankNTypes #-}--showMe :: (forall x. Show x => x -> String) -> Int -> String-showMe f = f--showedYou :: Int -> String-showedYou = showMe show-
+ test/golden/AutoThetaRefl.expected.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE GADTs #-}++data Z a b where Z :: Z a a++fun4 :: Z a b -> a -> b+fun4 Z = id -- id+
− test/golden/AutoThetaRefl.hs.expected
@@ -1,7 +0,0 @@-{-# LANGUAGE GADTs #-}--data Z a b where Z :: Z a a--fun4 :: Z a b -> a -> b-fun4 Z = id -- id-
+ test/golden/AutoThetaReflDestruct.expected.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE GADTs #-}++data Z a b where Z :: Z a a++fun4 :: Z a b -> a -> b+fun4 Z a = a -- id++
− test/golden/AutoThetaReflDestruct.hs.expected
@@ -1,8 +0,0 @@-{-# LANGUAGE GADTs #-}--data Z a b where Z :: Z a a--fun4 :: Z a b -> a -> b-fun4 Z a = a -- id--
+ test/golden/AutoThetaSplitUnification.expected.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE DataKinds      #-}+{-# LANGUAGE GADTs          #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators  #-}++data A = A+data B = B+data X = X+data Y = Y+++data Pairrow ax by  where+  Pairrow :: (a -> b) -> (x -> y) -> Pairrow '(a, x) '(b, y)++test2 :: (A -> B) -> (X -> Y) -> Pairrow '(A, X) '(B, Y)+test2 = Pairrow+
+ test/golden/AutoThetaSplitUnification.hs view
@@ -0,0 +1,17 @@+{-# LANGUAGE DataKinds      #-}+{-# LANGUAGE GADTs          #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators  #-}++data A = A+data B = B+data X = X+data Y = Y+++data Pairrow ax by  where+  Pairrow :: (a -> b) -> (x -> y) -> Pairrow '(a, x) '(b, y)++test2 :: (A -> B) -> (X -> Y) -> Pairrow '(A, X) '(B, Y)+test2 = _+
+ test/golden/AutoZip.expected.hs view
@@ -0,0 +1,6 @@+zip_it_up_and_zip_it_out :: [a] -> [b] -> [(a, b)]+zip_it_up_and_zip_it_out _ [] = []+zip_it_up_and_zip_it_out [] (_ : _) = []+zip_it_up_and_zip_it_out (a : as') (b : bs')+  = (a, b) : zip_it_up_and_zip_it_out as' bs'+
− test/golden/AutoZip.hs.expected
@@ -1,6 +0,0 @@-zip_it_up_and_zip_it_out :: [a] -> [b] -> [(a, b)]-zip_it_up_and_zip_it_out _ [] = []-zip_it_up_and_zip_it_out [] (_ : _) = []-zip_it_up_and_zip_it_out (a : l_a5) (b : l_b3)-  = (a, b) : zip_it_up_and_zip_it_out l_a5 l_b3-
+ test/golden/DestructAllAnd.expected.hs view
@@ -0,0 +1,5 @@+and :: Bool -> Bool -> Bool+and False False = _+and False True = _+and True False = _+and True True = _
− test/golden/DestructAllAnd.hs.expected
@@ -1,5 +0,0 @@-and :: Bool -> Bool -> Bool-and False False = _-and True False = _-and False True = _-and True True = _
+ test/golden/DestructAllFunc.expected.hs view
@@ -0,0 +1,4 @@+has_a_func :: Bool -> (a -> b) -> Bool+has_a_func False y = _+has_a_func True y = _+
− test/golden/DestructAllFunc.hs.expected
@@ -1,4 +0,0 @@-has_a_func :: Bool -> (a -> b) -> Bool-has_a_func False y = _-has_a_func True y = _-
+ test/golden/DestructAllGADTEvidence.expected.hs view
@@ -0,0 +1,21 @@+{-# LANGUAGE DataKinds      #-}+{-# LANGUAGE GADTs          #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators  #-}++import Data.Kind++data Nat = Z | S Nat++data HList (ls :: [Type]) where+  HNil :: HList '[]+  HCons :: t -> HList ts -> HList (t ': ts)++data ElemAt (n :: Nat) t (ts :: [Type]) where+  AtZ :: ElemAt 'Z t (t ': ts)+  AtS :: ElemAt k t ts -> ElemAt ('S k) t (u ': ts)++lookMeUp :: ElemAt i ty tys -> HList tys -> ty+lookMeUp AtZ (HCons t hl') = _+lookMeUp (AtS ea') (HCons t hl') = _+
+ test/golden/DestructAllGADTEvidence.hs view
@@ -0,0 +1,20 @@+{-# LANGUAGE DataKinds      #-}+{-# LANGUAGE GADTs          #-}+{-# LANGUAGE KindSignatures #-}+{-# LANGUAGE TypeOperators  #-}++import Data.Kind++data Nat = Z | S Nat++data HList (ls :: [Type]) where+  HNil :: HList '[]+  HCons :: t -> HList ts -> HList (t ': ts)++data ElemAt (n :: Nat) t (ts :: [Type]) where+  AtZ :: ElemAt 'Z t (t ': ts)+  AtS :: ElemAt k t ts -> ElemAt ('S k) t (u ': ts)++lookMeUp :: ElemAt i ty tys -> HList tys -> ty+lookMeUp ea hl = _+
+ test/golden/DestructAllMany.expected.hs view
@@ -0,0 +1,27 @@+data ABC = A | B | C++many :: () -> Either a b -> Bool -> Maybe ABC -> ABC -> ()+many () (Left a) False Nothing A = _+many () (Left a) False Nothing B = _+many () (Left a) False Nothing C = _+many () (Left a) False (Just abc') A = _+many () (Left a) False (Just abc') B = _+many () (Left a) False (Just abc') C = _+many () (Left a) True Nothing A = _+many () (Left a) True Nothing B = _+many () (Left a) True Nothing C = _+many () (Left a) True (Just abc') A = _+many () (Left a) True (Just abc') B = _+many () (Left a) True (Just abc') C = _+many () (Right b') False Nothing A = _+many () (Right b') False Nothing B = _+many () (Right b') False Nothing C = _+many () (Right b') False (Just abc') A = _+many () (Right b') False (Just abc') B = _+many () (Right b') False (Just abc') C = _+many () (Right b') True Nothing A = _+many () (Right b') True Nothing B = _+many () (Right b') True Nothing C = _+many () (Right b') True (Just abc') A = _+many () (Right b') True (Just abc') B = _+many () (Right b') True (Just abc') C = _
− test/golden/DestructAllMany.hs.expected
@@ -1,27 +0,0 @@-data ABC = A | B | C--many :: () -> Either a b -> Bool -> Maybe ABC -> ABC -> ()-many () (Left a) False Nothing A = _-many () (Right b5) False Nothing A = _-many () (Left a) True Nothing A = _-many () (Right b5) True Nothing A = _-many () (Left a6) False (Just a) A = _-many () (Right b6) False (Just a) A = _-many () (Left a6) True (Just a) A = _-many () (Right b6) True (Just a) A = _-many () (Left a) False Nothing B = _-many () (Right b5) False Nothing B = _-many () (Left a) True Nothing B = _-many () (Right b5) True Nothing B = _-many () (Left a6) False (Just a) B = _-many () (Right b6) False (Just a) B = _-many () (Left a6) True (Just a) B = _-many () (Right b6) True (Just a) B = _-many () (Left a) False Nothing C = _-many () (Right b5) False Nothing C = _-many () (Left a) True Nothing C = _-many () (Right b5) True Nothing C = _-many () (Left a6) False (Just a) C = _-many () (Right b6) False (Just a) C = _-many () (Left a6) True (Just a) C = _-many () (Right b6) True (Just a) C = _
+ test/golden/DestructAllNonVarTopMatch.expected.hs view
@@ -0,0 +1,6 @@+and :: (a, b) -> Bool -> Bool -> Bool+and (a, b) False False = _+and (a, b) False True = _+and (a, b) True False = _+and (a, b) True True = _+
− test/golden/DestructAllNonVarTopMatch.hs.expected
@@ -1,6 +0,0 @@-and :: (a, b) -> Bool -> Bool -> Bool-and (a, b) False False = _-and (a, b) True False = _-and (a, b) False True = _-and (a, b) True True = _-
+ test/golden/DestructCthulhu.expected.hs view
@@ -0,0 +1,54 @@+{-# LANGUAGE GADTs #-}++data FreePro r c a b where+  ID        :: FreePro r c x x+  Comp      :: FreePro r c x y -> FreePro r c y z -> FreePro r c x z+  Copy      :: FreePro r c x (x, x)+  Consume   :: FreePro r c x ()+  Swap      :: FreePro r c (a, b) (b, a)+  SwapE     :: FreePro r c (Either a b) (Either b a)+  Fst       :: FreePro r c (a, b) a+  Snd       :: FreePro r c (a, b) b+  InjectL   :: FreePro r c a (Either a b)+  InjectR   :: FreePro r c b (Either a b)+  Unify     :: FreePro r c (Either a a) a+  First     :: FreePro r c a b -> FreePro r c (a, m) (b, m)+  Second    :: FreePro r c a b -> FreePro r c (m, a) (m, b)+  Alongside :: FreePro r c a b -> FreePro r c a' b' -> FreePro r c (a, a') (b, b')+  Fanout    :: FreePro r c a b -> FreePro r c a b' -> FreePro r c a (b, b')+  Left'     :: FreePro r c a b -> FreePro r c (Either a x) (Either b x)+  Right'    :: FreePro r c a b -> FreePro r c (Either x a) (Either x b)+  EitherOf  :: FreePro r c a b -> FreePro r c a' b' -> FreePro r c (Either a a') (Either b b')+  Fanin     :: FreePro r c a b -> FreePro r c a' b -> FreePro r c (Either a a') b+  LiftC     :: c a b -> FreePro r c a b+  Zero      :: FreePro r c x y+  Plus      :: FreePro r c x y -> FreePro r c x y -> FreePro r c x y+  Unleft    :: FreePro r c (Either a d) (Either b d) -> FreePro r c a b+  Unright   :: FreePro r c (Either d a) (Either d b) -> FreePro r c a b+++cthulhu :: FreePro r c a b -> FreePro r c a b+cthulhu ID = _+cthulhu (Comp fp' fp_rcyb) = _+cthulhu Copy = _+cthulhu Consume = _+cthulhu Swap = _+cthulhu SwapE = _+cthulhu Fst = _+cthulhu Snd = _+cthulhu InjectL = _+cthulhu InjectR = _+cthulhu Unify = _+cthulhu (First fp') = _+cthulhu (Second fp') = _+cthulhu (Alongside fp' fp_rca'b') = _+cthulhu (Fanout fp' fp_rcab') = _+cthulhu (Left' fp') = _+cthulhu (Right' fp') = _+cthulhu (EitherOf fp' fp_rca'b') = _+cthulhu (Fanin fp' fp_rca'b) = _+cthulhu (LiftC cab) = _+cthulhu Zero = _+cthulhu (Plus fp' fp_rcab) = _+cthulhu (Unleft fp') = _+cthulhu (Unright fp') = _
+ test/golden/DestructCthulhu.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE GADTs #-}++data FreePro r c a b where+  ID        :: FreePro r c x x+  Comp      :: FreePro r c x y -> FreePro r c y z -> FreePro r c x z+  Copy      :: FreePro r c x (x, x)+  Consume   :: FreePro r c x ()+  Swap      :: FreePro r c (a, b) (b, a)+  SwapE     :: FreePro r c (Either a b) (Either b a)+  Fst       :: FreePro r c (a, b) a+  Snd       :: FreePro r c (a, b) b+  InjectL   :: FreePro r c a (Either a b)+  InjectR   :: FreePro r c b (Either a b)+  Unify     :: FreePro r c (Either a a) a+  First     :: FreePro r c a b -> FreePro r c (a, m) (b, m)+  Second    :: FreePro r c a b -> FreePro r c (m, a) (m, b)+  Alongside :: FreePro r c a b -> FreePro r c a' b' -> FreePro r c (a, a') (b, b')+  Fanout    :: FreePro r c a b -> FreePro r c a b' -> FreePro r c a (b, b')+  Left'     :: FreePro r c a b -> FreePro r c (Either a x) (Either b x)+  Right'    :: FreePro r c a b -> FreePro r c (Either x a) (Either x b)+  EitherOf  :: FreePro r c a b -> FreePro r c a' b' -> FreePro r c (Either a a') (Either b b')+  Fanin     :: FreePro r c a b -> FreePro r c a' b -> FreePro r c (Either a a') b+  LiftC     :: c a b -> FreePro r c a b+  Zero      :: FreePro r c x y+  Plus      :: FreePro r c x y -> FreePro r c x y -> FreePro r c x y+  Unleft    :: FreePro r c (Either a d) (Either b d) -> FreePro r c a b+  Unright   :: FreePro r c (Either d a) (Either d b) -> FreePro r c a b+++cthulhu :: FreePro r c a b -> FreePro r c a b+cthulhu fp = _
+ test/golden/DestructDataFam.expected.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE TypeFamilies #-}++data family Yo+data instance Yo = Heya Int++test :: Yo -> Int+test (Heya n) = _+
+ test/golden/DestructDataFam.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE TypeFamilies #-}++data family Yo+data instance Yo = Heya Int++test :: Yo -> Int+test b = _+
+ test/golden/DestructPun.expected.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE NamedFieldPuns #-}+++data Foo = Foo { a :: Bool, b :: Bool }++foo Foo {a = False, b} = _+foo Foo {a = True, b} = _+
+ test/golden/DestructPun.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE NamedFieldPuns #-}+++data Foo = Foo { a :: Bool, b :: Bool }++foo Foo {a, b} = _+
+ test/golden/DestructTyFam.expected.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE TypeFamilies #-}++type family Yo where+  Yo = Bool++test :: Yo -> Int+test False = _+test True = _+
+ test/golden/DestructTyFam.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE TypeFamilies #-}++type family Yo where+  Yo = Bool++test :: Yo -> Int+test b = _+
+ test/golden/DestructTyToDataFam.expected.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE UndecidableInstances #-}++type family T1 a where+  T1 a = T2 Int++type family T2 a+type instance T2 Int = T3++type family T3 where+  T3 = Yo++data family Yo+data instance Yo = Heya Int++test :: T1 Bool -> Int+test (Heya n) = _+
+ test/golden/DestructTyToDataFam.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE UndecidableInstances #-}++type family T1 a where+  T1 a = T2 Int++type family T2 a+type instance T2 Int = T3++type family T3 where+  T3 = Yo++data family Yo+data instance Yo = Heya Int++test :: T1 Bool -> Int+test b = _+
+ test/golden/EmptyCaseADT.expected.hs view
@@ -0,0 +1,8 @@+data Foo = A Int | B Bool | C++foo :: Foo -> ()+foo x = case x of+  A n -> _+  B b -> _+  C -> _+
+ test/golden/EmptyCaseADT.hs view
@@ -0,0 +1,5 @@+data Foo = A Int | B Bool | C++foo :: Foo -> ()+foo x = case x of+
+ test/golden/EmptyCaseApply.expected.hs view
@@ -0,0 +1,3 @@+blah = case show 5 of+  [] -> _+  c : s -> _
+ test/golden/EmptyCaseApply.hs view
@@ -0,0 +1,1 @@+blah = case show 5 of
+ test/golden/EmptyCaseGADT.expected.hs view
@@ -0,0 +1,13 @@+{-# LANGUAGE GADTs #-}++data GADT a where+  MyInt :: GADT Int+  MyBool :: GADT Bool+  MyVar :: GADT a+++test :: GADT Int -> GADT Bool+test x = case x of+  MyInt -> _+  MyVar -> _+
+ test/golden/EmptyCaseGADT.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE GADTs #-}++data GADT a where+  MyInt :: GADT Int+  MyBool :: GADT Bool+  MyVar :: GADT a+++test :: GADT Int -> GADT Bool+test x = case x of+
+ test/golden/EmptyCaseNested.expected.hs view
@@ -0,0 +1,5 @@+test =+  case (case (Just "") of+  Nothing -> _+  Just s -> _) of+    True -> _
+ test/golden/EmptyCaseNested.hs view
@@ -0,0 +1,3 @@+test =+  case (case (Just "") of) of+    True -> _
+ test/golden/EmptyCaseParens.expected.hs view
@@ -0,0 +1,3 @@+test = True && (case True of+   False -> _+   True -> _)
+ test/golden/EmptyCaseParens.hs view
@@ -0,0 +1,1 @@+test = True && case True of
+ test/golden/EmptyCaseShadow.expected.hs view
@@ -0,0 +1,10 @@+data Foo = A Int | B Bool | C++-- Make sure we don't shadow the i and b bindings when we empty case+-- split+foo :: Int -> Bool -> Foo -> ()+foo i b x = case x of+  A n -> _+  B b' -> _+  C -> _+
+ test/golden/EmptyCaseShadow.hs view
@@ -0,0 +1,7 @@+data Foo = A Int | B Bool | C++-- Make sure we don't shadow the i and b bindings when we empty case+-- split+foo :: Int -> Bool -> Foo -> ()+foo i b x = case x of+
+ test/golden/Fgmap.expected.hs view
@@ -0,0 +1,2 @@+fgmap :: (Functor f, Functor g) => (a -> b) -> (f (g a) -> f (g b))+fgmap = fmap . fmap
− test/golden/Fgmap.hs.expected
@@ -1,2 +0,0 @@-fgmap :: (Functor f, Functor g) => (a -> b) -> (f (g a) -> f (g b))-fgmap = fmap . fmap
+ test/golden/FmapBoth.expected.hs view
@@ -0,0 +1,3 @@+fmapBoth :: (Functor f, Functor g) => (a -> b) -> (f a, g a) -> (f b, g b)+fmapBoth fab (fa, ga) = (fmap fab fa, fmap fab ga)+
− test/golden/FmapBoth.hs.expected
@@ -1,3 +0,0 @@-fmapBoth :: (Functor f, Functor g) => (a -> b) -> (f a, g a) -> (f b, g b)-fmapBoth fab (fa, ga) = (fmap fab fa, fmap fab ga)-
+ test/golden/FmapJoin.expected.hs view
@@ -0,0 +1,2 @@+fJoin :: (Monad m, Monad f) => f (m (m a)) -> f (m a)+fJoin = fmap (\ m -> m >>= id)
− test/golden/FmapJoin.hs.expected
@@ -1,2 +0,0 @@-fJoin :: (Monad m, Monad f) => f (m (m a)) -> f (m a)-fJoin = fmap (\ mma -> mma >>= id)
+ test/golden/FmapJoinInLet.expected.hs view
@@ -0,0 +1,4 @@+{-# LANGUAGE ScopedTypeVariables #-}++fJoin :: forall f m a. (Monad m, Monad f) => f (m (m a)) -> f (m a)+fJoin =  let f = ( (\ m -> m >>= id) :: m (m a) -> m a) in fmap f
− test/golden/FmapJoinInLet.hs.expected
@@ -1,4 +0,0 @@-{-# LANGUAGE ScopedTypeVariables #-}--fJoin :: forall f m a. (Monad m, Monad f) => f (m (m a)) -> f (m a)-fJoin =  let f = ( (\ mma -> mma >>= id) :: m (m a) -> m a) in fmap f
+ test/golden/GoldenArbitrary.expected.hs view
@@ -0,0 +1,53 @@+-- Emulate a quickcheck import; deriveArbitrary works on any type with the+-- right name and kind+data Gen a++data Obj+  = Square Int Int+  | Circle Int+  | Polygon [(Int, Int)]+  | Rotate2 Double Obj+  | Empty+  | Full+  | Complement Obj+  | UnionR Double [Obj]+  | DifferenceR Double Obj [Obj]+  | IntersectR Double [Obj]+  | Translate Double Double Obj+  | Scale Double Double Obj+  | Mirror Double Double Obj+  | Outset Double Obj+  | Shell Double Obj+  | WithRounding Double Obj+++arbitrary :: Gen Obj+arbitrary+  = let+      terminal+        = [(Square <$> arbitrary) <*> arbitrary, Circle <$> arbitrary,+           Polygon <$> arbitrary, pure Empty, pure Full]+    in+      sized+        $ (\ n+             -> case n <= 1 of+                  True -> oneof terminal+                  False+                    -> oneof+                         $ ([(Rotate2 <$> arbitrary) <*> scale (subtract 1) arbitrary,+                             Complement <$> scale (subtract 1) arbitrary,+                             (UnionR <$> arbitrary) <*> scale (subtract 1) arbitrary,+                             ((DifferenceR <$> arbitrary) <*> scale (flip div 2) arbitrary)+                               <*> scale (flip div 2) arbitrary,+                             (IntersectR <$> arbitrary) <*> scale (subtract 1) arbitrary,+                             ((Translate <$> arbitrary) <*> arbitrary)+                               <*> scale (subtract 1) arbitrary,+                             ((Scale <$> arbitrary) <*> arbitrary)+                               <*> scale (subtract 1) arbitrary,+                             ((Mirror <$> arbitrary) <*> arbitrary)+                               <*> scale (subtract 1) arbitrary,+                             (Outset <$> arbitrary) <*> scale (subtract 1) arbitrary,+                             (Shell <$> arbitrary) <*> scale (subtract 1) arbitrary,+                             (WithRounding <$> arbitrary) <*> scale (subtract 1) arbitrary]+                              <> terminal))+
− test/golden/GoldenArbitrary.hs.expected
@@ -1,53 +0,0 @@--- Emulate a quickcheck import; deriveArbitrary works on any type with the--- right name and kind-data Gen a--data Obj-  = Square Int Int-  | Circle Int-  | Polygon [(Int, Int)]-  | Rotate2 Double Obj-  | Empty-  | Full-  | Complement Obj-  | UnionR Double [Obj]-  | DifferenceR Double Obj [Obj]-  | IntersectR Double [Obj]-  | Translate Double Double Obj-  | Scale Double Double Obj-  | Mirror Double Double Obj-  | Outset Double Obj-  | Shell Double Obj-  | WithRounding Double Obj---arbitrary :: Gen Obj-arbitrary-  = let-      terminal-        = [(Square <$> arbitrary) <*> arbitrary, Circle <$> arbitrary,-           Polygon <$> arbitrary, pure Empty, pure Full]-    in-      sized-        $ (\ n-             -> case n <= 1 of-                  True -> oneof terminal-                  False-                    -> oneof-                         $ ([(Rotate2 <$> arbitrary) <*> scale (subtract 1) arbitrary,-                             Complement <$> scale (subtract 1) arbitrary,-                             (UnionR <$> arbitrary) <*> scale (subtract 1) arbitrary,-                             ((DifferenceR <$> arbitrary) <*> scale (flip div 2) arbitrary)-                               <*> scale (flip div 2) arbitrary,-                             (IntersectR <$> arbitrary) <*> scale (subtract 1) arbitrary,-                             ((Translate <$> arbitrary) <*> arbitrary)-                               <*> scale (subtract 1) arbitrary,-                             ((Scale <$> arbitrary) <*> arbitrary)-                               <*> scale (subtract 1) arbitrary,-                             ((Mirror <$> arbitrary) <*> arbitrary)-                               <*> scale (subtract 1) arbitrary,-                             (Outset <$> arbitrary) <*> scale (subtract 1) arbitrary,-                             (Shell <$> arbitrary) <*> scale (subtract 1) arbitrary,-                             (WithRounding <$> arbitrary) <*> scale (subtract 1) arbitrary]-                              <> terminal))-
+ test/golden/GoldenBigTuple.expected.hs view
@@ -0,0 +1,4 @@+-- There used to be a bug where we were unable to perform a nested split. The+-- more serious regression test of this is 'AutoTupleSpec'.+bigTuple :: (a, b, c, d) -> (a, b, (c, d))+bigTuple (a, b, c, d) = (a, b, (c, d))
− test/golden/GoldenBigTuple.hs.expected
@@ -1,4 +0,0 @@--- There used to be a bug where we were unable to perform a nested split. The--- more serious regression test of this is 'AutoTupleSpec'.-bigTuple :: (a, b, c, d) -> (a, b, (c, d))-bigTuple (a, b, c, d) = (a, b, (c, d))
+ test/golden/GoldenEitherAuto.expected.hs view
@@ -0,0 +1,3 @@+either' :: (a -> c) -> (b -> c) -> Either a b -> c+either' fac _ (Left a) = fac a+either' _ fbc (Right b) = fbc b
− test/golden/GoldenEitherAuto.hs.expected
@@ -1,3 +0,0 @@-either' :: (a -> c) -> (b -> c) -> Either a b -> c-either' fac _ (Left a) = fac a-either' _ fbc (Right b) = fbc b
+ test/golden/GoldenEitherHomomorphic.expected.hs view
@@ -0,0 +1,3 @@+eitherSplit :: a -> Either (a -> b) (a -> c) -> Either b c+eitherSplit a (Left fab) = Left (fab a)+eitherSplit a (Right fac) = Right (fac a)
− test/golden/GoldenEitherHomomorphic.hs.expected
@@ -1,3 +0,0 @@-eitherSplit :: a -> Either (a -> b) (a -> c) -> Either b c-eitherSplit a (Left fab) = Left (fab a)-eitherSplit a (Right fac) = Right (fac a)
+ test/golden/GoldenFmapTree.expected.hs view
@@ -0,0 +1,5 @@+data Tree a = Leaf a | Branch (Tree a) (Tree a)++instance Functor Tree where+   fmap fab (Leaf a) = Leaf (fab a)+   fmap fab (Branch tr' tr_a) = Branch (fmap fab tr') (fmap fab tr_a)
− test/golden/GoldenFmapTree.hs.expected
@@ -1,5 +0,0 @@-data Tree a = Leaf a | Branch (Tree a) (Tree a)--instance Functor Tree where-   fmap fab (Leaf a) = Leaf (fab a)-   fmap fab (Branch ta2 ta3) = Branch (fmap fab ta2) (fmap fab ta3)
+ test/golden/GoldenFoldr.expected.hs view
@@ -0,0 +1,3 @@+foldr2 :: (a -> b -> b) -> b -> [a] -> b+foldr2 _ b [] = b+foldr2 fabb b (a : as') = fabb a (foldr2 fabb b as')
− test/golden/GoldenFoldr.hs.expected
@@ -1,3 +0,0 @@-foldr2 :: (a -> b -> b) -> b -> [a] -> b-foldr2 _ b [] = b-foldr2 f_b b (a : l_a4) = f_b a (foldr2 f_b b l_a4)
+ test/golden/GoldenFromMaybe.expected.hs view
@@ -0,0 +1,3 @@+fromMaybe :: a -> Maybe a -> a+fromMaybe a Nothing = a+fromMaybe _ (Just a') = a'
− test/golden/GoldenFromMaybe.hs.expected
@@ -1,3 +0,0 @@-fromMaybe :: a -> Maybe a -> a-fromMaybe a Nothing = a-fromMaybe _ (Just a2) = a2
+ test/golden/GoldenGADTAuto.expected.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE GADTs #-}+module GoldenGADTAuto where+data CtxGADT a where+  MkCtxGADT :: (Show a, Eq a) => a -> CtxGADT a++ctxGADT :: CtxGADT ()+ctxGADT = MkCtxGADT ()
− test/golden/GoldenGADTAuto.hs.expected
@@ -1,7 +0,0 @@-{-# LANGUAGE GADTs #-}-module GoldenGADTAuto where-data CtxGADT a where-  MkCtxGADT :: (Show a, Eq a) => a -> CtxGADT a--ctxGADT :: CtxGADT ()-ctxGADT = MkCtxGADT ()
+ test/golden/GoldenGADTDestruct.expected.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE GADTs #-}+module GoldenGADTDestruct where+data CtxGADT where+  MkCtxGADT :: (Show a, Eq a) => a -> CtxGADT++ctxGADT :: CtxGADT -> String+ctxGADT (MkCtxGADT a) = _
− test/golden/GoldenGADTDestruct.hs.expected
@@ -1,7 +0,0 @@-{-# LANGUAGE GADTs #-}-module GoldenGADTDestruct where-data CtxGADT where-  MkCtxGADT :: (Show a, Eq a) => a -> CtxGADT--ctxGADT :: CtxGADT -> String-ctxGADT (MkCtxGADT a) = _
+ test/golden/GoldenGADTDestructCoercion.expected.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE GADTs #-}+module GoldenGADTDestruct where+data E a b where+  E :: forall a b. (b ~ a, Ord a) => b -> E a [a]++ctxGADT :: E a b -> String+ctxGADT (E b) = _
− test/golden/GoldenGADTDestructCoercion.hs.expected
@@ -1,8 +0,0 @@-{-# LANGUAGE RankNTypes #-}-{-# LANGUAGE GADTs #-}-module GoldenGADTDestruct where-data E a b where-  E :: forall a b. (b ~ a, Ord a) => b -> E a [a]--ctxGADT :: E a b -> String-ctxGADT (E b) = _
+ test/golden/GoldenIdTypeFam.expected.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE TypeFamilies #-}++type family TyFam+type instance TyFam = Int++tyblah' :: TyFam -> Int+tyblah' = id
− test/golden/GoldenIdTypeFam.hs.expected
@@ -1,7 +0,0 @@-{-# LANGUAGE TypeFamilies #-}--type family TyFam-type instance TyFam = Int--tyblah' :: TyFam -> Int-tyblah' = id
+ test/golden/GoldenIdentityFunctor.expected.hs view
@@ -0,0 +1,3 @@+data Ident a = Ident a+instance Functor Ident where+   fmap fab (Ident a) = Ident (fab a)
− test/golden/GoldenIdentityFunctor.hs.expected
@@ -1,3 +0,0 @@-data Ident a = Ident a-instance Functor Ident where-   fmap fab (Ident a) = Ident (fab a)
+ test/golden/GoldenIntros.expected.hs view
@@ -0,0 +1,2 @@+blah :: Int -> Bool -> (a -> b) -> String -> Int+blah n b fab s = _
− test/golden/GoldenIntros.hs.expected
@@ -1,2 +0,0 @@-blah :: Int -> Bool -> (a -> b) -> String -> Int-blah i b fab l_c = _
+ test/golden/GoldenJoinCont.expected.hs view
@@ -0,0 +1,4 @@+type Cont r a = ((a -> r) -> r)++joinCont :: Cont r (Cont r a) -> Cont r a+joinCont f far = f (\ g -> g far)
− test/golden/GoldenJoinCont.hs.expected
@@ -1,4 +0,0 @@-type Cont r a = ((a -> r) -> r)--joinCont :: Cont r (Cont r a) -> Cont r a-joinCont f_r far = f_r (\ f_r2 -> f_r2 far)
+ test/golden/GoldenListFmap.expected.hs view
@@ -0,0 +1,3 @@+fmapList :: (a -> b) -> [a] -> [b]+fmapList _ [] = []+fmapList fab (a : as') = fab a : fmapList fab as'
− test/golden/GoldenListFmap.hs.expected
@@ -1,3 +0,0 @@-fmapList :: (a -> b) -> [a] -> [b]-fmapList _ [] = []-fmapList fab (a : l_a3) = fab a : fmapList fab l_a3
+ test/golden/GoldenNote.expected.hs view
@@ -0,0 +1,3 @@+note :: e -> Maybe a -> Either e a+note e Nothing = Left e+note _ (Just a) = Right a
− test/golden/GoldenNote.hs.expected
@@ -1,3 +0,0 @@-note :: e -> Maybe a -> Either e a-note e Nothing = Left e-note _ (Just a) = Right a
+ test/golden/GoldenPureList.expected.hs view
@@ -0,0 +1,2 @@+pureList :: a -> [a]+pureList a = a : []
− test/golden/GoldenPureList.hs.expected
@@ -1,2 +0,0 @@-pureList :: a -> [a]-pureList a = a : []
+ test/golden/GoldenSafeHead.expected.hs view
@@ -0,0 +1,3 @@+safeHead :: [x] -> Maybe x+safeHead [] = Nothing+safeHead (x : _) = Just x
− test/golden/GoldenSafeHead.hs.expected
@@ -1,3 +0,0 @@-safeHead :: [x] -> Maybe x-safeHead [] = Nothing-safeHead (x : _) = Just x
+ test/golden/GoldenShow.expected.hs view
@@ -0,0 +1,2 @@+showMe :: Show a => a -> String+showMe = show
− test/golden/GoldenShow.hs.expected
@@ -1,2 +0,0 @@-showMe :: Show a => a -> String-showMe = show
+ test/golden/GoldenShowCompose.expected.hs view
@@ -0,0 +1,2 @@+showCompose :: Show a => (b -> a) -> b -> String+showCompose fba = show . fba
− test/golden/GoldenShowCompose.hs.expected
@@ -1,2 +0,0 @@-showCompose :: Show a => (b -> a) -> b -> String-showCompose fba = show . fba
+ test/golden/GoldenShowMapChar.expected.hs view
@@ -0,0 +1,2 @@+test :: Show a => a -> (String -> b) -> b+test a f = f (show a)
− test/golden/GoldenShowMapChar.hs.expected
@@ -1,2 +0,0 @@-test :: Show a => a -> (String -> b) -> b-test a fl_cb = fl_cb (show a)
+ test/golden/GoldenSuperclass.expected.hs view
@@ -0,0 +1,8 @@+class Super a where+    super :: a++class Super a => Sub a++blah :: Sub a => a+blah = super+
− test/golden/GoldenSuperclass.hs.expected
@@ -1,8 +0,0 @@-class Super a where-    super :: a--class Super a => Sub a--blah :: Sub a => a-blah = super-
+ test/golden/GoldenSwap.expected.hs view
@@ -0,0 +1,2 @@+swap :: (a, b) -> (b, a)+swap (a, b) = (b, a)
− test/golden/GoldenSwap.hs.expected
@@ -1,2 +0,0 @@-swap :: (a, b) -> (b, a)-swap (a, b) = (b, a)
+ test/golden/GoldenSwapMany.expected.hs view
@@ -0,0 +1,2 @@+swapMany :: (a, b, c, d, e) -> (e, d, c, b, a)+swapMany (a, b, c, d, e) = (e, d, c, b, a)
− test/golden/GoldenSwapMany.hs.expected
@@ -1,2 +0,0 @@-swapMany :: (a, b, c, d, e) -> (e, d, c, b, a)-swapMany (a, b, c, d, e) = (e, d, c, b, a)
+ test/golden/KnownBigSemigroup.expected.hs view
@@ -0,0 +1,9 @@+import Data.Monoid++data Big a = Big [Bool] (Sum Int) String (Endo a) Any++instance Semigroup (Big a) where+  (<>) (Big bs sum s en any) (Big bs' sum' str en' any')+    = Big+        (bs <> bs') (sum <> sum') (s <> str) (en <> en') (any <> any')+
− test/golden/KnownBigSemigroup.hs.expected
@@ -1,9 +0,0 @@-import Data.Monoid--data Big a = Big [Bool] (Sum Int) String (Endo a) Any--instance Semigroup (Big a) where-  (<>) (Big l_b7 si8 l_c9 ea10 a11) (Big l_b si l_c ea a)-    = Big-        (l_b7 <> l_b) (si8 <> si) (l_c9 <> l_c) (ea10 <> ea) (a11 <> a)-
+ test/golden/KnownCounterfactualSemigroup.expected.hs view
@@ -0,0 +1,7 @@+{-# LANGUAGE UndecidableInstances #-}++data Semi = Semi [String] Int++instance Semigroup Int => Semigroup Semi where+  (<>) (Semi ss n) (Semi strs i) = Semi (ss <> strs) (n <> i)+
− test/golden/KnownCounterfactualSemigroup.hs.expected
@@ -1,8 +0,0 @@-{-# LANGUAGE UndecidableInstances #-}--data Semi = Semi [String] Int--instance Semigroup Int => Semigroup Semi where-  (<>) (Semi l_l_c5 i6) (Semi l_l_c i)-    = Semi (l_l_c5 <> l_l_c) (i6 <> i)-
+ test/golden/KnownDestructedSemigroup.expected.hs view
@@ -0,0 +1,5 @@+data Test a = Test [a]++instance Semigroup (Test a) where+  (<>) (Test a) (Test c) = Test (a <> c)+
− test/golden/KnownDestructedSemigroup.hs.expected
@@ -1,5 +0,0 @@-data Test a = Test [a]--instance Semigroup (Test a) where-  (<>) (Test a) (Test c) = Test (a <> c)-
+ test/golden/KnownMissingMonoid.expected.hs view
@@ -0,0 +1,8 @@+data Mono a = Monoid [String] a++instance Semigroup (Mono a) where+  (<>) = undefined++instance Monoid (Mono a) where+  mempty = Monoid mempty _+
− test/golden/KnownMissingMonoid.hs.expected
@@ -1,8 +0,0 @@-data Mono a = Monoid [String] a--instance Semigroup (Mono a) where-  (<>) = undefined--instance Monoid (Mono a) where-  mempty = Monoid mempty _-
+ test/golden/KnownMissingSemigroup.expected.hs view
@@ -0,0 +1,5 @@+data Semi = Semi [String] Int++instance Semigroup Semi where+  (<>) (Semi ss n) (Semi strs i) = Semi (ss <> strs) _+
− test/golden/KnownMissingSemigroup.hs.expected
@@ -1,5 +0,0 @@-data Semi = Semi [String] Int--instance Semigroup Semi where-  (<>) (Semi l_l_c4 i5) (Semi l_l_c i) = Semi (l_l_c4 <> l_l_c) _-
+ test/golden/KnownModuleInstanceSemigroup.expected.hs view
@@ -0,0 +1,12 @@+data Foo = Foo++instance Semigroup Foo where+  (<>) _ _ = Foo+++data Bar = Bar Foo Foo++instance Semigroup Bar where+  (<>) (Bar foo foo') (Bar foo2 foo3)+    = Bar (foo <> foo2) (foo' <> foo3)+
− test/golden/KnownModuleInstanceSemigroup.hs.expected
@@ -1,11 +0,0 @@-data Foo = Foo--instance Semigroup Foo where-  (<>) _ _ = Foo---data Bar = Bar Foo Foo--instance Semigroup Bar where-  (<>) (Bar f4 f5) (Bar f f3) = Bar (f4 <> f) (f5 <> f3)-
+ test/golden/KnownMonoid.expected.hs view
@@ -0,0 +1,8 @@+data Mono = Monoid [String]++instance Semigroup Mono where+  (<>) = undefined++instance Monoid Mono where+  mempty = Monoid mempty+
− test/golden/KnownMonoid.hs.expected
@@ -1,8 +0,0 @@-data Mono = Monoid [String]--instance Semigroup Mono where-  (<>) = undefined--instance Monoid Mono where-  mempty = Monoid mempty-
+ test/golden/KnownPolyMonoid.expected.hs view
@@ -0,0 +1,8 @@+data Mono a = Monoid [String] a++instance Semigroup (Mono a) where+  (<>) = undefined++instance Monoid a => Monoid (Mono a) where+  mempty = Monoid mempty mempty+
− test/golden/KnownPolyMonoid.hs.expected
@@ -1,8 +0,0 @@-data Mono a = Monoid [String] a--instance Semigroup (Mono a) where-  (<>) = undefined--instance Monoid a => Monoid (Mono a) where-  mempty = Monoid mempty mempty-
+ test/golden/KnownThetaSemigroup.expected.hs view
@@ -0,0 +1,5 @@+data Semi a = Semi a++instance Semigroup a => Semigroup (Semi a) where+  (<>) (Semi a) (Semi a') = Semi (a <> a')+
− test/golden/KnownThetaSemigroup.hs.expected
@@ -1,5 +0,0 @@-data Semi a = Semi a--instance Semigroup a => Semigroup (Semi a) where-  (<>) (Semi a4) (Semi a) = Semi (a4 <> a)-
+ test/golden/LayoutBind.expected.hs view
@@ -0,0 +1,8 @@+test :: Bool -> IO ()+test b = do+  putStrLn "hello"+  case b of+    False -> _+    True -> _+  pure ()+
− test/golden/LayoutBind.hs.expected
@@ -1,8 +0,0 @@-test :: Bool -> IO ()-test b = do-  putStrLn "hello"-  case b of-    False -> _-    True -> _-  pure ()-
+ test/golden/LayoutDollarApp.expected.hs view
@@ -0,0 +1,5 @@+test :: Bool -> Bool+test b = id $ (case b of+   False -> _+   True -> _)+
− test/golden/LayoutDollarApp.hs.expected
@@ -1,5 +0,0 @@-test :: Bool -> Bool-test b = id $ (case b of-   False -> _-   True -> _)-
+ test/golden/LayoutLam.expected.hs view
@@ -0,0 +1,5 @@+test :: Bool -> Bool+test = \b -> case b of+  False -> _+  True -> _+
− test/golden/LayoutLam.hs.expected
@@ -1,5 +0,0 @@-test :: Bool -> Bool-test = \b -> case b of-  False -> _-  True -> _-
+ test/golden/LayoutOpApp.expected.hs view
@@ -0,0 +1,4 @@+test :: Bool -> Bool+test b = True && (case b of+   False -> _+   True -> _)
− test/golden/LayoutOpApp.hs.expected
@@ -1,4 +0,0 @@-test :: Bool -> Bool-test b = True && (case b of-   False -> _-   True -> _)
+ test/golden/LayoutRec.expected.hs view
@@ -0,0 +1,5 @@+data Pair a b = Pair {pa :: a, pb :: b}++p :: Pair (a -> a) (a -> b -> c -> b)+p = Pair {pa = _, pb = \ a b c -> _}+
+ test/golden/LayoutRec.hs view
@@ -0,0 +1,5 @@+data Pair a b = Pair {pa :: a, pb :: b}++p :: Pair (a -> a) (a -> b -> c -> b)+p = Pair {pa = _, pb = _}+
+ test/golden/LayoutSplitClass.expected.hs view
@@ -0,0 +1,5 @@+class Test a where+  test :: Bool -> a+  test False = _+  test True = _+
− test/golden/LayoutSplitClass.hs.expected
@@ -1,5 +0,0 @@-class Test a where-  test :: Bool -> a-  test False = _-  test True = _-
+ test/golden/LayoutSplitGuard.expected.hs view
@@ -0,0 +1,5 @@+test :: Bool -> Bool -> Bool+test a b+  | a = case b of+  False -> _+  True -> _
− test/golden/LayoutSplitGuard.hs.expected
@@ -1,5 +0,0 @@-test :: Bool -> Bool -> Bool-test a b-  | a = (case b of-   False -> _-   True -> _)
+ test/golden/LayoutSplitIn.expected.hs view
@@ -0,0 +1,5 @@+test :: a+test =+  let a = (1,"bbb")+   in case a of { (n, s) -> _ }+
− test/golden/LayoutSplitIn.hs.expected
@@ -1,5 +0,0 @@-test :: a-test =-  let a = (1,"bbb")-   in case a of { (i, l_c) -> _ }-
+ test/golden/LayoutSplitLet.expected.hs view
@@ -0,0 +1,7 @@+test :: a+test =+  let t :: Bool -> a+      t False = _+      t True = _+   in _+
− test/golden/LayoutSplitLet.hs.expected
@@ -1,7 +0,0 @@-test :: a-test =-  let t :: Bool -> a-      t False = _-      t True = _-   in _-
+ test/golden/LayoutSplitPatSyn.expected.hs view
@@ -0,0 +1,11 @@+{-# LANGUAGE PatternSynonyms #-}++pattern JustSingleton :: a -> Maybe [a]+pattern JustSingleton a <- Just [a]+++test :: Maybe [Bool] -> Maybe Bool+test (JustSingleton False) = _+test (JustSingleton True) = _++
− test/golden/LayoutSplitPatSyn.hs.expected
@@ -1,11 +0,0 @@-{-# LANGUAGE PatternSynonyms #-}--pattern JustSingleton :: a -> Maybe [a]-pattern JustSingleton a <- Just [a]---test :: Maybe [Bool] -> Maybe Bool-test (JustSingleton False) = _-test (JustSingleton True) = _--
+ test/golden/LayoutSplitPattern.expected.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE PatternSynonyms #-}++pattern Blah :: a -> Maybe a+pattern Blah a = Just a++test :: Maybe Bool -> a+test (Blah False) = _+test (Blah True) = _+
− test/golden/LayoutSplitPattern.hs.expected
@@ -1,9 +0,0 @@-{-# LANGUAGE PatternSynonyms #-}--pattern Blah :: a -> Maybe a-pattern Blah a = Just a--test :: Maybe Bool -> a-test (Blah False) = _-test (Blah True) = _-
+ test/golden/LayoutSplitViewPat.expected.hs view
@@ -0,0 +1,6 @@+{-# LANGUAGE ViewPatterns #-}++splitLookup :: [(Int, String)] -> String+splitLookup (lookup 5 -> Nothing) = _+splitLookup (lookup 5 -> (Just s)) = _+
− test/golden/LayoutSplitViewPat.hs.expected
@@ -1,6 +0,0 @@-{-# LANGUAGE ViewPatterns #-}--splitLookup :: [(Int, String)] -> String-splitLookup (lookup 5 -> Nothing) = _-splitLookup (lookup 5 -> (Just l_c)) = _-
+ test/golden/LayoutSplitWhere.expected.hs view
@@ -0,0 +1,14 @@+data A = A | B | C++some :: A -> IO ()+some a = do+    foo+    bar a+  where+      foo = putStrLn "Hi"++      bar :: A -> IO ()+      bar A = _+      bar B = _+      bar C = _+
− test/golden/LayoutSplitWhere.hs.expected
@@ -1,14 +0,0 @@-data A = A | B | C--some :: A -> IO ()-some a = do-    foo-    bar a-  where-      foo = putStrLn "Hi"--      bar :: A -> IO ()-      bar A = _-      bar B = _-      bar C = _-
+ test/golden/MessageCantUnify.hs view
@@ -0,0 +1,8 @@+{-# LANGUAGE DataKinds, GADTs #-}++data Z ab where+  Z :: (a -> b) -> Z '(a, b)++test :: Z ab+test = _+
+ test/golden/MetaBegin.expected.hs view
@@ -0,0 +1,1 @@+foo = [wingman||]
+ test/golden/MetaBegin.hs view
@@ -0,0 +1,1 @@+foo = _
+ test/golden/MetaBindAll.expected.hs view
@@ -0,0 +1,2 @@+foo :: a -> (a, a)+foo a = (a, a)
+ test/golden/MetaBindAll.hs view
@@ -0,0 +1,2 @@+foo :: a -> (a, a)+foo a = [wingman| split; assumption |]
+ test/golden/MetaBindOne.expected.hs view
@@ -0,0 +1,2 @@+foo :: a -> (a, a)+foo a = (a, _)
+ test/golden/MetaBindOne.hs view
@@ -0,0 +1,2 @@+foo :: a -> (a, a)+foo a = [wingman| split, assumption |]
+ test/golden/MetaCataCollapse.expected.hs view
@@ -0,0 +1,14 @@+{-# LANGUAGE TypeOperators #-}++import GHC.Generics++class Yo f where+    yo :: f x -> Int++instance (Yo f, Yo g) => Yo (f :*: g) where+  yo (fx :*: gx)+    = let+        fx_c = yo fx+        gx_c = yo gx+      in _ fx_c gx_c+
+ test/golden/MetaCataCollapse.hs view
@@ -0,0 +1,10 @@+{-# LANGUAGE TypeOperators #-}++import GHC.Generics++class Yo f where+    yo :: f x -> Int++instance (Yo f, Yo g) => Yo (f :*: g) where+  yo = [wingman| intros x, cata x, collapse |]+
+ test/golden/MetaCataCollapseUnary.expected.hs view
@@ -0,0 +1,8 @@+import GHC.Generics++class Yo f where+    yo :: f x -> Int++instance (Yo f) => Yo (M1 _1 _2 f) where+  yo (M1 fx) = yo fx+
+ test/golden/MetaCataCollapseUnary.hs view
@@ -0,0 +1,8 @@+import GHC.Generics++class Yo f where+    yo :: f x -> Int++instance (Yo f) => Yo (M1 _1 _2 f) where+  yo = [wingman| intros x, cata x, collapse |]+
+ test/golden/MetaChoice.expected.hs view
@@ -0,0 +1,2 @@+reassoc :: (a, (b, c)) -> ((a, b), c)+reassoc (a, (b, c)) = ((a, b), c)
+ test/golden/MetaChoice.hs view
@@ -0,0 +1,2 @@+reassoc :: (a, (b, c)) -> ((a, b), c)+reassoc (a, (b, c)) = [wingman| split; split | assume c; assume a | assume b |]
+ test/golden/MetaMaybeAp.expected.hs view
@@ -0,0 +1,5 @@+maybeAp :: Maybe (a -> b) -> Maybe a -> Maybe b+maybeAp Nothing Nothing = Nothing+maybeAp Nothing (Just _) = Nothing+maybeAp (Just _) Nothing = Nothing+maybeAp (Just fab) (Just a) = Just (fab a)
+ test/golden/MetaMaybeAp.hs view
@@ -0,0 +1,11 @@+maybeAp :: Maybe (a -> b) -> Maybe a -> Maybe b+maybeAp = [wingman|+  intros,+  destruct_all,+  obvious,+  obvious,+  obvious,+  ctor Just,+  application,+  assumption+  |]
+ test/golden/MetaTry.expected.hs view
@@ -0,0 +1,2 @@+foo :: a -> (b, a)+foo a = (_, a)
+ test/golden/MetaTry.hs view
@@ -0,0 +1,2 @@+foo :: a -> (b, a)+foo a = [wingman| split; try assumption |]
+ test/golden/MetaUseImport.expected.hs view
@@ -0,0 +1,6 @@+import Data.Char+++result :: Char -> Bool+result = isAlpha+
+ test/golden/MetaUseImport.hs view
@@ -0,0 +1,6 @@+import Data.Char+++result :: Char -> Bool+result = [wingman| intro c, use isAlpha, assume c |]+
+ test/golden/MetaUseLocal.expected.hs view
@@ -0,0 +1,7 @@+test :: Int+test = 0+++resolve :: Int+resolve = test+
+ test/golden/MetaUseLocal.hs view
@@ -0,0 +1,7 @@+test :: Int+test = 0+++resolve :: Int+resolve = [wingman| use test |]+
+ test/golden/MetaUseMethod.expected.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE MultiParamTypeClasses #-}++class Test where+  test :: Int++instance Test where+  test = 10+++resolve :: Int+resolve = test+
+ test/golden/MetaUseMethod.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE MultiParamTypeClasses #-}++class Test where+  test :: Int++instance Test where+  test = 10+++resolve :: Int+resolve = [wingman| use test |]+
+ test/golden/NewtypeRecord.expected.hs view
@@ -0,0 +1,7 @@+newtype MyRecord a = Record+    { field1 :: a+    }++blah :: (a -> Int) -> a -> MyRecord a+blah _ = Record+
− test/golden/NewtypeRecord.hs.expected
@@ -1,7 +0,0 @@-newtype MyRecord a = Record-    { field1 :: a-    }--blah :: (a -> Int) -> a -> MyRecord a-blah _ = Record-
+ test/golden/PunGADT.expected.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE GADTs #-}++data GADT a where+  GADT ::+    { blah :: Int+    , bar :: a+    } -> GADT a+++split :: GADT a -> a+split GADT {blah, bar} = _+
+ test/golden/PunGADT.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE GADTs #-}++data GADT a where+  GADT ::+    { blah :: Int+    , bar :: a+    } -> GADT a+++split :: GADT a -> a+split x = _+
+ test/golden/PunMany.expected.hs view
@@ -0,0 +1,8 @@+data Many+  = Hello { world :: String }+  | Goodbye { a :: Int, b :: Bool, c :: Many }++test :: Many -> Many+test Hello {world} = _+test Goodbye {a, b, c} = _+
+ test/golden/PunMany.hs view
@@ -0,0 +1,7 @@+data Many+  = Hello { world :: String }+  | Goodbye { a :: Int, b :: Bool, c :: Many }++test :: Many -> Many+test x = _+
+ test/golden/PunManyGADT.expected.hs view
@@ -0,0 +1,19 @@+{-# LANGUAGE GADTs #-}++data GADT a where+  GADT ::+    { blah :: Int+    , bar :: a+    } -> GADT a+  Bar ::+    { zoo :: Bool+    , baxter :: a+    , another :: a+    } -> GADT Bool+  Baz :: GADT Int+++split :: GADT Bool -> a+split GADT {blah, bar} = _+split Bar {zoo, baxter, another} = _+
+ test/golden/PunManyGADT.hs view
@@ -0,0 +1,18 @@+{-# LANGUAGE GADTs #-}++data GADT a where+  GADT ::+    { blah :: Int+    , bar :: a+    } -> GADT a+  Bar ::+    { zoo :: Bool+    , baxter :: a+    , another :: a+    } -> GADT Bool+  Baz :: GADT Int+++split :: GADT Bool -> a+split x = _+
+ test/golden/PunShadowing.expected.hs view
@@ -0,0 +1,5 @@+data Bar = Bar { ax :: Int, bax :: Bool }++bar :: () -> Bar -> Int+bar ax Bar {ax = n, bax} = _+
+ test/golden/PunShadowing.hs view
@@ -0,0 +1,5 @@+data Bar = Bar { ax :: Int, bax :: Bool }++bar :: () -> Bar -> Int+bar ax x = _+
+ test/golden/PunSimple.expected.hs view
@@ -0,0 +1,5 @@+data Bar = Bar { ax :: Int, bax :: Bool }++bar :: Bar -> Int+bar Bar {ax, bax} = _+
+ test/golden/PunSimple.hs view
@@ -0,0 +1,5 @@+data Bar = Bar { ax :: Int, bax :: Bool }++bar :: Bar -> Int+bar x = _+
+ test/golden/RecordCon.expected.hs view
@@ -0,0 +1,9 @@+data MyRecord a = Record+    { field1 :: a+    , field2 :: Int+    }++blah :: (a -> Int) -> a -> MyRecord a+blah f a = Record {field1 = a, field2 = f a}++
− test/golden/RecordCon.hs.expected
@@ -1,9 +0,0 @@-data MyRecord a = Record-    { field1 :: a-    , field2 :: Int-    }--blah :: (a -> Int) -> a -> MyRecord a-blah fai a = Record {field1 = a, field2 = fai a}--
+ test/golden/RefineCon.expected.hs view
@@ -0,0 +1,3 @@+test :: ((), (b, c), d)+test = (_, _, _)+
− test/golden/RefineCon.hs.expected
@@ -1,3 +0,0 @@-test :: ((), (b, c), d)-test = (_, _, _)-
+ test/golden/RefineGADT.expected.hs view
@@ -0,0 +1,9 @@+{-# LANGUAGE GADTs #-}++data GADT a where+  One :: (b -> Int) -> GADT Int+  Two :: GADT Bool++test :: z -> GADT Int+test z = One _+
test/golden/RefineGADT.hs view
@@ -5,5 +5,5 @@   Two :: GADT Bool  test :: z -> GADT Int-test = _+test z = _ 
− test/golden/RefineGADT.hs.expected
@@ -1,9 +0,0 @@-{-# LANGUAGE GADTs #-}--data GADT a where-  One :: (b -> Int) -> GADT Int-  Two :: GADT Bool--test :: z -> GADT Int-test z = One (\ b -> _)-
+ test/golden/RefineIntro.expected.hs view
@@ -0,0 +1,2 @@+test :: a -> Either a b+test a = _
− test/golden/RefineIntro.hs.expected
@@ -1,2 +0,0 @@-test :: a -> Either a b-test a = _
+ test/golden/RefineReader.expected.hs view
@@ -0,0 +1,5 @@+newtype Reader r a = Reader (r -> a)++test :: b -> Reader r a+test b = Reader _+
test/golden/RefineReader.hs view
@@ -1,5 +1,5 @@ newtype Reader r a = Reader (r -> a)  test :: b -> Reader r a-test = _+test b = _ 
− test/golden/RefineReader.hs.expected
@@ -1,5 +0,0 @@-newtype Reader r a = Reader (r -> a)--test :: b -> Reader r a-test b = Reader (\ r -> _)-
+ test/golden/SplitPattern.expected.hs view
@@ -0,0 +1,12 @@+data ADT = One | Two Int | Three | Four Bool ADT | Five++case_split :: ADT -> Int+case_split One        = _+case_split (Two i)    = _+case_split Three      = _+case_split (Four b One) = _+case_split (Four b (Two n)) = _+case_split (Four b Three) = _+case_split (Four b (Four b' adt)) = _+case_split (Four b Five) = _+case_split Five       = _
− test/golden/SplitPattern.hs.expected
@@ -1,12 +0,0 @@-data ADT = One | Two Int | Three | Four Bool ADT | Five--case_split :: ADT -> Int-case_split One        = _-case_split (Two i)    = _-case_split Three      = _-case_split (Four b One) = _-case_split (Four b (Two i)) = _-case_split (Four b Three) = _-case_split (Four b (Four b3 a4)) = _-case_split (Four b Five) = _-case_split Five       = _
+ test/golden/UseConLeft.expected.hs view
@@ -0,0 +1,3 @@+test :: Either a b+test = Left _+
− test/golden/UseConLeft.hs.expected
@@ -1,3 +0,0 @@-test :: Either a b-test = Left _-
+ test/golden/UseConPair.expected.hs view
@@ -0,0 +1,2 @@+test :: (a, b)+test = (_, _)
− test/golden/UseConPair.hs.expected
@@ -1,2 +0,0 @@-test :: (a, b)-test = (_, _)
+ test/golden/UseConRight.expected.hs view
@@ -0,0 +1,3 @@+test :: Either a b+test = Right _+
− test/golden/UseConRight.hs.expected
@@ -1,3 +0,0 @@-test :: Either a b-test = Right _-