librustc: Match trait self types exactly.
This can break code that looked like: impl Foo for Box<Any> { fn f(&self) { ... } } let x: Box<Any + Send> = ...; x.f(); Change such code to: impl Foo for Box<Any> { fn f(&self) { ... } } let x: Box<Any> = ...; x.f(); That is, upcast before calling methods. This is a conservative solution to #5781. A more proper treatment (see the xfail'd `trait-contravariant-self.rs`) would take variance into account. This change fixes the soundness hole. Some library changes had to be made to make this work. In particular, `Box<Any>` is no longer showable, and only `Box<Any+Send>` is showable. Eventually, this restriction can be lifted; for now, it does not prove too onerous, because `Any` is only used for propagating the result of task failure. This patch also adds a test for the variance inference work in #12828, which accidentally landed as part of DST. Closes #5781. [breaking-change]
This commit is contained in:
parent
afdfe40aa0
commit
05e3248a79
20 changed files with 214 additions and 84 deletions
|
@ -16,6 +16,7 @@ use core::cmp::{PartialEq, PartialOrd, Eq, Ord, Ordering};
|
||||||
use core::default::Default;
|
use core::default::Default;
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use core::intrinsics;
|
use core::intrinsics;
|
||||||
|
use core::kinds::Send;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::raw::TraitObject;
|
use core::raw::TraitObject;
|
||||||
use core::result::{Ok, Err, Result};
|
use core::result::{Ok, Err, Result};
|
||||||
|
@ -106,6 +107,34 @@ impl AnyOwnExt for Box<Any> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extension methods for an owning `Any+Send` trait object
|
||||||
|
pub trait AnySendOwnExt {
|
||||||
|
/// Returns the boxed value if it is of type `T`, or
|
||||||
|
/// `Err(Self)` if it isn't.
|
||||||
|
fn move_send<T: 'static>(self) -> Result<Box<T>, Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AnySendOwnExt for Box<Any+Send> {
|
||||||
|
#[inline]
|
||||||
|
fn move_send<T: 'static>(self) -> Result<Box<T>, Box<Any+Send>> {
|
||||||
|
if self.is::<T>() {
|
||||||
|
unsafe {
|
||||||
|
// Get the raw representation of the trait object
|
||||||
|
let to: TraitObject =
|
||||||
|
*mem::transmute::<&Box<Any+Send>, &TraitObject>(&self);
|
||||||
|
|
||||||
|
// Prevent destructor on self being run
|
||||||
|
intrinsics::forget(self);
|
||||||
|
|
||||||
|
// Extract the data pointer
|
||||||
|
Ok(mem::transmute(to.data))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T: fmt::Show> fmt::Show for Box<T> {
|
impl<T: fmt::Show> fmt::Show for Box<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
(**self).fmt(f)
|
(**self).fmt(f)
|
||||||
|
|
|
@ -135,7 +135,8 @@ pub trait Iterator<A> {
|
||||||
/// let a = [0i];
|
/// let a = [0i];
|
||||||
/// let b = [1i];
|
/// let b = [1i];
|
||||||
/// let mut it = a.iter().zip(b.iter());
|
/// let mut it = a.iter().zip(b.iter());
|
||||||
/// assert_eq!(it.next().unwrap(), (&0, &1));
|
/// let (x0, x1) = (0i, 1i);
|
||||||
|
/// assert_eq!(it.next().unwrap(), (&x0, &x1));
|
||||||
/// assert!(it.next().is_none());
|
/// assert!(it.next().is_none());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -202,8 +203,9 @@ pub trait Iterator<A> {
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let a = [100i, 200];
|
/// let a = [100i, 200];
|
||||||
/// let mut it = a.iter().enumerate();
|
/// let mut it = a.iter().enumerate();
|
||||||
/// assert_eq!(it.next().unwrap(), (0, &100));
|
/// let (x100, x200) = (100i, 200i);
|
||||||
/// assert_eq!(it.next().unwrap(), (1, &200));
|
/// assert_eq!(it.next().unwrap(), (0, &x100));
|
||||||
|
/// assert_eq!(it.next().unwrap(), (1, &x200));
|
||||||
/// assert!(it.next().is_none());
|
/// assert!(it.next().is_none());
|
||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -220,11 +222,11 @@ pub trait Iterator<A> {
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// let xs = [100i, 200, 300];
|
/// let xs = [100i, 200, 300];
|
||||||
/// let mut it = xs.iter().map(|x| *x).peekable();
|
/// let mut it = xs.iter().map(|x| *x).peekable();
|
||||||
/// assert_eq!(it.peek().unwrap(), &100);
|
/// assert_eq!(*it.peek().unwrap(), 100);
|
||||||
/// assert_eq!(it.next().unwrap(), 100);
|
/// assert_eq!(it.next().unwrap(), 100);
|
||||||
/// assert_eq!(it.next().unwrap(), 200);
|
/// assert_eq!(it.next().unwrap(), 200);
|
||||||
/// assert_eq!(it.peek().unwrap(), &300);
|
/// assert_eq!(*it.peek().unwrap(), 300);
|
||||||
/// assert_eq!(it.peek().unwrap(), &300);
|
/// assert_eq!(*it.peek().unwrap(), 300);
|
||||||
/// assert_eq!(it.next().unwrap(), 300);
|
/// assert_eq!(it.next().unwrap(), 300);
|
||||||
/// assert!(it.peek().is_none());
|
/// assert!(it.peek().is_none());
|
||||||
/// assert!(it.next().is_none());
|
/// assert!(it.next().is_none());
|
||||||
|
|
|
@ -352,17 +352,15 @@ fn search_for_vtable(vcx: &VtableContext,
|
||||||
// the next impl.
|
// the next impl.
|
||||||
//
|
//
|
||||||
// FIXME: document a bit more what this means
|
// FIXME: document a bit more what this means
|
||||||
//
|
|
||||||
// FIXME(#5781) this should be mk_eqty not mk_subty
|
|
||||||
let TypeAndSubsts {
|
let TypeAndSubsts {
|
||||||
substs: substs,
|
substs: substs,
|
||||||
ty: for_ty
|
ty: for_ty
|
||||||
} = impl_self_ty(vcx, span, impl_did);
|
} = impl_self_ty(vcx, span, impl_did);
|
||||||
match infer::mk_subty(vcx.infcx,
|
match infer::mk_eqty(vcx.infcx,
|
||||||
false,
|
false,
|
||||||
infer::RelateSelfType(span),
|
infer::RelateSelfType(span),
|
||||||
ty,
|
ty,
|
||||||
for_ty) {
|
for_ty) {
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
Ok(()) => ()
|
Ok(()) => ()
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,16 +84,13 @@ pub trait Combine {
|
||||||
fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t>;
|
fn tys(&self, a: ty::t, b: ty::t) -> cres<ty::t>;
|
||||||
|
|
||||||
fn tps(&self,
|
fn tps(&self,
|
||||||
space: subst::ParamSpace,
|
_: subst::ParamSpace,
|
||||||
as_: &[ty::t],
|
as_: &[ty::t],
|
||||||
bs: &[ty::t])
|
bs: &[ty::t])
|
||||||
-> cres<Vec<ty::t>>
|
-> cres<Vec<ty::t>> {
|
||||||
{
|
// FIXME -- In general, we treat variance a bit wrong
|
||||||
// FIXME(#5781) -- In general, we treat variance a bit wrong
|
// here. For historical reasons, we treat tps and Self
|
||||||
// here. For historical reasons, we treat Self as
|
// as invariant. This is overly conservative.
|
||||||
// contravariant and other tps as invariant. Both are wrong:
|
|
||||||
// Self may or may not be contravariant, and other tps do not
|
|
||||||
// need to be invariant.
|
|
||||||
|
|
||||||
if as_.len() != bs.len() {
|
if as_.len() != bs.len() {
|
||||||
return Err(ty::terr_ty_param_size(expected_found(self,
|
return Err(ty::terr_ty_param_size(expected_found(self,
|
||||||
|
@ -101,24 +98,11 @@ pub trait Combine {
|
||||||
bs.len())));
|
bs.len())));
|
||||||
}
|
}
|
||||||
|
|
||||||
match space {
|
try!(result::fold_(as_
|
||||||
subst::SelfSpace => {
|
.iter()
|
||||||
result::fold(as_
|
.zip(bs.iter())
|
||||||
.iter()
|
.map(|(a, b)| eq_tys(self, *a, *b))));
|
||||||
.zip(bs.iter())
|
Ok(Vec::from_slice(as_))
|
||||||
.map(|(a, b)| self.contratys(*a, *b)),
|
|
||||||
Vec::new(),
|
|
||||||
|mut v, a| { v.push(a); v })
|
|
||||||
}
|
|
||||||
|
|
||||||
subst::TypeSpace | subst::FnSpace => {
|
|
||||||
try!(result::fold_(as_
|
|
||||||
.iter()
|
|
||||||
.zip(bs.iter())
|
|
||||||
.map(|(a, b)| eq_tys(self, *a, *b))));
|
|
||||||
Ok(Vec::from_slice(as_))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn substs(&self,
|
fn substs(&self,
|
||||||
|
|
|
@ -78,8 +78,8 @@ receiver position from being called via an object.)
|
||||||
#### Trait variance and vtable resolution
|
#### Trait variance and vtable resolution
|
||||||
|
|
||||||
But traits aren't only used with objects. They're also used when
|
But traits aren't only used with objects. They're also used when
|
||||||
deciding whether a given impl satisfies a given trait bound (or should
|
deciding whether a given impl satisfies a given trait bound. To set the
|
||||||
be -- FIXME #5781). To set the scene here, imagine I had a function:
|
scene here, imagine I had a function:
|
||||||
|
|
||||||
fn convertAll<A,T:ConvertTo<A>>(v: &[T]) {
|
fn convertAll<A,T:ConvertTo<A>>(v: &[T]) {
|
||||||
...
|
...
|
||||||
|
|
|
@ -140,7 +140,14 @@ fn runtest(test: &str, cratename: &str, libs: HashSet<Path>, should_fail: bool,
|
||||||
let old = io::stdio::set_stderr(box w1);
|
let old = io::stdio::set_stderr(box w1);
|
||||||
spawn(proc() {
|
spawn(proc() {
|
||||||
let mut p = io::ChanReader::new(rx);
|
let mut p = io::ChanReader::new(rx);
|
||||||
let mut err = old.unwrap_or(box io::stderr() as Box<Writer + Send>);
|
let mut err = match old {
|
||||||
|
Some(old) => {
|
||||||
|
// Chop off the `Send` bound.
|
||||||
|
let old: Box<Writer> = old;
|
||||||
|
old
|
||||||
|
}
|
||||||
|
None => box io::stderr() as Box<Writer>,
|
||||||
|
};
|
||||||
io::util::copy(&mut p, &mut err).unwrap();
|
io::util::copy(&mut p, &mut err).unwrap();
|
||||||
});
|
});
|
||||||
let emitter = diagnostic::EmitterWriter::new(box w2);
|
let emitter = diagnostic::EmitterWriter::new(box w2);
|
||||||
|
|
|
@ -183,7 +183,10 @@ mod test {
|
||||||
writer.write_be_u32(42).unwrap();
|
writer.write_be_u32(42).unwrap();
|
||||||
|
|
||||||
let wanted = vec![0u8, 0u8, 0u8, 42u8];
|
let wanted = vec![0u8, 0u8, 0u8, 42u8];
|
||||||
let got = task::try(proc() { rx.recv() }).unwrap();
|
let got = match task::try(proc() { rx.recv() }) {
|
||||||
|
Ok(got) => got,
|
||||||
|
Err(_) => fail!(),
|
||||||
|
};
|
||||||
assert_eq!(wanted, got);
|
assert_eq!(wanted, got);
|
||||||
|
|
||||||
match writer.write_u8(1) {
|
match writer.write_u8(1) {
|
||||||
|
|
|
@ -630,9 +630,11 @@ mod test {
|
||||||
let mut reader = ChanReader::new(rx);
|
let mut reader = ChanReader::new(rx);
|
||||||
let stdout = ChanWriter::new(tx);
|
let stdout = ChanWriter::new(tx);
|
||||||
|
|
||||||
TaskBuilder::new().stdout(box stdout as Box<Writer + Send>).try(proc() {
|
let r = TaskBuilder::new().stdout(box stdout as Box<Writer + Send>)
|
||||||
print!("Hello, world!");
|
.try(proc() {
|
||||||
}).unwrap();
|
print!("Hello, world!");
|
||||||
|
});
|
||||||
|
assert!(r.is_ok());
|
||||||
|
|
||||||
let output = reader.read_to_str().unwrap();
|
let output = reader.read_to_str().unwrap();
|
||||||
assert_eq!(output, "Hello, world!".to_string());
|
assert_eq!(output, "Hello, world!".to_string());
|
||||||
|
|
|
@ -18,6 +18,7 @@ use std::fmt;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::iter::range;
|
use std::iter::range;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
|
use term::WriterWrapper;
|
||||||
use term;
|
use term;
|
||||||
|
|
||||||
// maximum number of lines we will print for each error; arbitrary.
|
// maximum number of lines we will print for each error; arbitrary.
|
||||||
|
@ -281,7 +282,7 @@ pub struct EmitterWriter {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum Destination {
|
enum Destination {
|
||||||
Terminal(Box<term::Terminal<Box<Writer + Send>> + Send>),
|
Terminal(Box<term::Terminal<WriterWrapper> + Send>),
|
||||||
Raw(Box<Writer + Send>),
|
Raw(Box<Writer + Send>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,28 +66,52 @@ pub mod terminfo;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod win;
|
mod win;
|
||||||
|
|
||||||
|
/// A hack to work around the fact that `Box<Writer + Send>` does not
|
||||||
|
/// currently implement `Writer`.
|
||||||
|
pub struct WriterWrapper {
|
||||||
|
wrapped: Box<Writer + Send>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Writer for WriterWrapper {
|
||||||
|
#[inline]
|
||||||
|
fn write(&mut self, buf: &[u8]) -> IoResult<()> {
|
||||||
|
self.wrapped.write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn flush(&mut self) -> IoResult<()> {
|
||||||
|
self.wrapped.flush()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
|
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
|
||||||
/// opened.
|
/// opened.
|
||||||
pub fn stdout() -> Option<Box<Terminal<Box<Writer + Send>> + Send>> {
|
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
|
||||||
let ti: Option<TerminfoTerminal<Box<Writer + Send>>>
|
let ti: Option<TerminfoTerminal<WriterWrapper>>
|
||||||
= Terminal::new(box std::io::stdout() as Box<Writer + Send>);
|
= Terminal::new(WriterWrapper {
|
||||||
ti.map(|t| box t as Box<Terminal<Box<Writer + Send> + Send> + Send>)
|
wrapped: box std::io::stdout() as Box<Writer + Send>,
|
||||||
|
});
|
||||||
|
ti.map(|t| box t as Box<Terminal<WriterWrapper> + Send>)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
|
/// Return a Terminal wrapping stdout, or None if a terminal couldn't be
|
||||||
/// opened.
|
/// opened.
|
||||||
pub fn stdout() -> Option<Box<Terminal<Box<Writer + Send> + Send> + Send>> {
|
pub fn stdout() -> Option<Box<Terminal<WriterWrapper> + Send>> {
|
||||||
let ti: Option<TerminfoTerminal<Box<Writer + Send>>>
|
let ti: Option<TerminfoTerminal<WriterWrapper>>
|
||||||
= Terminal::new(box std::io::stdout() as Box<Writer + Send>);
|
= Terminal::new(WriterWrapper {
|
||||||
|
wrapped: box std::io::stdout() as Box<Writer + Send>,
|
||||||
|
});
|
||||||
|
|
||||||
match ti {
|
match ti {
|
||||||
Some(t) => Some(box t as Box<Terminal<Box<Writer + Send> + Send> + Send>),
|
Some(t) => Some(box t as Box<Terminal<WriterWrapper> + Send>),
|
||||||
None => {
|
None => {
|
||||||
let wc: Option<WinConsole<Box<Writer + Send>>>
|
let wc: Option<WinConsole<WriterWrapper>>
|
||||||
= Terminal::new(box std::io::stdout() as Box<Writer + Send>);
|
= Terminal::new(WriterWrapper {
|
||||||
wc.map(|w| box w as Box<Terminal<Box<Writer + Send> + Send> + Send>)
|
wrapped: box std::io::stdout() as Box<Writer + Send>,
|
||||||
|
});
|
||||||
|
wc.map(|w| box w as Box<Terminal<WriterWrapper> + Send>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,25 +119,31 @@ pub fn stdout() -> Option<Box<Terminal<Box<Writer + Send> + Send> + Send>> {
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
|
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
|
||||||
/// opened.
|
/// opened.
|
||||||
pub fn stderr() -> Option<Box<Terminal<Box<Writer + Send> + Send> + Send> + Send> {
|
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send> + Send> {
|
||||||
let ti: Option<TerminfoTerminal<Box<Writer + Send>>>
|
let ti: Option<TerminfoTerminal<WriterWrapper>>
|
||||||
= Terminal::new(box std::io::stderr() as Box<Writer + Send>);
|
= Terminal::new(WriterWrapper {
|
||||||
ti.map(|t| box t as Box<Terminal<Box<Writer + Send> + Send> + Send>)
|
wrapped: box std::io::stderr() as Box<Writer + Send>,
|
||||||
|
});
|
||||||
|
ti.map(|t| box t as Box<Terminal<WriterWrapper> + Send>)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
|
/// Return a Terminal wrapping stderr, or None if a terminal couldn't be
|
||||||
/// opened.
|
/// opened.
|
||||||
pub fn stderr() -> Option<Box<Terminal<Box<Writer + Send> + Send> + Send>> {
|
pub fn stderr() -> Option<Box<Terminal<WriterWrapper> + Send> + Send> {
|
||||||
let ti: Option<TerminfoTerminal<Box<Writer + Send>>>
|
let ti: Option<TerminfoTerminal<WriterWrapper>>
|
||||||
= Terminal::new(box std::io::stderr() as Box<Writer + Send>);
|
= Terminal::new(WriterWrapper {
|
||||||
|
wrapped: box std::io::stderr() as Box<Writer + Send>,
|
||||||
|
});
|
||||||
|
|
||||||
match ti {
|
match ti {
|
||||||
Some(t) => Some(box t as Box<Terminal<Box<Writer + Send> + Send> + Send>),
|
Some(t) => Some(box t as Box<Terminal<WriterWrapper> + Send>),
|
||||||
None => {
|
None => {
|
||||||
let wc: Option<WinConsole<Box<Writer + Send>>>
|
let wc: Option<WinConsole<WriterWrapper>>
|
||||||
= Terminal::new(box std::io::stderr() as Box<Writer + Send>);
|
= Terminal::new(WriterWrapper {
|
||||||
wc.map(|w| box w as Box<Terminal<Box<Writer + Send> + Send> + Send>)
|
wrapped: box std::io::stderr() as Box<Writer + Send>,
|
||||||
|
});
|
||||||
|
wc.map(|w| box w as Box<Terminal<WriterWrapper> + Send>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -474,7 +474,7 @@ pub enum TestResult {
|
||||||
}
|
}
|
||||||
|
|
||||||
enum OutputLocation<T> {
|
enum OutputLocation<T> {
|
||||||
Pretty(Box<term::Terminal<Box<Writer + Send>> + Send>),
|
Pretty(Box<term::Terminal<term::WriterWrapper> + Send>),
|
||||||
Raw(T),
|
Raw(T),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ fn with<R:deref>(f: |x: &int| -> R) -> int {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn return_it() -> int {
|
fn return_it() -> int {
|
||||||
with(|o| o) //~ ERROR lifetime of function argument does not outlive the function call
|
with(|o| o) //~ ERROR cannot infer an appropriate lifetime
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
31
src/test/compile-fail/variance-trait-matching-2.rs
Normal file
31
src/test/compile-fail/variance-trait-matching-2.rs
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
extern crate serialize;
|
||||||
|
|
||||||
|
use std::io::MemWriter;
|
||||||
|
use std::io;
|
||||||
|
use serialize::{Encodable, Encoder};
|
||||||
|
|
||||||
|
pub fn buffer_encode<'a,
|
||||||
|
T:Encodable<serialize::json::Encoder<'a>,io::IoError>>(
|
||||||
|
to_encode_object: &T)
|
||||||
|
-> Vec<u8> {
|
||||||
|
let mut m = MemWriter::new();
|
||||||
|
{
|
||||||
|
let mut encoder =
|
||||||
|
serialize::json::Encoder::new(&mut m as &mut io::Writer);
|
||||||
|
//~^ ERROR `m` does not live long enough
|
||||||
|
to_encode_object.encode(&mut encoder);
|
||||||
|
}
|
||||||
|
m.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
30
src/test/compile-fail/variance-trait-matching.rs
Normal file
30
src/test/compile-fail/variance-trait-matching.rs
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// Issue #5781. Tests that subtyping is handled properly in trait matching.
|
||||||
|
|
||||||
|
trait Make<'a> {
|
||||||
|
fn make(x: &'a mut int) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Make<'a> for &'a mut int {
|
||||||
|
fn make(x: &'a mut int) -> &'a mut int {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn f() -> &'static mut int {
|
||||||
|
let mut x = 1;
|
||||||
|
let y: &'static mut int = Make::make(&mut x); //~ ERROR `x` does not live long enough
|
||||||
|
y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
||||||
|
|
|
@ -13,8 +13,9 @@
|
||||||
use std::task;
|
use std::task;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
task::try(proc() {
|
let r: Result<int,_> = task::try(proc() {
|
||||||
fail!("test");
|
fail!("test");
|
||||||
1
|
1i
|
||||||
}).unwrap()
|
});
|
||||||
|
assert!(r.is_ok());
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,8 +13,10 @@
|
||||||
use std::task::TaskBuilder;
|
use std::task::TaskBuilder;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
TaskBuilder::new().named("owned name".to_string()).try(proc() {
|
let r: Result<int,_> = TaskBuilder::new().named("owned name".to_string())
|
||||||
|
.try(proc() {
|
||||||
fail!("test");
|
fail!("test");
|
||||||
1
|
1
|
||||||
}).unwrap()
|
});
|
||||||
|
assert!(r.is_ok());
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,8 +11,11 @@
|
||||||
// error-pattern:task 'send name' failed at 'test'
|
// error-pattern:task 'send name' failed at 'test'
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
::std::task::TaskBuilder::new().named("send name".into_maybe_owned()).try(proc() {
|
let r: Result<int,_> =
|
||||||
fail!("test");
|
::std::task::TaskBuilder::new().named("send name".into_maybe_owned())
|
||||||
3
|
.try(proc() {
|
||||||
}).unwrap()
|
fail!("test");
|
||||||
|
3
|
||||||
|
});
|
||||||
|
assert!(r.is_ok());
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,9 @@
|
||||||
// error-pattern:task 'static name' failed at 'test'
|
// error-pattern:task 'static name' failed at 'test'
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
::std::task::TaskBuilder::new().named("static name").try(proc() {
|
let r: Result<int,_> =
|
||||||
fail!("test");
|
::std::task::TaskBuilder::new().named("static name").try(proc() {
|
||||||
}).unwrap()
|
fail!("test");
|
||||||
|
});
|
||||||
|
assert!(r.is_ok());
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,10 @@ use std::task;
|
||||||
fn main() {
|
fn main() {
|
||||||
// the purpose of this test is to make sure that task::spawn()
|
// the purpose of this test is to make sure that task::spawn()
|
||||||
// works when provided with a bare function:
|
// works when provided with a bare function:
|
||||||
task::try(startfn).unwrap();
|
let r = task::try(startfn);
|
||||||
|
if r.is_err() {
|
||||||
|
fail!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn startfn() {
|
fn startfn() {
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
// ignore-test
|
||||||
|
|
||||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
// file at the top-level directory of this distribution and at
|
// file at the top-level directory of this distribution and at
|
||||||
// http://rust-lang.org/COPYRIGHT.
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue