diff options
| author | Nick Cameron <ncameron@mozilla.com> | 2014-10-01 19:01:08 +1300 |
|---|---|---|
| committer | Nick Cameron <ncameron@mozilla.com> | 2014-10-30 15:51:55 +1300 |
| commit | 1d500cfd74c02b6f9f84a4e7387d8126c79f3f76 (patch) | |
| tree | f4c5489c98cfb2deb492c37021f4ab7d3ed54427 | |
| parent | 8d8d8d4e5292c2fa4a622d981a5f85fd3d8f34d0 (diff) | |
| download | rust-1d500cfd74c02b6f9f84a4e7387d8126c79f3f76.tar.gz rust-1d500cfd74c02b6f9f84a4e7387d8126c79f3f76.zip | |
changes to libs
| -rw-r--r-- | src/librustc/diagnostics.rs | 1 | ||||
| -rw-r--r-- | src/librustc/middle/typeck/check/vtable.rs | 76 | ||||
| -rw-r--r-- | src/libstd/io/buffered.rs | 4 | ||||
| -rw-r--r-- | src/libstd/io/mem.rs | 8 | ||||
| -rw-r--r-- | src/libstd/io/mod.rs | 34 | ||||
| -rw-r--r-- | src/libterm/lib.rs | 29 | ||||
| -rw-r--r-- | src/libterm/terminfo/mod.rs | 91 | ||||
| -rw-r--r-- | src/test/run-fail/by-value-self-objects-fail.rs | 51 |
8 files changed, 145 insertions, 149 deletions
diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index f405e9df51d..c4e21379088 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -53,7 +53,6 @@ register_diagnostics!( E0035, E0036, E0038, - E0039, E0040, E0044, E0045, diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 639ba9bdf49..4829083f021 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -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, @@ -131,18 +130,46 @@ 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 @@ -150,13 +177,14 @@ pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Spa * 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 | @@ -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 } } diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index 9cd8dbcc509..cbb982e731a 100644 --- a/src/libstd/io/buffered.rs +++ b/src/libstd/io/buffered.rs @@ -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}; @@ -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 diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index 2f6dd7e4795..c743bee1fc9 100644 --- a/src/libstd/io/mem.rs +++ b/src/libstd/io/mem.rs @@ -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; @@ -97,6 +97,8 @@ impl Writer for MemWriter { } } +impl AsRefWriter for MemWriter {} + /// Reads from an owned byte vector /// /// # Example @@ -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) } @@ -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) } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 7826a6dd9c6..6aba5f67643 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -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. @@ -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 @@ -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; @@ -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(); @@ -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 @@ -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(); /// diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index fbf17b76d62..37c7162333b 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -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)] @@ -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)] @@ -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, @@ -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; +} diff --git a/src/libterm/terminfo/mod.rs b/src/libterm/terminfo/mod.rs index 36883c8fcf4..73edcf94892 100644 --- a/src/libterm/terminfo/mod.rs +++ b/src/libterm/terminfo/mod.rs @@ -17,6 +17,7 @@ use std::os; use attr; use color; use Terminal; +use UnwrappableTerminal; use self::searcher::open; use self::parser::compiled::{parse, msys_terminfo}; use self::parm::{expand, Number, Variables}; @@ -71,44 +72,7 @@ pub struct TerminfoTerminal<T> { ti: Box<TermInfo> } -impl<T: Writer> Terminal<T> for TerminfoTerminal<T> { - fn new(out: T) -> Option<TerminfoTerminal<T>> { - let term = match os::getenv("TERM") { - Some(t) => t, - None => { - debug!("TERM environment variable not defined"); - return None; - } - }; - - let entry = open(term.as_slice()); - if entry.is_err() { - if os::getenv("MSYSCON").map_or(false, |s| { - "mintty.exe" == s.as_slice() - }) { - // msys terminal - return Some(TerminfoTerminal {out: out, ti: msys_terminfo(), num_colors: 8}); - } - debug!("error finding terminfo entry: {}", entry.err().unwrap()); - return None; - } - - let mut file = entry.unwrap(); - let ti = parse(&mut file, false); - if ti.is_err() { - debug!("error parsing terminfo entry: {}", ti.unwrap_err()); - return None; - } - - let inf = ti.unwrap(); - let nc = if inf.strings.find_equiv(&("setaf")).is_some() - && inf.strings.find_equiv(&("setab")).is_some() { - inf.numbers.find_equiv(&("colors")).map_or(0, |&n| n) - } else { 0 }; - - return Some(TerminfoTerminal {out: out, ti: inf, num_colors: nc}); - } - +impl<T: Writer+Send> Terminal<T> for TerminfoTerminal<T> { fn fg(&mut self, color: color::Color) -> IoResult<bool> { let color = self.dim_if_necessary(color); if self.num_colors > color { @@ -195,14 +159,59 @@ impl<T: Writer> Terminal<T> for TerminfoTerminal<T> { Ok(()) } - fn unwrap(self) -> T { self.out } - fn get_ref<'a>(&'a self) -> &'a T { &self.out } fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.out } } -impl<T: Writer> TerminfoTerminal<T> { +impl<T: Writer+Send> UnwrappableTerminal<T> for TerminfoTerminal<T> { + fn unwrap(self) -> T { self.out } +} + +impl<T: Writer+Send> TerminfoTerminal<T> { + /// Returns `None` whenever the terminal cannot be created for some + /// reason. + pub fn new(out: T) -> Option<Box<Terminal<T>+Send+'static>> { + let term = match os::getenv("TERM") { + Some(t) => t, + None => { + debug!("TERM environment variable not defined"); + return None; + } + }; + + let entry = open(term.as_slice()); + if entry.is_err() { + if os::getenv("MSYSCON").map_or(false, |s| { + "mintty.exe" == s.as_slice() + }) { + // msys terminal + return Some(box TerminfoTerminal {out: out, + ti: msys_terminfo(), + num_colors: 8} as Box<Terminal<T>+Send>); + } + debug!("error finding terminfo entry: {}", entry.err().unwrap()); + return None; + } + + let mut file = entry.unwrap(); + let ti = parse(&mut file, false); + if ti.is_err() { + debug!("error parsing terminfo entry: {}", ti.unwrap_err()); + return None; + } + + let inf = ti.unwrap(); + let nc = if inf.strings.find_equiv(&("setaf")).is_some() + && inf.strings.find_equiv(&("setab")).is_some() { + inf.numbers.find_equiv(&("colors")).map_or(0, |&n| n) + } else { 0 }; + + return Some(box TerminfoTerminal {out: out, + ti: inf, + num_colors: nc} as Box<Terminal<T>+Send>); + } + fn dim_if_necessary(&self, color: color::Color) -> color::Color { if color >= self.num_colors && color >= 8 && color < 16 { color-8 diff --git a/src/test/run-fail/by-value-self-objects-fail.rs b/src/test/run-fail/by-value-self-objects-fail.rs deleted file mode 100644 index 6b000866d3a..00000000000 --- a/src/test/run-fail/by-value-self-objects-fail.rs +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// error-pattern:explicit panic - -trait Foo { - fn foo(self, x: int); -} - -struct S { - x: int, - y: int, - z: int, - s: String, -} - -impl Foo for S { - fn foo(self, x: int) { - panic!() - } -} - -impl Drop for S { - fn drop(&mut self) { - println!("bye 1!"); - } -} - -fn f() { - let s = S { - x: 2, - y: 3, - z: 4, - s: "hello".to_string(), - }; - let st = box s as Box<Foo>; - st.foo(5); -} - -fn main() { - f(); -} - - |
