    {-# LANGUAGE ExistentialQuantification #-}
    module GHC.Tc.Errors.Hole.FitTypes (
      TypedHole (..), HoleFit (..), HoleFitCandidate (..),
      hfIsLcl, pprHoleFitCand
      ) where

    import GHC.Prelude

    import GHC.Tc.Types.Constraint
    import GHC.Tc.Utils.TcType

    import GHC.Types.Name.Reader

    import GHC.Hs.Doc
    import GHC.Types.Id

    import GHC.Utils.Outputable
    import GHC.Types.Name

    import GHC.Data.Bag

    import Data.Function ( on )

    data TypedHole = TypedHole { TypedHole -> Bag CtEvidence
    th_relevant_cts :: Bag CtEvidence
                               -- ^ Any relevant Cts to the hole
                               , TypedHole -> [Implication]
    th_implics :: [Implication]
                               -- ^ The nested implications of the hole with the
                               --   innermost implication first.
                               , TypedHole -> Maybe Hole
    th_hole :: Maybe Hole
                               -- ^ The hole itself, if available.
                               }

    instance Outputable TypedHole where
      ppr :: TypedHole -> SDoc
    ppr (TypedHole { th_relevant_cts :: TypedHole -> Bag CtEvidence
    th_relevant_cts = Bag CtEvidence
    rels
                     , th_implics :: TypedHole -> [Implication]
    th_implics      = [Implication]
    implics
                     , th_hole :: TypedHole -> Maybe Hole
    th_hole         = Maybe Hole
    hole })
        = SDoc -> Int -> SDoc -> SDoc
    hang (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "TypedHole") Int
    2
            (Bag CtEvidence -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Bag CtEvidence
    rels SDoc -> SDoc -> SDoc
    $+$ [Implication] -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr [Implication]
    implics SDoc -> SDoc -> SDoc
    $+$ Maybe Hole -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Maybe Hole
    hole)

    -- | HoleFitCandidates are passed to hole fit plugins and then
    -- checked whether they fit a given typed-hole.
    data HoleFitCandidate = IdHFCand Id             -- An id, like locals.
                          | NameHFCand Name         -- A name, like built-in syntax.
                          | GreHFCand GlobalRdrElt  -- A global, like imported ids.

    instance Eq HoleFitCandidate where
      IdHFCand Id
    i1 == :: HoleFitCandidate -> HoleFitCandidate -> Bool
    == IdHFCand Id
    i2 = Id
    i1 Id -> Id -> Bool
    forall a. Eq a => a -> a -> Bool
    == Id
    i2
      NameHFCand Name
    n1 == NameHFCand Name
    n2 = Name
    n1 Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Name
    n2
      GreHFCand GlobalRdrElt
    gre1 == GreHFCand GlobalRdrElt
    gre2 = GlobalRdrElt -> Name
    forall info. GlobalRdrEltX info -> Name
    greName GlobalRdrElt
    gre1 Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == GlobalRdrElt -> Name
    forall info. GlobalRdrEltX info -> Name
    greName GlobalRdrElt
    gre2
      HoleFitCandidate
    _ == HoleFitCandidate
    _ = Bool
    False

    instance Outputable HoleFitCandidate where
      ppr :: HoleFitCandidate -> SDoc
    ppr = HoleFitCandidate -> SDoc
    pprHoleFitCand

    pprHoleFitCand :: HoleFitCandidate -> SDoc
    pprHoleFitCand :: HoleFitCandidate -> SDoc
    pprHoleFitCand (IdHFCand Id
    cid) = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Id HFC: " SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Id -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Id
    cid
    pprHoleFitCand (NameHFCand Name
    cname) = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Name HFC: " SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> Name -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr Name
    cname
    pprHoleFitCand (GreHFCand GlobalRdrElt
    cgre) = String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "Gre HFC: " SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <> GlobalRdrElt -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr GlobalRdrElt
    cgre

    instance NamedThing HoleFitCandidate where
      getName :: HoleFitCandidate -> Name
    getName HoleFitCandidate
    hfc = case HoleFitCandidate
    hfc of
                         IdHFCand Id
    cid -> Id -> Name
    idName Id
    cid
                         NameHFCand Name
    cname -> Name
    cname
                         GreHFCand GlobalRdrElt
    cgre -> GlobalRdrElt -> Name
    forall info. GlobalRdrEltX info -> Name
    greName GlobalRdrElt
    cgre
      getOccName :: HoleFitCandidate -> OccName
    getOccName HoleFitCandidate
    hfc = case HoleFitCandidate
    hfc of
                         IdHFCand Id
    cid -> Id -> OccName
    forall name. HasOccName name => name -> OccName
    occName Id
    cid
                         NameHFCand Name
    cname -> Name -> OccName
    forall name. HasOccName name => name -> OccName
    occName Name
    cname
                         GreHFCand GlobalRdrElt
    cgre -> Name -> OccName
    forall name. HasOccName name => name -> OccName
    occName (Name -> OccName) -> Name -> OccName
    forall a b. (a -> b) -> a -> b
    $ GlobalRdrElt -> Name
    forall info. GlobalRdrEltX info -> Name
    greName GlobalRdrElt
    cgre

    instance HasOccName HoleFitCandidate where
      occName :: HoleFitCandidate -> OccName
    occName = HoleFitCandidate -> OccName
    forall a. NamedThing a => a -> OccName
    getOccName

    instance Ord HoleFitCandidate where
      compare :: HoleFitCandidate -> HoleFitCandidate -> Ordering
    compare = Name -> Name -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare (Name -> Name -> Ordering)
    -> (HoleFitCandidate -> Name)
    -> HoleFitCandidate
    -> HoleFitCandidate
    -> Ordering
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` HoleFitCandidate -> Name
    forall a. NamedThing a => a -> Name
    getName

    -- | HoleFit is the type we use for valid hole fits. It contains the
    -- element that was checked, the Id of that element as found by `tcLookup`,
    -- and the refinement level of the fit, which is the number of extra argument
    -- holes that this fit uses (e.g. if hfRefLvl is 2, the fit is for `Id _ _`).
    data HoleFit =
      HoleFit { HoleFit -> Id
    hfId   :: Id       -- ^ The elements id in the TcM
              , HoleFit -> HoleFitCandidate
    hfCand :: HoleFitCandidate  -- ^ The candidate that was checked.
              , HoleFit -> TcType
    hfType :: TcType -- ^ The type of the id, possibly zonked.
              , HoleFit -> Int
    hfRefLvl :: Int  -- ^ The number of holes in this fit.
              , HoleFit -> [TcType]
    hfWrap :: [TcType] -- ^ The wrapper for the match.
              , HoleFit -> [TcType]
    hfMatches :: [TcType]
              -- ^ What the refinement variables got matched with, if anything
              , HoleFit -> Maybe [HsDocString]
    hfDoc :: Maybe [HsDocString]
              -- ^ Documentation of this HoleFit, if available.
              }
     | RawHoleFit SDoc
     -- ^ A fit that is just displayed as is. Here so thatHoleFitPlugins
     --   can inject any fit they want.

    -- We define an Eq and Ord instance to be able to build a graph.
    instance Eq HoleFit where
       == :: HoleFit -> HoleFit -> Bool
    (==) = Id -> Id -> Bool
    forall a. Eq a => a -> a -> Bool
    (==) (Id -> Id -> Bool) -> (HoleFit -> Id) -> HoleFit -> HoleFit -> Bool
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` HoleFit -> Id
    hfId

    instance Outputable HoleFit where
      ppr :: HoleFit -> SDoc
    ppr (RawHoleFit SDoc
    sd) = SDoc
    sd
      ppr (HoleFit Id
    _ HoleFitCandidate
    cand TcType
    ty Int
    _ [TcType]
    _ [TcType]
    mtchs Maybe [HsDocString]
    _) =
        SDoc -> Int -> SDoc -> SDoc
    hang (SDoc
    name SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> SDoc
    holes) Int
    2 (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "where" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> SDoc
    name SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> SDoc
    dcolon SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> (TcType -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr TcType
    ty))
        where name :: SDoc
    name = Name -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr (Name -> SDoc) -> Name -> SDoc
    forall a b. (a -> b) -> a -> b
    $ HoleFitCandidate -> Name
    forall a. NamedThing a => a -> Name
    getName HoleFitCandidate
    cand
              holes :: SDoc
    holes = [SDoc] -> SDoc
    forall doc. IsLine doc => [doc] -> doc
    sep ([SDoc] -> SDoc) -> [SDoc] -> SDoc
    forall a b. (a -> b) -> a -> b
    $ (TcType -> SDoc) -> [TcType] -> [SDoc]
    forall a b. (a -> b) -> [a] -> [b]
    map (SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc
    parens (SDoc -> SDoc) -> (TcType -> SDoc) -> TcType -> SDoc
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (String -> SDoc
    forall doc. IsLine doc => String -> doc
    text String
    "_" SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+> SDoc
    dcolon SDoc -> SDoc -> SDoc
    forall doc. IsLine doc => doc -> doc -> doc
    <+>) (SDoc -> SDoc) -> (TcType -> SDoc) -> TcType -> SDoc
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . TcType -> SDoc
    forall a. Outputable a => a -> SDoc
    ppr) [TcType]
    mtchs

    -- We compare HoleFits by their name instead of their Id, since we don't
    -- want our tests to be affected by the non-determinism of `nonDetCmpVar`,
    -- which is used to compare Ids. When comparing, we want HoleFits with a lower
    -- refinement level to come first.
    instance Ord HoleFit where
      compare :: HoleFit -> HoleFit -> Ordering
    compare (RawHoleFit SDoc
    _) (RawHoleFit SDoc
    _) = Ordering
    EQ
      compare (RawHoleFit SDoc
    _) HoleFit
    _ = Ordering
    LT
      compare HoleFit
    _ (RawHoleFit SDoc
    _) = Ordering
    GT
      compare a :: HoleFit
    a@(HoleFit {}) b :: HoleFit
    b@(HoleFit {}) = HoleFit -> HoleFit -> Ordering
    cmp HoleFit
    a HoleFit
    b
        where cmp :: HoleFit -> HoleFit -> Ordering
    cmp  = if HoleFit -> Int
    hfRefLvl HoleFit
    a Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    == HoleFit -> Int
    hfRefLvl HoleFit
    b
                     then Name -> Name -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare (Name -> Name -> Ordering)
    -> (HoleFit -> Name) -> HoleFit -> HoleFit -> Ordering
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` (HoleFitCandidate -> Name
    forall a. NamedThing a => a -> Name
    getName (HoleFitCandidate -> Name)
    -> (HoleFit -> HoleFitCandidate) -> HoleFit -> Name
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . HoleFit -> HoleFitCandidate
    hfCand)
                     else Int -> Int -> Ordering
    forall a. Ord a => a -> a -> Ordering
    compare (Int -> Int -> Ordering)
    -> (HoleFit -> Int) -> HoleFit -> HoleFit -> Ordering
    forall b c a. (b -> b -> c) -> (a -> b) -> a -> a -> c
    `on` HoleFit -> Int
    hfRefLvl

    hfIsLcl :: HoleFit -> Bool
    hfIsLcl :: HoleFit -> Bool
    hfIsLcl hf :: HoleFit
    hf@(HoleFit {}) = case HoleFit -> HoleFitCandidate
    hfCand HoleFit
    hf of
                                IdHFCand Id
    _    -> Bool
    True
                                NameHFCand Name
    _  -> Bool
    False
                                GreHFCand GlobalRdrElt
    gre -> GlobalRdrElt -> Bool
    forall info. GlobalRdrEltX info -> Bool
    gre_lcl GlobalRdrElt
    gre
    hfIsLcl HoleFit
    _ = Bool
    False