auto merge of #17704 : nick29581/rust/object-safety, r=nikomatsakis
r? @nikomatsakis
This commit is contained in:
commit
2d27bfaeb6
@ -53,7 +53,6 @@ register_diagnostics!(
|
||||
E0035,
|
||||
E0036,
|
||||
E0038,
|
||||
E0039,
|
||||
E0040,
|
||||
E0044,
|
||||
E0045,
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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<String> {
|
||||
/*!
|
||||
* There are some limitations to calling functions through an
|
||||
* object, because (a) the self type is not known
|
||||
* (that's the whole point of a trait instance, after all, to
|
||||
* obscure the self type) and (b) the call must go through a
|
||||
* vtable and hence cannot be monomorphized.
|
||||
*/
|
||||
let mut msgs = Vec::new();
|
||||
|
||||
let method_name = method.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,
|
||||
|
@ -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,
|
||||
|
@ -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<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
|
||||
/// 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<T: Reader> 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<T: Reader> BytesReader for T {
|
||||
fn bytes<'r>(&'r mut self) -> extensions::Bytes<'r, T> {
|
||||
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 +1000,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,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<T: Writer> 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: 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();
|
||||
///
|
||||
|
@ -265,7 +265,7 @@ impl<T: Iterator<u8>> Reader for IterReader<T> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use io::{MemReader, MemWriter, BufReader};
|
||||
use io::{MemReader, MemWriter, BufReader, AsRefReader};
|
||||
use io;
|
||||
use boxed::Box;
|
||||
use super::*;
|
||||
|
@ -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<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)]
|
||||
/// 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>,
|
||||
});
|
||||
let ti = TerminfoTerminal::new(WriterWrapper {
|
||||
wrapped: box std::io::stdout() as Box<Writer + Send>,
|
||||
});
|
||||
|
||||
match ti {
|
||||
Some(t) => Some(box t as Box<Terminal<WriterWrapper> + Send>),
|
||||
Some(t) => Some(t),
|
||||
None => {
|
||||
let wc: Option<WinConsole<WriterWrapper>>
|
||||
= Terminal::new(WriterWrapper {
|
||||
wrapped: box std::io::stdout() as Box<Writer + Send>,
|
||||
});
|
||||
wc.map(|w| box w as Box<Terminal<WriterWrapper> + Send>)
|
||||
WinConsole::new(WriterWrapper {
|
||||
wrapped: box std::io::stdout() as Box<Writer + Send>,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -121,30 +116,25 @@ 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)]
|
||||
/// 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>,
|
||||
});
|
||||
let ti = TerminfoTerminal::new(WriterWrapper {
|
||||
wrapped: box std::io::stderr() as Box<Writer + Send>,
|
||||
});
|
||||
|
||||
match ti {
|
||||
Some(t) => Some(box t as Box<Terminal<WriterWrapper> + Send>),
|
||||
Some(t) => Some(t),
|
||||
None => {
|
||||
let wc: Option<WinConsole<WriterWrapper>>
|
||||
= Terminal::new(WriterWrapper {
|
||||
wrapped: box std::io::stderr() as Box<Writer + Send>,
|
||||
});
|
||||
wc.map(|w| box w as Box<Terminal<WriterWrapper> + Send>)
|
||||
WinConsole::new(WriterWrapper {
|
||||
wrapped: box std::io::stderr() as Box<Writer + Send>,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -208,10 +198,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 +228,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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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<T> {
|
||||
@ -91,7 +91,7 @@ fn bits_to_color(bits: u16) -> color::Color {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Writer> WinConsole<T> {
|
||||
impl<T: Writer+Send> WinConsole<T> {
|
||||
fn apply(&mut self) {
|
||||
let _unused = self.buf.flush();
|
||||
let mut accum: libc::WORD = 0;
|
||||
@ -112,20 +112,10 @@ impl<T: Writer> WinConsole<T> {
|
||||
SetConsoleTextAttribute(out, accum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Writer> Writer for WinConsole<T> {
|
||||
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
|
||||
self.buf.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> IoResult<()> {
|
||||
self.buf.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Writer> Terminal<T> for WinConsole<T> {
|
||||
fn new(out: T) -> Option<WinConsole<T>> {
|
||||
/// Returns `None` whenever the terminal cannot be created for some
|
||||
/// reason.
|
||||
pub fn new(out: T) -> Option<Box<Terminal<T>+Send+'static>> {
|
||||
let fg;
|
||||
let bg;
|
||||
unsafe {
|
||||
@ -138,11 +128,23 @@ impl<T: Writer> Terminal<T> for WinConsole<T> {
|
||||
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<Terminal<T>+Send>)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Writer> Writer for WinConsole<T> {
|
||||
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
|
||||
self.buf.write(buf)
|
||||
}
|
||||
|
||||
fn flush(&mut self) -> IoResult<()> {
|
||||
self.buf.flush()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Writer+Send> Terminal<T> for WinConsole<T> {
|
||||
fn fg(&mut self, color: color::Color) -> IoResult<bool> {
|
||||
self.foreground = color;
|
||||
self.apply();
|
||||
@ -190,9 +192,11 @@ impl<T: Writer> Terminal<T> for WinConsole<T> {
|
||||
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<T: Writer+Send> UnwrappableTerminal<T> for WinConsole<T> {
|
||||
fn unwrap(self) -> T { self.buf }
|
||||
}
|
||||
|
@ -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<Clone + 'static> {
|
||||
let x: Box<Clone + 'static> = box v; //~ ERROR does not outlive
|
||||
trait Foo {}
|
||||
impl<'a> Foo for &'a [u8] {}
|
||||
|
||||
fn a(v: &[u8]) -> Box<Foo + 'static> {
|
||||
let x: Box<Foo + 'static> = box v; //~ ERROR does not outlive
|
||||
x
|
||||
}
|
||||
|
||||
fn b(v: &[u8]) -> Box<Clone + 'static> {
|
||||
fn b(v: &[u8]) -> Box<Foo + 'static> {
|
||||
box v //~ ERROR does not outlive
|
||||
}
|
||||
|
||||
fn c(v: &[u8]) -> Box<Clone> {
|
||||
fn c(v: &[u8]) -> Box<Foo> {
|
||||
box v // OK thanks to lifetime elision
|
||||
}
|
||||
|
||||
fn d<'a,'b>(v: &'a [u8]) -> Box<Clone+'b> {
|
||||
fn d<'a,'b>(v: &'a [u8]) -> Box<Foo+'b> {
|
||||
box v //~ ERROR does not outlive
|
||||
}
|
||||
|
||||
fn e<'a:'b,'b>(v: &'a [u8]) -> Box<Clone+'b> {
|
||||
fn e<'a:'b,'b>(v: &'a [u8]) -> Box<Foo+'b> {
|
||||
box v // OK, thanks to 'a:'b
|
||||
}
|
||||
|
||||
|
@ -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 <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.
|
||||
|
||||
|
||||
trait add {
|
||||
fn plus(&self, x: Self) -> Self;
|
||||
}
|
||||
|
||||
fn do_add(x: Box<add+'static>, y: Box<add+'static>) -> Box<add+'static> {
|
||||
x.plus(y) //~ ERROR E0038
|
||||
}
|
||||
|
||||
fn main() {}
|
43
src/test/compile-fail/trait-objects.rs
Normal file
43
src/test/compile-fail/trait-objects.rs
Normal file
@ -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 <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.
|
||||
|
||||
trait Foo {
|
||||
fn foo(self);
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
fn bar(&self, x: &Self);
|
||||
}
|
||||
|
||||
trait Baz {
|
||||
fn baz<T>(&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<T>(&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
|
||||
}
|
@ -16,5 +16,5 @@ impl bar for uint { fn dup(&self) -> uint { *self } fn blah<X>(&self) {} }
|
||||
fn main() {
|
||||
10i.dup::<int>(); //~ ERROR does not take type parameters
|
||||
10i.blah::<int, int>(); //~ ERROR incorrect number of type parameters
|
||||
(box 10i as Box<bar>).dup(); //~ ERROR contains a self-type
|
||||
(box 10i as Box<bar>).dup(); //~ ERROR cannot convert to a trait object
|
||||
}
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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 <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.
|
||||
|
||||
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<Foo>;
|
||||
st.foo(5);
|
||||
println!("bye 2!");
|
||||
}
|
||||
|
||||
fn g() {
|
||||
let s = 2i;
|
||||
let st = box s as Box<Foo>;
|
||||
st.foo(3);
|
||||
println!("bye 3!");
|
||||
}
|
||||
|
||||
fn main() {
|
||||
f();
|
||||
|
||||
unsafe {
|
||||
assert!(destructor_count == 1);
|
||||
}
|
||||
|
||||
g();
|
||||
}
|
||||
|
@ -12,11 +12,14 @@
|
||||
|
||||
struct Empty;
|
||||
|
||||
impl Iterator<int> for Empty {
|
||||
trait T<U> {
|
||||
fn next(&mut self) -> Option<U>;
|
||||
}
|
||||
impl T<int> for Empty {
|
||||
fn next(&mut self) -> Option<int> { None }
|
||||
}
|
||||
|
||||
fn do_something_with(a : &mut Iterator<int>) {
|
||||
fn do_something_with(a : &mut T<int>) {
|
||||
println!("{}", a.next())
|
||||
}
|
||||
|
||||
|
@ -60,16 +60,16 @@ fn dd() -> Result<int, int> {
|
||||
}
|
||||
|
||||
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<int, int> {
|
||||
fn ccc(&self) -> Result<int, int> {
|
||||
Ok(3)
|
||||
}
|
||||
fn ddd(self) -> Result<int, int> {
|
||||
fn ddd(&self) -> Result<int, int> {
|
||||
return Ok(3);
|
||||
}
|
||||
}
|
||||
|
@ -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 <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.
|
||||
|
||||
// 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 {
|
||||
a
|
||||
}
|
||||
}
|
||||
|
||||
struct Bar<T> {
|
||||
x: T,
|
||||
}
|
||||
|
||||
impl<T> Foo for Bar<T> { }
|
||||
|
||||
pub fn main() {
|
||||
let a = Bar { x: 1u };
|
||||
let b = &a as &Foo;
|
||||
}
|
@ -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<A>;
|
||||
assert_eq!(obj.h(), 11);
|
||||
|
||||
|
||||
// Trying out a real one
|
||||
assert!(12i.test_neq(&10i));
|
||||
|
Loading…
Reference in New Issue
Block a user