[m-rev.] for reviews: file streams as typeclasss instances

Julien Fischer juliensf at csse.unimelb.edu.au
Tue Oct 3 16:24:06 AEST 2006


NOTES:
 	- I won't commit this until the fix for intermodule optimization
  	  I committed the other day has bootstrapped on all our machines.
           (Also, people will need to update their laptops).

 	- I'll modify the NEWS file as a separate change.

 	- There is (most probably) another change that needs to be made
    	  for printing out streams in the raw_pretty format in the
 	  browser.  (We don't seem to have any tests cases for this
  	  at the moment so I'll also address that one as a separate
 	  change.)

For review by Ian.

Estimated hours taken: 25
Branches: main

Change the representation of file streams in the io module so that they
can be used as typeclass instances.  This is not currently possible because
file streams are defined as equivalence types and making them typeclass
instances results in overlapping instances.

This diff changes the representation by putting notag wrappers around the
various file stream types: io.input_stream, io.output_stream,
io.binary_input_stream, etc.  This avoids the problem with overlapping
instances.  It also improves type-safety; it is now not possible to pass a
binary input stream where a binary output stream is expected and so forth.

This change is complicated by the fact that the io module interacts
with both the runtime and the debugger via the C interface.  In order to
preserve the existing C interface that the io module presents to the runtime
(the alternative being to more or less to change all the types of the
arguments to MR_Word), the I/O operations that operate on file streams have
been split into two parts: a "typed" part that is exported from the io module
and an "untyped" part that deals with primitive streams (the io.stream type).

For the debugger the problem is the reverse since there we typically pass
values of type MercuryFilePtr to exported Mercury procedures.  In order
to avoid warnings from gcc we add a set of macros to the runtime that
wrap or unwrap MercuryFilePtrs.  There should be no performance impact
since the macros just expand to casts.

library/io.m:
 	Do not define the various I/O streams as equivalence types in order
 	to avoid problems with overlapping instances when these types are
 	used as typeclass instances.

 	Mark io.seek_binary/5 and io.binary_stream_offset/4 as obsolete.
 	Add a typeclass io.binary_stream and make both binary file stream
 	types instances of it.  This is so that the above predicates will
 	continue to work until they are deleted.

 	Add new predicates: io.seek_binary_input/5, io.seek_binary_output/5
 	io.binary_input_stream_offset/4 and io.binary_input_stream_offset/4
 	to replace the above.

 	When using io.write to print file streams strip off the wrapper
 	before printing the entry from the stream database.  The information
 	in the wrapper is redundant - we use that from the stream db since
 	that is more detailed.

 	Format some section headings to conform with our current coding
 	standard.

 	Lots of minor formatting changes.

runtime/mercury_init.h:
 	s/io.h/io.mh/ in a comment.

runtime/mercury_library_types.h:
 	Add macros to wrap (and in once case unwrap) file stream types
 	as we pass them across the C interface.  This avoids warnings
 	from gcc.

browser/listing.m:
 	Upwrap the input stream passed to mercury_stream_to_c_FILE_star
 	before trying to extract the underlying C file pointer.

trace/mercury_trace_browse.c:
trace/mercury_trace_declarative.c:
trace/mercury_trace_external.c:
trace/mercury_trace_help.c:
 	Use the new macros in the runtime to wrap streams that we pass back to
 	Mercury procedures.

compiler/export.m:
 	Unrelated change: s/Word/MR_Word/

tests/hard_coded/Mmakefile:
tests/hard_coded/print_stream.{m,exp}:
 	Test for io.write and file streams.

tests/invalid/Mmakefile:
tests/invalid/mixed_up_streams.{m,err_exp}:
 	Test that it isn't possible to pass binary input streams where
 	binary output streams are expected.

tests/valid/Mmakefile:
tests/valid/file_stream_instances.m:
 	Add a test case to check that we can use the various file stream
 	types as typeclass instances.

Julien.

Index: browser/listing.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/browser/listing.m,v
retrieving revision 1.8
diff -u -r1.8 listing.m
--- browser/listing.m	31 Aug 2006 11:09:49 -0000	1.8
+++ browser/listing.m	2 Oct 2006 04:22:00 -0000
@@ -198,7 +198,7 @@
      mercury_stream_to_c_FILE_star(InStream::in) = (InStrm::out),
      [promise_pure, thread_safe, will_not_call_mercury],
  "
-    InStrm = MR_file(*InStream);
+    InStrm = MR_file(*(MR_unwrap_input_stream(InStream)));
  ").

  %-----------------------------------------------------------------------------%
Index: compiler/export.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/compiler/export.m,v
retrieving revision 1.105
diff -u -r1.105 export.m
--- compiler/export.m	27 Sep 2006 06:16:51 -0000	1.105
+++ compiler/export.m	2 Oct 2006 04:22:00 -0000
@@ -177,7 +177,7 @@
      % #endif
      % <function name>(MR_Word Mercury__Argument1,
      %       MR_Word *Mercury__Argument2...);
-    %       /* Word for input, Word* for output */
+    %       /* MR_Word for input, MR_Word* for output */
      %
      % #if SEMIDET
      %   MR_bool
@@ -188,7 +188,7 @@
      % #endif
      % <function name>(MR_Word Mercury__Argument1,
      %       MR_Word *Mercury__Argument2...)
-    %       /* Word for input, Word* for output */
+    %       /* MR_Word for input, MR_Word* for output */
      % {
      % #if MR_NUM_REAL_REGS > 0
      %   MR_Word c_regs[MR_NUM_REAL_REGS];
Index: library/io.m
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/library/io.m,v
retrieving revision 1.358
diff -u -r1.358 io.m
--- library/io.m	27 Sep 2006 06:16:39 -0000	1.358
+++ library/io.m	3 Oct 2006 03:59:56 -0000
@@ -62,10 +62,8 @@

      % Opaque handles for binary I/O streams.
      %
-:- type io.binary_input_stream     ==  io.binary_stream.
-:- type io.binary_output_stream    ==  io.binary_stream.
-
-:- type io.binary_stream.
+:- type io.binary_input_stream.
+:- type io.binary_output_stream.

      % A unique identifier for an I/O stream.
      %
@@ -317,8 +315,8 @@
      % I/O error is encountered, then it returns `error(Message, LineNumber)'.
      %
  :- pred io.read(io.read_result(T)::out, io::di, io::uo) is det.
-:- pred io.read(io.input_stream::in, io.read_result(T)::out, io::di, io::uo)
-    is det.
+:- pred io.read(io.input_stream::in, io.read_result(T)::out,
+    io::di, io::uo) is det.

      % The type `posn' represents a position within a string.
      %
@@ -919,16 +917,54 @@
  :- pred io.flush_binary_output(io.binary_output_stream::in,
      io::di, io::uo) is det.

+    % The following typeclass and instances are required for the
+    % deprecated predicates io.seek_binary/5 io.binary_stream_offset/4 to work.
+    % They will deleted when those predicate are.
+    %
+:- typeclass io.binary_stream(T).
+:- instance  io.binary_stream(io.binary_input_stream).
+:- instance  io.binary_stream(io.binary_output_stream).
+
      % Seek to an offset relative to Whence (documented above)
      % on a specified binary stream. Attempting to seek on a pipe
      % or tty results in implementation dependent behaviour.
      %
-:- pred io.seek_binary(io.binary_stream::in, io.whence::in, int::in,
-    io::di, io::uo) is det.
+:- pragma obsolete(io.seek_binary/5).
+:- pred io.seek_binary(T::in, io.whence::in, int::in, io::di, io::uo) 
+    is det <= io.binary_stream(T).
+
+    % Seek to an offset relative to Whence (documented above)
+    % on a specified binary input stream. Attempting to seek on a pipe
+    % or tty results in implementation dependent behaviour.
+    %
+:- pred io.seek_binary_input(io.binary_input_stream::in, io.whence::in,
+    int::in, io::di, io::uo) is det.
+
+    % Seek to an offset relative to Whence (documented above)
+    % on a specified binary output stream. Attempting to seek on a pipe
+    % or tty results in implementation dependent behaviour.
+    %
+:- pred io.seek_binary_output(io.binary_output_stream::in, io.whence::in,
+    int::in, io::di, io::uo) is det.

      % Returns the offset (in bytes) into the specified binary stream.
+    % 
+    % NOTE: this predicate is deprecated; please use either
+    %       io.binary_input_stream_offset or io.binary_output_stream_offset
+    %       instead.
      %
-:- pred io.binary_stream_offset(io.binary_stream::in, int::out,
+:- pragma obsolete(io.binary_stream_offset/4).
+:- pred io.binary_stream_offset(T::in, int::out, io::di, io::uo)
+    is det <= io.binary_stream(T).
+
+    % Returns the offset (in bytes) into the specified binary input stream.
+    %
+:- pred io.binary_input_stream_offset(io.binary_input_stream::in, int::out,
+    io::di, io::uo) is det.
+
+    % Returns the offset (in bytes) into the specified binary output stream.
+    %
+:- pred io.binary_output_stream_offset(io.binary_output_stream::in, int::out,
      io::di, io::uo) is det.

  %-----------------------------------------------------------------------------%
@@ -1530,7 +1566,9 @@
  :- use_module rtti_implementation.
  :- use_module table_builtin.

-:- pragma foreign_import_module(c, string).
+%-----------------------------------------------------------------------------%
+
+:- pragma foreign_import_module("C", string).

      % Values of type `io.state' are never really used:
      % instead we store data in global variables.
@@ -1603,21 +1641,24 @@
          new mercury.tree234.Tree234_2.Empty_0();
  ").

-:- type io.stream_putback ==    map(io.stream_id, list(char)).
+:- type io.stream_putback ==  map(io.stream_id, list(char)).

-:- type io.input_stream  ==     io.stream.
-:- type io.output_stream ==     io.stream.
+:- type io.input_stream  ---> input_stream(io.stream).
+:- type io.output_stream ---> output_stream(io.stream).

-:- type io.binary_stream ==     io.stream.
+:- type io.binary_input_stream ---> binary_input_stream(io.stream).
+:- type io.binary_output_stream ---> binary_output_stream(io.stream).

-:- type io.stream --->     stream(c_pointer).
+:- type io.stream
+    --->    stream(c_pointer).
  :- pragma foreign_type("C", io.stream, "MercuryFilePtr",
      [can_pass_as_mercury_type]).
  :- pragma foreign_type("il", io.stream,
      "class [mercury]mercury.io__csharp_code.MR_MercuryFileStruct").
  :- pragma foreign_type("Java", io.stream, "mercury.io.MR_MercuryFileStruct").

-    % a unique identifier for an IO stream
+    % A unique identifier for an I/O stream.
+    %
  :- type io.stream_id == int.

  :- func io.get_stream_id(io.stream) = io.stream_id.
@@ -1667,8 +1708,9 @@
  :- impure pred io.setenv(string::in, string::in) is semidet.

  %-----------------------------------------------------------------------------%
-
-% input predicates
+%
+% Input predicates
+%

  % We want to inline these, to allow deforestation.
  :- pragma inline(io.read_char/3).
@@ -1697,8 +1739,8 @@
      io.binary_input_stream(Stream, !IO),
      io.read_byte(Stream, Result, !IO).

-io.read_byte(Stream, Result, !IO) :-
-    io.read_byte_val(Stream, Code, !IO),
+io.read_byte(binary_input_stream(Stream), Result, !IO) :-
+    io.read_byte_val(input_stream(Stream), Code, !IO),
      ( Code >= 0 ->
          Result = ok(Code)
      ; Code = -1 ->
@@ -1798,7 +1840,7 @@
      io.input_stream(Stream, !IO),
      io.read_line_as_string(Stream, Result, !IO).

-io.read_line_as_string(Stream, Result, !IO) :-
+io.read_line_as_string(input_stream(Stream), Result, !IO) :-
      io.read_line_as_string_2(Stream, yes, Res, String, !IO),
      ( Res < 0 ->
          ( Res = -1 ->
@@ -1811,11 +1853,11 @@
          Result = ok(String)
      ).

-:- pred io.read_line_as_string_2(io.input_stream::in, bool::in, int::out,
+:- pred io.read_line_as_string_2(io.stream::in, bool::in, int::out,
      string::out, io::di, io::uo) is det.

  :- pragma foreign_proc("C",
-    io.read_line_as_string_2(File::in, _Bool::in, Res :: out,
+    io.read_line_as_string_2(Stream::in, _Bool::in, Res :: out,
          RetString::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
  "
@@ -1831,7 +1873,7 @@

      Res = 0;
      for (i = 0; char_code != '\\n'; ) {
-        char_code = mercury_getc(File);
+        char_code = mercury_getc(Stream);
          if (char_code == EOF) {
              if (i == 0) {
                  Res = -1;
@@ -1881,7 +1923,7 @@
  io.read_line_as_string_2(Stream, FirstCall, Res, String, !IO) :-
      % XXX This is terribly inefficient, a better approach would be to
      % use a buffer like what is done for io.read_file_as_string.
-    io.read_char(Stream, Result, !IO),
+    io.read_char(input_stream(Stream), Result, !IO),
      (
          Result = ok(Char),
          ( Char = '\n' ->
@@ -1941,7 +1983,7 @@
      % Check if the stream is a regular file; if so, allocate a buffer
      % according to the size of the file. Otherwise, just use a default buffer
      % size of 4k minus a bit (to give malloc some room).
-    io.stream_file_size(Stream, FileSize, !IO),
+    io.input_stream_file_size(Stream, FileSize, !IO),
      ( FileSize >= 0 ->
          BufferSize0 = FileSize + 1
      ;
@@ -1951,13 +1993,13 @@

      % Read the file into the buffer (resizing it as we go if necessary),
      % convert the buffer into a string, and see if anything went wrong.
-    io.clear_err(Stream, !IO),
+    io.input_clear_err(Stream, !IO),
      Pos0 = 0,
      io.read_file_as_string_2(Stream, Buffer0, Buffer, Pos0, Pos,
          BufferSize0, BufferSize, !IO),
      require(Pos < BufferSize, "io.read_file_as_string: overflow"),
      io.buffer_to_string(Buffer, Pos, String),
-    io.check_err(Stream, Result0, !IO),
+    io.input_check_err(Stream, Result0, !IO),
      (
          Result0 = ok,
          Result = ok(String)
@@ -1973,7 +2015,8 @@
  io.read_file_as_string_2(Stream, !Buffer, !Pos, !Size, !IO) :-
      Pos0 = !.Pos,
      Size0 = !.Size,
-    io.read_into_buffer(Stream, !Buffer, !Pos, !.Size, !IO),
+    Stream = input_stream(RealStream),
+    io.read_into_buffer(RealStream, !Buffer, !Pos, !.Size, !IO),
      ( !.Pos =< Pos0 ->
          % End-of-file or error.
          true
@@ -2068,6 +2111,16 @@

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

+:- pred io.input_clear_err(io.input_stream::in, io::di, io::uo) is det.
+
+io.input_clear_err(input_stream(Stream), !IO) :-
+    io.clear_err(Stream, !IO).
+
+:- pred io.output_clear_err(io.output_stream::in, io::di, io::uo) is det.
+
+io.output_clear_err(output_stream(Stream), !IO) :-
+    io.clear_err(Stream, !IO).
+
      % Same as ANSI C's clearerr().
      %
  :- pred io.clear_err(stream::in, io::di, io::uo) is det.
@@ -2075,14 +2128,14 @@
  :- pragma foreign_proc("C",
      io.clear_err(Stream::in, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
-"{
+"
      if (MR_IS_FILE_STREAM(*Stream)) {
          clearerr(MR_file(*Stream));
      } else {
          /* Not a file stream so do nothing */
      }
      MR_update_io(IO0, IO);
-}").
+").

  :- pragma foreign_proc("C#",
      io.clear_err(_Stream::in, _IO0::di, _IO::uo),
@@ -2100,6 +2153,12 @@
      // XXX as for .NET above
  ").

+:- pred io.input_check_err(io.input_stream::in, io.res::out, io::di, io::uo)
+    is det.
+
+io.input_check_err(input_stream(Stream), Result, !IO) :-
+    io.check_err(Stream, Result, !IO).
+
  :- pred io.check_err(stream::in, io.res::out, io::di, io::uo) is det.

  io.check_err(Stream, Res, !IO) :-
@@ -2117,7 +2176,7 @@
  :- pragma foreign_proc("C",
      ferror(Stream::in, RetVal::out, RetStr::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
-"{
+"
      if (MR_IS_FILE_STREAM(*Stream)) {
          RetVal = ferror(MR_file(*Stream));
      } else {
@@ -2127,7 +2186,7 @@
      ML_maybe_make_err_msg(RetVal != 0, errno, ""read failed: "",
          MR_PROC_LABEL, RetStr);
      MR_update_io(IO0, IO);
-}").
+").

  :- pragma foreign_proc("C#",
      ferror(_Stream::in, RetVal::out, _RetStr::out, _IO0::di, _IO::uo),
@@ -2230,7 +2289,8 @@
  #endif
  ").

-have_dotnet :- semidet_fail.
+have_dotnet :-
+    semidet_fail.

  :- pragma foreign_proc("C#",
      have_dotnet,
@@ -2266,6 +2326,18 @@

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

+:- pred io.input_stream_file_size(io.input_stream::in, int::out,
+    io::di, io::uo) is det.
+
+io.input_stream_file_size(input_stream(Stream), Size, !IO) :-
+    io.stream_file_size(Stream, Size, !IO).
+
+:- pred io.output_stream_file_size(io.output_stream::in, int::out,
+    io::di, io::uo) is det.
+
+io.output_stream_file_size(output_stream(Stream), Size, !IO) :-
+    io.stream_file_size(Stream, Size, !IO).
+
      % io.stream_file_size(Stream, Size):
      % If Stream is a regular file, then Size is its size (in bytes),
      % otherwise Size is -1.
@@ -2286,7 +2358,7 @@
  :- pragma foreign_proc("C",
      io.stream_file_size(Stream::in, Size::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
-"{
+"
  #if defined(MR_HAVE_FSTAT) && \
          (defined(MR_HAVE_FILENO) || defined(fileno)) && defined(S_ISREG)
      struct stat s;
@@ -2303,7 +2375,7 @@
      Size = -1;
  #endif
      MR_update_io(IO0, IO);
-}").
+").

  :- pragma foreign_proc("C#",
      io.stream_file_size(Stream::in, Size::out, _IO0::di, _IO::uo),
@@ -2338,7 +2410,7 @@
      io.file_modification_time_2(FileName::in, Status::out, Msg::out,
          Time::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
-"{
+"
  #ifdef MR_HAVE_STAT
      struct stat s;
      if (stat(FileName, &s) == 0) {
@@ -2358,7 +2430,7 @@
  #endif
      MR_update_io(IO0, IO);

-}").
+").
  :- pragma foreign_proc("C#",
      io.file_modification_time_2(FileName::in, Status::out, Msg::out,
          Time::out, _IO0::di, _IO::uo),
@@ -2438,10 +2510,10 @@
      io::di, io::uo) is det.

  :- pragma foreign_proc("C",
-    io.file_type_2(FollowSymLinks::in, FileName::in,
-        Result::out, IO0::di, IO::uo),
+    io.file_type_2(FollowSymLinks::in, FileName::in, Result::out,
+        IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
-"{
+"
  #ifdef MR_HAVE_STAT
      struct stat s;
      int         stat_result;
@@ -2565,11 +2637,11 @@
          ""Sorry, io.file_type not implemented on this platform"") }
  #endif
      MR_update_io(IO0, IO);
-}").
+").

  :- pragma foreign_proc("C#",
-    io.file_type_2(_FollowSymLinks::in, FileName::in,
-        Result::out, _IO0::di, _IO::uo),
+    io.file_type_2(_FollowSymLinks::in, FileName::in, Result::out,
+        _IO0::di, _IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
  "
      try {
@@ -2685,7 +2757,7 @@
      io.check_file_accessibility_2(FileName::in, AccessTypes::in,
          Result::out, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
-"{
+"
  #if defined(MR_HAVE_ACCESS)
    #ifdef F_OK
      int mode = F_OK;
@@ -2728,7 +2800,7 @@
          ""io.check_file_accessibility not supported on this platform"");
  #endif
      IO = IO0;
-}").
+").

  :- pragma foreign_proc("Java",
      io.check_file_accessibility_2(FileName::in, AccessTypes::in,
@@ -3249,7 +3321,7 @@
      ( !.Pos >= Size ->
          true
      ;
-        io.read_char(Stream, CharResult, !IO),
+        io.read_char(input_stream(Stream), CharResult, !IO),
          ( CharResult = ok(Char) ->
              array.set(!.Array, !.Pos, Char, !:Array),
              !:Pos = !.Pos + 1,
@@ -3268,7 +3340,7 @@
  io.read_binary_file(Stream, Result, !IO) :-
      io.read_binary_file_2(Stream, [], Result, !IO).

-:- pred io.read_binary_file_2(io.input_stream::in, list(int)::in,
+:- pred io.read_binary_file_2(io.binary_input_stream::in, list(int)::in,
      io.result(list(int))::out, io::di, io::uo) is det.

  io.read_binary_file_2(Stream, Bytes0, Result, !IO) :-
@@ -3745,32 +3817,49 @@
  % Various different versions of io.print
  %

-:- pragma foreign_export("C", io.print(in, in(do_not_allow), in, di, uo),
+:- pragma foreign_export("C", io.print(in, di, uo),
+    "ML_io_print_to_cur_stream").
+
+io.print(Term, !IO) :-
+    io.do_print(canonicalize, Term, !IO).
+
+    % NOTE: in order to ensure that the signature for the exported 
+    % predicate matches that expected in the runtime we actually export
+    % io.print_2/4 rather than io.print/4 here.
+    %
+:- pragma foreign_export("C", io.print_2(in, in, di, uo),
+    "ML_io_print_to_stream").
+
+io.print(output_stream(Stream), Term, !IO) :-
+    io.print_2(Stream, Term, !IO).
+
+:- pred io.print_2(io.stream::in, T::in, io::di, io::uo) is det.
+
+io.print_2(Stream, Term, !IO) :-
+    io.print(output_stream(Stream), canonicalize, Term, !IO).
+
+:- pragma foreign_export("C", io.print_2(in, in(do_not_allow), in, di, uo),
      "ML_io_print_dna_to_stream").
-:- pragma foreign_export("C", io.print(in, in(canonicalize), in, di, uo),
+:- pragma foreign_export("C", io.print_2(in, in(canonicalize), in, di, uo),
      "ML_io_print_can_to_stream").
-:- pragma foreign_export("C", io.print(in, in(include_details_cc), in, di, uo),
+:- pragma foreign_export("C",
+    io.print_2(in, in(include_details_cc), in, di, uo),
      "ML_io_print_cc_to_stream").

-io.print(Stream, NonCanon, Term, !IO) :-
-    io.set_output_stream(Stream, OrigStream, !IO),
-    io.do_print(NonCanon, Term, !IO),
-    io.set_output_stream(OrigStream, _Stream, !IO).
+io.print(output_stream(Stream), NonCanon, Term, !IO) :-
+    io.print_2(Stream, NonCanon, Term, !IO).

-:- pragma foreign_export("C", io.print(in, in, di, uo),
-    "ML_io_print_to_stream").
+:- pred io.print_2(io.stream, deconstruct.noncanon_handling, T, io, io).
+:- mode io.print_2(in, in(do_not_allow), in, di, uo) is det.
+:- mode io.print_2(in, in(canonicalize), in, di, uo) is det.
+:- mode io.print_2(in, in(include_details_cc), in, di, uo) is cc_multi.
+:- mode io.print_2(in, in, in, di, uo) is cc_multi.

-io.print(Stream, Term, !IO) :-
-    io.set_output_stream(Stream, OrigStream, !IO),
-    io.do_print(canonicalize, Term, !IO),
+io.print_2(Stream, NonCanon, Term, !IO) :-
+    io.set_output_stream(output_stream(Stream), OrigStream, !IO),
+    io.do_print(NonCanon, Term, !IO),
      io.set_output_stream(OrigStream, _Stream, !IO).

-:- pragma foreign_export("C", io.print(in, di, uo),
-    "ML_io_print_to_cur_stream").
-
-io.print(Term, !IO) :-
-    io.do_print(canonicalize, Term, !IO).
-
  io.print_cc(Term, !IO) :-
      io.do_print(include_details_cc, Term, !IO).

@@ -3811,22 +3900,21 @@
  %   )

  %-----------------------------------------------------------------------------%
+%
+% Various different versions of io.write
+%

-% Various different versions of io.write.
+io.write(X, !IO) :-
+    io.do_write(canonicalize, X, !IO).
+
+io.write(Stream, X, !IO) :-
+    io.write(Stream, canonicalize, X, !IO).

  io.write(Stream, NonCanon, X, !IO) :-
      io.set_output_stream(Stream, OrigStream, !IO),
      io.do_write(NonCanon, X, !IO),
      io.set_output_stream(OrigStream, _Stream, !IO).

-io.write(Stream, X, !IO) :-
-    io.set_output_stream(Stream, OrigStream, !IO),
-    io.do_write(canonicalize, X, !IO),
-    io.set_output_stream(OrigStream, _Stream, !IO).
-
-io.write(X, !IO) :-
-    io.do_write(canonicalize, X, !IO).
-
  io.write_cc(X, !IO) :-
      io.do_write(include_details_cc, X, !IO).

@@ -3849,9 +3937,7 @@
      io.do_write_univ(canonicalize, Univ, !IO).

  io.write_univ(Stream, Univ, !IO) :-
-    io.set_output_stream(Stream, OrigStream, !IO),
-    io.do_write_univ(canonicalize, Univ, !IO),
-    io.set_output_stream(OrigStream, _Stream, !IO).
+    io.write_univ(Stream, canonicalize, Univ, !IO).

  io.write_univ(Stream, NonCanon, Univ, !IO) :-
      io.set_output_stream(Stream, OrigStream, !IO),
@@ -3894,11 +3980,14 @@
          io.write_type_desc(TypeDesc, !IO)
      ; univ_to_type(Univ, TypeCtorDesc) ->
          io.write_type_ctor_desc(TypeCtorDesc, !IO)
-    ; univ_to_type(Univ, Stream) ->
-        io.get_stream_db(StreamDb, !IO),
-        io.maybe_stream_info(StreamDb, Stream) = StreamInfo,
-        type_to_univ(StreamInfo, StreamInfoUniv),
-        io.do_write_univ_prio(NonCanon, StreamInfoUniv, Priority, !IO)
+    ; univ_to_type(Univ, input_stream(Stream)) ->
+        io.write_stream(NonCanon, Stream, Priority, !IO)
+    ; univ_to_type(Univ, output_stream(Stream)) ->
+        io.write_stream(NonCanon, Stream, Priority, !IO)
+    ; univ_to_type(Univ, binary_input_stream(Stream)) ->
+        io.write_stream(NonCanon, Stream, Priority, !IO)
+    ; univ_to_type(Univ, binary_output_stream(Stream)) -> 
+        io.write_stream(NonCanon, Stream, Priority, !IO)
      ; univ_to_type(Univ, C_Pointer) ->
          io.write_c_pointer(C_Pointer, !IO)
      ;
@@ -3953,6 +4042,19 @@

  same_private_builtin_type(_, _).

+:- pred io.write_stream(deconstruct.noncanon_handling, io.stream,
+    ops.priority, io, io).
+:- mode io.write_stream(in(do_not_allow), in, in, di, uo) is det.
+:- mode io.write_stream(in(canonicalize), in, in, di, uo) is det.
+:- mode io.write_stream(in(include_details_cc), in, in, di, uo) is cc_multi.
+:- mode io.write_stream(in, in, in, di, uo) is cc_multi.
+
+io.write_stream(NonCanon, Stream, Priority, !IO) :-
+    io.get_stream_db(StreamDb, !IO),
+    io.maybe_stream_info(StreamDb, Stream) = StreamInfo,
+    type_to_univ(StreamInfo, StreamInfoUniv),
+    io.do_write_univ_prio(NonCanon, StreamInfoUniv, Priority, !IO).
+
  :- pred io.write_ordinary_term(deconstruct.noncanon_handling, univ,
      ops.priority, io, io).
  :- mode io.write_ordinary_term(in(do_not_allow), in, in, di, uo) is det.
@@ -4305,22 +4407,22 @@
      % (not really binary!)
      % XXX This will not work for the Java back-end. See the comment at the
      % top of the MR_MercuryFileStruct class definition.
-    io.binary_output_stream(Stream, !IO),
-    io.write(Stream, Term, !IO),
-    io.write_string(Stream, ".\n", !IO).
+    io.binary_output_stream(binary_output_stream(Stream), !IO),
+    io.write(output_stream(Stream), Term, !IO),
+    io.write_string(output_stream(Stream), ".\n", !IO).

  io.read_binary(Result, !IO) :-
      % A quick-and-dirty implementation... not very space-efficient
      % (not really binary!)
      % XXX This will not work for the Java back-end. See the comment at the
      % top of the MR_MercuryFileStruct class definition.
-    io.binary_input_stream(Stream, !IO),
-    io.read(Stream, ReadResult, !IO),
+    io.binary_input_stream(binary_input_stream(Stream), !IO),
+    io.read(input_stream(Stream), ReadResult, !IO),
      (
          ReadResult = ok(T),
          % We've read the newline and the trailing full stop.
          % Now skip the newline after the full stop.
-        io.read_char(Stream, NewLineRes, !IO),
+        io.read_char(input_stream(Stream), NewLineRes, !IO),
          ( NewLineRes = error(Error) ->
              Result = error(Error)
          ; NewLineRes = ok('\n') ->
@@ -4344,7 +4446,7 @@
  io.open_input(FileName, Result, !IO) :-
      io.do_open_text(FileName, "r", Result0, OpenCount, NewStream, !IO),
      ( Result0 \= -1 ->
-        Result = ok(NewStream),
+        Result = ok(input_stream(NewStream)),
          io.insert_stream_info(NewStream,
              stream(OpenCount, input, text, file(FileName)), !IO)
      ;
@@ -4355,7 +4457,7 @@
  io.open_output(FileName, Result, !IO) :-
      io.do_open_text(FileName, "w", Result0, OpenCount, NewStream, !IO),
      ( Result0 \= -1 ->
-        Result = ok(NewStream),
+        Result = ok(output_stream(NewStream)),
          io.insert_stream_info(NewStream,
              stream(OpenCount, output, text, file(FileName)), !IO)
      ;
@@ -4366,7 +4468,7 @@
  io.open_append(FileName, Result, !IO) :-
      io.do_open_text(FileName, "a", Result0, OpenCount, NewStream, !IO),
      ( Result0 \= -1 ->
-        Result = ok(NewStream),
+        Result = ok(output_stream(NewStream)),
          io.insert_stream_info(NewStream,
              stream(OpenCount, append, text, file(FileName)), !IO)
      ;
@@ -4377,7 +4479,7 @@
  io.open_binary_input(FileName, Result, !IO) :-
      io.do_open_binary(FileName, "rb", Result0, OpenCount, NewStream, !IO),
      ( Result0 \= -1 ->
-        Result = ok(NewStream),
+        Result = ok(binary_input_stream(NewStream)),
          io.insert_stream_info(NewStream,
              stream(OpenCount, input, binary, file(FileName)), !IO)
      ;
@@ -4388,7 +4490,7 @@
  io.open_binary_output(FileName, Result, !IO) :-
      io.do_open_binary(FileName, "wb", Result0, OpenCount, NewStream, !IO),
      ( Result0 \= -1 ->
-        Result = ok(NewStream),
+        Result = ok(binary_output_stream(NewStream)),
          io.insert_stream_info(NewStream,
              stream(OpenCount, output, binary, file(FileName)), !IO)
      ;
@@ -4399,7 +4501,7 @@
  io.open_binary_append(FileName, Result, !IO) :-
      io.do_open_binary(FileName, "ab", Result0, OpenCount, NewStream, !IO),
      ( Result0 \= -1 ->
-        Result = ok(NewStream),
+        Result = ok(binary_output_stream(NewStream)),
          io.insert_stream_info(NewStream,
              stream(OpenCount, append, binary, file(FileName)), !IO)
      ;
@@ -4483,35 +4585,36 @@

  %-----------------------------------------------------------------------------%
  %-----------------------------------------------------------------------------%
-
-% Stream name predicates.
+%
+% Stream name predicates
+%

  io.input_stream_name(Name, !IO) :-
-    io.input_stream(Stream, !IO),
+    io.input_stream(input_stream(Stream), !IO),
      io.stream_name(Stream, Name, !IO).

-io.input_stream_name(Stream, Name, !IO) :-
+io.input_stream_name(input_stream(Stream), Name, !IO) :-
      io.stream_name(Stream, Name, !IO).

  io.output_stream_name(Name, !IO) :-
-    io.output_stream(Stream, !IO),
+    io.output_stream(output_stream(Stream), !IO),
      io.stream_name(Stream, Name, !IO).

-io.output_stream_name(Stream, Name, !IO) :-
+io.output_stream_name(output_stream(Stream), Name, !IO) :-
      io.stream_name(Stream, Name, !IO).

  io.binary_input_stream_name(Name, !IO) :-
-    io.binary_input_stream(Stream, !IO),
+    io.binary_input_stream(binary_input_stream(Stream), !IO),
      io.stream_name(Stream, Name, !IO).

-io.binary_input_stream_name(Stream, Name, !IO) :-
+io.binary_input_stream_name(binary_input_stream(Stream), Name, !IO) :-
      io.stream_name(Stream, Name, !IO).

  io.binary_output_stream_name(Name, !IO) :-
-    io.binary_output_stream(Stream, !IO),
+    io.binary_output_stream(binary_output_stream(Stream), !IO),
      io.stream_name(Stream, Name, !IO).

-io.binary_output_stream_name(Stream, Name, !IO) :-
+io.binary_output_stream_name(binary_output_stream(Stream), Name, !IO) :-
      io.stream_name(Stream, Name, !IO).

  :- pred io.stream_name(io.stream::in, string::out, io::di, io::uo) is det.
@@ -4538,16 +4641,16 @@
          MaybeInfo = no
      ).

-io.input_stream_info(StreamDb, Stream) =
+io.input_stream_info(StreamDb, input_stream(Stream)) =
      io.maybe_stream_info(StreamDb, Stream).

-io.output_stream_info(StreamDb, Stream) =
+io.output_stream_info(StreamDb, output_stream(Stream)) =
      io.maybe_stream_info(StreamDb, Stream).

-io.binary_input_stream_info(StreamDb, Stream) =
+io.binary_input_stream_info(StreamDb, binary_input_stream(Stream)) =
      io.maybe_stream_info(StreamDb, Stream).

-io.binary_output_stream_info(StreamDb, Stream) =
+io.binary_output_stream_info(StreamDb, binary_output_stream(Stream)) =
      io.maybe_stream_info(StreamDb, Stream).

  :- func io.maybe_stream_info(io.stream_db, io.stream) = maybe_stream_info.
@@ -4955,11 +5058,11 @@
  :- pred io.insert_std_stream_names(io::di, io::uo) is det.

  io.insert_std_stream_names(!IO) :-
-    io.stdin_stream(Stdin, !IO),
+    io.stdin_stream(input_stream(Stdin), !IO),
      io.insert_stream_info(Stdin, stream(0, input, preopen, stdin), !IO),
-    io.stdout_stream(Stdout, !IO),
+    io.stdout_stream(output_stream(Stdout), !IO),
      io.insert_stream_info(Stdout, stream(1, output, preopen, stdout), !IO),
-    io.stderr_stream(Stderr, !IO),
+    io.stderr_stream(output_stream(Stderr), !IO),
      io.insert_stream_info(Stderr, stream(1, output, preopen, stderr), !IO).

  io.call_system(Command, Result, !IO) :-
@@ -6394,32 +6497,50 @@

      return rc;
  }
-
  ").

-/* input predicates */
+%----------------------------------------------------------------------------%
+%
+% Input predicates 
+%
+
+io.read_char_code(input_stream(Stream), CharCode, !IO) :-
+    io.read_char_code_2(Stream, CharCode, !IO).
+
+:- pred io.read_char_code_2(io.stream::in, int::out, io::di, io::uo)
+    is det.

  :- pragma foreign_proc("C",
-    io.read_char_code(File::in, CharCode::out, IO0::di, IO::uo),
+    io.read_char_code_2(Stream::in, CharCode::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
-    CharCode = mercury_getc(File);
+    CharCode = mercury_getc(Stream);
      MR_update_io(IO0, IO);
  ").

+io.read_byte_val(input_stream(Stream), ByteVal, !IO) :-
+    io.read_byte_val_2(Stream, ByteVal, !IO).
+
+:- pred io.read_byte_val_2(io.stream::in, int::out, io::di, io::uo)
+    is det.
  :- pragma foreign_proc("C",
-    io.read_byte_val(File::in, ByteVal::out, IO0::di, IO::uo),
+    io.read_byte_val_2(Stream::in, ByteVal::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
-    ByteVal = mercury_getc(File);
+    ByteVal = mercury_getc(Stream);
      MR_update_io(IO0, IO);
  ").

+io.putback_char(input_stream(Stream), Character, !IO) :-
+    io.putback_char_2(Stream, Character, !IO).
+
+:- pred io.putback_char_2(io.stream::in, char::in, io::di, io::uo)
+    is det.
  :- pragma foreign_proc("C",
-    io.putback_char(File::in, Character::in, IO0::di, IO::uo),
+    io.putback_char_2(Stream::in, Character::in, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, terminates],
-"{
-    MercuryFilePtr mf = File;
+"
+    MercuryFilePtr mf = Stream;
      if (Character == '\\n') {
          MR_line_number(*mf)--;
      }
@@ -6428,19 +6549,23 @@
          mercury_io_error(mf, ""io.putback_char: ungetc failed"");
      }
      MR_update_io(IO0, IO);
-}").
+").

+io.putback_byte(binary_input_stream(Stream), Character, !IO) :-
+    io.putback_byte_2(Stream, Character, !IO).
+
+:- pred io.putback_byte_2(io.stream::in, int::in, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.putback_byte(File::in, Character::in, IO0::di, IO::uo),
+    io.putback_byte_2(Stream::in, Character::in, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, terminates],
-"{
-    MercuryFilePtr mf = File;
+"
+    MercuryFilePtr mf = Stream;
      /* XXX should work even if ungetc() fails */
      if (MR_UNGETCH(*mf, Character) == EOF) {
          mercury_io_error(mf, ""io.putback_byte: ungetc failed"");
      }
      MR_update_io(IO0, IO);
-}").
+").

  :- pragma foreign_proc("C#",
      io.read_char_code(File::in, CharCode::out, _IO0::di, _IO::uo),
@@ -6511,7 +6636,10 @@
      File.ungetc(Byte);
  ").

-/* output predicates - with output to mercury_current_text_output */
+%-----------------------------------------------------------------------------%
+%
+% Output predicates (with output to mercury_current_text_output)
+%

  :- pragma foreign_proc("C",
      io.write_string(Message::in, IO0::di, IO::uo),
@@ -6724,7 +6852,10 @@
  io.write_float(Float, !IO) :-
      io.write_string(string.float_to_string(Float), !IO).

-% Moving about binary streams.
+%-----------------------------------------------------------------------------%
+%
+% Moving about binary streams
+%

  :- pred whence_to_int(io.whence::in, int::out) is det.

@@ -6732,9 +6863,30 @@
  whence_to_int(cur, 1).
  whence_to_int(end, 2).

+:- typeclass io.binary_stream(T) where [
+    func extract_stream(T) = io.stream
+].
+
+:- instance io.binary_stream(io.binary_input_stream) where [
+    (extract_stream(binary_input_stream(Stream)) = Stream)
+].
+
+:- instance io.binary_stream(io.binary_output_stream) where [
+    (extract_stream(binary_output_stream(Stream)) = Stream)
+].
+
  io.seek_binary(Stream, Whence, Offset, IO0, IO) :-
      whence_to_int(Whence, Flag),
-    io.seek_binary_2(Stream, Flag, Offset, IO0, IO).
+    RealStream = extract_stream(Stream),
+    io.seek_binary_2(RealStream, Flag, Offset, IO0, IO).
+
+io.seek_binary_input(binary_input_stream(Stream), Whence, Offset, !IO) :-
+    whence_to_int(Whence, Flag),
+    io.seek_binary_2(Stream, Flag, Offset, !IO).
+
+io.seek_binary_output(binary_output_stream(Stream), Whence, Offset, !IO) :-
+    whence_to_int(Whence, Flag),
+    io.seek_binary_2(Stream, Flag, Offset, !IO).

  :- pred io.seek_binary_2(io.stream::in, int::in, int::in,
      io::di, io::uo) is det.
@@ -6742,7 +6894,7 @@
  :- pragma foreign_proc("C",
      io.seek_binary_2(Stream::in, Flag::in, Off::in, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
-"{
+"
      static const int seek_flags[] = { SEEK_SET, SEEK_CUR, SEEK_END };

      /* XXX should check for failure */
@@ -6753,37 +6905,60 @@
          mercury_io_error(Stream, ""io.seek_binary_2: unseekable stream"");
      }
      MR_update_io(IO0, IO);
-}").
+").
+
+io.binary_stream_offset(Stream, Offset, !IO) :-
+    RealStream = extract_stream(Stream),
+    io.binary_stream_offset_2(RealStream, Offset, !IO).
+
+io.binary_input_stream_offset(binary_input_stream(Stream), Offset, !IO) :-
+    io.binary_stream_offset_2(Stream, Offset, !IO).

+io.binary_output_stream_offset(binary_output_stream(Stream), Offset, !IO) :-
+    io.binary_stream_offset_2(Stream, Offset, !IO).
+
+:- pred io.binary_stream_offset_2(io.stream::in, int::out,
+    io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.binary_stream_offset(Stream::in, Offset::out, IO0::di, IO::uo),
+    io.binary_stream_offset_2(Stream::in, Offset::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
-"{
+"
      /* XXX should check for failure */
      /* XXX should check if the stream is tellable */
      if (MR_IS_FILE_STREAM(*Stream)) {
          Offset = ftell(MR_file(*Stream));
      } else {
          mercury_io_error(Stream,
-            ""io.binary_stream_offset: untellable stream"");
+            ""io.primitive_binary_stream_offset: untellable stream"");
      }
      MR_update_io(IO0, IO);
-}").
+").

-/* output predicates - with output to the specified stream */
+%-----------------------------------------------------------------------------%
+%
+% Output predicates (with output to the specified stream)
+%

+io.write_string(output_stream(Stream), Message, !IO) :-
+    io.write_string_2(Stream, Message, !IO).
+
+:- pred io.write_string_2(io.stream::in, string::in, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.write_string(Stream::in, Message::in, IO0::di, IO::uo),
+    io.write_string_2(Stream::in, Message::in, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
-"{
+"
      mercury_print_string(Stream, Message);
      MR_update_io(IO0, IO);
-}").
+").
+
+io.write_char(output_stream(Stream), Character, !IO) :-
+    io.write_char_2(Stream, Character, !IO).

+:- pred io.write_char_2(io.stream::in, char::in, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.write_char(Stream::in, Character::in, IO0::di, IO::uo),
+    io.write_char_2(Stream::in, Character::in, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
-"{
+"
      if (MR_PUTCH(*Stream, Character) < 0) {
          mercury_output_error(Stream);
      }
@@ -6791,81 +6966,104 @@
          MR_line_number(*Stream)++;
      }
      MR_update_io(IO0, IO);
-}").
+").
+
+io.write_int(output_stream(Stream), Val, !IO) :-
+    io.write_int_2(Stream, Val, !IO).

+:- pred io.write_int_2(io.stream::in, int::in, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.write_int(Stream::in, Val::in, IO0::di, IO::uo),
-    [may_call_mercury, promise_pure, tabled_for_io, thread_safe,
-        terminates],
-"{
+    io.write_int_2(Stream::in, Val::in, IO0::di, IO::uo),
+    [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
+"
      if (ML_fprintf(Stream, ""%ld"", (long) Val) < 0) {
          mercury_output_error(Stream);
      }
      MR_update_io(IO0, IO);
-}").
+").
+
+io.write_float(output_stream(Stream), Val, !IO) :-
+    io.write_float_2(Stream, Val, !IO).

+:- pred io.write_float_2(io.stream::in, float::in, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.write_float(Stream::in, Val::in, IO0::di, IO::uo),
+    io.write_float_2(Stream::in, Val::in, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
-"{
+"
      char buf[MR_SPRINTF_FLOAT_BUF_SIZE];
      MR_sprintf_float(buf, Val);
      if (ML_fprintf(Stream, ""%s"", buf) < 0) {
          mercury_output_error(Stream);
      }
      MR_update_io(IO0, IO);
-}").
+").

+io.write_byte(binary_output_stream(Stream), Byte, !IO) :-
+    io.write_byte_2(Stream, Byte, !IO).
+
+:- pred io.write_byte_2(io.stream::in, int::in, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.write_byte(Stream::in, Byte::in, IO0::di, IO::uo),
+    io.write_byte_2(Stream::in, Byte::in, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
-"{
+"
      /* call putc with a strictly non-negative byte-sized integer */
      if (MR_PUTCH(*Stream, (int) ((unsigned char) Byte)) < 0) {
          mercury_output_error(Stream);
      }
      MR_update_io(IO0, IO);
-}").
+").

+io.write_bytes(binary_output_stream(Stream), Message, !IO) :-
+    io.write_bytes_2(Stream, Message, !IO).
+
+:- pred io.write_bytes_2(io.stream::in, string::in, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.write_bytes(Stream::in, Message::in, IO0::di, IO::uo),
+    io.write_bytes_2(Stream::in, Message::in, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
-"{
+"
      mercury_print_binary_string(Stream, Message);
      MR_update_io(IO0, IO);
-}").
+").
+
+io.flush_output(output_stream(Stream), !IO) :-
+    io.flush_output_2(Stream, !IO).

+:- pred io.flush_output_2(io.stream::in, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.flush_output(Stream::in, IO0::di, IO::uo),
+    io.flush_output_2(Stream::in, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
-"{
+"
      if (MR_FLUSH(*Stream) < 0) {
          mercury_output_error(Stream);
      }
      MR_update_io(IO0, IO);
-}").
+").

+io.flush_binary_output(binary_output_stream(Stream), !IO) :-
+    io.flush_binary_output_2(Stream, !IO).
+
+:- pred io.flush_binary_output_2(io.stream::in, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.flush_binary_output(Stream::in, IO0::di, IO::uo),
+    io.flush_binary_output_2(Stream::in, IO0::di, IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
-"{
+"
      if (MR_FLUSH(*Stream) < 0) {
          mercury_output_error(Stream);
      }
      MR_update_io(IO0, IO);
-}").
+").

  :- pragma foreign_proc("C#",
      io.write_string(Stream::in, Message::in, _IO0::di, _IO::uo),
      [may_call_mercury, promise_pure, thread_safe, tabled_for_io, terminates],
-"{
+"
      mercury_print_string(Stream, Message);
-}").
+").

  :- pragma foreign_proc("C#",
      io.write_char(Stream::in, Character::in, _IO0::di, _IO::uo),
      [may_call_mercury, promise_pure, thread_safe, tabled_for_io, terminates],
-"{
+"
      MR_MercuryFileStruct stream = Stream;
      /* See mercury_output_string() for comments */
      if (stream.writer == null) {
@@ -6887,7 +7085,7 @@
      } else {
          w.Write(Character);
      }
-}").
+").

  :- pragma foreign_proc("C#",
      io.write_int(Stream::in, Val::in, _IO0::di, _IO::uo),
@@ -6911,7 +7109,7 @@
  }").

  :- pragma foreign_proc("C#",
-    io.flush_output(Stream::in, _IO0::di, _IO::uo),
+    io.flush_output_2(Stream::in, _IO0::di, _IO::uo),
      [may_call_mercury, promise_pure, thread_safe, tabled_for_io, terminates],
  "{
      Stream.stream.Flush();
@@ -6933,7 +7131,7 @@
  ").

  :- pragma foreign_proc("Java",
-    io.binary_stream_offset(Stream::in, Offset::out, _IO0::di, _IO::uo),
+    io.binary_stream_offset_2(Stream::in, Offset::out, _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe,
          terminates],
  "
@@ -6941,28 +7139,28 @@
  ").

  :- pragma foreign_proc("Java",
-    io.write_string(Stream::in, Message::in, _IO0::di, _IO::uo),
+    io.write_string_2(Stream::in, Message::in, _IO0::di, _IO::uo),
      [may_call_mercury, promise_pure, thread_safe, tabled_for_io, terminates],
  "
      Stream.write(Message);
  ").

  :- pragma foreign_proc("Java",
-    io.write_char(Stream::in, Character::in, _IO0::di, _IO::uo),
+    io.write_char_2(Stream::in, Character::in, _IO0::di, _IO::uo),
      [may_call_mercury, promise_pure, thread_safe, tabled_for_io, terminates],
  "
      Stream.put(Character);
  ").

  :- pragma foreign_proc("Java",
-    io.write_int(Stream::in, Val::in, _IO0::di, _IO::uo),
+    io.write_int_2(Stream::in, Val::in, _IO0::di, _IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
  "
      Stream.write(java.lang.String.valueOf(Val));
  ").

  :- pragma foreign_proc("Java",
-    io.write_float(Stream::in, Val::in, _IO0::di, _IO::uo),
+    io.write_float_2(Stream::in, Val::in, _IO0::di, _IO::uo),
      [may_call_mercury, promise_pure, tabled_for_io, thread_safe, terminates],
  "
      Stream.write(java.lang.String.valueOf(Val));
@@ -6983,7 +7181,7 @@
  ").

  :- pragma foreign_proc("Java",
-    io.flush_output(Stream::in, _IO0::di, _IO::uo),
+    io.flush_output_2(Stream::in, _IO0::di, _IO::uo),
      [may_call_mercury, promise_pure, thread_safe, tabled_for_io, terminates],
  "
      Stream.flush();
@@ -6996,105 +7194,153 @@
      Stream.flush();
  ").

-io.write_float(Stream, Float, !IO) :-
-    io.write_string(Stream, string.float_to_string(Float), !IO).
+io.write_float_2(Stream, Float, !IO) :-
+    io.write_string_2(Stream, string.float_to_string(Float), !IO).

-% Stream predicates.
+%----------------------------------------------------------------------------%
+%
+% Stream predicates
+%

-:- pragma foreign_export("C", io.stdin_stream(out, di, uo),
+:- pragma foreign_export("C", io.stdin_stream_2(out, di, uo),
      "ML_io_stdin_stream").
-:- pragma foreign_export("C", io.stdout_stream(out, di, uo),
+:- pragma foreign_export("C", io.stdout_stream_2(out, di, uo),
      "ML_io_stdout_stream").
-:- pragma foreign_export("C", io.stderr_stream(out, di, uo),
+:- pragma foreign_export("C", io.stderr_stream_2(out, di, uo),
      "ML_io_stderr_stream").

+io.stdin_stream = input_stream(io.stdin_stream_2).
+
+:- func io.stdin_stream_2 = io.stream.
  :- pragma foreign_proc("C",
-    io.stdin_stream = (Stream::out),
+    io.stdin_stream_2 = (Stream::out),
      [will_not_call_mercury, promise_pure, thread_safe],
  "
      Stream = &mercury_stdin;
  ").

+io.stdin_stream(input_stream(Stream), !IO) :-
+    io.stdin_stream_2(Stream, !IO).
+
+:- pred io.stdin_stream_2(io.stream::out, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.stdin_stream(Stream::out, IO0::di, IO::uo),
+    io.stdin_stream_2(Stream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
  "
      Stream = &mercury_stdin;
      MR_update_io(IO0, IO);
  ").

+io.stdout_stream = output_stream(io.stdout_stream_2).
+
+:- func io.stdout_stream_2 = io.stream.
  :- pragma foreign_proc("C",
-    io.stdout_stream = (Stream::out),
+    io.stdout_stream_2 = (Stream::out),
      [will_not_call_mercury, promise_pure, thread_safe],
  "
      Stream = &mercury_stdout;
  ").

+io.stdout_stream(output_stream(Stream), !IO) :-
+    io.stdout_stream_2(Stream, !IO).
+
+:- pred io.stdout_stream_2(io.stream::out, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.stdout_stream(Stream::out, IO0::di, IO::uo),
+    io.stdout_stream_2(Stream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
  "
      Stream = &mercury_stdout;
      MR_update_io(IO0, IO);
  ").

+io.stderr_stream = output_stream(io.stderr_stream_2).
+
+:- func io.stderr_stream_2 = io.stream.
  :- pragma foreign_proc("C",
-    io.stderr_stream = (Stream::out),
+    io.stderr_stream_2 = (Stream::out),
      [will_not_call_mercury, promise_pure, thread_safe],
  "
      Stream = &mercury_stderr;
  ").

+io.stderr_stream(output_stream(Stream), !IO) :-
+    io.stderr_stream_2(Stream, !IO).
+
+:- pred io.stderr_stream_2(io.stream::out, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.stderr_stream(Stream::out, IO0::di, IO::uo),
+    io.stderr_stream_2(Stream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
  "
      Stream = &mercury_stderr;
      MR_update_io(IO0, IO);
  ").

+io.stdin_binary_stream(binary_input_stream(Stream), !IO) :-
+    io.stdin_binary_stream_2(Stream, !IO).
+
+:- pred io.stdin_binary_stream_2(io.stream::out, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.stdin_binary_stream(Stream::out, IO0::di, IO::uo),
+    io.stdin_binary_stream_2(Stream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
  "
      Stream = &mercury_stdin_binary;
      MR_update_io(IO0, IO);
  ").

+io.stdout_binary_stream(binary_output_stream(Stream), !IO) :-
+    io.stdout_binary_stream_2(Stream, !IO).
+
+:- pred io.stdout_binary_stream_2(io.stream::out, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.stdout_binary_stream(Stream::out, IO0::di, IO::uo),
+    io.stdout_binary_stream_2(Stream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io, thread_safe],
  "
      Stream = &mercury_stdout_binary;
      MR_update_io(IO0, IO);
  ").

+io.input_stream(input_stream(Stream), !IO) :-
+    io.input_stream_2(Stream, !IO).
+
+:- pred io.input_stream_2(io.stream::out, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.input_stream(Stream::out, IO0::di, IO::uo),
+    io.input_stream_2(Stream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
      Stream = mercury_current_text_input;
      MR_update_io(IO0, IO);
  ").

+io.output_stream(output_stream(Stream), !IO) :-
+    io.output_stream_2(Stream, !IO).
+
+:- pred io.output_stream_2(io.stream::out, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.output_stream(Stream::out, IO0::di, IO::uo),
+    io.output_stream_2(Stream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
      Stream = mercury_current_text_output;
      MR_update_io(IO0, IO);
  ").

+io.binary_input_stream(binary_input_stream(Stream), !IO) :-
+    io.binary_input_stream_2(Stream, !IO).
+
+:- pred io.binary_input_stream_2(io.stream::out, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.binary_input_stream(Stream::out, IO0::di, IO::uo),
+    io.binary_input_stream_2(Stream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
      Stream = mercury_current_binary_input;
      MR_update_io(IO0, IO);
  ").

+io.binary_output_stream(binary_output_stream(Stream), !IO) :-
+    io.binary_output_stream_2(Stream, !IO).
+
+:- pred io.binary_output_stream_2(io.stream::out, io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.binary_output_stream(Stream::out, IO0::di, IO::uo),
+    io.binary_output_stream_2(Stream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
      Stream = mercury_current_binary_output;
@@ -7109,13 +7355,18 @@
      MR_update_io(IO0, IO);
  ").

+io.get_line_number(input_stream(Stream), LineNum, !IO) :-
+    io.get_line_number_2(Stream, LineNum, !IO).
+
+:- pred io.get_line_number_2(io.stream::in, int::out, io::di, io::uo)
+    is det.
  :- pragma foreign_proc("C",
-    io.get_line_number(Stream::in, LineNum::out, IO0::di, IO::uo),
+    io.get_line_number_2(Stream::in, LineNum::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
-"{
+"
      LineNum = MR_line_number(*Stream);
      MR_update_io(IO0, IO);
-}").
+").

  :- pragma foreign_proc("C",
      io.set_line_number(LineNum::in, IO0::di, IO::uo),
@@ -7125,13 +7376,19 @@
      MR_update_io(IO0, IO);
  ").

+io.set_line_number(input_stream(Stream), LineNum, !IO) :-
+    io.set_line_number_2(Stream, LineNum,!IO).
+
+:- pred io.set_line_number_2(io.stream::in, int::in, io::di, io::uo)
+    is det.
+
  :- pragma foreign_proc("C",
-    io.set_line_number(Stream::in, LineNum::in, IO0::di, IO::uo),
+    io.set_line_number_2(Stream::in, LineNum::in, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
-"{
+"
      MR_line_number(*Stream) = LineNum;
      MR_update_io(IO0, IO);
-}").
+").

  :- pragma foreign_proc("C",
      io.get_output_line_number(LineNum::out, IO0::di, IO::uo),
@@ -7141,13 +7398,19 @@
      MR_update_io(IO0, IO);
  ").

+io.get_output_line_number(output_stream(Stream), LineNum, !IO) :-
+    io.get_output_line_number_2(Stream, LineNum, !IO).
+
+:- pred io.get_output_line_number_2(io.stream::in, int::out,
+    io::di, io::uo) is det.
+
  :- pragma foreign_proc("C",
-    io.get_output_line_number(Stream::in, LineNum::out, IO0::di, IO::uo),
+    io.get_output_line_number_2(Stream::in, LineNum::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
-"{
+"
      LineNum = MR_line_number(*Stream);
      MR_update_io(IO0, IO);
-}").
+").

  :- pragma foreign_proc("C",
      io.set_output_line_number(LineNum::in, IO0::di, IO::uo),
@@ -7157,16 +7420,26 @@
      MR_update_io(IO0, IO);
  ").

+io.set_output_line_number(output_stream(Stream), LineNum, !IO) :-
+    io.set_output_line_number_2(Stream, LineNum, !IO).
+
+:- pred io.set_output_line_number_2(io.stream::in, int::in,
+    io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.set_output_line_number(Stream::in, LineNum::in, IO0::di, IO::uo),
+    io.set_output_line_number_2(Stream::in, LineNum::in, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
-"{
+"
      MR_line_number(*Stream) = LineNum;
      MR_update_io(IO0, IO);
-}").
+").
+
+io.set_input_stream(input_stream(NewStream), input_stream(OutStream), !IO) :-
+    io.set_input_stream_2(NewStream, OutStream, !IO).

+:- pred io.set_input_stream_2(io.stream::in, io.stream::out,
+    io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.set_input_stream(NewStream::in, OutStream::out, IO0::di, IO::uo),
+    io.set_input_stream_2(NewStream::in, OutStream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
      OutStream = mercury_current_text_input;
@@ -7174,8 +7447,15 @@
      MR_update_io(IO0, IO);
  ").

+io.set_output_stream(output_stream(NewStream), output_stream(OutStream),
+        !IO) :-
+    io.set_output_stream_2(NewStream, OutStream, !IO).
+
+:- pred io.set_output_stream_2(io.stream::in, io.stream::out,
+    io::di, io::uo) is det.
+
  :- pragma foreign_proc("C",
-    io.set_output_stream(NewStream::in, OutStream::out, IO0::di, IO::uo),
+    io.set_output_stream_2(NewStream::in, OutStream::out, IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
      OutStream = mercury_current_text_output;
@@ -7183,8 +7463,14 @@
      MR_update_io(IO0, IO);
  ").

+io.set_binary_input_stream(binary_input_stream(NewStream),
+        binary_input_stream(OutStream), !IO) :-
+    io.set_binary_input_stream_2(NewStream, OutStream, !IO).
+
+:- pred io.set_binary_input_stream_2(io.stream::in, io.stream::out,
+    io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.set_binary_input_stream(NewStream::in, OutStream::out,
+    io.set_binary_input_stream_2(NewStream::in, OutStream::out,
          IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
@@ -7193,8 +7479,14 @@
      MR_update_io(IO0, IO);
  ").

+io.set_binary_output_stream(binary_output_stream(NewStream),
+        binary_output_stream(OutStream), !IO) :-
+    io.set_binary_output_stream_2(NewStream, OutStream, !IO).
+
+:- pred io.set_binary_output_stream_2(io.stream::in, io.stream::out,
+    io::di, io::uo) is det.
  :- pragma foreign_proc("C",
-    io.set_binary_output_stream(NewStream::in, OutStream::out,
+    io.set_binary_output_stream_2(NewStream::in, OutStream::out,
          IO0::di, IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
  "
@@ -7276,9 +7568,9 @@
  :- pragma foreign_proc("C#",
      io.get_line_number(Stream::in, LineNum::out, _IO0::di, _IO::uo),
      [will_not_call_mercury, promise_pure, tabled_for_io],
-"{
+"
      LineNum = Stream.line_number;
-}").
+").

  :- pragma foreign_proc("C#",
      io.set_line_number(LineNum::in, _IO0::di, _IO::uo),
@@ -7525,10 +7817,10 @@
      % Both StreamId and Stream are valid only if Result == 0.
      %
  :- pred io.do_open_binary(string::in, string::in, int::out, int::out,
-    io.input_stream::out, io::di, io::uo) is det.
+    io.stream::out, io::di, io::uo) is det.

  :- pred io.do_open_text(string::in, string::in, int::out, int::out,
-    io.input_stream::out, io::di, io::uo) is det.
+    io.stream::out, io::di, io::uo) is det.

  :- pragma foreign_proc("C",
      io.do_open_text(FileName::in, Mode::in, ResultCode::out,
@@ -7632,19 +7924,19 @@
      }
  ").

-io.close_input(Stream, !IO) :-
+io.close_input(input_stream(Stream), !IO) :-
      io.maybe_delete_stream_info(Stream, !IO),
      io.close_stream(Stream, !IO).

-io.close_output(Stream, !IO) :-
+io.close_output(output_stream(Stream), !IO) :-
      io.maybe_delete_stream_info(Stream, !IO),
      io.close_stream(Stream, !IO).

-io.close_binary_input(Stream, !IO) :-
+io.close_binary_input(binary_input_stream(Stream), !IO) :-
      io.maybe_delete_stream_info(Stream, !IO),
      io.close_stream(Stream, !IO).

-io.close_binary_output(Stream, !IO) :-
+io.close_binary_output(binary_output_stream(Stream), !IO) :-
      io.maybe_delete_stream_info(Stream, !IO),
      io.close_stream(Stream, !IO).

Index: runtime/mercury_init.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_init.h,v
retrieving revision 1.48
diff -u -r1.48 mercury_init.h
--- runtime/mercury_init.h	29 Mar 2006 08:07:54 -0000	1.48
+++ runtime/mercury_init.h	2 Oct 2006 04:22:00 -0000
@@ -117,7 +117,7 @@
  ** accept this because it avoids having the runtime rely on the library.
  */

-/* in library/io.h */
+/* in library/io.mh */
  extern	void	mercury_init_io(void);
  extern	void	ML_io_init_state(void);
  extern	void	ML_io_finalize_state(void);
Index: runtime/mercury_library_types.h
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_library_types.h,v
retrieving revision 1.13
diff -u -r1.13 mercury_library_types.h
--- runtime/mercury_library_types.h	24 May 2004 04:32:48 -0000	1.13
+++ runtime/mercury_library_types.h	2 Oct 2006 04:22:00 -0000
@@ -19,7 +19,7 @@
  #include <stdarg.h>		/* for `va_list' */

  /*
-** The C `MercuryFile' type is used for the Mercury `io__stream' type
+** The C `MercuryFile' type is used for the Mercury `io.stream' type
  ** in library/io.m.
  ** Mercury files are not quite the same as C stdio FILEs,
  ** because we keep track of a lot more information.
@@ -150,4 +150,27 @@

  typedef MercuryFile	*MercuryFilePtr;

+/*
+** This macro should be used to wrap arguments of type MercuryFilePtr
+** that are being passed to exported Mercury procedures where the type
+** of the corresponding argument in the Mercury procedure is
+** io.input_stream or io.binary_input_stream.
+*/
+#define MR_wrap_output_stream(mf) ((MR_Word)(mf))
+
+/*
+** This macro should be used to wrap arguments of type MercuryFilePtr
+** that are being passed to exported Mercury procedures where the type
+** of the corresponding argument in the Mercury procedure is
+** io.output_stream or io.binary_output_stream.
+*/
+#define MR_wrap_input_stream(mf) ((MR_Word)(mf))
+
+/* 
+** Do the reverse to above.
+** The only place we use this in browser/listing.m.
+*/
+#define MR_unwrap_input_stream(mf) ((MercuryFilePtr)(mf))
+#define MR_unwrap_output_stream(mf) ((MercuryFilePtr)(mf))
+
  #endif /* not MERCURY_LIBRARY_TYPES_H */
Index: runtime/mercury_wrapper.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/runtime/mercury_wrapper.c,v
retrieving revision 1.169
diff -u -r1.169 mercury_wrapper.c
--- runtime/mercury_wrapper.c	2 Oct 2006 10:14:40 -0000	1.169
+++ runtime/mercury_wrapper.c	3 Oct 2006 02:57:42 -0000
@@ -389,9 +389,9 @@
  const char  *MR_runtime_flags = "";

  void        (*MR_library_initializer)(void);
-            /* normally ML_io_init_state (io__init_state/2)*/
+            /* normally ML_io_init_state (io.init_state/2)*/
  void        (*MR_library_finalizer)(void);
-            /* normally ML_io_finalize_state (io__finalize_state/2) */
+            /* normally ML_io_finalize_state (io.finalize_state/2) */

  void        (*MR_io_stderr_stream)(MercuryFilePtr *);
  void        (*MR_io_stdout_stream)(MercuryFilePtr *);
Index: tests/hard_coded/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/hard_coded/Mmakefile,v
retrieving revision 1.296
diff -u -r1.296 Mmakefile
--- tests/hard_coded/Mmakefile	16 Sep 2006 10:46:40 -0000	1.296
+++ tests/hard_coded/Mmakefile	3 Oct 2006 04:10:56 -0000
@@ -151,6 +151,7 @@
  	pragma_inline \
  	pretty_printing \
  	prince_frameopt \
+	print_stream \
  	promise_equivalent_clauses \
  	promise_equivalent_solutions_test \
  	promise_equiv_with_svars \
Index: tests/hard_coded/print_stream.exp
===================================================================
RCS file: tests/hard_coded/print_stream.exp
diff -N tests/hard_coded/print_stream.exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/print_stream.exp	3 Oct 2006 04:10:24 -0000
@@ -0,0 +1,5 @@
+stream(0, input, preopen, stdin)
+stream(1, output, preopen, stdout)
+stream(1, output, preopen, stderr)
+unknown_stream
+unknown_stream
Index: tests/hard_coded/print_stream.m
===================================================================
RCS file: tests/hard_coded/print_stream.m
diff -N tests/hard_coded/print_stream.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/hard_coded/print_stream.m	3 Oct 2006 04:10:24 -0000
@@ -0,0 +1,20 @@
+:- module print_stream.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+main(!IO) :-
+	io.stdout_stream(StdOut, !IO),
+	io.stdin_stream(StdIn, !IO),
+	io.stderr_stream(StdErr, !IO),
+	io.stdin_binary_stream(StdInBin, !IO),
+	io.stdout_binary_stream(StdOutBin, !IO),
+	io.write(StdIn, !IO),     io.nl(!IO),
+	io.write(StdOut, !IO),    io.nl(!IO),
+	io.write(StdErr, !IO),    io.nl(!IO),
+	io.write(StdInBin, !IO),  io.nl(!IO),
+	io.write(StdOutBin, !IO), io.nl(!IO).
Index: tests/invalid/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/invalid/Mmakefile,v
retrieving revision 1.196
diff -u -r1.196 Mmakefile
--- tests/invalid/Mmakefile	1 Aug 2006 23:36:59 -0000	1.196
+++ tests/invalid/Mmakefile	2 Oct 2006 04:22:00 -0000
@@ -117,6 +117,7 @@
  	missing_det_decls \
  	missing_init_pred \
  	missing_interface_import \
+	mixed_up_streams \
  	mode_inf \
  	modes_erroneous \
  	mostly_uniq1 \
Index: tests/invalid/mixed_up_streams.err_exp
===================================================================
RCS file: tests/invalid/mixed_up_streams.err_exp
diff -N tests/invalid/mixed_up_streams.err_exp
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/mixed_up_streams.err_exp	2 Oct 2006 05:23:38 -0000
@@ -0,0 +1,6 @@
+mixed_up_streams.m:014: In clause for predicate `main'/2:
+mixed_up_streams.m:014:   in argument 1 of call to predicate `io.write_byte'/4:
+mixed_up_streams.m:014:   type error: variable `BinaryInput' has type
+mixed_up_streams.m:014:   `(io.binary_input_stream)',
+mixed_up_streams.m:014:   expected type was `(io.binary_output_stream)'.
+For more information, recompile with `-E'.
Index: tests/invalid/mixed_up_streams.m
===================================================================
RCS file: tests/invalid/mixed_up_streams.m
diff -N tests/invalid/mixed_up_streams.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/invalid/mixed_up_streams.m	2 Oct 2006 04:22:00 -0000
@@ -0,0 +1,14 @@
+% rotd-2006-09-27 and before didn't complain if we pass a binary_input_stream
+% where a binary_output_stream was expected.
+:- module mixed_up_streams.
+:- interface.
+
+:- import_module io.
+
+:- pred main(io::di, io::uo) is det.
+
+:- implementation.
+
+main(!IO) :-
+	io.binary_input_stream(BinaryInput, !IO),
+	io.write_byte(BinaryInput, 0x1, !IO).
Index: tests/valid/Mmakefile
===================================================================
RCS file: /home/mercury/mercury1/repository/tests/valid/Mmakefile,v
retrieving revision 1.179
diff -u -r1.179 Mmakefile
--- tests/valid/Mmakefile	22 Sep 2006 05:35:33 -0000	1.179
+++ tests/valid/Mmakefile	2 Oct 2006 04:22:00 -0000
@@ -71,6 +71,7 @@
  	det_inference \
  	det_switch \
  	double_vn \
+	file_stream_instances \
  	easy_nondet_test \
  	easy_nondet_test_2 \
  	empty_bound_inst_list \
Index: tests/valid/file_stream_instances.m
===================================================================
RCS file: tests/valid/file_stream_instances.m
diff -N tests/valid/file_stream_instances.m
--- /dev/null	1 Jan 1970 00:00:00 -0000
+++ tests/valid/file_stream_instances.m	2 Oct 2006 04:22:00 -0000
@@ -0,0 +1,18 @@
+:- module file_stream_instances.
+:- interface.
+
+:- import_module io.
+
+:- typeclass file_stream(Stream) where [].
+
+:- instance file_stream(io.input_stream).
+:- instance file_stream(io.output_stream).
+:- instance file_stream(io.binary_input_stream).
+:- instance file_stream(io.binary_output_stream).
+
+:- implementation.
+
+:- instance file_stream(io.input_stream) where [].
+:- instance file_stream(io.output_stream) where [].
+:- instance file_stream(io.binary_input_stream) where [].
+:- instance file_stream(io.binary_output_stream) where [].
Index: trace/mercury_trace_browse.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_browse.c,v
retrieving revision 1.40
diff -u -r1.40 mercury_trace_browse.c
--- trace/mercury_trace_browse.c	6 Apr 2006 06:14:40 -0000	1.40
+++ trace/mercury_trace_browse.c	2 Oct 2006 04:22:00 -0000
@@ -95,7 +95,7 @@
      MR_c_file_to_mercury_file(MR_mdb_out, &mdb_out);
      MR_TRACE_CALL_MERCURY(
          ML_BROWSE_save_term_to_file(mercury_filename, mercury_format,
-            browser_term, &mdb_out);
+            browser_term, MR_wrap_output_stream(&mdb_out));
      );
  }

@@ -110,7 +110,7 @@
      MR_c_file_to_mercury_file(MR_mdb_out, &mdb_out);
      MR_TRACE_CALL_MERCURY(
          ML_BROWSE_save_term_to_file_xml(mercury_filename, browser_term,
-            &mdb_out);
+            MR_wrap_output_stream(&mdb_out));
      );
  }

@@ -124,7 +124,9 @@
      MR_c_file_to_mercury_file(MR_mdb_err, &mdb_err);

      MR_TRACE_CALL_MERCURY(
-        ML_BROWSE_browse_term_xml(browser_term, &mdb_out, &mdb_err,
+        ML_BROWSE_browse_term_xml(browser_term,
+            MR_wrap_output_stream(&mdb_out),
+            MR_wrap_output_stream(&mdb_err),
              MR_trace_browser_persistent_state);
      );
  }
@@ -170,14 +172,18 @@
      if (format != MR_BROWSE_DEFAULT_FORMAT) {
          MR_TRACE_CALL_MERCURY(
              ML_BROWSE_browse_browser_term_format(browser_term,
-                &mdb_in, &mdb_out, (MR_Word) format,
+                MR_wrap_input_stream(&mdb_in),
+                MR_wrap_output_stream(&mdb_out),
+                (MR_Word) format,
                  MR_trace_browser_persistent_state,
                  &MR_trace_browser_persistent_state);
          );
      } else {
          MR_TRACE_CALL_MERCURY(
              ML_BROWSE_browse_browser_term(browser_term,
-                &mdb_in, &mdb_out, &maybe_mark,
+                MR_wrap_input_stream(&mdb_in),
+                MR_wrap_output_stream(&mdb_out),
+                &maybe_mark,
                  MR_trace_browser_persistent_state,
                  &MR_trace_browser_persistent_state);
          );
@@ -206,14 +212,18 @@
      if (format != MR_BROWSE_DEFAULT_FORMAT) {
          MR_TRACE_CALL_MERCURY(
              ML_BROWSE_browse_browser_term_format(browser_term,
-                &mdb_in, &mdb_out, (MR_Word) format,
+                MR_wrap_input_stream(&mdb_in),
+                MR_wrap_output_stream(&mdb_out),
+                (MR_Word) format,
                  MR_trace_browser_persistent_state,
                  &MR_trace_browser_persistent_state);
          );
      } else {
          MR_TRACE_CALL_MERCURY(
              ML_BROWSE_browse_browser_term(browser_term,
-                &mdb_in, &mdb_out, &maybe_mark,
+                MR_wrap_input_stream(&mdb_in),
+                MR_wrap_output_stream(&mdb_out),
+                &maybe_mark,
                  MR_trace_browser_persistent_state,
                  &MR_trace_browser_persistent_state);
          );
@@ -240,7 +250,8 @@

      MR_TRACE_CALL_MERCURY(
          ML_BROWSE_browse_external(type_info, value,
-            &MR_debugger_socket_in, &MR_debugger_socket_out,
+            MR_wrap_input_stream(&MR_debugger_socket_in),
+            MR_wrap_output_stream(&MR_debugger_socket_out),
              MR_trace_browser_persistent_state,
              &MR_trace_browser_persistent_state);
      );
@@ -267,12 +278,14 @@

      if (format != MR_BROWSE_DEFAULT_FORMAT) {
          MR_TRACE_CALL_MERCURY(
-            ML_BROWSE_print_browser_term_format(browser_term, &mdb_out, caller,
+            ML_BROWSE_print_browser_term_format(browser_term, 
+                MR_wrap_output_stream(&mdb_out), caller,
                  (MR_Word) format, MR_trace_browser_persistent_state);
          );
      } else {
          MR_TRACE_CALL_MERCURY(
-            ML_BROWSE_print_browser_term(browser_term, &mdb_out,
+            ML_BROWSE_print_browser_term(browser_term,
+                MR_wrap_output_stream(&mdb_out),
                  (MR_Word) caller, MR_trace_browser_persistent_state);
          );
      }
@@ -293,12 +306,14 @@

      if (format != MR_BROWSE_DEFAULT_FORMAT) {
          MR_TRACE_CALL_MERCURY(
-            ML_BROWSE_print_browser_term_format(browser_term, &mdb_out, caller,
+            ML_BROWSE_print_browser_term_format(browser_term, 
+                MR_wrap_output_stream(&mdb_out), caller,
                  (MR_Word) format, MR_trace_browser_persistent_state);
          );
      } else {
          MR_TRACE_CALL_MERCURY(
-            ML_BROWSE_print_browser_term(browser_term, &mdb_out,
+            ML_BROWSE_print_browser_term(browser_term,
+                MR_wrap_output_stream(&mdb_out),
                  (MR_Word) caller, MR_trace_browser_persistent_state);
          );
      }
@@ -376,7 +391,8 @@

      MR_TRACE_CALL_MERCURY(
          ML_query(type, imports_list, (MR_String) options_on_heap,
-            &mdb_in, &mdb_out);
+            MR_wrap_input_stream(&mdb_in),
+            MR_wrap_output_stream(&mdb_out));
      );
  }

@@ -388,7 +404,8 @@
  {
      MR_TRACE_CALL_MERCURY(
          ML_query_external(type, imports_list, options,
-            &MR_debugger_socket_in, &MR_debugger_socket_out);
+            MR_wrap_input_stream(&MR_debugger_socket_in),
+            MR_wrap_output_stream(&MR_debugger_socket_out));
      );
  }

Index: trace/mercury_trace_declarative.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_declarative.c,v
retrieving revision 1.103
diff -u -r1.103 mercury_trace_declarative.c
--- trace/mercury_trace_declarative.c	2 Oct 2006 05:21:44 -0000	1.103
+++ trace/mercury_trace_declarative.c	2 Oct 2006 07:37:35 -0000
@@ -1416,7 +1416,9 @@
          MR_trace_browse_ensure_init();
          MR_TRACE_CALL_MERCURY(
              MR_trace_node_store = 0;
-            MR_DD_decl_diagnosis_state_init(&mdb_in, &mdb_out,
+            MR_DD_decl_diagnosis_state_init(
+                MR_wrap_input_stream(&mdb_in),
+                MR_wrap_output_stream(&mdb_out),
                  MR_trace_browser_persistent_state, MR_trace_help_system,
                  &MR_trace_front_end_state);
          );
@@ -1832,7 +1834,8 @@
          MR_mercuryfile_init(MR_trace_store_file, 1, &stream);

          MR_TRACE_CALL_MERCURY(
-            MR_DD_save_trace(&stream, MR_trace_node_store, root);
+            MR_DD_save_trace(MR_wrap_output_stream(&stream),
+                MR_trace_node_store, root);
          );

          fclose(MR_trace_store_file);
Index: trace/mercury_trace_external.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_external.c,v
retrieving revision 1.80
diff -u -r1.80 mercury_trace_external.c
--- trace/mercury_trace_external.c	4 Apr 2006 07:37:30 -0000	1.80
+++ trace/mercury_trace_external.c	2 Oct 2006 04:22:00 -0000
@@ -922,7 +922,7 @@
              layout->MR_sll_entry->MR_sle_detism,
              (MR_String) (MR_Word) path,
              lineno,
-            &MR_debugger_socket_out);
+            MR_wrap_output_stream(&MR_debugger_socket_out));
          );
      } else {
          MR_TRACE_CALL_MERCURY(
@@ -943,7 +943,7 @@
              layout->MR_sll_entry->MR_sle_detism,
              (MR_String) (MR_Word) path,
              lineno,
-            &MR_debugger_socket_out);
+            MR_wrap_output_stream(&MR_debugger_socket_out));
          );
      }
  }
@@ -952,8 +952,10 @@
  MR_output_current_vars(MR_Word var_list, MR_Word string_list)
  {
      MR_TRACE_CALL_MERCURY(
-        ML_DI_output_current_vars(var_list, string_list,
-            &MR_debugger_socket_out);
+    ML_DI_output_current_vars(
+        var_list,
+        string_list,
+        MR_wrap_output_stream(&MR_debugger_socket_out));
      );
  }

@@ -961,7 +963,9 @@
  MR_output_current_nth_var(MR_Word var)
  {
      MR_TRACE_CALL_MERCURY(
-        ML_DI_output_current_nth_var(var, &MR_debugger_socket_out);
+    ML_DI_output_current_nth_var(
+        var,
+        MR_wrap_output_stream(&MR_debugger_socket_out));
      );
  }

@@ -969,8 +973,10 @@
  MR_output_current_live_var_names(MR_Word var_names_list, MR_Word type_list)
  {
      MR_TRACE_CALL_MERCURY(
-        ML_DI_output_current_live_var_names(var_names_list, type_list,
-            &MR_debugger_socket_out);
+    ML_DI_output_current_live_var_names(
+        var_names_list,
+        type_list,
+        MR_wrap_output_stream(&MR_debugger_socket_out));
      );
  }

@@ -981,8 +987,10 @@
      fflush(MR_file(MR_debugger_socket_in));

      MR_TRACE_CALL_MERCURY(
-        ML_DI_read_request_from_socket(&MR_debugger_socket_in, 
-            debugger_request_ptr, debugger_request_type_ptr);
+    ML_DI_read_request_from_socket(
+        MR_wrap_input_stream(&MR_debugger_socket_in), 
+        debugger_request_ptr, 
+        debugger_request_type_ptr);
      );
  }

Index: trace/mercury_trace_help.c
===================================================================
RCS file: /home/mercury/mercury1/repository/mercury/trace/mercury_trace_help.c,v
retrieving revision 1.25
diff -u -r1.25 mercury_trace_help.c
--- trace/mercury_trace_help.c	2 May 2005 04:21:19 -0000	1.25
+++ trace/mercury_trace_help.c	2 Oct 2006 04:22:00 -0000
@@ -127,7 +127,8 @@
      MR_c_file_to_mercury_file(MR_mdb_out, &mdb_out);

      MR_TRACE_CALL_MERCURY(
-        ML_HELP_help(MR_trace_help_system, &mdb_out);
+        ML_HELP_help(MR_trace_help_system,
+            MR_wrap_output_stream(&mdb_out));
      );
  }

@@ -145,7 +146,8 @@

      MR_c_file_to_mercury_file(MR_mdb_out, &mdb_out);
      MR_TRACE_CALL_MERCURY(
-        ML_HELP_name(MR_trace_help_system, word_on_heap, &mdb_out);
+        ML_HELP_name(MR_trace_help_system, word_on_heap,
+            MR_wrap_output_stream(&mdb_out));
      );
  }

@@ -172,7 +174,9 @@

      MR_c_file_to_mercury_file(MR_mdb_out, &mdb_out);
      MR_TRACE_CALL_MERCURY(
-        ML_HELP_path(MR_trace_help_system, path, &mdb_out, &result);
+        ML_HELP_path(MR_trace_help_system, path,
+            MR_wrap_output_stream(&mdb_out),
+            &result);
          error = ML_HELP_result_is_error(result, &msg);
      );


--------------------------------------------------------------------------
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