mirror of
https://github.com/rust-lang/rust
synced 2024-10-04 15:50:51 +00:00
auto merge of #18596 : alexcrichton/rust/rollup, r=alexcrichton
Let's see if we can clear out the queue entirely today!
This commit is contained in:
commit
82fb413d37
|
@ -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::<Vec<int>>();
|
||||
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -276,7 +276,6 @@
|
|||
|
||||
#![stable]
|
||||
|
||||
use clone::Clone;
|
||||
use cmp::PartialEq;
|
||||
use std::fmt::Show;
|
||||
use slice;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
use mem;
|
||||
use char;
|
||||
use char::Char;
|
||||
use clone::Clone;
|
||||
use cmp;
|
||||
use cmp::{PartialEq, Eq};
|
||||
use default::Default;
|
||||
|
|
|
@ -227,6 +227,13 @@ fn ziggurat<R:Rng>(
|
|||
// 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;
|
||||
|
|
|
@ -78,6 +78,46 @@ fn next_u64(&mut self) -> u64 {
|
|||
(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
|
||||
|
|
|
@ -96,11 +96,11 @@ fn rand<R: Rng>(rng: &mut R) -> 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 @@ impl Rand for $ty {
|
|||
/// and `Open01` for the open interval `(0,1)`.
|
||||
#[inline]
|
||||
fn rand<R: Rng>(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 @@ fn rand<R: Rng>(rng: &mut R) -> Open01<$ty> {
|
|||
// 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<R: Rng>(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]
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
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 @@ fn check_expr(&mut self, cx: &Context, e: &ast::Expr) {
|
|||
|
||||
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 @@ fn float_ty_range(float_ty: ast::FloatTy) -> (f64, f64) {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ fn int_ty_bits(int_ty: ast::IntTy) -> u64 {
|
|||
}
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -532,7 +532,7 @@ fn with_lint_attrs(&mut self,
|
|||
}
|
||||
}
|
||||
|
||||
fn visit_ids(&self, f: |&mut ast_util::IdVisitor<Context>|) {
|
||||
fn visit_ids(&mut self, f: |&mut ast_util::IdVisitor<Context>|) {
|
||||
let mut v = ast_util::IdVisitor {
|
||||
operation: self,
|
||||
pass_through_items: false,
|
||||
|
@ -749,7 +749,7 @@ fn visit_attribute(&mut self, attr: &ast::Attribute) {
|
|||
|
||||
// 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) => {
|
||||
|
|
|
@ -148,7 +148,7 @@ impl astencode_tag {
|
|||
pub fn from_uint(value : uint) -> Option<astencode_tag> {
|
||||
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::<uint, astencode_tag>(value) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -247,4 +247,3 @@ pub struct LinkMeta {
|
|||
|
||||
pub const tag_item_generics: uint = 0xa6;
|
||||
pub const tag_method_ty_generics: uint = 0xa7;
|
||||
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
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<ty::Disr> {
|
||||
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)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,6 @@
|
|||
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<entry<i64>>) {
|
||||
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<entry<i64>>) {
|
||||
// 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<entry<i64>>,
|
||||
}
|
||||
|
||||
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 @@ fn visit_item(&mut self, i: &Item) {
|
|||
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);
|
||||
|
||||
|
|
|
@ -231,7 +231,6 @@
|
|||
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<ArchiveMetadata> {
|
||||
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<MetadataBlob
|
|||
let csz = llvm::LLVMGetSectionSize(si.llsi) as uint;
|
||||
let mut found =
|
||||
Err(format!("metadata not found: '{}'", filename.display()));
|
||||
let cvbuf: *const u8 = mem::transmute(cbuf);
|
||||
let cvbuf: *const u8 = cbuf as *const u8;
|
||||
let vlen = encoder::metadata_encoding_version.len();
|
||||
debug!("checking {} bytes of metadata-version stamp",
|
||||
vlen);
|
||||
|
|
|
@ -23,7 +23,6 @@
|
|||
use std::rc::Rc;
|
||||
use std::str;
|
||||
use std::string::String;
|
||||
use std::uint;
|
||||
use syntax::abi;
|
||||
use syntax::ast;
|
||||
use syntax::ast::*;
|
||||
|
@ -615,12 +614,12 @@ pub fn parse_def_id(buf: &[u8]) -> 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::<uint>) {
|
||||
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::<uint>) {
|
||||
Some(dn) => dn as ast::NodeId,
|
||||
None => panic!("internal error: parse_def_id: id expected, found {}",
|
||||
def_part)
|
||||
|
|
|
@ -38,9 +38,7 @@
|
|||
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 @@ fn read_vec_per_param_space<T>(&mut self,
|
|||
{
|
||||
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 @@ fn id(&mut self, id: ast::NodeId) {
|
|||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
|
|
@ -118,7 +118,6 @@
|
|||
|
||||
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,
|
||||
|
|
|
@ -296,8 +296,8 @@ fn visit_item(&mut self, item: &ast::Item) {
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -627,7 +627,10 @@ fn define_module(&self,
|
|||
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 @@ fn build_reduced_graph_for_item(&mut self,
|
|||
// 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 @@ fn build_reduced_graph_for_item(&mut self,
|
|||
// 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 @@ fn build_reduced_graph_for_item(&mut self,
|
|||
}
|
||||
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 @@ fn resolve_item(&mut self, item: &Item) {
|
|||
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 @@ fn resolve_item(&mut self, item: &Item) {
|
|||
_ => {}
|
||||
}
|
||||
|
||||
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 @@ fn resolve_item(&mut self, item: &Item) {
|
|||
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 @@ fn resolve_function(&mut self,
|
|||
fn resolve_type_parameters(&mut self,
|
||||
type_parameters: &OwnedSlice<TyParam>) {
|
||||
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 @@ fn resolve_trait_reference(&mut self,
|
|||
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());
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
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,{},\
|
||||
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())
|
||||
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 @@ pub fn span_for_last_ident(&self, span: Span) -> Option<Span> {
|
|||
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 @@ pub fn span_for_first_ident(&self, span: Span) -> Option<Span> {
|
|||
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 @@ pub fn span_for_first_ident(&self, span: Span) -> Option<Span> {
|
|||
// any brackets, or the last span.
|
||||
pub fn sub_span_for_meth_name(&self, span: Span) -> Option<Span> {
|
||||
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 @@ pub fn sub_span_for_meth_name(&self, span: Span) -> Option<Span> {
|
|||
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 @@ pub fn sub_span_for_meth_name(&self, span: Span) -> Option<Span> {
|
|||
// brackets, or the last span.
|
||||
pub fn sub_span_for_type_name(&self, span: Span) -> Option<Span> {
|
||||
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 @@ pub fn spans_with_brackets(&self, span: Span, nesting: int, limit: int) -> Vec<S
|
|||
// 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 @@ pub fn spans_with_brackets(&self, span: Span, nesting: int, limit: int) -> Vec<S
|
|||
|
||||
pub fn sub_span_before_token(&self, span: Span, tok: Token) -> Option<Span> {
|
||||
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 @@ pub fn sub_span_after_keyword(&self,
|
|||
keyword: keywords::Keyword) -> Option<Span> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -86,7 +86,7 @@ fn visit_trait_item(&mut self, t: &TraitItem) {
|
|||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -16,66 +16,10 @@
|
|||
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<T> {
|
||||
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<T> HomogeneousTuple3<T> 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 @@ pub fn new_type(t: Vec<ty::t>,
|
|||
r: Vec<ty::Region>)
|
||||
-> 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<ty::t>,
|
||||
r: Vec<ty::Region>,
|
||||
a: Vec<ty::t>,
|
||||
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<ty::t>) -> Substs
|
||||
|
@ -226,21 +171,23 @@ fn map<A>(self,
|
|||
#[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 @@ pub fn from_uint(u: uint) -> ParamSpace {
|
|||
match u {
|
||||
0 => TypeSpace,
|
||||
1 => SelfSpace,
|
||||
2 => FnSpace,
|
||||
2 => AssocSpace,
|
||||
3 => FnSpace,
|
||||
_ => panic!("Invalid ParamSpace: {}", u)
|
||||
}
|
||||
}
|
||||
|
@ -268,14 +216,27 @@ pub struct VecPerParamSpace<T> {
|
|||
// 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<T>,
|
||||
}
|
||||
|
||||
/**
|
||||
* The `split` function converts one `VecPerParamSpace` into this
|
||||
* `SeparateVecsPerParamSpace` structure.
|
||||
*/
|
||||
pub struct SeparateVecsPerParamSpace<T> {
|
||||
pub types: Vec<T>,
|
||||
pub selfs: Vec<T>,
|
||||
pub assocs: Vec<T>,
|
||||
pub fns: Vec<T>,
|
||||
}
|
||||
|
||||
impl<T:fmt::Show> fmt::Show for VecPerParamSpace<T> {
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||
try!(write!(fmt, "VecPerParamSpace {{"));
|
||||
|
@ -292,7 +253,8 @@ fn limits(&self, space: ParamSpace) -> (uint, uint) {
|
|||
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 @@ pub fn empty() -> VecPerParamSpace<T> {
|
|||
VecPerParamSpace {
|
||||
type_limit: 0,
|
||||
self_limit: 0,
|
||||
assoc_limit: 0,
|
||||
content: Vec::new()
|
||||
}
|
||||
}
|
||||
|
@ -310,26 +273,33 @@ pub fn params_from_type(types: Vec<T>) -> VecPerParamSpace<T> {
|
|||
|
||||
/// `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<T>, s: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
|
||||
pub fn new(t: Vec<T>, s: Vec<T>, a: Vec<T>, f: Vec<T>) -> VecPerParamSpace<T> {
|
||||
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<T>, type_limit: uint, self_limit: uint)
|
||||
fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint, assoc_limit: uint)
|
||||
-> VecPerParamSpace<T>
|
||||
{
|
||||
VecPerParamSpace {
|
||||
type_limit: type_limit,
|
||||
self_limit: self_limit,
|
||||
assoc_limit: assoc_limit,
|
||||
content: content,
|
||||
}
|
||||
}
|
||||
|
@ -341,9 +311,10 @@ fn new_internal(content: Vec<T>, type_limit: uint, self_limit: uint)
|
|||
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 @@ pub fn pop(&mut self, space: ParamSpace) -> Option<T> {
|
|||
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 @@ pub fn map<U>(&self, pred: |&T| -> U) -> VecPerParamSpace<U> {
|
|||
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<U>(self, pred: |T| -> U) -> VecPerParamSpace<U> {
|
||||
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<T>, Vec<T>, Vec<T>) {
|
||||
// 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<T> {
|
||||
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<T>)
|
||||
|
@ -616,12 +588,13 @@ fn check(this: &SubstFolder,
|
|||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -514,7 +514,7 @@ pub fn evaluate_method_obligation(&mut self,
|
|||
// and `Rc<Baz>`. (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 @@ fn vtable_builtin_data(&mut self,
|
|||
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 @@ fn confirm_unboxed_closure_candidate(&mut self,
|
|||
vec![arguments_tuple.subst(self.tcx(), substs),
|
||||
new_signature.output.unwrap().subst(self.tcx(), substs)],
|
||||
vec![],
|
||||
vec![],
|
||||
obligation.self_ty())
|
||||
});
|
||||
|
||||
|
@ -1942,7 +1944,7 @@ fn push_stack<'o,'s:'o>(&mut self,
|
|||
|
||||
fn all_impls(&self, trait_def_id: ast::DefId) -> Vec<ast::DefId> {
|
||||
/*!
|
||||
* 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(),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@
|
|||
use libc::c_uint;
|
||||
|
||||
#[deriving(Clone, PartialEq, Show)]
|
||||
#[repr(C)]
|
||||
pub struct Type {
|
||||
rf: TypeRef
|
||||
}
|
||||
|
@ -283,9 +284,10 @@ pub fn field_types(&self) -> Vec<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 @@ pub fn return_type(&self) -> Type {
|
|||
pub fn func_params(&self) -> Vec<Type> {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<DefIdMap<bool>>,
|
||||
|
||||
/// Maps def IDs of traits to information about their associated types.
|
||||
pub trait_associated_types:
|
||||
RefCell<DefIdMap<Rc<Vec<AssociatedTypeInfo>>>>,
|
||||
|
||||
/// 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 @@ pub fn is_noop(&self) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
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 @@ fn cmp(&self, other: &AssociatedTypeInfo) -> Ordering {
|
|||
}
|
||||
}
|
||||
|
||||
/// 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<Vec<AssociatedTypeInfo>> {
|
||||
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<Vec<ImplOrTraitItemId>> {
|
||||
lookup_locally_or_in_crate_store("trait_item_def_ids",
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
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;
|
||||
|
@ -215,7 +215,8 @@ fn ast_path_substs<'tcx,AC,RS>(
|
|||
associated_ty: Option<ty::t>,
|
||||
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
|
||||
|
@ -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();
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -207,8 +207,8 @@ fn check_implementation(&self,
|
|||
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));
|
||||
|
|
|
@ -41,7 +41,8 @@ fn visit_item(&mut self, item: &'v ast::Item) {
|
|||
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 \
|
||||
|
|
|
@ -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 @@ fn associated_type_binding(&self,
|
|||
ty: Option<ty::t>,
|
||||
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 @@ fn associated_type_binding(&self,
|
|||
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 @@ fn mk_trait_substs(ccx: &CrateCtxt,
|
|||
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 @@ fn mk_trait_substs(ccx: &CrateCtxt,
|
|||
.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 @@ fn mk_trait_substs(ccx: &CrateCtxt,
|
|||
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:Iterator>(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<A,T:Iterator<Elem=A>>(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;
|
||||
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<ast::DefId>)
|
||||
-> ty::TypeParameterDef
|
||||
where AC: AstConv<'tcx>
|
||||
{
|
||||
match this.tcx().ty_param_defs.borrow().find(¶m.id) {
|
||||
Some(d) => { return (*d).clone(); }
|
||||
None => { }
|
||||
}
|
||||
|
||||
ty::walk_ty(ty, |t| {
|
||||
match ty::get(t).sty {
|
||||
ty::ty_param(p) => if p.idx > cur_idx {
|
||||
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,
|
||||
|
|
|
@ -774,10 +774,15 @@ pub fn fresh_substs_for_trait(&self,
|
|||
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 @@ pub fn resolve_regions_and_report_errors(&self) {
|
|||
|
||||
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 {
|
||||
|
|
|
@ -425,7 +425,13 @@ fn infer_ty_to_string(cx: &ctxt, ty: ty::InferTy) -> 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;
|
||||
|
@ -481,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 {
|
||||
|
@ -505,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,
|
||||
|
@ -520,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 {
|
||||
|
@ -668,10 +673,11 @@ fn repr(&self, tcx: &ctxt) -> String {
|
|||
|
||||
impl<T:Repr> Repr for subst::VecPerParamSpace<T> {
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -726,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))
|
||||
}
|
||||
|
@ -741,6 +747,19 @@ fn repr(&self, tcx: &ctxt) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
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))
|
||||
|
@ -759,6 +778,12 @@ fn user_string(&self, _tcx: &ctxt) -> String {
|
|||
}
|
||||
}
|
||||
|
||||
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))
|
||||
|
@ -1262,7 +1287,8 @@ fn user_string(&self, tcx: &ctxt) -> String {
|
|||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -547,7 +547,7 @@ pub fn LLVMFunctionType(ReturnType: TypeRef,
|
|||
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;
|
||||
|
||||
|
|
|
@ -2203,12 +2203,12 @@ fn clean(&self, _: &DocContext) -> Stability {
|
|||
impl Clean<Item> 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,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,6 +203,7 @@ fn main() {
|
|||
use std::str::ScalarValue;
|
||||
use std::string;
|
||||
use std::vec::Vec;
|
||||
use std::ops;
|
||||
|
||||
use Encodable;
|
||||
|
||||
|
@ -889,9 +890,9 @@ pub fn to_pretty_str(&self) -> string::String {
|
|||
|
||||
/// 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 @@ pub fn find<'a>(&'a self, key: &string::String) -> Option<&'a 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 @@ pub fn find_path<'a>(&'a self, keys: &[&string::String]) -> Option<&'a 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 @@ pub fn as_null(&self) -> Option<()> {
|
|||
}
|
||||
}
|
||||
|
||||
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<uint, Json> 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 @@ fn test_decode_errors_enum() {
|
|||
#[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();
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
//
|
||||
// ignore-lexer-test FIXME #15883
|
||||
|
||||
use clone::Clone;
|
||||
use cmp::{Eq, Equiv, PartialEq};
|
||||
use core::kinds::Sized;
|
||||
use default::Default;
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
use c_str::CString;
|
||||
use collections::HashMap;
|
||||
use hash::Hash;
|
||||
use clone::Clone;
|
||||
#[cfg(windows)]
|
||||
use std::hash::sip::SipState;
|
||||
|
||||
|
|
|
@ -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<f32> {
|
||||
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<f32> {
|
||||
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<f32> {
|
||||
strconv::from_str_common(val, 10u, true, true, true,
|
||||
strconv::ExpDec, false, false)
|
||||
fn from_str(src: &str) -> Option<f32> {
|
||||
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<f32> {
|
||||
strconv::from_str_common(val, rdx, true, true, false,
|
||||
strconv::ExpNone, false, false)
|
||||
fn from_str_radix(src: &str, radix: uint) -> Option<f32> {
|
||||
strconv::from_str_radix_float(src, radix)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -710,8 +683,8 @@ fn test_classify() {
|
|||
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 @@ fn test_ldexp() {
|
|||
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));
|
||||
|
|
|
@ -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<f64> {
|
||||
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<f64> {
|
||||
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<f64> {
|
||||
strconv::from_str_common(val, 10u, true, true, true,
|
||||
strconv::ExpDec, false, false)
|
||||
fn from_str(src: &str) -> Option<f64> {
|
||||
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<f64> {
|
||||
strconv::from_str_common(val, rdx, true, true, false,
|
||||
strconv::ExpNone, false, false)
|
||||
fn from_str_radix(src: &str, radix: uint) -> Option<f64> {
|
||||
strconv::from_str_radix_float(src, radix)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -712,8 +680,8 @@ fn test_classify() {
|
|||
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 @@ fn test_ldexp() {
|
|||
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));
|
||||
|
|
|
@ -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 @@ fn from_str(s: &str) -> Option<$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 @@ fn test_from_str() {
|
|||
assert_eq!(from_str::<i32>("-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));
|
||||
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!(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!(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!(parse_bytes("Z".as_bytes(), 35u).is_none());
|
||||
assert!(parse_bytes("-9".as_bytes(), 2u).is_none());
|
||||
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 @@ fn test_int_to_str_overflow() {
|
|||
fn test_int_from_str_overflow() {
|
||||
let mut i8_val: i8 = 127_i8;
|
||||
assert_eq!(from_str::<i8>("127"), Some(i8_val));
|
||||
assert!(from_str::<i8>("128").is_none());
|
||||
assert_eq!(from_str::<i8>("128"), None);
|
||||
|
||||
i8_val += 1 as i8;
|
||||
assert_eq!(from_str::<i8>("-128"), Some(i8_val));
|
||||
assert!(from_str::<i8>("-129").is_none());
|
||||
assert_eq!(from_str::<i8>("-129"), None);
|
||||
|
||||
let mut i16_val: i16 = 32_767_i16;
|
||||
assert_eq!(from_str::<i16>("32767"), Some(i16_val));
|
||||
assert!(from_str::<i16>("32768").is_none());
|
||||
assert_eq!(from_str::<i16>("32768"), None);
|
||||
|
||||
i16_val += 1 as i16;
|
||||
assert_eq!(from_str::<i16>("-32768"), Some(i16_val));
|
||||
assert!(from_str::<i16>("-32769").is_none());
|
||||
assert_eq!(from_str::<i16>("-32769"), None);
|
||||
|
||||
let mut i32_val: i32 = 2_147_483_647_i32;
|
||||
assert_eq!(from_str::<i32>("2147483647"), Some(i32_val));
|
||||
assert!(from_str::<i32>("2147483648").is_none());
|
||||
assert_eq!(from_str::<i32>("2147483648"), None);
|
||||
|
||||
i32_val += 1 as i32;
|
||||
assert_eq!(from_str::<i32>("-2147483648"), Some(i32_val));
|
||||
assert!(from_str::<i32>("-2147483649").is_none());
|
||||
assert_eq!(from_str::<i32>("-2147483649"), None);
|
||||
|
||||
let mut i64_val: i64 = 9_223_372_036_854_775_807_i64;
|
||||
assert_eq!(from_str::<i64>("9223372036854775807"), Some(i64_val));
|
||||
assert!(from_str::<i64>("9223372036854775808").is_none());
|
||||
assert_eq!(from_str::<i64>("9223372036854775808"), None);
|
||||
|
||||
i64_val += 1 as i64;
|
||||
assert_eq!(from_str::<i64>("-9223372036854775808"), Some(i64_val));
|
||||
assert!(from_str::<i64>("-9223372036854775809").is_none());
|
||||
assert_eq!(from_str::<i64>("-9223372036854775809"), None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Self>;
|
||||
|
||||
/// Returns the infinite value.
|
||||
fn inf() -> Option<Self>;
|
||||
|
||||
/// Returns the negative infinite value.
|
||||
fn neg_inf() -> Option<Self>;
|
||||
|
||||
/// Returns -0.0.
|
||||
fn neg_zero() -> Option<Self>;
|
||||
|
||||
/// 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 @@ impl NumStrConv for $t {
|
|||
fn int_to_str_bytes_common<T: Int>(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<T: Int>(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<T:NumCast+Zero+One+PartialEq+PartialOrd+Float+
|
||||
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
|
||||
pub fn float_to_str_bytes_common<T: Float>(
|
||||
num: T, radix: uint, negative_zero: bool,
|
||||
sign: SignFormat, digits: SignificantDigits, exp_format: ExponentFormat, exp_upper: bool
|
||||
) -> (Vec<u8>, bool) {
|
||||
|
@ -271,8 +195,8 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+PartialEq+PartialOrd+Float+
|
|||
_ => ()
|
||||
}
|
||||
|
||||
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<T:NumCast+Zero+One+PartialEq+PartialOrd+Float+
|
|||
|
||||
let neg = num < _0 || (negative_zero && _1 / num == Float::neg_infinity());
|
||||
let mut buf = Vec::new();
|
||||
let radix_gen: T = cast(radix as int).unwrap();
|
||||
let radix_gen: T = num::cast(radix as int).unwrap();
|
||||
|
||||
let (num, exp) = match exp_format {
|
||||
ExpNone => (num, 0i32),
|
||||
|
@ -302,12 +226,12 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+PartialEq+PartialOrd+Float+
|
|||
(num, 0i32)
|
||||
} else {
|
||||
let (exp, exp_base) = match exp_format {
|
||||
ExpDec => (num.abs().log10().floor(), cast::<f64, T>(10.0f64).unwrap()),
|
||||
ExpBin => (num.abs().log2().floor(), cast::<f64, T>(2.0f64).unwrap()),
|
||||
ExpDec => (num.abs().log10().floor(), num::cast::<f64, T>(10.0f64).unwrap()),
|
||||
ExpBin => (num.abs().log2().floor(), num::cast::<f64, T>(2.0f64).unwrap()),
|
||||
ExpNone => unreachable!()
|
||||
};
|
||||
|
||||
(num / exp_base.powf(exp), cast::<T, i32>(exp).unwrap())
|
||||
(num / exp_base.powf(exp), num::cast::<T, i32>(exp).unwrap())
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -488,8 +412,7 @@ pub fn float_to_str_bytes_common<T:NumCast+Zero+One+PartialEq+PartialOrd+Float+
|
|||
* `to_str_bytes_common()`, for details see there.
|
||||
*/
|
||||
#[inline]
|
||||
pub fn float_to_str_common<T:NumCast+Zero+One+PartialEq+PartialOrd+NumStrConv+Float+
|
||||
Div<T,T>+Neg<T>+Rem<T,T>+Mul<T,T>>(
|
||||
pub fn float_to_str_common<T: Float>(
|
||||
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<T:NumCast+Zero+One+PartialEq+PartialOrd+NumStrConv+Fl
|
|||
// Some constants for from_str_bytes_common's input validation,
|
||||
// they define minimum radix values for which the character is a valid digit.
|
||||
static DIGIT_P_RADIX: uint = ('p' as uint) - ('a' as uint) + 11u;
|
||||
static DIGIT_I_RADIX: uint = ('i' as uint) - ('a' as uint) + 11u;
|
||||
static DIGIT_E_RADIX: uint = ('e' as uint) - ('a' as uint) + 11u;
|
||||
|
||||
/**
|
||||
* Parses a byte slice as a number. This is meant to
|
||||
* be a common base implementation for all numeric string conversion
|
||||
* functions like `from_str()` or `from_str_radix()`.
|
||||
*
|
||||
* # Arguments
|
||||
* - `buf` - The byte slice to parse.
|
||||
* - `radix` - Which base to parse the number as. Accepts 2-36.
|
||||
* - `negative` - Whether to accept negative numbers.
|
||||
* - `fractional` - Whether to accept numbers with fractional parts.
|
||||
* - `special` - Whether to accept special values like `inf`
|
||||
* and `NaN`. Can conflict with `radix`, see Failure.
|
||||
* - `exponent` - Which exponent format to accept. Options are:
|
||||
* - `ExpNone`: No Exponent, accepts just plain numbers like `42` or
|
||||
* `-8.2`.
|
||||
* - `ExpDec`: Accepts numbers with a decimal exponent like `42e5` or
|
||||
* `8.2E-2`. The exponent string itself is always base 10.
|
||||
* Can conflict with `radix`, see Failure.
|
||||
* - `ExpBin`: Accepts numbers with a binary exponent like `42P-8` or
|
||||
* `FFp128`. The exponent string itself is always base 10.
|
||||
* Can conflict with `radix`, see Failure.
|
||||
* - `empty_zero` - Whether to accept an empty `buf` as a 0 or not.
|
||||
* - `ignore_underscores` - Whether all underscores within the string should
|
||||
* be ignored.
|
||||
*
|
||||
* # Return value
|
||||
* Returns `Some(n)` if `buf` parses to a number n without overflowing, and
|
||||
* `None` otherwise, depending on the constraints set by the remaining
|
||||
* arguments.
|
||||
*
|
||||
* # Failure
|
||||
* - Fails if `radix` < 2 or `radix` > 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<T:NumCast+Zero+One+PartialEq+PartialOrd+Div<T,T>+
|
||||
Mul<T,T>+Sub<T,T>+Neg<T>+Add<T,T>+
|
||||
NumStrConv+Clone>(
|
||||
buf: &[u8], radix: uint, negative: bool, fractional: bool,
|
||||
special: bool, exponent: ExponentFormat, empty_zero: bool,
|
||||
ignore_underscores: bool
|
||||
) -> Option<T> {
|
||||
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),
|
||||
_ => ()
|
||||
pub fn from_str_radix_float<T: Float>(src: &str, radix: uint) -> Option<T> {
|
||||
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()),
|
||||
_ => {},
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
// 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 integer part of number
|
||||
while i < len {
|
||||
let c = buf[i] as char;
|
||||
|
||||
match char::to_digit(c, radix) {
|
||||
// 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::<uint>(src)),
|
||||
(Some('+'), src) => (true, from_str::<uint>(src)),
|
||||
(Some(_), _) => (true, from_str::<uint>(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
|
||||
};
|
||||
|
||||
// parse remaining bytes as decimal integer,
|
||||
// skipping the exponent char
|
||||
let exp: Option<int> = from_str_bytes_common(
|
||||
buf[i+1..len], 10, true, false, false, ExpNone, false,
|
||||
ignore_underscores);
|
||||
|
||||
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)
|
||||
}
|
||||
match (is_positive, exp) {
|
||||
(true, Some(exp)) => num::pow(base, exp),
|
||||
(false, Some(exp)) => _1 / num::pow(base, exp),
|
||||
(_, None) => return None,
|
||||
}
|
||||
None => return None // invalid exponent -> invalid number
|
||||
}
|
||||
}
|
||||
},
|
||||
None => _1, // no exponent
|
||||
};
|
||||
|
||||
Some(accum * multiplier)
|
||||
Some(sig * exp)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<T:NumCast+Zero+One+PartialEq+PartialOrd+Div<T,T>+Mul<T,T>+
|
||||
Sub<T,T>+Neg<T>+Add<T,T>+NumStrConv+Clone>(
|
||||
buf: &str, radix: uint, negative: bool, fractional: bool,
|
||||
special: bool, exponent: ExponentFormat, empty_zero: bool,
|
||||
ignore_underscores: bool
|
||||
) -> Option<T> {
|
||||
from_str_bytes_common(buf.as_bytes(), radix, negative,
|
||||
fractional, special, exponent, empty_zero,
|
||||
ignore_underscores)
|
||||
pub fn from_str_radix_int<T: Int>(src: &str, radix: uint) -> Option<T> {
|
||||
assert!(radix >= 2 && radix <= 36,
|
||||
"from_str_radix_int: must lie in the range `[2, 36]` - found {}",
|
||||
radix);
|
||||
|
||||
fn cast<T: Int>(x: uint) -> T {
|
||||
num::cast(x).unwrap()
|
||||
}
|
||||
|
||||
let _0: T = num::zero();
|
||||
let _1: T = num::one();
|
||||
let is_signed = _0 > Bounded::min_value();
|
||||
|
||||
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<u8> = from_str_common("__1__", 2, false, false, false,
|
||||
ExpNone, false, true);
|
||||
assert_eq!(s, Some(1u8));
|
||||
|
||||
let n : Option<u8> = from_str_common("__1__", 2, false, false, false,
|
||||
ExpNone, false, false);
|
||||
assert_eq!(n, None);
|
||||
|
||||
let f : Option<f32> = 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<u8> = 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<u8> = from_str_common("1000", 10, false, false, false,
|
||||
ExpNone, false, false);
|
||||
let u : Option<u8> = from_str_radix_int("1000", 10);
|
||||
assert_eq!(u, None);
|
||||
let s : Option<i16> = from_str_common("80000", 10, false, false, false,
|
||||
ExpNone, false, false);
|
||||
let s : Option<i16> = from_str_radix_int("80000", 10);
|
||||
assert_eq!(s, None);
|
||||
let f : Option<f32> = from_str_common(
|
||||
"10000000000000000000000000000000000000000", 10, false, false, false,
|
||||
ExpNone, false, false);
|
||||
assert_eq!(f, NumStrConv::inf())
|
||||
let fe : Option<f32> = from_str_common("1e40", 10, false, false, false,
|
||||
ExpDec, false, false);
|
||||
assert_eq!(fe, NumStrConv::inf())
|
||||
let f : Option<f32> = from_str_radix_float("10000000000000000000000000000000000000000", 10);
|
||||
assert_eq!(f, Some(Float::infinity()))
|
||||
let fe : Option<f32> = from_str_radix_float("1e40", 10);
|
||||
assert_eq!(fe, Some(Float::infinity()))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 @@ fn from_str(s: &str) -> Option<$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<U>(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 @@ pub fn test_from_str() {
|
|||
assert_eq!(from_str::<u32>("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_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!(parse_bytes("Z".as_bytes(), 10u).is_none());
|
||||
assert!(parse_bytes("_".as_bytes(), 2u).is_none());
|
||||
assert_eq!(FromStrRadix::from_str_radix("Z", 10), None::<$T>);
|
||||
assert_eq!(FromStrRadix::from_str_radix("_", 2), None::<$T>);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -148,35 +123,35 @@ fn test_uint_to_str_overflow() {
|
|||
fn test_uint_from_str_overflow() {
|
||||
let mut u8_val: u8 = 255_u8;
|
||||
assert_eq!(from_str::<u8>("255"), Some(u8_val));
|
||||
assert!(from_str::<u8>("256").is_none());
|
||||
assert_eq!(from_str::<u8>("256"), None);
|
||||
|
||||
u8_val += 1 as u8;
|
||||
assert_eq!(from_str::<u8>("0"), Some(u8_val));
|
||||
assert!(from_str::<u8>("-1").is_none());
|
||||
assert_eq!(from_str::<u8>("-1"), None);
|
||||
|
||||
let mut u16_val: u16 = 65_535_u16;
|
||||
assert_eq!(from_str::<u16>("65535"), Some(u16_val));
|
||||
assert!(from_str::<u16>("65536").is_none());
|
||||
assert_eq!(from_str::<u16>("65536"), None);
|
||||
|
||||
u16_val += 1 as u16;
|
||||
assert_eq!(from_str::<u16>("0"), Some(u16_val));
|
||||
assert!(from_str::<u16>("-1").is_none());
|
||||
assert_eq!(from_str::<u16>("-1"), None);
|
||||
|
||||
let mut u32_val: u32 = 4_294_967_295_u32;
|
||||
assert_eq!(from_str::<u32>("4294967295"), Some(u32_val));
|
||||
assert!(from_str::<u32>("4294967296").is_none());
|
||||
assert_eq!(from_str::<u32>("4294967296"), None);
|
||||
|
||||
u32_val += 1 as u32;
|
||||
assert_eq!(from_str::<u32>("0"), Some(u32_val));
|
||||
assert!(from_str::<u32>("-1").is_none());
|
||||
assert_eq!(from_str::<u32>("-1"), None);
|
||||
|
||||
let mut u64_val: u64 = 18_446_744_073_709_551_615_u64;
|
||||
assert_eq!(from_str::<u64>("18446744073709551615"), Some(u64_val));
|
||||
assert!(from_str::<u64>("18446744073709551616").is_none());
|
||||
assert_eq!(from_str::<u64>("18446744073709551616"), None);
|
||||
|
||||
u64_val += 1 as u64;
|
||||
assert_eq!(from_str::<u64>("0"), Some(u64_val));
|
||||
assert!(from_str::<u64>("-1").is_none());
|
||||
assert_eq!(from_str::<u64>("-1"), None);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Expr>),
|
||||
PatRange(P<Expr>, P<Expr>),
|
||||
/// [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<P<Pat>>, Option<P<Pat>>, Vec<P<Pat>>),
|
||||
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<Attribute>,
|
||||
pub ty_param: TyParam,
|
||||
}
|
||||
|
||||
#[deriving(Clone, PartialEq, Eq, Encodable, Decodable, Hash, Show)]
|
||||
|
|
|
@ -405,7 +405,9 @@ pub fn get_path_elem(&self, id: NodeId) -> PathElem {
|
|||
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 @@ pub fn opt_span(&self, id: NodeId) -> Option<Span> {
|
|||
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 @@ fn name(&self) -> Name {
|
|||
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 @@ fn visit_item(&mut self, i: &'ast Item) {
|
|||
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)
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
use visit::Visitor;
|
||||
use visit;
|
||||
|
||||
use std::cell::Cell;
|
||||
use std::cmp;
|
||||
use std::u32;
|
||||
|
||||
|
@ -333,20 +332,20 @@ pub fn add(&mut self, id: NodeId) {
|
|||
}
|
||||
|
||||
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 @@ fn visit_trait_item(&mut self, tm: &ast::TraitItem) {
|
|||
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 @@ fn visit_lifetime_decl(&mut self, def: &'v LifetimeDef) {
|
|||
}
|
||||
|
||||
pub fn visit_ids_for_inlined_item<O: IdVisitingOperation>(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<O: IdVisitingOperation>(item: &InlinedItem,
|
|||
}
|
||||
|
||||
struct IdRangeComputingVisitor {
|
||||
result: Cell<IdRange>,
|
||||
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 {
|
||||
|
|
|
@ -52,11 +52,19 @@ fn cs_clone(
|
|||
name: &str,
|
||||
cx: &mut ExtCtxt, trait_span: Span,
|
||||
substr: &Substructure) -> P<Expr> {
|
||||
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) => {
|
||||
|
|
|
@ -260,7 +260,7 @@ fn visit_trait_item(&mut self, trait_item: &ast::TraitItem) {
|
|||
ast::RequiredMethod(_) | ast::ProvidedMethod(_) => {}
|
||||
ast::TypeTraitItem(ref ti) => {
|
||||
self.gate_feature("associated_types",
|
||||
ti.span,
|
||||
ti.ty_param.span,
|
||||
"associated types are experimental")
|
||||
}
|
||||
}
|
||||
|
|
|
@ -793,19 +793,16 @@ pub fn noop_fold_typedef<T>(t: Typedef, folder: &mut T)
|
|||
|
||||
pub fn noop_fold_associated_type<T>(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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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)]
|
||||
|
|
|
@ -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<Reader+'a>)
|
||||
-> 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 @@ pub fn bump(&mut self) {
|
|||
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 @@ pub fn look_ahead<R>(&mut self, distance: uint, f: |&token::Token| -> R)
|
|||
-> 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 @@ pub fn parse_ty_fn_decl(&mut self, allow_variadic: bool)
|
|||
/// Parses `type Foo;` in a trait declaration only. The `type` keyword has
|
||||
/// already been parsed.
|
||||
fn parse_associated_type(&mut self, attrs: Vec<Attribute>)
|
||||
-> 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,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -668,12 +668,12 @@ pub fn get<'a>(&'a self) -> &'a str {
|
|||
|
||||
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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<MemWriter> = 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 @@ pub fn print_foreign_item(&mut self,
|
|||
}
|
||||
|
||||
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 @@ pub fn print_generics(&mut self,
|
|||
} 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 @@ pub fn print_generics(&mut self,
|
|||
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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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};
|
||||
|
|
|
@ -24,7 +24,6 @@
|
|||
use std::os;
|
||||
use std::result::{Ok, Err};
|
||||
use std::task;
|
||||
use std::uint;
|
||||
|
||||
fn fib(n: int) -> int {
|
||||
fn pfib(tx: &Sender<int>, 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::<uint>(args[1].as_slice()).unwrap() as int;
|
||||
|
||||
let num_trials = 10;
|
||||
|
||||
|
|
24
src/test/compile-fail/associated-types-unsized.rs
Normal file
24
src/test/compile-fail/associated-types-unsized.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![feature(associated_types)]
|
||||
|
||||
trait Get {
|
||||
type Sized? Value;
|
||||
fn get(&self) -> <Self as Get>::Value;
|
||||
}
|
||||
|
||||
fn foo<T:Get>(t: T) {
|
||||
let x = t.get(); //~ ERROR the trait `core::kinds::Sized` is not implemented
|
||||
}
|
||||
|
||||
fn main() {
|
||||
}
|
||||
|
|
@ -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`
|
||||
}
|
||||
|
||||
|
||||
|
|
22
src/test/compile-fail/issue-18532.rs
Normal file
22
src/test/compile-fail/issue-18532.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// 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
|
||||
}
|
|
@ -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 << 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 >> 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;
|
||||
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 << -9; //~ 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 << (4+4);
|
||||
let n = 1u8 << (4+5); //~ 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 = 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
|
||||
}
|
||||
|
||||
|
|
26
src/test/compile-fail/trait-impl-1.rs
Normal file
26
src/test/compile-fail/trait-impl-1.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// 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`
|
||||
}
|
24
src/test/compile-fail/trait-impl-2.rs
Normal file
24
src/test/compile-fail/trait-impl-2.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// 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() {}
|
|
@ -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 @@
|
|||
// 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 @@
|
|||
// 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 @@
|
|||
// 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 @@
|
|||
// 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),
|
||||
|
|
|
@ -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>
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
trait T { fn foo(); }
|
||||
|
||||
#[rustc_variance]
|
||||
struct TOption<'a> { //~ ERROR regions=[[-];[];[]]
|
||||
struct TOption<'a> { //~ ERROR regions=[[-];[];[];[]]
|
||||
v: Option<Box<T + 'a>>,
|
||||
}
|
||||
|
||||
|
|
16
src/test/run-pass/issue-15689-2.rs
Normal file
16
src/test/run-pass/issue-15689-2.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#[deriving(Clone)]
|
||||
enum Test<'a> {
|
||||
Slice(&'a int)
|
||||
}
|
||||
|
||||
fn main() {}
|
36
src/test/run-pass/trait-impl.rs
Normal file
36
src/test/run-pass/trait-impl.rs
Normal file
|
@ -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 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// 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); }
|
||||
}
|
Loading…
Reference in a new issue