summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/GHC/Rename/Bind.hs2
-rw-r--r--compiler/GHC/Rename/Env.hs17
-rw-r--r--compiler/GHC/Tc/Errors/Ppr.hs18
-rw-r--r--compiler/GHC/Tc/Errors/Types.hs7
-rw-r--r--compiler/GHC/Types/Error.hs20
-rw-r--r--compiler/GHC/Types/Error/Codes.hs1
-rw-r--r--compiler/GHC/Types/Hint.hs7
-rw-r--r--compiler/GHC/Types/Hint/Ppr.hs8
-rw-r--r--testsuite/tests/typecheck/should_fail/AssocTyDef01.stderr10
-rw-r--r--testsuite/tests/typecheck/should_fail/AssocTyDef07.stderr10
-rw-r--r--testsuite/tests/typecheck/should_fail/AssocTyDef08.stderr10
-rw-r--r--testsuite/tests/typecheck/should_fail/AssocTyDef09.stderr10
12 files changed, 102 insertions, 18 deletions
diff --git a/compiler/GHC/Rename/Bind.hs b/compiler/GHC/Rename/Bind.hs
index 7f3edf841c..8f650fccfd 100644
--- a/compiler/GHC/Rename/Bind.hs
+++ b/compiler/GHC/Rename/Bind.hs
@@ -936,7 +936,7 @@ rnMethodBindLHS :: Bool -> Name
-> RnM (LHsBindsLR GhcRn GhcPs)
rnMethodBindLHS _ cls (L loc bind@(FunBind { fun_id = name })) rest
= setSrcSpanA loc $ do
- do { sel_name <- wrapLocMA (lookupInstDeclBndr cls (text "method")) name
+ do { sel_name <- wrapLocMA (lookupInstDeclBndr cls "method") name
-- We use the selector name as the binder
; let bind' = bind { fun_id = sel_name, fun_ext = noExtField }
; return (L loc bind' `consBag` rest ) }
diff --git a/compiler/GHC/Rename/Env.hs b/compiler/GHC/Rename/Env.hs
index 3d3ded48f0..c79dfb38c1 100644
--- a/compiler/GHC/Rename/Env.hs
+++ b/compiler/GHC/Rename/Env.hs
@@ -350,7 +350,7 @@ lookupExactOcc_either name
}
-----------------------------------------------
-lookupInstDeclBndr :: Name -> SDoc -> RdrName -> RnM Name
+lookupInstDeclBndr :: Name -> String -> RdrName -> RnM Name
-- This is called on the method name on the left-hand side of an
-- instance declaration binding. eg. instance Functor T where
-- fmap = ...
@@ -378,11 +378,20 @@ lookupInstDeclBndr cls what rdr
-- when it's used
cls doc rdr
; case mb_name of
- Left err -> do { addErr (mkTcRnNotInScope rdr err)
+ Left err ->
+ -- If `what` is an associated type, we ignore the `err` value and create
+ -- our own error specifically dealing with associated types
+ case what of
+ "associated type" -> do { srcSpan <- getSrcSpanM
+ ; code <- liftIO $ getSrcCodeString srcSpan
+ ; addErr (mkTcRnNotInScope rdr (UnknownAssociatedType cls rdr code))
+ ; return (mkUnboundNameRdr rdr) }
+
+ _ -> do { addErr (mkTcRnNotInScope rdr err)
; return (mkUnboundNameRdr rdr) }
Right nm -> return nm }
where
- doc = what <+> text "of class" <+> quotes (ppr cls)
+ doc = text what <+> text "of class" <+> quotes (ppr cls)
-----------------------------------------------
lookupFamInstName :: Maybe Name -> LocatedN RdrName
@@ -390,7 +399,7 @@ lookupFamInstName :: Maybe Name -> LocatedN RdrName
-- Used for TyData and TySynonym family instances only,
-- See Note [Family instance binders]
lookupFamInstName (Just cls) tc_rdr -- Associated type; c.f GHC.Rename.Bind.rnMethodBind
- = wrapLocMA (lookupInstDeclBndr cls (text "associated type")) tc_rdr
+ = wrapLocMA (lookupInstDeclBndr cls "associated type") tc_rdr
lookupFamInstName Nothing tc_rdr -- Family instance; tc_rdr is an *occurrence*
= lookupLocatedOccRnConstr tc_rdr
diff --git a/compiler/GHC/Tc/Errors/Ppr.hs b/compiler/GHC/Tc/Errors/Ppr.hs
index 8dae970dee..4ace7d3398 100644
--- a/compiler/GHC/Tc/Errors/Ppr.hs
+++ b/compiler/GHC/Tc/Errors/Ppr.hs
@@ -3074,7 +3074,20 @@ pprScopeError rdr_name scope_err =
hang (text "No top-level binding for")
2 (what <+> quotes (ppr rdr_name) <+> text "in this module")
UnknownSubordinate doc ->
- quotes (ppr rdr_name) <+> text "is not a (visible)" <+> doc
+ quotes (ppr rdr_name) <+> text "is not a (visible)" <+> doc
+ UnknownAssociatedType _ _ code ->
+ case code of
+ Just c ->
+ text "The line:"
+ $+$ nest 2 (pprCode $ text c)
+ $+$ text "defines a default equation for type" <+> sname
+ <+> text "but" <+> sname <+> text "itself has not been declared."
+ Nothing ->
+ text "A default equation for" <+> sname <+> text "was found, but" <+> sname
+ <+> text "has not been declared."
+ where
+ sname = quotes (ppr rdr_name)
+
where
what = pprNonVarNameSpace (occNameSpace (rdrNameOcc rdr_name))
@@ -3087,6 +3100,9 @@ scopeErrorHints scope_err =
MissingBinding _ hints -> hints
NoTopLevelBinding -> noHints
UnknownSubordinate {} -> noHints
+ UnknownAssociatedType name rdr code ->
+ [SuggestDeclareAssociatedType name rdr decl]
+ where decl = head . split '=' <$> code
{- *********************************************************************
* *
diff --git a/compiler/GHC/Tc/Errors/Types.hs b/compiler/GHC/Tc/Errors/Types.hs
index 854ebd3bf6..0ce9831dfb 100644
--- a/compiler/GHC/Tc/Errors/Types.hs
+++ b/compiler/GHC/Tc/Errors/Types.hs
@@ -3248,6 +3248,13 @@ data NotInScopeError
-- or, a class doesn't have an associated type with this name,
-- or, a record doesn't have a record field with this name.
| UnknownSubordinate SDoc
+
+ -- | A class doesn't have an associated type with this name.
+ | UnknownAssociatedType
+ { typeclassName :: Name -- ^ The name of the typeclass with the missing type decl
+ , associatedTypeName :: RdrName -- ^ The name of the undeclared associated type
+ , srcCode :: Maybe String -- ^ The source code that caused the error. Derived from SrcSpan
+ }
deriving Generic
-- | Create a @"not in scope"@ error message for the given 'RdrName'.
diff --git a/compiler/GHC/Types/Error.hs b/compiler/GHC/Types/Error.hs
index 3c8ff8b4bb..d2deb57d63 100644
--- a/compiler/GHC/Types/Error.hs
+++ b/compiler/GHC/Types/Error.hs
@@ -56,6 +56,7 @@ module GHC.Types.Error
, pprMessageBag
, mkLocMessage
, mkLocMessageWarningGroups
+ , getSrcCodeString
, getCaretDiagnostic
-- * Queries
, isIntrinsicErrorMessage
@@ -526,10 +527,14 @@ getMessageClassColour (MCDiagnostic SevWarning _reason _code) = Col.sWarning
getMessageClassColour MCFatal = Col.sFatal
getMessageClassColour _ = const mempty
-getCaretDiagnostic :: MessageClass -> SrcSpan -> IO SDoc
-getCaretDiagnostic _ (UnhelpfulSpan _) = pure empty
-getCaretDiagnostic msg_class (RealSrcSpan span _) =
- caretDiagnostic <$> getSrcLine (srcSpanFile span) row
+-- | Get the snippet of code referenced by `SrcSpan`
+--
+-- We need this so that we can include the source code within our error message.
+-- E.g: https://gitlab.haskell.org/ghc/ghc/-/issues/21100
+getSrcCodeString :: SrcSpan -> IO (Maybe String)
+getSrcCodeString (UnhelpfulSpan _) = pure Nothing
+getSrcCodeString (RealSrcSpan span _) =
+ getSrcLine (srcSpanFile span) row
where
getSrcLine fn i =
getLine i (unpackFS fn)
@@ -549,11 +554,18 @@ getCaretDiagnostic msg_class (RealSrcSpan span _) =
_ -> Nothing
_ -> pure Nothing
+ row = srcSpanStartLine span
+
-- allow user to visibly see that their code is incorrectly encoded
-- (StringBuffer.nextChar uses \0 to represent undecodable characters)
fix '\0' = '\xfffd'
fix c = c
+getCaretDiagnostic :: MessageClass -> SrcSpan -> IO SDoc
+getCaretDiagnostic _ (UnhelpfulSpan _) = pure empty
+getCaretDiagnostic msg_class srcSpan@(RealSrcSpan span _) =
+ caretDiagnostic <$> getSrcCodeString srcSpan
+ where
row = srcSpanStartLine span
rowStr = show row
multiline = row /= srcSpanEndLine span
diff --git a/compiler/GHC/Types/Error/Codes.hs b/compiler/GHC/Types/Error/Codes.hs
index 00346aa722..b039193224 100644
--- a/compiler/GHC/Types/Error/Codes.hs
+++ b/compiler/GHC/Types/Error/Codes.hs
@@ -502,6 +502,7 @@ type family GhcDiagnosticCode c = n | n -> c where
GhcDiagnosticCode "MissingBinding" = 44432
GhcDiagnosticCode "NoTopLevelBinding" = 10173
GhcDiagnosticCode "UnknownSubordinate" = 54721
+ GhcDiagnosticCode "UnknownAssociatedType" = 87875
-- Diagnostic codes for deriving
GhcDiagnosticCode "DerivErrNotWellKinded" = 62016
diff --git a/compiler/GHC/Types/Hint.hs b/compiler/GHC/Types/Hint.hs
index 31f8d4422b..8ae2733baa 100644
--- a/compiler/GHC/Types/Hint.hs
+++ b/compiler/GHC/Types/Hint.hs
@@ -417,6 +417,13 @@ data GhcHint
Test cases: none
-}
| SuggestSpecialiseVisibilityHints Name
+ {-| Suggest to declare the associated type
+ -}
+ | SuggestDeclareAssociatedType
+ { typeclassName :: Name -- ^ The name of the typeclass with the missing type decl
+ , associatedTypeName :: RdrName -- ^ The name of the undeclared associated type
+ , typeDecl :: Maybe String -- ^ The code suggestion of how to declare the associated type
+ }
-- | An 'InstantiationSuggestion' for a '.hsig' file. This is generated
-- by GHC in case of a 'DriverUnexpectedSignature' and suggests a way
diff --git a/compiler/GHC/Types/Hint/Ppr.hs b/compiler/GHC/Types/Hint/Ppr.hs
index 53890e8daf..25b6476aab 100644
--- a/compiler/GHC/Types/Hint/Ppr.hs
+++ b/compiler/GHC/Types/Hint/Ppr.hs
@@ -206,6 +206,14 @@ instance Outputable GhcHint where
<+> quotes (ppr name) <+> text "has an INLINABLE pragma"
where
mod = nameModule name
+ SuggestDeclareAssociatedType name rdrName (Just decl)
+ -> text "Declare" <+> quotes (ppr rdrName) <+> text "by adding:"
+ $+$ nest 2 (pprCode $ text decl)
+ $+$ text "to the class" <+> quotes (ppr name)
+ SuggestDeclareAssociatedType name rdrName Nothing
+ -> text "Declare the associated type" <+> quotes (ppr rdrName)
+ <+> text "for class" <+> quotes (ppr name)
+ <+> text "in addition to the default equation"
perhapsAsPat :: SDoc
perhapsAsPat = text "Perhaps you meant an as-pattern, which must not be surrounded by whitespace"
diff --git a/testsuite/tests/typecheck/should_fail/AssocTyDef01.stderr b/testsuite/tests/typecheck/should_fail/AssocTyDef01.stderr
index 546803fcde..0aa62b1e37 100644
--- a/testsuite/tests/typecheck/should_fail/AssocTyDef01.stderr
+++ b/testsuite/tests/typecheck/should_fail/AssocTyDef01.stderr
@@ -1,3 +1,9 @@
-AssocTyDef01.hs:9:10: error: [GHC-54721]
- ‘OtherType’ is not a (visible) associated type of class ‘Cls’
+AssocTyDef01.hs:9:10: [GHC-87875]
+ The line:
+ type OtherType a = Int
+ defines a default equation for type ‘OtherType’ but ‘OtherType’ itself has not been declared.
+ Suggested fix:
+ Declare ‘OtherType’ by adding:
+ type OtherType a
+ to the class ‘Cls’ \ No newline at end of file
diff --git a/testsuite/tests/typecheck/should_fail/AssocTyDef07.stderr b/testsuite/tests/typecheck/should_fail/AssocTyDef07.stderr
index 30595d68aa..3dba70418f 100644
--- a/testsuite/tests/typecheck/should_fail/AssocTyDef07.stderr
+++ b/testsuite/tests/typecheck/should_fail/AssocTyDef07.stderr
@@ -1,3 +1,9 @@
-AssocTyDef07.hs:5:10: error: [GHC-54721]
- ‘Typ’ is not a (visible) associated type of class ‘Cls’
+AssocTyDef07.hs:5:10: [GHC-87875]
+ The line:
+ type Typ a = Int
+ defines a default equation for type ‘Typ’ but ‘Typ’ itself has not been declared.
+ Suggested fix:
+ Declare ‘Typ’ by adding:
+ type Typ a
+ to the class ‘Cls’ \ No newline at end of file
diff --git a/testsuite/tests/typecheck/should_fail/AssocTyDef08.stderr b/testsuite/tests/typecheck/should_fail/AssocTyDef08.stderr
index 1d2494243e..e51fae1abd 100644
--- a/testsuite/tests/typecheck/should_fail/AssocTyDef08.stderr
+++ b/testsuite/tests/typecheck/should_fail/AssocTyDef08.stderr
@@ -1,3 +1,9 @@
-AssocTyDef08.hs:4:10: error: [GHC-54721]
- ‘Typ’ is not a (visible) associated type of class ‘Cls’
+AssocTyDef08.hs:4:10: [GHC-87875]
+ The line:
+ type Typ a = Int
+ defines a default equation for type ‘Typ’ but ‘Typ’ itself has not been declared.
+ Suggested fix:
+ Declare ‘Typ’ by adding:
+ type Typ a
+ to the class ‘Cls’ \ No newline at end of file
diff --git a/testsuite/tests/typecheck/should_fail/AssocTyDef09.stderr b/testsuite/tests/typecheck/should_fail/AssocTyDef09.stderr
index 4bcf093a88..c8b84a6dbd 100644
--- a/testsuite/tests/typecheck/should_fail/AssocTyDef09.stderr
+++ b/testsuite/tests/typecheck/should_fail/AssocTyDef09.stderr
@@ -1,3 +1,9 @@
-AssocTyDef09.hs:8:10: error: [GHC-54721]
- ‘OtherType’ is not a (visible) associated type of class ‘Cls’
+AssocTyDef09.hs:8:10: [GHC-87875]
+ The line:
+ type OtherType a = Int
+ defines a default equation for type ‘OtherType’ but ‘OtherType’ itself has not been declared.
+ Suggested fix:
+ Declare ‘OtherType’ by adding:
+ type OtherType a
+ to the class ‘Cls’ \ No newline at end of file