[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 3 commits: If we have multiple defaulting plugins, then we should zonk in between them

Marge Bot (@marge-bot) gitlab at gitlab.haskell.org
Thu Sep 7 21:32:57 UTC 2023



Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC


Commits:
e6091f0d by Gergő Érdi at 2023-09-07T17:32:50-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.

- - - - -
4533caee by Gergő Érdi at 2023-09-07T17:32:50-04:00
Improvements to the documentation of defaulting plugins

Based on @simonpj's draft and comments in !11117

- - - - -
d71c4b2c by Krzysztof Gogolewski at 2023-09-07T17:32:51-04:00
Valid hole fits: don't suggest unsafeCoerce (#17940)

- - - - -


7 changed files:

- compiler/GHC/Tc/Errors/Hole.hs
- compiler/GHC/Tc/Solver.hs
- compiler/GHC/Tc/Types.hs
- docs/users_guide/extending_ghc.rst
- + testsuite/tests/typecheck/should_fail/T17940.hs
- + testsuite/tests/typecheck/should_fail/T17940.stderr
- testsuite/tests/typecheck/should_fail/all.T


Changes:

=====================================
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/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, [''])



View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/2bfb71e56a89be03072cb4b1d0f0958868478bb4...d71c4b2cdaa8e82c8ed2d058ae0dbc4a68edae7f

-- 
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/2bfb71e56a89be03072cb4b1d0f0958868478bb4...d71c4b2cdaa8e82c8ed2d058ae0dbc4a68edae7f
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/20230907/efbfbf09/attachment-0001.html>


More information about the ghc-commits mailing list