Commit a6199582 authored by simonmar's avatar simonmar
Browse files

[project @ 1999-06-17 09:51:16 by simonmar]

Comment cleanup and literisation(?) by Wolfram Kahl <kahl@DI.Unipi.IT>.
parent 07e4037d
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
% (c) The GRASP/AQUA Project, Glasgow University, 1997-1998 % (c) The GRASP/AQUA Project, Glasgow University, 1997-1998
% %
% Author: Juan J. Quintela <quintela@krilin.dc.fi.udc.es> % Author: Juan J. Quintela <quintela@krilin.dc.fi.udc.es>
\section{Module @Check@ in @deSugar@}
\begin{code} \begin{code}
...@@ -56,61 +57,69 @@ import Outputable ...@@ -56,61 +57,69 @@ import Outputable
\end{code} \end{code}
This module performs checks about if one list of equations are: This module performs checks about if one list of equations are:
- Overlapped \begin{itemize}
- Non exhaustive \item Overlapped
\item Non exhaustive
\end{itemize}
To discover that we go through the list of equations in a tree-like fashion. To discover that we go through the list of equations in a tree-like fashion.
If you like theory, a similar algorithm is described in: If you like theory, a similar algorithm is described in:
Two Techniques for Compiling Lazy Pattern Matching \begin{quotation}
Luc Maranguet {\em Two Techniques for Compiling Lazy Pattern Matching},
Luc Maranguet,
INRIA Rocquencourt (RR-2385, 1994) INRIA Rocquencourt (RR-2385, 1994)
\end{quotation}
The algorithm is based in the first Technique, but there are some differences: The algorithm is based on the first technique, but there are some differences:
- We don't generate code \begin{itemize}
- We have constructors and literals (not only literals as in the \item We don't generate code
\item We have constructors and literals (not only literals as in the
article) article)
- We don't use directions, we must select the columns from \item We don't use directions, we must select the columns from
left-to-right left-to-right
\end{itemize}
(By the way the second technique is really similar to the one used in (By the way the second technique is really similar to the one used in
Match.lhs to generate code) @Match.lhs@ to generate code)
This function takes the equations of a pattern and returns: This function takes the equations of a pattern and returns:
- The patterns that are not recognized \begin{itemize}
- The equations that are not overlapped \item The patterns that are not recognized
\item The equations that are not overlapped
It simplify the patterns and then call check' (the same semantics),and it \end{itemize}
It simplify the patterns and then call @check'@ (the same semantics), and it
needs to reconstruct the patterns again .... needs to reconstruct the patterns again ....
The problem appear with things like: The problem appear with things like:
\begin{verbatim}
f [x,y] = .... f [x,y] = ....
f (x:xs) = ..... f (x:xs) = .....
\end{verbatim}
We want to put the two patterns with the same syntax, (prefix form) and We want to put the two patterns with the same syntax, (prefix form) and
then all the constructors are equal: then all the constructors are equal:
\begin{verbatim}
f (: x (: y [])) = .... f (: x (: y [])) = ....
f (: x xs) = ..... f (: x xs) = .....
\end{verbatim}
(more about that in @simplify_eqns@)
(more about that in simplify_eqns) We would prefer to have a @WarningPat@ of type @String@, but Strings and the
We would prefer to have a WarningPat of type String, but Strings and the
Pretty Printer are not friends. Pretty Printer are not friends.
We use InPat in WarningPat instead of OutPat because we need to print the We use @InPat@ in @WarningPat@ instead of @OutPat@
because we need to print the
warning messages in the same way they are introduced, i.e. if the user warning messages in the same way they are introduced, i.e. if the user
wrote: wrote:
\begin{verbatim}
f [x,y] = .. f [x,y] = ..
\end{verbatim}
He don't want a warning message written: He don't want a warning message written:
\begin{verbatim}
f (: x (: y [])) ........ f (: x (: y [])) ........
\end{verbatim}
Then we need to use InPats. Then we need to use InPats.
\begin{quotation}
Juan Quintela 5 JUL 1998 Juan Quintela 5 JUL 1998\\
User-friendliness and compiler writers are no friends. User-friendliness and compiler writers are no friends.
\end{quotation}
\begin{code} \begin{code}
type WarningPat = InPat Name type WarningPat = InPat Name
...@@ -178,11 +187,11 @@ untidy_lit lit = lit ...@@ -178,11 +187,11 @@ untidy_lit lit = lit
This equation is the same that check, the only difference is that the This equation is the same that check, the only difference is that the
boring work is done, that work needs to be done only once, this is boring work is done, that work needs to be done only once, this is
the reason top have two functions, check is the external interface, the reason top have two functions, check is the external interface,
check' is called recursively. @check'@ is called recursively.
There are several cases: There are several cases:
\begin{item} \begin{itemize}
\item There are no equations: Everything is OK. \item There are no equations: Everything is OK.
\item There are only one equation, that can fail, and all the patterns are \item There are only one equation, that can fail, and all the patterns are
variables. Then that equation is used and the same equation is variables. Then that equation is used and the same equation is
...@@ -198,7 +207,7 @@ There are several cases: ...@@ -198,7 +207,7 @@ There are several cases:
\item In the general case, there can exist literals ,constructors or only \item In the general case, there can exist literals ,constructors or only
vars in the first column, we actuate in consequence. vars in the first column, we actuate in consequence.
\end{item} \end{itemize}
\begin{code} \begin{code}
...@@ -243,7 +252,7 @@ split_by_literals qs = process_literals used_lits qs ...@@ -243,7 +252,7 @@ split_by_literals qs = process_literals used_lits qs
used_lits = get_used_lits qs used_lits = get_used_lits qs
\end{code} \end{code}
process_explicit_literals is a function that process each literal that appears @process_explicit_literals@ is a function that process each literal that appears
in the column of the matrix. in the column of the matrix.
\begin{code} \begin{code}
...@@ -256,7 +265,7 @@ process_explicit_literals lits qs = (concat pats, unionManyUniqSets indexs) ...@@ -256,7 +265,7 @@ process_explicit_literals lits qs = (concat pats, unionManyUniqSets indexs)
\end{code} \end{code}
Process_literals calls process_explicit_literals to deal with the literals @process_literals@ calls @process_explicit_literals@ to deal with the literals
that appears in the matrix and deal also with the rest of the cases. It that appears in the matrix and deal also with the rest of the cases. It
must be one Variable to be complete. must be one Variable to be complete.
...@@ -297,7 +306,7 @@ remove_first_column_lit lit qs = ...@@ -297,7 +306,7 @@ remove_first_column_lit lit qs =
\end{code} \end{code}
This function splits the equations @qs@ in groups that deal with the This function splits the equations @qs@ in groups that deal with the
same constructor same constructor.
\begin{code} \begin{code}
...@@ -327,7 +336,7 @@ constructor, using all the constructors that appears in the first column ...@@ -327,7 +336,7 @@ constructor, using all the constructors that appears in the first column
of the pattern matching. of the pattern matching.
We can need a default clause or not ...., it depends if we used all the We can need a default clause or not ...., it depends if we used all the
constructors or not explicitly. The reasoning is similar to process_literals, constructors or not explicitly. The reasoning is similar to @process_literals@,
the difference is that here the default case is not always needed. the difference is that here the default case is not always needed.
\begin{code} \begin{code}
...@@ -362,15 +371,15 @@ Here remove first column is more difficult that with literals due to the fact ...@@ -362,15 +371,15 @@ Here remove first column is more difficult that with literals due to the fact
that constructors can have arguments. that constructors can have arguments.
For instance, the matrix For instance, the matrix
\begin{verbatim}
(: x xs) y (: x xs) y
z y z y
\end{verbatim}
is transformed in: is transformed in:
\begin{verbatim}
x xs y x xs y
_ _ y _ _ y
\end{verbatim}
\begin{code} \begin{code}
remove_first_column :: TypecheckedPat -- Constructor remove_first_column :: TypecheckedPat -- Constructor
...@@ -436,7 +445,8 @@ get_unused_cons used_cons = unused_cons ...@@ -436,7 +445,8 @@ get_unused_cons used_cons = unused_cons
Just (ty_con,_) = splitTyConApp_maybe ty Just (ty_con,_) = splitTyConApp_maybe ty
all_cons = tyConDataCons ty_con all_cons = tyConDataCons ty_con
used_cons_as_id = map (\ (ConPat d _ _ _ _) -> d) used_cons used_cons_as_id = map (\ (ConPat d _ _ _ _) -> d) used_cons
unused_cons = uniqSetToList (mkUniqSet all_cons `minusUniqSet` mkUniqSet used_cons_as_id) unused_cons = uniqSetToList
(mkUniqSet all_cons `minusUniqSet` mkUniqSet used_cons_as_id)
all_vars :: [TypecheckedPat] -> Bool all_vars :: [TypecheckedPat] -> Bool
...@@ -446,7 +456,8 @@ all_vars _ = False ...@@ -446,7 +456,8 @@ all_vars _ = False
remove_var :: EquationInfo -> EquationInfo remove_var :: EquationInfo -> EquationInfo
remove_var (EqnInfo n ctx (WildPat _:ps) result) = EqnInfo n ctx ps result remove_var (EqnInfo n ctx (WildPat _:ps) result) = EqnInfo n ctx ps result
remove_var _ = panic "Check:remove_var: equation not begin with a variable" remove_var _ =
panic "Check.remove_var: equation does not begin with a variable"
is_con :: EquationInfo -> Bool is_con :: EquationInfo -> Bool
is_con (EqnInfo _ _ ((ConPat _ _ _ _ _):_) _) = True is_con (EqnInfo _ _ ((ConPat _ _ _ _ _):_) _) = True
...@@ -481,39 +492,43 @@ is_var_lit lit (EqnInfo _ _ ((NPat lit' _ _):_) _) | lit == lit' = True ...@@ -481,39 +492,43 @@ is_var_lit lit (EqnInfo _ _ ((NPat lit' _ _):_) _) | lit == lit' = True
is_var_lit lit _ = False is_var_lit lit _ = False
\end{code} \end{code}
The difference beteewn make_con and make_whole_con is that The difference beteewn @make_con@ and @make_whole_con@ is that
make_wole_con creates a new constructor with all their arguments, and @make_wole_con@ creates a new constructor with all their arguments, and
make_Con takes a list of argumntes, creates the contructor geting thir @make_con@ takes a list of argumntes, creates the contructor getting their
argumnts from the list. See where are used for details. arguments from the list. See where \fbox{\ ???\ } are used for details.
We need to reconstruct the patterns (make the constructors infix and We need to reconstruct the patterns (make the constructors infix and
similar) at the same time that we create the constructors. similar) at the same time that we create the constructors.
You can tell tuple constructors using You can tell tuple constructors using
\begin{verbatim}
Id.isTupleCon Id.isTupleCon
\end{verbatim}
You can see if one constructor is infix with this clearer code :-)))))))))) You can see if one constructor is infix with this clearer code :-))))))))))
\begin{verbatim}
Lex.isLexConSym (Name.occNameString (Name.getOccName con)) Lex.isLexConSym (Name.occNameString (Name.getOccName con))
\end{verbatim}
Rather clumsy but it works. (Simon Peyton Jones) Rather clumsy but it works. (Simon Peyton Jones)
We con't mind the nilDataCon because it doesn't change the way to We don't mind the @nilDataCon@ because it doesn't change the way to
print the messsage, we are searching only for things like: [1,2,3], print the messsage, we are searching only for things like: @[1,2,3]@,
not x:xs .... not @x:xs@ ....
In reconstruct_pat we want to "undo" the work that we have done in simplify_pat In @reconstruct_pat@ we want to ``undo'' the work
that we have done in @simplify_pat@.
In particular: In particular:
((,) x y) returns to be (x, y) \begin{tabular}{lll}
((:) x xs) returns to be (x:xs) @((,) x y)@ & returns to be & @(x, y)@
(x:(...:[]) returns to be [x,...] \\ @((:) x xs)@ & returns to be & @(x:xs)@
\\ @(x:(...:[])@ & returns to be & @[x,...]@
\end{tabular}
%
The difficult case is the third one becouse we need to follow all the The difficult case is the third one becouse we need to follow all the
contructors until the [] to know taht we need to use the second case, contructors until the @[]@ to know that we need to use the second case,
not the second. not the second. \fbox{\ ???\ }
%
\begin{code} \begin{code}
isInfixCon con = isDataSymOcc (getOccName con) isInfixCon con = isDataSymOcc (getOccName con)
...@@ -560,9 +575,9 @@ new_wild_pat :: WarningPat ...@@ -560,9 +575,9 @@ new_wild_pat :: WarningPat
new_wild_pat = WildPatIn new_wild_pat = WildPatIn
\end{code} \end{code}
This equation makes the same thing that tidy in Match.lhs, the This equation makes the same thing as @tidy@ in @Match.lhs@, the
difference is that here we can do all the tidy in one place and in the difference is that here we can do all the tidy in one place and in the
Match tidy it must be done one column each time due to bookkeeping @Match@ tidy it must be done one column each time due to bookkeeping
constraints. constraints.
\begin{code} \begin{code}
...@@ -584,9 +599,9 @@ simplify_pat (AsPat id p) = simplify_pat p ...@@ -584,9 +599,9 @@ simplify_pat (AsPat id p) = simplify_pat p
simplify_pat (ConPat id ty tvs dicts ps) = ConPat id ty tvs dicts (map simplify_pat ps) simplify_pat (ConPat id ty tvs dicts ps) = ConPat id ty tvs dicts (map simplify_pat ps)
simplify_pat (ListPat ty ps) = foldr (\ x -> \y -> ConPat consDataCon list_ty [] [] [x, y]) simplify_pat (ListPat ty ps) = foldr (\ x -> \y -> ConPat consDataCon list_ty [] [] [x, y])
(ConPat nilDataCon list_ty [] [] []) (ConPat nilDataCon list_ty [] [] [])
(map simplify_pat ps) (map simplify_pat ps)
where list_ty = mkListTy ty where list_ty = mkListTy ty
......
...@@ -76,7 +76,7 @@ deSugar mod_name us (TcResults {tc_env = global_val_env, ...@@ -76,7 +76,7 @@ deSugar mod_name us (TcResults {tc_env = global_val_env,
module_and_group = (mod_name, grp_name) module_and_group = (mod_name, grp_name)
grp_name = case opt_SccGroup of grp_name = case opt_SccGroup of
Just xx -> _PK_ xx Just xx -> _PK_ xx
Nothing -> _PK_ (moduleString mod_name) -- default: module name Nothing -> _PK_ (moduleString mod_name) -- default: module name
dsProgram mod_name all_binds rules fo_decls dsProgram mod_name all_binds rules fo_decls
= dsMonoBinds auto_scc all_binds [] `thenDs` \ core_prs -> = dsMonoBinds auto_scc all_binds [] `thenDs` \ core_prs ->
...@@ -121,8 +121,8 @@ dsRule (RuleDecl name sig_tvs vars lhs rhs loc) ...@@ -121,8 +121,8 @@ dsRule (RuleDecl name sig_tvs vars lhs rhs loc)
ds_lhs all_vars lhs ds_lhs all_vars lhs
= let = let
(dict_binds, body) = case lhs of (dict_binds, body) = case lhs of
(HsLet (MonoBind dict_binds _ _) body) -> (dict_binds, body) (HsLet (MonoBind dict_binds _ _) body) -> (dict_binds, body)
other -> (EmptyMonoBinds, lhs) other -> (EmptyMonoBinds, lhs)
in in
ds_dict_binds dict_binds `thenDs` \ dict_binds' -> ds_dict_binds dict_binds `thenDs` \ dict_binds' ->
dsExpr body `thenDs` \ body' -> dsExpr body `thenDs` \ body' ->
......
...@@ -89,7 +89,8 @@ dsMonoBinds auto_scc (PatMonoBind pat grhss locn) rest ...@@ -89,7 +89,8 @@ dsMonoBinds auto_scc (PatMonoBind pat grhss locn) rest
-- Common case: one exported variable -- Common case: one exported variable
-- All non-recursive bindings come through this way -- All non-recursive bindings come through this way
dsMonoBinds auto_scc (AbsBinds all_tyvars dicts exps@[(tyvars, global, local)] inlines binds) rest dsMonoBinds auto_scc
(AbsBinds all_tyvars dicts exps@[(tyvars, global, local)] inlines binds) rest
= ASSERT( all (`elem` tyvars) all_tyvars ) = ASSERT( all (`elem` tyvars) all_tyvars )
dsMonoBinds (addSccs auto_scc exps) binds [] `thenDs` \ core_prs -> dsMonoBinds (addSccs auto_scc exps) binds [] `thenDs` \ core_prs ->
let let
...@@ -207,7 +208,8 @@ worthSCC (Con _ _) = False ...@@ -207,7 +208,8 @@ worthSCC (Con _ _) = False
worthSCC core_expr = True worthSCC core_expr = True
\end{code} \end{code}
If profiling and dealing with a dict binding, wrap the dict in "_scc_ DICT <dict>": If profiling and dealing with a dict binding,
wrap the dict in @_scc_ DICT <dict>@:
\begin{code} \begin{code}
addDictScc var rhs = returnDs rhs addDictScc var rhs = returnDs rhs
......
...@@ -180,9 +180,10 @@ unboxArg arg ...@@ -180,9 +180,10 @@ unboxArg arg
Just (arg2_tycon,_) = maybe_arg2_tycon Just (arg2_tycon,_) = maybe_arg2_tycon
can'tSeeDataConsPanic thing ty can'tSeeDataConsPanic thing ty
= pprPanic "ERROR: Can't see the data constructor(s) for _ccall_/_casm_/foreign declaration" = pprPanic
(hcat [text thing, text "; type: ", ppr ty, text "(try compiling with -fno-prune-tydecls ..)\n"]) "ERROR: Can't see the data constructor(s) for _ccall_/_casm_/foreign declaration"
(hcat [ text thing, text "; type: ", ppr ty
, text "(try compiling with -fno-prune-tydecls ..)\n"])
\end{code} \end{code}
......
...@@ -60,14 +60,14 @@ import Outputable ...@@ -60,14 +60,14 @@ import Outputable
%* * %* *
%************************************************************************ %************************************************************************
@dsLet@ is a match-result transformer, taking the MatchResult for the body @dsLet@ is a match-result transformer, taking the @MatchResult@ for the body
and transforming it into one for the let-bindings enclosing the body. and transforming it into one for the let-bindings enclosing the body.
This may seem a bit odd, but (source) let bindings can contain unboxed This may seem a bit odd, but (source) let bindings can contain unboxed
binds like binds like
\begin{verbatim}
C x# = e C x# = e
\end{verbatim}
This must be transformed to a case expression and, if the type has This must be transformed to a case expression and, if the type has
more than one constructor, may fail. more than one constructor, may fail.
...@@ -83,7 +83,8 @@ dsLet (ThenBinds b1 b2) body ...@@ -83,7 +83,8 @@ dsLet (ThenBinds b1 b2) body
-- Special case for bindings which bind unlifted variables -- Special case for bindings which bind unlifted variables
-- Silently ignore INLINE pragmas... -- Silently ignore INLINE pragmas...
dsLet (MonoBind (AbsBinds [] [] binder_triples inlines (PatMonoBind pat grhss loc)) sigs is_rec) body dsLet (MonoBind (AbsBinds [] [] binder_triples inlines
(PatMonoBind pat grhss loc)) sigs is_rec) body
| or [isUnLiftedType (idType g) | (_, g, l) <- binder_triples] | or [isUnLiftedType (idType g) | (_, g, l) <- binder_triples]
= ASSERT (case is_rec of {NonRecursive -> True; other -> False}) = ASSERT (case is_rec of {NonRecursive -> True; other -> False})
putSrcLocDs loc $ putSrcLocDs loc $
...@@ -93,7 +94,8 @@ dsLet (MonoBind (AbsBinds [] [] binder_triples inlines (PatMonoBind pat grhss lo ...@@ -93,7 +94,8 @@ dsLet (MonoBind (AbsBinds [] [] binder_triples inlines (PatMonoBind pat grhss lo
bind (tyvars, g, l) body = ASSERT( null tyvars ) bind (tyvars, g, l) body = ASSERT( null tyvars )
bindNonRec g (Var l) body bindNonRec g (Var l) body
in in
mkErrorAppDs iRREFUT_PAT_ERROR_ID result_ty (showSDoc (ppr pat)) `thenDs` \ error_expr -> mkErrorAppDs iRREFUT_PAT_ERROR_ID result_ty (showSDoc (ppr pat))
`thenDs` \ error_expr ->
matchSimply rhs PatBindMatch pat body' error_expr matchSimply rhs PatBindMatch pat body' error_expr
where where
result_ty = coreExprType body result_ty = coreExprType body
...@@ -124,17 +126,17 @@ dsExpr e@(HsVar var) = returnDs (Var var) ...@@ -124,17 +126,17 @@ dsExpr e@(HsVar var) = returnDs (Var var)
%* * %* *
%************************************************************************ %************************************************************************
We give int/float literals type Integer and Rational, respectively. We give int/float literals type @Integer@ and @Rational@, respectively.
The typechecker will (presumably) have put \tr{from{Integer,Rational}s} The typechecker will (presumably) have put \tr{from{Integer,Rational}s}
around them. around them.
ToDo: put in range checks for when converting "i" ToDo: put in range checks for when converting ``@i@''
(or should that be in the typechecker?) (or should that be in the typechecker?)
For numeric literals, we try to detect there use at a standard type For numeric literals, we try to detect there use at a standard type
(Int, Float, etc.) are directly put in the right constructor. (@Int@, @Float@, etc.) are directly put in the right constructor.
[NB: down with the @App@ conversion.] [NB: down with the @App@ conversion.]
Otherwise, we punt, putting in a "NoRep" Core literal (where the Otherwise, we punt, putting in a @NoRep@ Core literal (where the
representation decisions are delayed)... representation decisions are delayed)...
See also below where we look for @DictApps@ for \tr{plusInt}, etc. See also below where we look for @DictApps@ for \tr{plusInt}, etc.
...@@ -322,8 +324,8 @@ dsExpr (HsSCC cc expr) ...@@ -322,8 +324,8 @@ dsExpr (HsSCC cc expr)
dsExpr (HsCase discrim matches@[Match _ [TuplePat ps boxed] _ _] src_loc) dsExpr (HsCase discrim matches@[Match _ [TuplePat ps boxed] _ _] src_loc)
| not boxed && all var_pat ps | not boxed && all var_pat ps
= putSrcLocDs src_loc $ = putSrcLocDs src_loc $
dsExpr discrim `thenDs` \ core_discrim -> dsExpr discrim `thenDs` \ core_discrim ->
matchWrapper CaseMatch matches "case" `thenDs` \ ([discrim_var], matching_code) -> matchWrapper CaseMatch matches "case" `thenDs` \ ([discrim_var], matching_code) ->
case matching_code of case matching_code of
Case (Var x) bndr alts | x == discrim_var -> Case (Var x) bndr alts | x == discrim_var ->
returnDs (Case core_discrim bndr alts) returnDs (Case core_discrim bndr alts)
...@@ -331,8 +333,8 @@ dsExpr (HsCase discrim matches@[Match _ [TuplePat ps boxed] _ _] src_loc) ...@@ -331,8 +333,8 @@ dsExpr (HsCase discrim matches@[Match _ [TuplePat ps boxed] _ _] src_loc)
dsExpr (HsCase discrim matches src_loc) dsExpr (HsCase discrim matches src_loc)
= putSrcLocDs src_loc $ = putSrcLocDs src_loc $
dsExpr discrim `thenDs` \ core_discrim -> dsExpr discrim `thenDs` \ core_discrim ->
matchWrapper CaseMatch matches "case" `thenDs` \ ([discrim_var], matching_code) -> matchWrapper CaseMatch matches "case" `thenDs` \ ([discrim_var], matching_code) ->
returnDs (bindNonRec discrim_var core_discrim matching_code) returnDs (bindNonRec discrim_var core_discrim matching_code)
dsExpr (HsLet binds body) dsExpr (HsLet binds body)
...@@ -370,8 +372,9 @@ dsExpr (HsIf guard_expr then_expr else_expr src_loc) ...@@ -370,8 +372,9 @@ dsExpr (HsIf guard_expr then_expr else_expr src_loc)
\end{code} \end{code}
Type lambda and application \noindent
~~~~~~~~~~~~~~~~~~~~~~~~~~~ \underline{\bf Type lambda and application}
% ~~~~~~~~~~~~~~~~~~~~~~~~~~~
\begin{code} \begin{code}
dsExpr (TyLam tyvars expr) dsExpr (TyLam tyvars expr)
= dsExpr expr `thenDs` \ core_expr -> = dsExpr expr `thenDs` \ core_expr ->
...@@ -383,8 +386,9 @@ dsExpr (TyApp expr tys) ...@@ -383,8 +386,9 @@ dsExpr (TyApp expr tys)
\end{code} \end{code}
Various data construction things \noindent
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \underline{\bf Various data construction things}
% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
\begin{code} \begin{code}
dsExpr (ExplicitListOut ty xs) dsExpr (ExplicitListOut ty xs)
= go xs = go xs
...@@ -443,25 +447,26 @@ dsExpr (ArithSeqOut expr (FromThenTo from thn two)) ...@@ -443,25 +447,26 @@ dsExpr (ArithSeqOut expr (FromThenTo from thn two))
returnDs (mkApps expr2 [from2, thn2, two2]) returnDs (mkApps expr2 [from2, thn2, two2])
\end{code} \end{code}
Record construction and update \noindent
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \underline{\bf Record construction and update}
% ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
For record construction we do this (assuming T has three arguments) For record construction we do this (assuming T has three arguments)
\begin{verbatim}
T { op2 = e } T { op2 = e }
==> ==>
let err = /\a -> recConErr a let err = /\a -> recConErr a
T (recConErr t1 "M.lhs/230/op1") T (recConErr t1 "M.lhs/230/op1")
e e
(recConErr t1 "M.lhs/230/op3") (recConErr t1 "M.lhs/230/op3")
\end{verbatim}
recConErr then converts its arugment string into a proper message @recConErr@ then converts its arugment string into a proper message
before printing it as before printing it as
\begin{verbatim}
M.lhs, line 230: missing field op1 was evaluated