Skip to content

Commit 2cebef0

Browse files
committed
stdlib: Make io failures recoverable by returning a result
1 parent 2b62a80 commit 2cebef0

File tree

11 files changed

+123
-37
lines changed

11 files changed

+123
-37
lines changed

src/comp/driver/rustc.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import syntax::print::{pp, pprust};
1111
import util::{ppaux, common, filesearch};
1212
import back::link;
1313
import lib::llvm;
14-
import std::{fs, option, str, vec, int, io, run, getopts};
14+
import std::{fs, option, str, vec, int, io, run, getopts, result};
1515
import std::map::mk_hashmap;
1616
import std::option::{some, none};
1717
import std::getopts::{optopt, optmulti, optflag, optflagopt, opt_present};
@@ -77,10 +77,16 @@ fn parse_input(sess: session::session, cfg: ast::crate_cfg, input: str) ->
7777

7878
fn parse_input_src(sess: session::session, cfg: ast::crate_cfg, infile: str)
7979
-> {crate: @ast::crate, src: str} {
80-
let srcbytes =
81-
if infile != "-" {
82-
io::file_reader(infile)
83-
} else { io::stdin() }.read_whole_stream();
80+
let srcbytes = if infile != "-" {
81+
alt io::file_reader(infile) {
82+
result::ok(reader) { reader }
83+
result::err(e) {
84+
sess.fatal(e)
85+
}
86+
}
87+
} else {
88+
io::stdin()
89+
}.read_whole_stream();
8490
let src = str::unsafe_from_bytes(srcbytes);
8591
let crate =
8692
parser::parse_crate_from_source_str(infile, src, cfg,

src/comp/syntax/codemap.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import std::{vec, uint, str, term, io, option};
1+
import std::{vec, uint, str, term, io, option, result};
22
import std::option::{some, none};
33

44
type filename = str;
@@ -154,7 +154,13 @@ fn maybe_highlight_lines(sp: option::t<span>, cm: codemap,
154154

155155
// FIXME: reading in the entire file is the worst possible way to
156156
// get access to the necessary lines.
157-
let file = io::read_whole_file_str(lines.name);
157+
let file = alt io::read_whole_file_str(lines.name) {
158+
result::ok(file) { file }
159+
result::err(e) {
160+
emit_error(none, e, cm);
161+
fail;
162+
}
163+
};
158164
let fm = get_filemap(cm, lines.name);
159165

160166
// arbitrarily only print up to six lines of the error

src/comp/syntax/parse/parser.rs

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
import std::{io, vec, str, option, either};
2+
import std::{io, vec, str, option, either, result};
33
import std::option::{some, none};
44
import std::either::{left, right};
55
import std::map::{hashmap, new_str_hash};
@@ -53,7 +53,16 @@ type parser =
5353
fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, path: str,
5454
chpos: uint, byte_pos: uint, ftype: file_type) ->
5555
parser {
56-
let src = io::read_whole_file_str(path);
56+
let src = alt io::read_whole_file_str(path) {
57+
result::ok(src) {
58+
// FIXME: This copy is unfortunate
59+
src
60+
}
61+
result::err(e) {
62+
codemap::emit_error(none, e, sess.cm);
63+
fail;
64+
}
65+
};
5766
let filemap = codemap::new_filemap(path, chpos, byte_pos);
5867
sess.cm.files += [filemap];
5968
let itr = @interner::mk(str::hash, str::eq);

src/compiletest/header.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ fn is_test_ignored(config: config, testfile: str) -> bool {
6363
}
6464

6565
fn iter_header(testfile: str, it: block(str)) {
66-
let rdr = io::file_reader(testfile);
66+
let rdr = std::result::get(io::file_reader(testfile));
6767
while !rdr.eof() {
6868
let ln = rdr.read_line();
6969

src/compiletest/runtest.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import std::fs;
55
import std::os;
66
import std::vec;
77
import std::test;
8+
import std::result;
89

910
import common::mode_run_pass;
1011
import common::mode_run_fail;
@@ -92,7 +93,7 @@ fn run_pretty_test(cx: cx, props: test_props, testfile: str) {
9293
let rounds =
9394
alt props.pp_exact { option::some(_) { 1 } option::none. { 2 } };
9495

95-
let srcs = [io::read_whole_file_str(testfile)];
96+
let srcs = [result::get(io::read_whole_file_str(testfile))];
9697

9798
let round = 0;
9899
while round < rounds {
@@ -112,7 +113,7 @@ fn run_pretty_test(cx: cx, props: test_props, testfile: str) {
112113
alt props.pp_exact {
113114
option::some(file) {
114115
let filepath = fs::connect(fs::dirname(testfile), file);
115-
io::read_whole_file_str(filepath)
116+
result::get(io::read_whole_file_str(filepath))
116117
}
117118
option::none. { srcs[vec::len(srcs) - 2u] }
118119
};
@@ -339,7 +340,8 @@ fn dump_output(config: config, testfile: str, out: str, err: str) {
339340
#[cfg(target_os = "linux")]
340341
fn dump_output_file(config: config, testfile: str, out: str, extension: str) {
341342
let outfile = make_out_name(config, testfile, extension);
342-
let writer = io::file_writer(outfile, [io::create, io::truncate]);
343+
let writer = result::get(
344+
io::file_writer(outfile, [io::create, io::truncate]));
343345
writer.write_str(out);
344346
}
345347

src/fuzzer/fuzzer.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use std;
22
use rustc;
33

4-
import std::{fs, io, getopts, math, vec, str, int, uint, option};
4+
import std::{fs, io, getopts, math, vec, str, int, uint, option, result};
55
import std::getopts::{optopt, opt_present, opt_str};
66
import std::io::stdout;
77

@@ -13,7 +13,9 @@ tag test_mode { tm_converge; tm_run; }
1313
type context = { mode: test_mode }; // + rng
1414

1515
fn write_file(filename: str, content: str) {
16-
io::file_writer(filename, [io::create, io::truncate]).write_str(content);
16+
result::get(
17+
io::file_writer(filename, [io::create, io::truncate]))
18+
.write_str(content);
1719
// Work around https://github.com/graydon/rust/issues/726
1820
std::run::run_program("chmod", ["644", filename]);
1921
}
@@ -517,7 +519,7 @@ fn check_convergence(files: [str]) {
517519
log_err #fmt["pp convergence tests: %u files", vec::len(files)];
518520
for file in files {
519521
if !file_might_not_converge(file) {
520-
let s = io::read_whole_file_str(file);
522+
let s = result::get(io::read_whole_file_str(file));
521523
if !content_might_not_converge(s) {
522524
log_err #fmt["pp converge: %s", file];
523525
// Change from 7u to 2u once https://github.com/graydon/rust/issues/850 is fixed
@@ -533,7 +535,7 @@ fn check_variants(files: [str], cx: context) {
533535
cont;
534536
}
535537

536-
let s = io::read_whole_file_str(file);
538+
let s = result::get(io::read_whole_file_str(file));
537539
if contains(s, "#") {
538540
cont; // Macros are confusing
539541
}

src/lib/io.rs

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -173,14 +173,16 @@ fn stdin() -> reader {
173173
ret new_reader(FILE_buf_reader(rustrt::rust_get_stdin(), option::none));
174174
}
175175

176-
fn file_reader(path: str) -> reader {
176+
fn file_reader(path: str) -> result::t<reader, str> {
177177
let f = str::as_buf(path, {|pathbuf|
178178
str::as_buf("r", {|modebuf|
179179
os::libc::fopen(pathbuf, modebuf)
180180
})
181181
});
182-
if f as uint == 0u { log_err "error opening " + path; fail; }
183-
ret new_reader(FILE_buf_reader(f, option::some(@FILE_res(f))));
182+
ret if f as uint == 0u { result::err("error opening " + path) }
183+
else {
184+
result::ok(new_reader(FILE_buf_reader(f, option::some(@FILE_res(f)))))
185+
}
184186
}
185187

186188

@@ -278,7 +280,8 @@ obj fd_buf_writer(fd: int, res: option::t<@fd_res>) {
278280
}
279281
}
280282

281-
fn file_buf_writer(path: str, flags: [fileflag]) -> buf_writer {
283+
fn file_buf_writer(path: str,
284+
flags: [fileflag]) -> result::t<buf_writer, str> {
282285
let fflags: int =
283286
os::libc_constants::O_WRONLY() | os::libc_constants::O_BINARY();
284287
for f: fileflag in flags {
@@ -296,12 +299,12 @@ fn file_buf_writer(path: str, flags: [fileflag]) -> buf_writer {
296299
os::libc_constants::S_IRUSR() |
297300
os::libc_constants::S_IWUSR())
298301
});
299-
if fd < 0 {
300-
log_err "error opening file for writing";
302+
ret if fd < 0 {
301303
log_err sys::last_os_error();
302-
fail;
304+
result::err("error opening " + path)
305+
} else {
306+
result::ok(fd_buf_writer(fd, option::some(@fd_res(fd))))
303307
}
304-
ret fd_buf_writer(fd, option::some(@fd_res(fd)));
305308
}
306309

307310
type writer =
@@ -359,13 +362,15 @@ obj new_writer(out: buf_writer) {
359362
}
360363
}
361364

362-
fn file_writer(path: str, flags: [fileflag]) -> writer {
363-
ret new_writer(file_buf_writer(path, flags));
365+
fn file_writer(path: str, flags: [fileflag]) -> result::t<writer, str> {
366+
result::chain(file_buf_writer(path, flags), { |w|
367+
result::ok(new_writer(w))
368+
})
364369
}
365370

366371

367372
// FIXME: fileflags
368-
fn buffered_file_buf_writer(path: str) -> buf_writer {
373+
fn buffered_file_buf_writer(path: str) -> result::t<buf_writer, str> {
369374
let f =
370375
str::as_buf(path,
371376
{|pathbuf|
@@ -374,8 +379,8 @@ fn buffered_file_buf_writer(path: str) -> buf_writer {
374379
os::libc::fopen(pathbuf, modebuf)
375380
})
376381
});
377-
if f as uint == 0u { log_err "error opening " + path; fail; }
378-
ret FILE_writer(f, option::some(@FILE_res(f)));
382+
ret if f as uint == 0u { result::err("error opening " + path) }
383+
else { result::ok(FILE_writer(f, option::some(@FILE_res(f)))) }
379384
}
380385

381386

@@ -452,14 +457,18 @@ fn seek_in_buf(offset: int, pos: uint, len: uint, whence: seek_style) ->
452457
ret bpos as uint;
453458
}
454459

455-
fn read_whole_file_str(file: str) -> str {
456-
str::unsafe_from_bytes(read_whole_file(file))
460+
fn read_whole_file_str(file: str) -> result::t<str, str> {
461+
result::chain(read_whole_file(file), { |bytes|
462+
result::ok(str::unsafe_from_bytes(bytes))
463+
})
457464
}
458465

459-
fn read_whole_file(file: str) -> [u8] {
466+
fn read_whole_file(file: str) -> result::t<[u8], str> {
460467

461468
// FIXME: There's a lot of copying here
462-
file_reader(file).read_whole_stream()
469+
result::chain(file_reader(file), { |rdr|
470+
result::ok(rdr.read_whole_stream())
471+
})
463472
}
464473

465474

src/lib/result.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ fn get<T, U>(res: t<T, U>) -> T {
4141
alt res {
4242
ok(t) { t }
4343
err(_) {
44+
// FIXME: Serialize the error value
45+
// and include it in the fail message
4446
fail "get called on error result";
4547
}
4648
}

src/test/bench/task-perf-word-count.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import std::io;
2020

2121
import std::time;
2222
import std::u64;
23+
import std::result;
2324

2425
import std::task;
2526
import std::task::joinable_task;
@@ -30,7 +31,7 @@ import std::comm::recv;
3031
import std::comm::send;
3132

3233
fn map(filename: str, emit: map_reduce::putter) {
33-
let f = io::file_reader(filename);
34+
let f = result::get(io::file_reader(filename));
3435

3536

3637
while true {

src/test/compile-fail/missingmod.rc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
// error-pattern:error opening
2+
3+
mod doesnotexist;

src/test/stdtest/io.rs

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
use std;
33
import std::io;
44
import std::str;
5+
import std::result;
56

67
#[cfg(target_os = "linux")]
78
#[cfg(target_os = "win32")]
@@ -13,10 +14,10 @@ fn test_simple() {
1314
log frood;
1415
{
1516
let out: io::writer =
16-
io::file_writer(tmpfile, [io::create, io::truncate]);
17+
result::get(io::file_writer(tmpfile, [io::create, io::truncate]));
1718
out.write_str(frood);
1819
}
19-
let inp: io::reader = io::file_reader(tmpfile);
20+
let inp: io::reader = result::get(io::file_reader(tmpfile));
2021
let frood2: str = inp.read_c_str();
2122
log frood2;
2223
assert (str::eq(frood, frood2));
@@ -28,3 +29,48 @@ fn test_simple() {
2829
#[ignore]
2930
fn test_simple() { }
3031

32+
#[test]
33+
fn file_reader_not_exist() {
34+
alt io::file_reader("not a file") {
35+
result::err(e) {
36+
assert e == "error opening not a file";
37+
}
38+
result::ok(_) { fail; }
39+
}
40+
}
41+
42+
#[cfg(target_os = "linux")]
43+
#[cfg(target_os = "win32")]
44+
#[test]
45+
fn file_buf_writer_bad_name() {
46+
alt io::file_buf_writer("/?", []) {
47+
result::err(e) {
48+
assert e == "error opening /?";
49+
}
50+
result::ok(_) { fail; }
51+
}
52+
}
53+
54+
// FIXME (726)
55+
#[cfg(target_os = "macos")]
56+
#[test]
57+
#[ignore]
58+
fn file_buf_writer_bad_name() { }
59+
60+
#[cfg(target_os = "linux")]
61+
#[cfg(target_os = "win32")]
62+
#[test]
63+
fn buffered_file_buf_writer_bad_name() {
64+
alt io::buffered_file_buf_writer("/?") {
65+
result::err(e) {
66+
assert e == "error opening /?";
67+
}
68+
result::ok(_) { fail; }
69+
}
70+
}
71+
72+
// FIXME (726)
73+
#[cfg(target_os = "macos")]
74+
#[test]
75+
#[ignore]
76+
fn buffered_file_buf_writer_bad_name() { }

0 commit comments

Comments
 (0)