summaryrefslogtreecommitdiff
path: root/ghc/compiler/deSugar/DsUtils.lhs
blob: ff2ec5fe45a545a034580b2e3e29f80e24c5816b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
%
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1996
%
\section[DsUtils]{Utilities for desugaring}

This module exports some utility functions of no great interest.

\begin{code}
#include "HsVersions.h"

module DsUtils (
	CanItFail(..), EquationInfo(..), MatchResult(..),

	combineGRHSMatchResults,
	combineMatchResults,
	dsExprToAtom, SYN_IE(DsCoreArg),
	mkCoAlgCaseMatchResult,
	mkAppDs, mkConDs, mkPrimDs, mkErrorAppDs,
	mkCoLetsMatchResult,
	mkCoPrimCaseMatchResult,
	mkFailurePair,
	mkGuardedMatchResult,
	mkSelectorBinds,
	mkTupleBind,
	mkTupleExpr,
	selectMatchVars,
	showForErr
    ) where

IMP_Ubiq()
IMPORT_DELOOPER(DsLoop)		( match, matchSimply )

import HsSyn		( HsExpr(..), OutPat(..), HsLit(..), Fixity,
			  Match, HsBinds, Stmt, Qualifier, HsType, ArithSeqInfo )
import TcHsSyn		( SYN_IE(TypecheckedPat) )
import DsHsSyn		( outPatType )
import CoreSyn

import DsMonad

import CoreUtils	( coreExprType, mkCoreIfThenElse )
import PprStyle		( PprStyle(..) )
import PrelVals		( iRREFUT_PAT_ERROR_ID, voidId )
import Pretty		( ppShow, ppBesides, ppStr )
import Id		( idType, dataConArgTys, 
--			  pprId{-ToDo:rm-},
			  SYN_IE(DataCon), SYN_IE(DictVar), SYN_IE(Id), GenId )
import Literal		( Literal(..) )
import TyCon		( isNewTyCon, tyConDataCons )
import Type		( mkTyVarTys, mkRhoTy, mkForAllTys, mkFunTy,
			  mkTheta, isUnboxedType, applyTyCon, getAppTyCon
			)
import TysPrim		( voidTy )
import TysWiredIn	( tupleTyCon, unitDataCon, tupleCon )
import UniqSet		( mkUniqSet, minusUniqSet, uniqSetToList, SYN_IE(UniqSet) )
import Util		( panic, assertPanic{-, pprTrace ToDo:rm-} )
import Usage		( SYN_IE(UVar) )
import SrcLoc		( SrcLoc {- instance Outputable -} )
--import PprCore{-ToDo:rm-}
--import PprType--ToDo:rm
--import Pretty--ToDo:rm
--import TyVar--ToDo:rm
--import Unique--ToDo:rm
\end{code}

%************************************************************************
%*									*
%* type synonym EquationInfo and access functions for its pieces	*
%*									*
%************************************************************************
\subsection[EquationInfo-synonym]{@EquationInfo@: a useful synonym}

The ``equation info'' used by @match@ is relatively complicated and
worthy of a type synonym and a few handy functions.

\begin{code}
data EquationInfo
  = EqnInfo
	[TypecheckedPat]    -- the patterns for an eqn
      	MatchResult	    -- Encapsulates the guards and bindings
\end{code}

\begin{code}
data MatchResult
  = MatchResult
	CanItFail
	Type		-- Type of argument expression

	(CoreExpr -> CoreExpr)
			-- Takes a expression to plug in at the
			-- failure point(s). The expression should
			-- be duplicatable!

	DsMatchContext	-- The context info is used when producing warnings
			-- about shadowed patterns.  It's the context
			-- of the *first* thing matched in this group.
			-- Should perhaps be a list of them all!

data CanItFail = CanFail | CantFail

orFail CantFail CantFail = CantFail
orFail _        _	 = CanFail


mkCoLetsMatchResult :: [CoreBinding] -> MatchResult -> MatchResult
mkCoLetsMatchResult binds (MatchResult can_it_fail ty body_fn cxt)
  = MatchResult can_it_fail ty (\body -> mkCoLetsAny binds (body_fn body)) cxt

mkGuardedMatchResult :: CoreExpr -> MatchResult -> DsM MatchResult
mkGuardedMatchResult pred_expr (MatchResult can_it_fail ty body_fn cxt)
  = returnDs (MatchResult CanFail
			  ty
			  (\fail -> mkCoreIfThenElse pred_expr (body_fn fail) fail)
			  cxt
    )

mkCoPrimCaseMatchResult :: Id				-- Scrutinee
		    -> [(Literal, MatchResult)]	-- Alternatives
		    -> DsM MatchResult
mkCoPrimCaseMatchResult var alts
  = newSysLocalDs (idType var)	`thenDs` \ wild ->
    returnDs (MatchResult CanFail
			  ty1
			  (mk_case alts wild)
			  cxt1)
  where
    ((_,MatchResult _ ty1 _ cxt1) : _) = alts

    mk_case alts wild fail_expr
      = Case (Var var) (PrimAlts final_alts (BindDefault wild fail_expr))
      where
	final_alts = [ (lit, body_fn fail_expr)
		     | (lit, MatchResult _ _ body_fn _) <- alts
		     ]


mkCoAlgCaseMatchResult :: Id				-- Scrutinee
		    -> [(DataCon, [Id], MatchResult)]	-- Alternatives
		    -> DsM MatchResult

mkCoAlgCaseMatchResult var alts
  | isNewTyCon tycon		-- newtype case; use a let
  = ASSERT( newtype_sanity )
    returnDs (mkCoLetsMatchResult [coercion_bind] match_result)

  | otherwise			-- datatype case  
  =	    -- Find all the constructors in the type which aren't
	    -- explicitly mentioned in the alternatives:
    case un_mentioned_constructors of
	[] ->	-- All constructors mentioned, so no default needed
		returnDs (MatchResult can_any_alt_fail
			  	      ty1
				      (mk_case alts (\ignore -> NoDefault))
				      cxt1)

	[con] ->     -- Just one constructor missing, so add a case for it
		     -- We need to build new locals for the args of the constructor,
		     -- and figuring out their types is somewhat tiresome.
		let
			arg_tys = dataConArgTys con tycon_arg_tys
		in
		newSysLocalsDs arg_tys	`thenDs` \ arg_ids ->

		     -- Now we are ready to construct the new alternative
		let
			new_alt = (con, arg_ids, MatchResult CanFail ty1 id NoMatchContext)
		in
		returnDs (MatchResult CanFail
			  	      ty1
				      (mk_case (new_alt:alts) (\ignore -> NoDefault))
				      cxt1)

	other ->      -- Many constructors missing, so use a default case
		newSysLocalDs scrut_ty		`thenDs` \ wild ->
		returnDs (MatchResult CanFail
			  	      ty1
				      (mk_case alts (\fail_expr -> BindDefault wild fail_expr))
				      cxt1)
  where
	-- Common stuff
    scrut_ty = idType var
    (tycon, tycon_arg_tys) = --pprTrace "CoAlgCase:" (pprType PprDebug scrut_ty) $ 
			     getAppTyCon scrut_ty

	-- Stuff for newtype
    (con_id, arg_ids, match_result) = head alts
    arg_id 	   		    = head arg_ids
    coercion_bind		    = NonRec arg_id (Coerce (CoerceOut con_id) 
							    (idType arg_id)
							    (Var var))
    newtype_sanity		    = null (tail alts) && null (tail arg_ids)

	-- Stuff for data types
    data_cons = tyConDataCons tycon

    un_mentioned_constructors
      = uniqSetToList (mkUniqSet data_cons `minusUniqSet` mkUniqSet [ con | (con, _, _) <- alts] )

    match_results = [match_result | (_,_,match_result) <- alts]
    (MatchResult _ ty1 _ cxt1 : _) = match_results
    can_any_alt_fail = foldr1 orFail [can_it_fail | MatchResult can_it_fail _ _ _ <- match_results]

    mk_case alts deflt_fn fail_expr
      = Case (Var var) (AlgAlts final_alts (deflt_fn fail_expr))
      where
	final_alts = [ (con, args, body_fn fail_expr)
		     | (con, args, MatchResult _ _ body_fn _) <- alts
		     ]


combineMatchResults :: MatchResult -> MatchResult -> DsM MatchResult
combineMatchResults (MatchResult CanFail      ty1 body_fn1 cxt1)
		    (MatchResult can_it_fail2 ty2 body_fn2 cxt2)
  = mkFailurePair ty1		`thenDs` \ (bind_fn, duplicatable_expr) ->
    let
	new_body_fn1 = \body1 -> Let (bind_fn body1) (body_fn1 duplicatable_expr)
	new_body_fn2 = \body2 -> new_body_fn1 (body_fn2 body2)
    in
    returnDs (MatchResult can_it_fail2 ty1 new_body_fn2 cxt1)

combineMatchResults match_result1@(MatchResult CantFail ty body_fn1 cxt1)
				  match_result2
  = returnDs match_result1


-- The difference in combineGRHSMatchResults is that there is no
-- need to let-bind to avoid code duplication
combineGRHSMatchResults :: MatchResult -> MatchResult -> DsM MatchResult
combineGRHSMatchResults (MatchResult CanFail     ty1 body_fn1 cxt1)
			(MatchResult can_it_fail ty2 body_fn2 cxt2)
  = returnDs (MatchResult can_it_fail ty1 (\ body -> body_fn1 (body_fn2 body)) cxt1)

combineGRHSMatchResults match_result1 match_result2
  = 	-- Delegate to avoid duplication of code
    combineMatchResults match_result1 match_result2
\end{code}

%************************************************************************
%*									*
\subsection[dsExprToAtom]{Take an expression and produce an atom}
%*									*
%************************************************************************

\begin{code}
dsExprToAtom :: DsCoreArg		    -- The argument expression
	     -> (CoreArg -> DsM CoreExpr)   -- Something taking the argument *atom*,
					    -- and delivering an expression E
	     -> DsM CoreExpr		    -- Either E or let x=arg-expr in E

dsExprToAtom (UsageArg u) continue_with = continue_with (UsageArg u)
dsExprToAtom (TyArg    t) continue_with = continue_with (TyArg    t)
dsExprToAtom (LitArg   l) continue_with = continue_with (LitArg   l)

dsExprToAtom (VarArg (Var v)) continue_with = continue_with (VarArg v)
dsExprToAtom (VarArg (Lit v)) continue_with = continue_with (LitArg v)

dsExprToAtom (VarArg arg_expr) continue_with
  = let
	ty = coreExprType arg_expr
    in
    newSysLocalDs ty			`thenDs` \ arg_id ->
    continue_with (VarArg arg_id)	`thenDs` \ body   ->
    returnDs (
	if isUnboxedType ty
	then Case arg_expr (PrimAlts [] (BindDefault arg_id body))
	else Let (NonRec arg_id arg_expr) body
    )

dsExprsToAtoms :: [DsCoreArg]
	       -> ([CoreArg] -> DsM CoreExpr)
	       -> DsM CoreExpr

dsExprsToAtoms [] continue_with = continue_with []

dsExprsToAtoms (arg:args) continue_with
  = dsExprToAtom   arg 	$ \ arg_atom  ->
    dsExprsToAtoms args $ \ arg_atoms ->
    continue_with (arg_atom:arg_atoms)
\end{code}

%************************************************************************
%*									*
\subsection{Desugarer's versions of some Core functions}
%*									*
%************************************************************************

\begin{code}
type DsCoreArg = GenCoreArg CoreExpr{-NB!-} TyVar UVar

mkAppDs  :: CoreExpr -> [DsCoreArg] -> DsM CoreExpr
mkConDs  :: Id       -> [DsCoreArg] -> DsM CoreExpr
mkPrimDs :: PrimOp   -> [DsCoreArg] -> DsM CoreExpr

mkAppDs fun args
  = dsExprsToAtoms args $ \ atoms ->
    returnDs (mkGenApp fun atoms)

mkConDs con args
  = dsExprsToAtoms args $ \ atoms ->
    returnDs (Con  con atoms)

mkPrimDs op args
  = dsExprsToAtoms args $ \ atoms ->
    returnDs (Prim op  atoms)
\end{code}

\begin{code}
showForErr :: Outputable a => a -> String		-- Boring but useful
showForErr thing = ppShow 80 (ppr PprForUser thing)

mkErrorAppDs :: Id 		-- The error function
	     -> Type		-- Type to which it should be applied
	     -> String		-- The error message string to pass
	     -> DsM CoreExpr

mkErrorAppDs err_id ty msg
  = getSrcLocDs			`thenDs` \ src_loc ->
    let
	full_msg = ppShow 80 (ppBesides [ppr PprForUser src_loc, ppStr ": ", ppStr msg])
	msg_lit  = NoRepStr (_PK_ full_msg)
    in
    returnDs (mkApp (Var err_id) [] [ty] [LitArg msg_lit])
\end{code}

%************************************************************************
%*									*
\subsection[mkSelectorBind]{Make a selector bind}
%*									*
%************************************************************************

This is used in various places to do with lazy patterns.
For each binder $b$ in the pattern, we create a binding:

    b = case v of pat' -> b'

where pat' is pat with each binder b cloned into b'.

ToDo: making these bindings should really depend on whether there's
much work to be done per binding.  If the pattern is complex, it
should be de-mangled once, into a tuple (and then selected from).
Otherwise the demangling can be in-line in the bindings (as here).

Boring!  Boring!  One error message per binder.  The above ToDo is
even more helpful.  Something very similar happens for pattern-bound
expressions.

\begin{code}
mkSelectorBinds :: [TyVar]	    -- Variables wrt which the pattern is polymorphic
		-> TypecheckedPat   -- The pattern
		-> [(Id,Id)]	    -- Monomorphic and polymorphic binders for
				    -- the pattern
		-> CoreExpr    -- Expression to which the pattern is bound
		-> DsM [(Id,CoreExpr)]

mkSelectorBinds tyvars pat locals_and_globals val_expr
  = if is_simple_tuple_pat pat then
	mkTupleBind tyvars [] locals_and_globals val_expr
    else
	mkErrorAppDs iRREFUT_PAT_ERROR_ID res_ty ""	`thenDs` \ error_msg ->
	matchSimply val_expr pat res_ty local_tuple error_msg `thenDs` \ tuple_expr ->
	mkTupleBind tyvars [] locals_and_globals tuple_expr
  where
    locals	= [local | (local, _) <- locals_and_globals]
    local_tuple = mkTupleExpr locals
    res_ty      = coreExprType local_tuple

    is_simple_tuple_pat (TuplePat ps) = all is_var_pat ps
    is_simple_tuple_pat other         = False

    is_var_pat (VarPat v) = True
    is_var_pat other      = False -- Even wild-card patterns aren't acceptable
\end{code}

We're about to match against some patterns.  We want to make some
@Ids@ to use as match variables.  If a pattern has an @Id@ readily at
hand, which should indeed be bound to the pattern as a whole, then use it;
otherwise, make one up.
\begin{code}
selectMatchVars :: [TypecheckedPat] -> DsM [Id]
selectMatchVars pats
  = mapDs var_from_pat_maybe pats
  where
    var_from_pat_maybe (VarPat var)	= returnDs var
    var_from_pat_maybe (AsPat var pat)	= returnDs var
    var_from_pat_maybe (LazyPat pat)	= var_from_pat_maybe pat
    var_from_pat_maybe other_pat
      = newSysLocalDs (outPatType other_pat) -- OK, better make up one...
\end{code}

\begin{code}
mkTupleBind :: [TyVar]	    -- Abstract wrt these...
	-> [DictVar]	    -- ... and these

	-> [(Id, Id)]	    -- Local, global pairs, equal in number
			    -- to the size of the tuple.  The types
			    -- of the globals is the generalisation of
			    -- the corresp local, wrt the tyvars and dicts

	-> CoreExpr    -- Expr whose value is a tuple; the expression
			    -- may mention the tyvars and dicts

	-> DsM [(Id, CoreExpr)]	-- Bindings for the globals
\end{code}

The general call is
\begin{verbatim}
	mkTupleBind tyvars dicts [(l1,g1), ..., (ln,gn)] tup_expr
\end{verbatim}
If $n=1$, the result is:
\begin{verbatim}
	g1 = /\ tyvars -> \ dicts -> rhs
\end{verbatim}
Otherwise, the result is:
\begin{verbatim}
	tup = /\ tyvars -> \ dicts -> tup_expr
	g1  = /\ tyvars -> \ dicts -> case (tup tyvars dicts) of
					(l1, ..., ln) -> l1
	...etc...
\end{verbatim}

\begin{code}
mkTupleBind tyvars dicts [(local,global)] tuple_expr
  = returnDs [(global, mkLam tyvars dicts tuple_expr)]
\end{code}

The general case:

\begin{code}
mkTupleBind tyvars dicts local_global_prs tuple_expr
  = --pprTrace "mkTupleBind:\n" (ppAboves [ppCat (map (pprId PprShowAll) locals), ppCat (map (pprId PprShowAll) globals), {-ppr PprDebug local_tuple, pprType PprDebug res_ty,-} ppr PprDebug tuple_expr]) $

    newSysLocalDs tuple_var_ty	`thenDs` \ tuple_var ->

    zipWithDs (mk_selector (Var tuple_var))
	      local_global_prs
	      [(0::Int) .. (length local_global_prs - 1)]
				`thenDs` \ tup_selectors ->
    returnDs (
	(tuple_var, mkLam tyvars dicts tuple_expr)
	: tup_selectors
    )
  where
    locals, globals :: [Id]
    locals  = [local  | (local,global) <- local_global_prs]
    globals = [global | (local,global) <- local_global_prs]

    no_of_binders = length local_global_prs
    tyvar_tys = mkTyVarTys tyvars

    tuple_var_ty :: Type
    tuple_var_ty
      = mkForAllTys tyvars $
	mkRhoTy theta	   $
	applyTyCon (tupleTyCon no_of_binders)
		   (map idType locals)
      where
	theta = mkTheta (map idType dicts)

    mk_selector :: CoreExpr -> (Id, Id) -> Int -> DsM (Id, CoreExpr)

    mk_selector tuple_var_expr (local, global) which_local
      = mapDs duplicateLocalDs locals{-the whole bunch-} `thenDs` \ binders ->
	let
	    selected = binders !! which_local
	in
	returnDs (
	    global,
	    mkLam tyvars dicts (
		mkTupleSelector
		    (mkValApp (mkTyApp tuple_var_expr tyvar_tys)
			      (map VarArg dicts))
		    binders
		    selected)
	)
\end{code}

@mkTupleExpr@ builds a tuple; the inverse to @mkTupleSelector@.  If it
has only one element, it is the identity function.
\begin{code}
mkTupleExpr :: [Id] -> CoreExpr

mkTupleExpr []	 = Con unitDataCon []
mkTupleExpr [id] = Var id
mkTupleExpr ids	 = mkCon (tupleCon (length ids))
			 [{-usages-}]
			 (map idType ids)
			 [ VarArg i | i <- ids ]
\end{code}


@mkTupleSelector@ builds a selector which scrutises the given
expression and extracts the one name from the list given.
If you want the no-shadowing rule to apply, the caller
is responsible for making sure that none of these names
are in scope.

If there is just one id in the ``tuple'', then the selector is
just the identity.

\begin{code}
mkTupleSelector :: CoreExpr	-- Scrutinee
		-> [Id]			-- The tuple args
		-> Id			-- The selected one
		-> CoreExpr

mkTupleSelector expr [] the_var = panic "mkTupleSelector"

mkTupleSelector expr [var] should_be_the_same_var
  = ASSERT(var == should_be_the_same_var)
    expr

mkTupleSelector expr vars the_var
 = Case expr (AlgAlts [(tupleCon arity, vars, Var the_var)]
			  NoDefault)
 where
   arity = length vars
\end{code}


%************************************************************************
%*									*
\subsection[mkFailurePair]{Code for pattern-matching and other failures}
%*									*
%************************************************************************

Generally, we handle pattern matching failure like this: let-bind a
fail-variable, and use that variable if the thing fails:
\begin{verbatim}
	let fail.33 = error "Help"
	in
	case x of
		p1 -> ...
		p2 -> fail.33
		p3 -> fail.33
		p4 -> ...
\end{verbatim}
Then
\begin{itemize}
\item
If the case can't fail, then there'll be no mention of fail.33, and the
simplifier will later discard it.

\item
If it can fail in only one way, then the simplifier will inline it.

\item
Only if it is used more than once will the let-binding remain.
\end{itemize}

There's a problem when the result of the case expression is of
unboxed type.  Then the type of fail.33 is unboxed too, and
there is every chance that someone will change the let into a case:
\begin{verbatim}
	case error "Help" of
	  fail.33 -> case ....
\end{verbatim}

which is of course utterly wrong.  Rather than drop the condition that
only boxed types can be let-bound, we just turn the fail into a function
for the primitive case:
\begin{verbatim}
	let fail.33 :: Void -> Int#
	    fail.33 = \_ -> error "Help"
	in
	case x of
		p1 -> ...
		p2 -> fail.33 void
		p3 -> fail.33 void
		p4 -> ...
\end{verbatim}

Now fail.33 is a function, so it can be let-bound.

\begin{code}
mkFailurePair :: Type		-- Result type of the whole case expression
	      -> DsM (CoreExpr -> CoreBinding,
				-- Binds the newly-created fail variable
				-- to either the expression or \ _ -> expression
		      CoreExpr)	-- Either the fail variable, or fail variable
				-- applied to unit tuple
mkFailurePair ty
  | isUnboxedType ty
  = newFailLocalDs (voidTy `mkFunTy` ty)	`thenDs` \ fail_fun_var ->
    newSysLocalDs voidTy			`thenDs` \ fail_fun_arg ->
    returnDs (\ body ->
		NonRec fail_fun_var (Lam (ValBinder fail_fun_arg) body),
	      App (Var fail_fun_var) (VarArg voidId))

  | otherwise
  = newFailLocalDs ty 		`thenDs` \ fail_var ->
    returnDs (\ body -> NonRec fail_var body, Var fail_var)
\end{code}