[m-rev.] Re: for review: try goals

Peter Wang novalazy at gmail.com
Thu Feb 19 16:04:23 AEDT 2009


Interdiff.  Now it bootchecks.

--- gws_try_syntax,20090217,a.txt	2009-02-17 17:43:31.000000000 +1100
+++ gws_try_syntax,20090219,a.txt	2009-02-19 14:21:58.000000000 +1100
@@ -2,8 +2,7 @@

 Add support for `try' goals, syntactic sugar on top of the exception handling
 predicates in the standard library.  The syntax is documented in the reference
-manual.  Currently one of the proposed try parameters, io(!IO), is implemented,
-and the user must import the `exception' and `univ' modules explicitly.
+manual.  Currently one of the proposed try parameters, io(!IO), is implemented.

 Try goals are implemented by *two* source-to-source transformations, one at the
 parse tree level, then a later one on the HLDS.  The reason for this is given
@@ -36,6 +35,9 @@
 compiler/mercury_compile.m:
 	Call the try_expand pass near the end of the front-end pass.

+compiler/module_imports.m:
+	Implicitly import `exception' if a `try' goal is seen.
+
 compiler/det_analysis.m:
 	Conform to addition of try goals in HLDS.  Make it not wrap a commit
 	scope around the intermediate try goal (as it might if there are no
@@ -62,7 +64,6 @@
 compiler/mercury_to_mercury.m:
 compiler/mode_util.m:
 compiler/modes.m:
-compiler/module_imports.m:
 compiler/module_qual.m:
 compiler/ordering_mode_constraints.m:
 compiler/polymorphism.m:
@@ -80,6 +81,12 @@
 compiler/unused_imports.m:
 	Conform to changes in HLDS.

+compiler/il_peephole.m:
+compiler/il_asm.m:
+compiler/ilds.m:
+compiler/mlds_to_il.m:
+	Rename some symbols to avoid the new keywords.
+
 library/exception.m:
 	Add two helper predicates for the try goal transformations.

@@ -103,6 +110,8 @@
 tests/hard_coded/try_syntax_5.m:
 tests/hard_coded/try_syntax_6.exp:
 tests/hard_coded/try_syntax_6.m:
+tests/hard_coded/try_syntax_7.exp:
+tests/hard_coded/try_syntax_7.m:
 tests/invalid/Mmakefile:
 tests/invalid/try_bad_params.err_exp:
 tests/invalid/try_bad_params.m:
@@ -110,6 +119,9 @@
 tests/invalid/try_io_else.m:
 	Add test cases.

+tests/debugger/declarative/catch.m:
+	The module name is now a keyword so requires brackets.
+
 tests/invalid/trace_goal_env.err_exp:
 	Update test case for fixed spelling for "parameter".

diff --git a/compiler/add_clause.m b/compiler/add_clause.m
index d51ef39..6e71498 100644
--- a/compiler/add_clause.m
+++ b/compiler/add_clause.m
@@ -1457,7 +1457,7 @@ transform_try_expr_with_io(IOStateVarUnrenamed,
IOStateVar, Goal0, Then0,
     ResultIsSucceededUnify0 =
         unify_expr(
             ResultVarTerm,
-            functor(atom("succeeded"), [NullTupleTerm], Context),
+            exception_functor("succeeded", NullTupleTerm, Context),
             purity_pure
         ) - Context,
     transform_goal(ResultIsSucceededUnify0, Renaming, ResultIsSucceededUnify,
@@ -1582,7 +1582,7 @@ transform_try_expr_without_io(Goal0, Then0,
MaybeElse0, Catches0,
     ResultIsSucceededUnify0 =
         unify_expr(
             ResultVarTerm,
-            functor(atom("succeeded"), [NullTupleTerm], Context),
+            exception_functor("succeeded", NullTupleTerm, Context),
             purity_pure
         ) - Context,
     (
@@ -1629,7 +1629,7 @@ make_exception_handling_disjunct(ResultVarTerm,
ExcpVarTerm, Catches,
     ResultIsExceptionUnify =
         unify_expr(
             ResultVarTerm,
-            functor(atom("exception"), [ExcpVarTerm], Context),
+            exception_functor("exception", ExcpVarTerm, Context),
             purity_pure
         ) - Context,
     make_catch_ite_chain(ResultVarTerm, ExcpVarTerm, Catches, MaybeCatchAny,
@@ -1654,20 +1654,21 @@ make_catch_ite_chain(ResultVarTerm,
ExcpVarTerm, Catches, MaybeCatchAny,
         (
             MaybeCatchAny = yes(catch_any_expr(CatchAnyVar, CatchAnyGoal)),
             % With a catch_any part, end the if-then-else chain with:
-            %   CatchAnyVar = univ_value(Excp),
+            %   CatchAnyVar = exc_univ_value(Excp),
             %   CatchAnyGoal
             CatchAnyGoal = _ - Context,
             GetUnivValue = unify_expr(
                 variable(CatchAnyVar, Context),
-                functor(atom("univ_value"), [ExcpVarTerm], Context),
+                exception_functor("exc_univ_value", ExcpVarTerm, Context),
                 purity_pure) - Context,
             Goal = conj_expr(GetUnivValue, CatchAnyGoal) - Context
         ;
             MaybeCatchAny = no,
             % Without a catch_any part, end the if-then-else chain
             % by rethrowing the exception.
-            Goal = call_expr(string_to_sym_name("exception.rethrow"),
-                [ResultVarTerm], purity_pure) - get_term_context(ExcpVarTerm)
+            Rethrow = qualified(mercury_exception_module, "rethrow"),
+            Goal = call_expr(Rethrow, [ResultVarTerm], purity_pure)
+                - get_term_context(ExcpVarTerm)
         )
     ).

@@ -1675,7 +1676,8 @@ make_catch_ite_chain(ResultVarTerm, ExcpVarTerm,
Catches, MaybeCatchAny,
     goal::out) is det.

 make_catch_pattern_unify_goal(CatchPatternTerm, ExcpVarTerm, Goal) :-
-    GoalExpr = call_expr(string_to_sym_name("univ_to_type"),
+    GoalExpr = call_expr(
+        qualified(mercury_exception_module, "exc_univ_to_type"),
         [ExcpVarTerm, CatchPatternTerm], purity_pure),
     Goal = GoalExpr - get_term_context(CatchPatternTerm).

@@ -1684,6 +1686,12 @@ make_catch_pattern_unify_goal(CatchPatternTerm,
ExcpVarTerm, Goal) :-
 magic_exception_result_sym_name =
     qualified(mercury_exception_module, "magic_exception_result").

+:- func exception_functor(string, prog_term, term.context) = prog_term.
+
+exception_functor(Atom, Arg, Context) = Term :-
+    construct_qualified_term(qualified(mercury_exception_module, Atom),
+        [Arg], Context, Term).
+
 %----------------------------------------------------------------------------%

 :- func this_file = string.
diff --git a/compiler/hlds_goal.m b/compiler/hlds_goal.m
index 785775b..39c0cab 100644
--- a/compiler/hlds_goal.m
+++ b/compiler/hlds_goal.m
@@ -319,8 +319,8 @@
     ;       top_level_atomic_goal
     ;       nested_atomic_goal.

-:- type catch
-    --->    catch(
+:- type catch_part
+    --->    catch_part(
                 catch_expr  :: hlds_goal_expr,
                 catch_goal  :: hlds_goal
             ).
diff --git a/compiler/il_peephole.m b/compiler/il_peephole.m
index 7eebe64..99d60bc 100644
--- a/compiler/il_peephole.m
+++ b/compiler/il_peephole.m
@@ -276,12 +276,12 @@ match(ldc(Type, Const), VerifyOnly, [stloc(Var)|
Instrs0], Instrs) :-

     % Two patterns begin with start_scope.

-match(start_block(scope(Locals), Id), VerifyOnly, !Instrs) :-
+match(start_block(bt_scope(Locals), Id), VerifyOnly, !Instrs) :-
     VerifyOnly = no,
-    ( match_start_scope_1(start_block(scope(Locals), Id), !Instrs) ->
+    ( match_start_scope_1(start_block(bt_scope(Locals), Id), !Instrs) ->
         true
     ;
-        match_start_scope_2(start_block(scope(Locals), Id), !Instrs)
+        match_start_scope_2(start_block(bt_scope(Locals), Id), !Instrs)
     ).

     % If this is a scope with a local variable that is stored to but not
@@ -296,7 +296,7 @@ match(start_block(scope(Locals), Id), VerifyOnly,
!Instrs) :-
     %
 :- pred match_start_scope_1(instr::in, instrs::in, instrs::out) is semidet.

-match_start_scope_1(start_block(scope(Locals), Id), Instrs0, Instrs) :-
+match_start_scope_1(start_block(bt_scope(Locals), Id), Instrs0, Instrs) :-
     % Is this variable a local that is unused?
     IsUnusedLocal = (pred(V::in) is semidet :-
         % Var is in the locals
@@ -357,7 +357,7 @@ match_start_scope_1(start_block(scope(Locals),
Id), Instrs0, Instrs) :-
     Comment = string.format(
         "peephole: dup, stloc(%s) --> nothing (%s unused in scope)",
         [s(VarName), s(VarName)]),
-    Instrs = list.condense([[start_block(scope(Locals), Id)],
+    Instrs = list.condense([[start_block(bt_scope(Locals), Id)],
         PreStlocInstrs,
         Nops,
         [comment(Comment)],
@@ -369,7 +369,7 @@ match_start_scope_1(start_block(scope(Locals),
Id), Instrs0, Instrs) :-
     %
 :- pred match_start_scope_2(instr::in, instrs::in, instrs::out) is semidet.

-match_start_scope_2(start_block(scope(Locals), Id), Instrs0, Instrs) :-
+match_start_scope_2(start_block(bt_scope(Locals), Id), Instrs0, Instrs) :-
     no_handwritten_code(Instrs0, Id),

     % The pattern.
@@ -391,7 +391,7 @@ match_start_scope_2(start_block(scope(Locals),
Id), Instrs0, Instrs) :-
             [s(VarName)], CommentStr),
         Comment = comment(CommentStr)
     ), UnusedLocals, Comments),
-    Replacement = [start_block(scope(UsedLocals), Id)],
+    Replacement = [start_block(bt_scope(UsedLocals), Id)],

     Instrs = list.condense([Comments, Replacement, Instrs0]).

@@ -402,7 +402,7 @@ match_start_scope_2(start_block(scope(Locals),
Id), Instrs0, Instrs) :-
     % is incomplete. This procedure is not yet called from anywhere.
 :- pred match4(instr::in, instrs::in, instrs::out) is semidet.

-match4(start_block(scope([]), _), Instrs0, Instrs) :-
+match4(start_block(bt_scope([]), _), Instrs0, Instrs) :-
     Replacement = [],
     Rest = Instrs0,
     Instrs = list.append(Replacement, Rest).
@@ -591,16 +591,16 @@ can_call(unbox(_Type))              = no.
 :- func equivalent_to_nop(instr) = bool.

 equivalent_to_nop(comment(_))                   = yes.
-equivalent_to_nop(start_block(scope(_), _))     = yes.
-equivalent_to_nop(end_block(scope(_), _))       = yes.
+equivalent_to_nop(start_block(bt_scope(_), _))  = yes.
+equivalent_to_nop(end_block(bt_scope(_), _))    = yes.
 equivalent_to_nop(nop)                          = yes.
 equivalent_to_nop(context(_, _))                = yes.

 equivalent_to_nop(il_asm_code(_, _))            = no.
-equivalent_to_nop(start_block(try, _))          = no.
-equivalent_to_nop(end_block(try, _))            = no.
-equivalent_to_nop(start_block(catch(_), _))     = no.
-equivalent_to_nop(end_block(catch(_), _))       = no.
+equivalent_to_nop(start_block(bt_try, _))       = no.
+equivalent_to_nop(end_block(bt_try, _))         = no.
+equivalent_to_nop(start_block(bt_catch(_), _))  = no.
+equivalent_to_nop(end_block(bt_catch(_), _))    = no.
 equivalent_to_nop(label(_Label))                = no.
 equivalent_to_nop(call(_MethodRef))             = no.
 equivalent_to_nop(calli(_Signature))            = no.
diff --git a/compiler/ilasm.m b/compiler/ilasm.m
index 0901c4a..a987a97 100644
--- a/compiler/ilasm.m
+++ b/compiler/ilasm.m
@@ -1013,13 +1013,13 @@ output_debug_instruction(Instr, !Info, !IO) :-
     ; Instr = context(_, _) ->
         % Contexts are messy, let's ignore them for now.
         true
-    ; Instr = start_block(catch(ClassName), Id) ->
-        output_instr(start_block(catch(ClassName), Id), !Info, !IO),
+    ; Instr = start_block(bt_catch(ClassName), Id) ->
+        output_instr(start_block(bt_catch(ClassName), Id), !Info, !IO),
         io.write_string("\n", !IO),
         io.write_string("\t", !IO),
         output_trace_instr(Instr, !Info, !IO),
         io.write_string("\n", !IO)
-    ; Instr = start_block(scope(Locals), Id) ->
+    ; Instr = start_block(bt_scope(Locals), Id) ->
         string.format("{\t// #%d", [i(Id)], S),
         io.write_string(S, !IO),
         io.nl(!IO),
@@ -1112,7 +1112,7 @@ output_instr(comment(Comment), !Info, !IO) :-
 output_instr(label(Label), !Info, !IO) :-
     output_label(Label, !IO),
     io.write_string(":", !IO).
-output_instr(start_block(scope(Locals), Id), !Info, !IO) :-
+output_instr(start_block(bt_scope(Locals), Id), !Info, !IO) :-
     io.write_string("{", !IO),
     io.write_string("\t// #", !IO),
     io.write_int(Id, !IO),
@@ -1124,26 +1124,26 @@ output_instr(start_block(scope(Locals), Id),
!Info, !IO) :-
         ilasm.write_list(Locals, ",\n\t\t", output_local, !Info, !IO),
         io.write_string("\n\t)\n", !IO)
     ).
-output_instr(start_block(try, Id), !Info, !IO) :-
+output_instr(start_block(bt_try, Id), !Info, !IO) :-
     io.write_string(".try {", !IO),
     io.write_string("\t// #", !IO),
     io.write_int(Id, !IO).
-output_instr(start_block(catch(ClassName), Id), !Info, !IO) :-
+output_instr(start_block(bt_catch(ClassName), Id), !Info, !IO) :-
     io.write_string("catch ", !IO),
     output_class_name(ClassName, !Info, !IO),
     io.write_string(" {", !IO),
     io.write_string("\t// #", !IO),
     io.write_int(Id, !IO).
-output_instr(end_block(scope(_), Id), !Info, !IO) :-
+output_instr(end_block(bt_scope(_), Id), !Info, !IO) :-
     io.write_string("}", !IO),
     io.write_string("\t// #", !IO),
     io.write_int(Id, !IO).
-output_instr(end_block(catch(_), Id), !Info, !IO) :-
+output_instr(end_block(bt_catch(_), Id), !Info, !IO) :-
     io.write_string("}", !IO),
     io.write_string("\t// #", !IO),
     io.write_int(Id, !IO),
     io.write_string(" (catch block)", !IO).
-output_instr(end_block(try, Id), !Info, !IO) :-
+output_instr(end_block(bt_try, Id), !Info, !IO) :-
     io.write_string("}", !IO),
     io.write_string("\t// #", !IO),
     io.write_int(Id, !IO),
diff --git a/compiler/ilds.m b/compiler/ilds.m
index c6945de..b3e5bba 100644
--- a/compiler/ilds.m
+++ b/compiler/ilds.m
@@ -269,10 +269,10 @@
     % handwritten code, or can introduce try or catch code.
     %
 :- type blocktype
-    --->    scope(locals)
+    --->    bt_scope(locals)
             % scope just introduces a scope for local variables
-    ;       try
-    ;       catch(class_name).
+    ;       bt_try
+    ;       bt_catch(class_name).

     % Each block has a unique identifier (mainly so you can tell which
     % ones match up without counting them).
@@ -511,9 +511,9 @@ calculate_max_stack_2([I | Instrs], Current, Max) =

 get_stack_difference(end_block(_, _))           = 0.
 get_stack_difference(comment(_))                = 0.
-get_stack_difference(start_block(scope(_), _))  = 0.
-get_stack_difference(start_block(try, _))       = 0.
-get_stack_difference(start_block(catch(_), _))  = 1.
+get_stack_difference(start_block(bt_scope(_), _)) = 0.
+get_stack_difference(start_block(bt_try, _))      = 0.
+get_stack_difference(start_block(bt_catch(_), _)) = 1.
 get_stack_difference(context(_, _))             = 0.
 get_stack_difference(label(_Label))             = 0.
 get_stack_difference(il_asm_code(_, _))         = 0.
diff --git a/compiler/mlds_to_il.m b/compiler/mlds_to_il.m
index d4d56ae..86f974d 100644
--- a/compiler/mlds_to_il.m
+++ b/compiler/mlds_to_il.m
@@ -1158,10 +1158,10 @@ generate_method(_, IsCons, mlds_defn(Name,
Context, Flags, Entity),
         context_node(Context) ++
         from_list(CtorInstrs) ++
         context_node(Context) ++
-        singleton(start_block(scope(Locals), BlockId)) ++
+        singleton(start_block(bt_scope(Locals), BlockId)) ++
         InstrsTree1 ++
         MaybeRet ++
-        singleton(end_block(scope(Locals), BlockId)),
+        singleton(end_block(bt_scope(Locals), BlockId)),

     % If this is main, add the entrypoint, set a flag, wrap the code
     % in an exception handler and call the initialization instructions
@@ -1228,20 +1228,20 @@ generate_method(_, IsCons, mlds_defn(Name,
Context, Flags, Entity),

         CatchAnyException =
             from_list([
-                start_block(catch(ExceptionClassName), OuterCatchBlockId),
+                start_block(bt_catch(ExceptionClassName), OuterCatchBlockId),
                 ldstr("\nUncaught system exception: \n"),
                 call(WriteString),
                 call(WriteObject),
                 ldc(int32, i(1)),
                 call(il_set_exit_code),
                 leave(label_target(DoneLabel)),
-                end_block(catch(ExceptionClassName), OuterCatchBlockId)
+                end_block(bt_catch(ExceptionClassName), OuterCatchBlockId)
             ]),

         % Code to catch Mercury exceptions.
         CatchUserException =
             from_list([
-                start_block(catch(MercuryExceptionClassName),
+                start_block(bt_catch(MercuryExceptionClassName),
                     InnerCatchBlockId),
                 ldfld(FieldRef),
                 call(WriteUncaughtException),
@@ -1250,7 +1250,7 @@ generate_method(_, IsCons, mlds_defn(Name,
Context, Flags, Entity),
                 call(il_set_exit_code),

                 leave(label_target(DoneLabel)),
-                end_block(catch(MercuryExceptionClassName),
+                end_block(bt_catch(MercuryExceptionClassName),
                     InnerCatchBlockId)
             ]),

@@ -1283,21 +1283,21 @@ generate_method(_, IsCons, mlds_defn(Name,
Context, Flags, Entity),
         InstrsTree =
             from_list([
                 % outer try block
-                start_block(try, OuterTryBlockId),
+                start_block(bt_try, OuterTryBlockId),

                 % inner try block
-                start_block(try, InnerTryBlockId)
+                start_block(bt_try, InnerTryBlockId)
             ]) ++
             cord.map(RenameRets, InstrsTree2) ++
             from_list([
                 leave(label_target(DoneLabel)),
-                end_block(try, InnerTryBlockId)
+                end_block(bt_try, InnerTryBlockId)
             ]) ++
             % inner catch block
             CatchUserException ++
             from_list([
                 leave(label_target(DoneLabel)),
-                end_block(try, OuterTryBlockId)
+                end_block(bt_try, OuterTryBlockId)
             ]) ++
             % outer catch block
             CatchAnyException ++
@@ -1649,7 +1649,7 @@ statement_to_il(statement(BlockStmt, Context),
Instrs, !Info) :-
     DataRep = !.Info ^ il_data_rep,
     list.map((pred((K - V)::in, (K - W)::out) is det :-
         W = mlds_type_to_ilds_type(DataRep, V)), Locals, ILLocals),
-    Scope = scope(ILLocals),
+    Scope = bt_scope(ILLocals),
     Instrs =
         context_node(Context) ++
         singleton(start_block(Scope, BlockId)) ++
@@ -1900,17 +1900,17 @@ statement_to_il(statement(TryCommitStmt,
Context), Instrs, !Info) :-
         context_node(Context) ++
         comment_node("try_commit/3") ++

-        singleton(start_block(try, TryBlockId)) ++
+        singleton(start_block(bt_try, TryBlockId)) ++
         GoalInstrsTree ++
         singleton(leave(label_target(DoneLabel))) ++
-        singleton(end_block(try, TryBlockId)) ++
+        singleton(end_block(bt_try, TryBlockId)) ++

-        singleton(start_block(catch(ClassName), CatchBlockId)) ++
+        singleton(start_block(bt_catch(ClassName), CatchBlockId)) ++
         comment_node("discard the exception object") ++
         singleton(pop) ++
         HandlerInstrsTree ++
         singleton(leave(label_target(DoneLabel))) ++
-        singleton(end_block(catch(ClassName), CatchBlockId)) ++
+        singleton(end_block(bt_catch(ClassName), CatchBlockId)) ++
         singleton(label(DoneLabel)).

 statement_to_il(statement(ComputedGotoStmt, Context), Instrs, !Info) :-
diff --git a/compiler/module_imports.m b/compiler/module_imports.m
index 463dea5..90b7e6d 100644
--- a/compiler/module_imports.m
+++ b/compiler/module_imports.m
@@ -437,7 +437,8 @@ add_implicit_imports(Items, Globals, !ImportDeps,
!UseDeps) :-
     !:ImportDeps = [mercury_public_builtin_module | !.ImportDeps],
     !:UseDeps = [mercury_private_builtin_module | !.UseDeps],
     items_need_imports(Items, no, ItemsNeedTabling,
-        no, ItemsNeedTablingStatistics, no, ItemsNeedSTM),
+        no, ItemsNeedTablingStatistics, no, ItemsNeedSTM,
+        no, ItemsNeedException),
     % We should include mercury_table_builtin_module if the Items contain
     % a tabling pragma, or if one of --use-minimal-model (either kind) and
     % --trace-table-io is specified. In the former case, we may also need
@@ -479,6 +480,12 @@ add_implicit_imports(Items, Globals, !ImportDeps,
!UseDeps) :-
     ;
         ItemsNeedSTM = no
     ),
+    (
+        ItemsNeedException = yes,
+        !:UseDeps = [mercury_exception_module | !.UseDeps]
+    ;
+        ItemsNeedException = no
+    ),
     globals.lookup_bool_option(Globals, profile_deep, Deep),
     (
         Deep = yes,
@@ -527,12 +534,13 @@ add_implicit_imports(Items, Globals,
!ImportDeps, !UseDeps) :-
     ).

 :- pred items_need_imports(list(item)::in,
-    bool::in, bool::out, bool::in, bool::out, bool::in, bool::out) is det.
+    bool::in, bool::out, bool::in, bool::out, bool::in, bool::out,
+    bool::in, bool::out) is det.

 items_need_imports([], !ItemsNeedTabling,
-        !ItemsNeedTablingStatistics, !ItemsNeedSTM).
+        !ItemsNeedTablingStatistics, !ItemsNeedSTM, !ItemsNeedException).
 items_need_imports([Item | Items], !ItemsNeedTabling,
-        !ItemsNeedTablingStatistics, !ItemsNeedSTM) :-
+        !ItemsNeedTablingStatistics, !ItemsNeedSTM, !ItemsNeedException) :-
     (
         Item = item_pragma(ItemPragma),
         ItemPragma = item_pragma_info(_, Pragma, _, _),
@@ -541,65 +549,78 @@ items_need_imports([Item | Items], !ItemsNeedTabling,
         !:ItemsNeedTabling = yes,
         (
             MaybeAttributes = no,
-            % We cannot be done yet. If !.ItemsNeedTablingStatistics and
-            % !.ItemsNeedSTM were already both `yes', !.ItemsNeedTabling
-            % would have been too, and we would have stopped before looking
-            % at this item.
-            items_need_imports(Items, !ItemsNeedTabling,
-                !ItemsNeedTablingStatistics, !ItemsNeedSTM)
+            maybe_items_need_imports(Items, !ItemsNeedTabling,
+                !ItemsNeedTablingStatistics, !ItemsNeedSTM,
+                !ItemsNeedException)
         ;
             MaybeAttributes = yes(Attributes),
             StatsAttr = Attributes ^ table_attr_statistics,
             (
                 StatsAttr = table_gather_statistics,
                 !:ItemsNeedTablingStatistics = yes,
-                (
-                    !.ItemsNeedSTM = yes
-                    % There is nothing left to search for; stop recursing.
-                ;
-                    !.ItemsNeedSTM = no,
-                    items_need_imports(Items, !ItemsNeedTabling,
-                        !ItemsNeedTablingStatistics, !ItemsNeedSTM)
-                )
+                maybe_items_need_imports(Items, !ItemsNeedTabling,
+                    !ItemsNeedTablingStatistics, !ItemsNeedSTM,
+                    !ItemsNeedException)
             ;
                 StatsAttr = table_dont_gather_statistics
             )
         )
     ;
-        Item = item_clause(ItemClause),
-        Body = ItemClause ^ cl_body,
-        goal_contains_stm_atomic(Body) = yes
+        Item = item_clause(ItemClause)
     ->
-        !:ItemsNeedSTM = yes,
-        (
-            !.ItemsNeedTabling = yes,
-            !.ItemsNeedTablingStatistics = yes
-        ->
-            % There is nothing left to search for; stop recursing.
-            true
+        Body = ItemClause ^ cl_body,
+        goal_contains_stm_atomic_or_try(Body, ContainsAtomic, ContainsTry),
+        ( ContainsAtomic = yes ->
+            !:ItemsNeedSTM = yes,
+            !:ItemsNeedException = yes
+        ; ContainsTry = yes ->
+            !:ItemsNeedException = yes
         ;
-            items_need_imports(Items, !ItemsNeedTabling,
-                !ItemsNeedTablingStatistics, !ItemsNeedSTM)
-        )
+            true
+        ),
+        maybe_items_need_imports(Items, !ItemsNeedTabling,
+            !ItemsNeedTablingStatistics, !ItemsNeedSTM, !ItemsNeedException)
+    ;
+        items_need_imports(Items, !ItemsNeedTabling,
+            !ItemsNeedTablingStatistics, !ItemsNeedSTM, !ItemsNeedException)
+    ).
+
+:- pred maybe_items_need_imports(list(item)::in,
+    bool::in, bool::out, bool::in, bool::out, bool::in, bool::out,
+    bool::in, bool::out) is det.
+
+maybe_items_need_imports(Items, !ItemsNeedTabling, !ItemsNeedTablingStatistics,
+        !ItemsNeedSTM, !ItemsNeedException) :-
+    (
+        !.ItemsNeedTabling = yes,
+        !.ItemsNeedTablingStatistics = yes,
+        !.ItemsNeedSTM = yes,
+        !.ItemsNeedException = yes
+    ->
+        % There is nothing left to search for; stop recursing.
+        true
     ;
         items_need_imports(Items, !ItemsNeedTabling,
-            !ItemsNeedTablingStatistics, !ItemsNeedSTM)
+            !ItemsNeedTablingStatistics, !ItemsNeedSTM, !ItemsNeedException)
     ).

-:- func goal_contains_stm_atomic(goal) = bool.
+:- pred goal_contains_stm_atomic_or_try(goal::in, bool::out, bool::out) is det.

-goal_contains_stm_atomic(GoalExpr - _Context) = ContainsAtomic :-
+goal_contains_stm_atomic_or_try(GoalExpr - _Context,
+        ContainsAtomic, ContainsTry) :-
     (
         ( GoalExpr = true_expr
         ; GoalExpr = fail_expr
         ),
-        ContainsAtomic = no
+        ContainsAtomic = no,
+        ContainsTry = no
     ;
         ( GoalExpr = conj_expr(SubGoalA, SubGoalB)
         ; GoalExpr = par_conj_expr(SubGoalA, SubGoalB)
         ; GoalExpr = disj_expr(SubGoalA, SubGoalB)
         ),
-        ContainsAtomic = two_goals_contain_stm_atomic(SubGoalA, SubGoalB)
+        two_goals_contain_stm_atomic_or_try(SubGoalA, SubGoalB,
+            ContainsAtomic, ContainsTry)
     ;
         ( GoalExpr = some_expr(_, SubGoal)
         ; GoalExpr = all_expr(_, SubGoal)
@@ -612,52 +633,76 @@ goal_contains_stm_atomic(GoalExpr - _Context) =
ContainsAtomic :-
             SubGoal)
         ; GoalExpr = trace_expr(_, _, _, _, SubGoal)
         ),
-        ContainsAtomic = goal_contains_stm_atomic(SubGoal)
+        goal_contains_stm_atomic_or_try(SubGoal, ContainsAtomic, ContainsTry)
     ;
         GoalExpr = try_expr(_, SubGoal, Then, MaybeElse, Catches, CatchAny),
         ContainsAtomic = maybe_goals_contain_stm_atomic([
             yes(SubGoal), yes(Then), MaybeElse,
             maybe_catch_any_expr_goal(CatchAny) |
             list.map(yes_catch_expr_goal, Catches)
-        ])
+        ]),
+        ContainsTry = yes
     ;
         ( GoalExpr = implies_expr(SubGoalA, SubGoalB)
         ; GoalExpr = equivalent_expr(SubGoalA, SubGoalB)
         ),
-        ContainsAtomic = two_goals_contain_stm_atomic(SubGoalA, SubGoalB)
+        two_goals_contain_stm_atomic_or_try(SubGoalA, SubGoalB,
+            ContainsAtomic, ContainsTry)
     ;
         GoalExpr = not_expr(SubGoal),
-        ContainsAtomic = goal_contains_stm_atomic(SubGoal)
+        goal_contains_stm_atomic_or_try(SubGoal, ContainsAtomic, ContainsTry)
     ;
         GoalExpr = if_then_else_expr(_, _, Cond, Then, Else),
-        ContainsAtomic = three_goals_contain_stm_atomic(Cond, Then, Else)
+        three_goals_contain_stm_atomic_or_try(Cond, Then, Else,
+            ContainsAtomic, ContainsTry)
     ;
         GoalExpr = atomic_expr(_, _, _, _, _),
-        ContainsAtomic = yes
+        ContainsAtomic = yes,
+        ContainsTry = no
     ;
         ( GoalExpr = event_expr(_, _)
         ; GoalExpr = call_expr(_, _, _)
         ; GoalExpr = unify_expr(_, _, _)
         ),
-        ContainsAtomic = no
+        ContainsAtomic = no,
+        ContainsTry = no
     ).

-:- func two_goals_contain_stm_atomic(goal, goal) = bool.
+:- pred two_goals_contain_stm_atomic_or_try(goal::in, goal::in,
+    bool::out, bool::out) is det.

-two_goals_contain_stm_atomic(GoalA, GoalB) = ContainsAtomic :-
-    ( goal_contains_stm_atomic(GoalA) = yes ->
-        ContainsAtomic = yes
+two_goals_contain_stm_atomic_or_try(GoalA, GoalB,
+        ContainsAtomic, ContainsTry) :-
+    goal_contains_stm_atomic_or_try(GoalA, ContainsAtomicA, ContainsTryA),
+    (
+        ContainsAtomicA = yes,
+        ContainsTryA = yes
+    ->
+        ContainsAtomic = yes,
+        ContainsTry = yes
     ;
-        ContainsAtomic = goal_contains_stm_atomic(GoalB)
+        goal_contains_stm_atomic_or_try(GoalB, ContainsAtomicB, ContainsTryB),
+        bool.or(ContainsAtomicA, ContainsAtomicB, ContainsAtomic),
+        bool.or(ContainsTryA, ContainsTryB, ContainsTry)
     ).

-:- func three_goals_contain_stm_atomic(goal, goal, goal) = bool.
+:- pred three_goals_contain_stm_atomic_or_try(goal::in, goal::in, goal::in,
+    bool::out, bool::out) is det.

-three_goals_contain_stm_atomic(GoalA, GoalB, GoalC) = ContainsAtomic :-
-    ( goal_contains_stm_atomic(GoalA) = yes ->
-        ContainsAtomic = yes
+three_goals_contain_stm_atomic_or_try(GoalA, GoalB, GoalC,
+        ContainsAtomic, ContainsTry) :-
+    two_goals_contain_stm_atomic_or_try(GoalA, GoalB,
+        ContainsAtomicAB, ContainsTryAB),
+    (
+        ContainsAtomicAB = yes,
+        ContainsTryAB = yes
+    ->
+        ContainsAtomic = yes,
+        ContainsTry = yes
     ;
-        ContainsAtomic = two_goals_contain_stm_atomic(GoalB, GoalC)
+        goal_contains_stm_atomic_or_try(GoalC, ContainsAtomicC, ContainsTryC),
+        bool.or(ContainsAtomicAB, ContainsAtomicC, ContainsAtomic),
+        bool.or(ContainsTryAB, ContainsTryC, ContainsTry)
     ).

 :- func maybe_goals_contain_stm_atomic(list(maybe(goal))) = bool.
@@ -666,7 +711,7 @@ maybe_goals_contain_stm_atomic([]) = no.
 maybe_goals_contain_stm_atomic([MaybeGoal | MaybeGoals]) = ContainsAtomic :-
     (
         MaybeGoal = yes(Goal),
-        goal_contains_stm_atomic(Goal) = yes
+        goal_contains_stm_atomic_or_try(Goal, yes, _)
     ->
         ContainsAtomic = yes
     ;
diff --git a/compiler/try_expand.m b/compiler/try_expand.m
index 2831312..b2801bb 100644
--- a/compiler/try_expand.m
+++ b/compiler/try_expand.m
@@ -114,7 +114,9 @@
 %              OutputTuple = { <BoundVars> }
 %          ), TryResult),
 %      (
-%          TryResult = succeeded({ <BoundVars> }),
+%          TryResult = succeeded(TmpTupleVar),
+%          inst_cast(TmpTupleVar, TupleVar),
+%          TupleVar = { <BoundVars> },
 %          <Then>
 %      ;
 %          TryResult = failed,
@@ -131,7 +133,9 @@
 %              OutputTuple = { <BoundVars> }
 %          ), TryResult),
 %      (
-%          TryResult = succeeded({ <BoundVars> }),
+%          TryResult = succeeded(TmpTupleVar),
+%          inst_cast(TmpTupleVar, TupleVar),
+%          TupleVar = { <BoundVars> },
 %          <Then>
 %      ;
 %          TryResult = exception(Excp),
@@ -145,7 +149,9 @@
 %              OutputTuple = { <BoundVars> }
 %          ), TryResult, !IO),
 %      (
-%          TryResult = succeeded({ <BoundVars> }),
+%          TryResult = succeeded(TmpTupleVar),
+%          inst_cast(TmpTupleVar, TupleVar),
+%          TupleVar = { <BoundVars> },
 %          <Then>
 %      ;
 %          TryResult = exception(Excp),
@@ -155,23 +161,26 @@
 %   We have to rename an io.state variable in ExcpHandling so that the sequence
 %   begins with the output I/O state of the `try_io' call.
 %
+% The inst casts preserve the known insts of the BoundVars, which were lost due
+% to the calls to try*.
+%
 % The <ExcpHandling> parts can be passed through from the pre-transformation.
 % If a `catch_any' is present the exception handling looks like this:
 %
-%      ( univ_to_type(Excp, <CatchPattern1>) ->
+%      ( exc_univ_to_type(Excp, <CatchPattern1>) ->
 %          <CatchGoal1>
-%      ; univ_to_type(Excp, <CatchPattern2>) ->
+%      ; exc_univ_to_type(Excp, <CatchPattern2>) ->
 %          <CatchGoal2>
 %      ;
-%          CatchAnyVar = univ_value(Excp),
+%          CatchAnyVar = exc_univ_value(Excp),
 %          <CatchAnyGoal>
 %      )
 %
 % Otherwise, if `catch_any' is not present:
 %
-%      ( univ_to_type(Excp, <CatchPattern1>) ->
+%      ( exc_univ_to_type(Excp, <CatchPattern1>) ->
 %          <CatchGoal1>
-%      ; univ_to_type(Excp, <CatchPattern2>) ->
+%      ; exc_univ_to_type(Excp, <CatchPattern2>) ->
 %          <CatchGoal2>
 %      ;
 %          rethrow(TryResult)
@@ -199,6 +208,7 @@

 :- import_module check_hlds.det_analysis.
 :- import_module check_hlds.det_report.
+:- import_module check_hlds.inst_util.
 :- import_module check_hlds.modes.
 :- import_module check_hlds.polymorphism.
 :- import_module hlds.goal_util.
@@ -231,17 +241,25 @@
 %-----------------------------------------------------------------------------%

 expand_try_goals(!ModuleInfo, !IO) :-
-    some [!Globals] (
-        module_info_get_globals(!.ModuleInfo, !:Globals),
-        disable_det_warnings(OptionsToRestore, !Globals),
-        module_info_set_globals(!.Globals, !ModuleInfo),
-
-        module_info_predids(PredIds, !ModuleInfo),
-        list.foldl2(expand_try_goals_in_pred, PredIds, !ModuleInfo, !IO),
-
-        module_info_get_globals(!.ModuleInfo, !:Globals),
-        restore_det_warnings(OptionsToRestore, !Globals),
-        module_info_set_globals(!.Globals, !ModuleInfo)
+    % The exception module is implicitly imported if any try goals were seen,
+    % so if the exception module is not imported then we know there are no try
+    % goals to be expanded.
+    module_info_get_imported_module_specifiers(!.ModuleInfo, ImportedModules),
+    ( set.contains(ImportedModules, mercury_exception_module) ->
+        some [!Globals] (
+            module_info_get_globals(!.ModuleInfo, !:Globals),
+            disable_det_warnings(OptionsToRestore, !Globals),
+            module_info_set_globals(!.Globals, !ModuleInfo),
+
+            module_info_predids(PredIds, !ModuleInfo),
+            list.foldl2(expand_try_goals_in_pred, PredIds, !ModuleInfo, !IO),
+
+            module_info_get_globals(!.ModuleInfo, !:Globals),
+            restore_det_warnings(OptionsToRestore, !Globals),
+            module_info_set_globals(!.Globals, !ModuleInfo)
+        )
+    ;
+        true
     ).

 :- pred expand_try_goals_in_pred(pred_id::in,
@@ -478,18 +496,20 @@ expand_try_goal(Instmap, TryGoal, FinalGoal, !Info) :-
     some [!ModuleInfo, !PredInfo, !ProcInfo, !VarTypes] (
         !.Info = trys_info(!:ModuleInfo, !:PredInfo, !:ProcInfo, _),
         expand_try_goal_2(MaybeIO, ResultVar, Goal1, Then1, MaybeElse1,
-            ExcpHandling1, GoalOutputVarsSet, FinalGoal, !PredInfo, !ProcInfo,
-            !ModuleInfo),
+            ExcpHandling1, InstmapAfterGoal, GoalOutputVarsSet, FinalGoal,
+            !PredInfo, !ProcInfo, !ModuleInfo),
         !:Info = trys_info(!.ModuleInfo, !.PredInfo, !.ProcInfo, yes)
     ).

 :- pred expand_try_goal_2(maybe(try_io_state_vars)::in, prog_var::in,
     hlds_goal::in, hlds_goal::in, maybe(hlds_goal)::in, hlds_goal::in,
-    set(prog_var)::in, hlds_goal::out, pred_info::in, pred_info::out,
-    proc_info::in, proc_info::out, module_info::in, module_info::out) is det.
+    instmap::in, set(prog_var)::in, hlds_goal::out,
+    pred_info::in, pred_info::out, proc_info::in, proc_info::out,
+    module_info::in, module_info::out) is det.

 expand_try_goal_2(MaybeIO, ResultVar, Goal1, Then1, MaybeElse1, ExcpHandling1,
-        GoalOutputVarsSet, FinalGoal, !PredInfo, !ProcInfo, !ModuleInfo) :-
+        Instmap, GoalOutputVarsSet, FinalGoal,
+        !PredInfo, !ProcInfo, !ModuleInfo) :-
     some [!VarTypes] (
         % Get the type of the output tuple.
         proc_info_get_vartypes(!.ProcInfo, !:VarTypes),
@@ -509,6 +529,8 @@ expand_try_goal_2(MaybeIO, ResultVar, Goal1,
Then1, MaybeElse1, ExcpHandling1,
     make_try_lambda(Goal1, GoalOutputVarsSet, OutputTupleType, MaybeIO,
         LambdaVar, AssignLambdaVar, !ProcInfo),

+    GoalPurity = goal_get_purity(Goal1),
+
     (
         MaybeIO = yes(try_io_state_vars(GoalInitialIOVar, GoalFinalIOVar)),

@@ -535,7 +557,7 @@ expand_try_goal_2(MaybeIO, ResultVar, Goal1,
Then1, MaybeElse1, ExcpHandling1,
         proc_info_create_var_from_type(io_state_type, yes("TryIOOutput"),
             TryIOOutputVar, !ProcInfo),
         make_try_call("try_io", LambdaVar, ResultVar,
-            [GoalInitialIOVar, TryIOOutputVar], OutputTupleType,
+            [GoalInitialIOVar, TryIOOutputVar], OutputTupleType, GoalPurity,
             CallTryGoal, !PredInfo, !ProcInfo, !ModuleInfo),

         create_pure_atomic_complicated_unification(GoalFinalIOVar,
@@ -548,7 +570,7 @@ expand_try_goal_2(MaybeIO, ResultVar, Goal1,
Then1, MaybeElse1, ExcpHandling1,
     ;
         MaybeIO = no,
         make_try_call("try", LambdaVar, ResultVar, [], OutputTupleType,
-            CallTryGoal, !PredInfo, !ProcInfo, !ModuleInfo),
+            GoalPurity, CallTryGoal, !PredInfo, !ProcInfo, !ModuleInfo),
         Then = Then1,
         ExcpHandling = ExcpHandling1
     ),
@@ -556,13 +578,18 @@ expand_try_goal_2(MaybeIO, ResultVar, Goal1,
Then1, MaybeElse1, ExcpHandling1,
     goal_info_init(GoalInfo),

     % The `succeeded' case.
+    proc_info_create_var_from_type(OutputTupleType, yes("TmpOutputTuple"),
+        TmpTupleVar, !ProcInfo),
     proc_info_create_var_from_type(OutputTupleType, yes("OutputTuple"),
         TupleVar, !ProcInfo),
-    deconstruct_functor(ResultVar, succeeded_cons_id, [TupleVar],
+    deconstruct_functor(ResultVar, succeeded_cons_id, [TmpTupleVar],
         DeconstructSucceeded),
+    instmap_lookup_vars(Instmap, GoalOutputVars, TupleArgInsts),
+    make_output_tuple_inst_cast(TmpTupleVar, TupleVar, TupleArgInsts,
+        CastOutputTuple),
     deconstruct_tuple(TupleVar, GoalOutputVars, DeconstructOutputs),
-    conj_list_to_goal([DeconstructSucceeded, DeconstructOutputs, Then],
-        GoalInfo, DeconstructsThen),
+    conj_list_to_goal([DeconstructSucceeded, CastOutputTuple,
+        DeconstructOutputs, Then], GoalInfo, DeconstructsThen),
     SucceededCase = case(succeeded_cons_id, [], DeconstructsThen),

     % The `exception' case.
@@ -804,12 +831,12 @@ detism_to_try_lambda_detism(detism_erroneous, detism_det).
 detism_to_try_lambda_detism(detism_failure, detism_semi).

 :- pred make_try_call(string::in, prog_var::in, prog_var::in,
-    list(prog_var)::in, mer_type::in, hlds_goal::out,
+    list(prog_var)::in, mer_type::in, purity::in, hlds_goal::out,
     pred_info::in, pred_info::out, proc_info::in, proc_info::out,
     module_info::in, module_info::out) is det.

 make_try_call(PredName, LambdaVar, ResultVar, ExtraArgs, OutputTupleType,
-        OverallGoal, !PredInfo, !ProcInfo, !ModuleInfo) :-
+        GoalPurity, OverallGoal, !PredInfo, !ProcInfo, !ModuleInfo) :-
     create_poly_info(!.ModuleInfo, !.PredInfo, !.ProcInfo, PolyInfo0),
     polymorphism_make_type_info_var(OutputTupleType, term.context_init,
         TypeInfoVar, MakeTypeInfoGoals, PolyInfo0, PolyInfo),
@@ -822,9 +849,24 @@ make_try_call(PredName, LambdaVar, ResultVar,
ExtraArgs, OutputTupleType,
     InstMapSrc = [],
     generate_simple_call(mercury_exception_module, PredName,
         pf_predicate, Mode, detism_cc_multi, purity_pure, Args, Features,
-        InstMapSrc, !.ModuleInfo, term.context_init, CallGoal),
+        InstMapSrc, !.ModuleInfo, term.context_init, CallGoal0),

     goal_info_init(GoalInfo),
+
+    % The try* predicates are only implemented for pure lambdas.  If the lambda
+    % is actually non-pure, retain that in the call to try* with a purity
+    % scope.
+    (
+        GoalPurity = purity_pure,
+        CallGoal = CallGoal0
+    ;
+        ( GoalPurity = purity_semipure
+        ; GoalPurity = purity_impure
+        ),
+        ScopeReason = promise_purity(dont_make_implicit_promises, GoalPurity),
+        CallGoal = hlds_goal(scope(ScopeReason, CallGoal0), GoalInfo)
+    ),
+
     conj_list_to_goal(MakeTypeInfoGoals ++ [CallGoal], GoalInfo, OverallGoal).

 :- pred make_unreachable_call(module_info::in, hlds_goal::out) is det.
@@ -834,6 +876,28 @@ make_unreachable_call(ModuleInfo, Goal) :-
         pf_predicate, only_mode, detism_erroneous, purity_pure,
         [], [], [], ModuleInfo, term.context_init, Goal).

+:- pred make_output_tuple_inst_cast(prog_var::in, prog_var::in,
+    list(mer_inst)::in, hlds_goal::out) is det.
+
+make_output_tuple_inst_cast(TmpTupleVar, TupleVar, TupleArgInsts,
+        CastOrUnify) :-
+    % If all the arguments have inst `ground' then a unification is enough.
+    (
+        list.member(ArgInst, TupleArgInsts),
+        ArgInst \= ground(_, none)
+    ->
+        TupleArity = list.length(TupleArgInsts),
+        TupleInst = bound(shared, [
+            bound_functor(cons(unqualified("{}"), TupleArity), TupleArgInsts)
+        ]),
+        generate_cast_with_insts(unsafe_type_inst_cast, TmpTupleVar, TupleVar,
+            ground_inst, TupleInst, term.context_init, CastOrUnify)
+    ;
+        create_pure_atomic_complicated_unification(TupleVar,
+            rhs_var(TmpTupleVar), term.context_init,
+            umc_implicit("try_expand"), [], CastOrUnify)
+    ).
+
 %-----------------------------------------------------------------------------%

 :- func succeeded_cons_id = cons_id.
diff --git a/doc/reference_manual.texi b/doc/reference_manual.texi
index 93ad1e6..0cb344f 100644
--- a/doc/reference_manual.texi
+++ b/doc/reference_manual.texi
...

diff --git a/library/exception.m b/library/exception.m
index 643fdff..99250ef 100644
--- a/library/exception.m
+++ b/library/exception.m
@@ -253,6 +253,16 @@
     %
 :- pred unreachable is erroneous.

+    % Forwarding predicates so we don't need to implicitly import `univ'
+    % in the implementation of `try' goals.
+    %
+:- pred exc_univ_to_type(univ, T).
+:- mode exc_univ_to_type(in, out) is semidet.
+:- mode exc_univ_to_type(out, in) is det.
+:- mode exc_univ_to_type(uo, di) is det.
+
+:- some [T] func exc_univ_value(univ) = T.
+
 %-----------------------------------------------------------------------------%

 :- implementation.
@@ -801,6 +811,11 @@ magic_exception_result(succeeded({})).  % force cc_multi
 unreachable :-
     throw("unreachable code reached").

+exc_univ_to_type(Univ, Object) :-
+    univ.univ_to_type(Univ, Object).
+
+exc_univ_value(Univ) = univ.univ_value(Univ).
+
 %-----------------------------------------------------------------------------%

 :- pred throw_impl(univ::in) is erroneous.
diff --git a/tests/debugger/declarative/catch.m
b/tests/debugger/declarative/catch.m
index ae4c347..417f6ff 100644
--- a/tests/debugger/declarative/catch.m
+++ b/tests/debugger/declarative/catch.m
@@ -1,4 +1,4 @@
-:- module catch.
+:- module (catch).
 :- interface.
 :- import_module io.
 :- pred main(io__state::di, io__state::uo) is cc_multi.
diff --git a/tests/hard_coded/Mmakefile b/tests/hard_coded/Mmakefile
index 84cb72a..fb866e0 100644
--- a/tests/hard_coded/Mmakefile
+++ b/tests/hard_coded/Mmakefile
@@ -252,6 +252,7 @@ ORDINARY_PROGS=	\
 	try_syntax_4 \
 	try_syntax_5 \
 	try_syntax_6 \
+	try_syntax_7 \
 	tuple_test \
 	type_ctor_desc \
 	type_ctor_desc_manip \
diff --git a/tests/hard_coded/try_syntax_1.m b/tests/hard_coded/try_syntax_1.m
index f5ff6e9..f6cae20 100644
--- a/tests/hard_coded/try_syntax_1.m
+++ b/tests/hard_coded/try_syntax_1.m
@@ -14,7 +14,6 @@
 :- implementation.

 :- import_module exception.
-:- import_module univ.
 :- import_module string.

 %-----------------------------------------------------------------------------%
diff --git a/tests/hard_coded/try_syntax_2.m b/tests/hard_coded/try_syntax_2.m
index 89e534f..3be82b4 100644
--- a/tests/hard_coded/try_syntax_2.m
+++ b/tests/hard_coded/try_syntax_2.m
@@ -14,7 +14,6 @@
 :- implementation.

 :- import_module exception.
-:- import_module univ.
 :- import_module string.

 %-----------------------------------------------------------------------------%
diff --git a/tests/hard_coded/try_syntax_3.m b/tests/hard_coded/try_syntax_3.m
index 59e424f..d6e4128 100644
--- a/tests/hard_coded/try_syntax_3.m
+++ b/tests/hard_coded/try_syntax_3.m
@@ -14,7 +14,6 @@
 :- implementation.

 :- import_module exception.
-:- import_module univ.
 :- import_module string.

 %-----------------------------------------------------------------------------%
diff --git a/tests/hard_coded/try_syntax_4.m b/tests/hard_coded/try_syntax_4.m
index 4a3170c..5beb159 100644
--- a/tests/hard_coded/try_syntax_4.m
+++ b/tests/hard_coded/try_syntax_4.m
@@ -14,7 +14,6 @@
 :- implementation.

 :- import_module exception.
-:- import_module univ.
 :- import_module string.

 %-----------------------------------------------------------------------------%
diff --git a/tests/hard_coded/try_syntax_5.m b/tests/hard_coded/try_syntax_5.m
index b1c665b..ca5f99f 100644
--- a/tests/hard_coded/try_syntax_5.m
+++ b/tests/hard_coded/try_syntax_5.m
@@ -15,7 +15,6 @@
 :- implementation.

 :- import_module exception.
-:- import_module univ.

 %-----------------------------------------------------------------------------%

diff --git a/tests/hard_coded/try_syntax_6.m b/tests/hard_coded/try_syntax_6.m
index 60838e9..860453b 100644
--- a/tests/hard_coded/try_syntax_6.m
+++ b/tests/hard_coded/try_syntax_6.m
@@ -14,7 +14,6 @@
 :- implementation.

 :- import_module exception.
-:- import_module univ.

 %-----------------------------------------------------------------------------%

diff --git a/tests/hard_coded/try_syntax_7.exp
b/tests/hard_coded/try_syntax_7.exp
new file mode 100644
index 0000000..68300b8
--- /dev/null
+++ b/tests/hard_coded/try_syntax_7.exp
@@ -0,0 +1 @@
+It works!
diff --git a/tests/hard_coded/try_syntax_7.m b/tests/hard_coded/try_syntax_7.m
new file mode 100644
index 0000000..4ac38ec
--- /dev/null
+++ b/tests/hard_coded/try_syntax_7.m
@@ -0,0 +1,35 @@
+%-----------------------------------------------------------------------------%
+% Check inst casts get added in try goal transformation.
+
+:- module try_syntax_7.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is cc_multi.
+
+%-----------------------------------------------------------------------------%
+%-----------------------------------------------------------------------------%
+
+:- implementation.
+
+%-----------------------------------------------------------------------------%
+
+main(!IO) :-
+    (try [] (
+        X = 1,
+        Y = "hi"
+    )
+    then
+        % Without inst casts, X and Y would be `ground' here.
+        p(X, Y, !IO)
+    ).
+
+:- pred p(int::in(bound(1)), string::in(bound("hi")),
+    io::di, io::uo) is det.
+
+p(1, "hi", !IO) :-
+    io.write_string("It works!\n", !IO).
+
+%-----------------------------------------------------------------------------%
+% vim: ft=mercury ts=8 sts=4 sw=4 et
--------------------------------------------------------------------------
mercury-reviews mailing list
Post messages to:       mercury-reviews at csse.unimelb.edu.au
Administrative Queries: owner-mercury-reviews at csse.unimelb.edu.au
Subscriptions:          mercury-reviews-request at csse.unimelb.edu.au
--------------------------------------------------------------------------



More information about the reviews mailing list