Skip to content

Commit

Permalink
changes to libs
Browse files Browse the repository at this point in the history
  • Loading branch information
nrc committed Oct 30, 2014
1 parent 8d8d8d4 commit 1d500cf
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 149 deletions.
1 change: 0 additions & 1 deletion src/librustc/diagnostics.rs
Expand Up @@ -53,7 +53,6 @@ register_diagnostics!(
E0035,
E0036,
E0038,
E0039,
E0040,
E0044,
E0045,
Expand Down
76 changes: 51 additions & 25 deletions src/librustc/middle/typeck/check/vtable.rs
Expand Up @@ -21,8 +21,7 @@ use middle::typeck::infer;
use std::rc::Rc;
use syntax::ast;
use syntax::codemap::Span;
use util::ppaux::UserString;
use util::ppaux::Repr;
use util::ppaux::{UserString, Repr, ty_to_string};

pub fn check_object_cast(fcx: &FnCtxt,
cast_expr: &ast::Expr,
Expand Down Expand Up @@ -131,32 +130,61 @@ pub fn check_object_cast(fcx: &FnCtxt,
}
}

// TODO comment
// Check that a trait is 'object-safe'. This should be checked whenever a trait object
// is created (by casting or coercion, etc.). A trait is object-safe if all its
// methods are object-safe. A trait method is object-safe if it does not take
// self by value, has no type parameters and does not use the `Self` type, except
// in self position.
pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Span) {
// Skip the fn_once lang item trait since only the compiler should call
// `call_once` which is the method which takes self by value. What could go
// wrong?
match tcx.lang_items.fn_once_trait() {
Some(def_id) if def_id == object_trait.def_id => return,
_ => {}
}

let trait_items = ty::trait_items(tcx, object_trait.def_id);

let mut errors = Vec::new();
for item in trait_items.iter() {
match *item {
ty::MethodTraitItem(ref m) => check_object_safety_of_method(tcx, &**m, span),
ty::MethodTraitItem(ref m) => {
errors.push(check_object_safety_of_method(tcx, &**m))
}
ty::TypeTraitItem(_) => {}
}
}

// TODO error messages
fn check_object_safety_of_method(tcx: &ty::ctxt, method: &ty::Method, span: Span) {
let mut errors = errors.iter().flat_map(|x| x.iter()).peekable();
if errors.peek().is_some() {
let trait_name = ty::item_path_str(tcx, object_trait.def_id);
span_err!(tcx.sess, span, E0038,
"cannot convert to a trait object because trait `{}` is not object-safe",
trait_name);

for msg in errors {
tcx.sess.note(msg.as_slice());
}
}

// Returns a vec of error messages. If hte vec is empty - no errors!
fn check_object_safety_of_method(tcx: &ty::ctxt, method: &ty::Method) -> Vec<String> {
/*!
* There are some limitations to calling functions through an
* object, because (a) the self type is not known
* (that's the whole point of a trait instance, after all, to
* obscure the self type) and (b) the call must go through a
* vtable and hence cannot be monomorphized.
*/
let mut msgs = Vec::new();

let method_name = method.ident.repr(tcx);

match method.explicit_self {
ty::ByValueExplicitSelfCategory => { // reason (a) above
tcx.sess.span_err(
span,
"cannot call a method with a by-value receiver \
through a trait object");
msgs.push(format!("cannot call a method (`{}`) with a by-value \
receiver through a trait object", method_name))
}

ty::StaticExplicitSelfCategory |
Expand All @@ -167,31 +195,29 @@ pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Spa
// reason (a) above
let check_for_self_ty = |ty| {
if ty::type_has_self(ty) {
span_err!(tcx.sess, span, E0038,
"cannot call a method whose type contains a \
self-type through an object: {}", ::util::ppaux::ty_to_string(tcx, ty));
true
Some(format!(
"cannot call a method (`{}`) whose type (`{}`) contains \
a self-type through a trait object",
method_name, ty_to_string(tcx, ty)))
} else {
false
None
}
};
let ref sig = method.fty.sig;
let mut found_self_ty = false;
for &input_ty in sig.inputs.tail().iter() {
if check_for_self_ty(input_ty) {
found_self_ty = true;
break;
for &input_ty in sig.inputs.tail().iter().chain([sig.output].iter()) {
match check_for_self_ty(input_ty) {
Some(msg) => msgs.push(msg),
_ => {}
}
}
if !found_self_ty {
check_for_self_ty(sig.output);
}

if method.generics.has_type_params(FnSpace) {
// reason (b) above
span_err!(tcx.sess, span, E0039,
"cannot call a generic method through an object");
msgs.push(format!("cannot call a generic method (`{}`) through a trait object",
method_name));
}

msgs
}
}

Expand Down
4 changes: 3 additions & 1 deletion src/libstd/io/buffered.rs
Expand Up @@ -14,7 +14,7 @@

use cmp;
use collections::Collection;
use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult};
use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult, AsRefReader};
use iter::ExactSize;
use ops::Drop;
use option::{Some, None, Option};
Expand Down Expand Up @@ -118,6 +118,8 @@ impl<R: Reader> Reader for BufferedReader<R> {
}
}

impl<R: Reader> AsRefReader for BufferedReader<R> {}

/// Wraps a Writer and buffers output to it
///
/// It can be excessively inefficient to work directly with a `Writer`. For
Expand Down
8 changes: 7 additions & 1 deletion src/libstd/io/mem.rs
Expand Up @@ -17,7 +17,7 @@ use collections::Collection;
use option::None;
use result::{Err, Ok};
use io;
use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult};
use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult, AsRefReader, AsRefWriter};
use slice;
use slice::AsSlice;
use vec::Vec;
Expand Down Expand Up @@ -97,6 +97,8 @@ impl Writer for MemWriter {
}
}

impl AsRefWriter for MemWriter {}

/// Reads from an owned byte vector
///
/// # Example
Expand Down Expand Up @@ -163,6 +165,8 @@ impl Reader for MemReader {
}
}

impl AsRefReader for MemReader {}

impl Seek for MemReader {
#[inline]
fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
Expand Down Expand Up @@ -309,6 +313,8 @@ impl<'a> Reader for BufReader<'a> {
}
}

impl<'a> AsRefReader for BufReader<'a> {}

impl<'a> Seek for BufReader<'a> {
#[inline]
fn tell(&self) -> IoResult<u64> { Ok(self.pos as u64) }
Expand Down
34 changes: 22 additions & 12 deletions src/libstd/io/mod.rs
Expand Up @@ -712,17 +712,6 @@ pub trait Reader {
})
}

/// Create an iterator that reads a single byte on
/// each iteration, until EOF.
///
/// # Error
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self> {
extensions::Bytes::new(self)
}

// Byte conversion helpers

/// Reads `n` little-endian unsigned integer bytes.
Expand Down Expand Up @@ -932,7 +921,10 @@ pub trait Reader {
fn read_i8(&mut self) -> IoResult<i8> {
self.read_byte().map(|i| i as i8)
}
}

/// A reader which can be converted to a RefReader.
pub trait AsRefReader {
/// Creates a wrapper around a mutable reference to the reader.
///
/// This is useful to allow applying adaptors while still
Expand All @@ -942,6 +934,20 @@ pub trait Reader {
}
}

/// A reader which can be converted to bytes.
pub trait BytesReader: Reader {
/// Create an iterator that reads a single byte on
/// each iteration, until EOF.
///
/// # Error
///
/// Any error other than `EndOfFile` that is produced by the underlying Reader
/// is returned by the iterator and should be handled by the caller.
fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, Self> {
extensions::Bytes::new(self)
}
}

impl<'a> Reader for Box<Reader+'a> {
fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
let reader: &mut Reader = &mut **self;
Expand Down Expand Up @@ -986,6 +992,7 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec<T>, start: uint, end: uint) -
/// # fn process_input<R: Reader>(r: R) {}
/// # fn foo() {
/// use std::io;
/// use std::io::AsRefReader;
/// use std::io::util::LimitReader;
///
/// let mut stream = io::stdin();
Expand Down Expand Up @@ -1268,7 +1275,10 @@ pub trait Writer {
fn write_i8(&mut self, n: i8) -> IoResult<()> {
self.write([n as u8])
}
}

/// A writer which can be converted to a RefWriter.
pub trait AsRefWriter {
/// Creates a wrapper around a mutable reference to the writer.
///
/// This is useful to allow applying wrappers while still
Expand Down Expand Up @@ -1309,7 +1319,7 @@ impl<'a> Writer for &'a mut Writer+'a {
/// # fn process_input<R: Reader>(r: R) {}
/// # fn foo () {
/// use std::io::util::TeeReader;
/// use std::io::{stdin, MemWriter};
/// use std::io::{stdin, MemWriter, AsRefWriter};
///
/// let mut output = MemWriter::new();
///
Expand Down
29 changes: 12 additions & 17 deletions src/libterm/lib.rs
Expand Up @@ -89,11 +89,9 @@ impl Writer for WriterWrapper {
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
/// opened.
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
let ti: Option<TerminfoTerminal<WriterWrapper>>
= Terminal::new(WriterWrapper {
wrapped: box std::io::stdout() as Box<Writer + Send>,
});
ti.map(|t| box t as Box<Terminal<WriterWrapper> + Send>)
TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stdout() as Box<Writer + Send>,
})
}

#[cfg(windows)]
Expand Down Expand Up @@ -121,11 +119,9 @@ pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
/// opened.
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send> + Send> {
let ti: Option<TerminfoTerminal<WriterWrapper>>
= Terminal::new(WriterWrapper {
wrapped: box std::io::stderr() as Box<Writer + Send>,
});
ti.map(|t| box t as Box<Terminal<WriterWrapper> + Send>)
TerminfoTerminal::new(WriterWrapper {
wrapped: box std::io::stderr() as Box<Writer + Send>,
})
}

#[cfg(windows)]
Expand Down Expand Up @@ -208,10 +204,6 @@ pub mod attr {
/// A terminal with similar capabilities to an ANSI Terminal
/// (foreground/background colors etc).
pub trait Terminal<T: Writer>: Writer {
/// Returns `None` whenever the terminal cannot be created for some
/// reason.
fn new(out: T) -> Option<Self>;

/// Sets the foreground color to the given color.
///
/// If the color is a bright color, but the terminal only supports 8 colors,
Expand Down Expand Up @@ -242,12 +234,15 @@ pub trait Terminal<T: Writer>: Writer {
/// Returns `Ok()`.
fn reset(&mut self) -> IoResult<()>;

/// Returns the contained stream, destroying the `Terminal`
fn unwrap(self) -> T;

/// Gets an immutable reference to the stream inside
fn get_ref<'a>(&'a self) -> &'a T;

/// Gets a mutable reference to the stream inside
fn get_mut<'a>(&'a mut self) -> &'a mut T;
}

/// A terminal which can be unwrapped.
pub trait UnwrappableTerminal<T: Writer>: Terminal<T> {
/// Returns the contained stream, destroying the `Terminal`
fn unwrap(self) -> T;
}

0 comments on commit 1d500cf

Please sign in to comment.