about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNick Cameron <ncameron@mozilla.com>2014-10-01 19:01:08 +1300
committerNick Cameron <ncameron@mozilla.com>2014-10-30 15:51:55 +1300
commit1d500cfd74c02b6f9f84a4e7387d8126c79f3f76 (patch)
treef4c5489c98cfb2deb492c37021f4ab7d3ed54427
parent8d8d8d4e5292c2fa4a622d981a5f85fd3d8f34d0 (diff)
downloadrust-1d500cfd74c02b6f9f84a4e7387d8126c79f3f76.tar.gz
rust-1d500cfd74c02b6f9f84a4e7387d8126c79f3f76.zip
changes to libs
-rw-r--r--src/librustc/diagnostics.rs1
-rw-r--r--src/librustc/middle/typeck/check/vtable.rs76
-rw-r--r--src/libstd/io/buffered.rs4
-rw-r--r--src/libstd/io/mem.rs8
-rw-r--r--src/libstd/io/mod.rs34
-rw-r--r--src/libterm/lib.rs29
-rw-r--r--src/libterm/terminfo/mod.rs91
-rw-r--r--src/test/run-fail/by-value-self-objects-fail.rs51
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();
-}
-
-