Hannes Siebenhandl pushed to branch wip/fendor/has-field-hie at Glasgow Haskell Compiler / GHC
Commits:
-
e01153ff
by fendor at 2026-09-16T17:46:04+02:00
-
2dfa2ef6
by fendor at 2026-09-16T17:46:04+02:00
-
6f15256b
by fendor at 2026-09-16T17:46:04+02:00
-
84937391
by fendor at 2026-09-16T17:46:04+02:00
13 changed files:
- + changelog.d/record-dot-evidence
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Iface/Ext/Types.hs
- compiler/GHC/Iface/Ext/Utils.hs
- compiler/GHC/Rename/Expr.hs
- + testsuite/tests/hiefile/should_run/HasFieldQueries.hs
- + testsuite/tests/hiefile/should_run/HasFieldQueries.stdout
- + testsuite/tests/hiefile/should_run/HieTypeable.hs
- + testsuite/tests/hiefile/should_run/HieTypeable.stdout
- testsuite/tests/hiefile/should_run/RecordDotTypes.hs
- testsuite/tests/hiefile/should_run/RecordDotTypes.stdout
- testsuite/tests/hiefile/should_run/T23492.stdout
- testsuite/tests/hiefile/should_run/all.T
Changes:
| 1 | +section: compiler
|
|
| 2 | +synopsis: Record selector functions as evidence for `HasField` constraints during .hie file generation.
|
|
| 3 | +description: {
|
|
| 4 | + We record the record selector `foo` of an expression such as `f.foo` as evidence for
|
|
| 5 | + solving the constraint `HasField "foo" record ty`.
|
|
| 6 | + |
|
| 7 | + This allows us to point to the definition source location of the record selector `foo`, allowing
|
|
| 8 | + users to jump to definition using the evidence variables.
|
|
| 9 | +}
|
|
| 10 | + |
|
| 11 | +issues: #25418
|
|
| 12 | +mrs: !16694 |
| ... | ... | @@ -23,7 +23,6 @@ import GHC.Core.DataCon ( dataConWrapperType ) |
| 23 | 23 | import GHC.Core.Type ( Type, ForAllTyFlag(..) )
|
| 24 | 24 | import GHC.Core.TyCon ( TyCon, tyConClass_maybe )
|
| 25 | 25 | import GHC.Core.InstEnv
|
| 26 | -import GHC.Core.Predicate ( isEvId )
|
|
| 27 | 26 | |
| 28 | 27 | import GHC.Hs
|
| 29 | 28 | import GHC.Hs.Syn.Type
|
| ... | ... | @@ -33,7 +32,7 @@ import GHC.Types.Basic |
| 33 | 32 | import GHC.Types.UnresolvedImport ( isGeneratedImport )
|
| 34 | 33 | import GHC.Types.FieldLabel
|
| 35 | 34 | import GHC.Types.Avail ( Avails )
|
| 36 | -import GHC.Types.Id ( isDataConId_maybe )
|
|
| 35 | +import GHC.Types.Id ( isDataConId_maybe, isId, idDetails )
|
|
| 37 | 36 | import GHC.Types.Name ( Name, nameSrcSpan, nameUnique, wiredInNameTyThing_maybe, getName )
|
| 38 | 37 | import GHC.Types.Name.Env ( NameEnv, emptyNameEnv, extendNameEnv, lookupNameEnv )
|
| 39 | 38 | import GHC.Types.Name.Reader ( RecFieldInfo(..), WithUserRdr(..) )
|
| ... | ... | @@ -81,6 +80,7 @@ import Control.Applicative ( (<|>) ) |
| 81 | 80 | import GHC.Types.TypeEnv ( TypeEnv )
|
| 82 | 81 | import Control.Arrow ( second )
|
| 83 | 82 | import Data.Traversable ( mapAccumR )
|
| 83 | +import GHC.Types.Id.Info (IdDetails(..), recSelParentName)
|
|
| 84 | 84 | |
| 85 | 85 | {- Note [Updating HieAst for changes in the GHC AST]
|
| 86 | 86 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| ... | ... | @@ -682,7 +682,7 @@ instance ToHie (Context (Located (WithUserRdr Name))) where |
| 682 | 682 | |
| 683 | 683 | hieEvIdsOfTerm :: EvTerm -> [EvId]
|
| 684 | 684 | -- Returns only EvIds satisfying relevantEvId
|
| 685 | -hieEvIdsOfTerm = runFVSelectiveList isEvId . evTermFVs
|
|
| 685 | +hieEvIdsOfTerm = runFVSelectiveList isId . evTermFVs
|
|
| 686 | 686 | |
| 687 | 687 | instance ToHie (EvBindContext (LocatedA TcEvBinds)) where
|
| 688 | 688 | toHie (EvBindContext sc sp (L span (EvBinds bs)))
|
| ... | ... | @@ -690,7 +690,7 @@ instance ToHie (EvBindContext (LocatedA TcEvBinds)) where |
| 690 | 690 | where
|
| 691 | 691 | go evbind = do
|
| 692 | 692 | let evDeps = hieEvIdsOfTerm $ eb_rhs evbind
|
| 693 | - depNames = EvBindDeps $ map varName evDeps
|
|
| 693 | + depNames = EvBindDeps $ map classifyEvBindDep evDeps
|
|
| 694 | 694 | concatM $
|
| 695 | 695 | [ toHie (C (EvidenceVarBind (EvLetBind depNames) (combineScopes sc (mkScope span)) sp)
|
| 696 | 696 | (L span $ eb_lhs evbind))
|
| ... | ... | @@ -698,6 +698,12 @@ instance ToHie (EvBindContext (LocatedA TcEvBinds)) where |
| 698 | 698 | ]
|
| 699 | 699 | toHie _ = pure []
|
| 700 | 700 | |
| 701 | +classifyEvBindDep :: EvId -> EvBindDep
|
|
| 702 | +classifyEvBindDep evId =
|
|
| 703 | + case idDetails evId of
|
|
| 704 | + RecSelId{sel_tycon} -> RecordField (varName evId) (recSelParentName sel_tycon)
|
|
| 705 | + _ -> EvidenceVar (varName evId)
|
|
| 706 | + |
|
| 701 | 707 | instance ToHie (LocatedA HsWrapper) where
|
| 702 | 708 | toHie (L osp wrap)
|
| 703 | 709 | = case wrap of
|
| ... | ... | @@ -598,17 +598,61 @@ instance Outputable EvVarSource where |
| 598 | 598 | ppr (EvInstBind True cls) = text "bound due to a superclass of " <+> ppr cls
|
| 599 | 599 | ppr (EvLetBind deps) = text "bound by a let, depending on:" <+> ppr deps
|
| 600 | 600 | |
| 601 | +data EvBindDep
|
|
| 602 | + = EvidenceVar Name
|
|
| 603 | + | RecordField Name Name
|
|
| 604 | + | TypeableEvidence Name
|
|
| 605 | + deriving (Eq, Ord)
|
|
| 606 | + |
|
| 607 | +instance Outputable EvBindDep where
|
|
| 608 | + ppr = \ case
|
|
| 609 | + EvidenceVar n -> ppr n
|
|
| 610 | + RecordField sel parent -> ppr sel <+> text "of Record" <+> ppr parent
|
|
| 611 | + TypeableEvidence n -> ppr n <+> text "bound by Typeable"
|
|
| 612 | + |
|
| 613 | +evBindDepName :: EvBindDep -> Name
|
|
| 614 | +evBindDepName = \ case
|
|
| 615 | + EvidenceVar n -> n
|
|
| 616 | + RecordField selector _record -> selector
|
|
| 617 | + TypeableEvidence n -> n
|
|
| 618 | + |
|
| 619 | +evBindDepHieName :: EvBindDep -> HieName
|
|
| 620 | +evBindDepHieName = toHieName . evBindDepName
|
|
| 621 | + |
|
| 622 | +instance Binary EvBindDep where
|
|
| 623 | + put_ bh = \ case
|
|
| 624 | + EvidenceVar n -> do
|
|
| 625 | + putByte bh 0
|
|
| 626 | + put_ bh n
|
|
| 627 | + RecordField n sel -> do
|
|
| 628 | + putByte bh 1
|
|
| 629 | + put_ bh n
|
|
| 630 | + put_ bh sel
|
|
| 631 | + TypeableEvidence n -> do
|
|
| 632 | + putByte bh 2
|
|
| 633 | + put_ bh n
|
|
| 634 | + |
|
| 635 | + get bh =
|
|
| 636 | + getByte bh >>= \ case
|
|
| 637 | + 0 -> EvidenceVar <$> get bh
|
|
| 638 | + 1 -> RecordField <$> get bh <*> get bh
|
|
| 639 | + 2 -> TypeableEvidence <$> get bh
|
|
| 640 | + t -> fail $ "EvBindDep: Unknown tag: " ++ show t
|
|
| 641 | + |
|
| 601 | 642 | -- | Eq/Ord instances compare on the converted HieName,
|
| 602 | 643 | -- as non-exported names may have different uniques after
|
| 603 | 644 | -- a roundtrip
|
| 604 | -newtype EvBindDeps = EvBindDeps { getEvBindDeps :: [Name] }
|
|
| 645 | +newtype EvBindDeps = EvBindDeps { getEvBindDeps :: [EvBindDep] }
|
|
| 605 | 646 | deriving Outputable
|
| 606 | 647 | |
| 648 | +evBindDepsNames :: EvBindDeps -> [Name]
|
|
| 649 | +evBindDepsNames = map evBindDepName . getEvBindDeps
|
|
| 650 | + |
|
| 607 | 651 | instance Eq EvBindDeps where
|
| 608 | - (==) = coerce ((==) `on` map toHieName)
|
|
| 652 | + (==) = coerce ((==) `on` map evBindDepHieName)
|
|
| 609 | 653 | |
| 610 | 654 | instance Ord EvBindDeps where
|
| 611 | - compare = coerce (compare `on` map toHieName)
|
|
| 655 | + compare = coerce (compare `on` map evBindDepHieName)
|
|
| 612 | 656 | |
| 613 | 657 | instance Binary EvBindDeps where
|
| 614 | 658 | put_ bh (EvBindDeps xs) = put_ bh xs
|
| ... | ... | @@ -82,15 +82,19 @@ resolveVisibility kind ty_args |
| 82 | 82 | foldType :: (HieType a -> a) -> HieTypeFix -> a
|
| 83 | 83 | foldType f (Roll t) = f $ fmap (foldType f) t
|
| 84 | 84 | |
| 85 | -selectPoint :: HieFile -> (Int,Int) -> Maybe (HieAST Int)
|
|
| 86 | -selectPoint hf (sl,sc) = getFirst $
|
|
| 85 | +selectPoint :: HieFile -> (Int,Int) -> Maybe (HieAST TypeIndex)
|
|
| 86 | +selectPoint hf p = selectRange hf p p
|
|
| 87 | + |
|
| 88 | +selectRange :: HieFile -> (Int,Int) -> (Int,Int) -> Maybe (HieAST TypeIndex)
|
|
| 89 | +selectRange hf (sl,sc) (el, ec) = getFirst $
|
|
| 87 | 90 | flip foldMap (M.toList (getAsts $ hie_asts hf)) $ \(HiePath fs,ast) -> First $
|
| 88 | 91 | case selectSmallestContaining (sp fs) ast of
|
| 89 | 92 | Nothing -> Nothing
|
| 90 | 93 | Just ast' -> Just ast'
|
| 91 | 94 | where
|
| 92 | 95 | sloc fs = mkRealSrcLoc fs sl sc
|
| 93 | - sp fs = mkRealSrcSpan (sloc fs) (sloc fs)
|
|
| 96 | + eloc fs = mkRealSrcLoc fs el ec
|
|
| 97 | + sp fs = mkRealSrcSpan (sloc fs) (eloc fs)
|
|
| 94 | 98 | |
| 95 | 99 | findEvidenceUse :: NodeIdentifiers a -> [Name]
|
| 96 | 100 | findEvidenceUse ni = [n | (Right n, dets) <- xs, any isEvidenceUse (identInfo dets)]
|
| ... | ... | @@ -141,7 +145,7 @@ getEvidenceTree refmap var = go emptyNameSet var |
| 141 | 145 | det <- S.toList $ identInfo dets
|
| 142 | 146 | case det of
|
| 143 | 147 | EvidenceVarBind src@(EvLetBind (getEvBindDeps -> xs)) scp spn ->
|
| 144 | - pure $ Just ((src,scp,spn),mapMaybe (go $ extendNameSet seen var) xs)
|
|
| 148 | + pure $ Just ((src,scp,spn),mapMaybe (go (extendNameSet seen var) . evBindDepName) xs)
|
|
| 145 | 149 | EvidenceVarBind src scp spn -> pure $ Just ((src,scp,spn),[])
|
| 146 | 150 | _ -> pure Nothing
|
| 147 | 151 | pure $ Tree.Node (EvidenceInfo var sp typ (Just evdet)) children
|
| ... | ... | @@ -386,7 +390,7 @@ definedInAsts asts n = case nameSrcSpan n of |
| 386 | 390 | |
| 387 | 391 | getEvidenceBindDeps :: ContextInfo -> [Name]
|
| 388 | 392 | getEvidenceBindDeps (EvidenceVarBind (EvLetBind xs) _ _) =
|
| 389 | - getEvBindDeps xs
|
|
| 393 | + evBindDepsNames xs
|
|
| 390 | 394 | getEvidenceBindDeps _ = []
|
| 391 | 395 | |
| 392 | 396 | isEvidenceBind :: ContextInfo -> Bool
|
| ... | ... | @@ -422,7 +422,7 @@ rnExpr (HsGetField _ e f) |
| 422 | 422 | ; let f' = rnDotFieldOcc <$> f
|
| 423 | 423 | ; return ( mkExpandedExpr
|
| 424 | 424 | (HsGetField noExtField e f')
|
| 425 | - (mkGetField getField e (fmap (unLoc . dfoLabel) f'))
|
|
| 425 | + (mkGetField getField e (dfoLabel $ unLoc f'))
|
|
| 426 | 426 | , fv_e `plusFN` fv_getField ) }
|
| 427 | 427 | |
| 428 | 428 | rnExpr (HsProjection _ fs)
|
| ... | ... | @@ -431,7 +431,7 @@ rnExpr (HsProjection _ fs) |
| 431 | 431 | ; let fs' = NE.map rnDotFieldOcc fs
|
| 432 | 432 | ; return ( mkExpandedExpr
|
| 433 | 433 | (HsProjection noExtField fs')
|
| 434 | - (mkProjection getField circ $ NE.map (unLoc . dfoLabel) fs')
|
|
| 434 | + (mkProjection getField circ $ NE.map dfoLabel fs')
|
|
| 435 | 435 | , unitFN circ `plusFN` fv_getField) }
|
| 436 | 436 | |
| 437 | 437 | ------------------------------------------
|
| ... | ... | @@ -2882,8 +2882,9 @@ rnHsIf p b1 b2 |
| 2882 | 2882 | |
| 2883 | 2883 | -- mkGetField arg field calculates a get_field @field arg expression.
|
| 2884 | 2884 | -- e.g. z.x = mkGetField z x = get_field @x z
|
| 2885 | -mkGetField :: Name -> LHsExpr GhcRn -> LocatedAn NoEpAnns FieldLabelString -> HsExpr GhcRn
|
|
| 2886 | -mkGetField get_field arg field = unLoc (head $ mkGet get_field (arg :| []) field)
|
|
| 2885 | +mkGetField :: Name -> LHsExpr GhcRn -> XRec GhcRn FieldLabelString -> HsExpr GhcRn
|
|
| 2886 | +mkGetField get_field arg field =
|
|
| 2887 | + HsApp noExtField (mkGetFieldExpr get_field field) arg
|
|
| 2887 | 2888 | |
| 2888 | 2889 | -- mkSetField a field b calculates a set_field @field expression.
|
| 2889 | 2890 | -- e.g mkSetSetField a field b = set_field @"field" a b (read as "set field 'field' to a on b").
|
| ... | ... | @@ -2902,14 +2903,16 @@ mkSet set_field acc (field, g) = wrapGenSpan (mkSetField set_field g field acc) |
| 2902 | 2903 | -- mkProjection fields calculates a projection.
|
| 2903 | 2904 | -- e.g. .x = mkProjection [x] = getField @"x"
|
| 2904 | 2905 | -- .x.y = mkProjection [.x, .y] = (.y) . (.x) = getField @"y" . getField @"x"
|
| 2905 | -mkProjection :: Name -> Name -> NonEmpty FieldLabelString -> HsExpr GhcRn
|
|
| 2906 | -mkProjection getFieldName circName (field :| fields) = foldl' f (proj field) fields
|
|
| 2906 | +mkProjection :: Name -> Name -> NonEmpty (XRec GhcRn FieldLabelString) -> HsExpr GhcRn
|
|
| 2907 | +mkProjection getFieldName circName (field :| fields) =
|
|
| 2908 | + unLoc $ foldl' f (mkGetFieldExpr getFieldName field) fields
|
|
| 2907 | 2909 | where
|
| 2908 | - f :: HsExpr GhcRn -> FieldLabelString -> HsExpr GhcRn
|
|
| 2909 | - f acc field = genHsApps circName $ map wrapGenSpan [proj field, acc]
|
|
| 2910 | + f :: LHsExpr GhcRn -> XRec GhcRn FieldLabelString -> LHsExpr GhcRn
|
|
| 2911 | + f acc field = wrapGenSpan $ genHsApps circName [mkGetFieldExpr getFieldName field, acc]
|
|
| 2910 | 2912 | |
| 2911 | - proj :: FieldLabelString -> HsExpr GhcRn
|
|
| 2912 | - proj (FieldLabelString f) = genHsVar getFieldName `genAppType` genHsTyLit f
|
|
| 2913 | +mkGetFieldExpr :: Name -> XRec GhcRn FieldLabelString -> LHsExpr GhcRn
|
|
| 2914 | +mkGetFieldExpr getFieldName (L ann (FieldLabelString f)) =
|
|
| 2915 | + wrapGenSpan' (getHasLoc ann) (genHsVar getFieldName `genAppType` genHsTyLit f)
|
|
| 2913 | 2916 | |
| 2914 | 2917 | -- mkProjUpdateSetField calculates functions representing dot notation record updates.
|
| 2915 | 2918 | -- e.g. Suppose an update like foo.bar = 1.
|
| 1 | +{-# LANGUAGE OverloadedRecordDot #-}
|
|
| 2 | +module Main where
|
|
| 3 | + |
|
| 4 | +import TestUtils
|
|
| 5 | +import GHC.Records
|
|
| 6 | +import GHC.TypeLits
|
|
| 7 | +import Data.Tree
|
|
| 8 | + |
|
| 9 | +data Thing = Thing {field1 :: Char, field2 :: Bool}
|
|
| 10 | + deriving (Show, Eq)
|
|
| 11 | + |
|
| 12 | +foo :: Thing -> String
|
|
| 13 | +foo t = show t.field1
|
|
| 14 | +-- ^ this is the point
|
|
| 15 | + |
|
| 16 | +testing2 (x :: Thing) = x.field1
|
|
| 17 | +-- ^ this is the point
|
|
| 18 | +-- ^ this is the point
|
|
| 19 | + |
|
| 20 | +data NestedThing = NestedThing { nested1 :: Thing }
|
|
| 21 | + |
|
| 22 | +nestedSig :: NestedThing -> Char
|
|
| 23 | +nestedSig n = n.nested1.field1
|
|
| 24 | +-- ^ this is the point
|
|
| 25 | +-- ^ this is the point
|
|
| 26 | + |
|
| 27 | +nestedNoSig n = n.nested1.field2 :: Bool
|
|
| 28 | +-- ^ this is the point
|
|
| 29 | +-- ^ this is the point
|
|
| 30 | + |
|
| 31 | + |
|
| 32 | +withConstraint :: HasField "field1" x Char => x -> Char
|
|
| 33 | +withConstraint x = x.field1
|
|
| 34 | +-- ^ this is the point
|
|
| 35 | + |
|
| 36 | +points =
|
|
| 37 | + [ (13,17)
|
|
| 38 | + , (16,25)
|
|
| 39 | + , (16,27)
|
|
| 40 | + , (23,17)
|
|
| 41 | + , (23,25)
|
|
| 42 | + , (27,20)
|
|
| 43 | + , (27,28)
|
|
| 44 | + , (33,22)
|
|
| 45 | + ]
|
|
| 46 | + |
|
| 47 | +main = do
|
|
| 48 | + (df, hf) <- readTestHie "HasFieldQueries.hie"
|
|
| 49 | + let refmap = generateReferencesMap $ getAsts $ hie_asts hf
|
|
| 50 | + |
|
| 51 | + traverse (explainEv df hf refmap) points
|
|
| 52 | + return () |
| 1 | +==========================
|
|
| 2 | +At point (13,17), we found:
|
|
| 3 | +==========================
|
|
| 4 | +┌
|
|
| 5 | +│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
|
|
| 6 | +│ is an evidence variable bound by a let, depending on: [C:HasField,
|
|
| 7 | +│ field1 of Record Thing]
|
|
| 8 | +│ with scope: ModuleScope
|
|
| 9 | +│
|
|
| 10 | +│ Defined at <no location info>
|
|
| 11 | +└
|
|
| 12 | +|
|
|
| 13 | ++- ┌
|
|
| 14 | +| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
|
|
| 15 | +| │ is a usage of an external evidence variable
|
|
| 16 | +| │ Defined in `GHC.Internal.Records'
|
|
| 17 | +| └
|
|
| 18 | +|
|
|
| 19 | +`- ┌
|
|
| 20 | + │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
|
|
| 21 | + │ is a usage of an external evidence variable
|
|
| 22 | + │ Defined at HasFieldQueries.hs:9:21
|
|
| 23 | + └
|
|
| 24 | + |
|
| 25 | +==========================
|
|
| 26 | +At point (16,25), we found:
|
|
| 27 | +==========================
|
|
| 28 | +==========================
|
|
| 29 | +At point (16,27), we found:
|
|
| 30 | +==========================
|
|
| 31 | +┌
|
|
| 32 | +│ $dHasField at HasFieldQueries.hs:16:1-32, of type: HasField "field1" Thing Char
|
|
| 33 | +│ is an evidence variable bound by a let, depending on: [C:HasField,
|
|
| 34 | +│ field1 of Record Thing]
|
|
| 35 | +│ with scope: LocalScope HasFieldQueries.hs:16:1-32
|
|
| 36 | +│ bound at: HasFieldQueries.hs:16:1-32
|
|
| 37 | +│ Defined at <no location info>
|
|
| 38 | +└
|
|
| 39 | +|
|
|
| 40 | ++- ┌
|
|
| 41 | +| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
|
|
| 42 | +| │ is a usage of an external evidence variable
|
|
| 43 | +| │ Defined in `GHC.Internal.Records'
|
|
| 44 | +| └
|
|
| 45 | +|
|
|
| 46 | +`- ┌
|
|
| 47 | + │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
|
|
| 48 | + │ is a usage of an external evidence variable
|
|
| 49 | + │ Defined at HasFieldQueries.hs:9:21
|
|
| 50 | + └
|
|
| 51 | + |
|
| 52 | +==========================
|
|
| 53 | +At point (23,17), we found:
|
|
| 54 | +==========================
|
|
| 55 | +┌
|
|
| 56 | +│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "nested1" NestedThing Thing
|
|
| 57 | +│ is an evidence variable bound by a let, depending on: [C:HasField,
|
|
| 58 | +│ nested1 of Record NestedThing]
|
|
| 59 | +│ with scope: ModuleScope
|
|
| 60 | +│
|
|
| 61 | +│ Defined at <no location info>
|
|
| 62 | +└
|
|
| 63 | +|
|
|
| 64 | ++- ┌
|
|
| 65 | +| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
|
|
| 66 | +| │ is a usage of an external evidence variable
|
|
| 67 | +| │ Defined in `GHC.Internal.Records'
|
|
| 68 | +| └
|
|
| 69 | +|
|
|
| 70 | +`- ┌
|
|
| 71 | + │ nested1 at HasFieldQueries.hs:1:1, of type: NestedThing -> Thing
|
|
| 72 | + │ is a usage of an external evidence variable
|
|
| 73 | + │ Defined at HasFieldQueries.hs:20:34
|
|
| 74 | + └
|
|
| 75 | + |
|
| 76 | +==========================
|
|
| 77 | +At point (23,25), we found:
|
|
| 78 | +==========================
|
|
| 79 | +┌
|
|
| 80 | +│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
|
|
| 81 | +│ is an evidence variable bound by a let, depending on: [C:HasField,
|
|
| 82 | +│ field1 of Record Thing]
|
|
| 83 | +│ with scope: ModuleScope
|
|
| 84 | +│
|
|
| 85 | +│ Defined at <no location info>
|
|
| 86 | +└
|
|
| 87 | +|
|
|
| 88 | ++- ┌
|
|
| 89 | +| │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
|
|
| 90 | +| │ is a usage of an external evidence variable
|
|
| 91 | +| │ Defined in `GHC.Internal.Records'
|
|
| 92 | +| └
|
|
| 93 | +|
|
|
| 94 | +`- ┌
|
|
| 95 | + │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
|
|
| 96 | + │ is a usage of an external evidence variable
|
|
| 97 | + │ Defined at HasFieldQueries.hs:9:21
|
|
| 98 | + └
|
|
| 99 | + |
|
| 100 | +==========================
|
|
| 101 | +At point (27,20), we found:
|
|
| 102 | +==========================
|
|
| 103 | +┌
|
|
| 104 | +│ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "nested1" r r
|
|
| 105 | +│ is an evidence variable bound by a let, depending on: [$dHasField]
|
|
| 106 | +│ with scope: LocalScope HasFieldQueries.hs:27:1-40
|
|
| 107 | +│ bound at: HasFieldQueries.hs:27:1-40
|
|
| 108 | +│ Defined at <no location info>
|
|
| 109 | +└
|
|
| 110 | +|
|
|
| 111 | +`- ┌
|
|
| 112 | + │ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "nested1" r r
|
|
| 113 | + │ is an evidence variable bound by a type signature
|
|
| 114 | + │ with scope: LocalScope HasFieldQueries.hs:27:1-40
|
|
| 115 | + │ bound at: HasFieldQueries.hs:27:1-40
|
|
| 116 | + │ Defined at <no location info>
|
|
| 117 | + └
|
|
| 118 | + |
|
| 119 | +==========================
|
|
| 120 | +At point (27,28), we found:
|
|
| 121 | +==========================
|
|
| 122 | +┌
|
|
| 123 | +│ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "field2" r Bool
|
|
| 124 | +│ is an evidence variable bound by a let, depending on: [$dHasField]
|
|
| 125 | +│ with scope: LocalScope HasFieldQueries.hs:27:1-40
|
|
| 126 | +│ bound at: HasFieldQueries.hs:27:1-40
|
|
| 127 | +│ Defined at <no location info>
|
|
| 128 | +└
|
|
| 129 | +|
|
|
| 130 | +`- ┌
|
|
| 131 | + │ $dHasField at HasFieldQueries.hs:27:1-40, of type: HasField "field2" r Bool
|
|
| 132 | + │ is an evidence variable bound by a type signature
|
|
| 133 | + │ with scope: LocalScope HasFieldQueries.hs:27:1-40
|
|
| 134 | + │ bound at: HasFieldQueries.hs:27:1-40
|
|
| 135 | + │ Defined at <no location info>
|
|
| 136 | + └
|
|
| 137 | + |
|
| 138 | +==========================
|
|
| 139 | +At point (33,22), we found:
|
|
| 140 | +==========================
|
|
| 141 | +┌
|
|
| 142 | +│ $dHasField at HasFieldQueries.hs:33:1-27, of type: HasField "field1" x Char
|
|
| 143 | +│ is an evidence variable bound by a let, depending on: [$dHasField]
|
|
| 144 | +│ with scope: LocalScope HasFieldQueries.hs:33:1-27
|
|
| 145 | +│ bound at: HasFieldQueries.hs:33:1-27
|
|
| 146 | +│ Defined at <no location info>
|
|
| 147 | +└
|
|
| 148 | +|
|
|
| 149 | +`- ┌
|
|
| 150 | + │ $dHasField at HasFieldQueries.hs:33:1-27, of type: HasField "field1" x Char
|
|
| 151 | + │ is an evidence variable bound by a HsWrapper
|
|
| 152 | + │ with scope: LocalScope HasFieldQueries.hs:33:1-27
|
|
| 153 | + │ bound at: HasFieldQueries.hs:33:1-27
|
|
| 154 | + │ Defined at <no location info>
|
|
| 155 | + └
|
|
| 156 | + |
| 1 | +module Main where
|
|
| 2 | + |
|
| 3 | +import Data.Dynamic
|
|
| 4 | +import Data.Typeable
|
|
| 5 | +import TestUtils
|
|
| 6 | + |
|
| 7 | +data Thing = Thing {field1 :: Char, field2 :: Bool}
|
|
| 8 | + deriving (Show, Eq)
|
|
| 9 | + |
|
| 10 | +castFromDynamic :: Dynamic -> Maybe Thing
|
|
| 11 | +castFromDynamic d = fromDynamic d
|
|
| 12 | + -- ^ this is the point
|
|
| 13 | + |
|
| 14 | +rep :: Thing -> TypeRep
|
|
| 15 | +rep d = typeOf d
|
|
| 16 | + -- ^ this is the point
|
|
| 17 | + |
|
| 18 | +points =
|
|
| 19 | + [ (11,21)
|
|
| 20 | + , (15,10)
|
|
| 21 | + ]
|
|
| 22 | + |
|
| 23 | +main = do
|
|
| 24 | + (df, hf) <- readTestHie "HieTypeable.hie"
|
|
| 25 | + let refmap = generateReferencesMap $ getAsts $ hie_asts hf
|
|
| 26 | + |
|
| 27 | + traverse (explainEv df hf refmap) points
|
|
| 28 | + return () |
| 1 | +==========================
|
|
| 2 | +At point (11,21), we found:
|
|
| 3 | +==========================
|
|
| 4 | +┌
|
|
| 5 | +│ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
|
|
| 6 | +│ is an evidence variable bound by a let, depending on: [$dTypeable]
|
|
| 7 | +│ with scope: ModuleScope
|
|
| 8 | +│
|
|
| 9 | +│ Defined at <no location info>
|
|
| 10 | +└
|
|
| 11 | +|
|
|
| 12 | +`- ┌
|
|
| 13 | + │ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
|
|
| 14 | + │ is an evidence variable bound by a let, depending on: []
|
|
| 15 | + │ with scope: ModuleScope
|
|
| 16 | + │
|
|
| 17 | + │ Defined at <no location info>
|
|
| 18 | + └
|
|
| 19 | + |
|
| 20 | +==========================
|
|
| 21 | +At point (15,10), we found:
|
|
| 22 | +==========================
|
|
| 23 | +┌
|
|
| 24 | +│ $dTypeable at HieTypeable.hs:1:1, of type: Typeable Thing
|
|
| 25 | +│ is an evidence variable bound by a let, depending on: []
|
|
| 26 | +│ with scope: ModuleScope
|
|
| 27 | +│
|
|
| 28 | +│ Defined at <no location info>
|
|
| 29 | +└
|
|
| 30 | + |
| ... | ... | @@ -22,6 +22,11 @@ x = MyRecord { a = "Hello", b = 12, c = MyChild { z = "there" } } |
| 22 | 22 | y = x.a ++ show x.b ++ x.c.z
|
| 23 | 23 | -- ^ ^ ^ ^^
|
| 24 | 24 | -- 1 2 3 45
|
| 25 | +-- ^-^ ^-^ ^-^
|
|
| 26 | +-- 6 7 8
|
|
| 27 | +-- ^---^
|
|
| 28 | +-- 9
|
|
| 29 | + |
|
| 25 | 30 | |
| 26 | 31 | p1,p2,p3,p4 :: (Int,Int)
|
| 27 | 32 | p1 = (22,6)
|
| ... | ... | @@ -30,10 +35,19 @@ p3 = (22,25) |
| 30 | 35 | p4 = (22,28)
|
| 31 | 36 | p5 = (22,29)
|
| 32 | 37 | |
| 38 | +r6 = (p1, (22, 8))
|
|
| 39 | +r7 = ((22,17), p2)
|
|
| 40 | +r8 = (p3, (22, 27))
|
|
| 41 | +r9 = (p3, p5)
|
|
| 42 | + |
|
| 33 | 43 | selectPoint' :: HieFile -> (Int,Int) -> HieAST Int
|
| 34 | 44 | selectPoint' hf loc =
|
| 35 | 45 | maybe (error "point not found") id $ selectPoint hf loc
|
| 36 | 46 | |
| 47 | +selectRange' :: HieFile -> ((Int,Int), (Int, Int)) -> HieAST Int
|
|
| 48 | +selectRange' hf (s, e) =
|
|
| 49 | + maybe (error "range not found") id $ selectRange hf s e
|
|
| 50 | + |
|
| 37 | 51 | main = do
|
| 38 | 52 | (df, hf) <- readTestHie "RecordDotTypes.hie"
|
| 39 | 53 | forM_ [p1,p2,p3,p4,p5] $ \point -> do
|
| ... | ... | @@ -41,3 +55,11 @@ main = do |
| 41 | 55 | let types = concatMap nodeType $ getSourcedNodeInfo $ sourcedNodeInfo $ selectPoint' hf point
|
| 42 | 56 | forM_ types $ \typ -> do
|
| 43 | 57 | putStrLn (renderHieType df $ recoverFullType typ (hie_types hf))
|
| 58 | + |
|
| 59 | + forM_ [r6, r7, r8, r9] $ \range -> do
|
|
| 60 | + putStr $ "At " ++ showRange range ++ ", got type: "
|
|
| 61 | + let types = concatMap nodeType $ getSourcedNodeInfo $ sourcedNodeInfo $ selectRange' hf range
|
|
| 62 | + forM_ types $ \typ -> do
|
|
| 63 | + putStrLn (renderHieType df $ recoverFullType typ (hie_types hf))
|
|
| 64 | + where
|
|
| 65 | + showRange (p1, p2) = show p1 ++ " - " ++ show p2 |
| 1 | 1 | At (22,6), got type: MyRecord
|
| 2 | -At (22,20), got type: Integer
|
|
| 2 | +At (22,20), got type: MyRecord -> Integer
|
|
| 3 | 3 | At (22,25), got type: MyRecord
|
| 4 | -At (22,28), got type: String
|
|
| 5 | -At (22,29), got type: String |
|
| \ No newline at end of file | ||
| 4 | +At (22,28), got type: MyChild -> [Char]
|
|
| 5 | +At (22,29), got type: MyChild -> [Char]
|
|
| 6 | +At (22,6) - (22,8), got type: [Char]
|
|
| 7 | +At (22,17) - (22,20), got type: Integer
|
|
| 8 | +At (22,25) - (22,27), got type: MyChild
|
|
| 9 | +At (22,25) - (22,29), got type: [Char] |
| ... | ... | @@ -4,4 +4,4 @@ PartialFieldSelector |
| 4 | 4 | At (18,7), got type: PartialFieldSelector -> Bool
|
| 5 | 5 | At (23,7), got type: PartialFieldSelector
|
| 6 | 6 | At (23,8), got type: PartialFieldSelector
|
| 7 | -At (23,9), got type: Bool |
|
| 7 | +At (23,9), got type: PartialFieldSelector -> Bool |
| ... | ... | @@ -10,3 +10,5 @@ test('T23120', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUti |
| 10 | 10 | test('T24544', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
|
| 11 | 11 | test('HieGadtConSigs', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
|
| 12 | 12 | test('T25709', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
|
| 13 | +test('HasFieldQueries', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info'])
|
|
| 14 | +test('HieTypeable', [extra_run_opts('"' + config.libdir + '"'), extra_files(['TestUtils.hs'])], compile_and_run, ['-package ghc -fwrite-ide-info']) |