diff --git a/src/doc/guide.md b/src/doc/guide.md index f6aa04df1b9e0..d98f7c393f038 100644 --- a/src/doc/guide.md +++ b/src/doc/guide.md @@ -777,7 +777,7 @@ fn add_one(x: int) -> int { x + 1; } -note: consider removing this semicolon: +help: consider removing this semicolon: x + 1; ^ ``` @@ -4467,18 +4467,19 @@ see why consumers matter. ## Iterators -As we've said before, an iterator is something that we can call the `.next()` -method on repeatedly, and it gives us a sequence of things. Because you need -to call the method, this means that iterators are **lazy**. This code, for -example, does not actually generate the numbers `1-100`, and just creates a -value that represents the sequence: +As we've said before, an iterator is something that we can call the +`.next()` method on repeatedly, and it gives us a sequence of things. +Because you need to call the method, this means that iterators +are **lazy** and don't need to generate all of the values upfront. +This code, for example, does not actually generate the numbers +`1-100`, and just creates a value that represents the sequence: ```{rust} let nums = range(1i, 100i); ``` Since we didn't do anything with the range, it didn't generate the sequence. -Once we add the consumer: +Let's add the consumer: ```{rust} let nums = range(1i, 100i).collect::>(); @@ -4507,8 +4508,8 @@ std::iter::count(1i, 5i); ``` This iterator counts up from one, adding five each time. It will give -you a new integer every time, forever. Well, technically, until the -maximum number that an `int` can represent. But since iterators are lazy, +you a new integer every time, forever (well, technically, until it reaches the +maximum number representable by an `int`). But since iterators are lazy, that's okay! You probably don't want to use `collect()` on it, though... That's enough about iterators. Iterator adapters are the last concept @@ -5251,8 +5252,8 @@ to do something that it can't currently do? You may be able to write a macro to extend Rust's capabilities. You've already used one macro extensively: `println!`. When we invoke -a Rust macro, we need to use the exclamation mark (`!`). There's two reasons -that this is true: the first is that it makes it clear when you're using a +a Rust macro, we need to use the exclamation mark (`!`). There are two reasons +why this is so: the first is that it makes it clear when you're using a macro. The second is that macros allow for flexible syntax, and so Rust must be able to tell where a macro starts and ends. The `!(...)` helps with this. @@ -5267,7 +5268,7 @@ println!("x is: {}", x); The `println!` macro does a few things: -1. It parses the string to find any `{}`s +1. It parses the string to find any `{}`s. 2. It checks that the number of `{}`s matches the number of other arguments. 3. It generates a bunch of Rust code, taking this in mind. @@ -5276,8 +5277,8 @@ Rust will generate code that takes all of the types into account. If `println!` was a function, it could still do this type checking, but it would happen at run time rather than compile time. -We can check this out using a special flag to `rustc`. This code, in a file -`print.rs`: +We can check this out using a special flag to `rustc`. Put this code in a file +called `print.rs`: ```{rust} fn main() { @@ -5286,7 +5287,7 @@ fn main() { } ``` -Can have its macros expanded like this: `rustc print.rs --pretty=expanded`, will +You can have the macros expanded like this: `rustc print.rs --pretty=expanded` – which will give us this huge result: ```{rust,ignore} @@ -5325,12 +5326,12 @@ invoke the `println_args` function with the generated arguments. This is the code that Rust actually compiles. You can see all of the extra information that's here. We get all of the type safety and options that it provides, but at compile time, and without needing to type all of this out. -This is how macros are powerful. Without them, you would need to type all of -this by hand to get a type checked `println`. +This is how macros are powerful: without them you would need to type all of +this by hand to get a type-checked `println`. For more on macros, please consult [the Macros Guide](guide-macros.html). -Macros are a very advanced and still slightly experimental feature, but don't -require a deep understanding to call, since they look just like functions. The +Macros are a very advanced and still slightly experimental feature, but they don't +require a deep understanding to be called, since they look just like functions. The Guide can help you if you want to write your own. # Unsafe @@ -5347,8 +5348,8 @@ keyword, which indicates that the function may not behave properly. Second, if you'd like to create some sort of shared-memory data structure, Rust won't allow it, because memory must be owned by a single owner. However, if -you're planning on making access to that shared memory safe, such as with a -mutex, _you_ know that it's safe, but Rust can't know. Writing an `unsafe` +you're planning on making access to that shared memory safe – such as with a +mutex – _you_ know that it's safe, but Rust can't know. Writing an `unsafe` block allows you to ask the compiler to trust you. In this case, the _internal_ implementation of the mutex is considered unsafe, but the _external_ interface we present is safe. This allows it to be effectively used in normal Rust, while diff --git a/src/doc/reference.md b/src/doc/reference.md index 6f165b679a3ec..96d6bece23072 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -831,7 +831,7 @@ mod math { } ``` -Modules and types share the same namespace. Declaring a named type that has +Modules and types share the same namespace. Declaring a named type with the same name as a module in scope is forbidden: that is, a type definition, trait, struct, enumeration, or type parameter can't shadow the name of a module in scope, or vice versa. @@ -870,8 +870,8 @@ view_item : extern_crate_decl | use_decl ; ``` A view item manages the namespace of a module. View items do not define new -items, but rather, simply change other items' visibility. There are several -kinds of view item: +items, but rather, simply change other items' visibility. There are two +kinds of view items: * [`extern crate` declarations](#extern-crate-declarations) * [`use` declarations](#use-declarations) @@ -896,7 +896,7 @@ external crate when it was compiled. If no `crateid` is provided, a default `name` attribute is assumed, equal to the `ident` given in the `extern_crate_decl`. -Four examples of `extern crate` declarations: +Three examples of `extern crate` declarations: ```{.ignore} extern crate pcre; diff --git a/src/etc/vim/autoload/rust.vim b/src/etc/vim/autoload/rust.vim index c6b9b314da5c4..fe8e743e7826d 100644 --- a/src/etc/vim/autoload/rust.vim +++ b/src/etc/vim/autoload/rust.vim @@ -178,14 +178,14 @@ function! s:WithPath(func, ...) call mkdir(tmpdir) let save_cwd = getcwd() - silent exe 'lcd' tmpdir + silent exe 'lcd' fnameescape(tmpdir) let path = 'unnamed.rs' let save_mod = &mod set nomod - silent exe 'keepalt write! ' . path + silent exe 'keepalt write! ' . fnameescape(path) if pathisempty silent keepalt 0file endif @@ -195,10 +195,10 @@ function! s:WithPath(func, ...) call call(a:func, [path] + a:000) finally - if exists("save_mod") | let &mod = save_mod | endif - if exists("save_write") | let &write = save_write | endif - if exists("save_cwd") | silent exe 'lcd' save_cwd | endif - if exists("tmpdir") | silent call s:RmDir(tmpdir) | endif + if exists("save_mod") | let &mod = save_mod | endif + if exists("save_write") | let &write = save_write | endif + if exists("save_cwd") | silent exe 'lcd' fnameescape(save_cwd) | endif + if exists("tmpdir") | silent call s:RmDir(tmpdir) | endif endtry endfunction diff --git a/src/libcore/result.rs b/src/libcore/result.rs index 82da972f68a35..5b75e98baefe2 100644 --- a/src/libcore/result.rs +++ b/src/libcore/result.rs @@ -276,7 +276,6 @@ #![stable] -use clone::Clone; use cmp::PartialEq; use std::fmt::Show; use slice; diff --git a/src/libcore/str.rs b/src/libcore/str.rs index 3b29c25787292..8937f2a946a85 100644 --- a/src/libcore/str.rs +++ b/src/libcore/str.rs @@ -19,7 +19,6 @@ use mem; use char; use char::Char; -use clone::Clone; use cmp; use cmp::{PartialEq, Eq}; use default::Default; diff --git a/src/librand/distributions/mod.rs b/src/librand/distributions/mod.rs index 06bd04814c00b..6606031989151 100644 --- a/src/librand/distributions/mod.rs +++ b/src/librand/distributions/mod.rs @@ -227,6 +227,13 @@ fn ziggurat( // creating a f64), so we might as well reuse some to save // generating a whole extra random number. (Seems to be 15% // faster.) + // + // This unfortunately misses out on the benefits of direct + // floating point generation if an RNG like dSMFT is + // used. (That is, such RNGs create floats directly, highly + // efficiently and overload next_f32/f64, so by not calling it + // this may be slower than it would be otherwise.) + // FIXME: investigate/optimise for the above. let bits: u64 = rng.gen(); let i = (bits & 0xff) as uint; let f = (bits >> 11) as f64 / SCALE; diff --git a/src/librand/lib.rs b/src/librand/lib.rs index 405b70492a3aa..3c528c564a7ae 100644 --- a/src/librand/lib.rs +++ b/src/librand/lib.rs @@ -78,6 +78,46 @@ pub trait Rng { (self.next_u32() as u64 << 32) | (self.next_u32() as u64) } + /// Return the next random f32 selected from the half-open + /// interval `[0, 1)`. + /// + /// By default this is implemented in terms of `next_u32`, but a + /// random number generator which can generate numbers satisfying + /// the requirements directly can overload this for performance. + /// It is required that the return value lies in `[0, 1)`. + /// + /// See `Closed01` for the closed interval `[0,1]`, and + /// `Open01` for the open interval `(0,1)`. + fn next_f32(&mut self) -> f32 { + const MANTISSA_BITS: uint = 24; + const IGNORED_BITS: uint = 8; + const SCALE: f32 = (1u64 << MANTISSA_BITS) as f32; + + // using any more than `MANTISSA_BITS` bits will + // cause (e.g.) 0xffff_ffff to correspond to 1 + // exactly, so we need to drop some (8 for f32, 11 + // for f64) to guarantee the open end. + (self.next_u32() >> IGNORED_BITS) as f32 / SCALE + } + + /// Return the next random f64 selected from the half-open + /// interval `[0, 1)`. + /// + /// By default this is implemented in terms of `next_u64`, but a + /// random number generator which can generate numbers satisfying + /// the requirements directly can overload this for performance. + /// It is required that the return value lies in `[0, 1)`. + /// + /// See `Closed01` for the closed interval `[0,1]`, and + /// `Open01` for the open interval `(0,1)`. + fn next_f64(&mut self) -> f64 { + const MANTISSA_BITS: uint = 53; + const IGNORED_BITS: uint = 11; + const SCALE: f64 = (1u64 << MANTISSA_BITS) as f64; + + (self.next_u64() >> IGNORED_BITS) as f64 / SCALE + } + /// Fill `dest` with random data. /// /// This has a default implementation in terms of `next_u64` and diff --git a/src/librand/rand_impls.rs b/src/librand/rand_impls.rs index 77433877ec668..96f40bcc1565e 100644 --- a/src/librand/rand_impls.rs +++ b/src/librand/rand_impls.rs @@ -96,11 +96,11 @@ impl Rand for u64 { } macro_rules! float_impls { - ($mod_name:ident, $ty:ty, $mantissa_bits:expr, $method_name:ident, $ignored_bits:expr) => { + ($mod_name:ident, $ty:ty, $mantissa_bits:expr, $method_name:ident) => { mod $mod_name { use {Rand, Rng, Open01, Closed01}; - static SCALE: $ty = (1u64 << $mantissa_bits) as $ty; + const SCALE: $ty = (1u64 << $mantissa_bits) as $ty; impl Rand for $ty { /// Generate a floating point number in the half-open @@ -110,11 +110,7 @@ macro_rules! float_impls { /// and `Open01` for the open interval `(0,1)`. #[inline] fn rand(rng: &mut R) -> $ty { - // using any more than `mantissa_bits` bits will - // cause (e.g.) 0xffff_ffff to correspond to 1 - // exactly, so we need to drop some (8 for f32, 11 - // for f64) to guarantee the open end. - (rng.$method_name() >> $ignored_bits) as $ty / SCALE + rng.$method_name() } } impl Rand for Open01<$ty> { @@ -124,23 +120,22 @@ macro_rules! float_impls { // the precision of f64/f32 at 1.0), so that small // numbers are larger than 0, but large numbers // aren't pushed to/above 1. - Open01(((rng.$method_name() >> $ignored_bits) as $ty + 0.25) / SCALE) + Open01(rng.$method_name() + 0.25 / SCALE) } } impl Rand for Closed01<$ty> { #[inline] fn rand(rng: &mut R) -> Closed01<$ty> { - // divide by the maximum value of the numerator to - // get a non-zero probability of getting exactly - // 1.0. - Closed01((rng.$method_name() >> $ignored_bits) as $ty / (SCALE - 1.0)) + // rescale so that 1.0 - epsilon becomes 1.0 + // precisely. + Closed01(rng.$method_name() * SCALE / (SCALE - 1.0)) } } } } } -float_impls! { f64_rand_impls, f64, 53, next_u64, 11 } -float_impls! { f32_rand_impls, f32, 24, next_u32, 8 } +float_impls! { f64_rand_impls, f64, 53, next_f64 } +float_impls! { f32_rand_impls, f32, 24, next_f32 } impl Rand for char { #[inline] diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs index e52e1396b238f..f83facbb621ea 100644 --- a/src/librustc/lint/builtin.rs +++ b/src/librustc/lint/builtin.rs @@ -39,7 +39,7 @@ use std::cmp; use std::collections::HashMap; use std::collections::hash_map::{Occupied, Vacant}; use std::slice; -use std::{int, i8, i16, i32, i64, uint, u8, u16, u32, u64, f32, f64}; +use std::{i8, i16, i32, i64, u8, u16, u32, u64, f32, f64}; use syntax::abi; use syntax::ast_map; use syntax::ast_util::is_shift_binop; @@ -180,19 +180,19 @@ impl LintPass for TypeLimits { if is_shift_binop(binop) { let opt_ty_bits = match ty::get(ty::expr_ty(cx.tcx, &**l)).sty { - ty::ty_int(t) => Some(int_ty_bits(t)), - ty::ty_uint(t) => Some(uint_ty_bits(t)), + ty::ty_int(t) => Some(int_ty_bits(t, cx.sess().targ_cfg.int_type)), + ty::ty_uint(t) => Some(uint_ty_bits(t, cx.sess().targ_cfg.uint_type)), _ => None }; if let Some(bits) = opt_ty_bits { let exceeding = if let ast::ExprLit(ref lit) = r.node { - if let ast::LitInt(shift, _) = lit.node { shift > bits } + if let ast::LitInt(shift, _) = lit.node { shift >= bits } else { false } } else { match eval_const_expr_partial(cx.tcx, &**r) { - Ok(const_int(shift)) => { shift as u64 > bits }, - Ok(const_uint(shift)) => { shift > bits }, + Ok(const_int(shift)) => { shift as u64 >= bits }, + Ok(const_uint(shift)) => { shift >= bits }, _ => { false } } }; @@ -312,9 +312,9 @@ impl LintPass for TypeLimits { } } - fn int_ty_bits(int_ty: ast::IntTy) -> u64 { + fn int_ty_bits(int_ty: ast::IntTy, target_int_ty: ast::IntTy) -> u64 { match int_ty { - ast::TyI => int::BITS as u64, + ast::TyI => int_ty_bits(target_int_ty, target_int_ty), ast::TyI8 => i8::BITS as u64, ast::TyI16 => i16::BITS as u64, ast::TyI32 => i32::BITS as u64, @@ -322,9 +322,9 @@ impl LintPass for TypeLimits { } } - fn uint_ty_bits(uint_ty: ast::UintTy) -> u64 { + fn uint_ty_bits(uint_ty: ast::UintTy, target_uint_ty: ast::UintTy) -> u64 { match uint_ty { - ast::TyU => uint::BITS as u64, + ast::TyU => uint_ty_bits(target_uint_ty, target_uint_ty), ast::TyU8 => u8::BITS as u64, ast::TyU16 => u16::BITS as u64, ast::TyU32 => u32::BITS as u64, diff --git a/src/librustc/lint/context.rs b/src/librustc/lint/context.rs index a18d91196e04d..6da74eee8a319 100644 --- a/src/librustc/lint/context.rs +++ b/src/librustc/lint/context.rs @@ -532,7 +532,7 @@ impl<'a, 'tcx> Context<'a, 'tcx> { } } - fn visit_ids(&self, f: |&mut ast_util::IdVisitor|) { + fn visit_ids(&mut self, f: |&mut ast_util::IdVisitor|) { let mut v = ast_util::IdVisitor { operation: self, pass_through_items: false, @@ -749,7 +749,7 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { // Output any lints that were previously added to the session. impl<'a, 'tcx> IdVisitingOperation for Context<'a, 'tcx> { - fn visit_id(&self, id: ast::NodeId) { + fn visit_id(&mut self, id: ast::NodeId) { match self.tcx.sess.lints.borrow_mut().pop(&id) { None => {} Some(lints) => { diff --git a/src/librustc/metadata/common.rs b/src/librustc/metadata/common.rs index bc58097b86072..a04f94c31bfc5 100644 --- a/src/librustc/metadata/common.rs +++ b/src/librustc/metadata/common.rs @@ -148,7 +148,7 @@ impl astencode_tag { pub fn from_uint(value : uint) -> Option { let is_a_tag = first_astencode_tag <= value && value <= last_astencode_tag; if !is_a_tag { None } else { - Some(unsafe { mem::transmute(value) }) + Some(unsafe { mem::transmute::(value) }) } } } @@ -247,4 +247,3 @@ pub const tag_type_param_def: uint = 0xa5; pub const tag_item_generics: uint = 0xa6; pub const tag_method_ty_generics: uint = 0xa7; - diff --git a/src/librustc/metadata/decoder.rs b/src/librustc/metadata/decoder.rs index 20171ecfd99f7..92f3b888dcd52 100644 --- a/src/librustc/metadata/decoder.rs +++ b/src/librustc/metadata/decoder.rs @@ -36,7 +36,7 @@ use std::io::extensions::u64_from_be_bytes; use std::io; use std::collections::hash_map::HashMap; use std::rc::Rc; -use std::u64; +use std::str; use rbml::reader; use rbml; use serialize::Decodable; @@ -215,7 +215,9 @@ fn each_reexport(d: rbml::Doc, f: |rbml::Doc| -> bool) -> bool { fn variant_disr_val(d: rbml::Doc) -> Option { reader::maybe_get_doc(d, tag_disr_val).and_then(|val_doc| { - reader::with_doc_data(val_doc, |data| u64::parse_bytes(data, 10u)) + reader::with_doc_data(val_doc, |data| { + str::from_utf8(data).and_then(from_str) + }) }) } diff --git a/src/librustc/metadata/encoder.rs b/src/librustc/metadata/encoder.rs index a5d3cc1f12c29..fd389c1f31426 100644 --- a/src/librustc/metadata/encoder.rs +++ b/src/librustc/metadata/encoder.rs @@ -29,7 +29,6 @@ use serialize::Encodable; use std::cell::RefCell; use std::hash::Hash; use std::hash; -use std::mem; use std::collections::HashMap; use syntax::abi; use syntax::ast::*; @@ -1508,44 +1507,36 @@ fn my_visit_expr(_e: &Expr) { } fn my_visit_item(i: &Item, rbml_w: &mut Encoder, - ecx_ptr: *const int, + ecx: &EncodeContext, index: &mut Vec>) { - let mut rbml_w = unsafe { rbml_w.unsafe_clone() }; - // See above - let ecx: &EncodeContext = unsafe { mem::transmute(ecx_ptr) }; ecx.tcx.map.with_path(i.id, |path| { - encode_info_for_item(ecx, &mut rbml_w, i, index, path, i.vis); + encode_info_for_item(ecx, rbml_w, i, index, path, i.vis); }); } fn my_visit_foreign_item(ni: &ForeignItem, rbml_w: &mut Encoder, - ecx_ptr:*const int, + ecx: &EncodeContext, index: &mut Vec>) { - // See above - let ecx: &EncodeContext = unsafe { mem::transmute(ecx_ptr) }; debug!("writing foreign item {}::{}", ecx.tcx.map.path_to_string(ni.id), token::get_ident(ni.ident)); - let mut rbml_w = unsafe { - rbml_w.unsafe_clone() - }; let abi = ecx.tcx.map.get_foreign_abi(ni.id); ecx.tcx.map.with_path(ni.id, |path| { - encode_info_for_foreign_item(ecx, &mut rbml_w, + encode_info_for_foreign_item(ecx, rbml_w, ni, index, path, abi); }); } -struct EncodeVisitor<'a,'b:'a> { +struct EncodeVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { rbml_w_for_visit_item: &'a mut Encoder<'b>, - ecx_ptr:*const int, + ecx: &'a EncodeContext<'c,'tcx>, index: &'a mut Vec>, } -impl<'a, 'b, 'v> Visitor<'v> for EncodeVisitor<'a, 'b> { +impl<'a, 'b, 'c, 'tcx, 'v> Visitor<'v> for EncodeVisitor<'a, 'b, 'c, 'tcx> { fn visit_expr(&mut self, ex: &Expr) { visit::walk_expr(self, ex); my_visit_expr(ex); @@ -1554,14 +1545,14 @@ impl<'a, 'b, 'v> Visitor<'v> for EncodeVisitor<'a, 'b> { visit::walk_item(self, i); my_visit_item(i, self.rbml_w_for_visit_item, - self.ecx_ptr, + self.ecx, self.index); } fn visit_foreign_item(&mut self, ni: &ForeignItem) { visit::walk_foreign_item(self, ni); my_visit_foreign_item(ni, self.rbml_w_for_visit_item, - self.ecx_ptr, + self.ecx, self.index); } } @@ -1585,11 +1576,9 @@ fn encode_info_for_items(ecx: &EncodeContext, syntax::parse::token::special_idents::invalid, Public); - // See comment in `encode_side_tables_for_ii` in astencode - let ecx_ptr: *const int = unsafe { mem::transmute(ecx) }; visit::walk_crate(&mut EncodeVisitor { index: &mut index, - ecx_ptr: ecx_ptr, + ecx: ecx, rbml_w_for_visit_item: &mut *rbml_w, }, krate); diff --git a/src/librustc/metadata/loader.rs b/src/librustc/metadata/loader.rs index 7b67def405176..738eeaae6a5f8 100644 --- a/src/librustc/metadata/loader.rs +++ b/src/librustc/metadata/loader.rs @@ -231,7 +231,6 @@ use std::c_str::ToCStr; use std::cmp; use std::io::fs::PathExtensions; use std::io; -use std::mem; use std::ptr; use std::slice; use std::string; @@ -287,8 +286,8 @@ pub struct Library { pub struct ArchiveMetadata { _archive: ArchiveRO, - // See comments in ArchiveMetadata::new for why this is static - data: &'static [u8], + // points into self._archive + data: *const [u8], } pub struct CratePaths { @@ -709,33 +708,21 @@ pub fn note_crate_name(diag: &SpanHandler, name: &str) { impl ArchiveMetadata { fn new(ar: ArchiveRO) -> Option { - let data: &'static [u8] = { - let data = match ar.read(METADATA_FILENAME) { - Some(data) => data, - None => { - debug!("didn't find '{}' in the archive", METADATA_FILENAME); - return None; - } - }; - // This data is actually a pointer inside of the archive itself, but - // we essentially want to cache it because the lookup inside the - // archive is a fairly expensive operation (and it's queried for - // *very* frequently). For this reason, we transmute it to the - // static lifetime to put into the struct. Note that the buffer is - // never actually handed out with a static lifetime, but rather the - // buffer is loaned with the lifetime of this containing object. - // Hence, we're guaranteed that the buffer will never be used after - // this object is dead, so this is a safe operation to transmute and - // store the data as a static buffer. - unsafe { mem::transmute(data) } + let data = match ar.read(METADATA_FILENAME) { + Some(data) => data as *const [u8], + None => { + debug!("didn't find '{}' in the archive", METADATA_FILENAME); + return None; + } }; + Some(ArchiveMetadata { _archive: ar, data: data, }) } - pub fn as_slice<'a>(&'a self) -> &'a [u8] { self.data } + pub fn as_slice<'a>(&'a self) -> &'a [u8] { unsafe { &*self.data } } } // Just a small wrapper to time how long reading metadata takes. @@ -798,7 +785,7 @@ fn get_metadata_section_imp(os: abi::Os, filename: &Path) -> Result ast::DefId { let crate_part = buf[0u..colon_idx]; let def_part = buf[colon_idx + 1u..len]; - let crate_num = match uint::parse_bytes(crate_part, 10u) { + let crate_num = match str::from_utf8(crate_part).and_then(from_str::) { Some(cn) => cn as ast::CrateNum, None => panic!("internal error: parse_def_id: crate number expected, found {}", crate_part) }; - let def_num = match uint::parse_bytes(def_part, 10u) { + let def_num = match str::from_utf8(def_part).and_then(from_str::) { Some(dn) => dn as ast::NodeId, None => panic!("internal error: parse_def_id: id expected, found {}", def_part) diff --git a/src/librustc/middle/astencode.rs b/src/librustc/middle/astencode.rs index 988f7d46f5f95..0074c15defb0e 100644 --- a/src/librustc/middle/astencode.rs +++ b/src/librustc/middle/astencode.rs @@ -38,9 +38,7 @@ use syntax::parse::token; use syntax::ptr::P; use syntax; -use libc; use std::io::Seek; -use std::mem; use std::rc::Rc; use rbml::io::SeekableMemWriter; @@ -81,7 +79,7 @@ pub fn encode_inlined_item(ecx: &e::EncodeContext, e::IIForeignRef(i) => i.id, e::IITraitItemRef(_, &ast::ProvidedMethod(ref m)) => m.id, e::IITraitItemRef(_, &ast::RequiredMethod(ref m)) => m.id, - e::IITraitItemRef(_, &ast::TypeTraitItem(ref ti)) => ti.id, + e::IITraitItemRef(_, &ast::TypeTraitItem(ref ti)) => ti.ty_param.id, e::IIImplItemRef(_, &ast::MethodImplItem(ref m)) => m.id, e::IIImplItemRef(_, &ast::TypeImplItem(ref ti)) => ti.id, }; @@ -156,7 +154,7 @@ pub fn decode_inlined_item<'tcx>(cdata: &cstore::crate_metadata, match *ti { ast::ProvidedMethod(ref m) => m.pe_ident(), ast::RequiredMethod(ref ty_m) => ty_m.ident, - ast::TypeTraitItem(ref ti) => ti.ident, + ast::TypeTraitItem(ref ti) => ti.ty_param.ident, } }, ast::IIImplItem(_, ref m) => { @@ -711,8 +709,9 @@ impl<'a> vtable_decoder_helpers for reader::Decoder<'a> { { let types = self.read_to_vec(|this| Ok(f(this))).unwrap(); let selfs = self.read_to_vec(|this| Ok(f(this))).unwrap(); + let assocs = self.read_to_vec(|this| Ok(f(this))).unwrap(); let fns = self.read_to_vec(|this| Ok(f(this))).unwrap(); - VecPerParamSpace::new(types, selfs, fns) + VecPerParamSpace::new(types, selfs, assocs, fns) } fn read_vtable_res_with_key(&mut self, @@ -1122,27 +1121,15 @@ impl<'a> write_tag_and_id for Encoder<'a> { } } -struct SideTableEncodingIdVisitor<'a,'b:'a> { - ecx_ptr: *const libc::c_void, - new_rbml_w: &'a mut Encoder<'b>, +struct SideTableEncodingIdVisitor<'a, 'b:'a, 'c:'a, 'tcx:'c> { + ecx: &'a e::EncodeContext<'c, 'tcx>, + rbml_w: &'a mut Encoder<'b>, } -impl<'a,'b> ast_util::IdVisitingOperation for - SideTableEncodingIdVisitor<'a,'b> { - fn visit_id(&self, id: ast::NodeId) { - // Note: this will cause a copy of rbml_w, which is bad as - // it is mutable. But I believe it's harmless since we generate - // balanced EBML. - // - // FIXME(pcwalton): Don't copy this way. - let mut new_rbml_w = unsafe { - self.new_rbml_w.unsafe_clone() - }; - // See above - let ecx: &e::EncodeContext = unsafe { - mem::transmute(self.ecx_ptr) - }; - encode_side_tables_for_id(ecx, &mut new_rbml_w, id) +impl<'a, 'b, 'c, 'tcx> ast_util::IdVisitingOperation for + SideTableEncodingIdVisitor<'a, 'b, 'c, 'tcx> { + fn visit_id(&mut self, id: ast::NodeId) { + encode_side_tables_for_id(self.ecx, self.rbml_w, id) } } @@ -1150,18 +1137,9 @@ fn encode_side_tables_for_ii(ecx: &e::EncodeContext, rbml_w: &mut Encoder, ii: &ast::InlinedItem) { rbml_w.start_tag(c::tag_table as uint); - let mut new_rbml_w = unsafe { - rbml_w.unsafe_clone() - }; - - // Because the ast visitor uses @IdVisitingOperation, I can't pass in - // ecx directly, but /I/ know that it'll be fine since the lifetime is - // tied to the CrateContext that lives throughout this entire section. - ast_util::visit_ids_for_inlined_item(ii, &SideTableEncodingIdVisitor { - ecx_ptr: unsafe { - mem::transmute(ecx) - }, - new_rbml_w: &mut new_rbml_w, + ast_util::visit_ids_for_inlined_item(ii, &mut SideTableEncodingIdVisitor { + ecx: ecx, + rbml_w: rbml_w }); rbml_w.end_tag(); } diff --git a/src/librustc/middle/borrowck/check_loans.rs b/src/librustc/middle/borrowck/check_loans.rs index de61f4f2b404c..073b6dae0c385 100644 --- a/src/librustc/middle/borrowck/check_loans.rs +++ b/src/librustc/middle/borrowck/check_loans.rs @@ -789,7 +789,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> { assignment_span, format!("cannot assign to {}", self.bccx.cmt_to_string(&*assignee_cmt)).as_slice()); - self.bccx.span_note( + self.bccx.span_help( self.tcx().map.span(upvar_id.closure_expr_id), "consider changing this closure to take self by mutable reference"); } else { diff --git a/src/librustc/middle/borrowck/gather_loans/move_error.rs b/src/librustc/middle/borrowck/gather_loans/move_error.rs index 9d4d9fcf9a9d7..ab6ff08c9d4e8 100644 --- a/src/librustc/middle/borrowck/gather_loans/move_error.rs +++ b/src/librustc/middle/borrowck/gather_loans/move_error.rs @@ -148,9 +148,12 @@ fn note_move_destination(bccx: &BorrowckCtxt, if is_first_note { bccx.span_note( move_to_span, - format!("attempting to move value to here (to prevent the move, \ + "attempting to move value to here"); + bccx.span_help( + move_to_span, + format!("to prevent the move, \ use `ref {0}` or `ref mut {0}` to capture value by \ - reference)", + reference", pat_name).as_slice()); } else { bccx.span_note(move_to_span, diff --git a/src/librustc/middle/borrowck/mod.rs b/src/librustc/middle/borrowck/mod.rs index ae8e975e843b0..4e2b280eba686 100644 --- a/src/librustc/middle/borrowck/mod.rs +++ b/src/librustc/middle/borrowck/mod.rs @@ -527,8 +527,8 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { r).as_slice()) } }; - let suggestion = move_suggestion(self.tcx, expr_ty, - "moved by default (use `copy` to override)"); + let (suggestion, _) = move_suggestion(self.tcx, expr_ty, + ("moved by default", "")); self.tcx.sess.span_note( expr_span, format!("`{}` moved here{} because it has type `{}`, which is {}", @@ -540,13 +540,15 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { move_data::MovePat => { let pat_ty = ty::node_id_to_type(self.tcx, the_move.id); - self.tcx.sess.span_note(self.tcx.map.span(the_move.id), + let span = self.tcx.map.span(the_move.id); + self.tcx.sess.span_note(span, format!("`{}` moved here{} because it has type `{}`, \ - which is moved by default (use `ref` to \ - override)", + which is moved by default", ol, moved_lp_msg, pat_ty.user_string(self.tcx)).as_slice()); + self.tcx.sess.span_help(span, + "use `ref` to override"); } move_data::Captured => { @@ -563,9 +565,9 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { r).as_slice()) } }; - let suggestion = move_suggestion(self.tcx, expr_ty, - "moved by default (make a copy and \ - capture that instead to override)"); + let (suggestion, help) = move_suggestion(self.tcx, expr_ty, + ("moved by default", "make a copy and \ + capture that instead to override")); self.tcx.sess.span_note( expr_span, format!("`{}` moved into closure environment here{} because it \ @@ -574,21 +576,23 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { moved_lp_msg, expr_ty.user_string(self.tcx), suggestion).as_slice()); + self.tcx.sess.span_help(expr_span, help); } } - fn move_suggestion(tcx: &ty::ctxt, ty: ty::t, default_msg: &'static str) - -> &'static str { + fn move_suggestion(tcx: &ty::ctxt, ty: ty::t, default_msgs: (&'static str, &'static str)) + -> (&'static str, &'static str) { match ty::get(ty).sty { ty::ty_closure(box ty::ClosureTy { store: ty::RegionTraitStore(..), .. }) => - "a non-copyable stack closure (capture it in a new closure, \ - e.g. `|x| f(x)`, to override)", + ("a non-copyable stack closure", + "capture it in a new closure, e.g. `|x| f(x)`, to override"), _ if ty::type_moves_by_default(tcx, ty) => - "non-copyable (perhaps you meant to use clone()?)", - _ => default_msg, + ("non-copyable", + "perhaps you meant to use `clone()`?"), + _ => default_msgs, } } } @@ -733,7 +737,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { self.tcx.sess.span_err(span, format!("{} in a captured outer \ variable in an `Fn` closure", prefix).as_slice()); - span_note!(self.tcx.sess, self.tcx.map.span(id), + span_help!(self.tcx.sess, self.tcx.map.span(id), "consider changing this closure to take self by mutable reference"); } mc::AliasableStatic(..) | @@ -750,7 +754,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { } if is_closure { - self.tcx.sess.span_note( + self.tcx.sess.span_help( span, "closures behind references must be called via `&mut`"); } @@ -770,7 +774,7 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { _ => unreachable!() }; if kind == ty::FnUnboxedClosureKind { - self.tcx.sess.span_note( + self.tcx.sess.span_help( self.tcx.map.span(upvar_id.closure_expr_id), "consider changing this closure to take \ self by mutable reference"); @@ -787,15 +791,20 @@ impl<'a, 'tcx> BorrowckCtxt<'a, 'tcx> { sub_scope, "..."); let suggestion = if is_statement_scope(self.tcx, super_scope) { - "; consider using a `let` binding to increase its lifetime" + Some("consider using a `let` binding to increase its lifetime") } else { - "" + None }; - note_and_explain_region( + let span = note_and_explain_region( self.tcx, "...but borrowed value is only valid for ", super_scope, - suggestion); + ""); + match (span, suggestion) { + (_, None) => {}, + (Some(span), Some(msg)) => self.tcx.sess.span_help(span, msg), + (None, Some(msg)) => self.tcx.sess.help(msg), + } } err_borrowed_pointer_too_short(loan_scope, ptr_scope) => { diff --git a/src/librustc/middle/dependency_format.rs b/src/librustc/middle/dependency_format.rs index 3baa8eb0cc040..15ca00f6a7fe9 100644 --- a/src/librustc/middle/dependency_format.rs +++ b/src/librustc/middle/dependency_format.rs @@ -213,7 +213,7 @@ fn add_library(sess: &session::Session, sess.err(format!("cannot satisfy dependencies so `{}` only \ shows up once", data.name).as_slice()); - sess.note("having upstream crates all available in one format \ + sess.help("having upstream crates all available in one format \ will likely make this go away"); } } diff --git a/src/librustc/middle/liveness.rs b/src/librustc/middle/liveness.rs index 80eba56ea6ce0..b5847a94b8d9b 100644 --- a/src/librustc/middle/liveness.rs +++ b/src/librustc/middle/liveness.rs @@ -118,7 +118,6 @@ use util::nodemap::NodeMap; use std::fmt; use std::io; -use std::mem::transmute; use std::rc::Rc; use std::str; use std::uint; @@ -380,10 +379,7 @@ fn visit_fn(ir: &mut IrMaps, // swap in a new set of IR maps for this function body: let mut fn_maps = IrMaps::new(ir.tcx); - unsafe { - debug!("creating fn_maps: {}", - transmute::<&IrMaps, *const IrMaps>(&fn_maps)); - } + debug!("creating fn_maps: {}", &fn_maps as *const IrMaps); for arg in decl.inputs.iter() { pat_util::pat_bindings(&ir.tcx.def_map, @@ -1568,7 +1564,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hi: original_span.hi, expn_id: original_span.expn_id }; - self.ir.tcx.sess.span_note( + self.ir.tcx.sess.span_help( span_semicolon, "consider removing this semicolon:"); } } diff --git a/src/librustc/middle/privacy.rs b/src/librustc/middle/privacy.rs index 2256bd71e652c..4fbffa2a819d5 100644 --- a/src/librustc/middle/privacy.rs +++ b/src/librustc/middle/privacy.rs @@ -296,8 +296,8 @@ impl<'a, 'tcx, 'v> Visitor<'v> for EmbargoVisitor<'a, 'tcx> { self.exported_items.insert(m.id); } ast::TypeTraitItem(ref t) => { - debug!("typedef {}", t.id); - self.exported_items.insert(t.id); + debug!("typedef {}", t.ty_param.id); + self.exported_items.insert(t.ty_param.id); } } } diff --git a/src/librustc/middle/resolve.rs b/src/librustc/middle/resolve.rs index a2bea790c9f46..ed7d9296c701d 100644 --- a/src/librustc/middle/resolve.rs +++ b/src/librustc/middle/resolve.rs @@ -627,7 +627,10 @@ impl NameBindings { sp: Span) { // Merges the module with the existing type def or creates a new one. let modifiers = if is_public { PUBLIC } else { DefModifiers::empty() } | IMPORTABLE; - let module_ = Rc::new(Module::new(parent_link, def_id, kind, external, + let module_ = Rc::new(Module::new(parent_link, + def_id, + kind, + external, is_public)); let type_def = self.type_def.borrow().clone(); match type_def { @@ -1372,6 +1375,8 @@ impl<'a> Resolver<'a> { // Create the module and add all methods. match ty.node { TyPath(ref path, _, _) if path.segments.len() == 1 => { + // FIXME(18446) we should distinguish between the name of + // a trait and the name of an impl of that trait. let mod_name = path.segments.last().unwrap().identifier.name; let parent_opt = parent.module().children.borrow() @@ -1380,8 +1385,8 @@ impl<'a> Resolver<'a> { // It already exists Some(ref child) if child.get_module_if_available() .is_some() && - child.get_module().kind.get() == - ImplModuleKind => { + (child.get_module().kind.get() == ImplModuleKind || + child.get_module().kind.get() == TraitModuleKind) => { ModuleReducedGraphParent(child.get_module()) } Some(ref child) if child.get_module_if_available() @@ -1559,19 +1564,19 @@ impl<'a> Resolver<'a> { } ast::TypeTraitItem(ref associated_type) => { let def = DefAssociatedTy(local_def( - associated_type.id)); + associated_type.ty_param.id)); let name_bindings = - self.add_child(associated_type.ident.name, + self.add_child(associated_type.ty_param.ident.name, module_parent.clone(), ForbidDuplicateTypesAndValues, - associated_type.span); + associated_type.ty_param.span); // NB: not IMPORTABLE name_bindings.define_type(def, - associated_type.span, + associated_type.ty_param.span, PUBLIC); - (associated_type.ident.name, TypeTraitItemKind) + (associated_type.ty_param.ident.name, TypeTraitItemKind) } }; @@ -4218,7 +4223,7 @@ impl<'a> Resolver<'a> { impl_items.as_slice()); } - ItemTrait(ref generics, ref unbound, ref bounds, ref methods) => { + ItemTrait(ref generics, ref unbound, ref bounds, ref trait_items) => { // Create a new rib for the self type. let mut self_type_rib = Rib::new(ItemRibKind); @@ -4246,13 +4251,13 @@ impl<'a> Resolver<'a> { _ => {} } - for method in (*methods).iter() { - // Create a new rib for the method-specific type + for trait_item in (*trait_items).iter() { + // Create a new rib for the trait_item-specific type // parameters. // // FIXME #4951: Do we need a node ID here? - match *method { + match *trait_item { ast::RequiredMethod(ref ty_m) => { this.with_type_parameter_rib (HasTypeParameters(&ty_m.generics, @@ -4287,8 +4292,9 @@ impl<'a> Resolver<'a> { ProvidedMethod(m.id)), &**m) } - ast::TypeTraitItem(_) => { - visit::walk_trait_item(this, method); + ast::TypeTraitItem(ref data) => { + this.resolve_type_parameter(&data.ty_param); + visit::walk_trait_item(this, trait_item); } } } @@ -4477,20 +4483,25 @@ impl<'a> Resolver<'a> { fn resolve_type_parameters(&mut self, type_parameters: &OwnedSlice) { for type_parameter in type_parameters.iter() { - for bound in type_parameter.bounds.iter() { - self.resolve_type_parameter_bound(type_parameter.id, bound, - TraitBoundingTypeParameter); - } - match &type_parameter.unbound { - &Some(ref unbound) => - self.resolve_type_parameter_bound( - type_parameter.id, unbound, TraitBoundingTypeParameter), - &None => {} - } - match type_parameter.default { - Some(ref ty) => self.resolve_type(&**ty), - None => {} - } + self.resolve_type_parameter(type_parameter); + } + } + + fn resolve_type_parameter(&mut self, + type_parameter: &TyParam) { + for bound in type_parameter.bounds.iter() { + self.resolve_type_parameter_bound(type_parameter.id, bound, + TraitBoundingTypeParameter); + } + match &type_parameter.unbound { + &Some(ref unbound) => + self.resolve_type_parameter_bound( + type_parameter.id, unbound, TraitBoundingTypeParameter), + &None => {} + } + match type_parameter.default { + Some(ref ty) => self.resolve_type(&**ty), + None => {} } } @@ -4577,14 +4588,14 @@ impl<'a> Resolver<'a> { self.resolve_error(trait_reference.path.span, format!("`{}` is not a trait", self.path_names_to_string( - &trait_reference.path))); + &trait_reference.path))); // If it's a typedef, give a note match def { DefTy(..) => { self.session.span_note( - trait_reference.path.span, - format!("`type` aliases cannot \ + trait_reference.path.span, + format!("`type` aliases cannot \ be used for traits") .as_slice()); } @@ -5868,7 +5879,7 @@ impl<'a> Resolver<'a> { uses it like a function name", wrong_name).as_slice()); - self.session.span_note(expr.span, + self.session.span_help(expr.span, format!("Did you mean to write: \ `{} {{ /* fields */ }}`?", wrong_name).as_slice()); diff --git a/src/librustc/middle/save/span_utils.rs b/src/librustc/middle/save/span_utils.rs index 93ad29cff906a..14d8bf0cfed5c 100644 --- a/src/librustc/middle/save/span_utils.rs +++ b/src/librustc/middle/save/span_utils.rs @@ -31,13 +31,16 @@ impl<'a> SpanUtils<'a> { pub fn extent_str(&self, span: Span) -> String { let lo_loc = self.sess.codemap().lookup_char_pos(span.lo); let hi_loc = self.sess.codemap().lookup_char_pos(span.hi); - let lo_pos = self.sess.codemap().lookup_byte_offset(span.lo).pos; - let hi_pos = self.sess.codemap().lookup_byte_offset(span.hi).pos; - - format!("file_name,{},file_line,{},file_col,{},extent_start,{},\ - file_line_end,{},file_col_end,{},extent_end,{}", - lo_loc.file.name, lo_loc.line, lo_loc.col.to_uint(), lo_pos.to_uint(), - hi_loc.line, hi_loc.col.to_uint(), hi_pos.to_uint()) + let lo_pos = self.sess.codemap().bytepos_to_file_charpos(span.lo); + let hi_pos = self.sess.codemap().bytepos_to_file_charpos(span.hi); + let lo_pos_byte = self.sess.codemap().lookup_byte_offset(span.lo).pos; + let hi_pos_byte = self.sess.codemap().lookup_byte_offset(span.hi).pos; + + format!("file_name,{},file_line,{},file_col,{},extent_start,{},extent_start_bytes,{},\ + file_line_end,{},file_col_end,{},extent_end,{},extent_end_bytes,{}", + lo_loc.file.name, + lo_loc.line, lo_loc.col.to_uint(), lo_pos.to_uint(), lo_pos_byte.to_uint(), + hi_loc.line, hi_loc.col.to_uint(), hi_pos.to_uint(), hi_pos_byte.to_uint()) } // sub_span starts at span.lo, so we need to adjust the positions etc. @@ -92,7 +95,7 @@ impl<'a> SpanUtils<'a> { let mut toks = self.retokenise_span(span); let mut bracket_count = 0u; loop { - let ts = toks.next_token(); + let ts = toks.real_token(); if ts.tok == token::Eof { return self.make_sub_span(span, result) } @@ -115,7 +118,7 @@ impl<'a> SpanUtils<'a> { let mut toks = self.retokenise_span(span); let mut bracket_count = 0u; loop { - let ts = toks.next_token(); + let ts = toks.real_token(); if ts.tok == token::Eof { return None; } @@ -137,13 +140,13 @@ impl<'a> SpanUtils<'a> { // any brackets, or the last span. pub fn sub_span_for_meth_name(&self, span: Span) -> Option { let mut toks = self.retokenise_span(span); - let mut prev = toks.next_token(); + let mut prev = toks.real_token(); let mut result = None; let mut bracket_count = 0u; let mut last_span = None; while prev.tok != token::Eof { last_span = None; - let mut next = toks.next_token(); + let mut next = toks.real_token(); if (next.tok == token::OpenDelim(token::Paren) || next.tok == token::Lt) && @@ -156,7 +159,7 @@ impl<'a> SpanUtils<'a> { next.tok == token::ModSep { let old = prev; prev = next; - next = toks.next_token(); + next = toks.real_token(); if next.tok == token::Lt && old.tok.is_ident() { result = Some(old.sp); @@ -185,11 +188,11 @@ impl<'a> SpanUtils<'a> { // brackets, or the last span. pub fn sub_span_for_type_name(&self, span: Span) -> Option { let mut toks = self.retokenise_span(span); - let mut prev = toks.next_token(); + let mut prev = toks.real_token(); let mut result = None; let mut bracket_count = 0u; loop { - let next = toks.next_token(); + let next = toks.real_token(); if (next.tok == token::Lt || next.tok == token::Colon) && @@ -234,7 +237,7 @@ impl<'a> SpanUtils<'a> { // We keep track of how many brackets we're nested in let mut bracket_count = 0i; loop { - let ts = toks.next_token(); + let ts = toks.real_token(); if ts.tok == token::Eof { if bracket_count != 0 { let loc = self.sess.codemap().lookup_char_pos(span.lo); @@ -263,12 +266,12 @@ impl<'a> SpanUtils<'a> { pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option { let mut toks = self.retokenise_span(span); - let mut prev = toks.next_token(); + let mut prev = toks.real_token(); loop { if prev.tok == token::Eof { return None; } - let next = toks.next_token(); + let next = toks.real_token(); if next.tok == tok { return self.make_sub_span(span, Some(prev.sp)); } @@ -281,15 +284,16 @@ impl<'a> SpanUtils<'a> { keyword: keywords::Keyword) -> Option { let mut toks = self.retokenise_span(span); loop { - let ts = toks.next_token(); + let ts = toks.real_token(); if ts.tok == token::Eof { return None; } if ts.tok.is_keyword(keyword) { - let ts = toks.next_token(); + let ts = toks.real_token(); if ts.tok == token::Eof { return None } else { + println!("found keyword: {} at {}", ts, ts.sp); return self.make_sub_span(span, Some(ts.sp)); } } diff --git a/src/librustc/middle/stability.rs b/src/librustc/middle/stability.rs index 9cac97dc65941..7f6a73c83fa76 100644 --- a/src/librustc/middle/stability.rs +++ b/src/librustc/middle/stability.rs @@ -86,7 +86,7 @@ impl<'v> Visitor<'v> for Annotator { } } - TypeTraitItem(ref typedef) => (typedef.id, &typedef.attrs), + TypeTraitItem(ref typedef) => (typedef.ty_param.id, &typedef.attrs), }; self.annotate(id, attrs, |v| visit::walk_trait_item(v, t)); } diff --git a/src/librustc/middle/subst.rs b/src/librustc/middle/subst.rs index b986d4dd591f3..a29f99236e0cd 100644 --- a/src/librustc/middle/subst.rs +++ b/src/librustc/middle/subst.rs @@ -16,66 +16,10 @@ use middle::ty_fold::{TypeFoldable, TypeFolder}; use util::ppaux::Repr; use std::fmt; -use std::mem; -use std::raw; -use std::slice::{Items, MutItems}; +use std::slice::Items; use std::vec::Vec; use syntax::codemap::{Span, DUMMY_SP}; -/////////////////////////////////////////////////////////////////////////// -// HomogeneousTuple3 trait -// -// This could be moved into standard library at some point. - -trait HomogeneousTuple3 { - fn len(&self) -> uint; - fn as_slice<'a>(&'a self) -> &'a [T]; - fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T]; - fn iter<'a>(&'a self) -> Items<'a, T>; - fn iter_mut<'a>(&'a mut self) -> MutItems<'a, T>; - fn get<'a>(&'a self, index: uint) -> Option<&'a T>; - fn get_mut<'a>(&'a mut self, index: uint) -> Option<&'a mut T>; -} - -impl HomogeneousTuple3 for (T, T, T) { - fn len(&self) -> uint { - 3 - } - - fn as_slice<'a>(&'a self) -> &'a [T] { - unsafe { - let ptr: *const T = mem::transmute(self); - let slice = raw::Slice { data: ptr, len: 3 }; - mem::transmute(slice) - } - } - - fn as_mut_slice<'a>(&'a mut self) -> &'a mut [T] { - unsafe { - let ptr: *const T = mem::transmute(self); - let slice = raw::Slice { data: ptr, len: 3 }; - mem::transmute(slice) - } - } - - fn iter<'a>(&'a self) -> Items<'a, T> { - let slice: &'a [T] = self.as_slice(); - slice.iter() - } - - fn iter_mut<'a>(&'a mut self) -> MutItems<'a, T> { - self.as_mut_slice().iter_mut() - } - - fn get<'a>(&'a self, index: uint) -> Option<&'a T> { - self.as_slice().get(index) - } - - fn get_mut<'a>(&'a mut self, index: uint) -> Option<&'a mut T> { - Some(&mut self.as_mut_slice()[index]) // wrong: fallible - } -} - /////////////////////////////////////////////////////////////////////////// /** @@ -112,17 +56,18 @@ impl Substs { r: Vec) -> Substs { - Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new()), - VecPerParamSpace::new(r, Vec::new(), Vec::new())) + Substs::new(VecPerParamSpace::new(t, Vec::new(), Vec::new(), Vec::new()), + VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new())) } pub fn new_trait(t: Vec, r: Vec, + a: Vec, s: ty::t) -> Substs { - Substs::new(VecPerParamSpace::new(t, vec!(s), Vec::new()), - VecPerParamSpace::new(r, Vec::new(), Vec::new())) + Substs::new(VecPerParamSpace::new(t, vec!(s), a, Vec::new()), + VecPerParamSpace::new(r, Vec::new(), Vec::new(), Vec::new())) } pub fn erased(t: VecPerParamSpace) -> Substs @@ -226,21 +171,23 @@ impl RegionSubsts { #[deriving(PartialOrd, Ord, PartialEq, Eq, Clone, Hash, Encodable, Decodable, Show)] pub enum ParamSpace { - TypeSpace, // Type parameters attached to a type definition, trait, or impl - SelfSpace, // Self parameter on a trait - FnSpace, // Type parameters attached to a method or fn + TypeSpace, // Type parameters attached to a type definition, trait, or impl + SelfSpace, // Self parameter on a trait + AssocSpace, // Assoc types defined in a trait/impl + FnSpace, // Type parameters attached to a method or fn } impl ParamSpace { - pub fn all() -> [ParamSpace, ..3] { - [TypeSpace, SelfSpace, FnSpace] + pub fn all() -> [ParamSpace, ..4] { + [TypeSpace, SelfSpace, AssocSpace, FnSpace] } pub fn to_uint(self) -> uint { match self { TypeSpace => 0, SelfSpace => 1, - FnSpace => 2, + AssocSpace => 2, + FnSpace => 3, } } @@ -248,7 +195,8 @@ impl ParamSpace { match u { 0 => TypeSpace, 1 => SelfSpace, - 2 => FnSpace, + 2 => AssocSpace, + 3 => FnSpace, _ => panic!("Invalid ParamSpace: {}", u) } } @@ -268,14 +216,27 @@ pub struct VecPerParamSpace { // Here is how the representation corresponds to the abstraction // i.e. the "abstraction function" AF: // - // AF(self) = (self.content.slice_to(self.type_limit), - // self.content.slice(self.type_limit, self.self_limit), - // self.content.slice_from(self.self_limit)) + // AF(self) = (self.content[..self.type_limit], + // self.content[self.type_limit..self.self_limit], + // self.content[self.self_limit..self.assoc_limit], + // self.content[self.assoc_limit..]) type_limit: uint, self_limit: uint, + assoc_limit: uint, content: Vec, } +/** + * The `split` function converts one `VecPerParamSpace` into this + * `SeparateVecsPerParamSpace` structure. + */ +pub struct SeparateVecsPerParamSpace { + pub types: Vec, + pub selfs: Vec, + pub assocs: Vec, + pub fns: Vec, +} + impl fmt::Show for VecPerParamSpace { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { try!(write!(fmt, "VecPerParamSpace {{")); @@ -292,7 +253,8 @@ impl VecPerParamSpace { match space { TypeSpace => (0, self.type_limit), SelfSpace => (self.type_limit, self.self_limit), - FnSpace => (self.self_limit, self.content.len()), + AssocSpace => (self.self_limit, self.assoc_limit), + FnSpace => (self.assoc_limit, self.content.len()), } } @@ -300,6 +262,7 @@ impl VecPerParamSpace { VecPerParamSpace { type_limit: 0, self_limit: 0, + assoc_limit: 0, content: Vec::new() } } @@ -310,26 +273,33 @@ impl VecPerParamSpace { /// `t` is the type space. /// `s` is the self space. + /// `a` is the assoc space. /// `f` is the fn space. - pub fn new(t: Vec, s: Vec, f: Vec) -> VecPerParamSpace { + pub fn new(t: Vec, s: Vec, a: Vec, f: Vec) -> VecPerParamSpace { let type_limit = t.len(); - let self_limit = t.len() + s.len(); + let self_limit = type_limit + s.len(); + let assoc_limit = self_limit + a.len(); + let mut content = t; content.extend(s.into_iter()); + content.extend(a.into_iter()); content.extend(f.into_iter()); + VecPerParamSpace { type_limit: type_limit, self_limit: self_limit, + assoc_limit: assoc_limit, content: content, } } - fn new_internal(content: Vec, type_limit: uint, self_limit: uint) + fn new_internal(content: Vec, type_limit: uint, self_limit: uint, assoc_limit: uint) -> VecPerParamSpace { VecPerParamSpace { type_limit: type_limit, self_limit: self_limit, + assoc_limit: assoc_limit, content: content, } } @@ -341,9 +311,10 @@ impl VecPerParamSpace { pub fn push(&mut self, space: ParamSpace, value: T) { let (_, limit) = self.limits(space); match space { - TypeSpace => { self.type_limit += 1; self.self_limit += 1; } - SelfSpace => { self.self_limit += 1; } - FnSpace => {} + TypeSpace => { self.type_limit += 1; self.self_limit += 1; self.assoc_limit += 1; } + SelfSpace => { self.self_limit += 1; self.assoc_limit += 1; } + AssocSpace => { self.assoc_limit += 1; } + FnSpace => { } } self.content.insert(limit, value); } @@ -354,9 +325,10 @@ impl VecPerParamSpace { None } else { match space { - TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; } - SelfSpace => { self.self_limit -= 1; } - FnSpace => {} + TypeSpace => { self.type_limit -= 1; self.self_limit -= 1; self.assoc_limit -= 1; } + SelfSpace => { self.self_limit -= 1; self.assoc_limit -= 1; } + AssocSpace => { self.assoc_limit -= 1; } + FnSpace => {} } self.content.remove(limit - 1) } @@ -442,35 +414,35 @@ impl VecPerParamSpace { let result = self.iter().map(pred).collect(); VecPerParamSpace::new_internal(result, self.type_limit, - self.self_limit) + self.self_limit, + self.assoc_limit) } pub fn map_move(self, pred: |T| -> U) -> VecPerParamSpace { - let (t, s, f) = self.split(); + let SeparateVecsPerParamSpace { + types: t, + selfs: s, + assocs: a, + fns: f + } = self.split(); + VecPerParamSpace::new(t.into_iter().map(|p| pred(p)).collect(), s.into_iter().map(|p| pred(p)).collect(), + a.into_iter().map(|p| pred(p)).collect(), f.into_iter().map(|p| pred(p)).collect()) } - pub fn split(self) -> (Vec, Vec, Vec) { - // FIXME (#15418): this does two traversals when in principle - // one would suffice. i.e. change to use `move_iter`. - let VecPerParamSpace { type_limit, self_limit, content } = self; - let mut i = 0; - let (prefix, fn_vec) = content.partition(|_| { - let on_left = i < self_limit; - i += 1; - on_left - }); + pub fn split(self) -> SeparateVecsPerParamSpace { + let VecPerParamSpace { type_limit, self_limit, assoc_limit, content } = self; - let mut i = 0; - let (type_vec, self_vec) = prefix.partition(|_| { - let on_left = i < type_limit; - i += 1; - on_left - }); + let mut content_iter = content.into_iter(); - (type_vec, self_vec, fn_vec) + SeparateVecsPerParamSpace { + types: content_iter.by_ref().take(type_limit).collect(), + selfs: content_iter.by_ref().take(self_limit - type_limit).collect(), + assocs: content_iter.by_ref().take(assoc_limit - self_limit).collect(), + fns: content_iter.collect() + } } pub fn with_vec(mut self, space: ParamSpace, vec: Vec) @@ -616,12 +588,13 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { this.tcx().sess.span_bug( span, format!("Type parameter `{}` ({}/{}/{}) out of range \ - when substituting (root type={})", + when substituting (root type={}) substs={}", p.repr(this.tcx()), source_ty.repr(this.tcx()), space, index, - this.root_ty.repr(this.tcx())).as_slice()); + this.root_ty.repr(this.tcx()), + this.substs.repr(this.tcx())).as_slice()); } } } diff --git a/src/librustc/middle/traits/select.rs b/src/librustc/middle/traits/select.rs index eb58c99e55925..9a2d5b4d4dc0a 100644 --- a/src/librustc/middle/traits/select.rs +++ b/src/librustc/middle/traits/select.rs @@ -514,7 +514,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // and `Rc`. (Note that it is not a *coherence violation* // to have impls for both `Bar` and `Baz`, despite this // ambiguity). In this case, we report an error, listing all - // the applicable impls. The use can explicitly "up-coerce" + // the applicable impls. The user can explicitly "up-coerce" // to the type they want. // // Note that this coercion step only considers actual impls @@ -1618,7 +1618,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(o) => o, Err(ErrorReported) => Vec::new() }; - let obligations = VecPerParamSpace::new(obligations, Vec::new(), Vec::new()); + let obligations = VecPerParamSpace::new(obligations, Vec::new(), + Vec::new(), Vec::new()); VtableBuiltinData { nested: obligations } } @@ -1693,6 +1694,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { vec![arguments_tuple.subst(self.tcx(), substs), new_signature.output.unwrap().subst(self.tcx(), substs)], vec![], + vec![], obligation.self_ty()) }); @@ -1942,7 +1944,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { fn all_impls(&self, trait_def_id: ast::DefId) -> Vec { /*! - * Returns se tof all impls for a given trait. + * Returns set of all impls for a given trait. */ ty::populate_implementations_for_trait_if_necessary(self.tcx(), diff --git a/src/librustc/middle/trans/meth.rs b/src/librustc/middle/trans/meth.rs index db433167298ce..fbd4db959ce0c 100644 --- a/src/librustc/middle/trans/meth.rs +++ b/src/librustc/middle/trans/meth.rs @@ -205,7 +205,12 @@ pub fn trans_static_method_callee(bcx: Block, // type parameters that belong to the trait but also some that // belong to the method: let rcvr_substs = node_id_substs(bcx, ExprId(expr_id)); - let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.split(); + let subst::SeparateVecsPerParamSpace { + types: rcvr_type, + selfs: rcvr_self, + assocs: rcvr_assoc, + fns: rcvr_method + } = rcvr_substs.types.split(); // Lookup the precise impl being called. To do that, we need to // create a trait reference identifying the self type and other @@ -232,6 +237,7 @@ pub fn trans_static_method_callee(bcx: Block, let trait_substs = Substs::erased(VecPerParamSpace::new(rcvr_type, rcvr_self, + rcvr_assoc, Vec::new())); debug!("trait_substs={}", trait_substs.repr(bcx.tcx())); let trait_ref = Rc::new(ty::TraitRef { def_id: trait_id, @@ -265,10 +271,16 @@ pub fn trans_static_method_callee(bcx: Block, // that with the `rcvr_method` from before, which tells us // the type parameters from the *method*, to yield // `callee_substs=[[T=int],[],[U=String]]`. - let (impl_type, impl_self, _) = impl_substs.types.split(); + let subst::SeparateVecsPerParamSpace { + types: impl_type, + selfs: impl_self, + assocs: impl_assoc, + fns: _ + } = impl_substs.types.split(); let callee_substs = Substs::erased(VecPerParamSpace::new(impl_type, impl_self, + impl_assoc, rcvr_method)); let mth_id = method_with_name(ccx, impl_did, mname); @@ -397,12 +409,17 @@ fn combine_impl_and_methods_tps(bcx: Block, // Break apart the type parameters from the node and type // parameters from the receiver. - let (_, _, node_method) = node_substs.types.split(); - let (rcvr_type, rcvr_self, rcvr_method) = rcvr_substs.types.clone().split(); + let node_method = node_substs.types.split().fns; + let subst::SeparateVecsPerParamSpace { + types: rcvr_type, + selfs: rcvr_self, + assocs: rcvr_assoc, + fns: rcvr_method + } = rcvr_substs.types.clone().split(); assert!(rcvr_method.is_empty()); subst::Substs { regions: subst::ErasedRegions, - types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, node_method) + types: subst::VecPerParamSpace::new(rcvr_type, rcvr_self, rcvr_assoc, node_method) } } diff --git a/src/librustc/middle/trans/type_.rs b/src/librustc/middle/trans/type_.rs index d8424c9f316b5..1746f78531161 100644 --- a/src/librustc/middle/trans/type_.rs +++ b/src/librustc/middle/trans/type_.rs @@ -27,6 +27,7 @@ use std::collections::HashMap; use libc::c_uint; #[deriving(Clone, PartialEq, Show)] +#[repr(C)] pub struct Type { rf: TypeRef } @@ -283,9 +284,10 @@ impl Type { if n_elts == 0 { return Vec::new(); } - let mut elts = Vec::from_elem(n_elts, 0 as TypeRef); - llvm::LLVMGetStructElementTypes(self.to_ref(), &mut elts[0]); - mem::transmute(elts) + let mut elts = Vec::from_elem(n_elts, Type { rf: 0 as TypeRef }); + llvm::LLVMGetStructElementTypes(self.to_ref(), + elts.as_mut_ptr() as *mut TypeRef); + elts } } @@ -296,9 +298,10 @@ impl Type { pub fn func_params(&self) -> Vec { unsafe { let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint; - let args = Vec::from_elem(n_args, 0 as TypeRef); - llvm::LLVMGetParamTypes(self.to_ref(), args.as_ptr()); - mem::transmute(args) + let mut args = Vec::from_elem(n_args, Type { rf: 0 as TypeRef }); + llvm::LLVMGetParamTypes(self.to_ref(), + args.as_mut_ptr() as *mut TypeRef); + args } } diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs index 4c088e42243e1..a94b188cb28bd 100644 --- a/src/librustc/middle/ty.rs +++ b/src/librustc/middle/ty.rs @@ -573,10 +573,6 @@ pub struct ctxt<'tcx> { /// Maps def IDs to true if and only if they're associated types. pub associated_types: RefCell>, - /// Maps def IDs of traits to information about their associated types. - pub trait_associated_types: - RefCell>>>, - /// Caches the results of trait selection. This cache is used /// for things that do not have to do with the parameters in scope. pub selection_cache: traits::SelectionCache, @@ -1564,7 +1560,6 @@ pub fn mk_ctxt<'tcx>(s: Session, stability: RefCell::new(stability), capture_modes: capture_modes, associated_types: RefCell::new(DefIdMap::new()), - trait_associated_types: RefCell::new(DefIdMap::new()), selection_cache: traits::SelectionCache::new(), repr_hint_cache: RefCell::new(DefIdMap::new()), } @@ -1994,6 +1989,16 @@ impl ItemSubsts { } } +impl ParamBounds { + pub fn empty() -> ParamBounds { + ParamBounds { + builtin_bounds: empty_builtin_bounds(), + trait_bounds: Vec::new(), + region_bounds: Vec::new(), + } + } +} + // Type utilities pub fn type_is_nil(ty: t) -> bool { @@ -4155,18 +4160,6 @@ impl Ord for AssociatedTypeInfo { } } -/// Returns the associated types belonging to the given trait, in parameter -/// order. -pub fn associated_types_for_trait(cx: &ctxt, trait_id: ast::DefId) - -> Rc> { - cx.trait_associated_types - .borrow() - .find(&trait_id) - .expect("associated_types_for_trait(): trait not found, try calling \ - ensure_associated_types()") - .clone() -} - pub fn trait_item_def_ids(cx: &ctxt, id: ast::DefId) -> Rc> { lookup_locally_or_in_crate_store("trait_item_def_ids", diff --git a/src/librustc/middle/typeck/astconv.rs b/src/librustc/middle/typeck/astconv.rs index dba1fe966f147..7c8d9309df3b8 100644 --- a/src/librustc/middle/typeck/astconv.rs +++ b/src/librustc/middle/typeck/astconv.rs @@ -54,7 +54,7 @@ use middle::def; use middle::lang_items::{FnTraitLangItem, FnMutTraitLangItem}; use middle::lang_items::{FnOnceTraitLangItem}; use middle::resolve_lifetime as rl; -use middle::subst::{FnSpace, TypeSpace, SelfSpace, Subst, Substs}; +use middle::subst::{FnSpace, TypeSpace, AssocSpace, SelfSpace, Subst, Substs}; use middle::subst::{VecPerParamSpace}; use middle::ty; use middle::typeck::lookup_def_tcx; @@ -172,18 +172,18 @@ pub fn opt_ast_region_to_region<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( } } if len == 1 { - span_note!(this.tcx().sess, default_span, + span_help!(this.tcx().sess, default_span, "this function's return type contains a borrowed value, but \ the signature does not say which {} it is borrowed from", m); } else if len == 0 { - span_note!(this.tcx().sess, default_span, + span_help!(this.tcx().sess, default_span, "this function's return type contains a borrowed value, but \ there is no value for it to be borrowed from"); - span_note!(this.tcx().sess, default_span, + span_help!(this.tcx().sess, default_span, "consider giving it a 'static lifetime"); } else { - span_note!(this.tcx().sess, default_span, + span_help!(this.tcx().sess, default_span, "this function's return type contains a borrowed value, but \ the signature does not say whether it is borrowed from {}", m); @@ -215,7 +215,8 @@ fn ast_path_substs<'tcx,AC,RS>( associated_ty: Option, path: &ast::Path) -> Substs - where AC: AstConv<'tcx>, RS: RegionScope { + where AC: AstConv<'tcx>, RS: RegionScope +{ /*! * Given a path `path` that refers to an item `I` with the * declared generics `decl_generics`, returns an appropriate @@ -302,7 +303,7 @@ fn ast_path_substs<'tcx,AC,RS>( && !this.tcx().sess.features.borrow().default_type_params { span_err!(this.tcx().sess, path.span, E0108, "default type parameters are experimental and possibly buggy"); - span_note!(this.tcx().sess, path.span, + span_help!(this.tcx().sess, path.span, "add #![feature(default_type_params)] to the crate attributes to enable"); } @@ -338,17 +339,21 @@ fn ast_path_substs<'tcx,AC,RS>( substs.types.push(TypeSpace, default); } None => { - // This is an associated type. - substs.types.push( - TypeSpace, - this.associated_type_binding(path.span, - associated_ty, - decl_def_id, - param.def_id)) + tcx.sess.span_bug(path.span, + "extra parameter without default"); } } } + for param in decl_generics.types.get_slice(AssocSpace).iter() { + substs.types.push( + AssocSpace, + this.associated_type_binding(path.span, + associated_ty, + decl_def_id, + param.def_id)) + } + substs } @@ -628,9 +633,13 @@ fn mk_pointer<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( a_seq_ty: &ast::Ty, ptr_ty: PointerTy, constr: |ty::t| -> ty::t) - -> ty::t { + -> ty::t +{ let tcx = this.tcx(); - debug!("mk_pointer(ptr_ty={})", ptr_ty); + + debug!("mk_pointer(ptr_ty={}, a_seq_ty={})", + ptr_ty, + a_seq_ty.repr(tcx)); match a_seq_ty.node { ast::TyVec(ref ty) => { @@ -730,7 +739,13 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, trait_type_id: ast::DefId, span: Span) -> ty::t - where AC: AstConv<'tcx>, RS: RegionScope { + where AC: AstConv<'tcx>, RS: RegionScope +{ + debug!("associated_ty_to_ty(trait_path={}, for_ast_type={}, trait_type_id={})", + trait_path.repr(this.tcx()), + for_ast_type.repr(this.tcx()), + trait_type_id.repr(this.tcx())); + // Find the trait that this associated type belongs to. let trait_did = match ty::impl_or_trait_item(this.tcx(), trait_type_id).container() { @@ -757,9 +772,16 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, None, Some(for_type), trait_path); + + debug!("associated_ty_to_ty(trait_ref={})", + trait_ref.repr(this.tcx())); + let trait_def = this.get_trait_def(trait_did); for type_parameter in trait_def.generics.types.iter() { if type_parameter.def_id == trait_type_id { + debug!("associated_ty_to_ty(type_parameter={} substs={})", + type_parameter.repr(this.tcx()), + trait_ref.substs.repr(this.tcx())); return *trait_ref.substs.types.get(type_parameter.space, type_parameter.index) } @@ -772,7 +794,10 @@ fn associated_ty_to_ty<'tcx,AC,RS>(this: &AC, // Parses the programmer's textual representation of a type into our // internal notion of a type. pub fn ast_ty_to_ty<'tcx, AC: AstConv<'tcx>, RS: RegionScope>( - this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t { + this: &AC, rscope: &RS, ast_ty: &ast::Ty) -> ty::t +{ + debug!("ast_ty_to_ty(ast_ty={})", + ast_ty.repr(this.tcx())); let tcx = this.tcx(); @@ -1168,6 +1193,7 @@ fn ty_of_method_or_bare_fn<'tcx, AC: AstConv<'tcx>>( let param_lifetimes: Vec<(String, uint)> = lifetimes_for_params.into_iter() .map(|(n, v)| (n, v.len())) + .filter(|&(_, l)| l != 0) .collect(); let output_ty = match decl.output.node { diff --git a/src/librustc/middle/typeck/check/mod.rs b/src/librustc/middle/typeck/check/mod.rs index c280474a076a0..92b5b696e5221 100644 --- a/src/librustc/middle/typeck/check/mod.rs +++ b/src/librustc/middle/typeck/check/mod.rs @@ -1355,18 +1355,18 @@ fn check_cast(fcx: &FnCtxt, ast::MutImmutable => "" }; if ty::type_is_trait(t_1) { - span_note!(fcx.tcx().sess, t.span, "did you mean `&{}{}`?", mtstr, tstr); + span_help!(fcx.tcx().sess, t.span, "did you mean `&{}{}`?", mtstr, tstr); } else { - span_note!(fcx.tcx().sess, span, + span_help!(fcx.tcx().sess, span, "consider using an implicit coercion to `&{}{}` instead", mtstr, tstr); } } ty::ty_uniq(..) => { - span_note!(fcx.tcx().sess, t.span, "did you mean `Box<{}>`?", tstr); + span_help!(fcx.tcx().sess, t.span, "did you mean `Box<{}>`?", tstr); } _ => { - span_note!(fcx.tcx().sess, e.span, + span_help!(fcx.tcx().sess, e.span, "consider using a box or reference as appropriate"); } } @@ -2142,7 +2142,7 @@ fn try_overloaded_call<'a>(fcx: &FnCtxt, if !fcx.tcx().sess.features.borrow().overloaded_calls { span_err!(fcx.tcx().sess, call_expression.span, E0056, "overloaded calls are experimental"); - span_note!(fcx.tcx().sess, call_expression.span, + span_help!(fcx.tcx().sess, call_expression.span, "add `#![feature(overloaded_calls)]` to \ the crate attributes to enable"); } @@ -2536,7 +2536,7 @@ fn check_argument_types<'a>(fcx: &FnCtxt, span_err!(tcx.sess, sp, E0059, "cannot use call notation; the first type parameter \ for the function trait is neither a tuple nor unit"); - err_args(supplied_arg_count) + err_args(args.len()) } } } else if expected_arg_count == supplied_arg_count { @@ -3479,8 +3479,9 @@ fn check_expr_with_unifier(fcx: &FnCtxt, }, expr_t, None); - tcx.sess.span_note(field.span, - "maybe a missing `()` to call it? If not, try an anonymous function."); + tcx.sess.span_help(field.span, + "maybe a `()` to call it is missing? \ + If not, try an anonymous function"); } Err(_) => { @@ -4787,7 +4788,8 @@ pub fn check_instantiable(tcx: &ty::ctxt, if !ty::is_instantiable(tcx, item_ty) { span_err!(tcx.sess, sp, E0073, "this type cannot be instantiated without an \ - instance of itself; consider using `Option<{}>`", + instance of itself"); + span_help!(tcx.sess, sp, "consider using `Option<{}>`", ppaux::ty_to_string(tcx, item_ty)); false } else { diff --git a/src/librustc/middle/typeck/check/vtable.rs b/src/librustc/middle/typeck/check/vtable.rs index 87b0aed4ac49c..2fcce4cc3dcfd 100644 --- a/src/librustc/middle/typeck/check/vtable.rs +++ b/src/librustc/middle/typeck/check/vtable.rs @@ -525,7 +525,7 @@ fn note_obligation_cause(fcx: &FnCtxt, span_note!(tcx.sess, obligation.cause.span, "cannot implement a destructor on a \ structure or enumeration that does not satisfy Send"); - span_note!(tcx.sess, obligation.cause.span, + span_help!(tcx.sess, obligation.cause.span, "use \"#[unsafe_destructor]\" on the implementation \ to force the compiler to allow this"); } diff --git a/src/librustc/middle/typeck/coherence/mod.rs b/src/librustc/middle/typeck/coherence/mod.rs index a569053507cf8..ac18f53de0465 100644 --- a/src/librustc/middle/typeck/coherence/mod.rs +++ b/src/librustc/middle/typeck/coherence/mod.rs @@ -207,8 +207,8 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> { let impl_items = self.create_impl_from_item(item); for associated_trait in associated_traits.iter() { - let trait_ref = ty::node_id_to_trait_ref( - self.crate_context.tcx, associated_trait.ref_id); + let trait_ref = ty::node_id_to_trait_ref(self.crate_context.tcx, + associated_trait.ref_id); debug!("(checking implementation) adding impl for trait '{}', item '{}'", trait_ref.repr(self.crate_context.tcx), token::get_ident(item.ident)); diff --git a/src/librustc/middle/typeck/coherence/orphan.rs b/src/librustc/middle/typeck/coherence/orphan.rs index e7139e1229b23..3c4ad3473610c 100644 --- a/src/librustc/middle/typeck/coherence/orphan.rs +++ b/src/librustc/middle/typeck/coherence/orphan.rs @@ -41,7 +41,8 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> { let self_ty = ty::lookup_item_type(self.tcx, def_id).ty; match ty::get(self_ty).sty { ty::ty_enum(def_id, _) | - ty::ty_struct(def_id, _) => { + ty::ty_struct(def_id, _) | + ty::ty_trait(box ty::TyTrait{ def_id, ..}) => { if def_id.krate != ast::LOCAL_CRATE { span_err!(self.tcx.sess, item.span, E0116, "cannot associate methods with a type outside the \ diff --git a/src/librustc/middle/typeck/collect.rs b/src/librustc/middle/typeck/collect.rs index 847d8e88bde88..863f09736ab27 100644 --- a/src/librustc/middle/typeck/collect.rs +++ b/src/librustc/middle/typeck/collect.rs @@ -298,13 +298,19 @@ fn collect_trait_methods(ccx: &CrateCtxt, &*m.pe_fn_decl()) } ast::TypeTraitItem(ref at) => { - tcx.sess.span_bug(at.span, + tcx.sess.span_bug(at.ty_param.span, "there shouldn't \ be a type trait \ item here") } }); + debug!("ty_method_of_trait_method yielded {} \ + for method {} of trait {}", + ty_method.repr(ccx.tcx), + trait_item.repr(ccx.tcx), + local_def(trait_id).repr(ccx.tcx)); + make_method_ty(ccx, &*ty_method); tcx.impl_or_trait_items @@ -315,9 +321,9 @@ fn collect_trait_methods(ccx: &CrateCtxt, ast::TypeTraitItem(ref ast_associated_type) => { let trait_did = local_def(trait_id); let associated_type = ty::AssociatedType { - name: ast_associated_type.ident.name, + name: ast_associated_type.ty_param.ident.name, vis: ast::Public, - def_id: local_def(ast_associated_type.id), + def_id: local_def(ast_associated_type.ty_param.id), container: TraitContainer(trait_did), }; @@ -345,7 +351,7 @@ fn collect_trait_methods(ccx: &CrateCtxt, method.id)) } ast::TypeTraitItem(ref typedef) => { - ty::TypeTraitItemId(local_def(typedef.id)) + ty::TypeTraitItemId(local_def(typedef.ty_param.id)) } } }).collect()); @@ -460,35 +466,35 @@ fn convert_associated_type(ccx: &CrateCtxt, // associated type. let type_parameter_def = trait_def.generics .types - .get_slice(subst::TypeSpace) + .get_slice(subst::AssocSpace) .iter() .find(|def| { - def.def_id == local_def(associated_type.id) + def.def_id == local_def(associated_type.ty_param.id) }); let type_parameter_def = match type_parameter_def { Some(type_parameter_def) => type_parameter_def, None => { - ccx.tcx().sess.span_bug(associated_type.span, + ccx.tcx().sess.span_bug(associated_type.ty_param.span, "`convert_associated_type()` didn't find \ a type parameter ID corresponding to \ this type") } }; let param_type = ty::mk_param(ccx.tcx, - subst::TypeSpace, + type_parameter_def.space, type_parameter_def.index, - local_def(associated_type.id)); - ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.id), + local_def(associated_type.ty_param.id)); + ccx.tcx.tcache.borrow_mut().insert(local_def(associated_type.ty_param.id), Polytype { generics: ty::Generics::empty(), ty: param_type, }); - write_ty_to_tcx(ccx.tcx, associated_type.id, param_type); + write_ty_to_tcx(ccx.tcx, associated_type.ty_param.id, param_type); let associated_type = Rc::new(ty::AssociatedType { - name: associated_type.ident.name, + name: associated_type.ty_param.ident.name, vis: ast::Public, - def_id: local_def(associated_type.id), + def_id: local_def(associated_type.ty_param.id), container: TraitContainer(trait_def.trait_ref.def_id), }); ccx.tcx @@ -780,25 +786,18 @@ impl<'a,'tcx> AstConv<'tcx> for ImplCtxt<'a,'tcx> { ty: Option, trait_id: ast::DefId, associated_type_id: ast::DefId) - -> ty::t { - ensure_associated_types(self, trait_id); - let associated_type_ids = ty::associated_types_for_trait(self.ccx.tcx, - trait_id); + -> ty::t + { + let trait_def = ty::lookup_trait_def(self.tcx(), trait_id); match self.opt_trait_ref_id { Some(trait_ref_id) if trait_ref_id == trait_id => { // It's an associated type on the trait that we're // implementing. - let associated_type_id = - associated_type_ids.iter() - .find(|id| { - id.def_id == associated_type_id - }) - .expect("associated_type_binding(): \ - expected associated type ID \ - in trait"); - let associated_type = - ty::impl_or_trait_item(self.ccx.tcx, - associated_type_id.def_id); + assert!(trait_def.generics.types + .get_slice(subst::AssocSpace) + .iter() + .any(|type_param_def| type_param_def.def_id == associated_type_id)); + let associated_type = ty::impl_or_trait_item(self.ccx.tcx, associated_type_id); for impl_item in self.impl_items.iter() { match *impl_item { ast::MethodImplItem(_) => {} @@ -978,9 +977,9 @@ impl<'a,'tcx> AstConv<'tcx> for TraitMethodCtxt<'a,'tcx> { match *item { ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} ast::TypeTraitItem(ref item) => { - if local_def(item.id) == associated_type_id { + if local_def(item.ty_param.id) == associated_type_id { return ty::mk_param(self.tcx(), - subst::TypeSpace, + subst::AssocSpace, index, associated_type_id) } @@ -1451,7 +1450,8 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { trait_id: ast::NodeId, generics: &ast::Generics, items: &[ast::TraitItem]) - -> subst::Substs { + -> subst::Substs + { // Creates a no-op substitution for the trait's type parameters. let regions = generics.lifetimes @@ -1464,7 +1464,7 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { .collect(); // Start with the generics in the type parameters... - let mut types: Vec<_> = + let types: Vec<_> = generics.ty_params .iter() .enumerate() @@ -1472,24 +1472,27 @@ pub fn trait_def_of_item(ccx: &CrateCtxt, it: &ast::Item) -> Rc { i, local_def(def.id))) .collect(); - // ...and add generics synthesized from the associated types. - for item in items.iter() { - match *item { + // ...and also create generics synthesized from the associated types. + let assoc_types: Vec<_> = + items.iter() + .flat_map(|item| match *item { ast::TypeTraitItem(ref trait_item) => { let index = types.len(); - types.push(ty::mk_param(ccx.tcx, - subst::TypeSpace, - index, - local_def(trait_item.id))) + Some(ty::mk_param(ccx.tcx, + subst::AssocSpace, + index, + local_def(trait_item.ty_param.id))).into_iter() } - ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} - } - } + ast::RequiredMethod(_) | ast::ProvidedMethod(_) => { + None.into_iter() + } + }) + .collect(); let self_ty = ty::mk_param(ccx.tcx, subst::SelfSpace, 0, local_def(trait_id)); - subst::Substs::new_trait(types, regions, self_ty) + subst::Substs::new_trait(types, regions, assoc_types, self_ty) } } @@ -1630,11 +1633,11 @@ fn ty_of_trait_item(ccx: &CrateCtxt, trait_item: &ast::TraitItem) "ty_of_trait_item() on provided method") } ast::TypeTraitItem(ref associated_type) => { - let parent = ccx.tcx.map.get_parent(associated_type.id); + let parent = ccx.tcx.map.get_parent(associated_type.ty_param.id); let trait_def = match ccx.tcx.map.get(parent) { ast_map::NodeItem(item) => trait_def_of_item(ccx, &*item), _ => { - ccx.tcx.sess.span_bug(associated_type.span, + ccx.tcx.sess.span_bug(associated_type.ty_param.span, "associated type's parent wasn't \ an item?!") } @@ -1661,38 +1664,33 @@ fn ty_generics_for_type(ccx: &CrateCtxt, fn ty_generics_for_trait(ccx: &CrateCtxt, trait_id: ast::NodeId, substs: &subst::Substs, - generics: &ast::Generics, + ast_generics: &ast::Generics, items: &[ast::TraitItem]) -> ty::Generics { let mut generics = ty_generics(ccx, subst::TypeSpace, - generics.lifetimes.as_slice(), - generics.ty_params.as_slice(), + ast_generics.lifetimes.as_slice(), + ast_generics.ty_params.as_slice(), ty::Generics::empty(), - &generics.where_clause, + &ast_generics.where_clause, DontCreateTypeParametersForAssociatedTypes); // Add in type parameters for any associated types. for item in items.iter() { match *item { ast::TypeTraitItem(ref associated_type) => { - let def = ty::TypeParameterDef { - space: subst::TypeSpace, - index: generics.types.len(subst::TypeSpace), - name: associated_type.ident.name, - def_id: local_def(associated_type.id), - bounds: ty::ParamBounds { - builtin_bounds: ty::empty_builtin_bounds(), - trait_bounds: Vec::new(), - region_bounds: Vec::new(), - }, - associated_with: Some(local_def(trait_id)), - default: None, - }; - ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.id, + let def = + get_or_create_type_parameter_def( + ccx, + subst::AssocSpace, + &associated_type.ty_param, + generics.types.len(subst::TypeSpace), + &ast_generics.where_clause, + Some(local_def(trait_id))); + ccx.tcx.ty_param_defs.borrow_mut().insert(associated_type.ty_param.id, def.clone()); - generics.types.push(subst::TypeSpace, def); + generics.types.push(subst::AssocSpace, def); } ast::ProvidedMethod(_) | ast::RequiredMethod(_) => {} } @@ -1791,86 +1789,17 @@ enum CreateTypeParametersForAssociatedTypesFlag { CreateTypeParametersForAssociatedTypes, } -fn ensure_associated_types<'tcx,AC>(this: &AC, trait_id: ast::DefId) - where AC: AstConv<'tcx> { - if this.tcx().trait_associated_types.borrow().contains_key(&trait_id) { - return - } - - if trait_id.krate == ast::LOCAL_CRATE { - match this.tcx().map.find(trait_id.node) { - Some(ast_map::NodeItem(item)) => { - match item.node { - ast::ItemTrait(_, _, _, ref trait_items) => { - let mut result = Vec::new(); - let mut index = 0; - for trait_item in trait_items.iter() { - match *trait_item { - ast::RequiredMethod(_) | - ast::ProvidedMethod(_) => {} - ast::TypeTraitItem(ref associated_type) => { - let info = ty::AssociatedTypeInfo { - def_id: local_def(associated_type.id), - index: index, - name: associated_type.ident.name, - }; - result.push(info); - index += 1; - } - } - } - this.tcx() - .trait_associated_types - .borrow_mut() - .insert(trait_id, Rc::new(result)); - return - } - _ => { - this.tcx().sess.bug("ensure_associated_types() \ - called on non-trait") - } - } - } - _ => { - this.tcx().sess.bug("ensure_associated_types() called on \ - non-trait") - } - } - - } - - // Cross-crate case. - let mut result = Vec::new(); - let mut index = 0; - let trait_items = ty::trait_items(this.tcx(), trait_id); - for trait_item in trait_items.iter() { - match *trait_item { - ty::MethodTraitItem(_) => {} - ty::TypeTraitItem(ref associated_type) => { - let info = ty::AssociatedTypeInfo { - def_id: associated_type.def_id, - index: index, - name: associated_type.name - }; - result.push(info); - index += 1; - } - } - } - this.tcx().trait_associated_types.borrow_mut().insert(trait_id, - Rc::new(result)); -} - fn ty_generics<'tcx,AC>(this: &AC, space: subst::ParamSpace, lifetime_defs: &[ast::LifetimeDef], types: &[ast::TyParam], base_generics: ty::Generics, where_clause: &ast::WhereClause, - create_type_parameters_for_associated_types: + create_type_parameters_for_associated_types_flag: CreateTypeParametersForAssociatedTypesFlag) -> ty::Generics - where AC: AstConv<'tcx> { + where AC: AstConv<'tcx> +{ let mut result = base_generics; for (i, l) in lifetime_defs.iter().enumerate() { @@ -1891,62 +1820,11 @@ fn ty_generics<'tcx,AC>(this: &AC, // First, create the virtual type parameters for associated types if // necessary. let mut associated_types_generics = ty::Generics::empty(); - match create_type_parameters_for_associated_types { + match create_type_parameters_for_associated_types_flag { DontCreateTypeParametersForAssociatedTypes => {} CreateTypeParametersForAssociatedTypes => { - let mut index = 0; - for param in types.iter() { - for bound in param.bounds.iter() { - match *bound { - ast::TraitTyParamBound(ref trait_bound) => { - match lookup_def_tcx(this.tcx(), - trait_bound.path.span, - trait_bound.ref_id) { - def::DefTrait(trait_did) => { - ensure_associated_types(this, trait_did); - let associated_types = - ty::associated_types_for_trait( - this.tcx(), - trait_did); - for associated_type_info in - associated_types.iter() { - let associated_type_trait_item = - ty::impl_or_trait_item( - this.tcx(), - associated_type_info.def_id); - let def = ty::TypeParameterDef { - name: associated_type_trait_item.name(), - def_id: associated_type_info.def_id, - space: space, - index: types.len() + index, - bounds: ty::ParamBounds { - builtin_bounds: - ty::empty_builtin_bounds(), - trait_bounds: Vec::new(), - region_bounds: Vec::new(), - }, - associated_with: { - Some(local_def(param.id)) - }, - default: None, - }; - associated_types_generics.types - .push(space, - def); - index += 1; - } - } - _ => { - this.tcx().sess.span_bug(trait_bound.path - .span, - "not a trait?!") - } - } - } - _ => {} - } - } - } + create_type_parameters_for_associated_types(this, space, types, + &mut associated_types_generics); } } @@ -1960,7 +1838,8 @@ fn ty_generics<'tcx,AC>(this: &AC, space, param, i, - where_clause); + where_clause, + None); debug!("ty_generics: def for type param: {}, {}", def.repr(this.tcx()), space); @@ -1981,62 +1860,140 @@ fn ty_generics<'tcx,AC>(this: &AC, return result; - fn get_or_create_type_parameter_def<'tcx,AC>( - this: &AC, - space: subst::ParamSpace, - param: &ast::TyParam, - index: uint, - where_clause: &ast::WhereClause) - -> ty::TypeParameterDef - where AC: AstConv<'tcx> { - match this.tcx().ty_param_defs.borrow().find(¶m.id) { - Some(d) => { return (*d).clone(); } - None => { } + fn create_type_parameters_for_associated_types<'tcx,AC>( + this: &AC, + space: subst::ParamSpace, + types: &[ast::TyParam], + associated_types_generics: &mut ty::Generics) + where AC: AstConv<'tcx> + { + // The idea here is roughly as follows. We start with + // an item that is paramerized by various type parameters + // with bounds: + // + // fn foo(t: T) { ... } + // + // The traits in those bounds declare associated types: + // + // trait Iterator { type Elem; ... } + // + // And we rewrite the original function so that every associated + // type is bound to some fresh type parameter: + // + // fn foo>(t: T) { ... } + + // Number of synthetic type parameters created thus far + let mut index = 0; + + // Iterate over the each type parameter `T` (from the example) + for param in types.iter() { + // Iterate over the bound `Iterator` + for bound in param.bounds.iter() { + // In the above example, `ast_trait_ref` is `Iterator`. + let ast_trait_ref = match *bound { + ast::TraitTyParamBound(ref r) => r, + ast::UnboxedFnTyParamBound(..) => { continue; } + ast::RegionTyParamBound(..) => { continue; } + }; + + let trait_def_id = + match lookup_def_tcx(this.tcx(), + ast_trait_ref.path.span, + ast_trait_ref.ref_id) { + def::DefTrait(trait_def_id) => trait_def_id, + _ => { + this.tcx().sess.span_bug(ast_trait_ref.path.span, + "not a trait?!") + } + }; + + // trait_def_id is def-id of `Iterator` + let trait_def = ty::lookup_trait_def(this.tcx(), trait_def_id); + let associated_type_defs = trait_def.generics.types.get_slice(subst::AssocSpace); + + // Iterate over each associated type `Elem` + for associated_type_def in associated_type_defs.iter() { + // Create the fresh type parameter `A` + let def = ty::TypeParameterDef { + name: associated_type_def.name, + def_id: associated_type_def.def_id, + space: space, + index: types.len() + index, + bounds: ty::ParamBounds { + builtin_bounds: associated_type_def.bounds.builtin_bounds, + + // FIXME(#18178) -- we should add the other bounds, but + // that requires subst and more logic + trait_bounds: Vec::new(), + region_bounds: Vec::new(), + }, + associated_with: Some(local_def(param.id)), + default: None, + }; + associated_types_generics.types.push(space, def); + index += 1; + } + } } + } +} - let param_ty = ty::ParamTy::new(space, index, local_def(param.id)); - let bounds = compute_bounds(this, - param.ident.name, - param_ty, - param.bounds.as_slice(), - ¶m.unbound, - param.span, - where_clause); - let default = match param.default { - None => None, - Some(ref path) => { - let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path); - let cur_idx = index; - - ty::walk_ty(ty, |t| { - match ty::get(t).sty { - ty::ty_param(p) => if p.idx > cur_idx { +fn get_or_create_type_parameter_def<'tcx,AC>(this: &AC, + space: subst::ParamSpace, + param: &ast::TyParam, + index: uint, + where_clause: &ast::WhereClause, + associated_with: Option) + -> ty::TypeParameterDef + where AC: AstConv<'tcx> +{ + match this.tcx().ty_param_defs.borrow().find(¶m.id) { + Some(d) => { return (*d).clone(); } + None => { } + } + + let param_ty = ty::ParamTy::new(space, index, local_def(param.id)); + let bounds = compute_bounds(this, + param.ident.name, + param_ty, + param.bounds.as_slice(), + ¶m.unbound, + param.span, + where_clause); + let default = match param.default { + None => None, + Some(ref path) => { + let ty = ast_ty_to_ty(this, &ExplicitRscope, &**path); + let cur_idx = index; + + ty::walk_ty(ty, |t| { + match ty::get(t).sty { + ty::ty_param(p) => if p.idx > cur_idx { span_err!(this.tcx().sess, path.span, E0128, "type parameters with a default cannot use \ forward declared identifiers"); }, _ => {} } - }); + }); - Some(ty) - } - }; + Some(ty) + } + }; - let def = ty::TypeParameterDef { - space: space, - index: index, - name: param.ident.name, - def_id: local_def(param.id), - associated_with: None, - bounds: bounds, - default: default - }; + let def = ty::TypeParameterDef { + space: space, + index: index, + name: param.ident.name, + def_id: local_def(param.id), + associated_with: associated_with, + bounds: bounds, + default: default + }; - this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone()); + this.tcx().ty_param_defs.borrow_mut().insert(param.id, def.clone()); - def - } + def } fn compute_bounds<'tcx,AC>(this: &AC, diff --git a/src/librustc/middle/typeck/infer/error_reporting.rs b/src/librustc/middle/typeck/infer/error_reporting.rs index 3baa9a7a5f964..bfa0f94a74751 100644 --- a/src/librustc/middle/typeck/infer/error_reporting.rs +++ b/src/librustc/middle/typeck/infer/error_reporting.rs @@ -438,9 +438,12 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> { self.tcx.sess.span_err( origin.span(), format!( - "the parameter type `{}` may not live long enough; \ - consider adding an explicit lifetime bound `{}:{}`...", - param_ty.user_string(self.tcx), + "the parameter type `{}` may not live long enough", + param_ty.user_string(self.tcx)).as_slice()); + self.tcx.sess.span_help( + origin.span(), + format!( + "consider adding an explicit lifetime bound `{}: {}`...", param_ty.user_string(self.tcx), sub.user_string(self.tcx)).as_slice()); } @@ -450,9 +453,12 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> { self.tcx.sess.span_err( origin.span(), format!( - "the parameter type `{}` may not live long enough; \ - consider adding an explicit lifetime bound `{}:'static`...", - param_ty.user_string(self.tcx), + "the parameter type `{}` may not live long enough", + param_ty.user_string(self.tcx)).as_slice()); + self.tcx.sess.span_help( + origin.span(), + format!( + "consider adding an explicit lifetime bound `{}: 'static`...", param_ty.user_string(self.tcx)).as_slice()); } @@ -461,9 +467,12 @@ impl<'a, 'tcx> ErrorReporting for InferCtxt<'a, 'tcx> { self.tcx.sess.span_err( origin.span(), format!( - "the parameter type `{}` may not live long enough; \ - consider adding an explicit lifetime bound to `{}`", - param_ty.user_string(self.tcx), + "the parameter type `{}` may not live long enough", + param_ty.user_string(self.tcx)).as_slice()); + self.tcx.sess.span_help( + origin.span(), + format!( + "consider adding an explicit lifetime bound to `{}`", param_ty.user_string(self.tcx)).as_slice()); note_and_explain_region( self.tcx, diff --git a/src/librustc/middle/typeck/infer/mod.rs b/src/librustc/middle/typeck/infer/mod.rs index 227a9b1bdcc88..55c3c23685357 100644 --- a/src/librustc/middle/typeck/infer/mod.rs +++ b/src/librustc/middle/typeck/infer/mod.rs @@ -774,10 +774,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { assert!(generics.regions.len(subst::FnSpace) == 0); let type_parameter_count = generics.types.len(subst::TypeSpace); + let type_parameters = self.next_ty_vars(type_parameter_count); + let region_param_defs = generics.regions.get_slice(subst::TypeSpace); let regions = self.region_vars_for_defs(span, region_param_defs); - let type_parameters = self.next_ty_vars(type_parameter_count); - subst::Substs::new_trait(type_parameters, regions, self_ty) + + let assoc_type_parameter_count = generics.types.len(subst::AssocSpace); + let assoc_type_parameters = self.next_ty_vars(assoc_type_parameter_count); + + subst::Substs::new_trait(type_parameters, regions, assoc_type_parameters, self_ty) } pub fn fresh_bound_region(&self, binder_id: ast::NodeId) -> ty::Region { @@ -791,7 +796,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn ty_to_string(&self, t: ty::t) -> String { ty_to_string(self.tcx, - self.resolve_type_vars_if_possible(t)) + self.resolve_type_vars_if_possible(t)) } pub fn tys_to_string(&self, ts: &[ty::t]) -> String { diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs index 8befba00fd2fe..fb80b9f30f5df 100644 --- a/src/librustc/util/ppaux.rs +++ b/src/librustc/util/ppaux.rs @@ -48,16 +48,18 @@ pub trait UserString { pub fn note_and_explain_region(cx: &ctxt, prefix: &str, region: ty::Region, - suffix: &str) { + suffix: &str) -> Option { match explain_region_and_span(cx, region) { (ref str, Some(span)) => { cx.sess.span_note( span, format!("{}{}{}", prefix, *str, suffix).as_slice()); + Some(span) } (ref str, None) => { cx.sess.note( format!("{}{}{}", prefix, *str, suffix).as_slice()); + None } } } @@ -423,7 +425,13 @@ pub fn ty_to_string(cx: &ctxt, typ: t) -> String { } ty_infer(infer_ty) => infer_ty_to_string(cx, infer_ty), ty_err => "[type error]".to_string(), - ty_param(ref param_ty) => param_ty.repr(cx), + ty_param(ref param_ty) => { + if cx.sess.verbose() { + param_ty.repr(cx) + } else { + param_ty.user_string(cx) + } + } ty_enum(did, ref substs) | ty_struct(did, ref substs) => { let base = ty::item_path_str(cx, did); let generics = ty::lookup_item_type(cx, did).generics; @@ -479,6 +487,17 @@ pub fn parameterized(cx: &ctxt, generics: &ty::Generics) -> String { + if cx.sess.verbose() { + if substs.is_noop() { + return format!("{}", base); + } else { + return format!("{}<{},{}>", + base, + substs.regions.repr(cx), + substs.types.repr(cx)); + } + } + let mut strs = Vec::new(); match substs.regions { @@ -503,7 +522,7 @@ pub fn parameterized(cx: &ctxt, let tps = substs.types.get_slice(subst::TypeSpace); let ty_params = generics.types.get_slice(subst::TypeSpace); let has_defaults = ty_params.last().map_or(false, |def| def.default.is_some()); - let num_defaults = if has_defaults && !cx.sess.verbose() { + let num_defaults = if has_defaults { ty_params.iter().zip(tps.iter()).rev().take_while(|&(def, &actual)| { match def.default { Some(default) => default.subst(cx, substs) == actual, @@ -518,18 +537,6 @@ pub fn parameterized(cx: &ctxt, strs.push(ty_to_string(cx, *t)) } - if cx.sess.verbose() { - for t in substs.types.get_slice(subst::SelfSpace).iter() { - strs.push(format!("self {}", t.repr(cx))); - } - - // generally there shouldn't be any substs in the fn param - // space, but in verbose mode, print them out. - for t in substs.types.get_slice(subst::FnSpace).iter() { - strs.push(format!("fn {}", t.repr(cx))); - } - } - if strs.len() > 0u { format!("{}<{}>", base, strs.connect(", ")) } else { @@ -666,10 +673,11 @@ impl Repr for subst::Substs { impl Repr for subst::VecPerParamSpace { fn repr(&self, tcx: &ctxt) -> String { - format!("[{};{};{}]", - self.get_slice(subst::TypeSpace).repr(tcx), - self.get_slice(subst::SelfSpace).repr(tcx), - self.get_slice(subst::FnSpace).repr(tcx)) + format!("[{};{};{};{}]", + self.get_slice(subst::TypeSpace).repr(tcx), + self.get_slice(subst::SelfSpace).repr(tcx), + self.get_slice(subst::AssocSpace).repr(tcx), + self.get_slice(subst::FnSpace).repr(tcx)) } } @@ -724,7 +732,7 @@ impl Repr for ty::TraitRef { fn repr(&self, tcx: &ctxt) -> String { let base = ty::item_path_str(tcx, self.def_id); let trait_def = ty::lookup_trait_def(tcx, self.def_id); - format!("<{} as {}>", + format!("<{} : {}>", self.substs.self_ty().repr(tcx), parameterized(tcx, base.as_slice(), &self.substs, &trait_def.generics)) } @@ -739,6 +747,19 @@ impl Repr for ty::TraitDef { } } +impl Repr for ast::TraitItem { + fn repr(&self, _tcx: &ctxt) -> String { + match *self { + ast::RequiredMethod(ref data) => format!("RequiredMethod({}, id={})", + data.ident, data.id), + ast::ProvidedMethod(ref data) => format!("ProvidedMethod(id={})", + data.id), + ast::TypeTraitItem(ref data) => format!("TypeTraitItem({}, id={})", + data.ty_param.ident, data.ty_param.id), + } + } +} + impl Repr for ast::Expr { fn repr(&self, _tcx: &ctxt) -> String { format!("expr({}: {})", self.id, pprust::expr_to_string(self)) @@ -757,6 +778,12 @@ impl UserString for ast::Path { } } +impl Repr for ast::Ty { + fn repr(&self, _tcx: &ctxt) -> String { + format!("type({})", pprust::ty_to_string(self)) + } +} + impl Repr for ast::Item { fn repr(&self, tcx: &ctxt) -> String { format!("item({})", tcx.map.node_to_string(self.id)) @@ -1260,7 +1287,8 @@ impl UserString for ParamTy { impl Repr for ParamTy { fn repr(&self, tcx: &ctxt) -> String { - self.user_string(tcx) + let ident = self.user_string(tcx); + format!("{}/{}.{}", ident, self.space, self.idx) } } diff --git a/src/librustc_llvm/lib.rs b/src/librustc_llvm/lib.rs index 06456a91e03f3..48e1e590058bb 100644 --- a/src/librustc_llvm/lib.rs +++ b/src/librustc_llvm/lib.rs @@ -547,7 +547,7 @@ extern { pub fn LLVMIsFunctionVarArg(FunctionTy: TypeRef) -> Bool; pub fn LLVMGetReturnType(FunctionTy: TypeRef) -> TypeRef; pub fn LLVMCountParamTypes(FunctionTy: TypeRef) -> c_uint; - pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *const TypeRef); + pub fn LLVMGetParamTypes(FunctionTy: TypeRef, Dest: *mut TypeRef); /* Operations on struct types */ pub fn LLVMStructTypeInContext(C: ContextRef, @@ -2195,4 +2195,3 @@ pub unsafe fn static_link_hack_this_sucks() { // Works to the above fix for #15460 to ensure LLVM dependencies that // are only used by rustllvm don't get stripped by the linker. mod llvmdeps; - diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index c128588918e28..f96b3916f06de 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2203,12 +2203,12 @@ impl Clean for attr::Stability { impl Clean for ast::AssociatedType { fn clean(&self, cx: &DocContext) -> Item { Item { - source: self.span.clean(cx), - name: Some(self.ident.clean(cx)), + source: self.ty_param.span.clean(cx), + name: Some(self.ty_param.ident.clean(cx)), attrs: self.attrs.clean(cx), inner: AssociatedTypeItem, visibility: None, - def_id: ast_util::local_def(self.id), + def_id: ast_util::local_def(self.ty_param.id), stability: None, } } diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs index cde2dfac37821..e0d436f5e0eb6 100644 --- a/src/libserialize/json.rs +++ b/src/libserialize/json.rs @@ -203,6 +203,7 @@ use std::num::{FPNaN, FPInfinite}; use std::str::ScalarValue; use std::string; use std::vec::Vec; +use std::ops; use Encodable; @@ -889,9 +890,9 @@ impl Json { /// If the Json value is an Object, returns the value associated with the provided key. /// Otherwise, returns None. - pub fn find<'a>(&'a self, key: &string::String) -> Option<&'a Json>{ + pub fn find<'a>(&'a self, key: &str) -> Option<&'a Json>{ match self { - &Object(ref map) => map.find(key), + &Object(ref map) => map.find_with(|s| key.cmp(&s.as_slice())), _ => None } } @@ -899,7 +900,7 @@ impl Json { /// Attempts to get a nested Json Object for each key in `keys`. /// If any key is found not to exist, find_path will return None. /// Otherwise, it will return the Json value associated with the final key. - pub fn find_path<'a>(&'a self, keys: &[&string::String]) -> Option<&'a Json>{ + pub fn find_path<'a>(&'a self, keys: &[&str]) -> Option<&'a Json>{ let mut target = self; for key in keys.iter() { match target.find(*key) { @@ -913,20 +914,19 @@ impl Json { /// If the Json value is an Object, performs a depth-first search until /// a value associated with the provided key is found. If no value is found /// or the Json value is not an Object, returns None. - pub fn search<'a>(&'a self, key: &string::String) -> Option<&'a Json> { + pub fn search<'a>(&'a self, key: &str) -> Option<&'a Json> { match self { &Object(ref map) => { - match map.find(key) { + match map.find_with(|s| key.cmp(&s.as_slice())) { Some(json_value) => Some(json_value), None => { - let mut value : Option<&'a Json> = None; for (_, v) in map.iter() { - value = v.search(key); - if value.is_some() { - break; + match v.search(key) { + x if x.is_some() => return x, + _ => () } } - value + None } } }, @@ -1068,6 +1068,21 @@ impl Json { } } +impl<'a> ops::Index<&'a str, Json> for Json { + fn index<'a>(&'a self, idx: & &str) -> &'a Json { + self.find(*idx).unwrap() + } +} + +impl ops::Index for Json { + fn index<'a>(&'a self, idx: &uint) -> &'a Json { + match self { + &List(ref v) => v.index(idx), + _ => panic!("can only index Json with uint if it is a list") + } + } +} + /// The output of the streaming parser. #[deriving(PartialEq, Clone, Show)] pub enum JsonEvent { @@ -3089,26 +3104,33 @@ mod tests { #[test] fn test_find(){ let json_value = from_str("{\"dog\" : \"cat\"}").unwrap(); - let found_str = json_value.find(&"dog".to_string()); - assert!(found_str.is_some() && found_str.unwrap().as_string().unwrap() == "cat"); + let found_str = json_value.find("dog"); + assert!(found_str.unwrap().as_string().unwrap() == "cat"); } #[test] fn test_find_path(){ let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap(); - let found_str = json_value.find_path(&[&"dog".to_string(), - &"cat".to_string(), &"mouse".to_string()]); - assert!(found_str.is_some() && found_str.unwrap().as_string().unwrap() == "cheese"); + let found_str = json_value.find_path(&["dog", "cat", "mouse"]); + assert!(found_str.unwrap().as_string().unwrap() == "cheese"); } #[test] fn test_search(){ let json_value = from_str("{\"dog\":{\"cat\": {\"mouse\" : \"cheese\"}}}").unwrap(); - let found_str = json_value.search(&"mouse".to_string()).and_then(|j| j.as_string()); - assert!(found_str.is_some()); + let found_str = json_value.search("mouse").and_then(|j| j.as_string()); assert!(found_str.unwrap() == "cheese"); } + #[test] + fn test_index(){ + let json_value = from_str("{\"animals\":[\"dog\",\"cat\",\"mouse\"]}").unwrap(); + let ref list = json_value["animals"]; + assert_eq!(list[0].as_string().unwrap(), "dog"); + assert_eq!(list[1].as_string().unwrap(), "cat"); + assert_eq!(list[2].as_string().unwrap(), "mouse"); + } + #[test] fn test_is_object(){ let json_value = from_str("{}").unwrap(); diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs index 823bd49d7a663..b9758e11bc784 100644 --- a/src/libstd/collections/hash/set.rs +++ b/src/libstd/collections/hash/set.rs @@ -10,7 +10,6 @@ // // ignore-lexer-test FIXME #15883 -use clone::Clone; use cmp::{Eq, Equiv, PartialEq}; use core::kinds::Sized; use default::Default; diff --git a/src/libstd/io/process.rs b/src/libstd/io/process.rs index 312a4c41ac9a6..493e1b559d7b7 100644 --- a/src/libstd/io/process.rs +++ b/src/libstd/io/process.rs @@ -26,7 +26,6 @@ use rt::rtio; use c_str::CString; use collections::HashMap; use hash::Hash; -use clone::Clone; #[cfg(windows)] use std::hash::sip::SipState; diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 0b2f17b8f93cc..63c3956ef2412 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -333,35 +333,10 @@ pub fn to_str_exp_digits(num: f32, dig: uint, upper: bool) -> String { r } -/// Convert a string in base 16 to a float. -/// Accepts an optional binary exponent. -/// -/// This function accepts strings such as -/// -/// * 'a4.fe' -/// * '+a4.fe', equivalent to 'a4.fe' -/// * '-a4.fe' -/// * '2b.aP128', or equivalently, '2b.ap128' -/// * '2b.aP-128' -/// * '.' (understood as 0) -/// * 'c.' -/// * '.c', or, equivalently, '0.c' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `None` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `[num]`. #[inline] -pub fn from_str_hex(num: &str) -> Option { - strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false, false) +#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] +pub fn from_str_hex(src: &str) -> Option { + strconv::from_str_radix_float(src, 16) } impl FromStr for f32 { @@ -384,16 +359,15 @@ impl FromStr for f32 { /// /// # Arguments /// - /// * num - A string + /// * src - A string /// /// # Return value /// /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `num`. + /// `Some(n)` where `n` is the floating-point number represented by `src`. #[inline] - fn from_str(val: &str) -> Option { - strconv::from_str_common(val, 10u, true, true, true, - strconv::ExpDec, false, false) + fn from_str(src: &str) -> Option { + strconv::from_str_radix_float(src, 10u) } } @@ -408,17 +382,16 @@ impl num::FromStrRadix for f32 { /// /// # Arguments /// - /// * num - A string + /// * src - A string /// * radix - The base to use. Must lie in the range [2 .. 36] /// /// # Return value /// /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `num`. + /// `Some(n)` where `n` is the floating-point number represented by `src`. #[inline] - fn from_str_radix(val: &str, rdx: uint) -> Option { - strconv::from_str_common(val, rdx, true, true, false, - strconv::ExpNone, false, false) + fn from_str_radix(src: &str, radix: uint) -> Option { + strconv::from_str_radix_float(src, radix) } } @@ -710,8 +683,8 @@ mod tests { fn test_ldexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f32 = from_str_hex("1p-123").unwrap(); - let f2: f32 = from_str_hex("1p-111").unwrap(); + let f1: f32 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); + let f2: f32 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); assert_eq!(FloatMath::ldexp(1f32, -123), f1); assert_eq!(FloatMath::ldexp(1f32, -111), f2); @@ -730,8 +703,8 @@ mod tests { fn test_frexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f32 = from_str_hex("1p-123").unwrap(); - let f2: f32 = from_str_hex("1p-111").unwrap(); + let f1: f32 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); + let f2: f32 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); let (x1, exp1) = f1.frexp(); let (x2, exp2) = f2.frexp(); assert_eq!((x1, exp1), (0.5f32, -122)); diff --git a/src/libstd/num/f64.rs b/src/libstd/num/f64.rs index 35555b140815a..6e8e92eb91d03 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/num/f64.rs @@ -341,92 +341,60 @@ pub fn to_str_exp_digits(num: f64, dig: uint, upper: bool) -> String { r } -/// Convert a string in base 16 to a float. -/// Accepts an optional binary exponent. -/// -/// This function accepts strings such as -/// -/// * 'a4.fe' -/// * '+a4.fe', equivalent to 'a4.fe' -/// * '-a4.fe' -/// * '2b.aP128', or equivalently, '2b.ap128' -/// * '2b.aP-128' -/// * '.' (understood as 0) -/// * 'c.' -/// * '.c', or, equivalently, '0.c' -/// * '+inf', 'inf', '-inf', 'NaN' -/// -/// Leading and trailing whitespace represent an error. -/// -/// # Arguments -/// -/// * num - A string -/// -/// # Return value -/// -/// `None` if the string did not represent a valid number. Otherwise, -/// `Some(n)` where `n` is the floating-point number represented by `[num]`. #[inline] -pub fn from_str_hex(num: &str) -> Option { - strconv::from_str_common(num, 16u, true, true, true, - strconv::ExpBin, false, false) +#[deprecated="Use `FromStrRadix::from_str_radix(src, 16)`"] +pub fn from_str_hex(src: &str) -> Option { + strconv::from_str_radix_float(src, 16) } impl FromStr for f64 { /// Convert a string in base 10 to a float. /// Accepts an optional decimal exponent. /// - /// This function accepts strings such as + /// This function accepts strings such as: /// /// * '3.14' - /// * '+3.14', equivalent to '3.14' /// * '-3.14' /// * '2.5E10', or equivalently, '2.5e10' /// * '2.5E-10' /// * '.' (understood as 0) /// * '5.' /// * '.5', or, equivalently, '0.5' - /// * '+inf', 'inf', '-inf', 'NaN' + /// * inf', '-inf', 'NaN' /// /// Leading and trailing whitespace represent an error. /// /// # Arguments /// - /// * num - A string + /// * src - A string /// /// # Return value /// /// `none` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `num`. + /// `Some(n)` where `n` is the floating-point number represented by `src`. #[inline] - fn from_str(val: &str) -> Option { - strconv::from_str_common(val, 10u, true, true, true, - strconv::ExpDec, false, false) + fn from_str(src: &str) -> Option { + strconv::from_str_radix_float(src, 10u) } } impl num::FromStrRadix for f64 { /// Convert a string in a given base to a float. /// - /// Due to possible conflicts, this function does **not** accept - /// the special values `inf`, `-inf`, `+inf` and `NaN`, **nor** - /// does it recognize exponents of any kind. - /// /// Leading and trailing whitespace represent an error. /// /// # Arguments /// - /// * num - A string + /// * src - A string /// * radix - The base to use. Must lie in the range [2 .. 36] /// /// # Return value /// /// `None` if the string did not represent a valid number. Otherwise, - /// `Some(n)` where `n` is the floating-point number represented by `num`. + /// `Some(n)` where `n` is the floating-point number represented by `src`. #[inline] - fn from_str_radix(val: &str, rdx: uint) -> Option { - strconv::from_str_common(val, rdx, true, true, false, - strconv::ExpNone, false, false) + fn from_str_radix(src: &str, radix: uint) -> Option { + strconv::from_str_radix_float(src, radix) } } @@ -712,8 +680,8 @@ mod tests { fn test_ldexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f64 = from_str_hex("1p-123").unwrap(); - let f2: f64 = from_str_hex("1p-111").unwrap(); + let f1: f64 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); + let f2: f64 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); assert_eq!(FloatMath::ldexp(1f64, -123), f1); assert_eq!(FloatMath::ldexp(1f64, -111), f2); @@ -732,8 +700,8 @@ mod tests { fn test_frexp() { // We have to use from_str until base-2 exponents // are supported in floating-point literals - let f1: f64 = from_str_hex("1p-123").unwrap(); - let f2: f64 = from_str_hex("1p-111").unwrap(); + let f1: f64 = FromStrRadix::from_str_radix("1p-123", 16).unwrap(); + let f2: f64 = FromStrRadix::from_str_radix("1p-111", 16).unwrap(); let (x1, exp1) = f1.frexp(); let (x2, exp2) = f2.frexp(); assert_eq!((x1, exp1), (0.5f64, -122)); diff --git a/src/libstd/num/int_macros.rs b/src/libstd/num/int_macros.rs index ca45b40e687a1..9ae146c840ae8 100644 --- a/src/libstd/num/int_macros.rs +++ b/src/libstd/num/int_macros.rs @@ -14,31 +14,11 @@ macro_rules! int_module (($T:ty) => ( -// String conversion functions and impl str -> num - -/// Parse a byte slice as a number in the given base -/// -/// Yields an `Option` because `buf` may or may not actually be parseable. -/// -/// # Examples -/// -/// ``` -/// let num = std::i64::parse_bytes([49,50,51,52,53,54,55,56,57], 10); -/// assert!(num == Some(123456789)); -/// ``` -#[inline] -#[experimental = "might need to return Result"] -pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> { - strconv::from_str_bytes_common(buf, radix, true, false, false, - strconv::ExpNone, false, false) -} - #[experimental = "might need to return Result"] impl FromStr for $T { #[inline] fn from_str(s: &str) -> Option<$T> { - strconv::from_str_common(s, 10u, true, false, false, - strconv::ExpNone, false, false) + strconv::from_str_radix_int(s, 10) } } @@ -46,18 +26,14 @@ impl FromStr for $T { impl FromStrRadix for $T { #[inline] fn from_str_radix(s: &str, radix: uint) -> Option<$T> { - strconv::from_str_common(s, radix, true, false, false, - strconv::ExpNone, false, false) + strconv::from_str_radix_int(s, radix) } } #[cfg(test)] mod tests { use prelude::*; - use super::*; - - use i32; - use str::StrSlice; + use num::FromStrRadix; #[test] fn test_from_str() { @@ -73,33 +49,33 @@ mod tests { assert_eq!(from_str::("-123456789"), Some(-123456789 as i32)); assert_eq!(from_str::<$T>("-00100"), Some(-100 as $T)); - assert!(from_str::<$T>(" ").is_none()); - assert!(from_str::<$T>("x").is_none()); + assert_eq!(from_str::<$T>(""), None); + assert_eq!(from_str::<$T>(" "), None); + assert_eq!(from_str::<$T>("x"), None); } #[test] - fn test_parse_bytes() { - use str::StrSlice; - assert_eq!(parse_bytes("123".as_bytes(), 10u), Some(123 as $T)); - assert_eq!(parse_bytes("1001".as_bytes(), 2u), Some(9 as $T)); - assert_eq!(parse_bytes("123".as_bytes(), 8u), Some(83 as $T)); - assert_eq!(i32::parse_bytes("123".as_bytes(), 16u), Some(291 as i32)); - assert_eq!(i32::parse_bytes("ffff".as_bytes(), 16u), Some(65535 as i32)); - assert_eq!(i32::parse_bytes("FFFF".as_bytes(), 16u), Some(65535 as i32)); - assert_eq!(parse_bytes("z".as_bytes(), 36u), Some(35 as $T)); - assert_eq!(parse_bytes("Z".as_bytes(), 36u), Some(35 as $T)); - - assert_eq!(parse_bytes("-123".as_bytes(), 10u), Some(-123 as $T)); - assert_eq!(parse_bytes("-1001".as_bytes(), 2u), Some(-9 as $T)); - assert_eq!(parse_bytes("-123".as_bytes(), 8u), Some(-83 as $T)); - assert_eq!(i32::parse_bytes("-123".as_bytes(), 16u), Some(-291 as i32)); - assert_eq!(i32::parse_bytes("-ffff".as_bytes(), 16u), Some(-65535 as i32)); - assert_eq!(i32::parse_bytes("-FFFF".as_bytes(), 16u), Some(-65535 as i32)); - assert_eq!(parse_bytes("-z".as_bytes(), 36u), Some(-35 as $T)); - assert_eq!(parse_bytes("-Z".as_bytes(), 36u), Some(-35 as $T)); - - assert!(parse_bytes("Z".as_bytes(), 35u).is_none()); - assert!(parse_bytes("-9".as_bytes(), 2u).is_none()); + fn test_from_str_radix() { + assert_eq!(FromStrRadix::from_str_radix("123", 10), Some(123 as $T)); + assert_eq!(FromStrRadix::from_str_radix("1001", 2), Some(9 as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 8), Some(83 as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 16), Some(291 as i32)); + assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Some(65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("FFFF", 16), Some(65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("z", 36), Some(35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("Z", 36), Some(35 as $T)); + + assert_eq!(FromStrRadix::from_str_radix("-123", 10), Some(-123 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-1001", 2), Some(-9 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-123", 8), Some(-83 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-123", 16), Some(-291 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-ffff", 16), Some(-65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-FFFF", 16), Some(-65535 as i32)); + assert_eq!(FromStrRadix::from_str_radix("-z", 36), Some(-35 as $T)); + assert_eq!(FromStrRadix::from_str_radix("-Z", 36), Some(-35 as $T)); + + assert_eq!(FromStrRadix::from_str_radix("Z", 35), None::<$T>); + assert_eq!(FromStrRadix::from_str_radix("-9", 2), None::<$T>); } #[test] @@ -133,35 +109,35 @@ mod tests { fn test_int_from_str_overflow() { let mut i8_val: i8 = 127_i8; assert_eq!(from_str::("127"), Some(i8_val)); - assert!(from_str::("128").is_none()); + assert_eq!(from_str::("128"), None); i8_val += 1 as i8; assert_eq!(from_str::("-128"), Some(i8_val)); - assert!(from_str::("-129").is_none()); + assert_eq!(from_str::("-129"), None); let mut i16_val: i16 = 32_767_i16; assert_eq!(from_str::("32767"), Some(i16_val)); - assert!(from_str::("32768").is_none()); + assert_eq!(from_str::("32768"), None); i16_val += 1 as i16; assert_eq!(from_str::("-32768"), Some(i16_val)); - assert!(from_str::("-32769").is_none()); + assert_eq!(from_str::("-32769"), None); let mut i32_val: i32 = 2_147_483_647_i32; assert_eq!(from_str::("2147483647"), Some(i32_val)); - assert!(from_str::("2147483648").is_none()); + assert_eq!(from_str::("2147483648"), None); i32_val += 1 as i32; assert_eq!(from_str::("-2147483648"), Some(i32_val)); - assert!(from_str::("-2147483649").is_none()); + assert_eq!(from_str::("-2147483649"), None); let mut i64_val: i64 = 9_223_372_036_854_775_807_i64; assert_eq!(from_str::("9223372036854775807"), Some(i64_val)); - assert!(from_str::("9223372036854775808").is_none()); + assert_eq!(from_str::("9223372036854775808"), None); i64_val += 1 as i64; assert_eq!(from_str::("-9223372036854775808"), Some(i64_val)); - assert!(from_str::("-9223372036854775809").is_none()); + assert_eq!(from_str::("-9223372036854775809"), None); } } diff --git a/src/libstd/num/strconv.rs b/src/libstd/num/strconv.rs index 30ecf2284df76..7a02d8d77b0b1 100644 --- a/src/libstd/num/strconv.rs +++ b/src/libstd/num/strconv.rs @@ -13,14 +13,14 @@ #![allow(missing_docs)] use char; -use clone::Clone; -use num::{NumCast, Zero, One, cast, Int}; -use num::{Float, FPNaN, FPInfinite, ToPrimitive}; +use char::Char; +use from_str::from_str; +use iter::Iterator; use num; -use ops::{Add, Sub, Mul, Div, Rem, Neg}; +use num::{Int, Bounded}; +use num::{Float, FPNaN, FPInfinite, ToPrimitive}; use option::{None, Option, Some}; use slice::{ImmutableSlice, MutableSlice, CloneableVector}; -use std::cmp::{PartialOrd, PartialEq}; use str::StrSlice; use string::String; use vec::Vec; @@ -67,81 +67,6 @@ pub enum SignFormat { SignAll, } -/// Encompasses functions used by the string converter. -pub trait NumStrConv { - /// Returns the NaN value. - fn nan() -> Option; - - /// Returns the infinite value. - fn inf() -> Option; - - /// Returns the negative infinite value. - fn neg_inf() -> Option; - - /// Returns -0.0. - fn neg_zero() -> Option; - - /// Rounds the number toward zero. - fn round_to_zero(&self) -> Self; - - /// Returns the fractional part of the number. - fn fractional_part(&self) -> Self; -} - -macro_rules! impl_NumStrConv_Floating (($t:ty) => ( - impl NumStrConv for $t { - #[inline] - fn nan() -> Option<$t> { Some( 0.0 / 0.0) } - #[inline] - fn inf() -> Option<$t> { Some( 1.0 / 0.0) } - #[inline] - fn neg_inf() -> Option<$t> { Some(-1.0 / 0.0) } - #[inline] - fn neg_zero() -> Option<$t> { Some(-0.0 ) } - - #[inline] - fn round_to_zero(&self) -> $t { self.trunc() } - #[inline] - fn fractional_part(&self) -> $t { self.fract() } - } -)) - -macro_rules! impl_NumStrConv_Integer (($t:ty) => ( - impl NumStrConv for $t { - #[inline] fn nan() -> Option<$t> { None } - #[inline] fn inf() -> Option<$t> { None } - #[inline] fn neg_inf() -> Option<$t> { None } - #[inline] fn neg_zero() -> Option<$t> { None } - - #[inline] fn round_to_zero(&self) -> $t { *self } - #[inline] fn fractional_part(&self) -> $t { 0 } - } -)) - -// FIXME: #4955 -// Replace by two generic impls for traits 'Integral' and 'Floating' -impl_NumStrConv_Floating!(f32) -impl_NumStrConv_Floating!(f64) - -impl_NumStrConv_Integer!(int) -impl_NumStrConv_Integer!(i8) -impl_NumStrConv_Integer!(i16) -impl_NumStrConv_Integer!(i32) -impl_NumStrConv_Integer!(i64) - -impl_NumStrConv_Integer!(uint) -impl_NumStrConv_Integer!(u8) -impl_NumStrConv_Integer!(u16) -impl_NumStrConv_Integer!(u32) -impl_NumStrConv_Integer!(u64) - - -// Special value strings as [u8] consts. -static INF_BUF: [u8, ..3] = [b'i', b'n', b'f']; -static POS_INF_BUF: [u8, ..4] = [b'+', b'i', b'n', b'f']; -static NEG_INF_BUF: [u8, ..4] = [b'-', b'i', b'n', b'f']; -static NAN_BUF: [u8, ..3] = [b'N', b'a', b'N']; - /** * Converts an integral number to its string representation as a byte vector. * This is meant to be a common base implementation for all integral string @@ -170,10 +95,10 @@ static NAN_BUF: [u8, ..3] = [b'N', b'a', b'N']; fn int_to_str_bytes_common(num: T, radix: uint, sign: SignFormat, f: |u8|) { assert!(2 <= radix && radix <= 36); - let _0: T = Zero::zero(); + let _0: T = num::zero(); let neg = num < _0; - let radix_gen: T = cast(radix).unwrap(); + let radix_gen: T = num::cast(radix).unwrap(); let mut deccum = num; // This is just for integral types, the largest of which is a u64. The @@ -255,8 +180,7 @@ fn int_to_str_bytes_common(num: T, radix: uint, sign: SignFormat, f: |u8 * - Fails if `radix` > 25 and `exp_format` is `ExpBin` due to conflict * between digit and exponent sign `'p'`. */ -pub fn float_to_str_bytes_common+Neg+Rem+Mul>( +pub fn float_to_str_bytes_common( num: T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool ) -> (Vec, bool) { @@ -271,8 +195,8 @@ pub fn float_to_str_bytes_common () } - let _0: T = Zero::zero(); - let _1: T = One::one(); + let _0: T = num::zero(); + let _1: T = num::one(); match num.classify() { FPNaN => { return (b"NaN".to_vec(), true); } @@ -293,7 +217,7 @@ pub fn float_to_str_bytes_common (num, 0i32), @@ -302,12 +226,12 @@ pub fn float_to_str_bytes_common (num.abs().log10().floor(), cast::(10.0f64).unwrap()), - ExpBin => (num.abs().log2().floor(), cast::(2.0f64).unwrap()), + ExpDec => (num.abs().log10().floor(), num::cast::(10.0f64).unwrap()), + ExpBin => (num.abs().log2().floor(), num::cast::(2.0f64).unwrap()), ExpNone => unreachable!() }; - (num / exp_base.powf(exp), cast::(exp).unwrap()) + (num / exp_base.powf(exp), num::cast::(exp).unwrap()) } } }; @@ -488,8 +412,7 @@ pub fn float_to_str_bytes_common+Neg+Rem+Mul>( +pub fn float_to_str_common( num: T, radix: uint, negative_zero: bool, sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_capital: bool ) -> (String, bool) { @@ -501,311 +424,228 @@ pub fn float_to_str_common 36. - * - Fails if `radix` > 14 and `exponent` is `ExpDec` due to conflict - * between digit and exponent sign `'e'`. - * - Fails if `radix` > 25 and `exponent` is `ExpBin` due to conflict - * between digit and exponent sign `'p'`. - * - Fails if `radix` > 18 and `special == true` due to conflict - * between digit and lowest first character in `inf` and `NaN`, the `'i'`. - */ -pub fn from_str_bytes_common+ - Mul+Sub+Neg+Add+ - NumStrConv+Clone>( - buf: &[u8], radix: uint, negative: bool, fractional: bool, - special: bool, exponent: ExponentFormat, empty_zero: bool, - ignore_underscores: bool - ) -> Option { - match exponent { - ExpDec if radix >= DIGIT_E_RADIX // decimal exponent 'e' - => panic!("from_str_bytes_common: radix {} incompatible with \ - use of 'e' as decimal exponent", radix), - ExpBin if radix >= DIGIT_P_RADIX // binary exponent 'p' - => panic!("from_str_bytes_common: radix {} incompatible with \ - use of 'p' as binary exponent", radix), - _ if special && radix >= DIGIT_I_RADIX // first digit of 'inf' - => panic!("from_str_bytes_common: radix {} incompatible with \ - special values 'inf' and 'NaN'", radix), - _ if (radix as int) < 2 - => panic!("from_str_bytes_common: radix {} to low, \ - must lie in the range [2, 36]", radix), - _ if (radix as int) > 36 - => panic!("from_str_bytes_common: radix {} to high, \ - must lie in the range [2, 36]", radix), - _ => () - } - - let _0: T = Zero::zero(); - let _1: T = One::one(); - let radix_gen: T = cast(radix as int).unwrap(); - - let len = buf.len(); - - if len == 0 { - if empty_zero { - return Some(_0); - } else { - return None; - } +pub fn from_str_radix_float(src: &str, radix: uint) -> Option { + assert!(radix >= 2 && radix <= 36, + "from_str_radix_float: must lie in the range `[2, 36]` - found {}", + radix); + + let _0: T = num::zero(); + let _1: T = num::one(); + let radix_t: T = num::cast(radix as int).unwrap(); + + // Special values + match src { + "inf" => return Some(Float::infinity()), + "-inf" => return Some(Float::neg_infinity()), + "NaN" => return Some(Float::nan()), + _ => {}, } - if special { - if buf == INF_BUF || buf == POS_INF_BUF { - return NumStrConv::inf(); - } else if buf == NEG_INF_BUF { - if negative { - return NumStrConv::neg_inf(); - } else { - return None; - } - } else if buf == NAN_BUF { - return NumStrConv::nan(); - } - } - - let (start, accum_positive) = match buf[0] as char { - '-' if !negative => return None, - '-' => (1u, false), - '+' => (1u, true), - _ => (0u, true) + let (is_positive, src) = match src.slice_shift_char() { + (None, _) => return None, + (Some('-'), "") => return None, + (Some('-'), src) => (false, src), + (Some(_), _) => (true, src), }; - // Initialize accumulator with signed zero for floating point parsing to - // work - let mut accum = if accum_positive { _0.clone() } else { -_1 * _0}; - let mut last_accum = accum.clone(); // Necessary to detect overflow - let mut i = start; - let mut exp_found = false; - - // Parse integer part of number - while i < len { - let c = buf[i] as char; - - match char::to_digit(c, radix) { + // The significand to accumulate + let mut sig = if is_positive { _0 } else { -_1 }; + // Necessary to detect overflow + let mut prev_sig = sig; + let mut cs = src.chars().enumerate(); + // Exponent prefix and exponent index offset + let mut exp_info = None::<(char, uint)>; + + // Parse the integer part of the significand + for (i, c) in cs { + match c.to_digit(radix) { Some(digit) => { - // shift accum one digit left - accum = accum * radix_gen.clone(); + // shift significand one digit left + sig = sig * radix_t; // add/subtract current digit depending on sign - if accum_positive { - accum = accum + cast(digit as int).unwrap(); + if is_positive { + sig = sig + num::cast(digit as int).unwrap(); } else { - accum = accum - cast(digit as int).unwrap(); + sig = sig - num::cast(digit as int).unwrap(); } // Detect overflow by comparing to last value, except // if we've not seen any non-zero digits. - if last_accum != _0 { - if accum_positive && accum <= last_accum { return NumStrConv::inf(); } - if !accum_positive && accum >= last_accum { return NumStrConv::neg_inf(); } + if prev_sig != _0 { + if is_positive && sig <= prev_sig + { return Some(Float::infinity()); } + if !is_positive && sig >= prev_sig + { return Some(Float::neg_infinity()); } // Detect overflow by reversing the shift-and-add process - if accum_positive && - (last_accum != ((accum - cast(digit as int).unwrap())/radix_gen.clone())) { - return NumStrConv::inf(); - } - if !accum_positive && - (last_accum != ((accum + cast(digit as int).unwrap())/radix_gen.clone())) { - return NumStrConv::neg_inf(); - } + let digit: T = num::cast(digit as int).unwrap(); + if is_positive && (prev_sig != ((sig - digit) / radix_t)) + { return Some(Float::infinity()); } + if !is_positive && (prev_sig != ((sig + digit) / radix_t)) + { return Some(Float::neg_infinity()); } } - last_accum = accum.clone(); - } + prev_sig = sig; + }, None => match c { - '_' if ignore_underscores => {} 'e' | 'E' | 'p' | 'P' => { - exp_found = true; - break; // start of exponent - } - '.' if fractional => { - i += 1u; // skip the '.' - break; // start of fractional part - } - _ => return None // invalid number - } + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + '.' => { + break; // start of fractional part + }, + _ => { + return None; + }, + }, } - - i += 1u; } - // Parse fractional part of number - // Skip if already reached start of exponent - if !exp_found { - let mut power = _1.clone(); - - while i < len { - let c = buf[i] as char; - - match char::to_digit(c, radix) { + // If we are not yet at the exponent parse the fractional + // part of the significand + if exp_info.is_none() { + let mut power = _1; + for (i, c) in cs { + match c.to_digit(radix) { Some(digit) => { + let digit: T = num::cast(digit).unwrap(); // Decrease power one order of magnitude - power = power / radix_gen; - - let digit_t: T = cast(digit).unwrap(); - + power = power / radix_t; // add/subtract current digit depending on sign - if accum_positive { - accum = accum + digit_t * power; + sig = if is_positive { + sig + digit * power } else { - accum = accum - digit_t * power; - } - + sig - digit * power + }; // Detect overflow by comparing to last value - if accum_positive && accum < last_accum { return NumStrConv::inf(); } - if !accum_positive && accum > last_accum { return NumStrConv::neg_inf(); } - last_accum = accum.clone(); - } + if is_positive && sig < prev_sig + { return Some(Float::infinity()); } + if !is_positive && sig > prev_sig + { return Some(Float::neg_infinity()); } + prev_sig = sig; + }, None => match c { - '_' if ignore_underscores => {} 'e' | 'E' | 'p' | 'P' => { - exp_found = true; - break; // start of exponent - } - _ => return None // invalid number - } + exp_info = Some((c, i + 1)); + break; // start of exponent + }, + _ => { + return None; // invalid number + }, + }, } - - i += 1u; } } - // Special case: buf not empty, but does not contain any digit in front - // of the exponent sign -> number is empty string - if i == start { - if empty_zero { - return Some(_0); - } else { - return None; - } - } + // Parse and calculate the exponent + let exp = match exp_info { + Some((c, offset)) => { + let base: T = match c { + 'E' | 'e' if radix == 10 => num::cast(10u).unwrap(), + 'P' | 'p' if radix == 16 => num::cast(2u).unwrap(), + _ => return None, + }; - let mut multiplier = _1.clone(); + // Parse the exponent as decimal integer + let src = src[offset..]; + let (is_positive, exp) = match src.slice_shift_char() { + (Some('-'), src) => (false, from_str::(src)), + (Some('+'), src) => (true, from_str::(src)), + (Some(_), _) => (true, from_str::(src)), + (None, _) => return None, + }; - if exp_found { - let c = buf[i] as char; - let base: T = match (c, exponent) { - // c is never _ so don't need to handle specially - ('e', ExpDec) | ('E', ExpDec) => cast(10u).unwrap(), - ('p', ExpBin) | ('P', ExpBin) => cast(2u).unwrap(), - _ => return None // char doesn't fit given exponent format - }; + match (is_positive, exp) { + (true, Some(exp)) => num::pow(base, exp), + (false, Some(exp)) => _1 / num::pow(base, exp), + (_, None) => return None, + } + }, + None => _1, // no exponent + }; + + Some(sig * exp) +} - // parse remaining bytes as decimal integer, - // skipping the exponent char - let exp: Option = from_str_bytes_common( - buf[i+1..len], 10, true, false, false, ExpNone, false, - ignore_underscores); +pub fn from_str_radix_int(src: &str, radix: uint) -> Option { + assert!(radix >= 2 && radix <= 36, + "from_str_radix_int: must lie in the range `[2, 36]` - found {}", + radix); - match exp { - Some(exp_pow) => { - multiplier = if exp_pow < 0 { - _1 / num::pow(base, (-exp_pow.to_int().unwrap()) as uint) - } else { - num::pow(base, exp_pow.to_int().unwrap() as uint) - } - } - None => return None // invalid exponent -> invalid number - } + fn cast(x: uint) -> T { + num::cast(x).unwrap() } - Some(accum * multiplier) -} + let _0: T = num::zero(); + let _1: T = num::one(); + let is_signed = _0 > Bounded::min_value(); -/** - * Parses a string as a number. This is a wrapper for - * `from_str_bytes_common()`, for details see there. - */ -#[inline] -pub fn from_str_common+Mul+ - Sub+Neg+Add+NumStrConv+Clone>( - buf: &str, radix: uint, negative: bool, fractional: bool, - special: bool, exponent: ExponentFormat, empty_zero: bool, - ignore_underscores: bool - ) -> Option { - from_str_bytes_common(buf.as_bytes(), radix, negative, - fractional, special, exponent, empty_zero, - ignore_underscores) + let (is_positive, src) = match src.slice_shift_char() { + (Some('-'), src) if is_signed => (false, src), + (Some(_), _) => (true, src), + (None, _) => return None, + }; + + let mut xs = src.chars().map(|c| { + c.to_digit(radix).map(cast) + }); + let radix = cast(radix); + let mut result = _0; + + if is_positive { + for x in xs { + let x = match x { + Some(x) => x, + None => return None, + }; + result = match result.checked_mul(&radix) { + Some(result) => result, + None => return None, + }; + result = match result.checked_add(&x) { + Some(result) => result, + None => return None, + }; + } + } else { + for x in xs { + let x = match x { + Some(x) => x, + None => return None, + }; + result = match result.checked_mul(&radix) { + Some(result) => result, + None => return None, + }; + result = match result.checked_sub(&x) { + Some(result) => result, + None => return None, + }; + } + } + + Some(result) } #[cfg(test)] mod test { use super::*; use option::*; - - #[test] - fn from_str_ignore_underscores() { - let s : Option = from_str_common("__1__", 2, false, false, false, - ExpNone, false, true); - assert_eq!(s, Some(1u8)); - - let n : Option = from_str_common("__1__", 2, false, false, false, - ExpNone, false, false); - assert_eq!(n, None); - - let f : Option = from_str_common("_1_._5_e_1_", 10, false, true, false, - ExpDec, false, true); - assert_eq!(f, Some(1.5e1f32)); - } - - #[test] - fn from_str_issue5770() { - // try to parse 0b1_1111_1111 = 511 as a u8. Caused problems - // since 255*2+1 == 255 (mod 256) so the overflow wasn't - // detected. - let n : Option = from_str_common("111111111", 2, false, false, false, - ExpNone, false, false); - assert_eq!(n, None); - } + use num::Float; #[test] fn from_str_issue7588() { - let u : Option = from_str_common("1000", 10, false, false, false, - ExpNone, false, false); + let u : Option = from_str_radix_int("1000", 10); assert_eq!(u, None); - let s : Option = from_str_common("80000", 10, false, false, false, - ExpNone, false, false); + let s : Option = from_str_radix_int("80000", 10); assert_eq!(s, None); - let f : Option = from_str_common( - "10000000000000000000000000000000000000000", 10, false, false, false, - ExpNone, false, false); - assert_eq!(f, NumStrConv::inf()) - let fe : Option = from_str_common("1e40", 10, false, false, false, - ExpDec, false, false); - assert_eq!(fe, NumStrConv::inf()) + let f : Option = from_str_radix_float("10000000000000000000000000000000000000000", 10); + assert_eq!(f, Some(Float::infinity())) + let fe : Option = from_str_radix_float("1e40", 10); + assert_eq!(fe, Some(Float::infinity())) } } diff --git a/src/libstd/num/uint_macros.rs b/src/libstd/num/uint_macros.rs index c69c3ffa41c0e..aa8e58bab0286 100644 --- a/src/libstd/num/uint_macros.rs +++ b/src/libstd/num/uint_macros.rs @@ -15,31 +15,11 @@ macro_rules! uint_module (($T:ty) => ( -// String conversion functions and impl str -> num - -/// Parse a byte slice as a number in the given base -/// -/// Yields an `Option` because `buf` may or may not actually be parseable. -/// -/// # Examples -/// -/// ``` -/// let num = std::uint::parse_bytes([49,50,51,52,53,54,55,56,57], 10); -/// assert!(num == Some(123456789)); -/// ``` -#[inline] -#[experimental = "might need to return Result"] -pub fn parse_bytes(buf: &[u8], radix: uint) -> Option<$T> { - strconv::from_str_bytes_common(buf, radix, false, false, false, - strconv::ExpNone, false, false) -} - #[experimental = "might need to return Result"] impl FromStr for $T { #[inline] fn from_str(s: &str) -> Option<$T> { - strconv::from_str_common(s, 10u, false, false, false, - strconv::ExpNone, false, false) + strconv::from_str_radix_int(s, 10) } } @@ -47,8 +27,7 @@ impl FromStr for $T { impl FromStrRadix for $T { #[inline] fn from_str_radix(s: &str, radix: uint) -> Option<$T> { - strconv::from_str_common(s, radix, false, false, false, - strconv::ExpNone, false, false) + strconv::from_str_radix_int(s, radix) } } @@ -85,10 +64,7 @@ pub fn to_str_bytes(n: $T, radix: uint, f: |v: &[u8]| -> U) -> U { #[cfg(test)] mod tests { use prelude::*; - use super::*; - - use str::StrSlice; - use u16; + use num::FromStrRadix; #[test] pub fn test_from_str() { @@ -98,23 +74,22 @@ mod tests { assert_eq!(from_str::("123456789"), Some(123456789 as u32)); assert_eq!(from_str::<$T>("00100"), Some(100u as $T)); - assert!(from_str::<$T>("").is_none()); - assert!(from_str::<$T>(" ").is_none()); - assert!(from_str::<$T>("x").is_none()); + assert_eq!(from_str::<$T>(""), None); + assert_eq!(from_str::<$T>(" "), None); + assert_eq!(from_str::<$T>("x"), None); } #[test] pub fn test_parse_bytes() { - use str::StrSlice; - assert_eq!(parse_bytes("123".as_bytes(), 10u), Some(123u as $T)); - assert_eq!(parse_bytes("1001".as_bytes(), 2u), Some(9u as $T)); - assert_eq!(parse_bytes("123".as_bytes(), 8u), Some(83u as $T)); - assert_eq!(u16::parse_bytes("123".as_bytes(), 16u), Some(291u as u16)); - assert_eq!(u16::parse_bytes("ffff".as_bytes(), 16u), Some(65535u as u16)); - assert_eq!(parse_bytes("z".as_bytes(), 36u), Some(35u as $T)); - - assert!(parse_bytes("Z".as_bytes(), 10u).is_none()); - assert!(parse_bytes("_".as_bytes(), 2u).is_none()); + assert_eq!(FromStrRadix::from_str_radix("123", 10), Some(123u as $T)); + assert_eq!(FromStrRadix::from_str_radix("1001", 2), Some(9u as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 8), Some(83u as $T)); + assert_eq!(FromStrRadix::from_str_radix("123", 16), Some(291u as u16)); + assert_eq!(FromStrRadix::from_str_radix("ffff", 16), Some(65535u as u16)); + assert_eq!(FromStrRadix::from_str_radix("z", 36), Some(35u as $T)); + + assert_eq!(FromStrRadix::from_str_radix("Z", 10), None::<$T>); + assert_eq!(FromStrRadix::from_str_radix("_", 2), None::<$T>); } #[test] @@ -148,35 +123,35 @@ mod tests { fn test_uint_from_str_overflow() { let mut u8_val: u8 = 255_u8; assert_eq!(from_str::("255"), Some(u8_val)); - assert!(from_str::("256").is_none()); + assert_eq!(from_str::("256"), None); u8_val += 1 as u8; assert_eq!(from_str::("0"), Some(u8_val)); - assert!(from_str::("-1").is_none()); + assert_eq!(from_str::("-1"), None); let mut u16_val: u16 = 65_535_u16; assert_eq!(from_str::("65535"), Some(u16_val)); - assert!(from_str::("65536").is_none()); + assert_eq!(from_str::("65536"), None); u16_val += 1 as u16; assert_eq!(from_str::("0"), Some(u16_val)); - assert!(from_str::("-1").is_none()); + assert_eq!(from_str::("-1"), None); let mut u32_val: u32 = 4_294_967_295_u32; assert_eq!(from_str::("4294967295"), Some(u32_val)); - assert!(from_str::("4294967296").is_none()); + assert_eq!(from_str::("4294967296"), None); u32_val += 1 as u32; assert_eq!(from_str::("0"), Some(u32_val)); - assert!(from_str::("-1").is_none()); + assert_eq!(from_str::("-1"), None); let mut u64_val: u64 = 18_446_744_073_709_551_615_u64; assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); - assert!(from_str::("18446744073709551616").is_none()); + assert_eq!(from_str::("18446744073709551616"), None); u64_val += 1 as u64; assert_eq!(from_str::("0"), Some(u64_val)); - assert!(from_str::("-1").is_none()); + assert_eq!(from_str::("-1"), None); } } diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs index a2c859cf9fd3c..18fc970c21832 100644 --- a/src/libsyntax/ast.rs +++ b/src/libsyntax/ast.rs @@ -119,7 +119,7 @@ impl Name { pub fn as_str<'a>(&'a self) -> &'a str { unsafe { // FIXME #12938: can't use copy_lifetime since &str isn't a &T - ::std::mem::transmute(token::get_name(*self).get()) + ::std::mem::transmute::<&str,&str>(token::get_name(*self).get()) } } @@ -385,7 +385,7 @@ pub enum Pat_ { PatLit(P), PatRange(P, P), /// [a, b, ..i, y, z] is represented as: - /// PatVec(~[a, b], Some(i), ~[y, z]) + /// PatVec(box [a, b], Some(i), box [y, z]) PatVec(Vec>, Option>, Vec>), PatMac(Mac), } @@ -861,10 +861,8 @@ pub enum ImplItem { #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] pub struct AssociatedType { - pub id: NodeId, - pub span: Span, - pub ident: Ident, pub attrs: Vec, + pub ty_param: TyParam, } #[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)] diff --git a/src/libsyntax/ast_map/mod.rs b/src/libsyntax/ast_map/mod.rs index fa36577ebdb1f..f049b964ff33d 100644 --- a/src/libsyntax/ast_map/mod.rs +++ b/src/libsyntax/ast_map/mod.rs @@ -405,7 +405,9 @@ impl<'ast> Map<'ast> { MethMac(_) => panic!("no path elem for {}", node), } } - TypeTraitItem(ref m) => PathName(m.ident.name), + TypeTraitItem(ref m) => { + PathName(m.ty_param.ident.name) + } }, NodeVariant(v) => PathName(v.node.name.name), _ => panic!("no path elem for {}", node) @@ -510,7 +512,7 @@ impl<'ast> Map<'ast> { match *trait_method { RequiredMethod(ref type_method) => type_method.span, ProvidedMethod(ref method) => method.span, - TypeTraitItem(ref typedef) => typedef.span, + TypeTraitItem(ref typedef) => typedef.ty_param.span, } } Some(NodeImplItem(ref impl_item)) => { @@ -650,7 +652,7 @@ impl Named for TraitItem { match *self { RequiredMethod(ref tm) => tm.ident.name, ProvidedMethod(ref m) => m.name(), - TypeTraitItem(ref at) => at.ident.name, + TypeTraitItem(ref at) => at.ty_param.ident.name, } } } @@ -783,7 +785,7 @@ impl<'ast> Visitor<'ast> for NodeCollector<'ast> { self.insert(m.id, NodeTraitItem(tm)); } TypeTraitItem(ref typ) => { - self.insert(typ.id, NodeTraitItem(tm)); + self.insert(typ.ty_param.id, NodeTraitItem(tm)); } } } @@ -976,7 +978,7 @@ pub fn map_decoded_item<'ast, F: FoldOps>(map: &Map<'ast>, let trait_item_id = match *trait_item { ProvidedMethod(ref m) => m.id, RequiredMethod(ref m) => m.id, - TypeTraitItem(ref ty) => ty.id, + TypeTraitItem(ref ty) => ty.ty_param.id, }; collector.insert(trait_item_id, NodeTraitItem(trait_item)); @@ -1080,7 +1082,7 @@ fn node_id_to_string(map: &Map, id: NodeId) -> String { } TypeTraitItem(ref t) => { format!("type item {} in {} (id={})", - token::get_ident(t.ident), + token::get_ident(t.ty_param.ident), map.path_to_string(id), id) } diff --git a/src/libsyntax/ast_util.rs b/src/libsyntax/ast_util.rs index 8b0e1f32fd4c9..3aa60236d709a 100644 --- a/src/libsyntax/ast_util.rs +++ b/src/libsyntax/ast_util.rs @@ -21,7 +21,6 @@ use ptr::P; use visit::Visitor; use visit; -use std::cell::Cell; use std::cmp; use std::u32; @@ -333,20 +332,20 @@ impl IdRange { } pub trait IdVisitingOperation { - fn visit_id(&self, node_id: NodeId); + fn visit_id(&mut self, node_id: NodeId); } /// A visitor that applies its operation to all of the node IDs /// in a visitable thing. pub struct IdVisitor<'a, O:'a> { - pub operation: &'a O, + pub operation: &'a mut O, pub pass_through_items: bool, pub visited_outermost: bool, } impl<'a, O: IdVisitingOperation> IdVisitor<'a, O> { - fn visit_generics_helper(&self, generics: &Generics) { + fn visit_generics_helper(&mut self, generics: &Generics) { for type_parameter in generics.ty_params.iter() { self.operation.visit_id(type_parameter.id) } @@ -525,7 +524,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { match *tm { ast::RequiredMethod(ref m) => self.operation.visit_id(m.id), ast::ProvidedMethod(ref m) => self.operation.visit_id(m.id), - ast::TypeTraitItem(ref typ) => self.operation.visit_id(typ.id), + ast::TypeTraitItem(ref typ) => self.operation.visit_id(typ.ty_param.id), } visit::walk_trait_item(self, tm); } @@ -540,7 +539,7 @@ impl<'a, 'v, O: IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> { } pub fn visit_ids_for_inlined_item(item: &InlinedItem, - operation: &O) { + operation: &mut O) { let mut id_visitor = IdVisitor { operation: operation, pass_through_items: true, @@ -551,23 +550,21 @@ pub fn visit_ids_for_inlined_item(item: &InlinedItem, } struct IdRangeComputingVisitor { - result: Cell, + result: IdRange, } impl IdVisitingOperation for IdRangeComputingVisitor { - fn visit_id(&self, id: NodeId) { - let mut id_range = self.result.get(); - id_range.add(id); - self.result.set(id_range) + fn visit_id(&mut self, id: NodeId) { + self.result.add(id); } } pub fn compute_id_range_for_inlined_item(item: &InlinedItem) -> IdRange { - let visitor = IdRangeComputingVisitor { - result: Cell::new(IdRange::max()) + let mut visitor = IdRangeComputingVisitor { + result: IdRange::max() }; - visit_ids_for_inlined_item(item, &visitor); - visitor.result.get() + visit_ids_for_inlined_item(item, &mut visitor); + visitor.result } pub fn compute_id_range_for_fn_body(fk: visit::FnKind, @@ -582,16 +579,16 @@ pub fn compute_id_range_for_fn_body(fk: visit::FnKind, * ignoring nested items. */ - let visitor = IdRangeComputingVisitor { - result: Cell::new(IdRange::max()) + let mut visitor = IdRangeComputingVisitor { + result: IdRange::max() }; let mut id_visitor = IdVisitor { - operation: &visitor, + operation: &mut visitor, pass_through_items: false, visited_outermost: false, }; id_visitor.visit_fn(fk, decl, body, sp, id); - visitor.result.get() + id_visitor.operation.result } pub fn walk_pat(pat: &Pat, it: |&Pat| -> bool) -> bool { diff --git a/src/libsyntax/ext/bytes.rs b/src/libsyntax/ext/bytes.rs index a93295815e0ed..2d1d13f16d06d 100644 --- a/src/libsyntax/ext/bytes.rs +++ b/src/libsyntax/ext/bytes.rs @@ -22,10 +22,10 @@ pub fn expand_syntax_ext<'cx>(cx: &'cx mut ExtCtxt, tts: &[ast::TokenTree]) -> Box { cx.span_warn(sp, "`bytes!` is deprecated, use `b\"foo\"` literals instead"); - cx.parse_sess.span_diagnostic.span_note(sp, + cx.parse_sess.span_diagnostic.span_help(sp, "see http://doc.rust-lang.org/reference.html#byte-and-byte-string-literals \ for documentation"); - cx.parse_sess.span_diagnostic.span_note(sp, + cx.parse_sess.span_diagnostic.span_help(sp, "see https://github.com/rust-lang/rust/blob/master/src/etc/2014-06-rewrite-bytes-macros.py \ for an automated migration"); diff --git a/src/libsyntax/ext/deriving/clone.rs b/src/libsyntax/ext/deriving/clone.rs index 9748b53134577..e653c8aebf447 100644 --- a/src/libsyntax/ext/deriving/clone.rs +++ b/src/libsyntax/ext/deriving/clone.rs @@ -52,11 +52,19 @@ fn cs_clone( name: &str, cx: &mut ExtCtxt, trait_span: Span, substr: &Substructure) -> P { - let clone_ident = substr.method_ident; let ctor_ident; let all_fields; - let subcall = |field: &FieldInfo| - cx.expr_method_call(field.span, field.self_.clone(), clone_ident, Vec::new()); + let fn_path = vec![ + cx.ident_of("std"), + cx.ident_of("clone"), + cx.ident_of("Clone"), + cx.ident_of("clone"), + ]; + let subcall = |field: &FieldInfo| { + let args = vec![cx.expr_addr_of(field.span, field.self_.clone())]; + + cx.expr_call_global(field.span, fn_path.clone(), args) + }; match *substr.fields { Struct(ref af) => { diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 54eaa3086588e..7701f495f726f 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -131,7 +131,7 @@ impl<'a> Context<'a> { fn gate_feature(&self, feature: &str, span: Span, explain: &str) { if !self.has_feature(feature) { self.span_handler.span_err(span, explain); - self.span_handler.span_note(span, format!("add #![feature({})] to the \ + self.span_handler.span_help(span, format!("add #![feature({})] to the \ crate attributes to enable", feature).as_slice()); } @@ -260,7 +260,7 @@ impl<'a, 'v> Visitor<'v> for Context<'a> { ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {} ast::TypeTraitItem(ref ti) => { self.gate_feature("associated_types", - ti.span, + ti.ty_param.span, "associated types are experimental") } } diff --git a/src/libsyntax/fold.rs b/src/libsyntax/fold.rs index 9a55f07e98d79..6535c8e89fd4e 100644 --- a/src/libsyntax/fold.rs +++ b/src/libsyntax/fold.rs @@ -793,19 +793,16 @@ pub fn noop_fold_typedef(t: Typedef, folder: &mut T) pub fn noop_fold_associated_type(at: AssociatedType, folder: &mut T) -> AssociatedType - where T: Folder { - let new_id = folder.new_id(at.id); - let new_span = folder.new_span(at.span); - let new_ident = folder.fold_ident(at.ident); + where T: Folder +{ let new_attrs = at.attrs .iter() .map(|attr| folder.fold_attribute((*attr).clone())) .collect(); + let new_param = folder.fold_ty_param(at.ty_param); ast::AssociatedType { - ident: new_ident, attrs: new_attrs, - id: new_id, - span: new_span, + ty_param: new_param, } } diff --git a/src/libsyntax/parse/lexer/mod.rs b/src/libsyntax/parse/lexer/mod.rs index 293b91111b5b2..1bc1d42d888dd 100644 --- a/src/libsyntax/parse/lexer/mod.rs +++ b/src/libsyntax/parse/lexer/mod.rs @@ -35,6 +35,19 @@ pub trait Reader { /// Report a non-fatal error with the current span. fn err(&self, &str); fn peek(&self) -> TokenAndSpan; + /// Get a token the parser cares about. + fn real_token(&mut self) -> TokenAndSpan { + let mut t = self.next_token(); + loop { + match t.tok { + token::Whitespace | token::Comment | token::Shebang(_) => { + t = self.next_token(); + }, + _ => break + } + } + t + } } #[deriving(Clone, PartialEq, Eq, Show)] diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index aa3b9668d4632..8ad5bdac7e2c2 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -338,27 +338,13 @@ fn is_plain_ident_or_underscore(t: &token::Token) -> bool { t.is_plain_ident() || *t == token::Underscore } -/// Get a token the parser cares about -fn real_token(rdr: &mut Reader) -> TokenAndSpan { - let mut t = rdr.next_token(); - loop { - match t.tok { - token::Whitespace | token::Comment | token::Shebang(_) => { - t = rdr.next_token(); - }, - _ => break - } - } - t -} - impl<'a> Parser<'a> { pub fn new(sess: &'a ParseSess, cfg: ast::CrateConfig, mut rdr: Box) -> Parser<'a> { - let tok0 = real_token(&mut *rdr); + let tok0 = rdr.real_token(); let span = tok0.sp; let placeholder = TokenAndSpan { tok: token::Underscore, @@ -898,7 +884,7 @@ impl<'a> Parser<'a> { None }; let next = if self.buffer_start == self.buffer_end { - real_token(&mut *self.reader) + self.reader.real_token() } else { // Avoid token copies with `replace`. let buffer_start = self.buffer_start as uint; @@ -942,7 +928,7 @@ impl<'a> Parser<'a> { -> R { let dist = distance as int; while self.buffer_length() < dist { - self.buffer[self.buffer_end as uint] = real_token(&mut *self.reader); + self.buffer[self.buffer_end as uint] = self.reader.real_token(); self.buffer_end = (self.buffer_end + 1) & 3; } f(&self.buffer[((self.buffer_start + dist - 1) & 3) as uint].tok) @@ -1229,16 +1215,13 @@ impl<'a> Parser<'a> { /// Parses `type Foo;` in a trait declaration only. The `type` keyword has /// already been parsed. fn parse_associated_type(&mut self, attrs: Vec) - -> AssociatedType { - let lo = self.span.lo; - let ident = self.parse_ident(); - let hi = self.span.hi; + -> AssociatedType + { + let ty_param = self.parse_ty_param(); self.expect(&token::Semi); AssociatedType { - id: ast::DUMMY_NODE_ID, - span: mk_sp(lo, hi), - ident: ident, attrs: attrs, + ty_param: ty_param, } } @@ -2371,10 +2354,19 @@ impl<'a> Parser<'a> { token::LitFloat(n) => { self.bump(); let last_span = self.last_span; + let fstr = n.as_str(); self.span_err(last_span, format!("unexpected token: `{}`", n.as_str()).as_slice()); - self.span_note(last_span, - "try parenthesizing the first index; e.g., `(foo.0).1`"); + if fstr.chars().all(|x| "0123456789.".contains_char(x)) { + let float = match from_str::(fstr) { + Some(f) => f, + None => continue, + }; + self.span_help(last_span, + format!("try parenthesizing the first index; e.g., `(foo.{}){}`", + float.trunc() as uint, + float.fract().to_string()[1..]).as_slice()); + } self.abort_if_errors(); } @@ -2578,7 +2570,7 @@ impl<'a> Parser<'a> { token::Eof => { let open_braces = self.open_braces.clone(); for sp in open_braces.iter() { - self.span_note(*sp, "Did you mean to close this delimiter?"); + self.span_help(*sp, "did you mean to close this delimiter?"); } // There shouldn't really be a span, but it's easier for the test runner // if we give it one @@ -5352,8 +5344,8 @@ impl<'a> Parser<'a> { self.bump(); if self.eat_keyword(keywords::Mut) { let last_span = self.last_span; - self.span_err(last_span, "const globals cannot be mutable, \ - did you mean to declare a static?"); + self.span_err(last_span, "const globals cannot be mutable"); + self.span_help(last_span, "did you mean to declare a static?"); } let (ident, item_, extra_attrs) = self.parse_item_const(None); let last_span = self.last_span; diff --git a/src/libsyntax/parse/token.rs b/src/libsyntax/parse/token.rs index d56aa8da72a84..615cd34ca14df 100644 --- a/src/libsyntax/parse/token.rs +++ b/src/libsyntax/parse/token.rs @@ -668,12 +668,12 @@ impl InternedString { impl BytesContainer for InternedString { fn container_as_bytes<'a>(&'a self) -> &'a [u8] { - // FIXME(pcwalton): This is a workaround for the incorrect signature + // FIXME #12938: This is a workaround for the incorrect signature // of `BytesContainer`, which is itself a workaround for the lack of // DST. unsafe { let this = self.get(); - mem::transmute(this.container_as_bytes()) + mem::transmute::<&[u8],&[u8]>(this.container_as_bytes()) } } } diff --git a/src/libsyntax/print/pprust.rs b/src/libsyntax/print/pprust.rs index 386fd8ae5a617..4cae3691f2ab6 100644 --- a/src/libsyntax/print/pprust.rs +++ b/src/libsyntax/print/pprust.rs @@ -169,17 +169,14 @@ pub fn to_string(f: |&mut State| -> IoResult<()>) -> String { let mut s = rust_printer(box MemWriter::new()); f(&mut s).unwrap(); eof(&mut s.s).unwrap(); - unsafe { + let wr = unsafe { // FIXME(pcwalton): A nasty function to extract the string from an `io::Writer` // that we "know" to be a `MemWriter` that works around the lack of checked // downcasts. - let obj: TraitObject = mem::transmute_copy(&s.s.out); - let wr: Box = mem::transmute(obj.data); - let result = - String::from_utf8(wr.get_ref().as_slice().to_vec()).unwrap(); - mem::forget(wr); - result.to_string() - } + let obj: &TraitObject = mem::transmute(&s.s.out); + mem::transmute::<*mut (), &MemWriter>(obj.data) + }; + String::from_utf8(wr.get_ref().to_vec()).unwrap() } pub fn binop_to_string(op: BinOpToken) -> &'static str { @@ -818,9 +815,11 @@ impl<'a> State<'a> { } fn print_associated_type(&mut self, typedef: &ast::AssociatedType) - -> IoResult<()> { + -> IoResult<()> + { + try!(self.print_outer_attributes(typedef.attrs[])); try!(self.word_space("type")); - try!(self.print_ident(typedef.ident)); + try!(self.print_ty_param(&typedef.ty_param)); word(&mut self.s, ";") } @@ -2434,23 +2433,7 @@ impl<'a> State<'a> { } else { let idx = idx - generics.lifetimes.len(); let param = generics.ty_params.get(idx); - match param.unbound { - Some(TraitTyParamBound(ref tref)) => { - try!(s.print_trait_ref(tref)); - try!(s.word_space("?")); - } - _ => {} - } - try!(s.print_ident(param.ident)); - try!(s.print_bounds(":", ¶m.bounds)); - match param.default { - Some(ref default) => { - try!(space(&mut s.s)); - try!(s.word_space("=")); - s.print_type(&**default) - } - _ => Ok(()) - } + s.print_ty_param(param) } })); @@ -2458,6 +2441,26 @@ impl<'a> State<'a> { Ok(()) } + pub fn print_ty_param(&mut self, param: &ast::TyParam) -> IoResult<()> { + match param.unbound { + Some(TraitTyParamBound(ref tref)) => { + try!(self.print_trait_ref(tref)); + try!(self.word_space("?")); + } + _ => {} + } + try!(self.print_ident(param.ident)); + try!(self.print_bounds(":", ¶m.bounds)); + match param.default { + Some(ref default) => { + try!(space(&mut self.s)); + try!(self.word_space("=")); + self.print_type(&**default) + } + _ => Ok(()) + } + } + pub fn print_where_clause(&mut self, generics: &ast::Generics) -> IoResult<()> { if generics.where_clause.predicates.len() == 0 { diff --git a/src/libsyntax/visit.rs b/src/libsyntax/visit.rs index bec72e88f99b9..86ee23d71a6b2 100644 --- a/src/libsyntax/visit.rs +++ b/src/libsyntax/visit.rs @@ -596,7 +596,8 @@ pub fn walk_trait_item<'v, V: Visitor<'v>>(visitor: &mut V, trait_method: &'v Tr RequiredMethod(ref method_type) => visitor.visit_ty_method(method_type), ProvidedMethod(ref method) => walk_method_helper(visitor, &**method), TypeTraitItem(ref associated_type) => { - visitor.visit_ident(associated_type.span, associated_type.ident) + visitor.visit_ident(associated_type.ty_param.span, + associated_type.ty_param.ident) } } } diff --git a/src/libunicode/u_str.rs b/src/libunicode/u_str.rs index 4bad631798fb2..9e3830c1f6090 100644 --- a/src/libunicode/u_str.rs +++ b/src/libunicode/u_str.rs @@ -17,7 +17,6 @@ * methods provided by the UnicodeChar trait. */ -use core::clone::Clone; use core::cmp; use core::slice::ImmutableSlice; use core::iter::{Filter, AdditiveIterator, Iterator, DoubleEndedIterator}; diff --git a/src/test/bench/shootout-pfib.rs b/src/test/bench/shootout-pfib.rs index 425b2e3e7140b..7fa13d6074d43 100644 --- a/src/test/bench/shootout-pfib.rs +++ b/src/test/bench/shootout-pfib.rs @@ -24,7 +24,6 @@ extern crate time; use std::os; use std::result::{Ok, Err}; use std::task; -use std::uint; fn fib(n: int) -> int { fn pfib(tx: &Sender, n: int) { @@ -102,8 +101,7 @@ fn main() { if opts.stress { stress(2); } else { - let max = uint::parse_bytes(args[1].as_bytes(), 10u).unwrap() as - int; + let max = from_str::(args[1].as_slice()).unwrap() as int; let num_trials = 10; diff --git a/src/test/compile-fail/associated-types-unsized.rs b/src/test/compile-fail/associated-types-unsized.rs new file mode 100644 index 0000000000000..47ab09d279f62 --- /dev/null +++ b/src/test/compile-fail/associated-types-unsized.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![feature(associated_types)] + +trait Get { + type Sized? Value; + fn get(&self) -> ::Value; +} + +fn foo(t: T) { + let x = t.get(); //~ ERROR the trait `core::kinds::Sized` is not implemented +} + +fn main() { +} + diff --git a/src/test/compile-fail/borrowck-let-suggestion.rs b/src/test/compile-fail/borrowck-let-suggestion.rs index 385111170b126..cd1101c05d15f 100644 --- a/src/test/compile-fail/borrowck-let-suggestion.rs +++ b/src/test/compile-fail/borrowck-let-suggestion.rs @@ -11,7 +11,7 @@ fn f() { let x = [1i].iter(); //~ ERROR borrowed value does not live long enough //~^^ NOTE reference must be valid for the block - //~^^ NOTE consider using a `let` binding to increase its lifetime + //~^^ HELP consider using a `let` binding to increase its lifetime } fn main() { diff --git a/src/test/compile-fail/deriving-no-inner-impl-error-message.rs b/src/test/compile-fail/deriving-no-inner-impl-error-message.rs index 58593869d747b..15a7bc01c3ae7 100644 --- a/src/test/compile-fail/deriving-no-inner-impl-error-message.rs +++ b/src/test/compile-fail/deriving-no-inner-impl-error-message.rs @@ -17,7 +17,8 @@ struct E { } #[deriving(Clone)] struct C { - x: NoCloneOrEq //~ ERROR does not implement any method in scope named `clone` + x: NoCloneOrEq + //~^ ERROR the trait `core::clone::Clone` is not implemented for the type `NoCloneOrEq` } diff --git a/src/test/compile-fail/issue-11714.rs b/src/test/compile-fail/issue-11714.rs index d57182e275b2b..ed00d4131dbad 100644 --- a/src/test/compile-fail/issue-11714.rs +++ b/src/test/compile-fail/issue-11714.rs @@ -11,7 +11,7 @@ fn blah() -> int { //~ ERROR not all control paths return a value 1i - ; //~ NOTE consider removing this semicolon: + ; //~ HELP consider removing this semicolon: } fn main() { } diff --git a/src/test/compile-fail/issue-13428.rs b/src/test/compile-fail/issue-13428.rs index de558401aa6f0..c771970650d31 100644 --- a/src/test/compile-fail/issue-13428.rs +++ b/src/test/compile-fail/issue-13428.rs @@ -15,12 +15,12 @@ fn foo() -> String { //~ ERROR not all control paths return a value "world") // Put the trailing semicolon on its own line to test that the // note message gets the offending semicolon exactly - ; //~ NOTE consider removing this semicolon + ; //~ HELP consider removing this semicolon } fn bar() -> String { //~ ERROR not all control paths return a value "foobar".to_string() - ; //~ NOTE consider removing this semicolon + ; //~ HELP consider removing this semicolon } pub fn main() {} diff --git a/src/test/compile-fail/issue-16747.rs b/src/test/compile-fail/issue-16747.rs index 134f58951bab2..22e3e9ed09e7d 100644 --- a/src/test/compile-fail/issue-16747.rs +++ b/src/test/compile-fail/issue-16747.rs @@ -15,8 +15,9 @@ trait ListItem<'a> { trait Collection { fn len(&self) -> uint; } struct List<'a, T: ListItem<'a>> { -//~^ ERROR the parameter type `T` may not live long enough; consider adding an explicit lifetime bo -//~^^ NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at +//~^ ERROR the parameter type `T` may not live long enough +//~^^ HELP consider adding an explicit lifetime bound +//~^^^ NOTE ...so that the reference type `&'a [T]` does not outlive the data it points at slice: &'a [T] } diff --git a/src/test/compile-fail/issue-17441.rs b/src/test/compile-fail/issue-17441.rs index da5590971bc3c..11c815da1c7f5 100644 --- a/src/test/compile-fail/issue-17441.rs +++ b/src/test/compile-fail/issue-17441.rs @@ -11,14 +11,14 @@ fn main() { let _foo = &[1u, 2] as [uint]; //~^ ERROR cast to unsized type: `&[uint, ..2]` as `[uint]` - //~^^ NOTE consider using an implicit coercion to `&[uint]` instead + //~^^ HELP consider using an implicit coercion to `&[uint]` instead let _bar = box 1u as std::fmt::Show; //~^ ERROR cast to unsized type: `Box` as `core::fmt::Show` - //~^^ NOTE did you mean `Box`? + //~^^ HELP did you mean `Box`? let _baz = 1u as std::fmt::Show; //~^ ERROR cast to unsized type: `uint` as `core::fmt::Show` - //~^^ NOTE consider using a box or reference as appropriate + //~^^ HELP consider using a box or reference as appropriate let _quux = [1u, 2] as [uint]; //~^ ERROR cast to unsized type: `[uint, ..2]` as `[uint]` - //~^^ NOTE consider using a box or reference as appropriate + //~^^ HELP consider using a box or reference as appropriate } diff --git a/src/test/compile-fail/issue-17718-const-mut.rs b/src/test/compile-fail/issue-17718-const-mut.rs index 31a5fee2044dc..12b9cf4ba8c0c 100644 --- a/src/test/compile-fail/issue-17718-const-mut.rs +++ b/src/test/compile-fail/issue-17718-const-mut.rs @@ -9,7 +9,8 @@ // except according to those terms. const -mut //~ ERROR: const globals cannot be mutable, did you mean to declare a static? +mut //~ ERROR: const globals cannot be mutable +//~^ HELP did you mean to declare a static? FOO: uint = 3; fn main() { diff --git a/src/test/compile-fail/issue-18532.rs b/src/test/compile-fail/issue-18532.rs new file mode 100644 index 0000000000000..a67f4c851bf8a --- /dev/null +++ b/src/test/compile-fail/issue-18532.rs @@ -0,0 +1,22 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that overloaded call parameter checking does not ICE +// when a type error or unconstrained type variable propagates +// into it. + +#![feature(overloaded_calls)] + +fn main() { + (return)((),()); + //~^ ERROR the type of this value must be known + //~^^ ERROR the type of this value must be known + //~^^^ ERROR cannot use call notation +} diff --git a/src/test/compile-fail/issue-2354.rs b/src/test/compile-fail/issue-2354.rs index 93f38a50b0582..cc219a6acb5ef 100644 --- a/src/test/compile-fail/issue-2354.rs +++ b/src/test/compile-fail/issue-2354.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -fn foo() { //~ NOTE Did you mean to close this delimiter? +fn foo() { //~ HELP did you mean to close this delimiter? match Some(x) { Some(y) { panic!(); } None { panic!(); } diff --git a/src/test/compile-fail/issue-6702.rs b/src/test/compile-fail/issue-6702.rs index 168aa5f9d691f..3e35e4a659d1e 100644 --- a/src/test/compile-fail/issue-6702.rs +++ b/src/test/compile-fail/issue-6702.rs @@ -15,5 +15,5 @@ struct Monster { fn main() { let _m = Monster(); //~ ERROR `Monster` is a structure name, but - //~^ NOTE Did you mean to write: `Monster { /* fields */ }`? + //~^ HELP Did you mean to write: `Monster { /* fields */ }`? } diff --git a/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs index 849f337743b77..5d96176434239 100644 --- a/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs +++ b/src/test/compile-fail/lifetime-elision-return-type-requires-explicit-lifetime.rs @@ -10,13 +10,13 @@ // Lifetime annotation needed because we have no arguments. fn f() -> &int { //~ ERROR missing lifetime specifier -//~^ NOTE there is no value for it to be borrowed from +//~^ HELP there is no value for it to be borrowed from panic!() } // Lifetime annotation needed because we have two by-reference parameters. fn g(_x: &int, _y: &int) -> &int { //~ ERROR missing lifetime specifier -//~^ NOTE the signature does not say whether it is borrowed from `_x` or `_y` +//~^ HELP the signature does not say whether it is borrowed from `_x` or `_y` panic!() } @@ -27,7 +27,13 @@ struct Foo<'a> { // Lifetime annotation needed because we have two lifetimes: one as a parameter // and one on the reference. fn h(_x: &Foo) -> &int { //~ ERROR missing lifetime specifier -//~^ NOTE the signature does not say which one of `_x`'s 2 elided lifetimes it is borrowed from +//~^ HELP the signature does not say which one of `_x`'s 2 elided lifetimes it is borrowed from + panic!() +} + +fn i(_x: int) -> &int { //~ ERROR missing lifetime specifier +//~^ HELP this function's return type contains a borrowed value +//~^^ HELP consider giving it a 'static lifetime panic!() } diff --git a/src/test/compile-fail/lint-exceeding-bitshifts.rs b/src/test/compile-fail/lint-exceeding-bitshifts.rs index f270994bd38ef..dbb65d8b7cefd 100644 --- a/src/test/compile-fail/lint-exceeding-bitshifts.rs +++ b/src/test/compile-fail/lint-exceeding-bitshifts.rs @@ -10,49 +10,53 @@ #![deny(exceeding_bitshifts)] #![allow(unused_variables)] +#![allow(dead_code)] fn main() { - let n = 1u8 << 8; - let n = 1u8 << 9; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1u16 << 16; - let n = 1u16 << 17; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1u32 << 32; - let n = 1u32 << 33; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1u64 << 64; - let n = 1u64 << 65; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1i8 << 8; - let n = 1i8 << 9; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1i16 << 16; - let n = 1i16 << 17; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1i32 << 32; - let n = 1i32 << 33; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1i64 << 64; - let n = 1i64 << 65; //~ ERROR: bitshift exceeds the type's number of bits - - let n = 1u8 >> 8; - let n = 1u8 >> 9; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1u16 >> 16; - let n = 1u16 >> 17; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1u32 >> 32; - let n = 1u32 >> 33; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1u64 >> 64; - let n = 1u64 >> 65; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1i8 >> 8; - let n = 1i8 >> 9; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1i16 >> 16; - let n = 1i16 >> 17; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1i32 >> 32; - let n = 1i32 >> 33; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1i64 >> 64; - let n = 1i64 >> 65; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u8 << 7; + let n = 1u8 << 8; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u16 << 15; + let n = 1u16 << 16; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u32 << 31; + let n = 1u32 << 32; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u64 << 63; + let n = 1u64 << 64; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i8 << 7; + let n = 1i8 << 8; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i16 << 15; + let n = 1i16 << 16; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i32 << 31; + let n = 1i32 << 32; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i64 << 63; + let n = 1i64 << 64; //~ ERROR: bitshift exceeds the type's number of bits + + let n = 1u8 >> 7; + let n = 1u8 >> 8; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u16 >> 15; + let n = 1u16 >> 16; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u32 >> 31; + let n = 1u32 >> 32; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u64 >> 63; + let n = 1u64 >> 64; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i8 >> 7; + let n = 1i8 >> 8; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i16 >> 15; + let n = 1i16 >> 16; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i32 >> 31; + let n = 1i32 >> 32; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i64 >> 63; + let n = 1i64 >> 64; //~ ERROR: bitshift exceeds the type's number of bits let n = 1u8; - let n = n << 8; - let n = n << 9; //~ ERROR: bitshift exceeds the type's number of bits + let n = n << 7; + let n = n << 8; //~ ERROR: bitshift exceeds the type's number of bits + + let n = 1u8 << -8; //~ ERROR: bitshift exceeds the type's number of bits - let n = 1u8 << -9; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u8 << (4+3); + let n = 1u8 << (4+4); //~ ERROR: bitshift exceeds the type's number of bits - let n = 1u8 << (4+4); - let n = 1u8 << (4+5); //~ ERROR: bitshift exceeds the type's number of bits + let n = 1i << std::int::BITS; //~ ERROR: bitshift exceeds the type's number of bits + let n = 1u << std::uint::BITS; //~ ERROR: bitshift exceeds the type's number of bits } diff --git a/src/test/compile-fail/liveness-return-last-stmt-semi.rs b/src/test/compile-fail/liveness-return-last-stmt-semi.rs index 8a6585f8bbc41..f2ea2ca96a59d 100644 --- a/src/test/compile-fail/liveness-return-last-stmt-semi.rs +++ b/src/test/compile-fail/liveness-return-last-stmt-semi.rs @@ -14,12 +14,12 @@ macro_rules! test ( () => { fn foo() -> int { 1i; } } ) //~^ ERROR not all control paths return a value - //~^^ NOTE consider removing this semicolon + //~^^ HELP consider removing this semicolon fn no_return() -> int {} //~ ERROR not all control paths return a value fn bar(x: u32) -> u32 { //~ ERROR not all control paths return a value - x * 2; //~ NOTE consider removing this semicolon + x * 2; //~ HELP consider removing this semicolon } fn baz(x: u64) -> u32 { //~ ERROR not all control paths return a value diff --git a/src/test/compile-fail/method-missing-call.rs b/src/test/compile-fail/method-missing-call.rs index 1c8b7fbf85cc5..ddfa447f60e22 100644 --- a/src/test/compile-fail/method-missing-call.rs +++ b/src/test/compile-fail/method-missing-call.rs @@ -30,7 +30,7 @@ fn main() { let point: Point = Point::new(); let px: int = point .get_x;//~ ERROR attempted to take value of method `get_x` on type `Point` - //~^ NOTE maybe a missing `()` to call it? If not, try an anonymous + //~^ HELP maybe a `()` to call it is missing // Ensure the span is useful let ys = &[1i,2,3,4,5,6,7]; @@ -38,6 +38,6 @@ fn main() { .map(|x| x) .filter(|&&x| x == 1) .filter_map; //~ ERROR attempted to take value of method `filter_map` on type - //~^ NOTE maybe a missing `()` to call it? If not, try an anonymous function. + //~^ HELP maybe a `()` to call it is missing } diff --git a/src/test/compile-fail/trait-impl-1.rs b/src/test/compile-fail/trait-impl-1.rs new file mode 100644 index 0000000000000..5e2ebc3e620d6 --- /dev/null +++ b/src/test/compile-fail/trait-impl-1.rs @@ -0,0 +1,26 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test calling methods on an impl for a bare trait. This test checks that the +// trait impl is only applied to a trait object, not concrete types which implement +// the trait. + +trait T {} + +impl<'a> T+'a { + fn foo(&self) {} +} + +impl T for int {} + +fn main() { + let x = &42i; + x.foo(); //~ERROR: type `&int` does not implement any method in scope named `foo` +} diff --git a/src/test/compile-fail/trait-impl-2.rs b/src/test/compile-fail/trait-impl-2.rs new file mode 100644 index 0000000000000..303e3d937444d --- /dev/null +++ b/src/test/compile-fail/trait-impl-2.rs @@ -0,0 +1,24 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test calling methods on an impl for a bare trait. This test checks trait impls +// must be in the same module as the trait. + +mod Foo { + trait T {} +} + +mod Bar { + impl<'a> ::Foo::T+'a { //~ERROR: inherent implementations may only be implemented in the same + fn foo(&self) {} + } +} + +fn main() {} diff --git a/src/test/compile-fail/variance-regions-direct.rs b/src/test/compile-fail/variance-regions-direct.rs index fa38482b21c50..48813ff142c18 100644 --- a/src/test/compile-fail/variance-regions-direct.rs +++ b/src/test/compile-fail/variance-regions-direct.rs @@ -14,7 +14,7 @@ // Regions that just appear in normal spots are contravariant: #[rustc_variance] -struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]] +struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[];[]] x: &'a int, y: &'b [int], c: &'c str @@ -23,7 +23,7 @@ struct Test2<'a, 'b, 'c> { //~ ERROR regions=[[-, -, -];[];[]] // Those same annotations in function arguments become covariant: #[rustc_variance] -struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]] +struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[];[]] x: extern "Rust" fn(&'a int), y: extern "Rust" fn(&'b [int]), c: extern "Rust" fn(&'c str), @@ -32,7 +32,7 @@ struct Test3<'a, 'b, 'c> { //~ ERROR regions=[[+, +, +];[];[]] // Mutability induces invariance: #[rustc_variance] -struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] +struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[];[]] x: &'a mut &'b int, } @@ -40,7 +40,7 @@ struct Test4<'a, 'b:'a> { //~ ERROR regions=[[-, o];[];[]] // contravariant context: #[rustc_variance] -struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]] +struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[];[]] x: extern "Rust" fn(&'a mut &'b int), } @@ -50,21 +50,21 @@ struct Test5<'a, 'b> { //~ ERROR regions=[[+, o];[];[]] // argument list occurs in an invariant context. #[rustc_variance] -struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[]] +struct Test6<'a, 'b> { //~ ERROR regions=[[-, o];[];[];[]] x: &'a mut extern "Rust" fn(&'b int), } // No uses at all is bivariant: #[rustc_variance] -struct Test7<'a> { //~ ERROR regions=[[*];[];[]] +struct Test7<'a> { //~ ERROR regions=[[*];[];[];[]] x: int } // Try enums too. #[rustc_variance] -enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]] +enum Test8<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[];[]] Test8A(extern "Rust" fn(&'a int)), Test8B(&'b [int]), Test8C(&'b mut &'c str), diff --git a/src/test/compile-fail/variance-regions-indirect.rs b/src/test/compile-fail/variance-regions-indirect.rs index c049fbc0fedbc..0e8e52df456af 100644 --- a/src/test/compile-fail/variance-regions-indirect.rs +++ b/src/test/compile-fail/variance-regions-indirect.rs @@ -13,29 +13,29 @@ // Try enums too. #[rustc_variance] -enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[]] +enum Base<'a, 'b, 'c:'b, 'd> { //~ ERROR regions=[[+, -, o, *];[];[];[]] Test8A(extern "Rust" fn(&'a int)), Test8B(&'b [int]), Test8C(&'b mut &'c str), } #[rustc_variance] -struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[]] +struct Derived1<'w, 'x:'y, 'y, 'z> { //~ ERROR regions=[[*, o, -, +];[];[];[]] f: Base<'z, 'y, 'x, 'w> } #[rustc_variance] // Combine - and + to yield o -struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[]] +struct Derived2<'a, 'b:'a, 'c> { //~ ERROR regions=[[o, o, *];[];[];[]] f: Base<'a, 'a, 'b, 'c> } #[rustc_variance] // Combine + and o to yield o (just pay attention to 'a here) -struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[]] +struct Derived3<'a:'b, 'b, 'c> { //~ ERROR regions=[[o, -, *];[];[];[]] f: Base<'a, 'b, 'a, 'c> } #[rustc_variance] // Combine + and * to yield + (just pay attention to 'a here) -struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[]] +struct Derived4<'a, 'b, 'c:'b> { //~ ERROR regions=[[+, -, o];[];[];[]] f: Base<'a, 'b, 'c, 'a> } diff --git a/src/test/compile-fail/variance-trait-object-bound.rs b/src/test/compile-fail/variance-trait-object-bound.rs index c61f2ff79c019..c576c5e2edd64 100644 --- a/src/test/compile-fail/variance-trait-object-bound.rs +++ b/src/test/compile-fail/variance-trait-object-bound.rs @@ -19,7 +19,7 @@ use std::mem; trait T { fn foo(); } #[rustc_variance] -struct TOption<'a> { //~ ERROR regions=[[-];[];[]] +struct TOption<'a> { //~ ERROR regions=[[-];[];[];[]] v: Option>, } diff --git a/src/test/run-pass/issue-15689-2.rs b/src/test/run-pass/issue-15689-2.rs new file mode 100644 index 0000000000000..026122d1259f6 --- /dev/null +++ b/src/test/run-pass/issue-15689-2.rs @@ -0,0 +1,16 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[deriving(Clone)] +enum Test<'a> { + Slice(&'a int) +} + +fn main() {} diff --git a/src/test/run-pass/trait-impl.rs b/src/test/run-pass/trait-impl.rs new file mode 100644 index 0000000000000..216a7ef33f54c --- /dev/null +++ b/src/test/run-pass/trait-impl.rs @@ -0,0 +1,36 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test calling methods on an impl for a bare trait. + +static mut COUNT: uint = 1; + +trait T {} + +impl<'a> T+'a { + fn foo(&self) { + unsafe { COUNT *= 2; } + } + fn bar() { + unsafe { COUNT *= 3; } + } +} + +impl T for int {} + +fn main() { + let x: &T = &42i; + + x.foo(); + T::foo(x); + T::bar(); + + unsafe { assert!(COUNT == 12); } +}