
[Git][ghc/ghc][wip/haanss/depdir] Fix test for addDependentDirectory, hopefully.
by Hassan Al-Awwadi (@hassan.awwadi) 07 Jul '25
by Hassan Al-Awwadi (@hassan.awwadi) 07 Jul '25
07 Jul '25
Hassan Al-Awwadi pushed to branch wip/haanss/depdir at Glasgow Haskell Compiler / GHC
Commits:
d4ae1992 by Hassan Al-Awwadi at 2025-07-07T17:52:23+02:00
Fix test for addDependentDirectory, hopefully.
The rest of the changes are just reversions of accidental additions and spelling/grammer changes.
- - - - -
7 changed files:
- compiler/GHC/HsToCore/Usage.hs
- compiler/GHC/Unit/Finder.hs
- compiler/GHC/Utils/Fingerprint.hs
- libraries/base/src/GHC/Fingerprint.hs
- libraries/ghc-internal/src/GHC/Internal/Fingerprint.hs
- libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs
- testsuite/tests/th/Makefile
Changes:
=====================================
compiler/GHC/HsToCore/Usage.hs
=====================================
@@ -2,7 +2,7 @@ module GHC.HsToCore.Usage (
-- * Dependency/fingerprinting code (used by GHC.Iface.Make)
mkUsageInfo, mkUsedNames,
- UsageConfig(..)
+ UsageConfig(..),
) where
import GHC.Prelude
=====================================
compiler/GHC/Unit/Finder.hs
=====================================
@@ -32,7 +32,7 @@ module GHC.Unit.Finder (
findObjectLinkableMaybe,
findObjectLinkable,
- -- important that GHC.HsToCore.Usage uses the same hashing method for usage dirs as is done here.
+ -- important that GHC.HsToCore.Usage uses the same hashing method for usage dirs as is used here.
getDirHash,
) where
=====================================
compiler/GHC/Utils/Fingerprint.hs
=====================================
@@ -20,7 +20,7 @@ module GHC.Utils.Fingerprint (
fingerprintData,
fingerprintString,
fingerprintStrings,
- getFileHash,
+ getFileHash
) where
import GHC.Prelude.Basic
=====================================
libraries/base/src/GHC/Fingerprint.hs
=====================================
@@ -5,7 +5,7 @@ module GHC.Fingerprint (
fingerprintData,
fingerprintString,
fingerprintFingerprints,
- getFileHash,
+ getFileHash
) where
import GHC.Internal.Fingerprint
=====================================
libraries/ghc-internal/src/GHC/Internal/Fingerprint.hs
=====================================
@@ -16,7 +16,7 @@ module GHC.Internal.Fingerprint (
fingerprintData,
fingerprintString,
fingerprintFingerprints,
- getFileHash,
+ getFileHash
) where
import GHC.Internal.IO
=====================================
libraries/ghc-internal/src/GHC/Internal/TH/Syntax.hs
=====================================
@@ -830,7 +830,7 @@ getPackageRoot = Q qGetPackageRoot
-- The compiler can then recognize that it should re-compile the Haskell file
-- when a directory changes.
--
--- Expects an absolute file path.
+-- Expects an absolute directory path.
--
-- Notes:
--
=====================================
testsuite/tests/th/Makefile
=====================================
@@ -45,12 +45,12 @@ TH_Depends:
.PHONY: TH_Depends_Dir
TH_Depends_Dir:
- $(RM) TH_Depends_external/dummy.txt
+ rm -rf TH_Depends_external
$(RM) TH_Depends TH_Depends.exe
$(RM) TH_Depends.o TH_Depends.hi
$(RM) TH_Depends_External.o TH_Depends_External.hi
-
- mk_DIR TH_Depends_external
+
+ mkdir TH_Depends_external
'$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) --make -v0 TH_Depends_Dir
./TH_Depends_Dir
sleep 2
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/d4ae1992198aea378e5c0fefae1b66f…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/d4ae1992198aea378e5c0fefae1b66f…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/T23162-spj] 2 commits: Make FunDeps into a new module
by Simon Peyton Jones (@simonpj) 07 Jul '25
by Simon Peyton Jones (@simonpj) 07 Jul '25
07 Jul '25
Simon Peyton Jones pushed to branch wip/T23162-spj at Glasgow Haskell Compiler / GHC
Commits:
46241879 by Simon Peyton Jones at 2025-07-07T16:05:46+01:00
Make FunDeps into a new module
- - - - -
e970a6b8 by Simon Peyton Jones at 2025-07-07T16:39:04+01:00
Solve new_eqs rather than adding them to WantedConstraints
- - - - -
6 changed files:
- compiler/GHC/Tc/Solver/Dict.hs
- compiler/GHC/Tc/Solver/Equality.hs
- + compiler/GHC/Tc/Solver/FunDeps.hs
- compiler/GHC/Tc/Solver/Monad.hs
- compiler/GHC/Tc/Solver/Solve.hs
- compiler/ghc.cabal.in
Changes:
=====================================
compiler/GHC/Tc/Solver/Dict.hs
=====================================
@@ -8,9 +8,6 @@ module GHC.Tc.Solver.Dict (
matchLocalInst, chooseInstance,
makeSuperClasses, mkStrictSuperClasses,
solveCallStack, -- For GHC.Tc.Solver
-
- -- * Functional dependencies
- doDictFunDepImprovement
) where
import GHC.Prelude
@@ -1379,346 +1376,6 @@ with the least superclass depth (see Note [Replacement vs keeping]),
but that doesn't work for the example from #22216.
-}
-{- *********************************************************************
-* *
-* Functional dependencies, instantiation of equations
-* *
-************************************************************************
-
-When we spot an equality arising from a functional dependency,
-we now use that equality (a "wanted") to rewrite the work-item
-constraint right away. This avoids two dangers
-
- Danger 1: If we send the original constraint on down the pipeline
- it may react with an instance declaration, and in delicate
- situations (when a Given overlaps with an instance) that
- may produce new insoluble goals: see #4952
-
- Danger 2: If we don't rewrite the constraint, it may re-react
- with the same thing later, and produce the same equality
- again --> termination worries.
-
-To achieve this required some refactoring of GHC.Tc.Instance.FunDeps (nicer
-now!).
-
-Note [FunDep and implicit parameter reactions]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Currently, our story of interacting two dictionaries (or a dictionary
-and top-level instances) for functional dependencies (including implicit
-parameters), is that we simply produce new Wanted equalities. So for example
-
- class D a b | a -> b where ...
- Inert:
- [G] d1 : D Int Bool
- WorkItem:
- [W] d2 : D Int alpha
-
- We generate the extra work item
- [W] cv : alpha ~ Bool
- where 'cv' is currently unused. However, this new item can perhaps be
- spontaneously solved to become given and react with d2,
- discharging it in favour of a new constraint d2' thus:
- [W] d2' : D Int Bool
- d2 := d2' |> D Int cv
- Now d2' can be discharged from d1
-
-We could be more aggressive and try to *immediately* solve the dictionary
-using those extra equalities.
-
-If that were the case with the same inert set and work item we might discard
-d2 directly:
-
- [W] cv : alpha ~ Bool
- d2 := d1 |> D Int cv
-
-But in general it's a bit painful to figure out the necessary coercion,
-so we just take the first approach. Here is a better example. Consider:
- class C a b c | a -> b
-And:
- [G] d1 : C T Int Char
- [W] d2 : C T beta Int
-In this case, it's *not even possible* to solve the wanted immediately.
-So we should simply output the functional dependency and add this guy
-[but NOT its superclasses] back in the worklist. Even worse:
- [G] d1 : C T Int beta
- [W] d2: C T beta Int
-Then it is solvable, but its very hard to detect this on the spot.
-
-It's exactly the same with implicit parameters, except that the
-"aggressive" approach would be much easier to implement.
-
-Note [Fundeps with instances, and equality orientation]
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-This Note describes a delicate interaction that constrains the orientation of
-equalities. This one is about fundeps, but the /exact/ same thing arises for
-type-family injectivity constraints: see Note [Improvement orientation].
-
-doTopFunDepImprovement compares the constraint with all the instance
-declarations, to see if we can produce any equalities. E.g
- class C2 a b | a -> b
- instance C Int Bool
-Then the constraint (C Int ty) generates the equality [W] ty ~ Bool.
-
-There is a nasty corner in #19415 which led to the typechecker looping:
- class C s t b | s -> t
- instance ... => C (T kx x) (T ky y) Int
- T :: forall k. k -> Type
-
- work_item: dwrk :: C (T @ka (a::ka)) (T @kb0 (b0::kb0)) Char
- where kb0, b0 are unification vars
-
- ==> {doTopFunDepImprovement: compare work_item with instance,
- generate /fresh/ unification variables kfresh0, yfresh0,
- emit a new Wanted, and add dwrk to inert set}
-
- Suppose we emit this new Wanted from the fundep:
- [W] T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0)
-
- ==> {solve that equality kb0 := kfresh0, b0 := yfresh0}
- Now kick out dwrk, since it mentions kb0
- But now we are back to the start! Loop!
-
-NB1: This example relies on an instance that does not satisfy the
- coverage condition (although it may satisfy the weak coverage
- condition), and hence whose fundeps generate fresh unification
- variables. Not satisfying the coverage condition is known to
- lead to termination trouble, but in this case it's plain silly.
-
-NB2: In this example, the third parameter to C ensures that the
- instance doesn't actually match the Wanted, so we can't use it to
- solve the Wanted
-
-We solve the problem by (#21703):
-
- carefully orienting the new Wanted so that all the
- freshly-generated unification variables are on the LHS.
-
- Thus we call unifyWanteds on
- T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)
- and /NOT/
- T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0)
-
-Now we'll unify kfresh0:=kb0, yfresh0:=b0, and all is well. The general idea
-is that we want to preferentially eliminate those freshly-generated
-unification variables, rather than unifying older variables, which causes
-kick-out etc.
-
-Keeping younger variables on the left also gives very minor improvement in
-the compiler performance by having less kick-outs and allocations (-0.1% on
-average). Indeed Historical Note [Eliminate younger unification variables]
-in GHC.Tc.Utils.Unify describes an earlier attempt to do so systematically,
-apparently now in abeyance.
-
-But this is is a delicate solution. We must take care to /preserve/
-orientation during solving. Wrinkles:
-
-(W1) We start with
- [W] T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)
- Decompose to
- [W] kfresh0 ~ kb0
- [W] (yfresh0::kfresh0) ~ (b0::kb0)
- Preserve orientation when decomposing!!
-
-(W2) Suppose we happen to tackle the second Wanted from (W1)
- first. Then in canEqCanLHSHetero we emit a /kind/ equality, as
- well as a now-homogeneous type equality
- [W] kco : kfresh0 ~ kb0
- [W] (yfresh0::kfresh0) ~ (b0::kb0) |> (sym kco)
- Preserve orientation in canEqCanLHSHetero!! (Failing to
- preserve orientation here was the immediate cause of #21703.)
-
-(W3) There is a potential interaction with the swapping done by
- GHC.Tc.Utils.Unify.swapOverTyVars. We think it's fine, but it's
- a slight worry. See especially Note [TyVar/TyVar orientation] in
- that module.
-
-The trouble is that "preserving orientation" is a rather global invariant,
-and sometimes we definitely do want to swap (e.g. Int ~ alpha), so we don't
-even have a precise statement of what the invariant is. The advantage
-of the preserve-orientation plan is that it is extremely cheap to implement,
-and apparently works beautifully.
-
---- Alternative plan (1) ---
-Rather than have an ill-defined invariant, another possiblity is to
-elminate those fresh unification variables at birth, when generating
-the new fundep-inspired equalities.
-
-The key idea is to call `instFlexiX` in `emitFunDepWanteds` on only those
-type variables that are guaranteed to give us some progress. This means we
-have to locally (without calling emitWanteds) identify the type variables
-that do not give us any progress. In the above example, we _know_ that
-emitting the two wanteds `kco` and `co` is fruitless.
-
- Q: How do we identify such no-ops?
-
- 1. Generate a matching substitution from LHS to RHS
- ɸ = [kb0 :-> k0, b0 :-> y0]
- 2. Call `instFlexiX` on only those type variables that do not appear in the domain of ɸ
- ɸ' = instFlexiX ɸ (tvs - domain ɸ)
- 3. Apply ɸ' on LHS and then call emitWanteds
- unifyWanteds ... (subst ɸ' LHS) RHS
-
-Why will this work? The matching substitution ɸ will be a best effort
-substitution that gives us all the easy solutions. It can be generated with
-modified version of `Core/Unify.unify_tys` where we run it in a matching mode
-and never generate `SurelyApart` and always return a `MaybeApart Subst`
-instead.
-
-The same alternative plan would work for type-family injectivity constraints:
-see Note [Improvement orientation] in GHC.Tc.Solver.Equality.
---- End of Alternative plan (1) ---
-
---- Alternative plan (2) ---
-We could have a new flavour of TcTyVar (like `TauTv`, `TyVarTv` etc; see GHC.Tc.Utils.TcType.MetaInfo)
-for the fresh unification variables introduced by functional dependencies. Say `FunDepTv`. Then in
-GHC.Tc.Utils.Unify.swapOverTyVars we could arrange to keep a `FunDepTv` on the left if possible.
-Looks possible, but it's one more complication.
---- End of Alternative plan (2) ---
-
-
---- Historical note: Failed Alternative Plan (3) ---
-Previously we used a flag `cc_fundeps` in `CDictCan`. It would flip to False
-once we used a fun dep to hint the solver to break and to stop emitting more
-wanteds. This solution was not complete, and caused a failures while trying
-to solve for transitive functional dependencies (test case: T21703)
--- End of Historical note: Failed Alternative Plan (3) --
-
-Note [Do fundeps last]
-~~~~~~~~~~~~~~~~~~~~~~
-Consider T4254b:
- class FD a b | a -> b where { op :: a -> b }
-
- instance FD Int Bool
-
- foo :: forall a b. (a~Int,FD a b) => a -> Bool
- foo = op
-
-(DFL1) Try local fundeps first.
- From the ambiguity check on the type signature we get
- [G] FD Int b
- [W] FD Int beta
- Interacting these gives beta:=b; then we start again and solve without
- trying fundeps between the new [W] FD Int b and the top-level instance.
- If we did, we'd generate [W] b ~ Bool, which fails.
-
-(DFL2) Try solving from top-level instances before fundeps
- From the definition `foo = op` we get
- [G] FD Int b
- [W] FD Int Bool
- We solve this from the top level instance before even trying fundeps.
- If we did try fundeps, we'd generate [W] b ~ Bool, which fails.
-
-
-Note [Weird fundeps]
-~~~~~~~~~~~~~~~~~~~~
-Consider class Het a b | a -> b where
- het :: m (f c) -> a -> m b
-
- class GHet (a :: * -> *) (b :: * -> *) | a -> b
- instance GHet (K a) (K [a])
- instance Het a b => GHet (K a) (K b)
-
-The two instances don't actually conflict on their fundeps,
-although it's pretty strange. So they are both accepted. Now
-try [W] GHet (K Int) (K Bool)
-This triggers fundeps from both instance decls;
- [W] K Bool ~ K [a]
- [W] K Bool ~ K beta
-And there's a risk of complaining about Bool ~ [a]. But in fact
-the Wanted matches the second instance, so we never get as far
-as the fundeps.
-
-#7875 is a case in point.
--}
-
-doDictFunDepImprovement :: Cts -> TcS (Cts, Bool)
--- (doDictFunDepImprovement inst_envs cts)
--- * Generate the fundeps from interacting the
--- top-level `inst_envs` with the constraints `cts`
--- * Do the unifications and return any unsolved constraints
--- See Note [Fundeps with instances, and equality orientation]
-doDictFunDepImprovement unsolved_wanteds
- = do { inerts <- getInertCans -- The inert_dicts are all Givens
- ; inst_envs <- getInstEnvs
- ; (_, new_eqs, unifs) <- foldrM (do_one_dict inst_envs)
- (inert_dicts inerts, emptyBag, False)
- unsolved_wanteds
- ; return (new_eqs, unifs) }
-
-do_one_dict :: InstEnvs -> Ct
- -> (DictMap DictCt, Cts, Bool)
- -> TcS (DictMap DictCt, Cts, Bool)
-do_one_dict inst_envs (CDictCan dict_ct) (local_dicts, new_eqs, unifs)
- = do { (new_eqs1, unifs1) <- do_one_top inst_envs dict_ct
- ; (local_dicts2, new_eqs2, unifs2) <- do_one_local local_dicts dict_ct
- ; return ( local_dicts2
- , new_eqs1 `unionBags` new_eqs2 `unionBags` new_eqs
- , unifs1 || unifs2 || unifs ) }
-
-do_one_dict _ _ acc -- Non-DictCt constraints
- = return acc
-
-do_one_top :: InstEnvs -> DictCt -> TcS (Cts, Bool)
-do_one_top inst_envs (DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
- = unifyFunDepWanteds ev eqns
- where
- eqns :: [FunDepEqn (CtLoc, RewriterSet)]
- eqns = improveFromInstEnv inst_envs mk_ct_loc cls xis
-
- dict_pred = mkClassPred cls xis
- dict_loc = ctEvLoc ev
- dict_origin = ctLocOrigin dict_loc
- dict_rewriters = ctEvRewriters ev
-
- mk_ct_loc :: ClsInst -- The instance decl
- -> (CtLoc, RewriterSet)
- mk_ct_loc ispec
- = (dict_loc { ctl_origin = new_orig }, dict_rewriters)
- where
- inst_pred = mkClassPred cls (is_tys ispec)
- inst_loc = getSrcSpan (is_dfun ispec)
- new_orig = FunDepOrigin2 dict_pred dict_origin
- inst_pred inst_loc
-
-do_one_local :: DictMap DictCt -> DictCt -> TcS (DictMap DictCt, Cts, Bool)
--- Using functional dependencies, interact the unsolved Wanteds
--- against each other and the inert Givens, to produce new equalities
-do_one_local locals dict_ct@(DictCt { di_cls = cls, di_ev = wanted_ev })
- -- locals contains all the Givens and earlier Wanteds
- = do { (new_eqs, unifs) <- foldrM do_interaction (emptyBag, False) $
- findDictsByClass locals cls
- ; return (addDict dict_ct locals, new_eqs, unifs) }
- where
- wanted_pred = ctEvPred wanted_ev
- wanted_loc = ctEvLoc wanted_ev
-
- do_interaction :: DictCt -> (Cts,Bool) -> TcS (Cts,Bool)
- do_interaction (DictCt { di_ev = all_ev }) (new_eqs, unifs) -- This can be Given or Wanted
- = do { traceTcS "doLocalFunDepImprovement" $
- vcat [ ppr wanted_ev
- , pprCtLoc wanted_loc, ppr (isGivenLoc wanted_loc)
- , pprCtLoc all_loc, ppr (isGivenLoc all_loc)
- , pprCtLoc deriv_loc, ppr (isGivenLoc deriv_loc) ]
-
- ; (new_eqs1, unifs1) <- unifyFunDepWanteds wanted_ev $
- improveFromAnother (deriv_loc, all_rewriters)
- all_pred wanted_pred
- ; return (new_eqs1 `unionBags` new_eqs, unifs1 || unifs) }
- where
- all_pred = ctEvPred all_ev
- all_loc = ctEvLoc all_ev
- all_rewriters = ctEvRewriters all_ev
- deriv_loc = wanted_loc { ctl_depth = deriv_depth
- , ctl_origin = deriv_origin }
- deriv_depth = ctl_depth wanted_loc `maxSubGoalDepth`
- ctl_depth all_loc
- deriv_origin = FunDepOrigin1 wanted_pred
- (ctLocOrigin wanted_loc)
- (ctLocSpan wanted_loc)
- all_pred
- (ctLocOrigin all_loc)
- (ctLocSpan all_loc)
-
{- *********************************************************************
* *
=====================================
compiler/GHC/Tc/Solver/Equality.hs
=====================================
@@ -14,6 +14,7 @@ import GHC.Tc.Solver.Irred( solveIrred )
import GHC.Tc.Solver.Dict( matchLocalInst, chooseInstance )
import GHC.Tc.Solver.Rewrite
import GHC.Tc.Solver.Monad
+import GHC.Tc.Solver.FunDeps( unifyAndEmitFunDepWanteds )
import GHC.Tc.Solver.InertSet
import GHC.Tc.Solver.Types( findFunEqsByTyCon )
import GHC.Tc.Types.Evidence
@@ -3108,13 +3109,17 @@ improve_wanted_top_fun_eqs fam_tc lhs_tys rhs_ty
| Just ops <- isBuiltInSynFamTyCon_maybe fam_tc
= return (map snd $ tryInteractTopFam ops fam_tc lhs_tys rhs_ty)
+ -- ToDo: use ideas in #23162 for closed type families; injectivity only for open
+
-- See Note [Type inference for type families with injectivity]
+ -- Open, so look for inj
| Injective inj_args <- tyConInjectivityInfo fam_tc
= do { fam_envs <- getFamInstEnvs
; top_eqns <- improve_injective_wanted_top fam_envs inj_args fam_tc lhs_tys rhs_ty
; let local_eqns = improve_injective_wanted_famfam inj_args fam_tc lhs_tys rhs_ty
; traceTcS "improve_wanted_top_fun_eqs" $
vcat [ ppr fam_tc, text "local_eqns" <+> ppr local_eqns, text "top_eqns" <+> ppr top_eqns ]
+ -- xxx ToDo: this does both local and top => bug?
; return (local_eqns ++ top_eqns) }
| otherwise -- No injectivity
=====================================
compiler/GHC/Tc/Solver/FunDeps.hs
=====================================
@@ -0,0 +1,486 @@
+{-# LANGUAGE DuplicateRecordFields #-}
+{-# LANGUAGE MultiWayIf #-}
+
+-- | Solving Class constraints CDictCan
+module GHC.Tc.Solver.FunDeps (
+ unifyAndEmitFunDepWanteds,
+ doDictFunDepImprovement,
+ ImprovementResult, noImprovement
+ ) where
+
+import GHC.Prelude
+
+import GHC.Tc.Instance.FunDeps
+import GHC.Tc.Types.Evidence
+import GHC.Tc.Types.Constraint
+import GHC.Tc.Types.CtLoc
+import GHC.Tc.Types.Origin
+import GHC.Tc.Solver.InertSet
+import GHC.Tc.Solver.Monad
+import GHC.Tc.Solver.Types
+import GHC.Tc.Utils.TcType
+import GHC.Tc.Utils.Unify( UnifyEnv(..) )
+import GHC.Tc.Utils.Monad as TcM
+
+import GHC.Core.Type
+import GHC.Core.InstEnv ( InstEnvs, ClsInst(..) )
+import GHC.Core.Coercion.Axiom( TypeEqn )
+
+import GHC.Types.Name
+import GHC.Types.Var.Set
+
+import GHC.Utils.Outputable
+
+import GHC.Data.Bag
+import GHC.Data.Pair
+
+import qualified Data.Semigroup as S
+
+import Control.Monad
+
+{- *********************************************************************
+* *
+* Functional dependencies, instantiation of equations
+* *
+************************************************************************
+
+When we spot an equality arising from a functional dependency,
+we now use that equality (a "wanted") to rewrite the work-item
+constraint right away. This avoids two dangers
+
+ Danger 1: If we send the original constraint on down the pipeline
+ it may react with an instance declaration, and in delicate
+ situations (when a Given overlaps with an instance) that
+ may produce new insoluble goals: see #4952
+
+ Danger 2: If we don't rewrite the constraint, it may re-react
+ with the same thing later, and produce the same equality
+ again --> termination worries.
+
+To achieve this required some refactoring of GHC.Tc.Instance.FunDeps (nicer
+now!).
+
+Note [FunDep and implicit parameter reactions]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Currently, our story of interacting two dictionaries (or a dictionary
+and top-level instances) for functional dependencies (including implicit
+parameters), is that we simply produce new Wanted equalities. So for example
+
+ class D a b | a -> b where ...
+ Inert:
+ [G] d1 : D Int Bool
+ WorkItem:
+ [W] d2 : D Int alpha
+
+ We generate the extra work item
+ [W] cv : alpha ~ Bool
+ where 'cv' is currently unused. However, this new item can perhaps be
+ spontaneously solved to become given and react with d2,
+ discharging it in favour of a new constraint d2' thus:
+ [W] d2' : D Int Bool
+ d2 := d2' |> D Int cv
+ Now d2' can be discharged from d1
+
+We could be more aggressive and try to *immediately* solve the dictionary
+using those extra equalities.
+
+If that were the case with the same inert set and work item we might discard
+d2 directly:
+
+ [W] cv : alpha ~ Bool
+ d2 := d1 |> D Int cv
+
+But in general it's a bit painful to figure out the necessary coercion,
+so we just take the first approach. Here is a better example. Consider:
+ class C a b c | a -> b
+And:
+ [G] d1 : C T Int Char
+ [W] d2 : C T beta Int
+In this case, it's *not even possible* to solve the wanted immediately.
+So we should simply output the functional dependency and add this guy
+[but NOT its superclasses] back in the worklist. Even worse:
+ [G] d1 : C T Int beta
+ [W] d2: C T beta Int
+Then it is solvable, but its very hard to detect this on the spot.
+
+It's exactly the same with implicit parameters, except that the
+"aggressive" approach would be much easier to implement.
+
+Note [Fundeps with instances, and equality orientation]
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+This Note describes a delicate interaction that constrains the orientation of
+equalities. This one is about fundeps, but the /exact/ same thing arises for
+type-family injectivity constraints: see Note [Improvement orientation].
+
+doTopFunDepImprovement compares the constraint with all the instance
+declarations, to see if we can produce any equalities. E.g
+ class C2 a b | a -> b
+ instance C Int Bool
+Then the constraint (C Int ty) generates the equality [W] ty ~ Bool.
+
+There is a nasty corner in #19415 which led to the typechecker looping:
+ class C s t b | s -> t
+ instance ... => C (T kx x) (T ky y) Int
+ T :: forall k. k -> Type
+
+ work_item: dwrk :: C (T @ka (a::ka)) (T @kb0 (b0::kb0)) Char
+ where kb0, b0 are unification vars
+
+ ==> {doTopFunDepImprovement: compare work_item with instance,
+ generate /fresh/ unification variables kfresh0, yfresh0,
+ emit a new Wanted, and add dwrk to inert set}
+
+ Suppose we emit this new Wanted from the fundep:
+ [W] T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0)
+
+ ==> {solve that equality kb0 := kfresh0, b0 := yfresh0}
+ Now kick out dwrk, since it mentions kb0
+ But now we are back to the start! Loop!
+
+NB1: This example relies on an instance that does not satisfy the
+ coverage condition (although it may satisfy the weak coverage
+ condition), and hence whose fundeps generate fresh unification
+ variables. Not satisfying the coverage condition is known to
+ lead to termination trouble, but in this case it's plain silly.
+
+NB2: In this example, the third parameter to C ensures that the
+ instance doesn't actually match the Wanted, so we can't use it to
+ solve the Wanted
+
+We solve the problem by (#21703):
+
+ carefully orienting the new Wanted so that all the
+ freshly-generated unification variables are on the LHS.
+
+ Thus we call unifyWanteds on
+ T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)
+ and /NOT/
+ T kb0 (b0::kb0) ~ T kfresh0 (yfresh0::kfresh0)
+
+Now we'll unify kfresh0:=kb0, yfresh0:=b0, and all is well. The general idea
+is that we want to preferentially eliminate those freshly-generated
+unification variables, rather than unifying older variables, which causes
+kick-out etc.
+
+Keeping younger variables on the left also gives very minor improvement in
+the compiler performance by having less kick-outs and allocations (-0.1% on
+average). Indeed Historical Note [Eliminate younger unification variables]
+in GHC.Tc.Utils.Unify describes an earlier attempt to do so systematically,
+apparently now in abeyance.
+
+But this is is a delicate solution. We must take care to /preserve/
+orientation during solving. Wrinkles:
+
+(W1) We start with
+ [W] T kfresh0 (yfresh0::kfresh0) ~ T kb0 (b0::kb0)
+ Decompose to
+ [W] kfresh0 ~ kb0
+ [W] (yfresh0::kfresh0) ~ (b0::kb0)
+ Preserve orientation when decomposing!!
+
+(W2) Suppose we happen to tackle the second Wanted from (W1)
+ first. Then in canEqCanLHSHetero we emit a /kind/ equality, as
+ well as a now-homogeneous type equality
+ [W] kco : kfresh0 ~ kb0
+ [W] (yfresh0::kfresh0) ~ (b0::kb0) |> (sym kco)
+ Preserve orientation in canEqCanLHSHetero!! (Failing to
+ preserve orientation here was the immediate cause of #21703.)
+
+(W3) There is a potential interaction with the swapping done by
+ GHC.Tc.Utils.Unify.swapOverTyVars. We think it's fine, but it's
+ a slight worry. See especially Note [TyVar/TyVar orientation] in
+ that module.
+
+The trouble is that "preserving orientation" is a rather global invariant,
+and sometimes we definitely do want to swap (e.g. Int ~ alpha), so we don't
+even have a precise statement of what the invariant is. The advantage
+of the preserve-orientation plan is that it is extremely cheap to implement,
+and apparently works beautifully.
+
+--- Alternative plan (1) ---
+Rather than have an ill-defined invariant, another possiblity is to
+elminate those fresh unification variables at birth, when generating
+the new fundep-inspired equalities.
+
+The key idea is to call `instFlexiX` in `emitFunDepWanteds` on only those
+type variables that are guaranteed to give us some progress. This means we
+have to locally (without calling emitWanteds) identify the type variables
+that do not give us any progress. In the above example, we _know_ that
+emitting the two wanteds `kco` and `co` is fruitless.
+
+ Q: How do we identify such no-ops?
+
+ 1. Generate a matching substitution from LHS to RHS
+ ɸ = [kb0 :-> k0, b0 :-> y0]
+ 2. Call `instFlexiX` on only those type variables that do not appear in the domain of ɸ
+ ɸ' = instFlexiX ɸ (tvs - domain ɸ)
+ 3. Apply ɸ' on LHS and then call emitWanteds
+ unifyWanteds ... (subst ɸ' LHS) RHS
+
+Why will this work? The matching substitution ɸ will be a best effort
+substitution that gives us all the easy solutions. It can be generated with
+modified version of `Core/Unify.unify_tys` where we run it in a matching mode
+and never generate `SurelyApart` and always return a `MaybeApart Subst`
+instead.
+
+The same alternative plan would work for type-family injectivity constraints:
+see Note [Improvement orientation] in GHC.Tc.Solver.Equality.
+--- End of Alternative plan (1) ---
+
+--- Alternative plan (2) ---
+We could have a new flavour of TcTyVar (like `TauTv`, `TyVarTv` etc; see GHC.Tc.Utils.TcType.MetaInfo)
+for the fresh unification variables introduced by functional dependencies. Say `FunDepTv`. Then in
+GHC.Tc.Utils.Unify.swapOverTyVars we could arrange to keep a `FunDepTv` on the left if possible.
+Looks possible, but it's one more complication.
+--- End of Alternative plan (2) ---
+
+
+--- Historical note: Failed Alternative Plan (3) ---
+Previously we used a flag `cc_fundeps` in `CDictCan`. It would flip to False
+once we used a fun dep to hint the solver to break and to stop emitting more
+wanteds. This solution was not complete, and caused a failures while trying
+to solve for transitive functional dependencies (test case: T21703)
+-- End of Historical note: Failed Alternative Plan (3) --
+
+Note [Do fundeps last]
+~~~~~~~~~~~~~~~~~~~~~~
+Consider T4254b:
+ class FD a b | a -> b where { op :: a -> b }
+
+ instance FD Int Bool
+
+ foo :: forall a b. (a~Int,FD a b) => a -> Bool
+ foo = op
+
+(DFL1) Try local fundeps first.
+ From the ambiguity check on the type signature we get
+ [G] FD Int b
+ [W] FD Int beta
+ If we ineract that Wanted with /both/ the t0p-level instance, /and/ the
+ local Given, we'll get
+ beta ~ Int and beta ~ b
+ respectively. That would generate (b~Bool), which would fai. I think
+ it doesn't matter which of the two we pick, but historically we have
+ picked teh local-fundeps firs.
+
+(DFL2) Try solving from top-level instances before fundeps.
+ From the definition `foo = op` we get
+ [G] FD Int b
+ [W] FD Int Bool
+ We solve this from the top level instance before even trying fundeps.
+ If we did try fundeps, we'd generate [W] b ~ Bool, which fails.
+
+ (DFL2) is achieved by trying fundeps only on /unsolved/ Wanteds.
+
+
+Note [Weird fundeps]
+~~~~~~~~~~~~~~~~~~~~
+Consider class Het a b | a -> b where
+ het :: m (f c) -> a -> m b
+
+ class GHet (a :: * -> *) (b :: * -> *) | a -> b
+ instance GHet (K a) (K [a])
+ instance Het a b => GHet (K a) (K b)
+
+The two instances don't actually conflict on their fundeps,
+although it's pretty strange. So they are both accepted. Now
+try [W] GHet (K Int) (K Bool)
+This triggers fundeps from both instance decls;
+ [W] K Bool ~ K [a]
+ [W] K Bool ~ K beta
+And there's a risk of complaining about Bool ~ [a]. But in fact
+the Wanted matches the second instance, so we never get as far
+as the fundeps.
+
+#7875 is a case in point.
+-}
+
+doDictFunDepImprovement :: Cts -> TcS ImprovementResult
+-- (doDictFunDepImprovement inst_envs cts)
+-- * Generate the fundeps from interacting the
+-- top-level `inst_envs` with the constraints `cts`
+-- * Do the unifications and return any unsolved constraints
+-- See Note [Fundeps with instances, and equality orientation]
+-- foldrM :: (Foldable t, Monad m) => (a -> b -> m b) -> b -> t a -> m b
+doDictFunDepImprovement unsolved_wanteds
+ = do { inerts <- getInertCans -- The inert_dicts are all Givens
+ ; inst_envs <- getInstEnvs
+ ; (_, imp_res) <- foldM (do_one_dict inst_envs)
+ (inert_dicts inerts, noopImprovement)
+ unsolved_wanteds
+ ; return imp_res }
+
+do_one_dict :: InstEnvs
+ -> (DictMap DictCt, ImprovementResult)
+ -> Ct
+ -> TcS (DictMap DictCt, ImprovementResult)
+-- The `local_dicts` accumulator starts life as just the Givens, but
+-- as we encounter each Wanted we augment it. Result: each Wanted
+-- is interacted with all the Givens, and all prededing Wanteds.
+-- This is worst-case quadratic because we have to compare each
+-- constraint with all the others, to find all the pairwise interactions
+do_one_dict inst_envs (local_dicts, imp_res) (CDictCan dict_ct)
+ = do { (local_dicts1, imp_res1) <- do_one_local local_dicts dict_ct
+ ; if noImprovement imp_res1
+ then do { imp_res2 <- do_one_top inst_envs dict_ct
+ ; return (local_dicts1, imp_res `plusImprovements` imp_res2) }
+ else return (local_dicts1, imp_res `plusImprovements` imp_res1) }
+
+do_one_dict _ acc _ -- Non-DictCt constraints
+ = return acc
+
+do_one_top :: InstEnvs -> DictCt -> TcS ImprovementResult
+do_one_top inst_envs (DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
+ = unifyFunDepWanteds ev eqns
+ where
+ eqns :: [FunDepEqn (CtLoc, RewriterSet)]
+ eqns = improveFromInstEnv inst_envs mk_ct_loc cls xis
+
+ dict_pred = mkClassPred cls xis
+ dict_loc = ctEvLoc ev
+ dict_origin = ctLocOrigin dict_loc
+ dict_rewriters = ctEvRewriters ev
+
+ mk_ct_loc :: ClsInst -- The instance decl
+ -> (CtLoc, RewriterSet)
+ mk_ct_loc ispec
+ = (dict_loc { ctl_origin = new_orig }, dict_rewriters)
+ where
+ inst_pred = mkClassPred cls (is_tys ispec)
+ inst_loc = getSrcSpan (is_dfun ispec)
+ new_orig = FunDepOrigin2 dict_pred dict_origin
+ inst_pred inst_loc
+
+do_one_local :: DictMap DictCt -> DictCt -> TcS (DictMap DictCt, ImprovementResult)
+-- Using functional dependencies, interact the unsolved Wanteds
+-- against each other and the inert Givens, to produce new equalities
+do_one_local locals dict_ct@(DictCt { di_cls = cls, di_ev = wanted_ev })
+ -- locals contains all the Givens and earlier Wanteds
+ = do { imp_res <- foldM do_interaction noopImprovement $
+ findDictsByClass locals cls
+ ; return (addDict dict_ct locals, imp_res) }
+ where
+ wanted_pred = ctEvPred wanted_ev
+ wanted_loc = ctEvLoc wanted_ev
+
+ do_interaction :: (Cts,Bool) -> DictCt -> TcS (Cts,Bool)
+ do_interaction (new_eqs, unifs) (DictCt { di_ev = all_ev }) -- This can be Given or Wanted
+ = do { traceTcS "doLocalFunDepImprovement" $
+ vcat [ ppr wanted_ev
+ , pprCtLoc wanted_loc, ppr (isGivenLoc wanted_loc)
+ , pprCtLoc all_loc, ppr (isGivenLoc all_loc)
+ , pprCtLoc deriv_loc, ppr (isGivenLoc deriv_loc) ]
+
+ ; (new_eqs1, unifs1) <- unifyFunDepWanteds wanted_ev $
+ improveFromAnother (deriv_loc, all_rewriters)
+ all_pred wanted_pred
+ ; return (new_eqs1 `unionBags` new_eqs, unifs1 || unifs) }
+ where
+ all_pred = ctEvPred all_ev
+ all_loc = ctEvLoc all_ev
+ all_rewriters = ctEvRewriters all_ev
+ deriv_loc = wanted_loc { ctl_depth = deriv_depth
+ , ctl_origin = deriv_origin }
+ deriv_depth = ctl_depth wanted_loc `maxSubGoalDepth`
+ ctl_depth all_loc
+ deriv_origin = FunDepOrigin1 wanted_pred
+ (ctLocOrigin wanted_loc)
+ (ctLocSpan wanted_loc)
+ all_pred
+ (ctLocOrigin all_loc)
+ (ctLocSpan all_loc)
+
+
+{-
+************************************************************************
+* *
+ Emitting equalities arising from fundeps
+* *
+************************************************************************
+-}
+
+type ImprovementResult = (Cts, Bool)
+ -- The Cts are the new equality constraints
+ -- The Bool is True if we unified any meta-ty-vars on when
+ -- generating those new equality constraints
+
+noopImprovement :: ImprovementResult
+noopImprovement = (emptyBag, False)
+
+noImprovement :: ImprovementResult -> Bool
+noImprovement (cts,unifs) = not unifs && isEmptyBag cts
+
+plusImprovements :: ImprovementResult -> ImprovementResult -> ImprovementResult
+plusImprovements (cts1,unif1) (cts2,unif2)
+ = (cts1 `unionBags` cts2, unif1 || unif2)
+
+
+unifyAndEmitFunDepWanteds :: CtEvidence -- The work item
+ -> [FunDepEqn (CtLoc, RewriterSet)]
+ -> TcS Bool -- True <=> some unification happened
+unifyAndEmitFunDepWanteds ev fd_eqns
+ = do { (new_eqs, unifs) <- unifyFunDepWanteds ev fd_eqns
+
+ ; -- Emit the deferred constraints
+ -- See Note [Work-list ordering] in GHC.Tc.Solved.Equality
+ --
+ -- All the constraints in `cts` share the same rewriter set so,
+ -- rather than looking at it one by one, we pass it to
+ -- extendWorkListChildEqs; just a small optimisation.
+ ; unless (isEmptyBag new_eqs) $
+ updWorkListTcS (extendWorkListChildEqs ev new_eqs)
+
+ ; return unifs }
+
+unifyFunDepWanteds :: CtEvidence -- The work item
+ -> [FunDepEqn (CtLoc, RewriterSet)]
+ -> TcS ImprovementResult
+
+unifyFunDepWanteds _ [] = return noopImprovement -- common case noop
+-- See Note [FunDep and implicit parameter reactions]
+
+unifyFunDepWanteds ev fd_eqns
+ = do { (fresh_tvs_s, cts, unified_tvs) <- wrapUnifierX ev Nominal do_fundeps
+
+ -- Figure out if a "real" unification happened: See Note [unifyFunDeps]
+ ; let unif_happened = any is_old_tv unified_tvs
+ fresh_tvs = mkVarSet (concat fresh_tvs_s)
+ is_old_tv tv = not (tv `elemVarSet` fresh_tvs)
+
+ ; return (cts, unif_happened) }
+ where
+ do_fundeps :: UnifyEnv -> TcM [[TcTyVar]]
+ do_fundeps env = mapM (do_one env) fd_eqns
+
+ do_one :: UnifyEnv -> FunDepEqn (CtLoc, RewriterSet) -> TcM [TcTyVar]
+ do_one uenv (FDEqn { fd_qtvs = tvs, fd_eqs = eqs, fd_loc = (loc, rewriters) })
+ = do { (fresh_tvs, eqs') <- instantiateFunDepEqn tvs (reverse eqs)
+ -- (reverse eqs): See Note [Reverse order of fundep equations]
+ ; uPairsTcM env_one eqs'
+ ; return fresh_tvs }
+ where
+ env_one = uenv { u_rewriters = u_rewriters uenv S.<> rewriters
+ , u_loc = loc }
+
+instantiateFunDepEqn :: [TyVar] -> [TypeEqn] -> TcM ([TcTyVar], [TypeEqn])
+instantiateFunDepEqn tvs eqs
+ | null tvs
+ = return ([], eqs)
+ | otherwise
+ = do { TcM.traceTc "emitFunDepWanteds 2" (ppr tvs $$ ppr eqs)
+ ; (tvs', subst) <- instFlexiXTcM emptySubst tvs -- Takes account of kind substitution
+ ; return (tvs', map (subst_pair subst) eqs) }
+ where
+ subst_pair subst (Pair ty1 ty2)
+ = Pair (substTyUnchecked subst' ty1) ty2
+ -- ty2 does not mention fd_qtvs, so no need to subst it.
+ -- See GHC.Tc.Instance.Fundeps Note [Improving against instances]
+ -- Wrinkle (1)
+ where
+ subst' = extendSubstInScopeSet subst (tyCoVarsOfType ty1)
+ -- The free vars of ty1 aren't just fd_qtvs: ty1 is the result
+ -- of matching with the [W] constraint. So we add its free
+ -- vars to InScopeSet, to satisfy substTy's invariants, even
+ -- though ty1 will never (currently) be a poytype, so this
+ -- InScopeSet will never be looked at.
+
=====================================
compiler/GHC/Tc/Solver/Monad.hs
=====================================
@@ -105,10 +105,9 @@ module GHC.Tc.Solver.Monad (
-- Unification
wrapUnifierX, wrapUnifierTcS, unifyFunDeps, uPairsTcM, unifyForAllBody,
- unifyFunDepWanteds, unifyAndEmitFunDepWanteds,
-- MetaTyVars
- newFlexiTcSTy, instFlexiX,
+ newFlexiTcSTy, instFlexiX, instFlexiXTcM,
cloneMetaTyVar,
tcInstSkolTyVarsX,
@@ -129,8 +128,7 @@ module GHC.Tc.Solver.Monad (
pprEq,
-- Enforcing invariants for type equalities
- checkTypeEq,
- instantiateFunDepEqn
+ checkTypeEq
) where
import GHC.Prelude
@@ -2235,83 +2233,6 @@ solverDepthError loc ty
where
depth = ctLocDepth loc
-{-
-************************************************************************
-* *
- Emitting equalities arising from fundeps
-* *
-************************************************************************
--}
-
-unifyAndEmitFunDepWanteds :: CtEvidence -- The work item
- -> [FunDepEqn (CtLoc, RewriterSet)]
- -> TcS Bool -- True <=> some unification happened
-unifyAndEmitFunDepWanteds ev fd_eqns
- = do { (new_eqs, unifs) <- unifyFunDepWanteds ev fd_eqns
-
- ; -- Emit the deferred constraints
- -- See Note [Work-list ordering] in GHC.Tc.Solved.Equality
- --
- -- All the constraints in `cts` share the same rewriter set so,
- -- rather than looking at it one by one, we pass it to
- -- extendWorkListChildEqs; just a small optimisation.
- ; unless (isEmptyBag new_eqs) $
- updWorkListTcS (extendWorkListChildEqs ev new_eqs)
-
- ; return unifs }
-
-unifyFunDepWanteds :: CtEvidence -- The work item
- -> [FunDepEqn (CtLoc, RewriterSet)]
- -> TcS (Cts, Bool) -- True <=> some unification happened
-
-unifyFunDepWanteds _ [] = return (emptyBag, False) -- common case noop
--- See Note [FunDep and implicit parameter reactions]
-
-unifyFunDepWanteds ev fd_eqns
- = do { (fresh_tvs_s, cts, unified_tvs) <- wrapUnifierX ev Nominal do_fundeps
-
- -- Figure out if a "real" unification happened: See Note [unifyFunDeps]
- ; let unif_happened = any is_old_tv unified_tvs
- fresh_tvs = mkVarSet (concat fresh_tvs_s)
- is_old_tv tv = not (tv `elemVarSet` fresh_tvs)
-
- ; return (cts, unif_happened) }
- where
- do_fundeps :: UnifyEnv -> TcM [[TcTyVar]]
- do_fundeps env = mapM (do_one env) fd_eqns
-
- do_one :: UnifyEnv -> FunDepEqn (CtLoc, RewriterSet) -> TcM [TcTyVar]
- do_one uenv (FDEqn { fd_qtvs = tvs, fd_eqs = eqs, fd_loc = (loc, rewriters) })
- = do { (fresh_tvs, eqs') <- instantiateFunDepEqn tvs (reverse eqs)
- -- (reverse eqs): See Note [Reverse order of fundep equations]
- ; uPairsTcM env_one eqs'
- ; return fresh_tvs }
- where
- env_one = uenv { u_rewriters = u_rewriters uenv S.<> rewriters
- , u_loc = loc }
-
-instantiateFunDepEqn :: [TyVar] -> [TypeEqn] -> TcM ([TcTyVar], [TypeEqn])
-instantiateFunDepEqn tvs eqs
- | null tvs
- = return ([], eqs)
- | otherwise
- = do { TcM.traceTc "emitFunDepWanteds 2" (ppr tvs $$ ppr eqs)
- ; (tvs', subst) <- instFlexiXTcM emptySubst tvs -- Takes account of kind substitution
- ; return (tvs', map (subst_pair subst) eqs) }
- where
- subst_pair subst (Pair ty1 ty2)
- = Pair (substTyUnchecked subst' ty1) ty2
- -- ty2 does not mention fd_qtvs, so no need to subst it.
- -- See GHC.Tc.Instance.Fundeps Note [Improving against instances]
- -- Wrinkle (1)
- where
- subst' = extendSubstInScopeSet subst (tyCoVarsOfType ty1)
- -- The free vars of ty1 aren't just fd_qtvs: ty1 is the result
- -- of matching with the [W] constraint. So we add its free
- -- vars to InScopeSet, to satisfy substTy's invariants, even
- -- though ty1 will never (currently) be a poytype, so this
- -- InScopeSet will never be looked at.
-
{-
************************************************************************
* *
=====================================
compiler/GHC/Tc/Solver/Solve.hs
=====================================
@@ -15,6 +15,7 @@ module GHC.Tc.Solver.Solve (
import GHC.Prelude
import GHC.Tc.Solver.Dict
+import GHC.Tc.Solver.FunDeps( doDictFunDepImprovement )
import GHC.Tc.Solver.Equality( solveEquality )
import GHC.Tc.Solver.Irred( solveIrred )
import GHC.Tc.Solver.Rewrite( rewrite, rewriteType )
@@ -119,13 +120,13 @@ simplify_loop n limit definitely_redo_implications
, int (lengthBag simples) <+> text "simples to solve" ])
; traceTcS "simplify_loop: wc =" (ppr wc)
- ; (unifs1, wc1) <- reportUnifications $ -- See Note [Superclass iteration]
- solveSimpleWanteds simples
+ ; (n_unifs, wc1) <- reportUnifications $ -- See Note [Superclass iteration]
+ solveSimpleWanteds simples
-- Any insoluble constraints are in 'simples' and so get rewritten
-- See Note [Rewrite insolubles] in GHC.Tc.Solver.InertSet
; wc2 <- if not definitely_redo_implications -- See Note [Superclass iteration]
- && unifs1 == 0 -- for this conditional
+ && n_unifs == 0 -- for this conditional
&& isEmptyBag (wc_impl wc1)
then return (wc { wc_simple = wc_simple wc1 }) -- Short cut
else do { implics2 <- solveNestedImplications $
@@ -207,10 +208,19 @@ maybe_simplify_again n limit unif_happened wc@(WC { wc_simple = simples })
try_fundeps :: TcS (Maybe NextAction)
try_fundeps
- = do { (new_eqs, unifs) <- doDictFunDepImprovement simples
- ; if null new_eqs && not unifs
+ = do { (new_eqs, unifs1) <- doDictFunDepImprovement simples
+ ; if null new_eqs && not unifs1
then return Nothing
- else return (Just (NA_TryAgain (wc `addSimples` new_eqs) unifs)) }
+ else
+ -- We solve new_eqs immediately, hoping to get some unifications
+ -- If instead we just added them to `wc` we'll iterate and (in case when
+ -- that doesn't solve it) we'll add the same constraint again... loop!
+ do { traceTcS "try_fundeps" (ppr unifs1 $$ ppr new_eqs)
+ ; (n_unifs2, _wc) <- reportUnifications $
+ solveSimpleWanteds new_eqs
+ ; if (unifs1 || n_unifs2 > 0)
+ then return (Just (NA_TryAgain wc True))
+ else return Nothing } }
{- Note [Superclass iteration]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
=====================================
compiler/ghc.cabal.in
=====================================
@@ -854,6 +854,7 @@ Library
GHC.Tc.Solver.Irred
GHC.Tc.Solver.Equality
GHC.Tc.Solver.Dict
+ GHC.Tc.Solver.FunDeps
GHC.Tc.Solver.Monad
GHC.Tc.Solver.Types
GHC.Tc.TyCl
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/e9fc82be442304fc913469f2e41690…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/e9fc82be442304fc913469f2e41690…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/haanss/depdir] added a test for qAddDependentDirectory
by Hassan Al-Awwadi (@hassan.awwadi) 07 Jul '25
by Hassan Al-Awwadi (@hassan.awwadi) 07 Jul '25
07 Jul '25
Hassan Al-Awwadi pushed to branch wip/haanss/depdir at Glasgow Haskell Compiler / GHC
Commits:
5c81a09c by Hassan Al-Awwadi at 2025-07-07T16:39:55+02:00
added a test for qAddDependentDirectory
- - - - -
6 changed files:
- testsuite/.gitignore
- testsuite/tests/th/Makefile
- + testsuite/tests/th/TH_Depends_Dir.hs
- + testsuite/tests/th/TH_Depends_Dir.stdout
- + testsuite/tests/th/TH_Depends_External_Dir.hs
- testsuite/tests/th/all.T
Changes:
=====================================
testsuite/.gitignore
=====================================
@@ -1523,6 +1523,7 @@ mk/ghcconfig*_test___spaces_ghc*.exe.mk
/tests/th/T8633
/tests/th/TH_Depends
/tests/th/TH_Depends_external.txt
+/tests/th/TH_Depends_external/dummy.txt
/tests/th/TH_StringPrimL
/tests/th/TH_import_loop/ModuleA.hi-boot
/tests/th/TH_import_loop/ModuleA.o-boot
=====================================
testsuite/tests/th/Makefile
=====================================
@@ -43,6 +43,20 @@ TH_Depends:
'$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) --make -v0 TH_Depends
./TH_Depends
+.PHONY: TH_Depends_Dir
+TH_Depends_Dir:
+ $(RM) TH_Depends_external/dummy.txt
+ $(RM) TH_Depends TH_Depends.exe
+ $(RM) TH_Depends.o TH_Depends.hi
+ $(RM) TH_Depends_External.o TH_Depends_External.hi
+
+ mk_DIR TH_Depends_external
+ '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) --make -v0 TH_Depends_Dir
+ ./TH_Depends_Dir
+ sleep 2
+ echo "dummy" > TH_Depends_external/dummy.txt
+ '$(TEST_HC)' $(TEST_HC_OPTS) $(ghcThWayFlags) --make -v0 TH_Depends_Dir
+ ./TH_Depends_Dir
T8333:
'$(TEST_HC)' $(TEST_HC_OPTS_INTERACTIVE) $(ghcThWayFlags) T8333.hs < /dev/null
=====================================
testsuite/tests/th/TH_Depends_Dir.hs
=====================================
@@ -0,0 +1,9 @@
+
+{-# LANGUAGE TemplateHaskell #-}
+
+module Main where
+
+import TH_Depends_External (checkDirectoryContent)
+
+main :: IO ()
+main = putStrLn $checkDirectoryContent
=====================================
testsuite/tests/th/TH_Depends_Dir.stdout
=====================================
@@ -0,0 +1,3 @@
+no files?
+
+yes files!
\ No newline at end of file
=====================================
testsuite/tests/th/TH_Depends_External_Dir.hs
=====================================
@@ -0,0 +1,18 @@
+
+module TH_Depends_External where
+
+import Language.Haskell.TH.Syntax
+import Language.Haskell.TH.Lib
+import System.Directory (listDirectory)
+import Control.Monad.IO.Class (liftIO)
+
+checkDirectoryContent :: Q Exp
+checkDirectoryContent = do
+ let externalDependency = "TH_Depends_external"
+ qAddDependentDirectory externalDependency
+ files <- liftIO $ listDirectory externalDependency
+
+ let s = case files
+ [] -> "no files?"
+ _ -> "yes files!"
+ stringE s
\ No newline at end of file
=====================================
testsuite/tests/th/all.T
=====================================
@@ -214,6 +214,7 @@ test('T5434', [], multimod_compile,
['T5434', '-v0 -Wall ' + config.ghc_th_way_flags])
test('T5508', normal, compile, ['-v0 -ddump-splices -dsuppress-uniques'])
test('TH_Depends', [only_ways(['normal'])], makefile_test, ['TH_Depends'])
+test('TH_Depends_Dir', [only_ways(['normal'])], makefile_test, ['TH_Depends_Dir'])
test('T5597', [], multimod_compile, ['T5597', '-v0 ' + config.ghc_th_way_flags])
test('T5665', [], multimod_compile, ['T5665', '-v0 ' + config.ghc_th_way_flags])
test('T5700', [], multimod_compile,
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/5c81a09cbaefacac51022d9f484d25f…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/5c81a09cbaefacac51022d9f484d25f…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/marge_bot_batch_merge_job] 30 commits: Consider `PromotedDataCon` in `tyConStupidTheta`
by Marge Bot (@marge-bot) 07 Jul '25
by Marge Bot (@marge-bot) 07 Jul '25
07 Jul '25
Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
b6a2ecc7 by Berk Özkütük at 2025-07-07T10:39:41-04:00
Consider `PromotedDataCon` in `tyConStupidTheta`
Haddock checks data declarations for the stupid theta so as not to
pretty-print them as empty contexts. Type data declarations end up as
`PromotedDataCon`s by the time Haddock performs this check, causing a
panic. This commit extends `tyConStupidTheta` so that it returns an
empty list for `PromotedDataCon`s. This decision was guided by the fact
that type data declarations never have data type contexts (see (R1) in
Note [Type data declarations]).
Fixes #25739.
- - - - -
9ec94cc9 by Ryan Hendrickson at 2025-07-07T10:39:46-04:00
haddock: Document instances from other packages
When attaching instances to `Interface`s, it isn't enough just to look
for instances in the list of `Interface`s being processed. We also need
to look in the modules on which they depend, including those outside of
this package.
Fixes #25147.
Fixes #26079.
- - - - -
f7fb75aa by Rodrigo Mesquita at 2025-07-07T10:39:47-04:00
debugger/rts: Allow toggling step-in per thread
The RTS global flag `rts_stop_next_breakpoint` globally sets the
interpreter to stop at the immediate next breakpoint.
With this commit, single step mode can additionally be set per thread in
the TSO flag (TSO_STOP_NEXT_BREAKPOINT).
Being able to toggle "stop at next breakpoint" per thread is an
important requirement for implementing "stepping out" of a function in a
multi-threaded context.
And, more generally, having a per-thread flag for single-stepping paves the
way for multi-threaded debugging.
That said, when we want to enable "single step" mode for the whole
interpreted program we still want to stop at the immediate next
breakpoint, whichever thread it belongs to.
That's why we also keep the global `rts_stop_next_breakpoint` flag, with
`rts_enableStopNextBreakpointAll` and `rts_disableStopNextBreakpointAll` helpers.
Preparation for #26042
- - - - -
5529a4d8 by Rodrigo Mesquita at 2025-07-07T10:39:47-04:00
docs: Case continuation BCOs
This commit documents a subtle interaction between frames for case BCOs
and their parents frames. Namely, case continuation BCOs may refer to
(non-local) variables that are part of the parent's frame.
The note expanding a bit on these details is called [Case continuation BCOs]
- - - - -
92044eb0 by Rodrigo Mesquita at 2025-07-07T10:39:47-04:00
debugger: Implement step-out feature
Implements support for stepping-out of a function (aka breaking right after
returning from a function) in the interactive debugger.
It also introduces a GHCi command :stepout to step-out of a function
being debugged in the interpreter. The feature is described as:
Stop at the first breakpoint immediately after returning from the current
function scope.
Known limitations: because a function tail-call does not push a stack
frame, if step-out is used inside of a function that was tail-called,
execution will not be returned to its caller, but rather its caller's
first non-tail caller. On the other hand, it means the debugger
follows the more realistic execution of the program.
In the following example:
.. code-block:: none
f = do
a
b <--- (1) set breakpoint then step in here
c
b = do
...
d <--- (2) step-into this tail call
d = do
...
something <--- (3) step-out here
...
Stepping-out will stop execution at the `c` invokation in `f`, rather than
stopping at `b`.
The key idea is simple: When step-out is enabled, traverse the runtime
stack until a continuation BCO is found -- and enable the breakpoint
heading that BCO explicitly using its tick-index.
The details are specified in `Note [Debugger: Step-out]` in `rts/Interpreter.c`.
Since PUSH_ALTS BCOs (representing case continuations) were never headed
by a breakpoint (unlike the case alternatives they push), we introduced
the BRK_ALTS instruction to allow the debugger to set a case
continuation to stop at the breakpoint heading the alternative that is
taken. This is further described in `Note [Debugger: BRK_ALTS]`.
Fixes #26042
- - - - -
2e77d5be by Rodrigo Mesquita at 2025-07-07T10:39:47-04:00
debugger: Filter step-out stops by SrcSpan
To implement step-out, the RTS looks for the first continuation frame on
the stack and explicitly enables its entry breakpoint. However, some
continuations will be contained in the function from which step-out was
initiated (trivial example is a case expression).
Similarly to steplocal, we will filter the breakpoints at which the RTS
yields to the debugger based on the SrcSpan. When doing step-out, only
stop if the breakpoint is /not/ contained in the function from which we
initiated it.
This is especially relevant in monadic statements such as IO which is
compiled to a long chain of case expressions.
See Note [Debugger: Filtering step-out stops]
- - - - -
9a8739cc by Rodrigo Mesquita at 2025-07-07T10:39:48-04:00
hadrian: Fallback logic for internal interpreter
When determining whether to build the internal interpreter, the `make`
build system had a fallback case for platforms not in the list of
explicitly-supported operating systems and architectures.
This fallback says we should try to build the internal interpreter if
building dynamic GHC programs (if the architecture is unknown).
Fixes #24098
- - - - -
d85d6c41 by Ben Gamari at 2025-07-07T10:39:48-04:00
users-guide: Reference Wasm FFI section
- - - - -
e13546fb by Ben Gamari at 2025-07-07T10:39:49-04:00
users-guide: Fix too-short heading warning
- - - - -
1a395f27 by Duncan Coutts at 2025-07-07T10:39:57-04:00
Reorganise documentation for allocate* functions
Consolodate interface information into the .h file, keeping just
implementation details in the .c file.
Use Notes stlye in the .h file and refer to notes from the .c file.
- - - - -
2b144bc1 by Duncan Coutts at 2025-07-07T10:39:57-04:00
Introduce common utilities for allocating arrays
The intention is to share code among the several places that do this
already.
- - - - -
531dee3a by Duncan Coutts at 2025-07-07T10:39:57-04:00
Use new array alloc utils in Heap.c
The CMM primop can now report heap overflow.
- - - - -
ae745f70 by Duncan Coutts at 2025-07-07T10:39:57-04:00
Use new array alloc utils in ThreadLabels.c
Replacing a local utility.
- - - - -
162ad63b by Duncan Coutts at 2025-07-07T10:39:57-04:00
Use new array alloc utils in Threads.c
Replacing local open coded version.
- - - - -
d818c45d by Duncan Coutts at 2025-07-07T10:39:57-04:00
Add exitHeapOverflow helper utility
This will be useful with the array alloc functions, since unlike
allocate/allocateMaybeFail, they do not come in two versions. So if it's
not convenient to propagate failure, then one can use this.
- - - - -
5397f1d1 by Duncan Coutts at 2025-07-07T10:39:57-04:00
Use new array alloc utils in Weak.c
Also add a cpp macro CCS_SYSTEM_OR_NULL which does what it says. The
benefit of this is that it allows us to referece CCS_SYSTEM even when
we're not in PROFILING mode. That makes abstracting over profiling vs
normal mode a lot easier.
- - - - -
ccca189f by Duncan Coutts at 2025-07-07T10:39:57-04:00
Convert the array alloc primops to use the new array alloc utils
- - - - -
1c01dba5 by Duncan Coutts at 2025-07-07T10:39:57-04:00
While we're at it, add one missing 'likely' hint
To a cmm primops that raises an exception, like the others now do.
- - - - -
57a72016 by meooow25 at 2025-07-07T10:40:05-04:00
Keep scanl' strict in the head on rewrite
`scanl'` forces elements to WHNF when the corresponding `(:)`s are
forced. The rewrite rule for `scanl'` missed forcing the first element,
which is fixed here with a `seq`.
- - - - -
b0535d27 by Cheng Shao at 2025-07-07T10:40:06-04:00
compiler: make ModBreaks serializable
- - - - -
3517721d by Rodrigo Mesquita at 2025-07-07T10:40:06-04:00
refactor: "Inspecting the session" moved from GHC
Moved utilities for inspecting the session from the GHC module to
GHC.Driver.Session.Inspect
Purely a clean up
- - - - -
8052d77c by Rodrigo Mesquita at 2025-07-07T10:40:06-04:00
cleanup: Pass the HUG to readModBreaks, not HscEnv
A minor cleanup. The associated history and setupBreakpoint functions
are changed accordingly.
- - - - -
4c89bd5a by Rodrigo Mesquita at 2025-07-07T10:40:06-04:00
cleanup: Move readModBreaks to GHC.Runtime.Interpreter
With some small docs changes
- - - - -
4cfdbd19 by Rodrigo Mesquita at 2025-07-07T10:40:06-04:00
cleanup: Move interpreterProfiled to Interp.Types
Moves interpreterProfiled and interpreterDynamic to
GHC.Runtime.Interpreter.Types from GHC.Runtime.Interpreter.
- - - - -
ce89baea by Rodrigo Mesquita at 2025-07-07T10:40:06-04:00
cleanup: Don't import GHC in Debugger.Breakpoints
Remove the top-level
import GHC
from GHC.Runtime.Debugger.Breakpoints
This makes the module dependencies more granular and cleans up the
qualified imports from the code.
- - - - -
3e0f3aad by Rodrigo Mesquita at 2025-07-07T10:40:07-04:00
refactor: Use BreakpointId in Core and Ifaces
- - - - -
70705f66 by Rodrigo Mesquita at 2025-07-07T10:40:07-04:00
stg2bc: Derive BcM via ReaderT StateT
A small refactor that simplifies GHC.StgToByteCode by deriving-via the
Monad instances for BcM. This is done along the lines of previous
similar refactors like 72b54c0760bbf85be1f73c1a364d4701e5720465.
- - - - -
1a371b21 by Rodrigo Mesquita at 2025-07-07T10:40:07-04:00
refact: Split InternalModBreaks out of ModBreaks
There are currently two competing ways of referring to a Breakpoint:
1. Using the Tick module + Tick index
2. Using the Info module + Info index
1. The Tick index is allocated during desugaring in `mkModBreaks`. It is
used to refer to a breakpoint associated to a Core Tick. For a given
Tick module, there are N Ticks indexed by Tick index.
2. The Info index is allocated during code generation (in StgToByteCode)
and uniquely identifies the breakpoints at runtime (and is indeed used
to determine which breakpoint was hit at runtime).
Why we need both is described by Note [Breakpoint identifiers].
For every info index we used to keep a `CgBreakInfo`, a datatype containing
information relevant to ByteCode Generation, in `ModBreaks`.
This commit splits out the `IntMap CgBreakInfo` out of `ModBreaks` into
a new datatype `InternalModBreaks`.
- The purpose is to separate the `ModBreaks` datatype, which stores
data associated from tick-level information which is fixed after
desugaring, from the unrelated `IntMap CgBreakInfo` information
accumulated during bytecode generation.
- We move `ModBreaks` to GHC.HsToCore.Breakpoints
The new `InternalModBreaks` simply combines the `IntMap CgBreakInfo`
with `ModBreaks`. After code generation we construct an
`InternalModBreaks` with the `CgBreakInfo`s we accumulated and the
existing `ModBreaks` and store that in the compiled BCO in `bc_breaks`.
- Note that we previously only updated the `modBreaks_breakInfo`
field of `ModBreaks` at this exact location, and then stored the
updated `ModBreaks` in the same `bc_breaks`.
- We put this new datatype in GHC.ByteCode.Breakpoints
The rest of the pipeline for which CgBreakInfo is relevant is
accordingly updated to also use `InternalModBreaks`
- - - - -
e7c2d6a0 by Rodrigo Mesquita at 2025-07-07T10:40:07-04:00
cleanup: Use BreakpointIds in bytecode gen
Small clean up to use BreakpointId and InternalBreakpointId more
uniformly in bytecode generation rather than using Module + Ix pairs
- - - - -
4141e479 by Rodrigo Mesquita at 2025-07-07T10:40:07-04:00
ghci: Allocate BreakArrays at link time only
Previously, a BreakArray would be allocated with a slot for every tick
in a module at `mkModBreaks`, in HsToCore. However, this approach has
a few downsides:
- It interleaves interpreter behaviour (allocating arrays for
breakpoints) within the desugarer
- It is inflexible in the sense it is impossible for the bytecode
generator to add "internal" breakpoints that can be triggered at
runtime, because those wouldn't have a source tick. (This is relevant
for our intended implementation plan of step-out in #26042)
- It ties the BreakArray indices to the *tick* indexes, while at runtime
we would rather just have the *info* indexes (currently we have both
because BreakArrays are indexed by the *tick* one).
Paving the way for #26042 and #26064, this commit moves the allocation
of BreakArrays to bytecode-loading time -- akin to what is done for CCS
arrays.
Since a BreakArray is allocated only when bytecode is linked, if a
breakpoint is set (e.g. `:break 10`) before the bytecode is linked,
there will exist no BreakArray to trigger the breakpoint in.
Therefore, the function to allocate break arrays (`allocateBreakArrays`)
is exposed and also used in GHC.Runtime.Eval to allocate a break array
when a breakpoint is set, if it doesn't exist yet (in the linker env).
- - - - -
113 changed files:
- compiler/GHC.hs
- compiler/GHC/ByteCode/Asm.hs
- + compiler/GHC/ByteCode/Breakpoints.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Core/FVs.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/Map/Expr.hs
- compiler/GHC/Core/Opt/OccurAnal.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/Core/Ppr.hs
- compiler/GHC/Core/Subst.hs
- compiler/GHC/Core/Tidy.hs
- compiler/GHC/Core/TyCon.hs
- compiler/GHC/Core/Utils.hs
- compiler/GHC/CoreToIface.hs
- compiler/GHC/CoreToStg.hs
- compiler/GHC/CoreToStg/Prep.hs
- compiler/GHC/Driver/Config.hs
- + compiler/GHC/Driver/Session/Inspect.hs
- compiler/GHC/HsToCore.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Iface/Tidy.hs
- compiler/GHC/IfaceToCore.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Debugger/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Eval/Types.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/Runtime/Interpreter/Types.hs
- compiler/GHC/Stg/BcPrep.hs
- compiler/GHC/Stg/FVs.hs
- compiler/GHC/StgToByteCode.hs
- − compiler/GHC/Types/Breakpoint.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Unit/Module/ModGuts.hs
- compiler/ghc.cabal.in
- docs/users_guide/exts/doandifthenelse.rst
- docs/users_guide/exts/ffi.rst
- docs/users_guide/ghci.rst
- ghc/GHCi/UI.hs
- hadrian/src/Oracles/Flag.hs
- hadrian/src/Rules/Generate.hs
- hadrian/src/Settings/Builders/Cabal.hs
- hadrian/src/Settings/Packages.hs
- hadrian/src/Settings/Program.hs
- libraries/base/changelog.md
- libraries/ghc-heap/GHC/Exts/Heap/Closures.hs
- libraries/ghc-heap/GHC/Exts/Heap/FFIClosures_ProfilingDisabled.hsc
- libraries/ghc-heap/GHC/Exts/Heap/FFIClosures_ProfilingEnabled.hsc
- libraries/ghc-heap/tests/parse_tso_flags.hs
- libraries/ghc-internal/src/GHC/Internal/List.hs
- + libraries/ghci/GHCi/Debugger.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- libraries/ghci/ghci.cabal.in
- + rts/AllocArray.c
- + rts/AllocArray.h
- rts/Disassembler.c
- rts/Heap.c
- rts/Interpreter.c
- rts/Interpreter.h
- rts/PrimOps.cmm
- rts/RtsSymbols.c
- rts/RtsUtils.c
- rts/StgMiscClosures.cmm
- rts/ThreadLabels.c
- rts/Threads.c
- rts/Weak.c
- rts/include/Rts.h
- rts/include/rts/Bytecodes.h
- rts/include/rts/Constants.h
- rts/include/rts/prof/CCS.h
- rts/include/rts/storage/Closures.h
- rts/include/rts/storage/GC.h
- rts/include/rts/storage/Heap.h
- rts/rts.cabal
- rts/sm/Storage.c
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
- + testsuite/tests/ghci.debugger/scripts/T26042b.hs
- + testsuite/tests/ghci.debugger/scripts/T26042b.script
- + testsuite/tests/ghci.debugger/scripts/T26042b.stdout
- + testsuite/tests/ghci.debugger/scripts/T26042c.hs
- + testsuite/tests/ghci.debugger/scripts/T26042c.script
- + testsuite/tests/ghci.debugger/scripts/T26042c.stdout
- + testsuite/tests/ghci.debugger/scripts/T26042d.hs
- + testsuite/tests/ghci.debugger/scripts/T26042d.script
- + testsuite/tests/ghci.debugger/scripts/T26042d.stdout
- + testsuite/tests/ghci.debugger/scripts/T26042e.hs
- + testsuite/tests/ghci.debugger/scripts/T26042e.script
- + testsuite/tests/ghci.debugger/scripts/T26042e.stdout
- + testsuite/tests/ghci.debugger/scripts/T26042f.hs
- + testsuite/tests/ghci.debugger/scripts/T26042f.script
- + testsuite/tests/ghci.debugger/scripts/T26042f1.stderr
- + testsuite/tests/ghci.debugger/scripts/T26042f1.stdout
- + testsuite/tests/ghci.debugger/scripts/T26042f2.stdout
- + testsuite/tests/ghci.debugger/scripts/T26042g.hs
- + testsuite/tests/ghci.debugger/scripts/T26042g.script
- + testsuite/tests/ghci.debugger/scripts/T26042g.stdout
- testsuite/tests/ghci.debugger/scripts/all.T
- utils/haddock/CHANGES.md
- utils/haddock/haddock-api/src/Haddock/Interface/AttachInstances.hs
- utils/haddock/haddock-api/src/Haddock/Interface/Create.hs
- utils/haddock/haddock-api/src/Haddock/Types.hs
- utils/haddock/haddock-test/src/Test/Haddock/Config.hs
- utils/haddock/html-test/ref/Bug1004.html
- + utils/haddock/html-test/ref/Bug25739.html
- + utils/haddock/html-test/src/Bug25739.hs
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b1927b0bcf8f86d955aee6ed2bf118…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/b1927b0bcf8f86d955aee6ed2bf118…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

07 Jul '25
Simon Peyton Jones pushed to branch wip/T26176 at Glasgow Haskell Compiler / GHC
Commits:
382c945f by Simon Peyton Jones at 2025-07-07T14:19:44+01:00
Add test for #14010
This test started to work in GHC 9.6 and has worked since.
This MR just adds a regression test
- - - - -
2 changed files:
- + testsuite/tests/typecheck/should_compile/T14010.hs
- testsuite/tests/typecheck/should_compile/all.T
Changes:
=====================================
testsuite/tests/typecheck/should_compile/T14010.hs
=====================================
@@ -0,0 +1,44 @@
+{-# LANGUAGE NoImplicitPrelude, PolyKinds, DataKinds, TypeFamilies,
+ UndecidableSuperClasses, RankNTypes, TypeOperators,
+ FlexibleContexts, TypeSynonymInstances, FlexibleInstances,
+ UndecidableInstances #-}
+module Monolith where
+
+import Data.Kind (Type)
+import GHC.Exts (Constraint)
+
+type family (~>) :: c -> c -> Type
+
+type instance (~>) = (->)
+type instance (~>) = ArrPair
+
+type family Fst (p :: (a, b)) :: a where
+ Fst '(x, _) = x
+
+type family Snd (p :: (a, b)) :: b where
+ Snd '(_, y) = y
+
+data ArrPair a b = ArrPair (Fst a ~> Fst b) (Snd a ~> Snd b)
+
+type family Super c :: Constraint where
+ Super Type = ()
+ Super (c, d) = (Category c, Category d)
+
+class Super cat => Category cat where
+ id :: forall (a :: cat). a ~> a
+
+instance Category Type where
+ id = \x -> x
+
+instance (Category c, Category d) => Category (c, d) where
+ id = ArrPair id id
+
+-- The commented out version worked
+-- class Category (c, d) => Functor (f :: c -> d) where
+class (Category c, Category d) => Functor (f :: c -> d) where
+ map :: (a ~> b) -> (f a ~> f b)
+
+data OnSnd f a b = OnSnd (f '(a, b))
+
+instance Functor (f :: (c, d) -> Type) => Functor (OnSnd f a) where
+ map f (OnSnd x) = OnSnd (map (ArrPair id f) x)
=====================================
testsuite/tests/typecheck/should_compile/all.T
=====================================
@@ -939,3 +939,4 @@ test('T25960', normal, compile, [''])
test('T26020', normal, compile, [''])
test('T26020a', [extra_files(['T26020a_help.hs'])], multimod_compile, ['T26020a', '-v0'])
test('T25992', normal, compile, [''])
+test('T14010', normal, compile, [''])
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/382c945ff0d3999aa92d52f1076ad33…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/382c945ff0d3999aa92d52f1076ad33…
You're receiving this email because of your account on gitlab.haskell.org.
1
0
Simon Peyton Jones pushed to branch wip/T23162-spj at Glasgow Haskell Compiler / GHC
Commits:
e9fc82be by Simon Peyton Jones at 2025-07-07T12:00:22+01:00
Wibbles
- - - - -
2 changed files:
- compiler/GHC/Tc/Solver/Dict.hs
- compiler/GHC/Tc/Solver/Solve.hs
Changes:
=====================================
compiler/GHC/Tc/Solver/Dict.hs
=====================================
@@ -10,7 +10,7 @@ module GHC.Tc.Solver.Dict (
solveCallStack, -- For GHC.Tc.Solver
-- * Functional dependencies
- doTopFunDepImprovement, doLocalFunDepImprovement
+ doDictFunDepImprovement
) where
import GHC.Prelude
@@ -59,6 +59,7 @@ import GHC.Driver.DynFlags
import qualified GHC.LanguageExtensions as LangExt
+import Data.Foldable( foldrM )
import Data.Maybe ( listToMaybe, mapMaybe, isJust )
import Data.Void( Void )
@@ -1630,92 +1631,93 @@ as the fundeps.
#7875 is a case in point.
-}
-doTopFunDepImprovement :: Bag DictCt -> TcS (Cts, Bool)
--- (doFunDeps inst_envs cts)
+doDictFunDepImprovement :: Cts -> TcS (Cts, Bool)
+-- (doDictFunDepImprovement inst_envs cts)
-- * Generate the fundeps from interacting the
-- top-level `inst_envs` with the constraints `cts`
-- * Do the unifications and return any unsolved constraints
-- See Note [Fundeps with instances, and equality orientation]
-doTopFunDepImprovement cts
- = do { inst_envs <- getInstEnvs
- ; do_dict_fundeps (do_one inst_envs) cts }
+doDictFunDepImprovement unsolved_wanteds
+ = do { inerts <- getInertCans -- The inert_dicts are all Givens
+ ; inst_envs <- getInstEnvs
+ ; (_, new_eqs, unifs) <- foldrM (do_one_dict inst_envs)
+ (inert_dicts inerts, emptyBag, False)
+ unsolved_wanteds
+ ; return (new_eqs, unifs) }
+
+do_one_dict :: InstEnvs -> Ct
+ -> (DictMap DictCt, Cts, Bool)
+ -> TcS (DictMap DictCt, Cts, Bool)
+do_one_dict inst_envs (CDictCan dict_ct) (local_dicts, new_eqs, unifs)
+ = do { (new_eqs1, unifs1) <- do_one_top inst_envs dict_ct
+ ; (local_dicts2, new_eqs2, unifs2) <- do_one_local local_dicts dict_ct
+ ; return ( local_dicts2
+ , new_eqs1 `unionBags` new_eqs2 `unionBags` new_eqs
+ , unifs1 || unifs2 || unifs ) }
+
+do_one_dict _ _ acc -- Non-DictCt constraints
+ = return acc
+
+do_one_top :: InstEnvs -> DictCt -> TcS (Cts, Bool)
+do_one_top inst_envs (DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
+ = unifyFunDepWanteds ev eqns
where
- do_one :: InstEnvs -> DictCt -> TcS (Cts, Bool)
- do_one inst_envs (DictCt { di_ev = ev, di_cls = cls, di_tys = xis })
- = unifyFunDepWanteds ev eqns
+ eqns :: [FunDepEqn (CtLoc, RewriterSet)]
+ eqns = improveFromInstEnv inst_envs mk_ct_loc cls xis
+
+ dict_pred = mkClassPred cls xis
+ dict_loc = ctEvLoc ev
+ dict_origin = ctLocOrigin dict_loc
+ dict_rewriters = ctEvRewriters ev
+
+ mk_ct_loc :: ClsInst -- The instance decl
+ -> (CtLoc, RewriterSet)
+ mk_ct_loc ispec
+ = (dict_loc { ctl_origin = new_orig }, dict_rewriters)
where
- eqns :: [FunDepEqn (CtLoc, RewriterSet)]
- eqns = improveFromInstEnv inst_envs mk_ct_loc cls xis
-
- dict_pred = mkClassPred cls xis
- dict_loc = ctEvLoc ev
- dict_origin = ctLocOrigin dict_loc
- dict_rewriters = ctEvRewriters ev
-
- mk_ct_loc :: ClsInst -- The instance decl
- -> (CtLoc, RewriterSet)
- mk_ct_loc ispec
- = (dict_loc { ctl_origin = new_orig }, dict_rewriters)
- where
- inst_pred = mkClassPred cls (is_tys ispec)
- inst_loc = getSrcSpan (is_dfun ispec)
- new_orig = FunDepOrigin2 dict_pred dict_origin
- inst_pred inst_loc
-
-doLocalFunDepImprovement :: Bag DictCt -> TcS (Cts,Bool)
+ inst_pred = mkClassPred cls (is_tys ispec)
+ inst_loc = getSrcSpan (is_dfun ispec)
+ new_orig = FunDepOrigin2 dict_pred dict_origin
+ inst_pred inst_loc
+
+do_one_local :: DictMap DictCt -> DictCt -> TcS (DictMap DictCt, Cts, Bool)
-- Using functional dependencies, interact the unsolved Wanteds
-- against each other and the inert Givens, to produce new equalities
-doLocalFunDepImprovement wanted
- = do { inerts <- getInertCans -- The inert_dicts are all Givens
- ; let all_dicts :: DictMap DictCt -- Both Givens and Wanteds
- all_dicts = foldr addDict (inert_dicts inerts) wanted
- ; do_dict_fundeps (do_one all_dicts) wanted }
+do_one_local locals dict_ct@(DictCt { di_cls = cls, di_ev = wanted_ev })
+ -- locals contains all the Givens and earlier Wanteds
+ = do { (new_eqs, unifs) <- foldrM do_interaction (emptyBag, False) $
+ findDictsByClass locals cls
+ ; return (addDict dict_ct locals, new_eqs, unifs) }
where
- -- all_dicts are all the Givens and all the Wanteds
- do_one all_dicts (DictCt { di_cls = cls, di_ev = wanted_ev })
- = do_dict_fundeps do_interaction (findDictsByClass all_dicts cls)
+ wanted_pred = ctEvPred wanted_ev
+ wanted_loc = ctEvLoc wanted_ev
+
+ do_interaction :: DictCt -> (Cts,Bool) -> TcS (Cts,Bool)
+ do_interaction (DictCt { di_ev = all_ev }) (new_eqs, unifs) -- This can be Given or Wanted
+ = do { traceTcS "doLocalFunDepImprovement" $
+ vcat [ ppr wanted_ev
+ , pprCtLoc wanted_loc, ppr (isGivenLoc wanted_loc)
+ , pprCtLoc all_loc, ppr (isGivenLoc all_loc)
+ , pprCtLoc deriv_loc, ppr (isGivenLoc deriv_loc) ]
+
+ ; (new_eqs1, unifs1) <- unifyFunDepWanteds wanted_ev $
+ improveFromAnother (deriv_loc, all_rewriters)
+ all_pred wanted_pred
+ ; return (new_eqs1 `unionBags` new_eqs, unifs1 || unifs) }
where
- wanted_pred = ctEvPred wanted_ev
- wanted_loc = ctEvLoc wanted_ev
-
- do_interaction :: DictCt -> TcS (Cts,Bool)
- do_interaction (DictCt { di_ev = all_ev }) -- This can be Given or Wanted
- = do { traceTcS "doLocalFunDepImprovement" $
- vcat [ ppr wanted_ev
- , pprCtLoc wanted_loc, ppr (isGivenLoc wanted_loc)
- , pprCtLoc all_loc, ppr (isGivenLoc all_loc)
- , pprCtLoc deriv_loc, ppr (isGivenLoc deriv_loc) ]
-
- ; unifyFunDepWanteds wanted_ev $
- improveFromAnother (deriv_loc, all_rewriters)
- all_pred wanted_pred }
- where
- all_pred = ctEvPred all_ev
- all_loc = ctEvLoc all_ev
- all_rewriters = ctEvRewriters all_ev
- deriv_loc = wanted_loc { ctl_depth = deriv_depth
- , ctl_origin = deriv_origin }
- deriv_depth = ctl_depth wanted_loc `maxSubGoalDepth`
- ctl_depth all_loc
- deriv_origin = FunDepOrigin1 wanted_pred
- (ctLocOrigin wanted_loc)
- (ctLocSpan wanted_loc)
- all_pred
- (ctLocOrigin all_loc)
- (ctLocSpan all_loc)
-
-do_dict_fundeps :: (DictCt -> TcS (Cts,Bool)) -> Bag DictCt -> TcS (Cts,Bool)
-do_dict_fundeps do_dict_fundep cts
- = foldr do_one (return (emptyBag, False)) cts
- where
- do_one :: DictCt -> TcS (Cts,Bool) -> TcS (Cts,Bool)
- do_one dict_ct do_rest
- = -- assert (not (isGiven (dictCtEvidence dict_ct)) $
- do { (cts1, unifs1) <- do_dict_fundep dict_ct
- ; if isEmptyBag cts1 && not unifs1
- then do_rest -- Common case
- else do { (cts2, unifs2) <- do_rest
- ; return (cts1 `unionBags` cts2, unifs1 || unifs2) } }
+ all_pred = ctEvPred all_ev
+ all_loc = ctEvLoc all_ev
+ all_rewriters = ctEvRewriters all_ev
+ deriv_loc = wanted_loc { ctl_depth = deriv_depth
+ , ctl_origin = deriv_origin }
+ deriv_depth = ctl_depth wanted_loc `maxSubGoalDepth`
+ ctl_depth all_loc
+ deriv_origin = FunDepOrigin1 wanted_pred
+ (ctLocOrigin wanted_loc)
+ (ctLocSpan wanted_loc)
+ all_pred
+ (ctLocOrigin all_loc)
+ (ctLocSpan all_loc)
{- *********************************************************************
=====================================
compiler/GHC/Tc/Solver/Solve.hs
=====================================
@@ -205,18 +205,9 @@ maybe_simplify_again n limit unif_happened wc@(WC { wc_simple = simples })
| otherwise
= return Nothing
- dicts :: Bag DictCt
- dicts = mapMaybeBag is_dict simples
- where
- is_dict (CDictCan d) = Just d
- is_dict _ = Nothing
-
try_fundeps :: TcS (Maybe NextAction)
try_fundeps
- = do { (new_eqs1, unifs1) <- doTopFunDepImprovement dicts
- ; (new_eqs2, unifs2) <- doLocalFunDepImprovement dicts
- ; let new_eqs = new_eqs1 `unionBags` new_eqs2
- unifs = unifs1 || unifs2
+ = do { (new_eqs, unifs) <- doDictFunDepImprovement simples
; if null new_eqs && not unifs
then return Nothing
else return (Just (NA_TryAgain (wc `addSimples` new_eqs) unifs)) }
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e9fc82be442304fc913469f2e416908…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/e9fc82be442304fc913469f2e416908…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/romes/step-out-10] 5 commits: refact: Split InternalModBreaks out of ModBreaks
by Rodrigo Mesquita (@alt-romes) 07 Jul '25
by Rodrigo Mesquita (@alt-romes) 07 Jul '25
07 Jul '25
Rodrigo Mesquita pushed to branch wip/romes/step-out-10 at Glasgow Haskell Compiler / GHC
Commits:
06651a24 by Rodrigo Mesquita at 2025-07-02T17:24:52+01:00
refact: Split InternalModBreaks out of ModBreaks
There are currently two competing ways of referring to a Breakpoint:
1. Using the Tick module + Tick index
2. Using the Info module + Info index
1. The Tick index is allocated during desugaring in `mkModBreaks`. It is
used to refer to a breakpoint associated to a Core Tick. For a given
Tick module, there are N Ticks indexed by Tick index.
2. The Info index is allocated during code generation (in StgToByteCode)
and uniquely identifies the breakpoints at runtime (and is indeed used
to determine which breakpoint was hit at runtime).
Why we need both is described by Note [Breakpoint identifiers].
For every info index we used to keep a `CgBreakInfo`, a datatype containing
information relevant to ByteCode Generation, in `ModBreaks`.
This commit splits out the `IntMap CgBreakInfo` out of `ModBreaks` into
a new datatype `InternalModBreaks`.
- The purpose is to separate the `ModBreaks` datatype, which stores
data associated from tick-level information which is fixed after
desugaring, from the unrelated `IntMap CgBreakInfo` information
accumulated during bytecode generation.
- We move `ModBreaks` to GHC.HsToCore.Breakpoints
The new `InternalModBreaks` simply combines the `IntMap CgBreakInfo`
with `ModBreaks`. After code generation we construct an
`InternalModBreaks` with the `CgBreakInfo`s we accumulated and the
existing `ModBreaks` and store that in the compiled BCO in `bc_breaks`.
- Note that we previously only updated the `modBreaks_breakInfo`
field of `ModBreaks` at this exact location, and then stored the
updated `ModBreaks` in the same `bc_breaks`.
- We put this new datatype in GHC.ByteCode.Breakpoints
The rest of the pipeline for which CgBreakInfo is relevant is
accordingly updated to also use `InternalModBreaks`
- - - - -
c3f1b718 by Rodrigo Mesquita at 2025-07-02T17:24:52+01:00
cleanup: Use BreakpointIds in bytecode gen
Small clean up to use BreakpointId and InternalBreakpointId more
uniformly in bytecode generation rather than using Module + Ix pairs
- - - - -
92555217 by Rodrigo Mesquita at 2025-07-04T13:02:15+01:00
ghci: Allocate BreakArrays at link time only
Previously, a BreakArray would be allocated with a slot for every tick
in a module at `mkModBreaks`, in HsToCore. However, this approach has
a few downsides:
- It interleaves interpreter behaviour (allocating arrays for
breakpoints) within the desugarer
- It is inflexible in the sense it is impossible for the bytecode
generator to add "internal" breakpoints that can be triggered at
runtime, because those wouldn't have a source tick. (This is relevant
for our intended implementation plan of step-out in #26042)
- It ties the BreakArray indices to the *tick* indexes, while at runtime
we would rather just have the *info* indexes (currently we have both
because BreakArrays are indexed by the *tick* one).
Paving the way for #26042 and #26064, this commit moves the allocation
of BreakArrays to bytecode-loading time -- akin to what is done for CCS
arrays.
Since a BreakArray is allocated only when bytecode is linked, if a
breakpoint is set (e.g. `:break 10`) before the bytecode is linked,
there will exist no BreakArray to trigger the breakpoint in.
Therefore, the function to allocate break arrays (`allocateBreakArrays`)
is exposed and also used in GHC.Runtime.Eval to allocate a break array
when a breakpoint is set, if it doesn't exist yet (in the linker env).
- - - - -
fd87ea98 by Rodrigo Mesquita at 2025-07-07T11:58:44+01:00
Uniquely identify Breakpoints at runtime using internal breakpoint ids
- - - - -
3a9ac3cd by Rodrigo Mesquita at 2025-07-07T11:59:09+01:00
Figure out the GHCi Bits
- - - - -
34 changed files:
- compiler/GHC.hs
- compiler/GHC/ByteCode/Asm.hs
- + compiler/GHC/ByteCode/Breakpoints.hs
- compiler/GHC/ByteCode/Instr.hs
- compiler/GHC/ByteCode/Linker.hs
- compiler/GHC/ByteCode/Types.hs
- compiler/GHC/Core/Ppr.hs
- compiler/GHC/CoreToIface.hs
- compiler/GHC/Driver/Session/Inspect.hs
- compiler/GHC/HsToCore.hs
- compiler/GHC/HsToCore/Breakpoints.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Iface/Syntax.hs
- compiler/GHC/Linker/Loader.hs
- compiler/GHC/Linker/Types.hs
- compiler/GHC/Runtime/Debugger/Breakpoints.hs
- compiler/GHC/Runtime/Eval.hs
- compiler/GHC/Runtime/Eval/Types.hs
- compiler/GHC/Runtime/Interpreter.hs
- compiler/GHC/StgToByteCode.hs
- − compiler/GHC/Types/Breakpoint.hs
- compiler/GHC/Types/Tickish.hs
- compiler/GHC/Unit/Module/ModGuts.hs
- compiler/ghc.cabal.in
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Monad.hs
- libraries/ghci/GHCi/Debugger.hs
- libraries/ghci/GHCi/Message.hs
- libraries/ghci/GHCi/Run.hs
- rts/Disassembler.c
- rts/Exception.cmm
- rts/Interpreter.c
- testsuite/tests/count-deps/CountDepsAst.stdout
- testsuite/tests/count-deps/CountDepsParser.stdout
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7181968215b92999e63ebfd29d66cc…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/7181968215b92999e63ebfd29d66cc…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

07 Jul '25
Matthew Pickering pushed new branch wip/t26088 at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/t26088
You're receiving this email because of your account on gitlab.haskell.org.
1
0

[Git][ghc/ghc][wip/teo/allow-newer-ghc-paths] 11 commits: template-haskell: improve changelog
by Teo Camarasu (@teo) 07 Jul '25
by Teo Camarasu (@teo) 07 Jul '25
07 Jul '25
Teo Camarasu pushed to branch wip/teo/allow-newer-ghc-paths at Glasgow Haskell Compiler / GHC
Commits:
4b748a99 by Teo Camarasu at 2025-06-24T15:31:07-04:00
template-haskell: improve changelog
stable -> more stable, just to clarify that this interface isn't fully stable.
errornously -> mistakenly: I typod this and also let's go for a simpler word
- - - - -
e358e477 by Sylvain Henry at 2025-06-24T15:31:58-04:00
Bump stack resolver to use GHC 9.6.7
Cf #26139
- - - - -
4bf5eb63 by fendor at 2025-06-25T17:05:43-04:00
Teach `:reload` about multiple home units
`:reload` needs to lookup the `ModuleName` and must not assume the given
`ModuleName` is in the current `HomeUnit`.
We add a new utility function which allows us to find a `HomeUnitModule`
instead of a `Module`.
Further, we introduce the `GhciCommandError` type which can be used to
abort the execution of a GHCi command.
This error is caught and printed in a human readable fashion.
- - - - -
b3d97bb3 by fendor at 2025-06-25T17:06:25-04:00
Implement `-fno-load-initial-targets` flag
We add the new flag `-fno-load-initial-targets` which doesn't load all `Target`s
immediately but only computes the module graph for all `Target`s.
The user can then decide to load modules from that module graph using
the syntax:
ghci> :reload <Mod>
This will load everything in the module graph up to `Mod`.
The user can return to the initial state by using the builtin target
`none` to unload all modules.
ghci> :reload none
Is in principle identical to starting a new session with the
`-fno-load-initial-targets` flag.
The `-fno-load-initial-targets` flag allows for faster startup time of GHCi when a
user has lots of `Target`s.
We additionally extend the `:reload` command to accept multiple
`ModuleName`s. For example:
ghci> :reload <Mod1> <Mod2>
Loads all modules up to the modules `Mod1` and `Mod2`.
- - - - -
49f44e52 by Teo Camarasu at 2025-06-26T04:19:51-04:00
Expose ghc-internal unit id through the settings file
This in combination with the unit id of the compiler library allows
cabal to know of the two unit ids that should not be reinstalled (in
specific circumstances) as:
- when using plugins, we want to link against exactly the compiler unit
id
- when using TemplateHaskell we want to link against exactly the package
that contains the TemplateHaskell interfaces, which is `ghc-internal`
See: <https://github.com/haskell/cabal/issues/10087>
Resolves #25282
- - - - -
499c4efe by Bryan Richter at 2025-06-26T04:20:33-04:00
CI: Fix and clean up capture of timings
* Fixes the typo that caused 'cat ci-timings' to report "no such file or
directory"
* Gave ci_timings.txt a file extension so it may play better with other
systems
* Fixed the use of time_it so all times are recorded
* Fixed time_it to print name along with timing
- - - - -
86c90c9e by Bryan Richter at 2025-06-26T04:20:33-04:00
CI: Update collapsible section usage
The syntax apparently changed at some point.
- - - - -
04308ee4 by Bryan Richter at 2025-06-26T04:20:33-04:00
CI: Add more collapsible sections
- - - - -
43b606bb by Florian Ragwitz at 2025-06-27T16:31:26-04:00
Tick uses of wildcard/pun field binds as if using the record selector function
Fixes #17834.
See Note [Record-selector ticks] for additional reasoning behind this as well
as an overview of the implementation details and future improvements.
- - - - -
d4952549 by Ben Gamari at 2025-06-27T16:32:08-04:00
testsuite/caller-cc: Make CallerCc[123] less sensitive
These were previously sensitive to irrelevant changes in program
structure. To avoid this we filter out all by lines emitted by the
-fcaller-cc from the profile.
- - - - -
fa852009 by Teo Camarasu at 2025-07-07T10:06:28+00:00
cabal.project-reinstall: allow newer ghc-paths:Cabal
This upper bound will be wrong whenever we are using a development version of Cabal in-tree, so let's just add an allow-newer here
- - - - -
60 changed files:
- .gitlab-ci.yml
- .gitlab/ci.sh
- .gitlab/common.sh
- .gitlab/generate-ci/gen_ci.hs
- .gitlab/jobs.yaml
- cabal.project-reinstall
- compiler/GHC/Driver/DynFlags.hs
- compiler/GHC/Driver/Flags.hs
- compiler/GHC/Driver/Make.hs
- compiler/GHC/Driver/Session.hs
- compiler/GHC/HsToCore/Ticks.hs
- compiler/GHC/Unit/Module/Graph.hs
- compiler/Setup.hs
- docs/users_guide/9.14.1-notes.rst
- docs/users_guide/ghci.rst
- ghc/GHCi/UI.hs
- ghc/GHCi/UI/Exception.hs
- ghc/GHCi/UI/Print.hs
- hadrian/src/Rules/Generate.hs
- hadrian/stack.yaml
- hadrian/stack.yaml.lock
- libraries/template-haskell/changelog.md
- testsuite/tests/ghc-e/should_fail/T18441fail5.stderr
- testsuite/tests/ghci/prog-mhu003/prog-mhu003.stderr
- testsuite/tests/ghci/prog-mhu004/prog-mhu004a.stderr
- + testsuite/tests/ghci/prog-mhu005/Makefile
- + testsuite/tests/ghci/prog-mhu005/a/A.hs
- + testsuite/tests/ghci/prog-mhu005/all.T
- + testsuite/tests/ghci/prog-mhu005/b/B.hs
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005a.script
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005a.stderr
- + testsuite/tests/ghci/prog-mhu005/prog-mhu005a.stdout
- + testsuite/tests/ghci/prog-mhu005/unitA
- + testsuite/tests/ghci/prog-mhu005/unitB
- + testsuite/tests/ghci/prog021/A.hs
- + testsuite/tests/ghci/prog021/B.hs
- + testsuite/tests/ghci/prog021/Makefile
- + testsuite/tests/ghci/prog021/all.T
- + testsuite/tests/ghci/prog021/prog021a.script
- + testsuite/tests/ghci/prog021/prog021a.stderr
- + testsuite/tests/ghci/prog021/prog021a.stdout
- + testsuite/tests/ghci/prog021/prog021b.script
- + testsuite/tests/ghci/prog021/prog021b.stderr
- + testsuite/tests/ghci/prog021/prog021b.stdout
- + testsuite/tests/ghci/prog022/A.hs
- + testsuite/tests/ghci/prog022/B.hs
- + testsuite/tests/ghci/prog022/Makefile
- + testsuite/tests/ghci/prog022/all.T
- + testsuite/tests/ghci/prog022/ghci.prog022a.script
- + testsuite/tests/ghci/prog022/ghci.prog022a.stderr
- + testsuite/tests/ghci/prog022/ghci.prog022a.stdout
- + testsuite/tests/ghci/prog022/ghci.prog022b.script
- + testsuite/tests/ghci/prog022/ghci.prog022b.stderr
- + testsuite/tests/ghci/prog022/ghci.prog022b.stdout
- testsuite/tests/ghci/scripts/ghci021.stderr
- + testsuite/tests/hpc/recsel/Makefile
- + testsuite/tests/hpc/recsel/recsel.hs
- + testsuite/tests/hpc/recsel/recsel.stdout
- + testsuite/tests/hpc/recsel/test.T
- testsuite/tests/profiling/should_run/caller-cc/all.T
The diff was not included because it is too large.
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/878c388877a4390a77b959ba9dc31b…
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/compare/878c388877a4390a77b959ba9dc31b…
You're receiving this email because of your account on gitlab.haskell.org.
1
0

07 Jul '25
Matthew Pickering pushed new branch wip/t26087 at Glasgow Haskell Compiler / GHC
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/tree/wip/t26087
You're receiving this email because of your account on gitlab.haskell.org.
1
0