diff options
author | Simon Peyton Jones <simonpj@microsoft.com> | 2021-02-11 14:44:20 +0000 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2021-02-19 11:03:46 -0500 |
commit | 4196969c53c55191e644d9eb258c14c2bc8467da (patch) | |
tree | bb4608ff96e916c204b6837405690190b70c59db /compiler/GHC/Rename/Env.hs | |
parent | f78f001c91736e31cdfb23959647226f9bd9fe6b (diff) | |
download | haskell-4196969c53c55191e644d9eb258c14c2bc8467da.tar.gz |
Improve handling of overloaded labels, literals, lists etcwip/T19154
When implementing Quick Look I'd failed to remember that overloaded
labels, like #foo, should be treated as a "head", so that they can be
instantiated with Visible Type Application. This caused #19154.
A very similar ticket covers overloaded literals: #19167.
This patch fixes both problems, but (annoyingly, albeit temporarily)
in two different ways.
Overloaded labels
I dealt with overloaded labels by buying fully into the
Rebindable Syntax approach described in GHC.Hs.Expr
Note [Rebindable syntax and HsExpansion].
There is a good overview in GHC.Rename.Expr
Note [Handling overloaded and rebindable constructs].
That module contains much of the payload for this patch.
Specifically:
* Overloaded labels are expanded in the renamer, fixing #19154.
See Note [Overloaded labels] in GHC.Rename.Expr.
* Left and right sections used to have special code paths in the
typechecker and desugarer. Now we just expand them in the
renamer. This is harder than it sounds. See GHC.Rename.Expr
Note [Left and right sections].
* Infix operator applications are expanded in the typechecker,
specifically in GHC.Tc.Gen.App.splitHsApps. See
Note [Desugar OpApp in the typechecker] in that module
* ExplicitLists are expanded in the renamer, when (and only when)
OverloadedLists is on.
* HsIf is expanded in the renamer when (and only when) RebindableSyntax
is on. Reason: the coverage checker treats HsIf specially. Maybe
we could instead expand it unconditionally, and fix up the coverage
checker, but I did not attempt that.
Overloaded literals
Overloaded literals, like numbers (3, 4.2) and strings with
OverloadedStrings, were not working correctly with explicit type
applications (see #19167). Ideally I'd also expand them in the
renamer, like the stuff above, but I drew back on that because they
can occur in HsPat as well, and I did not want to to do the HsExpanded
thing for patterns.
But they *can* now be the "head" of an application in the typechecker,
and hence something like ("foo" @T) works now. See
GHC.Tc.Gen.Head.tcInferOverLit. It's also done a bit more elegantly,
rather than by constructing a new HsExpr and re-invoking the
typechecker. There is some refactoring around tcShortCutLit.
Ultimately there is more to do here, following the Rebindable Syntax
story.
There are a lot of knock-on effects:
* HsOverLabel and ExplicitList no longer need funny (Maybe SyntaxExpr)
fields to support rebindable syntax -- good!
* HsOverLabel, OpApp, SectionL, SectionR all become impossible in the
output of the typecheker, GhcTc; so we set their extension fields to
Void. See GHC.Hs.Expr Note [Constructor cannot occur]
* Template Haskell quotes for HsExpanded is a bit tricky. See
Note [Quotation and rebindable syntax] in GHC.HsToCore.Quote.
* In GHC.HsToCore.Match.viewLExprEq, which groups equal HsExprs for the
purpose of pattern-match overlap checking, I found that dictionary
evidence for the same type could have two different names. Easily
fixed by comparing types not names.
* I did quite a bit of annoying fiddling around in GHC.Tc.Gen.Head and
GHC.Tc.Gen.App to get error message locations and contexts right,
esp in splitHsApps, and the HsExprArg type. Tiresome and not very
illuminating. But at least the tricky, higher order, Rebuilder
function is gone.
* Some refactoring in GHC.Tc.Utils.Monad around contexts and locations
for rebindable syntax.
* Incidentally fixes #19346, because we now print renamed, rather than
typechecked, syntax in error mesages about applications.
The commit removes the vestigial module GHC.Builtin.RebindableNames,
and thus triggers a 2.4% metric decrease for test MultiLayerModules
(#19293).
Metric Decrease:
MultiLayerModules
T12545
Diffstat (limited to 'compiler/GHC/Rename/Env.hs')
-rw-r--r-- | compiler/GHC/Rename/Env.hs | 77 |
1 files changed, 27 insertions, 50 deletions
diff --git a/compiler/GHC/Rename/Env.hs b/compiler/GHC/Rename/Env.hs index 4b5d5d7af3..b1a8ce0351 100644 --- a/compiler/GHC/Rename/Env.hs +++ b/compiler/GHC/Rename/Env.hs @@ -40,8 +40,9 @@ module GHC.Rename.Env ( lookupGreAvailRn, -- Rebindable Syntax - lookupSyntax, lookupSyntaxExpr, lookupSyntaxName, lookupSyntaxNames, - lookupIfThenElse, lookupReboundIf, + lookupSyntax, lookupSyntaxExpr, lookupSyntaxNames, + lookupSyntaxName, + lookupIfThenElse, -- QualifiedDo lookupQualifiedDoExpr, lookupQualifiedDo, @@ -67,7 +68,6 @@ import GHC.Types.Name.Reader import GHC.Tc.Utils.Env import GHC.Tc.Utils.Monad import GHC.Parser.PostProcess ( setRdrNameSpace ) -import GHC.Builtin.RebindableNames import GHC.Builtin.Types import GHC.Types.Name import GHC.Types.Name.Set @@ -1950,40 +1950,42 @@ We treat the original (standard) names as free-vars too, because the type checke checks the type of the user thing against the type of the standard thing. -} -lookupIfThenElse :: Bool -- False <=> don't use rebindable syntax under any conditions - -> RnM (SyntaxExpr GhcRn, FreeVars) --- Different to lookupSyntax because in the non-rebindable --- case we desugar directly rather than calling an existing function --- Hence the (Maybe (SyntaxExpr GhcRn)) return type -lookupIfThenElse maybe_use_rs +lookupIfThenElse :: RnM (Maybe Name) +-- Looks up "ifThenElse" if rebindable syntax is on +lookupIfThenElse = do { rebindable_on <- xoptM LangExt.RebindableSyntax - ; if not (rebindable_on && maybe_use_rs) - then return (NoSyntaxExprRn, emptyFVs) + ; if not rebindable_on + then return Nothing else do { ite <- lookupOccRn (mkVarUnqual (fsLit "ifThenElse")) - ; return ( mkRnSyntaxExpr ite - , unitFV ite ) } } + ; return (Just ite) } } -lookupSyntaxName :: Name -- ^ The standard name - -> RnM (Name, FreeVars) -- ^ Possibly a non-standard name +lookupSyntaxName :: Name -- ^ The standard name + -> RnM (Name, FreeVars) -- ^ Possibly a non-standard name +-- Lookup a Name that may be subject to Rebindable Syntax (RS). +-- +-- - When RS is off, just return the supplied (standard) Name +-- +-- - When RS is on, look up the OccName of the supplied Name; return +-- what we find, or the supplied Name if there is nothing in scope lookupSyntaxName std_name - = do { rebindable_on <- xoptM LangExt.RebindableSyntax - ; if not rebindable_on then - return (std_name, emptyFVs) - else - -- Get the similarly named thing from the local environment - do { usr_name <- lookupOccRn (mkRdrUnqual (nameOccName std_name)) - ; return (usr_name, unitFV usr_name) } } + = do { rebind <- xoptM LangExt.RebindableSyntax + ; if not rebind + then return (std_name, emptyFVs) + else do { nm <- lookupOccRn (mkRdrUnqual (nameOccName std_name)) + ; return (nm, unitFV nm) } } lookupSyntaxExpr :: Name -- ^ The standard name -> RnM (HsExpr GhcRn, FreeVars) -- ^ Possibly a non-standard name lookupSyntaxExpr std_name - = fmap (first nl_HsVar) $ lookupSyntaxName std_name + = do { (name, fvs) <- lookupSyntaxName std_name + ; return (nl_HsVar name, fvs) } lookupSyntax :: Name -- The standard name -> RnM (SyntaxExpr GhcRn, FreeVars) -- Possibly a non-standard -- name lookupSyntax std_name - = fmap (first mkSyntaxExpr) $ lookupSyntaxExpr std_name + = do { (expr, fvs) <- lookupSyntaxExpr std_name + ; return (mkSyntaxExpr expr, fvs) } lookupSyntaxNames :: [Name] -- Standard names -> RnM ([HsExpr GhcRn], FreeVars) -- See comments with HsExpr.ReboundNames @@ -1996,6 +1998,7 @@ lookupSyntaxNames std_names do { usr_names <- mapM (lookupOccRn . mkRdrUnqual . nameOccName) std_names ; return (map (HsVar noExtField . noLoc) usr_names, mkFVs usr_names) } } + {- Note [QualifiedDo] ~~~~~~~~~~~~~~~~~~ @@ -2040,34 +2043,8 @@ lookupQualifiedDoName ctxt std_name Just modName -> lookupNameWithQualifier std_name modName --- Lookup a locally-rebound name for Rebindable Syntax (RS). --- --- - When RS is off, 'lookupRebound' just returns 'Nothing', whatever --- name it is given. --- --- - When RS is on, we always try to return a 'Just', and GHC errors out --- if no suitable name is found in the environment. --- --- 'Nothing' really is "reserved" and means that rebindable syntax is off. -lookupRebound :: FastString -> RnM (Maybe (Located Name)) -lookupRebound nameStr = do - rebind <- xoptM LangExt.RebindableSyntax - if rebind - -- If repetitive lookups ever become a problem perormance-wise, - -- we could lookup all the names we will ever care about just once - -- at the beginning and stick them in the environment, possibly - -- populating that "cache" lazily too. - then (\nm -> Just (L (nameSrcSpan nm) nm)) <$> - lookupOccRn (mkVarUnqual nameStr) - else pure Nothing - --- | Lookup an @ifThenElse@ binding (see 'lookupRebound'). -lookupReboundIf :: RnM (Maybe (Located Name)) -lookupReboundIf = lookupRebound reboundIfSymbol - -- Error messages - opDeclErr :: RdrName -> SDoc opDeclErr n = hang (text "Illegal declaration of a type or class operator" <+> quotes (ppr n)) |