use cmp::PartialOrd;
use fmt;
use marker::{Sized, Unsize};
+use result::Result::{self, Ok, Err};
/// The `Drop` trait is used to run some code when a value goes out of scope.
/// This is sometimes called a 'destructor'.
///
/// # Examples
///
-/// A trivial implementation of `BitAnd`. When `Foo & Foo` happens, it ends up
-/// calling `bitand`, and therefore, `main` prints `Bitwise And-ing!`.
+/// In this example, the `BitAnd` trait is implemented for a `BooleanVector`
+/// struct.
///
/// ```
/// use std::ops::BitAnd;
///
-/// struct Foo;
-///
-/// impl BitAnd for Foo {
-/// type Output = Foo;
-///
-/// fn bitand(self, _rhs: Foo) -> Foo {
-/// println!("Bitwise And-ing!");
-/// self
+/// #[derive(Debug)]
+/// struct BooleanVector {
+/// value: Vec<bool>,
+/// };
+///
+/// impl BitAnd for BooleanVector {
+/// type Output = Self;
+///
+/// fn bitand(self, rhs: Self) -> Self {
+/// BooleanVector {
+/// value: self.value
+/// .iter()
+/// .zip(rhs.value.iter())
+/// .map(|(x, y)| *x && *y)
+/// .collect(),
+/// }
/// }
/// }
///
-/// fn main() {
-/// Foo & Foo;
+/// impl PartialEq for BooleanVector {
+/// fn eq(&self, other: &Self) -> bool {
+/// self.value == other.value
+/// }
/// }
+///
+/// let bv1 = BooleanVector { value: vec![true, true, false, false] };
+/// let bv2 = BooleanVector { value: vec![true, false, true, false] };
+/// let expected = BooleanVector { value: vec![true, false, false, false] };
+/// assert_eq!(bv1 & bv2, expected);
/// ```
#[lang = "bitand"]
#[stable(feature = "rust1", since = "1.0.0")]
/// Creates a globally fresh place.
fn make_place() -> Self;
}
+
+/// A trait for types which have success and error states and are meant to work
+/// with the question mark operator.
+/// When the `?` operator is used with a value, whether the value is in the
+/// success or error state is determined by calling `translate`.
+///
+/// This trait is **very** experimental, it will probably be iterated on heavily
+/// before it is stabilised. Implementors should expect change. Users of `?`
+/// should not rely on any implementations of `Carrier` other than `Result`,
+/// i.e., you should not expect `?` to continue to work with `Option`, etc.
+#[unstable(feature = "question_mark_carrier", issue = "31436")]
+pub trait Carrier {
+ /// The type of the value when computation succeeds.
+ type Success;
+ /// The type of the value when computation errors out.
+ type Error;
+
+ /// Create a `Carrier` from a success value.
+ fn from_success(Self::Success) -> Self;
+
+ /// Create a `Carrier` from an error value.
+ fn from_error(Self::Error) -> Self;
+
+ /// Translate this `Carrier` to another implementation of `Carrier` with the
+ /// same associated types.
+ fn translate<T>(self) -> T where T: Carrier<Success=Self::Success, Error=Self::Error>;
+}
+
+#[unstable(feature = "question_mark_carrier", issue = "31436")]
+impl<U, V> Carrier for Result<U, V> {
+ type Success = U;
+ type Error = V;
+
+ fn from_success(u: U) -> Result<U, V> {
+ Ok(u)
+ }
+
+ fn from_error(e: V) -> Result<U, V> {
+ Err(e)
+ }
+
+ fn translate<T>(self) -> T
+ where T: Carrier<Success=U, Error=V>
+ {
+ match self {
+ Ok(u) => T::from_success(u),
+ Err(e) => T::from_error(e),
+ }
+ }
+}
+
+struct _DummyErrorType;
+
+impl Carrier for _DummyErrorType {
+ type Success = ();
+ type Error = ();
+
+ fn from_success(_: ()) -> _DummyErrorType {
+ _DummyErrorType
+ }
+
+ fn from_error(_: ()) -> _DummyErrorType {
+ _DummyErrorType
+ }
+
+ fn translate<T>(self) -> T
+ where T: Carrier<Success=(), Error=()>
+ {
+ T::from_success(())
+ }
+}
let inplace_finalize = ["ops", "InPlace", "finalize"];
let make_call = |this: &mut LoweringContext, p, args| {
- let path = this.core_path(e.span, p);
+ let path = this.std_path(e.span, p);
let path = this.expr_path(path, ThinVec::new());
this.expr_call(e.span, path, args)
};
ast_expr: &Expr,
path: &[&str],
fields: &[(&str, &P<Expr>)]) -> P<hir::Expr> {
- let strs = this.std_path(&iter::once(&"ops")
- .chain(path)
- .map(|s| *s)
- .collect::<Vec<_>>());
-
- let structpath = this.path_global(ast_expr.span, strs);
+ let struct_path = this.std_path(ast_expr.span,
+ &iter::once(&"ops").chain(path)
+ .map(|s| *s)
+ .collect::<Vec<_>>());
let hir_expr = if fields.len() == 0 {
- this.expr_path(structpath, ast_expr.attrs.clone())
+ this.expr_path(struct_path, ast_expr.attrs.clone())
} else {
let fields = fields.into_iter().map(|&(s, e)| {
let expr = this.lower_expr(&e);
}).collect();
let attrs = ast_expr.attrs.clone();
- this.expr_struct(ast_expr.span, structpath, fields, None, attrs)
+ this.expr_struct(ast_expr.span, struct_path, fields, None, attrs)
};
this.signal_block_expr(hir_vec![],
// `match ::std::iter::Iterator::next(&mut iter) { ... }`
let match_expr = {
- let next_path = {
- let strs = self.std_path(&["iter", "Iterator", "next"]);
-
- self.path_global(e.span, strs)
- };
+ let next_path = self.std_path(e.span, &["iter", "Iterator", "next"]);
let iter = self.expr_ident(e.span, iter, iter_pat.id);
let ref_mut_iter = self.expr_mut_addr_of(e.span, iter);
let next_path = self.expr_path(next_path, ThinVec::new());
// `match ::std::iter::IntoIterator::into_iter(<head>) { ... }`
let into_iter_expr = {
- let into_iter_path = {
- let strs = self.std_path(&["iter", "IntoIterator", "into_iter"]);
-
- self.path_global(e.span, strs)
- };
+ let into_iter_path = self.std_path(e.span,
+ &["iter", "IntoIterator", "into_iter"]);
let into_iter = self.expr_path(into_iter_path, ThinVec::new());
self.expr_call(e.span, into_iter, hir_vec![head])
// to:
//
// {
- // match <expr> {
+ // match { Carrier::translate( { <expr> } ) } {
// Ok(val) => val,
- // Err(err) => {
- // return Err(From::from(err))
- // }
+ // Err(err) => { return Carrier::from_error(From::from(err)); }
// }
// }
- // expand <expr>
- let sub_expr = self.lower_expr(sub_expr);
+ // { Carrier::translate( { <expr> } ) }
+ let discr = {
+ // expand <expr>
+ let sub_expr = self.lower_expr(sub_expr);
+ let sub_expr = self.signal_block_expr(hir_vec![],
+ sub_expr,
+ e.span,
+ hir::PopUnstableBlock,
+ ThinVec::new());
+
+ let path = self.std_path(e.span, &["ops", "Carrier", "translate"]);
+ let path = self.expr_path(path, ThinVec::new());
+ let call = self.expr_call(e.span, path, hir_vec![sub_expr]);
+
+ self.signal_block_expr(hir_vec![],
+ call,
+ e.span,
+ hir::PushUnstableBlock,
+ ThinVec::new())
+ };
// Ok(val) => val
let ok_arm = {
self.arm(hir_vec![ok_pat], val_expr)
};
- // Err(err) => return Err(From::from(err))
+ // Err(err) => { return Carrier::from_error(From::from(err)); }
let err_arm = {
let err_ident = self.str_to_ident("err");
let err_local = self.pat_ident(e.span, err_ident);
let from_expr = {
- let path = self.std_path(&["convert", "From", "from"]);
- let path = self.path_global(e.span, path);
+ let path = self.std_path(e.span, &["convert", "From", "from"]);
let from = self.expr_path(path, ThinVec::new());
let err_expr = self.expr_ident(e.span, err_ident, err_local.id);
self.expr_call(e.span, from, hir_vec![err_expr])
};
- let err_expr = {
- let path = self.std_path(&["result", "Result", "Err"]);
- let path = self.path_global(e.span, path);
- let err_ctor = self.expr_path(path, ThinVec::new());
- self.expr_call(e.span, err_ctor, hir_vec![from_expr])
+ let from_err_expr = {
+ let path = self.std_path(e.span, &["ops", "Carrier", "from_error"]);
+ let from_err = self.expr_path(path, ThinVec::new());
+ self.expr_call(e.span, from_err, hir_vec![from_expr])
};
- let err_pat = self.pat_err(e.span, err_local);
+
let ret_expr = self.expr(e.span,
- hir::Expr_::ExprRet(Some(err_expr)),
- ThinVec::new());
- self.arm(hir_vec![err_pat], ret_expr)
+ hir::Expr_::ExprRet(Some(from_err_expr)),
+ ThinVec::new());
+ let ret_stmt = self.stmt_expr(ret_expr);
+ let block = self.signal_block_stmt(ret_stmt, e.span,
+ hir::PushUnstableBlock, ThinVec::new());
+
+ let err_pat = self.pat_err(e.span, err_local);
+ self.arm(hir_vec![err_pat], block)
};
- return self.expr_match(e.span, sub_expr, hir_vec![err_arm, ok_arm],
+ return self.expr_match(e.span, discr, hir_vec![err_arm, ok_arm],
hir::MatchSource::TryDesugar);
}
(respan(sp, hir::StmtDecl(P(decl), self.next_id())), pat_id)
}
+ // Turns `<expr>` into `<expr>;`, note that this produces a StmtSemi, not a
+ // StmtExpr.
+ fn stmt_expr(&self, expr: P<hir::Expr>) -> hir::Stmt {
+ hir::Stmt {
+ span: expr.span,
+ node: hir::StmtSemi(expr, self.next_id()),
+ }
+ }
+
fn block_expr(&mut self, expr: P<hir::Expr>) -> P<hir::Block> {
self.block_all(expr.span, hir::HirVec::new(), Some(expr))
}
}
fn pat_ok(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
- let ok = self.std_path(&["result", "Result", "Ok"]);
- let path = self.path_global(span, ok);
+ let path = self.std_path(span, &["result", "Result", "Ok"]);
self.pat_enum(span, path, hir_vec![pat])
}
fn pat_err(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
- let err = self.std_path(&["result", "Result", "Err"]);
- let path = self.path_global(span, err);
+ let path = self.std_path(span, &["result", "Result", "Err"]);
self.pat_enum(span, path, hir_vec![pat])
}
fn pat_some(&mut self, span: Span, pat: P<hir::Pat>) -> P<hir::Pat> {
- let some = self.std_path(&["option", "Option", "Some"]);
- let path = self.path_global(span, some);
+ let path = self.std_path(span, &["option", "Option", "Some"]);
self.pat_enum(span, path, hir_vec![pat])
}
fn pat_none(&mut self, span: Span) -> P<hir::Pat> {
- let none = self.std_path(&["option", "Option", "None"]);
- let path = self.path_global(span, none);
+ let path = self.std_path(span, &["option", "Option", "None"]);
self.pat_enum(span, path, hir_vec![])
}
}
}
- fn std_path(&mut self, components: &[&str]) -> Vec<Name> {
+ fn std_path_components(&mut self, components: &[&str]) -> Vec<Name> {
let mut v = Vec::new();
if let Some(s) = self.crate_root {
v.push(token::intern(s));
// Given suffix ["b","c","d"], returns path `::std::b::c::d` when
// `fld.cx.use_std`, and `::core::b::c::d` otherwise.
- fn core_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
- let idents = self.std_path(components);
+ fn std_path(&mut self, span: Span, components: &[&str]) -> hir::Path {
+ let idents = self.std_path_components(components);
self.path_global(span, idents)
}
});
self.expr_block(block, attrs)
}
+
+ fn signal_block_stmt(&mut self,
+ stmt: hir::Stmt,
+ span: Span,
+ rule: hir::BlockCheckMode,
+ attrs: ThinVec<Attribute>)
+ -> P<hir::Expr> {
+ let id = self.next_id();
+ let block = P(hir::Block {
+ rules: rule,
+ span: span,
+ id: id,
+ stmts: hir_vec![stmt],
+ expr: None,
+ });
+ self.expr_block(block, attrs)
+ }
}
let b_ty = &b_subst.types[i];
let variance = variances.map_or(ty::Invariant, |v| v.types[i]);
relation.relate_with_variance(variance, a_ty, b_ty)
- }).collect()?;
+ }).collect::<Result<_, _>>()?;
let regions = a_subst.regions.iter().enumerate().map(|(i, a_r)| {
let b_r = &b_subst.regions[i];
let variance = variances.map_or(ty::Invariant, |v| v.regions[i]);
relation.relate_with_variance(variance, a_r, b_r)
- }).collect()?;
+ }).collect::<Result<_, _>>()?;
Ok(Substs::new(tcx, types, regions))
}
struct_span_err!(self.bccx, span, E0503,
"cannot use `{}` because it was mutably borrowed",
&self.bccx.loan_path_to_string(copy_path))
- .span_note(loan_span,
+ .span_label(loan_span,
&format!("borrow of `{}` occurs here",
&self.bccx.loan_path_to_string(&loan_path))
)
+ .span_label(span,
+ &format!("use of borrowed `{}`",
+ &self.bccx.loan_path_to_string(&loan_path)))
.emit();
}
}
}
mc::AliasableStatic |
mc::AliasableStaticMut => {
- struct_span_err!(
+ let mut err = struct_span_err!(
self.tcx.sess, span, E0388,
- "{} in a static location", prefix)
+ "{} in a static location", prefix);
+ err.span_label(span, &format!("cannot write data in a static definition"));
+ err
}
mc::AliasableBorrowed => {
struct_span_err!(
return
}
+ let mut arg = OsString::new();
let path = tmpdir.join("list");
- let prefix = if self.sess.target.target.options.is_like_osx {
- "_"
- } else {
- ""
- };
- let res = (|| -> io::Result<()> {
- let mut f = BufWriter::new(File::create(&path)?);
- for sym in &self.info.cdylib_exports {
- writeln!(f, "{}{}", prefix, sym)?;
+
+ if self.sess.target.target.options.is_like_solaris {
+ let res = (|| -> io::Result<()> {
+ let mut f = BufWriter::new(File::create(&path)?);
+ writeln!(f, "{{\n global:")?;
+ for sym in &self.info.cdylib_exports {
+ writeln!(f, " {};", sym)?;
+ }
+ writeln!(f, "\n local:\n *;\n}};")?;
+ Ok(())
+ })();
+ if let Err(e) = res {
+ self.sess.fatal(&format!("failed to write version script: {}", e));
}
- Ok(())
- })();
- if let Err(e) = res {
- self.sess.fatal(&format!("failed to write lib.def file: {}", e));
- }
- let mut arg = OsString::new();
- if self.sess.target.target.options.is_like_osx {
- arg.push("-Wl,-exported_symbols_list,");
+
+ arg.push("-Wl,-M,");
+ arg.push(&path);
} else {
- arg.push("-Wl,--retain-symbols-file=");
+ let prefix = if self.sess.target.target.options.is_like_osx {
+ "_"
+ } else {
+ ""
+ };
+ let res = (|| -> io::Result<()> {
+ let mut f = BufWriter::new(File::create(&path)?);
+ for sym in &self.info.cdylib_exports {
+ writeln!(f, "{}{}", prefix, sym)?;
+ }
+ Ok(())
+ })();
+ if let Err(e) = res {
+ self.sess.fatal(&format!("failed to write lib.def file: {}", e));
+ }
+ if self.sess.target.target.options.is_like_osx {
+ arg.push("-Wl,-exported_symbols_list,");
+ } else {
+ arg.push("-Wl,--retain-symbols-file=");
+ }
+ arg.push(&path);
}
- arg.push(&path);
+
self.cmd.arg(arg);
}
}
if let ty::TyTrait(..) = mt.ty.sty {
// This is "x = SomeTrait" being reduced from
// "let &x = &SomeTrait" or "let box x = Box<SomeTrait>", an error.
- span_err!(self.tcx.sess, span, E0033,
- "type `{}` cannot be dereferenced",
- self.ty_to_string(expected));
+ let type_str = self.ty_to_string(expected);
+ struct_span_err!(self.tcx.sess, span, E0033,
+ "type `{}` cannot be dereferenced", type_str)
+ .span_label(span, &format!("type `{}` cannot be dereferenced", type_str))
+ .emit();
return false
}
}
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_vec_unchecked(mut v: Vec<u8>) -> CString {
+ v.reserve_exact(1);
v.push(0);
CString { inner: v.into_boxed_slice() }
}
//~| ERROR E0017
//~| NOTE statics require immutable values
//~| ERROR E0388
+ //~| NOTE cannot write data in a static definition
static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0017
//~| NOTE statics require immutable values
//~| ERROR E0017
}
fn main() {
- let trait_obj: &SomeTrait = SomeTrait; //~ ERROR E0425
- //~^ ERROR E0038
- let &invalid = trait_obj; //~ ERROR E0033
+ let trait_obj: &SomeTrait = SomeTrait;
+ //~^ ERROR E0425
+ //~| ERROR E0038
+ //~| method `foo` has no receiver
+ //~| NOTE the trait `SomeTrait` cannot be made into an object
+
+ let &invalid = trait_obj;
+ //~^ ERROR E0033
+ //~| NOTE type `&SomeTrait` cannot be dereferenced
}
let _x = &mut a.x;
//~^ NOTE borrow of `a.x` occurs here
let _y = a.y; //~ ERROR cannot use
+ //~^ NOTE use of borrowed `a.x`
}
fn move_after_mut_borrow() {
let _x = &mut a.x.x;
//~^ NOTE borrow of `a.x.x` occurs here
let _y = a.y; //~ ERROR cannot use
+ //~^ NOTE use of borrowed `a.x.x`
}
fn move_after_mut_borrow_nested() {
($this:expr) => {
$this.width.unwrap()
//~^ ERROR cannot use `self.width` because it was mutably borrowed
+ //~| NOTE use of borrowed `*self`
}
);
--- /dev/null
+// Copyright 2016 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.
+
+#![feature(question_mark, question_mark_carrier)]
+
+// Test that type inference fails where there are multiple possible return types
+// for the `?` operator.
+
+fn f(x: &i32) -> Result<i32, ()> {
+ Ok(*x)
+}
+
+fn g() -> Result<Vec<i32>, ()> {
+ let l = [1, 2, 3, 4];
+ l.iter().map(f).collect()? //~ ERROR type annotations required: cannot resolve
+}
+
+fn main() {
+ g();
+}
fn broken() {
let mut x = 3;
let mut _y = vec!(&mut x);
+ //~^ NOTE borrow of `x` occurs here
+ //~| NOTE borrow of `x` occurs here
+ //~| NOTE borrow of `x` occurs here
while x < 10 { //~ ERROR cannot use `x` because it was mutably borrowed
+ //~^ NOTE use of borrowed `x`
let mut z = x; //~ ERROR cannot use `x` because it was mutably borrowed
+ //~^ NOTE use of borrowed `x`
_y.push(&mut z); //~ ERROR `z` does not live long enough
+ //~^ NOTE does not live long enough
x += 1; //~ ERROR cannot assign
+ //~^ NOTE assignment to borrowed `x` occurs here
}
+ //~^ NOTE borrowed value only valid until here
}
+//~^ NOTE borrowed value must be valid until here
fn main() { }
--- /dev/null
+// Copyright 2016 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.
+
+#![feature(question_mark, question_mark_carrier)]
+
+use std::ops::Carrier;
+
+enum MyResult<T, U> {
+ Awesome(T),
+ Terrible(U)
+}
+
+impl<U, V> Carrier for MyResult<U, V> {
+ type Success = U;
+ type Error = V;
+
+ fn from_success(u: U) -> MyResult<U, V> {
+ MyResult::Awesome(u)
+ }
+
+ fn from_error(e: V) -> MyResult<U, V> {
+ MyResult::Terrible(e)
+ }
+
+ fn translate<T>(self) -> T
+ where T: Carrier<Success=U, Error=V>
+ {
+ match self {
+ MyResult::Awesome(u) => T::from_success(u),
+ MyResult::Terrible(e) => T::from_error(e),
+ }
+ }
+}
+
+fn f(x: i32) -> Result<i32, String> {
+ if x == 0 {
+ Ok(42)
+ } else {
+ let y = g(x)?;
+ Ok(y)
+ }
+}
+
+fn g(x: i32) -> MyResult<i32, String> {
+ let _y = f(x - 1)?;
+ MyResult::Terrible("Hello".to_owned())
+}
+
+fn h() -> MyResult<i32, String> {
+ let a: Result<i32, &'static str> = Err("Hello");
+ let b = a?;
+ MyResult::Awesome(b)
+}
+
+fn i() -> MyResult<i32, String> {
+ let a: MyResult<i32, &'static str> = MyResult::Terrible("Hello");
+ let b = a?;
+ MyResult::Awesome(b)
+}
+
+fn main() {
+ assert!(f(0) == Ok(42));
+ assert!(f(10) == Err("Hello".to_owned()));
+ let _ = h();
+ let _ = i();
+}
#[cfg(unix)]
pub fn check(path: &Path, bad: &mut bool) {
use std::fs;
+ use std::process::{Command, Stdio};
use std::os::unix::prelude::*;
super::walk(path,
let metadata = t!(fs::symlink_metadata(&file), &file);
if metadata.mode() & 0o111 != 0 {
- println!("binary checked into source: {}", file.display());
- *bad = true;
+ let rel_path = file.strip_prefix(path).unwrap();
+ let git_friendly_path = rel_path.to_str().unwrap().replace("\\", "/");
+ let ret_code = Command::new("git")
+ .arg("ls-files")
+ .arg(&git_friendly_path)
+ .current_dir(path)
+ .stdout(Stdio::null())
+ .stderr(Stdio::null())
+ .status()
+ .unwrap_or_else(|e| {
+ panic!("could not run git ls-files: {}", e);
+ });
+ if ret_code.success() {
+ println!("binary checked into source: {}", file.display());
+ *bad = true;
+ }
}
})
}