diff --git a/.travis.yml b/.travis.yml index 29d287bfb4849..dc955bc2f2be2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,9 @@ -# Use something that's not 'ruby' so we don't set up things like -# RVM/bundler/ruby and whatnot. Right now 'rust' as a language actually -# downloads a rust/cargo snapshot, which we don't really want for building rust. +# ccache support is disabled unless your language is a C-derivative. However +# `language: C` unconditionally sets `CC=compiler`. If we just set it in our +# `env` it will be overwritten by the default (gcc 4.6). language: c +compiler: /usr/bin/gcc-4.7 +cache: ccache sudo: false # The test suite is in general way too stressful for travis, especially in @@ -9,12 +11,28 @@ sudo: false # back to only build the stage1 compiler and run a subset of tests, but this # didn't end up panning out very well. # -# As a result, we're just using travis to run `make tidy` now. It'll help -# everyone find out about their trailing spaces early on! +# As a result, we're just using travis to run `make tidy` and *only* build +# stage1 but *not* test it for now (a strict subset of the bootstrap). This will +# catch "obvious" errors like style or not even compiling. +# +# We need gcc4.7 or higher to build LLVM, and travis (well, Ubuntu 12.04) +# currently ships with 4.6. Gotta download our own. before_script: - - ./configure --llvm-root=path/to/nowhere + - ./configure --enable-ccache script: - make tidy + - make rustc-stage1 -j4 + +env: + - CXX=/usr/bin/g++-4.7 + +addons: + apt: + sources: + - ubuntu-toolchain-r-test + packages: + - gcc-4.7 + - g++-4.7 # Real testing happens on http://buildbot.rust-lang.org/ # diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 16113a32d2448..22a23de070780 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -133,8 +133,8 @@ Documentation improvements are very welcome. The source of `doc.rust-lang.org` is located in `src/doc` in the tree, and standard API documentation is generated from the source code itself. -Documentation pull requests function in the same as other pull requests, though -you may see a slightly different form of `r+`: +Documentation pull requests function in the same way as other pull requests, +though you may see a slightly different form of `r+`: @bors: r+ 38fe8d2 rollup diff --git a/RELEASES.md b/RELEASES.md index 636bcc4312eb8..db1c7380a788b 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -28,6 +28,9 @@ Breaking Changes in, and the same value reported by clang's `alignof`. [`mem::min_align_of`] is deprecated. This is not known to break real code. +* [The `#[packed]` attribute is no longer silently accepted by the + compiler][packed]. This attribute did nothing and code that + mentioned it likely did not work as intended. Language -------- @@ -140,7 +143,7 @@ Misc [fat]: https://github.com/rust-lang/rust/pull/26411 [dst]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md [parcodegen]: https://github.com/rust-lang/rust/pull/26018 - +[packed]: https://github.com/rust-lang/rust/pull/25541 Version 1.1.0 (June 2015) ========================= diff --git a/configure b/configure index 9be2f9b91f0a3..3d04cf7519ed4 100755 --- a/configure +++ b/configure @@ -1031,15 +1031,12 @@ fi if [ ! -z "$CFG_ENABLE_CCACHE" ] then - if [ -z "$CC" ] + if [ -z "$CFG_CCACHE" ] then - if [ -z "$CFG_CCACHE" ] - then - err "ccache requested but not found" - fi - - CFG_CC="ccache $CFG_CC" + err "ccache requested but not found" fi + + CFG_CC="ccache $CFG_CC" fi if [ -z "$CC" -a -z "$CFG_ENABLE_CLANG" -a -z "$CFG_GCC" ] @@ -1528,11 +1525,26 @@ do (*) msg "inferring LLVM_CXX/CC from CXX/CC = $CXX/$CC" - LLVM_CXX_32="$CXX" - LLVM_CC_32="$CC" + if [ ! -z "$CFG_ENABLE_CCACHE" ] + then + if [ -z "$CFG_CCACHE" ] + then + err "ccache requested but not found" + fi + + LLVM_CXX_32="ccache $CXX" + LLVM_CC_32="ccache $CC" + + LLVM_CXX_64="ccache $CXX" + LLVM_CC_64="ccache $CC" + else + LLVM_CXX_32="$CXX" + LLVM_CC_32="$CC" + + LLVM_CXX_64="$CXX" + LLVM_CC_64="$CC" + fi - LLVM_CXX_64="$CXX" - LLVM_CC_64="$CC" ;; esac diff --git a/src/doc/reference.md b/src/doc/reference.md index 060f954274a9d..a37e1c146681e 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -343,10 +343,10 @@ The type of an _unsuffixed_ integer literal is determined by type inference: * If an integer type can be _uniquely_ determined from the surrounding program context, the unsuffixed integer literal has that type. -* If the program context underconstrains the type, it defaults to the +* If the program context under-constrains the type, it defaults to the signed 32-bit integer `i32`. -* If the program context overconstrains the type, it is considered a +* If the program context over-constrains the type, it is considered a static type error. Examples of integer literals of various forms: @@ -382,9 +382,9 @@ type inference: surrounding program context, the unsuffixed floating-point literal has that type. -* If the program context underconstrains the type, it defaults to `f64`. +* If the program context under-constrains the type, it defaults to `f64`. -* If the program context overconstrains the type, it is considered a +* If the program context over-constrains the type, it is considered a static type error. Examples of floating-point literals of various forms: @@ -1292,7 +1292,7 @@ All access to a static is safe, but there are a number of restrictions on statics: * Statics may not contain any destructors. -* The types of static values must ascribe to `Sync` to allow threadsafe access. +* The types of static values must ascribe to `Sync` to allow thread-safe access. * Statics may not refer to other statics by value, only by reference. * Constants cannot refer to statics. @@ -1694,7 +1694,7 @@ explain, here's a few use cases and what they would entail: * A crate needs a global available "helper module" to itself, but it doesn't want to expose the helper module as a public API. To accomplish this, the root of the crate's hierarchy would have a private module which then - internally has a "public api". Because the entire crate is a descendant of + internally has a "public API". Because the entire crate is a descendant of the root, then the entire local crate can access this private module through the second case. @@ -1957,8 +1957,6 @@ macro scope. object file that this item's contents will be placed into. - `no_mangle` - on any item, do not apply the standard name mangling. Set the symbol for this item to its identifier. -- `packed` - on structs or enums, eliminate any padding that would be used to - align fields. - `simd` - on certain tuple structs, derive the arithmetic operators, which lower to the target's SIMD instructions, if any; the `simd` feature gate is necessary to use this attribute. @@ -3663,47 +3661,71 @@ sites are: * `let` statements where an explicit type is given. - In `let _: U = e;`, `e` is coerced to have type `U`. + For example, `128` is coerced to have type `i8` in the following: + + ```rust + let _: i8 = 128; + ``` * `static` and `const` statements (similar to `let` statements). -* arguments for function calls. +* Arguments for function calls + + The value being coerced is the actual parameter, and it is coerced to + the type of the formal parameter. + + For example, `128` is coerced to have type `i8` in the following: + + ```rust + fn bar(_: i8) { } - The value being coerced is the - actual parameter and it is coerced to the type of the formal parameter. For - example, let `foo` be defined as `fn foo(x: U) { ... }` and call it as - `foo(e);`. Then `e` is coerced to have type `U`; + fn main() { + bar(128); + } + ``` -* instantiations of struct or variant fields. +* Instantiations of struct or variant fields - Assume we have a `struct - Foo { x: U }` and instantiate it as `Foo { x: e }`. Then `e` is coerced to - have type `U`. + For example, `128` is coerced to have type `i8` in the following: -* function results (either the final line of a block if it is not semicolon -terminated or any expression in a `return` statement). + ```rust + struct Foo { x: i8 } - In `fn foo() -> U { e }`, `e` is coerced to to have type `U`. + fn main() { + Foo { x: 128 }; + } + ``` + +* Function results, either the final line of a block if it is not + semicolon-terminated or any expression in a `return` statement + + For example, `128` is coerced to have type `i8` in the following: + + ```rust + fn foo() -> i8 { + 128 + } + ``` If the expression in one of these coercion sites is a coercion-propagating expression, then the relevant sub-expressions in that expression are also coercion sites. Propagation recurses from these new coercion sites. Propagating expressions and their relevant sub-expressions are: -* array literals, where the array has type `[U; n]`. Each sub-expression in +* Array literals, where the array has type `[U; n]`. Each sub-expression in the array literal is a coercion site for coercion to type `U`. -* array literals with repeating syntax, where the array has type `[U; n]`. The +* Array literals with repeating syntax, where the array has type `[U; n]`. The repeated sub-expression is a coercion site for coercion to type `U`. -* tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`. +* Tuples, where a tuple is a coercion site to type `(U_0, U_1, ..., U_n)`. Each sub-expression is a coercion site to the respective type, e.g. the zeroth sub-expression is a coercion site to type `U_0`. -* parenthesised sub-expressions (`(e)`). If the expression has type `U`, then +* Parenthesised sub-expressions (`(e)`): if the expression has type `U`, then the sub-expression is a coercion site to `U`. -* blocks. If a block has type `U`, then the last expression in the block (if +* Blocks: if a block has type `U`, then the last expression in the block (if it is not semicolon-terminated) is a coercion site to `U`. This includes blocks which are part of control flow statements, such as `if`/`else`, if the block has a known type. @@ -3712,45 +3734,46 @@ the block has a known type. Coercion is allowed between the following types: -* `T` to `U` if `T` is a subtype of `U` (*reflexive case*). +* `T` to `U` if `T` is a subtype of `U` (*reflexive case*) * `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3` -(*transitive case*). +(*transitive case*) Note that this is not fully supported yet -* `&mut T` to `&T`. +* `&mut T` to `&T` -* `*mut T` to `*const T`. +* `*mut T` to `*const T` -* `&T` to `*const T`. +* `&T` to `*const T` -* `&mut T` to `*mut T`. +* `&mut T` to `*mut T` * `&T` to `&U` if `T` implements `Deref`. For example: -```rust -use std::ops::Deref; + ```rust + use std::ops::Deref; -struct CharContainer { - value: char -} + struct CharContainer { + value: char + } -impl Deref for CharContainer { - type Target = char; + impl Deref for CharContainer { + type Target = char; - fn deref<'a>(&'a self) -> &'a char { - &self.value - } -} + fn deref<'a>(&'a self) -> &'a char { + &self.value + } + } -fn foo(arg: &char) {} + fn foo(arg: &char) {} + + fn main() { + let x = &mut CharContainer { value: 'y' }; + foo(x); //&mut CharContainer is coerced to &char. + } + ``` -fn main() { - let x = &mut CharContainer { value: 'y' }; - foo(x); //&mut CharContainer is coerced to &char. -} -``` * `&mut T` to `&mut U` if `T` implements `DerefMut`. * TyCtor(`T`) to TyCtor(coerce_inner(`T`)), where TyCtor(`T`) is one of @@ -3964,7 +3987,7 @@ In general, `--crate-type=bin` or `--crate-type=lib` should be sufficient for all compilation needs, and the other options are just available if more fine-grained control is desired over the output format of a Rust crate. -# Appendix: Rationales and design tradeoffs +# Appendix: Rationales and design trade-offs *TODO*. @@ -3974,7 +3997,7 @@ Rust is not a particularly original language, with design elements coming from a wide range of sources. Some of these are listed below (including elements that have since been removed): -* SML, OCaml: algebraic datatypes, pattern matching, type inference, +* SML, OCaml: algebraic data types, pattern matching, type inference, semicolon statement separation * C++: references, RAII, smart pointers, move semantics, monomorphisation, memory model diff --git a/src/doc/trpl/error-handling.md b/src/doc/trpl/error-handling.md index 580eaa6ca5571..8dd5a3650ef52 100644 --- a/src/doc/trpl/error-handling.md +++ b/src/doc/trpl/error-handling.md @@ -50,6 +50,8 @@ is very wrong. Wrong enough that we can't continue with things in the current state. Another example is using the `unreachable!()` macro: ```rust,ignore +use Event::NewRelease; + enum Event { NewRelease, } @@ -71,7 +73,7 @@ fn descriptive_probability(event: Event) -> &'static str { } fn main() { - std::io::println(descriptive_probability(NewRelease)); + println!("{}", descriptive_probability(NewRelease)); } ``` diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md index 2c5f5927fd15a..ff81590cc03b9 100644 --- a/src/doc/trpl/the-stack-and-the-heap.md +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -176,7 +176,7 @@ After `bar()` is over, its frame is deallocated, leaving just `foo()` and | 1 | a | 5 | | 0 | x | 42 | -And then `foo()` ends, leaving just `main()` +And then `foo()` ends, leaving just `main()`: | Address | Name | Value | |---------|------|-------| @@ -537,7 +537,7 @@ Generally, you should prefer stack allocation, and so, Rust stack-allocates by default. The LIFO model of the stack is simpler, at a fundamental level. This has two big impacts: runtime efficiency and semantic impact. -## Runtime Efficiency. +## Runtime Efficiency Managing the memory for the stack is trivial: The machine just increments or decrements a single value, the so-called “stack pointer”. diff --git a/src/libcore/hash/sip.rs b/src/libcore/hash/sip.rs index a92b72e0f00fa..d26e9ab707205 100644 --- a/src/libcore/hash/sip.rs +++ b/src/libcore/hash/sip.rs @@ -10,8 +10,6 @@ //! An implementation of SipHash 2-4. -#![allow(deprecated)] // until the next snapshot for inherent wrapping ops - use prelude::*; use super::Hasher; diff --git a/src/libcoretest/hash/mod.rs b/src/libcoretest/hash/mod.rs index 5c11f0196aeb8..697c3ee254b98 100644 --- a/src/libcoretest/hash/mod.rs +++ b/src/libcoretest/hash/mod.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +mod sip; + use std::mem; use std::hash::{Hash, Hasher}; use std::default::Default; diff --git a/src/libcoretest/hash/sip.rs b/src/libcoretest/hash/sip.rs index 8289d06d04c61..7832985d3f1c1 100644 --- a/src/libcoretest/hash/sip.rs +++ b/src/libcoretest/hash/sip.rs @@ -8,28 +8,55 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. use test::Bencher; -use std::prelude::*; -use std::fmt; -use str::Str; -use string::String; -use slice::{AsSlice, SlicePrelude}; -use vec::Vec; - -use core::hash::{Hash, Writer}; -use core::hash::sip::{SipState, hash, hash_with_keys}; +use core::hash::{Hash, Hasher}; +use core::hash::SipHasher; // Hash just the bytes of the slice, without length prefix struct Bytes<'a>(&'a [u8]); -impl<'a, S: Writer> Hash for Bytes<'a> { +impl<'a> Hash for Bytes<'a> { #[allow(unused_must_use)] - fn hash(&self, state: &mut S) { + fn hash(&self, state: &mut H) { let Bytes(v) = *self; state.write(v); } } +macro_rules! u8to64_le { + ($buf:expr, $i:expr) => + ($buf[0+$i] as u64 | + ($buf[1+$i] as u64) << 8 | + ($buf[2+$i] as u64) << 16 | + ($buf[3+$i] as u64) << 24 | + ($buf[4+$i] as u64) << 32 | + ($buf[5+$i] as u64) << 40 | + ($buf[6+$i] as u64) << 48 | + ($buf[7+$i] as u64) << 56); + ($buf:expr, $i:expr, $len:expr) => + ({ + let mut t = 0; + let mut out = 0; + while t < $len { + out |= ($buf[t+$i] as u64) << t*8; + t += 1; + } + out + }); +} + +fn hash(x: &T) -> u64 { + let mut st = SipHasher::new(); + x.hash(&mut st); + st.finish() +} + +fn hash_with_keys(k1: u64, k2: u64, x: &T) -> u64 { + let mut st = SipHasher::new_with_keys(k1, k2); + x.hash(&mut st); + st.finish() +} + #[test] #[allow(unused_must_use)] fn test_siphash() { @@ -104,79 +131,43 @@ fn test_siphash() { let k1 = 0x_0f_0e_0d_0c_0b_0a_09_08; let mut buf = Vec::new(); let mut t = 0; - let mut state_inc = SipState::new_with_keys(k0, k1); - let mut state_full = SipState::new_with_keys(k0, k1); - - fn to_hex_str(r: &[u8; 8]) -> String { - let mut s = String::new(); - for b in r { - s.push_str(format!("{}", fmt::radix(*b, 16))); - } - s - } - - fn result_bytes(h: u64) -> Vec { - vec![(h >> 0) as u8, - (h >> 8) as u8, - (h >> 16) as u8, - (h >> 24) as u8, - (h >> 32) as u8, - (h >> 40) as u8, - (h >> 48) as u8, - (h >> 56) as u8, - ] - } - - fn result_str(h: u64) -> String { - let r = result_bytes(h); - let mut s = String::new(); - for b in &r { - s.push_str(format!("{}", fmt::radix(*b, 16))); - } - s - } + let mut state_inc = SipHasher::new_with_keys(k0, k1); while t < 64 { - debug!("siphash test {}: {}", t, buf); let vec = u8to64_le!(vecs[t], 0); - let out = hash_with_keys(k0, k1, &Bytes(buf)); - debug!("got {}, expected {}", out, vec); + let out = hash_with_keys(k0, k1, &Bytes(&buf)); assert_eq!(vec, out); - state_full.reset(); - state_full.write(buf); - let f = result_str(state_full.result()); - let i = result_str(state_inc.result()); - let v = to_hex_str(&vecs[t]); - debug!("{}: ({}) => inc={} full={}", t, v, i, f); + let full = hash_with_keys(k0, k1, &Bytes(&buf)); + let i = state_inc.finish(); - assert_eq!(f, i); - assert_eq!(f, v); + assert_eq!(full, i); + assert_eq!(full, vec); buf.push(t as u8); - state_inc.write(&[t as u8]); + Hasher::write(&mut state_inc, &[t as u8]); t += 1; } } #[test] #[cfg(target_arch = "arm")] -fn test_hash_uint() { +fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); + assert!(hash(&(val as u64)) != hash(&(val as usize))); + assert_eq!(hash(&(val as u32)), hash(&(val as usize))); } #[test] #[cfg(target_arch = "x86_64")] -fn test_hash_uint() { +fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; - assert_eq!(hash(&(val as u64)), hash(&(val as uint))); - assert!(hash(&(val as u32)) != hash(&(val as uint))); + assert_eq!(hash(&(val as u64)), hash(&(val as usize))); + assert!(hash(&(val as u32)) != hash(&(val as usize))); } #[test] #[cfg(target_arch = "x86")] -fn test_hash_uint() { +fn test_hash_usize() { let val = 0xdeadbeef_deadbeef_u64; - assert!(hash(&(val as u64)) != hash(&(val as uint))); - assert_eq!(hash(&(val as u32)), hash(&(val as uint))); + assert!(hash(&(val as u64)) != hash(&(val as usize))); + assert_eq!(hash(&(val as u32)), hash(&(val as usize))); } #[test] @@ -200,7 +191,7 @@ fn test_hash_no_bytes_dropped_64() { assert!(hash(&val) != hash(&zero_byte(val, 6))); assert!(hash(&val) != hash(&zero_byte(val, 7))); - fn zero_byte(val: u64, byte: uint) -> u64 { + fn zero_byte(val: u64, byte: usize) -> u64 { assert!(byte < 8); val & !(0xff << (byte * 8)) } @@ -215,7 +206,7 @@ fn test_hash_no_bytes_dropped_32() { assert!(hash(&val) != hash(&zero_byte(val, 2))); assert!(hash(&val) != hash(&zero_byte(val, 3))); - fn zero_byte(val: u32, byte: uint) -> u32 { + fn zero_byte(val: u32, byte: usize) -> u32 { assert!(byte < 4); val & !(0xff << (byte * 8)) } @@ -230,8 +221,9 @@ fn test_hash_no_concat_alias() { assert!(s != t && t != u); assert!(hash(&s) != hash(&t) && hash(&s) != hash(&u)); - let v: (&[u8], &[u8], &[u8]) = (&[1], &[0, 0], &[0]); - let w: (&[u8], &[u8], &[u8]) = (&[1, 0, 0, 0], &[], &[]); + let u = [1, 0, 0, 0]; + let v = (&u[..1], &u[1..3], &u[3..]); + let w = (&u[..], &u[4..4], &u[4..4]); assert!(v != w); assert!(hash(&v) != hash(&w)); diff --git a/src/librustc/ast_map/mod.rs b/src/librustc/ast_map/mod.rs index 3205141e604c2..5c10cc6aaa8db 100644 --- a/src/librustc/ast_map/mod.rs +++ b/src/librustc/ast_map/mod.rs @@ -411,6 +411,13 @@ impl<'ast> Map<'ast> { } } + pub fn expect_trait_item(&self, id: NodeId) -> &'ast TraitItem { + match self.find(id) { + Some(NodeTraitItem(item)) => item, + _ => panic!("expected trait item, found {}", self.node_to_string(id)) + } + } + pub fn expect_struct(&self, id: NodeId) -> &'ast StructDef { match self.find(id) { Some(NodeItem(i)) => { diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 9aa5daa3a0a27..4b77c211df983 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -972,16 +972,16 @@ Updates to the borrow checker in a future version of Rust may remove this restriction, but for now patterns must be rewritten without sub-bindings. ``` -// Code like this... -match Some(5) { - ref op_num @ Some(num) => ... +// Before. +match Some("hi".to_string()) { + ref op_string_ref @ Some(ref s) => ... None => ... } // After. match Some("hi".to_string()) { Some(ref s) => { - let op_string_ref = &Some(&s); + let op_string_ref = &Some(s); ... } None => ... diff --git a/src/librustc/middle/infer/higher_ranked/README.md b/src/librustc/middle/infer/higher_ranked/README.md index 3414c7515a374..57665b6d93923 100644 --- a/src/librustc/middle/infer/higher_ranked/README.md +++ b/src/librustc/middle/infer/higher_ranked/README.md @@ -17,7 +17,7 @@ The problem we are addressing is that there is a kind of subtyping between functions with bound region parameters. Consider, for example, whether the following relation holds: - for<'a> fn(&'a int) <: for<'b> fn(&'b int)? (Yes, a => b) + for<'a> fn(&'a isize) <: for<'b> fn(&'b isize)? (Yes, a => b) The answer is that of course it does. These two types are basically the same, except that in one we used the name `a` and one we used @@ -27,14 +27,14 @@ In the examples that follow, it becomes very important to know whether a lifetime is bound in a function type (that is, is a lifetime parameter) or appears free (is defined in some outer scope). Therefore, from now on I will always write the bindings explicitly, -using the Rust syntax `for<'a> fn(&'a int)` to indicate that `a` is a +using the Rust syntax `for<'a> fn(&'a isize)` to indicate that `a` is a lifetime parameter. Now let's consider two more function types. Here, we assume that the `'b` lifetime is defined somewhere outside and hence is not a lifetime parameter bound by the function type (it "appears free"): - for<'a> fn(&'a int) <: fn(&'b int)? (Yes, a => b) + for<'a> fn(&'a isize) <: fn(&'b isize)? (Yes, a => b) This subtyping relation does in fact hold. To see why, you have to consider what subtyping means. One way to look at `T1 <: T2` is to @@ -51,7 +51,7 @@ to the same thing: a function that accepts pointers with any lifetime So, what if we reverse the order of the two function types, like this: - fn(&'b int) <: for<'a> fn(&'a int)? (No) + fn(&'b isize) <: for<'a> fn(&'a isize)? (No) Does the subtyping relationship still hold? The answer of course is no. In this case, the function accepts *only the lifetime `'b`*, @@ -60,8 +60,8 @@ accepted any lifetime. What about these two examples: - for<'a,'b> fn(&'a int, &'b int) <: for<'a> fn(&'a int, &'a int)? (Yes) - for<'a> fn(&'a int, &'a int) <: for<'a,'b> fn(&'a int, &'b int)? (No) + for<'a,'b> fn(&'a isize, &'b isize) <: for<'a> fn(&'a isize, &'a isize)? (Yes) + for<'a> fn(&'a isize, &'a isize) <: for<'a,'b> fn(&'a isize, &'b isize)? (No) Here, it is true that functions which take two pointers with any two lifetimes can be treated as if they only accepted two pointers with diff --git a/src/librustc/middle/infer/region_inference/README.md b/src/librustc/middle/infer/region_inference/README.md index e44211da4a7bb..2dc16d4fa1dd4 100644 --- a/src/librustc/middle/infer/region_inference/README.md +++ b/src/librustc/middle/infer/region_inference/README.md @@ -121,7 +121,7 @@ every expression, block, and pattern (patterns are considered to "execute" by testing the value they are applied to and creating any relevant bindings). So, for example: - fn foo(x: int, y: int) { // -+ + fn foo(x: isize, y: isize) { // -+ // +------------+ // | // | +-----+ // | // | +-+ +-+ +-+ // | @@ -168,13 +168,13 @@ an error. Here is a more involved example (which is safe) so we can see what's going on: - struct Foo { f: uint, g: uint } + struct Foo { f: usize, g: usize } ... - fn add(p: &mut uint, v: uint) { + fn add(p: &mut usize, v: usize) { *p += v; } ... - fn inc(p: &mut uint) -> uint { + fn inc(p: &mut usize) -> usize { *p += 1; *p } fn weird() { @@ -199,8 +199,8 @@ in a call expression: 'a: { 'a_arg1: let a_temp1: ... = add; - 'a_arg2: let a_temp2: &'a mut uint = &'a mut (*x).f; - 'a_arg3: let a_temp3: uint = { + 'a_arg2: let a_temp2: &'a mut usize = &'a mut (*x).f; + 'a_arg3: let a_temp3: usize = { let b_temp1: ... = inc; let b_temp2: &'b = &'b mut (*x).f; 'b_call: b_temp1(b_temp2) @@ -225,13 +225,13 @@ it will not be *dereferenced* during the evaluation of the second argument, it can still be *invalidated* by that evaluation. Consider this similar but unsound example: - struct Foo { f: uint, g: uint } + struct Foo { f: usize, g: usize } ... - fn add(p: &mut uint, v: uint) { + fn add(p: &mut usize, v: usize) { *p += v; } ... - fn consume(x: Box) -> uint { + fn consume(x: Box) -> usize { x.f + x.g } fn weird() { diff --git a/src/librustc/middle/traits/README.md b/src/librustc/middle/traits/README.md index 853d12172af5e..92982af92dcfe 100644 --- a/src/librustc/middle/traits/README.md +++ b/src/librustc/middle/traits/README.md @@ -12,10 +12,10 @@ reference to a trait. So, for example, if there is a generic function like: and then a call to that function: - let v: Vec = clone_slice([1, 2, 3]) + let v: Vec = clone_slice([1, 2, 3]) it is the job of trait resolution to figure out (in which case) -whether there exists an impl of `int : Clone` +whether there exists an impl of `isize : Clone` Note that in some cases, like generic functions, we may not be able to find a specific impl, but we can figure out that the caller must @@ -115,27 +115,27 @@ trait Convert { This trait just has one method. It's about as simple as it gets. It converts from the (implicit) `Self` type to the `Target` type. If we -wanted to permit conversion between `int` and `uint`, we might +wanted to permit conversion between `isize` and `usize`, we might implement `Convert` like so: ```rust -impl Convert for int { ... } // int -> uint -impl Convert for uint { ... } // uint -> int +impl Convert for isize { ... } // isize -> usize +impl Convert for usize { ... } // usize -> isize ``` Now imagine there is some code like the following: ```rust -let x: int = ...; +let x: isize = ...; let y = x.convert(); ``` The call to convert will generate a trait reference `Convert<$Y> for -int`, where `$Y` is the type variable representing the type of +isize`, where `$Y` is the type variable representing the type of `y`. When we match this against the two impls we can see, we will find -that only one remains: `Convert for int`. Therefore, we can +that only one remains: `Convert for isize`. Therefore, we can select this impl, which will cause the type of `$Y` to be unified to -`uint`. (Note that while assembling candidates, we do the initial +`usize`. (Note that while assembling candidates, we do the initial unifications in a transaction, so that they don't affect one another.) There are tests to this effect in src/test/run-pass: @@ -225,7 +225,7 @@ Confirmation unifies the output type parameters of the trait with the values found in the obligation, possibly yielding a type error. If we return to our example of the `Convert` trait from the previous section, confirmation is where an error would be reported, because the -impl specified that `T` would be `uint`, but the obligation reported +impl specified that `T` would be `usize`, but the obligation reported `char`. Hence the result of selection would be an error. ### Selection during translation @@ -250,12 +250,12 @@ Here is an example: trait Foo { ... } impl> Foo for Vec { ... } - impl Bar for int { ... } + impl Bar for isize { ... } -After one shallow round of selection for an obligation like `Vec +After one shallow round of selection for an obligation like `Vec : Foo`, we would know which impl we want, and we would know that -`T=int`, but we do not know the type of `U`. We must select the -nested obligation `int : Bar` to find out that `U=uint`. +`T=isize`, but we do not know the type of `U`. We must select the +nested obligation `isize : Bar` to find out that `U=usize`. It would be good to only do *just as much* nested resolution as necessary. Currently, though, we just do a full resolution. @@ -263,7 +263,7 @@ necessary. Currently, though, we just do a full resolution. # Higher-ranked trait bounds One of the more subtle concepts at work are *higher-ranked trait -bounds*. An example of such a bound is `for<'a> MyTrait<&'a int>`. +bounds*. An example of such a bound is `for<'a> MyTrait<&'a isize>`. Let's walk through how selection on higher-ranked trait references works. @@ -279,21 +279,21 @@ trait Foo { ``` Let's say we have a function `want_hrtb` that wants a type which -implements `Foo<&'a int>` for any `'a`: +implements `Foo<&'a isize>` for any `'a`: ```rust -fn want_hrtb() where T : for<'a> Foo<&'a int> { ... } +fn want_hrtb() where T : for<'a> Foo<&'a isize> { ... } ``` -Now we have a struct `AnyInt` that implements `Foo<&'a int>` for any +Now we have a struct `AnyInt` that implements `Foo<&'a isize>` for any `'a`: ```rust struct AnyInt; -impl<'a> Foo<&'a int> for AnyInt { } +impl<'a> Foo<&'a isize> for AnyInt { } ``` -And the question is, does `AnyInt : for<'a> Foo<&'a int>`? We want the +And the question is, does `AnyInt : for<'a> Foo<&'a isize>`? We want the answer to be yes. The algorithm for figuring it out is closely related to the subtyping for higher-ranked types (which is described in `middle::infer::higher_ranked::doc`, but also in a [paper by SPJ] that @@ -306,12 +306,12 @@ I recommend you read). [paper by SPJ]: http://research.microsoft.com/en-us/um/people/simonpj/papers/higher-rank/ So let's work through our example. The first thing we would do is to -skolemize the obligation, yielding `AnyInt : Foo<&'0 int>` (here `'0` +skolemize the obligation, yielding `AnyInt : Foo<&'0 isize>` (here `'0` represents skolemized region #0). Note that now have no quantifiers; in terms of the compiler type, this changes from a `ty::PolyTraitRef` to a `TraitRef`. We would then create the `TraitRef` from the impl, using fresh variables for it's bound regions (and thus getting -`Foo<&'$a int>`, where `'$a` is the inference variable for `'a`). Next +`Foo<&'$a isize>`, where `'$a` is the inference variable for `'a`). Next we relate the two trait refs, yielding a graph with the constraint that `'0 == '$a`. Finally, we check for skolemization "leaks" -- a leak is basically any attempt to relate a skolemized region to another @@ -327,13 +327,13 @@ Let's consider a failure case. Imagine we also have a struct ```rust struct StaticInt; -impl Foo<&'static int> for StaticInt; +impl Foo<&'static isize> for StaticInt; ``` -We want the obligation `StaticInt : for<'a> Foo<&'a int>` to be +We want the obligation `StaticInt : for<'a> Foo<&'a isize>` to be considered unsatisfied. The check begins just as before. `'a` is skolemized to `'0` and the impl trait reference is instantiated to -`Foo<&'static int>`. When we relate those two, we get a constraint +`Foo<&'static isize>`. When we relate those two, we get a constraint like `'static == '0`. This means that the taint set for `'0` is `{'0, 'static}`, which fails the leak check. @@ -358,13 +358,13 @@ impl Foo for F } ``` -Now let's say we have a obligation `for<'a> Foo<&'a int>` and we match +Now let's say we have a obligation `for<'a> Foo<&'a isize>` and we match this impl. What obligation is generated as a result? We want to get -`for<'a> Bar<&'a int>`, but how does that happen? +`for<'a> Bar<&'a isize>`, but how does that happen? After the matching, we are in a position where we have a skolemized -substitution like `X => &'0 int`. If we apply this substitution to the -impl obligations, we get `F : Bar<&'0 int>`. Obviously this is not +substitution like `X => &'0 isize`. If we apply this substitution to the +impl obligations, we get `F : Bar<&'0 isize>`. Obviously this is not directly usable because the skolemized region `'0` cannot leak out of our computation. @@ -375,7 +375,7 @@ leak check passed, so this taint set consists solely of the skolemized region itself plus various intermediate region variables. We then walk the trait-reference and convert every region in that taint set back to a late-bound region, so in this case we'd wind up with `for<'a> F : -Bar<&'a int>`. +Bar<&'a isize>`. # Caching and subtle considerations therewith @@ -391,8 +391,8 @@ but *replay* its effects on the type variables. The high-level idea of how the cache works is that we first replace all unbound inference variables with skolemized versions. Therefore, -if we had a trait reference `uint : Foo<$1>`, where `$n` is an unbound -inference variable, we might replace it with `uint : Foo<%0>`, where +if we had a trait reference `usize : Foo<$1>`, where `$n` is an unbound +inference variable, we might replace it with `usize : Foo<%0>`, where `%n` is a skolemized type. We would then look this up in the cache. If we found a hit, the hit would tell us the immediate next step to take in the selection process: i.e., apply impl #22, or apply where @@ -401,17 +401,17 @@ Therefore, we search through impls and where clauses and so forth, and we come to the conclusion that the only possible impl is this one, with def-id 22: - impl Foo for uint { ... } // Impl #22 + impl Foo for usize { ... } // Impl #22 -We would then record in the cache `uint : Foo<%0> ==> +We would then record in the cache `usize : Foo<%0> ==> ImplCandidate(22)`. Next we would confirm `ImplCandidate(22)`, which -would (as a side-effect) unify `$1` with `int`. +would (as a side-effect) unify `$1` with `isize`. -Now, at some later time, we might come along and see a `uint : -Foo<$3>`. When skolemized, this would yield `uint : Foo<%0>`, just as +Now, at some later time, we might come along and see a `usize : +Foo<$3>`. When skolemized, this would yield `usize : Foo<%0>`, just as before, and hence the cache lookup would succeed, yielding `ImplCandidate(22)`. We would confirm `ImplCandidate(22)` which would -(as a side-effect) unify `$3` with `int`. +(as a side-effect) unify `$3` with `isize`. ## Where clauses and the local vs global cache diff --git a/src/librustc_borrowck/borrowck/mod.rs b/src/librustc_borrowck/borrowck/mod.rs index 0d475e1257141..8f2e5deb92c7d 100644 --- a/src/librustc_borrowck/borrowck/mod.rs +++ b/src/librustc_borrowck/borrowck/mod.rs @@ -705,8 +705,19 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { ol, moved_lp_msg, pat_ty)); - self.tcx.sess.fileline_help(span, - "use `ref` to override"); + match self.tcx.sess.codemap().span_to_snippet(span) { + Ok(string) => { + self.tcx.sess.span_suggestion( + span, + &format!("if you would like to borrow the value instead, \ + use a `ref` binding as shown:"), + format!("ref {}", string)); + }, + Err(_) => { + self.tcx.sess.fileline_help(span, + "use `ref` to override"); + }, + } } move_data::Captured => { diff --git a/src/librustc_driver/lib.rs b/src/librustc_driver/lib.rs index 2906fd35a0a18..873950b0be893 100644 --- a/src/librustc_driver/lib.rs +++ b/src/librustc_driver/lib.rs @@ -202,20 +202,24 @@ pub trait CompilerCalls<'a> { // be called straight after options have been parsed but before anything // else (e.g., selecting input and output). fn early_callback(&mut self, - &getopts::Matches, - &diagnostics::registry::Registry) - -> Compilation; + _: &getopts::Matches, + _: &diagnostics::registry::Registry) + -> Compilation { + Compilation::Continue + } // Hook for a callback late in the process of handling arguments. This will // be called just before actual compilation starts (and before build_controller // is called), after all arguments etc. have been completely handled. fn late_callback(&mut self, - &getopts::Matches, - &Session, - &Input, - &Option, - &Option) - -> Compilation; + _: &getopts::Matches, + _: &Session, + _: &Input, + _: &Option, + _: &Option) + -> Compilation { + Compilation::Continue + } // Called after we extract the input from the arguments. Gives the implementer // an opportunity to change the inputs or to add some custom input handling. @@ -231,12 +235,14 @@ pub trait CompilerCalls<'a> { // emitting error messages. Returning None will cause compilation to stop // at this point. fn no_input(&mut self, - &getopts::Matches, - &config::Options, - &Option, - &Option, - &diagnostics::registry::Registry) - -> Option<(Input, Option)>; + _: &getopts::Matches, + _: &config::Options, + _: &Option, + _: &Option, + _: &diagnostics::registry::Registry) + -> Option<(Input, Option)> { + None + } // Parse pretty printing information from the arguments. The implementer can // choose to ignore this (the default will return None) which will skip pretty diff --git a/src/librustc_resolve/build_reduced_graph.rs b/src/librustc_resolve/build_reduced_graph.rs index dd26fd25215a3..aa7f93776da22 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/src/librustc_resolve/build_reduced_graph.rs @@ -26,6 +26,7 @@ use ParentLink::{self, ModuleParentLink, BlockParentLink}; use Resolver; use resolve_imports::Shadowable; use TypeNsDef; +use {resolve_error, ResolutionError}; use self::DuplicateCheckingMode::*; use self::NamespaceError::*; @@ -208,10 +209,13 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { // Return an error here by looking up the namespace that // had the duplicate. let ns = ns.unwrap(); - self.resolve_error(sp, - &format!("duplicate definition of {} `{}`", - namespace_error_to_string(duplicate_type), - token::get_name(name))); + resolve_error( + self, + sp, + ResolutionError::DuplicateDefinition( + namespace_error_to_string(duplicate_type), + name) + ); { let r = child.span_for_namespace(ns); if let Some(sp) = r { @@ -304,8 +308,10 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { full_path.segments.last().unwrap().identifier.name; if &token::get_name(source_name)[..] == "mod" || &token::get_name(source_name)[..] == "self" { - self.resolve_error(view_path.span, - "`self` imports are only allowed within a { } list"); + resolve_error(self, + view_path.span, + ResolutionError::SelfImportsOnlyAllowedWithin + ); } let subclass = SingleImport(binding.name, @@ -325,8 +331,11 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { _ => None }).collect::>(); if mod_spans.len() > 1 { - self.resolve_error(mod_spans[0], - "`self` import can only appear once in the list"); + resolve_error( + self, + mod_spans[0], + ResolutionError::SelfImportCanOnlyAppearOnceInTheList + ); for other_span in mod_spans.iter().skip(1) { self.session.span_note(*other_span, "another `self` import appears here"); @@ -341,9 +350,12 @@ impl<'a, 'b:'a, 'tcx:'b> GraphBuilder<'a, 'b, 'tcx> { let name = match module_path.last() { Some(name) => *name, None => { - self.resolve_error(source_item.span, - "`self` import can only appear in an import list \ - with a non-empty prefix"); + resolve_error( + self, + source_item.span, + ResolutionError:: + SelfImportOnlyInImportListWithNonEmptyPrefix + ); continue; } }; diff --git a/src/librustc_resolve/diagnostics.rs b/src/librustc_resolve/diagnostics.rs index 15ddcbc80749c..939991da20307 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/src/librustc_resolve/diagnostics.rs @@ -202,12 +202,52 @@ http://doc.rust-lang.org/reference.html#types } register_diagnostics! { - E0157, - E0153, + E0153, // called no where + E0157, // called from no where E0253, // not directly importable E0254, // import conflicts with imported crate in this module E0257, E0258, E0364, // item is private - E0365 // item is private + E0365, // item is private + E0401, // can't use type parameters from outer function + E0402, // cannot use an outer type parameter in this context + E0403, // the name `{}` is already used + E0404, // is not a trait + E0405, // use of undeclared trait name + E0406, // undeclared associated type + E0407, // method is not a member of trait + E0408, // variable from pattern #1 is not bound in pattern # + E0409, // variable is bound with different mode in pattern # than in + // pattern #1 + E0410, // variable from pattern is not bound in pattern 1 + E0411, // use of `Self` outside of an impl or trait + E0412, // use of undeclared + E0413, // declaration of shadows an enum variant or unit-like struct in + // scope + E0414, // only irrefutable patterns allowed here + E0415, // identifier is bound more than once in this parameter list + E0416, // identifier is bound more than once in the same pattern + E0417, // static variables cannot be referenced in a pattern, use a + // `const` instead + E0418, // is not an enum variant, struct or const + E0419, // unresolved enum variant, struct or const + E0420, // is not an associated const + E0421, // unresolved associated const + E0422, // does not name a structure + E0423, // is a struct variant name, but this expression uses it like a + // function name + E0424, // `self` is not available in a static method. + E0425, // unresolved name + E0426, // use of undeclared label + E0427, // cannot use `ref` binding mode with ... + E0428, // duplicate definition of ... + E0429, // `self` imports are only allowed within a { } list + E0430, // `self` import can only appear once in the list + E0431, // `self` import can only appear in an import list with a non-empty + // prefix + E0432, // unresolved import + E0433, // failed to resolve + E0434, // can't capture dynamic environment in a fn item + E0435 // attempt to use a non-constant value in a constant } diff --git a/src/librustc_resolve/lib.rs b/src/librustc_resolve/lib.rs index 1093d2ef31815..e1afc33684ce6 100644 --- a/src/librustc_resolve/lib.rs +++ b/src/librustc_resolve/lib.rs @@ -99,7 +99,6 @@ use std::usize; use resolve_imports::{Target, ImportDirective, ImportResolution}; use resolve_imports::Shadowable; - // NB: This module needs to be declared first so diagnostics are // registered before they are used. pub mod diagnostics; @@ -109,6 +108,262 @@ mod record_exports; mod build_reduced_graph; mod resolve_imports; +pub enum ResolutionError<'a> { + /// error E0401: can't use type parameters from outer function + TypeParametersFromOuterFunction, + /// error E0402: cannot use an outer type parameter in this context + OuterTypeParameterContext, + /// error E0403: the name is already used for a type parameter in this type parameter list + NameAlreadyUsedInTypeParameterList(Name), + /// error E0404: is not a trait + IsNotATrait(&'a str), + /// error E0405: use of undeclared trait name + UndeclaredTraitName(&'a str), + /// error E0406: undeclared associated type + UndeclaredAssociatedType, + /// error E0407: method is not a member of trait + MethodNotMemberOfTrait(Name, &'a str), + /// error E0408: variable `{}` from pattern #1 is not bound in pattern + VariableNotBoundInPattern(Name, usize), + /// error E0409: variable is bound with different mode in pattern #{} than in pattern #1 + VariableBoundWithDifferentMode(Name, usize), + /// error E0410: variable from pattern is not bound in pattern #1 + VariableNotBoundInParentPattern(Name, usize), + /// error E0411: use of `Self` outside of an impl or trait + SelfUsedOutsideImplOrTrait, + /// error E0412: use of undeclared + UseOfUndeclared(&'a str, &'a str), + /// error E0413: declaration shadows an enum variant or unit-like struct in scope + DeclarationShadowsEnumVariantOrUnitLikeStruct(Name), + /// error E0414: only irrefutable patterns allowed here + OnlyIrrefutablePatternsAllowedHere, + /// error E0415: identifier is bound more than once in this parameter list + IdentifierBoundMoreThanOnceInParameterList(&'a str), + /// error E0416: identifier is bound more than once in the same pattern + IdentifierBoundMoreThanOnceInSamePattern(&'a str), + /// error E0417: static variables cannot be referenced in a pattern + StaticVariableReference, + /// error E0418: is not an enum variant, struct or const + NotAnEnumVariantStructOrConst(&'a str), + /// error E0419: unresolved enum variant, struct or const + UnresolvedEnumVariantStructOrConst(&'a str), + /// error E0420: is not an associated const + NotAnAssociatedConst(&'a str), + /// error E0421: unresolved associated const + UnresolvedAssociatedConst(&'a str), + /// error E0422: does not name a struct + DoesNotNameAStruct(&'a str), + /// error E0423: is a struct variant name, but this expression uses it like a function name + StructVariantUsedAsFunction(&'a str), + /// error E0424: `self` is not available in a static method + SelfNotAvailableInStaticMethod, + /// error E0425: unresolved name + UnresolvedName(&'a str, &'a str), + /// error E0426: use of undeclared label + UndeclaredLabel(&'a str), + /// error E0427: cannot use `ref` binding mode with ... + CannotUseRefBindingModeWith(&'a str), + /// error E0428: duplicate definition + DuplicateDefinition(&'a str, Name), + /// error E0429: `self` imports are only allowed within a { } list + SelfImportsOnlyAllowedWithin, + /// error E0430: `self` import can only appear once in the list + SelfImportCanOnlyAppearOnceInTheList, + /// error E0431: `self` import can only appear in an import list with a non-empty prefix + SelfImportOnlyInImportListWithNonEmptyPrefix, + /// error E0432: unresolved import + UnresolvedImport(Option<(&'a str, Option<&'a str>)>), + /// error E0433: failed to resolve + FailedToResolve(&'a str), + /// error E0434: can't capture dynamic environment in a fn item + CannotCaptureDynamicEnvironmentInFnItem, + /// error E0435: attempt to use a non-constant value in a constant + AttemptToUseNonConstantValueInConstant, +} + +fn resolve_error<'b, 'a:'b, 'tcx:'a>(resolver: &'b Resolver<'a, 'tcx>, span: syntax::codemap::Span, + resolution_error: ResolutionError<'b>) { + if !resolver.emit_errors { + return; + } + match resolution_error { + ResolutionError::TypeParametersFromOuterFunction => { + span_err!(resolver.session, span, E0401, "can't use type parameters from \ + outer function; try using a local \ + type parameter instead"); + }, + ResolutionError::OuterTypeParameterContext => { + span_err!(resolver.session, span, E0402, + "cannot use an outer type parameter in this context"); + }, + ResolutionError::NameAlreadyUsedInTypeParameterList(name) => { + span_err!(resolver.session, span, E0403, + "the name `{}` is already used for a type \ + parameter in this type parameter list", name); + }, + ResolutionError::IsNotATrait(name) => { + span_err!(resolver.session, span, E0404, + "`{}` is not a trait", + name); + }, + ResolutionError::UndeclaredTraitName(name) => { + span_err!(resolver.session, span, E0405, + "use of undeclared trait name `{}`", + name); + }, + ResolutionError::UndeclaredAssociatedType => { + span_err!(resolver.session, span, E0406, "undeclared associated type"); + }, + ResolutionError::MethodNotMemberOfTrait(method, trait_) => { + span_err!(resolver.session, span, E0407, + "method `{}` is not a member of trait `{}`", + method, + trait_); + }, + ResolutionError::VariableNotBoundInPattern(variable_name, pattern_number) => { + span_err!(resolver.session, span, E0408, + "variable `{}` from pattern #1 is not bound in pattern #{}", + variable_name, + pattern_number); + }, + ResolutionError::VariableBoundWithDifferentMode(variable_name, pattern_number) => { + span_err!(resolver.session, span, E0409, + "variable `{}` is bound with different \ + mode in pattern #{} than in pattern #1", + variable_name, + pattern_number); + }, + ResolutionError::VariableNotBoundInParentPattern(variable_name, pattern_number) => { + span_err!(resolver.session, span, E0410, + "variable `{}` from pattern #{} is not bound in pattern #1", + variable_name, + pattern_number); + }, + ResolutionError::SelfUsedOutsideImplOrTrait => { + span_err!(resolver.session, span, E0411, "use of `Self` outside of an impl or trait"); + }, + ResolutionError::UseOfUndeclared(kind, name) => { + span_err!(resolver.session, span, E0412, + "use of undeclared {} `{}`", + kind, + name); + }, + ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct(name) => { + span_err!(resolver.session, span, E0413, + "declaration of `{}` shadows an enum variant or unit-like struct in \ + scope", + name); + }, + ResolutionError::OnlyIrrefutablePatternsAllowedHere => { + span_err!(resolver.session, span, E0414, "only irrefutable patterns allowed here"); + }, + ResolutionError::IdentifierBoundMoreThanOnceInParameterList(identifier) => { + span_err!(resolver.session, span, E0415, + "identifier `{}` is bound more than once in this parameter list", + identifier); + }, + ResolutionError::IdentifierBoundMoreThanOnceInSamePattern(identifier) => { + span_err!(resolver.session, span, E0416, + "identifier `{}` is bound more than once in the same pattern", + identifier); + }, + ResolutionError::StaticVariableReference => { + span_err!(resolver.session, span, E0417, "static variables cannot be \ + referenced in a pattern, \ + use a `const` instead"); + }, + ResolutionError::NotAnEnumVariantStructOrConst(name) => { + span_err!(resolver.session, span, E0418, + "`{}` is not an enum variant, struct or const", + name); + }, + ResolutionError::UnresolvedEnumVariantStructOrConst(name) => { + span_err!(resolver.session, span, E0419, + "unresolved enum variant, struct or const `{}`", + name); + }, + ResolutionError::NotAnAssociatedConst(name) => { + span_err!(resolver.session, span, E0420, + "`{}` is not an associated const", + name); + }, + ResolutionError::UnresolvedAssociatedConst(name) => { + span_err!(resolver.session, span, E0421, + "unresolved associated const `{}`", + name); + }, + ResolutionError::DoesNotNameAStruct(name) => { + span_err!(resolver.session, span, E0422, "`{}` does not name a structure", name); + }, + ResolutionError::StructVariantUsedAsFunction(path_name) => { + span_err!(resolver.session, span, E0423, + "`{}` is a struct variant name, but \ + this expression \ + uses it like a function name", + path_name); + }, + ResolutionError::SelfNotAvailableInStaticMethod => { + span_err!(resolver.session, span, E0424, "`self` is not available in a static method. \ + Maybe a `self` argument is missing?"); + }, + ResolutionError::UnresolvedName(path, name) => { + span_err!(resolver.session, span, E0425, + "unresolved name `{}`{}", + path, + name); + }, + ResolutionError::UndeclaredLabel(name) => { + span_err!(resolver.session, span, E0426, + "use of undeclared label `{}`", + name); + }, + ResolutionError::CannotUseRefBindingModeWith(descr) => { + span_err!(resolver.session, span, E0427, + "cannot use `ref` binding mode with {}", + descr); + }, + ResolutionError::DuplicateDefinition(namespace, name) => { + span_err!(resolver.session, span, E0428, + "duplicate definition of {} `{}`", + namespace, + name); + }, + ResolutionError::SelfImportsOnlyAllowedWithin => { + span_err!(resolver.session, span, E0429, "{}", + "`self` imports are only allowed within a { } list"); + }, + ResolutionError::SelfImportCanOnlyAppearOnceInTheList => { + span_err!(resolver.session, span, E0430, + "`self` import can only appear once in the list"); + }, + ResolutionError::SelfImportOnlyInImportListWithNonEmptyPrefix => { + span_err!(resolver.session, span, E0431, + "`self` import can only appear in an import list with a \ + non-empty prefix"); + } + ResolutionError::UnresolvedImport(name) => { + let msg = match name { + Some((n, Some(p))) => format!("unresolved import `{}`{}", n, p), + Some((n, None)) => format!("unresolved import (maybe you meant `{}::*`?)", n), + None => "unresolved import".to_owned() + }; + span_err!(resolver.session, span, E0432, "{}", msg); + }, + ResolutionError::FailedToResolve(msg) => { + span_err!(resolver.session, span, E0433, "failed to resolve. {}", msg); + }, + ResolutionError::CannotCaptureDynamicEnvironmentInFnItem => { + span_err!(resolver.session, span, E0434, "{}", + "can't capture dynamic environment in a fn item; \ + use the || { ... } closure form instead"); + }, + ResolutionError::AttemptToUseNonConstantValueInConstant =>{ + span_err!(resolver.session, span, E0435, + "attempt to use a non-constant value in a constant"); + }, + } +} + #[derive(Copy, Clone)] struct BindingInfo { span: Span, @@ -947,8 +1202,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if module.external_module_children.borrow().contains_key(&name) { span_err!(self.session, span, E0259, "an external crate named `{}` has already \ - been imported into this module", - &token::get_name(name)); + been imported into this module", + name); } } @@ -960,9 +1215,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if module.external_module_children.borrow().contains_key(&name) { span_err!(self.session, span, E0260, "the name `{}` conflicts with an external \ - crate that has been imported into this \ - module", - &token::get_name(name)); + crate that has been imported into this \ + module", + name); } } @@ -1041,7 +1296,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Indeterminate => { debug!("(resolving module path for import) module \ resolution is indeterminate: {}", - token::get_name(name)); + name); return Indeterminate; } Success((target, used_proxy)) => { @@ -1052,7 +1307,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match type_def.module_def { None => { let msg = format!("Not a module `{}`", - token::get_name(name)); + name); return Failed(Some((span, msg))); } @@ -1078,7 +1333,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None => { // There are no type bindings at all. let msg = format!("Not a module `{}`", - token::get_name(name)); + name); return Failed(Some((span, msg))); } } @@ -1200,7 +1455,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { -> ResolveResult<(Target, bool)> { debug!("(resolving item in lexical scope) resolving `{}` in \ namespace {:?} in `{}`", - token::get_name(name), + name, namespace, module_to_string(&*module_)); @@ -1302,9 +1557,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { namespace, PathSearch, true) { - Failed(Some((span, msg))) => - self.resolve_error(span, &format!("failed to resolve. {}", - msg)), + Failed(Some((span, msg))) => { + resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)); + }, Failed(None) => (), // Continue up the search chain. Indeterminate => { // We couldn't see through the higher scope because of an @@ -1469,7 +1724,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { allow_private_imports: bool) -> ResolveResult<(Target, bool)> { debug!("(resolving name in module) resolving `{}` in `{}`", - &token::get_name(name), + name, module_to_string(&*module_)); // First, check the direct children of the module. @@ -1547,7 +1802,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // We're out of luck. debug!("(resolving name in module) failed to resolve `{}`", - &token::get_name(name)); + name); return Failed(None); } @@ -1561,12 +1816,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .span_to_snippet((*imports)[index].span) .unwrap(); if sn.contains("::") { - self.resolve_error((*imports)[index].span, - "unresolved import"); + resolve_error(self, + (*imports)[index].span, + ResolutionError::UnresolvedImport(None)); } else { - let err = format!("unresolved import (maybe you meant `{}::*`?)", - sn); - self.resolve_error((*imports)[index].span, &err[..]); + resolve_error(self, + (*imports)[index].span, + ResolutionError::UnresolvedImport(Some((&*sn, None)))); } } @@ -1623,7 +1879,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match orig_module.children.borrow().get(&name) { None => { debug!("!!! (with scope) didn't find `{}` in `{}`", - token::get_name(name), + name, module_to_string(&*orig_module)); } Some(name_bindings) => { @@ -1631,7 +1887,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { None => { debug!("!!! (with scope) didn't find module \ for `{}` in `{}`", - token::get_name(name), + name, module_to_string(&*orig_module)); } Some(module_) => { @@ -1692,17 +1948,20 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. - - self.resolve_error(span, - "can't capture dynamic environment in a fn item; \ - use the || { ... } closure form instead"); + resolve_error( + self, + span, + ResolutionError::CannotCaptureDynamicEnvironmentInFnItem + ); return None; } ConstantItemRibKind => { // Still doesn't deal with upvars - self.resolve_error(span, - "attempt to use a non-constant \ - value in a constant"); + resolve_error( + self, + span, + ResolutionError::AttemptToUseNonConstantValueInConstant + ); return None; } } @@ -1718,17 +1977,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // This was an attempt to use a type parameter outside // its scope. - self.resolve_error(span, - "can't use type parameters from \ - outer function; try using a local \ - type parameter instead"); + resolve_error(self, + span, + ResolutionError::TypeParametersFromOuterFunction); return None; } ConstantItemRibKind => { // see #9186 - self.resolve_error(span, - "cannot use an outer type \ - parameter in this context"); + resolve_error(self, span, ResolutionError::OuterTypeParameterContext); return None; } } @@ -1795,7 +2051,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let name = item.ident.name; debug!("(resolving item) resolving {}", - token::get_name(name)); + name); match item.node { ItemEnum(_, ref generics) | @@ -1921,12 +2177,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("with_type_parameter_rib: {}", type_parameter.id); if seen_bindings.contains(&name) { - self.resolve_error(type_parameter.span, - &format!("the name `{}` is already \ - used for a type \ - parameter in this type \ - parameter list", - token::get_name(name))) + resolve_error(self, + type_parameter.span, + ResolutionError::NameAlreadyUsedInTypeParameterList( + name) + ); } seen_bindings.insert(name); @@ -2013,9 +2268,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("(resolving trait) found trait def: {:?}", path_res); Ok(path_res) } else { - self.resolve_error(trait_path.span, - &format!("`{}` is not a trait", - path_names_to_string(trait_path, path_depth))); + resolve_error(self, + trait_path.span, + ResolutionError::IsNotATrait(&*path_names_to_string(trait_path, + path_depth)) + ); // If it's a typedef, give a note if let DefTy(..) = path_res.base_def { @@ -2025,9 +2282,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Err(()) } } else { - let msg = format!("use of undeclared trait name `{}`", - path_names_to_string(trait_path, path_depth)); - self.resolve_error(trait_path.span, &msg); + resolve_error(self, + trait_path.span, + ResolutionError::UndeclaredTraitName( + &*path_names_to_string(trait_path, path_depth)) + ); Err(()) } } @@ -2045,7 +2304,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some(PathResolution { base_def: DefTyParam(..), .. }) = path_res { self.record_def(eq_pred.id, path_res.unwrap()); } else { - self.resolve_error(eq_pred.path.span, "undeclared associated type"); + resolve_error(self, + eq_pred.span, + ResolutionError::UndeclaredAssociatedType); } } } @@ -2170,10 +2431,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if let Some((did, ref trait_ref)) = self.current_trait_ref { if !self.trait_item_map.contains_key(&(name, did)) { let path_str = path_names_to_string(&trait_ref.path, 0); - self.resolve_error(span, - &format!("method `{}` is not a member of trait `{}`", - token::get_name(name), - path_str)); + resolve_error(self, + span, + ResolutionError::MethodNotMemberOfTrait(name, + &*path_str)); } } } @@ -2220,21 +2481,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { for (&key, &binding_0) in &map_0 { match map_i.get(&key) { None => { - self.resolve_error( - p.span, - &format!("variable `{}` from pattern #1 is \ - not bound in pattern #{}", - token::get_name(key), - i + 1)); + resolve_error(self, + p.span, + ResolutionError::VariableNotBoundInPattern(key, + i + 1)); } Some(binding_i) => { if binding_0.binding_mode != binding_i.binding_mode { - self.resolve_error( - binding_i.span, - &format!("variable `{}` is bound with different \ - mode in pattern #{} than in pattern #1", - token::get_name(key), - i + 1)); + resolve_error(self, + binding_i.span, + ResolutionError::VariableBoundWithDifferentMode(key, + i + 1) + ); } } } @@ -2242,12 +2500,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { for (&key, &binding) in &map_i { if !map_0.contains_key(&key) { - self.resolve_error( - binding.span, - &format!("variable `{}` from pattern {}{} is \ - not bound in pattern {}1", - token::get_name(key), - "#", i + 1, "#")); + resolve_error(self, + binding.span, + ResolutionError::VariableNotBoundInParentPattern(key, + i + 1)); } } } @@ -2360,14 +2616,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { path.segments.len() > 0 && maybe_qself.is_none() && path.segments[0].identifier.name == self_type_name; - let msg = if is_invalid_self_type_name { - "use of `Self` outside of an impl or trait".to_string() + if is_invalid_self_type_name { + resolve_error(self, + ty.span, + ResolutionError::SelfUsedOutsideImplOrTrait); } else { - format!("use of undeclared {} `{}`", - kind, path_names_to_string(path, 0)) - }; - - self.resolve_error(ty.span, &msg[..]); + resolve_error(self, + ty.span, + ResolutionError::UseOfUndeclared( + kind, + &*path_names_to_string(path, + 0)) + ); + } } } } @@ -2405,7 +2666,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if mode == RefutableMode => { debug!("(resolving pattern) resolving `{}` to \ struct or enum variant", - token::get_name(renamed)); + renamed); self.enforce_default_binding_mode( pattern, @@ -2418,17 +2679,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); } FoundStructOrEnumVariant(..) => { - self.resolve_error( + resolve_error( + self, pattern.span, - &format!("declaration of `{}` shadows an enum \ - variant or unit-like struct in \ - scope", - token::get_name(renamed))); + ResolutionError::DeclarationShadowsEnumVariantOrUnitLikeStruct( + renamed) + ); } FoundConst(def, lp) if mode == RefutableMode => { debug!("(resolving pattern) resolving `{}` to \ constant", - token::get_name(renamed)); + renamed); self.enforce_default_binding_mode( pattern, @@ -2441,13 +2702,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }); } FoundConst(..) => { - self.resolve_error(pattern.span, - "only irrefutable patterns \ - allowed here"); + resolve_error( + self, + pattern.span, + ResolutionError::OnlyIrrefutablePatternsAllowedHere + ); } BareIdentifierPatternUnresolved => { debug!("(resolving pattern) binding `{}`", - token::get_name(renamed)); + renamed); let def = DefLocal(pattern.id); @@ -2475,24 +2738,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { bindings_list.contains_key(&renamed) { // Forbid duplicate bindings in the same // parameter list. - self.resolve_error(pattern.span, - &format!("identifier `{}` \ - is bound more \ - than once in \ - this parameter \ - list", - token::get_ident( - ident)) - ) + resolve_error( + self, + pattern.span, + ResolutionError::IdentifierBoundMoreThanOnceInParameterList( + &*token::get_ident(ident)) + ); } else if bindings_list.get(&renamed) == Some(&pat_id) { // Then this is a duplicate variable in the // same disjunction, which is an error. - self.resolve_error(pattern.span, - &format!("identifier `{}` is bound \ - more than once in the same \ - pattern", - token::get_ident(ident))); + resolve_error( + self, + pattern.span, + ResolutionError::IdentifierBoundMoreThanOnceInSamePattern( + &*token::get_ident(ident)) + ); } // Else, not bound in the same pattern: do // nothing. @@ -2523,10 +2784,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.record_def(pattern.id, path_res); } DefStatic(..) => { - self.resolve_error(path.span, - "static variables cannot be \ - referenced in a pattern, \ - use a `const` instead"); + resolve_error(&self, + path.span, + ResolutionError::StaticVariableReference); } _ => { // If anything ends up here entirely resolved, @@ -2534,11 +2794,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // partially resolved, that's OK, because it may // be a `T::CONST` that typeck will resolve. if path_res.depth == 0 { - self.resolve_error( + resolve_error( + self, path.span, - &format!("`{}` is not an enum variant, struct or const", - token::get_ident( - path.segments.last().unwrap().identifier))); + ResolutionError::NotAnEnumVariantStructOrConst( + &*token::get_ident( + path.segments.last().unwrap().identifier) + ) + ); } else { let const_name = path.segments.last().unwrap() .identifier.name; @@ -2549,9 +2812,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } } else { - self.resolve_error(path.span, - &format!("unresolved enum variant, struct or const `{}`", - token::get_ident(path.segments.last().unwrap().identifier))); + resolve_error( + self, + path.span, + ResolutionError::UnresolvedEnumVariantStructOrConst( + &*token::get_ident(path.segments.last().unwrap().identifier)) + ); } visit::walk_path(self, path); } @@ -2583,16 +2849,24 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { self.record_def(pattern.id, path_res); } _ => { - self.resolve_error(path.span, - &format!("`{}` is not an associated const", - token::get_ident( - path.segments.last().unwrap().identifier))); + resolve_error( + self, + path.span, + ResolutionError::NotAnAssociatedConst( + &*token::get_ident( + path.segments.last().unwrap().identifier) + ) + ); } } } else { - self.resolve_error(path.span, - &format!("unresolved associated const `{}`", - token::get_ident(path.segments.last().unwrap().identifier))); + resolve_error( + self, + path.span, + ResolutionError::UnresolvedAssociatedConst( + &*token::get_ident(path.segments.last().unwrap().identifier) + ) + ); } visit::walk_pat(self, pattern); } @@ -2605,9 +2879,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { result => { debug!("(resolving pattern) didn't find struct \ def: {:?}", result); - let msg = format!("`{}` does not name a structure", - path_names_to_string(path, 0)); - self.resolve_error(path.span, &msg[..]); + resolve_error( + self, + path.span, + ResolutionError::DoesNotNameAStruct( + &*path_names_to_string(path, 0)) + ); } } visit::walk_path(self, path); @@ -2634,7 +2911,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Success((target, _)) => { debug!("(resolve bare identifier pattern) succeeded in \ finding {} at {:?}", - token::get_name(name), + name, target.bindings.value_def.borrow()); match *target.bindings.value_def.borrow() { None => { @@ -2653,10 +2930,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { return FoundConst(def, LastMod(AllPublic)); } DefStatic(..) => { - self.resolve_error(span, - "static variables cannot be \ - referenced in a pattern, \ - use a `const` instead"); + resolve_error(self, + span, + ResolutionError::StaticVariableReference); return BareIdentifierPatternUnresolved; } _ => { @@ -2673,14 +2949,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Failed(err) => { match err { Some((span, msg)) => { - self.resolve_error(span, &format!("failed to resolve: {}", - msg)); + resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)); } None => () } debug!("(resolve bare identifier pattern) failed to find {}", - token::get_name(name)); + name); return BareIdentifierPatternUnresolved; } } @@ -2903,8 +3178,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }; - self.resolve_error(span, &format!("failed to resolve. {}", - msg)); + resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)); return None; } Indeterminate => panic!("indeterminate unexpected"), @@ -2963,8 +3237,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } }; - self.resolve_error(span, &format!("failed to resolve. {}", - msg)); + resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)); return None; } @@ -3038,13 +3311,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // found a module instead. Modules don't have defs. debug!("(resolving item path by identifier in lexical \ scope) failed to resolve {} after success...", - token::get_name(name)); + name); return None; } Some(def) => { debug!("(resolving item path in lexical scope) \ resolved `{}` to item", - token::get_name(name)); + name); // This lookup is "all public" because it only searched // for one identifier in the current module (couldn't // have passed through reexports or anything like that. @@ -3057,10 +3330,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } Failed(err) => { debug!("(resolving item path by identifier in lexical scope) \ - failed to resolve {}", token::get_name(name)); + failed to resolve {}", name); if let Some((span, msg)) = err { - self.resolve_error(span, &format!("failed to resolve. {}", msg)) + resolve_error(self, span, ResolutionError::FailedToResolve(&*msg)) } return None; @@ -3077,12 +3350,6 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { rs } - fn resolve_error(&self, span: Span, s: &str) { - if self.emit_errors { - self.session.span_err(span, s); - } - } - fn find_fallback_in_self_type(&mut self, name: Name) -> FallbackSuggestion { fn extract_path_and_node_id(t: &Ty, allow: FallbackChecks) -> Option<(Path, NodeId, FallbackChecks)> { @@ -3268,11 +3535,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // Check if struct variant if let DefVariant(_, _, true) = path_res.base_def { let path_name = path_names_to_string(path, 0); - self.resolve_error(expr.span, - &format!("`{}` is a struct variant name, but \ - this expression \ - uses it like a function name", - path_name)); + + resolve_error(self, + expr.span, + ResolutionError::StructVariantUsedAsFunction(&*path_name)); let msg = format!("did you mean to write: \ `{} {{ /* fields */ }}`?", @@ -3309,11 +3575,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match type_res.map(|r| r.base_def) { Some(DefTy(struct_id, _)) if self.structs.contains_key(&struct_id) => { - self.resolve_error(expr.span, - &format!("`{}` is a structure name, but \ - this expression \ - uses it like a function name", - path_name)); + resolve_error( + self, + expr.span, + ResolutionError::StructVariantUsedAsFunction( + &*path_name) + ); let msg = format!("did you mean to write: \ `{} {{ /* fields */ }}`?", @@ -3340,11 +3607,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { if method_scope && &token::get_name(special_names::self_)[..] == path_name { - self.resolve_error( - expr.span, - "`self` is not available \ - in a static method. Maybe a \ - `self` argument is missing?"); + resolve_error( + self, + expr.span, + ResolutionError::SelfNotAvailableInStaticMethod + ); } else { let last_name = path.segments.last().unwrap().identifier.name; let mut msg = match self.find_fallback_in_self_type(last_name) { @@ -3368,10 +3635,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { msg = format!(". Did you mean {}?", msg) } - self.resolve_error( - expr.span, - &format!("unresolved name `{}`{}", - path_name, msg)); + resolve_error(self, + expr.span, + ResolutionError::UnresolvedName(&*path_name, + &*msg)); } } } @@ -3388,9 +3655,12 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { Some(definition) => self.record_def(expr.id, definition), None => { debug!("(resolving expression) didn't find struct def",); - let msg = format!("`{}` does not name a structure", - path_names_to_string(path, 0)); - self.resolve_error(path.span, &msg[..]); + + resolve_error(self, + path.span, + ResolutionError::DoesNotNameAStruct( + &*path_names_to_string(path, 0)) + ); } } @@ -3415,10 +3685,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let renamed = mtwt::resolve(label); match self.search_label(renamed) { None => { - self.resolve_error( - expr.span, - &format!("use of undeclared label `{}`", - token::get_ident(label))) + resolve_error(self, + expr.span, + ResolutionError::UndeclaredLabel(&*token::get_ident(label))) } Some(DlDef(def @ DefLabel(_))) => { // Since this def is a label, it is never read. @@ -3467,7 +3736,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { fn get_traits_containing_item(&mut self, name: Name) -> Vec { debug!("(getting traits containing item) looking for '{}'", - token::get_name(name)); + name); fn add_trait_info(found_traits: &mut Vec, trait_def_id: DefId, @@ -3475,7 +3744,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("(adding trait info) found trait {}:{} for method '{}'", trait_def_id.krate, trait_def_id.node, - token::get_name(name)); + name); found_traits.push(trait_def_id); } @@ -3564,10 +3833,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match pat_binding_mode { BindByValue(_) => {} BindByRef(..) => { - self.resolve_error(pat.span, - &format!("cannot use `ref` binding mode \ - with {}", - descr)); + resolve_error(self, + pat.span, + ResolutionError::CannotUseRefBindingModeWith(descr)); } } } @@ -3586,7 +3854,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { debug!("Children:"); build_reduced_graph::populate_module_if_necessary(self, &module_); for (&name, _) in module_.children.borrow().iter() { - debug!("* {}", token::get_name(name)); + debug!("* {}", name); } debug!("Import resolutions:"); @@ -3610,7 +3878,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - debug!("* {}:{}{}", token::get_name(name), value_repr, type_repr); + debug!("* {}:{}{}", name, value_repr, type_repr); } } } diff --git a/src/librustc_resolve/resolve_imports.rs b/src/librustc_resolve/resolve_imports.rs index e77e7116b9fea..e797da7b8f64b 100644 --- a/src/librustc_resolve/resolve_imports.rs +++ b/src/librustc_resolve/resolve_imports.rs @@ -22,6 +22,7 @@ use ResolveResult; use Resolver; use UseLexicalScopeFlag; use {names_to_string, module_to_string}; +use {resolve_error, ResolutionError}; use build_reduced_graph; @@ -272,12 +273,14 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { Some((span, msg)) => (span, format!(". {}", msg)), None => (import_directive.span, String::new()) }; - let msg = format!("unresolved import `{}`{}", - import_path_to_string( - &import_directive.module_path, - import_directive.subclass), - help); - self.resolver.resolve_error(span, &msg[..]); + resolve_error(self.resolver, + span, + ResolutionError::UnresolvedImport( + Some((&*import_path_to_string( + &import_directive.module_path, + import_directive.subclass), + Some(&*help)))) + ); } ResolveResult::Indeterminate => break, // Bail out. We'll come around next time. ResolveResult::Success(()) => () // Good. Continue. @@ -394,9 +397,9 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { -> ResolveResult<()> { debug!("(resolving single import) resolving `{}` = `{}::{}` from \ `{}` id {}, last private {:?}", - token::get_name(target), + target, module_to_string(&*target_module), - token::get_name(source), + source, module_to_string(module_), directive.id, lp); @@ -431,7 +434,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { value_result = BoundResult(target_module.clone(), (*child_name_bindings).clone()); if directive.is_public && !child_name_bindings.is_public(ValueNS) { - let msg = format!("`{}` is private", token::get_name(source)); + let msg = format!("`{}` is private", source); span_err!(self.resolver.session, directive.span, E0364, "{}", &msg); pub_err = true; } @@ -441,7 +444,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { type_result = BoundResult(target_module.clone(), (*child_name_bindings).clone()); if !pub_err && directive.is_public && !child_name_bindings.is_public(TypeNS) { - let msg = format!("`{}` is private", token::get_name(source)); + let msg = format!("`{}` is private", source); span_err!(self.resolver.session, directive.span, E0365, "{}", &msg); } } @@ -655,7 +658,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { if value_result.is_unbound() && type_result.is_unbound() { let msg = format!("There is no `{}` in `{}`", - token::get_name(source), + source, module_to_string(&target_module)); return ResolveResult::Failed(Some((directive.span, msg))); } @@ -736,7 +739,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { for (ident, target_import_resolution) in import_resolutions.iter() { debug!("(resolving glob import) writing module resolution \ {} into `{}`", - token::get_name(*ident), + *ident, module_to_string(module_)); if !target_import_resolution.is_public { @@ -842,7 +845,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { debug!("(resolving glob import) writing resolution `{}` in `{}` \ to `{}`", - &token::get_name(name), + name, module_to_string(&*containing_module), module_to_string(module_)); @@ -861,7 +864,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { let msg = format!("a {} named `{}` has already been imported \ in this module", namespace_name, - &token::get_name(name)); + name); span_err!(self.resolver.session, import_directive.span, E0251, "{}", msg); } else { let target = Target::new(containing_module.clone(), @@ -894,7 +897,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { namespace: Namespace) { let target = import_resolution.target_for_namespace(namespace); debug!("check_for_conflicting_import: {}; target exists: {}", - &token::get_name(name), + name, target.is_some()); match target { @@ -918,13 +921,13 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { span_err!(self.resolver.session, import_span, E0252, "a {} named `{}` has already been imported \ in this module", ns_word, - &token::get_name(name)); + name); let use_id = import_resolution.id(namespace); let item = self.resolver.ast_map.expect_item(use_id); // item is syntax::ast::Item; span_note!(self.resolver.session, item.span, "previous import of `{}` here", - token::get_name(name)); + name); } Some(_) | None => {} } @@ -938,7 +941,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { namespace: Namespace) { if !name_bindings.defined_in_namespace_with(namespace, DefModifiers::IMPORTABLE) { let msg = format!("`{}` is not directly importable", - token::get_name(name)); + name); span_err!(self.resolver.session, import_span, E0253, "{}", &msg[..]); } } @@ -959,7 +962,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { let msg = format!("import `{0}` conflicts with imported \ crate in this module \ (maybe you meant `use {0}::*`?)", - &token::get_name(name)); + name); span_err!(self.resolver.session, import_span, E0254, "{}", &msg[..]); } Some(_) | None => {} @@ -981,7 +984,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { if let Some(ref value) = *name_bindings.value_def.borrow() { span_err!(self.resolver.session, import_span, E0255, "import `{}` conflicts with value in this module", - &token::get_name(name)); + name); if let Some(span) = value.value_span { self.resolver.session.span_note(span, "conflicting value here"); } @@ -1004,7 +1007,7 @@ impl<'a, 'b:'a, 'tcx:'b> ImportResolver<'a, 'b, 'tcx> { }; span_err!(self.resolver.session, import_span, E0256, "import `{}` conflicts with {}", - &token::get_name(name), what); + name, what); if let Some(span) = ty.type_span { self.resolver.session.span_note(span, note); } diff --git a/src/librustc_trans/save/dump_csv.rs b/src/librustc_trans/save/dump_csv.rs index c5196d09e00a1..680999717eae5 100644 --- a/src/librustc_trans/save/dump_csv.rs +++ b/src/librustc_trans/save/dump_csv.rs @@ -35,7 +35,6 @@ use session::Session; use middle::def; use middle::ty::{self, Ty}; -use std::cell::Cell; use std::fs::File; use std::path::Path; @@ -76,14 +75,11 @@ impl <'l, 'tcx> DumpCsvVisitor<'l, 'tcx> { pub fn new(tcx: &'l ty::ctxt<'tcx>, analysis: &'l ty::CrateAnalysis, output_file: Box) -> DumpCsvVisitor<'l, 'tcx> { - let span_utils = SpanUtils { - sess: &tcx.sess, - err_count: Cell::new(0) - }; + let span_utils = SpanUtils::new(&tcx.sess); DumpCsvVisitor { sess: &tcx.sess, tcx: tcx, - save_ctxt: SaveContext::new(tcx, span_utils.clone()), + save_ctxt: SaveContext::from_span_utils(tcx, span_utils.clone()), analysis: analysis, span: span_utils.clone(), fmt: FmtStrs::new(box Recorder { diff --git a/src/librustc_trans/save/mod.rs b/src/librustc_trans/save/mod.rs index 4e0b34b7ef8ac..26da803de6557 100644 --- a/src/librustc_trans/save/mod.rs +++ b/src/librustc_trans/save/mod.rs @@ -163,9 +163,14 @@ pub struct MethodCallData { impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { - pub fn new(tcx: &'l ty::ctxt<'tcx>, - span_utils: SpanUtils<'l>) - -> SaveContext<'l, 'tcx> { + pub fn new(tcx: &'l ty::ctxt<'tcx>) -> SaveContext <'l, 'tcx> { + let span_utils = SpanUtils::new(&tcx.sess); + SaveContext::from_span_utils(tcx, span_utils) + } + + pub fn from_span_utils(tcx: &'l ty::ctxt<'tcx>, + span_utils: SpanUtils<'l>) + -> SaveContext<'l, 'tcx> { SaveContext { tcx: tcx, span_utils: span_utils, @@ -527,7 +532,10 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { ref_id: def.def_id(), }) } - def::DefStruct(def_id) | def::DefTy(def_id, _) => { + def::DefStruct(def_id) | + def::DefTy(def_id, _) | + def::DefTrait(def_id) | + def::DefTyParam(_, _, def_id, _) => { Data::TypeRefData(TypeRefData { span: sub_span.unwrap(), ref_id: def_id, @@ -540,13 +548,12 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { let ti = self.tcx.impl_or_trait_item(decl_id); match provenence { def::FromTrait(def_id) => { - Some(self.tcx.trait_items(def_id) - .iter() - .find(|mr| { - mr.name() == ti.name() - }) - .unwrap() - .def_id()) + self.tcx.trait_items(def_id) + .iter() + .find(|mr| { + mr.name() == ti.name() && self.trait_method_has_body(mr) + }) + .map(|mr| mr.def_id()) } def::FromImpl(def_id) => { let impl_items = self.tcx.impl_items.borrow(); @@ -586,6 +593,20 @@ impl<'l, 'tcx: 'l> SaveContext<'l, 'tcx> { } } + fn trait_method_has_body(&self, mr: &ty::ImplOrTraitItem) -> bool { + let def_id = mr.def_id(); + if def_id.krate != ast::LOCAL_CRATE { + return false; + } + + let trait_item = self.tcx.map.expect_trait_item(def_id.node); + if let ast::TraitItem_::MethodTraitItem(_, Some(_)) = trait_item.node { + true + } else { + false + } + } + pub fn get_field_ref_data(&self, field_ref: &ast::Field, struct_id: DefId, @@ -753,6 +774,6 @@ fn escape(s: String) -> String { // If the expression is a macro expansion or other generated code, run screaming // and don't index. -fn generated_code(span: Span) -> bool { +pub fn generated_code(span: Span) -> bool { span.expn_id != NO_EXPANSION || span == DUMMY_SP } diff --git a/src/librustc_trans/save/span_utils.rs b/src/librustc_trans/save/span_utils.rs index 08cbd777c095c..ee7b1c4ff6e29 100644 --- a/src/librustc_trans/save/span_utils.rs +++ b/src/librustc_trans/save/span_utils.rs @@ -28,6 +28,13 @@ pub struct SpanUtils<'a> { } impl<'a> SpanUtils<'a> { + pub fn new(sess: &'a Session) -> SpanUtils<'a> { + SpanUtils { + sess: sess, + err_count: Cell::new(0) + } + } + // Standard string for extents/location. pub fn extent_str(&self, span: Span) -> String { let lo_loc = self.sess.codemap().lookup_char_pos(span.lo); diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs index 5a71d1ed0b5bd..9042cedccc857 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/src/librustc_typeck/check/mod.rs @@ -3426,6 +3426,11 @@ fn check_expr_with_unifier<'a, 'tcx, F>(fcx: &FnCtxt<'a, 'tcx>, let def = lookup_full_def(tcx, path.span, id); let struct_id = match def { def::DefVariant(enum_id, variant_id, true) => { + if let &Some(ref base_expr) = base_expr { + span_err!(tcx.sess, base_expr.span, E0436, + "functional record update syntax requires a struct"); + fcx.write_error(base_expr.id); + } check_struct_enum_variant(fcx, id, expr.span, enum_id, variant_id, &fields[..]); enum_id diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 5027be5fb62a3..2069e3098e638 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -2209,6 +2209,7 @@ register_diagnostics! { E0392, // parameter `{}` is never used E0393, // the type parameter `{}` must be explicitly specified in an object // type because its default value `{}` references the type `Self`" - E0399 // trait items need to be implemented because the associated + E0399, // trait items need to be implemented because the associated // type `{}` was overridden + E0436 // functional record update requires a struct } diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index c77cdd4d02183..1eb1556a25d26 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -701,6 +701,9 @@ // Push and pop states are used to add search results to the browser // history. if (browserSupportsHistoryApi()) { + // Store the previous so we can revert back to it later. + var previousTitle = $(document).prop("title"); + $(window).on('popstate', function(e) { var params = getQueryStringParams(); // When browsing back from search results the main page @@ -709,6 +712,9 @@ $('#main.content').removeClass('hidden'); $('#search.content').addClass('hidden'); } + // Revert to the previous title manually since the History + // API ignores the title parameter. + $(document).prop("title", previousTitle); // When browsing forward to search results the previous // search will be repeated, so the currentResults are // cleared to ensure the search is successful. @@ -951,3 +957,8 @@ }()); }()); + +// Sets the focus on the search bar at the top of the page +function focusSearchBar() { + document.getElementsByName('search')[0].focus(); +} diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 7598a1c7a48f0..2c78b2894311d 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -25,6 +25,7 @@ use io::{self, SeekFrom, Seek, Read, Write}; use path::{Path, PathBuf}; use sys::fs as fs_imp; use sys_common::{AsInnerMut, FromInner, AsInner}; +use sys_common::io::read_to_end_uninitialized; use vec::Vec; /// A reference to an open file on the filesystem. @@ -328,6 +329,9 @@ impl Read for File { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.inner.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + unsafe { read_to_end_uninitialized(self, buf) } + } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for File { diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 2551ffb2c056b..2447473103101 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -1449,6 +1449,8 @@ mod tests { use io::prelude::*; use io; use super::Cursor; + use test; + use super::repeat; #[test] fn read_until() { @@ -1567,4 +1569,13 @@ mod tests { let mut buf = [0; 1]; assert_eq!(0, R.take(0).read(&mut buf).unwrap()); } + + #[bench] + fn bench_read_to_end(b: &mut test::Bencher) { + b.iter(|| { + let mut lr = repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + super::read_to_end(&mut lr, &mut vec); + }); + } } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 62bbb939a71f5..d8b7c8a282ca2 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -18,6 +18,7 @@ use io::lazy::Lazy; use io::{self, BufReader, LineWriter}; use sync::{Arc, Mutex, MutexGuard}; use sys::stdio; +use sys_common::io::{read_to_end_uninitialized}; use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use libc; @@ -277,6 +278,9 @@ impl<'a> Read for StdinLock<'a> { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.inner.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + unsafe { read_to_end_uninitialized(self, buf) } + } } #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 53423cd5148c8..fa90670acfbef 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -10,29 +10,116 @@ //! # The Rust Standard Library //! -//! The Rust Standard Library provides the essential runtime -//! functionality for building portable Rust software. +//! The Rust Standard Library is the foundation of portable Rust +//! software, a set of minimal and battle-tested shared abstractions +//! for the [broader Rust ecosystem](https://crates.io). It offers +//! core types (e.g. [`Vec`](vec/index.html) +//! and [`Option`](option/index.html)), library-defined [operations on +//! language primitives](#primitive) (e.g. [`u32`](u32/index.html) and +//! [`str`](str/index.html)), [standard macros](#macros), +//! [I/O](io/index.html) and [multithreading](thread/index.html), among +//! [many other lovely +//! things](#what-is-in-the-standard-library-documentation?). //! -//! The Rust Standard Library is available to all Rust crates by -//! default, just as if contained an `extern crate std` import at the -//! crate root. Therefore the standard library can be accessed in -//! `use` statements through the path `std`, as in `use std::thread`, -//! or in expressions through the absolute path `::std`, as in -//! `::std::thread::sleep_ms(100)`. +//! `std` is available to all Rust crates by default, just as if each +//! one contained an `extern crate std` import at the [crate +//! root][book-crate-root]. Therefore the standard library can be +//! accessed in [`use`][book-use] statements through the path `std`, +//! as in [`use std::env`](env/index.html), or in expressions +//! through the absolute path `::std`, as in +//! [`::std::env::args()`](env/fn.args.html). //! -//! Furthermore, the standard library defines [The Rust -//! Prelude](prelude/index.html), a small collection of items, mostly -//! traits, that are imported into and available in every module. +//! [book-crate-root]: ../book/crates-and-modules.html#basic-terminology:-crates-and-modules +//! [book-use]: ../book/crates-and-modules.html#importing-modules-with-use //! -//! ## What is in the standard library +//! # How to read this documentation //! -//! The standard library is a set of minimal, battle-tested -//! core types and shared abstractions for the [broader Rust -//! ecosystem](https://crates.io) to build on. +//! If you already know the name of what you are looking for the +//! fastest way to find it is to use the <a href="#" +//! onclick="focusSearchBar();">search bar</a> at the top of the page. //! -//! The [primitive types](#primitives), though not defined in the -//! standard library, are documented here, as are the predefined -//! [macros](#macros). +//! Otherwise, you may want to jump to one of these useful sections: +//! +//! * [`std::*` modules](#modules) +//! * [Primitive types](#primitives) +//! * [Standard macros](#macros) +//! * [The Rust Prelude](prelude/index.html) +//! +//! If this is your first time, the documentation for the standard +//! library is written to be casually perused. Clicking on interesting +//! things should generally lead you to interesting places. Still, +//! there are important bits you don't want to miss, so read on for a +//! tour of the standard library and its documentation! +//! +//! Once you are familiar with the contents of the standard library +//! you may begin to find the verbosity of the prose distracting. At +//! this stage in your development you may want to press the **[-]** +//! button near the top of the page to collapse it into a more +//! skimmable view. +//! +//! While you are looking at that **[-]** button also notice the +//! **[src]** button. Rust's API documentation comes with the source +//! code and you are encouraged to read it. The standard library +//! source is generally high quality and a peek behind the curtains is +//! often enlightening. +//! +//! # What is in the standard library documentation? +//! +//! Lots of stuff. Well, broadly four things actually. +//! +//! First of all, The Rust Standard Library is divided into a number +//! of focused modules, [all listed further down this page](#modules). +//! These modules are the bedrock upon which all of Rust is forged, +//! and they have mighty names like [`std::slice`](slice/index.html) +//! and [`std::cmp`](cmp/index.html). Modules' documentation typically +//! includes an overview of the module along with examples, and are +//! a smart place to start familiarizing yourself with the library. +//! +//! Second, implicit methods on [primitive +//! types](../book/primitive-types.html) are documented here. This can +//! be a source of confusion for two reasons: +//! +//! 1. While primitives are implemented by the compiler, the standard +//! library implements methods directly on the primitive types (and +//! it is the only library that does so), which are [documented in +//! the section on primitives](#primitives). +//! 2. The standard library exports many modules *with the same name +//! as primitive types*. These define additional items related +//! to the primitive type, but not the all-important methods. +//! +//! So for example there is a [page for the primitive type +//! `i32`](primitive.i32.html) that lists all the methods that can be +//! called on 32-bit integers (mega useful), and there is a [page for +//! the module `std::i32`](i32/index.html) that documents the constant +//! values `MIN` and `MAX` (rarely useful). +//! +//! Note the documentation for the primitives +//! [`str`](primitive.str.html) and [`[T]`](primitive.slice.html) +//! (also called 'slice'). Many method calls on +//! [`String`](string/struct.String.html) and +//! [`Vec`](vec/struct.Vec.html) are actually calls to methods on +//! `str` and `[T]` respectively, via [deref +//! coercions](../book/deref-coercions.html). *Accepting that +//! primitive types are documented on their own pages will bring you a +//! deep inner wisdom. Embrace it now before proceeding.* +//! +//! Third, the standard library defines [The Rust +//! Prelude](prelude/index.html), a small collection of items - mostly +//! traits - that are imported into every module of every crate. The +//! traits in the prelude are pervasive, making the prelude +//! documentation a good entry point to learning about the library. +//! +//! And finally, the standard library exports a number of standard +//! macros, and [lists them on this page](#macros) (technically, not +//! all of the standard macros are defined by the standard library - +//! some are defined by the compiler - but they are documented here +//! the same). Like the prelude, the standard macros are imported by +//! default into all crates. +//! +//! # A Tour of The Rust Standard Library +//! +//! The rest of this crate documentation is dedicated to pointing +//! out notable features of The Rust Standard Library. //! //! ## Containers and collections //! @@ -43,17 +130,29 @@ //! [`Iterator`](iter/trait.Iterator.html), which works with the `for` //! loop to access collections. //! -//! The common container type, `Vec`, a growable vector backed by an array, -//! lives in the [`vec`](vec/index.html) module. Contiguous, unsized regions -//! of memory, `[T]`, commonly called "slices", and their borrowed versions, -//! `&[T]`, commonly called "borrowed slices", are built-in types for which the -//! [`slice`](slice/index.html) module defines many methods. +//! The standard library exposes 3 common ways to deal with contiguous +//! regions of memory: //! -//! `&str`, a UTF-8 string, is a built-in type, and the standard library -//! defines methods for it on a variety of traits in the -//! [`str`](str/index.html) module. Rust strings are immutable; -//! use the `String` type defined in [`string`](string/index.html) -//! for a mutable string builder. +//! * [`Vec<T>`](vec/index.html) - A heap-allocated *vector* that is +//! resizable at runtime. +//! * [`[T; n]`](primitive.array.html) - An inline *array* with a +//! fixed size at compile time. +//! * [`[T]`](primitive.slice.html) - A dynamically sized *slice* into +//! any other kind of contiguous storage, whether heap-allocated or +//! not. +//! +//! Slices can only be handled through some kind of *pointer*, and as +//! such come in many flavours such as: +//! +//! * `&[T]` - *shared slice* +//! * `&mut [T]` - *mutable slice* +//! * [`Box<[T]>`](boxed/index.html) - *owned slice* +//! +//! `str`, a UTF-8 string slice, is a primitive type, and the standard +//! library defines [many methods for it](primitive.str.html). Rust +//! `str`s are typically accessed as immutable references: `&str`. Use +//! the owned `String` type defined in [`string`](string/index.html) +//! for building and mutating strings. //! //! For converting to strings use the [`format!`](fmt/index.html) //! macro, and for converting from strings use the @@ -88,6 +187,7 @@ //! [`atomic`](sync/atomic/index.html) and //! [`mpsc`](sync/mpsc/index.html), which contains the channel types //! for message passing. +//! // Do not remove on snapshot creation. Needed for bootstrap. (Issue #22364) #![cfg_attr(stage0, feature(custom_attribute))] diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 085ba286dc3d9..66c8403b2685e 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -19,6 +19,7 @@ use io; use net::{ToSocketAddrs, SocketAddr, Shutdown}; use sys_common::net as net_imp; use sys_common::{AsInner, FromInner}; +use sys_common::io::read_to_end_uninitialized; use time::Duration; /// A structure which represents a TCP stream between a local socket and a @@ -189,6 +190,9 @@ impl TcpStream { #[stable(feature = "rust1", since = "1.0.0")] impl Read for TcpStream { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + unsafe { read_to_end_uninitialized(self, buf) } + } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for TcpStream { @@ -198,6 +202,9 @@ impl Write for TcpStream { #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Read for &'a TcpStream { fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } + fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> { + unsafe { read_to_end_uninitialized(self, buf) } + } } #[stable(feature = "rust1", since = "1.0.0")] impl<'a> Write for &'a TcpStream { diff --git a/src/libstd/prelude/mod.rs b/src/libstd/prelude/mod.rs index 156a3d428debd..275f415c6fc80 100644 --- a/src/libstd/prelude/mod.rs +++ b/src/libstd/prelude/mod.rs @@ -22,18 +22,107 @@ //! with the `std::` path prefix, as in `use std::vec`, `use std::thread::spawn`, //! etc. //! -//! Additionally, `std` contains a `prelude` module that reexports many of the -//! most common traits, types and functions. The contents of the prelude are -//! imported into every *module* by default. Implicitly, all modules behave as if -//! they contained the following prologue: +//! Additionally, `std` contains a versioned *prelude* that reexports many of the +//! most common traits, types and functions. *The contents of the prelude are +//! imported into every module by default*. Implicitly, all modules behave as if +//! they contained the following [`use` statement][book-use]: +//! +//! [book-use]: ../../book/crates-and-modules.html#importing-modules-with-use //! //! ```ignore //! use std::prelude::v1::*; //! ``` //! -//! The prelude is primarily concerned with exporting *traits* that are so -//! pervasive that it would be obnoxious to import for every use, particularly -//! those that define methods on primitive types. +//! The prelude is primarily concerned with exporting *traits* that +//! are so pervasive that they would be onerous to import for every use, +//! particularly those that are commonly mentioned in [generic type +//! bounds][book-traits]. +//! +//! The current version of the prelude (version 1) lives in +//! [`std::prelude::v1`](v1/index.html), and reexports the following. +//! +//! * `std::marker::`{ +//! [`Copy`](../marker/trait.Copy.html), +//! [`Send`](../marker/trait.Send.html), +//! [`Sized`](../marker/trait.Sized.html), +//! [`Sync`](../marker/trait.Sync.html) +//! }. +//! The marker traits indicate fundamental properties of types. +//! * `std::ops::`{ +//! [`Drop`](../ops/trait.Drop.html), +//! [`Fn`](../ops/trait.Fn.html), +//! [`FnMut`](../ops/trait.FnMut.html), +//! [`FnOnce`](../ops/trait.FnOnce.html) +//! }. +//! The [destructor][book-dtor] trait and the +//! [closure][book-closures] traits, reexported from the same +//! [module that also defines overloaded +//! operators](../ops/index.html). +//! * `std::mem::`[`drop`](../mem/fn.drop.html). +//! A convenience function for explicitly dropping a value. +//! * `std::boxed::`[`Box`](../boxed/struct.Box.html). +//! The owned heap pointer. +//! * `std::borrow::`[`ToOwned`](../borrow/trait.ToOwned.html). +//! The conversion trait that defines `to_owned`, the generic method +//! for creating an owned type from a borrowed type. +//! * `std::clone::`[`Clone`](../clone/trait.Clone.html). +//! The ubiquitous trait that defines `clone`, the method for +//! producing copies of values that are consider expensive to copy. +//! * `std::cmp::`{ +//! [`PartialEq`](../cmp/trait.PartialEq.html), +//! [`PartialOrd`](../cmp/trait.PartialOrd.html), +//! [`Eq`](../cmp/trait.Eq.html), +//! [`Ord`](../cmp/trait.Ord.html) +//! }. +//! The comparision traits, which implement the comparison operators +//! and are often seen in trait bounds. +//! * `std::convert::`{ +//! [`AsRef`](../convert/trait.AsRef.html), +//! [`AsMut`](../convert/trait.AsMut.html), +//! [`Into`](../convert/trait.Into.html), +//! [`From`](../convert/trait.From.html) +//! }. +//! Generic conversions, used by savvy API authors to create +//! overloaded methods. +//! * `std::default::`[`Default`](../default/trait.Default). +//! Types that have default values. +//! * `std::iter::`{ +//! [`Iterator`](../iter/trait.Iterator.html), +//! [`Extend`](../iter/trait.Extend.html), +//! [`IntoIterator`](../iter/trait.IntoIterator.html), +//! [`DoubleEndedIterator`](../iter/trait.DoubleEndedIterator.html), +//! [`ExactSizeIterator`](../iter/trait.ExactSizeIterator.html) +//! }. +//! [Iterators][book-iter]. +//! * `std::option::Option::`{ +//! [`self`](../option/enum.Option.html), +//! [`Some`](../option/enum.Option.html), +//! [`None`](../option/enum.Option.html) +//! }. +//! The ubiquitous `Option` type and its two [variants][book-enums], +//! `Some` and `None`. +//! * `std::result::Result::`{ +//! [`self`](../result/enum.Result.html), +//! [`Some`](../result/enum.Result.html), +//! [`None`](../result/enum.Result.html) +//! }. +//! The ubiquitous `Result` type and its two [variants][book-enums], +//! `Ok` and `Err`. +//! * `std::slice::`[`SliceConcatExt`](../slice/trait.SliceConcatExt.html). +//! An unstable extension to slices that shouldn't have to exist. +//! * `std::string::`{ +//! [`String`](../string/struct.String.html), +//! [`ToString`](../string/trait.ToString.html) +//! }. +//! Heap allocated strings. +//! * `std::vec::`[`Vec`](../vec/struct.Vec.html). +//! Heap allocated vectors. +//! +//! [book-traits]: ../../book/traits.html +//! [book-closures]: ../../book/closures.html +//! [book-dtor]: ../../book/drop.html +//! [book-iter]: ../../book/iterators.html +//! [book-enums]: ../../book/enums.html #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/common/io.rs b/src/libstd/sys/common/io.rs new file mode 100644 index 0000000000000..151d853fc9f7e --- /dev/null +++ b/src/libstd/sys/common/io.rs @@ -0,0 +1,139 @@ +// Copyright 2015 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. +use prelude::v1::*; +use io; +use io::ErrorKind; +use io::Read; +use slice::from_raw_parts_mut; + +// Provides read_to_end functionality over an uninitialized buffer. +// This function is unsafe because it calls the underlying +// read function with a slice into uninitialized memory. The default +// implementation of read_to_end for readers will zero out new memory in +// the buf before passing it to read, but avoiding this zero can often +// lead to a fairly significant performance win. +// +// Implementations using this method have to adhere to two guarantees: +// * The implementation of read never reads the buffer provided. +// * The implementation of read correctly reports how many bytes were written. +pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io::Result<usize> { + + let start_len = buf.len(); + buf.reserve(16); + + // Always try to read into the empty space of the vector (from the length to the capacity). + // If the vector ever fills up then we reserve an extra byte which should trigger the normal + // reallocation routines for the vector, which will likely double the size. + // + // This function is similar to the read_to_end function in std::io, but the logic about + // reservations and slicing is different enough that this is duplicated here. + loop { + if buf.len() == buf.capacity() { + buf.reserve(1); + } + + let buf_slice = from_raw_parts_mut(buf.as_mut_ptr().offset(buf.len() as isize), + buf.capacity() - buf.len()); + + match r.read(buf_slice) { + Ok(0) => { return Ok(buf.len() - start_len); } + Ok(n) => { let len = buf.len() + n; buf.set_len(len); }, + Err(ref e) if e.kind() == ErrorKind::Interrupted => { } + Err(e) => { return Err(e); } + } + } +} + +#[cfg(test)] +mod tests { + use prelude::v1::*; + use io::prelude::*; + use super::*; + use io; + use io::{ErrorKind, Take, Repeat, repeat}; + use test; + use slice::from_raw_parts; + + struct ErrorRepeat { + lr: Take<Repeat> + } + + fn error_repeat(byte: u8, limit: u64) -> ErrorRepeat { + ErrorRepeat { lr: repeat(byte).take(limit) } + } + + impl Read for ErrorRepeat { + fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { + let ret = self.lr.read(buf); + if let Ok(0) = ret { + return Err(io::Error::new(ErrorKind::Other, "")) + } + ret + } + } + + fn init_vec_data() -> Vec<u8> { + let mut vec = vec![10u8; 200]; + unsafe { vec.set_len(0); } + vec + } + + fn assert_all_eq(buf: &[u8], value: u8) { + for n in buf { + assert_eq!(*n, value); + } + } + + fn validate(buf: &Vec<u8>, good_read_len: usize) { + assert_all_eq(buf, 1u8); + let cap = buf.capacity(); + let end_slice = unsafe { from_raw_parts(buf.as_ptr().offset(good_read_len as isize), + cap - good_read_len) }; + assert_all_eq(end_slice, 10u8); + } + + #[test] + fn read_to_end_uninit_error() { + let mut er = error_repeat(1,100); + let mut vec = init_vec_data(); + if let Err(_) = unsafe { read_to_end_uninitialized(&mut er, &mut vec) } { + validate(&vec, 100); + } else { + assert!(false); + } + } + + #[test] + fn read_to_end_uninit_zero_len_vec() { + let mut er = repeat(1).take(100); + let mut vec = Vec::new(); + let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; + assert_all_eq(&vec, 1u8); + assert_eq!(vec.len(), n); + } + + #[test] + fn read_to_end_uninit_good() { + let mut er = repeat(1).take(100); + let mut vec = init_vec_data(); + let n = unsafe{ read_to_end_uninitialized(&mut er, &mut vec).unwrap() }; + validate(&vec, 100); + assert_eq!(vec.len(), n); + } + + #[bench] + fn bench_uninitialized(b: &mut test::Bencher) { + b.iter(|| { + let mut lr = repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + unsafe { read_to_end_uninitialized(&mut lr, &mut vec) }; + }); + } +} diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index b528575bbed33..69c54f9891759 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -16,6 +16,7 @@ pub mod backtrace; pub mod condvar; pub mod mutex; pub mod net; +pub mod io; pub mod poison; pub mod remutex; pub mod rwlock; diff --git a/src/libsyntax/diagnostic.rs b/src/libsyntax/diagnostic.rs index ec93d2c553627..fbf015169f858 100644 --- a/src/libsyntax/diagnostic.rs +++ b/src/libsyntax/diagnostic.rs @@ -308,63 +308,6 @@ impl Level { } } -fn print_maybe_styled(w: &mut EmitterWriter, - msg: &str, - color: term::attr::Attr) -> io::Result<()> { - match w.dst { - Terminal(ref mut t) => { - try!(t.attr(color)); - // If `msg` ends in a newline, we need to reset the color before - // the newline. We're making the assumption that we end up writing - // to a `LineBufferedWriter`, which means that emitting the reset - // after the newline ends up buffering the reset until we print - // another line or exit. Buffering the reset is a problem if we're - // sharing the terminal with any other programs (e.g. other rustc - // instances via `make -jN`). - // - // Note that if `msg` contains any internal newlines, this will - // result in the `LineBufferedWriter` flushing twice instead of - // once, which still leaves the opportunity for interleaved output - // to be miscolored. We assume this is rare enough that we don't - // have to worry about it. - if msg.ends_with("\n") { - try!(t.write_all(msg[..msg.len()-1].as_bytes())); - try!(t.reset()); - try!(t.write_all(b"\n")); - } else { - try!(t.write_all(msg.as_bytes())); - try!(t.reset()); - } - Ok(()) - } - Raw(ref mut w) => w.write_all(msg.as_bytes()), - } -} - -fn print_diagnostic(dst: &mut EmitterWriter, topic: &str, lvl: Level, - msg: &str, code: Option<&str>) -> io::Result<()> { - if !topic.is_empty() { - try!(write!(&mut dst.dst, "{} ", topic)); - } - - try!(print_maybe_styled(dst, - &format!("{}: ", lvl.to_string()), - term::attr::ForegroundColor(lvl.color()))); - try!(print_maybe_styled(dst, - &format!("{}", msg), - term::attr::Bold)); - - match code { - Some(code) => { - let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA); - try!(print_maybe_styled(dst, &format!(" [{}]", code.clone()), style)); - } - None => () - } - try!(write!(&mut dst.dst, "\n")); - Ok(()) -} - pub struct EmitterWriter { dst: Destination, registry: Option<diagnostics::registry::Registry> @@ -401,6 +344,392 @@ impl EmitterWriter { registry: Option<diagnostics::registry::Registry>) -> EmitterWriter { EmitterWriter { dst: Raw(dst), registry: registry } } + + fn print_maybe_styled(&mut self, + msg: &str, + color: term::attr::Attr) -> io::Result<()> { + match self.dst { + Terminal(ref mut t) => { + try!(t.attr(color)); + // If `msg` ends in a newline, we need to reset the color before + // the newline. We're making the assumption that we end up writing + // to a `LineBufferedWriter`, which means that emitting the reset + // after the newline ends up buffering the reset until we print + // another line or exit. Buffering the reset is a problem if we're + // sharing the terminal with any other programs (e.g. other rustc + // instances via `make -jN`). + // + // Note that if `msg` contains any internal newlines, this will + // result in the `LineBufferedWriter` flushing twice instead of + // once, which still leaves the opportunity for interleaved output + // to be miscolored. We assume this is rare enough that we don't + // have to worry about it. + if msg.ends_with("\n") { + try!(t.write_all(msg[..msg.len()-1].as_bytes())); + try!(t.reset()); + try!(t.write_all(b"\n")); + } else { + try!(t.write_all(msg.as_bytes())); + try!(t.reset()); + } + Ok(()) + } + Raw(ref mut w) => w.write_all(msg.as_bytes()), + } + } + + fn print_diagnostic(&mut self, topic: &str, lvl: Level, + msg: &str, code: Option<&str>) -> io::Result<()> { + if !topic.is_empty() { + try!(write!(&mut self.dst, "{} ", topic)); + } + + try!(self.print_maybe_styled(&format!("{}: ", lvl.to_string()), + term::attr::ForegroundColor(lvl.color()))); + try!(self.print_maybe_styled(&format!("{}", msg), + term::attr::Bold)); + + match code { + Some(code) => { + let style = term::attr::ForegroundColor(term::color::BRIGHT_MAGENTA); + try!(self.print_maybe_styled(&format!(" [{}]", code.clone()), style)); + } + None => () + } + try!(write!(&mut self.dst, "\n")); + Ok(()) + } + + fn emit_(&mut self, cm: &codemap::CodeMap, rsp: RenderSpan, + msg: &str, code: Option<&str>, lvl: Level) -> io::Result<()> { + let sp = rsp.span(); + + // We cannot check equality directly with COMMAND_LINE_SP + // since PartialEq is manually implemented to ignore the ExpnId + let ss = if sp.expn_id == COMMAND_LINE_EXPN { + "<command line option>".to_string() + } else if let EndSpan(_) = rsp { + let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id}; + cm.span_to_string(span_end) + } else { + cm.span_to_string(sp) + }; + + try!(self.print_diagnostic(&ss[..], lvl, msg, code)); + + match rsp { + FullSpan(_) => { + try!(self.highlight_lines(cm, sp, lvl, cm.span_to_lines(sp))); + try!(self.print_macro_backtrace(cm, sp)); + } + EndSpan(_) => { + try!(self.end_highlight_lines(cm, sp, lvl, cm.span_to_lines(sp))); + try!(self.print_macro_backtrace(cm, sp)); + } + Suggestion(_, ref suggestion) => { + try!(self.highlight_suggestion(cm, sp, suggestion)); + try!(self.print_macro_backtrace(cm, sp)); + } + FileLine(..) => { + // no source text in this case! + } + } + + match code { + Some(code) => + match self.registry.as_ref().and_then(|registry| registry.find_description(code)) { + Some(_) => { + try!(self.print_diagnostic(&ss[..], Help, + &format!("run `rustc --explain {}` to see a \ + detailed explanation", code), None)); + } + None => () + }, + None => (), + } + Ok(()) + } + + fn highlight_suggestion(&mut self, + cm: &codemap::CodeMap, + sp: Span, + suggestion: &str) + -> io::Result<()> + { + let lines = cm.span_to_lines(sp).unwrap(); + assert!(!lines.lines.is_empty()); + + // To build up the result, we want to take the snippet from the first + // line that precedes the span, prepend that with the suggestion, and + // then append the snippet from the last line that trails the span. + let fm = &lines.file; + + let first_line = &lines.lines[0]; + let prefix = fm.get_line(first_line.line_index) + .map(|l| &l[..first_line.start_col.0]) + .unwrap_or(""); + + let last_line = lines.lines.last().unwrap(); + let suffix = fm.get_line(last_line.line_index) + .map(|l| &l[last_line.end_col.0..]) + .unwrap_or(""); + + let complete = format!("{}{}{}", prefix, suggestion, suffix); + + // print the suggestion without any line numbers, but leave + // space for them. This helps with lining up with previous + // snippets from the actual error being reported. + let fm = &*lines.file; + let mut lines = complete.lines(); + for (line, line_index) in lines.by_ref().take(MAX_LINES).zip(first_line.line_index..) { + let elided_line_num = format!("{}", line_index+1); + try!(write!(&mut self.dst, "{0}:{1:2$} {3}\n", + fm.name, "", elided_line_num.len(), line)); + } + + // if we elided some lines, add an ellipsis + if lines.next().is_some() { + let elided_line_num = format!("{}", first_line.line_index + MAX_LINES + 1); + try!(write!(&mut self.dst, "{0:1$} {0:2$} ...\n", + "", fm.name.len(), elided_line_num.len())); + } + + Ok(()) + } + + fn highlight_lines(&mut self, + cm: &codemap::CodeMap, + sp: Span, + lvl: Level, + lines: codemap::FileLinesResult) + -> io::Result<()> + { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut self.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + + let fm = &*lines.file; + + let line_strings: Option<Vec<&str>> = + lines.lines.iter() + .map(|info| fm.get_line(info.line_index)) + .collect(); + + let line_strings = match line_strings { + None => { return Ok(()); } + Some(line_strings) => line_strings + }; + + // Display only the first MAX_LINES lines. + let all_lines = lines.lines.len(); + let display_lines = cmp::min(all_lines, MAX_LINES); + let display_line_infos = &lines.lines[..display_lines]; + let display_line_strings = &line_strings[..display_lines]; + + // Calculate the widest number to format evenly and fix #11715 + assert!(display_line_infos.len() > 0); + let mut max_line_num = display_line_infos[display_line_infos.len() - 1].line_index + 1; + let mut digits = 0; + while max_line_num > 0 { + max_line_num /= 10; + digits += 1; + } + + // Print the offending lines + for (line_info, line) in display_line_infos.iter().zip(display_line_strings) { + try!(write!(&mut self.dst, "{}:{:>width$} {}\n", + fm.name, + line_info.line_index + 1, + line, + width=digits)); + } + + // If we elided something, put an ellipsis. + if display_lines < all_lines { + let last_line_index = display_line_infos.last().unwrap().line_index; + let s = format!("{}:{} ", fm.name, last_line_index + 1); + try!(write!(&mut self.dst, "{0:1$}...\n", "", s.len())); + } + + // FIXME (#3260) + // If there's one line at fault we can easily point to the problem + if lines.lines.len() == 1 { + let lo = cm.lookup_char_pos(sp.lo); + let mut digits = 0; + let mut num = (lines.lines[0].line_index + 1) / 10; + + // how many digits must be indent past? + while num > 0 { num /= 10; digits += 1; } + + let mut s = String::new(); + // Skip is the number of characters we need to skip because they are + // part of the 'filename:line ' part of the previous line. + let skip = fm.name.chars().count() + digits + 3; + for _ in 0..skip { + s.push(' '); + } + if let Some(orig) = fm.get_line(lines.lines[0].line_index) { + let mut col = skip; + let mut lastc = ' '; + let mut iter = orig.chars().enumerate(); + for (pos, ch) in iter.by_ref() { + lastc = ch; + if pos >= lo.col.to_usize() { break; } + // Whenever a tab occurs on the previous line, we insert one on + // the error-point-squiggly-line as well (instead of a space). + // That way the squiggly line will usually appear in the correct + // position. + match ch { + '\t' => { + col += 8 - col%8; + s.push('\t'); + }, + _ => { + col += 1; + s.push(' '); + }, + } + } + + try!(write!(&mut self.dst, "{}", s)); + let mut s = String::from("^"); + let count = match lastc { + // Most terminals have a tab stop every eight columns by default + '\t' => 8 - col%8, + _ => 1, + }; + col += count; + s.extend(::std::iter::repeat('~').take(count)); + + let hi = cm.lookup_char_pos(sp.hi); + if hi.col != lo.col { + for (pos, ch) in iter { + if pos >= hi.col.to_usize() { break; } + let count = match ch { + '\t' => 8 - col%8, + _ => 1, + }; + col += count; + s.extend(::std::iter::repeat('~').take(count)); + } + } + + if s.len() > 1 { + // One extra squiggly is replaced by a "^" + s.pop(); + } + + try!(self.print_maybe_styled(&format!("{}\n", s), + term::attr::ForegroundColor(lvl.color()))); + } + } + Ok(()) + } + + /// Here are the differences between this and the normal `highlight_lines`: + /// `end_highlight_lines` will always put arrow on the last byte of the + /// span (instead of the first byte). Also, when the span is too long (more + /// than 6 lines), `end_highlight_lines` will print the first line, then + /// dot dot dot, then last line, whereas `highlight_lines` prints the first + /// six lines. + #[allow(deprecated)] + fn end_highlight_lines(&mut self, + cm: &codemap::CodeMap, + sp: Span, + lvl: Level, + lines: codemap::FileLinesResult) + -> io::Result<()> { + let lines = match lines { + Ok(lines) => lines, + Err(_) => { + try!(write!(&mut self.dst, "(internal compiler error: unprintable span)\n")); + return Ok(()); + } + }; + + let fm = &*lines.file; + + let lines = &lines.lines[..]; + if lines.len() > MAX_LINES { + if let Some(line) = fm.get_line(lines[0].line_index) { + try!(write!(&mut self.dst, "{}:{} {}\n", fm.name, + lines[0].line_index + 1, line)); + } + try!(write!(&mut self.dst, "...\n")); + let last_line_index = lines[lines.len() - 1].line_index; + if let Some(last_line) = fm.get_line(last_line_index) { + try!(write!(&mut self.dst, "{}:{} {}\n", fm.name, + last_line_index + 1, last_line)); + } + } else { + for line_info in lines { + if let Some(line) = fm.get_line(line_info.line_index) { + try!(write!(&mut self.dst, "{}:{} {}\n", fm.name, + line_info.line_index + 1, line)); + } + } + } + let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1].line_index + 1); + let hi = cm.lookup_char_pos(sp.hi); + let skip = last_line_start.chars().count(); + let mut s = String::new(); + for _ in 0..skip { + s.push(' '); + } + if let Some(orig) = fm.get_line(lines[0].line_index) { + let iter = orig.chars().enumerate(); + for (pos, ch) in iter { + // Span seems to use half-opened interval, so subtract 1 + if pos >= hi.col.to_usize() - 1 { break; } + // Whenever a tab occurs on the previous line, we insert one on + // the error-point-squiggly-line as well (instead of a space). + // That way the squiggly line will usually appear in the correct + // position. + match ch { + '\t' => s.push('\t'), + _ => s.push(' '), + } + } + } + s.push('^'); + s.push('\n'); + self.print_maybe_styled(&s[..], + term::attr::ForegroundColor(lvl.color())) + } + + fn print_macro_backtrace(&mut self, + cm: &codemap::CodeMap, + sp: Span) + -> io::Result<()> { + let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> { + match expn_info { + Some(ei) => { + let ss = ei.callee.span.map_or(String::new(), + |span| cm.span_to_string(span)); + let (pre, post) = match ei.callee.format { + codemap::MacroAttribute => ("#[", "]"), + codemap::MacroBang => ("", "!"), + codemap::CompilerExpansion => ("", ""), + }; + try!(self.print_diagnostic(&ss, Note, + &format!("in expansion of {}{}{}", + pre, + ei.callee.name, + post), + None)); + let ss = cm.span_to_string(ei.call_site); + try!(self.print_diagnostic(&ss, Note, "expansion site", None)); + Ok(Some(ei.call_site)) + } + None => Ok(None) + } + })); + cs.map_or(Ok(()), |call_site| self.print_macro_backtrace(cm, call_site)) + } } #[cfg(unix)] @@ -442,11 +771,11 @@ impl Emitter for EmitterWriter { cmsp: Option<(&codemap::CodeMap, Span)>, msg: &str, code: Option<&str>, lvl: Level) { let error = match cmsp { - Some((cm, COMMAND_LINE_SP)) => emit(self, cm, + Some((cm, COMMAND_LINE_SP)) => self.emit_(cm, FileLine(COMMAND_LINE_SP), msg, code, lvl), - Some((cm, sp)) => emit(self, cm, FullSpan(sp), msg, code, lvl), - None => print_diagnostic(self, "", lvl, msg, code), + Some((cm, sp)) => self.emit_(cm, FullSpan(sp), msg, code, lvl), + None => self.print_diagnostic("", lvl, msg, code), }; match error { @@ -457,346 +786,13 @@ impl Emitter for EmitterWriter { fn custom_emit(&mut self, cm: &codemap::CodeMap, sp: RenderSpan, msg: &str, lvl: Level) { - match emit(self, cm, sp, msg, None, lvl) { + match self.emit_(cm, sp, msg, None, lvl) { Ok(()) => {} Err(e) => panic!("failed to print diagnostics: {:?}", e), } } } -fn emit(dst: &mut EmitterWriter, cm: &codemap::CodeMap, rsp: RenderSpan, - msg: &str, code: Option<&str>, lvl: Level) -> io::Result<()> { - let sp = rsp.span(); - - // We cannot check equality directly with COMMAND_LINE_SP - // since PartialEq is manually implemented to ignore the ExpnId - let ss = if sp.expn_id == COMMAND_LINE_EXPN { - "<command line option>".to_string() - } else if let EndSpan(_) = rsp { - let span_end = Span { lo: sp.hi, hi: sp.hi, expn_id: sp.expn_id}; - cm.span_to_string(span_end) - } else { - cm.span_to_string(sp) - }; - - try!(print_diagnostic(dst, &ss[..], lvl, msg, code)); - - match rsp { - FullSpan(_) => { - try!(highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp))); - try!(print_macro_backtrace(dst, cm, sp)); - } - EndSpan(_) => { - try!(end_highlight_lines(dst, cm, sp, lvl, cm.span_to_lines(sp))); - try!(print_macro_backtrace(dst, cm, sp)); - } - Suggestion(_, ref suggestion) => { - try!(highlight_suggestion(dst, cm, sp, suggestion)); - try!(print_macro_backtrace(dst, cm, sp)); - } - FileLine(..) => { - // no source text in this case! - } - } - - match code { - Some(code) => - match dst.registry.as_ref().and_then(|registry| registry.find_description(code)) { - Some(_) => { - try!(print_diagnostic(dst, &ss[..], Help, - &format!("run `rustc --explain {}` to see a detailed \ - explanation", code), None)); - } - None => () - }, - None => (), - } - Ok(()) -} - -fn highlight_suggestion(err: &mut EmitterWriter, - cm: &codemap::CodeMap, - sp: Span, - suggestion: &str) - -> io::Result<()> -{ - let lines = cm.span_to_lines(sp).unwrap(); - assert!(!lines.lines.is_empty()); - - // To build up the result, we want to take the snippet from the first - // line that precedes the span, prepend that with the suggestion, and - // then append the snippet from the last line that trails the span. - let fm = &lines.file; - - let first_line = &lines.lines[0]; - let prefix = fm.get_line(first_line.line_index) - .map(|l| &l[..first_line.start_col.0]) - .unwrap_or(""); - - let last_line = lines.lines.last().unwrap(); - let suffix = fm.get_line(last_line.line_index) - .map(|l| &l[last_line.end_col.0..]) - .unwrap_or(""); - - let complete = format!("{}{}{}", prefix, suggestion, suffix); - - // print the suggestion without any line numbers, but leave - // space for them. This helps with lining up with previous - // snippets from the actual error being reported. - let fm = &*lines.file; - let mut lines = complete.lines(); - for (line, line_index) in lines.by_ref().take(MAX_LINES).zip(first_line.line_index..) { - let elided_line_num = format!("{}", line_index+1); - try!(write!(&mut err.dst, "{0}:{1:2$} {3}\n", - fm.name, "", elided_line_num.len(), line)); - } - - // if we elided some lines, add an ellipsis - if lines.next().is_some() { - let elided_line_num = format!("{}", first_line.line_index + MAX_LINES + 1); - try!(write!(&mut err.dst, "{0:1$} {0:2$} ...\n", - "", fm.name.len(), elided_line_num.len())); - } - - Ok(()) -} - -fn highlight_lines(err: &mut EmitterWriter, - cm: &codemap::CodeMap, - sp: Span, - lvl: Level, - lines: codemap::FileLinesResult) - -> io::Result<()> -{ - let lines = match lines { - Ok(lines) => lines, - Err(_) => { - try!(write!(&mut err.dst, "(internal compiler error: unprintable span)\n")); - return Ok(()); - } - }; - - let fm = &*lines.file; - - let line_strings: Option<Vec<&str>> = - lines.lines.iter() - .map(|info| fm.get_line(info.line_index)) - .collect(); - - let line_strings = match line_strings { - None => { return Ok(()); } - Some(line_strings) => line_strings - }; - - // Display only the first MAX_LINES lines. - let all_lines = lines.lines.len(); - let display_lines = cmp::min(all_lines, MAX_LINES); - let display_line_infos = &lines.lines[..display_lines]; - let display_line_strings = &line_strings[..display_lines]; - - // Calculate the widest number to format evenly and fix #11715 - assert!(display_line_infos.len() > 0); - let mut max_line_num = display_line_infos[display_line_infos.len() - 1].line_index + 1; - let mut digits = 0; - while max_line_num > 0 { - max_line_num /= 10; - digits += 1; - } - - // Print the offending lines - for (line_info, line) in display_line_infos.iter().zip(display_line_strings) { - try!(write!(&mut err.dst, "{}:{:>width$} {}\n", - fm.name, - line_info.line_index + 1, - line, - width=digits)); - } - - // If we elided something, put an ellipsis. - if display_lines < all_lines { - let last_line_index = display_line_infos.last().unwrap().line_index; - let s = format!("{}:{} ", fm.name, last_line_index + 1); - try!(write!(&mut err.dst, "{0:1$}...\n", "", s.len())); - } - - // FIXME (#3260) - // If there's one line at fault we can easily point to the problem - if lines.lines.len() == 1 { - let lo = cm.lookup_char_pos(sp.lo); - let mut digits = 0; - let mut num = (lines.lines[0].line_index + 1) / 10; - - // how many digits must be indent past? - while num > 0 { num /= 10; digits += 1; } - - let mut s = String::new(); - // Skip is the number of characters we need to skip because they are - // part of the 'filename:line ' part of the previous line. - let skip = fm.name.chars().count() + digits + 3; - for _ in 0..skip { - s.push(' '); - } - if let Some(orig) = fm.get_line(lines.lines[0].line_index) { - let mut col = skip; - let mut lastc = ' '; - let mut iter = orig.chars().enumerate(); - for (pos, ch) in iter.by_ref() { - lastc = ch; - if pos >= lo.col.to_usize() { break; } - // Whenever a tab occurs on the previous line, we insert one on - // the error-point-squiggly-line as well (instead of a space). - // That way the squiggly line will usually appear in the correct - // position. - match ch { - '\t' => { - col += 8 - col%8; - s.push('\t'); - }, - _ => { - col += 1; - s.push(' '); - }, - } - } - - try!(write!(&mut err.dst, "{}", s)); - let mut s = String::from("^"); - let count = match lastc { - // Most terminals have a tab stop every eight columns by default - '\t' => 8 - col%8, - _ => 1, - }; - col += count; - s.extend(::std::iter::repeat('~').take(count)); - - let hi = cm.lookup_char_pos(sp.hi); - if hi.col != lo.col { - for (pos, ch) in iter { - if pos >= hi.col.to_usize() { break; } - let count = match ch { - '\t' => 8 - col%8, - _ => 1, - }; - col += count; - s.extend(::std::iter::repeat('~').take(count)); - } - } - - if s.len() > 1 { - // One extra squiggly is replaced by a "^" - s.pop(); - } - - try!(print_maybe_styled(err, - &format!("{}\n", s), - term::attr::ForegroundColor(lvl.color()))); - } - } - Ok(()) -} - -/// Here are the differences between this and the normal `highlight_lines`: -/// `end_highlight_lines` will always put arrow on the last byte of the -/// span (instead of the first byte). Also, when the span is too long (more -/// than 6 lines), `end_highlight_lines` will print the first line, then -/// dot dot dot, then last line, whereas `highlight_lines` prints the first -/// six lines. -#[allow(deprecated)] -fn end_highlight_lines(w: &mut EmitterWriter, - cm: &codemap::CodeMap, - sp: Span, - lvl: Level, - lines: codemap::FileLinesResult) - -> io::Result<()> { - let lines = match lines { - Ok(lines) => lines, - Err(_) => { - try!(write!(&mut w.dst, "(internal compiler error: unprintable span)\n")); - return Ok(()); - } - }; - - let fm = &*lines.file; - - let lines = &lines.lines[..]; - if lines.len() > MAX_LINES { - if let Some(line) = fm.get_line(lines[0].line_index) { - try!(write!(&mut w.dst, "{}:{} {}\n", fm.name, - lines[0].line_index + 1, line)); - } - try!(write!(&mut w.dst, "...\n")); - let last_line_index = lines[lines.len() - 1].line_index; - if let Some(last_line) = fm.get_line(last_line_index) { - try!(write!(&mut w.dst, "{}:{} {}\n", fm.name, - last_line_index + 1, last_line)); - } - } else { - for line_info in lines { - if let Some(line) = fm.get_line(line_info.line_index) { - try!(write!(&mut w.dst, "{}:{} {}\n", fm.name, - line_info.line_index + 1, line)); - } - } - } - let last_line_start = format!("{}:{} ", fm.name, lines[lines.len()-1].line_index + 1); - let hi = cm.lookup_char_pos(sp.hi); - let skip = last_line_start.chars().count(); - let mut s = String::new(); - for _ in 0..skip { - s.push(' '); - } - if let Some(orig) = fm.get_line(lines[0].line_index) { - let iter = orig.chars().enumerate(); - for (pos, ch) in iter { - // Span seems to use half-opened interval, so subtract 1 - if pos >= hi.col.to_usize() - 1 { break; } - // Whenever a tab occurs on the previous line, we insert one on - // the error-point-squiggly-line as well (instead of a space). - // That way the squiggly line will usually appear in the correct - // position. - match ch { - '\t' => s.push('\t'), - _ => s.push(' '), - } - } - } - s.push('^'); - s.push('\n'); - print_maybe_styled(w, - &s[..], - term::attr::ForegroundColor(lvl.color())) -} - -fn print_macro_backtrace(w: &mut EmitterWriter, - cm: &codemap::CodeMap, - sp: Span) - -> io::Result<()> { - let cs = try!(cm.with_expn_info(sp.expn_id, |expn_info| -> io::Result<_> { - match expn_info { - Some(ei) => { - let ss = ei.callee.span.map_or(String::new(), - |span| cm.span_to_string(span)); - let (pre, post) = match ei.callee.format { - codemap::MacroAttribute => ("#[", "]"), - codemap::MacroBang => ("", "!"), - codemap::CompilerExpansion => ("", ""), - }; - try!(print_diagnostic(w, &ss, Note, - &format!("in expansion of {}{}{}", - pre, - ei.callee.name, - post), - None)); - let ss = cm.span_to_string(ei.call_site); - try!(print_diagnostic(w, &ss, Note, "expansion site", None)); - Ok(Some(ei.call_site)) - } - None => Ok(None) - } - })); - cs.map_or(Ok(()), |call_site| print_macro_backtrace(w, cm, call_site)) -} - pub fn expect<T, M>(diag: &SpanHandler, opt: Option<T>, msg: M) -> T where M: FnOnce() -> String, { @@ -808,7 +804,7 @@ pub fn expect<T, M>(diag: &SpanHandler, opt: Option<T>, msg: M) -> T where #[cfg(test)] mod test { - use super::{EmitterWriter, highlight_lines, Level}; + use super::{EmitterWriter, Level}; use codemap::{mk_sp, CodeMap, BytePos}; use std::sync::{Arc, Mutex}; use std::io::{self, Write}; @@ -854,7 +850,7 @@ mod test { println!("span_to_lines"); let lines = cm.span_to_lines(sp); println!("highlight_lines"); - highlight_lines(&mut ew, &cm, sp, lvl, lines).unwrap(); + ew.highlight_lines(&cm, sp, lvl, lines).unwrap(); println!("done"); let vec = data.lock().unwrap().clone(); let vec: &[u8] = &vec; diff --git a/src/rt/arch/aarch64/morestack.S b/src/rt/arch/aarch64/morestack.S index c5e412140e44a..8b7366ebed431 100644 --- a/src/rt/arch/aarch64/morestack.S +++ b/src/rt/arch/aarch64/morestack.S @@ -24,7 +24,7 @@ #endif #if !defined(__APPLE__) -.type MORESTACK,%function +func MORESTACK #endif // FIXME(AARCH64): this might not be perfectly right but works for now @@ -33,3 +33,7 @@ MORESTACK: bl STACK_EXHAUSTED // the above function ensures that it never returns .cfi_endproc + +#if !defined(__APPLE__) +endfunc MORESTACK +#endif diff --git a/src/rustbook/javascript.rs b/src/rustbook/javascript.rs index f33b79cc1888f..8e530bee39aad 100644 --- a/src/rustbook/javascript.rs +++ b/src/rustbook/javascript.rs @@ -57,11 +57,13 @@ document.addEventListener("DOMContentLoaded", function(event) { if (i > 0) { var prevNode = toc[i-1].cloneNode(true); prevNode.className = 'left'; + prevNode.setAttribute('rel', 'prev'); nav.appendChild(prevNode); } if (i < toc.length - 1) { var nextNode = toc[i+1].cloneNode(true); nextNode.className = 'right'; + nextNode.setAttribute('rel', 'next'); nav.appendChild(nextNode); } document.getElementById('page').appendChild(nav); diff --git a/src/test/compile-fail/issue-22312.rs b/src/test/compile-fail/issue-22312.rs new file mode 100644 index 0000000000000..4d6e6eded2118 --- /dev/null +++ b/src/test/compile-fail/issue-22312.rs @@ -0,0 +1,27 @@ +// Copyright 2015 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. + +use std::ops::Index; + +pub trait Array2D: Index<usize> { + fn rows(&self) -> usize; + fn columns(&self) -> usize; + fn get<'a>(&'a self, y: usize, x: usize) -> Option<&'a <Self as Index<usize>>::Output> { + if y >= self.rows() || x >= self.columns() { + return None; + } + let i = y * self.columns() + x; + let indexer = &(*self as &Index<usize, Output = <Self as Index<usize>>::Output>); + //~^ERROR non-scalar cast + Some(indexer.index(i)) + } +} + +fn main() {} diff --git a/src/test/compile-fail/issue-23595-1.rs b/src/test/compile-fail/issue-23595-1.rs new file mode 100644 index 0000000000000..749b261e38719 --- /dev/null +++ b/src/test/compile-fail/issue-23595-1.rs @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +use std::ops::{Index}; + +trait Hierarchy { + type Value; + type ChildKey; + type Children = Index<Self::ChildKey, Output=Hierarchy>; + //~^ ERROR: the value of the associated type `ChildKey` + //~^^ ERROR: the value of the associated type `Children` + //~^^^ ERROR: the value of the associated type `Value` + + fn data(&self) -> Option<(Self::Value, Self::Children)>; +} + +fn main() {} diff --git a/src/test/compile-fail/issue-23595-2.rs b/src/test/compile-fail/issue-23595-2.rs new file mode 100644 index 0000000000000..78a3f42f1a6a7 --- /dev/null +++ b/src/test/compile-fail/issue-23595-2.rs @@ -0,0 +1,18 @@ +// Copyright 2015 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. + +pub struct C<AType: A> {a:AType} + +pub trait A { + type B = C<Self::anything_here_kills_it>; + //~^ ERROR: associated type `anything_here_kills_it` not found for `Self` +} + +fn main() {} diff --git a/src/test/compile-fail/issue-26948.rs b/src/test/compile-fail/issue-26948.rs new file mode 100644 index 0000000000000..c63cb5defb7e3 --- /dev/null +++ b/src/test/compile-fail/issue-26948.rs @@ -0,0 +1,16 @@ +// Copyright 2015 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. + +fn main() { + enum Foo { A { x: u32 } } + let orig = Foo::A { x: 5 }; + Foo::A { x: 6, ..orig }; + //~^ ERROR functional record update syntax requires a struct +} diff --git a/src/test/compile-fail/issue-6702.rs b/src/test/compile-fail/issue-6702.rs index e464ddf54c2d9..bfda113ae8bc9 100644 --- a/src/test/compile-fail/issue-6702.rs +++ b/src/test/compile-fail/issue-6702.rs @@ -14,6 +14,6 @@ struct Monster { fn main() { - let _m = Monster(); //~ ERROR `Monster` is a structure name, but + let _m = Monster(); //~ ERROR `Monster` is a struct variant name, but //~^ HELP did you mean to write: `Monster { /* fields */ }`? } diff --git a/src/test/compile-fail/ref-suggestion.rs b/src/test/compile-fail/ref-suggestion.rs new file mode 100644 index 0000000000000..815f752663223 --- /dev/null +++ b/src/test/compile-fail/ref-suggestion.rs @@ -0,0 +1,33 @@ +// Copyright 2015 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. + +fn main() { + let x = vec![1]; + let y = x; + //~^ HELP use a `ref` binding as shown + //~| SUGGESTION let ref y = x; + x; //~ ERROR use of moved value + + let x = vec![1]; + let mut y = x; + //~^ HELP use a `ref` binding as shown + //~| SUGGESTION let ref mut y = x; + x; //~ ERROR use of moved value + + let x = (Some(vec![1]), ()); + + match x { + (Some(y), ()) => {}, + //~^ HELP use a `ref` binding as shown + //~| SUGGESTION (Some(ref y), ()) => {}, + _ => {}, + } + x; //~ ERROR use of partially moved value +} diff --git a/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs b/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs index fa15e31450f8b..5dd428119569d 100644 --- a/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs +++ b/src/test/debuginfo/gdb-pretty-struct-and-enums-pre-gdb-7-7.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// This test uses only GDB Python API features which should be available in -// older versions of GDB too. A more extensive test can be found in -// gdb-pretty-struct-and-enums.rs - // ignore-bitrig // ignore-windows failing on win32 bot // ignore-freebsd: gdb package too new diff --git a/src/test/run-pass/issue-20544.rs b/src/test/run-pass/issue-20544.rs new file mode 100644 index 0000000000000..c70b059d3e787 --- /dev/null +++ b/src/test/run-pass/issue-20544.rs @@ -0,0 +1,27 @@ +// Copyright 2015 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(unboxed_closures)] +#![feature(core)] + +struct Fun<F>(F); + +impl<F, T> FnOnce<(T,)> for Fun<F> where F: Fn(T) -> T { + type Output = T; + + extern "rust-call" fn call_once(self, (t,): (T,)) -> T { + (self.0)(t) + } +} + +fn main() { + let fun = Fun(|i: isize| i * 2); + println!("{}", fun(3)); +} diff --git a/src/test/run-pass/issue-21140.rs b/src/test/run-pass/issue-21140.rs new file mode 100644 index 0000000000000..c19f3327fbb41 --- /dev/null +++ b/src/test/run-pass/issue-21140.rs @@ -0,0 +1,15 @@ +// Copyright 2015 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. + +pub trait Trait where Self::Out: std::fmt::Display { + type Out; +} + +fn main() {}