Simon Peyton Jones pushed to branch wip/T26346 at Glasgow Haskell Compiler / GHC
Commits:
-
5b5d9d47
by Ben Gamari at 2025-08-25T14:29:35-04:00
-
10f06163
by Cheng Shao at 2025-08-25T14:30:16-04:00
-
bedc1004
by Cheng Shao at 2025-08-26T09:31:18-04:00
-
13250d97
by Ryan Scott at 2025-08-26T09:31:59-04:00
-
279a6fd3
by Simon Peyton Jones at 2025-08-26T17:17:15+01:00
-
40276cda
by Simon Peyton Jones at 2025-08-26T17:17:42+01:00
17 changed files:
- compiler/GHC/Cmm/Dataflow/Label.hs
- compiler/GHC/Core/Unify.hs
- compiler/GHC/Rename/HsType.hs
- compiler/GHC/Tc/Utils/Unify.hs
- docs/users_guide/9.16.1-notes.rst
- rts/PrimOps.cmm
- rts/RaiseAsync.c
- rts/STM.c
- − testsuite/tests/lib/stm/T26028.hs
- − testsuite/tests/lib/stm/T26028.stdout
- − testsuite/tests/lib/stm/all.T
- + testsuite/tests/typecheck/should_compile/T26346.hs
- testsuite/tests/typecheck/should_compile/all.T
- + testsuite/tests/typecheck/should_fail/T26318.hs
- + testsuite/tests/typecheck/should_fail/T26318.stderr
- testsuite/tests/typecheck/should_fail/all.T
- utils/jsffi/dyld.mjs
Changes:
| ... | ... | @@ -83,6 +83,7 @@ import GHC.Data.Word64Map.Strict (Word64Map) |
| 83 | 83 | import qualified GHC.Data.Word64Map.Strict as M
|
| 84 | 84 | import GHC.Data.TrieMap
|
| 85 | 85 | |
| 86 | +import Data.Coerce
|
|
| 86 | 87 | import Data.Word (Word64)
|
| 87 | 88 | |
| 88 | 89 | |
| ... | ... | @@ -164,7 +165,7 @@ setFoldr k z (LS s) = S.foldr (\v a -> k (mkHooplLabel v) a) z s |
| 164 | 165 | |
| 165 | 166 | {-# INLINE setElems #-}
|
| 166 | 167 | setElems :: LabelSet -> [Label]
|
| 167 | -setElems (LS s) = map mkHooplLabel (S.elems s)
|
|
| 168 | +setElems (LS s) = coerce $ S.elems s
|
|
| 168 | 169 | |
| 169 | 170 | {-# INLINE setFromList #-}
|
| 170 | 171 | setFromList :: [Label] -> LabelSet
|
| ... | ... | @@ -272,7 +273,7 @@ mapKeys (LM m) = map (mkHooplLabel . fst) (M.toList m) |
| 272 | 273 | |
| 273 | 274 | {-# INLINE mapToList #-}
|
| 274 | 275 | mapToList :: LabelMap b -> [(Label, b)]
|
| 275 | -mapToList (LM m) = [(mkHooplLabel k, v) | (k, v) <- M.toList m]
|
|
| 276 | +mapToList (LM m) = coerce $ M.toList m
|
|
| 276 | 277 | |
| 277 | 278 | {-# INLINE mapFromList #-}
|
| 278 | 279 | mapFromList :: [(Label, v)] -> LabelMap v
|
| ... | ... | @@ -245,16 +245,21 @@ give up on), but for /substitutivity/. If we have (F x x), we can see that (F x |
| 245 | 245 | can reduce to Double. So, it had better be the case that (F blah blah) can
|
| 246 | 246 | reduce to Double, no matter what (blah) is!
|
| 247 | 247 | |
| 248 | -To achieve this, `go_fam` in `uVarOrFam` does this;
|
|
| 248 | +To achieve this, `go` in `uVarOrFam` does this;
|
|
| 249 | + |
|
| 250 | +* We maintain /two/ substitutions, not just one:
|
|
| 251 | + * um_tv_env: the regular substitution, mapping TyVar :-> Type
|
|
| 252 | + * um_fam_env: maps (TyCon,[Type]) :-> Type, where the LHS is a type-fam application
|
|
| 253 | + In effect, these constitute one substitution mapping
|
|
| 254 | + CanEqLHS :-> Types
|
|
| 249 | 255 | |
| 250 | 256 | * When we attempt to unify (G Float) ~ Int, we return MaybeApart..
|
| 251 | - but we /also/ extend a "family substitution" [G Float :-> Int],
|
|
| 252 | - in `um_fam_env`, alongside the regular [tyvar :-> type] substitution in
|
|
| 253 | - `um_tv_env`. See the `BindMe` case of `go_fam` in `uVarOrFam`.
|
|
| 257 | + but we /also/ add a "family substitution" [G Float :-> Int],
|
|
| 258 | + to `um_fam_env`. See the `BindMe` case of `go` in `uVarOrFam`.
|
|
| 254 | 259 | |
| 255 | 260 | * When we later encounter (G Float) ~ Bool, we apply the family substitution,
|
| 256 | 261 | very much as we apply the conventional [tyvar :-> type] substitution
|
| 257 | - when we encounter a type variable. See the `lookupFamEnv` in `go_fam` in
|
|
| 262 | + when we encounter a type variable. See the `lookupFamEnv` in `go` in
|
|
| 258 | 263 | `uVarOrFam`.
|
| 259 | 264 | |
| 260 | 265 | So (G Float ~ Bool) becomes (Int ~ Bool) which is SurelyApart. Bingo.
|
| ... | ... | @@ -329,7 +334,7 @@ Wrinkles |
| 329 | 334 | alternative path. So `noMatchableGivenDicts` must return False;
|
| 330 | 335 | so `mightMatchLater` must return False; so when um_bind_fam_fun returns
|
| 331 | 336 | `DontBindMe`, the unifier must return `SurelyApart`, not `MaybeApart`. See
|
| 332 | - `go_fam` in `uVarOrFam`
|
|
| 337 | + `go` in `uVarOrFam`
|
|
| 333 | 338 | |
| 334 | 339 | (ATF6) When /matching/ can we ever have a type-family application on the LHS, in
|
| 335 | 340 | the template? You might think not, because type-class-instance and
|
| ... | ... | @@ -426,6 +431,26 @@ Wrinkles |
| 426 | 431 | (ATF12) There is a horrid exception for the injectivity check. See (UR1) in
|
| 427 | 432 | in Note [Specification of unification].
|
| 428 | 433 | |
| 434 | +(ATF13) Consider unifying
|
|
| 435 | + [F a, F Int, Int] ~ [Bool, Char, a]
|
|
| 436 | + Working left to right you might think we would build the mapping
|
|
| 437 | + F a :-> Bool
|
|
| 438 | + F Int :-> Char
|
|
| 439 | + Now we discover that `a` unifies with `Int`. So really these two lists are Apart
|
|
| 440 | + because F Int can't be both Bool and Char.
|
|
| 441 | + |
|
| 442 | + But that is very tricky! Perhaps whenever we unify a type variable we should
|
|
| 443 | + run it over the domain and (maybe range) of the type-family mapping too?
|
|
| 444 | + Sigh.
|
|
| 445 | + |
|
| 446 | + For we make no such attempt. The um_fam_env has only pre-substituted types.
|
|
| 447 | + Fortunately, while this may make use say MaybeApart when we could say SurelyApart,
|
|
| 448 | + it has no effect on the correctness of unification: if we return Unifiable, it
|
|
| 449 | + really is Unifiable.
|
|
| 450 | + |
|
| 451 | +(ATF14) We have to be careful about the occurs check.
|
|
| 452 | + See Note [The occurs check in the Core unifier]
|
|
| 453 | + |
|
| 429 | 454 | SIDE NOTE. The paper "Closed type families with overlapping equations"
|
| 430 | 455 | http://research.microsoft.com/en-us/um/people/simonpj/papers/ext-f/axioms-extended.pdf
|
| 431 | 456 | tries to achieve the same effect with a standard yes/no unifier, by "flattening"
|
| ... | ... | @@ -1776,16 +1801,11 @@ uVarOrFam env ty1 ty2 kco |
| 1776 | 1801 | -- E.g. a ~ F p q
|
| 1777 | 1802 | -- Starts with: go a (F p q)
|
| 1778 | 1803 | -- if `a` not bindable, swap to: go (F p q) a
|
| 1779 | - go swapped substs (TyVarLHS tv1) ty2 kco
|
|
| 1780 | - = go_tv swapped substs tv1 ty2 kco
|
|
| 1781 | - |
|
| 1782 | - go swapped substs (TyFamLHS tc tys) ty2 kco
|
|
| 1783 | - = go_fam swapped substs tc tys ty2 kco
|
|
| 1784 | 1804 | |
| 1785 | 1805 | -----------------------------
|
| 1786 | - -- go_tv: LHS is a type variable
|
|
| 1806 | + -- LHS is a type variable
|
|
| 1787 | 1807 | -- The sequence of tests is very similar to go_tv
|
| 1788 | - go_tv swapped substs tv1 ty2 kco
|
|
| 1808 | + go swapped substs lhs@(TyVarLHS tv1) ty2 kco
|
|
| 1789 | 1809 | | Just ty1' <- lookupVarEnv (um_tv_env substs) tv1'
|
| 1790 | 1810 | = -- We already have a substitution for tv1
|
| 1791 | 1811 | if | um_unif env -> unify_ty env ty1' ty2 kco
|
| ... | ... | @@ -1837,7 +1857,6 @@ uVarOrFam env ty1 ty2 kco |
| 1837 | 1857 | where
|
| 1838 | 1858 | tv1' = umRnOccL env tv1
|
| 1839 | 1859 | ty2_fvs = tyCoVarsOfType ty2
|
| 1840 | - rhs_fvs = ty2_fvs `unionVarSet` tyCoVarsOfCo kco
|
|
| 1841 | 1860 | rhs = ty2 `mkCastTy` mkSymCo kco
|
| 1842 | 1861 | tv1_is_bindable | not (tv1' `elemVarSet` um_foralls env)
|
| 1843 | 1862 | -- tv1' is not forall-bound, but tv1 can still differ
|
| ... | ... | @@ -1848,16 +1867,15 @@ uVarOrFam env ty1 ty2 kco |
| 1848 | 1867 | | otherwise
|
| 1849 | 1868 | = False
|
| 1850 | 1869 | |
| 1851 | - occurs_check = um_unif env &&
|
|
| 1852 | - occursCheck (um_tv_env substs) tv1 rhs_fvs
|
|
| 1870 | + occurs_check = um_unif env && uOccursCheck substs lhs rhs
|
|
| 1853 | 1871 | -- Occurs check, only when unifying
|
| 1854 | 1872 | -- see Note [Infinitary substitutions]
|
| 1855 | - -- Make sure you include `kco` in rhs_tvs #14846
|
|
| 1873 | + -- Make sure you include `kco` in rhs #14846
|
|
| 1856 | 1874 | |
| 1857 | 1875 | -----------------------------
|
| 1858 | - -- go_fam: LHS is a saturated type-family application
|
|
| 1876 | + -- LHS is a saturated type-family application
|
|
| 1859 | 1877 | -- Invariant: ty2 is not a TyVarTy
|
| 1860 | - go_fam swapped substs tc1 tys1 ty2 kco
|
|
| 1878 | + go swapped substs lhs@(TyFamLHS tc1 tys1) ty2 kco
|
|
| 1861 | 1879 | -- If we are under a forall, just give up and return MaybeApart
|
| 1862 | 1880 | -- see (ATF3) in Note [Apartness and type families]
|
| 1863 | 1881 | | not (isEmptyVarSet (um_foralls env))
|
| ... | ... | @@ -1883,9 +1901,10 @@ uVarOrFam env ty1 ty2 kco |
| 1883 | 1901 | -- Now check if we can bind the (F tys) to the RHS
|
| 1884 | 1902 | -- This can happen even when matching: see (ATF7)
|
| 1885 | 1903 | | BindMe <- um_bind_fam_fun env tc1 tys1 rhs
|
| 1886 | - = -- ToDo: do we need an occurs check here?
|
|
| 1887 | - do { extendFamEnv tc1 tys1 rhs
|
|
| 1888 | - ; maybeApart MARTypeFamily }
|
|
| 1904 | + = if uOccursCheck substs lhs rhs
|
|
| 1905 | + then maybeApart MARInfinite
|
|
| 1906 | + else do { extendFamEnv tc1 tys1 rhs -- We don't substitue tys1; see (ATF13)
|
|
| 1907 | + ; maybeApart MARTypeFamily }
|
|
| 1889 | 1908 | |
| 1890 | 1909 | -- Swap in case of (F a b) ~ (G c d e)
|
| 1891 | 1910 | -- Maybe um_bind_fam_fun is False of (F a b) but true of (G c d e)
|
| ... | ... | @@ -1939,17 +1958,67 @@ uVarOrFam env ty1 ty2 kco |
| 1939 | 1958 | rhs2 = mkTyConApp tc tys1 `mkCastTy` kco
|
| 1940 | 1959 | |
| 1941 | 1960 | |
| 1942 | -occursCheck :: TvSubstEnv -> TyVar -> TyCoVarSet -> Bool
|
|
| 1943 | -occursCheck env tv1 tvs
|
|
| 1944 | - = anyVarSet bad tvs
|
|
| 1961 | +uOccursCheck :: UMState -> CanEqLHS -> Type -> Bool
|
|
| 1962 | +-- See Note [The occurs check in the Core unifier] and (ATF13)
|
|
| 1963 | +uOccursCheck (UMState { um_tv_env = tv_env, um_fam_env = fam_env }) lhs ty
|
|
| 1964 | + = go emptyVarSet ty
|
|
| 1945 | 1965 | where
|
| 1946 | - bad tv | Just ty <- lookupVarEnv env tv
|
|
| 1947 | - = anyVarSet bad (tyCoVarsOfType ty)
|
|
| 1948 | - | otherwise
|
|
| 1949 | - = tv == tv1
|
|
| 1966 | + go :: TyCoVarSet -- Bound by enclosing foralls
|
|
| 1967 | + -> Type -> Bool
|
|
| 1968 | + go bvs ty | Just ty' <- coreView ty = go bvs ty'
|
|
| 1969 | + go bvs (TyVarTy tv) | Just ty' <- lookupVarEnv tv_env tv
|
|
| 1970 | + = go bvs ty'
|
|
| 1971 | + | TyVarLHS tv' <- lhs, tv==tv'
|
|
| 1972 | + = True
|
|
| 1973 | + | otherwise
|
|
| 1974 | + = go bvs (tyVarKind tv)
|
|
| 1975 | + go bvs (AppTy ty1 ty2) = go bvs ty1 || go bvs ty2
|
|
| 1976 | + go _ (LitTy {}) = False
|
|
| 1977 | + go bvs (FunTy _ w arg res) = go bvs w || go bvs arg || go bvs res
|
|
| 1978 | + go bvs (TyConApp tc tys) = go_tc bvs tc tys
|
|
| 1979 | + |
|
| 1980 | + go bvs (ForAllTy (Bndr tv _) ty)
|
|
| 1981 | + = go bvs (tyVarKind tv) ||
|
|
| 1982 | + (case lhs of
|
|
| 1983 | + TyVarLHS tv' | tv==tv' -> False -- Shadowing
|
|
| 1984 | + | otherwise -> go (bvs `extendVarSet` tv) ty
|
|
| 1985 | + TyFamLHS {} -> False) -- Lookups don't happen under a forall
|
|
| 1986 | + |
|
| 1987 | + go bvs (CastTy ty _co) = go bvs ty -- ToDo: should we worry about `co`?
|
|
| 1988 | + go _ (CoercionTy _co) = False -- ToDo: should we worry about `co`?
|
|
| 1989 | + |
|
| 1990 | + go_tc bvs tc tys
|
|
| 1991 | + | isTypeFamilyTyCon tc
|
|
| 1992 | + , Just ty' <- lookupFamEnv fam_env tc (take arity tys)
|
|
| 1993 | + = go bvs ty' || any (go bvs) (drop arity tys)
|
|
| 1994 | + |
|
| 1995 | + | TyFamLHS tc' tys' <- lhs
|
|
| 1996 | + , tc == tc'
|
|
| 1997 | + , tys `lengthAtLeast` arity -- Saturated, or over-saturated
|
|
| 1998 | + , and (zipWith tcEqType tys tys')
|
|
| 1999 | + = True
|
|
| 2000 | + |
|
| 2001 | + | otherwise
|
|
| 2002 | + = any (go bvs) tys
|
|
| 2003 | + where
|
|
| 2004 | + arity = tyConArity tc
|
|
| 1950 | 2005 | |
| 1951 | -{- Note [Unifying coercion-foralls]
|
|
| 1952 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 2006 | +{- Note [The occurs check in the Core unifier]
|
|
| 2007 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 2008 | +The unifier applies both substitutions (um_tv_env and um_fam_env) as it goes,
|
|
| 2009 | +so we'll get an infinite loop if we have, for example
|
|
| 2010 | + um_tv_env: a :-> F b -- (1)
|
|
| 2011 | + um_fam_env F b :-> a -- (2)
|
|
| 2012 | + |
|
| 2013 | +So (uOccursCheck substs lhs ty) returns True iff extending `substs` with `lhs :-> ty`
|
|
| 2014 | +could lead to a loop. That is, could there by a type `s` such that
|
|
| 2015 | + applySubsts( (substs + lhs:->ty), s ) is infinite
|
|
| 2016 | + |
|
| 2017 | +It's vital that we do both at once: we might have (1) already and add (2);
|
|
| 2018 | +or we might have (2) already and add (1).
|
|
| 2019 | + |
|
| 2020 | +Note [Unifying coercion-foralls]
|
|
| 2021 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1953 | 2022 | Suppose we try to unify (forall cv. t1) ~ (forall cv. t2).
|
| 1954 | 2023 | See Note [ForAllTy] in GHC.Core.TyCo.Rep.
|
| 1955 | 2024 |
| ... | ... | @@ -547,15 +547,7 @@ rnHsTyKi env tv@(HsTyVar _ ip (L loc rdr_name)) |
| 547 | 547 | ; this_mod <- getModule
|
| 548 | 548 | ; when (nameIsLocalOrFrom this_mod name) $
|
| 549 | 549 | checkThLocalTyName name
|
| 550 | - ; when (isDataConName name && not (isKindName name)) $
|
|
| 551 | - -- Any use of a promoted data constructor name (that is not
|
|
| 552 | - -- specifically exempted by isKindName) is illegal without the use
|
|
| 553 | - -- of DataKinds. See Note [Checking for DataKinds] in
|
|
| 554 | - -- GHC.Tc.Validity.
|
|
| 555 | - checkDataKinds env tv
|
|
| 556 | - ; when (isDataConName name && not (isPromoted ip)) $
|
|
| 557 | - -- NB: a prefix symbolic operator such as (:) is represented as HsTyVar.
|
|
| 558 | - addDiagnostic (TcRnUntickedPromotedThing $ UntickedConstructor Prefix name)
|
|
| 550 | + ; checkPromotedDataConName env tv Prefix ip name
|
|
| 559 | 551 | ; return (HsTyVar noAnn ip (L loc $ WithUserRdr rdr_name name), unitFV name) }
|
| 560 | 552 | |
| 561 | 553 | rnHsTyKi env ty@(HsOpTy _ prom ty1 l_op ty2)
|
| ... | ... | @@ -567,8 +559,7 @@ rnHsTyKi env ty@(HsOpTy _ prom ty1 l_op ty2) |
| 567 | 559 | ; (ty1', fvs2) <- rnLHsTyKi env ty1
|
| 568 | 560 | ; (ty2', fvs3) <- rnLHsTyKi env ty2
|
| 569 | 561 | ; res_ty <- mkHsOpTyRn prom (fmap (WithUserRdr op_rdr) l_op') fix ty1' ty2'
|
| 570 | - ; when (isDataConName op_name && not (isPromoted prom)) $
|
|
| 571 | - addDiagnostic (TcRnUntickedPromotedThing $ UntickedConstructor Infix op_name)
|
|
| 562 | + ; checkPromotedDataConName env ty Infix prom op_name
|
|
| 572 | 563 | ; return (res_ty, plusFVs [fvs1, fvs2, fvs3]) }
|
| 573 | 564 | |
| 574 | 565 | rnHsTyKi env (HsParTy _ ty)
|
| ... | ... | @@ -1670,6 +1661,30 @@ checkDataKinds env thing |
| 1670 | 1661 | type_or_kind | isRnKindLevel env = KindLevel
|
| 1671 | 1662 | | otherwise = TypeLevel
|
| 1672 | 1663 | |
| 1664 | +-- | If a 'Name' is that of a promoted data constructor, perform various
|
|
| 1665 | +-- validity checks on it.
|
|
| 1666 | +checkPromotedDataConName ::
|
|
| 1667 | + RnTyKiEnv ->
|
|
| 1668 | + -- | The type that the 'Name' belongs to. This will always be an 'HsTyVar'
|
|
| 1669 | + -- (for 'Prefix' names) or an 'HsOpTy' (for 'Infix' names).
|
|
| 1670 | + HsType GhcPs ->
|
|
| 1671 | + -- | Whether the type is written 'Prefix' or 'Infix'.
|
|
| 1672 | + LexicalFixity ->
|
|
| 1673 | + -- | Whether the name was written with an explicit promotion tick or not.
|
|
| 1674 | + PromotionFlag ->
|
|
| 1675 | + -- | The name to check.
|
|
| 1676 | + Name ->
|
|
| 1677 | + TcM ()
|
|
| 1678 | +checkPromotedDataConName env ty fixity ip name
|
|
| 1679 | + = do when (isDataConName name && not (isKindName name)) $
|
|
| 1680 | + -- Any use of a promoted data constructor name (that is not
|
|
| 1681 | + -- specifically exempted by isKindName) is illegal without the use
|
|
| 1682 | + -- of DataKinds. See Note [Checking for DataKinds] in
|
|
| 1683 | + -- GHC.Tc.Validity.
|
|
| 1684 | + checkDataKinds env ty
|
|
| 1685 | + when (isDataConName name && not (isPromoted ip)) $
|
|
| 1686 | + addDiagnostic (TcRnUntickedPromotedThing $ UntickedConstructor fixity name)
|
|
| 1687 | + |
|
| 1673 | 1688 | warnUnusedForAll :: OutputableBndrFlag flag 'Renamed
|
| 1674 | 1689 | => HsDocContext -> LHsTyVarBndr flag GhcRn -> FreeVars -> TcM ()
|
| 1675 | 1690 | warnUnusedForAll doc (L loc tvb) used_names =
|
| ... | ... | @@ -3342,8 +3342,9 @@ mapCheck f xs |
| 3342 | 3342 | -- | Options describing how to deal with a type equality
|
| 3343 | 3343 | -- in the eager unifier. See 'checkTyEqRhs'
|
| 3344 | 3344 | data TyEqFlags m a
|
| 3345 | - -- | LHS is a type family application; we are not unifying.
|
|
| 3346 | - = TEFTyFam
|
|
| 3345 | + = -- | TFTyFam: LHS is a type family application
|
|
| 3346 | + -- Invariant: we are not unifying; see `notUnifying_TEFTask`
|
|
| 3347 | + TEFTyFam
|
|
| 3347 | 3348 | { tefTyFam_occursCheck :: CheckTyEqProblem
|
| 3348 | 3349 | -- ^ The 'CheckTyEqProblem' to report for occurs-check failures
|
| 3349 | 3350 | -- (soluble or insoluble)
|
| ... | ... | @@ -3352,7 +3353,8 @@ data TyEqFlags m a |
| 3352 | 3353 | , tef_fam_app :: TyEqFamApp m a
|
| 3353 | 3354 | -- ^ How to deal with type family applications
|
| 3354 | 3355 | }
|
| 3355 | - -- | LHS is a 'TyVar'.
|
|
| 3356 | + |
|
| 3357 | + -- | TEFTyVar: LHS is a 'TyVar'.
|
|
| 3356 | 3358 | | TEFTyVar
|
| 3357 | 3359 | -- NB: this constructor does not actually store a 'TyVar', in order to
|
| 3358 | 3360 | -- support being called from 'makeTypeConcrete' (which works as if we
|
| ... | ... | @@ -11,6 +11,11 @@ for specific guidance on migrating programs to this release. |
| 11 | 11 | Language
|
| 12 | 12 | ~~~~~~~~
|
| 13 | 13 | |
| 14 | +- Fix a bug introduced in GHC 9.10 where GHC would erroneously accept infix uses
|
|
| 15 | + of promoted data constructors without enabling :extension:`DataKinds`. As a
|
|
| 16 | + result, you may need to enable :extension:`DataKinds` in code that did not
|
|
| 17 | + previously require it.
|
|
| 18 | + |
|
| 14 | 19 | Compiler
|
| 15 | 20 | ~~~~~~~~
|
| 16 | 21 |
| ... | ... | @@ -1211,27 +1211,16 @@ INFO_TABLE_RET(stg_catch_retry_frame, CATCH_RETRY_FRAME, |
| 1211 | 1211 | gcptr trec, outer, arg;
|
| 1212 | 1212 | |
| 1213 | 1213 | trec = StgTSO_trec(CurrentTSO);
|
| 1214 | - if (running_alt_code != 1) {
|
|
| 1215 | - // When exiting the lhs code of catchRetry# lhs rhs, we need to cleanup
|
|
| 1216 | - // the nested transaction.
|
|
| 1217 | - // See Note [catchRetry# implementation]
|
|
| 1218 | - outer = StgTRecHeader_enclosing_trec(trec);
|
|
| 1219 | - (r) = ccall stmCommitNestedTransaction(MyCapability() "ptr", trec "ptr");
|
|
| 1220 | - if (r != 0) {
|
|
| 1221 | - // Succeeded in first branch
|
|
| 1222 | - StgTSO_trec(CurrentTSO) = outer;
|
|
| 1223 | - return (ret);
|
|
| 1224 | - } else {
|
|
| 1225 | - // Did not commit: abort and restart.
|
|
| 1226 | - StgTSO_trec(CurrentTSO) = outer;
|
|
| 1227 | - jump stg_abort();
|
|
| 1228 | - }
|
|
| 1229 | - }
|
|
| 1230 | - else {
|
|
| 1231 | - // nothing to do in the rhs code of catchRetry# lhs rhs, it's already
|
|
| 1232 | - // using the parent transaction (not a nested one).
|
|
| 1233 | - // See Note [catchRetry# implementation]
|
|
| 1234 | - return (ret);
|
|
| 1214 | + outer = StgTRecHeader_enclosing_trec(trec);
|
|
| 1215 | + (r) = ccall stmCommitNestedTransaction(MyCapability() "ptr", trec "ptr");
|
|
| 1216 | + if (r != 0) {
|
|
| 1217 | + // Succeeded (either first branch or second branch)
|
|
| 1218 | + StgTSO_trec(CurrentTSO) = outer;
|
|
| 1219 | + return (ret);
|
|
| 1220 | + } else {
|
|
| 1221 | + // Did not commit: abort and restart.
|
|
| 1222 | + StgTSO_trec(CurrentTSO) = outer;
|
|
| 1223 | + jump stg_abort();
|
|
| 1235 | 1224 | }
|
| 1236 | 1225 | }
|
| 1237 | 1226 | |
| ... | ... | @@ -1464,26 +1453,21 @@ retry_pop_stack: |
| 1464 | 1453 | outer = StgTRecHeader_enclosing_trec(trec);
|
| 1465 | 1454 | |
| 1466 | 1455 | if (frame_type == CATCH_RETRY_FRAME) {
|
| 1467 | - // The retry reaches a CATCH_RETRY_FRAME before the ATOMICALLY_FRAME
|
|
| 1468 | - |
|
| 1456 | + // The retry reaches a CATCH_RETRY_FRAME before the atomic frame
|
|
| 1457 | + ASSERT(outer != NO_TREC);
|
|
| 1458 | + // Abort the transaction attempting the current branch
|
|
| 1459 | + ccall stmAbortTransaction(MyCapability() "ptr", trec "ptr");
|
|
| 1460 | + ccall stmFreeAbortedTRec(MyCapability() "ptr", trec "ptr");
|
|
| 1469 | 1461 | if (!StgCatchRetryFrame_running_alt_code(frame) != 0) {
|
| 1470 | - // Retrying in the lhs of catchRetry# lhs rhs, i.e. in a nested
|
|
| 1471 | - // transaction. See Note [catchRetry# implementation]
|
|
| 1472 | - |
|
| 1473 | - // check that we have a parent transaction
|
|
| 1474 | - ASSERT(outer != NO_TREC);
|
|
| 1475 | - |
|
| 1476 | - // Abort the nested transaction
|
|
| 1477 | - ccall stmAbortTransaction(MyCapability() "ptr", trec "ptr");
|
|
| 1478 | - ccall stmFreeAbortedTRec(MyCapability() "ptr", trec "ptr");
|
|
| 1479 | - |
|
| 1480 | - // As we are retrying in the lhs code, we must now try the rhs code
|
|
| 1481 | - StgTSO_trec(CurrentTSO) = outer;
|
|
| 1462 | + // Retry in the first branch: try the alternative
|
|
| 1463 | + ("ptr" trec) = ccall stmStartTransaction(MyCapability() "ptr", outer "ptr");
|
|
| 1464 | + StgTSO_trec(CurrentTSO) = trec;
|
|
| 1482 | 1465 | StgCatchRetryFrame_running_alt_code(frame) = 1 :: CInt; // true;
|
| 1483 | 1466 | R1 = StgCatchRetryFrame_alt_code(frame);
|
| 1484 | 1467 | jump stg_ap_v_fast [R1];
|
| 1485 | 1468 | } else {
|
| 1486 | - // Retry in the rhs code: propagate the retry
|
|
| 1469 | + // Retry in the alternative code: propagate the retry
|
|
| 1470 | + StgTSO_trec(CurrentTSO) = outer;
|
|
| 1487 | 1471 | Sp = Sp + SIZEOF_StgCatchRetryFrame;
|
| 1488 | 1472 | goto retry_pop_stack;
|
| 1489 | 1473 | }
|
| ... | ... | @@ -1043,7 +1043,8 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, |
| 1043 | 1043 | }
|
| 1044 | 1044 | |
| 1045 | 1045 | case CATCH_STM_FRAME:
|
| 1046 | - // CATCH_STM frame within an atomically block: abort the
|
|
| 1046 | + case CATCH_RETRY_FRAME:
|
|
| 1047 | + // CATCH frames within an atomically block: abort the
|
|
| 1047 | 1048 | // inner transaction and continue. Eventually we will
|
| 1048 | 1049 | // hit the outer transaction that will get frozen (see
|
| 1049 | 1050 | // above).
|
| ... | ... | @@ -1055,40 +1056,14 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, |
| 1055 | 1056 | {
|
| 1056 | 1057 | StgTRecHeader *trec = tso -> trec;
|
| 1057 | 1058 | StgTRecHeader *outer = trec -> enclosing_trec;
|
| 1058 | - debugTraceCap(DEBUG_stm, cap, "raiseAsync: traversing CATCH_STM frame");
|
|
| 1059 | + debugTraceCap(DEBUG_stm, cap,
|
|
| 1060 | + "found atomically block delivering async exception");
|
|
| 1059 | 1061 | stmAbortTransaction(cap, trec);
|
| 1060 | 1062 | stmFreeAbortedTRec(cap, trec);
|
| 1061 | 1063 | tso -> trec = outer;
|
| 1062 | 1064 | break;
|
| 1063 | 1065 | };
|
| 1064 | 1066 | |
| 1065 | - case CATCH_RETRY_FRAME:
|
|
| 1066 | - // CATCH_RETY frame within an atomically block: if we're executing
|
|
| 1067 | - // the lhs code, abort the inner transaction and continue; if we're
|
|
| 1068 | - // executing thr rhs, continue (no nested transaction to abort. See
|
|
| 1069 | - // Note [catchRetry# implementation]). Eventually we will hit the
|
|
| 1070 | - // outer transaction that will get frozen (see above).
|
|
| 1071 | - //
|
|
| 1072 | - // As for the CATCH_STM_FRAME case above, we do not care
|
|
| 1073 | - // whether the transaction is valid or not because its
|
|
| 1074 | - // possible validity cannot have caused the exception
|
|
| 1075 | - // and will not be visible after the abort.
|
|
| 1076 | - {
|
|
| 1077 | - if (!((StgCatchRetryFrame *)frame) -> running_alt_code) {
|
|
| 1078 | - debugTraceCap(DEBUG_stm, cap, "raiseAsync: traversing CATCH_RETRY frame (lhs)");
|
|
| 1079 | - StgTRecHeader *trec = tso -> trec;
|
|
| 1080 | - StgTRecHeader *outer = trec -> enclosing_trec;
|
|
| 1081 | - stmAbortTransaction(cap, trec);
|
|
| 1082 | - stmFreeAbortedTRec(cap, trec);
|
|
| 1083 | - tso -> trec = outer;
|
|
| 1084 | - }
|
|
| 1085 | - else
|
|
| 1086 | - {
|
|
| 1087 | - debugTraceCap(DEBUG_stm, cap, "raiseAsync: traversing CATCH_RETRY frame (rhs)");
|
|
| 1088 | - }
|
|
| 1089 | - break;
|
|
| 1090 | - };
|
|
| 1091 | - |
|
| 1092 | 1067 | default:
|
| 1093 | 1068 | // see Note [Update async masking state on unwind] in Schedule.c
|
| 1094 | 1069 | if (*frame == (W_)&stg_unmaskAsyncExceptionszh_ret_info) {
|
| ... | ... | @@ -1505,30 +1505,3 @@ void stmWriteTVar(Capability *cap, |
| 1505 | 1505 | }
|
| 1506 | 1506 | |
| 1507 | 1507 | /*......................................................................*/ |
| 1508 | - |
|
| 1509 | - |
|
| 1510 | - |
|
| 1511 | -/*
|
|
| 1512 | - |
|
| 1513 | -Note [catchRetry# implementation]
|
|
| 1514 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 1515 | -catchRetry# creates a nested transaction for its lhs:
|
|
| 1516 | -- if the lhs transaction succeeds:
|
|
| 1517 | - - the lhs transaction is committed
|
|
| 1518 | - - its read-variables are merged with those of the parent transaction
|
|
| 1519 | - - the rhs code is ignored
|
|
| 1520 | -- if the lhs transaction retries:
|
|
| 1521 | - - the lhs transaction is aborted
|
|
| 1522 | - - its read-variables are merged with those of the parent transaction
|
|
| 1523 | - - the rhs code is executed directly in the parent transaction (see #26028).
|
|
| 1524 | - |
|
| 1525 | -So note that:
|
|
| 1526 | -- lhs code uses a nested transaction
|
|
| 1527 | -- rhs code doesn't use a nested transaction
|
|
| 1528 | - |
|
| 1529 | -We have to take which case we're in into account (using the running_alt_code
|
|
| 1530 | -field of the catchRetry frame) in catchRetry's entry code, in retry#
|
|
| 1531 | -implementation, and also when an async exception is received (to cleanup the
|
|
| 1532 | -right number of transactions).
|
|
| 1533 | - |
|
| 1534 | -*/ |
| 1 | -module Main where
|
|
| 2 | - |
|
| 3 | -import GHC.Conc
|
|
| 4 | - |
|
| 5 | -forever :: IO String
|
|
| 6 | -forever = delay 10 >> forever
|
|
| 7 | - |
|
| 8 | -terminates :: IO String
|
|
| 9 | -terminates = delay 1 >> pure "terminates"
|
|
| 10 | - |
|
| 11 | -delay s = threadDelay (1000000 * s)
|
|
| 12 | - |
|
| 13 | -async :: IO a -> IO (STM a)
|
|
| 14 | -async a = do
|
|
| 15 | - var <- atomically (newTVar Nothing)
|
|
| 16 | - forkIO (a >>= atomically . writeTVar var . Just)
|
|
| 17 | - pure (readTVar var >>= maybe retry pure)
|
|
| 18 | - |
|
| 19 | -main :: IO ()
|
|
| 20 | -main = do
|
|
| 21 | - x <- mapM async $ terminates : replicate 50000 forever
|
|
| 22 | - r <- atomically (foldr1 orElse x)
|
|
| 23 | - print r |
| 1 | -"terminates" |
| 1 | -test('T26028', only_ways(['threaded1']), compile_and_run, ['-O2']) |
| 1 | +{-# LANGUAGE GHC2024 #-}
|
|
| 2 | +{-# LANGUAGE TypeFamilies #-}
|
|
| 3 | +{-# LANGUAGE UndecidableInstances #-}
|
|
| 4 | +module T26346 (warble) where
|
|
| 5 | + |
|
| 6 | +import Data.Kind (Type)
|
|
| 7 | +import Data.Type.Equality ((:~:)(..))
|
|
| 8 | + |
|
| 9 | +type Nat :: Type
|
|
| 10 | +data Nat = Z | S Nat
|
|
| 11 | + |
|
| 12 | +type SNat :: Nat -> Type
|
|
| 13 | +data SNat n where
|
|
| 14 | + SZ :: SNat Z
|
|
| 15 | + SS :: SNat n -> SNat (S n)
|
|
| 16 | + |
|
| 17 | +type NatPlus :: Nat -> Nat -> Nat
|
|
| 18 | +type family NatPlus a b where
|
|
| 19 | + NatPlus Z b = b
|
|
| 20 | + NatPlus (S a) b = S (NatPlus a b)
|
|
| 21 | + |
|
| 22 | +sNatPlus ::
|
|
| 23 | + forall (a :: Nat) (b :: Nat).
|
|
| 24 | + SNat a ->
|
|
| 25 | + SNat b ->
|
|
| 26 | + SNat (NatPlus a b)
|
|
| 27 | +sNatPlus SZ b = b
|
|
| 28 | +sNatPlus (SS a) b = SS (sNatPlus a b)
|
|
| 29 | + |
|
| 30 | +data Bin
|
|
| 31 | + = Zero
|
|
| 32 | + | Even Bin
|
|
| 33 | + | Odd Bin
|
|
| 34 | + |
|
| 35 | +type SBin :: Bin -> Type
|
|
| 36 | +data SBin b where
|
|
| 37 | + SZero :: SBin Zero
|
|
| 38 | + SEven :: SBin n -> SBin (Even n)
|
|
| 39 | + SOdd :: SBin n -> SBin (Odd n)
|
|
| 40 | + |
|
| 41 | +type Incr :: Bin -> Bin
|
|
| 42 | +type family Incr b where
|
|
| 43 | + Incr Zero = Odd Zero -- 0 + 1 = (2*0) + 1
|
|
| 44 | + Incr (Even n) = Odd n -- 2n + 1
|
|
| 45 | + Incr (Odd n) = Even (Incr n) -- (2n + 1) + 1 = 2*(n + 1)
|
|
| 46 | + |
|
| 47 | +type BinToNat :: Bin -> Nat
|
|
| 48 | +type family BinToNat b where
|
|
| 49 | + BinToNat Zero = Z
|
|
| 50 | + BinToNat (Even n) = NatPlus (BinToNat n) (BinToNat n)
|
|
| 51 | + BinToNat (Odd n) = S (NatPlus (BinToNat n) (BinToNat n))
|
|
| 52 | + |
|
| 53 | +sBinToNat ::
|
|
| 54 | + forall (b :: Bin).
|
|
| 55 | + SBin b ->
|
|
| 56 | + SNat (BinToNat b)
|
|
| 57 | +sBinToNat SZero = SZ
|
|
| 58 | +sBinToNat (SEven n) = sNatPlus (sBinToNat n) (sBinToNat n)
|
|
| 59 | +sBinToNat (SOdd n) = SS (sNatPlus (sBinToNat n) (sBinToNat n))
|
|
| 60 | + |
|
| 61 | +warble ::
|
|
| 62 | + forall (b :: Bin).
|
|
| 63 | + SBin b ->
|
|
| 64 | + BinToNat (Incr b) :~: S (BinToNat b)
|
|
| 65 | +warble SZero = Refl
|
|
| 66 | +warble (SEven {}) = Refl
|
|
| 67 | +warble (SOdd sb) | Refl <- warble sb
|
|
| 68 | + , Refl <- plusComm sbn (SS sbn)
|
|
| 69 | + = Refl
|
|
| 70 | + where
|
|
| 71 | + sbn = sBinToNat sb
|
|
| 72 | + |
|
| 73 | + plus0R ::
|
|
| 74 | + forall (n :: Nat).
|
|
| 75 | + SNat n ->
|
|
| 76 | + NatPlus n Z :~: n
|
|
| 77 | + plus0R SZ = Refl
|
|
| 78 | + plus0R (SS sn)
|
|
| 79 | + | Refl <- plus0R sn
|
|
| 80 | + = Refl
|
|
| 81 | + |
|
| 82 | + plusSnR ::
|
|
| 83 | + forall (n :: Nat) (m :: Nat).
|
|
| 84 | + SNat n ->
|
|
| 85 | + SNat m ->
|
|
| 86 | + NatPlus n (S m) :~: S (NatPlus n m)
|
|
| 87 | + plusSnR SZ _ = Refl
|
|
| 88 | + plusSnR (SS sn) sm
|
|
| 89 | + | Refl <- plusSnR sn sm
|
|
| 90 | + = Refl
|
|
| 91 | + |
|
| 92 | + plusComm ::
|
|
| 93 | + forall (n :: Nat) (m :: Nat).
|
|
| 94 | + SNat n ->
|
|
| 95 | + SNat m ->
|
|
| 96 | + NatPlus n m :~: NatPlus m n
|
|
| 97 | + plusComm SZ sm
|
|
| 98 | + | Refl <- plus0R sm
|
|
| 99 | + = Refl
|
|
| 100 | + plusComm (SS sn) sm
|
|
| 101 | + | Refl <- plusComm sn sm
|
|
| 102 | + , Refl <- plusSnR sm sn
|
|
| 103 | + = Refl |
| ... | ... | @@ -945,3 +945,4 @@ test('T25992', normal, compile, ['']) |
| 945 | 945 | test('T14010', normal, compile, [''])
|
| 946 | 946 | test('T26256a', normal, compile, [''])
|
| 947 | 947 | test('T25992a', normal, compile, [''])
|
| 948 | +test('T26346', normal, compile, ['']) |
| 1 | +{-# LANGUAGE GHC2021 #-}
|
|
| 2 | +{-# LANGUAGE NoDataKinds #-}
|
|
| 3 | +module T26318 where
|
|
| 4 | + |
|
| 5 | +class C1 l
|
|
| 6 | +instance C1 (x : xs)
|
|
| 7 | + |
|
| 8 | +class C2 l
|
|
| 9 | +instance C2 (x ': xs)
|
|
| 10 | + |
|
| 11 | +class C3 l
|
|
| 12 | +instance C3 ((:) x xs)
|
|
| 13 | + |
|
| 14 | +class C4 l
|
|
| 15 | +instance C4 ('(:) x xs) |
| 1 | +T26318.hs:6:16: error: [GHC-68567]
|
|
| 2 | + Illegal type: ‘x : xs’
|
|
| 3 | + Suggested fix:
|
|
| 4 | + Perhaps you intended to use the ‘DataKinds’ extension (implied by ‘UnliftedDatatypes’)
|
|
| 5 | + |
|
| 6 | +T26318.hs:9:16: error: [GHC-68567]
|
|
| 7 | + Illegal type: ‘x ': xs’
|
|
| 8 | + Suggested fix:
|
|
| 9 | + Perhaps you intended to use the ‘DataKinds’ extension (implied by ‘UnliftedDatatypes’)
|
|
| 10 | + |
|
| 11 | +T26318.hs:12:14: error: [GHC-68567]
|
|
| 12 | + Illegal type: ‘(:)’
|
|
| 13 | + Suggested fix:
|
|
| 14 | + Perhaps you intended to use the ‘DataKinds’ extension (implied by ‘UnliftedDatatypes’)
|
|
| 15 | + |
|
| 16 | +T26318.hs:15:14: error: [GHC-68567]
|
|
| 17 | + Illegal type: ‘'(:)’
|
|
| 18 | + Suggested fix:
|
|
| 19 | + Perhaps you intended to use the ‘DataKinds’ extension (implied by ‘UnliftedDatatypes’)
|
|
| 20 | + |
| ... | ... | @@ -741,3 +741,4 @@ test('T25325', normal, compile_fail, ['']) |
| 741 | 741 | test('T25004', normal, compile_fail, [''])
|
| 742 | 742 | test('T25004k', normal, compile_fail, [''])
|
| 743 | 743 | test('T26004', normal, compile_fail, [''])
|
| 744 | +test('T26318', normal, compile_fail, ['']) |
| ... | ... | @@ -1105,6 +1105,20 @@ class DyLD { |
| 1105 | 1105 | if (/libHSghc-internal-\d+(\.\d+)*/i.test(soname)) {
|
| 1106 | 1106 | this.rts_init();
|
| 1107 | 1107 | delete this.rts_init;
|
| 1108 | + |
|
| 1109 | + // At this point the RTS symbols in linear memory are fixed
|
|
| 1110 | + // and constructors are run, especially the one in JSFFI.c
|
|
| 1111 | + // that does GHC RTS initialization for any code that links
|
|
| 1112 | + // JSFFI.o. Luckily no Haskell computation or gc has taken
|
|
| 1113 | + // place yet, so we must set keepCAFs=1 right now! Otherwise,
|
|
| 1114 | + // any BCO created by later TH splice or ghci expression may
|
|
| 1115 | + // refer to any CAF that's not reachable from GC roots (here
|
|
| 1116 | + // our only entry point is defaultServer) and the CAF could
|
|
| 1117 | + // have been GC'ed! (#26106)
|
|
| 1118 | + //
|
|
| 1119 | + // We call it here instead of in RTS C code, since we only
|
|
| 1120 | + // want keepCAFs=1 for ghci, not user code.
|
|
| 1121 | + this.exportFuncs.setKeepCAFs();
|
|
| 1108 | 1122 | }
|
| 1109 | 1123 | init();
|
| 1110 | 1124 | }
|