From 8d8d8d4e5292c2fa4a622d981a5f85fd3d8f34d0 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 1 Oct 2014 16:43:39 +1300 Subject: [PATCH 1/7] Enforce object safety closes #17670 [breaking-change] Traits must be object-safe if they are to be used in trait objects. This might require splitting a trait into object-safe and non-object-safe parts. Some standard library traits in std::io have been split - Reader has new traits BytesReader (for the bytes method) and AsRefReader (for by_ref), Writer has new trait AsRefWriter (for by_ref). All these new traits have blanket impls, so any type which implements Reader or Writer (respectively) will have an implmentation of the new traits. To fix your code, you just need to `use` the new trait. --- src/librustc/middle/typeck/check/method.rs | 75 ---------------------- src/librustc/middle/typeck/check/mod.rs | 1 + src/librustc/middle/typeck/check/vtable.rs | 69 +++++++++++++++++++- 3 files changed, 69 insertions(+), 76 deletions(-) diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 7527160c825ae..31364748423ca 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -1336,16 +1336,6 @@ 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(); - } - self.enforce_drop_trait_limitations(candidate); // Determine the values for the generic parameters of the method. @@ -1554,71 +1544,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..7a5ce9a528cda 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) => { + vtable2::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..639ba9bdf4948 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}; @@ -46,6 +46,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 +69,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 +131,70 @@ pub fn check_object_cast(fcx: &FnCtxt, } } +// TODO comment +pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Span) { + let trait_items = ty::trait_items(tcx, object_trait.def_id); + for item in trait_items.iter() { + match *item { + ty::MethodTraitItem(ref m) => check_object_safety_of_method(tcx, &**m, span), + ty::TypeTraitItem(_) => {} + } + } + + // TODO error messages + fn check_object_safety_of_method(tcx: &ty::ctxt, method: &ty::Method, span: Span) { + /*! + * 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 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"); + } + + ty::StaticExplicitSelfCategory | + ty::ByReferenceExplicitSelfCategory(..) | + ty::ByBoxExplicitSelfCategory => {} + } + + // 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 + } else { + false + } + }; + 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; + } + } + 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"); + } + } +} + pub fn register_object_cast_obligations(fcx: &FnCtxt, span: Span, object_trait: &ty::TyTrait, From 1d500cfd74c02b6f9f84a4e7387d8126c79f3f76 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 1 Oct 2014 19:01:08 +1300 Subject: [PATCH 2/7] changes to libs --- src/librustc/diagnostics.rs | 1 - src/librustc/middle/typeck/check/vtable.rs | 76 +++++++++++----- src/libstd/io/buffered.rs | 4 +- src/libstd/io/mem.rs | 8 +- src/libstd/io/mod.rs | 34 ++++--- src/libterm/lib.rs | 29 +++--- src/libterm/terminfo/mod.rs | 91 ++++++++++--------- .../run-fail/by-value-self-objects-fail.rs | 51 ----------- 8 files changed, 145 insertions(+), 149 deletions(-) delete mode 100644 src/test/run-fail/by-value-self-objects-fail.rs 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/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 639ba9bdf4948..4829083f021bf 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 { /*! * 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 9cd8dbcc50949..cbb982e731ab4 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 Reader for BufferedReader { } } +impl AsRefReader for BufferedReader {} + /// 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 2f6dd7e47955f..c743bee1fc977 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 { 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 { Ok(self.pos as u64) } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 7826a6dd9c68e..6aba5f67643a6 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 { 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 { fn read(&mut self, buf: &mut [u8]) -> IoResult { let reader: &mut Reader = &mut **self; @@ -986,6 +992,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,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: 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 fbf17b76d6201..37c7162333bfd 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 + 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)] @@ -121,11 +119,9 @@ 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)] @@ -208,10 +204,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 +234,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/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(); -} - - From c48a1ab158110a35ee22a9fe06dc08d31aa6c56a Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 1 Oct 2014 19:31:21 +1300 Subject: [PATCH 3/7] changes to tests --- src/librustc/middle/typeck/check/vtable.rs | 4 +- src/libstd/io/extensions.rs | 5 +- src/libstd/io/util.rs | 2 +- src/test/compile-fail/selftype-traittype.rs | 20 ----- src/test/compile-fail/trait-objects.rs | 43 +++++++++++ src/test/compile-fail/trait-test-2.rs | 2 +- src/test/run-pass/by-value-self-objects.rs | 77 -------------------- src/test/run-pass/issue-11267.rs | 7 +- src/test/run-pass/issue-15763.rs | 8 +- src/test/run-pass/trait-cast-generic.rs | 30 -------- src/test/run-pass/trait-default-method-xc.rs | 3 - 11 files changed, 60 insertions(+), 141 deletions(-) delete mode 100644 src/test/compile-fail/selftype-traittype.rs create mode 100644 src/test/compile-fail/trait-objects.rs delete mode 100644 src/test/run-pass/by-value-self-objects.rs delete mode 100644 src/test/run-pass/trait-cast-generic.rs diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 4829083f021bf..115b224241b20 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -196,8 +196,8 @@ pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Spa 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", + "cannot call a method (`{}`) whose type contains \ + a self-type (`{}`) through a trait object", method_name, ty_to_string(tcx, ty))) } else { None diff --git a/src/libstd/io/extensions.rs b/src/libstd/io/extensions.rs index a595921fcf72d..59da797b12633 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, @@ -189,6 +189,7 @@ mod test { } } } + impl BytesReader for InitialZeroByteReader {} struct EofReader; @@ -197,6 +198,7 @@ mod test { Err(io::standard_error(io::EndOfFile)) } } + impl BytesReader for EofReader {} struct ErroringReader; @@ -205,6 +207,7 @@ mod test { Err(io::standard_error(io::InvalidInput)) } } + impl BytesReader for ErroringReader {} struct PartialReader { count: int, 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/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-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)); From dd2a1e34691d3ed6f8b1b05e3ef39c17510b46b4 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Thu, 16 Oct 2014 13:49:00 +1300 Subject: [PATCH 4/7] Change extensions traits to blanket impls --- src/librustc/middle/typeck/check/method.rs | 17 +++++++++-------- src/libstd/io/buffered.rs | 4 +--- src/libstd/io/extensions.rs | 3 --- src/libstd/io/mem.rs | 8 +------- src/libstd/io/mod.rs | 20 ++++++++++++++++---- 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 31364748423ca..064ceb1e1c18f 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -619,14 +619,15 @@ 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`. - let rcvr_substs = substs.with_self_ty(self_ty); + // It is illegal to create a trait object with methods which includes + // the Self type. An error will be reported when we coerce to a trait + // object if the method refers to the `Self` type. Substituting ty_err + // here allows compiler to soldier on. + // + // `confirm_candidate()` also relies upon this substitution + // for Self. (fix) + let rcvr_substs = substs.with_self_ty(ty::mk_err()); + let trait_ref = Rc::new(TraitRef { def_id: did, substs: rcvr_substs.clone() diff --git a/src/libstd/io/buffered.rs b/src/libstd/io/buffered.rs index cbb982e731ab4..9cd8dbcc50949 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, AsRefReader}; +use io::{Reader, Writer, Stream, Buffer, DEFAULT_BUF_SIZE, IoResult}; use iter::ExactSize; use ops::Drop; use option::{Some, None, Option}; @@ -118,8 +118,6 @@ impl Reader for BufferedReader { } } -impl AsRefReader for BufferedReader {} - /// 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/extensions.rs b/src/libstd/io/extensions.rs index 59da797b12633..078a9a014c9c8 100644 --- a/src/libstd/io/extensions.rs +++ b/src/libstd/io/extensions.rs @@ -189,7 +189,6 @@ mod test { } } } - impl BytesReader for InitialZeroByteReader {} struct EofReader; @@ -198,7 +197,6 @@ mod test { Err(io::standard_error(io::EndOfFile)) } } - impl BytesReader for EofReader {} struct ErroringReader; @@ -207,7 +205,6 @@ mod test { Err(io::standard_error(io::InvalidInput)) } } - impl BytesReader for ErroringReader {} struct PartialReader { count: int, diff --git a/src/libstd/io/mem.rs b/src/libstd/io/mem.rs index c743bee1fc977..2f6dd7e47955f 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, AsRefReader, AsRefWriter}; +use io::{Reader, Writer, Seek, Buffer, IoError, SeekStyle, IoResult}; use slice; use slice::AsSlice; use vec::Vec; @@ -97,8 +97,6 @@ impl Writer for MemWriter { } } -impl AsRefWriter for MemWriter {} - /// Reads from an owned byte vector /// /// # Example @@ -165,8 +163,6 @@ impl Reader for MemReader { } } -impl AsRefReader for MemReader {} - impl Seek for MemReader { #[inline] fn tell(&self) -> IoResult { Ok(self.pos as u64) } @@ -313,8 +309,6 @@ impl<'a> Reader for BufReader<'a> { } } -impl<'a> AsRefReader for BufReader<'a> {} - impl<'a> Seek for BufReader<'a> { #[inline] fn tell(&self) -> IoResult { Ok(self.pos as u64) } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 6aba5f67643a6..d22650107a334 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -929,13 +929,17 @@ pub trait AsRefReader { /// /// 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: Reader { +pub trait BytesReader { /// Create an iterator that reads a single byte on /// each iteration, until EOF. /// @@ -943,7 +947,11 @@ pub trait BytesReader: Reader { /// /// 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> { + 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) } } @@ -1284,7 +1292,11 @@ pub trait AsRefWriter { /// 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 } } } From 5dd1bc3d14ed51485197ba5d84d2f7a9d10bac1a Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Tue, 21 Oct 2014 10:59:00 +1300 Subject: [PATCH 5/7] Changes for Windows terminal --- src/libterm/lib.rs | 34 ++++++++++++++-------------------- src/libterm/win.rs | 46 +++++++++++++++++++++++++--------------------- 2 files changed, 39 insertions(+), 41 deletions(-) diff --git a/src/libterm/lib.rs b/src/libterm/lib.rs index 37c7162333bfd..2e93f6badf2c9 100644 --- a/src/libterm/lib.rs +++ b/src/libterm/lib.rs @@ -98,19 +98,16 @@ pub fn stdout() -> Option + Send>> { /// 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, + }) } } } @@ -128,19 +125,16 @@ pub fn stderr() -> Option + Send> + 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, - }); + 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, + }) } } } diff --git a/src/libterm/win.rs b/src/libterm/win.rs index d4f06403c1a6e..60b811db8fc5a 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 { @@ -125,24 +125,6 @@ impl Writer for WinConsole { } impl Terminal for WinConsole { - fn new(out: T) -> Option> { - let fg; - let bg; - unsafe { - let mut buffer_info = ::std::mem::uninitialized(); - if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 { - fg = bits_to_color(buffer_info.wAttributes); - bg = bits_to_color(buffer_info.wAttributes >> 4); - } else { - fg = color::WHITE; - bg = color::BLACK; - } - } - Some(WinConsole { buf: out, - def_foreground: fg, def_background: bg, - foreground: fg, background: bg } ) - } - fn fg(&mut self, color: color::Color) -> IoResult { self.foreground = color; self.apply(); @@ -190,9 +172,31 @@ 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 WinConsole { + fn new(out: T) -> Option+Send+'static>> { + let fg; + let bg; + unsafe { + let mut buffer_info = ::std::mem::uninitialized(); + if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 { + fg = bits_to_color(buffer_info.wAttributes); + bg = bits_to_color(buffer_info.wAttributes >> 4); + } else { + fg = color::WHITE; + bg = color::BLACK; + } + } + Some(box WinConsole { buf: out, + def_foreground: fg, def_background: bg, + foreground: fg, background: bg } ) + } +} + +impl UnwrappableTerminal for WinConsole { + fn unwrap(self) -> T { self.buf } +} From 3adb7554d63a66cc00323898a9b260fc616e94e2 Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 22 Oct 2014 16:53:03 +1300 Subject: [PATCH 6/7] Rebasing fixes --- src/librustc/middle/typeck/check/method.rs | 14 ++++++-------- src/librustc/middle/typeck/check/mod.rs | 2 +- src/librustc/middle/typeck/check/vtable.rs | 10 ++++++++-- .../region-object-lifetime-in-coercion.rs | 15 +++++++++------ 4 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/librustc/middle/typeck/check/method.rs b/src/librustc/middle/typeck/check/method.rs index 064ceb1e1c18f..cd3cc43b8539d 100644 --- a/src/librustc/middle/typeck/check/method.rs +++ b/src/librustc/middle/typeck/check/method.rs @@ -619,14 +619,11 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { let tcx = self.tcx(); - // It is illegal to create a trait object with methods which includes - // the Self type. An error will be reported when we coerce to a trait - // object if the method refers to the `Self` type. Substituting ty_err - // here allows compiler to soldier on. - // - // `confirm_candidate()` also relies upon this substitution - // for Self. (fix) - let rcvr_substs = substs.with_self_ty(ty::mk_err()); + // 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, @@ -1337,6 +1334,7 @@ impl<'a, 'tcx> LookupContext<'a, 'tcx> { self.ty_to_string(rcvr_ty), candidate.repr(self.tcx())); + let rcvr_substs = candidate.rcvr_substs.clone(); self.enforce_drop_trait_limitations(candidate); // Determine the values for the generic parameters of the method. diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index 7a5ce9a528cda..94c4d7c25e0a6 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1687,7 +1687,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.register_unsize_obligations(span, &**u) } ty::UnsizeVtable(ref ty_trait, self_ty) => { - vtable2::check_object_safety(self.tcx(), ty_trait, span); + 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 115b224241b20..b7195734e8b39 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -179,7 +179,7 @@ pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Spa */ let mut msgs = Vec::new(); - let method_name = method.ident.repr(tcx); + let method_name = method.name.repr(tcx); match method.explicit_self { ty::ByValueExplicitSelfCategory => { // reason (a) above @@ -204,12 +204,18 @@ pub fn check_object_safety(tcx: &ty::ctxt, object_trait: &ty::TyTrait, span: Spa } }; let ref sig = method.fty.sig; - for &input_ty in sig.inputs.tail().iter().chain([sig.output].iter()) { + 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 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 } From 88a250d194d7a7995c0740d706d9eb19007a85ee Mon Sep 17 00:00:00 2001 From: Nick Cameron Date: Wed, 22 Oct 2014 17:42:13 +1300 Subject: [PATCH 7/7] Try and fix Windows terminal --- src/libterm/win.rs | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/libterm/win.rs b/src/libterm/win.rs index 60b811db8fc5a..7ce6fb658b56d 100644 --- a/src/libterm/win.rs +++ b/src/libterm/win.rs @@ -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,6 +112,26 @@ impl WinConsole { SetConsoleTextAttribute(out, accum); } } + + /// Returns `None` whenever the terminal cannot be created for some + /// reason. + pub fn new(out: T) -> Option+Send+'static>> { + let fg; + let bg; + unsafe { + let mut buffer_info = ::std::mem::uninitialized(); + if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 { + fg = bits_to_color(buffer_info.wAttributes); + bg = bits_to_color(buffer_info.wAttributes >> 4); + } else { + fg = color::WHITE; + bg = color::BLACK; + } + } + Some(box WinConsole { buf: out, + def_foreground: fg, def_background: bg, + foreground: fg, background: bg } as Box+Send>) + } } impl Writer for WinConsole { @@ -124,7 +144,7 @@ impl Writer for WinConsole { } } -impl Terminal for WinConsole { +impl Terminal for WinConsole { fn fg(&mut self, color: color::Color) -> IoResult { self.foreground = color; self.apply(); @@ -177,26 +197,6 @@ impl Terminal for WinConsole { fn get_mut<'a>(&'a mut self) -> &'a mut T { &mut self.buf } } -impl WinConsole { - fn new(out: T) -> Option+Send+'static>> { - let fg; - let bg; - unsafe { - let mut buffer_info = ::std::mem::uninitialized(); - if GetConsoleScreenBufferInfo(GetStdHandle(-11), &mut buffer_info) != 0 { - fg = bits_to_color(buffer_info.wAttributes); - bg = bits_to_color(buffer_info.wAttributes >> 4); - } else { - fg = color::WHITE; - bg = color::BLACK; - } - } - Some(box WinConsole { buf: out, - def_foreground: fg, def_background: bg, - foreground: fg, background: bg } ) - } -} - -impl UnwrappableTerminal for WinConsole { +impl UnwrappableTerminal for WinConsole { fn unwrap(self) -> T { self.buf } }