auto merge of #8802 : pcwalton/rust/compile-speed, r=brson

r? @brson
This commit is contained in:
bors 2013-08-27 19:35:44 -07:00
commit 578e680477
143 changed files with 3070 additions and 1783 deletions

View File

@ -2230,7 +2230,7 @@ Some examples of call expressions:
# fn add(x: int, y: int) -> int { 0 }
let x: int = add(1, 2);
let pi = FromStr::from_str::<f32>("3.14");
let pi: Option<f32> = FromStr::from_str("3.14");
~~~~
### Lambda expressions

View File

@ -420,6 +420,7 @@ mod test {
#[test]
#[should_fail]
fn test_add_bytes_to_bits_tuple_overflow2() {
add_bytes_to_bits_tuple::<u64>((Bounded::max_value::<u64>() - 1, 0), 0x8000000000000000);
let value: u64 = Bounded::max_value();
add_bytes_to_bits_tuple::<u64>((value - 1, 0), 0x8000000000000000);
}
}

View File

@ -661,7 +661,7 @@ mod tests {
#[test]
fn test_basic() {
let mut m = DList::new::<~int>();
let mut m: DList<~int> = DList::new();
assert_eq!(m.pop_front(), None);
assert_eq!(m.pop_back(), None);
assert_eq!(m.pop_front(), None);
@ -768,7 +768,7 @@ mod tests {
#[test]
fn test_rotate() {
let mut n = DList::new::<int>();
let mut n: DList<int> = DList::new();
n.rotate_backward(); check_links(&n);
assert_eq!(n.len(), 0);
n.rotate_forward(); check_links(&n);
@ -1033,7 +1033,7 @@ mod tests {
#[cfg(test)]
fn fuzz_test(sz: int) {
let mut m = DList::new::<int>();
let mut m: DList<int> = DList::new();
let mut v = ~[];
for i in range(0, sz) {
check_links(&m);
@ -1078,7 +1078,7 @@ mod tests {
#[bench]
fn bench_push_front(b: &mut test::BenchHarness) {
let mut m = DList::new::<int>();
let mut m: DList<int> = DList::new();
do b.iter {
m.push_front(0);
}
@ -1086,7 +1086,7 @@ mod tests {
#[bench]
fn bench_push_back(b: &mut test::BenchHarness) {
let mut m = DList::new::<int>();
let mut m: DList<int> = DList::new();
do b.iter {
m.push_back(0);
}
@ -1094,7 +1094,7 @@ mod tests {
#[bench]
fn bench_push_back_pop_back(b: &mut test::BenchHarness) {
let mut m = DList::new::<int>();
let mut m: DList<int> = DList::new();
do b.iter {
m.push_back(0);
m.pop_back();
@ -1103,7 +1103,7 @@ mod tests {
#[bench]
fn bench_push_front_pop_front(b: &mut test::BenchHarness) {
let mut m = DList::new::<int>();
let mut m: DList<int> = DList::new();
do b.iter {
m.push_front(0);
m.pop_front();
@ -1112,7 +1112,7 @@ mod tests {
#[bench]
fn bench_rotate_forward(b: &mut test::BenchHarness) {
let mut m = DList::new::<int>();
let mut m: DList<int> = DList::new();
m.push_front(0);
m.push_front(1);
do b.iter {
@ -1122,7 +1122,7 @@ mod tests {
#[bench]
fn bench_rotate_backward(b: &mut test::BenchHarness) {
let mut m = DList::new::<int>();
let mut m: DList<int> = DList::new();
m.push_front(0);
m.push_front(1);
do b.iter {

View File

@ -25,13 +25,13 @@ pub mod rustrt {
#[link_name = "rustrt"]
extern {
pub fn tdefl_compress_mem_to_heap(psrc_buf: *const c_void,
pub fn tdefl_compress_mem_to_heap(psrc_buf: *c_void,
src_buf_len: size_t,
pout_len: *mut size_t,
flags: c_int)
-> *c_void;
pub fn tinfl_decompress_mem_to_heap(psrc_buf: *const c_void,
pub fn tinfl_decompress_mem_to_heap(psrc_buf: *c_void,
src_buf_len: size_t,
pout_len: *mut size_t,
flags: c_int)

View File

@ -359,7 +359,7 @@ impl Integer for BigUint {
fn div_mod_floor_inner(a: BigUint, b: BigUint) -> (BigUint, BigUint) {
let mut m = a;
let mut d = Zero::zero::<BigUint>();
let mut d: BigUint = Zero::zero();
let mut n = 1;
while m >= b {
let (d0, d_unit, b_unit) = div_estimate(&m, &b, n);
@ -411,8 +411,9 @@ impl Integer for BigUint {
if shift == 0 {
return (BigUint::new(d), One::one(), (*b).clone());
}
let one: BigUint = One::one();
return (BigUint::from_slice(d).shl_unit(shift),
One::one::<BigUint>().shl_unit(shift),
one.shl_unit(shift),
b.shl_unit(shift));
}
}
@ -1168,8 +1169,8 @@ mod biguint_tests {
#[test]
fn test_shl() {
fn check(s: &str, shift: uint, ans: &str) {
let bu = (FromStrRadix::from_str_radix::<BigUint>(s, 16).unwrap() << shift)
.to_str_radix(16);
let opt_biguint: Option<BigUint> = FromStrRadix::from_str_radix(s, 16);
let bu = (opt_biguint.unwrap() << shift).to_str_radix(16);
assert_eq!(bu.as_slice(), ans);
}
@ -1206,8 +1207,9 @@ mod biguint_tests {
#[test]
fn test_shr() {
fn check(s: &str, shift: uint, ans: &str) {
let bu = (FromStrRadix::from_str_radix::<BigUint>(s, 16).unwrap() >> shift)
.to_str_radix(16);
let opt_biguint: Option<BigUint> =
FromStrRadix::from_str_radix(s, 16);
let bu = (opt_biguint.unwrap() >> shift).to_str_radix(16);
assert_eq!(bu.as_slice(), ans);
}
@ -1445,11 +1447,18 @@ mod biguint_tests {
#[test]
fn test_is_even() {
assert!(FromStr::from_str::<BigUint>("1").unwrap().is_odd());
assert!(FromStr::from_str::<BigUint>("2").unwrap().is_even());
assert!(FromStr::from_str::<BigUint>("1000").unwrap().is_even());
assert!(FromStr::from_str::<BigUint>("1000000000000000000000").unwrap().is_even());
assert!(FromStr::from_str::<BigUint>("1000000000000000000001").unwrap().is_odd());
let one: Option<BigUint> = FromStr::from_str("1");
let two: Option<BigUint> = FromStr::from_str("2");
let thousand: Option<BigUint> = FromStr::from_str("1000");
let big: Option<BigUint> =
FromStr::from_str("1000000000000000000000");
let bigger: Option<BigUint> =
FromStr::from_str("1000000000000000000001");
assert!(one.unwrap().is_odd());
assert!(two.unwrap().is_even());
assert!(thousand.unwrap().is_even());
assert!(big.unwrap().is_even());
assert!(bigger.unwrap().is_odd());
assert!((BigUint::from_uint(1) << 64).is_even());
assert!(((BigUint::from_uint(1) << 64) + BigUint::from_uint(1)).is_odd());
}
@ -1534,15 +1543,19 @@ mod biguint_tests {
}
}
assert_eq!(FromStrRadix::from_str_radix::<BigUint>("Z", 10), None);
assert_eq!(FromStrRadix::from_str_radix::<BigUint>("_", 2), None);
assert_eq!(FromStrRadix::from_str_radix::<BigUint>("-1", 10), None);
let zed: Option<BigUint> = FromStrRadix::from_str_radix("Z", 10);
assert_eq!(zed, None);
let blank: Option<BigUint> = FromStrRadix::from_str_radix("_", 2);
assert_eq!(blank, None);
let minus_one: Option<BigUint> = FromStrRadix::from_str_radix("-1",
10);
assert_eq!(minus_one, None);
}
#[test]
fn test_factor() {
fn factor(n: uint) -> BigUint {
let mut f= One::one::<BigUint>();
let mut f: BigUint = One::one();
for i in range(2, n + 1) {
// FIXME(#6102): Assignment operator for BigInt causes ICE
// f *= BigUint::from_uint(i);
@ -1939,17 +1952,24 @@ mod bigint_tests {
#[test]
fn test_abs_sub() {
assert_eq!((-One::one::<BigInt>()).abs_sub(&One::one()), Zero::zero());
assert_eq!(One::one::<BigInt>().abs_sub(&One::one()), Zero::zero());
assert_eq!(One::one::<BigInt>().abs_sub(&Zero::zero()), One::one());
assert_eq!(One::one::<BigInt>().abs_sub(&-One::one::<BigInt>()),
IntConvertible::from_int(2));
let zero: BigInt = Zero::zero();
let one: BigInt = One::one();
assert_eq!((-one).abs_sub(&one), zero);
let one: BigInt = One::one();
let zero: BigInt = Zero::zero();
assert_eq!(one.abs_sub(&one), zero);
let one: BigInt = One::one();
let zero: BigInt = Zero::zero();
assert_eq!(one.abs_sub(&zero), one);
let one: BigInt = One::one();
assert_eq!(one.abs_sub(&-one), IntConvertible::from_int(2));
}
#[test]
fn test_to_str_radix() {
fn check(n: int, ans: &str) {
assert!(ans == IntConvertible::from_int::<BigInt>(n).to_str_radix(10));
let n: BigInt = IntConvertible::from_int(n);
assert!(ans == n.to_str_radix(10));
}
check(10, "10");
check(1, "1");
@ -1962,7 +1982,10 @@ mod bigint_tests {
#[test]
fn test_from_str_radix() {
fn check(s: &str, ans: Option<int>) {
let ans = ans.map_move(|n| IntConvertible::from_int::<BigInt>(n));
let ans = ans.map_move(|n| {
let x: BigInt = IntConvertible::from_int(n);
x
});
assert_eq!(FromStrRadix::from_str_radix(s, 10), ans);
}
check("10", Some(10));
@ -1980,7 +2003,8 @@ mod bigint_tests {
BigInt::new(Minus, ~[1, 1, 1]));
assert!(-BigInt::new(Minus, ~[1, 1, 1]) ==
BigInt::new(Plus, ~[1, 1, 1]));
assert_eq!(-Zero::zero::<BigInt>(), Zero::zero::<BigInt>());
let zero: BigInt = Zero::zero();
assert_eq!(-zero, zero);
}
}
@ -1992,7 +2016,7 @@ mod bench {
use extra::test::BenchHarness;
fn factorial(n: uint) -> BigUint {
let mut f = One::one::<BigUint>();
let mut f: BigUint = One::one();
for i in iterator::range_inclusive(1, n) {
f = f * BigUint::from_uint(i);
}
@ -2000,8 +2024,8 @@ mod bench {
}
fn fib(n: uint) -> BigUint {
let mut f0 = Zero::zero::<BigUint>();
let mut f1 = One::one::<BigUint>();
let mut f0: BigUint = Zero::zero();
let mut f1: BigUint = One::one();
for _ in range(0, n) {
let f2 = f0 + f1;
f0 = util::replace(&mut f1, f2);

View File

@ -269,9 +269,13 @@ impl<T: FromStr + Clone + Integer + Ord>
/// Parses `numer/denom`.
fn from_str(s: &str) -> Option<Ratio<T>> {
let split: ~[&str] = s.splitn_iter('/', 1).collect();
if split.len() < 2 { return None; }
do FromStr::from_str::<T>(split[0]).chain |a| {
do FromStr::from_str::<T>(split[1]).chain |b| {
if split.len() < 2 {
return None
}
let a_option: Option<T> = FromStr::from_str(split[0]);
do a_option.chain |a| {
let b_option: Option<T> = FromStr::from_str(split[1]);
do b_option.chain |b| {
Some(Ratio::new(a.clone(), b.clone()))
}
}
@ -282,10 +286,15 @@ impl<T: FromStrRadix + Clone + Integer + Ord>
/// Parses `numer/denom` where the numbers are in base `radix`.
fn from_str_radix(s: &str, radix: uint) -> Option<Ratio<T>> {
let split: ~[&str] = s.splitn_iter('/', 1).collect();
if split.len() < 2 { None }
else {
do FromStrRadix::from_str_radix::<T>(split[0], radix).chain |a| {
do FromStrRadix::from_str_radix::<T>(split[1], radix).chain |b| {
if split.len() < 2 {
None
} else {
let a_option: Option<T> = FromStrRadix::from_str_radix(split[0],
radix);
do a_option.chain |a| {
let b_option: Option<T> =
FromStrRadix::from_str_radix(split[1], radix);
do b_option.chain |b| {
Some(Ratio::new(a.clone(), b.clone()))
}
}
@ -496,7 +505,8 @@ mod test {
#[test]
fn test_from_str_fail() {
fn test(s: &str) {
assert_eq!(FromStr::from_str::<Rational>(s), None);
let rational: Option<Rational> = FromStr::from_str(s);
assert_eq!(rational, None);
}
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1"];
@ -536,7 +546,8 @@ mod test {
#[test]
fn test_from_str_radix_fail() {
fn test(s: &str) {
assert_eq!(FromStrRadix::from_str_radix::<Rational>(s, 3), None);
let radix: Option<Rational> = FromStrRadix::from_str_radix(s, 3);
assert_eq!(radix, None);
}
let xs = ["0 /1", "abc", "", "1/", "--1/2","3/2/1", "3/2"];

View File

@ -338,27 +338,36 @@ mod tests {
#[test]
#[should_fail]
fn test_empty_pop() { let mut heap = PriorityQueue::new::<int>(); heap.pop(); }
fn test_empty_pop() {
let mut heap: PriorityQueue<int> = PriorityQueue::new();
heap.pop();
}
#[test]
fn test_empty_maybe_pop() {
let mut heap = PriorityQueue::new::<int>();
let mut heap: PriorityQueue<int> = PriorityQueue::new();
assert!(heap.maybe_pop().is_none());
}
#[test]
#[should_fail]
fn test_empty_top() { let empty = PriorityQueue::new::<int>(); empty.top(); }
fn test_empty_top() {
let empty: PriorityQueue<int> = PriorityQueue::new();
empty.top();
}
#[test]
fn test_empty_maybe_top() {
let empty = PriorityQueue::new::<int>();
let empty: PriorityQueue<int> = PriorityQueue::new();
assert!(empty.maybe_top().is_none());
}
#[test]
#[should_fail]
fn test_empty_replace() { let mut heap = PriorityQueue::new(); heap.replace(5); }
fn test_empty_replace() {
let mut heap: PriorityQueue<int> = PriorityQueue::new();
heap.replace(5);
}
#[test]
fn test_from_iter() {

View File

@ -483,7 +483,7 @@ mod tests {
#[bench]
fn bench_new(b: &mut test::BenchHarness) {
do b.iter {
let _ = RingBuf::new::<u64>();
let _: RingBuf<u64> = RingBuf::new();
}
}

View File

@ -368,7 +368,7 @@ pub fn write_boxplot(w: @io::Writer, s: &Summary, width_hint: uint) {
/// Returns a HashMap with the number of occurrences of every element in the
/// sequence that the iterator exposes.
pub fn freq_count<T: Iterator<U>, U: Eq+Hash>(mut iter: T) -> hashmap::HashMap<U, uint> {
let mut map = hashmap::HashMap::new::<U, uint>();
let mut map: hashmap::HashMap<U,uint> = hashmap::HashMap::new();
for elem in iter {
map.insert_or_update_with(elem, 1, |_, count| *count += 1);
}

View File

@ -879,7 +879,8 @@ mod test_treemap {
#[test]
fn find_empty() {
let m = TreeMap::new::<int, int>(); assert!(m.find(&5) == None);
let m: TreeMap<int,int> = TreeMap::new();
assert!(m.find(&5) == None);
}
#[test]
@ -1006,7 +1007,7 @@ mod test_treemap {
#[test]
fn test_rand_int() {
let mut map = TreeMap::new::<int, int>();
let mut map: TreeMap<int,int> = TreeMap::new();
let mut ctrl = ~[];
check_equal(ctrl, &map);

View File

@ -17,6 +17,7 @@ use syntax::attr;
use syntax::codemap::dummy_sp;
use syntax::codemap;
use syntax::fold;
use syntax::opt_vec;
static STD_VERSION: &'static str = "0.8-pre";
@ -90,12 +91,18 @@ fn inject_libstd_ref(sess: Session, crate: &ast::Crate) -> @ast::Crate {
let prelude_path = ast::Path {
span: dummy_sp(),
global: false,
idents: ~[
sess.ident_of("std"),
sess.ident_of("prelude")
segments: ~[
ast::PathSegment {
identifier: sess.ident_of("std"),
lifetime: None,
types: opt_vec::Empty,
},
ast::PathSegment {
identifier: sess.ident_of("prelude"),
lifetime: None,
types: opt_vec::Empty,
},
],
rp: None,
types: ~[]
};
let vp = @spanned(ast::view_path_glob(prelude_path, n2));

View File

@ -16,14 +16,15 @@ use front::config;
use std::vec;
use syntax::ast_util::*;
use syntax::attr::AttrMetaMethods;
use syntax::attr;
use syntax::codemap::{dummy_sp, span, ExpnInfo, NameAndSpan};
use syntax::codemap;
use syntax::ext::base::ExtCtxt;
use syntax::fold;
use syntax::opt_vec;
use syntax::print::pprust;
use syntax::{ast, ast_util};
use syntax::attr::AttrMetaMethods;
type node_id_gen = @fn() -> ast::NodeId;
@ -383,19 +384,27 @@ fn nospan<T>(t: T) -> codemap::spanned<T> {
}
fn path_node(ids: ~[ast::ident]) -> ast::Path {
ast::Path { span: dummy_sp(),
global: false,
idents: ids,
rp: None,
types: ~[] }
ast::Path {
span: dummy_sp(),
global: false,
segments: ids.move_iter().map(|identifier| ast::PathSegment {
identifier: identifier,
lifetime: None,
types: opt_vec::Empty,
}).collect()
}
}
fn path_node_global(ids: ~[ast::ident]) -> ast::Path {
ast::Path { span: dummy_sp(),
global: true,
idents: ids,
rp: None,
types: ~[] }
ast::Path {
span: dummy_sp(),
global: true,
segments: ids.move_iter().map(|identifier| ast::PathSegment {
identifier: identifier,
lifetime: None,
types: opt_vec::Empty,
}).collect()
}
}
#[cfg(stage0)]

View File

@ -182,6 +182,12 @@ pub static tag_misc_info_crate_items: uint = 0x80;
pub static tag_item_method_provided_source: uint = 0x81;
pub static tag_item_impl_vtables: uint = 0x82;
pub static tag_impls: uint = 0x83;
pub static tag_impls_impl: uint = 0x84;
pub static tag_items_data_item_inherent_impl: uint = 0x85;
pub static tag_items_data_item_extension_impl: uint = 0x86;
pub struct LinkMeta {
name: @str,
vers: @str,

View File

@ -49,16 +49,34 @@ pub fn each_lang_item(cstore: @mut cstore::CStore,
decoder::each_lang_item(crate_data, f)
}
/// Iterates over all the paths in the given crate.
pub fn each_path(cstore: @mut cstore::CStore,
cnum: ast::CrateNum,
f: &fn(&str, decoder::def_like, ast::visibility) -> bool)
-> bool {
/// Iterates over each child of the given item.
pub fn each_child_of_item(cstore: @mut cstore::CStore,
def_id: ast::def_id,
callback: &fn(decoder::def_like, ast::ident)) {
let crate_data = cstore::get_crate_data(cstore, def_id.crate);
let get_crate_data: decoder::GetCrateDataCb = |cnum| {
cstore::get_crate_data(cstore, cnum)
};
decoder::each_child_of_item(cstore.intr,
crate_data,
def_id.node,
get_crate_data,
callback)
}
/// Iterates over each top-level crate item.
pub fn each_top_level_item_of_crate(cstore: @mut cstore::CStore,
cnum: ast::CrateNum,
callback: &fn(decoder::def_like,
ast::ident)) {
let crate_data = cstore::get_crate_data(cstore, cnum);
let get_crate_data: decoder::GetCrateDataCb = |cnum| {
cstore::get_crate_data(cstore, cnum)
};
decoder::each_path(cstore.intr, crate_data, get_crate_data, f)
decoder::each_top_level_item_of_crate(cstore.intr,
crate_data,
get_crate_data,
callback)
}
pub fn get_item_path(tcx: ty::ctxt, def: ast::def_id) -> ast_map::path {
@ -246,3 +264,36 @@ pub fn get_link_args_for_crate(cstore: @mut cstore::CStore,
let cdata = cstore::get_crate_data(cstore, crate_num);
decoder::get_link_args_for_crate(cdata)
}
pub fn each_impl(cstore: @mut cstore::CStore,
crate_num: ast::CrateNum,
callback: &fn(ast::def_id)) {
let cdata = cstore::get_crate_data(cstore, crate_num);
decoder::each_impl(cdata, callback)
}
pub fn each_implementation_for_type(cstore: @mut cstore::CStore,
def_id: ast::def_id,
callback: &fn(ast::def_id)) {
let cdata = cstore::get_crate_data(cstore, def_id.crate);
decoder::each_implementation_for_type(cdata, def_id.node, callback)
}
pub fn each_implementation_for_trait(cstore: @mut cstore::CStore,
def_id: ast::def_id,
callback: &fn(ast::def_id)) {
let cdata = cstore::get_crate_data(cstore, def_id.crate);
decoder::each_implementation_for_trait(cdata, def_id.node, callback)
}
/// If the given def ID describes a method belonging to a trait (either a
/// default method or an implementation of a trait method), returns the ID of
/// the trait that the method belongs to. Otherwise, returns `None`.
pub fn get_trait_of_method(cstore: @mut cstore::CStore,
def_id: ast::def_id,
tcx: ty::ctxt)
-> Option<ast::def_id> {
let cdata = cstore::get_crate_data(cstore, def_id.crate);
decoder::get_trait_of_method(cdata, def_id.node, tcx)
}

View File

@ -20,6 +20,7 @@ use metadata::decoder;
use metadata::tydecode::{parse_ty_data, parse_def_id,
parse_type_param_def_data,
parse_bare_fn_ty_data, parse_trait_ref_data};
use middle::ty::{ImplContainer, TraitContainer};
use middle::ty;
use middle::typeck;
use middle::astencode::vtable_decoder_helpers;
@ -39,7 +40,7 @@ use syntax::ast_map;
use syntax::attr;
use syntax::parse::token::{ident_interner, special_idents};
use syntax::print::pprust;
use syntax::{ast, ast_util};
use syntax::ast;
use syntax::codemap;
use syntax::parse::token;
@ -335,15 +336,19 @@ fn item_to_def_like(item: ebml::Doc, did: ast::def_id, cnum: ast::CrateNum)
let purity = if fam == UnsafeStaticMethod { ast::unsafe_fn } else
{ ast::impure_fn };
// def_static_method carries an optional field of its enclosing
// *trait*, but not an inclosing Impl (if this is an inherent
// static method). So we need to detect whether this is in
// a trait or not, which we do through the mildly hacky
// way of checking whether there is a trait_method_sort.
let trait_did_opt = if reader::maybe_get_doc(
// trait or enclosing impl (if this is an inherent static method).
// So we need to detect whether this is in a trait or not, which
// we do through the mildly hacky way of checking whether there is
// a trait_method_sort.
let provenance = if reader::maybe_get_doc(
item, tag_item_trait_method_sort).is_some() {
Some(item_reqd_and_translated_parent_item(cnum, item))
} else { None };
dl_def(ast::def_static_method(did, trait_did_opt, purity))
ast::FromTrait(item_reqd_and_translated_parent_item(cnum,
item))
} else {
ast::FromImpl(item_reqd_and_translated_parent_item(cnum,
item))
};
dl_def(ast::def_static_method(did, provenance, purity))
}
Type | ForeignType => dl_def(ast::def_ty(did)),
Mod => dl_def(ast::def_mod(did)),
@ -698,33 +703,164 @@ impl<'self> EachItemContext<'self> {
}
}
/// Iterates over all the paths in the given crate.
pub fn each_path(intr: @ident_interner,
cdata: cmd,
get_crate_data: GetCrateDataCb,
f: &fn(&str, def_like, ast::visibility) -> bool)
-> bool {
// FIXME #4572: This function needs to be nuked, as it's impossible to
// make fast. It's the source of most of the performance problems when
// compiling small crates.
fn each_child_of_item_or_crate(intr: @ident_interner,
cdata: cmd,
item_doc: ebml::Doc,
get_crate_data: GetCrateDataCb,
callback: &fn(def_like, ast::ident)) {
// Iterate over all children.
let _ = do reader::tagged_docs(item_doc, tag_mod_child) |child_info_doc| {
let child_def_id = reader::with_doc_data(child_info_doc,
parse_def_id);
let child_def_id = translate_def_id(cdata, child_def_id);
// This item may be in yet another crate if it was the child of a
// reexport.
let other_crates_items = if child_def_id.crate == cdata.cnum {
reader::get_doc(reader::Doc(cdata.data), tag_items)
} else {
let crate_data = get_crate_data(child_def_id.crate);
reader::get_doc(reader::Doc(crate_data.data), tag_items)
};
// Get the item.
match maybe_find_item(child_def_id.node, other_crates_items) {
None => {}
Some(child_item_doc) => {
// Hand off the item to the callback.
let child_name = item_name(intr, child_item_doc);
let def_like = item_to_def_like(child_item_doc,
child_def_id,
cdata.cnum);
callback(def_like, child_name);
}
}
true
};
// As a special case, iterate over all static methods of
// associated implementations too. This is a bit of a botch.
// --pcwalton
let _ = do reader::tagged_docs(item_doc,
tag_items_data_item_inherent_impl)
|inherent_impl_def_id_doc| {
let inherent_impl_def_id = item_def_id(inherent_impl_def_id_doc,
cdata);
let items = reader::get_doc(reader::Doc(cdata.data), tag_items);
match maybe_find_item(inherent_impl_def_id.node, items) {
None => {}
Some(inherent_impl_doc) => {
let _ = do reader::tagged_docs(inherent_impl_doc,
tag_item_impl_method)
|impl_method_def_id_doc| {
let impl_method_def_id =
reader::with_doc_data(impl_method_def_id_doc,
parse_def_id);
let impl_method_def_id =
translate_def_id(cdata, impl_method_def_id);
match maybe_find_item(impl_method_def_id.node, items) {
None => {}
Some(impl_method_doc) => {
match item_family(impl_method_doc) {
StaticMethod | UnsafeStaticMethod => {
// Hand off the static method
// to the callback.
let static_method_name =
item_name(intr, impl_method_doc);
let static_method_def_like =
item_to_def_like(impl_method_doc,
impl_method_def_id,
cdata.cnum);
callback(static_method_def_like,
static_method_name);
}
_ => {}
}
}
}
true
};
}
}
true
};
// Iterate over all reexports.
let _ = do each_reexport(item_doc) |reexport_doc| {
let def_id_doc = reader::get_doc(reexport_doc,
tag_items_data_item_reexport_def_id);
let child_def_id = reader::with_doc_data(def_id_doc,
parse_def_id);
let child_def_id = translate_def_id(cdata, child_def_id);
let name_doc = reader::get_doc(reexport_doc,
tag_items_data_item_reexport_name);
let name = name_doc.as_str_slice();
// This reexport may be in yet another crate.
let other_crates_items = if child_def_id.crate == cdata.cnum {
reader::get_doc(reader::Doc(cdata.data), tag_items)
} else {
let crate_data = get_crate_data(child_def_id.crate);
reader::get_doc(reader::Doc(crate_data.data), tag_items)
};
// Get the item.
match maybe_find_item(child_def_id.node, other_crates_items) {
None => {}
Some(child_item_doc) => {
// Hand off the item to the callback.
let def_like = item_to_def_like(child_item_doc,
child_def_id,
cdata.cnum);
callback(def_like, token::str_to_ident(name));
}
}
true
};
}
/// Iterates over each child of the given item.
pub fn each_child_of_item(intr: @ident_interner,
cdata: cmd,
id: ast::NodeId,
get_crate_data: GetCrateDataCb,
callback: &fn(def_like, ast::ident)) {
// Find the item.
let root_doc = reader::Doc(cdata.data);
let items = reader::get_doc(root_doc, tag_items);
let item_doc = match maybe_find_item(id, items) {
None => return,
Some(item_doc) => item_doc,
};
each_child_of_item_or_crate(intr,
cdata,
item_doc,
get_crate_data,
callback)
}
/// Iterates over all the top-level crate items.
pub fn each_top_level_item_of_crate(intr: @ident_interner,
cdata: cmd,
get_crate_data: GetCrateDataCb,
callback: &fn(def_like, ast::ident)) {
let root_doc = reader::Doc(cdata.data);
let misc_info_doc = reader::get_doc(root_doc, tag_misc_info);
let crate_items_doc = reader::get_doc(misc_info_doc,
tag_misc_info_crate_items);
let mut path_builder = ~"";
let mut context = EachItemContext {
intr: intr,
cdata: cdata,
get_crate_data: get_crate_data,
path_builder: &mut path_builder,
callback: f,
};
// Iterate over all top-level crate items.
context.each_child_of_module_or_crate(crate_items_doc)
each_child_of_item_or_crate(intr,
cdata,
crate_items_doc,
get_crate_data,
callback)
}
pub fn get_item_path(cdata: cmd, id: ast::NodeId) -> ast_map::path {
@ -804,12 +940,9 @@ pub fn get_enum_variants(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
fn get_explicit_self(item: ebml::Doc) -> ast::explicit_self_ {
fn get_mutability(ch: u8) -> ast::mutability {
match ch as char {
'i' => { ast::m_imm }
'm' => { ast::m_mutbl }
'c' => { ast::m_const }
_ => {
fail!("unknown mutability character: `%c`", ch as char)
}
'i' => ast::m_imm,
'm' => ast::m_mutbl,
_ => fail!("unknown mutability character: `%c`", ch as char),
}
}
@ -876,8 +1009,15 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
{
let method_doc = lookup_item(id, cdata.data);
let def_id = item_def_id(method_doc, cdata);
let container_id = item_reqd_and_translated_parent_item(cdata.cnum,
method_doc);
let container_doc = lookup_item(container_id.node, cdata.data);
let container = match item_family(container_doc) {
Trait => TraitContainer(container_id),
_ => ImplContainer(container_id),
};
let name = item_name(intr, method_doc);
let type_param_defs = item_ty_param_defs(method_doc, tcx, cdata,
tag_item_method_tps);
@ -898,7 +1038,7 @@ pub fn get_method(intr: @ident_interner, cdata: cmd, id: ast::NodeId,
explicit_self,
vis,
def_id,
container_id,
container,
provided_source
)
}
@ -1267,21 +1407,6 @@ pub fn get_crate_vers(data: @~[u8]) -> @str {
}
}
fn iter_crate_items(intr: @ident_interner, cdata: cmd,
get_crate_data: GetCrateDataCb,
proc: &fn(path: &str, ast::def_id)) {
do each_path(intr, cdata, get_crate_data) |path_string, def_like, _| {
match def_like {
dl_impl(*) | dl_field => {}
dl_def(def) => {
proc(path_string,
ast_util::def_id_of_def(def))
}
}
true
};
}
pub fn list_crate_metadata(intr: @ident_interner, bytes: @~[u8],
out: @io::Writer) {
let hash = get_crate_hash(bytes);
@ -1315,3 +1440,59 @@ pub fn get_link_args_for_crate(cdata: cmd) -> ~[~str] {
};
result
}
pub fn each_impl(cdata: cmd, callback: &fn(ast::def_id)) {
let impls_doc = reader::get_doc(reader::Doc(cdata.data), tag_impls);
let _ = do reader::tagged_docs(impls_doc, tag_impls_impl) |impl_doc| {
callback(item_def_id(impl_doc, cdata));
true
};
}
pub fn each_implementation_for_type(cdata: cmd,
id: ast::NodeId,
callback: &fn(ast::def_id)) {
let item_doc = lookup_item(id, cdata.data);
do reader::tagged_docs(item_doc, tag_items_data_item_inherent_impl)
|impl_doc| {
let implementation_def_id = item_def_id(impl_doc, cdata);
callback(implementation_def_id);
true
};
}
pub fn each_implementation_for_trait(cdata: cmd,
id: ast::NodeId,
callback: &fn(ast::def_id)) {
let item_doc = lookup_item(id, cdata.data);
let _ = do reader::tagged_docs(item_doc,
tag_items_data_item_extension_impl)
|impl_doc| {
let implementation_def_id = item_def_id(impl_doc, cdata);
callback(implementation_def_id);
true
};
}
pub fn get_trait_of_method(cdata: cmd, id: ast::NodeId, tcx: ty::ctxt)
-> Option<ast::def_id> {
let item_doc = lookup_item(id, cdata.data);
let parent_item_id = match item_parent_item(item_doc) {
None => return None,
Some(item_id) => item_id,
};
let parent_item_id = translate_def_id(cdata, parent_item_id);
let parent_item_doc = lookup_item(parent_item_id.node, cdata.data);
match item_family(parent_item_doc) {
Trait => Some(item_def_id(parent_item_doc, cdata)),
Impl => {
do reader::maybe_get_doc(parent_item_doc, tag_item_trait_ref).map
|_| {
item_trait_ref(parent_item_doc, tcx, cdata).def_id
}
}
_ => None
}
}

View File

@ -39,6 +39,7 @@ use syntax::attr::AttrMetaMethods;
use syntax::diagnostic::span_handler;
use syntax::parse::token::special_idents;
use syntax::ast_util;
use syntax::visit::Visitor;
use syntax::visit;
use syntax::parse::token;
use syntax;
@ -72,6 +73,7 @@ struct Stats {
dep_bytes: uint,
lang_item_bytes: uint,
link_args_bytes: uint,
impl_bytes: uint,
misc_bytes: uint,
item_bytes: uint,
index_bytes: uint,
@ -511,8 +513,12 @@ fn encode_reexports(ecx: &EncodeContext,
Some(ref exports) => {
debug!("(encoding info for module) found reexports for %d", id);
for exp in exports.iter() {
debug!("(encoding info for module) reexport '%s' for %d",
exp.name, id);
debug!("(encoding info for module) reexport '%s' (%d/%d) for \
%d",
exp.name,
exp.def_id.crate,
exp.def_id.node,
id);
ebml_w.start_tag(tag_items_data_item_reexport);
ebml_w.start_tag(tag_items_data_item_reexport_def_id);
ebml_w.wr_str(def_to_str(exp.def_id));
@ -635,15 +641,8 @@ fn encode_explicit_self(ebml_w: &mut writer::Encoder, explicit_self: ast::explic
fn encode_mutability(ebml_w: &writer::Encoder,
m: ast::mutability) {
match m {
m_imm => {
ebml_w.writer.write(&[ 'i' as u8 ]);
}
m_mutbl => {
ebml_w.writer.write(&[ 'm' as u8 ]);
}
m_const => {
ebml_w.writer.write(&[ 'c' as u8 ]);
}
m_imm => ebml_w.writer.write(&[ 'i' as u8 ]),
m_mutbl => ebml_w.writer.write(&[ 'm' as u8 ]),
}
}
}
@ -804,6 +803,38 @@ fn should_inline(attrs: &[Attribute]) -> bool {
}
}
// Encodes the inherent implementations of a structure, enumeration, or trait.
fn encode_inherent_implementations(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
def_id: def_id) {
match ecx.tcx.inherent_impls.find(&def_id) {
None => {}
Some(&implementations) => {
for implementation in implementations.iter() {
ebml_w.start_tag(tag_items_data_item_inherent_impl);
encode_def_id(ebml_w, implementation.did);
ebml_w.end_tag();
}
}
}
}
// Encodes the implementations of a trait defined in this crate.
fn encode_extension_implementations(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
trait_def_id: def_id) {
match ecx.tcx.trait_impls.find(&trait_def_id) {
None => {}
Some(&implementations) => {
for implementation in implementations.iter() {
ebml_w.start_tag(tag_items_data_item_extension_impl);
encode_def_id(ebml_w, implementation.did);
ebml_w.end_tag();
}
}
}
}
fn encode_info_for_item(ecx: &EncodeContext,
ebml_w: &mut writer::Encoder,
item: @item,
@ -907,6 +938,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
(ecx.encode_inlined_item)(ecx, ebml_w, path, ii_item(item));
encode_path(ecx, ebml_w, path, ast_map::path_name(item.ident));
encode_region_param(ecx, ebml_w, item);
// Encode inherent implementations for this enumeration.
encode_inherent_implementations(ecx, ebml_w, def_id);
ebml_w.end_tag();
encode_enum_variant_info(ecx,
@ -959,6 +994,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
}
}
// Encode inherent implementations for this structure.
encode_inherent_implementations(ecx, ebml_w, def_id);
/* Each class has its own index -- encode it */
let bkts = create_index(idx);
encode_index(ebml_w, bkts, write_i64);
@ -995,7 +1033,8 @@ fn encode_info_for_item(ecx: &EncodeContext,
encode_name(ecx, ebml_w, item.ident);
encode_attributes(ebml_w, item.attrs);
match ty.node {
ast::ty_path(ref path, ref bounds, _) if path.idents.len() == 1 => {
ast::ty_path(ref path, ref bounds, _) if path.segments
.len() == 1 => {
assert!(bounds.is_none());
encode_impl_type_basename(ecx, ebml_w,
ast_util::path_to_ident(path));
@ -1073,6 +1112,10 @@ fn encode_info_for_item(ecx: &EncodeContext,
let trait_ref = ty::node_id_to_trait_ref(ecx.tcx, ast_trait_ref.ref_id);
encode_trait_ref(ebml_w, ecx, trait_ref, tag_item_super_trait_ref);
}
// Encode the implementations of this trait.
encode_extension_implementations(ecx, ebml_w, def_id);
ebml_w.end_tag();
// Now output the method info for each method.
@ -1134,6 +1177,9 @@ fn encode_info_for_item(ecx: &EncodeContext,
ebml_w.end_tag();
}
// Encode inherent implementations for this trait.
encode_inherent_implementations(ecx, ebml_w, def_id);
}
item_mac(*) => fail!("item macros unimplemented")
}
@ -1227,7 +1273,10 @@ struct EncodeVisitor {
}
impl visit::Visitor<()> for EncodeVisitor {
fn visit_expr(&mut self, ex:@expr, _:()) { my_visit_expr(ex); }
fn visit_expr(&mut self, ex:@expr, _:()) {
visit::walk_expr(self, ex, ());
my_visit_expr(ex);
}
fn visit_item(&mut self, i:@item, _:()) {
visit::walk_item(self, i, ());
my_visit_item(i,
@ -1516,6 +1565,60 @@ fn encode_link_args(ecx: &EncodeContext, ebml_w: &mut writer::Encoder) {
ebml_w.end_tag();
}
struct ImplVisitor<'self> {
ecx: &'self EncodeContext<'self>,
ebml_w: &'self mut writer::Encoder,
}
impl<'self> Visitor<()> for ImplVisitor<'self> {
fn visit_item(&mut self, item: @item, _: ()) {
match item.node {
item_impl(_, Some(ref trait_ref), _, _) => {
let def_map = self.ecx.tcx.def_map;
let trait_def = def_map.get_copy(&trait_ref.ref_id);
let def_id = ast_util::def_id_of_def(trait_def);
// Load eagerly if this is an implementation of the Drop trait
// or if the trait is not defined in this crate.
if def_id == self.ecx.tcx.lang_items.drop_trait().unwrap() ||
def_id.crate != LOCAL_CRATE {
self.ebml_w.start_tag(tag_impls_impl);
encode_def_id(self.ebml_w, local_def(item.id));
self.ebml_w.end_tag();
}
}
_ => {}
}
visit::walk_item(self, item, ());
}
}
/// Encodes implementations that are eagerly loaded.
///
/// None of this is necessary in theory; we can load all implementations
/// lazily. However, in two cases the optimizations to lazily load
/// implementations are not yet implemented. These two cases, which require us
/// to load implementations eagerly, are:
///
/// * Destructors (implementations of the Drop trait).
///
/// * Implementations of traits not defined in this crate.
fn encode_impls(ecx: &EncodeContext,
crate: &Crate,
ebml_w: &mut writer::Encoder) {
ebml_w.start_tag(tag_impls);
{
let mut visitor = ImplVisitor {
ecx: ecx,
ebml_w: ebml_w,
};
visit::walk_crate(&mut visitor, crate, ());
}
ebml_w.end_tag();
}
fn encode_misc_info(ecx: &EncodeContext,
crate: &Crate,
ebml_w: &mut writer::Encoder) {
@ -1580,6 +1683,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
dep_bytes: 0,
lang_item_bytes: 0,
link_args_bytes: 0,
impl_bytes: 0,
misc_bytes: 0,
item_bytes: 0,
index_bytes: 0,
@ -1638,6 +1742,11 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
encode_link_args(&ecx, &mut ebml_w);
ecx.stats.link_args_bytes = *wr.pos - i;
// Encode the def IDs of impls, for coherence checking.
i = *wr.pos;
encode_impls(&ecx, crate, &mut ebml_w);
ecx.stats.impl_bytes = *wr.pos - i;
// Encode miscellaneous info.
i = *wr.pos;
encode_misc_info(&ecx, crate, &mut ebml_w);
@ -1670,6 +1779,7 @@ pub fn encode_metadata(parms: EncodeParams, crate: &Crate) -> ~[u8] {
printfln!(" dep bytes: %u", ecx.stats.dep_bytes);
printfln!(" lang item bytes: %u", ecx.stats.lang_item_bytes);
printfln!(" link args bytes: %u", ecx.stats.link_args_bytes);
printfln!(" impl bytes: %u", ecx.stats.impl_bytes);
printfln!(" misc bytes: %u", ecx.stats.misc_bytes);
printfln!(" item bytes: %u", ecx.stats.item_bytes);
printfln!(" index bytes: %u", ecx.stats.index_bytes);

View File

@ -138,12 +138,20 @@ fn parse_path(st: &mut PState) -> @ast::Path {
':' => { next(st); next(st); }
c => {
if c == '(' {
return @ast::Path { span: dummy_sp(),
global: false,
idents: idents,
rp: None,
types: ~[] };
} else { idents.push(parse_ident_(st, is_last)); }
return @ast::Path {
span: dummy_sp(),
global: false,
segments: idents.move_iter().map(|identifier| {
ast::PathSegment {
identifier: identifier,
lifetime: None,
types: opt_vec::Empty,
}
}).collect()
};
} else {
idents.push(parse_ident_(st, is_last));
}
}
}
};
@ -417,7 +425,6 @@ fn parse_ty(st: &mut PState, conv: conv_did) -> ty::t {
fn parse_mutability(st: &mut PState) -> ast::mutability {
match peek(st) {
'm' => { next(st); ast::m_mutbl }
'?' => { next(st); ast::m_const }
_ => { ast::m_imm }
}
}

View File

@ -99,7 +99,6 @@ fn enc_mutability(w: @io::Writer, mt: ast::mutability) {
match mt {
m_imm => (),
m_mutbl => w.write_char('m'),
m_const => w.write_char('?')
}
}

View File

@ -374,9 +374,16 @@ impl tr for ast::def {
fn tr(&self, xcx: @ExtendedDecodeContext) -> ast::def {
match *self {
ast::def_fn(did, p) => ast::def_fn(did.tr(xcx), p),
ast::def_static_method(did, did2_opt, p) => {
ast::def_static_method(did, wrapped_did2, p) => {
ast::def_static_method(did.tr(xcx),
did2_opt.map(|did2| did2.tr(xcx)),
match wrapped_did2 {
ast::FromTrait(did2) => {
ast::FromTrait(did2.tr(xcx))
}
ast::FromImpl(did2) => {
ast::FromImpl(did2.tr(xcx))
}
},
p)
}
ast::def_method(did0, did1) => {

View File

@ -23,12 +23,12 @@ use mc = middle::mem_categorization;
use middle::borrowck::*;
use middle::moves;
use middle::ty;
use syntax::ast::{m_mutbl, m_imm, m_const};
use syntax::ast::{m_imm, m_mutbl};
use syntax::ast;
use syntax::ast_util;
use syntax::codemap::span;
use syntax::visit;
use syntax::visit::Visitor;
use syntax::visit;
use util::ppaux::Repr;
#[deriving(Clone)]
@ -86,6 +86,44 @@ enum MoveError {
}
impl<'self> CheckLoanCtxt<'self> {
fn check_by_move_capture(&self,
closure_id: ast::NodeId,
cap_var: &moves::CaptureVar,
move_path: @LoanPath) {
let move_err = self.analyze_move_out_from(closure_id, move_path);
match move_err {
MoveOk => {}
MoveWhileBorrowed(loan_path, loan_span) => {
self.bccx.span_err(
cap_var.span,
fmt!("cannot move `%s` into closure \
because it is borrowed",
self.bccx.loan_path_to_str(move_path)));
self.bccx.span_note(
loan_span,
fmt!("borrow of `%s` occurs here",
self.bccx.loan_path_to_str(loan_path)));
}
}
}
fn check_captured_variables(&self, closure_id: ast::NodeId, span: span) {
let cap_vars = self.bccx.capture_map.get(&closure_id);
for cap_var in cap_vars.iter() {
let var_id = ast_util::def_id_of_def(cap_var.def).node;
let var_path = @LpVar(var_id);
self.check_if_path_is_moved(closure_id, span,
MovedInCapture, var_path);
match cap_var.mode {
moves::CapRef | moves::CapCopy => {}
moves::CapMove => {
self.check_by_move_capture(closure_id, cap_var, var_path);
}
}
}
return;
}
pub fn tcx(&self) -> ty::ctxt { self.bccx.tcx }
pub fn each_issued_loan(&self,
@ -220,9 +258,9 @@ impl<'self> CheckLoanCtxt<'self> {
// Restrictions that would cause the new loan to be illegal:
let illegal_if = match loan2.mutbl {
m_mutbl => RESTR_ALIAS | RESTR_FREEZE | RESTR_CLAIM,
m_imm => RESTR_ALIAS | RESTR_FREEZE,
m_const => RESTR_ALIAS,
MutableMutability => RESTR_ALIAS | RESTR_FREEZE | RESTR_CLAIM,
ImmutableMutability => RESTR_ALIAS | RESTR_FREEZE,
ConstMutability => RESTR_ALIAS,
};
debug!("illegal_if=%?", illegal_if);
@ -231,7 +269,7 @@ impl<'self> CheckLoanCtxt<'self> {
if restr.loan_path != loan2.loan_path { loop; }
match (new_loan.mutbl, old_loan.mutbl) {
(m_mutbl, m_mutbl) => {
(MutableMutability, MutableMutability) => {
self.bccx.span_err(
new_loan.span,
fmt!("cannot borrow `%s` as mutable \
@ -450,7 +488,6 @@ impl<'self> CheckLoanCtxt<'self> {
mc::cat_deref(_, _, mc::unsafe_ptr(*)) |
mc::cat_static_item(*) |
mc::cat_deref(_, _, mc::gc_ptr(_)) |
mc::cat_deref(_, _, mc::region_ptr(m_const, _)) |
mc::cat_deref(_, _, mc::region_ptr(m_imm, _)) => {
// Aliasability is independent of base cmt
match cmt.freely_aliasable() {
@ -582,7 +619,6 @@ impl<'self> CheckLoanCtxt<'self> {
// Otherwise stop iterating
LpExtend(_, mc::McDeclared, _) |
LpExtend(_, mc::McImmutable, _) |
LpExtend(_, mc::McReadOnly, _) |
LpVar(_) => {
return true;
}
@ -590,8 +626,11 @@ impl<'self> CheckLoanCtxt<'self> {
// Check for a non-const loan of `loan_path`
let cont = do this.each_in_scope_loan(expr.id) |loan| {
if loan.loan_path == loan_path && loan.mutbl != m_const {
this.report_illegal_mutation(expr, full_loan_path, loan);
if loan.loan_path == loan_path &&
loan.mutbl != ConstMutability {
this.report_illegal_mutation(expr,
full_loan_path,
loan);
false
} else {
true
@ -825,3 +864,4 @@ fn check_loans_in_block<'a>(vt: &mut CheckLoanVisitor,
visit::walk_block(vt, blk, this);
this.check_for_conflicting_loans(blk.id);
}

View File

@ -15,7 +15,7 @@
use middle::borrowck::*;
use mc = middle::mem_categorization;
use middle::ty;
use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast::{m_imm, m_mutbl};
use syntax::ast;
use syntax::codemap::span;
use util::ppaux::{note_and_explain_region};
@ -26,7 +26,7 @@ pub fn guarantee_lifetime(bccx: @BorrowckCtxt,
span: span,
cmt: mc::cmt,
loan_region: ty::Region,
loan_mutbl: ast::mutability) {
loan_mutbl: LoanMutability) {
debug!("guarantee_lifetime(cmt=%s, loan_region=%s)",
cmt.repr(bccx.tcx), loan_region.repr(bccx.tcx));
let ctxt = GuaranteeLifetimeContext {bccx: bccx,
@ -54,7 +54,7 @@ struct GuaranteeLifetimeContext {
span: span,
loan_region: ty::Region,
loan_mutbl: ast::mutability,
loan_mutbl: LoanMutability,
cmt_original: mc::cmt
}
@ -235,11 +235,11 @@ impl GuaranteeLifetimeContext {
// we need to dynamically mark it to prevent incompatible
// borrows from happening later.
let opt_dyna = match ptr_mutbl {
m_imm | m_const => None,
m_imm => None,
m_mutbl => {
match self.loan_mutbl {
m_mutbl => Some(DynaMut),
m_imm | m_const => Some(DynaImm)
MutableMutability => Some(DynaMut),
ImmutableMutability | ConstMutability => Some(DynaImm)
}
}
};

View File

@ -26,7 +26,6 @@ use middle::ty;
use util::common::indenter;
use util::ppaux::{Repr};
use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast;
use syntax::ast_util::id_range;
use syntax::codemap::span;
@ -237,7 +236,11 @@ fn gather_loans_in_expr(v: &mut GatherLoanVisitor,
// make sure that the thing we are pointing out stays valid
// for the lifetime `scope_r` of the resulting ptr:
let scope_r = ty_region(tcx, ex.span, ty::expr_ty(tcx, ex));
this.guarantee_valid(ex.id, ex.span, base_cmt, mutbl, scope_r);
this.guarantee_valid(ex.id,
ex.span,
base_cmt,
LoanMutability::from_ast_mutability(mutbl),
scope_r);
visit::walk_expr(v, ex, this);
}
@ -278,7 +281,11 @@ fn gather_loans_in_expr(v: &mut GatherLoanVisitor,
// adjustments).
let scope_r = ty::re_scope(ex.id);
let arg_cmt = this.bccx.cat_expr(arg);
this.guarantee_valid(arg.id, arg.span, arg_cmt, m_imm, scope_r);
this.guarantee_valid(arg.id,
arg.span,
arg_cmt,
ImmutableMutability,
scope_r);
visit::walk_expr(v, ex, this);
}
@ -357,18 +364,22 @@ impl GatherLoanCtxt {
match *autoref {
ty::AutoPtr(r, m) => {
let loan_mutability =
LoanMutability::from_ast_mutability(m);
self.guarantee_valid(expr.id,
expr.span,
cmt,
m,
loan_mutability,
r)
}
ty::AutoBorrowVec(r, m) | ty::AutoBorrowVecRef(r, m) => {
let cmt_index = mcx.cat_index(expr, cmt, autoderefs+1);
let loan_mutability =
LoanMutability::from_ast_mutability(m);
self.guarantee_valid(expr.id,
expr.span,
cmt_index,
m,
loan_mutability,
r)
}
ty::AutoBorrowFn(r) => {
@ -376,15 +387,17 @@ impl GatherLoanCtxt {
self.guarantee_valid(expr.id,
expr.span,
cmt_deref,
m_imm,
ImmutableMutability,
r)
}
ty::AutoBorrowObj(r, m) => {
let cmt_deref = mcx.cat_deref_fn_or_obj(expr, cmt, 0);
let loan_mutability =
LoanMutability::from_ast_mutability(m);
self.guarantee_valid(expr.id,
expr.span,
cmt_deref,
m,
loan_mutability,
r)
}
ty::AutoUnsafe(_) => {}
@ -402,7 +415,7 @@ impl GatherLoanCtxt {
borrow_id: ast::NodeId,
borrow_span: span,
cmt: mc::cmt,
req_mutbl: ast::mutability,
req_mutbl: LoanMutability,
loan_region: ty::Region) {
debug!("guarantee_valid(borrow_id=%?, cmt=%s, \
req_mutbl=%?, loan_region=%?)",
@ -473,7 +486,7 @@ impl GatherLoanCtxt {
let kill_scope = self.compute_kill_scope(loan_scope, loan_path);
debug!("kill_scope = %?", kill_scope);
if req_mutbl == m_mutbl {
if req_mutbl == MutableMutability {
self.mark_loan_path_as_mutated(loan_path);
}
@ -516,7 +529,7 @@ impl GatherLoanCtxt {
// index: all_loans.len(),
// loan_path: loan_path,
// cmt: cmt,
// mutbl: m_const,
// mutbl: ConstMutability,
// gen_scope: borrow_id,
// kill_scope: kill_scope,
// span: borrow_span,
@ -527,29 +540,20 @@ impl GatherLoanCtxt {
fn check_mutability(bccx: @BorrowckCtxt,
borrow_span: span,
cmt: mc::cmt,
req_mutbl: ast::mutability) {
req_mutbl: LoanMutability) {
//! Implements the M-* rules in doc.rs.
match req_mutbl {
m_const => {
ConstMutability => {
// Data of any mutability can be lent as const.
}
m_imm => {
match cmt.mutbl {
mc::McImmutable | mc::McDeclared | mc::McInherited => {
// both imm and mut data can be lent as imm;
// for mutable data, this is a freeze
}
mc::McReadOnly => {
bccx.report(BckError {span: borrow_span,
cmt: cmt,
code: err_mutbl(req_mutbl)});
}
}
ImmutableMutability => {
// both imm and mut data can be lent as imm;
// for mutable data, this is a freeze
}
m_mutbl => {
MutableMutability => {
// Only mutable data can be lent as mutable.
if !cmt.mutbl.is_mutable() {
bccx.report(BckError {span: borrow_span,
@ -561,12 +565,14 @@ impl GatherLoanCtxt {
}
}
pub fn restriction_set(&self, req_mutbl: ast::mutability)
pub fn restriction_set(&self, req_mutbl: LoanMutability)
-> RestrictionSet {
match req_mutbl {
m_const => RESTR_EMPTY,
m_imm => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM,
m_mutbl => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE
ConstMutability => RESTR_EMPTY,
ImmutableMutability => RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM,
MutableMutability => {
RESTR_EMPTY | RESTR_MUTATE | RESTR_CLAIM | RESTR_FREEZE
}
}
}
@ -582,8 +588,8 @@ impl GatherLoanCtxt {
self.mark_loan_path_as_mutated(base);
}
LpExtend(_, mc::McDeclared, _) |
LpExtend(_, mc::McImmutable, _) |
LpExtend(_, mc::McReadOnly, _) => {
LpExtend(_, mc::McImmutable, _) => {
// Nothing to do.
}
}
}
@ -701,8 +707,13 @@ impl GatherLoanCtxt {
}
}
};
self.guarantee_valid(pat.id, pat.span,
cmt_discr, mutbl, scope_r);
let loan_mutability =
LoanMutability::from_ast_mutability(mutbl);
self.guarantee_valid(pat.id,
pat.span,
cmt_discr,
loan_mutability,
scope_r);
}
ast::bind_infer => {
// No borrows here, but there may be moves
@ -725,6 +736,8 @@ impl GatherLoanCtxt {
self.vec_slice_info(slice_pat, slice_ty);
let mcx = self.bccx.mc_ctxt();
let cmt_index = mcx.cat_index(slice_pat, cmt, 0);
let slice_loan_mutability =
LoanMutability::from_ast_mutability(slice_mutbl);
// Note: We declare here that the borrow occurs upon
// entering the `[...]` pattern. This implies that
@ -743,8 +756,11 @@ impl GatherLoanCtxt {
// trans do the right thing, and it would only work
// for `~` vectors. It seems simpler to just require
// that people call `vec.pop()` or `vec.unshift()`.
self.guarantee_valid(pat.id, pat.span,
cmt_index, slice_mutbl, slice_r);
self.guarantee_valid(pat.id,
pat.span,
cmt_index,
slice_loan_mutability,
slice_r);
}
_ => {}

View File

@ -15,7 +15,7 @@ use std::vec;
use middle::borrowck::*;
use mc = middle::mem_categorization;
use middle::ty;
use syntax::ast::{m_const, m_imm, m_mutbl};
use syntax::ast::{m_imm, m_mutbl};
use syntax::codemap::span;
pub enum RestrictionResult {
@ -121,13 +121,6 @@ impl RestrictionsContext {
Safe
}
mc::cat_deref(_, _, mc::region_ptr(m_const, _)) |
mc::cat_deref(_, _, mc::gc_ptr(m_const)) => {
// R-Deref-Freeze-Borrowed
self.check_no_mutability_control(cmt, restrictions);
Safe
}
mc::cat_deref(cmt_base, _, pk @ mc::gc_ptr(m_mutbl)) => {
// R-Deref-Managed-Borrowed
//

View File

@ -241,12 +241,39 @@ pub enum PartialTotal {
///////////////////////////////////////////////////////////////////////////
// Loans and loan paths
#[deriving(Clone, Eq)]
pub enum LoanMutability {
ImmutableMutability,
ConstMutability,
MutableMutability,
}
impl LoanMutability {
pub fn from_ast_mutability(ast_mutability: ast::mutability)
-> LoanMutability {
match ast_mutability {
ast::m_imm => ImmutableMutability,
ast::m_mutbl => MutableMutability,
}
}
}
impl ToStr for LoanMutability {
fn to_str(&self) -> ~str {
match *self {
ImmutableMutability => ~"immutable",
ConstMutability => ~"read-only",
MutableMutability => ~"mutable",
}
}
}
/// Record of a loan that was issued.
pub struct Loan {
index: uint,
loan_path: @LoanPath,
cmt: mc::cmt,
mutbl: ast::mutability,
mutbl: LoanMutability,
restrictions: ~[Restriction],
gen_scope: ast::NodeId,
kill_scope: ast::NodeId,
@ -417,7 +444,7 @@ impl ToStr for DynaFreezeKind {
// Errors that can occur
#[deriving(Eq)]
pub enum bckerr_code {
err_mutbl(ast::mutability),
err_mutbl(LoanMutability),
err_out_of_root_scope(ty::Region, ty::Region), // superscope, subscope
err_out_of_scope(ty::Region, ty::Region), // superscope, subscope
err_freeze_aliasable_const
@ -794,17 +821,14 @@ impl BorrowckCtxt {
mc.cmt_to_str(cmt)
}
pub fn mut_to_str(&self, mutbl: ast::mutability) -> ~str {
let mc = &mc::mem_categorization_ctxt {tcx: self.tcx,
method_map: self.method_map};
mc.mut_to_str(mutbl)
pub fn mut_to_str(&self, mutbl: LoanMutability) -> ~str {
mutbl.to_str()
}
pub fn mut_to_keyword(&self, mutbl: ast::mutability) -> &'static str {
match mutbl {
ast::m_imm => "",
ast::m_const => "const",
ast::m_mutbl => "mut"
ast::m_mutbl => "mut",
}
}
}

View File

@ -141,7 +141,7 @@ pub fn check_expr(v: &mut CheckCrateVisitor,
// to handle on-demand instantiation of functions via
// foo::<bar> in a const. Currently that is only done on
// a path in trans::callee that only works in block contexts.
if pth.types.len() != 0 {
if !pth.segments.iter().all(|segment| segment.types.is_empty()) {
sess.span_err(
e.span, "paths in constants may only refer to \
items without type parameters");

View File

@ -52,7 +52,7 @@ use middle::typeck;
use util::ppaux::{ty_to_str, region_ptr_to_str, Repr};
use util::common::indenter;
use syntax::ast::{m_imm, m_const, m_mutbl};
use syntax::ast::{m_imm, m_mutbl};
use syntax::ast;
use syntax::codemap::span;
use syntax::print::pprust;
@ -113,7 +113,6 @@ pub enum ElementKind {
#[deriving(Eq, IterBytes)]
pub enum MutabilityCategory {
McImmutable, // Immutable.
McReadOnly, // Read-only (`const`)
McDeclared, // Directly declared as mutable.
McInherited // Inherited from the fact that owner is mutable.
}
@ -297,7 +296,6 @@ impl MutabilityCategory {
pub fn from_mutbl(m: ast::mutability) -> MutabilityCategory {
match m {
m_imm => McImmutable,
m_const => McReadOnly,
m_mutbl => McDeclared
}
}
@ -305,7 +303,6 @@ impl MutabilityCategory {
pub fn inherit(&self) -> MutabilityCategory {
match *self {
McImmutable => McImmutable,
McReadOnly => McReadOnly,
McDeclared => McInherited,
McInherited => McInherited
}
@ -313,7 +310,7 @@ impl MutabilityCategory {
pub fn is_mutable(&self) -> bool {
match *self {
McImmutable | McReadOnly => false,
McImmutable => false,
McDeclared | McInherited => true
}
}
@ -321,7 +318,7 @@ impl MutabilityCategory {
pub fn is_immutable(&self) -> bool {
match *self {
McImmutable => true,
McReadOnly | McDeclared | McInherited => false
McDeclared | McInherited => false
}
}
@ -329,7 +326,6 @@ impl MutabilityCategory {
match *self {
McDeclared | McInherited => "mutable",
McImmutable => "immutable",
McReadOnly => "const"
}
}
}
@ -610,7 +606,6 @@ impl mem_categorization_ctxt {
-> MutabilityCategory {
match interior_m {
m_imm => base_m.inherit(),
m_const => McReadOnly,
m_mutbl => McDeclared
}
}
@ -999,7 +994,6 @@ impl mem_categorization_ctxt {
pub fn mut_to_str(&self, mutbl: ast::mutability) -> ~str {
match mutbl {
m_mutbl => ~"mutable",
m_const => ~"const",
m_imm => ~"immutable"
}
}
@ -1164,7 +1158,6 @@ impl cmt_ {
Some(AliasableManaged(m))
}
cat_deref(_, _, region_ptr(m @ m_const, _)) |
cat_deref(_, _, region_ptr(m @ m_imm, _)) => {
Some(AliasableBorrowed(m))
}

View File

@ -8,9 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// A pass that checks to make sure private fields and methods aren't used
// outside their scopes.
//! A pass that checks to make sure private fields and methods aren't used
//! outside their scopes.
use metadata::csearch;
use middle::ty::{ty_struct, ty_enum};
@ -226,7 +225,7 @@ impl PrivacyVisitor {
if method_id.crate == LOCAL_CRATE {
let is_private = self.method_is_private(span, method_id.node);
let container_id = ty::method(self.tcx, method_id).container_id;
let container_id = ty::method(self.tcx, method_id).container_id();
if is_private &&
(container_id.crate != LOCAL_CRATE ||
!self.privileged_items.iter().any(|x| x == &(container_id.node))) {
@ -251,7 +250,9 @@ impl PrivacyVisitor {
match def {
def_static_method(method_id, _, _) => {
debug!("found static method def, checking it");
self.check_method_common(span, method_id, path.idents.last())
self.check_method_common(span,
method_id,
&path.segments.last().identifier)
}
def_fn(def_id, _) => {
if def_id.crate == LOCAL_CRATE {
@ -259,13 +260,19 @@ impl PrivacyVisitor {
!self.privileged_items.iter().any(|x| x == &def_id.node) {
self.tcx.sess.span_err(span,
fmt!("function `%s` is private",
token::ident_to_str(path.idents.last())));
token::ident_to_str(
&path.segments
.last()
.identifier)));
}
} else if csearch::get_item_visibility(self.tcx.sess.cstore,
def_id) != public {
self.tcx.sess.span_err(span,
fmt!("function `%s` is private",
token::ident_to_str(path.idents.last())));
token::ident_to_str(
&path.segments
.last()
.identifier)));
}
}
_ => {}

View File

@ -827,7 +827,7 @@ fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
Some(&ast::def_trait(did)) |
Some(&ast::def_struct(did)) => {
if did.crate == ast::LOCAL_CRATE {
if cx.region_is_relevant(&path.rp) {
if cx.region_is_relevant(&path.segments.last().lifetime) {
cx.add_dep(did.node);
}
} else {
@ -837,7 +837,7 @@ fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
Some(variance) => {
debug!("reference to external, rp'd type %s",
pprust::ty_to_str(ty, sess.intr()));
if cx.region_is_relevant(&path.rp) {
if cx.region_is_relevant(&path.segments.last().lifetime) {
let rv = cx.add_variance(variance);
cx.add_rp(cx.item_id, rv)
}
@ -860,7 +860,7 @@ fn determine_rp_in_ty(visitor: &mut DetermineRpVisitor,
ast::ty_path(ref path, _, _) => {
// type parameters are---for now, anyway---always invariant
do cx.with_ambient_variance(rv_invariant) {
for tp in path.types.iter() {
for tp in path.segments.iter().flat_map(|s| s.types.iter()) {
visitor.visit_ty(tp, cx);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -117,10 +117,13 @@ pub fn trans(bcx: @mut Block, expr: @ast::expr) -> Callee {
fn trans_def(bcx: @mut Block, def: ast::def, ref_expr: @ast::expr) -> Callee {
match def {
ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
ast::def_fn(did, _) |
ast::def_static_method(did, ast::FromImpl(_), _) => {
fn_callee(bcx, trans_fn_ref(bcx, did, ref_expr.id))
}
ast::def_static_method(impl_did, Some(trait_did), _) => {
ast::def_static_method(impl_did,
ast::FromTrait(trait_did),
_) => {
fn_callee(bcx, meth::trans_static_method_callee(bcx, impl_did,
trait_did,
ref_expr.id))
@ -280,6 +283,14 @@ pub fn trans_fn_ref_with_vtables(
self_ty: None,
tps: /*bad*/ type_params.to_owned() };
// Load the info for the appropriate trait if necessary.
match ty::trait_of_method(tcx, def_id) {
None => {}
Some(trait_id) => {
ty::populate_implementations_for_trait_if_necessary(tcx, trait_id)
}
}
// We need to do a bunch of special handling for default methods.
// We need to modify the def_id and our substs in order to monomorphize
// the function.
@ -300,7 +311,7 @@ pub fn trans_fn_ref_with_vtables(
// So, what we need to do is find this substitution and
// compose it with the one we already have.
let impl_id = ty::method(tcx, def_id).container_id;
let impl_id = ty::method(tcx, def_id).container_id();
let method = ty::method(tcx, source_id);
let trait_ref = ty::impl_trait_ref(tcx, impl_id)
.expect("could not find trait_ref for impl with \

View File

@ -559,7 +559,9 @@ fn const_expr_unadjusted(cx: @mut CrateContext, e: &ast::expr) -> ValueRef {
v
}
ast::expr_path(ref pth) => {
assert_eq!(pth.types.len(), 0);
// Assert that there are no type parameters in this path.
assert!(pth.segments.iter().all(|seg| seg.types.is_empty()));
let tcx = cx.tcx;
match tcx.def_map.find(&e.id) {
Some(&ast::def_fn(def_id, _purity)) => {

View File

@ -825,11 +825,13 @@ fn trans_def_datum_unadjusted(bcx: @mut Block,
let _icx = push_ctxt("trans_def_datum_unadjusted");
let fn_data = match def {
ast::def_fn(did, _) | ast::def_static_method(did, None, _) => {
ast::def_fn(did, _) |
ast::def_static_method(did, ast::FromImpl(_), _) => {
callee::trans_fn_ref(bcx, did, ref_expr.id)
}
ast::def_static_method(impl_did, Some(trait_did), _) => {
meth::trans_static_method_callee(bcx, impl_did,
ast::def_static_method(impl_did, ast::FromTrait(trait_did), _) => {
meth::trans_static_method_callee(bcx,
impl_did,
trait_did,
ref_expr.id)
}

View File

@ -176,6 +176,10 @@ pub fn trans_method_callee(bcx: @mut Block,
}) => {
match bcx.fcx.param_substs {
Some(substs) => {
ty::populate_implementations_for_trait_if_necessary(
bcx.tcx(),
trait_id);
let vtbl = find_vtable(bcx.tcx(), substs,
p, b);
trans_monomorphized_callee(bcx, callee_id, this, mentry,
@ -210,6 +214,8 @@ pub fn trans_static_method_callee(bcx: @mut Block,
callee_id);
let _indenter = indenter();
ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trait_id);
// When we translate a static fn defined in a trait like:
//
// trait<T1...Tn> Trait {
@ -575,6 +581,8 @@ fn emit_vtable_methods(bcx: @mut Block,
make a vtable for a type impl!")
};
ty::populate_implementations_for_trait_if_necessary(bcx.tcx(), trt_id);
let trait_method_def_ids = ty::trait_method_def_ids(tcx, trt_id);
do trait_method_def_ids.map |method_def_id| {
let ident = ty::method(tcx, *method_def_id).ident;

View File

@ -60,6 +60,12 @@ pub struct field {
mt: mt
}
#[deriving(Clone)]
pub enum MethodContainer {
TraitContainer(ast::def_id),
ImplContainer(ast::def_id),
}
#[deriving(Clone)]
pub struct Method {
ident: ast::ident,
@ -69,7 +75,7 @@ pub struct Method {
explicit_self: ast::explicit_self_,
vis: ast::visibility,
def_id: ast::def_id,
container_id: ast::def_id,
container: MethodContainer,
// If this method is provided, we need to know where it came from
provided_source: Option<ast::def_id>
@ -83,7 +89,7 @@ impl Method {
explicit_self: ast::explicit_self_,
vis: ast::visibility,
def_id: ast::def_id,
container_id: ast::def_id,
container: MethodContainer,
provided_source: Option<ast::def_id>)
-> Method {
// Check the invariants.
@ -101,10 +107,17 @@ impl Method {
explicit_self: explicit_self,
vis: vis,
def_id: def_id,
container_id: container_id,
container: container,
provided_source: provided_source
}
}
pub fn container_id(&self) -> ast::def_id {
match self.container {
TraitContainer(id) => id,
ImplContainer(id) => id,
}
}
}
pub struct Impl {
@ -324,7 +337,15 @@ struct ctxt_ {
used_mut_nodes: @mut HashSet<ast::NodeId>,
// vtable resolution information for impl declarations
impl_vtables: typeck::impl_vtable_map
impl_vtables: typeck::impl_vtable_map,
// The set of external nominal types whose implementations have been read.
// This is used for lazy resolution of methods.
populated_external_types: @mut HashSet<ast::def_id>,
// The set of external traits whose implementations have been read. This
// is used for lazy resolution of traits.
populated_external_traits: @mut HashSet<ast::def_id>,
}
pub enum tbox_flag {
@ -938,6 +959,8 @@ pub fn mk_ctxt(s: session::Session,
used_unsafe: @mut HashSet::new(),
used_mut_nodes: @mut HashSet::new(),
impl_vtables: @mut HashMap::new(),
populated_external_types: @mut HashSet::new(),
populated_external_traits: @mut HashSet::new(),
}
}
@ -3612,8 +3635,7 @@ pub fn def_has_ty_params(def: ast::def) -> bool {
}
}
pub fn provided_source(cx: ctxt, id: ast::def_id)
-> Option<ast::def_id> {
pub fn provided_source(cx: ctxt, id: ast::def_id) -> Option<ast::def_id> {
cx.provided_method_sources.find(&id).map_move(|x| *x)
}
@ -4553,3 +4575,135 @@ pub fn visitor_object_ty(tcx: ctxt,
ast::m_imm,
EmptyBuiltinBounds())))
}
/// Records a trait-to-implementation mapping.
fn record_trait_implementation(tcx: ctxt,
trait_def_id: def_id,
implementation: @Impl) {
let implementation_list;
match tcx.trait_impls.find(&trait_def_id) {
None => {
implementation_list = @mut ~[];
tcx.trait_impls.insert(trait_def_id, implementation_list);
}
Some(&existing_implementation_list) => {
implementation_list = existing_implementation_list
}
}
implementation_list.push(implementation);
}
/// Populates the type context with all the implementations for the given type
/// if necessary.
pub fn populate_implementations_for_type_if_necessary(tcx: ctxt,
type_id: ast::def_id) {
if type_id.crate == LOCAL_CRATE {
return
}
if tcx.populated_external_types.contains(&type_id) {
return
}
do csearch::each_implementation_for_type(tcx.sess.cstore, type_id)
|implementation_def_id| {
let implementation = @csearch::get_impl(tcx, implementation_def_id);
// Record the trait->implementation mappings, if applicable.
let associated_traits = csearch::get_impl_trait(tcx,
implementation.did);
for trait_ref in associated_traits.iter() {
record_trait_implementation(tcx,
trait_ref.def_id,
implementation);
}
// For any methods that use a default implementation, add them to
// the map. This is a bit unfortunate.
for method in implementation.methods.iter() {
for source in method.provided_source.iter() {
tcx.provided_method_sources.insert(method.def_id, *source);
}
}
// If this is an inherent implementation, record it.
if associated_traits.is_none() {
let implementation_list;
match tcx.inherent_impls.find(&type_id) {
None => {
implementation_list = @mut ~[];
tcx.inherent_impls.insert(type_id, implementation_list);
}
Some(&existing_implementation_list) => {
implementation_list = existing_implementation_list;
}
}
implementation_list.push(implementation);
}
// Store the implementation info.
tcx.impls.insert(implementation_def_id, implementation);
}
tcx.populated_external_types.insert(type_id);
}
/// Populates the type context with all the implementations for the given
/// trait if necessary.
pub fn populate_implementations_for_trait_if_necessary(
tcx: ctxt,
trait_id: ast::def_id) {
if trait_id.crate == LOCAL_CRATE {
return
}
if tcx.populated_external_traits.contains(&trait_id) {
return
}
do csearch::each_implementation_for_trait(tcx.sess.cstore, trait_id)
|implementation_def_id| {
let implementation = @csearch::get_impl(tcx, implementation_def_id);
// Record the trait->implementation mapping.
record_trait_implementation(tcx, trait_id, implementation);
// For any methods that use a default implementation, add them to
// the map. This is a bit unfortunate.
for method in implementation.methods.iter() {
for source in method.provided_source.iter() {
tcx.provided_method_sources.insert(method.def_id, *source);
}
}
// Store the implementation info.
tcx.impls.insert(implementation_def_id, implementation);
}
tcx.populated_external_traits.insert(trait_id);
}
/// If the given def ID describes a trait method, returns the ID of the trait
/// that the method belongs to. Otherwise, returns `None`.
pub fn trait_of_method(tcx: ctxt, def_id: ast::def_id)
-> Option<ast::def_id> {
match tcx.methods.find(&def_id) {
Some(method_descriptor) => {
match method_descriptor.container {
TraitContainer(id) => return Some(id),
_ => {}
}
}
None => {}
}
// If the method was in the local crate, then if we got here we know the
// answer is negative.
if def_id.crate == LOCAL_CRATE {
return None
}
let result = csearch::get_trait_of_method(tcx.cstore, def_id, tcx);
result
}

View File

@ -63,7 +63,6 @@ use middle::typeck::rscope::RegionParamNames;
use middle::typeck::lookup_def_tcx;
use std::result;
use std::vec;
use syntax::abi::AbiSet;
use syntax::{ast, ast_util};
use syntax::codemap::span;
@ -150,7 +149,8 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>(
// If the type is parameterized by the this region, then replace this
// region with the current anon region binding (in other words,
// whatever & would get replaced with).
let regions = match (&decl_generics.region_param, &path.rp) {
let regions = match (&decl_generics.region_param,
&path.segments.last().lifetime) {
(&None, &None) => {
opt_vec::Empty
}
@ -169,20 +169,34 @@ fn ast_path_substs<AC:AstConv,RS:region_scope + Clone + 'static>(
}
(&Some(_), &Some(_)) => {
opt_vec::with(
ast_region_to_region(this, rscope, path.span, &path.rp))
ast_region_to_region(this,
rscope,
path.span,
&path.segments.last().lifetime))
}
};
// Convert the type parameters supplied by the user.
if !vec::same_length(*decl_generics.type_param_defs, path.types) {
let supplied_type_parameter_count =
path.segments.iter().flat_map(|s| s.types.iter()).len();
if decl_generics.type_param_defs.len() != supplied_type_parameter_count {
this.tcx().sess.span_fatal(
path.span,
fmt!("wrong number of type arguments: expected %u but found %u",
decl_generics.type_param_defs.len(), path.types.len()));
decl_generics.type_param_defs.len(),
supplied_type_parameter_count));
}
let tps = path.types.map(|a_t| ast_ty_to_ty(this, rscope, a_t));
let tps = path.segments
.iter()
.flat_map(|s| s.types.iter())
.map(|a_t| ast_ty_to_ty(this, rscope, a_t))
.collect();
substs {regions:ty::NonerasedRegions(regions), self_ty:self_ty, tps:tps}
substs {
regions: ty::NonerasedRegions(regions),
self_ty: self_ty,
tps: tps
}
}
pub fn ast_path_to_substs_and_ty<AC:AstConv,
@ -272,8 +286,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Clone + 'static>(
match a_seq_ty.ty.node {
ast::ty_vec(ref mt) => {
let mut mt = ast_mt_to_mt(this, rscope, mt);
if a_seq_ty.mutbl == ast::m_mutbl ||
a_seq_ty.mutbl == ast::m_const {
if a_seq_ty.mutbl == ast::m_mutbl {
mt = ty::mt { ty: mt.ty, mutbl: a_seq_ty.mutbl };
}
return ty::mk_evec(tcx, mt, vst);
@ -326,7 +339,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Clone + 'static>(
path: &ast::Path,
flags: uint) {
if (flags & NO_TPS) != 0u {
if path.types.len() > 0u {
if !path.segments.iter().all(|s| s.types.is_empty()) {
tcx.sess.span_err(
path.span,
"type parameters are not allowed on this type");
@ -334,7 +347,7 @@ pub fn ast_ty_to_ty<AC:AstConv, RS:region_scope + Clone + 'static>(
}
if (flags & NO_REGIONS) != 0u {
if path.rp.is_some() {
if path.segments.last().lifetime.is_some() {
tcx.sess.span_err(
path.span,
"region parameters are not allowed on this type");

View File

@ -128,7 +128,12 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
Some((enm, var)) => {
// Assign the pattern the type of the *enum*, not the variant.
let enum_tpt = ty::lookup_item_type(tcx, enm);
instantiate_path(pcx.fcx, path, enum_tpt, pat.span, pat.id);
instantiate_path(pcx.fcx,
path,
enum_tpt,
v_def,
pat.span,
pat.id);
// check that the type of the value being matched is a subtype
// of the type of the pattern:
@ -185,7 +190,12 @@ pub fn check_pat_variant(pcx: &pat_ctxt, pat: @ast::pat, path: &ast::Path,
} else {
ctor_tpt
};
instantiate_path(pcx.fcx, path, struct_tpt, pat.span, pat.id);
instantiate_path(pcx.fcx,
path,
struct_tpt,
s_def,
pat.span,
pat.id);
// Check that the type of the value being matched is a subtype of
// the type of the pattern.

View File

@ -102,7 +102,7 @@ use std::vec;
use extra::list::Nil;
use syntax::ast::{def_id, sty_value, sty_region, sty_box};
use syntax::ast::{sty_uniq, sty_static, NodeId};
use syntax::ast::{m_const, m_mutbl, m_imm};
use syntax::ast::{m_mutbl, m_imm};
use syntax::ast;
use syntax::ast_map;
@ -350,6 +350,10 @@ impl<'self> LookupContext<'self> {
let opt_applicable_traits = trait_map.find(&self.expr.id);
for applicable_traits in opt_applicable_traits.iter() {
for trait_did in applicable_traits.iter() {
ty::populate_implementations_for_trait_if_necessary(
self.tcx(),
*trait_did);
// Look for explicit implementations.
let opt_impl_infos = self.tcx().trait_impls.find(trait_did);
for impl_infos in opt_impl_infos.iter() {
@ -534,6 +538,10 @@ impl<'self> LookupContext<'self> {
fn push_inherent_impl_candidates_for_type(&self, did: def_id) {
// Read the inherent implementation candidates for this type from the
// metadata if necessary.
ty::populate_implementations_for_type_if_necessary(self.tcx(), did);
let opt_impl_infos = self.tcx().inherent_impls.find(&did);
for impl_infos in opt_impl_infos.iter() {
for impl_info in impl_infos.iter() {
@ -700,7 +708,7 @@ impl<'self> LookupContext<'self> {
ty_evec(mt, vstore_fixed(_)) => {
// First try to borrow to a slice
let entry = self.search_for_some_kind_of_autorefd_method(
AutoBorrowVec, autoderefs, [m_const, m_imm, m_mutbl],
AutoBorrowVec, autoderefs, [m_imm, m_mutbl],
|m,r| ty::mk_evec(tcx,
ty::mt {ty:mt.ty, mutbl:m},
vstore_slice(r)));
@ -709,7 +717,7 @@ impl<'self> LookupContext<'self> {
// Then try to borrow to a slice *and* borrow a pointer.
self.search_for_some_kind_of_autorefd_method(
AutoBorrowVecRef, autoderefs, [m_const, m_imm, m_mutbl],
AutoBorrowVecRef, autoderefs, [m_imm, m_mutbl],
|m,r| {
let slice_ty = ty::mk_evec(tcx,
ty::mt {ty:mt.ty, mutbl:m},
@ -744,7 +752,7 @@ impl<'self> LookupContext<'self> {
// Coerce ~/@/&Trait instances to &Trait.
self.search_for_some_kind_of_autorefd_method(
AutoBorrowObj, autoderefs, [m_const, m_imm, m_mutbl],
AutoBorrowObj, autoderefs, [m_imm, m_mutbl],
|trt_mut, reg| {
ty::mk_trait(tcx, trt_did, trt_substs.clone(),
RegionTraitStore(reg), trt_mut, b)
@ -779,7 +787,7 @@ impl<'self> LookupContext<'self> {
ty_float(*) | ty_enum(*) | ty_ptr(*) | ty_struct(*) | ty_tup(*) |
ty_estr(*) | ty_evec(*) | ty_trait(*) | ty_closure(*) => {
self.search_for_some_kind_of_autorefd_method(
AutoPtr, autoderefs, [m_const, m_imm, m_mutbl],
AutoPtr, autoderefs, [m_imm, m_mutbl],
|m,r| ty::mk_rptr(tcx, r, ty::mt {ty:self_ty, mutbl:m}))
}
@ -1270,18 +1278,10 @@ impl<'self> LookupContext<'self> {
}
fn mutability_matches(self_mutbl: ast::mutability,
candidate_mutbl: ast::mutability) -> bool {
candidate_mutbl: ast::mutability)
-> bool {
//! True if `self_mutbl <: candidate_mutbl`
match (self_mutbl, candidate_mutbl) {
(_, m_const) => true,
(m_mutbl, m_mutbl) => true,
(m_imm, m_imm) => true,
(m_mutbl, m_imm) => false,
(m_imm, m_mutbl) => false,
(m_const, m_imm) => false,
(m_const, m_mutbl) => false,
}
self_mutbl == candidate_mutbl
}
}

View File

@ -377,7 +377,7 @@ impl Visitor<()> for GatherLocalsVisitor {
if pat_util::pat_is_binding(self.fcx.ccx.tcx.def_map, p) => {
self.assign(p.id, None);
debug!("Pattern binding %s is assigned to %s",
self.tcx.sess.str_of(path.idents[0]),
self.tcx.sess.str_of(path.segments[0].identifier),
self.fcx.infcx().ty_to_str(
self.fcx.inh.locals.get_copy(&p.id)));
}
@ -1132,8 +1132,160 @@ pub enum DerefArgs {
DoDerefArgs
}
pub fn break_here() {
debug!("break here!");
// Given the provenance of a static method, returns the generics of the static
// method's container.
fn generics_of_static_method_container(type_context: ty::ctxt,
provenance: ast::MethodProvenance)
-> ty::Generics {
match provenance {
ast::FromTrait(trait_def_id) => {
ty::lookup_trait_def(type_context, trait_def_id).generics
}
ast::FromImpl(impl_def_id) => {
ty::lookup_item_type(type_context, impl_def_id).generics
}
}
}
// Verifies that type parameters supplied in paths are in the right
// locations.
fn check_type_parameter_positions_in_path(function_context: @mut FnCtxt,
path: &ast::Path,
def: ast::def) {
// We only care about checking the case in which the path has two or
// more segments.
if path.segments.len() < 2 {
return
}
// Verify that no lifetimes or type parameters are present anywhere
// except the final two elements of the path.
for i in range(0, path.segments.len() - 2) {
match path.segments[i].lifetime {
None => {}
Some(lifetime) => {
function_context.tcx()
.sess
.span_err(lifetime.span,
"lifetime parameters may not \
appear here")
}
}
for typ in path.segments[i].types.iter() {
function_context.tcx()
.sess
.span_err(typ.span,
"type parameters may not appear here")
}
}
// If there are no parameters at all, there is nothing more to do; the
// rest of typechecking will (attempt to) infer everything.
if path.segments
.iter()
.all(|s| s.lifetime.is_none() && s.types.is_empty()) {
return
}
match def {
// If this is a static method of a trait or implementation, then
// ensure that the segment of the path which names the trait or
// implementation (the penultimate segment) is annotated with the
// right number of type parameters.
ast::def_static_method(_, provenance, _) => {
let generics =
generics_of_static_method_container(function_context.ccx.tcx,
provenance);
let name = match provenance {
ast::FromTrait(_) => "trait",
ast::FromImpl(_) => "impl",
};
let trait_segment = &path.segments[path.segments.len() - 2];
// Make sure lifetime parameterization agrees with the trait or
// implementation type.
match (generics.region_param, trait_segment.lifetime) {
(Some(_), None) => {
function_context.tcx()
.sess
.span_err(path.span,
fmt!("this %s has a lifetime \
parameter but no \
lifetime was specified",
name))
}
(None, Some(_)) => {
function_context.tcx()
.sess
.span_err(path.span,
fmt!("this %s has no lifetime \
parameter but a lifetime \
was specified",
name))
}
(Some(_), Some(_)) | (None, None) => {}
}
// Make sure the number of type parameters supplied on the trait
// or implementation segment equals the number of type parameters
// on the trait or implementation definition.
let trait_type_parameter_count = generics.type_param_defs.len();
let supplied_type_parameter_count = trait_segment.types.len();
if trait_type_parameter_count != supplied_type_parameter_count {
let trait_count_suffix = if trait_type_parameter_count == 1 {
""
} else {
"s"
};
let supplied_count_suffix =
if supplied_type_parameter_count == 1 {
""
} else {
"s"
};
function_context.tcx()
.sess
.span_err(path.span,
fmt!("the %s referenced by this \
path has %u type \
parameter%s, but %u type \
parameter%s were supplied",
name,
trait_type_parameter_count,
trait_count_suffix,
supplied_type_parameter_count,
supplied_count_suffix))
}
}
_ => {
// Verify that no lifetimes or type parameters are present on
// the penultimate segment of the path.
let segment = &path.segments[path.segments.len() - 2];
match segment.lifetime {
None => {}
Some(lifetime) => {
function_context.tcx()
.sess
.span_err(lifetime.span,
"lifetime parameters may not
appear here")
}
}
for typ in segment.types.iter() {
function_context.tcx()
.sess
.span_err(typ.span,
"type parameters may not appear \
here");
function_context.tcx()
.sess
.span_note(typ.span,
fmt!("this is a %?", def));
}
}
}
}
/// Invariant:
@ -2333,8 +2485,9 @@ pub fn check_expr_with_unifier(fcx: @mut FnCtxt,
ast::expr_path(ref pth) => {
let defn = lookup_def(fcx, pth.span, id);
check_type_parameter_positions_in_path(fcx, pth, defn);
let tpt = ty_param_bounds_and_ty_for_def(fcx, expr.span, defn);
instantiate_path(fcx, pth, tpt, expr.span, expr.id);
instantiate_path(fcx, pth, tpt, defn, expr.span, expr.id);
}
ast::expr_self => {
let definition = lookup_def(fcx, expr.span, id);
@ -3141,12 +3294,16 @@ pub fn ty_param_bounds_and_ty_for_def(fcx: @mut FnCtxt,
pub fn instantiate_path(fcx: @mut FnCtxt,
pth: &ast::Path,
tpt: ty_param_bounds_and_ty,
def: ast::def,
span: span,
node_id: ast::NodeId) {
debug!(">>> instantiate_path");
let ty_param_count = tpt.generics.type_param_defs.len();
let ty_substs_len = pth.types.len();
let mut ty_substs_len = 0;
for segment in pth.segments.iter() {
ty_substs_len += segment.types.len()
}
debug!("tpt=%s ty_param_count=%? ty_substs_len=%?",
tpt.repr(fcx.tcx()),
@ -3155,7 +3312,7 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
// determine the region bound, using the value given by the user
// (if any) and otherwise using a fresh region variable
let regions = match pth.rp {
let regions = match pth.segments.last().lifetime {
Some(_) => { // user supplied a lifetime parameter...
match tpt.generics.region_param {
None => { // ...but the type is not lifetime parameterized!
@ -3165,7 +3322,10 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
}
Some(_) => { // ...and the type is lifetime parameterized, ok.
opt_vec::with(
ast_region_to_region(fcx, fcx, span, &pth.rp))
ast_region_to_region(fcx,
fcx,
span,
&pth.segments.last().lifetime))
}
}
}
@ -3174,6 +3334,21 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
}
};
// Special case: If there is a self parameter, omit it from the list of
// type parameters.
//
// Here we calculate the "user type parameter count", which is the number
// of type parameters actually manifest in the AST. This will differ from
// the internal type parameter count when there are self types involved.
let (user_type_parameter_count, self_parameter_index) = match def {
ast::def_static_method(_, provenance @ ast::FromTrait(_), _) => {
let generics = generics_of_static_method_container(fcx.ccx.tcx,
provenance);
(ty_param_count - 1, Some(generics.type_param_defs.len()))
}
_ => (ty_param_count, None),
};
// determine values for type parameters, using the values given by
// the user (if any) and otherwise using fresh type variables
let tps = if ty_substs_len == 0 {
@ -3182,34 +3357,51 @@ pub fn instantiate_path(fcx: @mut FnCtxt,
fcx.ccx.tcx.sess.span_err
(span, "this item does not take type parameters");
fcx.infcx().next_ty_vars(ty_param_count)
} else if ty_substs_len > ty_param_count {
} else if ty_substs_len > user_type_parameter_count {
fcx.ccx.tcx.sess.span_err
(span,
fmt!("too many type parameters provided: expected %u, found %u",
ty_param_count, ty_substs_len));
user_type_parameter_count, ty_substs_len));
fcx.infcx().next_ty_vars(ty_param_count)
} else if ty_substs_len < ty_param_count {
let is_static_method = match fcx.ccx.tcx.def_map.find(&node_id) {
Some(&ast::def_static_method(*)) => true,
_ => false
};
} else if ty_substs_len < user_type_parameter_count {
fcx.ccx.tcx.sess.span_err
(span,
fmt!("not enough type parameters provided: expected %u, found %u",
ty_param_count, ty_substs_len));
if is_static_method {
fcx.ccx.tcx.sess.span_note
(span, "Static methods have an extra implicit type parameter -- \
did you omit the type parameter for the `Self` type?");
}
user_type_parameter_count, ty_substs_len));
fcx.infcx().next_ty_vars(ty_param_count)
} else {
pth.types.map(|aty| fcx.to_ty(aty))
// Build up the list of type parameters, inserting the self parameter
// at the appropriate position.
let mut result = ~[];
let mut pushed = false;
for (i, ast_type) in pth.segments
.iter()
.flat_map(|segment| segment.types.iter())
.enumerate() {
match self_parameter_index {
Some(index) if index == i => {
result.push(fcx.infcx().next_ty_vars(1)[0]);
pushed = true;
}
_ => {}
}
result.push(fcx.to_ty(ast_type))
}
// If the self parameter goes at the end, insert it there.
if !pushed && self_parameter_index.is_some() {
result.push(fcx.infcx().next_ty_vars(1)[0])
}
assert_eq!(result.len(), ty_param_count)
result
};
let substs = substs {regions: ty::NonerasedRegions(regions),
self_ty: None,
tps: tps };
let substs = substs {
regions: ty::NonerasedRegions(regions),
self_ty: None,
tps: tps
};
fcx.write_ty_substs(node_id, tpt.ty, substs);
debug!("<<<");

View File

@ -136,6 +136,9 @@ fn lookup_vtables_for_param(vcx: &VtableContext,
// ...and here trait_ref is each bound that was declared on A,
// expressed in terms of the type parameters.
ty::populate_implementations_for_trait_if_necessary(tcx,
trait_ref.def_id);
// Substitute the values of the type parameters that may
// appear in the bound.
let trait_ref = substs.map_default(trait_ref, |substs| {
@ -321,6 +324,10 @@ fn search_for_vtable(vcx: &VtableContext,
let mut found = ~[];
let mut impls_seen = HashSet::new();
// Load the implementations from external metadata if necessary.
ty::populate_implementations_for_trait_if_necessary(tcx,
trait_ref.def_id);
// XXX: this is a bad way to do this, since we do
// pointless allocations.
let impls = tcx.trait_impls.find(&trait_ref.def_id)

View File

@ -15,12 +15,11 @@
// each trait in the system to its implementations.
use metadata::csearch::{each_path, get_impl_trait};
use metadata::csearch::{each_impl, get_impl_trait};
use metadata::csearch;
use metadata::cstore::iter_crate_data;
use metadata::decoder::{dl_def, dl_field, dl_impl};
use middle::ty::get;
use middle::ty::{lookup_item_type, subst};
use middle::ty::{ImplContainer, lookup_item_type, subst};
use middle::ty::{substs, t, ty_bool, ty_bot, ty_box, ty_enum, ty_err};
use middle::ty::{ty_estr, ty_evec, ty_float, ty_infer, ty_int, ty_nil};
use middle::ty::{ty_opaque_box, ty_param, ty_param_bounds_and_ty, ty_ptr};
@ -43,13 +42,12 @@ use syntax::ast;
use syntax::ast_map::node_item;
use syntax::ast_map;
use syntax::ast_util::{def_id_of_def, local_def};
use syntax::codemap::{span, dummy_sp};
use syntax::codemap::span;
use syntax::opt_vec;
use syntax::visit;
use syntax::parse;
use util::ppaux::ty_to_str;
use std::hashmap::{HashMap, HashSet};
use std::hashmap::HashSet;
use std::result::Ok;
use std::vec;
@ -150,19 +148,12 @@ pub fn CoherenceChecker(crate_context: @mut CrateCtxt) -> CoherenceChecker {
CoherenceChecker {
crate_context: crate_context,
inference_context: new_infer_ctxt(crate_context.tcx),
base_type_def_ids: @mut HashMap::new(),
}
}
pub struct CoherenceChecker {
crate_context: @mut CrateCtxt,
inference_context: @mut InferCtxt,
// A mapping from implementations to the corresponding base type
// definition ID.
base_type_def_ids: @mut HashMap<def_id,def_id>,
}
struct CoherenceCheckVisitor { cc: CoherenceChecker }
@ -321,9 +312,6 @@ impl CoherenceChecker {
if associated_traits.len() == 0 {
self.add_inherent_impl(base_type_def_id, implementation);
}
self.base_type_def_ids.insert(local_def(item.id),
base_type_def_id);
}
}
@ -680,9 +668,6 @@ impl CoherenceChecker {
let tcx = self.crate_context.tcx;
let implementation = @csearch::get_impl(tcx, impl_def_id);
debug!("coherence: adding impl from external crate: %s",
ty::item_path_str(tcx, implementation.did));
// Make sure we don't visit the same implementation multiple times.
if !impls_seen.insert(implementation.did) {
// Skip this one.
@ -690,25 +675,11 @@ impl CoherenceChecker {
}
// Good. Continue.
let self_type = lookup_item_type(tcx, implementation.did);
let associated_traits = get_impl_trait(tcx,
implementation.did);
let _ = lookup_item_type(tcx, implementation.did);
let associated_traits = get_impl_trait(tcx, implementation.did);
// Do a sanity check to make sure that inherent methods have base
// types.
if associated_traits.is_none() {
match get_base_type_def_id(self.inference_context,
dummy_sp(),
self_type.ty) {
None => {
tcx.sess.bug(fmt!("no base type for external impl with no \
trait: %s (type %s)!",
tcx.sess.str_of(implementation.ident),
ty_to_str(tcx, self_type.ty)));
}
Some(_) => {} // Nothing to do.
}
}
// Do a sanity check.
assert!(associated_traits.is_some());
// Record all the trait methods.
for trait_ref in associated_traits.iter() {
@ -723,25 +694,6 @@ impl CoherenceChecker {
}
}
// Add the implementation to the mapping from implementation to base
// type def ID, if there is a base type for this implementation.
match get_base_type_def_id(self.inference_context,
dummy_sp(),
self_type.ty) {
None => {} // Nothing to do.
Some(base_type_def_id) => {
// inherent methods apply to `impl Type` but not
// `impl Trait for Type`:
if associated_traits.is_none() {
self.add_inherent_impl(base_type_def_id,
implementation);
}
self.base_type_def_ids.insert(implementation.did,
base_type_def_id);
}
}
tcx.impls.insert(implementation.did, implementation);
}
@ -752,15 +704,10 @@ impl CoherenceChecker {
let crate_store = self.crate_context.tcx.sess.cstore;
do iter_crate_data(crate_store) |crate_number, _crate_metadata| {
do each_path(crate_store, crate_number) |_, def_like, _| {
match def_like {
dl_impl(def_id) => {
self.add_external_impl(&mut impls_seen, def_id)
}
dl_def(_) | dl_field => (), // Skip this.
}
true
};
do each_impl(crate_store, crate_number) |def_id| {
assert_eq!(crate_number, def_id.crate);
self.add_external_impl(&mut impls_seen, def_id)
}
}
}
@ -892,7 +839,7 @@ fn subst_receiver_types_in_method_ty(tcx: ty::ctxt,
method.explicit_self,
method.vis,
new_def_id,
impl_id,
ImplContainer(impl_id),
provided_source
)
}

View File

@ -32,7 +32,8 @@ are represented as `ty_param()` instances.
use metadata::csearch;
use middle::ty::{substs, ty_param_bounds_and_ty};
use middle::ty::{ImplContainer, MethodContainer, TraitContainer, substs};
use middle::ty::{ty_param_bounds_and_ty};
use middle::ty;
use middle::subst::Subst;
use middle::typeck::astconv::{AstConv, ty_of_arg};
@ -388,7 +389,7 @@ pub fn ensure_trait_methods(ccx: &CrateCtxt,
// assume public, because this is only invoked on trait methods
ast::public,
local_def(*m_id),
local_def(trait_id),
TraitContainer(local_def(trait_id)),
None
)
}
@ -744,7 +745,7 @@ pub struct ConvertedMethod {
}
pub fn convert_methods(ccx: &CrateCtxt,
container_id: ast::NodeId,
container: MethodContainer,
ms: &[@ast::method],
untransformed_rcvr_ty: ty::t,
rcvr_ty_generics: &ty::Generics,
@ -758,11 +759,14 @@ pub fn convert_methods(ccx: &CrateCtxt,
let m_ty_generics =
ty_generics(ccx, rcvr_ty_generics.region_param, &m.generics,
num_rcvr_ty_params);
let mty =
@ty_of_method(ccx, container_id, *m, rcvr_ty_generics.region_param,
untransformed_rcvr_ty,
rcvr_ast_generics, rcvr_visibility,
&m.generics);
let mty = @ty_of_method(ccx,
container,
*m,
rcvr_ty_generics.region_param,
untransformed_rcvr_ty,
rcvr_ast_generics,
rcvr_visibility,
&m.generics);
let fty = ty::mk_bare_fn(tcx, mty.fty.clone());
tcx.tcache.insert(
local_def(m.id),
@ -785,7 +789,7 @@ pub fn convert_methods(ccx: &CrateCtxt,
}).collect();
fn ty_of_method(ccx: &CrateCtxt,
container_id: ast::NodeId,
container: MethodContainer,
m: &ast::method,
rp: Option<ty::region_variance>,
untransformed_rcvr_ty: ty::t,
@ -817,7 +821,7 @@ pub fn convert_methods(ccx: &CrateCtxt,
m.explicit_self.node,
method_vis,
local_def(m.id),
local_def(container_id),
container,
None
)
}
@ -877,8 +881,12 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
it.vis
};
let cms = convert_methods(ccx, it.id, *ms, selfty,
&i_ty_generics, generics,
let cms = convert_methods(ccx,
ImplContainer(local_def(it.id)),
*ms,
selfty,
&i_ty_generics,
generics,
parent_visibility);
for t in opt_trait_ref.iter() {
// Prevent the builtin kind traits from being manually implemented.
@ -901,9 +909,12 @@ pub fn convert(ccx: &CrateCtxt, it: &ast::item) {
let untransformed_rcvr_ty = ty::mk_self(tcx, local_def(it.id));
let (ty_generics, _) = mk_item_substs(ccx, generics, rp,
Some(untransformed_rcvr_ty));
let _ = convert_methods(ccx, it.id, provided_methods,
let _ = convert_methods(ccx,
TraitContainer(local_def(it.id)),
provided_methods,
untransformed_rcvr_ty,
&ty_generics, generics,
&ty_generics,
generics,
it.vis);
// We need to do this *after* converting methods, since

View File

@ -21,7 +21,7 @@ use middle::typeck::infer::{cres, InferCtxt};
use middle::typeck::infer::{TypeTrace, Subtype};
use middle::typeck::infer::fold_regions_in_sig;
use middle::typeck::isr_alist;
use syntax::ast::{Many, Once, extern_fn, impure_fn, m_const, m_imm, m_mutbl};
use syntax::ast::{Many, Once, extern_fn, impure_fn, m_imm, m_mutbl};
use syntax::ast::{unsafe_fn};
use syntax::ast::{Onceness, purity};
use util::common::{indenter};
@ -52,16 +52,6 @@ impl Combine for Glb {
match (a.mutbl, b.mutbl) {
// If one side or both is mut, then the GLB must use
// the precise type from the mut side.
(m_mutbl, m_const) => {
Sub(**self).tys(a.ty, b.ty).chain(|_t| {
Ok(ty::mt {ty: a.ty, mutbl: m_mutbl})
})
}
(m_const, m_mutbl) => {
Sub(**self).tys(b.ty, a.ty).chain(|_t| {
Ok(ty::mt {ty: b.ty, mutbl: m_mutbl})
})
}
(m_mutbl, m_mutbl) => {
eq_tys(self, a.ty, b.ty).then(|| {
Ok(ty::mt {ty: a.ty, mutbl: m_mutbl})
@ -70,22 +60,12 @@ impl Combine for Glb {
// If one side or both is immutable, we can use the GLB of
// both sides but mutbl must be `m_imm`.
(m_imm, m_const) |
(m_const, m_imm) |
(m_imm, m_imm) => {
self.tys(a.ty, b.ty).chain(|t| {
Ok(ty::mt {ty: t, mutbl: m_imm})
})
}
// If both sides are const, then we can use GLB of both
// sides and mutbl of only `m_const`.
(m_const, m_const) => {
self.tys(a.ty, b.ty).chain(|t| {
Ok(ty::mt {ty: t, mutbl: m_const})
})
}
// There is no mutual subtype of these combinations.
(m_mutbl, m_imm) |
(m_imm, m_mutbl) => {

View File

@ -24,7 +24,7 @@ use middle::typeck::isr_alist;
use util::ppaux::mt_to_str;
use extra::list;
use syntax::ast::{Many, Once, extern_fn, m_const, impure_fn};
use syntax::ast::{Many, Once, extern_fn, impure_fn};
use syntax::ast::{unsafe_fn};
use syntax::ast::{Onceness, purity};
@ -55,14 +55,13 @@ impl Combine for Lub {
mt_to_str(tcx, a),
mt_to_str(tcx, b));
let m = if a.mutbl == b.mutbl {
a.mutbl
} else {
m_const
};
if a.mutbl != b.mutbl {
return Err(ty::terr_mutability)
}
let m = a.mutbl;
match m {
m_imm | m_const => {
m_imm => {
self.tys(a.ty, b.ty).chain(|t| Ok(ty::mt {ty: t, mutbl: m}) )
}
@ -71,11 +70,7 @@ impl Combine for Lub {
eq_tys(self, a.ty, b.ty).then(|| {
Ok(ty::mt {ty: a.ty, mutbl: m})
})
}).chain_err(|_e| {
self.tys(a.ty, b.ty).chain(|t| {
Ok(ty::mt {ty: t, mutbl: m_const})
})
})
}).chain_err(|e| Err(e))
}
}
}

View File

@ -26,7 +26,7 @@ use util::ppaux::bound_region_to_str;
use extra::list::Nil;
use extra::list;
use syntax::ast::{Onceness, m_const, purity};
use syntax::ast::{Onceness, purity};
pub struct Sub(CombineFields); // "subtype", "subregion" etc
@ -67,7 +67,7 @@ impl Combine for Sub {
fn mts(&self, a: &ty::mt, b: &ty::mt) -> cres<ty::mt> {
debug!("mts(%s <: %s)", a.inf_str(self.infcx), b.inf_str(self.infcx));
if a.mutbl != b.mutbl && b.mutbl != m_const {
if a.mutbl != b.mutbl {
return Err(ty::terr_mutability);
}
@ -77,7 +77,7 @@ impl Combine for Sub {
// (i.e., invariant if mut):
eq_tys(self, a.ty, b.ty).then(|| Ok(*a))
}
m_imm | m_const => {
m_imm => {
// Otherwise we can be covariant:
self.tys(a.ty, b.ty).chain(|_t| Ok(*a) )
}

View File

@ -239,7 +239,6 @@ fn mutability_to_str(m: ast::mutability) -> ~str {
match m {
ast::m_mutbl => ~"mut ",
ast::m_imm => ~"",
ast::m_const => ~"const "
}
}

View File

@ -276,7 +276,7 @@ pub mod raw {
use rt::local::Local;
use rt::task::Task;
do Local::borrow::<Task, *()> |task| {
do Local::borrow |task: &mut Task| {
task.heap.realloc(ptr as *libc::c_void, size) as *()
}
}

View File

@ -10,6 +10,7 @@
//! Unsafe casting functions
use ptr::RawPtr;
use sys;
use unstable::intrinsics;
@ -94,13 +95,13 @@ pub unsafe fn transmute_region<'a,'b,T>(ptr: &'a T) -> &'b T {
/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_mut_unsafe<T>(ptr: *const T) -> *mut T {
pub unsafe fn transmute_mut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *mut T {
transmute(ptr)
}
/// Coerce an immutable reference to be mutable.
#[inline]
pub unsafe fn transmute_immut_unsafe<T>(ptr: *const T) -> *T {
pub unsafe fn transmute_immut_unsafe<T,P:RawPtr<T>>(ptr: P) -> *T {
transmute(ptr)
}

View File

@ -100,7 +100,7 @@ fn test_basic() {
#[test]
#[should_fail]
fn test_take_empty() {
let value_cell = Cell::new_empty::<~int>();
let value_cell: Cell<~int> = Cell::new_empty();
value_cell.take();
}

View File

@ -11,7 +11,7 @@
#[doc(hidden)];
use libc::c_void;
use ptr::{mut_null};
use ptr::null;
use unstable::intrinsics::TyDesc;
use unstable::raw;
@ -37,7 +37,7 @@ unsafe fn each_live_alloc(read_next_before: bool,
use rt::local_heap;
let mut box = local_heap::live_allocs();
while box != mut_null() {
while box != null() {
let next_before = (*box).next;
let uniq = (*box).ref_count == managed::RC_MANAGED_UNIQUE;

View File

@ -884,10 +884,17 @@ impl<T> Poly for T {
}
}
// n.b. use 'const' to get an implementation for both '*mut' and '*' at the same
// time.
impl<T> Pointer for *const T {
fn fmt(t: &*const T, f: &mut Formatter) {
impl<T> Pointer for *T {
fn fmt(t: &*T, f: &mut Formatter) {
f.flags |= 1 << (parse::FlagAlternate as uint);
do ::uint::to_str_bytes(*t as uint, 16) |buf| {
f.pad_integral(buf, "0x", true);
}
}
}
impl<T> Pointer for *mut T {
fn fmt(t: &*mut T, f: &mut Formatter) {
f.flags |= 1 << (parse::FlagAlternate as uint);
do ::uint::to_str_bytes(*t as uint, 16) |buf| {
f.pad_integral(buf, "0x", true);
@ -923,8 +930,12 @@ delegate!(float to Float)
delegate!(f32 to Float)
delegate!(f64 to Float)
impl<T> Default for *const T {
fn fmt(me: &*const T, f: &mut Formatter) { Pointer::fmt(me, f) }
impl<T> Default for *T {
fn fmt(me: &*T, f: &mut Formatter) { Pointer::fmt(me, f) }
}
impl<T> Default for *mut T {
fn fmt(me: &*mut T, f: &mut Formatter) { Pointer::fmt(me, f) }
}
// If you expected tests to be here, look instead at the run-pass/ifmt.rs test,

View File

@ -869,21 +869,21 @@ mod test_map {
#[test]
fn test_find_or_insert() {
let mut m = HashMap::new::<int, int>();
let mut m: HashMap<int,int> = HashMap::new();
assert_eq!(*m.find_or_insert(1, 2), 2);
assert_eq!(*m.find_or_insert(1, 3), 2);
}
#[test]
fn test_find_or_insert_with() {
let mut m = HashMap::new::<int, int>();
let mut m: HashMap<int,int> = HashMap::new();
assert_eq!(*m.find_or_insert_with(1, |_| 2), 2);
assert_eq!(*m.find_or_insert_with(1, |_| 3), 2);
}
#[test]
fn test_insert_or_update_with() {
let mut m = HashMap::new::<int, int>();
let mut m: HashMap<int,int> = HashMap::new();
assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 2);
assert_eq!(*m.insert_or_update_with(1, 2, |_,x| *x+=1), 3);
}

View File

@ -660,7 +660,10 @@ pub trait AdditiveIterator<A> {
impl<A: Add<A, A> + Zero, T: Iterator<A>> AdditiveIterator<A> for T {
#[inline]
fn sum(&mut self) -> A { self.fold(Zero::zero::<A>(), |s, x| s + x) }
fn sum(&mut self) -> A {
let zero: A = Zero::zero();
self.fold(zero, |s, x| s + x)
}
}
/// A trait for iterators over elements whose elements can be multiplied
@ -685,7 +688,10 @@ pub trait MultiplicativeIterator<A> {
impl<A: Mul<A, A> + One, T: Iterator<A>> MultiplicativeIterator<A> for T {
#[inline]
fn product(&mut self) -> A { self.fold(One::one::<A>(), |p, x| p * x) }
fn product(&mut self) -> A {
let one: A = One::one();
self.fold(one, |p, x| p * x)
}
}
/// A trait for iterators over elements which can be compared to one another.

View File

@ -59,7 +59,8 @@ fn newsched_log_str(msg: ~str) {
use rt::local::Local;
unsafe {
match Local::try_unsafe_borrow::<Task>() {
let optional_task: Option<*mut Task> = Local::try_unsafe_borrow();
match optional_task {
Some(local) => {
// Use the available logger
(*local).logger.log(Left(msg));

View File

@ -182,7 +182,7 @@ impl ApproxEq<f32> for f32 {
#[inline]
fn approx_eq(&self, other: &f32) -> bool {
self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<f32, f32>())
self.approx_eq_eps(other, &1.0e-6)
}
#[inline]
@ -561,11 +561,14 @@ impl Real for f32 {
/// Converts to degrees, assuming the number is in radians
#[inline]
fn to_degrees(&self) -> f32 { *self * (180.0 / Real::pi::<f32>()) }
fn to_degrees(&self) -> f32 { *self * (180.0f32 / Real::pi()) }
/// Converts to radians, assuming the number is in degrees
#[inline]
fn to_radians(&self) -> f32 { *self * (Real::pi::<f32>() / 180.0) }
fn to_radians(&self) -> f32 {
let value: f32 = Real::pi();
*self * (value / 180.0f32)
}
}
impl Bounded for f32 {
@ -578,10 +581,10 @@ impl Bounded for f32 {
impl Primitive for f32 {
#[inline]
fn bits() -> uint { 32 }
fn bits(_: Option<f32>) -> uint { 32 }
#[inline]
fn bytes() -> uint { Primitive::bits::<f32>() / 8 }
fn bytes(_: Option<f32>) -> uint { Primitive::bits(Some(0f32)) / 8 }
}
impl Float for f32 {
@ -638,25 +641,25 @@ impl Float for f32 {
}
#[inline]
fn mantissa_digits() -> uint { 24 }
fn mantissa_digits(_: Option<f32>) -> uint { 24 }
#[inline]
fn digits() -> uint { 6 }
fn digits(_: Option<f32>) -> uint { 6 }
#[inline]
fn epsilon() -> f32 { 1.19209290e-07 }
#[inline]
fn min_exp() -> int { -125 }
fn min_exp(_: Option<f32>) -> int { -125 }
#[inline]
fn max_exp() -> int { 128 }
fn max_exp(_: Option<f32>) -> int { 128 }
#[inline]
fn min_10_exp() -> int { -37 }
fn min_10_exp(_: Option<f32>) -> int { -37 }
#[inline]
fn max_10_exp() -> int { 38 }
fn max_10_exp(_: Option<f32>) -> int { 38 }
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
#[inline]
@ -949,9 +952,11 @@ mod tests {
assert_eq!(1f32.clamp(&2f32, &4f32), 2f32);
assert_eq!(8f32.clamp(&2f32, &4f32), 4f32);
assert_eq!(3f32.clamp(&2f32, &4f32), 3f32);
assert!(3f32.clamp(&Float::NaN::<f32>(), &4f32).is_NaN());
assert!(3f32.clamp(&2f32, &Float::NaN::<f32>()).is_NaN());
assert!(Float::NaN::<f32>().clamp(&2f32, &4f32).is_NaN());
let nan: f32 = Float::NaN();
assert!(3f32.clamp(&nan, &4f32).is_NaN());
assert!(3f32.clamp(&2f32, &nan).is_NaN());
assert!(nan.clamp(&2f32, &4f32).is_NaN());
}
#[test]
@ -1028,9 +1033,13 @@ mod tests {
fn test_asinh() {
assert_eq!(0.0f32.asinh(), 0.0f32);
assert_eq!((-0.0f32).asinh(), -0.0f32);
assert_eq!(Float::infinity::<f32>().asinh(), Float::infinity::<f32>());
assert_eq!(Float::neg_infinity::<f32>().asinh(), Float::neg_infinity::<f32>());
assert!(Float::NaN::<f32>().asinh().is_NaN());
let inf: f32 = Float::infinity();
let neg_inf: f32 = Float::neg_infinity();
let nan: f32 = Float::NaN();
assert_eq!(inf.asinh(), inf);
assert_eq!(neg_inf.asinh(), neg_inf);
assert!(nan.asinh().is_NaN());
assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32);
assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32);
}
@ -1039,9 +1048,13 @@ mod tests {
fn test_acosh() {
assert_eq!(1.0f32.acosh(), 0.0f32);
assert!(0.999f32.acosh().is_NaN());
assert_eq!(Float::infinity::<f32>().acosh(), Float::infinity::<f32>());
assert!(Float::neg_infinity::<f32>().acosh().is_NaN());
assert!(Float::NaN::<f32>().acosh().is_NaN());
let inf: f32 = Float::infinity();
let neg_inf: f32 = Float::neg_infinity();
let nan: f32 = Float::NaN();
assert_eq!(inf.acosh(), inf);
assert!(neg_inf.acosh().is_NaN());
assert!(nan.acosh().is_NaN());
assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32);
assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32);
}
@ -1050,34 +1063,61 @@ mod tests {
fn test_atanh() {
assert_eq!(0.0f32.atanh(), 0.0f32);
assert_eq!((-0.0f32).atanh(), -0.0f32);
assert_eq!(1.0f32.atanh(), Float::infinity::<f32>());
assert_eq!((-1.0f32).atanh(), Float::neg_infinity::<f32>());
let inf32: f32 = Float::infinity();
let neg_inf32: f32 = Float::neg_infinity();
assert_eq!(1.0f32.atanh(), inf32);
assert_eq!((-1.0f32).atanh(), neg_inf32);
assert!(2f64.atanh().atanh().is_NaN());
assert!((-2f64).atanh().atanh().is_NaN());
assert!(Float::infinity::<f64>().atanh().is_NaN());
assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
assert!(Float::NaN::<f32>().atanh().is_NaN());
let inf64: f32 = Float::infinity();
let neg_inf64: f32 = Float::neg_infinity();
let nan32: f32 = Float::NaN();
assert!(inf64.atanh().is_NaN());
assert!(neg_inf64.atanh().is_NaN());
assert!(nan32.atanh().is_NaN());
assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32);
assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32);
}
#[test]
fn test_real_consts() {
assert_approx_eq!(Real::two_pi::<f32>(), 2f32 * Real::pi::<f32>());
assert_approx_eq!(Real::frac_pi_2::<f32>(), Real::pi::<f32>() / 2f32);
assert_approx_eq!(Real::frac_pi_3::<f32>(), Real::pi::<f32>() / 3f32);
assert_approx_eq!(Real::frac_pi_4::<f32>(), Real::pi::<f32>() / 4f32);
assert_approx_eq!(Real::frac_pi_6::<f32>(), Real::pi::<f32>() / 6f32);
assert_approx_eq!(Real::frac_pi_8::<f32>(), Real::pi::<f32>() / 8f32);
assert_approx_eq!(Real::frac_1_pi::<f32>(), 1f32 / Real::pi::<f32>());
assert_approx_eq!(Real::frac_2_pi::<f32>(), 2f32 / Real::pi::<f32>());
assert_approx_eq!(Real::frac_2_sqrtpi::<f32>(), 2f32 / Real::pi::<f32>().sqrt());
assert_approx_eq!(Real::sqrt2::<f32>(), 2f32.sqrt());
assert_approx_eq!(Real::frac_1_sqrt2::<f32>(), 1f32 / 2f32.sqrt());
assert_approx_eq!(Real::log2_e::<f32>(), Real::e::<f32>().log2());
assert_approx_eq!(Real::log10_e::<f32>(), Real::e::<f32>().log10());
assert_approx_eq!(Real::ln_2::<f32>(), 2f32.ln());
assert_approx_eq!(Real::ln_10::<f32>(), 10f32.ln());
let pi: f32 = Real::pi();
let two_pi: f32 = Real::two_pi();
let frac_pi_2: f32 = Real::frac_pi_2();
let frac_pi_3: f32 = Real::frac_pi_3();
let frac_pi_4: f32 = Real::frac_pi_4();
let frac_pi_6: f32 = Real::frac_pi_6();
let frac_pi_8: f32 = Real::frac_pi_8();
let frac_1_pi: f32 = Real::frac_1_pi();
let frac_2_pi: f32 = Real::frac_2_pi();
let frac_2_sqrtpi: f32 = Real::frac_2_sqrtpi();
let sqrt2: f32 = Real::sqrt2();
let frac_1_sqrt2: f32 = Real::frac_1_sqrt2();
let e: f32 = Real::e();
let log2_e: f32 = Real::log2_e();
let log10_e: f32 = Real::log10_e();
let ln_2: f32 = Real::ln_2();
let ln_10: f32 = Real::ln_10();
assert_approx_eq!(two_pi, 2f32 * pi);
assert_approx_eq!(frac_pi_2, pi / 2f32);
assert_approx_eq!(frac_pi_3, pi / 3f32);
assert_approx_eq!(frac_pi_4, pi / 4f32);
assert_approx_eq!(frac_pi_6, pi / 6f32);
assert_approx_eq!(frac_pi_8, pi / 8f32);
assert_approx_eq!(frac_1_pi, 1f32 / pi);
assert_approx_eq!(frac_2_pi, 2f32 / pi);
assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt());
assert_approx_eq!(sqrt2, 2f32.sqrt());
assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt());
assert_approx_eq!(log2_e, e.log2());
assert_approx_eq!(log10_e, e.log10());
assert_approx_eq!(ln_2, 2f32.ln());
assert_approx_eq!(ln_10, 10f32.ln());
}
#[test]
@ -1153,17 +1193,23 @@ mod tests {
#[test]
fn test_primitive() {
assert_eq!(Primitive::bits::<f32>(), sys::size_of::<f32>() * 8);
assert_eq!(Primitive::bytes::<f32>(), sys::size_of::<f32>());
let none: Option<f32> = None;
assert_eq!(Primitive::bits(none), sys::size_of::<f32>() * 8);
assert_eq!(Primitive::bytes(none), sys::size_of::<f32>());
}
#[test]
fn test_is_normal() {
assert!(!Float::NaN::<f32>().is_normal());
assert!(!Float::infinity::<f32>().is_normal());
assert!(!Float::neg_infinity::<f32>().is_normal());
assert!(!Zero::zero::<f32>().is_normal());
assert!(!Float::neg_zero::<f32>().is_normal());
let nan: f32 = Float::NaN();
let inf: f32 = Float::infinity();
let neg_inf: f32 = Float::neg_infinity();
let zero: f32 = Zero::zero();
let neg_zero: f32 = Float::neg_zero();
assert!(!nan.is_normal());
assert!(!inf.is_normal());
assert!(!neg_inf.is_normal());
assert!(!zero.is_normal());
assert!(!neg_zero.is_normal());
assert!(1f32.is_normal());
assert!(1e-37f32.is_normal());
assert!(!1e-38f32.is_normal());
@ -1171,11 +1217,16 @@ mod tests {
#[test]
fn test_classify() {
assert_eq!(Float::NaN::<f32>().classify(), FPNaN);
assert_eq!(Float::infinity::<f32>().classify(), FPInfinite);
assert_eq!(Float::neg_infinity::<f32>().classify(), FPInfinite);
assert_eq!(Zero::zero::<f32>().classify(), FPZero);
assert_eq!(Float::neg_zero::<f32>().classify(), FPZero);
let nan: f32 = Float::NaN();
let inf: f32 = Float::infinity();
let neg_inf: f32 = Float::neg_infinity();
let zero: f32 = Zero::zero();
let neg_zero: f32 = Float::neg_zero();
assert_eq!(nan.classify(), FPNaN);
assert_eq!(inf.classify(), FPInfinite);
assert_eq!(neg_inf.classify(), FPInfinite);
assert_eq!(zero.classify(), FPZero);
assert_eq!(neg_zero.classify(), FPZero);
assert_eq!(1f32.classify(), FPNormal);
assert_eq!(1e-37f32.classify(), FPNormal);
assert_eq!(1e-38f32.classify(), FPSubnormal);
@ -1192,11 +1243,13 @@ mod tests {
assert_eq!(Float::ldexp(0f32, -123), 0f32);
assert_eq!(Float::ldexp(-0f32, -123), -0f32);
assert_eq!(Float::ldexp(Float::infinity::<f32>(), -123),
Float::infinity::<f32>());
assert_eq!(Float::ldexp(Float::neg_infinity::<f32>(), -123),
Float::neg_infinity::<f32>());
assert!(Float::ldexp(Float::NaN::<f32>(), -123).is_NaN());
let inf: f32 = Float::infinity();
let neg_inf: f32 = Float::neg_infinity();
let nan: f32 = Float::NaN();
assert_eq!(Float::ldexp(inf, -123), inf);
assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
assert!(Float::ldexp(nan, -123).is_NaN());
}
#[test]
@ -1214,10 +1267,12 @@ mod tests {
assert_eq!(0f32.frexp(), (0f32, 0));
assert_eq!((-0f32).frexp(), (-0f32, 0));
assert_eq!(match Float::infinity::<f32>().frexp() { (x, _) => x },
Float::infinity::<f32>())
assert_eq!(match Float::neg_infinity::<f32>().frexp() { (x, _) => x },
Float::neg_infinity::<f32>())
assert!(match Float::NaN::<f32>().frexp() { (x, _) => x.is_NaN() })
let inf: f32 = Float::infinity();
let neg_inf: f32 = Float::neg_infinity();
let nan: f32 = Float::NaN();
assert_eq!(match inf.frexp() { (x, _) => x }, inf)
assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
assert!(match nan.frexp() { (x, _) => x.is_NaN() })
}
}

View File

@ -205,7 +205,7 @@ impl ApproxEq<f64> for f64 {
#[inline]
fn approx_eq(&self, other: &f64) -> bool {
self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<f64, f64>())
self.approx_eq_eps(other, &1.0e-6)
}
#[inline]
@ -578,11 +578,14 @@ impl Real for f64 {
/// Converts to degrees, assuming the number is in radians
#[inline]
fn to_degrees(&self) -> f64 { *self * (180.0 / Real::pi::<f64>()) }
fn to_degrees(&self) -> f64 { *self * (180.0f64 / Real::pi()) }
/// Converts to radians, assuming the number is in degrees
#[inline]
fn to_radians(&self) -> f64 { *self * (Real::pi::<f64>() / 180.0) }
fn to_radians(&self) -> f64 {
let value: f64 = Real::pi();
*self * (value / 180.0)
}
}
impl RealExt for f64 {
@ -625,10 +628,10 @@ impl Bounded for f64 {
impl Primitive for f64 {
#[inline]
fn bits() -> uint { 64 }
fn bits(_: Option<f64>) -> uint { 64 }
#[inline]
fn bytes() -> uint { Primitive::bits::<f64>() / 8 }
fn bytes(_: Option<f64>) -> uint { Primitive::bits(Some(0f64)) / 8 }
}
impl Float for f64 {
@ -685,25 +688,25 @@ impl Float for f64 {
}
#[inline]
fn mantissa_digits() -> uint { 53 }
fn mantissa_digits(_: Option<f64>) -> uint { 53 }
#[inline]
fn digits() -> uint { 15 }
fn digits(_: Option<f64>) -> uint { 15 }
#[inline]
fn epsilon() -> f64 { 2.2204460492503131e-16 }
#[inline]
fn min_exp() -> int { -1021 }
fn min_exp(_: Option<f64>) -> int { -1021 }
#[inline]
fn max_exp() -> int { 1024 }
fn max_exp(_: Option<f64>) -> int { 1024 }
#[inline]
fn min_10_exp() -> int { -307 }
fn min_10_exp(_: Option<f64>) -> int { -307 }
#[inline]
fn max_10_exp() -> int { 308 }
fn max_10_exp(_: Option<f64>) -> int { 308 }
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
#[inline]
@ -983,16 +986,20 @@ mod tests {
fn test_min() {
assert_eq!(1f64.min(&2f64), 1f64);
assert_eq!(2f64.min(&1f64), 1f64);
assert!(1f64.min(&Float::NaN::<f64>()).is_NaN());
assert!(Float::NaN::<f64>().min(&1f64).is_NaN());
let nan: f64 = Float::NaN();
assert!(1f64.min(&nan).is_NaN());
assert!(nan.min(&1f64).is_NaN());
}
#[test]
fn test_max() {
assert_eq!(1f64.max(&2f64), 2f64);
assert_eq!(2f64.max(&1f64), 2f64);
assert!(1f64.max(&Float::NaN::<f64>()).is_NaN());
assert!(Float::NaN::<f64>().max(&1f64).is_NaN());
let nan: f64 = Float::NaN();
assert!(1f64.max(&nan).is_NaN());
assert!(nan.max(&1f64).is_NaN());
}
#[test]
@ -1000,9 +1007,11 @@ mod tests {
assert_eq!(1f64.clamp(&2f64, &4f64), 2f64);
assert_eq!(8f64.clamp(&2f64, &4f64), 4f64);
assert_eq!(3f64.clamp(&2f64, &4f64), 3f64);
assert!(3f64.clamp(&Float::NaN::<f64>(), &4f64).is_NaN());
assert!(3f64.clamp(&2f64, &Float::NaN::<f64>()).is_NaN());
assert!(Float::NaN::<f64>().clamp(&2f64, &4f64).is_NaN());
let nan: f64 = Float::NaN();
assert!(3f64.clamp(&nan, &4f64).is_NaN());
assert!(3f64.clamp(&2f64, &nan).is_NaN());
assert!(nan.clamp(&2f64, &4f64).is_NaN());
}
#[test]
@ -1079,9 +1088,13 @@ mod tests {
fn test_asinh() {
assert_eq!(0.0f64.asinh(), 0.0f64);
assert_eq!((-0.0f64).asinh(), -0.0f64);
assert_eq!(Float::infinity::<f64>().asinh(), Float::infinity::<f64>());
assert_eq!(Float::neg_infinity::<f64>().asinh(), Float::neg_infinity::<f64>());
assert!(Float::NaN::<f64>().asinh().is_NaN());
let inf: f64 = Float::infinity();
let neg_inf: f64 = Float::neg_infinity();
let nan: f64 = Float::NaN();
assert_eq!(inf.asinh(), inf);
assert_eq!(neg_inf.asinh(), neg_inf);
assert!(nan.asinh().is_NaN());
assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64);
assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64);
}
@ -1090,9 +1103,13 @@ mod tests {
fn test_acosh() {
assert_eq!(1.0f64.acosh(), 0.0f64);
assert!(0.999f64.acosh().is_NaN());
assert_eq!(Float::infinity::<f64>().acosh(), Float::infinity::<f64>());
assert!(Float::neg_infinity::<f64>().acosh().is_NaN());
assert!(Float::NaN::<f64>().acosh().is_NaN());
let inf: f64 = Float::infinity();
let neg_inf: f64 = Float::neg_infinity();
let nan: f64 = Float::NaN();
assert_eq!(inf.acosh(), inf);
assert!(neg_inf.acosh().is_NaN());
assert!(nan.acosh().is_NaN());
assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64);
assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64);
}
@ -1101,34 +1118,56 @@ mod tests {
fn test_atanh() {
assert_eq!(0.0f64.atanh(), 0.0f64);
assert_eq!((-0.0f64).atanh(), -0.0f64);
assert_eq!(1.0f64.atanh(), Float::infinity::<f64>());
assert_eq!((-1.0f64).atanh(), Float::neg_infinity::<f64>());
let inf: f64 = Float::infinity();
let neg_inf: f64 = Float::neg_infinity();
let nan: f64 = Float::NaN();
assert_eq!(1.0f64.atanh(), inf);
assert_eq!((-1.0f64).atanh(), neg_inf);
assert!(2f64.atanh().atanh().is_NaN());
assert!((-2f64).atanh().atanh().is_NaN());
assert!(Float::infinity::<f64>().atanh().is_NaN());
assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
assert!(Float::NaN::<f64>().atanh().is_NaN());
assert!(inf.atanh().is_NaN());
assert!(neg_inf.atanh().is_NaN());
assert!(nan.atanh().is_NaN());
assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64);
assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64);
}
#[test]
fn test_real_consts() {
assert_approx_eq!(Real::two_pi::<f64>(), 2.0 * Real::pi::<f64>());
assert_approx_eq!(Real::frac_pi_2::<f64>(), Real::pi::<f64>() / 2f64);
assert_approx_eq!(Real::frac_pi_3::<f64>(), Real::pi::<f64>() / 3f64);
assert_approx_eq!(Real::frac_pi_4::<f64>(), Real::pi::<f64>() / 4f64);
assert_approx_eq!(Real::frac_pi_6::<f64>(), Real::pi::<f64>() / 6f64);
assert_approx_eq!(Real::frac_pi_8::<f64>(), Real::pi::<f64>() / 8f64);
assert_approx_eq!(Real::frac_1_pi::<f64>(), 1f64 / Real::pi::<f64>());
assert_approx_eq!(Real::frac_2_pi::<f64>(), 2f64 / Real::pi::<f64>());
assert_approx_eq!(Real::frac_2_sqrtpi::<f64>(), 2f64 / Real::pi::<f64>().sqrt());
assert_approx_eq!(Real::sqrt2::<f64>(), 2f64.sqrt());
assert_approx_eq!(Real::frac_1_sqrt2::<f64>(), 1f64 / 2f64.sqrt());
assert_approx_eq!(Real::log2_e::<f64>(), Real::e::<f64>().log2());
assert_approx_eq!(Real::log10_e::<f64>(), Real::e::<f64>().log10());
assert_approx_eq!(Real::ln_2::<f64>(), 2f64.ln());
assert_approx_eq!(Real::ln_10::<f64>(), 10f64.ln());
let pi: f64 = Real::pi();
let two_pi: f64 = Real::two_pi();
let frac_pi_2: f64 = Real::frac_pi_2();
let frac_pi_3: f64 = Real::frac_pi_3();
let frac_pi_4: f64 = Real::frac_pi_4();
let frac_pi_6: f64 = Real::frac_pi_6();
let frac_pi_8: f64 = Real::frac_pi_8();
let frac_1_pi: f64 = Real::frac_1_pi();
let frac_2_pi: f64 = Real::frac_2_pi();
let frac_2_sqrtpi: f64 = Real::frac_2_sqrtpi();
let sqrt2: f64 = Real::sqrt2();
let frac_1_sqrt2: f64 = Real::frac_1_sqrt2();
let e: f64 = Real::e();
let log2_e: f64 = Real::log2_e();
let log10_e: f64 = Real::log10_e();
let ln_2: f64 = Real::ln_2();
let ln_10: f64 = Real::ln_10();
assert_approx_eq!(two_pi, 2.0 * pi);
assert_approx_eq!(frac_pi_2, pi / 2f64);
assert_approx_eq!(frac_pi_3, pi / 3f64);
assert_approx_eq!(frac_pi_4, pi / 4f64);
assert_approx_eq!(frac_pi_6, pi / 6f64);
assert_approx_eq!(frac_pi_8, pi / 8f64);
assert_approx_eq!(frac_1_pi, 1f64 / pi);
assert_approx_eq!(frac_2_pi, 2f64 / pi);
assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt());
assert_approx_eq!(sqrt2, 2f64.sqrt());
assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt());
assert_approx_eq!(log2_e, e.log2());
assert_approx_eq!(log10_e, e.log10());
assert_approx_eq!(ln_2, 2f64.ln());
assert_approx_eq!(ln_10, 10f64.ln());
}
#[test]
@ -1204,17 +1243,23 @@ mod tests {
#[test]
fn test_primitive() {
assert_eq!(Primitive::bits::<f64>(), sys::size_of::<f64>() * 8);
assert_eq!(Primitive::bytes::<f64>(), sys::size_of::<f64>());
let none: Option<f64> = None;
assert_eq!(Primitive::bits(none), sys::size_of::<f64>() * 8);
assert_eq!(Primitive::bytes(none), sys::size_of::<f64>());
}
#[test]
fn test_is_normal() {
assert!(!Float::NaN::<f64>().is_normal());
assert!(!Float::infinity::<f64>().is_normal());
assert!(!Float::neg_infinity::<f64>().is_normal());
assert!(!Zero::zero::<f64>().is_normal());
assert!(!Float::neg_zero::<f64>().is_normal());
let nan: f64 = Float::NaN();
let inf: f64 = Float::infinity();
let neg_inf: f64 = Float::neg_infinity();
let zero: f64 = Zero::zero();
let neg_zero: f64 = Float::neg_zero();
assert!(!nan.is_normal());
assert!(!inf.is_normal());
assert!(!neg_inf.is_normal());
assert!(!zero.is_normal());
assert!(!neg_zero.is_normal());
assert!(1f64.is_normal());
assert!(1e-307f64.is_normal());
assert!(!1e-308f64.is_normal());
@ -1222,11 +1267,16 @@ mod tests {
#[test]
fn test_classify() {
assert_eq!(Float::NaN::<f64>().classify(), FPNaN);
assert_eq!(Float::infinity::<f64>().classify(), FPInfinite);
assert_eq!(Float::neg_infinity::<f64>().classify(), FPInfinite);
assert_eq!(Zero::zero::<f64>().classify(), FPZero);
assert_eq!(Float::neg_zero::<f64>().classify(), FPZero);
let nan: f64 = Float::NaN();
let inf: f64 = Float::infinity();
let neg_inf: f64 = Float::neg_infinity();
let zero: f64 = Zero::zero();
let neg_zero: f64 = Float::neg_zero();
assert_eq!(nan.classify(), FPNaN);
assert_eq!(inf.classify(), FPInfinite);
assert_eq!(neg_inf.classify(), FPInfinite);
assert_eq!(zero.classify(), FPZero);
assert_eq!(neg_zero.classify(), FPZero);
assert_eq!(1e-307f64.classify(), FPNormal);
assert_eq!(1e-308f64.classify(), FPSubnormal);
}
@ -1242,11 +1292,13 @@ mod tests {
assert_eq!(Float::ldexp(0f64, -123), 0f64);
assert_eq!(Float::ldexp(-0f64, -123), -0f64);
assert_eq!(Float::ldexp(Float::infinity::<f64>(), -123),
Float::infinity::<f64>());
assert_eq!(Float::ldexp(Float::neg_infinity::<f64>(), -123),
Float::neg_infinity::<f64>());
assert!(Float::ldexp(Float::NaN::<f64>(), -123).is_NaN());
let inf: f64 = Float::infinity();
let neg_inf: f64 = Float::neg_infinity();
let nan: f64 = Float::NaN();
assert_eq!(Float::ldexp(inf, -123), inf);
assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
assert!(Float::ldexp(nan, -123).is_NaN());
}
#[test]
@ -1264,10 +1316,12 @@ mod tests {
assert_eq!(0f64.frexp(), (0f64, 0));
assert_eq!((-0f64).frexp(), (-0f64, 0));
assert_eq!(match Float::infinity::<f64>().frexp() { (x, _) => x },
Float::infinity::<f64>())
assert_eq!(match Float::neg_infinity::<f64>().frexp() { (x, _) => x },
Float::neg_infinity::<f64>())
assert!(match Float::NaN::<f64>().frexp() { (x, _) => x.is_NaN() })
let inf: f64 = Float::infinity();
let neg_inf: f64 = Float::neg_infinity();
let nan: f64 = Float::NaN();
assert_eq!(match inf.frexp() { (x, _) => x }, inf)
assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf)
assert!(match nan.frexp() { (x, _) => x.is_NaN() })
}
}

View File

@ -342,7 +342,7 @@ impl ApproxEq<float> for float {
#[inline]
fn approx_eq(&self, other: &float) -> bool {
self.approx_eq_eps(other, &ApproxEq::approx_epsilon::<float, float>())
self.approx_eq_eps(other, &1.0e-6)
}
#[inline]
@ -783,32 +783,56 @@ impl Signed for float {
impl Bounded for float {
#[inline]
fn min_value() -> float { Bounded::min_value::<f64>() as float }
fn min_value() -> float {
let x: f64 = Bounded::min_value();
x as float
}
#[inline]
fn max_value() -> float { Bounded::max_value::<f64>() as float }
fn max_value() -> float {
let x: f64 = Bounded::max_value();
x as float
}
}
impl Primitive for float {
#[inline]
fn bits() -> uint { Primitive::bits::<f64>() }
fn bits(_: Option<float>) -> uint {
let bits: uint = Primitive::bits(Some(0f64));
bits
}
#[inline]
fn bytes() -> uint { Primitive::bytes::<f64>() }
fn bytes(_: Option<float>) -> uint {
let bytes: uint = Primitive::bytes(Some(0f64));
bytes
}
}
impl Float for float {
#[inline]
fn NaN() -> float { Float::NaN::<f64>() as float }
fn NaN() -> float {
let value: f64 = Float::NaN();
value as float
}
#[inline]
fn infinity() -> float { Float::infinity::<f64>() as float }
fn infinity() -> float {
let value: f64 = Float::infinity();
value as float
}
#[inline]
fn neg_infinity() -> float { Float::neg_infinity::<f64>() as float }
fn neg_infinity() -> float {
let value: f64 = Float::neg_infinity();
value as float
}
#[inline]
fn neg_zero() -> float { Float::neg_zero::<f64>() as float }
fn neg_zero() -> float {
let value: f64 = Float::neg_zero();
value as float
}
/// Returns `true` if the number is NaN
#[inline]
@ -832,30 +856,46 @@ impl Float for float {
fn classify(&self) -> FPCategory { (*self as f64).classify() }
#[inline]
fn mantissa_digits() -> uint { Float::mantissa_digits::<f64>() }
fn mantissa_digits(_: Option<float>) -> uint {
Float::mantissa_digits(Some(0f64))
}
#[inline]
fn digits() -> uint { Float::digits::<f64>() }
fn digits(_: Option<float>) -> uint {
Float::digits(Some(0f64))
}
#[inline]
fn epsilon() -> float { Float::epsilon::<f64>() as float }
fn epsilon() -> float {
let value: f64 = Float::epsilon();
value as float
}
#[inline]
fn min_exp() -> int { Float::min_exp::<f64>() }
fn min_exp(_: Option<float>) -> int {
Float::min_exp(Some(0f64))
}
#[inline]
fn max_exp() -> int { Float::max_exp::<f64>() }
fn max_exp(_: Option<float>) -> int {
Float::max_exp(Some(0f64))
}
#[inline]
fn min_10_exp() -> int { Float::min_10_exp::<f64>() }
fn min_10_exp(_: Option<float>) -> int {
Float::min_10_exp(Some(0f64))
}
#[inline]
fn max_10_exp() -> int { Float::max_10_exp::<f64>() }
fn max_10_exp(_: Option<float>) -> int {
Float::max_10_exp(Some(0f64))
}
/// Constructs a floating point number by multiplying `x` by 2 raised to the power of `exp`
#[inline]
fn ldexp(x: float, exp: int) -> float {
Float::ldexp(x as f64, exp) as float
let value: f64 = Float::ldexp(x as f64, exp);
value as float
}
///
@ -937,9 +977,10 @@ mod tests {
assert_eq!(1f.clamp(&2f, &4f), 2f);
assert_eq!(8f.clamp(&2f, &4f), 4f);
assert_eq!(3f.clamp(&2f, &4f), 3f);
assert!(3f.clamp(&Float::NaN::<float>(), &4f).is_NaN());
assert!(3f.clamp(&2f, &Float::NaN::<float>()).is_NaN());
assert!(Float::NaN::<float>().clamp(&2f, &4f).is_NaN());
let nan: float = Float::NaN();
assert!(3f.clamp(&nan, &4f).is_NaN());
assert!(3f.clamp(&2f, &nan).is_NaN());
assert!(nan.clamp(&2f, &4f).is_NaN());
}
#[test]
@ -1016,9 +1057,13 @@ mod tests {
fn test_asinh() {
assert_eq!(0.0f.asinh(), 0.0f);
assert_eq!((-0.0f).asinh(), -0.0f);
assert_eq!(Float::infinity::<float>().asinh(), Float::infinity::<float>());
assert_eq!(Float::neg_infinity::<float>().asinh(), Float::neg_infinity::<float>());
assert!(Float::NaN::<float>().asinh().is_NaN());
let inf: float = Float::infinity();
let neg_inf: float = Float::neg_infinity();
let nan: float = Float::NaN();
assert_eq!(inf.asinh(), inf);
assert_eq!(neg_inf.asinh(), neg_inf);
assert!(nan.asinh().is_NaN());
assert_approx_eq!(2.0f.asinh(), 1.443635475178810342493276740273105f);
assert_approx_eq!((-2.0f).asinh(), -1.443635475178810342493276740273105f);
}
@ -1027,9 +1072,13 @@ mod tests {
fn test_acosh() {
assert_eq!(1.0f.acosh(), 0.0f);
assert!(0.999f.acosh().is_NaN());
assert_eq!(Float::infinity::<float>().acosh(), Float::infinity::<float>());
assert!(Float::neg_infinity::<float>().acosh().is_NaN());
assert!(Float::NaN::<float>().acosh().is_NaN());
let inf: float = Float::infinity();
let neg_inf: float = Float::neg_infinity();
let nan: float = Float::NaN();
assert_eq!(inf.acosh(), inf);
assert!(neg_inf.acosh().is_NaN());
assert!(nan.acosh().is_NaN());
assert_approx_eq!(2.0f.acosh(), 1.31695789692481670862504634730796844f);
assert_approx_eq!(3.0f.acosh(), 1.76274717403908605046521864995958461f);
}
@ -1038,34 +1087,58 @@ mod tests {
fn test_atanh() {
assert_eq!(0.0f.atanh(), 0.0f);
assert_eq!((-0.0f).atanh(), -0.0f);
assert_eq!(1.0f.atanh(), Float::infinity::<float>());
assert_eq!((-1.0f).atanh(), Float::neg_infinity::<float>());
let inf: float = Float::infinity();
let neg_inf: float = Float::neg_infinity();
let inf64: f64 = Float::infinity();
let neg_inf64: f64 = Float::neg_infinity();
let nan: float = Float::NaN();
assert_eq!(1.0f.atanh(), inf);
assert_eq!((-1.0f).atanh(), neg_inf);
assert!(2f64.atanh().atanh().is_NaN());
assert!((-2f64).atanh().atanh().is_NaN());
assert!(Float::infinity::<f64>().atanh().is_NaN());
assert!(Float::neg_infinity::<f64>().atanh().is_NaN());
assert!(Float::NaN::<float>().atanh().is_NaN());
assert!(inf64.atanh().is_NaN());
assert!(neg_inf64.atanh().is_NaN());
assert!(nan.atanh().is_NaN());
assert_approx_eq!(0.5f.atanh(), 0.54930614433405484569762261846126285f);
assert_approx_eq!((-0.5f).atanh(), -0.54930614433405484569762261846126285f);
}
#[test]
fn test_real_consts() {
assert_approx_eq!(Real::two_pi::<float>(), 2f * Real::pi::<float>());
assert_approx_eq!(Real::frac_pi_2::<float>(), Real::pi::<float>() / 2f);
assert_approx_eq!(Real::frac_pi_3::<float>(), Real::pi::<float>() / 3f);
assert_approx_eq!(Real::frac_pi_4::<float>(), Real::pi::<float>() / 4f);
assert_approx_eq!(Real::frac_pi_6::<float>(), Real::pi::<float>() / 6f);
assert_approx_eq!(Real::frac_pi_8::<float>(), Real::pi::<float>() / 8f);
assert_approx_eq!(Real::frac_1_pi::<float>(), 1f / Real::pi::<float>());
assert_approx_eq!(Real::frac_2_pi::<float>(), 2f / Real::pi::<float>());
assert_approx_eq!(Real::frac_2_sqrtpi::<float>(), 2f / Real::pi::<float>().sqrt());
assert_approx_eq!(Real::sqrt2::<float>(), 2f.sqrt());
assert_approx_eq!(Real::frac_1_sqrt2::<float>(), 1f / 2f.sqrt());
assert_approx_eq!(Real::log2_e::<float>(), Real::e::<float>().log2());
assert_approx_eq!(Real::log10_e::<float>(), Real::e::<float>().log10());
assert_approx_eq!(Real::ln_2::<float>(), 2f.ln());
assert_approx_eq!(Real::ln_10::<float>(), 10f.ln());
let pi: float = Real::pi();
let two_pi: float = Real::two_pi();
let frac_pi_2: float = Real::frac_pi_2();
let frac_pi_3: float = Real::frac_pi_3();
let frac_pi_4: float = Real::frac_pi_4();
let frac_pi_6: float = Real::frac_pi_6();
let frac_pi_8: float = Real::frac_pi_8();
let frac_1_pi: float = Real::frac_1_pi();
let frac_2_pi: float = Real::frac_2_pi();
let frac_2_sqrtpi: float = Real::frac_2_sqrtpi();
let sqrt2: float = Real::sqrt2();
let frac_1_sqrt2: float = Real::frac_1_sqrt2();
let e: float = Real::e();
let log2_e: float = Real::log2_e();
let log10_e: float = Real::log10_e();
let ln_2: float = Real::ln_2();
let ln_10: float = Real::ln_10();
assert_approx_eq!(two_pi, 2f * pi);
assert_approx_eq!(frac_pi_2, pi / 2f);
assert_approx_eq!(frac_pi_3, pi / 3f);
assert_approx_eq!(frac_pi_4, pi / 4f);
assert_approx_eq!(frac_pi_6, pi / 6f);
assert_approx_eq!(frac_pi_8, pi / 8f);
assert_approx_eq!(frac_1_pi, 1f / pi);
assert_approx_eq!(frac_2_pi, 2f / pi);
assert_approx_eq!(frac_2_sqrtpi, 2f / pi.sqrt());
assert_approx_eq!(sqrt2, 2f.sqrt());
assert_approx_eq!(frac_1_sqrt2, 1f / 2f.sqrt());
assert_approx_eq!(log2_e, e.log2());
assert_approx_eq!(log10_e, e.log10());
assert_approx_eq!(ln_2, 2f.ln());
assert_approx_eq!(ln_10, 10f.ln());
}
#[test]
@ -1141,17 +1214,23 @@ mod tests {
#[test]
fn test_primitive() {
assert_eq!(Primitive::bits::<float>(), sys::size_of::<float>() * 8);
assert_eq!(Primitive::bytes::<float>(), sys::size_of::<float>());
let none: Option<float> = None;
assert_eq!(Primitive::bits(none), sys::size_of::<float>() * 8);
assert_eq!(Primitive::bytes(none), sys::size_of::<float>());
}
#[test]
fn test_is_normal() {
assert!(!Float::NaN::<float>().is_normal());
assert!(!Float::infinity::<float>().is_normal());
assert!(!Float::neg_infinity::<float>().is_normal());
assert!(!Zero::zero::<float>().is_normal());
assert!(!Float::neg_zero::<float>().is_normal());
let nan: float = Float::NaN();
let inf: float = Float::infinity();
let neg_inf: float = Float::neg_infinity();
let zero: float = Zero::zero();
let neg_zero: float = Float::neg_zero();
assert!(!nan.is_normal());
assert!(!inf.is_normal());
assert!(!neg_inf.is_normal());
assert!(!zero.is_normal());
assert!(!neg_zero.is_normal());
assert!(1f.is_normal());
assert!(1e-307f.is_normal());
assert!(!1e-308f.is_normal());
@ -1159,11 +1238,16 @@ mod tests {
#[test]
fn test_classify() {
assert_eq!(Float::NaN::<float>().classify(), FPNaN);
assert_eq!(Float::infinity::<float>().classify(), FPInfinite);
assert_eq!(Float::neg_infinity::<float>().classify(), FPInfinite);
assert_eq!(Zero::zero::<float>().classify(), FPZero);
assert_eq!(Float::neg_zero::<float>().classify(), FPZero);
let nan: float = Float::NaN();
let inf: float = Float::infinity();
let neg_inf: float = Float::neg_infinity();
let zero: float = Zero::zero();
let neg_zero: float = Float::neg_zero();
assert_eq!(nan.classify(), FPNaN);
assert_eq!(inf.classify(), FPInfinite);
assert_eq!(neg_inf.classify(), FPInfinite);
assert_eq!(zero.classify(), FPZero);
assert_eq!(neg_zero.classify(), FPZero);
assert_eq!(1f.classify(), FPNormal);
assert_eq!(1e-307f.classify(), FPNormal);
assert_eq!(1e-308f.classify(), FPSubnormal);
@ -1180,11 +1264,13 @@ mod tests {
assert_eq!(Float::ldexp(0f, -123), 0f);
assert_eq!(Float::ldexp(-0f, -123), -0f);
assert_eq!(Float::ldexp(Float::infinity::<float>(), -123),
Float::infinity::<float>());
assert_eq!(Float::ldexp(Float::neg_infinity::<float>(), -123),
Float::neg_infinity::<float>());
assert!(Float::ldexp(Float::NaN::<float>(), -123).is_NaN());
let inf: float = Float::infinity();
let neg_inf: float = Float::neg_infinity();
let nan: float = Float::NaN();
assert_eq!(Float::ldexp(inf, -123), inf);
assert_eq!(Float::ldexp(neg_inf, -123), neg_inf);
assert!(Float::ldexp(nan, -123).is_NaN());
}
#[test]
@ -1202,11 +1288,13 @@ mod tests {
assert_eq!(0f.frexp(), (0f, 0));
assert_eq!((-0f).frexp(), (-0f, 0));
assert_eq!(match Float::infinity::<float>().frexp() { (x, _) => x },
Float::infinity::<float>())
assert_eq!(match Float::neg_infinity::<float>().frexp() { (x, _) => x },
Float::neg_infinity::<float>())
assert!(match Float::NaN::<float>().frexp() { (x, _) => x.is_NaN() })
let inf: float = Float::infinity();
let neg_inf: float = Float::neg_infinity();
let nan: float = Float::NaN();
assert_eq!(match inf.frexp() { (x, _) => x }, inf);
assert_eq!(match neg_inf.frexp() { (x, _) => x }, neg_inf);
assert!(match nan.frexp() { (x, _) => x.is_NaN() })
}
#[test]

View File

@ -466,10 +466,10 @@ impl Int for $T {}
impl Primitive for $T {
#[inline]
fn bits() -> uint { bits }
fn bits(_: Option<$T>) -> uint { bits }
#[inline]
fn bytes() -> uint { bits / 8 }
fn bytes(_: Option<$T>) -> uint { bits / 8 }
}
// String conversion functions and impl str -> num
@ -754,8 +754,9 @@ mod tests {
#[test]
fn test_primitive() {
assert_eq!(Primitive::bits::<$T>(), sys::size_of::<$T>() * 8);
assert_eq!(Primitive::bytes::<$T>(), sys::size_of::<$T>());
let none: Option<$T> = None;
assert_eq!(Primitive::bits(none), sys::size_of::<$T>() * 8);
assert_eq!(Primitive::bytes(none), sys::size_of::<$T>());
}
#[test]

View File

@ -272,8 +272,8 @@ pub trait Primitive: Num
+ Div<Self,Self>
+ Rem<Self,Self> {
// FIXME (#5527): These should be associated constants
fn bits() -> uint;
fn bytes() -> uint;
fn bits(unused_self: Option<Self>) -> uint;
fn bytes(unused_self: Option<Self>) -> uint;
}
/// A collection of traits relevant to primitive signed and unsigned integers
@ -314,13 +314,13 @@ pub trait Float: Real
fn is_normal(&self) -> bool;
fn classify(&self) -> FPCategory;
fn mantissa_digits() -> uint;
fn digits() -> uint;
fn mantissa_digits(unused_self: Option<Self>) -> uint;
fn digits(unused_self: Option<Self>) -> uint;
fn epsilon() -> Self;
fn min_exp() -> int;
fn max_exp() -> int;
fn min_10_exp() -> int;
fn max_10_exp() -> int;
fn min_exp(unused_self: Option<Self>) -> int;
fn max_exp(unused_self: Option<Self>) -> int;
fn min_10_exp(unused_self: Option<Self>) -> int;
fn max_10_exp(unused_self: Option<Self>) -> int;
fn ldexp(x: Self, exp: int) -> Self;
fn frexp(&self) -> (Self, int);
@ -484,9 +484,9 @@ impl<T: CheckedAdd+CheckedSub+Zero+Ord+Bounded> Saturating for T {
match self.checked_add(&v) {
Some(x) => x,
None => if v >= Zero::zero() {
Bounded::max_value::<T>()
Bounded::max_value()
} else {
Bounded::min_value::<T>()
Bounded::min_value()
}
}
}
@ -496,9 +496,9 @@ impl<T: CheckedAdd+CheckedSub+Zero+Ord+Bounded> Saturating for T {
match self.checked_sub(&v) {
Some(x) => x,
None => if v >= Zero::zero() {
Bounded::min_value::<T>()
Bounded::min_value()
} else {
Bounded::max_value::<T>()
Bounded::max_value()
}
}
}

View File

@ -404,10 +404,10 @@ impl ToStrRadix for $T {
impl Primitive for $T {
#[inline]
fn bits() -> uint { bits }
fn bits(_: Option<$T>) -> uint { bits }
#[inline]
fn bytes() -> uint { bits / 8 }
fn bytes(_: Option<$T>) -> uint { bits / 8 }
}
impl BitCount for $T {
@ -532,8 +532,9 @@ mod tests {
#[test]
fn test_primitive() {
assert_eq!(Primitive::bits::<$T>(), sys::size_of::<$T>() * 8);
assert_eq!(Primitive::bytes::<$T>(), sys::size_of::<$T>());
let none: Option<$T> = None;
assert_eq!(Primitive::bits(none), sys::size_of::<$T>() * 8);
assert_eq!(Primitive::bytes(none), sys::size_of::<$T>());
}
#[test]

View File

@ -1521,7 +1521,7 @@ impl MemoryMap {
let r = unsafe {
libc::mmap(addr, len, prot, flags, fd, offset)
};
if r == libc::MAP_FAILED {
if r.equiv(&libc::MAP_FAILED) {
Err(match errno() as c_int {
libc::EACCES => ErrFdNotAvail,
libc::EBADF => ErrInvalidFd,

View File

@ -12,8 +12,11 @@
use cast;
use clone::Clone;
use cmp::Equiv;
use iterator::{range, Iterator};
use option::{Option, Some, None};
#[cfg(stage0)]
use sys;
use unstable::intrinsics;
use util::swap;
@ -24,18 +27,28 @@ use util::swap;
/// Calculate the offset from a pointer
#[inline]
#[cfg(stage0)]
pub fn offset<T>(ptr: *T, count: int) -> *T {
unsafe { intrinsics::offset(ptr, count) }
}
/// Calculate the offset from a const pointer
#[inline]
pub fn const_offset<T>(ptr: *const T, count: int) -> *const T {
unsafe { intrinsics::offset(ptr as *T, count) }
(ptr as uint + (count as uint) * sys::size_of::<T>()) as *T
}
/// Calculate the offset from a mut pointer
#[inline]
#[cfg(stage0)]
pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
(ptr as uint + (count as uint) * sys::size_of::<T>()) as *mut T
}
/// Calculate the offset from a pointer
#[inline]
#[cfg(not(stage0))]
pub fn offset<T>(ptr: *T, count: int) -> *T {
unsafe { intrinsics::offset(ptr, count) }
}
/// Calculate the offset from a mut pointer
#[inline]
#[cfg(not(stage0))]
pub fn mut_offset<T>(ptr: *mut T, count: int) -> *mut T {
unsafe { intrinsics::offset(ptr as *T, count) as *mut T }
}
@ -73,11 +86,11 @@ pub fn mut_null<T>() -> *mut T { 0 as *mut T }
/// Returns true if the pointer is equal to the null pointer.
#[inline]
pub fn is_null<T>(ptr: *const T) -> bool { ptr == null() }
pub fn is_null<T,P:RawPtr<T>>(ptr: P) -> bool { ptr.is_null() }
/// Returns true if the pointer is not equal to the null pointer.
#[inline]
pub fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
pub fn is_not_null<T,P:RawPtr<T>>(ptr: P) -> bool { ptr.is_not_null() }
/**
* Copies data from one location to another.
@ -87,8 +100,10 @@ pub fn is_not_null<T>(ptr: *const T) -> bool { !is_null(ptr) }
*/
#[inline]
#[cfg(target_word_size = "32")]
pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
intrinsics::memmove32(dst, src as *T, count as u32);
pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
intrinsics::memmove32(dst,
cast::transmute_immut_unsafe(src),
count as u32);
}
/**
@ -99,8 +114,10 @@ pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
*/
#[inline]
#[cfg(target_word_size = "64")]
pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
intrinsics::memmove64(dst, src as *T, count as u64);
pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
intrinsics::memmove64(dst,
cast::transmute_immut_unsafe(src),
count as u64);
}
/**
@ -111,8 +128,12 @@ pub unsafe fn copy_memory<T>(dst: *mut T, src: *const T, count: uint) {
*/
#[inline]
#[cfg(target_word_size = "32")]
pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
intrinsics::memcpy32(dst, src as *T, count as u32);
pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
src: P,
count: uint) {
intrinsics::memcpy32(dst,
cast::transmute_immut_unsafe(src),
count as u32);
}
/**
@ -123,8 +144,12 @@ pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: u
*/
#[inline]
#[cfg(target_word_size = "64")]
pub unsafe fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *const T, count: uint) {
intrinsics::memcpy64(dst, src as *T, count as u64);
pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
src: P,
count: uint) {
intrinsics::memcpy64(dst,
cast::transmute_immut_unsafe(src),
count as u64);
}
/**
@ -216,12 +241,6 @@ pub fn to_unsafe_ptr<T>(thing: &T) -> *T {
thing as *T
}
/// Transform a const region pointer - &const T - to a const unsafe pointer - *const T.
#[inline]
pub fn to_const_unsafe_ptr<T>(thing: &const T) -> *const T {
thing as *const T
}
/// Transform a mutable region pointer - &mut T - to a mutable unsafe pointer - *mut T.
#[inline]
pub fn to_mut_unsafe_ptr<T>(thing: &mut T) -> *mut T {
@ -269,8 +288,10 @@ pub unsafe fn array_each<T>(arr: **T, cb: &fn(*T)) {
#[allow(missing_doc)]
pub trait RawPtr<T> {
fn null() -> Self;
fn is_null(&self) -> bool;
fn is_not_null(&self) -> bool;
fn to_uint(&self) -> uint;
unsafe fn to_option(&self) -> Option<&T>;
fn offset(&self, count: int) -> Self;
unsafe fn offset_inbounds(self, count: int) -> Self;
@ -278,13 +299,21 @@ pub trait RawPtr<T> {
/// Extension methods for immutable pointers
impl<T> RawPtr<T> for *T {
/// Returns the null pointer.
#[inline]
fn null() -> *T { null() }
/// Returns true if the pointer is equal to the null pointer.
#[inline]
fn is_null(&self) -> bool { is_null(*self) }
fn is_null(&self) -> bool { *self == RawPtr::null() }
/// Returns true if the pointer is not equal to the null pointer.
#[inline]
fn is_not_null(&self) -> bool { is_not_null(*self) }
fn is_not_null(&self) -> bool { *self != RawPtr::null() }
/// Returns the address of this pointer.
#[inline]
fn to_uint(&self) -> uint { *self as uint }
///
/// Returns `None` if the pointer is null, or else returns the value wrapped
@ -317,13 +346,21 @@ impl<T> RawPtr<T> for *T {
/// Extension methods for mutable pointers
impl<T> RawPtr<T> for *mut T {
/// Returns the null pointer.
#[inline]
fn null() -> *mut T { mut_null() }
/// Returns true if the pointer is equal to the null pointer.
#[inline]
fn is_null(&self) -> bool { is_null(*self) }
fn is_null(&self) -> bool { *self == RawPtr::null() }
/// Returns true if the pointer is not equal to the null pointer.
#[inline]
fn is_not_null(&self) -> bool { is_not_null(*self) }
fn is_not_null(&self) -> bool { *self != RawPtr::null() }
/// Returns the address of this pointer.
#[inline]
fn to_uint(&self) -> uint { *self as uint }
///
/// Returns `None` if the pointer is null, or else returns the value wrapped
@ -360,13 +397,38 @@ impl<T> RawPtr<T> for *mut T {
// Equality for pointers
#[cfg(not(test))]
impl<T> Eq for *const T {
impl<T> Eq for *T {
#[inline]
fn eq(&self, other: &*const T) -> bool {
fn eq(&self, other: &*T) -> bool {
(*self as uint) == (*other as uint)
}
#[inline]
fn ne(&self, other: &*const T) -> bool { !self.eq(other) }
fn ne(&self, other: &*T) -> bool { !self.eq(other) }
}
#[cfg(not(test))]
impl<T> Eq for *mut T {
#[inline]
fn eq(&self, other: &*mut T) -> bool {
(*self as uint) == (*other as uint)
}
#[inline]
fn ne(&self, other: &*mut T) -> bool { !self.eq(other) }
}
// Equivalence for pointers
#[cfg(not(test))]
impl<T> Equiv<*mut T> for *T {
fn equiv(&self, other: &*mut T) -> bool {
self.to_uint() == other.to_uint()
}
}
#[cfg(not(test))]
impl<T> Equiv<*T> for *mut T {
fn equiv(&self, other: &*T) -> bool {
self.to_uint() == other.to_uint()
}
}
// Equality for extern "C" fn pointers
@ -412,21 +474,41 @@ mod externfnpointers {
// Comparison for pointers
#[cfg(not(test))]
impl<T> Ord for *const T {
impl<T> Ord for *T {
#[inline]
fn lt(&self, other: &*const T) -> bool {
fn lt(&self, other: &*T) -> bool {
(*self as uint) < (*other as uint)
}
#[inline]
fn le(&self, other: &*const T) -> bool {
fn le(&self, other: &*T) -> bool {
(*self as uint) <= (*other as uint)
}
#[inline]
fn ge(&self, other: &*const T) -> bool {
fn ge(&self, other: &*T) -> bool {
(*self as uint) >= (*other as uint)
}
#[inline]
fn gt(&self, other: &*const T) -> bool {
fn gt(&self, other: &*T) -> bool {
(*self as uint) > (*other as uint)
}
}
#[cfg(not(test))]
impl<T> Ord for *mut T {
#[inline]
fn lt(&self, other: &*mut T) -> bool {
(*self as uint) < (*other as uint)
}
#[inline]
fn le(&self, other: &*mut T) -> bool {
(*self as uint) <= (*other as uint)
}
#[inline]
fn ge(&self, other: &*mut T) -> bool {
(*self as uint) >= (*other as uint)
}
#[inline]
fn gt(&self, other: &*mut T) -> bool {
(*self as uint) > (*other as uint)
}
}

View File

@ -11,17 +11,18 @@
use cell::Cell;
use c_str::ToCStr;
use cast::transmute;
use libc::{c_char, size_t, STDERR_FILENO};
use io;
use io::{Writer, WriterUtil};
use io;
use libc::{c_char, size_t, STDERR_FILENO};
use option::{Option, None, Some};
use uint;
use ptr::RawPtr;
use rt::env;
use rt::local::Local;
use rt::task::Task;
use str;
use str::{OwnedStr, StrSlice};
use str;
use sys;
use uint;
use unstable::raw;
use vec::ImmutableVector;
@ -37,7 +38,7 @@ pub struct BorrowRecord {
}
fn try_take_task_borrow_list() -> Option<~[BorrowRecord]> {
do Local::borrow::<Task, Option<~[BorrowRecord]>> |task| {
do Local::borrow |task: &mut Task| {
task.borrow_list.take()
}
}
@ -49,7 +50,7 @@ fn swap_task_borrow_list(f: &fn(~[BorrowRecord]) -> ~[BorrowRecord]) {
};
let borrows = f(borrows);
let borrows = Cell::new(borrows);
do Local::borrow::<Task, ()> |task| {
do Local::borrow |task: &mut Task| {
task.borrow_list = Some(borrows.take());
}
}
@ -93,12 +94,12 @@ unsafe fn fail_borrowed(box: *mut raw::Box<()>, file: *c_char, line: size_t) {
static ENABLE_DEBUG: bool = false;
#[inline]
unsafe fn debug_borrow<T>(tag: &'static str,
p: *const T,
old_bits: uint,
new_bits: uint,
filename: *c_char,
line: size_t) {
unsafe fn debug_borrow<T,P:RawPtr<T>>(tag: &'static str,
p: P,
old_bits: uint,
new_bits: uint,
filename: *c_char,
line: size_t) {
//! A useful debugging function that prints a pointer + tag + newline
//! without allocating memory.
@ -106,15 +107,15 @@ unsafe fn debug_borrow<T>(tag: &'static str,
debug_borrow_slow(tag, p, old_bits, new_bits, filename, line);
}
unsafe fn debug_borrow_slow<T>(tag: &'static str,
p: *const T,
old_bits: uint,
new_bits: uint,
filename: *c_char,
line: size_t) {
unsafe fn debug_borrow_slow<T,P:RawPtr<T>>(tag: &'static str,
p: P,
old_bits: uint,
new_bits: uint,
filename: *c_char,
line: size_t) {
let dbg = STDERR_FILENO as io::fd_t;
dbg.write_str(tag);
dbg.write_hex(p as uint);
dbg.write_hex(p.to_uint());
dbg.write_str(" ");
dbg.write_hex(old_bits);
dbg.write_str(" ");

View File

@ -159,7 +159,7 @@ impl<T> ChanOne<T> {
};
} else {
let recvr = Cell::new(recvr);
do Local::borrow::<Scheduler, ()> |sched| {
do Local::borrow |sched: &mut Scheduler| {
sched.enqueue_blocked_task(recvr.take());
}
}
@ -199,7 +199,7 @@ impl<T> PortOne<T> {
if !this.optimistic_check() {
// No data available yet.
// Switch to the scheduler to put the ~Task into the Packet state.
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
this.block_on(sched, task);
}
@ -221,7 +221,7 @@ impl<T> SelectInner for PortOne<T> {
// The optimistic check is never necessary for correctness. For testing
// purposes, making it randomly return false simulates a racing sender.
use rand::{Rand};
let actually_check = do Local::borrow::<Scheduler, bool> |sched| {
let actually_check = do Local::borrow |sched: &mut Scheduler| {
Rand::rand(&mut sched.rng)
};
if actually_check {

View File

@ -24,7 +24,7 @@ pub fn open<P: PathLike>(path: &P,
access: FileAccess
) -> Option<FileStream> {
let open_result = unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
(*io).fs_open(path, mode, access)
};
match open_result {
@ -43,7 +43,7 @@ pub fn open<P: PathLike>(path: &P,
/// by `path`.
pub fn unlink<P: PathLike>(path: &P) {
let unlink_result = unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
(*io).fs_unlink(path)
};
match unlink_result {

View File

@ -359,7 +359,7 @@ impl FromStr for SocketAddr {
mod test {
use super::*;
use from_str::FromStr;
use option::{Some, None};
use option::{Option, Some, None};
#[test]
fn test_from_str_ipv4() {
@ -368,13 +368,17 @@ mod test {
assert_eq!(Some(Ipv4Addr(0, 0, 0, 0)), FromStr::from_str("0.0.0.0"));
// out of range
assert_eq!(None, FromStr::from_str::<IpAddr>("256.0.0.1"));
let none: Option<IpAddr> = FromStr::from_str("256.0.0.1");
assert_eq!(None, none);
// too short
assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0"));
let none: Option<IpAddr> = FromStr::from_str("255.0.0");
assert_eq!(None, none);
// too long
assert_eq!(None, FromStr::from_str::<IpAddr>("255.0.0.1.2"));
let none: Option<IpAddr> = FromStr::from_str("255.0.0.1.2");
assert_eq!(None, none);
// no number between dots
assert_eq!(None, FromStr::from_str::<IpAddr>("255.0..1"));
let none: Option<IpAddr> = FromStr::from_str("255.0..1");
assert_eq!(None, none);
}
#[test]
@ -389,15 +393,20 @@ mod test {
FromStr::from_str("2a02:6b8::11:11"));
// too long group
assert_eq!(None, FromStr::from_str::<IpAddr>("::00000"));
let none: Option<IpAddr> = FromStr::from_str("::00000");
assert_eq!(None, none);
// too short
assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7"));
let none: Option<IpAddr> = FromStr::from_str("1:2:3:4:5:6:7");
assert_eq!(None, none);
// too long
assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:3:4:5:6:7:8:9"));
let none: Option<IpAddr> = FromStr::from_str("1:2:3:4:5:6:7:8:9");
assert_eq!(None, none);
// triple colon
assert_eq!(None, FromStr::from_str::<IpAddr>("1:2:::6:7:8"));
let none: Option<IpAddr> = FromStr::from_str("1:2:::6:7:8");
assert_eq!(None, none);
// two double colons
assert_eq!(None, FromStr::from_str::<IpAddr>("1:2::6::8"));
let none: Option<IpAddr> = FromStr::from_str("1:2::6::8");
assert_eq!(None, none);
}
#[test]
@ -412,11 +421,15 @@ mod test {
FromStr::from_str("2001:db8:122:c000:2:2100:192.0.2.33"));
// colon after v4
assert_eq!(None, FromStr::from_str::<IpAddr>("::127.0.0.1:"));
let none: Option<IpAddr> = FromStr::from_str("::127.0.0.1:");
assert_eq!(None, none);
// not enought groups
assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:127.0.0.1"));
let none: Option<IpAddr> = FromStr::from_str("1.2.3.4.5:127.0.0.1");
assert_eq!(None, none);
// too many groups
assert_eq!(None, FromStr::from_str::<IpAddr>("1.2.3.4.5:6:7:127.0.0.1"));
let none: Option<IpAddr> =
FromStr::from_str("1.2.3.4.5:6:7:127.0.0.1");
assert_eq!(None, none);
}
#[test]
@ -429,13 +442,17 @@ mod test {
FromStr::from_str("[::127.0.0.1]:22"));
// without port
assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1"));
let none: Option<SocketAddr> = FromStr::from_str("127.0.0.1");
assert_eq!(None, none);
// without port
assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:"));
let none: Option<SocketAddr> = FromStr::from_str("127.0.0.1:");
assert_eq!(None, none);
// wrong brackets around v4
assert_eq!(None, FromStr::from_str::<SocketAddr>("[127.0.0.1]:22"));
let none: Option<SocketAddr> = FromStr::from_str("[127.0.0.1]:22");
assert_eq!(None, none);
// port out of range
assert_eq!(None, FromStr::from_str::<SocketAddr>("127.0.0.1:123456"));
let none: Option<SocketAddr> = FromStr::from_str("127.0.0.1:123456");
assert_eq!(None, none);
}
#[test]

View File

@ -29,7 +29,7 @@ impl TcpStream {
pub fn connect(addr: SocketAddr) -> Option<TcpStream> {
let stream = unsafe {
rtdebug!("borrowing io to connect");
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
rtdebug!("about to connect");
(*io).tcp_connect(addr)
};
@ -100,7 +100,7 @@ pub struct TcpListener(~RtioTcpListenerObject);
impl TcpListener {
pub fn bind(addr: SocketAddr) -> Option<TcpListener> {
let listener = unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
(*io).tcp_bind(addr)
};
match listener {

View File

@ -20,7 +20,10 @@ pub struct UdpSocket(~RtioUdpSocketObject);
impl UdpSocket {
pub fn bind(addr: SocketAddr) -> Option<UdpSocket> {
let socket = unsafe { (*Local::unsafe_borrow::<IoFactoryObject>()).udp_bind(addr) };
let socket = unsafe {
let factory: *mut IoFactoryObject = Local::unsafe_borrow();
(*factory).udp_bind(addr)
};
match socket {
Ok(s) => Some(UdpSocket(s)),
Err(ioerr) => {

View File

@ -22,7 +22,7 @@ impl Timer {
pub fn new() -> Option<Timer> {
let timer = unsafe {
rtdebug!("Timer::init: borrowing io to init timer");
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
rtdebug!("about to init timer");
(*io).timer_init()
};

View File

@ -19,7 +19,7 @@ use cell::Cell;
pub trait Local {
fn put(value: ~Self);
fn take() -> ~Self;
fn exists() -> bool;
fn exists(unused_value: Option<Self>) -> bool;
fn borrow<T>(f: &fn(&mut Self) -> T) -> T;
unsafe fn unsafe_take() -> ~Self;
unsafe fn unsafe_borrow() -> *mut Self;
@ -31,7 +31,7 @@ impl Local for Task {
fn put(value: ~Task) { unsafe { local_ptr::put(value) } }
#[inline]
fn take() -> ~Task { unsafe { local_ptr::take() } }
fn exists() -> bool { local_ptr::exists() }
fn exists(_: Option<Task>) -> bool { local_ptr::exists() }
fn borrow<T>(f: &fn(&mut Task) -> T) -> T {
let mut res: Option<T> = None;
let res_ptr: *mut Option<T> = &mut res;
@ -59,7 +59,7 @@ impl Local for Task {
impl Local for Scheduler {
fn put(value: ~Scheduler) {
let value = Cell::new(value);
do Local::borrow::<Task,()> |task| {
do Local::borrow |task: &mut Task| {
let task = task;
task.sched = Some(value.take());
};
@ -68,12 +68,12 @@ impl Local for Scheduler {
fn take() -> ~Scheduler {
unsafe {
// XXX: Unsafe for speed
let task = Local::unsafe_borrow::<Task>();
let task: *mut Task = Local::unsafe_borrow();
(*task).sched.take_unwrap()
}
}
fn exists() -> bool {
do Local::borrow::<Task,bool> |task| {
fn exists(_: Option<Scheduler>) -> bool {
do Local::borrow |task: &mut Task| {
match task.sched {
Some(ref _task) => true,
None => false
@ -81,7 +81,7 @@ impl Local for Scheduler {
}
}
fn borrow<T>(f: &fn(&mut Scheduler) -> T) -> T {
do Local::borrow::<Task, T> |task| {
do Local::borrow |task: &mut Task| {
match task.sched {
Some(~ref mut task) => {
f(task)
@ -94,7 +94,8 @@ impl Local for Scheduler {
}
unsafe fn unsafe_take() -> ~Scheduler { rtabort!("unimpl") }
unsafe fn unsafe_borrow() -> *mut Scheduler {
match (*Local::unsafe_borrow::<Task>()).sched {
let task: *mut Task = Local::unsafe_borrow();
match (*task).sched {
Some(~ref mut sched) => {
let s: *mut Scheduler = &mut *sched;
return s;
@ -105,7 +106,8 @@ impl Local for Scheduler {
}
}
unsafe fn try_unsafe_borrow() -> Option<*mut Scheduler> {
match Local::try_unsafe_borrow::<Task>() {
let task_opt: Option<*mut Task> = Local::try_unsafe_borrow();
match task_opt {
Some(task) => {
match (*task).sched {
Some(~ref mut sched) => {
@ -124,15 +126,17 @@ impl Local for Scheduler {
impl Local for IoFactoryObject {
fn put(_value: ~IoFactoryObject) { rtabort!("unimpl") }
fn take() -> ~IoFactoryObject { rtabort!("unimpl") }
fn exists() -> bool { rtabort!("unimpl") }
fn exists(_: Option<IoFactoryObject>) -> bool { rtabort!("unimpl") }
fn borrow<T>(_f: &fn(&mut IoFactoryObject) -> T) -> T { rtabort!("unimpl") }
unsafe fn unsafe_take() -> ~IoFactoryObject { rtabort!("unimpl") }
unsafe fn unsafe_borrow() -> *mut IoFactoryObject {
let sched = Local::unsafe_borrow::<Scheduler>();
let sched: *mut Scheduler = Local::unsafe_borrow();
let io: *mut IoFactoryObject = (*sched).event_loop.io().unwrap();
return io;
}
unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> { rtabort!("unimpl") }
unsafe fn try_unsafe_borrow() -> Option<*mut IoFactoryObject> {
rtabort!("unimpl")
}
}
@ -198,7 +202,7 @@ mod test {
let task = ~Task::new_root(&mut sched.stack_pool, None, || {});
Local::put(task);
let res = do Local::borrow::<Task,bool> |_task| {
let res = do Local::borrow |_task: &mut Task| {
true
};
assert!(res)

View File

@ -13,7 +13,7 @@
use libc;
use libc::{c_void, uintptr_t, size_t};
use ops::Drop;
use option::{Some, None};
use option::{Option, None, Some};
use rt::local::Local;
use rt::task::Task;
use unstable::raw;
@ -89,7 +89,8 @@ impl Drop for LocalHeap {
// A little compatibility function
pub unsafe fn local_free(ptr: *libc::c_char) {
// XXX: Unsafe borrow for speed. Lame.
match Local::try_unsafe_borrow::<Task>() {
let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
match task_ptr {
Some(task) => {
(*task).heap.free(ptr as *libc::c_void);
}
@ -98,7 +99,7 @@ pub unsafe fn local_free(ptr: *libc::c_char) {
}
pub fn live_allocs() -> *raw::Box<()> {
let region = do Local::borrow::<Task, *BoxedRegion> |task| {
let region = do Local::borrow |task: &mut Task| {
task.heap.boxed_region
};

View File

@ -64,7 +64,7 @@ use cell::Cell;
use clone::Clone;
use container::Container;
use iterator::{Iterator, range};
use option::{Some, None};
use option::{Option, None, Some};
use ptr::RawPtr;
use rt::local::Local;
use rt::sched::{Scheduler, Shutdown};
@ -408,7 +408,8 @@ fn run_(main: ~fn(), use_main_sched: bool) -> int {
pub fn in_sched_context() -> bool {
unsafe {
match Local::try_unsafe_borrow::<Task>() {
let task_ptr: Option<*mut Task> = Local::try_unsafe_borrow();
match task_ptr {
Some(task) => {
match (*task).task_type {
SchedTask => true,
@ -422,7 +423,8 @@ pub fn in_sched_context() -> bool {
pub fn in_green_task_context() -> bool {
unsafe {
match Local::try_unsafe_borrow::<Task>() {
let task: Option<*mut Task> = Local::try_unsafe_borrow();
match task {
Some(task) => {
match (*task).task_type {
GreenTask(_) => true,

View File

@ -169,13 +169,13 @@ impl Scheduler {
// successfully run the input task. Start by running the
// scheduler. Grab it out of TLS - performing the scheduler
// action will have given it away.
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
rtdebug!("starting scheduler %u", sched.sched_id());
sched.run();
// Close the idle callback.
let mut sched = Local::take::<Scheduler>();
let mut sched: ~Scheduler = Local::take();
sched.idle_callback.get_mut_ref().close();
// Make one go through the loop to run the close callback.
sched.run();
@ -185,7 +185,7 @@ impl Scheduler {
// cleaning up the memory it uses. As we didn't actually call
// task.run() on the scheduler task we never get through all
// the cleanup code it runs.
let mut stask = Local::take::<Task>();
let mut stask: ~Task = Local::take();
rtdebug!("stopping scheduler %u", stask.sched.get_ref().sched_id());
@ -212,7 +212,7 @@ impl Scheduler {
// Our scheduler must be in the task before the event loop
// is started.
let self_sched = Cell::new(self_sched);
do Local::borrow::<Task,()> |stask| {
do Local::borrow |stask: &mut Task| {
stask.sched = Some(self_sched.take());
};
@ -234,7 +234,7 @@ impl Scheduler {
// already have a scheduler stored in our local task, so we
// start off by taking it. This is the only path through the
// scheduler where we get the scheduler this way.
let mut sched = Local::take::<Scheduler>();
let mut sched: ~Scheduler = Local::take();
// Assume that we need to continue idling unless we reach the
// end of this function without performing an action.
@ -522,7 +522,7 @@ impl Scheduler {
// The current task is grabbed from TLS, not taken as an input.
// Doing an unsafe_take to avoid writing back a null pointer -
// We're going to call `put` later to do that.
let current_task: ~Task = unsafe { Local::unsafe_take::<Task>() };
let current_task: ~Task = unsafe { Local::unsafe_take() };
// Check that the task is not in an atomically() section (e.g.,
// holding a pthread mutex, which could deadlock the scheduler).
@ -554,7 +554,8 @@ impl Scheduler {
let current_task: &mut Task = match sched.cleanup_job {
Some(CleanupJob { task: ref task, _ }) => {
transmute_mut_region(*transmute_mut_unsafe(task))
let task_ptr: *~Task = task;
transmute_mut_region(*transmute_mut_unsafe(task_ptr))
}
None => {
rtabort!("no cleanup job");
@ -580,7 +581,7 @@ impl Scheduler {
// run the cleanup job, as expected by the previously called
// swap_contexts function.
unsafe {
let task = Local::unsafe_borrow::<Task>();
let task: *mut Task = Local::unsafe_borrow();
(*task).sched.get_mut_ref().run_cleanup_job();
// Must happen after running the cleanup job (of course).
@ -685,13 +686,13 @@ impl Scheduler {
}
pub fn run_task(task: ~Task) {
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
sched.process_task(task, Scheduler::switch_task).map_move(Local::put);
}
pub fn run_task_later(next_task: ~Task) {
let next_task = Cell::new(next_task);
do Local::borrow::<Scheduler,()> |sched| {
do Local::borrow |sched: &mut Scheduler| {
sched.enqueue_task(next_task.take());
};
}
@ -1023,12 +1024,12 @@ mod test {
// exit before emptying the work queue
do run_in_newsched_task {
do spawntask {
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
let task = Cell::new(task);
do sched.event_loop.callback_ms(10) {
rtdebug!("in callback");
let mut sched = Local::take::<Scheduler>();
let mut sched: ~Scheduler = Local::take();
sched.enqueue_blocked_task(task.take());
Local::put(sched);
}

View File

@ -26,3 +26,4 @@ pub trait SelectInner {
pub trait SelectPortInner<T> {
fn recv_ready(self) -> Option<T>;
}

View File

@ -93,7 +93,7 @@ impl Task {
pub fn build_homed_child(stack_size: Option<uint>, f: ~fn(), home: SchedHome) -> ~Task {
let f = Cell::new(f);
let home = Cell::new(home);
do Local::borrow::<Task, ~Task> |running_task| {
do Local::borrow |running_task: &mut Task| {
let mut sched = running_task.sched.take_unwrap();
let new_task = ~running_task.new_child_homed(&mut sched.stack_pool,
stack_size,
@ -111,7 +111,7 @@ impl Task {
pub fn build_homed_root(stack_size: Option<uint>, f: ~fn(), home: SchedHome) -> ~Task {
let f = Cell::new(f);
let home = Cell::new(home);
do Local::borrow::<Task, ~Task> |running_task| {
do Local::borrow |running_task: &mut Task| {
let mut sched = running_task.sched.take_unwrap();
let new_task = ~Task::new_root_homed(&mut sched.stack_pool,
stack_size,
@ -305,7 +305,7 @@ impl Task {
// Grab both the scheduler and the task from TLS and check if the
// task is executing on an appropriate scheduler.
pub fn on_appropriate_sched() -> bool {
do Local::borrow::<Task,bool> |task| {
do Local::borrow |task: &mut Task| {
let sched_id = task.sched.get_ref().sched_id();
let sched_run_anything = task.sched.get_ref().run_anything;
match task.task_type {
@ -369,7 +369,7 @@ impl Coroutine {
unsafe {
// Again - might work while safe, or it might not.
do Local::borrow::<Scheduler,()> |sched| {
do Local::borrow |sched: &mut Scheduler| {
sched.run_cleanup_job();
}
@ -378,7 +378,7 @@ impl Coroutine {
// simply unsafe_borrow it to get this reference. We
// need to still have the task in TLS though, so we
// need to unsafe_borrow.
let task = Local::unsafe_borrow::<Task>();
let task: *mut Task = Local::unsafe_borrow();
do (*task).run {
// N.B. Removing `start` from the start wrapper
@ -397,7 +397,7 @@ impl Coroutine {
}
// We remove the sched from the Task in TLS right now.
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
// ... allowing us to give it away when performing a
// scheduling operation.
sched.terminate_current_task()

View File

@ -51,7 +51,7 @@ impl<T> Tube<T> {
// There's a waiting task. Wake it up
rtdebug!("waking blocked tube");
let task = (*state).blocked_task.take_unwrap();
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
sched.resume_blocked_task_immediately(task);
}
}
@ -67,7 +67,7 @@ impl<T> Tube<T> {
rtdebug!("blocking on tube recv");
assert!(self.p.refcount() > 1); // There better be somebody to wake us up
assert!((*state).blocked_task.is_none());
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |_, task| {
(*state).blocked_task = Some(task);
}
@ -102,7 +102,7 @@ mod test {
let mut tube: Tube<int> = Tube::new();
let tube_clone = tube.clone();
let tube_clone_cell = Cell::new(tube_clone);
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
let mut tube_clone = tube_clone_cell.take();
tube_clone.send(1);
@ -119,7 +119,7 @@ mod test {
let mut tube: Tube<int> = Tube::new();
let tube_clone = tube.clone();
let tube_clone = Cell::new(tube_clone);
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
let tube_clone = Cell::new(tube_clone.take());
do sched.event_loop.callback {
@ -143,7 +143,7 @@ mod test {
let mut tube: Tube<int> = Tube::new();
let tube_clone = tube.clone();
let tube_clone = Cell::new(tube_clone);
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
callback_send(tube_clone.take(), 0);
@ -151,7 +151,7 @@ mod test {
if i == 100 { return; }
let tube = Cell::new(Cell::new(tube));
do Local::borrow::<Scheduler, ()> |sched| {
do Local::borrow |sched: &mut Scheduler| {
let tube = tube.take();
do sched.event_loop.callback {
let mut tube = tube.take();

View File

@ -57,7 +57,7 @@ trait HomingIO {
let old_home = Cell::new_empty();
let old_home_ptr = &old_home;
do task::unkillable { // FIXME(#8674)
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
// get the old home first
do task.wake().map_move |mut task| {
@ -72,7 +72,7 @@ trait HomingIO {
// unhome home
do task::unkillable { // FIXME(#8674)
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |scheduler, task| {
do task.wake().map_move |mut task| {
task.give_home(old_home.take());
@ -92,7 +92,7 @@ trait HomingIO {
// go home
let old_home = Cell::new_empty();
let old_home_ptr = &old_home;
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
// get the old home first
do task.wake().map_move |mut task| {
@ -102,11 +102,11 @@ trait HomingIO {
}
// do IO
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
let a = io_sched(self, scheduler);
// unhome home
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |scheduler, task| {
do task.wake().map_move |mut task| {
task.give_home(old_home.take());
@ -122,7 +122,7 @@ trait HomingIO {
// get a handle for the current scheduler
macro_rules! get_handle_to_current_scheduler(
() => (do Local::borrow::<Scheduler, SchedHandle> |sched| { sched.make_handle() })
() => (do Local::borrow |sched: &mut Scheduler| { sched.make_handle() })
)
enum SocketNameKind {
@ -375,7 +375,7 @@ mod test_remote {
let mut tube = Tube::new();
let tube_clone = tube.clone();
let remote_cell = Cell::new_empty();
do Local::borrow::<Scheduler, ()>() |sched| {
do Local::borrow |sched: &mut Scheduler| {
let tube_clone = tube_clone.clone();
let tube_clone_cell = Cell::new(tube_clone);
let remote = do sched.event_loop.remote_callback {
@ -416,7 +416,7 @@ impl IoFactory for UvIoFactory {
// Block this task and take ownership, switch to scheduler context
do task::unkillable { // FIXME(#8674)
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
let mut tcp = TcpWatcher::new(self.uv_loop());
@ -434,7 +434,7 @@ impl IoFactory for UvIoFactory {
unsafe { (*result_cell_ptr).put_back(res); }
// Context switch
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
Some(_) => {
@ -442,7 +442,7 @@ impl IoFactory for UvIoFactory {
do stream.close {
let res = Err(uv_error_to_io_error(status.unwrap()));
unsafe { (*result_cell_ptr).put_back(res); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -464,11 +464,11 @@ impl IoFactory for UvIoFactory {
}
Err(uverr) => {
do task::unkillable { // FIXME(#8674)
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do watcher.as_stream().close {
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -487,11 +487,11 @@ impl IoFactory for UvIoFactory {
}
Err(uverr) => {
do task::unkillable { // FIXME(#8674)
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do watcher.close {
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -539,7 +539,7 @@ impl IoFactory for UvIoFactory {
IoError>> = &result_cell;
let path_cell = Cell::new(path);
do task::unkillable { // FIXME(#8674)
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
let path = path_cell.take();
@ -553,12 +553,12 @@ impl IoFactory for UvIoFactory {
loop_, fd, true, home) as ~RtioFileStream;
let res = Ok(fs);
unsafe { (*result_cell_ptr).put_back(res); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
} else {
let res = Err(uv_error_to_io_error(err.unwrap()));
unsafe { (*result_cell_ptr).put_back(res); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
};
@ -573,7 +573,7 @@ impl IoFactory for UvIoFactory {
let result_cell_ptr: *Cell<Result<(), IoError>> = &result_cell;
let path_cell = Cell::new(path);
do task::unkillable { // FIXME(#8674)
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
let path = path_cell.take();
@ -583,7 +583,7 @@ impl IoFactory for UvIoFactory {
Some(err) => Err(uv_error_to_io_error(err))
};
unsafe { (*result_cell_ptr).put_back(res); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
};
};
@ -625,7 +625,7 @@ impl Drop for UvTcpListener {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.watcher().as_stream().close {
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -717,7 +717,7 @@ impl Drop for UvTcpStream {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.watcher.as_stream().close {
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -765,7 +765,7 @@ impl RtioTcpStream for UvTcpStream {
unsafe { (*result_cell_ptr).put_back(result); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -793,7 +793,7 @@ impl RtioTcpStream for UvTcpStream {
unsafe { (*result_cell_ptr).put_back(result); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -876,7 +876,7 @@ impl Drop for UvUdpSocket {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.watcher.close {
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -917,7 +917,7 @@ impl RtioUdpSocket for UvUdpSocket {
unsafe { (*result_cell_ptr).put_back(result); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -944,7 +944,7 @@ impl RtioUdpSocket for UvUdpSocket {
unsafe { (*result_cell_ptr).put_back(result); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -1094,7 +1094,7 @@ impl Drop for UvTimer {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.watcher.close {
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -1110,7 +1110,7 @@ impl RtioTimer for UvTimer {
let task_cell = Cell::new(task);
do self_.watcher.start(msecs, 0) |_, status| {
assert!(status.is_none());
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
}
}
@ -1154,7 +1154,7 @@ impl UvFileStream {
Some(err) => Err(uv_error_to_io_error(err))
};
unsafe { (*result_cell_ptr).put_back(res); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
};
};
@ -1175,7 +1175,7 @@ impl UvFileStream {
Some(err) => Err(uv_error_to_io_error(err))
};
unsafe { (*result_cell_ptr).put_back(res); }
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
};
};
@ -1208,7 +1208,7 @@ impl Drop for UvFileStream {
do scheduler.deschedule_running_task_and_then |_, task| {
let task_cell = Cell::new(task);
do self_.fd.close(&self.loop_) |_,_| {
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
scheduler.resume_blocked_task_immediately(task_cell.take());
};
};
@ -1254,7 +1254,7 @@ impl RtioFileStream for UvFileStream {
fn test_simple_io_no_connect() {
do run_in_newsched_task {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let addr = next_test_ip4();
let maybe_chan = (*io).tcp_connect(addr);
assert!(maybe_chan.is_err());
@ -1266,7 +1266,7 @@ fn test_simple_io_no_connect() {
fn test_simple_udp_io_bind_only() {
do run_in_newsched_task {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let addr = next_test_ip4();
let maybe_socket = (*io).udp_bind(addr);
assert!(maybe_socket.is_ok());
@ -1303,7 +1303,9 @@ fn test_simple_homed_udp_io_bind_then_move_task_then_home_and_close() {
};
let test_function: ~fn() = || {
let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
let io: *mut IoFactoryObject = unsafe {
Local::unsafe_borrow()
};
let addr = next_test_ip4();
let maybe_socket = unsafe { (*io).udp_bind(addr) };
// this socket is bound to this event loop
@ -1311,7 +1313,7 @@ fn test_simple_homed_udp_io_bind_then_move_task_then_home_and_close() {
// block self on sched1
do task::unkillable { // FIXME(#8674)
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
do scheduler.deschedule_running_task_and_then |_, task| {
// unblock task
do task.wake().map_move |task| {
@ -1377,7 +1379,9 @@ fn test_simple_homed_udp_io_bind_then_move_handle_then_home_and_close() {
let chan = Cell::new(chan);
let body1: ~fn() = || {
let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
let io: *mut IoFactoryObject = unsafe {
Local::unsafe_borrow()
};
let addr = next_test_ip4();
let socket = unsafe { (*io).udp_bind(addr) };
assert!(socket.is_ok());
@ -1430,7 +1434,7 @@ fn test_simple_tcp_server_and_client() {
// Start the server first so it's listening when we connect
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut listener = (*io).tcp_bind(addr).unwrap();
let mut stream = listener.accept().unwrap();
let mut buf = [0, .. 2048];
@ -1445,7 +1449,7 @@ fn test_simple_tcp_server_and_client() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut stream = (*io).tcp_connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
}
@ -1489,7 +1493,9 @@ fn test_simple_tcp_server_and_client_on_diff_threads() {
};
let server_fn: ~fn() = || {
let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
let io: *mut IoFactoryObject = unsafe {
Local::unsafe_borrow()
};
let mut listener = unsafe { (*io).tcp_bind(server_addr).unwrap() };
let mut stream = listener.accept().unwrap();
let mut buf = [0, .. 2048];
@ -1501,7 +1507,9 @@ fn test_simple_tcp_server_and_client_on_diff_threads() {
};
let client_fn: ~fn() = || {
let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
let io: *mut IoFactoryObject = unsafe {
Local::unsafe_borrow()
};
let mut stream = unsafe { (*io).tcp_connect(client_addr) };
while stream.is_err() {
stream = unsafe { (*io).tcp_connect(client_addr) };
@ -1540,7 +1548,7 @@ fn test_simple_udp_server_and_client() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut server_socket = (*io).udp_bind(server_addr).unwrap();
let mut buf = [0, .. 2048];
let (nread,src) = server_socket.recvfrom(buf).unwrap();
@ -1555,7 +1563,7 @@ fn test_simple_udp_server_and_client() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut client_socket = (*io).udp_bind(client_addr).unwrap();
client_socket.sendto([0, 1, 2, 3, 4, 5, 6, 7], server_addr);
}
@ -1569,7 +1577,7 @@ fn test_read_and_block() {
let addr = next_test_ip4();
do spawntask {
let io = unsafe { Local::unsafe_borrow::<IoFactoryObject>() };
let io: *mut IoFactoryObject = unsafe { Local::unsafe_borrow() };
let mut listener = unsafe { (*io).tcp_bind(addr).unwrap() };
let mut stream = listener.accept().unwrap();
let mut buf = [0, .. 2048];
@ -1588,7 +1596,7 @@ fn test_read_and_block() {
reads += 1;
do task::unkillable { // FIXME(#8674)
let scheduler = Local::take::<Scheduler>();
let scheduler: ~Scheduler = Local::take();
// Yield to the other task in hopes that it
// will trigger a read callback while we are
// not ready for it
@ -1605,7 +1613,7 @@ fn test_read_and_block() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut stream = (*io).tcp_connect(addr).unwrap();
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
stream.write([0, 1, 2, 3, 4, 5, 6, 7]);
@ -1625,7 +1633,7 @@ fn test_read_read_read() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut listener = (*io).tcp_bind(addr).unwrap();
let mut stream = listener.accept().unwrap();
let buf = [1, .. 2048];
@ -1639,7 +1647,7 @@ fn test_read_read_read() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut stream = (*io).tcp_connect(addr).unwrap();
let mut buf = [0, .. 2048];
let mut total_bytes_read = 0;
@ -1665,7 +1673,7 @@ fn test_udp_twice() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut client = (*io).udp_bind(client_addr).unwrap();
assert!(client.sendto([1], server_addr).is_ok());
assert!(client.sendto([2], server_addr).is_ok());
@ -1674,7 +1682,7 @@ fn test_udp_twice() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut server = (*io).udp_bind(server_addr).unwrap();
let mut buf1 = [0];
let mut buf2 = [0];
@ -1702,7 +1710,7 @@ fn test_udp_many_read() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut server_out = (*io).udp_bind(server_out_addr).unwrap();
let mut server_in = (*io).udp_bind(server_in_addr).unwrap();
let msg = [1, .. 2048];
@ -1725,7 +1733,7 @@ fn test_udp_many_read() {
do spawntask {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let mut client_out = (*io).udp_bind(client_out_addr).unwrap();
let mut client_in = (*io).udp_bind(client_in_addr).unwrap();
let mut total_bytes_recv = 0;
@ -1754,7 +1762,7 @@ fn test_udp_many_read() {
fn test_timer_sleep_simple() {
do run_in_newsched_task {
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let timer = (*io).timer_init();
do timer.map_move |mut t| { t.sleep(1) };
}
@ -1768,7 +1776,7 @@ fn file_test_uvio_full_simple_impl() {
use path::Path;
use rt::io::{Open, Create, ReadWrite, Read};
unsafe {
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
let write_val = "hello uvio!";
let path = "./tmp/file_test_uvio_full.txt";
{
@ -1802,7 +1810,7 @@ fn uvio_naive_print(input: &str) {
use str::StrSlice;
unsafe {
use libc::{STDOUT_FILENO};
let io = Local::unsafe_borrow::<IoFactoryObject>();
let io: *mut IoFactoryObject = Local::unsafe_borrow();
{
let mut fd = (*io).fs_from_raw_fd(STDOUT_FILENO, false);
let write_buf = input.as_bytes();

View File

@ -60,7 +60,7 @@ pub fn select<A: Select>(ports: &mut [A]) -> uint {
do (|| {
let c = Cell::new(c.take());
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
let task_handles = task.make_selectable(ports.len());

View File

@ -143,7 +143,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
if in_green_task_context() {
// XXX: Logging doesn't work here - the check to call the log
// function never passes - so calling the log function directly.
do Local::borrow::<Task, ()> |task| {
do Local::borrow |task: &mut Task| {
let msg = match task.name {
Some(ref name) =>
fmt!("task '%s' failed at '%s', %s:%i",
@ -160,7 +160,7 @@ pub fn begin_unwind_(msg: *c_char, file: *c_char, line: size_t) -> ! {
msg, file, line as int);
}
let task = Local::unsafe_borrow::<Task>();
let task: *mut Task = Local::unsafe_borrow();
if (*task).unwinder.unwinding {
rtabort!("unwinding again");
}

View File

@ -28,7 +28,7 @@ impl Handle {
pub fn new() -> Handle {
use rt::local::Local;
unsafe {
let task = Local::unsafe_borrow::<Task>();
let task: *mut Task = Local::unsafe_borrow();
NewHandle(&mut (*task).storage)
}
}

View File

@ -526,7 +526,7 @@ pub fn with_task_name<U>(blk: &fn(Option<&str>) -> U) -> U {
use rt::task::Task;
if in_green_task_context() {
do Local::borrow::<Task, U> |task| {
do Local::borrow |task: &mut Task| {
match task.name {
Some(ref name) => blk(Some(name.as_slice())),
None => blk(None)
@ -545,7 +545,7 @@ pub fn deschedule() {
// FIXME #6842: What does yield really mean in newsched?
// FIXME(#7544): Optimize this, since we know we won't block.
let sched = Local::take::<Scheduler>();
let sched: ~Scheduler = Local::take();
do sched.deschedule_running_task_and_then |sched, task| {
sched.enqueue_blocked_task(task);
}
@ -556,7 +556,7 @@ pub fn failing() -> bool {
use rt::task::Task;
do Local::borrow::<Task, bool> |local| {
do Local::borrow |local: &mut Task| {
local.unwinder.unwinding
}
}
@ -582,7 +582,7 @@ pub fn unkillable<U>(f: &fn() -> U) -> U {
unsafe {
if in_green_task_context() {
// The inhibits/allows might fail and need to borrow the task.
let t = Local::unsafe_borrow::<Task>();
let t: *mut Task = Local::unsafe_borrow();
do (|| {
(*t).death.inhibit_kill((*t).unwinder.unwinding);
f()
@ -616,7 +616,7 @@ pub fn rekillable<U>(f: &fn() -> U) -> U {
unsafe {
if in_green_task_context() {
let t = Local::unsafe_borrow::<Task>();
let t: *mut Task = Local::unsafe_borrow();
do (|| {
(*t).death.allow_kill((*t).unwinder.unwinding);
f()
@ -1032,7 +1032,7 @@ fn test_try_fail() {
#[cfg(test)]
fn get_sched_id() -> int {
do Local::borrow::<::rt::sched::Scheduler, int> |sched| {
do Local::borrow |sched: &mut ::rt::sched::Scheduler| {
sched.sched_id() as int
}
}

View File

@ -449,7 +449,7 @@ impl RuntimeGlue {
fn kill_task(mut handle: KillHandle) {
do handle.kill().map_move |killed_task| {
let killed_task = Cell::new(killed_task);
do Local::borrow::<Scheduler, ()> |sched| {
do Local::borrow |sched: &mut Scheduler| {
sched.enqueue_task(killed_task.take());
}
};
@ -460,7 +460,7 @@ impl RuntimeGlue {
unsafe {
// Can't use safe borrow, because the taskgroup destructor needs to
// access the scheduler again to send kill signals to other tasks.
let me = Local::unsafe_borrow::<Task>();
let me: *mut Task = Local::unsafe_borrow();
blk((*me).death.kill_handle.get_ref(), (*me).unwinder.unwinding)
}
}
@ -470,7 +470,7 @@ impl RuntimeGlue {
unsafe {
// Can't use safe borrow, because creating new hashmaps for the
// tasksets requires an rng, which needs to borrow the sched.
let me = Local::unsafe_borrow::<Task>();
let me: *mut Task = Local::unsafe_borrow();
blk(match (*me).taskgroup {
None => {
// First task in its (unlinked/unsupervised) taskgroup.
@ -574,7 +574,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
// If child data is 'None', the enlist is vacuously successful.
let enlist_success = do child_data.take().map_move_default(true) |child_data| {
let child_data = Cell::new(child_data); // :(
do Local::borrow::<Task, bool> |me| {
do Local::borrow |me: &mut Task| {
let (child_tg, ancestors) = child_data.take();
let mut ancestors = ancestors;
let handle = me.death.kill_handle.get_ref();
@ -608,7 +608,7 @@ pub fn spawn_raw(mut opts: TaskOpts, f: ~fn()) {
} else {
unsafe {
// Creating a 1:1 task:thread ...
let sched = Local::unsafe_borrow::<Scheduler>();
let sched: *mut Scheduler = Local::unsafe_borrow();
let sched_handle = (*sched).make_handle();
// Since this is a 1:1 scheduler we create a queue not in

View File

@ -343,7 +343,14 @@ impl<A:IterBytes> IterBytes for ~A {
// NB: raw-pointer IterBytes does _not_ dereference
// to the target; it just gives you the pointer-bytes.
impl<A> IterBytes for *const A {
impl<A> IterBytes for *A {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
(*self as uint).iter_bytes(lsb0, f)
}
}
impl<A> IterBytes for *mut A {
#[inline]
fn iter_bytes(&self, lsb0: bool, f: Cb) -> bool {
(*self as uint).iter_bytes(lsb0, f)

View File

@ -176,7 +176,7 @@ macro_rules! tuple_impls {
impl<$($T:Zero),+> Zero for ($($T,)+) {
#[inline]
fn zero() -> ($($T,)+) {
($(Zero::zero::<$T>(),)+)
($({ let x: $T = Zero::zero(); x},)+)
}
#[inline]
fn is_zero(&self) -> bool {

View File

@ -538,7 +538,8 @@ mod test {
#[test]
fn option_empty() {
assert!(AtomicOption::empty::<()>().is_empty(SeqCst));
let mut option: AtomicOption<()> = AtomicOption::empty();
assert!(option.is_empty(SeqCst));
}
#[test]

View File

@ -13,7 +13,7 @@
use c_str::ToCStr;
use cast::transmute;
use libc::{c_char, c_void, size_t, uintptr_t};
use option::{Some, None};
use option::{Option, None, Some};
use sys;
use rt::task::Task;
use rt::local::Local;
@ -37,7 +37,8 @@ pub fn fail_bounds_check(file: *c_char, line: size_t,
#[lang="malloc"]
pub unsafe fn local_malloc(td: *c_char, size: uintptr_t) -> *c_char {
// XXX: Unsafe borrow for speed. Lame.
match Local::try_unsafe_borrow::<Task>() {
let task: Option<*mut Task> = Local::try_unsafe_borrow();
match task {
Some(task) => {
(*task).heap.alloc(td as *c_void, size as uint) as *c_char
}

View File

@ -279,7 +279,8 @@ pub unsafe fn atomically<U>(f: &fn() -> U) -> U {
use rt::task::{Task, GreenTask, SchedTask};
use rt::local::Local;
match Local::try_unsafe_borrow::<Task>() {
let task_opt: Option<*mut Task> = Local::try_unsafe_borrow();
match task_opt {
Some(t) => {
match (*t).task_type {
GreenTask(_) => {

View File

@ -54,8 +54,10 @@ pub fn swap<T>(x: &mut T, y: &mut T) {
let t: *mut T = &mut tmp;
// Perform the swap, `&mut` pointers never alias
ptr::copy_nonoverlapping_memory(t, x, 1);
ptr::copy_nonoverlapping_memory(x, y, 1);
let x_raw: *mut T = x;
let y_raw: *mut T = y;
ptr::copy_nonoverlapping_memory(t, x_raw, 1);
ptr::copy_nonoverlapping_memory(x, y_raw, 1);
ptr::copy_nonoverlapping_memory(y, t, 1);
// y and t now point to the same thing, but we need to completely forget `tmp`

View File

@ -1122,14 +1122,7 @@ impl<'self,T> ImmutableVector<'self, T> for &'self [T] {
* foreign interop.
*/
#[inline]
fn as_imm_buf<U>(&self,
/* NB---this CANNOT be const, see below */
f: &fn(*T, uint) -> U) -> U {
// NB---Do not change the type of s to `&const [T]`. This is
// unsound. The reason is that we are going to create immutable pointers
// into `s` and pass them to `f()`, but in fact they are potentially
// pointing at *mutable memory*. Use `as_mut_buf` instead!
fn as_imm_buf<U>(&self, f: &fn(*T, uint) -> U) -> U {
let s = self.repr();
f(s.data, s.len / sys::nonzero_size_of::<T>())
}

View File

@ -109,12 +109,21 @@ pub struct Path {
/// A `::foo` path, is relative to the crate root rather than current
/// module (like paths in an import).
global: bool,
/// The segments in the path (the things separated by ::)
idents: ~[ident],
/// "Region parameter", currently only one lifetime is allowed in a path.
rp: Option<Lifetime>,
/// These are the type parameters, ie, the `a, b` in `foo::bar::<a, b>`
types: ~[Ty],
/// The segments in the path: the things separated by `::`.
segments: ~[PathSegment],
}
/// A segment of a path: an identifier, an optional lifetime, and a set of
/// types.
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct PathSegment {
/// The identifier portion of this path segment.
identifier: ident,
/// The lifetime parameter for this path segment. Currently only one
/// lifetime parameter is allowed.
lifetime: Option<Lifetime>,
/// The type parameters for this path segment, if present.
types: OptVec<Ty>,
}
pub type CrateNum = int;
@ -165,12 +174,16 @@ impl Generics {
}
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum MethodProvenance {
FromTrait(def_id),
FromImpl(def_id),
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum def {
def_fn(def_id, purity),
def_static_method(/* method */ def_id,
/* trait */ Option<def_id>,
purity),
def_static_method(/* method */ def_id, MethodProvenance, purity),
def_self(NodeId),
def_self_ty(/* trait id */ NodeId),
def_mod(def_id),
@ -298,7 +311,10 @@ pub enum pat_ {
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum mutability { m_mutbl, m_imm, m_const, }
pub enum mutability {
m_mutbl,
m_imm,
}
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub enum Sigil {
@ -704,7 +720,7 @@ impl ToStr for float_ty {
}
// NB Eq method appears below.
#[deriving(Clone, Eq, Encodable, Decodable,IterBytes)]
#[deriving(Clone, Eq, Encodable, Decodable, IterBytes)]
pub struct Ty {
id: NodeId,
node: ty_,

View File

@ -28,8 +28,8 @@ pub fn path_name_i(idents: &[ident]) -> ~str {
idents.map(|i| token::interner_get(i.name)).connect("::")
}
pub fn path_to_ident(p: &Path) -> ident {
*p.idents.last()
pub fn path_to_ident(path: &Path) -> ident {
path.segments.last().identifier
}
pub fn local_def(id: NodeId) -> def_id {
@ -217,12 +217,18 @@ pub fn default_block(
}
}
pub fn ident_to_path(s: span, i: ident) -> Path {
ast::Path { span: s,
global: false,
idents: ~[i],
rp: None,
types: ~[] }
pub fn ident_to_path(s: span, identifier: ident) -> Path {
ast::Path {
span: s,
global: false,
segments: ~[
ast::PathSegment {
identifier: identifier,
lifetime: None,
types: opt_vec::Empty,
}
],
}
}
pub fn ident_to_pat(id: NodeId, s: span, i: ident) -> @pat {
@ -420,7 +426,7 @@ impl IdVisitor {
impl Visitor<()> for IdVisitor {
fn visit_mod(&mut self,
module: &_mod,
_span: span,
_: span,
node_id: NodeId,
env: ()) {
(self.visit_callback)(node_id);

View File

@ -329,20 +329,6 @@ pub fn expr_to_str(cx: @ExtCtxt, expr: @ast::expr, err_msg: &str) -> @str {
}
}
pub fn expr_to_ident(cx: @ExtCtxt,
expr: @ast::expr,
err_msg: &str) -> ast::ident {
match expr.node {
ast::expr_path(ref p) => {
if p.types.len() > 0u || p.idents.len() != 1u {
cx.span_fatal(expr.span, err_msg);
}
return p.idents[0];
}
_ => cx.span_fatal(expr.span, err_msg)
}
}
pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
name: &str) {
if tts.len() != 0 {
@ -353,15 +339,15 @@ pub fn check_zero_tts(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree],
pub fn get_single_str_from_tts(cx: @ExtCtxt,
sp: span,
tts: &[ast::token_tree],
name: &str) -> @str {
name: &str)
-> @str {
if tts.len() != 1 {
cx.span_fatal(sp, fmt!("%s takes 1 argument.", name));
}
match tts[0] {
ast::tt_tok(_, token::LIT_STR(ident)) => cx.str_of(ident),
_ =>
cx.span_fatal(sp, fmt!("%s requires a string.", name))
_ => cx.span_fatal(sp, fmt!("%s requires a string.", name)),
}
}

View File

@ -74,6 +74,13 @@ pub trait AstBuilder {
// statements
fn stmt_expr(&self, expr: @ast::expr) -> @ast::stmt;
fn stmt_let(&self, sp: span, mutbl: bool, ident: ast::ident, ex: @ast::expr) -> @ast::stmt;
fn stmt_let_typed(&self,
sp: span,
mutbl: bool,
ident: ast::ident,
typ: ast::Ty,
ex: @ast::expr)
-> @ast::stmt;
// blocks
fn block(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@ast::expr>) -> ast::Block;
@ -233,18 +240,31 @@ impl AstBuilder for @ExtCtxt {
fn path_global(&self, span: span, strs: ~[ast::ident]) -> ast::Path {
self.path_all(span, true, strs, None, ~[])
}
fn path_all(&self, sp: span,
fn path_all(&self,
sp: span,
global: bool,
idents: ~[ast::ident],
mut idents: ~[ast::ident],
rp: Option<ast::Lifetime>,
types: ~[ast::Ty])
-> ast::Path {
-> ast::Path {
let last_identifier = idents.pop();
let mut segments: ~[ast::PathSegment] = idents.move_iter()
.map(|ident| {
ast::PathSegment {
identifier: ident,
lifetime: None,
types: opt_vec::Empty,
}
}).collect();
segments.push(ast::PathSegment {
identifier: last_identifier,
lifetime: rp,
types: opt_vec::from(types),
});
ast::Path {
span: sp,
global: global,
idents: idents,
rp: rp,
types: types
segments: segments,
}
}
@ -387,6 +407,26 @@ impl AstBuilder for @ExtCtxt {
@respan(sp, ast::stmt_decl(@decl, self.next_id()))
}
fn stmt_let_typed(&self,
sp: span,
mutbl: bool,
ident: ast::ident,
typ: ast::Ty,
ex: @ast::expr)
-> @ast::stmt {
let pat = self.pat_ident(sp, ident);
let local = @ast::Local {
is_mutbl: mutbl,
ty: typ,
pat: pat,
init: Some(ex),
id: self.next_id(),
span: sp,
};
let decl = respan(sp, ast::decl_local(local));
@respan(sp, ast::stmt_decl(@decl, self.next_id()))
}
fn block(&self, span: span, stmts: ~[@ast::stmt], expr: Option<@expr>) -> ast::Block {
self.block_all(span, ~[], stmts, expr)
}

View File

@ -12,6 +12,7 @@ use ast;
use codemap::span;
use ext::base::*;
use ext::base;
use opt_vec;
use parse::token;
use parse::token::{str_to_ident};
@ -39,9 +40,13 @@ pub fn expand_syntax_ext(cx: @ExtCtxt, sp: span, tts: &[ast::token_tree])
ast::Path {
span: sp,
global: false,
idents: ~[res],
rp: None,
types: ~[],
segments: ~[
ast::PathSegment {
identifier: res,
lifetime: None,
types: opt_vec::Empty,
}
]
}
),
span: sp,

View File

@ -76,24 +76,33 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr {
let variant_count = cx.expr_uint(span, variants.len());
// need to specify the uint-ness of the random number
let uint_ty = cx.ty_ident(span, cx.ident_of("uint"));
let r_ty = cx.ty_ident(span, cx.ident_of("R"));
let rand_name = cx.path_all(span,
true,
rand_ident.clone(),
None,
~[ uint_ty, r_ty ]);
~[]);
let rand_name = cx.expr_path(rand_name);
// ::std::rand::Rand::rand::<uint>(rng)
// ::std::rand::Rand::rand(rng)
let rv_call = cx.expr_call(span,
rand_name,
~[ rng[0].duplicate(cx) ]);
// need to specify the uint-ness of the random number
let uint_ty = cx.ty_ident(span, cx.ident_of("uint"));
let value_ident = cx.ident_of("__value");
let let_statement = cx.stmt_let_typed(span,
false,
value_ident,
uint_ty,
rv_call);
// rand() % variants.len()
let rand_variant = cx.expr_binary(span, ast::rem,
rv_call, variant_count);
let value_ref = cx.expr_ident(span, value_ident);
let rand_variant = cx.expr_binary(span,
ast::rem,
value_ref,
variant_count);
let mut arms = do variants.iter().enumerate().map |(i, id_sum)| {
let i_expr = cx.expr_uint(span, i);
@ -111,7 +120,10 @@ fn rand_substructure(cx: @ExtCtxt, span: span, substr: &Substructure) -> @expr {
// _ => {} at the end. Should never occur
arms.push(cx.arm_unreachable(span));
cx.expr_match(span, rand_variant, arms)
let match_expr = cx.expr_match(span, rand_variant, arms);
let block = cx.block(span, ~[ let_statement ], Some(match_expr));
cx.expr_block(block)
}
_ => cx.bug("Non-static method in `deriving(Rand)`")
};

View File

@ -19,6 +19,7 @@ use codemap;
use codemap::{span, spanned, ExpnInfo, NameAndSpan};
use ext::base::*;
use fold::*;
use opt_vec;
use parse;
use parse::{parse_item_from_source_str};
use parse::token;
@ -42,13 +43,13 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
match (*mac).node {
// Token-tree macros:
mac_invoc_tt(ref pth, ref tts) => {
if (pth.idents.len() > 1u) {
if (pth.segments.len() > 1u) {
cx.span_fatal(
pth.span,
fmt!("expected macro name without module \
separators"));
}
let extname = &pth.idents[0];
let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
// leaving explicit deref here to highlight unbox op:
match (*extsbox).find(&extname.name) {
@ -143,9 +144,13 @@ pub fn expand_expr(extsbox: @mut SyntaxEnv,
ast::Path {
span: span,
global: false,
idents: ~[ident],
rp: None,
types: ~[]
segments: ~[
ast::PathSegment {
identifier: ident,
lifetime: None,
types: opt_vec::Empty,
}
],
}
}
@ -368,7 +373,7 @@ pub fn expand_item_mac(extsbox: @mut SyntaxEnv,
_ => cx.span_bug(it.span, "invalid item macro invocation")
};
let extname = &pth.idents[0];
let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
let expanded = match (*extsbox).find(&extname.name) {
None => cx.span_fatal(pth.span,
@ -459,13 +464,13 @@ pub fn expand_stmt(extsbox: @mut SyntaxEnv,
}
_ => return orig(s, sp, fld)
};
if (pth.idents.len() > 1u) {
if (pth.segments.len() > 1u) {
cx.span_fatal(
pth.span,
fmt!("expected macro name without module \
separators"));
}
let extname = &pth.idents[0];
let extname = &pth.segments[0].identifier;
let extnamestr = ident_to_str(extname);
let (fully_expanded, sp) = match (*extsbox).find(&extname.name) {
None =>
@ -534,10 +539,14 @@ impl Visitor<()> for NewNameFinderContext {
// a path of length one:
&ast::Path {
global: false,
idents: [id],
span: _,
rp: _,
types: _
segments: [
ast::PathSegment {
identifier: id,
lifetime: _,
types: _
}
]
} => self.ident_accumulator.push(id),
// I believe these must be enums...
_ => ()

View File

@ -16,8 +16,8 @@ use codemap::{BytePos, mk_sp};
use codemap;
use parse::lexer::*; //resolve bug?
use parse::ParseSess;
use parse::parser::Parser;
use parse::attr::parser_attr;
use parse::parser::{LifetimeAndTypesWithoutColons, Parser};
use parse::token::{Token, EOF, to_str, nonterminal, get_ident_interner, ident_to_str};
use parse::token;
@ -430,7 +430,9 @@ pub fn parse_nt(p: &Parser, name: &str) -> nonterminal {
_ => p.fatal(~"expected ident, found "
+ token::to_str(get_ident_interner(), p.token))
},
"path" => token::nt_path(~p.parse_path_with_tps(false)),
"path" => {
token::nt_path(~p.parse_path(LifetimeAndTypesWithoutColons).path)
}
"attr" => token::nt_attr(@p.parse_attribute(false)),
"tt" => {
*p.quote_depth += 1u; //but in theory, non-quoted tts might be useful

View File

@ -765,9 +765,11 @@ fn noop_fold_path(p: &Path, fld: @ast_fold) -> Path {
ast::Path {
span: fld.new_span(p.span),
global: p.global,
idents: p.idents.map(|x| fld.fold_ident(*x)),
rp: p.rp,
types: p.types.map(|x| fld.fold_ty(x)),
segments: p.segments.map(|segment| ast::PathSegment {
identifier: fld.fold_ident(segment.identifier),
lifetime: segment.lifetime,
types: segment.types.map(|typ| fld.fold_ty(typ)),
})
}
}

View File

@ -284,7 +284,11 @@ pub fn visit_ty<E:Clone>(t: &Ty, (e, v): (E, vt<E>)) {
}
pub fn visit_path<E:Clone>(p: &Path, (e, v): (E, vt<E>)) {
for tp in p.types.iter() { (v.visit_ty)(tp, (e.clone(), v)); }
for segment in p.segments.iter() {
for typ in segment.types.iter() {
(v.visit_ty)(typ, (e.clone(), v))
}
}
}
pub fn visit_pat<E:Clone>(p: &pat, (e, v): (E, vt<E>)) {

View File

@ -361,27 +361,47 @@ mod test {
span{lo:BytePos(a),hi:BytePos(b),expn_info:None}
}
#[test] fn path_exprs_1 () {
#[test] fn path_exprs_1() {
assert_eq!(string_to_expr(@"a"),
@ast::expr{id:1,
node:ast::expr_path(ast::Path {span:sp(0,1),
global:false,
idents:~[str_to_ident("a")],
rp:None,
types:~[]}),
span:sp(0,1)})
@ast::expr{
id: 1,
node: ast::expr_path(ast::Path {
span: sp(0, 1),
global: false,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("a"),
lifetime: None,
types: opt_vec::Empty,
}
],
}),
span: sp(0, 1)
})
}
#[test] fn path_exprs_2 () {
assert_eq!(string_to_expr(@"::a::b"),
@ast::expr{id:1,
node:ast::expr_path(
ast::Path {span:sp(0,6),
global:true,
idents:strs_to_idents(~["a","b"]),
rp:None,
types:~[]}),
span:sp(0,6)})
@ast::expr {
id:1,
node: ast::expr_path(ast::Path {
span: sp(0, 6),
global: true,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("a"),
lifetime: None,
types: opt_vec::Empty,
},
ast::PathSegment {
identifier: str_to_ident("b"),
lifetime: None,
types: opt_vec::Empty,
}
]
}),
span: sp(0, 6)
})
}
#[should_fail]
@ -420,32 +440,43 @@ mod test {
#[test] fn ret_expr() {
assert_eq!(string_to_expr(@"return d"),
@ast::expr{id:2,
node:ast::expr_ret(
Some(@ast::expr{id:1,
node:ast::expr_path(
ast::Path{span:sp(7,8),
global:false,
idents:~[str_to_ident("d")],
rp:None,
types:~[]
}),
span:sp(7,8)})),
span:sp(0,8)})
@ast::expr{
id:2,
node:ast::expr_ret(Some(@ast::expr{
id:1,
node:ast::expr_path(ast::Path{
span: sp(7, 8),
global: false,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("d"),
lifetime: None,
types: opt_vec::Empty,
}
],
}),
span:sp(7,8)
})),
span:sp(0,8)
})
}
#[test] fn parse_stmt_1 () {
assert_eq!(string_to_stmt(@"b;"),
@spanned{
node: ast::stmt_expr(@ast::expr{
node: ast::stmt_expr(@ast::expr {
id: 1,
node: ast::expr_path(
ast::Path{
span:sp(0,1),
global:false,
idents:~[str_to_ident("b")],
rp:None,
types: ~[]}),
node: ast::expr_path(ast::Path {
span:sp(0,1),
global:false,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("b"),
lifetime: None,
types: opt_vec::Empty,
}
],
}),
span: sp(0,1)},
2), // fixme
span: sp(0,1)})
@ -460,49 +491,24 @@ mod test {
let parser = string_to_parser(@"b");
assert_eq!(parser.parse_pat(),
@ast::pat{id:1, // fixme
node: ast::pat_ident(ast::bind_infer,
ast::Path{
span:sp(0,1),
global:false,
idents:~[str_to_ident("b")],
rp: None,
types: ~[]},
None // no idea
),
node: ast::pat_ident(
ast::bind_infer,
ast::Path {
span:sp(0,1),
global:false,
segments: ~[
ast::PathSegment {
identifier: str_to_ident("b"),
lifetime: None,
types: opt_vec::Empty,
}
],
},
None /* no idea */),
span: sp(0,1)});
parser_done(parser);
}
#[test] fn parse_arg () {
let parser = string_to_parser(@"b : int");
assert_eq!(parser.parse_arg_general(true),
ast::arg{
is_mutbl: false,
ty: ast::Ty{id:3, // fixme
node: ast::ty_path(ast::Path{
span:sp(4,4), // this is bizarre...
// check this in the original parser?
global:false,
idents:~[str_to_ident("int")],
rp: None,
types: ~[]},
None, 2),
span:sp(4,7)},
pat: @ast::pat{id:1,
node: ast::pat_ident(ast::bind_infer,
ast::Path{
span:sp(0,1),
global:false,
idents:~[str_to_ident("b")],
rp: None,
types: ~[]},
None // no idea
),
span: sp(0,1)},
id: 4 // fixme
})
}
// check the contents of the tt manually:
#[test] fn parse_fundecl () {
// this test depends on the intern order of "fn" and "int", and on the
@ -519,23 +525,37 @@ mod test {
node: ast::ty_path(ast::Path{
span:sp(10,13),
global:false,
idents:~[str_to_ident("int")],
rp: None,
types: ~[]},
None, 2),
span:sp(10,13)},
pat: @ast::pat{id:1, // fixme
node: ast::pat_ident(
ast::bind_infer,
ast::Path{
span:sp(6,7),
global:false,
idents:~[str_to_ident("b")],
rp: None,
types: ~[]},
None // no idea
),
span: sp(6,7)},
segments: ~[
ast::PathSegment {
identifier:
str_to_ident("int"),
lifetime: None,
types: opt_vec::Empty,
}
],
}, None, 2),
span:sp(10,13)
},
pat: @ast::pat {
id:1, // fixme
node: ast::pat_ident(
ast::bind_infer,
ast::Path {
span:sp(6,7),
global:false,
segments: ~[
ast::PathSegment {
identifier:
str_to_ident("b"),
lifetime: None,
types: opt_vec::Empty,
}
],
},
None // no idea
),
span: sp(6,7)
},
id: 4 // fixme
}],
output: ast::Ty{id:5, // fixme
@ -558,9 +578,18 @@ mod test {
ast::Path{
span:sp(17,18),
global:false,
idents:~[str_to_ident("b")],
rp:None,
types: ~[]}),
segments: ~[
ast::PathSegment {
identifier:
str_to_ident(
"b"),
lifetime:
None,
types:
opt_vec::Empty
}
],
}),
span: sp(17,18)},
7), // fixme
span: sp(17,18)}],

View File

@ -53,7 +53,6 @@ pub enum ObsoleteSyntax {
ObsoleteMode,
ObsoleteImplicitSelf,
ObsoleteLifetimeNotation,
ObsoleteConstManagedPointer,
ObsoletePurity,
ObsoleteStaticMethod,
ObsoleteConstItem,
@ -65,6 +64,7 @@ pub enum ObsoleteSyntax {
ObsoleteUnsafeExternFn,
ObsoletePrivVisibility,
ObsoleteTraitFuncVisibility,
ObsoleteConstPointer,
}
impl to_bytes::IterBytes for ObsoleteSyntax {
@ -201,10 +201,6 @@ impl ParserObsoleteMethods for Parser {
"instead of `&foo/bar`, write `&'foo bar`; instead of \
`bar/&foo`, write `&bar<'foo>"
),
ObsoleteConstManagedPointer => (
"const `@` pointer",
"instead of `@const Foo`, write `@Foo`"
),
ObsoletePurity => (
"pure function",
"remove `pure`"
@ -255,6 +251,11 @@ impl ParserObsoleteMethods for Parser {
"visibility not necessary",
"trait functions inherit the visibility of the trait itself"
),
ObsoleteConstPointer => (
"const pointer",
"instead of `&const Foo` or `@const Foo`, write `&Foo` or \
`@Foo`"
),
};
self.report(sp, kind, kind_str, desc);

Some files were not shown because too many files have changed in this diff Show More