[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 4 commits: If we have multiple defaulting plugins, then we should zonk in between them
Marge Bot (@marge-bot)
gitlab at gitlab.haskell.org
Fri Sep 8 05:24:35 UTC 2023
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
d72585e6 by Gergő Érdi at 2023-09-08T01:24:23-04:00
If we have multiple defaulting plugins, then we should zonk in between them
after any defaulting has taken place, to avoid a defaulting plugin seeing
a metavariable that has already been filled.
Fixes #23821.
- - - - -
b4b82878 by Gergő Érdi at 2023-09-08T01:24:23-04:00
Improvements to the documentation of defaulting plugins
Based on @simonpj's draft and comments in !11117
- - - - -
ceb9c0e4 by Alan Zimmerman at 2023-09-08T01:24:24-04:00
EPA: Incorrect span for LWarnDec GhcPs
The code (from T23465.hs)
{-# WARNInG in "x-c" e "d" #-}
e = e
gives an incorrect span for the LWarnDecl GhcPs
Closes #23892
It also fixes the Test23465/Test23464 mixup
- - - - -
f579652e by Krzysztof Gogolewski at 2023-09-08T01:24:24-04:00
Valid hole fits: don't suggest unsafeCoerce (#17940)
- - - - -
16 changed files:
- compiler/GHC/Hs/Decls.hs
- compiler/GHC/Parser.y
- compiler/GHC/Parser/Annotation.hs
- compiler/GHC/Tc/Errors/Hole.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Types.hs
- docs/users_guide/extending_ghc.rst
- testsuite/tests/printer/Makefile
- − testsuite/tests/printer/Test23464.hs
- + testsuite/tests/printer/Test23465.hs
- testsuite/tests/printer/all.T
- + testsuite/tests/typecheck/should_fail/T17940.hs
- + testsuite/tests/typecheck/should_fail/T17940.stderr
- testsuite/tests/typecheck/should_fail/all.T
- utils/check-exact/ExactPrint.hs
- utils/check-exact/Main.hs
Changes:
=====================================
compiler/GHC/Hs/Decls.hs
=====================================
@@ -1268,7 +1268,7 @@ type instance XXWarnDecl (GhcPass _) = DataConCantHappen
instance OutputableBndrId p
=> Outputable (WarnDecls (GhcPass p)) where
ppr (Warnings ext decls)
- = ftext src <+> vcat (punctuate comma (map ppr decls)) <+> text "#-}"
+ = ftext src <+> vcat (punctuate semi (map ppr decls)) <+> text "#-}"
where src = case ghcPass @p of
GhcPs | (_, SourceText src) <- ext -> src
GhcRn | SourceText src <- ext -> src
=====================================
compiler/GHC/Parser.y
=====================================
@@ -2002,8 +2002,8 @@ warnings :: { OrdList (LWarnDecl GhcPs) }
-- SUP: TEMPORARY HACK, not checking for `module Foo'
warning :: { OrdList (LWarnDecl GhcPs) }
: warning_category namelist strings
- {% fmap unitOL $ acsA (\cs -> sLL $2 $>
- (Warning (EpAnn (glR $2) (fst $ unLoc $3) cs) (unLoc $2)
+ {% fmap unitOL $ acsA (\cs -> L (comb3 $1 $2 $3)
+ (Warning (EpAnn (glMR $1 $2) (fst $ unLoc $3) cs) (unLoc $2)
(WarningTxt $1 NoSourceText $ map stringLiteralToHsDocWst $ snd $ unLoc $3))) }
deprecations :: { OrdList (LWarnDecl GhcPs) }
@@ -4300,6 +4300,10 @@ glN = getLocA
glR :: Located a -> Anchor
glR la = Anchor (realSrcSpan $ getLoc la) UnchangedAnchor
+glMR :: Maybe (Located a) -> Located b -> Anchor
+glMR (Just la) _ = glR la
+glMR _ la = glR la
+
glAA :: Located a -> EpaLocation
glAA = srcSpan2e . getLoc
@@ -4554,5 +4558,4 @@ adaptWhereBinds (Just (L l (b, mc))) = L l (b, maybe emptyComments id mc)
combineHasLocs :: (HasLoc a, HasLoc b) => a -> b -> SrcSpan
combineHasLocs a b = combineSrcSpans (getHasLoc a) (getHasLoc b)
-
}
=====================================
compiler/GHC/Parser/Annotation.hs
=====================================
@@ -1029,6 +1029,10 @@ instance HasLoc (Located a) where
instance HasLoc (GenLocated (SrcSpanAnn' a) e) where
getHasLoc (L (SrcSpanAnn _ l) _) = l
+instance (HasLoc a) => (HasLoc (Maybe a)) where
+ getHasLoc (Just a) = getHasLoc a
+ getHasLoc Nothing = noSrcSpan
+
getHasLocList :: HasLoc a => [a] -> SrcSpan
getHasLocList [] = noSrcSpan
getHasLocList xs = foldl1' combineSrcSpans $ map getHasLoc xs
=====================================
compiler/GHC/Tc/Errors/Hole.hs
=====================================
@@ -48,7 +48,7 @@ import GHC.Core.DataCon
import GHC.Core.Predicate( Pred(..), classifyPredType, eqRelRole )
import GHC.Types.Name
import GHC.Types.Name.Reader
-import GHC.Builtin.Names ( gHC_ERR )
+import GHC.Builtin.Names ( gHC_ERR, uNSAFE_COERCE )
import GHC.Types.Id
import GHC.Types.Var.Set
import GHC.Types.Var.Env
@@ -823,8 +823,8 @@ tcFilterHoleFits limit typed_hole ht@(hole_ty, _) candidates =
_ -> discard_it }
_ -> discard_it }
where
- -- We want to filter out undefined and the likes from GHC.Err
- not_trivial id = nameModule_maybe (idName id) /= Just gHC_ERR
+ -- We want to filter out undefined and the likes from GHC.Err (#17940)
+ not_trivial id = nameModule_maybe (idName id) `notElem` [Just gHC_ERR, Just uNSAFE_COERCE]
lookup :: HoleFitCandidate -> TcM (Maybe (Id, Type))
lookup (IdHFCand id) = return (Just (id, idType id))
=====================================
compiler/GHC/Tc/Solver.hs
=====================================
@@ -3577,6 +3577,48 @@ beta! Concrete example is in indexed_types/should_fail/ExtraTcsUntch.hs:
* Defaulting and disambiguation *
* *
*********************************************************************************
+
+Note [Defaulting plugins]
+~~~~~~~~~~~~~~~~~~~~~~~~~
+Defaulting plugins enable extending or overriding the defaulting
+behaviour. In `applyDefaulting`, before the built-in defaulting
+mechanism runs, the loaded defaulting plugins are passed the
+`WantedConstraints` and get a chance to propose defaulting assignments
+based on them.
+
+Proposals are represented as `[DefaultingProposal]` with each proposal
+consisting of a type variable to fill-in, the list of defaulting types to
+try in order, and a set of constraints to check at each try. This is
+the same representation (albeit in a nicely packaged-up data type) as
+the candidates generated by the built-in defaulting mechanism, so the
+actual trying of proposals is done by the same `disambigGroup` function.
+
+Wrinkle (DP1): The role of `WantedConstraints`
+
+ Plugins are passed `WantedConstraints` that can perhaps be
+ progressed on by defaulting. But a defaulting plugin is not a solver
+ plugin, its job is to provide defaulting proposals, i.e. mappings of
+ type variable to types. How do plugins know which type variables
+ they are supposed to default?
+
+ The `WantedConstraints` passed to the defaulting plugin are zonked
+ beforehand to ensure all remaining metavariables are unfilled. Thus,
+ the `WantedConstraints` serve a dual purpose: they are both the
+ constraints of the given context that can act as hints to the
+ defaulting, as well as the containers of the type variables under
+ consideration for defaulting.
+
+Wrinkle (DP2): Interactions between defaulting mechanisms
+
+ In the general case, we have multiple defaulting plugins loaded and
+ there is also the built-in defaulting mechanism. In this case, we
+ have to be careful to keep the `WantedConstraints` passed to the
+ plugins up-to-date by zonking between successful defaulting
+ rounds. Otherwise, two plugins might come up with a defaulting
+ proposal for the same metavariable; if the first one is accepted by
+ `disambigGroup` (thus the meta gets filled), the second proposal
+ becomes invalid (see #23821 for an example).
+
-}
applyDefaultingRules :: WantedConstraints -> TcS Bool
@@ -3593,20 +3635,16 @@ applyDefaultingRules wanteds
; tcg_env <- TcS.getGblEnv
; let plugins = tcg_defaulting_plugins tcg_env
- ; plugin_defaulted <- if null plugins then return [] else
+ -- Run any defaulting plugins
+ -- See Note [Defaulting plugins] for an overview
+ ; (wanteds, plugin_defaulted) <- if null plugins then return (wanteds, []) else
do {
; traceTcS "defaultingPlugins {" (ppr wanteds)
- ; defaultedGroups <- mapM (run_defaulting_plugin wanteds) plugins
+ ; (wanteds, defaultedGroups) <- mapAccumLM run_defaulting_plugin wanteds plugins
; traceTcS "defaultingPlugins }" (ppr defaultedGroups)
- ; return defaultedGroups
+ ; return (wanteds, defaultedGroups)
}
- -- If a defaulting plugin solves a tyvar, some of the wanteds
- -- will have filled-in metavars by now (see #23281). So we
- -- re-zonk to make sure the built-in defaulting rules don't try
- -- to solve the same metavars.
- ; wanteds <- if or plugin_defaulted then TcS.zonkWC wanteds else pure wanteds
-
; let groups = findDefaultableGroups info wanteds
; traceTcS "applyDefaultingRules {" $
@@ -3629,8 +3667,14 @@ applyDefaultingRules wanteds
groups
; traceTcS "defaultingPlugin " $ ppr defaultedGroups
; case defaultedGroups of
- [] -> return False
- _ -> return True
+ [] -> return (wanteds, False)
+ _ -> do
+ -- If a defaulting plugin solves any tyvars, some of the wanteds
+ -- will have filled-in metavars by now (see wrinkle DP2 of
+ -- Note [Defaulting plugins]). So we re-zonk to make sure later
+ -- defaulting doesn't try to solve the same metavars.
+ wanteds' <- TcS.zonkWC wanteds
+ return (wanteds', True)
}
=====================================
compiler/GHC/Tc/Types.hs
=====================================
@@ -1066,7 +1066,12 @@ instance Outputable DefaultingProposal where
<+> ppr (deProposals p)
<+> ppr (deProposalCts p)
-type FillDefaulting = WantedConstraints -> TcPluginM [DefaultingProposal]
+type FillDefaulting
+ = WantedConstraints
+ -- Zonked constraints containing the unfilled metavariables that
+ -- can be defaulted. See wrinkle (DP1) of Note [Defaulting plugins]
+ -- in GHC.Tc.Solver
+ -> TcPluginM [DefaultingProposal]
-- | A plugin for controlling defaulting.
data DefaultingPlugin = forall s. DefaultingPlugin
=====================================
docs/users_guide/extending_ghc.rst
=====================================
@@ -1378,18 +1378,36 @@ Defaulting plugins have a single access point in the `GHC.Tc.Types` module
-- ^ Clean up after the plugin, when exiting the type-checker.
}
-
-The plugin gets a combination of wanted constraints which can be most easily
-broken down into simple wanted constraints with ``approximateWC``. The result of
-running the plugin should be a ``[DefaultingProposal]``: a list of types that
-should be attempted for the given type variables that are ambiguous in a given
-context. GHC will check if one of the proposals is acceptable in the given
-context and then default to it. The most robust context to return in ``deProposalCts``
-is the list of all wanted constraints that mention the variables you are defaulting.
-If you leave out a constraint, the default will be accepted, and then potentially
-result in a type checker error if it is incompatible with one of the constraints
-you left out. This can be a useful way of forcing a default and reporting errors
-to the user.
+The plugin has type ``WantedConstraints -> [DefaultingProposal]``.
+
+* It is given the currently unsolved constraints.
+* It returns a list of independent "defaulting proposals".
+* Each proposal of type ``DefaultingProposal`` specifies:
+ * ``deProposals``: specifies a list,
+ in priority order, of sets of type variable assignments
+ * ``deProposalCts :: [Ct]`` gives a set of constraints (always a
+ subset of the incoming ``WantedConstraints``) to use as a
+ criterion for acceptance
+
+After calling the plugin, GHC executes each ``DefaultingProposal`` in
+turn. To "execute" a proposal, GHC tries each of the proposed type
+assignments in ``deProposals`` in turn:
+
+* It assigns the proposed types to the type variables, and then tries to
+ solve ``deProposalCts``
+* If those constraints are completely solved by the assignment, GHC
+ accepts the assignment and moves on to the next ``DefaultingProposal``
+* If not, GHC tries the next assignment in ``deProposals``.
+
+The plugin can assume that the incoming constraints are fully
+"zonked" (see :ghc-wiki:`the Wiki page on zonking <zonking>`).
+
+The most robust ``deProposalCts`` to provide is the list of all wanted
+constraints that mention the variable you are defaulting. If you leave
+out a constraint, the default may be accepted, and then potentially
+result in a type checker error if it is incompatible with one of the
+constraints you left out. This can be a useful way of forcing a
+default and reporting errors to the user.
There is an example of defaulting lifted types in the GHC test suite. In the
`testsuite/tests/plugins/` directory see `defaulting-plugin/` for the
=====================================
testsuite/tests/printer/Makefile
=====================================
@@ -796,12 +796,12 @@ Test22771:
$(CHECK_PPR) $(LIBDIR) Test22771.hs
$(CHECK_EXACT) $(LIBDIR) Test22771.hs
-.PHONY: Test23464
+.PHONY: Test23465
Test23465:
- $(CHECK_PPR) $(LIBDIR) Test23464.hs
- $(CHECK_EXACT) $(LIBDIR) Test23464.hs
+ $(CHECK_PPR) $(LIBDIR) Test23465.hs
+ $(CHECK_EXACT) $(LIBDIR) Test23465.hs
.PHONY: Test23887
-Test23465:
+Test23887:
$(CHECK_PPR) $(LIBDIR) Test23887.hs
$(CHECK_EXACT) $(LIBDIR) Test23887.hs
=====================================
testsuite/tests/printer/Test23464.hs deleted
=====================================
@@ -1,4 +0,0 @@
-module T23465 {-# WaRNING in "x-a" "b" #-} where
-
-{-# WARNInG in "x-c" e "d" #-}
-e = e
=====================================
testsuite/tests/printer/Test23465.hs
=====================================
@@ -0,0 +1,14 @@
+module Test23465 {-# WaRNING in "x-a" "b" #-} where
+
+{-# WARNInG in "x-c" e "d" #-}
+e = e
+
+{-# WARNInG
+ in "x-f" f "fw" ;
+ in "x-f" g "gw"
+#-}
+f = f
+g = g
+
+{-# WARNinG h "hw" #-}
+h = h
=====================================
testsuite/tests/printer/all.T
=====================================
@@ -191,5 +191,5 @@ test('T20531_red_ticks', extra_files(['T20531_defs.hs']), ghci_script, ['T20531_
test('HsDocTy', [ignore_stderr, req_ppr_deps], makefile_test, ['HsDocTy'])
test('Test22765', [ignore_stderr, req_ppr_deps], makefile_test, ['Test22765'])
test('Test22771', [ignore_stderr, req_ppr_deps], makefile_test, ['Test22771'])
-test('Test23464', [ignore_stderr, req_ppr_deps], makefile_test, ['Test23464'])
-test('Test23887', [ignore_stderr, req_ppr_deps], makefile_test, ['Test23887'])
+test('Test23465', [ignore_stderr, req_ppr_deps], makefile_test, ['Test23465'])
+test('Test23887', [ignore_stderr, req_ppr_deps], makefile_test, ['Test23887'])
\ No newline at end of file
=====================================
testsuite/tests/typecheck/should_fail/T17940.hs
=====================================
@@ -0,0 +1,7 @@
+{-# LANGUAGE MagicHash #-}
+module T17940 where
+
+import GHC.Exts
+
+index# :: ByteArray# -> Int# -> Word8#
+index# a i = _ (indexWord8Array# a i)
=====================================
testsuite/tests/typecheck/should_fail/T17940.stderr
=====================================
@@ -0,0 +1,17 @@
+
+T17940.hs:7:14: error: [GHC-88464]
+ • Found hole: _ :: Word8# -> Word8#
+ • In the expression: _ (indexWord8Array# a i)
+ In an equation for ‘index#’: index# a i = _ (indexWord8Array# a i)
+ • Relevant bindings include
+ i :: Int# (bound at T17940.hs:7:10)
+ a :: ByteArray# (bound at T17940.hs:7:8)
+ index# :: ByteArray# -> Int# -> Word8# (bound at T17940.hs:7:1)
+ Valid hole fits include
+ notWord8# :: Word8# -> Word8#
+ (imported from ‘GHC.Exts’ at T17940.hs:4:1-15
+ (and originally defined in ‘GHC.Prim’))
+ coerce :: forall a b. Coercible a b => a -> b
+ with coerce @Word8# @Word8#
+ (imported from ‘GHC.Exts’ at T17940.hs:4:1-15
+ (and originally defined in ‘GHC.Prim’))
=====================================
testsuite/tests/typecheck/should_fail/all.T
=====================================
@@ -700,3 +700,4 @@ test('T22684', normal, compile_fail, [''])
test('T23514a', normal, compile_fail, [''])
test('T22478c', normal, compile_fail, [''])
test('T23776', normal, compile, ['']) # to become an error in GHC 9.12
+test('T17940', normal, compile_fail, [''])
=====================================
utils/check-exact/ExactPrint.hs
=====================================
@@ -617,6 +617,15 @@ markEpAnnLMS' (EpAnn anc a cs) l kw (Just str) = do
-- ---------------------------------------------------------------------
+markLToken :: forall m w tok . (Monad m, Monoid w, KnownSymbol tok)
+ => Located (HsToken tok) -> EP w m (Located (HsToken tok))
+markLToken (L (RealSrcSpan aa mb) t) = do
+ epaLoc'<- printStringAtAA (EpaSpan aa mb) (symbolVal (Proxy @tok))
+ case epaLoc' of
+ EpaSpan aa' mb' -> return (L (RealSrcSpan aa' mb') t)
+ _ -> return (L (RealSrcSpan aa mb ) t)
+markLToken (L lt t) = return (L lt t)
+
markToken :: forall m w tok . (Monad m, Monoid w, KnownSymbol tok)
=> LHsToken tok GhcPs -> EP w m (LHsToken tok GhcPs)
markToken (L NoTokenLoc t) = return (L NoTokenLoc t)
@@ -1411,11 +1420,12 @@ instance ExactPrint (LocatedP (WarningTxt GhcPs)) where
exact (L (SrcSpanAnn an l) (WarningTxt mb_cat src ws)) = do
an0 <- markAnnOpenP an src "{-# WARNING"
+ mb_cat' <- markAnnotated mb_cat
an1 <- markEpAnnL an0 lapr_rest AnnOpenS
ws' <- markAnnotated ws
an2 <- markEpAnnL an1 lapr_rest AnnCloseS
an3 <- markAnnCloseP an2
- return (L (SrcSpanAnn an3 l) (WarningTxt mb_cat src ws'))
+ return (L (SrcSpanAnn an3 l) (WarningTxt mb_cat' src ws'))
exact (L (SrcSpanAnn an l) (DeprecatedTxt src ws)) = do
an0 <- markAnnOpenP an src "{-# DEPRECATED"
@@ -1425,6 +1435,25 @@ instance ExactPrint (LocatedP (WarningTxt GhcPs)) where
an3 <- markAnnCloseP an2
return (L (SrcSpanAnn an3 l) (DeprecatedTxt src ws'))
+instance ExactPrint InWarningCategory where
+ getAnnotationEntry _ = NoEntryVal
+ setAnnotationAnchor a _ _ = a
+
+ exact (InWarningCategory tkIn source (L l wc)) = do
+ tkIn' <- markLToken tkIn
+ L _ (_,wc') <- markAnnotated (L l (source, wc))
+ return (InWarningCategory tkIn' source (L l wc'))
+
+instance ExactPrint (SourceText, WarningCategory) where
+ getAnnotationEntry _ = NoEntryVal
+ setAnnotationAnchor a _ _ = a
+
+ exact (st, WarningCategory wc) = do
+ case st of
+ NoSourceText -> printStringAdvance $ "\"" ++ (unpackFS wc) ++ "\""
+ SourceText src -> printStringAdvance $ (unpackFS src)
+ return (st, WarningCategory wc)
+
-- ---------------------------------------------------------------------
instance ExactPrint (ImportDecl GhcPs) where
@@ -1748,19 +1777,20 @@ instance ExactPrint (WarnDecl GhcPs) where
getAnnotationEntry (Warning an _ _) = fromAnn an
setAnnotationAnchor (Warning an a b) anc cs = Warning (setAnchorEpa an anc cs) a b
- exact (Warning an lns txt) = do
+ exact (Warning an lns (WarningTxt mb_cat src ls )) = do
+ mb_cat' <- markAnnotated mb_cat
lns' <- markAnnotated lns
an0 <- markEpAnnL an lidl AnnOpenS -- "["
- txt' <-
- case txt of
- WarningTxt mb_cat src ls -> do
- ls' <- markAnnotated ls
- return (WarningTxt mb_cat src ls')
- DeprecatedTxt src ls -> do
- ls' <- markAnnotated ls
- return (DeprecatedTxt src ls')
+ ls' <- markAnnotated ls
an1 <- markEpAnnL an0 lidl AnnCloseS -- "]"
- return (Warning an1 lns' txt')
+ return (Warning an1 lns' (WarningTxt mb_cat' src ls'))
+
+ exact (Warning an lns (DeprecatedTxt src ls)) = do
+ lns' <- markAnnotated lns
+ an0 <- markEpAnnL an lidl AnnOpenS -- "["
+ ls' <- markAnnotated ls
+ an1 <- markEpAnnL an0 lidl AnnCloseS -- "]"
+ return (Warning an1 lns' (DeprecatedTxt src ls'))
-- ---------------------------------------------------------------------
@@ -1783,7 +1813,6 @@ instance ExactPrint FastString where
-- exact fs = printStringAdvance (show (unpackFS fs))
exact fs = printStringAdvance (unpackFS fs) >> return fs
-
-- ---------------------------------------------------------------------
instance ExactPrint (RuleDecls GhcPs) where
@@ -3122,7 +3151,6 @@ instance (ExactPrint body)
-- ---------------------------------------------------------------------
--- instance ExactPrint (HsRecUpdField GhcPs q) where
instance (ExactPrint (LocatedA body))
=> ExactPrint (HsFieldBind (LocatedAn NoEpAnns (AmbiguousFieldOcc GhcPs)) (LocatedA body)) where
getAnnotationEntry x = fromAnn (hfbAnn x)
=====================================
utils/check-exact/Main.hs
=====================================
@@ -206,7 +206,7 @@ _tt = testOneFile changers "/home/alanz/mysrc/git.haskell.org/worktree/epw/_buil
-- "../../testsuite/tests/printer/HsDocTy.hs" Nothing
-- "../../testsuite/tests/printer/Test22765.hs" Nothing
-- "../../testsuite/tests/printer/Test22771.hs" Nothing
- "../../testsuite/tests/typecheck/should_fail/T22560_fail_c.hs" Nothing
+ "../../testsuite/tests/printer/Test23465.hs" Nothing
-- cloneT does not need a test, function can be retired
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/d414a70508e2a75e3a1630792f49dca8084dc8e6...f579652e518181002ffe9f88e57e67f60c82e2f7
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/d414a70508e2a75e3a1630792f49dca8084dc8e6...f579652e518181002ffe9f88e57e67f60c82e2f7
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20230908/dfc868d1/attachment-0001.html>
More information about the ghc-commits
mailing list