Marge Bot pushed to branch wip/marge_bot_batch_merge_job at Glasgow Haskell Compiler / GHC
Commits:
-
a00840ea
by Simon Peyton Jones at 2025-11-14T15:23:56+00:00
-
b674971c
by Georgios Karachalias at 2025-11-14T20:12:40-05:00
-
23c9ebc9
by Sylvain Henry at 2025-11-14T20:13:08-05:00
-
d43cc50d
by Sylvain Henry at 2025-11-14T20:13:08-05:00
25 changed files:
- compiler/GHC/Builtin/Types/Prim.hs
- compiler/GHC/Core/Coercion.hs
- compiler/GHC/Core/Lint.hs
- compiler/GHC/Core/RoughMap.hs
- compiler/GHC/Core/Type.hs
- compiler/GHC/Core/Unify.hs
- compiler/GHC/Driver/MakeFile.hs
- compiler/GHC/StgToJS/Apply.hs
- compiler/GHC/StgToJS/Expr.hs
- compiler/GHC/StgToJS/Regs.hs
- compiler/GHC/StgToJS/Rts/Rts.hs
- compiler/GHC/StgToJS/Rts/Types.hs
- compiler/GHC/Tc/Instance/Class.hs
- docs/users_guide/9.16.1-notes.rst
- testsuite/tests/codeGen/should_run/all.T
- testsuite/tests/driver/Makefile
- + testsuite/tests/driver/T26551.hs
- + testsuite/tests/driver/T26551.stderr
- testsuite/tests/driver/all.T
- testsuite/tests/indexed-types/should_fail/T21092.hs
- − testsuite/tests/indexed-types/should_fail/T21092.stderr
- testsuite/tests/indexed-types/should_fail/all.T
- testsuite/tests/typecheck/should_fail/T24279.hs
- − testsuite/tests/typecheck/should_fail/T24279.stderr
- testsuite/tests/typecheck/should_fail/all.T
Changes:
| ... | ... | @@ -752,8 +752,9 @@ Specifically (a ~# b) :: CONSTRAINT (TupleRep []) |
| 752 | 752 | |
| 753 | 753 | Wrinkles
|
| 754 | 754 | |
| 755 | -(W1) Type and Constraint are considered distinct throughout GHC. But they
|
|
| 756 | - are not /apart/: see Note [Type and Constraint are not apart]
|
|
| 755 | +(W1) Type and Constraint are considered distinct throughout GHC.
|
|
| 756 | + That wasn't always the case:
|
|
| 757 | + see Historical Note [Type and Constraint are not apart]
|
|
| 757 | 758 | |
| 758 | 759 | (W2) We need two absent-error Ids, aBSENT_ERROR_ID for types of kind Type, and
|
| 759 | 760 | aBSENT_CONSTRAINT_ERROR_ID for types of kind Constraint.
|
| ... | ... | @@ -768,8 +769,24 @@ Wrinkles |
| 768 | 769 | of type TYPE rr. See (CPR2) in Note [Which types are unboxed?] in
|
| 769 | 770 | GHC.Core.Opt.WorkWrap.Utils.
|
| 770 | 771 | |
| 771 | -Note [Type and Constraint are not apart]
|
|
| 772 | -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 772 | +-------------------------------------------------------------
|
|
| 773 | +Historical Note [Type and Constraint are not apart]
|
|
| 774 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 775 | +Nov 2025:
|
|
| 776 | + In the past, Type and Constraint were carefully coonsiderd to be
|
|
| 777 | + not /apart/. But the necessity for that vanished with unary classes
|
|
| 778 | + (see Note [Unary class magic]), done in
|
|
| 779 | + |
|
| 780 | + commit 9bd7fcc518111a1549c98720c222cdbabd32ed46
|
|
| 781 | + Author: Simon Peyton Jones <simon.peytonjones@gmail.com>
|
|
| 782 | + Date: Tue Apr 15 17:43:46 2025 +0100
|
|
| 783 | + Implement unary classes
|
|
| 784 | + |
|
| 785 | + So now Type and Constraint are simply distinct type constructors, just as
|
|
| 786 | + much as Int and Bool.
|
|
| 787 | + |
|
| 788 | + The rest of this Note is preserved for historical interest.
|
|
| 789 | + |
|
| 773 | 790 | Type and Constraint are not equal (eqType) but they are not /apart/
|
| 774 | 791 | either. Reason (c.f. #7451):
|
| 775 | 792 | |
| ... | ... | @@ -841,6 +858,9 @@ Wrinkles |
| 841 | 858 | So in GHC.Tc.Instance.Class.matchTypeable, Type and Constraint are
|
| 842 | 859 | treated as separate TyCons; i.e. given no special treatment.
|
| 843 | 860 | |
| 861 | +End of Historical Note
|
|
| 862 | +-------------------------------------------------------------
|
|
| 863 | + |
|
| 844 | 864 | Note [RuntimeRep polymorphism]
|
| 845 | 865 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
| 846 | 866 | Generally speaking, you can't be polymorphic in `RuntimeRep`. E.g
|
| ... | ... | @@ -641,11 +641,6 @@ eqTyConRole tc |
| 641 | 641 | |
| 642 | 642 | -- | Given a coercion `co :: (t1 :: TYPE r1) ~ (t2 :: TYPE r2)`
|
| 643 | 643 | -- produce a coercion `rep_co :: r1 ~ r2`
|
| 644 | --- But actually it is possible that
|
|
| 645 | --- co :: (t1 :: CONSTRAINT r1) ~ (t2 :: CONSTRAINT r2)
|
|
| 646 | --- or co :: (t1 :: TYPE r1) ~ (t2 :: CONSTRAINT r2)
|
|
| 647 | --- or co :: (t1 :: CONSTRAINT r1) ~ (t2 :: TYPE r2)
|
|
| 648 | --- See Note [mkRuntimeRepCo]
|
|
| 649 | 644 | mkRuntimeRepCo :: HasDebugCallStack => Coercion -> Coercion
|
| 650 | 645 | mkRuntimeRepCo co
|
| 651 | 646 | = assert (isTYPEorCONSTRAINT k1 && isTYPEorCONSTRAINT k2) $
|
| ... | ... | @@ -654,26 +649,6 @@ mkRuntimeRepCo co |
| 654 | 649 | kind_co = mkKindCo co -- kind_co :: TYPE r1 ~ TYPE r2
|
| 655 | 650 | Pair k1 k2 = coercionKind kind_co
|
| 656 | 651 | |
| 657 | -{- Note [mkRuntimeRepCo]
|
|
| 658 | -~~~~~~~~~~~~~~~~~~~~~~~~
|
|
| 659 | -Given
|
|
| 660 | - class C a where { op :: Maybe a }
|
|
| 661 | -we will get an axiom
|
|
| 662 | - axC a :: (C a :: CONSTRAINT r1) ~ (Maybe a :: TYPE r2)
|
|
| 663 | -(See Note [Type and Constraint are not apart] in GHC.Builtin.Types.Prim.)
|
|
| 664 | - |
|
| 665 | -Then we may call mkRuntimeRepCo on (axC ty), and that will return
|
|
| 666 | - mkSelCo (SelTyCon 0 Nominal) (Kind (axC ty)) :: r1 ~ r2
|
|
| 667 | - |
|
| 668 | -So mkSelCo needs to be happy with decomposing a coercion of kind
|
|
| 669 | - CONSTRAINT r1 ~ TYPE r2
|
|
| 670 | - |
|
| 671 | -Hence the use of `tyConIsTYPEorCONSTRAINT` in the assertion `good_call`
|
|
| 672 | -in `mkSelCo`. See #23018 for a concrete example. (In this context it's
|
|
| 673 | -important that TYPE and CONSTRAINT have the same arity and kind, not
|
|
| 674 | -merely that they are not-apart; otherwise SelCo would not make sense.)
|
|
| 675 | --}
|
|
| 676 | - |
|
| 677 | 652 | isReflCoVar_maybe :: Var -> Maybe Coercion
|
| 678 | 653 | -- If cv :: t~t then isReflCoVar_maybe cv = Just (Refl t)
|
| 679 | 654 | -- Works on all kinds of Vars, not just CoVars
|
| ... | ... | @@ -1305,8 +1280,7 @@ mkSelCo_maybe cs co |
| 1305 | 1280 | , Just (tc2, tys2) <- splitTyConApp_maybe ty2
|
| 1306 | 1281 | , let { len1 = length tys1
|
| 1307 | 1282 | ; len2 = length tys2 }
|
| 1308 | - = (tc1 == tc2 || (tyConIsTYPEorCONSTRAINT tc1 && tyConIsTYPEorCONSTRAINT tc2))
|
|
| 1309 | - -- tyConIsTYPEorCONSTRAINT: see Note [mkRuntimeRepCo]
|
|
| 1283 | + = tc1 == tc2
|
|
| 1310 | 1284 | && len1 == len2
|
| 1311 | 1285 | && n < len1
|
| 1312 | 1286 | && r == tyConRole (coercionRole co) tc1 n
|
| ... | ... | @@ -2891,13 +2891,9 @@ lint_branch ax_tc (CoAxBranch { cab_tvs = tvs, cab_cvs = cvs |
| 2891 | 2891 | hang (text "Inhomogeneous axiom")
|
| 2892 | 2892 | 2 (text "lhs:" <+> ppr lhs <+> dcolon <+> ppr lhs_kind $$
|
| 2893 | 2893 | text "rhs:" <+> ppr rhs <+> dcolon <+> ppr rhs_kind) }
|
| 2894 | - -- Type and Constraint are not Apart, so this test allows
|
|
| 2895 | - -- the newtype axiom for a single-method class. Indeed the
|
|
| 2896 | - -- whole reason Type and Constraint are not Apart is to allow
|
|
| 2897 | - -- such axioms!
|
|
| 2898 | 2894 | |
| 2899 | --- these checks do not apply to newtype axioms
|
|
| 2900 | 2895 | lint_family_branch :: TyCon -> CoAxBranch -> LintM ()
|
| 2896 | +-- These checks do not apply to newtype axioms
|
|
| 2901 | 2897 | lint_family_branch fam_tc br@(CoAxBranch { cab_tvs = tvs
|
| 2902 | 2898 | , cab_eta_tvs = eta_tvs
|
| 2903 | 2899 | , cab_cvs = cvs
|
| ... | ... | @@ -36,7 +36,6 @@ import GHC.Core.Type |
| 36 | 36 | import GHC.Utils.Outputable
|
| 37 | 37 | import GHC.Types.Name
|
| 38 | 38 | import GHC.Types.Name.Env
|
| 39 | -import GHC.Builtin.Types.Prim( cONSTRAINTTyConName, tYPETyConName )
|
|
| 40 | 39 | |
| 41 | 40 | import Control.Monad (join)
|
| 42 | 41 | import Data.Data (Data)
|
| ... | ... | @@ -347,16 +346,7 @@ typeToRoughMatchTc ty |
| 347 | 346 | |
| 348 | 347 | roughMatchTyConName :: TyCon -> Name
|
| 349 | 348 | roughMatchTyConName tc
|
| 350 | - | tc_name == cONSTRAINTTyConName
|
|
| 351 | - = tYPETyConName -- TYPE and CONSTRAINT are not apart, so they must use
|
|
| 352 | - -- the same rough-map key. We arbitrarily use TYPE.
|
|
| 353 | - -- See Note [Type and Constraint are not apart]
|
|
| 354 | - -- wrinkle (W1) in GHC.Builtin.Types.Prim
|
|
| 355 | - | otherwise
|
|
| 356 | - = assertPpr (isGenerativeTyCon tc Nominal) (ppr tc) tc_name
|
|
| 357 | - where
|
|
| 358 | - tc_name = tyConName tc
|
|
| 359 | - |
|
| 349 | + = assertPpr (isGenerativeTyCon tc Nominal) (ppr tc) (tyConName tc)
|
|
| 360 | 350 | |
| 361 | 351 | -- | Trie of @[RoughMatchTc]@
|
| 362 | 352 | --
|
| ... | ... | @@ -1421,8 +1421,6 @@ piResultTy ty arg = case piResultTy_maybe ty arg of |
| 1421 | 1421 | Nothing -> pprPanic "piResultTy" (ppr ty $$ ppr arg)
|
| 1422 | 1422 | |
| 1423 | 1423 | piResultTy_maybe :: Type -> Type -> Maybe Type
|
| 1424 | --- We don't need a 'tc' version, because
|
|
| 1425 | --- this function behaves the same for Type and Constraint
|
|
| 1426 | 1424 | piResultTy_maybe ty arg = case coreFullView ty of
|
| 1427 | 1425 | FunTy { ft_res = res } -> Just res
|
| 1428 | 1426 |
| ... | ... | @@ -27,7 +27,6 @@ import GHC.Prelude |
| 27 | 27 | import GHC.Types.Var
|
| 28 | 28 | import GHC.Types.Var.Env
|
| 29 | 29 | import GHC.Types.Var.Set
|
| 30 | -import GHC.Builtin.Names( tYPETyConKey, cONSTRAINTTyConKey )
|
|
| 31 | 30 | import GHC.Core.Type hiding ( getTvSubstEnv )
|
| 32 | 31 | import GHC.Core.Coercion hiding ( getCvSubstEnv )
|
| 33 | 32 | import GHC.Core.Predicate( scopedSort )
|
| ... | ... | @@ -98,8 +97,6 @@ of ways. Here we summarise, but see Note [Specification of unification]. |
| 98 | 97 | See Note [Apartness and type families]
|
| 99 | 98 | * MARInfinite (occurs check):
|
| 100 | 99 | See Note [Infinitary substitutions]
|
| 101 | - * MARTypeVsConstraint:
|
|
| 102 | - See Note [Type and Constraint are not apart] in GHC.Builtin.Types.Prim
|
|
| 103 | 100 | * MARCast (obscure):
|
| 104 | 101 | See (KCU2) in Note [Kind coercions in Unify]
|
| 105 | 102 | |
| ... | ... | @@ -997,16 +994,12 @@ data UnifyResultM a = Unifiable a -- the subst that unifies the types |
| 997 | 994 | |
| 998 | 995 | -- | Why are two types 'MaybeApart'? 'MARInfinite' takes precedence:
|
| 999 | 996 | -- This is used (only) in Note [Infinitary substitution in lookup] in GHC.Core.InstEnv
|
| 1000 | --- As of Feb 2022, we never differentiate between MARTypeFamily and MARTypeVsConstraint;
|
|
| 1001 | --- it's really only MARInfinite that's interesting here.
|
|
| 997 | +-- It's really only MARInfinite that's interesting here.
|
|
| 1002 | 998 | data MaybeApartReason
|
| 1003 | 999 | = MARTypeFamily -- ^ matching e.g. F Int ~? Bool
|
| 1004 | 1000 | |
| 1005 | 1001 | | MARInfinite -- ^ matching e.g. a ~? Maybe a
|
| 1006 | 1002 | |
| 1007 | - | MARTypeVsConstraint -- ^ matching Type ~? Constraint or the arrow types
|
|
| 1008 | - -- See Note [Type and Constraint are not apart] in GHC.Builtin.Types.Prim
|
|
| 1009 | - |
|
| 1010 | 1003 | | MARCast -- ^ Very obscure.
|
| 1011 | 1004 | -- See (KCU2) in Note [Kind coercions in Unify]
|
| 1012 | 1005 | |
| ... | ... | @@ -1015,13 +1008,11 @@ combineMAR :: MaybeApartReason -> MaybeApartReason -> MaybeApartReason |
| 1015 | 1008 | -- See (UR1) in Note [Unification result] for why MARInfinite wins
|
| 1016 | 1009 | combineMAR MARInfinite _ = MARInfinite -- MARInfinite wins
|
| 1017 | 1010 | combineMAR MARTypeFamily r = r -- Otherwise it doesn't really matter
|
| 1018 | -combineMAR MARTypeVsConstraint r = r
|
|
| 1019 | 1011 | combineMAR MARCast r = r
|
| 1020 | 1012 | |
| 1021 | 1013 | instance Outputable MaybeApartReason where
|
| 1022 | 1014 | ppr MARTypeFamily = text "MARTypeFamily"
|
| 1023 | 1015 | ppr MARInfinite = text "MARInfinite"
|
| 1024 | - ppr MARTypeVsConstraint = text "MARTypeVsConstraint"
|
|
| 1025 | 1016 | ppr MARCast = text "MARCast"
|
| 1026 | 1017 | |
| 1027 | 1018 | instance Semigroup MaybeApartReason where
|
| ... | ... | @@ -1729,30 +1720,6 @@ unify_ty env ty1 ty2 kco |
| 1729 | 1720 | ; unify_tc_app env tc1 tys1 tys2
|
| 1730 | 1721 | }
|
| 1731 | 1722 | |
| 1732 | - -- TYPE and CONSTRAINT are not Apart
|
|
| 1733 | - -- See Note [Type and Constraint are not apart] in GHC.Builtin.Types.Prim
|
|
| 1734 | - -- NB: at this point we know that the two TyCons do not match
|
|
| 1735 | - | Just (tc1,_) <- mb_tc_app1, let u1 = tyConUnique tc1
|
|
| 1736 | - , Just (tc2,_) <- mb_tc_app2, let u2 = tyConUnique tc2
|
|
| 1737 | - , (u1 == tYPETyConKey && u2 == cONSTRAINTTyConKey) ||
|
|
| 1738 | - (u2 == tYPETyConKey && u1 == cONSTRAINTTyConKey)
|
|
| 1739 | - = maybeApart MARTypeVsConstraint
|
|
| 1740 | - -- We don't bother to look inside; wrinkle (W3) in GHC.Builtin.Types.Prim
|
|
| 1741 | - -- Note [Type and Constraint are not apart]
|
|
| 1742 | - |
|
| 1743 | - -- The arrow types are not Apart
|
|
| 1744 | - -- See Note [Type and Constraint are not apart] in GHC.Builtin.Types.Prim
|
|
| 1745 | - -- wrinkle (W2)
|
|
| 1746 | - -- NB1: at this point we know that the two TyCons do not match
|
|
| 1747 | - -- NB2: In the common FunTy/FunTy case you might wonder if we want to go via
|
|
| 1748 | - -- splitTyConApp_maybe. But yes we do: we need to look at those implied
|
|
| 1749 | - -- kind argument in order to satisfy (Unification Kind Invariant)
|
|
| 1750 | - | FunTy {} <- ty1
|
|
| 1751 | - , FunTy {} <- ty2
|
|
| 1752 | - = maybeApart MARTypeVsConstraint
|
|
| 1753 | - -- We don't bother to look inside; wrinkle (W3) in GHC.Builtin.Types.Prim
|
|
| 1754 | - -- Note [Type and Constraint are not apart]
|
|
| 1755 | - |
|
| 1756 | 1723 | where
|
| 1757 | 1724 | mb_tc_app1 = splitTyConApp_maybe ty1
|
| 1758 | 1725 | mb_tc_app2 = splitTyConApp_maybe ty2
|
| ... | ... | @@ -55,6 +55,7 @@ import Data.IORef |
| 55 | 55 | import qualified Data.Set as Set
|
| 56 | 56 | import GHC.Iface.Errors.Types
|
| 57 | 57 | import Data.Either
|
| 58 | +import GHC.Data.Bag (listToBag)
|
|
| 58 | 59 | |
| 59 | 60 | -----------------------------------------------------------------
|
| 60 | 61 | --
|
| ... | ... | @@ -237,19 +238,6 @@ processDeps dflags hsc_env excl_mods root hdl (AcyclicSCC (ModuleNode _ (ModuleN |
| 237 | 238 | obj_file = msObjFilePath node
|
| 238 | 239 | obj_files = insertSuffixes obj_file extra_suffixes
|
| 239 | 240 | |
| 240 | - do_imp loc is_boot pkg_qual imp_mod
|
|
| 241 | - = do { mb_hi <- findDependency hsc_env loc pkg_qual imp_mod
|
|
| 242 | - is_boot include_pkg_deps
|
|
| 243 | - ; case mb_hi of {
|
|
| 244 | - Nothing -> return () ;
|
|
| 245 | - Just hi_file -> do
|
|
| 246 | - { let hi_files = insertSuffixes hi_file extra_suffixes
|
|
| 247 | - write_dep (obj,hi) = writeDependency root hdl [obj] hi
|
|
| 248 | - |
|
| 249 | - -- Add one dependency for each suffix;
|
|
| 250 | - -- e.g. A.o : B.hi
|
|
| 251 | - -- A.x_o : B.x_hi
|
|
| 252 | - ; mapM_ write_dep (obj_files `zip` hi_files) }}}
|
|
| 253 | 241 | |
| 254 | 242 | |
| 255 | 243 | -- Emit std dependency of the object(s) on the source file
|
| ... | ... | @@ -280,15 +268,33 @@ processDeps dflags hsc_env excl_mods root hdl (AcyclicSCC (ModuleNode _ (ModuleN |
| 280 | 268 | |
| 281 | 269 | -- Emit a dependency for each import
|
| 282 | 270 | |
| 283 | - ; let do_imps is_boot idecls = sequence_
|
|
| 284 | - [ do_imp loc is_boot mb_pkg mod
|
|
| 271 | + ; let find_dep loc is_boot pkg_qual imp_mod = findDependency hsc_env loc pkg_qual imp_mod is_boot include_pkg_deps
|
|
| 272 | + |
|
| 273 | + find_deps is_boot idecls = sequence
|
|
| 274 | + [ find_dep loc is_boot mb_pkg mod
|
|
| 285 | 275 | | (_lvl, mb_pkg, L loc mod) <- idecls,
|
| 286 | 276 | mod `notElem` excl_mods ]
|
| 287 | 277 | |
| 288 | - ; do_imps IsBoot (map ((,,) NormalLevel NoPkgQual) (ms_srcimps node))
|
|
| 289 | - ; do_imps NotBoot (ms_imps node)
|
|
| 290 | - }
|
|
| 278 | + do_imp hi_file = do
|
|
| 279 | + let hi_files = insertSuffixes hi_file extra_suffixes
|
|
| 280 | + write_dep (obj,hi) = writeDependency root hdl [obj] hi
|
|
| 281 | + |
|
| 282 | + -- Add one dependency for each suffix;
|
|
| 283 | + -- e.g. A.o : B.hi
|
|
| 284 | + -- A.x_o : B.x_hi
|
|
| 285 | + mapM_ write_dep (obj_files `zip` hi_files)
|
|
| 291 | 286 | |
| 287 | + ; (missing_boot_dep_errs, boot_deps) <- partitionEithers <$> find_deps IsBoot (map ((,,) NormalLevel NoPkgQual) (ms_srcimps node))
|
|
| 288 | + ; (missing_not_boot_dep_errs, not_boot_deps) <- partitionEithers <$> find_deps NotBoot (ms_imps node)
|
|
| 289 | + |
|
| 290 | + ; let all_missing_errors = missing_boot_dep_errs ++ missing_not_boot_dep_errs
|
|
| 291 | + |
|
| 292 | + ; if null all_missing_errors
|
|
| 293 | + then mapM_ (mapM_ do_imp) (boot_deps ++ not_boot_deps)
|
|
| 294 | + else do
|
|
| 295 | + let sec = initSourceErrorContext (hsc_dflags hsc_env)
|
|
| 296 | + throwErrors sec (mkMessages (listToBag all_missing_errors))
|
|
| 297 | + }
|
|
| 292 | 298 | |
| 293 | 299 | findDependency :: HscEnv
|
| 294 | 300 | -> SrcSpan
|
| ... | ... | @@ -296,7 +302,7 @@ findDependency :: HscEnv |
| 296 | 302 | -> ModuleName -- Imported module
|
| 297 | 303 | -> IsBootInterface -- Source import
|
| 298 | 304 | -> Bool -- Record dependency on package modules
|
| 299 | - -> IO (Maybe FilePath) -- Interface file
|
|
| 305 | + -> IO (Either (MsgEnvelope GhcMessage) (Maybe FilePath)) -- Interface file
|
|
| 300 | 306 | findDependency hsc_env srcloc pkg imp is_boot include_pkg_deps = do
|
| 301 | 307 | -- Find the module; this will be fast because
|
| 302 | 308 | -- we've done it once during downsweep
|
| ... | ... | @@ -305,16 +311,15 @@ findDependency hsc_env srcloc pkg imp is_boot include_pkg_deps = do |
| 305 | 311 | Found loc _
|
| 306 | 312 | -- Home package: just depend on the .hi or hi-boot file
|
| 307 | 313 | | isJust (ml_hs_file loc) || include_pkg_deps
|
| 308 | - -> return (Just (ml_hi_file loc))
|
|
| 314 | + -> return (Right (Just (ml_hi_file loc)))
|
|
| 309 | 315 | |
| 310 | 316 | -- Not in this package: we don't need a dependency
|
| 311 | 317 | | otherwise
|
| 312 | - -> return Nothing
|
|
| 318 | + -> return (Right Nothing)
|
|
| 313 | 319 | |
| 314 | 320 | fail ->
|
| 315 | - let sec = initSourceErrorContext (hsc_dflags hsc_env)
|
|
| 316 | - in
|
|
| 317 | - throwOneError sec $
|
|
| 321 | + return $
|
|
| 322 | + Left $
|
|
| 318 | 323 | mkPlainErrorMsgEnvelope srcloc $
|
| 319 | 324 | GhcDriverMessage $ DriverInterfaceError $
|
| 320 | 325 | (Can'tFindInterface (cannotFindModule hsc_env imp fail) (LookingForModule imp is_boot))
|
| ... | ... | @@ -185,7 +185,7 @@ genApp ctx i args |
| 185 | 185 | as' <- concatMapM genArg args
|
| 186 | 186 | ei <- varForEntryId i
|
| 187 | 187 | let ra = mconcat . reverse $
|
| 188 | - zipWith (\r a -> toJExpr r |= a) [R1 ..] as'
|
|
| 188 | + zipWith (\r a -> toJExpr r |= a) regsFromR1 as'
|
|
| 189 | 189 | p <- pushLneFrame n ctx
|
| 190 | 190 | a <- adjSp 1 -- for the header (which will only be written when the thread is suspended)
|
| 191 | 191 | return (ra <> p <> a <> returnS ei, ExprCont)
|
| ... | ... | @@ -464,42 +464,31 @@ specTag spec = Bits.shiftL (specVars spec) 8 Bits..|. specArgs spec |
| 464 | 464 | specTagExpr :: ApplySpec -> JStgExpr
|
| 465 | 465 | specTagExpr = toJExpr . specTag
|
| 466 | 466 | |
| 467 | --- | Build arrays to quickly lookup apply functions
|
|
| 467 | +-- | Build functions to quickly lookup apply functions
|
|
| 468 | 468 | --
|
| 469 | --- h$apply[r << 8 | n] = function application for r regs, n args
|
|
| 470 | --- h$paps[r] = partial application for r registers (number of args is in the object)
|
|
| 469 | +-- h$apply(r << 8 | n) = function application for r regs, n args
|
|
| 470 | +-- h$paps(r) = partial application for r registers (number of args is in the object)
|
|
| 471 | 471 | mkApplyArr :: JSM JStgStat
|
| 472 | 472 | mkApplyArr =
|
| 473 | - do mk_ap_gens <- jFor (|= zero_) (.<. Int 65536) preIncrS
|
|
| 474 | - \j -> hdApply .! j |= hdApGen
|
|
| 475 | - mk_pap_gens <- jFor (|= zero_) (.<. Int 128) preIncrS
|
|
| 476 | - \j -> hdPaps .! j |= hdPapGen
|
|
| 473 | + do paps_fun <- jFunction (name hdPapsStr) \(MkSolo i) -> pure $ SwitchStat i (map case_pap specPap) (returnS hdPapGen)
|
|
| 474 | + apply_fun <- jFunction (name hdApplyStr) \(MkSolo i) -> pure $ SwitchStat i (mapMaybe' case_apply applySpec) (returnS hdApGen)
|
|
| 477 | 475 | return $ mconcat
|
| 478 | - [ name hdApplyStr ||= toJExpr (JList [])
|
|
| 479 | - , name hdPapsStr ||= toJExpr (JList [])
|
|
| 480 | - , ApplStat (hdInitStatic .^ "push")
|
|
| 481 | - [ jLam' $
|
|
| 482 | - mconcat
|
|
| 483 | - [ mk_ap_gens
|
|
| 484 | - , mk_pap_gens
|
|
| 485 | - , mconcat (map assignSpec applySpec)
|
|
| 486 | - , mconcat (map assignPap specPap)
|
|
| 487 | - ]
|
|
| 488 | - ]
|
|
| 476 | + [ paps_fun
|
|
| 477 | + , apply_fun
|
|
| 489 | 478 | ]
|
| 490 | 479 | where
|
| 491 | - assignSpec :: ApplySpec -> JStgStat
|
|
| 492 | - assignSpec spec = case specConv spec of
|
|
| 480 | + case_apply :: ApplySpec -> Maybe (JStgExpr,JStgStat)
|
|
| 481 | + case_apply spec = case specConv spec of
|
|
| 493 | 482 | -- both fast/slow (regs/stack) specialized apply functions have the same
|
| 494 | 483 | -- tags. We store the stack ones in the array because they are used as
|
| 495 | 484 | -- continuation stack frames.
|
| 496 | - StackConv -> hdApply .! specTagExpr spec |= specApplyExpr spec
|
|
| 497 | - RegsConv -> mempty
|
|
| 485 | + StackConv -> Just (specTagExpr spec, returnS (specApplyExpr spec))
|
|
| 486 | + RegsConv -> Nothing
|
|
| 498 | 487 | |
| 499 | 488 | hdPap_ = unpackFS hdPapStr_
|
| 500 | 489 | |
| 501 | - assignPap :: Int -> JStgStat
|
|
| 502 | - assignPap p = hdPaps .! toJExpr p |= global (mkFastString (hdPap_ ++ show p))
|
|
| 490 | + case_pap :: Int -> (JStgExpr, JStgStat)
|
|
| 491 | + case_pap p = (toJExpr p, returnS $ global (mkFastString (hdPap_ ++ show p)))
|
|
| 503 | 492 | |
| 504 | 493 | -- | Push a continuation on the stack
|
| 505 | 494 | --
|
| ... | ... | @@ -619,7 +608,7 @@ genericStackApply cfg = closure info body |
| 619 | 608 | -- compute new tag with consumed register values and args removed
|
| 620 | 609 | , newTag |= ((given_regs-needed_regs).<<.8) .|. (given_args - needed_args)
|
| 621 | 610 | -- find application function for the remaining regs/args
|
| 622 | - , newAp |= hdApply .! newTag
|
|
| 611 | + , newAp |= ApplExpr hdApply [newTag]
|
|
| 623 | 612 | , traceRts cfg (jString "h$ap_gen: next: " + (newAp .^ "n"))
|
| 624 | 613 | |
| 625 | 614 | -- Drop used registers from the stack.
|
| ... | ... | @@ -643,7 +632,7 @@ genericStackApply cfg = closure info body |
| 643 | 632 | -----------------------------
|
| 644 | 633 | [ traceRts cfg (jString "h$ap_gen: undersat")
|
| 645 | 634 | -- find PAP entry function corresponding to given_regs count
|
| 646 | - , p |= hdPaps .! given_regs
|
|
| 635 | + , p |= ApplExpr hdPaps [given_regs]
|
|
| 647 | 636 | |
| 648 | 637 | -- build PAP payload: R1 + tag + given register values
|
| 649 | 638 | , newTag |= ((needed_regs-given_regs) .<<. 8) .|. (needed_args-given_args)
|
| ... | ... | @@ -716,7 +705,7 @@ genericFastApply s = |
| 716 | 705 | do push_all_regs <- pushAllRegs tag
|
| 717 | 706 | return $ mconcat $
|
| 718 | 707 | [ push_all_regs
|
| 719 | - , ap |= hdApply .! tag
|
|
| 708 | + , ap |= ApplExpr hdApply [tag]
|
|
| 720 | 709 | , ifS (ap .===. hdApGen)
|
| 721 | 710 | ((sp |= sp + 2) <> (stack .! (sp-1) |= tag))
|
| 722 | 711 | (sp |= sp + 1)
|
| ... | ... | @@ -750,7 +739,7 @@ genericFastApply s = |
| 750 | 739 | , traceRts s (jString "h$ap_gen_fast: oversat " + sp)
|
| 751 | 740 | , push_args
|
| 752 | 741 | , newTag |= ((myRegs-( arity.>>.8)).<<.8).|.myAr-ar
|
| 753 | - , newAp |= hdApply .! newTag
|
|
| 742 | + , newAp |= ApplExpr hdApply [newTag]
|
|
| 754 | 743 | , ifS (newAp .===. hdApGen)
|
| 755 | 744 | ((sp |= sp + 2) <> (stack .! (sp - 1) |= newTag))
|
| 756 | 745 | (sp |= sp + 1)
|
| ... | ... | @@ -761,7 +750,7 @@ genericFastApply s = |
| 761 | 750 | -- else
|
| 762 | 751 | [traceRts s (jString "h$ap_gen_fast: undersat: " + myRegs + jString " " + tag)
|
| 763 | 752 | , jwhenS (tag .!=. 0) $ mconcat
|
| 764 | - [ p |= hdPaps .! myRegs
|
|
| 753 | + [ p |= ApplExpr hdPaps [myRegs]
|
|
| 765 | 754 | , dat |= toJExpr [r1, ((arity .>>. 8)-myRegs)*256+ar-myAr]
|
| 766 | 755 | , get_regs
|
| 767 | 756 | , r1 |= initClosure s p dat jCurrentCCS
|
| ... | ... | @@ -773,14 +762,24 @@ genericFastApply s = |
| 773 | 762 | pushAllRegs :: JStgExpr -> JSM JStgStat
|
| 774 | 763 | pushAllRegs tag =
|
| 775 | 764 | jVar \regs ->
|
| 776 | - return $ mconcat $
|
|
| 777 | - [ regs |= tag .>>. 8
|
|
| 778 | - , sp |= sp + regs
|
|
| 779 | - , SwitchStat regs (map pushReg [65,64..2]) mempty
|
|
| 780 | - ]
|
|
| 781 | - where
|
|
| 782 | - pushReg :: Int -> (JStgExpr, JStgStat)
|
|
| 783 | - pushReg r = (toJExpr (r-1), stack .! (sp - toJExpr (r - 2)) |= jsReg r)
|
|
| 765 | + let max_low_reg = regNumber maxLowReg
|
|
| 766 | + low_regs = [max_low_reg, max_low_reg-1..2] -- R1 isn't used for arguments
|
|
| 767 | + pushReg :: Int -> (JStgExpr, JStgStat)
|
|
| 768 | + pushReg r = (toJExpr r, stack .! (sp - toJExpr (r - 2)) |= jsReg r)
|
|
| 769 | + in return $ mconcat $
|
|
| 770 | + [ regs |= tag .>>. 8
|
|
| 771 | + , sp |= sp + regs
|
|
| 772 | + -- increment the number of regs by 1, so that it matches register
|
|
| 773 | + -- numbers (R1 is not used for args)
|
|
| 774 | + , postIncrS regs
|
|
| 775 | + -- copy high registers with a loop
|
|
| 776 | + , WhileStat False (regs .>. toJExpr max_low_reg) $ mconcat
|
|
| 777 | + -- rN stored in stack[sp - N - 2] so that r2 is stored in stack[sp], etc.
|
|
| 778 | + [ stack .! (sp - regs - 2) |= highReg_expr regs
|
|
| 779 | + , postDecrS regs
|
|
| 780 | + ]
|
|
| 781 | + , SwitchStat regs (map pushReg low_regs) mempty
|
|
| 782 | + ]
|
|
| 784 | 783 | |
| 785 | 784 | pushArgs :: JStgExpr -> JStgExpr -> JSM JStgStat
|
| 786 | 785 | pushArgs start end =
|
| ... | ... | @@ -906,7 +905,7 @@ stackApply s fun_name nargs nvars = |
| 906 | 905 | [ rs |= (arity .>>. 8)
|
| 907 | 906 | , loadRegs rs
|
| 908 | 907 | , sp |= sp - rs
|
| 909 | - , newAp |= (hdApply .! ((toJExpr nargs-arity0).|.((toJExpr nvars-rs).<<.8)))
|
|
| 908 | + , newAp |= ApplExpr hdApply [(toJExpr nargs-arity0).|.((toJExpr nvars-rs).<<.8)]
|
|
| 910 | 909 | , stack .! sp |= newAp
|
| 911 | 910 | , profStat s pushRestoreCCS
|
| 912 | 911 | , traceRts s (toJExpr (fun_name <> ": new stack frame: ") + (newAp .^ "n"))
|
| ... | ... | @@ -989,7 +988,7 @@ fastApply s fun_name nargs nvars = if nargs == 0 && nvars == 0 |
| 989 | 988 | + rsRemain)
|
| 990 | 989 | , saveRegs rs
|
| 991 | 990 | , sp |= sp + rsRemain + 1
|
| 992 | - , stack .! sp |= hdApply .! ((rsRemain.<<.8).|. (toJExpr nargs - mask8 arity))
|
|
| 991 | + , stack .! sp |= ApplExpr hdApply [(rsRemain.<<.8).|. (toJExpr nargs - mask8 arity)]
|
|
| 993 | 992 | , profStat s pushRestoreCCS
|
| 994 | 993 | , returnS c
|
| 995 | 994 | ]
|
| ... | ... | @@ -1238,14 +1237,30 @@ pap s r = closure (ClosureInfo |
| 1238 | 1237 | , profStat s (enterCostCentreFun currentCCS)
|
| 1239 | 1238 | , extra |= (funOrPapArity c (Just f) .>>. 8) - toJExpr r
|
| 1240 | 1239 | , traceRts s (toJExpr (funcName <> ": pap extra args moving: ") + extra)
|
| 1241 | - , moveBy extra
|
|
| 1240 | + , case r of
|
|
| 1241 | + 0 -> mempty -- in pap_0 we don't shift any register
|
|
| 1242 | + _ -> moveBy extra
|
|
| 1242 | 1243 | , loadOwnArgs d
|
| 1243 | 1244 | , r1 |= c
|
| 1244 | 1245 | , returnS f
|
| 1245 | 1246 | ]
|
| 1246 | - moveBy extra = SwitchStat extra
|
|
| 1247 | - (reverse $ map moveCase [1..maxReg-r-1]) mempty
|
|
| 1248 | - moveCase m = (toJExpr m, jsReg (m+r+1) |= jsReg (m+1))
|
|
| 1247 | + moveBy extra =
|
|
| 1248 | + let max_low_reg = regNumber maxLowReg
|
|
| 1249 | + low_regs = [max_low_reg, max_low_reg-1..2] -- R1 isn't used for arguments
|
|
| 1250 | + move_case m = (toJExpr m, jsReg (m+r) |= jsReg m)
|
|
| 1251 | + in mconcat
|
|
| 1252 | + [ -- increment the number of args by 1, so that it matches register
|
|
| 1253 | + -- numbers (R1 is not used for args)
|
|
| 1254 | + postIncrS extra
|
|
| 1255 | + -- copy high registers with a loop
|
|
| 1256 | + , WhileStat False (extra .>. toJExpr max_low_reg) $ mconcat
|
|
| 1257 | + [ highReg_expr (extra + toJExpr r) |= highReg_expr extra
|
|
| 1258 | + , postDecrS extra
|
|
| 1259 | + ]
|
|
| 1260 | + -- then copy low registers with a case
|
|
| 1261 | + , SwitchStat extra (map move_case low_regs) mempty
|
|
| 1262 | + ]
|
|
| 1263 | + |
|
| 1249 | 1264 | loadOwnArgs d = mconcat $ map (\r ->
|
| 1250 | 1265 | jsReg (r+1) |= dField d (r+2)) [1..r]
|
| 1251 | 1266 | dField d n = SelExpr d (name . mkFastString $ ('d':show (n-1)))
|
| ... | ... | @@ -1274,7 +1289,9 @@ papGen cfg = |
| 1274 | 1289 | (jString "h$pap_gen: expected function or pap")
|
| 1275 | 1290 | , profStat cfg (enterCostCentreFun currentCCS)
|
| 1276 | 1291 | , traceRts cfg (jString "h$pap_gen: generic pap extra args moving: " + or)
|
| 1292 | + -- shift newly applied arguments into appropriate registers
|
|
| 1277 | 1293 | , appS hdMoveRegs2 [or, r]
|
| 1294 | + -- load stored arguments into lowest argument registers (i.e. starting from R2)
|
|
| 1278 | 1295 | , loadOwnArgs d r
|
| 1279 | 1296 | , r1 |= c
|
| 1280 | 1297 | , returnS f
|
| ... | ... | @@ -1285,9 +1302,22 @@ papGen cfg = |
| 1285 | 1302 | funcIdent = name funcName
|
| 1286 | 1303 | funcName = hdPapGenStr
|
| 1287 | 1304 | loadOwnArgs d r =
|
| 1288 | - let prop n = d .^ ("d" <> mkFastString (show $ n+1))
|
|
| 1289 | - loadOwnArg n = (toJExpr n, jsReg (n+1) |= prop n)
|
|
| 1290 | - in SwitchStat r (map loadOwnArg [127,126..1]) mempty
|
|
| 1305 | + let prop n = d .^ (mkFastString ("d" ++ show n))
|
|
| 1306 | + loadOwnArg n = (toJExpr n, jsReg n |= prop n)
|
|
| 1307 | + max_low_reg = regNumber maxLowReg
|
|
| 1308 | + low_regs = [max_low_reg, max_low_reg-1..2] -- R1 isn't used for arguments
|
|
| 1309 | + in mconcat
|
|
| 1310 | + [ -- increment the number of args by 1, so that it matches register
|
|
| 1311 | + -- numbers (R1 is not used for args) and PAP fields (starting from d2)
|
|
| 1312 | + postIncrS r
|
|
| 1313 | + -- copy high registers with a loop
|
|
| 1314 | + , WhileStat False (r .>. toJExpr max_low_reg) $ mconcat
|
|
| 1315 | + [ highReg_expr r |= (d .! (jString (fsLit "d") + r))
|
|
| 1316 | + , postDecrS r
|
|
| 1317 | + ]
|
|
| 1318 | + -- then copy low registers with a case.
|
|
| 1319 | + , SwitchStat r (map loadOwnArg low_regs) mempty
|
|
| 1320 | + ]
|
|
| 1291 | 1321 | |
| 1292 | 1322 | -- general utilities
|
| 1293 | 1323 | -- move the first n registers, starting at R2, m places up (do not use with negative m)
|
| ... | ... | @@ -1301,7 +1331,7 @@ moveRegs2 = jFunction (name hdMoveRegs2) moveSwitch |
| 1301 | 1331 | switchCase n m = (toJExpr $
|
| 1302 | 1332 | (n `Bits.shiftL` 8) Bits..|. m
|
| 1303 | 1333 | , mconcat (map (`moveRegFast` m) [n+1,n..2])
|
| 1304 | - <> BreakStat Nothing {-[j| break; |]-})
|
|
| 1334 | + <> BreakStat Nothing)
|
|
| 1305 | 1335 | moveRegFast n m = jsReg (n+m) |= jsReg n
|
| 1306 | 1336 | -- fallback
|
| 1307 | 1337 | defaultCase n m =
|
| ... | ... | @@ -312,7 +312,7 @@ genBody ctx startReg args e typ = do |
| 312 | 312 | -- load arguments into local variables
|
| 313 | 313 | la <- do
|
| 314 | 314 | args' <- concatMapM genIdArgI args
|
| 315 | - return (declAssignAll args' (fmap toJExpr [startReg..]))
|
|
| 315 | + return (declAssignAll args' (jsRegsFrom startReg))
|
|
| 316 | 316 | |
| 317 | 317 | -- assert that arguments have valid runtime reps
|
| 318 | 318 | lav <- verifyRuntimeReps args
|
| ... | ... | @@ -665,7 +665,7 @@ genCase ctx bnd e at alts l |
| 665 | 665 | | otherwise = do
|
| 666 | 666 | rj <- genRet ctx bnd at alts l
|
| 667 | 667 | let ctx' = ctxSetTop bnd
|
| 668 | - $ ctxSetTarget (assocIdExprs bnd (map toJExpr [R1 ..]))
|
|
| 668 | + $ ctxSetTarget (assocIdExprs bnd jsRegsFromR1)
|
|
| 669 | 669 | $ ctx
|
| 670 | 670 | (ej, _r) <- genExpr ctx' e
|
| 671 | 671 | return (rj <> ej, ExprCont)
|
| ... | ... | @@ -730,7 +730,7 @@ genRet ctx e at as l = freshIdent >>= f |
| 730 | 730 | |
| 731 | 731 | fun free = resetSlots $ do
|
| 732 | 732 | decs <- declVarsForId e
|
| 733 | - load <- flip assignAll (map toJExpr [R1 ..]) . map toJExpr <$> identsForId e
|
|
| 733 | + load <- flip assignAll jsRegsFromR1 . map toJExpr <$> identsForId e
|
|
| 734 | 734 | loadv <- verifyRuntimeReps [e]
|
| 735 | 735 | ras <- loadRetArgs free
|
| 736 | 736 | rasv <- verifyRuntimeReps (map (\(x,_,_)->x) free)
|
| 1 | 1 | {-# LANGUAGE OverloadedStrings #-}
|
| 2 | +{-# LANGUAGE PatternSynonyms #-}
|
|
| 2 | 3 | |
| 3 | 4 | module GHC.StgToJS.Regs
|
| 4 | 5 | ( StgReg (..)
|
| ... | ... | @@ -6,17 +7,25 @@ module GHC.StgToJS.Regs |
| 6 | 7 | , sp
|
| 7 | 8 | , stack
|
| 8 | 9 | , r1, r2, r3, r4
|
| 10 | + , pattern R1, pattern R2, pattern R3, pattern R4
|
|
| 9 | 11 | , regsFromR1
|
| 10 | 12 | , regsFromR2
|
| 13 | + , regsFromTo
|
|
| 14 | + , jsRegsFrom
|
|
| 11 | 15 | , jsRegsFromR1
|
| 12 | 16 | , jsRegsFromR2
|
| 13 | 17 | , StgRet (..)
|
| 14 | - , jsRegToInt
|
|
| 15 | - , intToJSReg
|
|
| 18 | + , regNumber
|
|
| 16 | 19 | , jsReg
|
| 20 | + , highReg
|
|
| 21 | + , highReg_expr
|
|
| 17 | 22 | , maxReg
|
| 23 | + , maxLowReg
|
|
| 18 | 24 | , minReg
|
| 25 | + , minHighReg
|
|
| 19 | 26 | , lowRegs
|
| 27 | + , lowRegsCount
|
|
| 28 | + , lowRegsIdents
|
|
| 20 | 29 | , retRegs
|
| 21 | 30 | , register
|
| 22 | 31 | , foreignRegister
|
| ... | ... | @@ -32,6 +41,7 @@ import GHC.JS.Make |
| 32 | 41 | import GHC.StgToJS.Symbols
|
| 33 | 42 | |
| 34 | 43 | import GHC.Data.FastString
|
| 44 | +import GHC.Utils.Panic.Plain
|
|
| 35 | 45 | |
| 36 | 46 | import Data.Array
|
| 37 | 47 | import qualified Data.ByteString.Char8 as BSC
|
| ... | ... | @@ -39,26 +49,15 @@ import Data.Char |
| 39 | 49 | import Data.Semigroup ((<>))
|
| 40 | 50 | |
| 41 | 51 | -- | General purpose "registers"
|
| 42 | ---
|
|
| 43 | --- The JS backend arbitrarily supports 128 registers
|
|
| 44 | -data StgReg
|
|
| 45 | - = R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8
|
|
| 46 | - | R9 | R10 | R11 | R12 | R13 | R14 | R15 | R16
|
|
| 47 | - | R17 | R18 | R19 | R20 | R21 | R22 | R23 | R24
|
|
| 48 | - | R25 | R26 | R27 | R28 | R29 | R30 | R31 | R32
|
|
| 49 | - | R33 | R34 | R35 | R36 | R37 | R38 | R39 | R40
|
|
| 50 | - | R41 | R42 | R43 | R44 | R45 | R46 | R47 | R48
|
|
| 51 | - | R49 | R50 | R51 | R52 | R53 | R54 | R55 | R56
|
|
| 52 | - | R57 | R58 | R59 | R60 | R61 | R62 | R63 | R64
|
|
| 53 | - | R65 | R66 | R67 | R68 | R69 | R70 | R71 | R72
|
|
| 54 | - | R73 | R74 | R75 | R76 | R77 | R78 | R79 | R80
|
|
| 55 | - | R81 | R82 | R83 | R84 | R85 | R86 | R87 | R88
|
|
| 56 | - | R89 | R90 | R91 | R92 | R93 | R94 | R95 | R96
|
|
| 57 | - | R97 | R98 | R99 | R100 | R101 | R102 | R103 | R104
|
|
| 58 | - | R105 | R106 | R107 | R108 | R109 | R110 | R111 | R112
|
|
| 59 | - | R113 | R114 | R115 | R116 | R117 | R118 | R119 | R120
|
|
| 60 | - | R121 | R122 | R123 | R124 | R125 | R126 | R127 | R128
|
|
| 61 | - deriving (Eq, Ord, Show, Enum, Bounded, Ix)
|
|
| 52 | +newtype StgReg
|
|
| 53 | + = StgReg Int
|
|
| 54 | + deriving (Eq,Ord,Ix)
|
|
| 55 | + |
|
| 56 | +pattern R1, R2, R3, R4 :: StgReg
|
|
| 57 | +pattern R1 = StgReg 0
|
|
| 58 | +pattern R2 = StgReg 1
|
|
| 59 | +pattern R3 = StgReg 2
|
|
| 60 | +pattern R4 = StgReg 3
|
|
| 62 | 61 | |
| 63 | 62 | -- | Stack registers
|
| 64 | 63 | data Special
|
| ... | ... | @@ -78,7 +77,7 @@ instance ToJExpr Special where |
| 78 | 77 | toJExpr Sp = hdStackPtr
|
| 79 | 78 | |
| 80 | 79 | instance ToJExpr StgReg where
|
| 81 | - toJExpr r = registers ! r
|
|
| 80 | + toJExpr r = register r
|
|
| 82 | 81 | |
| 83 | 82 | instance ToJExpr StgRet where
|
| 84 | 83 | toJExpr r = rets ! r
|
| ... | ... | @@ -99,25 +98,42 @@ r2 = toJExpr R2 |
| 99 | 98 | r3 = toJExpr R3
|
| 100 | 99 | r4 = toJExpr R4
|
| 101 | 100 | |
| 101 | +-- | 1-indexed register number (R1 has index 1)
|
|
| 102 | +regNumber :: StgReg -> Int
|
|
| 103 | +regNumber (StgReg r) = r+1
|
|
| 102 | 104 | |
| 103 | -jsRegToInt :: StgReg -> Int
|
|
| 104 | -jsRegToInt = (+1) . fromEnum
|
|
| 105 | +-- | StgReg from 1-indexed number
|
|
| 106 | +regFromNumber :: Int -> StgReg
|
|
| 107 | +regFromNumber r = assert (r >= 1) $ StgReg (r-1)
|
|
| 105 | 108 | |
| 106 | -intToJSReg :: Int -> StgReg
|
|
| 107 | -intToJSReg r = toEnum (r - 1)
|
|
| 109 | +regsFromTo :: StgReg -> StgReg -> [StgReg]
|
|
| 110 | +regsFromTo (StgReg x) (StgReg y) = map StgReg [x .. y]
|
|
| 108 | 111 | |
| 112 | +-- | Register expression from its 1-indexed index
|
|
| 109 | 113 | jsReg :: Int -> JStgExpr
|
| 110 | -jsReg r = toJExpr (intToJSReg r)
|
|
| 114 | +jsReg r = toJExpr (regFromNumber r)
|
|
| 115 | + |
|
| 116 | +minReg :: StgReg
|
|
| 117 | +minReg = R1
|
|
| 111 | 118 | |
| 112 | -maxReg :: Int
|
|
| 113 | -maxReg = jsRegToInt maxBound
|
|
| 119 | +maxReg :: StgReg
|
|
| 120 | +maxReg = regFromNumber maxBound
|
|
| 114 | 121 | |
| 115 | -minReg :: Int
|
|
| 116 | -minReg = jsRegToInt minBound
|
|
| 122 | +lowRegsCount :: Int
|
|
| 123 | +lowRegsCount = 31
|
|
| 124 | + |
|
| 125 | +maxLowReg :: StgReg
|
|
| 126 | +maxLowReg = regFromNumber lowRegsCount
|
|
| 127 | + |
|
| 128 | +-- | First register stored in h$regs array instead of having its own top-level
|
|
| 129 | +-- variable
|
|
| 130 | +minHighReg :: StgReg
|
|
| 131 | +minHighReg = case maxLowReg of
|
|
| 132 | + StgReg r -> StgReg (r+1)
|
|
| 117 | 133 | |
| 118 | 134 | -- | List of registers, starting from R1
|
| 119 | 135 | regsFromR1 :: [StgReg]
|
| 120 | -regsFromR1 = enumFrom R1
|
|
| 136 | +regsFromR1 = regsFromTo R1 maxReg ++ repeat (panic "StgToJS: code requires too many registers")
|
|
| 121 | 137 | |
| 122 | 138 | -- | List of registers, starting from R2
|
| 123 | 139 | regsFromR2 :: [StgReg]
|
| ... | ... | @@ -131,35 +147,59 @@ jsRegsFromR1 = fmap toJExpr regsFromR1 |
| 131 | 147 | jsRegsFromR2 :: [JStgExpr]
|
| 132 | 148 | jsRegsFromR2 = tail jsRegsFromR1
|
| 133 | 149 | |
| 150 | +-- | List of registers, starting from given reg as JExpr
|
|
| 151 | +jsRegsFrom :: StgReg -> [JStgExpr]
|
|
| 152 | +jsRegsFrom (StgReg n) = drop n jsRegsFromR1
|
|
| 153 | + |
|
| 154 | +-- | High register
|
|
| 155 | +highReg :: Int -> JStgExpr
|
|
| 156 | +highReg r = assert (r >= regNumber minHighReg) $ IdxExpr hdRegs (toJExpr (r - regNumber minHighReg))
|
|
| 157 | + |
|
| 158 | +-- | High register indexing with a JS expression
|
|
| 159 | +highReg_expr :: JStgExpr -> JStgExpr
|
|
| 160 | +highReg_expr r = IdxExpr hdRegs (r - toJExpr (regNumber minHighReg))
|
|
| 161 | + |
|
| 162 | + |
|
| 134 | 163 | ---------------------------------------------------
|
| 135 | 164 | -- caches
|
| 136 | 165 | ---------------------------------------------------
|
| 137 | 166 | |
| 138 | -lowRegs :: [Ident]
|
|
| 139 | -lowRegs = map reg_to_ident [R1 .. R31]
|
|
| 140 | - where reg_to_ident = name . mkFastString . (unpackFS hdStr ++) . map toLower . show
|
|
| 167 | +lowRegs :: [StgReg]
|
|
| 168 | +lowRegs = regsFromTo minReg maxLowReg
|
|
| 169 | + |
|
| 170 | +lowRegsIdents :: [Ident]
|
|
| 171 | +lowRegsIdents = map reg_to_ident lowRegs
|
|
| 172 | + where
|
|
| 173 | + -- low regs are named h$r1, h$r2, etc.
|
|
| 174 | + reg_to_ident r = name (mkFastString (unpackFS hdStr ++ "r" ++ show (regNumber r)))
|
|
| 141 | 175 | |
| 142 | 176 | retRegs :: [Ident]
|
| 143 | 177 | retRegs = [name . mkFastStringByteString
|
| 144 | 178 | $ hdB <> BSC.pack (map toLower $ show n) | n <- enumFrom Ret1]
|
| 145 | 179 | |
| 146 | --- cache JExpr representing StgReg
|
|
| 147 | -registers :: Array StgReg JStgExpr
|
|
| 148 | -registers = listArray (minBound, maxBound) (map (global . identFS) lowRegs ++ map regN [R32 .. R128])
|
|
| 149 | - where
|
|
| 150 | - regN :: StgReg -> JStgExpr
|
|
| 151 | - regN r = IdxExpr hdRegs (toJExpr (fromEnum r - 32))
|
|
| 152 | - |
|
| 153 | 180 | -- cache JExpr representing StgRet
|
| 154 | 181 | rets :: Array StgRet JStgExpr
|
| 155 | 182 | rets = listArray (minBound, maxBound) (map retN (enumFrom Ret1))
|
| 156 | 183 | where
|
| 157 | 184 | retN = global . mkFastString . (unpackFS hdStr ++) . map toLower . show
|
| 158 | 185 | |
| 159 | --- | Given a register, return the JS syntax object representing that register
|
|
| 160 | -register :: StgReg -> JStgExpr
|
|
| 161 | -register i = registers ! i
|
|
| 162 | - |
|
| 163 | 186 | -- | Given a register, return the JS syntax object representing that register
|
| 164 | 187 | foreignRegister :: StgRet -> JStgExpr
|
| 165 | 188 | foreignRegister i = rets ! i
|
| 189 | + |
|
| 190 | +-- | Given a register, return the JS syntax object representing that register
|
|
| 191 | +register :: StgReg -> JStgExpr
|
|
| 192 | +register i
|
|
| 193 | + | i <= maxCachedReg = register_cache ! i -- Expressions of common registers are cached.
|
|
| 194 | + | otherwise = make_high_reg i -- Expression of higher registers are made on the fly
|
|
| 195 | + |
|
| 196 | +maxCachedReg :: StgReg
|
|
| 197 | +maxCachedReg = regFromNumber 128
|
|
| 198 | + |
|
| 199 | +-- cache JExpr representing StgReg
|
|
| 200 | +register_cache :: Array StgReg JStgExpr
|
|
| 201 | +register_cache = listArray (minReg, maxCachedReg) (map (global . identFS) lowRegsIdents ++ map make_high_reg (regsFromTo minHighReg maxCachedReg))
|
|
| 202 | + |
|
| 203 | +-- | Make h$regs[XXX] expression for the register
|
|
| 204 | +make_high_reg :: StgReg -> JStgExpr
|
|
| 205 | +make_high_reg r = highReg (regNumber r) |
| ... | ... | @@ -54,7 +54,12 @@ import qualified Data.Bits as Bits |
| 54 | 54 | -- | The garbageCollector resets registers and result variables.
|
| 55 | 55 | garbageCollector :: JSM JStgStat
|
| 56 | 56 | garbageCollector = jBlock
|
| 57 | - [ jFunction' hdResetRegisters (return $ mconcat $ map resetRegister [minBound..maxBound])
|
|
| 57 | + [ jFunction' hdResetRegisters $ return $ mconcat
|
|
| 58 | + [ -- reset low registers explicitly
|
|
| 59 | + mconcat (map resetRegister lowRegs)
|
|
| 60 | + -- reset the whole h$regs array with h$regs.fill(null)
|
|
| 61 | + , toStat $ ApplExpr (hdRegs .^ "fill") [null_]
|
|
| 62 | + ]
|
|
| 58 | 63 | , jFunction' hdResetResultVars (return $ mconcat $ map resetResultVar [minBound..maxBound])
|
| 59 | 64 | ]
|
| 60 | 65 | |
| ... | ... | @@ -249,7 +254,7 @@ declRegs = do |
| 249 | 254 | loaders <- loadRegs
|
| 250 | 255 | return $
|
| 251 | 256 | mconcat [ hdRegsStr ||= toJExpr (JList [])
|
| 252 | - , mconcat (map declReg lowRegs)
|
|
| 257 | + , mconcat (map declReg lowRegsIdents)
|
|
| 253 | 258 | , getters_setters
|
| 254 | 259 | , loaders
|
| 255 | 260 | ]
|
| ... | ... | @@ -259,15 +264,15 @@ declRegs = do |
| 259 | 264 | -- | JS payload to define getters and setters on the registers.
|
| 260 | 265 | regGettersSetters :: JSM JStgStat
|
| 261 | 266 | regGettersSetters =
|
| 262 | - do setters <- jFunction (name hdGetRegStr) (\(MkSolo n) -> return $ SwitchStat n getRegCases mempty)
|
|
| 263 | - getters <- jFunction (name hdSetRegStr) (\(n,v) -> return $ SwitchStat n (setRegCases v) mempty)
|
|
| 267 | + do getters <- jFunction (name hdGetRegStr) (\(MkSolo n) -> return $ SwitchStat n getRegCases (defaultGetRegCase n))
|
|
| 268 | + setters <- jFunction (name hdSetRegStr) (\(n,v) -> return $ SwitchStat n (setRegCases v) (defaultSetRegCase n v))
|
|
| 264 | 269 | return $ setters <> getters
|
| 265 | 270 | where
|
| 266 | - getRegCases =
|
|
| 267 | - map (\r -> (toJExpr (jsRegToInt r) , returnS (toJExpr r))) regsFromR1
|
|
| 268 | - setRegCases :: JStgExpr -> [(JStgExpr,JStgStat)]
|
|
| 269 | - setRegCases v =
|
|
| 270 | - map (\r -> (toJExpr (jsRegToInt r), (toJExpr r |= toJExpr v) <> returnS undefined_)) regsFromR1
|
|
| 271 | + getRegCases = map (\r -> (toJExpr (regNumber r) , returnS (toJExpr r))) lowRegs
|
|
| 272 | + defaultGetRegCase n = returnS (highReg_expr n)
|
|
| 273 | + |
|
| 274 | + setRegCases v = map (\r -> (toJExpr (regNumber r), (toJExpr r |= v) <> BreakStat Nothing)) lowRegs
|
|
| 275 | + defaultSetRegCase n v = highReg_expr n |= v
|
|
| 271 | 276 | |
| 272 | 277 | -- | JS payload that defines the functions to load each register
|
| 273 | 278 | loadRegs :: JSM JStgStat
|
| ... | ... | @@ -69,12 +69,3 @@ stackFrameSize tgt f = |
| 69 | 69 | (tgt |= mask8 tag + 1) -- else set to mask'd tag + 1
|
| 70 | 70 | ]
|
| 71 | 71 | )) |
| 72 | - |
|
| 73 | - --------------------------------------------------------------------------------
|
|
| 74 | --- Register utilities
|
|
| 75 | ---------------------------------------------------------------------------------
|
|
| 76 | - |
|
| 77 | --- | Perform the computation 'f', on the range of registers bounded by 'start'
|
|
| 78 | --- and 'end'.
|
|
| 79 | -withRegs :: StgReg -> StgReg -> (StgReg -> JStgStat) -> JStgStat
|
|
| 80 | -withRegs start end f = mconcat $ fmap f [start..end] |
| ... | ... | @@ -963,11 +963,6 @@ matchTypeable clas [k,t] -- clas = Typeable |
| 963 | 963 | | k `eqType` naturalTy = doTyLit knownNatClassName t
|
| 964 | 964 | | k `eqType` typeSymbolKind = doTyLit knownSymbolClassName t
|
| 965 | 965 | | k `eqType` charTy = doTyLit knownCharClassName t
|
| 966 | - |
|
| 967 | - -- TyCon applied to its kind args
|
|
| 968 | - -- No special treatment of Type and Constraint; they get distinct TypeReps
|
|
| 969 | - -- see wrinkle (W4) of Note [Type and Constraint are not apart]
|
|
| 970 | - -- in GHC.Builtin.Types.Prim.
|
|
| 971 | 966 | | Just (tc, ks) <- splitTyConApp_maybe t -- See Note [Typeable (T a b c)]
|
| 972 | 967 | , onlyNamedBndrsApplied tc ks = doTyConApp clas t tc ks
|
| 973 | 968 |
| ... | ... | @@ -16,6 +16,17 @@ Language |
| 16 | 16 | result, you may need to enable :extension:`DataKinds` in code that did not
|
| 17 | 17 | previously require it.
|
| 18 | 18 | |
| 19 | +- ``Type`` and ``Constraint`` are now (at last) completely distinct types, just as much
|
|
| 20 | + as ``Int`` and ``Bool``. For example, you can now
|
|
| 21 | + write::
|
|
| 22 | + |
|
| 23 | + type family F a
|
|
| 24 | + |
|
| 25 | + type instance F Type = Int
|
|
| 26 | + type instance F Constraint = Bool
|
|
| 27 | + |
|
| 28 | + which was previously rejected with "Conflicting family instance declarations".
|
|
| 29 | + |
|
| 19 | 30 | Compiler
|
| 20 | 31 | ~~~~~~~~
|
| 21 | 32 |
| ... | ... | @@ -256,4 +256,4 @@ test('T24893', normal, compile_and_run, ['-O']) |
| 256 | 256 | test('CCallConv', [req_c], compile_and_run, ['CCallConv_c.c'])
|
| 257 | 257 | test('T25364', normal, compile_and_run, [''])
|
| 258 | 258 | test('T26061', normal, compile_and_run, [''])
|
| 259 | -test('T26537', js_broken(26558), compile_and_run, ['-O2 -fregs-graph']) |
|
| 259 | +test('T26537', normal, compile_and_run, ['-O2 -fregs-graph']) |
| ... | ... | @@ -415,6 +415,10 @@ test200: |
| 415 | 415 | "$(TEST_HC)" $(TEST_HC_OPTS) -M -dep-suffix "" -dep-makefile $(DEPFILE200) D200.hs B200/C.hs A200.hs
|
| 416 | 416 | test -f $(DEPFILE200)
|
| 417 | 417 | |
| 418 | +# Test that we produce "could not find module" errors for _all_ missing imports.
|
|
| 419 | +T26551:
|
|
| 420 | + "$(TEST_HC)" $(TEST_HC_OPTS) -M T26551.hs || true
|
|
| 421 | + |
|
| 418 | 422 | # -----------------------------------------------------------------------------
|
| 419 | 423 | |
| 420 | 424 | T2566::
|
| 1 | +module Main where
|
|
| 2 | + |
|
| 3 | +import Foo
|
|
| 4 | +import Bar
|
|
| 5 | +import Baz |
| 1 | +T26551.hs:3:8: [GHC-87110]
|
|
| 2 | + Could not find module ‘Foo’.
|
|
| 3 | + Use -v to see a list of the files searched for.
|
|
| 4 | + |
|
| 5 | +T26551.hs:4:8: [GHC-87110]
|
|
| 6 | + Could not find module ‘Bar’.
|
|
| 7 | + Use -v to see a list of the files searched for.
|
|
| 8 | + |
|
| 9 | +T26551.hs:5:8: [GHC-87110]
|
|
| 10 | + Could not find module ‘Baz’.
|
|
| 11 | + Use -v to see a list of the files searched for. |
| ... | ... | @@ -332,3 +332,4 @@ test('t25150', [extra_files(["t25150"])], multimod_compile, ['Main.hs', '-v0 -wo |
| 332 | 332 | test('T25382', normal, makefile_test, [])
|
| 333 | 333 | test('T26018', req_c, makefile_test, [])
|
| 334 | 334 | test('T24120', normal, compile, ['-Wunused-packages -hide-all-packages -package base -package system-cxx-std-lib'])
|
| 335 | +test('T26551', [extra_files(['T26551.hs'])], makefile_test, []) |
| ... | ... | @@ -7,3 +7,5 @@ type family F a |
| 7 | 7 | |
| 8 | 8 | type instance F Type = Int
|
| 9 | 9 | type instance F Constraint = Bool
|
| 10 | + |
|
| 11 | +-- Nov 2025: Type and Constraint are now Apart (#24279) |
| 1 | - |
|
| 2 | -T21092.hs:8:15: error: [GHC-34447]
|
|
| 3 | - Conflicting family instance declarations:
|
|
| 4 | - F (*) = Int -- Defined at T21092.hs:8:15
|
|
| 5 | - F Constraint = Bool -- Defined at T21092.hs:9:15 |
| ... | ... | @@ -107,7 +107,7 @@ test('T8368', normal, compile_fail, ['']) |
| 107 | 107 | test('T8368a', normal, compile_fail, [''])
|
| 108 | 108 | test('T8518', normal, compile_fail, [''])
|
| 109 | 109 | test('T9036', normal, compile_fail, [''])
|
| 110 | -test('T21092', normal, compile_fail, [''])
|
|
| 110 | +test('T21092', normal, compile, ['']) # Now compiles fine
|
|
| 111 | 111 | test('T9167', normal, compile_fail, [''])
|
| 112 | 112 | test('T9171', normal, compile_fail, [''])
|
| 113 | 113 | test('T9097', normal, compile_fail, [''])
|
| ... | ... | @@ -13,7 +13,7 @@ type G :: Type -> RuntimeRep -> Type |
| 13 | 13 | type family G a where
|
| 14 | 14 | G (a b) = a
|
| 15 | 15 | |
| 16 | --- Should be rejected
|
|
| 16 | +-- Now (Nov 2025) accepted
|
|
| 17 | 17 | foo :: (F (G Constraint)) -> Bool
|
| 18 | 18 | foo x = x
|
| 19 | 19 | |
| ... | ... | @@ -22,10 +22,10 @@ type family H a b where |
| 22 | 22 | H a a = Int
|
| 23 | 23 | H a b = Bool
|
| 24 | 24 | |
| 25 | --- Should be rejected
|
|
| 26 | -bar1 :: H TYPE CONSTRAINT -> Int
|
|
| 25 | +-- Now (Nov 2025) accepted
|
|
| 26 | +bar1 :: H TYPE CONSTRAINT -> Bool
|
|
| 27 | 27 | bar1 x = x
|
| 28 | 28 | |
| 29 | --- Should be rejected
|
|
| 30 | -bar2 :: H Type Constraint -> Int
|
|
| 29 | +-- Now (Nov 2025) accepted
|
|
| 30 | +bar2 :: H Type Constraint -> Bool
|
|
| 31 | 31 | bar2 x = x |
| 1 | - |
|
| 2 | -T24279.hs:18:9: error: [GHC-83865]
|
|
| 3 | - • Couldn't match type ‘F CONSTRAINT’ with ‘Bool’
|
|
| 4 | - Expected: Bool
|
|
| 5 | - Actual: F (G Constraint)
|
|
| 6 | - • In the expression: x
|
|
| 7 | - In an equation for ‘foo’: foo x = x
|
|
| 8 | - |
|
| 9 | -T24279.hs:27:10: error: [GHC-83865]
|
|
| 10 | - • Couldn't match expected type ‘Int’
|
|
| 11 | - with actual type ‘H TYPE CONSTRAINT’
|
|
| 12 | - • In the expression: x
|
|
| 13 | - In an equation for ‘bar1’: bar1 x = x
|
|
| 14 | - |
|
| 15 | -T24279.hs:31:10: error: [GHC-83865]
|
|
| 16 | - • Couldn't match expected type ‘Int’
|
|
| 17 | - with actual type ‘H (*) Constraint’
|
|
| 18 | - • In the expression: x
|
|
| 19 | - In an equation for ‘bar2’: bar2 x = x |
| ... | ... | @@ -718,7 +718,7 @@ test('T24064', normal, compile_fail, ['']) |
| 718 | 718 | test('T24090a', normal, compile_fail, [''])
|
| 719 | 719 | test('T24090b', normal, compile, ['']) # scheduled to become an actual error in GHC 9.16
|
| 720 | 720 | test('T24298', normal, compile_fail, [''])
|
| 721 | -test('T24279', normal, compile_fail, [''])
|
|
| 721 | +test('T24279', normal, compile, ['']) # Now accepted (Nov 2025)
|
|
| 722 | 722 | test('T24318', normal, compile_fail, [''])
|
| 723 | 723 | |
| 724 | 724 | # all the various do expansion fail messages
|