diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index f405e9df51db0..c4e213790880f 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/method.rs b/src/librustc/middle/typeck/check/method.rs index 7527160c825ae..cd3cc43b8539d 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -619,14 +619,12 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { let tcx = self.tcx(); - // It is illegal to invoke a method on a trait instance that - // refers to the `Self` type. An error will be reported by - // `enforce_object_limitations()` if the method refers to the - // `Self` type anywhere other than the receiver. Here, we use - // a substitution that replaces `Self` with the object type - // itself. Hence, a `&self` method will wind up with an - // argument type like `&Trait`. + // It is illegal to invoke a method on a trait instance that refers to + // the `Self` type. Here, we use a substitution that replaces `Self` + // with the object type itself. Hence, a `&self` method will wind up + // with an argument type like `&Trait`. let rcvr_substs = substs.with_self_ty(self_ty); + let trait_ref = Rc::new(TraitRef { def_id: did, substs: rcvr_substs.clone() @@ -1336,16 +1334,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.ty_to_string(rcvr_ty), candidate.repr(self.tcx())); - let mut rcvr_substs = candidate.rcvr_substs.clone(); - - if !self.enforce_object_limitations(candidate) { - // Here we change `Self` from `Trait` to `err` in the case that - // this is an illegal object method. This is necessary to prevent - // the user from getting strange, derivative errors when the method - // takes an argument/return-type of type `Self` etc. - rcvr_substs.types.get_mut_slice(SelfSpace)[0] = ty::mk_err(); - } - + let rcvr_substs = candidate.rcvr_substs.clone(); self.enforce_drop_trait_limitations(candidate); // Determine the values for the generic parameters of the method. @@ -1554,71 +1543,6 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { } } - fn enforce_object_limitations(&self, candidate: &Candidate) -> bool { - /*! - * 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. - */ - - match candidate.origin { - MethodStatic(..) | - MethodTypeParam(..) | - MethodStaticUnboxedClosure(..) => { - return true; // not a call to a trait instance - } - MethodTraitObject(..) => {} - } - - match candidate.method_ty.explicit_self { - ty::StaticExplicitSelfCategory => { // reason (a) above - self.tcx().sess.span_err( - self.span, - "cannot call a method without a receiver \ - through an object"); - return false; - } - - ty::ByValueExplicitSelfCategory | - ty::ByReferenceExplicitSelfCategory(..) | - ty::ByBoxExplicitSelfCategory => {} - } - - // reason (a) above - let check_for_self_ty = |ty| -> bool { - if ty::type_has_self(ty) { - span_err!(self.tcx().sess, self.span, E0038, - "cannot call a method whose type contains a \ - self-type through an object"); - false - } else { - true - } - }; - let ref sig = candidate.method_ty.fty.sig; - for &input_ty in sig.inputs[1..].iter() { - if !check_for_self_ty(input_ty) { - return false; - } - } - if let ty::FnConverging(result_type) = sig.output { - if !check_for_self_ty(result_type) { - return false; - } - } - - if candidate.method_ty.generics.has_type_params(subst::FnSpace) { - // reason (b) above - span_err!(self.tcx().sess, self.span, E0039, - "cannot call a generic method through an object"); - return false; - } - - true - } - fn enforce_drop_trait_limitations(&self, candidate: &Candidate) { // No code can call the finalize method explicitly. let bad = match candidate.origin { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 8843be3cf816f..94c4d7c25e0a6 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1687,6 +1687,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_unsize_obligations(span, &**u) } ty::UnsizeVtable(ref ty_trait, self_ty) => { + vtable::check_object_safety(self.tcx(), ty_trait, span); // If the type is `Foo+'a`, ensures that the type // being cast to `Foo+'a` implements `Foo`: vtable::register_object_cast_obligations(self, diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index a5624dcc2fcd3..b7195734e8b39 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use middle::subst::{SelfSpace}; +use middle::subst::{SelfSpace, FnSpace}; use middle::traits; use middle::traits::{SelectionError, OutputTypeParameterMismatch, Overflow, Unimplemented}; use middle::traits::{Obligation, obligation_for_builtin_bound}; @@ -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, @@ -46,6 +45,7 @@ pub fn check_object_cast(fcx: &FnCtxt, // Ensure that if ~T is cast to ~Trait, then T : Trait push_cast_obligation(fcx, cast_expr, object_trait, referent_ty); + check_object_safety(fcx.tcx(), object_trait, source_expr.span); } (&ty::ty_rptr(referent_region, ty::mt { ty: referent_ty, @@ -68,6 +68,8 @@ pub fn check_object_cast(fcx: &FnCtxt, infer::RelateObjectBound(source_expr.span), target_region, referent_region); + + check_object_safety(fcx.tcx(), object_trait, source_expr.span); } } @@ -128,6 +130,103 @@ pub fn check_object_cast(fcx: &FnCtxt, } } +// 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) => { + errors.push(check_object_safety_of_method(tcx, &**m)) + } + ty::TypeTraitItem(_) => {} + } + } + + 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 { + /*! + * 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.name.repr(tcx); + + match method.explicit_self { + ty::ByValueExplicitSelfCategory => { // reason (a) above + msgs.push(format!("cannot call a method (`{}`) with a by-value \ + receiver through a trait object", method_name)) + } + + ty::StaticExplicitSelfCategory | + ty::ByReferenceExplicitSelfCategory(..) | + ty::ByBoxExplicitSelfCategory => {} + } + + // reason (a) above + let check_for_self_ty = |ty| { + if ty::type_has_self(ty) { + Some(format!( + "cannot call a method (`{}`) whose type contains \ + a self-type (`{}`) through a trait object", + method_name, ty_to_string(tcx, ty))) + } else { + None + } + }; + let ref sig = method.fty.sig; + for &input_ty in sig.inputs[1..].iter() { + match check_for_self_ty(input_ty) { + Some(msg) => msgs.push(msg), + _ => {} + } + } + if let ty::FnConverging(result_type) = sig.output { + match check_for_self_ty(result_type) { + Some(msg) => msgs.push(msg), + _ => {} + } + } + + if method.generics.has_type_params(FnSpace) { + // reason (b) above + msgs.push(format!("cannot call a generic method (`{}`) through a trait object", + method_name)); + } + + msgs + } +} + pub fn register_object_cast_obligations(fcx: &FnCtxt, span: Span, object_trait: &ty::TyTrait, diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs index a595921fcf72d..078a9a014c9c8 100644 --- a/src/libstd/io/extensions.rs +++ b/src/libstd/io/extensions.rs @@ -172,7 +172,7 @@ pub fn u64_from_be_bytes(data: &[u8], start: uint, size: uint) -> u64 { mod test { use prelude::*; use io; - use io::{MemReader, MemWriter}; + use io::{MemReader, MemWriter, BytesReader}; struct InitialZeroByteReader { count: int, diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 7826a6dd9c68e..d22650107a334 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,16 +921,41 @@ pub trait Reader { fn read_i8(&mut self) -> IoResult { 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 /// retaining ownership of the original value. - fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self> { + fn by_ref<'a>(&'a mut self) -> RefReader<'a, Self>; +} + +impl AsRefReader for T { + fn by_ref<'a>(&'a mut self) -> RefReader<'a, T> { RefReader { inner: self } } } +/// A reader which can be converted to bytes. +pub trait BytesReader { + /// 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>; +} + +impl BytesReader for T { + fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, T> { + extensions::Bytes::new(self) + } +} + impl<'a> Reader for Box { fn read(&mut self, buf: &mut [u8]) -> IoResult { let reader: &mut Reader = &mut **self; @@ -986,6 +1000,7 @@ unsafe fn slice_vec_capacity<'a, T>(v: &'a mut Vec, start: uint, end: uint) - /// # fn process_input(r: R) {} /// # fn foo() { /// use std::io; +/// use std::io::AsRefReader; /// use std::io::util::LimitReader; /// /// let mut stream = io::stdin(); @@ -1268,13 +1283,20 @@ 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 /// retaining ownership of the original value. #[inline] - fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self> { + fn by_ref<'a>(&'a mut self) -> RefWriter<'a, Self>; +} + +impl AsRefWriter for T { + fn by_ref<'a>(&'a mut self) -> RefWriter<'a, T> { RefWriter { inner: self } } } @@ -1309,7 +1331,7 @@ impl<'a> Writer for &'a mut Writer+'a { /// # fn process_input(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/libstd/io/util.rs b/src/libstd/io/util.rs index 820ae931f3204..5694565b4ea6a 100644 --- a/src/libstd/io/util.rs +++ b/src/libstd/io/util.rs @@ -265,7 +265,7 @@ impl> Reader for IterReader { #[cfg(test)] mod test { - use io::{MemReader, MemWriter, BufReader}; + use io::{MemReader, MemWriter, BufReader, AsRefReader}; use io; use boxed::Box; use super::*; diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index fbf17b76d6201..2e93f6badf2c9 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -89,30 +89,25 @@ impl Writer for WriterWrapper { /// Return a Terminal wrapping stdout, or None if a terminal couldn't be /// opened. pub fn stdout() -> Option + Send>> { - let ti: Option> - = Terminal::new(WriterWrapper { - wrapped: box std::io::stdout() as Box, - }); - ti.map(|t| box t as Box + Send>) + TerminfoTerminal::new(WriterWrapper { + wrapped: box std::io::stdout() as Box, + }) } #[cfg(windows)] /// Return a Terminal wrapping stdout, or None if a terminal couldn't be /// opened. pub fn stdout() -> Option + Send>> { - let ti: Option> - = Terminal::new(WriterWrapper { - wrapped: box std::io::stdout() as Box, - }); + let ti = TerminfoTerminal::new(WriterWrapper { + wrapped: box std::io::stdout() as Box, + }); match ti { - Some(t) => Some(box t as Box + Send>), + Some(t) => Some(t), None => { - let wc: Option> - = Terminal::new(WriterWrapper { - wrapped: box std::io::stdout() as Box, - }); - wc.map(|w| box w as Box + Send>) + WinConsole::new(WriterWrapper { + wrapped: box std::io::stdout() as Box, + }) } } } @@ -121,30 +116,25 @@ pub fn stdout() -> Option + Send>> { /// Return a Terminal wrapping stderr, or None if a terminal couldn't be /// opened. pub fn stderr() -> Option + Send> + Send> { - let ti: Option> - = Terminal::new(WriterWrapper { - wrapped: box std::io::stderr() as Box, - }); - ti.map(|t| box t as Box + Send>) + TerminfoTerminal::new(WriterWrapper { + wrapped: box std::io::stderr() as Box, + }) } #[cfg(windows)] /// Return a Terminal wrapping stderr, or None if a terminal couldn't be /// opened. pub fn stderr() -> Option + Send> + Send> { - let ti: Option> - = Terminal::new(WriterWrapper { - wrapped: box std::io::stderr() as Box, - }); + let ti = TerminfoTerminal::new(WriterWrapper { + wrapped: box std::io::stderr() as Box, + }); match ti { - Some(t) => Some(box t as Box + Send>), + Some(t) => Some(t), None => { - let wc: Option> - = Terminal::new(WriterWrapper { - wrapped: box std::io::stderr() as Box, - }); - wc.map(|w| box w as Box + Send>) + WinConsole::new(WriterWrapper { + wrapped: box std::io::stderr() as Box, + }) } } } @@ -208,10 +198,6 @@ pub mod attr { /// A terminal with similar capabilities to an ANSI Terminal /// (foreground/background colors etc). pub trait Terminal: Writer { - /// Returns `None` whenever the terminal cannot be created for some - /// reason. - fn new(out: T) -> Option; - /// Sets the foreground color to the given color. /// /// If the color is a bright color, but the terminal only supports 8 colors, @@ -242,12 +228,15 @@ pub trait Terminal: 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: Terminal { + /// 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 36883c8fcf4f2..73edcf9489216 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 { ti: Box } -impl Terminal for TerminfoTerminal { - fn new(out: T) -> Option> { - 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 Terminal for TerminfoTerminal { fn fg(&mut self, color: color::Color) -> IoResult { let color = self.dim_if_necessary(color); if self.num_colors > color { @@ -195,14 +159,59 @@ impl Terminal for TerminfoTerminal { 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 TerminfoTerminal { +impl UnwrappableTerminal for TerminfoTerminal { + fn unwrap(self) -> T { self.out } +} + +impl TerminfoTerminal { + /// Returns `None` whenever the terminal cannot be created for some + /// reason. + pub fn new(out: T) -> Option+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+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+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/libterm/win.rs b/src/libterm/win.rs index d4f06403c1a6e..7ce6fb658b56d 100644 --- a/src/libterm/win.rs +++ b/src/libterm/win.rs @@ -18,7 +18,7 @@ use std::io::IoResult; use attr; use color; -use Terminal; +use {Terminal,UnwrappableTerminal}; /// A Terminal implementation which uses the Win32 Console API. pub struct WinConsole { @@ -91,7 +91,7 @@ fn bits_to_color(bits: u16) -> color::Color { } } -impl WinConsole { +impl WinConsole { fn apply(&mut self) { let _unused = self.buf.flush(); let mut accum: libc::WORD = 0; @@ -112,20 +112,10 @@ impl WinConsole { SetConsoleTextAttribute(out, accum); } } -} - -impl Writer for WinConsole { - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - self.buf.write(buf) - } - - fn flush(&mut self) -> IoResult<()> { - self.buf.flush() - } -} -impl Terminal for WinConsole { - fn new(out: T) -> Option> { + /// Returns `None` whenever the terminal cannot be created for some + /// reason. + pub fn new(out: T) -> Option+Send+'static>> { let fg; let bg; unsafe { @@ -138,11 +128,23 @@ impl Terminal for WinConsole { bg = color::BLACK; } } - Some(WinConsole { buf: out, - def_foreground: fg, def_background: bg, - foreground: fg, background: bg } ) + Some(box WinConsole { buf: out, + def_foreground: fg, def_background: bg, + foreground: fg, background: bg } as Box+Send>) } +} +impl Writer for WinConsole { + fn write(&mut self, buf: &[u8]) -> IoResult<()> { + self.buf.write(buf) + } + + fn flush(&mut self) -> IoResult<()> { + self.buf.flush() + } +} + +impl Terminal for WinConsole { fn fg(&mut self, color: color::Color) -> IoResult { self.foreground = color; self.apply(); @@ -190,9 +192,11 @@ impl Terminal for WinConsole { Ok(()) } - fn unwrap(self) -> T { self.buf } - fn get_ref<'a>(&'a self) -> &'a T { &self.buf } fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf } } + +impl UnwrappableTerminal for WinConsole { + fn unwrap(self) -> T { self.buf } +} diff --git a/src/test/compile-fail/region-object-lifetime-in-coercion.rs b/src/test/compile-fail/region-object-lifetime-in-coercion.rs index 6791b7c5870e0..dfeba04109281 100644 --- a/src/test/compile-fail/region-object-lifetime-in-coercion.rs +++ b/src/test/compile-fail/region-object-lifetime-in-coercion.rs @@ -11,24 +11,27 @@ // Test that attempts to implicitly coerce a value into an // object respect the lifetime bound on the object type. -fn a(v: &[u8]) -> Box { - let x: Box = box v; //~ ERROR does not outlive +trait Foo {} +impl<'a> Foo for &'a [u8] {} + +fn a(v: &[u8]) -> Box { + let x: Box = box v; //~ ERROR does not outlive x } -fn b(v: &[u8]) -> Box { +fn b(v: &[u8]) -> Box { box v //~ ERROR does not outlive } -fn c(v: &[u8]) -> Box { +fn c(v: &[u8]) -> Box { box v // OK thanks to lifetime elision } -fn d<'a,'b>(v: &'a [u8]) -> Box { +fn d<'a,'b>(v: &'a [u8]) -> Box { box v //~ ERROR does not outlive } -fn e<'a:'b,'b>(v: &'a [u8]) -> Box { +fn e<'a:'b,'b>(v: &'a [u8]) -> Box { box v // OK, thanks to 'a:'b } diff --git a/src/test/compile-fail/selftype-traittype.rs b/src/test/compile-fail/selftype-traittype.rs deleted file mode 100644 index 44ee5002dce3d..0000000000000 --- a/src/test/compile-fail/selftype-traittype.rs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright 2012 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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - - -trait add { - fn plus(&self, x: Self) -> Self; -} - -fn do_add(x: Box, y: Box) -> Box { - x.plus(y) //~ ERROR E0038 -} - -fn main() {} diff --git a/src/test/compile-fail/trait-objects.rs b/src/test/compile-fail/trait-objects.rs new file mode 100644 index 0000000000000..88b907a5cb965 --- /dev/null +++ b/src/test/compile-fail/trait-objects.rs @@ -0,0 +1,43 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +trait Foo { + fn foo(self); +} + +trait Bar { + fn bar(&self, x: &Self); +} + +trait Baz { + fn baz(&self, x: &T); +} + +impl Foo for int { + fn foo(self) {} +} + +impl Bar for int { + fn bar(&self, _x: &int) {} +} + +impl Baz for int { + fn baz(&self, _x: &T) {} +} + +fn main() { + let _: &Foo = &42i; //~ ERROR cannot convert to a trait object + let _: &Bar = &42i; //~ ERROR cannot convert to a trait object + let _: &Baz = &42i; //~ ERROR cannot convert to a trait object + + let _ = &42i as &Foo; //~ ERROR cannot convert to a trait object + let _ = &42i as &Bar; //~ ERROR cannot convert to a trait object + let _ = &42i as &Baz; //~ ERROR cannot convert to a trait object +} diff --git a/src/test/compile-fail/trait-test-2.rs b/src/test/compile-fail/trait-test-2.rs index 3dce0178597cf..a24f7710d7b61 100644 --- a/src/test/compile-fail/trait-test-2.rs +++ b/src/test/compile-fail/trait-test-2.rs @@ -16,5 +16,5 @@ impl bar for uint { fn dup(&self) -> uint { *self } fn blah(&self) {} } fn main() { 10i.dup::(); //~ ERROR does not take type parameters 10i.blah::(); //~ ERROR incorrect number of type parameters - (box 10i as Box).dup(); //~ ERROR contains a self-type + (box 10i as Box).dup(); //~ ERROR cannot convert to a trait object } 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 6b000866d3ab9..0000000000000 --- 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 or the MIT license -// , 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; - st.foo(5); -} - -fn main() { - f(); -} - - diff --git a/src/test/run-pass/by-value-self-objects.rs b/src/test/run-pass/by-value-self-objects.rs deleted file mode 100644 index 3a588367a9709..0000000000000 --- a/src/test/run-pass/by-value-self-objects.rs +++ /dev/null @@ -1,77 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -static mut destructor_count: uint = 0; - -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) { - assert!(self.x == 2); - assert!(self.y == 3); - assert!(self.z == 4); - assert!(self.s.as_slice() == "hello"); - assert!(x == 5); - } -} - -impl Drop for S { - fn drop(&mut self) { - println!("bye 1!"); - unsafe { - destructor_count += 1; - } - } -} - -impl Foo for int { - fn foo(self, x: int) { - println!("{}", x * x); - } -} - -fn f() { - let s = S { - x: 2, - y: 3, - z: 4, - s: "hello".to_string(), - }; - let st = box s as Box; - st.foo(5); - println!("bye 2!"); -} - -fn g() { - let s = 2i; - let st = box s as Box; - st.foo(3); - println!("bye 3!"); -} - -fn main() { - f(); - - unsafe { - assert!(destructor_count == 1); - } - - g(); -} - diff --git a/src/test/run-pass/issue-11267.rs b/src/test/run-pass/issue-11267.rs index 53659a72132ef..f08805fe49c2c 100644 --- a/src/test/run-pass/issue-11267.rs +++ b/src/test/run-pass/issue-11267.rs @@ -12,11 +12,14 @@ struct Empty; -impl Iterator for Empty { +trait T { + fn next(&mut self) -> Option; +} +impl T for Empty { fn next(&mut self) -> Option { None } } -fn do_something_with(a : &mut Iterator) { +fn do_something_with(a : &mut T) { println!("{}", a.next()) } diff --git a/src/test/run-pass/issue-15763.rs b/src/test/run-pass/issue-15763.rs index 6e3599bda149a..0c09e456930c2 100644 --- a/src/test/run-pass/issue-15763.rs +++ b/src/test/run-pass/issue-15763.rs @@ -60,16 +60,16 @@ fn dd() -> Result { } trait A { - fn aaa(self) -> int { + fn aaa(&self) -> int { 3 } - fn bbb(self) -> int { + fn bbb(&self) -> int { return 3; } - fn ccc(self) -> Result { + fn ccc(&self) -> Result { Ok(3) } - fn ddd(self) -> Result { + fn ddd(&self) -> Result { return Ok(3); } } diff --git a/src/test/run-pass/trait-cast-generic.rs b/src/test/run-pass/trait-cast-generic.rs deleted file mode 100644 index 8f0ec5ec7a19e..0000000000000 --- a/src/test/run-pass/trait-cast-generic.rs +++ /dev/null @@ -1,30 +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 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -// Testing casting of a generic Struct to a Trait with a generic method. -// This is test for issue 10955. -#![allow(unused_variable)] - -trait Foo { - fn f(a: A) -> A { - a - } -} - -struct Bar { - x: T, -} - -impl Foo for Bar { } - -pub fn main() { - let a = Bar { x: 1u }; - let b = &a as &Foo; -} diff --git a/src/test/run-pass/trait-default-method-xc.rs b/src/test/run-pass/trait-default-method-xc.rs index f88522facdfdf..c4880e97c458b 100644 --- a/src/test/run-pass/trait-default-method-xc.rs +++ b/src/test/run-pass/trait-default-method-xc.rs @@ -72,9 +72,6 @@ pub fn main() { assert_eq!(g(0i, 3.14f64, 1i), (3.14f64, 1i)); assert_eq!(g(false, 3.14f64, 1i), (3.14, 1)); - let obj = box 0i as Box; - assert_eq!(obj.h(), 11); - // Trying out a real one assert!(12i.test_neq(&10i));