Name qualification reported to the user can be extremely confusing
Consider the following program:
-- M.hs
module M where
data A = A
-- N.hs
module N where
import qualified M as X (A)
import qualified M as Y (A(..))
test = X.A
Look at the awfully confusing error message we get:
• Illegal term-level use of the type constructor ‘Y.A’
• Perhaps use ‘Y.A’
• In the expression: Y.A
In an equation for ‘test’: test = Y.A
|
5 | test = X.A
| ^^^
Now this is really strange:
- GHC says
Illegal term-level use of the type constructor ‘Y.A’
, but the user wroteX.A
- Then it suggests to use
Y.A
... which is what GHC just said was illegal! - The "in the expression" context also uses
Y.A
even though the user wroteX.A
!
The reason this is all so weird is that, in the renamer, we see the user-written Qual
RdrName
X.A
, and resolve it to the Name
of the type constructor A
. We then move forward with this Name
, but lose track of the original user-written qualification. The way GHC deals with this (in general) is that it tries to "guess" a possible qualification when printing out Name
s, omitting qualification entirely if we can determine that the unqualified identifier is in scope and is unambiguous (see GHC.Types.Name.Ppr.{mkNamePprCtx,mkQualName}
).
I think there are two separate issues here:
- The logic in
mkQualName
does not correctly account for namespace clashes.mkQualName
erroneously concludes thatY.A
is unambiguous, because it only looks in the type constructorNameSpace
(in which indeedY.A
is unambiguous). - We lose track of user-written qualification after renaming.
My plan to address (2) is to store the original user-written RdrName
in the extension fields for HsVar
, RecordCon
and ConPat
. This should allow us to update the logic in mkQualName
to prefer the user-written qualification (when it is unambiguous).