Hannes Siebenhandl pushed to branch wip/fendor/has-field-hie at Glasgow Haskell Compiler / GHC
Commits:
-
7514547d
by Your Name at 2026-09-02T11:44:05+00:00
-
68ec7739
by Your Name at 2026-09-02T11:45:30+00:00
-
aec841af
by fendor at 2026-09-02T14:47:06+02:00
7 changed files:
- compiler/GHC/Iface/Ext/Ast.hs
- compiler/GHC/Rename/Expr.hs
- testsuite/tests/hiefile/should_run/HasFieldQueries.hs
- testsuite/tests/hiefile/should_run/HasFieldQueries.stdout
- + testsuite/tests/overloadedrecflds/should_fail/RecordDotErrCtxt.hs
- + testsuite/tests/overloadedrecflds/should_fail/RecordDotErrCtxt.stderr
- testsuite/tests/overloadedrecflds/should_fail/all.T
Changes:
| ... | ... | @@ -22,11 +22,11 @@ import GHC.Core.Utils (exprType) |
| 22 | 22 | import GHC.Core.TyCo.Rep (Type(TyConApp))
|
| 23 | 23 | import GHC.Core.TyCon (TyCon(..))
|
| 24 | 24 | import GHC.Core.ConLike ( conLikeName )
|
| 25 | -import GHC.Core.DataCon ( dataConWrapperType )
|
|
| 25 | +import GHC.Core.DataCon ( dataConWrapperType, dataConTyCon )
|
|
| 26 | 26 | import GHC.Core.Type ( Type, ForAllTyFlag(..) )
|
| 27 | -import GHC.Core.TyCon ( TyCon, tyConClass_maybe )
|
|
| 27 | +import GHC.Core.TyCon ( TyCon, tyConClass_maybe, isClassTyCon )
|
|
| 28 | 28 | import GHC.Core.InstEnv
|
| 29 | -import GHC.Core.Predicate ( isEvId )
|
|
| 29 | +import GHC.Core.Predicate ( isEvId, getClassPredTys_maybe )
|
|
| 30 | 30 | |
| 31 | 31 | import GHC.Hs
|
| 32 | 32 | import GHC.Hs.Syn.Type
|
| ... | ... | @@ -36,12 +36,12 @@ import GHC.Types.Basic |
| 36 | 36 | import GHC.Types.UnresolvedImport ( isGeneratedImport )
|
| 37 | 37 | import GHC.Types.FieldLabel
|
| 38 | 38 | import GHC.Types.Avail ( Avails )
|
| 39 | -import GHC.Types.Id ( isDataConId_maybe )
|
|
| 39 | +import GHC.Types.Id ( isDataConId_maybe, isRecordSelector )
|
|
| 40 | 40 | import GHC.Types.Name ( Name, nameSrcSpan, nameUnique, wiredInNameTyThing_maybe, getName, hasKnownKey )
|
| 41 | 41 | import GHC.Types.Name.Env ( NameEnv, emptyNameEnv, extendNameEnv, lookupNameEnv )
|
| 42 | 42 | import GHC.Types.Name.Reader ( RecFieldInfo(..), WithUserRdr(..) )
|
| 43 | 43 | import GHC.Types.SrcLoc
|
| 44 | -import GHC.Types.Var ( Id, Var, EvId, varName, varType, varUnique )
|
|
| 44 | +import GHC.Types.Var ( Id, Var, EvId, varName, varType, varUnique, isId )
|
|
| 45 | 45 | import GHC.Types.Var.Env
|
| 46 | 46 | import GHC.Types.Var.FV
|
| 47 | 47 | |
| ... | ... | @@ -684,9 +684,73 @@ instance ToHie (Context (Located Name)) where |
| 684 | 684 | instance ToHie (Context (Located (WithUserRdr Name))) where
|
| 685 | 685 | toHie (C c (L l (WithUserRdr _ n))) = toHie $ C c (L l n)
|
| 686 | 686 | |
| 687 | -hieEvIdsOfTerm :: EvTerm -> [EvId]
|
|
| 688 | --- Returns only EvIds satisfying relevantEvId
|
|
| 689 | -hieEvIdsOfTerm = runFVSelectiveList isEvId . evTermFVs
|
|
| 687 | +{- Note [Evidence dependencies in HIE files]
|
|
| 688 | + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 689 | +The 'EvBindDeps' of an 'EvLetBind' record what a dictionary was built out of,
|
|
| 690 | +so that a tool can answer "where does the evidence for this constraint come
|
|
| 691 | +from?" by walking 'getEvidenceTree' (in GHC.Iface.Ext.Utils). For that to be
|
|
| 692 | +useful, the dependencies have to /discriminate/ one solution from another. So
|
|
| 693 | +we make two adjustments to the plain free evidence variables of the right hand
|
|
| 694 | +side:
|
|
| 695 | + |
|
| 696 | +(1) We drop the data constructor of a class dictionary, e.g. @C:HasField@.
|
|
| 697 | + These do satisfy 'isEvId', but they /construct/ a dictionary rather than
|
|
| 698 | + being evidence in their own right, and which one appears is already
|
|
| 699 | + determined by the constraint being solved. Reporting one tells a user
|
|
| 700 | + nothing they did not know from the constraint they hovered over, and is
|
|
| 701 | + actively misleading: it points into the module defining the /class/,
|
|
| 702 | + rather than at whatever provided the instance.
|
|
| 703 | + |
|
| 704 | +(2) We keep record selectors, which are not evidence and so do not satisfy
|
|
| 705 | + 'isEvId'. When a constraint is solved by a built-in rule that builds the
|
|
| 706 | + dictionary out of a record selector instead of applying a dictionary
|
|
| 707 | + function, that selector plays exactly the role the dictionary function
|
|
| 708 | + would, and is the only thing recording /which/ instance was used. Such a
|
|
| 709 | + selector is additionally recorded as an 'EvInstBind' for the constraint's
|
|
| 710 | + own class, so that 'getEvidenceTree' describes it as providing the
|
|
| 711 | + instance instead of falling through to its "external evidence variable"
|
|
| 712 | + case (which is what it reports for a dependency it can find no evidence
|
|
| 713 | + binding for).
|
|
| 714 | + |
|
| 715 | +@HasField@ is what motivates both rules: a constraint @HasField "fld" T Int@
|
|
| 716 | +for a real record field is solved by building @MkHasField (fld |> co)@ -- see
|
|
| 717 | +Note [HasField instances] in GHC.Tc.Instance.Class -- so without (1) and (2)
|
|
| 718 | +the evidence for every record selection, however different, bottomed out at
|
|
| 719 | +@GHC.Internal.Records.C:HasField@. Neither rule names @HasField@, though, and
|
|
| 720 | +neither should: they say "a dictionary constructor explains nothing" and "a
|
|
| 721 | +selector used as evidence explains something", which holds for any class
|
|
| 722 | +solved this way.
|
|
| 723 | + |
|
| 724 | +The 'EvInstBind' of (2) is deliberately recorded at the span of the /evidence
|
|
| 725 | +binding/, not at the selector's own 'nameSrcSpan'. Attaching an evidence
|
|
| 726 | +context to the field's declaration would merge it into the
|
|
| 727 | +'IdentifierDetails' of the declaration itself, and consumers reasonably skip
|
|
| 728 | +identifiers mentioning evidence when deciding what a source token refers to --
|
|
| 729 | +Haddock's hyperlinked source would then stop linking the field declaration.
|
|
| 730 | +The 'Name' recorded is the selector either way, which is what an IDE needs in
|
|
| 731 | +order to navigate to it.
|
|
| 732 | +-}
|
|
| 733 | + |
|
| 734 | +-- | Is this the data constructor of a class dictionary, e.g. @C:HasField@?
|
|
| 735 | +--
|
|
| 736 | +-- See Note [Evidence dependencies in HIE files]
|
|
| 737 | +isClassDataConId :: Id -> Bool
|
|
| 738 | +isClassDataConId v
|
|
| 739 | + | Just dc <- isDataConId_maybe v = isClassTyCon (dataConTyCon dc)
|
|
| 740 | + | otherwise = False
|
|
| 741 | + |
|
| 742 | +hieEvIdsOfTerm :: EvTerm -> [Var]
|
|
| 743 | +-- See Note [Evidence dependencies in HIE files]
|
|
| 744 | +hieEvIdsOfTerm = runFVSelectiveList relevant . evTermFVs
|
|
| 745 | + where
|
|
| 746 | + -- NB: this traversal offers us TyVars as well as Ids, and 'idDetails'
|
|
| 747 | + -- panics on a TyVar, so the Id-only predicates must be guarded by
|
|
| 748 | + -- 'isId'. 'isEvId' only looks at the type and is safe on either; it
|
|
| 749 | + -- deliberately admits coercion variables, which are TyVars.
|
|
| 750 | + relevant v
|
|
| 751 | + | not (isId v) = isEvId v
|
|
| 752 | + | otherwise = (isEvId v && not (isClassDataConId v))
|
|
| 753 | + || isRecordSelector v
|
|
| 690 | 754 | |
| 691 | 755 | instance ToHie (EvBindContext (LocatedA TcEvBinds)) where
|
| 692 | 756 | toHie (EvBindContext sc sp (L span (EvBinds bs)))
|
| ... | ... | @@ -699,6 +763,13 @@ instance ToHie (EvBindContext (LocatedA TcEvBinds)) where |
| 699 | 763 | [ toHie (C (EvidenceVarBind (EvLetBind depNames) (combineScopes sc (mkScope span)) sp)
|
| 700 | 764 | (L span $ eb_lhs evbind))
|
| 701 | 765 | , toHie $ map (C EvidenceVarUse . L span) $ evDeps
|
| 766 | + -- See Note [Evidence dependencies in HIE files]
|
|
| 767 | + , toHie [ C (EvidenceVarBind (EvInstBind False (className cls))
|
|
| 768 | + ModuleScope Nothing)
|
|
| 769 | + (L span sel)
|
|
| 770 | + | Just (cls, _) <- [getClassPredTys_maybe (varType (eb_lhs evbind))]
|
|
| 771 | + , sel <- evDeps
|
|
| 772 | + , isId sel, isRecordSelector sel ]
|
|
| 702 | 773 | ]
|
| 703 | 774 | toHie _ = pure []
|
| 704 | 775 |
| ... | ... | @@ -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 | ------------------------------------------
|
| ... | ... | @@ -2916,14 +2916,24 @@ mkSet set_field acc (field, g) = wrapGenSpan (mkSetField set_field g field acc) |
| 2916 | 2916 | -- mkProjection fields calculates a projection.
|
| 2917 | 2917 | -- e.g. .x = mkProjection [x] = getField @"x"
|
| 2918 | 2918 | -- .x.y = mkProjection [.x, .y] = (.y) . (.x) = getField @"y" . getField @"x"
|
| 2919 | -mkProjection :: Name -> Name -> NonEmpty FieldLabelString -> HsExpr GhcRn
|
|
| 2920 | -mkProjection getFieldName circName (field :| fields) = foldl' f (proj field) fields
|
|
| 2919 | +mkProjection :: Name -> Name -> NonEmpty (XRec GhcRn FieldLabelString)
|
|
| 2920 | + -> HsExpr GhcRn
|
|
| 2921 | +mkProjection getFieldName circName (field :| fields)
|
|
| 2922 | + = unLoc $ foldl' f (proj field) fields
|
|
| 2921 | 2923 | where
|
| 2922 | - f :: HsExpr GhcRn -> FieldLabelString -> HsExpr GhcRn
|
|
| 2923 | - f acc field = genHsApps circName $ map wrapGenSpan [proj field, acc]
|
|
| 2924 | - |
|
| 2925 | - proj :: FieldLabelString -> HsExpr GhcRn
|
|
| 2926 | - proj (FieldLabelString f) = genHsVar getFieldName `genAppType` genHsTyLit f
|
|
| 2924 | + f :: LHsExpr GhcRn -> XRec GhcRn FieldLabelString -> LHsExpr GhcRn
|
|
| 2925 | + f acc field = wrapGenSpan $ genHsApps circName [proj field, acc]
|
|
| 2926 | + |
|
| 2927 | + -- Give each `getField` the SrcSpan of the label it projects, so that the
|
|
| 2928 | + -- HasField evidence for that label can be found at the label itself.
|
|
| 2929 | + -- Without this a multi-label section like (.x.y) has no usable span
|
|
| 2930 | + -- anywhere inside it, and the whole section shows no type and no
|
|
| 2931 | + -- evidence at all.
|
|
| 2932 | + -- See Note [Source locations for implicit function calls] in GHC.Iface.Ext.Ast
|
|
| 2933 | + proj :: XRec GhcRn FieldLabelString -> LHsExpr GhcRn
|
|
| 2934 | + proj lfield@(L _ (FieldLabelString f))
|
|
| 2935 | + = wrapGenSpan' (getHasLoc lfield)
|
|
| 2936 | + $ genHsVar getFieldName `genAppType` genHsTyLit f
|
|
| 2927 | 2937 | |
| 2928 | 2938 | -- mkProjUpdateSetField calculates functions representing dot notation record updates.
|
| 2929 | 2939 | -- e.g. Suppose an update like foo.bar = 1.
|
| ... | ... | @@ -29,6 +29,16 @@ nestedNoSig n = n.nested1.field2 :: Bool |
| 29 | 29 | -- ^ this is the point
|
| 30 | 30 | |
| 31 | 31 | |
| 32 | +-- Multi-label projection sections: each getField gets the SrcSpan of its own
|
|
| 33 | +-- field label, so both HasField dictionaries are reachable. Before that, no
|
|
| 34 | +-- node inside the section had a usable span and hovering it found nothing at
|
|
| 35 | +-- all. The points below are on 'nested1' and 'field1' respectively.
|
|
| 36 | +projSection :: NestedThing -> Char
|
|
| 37 | +projSection = (.nested1.field1)
|
|
| 38 | + |
|
| 39 | +projSectionApplied :: NestedThing -> Char
|
|
| 40 | +projSectionApplied n = (.nested1.field1) n
|
|
| 41 | + |
|
| 32 | 42 | |
| 33 | 43 | points =
|
| 34 | 44 | [ (13,17)
|
| ... | ... | @@ -38,6 +48,10 @@ points = |
| 38 | 48 | , (23,25)
|
| 39 | 49 | , (27,20)
|
| 40 | 50 | , (27,28)
|
| 51 | + , (37,17)
|
|
| 52 | + , (37,25)
|
|
| 53 | + , (40,26)
|
|
| 54 | + , (40,34)
|
|
| 41 | 55 | ]
|
| 42 | 56 | |
| 43 | 57 | main = do
|
| ... | ... | @@ -3,16 +3,18 @@ At point (13,17), we found: |
| 3 | 3 | ==========================
|
| 4 | 4 | ┌
|
| 5 | 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]
|
|
| 6 | +│ is an evidence variable bound by a let, depending on: [field1]
|
|
| 7 | 7 | │ with scope: ModuleScope
|
| 8 | 8 | │
|
| 9 | 9 | │ Defined at <no location info>
|
| 10 | 10 | └
|
| 11 | 11 | |
|
| 12 | 12 | `- ┌
|
| 13 | - │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
|
|
| 14 | - │ is a usage of an external evidence variable
|
|
| 15 | - │ Defined in `GHC.Internal.Records'
|
|
| 13 | + │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
|
|
| 14 | + │ is an evidence variable bound by an instance of class HasField
|
|
| 15 | + │ with scope: ModuleScope
|
|
| 16 | + │
|
|
| 17 | + │ Defined at HasFieldQueries.hs:9:21
|
|
| 16 | 18 | └
|
| 17 | 19 | |
| 18 | 20 | ==========================
|
| ... | ... | @@ -23,16 +25,18 @@ At point (16,27), we found: |
| 23 | 25 | ==========================
|
| 24 | 26 | ┌
|
| 25 | 27 | │ $dHasField at HasFieldQueries.hs:16:1-32, of type: HasField "field1" Thing Char
|
| 26 | -│ is an evidence variable bound by a let, depending on: [C:HasField]
|
|
| 28 | +│ is an evidence variable bound by a let, depending on: [field1]
|
|
| 27 | 29 | │ with scope: LocalScope HasFieldQueries.hs:16:1-32
|
| 28 | 30 | │ bound at: HasFieldQueries.hs:16:1-32
|
| 29 | 31 | │ Defined at <no location info>
|
| 30 | 32 | └
|
| 31 | 33 | |
|
| 32 | 34 | `- ┌
|
| 33 | - │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
|
|
| 34 | - │ is a usage of an external evidence variable
|
|
| 35 | - │ Defined in `GHC.Internal.Records'
|
|
| 35 | + │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
|
|
| 36 | + │ is an evidence variable bound by an instance of class HasField
|
|
| 37 | + │ with scope: ModuleScope
|
|
| 38 | + │
|
|
| 39 | + │ Defined at HasFieldQueries.hs:9:21
|
|
| 36 | 40 | └
|
| 37 | 41 | |
| 38 | 42 | ==========================
|
| ... | ... | @@ -40,16 +44,18 @@ At point (23,17), we found: |
| 40 | 44 | ==========================
|
| 41 | 45 | ┌
|
| 42 | 46 | │ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "nested1" NestedThing Thing
|
| 43 | -│ is an evidence variable bound by a let, depending on: [C:HasField]
|
|
| 47 | +│ is an evidence variable bound by a let, depending on: [nested1]
|
|
| 44 | 48 | │ with scope: ModuleScope
|
| 45 | 49 | │
|
| 46 | 50 | │ Defined at <no location info>
|
| 47 | 51 | └
|
| 48 | 52 | |
|
| 49 | 53 | `- ┌
|
| 50 | - │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
|
|
| 51 | - │ is a usage of an external evidence variable
|
|
| 52 | - │ Defined in `GHC.Internal.Records'
|
|
| 54 | + │ nested1 at HasFieldQueries.hs:1:1, of type: NestedThing -> Thing
|
|
| 55 | + │ is an evidence variable bound by an instance of class HasField
|
|
| 56 | + │ with scope: ModuleScope
|
|
| 57 | + │
|
|
| 58 | + │ Defined at HasFieldQueries.hs:20:34
|
|
| 53 | 59 | └
|
| 54 | 60 | |
| 55 | 61 | ==========================
|
| ... | ... | @@ -57,17 +63,27 @@ At point (23,25), we found: |
| 57 | 63 | ==========================
|
| 58 | 64 | ┌
|
| 59 | 65 | │ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
|
| 60 | -│ is an evidence variable bound by a let, depending on: [C:HasField]
|
|
| 66 | +│ is an evidence variable bound by a let, depending on: [$dHasField]
|
|
| 61 | 67 | │ with scope: ModuleScope
|
| 62 | 68 | │
|
| 63 | 69 | │ Defined at <no location info>
|
| 64 | 70 | └
|
| 65 | 71 | |
|
| 66 | 72 | `- ┌
|
| 67 | - │ C:HasField at HasFieldQueries.hs:1:1, of type: forall {k} (x :: k) r a. (r -> a) -> HasField x r a
|
|
| 68 | - │ is a usage of an external evidence variable
|
|
| 69 | - │ Defined in `GHC.Internal.Records'
|
|
| 73 | + │ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
|
|
| 74 | + │ is an evidence variable bound by a let, depending on: [field1]
|
|
| 75 | + │ with scope: ModuleScope
|
|
| 76 | + │
|
|
| 77 | + │ Defined at <no location info>
|
|
| 70 | 78 | └
|
| 79 | + |
|
|
| 80 | + `- ┌
|
|
| 81 | + │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
|
|
| 82 | + │ is an evidence variable bound by an instance of class HasField
|
|
| 83 | + │ with scope: ModuleScope
|
|
| 84 | + │
|
|
| 85 | + │ Defined at HasFieldQueries.hs:9:21
|
|
| 86 | + └
|
|
| 71 | 87 | |
| 72 | 88 | ==========================
|
| 73 | 89 | At point (27,20), we found:
|
| ... | ... | @@ -107,3 +123,87 @@ At point (27,28), we found: |
| 107 | 123 | │ Defined at <no location info>
|
| 108 | 124 | └
|
| 109 | 125 | |
| 126 | +==========================
|
|
| 127 | +At point (37,17), we found:
|
|
| 128 | +==========================
|
|
| 129 | +┌
|
|
| 130 | +│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "nested1" NestedThing Thing
|
|
| 131 | +│ is an evidence variable bound by a let, depending on: [nested1]
|
|
| 132 | +│ with scope: ModuleScope
|
|
| 133 | +│
|
|
| 134 | +│ Defined at <no location info>
|
|
| 135 | +└
|
|
| 136 | +|
|
|
| 137 | +`- ┌
|
|
| 138 | + │ nested1 at HasFieldQueries.hs:1:1, of type: NestedThing -> Thing
|
|
| 139 | + │ is an evidence variable bound by an instance of class HasField
|
|
| 140 | + │ with scope: ModuleScope
|
|
| 141 | + │
|
|
| 142 | + │ Defined at HasFieldQueries.hs:20:34
|
|
| 143 | + └
|
|
| 144 | + |
|
| 145 | +==========================
|
|
| 146 | +At point (37,25), we found:
|
|
| 147 | +==========================
|
|
| 148 | +┌
|
|
| 149 | +│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
|
|
| 150 | +│ is an evidence variable bound by a let, depending on: [$dHasField]
|
|
| 151 | +│ with scope: ModuleScope
|
|
| 152 | +│
|
|
| 153 | +│ Defined at <no location info>
|
|
| 154 | +└
|
|
| 155 | +|
|
|
| 156 | +`- ┌
|
|
| 157 | + │ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
|
|
| 158 | + │ is an evidence variable bound by a let, depending on: [field1]
|
|
| 159 | + │ with scope: ModuleScope
|
|
| 160 | + │
|
|
| 161 | + │ Defined at <no location info>
|
|
| 162 | + └
|
|
| 163 | + |
|
|
| 164 | + `- ┌
|
|
| 165 | + │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
|
|
| 166 | + │ is an evidence variable bound by an instance of class HasField
|
|
| 167 | + │ with scope: ModuleScope
|
|
| 168 | + │
|
|
| 169 | + │ Defined at HasFieldQueries.hs:9:21
|
|
| 170 | + └
|
|
| 171 | + |
|
| 172 | +==========================
|
|
| 173 | +At point (40,26), we found:
|
|
| 174 | +==========================
|
|
| 175 | +┌
|
|
| 176 | +│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "nested1" NestedThing Thing
|
|
| 177 | +│ is an evidence variable bound by a let, depending on: [nested1]
|
|
| 178 | +│ with scope: ModuleScope
|
|
| 179 | +│
|
|
| 180 | +│ Defined at <no location info>
|
|
| 181 | +└
|
|
| 182 | +|
|
|
| 183 | +`- ┌
|
|
| 184 | + │ nested1 at HasFieldQueries.hs:1:1, of type: NestedThing -> Thing
|
|
| 185 | + │ is an evidence variable bound by an instance of class HasField
|
|
| 186 | + │ with scope: ModuleScope
|
|
| 187 | + │
|
|
| 188 | + │ Defined at HasFieldQueries.hs:20:34
|
|
| 189 | + └
|
|
| 190 | + |
|
| 191 | +==========================
|
|
| 192 | +At point (40,34), we found:
|
|
| 193 | +==========================
|
|
| 194 | +┌
|
|
| 195 | +│ $dHasField at HasFieldQueries.hs:1:1, of type: HasField "field1" Thing Char
|
|
| 196 | +│ is an evidence variable bound by a let, depending on: [field1]
|
|
| 197 | +│ with scope: ModuleScope
|
|
| 198 | +│
|
|
| 199 | +│ Defined at <no location info>
|
|
| 200 | +└
|
|
| 201 | +|
|
|
| 202 | +`- ┌
|
|
| 203 | + │ field1 at HasFieldQueries.hs:1:1, of type: Thing -> Char
|
|
| 204 | + │ is an evidence variable bound by an instance of class HasField
|
|
| 205 | + │ with scope: ModuleScope
|
|
| 206 | + │
|
|
| 207 | + │ Defined at HasFieldQueries.hs:9:21
|
|
| 208 | + └
|
|
| 209 | + |
| 1 | +{-# LANGUAGE OverloadedRecordDot #-}
|
|
| 2 | + |
|
| 3 | +-- The renamer expands @e.fld@ to @getField \@"fld" e@ (mkGetField in
|
|
| 4 | +-- GHC.Rename.Expr). For the sake of .hie files the application head of that
|
|
| 5 | +-- expansion carries the SrcSpan of the field label, but it must be a
|
|
| 6 | +-- *generated* span (@GeneratedSrcSpan (OrigSpan ...)@, built by wrapGenSpan')
|
|
| 7 | +-- rather than a plain RealSrcSpan, or else isGeneratedSrcSpan is False and
|
|
| 8 | +-- GHC.Tc.Gen.App starts reporting the internal 'getField' to the user.
|
|
| 9 | +--
|
|
| 10 | +-- The CtOrigin site (mk_origin) is already covered by T26480b, which contrasts
|
|
| 11 | +-- an explicit 'getField' ("arising from a use of `getField'") with record dot
|
|
| 12 | +-- syntax ("arising from selecting the field `x'"); see also T19843h and
|
|
| 13 | +-- RecordDotSyntaxFail8. The result-type site is covered by
|
|
| 14 | +-- RecordDotSyntaxFail9.
|
|
| 15 | +--
|
|
| 16 | +-- What is *not* covered anywhere else is addArgCtxt (GHC.Tc.Gen.App), which
|
|
| 17 | +-- needs an ill-typed argument underneath the selection. With a real head span
|
|
| 18 | +-- the second error below would gain a
|
|
| 19 | +-- "In the first argument of `getField', namely `('c' + 1)'"
|
|
| 20 | +-- context line.
|
|
| 21 | +module RecordDotErrCtxt where
|
|
| 22 | + |
|
| 23 | +data T = MkT { fld :: Int }
|
|
| 24 | + |
|
| 25 | +argCtxt :: Int
|
|
| 26 | +argCtxt = ('c' + 1).fld |
| 1 | +RecordDotErrCtxt.hs:26:11: error: [GHC-39999]
|
|
| 2 | + • No instance for ‘GHC.Internal.Records.HasField "fld" Char Int’
|
|
| 3 | + arising from selecting the field ‘fld’
|
|
| 4 | + NB: ‘Char’ is not a record type.
|
|
| 5 | + • In the expression: ('c' + 1).fld
|
|
| 6 | + In an equation for ‘argCtxt’: argCtxt = ('c' + 1).fld
|
|
| 7 | + |
|
| 8 | +RecordDotErrCtxt.hs:26:16: error: [GHC-39999]
|
|
| 9 | + • No instance for ‘Num Char’ arising from a use of ‘+’
|
|
| 10 | + • In the expression: 'c' + 1
|
|
| 11 | + In the expression: ('c' + 1).fld
|
|
| 12 | + In an equation for ‘argCtxt’: argCtxt = ('c' + 1).fld
|
|
| 13 | + |
| ... | ... | @@ -63,3 +63,4 @@ test('T23010_fail', [extra_files(['T23010_fail.hs-boot', 'T23010_fail_aux.hs'])] |
| 63 | 63 | , multimod_compile_fail
|
| 64 | 64 | , ['T23010_fail T23010_fail_aux', '-v0'])
|
| 65 | 65 | test('T23063', extra_files(['T23063_aux.hs']), multimod_compile_fail, ['T23063', '-v0'])
|
| 66 | +test('RecordDotErrCtxt', normal, compile_fail, ['']) |