[Git][ghc/ghc][wip/romes/linear-core] Make match variables always lambda bound
Rodrigo Mesquita (@alt-romes)
gitlab at gitlab.haskell.org
Thu May 11 13:55:30 UTC 2023
Rodrigo Mesquita pushed to branch wip/romes/linear-core at Glasgow Haskell Compiler / GHC
Commits:
d97c081f by Rodrigo Mesquita at 2023-05-11T14:53:59+01:00
Make match variables always lambda bound
The burning question being: Will variables selected for match
(`selectMatchVar`) always be bound in case patterns?
- - - - -
9 changed files:
- compiler/GHC/Core/Make.hs
- compiler/GHC/Core/Opt/Simplify/Iteration.hs
- compiler/GHC/HsToCore/Expr.hs
- compiler/GHC/HsToCore/Match.hs
- compiler/GHC/HsToCore/Match/Constructor.hs
- compiler/GHC/HsToCore/Monad.hs
- compiler/GHC/HsToCore/Utils.hs
- compiler/GHC/Types/Id.hs
- compiler/GHC/Types/Var.hs
Changes:
=====================================
compiler/GHC/Core/Make.hs
=====================================
@@ -182,7 +182,7 @@ mkCoreAppTyped d (fun, fun_ty) arg
--
-- See Note [WildCard binders] in "GHC.Core.Opt.Simplify.Env"
mkWildValBinder :: Mult -> Type -> Id
-mkWildValBinder w ty = mkLocalIdOrCoVar wildCardName (LambdaBound w) ty -- ROMES: for now we consider wildcards to be lambdabound
+mkWildValBinder w ty = mkLocalIdOrCoVar wildCardName (LambdaBound w) ty -- ROMES: just tepmorarily now we consider wildcards to be lambdabound
-- "OrCoVar" since a coercion can be a scrutinee with -fdefer-type-errors
-- (e.g. see test T15695). Ticket #17291 covers fixing this problem.
=====================================
compiler/GHC/Core/Opt/Simplify/Iteration.hs
=====================================
@@ -809,14 +809,14 @@ prepareRhs env top_lvl occ rhs0
anfise other = return (emptyLetFloats, other)
-makeTrivialArg :: HasDebugCallStack => SimplEnv -> ArgSpec -> SimplM (LetFloats, ArgSpec)
+makeTrivialArg :: HasCallStack => HasDebugCallStack => SimplEnv -> ArgSpec -> SimplM (LetFloats, ArgSpec)
makeTrivialArg env arg@(ValArg { as_arg = e, as_dmd = dmd })
= do { (floats, e') <- makeTrivial env NotTopLevel dmd (fsLit "arg") e
; return (floats, arg { as_arg = e' }) }
makeTrivialArg _ arg
= return (emptyLetFloats, arg) -- CastBy, TyArg
-makeTrivial :: HasDebugCallStack
+makeTrivial :: HasCallStack => HasDebugCallStack
=> SimplEnv -> TopLevelFlag -> Demand
-> FastString -- ^ A "friendly name" to build the new binder from
-> OutExpr
@@ -3676,7 +3676,12 @@ mkDupableContWithDmds env _
; let join_body = wrapFloats floats1 join_inner
res_ty = contResultType cont
- ; mkDupableStrictBind env bndr' join_body res_ty }
+ -- romes: The `x` becomes an arg of the join point, so it should move
+ -- from let bound to lambda bound (with which multiplicity? ROMES:TODO).
+ -- (Note [Duplicating StrictBind] explains the transformation)
+ bndr'' = bndr' `setIdBinding` LambdaBound ManyTy
+
+ ; mkDupableStrictBind env bndr'' join_body res_ty }
mkDupableContWithDmds env _
(StrictArg { sc_fun = fun, sc_cont = cont
@@ -3792,7 +3797,9 @@ mkDupableContWithDmds env _
-- See Note [StaticEnv invariant] in GHC.Core.Opt.Simplify.Utils
, sc_cont = mkBoringStop (contResultType cont) } ) }
-mkDupableStrictBind :: SimplEnv -> OutId -> OutExpr -> OutType
+-- ROMES:TODO: What does this function do?
+-- Refer to Note [Dupable StrictBind]? StrictBind con?
+mkDupableStrictBind :: HasCallStack => SimplEnv -> OutId -> OutExpr -> OutType
-> SimplM (SimplFloats, SimplCont)
mkDupableStrictBind env arg_bndr join_rhs res_ty
| exprIsTrivial join_rhs -- See point (2) of Note [Duplicating join points]
=====================================
compiler/GHC/HsToCore/Expr.hs
=====================================
@@ -217,6 +217,12 @@ dsUnliftedBind p@(PatBind { pat_lhs = pat, pat_rhs = grhss
-- ROMES:TODO: I will need to make this correct here... this transformation seems suspicious
-- Matching will turn a group of equations and matching ids into a group of case expressions?
-- It seems really weird for the eqn to have let bound variables, if they're patterns...?
+ --
+ -- Should match equations ever move a let bound var into a case bound position?
+ -- If not, then it is never its responsibility to update the IdBindings
+ --
+ -- It seems in matchConFamily is where we treat C x# y# = ... ==> case rhs of C x# y# -> ..?
+ ; pprTraceM "dsUnliftedBind:eqn" (ppr var <+> ppr eqn)
; result <- matchEquations PatBindRhs [var] [eqn] (exprType body)
; return (bindNonRec var rhs result) }
=====================================
compiler/GHC/HsToCore/Match.hs
=====================================
@@ -371,6 +371,7 @@ Among other things in the resulting Pattern:
The bindings created by the above patterns are put into the returned wrapper
instead.
+-- ROMES:TODO: Do something about this, lambda bound can become let bound for irrefutable patterns
This means a definition of the form:
f x = rhs
when called with v get's desugared to the equivalent of:
@@ -825,8 +826,9 @@ matchWrapper ctxt scrs (MG { mg_alts = L _ matches
$ replicate (length (grhssGRHSs m)) initNablas
+-- No wait, doesn't seem quite right?
-- | Matching will turn a group of pattern-matching equations and MatchId's
--- into a group of case expressions
+-- into a case expression
--
-- For example:
--
@@ -840,6 +842,8 @@ matchWrapper ctxt scrs (MG { mg_alts = L _ matches
-- (x:xs) -> case ys' of
-- [] -> []
-- (y:ys) -> f x y : mappairs f xs ys
+--
+-- See also 'match'
matchEquations :: HasCallStack => HsMatchContext GhcRn
-> [MatchId] -> [EquationInfo] -> Type
-> DsM CoreExpr
@@ -970,7 +974,7 @@ groupEquations :: Platform -> [EquationInfo] -> [NonEmpty (PatGroup, EquationInf
-- (b) none of the gi are empty
-- The ordering of equations is unchanged
groupEquations platform eqns
- = NEL.groupBy same_gp $ [(patGroup platform (firstPat eqn), eqn) | eqn <- eqns]
+ = NEL.groupBy same_gp $ [pprTrace "groupEquations" (ppr (firstPat eqn)) $! (patGroup platform (firstPat eqn), eqn) | eqn <- eqns]
-- comprehension on NonEmpty
where
same_gp :: (PatGroup,EquationInfo) -> (PatGroup,EquationInfo) -> Bool
=====================================
compiler/GHC/HsToCore/Match/Constructor.hs
=====================================
@@ -93,17 +93,36 @@ have-we-used-all-the-constructors? question; the local function
@match_cons_used@ does all the real work.
-}
+-- | Turn group of equations for a single constructor into a case expression?
+--
+-- Example:
+--
+-- data T = C Int Int | D Bool
+--
+-- ROMES: Doesn't seem quite right, perhaps each group can only have 1 expr it's deconstructing?
+-- let C a b = <expr>
+-- D c = <expr> -- not sure about this second one, I think it's wrong here, just adding it bc I'm unsure.
+-- in ...
+--
+-- ==>
+--
+-- case <expr> of
+-- C a b -> ...
+-- D c -> ... -- not sure about this second constructor being correct
+--
+-- Relevant notes seem to be [Match Ids] and [Localise pattern binders]
matchConFamily :: HasCallStack => NonEmpty Id
-> Type
-> NonEmpty (NonEmpty EquationInfo)
-> DsM (MatchResult CoreExpr)
-- Each group of eqns is for a single constructor
matchConFamily (var :| vars) ty groups
- = do let mult = idMult var
+ = pprTrace "matchConFamily" (ppr var <+> hsep (map ppr vars) $$ ppr (map idBinding (var:vars)) $$ ppr groups) $
+ do let !mult = idMult var
-- Each variable in the argument list correspond to one column in the
-- pattern matching equations. Its multiplicity is the context
-- multiplicity of the pattern. We extract that multiplicity, so that
- -- 'matchOneconLike' knows the context multiplicity, in case it needs
+ -- 'matchOneConLike' knows the context multiplicity, in case it needs
-- to come up with new variables.
alts <- mapM (fmap toRealAlt . matchOneConLike vars ty mult) groups
return (mkCoAlgCaseMatchResult var ty alts)
@@ -198,9 +217,16 @@ matchOneConLike vars ty mult (eqn1 :| eqns) -- All eqns for a single construct
-- necessarily correct, as it may come from a variable which was
-- originally let bound and will now be lambda bound.
-- See comments in dsUnliftedBind too.
- ; let arg_vars' = map (`setIdBinding` (LambdaBound ManyTy)) arg_vars -- ROMES:TODO: Not ManyTy!! It depends on the constructor!
+ --
+ -- ROMES:TODO:No,! We should only set LambdaBound x if we have a
+ -- LetBound var, otherwise it already has a multiplicity? Or should we
+ -- simply recompute it completely here?
+ --
+ -- What if the only case putting us here really is dsUnliftedBind? Try to make the change there.
+ -- ; let arg_vars' = map (`setIdBinding` (LambdaBound ManyTy)) arg_vars -- ROMES:TODO: Not ManyTy!! It depends on the constructor! Don't always overwrite?
+ -- ...these arg_vars sometimes contain variables that were originally let bound, when do we make the change passing let bound variables to matchEquations? Should we always discern it here?
; return $ MkCaseAlt{ alt_pat = con1,
- alt_bndrs = tvs1 ++ dicts1 ++ arg_vars', -- these arg_vars contain variables that were originally let bound
+ alt_bndrs = tvs1 ++ dicts1 ++ arg_vars,
alt_wrapper = wrapper1,
alt_result = foldr1 combineMatchResults match_results } }
where
=====================================
compiler/GHC/HsToCore/Monad.hs
=====================================
@@ -395,7 +395,7 @@ newSysLocalDs = mkSysLocalM (fsLit "ds")
newFailLocalDs = mkSysLocalM (fsLit "fail")
newSysLocalsDs :: [Scaled Type] -> DsM [Id]
-newSysLocalsDs = mapM (\(Scaled w t) -> newSysLocalDs (LambdaBound w) t) -- Scaled -> LambdaBound
+newSysLocalsDs = mapM (\(Scaled w t) -> newSysLocalDs (LambdaBound w) t) -- Scaled -> LambdaBound?
{-
We can also reach out and either set/grab location information from
=====================================
compiler/GHC/HsToCore/Utils.hs
=====================================
@@ -143,7 +143,7 @@ selectMatchVar :: HasCallStack => Mult -> Pat GhcTc -> DsM Id
selectMatchVar w (BangPat _ pat) = selectMatchVar w (unLoc pat)
selectMatchVar w (LazyPat _ pat) = selectMatchVar w (unLoc pat)
selectMatchVar w (ParPat _ _ pat _) = selectMatchVar w (unLoc pat)
-selectMatchVar _w (VarPat _ var) = pprTrace "selectMatchVar:VarPat" (pprIdWithBinding (unLoc var)) $ return (localiseId (unLoc var))
+selectMatchVar _w (VarPat _ var) = pprTrace "selectMatchVar:VarPat" (pprIdWithBinding (unLoc var)) $ return (localiseId ((unLoc var) `setIdBinding` (LambdaBound ManyTy))) -- ROMES:TODO: see comment below about match variables being put in cases
-- Note [Localise pattern binders]
--
-- Remark: when the pattern is a variable (or
@@ -151,8 +151,9 @@ selectMatchVar _w (VarPat _ var) = pprTrace "selectMatchVar:VarPat" (pprIdWit
-- multiplicity stored within the variable
-- itself. It's easier to pull it from the
-- variable, so we ignore the multiplicity.
-selectMatchVar _w (AsPat _ var _ _) = assert (isManyTy _w ) (return (unLoc var))
-selectMatchVar w other_pat = newSysLocalDs (LambdaBound w) (hsPatType other_pat) -- ROMES:TODO: provenance isn't so trivial in match var?
+selectMatchVar _w (AsPat _ var _ _) = assert (isManyTy _w ) (return ((unLoc var) `setIdBinding` (LambdaBound ManyTy))) -- ROMES:TODO: Are match variables always put in cases? If yes, then this could be a way to guarantee match variables are lambda bound/case bound
+-- selectMatchVar _w (AsPat _ var _ _) = assert (isManyTy _w ) (return (unLoc var))
+selectMatchVar w other_pat = newSysLocalDs (LambdaBound w) (hsPatType other_pat) -- ROMES:TODO: Can match variables end up in lets and cases?, I think yes.
{- Note [Localise pattern binders]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -300,7 +301,7 @@ data CaseAlt a = HasCallStack => MkCaseAlt{ alt_pat :: a,
alt_result :: MatchResult CoreExpr }
mkCoAlgCaseMatchResult
- :: Id -- ^ Scrutinee
+ :: HasCallStack => Id -- ^ Scrutinee
-> Type -- ^ Type of exp
-> NonEmpty (CaseAlt DataCon) -- ^ Alternatives (bndrs *include* tyvars, dicts)
-> MatchResult CoreExpr
@@ -310,7 +311,7 @@ mkCoAlgCaseMatchResult var ty match_alts
mkCoLetMatchResult (NonRec arg_id1 newtype_rhs) match_result1
| otherwise
- = mkDataConCase var ty match_alts
+ = pprTrace "mkCoAlgCaseMatchResult" (pprIdWithBinding var) $ mkDataConCase var ty match_alts
where
isNewtype = isNewTyCon (dataConTyCon (alt_pat alt1))
@@ -348,9 +349,9 @@ mkPatSynCase var ty alt fail = do
ensure_unstrict cont | needs_void_lam = Lam voidArgId cont
| otherwise = cont
-mkDataConCase :: Id -> Type -> NonEmpty (CaseAlt DataCon) -> MatchResult CoreExpr
+mkDataConCase :: HasCallStack => Id -> Type -> NonEmpty (CaseAlt DataCon) -> MatchResult CoreExpr
mkDataConCase var ty alts@(alt1 :| _)
- = liftA2 mk_case mk_default mk_alts
+ = pprTrace "mkDataConCase" (ppr var <+> ppr (idBinding var)) $ liftA2 mk_case mk_default mk_alts
-- The liftA2 combines the failability of all the alternatives and the default
where
con1 = alt_pat alt1
@@ -365,7 +366,7 @@ mkDataConCase var ty alts@(alt1 :| _)
-- (not that splitTyConApp does, these days)
mk_case :: Maybe CoreAlt -> [CoreAlt] -> CoreExpr
- mk_case def alts = mkWildCase (Var var) (idScaledType var) ty $
+ mk_case def alts = mkWildCase (Var var) (pprTrace "mk_case:var" (pprIdWithBinding var) $ idScaledType var) ty $
maybeToList def ++ alts
mk_alts :: MatchResult [CoreAlt]
=====================================
compiler/GHC/Types/Id.hs
=====================================
@@ -223,6 +223,7 @@ idUsageEnv x = case Var.idBinding x of
-- ROMES: Scaled Types seem to be used mainly in data cons; I think Scaled
-- things remain as they are, bc they seem to only occur in places where the Id is definitely a lambda bound (or datacon, which would be the same) variable
+-- Truly horrendous that this might fail like this, not how we'll leave it... at least return an optional value
idScaledType :: HasCallStack => Id -> Scaled Type
idScaledType id = Scaled (idMult id) (idType id)
=====================================
compiler/GHC/Types/Var.hs
=====================================
@@ -280,6 +280,7 @@ data Var
data IdBinding where
LambdaBound :: !Mult -> IdBinding -- ^ includes lambda-bound and constructor fields---pattern bound
LetBound :: HasCallStack => UsageEnv -> IdBinding -- ^ a local let binding has a usage env bc it might have free linear variables in its body
+ -- ROMES:TODO: What about type variables? LambdaBound too? Do type variables have a multiplicity?
-- Removed globalbinding in exchange for LetBound with zero Ue (closed top-level let bound)
-- Might no longer make sense to merge with IdScope at all
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/d97c081f88fc793e336e76ac59c5c5c57e557612
--
View it on GitLab: https://gitlab.haskell.org/ghc/ghc/-/commit/d97c081f88fc793e336e76ac59c5c5c57e557612
You're receiving this email because of your account on gitlab.haskell.org.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.haskell.org/pipermail/ghc-commits/attachments/20230511/f7c6837b/attachment-0001.html>
More information about the ghc-commits
mailing list